View | Details | Raw Unified | Return to bug 14899
Collapse All | Expand All

(-)a/koha-tmpl/intranet-tmpl/lib/jquery/plugins/jquery.tablednd.js (+672 lines)
Line 0 Link Here
1
/**
2
 * TableDnD plug-in for JQuery, allows you to drag and drop table rows
3
 * You can set up various options to control how the system will work
4
 * Copyright (c) Denis Howlett <denish@isocra.com>
5
 * Licensed like jQuery, see http://docs.jquery.com/License.
6
 *
7
 * Configuration options:
8
 *
9
 * onDragStyle
10
 *     This is the style that is assigned to the row during drag. There are limitations to the styles that can be
11
 *     associated with a row (such as you can't assign a border--well you can, but it won't be
12
 *     displayed). (So instead consider using onDragClass.) The CSS style to apply is specified as
13
 *     a map (as used in the jQuery css(...) function).
14
 * onDropStyle
15
 *     This is the style that is assigned to the row when it is dropped. As for onDragStyle, there are limitations
16
 *     to what you can do. Also this replaces the original style, so again consider using onDragClass which
17
 *     is simply added and then removed on drop.
18
 * onDragClass
19
 *     This class is added for the duration of the drag and then removed when the row is dropped. It is more
20
 *     flexible than using onDragStyle since it can be inherited by the row cells and other content. The default
21
 *     is class is tDnD_whileDrag. So to use the default, simply customise this CSS class in your
22
 *     stylesheet.
23
 * onDrop
24
 *     Pass a function that will be called when the row is dropped. The function takes 2 parameters: the table
25
 *     and the row that was dropped. You can work out the new order of the rows by using
26
 *     table.rows.
27
 * onDragStart
28
 *     Pass a function that will be called when the user starts dragging. The function takes 2 parameters: the
29
 *     table and the row which the user has started to drag.
30
 * onAllowDrop
31
 *     Pass a function that will be called as a row is over another row. If the function returns true, allow
32
 *     dropping on that row, otherwise not. The function takes 2 parameters: the dragged row and the row under
33
 *     the cursor. It returns a boolean: true allows the drop, false doesn't allow it.
34
 * scrollAmount
35
 *     This is the number of pixels to scroll if the user moves the mouse cursor to the top or bottom of the
36
 *     window. The page should automatically scroll up or down as appropriate (tested in IE6, IE7, Safari, FF2,
37
 *     FF3 beta
38
 * dragHandle
39
 *     This is a jQuery mach string for one or more cells in each row that is draggable. If you
40
 *     specify this, then you are responsible for setting cursor: move in the CSS and only these cells
41
 *     will have the drag behaviour. If you do not specify a dragHandle, then you get the old behaviour where
42
 *     the whole row is draggable.
43
 *
44
 * Other ways to control behaviour:
45
 *
46
 * Add class="nodrop" to any rows for which you don't want to allow dropping, and class="nodrag" to any rows
47
 * that you don't want to be draggable.
48
 *
49
 * Inside the onDrop method you can also call $.tableDnD.serialize() this returns a string of the form
50
 * <tableID>[]=<rowID1>&<tableID>[]=<rowID2> so that you can send this back to the server. The table must have
51
 * an ID as must all the rows.
52
 *
53
 * Other methods:
54
 *
55
 * $("...").tableDnDUpdate()
56
 * Will update all the matching tables, that is it will reapply the mousedown method to the rows (or handle cells).
57
 * This is useful if you have updated the table rows using Ajax and you want to make the table draggable again.
58
 * The table maintains the original configuration (so you don't have to specify it again).
59
 *
60
 * $("...").tableDnDSerialize()
61
 * Will serialize and return the serialized string as above, but for each of the matching tables--so it can be
62
 * called from anywhere and isn't dependent on the currentTable being set up correctly before calling
63
 *
64
 * Known problems:
65
 * - Auto-scoll has some problems with IE7  (it scrolls even when it shouldn't), work-around: set scrollAmount to 0
66
 *
67
 * Version 0.2: 2008-02-20 First public version
68
 * Version 0.3: 2008-02-07 Added onDragStart option
69
 *                         Made the scroll amount configurable (default is 5 as before)
70
 * Version 0.4: 2008-03-15 Changed the noDrag/noDrop attributes to nodrag/nodrop classes
71
 *                         Added onAllowDrop to control dropping
72
 *                         Fixed a bug which meant that you couldn't set the scroll amount in both directions
73
 *                         Added serialize method
74
 * Version 0.5: 2008-05-16 Changed so that if you specify a dragHandle class it doesn't make the whole row
75
 *                         draggable
76
 *                         Improved the serialize method to use a default (and settable) regular expression.
77
 *                         Added tableDnDupate() and tableDnDSerialize() to be called when you are outside the table
78
 * Version 0.6: 2011-12-02 Added support for touch devices
79
 * Version 0.7  2012-04-09 Now works with jQuery 1.7 and supports touch, tidied up tabs and spaces
80
 */
81
!function ($, window, document, undefined) {
82
// Determine if this is a touch device
83
var hasTouch   = 'ontouchstart' in document.documentElement,
84
    startEvent = 'touchstart mousedown',
85
    moveEvent  = 'touchmove mousemove',
86
    endEvent   = 'touchend mouseup';
87
88
// If we're on a touch device, then wire up the events
89
// see http://stackoverflow.com/a/8456194/1316086
90
hasTouch
91
    && $.each("touchstart touchmove touchend".split(" "), function(i, name) {
92
        $.event.fixHooks[name] = $.event.mouseHooks;
93
    });
94
95
96
$(document).ready(function () {
97
    function parseStyle(css) {
98
        var objMap = {},
99
            parts = css.match(/([^;:]+)/g) || [];
100
        while (parts.length)
101
            objMap[parts.shift()] = parts.shift().trim();
102
103
        return objMap;
104
    }
105
    $('table').each(function () {
106
        if ($(this).data('table') == 'dnd') {
107
108
            $(this).tableDnD({
109
                onDragStyle: $(this).data('ondragstyle') && parseStyle($(this).data('ondragstyle')) || null,
110
                onDropStyle: $(this).data('ondropstyle') && parseStyle($(this).data('ondropstyle')) || null,
111
                onDragClass: $(this).data('ondragclass') == undefined && "tDnD_whileDrag" || $(this).data('ondragclass'),
112
                onDrop: $(this).data('ondrop') && new Function('table', 'row', $(this).data('ondrop')), // 'return eval("'+$(this).data('ondrop')+'");') || null,
113
                onDragStart: $(this).data('ondragstart') && new Function('table', 'row' ,$(this).data('ondragstart')), // 'return eval("'+$(this).data('ondragstart')+'");') || null,
114
                scrollAmount: $(this).data('scrollamount') || 5,
115
                sensitivity: $(this).data('sensitivity') || 10,
116
                hierarchyLevel: $(this).data('hierarchylevel') || 0,
117
                indentArtifact: $(this).data('indentartifact') || '<div class="indent">&nbsp;</div>',
118
                autoWidthAdjust: $(this).data('autowidthadjust') || true,
119
                autoCleanRelations: $(this).data('autocleanrelations') || true,
120
                jsonPretifySeparator: $(this).data('jsonpretifyseparator') || '\t',
121
                serializeRegexp: $(this).data('serializeregexp') && new RegExp($(this).data('serializeregexp')) || /[^\-]*$/,
122
                serializeParamName: $(this).data('serializeparamname') || false,
123
                dragHandle: $(this).data('draghandle') || null
124
            });
125
        }
126
127
128
    });
129
});
130
131
jQuery.tableDnD = {
132
    /** Keep hold of the current table being dragged */
133
    currentTable: null,
134
    /** Keep hold of the current drag object if any */
135
    dragObject: null,
136
    /** The current mouse offset */
137
    mouseOffset: null,
138
    /** Remember the old value of X and Y so that we don't do too much processing */
139
    oldX: 0,
140
    oldY: 0,
141
142
    /** Actually build the structure */
143
    build: function(options) {
144
        // Set up the defaults if any
145
146
        this.each(function() {
147
            // This is bound to each matching table, set up the defaults and override with user options
148
            this.tableDnDConfig = $.extend({
149
                onDragStyle: null,
150
                onDropStyle: null,
151
                // Add in the default class for whileDragging
152
                onDragClass: "tDnD_whileDrag",
153
                onDrop: null,
154
                onDragStart: null,
155
                scrollAmount: 5,
156
                /** Sensitivity setting will throttle the trigger rate for movement detection */
157
                sensitivity: 10,
158
                /** Hierarchy level to support parent child. 0 switches this functionality off */
159
                hierarchyLevel: 0,
160
                /** The html artifact to prepend the first cell with as indentation */
161
                indentArtifact: '<div class="indent">&nbsp;</div>',
162
                /** Automatically adjust width of first cell */
163
                autoWidthAdjust: true,
164
                /** Automatic clean-up to ensure relationship integrity */
165
                autoCleanRelations: true,
166
                /** Specify a number (4) as number of spaces or any indent string for JSON.stringify */
167
                jsonPretifySeparator: '\t',
168
                /** The regular expression to use to trim row IDs */
169
                serializeRegexp: /[^\-]*$/,
170
                /** If you want to specify another parameter name instead of the table ID */
171
                serializeParamName: false,
172
                /** If you give the name of a class here, then only Cells with this class will be draggable */
173
                dragHandle: null
174
            }, options || {});
175
176
            // Now make the rows draggable
177
            $.tableDnD.makeDraggable(this);
178
            // Prepare hierarchy support
179
            this.tableDnDConfig.hierarchyLevel
180
                && $.tableDnD.makeIndented(this);
181
        });
182
183
        // Don't break the chain
184
        return this;
185
    },
186
    makeIndented: function (table) {
187
        var config = table.tableDnDConfig,
188
            rows = table.rows,
189
            firstCell = $(rows).first().find('td:first')[0],
190
            indentLevel = 0,
191
            cellWidth = 0,
192
            longestCell,
193
            tableStyle;
194
195
        if ($(table).hasClass('indtd'))
196
            return null;
197
198
        tableStyle = $(table).addClass('indtd').attr('style');
199
        $(table).css({whiteSpace: "nowrap"});
200
201
        for (var w = 0; w < rows.length; w++) {
202
            if (cellWidth < $(rows[w]).find('td:first').text().length) {
203
                cellWidth = $(rows[w]).find('td:first').text().length;
204
                longestCell = w;
205
            }
206
        }
207
        $(firstCell).css({width: 'auto'});
208
        for (w = 0; w < config.hierarchyLevel; w++)
209
            $(rows[longestCell]).find('td:first').prepend(config.indentArtifact);
210
        firstCell && $(firstCell).css({width: firstCell.offsetWidth});
211
        tableStyle && $(table).css(tableStyle);
212
213
        for (w = 0; w < config.hierarchyLevel; w++)
214
            $(rows[longestCell]).find('td:first').children(':first').remove();
215
216
        config.hierarchyLevel
217
            && $(rows).each(function () {
218
                indentLevel = $(this).data('level') || 0;
219
                indentLevel <= config.hierarchyLevel
220
                    && $(this).data('level', indentLevel)
221
                    || $(this).data('level', 0);
222
                for (var i = 0; i < $(this).data('level'); i++)
223
                    $(this).find('td:first').prepend(config.indentArtifact);
224
            });
225
226
        return this;
227
    },
228
    /** This function makes all the rows on the table draggable apart from those marked as "NoDrag" */
229
    makeDraggable: function(table) {
230
        var config = table.tableDnDConfig;
231
232
        config.dragHandle
233
            // We only need to add the event to the specified cells
234
            && $(config.dragHandle, table).each(function() {
235
                // The cell is bound to "this"
236
                $(this).bind(startEvent, function(e) {
237
                    $.tableDnD.initialiseDrag($(this).parents('tr')[0], table, this, e, config);
238
                    return false;
239
                });
240
            })
241
            // For backwards compatibility, we add the event to the whole row
242
            // get all the rows as a wrapped set
243
            || $(table.rows).each(function() {
244
                // Iterate through each row, the row is bound to "this"
245
                if (! $(this).hasClass("nodrag")) {
246
                    $(this).bind(startEvent, function(e) {
247
                        if (e.target.tagName == "TD") {
248
                            $.tableDnD.initialiseDrag(this, table, this, e, config);
249
                            return false;
250
                        }
251
                    }).css("cursor", "move"); // Store the tableDnD object
252
                } else {
253
                    $(this).css("cursor", ""); // Remove the cursor if we don't have the nodrag class
254
                }
255
            });
256
    },
257
    currentOrder: function() {
258
        var rows = this.currentTable.rows;
259
        return $.map(rows, function (val) {
260
            return ($(val).data('level') + val.id).replace(/\s/g, '');
261
        }).join('');
262
    },
263
    initialiseDrag: function(dragObject, table, target, e, config) {
264
        this.dragObject    = dragObject;
265
        this.currentTable  = table;
266
        this.mouseOffset   = this.getMouseOffset(target, e);
267
        this.originalOrder = this.currentOrder();
268
269
        // Now we need to capture the mouse up and mouse move event
270
        // We can use bind so that we don't interfere with other event handlers
271
        $(document)
272
            .bind(moveEvent, this.mousemove)
273
            .bind(endEvent, this.mouseup);
274
275
        // Call the onDragStart method if there is one
276
        config.onDragStart
277
            && config.onDragStart(table, target);
278
    },
279
    updateTables: function() {
280
        this.each(function() {
281
            // this is now bound to each matching table
282
            if (this.tableDnDConfig)
283
                $.tableDnD.makeDraggable(this);
284
        });
285
    },
286
    /** Get the mouse coordinates from the event (allowing for browser differences) */
287
    mouseCoords: function(e) {
288
        if (e.originalEvent.changedTouches)
289
            return {
290
                x: e.originalEvent.changedTouches[0].clientX,
291
                y: e.originalEvent.changedTouches[0].clientY
292
            };
293
        
294
        if(e.pageX || e.pageY)
295
            return {
296
                x: e.pageX,
297
                y: e.pageY
298
            };
299
300
        return {
301
            x: e.clientX + document.body.scrollLeft - document.body.clientLeft,
302
            y: e.clientY + document.body.scrollTop  - document.body.clientTop
303
        };
304
    },
305
    /** Given a target element and a mouse eent, get the mouse offset from that element.
306
     To do this we need the element's position and the mouse position */
307
    getMouseOffset: function(target, e) {
308
        var mousePos,
309
            docPos;
310
311
        e = e || window.event;
312
313
        docPos    = this.getPosition(target);
314
        mousePos  = this.mouseCoords(e);
315
316
        return {
317
            x: mousePos.x - docPos.x,
318
            y: mousePos.y - docPos.y
319
        };
320
    },
321
    /** Get the position of an element by going up the DOM tree and adding up all the offsets */
322
    getPosition: function(element) {
323
        var left = 0,
324
            top  = 0;
325
326
        // Safari fix -- thanks to Luis Chato for this!
327
        // Safari 2 doesn't correctly grab the offsetTop of a table row
328
        // this is detailed here:
329
        // http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari/
330
        // the solution is likewise noted there, grab the offset of a table cell in the row - the firstChild.
331
        // note that firefox will return a text node as a first child, so designing a more thorough
332
        // solution may need to take that into account, for now this seems to work in firefox, safari, ie
333
        if (element.offsetHeight == 0)
334
            element = element.firstChild; // a table cell
335
336
        while (element.offsetParent) {
337
            left   += element.offsetLeft;
338
            top    += element.offsetTop;
339
            element = element.offsetParent;
340
        }
341
342
        left += element.offsetLeft;
343
        top  += element.offsetTop;
344
345
        return {
346
            x: left,
347
            y: top
348
        };
349
    },
350
    autoScroll: function (mousePos) {
351
      var config       = this.currentTable.tableDnDConfig,
352
          yOffset      = window.pageYOffset,
353
          windowHeight = window.innerHeight
354
            ? window.innerHeight
355
            : document.documentElement.clientHeight
356
            ? document.documentElement.clientHeight
357
            : document.body.clientHeight;
358
359
        // Windows version
360
        // yOffset=document.body.scrollTop;
361
        if (document.all)
362
            if (typeof document.compatMode != 'undefined'
363
                && document.compatMode != 'BackCompat')
364
                yOffset = document.documentElement.scrollTop;
365
            else if (typeof document.body != 'undefined')
366
                yOffset = document.body.scrollTop;
367
368
        mousePos.y - yOffset < config.scrollAmount
369
            && window.scrollBy(0, - config.scrollAmount)
370
        || windowHeight - (mousePos.y - yOffset) < config.scrollAmount
371
            && window.scrollBy(0, config.scrollAmount);
372
373
    },
374
    moveVerticle: function (moving, currentRow) {
375
376
        if (0 != moving.vertical
377
            // If we're over a row then move the dragged row to there so that the user sees the
378
            // effect dynamically
379
            && currentRow
380
            && this.dragObject != currentRow
381
            && this.dragObject.parentNode == currentRow.parentNode)
382
            0 > moving.vertical
383
                && this.dragObject.parentNode.insertBefore(this.dragObject, currentRow.nextSibling)
384
            || 0 < moving.vertical
385
                && this.dragObject.parentNode.insertBefore(this.dragObject, currentRow);
386
387
    },
388
    moveHorizontal: function (moving, currentRow) {
389
        var config       = this.currentTable.tableDnDConfig,
390
            currentLevel;
391
392
        if (!config.hierarchyLevel
393
            || 0 == moving.horizontal
394
            // We only care if moving left or right on the current row
395
            || !currentRow
396
            || this.dragObject != currentRow)
397
                return null;
398
399
            currentLevel = $(currentRow).data('level');
400
401
            0 < moving.horizontal
402
                && currentLevel > 0
403
                && $(currentRow).find('td:first').children(':first').remove()
404
                && $(currentRow).data('level', --currentLevel);
405
406
            0 > moving.horizontal
407
                && currentLevel < config.hierarchyLevel
408
                && $(currentRow).prev().data('level') >= currentLevel
409
                && $(currentRow).children(':first').prepend(config.indentArtifact)
410
                && $(currentRow).data('level', ++currentLevel);
411
412
    },
413
    mousemove: function(e) {
414
        var dragObj      = $($.tableDnD.dragObject),
415
            config       = $.tableDnD.currentTable.tableDnDConfig,
416
            currentRow,
417
            mousePos,
418
            moving,
419
            x,
420
            y;
421
422
        e && e.preventDefault();
423
424
        if (!$.tableDnD.dragObject)
425
            return false;
426
427
        // prevent touch device screen scrolling
428
        e.type == 'touchmove'
429
            && event.preventDefault(); // TODO verify this is event and not really e
430
431
        // update the style to show we're dragging
432
        config.onDragClass
433
            && dragObj.addClass(config.onDragClass)
434
            || dragObj.css(config.onDragStyle);
435
436
        mousePos = $.tableDnD.mouseCoords(e);
437
        x = mousePos.x - $.tableDnD.mouseOffset.x;
438
        y = mousePos.y - $.tableDnD.mouseOffset.y;
439
440
        // auto scroll the window
441
        $.tableDnD.autoScroll(mousePos);
442
443
        currentRow = $.tableDnD.findDropTargetRow(dragObj, y);
444
        moving = $.tableDnD.findDragDirection(x, y);
445
446
        $.tableDnD.moveVerticle(moving, currentRow);
447
        $.tableDnD.moveHorizontal(moving, currentRow);
448
449
        return false;
450
    },
451
    findDragDirection: function (x,y) {
452
        var sensitivity = this.currentTable.tableDnDConfig.sensitivity,
453
            oldX        = this.oldX,
454
            oldY        = this.oldY,
455
            xMin        = oldX - sensitivity,
456
            xMax        = oldX + sensitivity,
457
            yMin        = oldY - sensitivity,
458
            yMax        = oldY + sensitivity,
459
            moving      = {
460
                horizontal: x >= xMin && x <= xMax ? 0 : x > oldX ? -1 : 1,
461
                vertical  : y >= yMin && y <= yMax ? 0 : y > oldY ? -1 : 1
462
            };
463
464
        // update the old value
465
        if (moving.horizontal != 0)
466
            this.oldX    = x;
467
        if (moving.vertical   != 0)
468
            this.oldY    = y;
469
470
        return moving;
471
    },
472
    /** We're only worried about the y position really, because we can only move rows up and down */
473
    findDropTargetRow: function(draggedRow, y) {
474
        var rowHeight = 0,
475
            rows      = this.currentTable.rows,
476
            config    = this.currentTable.tableDnDConfig,
477
            rowY      = 0,
478
            row       = null;
479
480
        for (var i = 0; i < rows.length; i++) {
481
            row       = rows[i];
482
            rowY      = this.getPosition(row).y;
483
            rowHeight = parseInt(row.offsetHeight) / 2;
484
            if (row.offsetHeight == 0) {
485
                rowY      = this.getPosition(row.firstChild).y;
486
                rowHeight = parseInt(row.firstChild.offsetHeight) / 2;
487
            }
488
            // Because we always have to insert before, we need to offset the height a bit
489
            if (y > (rowY - rowHeight) && y < (rowY + rowHeight))
490
                // that's the row we're over
491
                // If it's the same as the current row, ignore it
492
                if (draggedRow.is(row)
493
                    || (config.onAllowDrop
494
                    && !config.onAllowDrop(draggedRow, row))
495
                    // If a row has nodrop class, then don't allow dropping (inspired by John Tarr and Famic)
496
                    || $(row).hasClass("nodrop"))
497
                        return null;
498
                else
499
                    return row;
500
        }
501
        return null;
502
    },
503
    processMouseup: function() {
504
        if (!this.currentTable || !this.dragObject)
505
            return null;
506
507
        var config      = this.currentTable.tableDnDConfig,
508
            droppedRow  = this.dragObject,
509
            parentLevel = 0,
510
            myLevel     = 0;
511
512
        // Unbind the event handlers
513
        $(document)
514
            .unbind(moveEvent, this.mousemove)
515
            .unbind(endEvent,  this.mouseup);
516
517
        config.hierarchyLevel
518
            && config.autoCleanRelations
519
            && $(this.currentTable.rows).first().find('td:first').children().each(function () {
520
                myLevel = $(this).parents('tr:first').data('level');
521
                myLevel
522
                    && $(this).parents('tr:first').data('level', --myLevel)
523
                    && $(this).remove();
524
            })
525
            && config.hierarchyLevel > 1
526
            && $(this.currentTable.rows).each(function () {
527
                myLevel = $(this).data('level');
528
                if (myLevel > 1) {
529
                    parentLevel = $(this).prev().data('level');
530
                    while (myLevel > parentLevel + 1) {
531
                        $(this).find('td:first').children(':first').remove();
532
                        $(this).data('level', --myLevel);
533
                    }
534
                }
535
            });
536
537
        // If we have a dragObject, then we need to release it,
538
        // The row will already have been moved to the right place so we just reset stuff
539
        config.onDragClass
540
            && $(droppedRow).removeClass(config.onDragClass)
541
            || $(droppedRow).css(config.onDropStyle);
542
543
        this.dragObject = null;
544
        // Call the onDrop method if there is one
545
        config.onDrop
546
            && this.originalOrder != this.currentOrder()
547
            && $(droppedRow).hide().fadeIn('fast')
548
            && config.onDrop(this.currentTable, droppedRow);
549
550
        this.currentTable = null; // let go of the table too
551
    },
552
    mouseup: function(e) {
553
        e && e.preventDefault();
554
        $.tableDnD.processMouseup();
555
        return false;
556
    },
557
    jsonize: function(pretify) {
558
        var table = this.currentTable;
559
        if (pretify)
560
            return JSON.stringify(
561
                this.tableData(table),
562
                null,
563
                table.tableDnDConfig.jsonPretifySeparator
564
            );
565
        return JSON.stringify(this.tableData(table));
566
    },
567
    serialize: function() {
568
        return $.param(this.tableData(this.currentTable));
569
    },
570
    serializeTable: function(table) {
571
        var result = "";
572
        var paramName = table.tableDnDConfig.serializeParamName || table.id;
573
        var rows = table.rows;
574
        for (var i=0; i<rows.length; i++) {
575
            if (result.length > 0) result += "&";
576
            var rowId = rows[i].id;
577
            if (rowId && table.tableDnDConfig && table.tableDnDConfig.serializeRegexp) {
578
                rowId = rowId.match(table.tableDnDConfig.serializeRegexp)[0];
579
                result += paramName + '[]=' + rowId;
580
            }
581
        }
582
        return result;
583
    },
584
    serializeTables: function() {
585
        var result = [];
586
        $('table').each(function() {
587
            this.id && result.push($.param(this.tableData(this)));
588
        });
589
        return result.join('&');
590
    },
591
    tableData: function (table) {
592
        var config = table.tableDnDConfig,
593
            previousIDs  = [],
594
            currentLevel = 0,
595
            indentLevel  = 0,
596
            rowID        = null,
597
            data         = {},
598
            getSerializeRegexp,
599
            paramName,
600
            currentID,
601
            rows;
602
603
        if (!table)
604
            table = this.currentTable;
605
        if (!table || !table.id || !table.rows || !table.rows.length)
606
            return {error: { code: 500, message: "Not a valid table, no serializable unique id provided."}};
607
608
        rows      = config.autoCleanRelations
609
                        && table.rows
610
                        || $.makeArray(table.rows);
611
        paramName = config.serializeParamName || table.id;
612
        currentID = paramName;
613
614
        getSerializeRegexp = function (rowId) {
615
            if (rowId && config && config.serializeRegexp)
616
                return rowId.match(config.serializeRegexp)[0];
617
            return rowId;
618
        };
619
620
        data[currentID] = [];
621
        !config.autoCleanRelations
622
            && $(rows[0]).data('level')
623
            && rows.unshift({id: 'undefined'});
624
625
626
627
        for (var i=0; i < rows.length; i++) {
628
            if (config.hierarchyLevel) {
629
                indentLevel = $(rows[i]).data('level') || 0;
630
                if (indentLevel == 0) {
631
                    currentID   = paramName;
632
                    previousIDs = [];
633
                }
634
                else if (indentLevel > currentLevel) {
635
                    previousIDs.push([currentID, currentLevel]);
636
                    currentID = getSerializeRegexp(rows[i-1].id);
637
                }
638
                else if (indentLevel < currentLevel) {
639
                    for (var h = 0; h < previousIDs.length; h++) {
640
                        if (previousIDs[h][1] == indentLevel)
641
                            currentID         = previousIDs[h][0];
642
                        if (previousIDs[h][1] >= currentLevel)
643
                            previousIDs[h][1] = 0;
644
                    }
645
                }
646
                currentLevel = indentLevel;
647
648
                if (!$.isArray(data[currentID]))
649
                    data[currentID] = [];
650
                rowID = getSerializeRegexp(rows[i].id);
651
                rowID && data[currentID].push(rowID);
652
            }
653
            else {
654
                rowID = getSerializeRegexp(rows[i].id);
655
                rowID && data[currentID].push(rowID);
656
            }
657
        }
658
        return data;
659
    }
660
};
661
662
jQuery.fn.extend(
663
    {
664
        tableDnD             : $.tableDnD.build,
665
        tableDnDUpdate       : $.tableDnD.updateTables,
666
        tableDnDSerialize    : $.proxy($.tableDnD.serialize, $.tableDnD),
667
        tableDnDSerializeAll : $.tableDnD.serializeTables,
668
        tableDnDData         : $.proxy($.tableDnD.tableData, $.tableDnD)
669
    }
670
);
671
672
}(jQuery, window, window.document);
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/about.tt (-1 / +3 lines)
Lines 778-783 Link Here
778
778
779
            <h2>Select2</h2>
779
            <h2>Select2</h2>
780
            <p>The <a href="http://select2.github.io/select2/">Select2</a> library is licensed under <a href="https://github.com/select2/select2/blob/stable/3.5/LICENSE">the Apache License, Version 2.0 (the "Apache License") or the GNU General Public License version 2 (the "GPL License")</a>.</p>
780
            <p>The <a href="http://select2.github.io/select2/">Select2</a> library is licensed under <a href="https://github.com/select2/select2/blob/stable/3.5/LICENSE">the Apache License, Version 2.0 (the "Apache License") or the GNU General Public License version 2 (the "GPL License")</a>.</p>
781
782
            <h2>jquery.tablednd.js</h2>
783
            <p>The <a href="https://github.com/isocra/TableDnD">TableDnD plug-in for jQuery</a> by Denis Howlett is licensed under the <a href="http://opensource.org/licenses/mit-license.php">MIT License</a>.</p>
781
        </div>
784
        </div>
782
785
783
        <div id="translations">
786
        <div id="translations">
784
- 

Return to bug 14899