From 13eb0ccb30f8480739ec8412d486d50b4712818e Mon Sep 17 00:00:00 2001 From: Emanuel Schuetze Date: Tue, 14 Jan 2014 21:44:48 +0100 Subject: [PATCH] Fixed #1190: Wrong sorting of motion identifier - Added natural sorting JS plugin for motion DataTables (column identifier). - Added the new requirements python package 'natsort' for natural sorting of motions in PDF. --- README.rst | 5 ++ extras/win32-portable/create_portable.txt | 2 +- extras/win32-portable/licenses/natsort | 19 +++++++ extras/win32-portable/prepare_portable.py | 3 ++ openslides/motion/pdf.py | 5 +- .../motion/templates/motion/motion_list.html | 8 +++ .../static/javascript/dataTables.bootstrap.js | 1 + openslides/static/javascript/naturalSort.js | 50 +++++++++++++++++++ requirements_production.txt | 1 + 9 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 extras/win32-portable/licenses/natsort create mode 100644 openslides/static/javascript/naturalSort.js diff --git a/README.rst b/README.rst index 66da95e06..919830cfc 100644 --- a/README.rst +++ b/README.rst @@ -256,6 +256,8 @@ OpenSlides uses the following projects or parts of them: * `Django haystack `_, License: BSD +* `natsort `_, License: MIT + * `pdf.js `_, License: Apache License v2.0 * `Pillow `_, License: Standard @@ -292,6 +294,9 @@ OpenSlides uses the following projects or parts of them: - `jQuery DataTables Plugin `_, License: BSD/GPLv2 + - `DataTables Natural Sort Plugin `_, + License: MIT + - `jQuery Cookie Plugin `_, License: MIT/GPL diff --git a/extras/win32-portable/create_portable.txt b/extras/win32-portable/create_portable.txt index 959ac27eb..8dfd7e93b 100644 --- a/extras/win32-portable/create_portable.txt +++ b/extras/win32-portable/create_portable.txt @@ -7,7 +7,7 @@ How to create a new portable Windows distribution of OpenSlides: 2. Install all required python packages (see requirements_production.txt): - easy_install -Z django django-mptt beautifulsoup4 bleach pillow reportlab sockjs_tornado tornado django-haystack whoosh + easy_install -Z django django-mptt beautifulsoup4 bleach natsort pillow reportlab sockjs_tornado tornado django-haystack whoosh 3. Install pywin32 from binary installer: diff --git a/extras/win32-portable/licenses/natsort b/extras/win32-portable/licenses/natsort new file mode 100644 index 000000000..993858af2 --- /dev/null +++ b/extras/win32-portable/licenses/natsort @@ -0,0 +1,19 @@ +Copyright (c) 2012 Seth M. Morton + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/extras/win32-portable/prepare_portable.py b/extras/win32-portable/prepare_portable.py index 65364fea2..921a91de6 100755 --- a/extras/win32-portable/prepare_portable.py +++ b/extras/win32-portable/prepare_portable.py @@ -93,6 +93,9 @@ SITE_PACKAGES = { "django-haystack": { "copy": ["haystack"], }, + "natsort": { + "copy": ["natsort"], + }, "whoosh": { "copy": ["whoosh"], }, diff --git a/openslides/motion/pdf.py b/openslides/motion/pdf.py index 3eb09b93d..a9166b98c 100644 --- a/openslides/motion/pdf.py +++ b/openslides/motion/pdf.py @@ -1,11 +1,13 @@ # -*- coding: utf-8 -*- +from operator import attrgetter import os import random from bs4 import BeautifulSoup from django.conf import settings from django.utils.translation import ugettext as _ +from natsort import natsorted from reportlab.lib import colors from reportlab.lib.units import cm from reportlab.platypus import PageBreak, Paragraph, Spacer, Table, TableStyle @@ -25,6 +27,7 @@ def motions_to_pdf(pdf): Create a PDF with all motions. """ motions = Motion.objects.all() + motions = natsorted(motions, key=attrgetter('identifier')) all_motion_cover(pdf, motions) for motion in motions: pdf.append(PageBreak()) @@ -254,7 +257,7 @@ def all_motion_cover(pdf, motions): identifier = "" if motion.identifier: identifier = "%s " % motion.identifier - pdf.append(Paragraph("%s%s" % (identifier, motion.title), stylesheet['Heading3'])) + pdf.append(Paragraph("%s   %s" % (identifier, motion.title), stylesheet['Heading3'])) def motion_poll_to_pdf(pdf, poll): diff --git a/openslides/motion/templates/motion/motion_list.html b/openslides/motion/templates/motion/motion_list.html index b7772a695..865f5d771 100644 --- a/openslides/motion/templates/motion/motion_list.html +++ b/openslides/motion/templates/motion/motion_list.html @@ -12,7 +12,15 @@ {% block javascript %} + + {% endblock %} {% block content %} diff --git a/openslides/static/javascript/dataTables.bootstrap.js b/openslides/static/javascript/dataTables.bootstrap.js index 6e160ad3a..9fd6ad615 100644 --- a/openslides/static/javascript/dataTables.bootstrap.js +++ b/openslides/static/javascript/dataTables.bootstrap.js @@ -11,6 +11,7 @@ /* Table initialisation */ $(document).ready(function() { $('#dataTable').dataTable( { + "bRetrieve": true, "aLengthMenu": [[10, 25, 50, -1], [10, 25, 50, gettext("All")]], "aoColumnDefs": [ { "bSortable": false, "aTargets": [ -1 ] } diff --git a/openslides/static/javascript/naturalSort.js b/openslides/static/javascript/naturalSort.js new file mode 100644 index 000000000..c831beba7 --- /dev/null +++ b/openslides/static/javascript/naturalSort.js @@ -0,0 +1,50 @@ +/* + * Natural Sort algorithm for Javascript - Version 0.6 - Released under MIT license + * Author: Jim Palmer (based on chunking idea from Dave Koelle) + * Contributors: Mike Grier (mgrier.com), Clint Priest, Kyle Adams, guillermo + */ + +function naturalSort (a, b) { + var re = /(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi, + sre = /(^[ ]*|[ ]*$)/g, + dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/, + hre = /^0x[0-9a-f]+$/i, + ore = /^0/, + // convert all to strings and trim() + x = a.toString().replace(sre, '') || '', + y = b.toString().replace(sre, '') || '', + // chunk/tokenize + xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'), + yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'), + // numeric, hex or date detection + xD = parseInt(x.match(hre)) || (xN.length != 1 && x.match(dre) && Date.parse(x)), + yD = parseInt(y.match(hre)) || xD && y.match(dre) && Date.parse(y) || null; + // first try and sort Hex codes or Dates + if (yD) + if ( xD < yD ) return -1; + else if ( xD > yD ) return 1; + // natural sorting through split numeric strings and default strings + for(var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) { + // find floats not starting with '0', string or 0 if not defined (Clint Priest) + oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0; + oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0; + // handle numeric vs string comparison - number < string - (Kyle Adams) + if (isNaN(oFxNcL) !== isNaN(oFyNcL)) return (isNaN(oFxNcL)) ? 1 : -1; + // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2' + else if (typeof oFxNcL !== typeof oFyNcL) { + oFxNcL += ''; + oFyNcL += ''; + } + if (oFxNcL < oFyNcL) return -1; + if (oFxNcL > oFyNcL) return 1; + } + return 0; +} + +// use naturalSort as dataTable extension +jQuery.fn.dataTableExt.oSort['natural-asc'] = function(a,b) { + return naturalSort(a,b); +}; +jQuery.fn.dataTableExt.oSort['natural-desc'] = function(a,b) { + return naturalSort(a,b) * -1; +}; diff --git a/requirements_production.txt b/requirements_production.txt index 061138f38..f593b43f2 100644 --- a/requirements_production.txt +++ b/requirements_production.txt @@ -4,6 +4,7 @@ beautifulsoup4>=4.3,<4.4 bleach>=1.2,<1.3 django-haystack>=2.1,<2.2 django-mptt>=0.6,<0.7 +natsort>=3.0,<3.1 pillow>=2.2,<2.3 reportlab>=2.7,<2.8 sockjs-tornado>=1.0,<1.1