pageflow-linkmap-page 1.5.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -6
  3. data/Gemfile +0 -7
  4. data/README.md +0 -5
  5. data/app/assets/javascript/pageflow/linkmap_page/editor/collections/areas_collection.js +8 -1
  6. data/app/assets/javascript/pageflow/linkmap_page/editor/config.js +23 -1
  7. data/app/assets/javascript/pageflow/linkmap_page/editor/controllers/side_bar_controller.js +24 -5
  8. data/app/assets/javascript/pageflow/linkmap_page/editor/models/area.js +4 -1
  9. data/app/assets/javascript/pageflow/linkmap_page/editor/models/color_map_delegator.js +16 -0
  10. data/app/assets/javascript/pageflow/linkmap_page/editor/models/color_map_file.js +6 -0
  11. data/app/assets/javascript/pageflow/linkmap_page/editor/models/masked_image_file.js +7 -0
  12. data/app/assets/javascript/pageflow/linkmap_page/editor/models/page_configuration_mixin.js +49 -55
  13. data/app/assets/javascript/pageflow/linkmap_page/editor/models/processed_file.js +12 -0
  14. data/app/assets/javascript/pageflow/linkmap_page/editor/patterns/area_pattern.js +42 -0
  15. data/app/assets/javascript/pageflow/linkmap_page/editor/routers/side_bar_router.js +3 -1
  16. data/app/assets/javascript/pageflow/linkmap_page/editor/templates/embedded/area_item.jst.ejs +2 -2
  17. data/app/assets/javascript/pageflow/linkmap_page/editor/templates/embedded/area_masks_preview.jst.ejs +4 -2
  18. data/app/assets/javascript/pageflow/linkmap_page/editor/templates/embedded/area_outlines.jst.ejs +3 -2
  19. data/app/assets/javascript/pageflow/linkmap_page/editor/templates/embedded/mobile_info_box_page_item.jst.ejs +2 -0
  20. data/app/assets/javascript/pageflow/linkmap_page/editor/views/areas_list_view.js +1 -0
  21. data/app/assets/javascript/pageflow/linkmap_page/editor/views/configuration_editor_view.js +46 -0
  22. data/app/assets/javascript/pageflow/linkmap_page/editor/views/edit_area_view.js +3 -6
  23. data/app/assets/javascript/pageflow/linkmap_page/editor/views/embedded/area_item_embedded_view.js +75 -10
  24. data/app/assets/javascript/pageflow/linkmap_page/editor/views/embedded/area_masks_preview_embedded_view.js +71 -77
  25. data/app/assets/javascript/pageflow/linkmap_page/editor/views/embedded/area_outlines_embedded_view.js +44 -82
  26. data/app/assets/javascript/pageflow/linkmap_page/editor/views/embedded/areas_embedded_view.js +12 -13
  27. data/app/assets/javascript/pageflow/linkmap_page/editor/views/embedded/mobile_info_box_embedded_view.js +61 -0
  28. data/app/assets/javascript/pageflow/linkmap_page/editor/views/embedded/mobile_info_box_page_item_embedded_view.js +28 -0
  29. data/app/assets/javascript/pageflow/linkmap_page/editor.js +10 -2
  30. data/app/assets/javascript/pageflow/linkmap_page/page_type.js +155 -20
  31. data/app/assets/javascript/pageflow/linkmap_page/widgets/hover_video.js +4 -1
  32. data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap/area_contains.js +7 -6
  33. data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap/area_set_mask.js +16 -0
  34. data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap/color_map.js +83 -142
  35. data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap/image_data.js +17 -47
  36. data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap/mask.js +3 -34
  37. data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap/remote_image.js +3 -6
  38. data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap.js +78 -92
  39. data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap_area_indicators.js +75 -0
  40. data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap_paginator.js +292 -0
  41. data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap_pan_zoom.js +241 -0
  42. data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap_panorama.js +81 -59
  43. data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap_scroll_indicators.js +14 -0
  44. data/app/assets/stylesheets/pageflow/linkmap_page/editor/area_outlines.scss +6 -0
  45. data/app/assets/stylesheets/pageflow/linkmap_page/editor/masks_preview.scss +10 -0
  46. data/app/assets/stylesheets/pageflow/linkmap_page/themes/default/mobile_info_box.scss +31 -0
  47. data/app/assets/stylesheets/pageflow/linkmap_page/themes/default/paginator.scss +53 -0
  48. data/app/assets/stylesheets/pageflow/linkmap_page/themes/default/scroll_indicators.scss +5 -1
  49. data/app/assets/stylesheets/pageflow/linkmap_page/themes/default.scss +3 -0
  50. data/app/assets/stylesheets/pageflow/linkmap_page.scss +29 -3
  51. data/app/helpers/pageflow/linkmap_page/areas_helper.rb +37 -11
  52. data/app/jobs/pageflow/linkmap_page/process_source_image_file_job.rb +4 -4
  53. data/app/views/pageflow/linkmap_page/areas/_div.html.erb +13 -7
  54. data/app/views/pageflow/linkmap_page/color_map_files/_color_map_file.json.jbuilder +18 -0
  55. data/app/views/pageflow/linkmap_page/editor/color_map_files/_color_map_file.json.jbuilder +1 -0
  56. data/app/views/pageflow/linkmap_page/editor/masked_image_files/_masked_image_file.json.jbuilder +1 -0
  57. data/app/views/pageflow/linkmap_page/page.html.erb +76 -39
  58. data/config/locales/de.yml +47 -4
  59. data/config/locales/en.yml +43 -4
  60. data/db/migrate/20170330201200_create_mask_sprites.rb +1 -1
  61. data/db/migrate/20171106151700_create_masked_image_files.rb +1 -1
  62. data/db/migrate/20180111145100_create_color_map_files.rb +1 -1
  63. data/db/migrate/20180214201200_drop_mask_sprites.rb +7 -0
  64. data/lib/pageflow/linkmap_page/engine.rb +4 -0
  65. data/lib/pageflow/linkmap_page/page_type.rb +26 -0
  66. data/lib/pageflow/linkmap_page/paperclip_processors/color_mask.rb +1 -1
  67. data/lib/pageflow/linkmap_page/paperclip_processors/colors.rb +1 -1
  68. data/lib/pageflow/linkmap_page/version.rb +1 -1
  69. data/lib/tasks/pageflow_linkmap_page_tasks.rake +8 -7
  70. data/pageflow-linkmap-page.gemspec +11 -5
  71. data/spec/factories/color_map_file.rb +16 -0
  72. data/spec/factories/image_file.rb +25 -0
  73. data/spec/factories/masked_image_file.rb +10 -0
  74. data/spec/helpers/pageflow/linkmap_page/areas_helper_spec.rb +76 -13
  75. data/spec/integration/masked_image_file_type_spec.rb +15 -0
  76. data/spec/models/pageflow/linkmap_page/color_map_file_spec.rb +113 -0
  77. data/spec/models/pageflow/linkmap_page/masked_image_file_spec.rb +87 -0
  78. data/spec/pageflow/linkmap_page/paperclip_processors/colors_spec.rb +46 -0
  79. data/spec/pageflow/linkmap_page/progress_spec.rb +91 -0
  80. data/spec/spec_helper.rb +5 -1
  81. data/spec/support/config/devise.rb +1 -8
  82. data/spec/support/config/{factory_girl.rb → factory_bot.rb} +5 -3
  83. data/spec/support/config/resque.rb +9 -0
  84. data/spec/support/fixtures/black_dots.png +0 -0
  85. data/spec/support/fixtures/color_map.png +0 -0
  86. data/spec/support/fixtures/dots_and_lines.png +0 -0
  87. data/spec/support/fixtures/green_and_black.png +0 -0
  88. data/spec/support/fixtures/red.png +0 -0
  89. data/spec/support/fixtures/transparent.png +0 -0
  90. data/spec/support/matchers/have_color.rb +34 -0
  91. metadata +98 -41
  92. data/app/assets/javascript/pageflow/linkmap_page/editor/models/masks_delegator.js +0 -16
  93. data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap/area_redraw.js +0 -34
  94. data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap/mask_sprite.js +0 -68
  95. data/app/assets/javascript/pageflow/linkmap_page/widgets/linkmap/masks.js +0 -99
  96. data/app/controllers/pageflow/linkmap_page/mask_sprites_controller.rb +0 -26
  97. data/app/models/pageflow/linkmap_page/mask_sprite.rb +0 -15
  98. data/config/routes.rb +0 -5
  99. data/spec/controllers/pageflow/linkmap_page/mask_sprites_controller_spec.rb +0 -108
@@ -1,5 +1,5 @@
1
1
  pageflow.linkmapPage.ImageData = (function() {
2
- function ImageData(width, height) {
2
+ function ImageData(width, height, image) {
3
3
  var canvas = document.createElement('canvas');
4
4
 
5
5
  this.width = width;
@@ -8,66 +8,36 @@ pageflow.linkmapPage.ImageData = (function() {
8
8
  canvas.width = width;
9
9
  canvas.height = height;
10
10
 
11
- this.loadImage = function(image) {
12
- image.draw(canvas, {disableImageSmoothing: true});
13
- };
11
+ image.draw(canvas.getContext('2d'), {
12
+ width: width,
13
+ disableImageSmoothing: true
14
+ });
14
15
 
15
16
  this.draw = function(context, sx, sy, sw, sh, dx, dy, dw, dh) {
16
17
  context.drawImage(canvas, sx, sy, sw, sh, dx, dy, dw, dh);
17
18
  };
18
19
 
19
- this.copyColorFrom = function(imageData, color, destinationX, destinationY) {
20
- var data = imageData.data;
21
- var destinationContext = canvas.getContext('2d');
22
-
23
- for (var i = 0; i < data.length; i += 4) {
24
- if (data[i] != color[0] ||
25
- data[i + 1] != color[1] ||
26
- data[i + 2] != color[2]) {
27
-
28
- data[i + 3] = 0;
29
- }
30
- else {
31
- data[i + 3] = 255;
32
- }
33
- }
34
-
35
- destinationContext.putImageData(imageData, destinationX, destinationY);
36
- };
37
-
38
- this.getBoundingBox = function(box) {
39
- return this.get(box.left, box.top, box.width, box.height);
40
- };
41
-
42
- this.get = function(left, top, width, height) {
20
+ this.nonTransparentAt = function(x, y) {
43
21
  var context = canvas.getContext('2d');
44
- return context.getImageData(left, top, width, height);
45
- };
46
-
47
- this.toDataURL = function() {
48
- var result = canvas.toDataURL();
49
-
50
- if (!result.match(/^data:image/)) {
51
- throw new invalidImageDataUrl();
52
- }
22
+ var pixel = context.getImageData(x, y, 1, 1).data;
53
23
 
54
- return result;
24
+ return pixel[3] > 0;
55
25
  };
56
26
  }
57
27
 
58
- function invalidImageDataUrl() {
59
- var error = new Error('Invalid data url from canvas.');
60
- error.i18nKey = 'pageflow.linkmap_page.errors.invalid_image_data';
28
+ ImageData.empty = {
29
+ hasColorAt: function() {
30
+ return false;
31
+ },
61
32
 
62
- return error;
63
- }
33
+ colorAt: function() {
34
+ return null;
35
+ }
36
+ };
64
37
 
65
38
  ImageData.load = function(url) {
66
39
  return pageflow.linkmapPage.RemoteImage.load(url).then(function(image) {
67
- var imageData = new ImageData(image.width(), image.height());
68
- imageData.loadImage(image);
69
-
70
- return imageData;
40
+ return new ImageData(image.width(), image.height(), image);
71
41
  });
72
42
  };
73
43
 
@@ -1,37 +1,6 @@
1
1
  pageflow.linkmapPage.Mask = function Mask(options) {
2
- var sprite = options.sprite;
3
- var spriteOffset = options.spriteOffset;
4
- var boundingBox = options.boundingBox;
5
-
6
- this.permaId = options.permaId;
7
-
8
- this.areaAttributes = function() {
9
- return {
10
- mask_perma_id: options.permaId,
11
- top: boundingBox.top / options.originalHeight * 100,
12
- left: boundingBox.left / options.originalWidth * 100,
13
- height: boundingBox.height / options.originalHeight * 100,
14
- width: boundingBox.width / options.originalWidth * 100
15
- };
16
- };
17
-
18
- this.contains = function(fractionX, fractionY) {
19
- var x = fractionX * options.originalWidth;
20
- var y = fractionY * options.originalHeight;
21
-
22
- var spriteX = x - boundingBox.left;
23
- var spriteY = y - boundingBox.top;
24
-
25
- if (spriteX < 0 || spriteX >= boundingBox.width ||
26
- spriteY < 0 || spriteY >= boundingBox.height) {
27
- return false;
28
- }
29
-
30
- return sprite.nonTransparentAt(spriteOffset + spriteX, spriteY);
31
- };
32
-
33
- this.draw = function(context, currentWidth) {
34
- var scale = currentWidth / options.originalWidth;
35
- sprite.draw(context, spriteOffset, boundingBox, scale);
2
+ this.contains = function(xInPercent, yInPercent) {
3
+ var component = options.colorMap.componentFromPoint(xInPercent, yInPercent);
4
+ return !!component && component.permaId == options.colorMapComponentPermaId;
36
5
  };
37
6
  };
@@ -8,10 +8,7 @@ pageflow.linkmapPage.RemoteImage = (function() {
8
8
  return image.height;
9
9
  };
10
10
 
11
- this.draw = function(canvas, options) {
12
- options = options || {};
13
- var context = canvas.getContext('2d');
14
-
11
+ this.draw = function(context, options) {
15
12
  if (options.disableImageSmoothing) {
16
13
  context.imageSmoothingEnabled = false;
17
14
  }
@@ -19,8 +16,8 @@ pageflow.linkmapPage.RemoteImage = (function() {
19
16
  context.drawImage(image,
20
17
  0,
21
18
  0,
22
- canvas.width,
23
- canvas.height);
19
+ options.width,
20
+ image.height * (options.width / image.width));
24
21
  };
25
22
  }
26
23
 
@@ -4,50 +4,53 @@
4
4
 
5
5
  $.widget('pageflow.linkmap', {
6
6
  _create: function() {
7
- var widget = this;
8
-
9
- this.lastImageUrls = {};
10
- this.imagePromises = {};
7
+ this.colorMapPromise = $.when(pageflow.linkmapPage.ColorMap.empty);
11
8
 
12
9
  this.refresh();
13
10
 
14
- if (widget.options.hoverVideoEnabled) {
15
- widget.options.hoverVideo.activate();
11
+ if (this.options.hoverVideoEnabled) {
12
+ this.options.hoverVideo.activate();
16
13
  }
17
14
 
18
- this.element.on('mousemove', '.hover_area', function() {
19
- var hoverArea = $(this);
20
-
21
- if (widget.options.hoverVideoEnabled) {
22
- widget.options.hoverVideo.schedulePlay({
23
- area: hoverArea,
24
- baseImage: widget.options.baseImage()
25
- });
15
+ this._on({
16
+ 'mousemove .hover_area': function(event) {
17
+ var hoverArea = $(event.currentTarget);
18
+
19
+ if (this.options.hoverVideoEnabled) {
20
+ this.options.hoverVideo.schedulePlay({
21
+ area: hoverArea,
22
+ baseImage: this.options.baseImage()
23
+ });
24
+ }
25
+ },
26
+
27
+ 'mouseleave .hover_area': function() {
28
+ if (this.options.hoverVideoEnabled) {
29
+ this.options.hoverVideo.pause();
30
+ }
31
+ },
32
+
33
+ 'click': function(event) {
34
+ var area = this.areaAt(this.positionFromEvent(event));
35
+
36
+ if (area.length && area.hasClass('enabled')) {
37
+ area.first().trigger($.Event('linkmapareaclick', {originalEvent: event}));
38
+ }
39
+ else {
40
+ this._trigger('backgroundclick');
41
+ }
42
+
43
+ return false;
44
+ },
45
+
46
+ 'mousemove': function(event) {
47
+ this.updateHoverStates(event);
48
+ },
49
+
50
+ 'mouseleave': function(event) {
51
+ this.updateHoverStates(event);
26
52
  }
27
53
  });
28
-
29
- this.element.on('mouseleave', '.hover_area', function() {
30
- if (widget.options.hoverVideoEnabled) {
31
- widget.options.hoverVideo.pause();
32
- }
33
- });
34
-
35
- this.element.on('click', function(event) {
36
- var area = widget.areaAt(widget.positionFromEvent(event));
37
-
38
- if (area.length) {
39
- area.first().trigger($.Event('linkmapareaclick', {originalEvent: event}));
40
- }
41
- else {
42
- widget._trigger('backgroundclick');
43
- }
44
-
45
- return false;
46
- });
47
-
48
- this.element.on('mousemove mouseleave', function(event) {
49
- widget.updateHoverStates(event);
50
- });
51
54
  },
52
55
 
53
56
  areaAt: function(position) {
@@ -63,7 +66,7 @@
63
66
  var area = $(this);
64
67
  var hovered = area.linkmapAreaContains(position);
65
68
 
66
- if (area.hasClass('hover') && !hovered) {
69
+ if (area.hasClass('pointer_inside') && !hovered) {
67
70
  area.trigger('linkmaparealeave');
68
71
  }
69
72
  });
@@ -72,24 +75,30 @@
72
75
  var area = $(this);
73
76
  var hovered = area.linkmapAreaContains(position);
74
77
 
75
- if (!area.hasClass('hover') && hovered) {
76
- area.trigger('linkmapareaenter');
78
+ if (area.hasClass('enabled')) {
79
+ if (!area.hasClass('pointer_inside') && hovered) {
80
+ area.trigger('linkmapareaenter');
81
+ }
82
+
83
+ area.toggleClass('pointer_inside', hovered);
77
84
  }
78
85
 
79
86
  area.css('cursor',
80
87
  hovered &&
81
88
  area.attr('data-target-type') !== 'text_only' ?
82
89
  'pointer' : 'default');
83
-
84
- area.toggleClass('hover', hovered);
85
90
  });
86
91
  },
87
92
 
88
93
  positionFromEvent: function(event) {
94
+ // Older versions of Firefox do not support event.offsetX, which
95
+ // would be exactly what we need here.
96
+
89
97
  var clientRect = this.element[0].getBoundingClientRect();
98
+ var scale = this.options.parentScale();
90
99
 
91
- var left = event.clientX - clientRect.left;
92
- var top = event.clientY - clientRect.top;
100
+ var left = (event.clientX - clientRect.left) / scale;
101
+ var top = (event.clientY - clientRect.top) / scale;
93
102
 
94
103
  return {
95
104
  leftInPixel: left,
@@ -111,32 +120,14 @@
111
120
  },
112
121
 
113
122
  refresh: function() {
123
+ var areaBackgroundImages = this.element.find('.background_image, .linkmap_area_outlines-canvas_wrapper');
114
124
  var hoverAreas = this.element.find('.hover_area');
115
- var widget = this;
116
125
 
117
- $.when(
118
- this.loadImage('hover'),
119
- this.loadImage('visited'),
120
- this.loadMasks()
121
- ).then(function(hoverImage, visitedImage, masks) {
122
- var baseImage = widget.options.baseImage();
123
- var width = baseImage.width();
124
- var height = baseImage.height();
125
-
126
- hoverAreas.linkmapAreaRedraw({
127
- target: '.hover_image',
128
- image: hoverImage,
129
- width: width,
130
- height: height,
131
- masks: masks
132
- });
126
+ this.resizeToBaseImage(areaBackgroundImages);
133
127
 
134
- hoverAreas.linkmapAreaRedraw({
135
- target: '.visited_image',
136
- image: visitedImage,
137
- width: width,
138
- height: height,
139
- masks: masks
128
+ this.loadColorMap().then(function(colorMap) {
129
+ hoverAreas.linkmapAreaSetMask({
130
+ colorMap: colorMap
140
131
  });
141
132
  });
142
133
 
@@ -145,43 +136,38 @@
145
136
  hoverAreas.linkmapAreaVisited();
146
137
  },
147
138
 
148
- loadImage: function(name) {
149
- var url = this.options[name + 'ImageUrl'];
150
-
151
- if (this.lastImageUrls[name] !== url) {
152
- this.lastImageUrls[name] = url;
153
- this.imagePromises[name] = url && pageflow.linkmapPage.RemoteImage.load(url);
154
- }
155
-
156
- return this.imagePromises[name];
157
- },
158
-
159
- loadMasks: function() {
139
+ loadColorMap: function() {
160
140
  var widget = this;
161
- var maskImageId = this.options.masksData && this.options.masksData.id;
162
141
 
163
- if (this.lastMaskImageId !== maskImageId) {
164
- this.lastMaskImageId = maskImageId;
142
+ if (this.lastColorMapFileId !== this.options.colorMapFileId) {
143
+ this.lastColorMapFileId = this.options.colorMapFileId;
144
+ this.colorMapPromise = pageflow.linkmapPage.ColorMap.load(this.options.colorMapFileId);
165
145
 
166
- this.masksPromise = this.options.masksData ?
167
- pageflow.linkmapPage.Masks.deserialize(this.options.masksData,
168
- this.options.maskSpriteUrlTemplate) :
169
- $.when(pageflow.linkmapPage.Masks.empty);
170
-
171
- this.masksPromise.then(function(masks) {
172
- widget._trigger('updatemasks', null, {masks: masks});
146
+ this.colorMapPromise.then(function(colorMap) {
147
+ widget._trigger('updatecolormap', null, {colorMap: colorMap});
173
148
  });
174
149
  }
175
150
 
176
- return this.masksPromise;
151
+ return this.colorMapPromise;
152
+ },
153
+
154
+ resizeToBaseImage: function(target) {
155
+ var baseImage = this.options.baseImage();
156
+
157
+ target
158
+ .width(baseImage.width())
159
+ .height(baseImage.height());
177
160
  }
178
161
  });
179
162
 
180
163
  $.fn.linkmapAreaClip = function(optionalPosition) {
181
164
  this.each(function() {
182
165
  var hoverArea = $(this);
183
- var clippedElement = hoverArea.find('.panorama_video, .hover_image, .visited_image');
184
- var position = optionalPosition || hoverArea.position();
166
+ var clippedElement = hoverArea.find('.panorama_video, .background_image, .linkmap_area_outlines-canvas_wrapper');
167
+ var position = optionalPosition || {
168
+ left: hoverArea.prop('offsetLeft'),
169
+ top: hoverArea.prop('offsetTop')
170
+ };
185
171
 
186
172
  clippedElement.css({
187
173
  left: -position.left + 'px',
@@ -0,0 +1,75 @@
1
+ (function($) {
2
+ $.widget('pageflow.linkmapAreaIndicators', {
3
+ _create: function() {
4
+ this.touchIndicator = this.element.find('.touch_indicator');
5
+ this.externalLinkLoadingIndicator = this.element.find('.external_link_loading_indicator');
6
+ },
7
+
8
+ displayForSelectedArea: function(area, event) {
9
+ if (!area.hasClass('dynamic_marker') &&
10
+ !area.hasClass('text_only_area')) {
11
+ this._animateTouchIndicator(event);
12
+ }
13
+ },
14
+
15
+ displayForClickedArea: function(area, event) {
16
+ if (!area.hasClass('dynamic_marker') &&
17
+ area.hasClass('external_site_area') &&
18
+ area.hasClass('target_self')) {
19
+ this._displayExternalLinkLoadingIndicator(event);
20
+ }
21
+ },
22
+
23
+ reset: function() {
24
+ this.externalLinkLoadingIndicator.hide();
25
+ },
26
+
27
+ _animateTouchIndicator: function(event) {
28
+ this._updatePosition(this.touchIndicator, event);
29
+ this._animate(this.touchIndicator);
30
+ },
31
+
32
+ _displayExternalLinkLoadingIndicator: function(event) {
33
+ this._updatePosition(this.externalLinkLoadingIndicator, event);
34
+ this.externalLinkLoadingIndicator.show();
35
+ },
36
+
37
+ _animate: function(element) {
38
+ element.hide();
39
+
40
+ setTimeout(function() {
41
+ element.show();
42
+ }, 500);
43
+
44
+ setTimeout(function() {
45
+ element.hide();
46
+ }, 1200);
47
+ },
48
+
49
+ _updatePosition: function(element, event) {
50
+ if (event) {
51
+ this._updatePositionByEvent(element, event);
52
+ }
53
+ else {
54
+ this._center(element);
55
+ }
56
+ },
57
+
58
+ _updatePositionByEvent: function(element, event) {
59
+ var touch = event.touches ? event.touches[0] : event;
60
+ var parentClientRect = this.options.pageElement[0].getBoundingClientRect();
61
+
62
+ element.css({
63
+ left: touch.clientX - parentClientRect.left,
64
+ top: touch.clientY - parentClientRect.top
65
+ });
66
+ },
67
+
68
+ _center: function(element) {
69
+ element.css({
70
+ left: '50%',
71
+ top: '40%'
72
+ });
73
+ }
74
+ });
75
+ }(jQuery));