SlickGrid Integration in to query tool. Fixes #1618
@ -31,3 +31,5 @@ dropzone 4e20bd4 MIT https://github.com/enyo/dropzone
|
|||||||
Filemanager 7e060c2 MIT https://github.com/simogeo/Filemanager
|
Filemanager 7e060c2 MIT https://github.com/simogeo/Filemanager
|
||||||
Unit (Length) d8e6237 MIT https://github.com/heygrady/Units/blob/master/Length.min.js
|
Unit (Length) d8e6237 MIT https://github.com/heygrady/Units/blob/master/Length.min.js
|
||||||
Natural Sort 9565816 MIT https://github.com/javve/natural-sort/blob/master/index.js
|
Natural Sort 9565816 MIT https://github.com/javve/natural-sort/blob/master/index.js
|
||||||
|
SlickGrid 2.2.4 MIT https://github.com/6pac/SlickGrid
|
||||||
|
jQuery-UI 1.11.3 MIT https://jqueryui.com/
|
||||||
|
BIN
web/pgadmin/static/css/slickgrid/images/actions.gif
Normal file
After Width: | Height: | Size: 170 B |
BIN
web/pgadmin/static/css/slickgrid/images/ajax-loader-small.gif
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
web/pgadmin/static/css/slickgrid/images/arrow_redo.png
Normal file
After Width: | Height: | Size: 572 B |
After Width: | Height: | Size: 128 B |
After Width: | Height: | Size: 128 B |
BIN
web/pgadmin/static/css/slickgrid/images/arrow_undo.png
Normal file
After Width: | Height: | Size: 578 B |
BIN
web/pgadmin/static/css/slickgrid/images/bullet_blue.png
Normal file
After Width: | Height: | Size: 241 B |
BIN
web/pgadmin/static/css/slickgrid/images/bullet_star.png
Normal file
After Width: | Height: | Size: 279 B |
BIN
web/pgadmin/static/css/slickgrid/images/bullet_toggle_minus.png
Normal file
After Width: | Height: | Size: 154 B |
BIN
web/pgadmin/static/css/slickgrid/images/bullet_toggle_plus.png
Normal file
After Width: | Height: | Size: 156 B |
BIN
web/pgadmin/static/css/slickgrid/images/calendar.gif
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
web/pgadmin/static/css/slickgrid/images/collapse.gif
Normal file
After Width: | Height: | Size: 846 B |
BIN
web/pgadmin/static/css/slickgrid/images/comment_yellow.gif
Normal file
After Width: | Height: | Size: 257 B |
BIN
web/pgadmin/static/css/slickgrid/images/down.gif
Normal file
After Width: | Height: | Size: 59 B |
BIN
web/pgadmin/static/css/slickgrid/images/drag-handle.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
web/pgadmin/static/css/slickgrid/images/editor-helper-bg.gif
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
web/pgadmin/static/css/slickgrid/images/expand.gif
Normal file
After Width: | Height: | Size: 851 B |
BIN
web/pgadmin/static/css/slickgrid/images/header-bg.gif
Normal file
After Width: | Height: | Size: 872 B |
BIN
web/pgadmin/static/css/slickgrid/images/header-columns-bg.gif
Normal file
After Width: | Height: | Size: 836 B |
After Width: | Height: | Size: 823 B |
BIN
web/pgadmin/static/css/slickgrid/images/help.png
Normal file
After Width: | Height: | Size: 345 B |
BIN
web/pgadmin/static/css/slickgrid/images/info.gif
Normal file
After Width: | Height: | Size: 80 B |
BIN
web/pgadmin/static/css/slickgrid/images/listview.gif
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
web/pgadmin/static/css/slickgrid/images/pencil.gif
Normal file
After Width: | Height: | Size: 914 B |
BIN
web/pgadmin/static/css/slickgrid/images/row-over-bg.gif
Normal file
After Width: | Height: | Size: 823 B |
BIN
web/pgadmin/static/css/slickgrid/images/sort-asc.gif
Normal file
After Width: | Height: | Size: 830 B |
BIN
web/pgadmin/static/css/slickgrid/images/sort-asc.png
Normal file
After Width: | Height: | Size: 105 B |
BIN
web/pgadmin/static/css/slickgrid/images/sort-desc.gif
Normal file
After Width: | Height: | Size: 833 B |
BIN
web/pgadmin/static/css/slickgrid/images/sort-desc.png
Normal file
After Width: | Height: | Size: 107 B |
BIN
web/pgadmin/static/css/slickgrid/images/stripes.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
web/pgadmin/static/css/slickgrid/images/tag_red.png
Normal file
After Width: | Height: | Size: 537 B |
BIN
web/pgadmin/static/css/slickgrid/images/tick.png
Normal file
After Width: | Height: | Size: 484 B |
BIN
web/pgadmin/static/css/slickgrid/images/user_identity.gif
Normal file
After Width: | Height: | Size: 905 B |
BIN
web/pgadmin/static/css/slickgrid/images/user_identity_plus.gif
Normal file
After Width: | Height: | Size: 546 B |
118
web/pgadmin/static/css/slickgrid/slick-default-theme.css
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
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('images/header-columns-bg.gif') repeat-x center bottom;
|
||||||
|
border-bottom: 1px solid silver;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-header-column {
|
||||||
|
background: url('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('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(images/collapse.gif) no-repeat center center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-group-toggle.collapsed {
|
||||||
|
background: url(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.odd {
|
||||||
|
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;
|
||||||
|
-moz-animation-duration: 0.2s;
|
||||||
|
-webkit-animation-duration: 0.2s;
|
||||||
|
-moz-animation-name: slickgrid-invalid-hilite;
|
||||||
|
-webkit-animation-name: slickgrid-invalid-hilite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-moz-keyframes slickgrid-invalid-hilite {
|
||||||
|
from { box-shadow: 0 0 6px red; }
|
||||||
|
to { box-shadow: none; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes slickgrid-invalid-hilite {
|
||||||
|
from { box-shadow: 0 0 6px red; }
|
||||||
|
to { box-shadow: none; }
|
||||||
|
}
|
158
web/pgadmin/static/css/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 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-header-columns, .slick-headerrow-columns {
|
||||||
|
position: relative;
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: default;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-header-column.ui-state-default {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
/*box-sizing: content-box !important; */
|
||||||
|
overflow: hidden;
|
||||||
|
-o-text-overflow: ellipsis;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
height: 16px;
|
||||||
|
line-height: 16px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 4px;
|
||||||
|
border-right: 1px solid silver;
|
||||||
|
border-left: 0px !important;
|
||||||
|
border-top: 0px !important;
|
||||||
|
border-bottom: 0px !important;
|
||||||
|
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;
|
||||||
|
margin-top: 6px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
-o-text-overflow: ellipsis;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
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;
|
||||||
|
-o-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;
|
||||||
|
}
|
After Width: | Height: | Size: 212 B |
After Width: | Height: | Size: 208 B |
After Width: | Height: | Size: 335 B |
After Width: | Height: | Size: 207 B |
After Width: | Height: | Size: 262 B |
After Width: | Height: | Size: 262 B |
After Width: | Height: | Size: 332 B |
After Width: | Height: | Size: 280 B |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 4.4 KiB |
1225
web/pgadmin/static/css/slickgrid/smoothness/jquery-ui-1.11.3.custom.css
vendored
Normal file
7
web/pgadmin/static/css/slickgrid/smoothness/jquery-ui-1.11.3.custom.min.css
vendored
Normal file
16608
web/pgadmin/static/js/jquery-ui/jquery-ui-1.11.3.js
vendored
Normal file
13
web/pgadmin/static/js/jquery-ui/jquery-ui-1.11.3.min.js
vendored
Normal file
402
web/pgadmin/static/js/jquery-ui/jquery.event.drag-2.2.js
Normal file
@ -0,0 +1,402 @@
|
|||||||
|
/*!
|
||||||
|
* jquery.event.drag - v 2.2
|
||||||
|
* Copyright (c) 2010 Three Dub Media - http://threedubmedia.com
|
||||||
|
* Open Source MIT License - http://threedubmedia.com/code/license
|
||||||
|
*/
|
||||||
|
// Created: 2008-06-04
|
||||||
|
// Updated: 2012-05-21
|
||||||
|
// REQUIRES: jquery 1.7.x
|
||||||
|
|
||||||
|
;(function( $ ){
|
||||||
|
|
||||||
|
// add the jquery instance method
|
||||||
|
$.fn.drag = function( str, arg, opts ){
|
||||||
|
// figure out the event type
|
||||||
|
var type = typeof str == "string" ? str : "",
|
||||||
|
// figure out the event handler...
|
||||||
|
fn = $.isFunction( str ) ? str : $.isFunction( arg ) ? arg : null;
|
||||||
|
// fix the event type
|
||||||
|
if ( type.indexOf("drag") !== 0 )
|
||||||
|
type = "drag"+ type;
|
||||||
|
// were options passed
|
||||||
|
opts = ( str == fn ? arg : opts ) || {};
|
||||||
|
// trigger or bind event handler
|
||||||
|
return fn ? this.bind( type, opts, fn ) : this.trigger( type );
|
||||||
|
};
|
||||||
|
|
||||||
|
// local refs (increase compression)
|
||||||
|
var $event = $.event,
|
||||||
|
$special = $event.special,
|
||||||
|
// configure the drag special event
|
||||||
|
drag = $special.drag = {
|
||||||
|
|
||||||
|
// these are the default settings
|
||||||
|
defaults: {
|
||||||
|
which: 1, // mouse button pressed to start drag sequence
|
||||||
|
distance: 0, // distance dragged before dragstart
|
||||||
|
not: ':input', // selector to suppress dragging on target elements
|
||||||
|
handle: null, // selector to match handle target elements
|
||||||
|
relative: false, // true to use "position", false to use "offset"
|
||||||
|
drop: true, // false to suppress drop events, true or selector to allow
|
||||||
|
click: false // false to suppress click events after dragend (no proxy)
|
||||||
|
},
|
||||||
|
|
||||||
|
// the key name for stored drag data
|
||||||
|
datakey: "dragdata",
|
||||||
|
|
||||||
|
// prevent bubbling for better performance
|
||||||
|
noBubble: true,
|
||||||
|
|
||||||
|
// count bound related events
|
||||||
|
add: function( obj ){
|
||||||
|
// read the interaction data
|
||||||
|
var data = $.data( this, drag.datakey ),
|
||||||
|
// read any passed options
|
||||||
|
opts = obj.data || {};
|
||||||
|
// count another realted event
|
||||||
|
data.related += 1;
|
||||||
|
// extend data options bound with this event
|
||||||
|
// don't iterate "opts" in case it is a node
|
||||||
|
$.each( drag.defaults, function( key, def ){
|
||||||
|
if ( opts[ key ] !== undefined )
|
||||||
|
data[ key ] = opts[ key ];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// forget unbound related events
|
||||||
|
remove: function(){
|
||||||
|
$.data( this, drag.datakey ).related -= 1;
|
||||||
|
},
|
||||||
|
|
||||||
|
// configure interaction, capture settings
|
||||||
|
setup: function(){
|
||||||
|
// check for related events
|
||||||
|
if ( $.data( this, drag.datakey ) )
|
||||||
|
return;
|
||||||
|
// initialize the drag data with copied defaults
|
||||||
|
var data = $.extend({ related:0 }, drag.defaults );
|
||||||
|
// store the interaction data
|
||||||
|
$.data( this, drag.datakey, data );
|
||||||
|
// bind the mousedown event, which starts drag interactions
|
||||||
|
$event.add( this, "touchstart mousedown", drag.init, data );
|
||||||
|
// prevent image dragging in IE...
|
||||||
|
if ( this.attachEvent )
|
||||||
|
this.attachEvent("ondragstart", drag.dontstart );
|
||||||
|
},
|
||||||
|
|
||||||
|
// destroy configured interaction
|
||||||
|
teardown: function(){
|
||||||
|
var data = $.data( this, drag.datakey ) || {};
|
||||||
|
// check for related events
|
||||||
|
if ( data.related )
|
||||||
|
return;
|
||||||
|
// remove the stored data
|
||||||
|
$.removeData( this, drag.datakey );
|
||||||
|
// remove the mousedown event
|
||||||
|
$event.remove( this, "touchstart mousedown", drag.init );
|
||||||
|
// enable text selection
|
||||||
|
drag.textselect( true );
|
||||||
|
// un-prevent image dragging in IE...
|
||||||
|
if ( this.detachEvent )
|
||||||
|
this.detachEvent("ondragstart", drag.dontstart );
|
||||||
|
},
|
||||||
|
|
||||||
|
// initialize the interaction
|
||||||
|
init: function( event ){
|
||||||
|
// sorry, only one touch at a time
|
||||||
|
if ( drag.touched )
|
||||||
|
return;
|
||||||
|
// the drag/drop interaction data
|
||||||
|
var dd = event.data, results;
|
||||||
|
// check the which directive
|
||||||
|
if ( event.which != 0 && dd.which > 0 && event.which != dd.which )
|
||||||
|
return;
|
||||||
|
// check for suppressed selector
|
||||||
|
if ( $( event.target ).is( dd.not ) )
|
||||||
|
return;
|
||||||
|
// check for handle selector
|
||||||
|
if ( dd.handle && !$( event.target ).closest( dd.handle, event.currentTarget ).length )
|
||||||
|
return;
|
||||||
|
|
||||||
|
drag.touched = event.type == 'touchstart' ? this : null;
|
||||||
|
dd.propagates = 1;
|
||||||
|
dd.mousedown = this;
|
||||||
|
dd.interactions = [ drag.interaction( this, dd ) ];
|
||||||
|
dd.target = event.target;
|
||||||
|
dd.pageX = event.pageX;
|
||||||
|
dd.pageY = event.pageY;
|
||||||
|
dd.dragging = null;
|
||||||
|
// handle draginit event...
|
||||||
|
results = drag.hijack( event, "draginit", dd );
|
||||||
|
// early cancel
|
||||||
|
if ( !dd.propagates )
|
||||||
|
return;
|
||||||
|
// flatten the result set
|
||||||
|
results = drag.flatten( results );
|
||||||
|
// insert new interaction elements
|
||||||
|
if ( results && results.length ){
|
||||||
|
dd.interactions = [];
|
||||||
|
$.each( results, function(){
|
||||||
|
dd.interactions.push( drag.interaction( this, dd ) );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// remember how many interactions are propagating
|
||||||
|
dd.propagates = dd.interactions.length;
|
||||||
|
// locate and init the drop targets
|
||||||
|
if ( dd.drop !== false && $special.drop )
|
||||||
|
$special.drop.handler( event, dd );
|
||||||
|
// disable text selection
|
||||||
|
drag.textselect( false );
|
||||||
|
// bind additional events...
|
||||||
|
if ( drag.touched )
|
||||||
|
$event.add( drag.touched, "touchmove touchend", drag.handler, dd );
|
||||||
|
else
|
||||||
|
$event.add( document, "mousemove mouseup", drag.handler, dd );
|
||||||
|
// helps prevent text selection or scrolling
|
||||||
|
if ( !drag.touched || dd.live )
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
// returns an interaction object
|
||||||
|
interaction: function( elem, dd ){
|
||||||
|
var offset = $( elem )[ dd.relative ? "position" : "offset" ]() || { top:0, left:0 };
|
||||||
|
return {
|
||||||
|
drag: elem,
|
||||||
|
callback: new drag.callback(),
|
||||||
|
droppable: [],
|
||||||
|
offset: offset
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
// handle drag-releatd DOM events
|
||||||
|
handler: function( event ){
|
||||||
|
// read the data before hijacking anything
|
||||||
|
var dd = event.data;
|
||||||
|
// handle various events
|
||||||
|
switch ( event.type ){
|
||||||
|
// mousemove, check distance, start dragging
|
||||||
|
case !dd.dragging && 'touchmove':
|
||||||
|
event.preventDefault();
|
||||||
|
case !dd.dragging && 'mousemove':
|
||||||
|
// drag tolerance, x≤ + y≤ = distance≤
|
||||||
|
if ( Math.pow( event.pageX-dd.pageX, 2 ) + Math.pow( event.pageY-dd.pageY, 2 ) < Math.pow( dd.distance, 2 ) )
|
||||||
|
break; // distance tolerance not reached
|
||||||
|
event.target = dd.target; // force target from "mousedown" event (fix distance issue)
|
||||||
|
drag.hijack( event, "dragstart", dd ); // trigger "dragstart"
|
||||||
|
if ( dd.propagates ) // "dragstart" not rejected
|
||||||
|
dd.dragging = true; // activate interaction
|
||||||
|
// mousemove, dragging
|
||||||
|
case 'touchmove':
|
||||||
|
event.preventDefault();
|
||||||
|
case 'mousemove':
|
||||||
|
if ( dd.dragging ){
|
||||||
|
// trigger "drag"
|
||||||
|
drag.hijack( event, "drag", dd );
|
||||||
|
if ( dd.propagates ){
|
||||||
|
// manage drop events
|
||||||
|
if ( dd.drop !== false && $special.drop )
|
||||||
|
$special.drop.handler( event, dd ); // "dropstart", "dropend"
|
||||||
|
break; // "drag" not rejected, stop
|
||||||
|
}
|
||||||
|
event.type = "mouseup"; // helps "drop" handler behave
|
||||||
|
}
|
||||||
|
// mouseup, stop dragging
|
||||||
|
case 'touchend':
|
||||||
|
case 'mouseup':
|
||||||
|
default:
|
||||||
|
if ( drag.touched )
|
||||||
|
$event.remove( drag.touched, "touchmove touchend", drag.handler ); // remove touch events
|
||||||
|
else
|
||||||
|
$event.remove( document, "mousemove mouseup", drag.handler ); // remove page events
|
||||||
|
if ( dd.dragging ){
|
||||||
|
if ( dd.drop !== false && $special.drop )
|
||||||
|
$special.drop.handler( event, dd ); // "drop"
|
||||||
|
drag.hijack( event, "dragend", dd ); // trigger "dragend"
|
||||||
|
}
|
||||||
|
drag.textselect( true ); // enable text selection
|
||||||
|
// if suppressing click events...
|
||||||
|
if ( dd.click === false && dd.dragging )
|
||||||
|
$.data( dd.mousedown, "suppress.click", new Date().getTime() + 5 );
|
||||||
|
dd.dragging = drag.touched = false; // deactivate element
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// re-use event object for custom events
|
||||||
|
hijack: function( event, type, dd, x, elem ){
|
||||||
|
// not configured
|
||||||
|
if ( !dd )
|
||||||
|
return;
|
||||||
|
// remember the original event and type
|
||||||
|
var orig = { event:event.originalEvent, type:event.type },
|
||||||
|
// is the event drag related or drog related?
|
||||||
|
mode = type.indexOf("drop") ? "drag" : "drop",
|
||||||
|
// iteration vars
|
||||||
|
result, i = x || 0, ia, $elems, callback,
|
||||||
|
len = !isNaN( x ) ? x : dd.interactions.length;
|
||||||
|
// modify the event type
|
||||||
|
event.type = type;
|
||||||
|
// remove the original event
|
||||||
|
event.originalEvent = null;
|
||||||
|
// initialize the results
|
||||||
|
dd.results = [];
|
||||||
|
// handle each interacted element
|
||||||
|
do if ( ia = dd.interactions[ i ] ){
|
||||||
|
// validate the interaction
|
||||||
|
if ( type !== "dragend" && ia.cancelled )
|
||||||
|
continue;
|
||||||
|
// set the dragdrop properties on the event object
|
||||||
|
callback = drag.properties( event, dd, ia );
|
||||||
|
// prepare for more results
|
||||||
|
ia.results = [];
|
||||||
|
// handle each element
|
||||||
|
$( elem || ia[ mode ] || dd.droppable ).each(function( p, subject ){
|
||||||
|
// identify drag or drop targets individually
|
||||||
|
callback.target = subject;
|
||||||
|
// force propagtion of the custom event
|
||||||
|
event.isPropagationStopped = function(){ return false; };
|
||||||
|
// handle the event
|
||||||
|
result = subject ? $event.dispatch.call( subject, event, callback ) : null;
|
||||||
|
// stop the drag interaction for this element
|
||||||
|
if ( result === false ){
|
||||||
|
if ( mode == "drag" ){
|
||||||
|
ia.cancelled = true;
|
||||||
|
dd.propagates -= 1;
|
||||||
|
}
|
||||||
|
if ( type == "drop" ){
|
||||||
|
ia[ mode ][p] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// assign any dropinit elements
|
||||||
|
else if ( type == "dropinit" )
|
||||||
|
ia.droppable.push( drag.element( result ) || subject );
|
||||||
|
// accept a returned proxy element
|
||||||
|
if ( type == "dragstart" )
|
||||||
|
ia.proxy = $( drag.element( result ) || ia.drag )[0];
|
||||||
|
// remember this result
|
||||||
|
ia.results.push( result );
|
||||||
|
// forget the event result, for recycling
|
||||||
|
delete event.result;
|
||||||
|
// break on cancelled handler
|
||||||
|
if ( type !== "dropinit" )
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
// flatten the results
|
||||||
|
dd.results[ i ] = drag.flatten( ia.results );
|
||||||
|
// accept a set of valid drop targets
|
||||||
|
if ( type == "dropinit" )
|
||||||
|
ia.droppable = drag.flatten( ia.droppable );
|
||||||
|
// locate drop targets
|
||||||
|
if ( type == "dragstart" && !ia.cancelled )
|
||||||
|
callback.update();
|
||||||
|
}
|
||||||
|
while ( ++i < len )
|
||||||
|
// restore the original event & type
|
||||||
|
event.type = orig.type;
|
||||||
|
event.originalEvent = orig.event;
|
||||||
|
// return all handler results
|
||||||
|
return drag.flatten( dd.results );
|
||||||
|
},
|
||||||
|
|
||||||
|
// extend the callback object with drag/drop properties...
|
||||||
|
properties: function( event, dd, ia ){
|
||||||
|
var obj = ia.callback;
|
||||||
|
// elements
|
||||||
|
obj.drag = ia.drag;
|
||||||
|
obj.proxy = ia.proxy || ia.drag;
|
||||||
|
// starting mouse position
|
||||||
|
obj.startX = dd.pageX;
|
||||||
|
obj.startY = dd.pageY;
|
||||||
|
// current distance dragged
|
||||||
|
obj.deltaX = event.pageX - dd.pageX;
|
||||||
|
obj.deltaY = event.pageY - dd.pageY;
|
||||||
|
// original element position
|
||||||
|
obj.originalX = ia.offset.left;
|
||||||
|
obj.originalY = ia.offset.top;
|
||||||
|
// adjusted element position
|
||||||
|
obj.offsetX = obj.originalX + obj.deltaX;
|
||||||
|
obj.offsetY = obj.originalY + obj.deltaY;
|
||||||
|
// assign the drop targets information
|
||||||
|
obj.drop = drag.flatten( ( ia.drop || [] ).slice() );
|
||||||
|
obj.available = drag.flatten( ( ia.droppable || [] ).slice() );
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
|
||||||
|
// determine is the argument is an element or jquery instance
|
||||||
|
element: function( arg ){
|
||||||
|
if ( arg && ( arg.jquery || arg.nodeType == 1 ) )
|
||||||
|
return arg;
|
||||||
|
},
|
||||||
|
|
||||||
|
// flatten nested jquery objects and arrays into a single dimension array
|
||||||
|
flatten: function( arr ){
|
||||||
|
return $.map( arr, function( member ){
|
||||||
|
return member && member.jquery ? $.makeArray( member ) :
|
||||||
|
member && member.length ? drag.flatten( member ) : member;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// toggles text selection attributes ON (true) or OFF (false)
|
||||||
|
textselect: function( bool ){
|
||||||
|
$( document )[ bool ? "unbind" : "bind" ]("selectstart", drag.dontstart )
|
||||||
|
.css("MozUserSelect", bool ? "" : "none" );
|
||||||
|
// .attr("unselectable", bool ? "off" : "on" )
|
||||||
|
document.unselectable = bool ? "off" : "on";
|
||||||
|
},
|
||||||
|
|
||||||
|
// suppress "selectstart" and "ondragstart" events
|
||||||
|
dontstart: function(){
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
// a callback instance contructor
|
||||||
|
callback: function(){}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// callback methods
|
||||||
|
drag.callback.prototype = {
|
||||||
|
update: function(){
|
||||||
|
if ( $special.drop && this.available.length )
|
||||||
|
$.each( this.available, function( i ){
|
||||||
|
$special.drop.locate( this, i );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// patch $.event.$dispatch to allow suppressing clicks
|
||||||
|
var $dispatch = $event.dispatch;
|
||||||
|
$event.dispatch = function( event ){
|
||||||
|
if ( $.data( this, "suppress."+ event.type ) - new Date().getTime() > 0 ){
|
||||||
|
$.removeData( this, "suppress."+ event.type );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return $dispatch.apply( this, arguments );
|
||||||
|
};
|
||||||
|
|
||||||
|
// event fix hooks for touch events...
|
||||||
|
var touchHooks =
|
||||||
|
$event.fixHooks.touchstart =
|
||||||
|
$event.fixHooks.touchmove =
|
||||||
|
$event.fixHooks.touchend =
|
||||||
|
$event.fixHooks.touchcancel = {
|
||||||
|
props: "clientX clientY pageX pageY screenX screenY".split( " " ),
|
||||||
|
filter: function( event, orig ) {
|
||||||
|
if ( orig ){
|
||||||
|
var touched = ( orig.touches && orig.touches[0] )
|
||||||
|
|| ( orig.changedTouches && orig.changedTouches[0] )
|
||||||
|
|| null;
|
||||||
|
// iOS webkit: touchstart, touchmove, touchend
|
||||||
|
if ( touched )
|
||||||
|
$.each( touchHooks.props, function( i, prop ){
|
||||||
|
event[ prop ] = touched[ prop ];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// share the same special event configuration with related events...
|
||||||
|
$special.draginit = $special.dragstart = $special.dragend = drag;
|
||||||
|
|
||||||
|
})( jQuery );
|
302
web/pgadmin/static/js/jquery-ui/jquery.event.drop-2.2.js
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
/*!
|
||||||
|
* jquery.event.drop - v 2.2
|
||||||
|
* Copyright (c) 2010 Three Dub Media - http://threedubmedia.com
|
||||||
|
* Open Source MIT License - http://threedubmedia.com/code/license
|
||||||
|
*/
|
||||||
|
// Created: 2008-06-04
|
||||||
|
// Updated: 2012-05-21
|
||||||
|
// REQUIRES: jquery 1.7.x, event.drag 2.2
|
||||||
|
|
||||||
|
;(function($){ // secure $ jQuery alias
|
||||||
|
|
||||||
|
// Events: drop, dropstart, dropend
|
||||||
|
|
||||||
|
// add the jquery instance method
|
||||||
|
$.fn.drop = function( str, arg, opts ){
|
||||||
|
// figure out the event type
|
||||||
|
var type = typeof str == "string" ? str : "",
|
||||||
|
// figure out the event handler...
|
||||||
|
fn = $.isFunction( str ) ? str : $.isFunction( arg ) ? arg : null;
|
||||||
|
// fix the event type
|
||||||
|
if ( type.indexOf("drop") !== 0 )
|
||||||
|
type = "drop"+ type;
|
||||||
|
// were options passed
|
||||||
|
opts = ( str == fn ? arg : opts ) || {};
|
||||||
|
// trigger or bind event handler
|
||||||
|
return fn ? this.bind( type, opts, fn ) : this.trigger( type );
|
||||||
|
};
|
||||||
|
|
||||||
|
// DROP MANAGEMENT UTILITY
|
||||||
|
// returns filtered drop target elements, caches their positions
|
||||||
|
$.drop = function( opts ){
|
||||||
|
opts = opts || {};
|
||||||
|
// safely set new options...
|
||||||
|
drop.multi = opts.multi === true ? Infinity :
|
||||||
|
opts.multi === false ? 1 : !isNaN( opts.multi ) ? opts.multi : drop.multi;
|
||||||
|
drop.delay = opts.delay || drop.delay;
|
||||||
|
drop.tolerance = $.isFunction( opts.tolerance ) ? opts.tolerance :
|
||||||
|
opts.tolerance === null ? null : drop.tolerance;
|
||||||
|
drop.mode = opts.mode || drop.mode || 'intersect';
|
||||||
|
};
|
||||||
|
|
||||||
|
// local refs (increase compression)
|
||||||
|
var $event = $.event,
|
||||||
|
$special = $event.special,
|
||||||
|
// configure the drop special event
|
||||||
|
drop = $.event.special.drop = {
|
||||||
|
|
||||||
|
// these are the default settings
|
||||||
|
multi: 1, // allow multiple drop winners per dragged element
|
||||||
|
delay: 20, // async timeout delay
|
||||||
|
mode: 'overlap', // drop tolerance mode
|
||||||
|
|
||||||
|
// internal cache
|
||||||
|
targets: [],
|
||||||
|
|
||||||
|
// the key name for stored drop data
|
||||||
|
datakey: "dropdata",
|
||||||
|
|
||||||
|
// prevent bubbling for better performance
|
||||||
|
noBubble: true,
|
||||||
|
|
||||||
|
// count bound related events
|
||||||
|
add: function( obj ){
|
||||||
|
// read the interaction data
|
||||||
|
var data = $.data( this, drop.datakey );
|
||||||
|
// count another realted event
|
||||||
|
data.related += 1;
|
||||||
|
},
|
||||||
|
|
||||||
|
// forget unbound related events
|
||||||
|
remove: function(){
|
||||||
|
$.data( this, drop.datakey ).related -= 1;
|
||||||
|
},
|
||||||
|
|
||||||
|
// configure the interactions
|
||||||
|
setup: function(){
|
||||||
|
// check for related events
|
||||||
|
if ( $.data( this, drop.datakey ) )
|
||||||
|
return;
|
||||||
|
// initialize the drop element data
|
||||||
|
var data = {
|
||||||
|
related: 0,
|
||||||
|
active: [],
|
||||||
|
anyactive: 0,
|
||||||
|
winner: 0,
|
||||||
|
location: {}
|
||||||
|
};
|
||||||
|
// store the drop data on the element
|
||||||
|
$.data( this, drop.datakey, data );
|
||||||
|
// store the drop target in internal cache
|
||||||
|
drop.targets.push( this );
|
||||||
|
},
|
||||||
|
|
||||||
|
// destroy the configure interaction
|
||||||
|
teardown: function(){
|
||||||
|
var data = $.data( this, drop.datakey ) || {};
|
||||||
|
// check for related events
|
||||||
|
if ( data.related )
|
||||||
|
return;
|
||||||
|
// remove the stored data
|
||||||
|
$.removeData( this, drop.datakey );
|
||||||
|
// reference the targeted element
|
||||||
|
var element = this;
|
||||||
|
// remove from the internal cache
|
||||||
|
drop.targets = $.grep( drop.targets, function( target ){
|
||||||
|
return ( target !== element );
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// shared event handler
|
||||||
|
handler: function( event, dd ){
|
||||||
|
// local vars
|
||||||
|
var results, $targets;
|
||||||
|
// make sure the right data is available
|
||||||
|
if ( !dd )
|
||||||
|
return;
|
||||||
|
// handle various events
|
||||||
|
switch ( event.type ){
|
||||||
|
// draginit, from $.event.special.drag
|
||||||
|
case 'mousedown': // DROPINIT >>
|
||||||
|
case 'touchstart': // DROPINIT >>
|
||||||
|
// collect and assign the drop targets
|
||||||
|
$targets = $( drop.targets );
|
||||||
|
if ( typeof dd.drop == "string" )
|
||||||
|
$targets = $targets.filter( dd.drop );
|
||||||
|
// reset drop data winner properties
|
||||||
|
$targets.each(function(){
|
||||||
|
var data = $.data( this, drop.datakey );
|
||||||
|
data.active = [];
|
||||||
|
data.anyactive = 0;
|
||||||
|
data.winner = 0;
|
||||||
|
});
|
||||||
|
// set available target elements
|
||||||
|
dd.droppable = $targets;
|
||||||
|
// activate drop targets for the initial element being dragged
|
||||||
|
$special.drag.hijack( event, "dropinit", dd );
|
||||||
|
break;
|
||||||
|
// drag, from $.event.special.drag
|
||||||
|
case 'mousemove': // TOLERATE >>
|
||||||
|
case 'touchmove': // TOLERATE >>
|
||||||
|
drop.event = event; // store the mousemove event
|
||||||
|
if ( !drop.timer )
|
||||||
|
// monitor drop targets
|
||||||
|
drop.tolerate( dd );
|
||||||
|
break;
|
||||||
|
// dragend, from $.event.special.drag
|
||||||
|
case 'mouseup': // DROP >> DROPEND >>
|
||||||
|
case 'touchend': // DROP >> DROPEND >>
|
||||||
|
drop.timer = clearTimeout( drop.timer ); // delete timer
|
||||||
|
if ( dd.propagates ){
|
||||||
|
$special.drag.hijack( event, "drop", dd );
|
||||||
|
$special.drag.hijack( event, "dropend", dd );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// returns the location positions of an element
|
||||||
|
locate: function( elem, index ){
|
||||||
|
var data = $.data( elem, drop.datakey ),
|
||||||
|
$elem = $( elem ),
|
||||||
|
posi = $elem.offset() || {},
|
||||||
|
height = $elem.outerHeight(),
|
||||||
|
width = $elem.outerWidth(),
|
||||||
|
location = {
|
||||||
|
elem: elem,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
top: posi.top,
|
||||||
|
left: posi.left,
|
||||||
|
right: posi.left + width,
|
||||||
|
bottom: posi.top + height
|
||||||
|
};
|
||||||
|
// drag elements might not have dropdata
|
||||||
|
if ( data ){
|
||||||
|
data.location = location;
|
||||||
|
data.index = index;
|
||||||
|
data.elem = elem;
|
||||||
|
}
|
||||||
|
return location;
|
||||||
|
},
|
||||||
|
|
||||||
|
// test the location positions of an element against another OR an X,Y coord
|
||||||
|
contains: function( target, test ){ // target { location } contains test [x,y] or { location }
|
||||||
|
return ( ( test[0] || test.left ) >= target.left && ( test[0] || test.right ) <= target.right
|
||||||
|
&& ( test[1] || test.top ) >= target.top && ( test[1] || test.bottom ) <= target.bottom );
|
||||||
|
},
|
||||||
|
|
||||||
|
// stored tolerance modes
|
||||||
|
modes: { // fn scope: "$.event.special.drop" object
|
||||||
|
// target with mouse wins, else target with most overlap wins
|
||||||
|
'intersect': function( event, proxy, target ){
|
||||||
|
return this.contains( target, [ event.pageX, event.pageY ] ) ? // check cursor
|
||||||
|
1e9 : this.modes.overlap.apply( this, arguments ); // check overlap
|
||||||
|
},
|
||||||
|
// target with most overlap wins
|
||||||
|
'overlap': function( event, proxy, target ){
|
||||||
|
// calculate the area of overlap...
|
||||||
|
return Math.max( 0, Math.min( target.bottom, proxy.bottom ) - Math.max( target.top, proxy.top ) )
|
||||||
|
* Math.max( 0, Math.min( target.right, proxy.right ) - Math.max( target.left, proxy.left ) );
|
||||||
|
},
|
||||||
|
// proxy is completely contained within target bounds
|
||||||
|
'fit': function( event, proxy, target ){
|
||||||
|
return this.contains( target, proxy ) ? 1 : 0;
|
||||||
|
},
|
||||||
|
// center of the proxy is contained within target bounds
|
||||||
|
'middle': function( event, proxy, target ){
|
||||||
|
return this.contains( target, [ proxy.left + proxy.width * .5, proxy.top + proxy.height * .5 ] ) ? 1 : 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// sort drop target cache by by winner (dsc), then index (asc)
|
||||||
|
sort: function( a, b ){
|
||||||
|
return ( b.winner - a.winner ) || ( a.index - b.index );
|
||||||
|
},
|
||||||
|
|
||||||
|
// async, recursive tolerance execution
|
||||||
|
tolerate: function( dd ){
|
||||||
|
// declare local refs
|
||||||
|
var i, drp, drg, data, arr, len, elem,
|
||||||
|
// interaction iteration variables
|
||||||
|
x = 0, ia, end = dd.interactions.length,
|
||||||
|
// determine the mouse coords
|
||||||
|
xy = [ drop.event.pageX, drop.event.pageY ],
|
||||||
|
// custom or stored tolerance fn
|
||||||
|
tolerance = drop.tolerance || drop.modes[ drop.mode ];
|
||||||
|
// go through each passed interaction...
|
||||||
|
do if ( ia = dd.interactions[x] ){
|
||||||
|
// check valid interaction
|
||||||
|
if ( !ia )
|
||||||
|
return;
|
||||||
|
// initialize or clear the drop data
|
||||||
|
ia.drop = [];
|
||||||
|
// holds the drop elements
|
||||||
|
arr = [];
|
||||||
|
len = ia.droppable.length;
|
||||||
|
// determine the proxy location, if needed
|
||||||
|
if ( tolerance )
|
||||||
|
drg = drop.locate( ia.proxy );
|
||||||
|
// reset the loop
|
||||||
|
i = 0;
|
||||||
|
// loop each stored drop target
|
||||||
|
do if ( elem = ia.droppable[i] ){
|
||||||
|
data = $.data( elem, drop.datakey );
|
||||||
|
drp = data.location;
|
||||||
|
if ( !drp ) continue;
|
||||||
|
// find a winner: tolerance function is defined, call it
|
||||||
|
data.winner = tolerance ? tolerance.call( drop, drop.event, drg, drp )
|
||||||
|
// mouse position is always the fallback
|
||||||
|
: drop.contains( drp, xy ) ? 1 : 0;
|
||||||
|
arr.push( data );
|
||||||
|
} while ( ++i < len ); // loop
|
||||||
|
// sort the drop targets
|
||||||
|
arr.sort( drop.sort );
|
||||||
|
// reset the loop
|
||||||
|
i = 0;
|
||||||
|
// loop through all of the targets again
|
||||||
|
do if ( data = arr[ i ] ){
|
||||||
|
// winners...
|
||||||
|
if ( data.winner && ia.drop.length < drop.multi ){
|
||||||
|
// new winner... dropstart
|
||||||
|
if ( !data.active[x] && !data.anyactive ){
|
||||||
|
// check to make sure that this is not prevented
|
||||||
|
if ( $special.drag.hijack( drop.event, "dropstart", dd, x, data.elem )[0] !== false ){
|
||||||
|
data.active[x] = 1;
|
||||||
|
data.anyactive += 1;
|
||||||
|
}
|
||||||
|
// if false, it is not a winner
|
||||||
|
else
|
||||||
|
data.winner = 0;
|
||||||
|
}
|
||||||
|
// if it is still a winner
|
||||||
|
if ( data.winner )
|
||||||
|
ia.drop.push( data.elem );
|
||||||
|
}
|
||||||
|
// losers...
|
||||||
|
else if ( data.active[x] && data.anyactive == 1 ){
|
||||||
|
// former winner... dropend
|
||||||
|
$special.drag.hijack( drop.event, "dropend", dd, x, data.elem );
|
||||||
|
data.active[x] = 0;
|
||||||
|
data.anyactive -= 1;
|
||||||
|
}
|
||||||
|
} while ( ++i < len ); // loop
|
||||||
|
} while ( ++x < end ) // loop
|
||||||
|
// check if the mouse is still moving or is idle
|
||||||
|
if ( drop.last && xy[0] == drop.last.pageX && xy[1] == drop.last.pageY )
|
||||||
|
delete drop.timer; // idle, don't recurse
|
||||||
|
else // recurse
|
||||||
|
drop.timer = setTimeout(function(){
|
||||||
|
drop.tolerate( dd );
|
||||||
|
}, drop.delay );
|
||||||
|
// remember event, to compare idleness
|
||||||
|
drop.last = drop.event;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// share the same special event configuration with related events...
|
||||||
|
$special.dropinit = $special.dropstart = $special.dropend = drop;
|
||||||
|
|
||||||
|
})(jQuery); // confine scope
|
@ -0,0 +1,31 @@
|
|||||||
|
.slick-columnpicker {
|
||||||
|
border: 1px solid #718BB7;
|
||||||
|
background: #f0f0f0;
|
||||||
|
padding: 6px;
|
||||||
|
-moz-box-shadow: 2px 2px 2px silver;
|
||||||
|
-webkit-box-shadow: 2px 2px 2px silver;
|
||||||
|
box-shadow: 2px 2px 2px silver;
|
||||||
|
min-width: 100px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-columnpicker li {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-columnpicker input {
|
||||||
|
margin: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-columnpicker li a {
|
||||||
|
display: block;
|
||||||
|
padding: 4px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-columnpicker li a:hover {
|
||||||
|
background: white;
|
||||||
|
}
|
152
web/pgadmin/static/js/slickgrid/controls/slick.columnpicker.js
vendored
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
(function ($) {
|
||||||
|
function SlickColumnPicker(columns, grid, options) {
|
||||||
|
var $menu;
|
||||||
|
var columnCheckboxes;
|
||||||
|
|
||||||
|
var defaults = {
|
||||||
|
fadeSpeed:250
|
||||||
|
};
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
grid.onHeaderContextMenu.subscribe(handleHeaderContextMenu);
|
||||||
|
grid.onColumnsReordered.subscribe(updateColumnOrder);
|
||||||
|
options = $.extend({}, defaults, options);
|
||||||
|
|
||||||
|
$menu = $("<span class='slick-columnpicker' style='display:none;position:absolute;z-index:20;' />").appendTo(document.body);
|
||||||
|
|
||||||
|
$menu.bind("mouseleave", function (e) {
|
||||||
|
$(this).fadeOut(options.fadeSpeed)
|
||||||
|
});
|
||||||
|
$menu.bind("click", updateColumn);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroy() {
|
||||||
|
grid.onHeaderContextMenu.unsubscribe(handleHeaderContextMenu);
|
||||||
|
grid.onColumnsReordered.unsubscribe(updateColumnOrder);
|
||||||
|
$menu.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleHeaderContextMenu(e, args) {
|
||||||
|
e.preventDefault();
|
||||||
|
$menu.empty();
|
||||||
|
updateColumnOrder();
|
||||||
|
columnCheckboxes = [];
|
||||||
|
|
||||||
|
var $li, $input;
|
||||||
|
for (var i = 0; i < columns.length; i++) {
|
||||||
|
$li = $("<li />").appendTo($menu);
|
||||||
|
$input = $("<input type='checkbox' />").data("column-id", columns[i].id);
|
||||||
|
columnCheckboxes.push($input);
|
||||||
|
|
||||||
|
if (grid.getColumnIndex(columns[i].id) != null) {
|
||||||
|
$input.attr("checked", "checked");
|
||||||
|
}
|
||||||
|
|
||||||
|
$("<label />")
|
||||||
|
.text(columns[i].name)
|
||||||
|
.prepend($input)
|
||||||
|
.appendTo($li);
|
||||||
|
}
|
||||||
|
|
||||||
|
$("<hr/>").appendTo($menu);
|
||||||
|
$li = $("<li />").appendTo($menu);
|
||||||
|
$input = $("<input type='checkbox' />").data("option", "autoresize");
|
||||||
|
$("<label />")
|
||||||
|
.text("Force fit columns")
|
||||||
|
.prepend($input)
|
||||||
|
.appendTo($li);
|
||||||
|
if (grid.getOptions().forceFitColumns) {
|
||||||
|
$input.attr("checked", "checked");
|
||||||
|
}
|
||||||
|
|
||||||
|
$li = $("<li />").appendTo($menu);
|
||||||
|
$input = $("<input type='checkbox' />").data("option", "syncresize");
|
||||||
|
$("<label />")
|
||||||
|
.text("Synchronous resize")
|
||||||
|
.prepend($input)
|
||||||
|
.appendTo($li);
|
||||||
|
if (grid.getOptions().syncColumnCellResize) {
|
||||||
|
$input.attr("checked", "checked");
|
||||||
|
}
|
||||||
|
|
||||||
|
$menu
|
||||||
|
.css("top", e.pageY - 10)
|
||||||
|
.css("left", e.pageX - 10)
|
||||||
|
.fadeIn(options.fadeSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateColumnOrder() {
|
||||||
|
// Because columns can be reordered, we have to update the `columns`
|
||||||
|
// to reflect the new order, however we can't just take `grid.getColumns()`,
|
||||||
|
// as it does not include columns currently hidden by the picker.
|
||||||
|
// We create a new `columns` structure by leaving currently-hidden
|
||||||
|
// columns in their original ordinal position and interleaving the results
|
||||||
|
// of the current column sort.
|
||||||
|
var current = grid.getColumns().slice(0);
|
||||||
|
var ordered = new Array(columns.length);
|
||||||
|
for (var i = 0; i < ordered.length; i++) {
|
||||||
|
if ( grid.getColumnIndex(columns[i].id) === undefined ) {
|
||||||
|
// If the column doesn't return a value from getColumnIndex,
|
||||||
|
// it is hidden. Leave it in this position.
|
||||||
|
ordered[i] = columns[i];
|
||||||
|
} else {
|
||||||
|
// Otherwise, grab the next visible column.
|
||||||
|
ordered[i] = current.shift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
columns = ordered;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateColumn(e) {
|
||||||
|
if ($(e.target).data("option") == "autoresize") {
|
||||||
|
if (e.target.checked) {
|
||||||
|
grid.setOptions({forceFitColumns:true});
|
||||||
|
grid.autosizeColumns();
|
||||||
|
} else {
|
||||||
|
grid.setOptions({forceFitColumns:false});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($(e.target).data("option") == "syncresize") {
|
||||||
|
if (e.target.checked) {
|
||||||
|
grid.setOptions({syncColumnCellResize:true});
|
||||||
|
} else {
|
||||||
|
grid.setOptions({syncColumnCellResize:false});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($(e.target).is(":checkbox")) {
|
||||||
|
var visibleColumns = [];
|
||||||
|
$.each(columnCheckboxes, function (i, e) {
|
||||||
|
if ($(this).is(":checked")) {
|
||||||
|
visibleColumns.push(columns[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!visibleColumns.length) {
|
||||||
|
$(e.target).attr("checked", "checked");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
grid.setColumns(visibleColumns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAllColumns() {
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
return {
|
||||||
|
"getAllColumns": getAllColumns,
|
||||||
|
"destroy": destroy
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slick.Controls.ColumnPicker
|
||||||
|
$.extend(true, window, { Slick:{ Controls:{ ColumnPicker:SlickColumnPicker }}});
|
||||||
|
})(jQuery);
|
41
web/pgadmin/static/js/slickgrid/controls/slick.pager.css
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
.slick-pager {
|
||||||
|
width: 100%;
|
||||||
|
height: 26px;
|
||||||
|
border: 1px solid gray;
|
||||||
|
border-top: 0;
|
||||||
|
background: url('../images/header-columns-bg.gif') repeat-x center bottom;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-pager .slick-pager-status {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-pager .ui-icon-container {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 2px;
|
||||||
|
border-color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-pager .slick-pager-nav {
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-pager .slick-pager-settings {
|
||||||
|
display: block;
|
||||||
|
float: right;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-pager .slick-pager-settings * {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-pager .slick-pager-settings a {
|
||||||
|
padding: 2px;
|
||||||
|
text-decoration: underline;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
147
web/pgadmin/static/js/slickgrid/controls/slick.pager.js
vendored
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
(function ($) {
|
||||||
|
function SlickGridPager(dataView, grid, $container) {
|
||||||
|
var $status;
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
dataView.onPagingInfoChanged.subscribe(function (e, pagingInfo) {
|
||||||
|
updatePager(pagingInfo);
|
||||||
|
});
|
||||||
|
|
||||||
|
constructPagerUI();
|
||||||
|
updatePager(dataView.getPagingInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNavState() {
|
||||||
|
var cannotLeaveEditMode = !Slick.GlobalEditorLock.commitCurrentEdit();
|
||||||
|
var pagingInfo = dataView.getPagingInfo();
|
||||||
|
var lastPage = pagingInfo.totalPages - 1;
|
||||||
|
|
||||||
|
return {
|
||||||
|
canGotoFirst: !cannotLeaveEditMode && pagingInfo.pageSize != 0 && pagingInfo.pageNum > 0,
|
||||||
|
canGotoLast: !cannotLeaveEditMode && pagingInfo.pageSize != 0 && pagingInfo.pageNum != lastPage,
|
||||||
|
canGotoPrev: !cannotLeaveEditMode && pagingInfo.pageSize != 0 && pagingInfo.pageNum > 0,
|
||||||
|
canGotoNext: !cannotLeaveEditMode && pagingInfo.pageSize != 0 && pagingInfo.pageNum < lastPage,
|
||||||
|
pagingInfo: pagingInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPageSize(n) {
|
||||||
|
dataView.setRefreshHints({
|
||||||
|
isFilterUnchanged: true
|
||||||
|
});
|
||||||
|
dataView.setPagingOptions({pageSize: n});
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotoFirst() {
|
||||||
|
if (getNavState().canGotoFirst) {
|
||||||
|
dataView.setPagingOptions({pageNum: 0});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotoLast() {
|
||||||
|
var state = getNavState();
|
||||||
|
if (state.canGotoLast) {
|
||||||
|
dataView.setPagingOptions({pageNum: state.pagingInfo.totalPages - 1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotoPrev() {
|
||||||
|
var state = getNavState();
|
||||||
|
if (state.canGotoPrev) {
|
||||||
|
dataView.setPagingOptions({pageNum: state.pagingInfo.pageNum - 1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotoNext() {
|
||||||
|
var state = getNavState();
|
||||||
|
if (state.canGotoNext) {
|
||||||
|
dataView.setPagingOptions({pageNum: state.pagingInfo.pageNum + 1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function constructPagerUI() {
|
||||||
|
$container.empty();
|
||||||
|
|
||||||
|
var $nav = $("<span class='slick-pager-nav' />").appendTo($container);
|
||||||
|
var $settings = $("<span class='slick-pager-settings' />").appendTo($container);
|
||||||
|
$status = $("<span class='slick-pager-status' />").appendTo($container);
|
||||||
|
|
||||||
|
$settings
|
||||||
|
.append("<span class='slick-pager-settings-expanded' style='display:none'>Show: <a data=0>All</a><a data='-1'>Auto</a><a data=25>25</a><a data=50>50</a><a data=100>100</a></span>");
|
||||||
|
|
||||||
|
$settings.find("a[data]").click(function (e) {
|
||||||
|
var pagesize = $(e.target).attr("data");
|
||||||
|
if (pagesize != undefined) {
|
||||||
|
if (pagesize == -1) {
|
||||||
|
var vp = grid.getViewport();
|
||||||
|
setPageSize(vp.bottom - vp.top);
|
||||||
|
} else {
|
||||||
|
setPageSize(parseInt(pagesize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var icon_prefix = "<span class='ui-state-default ui-corner-all ui-icon-container'><span class='ui-icon ";
|
||||||
|
var icon_suffix = "' /></span>";
|
||||||
|
|
||||||
|
$(icon_prefix + "ui-icon-lightbulb" + icon_suffix)
|
||||||
|
.click(function () {
|
||||||
|
$(".slick-pager-settings-expanded").toggle()
|
||||||
|
})
|
||||||
|
.appendTo($settings);
|
||||||
|
|
||||||
|
$(icon_prefix + "ui-icon-seek-first" + icon_suffix)
|
||||||
|
.click(gotoFirst)
|
||||||
|
.appendTo($nav);
|
||||||
|
|
||||||
|
$(icon_prefix + "ui-icon-seek-prev" + icon_suffix)
|
||||||
|
.click(gotoPrev)
|
||||||
|
.appendTo($nav);
|
||||||
|
|
||||||
|
$(icon_prefix + "ui-icon-seek-next" + icon_suffix)
|
||||||
|
.click(gotoNext)
|
||||||
|
.appendTo($nav);
|
||||||
|
|
||||||
|
$(icon_prefix + "ui-icon-seek-end" + icon_suffix)
|
||||||
|
.click(gotoLast)
|
||||||
|
.appendTo($nav);
|
||||||
|
|
||||||
|
$container.find(".ui-icon-container")
|
||||||
|
.hover(function () {
|
||||||
|
$(this).toggleClass("ui-state-hover");
|
||||||
|
});
|
||||||
|
|
||||||
|
$container.children().wrapAll("<div class='slick-pager' />");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function updatePager(pagingInfo) {
|
||||||
|
var state = getNavState();
|
||||||
|
|
||||||
|
$container.find(".slick-pager-nav span").removeClass("ui-state-disabled");
|
||||||
|
if (!state.canGotoFirst) {
|
||||||
|
$container.find(".ui-icon-seek-first").addClass("ui-state-disabled");
|
||||||
|
}
|
||||||
|
if (!state.canGotoLast) {
|
||||||
|
$container.find(".ui-icon-seek-end").addClass("ui-state-disabled");
|
||||||
|
}
|
||||||
|
if (!state.canGotoNext) {
|
||||||
|
$container.find(".ui-icon-seek-next").addClass("ui-state-disabled");
|
||||||
|
}
|
||||||
|
if (!state.canGotoPrev) {
|
||||||
|
$container.find(".ui-icon-seek-prev").addClass("ui-state-disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pagingInfo.pageSize == 0) {
|
||||||
|
$status.text("Showing all " + pagingInfo.totalRows + " rows");
|
||||||
|
} else {
|
||||||
|
$status.text("Showing page " + (pagingInfo.pageNum + 1) + " of " + pagingInfo.totalPages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slick.Controls.Pager
|
||||||
|
$.extend(true, window, { Slick:{ Controls:{ Pager:SlickGridPager }}});
|
||||||
|
})(jQuery);
|
83
web/pgadmin/static/js/slickgrid/plugins/slick.autotooltips.js
vendored
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
(function ($) {
|
||||||
|
// Register namespace
|
||||||
|
$.extend(true, window, {
|
||||||
|
"Slick": {
|
||||||
|
"AutoTooltips": AutoTooltips
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AutoTooltips plugin to show/hide tooltips when columns are too narrow to fit content.
|
||||||
|
* @constructor
|
||||||
|
* @param {boolean} [options.enableForCells=true] - Enable tooltip for grid cells
|
||||||
|
* @param {boolean} [options.enableForHeaderCells=false] - Enable tooltip for header cells
|
||||||
|
* @param {number} [options.maxToolTipLength=null] - The maximum length for a tooltip
|
||||||
|
*/
|
||||||
|
function AutoTooltips(options) {
|
||||||
|
var _grid;
|
||||||
|
var _self = this;
|
||||||
|
var _defaults = {
|
||||||
|
enableForCells: true,
|
||||||
|
enableForHeaderCells: false,
|
||||||
|
maxToolTipLength: null
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize plugin.
|
||||||
|
*/
|
||||||
|
function init(grid) {
|
||||||
|
options = $.extend(true, {}, _defaults, options);
|
||||||
|
_grid = grid;
|
||||||
|
if (options.enableForCells) _grid.onMouseEnter.subscribe(handleMouseEnter);
|
||||||
|
if (options.enableForHeaderCells) _grid.onHeaderMouseEnter.subscribe(handleHeaderMouseEnter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy plugin.
|
||||||
|
*/
|
||||||
|
function destroy() {
|
||||||
|
if (options.enableForCells) _grid.onMouseEnter.unsubscribe(handleMouseEnter);
|
||||||
|
if (options.enableForHeaderCells) _grid.onHeaderMouseEnter.unsubscribe(handleHeaderMouseEnter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle mouse entering grid cell to add/remove tooltip.
|
||||||
|
* @param {jQuery.Event} e - The event
|
||||||
|
*/
|
||||||
|
function handleMouseEnter(e) {
|
||||||
|
var cell = _grid.getCellFromEvent(e);
|
||||||
|
if (cell) {
|
||||||
|
var $node = $(_grid.getCellNode(cell.row, cell.cell));
|
||||||
|
var text;
|
||||||
|
if ($node.innerWidth() < $node[0].scrollWidth) {
|
||||||
|
text = $.trim($node.text());
|
||||||
|
if (options.maxToolTipLength && text.length > options.maxToolTipLength) {
|
||||||
|
text = text.substr(0, options.maxToolTipLength - 3) + "...";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
text = "";
|
||||||
|
}
|
||||||
|
$node.attr("title", text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle mouse entering header cell to add/remove tooltip.
|
||||||
|
* @param {jQuery.Event} e - The event
|
||||||
|
* @param {object} args.column - The column definition
|
||||||
|
*/
|
||||||
|
function handleHeaderMouseEnter(e, args) {
|
||||||
|
var column = args.column,
|
||||||
|
$node = $(e.target).closest(".slick-header-column");
|
||||||
|
if (column && !column.toolTip) {
|
||||||
|
$node.attr("title", ($node.innerWidth() < $node[0].scrollWidth) ? column.name : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public API
|
||||||
|
$.extend(this, {
|
||||||
|
"init": init,
|
||||||
|
"destroy": destroy
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})(jQuery);
|
86
web/pgadmin/static/js/slickgrid/plugins/slick.cellcopymanager.js
vendored
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
(function ($) {
|
||||||
|
// register namespace
|
||||||
|
$.extend(true, window, {
|
||||||
|
"Slick": {
|
||||||
|
"CellCopyManager": CellCopyManager
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function CellCopyManager() {
|
||||||
|
var _grid;
|
||||||
|
var _self = this;
|
||||||
|
var _copiedRanges;
|
||||||
|
|
||||||
|
function init(grid) {
|
||||||
|
_grid = grid;
|
||||||
|
_grid.onKeyDown.subscribe(handleKeyDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroy() {
|
||||||
|
_grid.onKeyDown.unsubscribe(handleKeyDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleKeyDown(e, args) {
|
||||||
|
var ranges;
|
||||||
|
if (!_grid.getEditorLock().isActive()) {
|
||||||
|
if (e.which == $.ui.keyCode.ESCAPE) {
|
||||||
|
if (_copiedRanges) {
|
||||||
|
e.preventDefault();
|
||||||
|
clearCopySelection();
|
||||||
|
_self.onCopyCancelled.notify({ranges: _copiedRanges});
|
||||||
|
_copiedRanges = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.which == 67 && (e.ctrlKey || e.metaKey)) {
|
||||||
|
ranges = _grid.getSelectionModel().getSelectedRanges();
|
||||||
|
if (ranges.length != 0) {
|
||||||
|
e.preventDefault();
|
||||||
|
_copiedRanges = ranges;
|
||||||
|
markCopySelection(ranges);
|
||||||
|
_self.onCopyCells.notify({ranges: ranges});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.which == 86 && (e.ctrlKey || e.metaKey)) {
|
||||||
|
if (_copiedRanges) {
|
||||||
|
e.preventDefault();
|
||||||
|
clearCopySelection();
|
||||||
|
ranges = _grid.getSelectionModel().getSelectedRanges();
|
||||||
|
_self.onPasteCells.notify({from: _copiedRanges, to: ranges});
|
||||||
|
_copiedRanges = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function markCopySelection(ranges) {
|
||||||
|
var columns = _grid.getColumns();
|
||||||
|
var hash = {};
|
||||||
|
for (var i = 0; i < ranges.length; i++) {
|
||||||
|
for (var j = ranges[i].fromRow; j <= ranges[i].toRow; j++) {
|
||||||
|
hash[j] = {};
|
||||||
|
for (var k = ranges[i].fromCell; k <= ranges[i].toCell; k++) {
|
||||||
|
hash[j][columns[k].id] = "copied";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_grid.setCellCssStyles("copy-manager", hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearCopySelection() {
|
||||||
|
_grid.removeCellCssStyles("copy-manager");
|
||||||
|
}
|
||||||
|
|
||||||
|
$.extend(this, {
|
||||||
|
"init": init,
|
||||||
|
"destroy": destroy,
|
||||||
|
"clearCopySelection": clearCopySelection,
|
||||||
|
|
||||||
|
"onCopyCells": new Slick.Event(),
|
||||||
|
"onCopyCancelled": new Slick.Event(),
|
||||||
|
"onPasteCells": new Slick.Event()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})(jQuery);
|
66
web/pgadmin/static/js/slickgrid/plugins/slick.cellrangedecorator.js
vendored
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
(function ($) {
|
||||||
|
// register namespace
|
||||||
|
$.extend(true, window, {
|
||||||
|
"Slick": {
|
||||||
|
"CellRangeDecorator": CellRangeDecorator
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Displays an overlay on top of a given cell range.
|
||||||
|
*
|
||||||
|
* TODO:
|
||||||
|
* Currently, it blocks mouse events to DOM nodes behind it.
|
||||||
|
* Use FF and WebKit-specific "pointer-events" CSS style, or some kind of event forwarding.
|
||||||
|
* Could also construct the borders separately using 4 individual DIVs.
|
||||||
|
*
|
||||||
|
* @param {Grid} grid
|
||||||
|
* @param {Object} options
|
||||||
|
*/
|
||||||
|
function CellRangeDecorator(grid, options) {
|
||||||
|
var _elem;
|
||||||
|
var _defaults = {
|
||||||
|
selectionCssClass: 'slick-range-decorator',
|
||||||
|
selectionCss: {
|
||||||
|
"zIndex": "9999",
|
||||||
|
"border": "2px dashed red"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
options = $.extend(true, {}, _defaults, options);
|
||||||
|
|
||||||
|
|
||||||
|
function show(range) {
|
||||||
|
if (!_elem) {
|
||||||
|
_elem = $("<div></div>", {css: options.selectionCss})
|
||||||
|
.addClass(options.selectionCssClass)
|
||||||
|
.css("position", "absolute")
|
||||||
|
.appendTo(grid.getCanvasNode());
|
||||||
|
}
|
||||||
|
|
||||||
|
var from = grid.getCellNodeBox(range.fromRow, range.fromCell);
|
||||||
|
var to = grid.getCellNodeBox(range.toRow, range.toCell);
|
||||||
|
|
||||||
|
_elem.css({
|
||||||
|
top: from.top - 1,
|
||||||
|
left: from.left - 1,
|
||||||
|
height: to.bottom - from.top - 2,
|
||||||
|
width: to.right - from.left - 2
|
||||||
|
});
|
||||||
|
|
||||||
|
return _elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide() {
|
||||||
|
if (_elem) {
|
||||||
|
_elem.remove();
|
||||||
|
_elem = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$.extend(this, {
|
||||||
|
"show": show,
|
||||||
|
"hide": hide
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})(jQuery);
|
113
web/pgadmin/static/js/slickgrid/plugins/slick.cellrangeselector.js
vendored
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
(function ($) {
|
||||||
|
// register namespace
|
||||||
|
$.extend(true, window, {
|
||||||
|
"Slick": {
|
||||||
|
"CellRangeSelector": CellRangeSelector
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function CellRangeSelector(options) {
|
||||||
|
var _grid;
|
||||||
|
var _canvas;
|
||||||
|
var _dragging;
|
||||||
|
var _decorator;
|
||||||
|
var _self = this;
|
||||||
|
var _handler = new Slick.EventHandler();
|
||||||
|
var _defaults = {
|
||||||
|
selectionCss: {
|
||||||
|
"border": "2px dashed blue"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function init(grid) {
|
||||||
|
options = $.extend(true, {}, _defaults, options);
|
||||||
|
_decorator = new Slick.CellRangeDecorator(grid, options);
|
||||||
|
_grid = grid;
|
||||||
|
_canvas = _grid.getCanvasNode();
|
||||||
|
_handler
|
||||||
|
.subscribe(_grid.onDragInit, handleDragInit)
|
||||||
|
.subscribe(_grid.onDragStart, handleDragStart)
|
||||||
|
.subscribe(_grid.onDrag, handleDrag)
|
||||||
|
.subscribe(_grid.onDragEnd, handleDragEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroy() {
|
||||||
|
_handler.unsubscribeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragInit(e, dd) {
|
||||||
|
// prevent the grid from cancelling drag'n'drop by default
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragStart(e, dd) {
|
||||||
|
var cell = _grid.getCellFromEvent(e);
|
||||||
|
if (_self.onBeforeCellRangeSelected.notify(cell) !== false) {
|
||||||
|
if (_grid.canCellBeSelected(cell.row, cell.cell)) {
|
||||||
|
_dragging = true;
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!_dragging) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_grid.focus();
|
||||||
|
|
||||||
|
var start = _grid.getCellFromPoint(
|
||||||
|
dd.startX - $(_canvas).offset().left,
|
||||||
|
dd.startY - $(_canvas).offset().top);
|
||||||
|
|
||||||
|
dd.range = {start: start, end: {}};
|
||||||
|
|
||||||
|
return _decorator.show(new Slick.Range(start.row, start.cell));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDrag(e, dd) {
|
||||||
|
if (!_dragging) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
|
||||||
|
var end = _grid.getCellFromPoint(
|
||||||
|
e.pageX - $(_canvas).offset().left,
|
||||||
|
e.pageY - $(_canvas).offset().top);
|
||||||
|
|
||||||
|
if (!_grid.canCellBeSelected(end.row, end.cell)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd.range.end = end;
|
||||||
|
_decorator.show(new Slick.Range(dd.range.start.row, dd.range.start.cell, end.row, end.cell));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragEnd(e, dd) {
|
||||||
|
if (!_dragging) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dragging = false;
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
|
||||||
|
_decorator.hide();
|
||||||
|
_self.onCellRangeSelected.notify({
|
||||||
|
range: new Slick.Range(
|
||||||
|
dd.range.start.row,
|
||||||
|
dd.range.start.cell,
|
||||||
|
dd.range.end.row,
|
||||||
|
dd.range.end.cell
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$.extend(this, {
|
||||||
|
"init": init,
|
||||||
|
"destroy": destroy,
|
||||||
|
|
||||||
|
"onBeforeCellRangeSelected": new Slick.Event(),
|
||||||
|
"onCellRangeSelected": new Slick.Event()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})(jQuery);
|
157
web/pgadmin/static/js/slickgrid/plugins/slick.cellselectionmodel.js
vendored
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
(function ($) {
|
||||||
|
// register namespace
|
||||||
|
$.extend(true, window, {
|
||||||
|
"Slick": {
|
||||||
|
"CellSelectionModel": CellSelectionModel
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function CellSelectionModel(options) {
|
||||||
|
var _grid;
|
||||||
|
var _canvas;
|
||||||
|
var _ranges = [];
|
||||||
|
var _self = this;
|
||||||
|
var _selector = new Slick.CellRangeSelector({
|
||||||
|
"selectionCss": {
|
||||||
|
"border": "2px solid black"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var _options;
|
||||||
|
var _defaults = {
|
||||||
|
selectActiveCell: true
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function init(grid) {
|
||||||
|
_options = $.extend(true, {}, _defaults, options);
|
||||||
|
_grid = grid;
|
||||||
|
_canvas = _grid.getCanvasNode();
|
||||||
|
_grid.onActiveCellChanged.subscribe(handleActiveCellChange);
|
||||||
|
_grid.onKeyDown.subscribe(handleKeyDown);
|
||||||
|
grid.registerPlugin(_selector);
|
||||||
|
_selector.onCellRangeSelected.subscribe(handleCellRangeSelected);
|
||||||
|
_selector.onBeforeCellRangeSelected.subscribe(handleBeforeCellRangeSelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroy() {
|
||||||
|
_grid.onActiveCellChanged.unsubscribe(handleActiveCellChange);
|
||||||
|
_grid.onKeyDown.unsubscribe(handleKeyDown);
|
||||||
|
_selector.onCellRangeSelected.unsubscribe(handleCellRangeSelected);
|
||||||
|
_selector.onBeforeCellRangeSelected.unsubscribe(handleBeforeCellRangeSelected);
|
||||||
|
_grid.unregisterPlugin(_selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeInvalidRanges(ranges) {
|
||||||
|
var result = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < ranges.length; i++) {
|
||||||
|
var r = ranges[i];
|
||||||
|
if (_grid.canCellBeSelected(r.fromRow, r.fromCell) && _grid.canCellBeSelected(r.toRow, r.toCell)) {
|
||||||
|
result.push(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSelectedRanges(ranges) {
|
||||||
|
// simle check for: empty selection didn't change, prevent firing onSelectedRangesChanged
|
||||||
|
if ((!_ranges || _ranges.length === 0) && (!ranges || ranges.length === 0)) { return; }
|
||||||
|
|
||||||
|
_ranges = removeInvalidRanges(ranges);
|
||||||
|
_self.onSelectedRangesChanged.notify(_ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelectedRanges() {
|
||||||
|
return _ranges;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBeforeCellRangeSelected(e, args) {
|
||||||
|
if (_grid.getEditorLock().isActive()) {
|
||||||
|
e.stopPropagation();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCellRangeSelected(e, args) {
|
||||||
|
setSelectedRanges([args.range]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleActiveCellChange(e, args) {
|
||||||
|
if (_options.selectActiveCell && args.row != null && args.cell != null) {
|
||||||
|
setSelectedRanges([new Slick.Range(args.row, args.cell)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleKeyDown(e) {
|
||||||
|
/***
|
||||||
|
* Кey codes
|
||||||
|
* 37 left
|
||||||
|
* 38 up
|
||||||
|
* 39 right
|
||||||
|
* 40 down
|
||||||
|
*/
|
||||||
|
var ranges, last;
|
||||||
|
var active = _grid.getActiveCell();
|
||||||
|
|
||||||
|
if ( active && e.shiftKey && !e.ctrlKey && !e.altKey &&
|
||||||
|
(e.which == 37 || e.which == 39 || e.which == 38 || e.which == 40) ) {
|
||||||
|
|
||||||
|
ranges = getSelectedRanges();
|
||||||
|
if (!ranges.length)
|
||||||
|
ranges.push(new Slick.Range(active.row, active.cell));
|
||||||
|
|
||||||
|
// keyboard can work with last range only
|
||||||
|
last = ranges.pop();
|
||||||
|
|
||||||
|
// can't handle selection out of active cell
|
||||||
|
if (!last.contains(active.row, active.cell))
|
||||||
|
last = new Slick.Range(active.row, active.cell);
|
||||||
|
|
||||||
|
var dRow = last.toRow - last.fromRow,
|
||||||
|
dCell = last.toCell - last.fromCell,
|
||||||
|
// walking direction
|
||||||
|
dirRow = active.row == last.fromRow ? 1 : -1,
|
||||||
|
dirCell = active.cell == last.fromCell ? 1 : -1;
|
||||||
|
|
||||||
|
if (e.which == 37) {
|
||||||
|
dCell -= dirCell;
|
||||||
|
} else if (e.which == 39) {
|
||||||
|
dCell += dirCell ;
|
||||||
|
} else if (e.which == 38) {
|
||||||
|
dRow -= dirRow;
|
||||||
|
} else if (e.which == 40) {
|
||||||
|
dRow += dirRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// define new selection range
|
||||||
|
var new_last = new Slick.Range(active.row, active.cell, active.row + dirRow*dRow, active.cell + dirCell*dCell);
|
||||||
|
if (removeInvalidRanges([new_last]).length) {
|
||||||
|
ranges.push(new_last);
|
||||||
|
var viewRow = dirRow > 0 ? new_last.toRow : new_last.fromRow;
|
||||||
|
var viewCell = dirCell > 0 ? new_last.toCell : new_last.fromCell;
|
||||||
|
_grid.scrollRowIntoView(viewRow);
|
||||||
|
_grid.scrollCellIntoView(viewRow, viewCell);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ranges.push(last);
|
||||||
|
|
||||||
|
setSelectedRanges(ranges);
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$.extend(this, {
|
||||||
|
"getSelectedRanges": getSelectedRanges,
|
||||||
|
"setSelectedRanges": setSelectedRanges,
|
||||||
|
|
||||||
|
"init": init,
|
||||||
|
"destroy": destroy,
|
||||||
|
|
||||||
|
"onSelectedRangesChanged": new Slick.Event()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})(jQuery);
|
153
web/pgadmin/static/js/slickgrid/plugins/slick.checkboxselectcolumn.js
vendored
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
(function ($) {
|
||||||
|
// register namespace
|
||||||
|
$.extend(true, window, {
|
||||||
|
"Slick": {
|
||||||
|
"CheckboxSelectColumn": CheckboxSelectColumn
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function CheckboxSelectColumn(options) {
|
||||||
|
var _grid;
|
||||||
|
var _self = this;
|
||||||
|
var _handler = new Slick.EventHandler();
|
||||||
|
var _selectedRowsLookup = {};
|
||||||
|
var _defaults = {
|
||||||
|
columnId: "_checkbox_selector",
|
||||||
|
cssClass: null,
|
||||||
|
toolTip: "Select/Deselect All",
|
||||||
|
width: 30
|
||||||
|
};
|
||||||
|
|
||||||
|
var _options = $.extend(true, {}, _defaults, options);
|
||||||
|
|
||||||
|
function init(grid) {
|
||||||
|
_grid = grid;
|
||||||
|
_handler
|
||||||
|
.subscribe(_grid.onSelectedRowsChanged, handleSelectedRowsChanged)
|
||||||
|
.subscribe(_grid.onClick, handleClick)
|
||||||
|
.subscribe(_grid.onHeaderClick, handleHeaderClick)
|
||||||
|
.subscribe(_grid.onKeyDown, handleKeyDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroy() {
|
||||||
|
_handler.unsubscribeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSelectedRowsChanged(e, args) {
|
||||||
|
var selectedRows = _grid.getSelectedRows();
|
||||||
|
var lookup = {}, row, i;
|
||||||
|
for (i = 0; i < selectedRows.length; i++) {
|
||||||
|
row = selectedRows[i];
|
||||||
|
lookup[row] = true;
|
||||||
|
if (lookup[row] !== _selectedRowsLookup[row]) {
|
||||||
|
_grid.invalidateRow(row);
|
||||||
|
delete _selectedRowsLookup[row];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i in _selectedRowsLookup) {
|
||||||
|
_grid.invalidateRow(i);
|
||||||
|
}
|
||||||
|
_selectedRowsLookup = lookup;
|
||||||
|
_grid.render();
|
||||||
|
|
||||||
|
if (selectedRows.length && selectedRows.length == _grid.getDataLength()) {
|
||||||
|
_grid.updateColumnHeader(_options.columnId, "<input type='checkbox' checked='checked'>", _options.toolTip);
|
||||||
|
} else {
|
||||||
|
_grid.updateColumnHeader(_options.columnId, "<input type='checkbox'>", _options.toolTip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleKeyDown(e, args) {
|
||||||
|
if (e.which == 32) {
|
||||||
|
if (_grid.getColumns()[args.cell].id === _options.columnId) {
|
||||||
|
// if editing, try to commit
|
||||||
|
if (!_grid.getEditorLock().isActive() || _grid.getEditorLock().commitCurrentEdit()) {
|
||||||
|
toggleRowSelection(args.row);
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClick(e, args) {
|
||||||
|
// clicking on a row select checkbox
|
||||||
|
if (_grid.getColumns()[args.cell].id === _options.columnId && $(e.target).is(":checkbox")) {
|
||||||
|
// if editing, try to commit
|
||||||
|
if (_grid.getEditorLock().isActive() && !_grid.getEditorLock().commitCurrentEdit()) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleRowSelection(args.row);
|
||||||
|
e.stopPropagation();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleRowSelection(row) {
|
||||||
|
if (_selectedRowsLookup[row]) {
|
||||||
|
_grid.setSelectedRows($.grep(_grid.getSelectedRows(), function (n) {
|
||||||
|
return n != row
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
_grid.setSelectedRows(_grid.getSelectedRows().concat(row));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleHeaderClick(e, args) {
|
||||||
|
if (args.column.id == _options.columnId && $(e.target).is(":checkbox")) {
|
||||||
|
// if editing, try to commit
|
||||||
|
if (_grid.getEditorLock().isActive() && !_grid.getEditorLock().commitCurrentEdit()) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($(e.target).is(":checked")) {
|
||||||
|
var rows = [];
|
||||||
|
for (var i = 0; i < _grid.getDataLength(); i++) {
|
||||||
|
rows.push(i);
|
||||||
|
}
|
||||||
|
_grid.setSelectedRows(rows);
|
||||||
|
} else {
|
||||||
|
_grid.setSelectedRows([]);
|
||||||
|
}
|
||||||
|
e.stopPropagation();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getColumnDefinition() {
|
||||||
|
return {
|
||||||
|
id: _options.columnId,
|
||||||
|
name: "<input type='checkbox'>",
|
||||||
|
toolTip: _options.toolTip,
|
||||||
|
field: "sel",
|
||||||
|
width: _options.width,
|
||||||
|
resizable: false,
|
||||||
|
sortable: false,
|
||||||
|
cssClass: _options.cssClass,
|
||||||
|
formatter: checkboxSelectionFormatter
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkboxSelectionFormatter(row, cell, value, columnDef, dataContext) {
|
||||||
|
if (dataContext) {
|
||||||
|
return _selectedRowsLookup[row]
|
||||||
|
? "<input type='checkbox' checked='checked'>"
|
||||||
|
: "<input type='checkbox'>";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$.extend(this, {
|
||||||
|
"init": init,
|
||||||
|
"destroy": destroy,
|
||||||
|
|
||||||
|
"getColumnDefinition": getColumnDefinition
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})(jQuery);
|
@ -0,0 +1,39 @@
|
|||||||
|
.slick-column-name,
|
||||||
|
.slick-sort-indicator {
|
||||||
|
/**
|
||||||
|
* This makes all "float:right" elements after it that spill over to the next line
|
||||||
|
* display way below the lower boundary of the column thus hiding them.
|
||||||
|
*/
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
margin-bottom: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-header-button {
|
||||||
|
display: inline-block;
|
||||||
|
float: right;
|
||||||
|
vertical-align: top;
|
||||||
|
margin: 1px;
|
||||||
|
/**
|
||||||
|
* This makes all "float:right" elements after it that spill over to the next line
|
||||||
|
* display way below the lower boundary of the column thus hiding them.
|
||||||
|
*/
|
||||||
|
margin-bottom: 100px;
|
||||||
|
height: 15px;
|
||||||
|
width: 15px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-header-button-hidden {
|
||||||
|
width: 0;
|
||||||
|
|
||||||
|
-webkit-transition: 0.2s width;
|
||||||
|
-ms-transition: 0.2s width;
|
||||||
|
transition: 0.2s width;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-header-column:hover > .slick-header-button {
|
||||||
|
width: 15px;
|
||||||
|
}
|
177
web/pgadmin/static/js/slickgrid/plugins/slick.headerbuttons.js
vendored
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
(function ($) {
|
||||||
|
// register namespace
|
||||||
|
$.extend(true, window, {
|
||||||
|
"Slick": {
|
||||||
|
"Plugins": {
|
||||||
|
"HeaderButtons": HeaderButtons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/***
|
||||||
|
* A plugin to add custom buttons to column headers.
|
||||||
|
*
|
||||||
|
* USAGE:
|
||||||
|
*
|
||||||
|
* Add the plugin .js & .css files and register it with the grid.
|
||||||
|
*
|
||||||
|
* To specify a custom button in a column header, extend the column definition like so:
|
||||||
|
*
|
||||||
|
* var columns = [
|
||||||
|
* {
|
||||||
|
* id: 'myColumn',
|
||||||
|
* name: 'My column',
|
||||||
|
*
|
||||||
|
* // This is the relevant part
|
||||||
|
* header: {
|
||||||
|
* buttons: [
|
||||||
|
* {
|
||||||
|
* // button options
|
||||||
|
* },
|
||||||
|
* {
|
||||||
|
* // button options
|
||||||
|
* }
|
||||||
|
* ]
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ];
|
||||||
|
*
|
||||||
|
* Available button options:
|
||||||
|
* cssClass: CSS class to add to the button.
|
||||||
|
* image: Relative button image path.
|
||||||
|
* tooltip: Button tooltip.
|
||||||
|
* showOnHover: Only show the button on hover.
|
||||||
|
* handler: Button click handler.
|
||||||
|
* command: A command identifier to be passed to the onCommand event handlers.
|
||||||
|
*
|
||||||
|
* The plugin exposes the following events:
|
||||||
|
* onCommand: Fired on button click for buttons with 'command' specified.
|
||||||
|
* Event args:
|
||||||
|
* grid: Reference to the grid.
|
||||||
|
* column: Column definition.
|
||||||
|
* command: Button command identified.
|
||||||
|
* button: Button options. Note that you can change the button options in your
|
||||||
|
* event handler, and the column header will be automatically updated to
|
||||||
|
* reflect them. This is useful if you want to implement something like a
|
||||||
|
* toggle button.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param options {Object} Options:
|
||||||
|
* buttonCssClass: a CSS class to use for buttons (default 'slick-header-button')
|
||||||
|
* @class Slick.Plugins.HeaderButtons
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function HeaderButtons(options) {
|
||||||
|
var _grid;
|
||||||
|
var _self = this;
|
||||||
|
var _handler = new Slick.EventHandler();
|
||||||
|
var _defaults = {
|
||||||
|
buttonCssClass: "slick-header-button"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function init(grid) {
|
||||||
|
options = $.extend(true, {}, _defaults, options);
|
||||||
|
_grid = grid;
|
||||||
|
_handler
|
||||||
|
.subscribe(_grid.onHeaderCellRendered, handleHeaderCellRendered)
|
||||||
|
.subscribe(_grid.onBeforeHeaderCellDestroy, handleBeforeHeaderCellDestroy);
|
||||||
|
|
||||||
|
// Force the grid to re-render the header now that the events are hooked up.
|
||||||
|
_grid.setColumns(_grid.getColumns());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function destroy() {
|
||||||
|
_handler.unsubscribeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function handleHeaderCellRendered(e, args) {
|
||||||
|
var column = args.column;
|
||||||
|
|
||||||
|
if (column.header && column.header.buttons) {
|
||||||
|
// Append buttons in reverse order since they are floated to the right.
|
||||||
|
var i = column.header.buttons.length;
|
||||||
|
while (i--) {
|
||||||
|
var button = column.header.buttons[i];
|
||||||
|
var btn = $("<div></div>")
|
||||||
|
.addClass(options.buttonCssClass)
|
||||||
|
.data("column", column)
|
||||||
|
.data("button", button);
|
||||||
|
|
||||||
|
if (button.showOnHover) {
|
||||||
|
btn.addClass("slick-header-button-hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button.image) {
|
||||||
|
btn.css("backgroundImage", "url(" + button.image + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button.cssClass) {
|
||||||
|
btn.addClass(button.cssClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button.tooltip) {
|
||||||
|
btn.attr("title", button.tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button.command) {
|
||||||
|
btn.data("command", button.command);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button.handler) {
|
||||||
|
btn.bind("click", button.handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
btn
|
||||||
|
.bind("click", handleButtonClick)
|
||||||
|
.appendTo(args.node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function handleBeforeHeaderCellDestroy(e, args) {
|
||||||
|
var column = args.column;
|
||||||
|
|
||||||
|
if (column.header && column.header.buttons) {
|
||||||
|
// Removing buttons via jQuery will also clean up any event handlers and data.
|
||||||
|
// NOTE: If you attach event handlers directly or using a different framework,
|
||||||
|
// you must also clean them up here to avoid memory leaks.
|
||||||
|
$(args.node).find("." + options.buttonCssClass).remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function handleButtonClick(e) {
|
||||||
|
var command = $(this).data("command");
|
||||||
|
var columnDef = $(this).data("column");
|
||||||
|
var button = $(this).data("button");
|
||||||
|
|
||||||
|
if (command != null) {
|
||||||
|
_self.onCommand.notify({
|
||||||
|
"grid": _grid,
|
||||||
|
"column": columnDef,
|
||||||
|
"command": command,
|
||||||
|
"button": button
|
||||||
|
}, e, _self);
|
||||||
|
|
||||||
|
// Update the header in case the user updated the button definition in the handler.
|
||||||
|
_grid.updateColumnHeader(columnDef.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop propagation so that it doesn't register as a header click event.
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
$.extend(this, {
|
||||||
|
"init": init,
|
||||||
|
"destroy": destroy,
|
||||||
|
|
||||||
|
"onCommand": new Slick.Event()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})(jQuery);
|
59
web/pgadmin/static/js/slickgrid/plugins/slick.headermenu.css
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/* Menu button */
|
||||||
|
.slick-header-menubutton {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 14px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: left center;
|
||||||
|
background-image: url(../images/down.gif);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
display: none;
|
||||||
|
border-left: thin ridge silver;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-header-column:hover > .slick-header-menubutton,
|
||||||
|
.slick-header-column-active .slick-header-menubutton {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Menu */
|
||||||
|
.slick-header-menu {
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0;
|
||||||
|
padding: 2px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Menu items */
|
||||||
|
.slick-header-menuitem {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-header-menuicon {
|
||||||
|
display: inline-block;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 4px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-header-menucontent {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Disabled */
|
||||||
|
.slick-header-menuitem-disabled {
|
||||||
|
color: silver;
|
||||||
|
}
|
275
web/pgadmin/static/js/slickgrid/plugins/slick.headermenu.js
vendored
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
(function ($) {
|
||||||
|
// register namespace
|
||||||
|
$.extend(true, window, {
|
||||||
|
"Slick": {
|
||||||
|
"Plugins": {
|
||||||
|
"HeaderMenu": HeaderMenu
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/***
|
||||||
|
* A plugin to add drop-down menus to column headers.
|
||||||
|
*
|
||||||
|
* USAGE:
|
||||||
|
*
|
||||||
|
* Add the plugin .js & .css files and register it with the grid.
|
||||||
|
*
|
||||||
|
* To specify a menu in a column header, extend the column definition like so:
|
||||||
|
*
|
||||||
|
* var columns = [
|
||||||
|
* {
|
||||||
|
* id: 'myColumn',
|
||||||
|
* name: 'My column',
|
||||||
|
*
|
||||||
|
* // This is the relevant part
|
||||||
|
* header: {
|
||||||
|
* menu: {
|
||||||
|
* items: [
|
||||||
|
* {
|
||||||
|
* // menu item options
|
||||||
|
* },
|
||||||
|
* {
|
||||||
|
* // menu item options
|
||||||
|
* }
|
||||||
|
* ]
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ];
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Available menu options:
|
||||||
|
* tooltip: Menu button tooltip.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Available menu item options:
|
||||||
|
* title: Menu item text.
|
||||||
|
* disabled: Whether the item is disabled.
|
||||||
|
* tooltip: Item tooltip.
|
||||||
|
* command: A command identifier to be passed to the onCommand event handlers.
|
||||||
|
* iconCssClass: A CSS class to be added to the menu item icon.
|
||||||
|
* iconImage: A url to the icon image.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* The plugin exposes the following events:
|
||||||
|
* onBeforeMenuShow: Fired before the menu is shown. You can customize the menu or dismiss it by returning false.
|
||||||
|
* Event args:
|
||||||
|
* grid: Reference to the grid.
|
||||||
|
* column: Column definition.
|
||||||
|
* menu: Menu options. Note that you can change the menu items here.
|
||||||
|
*
|
||||||
|
* onCommand: Fired on menu item click for buttons with 'command' specified.
|
||||||
|
* Event args:
|
||||||
|
* grid: Reference to the grid.
|
||||||
|
* column: Column definition.
|
||||||
|
* command: Button command identified.
|
||||||
|
* button: Button options. Note that you can change the button options in your
|
||||||
|
* event handler, and the column header will be automatically updated to
|
||||||
|
* reflect them. This is useful if you want to implement something like a
|
||||||
|
* toggle button.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param options {Object} Options:
|
||||||
|
* buttonCssClass: an extra CSS class to add to the menu button
|
||||||
|
* buttonImage: a url to the menu button image (default '../images/down.gif')
|
||||||
|
* @class Slick.Plugins.HeaderButtons
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function HeaderMenu(options) {
|
||||||
|
var _grid;
|
||||||
|
var _self = this;
|
||||||
|
var _handler = new Slick.EventHandler();
|
||||||
|
var _defaults = {
|
||||||
|
buttonCssClass: null,
|
||||||
|
buttonImage: null
|
||||||
|
};
|
||||||
|
var $menu;
|
||||||
|
var $activeHeaderColumn;
|
||||||
|
|
||||||
|
|
||||||
|
function init(grid) {
|
||||||
|
options = $.extend(true, {}, _defaults, options);
|
||||||
|
_grid = grid;
|
||||||
|
_handler
|
||||||
|
.subscribe(_grid.onHeaderCellRendered, handleHeaderCellRendered)
|
||||||
|
.subscribe(_grid.onBeforeHeaderCellDestroy, handleBeforeHeaderCellDestroy);
|
||||||
|
|
||||||
|
// Force the grid to re-render the header now that the events are hooked up.
|
||||||
|
_grid.setColumns(_grid.getColumns());
|
||||||
|
|
||||||
|
// Hide the menu on outside click.
|
||||||
|
$(document.body).bind("mousedown", handleBodyMouseDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function destroy() {
|
||||||
|
_handler.unsubscribeAll();
|
||||||
|
$(document.body).unbind("mousedown", handleBodyMouseDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function handleBodyMouseDown(e) {
|
||||||
|
if ($menu && $menu[0] != e.target && !$.contains($menu[0], e.target)) {
|
||||||
|
hideMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function hideMenu() {
|
||||||
|
if ($menu) {
|
||||||
|
$menu.remove();
|
||||||
|
$menu = null;
|
||||||
|
$activeHeaderColumn
|
||||||
|
.removeClass("slick-header-column-active");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleHeaderCellRendered(e, args) {
|
||||||
|
var column = args.column;
|
||||||
|
var menu = column.header && column.header.menu;
|
||||||
|
|
||||||
|
if (menu) {
|
||||||
|
var $el = $("<div></div>")
|
||||||
|
.addClass("slick-header-menubutton")
|
||||||
|
.data("column", column)
|
||||||
|
.data("menu", menu);
|
||||||
|
|
||||||
|
if (options.buttonCssClass) {
|
||||||
|
$el.addClass(options.buttonCssClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.buttonImage) {
|
||||||
|
$el.css("background-image", "url(" + options.buttonImage + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (menu.tooltip) {
|
||||||
|
$el.attr("title", menu.tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
$el
|
||||||
|
.bind("click", showMenu)
|
||||||
|
.appendTo(args.node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function handleBeforeHeaderCellDestroy(e, args) {
|
||||||
|
var column = args.column;
|
||||||
|
|
||||||
|
if (column.header && column.header.menu) {
|
||||||
|
$(args.node).find(".slick-header-menubutton").remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function showMenu(e) {
|
||||||
|
var $menuButton = $(this);
|
||||||
|
var menu = $menuButton.data("menu");
|
||||||
|
var columnDef = $menuButton.data("column");
|
||||||
|
|
||||||
|
// Let the user modify the menu or cancel altogether,
|
||||||
|
// or provide alternative menu implementation.
|
||||||
|
if (_self.onBeforeMenuShow.notify({
|
||||||
|
"grid": _grid,
|
||||||
|
"column": columnDef,
|
||||||
|
"menu": menu
|
||||||
|
}, e, _self) == false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!$menu) {
|
||||||
|
$menu = $("<div class='slick-header-menu'></div>")
|
||||||
|
.appendTo(_grid.getContainerNode());
|
||||||
|
}
|
||||||
|
$menu.empty();
|
||||||
|
|
||||||
|
|
||||||
|
// Construct the menu items.
|
||||||
|
for (var i = 0; i < menu.items.length; i++) {
|
||||||
|
var item = menu.items[i];
|
||||||
|
|
||||||
|
var $li = $("<div class='slick-header-menuitem'></div>")
|
||||||
|
.data("command", item.command || '')
|
||||||
|
.data("column", columnDef)
|
||||||
|
.data("item", item)
|
||||||
|
.bind("click", handleMenuItemClick)
|
||||||
|
.appendTo($menu);
|
||||||
|
|
||||||
|
if (item.disabled) {
|
||||||
|
$li.addClass("slick-header-menuitem-disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.tooltip) {
|
||||||
|
$li.attr("title", item.tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
var $icon = $("<div class='slick-header-menuicon'></div>")
|
||||||
|
.appendTo($li);
|
||||||
|
|
||||||
|
if (item.iconCssClass) {
|
||||||
|
$icon.addClass(item.iconCssClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.iconImage) {
|
||||||
|
$icon.css("background-image", "url(" + item.iconImage + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
$("<span class='slick-header-menucontent'></span>")
|
||||||
|
.text(item.title)
|
||||||
|
.appendTo($li);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Position the menu.
|
||||||
|
$menu
|
||||||
|
.offset({ top: $(this).offset().top + $(this).height(), left: $(this).offset().left });
|
||||||
|
|
||||||
|
|
||||||
|
// Mark the header as active to keep the highlighting.
|
||||||
|
$activeHeaderColumn = $menuButton.closest(".slick-header-column");
|
||||||
|
$activeHeaderColumn
|
||||||
|
.addClass("slick-header-column-active");
|
||||||
|
|
||||||
|
// Stop propagation so that it doesn't register as a header click event.
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function handleMenuItemClick(e) {
|
||||||
|
var command = $(this).data("command");
|
||||||
|
var columnDef = $(this).data("column");
|
||||||
|
var item = $(this).data("item");
|
||||||
|
|
||||||
|
if (item.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hideMenu();
|
||||||
|
|
||||||
|
if (command != null && command != '') {
|
||||||
|
_self.onCommand.notify({
|
||||||
|
"grid": _grid,
|
||||||
|
"column": columnDef,
|
||||||
|
"command": command,
|
||||||
|
"item": item
|
||||||
|
}, e, _self);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop propagation so that it doesn't register as a header click event.
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
$.extend(this, {
|
||||||
|
"init": init,
|
||||||
|
"destroy": destroy,
|
||||||
|
|
||||||
|
"onBeforeMenuShow": new Slick.Event(),
|
||||||
|
"onCommand": new Slick.Event()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})(jQuery);
|
138
web/pgadmin/static/js/slickgrid/plugins/slick.rowmovemanager.js
vendored
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
(function ($) {
|
||||||
|
// register namespace
|
||||||
|
$.extend(true, window, {
|
||||||
|
"Slick": {
|
||||||
|
"RowMoveManager": RowMoveManager
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function RowMoveManager(options) {
|
||||||
|
var _grid;
|
||||||
|
var _canvas;
|
||||||
|
var _dragging;
|
||||||
|
var _self = this;
|
||||||
|
var _handler = new Slick.EventHandler();
|
||||||
|
var _defaults = {
|
||||||
|
cancelEditOnDrag: false
|
||||||
|
};
|
||||||
|
|
||||||
|
function init(grid) {
|
||||||
|
options = $.extend(true, {}, _defaults, options);
|
||||||
|
_grid = grid;
|
||||||
|
_canvas = _grid.getCanvasNode();
|
||||||
|
_handler
|
||||||
|
.subscribe(_grid.onDragInit, handleDragInit)
|
||||||
|
.subscribe(_grid.onDragStart, handleDragStart)
|
||||||
|
.subscribe(_grid.onDrag, handleDrag)
|
||||||
|
.subscribe(_grid.onDragEnd, handleDragEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroy() {
|
||||||
|
_handler.unsubscribeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragInit(e, dd) {
|
||||||
|
// prevent the grid from cancelling drag'n'drop by default
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragStart(e, dd) {
|
||||||
|
var cell = _grid.getCellFromEvent(e);
|
||||||
|
|
||||||
|
if (options.cancelEditOnDrag && _grid.getEditorLock().isActive()) {
|
||||||
|
_grid.getEditorLock().cancelCurrentEdit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_grid.getEditorLock().isActive() || !/move|selectAndMove/.test(_grid.getColumns()[cell.cell].behavior)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dragging = true;
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
|
||||||
|
var selectedRows = _grid.getSelectedRows();
|
||||||
|
|
||||||
|
if (selectedRows.length == 0 || $.inArray(cell.row, selectedRows) == -1) {
|
||||||
|
selectedRows = [cell.row];
|
||||||
|
_grid.setSelectedRows(selectedRows);
|
||||||
|
}
|
||||||
|
|
||||||
|
var rowHeight = _grid.getOptions().rowHeight;
|
||||||
|
|
||||||
|
dd.selectedRows = selectedRows;
|
||||||
|
|
||||||
|
dd.selectionProxy = $("<div class='slick-reorder-proxy'/>")
|
||||||
|
.css("position", "absolute")
|
||||||
|
.css("zIndex", "99999")
|
||||||
|
.css("width", $(_canvas).innerWidth())
|
||||||
|
.css("height", rowHeight * selectedRows.length)
|
||||||
|
.appendTo(_canvas);
|
||||||
|
|
||||||
|
dd.guide = $("<div class='slick-reorder-guide'/>")
|
||||||
|
.css("position", "absolute")
|
||||||
|
.css("zIndex", "99998")
|
||||||
|
.css("width", $(_canvas).innerWidth())
|
||||||
|
.css("top", -1000)
|
||||||
|
.appendTo(_canvas);
|
||||||
|
|
||||||
|
dd.insertBefore = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDrag(e, dd) {
|
||||||
|
if (!_dragging) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
|
||||||
|
var top = e.pageY - $(_canvas).offset().top;
|
||||||
|
dd.selectionProxy.css("top", top - 5);
|
||||||
|
|
||||||
|
var insertBefore = Math.max(0, Math.min(Math.round(top / _grid.getOptions().rowHeight), _grid.getDataLength()));
|
||||||
|
if (insertBefore !== dd.insertBefore) {
|
||||||
|
var eventData = {
|
||||||
|
"rows": dd.selectedRows,
|
||||||
|
"insertBefore": insertBefore
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_self.onBeforeMoveRows.notify(eventData) === false) {
|
||||||
|
dd.guide.css("top", -1000);
|
||||||
|
dd.canMove = false;
|
||||||
|
} else {
|
||||||
|
dd.guide.css("top", insertBefore * _grid.getOptions().rowHeight);
|
||||||
|
dd.canMove = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd.insertBefore = insertBefore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragEnd(e, dd) {
|
||||||
|
if (!_dragging) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_dragging = false;
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
|
||||||
|
dd.guide.remove();
|
||||||
|
dd.selectionProxy.remove();
|
||||||
|
|
||||||
|
if (dd.canMove) {
|
||||||
|
var eventData = {
|
||||||
|
"rows": dd.selectedRows,
|
||||||
|
"insertBefore": dd.insertBefore
|
||||||
|
};
|
||||||
|
// TODO: _grid.remapCellCssClasses ?
|
||||||
|
_self.onMoveRows.notify(eventData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$.extend(this, {
|
||||||
|
"onBeforeMoveRows": new Slick.Event(),
|
||||||
|
"onMoveRows": new Slick.Event(),
|
||||||
|
|
||||||
|
"init": init,
|
||||||
|
"destroy": destroy
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})(jQuery);
|
189
web/pgadmin/static/js/slickgrid/plugins/slick.rowselectionmodel.js
vendored
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
(function ($) {
|
||||||
|
// register namespace
|
||||||
|
$.extend(true, window, {
|
||||||
|
"Slick": {
|
||||||
|
"RowSelectionModel": RowSelectionModel
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function RowSelectionModel(options) {
|
||||||
|
var _grid;
|
||||||
|
var _ranges = [];
|
||||||
|
var _self = this;
|
||||||
|
var _handler = new Slick.EventHandler();
|
||||||
|
var _inHandler;
|
||||||
|
var _options;
|
||||||
|
var _defaults = {
|
||||||
|
selectActiveRow: true
|
||||||
|
};
|
||||||
|
|
||||||
|
function init(grid) {
|
||||||
|
_options = $.extend(true, {}, _defaults, options);
|
||||||
|
_grid = grid;
|
||||||
|
_handler.subscribe(_grid.onActiveCellChanged,
|
||||||
|
wrapHandler(handleActiveCellChange));
|
||||||
|
_handler.subscribe(_grid.onKeyDown,
|
||||||
|
wrapHandler(handleKeyDown));
|
||||||
|
_handler.subscribe(_grid.onClick,
|
||||||
|
wrapHandler(handleClick));
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroy() {
|
||||||
|
_handler.unsubscribeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
function wrapHandler(handler) {
|
||||||
|
return function () {
|
||||||
|
if (!_inHandler) {
|
||||||
|
_inHandler = true;
|
||||||
|
handler.apply(this, arguments);
|
||||||
|
_inHandler = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function rangesToRows(ranges) {
|
||||||
|
var rows = [];
|
||||||
|
for (var i = 0; i < ranges.length; i++) {
|
||||||
|
for (var j = ranges[i].fromRow; j <= ranges[i].toRow; j++) {
|
||||||
|
rows.push(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rowsToRanges(rows) {
|
||||||
|
var ranges = [];
|
||||||
|
var lastCell = _grid.getColumns().length - 1;
|
||||||
|
for (var i = 0; i < rows.length; i++) {
|
||||||
|
ranges.push(new Slick.Range(rows[i], 0, rows[i], lastCell));
|
||||||
|
}
|
||||||
|
return ranges;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRowsRange(from, to) {
|
||||||
|
var i, rows = [];
|
||||||
|
for (i = from; i <= to; i++) {
|
||||||
|
rows.push(i);
|
||||||
|
}
|
||||||
|
for (i = to; i < from; i++) {
|
||||||
|
rows.push(i);
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelectedRows() {
|
||||||
|
return rangesToRows(_ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSelectedRows(rows) {
|
||||||
|
setSelectedRanges(rowsToRanges(rows));
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSelectedRanges(ranges) {
|
||||||
|
// simle check for: empty selection didn't change, prevent firing onSelectedRangesChanged
|
||||||
|
if ((!_ranges || _ranges.length === 0) && (!ranges || ranges.length === 0)) { return; }
|
||||||
|
_ranges = ranges;
|
||||||
|
_self.onSelectedRangesChanged.notify(_ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelectedRanges() {
|
||||||
|
return _ranges;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleActiveCellChange(e, data) {
|
||||||
|
if (_options.selectActiveRow && data.row != null) {
|
||||||
|
setSelectedRanges([new Slick.Range(data.row, 0, data.row, _grid.getColumns().length - 1)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleKeyDown(e) {
|
||||||
|
var activeRow = _grid.getActiveCell();
|
||||||
|
if (activeRow && e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey && (e.which == 38 || e.which == 40)) {
|
||||||
|
var selectedRows = getSelectedRows();
|
||||||
|
selectedRows.sort(function (x, y) {
|
||||||
|
return x - y
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!selectedRows.length) {
|
||||||
|
selectedRows = [activeRow.row];
|
||||||
|
}
|
||||||
|
|
||||||
|
var top = selectedRows[0];
|
||||||
|
var bottom = selectedRows[selectedRows.length - 1];
|
||||||
|
var active;
|
||||||
|
|
||||||
|
if (e.which == 40) {
|
||||||
|
active = activeRow.row < bottom || top == bottom ? ++bottom : ++top;
|
||||||
|
} else {
|
||||||
|
active = activeRow.row < bottom ? --bottom : --top;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (active >= 0 && active < _grid.getDataLength()) {
|
||||||
|
_grid.scrollRowIntoView(active);
|
||||||
|
_ranges = rowsToRanges(getRowsRange(top, bottom));
|
||||||
|
setSelectedRanges(_ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClick(e) {
|
||||||
|
var cell = _grid.getCellFromEvent(e);
|
||||||
|
if (!cell || !_grid.canCellBeActive(cell.row, cell.cell)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_grid.getOptions().multiSelect || (
|
||||||
|
!e.ctrlKey && !e.shiftKey && !e.metaKey)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selection = rangesToRows(_ranges);
|
||||||
|
var idx = $.inArray(cell.row, selection);
|
||||||
|
|
||||||
|
if (idx === -1 && (e.ctrlKey || e.metaKey)) {
|
||||||
|
selection.push(cell.row);
|
||||||
|
_grid.setActiveCell(cell.row, cell.cell);
|
||||||
|
} else if (idx !== -1 && (e.ctrlKey || e.metaKey)) {
|
||||||
|
selection = $.grep(selection, function (o, i) {
|
||||||
|
return (o !== cell.row);
|
||||||
|
});
|
||||||
|
_grid.setActiveCell(cell.row, cell.cell);
|
||||||
|
} else if (selection.length && e.shiftKey) {
|
||||||
|
var last = selection.pop();
|
||||||
|
var from = Math.min(cell.row, last);
|
||||||
|
var to = Math.max(cell.row, last);
|
||||||
|
selection = [];
|
||||||
|
for (var i = from; i <= to; i++) {
|
||||||
|
if (i !== last) {
|
||||||
|
selection.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selection.push(last);
|
||||||
|
_grid.setActiveCell(cell.row, cell.cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ranges = rowsToRanges(selection);
|
||||||
|
setSelectedRanges(_ranges);
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$.extend(this, {
|
||||||
|
"getSelectedRows": getSelectedRows,
|
||||||
|
"setSelectedRows": setSelectedRows,
|
||||||
|
|
||||||
|
"getSelectedRanges": getSelectedRanges,
|
||||||
|
"setSelectedRanges": setSelectedRanges,
|
||||||
|
|
||||||
|
"init": init,
|
||||||
|
"destroy": destroy,
|
||||||
|
|
||||||
|
"onSelectedRangesChanged": new Slick.Event()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})(jQuery);
|
484
web/pgadmin/static/js/slickgrid/slick.core.js
vendored
Normal file
@ -0,0 +1,484 @@
|
|||||||
|
/***
|
||||||
|
* 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(),
|
||||||
|
|
||||||
|
"keyCode": {
|
||||||
|
BACKSPACE: 8,
|
||||||
|
DELETE: 46,
|
||||||
|
DOWN: 40,
|
||||||
|
END: 35,
|
||||||
|
ENTER: 13,
|
||||||
|
ESCAPE: 27,
|
||||||
|
HOME: 36,
|
||||||
|
INSERT: 45,
|
||||||
|
LEFT: 37,
|
||||||
|
PAGE_DOWN: 34,
|
||||||
|
PAGE_UP: 33,
|
||||||
|
RIGHT: 39,
|
||||||
|
TAB: 9,
|
||||||
|
UP: 38
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
return this; // allow chaining
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this; // allow chaining
|
||||||
|
};
|
||||||
|
|
||||||
|
this.unsubscribeAll = function () {
|
||||||
|
var i = handlers.length;
|
||||||
|
while (i--) {
|
||||||
|
handlers[i].event.unsubscribe(handlers[i].handler);
|
||||||
|
}
|
||||||
|
handlers = [];
|
||||||
|
|
||||||
|
return this; // allow chaining
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grouping level, starting with 0.
|
||||||
|
* @property level
|
||||||
|
* @type {Number}
|
||||||
|
*/
|
||||||
|
this.level = 0;
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rows that are part of the group.
|
||||||
|
* @property rows
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
this.rows = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sub-groups that are part of the group.
|
||||||
|
* @property groups
|
||||||
|
* @type {Array}
|
||||||
|
*/
|
||||||
|
this.groups = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unique key used to identify the group. This key can be used in calls to DataView
|
||||||
|
* collapseGroup() or expandGroup().
|
||||||
|
* @property groupingKey
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
this.groupingKey = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Group.prototype = new NonDataItem();
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 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 &&
|
||||||
|
this.title === group.title;
|
||||||
|
};
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Whether the totals have been fully initialized / calculated.
|
||||||
|
* Will be set to false for lazy-calculated group totals.
|
||||||
|
* @param initialized
|
||||||
|
* @type {Boolean}
|
||||||
|
*/
|
||||||
|
this.initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupTotals.prototype = new NonDataItem();
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
|
1141
web/pgadmin/static/js/slickgrid/slick.dataview.js
vendored
Normal file
631
web/pgadmin/static/js/slickgrid/slick.editors.js
vendored
Normal file
@ -0,0 +1,631 @@
|
|||||||
|
/***
|
||||||
|
* Contains basic SlickGrid editors.
|
||||||
|
* @module Editors
|
||||||
|
* @namespace Slick
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function ($) {
|
||||||
|
// register namespace
|
||||||
|
$.extend(true, window, {
|
||||||
|
"Slick": {
|
||||||
|
"Editors": {
|
||||||
|
"Text": TextEditor,
|
||||||
|
"Integer": IntegerEditor,
|
||||||
|
"Float": FloatEditor,
|
||||||
|
"Date": DateEditor,
|
||||||
|
"YesNoSelect": YesNoSelectEditor,
|
||||||
|
"Checkbox": CheckboxEditor,
|
||||||
|
"PercentComplete": PercentCompleteEditor,
|
||||||
|
"LongText": LongTextEditor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function TextEditor(args) {
|
||||||
|
var $input;
|
||||||
|
var defaultValue;
|
||||||
|
var scope = this;
|
||||||
|
|
||||||
|
this.init = function () {
|
||||||
|
$input = $("<INPUT type=text class='editor-text' />")
|
||||||
|
.appendTo(args.container)
|
||||||
|
.bind("keydown.nav", function (e) {
|
||||||
|
if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.focus()
|
||||||
|
.select();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.destroy = function () {
|
||||||
|
$input.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.focus = function () {
|
||||||
|
$input.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getValue = function () {
|
||||||
|
return $input.val();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setValue = function (val) {
|
||||||
|
$input.val(val);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.loadValue = function (item) {
|
||||||
|
defaultValue = item[args.column.field] || "";
|
||||||
|
$input.val(defaultValue);
|
||||||
|
$input[0].defaultValue = defaultValue;
|
||||||
|
$input.select();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.serializeValue = function () {
|
||||||
|
return $input.val();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.applyValue = function (item, state) {
|
||||||
|
item[args.column.field] = state;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isValueChanged = function () {
|
||||||
|
return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.validate = function () {
|
||||||
|
if (args.column.validator) {
|
||||||
|
var validationResults = args.column.validator($input.val());
|
||||||
|
if (!validationResults.valid) {
|
||||||
|
return validationResults;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
msg: null
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
function IntegerEditor(args) {
|
||||||
|
var $input;
|
||||||
|
var defaultValue;
|
||||||
|
var scope = this;
|
||||||
|
|
||||||
|
this.init = function () {
|
||||||
|
$input = $("<INPUT type=text class='editor-text' />");
|
||||||
|
|
||||||
|
$input.bind("keydown.nav", function (e) {
|
||||||
|
if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$input.appendTo(args.container);
|
||||||
|
$input.focus().select();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.destroy = function () {
|
||||||
|
$input.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.focus = function () {
|
||||||
|
$input.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.loadValue = function (item) {
|
||||||
|
defaultValue = item[args.column.field];
|
||||||
|
$input.val(defaultValue);
|
||||||
|
$input[0].defaultValue = defaultValue;
|
||||||
|
$input.select();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.serializeValue = function () {
|
||||||
|
return parseInt($input.val(), 10) || 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.applyValue = function (item, state) {
|
||||||
|
item[args.column.field] = state;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isValueChanged = function () {
|
||||||
|
return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.validate = function () {
|
||||||
|
if (isNaN($input.val())) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
msg: "Please enter a valid integer"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.column.validator) {
|
||||||
|
var validationResults = args.column.validator($input.val());
|
||||||
|
if (!validationResults.valid) {
|
||||||
|
return validationResults;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
msg: null
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
function FloatEditor(args) {
|
||||||
|
var $input;
|
||||||
|
var defaultValue;
|
||||||
|
var scope = this;
|
||||||
|
|
||||||
|
this.init = function () {
|
||||||
|
$input = $("<INPUT type=text class='editor-text' />");
|
||||||
|
|
||||||
|
$input.bind("keydown.nav", function (e) {
|
||||||
|
if (e.keyCode === $.ui.keyCode.LEFT || e.keyCode === $.ui.keyCode.RIGHT) {
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$input.appendTo(args.container);
|
||||||
|
$input.focus().select();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.destroy = function () {
|
||||||
|
$input.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.focus = function () {
|
||||||
|
$input.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
function getDecimalPlaces() {
|
||||||
|
// returns the number of fixed decimal places or null
|
||||||
|
var rtn = args.column.editorFixedDecimalPlaces;
|
||||||
|
if (typeof rtn == 'undefined') {
|
||||||
|
rtn = FloatEditor.DefaultDecimalPlaces;
|
||||||
|
}
|
||||||
|
return (!rtn && rtn!==0 ? null : rtn);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadValue = function (item) {
|
||||||
|
defaultValue = item[args.column.field];
|
||||||
|
|
||||||
|
var decPlaces = getDecimalPlaces();
|
||||||
|
if (decPlaces !== null
|
||||||
|
&& (defaultValue || defaultValue===0)
|
||||||
|
&& defaultValue.toFixed) {
|
||||||
|
defaultValue = defaultValue.toFixed(decPlaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
$input.val(defaultValue);
|
||||||
|
$input[0].defaultValue = defaultValue;
|
||||||
|
$input.select();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.serializeValue = function () {
|
||||||
|
var rtn = parseFloat($input.val()) || 0;
|
||||||
|
|
||||||
|
var decPlaces = getDecimalPlaces();
|
||||||
|
if (decPlaces !== null
|
||||||
|
&& (rtn || rtn===0)
|
||||||
|
&& rtn.toFixed) {
|
||||||
|
rtn = parseFloat(rtn.toFixed(decPlaces));
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtn;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.applyValue = function (item, state) {
|
||||||
|
item[args.column.field] = state;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isValueChanged = function () {
|
||||||
|
return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.validate = function () {
|
||||||
|
if (isNaN($input.val())) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
msg: "Please enter a valid number"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.column.validator) {
|
||||||
|
var validationResults = args.column.validator($input.val());
|
||||||
|
if (!validationResults.valid) {
|
||||||
|
return validationResults;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
msg: null
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatEditor.DefaultDecimalPlaces = null;
|
||||||
|
|
||||||
|
function DateEditor(args) {
|
||||||
|
var $input;
|
||||||
|
var defaultValue;
|
||||||
|
var scope = this;
|
||||||
|
var calendarOpen = false;
|
||||||
|
|
||||||
|
this.init = function () {
|
||||||
|
$input = $("<INPUT type=text class='editor-text' />");
|
||||||
|
$input.appendTo(args.container);
|
||||||
|
$input.focus().select();
|
||||||
|
$input.datepicker({
|
||||||
|
showOn: "button",
|
||||||
|
buttonImageOnly: true,
|
||||||
|
buttonImage: "../images/calendar.gif",
|
||||||
|
beforeShow: function () {
|
||||||
|
calendarOpen = true
|
||||||
|
},
|
||||||
|
onClose: function () {
|
||||||
|
calendarOpen = false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$input.width($input.width() - 18);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.destroy = function () {
|
||||||
|
$.datepicker.dpDiv.stop(true, true);
|
||||||
|
$input.datepicker("hide");
|
||||||
|
$input.datepicker("destroy");
|
||||||
|
$input.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.show = function () {
|
||||||
|
if (calendarOpen) {
|
||||||
|
$.datepicker.dpDiv.stop(true, true).show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.hide = function () {
|
||||||
|
if (calendarOpen) {
|
||||||
|
$.datepicker.dpDiv.stop(true, true).hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.position = function (position) {
|
||||||
|
if (!calendarOpen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.datepicker.dpDiv
|
||||||
|
.css("top", position.top + 30)
|
||||||
|
.css("left", position.left);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.focus = function () {
|
||||||
|
$input.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.loadValue = function (item) {
|
||||||
|
defaultValue = item[args.column.field];
|
||||||
|
$input.val(defaultValue);
|
||||||
|
$input[0].defaultValue = defaultValue;
|
||||||
|
$input.select();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.serializeValue = function () {
|
||||||
|
return $input.val();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.applyValue = function (item, state) {
|
||||||
|
item[args.column.field] = state;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isValueChanged = function () {
|
||||||
|
return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.validate = function () {
|
||||||
|
if (args.column.validator) {
|
||||||
|
var validationResults = args.column.validator($input.val());
|
||||||
|
if (!validationResults.valid) {
|
||||||
|
return validationResults;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
msg: null
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
function YesNoSelectEditor(args) {
|
||||||
|
var $select;
|
||||||
|
var defaultValue;
|
||||||
|
var scope = this;
|
||||||
|
|
||||||
|
this.init = function () {
|
||||||
|
$select = $("<SELECT tabIndex='0' class='editor-yesno'><OPTION value='yes'>Yes</OPTION><OPTION value='no'>No</OPTION></SELECT>");
|
||||||
|
$select.appendTo(args.container);
|
||||||
|
$select.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.destroy = function () {
|
||||||
|
$select.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.focus = function () {
|
||||||
|
$select.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.loadValue = function (item) {
|
||||||
|
$select.val((defaultValue = item[args.column.field]) ? "yes" : "no");
|
||||||
|
$select.select();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.serializeValue = function () {
|
||||||
|
return ($select.val() == "yes");
|
||||||
|
};
|
||||||
|
|
||||||
|
this.applyValue = function (item, state) {
|
||||||
|
item[args.column.field] = state;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isValueChanged = function () {
|
||||||
|
return ($select.val() != defaultValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.validate = function () {
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
msg: null
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
function CheckboxEditor(args) {
|
||||||
|
var $select;
|
||||||
|
var defaultValue;
|
||||||
|
var scope = this;
|
||||||
|
|
||||||
|
this.init = function () {
|
||||||
|
$select = $("<INPUT type=checkbox value='true' class='editor-checkbox' hideFocus>");
|
||||||
|
$select.appendTo(args.container);
|
||||||
|
$select.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.destroy = function () {
|
||||||
|
$select.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.focus = function () {
|
||||||
|
$select.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.loadValue = function (item) {
|
||||||
|
defaultValue = !!item[args.column.field];
|
||||||
|
if (defaultValue) {
|
||||||
|
$select.prop('checked', true);
|
||||||
|
} else {
|
||||||
|
$select.prop('checked', false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.serializeValue = function () {
|
||||||
|
return $select.prop('checked');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.applyValue = function (item, state) {
|
||||||
|
item[args.column.field] = state;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isValueChanged = function () {
|
||||||
|
return (this.serializeValue() !== defaultValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.validate = function () {
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
msg: null
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
function PercentCompleteEditor(args) {
|
||||||
|
var $input, $picker;
|
||||||
|
var defaultValue;
|
||||||
|
var scope = this;
|
||||||
|
|
||||||
|
this.init = function () {
|
||||||
|
$input = $("<INPUT type=text class='editor-percentcomplete' />");
|
||||||
|
$input.width($(args.container).innerWidth() - 25);
|
||||||
|
$input.appendTo(args.container);
|
||||||
|
|
||||||
|
$picker = $("<div class='editor-percentcomplete-picker' />").appendTo(args.container);
|
||||||
|
$picker.append("<div class='editor-percentcomplete-helper'><div class='editor-percentcomplete-wrapper'><div class='editor-percentcomplete-slider' /><div class='editor-percentcomplete-buttons' /></div></div>");
|
||||||
|
|
||||||
|
$picker.find(".editor-percentcomplete-buttons").append("<button val=0>Not started</button><br/><button val=50>In Progress</button><br/><button val=100>Complete</button>");
|
||||||
|
|
||||||
|
$input.focus().select();
|
||||||
|
|
||||||
|
$picker.find(".editor-percentcomplete-slider").slider({
|
||||||
|
orientation: "vertical",
|
||||||
|
range: "min",
|
||||||
|
value: defaultValue,
|
||||||
|
slide: function (event, ui) {
|
||||||
|
$input.val(ui.value)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$picker.find(".editor-percentcomplete-buttons button").bind("click", function (e) {
|
||||||
|
$input.val($(this).attr("val"));
|
||||||
|
$picker.find(".editor-percentcomplete-slider").slider("value", $(this).attr("val"));
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
this.destroy = function () {
|
||||||
|
$input.remove();
|
||||||
|
$picker.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.focus = function () {
|
||||||
|
$input.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.loadValue = function (item) {
|
||||||
|
$input.val(defaultValue = item[args.column.field]);
|
||||||
|
$input.select();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.serializeValue = function () {
|
||||||
|
return parseInt($input.val(), 10) || 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.applyValue = function (item, state) {
|
||||||
|
item[args.column.field] = state;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isValueChanged = function () {
|
||||||
|
return (!($input.val() == "" && defaultValue == null)) && ((parseInt($input.val(), 10) || 0) != defaultValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.validate = function () {
|
||||||
|
if (isNaN(parseInt($input.val(), 10))) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
msg: "Please enter a valid positive number"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
msg: null
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An example of a "detached" editor.
|
||||||
|
* The UI is added onto document BODY and .position(), .show() and .hide() are implemented.
|
||||||
|
* KeyDown events are also handled to provide handling for Tab, Shift-Tab, Esc and Ctrl-Enter.
|
||||||
|
*/
|
||||||
|
function LongTextEditor(args) {
|
||||||
|
var $input, $wrapper;
|
||||||
|
var defaultValue;
|
||||||
|
var scope = this;
|
||||||
|
|
||||||
|
this.init = function () {
|
||||||
|
var $container = $("body");
|
||||||
|
|
||||||
|
$wrapper = $("<DIV style='z-index:10000;position:absolute;background:white;padding:5px;border:3px solid gray; -moz-border-radius:10px; border-radius:10px;'/>")
|
||||||
|
.appendTo($container);
|
||||||
|
|
||||||
|
$input = $("<TEXTAREA hidefocus rows=5 style='backround:white;width:250px;height:80px;border:0;outline:0'>")
|
||||||
|
.appendTo($wrapper);
|
||||||
|
|
||||||
|
$("<DIV style='text-align:right'><BUTTON>Save</BUTTON><BUTTON>Cancel</BUTTON></DIV>")
|
||||||
|
.appendTo($wrapper);
|
||||||
|
|
||||||
|
$wrapper.find("button:first").bind("click", this.save);
|
||||||
|
$wrapper.find("button:last").bind("click", this.cancel);
|
||||||
|
$input.bind("keydown", this.handleKeyDown);
|
||||||
|
|
||||||
|
scope.position(args.position);
|
||||||
|
$input.focus().select();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.handleKeyDown = function (e) {
|
||||||
|
if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
|
||||||
|
scope.save();
|
||||||
|
} else if (e.which == $.ui.keyCode.ESCAPE) {
|
||||||
|
e.preventDefault();
|
||||||
|
scope.cancel();
|
||||||
|
} else if (e.which == $.ui.keyCode.TAB && e.shiftKey) {
|
||||||
|
e.preventDefault();
|
||||||
|
args.grid.navigatePrev();
|
||||||
|
} else if (e.which == $.ui.keyCode.TAB) {
|
||||||
|
e.preventDefault();
|
||||||
|
args.grid.navigateNext();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.save = function () {
|
||||||
|
args.commitChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.cancel = function () {
|
||||||
|
$input.val(defaultValue);
|
||||||
|
args.cancelChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.hide = function () {
|
||||||
|
$wrapper.hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.show = function () {
|
||||||
|
$wrapper.show();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.position = function (position) {
|
||||||
|
$wrapper
|
||||||
|
.css("top", position.top - 5)
|
||||||
|
.css("left", position.left - 5)
|
||||||
|
};
|
||||||
|
|
||||||
|
this.destroy = function () {
|
||||||
|
$wrapper.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.focus = function () {
|
||||||
|
$input.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.loadValue = function (item) {
|
||||||
|
$input.val(defaultValue = item[args.column.field]);
|
||||||
|
$input.select();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.serializeValue = function () {
|
||||||
|
return $input.val();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.applyValue = function (item, state) {
|
||||||
|
item[args.column.field] = state;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isValueChanged = function () {
|
||||||
|
return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.validate = function () {
|
||||||
|
if (args.column.validator) {
|
||||||
|
var validationResults = args.column.validator($input.val());
|
||||||
|
if (!validationResults.valid) {
|
||||||
|
return validationResults;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
msg: null
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
})(jQuery);
|
59
web/pgadmin/static/js/slickgrid/slick.formatters.js
vendored
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/***
|
||||||
|
* Contains basic SlickGrid formatters.
|
||||||
|
*
|
||||||
|
* NOTE: These are merely examples. You will most likely need to implement something more
|
||||||
|
* robust/extensible/localizable/etc. for your use!
|
||||||
|
*
|
||||||
|
* @module Formatters
|
||||||
|
* @namespace Slick
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function ($) {
|
||||||
|
// register namespace
|
||||||
|
$.extend(true, window, {
|
||||||
|
"Slick": {
|
||||||
|
"Formatters": {
|
||||||
|
"PercentComplete": PercentCompleteFormatter,
|
||||||
|
"PercentCompleteBar": PercentCompleteBarFormatter,
|
||||||
|
"YesNo": YesNoFormatter,
|
||||||
|
"Checkmark": CheckmarkFormatter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function PercentCompleteFormatter(row, cell, value, columnDef, dataContext) {
|
||||||
|
if (value == null || value === "") {
|
||||||
|
return "-";
|
||||||
|
} else if (value < 50) {
|
||||||
|
return "<span style='color:red;font-weight:bold;'>" + value + "%</span>";
|
||||||
|
} else {
|
||||||
|
return "<span style='color:green'>" + value + "%</span>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function PercentCompleteBarFormatter(row, cell, value, columnDef, dataContext) {
|
||||||
|
if (value == null || value === "") {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
var color;
|
||||||
|
|
||||||
|
if (value < 30) {
|
||||||
|
color = "red";
|
||||||
|
} else if (value < 70) {
|
||||||
|
color = "silver";
|
||||||
|
} else {
|
||||||
|
color = "green";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<span class='percent-complete-bar' style='background:" + color + ";width:" + value + "%'></span>";
|
||||||
|
}
|
||||||
|
|
||||||
|
function YesNoFormatter(row, cell, value, columnDef, dataContext) {
|
||||||
|
return value ? "Yes" : "No";
|
||||||
|
}
|
||||||
|
|
||||||
|
function CheckmarkFormatter(row, cell, value, columnDef, dataContext) {
|
||||||
|
return value ? "<img src='../images/tick.png'>" : "";
|
||||||
|
}
|
||||||
|
})(jQuery);
|
3607
web/pgadmin/static/js/slickgrid/slick.grid.js
vendored
Normal file
261
web/pgadmin/static/js/slickgrid/slick.pgadmin.editors.js
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
/***
|
||||||
|
* Contains JSON SlickGrid editors.
|
||||||
|
* @module Editors
|
||||||
|
* @namespace Slick
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function ($) {
|
||||||
|
// register namespace
|
||||||
|
$.extend(true, window, {
|
||||||
|
"Slick": {
|
||||||
|
"Editors": {
|
||||||
|
"pgText": pgTextEditor,
|
||||||
|
"JsonText": JsonTextEditor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Text data type editor
|
||||||
|
function pgTextEditor(args) {
|
||||||
|
var $input, $wrapper;
|
||||||
|
var defaultValue;
|
||||||
|
var scope = this;
|
||||||
|
|
||||||
|
this.init = function () {
|
||||||
|
var $container = $("body");
|
||||||
|
|
||||||
|
$wrapper = $("<DIV style='z-index:10000;position:absolute;background:white;padding:5px;border:3px solid gray; -moz-border-radius:10px; border-radius:10px;'/>")
|
||||||
|
.appendTo($container);
|
||||||
|
|
||||||
|
$input = $("<TEXTAREA hidefocus rows=5 style='backround:white;width:250px;height:80px;border:0;outline:0'>")
|
||||||
|
.appendTo($wrapper);
|
||||||
|
|
||||||
|
$("<DIV style='text-align:right'><BUTTON class='btn btn-primary fa fa-lg fa-save long_text_editor pg-alertify-button'>Save</BUTTON>"
|
||||||
|
+ "<BUTTON class='btn btn-danger fa fa-lg fa-times long_text_editor pg-alertify-button'>Cancel</BUTTON></DIV>")
|
||||||
|
.appendTo($wrapper);
|
||||||
|
|
||||||
|
$wrapper.find("button:first").bind("click", this.save);
|
||||||
|
$wrapper.find("button:last").bind("click", this.cancel);
|
||||||
|
$input.bind("keydown", this.handleKeyDown);
|
||||||
|
|
||||||
|
scope.position(args.position);
|
||||||
|
$input.focus().select();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.handleKeyDown = function (e) {
|
||||||
|
if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
|
||||||
|
scope.save();
|
||||||
|
} else if (e.which == $.ui.keyCode.ESCAPE) {
|
||||||
|
e.preventDefault();
|
||||||
|
scope.cancel();
|
||||||
|
} else if (e.which == $.ui.keyCode.TAB && e.shiftKey) {
|
||||||
|
e.preventDefault();
|
||||||
|
args.grid.navigatePrev();
|
||||||
|
} else if (e.which == $.ui.keyCode.TAB) {
|
||||||
|
e.preventDefault();
|
||||||
|
args.grid.navigateNext();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.save = function () {
|
||||||
|
args.commitChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.cancel = function () {
|
||||||
|
$input.val(defaultValue);
|
||||||
|
args.cancelChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.hide = function () {
|
||||||
|
$wrapper.hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.show = function () {
|
||||||
|
$wrapper.show();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.position = function (position) {
|
||||||
|
var _elem_height = $wrapper.parent().find('#datagrid').height(),
|
||||||
|
is_hidden, _position;
|
||||||
|
// We can not display editor partially visible so we will lift it above select column
|
||||||
|
if(position.top > _elem_height) {
|
||||||
|
is_hidden = position.bottom - _elem_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_hidden) {
|
||||||
|
_position = position.top - is_hidden;
|
||||||
|
} else {
|
||||||
|
_position = position.top - 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
$wrapper
|
||||||
|
.css("top", _position)
|
||||||
|
.css("left", position.left - 5)
|
||||||
|
};
|
||||||
|
|
||||||
|
this.destroy = function () {
|
||||||
|
$wrapper.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.focus = function () {
|
||||||
|
$input.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.loadValue = function (item) {
|
||||||
|
$input.val(defaultValue = item[args.column.field]);
|
||||||
|
$input.select();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.serializeValue = function () {
|
||||||
|
return $input.val();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.applyValue = function (item, state) {
|
||||||
|
item[args.column.field] = state;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isValueChanged = function () {
|
||||||
|
return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.validate = function () {
|
||||||
|
if (args.column.validator) {
|
||||||
|
var validationResults = args.column.validator($input.val());
|
||||||
|
if (!validationResults.valid) {
|
||||||
|
return validationResults;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
msg: null
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON data type editor
|
||||||
|
function JsonTextEditor(args) {
|
||||||
|
var $input, $wrapper;
|
||||||
|
var defaultValue;
|
||||||
|
var scope = this;
|
||||||
|
|
||||||
|
this.init = function () {
|
||||||
|
var $container = $("body");
|
||||||
|
|
||||||
|
$wrapper = $("<DIV style='z-index:10000;position:absolute;background:white;padding:5px;border:3px solid gray; -moz-border-radius:10px; border-radius:10px;'/>")
|
||||||
|
.appendTo($container);
|
||||||
|
|
||||||
|
$input = $("<TEXTAREA hidefocus rows=5 style='backround:white;width:250px;height:80px;border:0;outline:0'>")
|
||||||
|
.appendTo($wrapper);
|
||||||
|
|
||||||
|
$("<DIV style='text-align:right'><BUTTON class='btn btn-primary fa fa-lg fa-save long_text_editor pg-alertify-button'>Save</BUTTON>"
|
||||||
|
+ "<BUTTON class='btn btn-danger fa fa-lg fa-times long_text_editor pg-alertify-button'>Cancel</BUTTON></DIV>")
|
||||||
|
.appendTo($wrapper);
|
||||||
|
|
||||||
|
$wrapper.find("button:first").bind("click", this.save);
|
||||||
|
$wrapper.find("button:last").bind("click", this.cancel);
|
||||||
|
$input.bind("keydown", this.handleKeyDown);
|
||||||
|
|
||||||
|
scope.position(args.position);
|
||||||
|
$input.focus().select();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.handleKeyDown = function (e) {
|
||||||
|
if (e.which == $.ui.keyCode.ENTER && e.ctrlKey) {
|
||||||
|
scope.save();
|
||||||
|
} else if (e.which == $.ui.keyCode.ESCAPE) {
|
||||||
|
e.preventDefault();
|
||||||
|
scope.cancel();
|
||||||
|
} else if (e.which == $.ui.keyCode.TAB && e.shiftKey) {
|
||||||
|
e.preventDefault();
|
||||||
|
args.grid.navigatePrev();
|
||||||
|
} else if (e.which == $.ui.keyCode.TAB) {
|
||||||
|
e.preventDefault();
|
||||||
|
args.grid.navigateNext();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.save = function () {
|
||||||
|
args.commitChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.cancel = function () {
|
||||||
|
$input.val(defaultValue);
|
||||||
|
args.cancelChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.hide = function () {
|
||||||
|
$wrapper.hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.show = function () {
|
||||||
|
$wrapper.show();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.position = function (position) {
|
||||||
|
var _elem_height = $wrapper.parent().find('#datagrid').height(),
|
||||||
|
is_hidden, _position;
|
||||||
|
// We can not display editor partially visible so we will lift it above select column
|
||||||
|
if(position.top > _elem_height) {
|
||||||
|
is_hidden = position.bottom - _elem_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_hidden) {
|
||||||
|
_position = position.top - is_hidden;
|
||||||
|
} else {
|
||||||
|
_position = position.top - 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
$wrapper
|
||||||
|
.css("top", position.top - 5)
|
||||||
|
.css("left", position.left - 5)
|
||||||
|
};
|
||||||
|
|
||||||
|
this.destroy = function () {
|
||||||
|
$wrapper.remove();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.focus = function () {
|
||||||
|
$input.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.loadValue = function (item) {
|
||||||
|
var data = defaultValue = item[args.column.field];
|
||||||
|
if (typeof data === "object" && !Array.isArray(data)) {
|
||||||
|
data = JSON.stringify(data);
|
||||||
|
}
|
||||||
|
$input.val(data);
|
||||||
|
$input.select();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.serializeValue = function () {
|
||||||
|
return $input.val();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.applyValue = function (item, state) {
|
||||||
|
item[args.column.field] = state;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isValueChanged = function () {
|
||||||
|
return (!($input.val() == "" && defaultValue == null)) && ($input.val() != defaultValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.validate = function () {
|
||||||
|
if (args.column.validator) {
|
||||||
|
var validationResults = args.column.validator($input.val());
|
||||||
|
if (!validationResults.valid) {
|
||||||
|
return validationResults;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
msg: null
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
})(jQuery);
|
31
web/pgadmin/static/js/slickgrid/slick.pgadmin.formatters.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/***
|
||||||
|
* Contains pgAdmin4 related SlickGrid formatters.
|
||||||
|
*
|
||||||
|
* @module Formatters
|
||||||
|
* @namespace Slick
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function ($) {
|
||||||
|
// register namespace
|
||||||
|
$.extend(true, window, {
|
||||||
|
"Slick": {
|
||||||
|
"Formatters": {
|
||||||
|
"JsonString": JsonFormatter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function JsonFormatter(row, cell, value, columnDef, dataContext) {
|
||||||
|
if (value == null || value === "") {
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
// Stringify only if it's json object
|
||||||
|
if (typeof value === "object" && !Array.isArray(value)) {
|
||||||
|
return JSON.stringify(value);
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})(jQuery);
|
@ -44,6 +44,13 @@
|
|||||||
<link type="text/css" rel="stylesheet"
|
<link type="text/css" rel="stylesheet"
|
||||||
href="{{ url_for('static', filename='css/select2/select2.css' if config.DEBUG else 'css/select2/select2.min.css')}}"/>
|
href="{{ url_for('static', filename='css/select2/select2.css' if config.DEBUG else 'css/select2/select2.min.css')}}"/>
|
||||||
|
|
||||||
|
<link type="text/css" rel="stylesheet"
|
||||||
|
href="{{ url_for('static', filename='css/slickgrid/slick.grid.css')}}"/>
|
||||||
|
<link type="text/css" rel="stylesheet"
|
||||||
|
href="{{ url_for('static', filename='css/slickgrid/slick-default-theme.css')}}"/>
|
||||||
|
<link type="text/css" rel="stylesheet"
|
||||||
|
href="{{ url_for('static', filename='css/slickgrid/smoothness/jquery-ui-1.11.3.custom.css' if config.DEBUG else 'css/slickgrid/smoothness/jquery-ui-1.11.3.custom.min.css')}}"/>
|
||||||
|
|
||||||
<!-- View specified stylesheets -->
|
<!-- View specified stylesheets -->
|
||||||
{% for stylesheet in current_app.stylesheets %}
|
{% for stylesheet in current_app.stylesheets %}
|
||||||
<link type="text/css" rel="stylesheet" href="{{ stylesheet }}">
|
<link type="text/css" rel="stylesheet" href="{{ stylesheet }}">
|
||||||
@ -110,6 +117,17 @@
|
|||||||
"pgadmin.backform": {
|
"pgadmin.backform": {
|
||||||
"deps": ['backform', "pgadmin.backgrid", "select2"],
|
"deps": ['backform', "pgadmin.backgrid", "select2"],
|
||||||
},
|
},
|
||||||
|
"slickgrid": {
|
||||||
|
"deps": ['jquery', "jquery.ui", "jquery.event.drag", "slick.core",
|
||||||
|
"slick.cellrangedecorator", "slick.cellrangeselector",
|
||||||
|
"slick.cellselectionmodel", "slick.formatters",
|
||||||
|
"slick.pgadmin.formatters", "slick.editors",
|
||||||
|
"slick.pgadmin.editors", "slick.tooltip",
|
||||||
|
"slick.checkboxselectcolumn", "slick.cellcopymanager",
|
||||||
|
"slick.rowselectionmodel"
|
||||||
|
],
|
||||||
|
"exports": 'Slick'
|
||||||
|
},
|
||||||
"flotr2": {
|
"flotr2": {
|
||||||
deps: ['bean'],
|
deps: ['bean'],
|
||||||
exports: function(bean) {
|
exports: function(bean) {
|
||||||
@ -145,6 +163,21 @@
|
|||||||
"backbone.undo": "{{ url_for('static', filename='js/' + ('backbone.undo' if config.DEBUG else 'backbone.undo.min')) }}",
|
"backbone.undo": "{{ url_for('static', filename='js/' + ('backbone.undo' if config.DEBUG else 'backbone.undo.min')) }}",
|
||||||
"pgadmin.backgrid": "{{ url_for('static', filename='js/backgrid/backgrid.pgadmin') }}",
|
"pgadmin.backgrid": "{{ url_for('static', filename='js/backgrid/backgrid.pgadmin') }}",
|
||||||
'pgadmin.backform': "{{ url_for('static', filename='js/backform.pgadmin') }}",
|
'pgadmin.backform': "{{ url_for('static', filename='js/backform.pgadmin') }}",
|
||||||
|
"jquery.event.drag": "{{ url_for('static', filename='js/jquery-ui/jquery.event.drag-2.2') }}",
|
||||||
|
"slickgrid": "{{ url_for('static', filename='js/slickgrid/slick.grid') }}",
|
||||||
|
"slick.core": "{{ url_for('static', filename='js/slickgrid/slick.core') }}",
|
||||||
|
"slick.formatters": "{{ url_for('static', filename='js/slickgrid/slick.formatters') }}",
|
||||||
|
"slick.pgadmin.formatters": "{{ url_for('static', filename='js/slickgrid/slick.pgadmin.formatters') }}",
|
||||||
|
"slick.editors": "{{ url_for('static', filename='js/slickgrid/slick.editors') }}",
|
||||||
|
"slick.pgadmin.editors": "{{ url_for('static', filename='js/slickgrid/slick.pgadmin.editors') }}",
|
||||||
|
"jquery.ui": "{{ url_for('static', filename='js/jquery-ui/jquery-ui-1.11.3' if config.DEBUG else 'js/jquery-ui/jquery-ui-1.11.3.min') }}",
|
||||||
|
"slick.cellrangedecorator": "{{ url_for('static', filename='js/slickgrid/plugins/slick.cellrangedecorator') }}",
|
||||||
|
"slick.cellrangeselector": "{{ url_for('static', filename='js/slickgrid/plugins/slick.cellrangeselector') }}",
|
||||||
|
"slick.cellselectionmodel": "{{ url_for('static', filename='js/slickgrid/plugins/slick.cellselectionmodel') }}",
|
||||||
|
"slick.tooltip": "{{ url_for('static', filename='js/slickgrid/plugins/slick.autotooltips') }}",
|
||||||
|
"slick.checkboxselectcolumn": "{{ url_for('static', filename='js/slickgrid/plugins/slick.checkboxselectcolumn') }}",
|
||||||
|
"slick.cellcopymanager": "{{ url_for('static', filename='js/slickgrid/plugins/slick.cellcopymanager') }}",
|
||||||
|
"slick.rowselectionmodel": "{{ url_for('static', filename='js/slickgrid/plugins/slick.rowselectionmodel') }}",
|
||||||
bean :"{{ url_for('static', filename='js/flotr2/' + ('bean' if config.DEBUG else 'bean-min')) }}",
|
bean :"{{ url_for('static', filename='js/flotr2/' + ('bean' if config.DEBUG else 'bean-min')) }}",
|
||||||
flotr2 :"{{ url_for('static', filename='js/flotr2/flotr2.amd') }}"{% for script in current_app.javascripts %},
|
flotr2 :"{{ url_for('static', filename='js/flotr2/flotr2.amd') }}"{% for script in current_app.javascripts %},
|
||||||
'{{ script.name }}': "{{ script.path }}"{% endfor %}
|
'{{ script.name }}': "{{ script.path }}"{% endfor %}
|
||||||
|
@ -56,8 +56,8 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group" role="group" aria-label="">
|
<div class="btn-group" role="group" aria-label="">
|
||||||
<button id="btn-add-row" type="button" class="btn btn-default" title="{{ _('Add New Row') }}" disabled>
|
<button id="btn-delete-row" type="button" class="btn btn-default" title="{{ _('Delete Row(s)') }}" disabled>
|
||||||
<i class="fa fa-plus" aria-hidden="true"></i>
|
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group" role="group" aria-label="">
|
<div class="btn-group" role="group" aria-label="">
|
||||||
|
@ -416,6 +416,7 @@ class TableCommand(GridCommand):
|
|||||||
res = None
|
res = None
|
||||||
query_res = dict()
|
query_res = dict()
|
||||||
count = 0
|
count = 0
|
||||||
|
list_of_sql = []
|
||||||
|
|
||||||
if conn.connected():
|
if conn.connected():
|
||||||
|
|
||||||
@ -423,45 +424,70 @@ class TableCommand(GridCommand):
|
|||||||
conn.execute_void('BEGIN;')
|
conn.execute_void('BEGIN;')
|
||||||
|
|
||||||
# Iterate total number of records to be updated/inserted
|
# Iterate total number of records to be updated/inserted
|
||||||
for row in changed_data:
|
for of_type in changed_data:
|
||||||
|
|
||||||
# if no data to be saved then continue
|
# if no data to be saved then continue
|
||||||
if 'data' not in row:
|
if len(changed_data[of_type]) < 1:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# if 'keys' is present in row then it is and update query
|
# For newly added rows
|
||||||
# else it is an insert query.
|
if of_type == 'added':
|
||||||
if 'keys' in row:
|
for each_row in changed_data[of_type]:
|
||||||
# if 'marked_for_deletion' is present in row and it is true then delete
|
data = changed_data[of_type][each_row]['data']
|
||||||
if 'marked_for_deletion' in row and row['marked_for_deletion']:
|
data_type = changed_data[of_type][each_row]['data_type']
|
||||||
|
# Remove our unique tracking key
|
||||||
|
data.pop('__temp_PK', None)
|
||||||
|
sql = render_template("/".join([self.sql_path, 'insert.sql']),
|
||||||
|
data_to_be_saved=data,
|
||||||
|
primary_keys=None,
|
||||||
|
object_name=self.object_name,
|
||||||
|
nsp_name=self.nsp_name,
|
||||||
|
data_type=data_type)
|
||||||
|
list_of_sql.append(sql)
|
||||||
|
|
||||||
|
# For updated rows
|
||||||
|
elif of_type == 'updated':
|
||||||
|
for each_row in changed_data[of_type]:
|
||||||
|
data = changed_data[of_type][each_row]['data']
|
||||||
|
pk = changed_data[of_type][each_row]['primary_keys']
|
||||||
|
data_type = changed_data[of_type][each_row]['data_type']
|
||||||
|
sql = render_template("/".join([self.sql_path, 'update.sql']),
|
||||||
|
data_to_be_saved=data,
|
||||||
|
primary_keys=pk,
|
||||||
|
object_name=self.object_name,
|
||||||
|
nsp_name=self.nsp_name,
|
||||||
|
data_type=data_type)
|
||||||
|
list_of_sql.append(sql)
|
||||||
|
|
||||||
|
# For deleted rows
|
||||||
|
elif of_type == 'deleted':
|
||||||
|
for each_row in changed_data[of_type]:
|
||||||
|
data = changed_data[of_type][each_row]
|
||||||
sql = render_template("/".join([self.sql_path, 'delete.sql']),
|
sql = render_template("/".join([self.sql_path, 'delete.sql']),
|
||||||
primary_keys=row['keys'], object_name=self.object_name,
|
data=data,
|
||||||
|
object_name=self.object_name,
|
||||||
nsp_name=self.nsp_name)
|
nsp_name=self.nsp_name)
|
||||||
else:
|
list_of_sql.append(sql)
|
||||||
sql = render_template("/".join([self.sql_path, 'update.sql']), object_name=self.object_name,
|
|
||||||
data_to_be_saved=row['data'], primary_keys=row['keys'],
|
|
||||||
nsp_name=self.nsp_name)
|
|
||||||
else:
|
|
||||||
sql = render_template("/".join([self.sql_path, 'insert.sql']), object_name=self.object_name,
|
|
||||||
data_to_be_saved=row['data'], nsp_name=self.nsp_name)
|
|
||||||
|
|
||||||
status, res = conn.execute_void(sql)
|
for sql in list_of_sql:
|
||||||
rows_affected = conn.rows_affected()
|
if sql:
|
||||||
|
status, res = conn.execute_void(sql)
|
||||||
|
rows_affected = conn.rows_affected()
|
||||||
|
|
||||||
# store the result of each query in dictionary
|
# store the result of each query in dictionary
|
||||||
query_res[count] = {'status': status, 'result': res,
|
query_res[count] = {'status': status, 'result': res,
|
||||||
'sql': sql, 'rows_affected': rows_affected}
|
'sql': sql, 'rows_affected': rows_affected}
|
||||||
count += 1
|
count += 1
|
||||||
|
|
||||||
if not status:
|
if not status:
|
||||||
conn.execute_void('ROLLBACK;')
|
conn.execute_void('ROLLBACK;')
|
||||||
# If we roll backed every thing then update the message for
|
# If we roll backed every thing then update the message for
|
||||||
# each sql query.
|
# each sql query.
|
||||||
for val in query_res:
|
for val in query_res:
|
||||||
if query_res[val]['status']:
|
if query_res[val]['status']:
|
||||||
query_res[val]['result'] = 'Transaction ROLLBACK'
|
query_res[val]['result'] = 'Transaction ROLLBACK'
|
||||||
|
|
||||||
return status, res, query_res
|
return status, res, query_res
|
||||||
|
|
||||||
# Commit the transaction if there is no error found
|
# Commit the transaction if there is no error found
|
||||||
conn.execute_void('COMMIT;')
|
conn.execute_void('COMMIT;')
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sql-editor-grid-container {
|
.sql-editor-grid-container {
|
||||||
height: calc(100% - 45px);
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,63 +49,6 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#datagrid-paginator {
|
|
||||||
bottom: 0px;
|
|
||||||
width: 100%;
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Move he original checkbox out of the way */
|
|
||||||
#datagrid .select-row-cell .sqleditor-checkbox {
|
|
||||||
position: absolute;
|
|
||||||
left: -9999px;
|
|
||||||
}
|
|
||||||
/*Align the icon and the label.deletable text to same height using tabl-cell display*/
|
|
||||||
/*If you change the font-size of the text, you may also want to do som padding or alignhment changes here*/
|
|
||||||
#datagrid .sqleditor-checkbox ~ label.deletable > span {
|
|
||||||
display: table-cell;
|
|
||||||
vertical-align: middle;
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
/*The label.deletable will contain the icon and the text, will grab the focus*/
|
|
||||||
#datagrid .select-row-cell .sqleditor-checkbox + label.deletable {
|
|
||||||
cursor: pointer;
|
|
||||||
display: table;
|
|
||||||
}
|
|
||||||
/*The icon container, set it to fixed size and font size, the padding is to align the border*/
|
|
||||||
/*If you change the font-size of this icon, be sure to adjust the min-width as well*/
|
|
||||||
#datagrid .select-row-cell .sqleditor-checkbox + label.deletable:before {
|
|
||||||
font-family: 'FontAwesome';
|
|
||||||
font-size: small;
|
|
||||||
font-weight: normal;
|
|
||||||
display: inline-block;
|
|
||||||
min-width: 28px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* toggle font awesome icon*/
|
|
||||||
#datagrid .select-row-cell .sqleditor-checkbox:checked + label:before {
|
|
||||||
content: "\f014";
|
|
||||||
}
|
|
||||||
|
|
||||||
#datagrid .select-row-cell .sqleditor-checkbox:not(:checked) + label:before {
|
|
||||||
content: "\f014";
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Do something on focus, in this case show dashed border*/
|
|
||||||
#datagrid .select-row-cell .sqleditor-checkbox:focus + label:before {
|
|
||||||
border: 1px dashed #777;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Do something on hover, in this case change the image color*/
|
|
||||||
#datagrid .select-row-cell .sqleditor-checkbox:hover + label:before {
|
|
||||||
color: #67afe5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pgadmin-row-deleted td {
|
|
||||||
color: red !important;
|
|
||||||
text-decoration: line-through;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-container {
|
.filter-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
@ -283,3 +226,161 @@ li.CodeMirror-hint-active {
|
|||||||
.CodeMirror-hint .fa::before {
|
.CodeMirror-hint .fa::before {
|
||||||
padding-right: 7px;
|
padding-right: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 10pt;
|
||||||
|
border-bottom: 1px dotted gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin-left: 0;
|
||||||
|
padding: 0;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
background: url("../images/arrow_right_spearmint.png") no-repeat center left;
|
||||||
|
padding: 0 0 0 0px;
|
||||||
|
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#datagrid {
|
||||||
|
background: white;
|
||||||
|
outline: 0;
|
||||||
|
border: 1px solid gray;
|
||||||
|
font-size: 9pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-header-column.ui-state-default {
|
||||||
|
height: 40px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#datagrid .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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Slick.Editors.Text, Slick.Editors.Date */
|
||||||
|
#datagrid .slick-header > input.editor-text {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
background: transparent;
|
||||||
|
outline: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Slick.Editors.Checkbox */
|
||||||
|
#datagrid .slick-header > input.editor-checkbox {
|
||||||
|
margin: 0;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell-selection {
|
||||||
|
border-right-color: silver;
|
||||||
|
border-right-style: solid;
|
||||||
|
background: #f5f5f5;
|
||||||
|
color: gray;
|
||||||
|
text-align: right;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-row.selected .cell-selection {
|
||||||
|
background-color: transparent; /* show default selected row background */
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-cell-checkboxsel {
|
||||||
|
background: #f0f0f0;
|
||||||
|
border-right-color: silver;
|
||||||
|
border-right-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
#datagrid .slick-header .ui-state-default,
|
||||||
|
#datagrid .slick-header .ui-widget-content.ui-state-default,
|
||||||
|
#datagrid .slick-header .ui-widget-header .ui-state-default {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#datagrid .slick-header .slick-header-columns {
|
||||||
|
background: #2c76b4;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#datagrid .slick-header .slick-header-column.ui-state-default {
|
||||||
|
color: #fff;
|
||||||
|
padding: 4px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.long_text_editor {
|
||||||
|
margin-left: 5px;
|
||||||
|
font-size: 12px !important;
|
||||||
|
padding: 1px 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Slick.Editors.Text, Slick.Editors.Date */
|
||||||
|
input.editor-text {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
background: transparent;
|
||||||
|
outline: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Slick.Editors.Text, Slick.Editors.Date */
|
||||||
|
textarea.editor-text {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
background: transparent;
|
||||||
|
outline: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Override selected row color */
|
||||||
|
.slick-cell.selected {
|
||||||
|
background-color: #eeeeee !important;
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{# Delete the row with primary keys (specified in primary_keys) #}
|
{# Delete the row with primary keys #}
|
||||||
DELETE FROM {{ conn|qtIdent(nsp_name, object_name) }} WHERE
|
DELETE FROM {{ conn|qtIdent(nsp_name, object_name) }} WHERE
|
||||||
{% for pk in primary_keys %}
|
{% for pk_key in data %}
|
||||||
{% if not loop.first %} AND {% endif %}{{ conn|qtIdent(pk) }} = {{ primary_keys[pk]|qtLiteral }}{% endfor %};
|
{% if not loop.first %} AND {% endif %}{{ conn|qtIdent(pk_key) }} = {{ data[pk_key]|qtLiteral }}{% endfor %};
|
@ -4,5 +4,13 @@ INSERT INTO {{ conn|qtIdent(nsp_name, object_name) }} (
|
|||||||
{% if not loop.first %}, {% endif %}{{ conn|qtIdent(col) }}{% endfor %}
|
{% if not loop.first %}, {% endif %}{{ conn|qtIdent(col) }}{% endfor %}
|
||||||
) VALUES (
|
) VALUES (
|
||||||
{% for col in data_to_be_saved %}
|
{% for col in data_to_be_saved %}
|
||||||
{% if not loop.first %}, {% endif %}{{ data_to_be_saved[col]|qtLiteral }}{% endfor %}
|
{########################################################}
|
||||||
|
{# THIS IS TO CHECK IF DATA TYPE IS ARRAY? #}
|
||||||
|
{% if data_type[col].endswith('[]') %}
|
||||||
|
{% set col_value = "{%s}"|format(data_to_be_saved[col])|qtLiteral %}
|
||||||
|
{% else %}
|
||||||
|
{% set col_value = data_to_be_saved[col]|qtLiteral %}
|
||||||
|
{% endif %}
|
||||||
|
{########################################################}
|
||||||
|
{% if not loop.first %}, {% endif %}{{ col_value }}::{{data_type[col]}}{% endfor %}
|
||||||
);
|
);
|
@ -1,7 +1,15 @@
|
|||||||
{# Update the row with primary keys (specified in primary_keys) #}
|
{# Update the row with primary keys (specified in primary_keys) #}
|
||||||
UPDATE {{ conn|qtIdent(nsp_name, object_name) }} SET
|
UPDATE {{ conn|qtIdent(nsp_name, object_name) }} SET
|
||||||
{% for col in data_to_be_saved %}
|
{% for col in data_to_be_saved %}
|
||||||
{% if not loop.first %}, {% endif %}{{ conn|qtIdent(col) }} = {{ data_to_be_saved[col]|qtLiteral }}{% endfor %}
|
{########################################################}
|
||||||
|
{# THIS IS TO CHECK IF DATA TYPE IS ARRAY? #}
|
||||||
|
{% if data_type[col].endswith('[]') %}
|
||||||
|
{% set col_value = "{%s}"|format(data_to_be_saved[col])|qtLiteral %}
|
||||||
|
{% else %}
|
||||||
|
{% set col_value = data_to_be_saved[col]|qtLiteral %}
|
||||||
|
{% endif %}
|
||||||
|
{########################################################}
|
||||||
|
{% if not loop.first %}, {% endif %}{{ conn|qtIdent(col) }} = {{ col_value }}::{{data_type[col]}}{% endfor %}
|
||||||
WHERE
|
WHERE
|
||||||
{% for pk in primary_keys %}
|
{% for pk in primary_keys %}
|
||||||
{% if not loop.first %} AND {% endif %}{{ conn|qtIdent(pk) }} = {{ primary_keys[pk]|qtLiteral }}{% endfor %};
|
{% if not loop.first %} AND {% endif %}{{ conn|qtIdent(pk) }} = {{ primary_keys[pk]|qtLiteral }}{% endfor %};
|