jquery.zeroclipboard.js 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881
  1. /*!
  2. * jquery.zeroclipboard
  3. * Bind to the `beforecopy`, `copy`, `aftercopy`, and `copy-error` events, custom DOM-like events for clipboard injection generated using jQuery's Special Events API and ZeroClipboard's Core module.
  4. * Copyright (c) 2014
  5. * Licensed MIT
  6. * https://github.com/zeroclipboard/jquery.zeroclipboard
  7. * v0.2.0
  8. */
  9. (function($, window, undefined) {
  10. "use strict";
  11. var require, module, exports;
  12. var zcExistsAlready = !!window.ZeroClipboard;
  13. /*!
  14. * ZeroClipboard
  15. * The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface.
  16. * Copyright (c) 2014 Jon Rohan, James M. Greene
  17. * Licensed MIT
  18. * http://zeroclipboard.org/
  19. * v2.1.2
  20. */
  21. (function(window, undefined) {
  22. /**
  23. * Store references to critically important global functions that may be
  24. * overridden on certain web pages.
  25. */
  26. 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;
  27. /**
  28. * Convert an `arguments` object into an Array.
  29. *
  30. * @returns The arguments as an Array
  31. * @private
  32. */
  33. var _args = function(argumentsObj) {
  34. return _slice.call(argumentsObj, 0);
  35. };
  36. /**
  37. * Shallow-copy the owned, enumerable properties of one object over to another, similar to jQuery's `$.extend`.
  38. *
  39. * @returns The target object, augmented
  40. * @private
  41. */
  42. var _extend = function() {
  43. var i, len, arg, prop, src, copy, args = _args(arguments), target = args[0] || {};
  44. for (i = 1, len = args.length; i < len; i++) {
  45. if ((arg = args[i]) != null) {
  46. for (prop in arg) {
  47. if (_hasOwn.call(arg, prop)) {
  48. src = target[prop];
  49. copy = arg[prop];
  50. if (target !== copy && copy !== undefined) {
  51. target[prop] = copy;
  52. }
  53. }
  54. }
  55. }
  56. }
  57. return target;
  58. };
  59. /**
  60. * Return a deep copy of the source object or array.
  61. *
  62. * @returns Object or Array
  63. * @private
  64. */
  65. var _deepCopy = function(source) {
  66. var copy, i, len, prop;
  67. if (typeof source !== "object" || source == null) {
  68. copy = source;
  69. } else if (typeof source.length === "number") {
  70. copy = [];
  71. for (i = 0, len = source.length; i < len; i++) {
  72. if (_hasOwn.call(source, i)) {
  73. copy[i] = _deepCopy(source[i]);
  74. }
  75. }
  76. } else {
  77. copy = {};
  78. for (prop in source) {
  79. if (_hasOwn.call(source, prop)) {
  80. copy[prop] = _deepCopy(source[prop]);
  81. }
  82. }
  83. }
  84. return copy;
  85. };
  86. /**
  87. * Makes a shallow copy of `obj` (like `_extend`) but filters its properties based on a list of `keys` to keep.
  88. * The inverse of `_omit`, mostly. The big difference is that these properties do NOT need to be enumerable to
  89. * be kept.
  90. *
  91. * @returns A new filtered object.
  92. * @private
  93. */
  94. var _pick = function(obj, keys) {
  95. var newObj = {};
  96. for (var i = 0, len = keys.length; i < len; i++) {
  97. if (keys[i] in obj) {
  98. newObj[keys[i]] = obj[keys[i]];
  99. }
  100. }
  101. return newObj;
  102. };
  103. /**
  104. * Makes a shallow copy of `obj` (like `_extend`) but filters its properties based on a list of `keys` to omit.
  105. * The inverse of `_pick`.
  106. *
  107. * @returns A new filtered object.
  108. * @private
  109. */
  110. var _omit = function(obj, keys) {
  111. var newObj = {};
  112. for (var prop in obj) {
  113. if (keys.indexOf(prop) === -1) {
  114. newObj[prop] = obj[prop];
  115. }
  116. }
  117. return newObj;
  118. };
  119. /**
  120. * Remove all owned, enumerable properties from an object.
  121. *
  122. * @returns The original object without its owned, enumerable properties.
  123. * @private
  124. */
  125. var _deleteOwnProperties = function(obj) {
  126. if (obj) {
  127. for (var prop in obj) {
  128. if (_hasOwn.call(obj, prop)) {
  129. delete obj[prop];
  130. }
  131. }
  132. }
  133. return obj;
  134. };
  135. /**
  136. * Determine if an element is contained within another element.
  137. *
  138. * @returns Boolean
  139. * @private
  140. */
  141. var _containedBy = function(el, ancestorEl) {
  142. if (el && el.nodeType === 1 && el.ownerDocument && ancestorEl && (ancestorEl.nodeType === 1 && ancestorEl.ownerDocument && ancestorEl.ownerDocument === el.ownerDocument || ancestorEl.nodeType === 9 && !ancestorEl.ownerDocument && ancestorEl === el.ownerDocument)) {
  143. do {
  144. if (el === ancestorEl) {
  145. return true;
  146. }
  147. el = el.parentNode;
  148. } while (el);
  149. }
  150. return false;
  151. };
  152. /**
  153. * Keep track of the state of the Flash object.
  154. * @private
  155. */
  156. var _flashState = {
  157. bridge: null,
  158. version: "0.0.0",
  159. pluginType: "unknown",
  160. disabled: null,
  161. outdated: null,
  162. unavailable: null,
  163. deactivated: null,
  164. overdue: null,
  165. ready: null
  166. };
  167. /**
  168. * The minimum Flash Player version required to use ZeroClipboard completely.
  169. * @readonly
  170. * @private
  171. */
  172. var _minimumFlashVersion = "11.0.0";
  173. /**
  174. * Keep track of all event listener registrations.
  175. * @private
  176. */
  177. var _handlers = {};
  178. /**
  179. * Keep track of the currently activated element.
  180. * @private
  181. */
  182. var _currentElement;
  183. /**
  184. * Keep track of data for the pending clipboard transaction.
  185. * @private
  186. */
  187. var _clipData = {};
  188. /**
  189. * Keep track of data formats for the pending clipboard transaction.
  190. * @private
  191. */
  192. var _clipDataFormatMap = null;
  193. /**
  194. * The `message` store for events
  195. * @private
  196. */
  197. var _eventMessages = {
  198. ready: "Flash communication is established",
  199. error: {
  200. "flash-disabled": "Flash is disabled or not installed",
  201. "flash-outdated": "Flash is too outdated to support ZeroClipboard",
  202. "flash-unavailable": "Flash is unable to communicate bidirectionally with JavaScript",
  203. "flash-deactivated": "Flash is too outdated for your browser and/or is configured as click-to-activate",
  204. "flash-overdue": "Flash communication was established but NOT within the acceptable time limit"
  205. }
  206. };
  207. /**
  208. * The presumed location of the "ZeroClipboard.swf" file, based on the location
  209. * of the executing JavaScript file (e.g. "ZeroClipboard.js", etc.).
  210. * @private
  211. */
  212. var _swfPath = function() {
  213. var i, jsDir, tmpJsPath, jsPath, swfPath = "ZeroClipboard.swf";
  214. if (!(_document.currentScript && (jsPath = _document.currentScript.src))) {
  215. var scripts = _document.getElementsByTagName("script");
  216. if ("readyState" in scripts[0]) {
  217. for (i = scripts.length; i--; ) {
  218. if (scripts[i].readyState === "interactive" && (jsPath = scripts[i].src)) {
  219. break;
  220. }
  221. }
  222. } else if (_document.readyState === "loading") {
  223. jsPath = scripts[scripts.length - 1].src;
  224. } else {
  225. for (i = scripts.length; i--; ) {
  226. tmpJsPath = scripts[i].src;
  227. if (!tmpJsPath) {
  228. jsDir = null;
  229. break;
  230. }
  231. tmpJsPath = tmpJsPath.split("#")[0].split("?")[0];
  232. tmpJsPath = tmpJsPath.slice(0, tmpJsPath.lastIndexOf("/") + 1);
  233. if (jsDir == null) {
  234. jsDir = tmpJsPath;
  235. } else if (jsDir !== tmpJsPath) {
  236. jsDir = null;
  237. break;
  238. }
  239. }
  240. if (jsDir !== null) {
  241. jsPath = jsDir;
  242. }
  243. }
  244. }
  245. if (jsPath) {
  246. jsPath = jsPath.split("#")[0].split("?")[0];
  247. swfPath = jsPath.slice(0, jsPath.lastIndexOf("/") + 1) + swfPath;
  248. }
  249. return swfPath;
  250. }();
  251. /**
  252. * ZeroClipboard configuration defaults for the Core module.
  253. * @private
  254. */
  255. var _globalConfig = {
  256. swfPath: _swfPath,
  257. trustedDomains: window.location.host ? [ window.location.host ] : [],
  258. cacheBust: true,
  259. forceEnhancedClipboard: false,
  260. flashLoadTimeout: 3e4,
  261. autoActivate: true,
  262. bubbleEvents: true,
  263. containerId: "global-zeroclipboard-html-bridge",
  264. containerClass: "global-zeroclipboard-container",
  265. swfObjectId: "global-zeroclipboard-flash-bridge",
  266. hoverClass: "zeroclipboard-is-hover",
  267. activeClass: "zeroclipboard-is-active",
  268. forceHandCursor: false,
  269. title: null,
  270. zIndex: 999999999
  271. };
  272. /**
  273. * The underlying implementation of `ZeroClipboard.config`.
  274. * @private
  275. */
  276. var _config = function(options) {
  277. if (typeof options === "object" && options !== null) {
  278. for (var prop in options) {
  279. if (_hasOwn.call(options, prop)) {
  280. if (/^(?:forceHandCursor|title|zIndex|bubbleEvents)$/.test(prop)) {
  281. _globalConfig[prop] = options[prop];
  282. } else if (_flashState.bridge == null) {
  283. if (prop === "containerId" || prop === "swfObjectId") {
  284. if (_isValidHtml4Id(options[prop])) {
  285. _globalConfig[prop] = options[prop];
  286. } else {
  287. throw new Error("The specified `" + prop + "` value is not valid as an HTML4 Element ID");
  288. }
  289. } else {
  290. _globalConfig[prop] = options[prop];
  291. }
  292. }
  293. }
  294. }
  295. }
  296. if (typeof options === "string" && options) {
  297. if (_hasOwn.call(_globalConfig, options)) {
  298. return _globalConfig[options];
  299. }
  300. return;
  301. }
  302. return _deepCopy(_globalConfig);
  303. };
  304. /**
  305. * The underlying implementation of `ZeroClipboard.state`.
  306. * @private
  307. */
  308. var _state = function() {
  309. return {
  310. browser: _pick(_navigator, [ "userAgent", "platform", "appName" ]),
  311. flash: _omit(_flashState, [ "bridge" ]),
  312. zeroclipboard: {
  313. version: ZeroClipboard.version,
  314. config: ZeroClipboard.config()
  315. }
  316. };
  317. };
  318. /**
  319. * The underlying implementation of `ZeroClipboard.isFlashUnusable`.
  320. * @private
  321. */
  322. var _isFlashUnusable = function() {
  323. return !!(_flashState.disabled || _flashState.outdated || _flashState.unavailable || _flashState.deactivated);
  324. };
  325. /**
  326. * The underlying implementation of `ZeroClipboard.on`.
  327. * @private
  328. */
  329. var _on = function(eventType, listener) {
  330. var i, len, events, added = {};
  331. if (typeof eventType === "string" && eventType) {
  332. events = eventType.toLowerCase().split(/\s+/);
  333. } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") {
  334. for (i in eventType) {
  335. if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") {
  336. ZeroClipboard.on(i, eventType[i]);
  337. }
  338. }
  339. }
  340. if (events && events.length) {
  341. for (i = 0, len = events.length; i < len; i++) {
  342. eventType = events[i].replace(/^on/, "");
  343. added[eventType] = true;
  344. if (!_handlers[eventType]) {
  345. _handlers[eventType] = [];
  346. }
  347. _handlers[eventType].push(listener);
  348. }
  349. if (added.ready && _flashState.ready) {
  350. ZeroClipboard.emit({
  351. type: "ready"
  352. });
  353. }
  354. if (added.error) {
  355. var errorTypes = [ "disabled", "outdated", "unavailable", "deactivated", "overdue" ];
  356. for (i = 0, len = errorTypes.length; i < len; i++) {
  357. if (_flashState[errorTypes[i]] === true) {
  358. ZeroClipboard.emit({
  359. type: "error",
  360. name: "flash-" + errorTypes[i]
  361. });
  362. break;
  363. }
  364. }
  365. }
  366. }
  367. return ZeroClipboard;
  368. };
  369. /**
  370. * The underlying implementation of `ZeroClipboard.off`.
  371. * @private
  372. */
  373. var _off = function(eventType, listener) {
  374. var i, len, foundIndex, events, perEventHandlers;
  375. if (arguments.length === 0) {
  376. events = _keys(_handlers);
  377. } else if (typeof eventType === "string" && eventType) {
  378. events = eventType.split(/\s+/);
  379. } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") {
  380. for (i in eventType) {
  381. if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") {
  382. ZeroClipboard.off(i, eventType[i]);
  383. }
  384. }
  385. }
  386. if (events && events.length) {
  387. for (i = 0, len = events.length; i < len; i++) {
  388. eventType = events[i].toLowerCase().replace(/^on/, "");
  389. perEventHandlers = _handlers[eventType];
  390. if (perEventHandlers && perEventHandlers.length) {
  391. if (listener) {
  392. foundIndex = perEventHandlers.indexOf(listener);
  393. while (foundIndex !== -1) {
  394. perEventHandlers.splice(foundIndex, 1);
  395. foundIndex = perEventHandlers.indexOf(listener, foundIndex);
  396. }
  397. } else {
  398. perEventHandlers.length = 0;
  399. }
  400. }
  401. }
  402. }
  403. return ZeroClipboard;
  404. };
  405. /**
  406. * The underlying implementation of `ZeroClipboard.handlers`.
  407. * @private
  408. */
  409. var _listeners = function(eventType) {
  410. var copy;
  411. if (typeof eventType === "string" && eventType) {
  412. copy = _deepCopy(_handlers[eventType]) || null;
  413. } else {
  414. copy = _deepCopy(_handlers);
  415. }
  416. return copy;
  417. };
  418. /**
  419. * The underlying implementation of `ZeroClipboard.emit`.
  420. * @private
  421. */
  422. var _emit = function(event) {
  423. var eventCopy, returnVal, tmp;
  424. event = _createEvent(event);
  425. if (!event) {
  426. return;
  427. }
  428. if (_preprocessEvent(event)) {
  429. return;
  430. }
  431. if (event.type === "ready" && _flashState.overdue === true) {
  432. return ZeroClipboard.emit({
  433. type: "error",
  434. name: "flash-overdue"
  435. });
  436. }
  437. eventCopy = _extend({}, event);
  438. _dispatchCallbacks.call(this, eventCopy);
  439. if (event.type === "copy") {
  440. tmp = _mapClipDataToFlash(_clipData);
  441. returnVal = tmp.data;
  442. _clipDataFormatMap = tmp.formatMap;
  443. }
  444. return returnVal;
  445. };
  446. /**
  447. * The underlying implementation of `ZeroClipboard.create`.
  448. * @private
  449. */
  450. var _create = function() {
  451. if (typeof _flashState.ready !== "boolean") {
  452. _flashState.ready = false;
  453. }
  454. if (!ZeroClipboard.isFlashUnusable() && _flashState.bridge === null) {
  455. var maxWait = _globalConfig.flashLoadTimeout;
  456. if (typeof maxWait === "number" && maxWait >= 0) {
  457. _setTimeout(function() {
  458. if (typeof _flashState.deactivated !== "boolean") {
  459. _flashState.deactivated = true;
  460. }
  461. if (_flashState.deactivated === true) {
  462. ZeroClipboard.emit({
  463. type: "error",
  464. name: "flash-deactivated"
  465. });
  466. }
  467. }, maxWait);
  468. }
  469. _flashState.overdue = false;
  470. _embedSwf();
  471. }
  472. };
  473. /**
  474. * The underlying implementation of `ZeroClipboard.destroy`.
  475. * @private
  476. */
  477. var _destroy = function() {
  478. ZeroClipboard.clearData();
  479. ZeroClipboard.blur();
  480. ZeroClipboard.emit("destroy");
  481. _unembedSwf();
  482. ZeroClipboard.off();
  483. };
  484. /**
  485. * The underlying implementation of `ZeroClipboard.setData`.
  486. * @private
  487. */
  488. var _setData = function(format, data) {
  489. var dataObj;
  490. if (typeof format === "object" && format && typeof data === "undefined") {
  491. dataObj = format;
  492. ZeroClipboard.clearData();
  493. } else if (typeof format === "string" && format) {
  494. dataObj = {};
  495. dataObj[format] = data;
  496. } else {
  497. return;
  498. }
  499. for (var dataFormat in dataObj) {
  500. if (typeof dataFormat === "string" && dataFormat && _hasOwn.call(dataObj, dataFormat) && typeof dataObj[dataFormat] === "string" && dataObj[dataFormat]) {
  501. _clipData[dataFormat] = dataObj[dataFormat];
  502. }
  503. }
  504. };
  505. /**
  506. * The underlying implementation of `ZeroClipboard.clearData`.
  507. * @private
  508. */
  509. var _clearData = function(format) {
  510. if (typeof format === "undefined") {
  511. _deleteOwnProperties(_clipData);
  512. _clipDataFormatMap = null;
  513. } else if (typeof format === "string" && _hasOwn.call(_clipData, format)) {
  514. delete _clipData[format];
  515. }
  516. };
  517. /**
  518. * The underlying implementation of `ZeroClipboard.getData`.
  519. * @private
  520. */
  521. var _getData = function(format) {
  522. if (typeof format === "undefined") {
  523. return _deepCopy(_clipData);
  524. } else if (typeof format === "string" && _hasOwn.call(_clipData, format)) {
  525. return _clipData[format];
  526. }
  527. };
  528. /**
  529. * The underlying implementation of `ZeroClipboard.focus`/`ZeroClipboard.activate`.
  530. * @private
  531. */
  532. var _focus = function(element) {
  533. if (!(element && element.nodeType === 1)) {
  534. return;
  535. }
  536. if (_currentElement) {
  537. _removeClass(_currentElement, _globalConfig.activeClass);
  538. if (_currentElement !== element) {
  539. _removeClass(_currentElement, _globalConfig.hoverClass);
  540. }
  541. }
  542. _currentElement = element;
  543. _addClass(element, _globalConfig.hoverClass);
  544. var newTitle = element.getAttribute("title") || _globalConfig.title;
  545. if (typeof newTitle === "string" && newTitle) {
  546. var htmlBridge = _getHtmlBridge(_flashState.bridge);
  547. if (htmlBridge) {
  548. htmlBridge.setAttribute("title", newTitle);
  549. }
  550. }
  551. var useHandCursor = _globalConfig.forceHandCursor === true || _getStyle(element, "cursor") === "pointer";
  552. _setHandCursor(useHandCursor);
  553. _reposition();
  554. };
  555. /**
  556. * The underlying implementation of `ZeroClipboard.blur`/`ZeroClipboard.deactivate`.
  557. * @private
  558. */
  559. var _blur = function() {
  560. var htmlBridge = _getHtmlBridge(_flashState.bridge);
  561. if (htmlBridge) {
  562. htmlBridge.removeAttribute("title");
  563. htmlBridge.style.left = "0px";
  564. htmlBridge.style.top = "-9999px";
  565. htmlBridge.style.width = "1px";
  566. htmlBridge.style.top = "1px";
  567. }
  568. if (_currentElement) {
  569. _removeClass(_currentElement, _globalConfig.hoverClass);
  570. _removeClass(_currentElement, _globalConfig.activeClass);
  571. _currentElement = null;
  572. }
  573. };
  574. /**
  575. * The underlying implementation of `ZeroClipboard.activeElement`.
  576. * @private
  577. */
  578. var _activeElement = function() {
  579. return _currentElement || null;
  580. };
  581. /**
  582. * Check if a value is a valid HTML4 `ID` or `Name` token.
  583. * @private
  584. */
  585. var _isValidHtml4Id = function(id) {
  586. return typeof id === "string" && id && /^[A-Za-z][A-Za-z0-9_:\-\.]*$/.test(id);
  587. };
  588. /**
  589. * Create or update an `event` object, based on the `eventType`.
  590. * @private
  591. */
  592. var _createEvent = function(event) {
  593. var eventType;
  594. if (typeof event === "string" && event) {
  595. eventType = event;
  596. event = {};
  597. } else if (typeof event === "object" && event && typeof event.type === "string" && event.type) {
  598. eventType = event.type;
  599. }
  600. if (!eventType) {
  601. return;
  602. }
  603. _extend(event, {
  604. type: eventType.toLowerCase(),
  605. target: event.target || _currentElement || null,
  606. relatedTarget: event.relatedTarget || null,
  607. currentTarget: _flashState && _flashState.bridge || null,
  608. timeStamp: event.timeStamp || _now() || null
  609. });
  610. var msg = _eventMessages[event.type];
  611. if (event.type === "error" && event.name && msg) {
  612. msg = msg[event.name];
  613. }
  614. if (msg) {
  615. event.message = msg;
  616. }
  617. if (event.type === "ready") {
  618. _extend(event, {
  619. target: null,
  620. version: _flashState.version
  621. });
  622. }
  623. if (event.type === "error") {
  624. if (/^flash-(disabled|outdated|unavailable|deactivated|overdue)$/.test(event.name)) {
  625. _extend(event, {
  626. target: null,
  627. minimumVersion: _minimumFlashVersion
  628. });
  629. }
  630. if (/^flash-(outdated|unavailable|deactivated|overdue)$/.test(event.name)) {
  631. _extend(event, {
  632. version: _flashState.version
  633. });
  634. }
  635. }
  636. if (event.type === "copy") {
  637. event.clipboardData = {
  638. setData: ZeroClipboard.setData,
  639. clearData: ZeroClipboard.clearData
  640. };
  641. }
  642. if (event.type === "aftercopy") {
  643. event = _mapClipResultsFromFlash(event, _clipDataFormatMap);
  644. }
  645. if (event.target && !event.relatedTarget) {
  646. event.relatedTarget = _getRelatedTarget(event.target);
  647. }
  648. event = _addMouseData(event);
  649. return event;
  650. };
  651. /**
  652. * Get a relatedTarget from the target's `data-clipboard-target` attribute
  653. * @private
  654. */
  655. var _getRelatedTarget = function(targetEl) {
  656. var relatedTargetId = targetEl && targetEl.getAttribute && targetEl.getAttribute("data-clipboard-target");
  657. return relatedTargetId ? _document.getElementById(relatedTargetId) : null;
  658. };
  659. /**
  660. * Add element and position data to `MouseEvent` instances
  661. * @private
  662. */
  663. var _addMouseData = function(event) {
  664. if (event && /^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) {
  665. var srcElement = event.target;
  666. var fromElement = event.type === "_mouseover" && event.relatedTarget ? event.relatedTarget : undefined;
  667. var toElement = event.type === "_mouseout" && event.relatedTarget ? event.relatedTarget : undefined;
  668. var pos = _getDOMObjectPosition(srcElement);
  669. var screenLeft = _window.screenLeft || _window.screenX || 0;
  670. var screenTop = _window.screenTop || _window.screenY || 0;
  671. var scrollLeft = _document.body.scrollLeft + _document.documentElement.scrollLeft;
  672. var scrollTop = _document.body.scrollTop + _document.documentElement.scrollTop;
  673. var pageX = pos.left + (typeof event._stageX === "number" ? event._stageX : 0);
  674. var pageY = pos.top + (typeof event._stageY === "number" ? event._stageY : 0);
  675. var clientX = pageX - scrollLeft;
  676. var clientY = pageY - scrollTop;
  677. var screenX = screenLeft + clientX;
  678. var screenY = screenTop + clientY;
  679. var moveX = typeof event.movementX === "number" ? event.movementX : 0;
  680. var moveY = typeof event.movementY === "number" ? event.movementY : 0;
  681. delete event._stageX;
  682. delete event._stageY;
  683. _extend(event, {
  684. srcElement: srcElement,
  685. fromElement: fromElement,
  686. toElement: toElement,
  687. screenX: screenX,
  688. screenY: screenY,
  689. pageX: pageX,
  690. pageY: pageY,
  691. clientX: clientX,
  692. clientY: clientY,
  693. x: clientX,
  694. y: clientY,
  695. movementX: moveX,
  696. movementY: moveY,
  697. offsetX: 0,
  698. offsetY: 0,
  699. layerX: 0,
  700. layerY: 0
  701. });
  702. }
  703. return event;
  704. };
  705. /**
  706. * Determine if an event's registered handlers should be execute synchronously or asynchronously.
  707. *
  708. * @returns {boolean}
  709. * @private
  710. */
  711. var _shouldPerformAsync = function(event) {
  712. var eventType = event && typeof event.type === "string" && event.type || "";
  713. return !/^(?:(?:before)?copy|destroy)$/.test(eventType);
  714. };
  715. /**
  716. * Control if a callback should be executed asynchronously or not.
  717. *
  718. * @returns `undefined`
  719. * @private
  720. */
  721. var _dispatchCallback = function(func, context, args, async) {
  722. if (async) {
  723. _setTimeout(function() {
  724. func.apply(context, args);
  725. }, 0);
  726. } else {
  727. func.apply(context, args);
  728. }
  729. };
  730. /**
  731. * Handle the actual dispatching of events to client instances.
  732. *
  733. * @returns `undefined`
  734. * @private
  735. */
  736. var _dispatchCallbacks = function(event) {
  737. if (!(typeof event === "object" && event && event.type)) {
  738. return;
  739. }
  740. var async = _shouldPerformAsync(event);
  741. var wildcardTypeHandlers = _handlers["*"] || [];
  742. var specificTypeHandlers = _handlers[event.type] || [];
  743. var handlers = wildcardTypeHandlers.concat(specificTypeHandlers);
  744. if (handlers && handlers.length) {
  745. var i, len, func, context, eventCopy, originalContext = this;
  746. for (i = 0, len = handlers.length; i < len; i++) {
  747. func = handlers[i];
  748. context = originalContext;
  749. if (typeof func === "string" && typeof _window[func] === "function") {
  750. func = _window[func];
  751. }
  752. if (typeof func === "object" && func && typeof func.handleEvent === "function") {
  753. context = func;
  754. func = func.handleEvent;
  755. }
  756. if (typeof func === "function") {
  757. eventCopy = _extend({}, event);
  758. _dispatchCallback(func, context, [ eventCopy ], async);
  759. }
  760. }
  761. }
  762. return this;
  763. };
  764. /**
  765. * Preprocess any special behaviors, reactions, or state changes after receiving this event.
  766. * Executes only once per event emitted, NOT once per client.
  767. * @private
  768. */
  769. var _preprocessEvent = function(event) {
  770. var element = event.target || _currentElement || null;
  771. var sourceIsSwf = event._source === "swf";
  772. delete event._source;
  773. var flashErrorNames = [ "flash-disabled", "flash-outdated", "flash-unavailable", "flash-deactivated", "flash-overdue" ];
  774. switch (event.type) {
  775. case "error":
  776. if (flashErrorNames.indexOf(event.name) !== -1) {
  777. _extend(_flashState, {
  778. disabled: event.name === "flash-disabled",
  779. outdated: event.name === "flash-outdated",
  780. unavailable: event.name === "flash-unavailable",
  781. deactivated: event.name === "flash-deactivated",
  782. overdue: event.name === "flash-overdue",
  783. ready: false
  784. });
  785. }
  786. break;
  787. case "ready":
  788. var wasDeactivated = _flashState.deactivated === true;
  789. _extend(_flashState, {
  790. disabled: false,
  791. outdated: false,
  792. unavailable: false,
  793. deactivated: false,
  794. overdue: wasDeactivated,
  795. ready: !wasDeactivated
  796. });
  797. break;
  798. case "copy":
  799. var textContent, htmlContent, targetEl = event.relatedTarget;
  800. if (!(_clipData["text/html"] || _clipData["text/plain"]) && targetEl && (htmlContent = targetEl.value || targetEl.outerHTML || targetEl.innerHTML) && (textContent = targetEl.value || targetEl.textContent || targetEl.innerText)) {
  801. event.clipboardData.clearData();
  802. event.clipboardData.setData("text/plain", textContent);
  803. if (htmlContent !== textContent) {
  804. event.clipboardData.setData("text/html", htmlContent);
  805. }
  806. } else if (!_clipData["text/plain"] && event.target && (textContent = event.target.getAttribute("data-clipboard-text"))) {
  807. event.clipboardData.clearData();
  808. event.clipboardData.setData("text/plain", textContent);
  809. }
  810. break;
  811. case "aftercopy":
  812. ZeroClipboard.clearData();
  813. if (element && element !== _safeActiveElement() && element.focus) {
  814. element.focus();
  815. }
  816. break;
  817. case "_mouseover":
  818. ZeroClipboard.focus(element);
  819. if (_globalConfig.bubbleEvents === true && sourceIsSwf) {
  820. if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) {
  821. _fireMouseEvent(_extend({}, event, {
  822. type: "mouseenter",
  823. bubbles: false,
  824. cancelable: false
  825. }));
  826. }
  827. _fireMouseEvent(_extend({}, event, {
  828. type: "mouseover"
  829. }));
  830. }
  831. break;
  832. case "_mouseout":
  833. ZeroClipboard.blur();
  834. if (_globalConfig.bubbleEvents === true && sourceIsSwf) {
  835. if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) {
  836. _fireMouseEvent(_extend({}, event, {
  837. type: "mouseleave",
  838. bubbles: false,
  839. cancelable: false
  840. }));
  841. }
  842. _fireMouseEvent(_extend({}, event, {
  843. type: "mouseout"
  844. }));
  845. }
  846. break;
  847. case "_mousedown":
  848. _addClass(element, _globalConfig.activeClass);
  849. if (_globalConfig.bubbleEvents === true && sourceIsSwf) {
  850. _fireMouseEvent(_extend({}, event, {
  851. type: event.type.slice(1)
  852. }));
  853. }
  854. break;
  855. case "_mouseup":
  856. _removeClass(element, _globalConfig.activeClass);
  857. if (_globalConfig.bubbleEvents === true && sourceIsSwf) {
  858. _fireMouseEvent(_extend({}, event, {
  859. type: event.type.slice(1)
  860. }));
  861. }
  862. break;
  863. case "_click":
  864. case "_mousemove":
  865. if (_globalConfig.bubbleEvents === true && sourceIsSwf) {
  866. _fireMouseEvent(_extend({}, event, {
  867. type: event.type.slice(1)
  868. }));
  869. }
  870. break;
  871. }
  872. if (/^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) {
  873. return true;
  874. }
  875. };
  876. /**
  877. * Dispatch a synthetic MouseEvent.
  878. *
  879. * @returns `undefined`
  880. * @private
  881. */
  882. var _fireMouseEvent = function(event) {
  883. if (!(event && typeof event.type === "string" && event)) {
  884. return;
  885. }
  886. var e, target = event.target || null, doc = target && target.ownerDocument || _document, defaults = {
  887. view: doc.defaultView || _window,
  888. canBubble: true,
  889. cancelable: true,
  890. detail: event.type === "click" ? 1 : 0,
  891. button: typeof event.which === "number" ? event.which - 1 : typeof event.button === "number" ? event.button : doc.createEvent ? 0 : 1
  892. }, args = _extend(defaults, event);
  893. if (!target) {
  894. return;
  895. }
  896. if (doc.createEvent && target.dispatchEvent) {
  897. args = [ args.type, args.canBubble, args.cancelable, args.view, args.detail, args.screenX, args.screenY, args.clientX, args.clientY, args.ctrlKey, args.altKey, args.shiftKey, args.metaKey, args.button, args.relatedTarget ];
  898. e = doc.createEvent("MouseEvents");
  899. if (e.initMouseEvent) {
  900. e.initMouseEvent.apply(e, args);
  901. e._source = "js";
  902. target.dispatchEvent(e);
  903. }
  904. }
  905. };
  906. /**
  907. * Create the HTML bridge element to embed the Flash object into.
  908. * @private
  909. */
  910. var _createHtmlBridge = function() {
  911. var container = _document.createElement("div");
  912. container.id = _globalConfig.containerId;
  913. container.className = _globalConfig.containerClass;
  914. container.style.position = "absolute";
  915. container.style.left = "0px";
  916. container.style.top = "-9999px";
  917. container.style.width = "1px";
  918. container.style.height = "1px";
  919. container.style.zIndex = "" + _getSafeZIndex(_globalConfig.zIndex);
  920. return container;
  921. };
  922. /**
  923. * Get the HTML element container that wraps the Flash bridge object/element.
  924. * @private
  925. */
  926. var _getHtmlBridge = function(flashBridge) {
  927. var htmlBridge = flashBridge && flashBridge.parentNode;
  928. while (htmlBridge && htmlBridge.nodeName === "OBJECT" && htmlBridge.parentNode) {
  929. htmlBridge = htmlBridge.parentNode;
  930. }
  931. return htmlBridge || null;
  932. };
  933. /**
  934. * Create the SWF object.
  935. *
  936. * @returns The SWF object reference.
  937. * @private
  938. */
  939. var _embedSwf = function() {
  940. var len, flashBridge = _flashState.bridge, container = _getHtmlBridge(flashBridge);
  941. if (!flashBridge) {
  942. var allowScriptAccess = _determineScriptAccess(_window.location.host, _globalConfig);
  943. var allowNetworking = allowScriptAccess === "never" ? "none" : "all";
  944. var flashvars = _vars(_globalConfig);
  945. var swfUrl = _globalConfig.swfPath + _cacheBust(_globalConfig.swfPath, _globalConfig);
  946. container = _createHtmlBridge();
  947. var divToBeReplaced = _document.createElement("div");
  948. container.appendChild(divToBeReplaced);
  949. _document.body.appendChild(container);
  950. var tmpDiv = _document.createElement("div");
  951. var oldIE = _flashState.pluginType === "activex";
  952. 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>";
  953. flashBridge = tmpDiv.firstChild;
  954. tmpDiv = null;
  955. flashBridge.ZeroClipboard = ZeroClipboard;
  956. container.replaceChild(flashBridge, divToBeReplaced);
  957. }
  958. if (!flashBridge) {
  959. flashBridge = _document[_globalConfig.swfObjectId];
  960. if (flashBridge && (len = flashBridge.length)) {
  961. flashBridge = flashBridge[len - 1];
  962. }
  963. if (!flashBridge && container) {
  964. flashBridge = container.firstChild;
  965. }
  966. }
  967. _flashState.bridge = flashBridge || null;
  968. return flashBridge;
  969. };
  970. /**
  971. * Destroy the SWF object.
  972. * @private
  973. */
  974. var _unembedSwf = function() {
  975. var flashBridge = _flashState.bridge;
  976. if (flashBridge) {
  977. var htmlBridge = _getHtmlBridge(flashBridge);
  978. if (htmlBridge) {
  979. if (_flashState.pluginType === "activex" && "readyState" in flashBridge) {
  980. flashBridge.style.display = "none";
  981. (function removeSwfFromIE() {
  982. if (flashBridge.readyState === 4) {
  983. for (var prop in flashBridge) {
  984. if (typeof flashBridge[prop] === "function") {
  985. flashBridge[prop] = null;
  986. }
  987. }
  988. if (flashBridge.parentNode) {
  989. flashBridge.parentNode.removeChild(flashBridge);
  990. }
  991. if (htmlBridge.parentNode) {
  992. htmlBridge.parentNode.removeChild(htmlBridge);
  993. }
  994. } else {
  995. _setTimeout(removeSwfFromIE, 10);
  996. }
  997. })();
  998. } else {
  999. if (flashBridge.parentNode) {
  1000. flashBridge.parentNode.removeChild(flashBridge);
  1001. }
  1002. if (htmlBridge.parentNode) {
  1003. htmlBridge.parentNode.removeChild(htmlBridge);
  1004. }
  1005. }
  1006. }
  1007. _flashState.ready = null;
  1008. _flashState.bridge = null;
  1009. _flashState.deactivated = null;
  1010. }
  1011. };
  1012. /**
  1013. * Map the data format names of the "clipData" to Flash-friendly names.
  1014. *
  1015. * @returns A new transformed object.
  1016. * @private
  1017. */
  1018. var _mapClipDataToFlash = function(clipData) {
  1019. var newClipData = {}, formatMap = {};
  1020. if (!(typeof clipData === "object" && clipData)) {
  1021. return;
  1022. }
  1023. for (var dataFormat in clipData) {
  1024. if (dataFormat && _hasOwn.call(clipData, dataFormat) && typeof clipData[dataFormat] === "string" && clipData[dataFormat]) {
  1025. switch (dataFormat.toLowerCase()) {
  1026. case "text/plain":
  1027. case "text":
  1028. case "air:text":
  1029. case "flash:text":
  1030. newClipData.text = clipData[dataFormat];
  1031. formatMap.text = dataFormat;
  1032. break;
  1033. case "text/html":
  1034. case "html":
  1035. case "air:html":
  1036. case "flash:html":
  1037. newClipData.html = clipData[dataFormat];
  1038. formatMap.html = dataFormat;
  1039. break;
  1040. case "application/rtf":
  1041. case "text/rtf":
  1042. case "rtf":
  1043. case "richtext":
  1044. case "air:rtf":
  1045. case "flash:rtf":
  1046. newClipData.rtf = clipData[dataFormat];
  1047. formatMap.rtf = dataFormat;
  1048. break;
  1049. default:
  1050. break;
  1051. }
  1052. }
  1053. }
  1054. return {
  1055. data: newClipData,
  1056. formatMap: formatMap
  1057. };
  1058. };
  1059. /**
  1060. * Map the data format names from Flash-friendly names back to their original "clipData" names (via a format mapping).
  1061. *
  1062. * @returns A new transformed object.
  1063. * @private
  1064. */
  1065. var _mapClipResultsFromFlash = function(clipResults, formatMap) {
  1066. if (!(typeof clipResults === "object" && clipResults && typeof formatMap === "object" && formatMap)) {
  1067. return clipResults;
  1068. }
  1069. var newResults = {};
  1070. for (var prop in clipResults) {
  1071. if (_hasOwn.call(clipResults, prop)) {
  1072. if (prop !== "success" && prop !== "data") {
  1073. 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];
  1081. }
  1082. }
  1083. }
  1084. }
  1085. return newResults;
  1086. };
  1087. /**
  1088. * Will look at a path, and will create a "?noCache={time}" or "&noCache={time}"
  1089. * query param string to return. Does NOT append that string to the original path.
  1090. * This is useful because ExternalInterface often breaks when a Flash SWF is cached.
  1091. *
  1092. * @returns The `noCache` query param with necessary "?"/"&" prefix.
  1093. * @private
  1094. */
  1095. var _cacheBust = function(path, options) {
  1096. var cacheBust = options == null || options && options.cacheBust === true;
  1097. if (cacheBust) {
  1098. return (path.indexOf("?") === -1 ? "?" : "&") + "noCache=" + _now();
  1099. } else {
  1100. return "";
  1101. }
  1102. };
  1103. /**
  1104. * Creates a query string for the FlashVars param.
  1105. * Does NOT include the cache-busting query param.
  1106. *
  1107. * @returns FlashVars query string
  1108. * @private
  1109. */
  1110. var _vars = function(options) {
  1111. var i, len, domain, domains, str = "", trustedOriginsExpanded = [];
  1112. if (options.trustedDomains) {
  1113. if (typeof options.trustedDomains === "string") {
  1114. domains = [ options.trustedDomains ];
  1115. } else if (typeof options.trustedDomains === "object" && "length" in options.trustedDomains) {
  1116. domains = options.trustedDomains;
  1117. }
  1118. }
  1119. if (domains && domains.length) {
  1120. for (i = 0, len = domains.length; i < len; i++) {
  1121. if (_hasOwn.call(domains, i) && domains[i] && typeof domains[i] === "string") {
  1122. domain = _extractDomain(domains[i]);
  1123. if (!domain) {
  1124. continue;
  1125. }
  1126. if (domain === "*") {
  1127. trustedOriginsExpanded.length = 0;
  1128. trustedOriginsExpanded.push(domain);
  1129. break;
  1130. }
  1131. trustedOriginsExpanded.push.apply(trustedOriginsExpanded, [ domain, "//" + domain, _window.location.protocol + "//" + domain ]);
  1132. }
  1133. }
  1134. }
  1135. if (trustedOriginsExpanded.length) {
  1136. str += "trustedOrigins=" + _encodeURIComponent(trustedOriginsExpanded.join(","));
  1137. }
  1138. if (options.forceEnhancedClipboard === true) {
  1139. str += (str ? "&" : "") + "forceEnhancedClipboard=true";
  1140. }
  1141. if (typeof options.swfObjectId === "string" && options.swfObjectId) {
  1142. str += (str ? "&" : "") + "swfObjectId=" + _encodeURIComponent(options.swfObjectId);
  1143. }
  1144. return str;
  1145. };
  1146. /**
  1147. * Extract the domain (e.g. "github.com") from an origin (e.g. "https://github.com") or
  1148. * URL (e.g. "https://github.com/zeroclipboard/zeroclipboard/").
  1149. *
  1150. * @returns the domain
  1151. * @private
  1152. */
  1153. var _extractDomain = function(originOrUrl) {
  1154. if (originOrUrl == null || originOrUrl === "") {
  1155. return null;
  1156. }
  1157. originOrUrl = originOrUrl.replace(/^\s+|\s+$/g, "");
  1158. if (originOrUrl === "") {
  1159. return null;
  1160. }
  1161. var protocolIndex = originOrUrl.indexOf("//");
  1162. originOrUrl = protocolIndex === -1 ? originOrUrl : originOrUrl.slice(protocolIndex + 2);
  1163. var pathIndex = originOrUrl.indexOf("/");
  1164. originOrUrl = pathIndex === -1 ? originOrUrl : protocolIndex === -1 || pathIndex === 0 ? null : originOrUrl.slice(0, pathIndex);
  1165. if (originOrUrl && originOrUrl.slice(-4).toLowerCase() === ".swf") {
  1166. return null;
  1167. }
  1168. return originOrUrl || null;
  1169. };
  1170. /**
  1171. * Set `allowScriptAccess` based on `trustedDomains` and `window.location.host` vs. `swfPath`.
  1172. *
  1173. * @returns The appropriate script access level.
  1174. * @private
  1175. */
  1176. var _determineScriptAccess = function() {
  1177. var _extractAllDomains = function(origins) {
  1178. var i, len, tmp, resultsArray = [];
  1179. if (typeof origins === "string") {
  1180. origins = [ origins ];
  1181. }
  1182. if (!(typeof origins === "object" && origins && typeof origins.length === "number")) {
  1183. return resultsArray;
  1184. }
  1185. for (i = 0, len = origins.length; i < len; i++) {
  1186. if (_hasOwn.call(origins, i) && (tmp = _extractDomain(origins[i]))) {
  1187. if (tmp === "*") {
  1188. resultsArray.length = 0;
  1189. resultsArray.push("*");
  1190. break;
  1191. }
  1192. if (resultsArray.indexOf(tmp) === -1) {
  1193. resultsArray.push(tmp);
  1194. }
  1195. }
  1196. }
  1197. return resultsArray;
  1198. };
  1199. return function(currentDomain, configOptions) {
  1200. var swfDomain = _extractDomain(configOptions.swfPath);
  1201. if (swfDomain === null) {
  1202. swfDomain = currentDomain;
  1203. }
  1204. var trustedDomains = _extractAllDomains(configOptions.trustedDomains);
  1205. var len = trustedDomains.length;
  1206. if (len > 0) {
  1207. if (len === 1 && trustedDomains[0] === "*") {
  1208. return "always";
  1209. }
  1210. if (trustedDomains.indexOf(currentDomain) !== -1) {
  1211. if (len === 1 && currentDomain === swfDomain) {
  1212. return "sameDomain";
  1213. }
  1214. return "always";
  1215. }
  1216. }
  1217. return "never";
  1218. };
  1219. }();
  1220. /**
  1221. * Get the currently active/focused DOM element.
  1222. *
  1223. * @returns the currently active/focused element, or `null`
  1224. * @private
  1225. */
  1226. var _safeActiveElement = function() {
  1227. try {
  1228. return _document.activeElement;
  1229. } catch (err) {
  1230. return null;
  1231. }
  1232. };
  1233. /**
  1234. * Add a class to an element, if it doesn't already have it.
  1235. *
  1236. * @returns The element, with its new class added.
  1237. * @private
  1238. */
  1239. 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;
  1248. }
  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. }
  1260. }
  1261. element.className = setClass.replace(/^\s+|\s+$/g, "");
  1262. }
  1263. }
  1264. }
  1265. return element;
  1266. };
  1267. /**
  1268. * Remove a class from an element, if it has it.
  1269. *
  1270. * @returns The element, with its class removed.
  1271. * @private
  1272. */
  1273. 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. }
  1283. 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++) {
  1288. className = className.replace(" " + classNames[c] + " ", " ");
  1289. }
  1290. element.className = className.replace(/^\s+|\s+$/g, "");
  1291. }
  1292. }
  1293. return element;
  1294. };
  1295. /**
  1296. * Attempt to interpret the element's CSS styling. If `prop` is `"cursor"`,
  1297. * then we assume that it should be a hand ("pointer") cursor if the element
  1298. * is an anchor element ("a" tag).
  1299. *
  1300. * @returns The computed style property.
  1301. * @private
  1302. */
  1303. var _getStyle = function(el, prop) {
  1304. var value = _window.getComputedStyle(el, null).getPropertyValue(prop);
  1305. if (prop === "cursor") {
  1306. if (!value || value === "auto") {
  1307. if (el.nodeName === "A") {
  1308. return "pointer";
  1309. }
  1310. }
  1311. }
  1312. return value;
  1313. };
  1314. /**
  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.
  1333. *
  1334. * @returns Object containing the element's position, width, and height.
  1335. * @private
  1336. */
  1337. var _getDOMObjectPosition = function(obj) {
  1338. var info = {
  1339. left: 0,
  1340. top: 0,
  1341. width: 0,
  1342. height: 0
  1343. };
  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. }
  1355. var leftBorderWidth = _document.documentElement.clientLeft || 0;
  1356. 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;
  1361. }
  1362. return info;
  1363. };
  1364. /**
  1365. * Reposition the Flash object to cover the currently activated element.
  1366. *
  1367. * @returns `undefined`
  1368. * @private
  1369. */
  1370. var _reposition = function() {
  1371. var htmlBridge;
  1372. if (_currentElement && (htmlBridge = _getHtmlBridge(_flashState.bridge))) {
  1373. var pos = _getDOMObjectPosition(_currentElement);
  1374. _extend(htmlBridge.style, {
  1375. width: pos.width + "px",
  1376. height: pos.height + "px",
  1377. top: pos.top + "px",
  1378. left: pos.left + "px",
  1379. zIndex: "" + _getSafeZIndex(_globalConfig.zIndex)
  1380. });
  1381. }
  1382. };
  1383. /**
  1384. * Sends a signal to the Flash object to display the hand cursor if `true`.
  1385. *
  1386. * @returns `undefined`
  1387. * @private
  1388. */
  1389. var _setHandCursor = function(enabled) {
  1390. if (_flashState.ready === true) {
  1391. if (_flashState.bridge && typeof _flashState.bridge.setHandCursor === "function") {
  1392. _flashState.bridge.setHandCursor(enabled);
  1393. } else {
  1394. _flashState.ready = false;
  1395. }
  1396. }
  1397. };
  1398. /**
  1399. * Get a safe value for `zIndex`
  1400. *
  1401. * @returns an integer, or "auto"
  1402. * @private
  1403. */
  1404. var _getSafeZIndex = function(val) {
  1405. if (/^(?:auto|inherit)$/.test(val)) {
  1406. return val;
  1407. }
  1408. var zIndex;
  1409. if (typeof val === "number" && !_isNaN(val)) {
  1410. zIndex = val;
  1411. } else if (typeof val === "string") {
  1412. zIndex = _getSafeZIndex(_parseInt(val, 10));
  1413. }
  1414. return typeof zIndex === "number" ? zIndex : "auto";
  1415. };
  1416. /**
  1417. * Detect the Flash Player status, version, and plugin type.
  1418. *
  1419. * @see {@link https://code.google.com/p/doctype-mirror/wiki/ArticleDetectFlash#The_code}
  1420. * @see {@link http://stackoverflow.com/questions/12866060/detecting-pepper-ppapi-flash-with-javascript}
  1421. *
  1422. * @returns `undefined`
  1423. * @private
  1424. */
  1425. var _detectFlashSupport = function(ActiveXObject) {
  1426. var plugin, ax, mimeType, hasFlash = false, isActiveX = false, isPPAPI = false, flashVersion = "";
  1427. /**
  1428. * Derived from Apple's suggested sniffer.
  1429. * @param {String} desc e.g. "Shockwave Flash 7.0 r61"
  1430. * @returns {String} "7.0.61"
  1431. * @private
  1432. */
  1433. function parseFlashVersion(desc) {
  1434. var matches = desc.match(/[\d]+/g);
  1435. matches.length = 3;
  1436. return matches.join(".");
  1437. }
  1438. function isPepperFlash(flashPlayerFileName) {
  1439. return !!flashPlayerFileName && (flashPlayerFileName = flashPlayerFileName.toLowerCase()) && (/^(pepflashplayer\.dll|libpepflashplayer\.so|pepperflashplayer\.plugin)$/.test(flashPlayerFileName) || flashPlayerFileName.slice(-13) === "chrome.plugin");
  1440. }
  1441. function inspectPlugin(plugin) {
  1442. if (plugin) {
  1443. hasFlash = true;
  1444. if (plugin.version) {
  1445. flashVersion = parseFlashVersion(plugin.version);
  1446. }
  1447. if (!flashVersion && plugin.description) {
  1448. flashVersion = parseFlashVersion(plugin.description);
  1449. }
  1450. if (plugin.filename) {
  1451. isPPAPI = isPepperFlash(plugin.filename);
  1452. }
  1453. }
  1454. }
  1455. if (_navigator.plugins && _navigator.plugins.length) {
  1456. plugin = _navigator.plugins["Shockwave Flash"];
  1457. inspectPlugin(plugin);
  1458. if (_navigator.plugins["Shockwave Flash 2.0"]) {
  1459. hasFlash = true;
  1460. flashVersion = "2.0.0.11";
  1461. }
  1462. } else if (_navigator.mimeTypes && _navigator.mimeTypes.length) {
  1463. mimeType = _navigator.mimeTypes["application/x-shockwave-flash"];
  1464. plugin = mimeType && mimeType.enabledPlugin;
  1465. inspectPlugin(plugin);
  1466. } else if (typeof ActiveXObject !== "undefined") {
  1467. isActiveX = true;
  1468. try {
  1469. ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
  1470. hasFlash = true;
  1471. flashVersion = parseFlashVersion(ax.GetVariable("$version"));
  1472. } catch (e1) {
  1473. try {
  1474. ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
  1475. hasFlash = true;
  1476. flashVersion = "6.0.21";
  1477. } catch (e2) {
  1478. try {
  1479. ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
  1480. hasFlash = true;
  1481. flashVersion = parseFlashVersion(ax.GetVariable("$version"));
  1482. } catch (e3) {
  1483. isActiveX = false;
  1484. }
  1485. }
  1486. }
  1487. }
  1488. _flashState.disabled = hasFlash !== true;
  1489. _flashState.outdated = flashVersion && _parseFloat(flashVersion) < _parseFloat(_minimumFlashVersion);
  1490. _flashState.version = flashVersion || "0.0.0";
  1491. _flashState.pluginType = isPPAPI ? "pepper" : isActiveX ? "activex" : hasFlash ? "netscape" : "unknown";
  1492. };
  1493. /**
  1494. * Invoke the Flash detection algorithms immediately upon inclusion so we're not waiting later.
  1495. */
  1496. _detectFlashSupport(_ActiveXObject);
  1497. /**
  1498. * A shell constructor for `ZeroClipboard` client instances.
  1499. *
  1500. * @constructor
  1501. */
  1502. var ZeroClipboard = function() {
  1503. if (!(this instanceof ZeroClipboard)) {
  1504. return new ZeroClipboard();
  1505. }
  1506. if (typeof ZeroClipboard._createClient === "function") {
  1507. ZeroClipboard._createClient.apply(this, _args(arguments));
  1508. }
  1509. };
  1510. /**
  1511. * The ZeroClipboard library's version number.
  1512. *
  1513. * @static
  1514. * @readonly
  1515. * @property {string}
  1516. */
  1517. _defineProperty(ZeroClipboard, "version", {
  1518. value: "2.1.2",
  1519. writable: false,
  1520. configurable: true,
  1521. enumerable: true
  1522. });
  1523. /**
  1524. * Update or get a copy of the ZeroClipboard global configuration.
  1525. * Returns a copy of the current/updated configuration.
  1526. *
  1527. * @returns Object
  1528. * @static
  1529. */
  1530. ZeroClipboard.config = function() {
  1531. return _config.apply(this, _args(arguments));
  1532. };
  1533. /**
  1534. * Diagnostic method that describes the state of the browser, Flash Player, and ZeroClipboard.
  1535. *
  1536. * @returns Object
  1537. * @static
  1538. */
  1539. ZeroClipboard.state = function() {
  1540. return _state.apply(this, _args(arguments));
  1541. };
  1542. /**
  1543. * Check if Flash is unusable for any reason: disabled, outdated, deactivated, etc.
  1544. *
  1545. * @returns Boolean
  1546. * @static
  1547. */
  1548. ZeroClipboard.isFlashUnusable = function() {
  1549. return _isFlashUnusable.apply(this, _args(arguments));
  1550. };
  1551. /**
  1552. * Register an event listener.
  1553. *
  1554. * @returns `ZeroClipboard`
  1555. * @static
  1556. */
  1557. ZeroClipboard.on = function() {
  1558. return _on.apply(this, _args(arguments));
  1559. };
  1560. /**
  1561. * Unregister an event listener.
  1562. * If no `listener` function/object is provided, it will unregister all listeners for the provided `eventType`.
  1563. * If no `eventType` is provided, it will unregister all listeners for every event type.
  1564. *
  1565. * @returns `ZeroClipboard`
  1566. * @static
  1567. */
  1568. ZeroClipboard.off = function() {
  1569. return _off.apply(this, _args(arguments));
  1570. };
  1571. /**
  1572. * Retrieve event listeners for an `eventType`.
  1573. * If no `eventType` is provided, it will retrieve all listeners for every event type.
  1574. *
  1575. * @returns array of listeners for the `eventType`; if no `eventType`, then a map/hash object of listeners for all event types; or `null`
  1576. */
  1577. ZeroClipboard.handlers = function() {
  1578. return _listeners.apply(this, _args(arguments));
  1579. };
  1580. /**
  1581. * Event emission receiver from the Flash object, forwarding to any registered JavaScript event listeners.
  1582. *
  1583. * @returns For the "copy" event, returns the Flash-friendly "clipData" object; otherwise `undefined`.
  1584. * @static
  1585. */
  1586. ZeroClipboard.emit = function() {
  1587. return _emit.apply(this, _args(arguments));
  1588. };
  1589. /**
  1590. * Create and embed the Flash object.
  1591. *
  1592. * @returns The Flash object
  1593. * @static
  1594. */
  1595. ZeroClipboard.create = function() {
  1596. return _create.apply(this, _args(arguments));
  1597. };
  1598. /**
  1599. * Self-destruct and clean up everything, including the embedded Flash object.
  1600. *
  1601. * @returns `undefined`
  1602. * @static
  1603. */
  1604. ZeroClipboard.destroy = function() {
  1605. return _destroy.apply(this, _args(arguments));
  1606. };
  1607. /**
  1608. * Set the pending data for clipboard injection.
  1609. *
  1610. * @returns `undefined`
  1611. * @static
  1612. */
  1613. ZeroClipboard.setData = function() {
  1614. return _setData.apply(this, _args(arguments));
  1615. };
  1616. /**
  1617. * Clear the pending data for clipboard injection.
  1618. * If no `format` is provided, all pending data formats will be cleared.
  1619. *
  1620. * @returns `undefined`
  1621. * @static
  1622. */
  1623. ZeroClipboard.clearData = function() {
  1624. return _clearData.apply(this, _args(arguments));
  1625. };
  1626. /**
  1627. * Get a copy of the pending data for clipboard injection.
  1628. * If no `format` is provided, a copy of ALL pending data formats will be returned.
  1629. *
  1630. * @returns `String` or `Object`
  1631. * @static
  1632. */
  1633. ZeroClipboard.getData = function() {
  1634. return _getData.apply(this, _args(arguments));
  1635. };
  1636. /**
  1637. * Sets the current HTML object that the Flash object should overlay. This will put the global
  1638. * Flash object on top of the current element; depending on the setup, this may also set the
  1639. * pending clipboard text data as well as the Flash object's wrapping element's title attribute
  1640. * based on the underlying HTML element and ZeroClipboard configuration.
  1641. *
  1642. * @returns `undefined`
  1643. * @static
  1644. */
  1645. ZeroClipboard.focus = ZeroClipboard.activate = function() {
  1646. return _focus.apply(this, _args(arguments));
  1647. };
  1648. /**
  1649. * Un-overlays the Flash object. This will put the global Flash object off-screen; depending on
  1650. * the setup, this may also unset the Flash object's wrapping element's title attribute based on
  1651. * the underlying HTML element and ZeroClipboard configuration.
  1652. *
  1653. * @returns `undefined`
  1654. * @static
  1655. */
  1656. ZeroClipboard.blur = ZeroClipboard.deactivate = function() {
  1657. return _blur.apply(this, _args(arguments));
  1658. };
  1659. /**
  1660. * Returns the currently focused/"activated" HTML element that the Flash object is wrapping.
  1661. *
  1662. * @returns `HTMLElement` or `null`
  1663. * @static
  1664. */
  1665. ZeroClipboard.activeElement = function() {
  1666. return _activeElement.apply(this, _args(arguments));
  1667. };
  1668. if (typeof define === "function" && define.amd) {
  1669. define(function() {
  1670. return ZeroClipboard;
  1671. });
  1672. } else if (typeof module === "object" && module && typeof module.exports === "object" && module.exports) {
  1673. module.exports = ZeroClipboard;
  1674. } else {
  1675. window.ZeroClipboard = ZeroClipboard;
  1676. }
  1677. })(function() {
  1678. return this || window;
  1679. }());
  1680. (function($, window, undefined) {
  1681. var mouseEnterBindingCount = 0, customEventNamespace = ".zeroclipboard", ZeroClipboard = window.ZeroClipboard, _trustedDomains = ZeroClipboard.config("trustedDomains");
  1682. function getSelectionData() {
  1683. var range, selectedText = "", selectedData = {}, sel = window.getSelection(), tmp = document.createElement("div");
  1684. for (var i = 0, len = sel.rangeCount; i < len; i++) {
  1685. range = sel.getRangeAt(i);
  1686. selectedText += range.toString();
  1687. tmp.appendChild(range.cloneContents());
  1688. }
  1689. selectedData["text/plain"] = selectedText;
  1690. if (selectedText.replace(/\s/g, "")) {
  1691. selectedData["text/html"] = tmp.innerHTML;
  1692. }
  1693. return selectedData;
  1694. }
  1695. function convertHtmlToRtf(html) {
  1696. if (!(typeof html === "string" && html)) {
  1697. return null;
  1698. }
  1699. var tmpRichText, hasHyperlinks, richText = html;
  1700. richText = richText.replace(/<(?:hr)(?:\s+[^>]*)?\s*[\/]?>/gi, "{\\pard \\brdrb \\brdrs \\brdrw10 \\brsp20 \\par}\n{\\pard\\par}\n");
  1701. richText = richText.replace(/<(?:br)(?:\s+[^>]*)?\s*[\/]?>/gi, "{\\pard\\par}\n");
  1702. richText = richText.replace(/<(?:p|div|section|article)(?:\s+[^>]*)?\s*[\/]>/gi, "{\\pard\\par}\n");
  1703. richText = richText.replace(/<(?:[^>]+)\/>/g, "");
  1704. richText = richText.replace(/<a(?:\s+[^>]*)?(?:\s+href=(["'])(?:javascript:void\(0?\);?|#|return false;?|void\(0?\);?|)\1)(?:\s+[^>]*)?>/gi, "{{{\n");
  1705. tmpRichText = richText;
  1706. richText = richText.replace(/<a(?:\s+[^>]*)?(?:\s+href=(["'])(.+)\1)(?:\s+[^>]*)?>/gi, '{\\field{\\*\\fldinst{HYPERLINK\n "$2"\n}}{\\fldrslt{\\ul\\cf1\n');
  1707. hasHyperlinks = richText !== tmpRichText;
  1708. richText = richText.replace(/<a(?:\s+[^>]*)?>/gi, "{{{\n");
  1709. richText = richText.replace(/<\/a(?:\s+[^>]*)?>/gi, "\n}}}");
  1710. richText = richText.replace(/<(?:b|strong)(?:\s+[^>]*)?>/gi, "{\\b\n");
  1711. richText = richText.replace(/<(?:i|em)(?:\s+[^>]*)?>/gi, "{\\i\n");
  1712. richText = richText.replace(/<(?:u|ins)(?:\s+[^>]*)?>/gi, "{\\ul\n");
  1713. richText = richText.replace(/<(?:strike|del)(?:\s+[^>]*)?>/gi, "{\\strike\n");
  1714. richText = richText.replace(/<sup(?:\s+[^>]*)?>/gi, "{\\super\n");
  1715. richText = richText.replace(/<sub(?:\s+[^>]*)?>/gi, "{\\sub\n");
  1716. richText = richText.replace(/<(?:p|div|section|article)(?:\s+[^>]*)?>/gi, "{\\pard\n");
  1717. richText = richText.replace(/<\/(?:p|div|section|article)(?:\s+[^>]*)?>/gi, "\n\\par}\n");
  1718. richText = richText.replace(/<\/(?:b|strong|i|em|u|ins|strike|del|sup|sub)(?:\s+[^>]*)?>/gi, "\n}");
  1719. richText = richText.replace(/<(?:[^>]+)>/g, "");
  1720. richText = "{\\rtf1\\ansi\n" + (hasHyperlinks ? "{\\colortbl\n;\n\\red0\\green0\\blue255;\n}\n" : "") + richText + "\n}";
  1721. return richText;
  1722. }
  1723. function zcEventHandler(e) {
  1724. var $event = $.Event(e.type, $.extend(e, {
  1725. _source: "swf"
  1726. }));
  1727. $(e.target).trigger($event);
  1728. if ($event.type === "copy") {
  1729. if ($.event.special.copy.options.requirePreventDefault === true && !$event.isDefaultPrevented()) {
  1730. e.clipboardData.clearData();
  1731. var selectionData = getSelectionData();
  1732. if (selectionData["text/plain"] || selectionData["text/html"]) {
  1733. e.clipboardData.setData(selectionData);
  1734. }
  1735. }
  1736. var _clipData = ZeroClipboard.getData();
  1737. if ($.event.special.copy.options.autoConvertHtmlToRtf === true && _clipData["text/html"] && !_clipData["application/rtf"]) {
  1738. var richText = convertHtmlToRtf(_clipData["text/html"]);
  1739. e.clipboardData.setData("application/rtf", richText);
  1740. }
  1741. }
  1742. }
  1743. function zcErrorHandler(e) {
  1744. var $event = $.Event("copy-error", $.extend(e, {
  1745. type: "copy-error",
  1746. _source: "swf"
  1747. }));
  1748. $(e.target).trigger($event);
  1749. }
  1750. function setup() {
  1751. $.event.props.push("clipboardData");
  1752. ZeroClipboard.config($.extend(true, {
  1753. autoActivate: false
  1754. }, copyEventDef.options));
  1755. ZeroClipboard.on("beforecopy copy aftercopy", zcEventHandler);
  1756. ZeroClipboard.on("error", zcErrorHandler);
  1757. ZeroClipboard.create();
  1758. }
  1759. function teardown() {
  1760. ZeroClipboard.destroy();
  1761. var indy = $.event.props.indexOf("clipboardData");
  1762. if (indy !== -1) {
  1763. $.event.props.splice(indy, 1);
  1764. }
  1765. }
  1766. function mouseEnterHandler($event) {
  1767. mouseSuppressor($event);
  1768. if ($event.target && $event.target !== ZeroClipboard.activeElement() && $event.target !== $("#" + ZeroClipboard.config("containerId"))[0] && $event.target !== $("#" + ZeroClipboard.config("swfObjectId"))[0]) {
  1769. ZeroClipboard.focus($event.target);
  1770. }
  1771. }
  1772. function mouseLeaveHandler($event) {
  1773. mouseSuppressor($event);
  1774. if ($event.relatedTarget && $event.relatedTarget !== ZeroClipboard.activeElement() && $event.relatedTarget !== $("#" + ZeroClipboard.config("containerId"))[0] && $event.relatedTarget !== $("#" + ZeroClipboard.config("swfObjectId"))[0]) {
  1775. ZeroClipboard.blur();
  1776. }
  1777. }
  1778. function mouseSuppressor($event) {
  1779. if (!ZeroClipboard.isFlashUnusable() && $event.originalEvent._source !== "js") {
  1780. $event.stopImmediatePropagation();
  1781. $event.preventDefault();
  1782. }
  1783. }
  1784. var copyEventDef = {
  1785. add: function(handleObj) {
  1786. if (0 === mouseEnterBindingCount++) {
  1787. setup();
  1788. }
  1789. var namespaces = customEventNamespace + (handleObj.namespace ? "." + handleObj.namespace : ""), selector = handleObj.selector, zcDataKey = "zc|{" + selector + "}|{" + namespaces + "}|count", $this = $(this);
  1790. if (typeof $this.data(zcDataKey) !== "number") {
  1791. $this.data(zcDataKey, 0);
  1792. }
  1793. if ($this.data(zcDataKey) === 0) {
  1794. $this.on("mouseenter" + namespaces, selector, mouseEnterHandler);
  1795. $this.on("mouseleave" + namespaces, selector, mouseLeaveHandler);
  1796. $this.on("mouseover" + namespaces, selector, mouseSuppressor);
  1797. $this.on("mouseout" + namespaces, selector, mouseSuppressor);
  1798. $this.on("mousemove" + namespaces, selector, mouseSuppressor);
  1799. $this.on("mousedown" + namespaces, selector, mouseSuppressor);
  1800. $this.on("mouseup" + namespaces, selector, mouseSuppressor);
  1801. $this.on("click" + namespaces, selector, mouseSuppressor);
  1802. }
  1803. $this.data(zcDataKey, $this.data(zcDataKey) + 1);
  1804. },
  1805. remove: function(handleObj) {
  1806. var namespaces = customEventNamespace + (handleObj.namespace ? "." + handleObj.namespace : ""), selector = handleObj.selector, zcDataKey = "zc|{" + selector + "}|{" + namespaces + "}|count", $this = $(this);
  1807. $this.data(zcDataKey, $this.data(zcDataKey) - 1);
  1808. if ($this.data(zcDataKey) === 0) {
  1809. $this.off("click" + namespaces, selector, mouseSuppressor);
  1810. $this.off("mouseup" + namespaces, selector, mouseSuppressor);
  1811. $this.off("mousedown" + namespaces, selector, mouseSuppressor);
  1812. $this.off("mousemove" + namespaces, selector, mouseSuppressor);
  1813. $this.off("mouseout" + namespaces, selector, mouseSuppressor);
  1814. $this.off("mouseover" + namespaces, selector, mouseSuppressor);
  1815. $this.off("mouseleave" + namespaces, selector, mouseLeaveHandler);
  1816. $this.off("mouseenter" + namespaces, selector, mouseEnterHandler);
  1817. $this.removeData(zcDataKey);
  1818. }
  1819. if (0 === --mouseEnterBindingCount) {
  1820. teardown();
  1821. }
  1822. },
  1823. trigger: function($event) {
  1824. if ($event.type === "copy") {
  1825. var $this = $(this);
  1826. var sourceIsSwf = $event._source === "swf";
  1827. delete $event._source;
  1828. if (!sourceIsSwf) {
  1829. $this.trigger($.extend(true, {}, $event, {
  1830. type: "beforecopy"
  1831. }));
  1832. $this.one("copy", function() {
  1833. var successData = {}, _clipData = ZeroClipboard.getData();
  1834. $.each(_clipData, function(key) {
  1835. successData[key] = false;
  1836. });
  1837. var $e = $.extend(true, {}, $event, {
  1838. type: "aftercopy",
  1839. data: $.extend(true, {}, _clipData),
  1840. success: successData
  1841. });
  1842. $this.trigger($e);
  1843. });
  1844. }
  1845. }
  1846. },
  1847. _default: function() {
  1848. return true;
  1849. },
  1850. options: {
  1851. requirePreventDefault: true,
  1852. autoConvertHtmlToRtf: true,
  1853. trustedDomains: _trustedDomains,
  1854. hoverClass: "hover",
  1855. activeClass: "active"
  1856. }
  1857. };
  1858. $.event.special.beforecopy = copyEventDef;
  1859. $.event.special.copy = copyEventDef;
  1860. $.event.special.aftercopy = copyEventDef;
  1861. $.event.special["copy-error"] = copyEventDef;
  1862. })(jQuery, function() {
  1863. return this || window;
  1864. }());
  1865. if (!zcExistsAlready) {
  1866. delete window.ZeroClipboard;
  1867. }
  1868. })(jQuery, function() {
  1869. return this || window;
  1870. }());