- Latest version of slickgrid.
This commit is contained in:
Matt Gilman 2014-12-10 10:12:43 -05:00
parent 658131de13
commit 4c959f7298
25 changed files with 6262 additions and 5461 deletions

View File

@ -48,7 +48,7 @@
<script type="text/javascript" src="js/jquery/modal/jquery.modal.js?${project.version}"></script> <script type="text/javascript" src="js/jquery/modal/jquery.modal.js?${project.version}"></script>
<script type="text/javascript" src="js/jquery/minicolors/jquery.minicolors.min.js"></script> <script type="text/javascript" src="js/jquery/minicolors/jquery.minicolors.min.js"></script>
<script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script> <script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script>
<script type="text/javascript" src="js/jquery/jquery.event.drag-2.0.min.js"></script> <script type="text/javascript" src="js/jquery/jquery.event.drag-2.2.min.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellrangeselector.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellrangeselector.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellselectionmodel.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellselectionmodel.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.rowselectionmodel.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.rowselectionmodel.js"></script>

View File

@ -36,7 +36,7 @@
<script type="text/javascript" src="js/jquery/jquery.each.js"></script> <script type="text/javascript" src="js/jquery/jquery.each.js"></script>
<script type="text/javascript" src="js/jquery/jquery-ui-1.8.10.custom.min.js"></script> <script type="text/javascript" src="js/jquery/jquery-ui-1.8.10.custom.min.js"></script>
<script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script> <script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script>
<script type="text/javascript" src="js/jquery/jquery.event.drag-2.0.min.js"></script> <script type="text/javascript" src="js/jquery/jquery.event.drag-2.2.min.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellrangeselector.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellrangeselector.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellselectionmodel.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellselectionmodel.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.rowselectionmodel.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.rowselectionmodel.js"></script>

View File

@ -36,7 +36,7 @@
<script type="text/javascript" src="js/jquery/jquery.each.js"></script> <script type="text/javascript" src="js/jquery/jquery.each.js"></script>
<script type="text/javascript" src="js/jquery/jquery-ui-1.8.10.custom.min.js"></script> <script type="text/javascript" src="js/jquery/jquery-ui-1.8.10.custom.min.js"></script>
<script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script> <script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script>
<script type="text/javascript" src="js/jquery/jquery.event.drag-2.0.min.js"></script> <script type="text/javascript" src="js/jquery/jquery.event.drag-2.2.min.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellrangeselector.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellrangeselector.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellselectionmodel.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellselectionmodel.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.rowselectionmodel.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.rowselectionmodel.js"></script>

View File

@ -36,7 +36,7 @@
<script type="text/javascript" src="js/jquery/jquery.each.js"></script> <script type="text/javascript" src="js/jquery/jquery.each.js"></script>
<script type="text/javascript" src="js/jquery/jquery-ui-1.8.10.custom.min.js"></script> <script type="text/javascript" src="js/jquery/jquery-ui-1.8.10.custom.min.js"></script>
<script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script> <script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script>
<script type="text/javascript" src="js/jquery/jquery.event.drag-2.0.min.js"></script> <script type="text/javascript" src="js/jquery/jquery.event.drag-2.2.min.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellrangeselector.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellrangeselector.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellselectionmodel.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellselectionmodel.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.rowselectionmodel.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.rowselectionmodel.js"></script>

View File

@ -38,7 +38,7 @@
<script type="text/javascript" src="js/jquery/jquery.each.js"></script> <script type="text/javascript" src="js/jquery/jquery.each.js"></script>
<script type="text/javascript" src="js/jquery/jquery-ui-1.8.10.custom.min.js"></script> <script type="text/javascript" src="js/jquery/jquery-ui-1.8.10.custom.min.js"></script>
<script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script> <script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script>
<script type="text/javascript" src="js/jquery/jquery.event.drag-2.0.min.js"></script> <script type="text/javascript" src="js/jquery/jquery.event.drag-2.2.min.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellrangeselector.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellrangeselector.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellselectionmodel.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellselectionmodel.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.rowselectionmodel.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.rowselectionmodel.js"></script>

View File

@ -38,7 +38,7 @@
<script type="text/javascript" src="js/jquery/jquery.ellipsis.js"></script> <script type="text/javascript" src="js/jquery/jquery.ellipsis.js"></script>
<script type="text/javascript" src="js/jquery/jquery.each.js"></script> <script type="text/javascript" src="js/jquery/jquery.each.js"></script>
<script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script> <script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script>
<script type="text/javascript" src="js/jquery/jquery.event.drag-2.0.min.js"></script> <script type="text/javascript" src="js/jquery/jquery.event.drag-2.2.min.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellrangeselector.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellrangeselector.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellselectionmodel.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellselectionmodel.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.rowselectionmodel.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.rowselectionmodel.js"></script>

View File

@ -37,7 +37,7 @@
<script type="text/javascript" src="js/jquery/jquery.each.js"></script> <script type="text/javascript" src="js/jquery/jquery.each.js"></script>
<script type="text/javascript" src="js/jquery/jquery-ui-1.8.10.custom.min.js"></script> <script type="text/javascript" src="js/jquery/jquery-ui-1.8.10.custom.min.js"></script>
<script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script> <script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script>
<script type="text/javascript" src="js/jquery/jquery.event.drag-2.0.min.js"></script> <script type="text/javascript" src="js/jquery/jquery.event.drag-2.2.min.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellrangeselector.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellrangeselector.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellselectionmodel.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellselectionmodel.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.rowselectionmodel.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.rowselectionmodel.js"></script>

View File

@ -38,7 +38,7 @@
<script type="text/javascript" src="js/jquery/jquery.each.js"></script> <script type="text/javascript" src="js/jquery/jquery.each.js"></script>
<script type="text/javascript" src="js/jquery/jquery-ui-1.8.10.custom.min.js"></script> <script type="text/javascript" src="js/jquery/jquery-ui-1.8.10.custom.min.js"></script>
<script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script> <script type="text/javascript" src="js/jquery/qtip2/jquery.qtip.min.js"></script>
<script type="text/javascript" src="js/jquery/jquery.event.drag-2.0.min.js"></script> <script type="text/javascript" src="js/jquery/jquery.event.drag-2.2.min.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellrangeselector.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellrangeselector.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellselectionmodel.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.cellselectionmodel.js"></script>
<script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.rowselectionmodel.js"></script> <script type="text/javascript" src="js/jquery/slickgrid/plugins/slick.rowselectionmodel.js"></script>

View File

@ -1,194 +0,0 @@
/*!
* jquery.event.drag - v 2.0.0
* Copyright (c) 2010 Three Dub Media - http://threedubmedia.com
* Open Source MIT License - http://threedubmedia.com/code/license
*/
;
(function (f) {
f.fn.drag = function (b, a, d) {
var e = typeof b == "string" ? b : "", k = f.isFunction(b) ? b : f.isFunction(a) ? a : null;
if (e.indexOf("drag") !== 0)
e = "drag" + e;
d = (b == k ? a : d) || {};
return k ? this.bind(e, d, k) : this.trigger(e)
};
var i = f.event, h = i.special, c = h.drag = {defaults: {which: 1, distance: 0, not: ":input", handle: null, relative: false, drop: true, click: false}, datakey: "dragdata", livekey: "livedrag", add: function (b) {
var a = f.data(this, c.datakey), d = b.data || {};
a.related += 1;
if (!a.live && b.selector) {
a.live = true;
i.add(this, "draginit." + c.livekey, c.delegate)
}
f.each(c.defaults, function (e) {
if (d[e] !== undefined)
a[e] = d[e]
})
}, remove: function () {
f.data(this, c.datakey).related -= 1
}, setup: function () {
if (!f.data(this, c.datakey)) {
var b = f.extend({related: 0}, c.defaults);
f.data(this, c.datakey, b);
i.add(this, "mousedown", c.init, b);
this.attachEvent && this.attachEvent("ondragstart", c.dontstart)
}
}, teardown: function () {
if (!f.data(this, c.datakey).related) {
f.removeData(this, c.datakey);
i.remove(this, "mousedown", c.init);
i.remove(this, "draginit", c.delegate);
c.textselect(true);
this.detachEvent && this.detachEvent("ondragstart", c.dontstart)
}
}, init: function (b) {
var a = b.data, d;
if (!(a.which > 0 && b.which != a.which))
if (!f(b.target).is(a.not))
if (!(a.handle && !f(b.target).closest(a.handle, b.currentTarget).length)) {
a.propagates = 1;
a.interactions = [c.interaction(this, a)];
a.target = b.target;
a.pageX = b.pageX;
a.pageY = b.pageY;
a.dragging = null;
d = c.hijack(b, "draginit", a);
if (a.propagates) {
if ((d = c.flatten(d)) && d.length) {
a.interactions = [];
f.each(d, function () {
a.interactions.push(c.interaction(this, a))
})
}
a.propagates = a.interactions.length;
a.drop !== false && h.drop && h.drop.handler(b, a);
c.textselect(false);
i.add(document, "mousemove mouseup", c.handler, a);
return false
}
}
}, interaction: function (b, a) {
return{drag: b, callback: new c.callback, droppable: [], offset: f(b)[a.relative ? "position" : "offset"]() || {top: 0, left: 0}}
}, handler: function (b) {
var a = b.data;
switch (b.type) {
case !a.dragging && "mousemove":
if (Math.pow(b.pageX - a.pageX, 2) + Math.pow(b.pageY - a.pageY, 2) < Math.pow(a.distance, 2))
break;
b.target = a.target;
c.hijack(b, "dragstart", a);
if (a.propagates)
a.dragging = true;
case "mousemove":
if (a.dragging) {
c.hijack(b, "drag", a);
if (a.propagates) {
a.drop !== false && h.drop && h.drop.handler(b, a);
break
}
b.type = "mouseup"
}
case "mouseup":
i.remove(document, "mousemove mouseup", c.handler);
if (a.dragging) {
a.drop !== false && h.drop && h.drop.handler(b, a);
c.hijack(b, "dragend", a)
}
c.textselect(true);
if (a.click === false && a.dragging) {
jQuery.event.triggered = true;
setTimeout(function () {
jQuery.event.triggered = false
}, 20);
a.dragging = false
}
break
}
}, delegate: function (b) {
var a = [], d, e = f.data(this, "events") || {};
f.each(e.live || [], function (k, j) {
if (j.preType.indexOf("drag") === 0)
if (d = f(b.target).closest(j.selector, b.currentTarget)[0]) {
i.add(d, j.origType + "." + c.livekey, j.origHandler, j.data);
f.inArray(d, a) < 0 && a.push(d)
}
});
if (!a.length)
return false;
return f(a).bind("dragend." + c.livekey, function () {
i.remove(this, "." + c.livekey)
})
}, hijack: function (b, a, d, e, k) {
if (d) {
var j = {event: b.originalEvent, type: b.type}, n = a.indexOf("drop") ? "drag" : "drop", l, o = e || 0, g, m;
e = !isNaN(e) ? e : d.interactions.length;
b.type = a;
b.originalEvent = null;
d.results = [];
do
if (g = d.interactions[o])
if (!(a !== "dragend" && g.cancelled)) {
m = c.properties(b, d, g);
g.results = [];
f(k || g[n] || d.droppable).each(function (q, p) {
l = (m.target = p) ? i.handle.call(p, b, m) : null;
if (l === false) {
if (n == "drag") {
g.cancelled = true;
d.propagates -= 1
}
if (a == "drop")
g[n][q] = null
} else if (a == "dropinit")
g.droppable.push(c.element(l) || p);
if (a == "dragstart")
g.proxy = f(c.element(l) || g.drag)[0];
g.results.push(l);
delete b.result;
if (a !== "dropinit")
return l
});
d.results[o] = c.flatten(g.results);
if (a == "dropinit")
g.droppable = c.flatten(g.droppable);
a == "dragstart" && !g.cancelled && m.update()
}
while (++o < e);
b.type = j.type;
b.originalEvent = j.event;
return c.flatten(d.results)
}
}, properties: function (b, a, d) {
var e = d.callback;
e.drag = d.drag;
e.proxy = d.proxy || d.drag;
e.startX = a.pageX;
e.startY = a.pageY;
e.deltaX = b.pageX - a.pageX;
e.deltaY = b.pageY - a.pageY;
e.originalX = d.offset.left;
e.originalY = d.offset.top;
e.offsetX = b.pageX - (a.pageX - e.originalX);
e.offsetY = b.pageY - (a.pageY - e.originalY);
e.drop = c.flatten((d.drop || []).slice());
e.available = c.flatten((d.droppable || []).slice());
return e
}, element: function (b) {
if (b && (b.jquery || b.nodeType == 1))
return b
}, flatten: function (b) {
return f.map(b, function (a) {
return a && a.jquery ? f.makeArray(a) : a && a.length ? c.flatten(a) : a
})
}, textselect: function (b) {
f(document)[b ? "unbind" : "bind"]("selectstart", c.dontstart).attr("unselectable", b ? "off" : "on").css("MozUserSelect", b ? "" : "none")
}, dontstart: function () {
return false
}, callback: function () {
}};
c.callback.prototype = {update: function () {
h.drop && this.available.length && f.each(this.available, function (b) {
h.drop.locate(this, b)
})
}};
h.draginit = h.dragstart = h.dragend = c
})(jQuery);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,20 @@
Copyright (c) 2010 Michael Leibman, http://github.com/mleibman/slickgrid
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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 851 B

View File

@ -77,11 +77,11 @@ classes should alter those!
} }
.slick-group-toggle.expanded { .slick-group-toggle.expanded {
background: url(../../../../images/collapse.gif) no-repeat center center; background: url(images/collapse.gif) no-repeat center center;
} }
.slick-group-toggle.collapsed { .slick-group-toggle.collapsed {
background: url(../../../../images/expand.gif) no-repeat center center; background: url(images/expand.gif) no-repeat center center;
} }
.slick-group-totals { .slick-group-totals {
@ -103,7 +103,7 @@ classes should alter those!
background: silver !important; background: silver !important;
} }
.slick-row[row$="1"], .slick-row[row$="3"], .slick-row[row$="5"], .slick-row[row$="7"], .slick-row[row$="9"] { .slick-row.odd {
background: #fafafa; background: #fafafa;
} }
@ -118,4 +118,18 @@ classes should alter those!
.slick-cell.invalid { .slick-cell.invalid {
border-color: red; border-color: red;
-moz-animation-duration: 0.2s;
-webkit-animation-duration: 0.2s;
-moz-animation-name: slickgrid-invalid-hilite;
-webkit-animation-name: slickgrid-invalid-hilite;
}
@-moz-keyframes slickgrid-invalid-hilite {
from { box-shadow: 0 0 6px red; }
to { box-shadow: none; }
}
@-webkit-keyframes slickgrid-invalid-hilite {
from { box-shadow: 0 0 6px red; }
to { box-shadow: none; }
} }

View File

@ -12,7 +12,6 @@ classes should alter those!
} }
.slick-header-columns, .slick-headerrow-columns { .slick-header-columns, .slick-headerrow-columns {
width: 999999px;
position: relative; position: relative;
white-space: nowrap; white-space: nowrap;
cursor: default; cursor: default;
@ -23,6 +22,7 @@ classes should alter those!
position: relative; position: relative;
display: inline-block; display: inline-block;
overflow: hidden; overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis; text-overflow: ellipsis;
height: 16px; height: 16px;
line-height: 16px; line-height: 16px;
@ -48,6 +48,8 @@ classes should alter those!
width: 8px; width: 8px;
height: 5px; height: 5px;
margin-left: 4px; margin-left: 4px;
margin-top: 6px;
/*float: left;*/
} }
.slick-sort-indicator-desc { .slick-sort-indicator-desc {
@ -86,21 +88,17 @@ classes should alter those!
.slick-cell, .slick-headerrow-column { .slick-cell, .slick-headerrow-column {
position: absolute; position: absolute;
border: 1px solid transparent; border: 1px solid transparent;
border-right: 1px dotted silver; border-right: 1px dotted silver;
border-bottom-color: silver; border-bottom-color: silver;
overflow: hidden; overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle; vertical-align: middle;
z-index: 1; z-index: 1;
padding: 1px 2px 2px 1px; padding: 1px 2px 2px 1px;
margin: 0; margin: 0;
white-space: nowrap; white-space: nowrap;
cursor: default; cursor: default;
} }
@ -116,6 +114,7 @@ classes should alter those!
background: rgba(0, 0, 255, 0.2); background: rgba(0, 0, 255, 0.2);
-webkit-transition: all 0.5s; -webkit-transition: all 0.5s;
-moz-transition: all 0.5s; -moz-transition: all 0.5s;
-o-transition: all 0.5s;
transition: all 0.5s; transition: all 0.5s;
} }

View File

@ -1,45 +1,80 @@
(function ($) { (function ($) {
// register namespace // Register namespace
$.extend(true, window, { $.extend(true, window, {
"Slick": { "Slick": {
"AutoTooltips": AutoTooltips "AutoTooltips": AutoTooltips
} }
}); });
/**
* AutoTooltips plugin to show/hide tooltips when columns are too narrow to fit content.
* @constructor
* @param {boolean} [options.enableForCells=true] - Enable tooltip for grid cells
* @param {boolean} [options.enableForHeaderCells=false] - Enable tooltip for header cells
* @param {number} [options.maxToolTipLength=null] - The maximum length for a tooltip
*/
function AutoTooltips(options) { function AutoTooltips(options) {
var _grid; var _grid;
var _self = this; var _self = this;
var _defaults = { var _defaults = {
enableForCells: true,
enableForHeaderCells: false,
maxToolTipLength: null maxToolTipLength: null
}; };
/**
* Initialize plugin.
*/
function init(grid) { function init(grid) {
options = $.extend(true, {}, _defaults, options); options = $.extend(true, {}, _defaults, options);
_grid = grid; _grid = grid;
_grid.onMouseEnter.subscribe(handleMouseEnter); if (options.enableForCells) _grid.onMouseEnter.subscribe(handleMouseEnter);
if (options.enableForHeaderCells) _grid.onHeaderMouseEnter.subscribe(handleHeaderMouseEnter);
} }
/**
* Destroy plugin.
*/
function destroy() { function destroy() {
_grid.onMouseEnter.unsubscribe(handleMouseEnter); if (options.enableForCells) _grid.onMouseEnter.unsubscribe(handleMouseEnter);
if (options.enableForHeaderCells) _grid.onHeaderMouseEnter.unsubscribe(handleHeaderMouseEnter);
} }
function handleMouseEnter(e, args) { /**
* Handle mouse entering grid cell to add/remove tooltip.
* @param {jQuery.Event} e - The event
*/
function handleMouseEnter(e) {
var cell = _grid.getCellFromEvent(e); var cell = _grid.getCellFromEvent(e);
if (cell) { if (cell) {
var node = _grid.getCellNode(cell.row, cell.cell); var $node = $(_grid.getCellNode(cell.row, cell.cell));
if ($(node).innerWidth() < node.scrollWidth) { var text;
var text = $.trim($(node).text()); if ($node.innerWidth() < $node[0].scrollWidth) {
text = $.trim($node.text());
if (options.maxToolTipLength && text.length > options.maxToolTipLength) { if (options.maxToolTipLength && text.length > options.maxToolTipLength) {
text = text.substr(0, options.maxToolTipLength - 3) + "..."; text = text.substr(0, options.maxToolTipLength - 3) + "...";
} }
$(node).attr("title", text);
} else { } else {
$(node).attr("title", ""); text = "";
} }
$node.attr("title", text);
} }
} }
/**
* Handle mouse entering header cell to add/remove tooltip.
* @param {jQuery.Event} e - The event
* @param {object} args.column - The column definition
*/
function handleHeaderMouseEnter(e, args) {
var column = args.column,
$node = $(e.target).closest(".slick-header-column");
if (!column.toolTip) {
$node.attr("title", ($node.innerWidth() < $node[0].scrollWidth) ? column.name : "");
}
}
// Public API
$.extend(this, { $.extend(this, {
"init": init, "init": init,
"destroy": destroy "destroy": destroy

View File

@ -20,6 +20,7 @@
function CellRangeDecorator(grid, options) { function CellRangeDecorator(grid, options) {
var _elem; var _elem;
var _defaults = { var _defaults = {
selectionCssClass: 'slick-range-decorator',
selectionCss: { selectionCss: {
"zIndex": "9999", "zIndex": "9999",
"border": "2px dashed red" "border": "2px dashed red"
@ -32,6 +33,7 @@
function show(range) { function show(range) {
if (!_elem) { if (!_elem) {
_elem = $("<div></div>", {css: options.selectionCss}) _elem = $("<div></div>", {css: options.selectionCss})
.addClass(options.selectionCssClass)
.css("position", "absolute") .css("position", "absolute")
.appendTo(grid.getCanvasNode()); .appendTo(grid.getCanvasNode());
} }

View File

@ -13,6 +13,7 @@
var _dragging; var _dragging;
var _decorator; var _decorator;
var _self = this; var _self = this;
var _handler = new Slick.EventHandler();
var _defaults = { var _defaults = {
selectionCss: { selectionCss: {
"border": "2px dashed blue" "border": "2px dashed blue"
@ -25,17 +26,15 @@
_decorator = new Slick.CellRangeDecorator(grid, options); _decorator = new Slick.CellRangeDecorator(grid, options);
_grid = grid; _grid = grid;
_canvas = _grid.getCanvasNode(); _canvas = _grid.getCanvasNode();
_grid.onDragInit.subscribe(handleDragInit); _handler
_grid.onDragStart.subscribe(handleDragStart); .subscribe(_grid.onDragInit, handleDragInit)
_grid.onDrag.subscribe(handleDrag); .subscribe(_grid.onDragStart, handleDragStart)
_grid.onDragEnd.subscribe(handleDragEnd); .subscribe(_grid.onDrag, handleDrag)
.subscribe(_grid.onDragEnd, handleDragEnd);
} }
function destroy() { function destroy() {
_grid.onDragInit.unsubscribe(handleDragInit); _handler.unsubscribeAll();
_grid.onDragStart.unsubscribe(handleDragStart);
_grid.onDrag.unsubscribe(handleDrag);
_grid.onDragEnd.unsubscribe(handleDragEnd);
} }
function handleDragInit(e, dd) { function handleDragInit(e, dd) {
@ -55,6 +54,8 @@
return; return;
} }
_grid.focus();
var start = _grid.getCellFromPoint( var start = _grid.getCellFromPoint(
dd.startX - $(_canvas).offset().left, dd.startX - $(_canvas).offset().left,
dd.startY - $(_canvas).offset().top); dd.startY - $(_canvas).offset().top);
@ -104,6 +105,7 @@
$.extend(this, { $.extend(this, {
"init": init, "init": init,
"destroy": destroy, "destroy": destroy,
"onBeforeCellRangeSelected": new Slick.Event(), "onBeforeCellRangeSelected": new Slick.Event(),
"onCellRangeSelected": new Slick.Event() "onCellRangeSelected": new Slick.Event()
}); });

View File

@ -28,6 +28,7 @@
_grid = grid; _grid = grid;
_canvas = _grid.getCanvasNode(); _canvas = _grid.getCanvasNode();
_grid.onActiveCellChanged.subscribe(handleActiveCellChange); _grid.onActiveCellChanged.subscribe(handleActiveCellChange);
_grid.onKeyDown.subscribe(handleKeyDown);
grid.registerPlugin(_selector); grid.registerPlugin(_selector);
_selector.onCellRangeSelected.subscribe(handleCellRangeSelected); _selector.onCellRangeSelected.subscribe(handleCellRangeSelected);
_selector.onBeforeCellRangeSelected.subscribe(handleBeforeCellRangeSelected); _selector.onBeforeCellRangeSelected.subscribe(handleBeforeCellRangeSelected);
@ -35,6 +36,7 @@
function destroy() { function destroy() {
_grid.onActiveCellChanged.unsubscribe(handleActiveCellChange); _grid.onActiveCellChanged.unsubscribe(handleActiveCellChange);
_grid.onKeyDown.unsubscribe(handleKeyDown);
_selector.onCellRangeSelected.unsubscribe(handleCellRangeSelected); _selector.onCellRangeSelected.unsubscribe(handleCellRangeSelected);
_selector.onBeforeCellRangeSelected.unsubscribe(handleBeforeCellRangeSelected); _selector.onBeforeCellRangeSelected.unsubscribe(handleBeforeCellRangeSelected);
_grid.unregisterPlugin(_selector); _grid.unregisterPlugin(_selector);
@ -74,16 +76,78 @@
} }
function handleActiveCellChange(e, args) { function handleActiveCellChange(e, args) {
if (_options.selectActiveCell) { if (_options.selectActiveCell && args.row != null && args.cell != null) {
setSelectedRanges([new Slick.Range(args.row, args.cell)]); setSelectedRanges([new Slick.Range(args.row, args.cell)]);
} }
} }
function handleKeyDown(e) {
/***
* Кey codes
* 37 left
* 38 up
* 39 right
* 40 down
*/
var ranges, last;
var active = _grid.getActiveCell();
if ( active && e.shiftKey && !e.ctrlKey && !e.altKey &&
(e.which == 37 || e.which == 39 || e.which == 38 || e.which == 40) ) {
ranges = getSelectedRanges();
if (!ranges.length)
ranges.push(new Slick.Range(active.row, active.cell));
// keyboard can work with last range only
last = ranges.pop();
// can't handle selection out of active cell
if (!last.contains(active.row, active.cell))
last = new Slick.Range(active.row, active.cell);
var dRow = last.toRow - last.fromRow,
dCell = last.toCell - last.fromCell,
// walking direction
dirRow = active.row == last.fromRow ? 1 : -1,
dirCell = active.cell == last.fromCell ? 1 : -1;
if (e.which == 37) {
dCell -= dirCell;
} else if (e.which == 39) {
dCell += dirCell ;
} else if (e.which == 38) {
dRow -= dirRow;
} else if (e.which == 40) {
dRow += dirRow;
}
// define new selection range
var new_last = new Slick.Range(active.row, active.cell, active.row + dirRow*dRow, active.cell + dirCell*dCell);
if (removeInvalidRanges([new_last]).length) {
ranges.push(new_last);
var viewRow = dirRow > 0 ? new_last.toRow : new_last.fromRow;
var viewCell = dirCell > 0 ? new_last.toCell : new_last.fromCell;
_grid.scrollRowIntoView(viewRow);
_grid.scrollCellIntoView(viewRow, viewCell);
}
else
ranges.push(last);
setSelectedRanges(ranges);
e.preventDefault();
e.stopPropagation();
}
}
$.extend(this, { $.extend(this, {
"getSelectedRanges": getSelectedRanges, "getSelectedRanges": getSelectedRanges,
"setSelectedRanges": setSelectedRanges, "setSelectedRanges": setSelectedRanges,
"init": init, "init": init,
"destroy": destroy, "destroy": destroy,
"onSelectedRangesChanged": new Slick.Event() "onSelectedRangesChanged": new Slick.Event()
}); });
} }

View File

@ -90,7 +90,7 @@
} }
function handleActiveCellChange(e, data) { function handleActiveCellChange(e, data) {
if (_options.selectActiveRow) { if (_options.selectActiveRow && data.row != null) {
setSelectedRanges([new Slick.Range(data.row, 0, data.row, _grid.getColumns().length - 1)]); setSelectedRanges([new Slick.Range(data.row, 0, data.row, _grid.getColumns().length - 1)]);
} }
} }
@ -134,13 +134,14 @@
return false; return false;
} }
if (!_grid.getOptions().multiSelect || (
!e.ctrlKey && !e.shiftKey && !e.metaKey)) {
return false;
}
var selection = rangesToRows(_ranges); var selection = rangesToRows(_ranges);
var idx = $.inArray(cell.row, selection); var idx = $.inArray(cell.row, selection);
if (!e.ctrlKey && !e.shiftKey && !e.metaKey) {
return false;
}
else if (_grid.getOptions().multiSelect) {
if (idx === -1 && (e.ctrlKey || e.metaKey)) { if (idx === -1 && (e.ctrlKey || e.metaKey)) {
selection.push(cell.row); selection.push(cell.row);
_grid.setActiveCell(cell.row, cell.cell); _grid.setActiveCell(cell.row, cell.cell);
@ -162,7 +163,6 @@
selection.push(last); selection.push(last);
_grid.setActiveCell(cell.row, cell.cell); _grid.setActiveCell(cell.row, cell.cell);
} }
}
_ranges = rowsToRanges(selection); _ranges = rowsToRanges(selection);
setSelectedRanges(_ranges); setSelectedRanges(_ranges);
@ -174,10 +174,13 @@
$.extend(this, { $.extend(this, {
"getSelectedRows": getSelectedRows, "getSelectedRows": getSelectedRows,
"setSelectedRows": setSelectedRows, "setSelectedRows": setSelectedRows,
"getSelectedRanges": getSelectedRanges, "getSelectedRanges": getSelectedRanges,
"setSelectedRanges": setSelectedRanges, "setSelectedRanges": setSelectedRanges,
"init": init, "init": init,
"destroy": destroy, "destroy": destroy,
"onSelectedRangesChanged": new Slick.Event() "onSelectedRangesChanged": new Slick.Event()
}); });
} }

View File

@ -16,6 +16,7 @@
"Group": Group, "Group": Group,
"GroupTotals": GroupTotals, "GroupTotals": GroupTotals,
"EditorLock": EditorLock, "EditorLock": EditorLock,
/*** /***
* A global singleton editor lock. * A global singleton editor lock.
* @class GlobalEditorLock * @class GlobalEditorLock
@ -138,6 +139,8 @@
handler: handler handler: handler
}); });
event.subscribe(handler); event.subscribe(handler);
return this; // allow chaining
}; };
this.unsubscribe = function (event, handler) { this.unsubscribe = function (event, handler) {
@ -150,6 +153,8 @@
return; return;
} }
} }
return this; // allow chaining
}; };
this.unsubscribeAll = function () { this.unsubscribeAll = function () {
@ -158,6 +163,8 @@
handlers[i].event.unsubscribe(handlers[i].handler); handlers[i].event.unsubscribe(handlers[i].handler);
} }
handlers = []; handlers = [];
return this; // allow chaining
} }
} }
@ -264,7 +271,13 @@
*/ */
function Group() { function Group() {
this.__group = true; this.__group = true;
this.__updated = false;
/**
* Grouping level, starting with 0.
* @property level
* @type {Number}
*/
this.level = 0;
/*** /***
* Number of rows in the group. * Number of rows in the group.
@ -300,6 +313,28 @@
* @type {GroupTotals} * @type {GroupTotals}
*/ */
this.totals = null; this.totals = null;
/**
* Rows that are part of the group.
* @property rows
* @type {Array}
*/
this.rows = [];
/**
* Sub-groups that are part of the group.
* @property groups
* @type {Array}
*/
this.groups = null;
/**
* A unique key used to identify the group. This key can be used in calls to DataView
* collapseGroup() or expandGroup().
* @property groupingKey
* @type {Object}
*/
this.groupingKey = null;
} }
Group.prototype = new NonDataItem(); Group.prototype = new NonDataItem();
@ -313,7 +348,8 @@
Group.prototype.equals = function (group) { Group.prototype.equals = function (group) {
return this.value === group.value && return this.value === group.value &&
this.count === group.count && this.count === group.count &&
this.collapsed === group.collapsed; this.collapsed === group.collapsed &&
this.title === group.title;
}; };
/*** /***
@ -334,6 +370,14 @@
* @type {Group} * @type {Group}
*/ */
this.group = null; this.group = null;
/***
* Whether the totals have been fully initialized / calculated.
* Will be set to false for lazy-calculated group totals.
* @param initialized
* @type {Boolean}
*/
this.initialized = false;
} }
GroupTotals.prototype = new NonDataItem(); GroupTotals.prototype = new NonDataItem();

View File

@ -50,15 +50,23 @@
var filterCache = []; var filterCache = [];
// grouping // grouping
var groupingGetter; var groupingInfoDefaults = {
var groupingGetterIsAFn; getter: null,
var groupingFormatter; formatter: null,
var groupingComparer; comparer: function(a, b) { return a.value - b.value; },
predefinedValues: [],
aggregators: [],
aggregateEmpty: false,
aggregateCollapsed: false,
aggregateChildGroups: false,
collapsed: false,
displayTotalsRow: true,
lazyTotalsCalculation: false
};
var groupingInfos = [];
var groups = []; var groups = [];
var collapsedGroups = {}; var toggledGroupsByLevel = [];
var aggregators; var groupingDelimiter = ':|:';
var aggregateCollapsed = false;
var compiledAccumulators;
var pagesize = 0; var pagesize = 0;
var pagenum = 0; var pagenum = 0;
@ -207,35 +215,67 @@
refresh(); refresh();
} }
function groupBy(valueGetter, valueFormatter, sortComparer) { function getGrouping() {
return groupingInfos;
}
function setGrouping(groupingInfo) {
if (!options.groupItemMetadataProvider) { if (!options.groupItemMetadataProvider) {
options.groupItemMetadataProvider = new Slick.Data.GroupItemMetadataProvider(); options.groupItemMetadataProvider = new Slick.Data.GroupItemMetadataProvider();
} }
groupingGetter = valueGetter;
groupingGetterIsAFn = typeof groupingGetter === "function";
groupingFormatter = valueFormatter;
groupingComparer = sortComparer;
collapsedGroups = {};
groups = []; groups = [];
refresh(); toggledGroupsByLevel = [];
} groupingInfo = groupingInfo || [];
groupingInfos = (groupingInfo instanceof Array) ? groupingInfo : [groupingInfo];
function setAggregators(groupAggregators, includeCollapsed) { for (var i = 0; i < groupingInfos.length; i++) {
aggregators = groupAggregators; var gi = groupingInfos[i] = $.extend(true, {}, groupingInfoDefaults, groupingInfos[i]);
aggregateCollapsed = (includeCollapsed !== undefined) gi.getterIsAFn = typeof gi.getter === "function";
? includeCollapsed : aggregateCollapsed;
// pre-compile accumulator loops // pre-compile accumulator loops
compiledAccumulators = []; gi.compiledAccumulators = [];
var idx = aggregators.length; var idx = gi.aggregators.length;
while (idx--) { while (idx--) {
compiledAccumulators[idx] = compileAccumulatorLoop(aggregators[idx]); gi.compiledAccumulators[idx] = compileAccumulatorLoop(gi.aggregators[idx]);
}
toggledGroupsByLevel[i] = {};
} }
refresh(); refresh();
} }
/**
* @deprecated Please use {@link setGrouping}.
*/
function groupBy(valueGetter, valueFormatter, sortComparer) {
if (valueGetter == null) {
setGrouping([]);
return;
}
setGrouping({
getter: valueGetter,
formatter: valueFormatter,
comparer: sortComparer
});
}
/**
* @deprecated Please use {@link setGrouping}.
*/
function setAggregators(groupAggregators, includeCollapsed) {
if (!groupingInfos.length) {
throw new Error("At least one grouping must be specified before calling setAggregators().");
}
groupingInfos[0].aggregators = groupAggregators;
groupingInfos[0].aggregateCollapsed = includeCollapsed;
setGrouping(groupingInfos);
}
function getItemByIdx(i) { function getItemByIdx(i) {
return items[i]; return items[i];
} }
@ -265,7 +305,7 @@
function mapIdsToRows(idArray) { function mapIdsToRows(idArray) {
var rows = []; var rows = [];
ensureRowsByIdCache(); ensureRowsByIdCache();
for (var i = 0; i < idArray.length; i++) { for (var i = 0, l = idArray.length; i < l; i++) {
var row = rowsById[idArray[i]]; var row = rowsById[idArray[i]];
if (row != null) { if (row != null) {
rows[rows.length] = row; rows[rows.length] = row;
@ -276,7 +316,7 @@
function mapRowsToIds(rowArray) { function mapRowsToIds(rowArray) {
var ids = []; var ids = [];
for (var i = 0; i < rowArray.length; i++) { for (var i = 0, l = rowArray.length; i < l; i++) {
if (rowArray[i] < rows.length) { if (rowArray[i] < rows.length) {
ids[ids.length] = rows[rowArray[i]][idProperty]; ids[ids.length] = rows[rowArray[i]][idProperty];
} }
@ -324,7 +364,22 @@
} }
function getItem(i) { function getItem(i) {
return rows[i]; var item = rows[i];
// if this is a group row, make sure totals are calculated and update the title
if (item && item.__group && item.totals && !item.totals.initialized) {
var gi = groupingInfos[item.level];
if (!gi.displayTotalsRow) {
calculateTotals(item.totals);
item.title = gi.formatter ? gi.formatter(item) : item.value;
}
}
// if this is a totals row, make sure it's calculated
else if (item && item.__groupTotals && !item.initialized) {
calculateTotals(item);
}
return item;
} }
function getItemMetadata(i) { function getItemMetadata(i) {
@ -333,7 +388,7 @@
return null; return null;
} }
// overrides for group rows // overrides for grouping rows
if (item.__group) { if (item.__group) {
return options.groupItemMetadataProvider.getGroupRowMetadata(item); return options.groupItemMetadataProvider.getGroupRowMetadata(item);
} }
@ -346,37 +401,105 @@
return null; return null;
} }
function collapseGroup(groupingValue) { function expandCollapseAllGroups(level, collapse) {
collapsedGroups[groupingValue] = true; if (level == null) {
for (var i = 0; i < groupingInfos.length; i++) {
toggledGroupsByLevel[i] = {};
groupingInfos[i].collapsed = collapse;
}
} else {
toggledGroupsByLevel[level] = {};
groupingInfos[level].collapsed = collapse;
}
refresh(); refresh();
} }
function expandGroup(groupingValue) { /**
delete collapsedGroups[groupingValue]; * @param level {Number} Optional level to collapse. If not specified, applies to all levels.
*/
function collapseAllGroups(level) {
expandCollapseAllGroups(level, true);
}
/**
* @param level {Number} Optional level to expand. If not specified, applies to all levels.
*/
function expandAllGroups(level) {
expandCollapseAllGroups(level, false);
}
function expandCollapseGroup(level, groupingKey, collapse) {
toggledGroupsByLevel[level][groupingKey] = groupingInfos[level].collapsed ^ collapse;
refresh(); refresh();
} }
/**
* @param varArgs Either a Slick.Group's "groupingKey" property, or a
* variable argument list of grouping values denoting a unique path to the row. For
* example, calling collapseGroup('high', '10%') will collapse the '10%' subgroup of
* the 'high' group.
*/
function collapseGroup(varArgs) {
var args = Array.prototype.slice.call(arguments);
var arg0 = args[0];
if (args.length == 1 && arg0.indexOf(groupingDelimiter) != -1) {
expandCollapseGroup(arg0.split(groupingDelimiter).length - 1, arg0, true);
} else {
expandCollapseGroup(args.length - 1, args.join(groupingDelimiter), true);
}
}
/**
* @param varArgs Either a Slick.Group's "groupingKey" property, or a
* variable argument list of grouping values denoting a unique path to the row. For
* example, calling expandGroup('high', '10%') will expand the '10%' subgroup of
* the 'high' group.
*/
function expandGroup(varArgs) {
var args = Array.prototype.slice.call(arguments);
var arg0 = args[0];
if (args.length == 1 && arg0.indexOf(groupingDelimiter) != -1) {
expandCollapseGroup(arg0.split(groupingDelimiter).length - 1, arg0, false);
} else {
expandCollapseGroup(args.length - 1, args.join(groupingDelimiter), false);
}
}
function getGroups() { function getGroups() {
return groups; return groups;
} }
function extractGroups(rows) { function extractGroups(rows, parentGroup) {
var group; var group;
var val; var val;
var groups = []; var groups = [];
var groupsByVal = []; var groupsByVal = {};
var r; var r;
var level = parentGroup ? parentGroup.level + 1 : 0;
var gi = groupingInfos[level];
for (var i = 0, l = rows.length; i < l; i++) { for (var i = 0, l = gi.predefinedValues.length; i < l; i++) {
r = rows[i]; val = gi.predefinedValues[i];
val = (groupingGetterIsAFn) ? groupingGetter(r) : r[groupingGetter];
val = val || 0;
group = groupsByVal[val]; group = groupsByVal[val];
if (!group) { if (!group) {
group = new Slick.Group(); group = new Slick.Group();
group.count = 0;
group.value = val; group.value = val;
group.rows = []; group.level = level;
group.groupingKey = (parentGroup ? parentGroup.groupingKey + groupingDelimiter : '') + val;
groups[groups.length] = group;
groupsByVal[val] = group;
}
}
for (var i = 0, l = rows.length; i < l; i++) {
r = rows[i];
val = gi.getterIsAFn ? gi.getter(r) : r[gi.getter];
group = groupsByVal[val];
if (!group) {
group = new Slick.Group();
group.value = val;
group.level = level;
group.groupingKey = (parentGroup ? parentGroup.groupingKey + groupingDelimiter : '') + val;
groups[groups.length] = group; groups[groups.length] = group;
groupsByVal[val] = group; groupsByVal[val] = group;
} }
@ -384,57 +507,101 @@
group.rows[group.count++] = r; group.rows[group.count++] = r;
} }
if (level < groupingInfos.length - 1) {
for (var i = 0; i < groups.length; i++) {
group = groups[i];
group.groups = extractGroups(group.rows, group);
}
}
groups.sort(groupingInfos[level].comparer);
return groups; return groups;
} }
// TODO: lazy totals calculation function calculateTotals(totals) {
function calculateGroupTotals(group) { var group = totals.group;
if (group.collapsed && !aggregateCollapsed) { var gi = groupingInfos[group.level];
return; var isLeafLevel = (group.level == groupingInfos.length);
var agg, idx = gi.aggregators.length;
if (!isLeafLevel && gi.aggregateChildGroups) {
// make sure all the subgroups are calculated
var i = group.groups.length;
while (i--) {
if (!group.groups[i].initialized) {
calculateTotals(group.groups[i]);
}
}
} }
// TODO: try moving iterating over groups into compiled accumulator
var totals = new Slick.GroupTotals();
var agg, idx = aggregators.length;
while (idx--) { while (idx--) {
agg = aggregators[idx]; agg = gi.aggregators[idx];
agg.init(); agg.init();
compiledAccumulators[idx].call(agg, group.rows); if (!isLeafLevel && gi.aggregateChildGroups) {
gi.compiledAccumulators[idx].call(agg, group.groups);
} else {
gi.compiledAccumulators[idx].call(agg, group.rows);
}
agg.storeResult(totals); agg.storeResult(totals);
} }
totals.initialized = true;
}
function addGroupTotals(group) {
var gi = groupingInfos[group.level];
var totals = new Slick.GroupTotals();
totals.group = group; totals.group = group;
group.totals = totals; group.totals = totals;
} if (!gi.lazyTotalsCalculation) {
calculateTotals(totals);
function calculateTotals(groups) {
var idx = groups.length;
while (idx--) {
calculateGroupTotals(groups[idx]);
} }
} }
function finalizeGroups(groups) { function addTotals(groups, level) {
level = level || 0;
var gi = groupingInfos[level];
var groupCollapsed = gi.collapsed;
var toggledGroups = toggledGroupsByLevel[level];
var idx = groups.length, g; var idx = groups.length, g;
while (idx--) { while (idx--) {
g = groups[idx]; g = groups[idx];
g.collapsed = (g.value in collapsedGroups);
g.title = groupingFormatter ? groupingFormatter(g) : g.value; if (g.collapsed && !gi.aggregateCollapsed) {
continue;
}
// Do a depth-first aggregation so that parent group aggregators can access subgroup totals.
if (g.groups) {
addTotals(g.groups, level + 1);
}
if (gi.aggregators.length && (
gi.aggregateEmpty || g.rows.length || (g.groups && g.groups.length))) {
addGroupTotals(g);
}
g.collapsed = groupCollapsed ^ toggledGroups[g.groupingKey];
g.title = gi.formatter ? gi.formatter(g) : g.value;
} }
} }
function flattenGroupedRows(groups) { function flattenGroupedRows(groups, level) {
var groupedRows = [], gl = 0, g; level = level || 0;
var gi = groupingInfos[level];
var groupedRows = [], rows, gl = 0, g;
for (var i = 0, l = groups.length; i < l; i++) { for (var i = 0, l = groups.length; i < l; i++) {
g = groups[i]; g = groups[i];
groupedRows[gl++] = g; groupedRows[gl++] = g;
if (!g.collapsed) { if (!g.collapsed) {
for (var j = 0, jj = g.rows.length; j < jj; j++) { rows = g.groups ? flattenGroupedRows(g.groups, level + 1) : g.rows;
groupedRows[gl++] = g.rows[j]; for (var j = 0, jj = rows.length; j < jj; j++) {
groupedRows[gl++] = rows[j];
} }
} }
if (g.totals && (!g.collapsed || aggregateCollapsed)) { if (g.totals && gi.displayTotalsRow && (!g.collapsed || gi.aggregateCollapsed)) {
groupedRows[gl++] = g.totals; groupedRows[gl++] = g.totals;
} }
} }
@ -467,10 +634,10 @@
var filterInfo = getFunctionInfo(filter); var filterInfo = getFunctionInfo(filter);
var filterBody = filterInfo.body var filterBody = filterInfo.body
.replace(/return false[;}]/gi, "{ continue _coreloop; }") .replace(/return false\s*([;}]|$)/gi, "{ continue _coreloop; }$1")
.replace(/return true[;}]/gi, "{ _retval[_idx++] = $item$; continue _coreloop; }") .replace(/return true\s*([;}]|$)/gi, "{ _retval[_idx++] = $item$; continue _coreloop; }$1")
.replace(/return ([^;}]+?);/gi, .replace(/return ([^;}]+?)\s*([;}]|$)/gi,
"{ if ($1) { _retval[_idx++] = $item$; }; continue _coreloop; }"); "{ if ($1) { _retval[_idx++] = $item$; }; continue _coreloop; }$2");
// This preserves the function template code after JS compression, // This preserves the function template code after JS compression,
// so that replace() commands still work as expected. // so that replace() commands still work as expected.
@ -499,10 +666,10 @@
var filterInfo = getFunctionInfo(filter); var filterInfo = getFunctionInfo(filter);
var filterBody = filterInfo.body var filterBody = filterInfo.body
.replace(/return false[;}]/gi, "{ continue _coreloop; }") .replace(/return false\s*([;}]|$)/gi, "{ continue _coreloop; }$1")
.replace(/return true[;}]/gi, "{ _cache[_i] = true;_retval[_idx++] = $item$; continue _coreloop; }") .replace(/return true\s*([;}]|$)/gi, "{ _cache[_i] = true;_retval[_idx++] = $item$; continue _coreloop; }$1")
.replace(/return ([^;}]+?);/gi, .replace(/return ([^;}]+?)\s*([;}]|$)/gi,
"{ if ((_cache[_i] = $1)) { _retval[_idx++] = $item$; }; continue _coreloop; }"); "{ if ((_cache[_i] = $1)) { _retval[_idx++] = $item$; }; continue _coreloop; }$2");
// This preserves the function template code after JS compression, // This preserves the function template code after JS compression,
// so that replace() commands still work as expected. // so that replace() commands still work as expected.
@ -613,11 +780,10 @@
item = newRows[i]; item = newRows[i];
r = rows[i]; r = rows[i];
if ((groupingGetter && (eitherIsNonData = (item.__nonDataRow) || (r.__nonDataRow)) && if ((groupingInfos.length && (eitherIsNonData = (item.__nonDataRow) || (r.__nonDataRow)) &&
item.__group !== r.__group || item.__group !== r.__group ||
item.__updated ||
item.__group && !item.equals(r)) item.__group && !item.equals(r))
|| (aggregators && eitherIsNonData && || (eitherIsNonData &&
// no good way to compare totals since they are arbitrary DTOs // no good way to compare totals since they are arbitrary DTOs
// deep object comparison is pretty expensive // deep object comparison is pretty expensive
// always considering them 'dirty' seems easier for the time being // always considering them 'dirty' seems easier for the time being
@ -645,14 +811,10 @@
var newRows = filteredItems.rows; var newRows = filteredItems.rows;
groups = []; groups = [];
if (groupingGetter != null) { if (groupingInfos.length) {
groups = extractGroups(newRows); groups = extractGroups(newRows);
if (groups.length) { if (groups.length) {
finalizeGroups(groups); addTotals(groups);
if (aggregators) {
calculateTotals(groups);
}
groups.sort(groupingComparer);
newRows = flattenGroupedRows(groups); newRows = flattenGroupedRows(groups);
} }
} }
@ -696,30 +858,74 @@
} }
} }
function syncGridSelection(grid, preserveHidden) { /***
* Wires the grid and the DataView together to keep row selection tied to item ids.
* This is useful since, without it, the grid only knows about rows, so if the items
* move around, the same rows stay selected instead of the selection moving along
* with the items.
*
* NOTE: This doesn't work with cell selection model.
*
* @param grid {Slick.Grid} The grid to sync selection with.
* @param preserveHidden {Boolean} Whether to keep selected items that go out of the
* view due to them getting filtered out.
* @param preserveHiddenOnSelectionChange {Boolean} Whether to keep selected items
* that are currently out of the view (see preserveHidden) as selected when selection
* changes.
* @return {Slick.Event} An event that notifies when an internal list of selected row ids
* changes. This is useful since, in combination with the above two options, it allows
* access to the full list selected row ids, and not just the ones visible to the grid.
* @method syncGridSelection
*/
function syncGridSelection(grid, preserveHidden, preserveHiddenOnSelectionChange) {
var self = this; var self = this;
var selectedRowIds = self.mapRowsToIds(grid.getSelectedRows());
;
var inHandler; var inHandler;
var selectedRowIds = self.mapRowsToIds(grid.getSelectedRows());
var onSelectedRowIdsChanged = new Slick.Event();
grid.onSelectedRowsChanged.subscribe(function (e, args) { function setSelectedRowIds(rowIds) {
if (inHandler) { if (selectedRowIds.join(",") == rowIds.join(",")) {
return; return;
} }
selectedRowIds = self.mapRowsToIds(grid.getSelectedRows());
});
this.onRowsChanged.subscribe(function (e, args) { selectedRowIds = rowIds;
onSelectedRowIdsChanged.notify({
"grid": grid,
"ids": selectedRowIds
}, new Slick.EventData(), self);
}
function update() {
if (selectedRowIds.length > 0) { if (selectedRowIds.length > 0) {
inHandler = true; inHandler = true;
var selectedRows = self.mapIdsToRows(selectedRowIds); var selectedRows = self.mapIdsToRows(selectedRowIds);
if (!preserveHidden) { if (!preserveHidden) {
selectedRowIds = self.mapRowsToIds(selectedRows); setSelectedRowIds(self.mapRowsToIds(selectedRows));
} }
grid.setSelectedRows(selectedRows); grid.setSelectedRows(selectedRows);
inHandler = false; inHandler = false;
} }
}
grid.onSelectedRowsChanged.subscribe(function(e, args) {
if (inHandler) { return; }
var newSelectedRowIds = self.mapRowsToIds(grid.getSelectedRows());
if (!preserveHiddenOnSelectionChange || !grid.getOptions().multiSelect) {
setSelectedRowIds(newSelectedRowIds);
} else {
// keep the ones that are hidden
var existing = $.grep(selectedRowIds, function(id) { return self.getRowById(id) === undefined; });
// add the newly selected ones
setSelectedRowIds(existing.concat(newSelectedRowIds));
}
}); });
this.onRowsChanged.subscribe(update);
this.onRowCountChanged.subscribe(update);
return onSelectedRowIdsChanged;
} }
function syncGridCellCssStyles(grid, key) { function syncGridCellCssStyles(grid, key) {
@ -738,19 +944,7 @@
} }
} }
grid.onCellCssStylesChanged.subscribe(function (e, args) { function update() {
if (inHandler) {
return;
}
if (key != args.key) {
return;
}
if (args.hash) {
storeCellCssStyles(args.hash);
}
});
this.onRowsChanged.subscribe(function (e, args) {
if (hashById) { if (hashById) {
inHandler = true; inHandler = true;
ensureRowsByIdCache(); ensureRowsByIdCache();
@ -764,10 +958,22 @@
grid.setCellCssStyles(key, newHash); grid.setCellCssStyles(key, newHash);
inHandler = false; inHandler = false;
} }
});
} }
return { grid.onCellCssStylesChanged.subscribe(function(e, args) {
if (inHandler) { return; }
if (key != args.key) { return; }
if (args.hash) {
storeCellCssStyles(args.hash);
}
});
this.onRowsChanged.subscribe(update);
this.onRowCountChanged.subscribe(update);
}
$.extend(this, {
// methods // methods
"beginUpdate": beginUpdate, "beginUpdate": beginUpdate,
"endUpdate": endUpdate, "endUpdate": endUpdate,
@ -779,8 +985,12 @@
"sort": sort, "sort": sort,
"fastSort": fastSort, "fastSort": fastSort,
"reSort": reSort, "reSort": reSort,
"setGrouping": setGrouping,
"getGrouping": getGrouping,
"groupBy": groupBy, "groupBy": groupBy,
"setAggregators": setAggregators, "setAggregators": setAggregators,
"collapseAllGroups": collapseAllGroups,
"expandAllGroups": expandAllGroups,
"collapseGroup": collapseGroup, "collapseGroup": collapseGroup,
"expandGroup": expandGroup, "expandGroup": expandGroup,
"getGroups": getGroups, "getGroups": getGroups,
@ -799,15 +1009,17 @@
"deleteItem": deleteItem, "deleteItem": deleteItem,
"syncGridSelection": syncGridSelection, "syncGridSelection": syncGridSelection,
"syncGridCellCssStyles": syncGridCellCssStyles, "syncGridCellCssStyles": syncGridCellCssStyles,
// data provider methods // data provider methods
"getLength": getLength, "getLength": getLength,
"getItem": getItem, "getItem": getItem,
"getItemMetadata": getItemMetadata, "getItemMetadata": getItemMetadata,
// events // events
"onRowCountChanged": onRowCountChanged, "onRowCountChanged": onRowCountChanged,
"onRowsChanged": onRowsChanged, "onRowsChanged": onRowsChanged,
"onPagingInfoChanged": onPagingInfoChanged "onPagingInfoChanged": onPagingInfoChanged
}; });
} }
function AvgAggregator(field) { function AvgAggregator(field) {
@ -822,7 +1034,7 @@
this.accumulate = function (item) { this.accumulate = function (item) {
var val = item[this.field_]; var val = item[this.field_];
this.count_++; this.count_++;
if (val != null && val != "" && val != NaN) { if (val != null && val !== "" && val !== NaN) {
this.nonNullCount_++; this.nonNullCount_++;
this.sum_ += parseFloat(val); this.sum_ += parseFloat(val);
} }
@ -847,7 +1059,7 @@
this.accumulate = function (item) { this.accumulate = function (item) {
var val = item[this.field_]; var val = item[this.field_];
if (val != null && val != "" && val != NaN) { if (val != null && val !== "" && val !== NaN) {
if (this.min_ == null || val < this.min_) { if (this.min_ == null || val < this.min_) {
this.min_ = val; this.min_ = val;
} }
@ -871,7 +1083,7 @@
this.accumulate = function (item) { this.accumulate = function (item) {
var val = item[this.field_]; var val = item[this.field_];
if (val != null && val != "" && val != NaN) { if (val != null && val !== "" && val !== NaN) {
if (this.max_ == null || val > this.max_) { if (this.max_ == null || val > this.max_) {
this.max_ = val; this.max_ = val;
} }
@ -895,7 +1107,7 @@
this.accumulate = function (item) { this.accumulate = function (item) {
var val = item[this.field_]; var val = item[this.field_];
if (val != null && val != "" && val != NaN) { if (val != null && val !== "" && val !== NaN) {
this.sum_ += parseFloat(val); this.sum_ += parseFloat(val);
} }
}; };

View File

@ -302,16 +302,16 @@
}; };
this.loadValue = function (item) { this.loadValue = function (item) {
defaultValue = item[args.column.field]; defaultValue = !!item[args.column.field];
if (defaultValue) { if (defaultValue) {
$select.attr("checked", "checked"); $select.prop('checked', true);
} else { } else {
$select.removeAttr("checked"); $select.prop('checked', false);
} }
}; };
this.serializeValue = function () { this.serializeValue = function () {
return $select.attr("checked"); return $select.prop('checked');
}; };
this.applyValue = function (item, state) { this.applyValue = function (item, state) {
@ -319,7 +319,7 @@
}; };
this.isValueChanged = function () { this.isValueChanged = function () {
return ($select.attr("checked") != defaultValue); return (this.serializeValue() !== defaultValue);
}; };
this.validate = function () { this.validate = function () {
@ -445,10 +445,10 @@
scope.cancel(); scope.cancel();
} else if (e.which == $.ui.keyCode.TAB && e.shiftKey) { } else if (e.which == $.ui.keyCode.TAB && e.shiftKey) {
e.preventDefault(); e.preventDefault();
grid.navigatePrev(); args.grid.navigatePrev();
} else if (e.which == $.ui.keyCode.TAB) { } else if (e.which == $.ui.keyCode.TAB) {
e.preventDefault(); e.preventDefault();
grid.navigateNext(); args.grid.navigateNext();
} }
}; };

View File

@ -1,5 +1,9 @@
/*** /***
* Contains basic SlickGrid formatters. * Contains basic SlickGrid formatters.
*
* NOTE: These are merely examples. You will most likely need to implement something more
* robust/extensible/localizable/etc. for your use!
*
* @module Formatters * @module Formatters
* @namespace Slick * @namespace Slick
*/ */