zeroclipboard-rails 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: