diff options
author | Daniel Baumann <daniel@debian.org> | 2024-12-01 20:42:54 +0100 |
---|---|---|
committer | Daniel Baumann <daniel@debian.org> | 2024-12-01 22:18:37 +0100 |
commit | 5622eceb23cb593322e7c0494323fab8efdb288e (patch) | |
tree | 661058f3088debcd764dda2addd7f208669132aa | |
parent | Adding sortablejs makefile. (diff) | |
download | dokuwiki-plugins-extra-5622eceb23cb593322e7c0494323fab8efdb288e.tar.xz dokuwiki-plugins-extra-5622eceb23cb593322e7c0494323fab8efdb288e.zip |
Adding sortablejs version 2023-04-20 (ef9a13e).
Signed-off-by: Daniel Baumann <daniel@debian.org>
-rw-r--r-- | plugins/55/sortablejs/README.md | 12 | ||||
-rw-r--r-- | plugins/55/sortablejs/plugin.info.txt | 7 | ||||
-rw-r--r-- | plugins/55/sortablejs/screen.css | 11 | ||||
-rw-r--r-- | plugins/55/sortablejs/script.js | 464 | ||||
-rw-r--r-- | plugins/55/sortablejs/syntax.php | 157 |
5 files changed, 651 insertions, 0 deletions
diff --git a/plugins/55/sortablejs/README.md b/plugins/55/sortablejs/README.md new file mode 100644 index 0000000..4a74654 --- /dev/null +++ b/plugins/55/sortablejs/README.md @@ -0,0 +1,12 @@ +sortablejs +========== + +JavaScript-based (client-side) DokuWiki table sorting plugin. In semi-maintenance mode now - only bugfixes and feature requests via PRs are handled. + +DokuWiki homepage at https://www.dokuwiki.org/plugin:sortablejs + +For server-side sorting (required for DW2PDF etc.) or more robust sort facilities, use @samwilson 's dokuwiki sorter (based on https://github.com/Mottie/tablesorter): https://github.com/samwilson/dokuwiki_sortablejs + +Cross-plugin compatibility is outside the scope of this repo. + +If reporting bugs, please provide a valid reproduction scenario for any non-trivial case. diff --git a/plugins/55/sortablejs/plugin.info.txt b/plugins/55/sortablejs/plugin.info.txt new file mode 100644 index 0000000..a154473 --- /dev/null +++ b/plugins/55/sortablejs/plugin.info.txt @@ -0,0 +1,7 @@ +base sortablejs +author vaxquis +email spamove@gmail.com +date 2023-04-20 +name sortablejs +desc Allow sorting tables by columns +url https://github.com/FyiurAmron/sortablejs diff --git a/plugins/55/sortablejs/screen.css b/plugins/55/sortablejs/screen.css new file mode 100644 index 0000000..53289e7 --- /dev/null +++ b/plugins/55/sortablejs/screen.css @@ -0,0 +1,11 @@ +div.sortable thead tr.row0 th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sorttable_nosort):after { + content: " \25B4\25BE" +} + +div.sortable thead tr.row0 th.sorttable_sorted:after { + content: " \25BE" +} + +div.sortable thead tr.row0 th.sorttable_sorted_reverse:after { + content: " \25B4" +} diff --git a/plugins/55/sortablejs/script.js b/plugins/55/sortablejs/script.js new file mode 100644 index 0000000..f9a85cb --- /dev/null +++ b/plugins/55/sortablejs/script.js @@ -0,0 +1,464 @@ +/** + Based on code from http://www.kryogenix.org/code/browser/sorttable/ by Stuart Langridge + (distributed under the conditions of MIT licence from http://www.kryogenix.org/code/browser/licence.html). + Includes open-source contributions from other people + (see https://github.com/FyiurAmron/sortablejs/graphs/contributors for more details). + Maintainers: + 2007-2016 oiv (Otto Vainio at otto@valjakko.net) + 2016-? vaxquis AKA FyiurAmron (spamove@gmail.com) + */ + +var stIsIE = /*@cc_on!@*/false; +//var tableid = 0; + +var sorttable = { + reinit: function () { + arguments.callee.done = true; + + if ( !document.createElement || !document.getElementsByTagName ) { + return; + } + + var elems = document.getElementsByTagName( "table" ); + var elem; + for( var i = 0; i < elems.length; i++ ) { + elem = elems[i]; + if ( jQuery(elem).hasClass("sortable") ) { + sorttable.makeSortable( elem ); + } + } + elems = document.getElementsByTagName( "div" ); + for( var i = 0; i < elems.length; i++ ) { + elem = elems[i]; + if ( jQuery(elem).hasClass("sortable") ) { + sorttable.makeSortableDiv( elem ); + } + } + }, + init: function () { + if ( arguments.callee.done ) { + return; + } + sorttable.reinit(); + }, + makeSortableDiv: function ( div ) { + var childTables = div.getElementsByTagName( "table" ); + var elem; + for( var i = 0; i < childTables.length; i++ ) { + elem = childTables[i]; + var colid = div.className; + var patt1 = /\bcol_\d+_[a-z]+/gi; + var overs = []; + if ( colid.search( patt1 ) !== -1 ) { + var overrides = colid.match( patt1 ); + for( var i = 0; i < overrides.length; i++ ) { + var entry = overrides[i]; + if ( entry !== "" ) { + try { + var tmp = entry.split( "_" ); + var ind = tmp[1]; + var val = tmp[2]; + overs[ind] = val; + } catch( e ) { + } + } + } + colid = colid.replace( patt1, '' ); + } + var patt2 = /\bsortbottom_?\d?/gi; + var bottoms = 0; + if ( colid.search( patt2 ) !== -1 ) { + var bs = colid.match( patt2 ); + try { + var tmp = bs[0].split( "_" ); + //var ind = tmp[1]; + var val = 1; + if ( tmp.length > 1 ) { + val = tmp[1]; + } + bottoms = val; + } catch( e ) { + } + } + var patt2ph = /\bthreephase/gi; + var ph2 = true; + if ( colid.search( patt2ph ) !== -1 ) { + ph2 = false; + } + + sorttable.makeSortable( elem, overs, bottoms, ph2 ); + var pattdefault = /\bsortr?\d\d?/gi; + if ( colid.search( pattdefault ) !== -1 ) { + var mi = colid.match( pattdefault ); + colid = mi[0].replace( 'sort', '' ); + if ( colid !== '' ) { + colid = colid.trim(); + } + var revs = false; + if ( colid.search( /\br/ ) !== -1 ) { + revs = true; + colid = colid.replace( 'r', '' ); + } + sorttable.defaultSort( elem, colid, revs ); + } + } + }, + defaultSort: function ( table, colid, revs ) { + var havetHead = table.tHead; + var sindex = 1; + if ( havetHead ) { + sindex = 0; + } + var theadrow = table.rows[0].cells; + colid--; + var colname = "col" + colid; + // remove sorttable_sorted classes + var thiscell = false; + for( var i = 0; i < theadrow.length; i++ ) { + var cell = theadrow[i]; + var colclass = cell.className; + var classname = colclass.split( " " ); + if ( classname[0] === colname ) { + thiscell = cell; + } + } + if ( thiscell === false ) { + return; + } + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + var row_array = []; + var col = thiscell.sorttable_columnindex; + var rows = thiscell.sorttable_tbody.rows; + for( var j = sindex; j < rows.length; j++ ) { + row_array[row_array.length] = [sorttable.getInnerText( rows[j].cells[col] ), rows[j]]; + } + /* If you want a stable sort, uncomment the following line */ + //sorttable.shaker_sort(row_array, this.sorttable_sortfunction); + /* and comment out this one */ + row_array.sort( thiscell.sorttable_sortfunction ); + + var tb = thiscell.sorttable_tbody; + for( var jj = 0; jj < row_array.length; jj++ ) { + tb.appendChild( row_array[jj][1] ); + } + + if ( revs ) { + sorttable.reverse( thiscell.sorttable_tbody, sindex ); + jQuery(thiscell).addClass( "sorttable_sorted_reverse" ); + } else { + jQuery(thiscell).addClass( "sorttable_sorted" ); + } + }, + makeSortable: function ( table, overrides, bottoms, ph2 ) { + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backwards compatibility, move them to tfoot (creating it if needed). + + var sortbottomrows = []; + if ( bottoms > 0 ) { + var frombottom = table.rows.length - bottoms; + for( var i = table.rows.length - 1; i >= frombottom; i-- ) { + sortbottomrows[sortbottomrows.length] = table.rows[i]; + } + if ( sortbottomrows ) { + var tfo; + if ( table.tFoot === null ) { + // table doesn't have a tfoot. Create one. + tfo = document.createElement( 'tfoot' ); + table.appendChild( tfo ); + } + for( var ii = sortbottomrows.length - 1; ii >= 0; ii-- ) { + tfo.appendChild( sortbottomrows[ii] ); + } + //delete sortbottomrows; + } + } + // work through each column and calculate its type + var havetHead = table.tHead; + var sindex = 1; + if ( havetHead ) { + sindex = 0; + } + var headrow = table.rows[0].cells; + + for( var i = 0; i < headrow.length; i++ ) { + // manually override the type with a sorttable_type attribute + var colOptions = ""; + if ( overrides[i + 1] ) + { + colOptions = overrides[i + 1]; + } + if ( colOptions.match( /\bnosort\b/ ) ) { + jQuery(headrow[i]).addClass("sorttable_nosort"); + } else { // skip this col + var mtch = colOptions.match( /\b[a-z0-9]+\b/ ); + var override; + if ( mtch ) { + override = mtch[0]; + } + if ( mtch && typeof sorttable["sort_" + override] === 'function' ) { + headrow[i].sorttable_sortfunction = sorttable["sort_" + override]; + } else { + headrow[i].sorttable_sortfunction = sorttable.guessType( table, i ); + } + + // make it clickable to sort + headrow[i].sorttable_columnindex = i; + headrow[i].sorttable_tbody = table.tBodies[0]; + headrow[i].sindex = sindex; + + jQuery( headrow[i] ).click( function () { + var theadrow = this.parentNode; + var jqt = jQuery( this ); + if ( jqt.hasClass( "sorttable_sorted" ) ) { + // if we're already sorted by this column, just reverse the table + sorttable.reverse( this.sorttable_tbody, this.sindex ); + jqt.removeClass( "sorttable_sorted" ); + jqt.addClass( "sorttable_sorted_reverse" ); + return; + } + if ( jqt.hasClass( "sorttable_sorted_reverse" ) ) { + if ( !ph2 ) { + sorttable.original_order( this.sorttable_tbody, this.sindex ); + var list = theadrow.childNodes; + for( var i = 0; i < list.length; i++ ) { + var cell = list[i]; + if ( cell.nodeType === 1 ) { // an element + var cc = jQuery( cell ); + cc.removeClass( "sorttable_sorted" ); + cc.removeClass( "sorttable_sorted_reverse" ); + } + } + return; + } else { + // if we're already sorted by this column in reverse, just re-reverse the table + sorttable.reverse( this.sorttable_tbody, this.sindex ); + jqt.removeClass( "sorttable_sorted_reverse" ); + jqt.addClass( "sorttable_sorted" ); + return; + } + } + + // remove sorttable_sorted classes + var list = theadrow.childNodes; + for( var i = 0; i < list.length; i++ ) { + var cell = list[i]; + if ( cell.nodeType === 1 ) { // an element + var cc = jQuery( cell ); + cc.removeClass( "sorttable_sorted" ); + cc.removeClass( "sorttable_sorted_reverse" ); + } + } + jqt.addClass( "sorttable_sorted" ); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + var row_array = []; + var col = this.sorttable_columnindex; + var rows = this.sorttable_tbody.rows; + sindex = this.sindex; + for( var j = sindex; j < rows.length; j++ ) { + row_array[row_array.length] = [sorttable.getInnerText( rows[j].cells[col] ), rows[j]]; + } + /* If you want a stable sort, uncomment the following line */ + //sorttable.shaker_sort(row_array, this.sorttable_sortfunction); + /* and comment out this one */ + row_array.sort( this.sorttable_sortfunction ); + + var tb = this.sorttable_tbody; + for( var j3 = 0; j3 < row_array.length; j3++ ) { + tb.appendChild( row_array[j3][1] ); + } + + //delete row_array; + } ); + } + } + }, + guessType: function ( table, column ) { + // guess the type of a column based on its first non-blank row + var textCnt = 0; + var numCnt = 0; + var dateCnt = 0; + var ipCnt = 0; + + for( var i = 0; i < table.tBodies[0].rows.length; i++ ) { + var text = sorttable.getInnerText( table.tBodies[0].rows[i].cells[column] ); + if ( text !== "" ) { + if ( text.match( /^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$/ ) ) { + ipCnt++; + } else if ( text.match( /^[\-\+]?.?\d*[\d,.]?\d+.?$/ ) ) { + numCnt++; + } else if ( !isNaN( new Date( text ).getTime() ) ) { + dateCnt++; + } else { // not a date (nor IP nor number) + textCnt++; + } + } + } + if ( textCnt > numCnt && textCnt > ipCnt && textCnt > dateCnt ) + return sorttable.sort_alpha; + if ( numCnt > ipCnt && numCnt > dateCnt ) + return sorttable.sort_numeric; + if ( ipCnt > dateCnt ) + return sorttable.sort_ipaddr; + return sorttable.sort_date; + }, + getInnerText: function ( node ) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for <input> fields. + if ( !node ) { + return ''; + } + var hasInputs = ( typeof node.getElementsByTagName === "function" ) && + node.getElementsByTagName( "input" ).length; + if ( node.getAttribute( "sorttable_customkey" ) !== null ) { + return node.getAttribute( "sorttable_customkey" ); + } else if ( typeof node.textContent !== "undefined" && !hasInputs ) { + return node.textContent.replace( /^\s+|\s+$/g, '' ); + } else if ( typeof node.innerText !== "undefined" && !hasInputs ) { + return node.innerText.replace( /^\s+|\s+$/g, '' ); + } else if ( typeof node.text !== "undefined" && !hasInputs ) { + return node.text.replace( /^\s+|\s+$/g, '' ); + } else { + switch ( node.nodeType ) { + case 3: + return ( node.nodeName.toLowerCase() === "input" ) ? node.value.replace( /^\s+|\s+$/g, '' ) : ''; + case 4: + return node.nodeValue.replace( /^\s+|\s+$/g, '' ); + case 1: + case 11: + var innerText = ''; + for( var i = 0; i < node.childNodes.length; i++ ) { + innerText += sorttable.getInnerText( node.childNodes[i] ); + } + return innerText.replace( /^\s+|\s+$/g, '' ); + default: + return ''; + } + } + }, + reverse: function ( tbody, sindex ) { + // reverse the rows in a tbody + var newrows = []; + for( var i = sindex; i < tbody.rows.length; i++ ) { + newrows[newrows.length] = tbody.rows[i]; + } + for( var i = newrows.length - 1; i >= 0; i-- ) { + tbody.appendChild( newrows[i] ); + } + //delete newrows; + }, + original_order: function ( tbody, isindex ) { + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + var row_array = []; + var rows = tbody.rows; + var sindex = isindex; + for( var j = sindex; j < rows.length; j++ ) { + row_array[row_array.length] = [rows[j].className, rows[j]]; + } + /* If you want a stable sort, uncomment the following line */ + //sorttable.shaker_sort(row_array, this.sorttable_sortfunction); + /* and comment out this one */ + row_array.sort( sorttable.sort_alpha ); + + var tb = tbody; + for( var j3 = 0; j3 < row_array.length; j3++ ) { + tb.appendChild( row_array[j3][1] ); + } + + //delete row_array; + }, + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_ipaddr: function ( a, b ) { + var aa = a[0].split( ".", 4 ); + var bb = b[0].split( ".", 4 ); + var resulta = aa[0] * 0x1000000 + aa[1] * 0x10000 + aa[2] * 0x100 + aa[3] * 1; + var resultb = bb[0] * 0x1000000 + bb[1] * 0x10000 + bb[2] * 0x100 + bb[3] * 1; + return resulta - resultb; + }, + sort_numeric: function ( a, b ) { + if ( a[0] === "" ) { + return -1; + } + if ( b[0] === "" ) { + return 1; + } + var aa = parseFloat( a[0].replace( ",", "." ).replace( /[^0-9.\-]/g, "" ) ); + if ( isNaN( aa ) ) { + aa = Number.NEGATIVE_INFINITY; + } + var bb = parseFloat( b[0].replace( ",", "." ).replace( /[^0-9.\-]/g, "" ) ); + if ( isNaN( bb ) ) { + bb = Number.NEGATIVE_INFINITY; + } + return aa - bb; + }, + sort_alpha: function ( a, b ) { + return a[0].localeCompare( b[0] ); + }, + sort_date: function ( a, b ) { + var aa = new Date( a[0] ), bb = new Date( b[0] ); + return ( aa > bb ) - ( aa < bb ); + }, + shaker_sort: function ( list, comp_func ) { + // A stable sort function to allow multi-level sorting of data + // see: http://en.wikipedia.org/wiki/Cocktail_sort + // thanks to Joseph Nahmias + var b = 0; + var t = list.length - 1; + var swap = true; + var q; + + while( swap ) { + swap = false; + for( var i = b; i < t; ++i ) { + if ( comp_func( list[i], list[i + 1] ) > 0 ) { + q = list[i]; + list[i] = list[i + 1]; + list[i + 1] = q; + swap = true; + } + } // for + t--; + + if ( !swap ) { + break; + } + + for( var i = t; i > b; --i ) { + if ( comp_func( list[i], list[i - 1] ) < 0 ) { + q = list[i]; + list[i] = list[i - 1]; + list[i - 1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } + +}; + +if ( typeof ( window.addEvent ) !== "undefined" ) { + window.addEvent( window, "load", sorttable.init ); +} else { + jQuery( function () { + sorttable.init(); + } ); +} diff --git a/plugins/55/sortablejs/syntax.php b/plugins/55/sortablejs/syntax.php new file mode 100644 index 0000000..145c925 --- /dev/null +++ b/plugins/55/sortablejs/syntax.php @@ -0,0 +1,157 @@ +<?php +/** + Based on code from http://www.kryogenix.org/code/browser/sorttable/ by Stuart Langridge + (distributed under the conditions of MIT licence from http://www.kryogenix.org/code/browser/licence.html). + Includes open-source contributions from other people + (see https://github.com/FyiurAmron/sortablejs/graphs/contributors for more details). + Maintainers: + 2007-2016 oiv (Otto Vainio at otto@valjakko.net) + 2016-? vaxquis AKA FyiurAmron (spamove@gmail.com) + */ + +// must be run within Dokuwiki +if ( !defined( 'DOKU_INC' ) ) + die(); +// +class syntax_plugin_sortablejs extends DokuWiki_Syntax_Plugin { + + function getType() { + return 'container'; + } + + function getPType() { + return 'block'; + } + + function getSort() { + return 371; + } + + function getAllowedTypes() { + return array( 'container', 'formatting', 'substition' ); + } + + function connectTo( $mode ) { + $this->Lexer->addEntryPattern( '<sortable[^>]*>(?=.*?</sortable>)', $mode, 'plugin_sortablejs' ); + } + + function postConnect() { + $this->Lexer->addExitPattern( '</sortable>', 'plugin_sortablejs' ); + } + + function handle( $match, $state, $pos, Doku_Handler $handler ) { + + switch ( $state ) { + case DOKU_LEXER_ENTER : + $match = substr( $match, 9, -1 ); + $match = trim( $match ); + $scl = ""; + if ( strlen( $match ) > 0 ) { + $scl = $this->__validateOptions( $match ); + } + return array( $state, $scl ); + case DOKU_LEXER_UNMATCHED : + return array( $state, $match ); + case DOKU_LEXER_EXIT : + return array( $state, "" ); + } + return array(); + } + + function render( $mode, Doku_Renderer $renderer, $data ) { + list($state, $match) = $data; + if ( $mode == 'xhtml' ) { + switch ( $state ) { + case DOKU_LEXER_ENTER : + $renderer->doc .= "<div class=\"sortable$match\">"; + break; + case DOKU_LEXER_UNMATCHED : + $instructions = p_get_instructions( $match ); + foreach( $instructions as $instruction ) { + call_user_func_array( array( &$renderer, $instruction[0] ), $instruction[1] ); + } + + break; + case DOKU_LEXER_EXIT : + $renderer->doc .= "</div>"; + break; + } + return true; + } else if ( $mode == 'odt' ) { + switch ( $state ) { + case DOKU_LEXER_ENTER : + // In ODT, tables must not be inside a paragraph. Make sure we + // closed any opened paragraph + $renderer->p_close(); + break; + case DOKU_LEXER_UNMATCHED : + $instructions = array_slice( p_get_instructions( $match ), 1, -1 ); + foreach( $instructions as $instruction ) { + call_user_func_array( array( &$renderer, $instruction[0] ), $instruction[1] ); + } + break; + case DOKU_LEXER_EXIT : + //$renderer->p_open(); + // DO NOT re-open the paragraph, it would cause an error if the table is the last content on a page + break; + } + return true; + } + return false; + } + + function __validateOptions( $opts ) { + if ( empty( $opts ) ) { + return ""; + } + $ret = ""; + $oa = explode( " ", $opts ); + foreach( $oa as $opt ) { + $explodedOption = explode( "=", $opt ); + $c = $explodedOption[0]; + $v = $explodedOption[1] ?? null; + if ( $c == "sumrow" ) { + $c = $v; + $v = "sumrow"; + if ( $c == "" ) { + $c = "1"; + } + } else if ( $c == "3phase" ) { + $v = $c; + $c = ""; + } + if ( $v != null ) { + $cmpr = $v; + } else { + if ( preg_match( '/r?\d*/', $c, $matches ) ) { + $cmpr = 'sort'; + } + } + switch ( $cmpr ) { + case '3phase': + $ret .= " threephase"; + break; + case 'nosort': + $ret .= " col_".$c."_nosort"; + break; + case 'numeric': + $ret .= " col_".$c."_numeric"; + break; + case 'date': + $ret .= " col_".$c."_date"; + break; + case 'alpha': + case 'text': + $ret .= " col_".$c."_alpha"; + break; + case 'sort': + $ret .= ' sort'.$opt; + break; + case 'sumrow': + $ret .= ' sortbottom_'.$c; + break; + } + } + return $ret; + } +} |