zeroclipboard-rails 0.1.0 → 0.1.1

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: 11106a7f252d9580af77ab54c7a979769824bf96
4
- data.tar.gz: 1912126d137697e613bb206bec6f982893e09c5d
3
+ metadata.gz: 9e4d2a4aacf2d4176ab9a6d0ac2b0b3372e2801a
4
+ data.tar.gz: e846236a9805c3289b24a38dd1e308776bdd1924
5
5
  SHA512:
6
- metadata.gz: 2ff318896ae59121daa0c07c972e03d99c22893ef3bcc6e4461c890c4eccbabe0ddf9121a48a419cbb05d8d409534a23deea09c735b2a2070e85740e6015b05a
7
- data.tar.gz: 981fb0fc85d610ccaa3094482fd730ae76b45c46bd120770a0c2ae7ba53becf324fb7d38ace9b1dd818f56b04d470855929db14fd9c52a5f28fd83f5fe21538f
6
+ metadata.gz: 68e787f091f046d302a880e73d8ab3ceef84d0441471974c9c5b597bda2229a6a23051e30440551cde98a524f3676f4e30dc61b9e3f1214a4346c91db38c9e48
7
+ data.tar.gz: 00c80fc2601c7dd983f1c360349f2b4a2d7f61daa84758f8c8607a10d9bc14121d7b280fe94572b6e8ab6c44bdfb10ed518ff567179e5e38dcf6742b97e23093
data/README.md CHANGED
@@ -104,6 +104,7 @@ This gem is merely a wrapper around [ZeroClipboard](https://github.com/zeroclipb
104
104
  |[`0.0.12`](https://rubygems.org/gems/zeroclipboard-rails/versions/0.0.12)|[`1.3.1`](https://github.com/zeroclipboard/ZeroClipboard/tree/v1.3.1)|[Fix deprecation warning](https://github.com/zeroclipboard/zeroclipboard-rails/pull/17) - [@markrickert](https://github.com/markrickert)|
105
105
  |[`0.0.13`](https://rubygems.org/gems/zeroclipboard-rails/versions/0.0.13)|[`1.3.5`](https://github.com/zeroclipboard/ZeroClipboard/tree/v1.3.5)||
106
106
  |[`0.1.0`](https://rubygems.org/gems/zeroclipboard-rails/versions/0.1.0)|[`2.1.2`](https://github.com/zeroclipboard/ZeroClipboard/tree/v2.1.2)|Switch to new zeroclipboard.js major version, see their [releases](https://github.com/zeroclipboard/zeroclipboard/releases)|
107
+ |[`0.1.1`](https://rubygems.org/gems/zeroclipboard-rails/versions/0.1.1)|[`2.2.0`](https://github.com/zeroclipboard/ZeroClipboard/tree/v2.2.0)
107
108
 
108
109
 
109
110
 
@@ -1,10 +1,10 @@
1
1
  /*!
2
2
  * ZeroClipboard
3
3
  * The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface.
4
- * Copyright (c) 2014 Jon Rohan, James M. Greene
4
+ * Copyright (c) 2009-2014 Jon Rohan, James M. Greene
5
5
  * Licensed MIT
6
6
  * http://zeroclipboard.org/
7
- * v2.1.2
7
+ * v2.2.0
8
8
  */
9
9
  (function(window, undefined) {
10
10
  "use strict";
@@ -12,7 +12,21 @@
12
12
  * Store references to critically important global functions that may be
13
13
  * overridden on certain web pages.
14
14
  */
15
- var _window = window, _document = _window.document, _navigator = _window.navigator, _setTimeout = _window.setTimeout, _encodeURIComponent = _window.encodeURIComponent, _ActiveXObject = _window.ActiveXObject, _parseInt = _window.Number.parseInt || _window.parseInt, _parseFloat = _window.Number.parseFloat || _window.parseFloat, _isNaN = _window.Number.isNaN || _window.isNaN, _round = _window.Math.round, _now = _window.Date.now, _keys = _window.Object.keys, _defineProperty = _window.Object.defineProperty, _hasOwn = _window.Object.prototype.hasOwnProperty, _slice = _window.Array.prototype.slice;
15
+ var _window = window, _document = _window.document, _navigator = _window.navigator, _setTimeout = _window.setTimeout, _clearTimeout = _window.clearTimeout, _setInterval = _window.setInterval, _clearInterval = _window.clearInterval, _getComputedStyle = _window.getComputedStyle, _encodeURIComponent = _window.encodeURIComponent, _ActiveXObject = _window.ActiveXObject, _Error = _window.Error, _parseInt = _window.Number.parseInt || _window.parseInt, _parseFloat = _window.Number.parseFloat || _window.parseFloat, _isNaN = _window.Number.isNaN || _window.isNaN, _now = _window.Date.now, _keys = _window.Object.keys, _defineProperty = _window.Object.defineProperty, _hasOwn = _window.Object.prototype.hasOwnProperty, _slice = _window.Array.prototype.slice, _unwrap = function() {
16
+ var unwrapper = function(el) {
17
+ return el;
18
+ };
19
+ if (typeof _window.wrap === "function" && typeof _window.unwrap === "function") {
20
+ try {
21
+ var div = _document.createElement("div");
22
+ var unwrappedDiv = _window.unwrap(div);
23
+ if (div.nodeType === 1 && unwrappedDiv && unwrappedDiv.nodeType === 1) {
24
+ unwrapper = _window.unwrap;
25
+ }
26
+ } catch (e) {}
27
+ }
28
+ return unwrapper;
29
+ }();
16
30
  /**
17
31
  * Convert an `arguments` object into an Array.
18
32
  *
@@ -53,7 +67,7 @@
53
67
  */
54
68
  var _deepCopy = function(source) {
55
69
  var copy, i, len, prop;
56
- if (typeof source !== "object" || source == null) {
70
+ if (typeof source !== "object" || source == null || typeof source.nodeType === "number") {
57
71
  copy = source;
58
72
  } else if (typeof source.length === "number") {
59
73
  copy = [];
@@ -139,6 +153,132 @@
139
153
  return false;
140
154
  };
141
155
  /**
156
+ * Get the URL path's parent directory.
157
+ *
158
+ * @returns String or `undefined`
159
+ * @private
160
+ */
161
+ var _getDirPathOfUrl = function(url) {
162
+ var dir;
163
+ if (typeof url === "string" && url) {
164
+ dir = url.split("#")[0].split("?")[0];
165
+ dir = url.slice(0, url.lastIndexOf("/") + 1);
166
+ }
167
+ return dir;
168
+ };
169
+ /**
170
+ * Get the current script's URL by throwing an `Error` and analyzing it.
171
+ *
172
+ * @returns String or `undefined`
173
+ * @private
174
+ */
175
+ var _getCurrentScriptUrlFromErrorStack = function(stack) {
176
+ var url, matches;
177
+ if (typeof stack === "string" && stack) {
178
+ matches = stack.match(/^(?:|[^:@]*@|.+\)@(?=http[s]?|file)|.+?\s+(?: at |@)(?:[^:\(]+ )*[\(]?)((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/);
179
+ if (matches && matches[1]) {
180
+ url = matches[1];
181
+ } else {
182
+ matches = stack.match(/\)@((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/);
183
+ if (matches && matches[1]) {
184
+ url = matches[1];
185
+ }
186
+ }
187
+ }
188
+ return url;
189
+ };
190
+ /**
191
+ * Get the current script's URL by throwing an `Error` and analyzing it.
192
+ *
193
+ * @returns String or `undefined`
194
+ * @private
195
+ */
196
+ var _getCurrentScriptUrlFromError = function() {
197
+ var url, err;
198
+ try {
199
+ throw new _Error();
200
+ } catch (e) {
201
+ err = e;
202
+ }
203
+ if (err) {
204
+ url = err.sourceURL || err.fileName || _getCurrentScriptUrlFromErrorStack(err.stack);
205
+ }
206
+ return url;
207
+ };
208
+ /**
209
+ * Get the current script's URL.
210
+ *
211
+ * @returns String or `undefined`
212
+ * @private
213
+ */
214
+ var _getCurrentScriptUrl = function() {
215
+ var jsPath, scripts, i;
216
+ if (_document.currentScript && (jsPath = _document.currentScript.src)) {
217
+ return jsPath;
218
+ }
219
+ scripts = _document.getElementsByTagName("script");
220
+ if (scripts.length === 1) {
221
+ return scripts[0].src || undefined;
222
+ }
223
+ if ("readyState" in scripts[0]) {
224
+ for (i = scripts.length; i--; ) {
225
+ if (scripts[i].readyState === "interactive" && (jsPath = scripts[i].src)) {
226
+ return jsPath;
227
+ }
228
+ }
229
+ }
230
+ if (_document.readyState === "loading" && (jsPath = scripts[scripts.length - 1].src)) {
231
+ return jsPath;
232
+ }
233
+ if (jsPath = _getCurrentScriptUrlFromError()) {
234
+ return jsPath;
235
+ }
236
+ return undefined;
237
+ };
238
+ /**
239
+ * Get the unanimous parent directory of ALL script tags.
240
+ * If any script tags are either (a) inline or (b) from differing parent
241
+ * directories, this method must return `undefined`.
242
+ *
243
+ * @returns String or `undefined`
244
+ * @private
245
+ */
246
+ var _getUnanimousScriptParentDir = function() {
247
+ var i, jsDir, jsPath, scripts = _document.getElementsByTagName("script");
248
+ for (i = scripts.length; i--; ) {
249
+ if (!(jsPath = scripts[i].src)) {
250
+ jsDir = null;
251
+ break;
252
+ }
253
+ jsPath = _getDirPathOfUrl(jsPath);
254
+ if (jsDir == null) {
255
+ jsDir = jsPath;
256
+ } else if (jsDir !== jsPath) {
257
+ jsDir = null;
258
+ break;
259
+ }
260
+ }
261
+ return jsDir || undefined;
262
+ };
263
+ /**
264
+ * Get the presumed location of the "ZeroClipboard.swf" file, based on the location
265
+ * of the executing JavaScript file (e.g. "ZeroClipboard.js", etc.).
266
+ *
267
+ * @returns String
268
+ * @private
269
+ */
270
+ var _getDefaultSwfPath = function() {
271
+ var jsDir = _getDirPathOfUrl(_getCurrentScriptUrl()) || _getUnanimousScriptParentDir() || "";
272
+ return jsDir + "ZeroClipboard.swf";
273
+ };
274
+ /**
275
+ * Keep track of if the page is framed (in an `iframe`). This can never change.
276
+ * @private
277
+ */
278
+ var _pageIsFramed = function() {
279
+ return window.opener == null && (!!window.top && window != window.top || !!window.parent && window != window.parent);
280
+ }();
281
+ /**
142
282
  * Keep track of the state of the Flash object.
143
283
  * @private
144
284
  */
@@ -148,7 +288,9 @@
148
288
  pluginType: "unknown",
149
289
  disabled: null,
150
290
  outdated: null,
291
+ sandboxed: null,
151
292
  unavailable: null,
293
+ degraded: null,
152
294
  deactivated: null,
153
295
  overdue: null,
154
296
  ready: null
@@ -160,6 +302,10 @@
160
302
  */
161
303
  var _minimumFlashVersion = "11.0.0";
162
304
  /**
305
+ * The ZeroClipboard library version number, as reported by Flash, at the time the SWF was compiled.
306
+ */
307
+ var _zcSwfVersion;
308
+ /**
163
309
  * Keep track of all event listener registrations.
164
310
  * @private
165
311
  */
@@ -170,6 +316,11 @@
170
316
  */
171
317
  var _currentElement;
172
318
  /**
319
+ * Keep track of the element that was activated when a `copy` process started.
320
+ * @private
321
+ */
322
+ var _copyTarget;
323
+ /**
173
324
  * Keep track of data for the pending clipboard transaction.
174
325
  * @private
175
326
  */
@@ -180,69 +331,68 @@
180
331
  */
181
332
  var _clipDataFormatMap = null;
182
333
  /**
334
+ * Keep track of the Flash availability check timeout.
335
+ * @private
336
+ */
337
+ var _flashCheckTimeout = 0;
338
+ /**
339
+ * Keep track of SWF network errors interval polling.
340
+ * @private
341
+ */
342
+ var _swfFallbackCheckInterval = 0;
343
+ /**
183
344
  * The `message` store for events
184
345
  * @private
185
346
  */
186
347
  var _eventMessages = {
187
348
  ready: "Flash communication is established",
188
349
  error: {
189
- "flash-disabled": "Flash is disabled or not installed",
350
+ "flash-disabled": "Flash is disabled or not installed. May also be attempting to run Flash in a sandboxed iframe, which is impossible.",
190
351
  "flash-outdated": "Flash is too outdated to support ZeroClipboard",
352
+ "flash-sandboxed": "Attempting to run Flash in a sandboxed iframe, which is impossible",
191
353
  "flash-unavailable": "Flash is unable to communicate bidirectionally with JavaScript",
192
- "flash-deactivated": "Flash is too outdated for your browser and/or is configured as click-to-activate",
193
- "flash-overdue": "Flash communication was established but NOT within the acceptable time limit"
354
+ "flash-degraded": "Flash is unable to preserve data fidelity when communicating with JavaScript",
355
+ "flash-deactivated": "Flash is too outdated for your browser and/or is configured as click-to-activate.\nThis may also mean that the ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity.\nMay also be attempting to run Flash in a sandboxed iframe, which is impossible.",
356
+ "flash-overdue": "Flash communication was established but NOT within the acceptable time limit",
357
+ "version-mismatch": "ZeroClipboard JS version number does not match ZeroClipboard SWF version number",
358
+ "clipboard-error": "At least one error was thrown while ZeroClipboard was attempting to inject your data into the clipboard",
359
+ "config-mismatch": "ZeroClipboard configuration does not match Flash's reality",
360
+ "swf-not-found": "The ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity"
194
361
  }
195
362
  };
196
363
  /**
197
- * The presumed location of the "ZeroClipboard.swf" file, based on the location
198
- * of the executing JavaScript file (e.g. "ZeroClipboard.js", etc.).
364
+ * The `name`s of `error` events that can only occur is Flash has at least
365
+ * been able to load the SWF successfully.
199
366
  * @private
200
367
  */
201
- var _swfPath = function() {
202
- var i, jsDir, tmpJsPath, jsPath, swfPath = "ZeroClipboard.swf";
203
- if (!(_document.currentScript && (jsPath = _document.currentScript.src))) {
204
- var scripts = _document.getElementsByTagName("script");
205
- if ("readyState" in scripts[0]) {
206
- for (i = scripts.length; i--; ) {
207
- if (scripts[i].readyState === "interactive" && (jsPath = scripts[i].src)) {
208
- break;
209
- }
210
- }
211
- } else if (_document.readyState === "loading") {
212
- jsPath = scripts[scripts.length - 1].src;
213
- } else {
214
- for (i = scripts.length; i--; ) {
215
- tmpJsPath = scripts[i].src;
216
- if (!tmpJsPath) {
217
- jsDir = null;
218
- break;
219
- }
220
- tmpJsPath = tmpJsPath.split("#")[0].split("?")[0];
221
- tmpJsPath = tmpJsPath.slice(0, tmpJsPath.lastIndexOf("/") + 1);
222
- if (jsDir == null) {
223
- jsDir = tmpJsPath;
224
- } else if (jsDir !== tmpJsPath) {
225
- jsDir = null;
226
- break;
227
- }
228
- }
229
- if (jsDir !== null) {
230
- jsPath = jsDir;
231
- }
232
- }
233
- }
234
- if (jsPath) {
235
- jsPath = jsPath.split("#")[0].split("?")[0];
236
- swfPath = jsPath.slice(0, jsPath.lastIndexOf("/") + 1) + swfPath;
237
- }
238
- return swfPath;
239
- }();
368
+ var _errorsThatOnlyOccurAfterFlashLoads = [ "flash-unavailable", "flash-degraded", "flash-overdue", "version-mismatch", "config-mismatch", "clipboard-error" ];
369
+ /**
370
+ * The `name`s of `error` events that should likely result in the `_flashState`
371
+ * variable's property values being updated.
372
+ * @private
373
+ */
374
+ var _flashStateErrorNames = [ "flash-disabled", "flash-outdated", "flash-sandboxed", "flash-unavailable", "flash-degraded", "flash-deactivated", "flash-overdue" ];
375
+ /**
376
+ * A RegExp to match the `name` property of `error` events related to Flash.
377
+ * @private
378
+ */
379
+ var _flashStateErrorNameMatchingRegex = new RegExp("^flash-(" + _flashStateErrorNames.map(function(errorName) {
380
+ return errorName.replace(/^flash-/, "");
381
+ }).join("|") + ")$");
382
+ /**
383
+ * A RegExp to match the `name` property of `error` events related to Flash,
384
+ * which is enabled.
385
+ * @private
386
+ */
387
+ var _flashStateEnabledErrorNameMatchingRegex = new RegExp("^flash-(" + _flashStateErrorNames.slice(1).map(function(errorName) {
388
+ return errorName.replace(/^flash-/, "");
389
+ }).join("|") + ")$");
240
390
  /**
241
391
  * ZeroClipboard configuration defaults for the Core module.
242
392
  * @private
243
393
  */
244
394
  var _globalConfig = {
245
- swfPath: _swfPath,
395
+ swfPath: _getDefaultSwfPath(),
246
396
  trustedDomains: window.location.host ? [ window.location.host ] : [],
247
397
  cacheBust: true,
248
398
  forceEnhancedClipboard: false,
@@ -295,6 +445,7 @@
295
445
  * @private
296
446
  */
297
447
  var _state = function() {
448
+ _detectSandbox();
298
449
  return {
299
450
  browser: _pick(_navigator, [ "userAgent", "platform", "appName" ]),
300
451
  flash: _omit(_flashState, [ "bridge" ]),
@@ -309,7 +460,7 @@
309
460
  * @private
310
461
  */
311
462
  var _isFlashUnusable = function() {
312
- return !!(_flashState.disabled || _flashState.outdated || _flashState.unavailable || _flashState.deactivated);
463
+ return !!(_flashState.disabled || _flashState.outdated || _flashState.sandboxed || _flashState.unavailable || _flashState.degraded || _flashState.deactivated);
313
464
  };
314
465
  /**
315
466
  * The underlying implementation of `ZeroClipboard.on`.
@@ -341,16 +492,23 @@
341
492
  });
342
493
  }
343
494
  if (added.error) {
344
- var errorTypes = [ "disabled", "outdated", "unavailable", "deactivated", "overdue" ];
345
- for (i = 0, len = errorTypes.length; i < len; i++) {
346
- if (_flashState[errorTypes[i]] === true) {
495
+ for (i = 0, len = _flashStateErrorNames.length; i < len; i++) {
496
+ if (_flashState[_flashStateErrorNames[i].replace(/^flash-/, "")] === true) {
347
497
  ZeroClipboard.emit({
348
498
  type: "error",
349
- name: "flash-" + errorTypes[i]
499
+ name: _flashStateErrorNames[i]
350
500
  });
351
501
  break;
352
502
  }
353
503
  }
504
+ if (_zcSwfVersion !== undefined && ZeroClipboard.version !== _zcSwfVersion) {
505
+ ZeroClipboard.emit({
506
+ type: "error",
507
+ name: "version-mismatch",
508
+ jsVersion: ZeroClipboard.version,
509
+ swfVersion: _zcSwfVersion
510
+ });
511
+ }
354
512
  }
355
513
  }
356
514
  return ZeroClipboard;
@@ -437,13 +595,21 @@
437
595
  * @private
438
596
  */
439
597
  var _create = function() {
598
+ var previousState = _flashState.sandboxed;
599
+ _detectSandbox();
440
600
  if (typeof _flashState.ready !== "boolean") {
441
601
  _flashState.ready = false;
442
602
  }
443
- if (!ZeroClipboard.isFlashUnusable() && _flashState.bridge === null) {
603
+ if (_flashState.sandboxed !== previousState && _flashState.sandboxed === true) {
604
+ _flashState.ready = false;
605
+ ZeroClipboard.emit({
606
+ type: "error",
607
+ name: "flash-sandboxed"
608
+ });
609
+ } else if (!ZeroClipboard.isFlashUnusable() && _flashState.bridge === null) {
444
610
  var maxWait = _globalConfig.flashLoadTimeout;
445
611
  if (typeof maxWait === "number" && maxWait >= 0) {
446
- _setTimeout(function() {
612
+ _flashCheckTimeout = _setTimeout(function() {
447
613
  if (typeof _flashState.deactivated !== "boolean") {
448
614
  _flashState.deactivated = true;
449
615
  }
@@ -552,7 +718,7 @@
552
718
  htmlBridge.style.left = "0px";
553
719
  htmlBridge.style.top = "-9999px";
554
720
  htmlBridge.style.width = "1px";
555
- htmlBridge.style.top = "1px";
721
+ htmlBridge.style.height = "1px";
556
722
  }
557
723
  if (_currentElement) {
558
724
  _removeClass(_currentElement, _globalConfig.hoverClass);
@@ -589,8 +755,12 @@
589
755
  if (!eventType) {
590
756
  return;
591
757
  }
758
+ eventType = eventType.toLowerCase();
759
+ if (!event.target && (/^(copy|aftercopy|_click)$/.test(eventType) || eventType === "error" && event.name === "clipboard-error")) {
760
+ event.target = _copyTarget;
761
+ }
592
762
  _extend(event, {
593
- type: eventType.toLowerCase(),
763
+ type: eventType,
594
764
  target: event.target || _currentElement || null,
595
765
  relatedTarget: event.relatedTarget || null,
596
766
  currentTarget: _flashState && _flashState.bridge || null,
@@ -610,13 +780,13 @@
610
780
  });
611
781
  }
612
782
  if (event.type === "error") {
613
- if (/^flash-(disabled|outdated|unavailable|deactivated|overdue)$/.test(event.name)) {
783
+ if (_flashStateErrorNameMatchingRegex.test(event.name)) {
614
784
  _extend(event, {
615
785
  target: null,
616
786
  minimumVersion: _minimumFlashVersion
617
787
  });
618
788
  }
619
- if (/^flash-(outdated|unavailable|deactivated|overdue)$/.test(event.name)) {
789
+ if (_flashStateEnabledErrorNameMatchingRegex.test(event.name)) {
620
790
  _extend(event, {
621
791
  version: _flashState.version
622
792
  });
@@ -634,8 +804,7 @@
634
804
  if (event.target && !event.relatedTarget) {
635
805
  event.relatedTarget = _getRelatedTarget(event.target);
636
806
  }
637
- event = _addMouseData(event);
638
- return event;
807
+ return _addMouseData(event);
639
808
  };
640
809
  /**
641
810
  * Get a relatedTarget from the target's `data-clipboard-target` attribute
@@ -654,7 +823,7 @@
654
823
  var srcElement = event.target;
655
824
  var fromElement = event.type === "_mouseover" && event.relatedTarget ? event.relatedTarget : undefined;
656
825
  var toElement = event.type === "_mouseout" && event.relatedTarget ? event.relatedTarget : undefined;
657
- var pos = _getDOMObjectPosition(srcElement);
826
+ var pos = _getElementPosition(srcElement);
658
827
  var screenLeft = _window.screenLeft || _window.screenX || 0;
659
828
  var screenTop = _window.screenTop || _window.screenY || 0;
660
829
  var scrollLeft = _document.body.scrollLeft + _document.documentElement.scrollLeft;
@@ -751,6 +920,18 @@
751
920
  return this;
752
921
  };
753
922
  /**
923
+ * Check an `error` event's `name` property to see if Flash has
924
+ * already loaded, which rules out possible `iframe` sandboxing.
925
+ * @private
926
+ */
927
+ var _getSandboxStatusFromErrorEvent = function(event) {
928
+ var isSandboxed = null;
929
+ if (_pageIsFramed === false || event && event.type === "error" && event.name && _errorsThatOnlyOccurAfterFlashLoads.indexOf(event.name) !== -1) {
930
+ isSandboxed = false;
931
+ }
932
+ return isSandboxed;
933
+ };
934
+ /**
754
935
  * Preprocess any special behaviors, reactions, or state changes after receiving this event.
755
936
  * Executes only once per event emitted, NOT once per client.
756
937
  * @private
@@ -759,31 +940,55 @@
759
940
  var element = event.target || _currentElement || null;
760
941
  var sourceIsSwf = event._source === "swf";
761
942
  delete event._source;
762
- var flashErrorNames = [ "flash-disabled", "flash-outdated", "flash-unavailable", "flash-deactivated", "flash-overdue" ];
763
943
  switch (event.type) {
764
944
  case "error":
765
- if (flashErrorNames.indexOf(event.name) !== -1) {
945
+ var isSandboxed = event.name === "flash-sandboxed" || _getSandboxStatusFromErrorEvent(event);
946
+ if (typeof isSandboxed === "boolean") {
947
+ _flashState.sandboxed = isSandboxed;
948
+ }
949
+ if (_flashStateErrorNames.indexOf(event.name) !== -1) {
766
950
  _extend(_flashState, {
767
951
  disabled: event.name === "flash-disabled",
768
952
  outdated: event.name === "flash-outdated",
769
953
  unavailable: event.name === "flash-unavailable",
954
+ degraded: event.name === "flash-degraded",
770
955
  deactivated: event.name === "flash-deactivated",
771
956
  overdue: event.name === "flash-overdue",
772
957
  ready: false
773
958
  });
959
+ } else if (event.name === "version-mismatch") {
960
+ _zcSwfVersion = event.swfVersion;
961
+ _extend(_flashState, {
962
+ disabled: false,
963
+ outdated: false,
964
+ unavailable: false,
965
+ degraded: false,
966
+ deactivated: false,
967
+ overdue: false,
968
+ ready: false
969
+ });
774
970
  }
971
+ _clearTimeoutsAndPolling();
775
972
  break;
776
973
 
777
974
  case "ready":
975
+ _zcSwfVersion = event.swfVersion;
778
976
  var wasDeactivated = _flashState.deactivated === true;
779
977
  _extend(_flashState, {
780
978
  disabled: false,
781
979
  outdated: false,
980
+ sandboxed: false,
782
981
  unavailable: false,
982
+ degraded: false,
783
983
  deactivated: false,
784
984
  overdue: wasDeactivated,
785
985
  ready: !wasDeactivated
786
986
  });
987
+ _clearTimeoutsAndPolling();
988
+ break;
989
+
990
+ case "beforecopy":
991
+ _copyTarget = element;
787
992
  break;
788
993
 
789
994
  case "copy":
@@ -801,6 +1006,7 @@
801
1006
  break;
802
1007
 
803
1008
  case "aftercopy":
1009
+ _queueEmitClipboardErrors(event);
804
1010
  ZeroClipboard.clearData();
805
1011
  if (element && element !== _safeActiveElement() && element.focus) {
806
1012
  element.focus();
@@ -858,6 +1064,14 @@
858
1064
  break;
859
1065
 
860
1066
  case "_click":
1067
+ _copyTarget = null;
1068
+ if (_globalConfig.bubbleEvents === true && sourceIsSwf) {
1069
+ _fireMouseEvent(_extend({}, event, {
1070
+ type: event.type.slice(1)
1071
+ }));
1072
+ }
1073
+ break;
1074
+
861
1075
  case "_mousemove":
862
1076
  if (_globalConfig.bubbleEvents === true && sourceIsSwf) {
863
1077
  _fireMouseEvent(_extend({}, event, {
@@ -871,6 +1085,23 @@
871
1085
  }
872
1086
  };
873
1087
  /**
1088
+ * Check an "aftercopy" event for clipboard errors and emit a corresponding "error" event.
1089
+ * @private
1090
+ */
1091
+ var _queueEmitClipboardErrors = function(aftercopyEvent) {
1092
+ if (aftercopyEvent.errors && aftercopyEvent.errors.length > 0) {
1093
+ var errorEvent = _deepCopy(aftercopyEvent);
1094
+ _extend(errorEvent, {
1095
+ type: "error",
1096
+ name: "clipboard-error"
1097
+ });
1098
+ delete errorEvent.success;
1099
+ _setTimeout(function() {
1100
+ ZeroClipboard.emit(errorEvent);
1101
+ }, 0);
1102
+ }
1103
+ };
1104
+ /**
874
1105
  * Dispatch a synthetic MouseEvent.
875
1106
  *
876
1107
  * @returns `undefined`
@@ -901,6 +1132,40 @@
901
1132
  }
902
1133
  };
903
1134
  /**
1135
+ * Continuously poll the DOM until either:
1136
+ * (a) the fallback content becomes visible, or
1137
+ * (b) we receive an event from SWF (handled elsewhere)
1138
+ *
1139
+ * IMPORTANT:
1140
+ * This is NOT a necessary check but it can result in significantly faster
1141
+ * detection of bad `swfPath` configuration and/or network/server issues [in
1142
+ * supported browsers] than waiting for the entire `flashLoadTimeout` duration
1143
+ * to elapse before detecting that the SWF cannot be loaded. The detection
1144
+ * duration can be anywhere from 10-30 times faster [in supported browsers] by
1145
+ * using this approach.
1146
+ *
1147
+ * @returns `undefined`
1148
+ * @private
1149
+ */
1150
+ var _watchForSwfFallbackContent = function() {
1151
+ var maxWait = _globalConfig.flashLoadTimeout;
1152
+ if (typeof maxWait === "number" && maxWait >= 0) {
1153
+ var pollWait = Math.min(1e3, maxWait / 10);
1154
+ var fallbackContentId = _globalConfig.swfObjectId + "_fallbackContent";
1155
+ _swfFallbackCheckInterval = _setInterval(function() {
1156
+ var el = _document.getElementById(fallbackContentId);
1157
+ if (_isElementVisible(el)) {
1158
+ _clearTimeoutsAndPolling();
1159
+ _flashState.deactivated = null;
1160
+ ZeroClipboard.emit({
1161
+ type: "error",
1162
+ name: "swf-not-found"
1163
+ });
1164
+ }
1165
+ }, pollWait);
1166
+ }
1167
+ };
1168
+ /**
904
1169
  * Create the HTML bridge element to embed the Flash object into.
905
1170
  * @private
906
1171
  */
@@ -938,19 +1203,22 @@
938
1203
  if (!flashBridge) {
939
1204
  var allowScriptAccess = _determineScriptAccess(_window.location.host, _globalConfig);
940
1205
  var allowNetworking = allowScriptAccess === "never" ? "none" : "all";
941
- var flashvars = _vars(_globalConfig);
1206
+ var flashvars = _vars(_extend({
1207
+ jsVersion: ZeroClipboard.version
1208
+ }, _globalConfig));
942
1209
  var swfUrl = _globalConfig.swfPath + _cacheBust(_globalConfig.swfPath, _globalConfig);
943
1210
  container = _createHtmlBridge();
944
1211
  var divToBeReplaced = _document.createElement("div");
945
1212
  container.appendChild(divToBeReplaced);
946
1213
  _document.body.appendChild(container);
947
1214
  var tmpDiv = _document.createElement("div");
948
- var oldIE = _flashState.pluginType === "activex";
949
- tmpDiv.innerHTML = '<object id="' + _globalConfig.swfObjectId + '" name="' + _globalConfig.swfObjectId + '" ' + 'width="100%" height="100%" ' + (oldIE ? 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"' : 'type="application/x-shockwave-flash" data="' + swfUrl + '"') + ">" + (oldIE ? '<param name="movie" value="' + swfUrl + '"/>' : "") + '<param name="allowScriptAccess" value="' + allowScriptAccess + '"/>' + '<param name="allowNetworking" value="' + allowNetworking + '"/>' + '<param name="menu" value="false"/>' + '<param name="wmode" value="transparent"/>' + '<param name="flashvars" value="' + flashvars + '"/>' + "</object>";
1215
+ var usingActiveX = _flashState.pluginType === "activex";
1216
+ tmpDiv.innerHTML = '<object id="' + _globalConfig.swfObjectId + '" name="' + _globalConfig.swfObjectId + '" ' + 'width="100%" height="100%" ' + (usingActiveX ? 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"' : 'type="application/x-shockwave-flash" data="' + swfUrl + '"') + ">" + (usingActiveX ? '<param name="movie" value="' + swfUrl + '"/>' : "") + '<param name="allowScriptAccess" value="' + allowScriptAccess + '"/>' + '<param name="allowNetworking" value="' + allowNetworking + '"/>' + '<param name="menu" value="false"/>' + '<param name="wmode" value="transparent"/>' + '<param name="flashvars" value="' + flashvars + '"/>' + '<div id="' + _globalConfig.swfObjectId + '_fallbackContent">&nbsp;</div>' + "</object>";
950
1217
  flashBridge = tmpDiv.firstChild;
951
1218
  tmpDiv = null;
952
- flashBridge.ZeroClipboard = ZeroClipboard;
1219
+ _unwrap(flashBridge).ZeroClipboard = ZeroClipboard;
953
1220
  container.replaceChild(flashBridge, divToBeReplaced);
1221
+ _watchForSwfFallbackContent();
954
1222
  }
955
1223
  if (!flashBridge) {
956
1224
  flashBridge = _document[_globalConfig.swfObjectId];
@@ -1001,9 +1269,11 @@
1001
1269
  }
1002
1270
  }
1003
1271
  }
1272
+ _clearTimeoutsAndPolling();
1004
1273
  _flashState.ready = null;
1005
1274
  _flashState.bridge = null;
1006
1275
  _flashState.deactivated = null;
1276
+ _zcSwfVersion = undefined;
1007
1277
  }
1008
1278
  };
1009
1279
  /**
@@ -1069,15 +1339,20 @@
1069
1339
  var newResults = {};
1070
1340
  for (var prop in clipResults) {
1071
1341
  if (_hasOwn.call(clipResults, prop)) {
1072
- if (prop !== "success" && prop !== "data") {
1342
+ if (prop === "errors") {
1343
+ newResults[prop] = clipResults[prop] ? clipResults[prop].slice() : [];
1344
+ for (var i = 0, len = newResults[prop].length; i < len; i++) {
1345
+ newResults[prop][i].format = formatMap[newResults[prop][i].format];
1346
+ }
1347
+ } else if (prop !== "success" && prop !== "data") {
1073
1348
  newResults[prop] = clipResults[prop];
1074
- continue;
1075
- }
1076
- newResults[prop] = {};
1077
- var tmpHash = clipResults[prop];
1078
- for (var dataFormat in tmpHash) {
1079
- if (dataFormat && _hasOwn.call(tmpHash, dataFormat) && _hasOwn.call(formatMap, dataFormat)) {
1080
- newResults[prop][formatMap[dataFormat]] = tmpHash[dataFormat];
1349
+ } else {
1350
+ newResults[prop] = {};
1351
+ var tmpHash = clipResults[prop];
1352
+ for (var dataFormat in tmpHash) {
1353
+ if (dataFormat && _hasOwn.call(tmpHash, dataFormat) && _hasOwn.call(formatMap, dataFormat)) {
1354
+ newResults[prop][formatMap[dataFormat]] = tmpHash[dataFormat];
1355
+ }
1081
1356
  }
1082
1357
  }
1083
1358
  }
@@ -1141,6 +1416,9 @@
1141
1416
  if (typeof options.swfObjectId === "string" && options.swfObjectId) {
1142
1417
  str += (str ? "&" : "") + "swfObjectId=" + _encodeURIComponent(options.swfObjectId);
1143
1418
  }
1419
+ if (typeof options.jsVersion === "string" && options.jsVersion) {
1420
+ str += (str ? "&" : "") + "jsVersion=" + _encodeURIComponent(options.jsVersion);
1421
+ }
1144
1422
  return str;
1145
1423
  };
1146
1424
  /**
@@ -1237,29 +1515,23 @@
1237
1515
  * @private
1238
1516
  */
1239
1517
  var _addClass = function(element, value) {
1240
- if (!element || element.nodeType !== 1) {
1241
- return element;
1242
- }
1243
- if (element.classList) {
1244
- if (!element.classList.contains(value)) {
1245
- element.classList.add(value);
1246
- }
1247
- return element;
1518
+ var c, cl, className, classNames = [];
1519
+ if (typeof value === "string" && value) {
1520
+ classNames = value.split(/\s+/);
1248
1521
  }
1249
- if (value && typeof value === "string") {
1250
- var classNames = (value || "").split(/\s+/);
1251
- if (element.nodeType === 1) {
1252
- if (!element.className) {
1253
- element.className = value;
1254
- } else {
1255
- var className = " " + element.className + " ", setClass = element.className;
1256
- for (var c = 0, cl = classNames.length; c < cl; c++) {
1257
- if (className.indexOf(" " + classNames[c] + " ") < 0) {
1258
- setClass += " " + classNames[c];
1259
- }
1522
+ if (element && element.nodeType === 1 && classNames.length > 0) {
1523
+ if (element.classList) {
1524
+ for (c = 0, cl = classNames.length; c < cl; c++) {
1525
+ element.classList.add(classNames[c]);
1526
+ }
1527
+ } else if (element.hasOwnProperty("className")) {
1528
+ className = " " + element.className + " ";
1529
+ for (c = 0, cl = classNames.length; c < cl; c++) {
1530
+ if (className.indexOf(" " + classNames[c] + " ") === -1) {
1531
+ className += classNames[c] + " ";
1260
1532
  }
1261
- element.className = setClass.replace(/^\s+|\s+$/g, "");
1262
1533
  }
1534
+ element.className = className.replace(/^\s+|\s+$/g, "");
1263
1535
  }
1264
1536
  }
1265
1537
  return element;
@@ -1271,20 +1543,18 @@
1271
1543
  * @private
1272
1544
  */
1273
1545
  var _removeClass = function(element, value) {
1274
- if (!element || element.nodeType !== 1) {
1275
- return element;
1276
- }
1277
- if (element.classList) {
1278
- if (element.classList.contains(value)) {
1279
- element.classList.remove(value);
1280
- }
1281
- return element;
1282
- }
1546
+ var c, cl, className, classNames = [];
1283
1547
  if (typeof value === "string" && value) {
1284
- var classNames = value.split(/\s+/);
1285
- if (element.nodeType === 1 && element.className) {
1286
- var className = (" " + element.className + " ").replace(/[\n\t]/g, " ");
1287
- for (var c = 0, cl = classNames.length; c < cl; c++) {
1548
+ classNames = value.split(/\s+/);
1549
+ }
1550
+ if (element && element.nodeType === 1 && classNames.length > 0) {
1551
+ if (element.classList && element.classList.length > 0) {
1552
+ for (c = 0, cl = classNames.length; c < cl; c++) {
1553
+ element.classList.remove(classNames[c]);
1554
+ }
1555
+ } else if (element.className) {
1556
+ className = (" " + element.className + " ").replace(/[\r\n\t]/g, " ");
1557
+ for (c = 0, cl = classNames.length; c < cl; c++) {
1288
1558
  className = className.replace(" " + classNames[c] + " ", " ");
1289
1559
  }
1290
1560
  element.className = className.replace(/^\s+|\s+$/g, "");
@@ -1301,7 +1571,7 @@
1301
1571
  * @private
1302
1572
  */
1303
1573
  var _getStyle = function(el, prop) {
1304
- var value = _window.getComputedStyle(el, null).getPropertyValue(prop);
1574
+ var value = _getComputedStyle(el, null).getPropertyValue(prop);
1305
1575
  if (prop === "cursor") {
1306
1576
  if (!value || value === "auto") {
1307
1577
  if (el.nodeName === "A") {
@@ -1312,54 +1582,70 @@
1312
1582
  return value;
1313
1583
  };
1314
1584
  /**
1315
- * Get the zoom factor of the browser. Always returns `1.0`, except at
1316
- * non-default zoom levels in IE<8 and some older versions of WebKit.
1317
- *
1318
- * @returns Floating unit percentage of the zoom factor (e.g. 150% = `1.5`).
1319
- * @private
1320
- */
1321
- var _getZoomFactor = function() {
1322
- var rect, physicalWidth, logicalWidth, zoomFactor = 1;
1323
- if (typeof _document.body.getBoundingClientRect === "function") {
1324
- rect = _document.body.getBoundingClientRect();
1325
- physicalWidth = rect.right - rect.left;
1326
- logicalWidth = _document.body.offsetWidth;
1327
- zoomFactor = _round(physicalWidth / logicalWidth * 100) / 100;
1328
- }
1329
- return zoomFactor;
1330
- };
1331
- /**
1332
- * Get the DOM positioning info of an element.
1585
+ * Get the absolutely positioned coordinates of a DOM element.
1333
1586
  *
1334
1587
  * @returns Object containing the element's position, width, and height.
1335
1588
  * @private
1336
1589
  */
1337
- var _getDOMObjectPosition = function(obj) {
1338
- var info = {
1590
+ var _getElementPosition = function(el) {
1591
+ var pos = {
1339
1592
  left: 0,
1340
1593
  top: 0,
1341
1594
  width: 0,
1342
1595
  height: 0
1343
1596
  };
1344
- if (obj.getBoundingClientRect) {
1345
- var rect = obj.getBoundingClientRect();
1346
- var pageXOffset, pageYOffset, zoomFactor;
1347
- if ("pageXOffset" in _window && "pageYOffset" in _window) {
1348
- pageXOffset = _window.pageXOffset;
1349
- pageYOffset = _window.pageYOffset;
1350
- } else {
1351
- zoomFactor = _getZoomFactor();
1352
- pageXOffset = _round(_document.documentElement.scrollLeft / zoomFactor);
1353
- pageYOffset = _round(_document.documentElement.scrollTop / zoomFactor);
1354
- }
1597
+ if (el.getBoundingClientRect) {
1598
+ var elRect = el.getBoundingClientRect();
1599
+ var pageXOffset = _window.pageXOffset;
1600
+ var pageYOffset = _window.pageYOffset;
1355
1601
  var leftBorderWidth = _document.documentElement.clientLeft || 0;
1356
1602
  var topBorderWidth = _document.documentElement.clientTop || 0;
1357
- info.left = rect.left + pageXOffset - leftBorderWidth;
1358
- info.top = rect.top + pageYOffset - topBorderWidth;
1359
- info.width = "width" in rect ? rect.width : rect.right - rect.left;
1360
- info.height = "height" in rect ? rect.height : rect.bottom - rect.top;
1603
+ var leftBodyOffset = 0;
1604
+ var topBodyOffset = 0;
1605
+ if (_getStyle(_document.body, "position") === "relative") {
1606
+ var bodyRect = _document.body.getBoundingClientRect();
1607
+ var htmlRect = _document.documentElement.getBoundingClientRect();
1608
+ leftBodyOffset = bodyRect.left - htmlRect.left || 0;
1609
+ topBodyOffset = bodyRect.top - htmlRect.top || 0;
1610
+ }
1611
+ pos.left = elRect.left + pageXOffset - leftBorderWidth - leftBodyOffset;
1612
+ pos.top = elRect.top + pageYOffset - topBorderWidth - topBodyOffset;
1613
+ pos.width = "width" in elRect ? elRect.width : elRect.right - elRect.left;
1614
+ pos.height = "height" in elRect ? elRect.height : elRect.bottom - elRect.top;
1361
1615
  }
1362
- return info;
1616
+ return pos;
1617
+ };
1618
+ /**
1619
+ * Determine is an element is visible somewhere within the document (page).
1620
+ *
1621
+ * @returns Boolean
1622
+ * @private
1623
+ */
1624
+ var _isElementVisible = function(el) {
1625
+ if (!el) {
1626
+ return false;
1627
+ }
1628
+ var styles = _getComputedStyle(el, null);
1629
+ var hasCssHeight = _parseFloat(styles.height) > 0;
1630
+ var hasCssWidth = _parseFloat(styles.width) > 0;
1631
+ var hasCssTop = _parseFloat(styles.top) >= 0;
1632
+ var hasCssLeft = _parseFloat(styles.left) >= 0;
1633
+ var cssKnows = hasCssHeight && hasCssWidth && hasCssTop && hasCssLeft;
1634
+ var rect = cssKnows ? null : _getElementPosition(el);
1635
+ var isVisible = styles.display !== "none" && styles.visibility !== "collapse" && (cssKnows || !!rect && (hasCssHeight || rect.height > 0) && (hasCssWidth || rect.width > 0) && (hasCssTop || rect.top >= 0) && (hasCssLeft || rect.left >= 0));
1636
+ return isVisible;
1637
+ };
1638
+ /**
1639
+ * Clear all existing timeouts and interval polling delegates.
1640
+ *
1641
+ * @returns `undefined`
1642
+ * @private
1643
+ */
1644
+ var _clearTimeoutsAndPolling = function() {
1645
+ _clearTimeout(_flashCheckTimeout);
1646
+ _flashCheckTimeout = 0;
1647
+ _clearInterval(_swfFallbackCheckInterval);
1648
+ _swfFallbackCheckInterval = 0;
1363
1649
  };
1364
1650
  /**
1365
1651
  * Reposition the Flash object to cover the currently activated element.
@@ -1370,7 +1656,7 @@
1370
1656
  var _reposition = function() {
1371
1657
  var htmlBridge;
1372
1658
  if (_currentElement && (htmlBridge = _getHtmlBridge(_flashState.bridge))) {
1373
- var pos = _getDOMObjectPosition(_currentElement);
1659
+ var pos = _getElementPosition(_currentElement);
1374
1660
  _extend(htmlBridge.style, {
1375
1661
  width: pos.width + "px",
1376
1662
  height: pos.height + "px",
@@ -1414,6 +1700,54 @@
1414
1700
  return typeof zIndex === "number" ? zIndex : "auto";
1415
1701
  };
1416
1702
  /**
1703
+ * Attempt to detect if ZeroClipboard is executing inside of a sandboxed iframe.
1704
+ * If it is, Flash Player cannot be used, so ZeroClipboard is dead in the water.
1705
+ *
1706
+ * @see {@link http://lists.w3.org/Archives/Public/public-whatwg-archive/2014Dec/0002.html}
1707
+ * @see {@link https://github.com/zeroclipboard/zeroclipboard/issues/511}
1708
+ * @see {@link http://zeroclipboard.org/test-iframes.html}
1709
+ *
1710
+ * @returns `true` (is sandboxed), `false` (is not sandboxed), or `null` (uncertain)
1711
+ * @private
1712
+ */
1713
+ var _detectSandbox = function(doNotReassessFlashSupport) {
1714
+ var effectiveScriptOrigin, frame, frameError, previousState = _flashState.sandboxed, isSandboxed = null;
1715
+ doNotReassessFlashSupport = doNotReassessFlashSupport === true;
1716
+ if (_pageIsFramed === false) {
1717
+ isSandboxed = false;
1718
+ } else {
1719
+ try {
1720
+ frame = window.frameElement || null;
1721
+ } catch (e) {
1722
+ frameError = {
1723
+ name: e.name,
1724
+ message: e.message
1725
+ };
1726
+ }
1727
+ if (frame && frame.nodeType === 1 && frame.nodeName === "IFRAME") {
1728
+ try {
1729
+ isSandboxed = frame.hasAttribute("sandbox");
1730
+ } catch (e) {
1731
+ isSandboxed = null;
1732
+ }
1733
+ } else {
1734
+ try {
1735
+ effectiveScriptOrigin = document.domain || null;
1736
+ } catch (e) {
1737
+ effectiveScriptOrigin = null;
1738
+ }
1739
+ if (effectiveScriptOrigin === null || frameError && frameError.name === "SecurityError" && /(^|[\s\(\[@])sandbox(es|ed|ing|[\s\.,!\)\]@]|$)/.test(frameError.message.toLowerCase())) {
1740
+ isSandboxed = true;
1741
+ }
1742
+ }
1743
+ }
1744
+ _flashState.sandboxed = isSandboxed;
1745
+ if (previousState !== isSandboxed && !doNotReassessFlashSupport) {
1746
+ _detectFlashSupport(_ActiveXObject);
1747
+ }
1748
+ return isSandboxed;
1749
+ };
1750
+ /**
1417
1751
  * Detect the Flash Player status, version, and plugin type.
1418
1752
  *
1419
1753
  * @see {@link https://code.google.com/p/doctype-mirror/wiki/ArticleDetectFlash#The_code}
@@ -1495,6 +1829,10 @@
1495
1829
  */
1496
1830
  _detectFlashSupport(_ActiveXObject);
1497
1831
  /**
1832
+ * Always assess the `sandboxed` state of the page at important Flash-related moments.
1833
+ */
1834
+ _detectSandbox(true);
1835
+ /**
1498
1836
  * A shell constructor for `ZeroClipboard` client instances.
1499
1837
  *
1500
1838
  * @constructor
@@ -1515,7 +1853,7 @@
1515
1853
  * @property {string}
1516
1854
  */
1517
1855
  _defineProperty(ZeroClipboard, "version", {
1518
- value: "2.1.2",
1856
+ value: "2.2.0",
1519
1857
  writable: false,
1520
1858
  configurable: true,
1521
1859
  enumerable: true
@@ -1738,7 +2076,10 @@
1738
2076
  * @private
1739
2077
  */
1740
2078
  var _clientOn = function(eventType, listener) {
1741
- var i, len, events, added = {}, handlers = _clientMeta[this.id] && _clientMeta[this.id].handlers;
2079
+ var i, len, events, added = {}, meta = _clientMeta[this.id], handlers = meta && meta.handlers;
2080
+ if (!meta) {
2081
+ throw new Error("Attempted to add new listener(s) to a destroyed ZeroClipboard client instance");
2082
+ }
1742
2083
  if (typeof eventType === "string" && eventType) {
1743
2084
  events = eventType.toLowerCase().split(/\s+/);
1744
2085
  } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") {
@@ -1764,17 +2105,24 @@
1764
2105
  });
1765
2106
  }
1766
2107
  if (added.error) {
1767
- var errorTypes = [ "disabled", "outdated", "unavailable", "deactivated", "overdue" ];
1768
- for (i = 0, len = errorTypes.length; i < len; i++) {
1769
- if (_flashState[errorTypes[i]]) {
2108
+ for (i = 0, len = _flashStateErrorNames.length; i < len; i++) {
2109
+ if (_flashState[_flashStateErrorNames[i].replace(/^flash-/, "")]) {
1770
2110
  this.emit({
1771
2111
  type: "error",
1772
- name: "flash-" + errorTypes[i],
2112
+ name: _flashStateErrorNames[i],
1773
2113
  client: this
1774
2114
  });
1775
2115
  break;
1776
2116
  }
1777
2117
  }
2118
+ if (_zcSwfVersion !== undefined && ZeroClipboard.version !== _zcSwfVersion) {
2119
+ this.emit({
2120
+ type: "error",
2121
+ name: "version-mismatch",
2122
+ jsVersion: ZeroClipboard.version,
2123
+ swfVersion: _zcSwfVersion
2124
+ });
2125
+ }
1778
2126
  }
1779
2127
  }
1780
2128
  return this;
@@ -1784,7 +2132,10 @@
1784
2132
  * @private
1785
2133
  */
1786
2134
  var _clientOff = function(eventType, listener) {
1787
- var i, len, foundIndex, events, perEventHandlers, handlers = _clientMeta[this.id] && _clientMeta[this.id].handlers;
2135
+ var i, len, foundIndex, events, perEventHandlers, meta = _clientMeta[this.id], handlers = meta && meta.handlers;
2136
+ if (!handlers) {
2137
+ return this;
2138
+ }
1788
2139
  if (arguments.length === 0) {
1789
2140
  events = _keys(handlers);
1790
2141
  } else if (typeof eventType === "string" && eventType) {
@@ -1851,6 +2202,9 @@
1851
2202
  * @private
1852
2203
  */
1853
2204
  var _clientClip = function(elements) {
2205
+ if (!_clientMeta[this.id]) {
2206
+ throw new Error("Attempted to clip element(s) to a destroyed ZeroClipboard client instance");
2207
+ }
1854
2208
  elements = _prepClip(elements);
1855
2209
  for (var i = 0; i < elements.length; i++) {
1856
2210
  if (_hasOwn.call(elements, i) && elements[i] && elements[i].nodeType === 1) {
@@ -1923,6 +2277,9 @@
1923
2277
  * @private
1924
2278
  */
1925
2279
  var _clientDestroy = function() {
2280
+ if (!_clientMeta[this.id]) {
2281
+ return;
2282
+ }
1926
2283
  this.unclip();
1927
2284
  this.off();
1928
2285
  delete _clientMeta[this.id];
@@ -1938,12 +2295,13 @@
1938
2295
  if (event.client && event.client !== this) {
1939
2296
  return false;
1940
2297
  }
1941
- var clippedEls = _clientMeta[this.id] && _clientMeta[this.id].elements;
2298
+ var meta = _clientMeta[this.id];
2299
+ var clippedEls = meta && meta.elements;
1942
2300
  var hasClippedEls = !!clippedEls && clippedEls.length > 0;
1943
2301
  var goodTarget = !event.target || hasClippedEls && clippedEls.indexOf(event.target) !== -1;
1944
2302
  var goodRelTarget = event.relatedTarget && hasClippedEls && clippedEls.indexOf(event.relatedTarget) !== -1;
1945
2303
  var goodClient = event.client && event.client === this;
1946
- if (!(goodTarget || goodRelTarget || goodClient)) {
2304
+ if (!meta || !(goodTarget || goodRelTarget || goodClient)) {
1947
2305
  return false;
1948
2306
  }
1949
2307
  return true;
@@ -1951,16 +2309,17 @@
1951
2309
  /**
1952
2310
  * Handle the actual dispatching of events to a client instance.
1953
2311
  *
1954
- * @returns `this`
2312
+ * @returns `undefined`
1955
2313
  * @private
1956
2314
  */
1957
2315
  var _clientDispatchCallbacks = function(event) {
1958
- if (!(typeof event === "object" && event && event.type)) {
2316
+ var meta = _clientMeta[this.id];
2317
+ if (!(typeof event === "object" && event && event.type && meta)) {
1959
2318
  return;
1960
2319
  }
1961
2320
  var async = _shouldPerformAsync(event);
1962
- var wildcardTypeHandlers = _clientMeta[this.id] && _clientMeta[this.id].handlers["*"] || [];
1963
- var specificTypeHandlers = _clientMeta[this.id] && _clientMeta[this.id].handlers[event.type] || [];
2321
+ var wildcardTypeHandlers = meta && meta.handlers["*"] || [];
2322
+ var specificTypeHandlers = meta && meta.handlers[event.type] || [];
1964
2323
  var handlers = wildcardTypeHandlers.concat(specificTypeHandlers);
1965
2324
  if (handlers && handlers.length) {
1966
2325
  var i, len, func, context, eventCopy, originalContext = this;
@@ -1980,7 +2339,6 @@
1980
2339
  }
1981
2340
  }
1982
2341
  }
1983
- return this;
1984
2342
  };
1985
2343
  /**
1986
2344
  * Prepares the elements for clipping/unclipping.
@@ -2142,6 +2500,9 @@
2142
2500
  * @returns `this`
2143
2501
  */
2144
2502
  ZeroClipboard.prototype.setText = function(text) {
2503
+ if (!_clientMeta[this.id]) {
2504
+ throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");
2505
+ }
2145
2506
  ZeroClipboard.setData("text/plain", text);
2146
2507
  return this;
2147
2508
  };
@@ -2151,6 +2512,9 @@
2151
2512
  * @returns `this`
2152
2513
  */
2153
2514
  ZeroClipboard.prototype.setHtml = function(html) {
2515
+ if (!_clientMeta[this.id]) {
2516
+ throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");
2517
+ }
2154
2518
  ZeroClipboard.setData("text/html", html);
2155
2519
  return this;
2156
2520
  };
@@ -2160,6 +2524,9 @@
2160
2524
  * @returns `this`
2161
2525
  */
2162
2526
  ZeroClipboard.prototype.setRichText = function(richText) {
2527
+ if (!_clientMeta[this.id]) {
2528
+ throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");
2529
+ }
2163
2530
  ZeroClipboard.setData("application/rtf", richText);
2164
2531
  return this;
2165
2532
  };
@@ -2169,6 +2536,9 @@
2169
2536
  * @returns `this`
2170
2537
  */
2171
2538
  ZeroClipboard.prototype.setData = function() {
2539
+ if (!_clientMeta[this.id]) {
2540
+ throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");
2541
+ }
2172
2542
  ZeroClipboard.setData.apply(this, _args(arguments));
2173
2543
  return this;
2174
2544
  };
@@ -2179,6 +2549,9 @@
2179
2549
  * @returns `this`
2180
2550
  */
2181
2551
  ZeroClipboard.prototype.clearData = function() {
2552
+ if (!_clientMeta[this.id]) {
2553
+ throw new Error("Attempted to clear pending clipboard data from a destroyed ZeroClipboard client instance");
2554
+ }
2182
2555
  ZeroClipboard.clearData.apply(this, _args(arguments));
2183
2556
  return this;
2184
2557
  };
@@ -2189,6 +2562,9 @@
2189
2562
  * @returns `String` or `Object`
2190
2563
  */
2191
2564
  ZeroClipboard.prototype.getData = function() {
2565
+ if (!_clientMeta[this.id]) {
2566
+ throw new Error("Attempted to get pending clipboard data from a destroyed ZeroClipboard client instance");
2567
+ }
2192
2568
  return ZeroClipboard.getData.apply(this, _args(arguments));
2193
2569
  };
2194
2570
  if (typeof define === "function" && define.amd) {
@@ -1,2 +1,4 @@
1
1
  //= depend_on_asset "ZeroClipboard.swf"
2
- ZeroClipboard.config( { swfPath: '<%= asset_path 'ZeroClipboard.swf' %>' } );
2
+ ZeroClipboard.config({
3
+ swfPath: '<%= image_path "ZeroClipboard.swf" %>'
4
+ });
@@ -1,5 +1,5 @@
1
1
  module Zeroclipboard
2
2
  module Rails
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.1"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zeroclipboard-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henrik Wenz
@@ -9,20 +9,20 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-06-25 00:00:00.000000000 Z
12
+ date: 2015-08-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: railties
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - '>='
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: '3.1'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - '>='
25
+ - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: '3.1'
28
28
  description: ZeroClipboard libary support for Rails
@@ -50,19 +50,18 @@ require_paths:
50
50
  - lib
51
51
  required_ruby_version: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - '>='
53
+ - - ">="
54
54
  - !ruby/object:Gem::Version
55
55
  version: '0'
56
56
  required_rubygems_version: !ruby/object:Gem::Requirement
57
57
  requirements:
58
- - - '>='
58
+ - - ">="
59
59
  - !ruby/object:Gem::Version
60
60
  version: '0'
61
61
  requirements: []
62
62
  rubyforge_project:
63
- rubygems_version: 2.2.2
63
+ rubygems_version: 2.4.8
64
64
  signing_key:
65
65
  specification_version: 4
66
66
  summary: Adds the Javascript ZeroClipboard libary to Rails
67
67
  test_files: []
68
- has_rdoc: