activeadmin-regex-input 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0f89e25f926b82901849e3c0d080589f34172762
4
- data.tar.gz: 7bbc3f2258e117eefee436ad198648eef4da1cb3
3
+ metadata.gz: 1e7f8e662f6126811d3592d8ac4c4e7789b89373
4
+ data.tar.gz: 8d9a2e8b6d6a9c3e94ddb8751c138384dcab3a0d
5
5
  SHA512:
6
- metadata.gz: 86e041f04e9b2d55ca92c537b7bf85ee10cde2ff45765d64ad793b976b097e3e9fe220332becd0ef4de11eaec81855c5c7ee92d9b8946b808395bb91bfa50ca4
7
- data.tar.gz: af9daae59ba732f1ed0a71ad46eea743b81085889800a8e9876d3fa63db647b82afb59d8fb17d6cabe6428bc0016fc260e88334ad39a41e4b0f1a49e3edd305b
6
+ metadata.gz: b350d11d0619e5e3f310e3ef9adb20860cacec4bb37917e26e53f2140d2b7dc9beaa63f5cb3d3e02ea7e085755daa5955e816237c665ea839cbc2883586fafad
7
+ data.tar.gz: 311e601ee56b7e003dc858534daed776b763cbee15f4233644b344226a6f9d6b9ceffa485e570d37dc728fec8a034f73429b9febabf2df1556fb20c4cf1c1e63
@@ -0,0 +1,4 @@
1
+ ## VERSION 0.2
2
+
3
+ - Remove gem 'rails-assets-webui-popover' from https://rails-assets.org to avoid conflict with active admin jquery.
4
+ - Add Webui popover source code.
@@ -1,9 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- activeadmin-regex-input (0.0.0)
5
- activeadmin (~> 1.0)
6
- jquery-rails
4
+ activeadmin-regex-input (0.2.0)
5
+ activeadmin
7
6
 
8
7
  GEM
9
8
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -9,21 +9,17 @@ A simple filter input for active admin with checking at client if input match pr
9
9
  ## Dependency
10
10
 
11
11
  * activeadmin 1.0.0 pre
12
- * rails-assets-webui-popover (Require manual install)
13
- * jquery-rails 3.1
14
12
 
15
13
  ## Installation
16
14
 
17
15
  Add following lines to the Gemfile:
18
16
 
19
17
  ```ruby
20
- gem 'rails-assets-webui-popover', source: 'https://rails-assets.org'
21
18
  gem 'activeadmin-regex-input', '~> 0.1'
22
19
  ```
23
20
 
24
21
  Then execute `bundle` to install to your activeadmin project.
25
22
 
26
-
27
23
  ## Usage
28
24
  In the index section of activeadmin controller:
29
25
  ```ruby
@@ -33,4 +29,8 @@ filter :sample_regex,
33
29
  example: '123'
34
30
  ```
35
31
 
36
- The regex option is the string representation of the regex. This must compatible with javascript default regex engine. Currently the server side validation isn't included.
32
+ The regex option is the string representation of the regex. This must compatible with javascript default regex engine. Currently the server side validation isn't included.
33
+
34
+ ## Thanks
35
+
36
+ Thank sandywalker for beautiful jquery popover library [webui-popover](https://github.com/sandywalker/webui-popover).
@@ -4,9 +4,9 @@ require 'activeadmin/regex-input/version'
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = 'activeadmin-regex-input'
7
- s.version = '0.1.1'
7
+ s.version = '0.2.0'
8
8
  s.date = '2018-03-14'
9
- s.summary = "Formtastic Regex Input"
9
+ s.summary = "Active Admin Regex Input"
10
10
  s.description = "A simple filter input for active admin with checking at client if input match predefined regex."
11
11
  s.authors = ["Canh Nguyen"]
12
12
  s.email = 'xuancanh.1994@gmail.com'
@@ -19,5 +19,4 @@ Gem::Specification.new do |s|
19
19
  s.add_development_dependency "rake", "~> 12"
20
20
 
21
21
  s.add_runtime_dependency 'activeadmin'
22
- s.add_runtime_dependency 'jquery-rails', '~> 3.1'
23
22
  end
@@ -0,0 +1,1225 @@
1
+ /*
2
+ * webui popover plugin - v1.2.17
3
+ * A lightWeight popover plugin with jquery ,enchance the popover plugin of bootstrap with some awesome new features. It works well with bootstrap ,but bootstrap is not necessary!
4
+ * https://github.com/sandywalker/webui-popover
5
+ *
6
+ * Made by Sandy Duan
7
+ * Under MIT License
8
+ */
9
+ (function(window, document, undefined) {
10
+ 'use strict';
11
+ (function(factory) {
12
+ if (typeof define === 'function' && define.amd) {
13
+ // Register as an anonymous AMD module.
14
+ define(['jquery'], factory);
15
+ } else if (typeof exports === 'object') {
16
+ // Node/CommonJS
17
+ module.exports = factory(require('jquery'));
18
+ } else {
19
+ // Browser globals
20
+ factory(window.jQuery);
21
+ }
22
+ }(function($) {
23
+ // Create the defaults once
24
+ var pluginName = 'webuiPopover';
25
+ var pluginClass = 'webui-popover';
26
+ var pluginType = 'webui.popover';
27
+ var defaults = {
28
+ placement: 'auto',
29
+ container: null,
30
+ width: 'auto',
31
+ height: 'auto',
32
+ trigger: 'click', //hover,click,sticky,manual
33
+ style: '',
34
+ selector: false, // jQuery selector, if a selector is provided, popover objects will be delegated to the specified.
35
+ delay: {
36
+ show: null,
37
+ hide: 300
38
+ },
39
+ async: {
40
+ type: 'GET',
41
+ before: null, //function(that, xhr, settings){}
42
+ success: null, //function(that, xhr){}
43
+ error: null //function(that, xhr, data){}
44
+ },
45
+ cache: true,
46
+ multi: false,
47
+ arrow: true,
48
+ title: '',
49
+ content: '',
50
+ closeable: false,
51
+ padding: true,
52
+ url: '',
53
+ type: 'html',
54
+ direction: '', // ltr,rtl
55
+ animation: null,
56
+ template: '<div class="webui-popover">' +
57
+ '<div class="webui-arrow"></div>' +
58
+ '<div class="webui-popover-inner">' +
59
+ '<a href="#" class="close"></a>' +
60
+ '<h3 class="webui-popover-title"></h3>' +
61
+ '<div class="webui-popover-content"><i class="icon-refresh"></i> <p>&nbsp;</p></div>' +
62
+ '</div>' +
63
+ '</div>',
64
+ backdrop: false,
65
+ dismissible: true,
66
+ onShow: null,
67
+ onHide: null,
68
+ abortXHR: true,
69
+ autoHide: false,
70
+ offsetTop: 0,
71
+ offsetLeft: 0,
72
+ iframeOptions: {
73
+ frameborder: '0',
74
+ allowtransparency: 'true',
75
+ id: '',
76
+ name: '',
77
+ scrolling: '',
78
+ onload: '',
79
+ height: '',
80
+ width: ''
81
+ },
82
+ hideEmpty: false
83
+ };
84
+
85
+ var rtlClass = pluginClass + '-rtl';
86
+ var _srcElements = [];
87
+ var backdrop = $('<div class="webui-popover-backdrop"></div>');
88
+ var _globalIdSeed = 0;
89
+ var _isBodyEventHandled = false;
90
+ var _offsetOut = -2000; // the value offset out of the screen
91
+ var $document = $(document);
92
+
93
+ var toNumber = function(numeric, fallback) {
94
+ return isNaN(numeric) ? (fallback || 0) : Number(numeric);
95
+ };
96
+
97
+ var getPopFromElement = function($element) {
98
+ return $element.data('plugin_' + pluginName);
99
+ };
100
+
101
+ var hideAllPop = function() {
102
+ var pop = null;
103
+ for (var i = 0; i < _srcElements.length; i++) {
104
+ pop = getPopFromElement(_srcElements[i]);
105
+ if (pop) {
106
+ pop.hide(true);
107
+ }
108
+ }
109
+ $document.trigger('hiddenAll.' + pluginType);
110
+ };
111
+
112
+ var hideOtherPops = function(currentPop) {
113
+ var pop = null;
114
+ for (var i = 0; i < _srcElements.length; i++) {
115
+ pop = getPopFromElement(_srcElements[i]);
116
+ if (pop && pop.id !== currentPop.id) {
117
+ pop.hide(true);
118
+ }
119
+ }
120
+ $document.trigger('hiddenAll.' + pluginType);
121
+ };
122
+
123
+ var isMobile = ('ontouchstart' in document.documentElement) && (/Mobi/.test(navigator.userAgent));
124
+
125
+ var pointerEventToXY = function(e) {
126
+ var out = {
127
+ x: 0,
128
+ y: 0
129
+ };
130
+ if (e.type === 'touchstart' || e.type === 'touchmove' || e.type === 'touchend' || e.type === 'touchcancel') {
131
+ var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
132
+ out.x = touch.pageX;
133
+ out.y = touch.pageY;
134
+ } else if (e.type === 'mousedown' || e.type === 'mouseup' || e.type === 'click') {
135
+ out.x = e.pageX;
136
+ out.y = e.pageY;
137
+ }
138
+ return out;
139
+ };
140
+
141
+
142
+
143
+ // The actual plugin constructor
144
+ function WebuiPopover(element, options) {
145
+ this.$element = $(element);
146
+ if (options) {
147
+ if ($.type(options.delay) === 'string' || $.type(options.delay) === 'number') {
148
+ options.delay = {
149
+ show: options.delay,
150
+ hide: options.delay
151
+ }; // bc break fix
152
+ }
153
+ }
154
+ this.options = $.extend({}, defaults, options);
155
+ this._defaults = defaults;
156
+ this._name = pluginName;
157
+ this._targetclick = false;
158
+ this.init();
159
+ _srcElements.push(this.$element);
160
+ return this;
161
+
162
+ }
163
+
164
+ WebuiPopover.prototype = {
165
+ //init webui popover
166
+ init: function() {
167
+ if (this.$element[0] instanceof document.constructor && !this.options.selector) {
168
+ throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!');
169
+ }
170
+
171
+ if (this.getTrigger() !== 'manual') {
172
+ //init the event handlers
173
+ if (isMobile) {
174
+ this.$element.off('touchend', this.options.selector).on('touchend', this.options.selector, $.proxy(this.toggle, this));
175
+ } else if (this.getTrigger() === 'click') {
176
+ this.$element.off('click', this.options.selector).on('click', this.options.selector, $.proxy(this.toggle, this));
177
+ } else if (this.getTrigger() === 'hover') {
178
+ this.$element
179
+ .off('mouseenter mouseleave click', this.options.selector)
180
+ .on('mouseenter', this.options.selector, $.proxy(this.mouseenterHandler, this))
181
+ .on('mouseleave', this.options.selector, $.proxy(this.mouseleaveHandler, this));
182
+ }
183
+ }
184
+ this._poped = false;
185
+ this._inited = true;
186
+ this._opened = false;
187
+ this._idSeed = _globalIdSeed;
188
+ this.id = pluginName + this._idSeed;
189
+ // normalize container
190
+ this.options.container = $(this.options.container || document.body).first();
191
+
192
+ if (this.options.backdrop) {
193
+ backdrop.appendTo(this.options.container).hide();
194
+ }
195
+ _globalIdSeed++;
196
+ if (this.getTrigger() === 'sticky') {
197
+ this.show();
198
+ }
199
+
200
+ if (this.options.selector) {
201
+ this._options = $.extend({}, this.options, {
202
+ selector: ''
203
+ });
204
+ }
205
+
206
+ },
207
+ /* api methods and actions */
208
+ destroy: function() {
209
+ var index = -1;
210
+
211
+ for (var i = 0; i < _srcElements.length; i++) {
212
+ if (_srcElements[i] === this.$element) {
213
+ index = i;
214
+ break;
215
+ }
216
+ }
217
+
218
+ _srcElements.splice(index, 1);
219
+
220
+
221
+ this.hide();
222
+ this.$element.data('plugin_' + pluginName, null);
223
+ if (this.getTrigger() === 'click') {
224
+ this.$element.off('click');
225
+ } else if (this.getTrigger() === 'hover') {
226
+ this.$element.off('mouseenter mouseleave');
227
+ }
228
+ if (this.$target) {
229
+ this.$target.remove();
230
+ }
231
+ },
232
+ getDelegateOptions: function() {
233
+ var options = {};
234
+
235
+ this._options && $.each(this._options, function(key, value) {
236
+ if (defaults[key] !== value) {
237
+ options[key] = value;
238
+ }
239
+ });
240
+ return options;
241
+ },
242
+ /*
243
+ param: force boolean value, if value is true then force hide the popover
244
+ param: event dom event,
245
+ */
246
+ hide: function(force, event) {
247
+
248
+ if (!force && this.getTrigger() === 'sticky') {
249
+ return;
250
+ }
251
+ if (!this._opened) {
252
+ return;
253
+ }
254
+ if (event) {
255
+ event.preventDefault();
256
+ event.stopPropagation();
257
+ }
258
+
259
+ if (this.xhr && this.options.abortXHR === true) {
260
+ this.xhr.abort();
261
+ this.xhr = null;
262
+ }
263
+
264
+
265
+ var e = $.Event('hide.' + pluginType);
266
+ this.$element.trigger(e, [this.$target]);
267
+ if (this.$target) {
268
+ this.$target.removeClass('in').addClass(this.getHideAnimation());
269
+ var that = this;
270
+ setTimeout(function() {
271
+ that.$target.hide();
272
+ if (!that.getCache()) {
273
+ that.$target.remove();
274
+ //that.getTriggerElement.removeAttr('data-target');
275
+ }
276
+ }, that.getHideDelay());
277
+ }
278
+ if (this.options.backdrop) {
279
+ backdrop.hide();
280
+ }
281
+ this._opened = false;
282
+ this.$element.trigger('hidden.' + pluginType, [this.$target]);
283
+
284
+ if (this.options.onHide) {
285
+ this.options.onHide(this.$target);
286
+ }
287
+
288
+ },
289
+ resetAutoHide: function() {
290
+ var that = this;
291
+ var autoHide = that.getAutoHide();
292
+ if (autoHide) {
293
+ if (that.autoHideHandler) {
294
+ clearTimeout(that.autoHideHandler);
295
+ }
296
+ that.autoHideHandler = setTimeout(function() {
297
+ that.hide();
298
+ }, autoHide);
299
+ }
300
+ },
301
+ delegate: function(eventTarget) {
302
+ var self = $(eventTarget).data('plugin_' + pluginName);
303
+ if (!self) {
304
+ self = new WebuiPopover(eventTarget, this.getDelegateOptions());
305
+ $(eventTarget).data('plugin_' + pluginName, self);
306
+ }
307
+ return self;
308
+ },
309
+ toggle: function(e) {
310
+ var self = this;
311
+ if (e) {
312
+ e.preventDefault();
313
+ e.stopPropagation();
314
+ if (this.options.selector) {
315
+ self = this.delegate(e.currentTarget);
316
+ }
317
+ }
318
+ self[self.getTarget().hasClass('in') ? 'hide' : 'show']();
319
+ },
320
+ hideAll: function() {
321
+ hideAllPop();
322
+ },
323
+ hideOthers: function() {
324
+ hideOtherPops(this);
325
+ },
326
+ /*core method ,show popover */
327
+ show: function() {
328
+ if (this._opened) {
329
+ return;
330
+ }
331
+ //removeAllTargets();
332
+ var
333
+ $target = this.getTarget().removeClass().addClass(pluginClass).addClass(this._customTargetClass);
334
+ if (!this.options.multi) {
335
+ this.hideOthers();
336
+ }
337
+
338
+ // use cache by default, if not cache setted , reInit the contents
339
+ if (!this.getCache() || !this._poped || this.content === '') {
340
+ this.content = '';
341
+ this.setTitle(this.getTitle());
342
+ if (!this.options.closeable) {
343
+ $target.find('.close').off('click').remove();
344
+ }
345
+ if (!this.isAsync()) {
346
+ this.setContent(this.getContent());
347
+ } else {
348
+ this.setContentASync(this.options.content);
349
+ }
350
+
351
+ if (this.canEmptyHide() && this.content === '') {
352
+ return;
353
+ }
354
+ $target.show();
355
+ }
356
+
357
+ this.displayContent();
358
+
359
+ if (this.options.onShow) {
360
+ this.options.onShow($target);
361
+ }
362
+
363
+ this.bindBodyEvents();
364
+ if (this.options.backdrop) {
365
+ backdrop.show();
366
+ }
367
+ this._opened = true;
368
+ this.resetAutoHide();
369
+ },
370
+ displayContent: function() {
371
+ var
372
+ //element postion
373
+ elementPos = this.getElementPosition(),
374
+ //target postion
375
+ $target = this.getTarget().removeClass().addClass(pluginClass).addClass(this._customTargetClass),
376
+ //target content
377
+ $targetContent = this.getContentElement(),
378
+ //target Width
379
+ targetWidth = $target[0].offsetWidth,
380
+ //target Height
381
+ targetHeight = $target[0].offsetHeight,
382
+ //placement
383
+ placement = 'bottom',
384
+ e = $.Event('show.' + pluginType);
385
+
386
+ if (this.canEmptyHide()) {
387
+
388
+ var content = $targetContent.children().html();
389
+ if (content !== null && content.trim().length === 0) {
390
+ return;
391
+ }
392
+ }
393
+
394
+ //if (this.hasContent()){
395
+ this.$element.trigger(e, [$target]);
396
+ //}
397
+ // support width as data attribute
398
+ var optWidth = this.$element.data('width') || this.options.width;
399
+ if (optWidth === '') {
400
+ optWidth = this._defaults.width;
401
+ }
402
+
403
+ if (optWidth !== 'auto') {
404
+ $target.width(optWidth);
405
+ }
406
+
407
+ // support height as data attribute
408
+ var optHeight = this.$element.data('height') || this.options.height;
409
+ if (optHeight === '') {
410
+ optHeight = this._defaults.height;
411
+ }
412
+
413
+ if (optHeight !== 'auto') {
414
+ $targetContent.height(optHeight);
415
+ }
416
+
417
+ if (this.options.style) {
418
+ this.$target.addClass(pluginClass + '-' + this.options.style);
419
+ }
420
+
421
+ //check rtl
422
+ if (this.options.direction === 'rtl' && !$targetContent.hasClass(rtlClass)) {
423
+ $targetContent.addClass(rtlClass);
424
+ }
425
+
426
+ //init the popover and insert into the document body
427
+ if (!this.options.arrow) {
428
+ $target.find('.webui-arrow').remove();
429
+ }
430
+ $target.detach().css({
431
+ top: _offsetOut,
432
+ left: _offsetOut,
433
+ display: 'block'
434
+ });
435
+
436
+ if (this.getAnimation()) {
437
+ $target.addClass(this.getAnimation());
438
+ }
439
+ $target.appendTo(this.options.container);
440
+
441
+
442
+ placement = this.getPlacement(elementPos);
443
+
444
+ //This line is just for compatible with knockout custom binding
445
+ this.$element.trigger('added.' + pluginType);
446
+
447
+ this.initTargetEvents();
448
+
449
+ if (!this.options.padding) {
450
+ if (this.options.height !== 'auto') {
451
+ $targetContent.css('height', $targetContent.outerHeight());
452
+ }
453
+ this.$target.addClass('webui-no-padding');
454
+ }
455
+
456
+ // add maxHeight and maxWidth support by limodou@gmail.com 2016/10/1
457
+ if (this.options.maxHeight) {
458
+ $targetContent.css('maxHeight', this.options.maxHeight);
459
+ }
460
+
461
+ if (this.options.maxWidth) {
462
+ $targetContent.css('maxWidth', this.options.maxWidth);
463
+ }
464
+ // end
465
+
466
+ targetWidth = $target[0].offsetWidth;
467
+ targetHeight = $target[0].offsetHeight;
468
+
469
+ var postionInfo = this.getTargetPositin(elementPos, placement, targetWidth, targetHeight);
470
+
471
+ this.$target.css(postionInfo.position).addClass(placement).addClass('in');
472
+
473
+ if (this.options.type === 'iframe') {
474
+ var $iframe = $target.find('iframe');
475
+ var iframeWidth = $target.width();
476
+ var iframeHeight = $iframe.parent().height();
477
+
478
+ if (this.options.iframeOptions.width !== '' && this.options.iframeOptions.width !== 'auto') {
479
+ iframeWidth = this.options.iframeOptions.width;
480
+ }
481
+
482
+ if (this.options.iframeOptions.height !== '' && this.options.iframeOptions.height !== 'auto') {
483
+ iframeHeight = this.options.iframeOptions.height;
484
+ }
485
+
486
+ $iframe.width(iframeWidth).height(iframeHeight);
487
+ }
488
+
489
+ if (!this.options.arrow) {
490
+ this.$target.css({
491
+ 'margin': 0
492
+ });
493
+ }
494
+ if (this.options.arrow) {
495
+ var $arrow = this.$target.find('.webui-arrow');
496
+ $arrow.removeAttr('style');
497
+
498
+ //prevent arrow change by content size
499
+ if (placement === 'left' || placement === 'right') {
500
+ $arrow.css({
501
+ top: this.$target.height() / 2
502
+ });
503
+ } else if (placement === 'top' || placement === 'bottom') {
504
+ $arrow.css({
505
+ left: this.$target.width() / 2
506
+ });
507
+ }
508
+
509
+ if (postionInfo.arrowOffset) {
510
+ //hide the arrow if offset is negative
511
+ if (postionInfo.arrowOffset.left === -1 || postionInfo.arrowOffset.top === -1) {
512
+ $arrow.hide();
513
+ } else {
514
+ $arrow.css(postionInfo.arrowOffset);
515
+ }
516
+ }
517
+
518
+ }
519
+ this._poped = true;
520
+ this.$element.trigger('shown.' + pluginType, [this.$target]);
521
+ },
522
+
523
+ isTargetLoaded: function() {
524
+ return this.getTarget().find('i.glyphicon-refresh').length === 0;
525
+ },
526
+
527
+ /*getter setters */
528
+ getTriggerElement: function() {
529
+ return this.$element;
530
+ },
531
+ getTarget: function() {
532
+ if (!this.$target) {
533
+ var id = pluginName + this._idSeed;
534
+ this.$target = $(this.options.template)
535
+ .attr('id', id);
536
+ this._customTargetClass = this.$target.attr('class') !== pluginClass ? this.$target.attr('class') : null;
537
+ this.getTriggerElement().attr('data-target', id);
538
+ }
539
+ if (!this.$target.data('trigger-element')) {
540
+ this.$target.data('trigger-element', this.getTriggerElement());
541
+ }
542
+ return this.$target;
543
+ },
544
+ removeTarget: function() {
545
+ this.$target.remove();
546
+ this.$target = null;
547
+ this.$contentElement = null;
548
+ },
549
+ getTitleElement: function() {
550
+ return this.getTarget().find('.' + pluginClass + '-title');
551
+ },
552
+ getContentElement: function() {
553
+ if (!this.$contentElement) {
554
+ this.$contentElement = this.getTarget().find('.' + pluginClass + '-content');
555
+ }
556
+ return this.$contentElement;
557
+ },
558
+ getTitle: function() {
559
+ return this.$element.attr('data-title') || this.options.title || this.$element.attr('title');
560
+ },
561
+ getUrl: function() {
562
+ return this.$element.attr('data-url') || this.options.url;
563
+ },
564
+ getAutoHide: function() {
565
+ return this.$element.attr('data-auto-hide') || this.options.autoHide;
566
+ },
567
+ getOffsetTop: function() {
568
+ return toNumber(this.$element.attr('data-offset-top')) || this.options.offsetTop;
569
+ },
570
+ getOffsetLeft: function() {
571
+ return toNumber(this.$element.attr('data-offset-left')) || this.options.offsetLeft;
572
+ },
573
+ getCache: function() {
574
+ var dataAttr = this.$element.attr('data-cache');
575
+ if (typeof(dataAttr) !== 'undefined') {
576
+ switch (dataAttr.toLowerCase()) {
577
+ case 'true':
578
+ case 'yes':
579
+ case '1':
580
+ return true;
581
+ case 'false':
582
+ case 'no':
583
+ case '0':
584
+ return false;
585
+ }
586
+ }
587
+ return this.options.cache;
588
+ },
589
+ getTrigger: function() {
590
+ return this.$element.attr('data-trigger') || this.options.trigger;
591
+ },
592
+ getDelayShow: function() {
593
+ var dataAttr = this.$element.attr('data-delay-show');
594
+ if (typeof(dataAttr) !== 'undefined') {
595
+ return dataAttr;
596
+ }
597
+ return this.options.delay.show === 0 ? 0 : this.options.delay.show || 100;
598
+ },
599
+ getHideDelay: function() {
600
+ var dataAttr = this.$element.attr('data-delay-hide');
601
+ if (typeof(dataAttr) !== 'undefined') {
602
+ return dataAttr;
603
+ }
604
+ return this.options.delay.hide === 0 ? 0 : this.options.delay.hide || 100;
605
+ },
606
+ getAnimation: function() {
607
+ var dataAttr = this.$element.attr('data-animation');
608
+ return dataAttr || this.options.animation;
609
+ },
610
+ getHideAnimation: function() {
611
+ var ani = this.getAnimation();
612
+ return ani ? ani + '-out' : 'out';
613
+ },
614
+ setTitle: function(title) {
615
+ var $titleEl = this.getTitleElement();
616
+ if (title) {
617
+ //check rtl
618
+ if (this.options.direction === 'rtl' && !$titleEl.hasClass(rtlClass)) {
619
+ $titleEl.addClass(rtlClass);
620
+ }
621
+ $titleEl.html(title);
622
+ } else {
623
+ $titleEl.remove();
624
+ }
625
+ },
626
+ hasContent: function() {
627
+ return this.getContent();
628
+ },
629
+ canEmptyHide: function() {
630
+ return this.options.hideEmpty && this.options.type === 'html';
631
+ },
632
+ getIframe: function() {
633
+ var $iframe = $('<iframe></iframe>').attr('src', this.getUrl());
634
+ var self = this;
635
+ $.each(this._defaults.iframeOptions, function(opt) {
636
+ if (typeof self.options.iframeOptions[opt] !== 'undefined') {
637
+ $iframe.attr(opt, self.options.iframeOptions[opt]);
638
+ }
639
+ });
640
+
641
+ return $iframe;
642
+ },
643
+ getContent: function() {
644
+ if (this.getUrl()) {
645
+ switch (this.options.type) {
646
+ case 'iframe':
647
+ this.content = this.getIframe();
648
+ break;
649
+ case 'html':
650
+ try {
651
+ this.content = $(this.getUrl());
652
+ if (!this.content.is(':visible')) {
653
+ this.content.show();
654
+ }
655
+ } catch (error) {
656
+ throw new Error('Unable to get popover content. Invalid selector specified.');
657
+ }
658
+ break;
659
+ }
660
+ } else if (!this.content) {
661
+ var content = '';
662
+ if ($.isFunction(this.options.content)) {
663
+ content = this.options.content.apply(this.$element[0], [this]);
664
+ } else {
665
+ content = this.options.content;
666
+ }
667
+ this.content = this.$element.attr('data-content') || content;
668
+ if (!this.content) {
669
+ var $next = this.$element.next();
670
+
671
+ if ($next && $next.hasClass(pluginClass + '-content')) {
672
+ this.content = $next;
673
+ }
674
+ }
675
+ }
676
+ return this.content;
677
+ },
678
+ setContent: function(content) {
679
+ var $target = this.getTarget();
680
+ var $ct = this.getContentElement();
681
+ if (typeof content === 'string') {
682
+ $ct.html(content);
683
+ } else if (content instanceof $) {
684
+ $ct.html('');
685
+ //Don't want to clone too many times.
686
+ if (!this.options.cache) {
687
+ content.clone(true, true).removeClass(pluginClass + '-content').appendTo($ct);
688
+ } else {
689
+ content.removeClass(pluginClass + '-content').appendTo($ct);
690
+ }
691
+ }
692
+ this.$target = $target;
693
+ },
694
+ isAsync: function() {
695
+ return this.options.type === 'async';
696
+ },
697
+ setContentASync: function(content) {
698
+ var that = this;
699
+ if (this.xhr) {
700
+ return;
701
+ }
702
+ this.xhr = $.ajax({
703
+ url: this.getUrl(),
704
+ type: this.options.async.type,
705
+ cache: this.getCache(),
706
+ beforeSend: function(xhr, settings) {
707
+ if (that.options.async.before) {
708
+ that.options.async.before(that, xhr, settings);
709
+ }
710
+ },
711
+ success: function(data) {
712
+ that.bindBodyEvents();
713
+ if (content && $.isFunction(content)) {
714
+ that.content = content.apply(that.$element[0], [data]);
715
+ } else {
716
+ that.content = data;
717
+ }
718
+ that.setContent(that.content);
719
+ var $targetContent = that.getContentElement();
720
+ $targetContent.removeAttr('style');
721
+ that.displayContent();
722
+ if (that.options.async.success) {
723
+ that.options.async.success(that, data);
724
+ }
725
+ },
726
+ complete: function() {
727
+ that.xhr = null;
728
+ },
729
+ error: function(xhr, data) {
730
+ if (that.options.async.error) {
731
+ that.options.async.error(that, xhr, data);
732
+ }
733
+ }
734
+ });
735
+ },
736
+
737
+ bindBodyEvents: function() {
738
+ if (_isBodyEventHandled) {
739
+ return;
740
+ }
741
+ if (this.options.dismissible && this.getTrigger() === 'click') {
742
+ if (isMobile) {
743
+ $document.off('touchstart.webui-popover').on('touchstart.webui-popover', $.proxy(this.bodyTouchStartHandler, this));
744
+ } else {
745
+ $document.off('keyup.webui-popover').on('keyup.webui-popover', $.proxy(this.escapeHandler, this));
746
+ $document.off('click.webui-popover').on('click.webui-popover', $.proxy(this.bodyClickHandler, this));
747
+ }
748
+ } else if (this.getTrigger() === 'hover') {
749
+ $document.off('touchend.webui-popover')
750
+ .on('touchend.webui-popover', $.proxy(this.bodyClickHandler, this));
751
+ }
752
+ },
753
+
754
+ /* event handlers */
755
+ mouseenterHandler: function(e) {
756
+ var self = this;
757
+
758
+ if (e && this.options.selector) {
759
+ self = this.delegate(e.currentTarget);
760
+ }
761
+
762
+ if (self._timeout) {
763
+ clearTimeout(self._timeout);
764
+ }
765
+ self._enterTimeout = setTimeout(function() {
766
+ if (!self.getTarget().is(':visible')) {
767
+ self.show();
768
+ }
769
+ }, this.getDelayShow());
770
+ },
771
+ mouseleaveHandler: function() {
772
+ var self = this;
773
+ clearTimeout(self._enterTimeout);
774
+ //key point, set the _timeout then use clearTimeout when mouse leave
775
+ self._timeout = setTimeout(function() {
776
+ self.hide();
777
+ }, this.getHideDelay());
778
+ },
779
+ escapeHandler: function(e) {
780
+ if (e.keyCode === 27) {
781
+ this.hideAll();
782
+ }
783
+ },
784
+ bodyTouchStartHandler: function(e) {
785
+ var self = this;
786
+ var $eventEl = $(e.currentTarget);
787
+ $eventEl.on('touchend', function(e) {
788
+ self.bodyClickHandler(e);
789
+ $eventEl.off('touchend');
790
+ });
791
+ $eventEl.on('touchmove', function() {
792
+ $eventEl.off('touchend');
793
+ });
794
+ },
795
+ bodyClickHandler: function(e) {
796
+ _isBodyEventHandled = true;
797
+ var canHide = true;
798
+ for (var i = 0; i < _srcElements.length; i++) {
799
+ var pop = getPopFromElement(_srcElements[i]);
800
+ if (pop && pop._opened) {
801
+ var offset = pop.getTarget().offset();
802
+ var popX1 = offset.left;
803
+ var popY1 = offset.top;
804
+ var popX2 = offset.left + pop.getTarget().width();
805
+ var popY2 = offset.top + pop.getTarget().height();
806
+ var pt = pointerEventToXY(e);
807
+ var inPop = pt.x >= popX1 && pt.x <= popX2 && pt.y >= popY1 && pt.y <= popY2;
808
+ if (inPop) {
809
+ canHide = false;
810
+ break;
811
+ }
812
+ }
813
+ }
814
+ if (canHide) {
815
+ hideAllPop();
816
+ }
817
+ },
818
+
819
+ /*
820
+ targetClickHandler: function() {
821
+ this._targetclick = true;
822
+ },
823
+ */
824
+
825
+ //reset and init the target events;
826
+ initTargetEvents: function() {
827
+ if (this.getTrigger() === 'hover') {
828
+ this.$target
829
+ .off('mouseenter mouseleave')
830
+ .on('mouseenter', $.proxy(this.mouseenterHandler, this))
831
+ .on('mouseleave', $.proxy(this.mouseleaveHandler, this));
832
+ }
833
+ this.$target.find('.close').off('click').on('click', $.proxy(this.hide, this, true));
834
+ //this.$target.off('click.webui-popover').on('click.webui-popover', $.proxy(this.targetClickHandler, this));
835
+ },
836
+ /* utils methods */
837
+ //caculate placement of the popover
838
+ getPlacement: function(pos) {
839
+ var
840
+ placement,
841
+ container = this.options.container,
842
+ clientWidth = container.innerWidth(),
843
+ clientHeight = container.innerHeight(),
844
+ scrollTop = container.scrollTop(),
845
+ scrollLeft = container.scrollLeft(),
846
+ pageX = Math.max(0, pos.left - scrollLeft),
847
+ pageY = Math.max(0, pos.top - scrollTop);
848
+ //arrowSize = 20;
849
+
850
+ //if placement equals auto,caculate the placement by element information;
851
+ if (typeof(this.options.placement) === 'function') {
852
+ placement = this.options.placement.call(this, this.getTarget()[0], this.$element[0]);
853
+ } else {
854
+ placement = this.$element.data('placement') || this.options.placement;
855
+ }
856
+
857
+ var isH = placement === 'horizontal';
858
+ var isV = placement === 'vertical';
859
+ var detect = placement === 'auto' || isH || isV;
860
+
861
+ if (detect) {
862
+ if (pageX < clientWidth / 3) {
863
+ if (pageY < clientHeight / 3) {
864
+ placement = isH ? 'right-bottom' : 'bottom-right';
865
+ } else if (pageY < clientHeight * 2 / 3) {
866
+ if (isV) {
867
+ placement = pageY <= clientHeight / 2 ? 'bottom-right' : 'top-right';
868
+ } else {
869
+ placement = 'right';
870
+ }
871
+ } else {
872
+ placement = isH ? 'right-top' : 'top-right';
873
+ }
874
+ //placement= pageY>targetHeight+arrowSize?'top-right':'bottom-right';
875
+ } else if (pageX < clientWidth * 2 / 3) {
876
+ if (pageY < clientHeight / 3) {
877
+ if (isH) {
878
+ placement = pageX <= clientWidth / 2 ? 'right-bottom' : 'left-bottom';
879
+ } else {
880
+ placement = 'bottom';
881
+ }
882
+ } else if (pageY < clientHeight * 2 / 3) {
883
+ if (isH) {
884
+ placement = pageX <= clientWidth / 2 ? 'right' : 'left';
885
+ } else {
886
+ placement = pageY <= clientHeight / 2 ? 'bottom' : 'top';
887
+ }
888
+ } else {
889
+ if (isH) {
890
+ placement = pageX <= clientWidth / 2 ? 'right-top' : 'left-top';
891
+ } else {
892
+ placement = 'top';
893
+ }
894
+ }
895
+ } else {
896
+ //placement = pageY>targetHeight+arrowSize?'top-left':'bottom-left';
897
+ if (pageY < clientHeight / 3) {
898
+ placement = isH ? 'left-bottom' : 'bottom-left';
899
+ } else if (pageY < clientHeight * 2 / 3) {
900
+ if (isV) {
901
+ placement = pageY <= clientHeight / 2 ? 'bottom-left' : 'top-left';
902
+ } else {
903
+ placement = 'left';
904
+ }
905
+ } else {
906
+ placement = isH ? 'left-top' : 'top-left';
907
+ }
908
+ }
909
+ } else if (placement === 'auto-top') {
910
+ if (pageX < clientWidth / 3) {
911
+ placement = 'top-right';
912
+ } else if (pageX < clientWidth * 2 / 3) {
913
+ placement = 'top';
914
+ } else {
915
+ placement = 'top-left';
916
+ }
917
+ } else if (placement === 'auto-bottom') {
918
+ if (pageX < clientWidth / 3) {
919
+ placement = 'bottom-right';
920
+ } else if (pageX < clientWidth * 2 / 3) {
921
+ placement = 'bottom';
922
+ } else {
923
+ placement = 'bottom-left';
924
+ }
925
+ } else if (placement === 'auto-left') {
926
+ if (pageY < clientHeight / 3) {
927
+ placement = 'left-top';
928
+ } else if (pageY < clientHeight * 2 / 3) {
929
+ placement = 'left';
930
+ } else {
931
+ placement = 'left-bottom';
932
+ }
933
+ } else if (placement === 'auto-right') {
934
+ if (pageY < clientHeight / 3) {
935
+ placement = 'right-bottom';
936
+ } else if (pageY < clientHeight * 2 / 3) {
937
+ placement = 'right';
938
+ } else {
939
+ placement = 'right-top';
940
+ }
941
+ }
942
+ return placement;
943
+ },
944
+ getElementPosition: function() {
945
+ // If the container is the body or normal conatiner, just use $element.offset()
946
+ var elRect = this.$element[0].getBoundingClientRect();
947
+ var container = this.options.container;
948
+ var cssPos = container.css('position');
949
+
950
+ if (container.is(document.body) || cssPos === 'static') {
951
+ return $.extend({}, this.$element.offset(), {
952
+ width: this.$element[0].offsetWidth || elRect.width,
953
+ height: this.$element[0].offsetHeight || elRect.height
954
+ });
955
+ // Else fixed container need recalculate the position
956
+ } else if (cssPos === 'fixed') {
957
+ var containerRect = container[0].getBoundingClientRect();
958
+ return {
959
+ top: elRect.top - containerRect.top + container.scrollTop(),
960
+ left: elRect.left - containerRect.left + container.scrollLeft(),
961
+ width: elRect.width,
962
+ height: elRect.height
963
+ };
964
+ } else if (cssPos === 'relative') {
965
+ return {
966
+ top: this.$element.offset().top - container.offset().top,
967
+ left: this.$element.offset().left - container.offset().left,
968
+ width: this.$element[0].offsetWidth || elRect.width,
969
+ height: this.$element[0].offsetHeight || elRect.height
970
+ };
971
+ }
972
+ },
973
+
974
+ getTargetPositin: function(elementPos, placement, targetWidth, targetHeight) {
975
+ var pos = elementPos,
976
+ container = this.options.container,
977
+ //clientWidth = container.innerWidth(),
978
+ //clientHeight = container.innerHeight(),
979
+ elementW = this.$element.outerWidth(),
980
+ elementH = this.$element.outerHeight(),
981
+ scrollTop = document.documentElement.scrollTop + container.scrollTop(),
982
+ scrollLeft = document.documentElement.scrollLeft + container.scrollLeft(),
983
+ position = {},
984
+ arrowOffset = null,
985
+ arrowSize = this.options.arrow ? 20 : 0,
986
+ padding = 10,
987
+ fixedW = elementW < arrowSize + padding ? arrowSize : 0,
988
+ fixedH = elementH < arrowSize + padding ? arrowSize : 0,
989
+ refix = 0,
990
+ pageH = document.documentElement.clientHeight + scrollTop,
991
+ pageW = document.documentElement.clientWidth + scrollLeft;
992
+
993
+ var validLeft = pos.left + pos.width / 2 - fixedW > 0;
994
+ var validRight = pos.left + pos.width / 2 + fixedW < pageW;
995
+ var validTop = pos.top + pos.height / 2 - fixedH > 0;
996
+ var validBottom = pos.top + pos.height / 2 + fixedH < pageH;
997
+
998
+
999
+ switch (placement) {
1000
+ case 'bottom':
1001
+ position = {
1002
+ top: pos.top + pos.height,
1003
+ left: pos.left + pos.width / 2 - targetWidth / 2
1004
+ };
1005
+ break;
1006
+ case 'top':
1007
+ position = {
1008
+ top: pos.top - targetHeight,
1009
+ left: pos.left + pos.width / 2 - targetWidth / 2
1010
+ };
1011
+ break;
1012
+ case 'left':
1013
+ position = {
1014
+ top: pos.top + pos.height / 2 - targetHeight / 2,
1015
+ left: pos.left - targetWidth
1016
+ };
1017
+ break;
1018
+ case 'right':
1019
+ position = {
1020
+ top: pos.top + pos.height / 2 - targetHeight / 2,
1021
+ left: pos.left + pos.width
1022
+ };
1023
+ break;
1024
+ case 'top-right':
1025
+ position = {
1026
+ top: pos.top - targetHeight,
1027
+ left: validLeft ? pos.left - fixedW : padding
1028
+ };
1029
+ arrowOffset = {
1030
+ left: validLeft ? Math.min(elementW, targetWidth) / 2 + fixedW : _offsetOut
1031
+ };
1032
+ break;
1033
+ case 'top-left':
1034
+ refix = validRight ? fixedW : -padding;
1035
+ position = {
1036
+ top: pos.top - targetHeight,
1037
+ left: pos.left - targetWidth + pos.width + refix
1038
+ };
1039
+ arrowOffset = {
1040
+ left: validRight ? targetWidth - Math.min(elementW, targetWidth) / 2 - fixedW : _offsetOut
1041
+ };
1042
+ break;
1043
+ case 'bottom-right':
1044
+ position = {
1045
+ top: pos.top + pos.height,
1046
+ left: validLeft ? pos.left - fixedW : padding
1047
+ };
1048
+ arrowOffset = {
1049
+ left: validLeft ? Math.min(elementW, targetWidth) / 2 + fixedW : _offsetOut
1050
+ };
1051
+ break;
1052
+ case 'bottom-left':
1053
+ refix = validRight ? fixedW : -padding;
1054
+ position = {
1055
+ top: pos.top + pos.height,
1056
+ left: pos.left - targetWidth + pos.width + refix
1057
+ };
1058
+ arrowOffset = {
1059
+ left: validRight ? targetWidth - Math.min(elementW, targetWidth) / 2 - fixedW : _offsetOut
1060
+ };
1061
+ break;
1062
+ case 'right-top':
1063
+ refix = validBottom ? fixedH : -padding;
1064
+ position = {
1065
+ top: pos.top - targetHeight + pos.height + refix,
1066
+ left: pos.left + pos.width
1067
+ };
1068
+ arrowOffset = {
1069
+ top: validBottom ? targetHeight - Math.min(elementH, targetHeight) / 2 - fixedH : _offsetOut
1070
+ };
1071
+ break;
1072
+ case 'right-bottom':
1073
+ position = {
1074
+ top: validTop ? pos.top - fixedH : padding,
1075
+ left: pos.left + pos.width
1076
+ };
1077
+ arrowOffset = {
1078
+ top: validTop ? Math.min(elementH, targetHeight) / 2 + fixedH : _offsetOut
1079
+ };
1080
+ break;
1081
+ case 'left-top':
1082
+ refix = validBottom ? fixedH : -padding;
1083
+ position = {
1084
+ top: pos.top - targetHeight + pos.height + refix,
1085
+ left: pos.left - targetWidth
1086
+ };
1087
+ arrowOffset = {
1088
+ top: validBottom ? targetHeight - Math.min(elementH, targetHeight) / 2 - fixedH : _offsetOut
1089
+ };
1090
+ break;
1091
+ case 'left-bottom':
1092
+ position = {
1093
+ top: validTop ? pos.top - fixedH : padding,
1094
+ left: pos.left - targetWidth
1095
+ };
1096
+ arrowOffset = {
1097
+ top: validTop ? Math.min(elementH, targetHeight) / 2 + fixedH : _offsetOut
1098
+ };
1099
+ break;
1100
+
1101
+ }
1102
+ position.top += this.getOffsetTop();
1103
+ position.left += this.getOffsetLeft();
1104
+
1105
+ return {
1106
+ position: position,
1107
+ arrowOffset: arrowOffset
1108
+ };
1109
+ }
1110
+ };
1111
+ $.fn[pluginName] = function(options, noInit) {
1112
+ var results = [];
1113
+ var $result = this.each(function() {
1114
+
1115
+ var webuiPopover = $.data(this, 'plugin_' + pluginName);
1116
+ if (!webuiPopover) {
1117
+ if (!options) {
1118
+ webuiPopover = new WebuiPopover(this, null);
1119
+ } else if (typeof options === 'string') {
1120
+ if (options !== 'destroy') {
1121
+ if (!noInit) {
1122
+ webuiPopover = new WebuiPopover(this, null);
1123
+ results.push(webuiPopover[options]());
1124
+ }
1125
+ }
1126
+ } else if (typeof options === 'object') {
1127
+ webuiPopover = new WebuiPopover(this, options);
1128
+ }
1129
+ $.data(this, 'plugin_' + pluginName, webuiPopover);
1130
+ } else {
1131
+ if (options === 'destroy') {
1132
+ webuiPopover.destroy();
1133
+ } else if (typeof options === 'string') {
1134
+ results.push(webuiPopover[options]());
1135
+ }
1136
+ }
1137
+ });
1138
+ return (results.length) ? results : $result;
1139
+ };
1140
+
1141
+ //Global object exposes to window.
1142
+ var webuiPopovers = (function() {
1143
+ var _hideAll = function() {
1144
+ hideAllPop();
1145
+ };
1146
+ var _create = function(selector, options) {
1147
+ options = options || {};
1148
+ $(selector).webuiPopover(options);
1149
+ };
1150
+ var _isCreated = function(selector) {
1151
+ var created = true;
1152
+ $(selector).each(function(i, item) {
1153
+ created = created && $(item).data('plugin_' + pluginName) !== undefined;
1154
+ });
1155
+ return created;
1156
+ };
1157
+ var _show = function(selector, options) {
1158
+ if (options) {
1159
+ $(selector).webuiPopover(options).webuiPopover('show');
1160
+ } else {
1161
+ $(selector).webuiPopover('show');
1162
+ }
1163
+ };
1164
+ var _hide = function(selector) {
1165
+ $(selector).webuiPopover('hide');
1166
+ };
1167
+
1168
+ var _setDefaultOptions = function(options) {
1169
+ defaults = $.extend({}, defaults, options);
1170
+ };
1171
+
1172
+ var _updateContent = function(selector, content) {
1173
+ var pop = $(selector).data('plugin_' + pluginName);
1174
+ if (pop) {
1175
+ var cache = pop.getCache();
1176
+ pop.options.cache = false;
1177
+ pop.options.content = content;
1178
+ if (pop._opened) {
1179
+ pop._opened = false;
1180
+ pop.show();
1181
+ } else {
1182
+ if (pop.isAsync()) {
1183
+ pop.setContentASync(content);
1184
+ } else {
1185
+ pop.setContent(content);
1186
+ }
1187
+ }
1188
+ pop.options.cache = cache;
1189
+ }
1190
+ };
1191
+
1192
+ var _updateContentAsync = function(selector, url) {
1193
+ var pop = $(selector).data('plugin_' + pluginName);
1194
+ if (pop) {
1195
+ var cache = pop.getCache();
1196
+ var type = pop.options.type;
1197
+ pop.options.cache = false;
1198
+ pop.options.url = url;
1199
+
1200
+ if (pop._opened) {
1201
+ pop._opened = false;
1202
+ pop.show();
1203
+ } else {
1204
+ pop.options.type = 'async';
1205
+ pop.setContentASync(pop.content);
1206
+ }
1207
+ pop.options.cache = cache;
1208
+ pop.options.type = type;
1209
+ }
1210
+ };
1211
+
1212
+ return {
1213
+ show: _show,
1214
+ hide: _hide,
1215
+ create: _create,
1216
+ isCreated: _isCreated,
1217
+ hideAll: _hideAll,
1218
+ updateContent: _updateContent,
1219
+ updateContentAsync: _updateContentAsync,
1220
+ setDefaultOptions: _setDefaultOptions
1221
+ };
1222
+ })();
1223
+ window.WebuiPopovers = webuiPopovers;
1224
+ }));
1225
+ })(window, document);