new listing and changed wn.widgets.listing to wn.ui.listing

This commit is contained in:
Rushabh Mehta 2012-03-07 18:19:49 +05:30
parent 3d74878c2d
commit c1bc39976e
47 changed files with 4258 additions and 447 deletions

View file

@ -26,6 +26,7 @@
}
</script>
{% endif %}
<script src="lib/js/wn/ui/listing.js"></script>
<script src="lib/js/wn/pages/doclistview.js"></script>
</head>
<body>

View file

@ -235,4 +235,4 @@ div.std-footer-item {
height: 24px;
margin-bottom: -7px;
max-width: 24px;
}
}

0
css/legacy/final.css Normal file
View file

View file

@ -1,3 +1,26 @@
.hide {
display: none;
}
.list-filters {
margin: 7px 0px;
}
.wnlist .img-load {
display: none;
float: left;
margin-left: 11px;
margin-top: 8px;
}
div.list-row {
border-bottom: 1px solid #eee;
padding: 3px 0px;
}
div.list-row:hover {
background-color: #eef
}
div.show_filters {
display: none;
}
@ -8,7 +31,7 @@ div.filter_list {
div.show_filters.well {
margin-top: 11px;
margin-bottom: 0px;
margin-bottom: 11px;
}
div.filter_list .run_btn {
@ -46,9 +69,3 @@ span.bar-inner {
span.bar-complete {
background-color: green;
}
div.list-row {
border-bottom: 1px solid #eee;
}
div.list-row:hover {
background-color: #eef
}

View file

@ -23,7 +23,7 @@
// Listing
// this listing object will soon be
// deprecated because it has a very non standard way of creation
// the new listing object is at wn.widgets.Listing
// the new listing object is at wn.ui.Listing
// -----------------------
list_opts = {

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 851 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 836 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 823 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 914 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 823 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

View file

@ -0,0 +1,6 @@
/*!
* 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);

View file

@ -0,0 +1,295 @@
/*
IMPORTANT:
In order to preserve the uniform grid appearance, all cell styles need to have padding, margin and border sizes.
No built-in (selected, editable, highlight, flashing, invalid, loading, :focus) or user-specified CSS
classes should alter those!
*/
.slick-header-columns {
background: url('lib/js/lib/slickgrid/images/header-columns-bg.gif') repeat-x center bottom;
border-bottom: 1px solid silver;
}
.slick-header-column {
background: url('lib/js/lib/slickgrid/images/header-columns-bg.gif') repeat-x center bottom;
border-right: 1px solid silver;
}
.slick-header-column:hover, .slick-header-column-active {
background: white url('lib/js/lib/slickgrid/images/header-columns-over-bg.gif') repeat-x center bottom;
}
.slick-headerrow {
background: #fafafa;
}
.slick-headerrow-column {
background: #fafafa;
border-bottom: 0;
height: 100%;
}
.slick-row.ui-state-active {
background: #F5F7D7;
}
.slick-row {
position: absolute;
background: white;
border: 0px;
line-height: 20px;
}
.slick-row.selected {
z-index: 10;
background: #DFE8F6;
}
.slick-cell {
padding-left: 4px;
padding-right: 4px;
}
.slick-group {
border-bottom: 2px solid silver;
}
.slick-group-toggle {
width: 9px;
height: 9px;
margin-right: 5px;
}
.slick-group-toggle.expanded {
background: url(lib/js/lib/slickgrid/images/collapse.gif) no-repeat center center;
}
.slick-group-toggle.collapsed {
background: url(lib/js/lib/slickgrid/images/expand.gif) no-repeat center center;
}
.slick-group-totals {
color: gray;
background: white;
}
.slick-cell.selected {
background-color: beige;
}
.slick-cell.active {
border-color: gray;
border-style: solid;
}
.slick-sortable-placeholder {
background: silver !important;
}
.slick-row[row$="1"], .slick-row[row$="3"], .slick-row[row$="5"], .slick-row[row$="7"], .slick-row[row$="9"] {
background: #fafafa;
}
.slick-row.ui-state-active {
background: #F5F7D7;
}
.slick-row.loading {
opacity: 0.5;
filter: alpha(opacity = 50);
}
.slick-cell.invalid {
border-color: red;
}
.grid-header {
border: 1px solid gray;
border-bottom: 0;
border-top: 0;
background: url('lib/js/lib/slickgrid/images/header-bg.gif') repeat-x center top;
color: black;
height: 24px;
line-height: 24px;
}
.grid-header label {
display: inline-block;
font-weight: bold;
margin: auto auto auto 6px;
}
.grid-header .ui-icon {
margin: 4px 4px auto 6px;
background-color: transparent;
border-color: transparent;
}
.grid-header .ui-icon.ui-state-hover {
background-color: white;
}
.grid-header #txtSearch {
margin: 0 4px 0 4px;
padding: 2px 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border: 1px solid silver;
}
.options-panel {
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border: 1px solid silver;
background: #f0f0f0;
padding: 4px;
margin-bottom: 20px;
width: 320px;
position: absolute;
top: 0px;
left: 650px;
}
/* Individual cell styles */
.slick-cell.task-name {
font-weight: bold;
text-align: right;
}
.slick-cell.task-percent {
text-align: right;
}
.slick-cell.cell-move-handle {
font-weight: bold;
text-align: right;
border-right: solid gray;
background: #efefef;
cursor: move;
}
.cell-move-handle:hover {
background: #b6b9bd;
}
.slick-row.selected .cell-move-handle {
background: #D5DC8D;
}
.slick-row .cell-actions {
text-align: left;
}
.slick-row.complete {
background-color: #DFD;
color: #555;
}
.percent-complete-bar {
display: inline-block;
height: 6px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
}
/* Slick.Editors.Text, Slick.Editors.Date */
input.editor-text {
width: 100%;
height: 100%;
border: 0;
margin: 0;
background: transparent;
outline: 0;
padding: 0;
}
.ui-datepicker-trigger {
margin-top: 2px;
padding: 0;
vertical-align: top;
}
/* Slick.Editors.PercentComplete */
input.editor-percentcomplete {
width: 100%;
height: 100%;
border: 0;
margin: 0;
background: transparent;
outline: 0;
padding: 0;
float: left;
}
.editor-percentcomplete-picker {
position: relative;
display: inline-block;
width: 16px;
height: 100%;
background: url("lib/js/lib/slickgrid/images/pencil.gif") no-repeat center center;
overflow: visible;
z-index: 1000;
float: right;
}
.editor-percentcomplete-helper {
border: 0 solid gray;
position: absolute;
top: -2px;
left: -9px;
background: url("lib/js/lib/slickgrid/images/editor-helper-bg.gif") no-repeat top left;
padding-left: 9px;
width: 120px;
height: 140px;
display: none;
overflow: visible;
}
.editor-percentcomplete-wrapper {
background: beige;
padding: 20px 8px;
width: 100%;
height: 98px;
border: 1px solid gray;
border-left: 0;
}
.editor-percentcomplete-buttons {
float: right;
}
.editor-percentcomplete-buttons button {
width: 80px;
}
.editor-percentcomplete-slider {
float: left;
}
.editor-percentcomplete-picker:hover .editor-percentcomplete-helper {
display: block;
}
.editor-percentcomplete-helper:hover {
display: block;
}
/* Slick.Editors.YesNoSelect */
select.editor-yesno {
width: 100%;
margin: 0;
vertical-align: middle;
}
/* Slick.Editors.Checkbox */
input.editor-checkbox {
margin: 0;
height: 100%;
padding: 0;
border: 0;
}

424
js/lib/slickgrid/slick.core.js vendored Normal file
View file

@ -0,0 +1,424 @@
/***
* Contains core SlickGrid classes.
* @module Core
* @namespace Slick
*/
(function ($) {
// register namespace
$.extend(true, window, {
"Slick": {
"Event": Event,
"EventData": EventData,
"EventHandler": EventHandler,
"Range": Range,
"NonDataRow": NonDataItem,
"Group": Group,
"GroupTotals": GroupTotals,
"EditorLock": EditorLock,
/***
* A global singleton editor lock.
* @class GlobalEditorLock
* @static
* @constructor
*/
"GlobalEditorLock": new EditorLock()
}
});
/***
* An event object for passing data to event handlers and letting them control propagation.
* <p>This is pretty much identical to how W3C and jQuery implement events.</p>
* @class EventData
* @constructor
*/
function EventData() {
var isPropagationStopped = false;
var isImmediatePropagationStopped = false;
/***
* Stops event from propagating up the DOM tree.
* @method stopPropagation
*/
this.stopPropagation = function () {
isPropagationStopped = true;
};
/***
* Returns whether stopPropagation was called on this event object.
* @method isPropagationStopped
* @return {Boolean}
*/
this.isPropagationStopped = function () {
return isPropagationStopped;
};
/***
* Prevents the rest of the handlers from being executed.
* @method stopImmediatePropagation
*/
this.stopImmediatePropagation = function () {
isImmediatePropagationStopped = true;
};
/***
* Returns whether stopImmediatePropagation was called on this event object.\
* @method isImmediatePropagationStopped
* @return {Boolean}
*/
this.isImmediatePropagationStopped = function () {
return isImmediatePropagationStopped;
}
}
/***
* A simple publisher-subscriber implementation.
* @class Event
* @constructor
*/
function Event() {
var handlers = [];
/***
* Adds an event handler to be called when the event is fired.
* <p>Event handler will receive two arguments - an <code>EventData</code> and the <code>data</code>
* object the event was fired with.<p>
* @method subscribe
* @param fn {Function} Event handler.
*/
this.subscribe = function (fn) {
handlers.push(fn);
};
/***
* Removes an event handler added with <code>subscribe(fn)</code>.
* @method unsubscribe
* @param fn {Function} Event handler to be removed.
*/
this.unsubscribe = function (fn) {
for (var i = handlers.length - 1; i >= 0; i--) {
if (handlers[i] === fn) {
handlers.splice(i, 1);
}
}
};
/***
* Fires an event notifying all subscribers.
* @method notify
* @param args {Object} Additional data object to be passed to all handlers.
* @param e {EventData}
* Optional.
* An <code>EventData</code> object to be passed to all handlers.
* For DOM events, an existing W3C/jQuery event object can be passed in.
* @param scope {Object}
* Optional.
* The scope ("this") within which the handler will be executed.
* If not specified, the scope will be set to the <code>Event</code> instance.
*/
this.notify = function (args, e, scope) {
e = e || new EventData();
scope = scope || this;
var returnValue;
for (var i = 0; i < handlers.length && !(e.isPropagationStopped() || e.isImmediatePropagationStopped()); i++) {
returnValue = handlers[i].call(scope, e, args);
}
return returnValue;
};
}
function EventHandler() {
var handlers = [];
this.subscribe = function (event, handler) {
handlers.push({
event: event,
handler: handler
});
event.subscribe(handler);
};
this.unsubscribe = function (event, handler) {
var i = handlers.length;
while (i--) {
if (handlers[i].event === event &&
handlers[i].handler === handler) {
handlers.splice(i, 1);
event.unsubscribe(handler);
return;
}
}
};
this.unsubscribeAll = function () {
var i = handlers.length;
while (i--) {
handlers[i].event.unsubscribe(handlers[i].handler);
}
handlers = [];
}
}
/***
* A structure containing a range of cells.
* @class Range
* @constructor
* @param fromRow {Integer} Starting row.
* @param fromCell {Integer} Starting cell.
* @param toRow {Integer} Optional. Ending row. Defaults to <code>fromRow</code>.
* @param toCell {Integer} Optional. Ending cell. Defaults to <code>fromCell</code>.
*/
function Range(fromRow, fromCell, toRow, toCell) {
if (toRow === undefined && toCell === undefined) {
toRow = fromRow;
toCell = fromCell;
}
/***
* @property fromRow
* @type {Integer}
*/
this.fromRow = Math.min(fromRow, toRow);
/***
* @property fromCell
* @type {Integer}
*/
this.fromCell = Math.min(fromCell, toCell);
/***
* @property toRow
* @type {Integer}
*/
this.toRow = Math.max(fromRow, toRow);
/***
* @property toCell
* @type {Integer}
*/
this.toCell = Math.max(fromCell, toCell);
/***
* Returns whether a range represents a single row.
* @method isSingleRow
* @return {Boolean}
*/
this.isSingleRow = function () {
return this.fromRow == this.toRow;
};
/***
* Returns whether a range represents a single cell.
* @method isSingleCell
* @return {Boolean}
*/
this.isSingleCell = function () {
return this.fromRow == this.toRow && this.fromCell == this.toCell;
};
/***
* Returns whether a range contains a given cell.
* @method contains
* @param row {Integer}
* @param cell {Integer}
* @return {Boolean}
*/
this.contains = function (row, cell) {
return row >= this.fromRow && row <= this.toRow &&
cell >= this.fromCell && cell <= this.toCell;
};
/***
* Returns a readable representation of a range.
* @method toString
* @return {String}
*/
this.toString = function () {
if (this.isSingleCell()) {
return "(" + this.fromRow + ":" + this.fromCell + ")";
}
else {
return "(" + this.fromRow + ":" + this.fromCell + " - " + this.toRow + ":" + this.toCell + ")";
}
}
}
/***
* A base class that all special / non-data rows (like Group and GroupTotals) derive from.
* @class NonDataItem
* @constructor
*/
function NonDataItem() {
this.__nonDataRow = true;
}
/***
* Information about a group of rows.
* @class Group
* @extends Slick.NonDataItem
* @constructor
*/
function Group() {
this.__group = true;
this.__updated = false;
/***
* Number of rows in the group.
* @property count
* @type {Integer}
*/
this.count = 0;
/***
* Grouping value.
* @property value
* @type {Object}
*/
this.value = null;
/***
* Formatted display value of the group.
* @property title
* @type {String}
*/
this.title = null;
/***
* Whether a group is collapsed.
* @property collapsed
* @type {Boolean}
*/
this.collapsed = false;
/***
* GroupTotals, if any.
* @property totals
* @type {GroupTotals}
*/
this.totals = null;
}
Group.prototype = new NonDataItem();
/***
* Compares two Group instances.
* @method equals
* @return {Boolean}
* @param group {Group} Group instance to compare to.
*/
Group.prototype.equals = function (group) {
return this.value === group.value &&
this.count === group.count &&
this.collapsed === group.collapsed;
};
/***
* Information about group totals.
* An instance of GroupTotals will be created for each totals row and passed to the aggregators
* so that they can store arbitrary data in it. That data can later be accessed by group totals
* formatters during the display.
* @class GroupTotals
* @extends Slick.NonDataItem
* @constructor
*/
function GroupTotals() {
this.__groupTotals = true;
/***
* Parent Group.
* @param group
* @type {Group}
*/
this.group = null;
}
GroupTotals.prototype = new NonDataItem();
/***
* A locking helper to track the active edit controller and ensure that only a single controller
* can be active at a time. This prevents a whole class of state and validation synchronization
* issues. An edit controller (such as SlickGrid) can query if an active edit is in progress
* and attempt a commit or cancel before proceeding.
* @class EditorLock
* @constructor
*/
function EditorLock() {
var activeEditController = null;
/***
* Returns true if a specified edit controller is active (has the edit lock).
* If the parameter is not specified, returns true if any edit controller is active.
* @method isActive
* @param editController {EditController}
* @return {Boolean}
*/
this.isActive = function (editController) {
return (editController ? activeEditController === editController : activeEditController !== null);
};
/***
* Sets the specified edit controller as the active edit controller (acquire edit lock).
* If another edit controller is already active, and exception will be thrown.
* @method activate
* @param editController {EditController} edit controller acquiring the lock
*/
this.activate = function (editController) {
if (editController === activeEditController) { // already activated?
return;
}
if (activeEditController !== null) {
throw "SlickGrid.EditorLock.activate: an editController is still active, can't activate another editController";
}
if (!editController.commitCurrentEdit) {
throw "SlickGrid.EditorLock.activate: editController must implement .commitCurrentEdit()";
}
if (!editController.cancelCurrentEdit) {
throw "SlickGrid.EditorLock.activate: editController must implement .cancelCurrentEdit()";
}
activeEditController = editController;
};
/***
* Unsets the specified edit controller as the active edit controller (release edit lock).
* If the specified edit controller is not the active one, an exception will be thrown.
* @method deactivate
* @param editController {EditController} edit controller releasing the lock
*/
this.deactivate = function (editController) {
if (activeEditController !== editController) {
throw "SlickGrid.EditorLock.deactivate: specified editController is not the currently active one";
}
activeEditController = null;
};
/***
* Attempts to commit the current edit by calling "commitCurrentEdit" method on the active edit
* controller and returns whether the commit attempt was successful (commit may fail due to validation
* errors, etc.). Edit controller's "commitCurrentEdit" must return true if the commit has succeeded
* and false otherwise. If no edit controller is active, returns true.
* @method commitCurrentEdit
* @return {Boolean}
*/
this.commitCurrentEdit = function () {
return (activeEditController ? activeEditController.commitCurrentEdit() : true);
};
/***
* Attempts to cancel the current edit by calling "cancelCurrentEdit" method on the active edit
* controller and returns whether the edit was successfully cancelled. If no edit controller is
* active, returns true.
* @method cancelCurrentEdit
* @return {Boolean}
*/
this.cancelCurrentEdit = function cancelCurrentEdit() {
return (activeEditController ? activeEditController.cancelCurrentEdit() : true);
};
}
})(jQuery);

View file

@ -0,0 +1,158 @@
/*
IMPORTANT:
In order to preserve the uniform grid appearance, all cell styles need to have padding, margin and border sizes.
No built-in (selected, editable, highlight, flashing, invalid, loading, :focus) or user-specified CSS
classes should alter those!
*/
.slick-header.ui-state-default, .slick-headerrow.ui-state-default {
width: 100%;
overflow: hidden;
border-left: 0px;
}
.slick-header-columns, .slick-headerrow-columns {
width: 999999px;
position: relative;
white-space: nowrap;
cursor: default;
overflow: hidden;
}
.slick-header-column.ui-state-default {
position: relative;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
height: 16px;
line-height: 16px;
margin: 0;
padding: 4px;
border-right: 1px solid silver;
border-left: 0px;
border-top: 0px;
border-bottom: 0px;
float: left;
}
.slick-headerrow-column.ui-state-default {
padding: 4px;
}
.slick-header-column-sorted {
font-style: italic;
}
.slick-sort-indicator {
display: inline-block;
width: 8px;
height: 5px;
margin-left: 4px;
}
.slick-sort-indicator-desc {
background: url(images/sort-desc.gif);
}
.slick-sort-indicator-asc {
background: url(images/sort-asc.gif);
}
.slick-resizable-handle {
position: absolute;
font-size: 0.1px;
display: block;
cursor: col-resize;
width: 4px;
right: 0px;
top: 0;
height: 100%;
}
.slick-sortable-placeholder {
background: silver;
}
.grid-canvas {
position: relative;
outline: 0;
}
.slick-row.ui-widget-content, .slick-row.ui-state-active {
position: absolute;
border: 0px;
width: 100%;
}
.slick-cell, .slick-headerrow-column {
position: absolute;
border: 1px solid transparent;
border-right: 1px dotted silver;
border-bottom-color: silver;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
z-index: 1;
padding: 1px 2px 2px 1px;
margin: 0;
white-space: nowrap;
cursor: default;
}
.slick-group {
}
.slick-group-toggle {
display: inline-block;
}
.slick-cell.highlighted {
background: lightskyblue;
background: rgba(0, 0, 255, 0.2);
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
transition: all 0.5s;
}
.slick-cell.flashing {
border: 1px solid red !important;
}
.slick-cell.editable {
z-index: 11;
overflow: visible;
background: white;
border-color: black;
border-style: solid;
}
.slick-cell:focus {
outline: none;
}
.slick-reorder-proxy {
display: inline-block;
background: blue;
opacity: 0.15;
filter: alpha(opacity = 15);
cursor: move;
}
.slick-reorder-guide {
display: inline-block;
height: 2px;
background: blue;
opacity: 0.7;
filter: alpha(opacity = 70);
}
.slick-selection {
z-index: 10;
position: absolute;
border: 2px dashed black;
}

2799
js/lib/slickgrid/slick.grid.js vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -34,88 +34,92 @@ wn.pages.doclistview.show = function(doctype) {
page_body.change_to(pagename);
}
wn.pages.DocListView = Class.extend({
wn.pages.DocListView = wn.ui.Listing.extend({
init: function(doctype, page) {
this.doctype = doctype;
this.wrapper = page;
this.$w = $(page);
this.label = get_doctype_label(doctype);
this.label = (this.label.toLowerCase().substr(-4) == 'list') ?
this.label : (this.label + ' List')
this.make();
this.label : (this.label + ' List');
this.make_page();
this.load_doctype();
},
make: function() {
make_page: function() {
var me = this;
$(this.wrapper).html('<div class="layout-wrapper layout-wrapper-background">\
<div class="layout-main-section">\
this.$w.html(repl('<div class="layout-wrapper">\
<a class="close" onclick="window.history.back();">&times;</a>\
<h1>List</h1>\
<h1>%(label)s</h1>\
<hr>\
<div id="list-filters"></div>\
<button class="btn btn-small btn-info run-btn" style="margin-top: 11px">\
<i class="icon-refresh icon-white"></i> Refresh</button>\
<div id="list-body"></div>\
</div>\
<div class="layout-side-section">\
</div>\
<div style="clear: both"></div>\
</div>');
// filter button
$(this.wrapper).find('.run-btn').click(function() {
me.list.run();
});
$(this.wrapper).find('h1').html(this.label);
<div class="wnlist-area"><div class="help">Loading...</div></div>\
</div>', {label: this.label}));
},
load_doctype: function() {
var me = this;
wn.call({
method: 'webnotes.widgets.form.load.getdoctype',
args: {doctype: me.doctype},
callback: function() {
if(locals.DocType[me.doctype].__listjs) {
eval(locals.DocType[me.doctype].__listjs);
me.listview = wn.doclistviews[me.doctype];
} else {
me.listview = {}
}
if(!me.listview.fields)
me.listview.fields = ['name', 'modified', 'owner'];
if(!me.listview.render)
me.listview.render = me.default_render;
me.make_filters();
me.make_list();
me.$w.find('.wnlist-area').empty(),
me.setup_listview();
me.init_list();
}
});
},
make_filters: function() {
this.filter_list = new wn.ui.FilterList(this, $('#list-filters').get(0), this.doctype);
setup_listview: function() {
if(locals.DocType[this.doctype].__listjs) {
eval(locals.DocType[this.doctype].__listjs);
this.listview = wn.doclistviews[this.doctype];
} else {
this.listview = {}
}
if(!this.listview.fields)
this.listview.fields = [
{field: "name", name:"ID"},
{field: "modified", name:"Last Updated"},
{field: "owner", name:"Created By"}
];
if(!this.listview.render)
this.listview.render = this.default_render;
},
make_list: function() {
var me = this;
this.list = new wn.widgets.Listing({
parent: $('#list-body').get(0),
init_list: function() {
// init list
this.make({
method: 'webnotes.widgets.doclistview.get',
args: {
doctype: this.doctype,
subject: locals.DocType[this.doctype].subject,
fields: JSON.stringify(me.listview.fields),
},
get_args: function() {
return {filters: JSON.stringify(me.filter_list.get_filters())}
},
render_row: function(row, data) {
data.fullname = wn.user_info(data.owner).fullname;
data.avatar = wn.user_info(data.owner).image;
data.when = dateutil.comment_when(data.modified);
data.doctype = me.doctype;
me.listview.render(row, data, me);
},
hide_refresh: true
get_args: this.get_args,
parent: this.$w.find('.wnlist-area'),
start: 0,
page_length: 20,
show_filters: true,
show_grid: true,
columns: this.listview.fields
});
this.list.run();
this.run();
},
render_row: function(row, data) {
data.fullname = wn.user_info(data.owner).fullname;
data.avatar = wn.user_info(data.owner).image;
data.when = dateutil.comment_when(data.modified);
data.doctype = this.doctype;
this.listview.render(row, data, this);
},
get_query_fields: function() {
var fields = [];
$.each(this.listview.fields, function(i,f) {
fields.push(f.query || f.field);
});
return fields;
},
get_args: function() {
return {
doctype: this.doctype,
subject: locals.DocType[this.doctype].subject,
fields: JSON.stringify(this.get_query_fields()),
filters: JSON.stringify(this.filter_list.get_filters())
}
},
default_render: function(row, data) {
$(row).html(repl('<span class="avatar-small"><img src="%(avatar)s" /></span>\
@ -124,220 +128,3 @@ wn.pages.DocListView = Class.extend({
.addClass('list-row');
}
});
wn.require('lib/css/ui/filter.css');
wn.ui.FilterList = Class.extend({
init: function(list_obj, parent, doctype) {
this.filters = [];
this.list_obj = list_obj;
this.doctype = doctype;
this.make(parent);
this.set_events();
},
make: function(parent) {
$(parent).html('<div>\
<span class="link_type set_filters">Filter this list</span>\
</div>\
<div class="show_filters well">\
<div class="filter_area"></div>\
<div>\
<button class="btn btn-small add-filter-btn">\
<i class="icon-plus"></i> Add Filter</button>\
</div>\
</div>');
this.$w = $(parent);
},
set_events: function() {
var me = this;
// show filters
this.$w.find('.set_filters').bind('click', function() {
me.$w.find('.show_filters').slideToggle();
if(!me.filters.length)
me.add_filter();
});
// show filters
this.$w.find('.add-filter-btn').bind('click', function() {
me.add_filter();
});
},
add_filter: function(fieldname, condition, value) {
this.filters.push(new wn.ui.Filter(this, this.doctype, fieldname, condition, value));
},
get_filters: function() {
// get filter values as dict
var values = [];
$.each(this.filters, function(i, f) {
if(f.filter_field)
values.push(f.get_value());
})
return values;
}
});
wn.ui.Filter = Class.extend({
init: function(flist, doctype, fieldname, condition, value) {
flist.$w.find('.filter_area').append('<div class="list_filter">\
<select class="fieldname_select"></select>\
<select class="condition">\
<option value="=">Equals</option>\
<option value="like">Like</option>\
<option value=">=">Greater or equals</option>\
<option value=">=">Less or equals</option>\
<option value=">">Greater than</option>\
<option value="<">Less than</option>\
<option value="!=">Not equals</option>\
</select>\
<span class="filter_field"></span>\
<a class="close">&times;</a>\
</div>');
this.fields_by_name = {};
this.flist = flist;
this.$w = this.flist.$w.find('.list_filter:last-child');
this.doctype = doctype;
this.fieldname = fieldname;
this.condition = condition;
this.value = value;
this.set_events();
},
set_events: function() {
var me = this;
// render fields
this.render_field_select();
this.$w.find('.fieldname_select').bind('change', function() {
me.set_field(this.value);
});
this.$w.find('a.close').bind('click', function() {
me.$w.css('display','none');
var value = me.filter_field.get_value();
me.filter_field = null;
if(!me.flist.get_filters().length) {
me.flist.$w.find('.set_filters').toggle(true);
me.flist.$w.find('.show_filters').toggle(false);
me.list_obj.list.run();
}
if(value) {
me.list_obj.list.run();
}
return false;
});
// set the field
if(me.fieldname) {
// presents given (could be via tags!)
me.set_field(me.fieldname);
if(me.condition) me.$w.find('.condition').val(me.condition)
if(me.value) me.filter_field.set_input(me.value)
} else {
me.set_field('name');
}
},
render_field_select: function() {
var me = this;
var $fs = me.$w.find('.fieldname_select');
me.table_fields = [];
var std_filters = [
{fieldname:'name', fieldtype:'Data', label:'ID', parent:me.doctype},
{fieldname:'modified', fieldtype:'Date', label:'Last Modified', parent:me.doctype},
{fieldname:'owner', fieldtype:'Data', label:'Created By', parent:me.doctype},
{fieldname:'_user_tags', fieldtype:'Data', label:'Tags', parent:me.doctype}
];
// main table
$.each(std_filters.concat(fields_list[me.doctype]), function(i, df) {
me.add_field_option(df, $fs);
});
// child tables
$.each(me.table_fields, function(i,table_df) {
if(table_df.options) {
$.each(fields_list[table_df.options], function(i, df) {
me.add_field_option(df, $fs);
});
}
})
},
add_field_option: function(df, $fs) {
var me = this;
if(df.parent==me.doctype) {
var label = df.label;
var table = get_label_doctype(me.doctype);
if(df.fieldtype=='Table') me.table_fields.push(df);
} else {
var label = df.label + ' (' + df.parent + ')';
var table = df.parent;
}
if(wn.model.no_value_type.indexOf(df.fieldtype)==-1 &&
!me.fields_by_name[df.fieldname]) {
$fs.append($('<option>', {
value: df.fieldname,
table: table
}).text(label));
me.fields_by_name[df.fieldname] = df;
}
},
set_field: function(fieldname) {
var me = this;
// set in fieldname (again)
me.$w.find('.fieldname_select').val(fieldname);
wn.require('lib/js/legacy/widgets/form/fields.js');
var field_area = me.$w.find('.filter_field').get(0);
field_area.innerHTML = '';
var df = me.fields_by_name[fieldname];
df.original_type = df.fieldtype;
df.description = '';
if(df.fieldtype=='Check') {
df.fieldtype='Select';
df.options='No\nYes';
} else if(['Text','Text Editor','Code','Link'].indexOf(df.fieldtype)!=-1) {
df.fieldtype = 'Data';
}
f = make_field(me.fields_by_name[fieldname], null, field_area, null, 0, 1);
f.df.single_select = 1;
f.not_in_form = 1;
f.with_label = 0;
f.refresh();
me.filter_field = f;
// set as "like" for data fields
if(df.fieldtype=='Data') {
me.$w.find('.condition').val('like');
} else {
me.$w.find('.condition').val('=');
}
},
get_value: function() {
var me = this;
var val = me.filter_field.get_value();
var cond = me.$w.find('.condition').val();
if(me.filter_field.df.original_type == 'Check') {
val = (val=='Yes' ? 1 :0);
}
if(cond=='like') {
val = val + '%';
}
return [me.$w.find('.fieldname_select option:selected').attr('table'),
me.filter_field.df.fieldname, me.$w.find('.condition').val(), val];
}
});

View file

@ -26,171 +26,213 @@
//
// opts:
// parent
// method (method to call on server)
// args (additional args to method)
// get_args (method to return args as dict)
// show_filters [false]
// doctype
// filter_fields (if given, this list is rendered, else built from doctype)
// query or get_query (will be deprecated)
// query_max
// no_result_message ("No result")
// show_grid [false]
// page_length (20)
// filters ([{docfield}, ..])
// hide_refresh (False)
// new_doctype
// [function] render_row(parent, data)
// [function] onrun
// no_loading (no ajax indicator)
wn.widgets.Listing = function(opts) {
this.opts = opts;
this.page_length = 20;
this.btns = {};
this.start = 0;
var me = this;
// create place holders for all the elements
this.make = function(opts) {
if(this.opts.parent.jquery)
this.opts.parent = this.opts.parent.get(0);
this.wrapper = $a(this.opts.parent, 'div');
this.filters_area = $a(this.wrapper, 'div', 'listing-filters');
this.toolbar_area = $a(this.wrapper, 'div', 'listing-toolbar');
this.results_area = $a(this.wrapper, 'div', 'listing-results');
this.more_button_area = $a(this.wrapper, 'div', 'listing-more');
this.no_results_area = $a(this.wrapper, 'div', 'help_box', {display: 'none'},
(this.opts.no_result_message ? this.opts.no_result_message : 'No results'));
if(opts) this.opts = opts;
this.page_length = this.opts.page_length ? this.opts.page_length : this.page_length;
wn.provide('wn.ui');
wn.ui.Listing = Class.extend({
init: function(opts) {
this.opts = opts || {};
this.page_length = 20;
this.start = 0;
this.data = [];
if(opts) {
this.make();
}
},
prepare_opts: function() {
if(this.opts.new_doctype)
this.opts.new_doctype = get_doctype_label(this.opts.new_doctype);
},
make: function(opts) {
if(opts) {
this.opts = opts;
}
$.extend(this, this.opts);
this.prepare_opts();
this.make_toolbar();
$(this.parent).html(repl('\
<div class="wnlist">\
<div class="btn-group hide select-view" style="float: right;">\
<a class="btn btn-small btn-info btn-list">\
<i class="icon-list icon-white"></i> List</a>\
<a class="btn btn-small btn-grid">\
<i class="icon-th"></i> Grid</a>\
</div>\
\
<h3 class="title hide">%(title)s</h3>\
<div style="height: 30px;">\
<div class="btn-group" style="float: left;">\
<a class="btn btn-small btn-refresh btn-info">\
<i class="icon-refresh icon-white"></i> Refresh</a>\
<a class="btn btn-small btn-new">\
<i class="icon-plus"></i> New %(new_doctype)s</a>\
<a class="btn btn-small btn-filter">\
<i class="icon-search"></i> Filter</a>\
</div>\
<img src="lib/images/ui/button-load.gif" \
class="img-load"/>\
</div>\
\
<div style="clear: both; height: 11px;"></div>\
<div class="list-filters hide">\
<div class="show_filters well">\
<div class="filter_area"></div>\
<div>\
<button class="btn btn-small add-filter-btn">\
<i class="icon-plus"></i> Add Filter</button>\
</div>\
</div>\
</div>\
\
<div class="no-result help hide">\
%(no_result_message)s\
</div>\
\
<div class="result">\
<div class="result-list"></div>\
<div class="result-grid"></div>\
</div>\
\
<div class="paging-button hide">\
<button class="btn btn-small btn-more">More...</div>\
</div>\
</div>\
', this.opts));
this.$w = $(this.parent).find('.wnlist');
this.set_events();
this.make_filters();
this.make_more_button();
}
},
show_view: function($btn, $div, $btn_unsel, $div_unsel) {
$btn_unsel.removeClass('btn-info');
$btn_unsel.find('i').removeClass('icon-white');
$div_unsel.toggle(false);
$btn.addClass('btn-info');
$btn.find('i').addClass('icon-white');
$div.toggle(true);
},
set_events: function() {
var me = this;
// make filters using FieldGroup
this.make_filters = function() {
if(this.opts.filters) {
$ds(this.filters_area);
// expand / collapse filters
this.filters = new wn.widgets.FieldGroup(this.filters_area, this.opts.fields);
}
}
// make the toolbar
this.make_toolbar = function() {
if(!(this.opts.hide_refresh || this.opts.no_refresh)) {
if(this.opts.title) {
$a(this.toolbar_area, 'h3', '',
{display:'inline-block',marginRight:'15px'},
this.opts.title);
}
this.ref_img = $a(this.toolbar_area, 'span', 'link_type',
{color:'#888'}, '[refresh]');
this.ref_img.onclick = function() { me.run(); }
this.loading_img = $a(this.toolbar_area, 'img', 'lib/images/ui/button-load.gif', {display:'none', marginLeft:'3px', marginBottom:'-2px'});
// run
this.$w.find('.btn-refresh').click(function() {
me.run();
});
// next page
this.$w.find('.btn-more').click(function() {
me.run({append: true });
});
// show list view
this.$w.find('.btn-list').click(function() {
me.show_view($(this), me.$w.find('.result-list'),
me.$w.find('.btn-grid'), me.$w.find('.result-grid'))
});
// show grid view
this.$w.find('.btn-grid').click(function() {
me.show_view($(this), me.$w.find('.result-grid'),
me.$w.find('.btn-list'), me.$w.find('.result-list'))
});
// title
if(this.title) {
this.$w.find('h3').html(this.title).toggle(true);
}
if(this.opts.new_doctype) {
this.new_btn = $btn(this.toolbar_area,
'New ' + get_doctype_label(this.opts.new_doctype),
function() {
newdoc(me.opts.new_doctype, me.opts.new_doc_onload, me.opts.new_doc_indialog, me.opts.new_doc_onsave);
},
{marginLeft:'7px'});
}
}
// make more button
// that shows more results when they are displayed
this.make_more_button = function() {
this.more_btn = $btn(this.more_button_area, 'More...',
function() {
me.more_btn.set_working();
me.run(function() {
me.more_btn.done_working();
}, 1);
}, '', 0, 1
);
$y(this.more_btn.loading_img, {marginBottom:'0px'});
}
// clear the results and re-run the query
this.clear = function() {
this.results_area.innerHTML = '';
this.table = null;
$ds(this.results_area);
$dh(this.no_results_area);
}
// callback on the query
// build the table
// returns r.values as a table of results
this.make_results = function(r, rt) {
if(this.start==0) this.clear();
$dh(this.more_button_area);
if(this.loading_img) $dh(this.loading_img)
if(r.message) r.values = r.message;
if(r.values && r.values.length) {
this.values = r.values;
var m = Math.min(r.values.length, this.page_length);
// render the rows
for(var i=0; i < m; i++) {
var row = this.add_row();
// call the show_cell with row, ri, ci, d
this.opts.render_row(row, r.values[i], this, i);
}
// extend start
this.start += m;
// refreh more button
if(r.values.length >= this.page_length) $ds(this.more_button_area);
// new
if(this.new_doctype) {
this.$w.find('.btn-new').toggle(true).click(function() {
newdoc(me.new_doctype);
})
} else {
if(this.start==0) {
$dh(this.results_area);
$ds(this.no_results_area);
}
this.$w.find('.btn-new').toggle(false);
}
// callbacks
if(this.onrun) this.onrun();
if(this.opts.onrun) this.opts.onrun();
if(this.opts.callback) this.opts.callback(r);
}
// add a results row
this.add_row = function() {
return $a(this.results_area, 'div', '',
(opts.cell_style ? opts.cell_style : {padding: '3px 0px'}));
}
// hide-filter
if(!me.show_filters) {
this.$w.find('.btn-filter').toggle(false);
}
// hide-refresh
if(this.hide_refresh || this.no_refresh) {
this.$w.find('.btn-refresh').toggle(false);
}
// toggle-view
if(this.show_grid) {
this.$w.find('.select-view').toggle(true);
}
},
make_filters: function() {
this.filter_list = new wn.ui.FilterList({
listobj: this,
$parent: this.$w.find('.list-filters').toggle(true),
doctype: this.doctype,
filter_fields: this.filter_fields
});
},
// run the query, get the query from
// the get_query method of opts
this.run = function(callback, append) {
if(callback)
this.onrun = callback;
if(!append)
this.start = 0;
clear: function() {
this.data = [];
this.$w.find('.result-list').empty();
this.$w.find('.result').toggle(true);
this.$w.find('.no-result').toggle(false);
this.start = 0;
},
run: function() {
// in old - arguments: 0 = callback, 1 = append
var me = this;
var a0 = arguments[0]; var a1 = arguments[1];
if(a0 && typeof a0=='function')
this.onrun = a0;
if(a0 && a0.callback)
this.onrun = a0.callback;
if(!a1 || (a0 && a0.append))
this.start = 0;
me.$w.find('.img-load').toggle(true);
wn.call({
method: this.opts.method || 'webnotes.widgets.query_builder.runquery',
args: this.get_call_args(),
callback: function(r) {
me.$w.find('.img-load').toggle(false);
me.render_results(r)
},
no_spinner: this.opts.no_loading,
btn: this.run_btn
});
},
get_call_args: function() {
// load query
if(!this.opts.method) {
this.query = this.opts.get_query ? this.opts.get_query() : this.opts.query;
if(!this.method) {
this.query = this.get_query ? this.get_query() : this.query;
this.add_limits();
var args={
query_max: this.query_max || this.opts.query_max || '',
query_max: this.query_max,
as_dict: 1
}
args.simple_query = this.query;
@ -201,29 +243,311 @@ wn.widgets.Listing = function(opts) {
}
}
if(this.opts.args)
$.extend(args, this.opts.args)
// append user-defined arguments
if(this.args)
$.extend(args, this.args)
if(this.opts.get_args) {
$.extend(args, this.opts.get_args());
if(this.get_args) {
$.extend(args, this.get_args());
}
return args;
},
render_results: function(r) {
if(this.start==0) this.clear();
this.$w.find('.btn-more').toggle(false);
if(r.message) r.values = r.message;
if(r.values && r.values.length) {
this.data = this.data.concat(r.values);
this.render_list(r.values);
if(this.show_grid) {
this.render_grid();
}
} else {
if(this.start==0) {
this.$w.find('.result').toggle(false);
this.$w.find('.no-result').toggle(true);
}
}
// show loading
if(this.loading_img) $di(this.loading_img);
wn.call({
method: this.opts.method || 'webnotes.widgets.query_builder.runquery',
args: args,
callback: function(r, rt) { me.make_results(r, rt) },
no_spinner: this.opts.no_loading,
btn: this.opts.run_btn
});
}
this.refresh = this.run;
this.add_limits = function() {
// callbacks
if(this.onrun) this.onrun();
if(this.callback) this.callback(r);
},
render_grid: function() {
//this.gridid = wn.dom.set_unique_id()
$.each(this.columns, function(i, c) {
if(!c.id) c.id = c.field;
})
wn.require('lib/js/lib/slickgrid/slick.grid.css');
wn.require('lib/js/lib/slickgrid/slick-default-theme.css');
wn.require('lib/js/lib/slickgrid/jquery.event.drag.min.js');
wn.require('lib/js/lib/slickgrid/slick.core.js');
wn.require('lib/js/lib/slickgrid/slick.grid.js');
var options = {
enableCellNavigation: true,
enableColumnReorder: false
};
grid = new Slick.Grid(this.$w.find('.result-grid')
.css('border', '1px solid grey')
.css('height', '500px')
.get(0), this.data,
this.columns, options);
},
render_list: function(values) {
var m = Math.min(values.length, this.page_length);
// render the rows
for(var i=0; i < m; i++) {
this.render_row(this.add_row(), values[i], this, i);
}
// extend start
this.start += m;
// refreh more button
if(values.length >= this.page_length)
this.$w.find('.btn-more').toggle(true);
},
add_row: function() {
return this.$w.find('.result-list').append('<div class="list-row">')
.find('.list-row:last').get(0);
},
refresh: function() {
this.run();
},
add_limits: function() {
this.query += ' LIMIT ' + this.start + ',' + (this.page_length+1);
}
}
});
wn.ui.FilterList = Class.extend({
init: function(opts) {
$.extend(this, opts);
this.filters = [];
this.$w = this.$parent;
this.set_events();
},
set_events: function() {
var me = this;
// show filters
this.listobj.$w.find('.btn-filter').bind('click', function() {
me.$w.find('.show_filters').slideToggle();
if(!me.filters.length)
me.add_filter();
});
// show filters
this.$w.find('.add-filter-btn').bind('click', function() {
me.add_filter();
});
},
if(opts) this.make();
}
add_filter: function(fieldname, condition, value) {
this.filters.push(new wn.ui.Filter({
flist: this,
fieldname: fieldname,
condition: condition,
value: value
}));
},
get_filters: function() {
// get filter values as dict
var values = [];
$.each(this.filters, function(i, f) {
if(f.filter_field)
values.push(f.get_value());
})
return values;
},
// remove hidden filters
update_filters: function() {
var fl = [];
$.each(this.filters, function(i, f) {
if(f.filter_field) fl.push(f);
})
this.filters = fl;
}
});
wn.ui.Filter = Class.extend({
init: function(opts) {
$.extend(this, opts);
this.doctype = this.flist.doctype;
this.fields_by_name = {};
this.make();
this.make_options();
this.set_events();
},
make: function() {
this.flist.$w.find('.filter_area').append('<div class="list_filter">\
<select class="fieldname_select"></select>\
<select class="condition">\
<option value="=">Equals</option>\
<option value="like">Like</option>\
<option value=">=">Greater or equals</option>\
<option value=">=">Less or equals</option>\
<option value=">">Greater than</option>\
<option value="<">Less than</option>\
<option value="!=">Not equals</option>\
</select>\
<span class="filter_field"></span>\
<a class="close">&times;</a>\
</div>');
this.$w = this.flist.$w.find('.list_filter:last-child');
this.$select = this.$w.find('.fieldname_select');
},
make_options: function() {
if(this.filter_fields) {
// filters specified explicitly
for(var i in this.filter_fields)
this.add_field_option(this.filter_fields[i])
} else {
// filters to be built from doctype
this.render_field_select();
}
},
set_events: function() {
var me = this;
// render fields
this.$w.find('.fieldname_select').bind('change', function() {
me.set_field(this.value);
});
this.$w.find('a.close').bind('click', function() {
me.$w.css('display','none');
var value = me.filter_field.get_value();
me.filter_field = null;
if(!me.flist.get_filters().length) {
me.flist.$w.find('.set_filters').toggle(true);
me.flist.$w.find('.show_filters').toggle(false);
}
if(value) {
me.flist.listobj.run();
}
me.flist.update_filters();
return false;
});
// set the field
if(me.fieldname) {
// presents given (could be via tags!)
me.set_field(me.fieldname);
if(me.condition) me.$w.find('.condition').val(me.condition)
if(me.value) me.filter_field.set_input(me.value)
} else {
me.set_field('name');
}
},
render_field_select: function() {
var me = this;
me.table_fields = [];
var std_filters = [
{fieldname:'name', fieldtype:'Data', label:'ID', parent:me.doctype},
{fieldname:'modified', fieldtype:'Date', label:'Last Modified', parent:me.doctype},
{fieldname:'owner', fieldtype:'Data', label:'Created By', parent:me.doctype},
{fieldname:'_user_tags', fieldtype:'Data', label:'Tags', parent:me.doctype}
];
// main table
$.each(std_filters.concat(fields_list[me.doctype]), function(i, df) {
me.add_field_option(df);
});
// child tables
$.each(me.table_fields, function(i,table_df) {
if(table_df.options) {
$.each(fields_list[table_df.options], function(i, df) {
me.add_field_option(df);
});
}
})
},
add_field_option: function(df) {
var me = this;
if(me.doctype && df.parent==me.doctype) {
var label = df.label;
var table = get_label_doctype(me.doctype);
if(df.fieldtype=='Table') me.table_fields.push(df);
} else {
var label = df.label + ' (' + df.parent + ')';
var table = df.parent;
}
if(wn.model.no_value_type.indexOf(df.fieldtype)==-1 &&
!me.fields_by_name[df.fieldname]) {
this.$select.append($('<option>', {
value: df.fieldname,
table: table
}).text(label));
me.fields_by_name[df.fieldname] = df;
}
},
set_field: function(fieldname) {
var me = this;
// set in fieldname (again)
me.$w.find('.fieldname_select').val(fieldname);
wn.require('lib/js/legacy/widgets/form/fields.js');
var field_area = me.$w.find('.filter_field').empty().get(0);
var df = me.fields_by_name[fieldname];
df.original_type = df.fieldtype;
df.description = '';
if(df.fieldtype=='Check') {
df.fieldtype='Select';
df.options='No\nYes';
} else if(['Text','Text Editor','Code','Link'].indexOf(df.fieldtype)!=-1) {
df.fieldtype = 'Data';
}
f = make_field(me.fields_by_name[fieldname], null, field_area, null, 0, 1);
f.df.single_select = 1;
f.not_in_form = 1;
f.with_label = 0;
f.refresh();
me.filter_field = f;
// set as "like" for data fields
if(df.fieldtype=='Data') {
me.$w.find('.condition').val('like');
} else {
me.$w.find('.condition').val('=');
}
},
get_value: function() {
var me = this;
var val = me.filter_field.get_value();
var cond = me.$w.find('.condition').val();
if(me.filter_field.df.original_type == 'Check') {
val = (val=='Yes' ? 1 :0);
}
if(cond=='like') {
val = val + '%';
}
return [me.$w.find('.fieldname_select option:selected').attr('table'),
me.filter_field.df.fieldname, me.$w.find('.condition').val(), val];
}
});

View file

@ -61,4 +61,4 @@ def get(arg=None):
query = """select %(fields)s from %(tables)s where %(conditions)s
order by %(order_by)s
limit %(limit_start)s, %(limit_page_length)s""" % data
return webnotes.conn.sql(query, as_dict=1, debug=1)
return webnotes.conn.sql(query, as_dict=1)