smartkiosk-server 0.12.1 → 0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.ruby-version +1 -1
- data/Gemfile +9 -6
- data/Gemfile.lock +36 -9
- data/app/assets/images/sort-asc.png +0 -0
- data/app/assets/images/sort-desc.png +0 -0
- data/app/assets/javascripts/application.js +1 -1
- data/app/assets/javascripts/monitoring.js.coffee +25 -0
- data/app/assets/javascripts/monitoring/helpers/application.js.coffee +12 -0
- data/app/assets/javascripts/monitoring/layouts/application.js.coffee +2 -0
- data/app/assets/javascripts/monitoring/pages/application.js.coffee +1 -0
- data/app/assets/javascripts/monitoring/pages/welcome/index.js.coffee +229 -0
- data/app/assets/javascripts/monitoring/resources/.gitkeep +0 -0
- data/app/assets/javascripts/monitoring/routes.js.coffee +8 -0
- data/app/assets/javascripts/monitoring/templates/layouts/.gitkeep +0 -0
- data/app/assets/javascripts/monitoring/templates/layouts/application.jst.hamlc +1 -0
- data/app/assets/javascripts/monitoring/templates/pages/welcome/_row.jst.hamlc +28 -0
- data/app/assets/javascripts/monitoring/templates/pages/welcome/_tbody.jst.hamlc +3 -0
- data/app/assets/javascripts/monitoring/templates/pages/welcome/index.jst.hamlc +37 -0
- data/app/assets/javascripts/monitoring/templates/widgets/.gitkeep +0 -0
- data/app/assets/javascripts/monitoring/widgets/.gitkeep +0 -0
- data/app/assets/javascripts/monitoring_preloader.js.coffee.erb +17 -0
- data/app/assets/stylesheets/active_admin.css.scss +4 -4
- data/app/assets/stylesheets/{fonts.css.scss → active_admin/fonts.css.scss} +0 -0
- data/app/assets/stylesheets/active_admin/provider_groups.css.scss +12 -0
- data/app/assets/stylesheets/{provider_receipt_templates.css.scss → active_admin/provider_receipt_templates.css.scss} +0 -0
- data/app/assets/stylesheets/{terminals.css.scss → active_admin/terminals.css.scss} +0 -0
- data/app/assets/stylesheets/monitoring.css.scss +4 -0
- data/app/assets/stylesheets/monitoring/bootstrap.css +9 -0
- data/app/assets/stylesheets/monitoring/theme.css.scss +35 -0
- data/app/controllers/monitoring_controller.rb +31 -0
- data/app/controllers/payments_controller.rb +1 -1
- data/app/controllers/terminal_builds_controller.rb +2 -0
- data/app/controllers/welcome_controller.rb +5 -2
- data/app/models/ability.rb +6 -4
- data/app/models/agent.rb +6 -0
- data/app/models/collection.rb +2 -2
- data/app/models/payment.rb +3 -3
- data/app/models/provider_gateway.rb +1 -1
- data/app/models/report_result.rb +1 -1
- data/app/models/report_template.rb +3 -3
- data/app/models/role.rb +51 -10
- data/app/models/terminal.rb +25 -1
- data/app/models/terminal_build.rb +1 -1
- data/app/models/terminal_order.rb +1 -1
- data/app/models/terminal_ping.rb +3 -0
- data/app/models/terminal_profile.rb +6 -0
- data/app/models/user_role.rb +1 -1
- data/app/views/monitoring/index.html.erb +28 -0
- data/config.ru +7 -0
- data/config/deploy.rb +1 -1
- data/config/environments/development.rb +2 -0
- data/config/environments/production.rb +1 -1
- data/config/initializers/monitoring.rb +3 -0
- data/config/initializers/redis.rb +1 -1
- data/config/locales/activerecord.ru.yml +14 -0
- data/config/locales/smartkiosk.ru.yml +38 -0
- data/config/routes.rb +1 -1
- data/db/migrate/20130419125334_add_ping_to_terminals.rb +22 -0
- data/db/schema.rb +25 -7
- data/lib/blueprints.rb +2 -0
- data/lib/monitorer.rb +41 -0
- data/lib/seeder.rb +1 -1
- data/lib/smartkiosk/server/version.rb +1 -1
- data/vendor/assets/javascripts/chosen.jquery.js +1 -1
- data/vendor/assets/javascripts/cookie.jquery.js +95 -0
- data/vendor/assets/javascripts/copypaste.js +148 -0
- data/vendor/assets/javascripts/event-drag.jquery.js +402 -0
- data/vendor/assets/javascripts/sheetclip.js +87 -0
- data/vendor/assets/javascripts/slick.cellrangedecorator.js +64 -0
- data/vendor/assets/javascripts/slick.cellrangeselector.js +111 -0
- data/vendor/assets/javascripts/slick.cellselectionmodel.js +152 -0
- data/vendor/assets/javascripts/slick.core.js +458 -0
- data/vendor/assets/javascripts/slick.grid.js +3287 -0
- data/vendor/assets/stylesheets/slick.grid.css +167 -0
- metadata +42 -9
- data/app/assets/stylesheets/provider_groups.css.scss +0 -12
- data/app/views/layouts/application.html.erb +0 -1
- data/app/views/welcome/index.html.erb +0 -25
@@ -142,7 +142,7 @@ Copyright (c) 2011 by Harvest
|
|
142
142
|
} else if (this.is_multiple) {
|
143
143
|
this.default_text = this.options.placeholder_text_multiple || this.options.placeholder_text || "Select Some Options";
|
144
144
|
} else {
|
145
|
-
this.default_text = this.options.placeholder_text_single || this.options.placeholder_text || "
|
145
|
+
this.default_text = this.options.placeholder_text_single || this.options.placeholder_text || "Select";
|
146
146
|
}
|
147
147
|
return this.results_none_found = this.form_field.getAttribute("data-no_results_text") || this.options.no_results_text || "No results match";
|
148
148
|
};
|
@@ -0,0 +1,95 @@
|
|
1
|
+
/*!
|
2
|
+
* jQuery Cookie Plugin v1.3.1
|
3
|
+
* https://github.com/carhartl/jquery-cookie
|
4
|
+
*
|
5
|
+
* Copyright 2013 Klaus Hartl
|
6
|
+
* Released under the MIT license
|
7
|
+
*/
|
8
|
+
(function (factory) {
|
9
|
+
if (typeof define === 'function' && define.amd) {
|
10
|
+
// AMD. Register as anonymous module.
|
11
|
+
define(['jquery'], factory);
|
12
|
+
} else {
|
13
|
+
// Browser globals.
|
14
|
+
factory(jQuery);
|
15
|
+
}
|
16
|
+
}(function ($) {
|
17
|
+
|
18
|
+
var pluses = /\+/g;
|
19
|
+
|
20
|
+
function raw(s) {
|
21
|
+
return s;
|
22
|
+
}
|
23
|
+
|
24
|
+
function decoded(s) {
|
25
|
+
return decodeURIComponent(s.replace(pluses, ' '));
|
26
|
+
}
|
27
|
+
|
28
|
+
function converted(s) {
|
29
|
+
if (s.indexOf('"') === 0) {
|
30
|
+
// This is a quoted cookie as according to RFC2068, unescape
|
31
|
+
s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
|
32
|
+
}
|
33
|
+
try {
|
34
|
+
return config.json ? JSON.parse(s) : s;
|
35
|
+
} catch(er) {}
|
36
|
+
}
|
37
|
+
|
38
|
+
var config = $.cookie = function (key, value, options) {
|
39
|
+
|
40
|
+
// write
|
41
|
+
if (value !== undefined) {
|
42
|
+
options = $.extend({}, config.defaults, options);
|
43
|
+
|
44
|
+
if (typeof options.expires === 'number') {
|
45
|
+
var days = options.expires, t = options.expires = new Date();
|
46
|
+
t.setDate(t.getDate() + days);
|
47
|
+
}
|
48
|
+
|
49
|
+
value = config.json ? JSON.stringify(value) : String(value);
|
50
|
+
|
51
|
+
return (document.cookie = [
|
52
|
+
config.raw ? key : encodeURIComponent(key),
|
53
|
+
'=',
|
54
|
+
config.raw ? value : encodeURIComponent(value),
|
55
|
+
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
|
56
|
+
options.path ? '; path=' + options.path : '',
|
57
|
+
options.domain ? '; domain=' + options.domain : '',
|
58
|
+
options.secure ? '; secure' : ''
|
59
|
+
].join(''));
|
60
|
+
}
|
61
|
+
|
62
|
+
// read
|
63
|
+
var decode = config.raw ? raw : decoded;
|
64
|
+
var cookies = document.cookie.split('; ');
|
65
|
+
var result = key ? undefined : {};
|
66
|
+
for (var i = 0, l = cookies.length; i < l; i++) {
|
67
|
+
var parts = cookies[i].split('=');
|
68
|
+
var name = decode(parts.shift());
|
69
|
+
var cookie = decode(parts.join('='));
|
70
|
+
|
71
|
+
if (key && key === name) {
|
72
|
+
result = converted(cookie);
|
73
|
+
break;
|
74
|
+
}
|
75
|
+
|
76
|
+
if (!key) {
|
77
|
+
result[name] = converted(cookie);
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
return result;
|
82
|
+
};
|
83
|
+
|
84
|
+
config.defaults = {};
|
85
|
+
|
86
|
+
$.removeCookie = function (key, options) {
|
87
|
+
if ($.cookie(key) !== undefined) {
|
88
|
+
// Must not alter options, thus extending a fresh object...
|
89
|
+
$.cookie(key, '', $.extend({}, options, { expires: -1 }));
|
90
|
+
return true;
|
91
|
+
}
|
92
|
+
return false;
|
93
|
+
};
|
94
|
+
|
95
|
+
}));
|
@@ -0,0 +1,148 @@
|
|
1
|
+
/**
|
2
|
+
* CopyPaste.js
|
3
|
+
* Creates a textarea that stays hidden on the page and gets focused when user presses CTRL while not having a form input focused
|
4
|
+
* In future we may implement a better driver when better APIs are available
|
5
|
+
* @constructor
|
6
|
+
*/
|
7
|
+
function CopyPaste(listenerElement) {
|
8
|
+
var that = this
|
9
|
+
, style;
|
10
|
+
listenerElement = listenerElement || document.body;
|
11
|
+
|
12
|
+
this.disabled = false;
|
13
|
+
this.elDiv = document.createElement('DIV');
|
14
|
+
style = this.elDiv.style;
|
15
|
+
style.position = 'fixed';
|
16
|
+
style.top = 0;
|
17
|
+
style.left = 0;
|
18
|
+
listenerElement.appendChild(this.elDiv);
|
19
|
+
|
20
|
+
this.elTextarea = document.createElement('TEXTAREA');
|
21
|
+
this.elTextarea.className = 'copyPaste';
|
22
|
+
style = this.elTextarea.style;
|
23
|
+
style.width = '1px';
|
24
|
+
style.height = '1px';
|
25
|
+
this.elDiv.appendChild(this.elTextarea);
|
26
|
+
|
27
|
+
if (typeof style.opacity !== 'undefined') {
|
28
|
+
style.opacity = 0;
|
29
|
+
}
|
30
|
+
else {
|
31
|
+
/*@cc_on @if (@_jscript)
|
32
|
+
if(typeof style.filter === 'string') {
|
33
|
+
style.filter = 'alpha(opacity=0)';
|
34
|
+
}
|
35
|
+
@end @*/
|
36
|
+
}
|
37
|
+
|
38
|
+
this._bindEvent(listenerElement, 'keydown', function (event) {
|
39
|
+
if (that.disabled) {
|
40
|
+
return true;
|
41
|
+
}
|
42
|
+
var isCtrlDown = false;
|
43
|
+
if (event.metaKey) { //mac
|
44
|
+
isCtrlDown = true;
|
45
|
+
}
|
46
|
+
else if (event.ctrlKey && navigator.userAgent.indexOf('Mac') === -1) { //pc
|
47
|
+
isCtrlDown = true;
|
48
|
+
}
|
49
|
+
|
50
|
+
if (isCtrlDown && !(event.keyCode === 67 || event.keyCode === 86 || event.keyCode === 88)) {
|
51
|
+
if (that.prepareCallback) {
|
52
|
+
that.copyable(that.prepareCallback(event));
|
53
|
+
}
|
54
|
+
|
55
|
+
that.selectNodeText(that.elTextarea);
|
56
|
+
setTimeout(function () {
|
57
|
+
that.selectNodeText(that.elTextarea);
|
58
|
+
}, 0);
|
59
|
+
}
|
60
|
+
|
61
|
+
/* 67 = c
|
62
|
+
* 86 = v
|
63
|
+
* 88 = x
|
64
|
+
*/
|
65
|
+
if (isCtrlDown && (event.keyCode === 67 || event.keyCode === 86 || event.keyCode === 88)) {
|
66
|
+
// that.selectNodeText(that.elTextarea);
|
67
|
+
|
68
|
+
if (event.keyCode === 88) { //works in all browsers, incl. Opera < 12.12
|
69
|
+
setTimeout(function () {
|
70
|
+
that.triggerCut(event);
|
71
|
+
}, 0);
|
72
|
+
}
|
73
|
+
else if (event.keyCode === 86) {
|
74
|
+
setTimeout(function () {
|
75
|
+
that.triggerPaste(event);
|
76
|
+
}, 0);
|
77
|
+
}
|
78
|
+
}
|
79
|
+
});
|
80
|
+
}
|
81
|
+
|
82
|
+
//http://jsperf.com/textara-selection
|
83
|
+
//http://stackoverflow.com/questions/1502385/how-can-i-make-this-code-work-in-ie
|
84
|
+
CopyPaste.prototype.selectNodeText = function (el) {
|
85
|
+
el.select();
|
86
|
+
};
|
87
|
+
|
88
|
+
CopyPaste.prototype.copyable = function (str) {
|
89
|
+
if (typeof str !== 'string' && str.toString === void 0) {
|
90
|
+
throw new Error('copyable requires string parameter');
|
91
|
+
}
|
92
|
+
this.elTextarea.value = str;
|
93
|
+
};
|
94
|
+
|
95
|
+
CopyPaste.prototype.prepare = function (fn) {
|
96
|
+
this.prepareCallback = fn;
|
97
|
+
}
|
98
|
+
|
99
|
+
CopyPaste.prototype.onCopy = function (fn) {
|
100
|
+
this.copyCallback = fn;
|
101
|
+
};
|
102
|
+
|
103
|
+
CopyPaste.prototype.onCut = function (fn) {
|
104
|
+
this.cutCallback = fn;
|
105
|
+
};
|
106
|
+
|
107
|
+
CopyPaste.prototype.onPaste = function (fn) {
|
108
|
+
this.pasteCallback = fn;
|
109
|
+
};
|
110
|
+
|
111
|
+
CopyPaste.prototype.triggerCut = function (event) {
|
112
|
+
var that = this;
|
113
|
+
if (that.cutCallback) {
|
114
|
+
setTimeout(function () {
|
115
|
+
that.cutCallback(event);
|
116
|
+
}, 0);
|
117
|
+
}
|
118
|
+
};
|
119
|
+
|
120
|
+
CopyPaste.prototype.triggerPaste = function (event, str) {
|
121
|
+
var that = this;
|
122
|
+
if (that.pasteCallback) {
|
123
|
+
setTimeout(function () {
|
124
|
+
that.pasteCallback((str || that.elTextarea.value).replace(/\n$/, ''), event); //remove trailing newline
|
125
|
+
}, 0);
|
126
|
+
}
|
127
|
+
};
|
128
|
+
|
129
|
+
//http://net.tutsplus.com/tutorials/javascript-ajax/javascript-from-null-cross-browser-event-binding/
|
130
|
+
//http://stackoverflow.com/questions/4643249/cross-browser-event-object-normalization
|
131
|
+
CopyPaste.prototype._bindEvent = (function () {
|
132
|
+
if (document.addEventListener) {
|
133
|
+
return function (elem, type, cb) {
|
134
|
+
elem.addEventListener(type, cb, false);
|
135
|
+
};
|
136
|
+
}
|
137
|
+
else {
|
138
|
+
return function (elem, type, cb) {
|
139
|
+
elem.attachEvent('on' + type, function () {
|
140
|
+
var e = window['event'];
|
141
|
+
e.target = e.srcElement;
|
142
|
+
e.relatedTarget = e.relatedTarget || e.type == 'mouseover' ? e.fromElement : e.toElement;
|
143
|
+
if (e.target.nodeType === 3) e.target = e.target.parentNode; //Safari bug
|
144
|
+
return cb.call(elem, e)
|
145
|
+
});
|
146
|
+
};
|
147
|
+
}
|
148
|
+
})();
|
@@ -0,0 +1,402 @@
|
|
1
|
+
/*!
|
2
|
+
* jquery.event.drag - v 2.2
|
3
|
+
* Copyright (c) 2010 Three Dub Media - http://threedubmedia.com
|
4
|
+
* Open Source MIT License - http://threedubmedia.com/code/license
|
5
|
+
*/
|
6
|
+
// Created: 2008-06-04
|
7
|
+
// Updated: 2012-05-21
|
8
|
+
// REQUIRES: jquery 1.7.x
|
9
|
+
|
10
|
+
;(function( $ ){
|
11
|
+
|
12
|
+
// add the jquery instance method
|
13
|
+
$.fn.drag = function( str, arg, opts ){
|
14
|
+
// figure out the event type
|
15
|
+
var type = typeof str == "string" ? str : "",
|
16
|
+
// figure out the event handler...
|
17
|
+
fn = $.isFunction( str ) ? str : $.isFunction( arg ) ? arg : null;
|
18
|
+
// fix the event type
|
19
|
+
if ( type.indexOf("drag") !== 0 )
|
20
|
+
type = "drag"+ type;
|
21
|
+
// were options passed
|
22
|
+
opts = ( str == fn ? arg : opts ) || {};
|
23
|
+
// trigger or bind event handler
|
24
|
+
return fn ? this.bind( type, opts, fn ) : this.trigger( type );
|
25
|
+
};
|
26
|
+
|
27
|
+
// local refs (increase compression)
|
28
|
+
var $event = $.event,
|
29
|
+
$special = $event.special,
|
30
|
+
// configure the drag special event
|
31
|
+
drag = $special.drag = {
|
32
|
+
|
33
|
+
// these are the default settings
|
34
|
+
defaults: {
|
35
|
+
which: 1, // mouse button pressed to start drag sequence
|
36
|
+
distance: 0, // distance dragged before dragstart
|
37
|
+
not: ':input', // selector to suppress dragging on target elements
|
38
|
+
handle: null, // selector to match handle target elements
|
39
|
+
relative: false, // true to use "position", false to use "offset"
|
40
|
+
drop: true, // false to suppress drop events, true or selector to allow
|
41
|
+
click: false // false to suppress click events after dragend (no proxy)
|
42
|
+
},
|
43
|
+
|
44
|
+
// the key name for stored drag data
|
45
|
+
datakey: "dragdata",
|
46
|
+
|
47
|
+
// prevent bubbling for better performance
|
48
|
+
noBubble: true,
|
49
|
+
|
50
|
+
// count bound related events
|
51
|
+
add: function( obj ){
|
52
|
+
// read the interaction data
|
53
|
+
var data = $.data( this, drag.datakey ),
|
54
|
+
// read any passed options
|
55
|
+
opts = obj.data || {};
|
56
|
+
// count another realted event
|
57
|
+
data.related += 1;
|
58
|
+
// extend data options bound with this event
|
59
|
+
// don't iterate "opts" in case it is a node
|
60
|
+
$.each( drag.defaults, function( key, def ){
|
61
|
+
if ( opts[ key ] !== undefined )
|
62
|
+
data[ key ] = opts[ key ];
|
63
|
+
});
|
64
|
+
},
|
65
|
+
|
66
|
+
// forget unbound related events
|
67
|
+
remove: function(){
|
68
|
+
$.data( this, drag.datakey ).related -= 1;
|
69
|
+
},
|
70
|
+
|
71
|
+
// configure interaction, capture settings
|
72
|
+
setup: function(){
|
73
|
+
// check for related events
|
74
|
+
if ( $.data( this, drag.datakey ) )
|
75
|
+
return;
|
76
|
+
// initialize the drag data with copied defaults
|
77
|
+
var data = $.extend({ related:0 }, drag.defaults );
|
78
|
+
// store the interaction data
|
79
|
+
$.data( this, drag.datakey, data );
|
80
|
+
// bind the mousedown event, which starts drag interactions
|
81
|
+
$event.add( this, "touchstart mousedown", drag.init, data );
|
82
|
+
// prevent image dragging in IE...
|
83
|
+
if ( this.attachEvent )
|
84
|
+
this.attachEvent("ondragstart", drag.dontstart );
|
85
|
+
},
|
86
|
+
|
87
|
+
// destroy configured interaction
|
88
|
+
teardown: function(){
|
89
|
+
var data = $.data( this, drag.datakey ) || {};
|
90
|
+
// check for related events
|
91
|
+
if ( data.related )
|
92
|
+
return;
|
93
|
+
// remove the stored data
|
94
|
+
$.removeData( this, drag.datakey );
|
95
|
+
// remove the mousedown event
|
96
|
+
$event.remove( this, "touchstart mousedown", drag.init );
|
97
|
+
// enable text selection
|
98
|
+
drag.textselect( true );
|
99
|
+
// un-prevent image dragging in IE...
|
100
|
+
if ( this.detachEvent )
|
101
|
+
this.detachEvent("ondragstart", drag.dontstart );
|
102
|
+
},
|
103
|
+
|
104
|
+
// initialize the interaction
|
105
|
+
init: function( event ){
|
106
|
+
// sorry, only one touch at a time
|
107
|
+
if ( drag.touched )
|
108
|
+
return;
|
109
|
+
// the drag/drop interaction data
|
110
|
+
var dd = event.data, results;
|
111
|
+
// check the which directive
|
112
|
+
if ( event.which != 0 && dd.which > 0 && event.which != dd.which )
|
113
|
+
return;
|
114
|
+
// check for suppressed selector
|
115
|
+
if ( $( event.target ).is( dd.not ) )
|
116
|
+
return;
|
117
|
+
// check for handle selector
|
118
|
+
if ( dd.handle && !$( event.target ).closest( dd.handle, event.currentTarget ).length )
|
119
|
+
return;
|
120
|
+
|
121
|
+
drag.touched = event.type == 'touchstart' ? this : null;
|
122
|
+
dd.propagates = 1;
|
123
|
+
dd.mousedown = this;
|
124
|
+
dd.interactions = [ drag.interaction( this, dd ) ];
|
125
|
+
dd.target = event.target;
|
126
|
+
dd.pageX = event.pageX;
|
127
|
+
dd.pageY = event.pageY;
|
128
|
+
dd.dragging = null;
|
129
|
+
// handle draginit event...
|
130
|
+
results = drag.hijack( event, "draginit", dd );
|
131
|
+
// early cancel
|
132
|
+
if ( !dd.propagates )
|
133
|
+
return;
|
134
|
+
// flatten the result set
|
135
|
+
results = drag.flatten( results );
|
136
|
+
// insert new interaction elements
|
137
|
+
if ( results && results.length ){
|
138
|
+
dd.interactions = [];
|
139
|
+
$.each( results, function(){
|
140
|
+
dd.interactions.push( drag.interaction( this, dd ) );
|
141
|
+
});
|
142
|
+
}
|
143
|
+
// remember how many interactions are propagating
|
144
|
+
dd.propagates = dd.interactions.length;
|
145
|
+
// locate and init the drop targets
|
146
|
+
if ( dd.drop !== false && $special.drop )
|
147
|
+
$special.drop.handler( event, dd );
|
148
|
+
// disable text selection
|
149
|
+
drag.textselect( false );
|
150
|
+
// bind additional events...
|
151
|
+
if ( drag.touched )
|
152
|
+
$event.add( drag.touched, "touchmove touchend", drag.handler, dd );
|
153
|
+
else
|
154
|
+
$event.add( document, "mousemove mouseup", drag.handler, dd );
|
155
|
+
// helps prevent text selection or scrolling
|
156
|
+
if ( !drag.touched || dd.live )
|
157
|
+
return false;
|
158
|
+
},
|
159
|
+
|
160
|
+
// returns an interaction object
|
161
|
+
interaction: function( elem, dd ){
|
162
|
+
var offset = $( elem )[ dd.relative ? "position" : "offset" ]() || { top:0, left:0 };
|
163
|
+
return {
|
164
|
+
drag: elem,
|
165
|
+
callback: new drag.callback(),
|
166
|
+
droppable: [],
|
167
|
+
offset: offset
|
168
|
+
};
|
169
|
+
},
|
170
|
+
|
171
|
+
// handle drag-releatd DOM events
|
172
|
+
handler: function( event ){
|
173
|
+
// read the data before hijacking anything
|
174
|
+
var dd = event.data;
|
175
|
+
// handle various events
|
176
|
+
switch ( event.type ){
|
177
|
+
// mousemove, check distance, start dragging
|
178
|
+
case !dd.dragging && 'touchmove':
|
179
|
+
event.preventDefault();
|
180
|
+
case !dd.dragging && 'mousemove':
|
181
|
+
// drag tolerance, x² + y² = distance²
|
182
|
+
if ( Math.pow( event.pageX-dd.pageX, 2 ) + Math.pow( event.pageY-dd.pageY, 2 ) < Math.pow( dd.distance, 2 ) )
|
183
|
+
break; // distance tolerance not reached
|
184
|
+
event.target = dd.target; // force target from "mousedown" event (fix distance issue)
|
185
|
+
drag.hijack( event, "dragstart", dd ); // trigger "dragstart"
|
186
|
+
if ( dd.propagates ) // "dragstart" not rejected
|
187
|
+
dd.dragging = true; // activate interaction
|
188
|
+
// mousemove, dragging
|
189
|
+
case 'touchmove':
|
190
|
+
event.preventDefault();
|
191
|
+
case 'mousemove':
|
192
|
+
if ( dd.dragging ){
|
193
|
+
// trigger "drag"
|
194
|
+
drag.hijack( event, "drag", dd );
|
195
|
+
if ( dd.propagates ){
|
196
|
+
// manage drop events
|
197
|
+
if ( dd.drop !== false && $special.drop )
|
198
|
+
$special.drop.handler( event, dd ); // "dropstart", "dropend"
|
199
|
+
break; // "drag" not rejected, stop
|
200
|
+
}
|
201
|
+
event.type = "mouseup"; // helps "drop" handler behave
|
202
|
+
}
|
203
|
+
// mouseup, stop dragging
|
204
|
+
case 'touchend':
|
205
|
+
case 'mouseup':
|
206
|
+
default:
|
207
|
+
if ( drag.touched )
|
208
|
+
$event.remove( drag.touched, "touchmove touchend", drag.handler ); // remove touch events
|
209
|
+
else
|
210
|
+
$event.remove( document, "mousemove mouseup", drag.handler ); // remove page events
|
211
|
+
if ( dd.dragging ){
|
212
|
+
if ( dd.drop !== false && $special.drop )
|
213
|
+
$special.drop.handler( event, dd ); // "drop"
|
214
|
+
drag.hijack( event, "dragend", dd ); // trigger "dragend"
|
215
|
+
}
|
216
|
+
drag.textselect( true ); // enable text selection
|
217
|
+
// if suppressing click events...
|
218
|
+
if ( dd.click === false && dd.dragging )
|
219
|
+
$.data( dd.mousedown, "suppress.click", new Date().getTime() + 5 );
|
220
|
+
dd.dragging = drag.touched = false; // deactivate element
|
221
|
+
break;
|
222
|
+
}
|
223
|
+
},
|
224
|
+
|
225
|
+
// re-use event object for custom events
|
226
|
+
hijack: function( event, type, dd, x, elem ){
|
227
|
+
// not configured
|
228
|
+
if ( !dd )
|
229
|
+
return;
|
230
|
+
// remember the original event and type
|
231
|
+
var orig = { event:event.originalEvent, type:event.type },
|
232
|
+
// is the event drag related or drog related?
|
233
|
+
mode = type.indexOf("drop") ? "drag" : "drop",
|
234
|
+
// iteration vars
|
235
|
+
result, i = x || 0, ia, $elems, callback,
|
236
|
+
len = !isNaN( x ) ? x : dd.interactions.length;
|
237
|
+
// modify the event type
|
238
|
+
event.type = type;
|
239
|
+
// remove the original event
|
240
|
+
event.originalEvent = null;
|
241
|
+
// initialize the results
|
242
|
+
dd.results = [];
|
243
|
+
// handle each interacted element
|
244
|
+
do if ( ia = dd.interactions[ i ] ){
|
245
|
+
// validate the interaction
|
246
|
+
if ( type !== "dragend" && ia.cancelled )
|
247
|
+
continue;
|
248
|
+
// set the dragdrop properties on the event object
|
249
|
+
callback = drag.properties( event, dd, ia );
|
250
|
+
// prepare for more results
|
251
|
+
ia.results = [];
|
252
|
+
// handle each element
|
253
|
+
$( elem || ia[ mode ] || dd.droppable ).each(function( p, subject ){
|
254
|
+
// identify drag or drop targets individually
|
255
|
+
callback.target = subject;
|
256
|
+
// force propagtion of the custom event
|
257
|
+
event.isPropagationStopped = function(){ return false; };
|
258
|
+
// handle the event
|
259
|
+
result = subject ? $event.dispatch.call( subject, event, callback ) : null;
|
260
|
+
// stop the drag interaction for this element
|
261
|
+
if ( result === false ){
|
262
|
+
if ( mode == "drag" ){
|
263
|
+
ia.cancelled = true;
|
264
|
+
dd.propagates -= 1;
|
265
|
+
}
|
266
|
+
if ( type == "drop" ){
|
267
|
+
ia[ mode ][p] = null;
|
268
|
+
}
|
269
|
+
}
|
270
|
+
// assign any dropinit elements
|
271
|
+
else if ( type == "dropinit" )
|
272
|
+
ia.droppable.push( drag.element( result ) || subject );
|
273
|
+
// accept a returned proxy element
|
274
|
+
if ( type == "dragstart" )
|
275
|
+
ia.proxy = $( drag.element( result ) || ia.drag )[0];
|
276
|
+
// remember this result
|
277
|
+
ia.results.push( result );
|
278
|
+
// forget the event result, for recycling
|
279
|
+
delete event.result;
|
280
|
+
// break on cancelled handler
|
281
|
+
if ( type !== "dropinit" )
|
282
|
+
return result;
|
283
|
+
});
|
284
|
+
// flatten the results
|
285
|
+
dd.results[ i ] = drag.flatten( ia.results );
|
286
|
+
// accept a set of valid drop targets
|
287
|
+
if ( type == "dropinit" )
|
288
|
+
ia.droppable = drag.flatten( ia.droppable );
|
289
|
+
// locate drop targets
|
290
|
+
if ( type == "dragstart" && !ia.cancelled )
|
291
|
+
callback.update();
|
292
|
+
}
|
293
|
+
while ( ++i < len )
|
294
|
+
// restore the original event & type
|
295
|
+
event.type = orig.type;
|
296
|
+
event.originalEvent = orig.event;
|
297
|
+
// return all handler results
|
298
|
+
return drag.flatten( dd.results );
|
299
|
+
},
|
300
|
+
|
301
|
+
// extend the callback object with drag/drop properties...
|
302
|
+
properties: function( event, dd, ia ){
|
303
|
+
var obj = ia.callback;
|
304
|
+
// elements
|
305
|
+
obj.drag = ia.drag;
|
306
|
+
obj.proxy = ia.proxy || ia.drag;
|
307
|
+
// starting mouse position
|
308
|
+
obj.startX = dd.pageX;
|
309
|
+
obj.startY = dd.pageY;
|
310
|
+
// current distance dragged
|
311
|
+
obj.deltaX = event.pageX - dd.pageX;
|
312
|
+
obj.deltaY = event.pageY - dd.pageY;
|
313
|
+
// original element position
|
314
|
+
obj.originalX = ia.offset.left;
|
315
|
+
obj.originalY = ia.offset.top;
|
316
|
+
// adjusted element position
|
317
|
+
obj.offsetX = obj.originalX + obj.deltaX;
|
318
|
+
obj.offsetY = obj.originalY + obj.deltaY;
|
319
|
+
// assign the drop targets information
|
320
|
+
obj.drop = drag.flatten( ( ia.drop || [] ).slice() );
|
321
|
+
obj.available = drag.flatten( ( ia.droppable || [] ).slice() );
|
322
|
+
return obj;
|
323
|
+
},
|
324
|
+
|
325
|
+
// determine is the argument is an element or jquery instance
|
326
|
+
element: function( arg ){
|
327
|
+
if ( arg && ( arg.jquery || arg.nodeType == 1 ) )
|
328
|
+
return arg;
|
329
|
+
},
|
330
|
+
|
331
|
+
// flatten nested jquery objects and arrays into a single dimension array
|
332
|
+
flatten: function( arr ){
|
333
|
+
return $.map( arr, function( member ){
|
334
|
+
return member && member.jquery ? $.makeArray( member ) :
|
335
|
+
member && member.length ? drag.flatten( member ) : member;
|
336
|
+
});
|
337
|
+
},
|
338
|
+
|
339
|
+
// toggles text selection attributes ON (true) or OFF (false)
|
340
|
+
textselect: function( bool ){
|
341
|
+
$( document )[ bool ? "unbind" : "bind" ]("selectstart", drag.dontstart )
|
342
|
+
.css("MozUserSelect", bool ? "" : "none" );
|
343
|
+
// .attr("unselectable", bool ? "off" : "on" )
|
344
|
+
document.unselectable = bool ? "off" : "on";
|
345
|
+
},
|
346
|
+
|
347
|
+
// suppress "selectstart" and "ondragstart" events
|
348
|
+
dontstart: function(){
|
349
|
+
return false;
|
350
|
+
},
|
351
|
+
|
352
|
+
// a callback instance contructor
|
353
|
+
callback: function(){}
|
354
|
+
|
355
|
+
};
|
356
|
+
|
357
|
+
// callback methods
|
358
|
+
drag.callback.prototype = {
|
359
|
+
update: function(){
|
360
|
+
if ( $special.drop && this.available.length )
|
361
|
+
$.each( this.available, function( i ){
|
362
|
+
$special.drop.locate( this, i );
|
363
|
+
});
|
364
|
+
}
|
365
|
+
};
|
366
|
+
|
367
|
+
// patch $.event.$dispatch to allow suppressing clicks
|
368
|
+
var $dispatch = $event.dispatch;
|
369
|
+
$event.dispatch = function( event ){
|
370
|
+
if ( $.data( this, "suppress."+ event.type ) - new Date().getTime() > 0 ){
|
371
|
+
$.removeData( this, "suppress."+ event.type );
|
372
|
+
return;
|
373
|
+
}
|
374
|
+
return $dispatch.apply( this, arguments );
|
375
|
+
};
|
376
|
+
|
377
|
+
// event fix hooks for touch events...
|
378
|
+
var touchHooks =
|
379
|
+
$event.fixHooks.touchstart =
|
380
|
+
$event.fixHooks.touchmove =
|
381
|
+
$event.fixHooks.touchend =
|
382
|
+
$event.fixHooks.touchcancel = {
|
383
|
+
props: "clientX clientY pageX pageY screenX screenY".split( " " ),
|
384
|
+
filter: function( event, orig ) {
|
385
|
+
if ( orig ){
|
386
|
+
var touched = ( orig.touches && orig.touches[0] )
|
387
|
+
|| ( orig.changedTouches && orig.changedTouches[0] )
|
388
|
+
|| null;
|
389
|
+
// iOS webkit: touchstart, touchmove, touchend
|
390
|
+
if ( touched )
|
391
|
+
$.each( touchHooks.props, function( i, prop ){
|
392
|
+
event[ prop ] = touched[ prop ];
|
393
|
+
});
|
394
|
+
}
|
395
|
+
return event;
|
396
|
+
}
|
397
|
+
};
|
398
|
+
|
399
|
+
// share the same special event configuration with related events...
|
400
|
+
$special.draginit = $special.dragstart = $special.dragend = drag;
|
401
|
+
|
402
|
+
})( jQuery );
|