new listing and changed wn.widgets.listing to wn.ui.listing
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -235,4 +235,4 @@ div.std-footer-item {
|
|||
height: 24px;
|
||||
margin-bottom: -7px;
|
||||
max-width: 24px;
|
||||
}
|
||||
}
|
||||
0
css/legacy/final.css
Normal 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
|
||||
}
|
||||
|
|
@ -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 = {
|
||||
|
|
|
|||
BIN
js/lib/slickgrid/images/actions.gif
Normal file
|
After Width: | Height: | Size: 170 B |
BIN
js/lib/slickgrid/images/ajax-loader-small.gif
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
js/lib/slickgrid/images/arrow_redo.png
Normal file
|
After Width: | Height: | Size: 625 B |
BIN
js/lib/slickgrid/images/arrow_right_peppermint.png
Normal file
|
After Width: | Height: | Size: 240 B |
BIN
js/lib/slickgrid/images/arrow_right_spearmint.png
Normal file
|
After Width: | Height: | Size: 240 B |
BIN
js/lib/slickgrid/images/arrow_undo.png
Normal file
|
After Width: | Height: | Size: 631 B |
BIN
js/lib/slickgrid/images/bullet_blue.png
Normal file
|
After Width: | Height: | Size: 289 B |
BIN
js/lib/slickgrid/images/bullet_star.png
Normal file
|
After Width: | Height: | Size: 347 B |
BIN
js/lib/slickgrid/images/bullet_toggle_minus.png
Normal file
|
After Width: | Height: | Size: 207 B |
BIN
js/lib/slickgrid/images/bullet_toggle_plus.png
Normal file
|
After Width: | Height: | Size: 209 B |
BIN
js/lib/slickgrid/images/calendar.gif
Normal file
|
After Width: | Height: | Size: 1 KiB |
BIN
js/lib/slickgrid/images/collapse.gif
Normal file
|
After Width: | Height: | Size: 846 B |
BIN
js/lib/slickgrid/images/comment_yellow.gif
Normal file
|
After Width: | Height: | Size: 257 B |
BIN
js/lib/slickgrid/images/down.gif
Normal file
|
After Width: | Height: | Size: 59 B |
BIN
js/lib/slickgrid/images/drag-handle.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
js/lib/slickgrid/images/editor-helper-bg.gif
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
js/lib/slickgrid/images/expand.gif
Normal file
|
After Width: | Height: | Size: 851 B |
BIN
js/lib/slickgrid/images/header-bg.gif
Normal file
|
After Width: | Height: | Size: 872 B |
BIN
js/lib/slickgrid/images/header-columns-bg.gif
Normal file
|
After Width: | Height: | Size: 836 B |
BIN
js/lib/slickgrid/images/header-columns-over-bg.gif
Normal file
|
After Width: | Height: | Size: 823 B |
BIN
js/lib/slickgrid/images/help.png
Normal file
|
After Width: | Height: | Size: 510 B |
BIN
js/lib/slickgrid/images/info.gif
Normal file
|
After Width: | Height: | Size: 80 B |
BIN
js/lib/slickgrid/images/listview.gif
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
js/lib/slickgrid/images/pencil.gif
Normal file
|
After Width: | Height: | Size: 914 B |
BIN
js/lib/slickgrid/images/row-over-bg.gif
Normal file
|
After Width: | Height: | Size: 823 B |
BIN
js/lib/slickgrid/images/sort-asc.gif
Normal file
|
After Width: | Height: | Size: 830 B |
BIN
js/lib/slickgrid/images/sort-asc.png
Normal file
|
After Width: | Height: | Size: 163 B |
BIN
js/lib/slickgrid/images/sort-desc.gif
Normal file
|
After Width: | Height: | Size: 833 B |
BIN
js/lib/slickgrid/images/sort-desc.png
Normal file
|
After Width: | Height: | Size: 161 B |
BIN
js/lib/slickgrid/images/stripes.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
js/lib/slickgrid/images/tag_red.png
Normal file
|
After Width: | Height: | Size: 592 B |
BIN
js/lib/slickgrid/images/tick.png
Normal file
|
After Width: | Height: | Size: 537 B |
BIN
js/lib/slickgrid/images/user_identity.gif
Normal file
|
After Width: | Height: | Size: 905 B |
BIN
js/lib/slickgrid/images/user_identity_plus.gif
Normal file
|
After Width: | Height: | Size: 546 B |
6
js/lib/slickgrid/jquery.event.drag.min.js
vendored
Normal 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);
|
||||
295
js/lib/slickgrid/slick-default-theme.css
Normal 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
|
|
@ -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);
|
||||
|
||||
|
||||
158
js/lib/slickgrid/slick.grid.css
Normal 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
|
|
@ -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();">×</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">×</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];
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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">×</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];
|
||||
}
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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)
|
||||