jquery-qtip2-rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,14 @@
1
+ /*
2
+ * qTip2 - Pretty powerful tooltips
3
+ * http://craigsworks.com/projects/qtip2/
4
+ *
5
+ * Version: 2.0.0pre
6
+ * Copyright 2009-2010 Craig Michael Thompson - http://craigsworks.com
7
+ *
8
+ * Dual licensed under MIT or GPLv2 licenses
9
+ * http://en.wikipedia.org/wiki/MIT_License
10
+ * http://en.wikipedia.org/wiki/GNU_General_Public_License
11
+ *
12
+ * Date: Thu Apr 26 20:40:09 2012 +0100
13
+ */
14
+
@@ -0,0 +1,143 @@
1
+ PLUGINS.imagemap = function(area, corner, flip)
2
+ {
3
+ if(!area.jquery) { area = $(area); }
4
+
5
+ var shape = (area[0].shape || area.attr('shape')).toLowerCase(),
6
+ baseCoords = (area[0].coords || area.attr('coords')).split(','),
7
+ coords = [],
8
+ image = $('img[usemap="#'+area.parent('map').attr('name')+'"]'),
9
+ imageOffset = image.offset(),
10
+ result = {
11
+ width: 0, height: 0,
12
+ offset: { top: 1e10, right: 0, bottom: 0, left: 1e10 }
13
+ },
14
+ i = 0, next = 0, dimensions;
15
+
16
+ // POLY area coordinate calculator
17
+ // Special thanks to Ed Cradock for helping out with this.
18
+ // Uses a binary search algorithm to find suitable coordinates.
19
+ function polyCoordinates(result, coords, corner)
20
+ {
21
+ var i = 0,
22
+ compareX = 1, compareY = 1,
23
+ realX = 0, realY = 0,
24
+ newWidth = result.width,
25
+ newHeight = result.height;
26
+
27
+ // Use a binary search algorithm to locate most suitable coordinate (hopefully)
28
+ while(newWidth > 0 && newHeight > 0 && compareX > 0 && compareY > 0)
29
+ {
30
+ newWidth = Math.floor(newWidth / 2);
31
+ newHeight = Math.floor(newHeight / 2);
32
+
33
+ if(corner.x === 'left'){ compareX = newWidth; }
34
+ else if(corner.x === 'right'){ compareX = result.width - newWidth; }
35
+ else{ compareX += Math.floor(newWidth / 2); }
36
+
37
+ if(corner.y === 'top'){ compareY = newHeight; }
38
+ else if(corner.y === 'bottom'){ compareY = result.height - newHeight; }
39
+ else{ compareY += Math.floor(newHeight / 2); }
40
+
41
+ i = coords.length; while(i--)
42
+ {
43
+ if(coords.length < 2){ break; }
44
+
45
+ realX = coords[i][0] - result.offset.left;
46
+ realY = coords[i][1] - result.offset.top;
47
+
48
+ if((corner.x === 'left' && realX >= compareX) ||
49
+ (corner.x === 'right' && realX <= compareX) ||
50
+ (corner.x === 'center' && (realX < compareX || realX > (result.width - compareX))) ||
51
+ (corner.y === 'top' && realY >= compareY) ||
52
+ (corner.y === 'bottom' && realY <= compareY) ||
53
+ (corner.y === 'center' && (realY < compareY || realY > (result.height - compareY)))) {
54
+ coords.splice(i, 1);
55
+ }
56
+ }
57
+ }
58
+
59
+ return { left: coords[0][0], top: coords[0][1] };
60
+ }
61
+
62
+ // Make sure we account for padding and borders on the image
63
+ imageOffset.left += Math.ceil((image.outerWidth() - image.width()) / 2);
64
+ imageOffset.top += Math.ceil((image.outerHeight() - image.height()) / 2);
65
+
66
+ // Parse coordinates into proper array
67
+ if(shape === 'poly') {
68
+ i = baseCoords.length; while(i--)
69
+ {
70
+ next = [ parseInt(baseCoords[--i], 10), parseInt(baseCoords[i+1], 10) ];
71
+
72
+ if(next[0] > result.offset.right){ result.offset.right = next[0]; }
73
+ if(next[0] < result.offset.left){ result.offset.left = next[0]; }
74
+ if(next[1] > result.offset.bottom){ result.offset.bottom = next[1]; }
75
+ if(next[1] < result.offset.top){ result.offset.top = next[1]; }
76
+
77
+ coords.push(next);
78
+ }
79
+ }
80
+ else {
81
+ coords = $.map(baseCoords, function(coord){ return parseInt(coord, 10); });
82
+ }
83
+
84
+ // Calculate details
85
+ switch(shape)
86
+ {
87
+ case 'rect':
88
+ result = {
89
+ width: Math.abs(coords[2] - coords[0]),
90
+ height: Math.abs(coords[3] - coords[1]),
91
+ offset: {
92
+ left: Math.min(coords[0], coords[2]),
93
+ top: Math.min(coords[1], coords[3])
94
+ }
95
+ };
96
+ break;
97
+
98
+ case 'circle':
99
+ result = {
100
+ width: coords[2] + 2,
101
+ height: coords[2] + 2,
102
+ offset: { left: coords[0], top: coords[1] }
103
+ };
104
+ break;
105
+
106
+ case 'poly':
107
+ $.extend(result, {
108
+ width: Math.abs(result.offset.right - result.offset.left),
109
+ height: Math.abs(result.offset.bottom - result.offset.top)
110
+ });
111
+
112
+ if(corner.string() === 'centercenter') {
113
+ result.offset = {
114
+ left: result.offset.left + (result.width / 2),
115
+ top: result.offset.top + (result.height / 2)
116
+ };
117
+ }
118
+ else {
119
+ result.offset = polyCoordinates(result, coords.slice(), corner);
120
+
121
+ // If flip adjustment is enabled, also calculate the closest opposite point
122
+ if(flip && (flip[0] === 'flip' || flip[1] === 'flip')) {
123
+ result.flipoffset = polyCoordinates(result, coords.slice(), {
124
+ x: corner.x === 'left' ? 'right' : corner.x === 'right' ? 'left' : 'center',
125
+ y: corner.y === 'top' ? 'bottom' : corner.y === 'bottom' ? 'top' : 'center'
126
+ });
127
+
128
+ result.flipoffset.left -= result.offset.left;
129
+ result.flipoffset.top -= result.offset.top;
130
+ }
131
+ }
132
+
133
+ result.width = result.height = 0;
134
+ break;
135
+ }
136
+
137
+ // Add image position to offset coordinates
138
+ result.offset.left += imageOffset.left;
139
+ result.offset.top += imageOffset.top;
140
+
141
+ return result;
142
+ };
143
+
@@ -0,0 +1,58 @@
1
+ /*jslint browser: true, onevar: true, undef: true, nomen: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: true */
2
+ /*global window: false, jQuery: false, console: false, define: false */
3
+
4
+ // Uses AMD or browser globals to create a jQuery plugin.
5
+ (function(factory) {
6
+ if(typeof define === 'function' && define.amd) {
7
+ define(['jquery'], factory);
8
+ }
9
+ else {
10
+ factory(jQuery);
11
+ }
12
+ }
13
+ (function($) {
14
+
15
+ "use strict"; // Enable ECMAScript "strict" operation for this function. See more: http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
16
+
17
+ // Munge the primitives - Paul Irish tip
18
+ var TRUE = true,
19
+ FALSE = false,
20
+ NULL = null,
21
+ undefined,
22
+
23
+ // Shortcut vars
24
+ QTIP, PLUGINS, MOUSE,
25
+ usedIDs = {},
26
+ uitooltip = 'ui-tooltip',
27
+ widget = 'ui-widget',
28
+ disabled = 'ui-state-disabled',
29
+ selector = 'div.qtip.'+uitooltip,
30
+ defaultClass = uitooltip + '-default',
31
+ focusClass = uitooltip + '-focus',
32
+ hoverClass = uitooltip + '-hover',
33
+ fluidClass = uitooltip + '-fluid',
34
+ hideOffset = '-31000px',
35
+ replaceSuffix = '_replacedByqTip',
36
+ oldtitle = 'oldtitle',
37
+ trackingBound;
38
+
39
+ /* Thanks to Paul Irish for this one: http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/ */
40
+ function log() {
41
+ log.history = log.history || [];
42
+ log.history.push(arguments);
43
+
44
+ // Make sure console is present
45
+ if('object' === typeof console) {
46
+
47
+ // Setup console and arguments
48
+ var c = console[ console.warn ? 'warn' : 'log' ],
49
+ args = Array.prototype.slice.call(arguments), a;
50
+
51
+ // Add qTip2 marker to first argument if it's a string
52
+ if(typeof arguments[0] === 'string') { args[0] = 'qTip2: ' + args[0]; }
53
+
54
+ // Apply console.warn or .log if not supported
55
+ a = c.apply ? c.apply(console, args) : c(args);
56
+ }
57
+ }
58
+
@@ -0,0 +1,286 @@
1
+ function Modal(api)
2
+ {
3
+ var self = this,
4
+ options = api.options.show.modal,
5
+ elems = api.elements,
6
+ tooltip = elems.tooltip,
7
+ overlaySelector = '#qtip-overlay',
8
+ globalNamespace = '.qtipmodal',
9
+ namespace = globalNamespace + api.id,
10
+ attr = 'is-modal-qtip',
11
+ docBody = $(document.body),
12
+ overlay;
13
+
14
+ // Setup option set checks
15
+ api.checks.modal = {
16
+ '^show.modal.(on|blur)$': function() {
17
+ // Initialise
18
+ self.init();
19
+
20
+ // Show the modal if not visible already and tooltip is visible
21
+ elems.overlay.toggle( tooltip.is(':visible') );
22
+ }
23
+ };
24
+
25
+ $.extend(self, {
26
+ init: function()
27
+ {
28
+ // If modal is disabled... return
29
+ if(!options.on) { return self; }
30
+
31
+ // Create the overlay if needed
32
+ overlay = self.create();
33
+
34
+ // Add unique attribute so we can grab modal tooltips easily via a selector
35
+ tooltip.attr(attr, TRUE)
36
+
37
+ // Set z-index
38
+ .css('z-index', PLUGINS.modal.zindex + $(selector+'['+attr+']').length)
39
+
40
+ // Remove previous bound events in globalNamespace
41
+ .unbind(globalNamespace).unbind(namespace)
42
+
43
+ // Apply our show/hide/focus modal events
44
+ .bind('tooltipshow'+globalNamespace+' tooltiphide'+globalNamespace, function(event, api, duration) {
45
+ var oEvent = event.originalEvent;
46
+
47
+ // Make sure mouseout doesn't trigger a hide when showing the modal and mousing onto backdrop
48
+ if(event.target === tooltip[0]) {
49
+ if(oEvent && event.type === 'tooltiphide' && /mouse(leave|enter)/.test(oEvent.type) && $(oEvent.relatedTarget).closest(overlay[0]).length) {
50
+ try { event.preventDefault(); } catch(e) {}
51
+ }
52
+ else if(!oEvent || (oEvent && !oEvent.solo)) {
53
+ self[ event.type.replace('tooltip', '') ](event, duration);
54
+ }
55
+ }
56
+ })
57
+
58
+ // Adjust modal z-index on tooltip focus
59
+ .bind('tooltipfocus'+globalNamespace, function(event) {
60
+ // If focus was cancelled before it reearch us, don't do anything
61
+ if(event.isDefaultPrevented() || event.target !== tooltip[0]) { return; }
62
+
63
+ var qtips = $(selector).filter('['+attr+']'),
64
+
65
+ // Keep the modal's lower than other, regular qtips
66
+ newIndex = PLUGINS.modal.zindex + qtips.length,
67
+ curIndex = parseInt(tooltip[0].style.zIndex, 10);
68
+
69
+ // Set overlay z-index
70
+ overlay[0].style.zIndex = newIndex - 1;
71
+
72
+ // Reduce modal z-index's and keep them properly ordered
73
+ qtips.each(function() {
74
+ if(this.style.zIndex > curIndex) {
75
+ this.style.zIndex -= 1;
76
+ }
77
+ });
78
+
79
+ // Fire blur event for focused tooltip
80
+ qtips.end().filter('.' + focusClass).qtip('blur', event.originalEvent);
81
+
82
+ // Set the new z-index
83
+ tooltip.addClass(focusClass)[0].style.zIndex = newIndex;
84
+
85
+ // Prevent default handling
86
+ try { event.preventDefault(); } catch(e) {}
87
+ })
88
+
89
+ // Focus any other visible modals when this one hides
90
+ .bind('tooltiphide'+globalNamespace, function(event) {
91
+ if(event.target === tooltip[0]) {
92
+ $('[' + attr + ']').filter(':visible').not(tooltip).last().qtip('focus', event);
93
+ }
94
+ });
95
+
96
+ // Apply keyboard "Escape key" close handler
97
+ if(options.escape) {
98
+ $(window).unbind(namespace).bind('keydown'+namespace, function(event) {
99
+ if(event.keyCode === 27 && tooltip.hasClass(focusClass)) {
100
+ api.hide(event);
101
+ }
102
+ });
103
+ }
104
+
105
+ // Apply click handler for blur option
106
+ if(options.blur) {
107
+ elems.overlay.unbind(namespace).bind('click'+namespace, function(event) {
108
+ if(tooltip.hasClass(focusClass)) { api.hide(event); }
109
+ });
110
+ }
111
+
112
+ return self;
113
+ },
114
+
115
+ create: function()
116
+ {
117
+ var elem = $(overlaySelector);
118
+
119
+ // Return if overlay is already rendered
120
+ if(elem.length) {
121
+ // Modal overlay should always be below all tooltips if possible
122
+ return (elems.overlay = elem.insertAfter( $(selector).last() ));
123
+ }
124
+
125
+ // Create document overlay
126
+ overlay = elems.overlay = $('<div />', {
127
+ id: overlaySelector.substr(1),
128
+ html: '<div></div>',
129
+ mousedown: function() { return FALSE; }
130
+ })
131
+ .insertAfter( $(selector).last() );
132
+
133
+ // Update position on window resize or scroll
134
+ function resize() {
135
+ overlay.css({
136
+ height: $(window).height(),
137
+ width: $(window).width()
138
+ });
139
+ }
140
+ $(window).unbind(globalNamespace).bind('resize'+globalNamespace, resize);
141
+ resize(); // Fire it initially too
142
+
143
+ return overlay;
144
+ },
145
+
146
+ toggle: function(event, state, duration)
147
+ {
148
+ // Make sure default event hasn't been prevented
149
+ if(event && event.isDefaultPrevented()) { return self; }
150
+
151
+ var effect = options.effect,
152
+ type = state ? 'show': 'hide',
153
+ visible = overlay.is(':visible'),
154
+ modals = $('[' + attr + ']').filter(':visible').not(tooltip),
155
+ zindex;
156
+
157
+ // Create our overlay if it isn't present already
158
+ if(!overlay) { overlay = self.create(); }
159
+
160
+ // Prevent modal from conflicting with show.solo, and don't hide backdrop is other modals are visible
161
+ if((overlay.is(':animated') && visible === state) || (!state && modals.length)) { return self; }
162
+
163
+ // State specific...
164
+ if(state) {
165
+ // Set position
166
+ overlay.css({ left: 0, top: 0 });
167
+
168
+ // Toggle backdrop cursor style on show
169
+ overlay.toggleClass('blurs', options.blur);
170
+
171
+ // Make sure we can't focus anything outside the tooltip
172
+ docBody.bind('focusin'+namespace, function(event) {
173
+ var target = $(event.target),
174
+ container = target.closest('.qtip'),
175
+
176
+ // Determine if input container target is above this
177
+ targetOnTop = container.length < 1 ? FALSE :
178
+ (parseInt(container[0].style.zIndex, 10) > parseInt(tooltip[0].style.zIndex, 10));
179
+
180
+ // If we're showing a modal, but focus has landed on an input below
181
+ // this modal, divert focus to the first visible input in this modal
182
+ if(!targetOnTop && ($(event.target).closest(selector)[0] !== tooltip[0])) {
183
+ tooltip.find('input:visible').filter(':first').focus();
184
+ }
185
+ });
186
+ }
187
+ else {
188
+ // Undelegate focus handler
189
+ docBody.undelegate('*', 'focusin'+namespace);
190
+ }
191
+
192
+ // Stop all animations
193
+ overlay.stop(TRUE, FALSE);
194
+
195
+ // Use custom function if provided
196
+ if($.isFunction(effect)) {
197
+ effect.call(overlay, state);
198
+ }
199
+
200
+ // If no effect type is supplied, use a simple toggle
201
+ else if(effect === FALSE) {
202
+ overlay[ type ]();
203
+ }
204
+
205
+ // Use basic fade function
206
+ else {
207
+ overlay.fadeTo( parseInt(duration, 10) || 90, state ? 1 : 0, function() {
208
+ if(!state) { $(this).hide(); }
209
+ });
210
+ }
211
+
212
+ // Reset position on hide
213
+ if(!state) {
214
+ overlay.queue(function(next) {
215
+ overlay.css({ left: '', top: '' });
216
+ next();
217
+ });
218
+ }
219
+
220
+ return self;
221
+ },
222
+
223
+ show: function(event, duration) { return self.toggle(event, TRUE, duration); },
224
+ hide: function(event, duration) { return self.toggle(event, FALSE, duration); },
225
+
226
+ destroy: function()
227
+ {
228
+ var delBlanket = overlay;
229
+
230
+ if(delBlanket) {
231
+ // Check if any other modal tooltips are present
232
+ delBlanket = $('[' + attr + ']').not(tooltip).length < 1;
233
+
234
+ // Remove overlay if needed
235
+ if(delBlanket) {
236
+ elems.overlay.remove();
237
+ $(window).unbind(globalNamespace);
238
+ }
239
+ else {
240
+ elems.overlay.unbind(globalNamespace+api.id);
241
+ }
242
+
243
+ // Undelegate focus handler
244
+ docBody.undelegate('*', 'focusin'+namespace);
245
+ }
246
+
247
+ // Remove bound events
248
+ return tooltip.removeAttr(attr).unbind(globalNamespace);
249
+ }
250
+ });
251
+
252
+ self.init();
253
+ }
254
+
255
+ PLUGINS.modal = function(api) {
256
+ var self = api.plugins.modal;
257
+
258
+ return 'object' === typeof self ? self : (api.plugins.modal = new Modal(api));
259
+ };
260
+
261
+ // Plugin needs to be initialized on render
262
+ PLUGINS.modal.initialize = 'render';
263
+
264
+ // Setup sanitiztion rules
265
+ PLUGINS.modal.sanitize = function(opts) {
266
+ if(opts.show) {
267
+ if(typeof opts.show.modal !== 'object') { opts.show.modal = { on: !!opts.show.modal }; }
268
+ else if(typeof opts.show.modal.on === 'undefined') { opts.show.modal.on = TRUE; }
269
+ }
270
+ };
271
+
272
+ // Base z-index for all modal tooltips (use qTip core z-index as a base)
273
+ PLUGINS.modal.zindex = QTIP.zindex + 1000;
274
+
275
+ // Extend original api defaults
276
+ $.extend(TRUE, QTIP.defaults, {
277
+ show: {
278
+ modal: {
279
+ on: FALSE,
280
+ effect: TRUE,
281
+ blur: TRUE,
282
+ escape: TRUE
283
+ }
284
+ }
285
+ });
286
+