From 3eab40a7610c86c9dc16d361fc7f9588a94d566f Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Fri, 12 Dec 2014 13:56:30 +0000 Subject: [PATCH 001/295] make id a sortable column --- mail/templates/default/index.xet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mail/templates/default/index.xet b/mail/templates/default/index.xet index 4a6b153665..d91d1b157f 100644 --- a/mail/templates/default/index.xet +++ b/mail/templates/default/index.xet @@ -16,7 +16,7 @@ - + From e07c11be85a357a5df8353f9456c1ae54daf5c5e Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Fri, 12 Dec 2014 14:21:04 +0000 Subject: [PATCH 002/295] Fix popup's window close -Make sure window.close() closing the right egw window -Make sure the modal popup has the opener --- addressbook/inc/class.addressbook_ui.inc.php | 2 +- addressbook/js/app.js | 4 ++-- calendar/js/app.js | 2 +- mail/inc/class.mail_ui.inc.php | 4 ++-- mail/js/app.js | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/addressbook/inc/class.addressbook_ui.inc.php b/addressbook/inc/class.addressbook_ui.inc.php index 5ac1394327..6e178ebcaf 100644 --- a/addressbook/inc/class.addressbook_ui.inc.php +++ b/addressbook/inc/class.addressbook_ui.inc.php @@ -884,7 +884,7 @@ window.egw_LAB.wait(function() { { if (!$msg) $msg = lang('%1 contact(s) %2',$success,$action_msg); $response->addScript("alert('".addslashes($msg)."')"); - $response->addScript('window.close();'); + $response->addScript('egw(window).close();'); } } diff --git a/addressbook/js/app.js b/addressbook/js/app.js index 68a72a15d9..dc05aee619 100644 --- a/addressbook/js/app.js +++ b/addressbook/js/app.js @@ -581,14 +581,14 @@ app.classes.addressbook = AppJS.extend( if(!index) { alert('Could not find index'); - window.close(); + egw(window).close(); return false; } var nm = index.widgetContainer.getWidgetById('nm'); if(!index) { window.opener.egw.message('Could not find list', 'error'); - window.close(); + egw(window).close(); return false; } // Reset filters first diff --git a/calendar/js/app.js b/calendar/js/app.js index 0d3a6e56fd..4a1dc7ade4 100644 --- a/calendar/js/app.js +++ b/calendar/js/app.js @@ -979,7 +979,7 @@ app.classes.calendar = AppJS.extend( alert(this.egw.lang('The original calendar edit popup is closed!')); } } - window.close(); + egw(window).close(); }, /** diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index bffbf1973e..319301b2d6 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -2582,7 +2582,7 @@ class mail_ui if (is_array($ids) && !egw_vfs::is_writable($path) || !is_array($ids) && !egw_vfs::is_writable(dirname($path))) { - return 'alert("'.addslashes(lang('%1 is NOT writable by you!',$path)).'"); window.close();'; + return 'alert("'.addslashes(lang('%1 is NOT writable by you!',$path)).'"); egw(window).close();'; } translation::add_app('mail'); @@ -2656,7 +2656,7 @@ class mail_ui if (is_array($ids) && !egw_vfs::is_writable($path) || !is_array($ids) && !egw_vfs::is_writable(dirname($path))) { - return 'alert("'.addslashes(lang('%1 is NOT writable by you!',$path)).'"); window.close();'; + return 'alert("'.addslashes(lang('%1 is NOT writable by you!',$path)).'"); egw(window).close();'; } $err=null; $rememberServerID = $this->mail_bo->profileID; diff --git a/mail/js/app.js b/mail/js/app.js index 9c75a2c00f..bf25a69539 100644 --- a/mail/js/app.js +++ b/mail/js/app.js @@ -1420,7 +1420,7 @@ app.classes.mail = AppJS.extend( //alert(_action.id+','+ msg); if (!calledFromPopup) this.mail_setRowClass(_elems,'deleted'); this.mail_deleteMessages(msg,'no',calledFromPopup); - if (calledFromPopup && this.mail_isMainWindow==false) window.close(); + if (calledFromPopup && this.mail_isMainWindow==false) egw(window).close(); }, /** @@ -3902,14 +3902,14 @@ app.classes.mail = AppJS.extend( print_for_compose: function() { var afterprint = function (){ - window.close(); + egw(window).close(); }; if (!window.onafterprint) { // For browsers which does not support onafterprint event, eg. Chrome setTimeout(function() { - window.close(); + egw(window).close(); }, 2000); } else From 6eedc38a429df6d92d8d22c7b156da0d63714f6d Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 12 Dec 2014 15:06:29 +0000 Subject: [PATCH 003/295] * Filemanager: fixed directory creation in vfs root (you need root permisstions of cause) --- phpgwapi/inc/class.vfs_stream_wrapper.inc.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpgwapi/inc/class.vfs_stream_wrapper.inc.php b/phpgwapi/inc/class.vfs_stream_wrapper.inc.php index caf993043b..441c27f52b 100644 --- a/phpgwapi/inc/class.vfs_stream_wrapper.inc.php +++ b/phpgwapi/inc/class.vfs_stream_wrapper.inc.php @@ -1316,10 +1316,10 @@ class vfs_stream_wrapper implements iface_stream_wrapper { $path = self::parse_url($path, PHP_URL_PATH); } - // remove trailing slashes eg. added by WebDAV + // remove trailing slashes eg. added by WebDAV, but do NOT remove / from "sqlfs://default/"! if ($path != '/') { - while (mb_substr($path, -1) == '/' && $path != '/') + while (mb_substr($path, -1) == '/' && $path != '/' && ($path[0] == '/' || self::parse_url($path, PHP_URL_PATH) != '/')) { $path = mb_substr($path,0,-1); } From a87e9840fe82ee324076a0da45c4a0170a63b971 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Fri, 12 Dec 2014 15:16:59 +0000 Subject: [PATCH 004/295] Fix another popup window.close --- filemanager/inc/class.filemanager_select.inc.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/filemanager/inc/class.filemanager_select.inc.php b/filemanager/inc/class.filemanager_select.inc.php index 64f6f7541a..bc105282ac 100644 --- a/filemanager/inc/class.filemanager_select.inc.php +++ b/filemanager/inc/class.filemanager_select.inc.php @@ -185,7 +185,7 @@ class filemanager_select $js = "window.opener.CKEDITOR.tools.callFunction(". $content['ckeditorfuncnum'].",'". htmlspecialchars($download_url)."',". - "'');\nwindow.close();"; + "'');\negw(window).close();"; } if(egw_json_response::isJSONResponse() && !($content['method'] == 'ckeditor_return')) { @@ -196,7 +196,7 @@ class filemanager_select } // Ahh! // The vfs-select widget looks for this - $response->script('this.selected_files = '.json_encode($files) . '; this.close();'); + $response->script('this.selected_files = '.json_encode($files) . '; egw(this).close();'); } else { From 87c442434e374ec98e73eccb3596bf4373084578 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 12 Dec 2014 15:28:53 +0000 Subject: [PATCH 005/295] * Mail: update title of compose window with subject --- mail/js/app.js | 28 +++++++++++++++++++++++----- mail/templates/default/compose.xet | 2 +- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/mail/js/app.js b/mail/js/app.js index bf25a69539..9e6a0df05f 100644 --- a/mail/js/app.js +++ b/mail/js/app.js @@ -181,6 +181,8 @@ app.classes.mail = AppJS.extend( this.compose_fieldExpander_init(); this.check_sharing_filemode(); + this.subject2title(); + // Set autosaving interval to 2 minutes for compose message window.setInterval(function (){ that.saveAsDraft(null,that.et2.getWidgetById('button[saveAsDraft]'),'autosaving'); @@ -3674,15 +3676,15 @@ app.classes.mail = AppJS.extend( var $headerSec = jQuery('.mailComposeHeaderSection'); var attachments = this.et2.getWidgetById('attachments'); var content = this.et2.getArrayMgr('content').data; - + // @var arrbitary int represents px // Visible height of attachment progress var prgV_H = 150; - + // @var arrbitary int represents px // Visible height of attchements list var attchV_H = 68; - + if (typeof textArea != 'undefined' && textArea != null) { if (textArea.getParent().disabled) @@ -3691,11 +3693,11 @@ app.classes.mail = AppJS.extend( } // Tolerate values base on plain text or html, in order to calculate freespaces var textAreaDelta = textArea.id == "mail_htmltext"?20:40; - + // while attachments are in progress take progress visiblity into account // otherwise the attachment progress is finished and consider attachments list var delta = (attachments.table.find('li').length>0 && attachments.table.height() > 0)? prgV_H: (content.attachments? attchV_H: textAreaDelta); - + var bodySize = (bodyH - Math.round($headerSec.height() + $headerSec.offset().top) - delta); if (textArea.id != "mail_htmltext") @@ -4149,5 +4151,21 @@ app.classes.mail = AppJS.extend( this.egw.message(this.egw.lang('Writable sharing required EPL version!'), 'info'); _widget.setValue('share_ro'); } + }, + + /** + * Write / update compose window title with subject + * + * @param {DOMNode} _node + * @param {et2_widget} _widget + */ + subject2title: function(_node, _widget) + { + if (!_widget) _widget = this.et2.getWidgetById('subject'); + + if (_widget && _widget.get_value()) + { + document.title = _widget.get_value(); + } } }); diff --git a/mail/templates/default/compose.xet b/mail/templates/default/compose.xet index 7e4e8efa02..a646c310b8 100644 --- a/mail/templates/default/compose.xet +++ b/mail/templates/default/compose.xet @@ -92,7 +92,7 @@ - + From f96d6aefe675716bd029dea439612df005d6c8ae Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 12 Dec 2014 15:54:34 +0000 Subject: [PATCH 006/295] button to mount /etemplates --- filemanager/inc/class.filemanager_admin.inc.php | 12 +++++++++++- filemanager/templates/default/admin.xet | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/filemanager/inc/class.filemanager_admin.inc.php b/filemanager/inc/class.filemanager_admin.inc.php index 8ceae6b71b..73711c0ce6 100644 --- a/filemanager/inc/class.filemanager_admin.inc.php +++ b/filemanager/inc/class.filemanager_admin.inc.php @@ -83,6 +83,13 @@ class filemanager_admin extends filemanager_ui lang('Root access granted.') : lang('Wrong username or password!'); $msg_type = egw_vfs::$is_root ? 'success' : 'error'; } + elseif ($content['etemplates'] && $GLOBALS['egw_info']['user']['apps']['admin']) + { + $path = '/etemplates'; + $url = 'stylite.merge://default/etemplates?merge=.&lang=0&level=1&extension=xet&url=egw'; + $msg = egw_vfs::mount($url, $path) ? + lang('Successful mounted %1 on %2.',$url,$path) : lang('Error mounting %1 on %2!',$url,$path); + } elseif (egw_vfs::$is_root) { if ($content['logout']) @@ -147,7 +154,7 @@ class filemanager_admin extends filemanager_ui } } } - $content = array(); + if (true) $content = array(); if ($this->versioning) { // statistical information @@ -189,6 +196,9 @@ class filemanager_admin extends filemanager_ui 'admins' => lang('Administrators'), 'everyone' => lang('Everyone'), ); + // show [Mount /etemplates] button for admin, if not already mounted and available + $readonlys['etemplates'] = !class_exists('stylite_merge_stream_wrapper') || egw_vfs::file_exists('/etemplates') || + !isset($GLOBALS['egw_info']['user']['apps']['admin']); //_debug_array($content); $tpl = new etemplate_new('filemanager.admin'); diff --git a/filemanager/templates/default/admin.xet b/filemanager/templates/default/admin.xet index afb5b58a4a..78cc590b01 100644 --- a/filemanager/templates/default/admin.xet +++ b/filemanager/templates/default/admin.xet @@ -63,6 +63,7 @@ + + + + + +``` + +```js +// main.js +var client = new ZeroClipboard( document.getElementById("copy-button") ); + +client.on( "ready", function( readyEvent ) { + // alert( "ZeroClipboard SWF is ready!" ); + + client.on( "aftercopy", function( event ) { + // `this` === `client` + // `event.target` === the element that was clicked + event.target.style.display = "none"; + alert("Copied text to clipboard: " + event.data["text/plain"] ); + } ); +} ); +``` + +See [docs/instructions.md](docs/instructions.md) for more advanced options in using the library on your site. +See [docs/api/ZeroClipboard.md](docs/api/ZeroClipboard.md) for the complete API documentation. + +Here is a working [test page](http://zeroclipboard.org/#demo) where you can try out ZeroClipboard in your browser. + + +## Testing ZeroClipboard Locally + +To test the page [demo page](http://zeroclipboard.org/#demo) locally, clone the [website repo](https://github.com/zeroclipboard/zeroclipboard.org). + + +## Support + +This library is fully compatible with Flash Player 11.0.0 and above, which requires +that the clipboard copy operation be initiated by a user click event inside the +Flash movie. This is achieved by automatically floating the invisible movie on top +of a [DOM](http://en.wikipedia.org/wiki/Document_Object_Model) element of your +choice. Standard mouse events are even propagated out to your DOM element, so you +can still have rollover and mousedown effects with just a _little_ extra effort. + +ZeroClipboard `v2.x` is expected to work in IE9+ and all of the evergreen browsers. +Although support for IE7 & IE8 was officially dropped in `v2.0.0`, it was actually +still _technically_ supported through `v2.0.2`. + +## Contributing + +see [CONTRIBUTING.md](CONTRIBUTING.md) + + +## Releases + +Starting with version [1.1.7](https://github.com/zeroclipboard/zeroclipboard/releases/tag/v1.1.7), ZeroClipboard uses [semantic versioning](http://semver.org/). + +see [releases](https://github.com/zeroclipboard/zeroclipboard/releases) + + +## Roadmap + +see [roadmap.md](docs/roadmap.md) diff --git a/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.Core.js b/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.Core.js new file mode 100644 index 0000000000..9edd4b19ef --- /dev/null +++ b/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.Core.js @@ -0,0 +1,1913 @@ +/*! + * ZeroClipboard + * The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface. + * Copyright (c) 2009-2014 Jon Rohan, James M. Greene + * Licensed MIT + * http://zeroclipboard.org/ + * v2.2.0-beta.3 + */ +(function(window, undefined) { + "use strict"; + /** + * Store references to critically important global functions that may be + * overridden on certain web pages. + */ + 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() { + var unwrapper = function(el) { + return el; + }; + if (typeof _window.wrap === "function" && typeof _window.unwrap === "function") { + try { + var div = _document.createElement("div"); + var unwrappedDiv = _window.unwrap(div); + if (div.nodeType === 1 && unwrappedDiv && unwrappedDiv.nodeType === 1) { + unwrapper = _window.unwrap; + } + } catch (e) {} + } + return unwrapper; + }(); + /** + * Convert an `arguments` object into an Array. + * + * @returns The arguments as an Array + * @private + */ + var _args = function(argumentsObj) { + return _slice.call(argumentsObj, 0); + }; + /** + * Shallow-copy the owned, enumerable properties of one object over to another, similar to jQuery's `$.extend`. + * + * @returns The target object, augmented + * @private + */ + var _extend = function() { + var i, len, arg, prop, src, copy, args = _args(arguments), target = args[0] || {}; + for (i = 1, len = args.length; i < len; i++) { + if ((arg = args[i]) != null) { + for (prop in arg) { + if (_hasOwn.call(arg, prop)) { + src = target[prop]; + copy = arg[prop]; + if (target !== copy && copy !== undefined) { + target[prop] = copy; + } + } + } + } + } + return target; + }; + /** + * Return a deep copy of the source object or array. + * + * @returns Object or Array + * @private + */ + var _deepCopy = function(source) { + var copy, i, len, prop; + if (typeof source !== "object" || source == null || typeof source.nodeType === "number") { + copy = source; + } else if (typeof source.length === "number") { + copy = []; + for (i = 0, len = source.length; i < len; i++) { + if (_hasOwn.call(source, i)) { + copy[i] = _deepCopy(source[i]); + } + } + } else { + copy = {}; + for (prop in source) { + if (_hasOwn.call(source, prop)) { + copy[prop] = _deepCopy(source[prop]); + } + } + } + return copy; + }; + /** + * Makes a shallow copy of `obj` (like `_extend`) but filters its properties based on a list of `keys` to keep. + * The inverse of `_omit`, mostly. The big difference is that these properties do NOT need to be enumerable to + * be kept. + * + * @returns A new filtered object. + * @private + */ + var _pick = function(obj, keys) { + var newObj = {}; + for (var i = 0, len = keys.length; i < len; i++) { + if (keys[i] in obj) { + newObj[keys[i]] = obj[keys[i]]; + } + } + return newObj; + }; + /** + * Makes a shallow copy of `obj` (like `_extend`) but filters its properties based on a list of `keys` to omit. + * The inverse of `_pick`. + * + * @returns A new filtered object. + * @private + */ + var _omit = function(obj, keys) { + var newObj = {}; + for (var prop in obj) { + if (keys.indexOf(prop) === -1) { + newObj[prop] = obj[prop]; + } + } + return newObj; + }; + /** + * Remove all owned, enumerable properties from an object. + * + * @returns The original object without its owned, enumerable properties. + * @private + */ + var _deleteOwnProperties = function(obj) { + if (obj) { + for (var prop in obj) { + if (_hasOwn.call(obj, prop)) { + delete obj[prop]; + } + } + } + return obj; + }; + /** + * Determine if an element is contained within another element. + * + * @returns Boolean + * @private + */ + var _containedBy = function(el, ancestorEl) { + 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)) { + do { + if (el === ancestorEl) { + return true; + } + el = el.parentNode; + } while (el); + } + return false; + }; + /** + * Get the URL path's parent directory. + * + * @returns String or `undefined` + * @private + */ + var _getDirPathOfUrl = function(url) { + var dir; + if (typeof url === "string" && url) { + dir = url.split("#")[0].split("?")[0]; + dir = url.slice(0, url.lastIndexOf("/") + 1); + } + return dir; + }; + /** + * Get the current script's URL by throwing an `Error` and analyzing it. + * + * @returns String or `undefined` + * @private + */ + var _getCurrentScriptUrlFromErrorStack = function(stack) { + var url, matches; + if (typeof stack === "string" && stack) { + matches = stack.match(/^(?:|[^:@]*@|.+\)@(?=http[s]?|file)|.+?\s+(?: at |@)(?:[^:\(]+ )*[\(]?)((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/); + if (matches && matches[1]) { + url = matches[1]; + } else { + matches = stack.match(/\)@((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/); + if (matches && matches[1]) { + url = matches[1]; + } + } + } + return url; + }; + /** + * Get the current script's URL by throwing an `Error` and analyzing it. + * + * @returns String or `undefined` + * @private + */ + var _getCurrentScriptUrlFromError = function() { + var url, err; + try { + throw new _Error(); + } catch (e) { + err = e; + } + if (err) { + url = err.sourceURL || err.fileName || _getCurrentScriptUrlFromErrorStack(err.stack); + } + return url; + }; + /** + * Get the current script's URL. + * + * @returns String or `undefined` + * @private + */ + var _getCurrentScriptUrl = function() { + var jsPath, scripts, i; + if (_document.currentScript && (jsPath = _document.currentScript.src)) { + return jsPath; + } + scripts = _document.getElementsByTagName("script"); + if (scripts.length === 1) { + return scripts[0].src || undefined; + } + if ("readyState" in scripts[0]) { + for (i = scripts.length; i--; ) { + if (scripts[i].readyState === "interactive" && (jsPath = scripts[i].src)) { + return jsPath; + } + } + } + if (_document.readyState === "loading" && (jsPath = scripts[scripts.length - 1].src)) { + return jsPath; + } + if (jsPath = _getCurrentScriptUrlFromError()) { + return jsPath; + } + return undefined; + }; + /** + * Get the unanimous parent directory of ALL script tags. + * If any script tags are either (a) inline or (b) from differing parent + * directories, this method must return `undefined`. + * + * @returns String or `undefined` + * @private + */ + var _getUnanimousScriptParentDir = function() { + var i, jsDir, jsPath, scripts = _document.getElementsByTagName("script"); + for (i = scripts.length; i--; ) { + if (!(jsPath = scripts[i].src)) { + jsDir = null; + break; + } + jsPath = _getDirPathOfUrl(jsPath); + if (jsDir == null) { + jsDir = jsPath; + } else if (jsDir !== jsPath) { + jsDir = null; + break; + } + } + return jsDir || undefined; + }; + /** + * Get the presumed location of the "ZeroClipboard.swf" file, based on the location + * of the executing JavaScript file (e.g. "ZeroClipboard.js", etc.). + * + * @returns String + * @private + */ + var _getDefaultSwfPath = function() { + var jsDir = _getDirPathOfUrl(_getCurrentScriptUrl()) || _getUnanimousScriptParentDir() || ""; + return jsDir + "ZeroClipboard.swf"; + }; + /** + * Keep track of the state of the Flash object. + * @private + */ + var _flashState = { + bridge: null, + version: "0.0.0", + pluginType: "unknown", + disabled: null, + outdated: null, + unavailable: null, + degraded: null, + deactivated: null, + overdue: null, + ready: null + }; + /** + * The minimum Flash Player version required to use ZeroClipboard completely. + * @readonly + * @private + */ + var _minimumFlashVersion = "11.0.0"; + /** + * The ZeroClipboard library version number, as reported by Flash, at the time the SWF was compiled. + */ + var _zcSwfVersion; + /** + * Keep track of all event listener registrations. + * @private + */ + var _handlers = {}; + /** + * Keep track of the currently activated element. + * @private + */ + var _currentElement; + /** + * Keep track of the element that was activated when a `copy` process started. + * @private + */ + var _copyTarget; + /** + * Keep track of data for the pending clipboard transaction. + * @private + */ + var _clipData = {}; + /** + * Keep track of data formats for the pending clipboard transaction. + * @private + */ + var _clipDataFormatMap = null; + /** + * Keep track of the Flash availability check timeout. + * @private + */ + var _flashCheckTimeout = 0; + /** + * Keep track of SWF network errors interval polling. + * @private + */ + var _swfFallbackCheckInterval = 0; + /** + * The `message` store for events + * @private + */ + var _eventMessages = { + ready: "Flash communication is established", + error: { + "flash-disabled": "Flash is disabled or not installed", + "flash-outdated": "Flash is too outdated to support ZeroClipboard", + "flash-unavailable": "Flash is unable to communicate bidirectionally with JavaScript", + "flash-degraded": "Flash is unable to preserve data fidelity when communicating with JavaScript", + "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.", + "flash-overdue": "Flash communication was established but NOT within the acceptable time limit", + "version-mismatch": "ZeroClipboard JS version number does not match ZeroClipboard SWF version number", + "clipboard-error": "At least one error was thrown while ZeroClipboard was attempting to inject your data into the clipboard", + "config-mismatch": "ZeroClipboard configuration does not match Flash's reality", + "swf-not-found": "The ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity" + } + }; + /** + * ZeroClipboard configuration defaults for the Core module. + * @private + */ + var _globalConfig = { + swfPath: _getDefaultSwfPath(), + trustedDomains: window.location.host ? [ window.location.host ] : [], + cacheBust: true, + forceEnhancedClipboard: false, + flashLoadTimeout: 3e4, + autoActivate: true, + bubbleEvents: true, + containerId: "global-zeroclipboard-html-bridge", + containerClass: "global-zeroclipboard-container", + swfObjectId: "global-zeroclipboard-flash-bridge", + hoverClass: "zeroclipboard-is-hover", + activeClass: "zeroclipboard-is-active", + forceHandCursor: false, + title: null, + zIndex: 999999999 + }; + /** + * The underlying implementation of `ZeroClipboard.config`. + * @private + */ + var _config = function(options) { + if (typeof options === "object" && options !== null) { + for (var prop in options) { + if (_hasOwn.call(options, prop)) { + if (/^(?:forceHandCursor|title|zIndex|bubbleEvents)$/.test(prop)) { + _globalConfig[prop] = options[prop]; + } else if (_flashState.bridge == null) { + if (prop === "containerId" || prop === "swfObjectId") { + if (_isValidHtml4Id(options[prop])) { + _globalConfig[prop] = options[prop]; + } else { + throw new Error("The specified `" + prop + "` value is not valid as an HTML4 Element ID"); + } + } else { + _globalConfig[prop] = options[prop]; + } + } + } + } + } + if (typeof options === "string" && options) { + if (_hasOwn.call(_globalConfig, options)) { + return _globalConfig[options]; + } + return; + } + return _deepCopy(_globalConfig); + }; + /** + * The underlying implementation of `ZeroClipboard.state`. + * @private + */ + var _state = function() { + return { + browser: _pick(_navigator, [ "userAgent", "platform", "appName" ]), + flash: _omit(_flashState, [ "bridge" ]), + zeroclipboard: { + version: ZeroClipboard.version, + config: ZeroClipboard.config() + } + }; + }; + /** + * The underlying implementation of `ZeroClipboard.isFlashUnusable`. + * @private + */ + var _isFlashUnusable = function() { + return !!(_flashState.disabled || _flashState.outdated || _flashState.unavailable || _flashState.degraded || _flashState.deactivated); + }; + /** + * The underlying implementation of `ZeroClipboard.on`. + * @private + */ + var _on = function(eventType, listener) { + var i, len, events, added = {}; + if (typeof eventType === "string" && eventType) { + events = eventType.toLowerCase().split(/\s+/); + } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") { + for (i in eventType) { + if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") { + ZeroClipboard.on(i, eventType[i]); + } + } + } + if (events && events.length) { + for (i = 0, len = events.length; i < len; i++) { + eventType = events[i].replace(/^on/, ""); + added[eventType] = true; + if (!_handlers[eventType]) { + _handlers[eventType] = []; + } + _handlers[eventType].push(listener); + } + if (added.ready && _flashState.ready) { + ZeroClipboard.emit({ + type: "ready" + }); + } + if (added.error) { + var flashErrorTypes = [ "disabled", "outdated", "unavailable", "degraded", "deactivated", "overdue" ]; + for (i = 0, len = flashErrorTypes.length; i < len; i++) { + if (_flashState[flashErrorTypes[i]] === true) { + ZeroClipboard.emit({ + type: "error", + name: "flash-" + flashErrorTypes[i] + }); + break; + } + } + if (_zcSwfVersion !== undefined && ZeroClipboard.version !== _zcSwfVersion) { + ZeroClipboard.emit({ + type: "error", + name: "version-mismatch", + jsVersion: ZeroClipboard.version, + swfVersion: _zcSwfVersion + }); + } + } + } + return ZeroClipboard; + }; + /** + * The underlying implementation of `ZeroClipboard.off`. + * @private + */ + var _off = function(eventType, listener) { + var i, len, foundIndex, events, perEventHandlers; + if (arguments.length === 0) { + events = _keys(_handlers); + } else if (typeof eventType === "string" && eventType) { + events = eventType.split(/\s+/); + } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") { + for (i in eventType) { + if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") { + ZeroClipboard.off(i, eventType[i]); + } + } + } + if (events && events.length) { + for (i = 0, len = events.length; i < len; i++) { + eventType = events[i].toLowerCase().replace(/^on/, ""); + perEventHandlers = _handlers[eventType]; + if (perEventHandlers && perEventHandlers.length) { + if (listener) { + foundIndex = perEventHandlers.indexOf(listener); + while (foundIndex !== -1) { + perEventHandlers.splice(foundIndex, 1); + foundIndex = perEventHandlers.indexOf(listener, foundIndex); + } + } else { + perEventHandlers.length = 0; + } + } + } + } + return ZeroClipboard; + }; + /** + * The underlying implementation of `ZeroClipboard.handlers`. + * @private + */ + var _listeners = function(eventType) { + var copy; + if (typeof eventType === "string" && eventType) { + copy = _deepCopy(_handlers[eventType]) || null; + } else { + copy = _deepCopy(_handlers); + } + return copy; + }; + /** + * The underlying implementation of `ZeroClipboard.emit`. + * @private + */ + var _emit = function(event) { + var eventCopy, returnVal, tmp; + event = _createEvent(event); + if (!event) { + return; + } + if (_preprocessEvent(event)) { + return; + } + if (event.type === "ready" && _flashState.overdue === true) { + return ZeroClipboard.emit({ + type: "error", + name: "flash-overdue" + }); + } + eventCopy = _extend({}, event); + _dispatchCallbacks.call(this, eventCopy); + if (event.type === "copy") { + tmp = _mapClipDataToFlash(_clipData); + returnVal = tmp.data; + _clipDataFormatMap = tmp.formatMap; + } + return returnVal; + }; + /** + * The underlying implementation of `ZeroClipboard.create`. + * @private + */ + var _create = function() { + if (typeof _flashState.ready !== "boolean") { + _flashState.ready = false; + } + if (!ZeroClipboard.isFlashUnusable() && _flashState.bridge === null) { + var maxWait = _globalConfig.flashLoadTimeout; + if (typeof maxWait === "number" && maxWait >= 0) { + _flashCheckTimeout = _setTimeout(function() { + if (typeof _flashState.deactivated !== "boolean") { + _flashState.deactivated = true; + } + if (_flashState.deactivated === true) { + ZeroClipboard.emit({ + type: "error", + name: "flash-deactivated" + }); + } + }, maxWait); + } + _flashState.overdue = false; + _embedSwf(); + } + }; + /** + * The underlying implementation of `ZeroClipboard.destroy`. + * @private + */ + var _destroy = function() { + ZeroClipboard.clearData(); + ZeroClipboard.blur(); + ZeroClipboard.emit("destroy"); + _unembedSwf(); + ZeroClipboard.off(); + }; + /** + * The underlying implementation of `ZeroClipboard.setData`. + * @private + */ + var _setData = function(format, data) { + var dataObj; + if (typeof format === "object" && format && typeof data === "undefined") { + dataObj = format; + ZeroClipboard.clearData(); + } else if (typeof format === "string" && format) { + dataObj = {}; + dataObj[format] = data; + } else { + return; + } + for (var dataFormat in dataObj) { + if (typeof dataFormat === "string" && dataFormat && _hasOwn.call(dataObj, dataFormat) && typeof dataObj[dataFormat] === "string" && dataObj[dataFormat]) { + _clipData[dataFormat] = dataObj[dataFormat]; + } + } + }; + /** + * The underlying implementation of `ZeroClipboard.clearData`. + * @private + */ + var _clearData = function(format) { + if (typeof format === "undefined") { + _deleteOwnProperties(_clipData); + _clipDataFormatMap = null; + } else if (typeof format === "string" && _hasOwn.call(_clipData, format)) { + delete _clipData[format]; + } + }; + /** + * The underlying implementation of `ZeroClipboard.getData`. + * @private + */ + var _getData = function(format) { + if (typeof format === "undefined") { + return _deepCopy(_clipData); + } else if (typeof format === "string" && _hasOwn.call(_clipData, format)) { + return _clipData[format]; + } + }; + /** + * The underlying implementation of `ZeroClipboard.focus`/`ZeroClipboard.activate`. + * @private + */ + var _focus = function(element) { + if (!(element && element.nodeType === 1)) { + return; + } + if (_currentElement) { + _removeClass(_currentElement, _globalConfig.activeClass); + if (_currentElement !== element) { + _removeClass(_currentElement, _globalConfig.hoverClass); + } + } + _currentElement = element; + _addClass(element, _globalConfig.hoverClass); + var newTitle = element.getAttribute("title") || _globalConfig.title; + if (typeof newTitle === "string" && newTitle) { + var htmlBridge = _getHtmlBridge(_flashState.bridge); + if (htmlBridge) { + htmlBridge.setAttribute("title", newTitle); + } + } + var useHandCursor = _globalConfig.forceHandCursor === true || _getStyle(element, "cursor") === "pointer"; + _setHandCursor(useHandCursor); + _reposition(); + }; + /** + * The underlying implementation of `ZeroClipboard.blur`/`ZeroClipboard.deactivate`. + * @private + */ + var _blur = function() { + var htmlBridge = _getHtmlBridge(_flashState.bridge); + if (htmlBridge) { + htmlBridge.removeAttribute("title"); + htmlBridge.style.left = "0px"; + htmlBridge.style.top = "-9999px"; + htmlBridge.style.width = "1px"; + htmlBridge.style.top = "1px"; + } + if (_currentElement) { + _removeClass(_currentElement, _globalConfig.hoverClass); + _removeClass(_currentElement, _globalConfig.activeClass); + _currentElement = null; + } + }; + /** + * The underlying implementation of `ZeroClipboard.activeElement`. + * @private + */ + var _activeElement = function() { + return _currentElement || null; + }; + /** + * Check if a value is a valid HTML4 `ID` or `Name` token. + * @private + */ + var _isValidHtml4Id = function(id) { + return typeof id === "string" && id && /^[A-Za-z][A-Za-z0-9_:\-\.]*$/.test(id); + }; + /** + * Create or update an `event` object, based on the `eventType`. + * @private + */ + var _createEvent = function(event) { + var eventType; + if (typeof event === "string" && event) { + eventType = event; + event = {}; + } else if (typeof event === "object" && event && typeof event.type === "string" && event.type) { + eventType = event.type; + } + if (!eventType) { + return; + } + eventType = eventType.toLowerCase(); + if (!event.target && (/^(copy|aftercopy|_click)$/.test(eventType) || eventType === "error" && event.name === "clipboard-error")) { + event.target = _copyTarget; + } + _extend(event, { + type: eventType, + target: event.target || _currentElement || null, + relatedTarget: event.relatedTarget || null, + currentTarget: _flashState && _flashState.bridge || null, + timeStamp: event.timeStamp || _now() || null + }); + var msg = _eventMessages[event.type]; + if (event.type === "error" && event.name && msg) { + msg = msg[event.name]; + } + if (msg) { + event.message = msg; + } + if (event.type === "ready") { + _extend(event, { + target: null, + version: _flashState.version + }); + } + if (event.type === "error") { + if (/^flash-(disabled|outdated|unavailable|degraded|deactivated|overdue)$/.test(event.name)) { + _extend(event, { + target: null, + minimumVersion: _minimumFlashVersion + }); + } + if (/^flash-(outdated|unavailable|degraded|deactivated|overdue)$/.test(event.name)) { + _extend(event, { + version: _flashState.version + }); + } + } + if (event.type === "copy") { + event.clipboardData = { + setData: ZeroClipboard.setData, + clearData: ZeroClipboard.clearData + }; + } + if (event.type === "aftercopy") { + event = _mapClipResultsFromFlash(event, _clipDataFormatMap); + } + if (event.target && !event.relatedTarget) { + event.relatedTarget = _getRelatedTarget(event.target); + } + return _addMouseData(event); + }; + /** + * Get a relatedTarget from the target's `data-clipboard-target` attribute + * @private + */ + var _getRelatedTarget = function(targetEl) { + var relatedTargetId = targetEl && targetEl.getAttribute && targetEl.getAttribute("data-clipboard-target"); + return relatedTargetId ? _document.getElementById(relatedTargetId) : null; + }; + /** + * Add element and position data to `MouseEvent` instances + * @private + */ + var _addMouseData = function(event) { + if (event && /^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) { + var srcElement = event.target; + var fromElement = event.type === "_mouseover" && event.relatedTarget ? event.relatedTarget : undefined; + var toElement = event.type === "_mouseout" && event.relatedTarget ? event.relatedTarget : undefined; + var pos = _getElementPosition(srcElement); + var screenLeft = _window.screenLeft || _window.screenX || 0; + var screenTop = _window.screenTop || _window.screenY || 0; + var scrollLeft = _document.body.scrollLeft + _document.documentElement.scrollLeft; + var scrollTop = _document.body.scrollTop + _document.documentElement.scrollTop; + var pageX = pos.left + (typeof event._stageX === "number" ? event._stageX : 0); + var pageY = pos.top + (typeof event._stageY === "number" ? event._stageY : 0); + var clientX = pageX - scrollLeft; + var clientY = pageY - scrollTop; + var screenX = screenLeft + clientX; + var screenY = screenTop + clientY; + var moveX = typeof event.movementX === "number" ? event.movementX : 0; + var moveY = typeof event.movementY === "number" ? event.movementY : 0; + delete event._stageX; + delete event._stageY; + _extend(event, { + srcElement: srcElement, + fromElement: fromElement, + toElement: toElement, + screenX: screenX, + screenY: screenY, + pageX: pageX, + pageY: pageY, + clientX: clientX, + clientY: clientY, + x: clientX, + y: clientY, + movementX: moveX, + movementY: moveY, + offsetX: 0, + offsetY: 0, + layerX: 0, + layerY: 0 + }); + } + return event; + }; + /** + * Determine if an event's registered handlers should be execute synchronously or asynchronously. + * + * @returns {boolean} + * @private + */ + var _shouldPerformAsync = function(event) { + var eventType = event && typeof event.type === "string" && event.type || ""; + return !/^(?:(?:before)?copy|destroy)$/.test(eventType); + }; + /** + * Control if a callback should be executed asynchronously or not. + * + * @returns `undefined` + * @private + */ + var _dispatchCallback = function(func, context, args, async) { + if (async) { + _setTimeout(function() { + func.apply(context, args); + }, 0); + } else { + func.apply(context, args); + } + }; + /** + * Handle the actual dispatching of events to client instances. + * + * @returns `undefined` + * @private + */ + var _dispatchCallbacks = function(event) { + if (!(typeof event === "object" && event && event.type)) { + return; + } + var async = _shouldPerformAsync(event); + var wildcardTypeHandlers = _handlers["*"] || []; + var specificTypeHandlers = _handlers[event.type] || []; + var handlers = wildcardTypeHandlers.concat(specificTypeHandlers); + if (handlers && handlers.length) { + var i, len, func, context, eventCopy, originalContext = this; + for (i = 0, len = handlers.length; i < len; i++) { + func = handlers[i]; + context = originalContext; + if (typeof func === "string" && typeof _window[func] === "function") { + func = _window[func]; + } + if (typeof func === "object" && func && typeof func.handleEvent === "function") { + context = func; + func = func.handleEvent; + } + if (typeof func === "function") { + eventCopy = _extend({}, event); + _dispatchCallback(func, context, [ eventCopy ], async); + } + } + } + return this; + }; + /** + * Preprocess any special behaviors, reactions, or state changes after receiving this event. + * Executes only once per event emitted, NOT once per client. + * @private + */ + var _preprocessEvent = function(event) { + var element = event.target || _currentElement || null; + var sourceIsSwf = event._source === "swf"; + delete event._source; + var flashErrorNames = [ "flash-disabled", "flash-outdated", "flash-unavailable", "flash-degraded", "flash-deactivated", "flash-overdue" ]; + switch (event.type) { + case "error": + if (flashErrorNames.indexOf(event.name) !== -1) { + _extend(_flashState, { + disabled: event.name === "flash-disabled", + outdated: event.name === "flash-outdated", + unavailable: event.name === "flash-unavailable", + degraded: event.name === "flash-degraded", + deactivated: event.name === "flash-deactivated", + overdue: event.name === "flash-overdue", + ready: false + }); + } else if (event.name === "version-mismatch") { + _zcSwfVersion = event.swfVersion; + _extend(_flashState, { + disabled: false, + outdated: false, + unavailable: false, + degraded: false, + deactivated: false, + overdue: false, + ready: false + }); + } + _clearTimeoutsAndPolling(); + break; + + case "ready": + _zcSwfVersion = event.swfVersion; + var wasDeactivated = _flashState.deactivated === true; + _extend(_flashState, { + disabled: false, + outdated: false, + unavailable: false, + degraded: false, + deactivated: false, + overdue: wasDeactivated, + ready: !wasDeactivated + }); + _clearTimeoutsAndPolling(); + break; + + case "beforecopy": + _copyTarget = element; + break; + + case "copy": + var textContent, htmlContent, targetEl = event.relatedTarget; + if (!(_clipData["text/html"] || _clipData["text/plain"]) && targetEl && (htmlContent = targetEl.value || targetEl.outerHTML || targetEl.innerHTML) && (textContent = targetEl.value || targetEl.textContent || targetEl.innerText)) { + event.clipboardData.clearData(); + event.clipboardData.setData("text/plain", textContent); + if (htmlContent !== textContent) { + event.clipboardData.setData("text/html", htmlContent); + } + } else if (!_clipData["text/plain"] && event.target && (textContent = event.target.getAttribute("data-clipboard-text"))) { + event.clipboardData.clearData(); + event.clipboardData.setData("text/plain", textContent); + } + break; + + case "aftercopy": + _queueEmitClipboardErrors(event); + ZeroClipboard.clearData(); + if (element && element !== _safeActiveElement() && element.focus) { + element.focus(); + } + break; + + case "_mouseover": + ZeroClipboard.focus(element); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) { + _fireMouseEvent(_extend({}, event, { + type: "mouseenter", + bubbles: false, + cancelable: false + })); + } + _fireMouseEvent(_extend({}, event, { + type: "mouseover" + })); + } + break; + + case "_mouseout": + ZeroClipboard.blur(); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) { + _fireMouseEvent(_extend({}, event, { + type: "mouseleave", + bubbles: false, + cancelable: false + })); + } + _fireMouseEvent(_extend({}, event, { + type: "mouseout" + })); + } + break; + + case "_mousedown": + _addClass(element, _globalConfig.activeClass); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + + case "_mouseup": + _removeClass(element, _globalConfig.activeClass); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + + case "_click": + _copyTarget = null; + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + + case "_mousemove": + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + } + if (/^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) { + return true; + } + }; + /** + * Check an "aftercopy" event for clipboard errors and emit a corresponding "error" event. + * @private + */ + var _queueEmitClipboardErrors = function(aftercopyEvent) { + if (aftercopyEvent.errors && aftercopyEvent.errors.length > 0) { + var errorEvent = _deepCopy(aftercopyEvent); + _extend(errorEvent, { + type: "error", + name: "clipboard-error" + }); + delete errorEvent.success; + _setTimeout(function() { + ZeroClipboard.emit(errorEvent); + }, 0); + } + }; + /** + * Dispatch a synthetic MouseEvent. + * + * @returns `undefined` + * @private + */ + var _fireMouseEvent = function(event) { + if (!(event && typeof event.type === "string" && event)) { + return; + } + var e, target = event.target || null, doc = target && target.ownerDocument || _document, defaults = { + view: doc.defaultView || _window, + canBubble: true, + cancelable: true, + detail: event.type === "click" ? 1 : 0, + button: typeof event.which === "number" ? event.which - 1 : typeof event.button === "number" ? event.button : doc.createEvent ? 0 : 1 + }, args = _extend(defaults, event); + if (!target) { + return; + } + if (doc.createEvent && target.dispatchEvent) { + 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 ]; + e = doc.createEvent("MouseEvents"); + if (e.initMouseEvent) { + e.initMouseEvent.apply(e, args); + e._source = "js"; + target.dispatchEvent(e); + } + } + }; + /** + * Continuously poll the DOM until either: + * (a) the fallback content becomes visible, or + * (b) we receive an event from SWF (handled elsewhere) + * + * IMPORTANT: + * This is NOT a necessary check but it can result in significantly faster + * detection of bad `swfPath` configuration and/or network/server issues [in + * supported browsers] than waiting for the entire `flashLoadTimeout` duration + * to elapse before detecting that the SWF cannot be loaded. The detection + * duration can be anywhere from 10-30 times faster [in supported browsers] by + * using this approach. + * + * @returns `undefined` + * @private + */ + var _watchForSwfFallbackContent = function() { + var maxWait = _globalConfig.flashLoadTimeout; + if (typeof maxWait === "number" && maxWait >= 0) { + var pollWait = Math.min(1e3, maxWait / 10); + var fallbackContentId = _globalConfig.swfObjectId + "_fallbackContent"; + _swfFallbackCheckInterval = _setInterval(function() { + var el = _document.getElementById(fallbackContentId); + if (_isElementVisible(el)) { + _clearTimeoutsAndPolling(); + _flashState.deactivated = null; + ZeroClipboard.emit({ + type: "error", + name: "swf-not-found" + }); + } + }, pollWait); + } + }; + /** + * Create the HTML bridge element to embed the Flash object into. + * @private + */ + var _createHtmlBridge = function() { + var container = _document.createElement("div"); + container.id = _globalConfig.containerId; + container.className = _globalConfig.containerClass; + container.style.position = "absolute"; + container.style.left = "0px"; + container.style.top = "-9999px"; + container.style.width = "1px"; + container.style.height = "1px"; + container.style.zIndex = "" + _getSafeZIndex(_globalConfig.zIndex); + return container; + }; + /** + * Get the HTML element container that wraps the Flash bridge object/element. + * @private + */ + var _getHtmlBridge = function(flashBridge) { + var htmlBridge = flashBridge && flashBridge.parentNode; + while (htmlBridge && htmlBridge.nodeName === "OBJECT" && htmlBridge.parentNode) { + htmlBridge = htmlBridge.parentNode; + } + return htmlBridge || null; + }; + /** + * Create the SWF object. + * + * @returns The SWF object reference. + * @private + */ + var _embedSwf = function() { + var len, flashBridge = _flashState.bridge, container = _getHtmlBridge(flashBridge); + if (!flashBridge) { + var allowScriptAccess = _determineScriptAccess(_window.location.host, _globalConfig); + var allowNetworking = allowScriptAccess === "never" ? "none" : "all"; + var flashvars = _vars(_extend({ + jsVersion: ZeroClipboard.version + }, _globalConfig)); + var swfUrl = _globalConfig.swfPath + _cacheBust(_globalConfig.swfPath, _globalConfig); + container = _createHtmlBridge(); + var divToBeReplaced = _document.createElement("div"); + container.appendChild(divToBeReplaced); + _document.body.appendChild(container); + var tmpDiv = _document.createElement("div"); + var usingActiveX = _flashState.pluginType === "activex"; + tmpDiv.innerHTML = '" + (usingActiveX ? '' : "") + '' + '' + '' + '' + '' + '
 
' + "
"; + flashBridge = tmpDiv.firstChild; + tmpDiv = null; + _unwrap(flashBridge).ZeroClipboard = ZeroClipboard; + container.replaceChild(flashBridge, divToBeReplaced); + _watchForSwfFallbackContent(); + } + if (!flashBridge) { + flashBridge = _document[_globalConfig.swfObjectId]; + if (flashBridge && (len = flashBridge.length)) { + flashBridge = flashBridge[len - 1]; + } + if (!flashBridge && container) { + flashBridge = container.firstChild; + } + } + _flashState.bridge = flashBridge || null; + return flashBridge; + }; + /** + * Destroy the SWF object. + * @private + */ + var _unembedSwf = function() { + var flashBridge = _flashState.bridge; + if (flashBridge) { + var htmlBridge = _getHtmlBridge(flashBridge); + if (htmlBridge) { + if (_flashState.pluginType === "activex" && "readyState" in flashBridge) { + flashBridge.style.display = "none"; + (function removeSwfFromIE() { + if (flashBridge.readyState === 4) { + for (var prop in flashBridge) { + if (typeof flashBridge[prop] === "function") { + flashBridge[prop] = null; + } + } + if (flashBridge.parentNode) { + flashBridge.parentNode.removeChild(flashBridge); + } + if (htmlBridge.parentNode) { + htmlBridge.parentNode.removeChild(htmlBridge); + } + } else { + _setTimeout(removeSwfFromIE, 10); + } + })(); + } else { + if (flashBridge.parentNode) { + flashBridge.parentNode.removeChild(flashBridge); + } + if (htmlBridge.parentNode) { + htmlBridge.parentNode.removeChild(htmlBridge); + } + } + } + _clearTimeoutsAndPolling(); + _flashState.ready = null; + _flashState.bridge = null; + _flashState.deactivated = null; + _zcSwfVersion = undefined; + } + }; + /** + * Map the data format names of the "clipData" to Flash-friendly names. + * + * @returns A new transformed object. + * @private + */ + var _mapClipDataToFlash = function(clipData) { + var newClipData = {}, formatMap = {}; + if (!(typeof clipData === "object" && clipData)) { + return; + } + for (var dataFormat in clipData) { + if (dataFormat && _hasOwn.call(clipData, dataFormat) && typeof clipData[dataFormat] === "string" && clipData[dataFormat]) { + switch (dataFormat.toLowerCase()) { + case "text/plain": + case "text": + case "air:text": + case "flash:text": + newClipData.text = clipData[dataFormat]; + formatMap.text = dataFormat; + break; + + case "text/html": + case "html": + case "air:html": + case "flash:html": + newClipData.html = clipData[dataFormat]; + formatMap.html = dataFormat; + break; + + case "application/rtf": + case "text/rtf": + case "rtf": + case "richtext": + case "air:rtf": + case "flash:rtf": + newClipData.rtf = clipData[dataFormat]; + formatMap.rtf = dataFormat; + break; + + default: + break; + } + } + } + return { + data: newClipData, + formatMap: formatMap + }; + }; + /** + * Map the data format names from Flash-friendly names back to their original "clipData" names (via a format mapping). + * + * @returns A new transformed object. + * @private + */ + var _mapClipResultsFromFlash = function(clipResults, formatMap) { + if (!(typeof clipResults === "object" && clipResults && typeof formatMap === "object" && formatMap)) { + return clipResults; + } + var newResults = {}; + for (var prop in clipResults) { + if (_hasOwn.call(clipResults, prop)) { + if (prop === "errors") { + newResults[prop] = clipResults[prop] ? clipResults[prop].slice() : []; + for (var i = 0, len = newResults[prop].length; i < len; i++) { + newResults[prop][i].format = formatMap[newResults[prop][i].format]; + } + } else if (prop !== "success" && prop !== "data") { + newResults[prop] = clipResults[prop]; + } else { + newResults[prop] = {}; + var tmpHash = clipResults[prop]; + for (var dataFormat in tmpHash) { + if (dataFormat && _hasOwn.call(tmpHash, dataFormat) && _hasOwn.call(formatMap, dataFormat)) { + newResults[prop][formatMap[dataFormat]] = tmpHash[dataFormat]; + } + } + } + } + } + return newResults; + }; + /** + * Will look at a path, and will create a "?noCache={time}" or "&noCache={time}" + * query param string to return. Does NOT append that string to the original path. + * This is useful because ExternalInterface often breaks when a Flash SWF is cached. + * + * @returns The `noCache` query param with necessary "?"/"&" prefix. + * @private + */ + var _cacheBust = function(path, options) { + var cacheBust = options == null || options && options.cacheBust === true; + if (cacheBust) { + return (path.indexOf("?") === -1 ? "?" : "&") + "noCache=" + _now(); + } else { + return ""; + } + }; + /** + * Creates a query string for the FlashVars param. + * Does NOT include the cache-busting query param. + * + * @returns FlashVars query string + * @private + */ + var _vars = function(options) { + var i, len, domain, domains, str = "", trustedOriginsExpanded = []; + if (options.trustedDomains) { + if (typeof options.trustedDomains === "string") { + domains = [ options.trustedDomains ]; + } else if (typeof options.trustedDomains === "object" && "length" in options.trustedDomains) { + domains = options.trustedDomains; + } + } + if (domains && domains.length) { + for (i = 0, len = domains.length; i < len; i++) { + if (_hasOwn.call(domains, i) && domains[i] && typeof domains[i] === "string") { + domain = _extractDomain(domains[i]); + if (!domain) { + continue; + } + if (domain === "*") { + trustedOriginsExpanded.length = 0; + trustedOriginsExpanded.push(domain); + break; + } + trustedOriginsExpanded.push.apply(trustedOriginsExpanded, [ domain, "//" + domain, _window.location.protocol + "//" + domain ]); + } + } + } + if (trustedOriginsExpanded.length) { + str += "trustedOrigins=" + _encodeURIComponent(trustedOriginsExpanded.join(",")); + } + if (options.forceEnhancedClipboard === true) { + str += (str ? "&" : "") + "forceEnhancedClipboard=true"; + } + if (typeof options.swfObjectId === "string" && options.swfObjectId) { + str += (str ? "&" : "") + "swfObjectId=" + _encodeURIComponent(options.swfObjectId); + } + if (typeof options.jsVersion === "string" && options.jsVersion) { + str += (str ? "&" : "") + "jsVersion=" + _encodeURIComponent(options.jsVersion); + } + return str; + }; + /** + * Extract the domain (e.g. "github.com") from an origin (e.g. "https://github.com") or + * URL (e.g. "https://github.com/zeroclipboard/zeroclipboard/"). + * + * @returns the domain + * @private + */ + var _extractDomain = function(originOrUrl) { + if (originOrUrl == null || originOrUrl === "") { + return null; + } + originOrUrl = originOrUrl.replace(/^\s+|\s+$/g, ""); + if (originOrUrl === "") { + return null; + } + var protocolIndex = originOrUrl.indexOf("//"); + originOrUrl = protocolIndex === -1 ? originOrUrl : originOrUrl.slice(protocolIndex + 2); + var pathIndex = originOrUrl.indexOf("/"); + originOrUrl = pathIndex === -1 ? originOrUrl : protocolIndex === -1 || pathIndex === 0 ? null : originOrUrl.slice(0, pathIndex); + if (originOrUrl && originOrUrl.slice(-4).toLowerCase() === ".swf") { + return null; + } + return originOrUrl || null; + }; + /** + * Set `allowScriptAccess` based on `trustedDomains` and `window.location.host` vs. `swfPath`. + * + * @returns The appropriate script access level. + * @private + */ + var _determineScriptAccess = function() { + var _extractAllDomains = function(origins) { + var i, len, tmp, resultsArray = []; + if (typeof origins === "string") { + origins = [ origins ]; + } + if (!(typeof origins === "object" && origins && typeof origins.length === "number")) { + return resultsArray; + } + for (i = 0, len = origins.length; i < len; i++) { + if (_hasOwn.call(origins, i) && (tmp = _extractDomain(origins[i]))) { + if (tmp === "*") { + resultsArray.length = 0; + resultsArray.push("*"); + break; + } + if (resultsArray.indexOf(tmp) === -1) { + resultsArray.push(tmp); + } + } + } + return resultsArray; + }; + return function(currentDomain, configOptions) { + var swfDomain = _extractDomain(configOptions.swfPath); + if (swfDomain === null) { + swfDomain = currentDomain; + } + var trustedDomains = _extractAllDomains(configOptions.trustedDomains); + var len = trustedDomains.length; + if (len > 0) { + if (len === 1 && trustedDomains[0] === "*") { + return "always"; + } + if (trustedDomains.indexOf(currentDomain) !== -1) { + if (len === 1 && currentDomain === swfDomain) { + return "sameDomain"; + } + return "always"; + } + } + return "never"; + }; + }(); + /** + * Get the currently active/focused DOM element. + * + * @returns the currently active/focused element, or `null` + * @private + */ + var _safeActiveElement = function() { + try { + return _document.activeElement; + } catch (err) { + return null; + } + }; + /** + * Add a class to an element, if it doesn't already have it. + * + * @returns The element, with its new class added. + * @private + */ + var _addClass = function(element, value) { + if (!element || element.nodeType !== 1) { + return element; + } + if (element.classList) { + if (!element.classList.contains(value)) { + element.classList.add(value); + } + return element; + } + if (value && typeof value === "string") { + var classNames = (value || "").split(/\s+/); + if (element.nodeType === 1) { + if (!element.className) { + element.className = value; + } else { + var className = " " + element.className + " ", setClass = element.className; + for (var c = 0, cl = classNames.length; c < cl; c++) { + if (className.indexOf(" " + classNames[c] + " ") < 0) { + setClass += " " + classNames[c]; + } + } + element.className = setClass.replace(/^\s+|\s+$/g, ""); + } + } + } + return element; + }; + /** + * Remove a class from an element, if it has it. + * + * @returns The element, with its class removed. + * @private + */ + var _removeClass = function(element, value) { + if (!element || element.nodeType !== 1) { + return element; + } + if (element.classList) { + if (element.classList.contains(value)) { + element.classList.remove(value); + } + return element; + } + if (typeof value === "string" && value) { + var classNames = value.split(/\s+/); + if (element.nodeType === 1 && element.className) { + var className = (" " + element.className + " ").replace(/[\n\t]/g, " "); + for (var c = 0, cl = classNames.length; c < cl; c++) { + className = className.replace(" " + classNames[c] + " ", " "); + } + element.className = className.replace(/^\s+|\s+$/g, ""); + } + } + return element; + }; + /** + * Attempt to interpret the element's CSS styling. If `prop` is `"cursor"`, + * then we assume that it should be a hand ("pointer") cursor if the element + * is an anchor element ("a" tag). + * + * @returns The computed style property. + * @private + */ + var _getStyle = function(el, prop) { + var value = _getComputedStyle(el, null).getPropertyValue(prop); + if (prop === "cursor") { + if (!value || value === "auto") { + if (el.nodeName === "A") { + return "pointer"; + } + } + } + return value; + }; + /** + * Get the absolutely positioned coordinates of a DOM element. + * + * @returns Object containing the element's position, width, and height. + * @private + */ + var _getElementPosition = function(el) { + var pos = { + left: 0, + top: 0, + width: 0, + height: 0 + }; + if (el.getBoundingClientRect) { + var elRect = el.getBoundingClientRect(); + var pageXOffset = _window.pageXOffset; + var pageYOffset = _window.pageYOffset; + var leftBorderWidth = _document.documentElement.clientLeft || 0; + var topBorderWidth = _document.documentElement.clientTop || 0; + var leftBodyOffset = 0; + var topBodyOffset = 0; + if (_getStyle(_document.body, "position") === "relative") { + var bodyRect = _document.body.getBoundingClientRect(); + var htmlRect = _document.documentElement.getBoundingClientRect(); + leftBodyOffset = bodyRect.left - htmlRect.left || 0; + topBodyOffset = bodyRect.top - htmlRect.top || 0; + } + pos.left = elRect.left + pageXOffset - leftBorderWidth - leftBodyOffset; + pos.top = elRect.top + pageYOffset - topBorderWidth - topBodyOffset; + pos.width = "width" in elRect ? elRect.width : elRect.right - elRect.left; + pos.height = "height" in elRect ? elRect.height : elRect.bottom - elRect.top; + } + return pos; + }; + /** + * Determine is an element is visible somewhere within the document (page). + * + * @returns Boolean + * @private + */ + var _isElementVisible = function(el) { + if (!el) { + return false; + } + var styles = _getComputedStyle(el, null); + var hasCssHeight = _parseFloat(styles.height) > 0; + var hasCssWidth = _parseFloat(styles.width) > 0; + var hasCssTop = _parseFloat(styles.top) >= 0; + var hasCssLeft = _parseFloat(styles.left) >= 0; + var cssKnows = hasCssHeight && hasCssWidth && hasCssTop && hasCssLeft; + var rect = cssKnows ? null : _getElementPosition(el); + 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)); + return isVisible; + }; + /** + * Clear all existing timeouts and interval polling delegates. + * + * @returns `undefined` + * @private + */ + var _clearTimeoutsAndPolling = function() { + _clearTimeout(_flashCheckTimeout); + _flashCheckTimeout = 0; + _clearInterval(_swfFallbackCheckInterval); + _swfFallbackCheckInterval = 0; + }; + /** + * Reposition the Flash object to cover the currently activated element. + * + * @returns `undefined` + * @private + */ + var _reposition = function() { + var htmlBridge; + if (_currentElement && (htmlBridge = _getHtmlBridge(_flashState.bridge))) { + var pos = _getElementPosition(_currentElement); + _extend(htmlBridge.style, { + width: pos.width + "px", + height: pos.height + "px", + top: pos.top + "px", + left: pos.left + "px", + zIndex: "" + _getSafeZIndex(_globalConfig.zIndex) + }); + } + }; + /** + * Sends a signal to the Flash object to display the hand cursor if `true`. + * + * @returns `undefined` + * @private + */ + var _setHandCursor = function(enabled) { + if (_flashState.ready === true) { + if (_flashState.bridge && typeof _flashState.bridge.setHandCursor === "function") { + _flashState.bridge.setHandCursor(enabled); + } else { + _flashState.ready = false; + } + } + }; + /** + * Get a safe value for `zIndex` + * + * @returns an integer, or "auto" + * @private + */ + var _getSafeZIndex = function(val) { + if (/^(?:auto|inherit)$/.test(val)) { + return val; + } + var zIndex; + if (typeof val === "number" && !_isNaN(val)) { + zIndex = val; + } else if (typeof val === "string") { + zIndex = _getSafeZIndex(_parseInt(val, 10)); + } + return typeof zIndex === "number" ? zIndex : "auto"; + }; + /** + * Detect the Flash Player status, version, and plugin type. + * + * @see {@link https://code.google.com/p/doctype-mirror/wiki/ArticleDetectFlash#The_code} + * @see {@link http://stackoverflow.com/questions/12866060/detecting-pepper-ppapi-flash-with-javascript} + * + * @returns `undefined` + * @private + */ + var _detectFlashSupport = function(ActiveXObject) { + var plugin, ax, mimeType, hasFlash = false, isActiveX = false, isPPAPI = false, flashVersion = ""; + /** + * Derived from Apple's suggested sniffer. + * @param {String} desc e.g. "Shockwave Flash 7.0 r61" + * @returns {String} "7.0.61" + * @private + */ + function parseFlashVersion(desc) { + var matches = desc.match(/[\d]+/g); + matches.length = 3; + return matches.join("."); + } + function isPepperFlash(flashPlayerFileName) { + return !!flashPlayerFileName && (flashPlayerFileName = flashPlayerFileName.toLowerCase()) && (/^(pepflashplayer\.dll|libpepflashplayer\.so|pepperflashplayer\.plugin)$/.test(flashPlayerFileName) || flashPlayerFileName.slice(-13) === "chrome.plugin"); + } + function inspectPlugin(plugin) { + if (plugin) { + hasFlash = true; + if (plugin.version) { + flashVersion = parseFlashVersion(plugin.version); + } + if (!flashVersion && plugin.description) { + flashVersion = parseFlashVersion(plugin.description); + } + if (plugin.filename) { + isPPAPI = isPepperFlash(plugin.filename); + } + } + } + if (_navigator.plugins && _navigator.plugins.length) { + plugin = _navigator.plugins["Shockwave Flash"]; + inspectPlugin(plugin); + if (_navigator.plugins["Shockwave Flash 2.0"]) { + hasFlash = true; + flashVersion = "2.0.0.11"; + } + } else if (_navigator.mimeTypes && _navigator.mimeTypes.length) { + mimeType = _navigator.mimeTypes["application/x-shockwave-flash"]; + plugin = mimeType && mimeType.enabledPlugin; + inspectPlugin(plugin); + } else if (typeof ActiveXObject !== "undefined") { + isActiveX = true; + try { + ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); + hasFlash = true; + flashVersion = parseFlashVersion(ax.GetVariable("$version")); + } catch (e1) { + try { + ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); + hasFlash = true; + flashVersion = "6.0.21"; + } catch (e2) { + try { + ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); + hasFlash = true; + flashVersion = parseFlashVersion(ax.GetVariable("$version")); + } catch (e3) { + isActiveX = false; + } + } + } + } + _flashState.disabled = hasFlash !== true; + _flashState.outdated = flashVersion && _parseFloat(flashVersion) < _parseFloat(_minimumFlashVersion); + _flashState.version = flashVersion || "0.0.0"; + _flashState.pluginType = isPPAPI ? "pepper" : isActiveX ? "activex" : hasFlash ? "netscape" : "unknown"; + }; + /** + * Invoke the Flash detection algorithms immediately upon inclusion so we're not waiting later. + */ + _detectFlashSupport(_ActiveXObject); + /** + * A shell constructor for `ZeroClipboard` client instances. + * + * @constructor + */ + var ZeroClipboard = function() { + if (!(this instanceof ZeroClipboard)) { + return new ZeroClipboard(); + } + if (typeof ZeroClipboard._createClient === "function") { + ZeroClipboard._createClient.apply(this, _args(arguments)); + } + }; + /** + * The ZeroClipboard library's version number. + * + * @static + * @readonly + * @property {string} + */ + _defineProperty(ZeroClipboard, "version", { + value: "2.2.0-beta.3", + writable: false, + configurable: true, + enumerable: true + }); + /** + * Update or get a copy of the ZeroClipboard global configuration. + * Returns a copy of the current/updated configuration. + * + * @returns Object + * @static + */ + ZeroClipboard.config = function() { + return _config.apply(this, _args(arguments)); + }; + /** + * Diagnostic method that describes the state of the browser, Flash Player, and ZeroClipboard. + * + * @returns Object + * @static + */ + ZeroClipboard.state = function() { + return _state.apply(this, _args(arguments)); + }; + /** + * Check if Flash is unusable for any reason: disabled, outdated, deactivated, etc. + * + * @returns Boolean + * @static + */ + ZeroClipboard.isFlashUnusable = function() { + return _isFlashUnusable.apply(this, _args(arguments)); + }; + /** + * Register an event listener. + * + * @returns `ZeroClipboard` + * @static + */ + ZeroClipboard.on = function() { + return _on.apply(this, _args(arguments)); + }; + /** + * Unregister an event listener. + * If no `listener` function/object is provided, it will unregister all listeners for the provided `eventType`. + * If no `eventType` is provided, it will unregister all listeners for every event type. + * + * @returns `ZeroClipboard` + * @static + */ + ZeroClipboard.off = function() { + return _off.apply(this, _args(arguments)); + }; + /** + * Retrieve event listeners for an `eventType`. + * If no `eventType` is provided, it will retrieve all listeners for every event type. + * + * @returns array of listeners for the `eventType`; if no `eventType`, then a map/hash object of listeners for all event types; or `null` + */ + ZeroClipboard.handlers = function() { + return _listeners.apply(this, _args(arguments)); + }; + /** + * Event emission receiver from the Flash object, forwarding to any registered JavaScript event listeners. + * + * @returns For the "copy" event, returns the Flash-friendly "clipData" object; otherwise `undefined`. + * @static + */ + ZeroClipboard.emit = function() { + return _emit.apply(this, _args(arguments)); + }; + /** + * Create and embed the Flash object. + * + * @returns The Flash object + * @static + */ + ZeroClipboard.create = function() { + return _create.apply(this, _args(arguments)); + }; + /** + * Self-destruct and clean up everything, including the embedded Flash object. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.destroy = function() { + return _destroy.apply(this, _args(arguments)); + }; + /** + * Set the pending data for clipboard injection. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.setData = function() { + return _setData.apply(this, _args(arguments)); + }; + /** + * Clear the pending data for clipboard injection. + * If no `format` is provided, all pending data formats will be cleared. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.clearData = function() { + return _clearData.apply(this, _args(arguments)); + }; + /** + * Get a copy of the pending data for clipboard injection. + * If no `format` is provided, a copy of ALL pending data formats will be returned. + * + * @returns `String` or `Object` + * @static + */ + ZeroClipboard.getData = function() { + return _getData.apply(this, _args(arguments)); + }; + /** + * Sets the current HTML object that the Flash object should overlay. This will put the global + * Flash object on top of the current element; depending on the setup, this may also set the + * pending clipboard text data as well as the Flash object's wrapping element's title attribute + * based on the underlying HTML element and ZeroClipboard configuration. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.focus = ZeroClipboard.activate = function() { + return _focus.apply(this, _args(arguments)); + }; + /** + * Un-overlays the Flash object. This will put the global Flash object off-screen; depending on + * the setup, this may also unset the Flash object's wrapping element's title attribute based on + * the underlying HTML element and ZeroClipboard configuration. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.blur = ZeroClipboard.deactivate = function() { + return _blur.apply(this, _args(arguments)); + }; + /** + * Returns the currently focused/"activated" HTML element that the Flash object is wrapping. + * + * @returns `HTMLElement` or `null` + * @static + */ + ZeroClipboard.activeElement = function() { + return _activeElement.apply(this, _args(arguments)); + }; + if (typeof define === "function" && define.amd) { + define(function() { + return ZeroClipboard; + }); + } else if (typeof module === "object" && module && typeof module.exports === "object" && module.exports) { + module.exports = ZeroClipboard; + } else { + window.ZeroClipboard = ZeroClipboard; + } +})(function() { + return this || window; +}()); \ No newline at end of file diff --git a/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.Core.min.js b/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.Core.min.js new file mode 100644 index 0000000000..740fd65107 --- /dev/null +++ b/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.Core.min.js @@ -0,0 +1,10 @@ +/*! + * ZeroClipboard + * The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface. + * Copyright (c) 2009-2014 Jon Rohan, James M. Greene + * Licensed MIT + * http://zeroclipboard.org/ + * v2.2.0-beta.3 + */ +!function(a,b){"use strict";var c,d,e,f=a,g=f.document,h=f.navigator,i=f.setTimeout,j=f.clearTimeout,k=f.setInterval,l=f.clearInterval,m=f.getComputedStyle,n=f.encodeURIComponent,o=f.ActiveXObject,p=f.Error,q=f.Number.parseInt||f.parseInt,r=f.Number.parseFloat||f.parseFloat,s=f.Number.isNaN||f.isNaN,t=f.Date.now,u=f.Object.keys,v=f.Object.defineProperty,w=f.Object.prototype.hasOwnProperty,x=f.Array.prototype.slice,y=function(){var a=function(a){return a};if("function"==typeof f.wrap&&"function"==typeof f.unwrap)try{var b=g.createElement("div"),c=f.unwrap(b);1===b.nodeType&&c&&1===c.nodeType&&(a=f.unwrap)}catch(d){}return a}(),z=function(a){return x.call(a,0)},A=function(){var a,c,d,e,f,g,h=z(arguments),i=h[0]||{};for(a=1,c=h.length;c>a;a++)if(null!=(d=h[a]))for(e in d)w.call(d,e)&&(f=i[e],g=d[e],i!==g&&g!==b&&(i[e]=g));return i},B=function(a){var b,c,d,e;if("object"!=typeof a||null==a||"number"==typeof a.nodeType)b=a;else if("number"==typeof a.length)for(b=[],c=0,d=a.length;d>c;c++)w.call(a,c)&&(b[c]=B(a[c]));else{b={};for(e in a)w.call(a,e)&&(b[e]=B(a[e]))}return b},C=function(a,b){for(var c={},d=0,e=b.length;e>d;d++)b[d]in a&&(c[b[d]]=a[b[d]]);return c},D=function(a,b){var c={};for(var d in a)-1===b.indexOf(d)&&(c[d]=a[d]);return c},E=function(a){if(a)for(var b in a)w.call(a,b)&&delete a[b];return a},F=function(a,b){if(a&&1===a.nodeType&&a.ownerDocument&&b&&(1===b.nodeType&&b.ownerDocument&&b.ownerDocument===a.ownerDocument||9===b.nodeType&&!b.ownerDocument&&b===a.ownerDocument))do{if(a===b)return!0;a=a.parentNode}while(a);return!1},G=function(a){var b;return"string"==typeof a&&a&&(b=a.split("#")[0].split("?")[0],b=a.slice(0,a.lastIndexOf("/")+1)),b},H=function(a){var b,c;return"string"==typeof a&&a&&(c=a.match(/^(?:|[^:@]*@|.+\)@(?=http[s]?|file)|.+?\s+(?: at |@)(?:[^:\(]+ )*[\(]?)((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/),c&&c[1]?b=c[1]:(c=a.match(/\)@((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/),c&&c[1]&&(b=c[1]))),b},I=function(){var a,b;try{throw new p}catch(c){b=c}return b&&(a=b.sourceURL||b.fileName||H(b.stack)),a},J=function(){var a,c,d;if(g.currentScript&&(a=g.currentScript.src))return a;if(c=g.getElementsByTagName("script"),1===c.length)return c[0].src||b;if("readyState"in c[0])for(d=c.length;d--;)if("interactive"===c[d].readyState&&(a=c[d].src))return a;return"loading"===g.readyState&&(a=c[c.length-1].src)?a:(a=I())?a:b},K=function(){var a,c,d,e=g.getElementsByTagName("script");for(a=e.length;a--;){if(!(d=e[a].src)){c=null;break}if(d=G(d),null==c)c=d;else if(c!==d){c=null;break}}return c||b},L=function(){var a=G(J())||K()||"";return a+"ZeroClipboard.swf"},M={bridge:null,version:"0.0.0",pluginType:"unknown",disabled:null,outdated:null,unavailable:null,degraded:null,deactivated:null,overdue:null,ready:null},N="11.0.0",O={},P={},Q=null,R=0,S=0,T={ready:"Flash communication is established",error:{"flash-disabled":"Flash is disabled or not installed","flash-outdated":"Flash is too outdated to support ZeroClipboard","flash-unavailable":"Flash is unable to communicate bidirectionally with JavaScript","flash-degraded":"Flash is unable to preserve data fidelity when communicating with JavaScript","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.","flash-overdue":"Flash communication was established but NOT within the acceptable time limit","version-mismatch":"ZeroClipboard JS version number does not match ZeroClipboard SWF version number","clipboard-error":"At least one error was thrown while ZeroClipboard was attempting to inject your data into the clipboard","config-mismatch":"ZeroClipboard configuration does not match Flash's reality","swf-not-found":"The ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity"}},U={swfPath:L(),trustedDomains:a.location.host?[a.location.host]:[],cacheBust:!0,forceEnhancedClipboard:!1,flashLoadTimeout:3e4,autoActivate:!0,bubbleEvents:!0,containerId:"global-zeroclipboard-html-bridge",containerClass:"global-zeroclipboard-container",swfObjectId:"global-zeroclipboard-flash-bridge",hoverClass:"zeroclipboard-is-hover",activeClass:"zeroclipboard-is-active",forceHandCursor:!1,title:null,zIndex:999999999},V=function(a){if("object"==typeof a&&null!==a)for(var b in a)if(w.call(a,b))if(/^(?:forceHandCursor|title|zIndex|bubbleEvents)$/.test(b))U[b]=a[b];else if(null==M.bridge)if("containerId"===b||"swfObjectId"===b){if(!ib(a[b]))throw new Error("The specified `"+b+"` value is not valid as an HTML4 Element ID");U[b]=a[b]}else U[b]=a[b];{if("string"!=typeof a||!a)return B(U);if(w.call(U,a))return U[a]}},W=function(){return{browser:C(h,["userAgent","platform","appName"]),flash:D(M,["bridge"]),zeroclipboard:{version:Ob.version,config:Ob.config()}}},X=function(){return!!(M.disabled||M.outdated||M.unavailable||M.degraded||M.deactivated)},Y=function(a,d){var e,f,g,h={};if("string"==typeof a&&a)g=a.toLowerCase().split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof d)for(e in a)w.call(a,e)&&"string"==typeof e&&e&&"function"==typeof a[e]&&Ob.on(e,a[e]);if(g&&g.length){for(e=0,f=g.length;f>e;e++)a=g[e].replace(/^on/,""),h[a]=!0,O[a]||(O[a]=[]),O[a].push(d);if(h.ready&&M.ready&&Ob.emit({type:"ready"}),h.error){var i=["disabled","outdated","unavailable","degraded","deactivated","overdue"];for(e=0,f=i.length;f>e;e++)if(M[i[e]]===!0){Ob.emit({type:"error",name:"flash-"+i[e]});break}c!==b&&Ob.version!==c&&Ob.emit({type:"error",name:"version-mismatch",jsVersion:Ob.version,swfVersion:c})}}return Ob},Z=function(a,b){var c,d,e,f,g;if(0===arguments.length)f=u(O);else if("string"==typeof a&&a)f=a.split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof b)for(c in a)w.call(a,c)&&"string"==typeof c&&c&&"function"==typeof a[c]&&Ob.off(c,a[c]);if(f&&f.length)for(c=0,d=f.length;d>c;c++)if(a=f[c].toLowerCase().replace(/^on/,""),g=O[a],g&&g.length)if(b)for(e=g.indexOf(b);-1!==e;)g.splice(e,1),e=g.indexOf(b,e);else g.length=0;return Ob},$=function(a){var b;return b="string"==typeof a&&a?B(O[a])||null:B(O)},_=function(a){var b,c,d;return a=jb(a),a&&!pb(a)?"ready"===a.type&&M.overdue===!0?Ob.emit({type:"error",name:"flash-overdue"}):(b=A({},a),ob.call(this,b),"copy"===a.type&&(d=xb(P),c=d.data,Q=d.formatMap),c):void 0},ab=function(){if("boolean"!=typeof M.ready&&(M.ready=!1),!Ob.isFlashUnusable()&&null===M.bridge){var a=U.flashLoadTimeout;"number"==typeof a&&a>=0&&(R=i(function(){"boolean"!=typeof M.deactivated&&(M.deactivated=!0),M.deactivated===!0&&Ob.emit({type:"error",name:"flash-deactivated"})},a)),M.overdue=!1,vb()}},bb=function(){Ob.clearData(),Ob.blur(),Ob.emit("destroy"),wb(),Ob.off()},cb=function(a,b){var c;if("object"==typeof a&&a&&"undefined"==typeof b)c=a,Ob.clearData();else{if("string"!=typeof a||!a)return;c={},c[a]=b}for(var d in c)"string"==typeof d&&d&&w.call(c,d)&&"string"==typeof c[d]&&c[d]&&(P[d]=c[d])},db=function(a){"undefined"==typeof a?(E(P),Q=null):"string"==typeof a&&w.call(P,a)&&delete P[a]},eb=function(a){return"undefined"==typeof a?B(P):"string"==typeof a&&w.call(P,a)?P[a]:void 0},fb=function(a){if(a&&1===a.nodeType){d&&(Fb(d,U.activeClass),d!==a&&Fb(d,U.hoverClass)),d=a,Eb(a,U.hoverClass);var b=a.getAttribute("title")||U.title;if("string"==typeof b&&b){var c=ub(M.bridge);c&&c.setAttribute("title",b)}var e=U.forceHandCursor===!0||"pointer"===Gb(a,"cursor");Lb(e),Kb()}},gb=function(){var a=ub(M.bridge);a&&(a.removeAttribute("title"),a.style.left="0px",a.style.top="-9999px",a.style.width="1px",a.style.top="1px"),d&&(Fb(d,U.hoverClass),Fb(d,U.activeClass),d=null)},hb=function(){return d||null},ib=function(a){return"string"==typeof a&&a&&/^[A-Za-z][A-Za-z0-9_:\-\.]*$/.test(a)},jb=function(a){var b;if("string"==typeof a&&a?(b=a,a={}):"object"==typeof a&&a&&"string"==typeof a.type&&a.type&&(b=a.type),b){b=b.toLowerCase(),!a.target&&(/^(copy|aftercopy|_click)$/.test(b)||"error"===b&&"clipboard-error"===a.name)&&(a.target=e),A(a,{type:b,target:a.target||d||null,relatedTarget:a.relatedTarget||null,currentTarget:M&&M.bridge||null,timeStamp:a.timeStamp||t()||null});var c=T[a.type];return"error"===a.type&&a.name&&c&&(c=c[a.name]),c&&(a.message=c),"ready"===a.type&&A(a,{target:null,version:M.version}),"error"===a.type&&(/^flash-(disabled|outdated|unavailable|degraded|deactivated|overdue)$/.test(a.name)&&A(a,{target:null,minimumVersion:N}),/^flash-(outdated|unavailable|degraded|deactivated|overdue)$/.test(a.name)&&A(a,{version:M.version})),"copy"===a.type&&(a.clipboardData={setData:Ob.setData,clearData:Ob.clearData}),"aftercopy"===a.type&&(a=yb(a,Q)),a.target&&!a.relatedTarget&&(a.relatedTarget=kb(a.target)),lb(a)}},kb=function(a){var b=a&&a.getAttribute&&a.getAttribute("data-clipboard-target");return b?g.getElementById(b):null},lb=function(a){if(a&&/^_(?:click|mouse(?:over|out|down|up|move))$/.test(a.type)){var c=a.target,d="_mouseover"===a.type&&a.relatedTarget?a.relatedTarget:b,e="_mouseout"===a.type&&a.relatedTarget?a.relatedTarget:b,h=Hb(c),i=f.screenLeft||f.screenX||0,j=f.screenTop||f.screenY||0,k=g.body.scrollLeft+g.documentElement.scrollLeft,l=g.body.scrollTop+g.documentElement.scrollTop,m=h.left+("number"==typeof a._stageX?a._stageX:0),n=h.top+("number"==typeof a._stageY?a._stageY:0),o=m-k,p=n-l,q=i+o,r=j+p,s="number"==typeof a.movementX?a.movementX:0,t="number"==typeof a.movementY?a.movementY:0;delete a._stageX,delete a._stageY,A(a,{srcElement:c,fromElement:d,toElement:e,screenX:q,screenY:r,pageX:m,pageY:n,clientX:o,clientY:p,x:o,y:p,movementX:s,movementY:t,offsetX:0,offsetY:0,layerX:0,layerY:0})}return a},mb=function(a){var b=a&&"string"==typeof a.type&&a.type||"";return!/^(?:(?:before)?copy|destroy)$/.test(b)},nb=function(a,b,c,d){d?i(function(){a.apply(b,c)},0):a.apply(b,c)},ob=function(a){if("object"==typeof a&&a&&a.type){var b=mb(a),c=O["*"]||[],d=O[a.type]||[],e=c.concat(d);if(e&&e.length){var g,h,i,j,k,l=this;for(g=0,h=e.length;h>g;g++)i=e[g],j=l,"string"==typeof i&&"function"==typeof f[i]&&(i=f[i]),"object"==typeof i&&i&&"function"==typeof i.handleEvent&&(j=i,i=i.handleEvent),"function"==typeof i&&(k=A({},a),nb(i,j,[k],b))}return this}},pb=function(a){var b=a.target||d||null,f="swf"===a._source;delete a._source;var g=["flash-disabled","flash-outdated","flash-unavailable","flash-degraded","flash-deactivated","flash-overdue"];switch(a.type){case"error":-1!==g.indexOf(a.name)?A(M,{disabled:"flash-disabled"===a.name,outdated:"flash-outdated"===a.name,unavailable:"flash-unavailable"===a.name,degraded:"flash-degraded"===a.name,deactivated:"flash-deactivated"===a.name,overdue:"flash-overdue"===a.name,ready:!1}):"version-mismatch"===a.name&&(c=a.swfVersion,A(M,{disabled:!1,outdated:!1,unavailable:!1,degraded:!1,deactivated:!1,overdue:!1,ready:!1})),Jb();break;case"ready":c=a.swfVersion;var h=M.deactivated===!0;A(M,{disabled:!1,outdated:!1,unavailable:!1,degraded:!1,deactivated:!1,overdue:h,ready:!h}),Jb();break;case"beforecopy":e=b;break;case"copy":var i,j,k=a.relatedTarget;!P["text/html"]&&!P["text/plain"]&&k&&(j=k.value||k.outerHTML||k.innerHTML)&&(i=k.value||k.textContent||k.innerText)?(a.clipboardData.clearData(),a.clipboardData.setData("text/plain",i),j!==i&&a.clipboardData.setData("text/html",j)):!P["text/plain"]&&a.target&&(i=a.target.getAttribute("data-clipboard-text"))&&(a.clipboardData.clearData(),a.clipboardData.setData("text/plain",i));break;case"aftercopy":qb(a),Ob.clearData(),b&&b!==Db()&&b.focus&&b.focus();break;case"_mouseover":Ob.focus(b),U.bubbleEvents===!0&&f&&(b&&b!==a.relatedTarget&&!F(a.relatedTarget,b)&&rb(A({},a,{type:"mouseenter",bubbles:!1,cancelable:!1})),rb(A({},a,{type:"mouseover"})));break;case"_mouseout":Ob.blur(),U.bubbleEvents===!0&&f&&(b&&b!==a.relatedTarget&&!F(a.relatedTarget,b)&&rb(A({},a,{type:"mouseleave",bubbles:!1,cancelable:!1})),rb(A({},a,{type:"mouseout"})));break;case"_mousedown":Eb(b,U.activeClass),U.bubbleEvents===!0&&f&&rb(A({},a,{type:a.type.slice(1)}));break;case"_mouseup":Fb(b,U.activeClass),U.bubbleEvents===!0&&f&&rb(A({},a,{type:a.type.slice(1)}));break;case"_click":e=null,U.bubbleEvents===!0&&f&&rb(A({},a,{type:a.type.slice(1)}));break;case"_mousemove":U.bubbleEvents===!0&&f&&rb(A({},a,{type:a.type.slice(1)}))}return/^_(?:click|mouse(?:over|out|down|up|move))$/.test(a.type)?!0:void 0},qb=function(a){if(a.errors&&a.errors.length>0){var b=B(a);A(b,{type:"error",name:"clipboard-error"}),delete b.success,i(function(){Ob.emit(b)},0)}},rb=function(a){if(a&&"string"==typeof a.type&&a){var b,c=a.target||null,d=c&&c.ownerDocument||g,e={view:d.defaultView||f,canBubble:!0,cancelable:!0,detail:"click"===a.type?1:0,button:"number"==typeof a.which?a.which-1:"number"==typeof a.button?a.button:d.createEvent?0:1},h=A(e,a);c&&d.createEvent&&c.dispatchEvent&&(h=[h.type,h.canBubble,h.cancelable,h.view,h.detail,h.screenX,h.screenY,h.clientX,h.clientY,h.ctrlKey,h.altKey,h.shiftKey,h.metaKey,h.button,h.relatedTarget],b=d.createEvent("MouseEvents"),b.initMouseEvent&&(b.initMouseEvent.apply(b,h),b._source="js",c.dispatchEvent(b)))}},sb=function(){var a=U.flashLoadTimeout;if("number"==typeof a&&a>=0){var b=Math.min(1e3,a/10),c=U.swfObjectId+"_fallbackContent";S=k(function(){var a=g.getElementById(c);Ib(a)&&(Jb(),M.deactivated=null,Ob.emit({type:"error",name:"swf-not-found"}))},b)}},tb=function(){var a=g.createElement("div");return a.id=U.containerId,a.className=U.containerClass,a.style.position="absolute",a.style.left="0px",a.style.top="-9999px",a.style.width="1px",a.style.height="1px",a.style.zIndex=""+Mb(U.zIndex),a},ub=function(a){for(var b=a&&a.parentNode;b&&"OBJECT"===b.nodeName&&b.parentNode;)b=b.parentNode;return b||null},vb=function(){var a,b=M.bridge,c=ub(b);if(!b){var d=Cb(f.location.host,U),e="never"===d?"none":"all",h=Ab(A({jsVersion:Ob.version},U)),i=U.swfPath+zb(U.swfPath,U);c=tb();var j=g.createElement("div");c.appendChild(j),g.body.appendChild(c);var k=g.createElement("div"),l="activex"===M.pluginType;k.innerHTML='"+(l?'':"")+'
 
',b=k.firstChild,k=null,y(b).ZeroClipboard=Ob,c.replaceChild(b,j),sb()}return b||(b=g[U.swfObjectId],b&&(a=b.length)&&(b=b[a-1]),!b&&c&&(b=c.firstChild)),M.bridge=b||null,b},wb=function(){var a=M.bridge;if(a){var d=ub(a);d&&("activex"===M.pluginType&&"readyState"in a?(a.style.display="none",function e(){if(4===a.readyState){for(var b in a)"function"==typeof a[b]&&(a[b]=null);a.parentNode&&a.parentNode.removeChild(a),d.parentNode&&d.parentNode.removeChild(d)}else i(e,10)}()):(a.parentNode&&a.parentNode.removeChild(a),d.parentNode&&d.parentNode.removeChild(d))),Jb(),M.ready=null,M.bridge=null,M.deactivated=null,c=b}},xb=function(a){var b={},c={};if("object"==typeof a&&a){for(var d in a)if(d&&w.call(a,d)&&"string"==typeof a[d]&&a[d])switch(d.toLowerCase()){case"text/plain":case"text":case"air:text":case"flash:text":b.text=a[d],c.text=d;break;case"text/html":case"html":case"air:html":case"flash:html":b.html=a[d],c.html=d;break;case"application/rtf":case"text/rtf":case"rtf":case"richtext":case"air:rtf":case"flash:rtf":b.rtf=a[d],c.rtf=d}return{data:b,formatMap:c}}},yb=function(a,b){if("object"!=typeof a||!a||"object"!=typeof b||!b)return a;var c={};for(var d in a)if(w.call(a,d))if("errors"===d){c[d]=a[d]?a[d].slice():[];for(var e=0,f=c[d].length;f>e;e++)c[d][e].format=b[c[d][e].format]}else if("success"!==d&&"data"!==d)c[d]=a[d];else{c[d]={};var g=a[d];for(var h in g)h&&w.call(g,h)&&w.call(b,h)&&(c[d][b[h]]=g[h])}return c},zb=function(a,b){var c=null==b||b&&b.cacheBust===!0;return c?(-1===a.indexOf("?")?"?":"&")+"noCache="+t():""},Ab=function(a){var b,c,d,e,g="",h=[];if(a.trustedDomains&&("string"==typeof a.trustedDomains?e=[a.trustedDomains]:"object"==typeof a.trustedDomains&&"length"in a.trustedDomains&&(e=a.trustedDomains)),e&&e.length)for(b=0,c=e.length;c>b;b++)if(w.call(e,b)&&e[b]&&"string"==typeof e[b]){if(d=Bb(e[b]),!d)continue;if("*"===d){h.length=0,h.push(d);break}h.push.apply(h,[d,"//"+d,f.location.protocol+"//"+d])}return h.length&&(g+="trustedOrigins="+n(h.join(","))),a.forceEnhancedClipboard===!0&&(g+=(g?"&":"")+"forceEnhancedClipboard=true"),"string"==typeof a.swfObjectId&&a.swfObjectId&&(g+=(g?"&":"")+"swfObjectId="+n(a.swfObjectId)),"string"==typeof a.jsVersion&&a.jsVersion&&(g+=(g?"&":"")+"jsVersion="+n(a.jsVersion)),g},Bb=function(a){if(null==a||""===a)return null;if(a=a.replace(/^\s+|\s+$/g,""),""===a)return null;var b=a.indexOf("//");a=-1===b?a:a.slice(b+2);var c=a.indexOf("/");return a=-1===c?a:-1===b||0===c?null:a.slice(0,c),a&&".swf"===a.slice(-4).toLowerCase()?null:a||null},Cb=function(){var a=function(a){var b,c,d,e=[];if("string"==typeof a&&(a=[a]),"object"!=typeof a||!a||"number"!=typeof a.length)return e;for(b=0,c=a.length;c>b;b++)if(w.call(a,b)&&(d=Bb(a[b]))){if("*"===d){e.length=0,e.push("*");break}-1===e.indexOf(d)&&e.push(d)}return e};return function(b,c){var d=Bb(c.swfPath);null===d&&(d=b);var e=a(c.trustedDomains),f=e.length;if(f>0){if(1===f&&"*"===e[0])return"always";if(-1!==e.indexOf(b))return 1===f&&b===d?"sameDomain":"always"}return"never"}}(),Db=function(){try{return g.activeElement}catch(a){return null}},Eb=function(a,b){if(!a||1!==a.nodeType)return a;if(a.classList)return a.classList.contains(b)||a.classList.add(b),a;if(b&&"string"==typeof b){var c=(b||"").split(/\s+/);if(1===a.nodeType)if(a.className){for(var d=" "+a.className+" ",e=a.className,f=0,g=c.length;g>f;f++)d.indexOf(" "+c[f]+" ")<0&&(e+=" "+c[f]);a.className=e.replace(/^\s+|\s+$/g,"")}else a.className=b}return a},Fb=function(a,b){if(!a||1!==a.nodeType)return a;if(a.classList)return a.classList.contains(b)&&a.classList.remove(b),a;if("string"==typeof b&&b){var c=b.split(/\s+/);if(1===a.nodeType&&a.className){for(var d=(" "+a.className+" ").replace(/[\n\t]/g," "),e=0,f=c.length;f>e;e++)d=d.replace(" "+c[e]+" "," ");a.className=d.replace(/^\s+|\s+$/g,"")}}return a},Gb=function(a,b){var c=m(a,null).getPropertyValue(b);return"cursor"!==b||c&&"auto"!==c||"A"!==a.nodeName?c:"pointer"},Hb=function(a){var b={left:0,top:0,width:0,height:0};if(a.getBoundingClientRect){var c=a.getBoundingClientRect(),d=f.pageXOffset,e=f.pageYOffset,h=g.documentElement.clientLeft||0,i=g.documentElement.clientTop||0,j=0,k=0;if("relative"===Gb(g.body,"position")){var l=g.body.getBoundingClientRect(),m=g.documentElement.getBoundingClientRect();j=l.left-m.left||0,k=l.top-m.top||0}b.left=c.left+d-h-j,b.top=c.top+e-i-k,b.width="width"in c?c.width:c.right-c.left,b.height="height"in c?c.height:c.bottom-c.top}return b},Ib=function(a){if(!a)return!1;var b=m(a,null),c=r(b.height)>0,d=r(b.width)>0,e=r(b.top)>=0,f=r(b.left)>=0,g=c&&d&&e&&f,h=g?null:Hb(a),i="none"!==b.display&&"collapse"!==b.visibility&&(g||!!h&&(c||h.height>0)&&(d||h.width>0)&&(e||h.top>=0)&&(f||h.left>=0));return i},Jb=function(){j(R),R=0,l(S),S=0},Kb=function(){var a;if(d&&(a=ub(M.bridge))){var b=Hb(d);A(a.style,{width:b.width+"px",height:b.height+"px",top:b.top+"px",left:b.left+"px",zIndex:""+Mb(U.zIndex)})}},Lb=function(a){M.ready===!0&&(M.bridge&&"function"==typeof M.bridge.setHandCursor?M.bridge.setHandCursor(a):M.ready=!1)},Mb=function(a){if(/^(?:auto|inherit)$/.test(a))return a;var b;return"number"!=typeof a||s(a)?"string"==typeof a&&(b=Mb(q(a,10))):b=a,"number"==typeof b?b:"auto"},Nb=function(a){function b(a){var b=a.match(/[\d]+/g);return b.length=3,b.join(".")}function c(a){return!!a&&(a=a.toLowerCase())&&(/^(pepflashplayer\.dll|libpepflashplayer\.so|pepperflashplayer\.plugin)$/.test(a)||"chrome.plugin"===a.slice(-13))}function d(a){a&&(i=!0,a.version&&(l=b(a.version)),!l&&a.description&&(l=b(a.description)),a.filename&&(k=c(a.filename)))}var e,f,g,i=!1,j=!1,k=!1,l="";if(h.plugins&&h.plugins.length)e=h.plugins["Shockwave Flash"],d(e),h.plugins["Shockwave Flash 2.0"]&&(i=!0,l="2.0.0.11");else if(h.mimeTypes&&h.mimeTypes.length)g=h.mimeTypes["application/x-shockwave-flash"],e=g&&g.enabledPlugin,d(e);else if("undefined"!=typeof a){j=!0;try{f=new a("ShockwaveFlash.ShockwaveFlash.7"),i=!0,l=b(f.GetVariable("$version"))}catch(m){try{f=new a("ShockwaveFlash.ShockwaveFlash.6"),i=!0,l="6.0.21"}catch(n){try{f=new a("ShockwaveFlash.ShockwaveFlash"),i=!0,l=b(f.GetVariable("$version"))}catch(o){j=!1}}}}M.disabled=i!==!0,M.outdated=l&&r(l)= 0) {\n _flashCheckTimeout = _setTimeout(function() {\n if (typeof _flashState.deactivated !== \"boolean\") {\n _flashState.deactivated = true;\n }\n if (_flashState.deactivated === true) {\n ZeroClipboard.emit({\n type: \"error\",\n name: \"flash-deactivated\"\n });\n }\n }, maxWait);\n }\n _flashState.overdue = false;\n _embedSwf();\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.destroy`.\n * @private\n */\n var _destroy = function() {\n ZeroClipboard.clearData();\n ZeroClipboard.blur();\n ZeroClipboard.emit(\"destroy\");\n _unembedSwf();\n ZeroClipboard.off();\n };\n /**\n * The underlying implementation of `ZeroClipboard.setData`.\n * @private\n */\n var _setData = function(format, data) {\n var dataObj;\n if (typeof format === \"object\" && format && typeof data === \"undefined\") {\n dataObj = format;\n ZeroClipboard.clearData();\n } else if (typeof format === \"string\" && format) {\n dataObj = {};\n dataObj[format] = data;\n } else {\n return;\n }\n for (var dataFormat in dataObj) {\n if (typeof dataFormat === \"string\" && dataFormat && _hasOwn.call(dataObj, dataFormat) && typeof dataObj[dataFormat] === \"string\" && dataObj[dataFormat]) {\n _clipData[dataFormat] = dataObj[dataFormat];\n }\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.clearData`.\n * @private\n */\n var _clearData = function(format) {\n if (typeof format === \"undefined\") {\n _deleteOwnProperties(_clipData);\n _clipDataFormatMap = null;\n } else if (typeof format === \"string\" && _hasOwn.call(_clipData, format)) {\n delete _clipData[format];\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.getData`.\n * @private\n */\n var _getData = function(format) {\n if (typeof format === \"undefined\") {\n return _deepCopy(_clipData);\n } else if (typeof format === \"string\" && _hasOwn.call(_clipData, format)) {\n return _clipData[format];\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.focus`/`ZeroClipboard.activate`.\n * @private\n */\n var _focus = function(element) {\n if (!(element && element.nodeType === 1)) {\n return;\n }\n if (_currentElement) {\n _removeClass(_currentElement, _globalConfig.activeClass);\n if (_currentElement !== element) {\n _removeClass(_currentElement, _globalConfig.hoverClass);\n }\n }\n _currentElement = element;\n _addClass(element, _globalConfig.hoverClass);\n var newTitle = element.getAttribute(\"title\") || _globalConfig.title;\n if (typeof newTitle === \"string\" && newTitle) {\n var htmlBridge = _getHtmlBridge(_flashState.bridge);\n if (htmlBridge) {\n htmlBridge.setAttribute(\"title\", newTitle);\n }\n }\n var useHandCursor = _globalConfig.forceHandCursor === true || _getStyle(element, \"cursor\") === \"pointer\";\n _setHandCursor(useHandCursor);\n _reposition();\n };\n /**\n * The underlying implementation of `ZeroClipboard.blur`/`ZeroClipboard.deactivate`.\n * @private\n */\n var _blur = function() {\n var htmlBridge = _getHtmlBridge(_flashState.bridge);\n if (htmlBridge) {\n htmlBridge.removeAttribute(\"title\");\n htmlBridge.style.left = \"0px\";\n htmlBridge.style.top = \"-9999px\";\n htmlBridge.style.width = \"1px\";\n htmlBridge.style.top = \"1px\";\n }\n if (_currentElement) {\n _removeClass(_currentElement, _globalConfig.hoverClass);\n _removeClass(_currentElement, _globalConfig.activeClass);\n _currentElement = null;\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.activeElement`.\n * @private\n */\n var _activeElement = function() {\n return _currentElement || null;\n };\n /**\n * Check if a value is a valid HTML4 `ID` or `Name` token.\n * @private\n */\n var _isValidHtml4Id = function(id) {\n return typeof id === \"string\" && id && /^[A-Za-z][A-Za-z0-9_:\\-\\.]*$/.test(id);\n };\n /**\n * Create or update an `event` object, based on the `eventType`.\n * @private\n */\n var _createEvent = function(event) {\n var eventType;\n if (typeof event === \"string\" && event) {\n eventType = event;\n event = {};\n } else if (typeof event === \"object\" && event && typeof event.type === \"string\" && event.type) {\n eventType = event.type;\n }\n if (!eventType) {\n return;\n }\n eventType = eventType.toLowerCase();\n if (!event.target && (/^(copy|aftercopy|_click)$/.test(eventType) || eventType === \"error\" && event.name === \"clipboard-error\")) {\n event.target = _copyTarget;\n }\n _extend(event, {\n type: eventType,\n target: event.target || _currentElement || null,\n relatedTarget: event.relatedTarget || null,\n currentTarget: _flashState && _flashState.bridge || null,\n timeStamp: event.timeStamp || _now() || null\n });\n var msg = _eventMessages[event.type];\n if (event.type === \"error\" && event.name && msg) {\n msg = msg[event.name];\n }\n if (msg) {\n event.message = msg;\n }\n if (event.type === \"ready\") {\n _extend(event, {\n target: null,\n version: _flashState.version\n });\n }\n if (event.type === \"error\") {\n if (/^flash-(disabled|outdated|unavailable|degraded|deactivated|overdue)$/.test(event.name)) {\n _extend(event, {\n target: null,\n minimumVersion: _minimumFlashVersion\n });\n }\n if (/^flash-(outdated|unavailable|degraded|deactivated|overdue)$/.test(event.name)) {\n _extend(event, {\n version: _flashState.version\n });\n }\n }\n if (event.type === \"copy\") {\n event.clipboardData = {\n setData: ZeroClipboard.setData,\n clearData: ZeroClipboard.clearData\n };\n }\n if (event.type === \"aftercopy\") {\n event = _mapClipResultsFromFlash(event, _clipDataFormatMap);\n }\n if (event.target && !event.relatedTarget) {\n event.relatedTarget = _getRelatedTarget(event.target);\n }\n return _addMouseData(event);\n };\n /**\n * Get a relatedTarget from the target's `data-clipboard-target` attribute\n * @private\n */\n var _getRelatedTarget = function(targetEl) {\n var relatedTargetId = targetEl && targetEl.getAttribute && targetEl.getAttribute(\"data-clipboard-target\");\n return relatedTargetId ? _document.getElementById(relatedTargetId) : null;\n };\n /**\n * Add element and position data to `MouseEvent` instances\n * @private\n */\n var _addMouseData = function(event) {\n if (event && /^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) {\n var srcElement = event.target;\n var fromElement = event.type === \"_mouseover\" && event.relatedTarget ? event.relatedTarget : undefined;\n var toElement = event.type === \"_mouseout\" && event.relatedTarget ? event.relatedTarget : undefined;\n var pos = _getElementPosition(srcElement);\n var screenLeft = _window.screenLeft || _window.screenX || 0;\n var screenTop = _window.screenTop || _window.screenY || 0;\n var scrollLeft = _document.body.scrollLeft + _document.documentElement.scrollLeft;\n var scrollTop = _document.body.scrollTop + _document.documentElement.scrollTop;\n var pageX = pos.left + (typeof event._stageX === \"number\" ? event._stageX : 0);\n var pageY = pos.top + (typeof event._stageY === \"number\" ? event._stageY : 0);\n var clientX = pageX - scrollLeft;\n var clientY = pageY - scrollTop;\n var screenX = screenLeft + clientX;\n var screenY = screenTop + clientY;\n var moveX = typeof event.movementX === \"number\" ? event.movementX : 0;\n var moveY = typeof event.movementY === \"number\" ? event.movementY : 0;\n delete event._stageX;\n delete event._stageY;\n _extend(event, {\n srcElement: srcElement,\n fromElement: fromElement,\n toElement: toElement,\n screenX: screenX,\n screenY: screenY,\n pageX: pageX,\n pageY: pageY,\n clientX: clientX,\n clientY: clientY,\n x: clientX,\n y: clientY,\n movementX: moveX,\n movementY: moveY,\n offsetX: 0,\n offsetY: 0,\n layerX: 0,\n layerY: 0\n });\n }\n return event;\n };\n /**\n * Determine if an event's registered handlers should be execute synchronously or asynchronously.\n *\n * @returns {boolean}\n * @private\n */\n var _shouldPerformAsync = function(event) {\n var eventType = event && typeof event.type === \"string\" && event.type || \"\";\n return !/^(?:(?:before)?copy|destroy)$/.test(eventType);\n };\n /**\n * Control if a callback should be executed asynchronously or not.\n *\n * @returns `undefined`\n * @private\n */\n var _dispatchCallback = function(func, context, args, async) {\n if (async) {\n _setTimeout(function() {\n func.apply(context, args);\n }, 0);\n } else {\n func.apply(context, args);\n }\n };\n /**\n * Handle the actual dispatching of events to client instances.\n *\n * @returns `undefined`\n * @private\n */\n var _dispatchCallbacks = function(event) {\n if (!(typeof event === \"object\" && event && event.type)) {\n return;\n }\n var async = _shouldPerformAsync(event);\n var wildcardTypeHandlers = _handlers[\"*\"] || [];\n var specificTypeHandlers = _handlers[event.type] || [];\n var handlers = wildcardTypeHandlers.concat(specificTypeHandlers);\n if (handlers && handlers.length) {\n var i, len, func, context, eventCopy, originalContext = this;\n for (i = 0, len = handlers.length; i < len; i++) {\n func = handlers[i];\n context = originalContext;\n if (typeof func === \"string\" && typeof _window[func] === \"function\") {\n func = _window[func];\n }\n if (typeof func === \"object\" && func && typeof func.handleEvent === \"function\") {\n context = func;\n func = func.handleEvent;\n }\n if (typeof func === \"function\") {\n eventCopy = _extend({}, event);\n _dispatchCallback(func, context, [ eventCopy ], async);\n }\n }\n }\n return this;\n };\n /**\n * Preprocess any special behaviors, reactions, or state changes after receiving this event.\n * Executes only once per event emitted, NOT once per client.\n * @private\n */\n var _preprocessEvent = function(event) {\n var element = event.target || _currentElement || null;\n var sourceIsSwf = event._source === \"swf\";\n delete event._source;\n var flashErrorNames = [ \"flash-disabled\", \"flash-outdated\", \"flash-unavailable\", \"flash-degraded\", \"flash-deactivated\", \"flash-overdue\" ];\n switch (event.type) {\n case \"error\":\n if (flashErrorNames.indexOf(event.name) !== -1) {\n _extend(_flashState, {\n disabled: event.name === \"flash-disabled\",\n outdated: event.name === \"flash-outdated\",\n unavailable: event.name === \"flash-unavailable\",\n degraded: event.name === \"flash-degraded\",\n deactivated: event.name === \"flash-deactivated\",\n overdue: event.name === \"flash-overdue\",\n ready: false\n });\n } else if (event.name === \"version-mismatch\") {\n _zcSwfVersion = event.swfVersion;\n _extend(_flashState, {\n disabled: false,\n outdated: false,\n unavailable: false,\n degraded: false,\n deactivated: false,\n overdue: false,\n ready: false\n });\n }\n _clearTimeoutsAndPolling();\n break;\n\n case \"ready\":\n _zcSwfVersion = event.swfVersion;\n var wasDeactivated = _flashState.deactivated === true;\n _extend(_flashState, {\n disabled: false,\n outdated: false,\n unavailable: false,\n degraded: false,\n deactivated: false,\n overdue: wasDeactivated,\n ready: !wasDeactivated\n });\n _clearTimeoutsAndPolling();\n break;\n\n case \"beforecopy\":\n _copyTarget = element;\n break;\n\n case \"copy\":\n var textContent, htmlContent, targetEl = event.relatedTarget;\n if (!(_clipData[\"text/html\"] || _clipData[\"text/plain\"]) && targetEl && (htmlContent = targetEl.value || targetEl.outerHTML || targetEl.innerHTML) && (textContent = targetEl.value || targetEl.textContent || targetEl.innerText)) {\n event.clipboardData.clearData();\n event.clipboardData.setData(\"text/plain\", textContent);\n if (htmlContent !== textContent) {\n event.clipboardData.setData(\"text/html\", htmlContent);\n }\n } else if (!_clipData[\"text/plain\"] && event.target && (textContent = event.target.getAttribute(\"data-clipboard-text\"))) {\n event.clipboardData.clearData();\n event.clipboardData.setData(\"text/plain\", textContent);\n }\n break;\n\n case \"aftercopy\":\n _queueEmitClipboardErrors(event);\n ZeroClipboard.clearData();\n if (element && element !== _safeActiveElement() && element.focus) {\n element.focus();\n }\n break;\n\n case \"_mouseover\":\n ZeroClipboard.focus(element);\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) {\n _fireMouseEvent(_extend({}, event, {\n type: \"mouseenter\",\n bubbles: false,\n cancelable: false\n }));\n }\n _fireMouseEvent(_extend({}, event, {\n type: \"mouseover\"\n }));\n }\n break;\n\n case \"_mouseout\":\n ZeroClipboard.blur();\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) {\n _fireMouseEvent(_extend({}, event, {\n type: \"mouseleave\",\n bubbles: false,\n cancelable: false\n }));\n }\n _fireMouseEvent(_extend({}, event, {\n type: \"mouseout\"\n }));\n }\n break;\n\n case \"_mousedown\":\n _addClass(element, _globalConfig.activeClass);\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n _fireMouseEvent(_extend({}, event, {\n type: event.type.slice(1)\n }));\n }\n break;\n\n case \"_mouseup\":\n _removeClass(element, _globalConfig.activeClass);\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n _fireMouseEvent(_extend({}, event, {\n type: event.type.slice(1)\n }));\n }\n break;\n\n case \"_click\":\n _copyTarget = null;\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n _fireMouseEvent(_extend({}, event, {\n type: event.type.slice(1)\n }));\n }\n break;\n\n case \"_mousemove\":\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n _fireMouseEvent(_extend({}, event, {\n type: event.type.slice(1)\n }));\n }\n break;\n }\n if (/^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) {\n return true;\n }\n };\n /**\n * Check an \"aftercopy\" event for clipboard errors and emit a corresponding \"error\" event.\n * @private\n */\n var _queueEmitClipboardErrors = function(aftercopyEvent) {\n if (aftercopyEvent.errors && aftercopyEvent.errors.length > 0) {\n var errorEvent = _deepCopy(aftercopyEvent);\n _extend(errorEvent, {\n type: \"error\",\n name: \"clipboard-error\"\n });\n delete errorEvent.success;\n _setTimeout(function() {\n ZeroClipboard.emit(errorEvent);\n }, 0);\n }\n };\n /**\n * Dispatch a synthetic MouseEvent.\n *\n * @returns `undefined`\n * @private\n */\n var _fireMouseEvent = function(event) {\n if (!(event && typeof event.type === \"string\" && event)) {\n return;\n }\n var e, target = event.target || null, doc = target && target.ownerDocument || _document, defaults = {\n view: doc.defaultView || _window,\n canBubble: true,\n cancelable: true,\n detail: event.type === \"click\" ? 1 : 0,\n button: typeof event.which === \"number\" ? event.which - 1 : typeof event.button === \"number\" ? event.button : doc.createEvent ? 0 : 1\n }, args = _extend(defaults, event);\n if (!target) {\n return;\n }\n if (doc.createEvent && target.dispatchEvent) {\n 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 ];\n e = doc.createEvent(\"MouseEvents\");\n if (e.initMouseEvent) {\n e.initMouseEvent.apply(e, args);\n e._source = \"js\";\n target.dispatchEvent(e);\n }\n }\n };\n /**\n * Continuously poll the DOM until either:\n * (a) the fallback content becomes visible, or\n * (b) we receive an event from SWF (handled elsewhere)\n *\n * IMPORTANT:\n * This is NOT a necessary check but it can result in significantly faster\n * detection of bad `swfPath` configuration and/or network/server issues [in\n * supported browsers] than waiting for the entire `flashLoadTimeout` duration\n * to elapse before detecting that the SWF cannot be loaded. The detection\n * duration can be anywhere from 10-30 times faster [in supported browsers] by\n * using this approach.\n *\n * @returns `undefined`\n * @private\n */\n var _watchForSwfFallbackContent = function() {\n var maxWait = _globalConfig.flashLoadTimeout;\n if (typeof maxWait === \"number\" && maxWait >= 0) {\n var pollWait = Math.min(1e3, maxWait / 10);\n var fallbackContentId = _globalConfig.swfObjectId + \"_fallbackContent\";\n _swfFallbackCheckInterval = _setInterval(function() {\n var el = _document.getElementById(fallbackContentId);\n if (_isElementVisible(el)) {\n _clearTimeoutsAndPolling();\n _flashState.deactivated = null;\n ZeroClipboard.emit({\n type: \"error\",\n name: \"swf-not-found\"\n });\n }\n }, pollWait);\n }\n };\n /**\n * Create the HTML bridge element to embed the Flash object into.\n * @private\n */\n var _createHtmlBridge = function() {\n var container = _document.createElement(\"div\");\n container.id = _globalConfig.containerId;\n container.className = _globalConfig.containerClass;\n container.style.position = \"absolute\";\n container.style.left = \"0px\";\n container.style.top = \"-9999px\";\n container.style.width = \"1px\";\n container.style.height = \"1px\";\n container.style.zIndex = \"\" + _getSafeZIndex(_globalConfig.zIndex);\n return container;\n };\n /**\n * Get the HTML element container that wraps the Flash bridge object/element.\n * @private\n */\n var _getHtmlBridge = function(flashBridge) {\n var htmlBridge = flashBridge && flashBridge.parentNode;\n while (htmlBridge && htmlBridge.nodeName === \"OBJECT\" && htmlBridge.parentNode) {\n htmlBridge = htmlBridge.parentNode;\n }\n return htmlBridge || null;\n };\n /**\n * Create the SWF object.\n *\n * @returns The SWF object reference.\n * @private\n */\n var _embedSwf = function() {\n var len, flashBridge = _flashState.bridge, container = _getHtmlBridge(flashBridge);\n if (!flashBridge) {\n var allowScriptAccess = _determineScriptAccess(_window.location.host, _globalConfig);\n var allowNetworking = allowScriptAccess === \"never\" ? \"none\" : \"all\";\n var flashvars = _vars(_extend({\n jsVersion: ZeroClipboard.version\n }, _globalConfig));\n var swfUrl = _globalConfig.swfPath + _cacheBust(_globalConfig.swfPath, _globalConfig);\n container = _createHtmlBridge();\n var divToBeReplaced = _document.createElement(\"div\");\n container.appendChild(divToBeReplaced);\n _document.body.appendChild(container);\n var tmpDiv = _document.createElement(\"div\");\n var usingActiveX = _flashState.pluginType === \"activex\";\n tmpDiv.innerHTML = '\" + (usingActiveX ? '' : \"\") + '' + '' + '' + '' + '' + '
 
' + \"
\";\n flashBridge = tmpDiv.firstChild;\n tmpDiv = null;\n _unwrap(flashBridge).ZeroClipboard = ZeroClipboard;\n container.replaceChild(flashBridge, divToBeReplaced);\n _watchForSwfFallbackContent();\n }\n if (!flashBridge) {\n flashBridge = _document[_globalConfig.swfObjectId];\n if (flashBridge && (len = flashBridge.length)) {\n flashBridge = flashBridge[len - 1];\n }\n if (!flashBridge && container) {\n flashBridge = container.firstChild;\n }\n }\n _flashState.bridge = flashBridge || null;\n return flashBridge;\n };\n /**\n * Destroy the SWF object.\n * @private\n */\n var _unembedSwf = function() {\n var flashBridge = _flashState.bridge;\n if (flashBridge) {\n var htmlBridge = _getHtmlBridge(flashBridge);\n if (htmlBridge) {\n if (_flashState.pluginType === \"activex\" && \"readyState\" in flashBridge) {\n flashBridge.style.display = \"none\";\n (function removeSwfFromIE() {\n if (flashBridge.readyState === 4) {\n for (var prop in flashBridge) {\n if (typeof flashBridge[prop] === \"function\") {\n flashBridge[prop] = null;\n }\n }\n if (flashBridge.parentNode) {\n flashBridge.parentNode.removeChild(flashBridge);\n }\n if (htmlBridge.parentNode) {\n htmlBridge.parentNode.removeChild(htmlBridge);\n }\n } else {\n _setTimeout(removeSwfFromIE, 10);\n }\n })();\n } else {\n if (flashBridge.parentNode) {\n flashBridge.parentNode.removeChild(flashBridge);\n }\n if (htmlBridge.parentNode) {\n htmlBridge.parentNode.removeChild(htmlBridge);\n }\n }\n }\n _clearTimeoutsAndPolling();\n _flashState.ready = null;\n _flashState.bridge = null;\n _flashState.deactivated = null;\n _zcSwfVersion = undefined;\n }\n };\n /**\n * Map the data format names of the \"clipData\" to Flash-friendly names.\n *\n * @returns A new transformed object.\n * @private\n */\n var _mapClipDataToFlash = function(clipData) {\n var newClipData = {}, formatMap = {};\n if (!(typeof clipData === \"object\" && clipData)) {\n return;\n }\n for (var dataFormat in clipData) {\n if (dataFormat && _hasOwn.call(clipData, dataFormat) && typeof clipData[dataFormat] === \"string\" && clipData[dataFormat]) {\n switch (dataFormat.toLowerCase()) {\n case \"text/plain\":\n case \"text\":\n case \"air:text\":\n case \"flash:text\":\n newClipData.text = clipData[dataFormat];\n formatMap.text = dataFormat;\n break;\n\n case \"text/html\":\n case \"html\":\n case \"air:html\":\n case \"flash:html\":\n newClipData.html = clipData[dataFormat];\n formatMap.html = dataFormat;\n break;\n\n case \"application/rtf\":\n case \"text/rtf\":\n case \"rtf\":\n case \"richtext\":\n case \"air:rtf\":\n case \"flash:rtf\":\n newClipData.rtf = clipData[dataFormat];\n formatMap.rtf = dataFormat;\n break;\n\n default:\n break;\n }\n }\n }\n return {\n data: newClipData,\n formatMap: formatMap\n };\n };\n /**\n * Map the data format names from Flash-friendly names back to their original \"clipData\" names (via a format mapping).\n *\n * @returns A new transformed object.\n * @private\n */\n var _mapClipResultsFromFlash = function(clipResults, formatMap) {\n if (!(typeof clipResults === \"object\" && clipResults && typeof formatMap === \"object\" && formatMap)) {\n return clipResults;\n }\n var newResults = {};\n for (var prop in clipResults) {\n if (_hasOwn.call(clipResults, prop)) {\n if (prop === \"errors\") {\n newResults[prop] = clipResults[prop] ? clipResults[prop].slice() : [];\n for (var i = 0, len = newResults[prop].length; i < len; i++) {\n newResults[prop][i].format = formatMap[newResults[prop][i].format];\n }\n } else if (prop !== \"success\" && prop !== \"data\") {\n newResults[prop] = clipResults[prop];\n } else {\n newResults[prop] = {};\n var tmpHash = clipResults[prop];\n for (var dataFormat in tmpHash) {\n if (dataFormat && _hasOwn.call(tmpHash, dataFormat) && _hasOwn.call(formatMap, dataFormat)) {\n newResults[prop][formatMap[dataFormat]] = tmpHash[dataFormat];\n }\n }\n }\n }\n }\n return newResults;\n };\n /**\n * Will look at a path, and will create a \"?noCache={time}\" or \"&noCache={time}\"\n * query param string to return. Does NOT append that string to the original path.\n * This is useful because ExternalInterface often breaks when a Flash SWF is cached.\n *\n * @returns The `noCache` query param with necessary \"?\"/\"&\" prefix.\n * @private\n */\n var _cacheBust = function(path, options) {\n var cacheBust = options == null || options && options.cacheBust === true;\n if (cacheBust) {\n return (path.indexOf(\"?\") === -1 ? \"?\" : \"&\") + \"noCache=\" + _now();\n } else {\n return \"\";\n }\n };\n /**\n * Creates a query string for the FlashVars param.\n * Does NOT include the cache-busting query param.\n *\n * @returns FlashVars query string\n * @private\n */\n var _vars = function(options) {\n var i, len, domain, domains, str = \"\", trustedOriginsExpanded = [];\n if (options.trustedDomains) {\n if (typeof options.trustedDomains === \"string\") {\n domains = [ options.trustedDomains ];\n } else if (typeof options.trustedDomains === \"object\" && \"length\" in options.trustedDomains) {\n domains = options.trustedDomains;\n }\n }\n if (domains && domains.length) {\n for (i = 0, len = domains.length; i < len; i++) {\n if (_hasOwn.call(domains, i) && domains[i] && typeof domains[i] === \"string\") {\n domain = _extractDomain(domains[i]);\n if (!domain) {\n continue;\n }\n if (domain === \"*\") {\n trustedOriginsExpanded.length = 0;\n trustedOriginsExpanded.push(domain);\n break;\n }\n trustedOriginsExpanded.push.apply(trustedOriginsExpanded, [ domain, \"//\" + domain, _window.location.protocol + \"//\" + domain ]);\n }\n }\n }\n if (trustedOriginsExpanded.length) {\n str += \"trustedOrigins=\" + _encodeURIComponent(trustedOriginsExpanded.join(\",\"));\n }\n if (options.forceEnhancedClipboard === true) {\n str += (str ? \"&\" : \"\") + \"forceEnhancedClipboard=true\";\n }\n if (typeof options.swfObjectId === \"string\" && options.swfObjectId) {\n str += (str ? \"&\" : \"\") + \"swfObjectId=\" + _encodeURIComponent(options.swfObjectId);\n }\n if (typeof options.jsVersion === \"string\" && options.jsVersion) {\n str += (str ? \"&\" : \"\") + \"jsVersion=\" + _encodeURIComponent(options.jsVersion);\n }\n return str;\n };\n /**\n * Extract the domain (e.g. \"github.com\") from an origin (e.g. \"https://github.com\") or\n * URL (e.g. \"https://github.com/zeroclipboard/zeroclipboard/\").\n *\n * @returns the domain\n * @private\n */\n var _extractDomain = function(originOrUrl) {\n if (originOrUrl == null || originOrUrl === \"\") {\n return null;\n }\n originOrUrl = originOrUrl.replace(/^\\s+|\\s+$/g, \"\");\n if (originOrUrl === \"\") {\n return null;\n }\n var protocolIndex = originOrUrl.indexOf(\"//\");\n originOrUrl = protocolIndex === -1 ? originOrUrl : originOrUrl.slice(protocolIndex + 2);\n var pathIndex = originOrUrl.indexOf(\"/\");\n originOrUrl = pathIndex === -1 ? originOrUrl : protocolIndex === -1 || pathIndex === 0 ? null : originOrUrl.slice(0, pathIndex);\n if (originOrUrl && originOrUrl.slice(-4).toLowerCase() === \".swf\") {\n return null;\n }\n return originOrUrl || null;\n };\n /**\n * Set `allowScriptAccess` based on `trustedDomains` and `window.location.host` vs. `swfPath`.\n *\n * @returns The appropriate script access level.\n * @private\n */\n var _determineScriptAccess = function() {\n var _extractAllDomains = function(origins) {\n var i, len, tmp, resultsArray = [];\n if (typeof origins === \"string\") {\n origins = [ origins ];\n }\n if (!(typeof origins === \"object\" && origins && typeof origins.length === \"number\")) {\n return resultsArray;\n }\n for (i = 0, len = origins.length; i < len; i++) {\n if (_hasOwn.call(origins, i) && (tmp = _extractDomain(origins[i]))) {\n if (tmp === \"*\") {\n resultsArray.length = 0;\n resultsArray.push(\"*\");\n break;\n }\n if (resultsArray.indexOf(tmp) === -1) {\n resultsArray.push(tmp);\n }\n }\n }\n return resultsArray;\n };\n return function(currentDomain, configOptions) {\n var swfDomain = _extractDomain(configOptions.swfPath);\n if (swfDomain === null) {\n swfDomain = currentDomain;\n }\n var trustedDomains = _extractAllDomains(configOptions.trustedDomains);\n var len = trustedDomains.length;\n if (len > 0) {\n if (len === 1 && trustedDomains[0] === \"*\") {\n return \"always\";\n }\n if (trustedDomains.indexOf(currentDomain) !== -1) {\n if (len === 1 && currentDomain === swfDomain) {\n return \"sameDomain\";\n }\n return \"always\";\n }\n }\n return \"never\";\n };\n }();\n /**\n * Get the currently active/focused DOM element.\n *\n * @returns the currently active/focused element, or `null`\n * @private\n */\n var _safeActiveElement = function() {\n try {\n return _document.activeElement;\n } catch (err) {\n return null;\n }\n };\n /**\n * Add a class to an element, if it doesn't already have it.\n *\n * @returns The element, with its new class added.\n * @private\n */\n var _addClass = function(element, value) {\n if (!element || element.nodeType !== 1) {\n return element;\n }\n if (element.classList) {\n if (!element.classList.contains(value)) {\n element.classList.add(value);\n }\n return element;\n }\n if (value && typeof value === \"string\") {\n var classNames = (value || \"\").split(/\\s+/);\n if (element.nodeType === 1) {\n if (!element.className) {\n element.className = value;\n } else {\n var className = \" \" + element.className + \" \", setClass = element.className;\n for (var c = 0, cl = classNames.length; c < cl; c++) {\n if (className.indexOf(\" \" + classNames[c] + \" \") < 0) {\n setClass += \" \" + classNames[c];\n }\n }\n element.className = setClass.replace(/^\\s+|\\s+$/g, \"\");\n }\n }\n }\n return element;\n };\n /**\n * Remove a class from an element, if it has it.\n *\n * @returns The element, with its class removed.\n * @private\n */\n var _removeClass = function(element, value) {\n if (!element || element.nodeType !== 1) {\n return element;\n }\n if (element.classList) {\n if (element.classList.contains(value)) {\n element.classList.remove(value);\n }\n return element;\n }\n if (typeof value === \"string\" && value) {\n var classNames = value.split(/\\s+/);\n if (element.nodeType === 1 && element.className) {\n var className = (\" \" + element.className + \" \").replace(/[\\n\\t]/g, \" \");\n for (var c = 0, cl = classNames.length; c < cl; c++) {\n className = className.replace(\" \" + classNames[c] + \" \", \" \");\n }\n element.className = className.replace(/^\\s+|\\s+$/g, \"\");\n }\n }\n return element;\n };\n /**\n * Attempt to interpret the element's CSS styling. If `prop` is `\"cursor\"`,\n * then we assume that it should be a hand (\"pointer\") cursor if the element\n * is an anchor element (\"a\" tag).\n *\n * @returns The computed style property.\n * @private\n */\n var _getStyle = function(el, prop) {\n var value = _getComputedStyle(el, null).getPropertyValue(prop);\n if (prop === \"cursor\") {\n if (!value || value === \"auto\") {\n if (el.nodeName === \"A\") {\n return \"pointer\";\n }\n }\n }\n return value;\n };\n /**\n * Get the absolutely positioned coordinates of a DOM element.\n *\n * @returns Object containing the element's position, width, and height.\n * @private\n */\n var _getElementPosition = function(el) {\n var pos = {\n left: 0,\n top: 0,\n width: 0,\n height: 0\n };\n if (el.getBoundingClientRect) {\n var elRect = el.getBoundingClientRect();\n var pageXOffset = _window.pageXOffset;\n var pageYOffset = _window.pageYOffset;\n var leftBorderWidth = _document.documentElement.clientLeft || 0;\n var topBorderWidth = _document.documentElement.clientTop || 0;\n var leftBodyOffset = 0;\n var topBodyOffset = 0;\n if (_getStyle(_document.body, \"position\") === \"relative\") {\n var bodyRect = _document.body.getBoundingClientRect();\n var htmlRect = _document.documentElement.getBoundingClientRect();\n leftBodyOffset = bodyRect.left - htmlRect.left || 0;\n topBodyOffset = bodyRect.top - htmlRect.top || 0;\n }\n pos.left = elRect.left + pageXOffset - leftBorderWidth - leftBodyOffset;\n pos.top = elRect.top + pageYOffset - topBorderWidth - topBodyOffset;\n pos.width = \"width\" in elRect ? elRect.width : elRect.right - elRect.left;\n pos.height = \"height\" in elRect ? elRect.height : elRect.bottom - elRect.top;\n }\n return pos;\n };\n /**\n * Determine is an element is visible somewhere within the document (page).\n *\n * @returns Boolean\n * @private\n */\n var _isElementVisible = function(el) {\n if (!el) {\n return false;\n }\n var styles = _getComputedStyle(el, null);\n var hasCssHeight = _parseFloat(styles.height) > 0;\n var hasCssWidth = _parseFloat(styles.width) > 0;\n var hasCssTop = _parseFloat(styles.top) >= 0;\n var hasCssLeft = _parseFloat(styles.left) >= 0;\n var cssKnows = hasCssHeight && hasCssWidth && hasCssTop && hasCssLeft;\n var rect = cssKnows ? null : _getElementPosition(el);\n 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));\n return isVisible;\n };\n /**\n * Clear all existing timeouts and interval polling delegates.\n *\n * @returns `undefined`\n * @private\n */\n var _clearTimeoutsAndPolling = function() {\n _clearTimeout(_flashCheckTimeout);\n _flashCheckTimeout = 0;\n _clearInterval(_swfFallbackCheckInterval);\n _swfFallbackCheckInterval = 0;\n };\n /**\n * Reposition the Flash object to cover the currently activated element.\n *\n * @returns `undefined`\n * @private\n */\n var _reposition = function() {\n var htmlBridge;\n if (_currentElement && (htmlBridge = _getHtmlBridge(_flashState.bridge))) {\n var pos = _getElementPosition(_currentElement);\n _extend(htmlBridge.style, {\n width: pos.width + \"px\",\n height: pos.height + \"px\",\n top: pos.top + \"px\",\n left: pos.left + \"px\",\n zIndex: \"\" + _getSafeZIndex(_globalConfig.zIndex)\n });\n }\n };\n /**\n * Sends a signal to the Flash object to display the hand cursor if `true`.\n *\n * @returns `undefined`\n * @private\n */\n var _setHandCursor = function(enabled) {\n if (_flashState.ready === true) {\n if (_flashState.bridge && typeof _flashState.bridge.setHandCursor === \"function\") {\n _flashState.bridge.setHandCursor(enabled);\n } else {\n _flashState.ready = false;\n }\n }\n };\n /**\n * Get a safe value for `zIndex`\n *\n * @returns an integer, or \"auto\"\n * @private\n */\n var _getSafeZIndex = function(val) {\n if (/^(?:auto|inherit)$/.test(val)) {\n return val;\n }\n var zIndex;\n if (typeof val === \"number\" && !_isNaN(val)) {\n zIndex = val;\n } else if (typeof val === \"string\") {\n zIndex = _getSafeZIndex(_parseInt(val, 10));\n }\n return typeof zIndex === \"number\" ? zIndex : \"auto\";\n };\n /**\n * Detect the Flash Player status, version, and plugin type.\n *\n * @see {@link https://code.google.com/p/doctype-mirror/wiki/ArticleDetectFlash#The_code}\n * @see {@link http://stackoverflow.com/questions/12866060/detecting-pepper-ppapi-flash-with-javascript}\n *\n * @returns `undefined`\n * @private\n */\n var _detectFlashSupport = function(ActiveXObject) {\n var plugin, ax, mimeType, hasFlash = false, isActiveX = false, isPPAPI = false, flashVersion = \"\";\n /**\n * Derived from Apple's suggested sniffer.\n * @param {String} desc e.g. \"Shockwave Flash 7.0 r61\"\n * @returns {String} \"7.0.61\"\n * @private\n */\n function parseFlashVersion(desc) {\n var matches = desc.match(/[\\d]+/g);\n matches.length = 3;\n return matches.join(\".\");\n }\n function isPepperFlash(flashPlayerFileName) {\n return !!flashPlayerFileName && (flashPlayerFileName = flashPlayerFileName.toLowerCase()) && (/^(pepflashplayer\\.dll|libpepflashplayer\\.so|pepperflashplayer\\.plugin)$/.test(flashPlayerFileName) || flashPlayerFileName.slice(-13) === \"chrome.plugin\");\n }\n function inspectPlugin(plugin) {\n if (plugin) {\n hasFlash = true;\n if (plugin.version) {\n flashVersion = parseFlashVersion(plugin.version);\n }\n if (!flashVersion && plugin.description) {\n flashVersion = parseFlashVersion(plugin.description);\n }\n if (plugin.filename) {\n isPPAPI = isPepperFlash(plugin.filename);\n }\n }\n }\n if (_navigator.plugins && _navigator.plugins.length) {\n plugin = _navigator.plugins[\"Shockwave Flash\"];\n inspectPlugin(plugin);\n if (_navigator.plugins[\"Shockwave Flash 2.0\"]) {\n hasFlash = true;\n flashVersion = \"2.0.0.11\";\n }\n } else if (_navigator.mimeTypes && _navigator.mimeTypes.length) {\n mimeType = _navigator.mimeTypes[\"application/x-shockwave-flash\"];\n plugin = mimeType && mimeType.enabledPlugin;\n inspectPlugin(plugin);\n } else if (typeof ActiveXObject !== \"undefined\") {\n isActiveX = true;\n try {\n ax = new ActiveXObject(\"ShockwaveFlash.ShockwaveFlash.7\");\n hasFlash = true;\n flashVersion = parseFlashVersion(ax.GetVariable(\"$version\"));\n } catch (e1) {\n try {\n ax = new ActiveXObject(\"ShockwaveFlash.ShockwaveFlash.6\");\n hasFlash = true;\n flashVersion = \"6.0.21\";\n } catch (e2) {\n try {\n ax = new ActiveXObject(\"ShockwaveFlash.ShockwaveFlash\");\n hasFlash = true;\n flashVersion = parseFlashVersion(ax.GetVariable(\"$version\"));\n } catch (e3) {\n isActiveX = false;\n }\n }\n }\n }\n _flashState.disabled = hasFlash !== true;\n _flashState.outdated = flashVersion && _parseFloat(flashVersion) < _parseFloat(_minimumFlashVersion);\n _flashState.version = flashVersion || \"0.0.0\";\n _flashState.pluginType = isPPAPI ? \"pepper\" : isActiveX ? \"activex\" : hasFlash ? \"netscape\" : \"unknown\";\n };\n /**\n * Invoke the Flash detection algorithms immediately upon inclusion so we're not waiting later.\n */\n _detectFlashSupport(_ActiveXObject);\n /**\n * A shell constructor for `ZeroClipboard` client instances.\n *\n * @constructor\n */\n var ZeroClipboard = function() {\n if (!(this instanceof ZeroClipboard)) {\n return new ZeroClipboard();\n }\n if (typeof ZeroClipboard._createClient === \"function\") {\n ZeroClipboard._createClient.apply(this, _args(arguments));\n }\n };\n /**\n * The ZeroClipboard library's version number.\n *\n * @static\n * @readonly\n * @property {string}\n */\n _defineProperty(ZeroClipboard, \"version\", {\n value: \"2.2.0-beta.3\",\n writable: false,\n configurable: true,\n enumerable: true\n });\n /**\n * Update or get a copy of the ZeroClipboard global configuration.\n * Returns a copy of the current/updated configuration.\n *\n * @returns Object\n * @static\n */\n ZeroClipboard.config = function() {\n return _config.apply(this, _args(arguments));\n };\n /**\n * Diagnostic method that describes the state of the browser, Flash Player, and ZeroClipboard.\n *\n * @returns Object\n * @static\n */\n ZeroClipboard.state = function() {\n return _state.apply(this, _args(arguments));\n };\n /**\n * Check if Flash is unusable for any reason: disabled, outdated, deactivated, etc.\n *\n * @returns Boolean\n * @static\n */\n ZeroClipboard.isFlashUnusable = function() {\n return _isFlashUnusable.apply(this, _args(arguments));\n };\n /**\n * Register an event listener.\n *\n * @returns `ZeroClipboard`\n * @static\n */\n ZeroClipboard.on = function() {\n return _on.apply(this, _args(arguments));\n };\n /**\n * Unregister an event listener.\n * If no `listener` function/object is provided, it will unregister all listeners for the provided `eventType`.\n * If no `eventType` is provided, it will unregister all listeners for every event type.\n *\n * @returns `ZeroClipboard`\n * @static\n */\n ZeroClipboard.off = function() {\n return _off.apply(this, _args(arguments));\n };\n /**\n * Retrieve event listeners for an `eventType`.\n * If no `eventType` is provided, it will retrieve all listeners for every event type.\n *\n * @returns array of listeners for the `eventType`; if no `eventType`, then a map/hash object of listeners for all event types; or `null`\n */\n ZeroClipboard.handlers = function() {\n return _listeners.apply(this, _args(arguments));\n };\n /**\n * Event emission receiver from the Flash object, forwarding to any registered JavaScript event listeners.\n *\n * @returns For the \"copy\" event, returns the Flash-friendly \"clipData\" object; otherwise `undefined`.\n * @static\n */\n ZeroClipboard.emit = function() {\n return _emit.apply(this, _args(arguments));\n };\n /**\n * Create and embed the Flash object.\n *\n * @returns The Flash object\n * @static\n */\n ZeroClipboard.create = function() {\n return _create.apply(this, _args(arguments));\n };\n /**\n * Self-destruct and clean up everything, including the embedded Flash object.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.destroy = function() {\n return _destroy.apply(this, _args(arguments));\n };\n /**\n * Set the pending data for clipboard injection.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.setData = function() {\n return _setData.apply(this, _args(arguments));\n };\n /**\n * Clear the pending data for clipboard injection.\n * If no `format` is provided, all pending data formats will be cleared.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.clearData = function() {\n return _clearData.apply(this, _args(arguments));\n };\n /**\n * Get a copy of the pending data for clipboard injection.\n * If no `format` is provided, a copy of ALL pending data formats will be returned.\n *\n * @returns `String` or `Object`\n * @static\n */\n ZeroClipboard.getData = function() {\n return _getData.apply(this, _args(arguments));\n };\n /**\n * Sets the current HTML object that the Flash object should overlay. This will put the global\n * Flash object on top of the current element; depending on the setup, this may also set the\n * pending clipboard text data as well as the Flash object's wrapping element's title attribute\n * based on the underlying HTML element and ZeroClipboard configuration.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.focus = ZeroClipboard.activate = function() {\n return _focus.apply(this, _args(arguments));\n };\n /**\n * Un-overlays the Flash object. This will put the global Flash object off-screen; depending on\n * the setup, this may also unset the Flash object's wrapping element's title attribute based on\n * the underlying HTML element and ZeroClipboard configuration.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.blur = ZeroClipboard.deactivate = function() {\n return _blur.apply(this, _args(arguments));\n };\n /**\n * Returns the currently focused/\"activated\" HTML element that the Flash object is wrapping.\n *\n * @returns `HTMLElement` or `null`\n * @static\n */\n ZeroClipboard.activeElement = function() {\n return _activeElement.apply(this, _args(arguments));\n };\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return ZeroClipboard;\n });\n } else if (typeof module === \"object\" && module && typeof module.exports === \"object\" && module.exports) {\n module.exports = ZeroClipboard;\n } else {\n window.ZeroClipboard = ZeroClipboard;\n }\n})(function() {\n return this || window;\n}());"]} \ No newline at end of file diff --git a/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.js b/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.js new file mode 100644 index 0000000000..8c093c6735 --- /dev/null +++ b/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.js @@ -0,0 +1,2478 @@ +/*! + * ZeroClipboard + * The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface. + * Copyright (c) 2009-2014 Jon Rohan, James M. Greene + * Licensed MIT + * http://zeroclipboard.org/ + * v2.2.0-beta.3 + */ +(function(window, undefined) { + "use strict"; + /** + * Store references to critically important global functions that may be + * overridden on certain web pages. + */ + 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() { + var unwrapper = function(el) { + return el; + }; + if (typeof _window.wrap === "function" && typeof _window.unwrap === "function") { + try { + var div = _document.createElement("div"); + var unwrappedDiv = _window.unwrap(div); + if (div.nodeType === 1 && unwrappedDiv && unwrappedDiv.nodeType === 1) { + unwrapper = _window.unwrap; + } + } catch (e) {} + } + return unwrapper; + }(); + /** + * Convert an `arguments` object into an Array. + * + * @returns The arguments as an Array + * @private + */ + var _args = function(argumentsObj) { + return _slice.call(argumentsObj, 0); + }; + /** + * Shallow-copy the owned, enumerable properties of one object over to another, similar to jQuery's `$.extend`. + * + * @returns The target object, augmented + * @private + */ + var _extend = function() { + var i, len, arg, prop, src, copy, args = _args(arguments), target = args[0] || {}; + for (i = 1, len = args.length; i < len; i++) { + if ((arg = args[i]) != null) { + for (prop in arg) { + if (_hasOwn.call(arg, prop)) { + src = target[prop]; + copy = arg[prop]; + if (target !== copy && copy !== undefined) { + target[prop] = copy; + } + } + } + } + } + return target; + }; + /** + * Return a deep copy of the source object or array. + * + * @returns Object or Array + * @private + */ + var _deepCopy = function(source) { + var copy, i, len, prop; + if (typeof source !== "object" || source == null || typeof source.nodeType === "number") { + copy = source; + } else if (typeof source.length === "number") { + copy = []; + for (i = 0, len = source.length; i < len; i++) { + if (_hasOwn.call(source, i)) { + copy[i] = _deepCopy(source[i]); + } + } + } else { + copy = {}; + for (prop in source) { + if (_hasOwn.call(source, prop)) { + copy[prop] = _deepCopy(source[prop]); + } + } + } + return copy; + }; + /** + * Makes a shallow copy of `obj` (like `_extend`) but filters its properties based on a list of `keys` to keep. + * The inverse of `_omit`, mostly. The big difference is that these properties do NOT need to be enumerable to + * be kept. + * + * @returns A new filtered object. + * @private + */ + var _pick = function(obj, keys) { + var newObj = {}; + for (var i = 0, len = keys.length; i < len; i++) { + if (keys[i] in obj) { + newObj[keys[i]] = obj[keys[i]]; + } + } + return newObj; + }; + /** + * Makes a shallow copy of `obj` (like `_extend`) but filters its properties based on a list of `keys` to omit. + * The inverse of `_pick`. + * + * @returns A new filtered object. + * @private + */ + var _omit = function(obj, keys) { + var newObj = {}; + for (var prop in obj) { + if (keys.indexOf(prop) === -1) { + newObj[prop] = obj[prop]; + } + } + return newObj; + }; + /** + * Remove all owned, enumerable properties from an object. + * + * @returns The original object without its owned, enumerable properties. + * @private + */ + var _deleteOwnProperties = function(obj) { + if (obj) { + for (var prop in obj) { + if (_hasOwn.call(obj, prop)) { + delete obj[prop]; + } + } + } + return obj; + }; + /** + * Determine if an element is contained within another element. + * + * @returns Boolean + * @private + */ + var _containedBy = function(el, ancestorEl) { + 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)) { + do { + if (el === ancestorEl) { + return true; + } + el = el.parentNode; + } while (el); + } + return false; + }; + /** + * Get the URL path's parent directory. + * + * @returns String or `undefined` + * @private + */ + var _getDirPathOfUrl = function(url) { + var dir; + if (typeof url === "string" && url) { + dir = url.split("#")[0].split("?")[0]; + dir = url.slice(0, url.lastIndexOf("/") + 1); + } + return dir; + }; + /** + * Get the current script's URL by throwing an `Error` and analyzing it. + * + * @returns String or `undefined` + * @private + */ + var _getCurrentScriptUrlFromErrorStack = function(stack) { + var url, matches; + if (typeof stack === "string" && stack) { + matches = stack.match(/^(?:|[^:@]*@|.+\)@(?=http[s]?|file)|.+?\s+(?: at |@)(?:[^:\(]+ )*[\(]?)((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/); + if (matches && matches[1]) { + url = matches[1]; + } else { + matches = stack.match(/\)@((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/); + if (matches && matches[1]) { + url = matches[1]; + } + } + } + return url; + }; + /** + * Get the current script's URL by throwing an `Error` and analyzing it. + * + * @returns String or `undefined` + * @private + */ + var _getCurrentScriptUrlFromError = function() { + var url, err; + try { + throw new _Error(); + } catch (e) { + err = e; + } + if (err) { + url = err.sourceURL || err.fileName || _getCurrentScriptUrlFromErrorStack(err.stack); + } + return url; + }; + /** + * Get the current script's URL. + * + * @returns String or `undefined` + * @private + */ + var _getCurrentScriptUrl = function() { + var jsPath, scripts, i; + if (_document.currentScript && (jsPath = _document.currentScript.src)) { + return jsPath; + } + scripts = _document.getElementsByTagName("script"); + if (scripts.length === 1) { + return scripts[0].src || undefined; + } + if ("readyState" in scripts[0]) { + for (i = scripts.length; i--; ) { + if (scripts[i].readyState === "interactive" && (jsPath = scripts[i].src)) { + return jsPath; + } + } + } + if (_document.readyState === "loading" && (jsPath = scripts[scripts.length - 1].src)) { + return jsPath; + } + if (jsPath = _getCurrentScriptUrlFromError()) { + return jsPath; + } + return undefined; + }; + /** + * Get the unanimous parent directory of ALL script tags. + * If any script tags are either (a) inline or (b) from differing parent + * directories, this method must return `undefined`. + * + * @returns String or `undefined` + * @private + */ + var _getUnanimousScriptParentDir = function() { + var i, jsDir, jsPath, scripts = _document.getElementsByTagName("script"); + for (i = scripts.length; i--; ) { + if (!(jsPath = scripts[i].src)) { + jsDir = null; + break; + } + jsPath = _getDirPathOfUrl(jsPath); + if (jsDir == null) { + jsDir = jsPath; + } else if (jsDir !== jsPath) { + jsDir = null; + break; + } + } + return jsDir || undefined; + }; + /** + * Get the presumed location of the "ZeroClipboard.swf" file, based on the location + * of the executing JavaScript file (e.g. "ZeroClipboard.js", etc.). + * + * @returns String + * @private + */ + var _getDefaultSwfPath = function() { + var jsDir = _getDirPathOfUrl(_getCurrentScriptUrl()) || _getUnanimousScriptParentDir() || ""; + return jsDir + "ZeroClipboard.swf"; + }; + /** + * Keep track of the state of the Flash object. + * @private + */ + var _flashState = { + bridge: null, + version: "0.0.0", + pluginType: "unknown", + disabled: null, + outdated: null, + unavailable: null, + degraded: null, + deactivated: null, + overdue: null, + ready: null + }; + /** + * The minimum Flash Player version required to use ZeroClipboard completely. + * @readonly + * @private + */ + var _minimumFlashVersion = "11.0.0"; + /** + * The ZeroClipboard library version number, as reported by Flash, at the time the SWF was compiled. + */ + var _zcSwfVersion; + /** + * Keep track of all event listener registrations. + * @private + */ + var _handlers = {}; + /** + * Keep track of the currently activated element. + * @private + */ + var _currentElement; + /** + * Keep track of the element that was activated when a `copy` process started. + * @private + */ + var _copyTarget; + /** + * Keep track of data for the pending clipboard transaction. + * @private + */ + var _clipData = {}; + /** + * Keep track of data formats for the pending clipboard transaction. + * @private + */ + var _clipDataFormatMap = null; + /** + * Keep track of the Flash availability check timeout. + * @private + */ + var _flashCheckTimeout = 0; + /** + * Keep track of SWF network errors interval polling. + * @private + */ + var _swfFallbackCheckInterval = 0; + /** + * The `message` store for events + * @private + */ + var _eventMessages = { + ready: "Flash communication is established", + error: { + "flash-disabled": "Flash is disabled or not installed", + "flash-outdated": "Flash is too outdated to support ZeroClipboard", + "flash-unavailable": "Flash is unable to communicate bidirectionally with JavaScript", + "flash-degraded": "Flash is unable to preserve data fidelity when communicating with JavaScript", + "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.", + "flash-overdue": "Flash communication was established but NOT within the acceptable time limit", + "version-mismatch": "ZeroClipboard JS version number does not match ZeroClipboard SWF version number", + "clipboard-error": "At least one error was thrown while ZeroClipboard was attempting to inject your data into the clipboard", + "config-mismatch": "ZeroClipboard configuration does not match Flash's reality", + "swf-not-found": "The ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity" + } + }; + /** + * ZeroClipboard configuration defaults for the Core module. + * @private + */ + var _globalConfig = { + swfPath: _getDefaultSwfPath(), + trustedDomains: window.location.host ? [ window.location.host ] : [], + cacheBust: true, + forceEnhancedClipboard: false, + flashLoadTimeout: 3e4, + autoActivate: true, + bubbleEvents: true, + containerId: "global-zeroclipboard-html-bridge", + containerClass: "global-zeroclipboard-container", + swfObjectId: "global-zeroclipboard-flash-bridge", + hoverClass: "zeroclipboard-is-hover", + activeClass: "zeroclipboard-is-active", + forceHandCursor: false, + title: null, + zIndex: 999999999 + }; + /** + * The underlying implementation of `ZeroClipboard.config`. + * @private + */ + var _config = function(options) { + if (typeof options === "object" && options !== null) { + for (var prop in options) { + if (_hasOwn.call(options, prop)) { + if (/^(?:forceHandCursor|title|zIndex|bubbleEvents)$/.test(prop)) { + _globalConfig[prop] = options[prop]; + } else if (_flashState.bridge == null) { + if (prop === "containerId" || prop === "swfObjectId") { + if (_isValidHtml4Id(options[prop])) { + _globalConfig[prop] = options[prop]; + } else { + throw new Error("The specified `" + prop + "` value is not valid as an HTML4 Element ID"); + } + } else { + _globalConfig[prop] = options[prop]; + } + } + } + } + } + if (typeof options === "string" && options) { + if (_hasOwn.call(_globalConfig, options)) { + return _globalConfig[options]; + } + return; + } + return _deepCopy(_globalConfig); + }; + /** + * The underlying implementation of `ZeroClipboard.state`. + * @private + */ + var _state = function() { + return { + browser: _pick(_navigator, [ "userAgent", "platform", "appName" ]), + flash: _omit(_flashState, [ "bridge" ]), + zeroclipboard: { + version: ZeroClipboard.version, + config: ZeroClipboard.config() + } + }; + }; + /** + * The underlying implementation of `ZeroClipboard.isFlashUnusable`. + * @private + */ + var _isFlashUnusable = function() { + return !!(_flashState.disabled || _flashState.outdated || _flashState.unavailable || _flashState.degraded || _flashState.deactivated); + }; + /** + * The underlying implementation of `ZeroClipboard.on`. + * @private + */ + var _on = function(eventType, listener) { + var i, len, events, added = {}; + if (typeof eventType === "string" && eventType) { + events = eventType.toLowerCase().split(/\s+/); + } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") { + for (i in eventType) { + if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") { + ZeroClipboard.on(i, eventType[i]); + } + } + } + if (events && events.length) { + for (i = 0, len = events.length; i < len; i++) { + eventType = events[i].replace(/^on/, ""); + added[eventType] = true; + if (!_handlers[eventType]) { + _handlers[eventType] = []; + } + _handlers[eventType].push(listener); + } + if (added.ready && _flashState.ready) { + ZeroClipboard.emit({ + type: "ready" + }); + } + if (added.error) { + var flashErrorTypes = [ "disabled", "outdated", "unavailable", "degraded", "deactivated", "overdue" ]; + for (i = 0, len = flashErrorTypes.length; i < len; i++) { + if (_flashState[flashErrorTypes[i]] === true) { + ZeroClipboard.emit({ + type: "error", + name: "flash-" + flashErrorTypes[i] + }); + break; + } + } + if (_zcSwfVersion !== undefined && ZeroClipboard.version !== _zcSwfVersion) { + ZeroClipboard.emit({ + type: "error", + name: "version-mismatch", + jsVersion: ZeroClipboard.version, + swfVersion: _zcSwfVersion + }); + } + } + } + return ZeroClipboard; + }; + /** + * The underlying implementation of `ZeroClipboard.off`. + * @private + */ + var _off = function(eventType, listener) { + var i, len, foundIndex, events, perEventHandlers; + if (arguments.length === 0) { + events = _keys(_handlers); + } else if (typeof eventType === "string" && eventType) { + events = eventType.split(/\s+/); + } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") { + for (i in eventType) { + if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") { + ZeroClipboard.off(i, eventType[i]); + } + } + } + if (events && events.length) { + for (i = 0, len = events.length; i < len; i++) { + eventType = events[i].toLowerCase().replace(/^on/, ""); + perEventHandlers = _handlers[eventType]; + if (perEventHandlers && perEventHandlers.length) { + if (listener) { + foundIndex = perEventHandlers.indexOf(listener); + while (foundIndex !== -1) { + perEventHandlers.splice(foundIndex, 1); + foundIndex = perEventHandlers.indexOf(listener, foundIndex); + } + } else { + perEventHandlers.length = 0; + } + } + } + } + return ZeroClipboard; + }; + /** + * The underlying implementation of `ZeroClipboard.handlers`. + * @private + */ + var _listeners = function(eventType) { + var copy; + if (typeof eventType === "string" && eventType) { + copy = _deepCopy(_handlers[eventType]) || null; + } else { + copy = _deepCopy(_handlers); + } + return copy; + }; + /** + * The underlying implementation of `ZeroClipboard.emit`. + * @private + */ + var _emit = function(event) { + var eventCopy, returnVal, tmp; + event = _createEvent(event); + if (!event) { + return; + } + if (_preprocessEvent(event)) { + return; + } + if (event.type === "ready" && _flashState.overdue === true) { + return ZeroClipboard.emit({ + type: "error", + name: "flash-overdue" + }); + } + eventCopy = _extend({}, event); + _dispatchCallbacks.call(this, eventCopy); + if (event.type === "copy") { + tmp = _mapClipDataToFlash(_clipData); + returnVal = tmp.data; + _clipDataFormatMap = tmp.formatMap; + } + return returnVal; + }; + /** + * The underlying implementation of `ZeroClipboard.create`. + * @private + */ + var _create = function() { + if (typeof _flashState.ready !== "boolean") { + _flashState.ready = false; + } + if (!ZeroClipboard.isFlashUnusable() && _flashState.bridge === null) { + var maxWait = _globalConfig.flashLoadTimeout; + if (typeof maxWait === "number" && maxWait >= 0) { + _flashCheckTimeout = _setTimeout(function() { + if (typeof _flashState.deactivated !== "boolean") { + _flashState.deactivated = true; + } + if (_flashState.deactivated === true) { + ZeroClipboard.emit({ + type: "error", + name: "flash-deactivated" + }); + } + }, maxWait); + } + _flashState.overdue = false; + _embedSwf(); + } + }; + /** + * The underlying implementation of `ZeroClipboard.destroy`. + * @private + */ + var _destroy = function() { + ZeroClipboard.clearData(); + ZeroClipboard.blur(); + ZeroClipboard.emit("destroy"); + _unembedSwf(); + ZeroClipboard.off(); + }; + /** + * The underlying implementation of `ZeroClipboard.setData`. + * @private + */ + var _setData = function(format, data) { + var dataObj; + if (typeof format === "object" && format && typeof data === "undefined") { + dataObj = format; + ZeroClipboard.clearData(); + } else if (typeof format === "string" && format) { + dataObj = {}; + dataObj[format] = data; + } else { + return; + } + for (var dataFormat in dataObj) { + if (typeof dataFormat === "string" && dataFormat && _hasOwn.call(dataObj, dataFormat) && typeof dataObj[dataFormat] === "string" && dataObj[dataFormat]) { + _clipData[dataFormat] = dataObj[dataFormat]; + } + } + }; + /** + * The underlying implementation of `ZeroClipboard.clearData`. + * @private + */ + var _clearData = function(format) { + if (typeof format === "undefined") { + _deleteOwnProperties(_clipData); + _clipDataFormatMap = null; + } else if (typeof format === "string" && _hasOwn.call(_clipData, format)) { + delete _clipData[format]; + } + }; + /** + * The underlying implementation of `ZeroClipboard.getData`. + * @private + */ + var _getData = function(format) { + if (typeof format === "undefined") { + return _deepCopy(_clipData); + } else if (typeof format === "string" && _hasOwn.call(_clipData, format)) { + return _clipData[format]; + } + }; + /** + * The underlying implementation of `ZeroClipboard.focus`/`ZeroClipboard.activate`. + * @private + */ + var _focus = function(element) { + if (!(element && element.nodeType === 1)) { + return; + } + if (_currentElement) { + _removeClass(_currentElement, _globalConfig.activeClass); + if (_currentElement !== element) { + _removeClass(_currentElement, _globalConfig.hoverClass); + } + } + _currentElement = element; + _addClass(element, _globalConfig.hoverClass); + var newTitle = element.getAttribute("title") || _globalConfig.title; + if (typeof newTitle === "string" && newTitle) { + var htmlBridge = _getHtmlBridge(_flashState.bridge); + if (htmlBridge) { + htmlBridge.setAttribute("title", newTitle); + } + } + var useHandCursor = _globalConfig.forceHandCursor === true || _getStyle(element, "cursor") === "pointer"; + _setHandCursor(useHandCursor); + _reposition(); + }; + /** + * The underlying implementation of `ZeroClipboard.blur`/`ZeroClipboard.deactivate`. + * @private + */ + var _blur = function() { + var htmlBridge = _getHtmlBridge(_flashState.bridge); + if (htmlBridge) { + htmlBridge.removeAttribute("title"); + htmlBridge.style.left = "0px"; + htmlBridge.style.top = "-9999px"; + htmlBridge.style.width = "1px"; + htmlBridge.style.top = "1px"; + } + if (_currentElement) { + _removeClass(_currentElement, _globalConfig.hoverClass); + _removeClass(_currentElement, _globalConfig.activeClass); + _currentElement = null; + } + }; + /** + * The underlying implementation of `ZeroClipboard.activeElement`. + * @private + */ + var _activeElement = function() { + return _currentElement || null; + }; + /** + * Check if a value is a valid HTML4 `ID` or `Name` token. + * @private + */ + var _isValidHtml4Id = function(id) { + return typeof id === "string" && id && /^[A-Za-z][A-Za-z0-9_:\-\.]*$/.test(id); + }; + /** + * Create or update an `event` object, based on the `eventType`. + * @private + */ + var _createEvent = function(event) { + var eventType; + if (typeof event === "string" && event) { + eventType = event; + event = {}; + } else if (typeof event === "object" && event && typeof event.type === "string" && event.type) { + eventType = event.type; + } + if (!eventType) { + return; + } + eventType = eventType.toLowerCase(); + if (!event.target && (/^(copy|aftercopy|_click)$/.test(eventType) || eventType === "error" && event.name === "clipboard-error")) { + event.target = _copyTarget; + } + _extend(event, { + type: eventType, + target: event.target || _currentElement || null, + relatedTarget: event.relatedTarget || null, + currentTarget: _flashState && _flashState.bridge || null, + timeStamp: event.timeStamp || _now() || null + }); + var msg = _eventMessages[event.type]; + if (event.type === "error" && event.name && msg) { + msg = msg[event.name]; + } + if (msg) { + event.message = msg; + } + if (event.type === "ready") { + _extend(event, { + target: null, + version: _flashState.version + }); + } + if (event.type === "error") { + if (/^flash-(disabled|outdated|unavailable|degraded|deactivated|overdue)$/.test(event.name)) { + _extend(event, { + target: null, + minimumVersion: _minimumFlashVersion + }); + } + if (/^flash-(outdated|unavailable|degraded|deactivated|overdue)$/.test(event.name)) { + _extend(event, { + version: _flashState.version + }); + } + } + if (event.type === "copy") { + event.clipboardData = { + setData: ZeroClipboard.setData, + clearData: ZeroClipboard.clearData + }; + } + if (event.type === "aftercopy") { + event = _mapClipResultsFromFlash(event, _clipDataFormatMap); + } + if (event.target && !event.relatedTarget) { + event.relatedTarget = _getRelatedTarget(event.target); + } + return _addMouseData(event); + }; + /** + * Get a relatedTarget from the target's `data-clipboard-target` attribute + * @private + */ + var _getRelatedTarget = function(targetEl) { + var relatedTargetId = targetEl && targetEl.getAttribute && targetEl.getAttribute("data-clipboard-target"); + return relatedTargetId ? _document.getElementById(relatedTargetId) : null; + }; + /** + * Add element and position data to `MouseEvent` instances + * @private + */ + var _addMouseData = function(event) { + if (event && /^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) { + var srcElement = event.target; + var fromElement = event.type === "_mouseover" && event.relatedTarget ? event.relatedTarget : undefined; + var toElement = event.type === "_mouseout" && event.relatedTarget ? event.relatedTarget : undefined; + var pos = _getElementPosition(srcElement); + var screenLeft = _window.screenLeft || _window.screenX || 0; + var screenTop = _window.screenTop || _window.screenY || 0; + var scrollLeft = _document.body.scrollLeft + _document.documentElement.scrollLeft; + var scrollTop = _document.body.scrollTop + _document.documentElement.scrollTop; + var pageX = pos.left + (typeof event._stageX === "number" ? event._stageX : 0); + var pageY = pos.top + (typeof event._stageY === "number" ? event._stageY : 0); + var clientX = pageX - scrollLeft; + var clientY = pageY - scrollTop; + var screenX = screenLeft + clientX; + var screenY = screenTop + clientY; + var moveX = typeof event.movementX === "number" ? event.movementX : 0; + var moveY = typeof event.movementY === "number" ? event.movementY : 0; + delete event._stageX; + delete event._stageY; + _extend(event, { + srcElement: srcElement, + fromElement: fromElement, + toElement: toElement, + screenX: screenX, + screenY: screenY, + pageX: pageX, + pageY: pageY, + clientX: clientX, + clientY: clientY, + x: clientX, + y: clientY, + movementX: moveX, + movementY: moveY, + offsetX: 0, + offsetY: 0, + layerX: 0, + layerY: 0 + }); + } + return event; + }; + /** + * Determine if an event's registered handlers should be execute synchronously or asynchronously. + * + * @returns {boolean} + * @private + */ + var _shouldPerformAsync = function(event) { + var eventType = event && typeof event.type === "string" && event.type || ""; + return !/^(?:(?:before)?copy|destroy)$/.test(eventType); + }; + /** + * Control if a callback should be executed asynchronously or not. + * + * @returns `undefined` + * @private + */ + var _dispatchCallback = function(func, context, args, async) { + if (async) { + _setTimeout(function() { + func.apply(context, args); + }, 0); + } else { + func.apply(context, args); + } + }; + /** + * Handle the actual dispatching of events to client instances. + * + * @returns `undefined` + * @private + */ + var _dispatchCallbacks = function(event) { + if (!(typeof event === "object" && event && event.type)) { + return; + } + var async = _shouldPerformAsync(event); + var wildcardTypeHandlers = _handlers["*"] || []; + var specificTypeHandlers = _handlers[event.type] || []; + var handlers = wildcardTypeHandlers.concat(specificTypeHandlers); + if (handlers && handlers.length) { + var i, len, func, context, eventCopy, originalContext = this; + for (i = 0, len = handlers.length; i < len; i++) { + func = handlers[i]; + context = originalContext; + if (typeof func === "string" && typeof _window[func] === "function") { + func = _window[func]; + } + if (typeof func === "object" && func && typeof func.handleEvent === "function") { + context = func; + func = func.handleEvent; + } + if (typeof func === "function") { + eventCopy = _extend({}, event); + _dispatchCallback(func, context, [ eventCopy ], async); + } + } + } + return this; + }; + /** + * Preprocess any special behaviors, reactions, or state changes after receiving this event. + * Executes only once per event emitted, NOT once per client. + * @private + */ + var _preprocessEvent = function(event) { + var element = event.target || _currentElement || null; + var sourceIsSwf = event._source === "swf"; + delete event._source; + var flashErrorNames = [ "flash-disabled", "flash-outdated", "flash-unavailable", "flash-degraded", "flash-deactivated", "flash-overdue" ]; + switch (event.type) { + case "error": + if (flashErrorNames.indexOf(event.name) !== -1) { + _extend(_flashState, { + disabled: event.name === "flash-disabled", + outdated: event.name === "flash-outdated", + unavailable: event.name === "flash-unavailable", + degraded: event.name === "flash-degraded", + deactivated: event.name === "flash-deactivated", + overdue: event.name === "flash-overdue", + ready: false + }); + } else if (event.name === "version-mismatch") { + _zcSwfVersion = event.swfVersion; + _extend(_flashState, { + disabled: false, + outdated: false, + unavailable: false, + degraded: false, + deactivated: false, + overdue: false, + ready: false + }); + } + _clearTimeoutsAndPolling(); + break; + + case "ready": + _zcSwfVersion = event.swfVersion; + var wasDeactivated = _flashState.deactivated === true; + _extend(_flashState, { + disabled: false, + outdated: false, + unavailable: false, + degraded: false, + deactivated: false, + overdue: wasDeactivated, + ready: !wasDeactivated + }); + _clearTimeoutsAndPolling(); + break; + + case "beforecopy": + _copyTarget = element; + break; + + case "copy": + var textContent, htmlContent, targetEl = event.relatedTarget; + if (!(_clipData["text/html"] || _clipData["text/plain"]) && targetEl && (htmlContent = targetEl.value || targetEl.outerHTML || targetEl.innerHTML) && (textContent = targetEl.value || targetEl.textContent || targetEl.innerText)) { + event.clipboardData.clearData(); + event.clipboardData.setData("text/plain", textContent); + if (htmlContent !== textContent) { + event.clipboardData.setData("text/html", htmlContent); + } + } else if (!_clipData["text/plain"] && event.target && (textContent = event.target.getAttribute("data-clipboard-text"))) { + event.clipboardData.clearData(); + event.clipboardData.setData("text/plain", textContent); + } + break; + + case "aftercopy": + _queueEmitClipboardErrors(event); + ZeroClipboard.clearData(); + if (element && element !== _safeActiveElement() && element.focus) { + element.focus(); + } + break; + + case "_mouseover": + ZeroClipboard.focus(element); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) { + _fireMouseEvent(_extend({}, event, { + type: "mouseenter", + bubbles: false, + cancelable: false + })); + } + _fireMouseEvent(_extend({}, event, { + type: "mouseover" + })); + } + break; + + case "_mouseout": + ZeroClipboard.blur(); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) { + _fireMouseEvent(_extend({}, event, { + type: "mouseleave", + bubbles: false, + cancelable: false + })); + } + _fireMouseEvent(_extend({}, event, { + type: "mouseout" + })); + } + break; + + case "_mousedown": + _addClass(element, _globalConfig.activeClass); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + + case "_mouseup": + _removeClass(element, _globalConfig.activeClass); + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + + case "_click": + _copyTarget = null; + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + + case "_mousemove": + if (_globalConfig.bubbleEvents === true && sourceIsSwf) { + _fireMouseEvent(_extend({}, event, { + type: event.type.slice(1) + })); + } + break; + } + if (/^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) { + return true; + } + }; + /** + * Check an "aftercopy" event for clipboard errors and emit a corresponding "error" event. + * @private + */ + var _queueEmitClipboardErrors = function(aftercopyEvent) { + if (aftercopyEvent.errors && aftercopyEvent.errors.length > 0) { + var errorEvent = _deepCopy(aftercopyEvent); + _extend(errorEvent, { + type: "error", + name: "clipboard-error" + }); + delete errorEvent.success; + _setTimeout(function() { + ZeroClipboard.emit(errorEvent); + }, 0); + } + }; + /** + * Dispatch a synthetic MouseEvent. + * + * @returns `undefined` + * @private + */ + var _fireMouseEvent = function(event) { + if (!(event && typeof event.type === "string" && event)) { + return; + } + var e, target = event.target || null, doc = target && target.ownerDocument || _document, defaults = { + view: doc.defaultView || _window, + canBubble: true, + cancelable: true, + detail: event.type === "click" ? 1 : 0, + button: typeof event.which === "number" ? event.which - 1 : typeof event.button === "number" ? event.button : doc.createEvent ? 0 : 1 + }, args = _extend(defaults, event); + if (!target) { + return; + } + if (doc.createEvent && target.dispatchEvent) { + 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 ]; + e = doc.createEvent("MouseEvents"); + if (e.initMouseEvent) { + e.initMouseEvent.apply(e, args); + e._source = "js"; + target.dispatchEvent(e); + } + } + }; + /** + * Continuously poll the DOM until either: + * (a) the fallback content becomes visible, or + * (b) we receive an event from SWF (handled elsewhere) + * + * IMPORTANT: + * This is NOT a necessary check but it can result in significantly faster + * detection of bad `swfPath` configuration and/or network/server issues [in + * supported browsers] than waiting for the entire `flashLoadTimeout` duration + * to elapse before detecting that the SWF cannot be loaded. The detection + * duration can be anywhere from 10-30 times faster [in supported browsers] by + * using this approach. + * + * @returns `undefined` + * @private + */ + var _watchForSwfFallbackContent = function() { + var maxWait = _globalConfig.flashLoadTimeout; + if (typeof maxWait === "number" && maxWait >= 0) { + var pollWait = Math.min(1e3, maxWait / 10); + var fallbackContentId = _globalConfig.swfObjectId + "_fallbackContent"; + _swfFallbackCheckInterval = _setInterval(function() { + var el = _document.getElementById(fallbackContentId); + if (_isElementVisible(el)) { + _clearTimeoutsAndPolling(); + _flashState.deactivated = null; + ZeroClipboard.emit({ + type: "error", + name: "swf-not-found" + }); + } + }, pollWait); + } + }; + /** + * Create the HTML bridge element to embed the Flash object into. + * @private + */ + var _createHtmlBridge = function() { + var container = _document.createElement("div"); + container.id = _globalConfig.containerId; + container.className = _globalConfig.containerClass; + container.style.position = "absolute"; + container.style.left = "0px"; + container.style.top = "-9999px"; + container.style.width = "1px"; + container.style.height = "1px"; + container.style.zIndex = "" + _getSafeZIndex(_globalConfig.zIndex); + return container; + }; + /** + * Get the HTML element container that wraps the Flash bridge object/element. + * @private + */ + var _getHtmlBridge = function(flashBridge) { + var htmlBridge = flashBridge && flashBridge.parentNode; + while (htmlBridge && htmlBridge.nodeName === "OBJECT" && htmlBridge.parentNode) { + htmlBridge = htmlBridge.parentNode; + } + return htmlBridge || null; + }; + /** + * Create the SWF object. + * + * @returns The SWF object reference. + * @private + */ + var _embedSwf = function() { + var len, flashBridge = _flashState.bridge, container = _getHtmlBridge(flashBridge); + if (!flashBridge) { + var allowScriptAccess = _determineScriptAccess(_window.location.host, _globalConfig); + var allowNetworking = allowScriptAccess === "never" ? "none" : "all"; + var flashvars = _vars(_extend({ + jsVersion: ZeroClipboard.version + }, _globalConfig)); + var swfUrl = _globalConfig.swfPath + _cacheBust(_globalConfig.swfPath, _globalConfig); + container = _createHtmlBridge(); + var divToBeReplaced = _document.createElement("div"); + container.appendChild(divToBeReplaced); + _document.body.appendChild(container); + var tmpDiv = _document.createElement("div"); + var usingActiveX = _flashState.pluginType === "activex"; + tmpDiv.innerHTML = '" + (usingActiveX ? '' : "") + '' + '' + '' + '' + '' + '
 
' + "
"; + flashBridge = tmpDiv.firstChild; + tmpDiv = null; + _unwrap(flashBridge).ZeroClipboard = ZeroClipboard; + container.replaceChild(flashBridge, divToBeReplaced); + _watchForSwfFallbackContent(); + } + if (!flashBridge) { + flashBridge = _document[_globalConfig.swfObjectId]; + if (flashBridge && (len = flashBridge.length)) { + flashBridge = flashBridge[len - 1]; + } + if (!flashBridge && container) { + flashBridge = container.firstChild; + } + } + _flashState.bridge = flashBridge || null; + return flashBridge; + }; + /** + * Destroy the SWF object. + * @private + */ + var _unembedSwf = function() { + var flashBridge = _flashState.bridge; + if (flashBridge) { + var htmlBridge = _getHtmlBridge(flashBridge); + if (htmlBridge) { + if (_flashState.pluginType === "activex" && "readyState" in flashBridge) { + flashBridge.style.display = "none"; + (function removeSwfFromIE() { + if (flashBridge.readyState === 4) { + for (var prop in flashBridge) { + if (typeof flashBridge[prop] === "function") { + flashBridge[prop] = null; + } + } + if (flashBridge.parentNode) { + flashBridge.parentNode.removeChild(flashBridge); + } + if (htmlBridge.parentNode) { + htmlBridge.parentNode.removeChild(htmlBridge); + } + } else { + _setTimeout(removeSwfFromIE, 10); + } + })(); + } else { + if (flashBridge.parentNode) { + flashBridge.parentNode.removeChild(flashBridge); + } + if (htmlBridge.parentNode) { + htmlBridge.parentNode.removeChild(htmlBridge); + } + } + } + _clearTimeoutsAndPolling(); + _flashState.ready = null; + _flashState.bridge = null; + _flashState.deactivated = null; + _zcSwfVersion = undefined; + } + }; + /** + * Map the data format names of the "clipData" to Flash-friendly names. + * + * @returns A new transformed object. + * @private + */ + var _mapClipDataToFlash = function(clipData) { + var newClipData = {}, formatMap = {}; + if (!(typeof clipData === "object" && clipData)) { + return; + } + for (var dataFormat in clipData) { + if (dataFormat && _hasOwn.call(clipData, dataFormat) && typeof clipData[dataFormat] === "string" && clipData[dataFormat]) { + switch (dataFormat.toLowerCase()) { + case "text/plain": + case "text": + case "air:text": + case "flash:text": + newClipData.text = clipData[dataFormat]; + formatMap.text = dataFormat; + break; + + case "text/html": + case "html": + case "air:html": + case "flash:html": + newClipData.html = clipData[dataFormat]; + formatMap.html = dataFormat; + break; + + case "application/rtf": + case "text/rtf": + case "rtf": + case "richtext": + case "air:rtf": + case "flash:rtf": + newClipData.rtf = clipData[dataFormat]; + formatMap.rtf = dataFormat; + break; + + default: + break; + } + } + } + return { + data: newClipData, + formatMap: formatMap + }; + }; + /** + * Map the data format names from Flash-friendly names back to their original "clipData" names (via a format mapping). + * + * @returns A new transformed object. + * @private + */ + var _mapClipResultsFromFlash = function(clipResults, formatMap) { + if (!(typeof clipResults === "object" && clipResults && typeof formatMap === "object" && formatMap)) { + return clipResults; + } + var newResults = {}; + for (var prop in clipResults) { + if (_hasOwn.call(clipResults, prop)) { + if (prop === "errors") { + newResults[prop] = clipResults[prop] ? clipResults[prop].slice() : []; + for (var i = 0, len = newResults[prop].length; i < len; i++) { + newResults[prop][i].format = formatMap[newResults[prop][i].format]; + } + } else if (prop !== "success" && prop !== "data") { + newResults[prop] = clipResults[prop]; + } else { + newResults[prop] = {}; + var tmpHash = clipResults[prop]; + for (var dataFormat in tmpHash) { + if (dataFormat && _hasOwn.call(tmpHash, dataFormat) && _hasOwn.call(formatMap, dataFormat)) { + newResults[prop][formatMap[dataFormat]] = tmpHash[dataFormat]; + } + } + } + } + } + return newResults; + }; + /** + * Will look at a path, and will create a "?noCache={time}" or "&noCache={time}" + * query param string to return. Does NOT append that string to the original path. + * This is useful because ExternalInterface often breaks when a Flash SWF is cached. + * + * @returns The `noCache` query param with necessary "?"/"&" prefix. + * @private + */ + var _cacheBust = function(path, options) { + var cacheBust = options == null || options && options.cacheBust === true; + if (cacheBust) { + return (path.indexOf("?") === -1 ? "?" : "&") + "noCache=" + _now(); + } else { + return ""; + } + }; + /** + * Creates a query string for the FlashVars param. + * Does NOT include the cache-busting query param. + * + * @returns FlashVars query string + * @private + */ + var _vars = function(options) { + var i, len, domain, domains, str = "", trustedOriginsExpanded = []; + if (options.trustedDomains) { + if (typeof options.trustedDomains === "string") { + domains = [ options.trustedDomains ]; + } else if (typeof options.trustedDomains === "object" && "length" in options.trustedDomains) { + domains = options.trustedDomains; + } + } + if (domains && domains.length) { + for (i = 0, len = domains.length; i < len; i++) { + if (_hasOwn.call(domains, i) && domains[i] && typeof domains[i] === "string") { + domain = _extractDomain(domains[i]); + if (!domain) { + continue; + } + if (domain === "*") { + trustedOriginsExpanded.length = 0; + trustedOriginsExpanded.push(domain); + break; + } + trustedOriginsExpanded.push.apply(trustedOriginsExpanded, [ domain, "//" + domain, _window.location.protocol + "//" + domain ]); + } + } + } + if (trustedOriginsExpanded.length) { + str += "trustedOrigins=" + _encodeURIComponent(trustedOriginsExpanded.join(",")); + } + if (options.forceEnhancedClipboard === true) { + str += (str ? "&" : "") + "forceEnhancedClipboard=true"; + } + if (typeof options.swfObjectId === "string" && options.swfObjectId) { + str += (str ? "&" : "") + "swfObjectId=" + _encodeURIComponent(options.swfObjectId); + } + if (typeof options.jsVersion === "string" && options.jsVersion) { + str += (str ? "&" : "") + "jsVersion=" + _encodeURIComponent(options.jsVersion); + } + return str; + }; + /** + * Extract the domain (e.g. "github.com") from an origin (e.g. "https://github.com") or + * URL (e.g. "https://github.com/zeroclipboard/zeroclipboard/"). + * + * @returns the domain + * @private + */ + var _extractDomain = function(originOrUrl) { + if (originOrUrl == null || originOrUrl === "") { + return null; + } + originOrUrl = originOrUrl.replace(/^\s+|\s+$/g, ""); + if (originOrUrl === "") { + return null; + } + var protocolIndex = originOrUrl.indexOf("//"); + originOrUrl = protocolIndex === -1 ? originOrUrl : originOrUrl.slice(protocolIndex + 2); + var pathIndex = originOrUrl.indexOf("/"); + originOrUrl = pathIndex === -1 ? originOrUrl : protocolIndex === -1 || pathIndex === 0 ? null : originOrUrl.slice(0, pathIndex); + if (originOrUrl && originOrUrl.slice(-4).toLowerCase() === ".swf") { + return null; + } + return originOrUrl || null; + }; + /** + * Set `allowScriptAccess` based on `trustedDomains` and `window.location.host` vs. `swfPath`. + * + * @returns The appropriate script access level. + * @private + */ + var _determineScriptAccess = function() { + var _extractAllDomains = function(origins) { + var i, len, tmp, resultsArray = []; + if (typeof origins === "string") { + origins = [ origins ]; + } + if (!(typeof origins === "object" && origins && typeof origins.length === "number")) { + return resultsArray; + } + for (i = 0, len = origins.length; i < len; i++) { + if (_hasOwn.call(origins, i) && (tmp = _extractDomain(origins[i]))) { + if (tmp === "*") { + resultsArray.length = 0; + resultsArray.push("*"); + break; + } + if (resultsArray.indexOf(tmp) === -1) { + resultsArray.push(tmp); + } + } + } + return resultsArray; + }; + return function(currentDomain, configOptions) { + var swfDomain = _extractDomain(configOptions.swfPath); + if (swfDomain === null) { + swfDomain = currentDomain; + } + var trustedDomains = _extractAllDomains(configOptions.trustedDomains); + var len = trustedDomains.length; + if (len > 0) { + if (len === 1 && trustedDomains[0] === "*") { + return "always"; + } + if (trustedDomains.indexOf(currentDomain) !== -1) { + if (len === 1 && currentDomain === swfDomain) { + return "sameDomain"; + } + return "always"; + } + } + return "never"; + }; + }(); + /** + * Get the currently active/focused DOM element. + * + * @returns the currently active/focused element, or `null` + * @private + */ + var _safeActiveElement = function() { + try { + return _document.activeElement; + } catch (err) { + return null; + } + }; + /** + * Add a class to an element, if it doesn't already have it. + * + * @returns The element, with its new class added. + * @private + */ + var _addClass = function(element, value) { + if (!element || element.nodeType !== 1) { + return element; + } + if (element.classList) { + if (!element.classList.contains(value)) { + element.classList.add(value); + } + return element; + } + if (value && typeof value === "string") { + var classNames = (value || "").split(/\s+/); + if (element.nodeType === 1) { + if (!element.className) { + element.className = value; + } else { + var className = " " + element.className + " ", setClass = element.className; + for (var c = 0, cl = classNames.length; c < cl; c++) { + if (className.indexOf(" " + classNames[c] + " ") < 0) { + setClass += " " + classNames[c]; + } + } + element.className = setClass.replace(/^\s+|\s+$/g, ""); + } + } + } + return element; + }; + /** + * Remove a class from an element, if it has it. + * + * @returns The element, with its class removed. + * @private + */ + var _removeClass = function(element, value) { + if (!element || element.nodeType !== 1) { + return element; + } + if (element.classList) { + if (element.classList.contains(value)) { + element.classList.remove(value); + } + return element; + } + if (typeof value === "string" && value) { + var classNames = value.split(/\s+/); + if (element.nodeType === 1 && element.className) { + var className = (" " + element.className + " ").replace(/[\n\t]/g, " "); + for (var c = 0, cl = classNames.length; c < cl; c++) { + className = className.replace(" " + classNames[c] + " ", " "); + } + element.className = className.replace(/^\s+|\s+$/g, ""); + } + } + return element; + }; + /** + * Attempt to interpret the element's CSS styling. If `prop` is `"cursor"`, + * then we assume that it should be a hand ("pointer") cursor if the element + * is an anchor element ("a" tag). + * + * @returns The computed style property. + * @private + */ + var _getStyle = function(el, prop) { + var value = _getComputedStyle(el, null).getPropertyValue(prop); + if (prop === "cursor") { + if (!value || value === "auto") { + if (el.nodeName === "A") { + return "pointer"; + } + } + } + return value; + }; + /** + * Get the absolutely positioned coordinates of a DOM element. + * + * @returns Object containing the element's position, width, and height. + * @private + */ + var _getElementPosition = function(el) { + var pos = { + left: 0, + top: 0, + width: 0, + height: 0 + }; + if (el.getBoundingClientRect) { + var elRect = el.getBoundingClientRect(); + var pageXOffset = _window.pageXOffset; + var pageYOffset = _window.pageYOffset; + var leftBorderWidth = _document.documentElement.clientLeft || 0; + var topBorderWidth = _document.documentElement.clientTop || 0; + var leftBodyOffset = 0; + var topBodyOffset = 0; + if (_getStyle(_document.body, "position") === "relative") { + var bodyRect = _document.body.getBoundingClientRect(); + var htmlRect = _document.documentElement.getBoundingClientRect(); + leftBodyOffset = bodyRect.left - htmlRect.left || 0; + topBodyOffset = bodyRect.top - htmlRect.top || 0; + } + pos.left = elRect.left + pageXOffset - leftBorderWidth - leftBodyOffset; + pos.top = elRect.top + pageYOffset - topBorderWidth - topBodyOffset; + pos.width = "width" in elRect ? elRect.width : elRect.right - elRect.left; + pos.height = "height" in elRect ? elRect.height : elRect.bottom - elRect.top; + } + return pos; + }; + /** + * Determine is an element is visible somewhere within the document (page). + * + * @returns Boolean + * @private + */ + var _isElementVisible = function(el) { + if (!el) { + return false; + } + var styles = _getComputedStyle(el, null); + var hasCssHeight = _parseFloat(styles.height) > 0; + var hasCssWidth = _parseFloat(styles.width) > 0; + var hasCssTop = _parseFloat(styles.top) >= 0; + var hasCssLeft = _parseFloat(styles.left) >= 0; + var cssKnows = hasCssHeight && hasCssWidth && hasCssTop && hasCssLeft; + var rect = cssKnows ? null : _getElementPosition(el); + 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)); + return isVisible; + }; + /** + * Clear all existing timeouts and interval polling delegates. + * + * @returns `undefined` + * @private + */ + var _clearTimeoutsAndPolling = function() { + _clearTimeout(_flashCheckTimeout); + _flashCheckTimeout = 0; + _clearInterval(_swfFallbackCheckInterval); + _swfFallbackCheckInterval = 0; + }; + /** + * Reposition the Flash object to cover the currently activated element. + * + * @returns `undefined` + * @private + */ + var _reposition = function() { + var htmlBridge; + if (_currentElement && (htmlBridge = _getHtmlBridge(_flashState.bridge))) { + var pos = _getElementPosition(_currentElement); + _extend(htmlBridge.style, { + width: pos.width + "px", + height: pos.height + "px", + top: pos.top + "px", + left: pos.left + "px", + zIndex: "" + _getSafeZIndex(_globalConfig.zIndex) + }); + } + }; + /** + * Sends a signal to the Flash object to display the hand cursor if `true`. + * + * @returns `undefined` + * @private + */ + var _setHandCursor = function(enabled) { + if (_flashState.ready === true) { + if (_flashState.bridge && typeof _flashState.bridge.setHandCursor === "function") { + _flashState.bridge.setHandCursor(enabled); + } else { + _flashState.ready = false; + } + } + }; + /** + * Get a safe value for `zIndex` + * + * @returns an integer, or "auto" + * @private + */ + var _getSafeZIndex = function(val) { + if (/^(?:auto|inherit)$/.test(val)) { + return val; + } + var zIndex; + if (typeof val === "number" && !_isNaN(val)) { + zIndex = val; + } else if (typeof val === "string") { + zIndex = _getSafeZIndex(_parseInt(val, 10)); + } + return typeof zIndex === "number" ? zIndex : "auto"; + }; + /** + * Detect the Flash Player status, version, and plugin type. + * + * @see {@link https://code.google.com/p/doctype-mirror/wiki/ArticleDetectFlash#The_code} + * @see {@link http://stackoverflow.com/questions/12866060/detecting-pepper-ppapi-flash-with-javascript} + * + * @returns `undefined` + * @private + */ + var _detectFlashSupport = function(ActiveXObject) { + var plugin, ax, mimeType, hasFlash = false, isActiveX = false, isPPAPI = false, flashVersion = ""; + /** + * Derived from Apple's suggested sniffer. + * @param {String} desc e.g. "Shockwave Flash 7.0 r61" + * @returns {String} "7.0.61" + * @private + */ + function parseFlashVersion(desc) { + var matches = desc.match(/[\d]+/g); + matches.length = 3; + return matches.join("."); + } + function isPepperFlash(flashPlayerFileName) { + return !!flashPlayerFileName && (flashPlayerFileName = flashPlayerFileName.toLowerCase()) && (/^(pepflashplayer\.dll|libpepflashplayer\.so|pepperflashplayer\.plugin)$/.test(flashPlayerFileName) || flashPlayerFileName.slice(-13) === "chrome.plugin"); + } + function inspectPlugin(plugin) { + if (plugin) { + hasFlash = true; + if (plugin.version) { + flashVersion = parseFlashVersion(plugin.version); + } + if (!flashVersion && plugin.description) { + flashVersion = parseFlashVersion(plugin.description); + } + if (plugin.filename) { + isPPAPI = isPepperFlash(plugin.filename); + } + } + } + if (_navigator.plugins && _navigator.plugins.length) { + plugin = _navigator.plugins["Shockwave Flash"]; + inspectPlugin(plugin); + if (_navigator.plugins["Shockwave Flash 2.0"]) { + hasFlash = true; + flashVersion = "2.0.0.11"; + } + } else if (_navigator.mimeTypes && _navigator.mimeTypes.length) { + mimeType = _navigator.mimeTypes["application/x-shockwave-flash"]; + plugin = mimeType && mimeType.enabledPlugin; + inspectPlugin(plugin); + } else if (typeof ActiveXObject !== "undefined") { + isActiveX = true; + try { + ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); + hasFlash = true; + flashVersion = parseFlashVersion(ax.GetVariable("$version")); + } catch (e1) { + try { + ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); + hasFlash = true; + flashVersion = "6.0.21"; + } catch (e2) { + try { + ax = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); + hasFlash = true; + flashVersion = parseFlashVersion(ax.GetVariable("$version")); + } catch (e3) { + isActiveX = false; + } + } + } + } + _flashState.disabled = hasFlash !== true; + _flashState.outdated = flashVersion && _parseFloat(flashVersion) < _parseFloat(_minimumFlashVersion); + _flashState.version = flashVersion || "0.0.0"; + _flashState.pluginType = isPPAPI ? "pepper" : isActiveX ? "activex" : hasFlash ? "netscape" : "unknown"; + }; + /** + * Invoke the Flash detection algorithms immediately upon inclusion so we're not waiting later. + */ + _detectFlashSupport(_ActiveXObject); + /** + * A shell constructor for `ZeroClipboard` client instances. + * + * @constructor + */ + var ZeroClipboard = function() { + if (!(this instanceof ZeroClipboard)) { + return new ZeroClipboard(); + } + if (typeof ZeroClipboard._createClient === "function") { + ZeroClipboard._createClient.apply(this, _args(arguments)); + } + }; + /** + * The ZeroClipboard library's version number. + * + * @static + * @readonly + * @property {string} + */ + _defineProperty(ZeroClipboard, "version", { + value: "2.2.0-beta.3", + writable: false, + configurable: true, + enumerable: true + }); + /** + * Update or get a copy of the ZeroClipboard global configuration. + * Returns a copy of the current/updated configuration. + * + * @returns Object + * @static + */ + ZeroClipboard.config = function() { + return _config.apply(this, _args(arguments)); + }; + /** + * Diagnostic method that describes the state of the browser, Flash Player, and ZeroClipboard. + * + * @returns Object + * @static + */ + ZeroClipboard.state = function() { + return _state.apply(this, _args(arguments)); + }; + /** + * Check if Flash is unusable for any reason: disabled, outdated, deactivated, etc. + * + * @returns Boolean + * @static + */ + ZeroClipboard.isFlashUnusable = function() { + return _isFlashUnusable.apply(this, _args(arguments)); + }; + /** + * Register an event listener. + * + * @returns `ZeroClipboard` + * @static + */ + ZeroClipboard.on = function() { + return _on.apply(this, _args(arguments)); + }; + /** + * Unregister an event listener. + * If no `listener` function/object is provided, it will unregister all listeners for the provided `eventType`. + * If no `eventType` is provided, it will unregister all listeners for every event type. + * + * @returns `ZeroClipboard` + * @static + */ + ZeroClipboard.off = function() { + return _off.apply(this, _args(arguments)); + }; + /** + * Retrieve event listeners for an `eventType`. + * If no `eventType` is provided, it will retrieve all listeners for every event type. + * + * @returns array of listeners for the `eventType`; if no `eventType`, then a map/hash object of listeners for all event types; or `null` + */ + ZeroClipboard.handlers = function() { + return _listeners.apply(this, _args(arguments)); + }; + /** + * Event emission receiver from the Flash object, forwarding to any registered JavaScript event listeners. + * + * @returns For the "copy" event, returns the Flash-friendly "clipData" object; otherwise `undefined`. + * @static + */ + ZeroClipboard.emit = function() { + return _emit.apply(this, _args(arguments)); + }; + /** + * Create and embed the Flash object. + * + * @returns The Flash object + * @static + */ + ZeroClipboard.create = function() { + return _create.apply(this, _args(arguments)); + }; + /** + * Self-destruct and clean up everything, including the embedded Flash object. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.destroy = function() { + return _destroy.apply(this, _args(arguments)); + }; + /** + * Set the pending data for clipboard injection. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.setData = function() { + return _setData.apply(this, _args(arguments)); + }; + /** + * Clear the pending data for clipboard injection. + * If no `format` is provided, all pending data formats will be cleared. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.clearData = function() { + return _clearData.apply(this, _args(arguments)); + }; + /** + * Get a copy of the pending data for clipboard injection. + * If no `format` is provided, a copy of ALL pending data formats will be returned. + * + * @returns `String` or `Object` + * @static + */ + ZeroClipboard.getData = function() { + return _getData.apply(this, _args(arguments)); + }; + /** + * Sets the current HTML object that the Flash object should overlay. This will put the global + * Flash object on top of the current element; depending on the setup, this may also set the + * pending clipboard text data as well as the Flash object's wrapping element's title attribute + * based on the underlying HTML element and ZeroClipboard configuration. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.focus = ZeroClipboard.activate = function() { + return _focus.apply(this, _args(arguments)); + }; + /** + * Un-overlays the Flash object. This will put the global Flash object off-screen; depending on + * the setup, this may also unset the Flash object's wrapping element's title attribute based on + * the underlying HTML element and ZeroClipboard configuration. + * + * @returns `undefined` + * @static + */ + ZeroClipboard.blur = ZeroClipboard.deactivate = function() { + return _blur.apply(this, _args(arguments)); + }; + /** + * Returns the currently focused/"activated" HTML element that the Flash object is wrapping. + * + * @returns `HTMLElement` or `null` + * @static + */ + ZeroClipboard.activeElement = function() { + return _activeElement.apply(this, _args(arguments)); + }; + /** + * Keep track of the ZeroClipboard client instance counter. + */ + var _clientIdCounter = 0; + /** + * Keep track of the state of the client instances. + * + * Entry structure: + * _clientMeta[client.id] = { + * instance: client, + * elements: [], + * handlers: {} + * }; + */ + var _clientMeta = {}; + /** + * Keep track of the ZeroClipboard clipped elements counter. + */ + var _elementIdCounter = 0; + /** + * Keep track of the state of the clipped element relationships to clients. + * + * Entry structure: + * _elementMeta[element.zcClippingId] = [client1.id, client2.id]; + */ + var _elementMeta = {}; + /** + * Keep track of the state of the mouse event handlers for clipped elements. + * + * Entry structure: + * _mouseHandlers[element.zcClippingId] = { + * mouseover: function(event) {}, + * mouseout: function(event) {}, + * mouseenter: function(event) {}, + * mouseleave: function(event) {}, + * mousemove: function(event) {} + * }; + */ + var _mouseHandlers = {}; + /** + * Extending the ZeroClipboard configuration defaults for the Client module. + */ + _extend(_globalConfig, { + autoActivate: true + }); + /** + * The real constructor for `ZeroClipboard` client instances. + * @private + */ + var _clientConstructor = function(elements) { + var client = this; + client.id = "" + _clientIdCounter++; + _clientMeta[client.id] = { + instance: client, + elements: [], + handlers: {} + }; + if (elements) { + client.clip(elements); + } + ZeroClipboard.on("*", function(event) { + return client.emit(event); + }); + ZeroClipboard.on("destroy", function() { + client.destroy(); + }); + ZeroClipboard.create(); + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.on`. + * @private + */ + var _clientOn = function(eventType, listener) { + var i, len, events, added = {}, meta = _clientMeta[this.id], handlers = meta && meta.handlers; + if (!meta) { + throw new Error("Attempted to add new listener(s) to a destroyed ZeroClipboard client instance"); + } + if (typeof eventType === "string" && eventType) { + events = eventType.toLowerCase().split(/\s+/); + } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") { + for (i in eventType) { + if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") { + this.on(i, eventType[i]); + } + } + } + if (events && events.length) { + for (i = 0, len = events.length; i < len; i++) { + eventType = events[i].replace(/^on/, ""); + added[eventType] = true; + if (!handlers[eventType]) { + handlers[eventType] = []; + } + handlers[eventType].push(listener); + } + if (added.ready && _flashState.ready) { + this.emit({ + type: "ready", + client: this + }); + } + if (added.error) { + var flashErrorTypes = [ "disabled", "outdated", "unavailable", "degraded", "deactivated", "overdue" ]; + for (i = 0, len = flashErrorTypes.length; i < len; i++) { + if (_flashState[flashErrorTypes[i]]) { + this.emit({ + type: "error", + name: "flash-" + flashErrorTypes[i], + client: this + }); + break; + } + } + if (_zcSwfVersion !== undefined && ZeroClipboard.version !== _zcSwfVersion) { + this.emit({ + type: "error", + name: "version-mismatch", + jsVersion: ZeroClipboard.version, + swfVersion: _zcSwfVersion + }); + } + } + } + return this; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.off`. + * @private + */ + var _clientOff = function(eventType, listener) { + var i, len, foundIndex, events, perEventHandlers, meta = _clientMeta[this.id], handlers = meta && meta.handlers; + if (!handlers) { + return this; + } + if (arguments.length === 0) { + events = _keys(handlers); + } else if (typeof eventType === "string" && eventType) { + events = eventType.split(/\s+/); + } else if (typeof eventType === "object" && eventType && typeof listener === "undefined") { + for (i in eventType) { + if (_hasOwn.call(eventType, i) && typeof i === "string" && i && typeof eventType[i] === "function") { + this.off(i, eventType[i]); + } + } + } + if (events && events.length) { + for (i = 0, len = events.length; i < len; i++) { + eventType = events[i].toLowerCase().replace(/^on/, ""); + perEventHandlers = handlers[eventType]; + if (perEventHandlers && perEventHandlers.length) { + if (listener) { + foundIndex = perEventHandlers.indexOf(listener); + while (foundIndex !== -1) { + perEventHandlers.splice(foundIndex, 1); + foundIndex = perEventHandlers.indexOf(listener, foundIndex); + } + } else { + perEventHandlers.length = 0; + } + } + } + } + return this; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.handlers`. + * @private + */ + var _clientListeners = function(eventType) { + var copy = null, handlers = _clientMeta[this.id] && _clientMeta[this.id].handlers; + if (handlers) { + if (typeof eventType === "string" && eventType) { + copy = handlers[eventType] ? handlers[eventType].slice(0) : []; + } else { + copy = _deepCopy(handlers); + } + } + return copy; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.emit`. + * @private + */ + var _clientEmit = function(event) { + if (_clientShouldEmit.call(this, event)) { + if (typeof event === "object" && event && typeof event.type === "string" && event.type) { + event = _extend({}, event); + } + var eventCopy = _extend({}, _createEvent(event), { + client: this + }); + _clientDispatchCallbacks.call(this, eventCopy); + } + return this; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.clip`. + * @private + */ + var _clientClip = function(elements) { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to clip element(s) to a destroyed ZeroClipboard client instance"); + } + elements = _prepClip(elements); + for (var i = 0; i < elements.length; i++) { + if (_hasOwn.call(elements, i) && elements[i] && elements[i].nodeType === 1) { + if (!elements[i].zcClippingId) { + elements[i].zcClippingId = "zcClippingId_" + _elementIdCounter++; + _elementMeta[elements[i].zcClippingId] = [ this.id ]; + if (_globalConfig.autoActivate === true) { + _addMouseHandlers(elements[i]); + } + } else if (_elementMeta[elements[i].zcClippingId].indexOf(this.id) === -1) { + _elementMeta[elements[i].zcClippingId].push(this.id); + } + var clippedElements = _clientMeta[this.id] && _clientMeta[this.id].elements; + if (clippedElements.indexOf(elements[i]) === -1) { + clippedElements.push(elements[i]); + } + } + } + return this; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.unclip`. + * @private + */ + var _clientUnclip = function(elements) { + var meta = _clientMeta[this.id]; + if (!meta) { + return this; + } + var clippedElements = meta.elements; + var arrayIndex; + if (typeof elements === "undefined") { + elements = clippedElements.slice(0); + } else { + elements = _prepClip(elements); + } + for (var i = elements.length; i--; ) { + if (_hasOwn.call(elements, i) && elements[i] && elements[i].nodeType === 1) { + arrayIndex = 0; + while ((arrayIndex = clippedElements.indexOf(elements[i], arrayIndex)) !== -1) { + clippedElements.splice(arrayIndex, 1); + } + var clientIds = _elementMeta[elements[i].zcClippingId]; + if (clientIds) { + arrayIndex = 0; + while ((arrayIndex = clientIds.indexOf(this.id, arrayIndex)) !== -1) { + clientIds.splice(arrayIndex, 1); + } + if (clientIds.length === 0) { + if (_globalConfig.autoActivate === true) { + _removeMouseHandlers(elements[i]); + } + delete elements[i].zcClippingId; + } + } + } + } + return this; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.elements`. + * @private + */ + var _clientElements = function() { + var meta = _clientMeta[this.id]; + return meta && meta.elements ? meta.elements.slice(0) : []; + }; + /** + * The underlying implementation of `ZeroClipboard.Client.prototype.destroy`. + * @private + */ + var _clientDestroy = function() { + if (!_clientMeta[this.id]) { + return; + } + this.unclip(); + this.off(); + delete _clientMeta[this.id]; + }; + /** + * Inspect an Event to see if the Client (`this`) should honor it for emission. + * @private + */ + var _clientShouldEmit = function(event) { + if (!(event && event.type)) { + return false; + } + if (event.client && event.client !== this) { + return false; + } + var meta = _clientMeta[this.id]; + var clippedEls = meta && meta.elements; + var hasClippedEls = !!clippedEls && clippedEls.length > 0; + var goodTarget = !event.target || hasClippedEls && clippedEls.indexOf(event.target) !== -1; + var goodRelTarget = event.relatedTarget && hasClippedEls && clippedEls.indexOf(event.relatedTarget) !== -1; + var goodClient = event.client && event.client === this; + if (!meta || !(goodTarget || goodRelTarget || goodClient)) { + return false; + } + return true; + }; + /** + * Handle the actual dispatching of events to a client instance. + * + * @returns `undefined` + * @private + */ + var _clientDispatchCallbacks = function(event) { + var meta = _clientMeta[this.id]; + if (!(typeof event === "object" && event && event.type && meta)) { + return; + } + var async = _shouldPerformAsync(event); + var wildcardTypeHandlers = meta && meta.handlers["*"] || []; + var specificTypeHandlers = meta && meta.handlers[event.type] || []; + var handlers = wildcardTypeHandlers.concat(specificTypeHandlers); + if (handlers && handlers.length) { + var i, len, func, context, eventCopy, originalContext = this; + for (i = 0, len = handlers.length; i < len; i++) { + func = handlers[i]; + context = originalContext; + if (typeof func === "string" && typeof _window[func] === "function") { + func = _window[func]; + } + if (typeof func === "object" && func && typeof func.handleEvent === "function") { + context = func; + func = func.handleEvent; + } + if (typeof func === "function") { + eventCopy = _extend({}, event); + _dispatchCallback(func, context, [ eventCopy ], async); + } + } + } + }; + /** + * Prepares the elements for clipping/unclipping. + * + * @returns An Array of elements. + * @private + */ + var _prepClip = function(elements) { + if (typeof elements === "string") { + elements = []; + } + return typeof elements.length !== "number" ? [ elements ] : elements; + }; + /** + * Add a `mouseover` handler function for a clipped element. + * + * @returns `undefined` + * @private + */ + var _addMouseHandlers = function(element) { + if (!(element && element.nodeType === 1)) { + return; + } + var _suppressMouseEvents = function(event) { + if (!(event || (event = _window.event))) { + return; + } + if (event._source !== "js") { + event.stopImmediatePropagation(); + event.preventDefault(); + } + delete event._source; + }; + var _elementMouseOver = function(event) { + if (!(event || (event = _window.event))) { + return; + } + _suppressMouseEvents(event); + ZeroClipboard.focus(element); + }; + element.addEventListener("mouseover", _elementMouseOver, false); + element.addEventListener("mouseout", _suppressMouseEvents, false); + element.addEventListener("mouseenter", _suppressMouseEvents, false); + element.addEventListener("mouseleave", _suppressMouseEvents, false); + element.addEventListener("mousemove", _suppressMouseEvents, false); + _mouseHandlers[element.zcClippingId] = { + mouseover: _elementMouseOver, + mouseout: _suppressMouseEvents, + mouseenter: _suppressMouseEvents, + mouseleave: _suppressMouseEvents, + mousemove: _suppressMouseEvents + }; + }; + /** + * Remove a `mouseover` handler function for a clipped element. + * + * @returns `undefined` + * @private + */ + var _removeMouseHandlers = function(element) { + if (!(element && element.nodeType === 1)) { + return; + } + var mouseHandlers = _mouseHandlers[element.zcClippingId]; + if (!(typeof mouseHandlers === "object" && mouseHandlers)) { + return; + } + var key, val, mouseEvents = [ "move", "leave", "enter", "out", "over" ]; + for (var i = 0, len = mouseEvents.length; i < len; i++) { + key = "mouse" + mouseEvents[i]; + val = mouseHandlers[key]; + if (typeof val === "function") { + element.removeEventListener(key, val, false); + } + } + delete _mouseHandlers[element.zcClippingId]; + }; + /** + * Creates a new ZeroClipboard client instance. + * Optionally, auto-`clip` an element or collection of elements. + * + * @constructor + */ + ZeroClipboard._createClient = function() { + _clientConstructor.apply(this, _args(arguments)); + }; + /** + * Register an event listener to the client. + * + * @returns `this` + */ + ZeroClipboard.prototype.on = function() { + return _clientOn.apply(this, _args(arguments)); + }; + /** + * Unregister an event handler from the client. + * If no `listener` function/object is provided, it will unregister all handlers for the provided `eventType`. + * If no `eventType` is provided, it will unregister all handlers for every event type. + * + * @returns `this` + */ + ZeroClipboard.prototype.off = function() { + return _clientOff.apply(this, _args(arguments)); + }; + /** + * Retrieve event listeners for an `eventType` from the client. + * If no `eventType` is provided, it will retrieve all listeners for every event type. + * + * @returns array of listeners for the `eventType`; if no `eventType`, then a map/hash object of listeners for all event types; or `null` + */ + ZeroClipboard.prototype.handlers = function() { + return _clientListeners.apply(this, _args(arguments)); + }; + /** + * Event emission receiver from the Flash object for this client's registered JavaScript event listeners. + * + * @returns For the "copy" event, returns the Flash-friendly "clipData" object; otherwise `undefined`. + */ + ZeroClipboard.prototype.emit = function() { + return _clientEmit.apply(this, _args(arguments)); + }; + /** + * Register clipboard actions for new element(s) to the client. + * + * @returns `this` + */ + ZeroClipboard.prototype.clip = function() { + return _clientClip.apply(this, _args(arguments)); + }; + /** + * Unregister the clipboard actions of previously registered element(s) on the page. + * If no elements are provided, ALL registered elements will be unregistered. + * + * @returns `this` + */ + ZeroClipboard.prototype.unclip = function() { + return _clientUnclip.apply(this, _args(arguments)); + }; + /** + * Get all of the elements to which this client is clipped. + * + * @returns array of clipped elements + */ + ZeroClipboard.prototype.elements = function() { + return _clientElements.apply(this, _args(arguments)); + }; + /** + * Self-destruct and clean up everything for a single client. + * This will NOT destroy the embedded Flash object. + * + * @returns `undefined` + */ + ZeroClipboard.prototype.destroy = function() { + return _clientDestroy.apply(this, _args(arguments)); + }; + /** + * Stores the pending plain text to inject into the clipboard. + * + * @returns `this` + */ + ZeroClipboard.prototype.setText = function(text) { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance"); + } + ZeroClipboard.setData("text/plain", text); + return this; + }; + /** + * Stores the pending HTML text to inject into the clipboard. + * + * @returns `this` + */ + ZeroClipboard.prototype.setHtml = function(html) { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance"); + } + ZeroClipboard.setData("text/html", html); + return this; + }; + /** + * Stores the pending rich text (RTF) to inject into the clipboard. + * + * @returns `this` + */ + ZeroClipboard.prototype.setRichText = function(richText) { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance"); + } + ZeroClipboard.setData("application/rtf", richText); + return this; + }; + /** + * Stores the pending data to inject into the clipboard. + * + * @returns `this` + */ + ZeroClipboard.prototype.setData = function() { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance"); + } + ZeroClipboard.setData.apply(this, _args(arguments)); + return this; + }; + /** + * Clears the pending data to inject into the clipboard. + * If no `format` is provided, all pending data formats will be cleared. + * + * @returns `this` + */ + ZeroClipboard.prototype.clearData = function() { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to clear pending clipboard data from a destroyed ZeroClipboard client instance"); + } + ZeroClipboard.clearData.apply(this, _args(arguments)); + return this; + }; + /** + * Gets a copy of the pending data to inject into the clipboard. + * If no `format` is provided, a copy of ALL pending data formats will be returned. + * + * @returns `String` or `Object` + */ + ZeroClipboard.prototype.getData = function() { + if (!_clientMeta[this.id]) { + throw new Error("Attempted to get pending clipboard data from a destroyed ZeroClipboard client instance"); + } + return ZeroClipboard.getData.apply(this, _args(arguments)); + }; + if (typeof define === "function" && define.amd) { + define(function() { + return ZeroClipboard; + }); + } else if (typeof module === "object" && module && typeof module.exports === "object" && module.exports) { + module.exports = ZeroClipboard; + } else { + window.ZeroClipboard = ZeroClipboard; + } +})(function() { + return this || window; +}()); \ No newline at end of file diff --git a/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.min.js b/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.min.js new file mode 100644 index 0000000000..61cb16dd20 --- /dev/null +++ b/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.min.js @@ -0,0 +1,10 @@ +/*! + * ZeroClipboard + * The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface. + * Copyright (c) 2009-2014 Jon Rohan, James M. Greene + * Licensed MIT + * http://zeroclipboard.org/ + * v2.2.0-beta.3 + */ +!function(a,b){"use strict";var c,d,e,f=a,g=f.document,h=f.navigator,i=f.setTimeout,j=f.clearTimeout,k=f.setInterval,l=f.clearInterval,m=f.getComputedStyle,n=f.encodeURIComponent,o=f.ActiveXObject,p=f.Error,q=f.Number.parseInt||f.parseInt,r=f.Number.parseFloat||f.parseFloat,s=f.Number.isNaN||f.isNaN,t=f.Date.now,u=f.Object.keys,v=f.Object.defineProperty,w=f.Object.prototype.hasOwnProperty,x=f.Array.prototype.slice,y=function(){var a=function(a){return a};if("function"==typeof f.wrap&&"function"==typeof f.unwrap)try{var b=g.createElement("div"),c=f.unwrap(b);1===b.nodeType&&c&&1===c.nodeType&&(a=f.unwrap)}catch(d){}return a}(),z=function(a){return x.call(a,0)},A=function(){var a,c,d,e,f,g,h=z(arguments),i=h[0]||{};for(a=1,c=h.length;c>a;a++)if(null!=(d=h[a]))for(e in d)w.call(d,e)&&(f=i[e],g=d[e],i!==g&&g!==b&&(i[e]=g));return i},B=function(a){var b,c,d,e;if("object"!=typeof a||null==a||"number"==typeof a.nodeType)b=a;else if("number"==typeof a.length)for(b=[],c=0,d=a.length;d>c;c++)w.call(a,c)&&(b[c]=B(a[c]));else{b={};for(e in a)w.call(a,e)&&(b[e]=B(a[e]))}return b},C=function(a,b){for(var c={},d=0,e=b.length;e>d;d++)b[d]in a&&(c[b[d]]=a[b[d]]);return c},D=function(a,b){var c={};for(var d in a)-1===b.indexOf(d)&&(c[d]=a[d]);return c},E=function(a){if(a)for(var b in a)w.call(a,b)&&delete a[b];return a},F=function(a,b){if(a&&1===a.nodeType&&a.ownerDocument&&b&&(1===b.nodeType&&b.ownerDocument&&b.ownerDocument===a.ownerDocument||9===b.nodeType&&!b.ownerDocument&&b===a.ownerDocument))do{if(a===b)return!0;a=a.parentNode}while(a);return!1},G=function(a){var b;return"string"==typeof a&&a&&(b=a.split("#")[0].split("?")[0],b=a.slice(0,a.lastIndexOf("/")+1)),b},H=function(a){var b,c;return"string"==typeof a&&a&&(c=a.match(/^(?:|[^:@]*@|.+\)@(?=http[s]?|file)|.+?\s+(?: at |@)(?:[^:\(]+ )*[\(]?)((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/),c&&c[1]?b=c[1]:(c=a.match(/\)@((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/),c&&c[1]&&(b=c[1]))),b},I=function(){var a,b;try{throw new p}catch(c){b=c}return b&&(a=b.sourceURL||b.fileName||H(b.stack)),a},J=function(){var a,c,d;if(g.currentScript&&(a=g.currentScript.src))return a;if(c=g.getElementsByTagName("script"),1===c.length)return c[0].src||b;if("readyState"in c[0])for(d=c.length;d--;)if("interactive"===c[d].readyState&&(a=c[d].src))return a;return"loading"===g.readyState&&(a=c[c.length-1].src)?a:(a=I())?a:b},K=function(){var a,c,d,e=g.getElementsByTagName("script");for(a=e.length;a--;){if(!(d=e[a].src)){c=null;break}if(d=G(d),null==c)c=d;else if(c!==d){c=null;break}}return c||b},L=function(){var a=G(J())||K()||"";return a+"ZeroClipboard.swf"},M={bridge:null,version:"0.0.0",pluginType:"unknown",disabled:null,outdated:null,unavailable:null,degraded:null,deactivated:null,overdue:null,ready:null},N="11.0.0",O={},P={},Q=null,R=0,S=0,T={ready:"Flash communication is established",error:{"flash-disabled":"Flash is disabled or not installed","flash-outdated":"Flash is too outdated to support ZeroClipboard","flash-unavailable":"Flash is unable to communicate bidirectionally with JavaScript","flash-degraded":"Flash is unable to preserve data fidelity when communicating with JavaScript","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.","flash-overdue":"Flash communication was established but NOT within the acceptable time limit","version-mismatch":"ZeroClipboard JS version number does not match ZeroClipboard SWF version number","clipboard-error":"At least one error was thrown while ZeroClipboard was attempting to inject your data into the clipboard","config-mismatch":"ZeroClipboard configuration does not match Flash's reality","swf-not-found":"The ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity"}},U={swfPath:L(),trustedDomains:a.location.host?[a.location.host]:[],cacheBust:!0,forceEnhancedClipboard:!1,flashLoadTimeout:3e4,autoActivate:!0,bubbleEvents:!0,containerId:"global-zeroclipboard-html-bridge",containerClass:"global-zeroclipboard-container",swfObjectId:"global-zeroclipboard-flash-bridge",hoverClass:"zeroclipboard-is-hover",activeClass:"zeroclipboard-is-active",forceHandCursor:!1,title:null,zIndex:999999999},V=function(a){if("object"==typeof a&&null!==a)for(var b in a)if(w.call(a,b))if(/^(?:forceHandCursor|title|zIndex|bubbleEvents)$/.test(b))U[b]=a[b];else if(null==M.bridge)if("containerId"===b||"swfObjectId"===b){if(!ib(a[b]))throw new Error("The specified `"+b+"` value is not valid as an HTML4 Element ID");U[b]=a[b]}else U[b]=a[b];{if("string"!=typeof a||!a)return B(U);if(w.call(U,a))return U[a]}},W=function(){return{browser:C(h,["userAgent","platform","appName"]),flash:D(M,["bridge"]),zeroclipboard:{version:Ob.version,config:Ob.config()}}},X=function(){return!!(M.disabled||M.outdated||M.unavailable||M.degraded||M.deactivated)},Y=function(a,d){var e,f,g,h={};if("string"==typeof a&&a)g=a.toLowerCase().split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof d)for(e in a)w.call(a,e)&&"string"==typeof e&&e&&"function"==typeof a[e]&&Ob.on(e,a[e]);if(g&&g.length){for(e=0,f=g.length;f>e;e++)a=g[e].replace(/^on/,""),h[a]=!0,O[a]||(O[a]=[]),O[a].push(d);if(h.ready&&M.ready&&Ob.emit({type:"ready"}),h.error){var i=["disabled","outdated","unavailable","degraded","deactivated","overdue"];for(e=0,f=i.length;f>e;e++)if(M[i[e]]===!0){Ob.emit({type:"error",name:"flash-"+i[e]});break}c!==b&&Ob.version!==c&&Ob.emit({type:"error",name:"version-mismatch",jsVersion:Ob.version,swfVersion:c})}}return Ob},Z=function(a,b){var c,d,e,f,g;if(0===arguments.length)f=u(O);else if("string"==typeof a&&a)f=a.split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof b)for(c in a)w.call(a,c)&&"string"==typeof c&&c&&"function"==typeof a[c]&&Ob.off(c,a[c]);if(f&&f.length)for(c=0,d=f.length;d>c;c++)if(a=f[c].toLowerCase().replace(/^on/,""),g=O[a],g&&g.length)if(b)for(e=g.indexOf(b);-1!==e;)g.splice(e,1),e=g.indexOf(b,e);else g.length=0;return Ob},$=function(a){var b;return b="string"==typeof a&&a?B(O[a])||null:B(O)},_=function(a){var b,c,d;return a=jb(a),a&&!pb(a)?"ready"===a.type&&M.overdue===!0?Ob.emit({type:"error",name:"flash-overdue"}):(b=A({},a),ob.call(this,b),"copy"===a.type&&(d=xb(P),c=d.data,Q=d.formatMap),c):void 0},ab=function(){if("boolean"!=typeof M.ready&&(M.ready=!1),!Ob.isFlashUnusable()&&null===M.bridge){var a=U.flashLoadTimeout;"number"==typeof a&&a>=0&&(R=i(function(){"boolean"!=typeof M.deactivated&&(M.deactivated=!0),M.deactivated===!0&&Ob.emit({type:"error",name:"flash-deactivated"})},a)),M.overdue=!1,vb()}},bb=function(){Ob.clearData(),Ob.blur(),Ob.emit("destroy"),wb(),Ob.off()},cb=function(a,b){var c;if("object"==typeof a&&a&&"undefined"==typeof b)c=a,Ob.clearData();else{if("string"!=typeof a||!a)return;c={},c[a]=b}for(var d in c)"string"==typeof d&&d&&w.call(c,d)&&"string"==typeof c[d]&&c[d]&&(P[d]=c[d])},db=function(a){"undefined"==typeof a?(E(P),Q=null):"string"==typeof a&&w.call(P,a)&&delete P[a]},eb=function(a){return"undefined"==typeof a?B(P):"string"==typeof a&&w.call(P,a)?P[a]:void 0},fb=function(a){if(a&&1===a.nodeType){d&&(Fb(d,U.activeClass),d!==a&&Fb(d,U.hoverClass)),d=a,Eb(a,U.hoverClass);var b=a.getAttribute("title")||U.title;if("string"==typeof b&&b){var c=ub(M.bridge);c&&c.setAttribute("title",b)}var e=U.forceHandCursor===!0||"pointer"===Gb(a,"cursor");Lb(e),Kb()}},gb=function(){var a=ub(M.bridge);a&&(a.removeAttribute("title"),a.style.left="0px",a.style.top="-9999px",a.style.width="1px",a.style.top="1px"),d&&(Fb(d,U.hoverClass),Fb(d,U.activeClass),d=null)},hb=function(){return d||null},ib=function(a){return"string"==typeof a&&a&&/^[A-Za-z][A-Za-z0-9_:\-\.]*$/.test(a)},jb=function(a){var b;if("string"==typeof a&&a?(b=a,a={}):"object"==typeof a&&a&&"string"==typeof a.type&&a.type&&(b=a.type),b){b=b.toLowerCase(),!a.target&&(/^(copy|aftercopy|_click)$/.test(b)||"error"===b&&"clipboard-error"===a.name)&&(a.target=e),A(a,{type:b,target:a.target||d||null,relatedTarget:a.relatedTarget||null,currentTarget:M&&M.bridge||null,timeStamp:a.timeStamp||t()||null});var c=T[a.type];return"error"===a.type&&a.name&&c&&(c=c[a.name]),c&&(a.message=c),"ready"===a.type&&A(a,{target:null,version:M.version}),"error"===a.type&&(/^flash-(disabled|outdated|unavailable|degraded|deactivated|overdue)$/.test(a.name)&&A(a,{target:null,minimumVersion:N}),/^flash-(outdated|unavailable|degraded|deactivated|overdue)$/.test(a.name)&&A(a,{version:M.version})),"copy"===a.type&&(a.clipboardData={setData:Ob.setData,clearData:Ob.clearData}),"aftercopy"===a.type&&(a=yb(a,Q)),a.target&&!a.relatedTarget&&(a.relatedTarget=kb(a.target)),lb(a)}},kb=function(a){var b=a&&a.getAttribute&&a.getAttribute("data-clipboard-target");return b?g.getElementById(b):null},lb=function(a){if(a&&/^_(?:click|mouse(?:over|out|down|up|move))$/.test(a.type)){var c=a.target,d="_mouseover"===a.type&&a.relatedTarget?a.relatedTarget:b,e="_mouseout"===a.type&&a.relatedTarget?a.relatedTarget:b,h=Hb(c),i=f.screenLeft||f.screenX||0,j=f.screenTop||f.screenY||0,k=g.body.scrollLeft+g.documentElement.scrollLeft,l=g.body.scrollTop+g.documentElement.scrollTop,m=h.left+("number"==typeof a._stageX?a._stageX:0),n=h.top+("number"==typeof a._stageY?a._stageY:0),o=m-k,p=n-l,q=i+o,r=j+p,s="number"==typeof a.movementX?a.movementX:0,t="number"==typeof a.movementY?a.movementY:0;delete a._stageX,delete a._stageY,A(a,{srcElement:c,fromElement:d,toElement:e,screenX:q,screenY:r,pageX:m,pageY:n,clientX:o,clientY:p,x:o,y:p,movementX:s,movementY:t,offsetX:0,offsetY:0,layerX:0,layerY:0})}return a},mb=function(a){var b=a&&"string"==typeof a.type&&a.type||"";return!/^(?:(?:before)?copy|destroy)$/.test(b)},nb=function(a,b,c,d){d?i(function(){a.apply(b,c)},0):a.apply(b,c)},ob=function(a){if("object"==typeof a&&a&&a.type){var b=mb(a),c=O["*"]||[],d=O[a.type]||[],e=c.concat(d);if(e&&e.length){var g,h,i,j,k,l=this;for(g=0,h=e.length;h>g;g++)i=e[g],j=l,"string"==typeof i&&"function"==typeof f[i]&&(i=f[i]),"object"==typeof i&&i&&"function"==typeof i.handleEvent&&(j=i,i=i.handleEvent),"function"==typeof i&&(k=A({},a),nb(i,j,[k],b))}return this}},pb=function(a){var b=a.target||d||null,f="swf"===a._source;delete a._source;var g=["flash-disabled","flash-outdated","flash-unavailable","flash-degraded","flash-deactivated","flash-overdue"];switch(a.type){case"error":-1!==g.indexOf(a.name)?A(M,{disabled:"flash-disabled"===a.name,outdated:"flash-outdated"===a.name,unavailable:"flash-unavailable"===a.name,degraded:"flash-degraded"===a.name,deactivated:"flash-deactivated"===a.name,overdue:"flash-overdue"===a.name,ready:!1}):"version-mismatch"===a.name&&(c=a.swfVersion,A(M,{disabled:!1,outdated:!1,unavailable:!1,degraded:!1,deactivated:!1,overdue:!1,ready:!1})),Jb();break;case"ready":c=a.swfVersion;var h=M.deactivated===!0;A(M,{disabled:!1,outdated:!1,unavailable:!1,degraded:!1,deactivated:!1,overdue:h,ready:!h}),Jb();break;case"beforecopy":e=b;break;case"copy":var i,j,k=a.relatedTarget;!P["text/html"]&&!P["text/plain"]&&k&&(j=k.value||k.outerHTML||k.innerHTML)&&(i=k.value||k.textContent||k.innerText)?(a.clipboardData.clearData(),a.clipboardData.setData("text/plain",i),j!==i&&a.clipboardData.setData("text/html",j)):!P["text/plain"]&&a.target&&(i=a.target.getAttribute("data-clipboard-text"))&&(a.clipboardData.clearData(),a.clipboardData.setData("text/plain",i));break;case"aftercopy":qb(a),Ob.clearData(),b&&b!==Db()&&b.focus&&b.focus();break;case"_mouseover":Ob.focus(b),U.bubbleEvents===!0&&f&&(b&&b!==a.relatedTarget&&!F(a.relatedTarget,b)&&rb(A({},a,{type:"mouseenter",bubbles:!1,cancelable:!1})),rb(A({},a,{type:"mouseover"})));break;case"_mouseout":Ob.blur(),U.bubbleEvents===!0&&f&&(b&&b!==a.relatedTarget&&!F(a.relatedTarget,b)&&rb(A({},a,{type:"mouseleave",bubbles:!1,cancelable:!1})),rb(A({},a,{type:"mouseout"})));break;case"_mousedown":Eb(b,U.activeClass),U.bubbleEvents===!0&&f&&rb(A({},a,{type:a.type.slice(1)}));break;case"_mouseup":Fb(b,U.activeClass),U.bubbleEvents===!0&&f&&rb(A({},a,{type:a.type.slice(1)}));break;case"_click":e=null,U.bubbleEvents===!0&&f&&rb(A({},a,{type:a.type.slice(1)}));break;case"_mousemove":U.bubbleEvents===!0&&f&&rb(A({},a,{type:a.type.slice(1)}))}return/^_(?:click|mouse(?:over|out|down|up|move))$/.test(a.type)?!0:void 0},qb=function(a){if(a.errors&&a.errors.length>0){var b=B(a);A(b,{type:"error",name:"clipboard-error"}),delete b.success,i(function(){Ob.emit(b)},0)}},rb=function(a){if(a&&"string"==typeof a.type&&a){var b,c=a.target||null,d=c&&c.ownerDocument||g,e={view:d.defaultView||f,canBubble:!0,cancelable:!0,detail:"click"===a.type?1:0,button:"number"==typeof a.which?a.which-1:"number"==typeof a.button?a.button:d.createEvent?0:1},h=A(e,a);c&&d.createEvent&&c.dispatchEvent&&(h=[h.type,h.canBubble,h.cancelable,h.view,h.detail,h.screenX,h.screenY,h.clientX,h.clientY,h.ctrlKey,h.altKey,h.shiftKey,h.metaKey,h.button,h.relatedTarget],b=d.createEvent("MouseEvents"),b.initMouseEvent&&(b.initMouseEvent.apply(b,h),b._source="js",c.dispatchEvent(b)))}},sb=function(){var a=U.flashLoadTimeout;if("number"==typeof a&&a>=0){var b=Math.min(1e3,a/10),c=U.swfObjectId+"_fallbackContent";S=k(function(){var a=g.getElementById(c);Ib(a)&&(Jb(),M.deactivated=null,Ob.emit({type:"error",name:"swf-not-found"}))},b)}},tb=function(){var a=g.createElement("div");return a.id=U.containerId,a.className=U.containerClass,a.style.position="absolute",a.style.left="0px",a.style.top="-9999px",a.style.width="1px",a.style.height="1px",a.style.zIndex=""+Mb(U.zIndex),a},ub=function(a){for(var b=a&&a.parentNode;b&&"OBJECT"===b.nodeName&&b.parentNode;)b=b.parentNode;return b||null},vb=function(){var a,b=M.bridge,c=ub(b);if(!b){var d=Cb(f.location.host,U),e="never"===d?"none":"all",h=Ab(A({jsVersion:Ob.version},U)),i=U.swfPath+zb(U.swfPath,U);c=tb();var j=g.createElement("div");c.appendChild(j),g.body.appendChild(c);var k=g.createElement("div"),l="activex"===M.pluginType;k.innerHTML='"+(l?'':"")+'
 
',b=k.firstChild,k=null,y(b).ZeroClipboard=Ob,c.replaceChild(b,j),sb()}return b||(b=g[U.swfObjectId],b&&(a=b.length)&&(b=b[a-1]),!b&&c&&(b=c.firstChild)),M.bridge=b||null,b},wb=function(){var a=M.bridge;if(a){var d=ub(a);d&&("activex"===M.pluginType&&"readyState"in a?(a.style.display="none",function e(){if(4===a.readyState){for(var b in a)"function"==typeof a[b]&&(a[b]=null);a.parentNode&&a.parentNode.removeChild(a),d.parentNode&&d.parentNode.removeChild(d)}else i(e,10)}()):(a.parentNode&&a.parentNode.removeChild(a),d.parentNode&&d.parentNode.removeChild(d))),Jb(),M.ready=null,M.bridge=null,M.deactivated=null,c=b}},xb=function(a){var b={},c={};if("object"==typeof a&&a){for(var d in a)if(d&&w.call(a,d)&&"string"==typeof a[d]&&a[d])switch(d.toLowerCase()){case"text/plain":case"text":case"air:text":case"flash:text":b.text=a[d],c.text=d;break;case"text/html":case"html":case"air:html":case"flash:html":b.html=a[d],c.html=d;break;case"application/rtf":case"text/rtf":case"rtf":case"richtext":case"air:rtf":case"flash:rtf":b.rtf=a[d],c.rtf=d}return{data:b,formatMap:c}}},yb=function(a,b){if("object"!=typeof a||!a||"object"!=typeof b||!b)return a;var c={};for(var d in a)if(w.call(a,d))if("errors"===d){c[d]=a[d]?a[d].slice():[];for(var e=0,f=c[d].length;f>e;e++)c[d][e].format=b[c[d][e].format]}else if("success"!==d&&"data"!==d)c[d]=a[d];else{c[d]={};var g=a[d];for(var h in g)h&&w.call(g,h)&&w.call(b,h)&&(c[d][b[h]]=g[h])}return c},zb=function(a,b){var c=null==b||b&&b.cacheBust===!0;return c?(-1===a.indexOf("?")?"?":"&")+"noCache="+t():""},Ab=function(a){var b,c,d,e,g="",h=[];if(a.trustedDomains&&("string"==typeof a.trustedDomains?e=[a.trustedDomains]:"object"==typeof a.trustedDomains&&"length"in a.trustedDomains&&(e=a.trustedDomains)),e&&e.length)for(b=0,c=e.length;c>b;b++)if(w.call(e,b)&&e[b]&&"string"==typeof e[b]){if(d=Bb(e[b]),!d)continue;if("*"===d){h.length=0,h.push(d);break}h.push.apply(h,[d,"//"+d,f.location.protocol+"//"+d])}return h.length&&(g+="trustedOrigins="+n(h.join(","))),a.forceEnhancedClipboard===!0&&(g+=(g?"&":"")+"forceEnhancedClipboard=true"),"string"==typeof a.swfObjectId&&a.swfObjectId&&(g+=(g?"&":"")+"swfObjectId="+n(a.swfObjectId)),"string"==typeof a.jsVersion&&a.jsVersion&&(g+=(g?"&":"")+"jsVersion="+n(a.jsVersion)),g},Bb=function(a){if(null==a||""===a)return null;if(a=a.replace(/^\s+|\s+$/g,""),""===a)return null;var b=a.indexOf("//");a=-1===b?a:a.slice(b+2);var c=a.indexOf("/");return a=-1===c?a:-1===b||0===c?null:a.slice(0,c),a&&".swf"===a.slice(-4).toLowerCase()?null:a||null},Cb=function(){var a=function(a){var b,c,d,e=[];if("string"==typeof a&&(a=[a]),"object"!=typeof a||!a||"number"!=typeof a.length)return e;for(b=0,c=a.length;c>b;b++)if(w.call(a,b)&&(d=Bb(a[b]))){if("*"===d){e.length=0,e.push("*");break}-1===e.indexOf(d)&&e.push(d)}return e};return function(b,c){var d=Bb(c.swfPath);null===d&&(d=b);var e=a(c.trustedDomains),f=e.length;if(f>0){if(1===f&&"*"===e[0])return"always";if(-1!==e.indexOf(b))return 1===f&&b===d?"sameDomain":"always"}return"never"}}(),Db=function(){try{return g.activeElement}catch(a){return null}},Eb=function(a,b){if(!a||1!==a.nodeType)return a;if(a.classList)return a.classList.contains(b)||a.classList.add(b),a;if(b&&"string"==typeof b){var c=(b||"").split(/\s+/);if(1===a.nodeType)if(a.className){for(var d=" "+a.className+" ",e=a.className,f=0,g=c.length;g>f;f++)d.indexOf(" "+c[f]+" ")<0&&(e+=" "+c[f]);a.className=e.replace(/^\s+|\s+$/g,"")}else a.className=b}return a},Fb=function(a,b){if(!a||1!==a.nodeType)return a;if(a.classList)return a.classList.contains(b)&&a.classList.remove(b),a;if("string"==typeof b&&b){var c=b.split(/\s+/);if(1===a.nodeType&&a.className){for(var d=(" "+a.className+" ").replace(/[\n\t]/g," "),e=0,f=c.length;f>e;e++)d=d.replace(" "+c[e]+" "," ");a.className=d.replace(/^\s+|\s+$/g,"")}}return a},Gb=function(a,b){var c=m(a,null).getPropertyValue(b);return"cursor"!==b||c&&"auto"!==c||"A"!==a.nodeName?c:"pointer"},Hb=function(a){var b={left:0,top:0,width:0,height:0};if(a.getBoundingClientRect){var c=a.getBoundingClientRect(),d=f.pageXOffset,e=f.pageYOffset,h=g.documentElement.clientLeft||0,i=g.documentElement.clientTop||0,j=0,k=0;if("relative"===Gb(g.body,"position")){var l=g.body.getBoundingClientRect(),m=g.documentElement.getBoundingClientRect();j=l.left-m.left||0,k=l.top-m.top||0}b.left=c.left+d-h-j,b.top=c.top+e-i-k,b.width="width"in c?c.width:c.right-c.left,b.height="height"in c?c.height:c.bottom-c.top}return b},Ib=function(a){if(!a)return!1;var b=m(a,null),c=r(b.height)>0,d=r(b.width)>0,e=r(b.top)>=0,f=r(b.left)>=0,g=c&&d&&e&&f,h=g?null:Hb(a),i="none"!==b.display&&"collapse"!==b.visibility&&(g||!!h&&(c||h.height>0)&&(d||h.width>0)&&(e||h.top>=0)&&(f||h.left>=0));return i},Jb=function(){j(R),R=0,l(S),S=0},Kb=function(){var a;if(d&&(a=ub(M.bridge))){var b=Hb(d);A(a.style,{width:b.width+"px",height:b.height+"px",top:b.top+"px",left:b.left+"px",zIndex:""+Mb(U.zIndex)})}},Lb=function(a){M.ready===!0&&(M.bridge&&"function"==typeof M.bridge.setHandCursor?M.bridge.setHandCursor(a):M.ready=!1)},Mb=function(a){if(/^(?:auto|inherit)$/.test(a))return a;var b;return"number"!=typeof a||s(a)?"string"==typeof a&&(b=Mb(q(a,10))):b=a,"number"==typeof b?b:"auto"},Nb=function(a){function b(a){var b=a.match(/[\d]+/g);return b.length=3,b.join(".")}function c(a){return!!a&&(a=a.toLowerCase())&&(/^(pepflashplayer\.dll|libpepflashplayer\.so|pepperflashplayer\.plugin)$/.test(a)||"chrome.plugin"===a.slice(-13))}function d(a){a&&(i=!0,a.version&&(l=b(a.version)),!l&&a.description&&(l=b(a.description)),a.filename&&(k=c(a.filename)))}var e,f,g,i=!1,j=!1,k=!1,l="";if(h.plugins&&h.plugins.length)e=h.plugins["Shockwave Flash"],d(e),h.plugins["Shockwave Flash 2.0"]&&(i=!0,l="2.0.0.11");else if(h.mimeTypes&&h.mimeTypes.length)g=h.mimeTypes["application/x-shockwave-flash"],e=g&&g.enabledPlugin,d(e);else if("undefined"!=typeof a){j=!0;try{f=new a("ShockwaveFlash.ShockwaveFlash.7"),i=!0,l=b(f.GetVariable("$version"))}catch(m){try{f=new a("ShockwaveFlash.ShockwaveFlash.6"),i=!0,l="6.0.21"}catch(n){try{f=new a("ShockwaveFlash.ShockwaveFlash"),i=!0,l=b(f.GetVariable("$version"))}catch(o){j=!1}}}}M.disabled=i!==!0,M.outdated=l&&r(l)e;e++)a=g[e].replace(/^on/,""),h[a]=!0,j[a]||(j[a]=[]),j[a].push(d);if(h.ready&&M.ready&&this.emit({type:"ready",client:this}),h.error){var k=["disabled","outdated","unavailable","degraded","deactivated","overdue"];for(e=0,f=k.length;f>e;e++)if(M[k[e]]){this.emit({type:"error",name:"flash-"+k[e],client:this});break}c!==b&&Ob.version!==c&&this.emit({type:"error",name:"version-mismatch",jsVersion:Ob.version,swfVersion:c})}}return this},Wb=function(a,b){var c,d,e,f,g,h=Qb[this.id],i=h&&h.handlers;if(!i)return this;if(0===arguments.length)f=u(i);else if("string"==typeof a&&a)f=a.split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof b)for(c in a)w.call(a,c)&&"string"==typeof c&&c&&"function"==typeof a[c]&&this.off(c,a[c]);if(f&&f.length)for(c=0,d=f.length;d>c;c++)if(a=f[c].toLowerCase().replace(/^on/,""),g=i[a],g&&g.length)if(b)for(e=g.indexOf(b);-1!==e;)g.splice(e,1),e=g.indexOf(b,e);else g.length=0;return this},Xb=function(a){var b=null,c=Qb[this.id]&&Qb[this.id].handlers;return c&&(b="string"==typeof a&&a?c[a]?c[a].slice(0):[]:B(c)),b},Yb=function(a){if(bc.call(this,a)){"object"==typeof a&&a&&"string"==typeof a.type&&a.type&&(a=A({},a));var b=A({},jb(a),{client:this});cc.call(this,b)}return this},Zb=function(a){if(!Qb[this.id])throw new Error("Attempted to clip element(s) to a destroyed ZeroClipboard client instance");a=dc(a);for(var b=0;b0,e=!a.target||d&&-1!==c.indexOf(a.target),f=a.relatedTarget&&d&&-1!==c.indexOf(a.relatedTarget),g=a.client&&a.client===this;return b&&(e||f||g)?!0:!1},cc=function(a){var b=Qb[this.id];if("object"==typeof a&&a&&a.type&&b){var c=mb(a),d=b&&b.handlers["*"]||[],e=b&&b.handlers[a.type]||[],g=d.concat(e);if(g&&g.length){var h,i,j,k,l,m=this;for(h=0,i=g.length;i>h;h++)j=g[h],k=m,"string"==typeof j&&"function"==typeof f[j]&&(j=f[j]),"object"==typeof j&&j&&"function"==typeof j.handleEvent&&(k=j,j=j.handleEvent),"function"==typeof j&&(l=A({},a),nb(j,k,[l],c))}}},dc=function(a){return"string"==typeof a&&(a=[]),"number"!=typeof a.length?[a]:a},ec=function(a){if(a&&1===a.nodeType){var b=function(a){(a||(a=f.event))&&("js"!==a._source&&(a.stopImmediatePropagation(),a.preventDefault()),delete a._source)},c=function(c){(c||(c=f.event))&&(b(c),Ob.focus(a))};a.addEventListener("mouseover",c,!1),a.addEventListener("mouseout",b,!1),a.addEventListener("mouseenter",b,!1),a.addEventListener("mouseleave",b,!1),a.addEventListener("mousemove",b,!1),Tb[a.zcClippingId]={mouseover:c,mouseout:b,mouseenter:b,mouseleave:b,mousemove:b}}},fc=function(a){if(a&&1===a.nodeType){var b=Tb[a.zcClippingId];if("object"==typeof b&&b){for(var c,d,e=["move","leave","enter","out","over"],f=0,g=e.length;g>f;f++)c="mouse"+e[f],d=b[c],"function"==typeof d&&a.removeEventListener(c,d,!1);delete Tb[a.zcClippingId]}}};Ob._createClient=function(){Ub.apply(this,z(arguments))},Ob.prototype.on=function(){return Vb.apply(this,z(arguments))},Ob.prototype.off=function(){return Wb.apply(this,z(arguments))},Ob.prototype.handlers=function(){return Xb.apply(this,z(arguments))},Ob.prototype.emit=function(){return Yb.apply(this,z(arguments))},Ob.prototype.clip=function(){return Zb.apply(this,z(arguments))},Ob.prototype.unclip=function(){return $b.apply(this,z(arguments))},Ob.prototype.elements=function(){return _b.apply(this,z(arguments))},Ob.prototype.destroy=function(){return ac.apply(this,z(arguments))},Ob.prototype.setText=function(a){if(!Qb[this.id])throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");return Ob.setData("text/plain",a),this},Ob.prototype.setHtml=function(a){if(!Qb[this.id])throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");return Ob.setData("text/html",a),this},Ob.prototype.setRichText=function(a){if(!Qb[this.id])throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");return Ob.setData("application/rtf",a),this},Ob.prototype.setData=function(){if(!Qb[this.id])throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");return Ob.setData.apply(this,z(arguments)),this},Ob.prototype.clearData=function(){if(!Qb[this.id])throw new Error("Attempted to clear pending clipboard data from a destroyed ZeroClipboard client instance");return Ob.clearData.apply(this,z(arguments)),this},Ob.prototype.getData=function(){if(!Qb[this.id])throw new Error("Attempted to get pending clipboard data from a destroyed ZeroClipboard client instance");return Ob.getData.apply(this,z(arguments))},"function"==typeof define&&define.amd?define(function(){return Ob}):"object"==typeof module&&module&&"object"==typeof module.exports&&module.exports?module.exports=Ob:a.ZeroClipboard=Ob}(function(){return this||window}()); +//# sourceMappingURL=ZeroClipboard.min.map \ No newline at end of file diff --git a/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.min.map b/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.min.map new file mode 100644 index 0000000000..ddc6eee376 --- /dev/null +++ b/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.min.map @@ -0,0 +1 @@ +{"version":3,"file":"ZeroClipboard.min.js","sources":["ZeroClipboard.js"],"names":["window","undefined","_zcSwfVersion","_currentElement","_copyTarget","_window","_document","document","_navigator","navigator","_setTimeout","setTimeout","_clearTimeout","clearTimeout","_setInterval","setInterval","_clearInterval","clearInterval","_getComputedStyle","getComputedStyle","_encodeURIComponent","encodeURIComponent","_ActiveXObject","ActiveXObject","_Error","Error","_parseInt","Number","parseInt","_parseFloat","parseFloat","_isNaN","isNaN","_now","Date","now","_keys","Object","keys","_defineProperty","defineProperty","_hasOwn","prototype","hasOwnProperty","_slice","Array","slice","_unwrap","unwrapper","el","wrap","unwrap","div","createElement","unwrappedDiv","nodeType","e","_args","argumentsObj","call","_extend","i","len","arg","prop","src","copy","args","arguments","target","length","_deepCopy","source","_pick","obj","newObj","_omit","indexOf","_deleteOwnProperties","_containedBy","ancestorEl","ownerDocument","parentNode","_getDirPathOfUrl","url","dir","split","lastIndexOf","_getCurrentScriptUrlFromErrorStack","stack","matches","match","_getCurrentScriptUrlFromError","err","sourceURL","fileName","_getCurrentScriptUrl","jsPath","scripts","currentScript","getElementsByTagName","readyState","_getUnanimousScriptParentDir","jsDir","_getDefaultSwfPath","_flashState","bridge","version","pluginType","disabled","outdated","unavailable","degraded","deactivated","overdue","ready","_minimumFlashVersion","_handlers","_clipData","_clipDataFormatMap","_flashCheckTimeout","_swfFallbackCheckInterval","_eventMessages","error","flash-disabled","flash-outdated","flash-unavailable","flash-degraded","flash-deactivated","flash-overdue","version-mismatch","clipboard-error","config-mismatch","swf-not-found","_globalConfig","swfPath","trustedDomains","location","host","cacheBust","forceEnhancedClipboard","flashLoadTimeout","autoActivate","bubbleEvents","containerId","containerClass","swfObjectId","hoverClass","activeClass","forceHandCursor","title","zIndex","_config","options","test","_isValidHtml4Id","_state","browser","flash","zeroclipboard","ZeroClipboard","config","_isFlashUnusable","_on","eventType","listener","events","added","toLowerCase","on","replace","push","emit","type","flashErrorTypes","name","jsVersion","swfVersion","_off","foundIndex","perEventHandlers","off","splice","_listeners","_emit","event","eventCopy","returnVal","tmp","_createEvent","_preprocessEvent","_dispatchCallbacks","this","_mapClipDataToFlash","data","formatMap","_create","isFlashUnusable","maxWait","_embedSwf","_destroy","clearData","blur","_unembedSwf","_setData","format","dataObj","dataFormat","_clearData","_getData","_focus","element","_removeClass","_addClass","newTitle","getAttribute","htmlBridge","_getHtmlBridge","setAttribute","useHandCursor","_getStyle","_setHandCursor","_reposition","_blur","removeAttribute","style","left","top","width","_activeElement","id","relatedTarget","currentTarget","timeStamp","msg","message","minimumVersion","clipboardData","setData","_mapClipResultsFromFlash","_getRelatedTarget","_addMouseData","targetEl","relatedTargetId","getElementById","srcElement","fromElement","toElement","pos","_getElementPosition","screenLeft","screenX","screenTop","screenY","scrollLeft","body","documentElement","scrollTop","pageX","_stageX","pageY","_stageY","clientX","clientY","moveX","movementX","moveY","movementY","x","y","offsetX","offsetY","layerX","layerY","_shouldPerformAsync","_dispatchCallback","func","context","async","apply","wildcardTypeHandlers","specificTypeHandlers","handlers","concat","originalContext","handleEvent","sourceIsSwf","_source","flashErrorNames","_clearTimeoutsAndPolling","wasDeactivated","textContent","htmlContent","value","outerHTML","innerHTML","innerText","_queueEmitClipboardErrors","_safeActiveElement","focus","_fireMouseEvent","bubbles","cancelable","aftercopyEvent","errors","errorEvent","success","doc","defaults","view","defaultView","canBubble","detail","button","which","createEvent","dispatchEvent","ctrlKey","altKey","shiftKey","metaKey","initMouseEvent","_watchForSwfFallbackContent","pollWait","Math","min","fallbackContentId","_isElementVisible","_createHtmlBridge","container","className","position","height","_getSafeZIndex","flashBridge","nodeName","allowScriptAccess","_determineScriptAccess","allowNetworking","flashvars","_vars","swfUrl","_cacheBust","divToBeReplaced","appendChild","tmpDiv","usingActiveX","firstChild","replaceChild","display","removeSwfFromIE","removeChild","clipData","newClipData","text","html","rtf","clipResults","newResults","tmpHash","path","domain","domains","str","trustedOriginsExpanded","_extractDomain","protocol","join","originOrUrl","protocolIndex","pathIndex","_extractAllDomains","origins","resultsArray","currentDomain","configOptions","swfDomain","activeElement","classList","contains","add","classNames","setClass","c","cl","remove","getPropertyValue","getBoundingClientRect","elRect","pageXOffset","pageYOffset","leftBorderWidth","clientLeft","topBorderWidth","clientTop","leftBodyOffset","topBodyOffset","bodyRect","htmlRect","right","bottom","styles","hasCssHeight","hasCssWidth","hasCssTop","hasCssLeft","cssKnows","rect","isVisible","visibility","enabled","setHandCursor","val","_detectFlashSupport","parseFlashVersion","desc","isPepperFlash","flashPlayerFileName","inspectPlugin","plugin","hasFlash","flashVersion","description","filename","isPPAPI","ax","mimeType","isActiveX","plugins","mimeTypes","enabledPlugin","GetVariable","e1","e2","e3","_createClient","writable","configurable","enumerable","state","create","destroy","getData","activate","deactivate","_clientIdCounter","_clientMeta","_elementIdCounter","_elementMeta","_mouseHandlers","_clientConstructor","elements","client","instance","clip","_clientOn","meta","_clientOff","_clientListeners","_clientEmit","_clientShouldEmit","_clientDispatchCallbacks","_clientClip","_prepClip","zcClippingId","_addMouseHandlers","clippedElements","_clientUnclip","arrayIndex","clientIds","_removeMouseHandlers","_clientElements","_clientDestroy","unclip","clippedEls","hasClippedEls","goodTarget","goodRelTarget","goodClient","_suppressMouseEvents","stopImmediatePropagation","preventDefault","_elementMouseOver","addEventListener","mouseover","mouseout","mouseenter","mouseleave","mousemove","mouseHandlers","key","mouseEvents","removeEventListener","setText","setHtml","setRichText","richText","define","amd","module","exports"],"mappings":"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","sourcesContent":["/*!\n * ZeroClipboard\n * The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface.\n * Copyright (c) 2009-2014 Jon Rohan, James M. Greene\n * Licensed MIT\n * http://zeroclipboard.org/\n * v2.2.0-beta.3\n */\n(function(window, undefined) {\n \"use strict\";\n /**\n * Store references to critically important global functions that may be\n * overridden on certain web pages.\n */\n 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() {\n var unwrapper = function(el) {\n return el;\n };\n if (typeof _window.wrap === \"function\" && typeof _window.unwrap === \"function\") {\n try {\n var div = _document.createElement(\"div\");\n var unwrappedDiv = _window.unwrap(div);\n if (div.nodeType === 1 && unwrappedDiv && unwrappedDiv.nodeType === 1) {\n unwrapper = _window.unwrap;\n }\n } catch (e) {}\n }\n return unwrapper;\n }();\n /**\n * Convert an `arguments` object into an Array.\n *\n * @returns The arguments as an Array\n * @private\n */\n var _args = function(argumentsObj) {\n return _slice.call(argumentsObj, 0);\n };\n /**\n * Shallow-copy the owned, enumerable properties of one object over to another, similar to jQuery's `$.extend`.\n *\n * @returns The target object, augmented\n * @private\n */\n var _extend = function() {\n var i, len, arg, prop, src, copy, args = _args(arguments), target = args[0] || {};\n for (i = 1, len = args.length; i < len; i++) {\n if ((arg = args[i]) != null) {\n for (prop in arg) {\n if (_hasOwn.call(arg, prop)) {\n src = target[prop];\n copy = arg[prop];\n if (target !== copy && copy !== undefined) {\n target[prop] = copy;\n }\n }\n }\n }\n }\n return target;\n };\n /**\n * Return a deep copy of the source object or array.\n *\n * @returns Object or Array\n * @private\n */\n var _deepCopy = function(source) {\n var copy, i, len, prop;\n if (typeof source !== \"object\" || source == null || typeof source.nodeType === \"number\") {\n copy = source;\n } else if (typeof source.length === \"number\") {\n copy = [];\n for (i = 0, len = source.length; i < len; i++) {\n if (_hasOwn.call(source, i)) {\n copy[i] = _deepCopy(source[i]);\n }\n }\n } else {\n copy = {};\n for (prop in source) {\n if (_hasOwn.call(source, prop)) {\n copy[prop] = _deepCopy(source[prop]);\n }\n }\n }\n return copy;\n };\n /**\n * Makes a shallow copy of `obj` (like `_extend`) but filters its properties based on a list of `keys` to keep.\n * The inverse of `_omit`, mostly. The big difference is that these properties do NOT need to be enumerable to\n * be kept.\n *\n * @returns A new filtered object.\n * @private\n */\n var _pick = function(obj, keys) {\n var newObj = {};\n for (var i = 0, len = keys.length; i < len; i++) {\n if (keys[i] in obj) {\n newObj[keys[i]] = obj[keys[i]];\n }\n }\n return newObj;\n };\n /**\n * Makes a shallow copy of `obj` (like `_extend`) but filters its properties based on a list of `keys` to omit.\n * The inverse of `_pick`.\n *\n * @returns A new filtered object.\n * @private\n */\n var _omit = function(obj, keys) {\n var newObj = {};\n for (var prop in obj) {\n if (keys.indexOf(prop) === -1) {\n newObj[prop] = obj[prop];\n }\n }\n return newObj;\n };\n /**\n * Remove all owned, enumerable properties from an object.\n *\n * @returns The original object without its owned, enumerable properties.\n * @private\n */\n var _deleteOwnProperties = function(obj) {\n if (obj) {\n for (var prop in obj) {\n if (_hasOwn.call(obj, prop)) {\n delete obj[prop];\n }\n }\n }\n return obj;\n };\n /**\n * Determine if an element is contained within another element.\n *\n * @returns Boolean\n * @private\n */\n var _containedBy = function(el, ancestorEl) {\n 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)) {\n do {\n if (el === ancestorEl) {\n return true;\n }\n el = el.parentNode;\n } while (el);\n }\n return false;\n };\n /**\n * Get the URL path's parent directory.\n *\n * @returns String or `undefined`\n * @private\n */\n var _getDirPathOfUrl = function(url) {\n var dir;\n if (typeof url === \"string\" && url) {\n dir = url.split(\"#\")[0].split(\"?\")[0];\n dir = url.slice(0, url.lastIndexOf(\"/\") + 1);\n }\n return dir;\n };\n /**\n * Get the current script's URL by throwing an `Error` and analyzing it.\n *\n * @returns String or `undefined`\n * @private\n */\n var _getCurrentScriptUrlFromErrorStack = function(stack) {\n var url, matches;\n if (typeof stack === \"string\" && stack) {\n matches = stack.match(/^(?:|[^:@]*@|.+\\)@(?=http[s]?|file)|.+?\\s+(?: at |@)(?:[^:\\(]+ )*[\\(]?)((?:http[s]?|file):\\/\\/[\\/]?.+?\\/[^:\\)]*?)(?::\\d+)(?::\\d+)?/);\n if (matches && matches[1]) {\n url = matches[1];\n } else {\n matches = stack.match(/\\)@((?:http[s]?|file):\\/\\/[\\/]?.+?\\/[^:\\)]*?)(?::\\d+)(?::\\d+)?/);\n if (matches && matches[1]) {\n url = matches[1];\n }\n }\n }\n return url;\n };\n /**\n * Get the current script's URL by throwing an `Error` and analyzing it.\n *\n * @returns String or `undefined`\n * @private\n */\n var _getCurrentScriptUrlFromError = function() {\n var url, err;\n try {\n throw new _Error();\n } catch (e) {\n err = e;\n }\n if (err) {\n url = err.sourceURL || err.fileName || _getCurrentScriptUrlFromErrorStack(err.stack);\n }\n return url;\n };\n /**\n * Get the current script's URL.\n *\n * @returns String or `undefined`\n * @private\n */\n var _getCurrentScriptUrl = function() {\n var jsPath, scripts, i;\n if (_document.currentScript && (jsPath = _document.currentScript.src)) {\n return jsPath;\n }\n scripts = _document.getElementsByTagName(\"script\");\n if (scripts.length === 1) {\n return scripts[0].src || undefined;\n }\n if (\"readyState\" in scripts[0]) {\n for (i = scripts.length; i--; ) {\n if (scripts[i].readyState === \"interactive\" && (jsPath = scripts[i].src)) {\n return jsPath;\n }\n }\n }\n if (_document.readyState === \"loading\" && (jsPath = scripts[scripts.length - 1].src)) {\n return jsPath;\n }\n if (jsPath = _getCurrentScriptUrlFromError()) {\n return jsPath;\n }\n return undefined;\n };\n /**\n * Get the unanimous parent directory of ALL script tags.\n * If any script tags are either (a) inline or (b) from differing parent\n * directories, this method must return `undefined`.\n *\n * @returns String or `undefined`\n * @private\n */\n var _getUnanimousScriptParentDir = function() {\n var i, jsDir, jsPath, scripts = _document.getElementsByTagName(\"script\");\n for (i = scripts.length; i--; ) {\n if (!(jsPath = scripts[i].src)) {\n jsDir = null;\n break;\n }\n jsPath = _getDirPathOfUrl(jsPath);\n if (jsDir == null) {\n jsDir = jsPath;\n } else if (jsDir !== jsPath) {\n jsDir = null;\n break;\n }\n }\n return jsDir || undefined;\n };\n /**\n * Get the presumed location of the \"ZeroClipboard.swf\" file, based on the location\n * of the executing JavaScript file (e.g. \"ZeroClipboard.js\", etc.).\n *\n * @returns String\n * @private\n */\n var _getDefaultSwfPath = function() {\n var jsDir = _getDirPathOfUrl(_getCurrentScriptUrl()) || _getUnanimousScriptParentDir() || \"\";\n return jsDir + \"ZeroClipboard.swf\";\n };\n /**\n * Keep track of the state of the Flash object.\n * @private\n */\n var _flashState = {\n bridge: null,\n version: \"0.0.0\",\n pluginType: \"unknown\",\n disabled: null,\n outdated: null,\n unavailable: null,\n degraded: null,\n deactivated: null,\n overdue: null,\n ready: null\n };\n /**\n * The minimum Flash Player version required to use ZeroClipboard completely.\n * @readonly\n * @private\n */\n var _minimumFlashVersion = \"11.0.0\";\n /**\n * The ZeroClipboard library version number, as reported by Flash, at the time the SWF was compiled.\n */\n var _zcSwfVersion;\n /**\n * Keep track of all event listener registrations.\n * @private\n */\n var _handlers = {};\n /**\n * Keep track of the currently activated element.\n * @private\n */\n var _currentElement;\n /**\n * Keep track of the element that was activated when a `copy` process started.\n * @private\n */\n var _copyTarget;\n /**\n * Keep track of data for the pending clipboard transaction.\n * @private\n */\n var _clipData = {};\n /**\n * Keep track of data formats for the pending clipboard transaction.\n * @private\n */\n var _clipDataFormatMap = null;\n /**\n * Keep track of the Flash availability check timeout.\n * @private\n */\n var _flashCheckTimeout = 0;\n /**\n * Keep track of SWF network errors interval polling.\n * @private\n */\n var _swfFallbackCheckInterval = 0;\n /**\n * The `message` store for events\n * @private\n */\n var _eventMessages = {\n ready: \"Flash communication is established\",\n error: {\n \"flash-disabled\": \"Flash is disabled or not installed\",\n \"flash-outdated\": \"Flash is too outdated to support ZeroClipboard\",\n \"flash-unavailable\": \"Flash is unable to communicate bidirectionally with JavaScript\",\n \"flash-degraded\": \"Flash is unable to preserve data fidelity when communicating with JavaScript\",\n \"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.\",\n \"flash-overdue\": \"Flash communication was established but NOT within the acceptable time limit\",\n \"version-mismatch\": \"ZeroClipboard JS version number does not match ZeroClipboard SWF version number\",\n \"clipboard-error\": \"At least one error was thrown while ZeroClipboard was attempting to inject your data into the clipboard\",\n \"config-mismatch\": \"ZeroClipboard configuration does not match Flash's reality\",\n \"swf-not-found\": \"The ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity\"\n }\n };\n /**\n * ZeroClipboard configuration defaults for the Core module.\n * @private\n */\n var _globalConfig = {\n swfPath: _getDefaultSwfPath(),\n trustedDomains: window.location.host ? [ window.location.host ] : [],\n cacheBust: true,\n forceEnhancedClipboard: false,\n flashLoadTimeout: 3e4,\n autoActivate: true,\n bubbleEvents: true,\n containerId: \"global-zeroclipboard-html-bridge\",\n containerClass: \"global-zeroclipboard-container\",\n swfObjectId: \"global-zeroclipboard-flash-bridge\",\n hoverClass: \"zeroclipboard-is-hover\",\n activeClass: \"zeroclipboard-is-active\",\n forceHandCursor: false,\n title: null,\n zIndex: 999999999\n };\n /**\n * The underlying implementation of `ZeroClipboard.config`.\n * @private\n */\n var _config = function(options) {\n if (typeof options === \"object\" && options !== null) {\n for (var prop in options) {\n if (_hasOwn.call(options, prop)) {\n if (/^(?:forceHandCursor|title|zIndex|bubbleEvents)$/.test(prop)) {\n _globalConfig[prop] = options[prop];\n } else if (_flashState.bridge == null) {\n if (prop === \"containerId\" || prop === \"swfObjectId\") {\n if (_isValidHtml4Id(options[prop])) {\n _globalConfig[prop] = options[prop];\n } else {\n throw new Error(\"The specified `\" + prop + \"` value is not valid as an HTML4 Element ID\");\n }\n } else {\n _globalConfig[prop] = options[prop];\n }\n }\n }\n }\n }\n if (typeof options === \"string\" && options) {\n if (_hasOwn.call(_globalConfig, options)) {\n return _globalConfig[options];\n }\n return;\n }\n return _deepCopy(_globalConfig);\n };\n /**\n * The underlying implementation of `ZeroClipboard.state`.\n * @private\n */\n var _state = function() {\n return {\n browser: _pick(_navigator, [ \"userAgent\", \"platform\", \"appName\" ]),\n flash: _omit(_flashState, [ \"bridge\" ]),\n zeroclipboard: {\n version: ZeroClipboard.version,\n config: ZeroClipboard.config()\n }\n };\n };\n /**\n * The underlying implementation of `ZeroClipboard.isFlashUnusable`.\n * @private\n */\n var _isFlashUnusable = function() {\n return !!(_flashState.disabled || _flashState.outdated || _flashState.unavailable || _flashState.degraded || _flashState.deactivated);\n };\n /**\n * The underlying implementation of `ZeroClipboard.on`.\n * @private\n */\n var _on = function(eventType, listener) {\n var i, len, events, added = {};\n if (typeof eventType === \"string\" && eventType) {\n events = eventType.toLowerCase().split(/\\s+/);\n } else if (typeof eventType === \"object\" && eventType && typeof listener === \"undefined\") {\n for (i in eventType) {\n if (_hasOwn.call(eventType, i) && typeof i === \"string\" && i && typeof eventType[i] === \"function\") {\n ZeroClipboard.on(i, eventType[i]);\n }\n }\n }\n if (events && events.length) {\n for (i = 0, len = events.length; i < len; i++) {\n eventType = events[i].replace(/^on/, \"\");\n added[eventType] = true;\n if (!_handlers[eventType]) {\n _handlers[eventType] = [];\n }\n _handlers[eventType].push(listener);\n }\n if (added.ready && _flashState.ready) {\n ZeroClipboard.emit({\n type: \"ready\"\n });\n }\n if (added.error) {\n var flashErrorTypes = [ \"disabled\", \"outdated\", \"unavailable\", \"degraded\", \"deactivated\", \"overdue\" ];\n for (i = 0, len = flashErrorTypes.length; i < len; i++) {\n if (_flashState[flashErrorTypes[i]] === true) {\n ZeroClipboard.emit({\n type: \"error\",\n name: \"flash-\" + flashErrorTypes[i]\n });\n break;\n }\n }\n if (_zcSwfVersion !== undefined && ZeroClipboard.version !== _zcSwfVersion) {\n ZeroClipboard.emit({\n type: \"error\",\n name: \"version-mismatch\",\n jsVersion: ZeroClipboard.version,\n swfVersion: _zcSwfVersion\n });\n }\n }\n }\n return ZeroClipboard;\n };\n /**\n * The underlying implementation of `ZeroClipboard.off`.\n * @private\n */\n var _off = function(eventType, listener) {\n var i, len, foundIndex, events, perEventHandlers;\n if (arguments.length === 0) {\n events = _keys(_handlers);\n } else if (typeof eventType === \"string\" && eventType) {\n events = eventType.split(/\\s+/);\n } else if (typeof eventType === \"object\" && eventType && typeof listener === \"undefined\") {\n for (i in eventType) {\n if (_hasOwn.call(eventType, i) && typeof i === \"string\" && i && typeof eventType[i] === \"function\") {\n ZeroClipboard.off(i, eventType[i]);\n }\n }\n }\n if (events && events.length) {\n for (i = 0, len = events.length; i < len; i++) {\n eventType = events[i].toLowerCase().replace(/^on/, \"\");\n perEventHandlers = _handlers[eventType];\n if (perEventHandlers && perEventHandlers.length) {\n if (listener) {\n foundIndex = perEventHandlers.indexOf(listener);\n while (foundIndex !== -1) {\n perEventHandlers.splice(foundIndex, 1);\n foundIndex = perEventHandlers.indexOf(listener, foundIndex);\n }\n } else {\n perEventHandlers.length = 0;\n }\n }\n }\n }\n return ZeroClipboard;\n };\n /**\n * The underlying implementation of `ZeroClipboard.handlers`.\n * @private\n */\n var _listeners = function(eventType) {\n var copy;\n if (typeof eventType === \"string\" && eventType) {\n copy = _deepCopy(_handlers[eventType]) || null;\n } else {\n copy = _deepCopy(_handlers);\n }\n return copy;\n };\n /**\n * The underlying implementation of `ZeroClipboard.emit`.\n * @private\n */\n var _emit = function(event) {\n var eventCopy, returnVal, tmp;\n event = _createEvent(event);\n if (!event) {\n return;\n }\n if (_preprocessEvent(event)) {\n return;\n }\n if (event.type === \"ready\" && _flashState.overdue === true) {\n return ZeroClipboard.emit({\n type: \"error\",\n name: \"flash-overdue\"\n });\n }\n eventCopy = _extend({}, event);\n _dispatchCallbacks.call(this, eventCopy);\n if (event.type === \"copy\") {\n tmp = _mapClipDataToFlash(_clipData);\n returnVal = tmp.data;\n _clipDataFormatMap = tmp.formatMap;\n }\n return returnVal;\n };\n /**\n * The underlying implementation of `ZeroClipboard.create`.\n * @private\n */\n var _create = function() {\n if (typeof _flashState.ready !== \"boolean\") {\n _flashState.ready = false;\n }\n if (!ZeroClipboard.isFlashUnusable() && _flashState.bridge === null) {\n var maxWait = _globalConfig.flashLoadTimeout;\n if (typeof maxWait === \"number\" && maxWait >= 0) {\n _flashCheckTimeout = _setTimeout(function() {\n if (typeof _flashState.deactivated !== \"boolean\") {\n _flashState.deactivated = true;\n }\n if (_flashState.deactivated === true) {\n ZeroClipboard.emit({\n type: \"error\",\n name: \"flash-deactivated\"\n });\n }\n }, maxWait);\n }\n _flashState.overdue = false;\n _embedSwf();\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.destroy`.\n * @private\n */\n var _destroy = function() {\n ZeroClipboard.clearData();\n ZeroClipboard.blur();\n ZeroClipboard.emit(\"destroy\");\n _unembedSwf();\n ZeroClipboard.off();\n };\n /**\n * The underlying implementation of `ZeroClipboard.setData`.\n * @private\n */\n var _setData = function(format, data) {\n var dataObj;\n if (typeof format === \"object\" && format && typeof data === \"undefined\") {\n dataObj = format;\n ZeroClipboard.clearData();\n } else if (typeof format === \"string\" && format) {\n dataObj = {};\n dataObj[format] = data;\n } else {\n return;\n }\n for (var dataFormat in dataObj) {\n if (typeof dataFormat === \"string\" && dataFormat && _hasOwn.call(dataObj, dataFormat) && typeof dataObj[dataFormat] === \"string\" && dataObj[dataFormat]) {\n _clipData[dataFormat] = dataObj[dataFormat];\n }\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.clearData`.\n * @private\n */\n var _clearData = function(format) {\n if (typeof format === \"undefined\") {\n _deleteOwnProperties(_clipData);\n _clipDataFormatMap = null;\n } else if (typeof format === \"string\" && _hasOwn.call(_clipData, format)) {\n delete _clipData[format];\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.getData`.\n * @private\n */\n var _getData = function(format) {\n if (typeof format === \"undefined\") {\n return _deepCopy(_clipData);\n } else if (typeof format === \"string\" && _hasOwn.call(_clipData, format)) {\n return _clipData[format];\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.focus`/`ZeroClipboard.activate`.\n * @private\n */\n var _focus = function(element) {\n if (!(element && element.nodeType === 1)) {\n return;\n }\n if (_currentElement) {\n _removeClass(_currentElement, _globalConfig.activeClass);\n if (_currentElement !== element) {\n _removeClass(_currentElement, _globalConfig.hoverClass);\n }\n }\n _currentElement = element;\n _addClass(element, _globalConfig.hoverClass);\n var newTitle = element.getAttribute(\"title\") || _globalConfig.title;\n if (typeof newTitle === \"string\" && newTitle) {\n var htmlBridge = _getHtmlBridge(_flashState.bridge);\n if (htmlBridge) {\n htmlBridge.setAttribute(\"title\", newTitle);\n }\n }\n var useHandCursor = _globalConfig.forceHandCursor === true || _getStyle(element, \"cursor\") === \"pointer\";\n _setHandCursor(useHandCursor);\n _reposition();\n };\n /**\n * The underlying implementation of `ZeroClipboard.blur`/`ZeroClipboard.deactivate`.\n * @private\n */\n var _blur = function() {\n var htmlBridge = _getHtmlBridge(_flashState.bridge);\n if (htmlBridge) {\n htmlBridge.removeAttribute(\"title\");\n htmlBridge.style.left = \"0px\";\n htmlBridge.style.top = \"-9999px\";\n htmlBridge.style.width = \"1px\";\n htmlBridge.style.top = \"1px\";\n }\n if (_currentElement) {\n _removeClass(_currentElement, _globalConfig.hoverClass);\n _removeClass(_currentElement, _globalConfig.activeClass);\n _currentElement = null;\n }\n };\n /**\n * The underlying implementation of `ZeroClipboard.activeElement`.\n * @private\n */\n var _activeElement = function() {\n return _currentElement || null;\n };\n /**\n * Check if a value is a valid HTML4 `ID` or `Name` token.\n * @private\n */\n var _isValidHtml4Id = function(id) {\n return typeof id === \"string\" && id && /^[A-Za-z][A-Za-z0-9_:\\-\\.]*$/.test(id);\n };\n /**\n * Create or update an `event` object, based on the `eventType`.\n * @private\n */\n var _createEvent = function(event) {\n var eventType;\n if (typeof event === \"string\" && event) {\n eventType = event;\n event = {};\n } else if (typeof event === \"object\" && event && typeof event.type === \"string\" && event.type) {\n eventType = event.type;\n }\n if (!eventType) {\n return;\n }\n eventType = eventType.toLowerCase();\n if (!event.target && (/^(copy|aftercopy|_click)$/.test(eventType) || eventType === \"error\" && event.name === \"clipboard-error\")) {\n event.target = _copyTarget;\n }\n _extend(event, {\n type: eventType,\n target: event.target || _currentElement || null,\n relatedTarget: event.relatedTarget || null,\n currentTarget: _flashState && _flashState.bridge || null,\n timeStamp: event.timeStamp || _now() || null\n });\n var msg = _eventMessages[event.type];\n if (event.type === \"error\" && event.name && msg) {\n msg = msg[event.name];\n }\n if (msg) {\n event.message = msg;\n }\n if (event.type === \"ready\") {\n _extend(event, {\n target: null,\n version: _flashState.version\n });\n }\n if (event.type === \"error\") {\n if (/^flash-(disabled|outdated|unavailable|degraded|deactivated|overdue)$/.test(event.name)) {\n _extend(event, {\n target: null,\n minimumVersion: _minimumFlashVersion\n });\n }\n if (/^flash-(outdated|unavailable|degraded|deactivated|overdue)$/.test(event.name)) {\n _extend(event, {\n version: _flashState.version\n });\n }\n }\n if (event.type === \"copy\") {\n event.clipboardData = {\n setData: ZeroClipboard.setData,\n clearData: ZeroClipboard.clearData\n };\n }\n if (event.type === \"aftercopy\") {\n event = _mapClipResultsFromFlash(event, _clipDataFormatMap);\n }\n if (event.target && !event.relatedTarget) {\n event.relatedTarget = _getRelatedTarget(event.target);\n }\n return _addMouseData(event);\n };\n /**\n * Get a relatedTarget from the target's `data-clipboard-target` attribute\n * @private\n */\n var _getRelatedTarget = function(targetEl) {\n var relatedTargetId = targetEl && targetEl.getAttribute && targetEl.getAttribute(\"data-clipboard-target\");\n return relatedTargetId ? _document.getElementById(relatedTargetId) : null;\n };\n /**\n * Add element and position data to `MouseEvent` instances\n * @private\n */\n var _addMouseData = function(event) {\n if (event && /^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) {\n var srcElement = event.target;\n var fromElement = event.type === \"_mouseover\" && event.relatedTarget ? event.relatedTarget : undefined;\n var toElement = event.type === \"_mouseout\" && event.relatedTarget ? event.relatedTarget : undefined;\n var pos = _getElementPosition(srcElement);\n var screenLeft = _window.screenLeft || _window.screenX || 0;\n var screenTop = _window.screenTop || _window.screenY || 0;\n var scrollLeft = _document.body.scrollLeft + _document.documentElement.scrollLeft;\n var scrollTop = _document.body.scrollTop + _document.documentElement.scrollTop;\n var pageX = pos.left + (typeof event._stageX === \"number\" ? event._stageX : 0);\n var pageY = pos.top + (typeof event._stageY === \"number\" ? event._stageY : 0);\n var clientX = pageX - scrollLeft;\n var clientY = pageY - scrollTop;\n var screenX = screenLeft + clientX;\n var screenY = screenTop + clientY;\n var moveX = typeof event.movementX === \"number\" ? event.movementX : 0;\n var moveY = typeof event.movementY === \"number\" ? event.movementY : 0;\n delete event._stageX;\n delete event._stageY;\n _extend(event, {\n srcElement: srcElement,\n fromElement: fromElement,\n toElement: toElement,\n screenX: screenX,\n screenY: screenY,\n pageX: pageX,\n pageY: pageY,\n clientX: clientX,\n clientY: clientY,\n x: clientX,\n y: clientY,\n movementX: moveX,\n movementY: moveY,\n offsetX: 0,\n offsetY: 0,\n layerX: 0,\n layerY: 0\n });\n }\n return event;\n };\n /**\n * Determine if an event's registered handlers should be execute synchronously or asynchronously.\n *\n * @returns {boolean}\n * @private\n */\n var _shouldPerformAsync = function(event) {\n var eventType = event && typeof event.type === \"string\" && event.type || \"\";\n return !/^(?:(?:before)?copy|destroy)$/.test(eventType);\n };\n /**\n * Control if a callback should be executed asynchronously or not.\n *\n * @returns `undefined`\n * @private\n */\n var _dispatchCallback = function(func, context, args, async) {\n if (async) {\n _setTimeout(function() {\n func.apply(context, args);\n }, 0);\n } else {\n func.apply(context, args);\n }\n };\n /**\n * Handle the actual dispatching of events to client instances.\n *\n * @returns `undefined`\n * @private\n */\n var _dispatchCallbacks = function(event) {\n if (!(typeof event === \"object\" && event && event.type)) {\n return;\n }\n var async = _shouldPerformAsync(event);\n var wildcardTypeHandlers = _handlers[\"*\"] || [];\n var specificTypeHandlers = _handlers[event.type] || [];\n var handlers = wildcardTypeHandlers.concat(specificTypeHandlers);\n if (handlers && handlers.length) {\n var i, len, func, context, eventCopy, originalContext = this;\n for (i = 0, len = handlers.length; i < len; i++) {\n func = handlers[i];\n context = originalContext;\n if (typeof func === \"string\" && typeof _window[func] === \"function\") {\n func = _window[func];\n }\n if (typeof func === \"object\" && func && typeof func.handleEvent === \"function\") {\n context = func;\n func = func.handleEvent;\n }\n if (typeof func === \"function\") {\n eventCopy = _extend({}, event);\n _dispatchCallback(func, context, [ eventCopy ], async);\n }\n }\n }\n return this;\n };\n /**\n * Preprocess any special behaviors, reactions, or state changes after receiving this event.\n * Executes only once per event emitted, NOT once per client.\n * @private\n */\n var _preprocessEvent = function(event) {\n var element = event.target || _currentElement || null;\n var sourceIsSwf = event._source === \"swf\";\n delete event._source;\n var flashErrorNames = [ \"flash-disabled\", \"flash-outdated\", \"flash-unavailable\", \"flash-degraded\", \"flash-deactivated\", \"flash-overdue\" ];\n switch (event.type) {\n case \"error\":\n if (flashErrorNames.indexOf(event.name) !== -1) {\n _extend(_flashState, {\n disabled: event.name === \"flash-disabled\",\n outdated: event.name === \"flash-outdated\",\n unavailable: event.name === \"flash-unavailable\",\n degraded: event.name === \"flash-degraded\",\n deactivated: event.name === \"flash-deactivated\",\n overdue: event.name === \"flash-overdue\",\n ready: false\n });\n } else if (event.name === \"version-mismatch\") {\n _zcSwfVersion = event.swfVersion;\n _extend(_flashState, {\n disabled: false,\n outdated: false,\n unavailable: false,\n degraded: false,\n deactivated: false,\n overdue: false,\n ready: false\n });\n }\n _clearTimeoutsAndPolling();\n break;\n\n case \"ready\":\n _zcSwfVersion = event.swfVersion;\n var wasDeactivated = _flashState.deactivated === true;\n _extend(_flashState, {\n disabled: false,\n outdated: false,\n unavailable: false,\n degraded: false,\n deactivated: false,\n overdue: wasDeactivated,\n ready: !wasDeactivated\n });\n _clearTimeoutsAndPolling();\n break;\n\n case \"beforecopy\":\n _copyTarget = element;\n break;\n\n case \"copy\":\n var textContent, htmlContent, targetEl = event.relatedTarget;\n if (!(_clipData[\"text/html\"] || _clipData[\"text/plain\"]) && targetEl && (htmlContent = targetEl.value || targetEl.outerHTML || targetEl.innerHTML) && (textContent = targetEl.value || targetEl.textContent || targetEl.innerText)) {\n event.clipboardData.clearData();\n event.clipboardData.setData(\"text/plain\", textContent);\n if (htmlContent !== textContent) {\n event.clipboardData.setData(\"text/html\", htmlContent);\n }\n } else if (!_clipData[\"text/plain\"] && event.target && (textContent = event.target.getAttribute(\"data-clipboard-text\"))) {\n event.clipboardData.clearData();\n event.clipboardData.setData(\"text/plain\", textContent);\n }\n break;\n\n case \"aftercopy\":\n _queueEmitClipboardErrors(event);\n ZeroClipboard.clearData();\n if (element && element !== _safeActiveElement() && element.focus) {\n element.focus();\n }\n break;\n\n case \"_mouseover\":\n ZeroClipboard.focus(element);\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) {\n _fireMouseEvent(_extend({}, event, {\n type: \"mouseenter\",\n bubbles: false,\n cancelable: false\n }));\n }\n _fireMouseEvent(_extend({}, event, {\n type: \"mouseover\"\n }));\n }\n break;\n\n case \"_mouseout\":\n ZeroClipboard.blur();\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n if (element && element !== event.relatedTarget && !_containedBy(event.relatedTarget, element)) {\n _fireMouseEvent(_extend({}, event, {\n type: \"mouseleave\",\n bubbles: false,\n cancelable: false\n }));\n }\n _fireMouseEvent(_extend({}, event, {\n type: \"mouseout\"\n }));\n }\n break;\n\n case \"_mousedown\":\n _addClass(element, _globalConfig.activeClass);\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n _fireMouseEvent(_extend({}, event, {\n type: event.type.slice(1)\n }));\n }\n break;\n\n case \"_mouseup\":\n _removeClass(element, _globalConfig.activeClass);\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n _fireMouseEvent(_extend({}, event, {\n type: event.type.slice(1)\n }));\n }\n break;\n\n case \"_click\":\n _copyTarget = null;\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n _fireMouseEvent(_extend({}, event, {\n type: event.type.slice(1)\n }));\n }\n break;\n\n case \"_mousemove\":\n if (_globalConfig.bubbleEvents === true && sourceIsSwf) {\n _fireMouseEvent(_extend({}, event, {\n type: event.type.slice(1)\n }));\n }\n break;\n }\n if (/^_(?:click|mouse(?:over|out|down|up|move))$/.test(event.type)) {\n return true;\n }\n };\n /**\n * Check an \"aftercopy\" event for clipboard errors and emit a corresponding \"error\" event.\n * @private\n */\n var _queueEmitClipboardErrors = function(aftercopyEvent) {\n if (aftercopyEvent.errors && aftercopyEvent.errors.length > 0) {\n var errorEvent = _deepCopy(aftercopyEvent);\n _extend(errorEvent, {\n type: \"error\",\n name: \"clipboard-error\"\n });\n delete errorEvent.success;\n _setTimeout(function() {\n ZeroClipboard.emit(errorEvent);\n }, 0);\n }\n };\n /**\n * Dispatch a synthetic MouseEvent.\n *\n * @returns `undefined`\n * @private\n */\n var _fireMouseEvent = function(event) {\n if (!(event && typeof event.type === \"string\" && event)) {\n return;\n }\n var e, target = event.target || null, doc = target && target.ownerDocument || _document, defaults = {\n view: doc.defaultView || _window,\n canBubble: true,\n cancelable: true,\n detail: event.type === \"click\" ? 1 : 0,\n button: typeof event.which === \"number\" ? event.which - 1 : typeof event.button === \"number\" ? event.button : doc.createEvent ? 0 : 1\n }, args = _extend(defaults, event);\n if (!target) {\n return;\n }\n if (doc.createEvent && target.dispatchEvent) {\n 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 ];\n e = doc.createEvent(\"MouseEvents\");\n if (e.initMouseEvent) {\n e.initMouseEvent.apply(e, args);\n e._source = \"js\";\n target.dispatchEvent(e);\n }\n }\n };\n /**\n * Continuously poll the DOM until either:\n * (a) the fallback content becomes visible, or\n * (b) we receive an event from SWF (handled elsewhere)\n *\n * IMPORTANT:\n * This is NOT a necessary check but it can result in significantly faster\n * detection of bad `swfPath` configuration and/or network/server issues [in\n * supported browsers] than waiting for the entire `flashLoadTimeout` duration\n * to elapse before detecting that the SWF cannot be loaded. The detection\n * duration can be anywhere from 10-30 times faster [in supported browsers] by\n * using this approach.\n *\n * @returns `undefined`\n * @private\n */\n var _watchForSwfFallbackContent = function() {\n var maxWait = _globalConfig.flashLoadTimeout;\n if (typeof maxWait === \"number\" && maxWait >= 0) {\n var pollWait = Math.min(1e3, maxWait / 10);\n var fallbackContentId = _globalConfig.swfObjectId + \"_fallbackContent\";\n _swfFallbackCheckInterval = _setInterval(function() {\n var el = _document.getElementById(fallbackContentId);\n if (_isElementVisible(el)) {\n _clearTimeoutsAndPolling();\n _flashState.deactivated = null;\n ZeroClipboard.emit({\n type: \"error\",\n name: \"swf-not-found\"\n });\n }\n }, pollWait);\n }\n };\n /**\n * Create the HTML bridge element to embed the Flash object into.\n * @private\n */\n var _createHtmlBridge = function() {\n var container = _document.createElement(\"div\");\n container.id = _globalConfig.containerId;\n container.className = _globalConfig.containerClass;\n container.style.position = \"absolute\";\n container.style.left = \"0px\";\n container.style.top = \"-9999px\";\n container.style.width = \"1px\";\n container.style.height = \"1px\";\n container.style.zIndex = \"\" + _getSafeZIndex(_globalConfig.zIndex);\n return container;\n };\n /**\n * Get the HTML element container that wraps the Flash bridge object/element.\n * @private\n */\n var _getHtmlBridge = function(flashBridge) {\n var htmlBridge = flashBridge && flashBridge.parentNode;\n while (htmlBridge && htmlBridge.nodeName === \"OBJECT\" && htmlBridge.parentNode) {\n htmlBridge = htmlBridge.parentNode;\n }\n return htmlBridge || null;\n };\n /**\n * Create the SWF object.\n *\n * @returns The SWF object reference.\n * @private\n */\n var _embedSwf = function() {\n var len, flashBridge = _flashState.bridge, container = _getHtmlBridge(flashBridge);\n if (!flashBridge) {\n var allowScriptAccess = _determineScriptAccess(_window.location.host, _globalConfig);\n var allowNetworking = allowScriptAccess === \"never\" ? \"none\" : \"all\";\n var flashvars = _vars(_extend({\n jsVersion: ZeroClipboard.version\n }, _globalConfig));\n var swfUrl = _globalConfig.swfPath + _cacheBust(_globalConfig.swfPath, _globalConfig);\n container = _createHtmlBridge();\n var divToBeReplaced = _document.createElement(\"div\");\n container.appendChild(divToBeReplaced);\n _document.body.appendChild(container);\n var tmpDiv = _document.createElement(\"div\");\n var usingActiveX = _flashState.pluginType === \"activex\";\n tmpDiv.innerHTML = '\" + (usingActiveX ? '' : \"\") + '' + '' + '' + '' + '' + '
 
' + \"
\";\n flashBridge = tmpDiv.firstChild;\n tmpDiv = null;\n _unwrap(flashBridge).ZeroClipboard = ZeroClipboard;\n container.replaceChild(flashBridge, divToBeReplaced);\n _watchForSwfFallbackContent();\n }\n if (!flashBridge) {\n flashBridge = _document[_globalConfig.swfObjectId];\n if (flashBridge && (len = flashBridge.length)) {\n flashBridge = flashBridge[len - 1];\n }\n if (!flashBridge && container) {\n flashBridge = container.firstChild;\n }\n }\n _flashState.bridge = flashBridge || null;\n return flashBridge;\n };\n /**\n * Destroy the SWF object.\n * @private\n */\n var _unembedSwf = function() {\n var flashBridge = _flashState.bridge;\n if (flashBridge) {\n var htmlBridge = _getHtmlBridge(flashBridge);\n if (htmlBridge) {\n if (_flashState.pluginType === \"activex\" && \"readyState\" in flashBridge) {\n flashBridge.style.display = \"none\";\n (function removeSwfFromIE() {\n if (flashBridge.readyState === 4) {\n for (var prop in flashBridge) {\n if (typeof flashBridge[prop] === \"function\") {\n flashBridge[prop] = null;\n }\n }\n if (flashBridge.parentNode) {\n flashBridge.parentNode.removeChild(flashBridge);\n }\n if (htmlBridge.parentNode) {\n htmlBridge.parentNode.removeChild(htmlBridge);\n }\n } else {\n _setTimeout(removeSwfFromIE, 10);\n }\n })();\n } else {\n if (flashBridge.parentNode) {\n flashBridge.parentNode.removeChild(flashBridge);\n }\n if (htmlBridge.parentNode) {\n htmlBridge.parentNode.removeChild(htmlBridge);\n }\n }\n }\n _clearTimeoutsAndPolling();\n _flashState.ready = null;\n _flashState.bridge = null;\n _flashState.deactivated = null;\n _zcSwfVersion = undefined;\n }\n };\n /**\n * Map the data format names of the \"clipData\" to Flash-friendly names.\n *\n * @returns A new transformed object.\n * @private\n */\n var _mapClipDataToFlash = function(clipData) {\n var newClipData = {}, formatMap = {};\n if (!(typeof clipData === \"object\" && clipData)) {\n return;\n }\n for (var dataFormat in clipData) {\n if (dataFormat && _hasOwn.call(clipData, dataFormat) && typeof clipData[dataFormat] === \"string\" && clipData[dataFormat]) {\n switch (dataFormat.toLowerCase()) {\n case \"text/plain\":\n case \"text\":\n case \"air:text\":\n case \"flash:text\":\n newClipData.text = clipData[dataFormat];\n formatMap.text = dataFormat;\n break;\n\n case \"text/html\":\n case \"html\":\n case \"air:html\":\n case \"flash:html\":\n newClipData.html = clipData[dataFormat];\n formatMap.html = dataFormat;\n break;\n\n case \"application/rtf\":\n case \"text/rtf\":\n case \"rtf\":\n case \"richtext\":\n case \"air:rtf\":\n case \"flash:rtf\":\n newClipData.rtf = clipData[dataFormat];\n formatMap.rtf = dataFormat;\n break;\n\n default:\n break;\n }\n }\n }\n return {\n data: newClipData,\n formatMap: formatMap\n };\n };\n /**\n * Map the data format names from Flash-friendly names back to their original \"clipData\" names (via a format mapping).\n *\n * @returns A new transformed object.\n * @private\n */\n var _mapClipResultsFromFlash = function(clipResults, formatMap) {\n if (!(typeof clipResults === \"object\" && clipResults && typeof formatMap === \"object\" && formatMap)) {\n return clipResults;\n }\n var newResults = {};\n for (var prop in clipResults) {\n if (_hasOwn.call(clipResults, prop)) {\n if (prop === \"errors\") {\n newResults[prop] = clipResults[prop] ? clipResults[prop].slice() : [];\n for (var i = 0, len = newResults[prop].length; i < len; i++) {\n newResults[prop][i].format = formatMap[newResults[prop][i].format];\n }\n } else if (prop !== \"success\" && prop !== \"data\") {\n newResults[prop] = clipResults[prop];\n } else {\n newResults[prop] = {};\n var tmpHash = clipResults[prop];\n for (var dataFormat in tmpHash) {\n if (dataFormat && _hasOwn.call(tmpHash, dataFormat) && _hasOwn.call(formatMap, dataFormat)) {\n newResults[prop][formatMap[dataFormat]] = tmpHash[dataFormat];\n }\n }\n }\n }\n }\n return newResults;\n };\n /**\n * Will look at a path, and will create a \"?noCache={time}\" or \"&noCache={time}\"\n * query param string to return. Does NOT append that string to the original path.\n * This is useful because ExternalInterface often breaks when a Flash SWF is cached.\n *\n * @returns The `noCache` query param with necessary \"?\"/\"&\" prefix.\n * @private\n */\n var _cacheBust = function(path, options) {\n var cacheBust = options == null || options && options.cacheBust === true;\n if (cacheBust) {\n return (path.indexOf(\"?\") === -1 ? \"?\" : \"&\") + \"noCache=\" + _now();\n } else {\n return \"\";\n }\n };\n /**\n * Creates a query string for the FlashVars param.\n * Does NOT include the cache-busting query param.\n *\n * @returns FlashVars query string\n * @private\n */\n var _vars = function(options) {\n var i, len, domain, domains, str = \"\", trustedOriginsExpanded = [];\n if (options.trustedDomains) {\n if (typeof options.trustedDomains === \"string\") {\n domains = [ options.trustedDomains ];\n } else if (typeof options.trustedDomains === \"object\" && \"length\" in options.trustedDomains) {\n domains = options.trustedDomains;\n }\n }\n if (domains && domains.length) {\n for (i = 0, len = domains.length; i < len; i++) {\n if (_hasOwn.call(domains, i) && domains[i] && typeof domains[i] === \"string\") {\n domain = _extractDomain(domains[i]);\n if (!domain) {\n continue;\n }\n if (domain === \"*\") {\n trustedOriginsExpanded.length = 0;\n trustedOriginsExpanded.push(domain);\n break;\n }\n trustedOriginsExpanded.push.apply(trustedOriginsExpanded, [ domain, \"//\" + domain, _window.location.protocol + \"//\" + domain ]);\n }\n }\n }\n if (trustedOriginsExpanded.length) {\n str += \"trustedOrigins=\" + _encodeURIComponent(trustedOriginsExpanded.join(\",\"));\n }\n if (options.forceEnhancedClipboard === true) {\n str += (str ? \"&\" : \"\") + \"forceEnhancedClipboard=true\";\n }\n if (typeof options.swfObjectId === \"string\" && options.swfObjectId) {\n str += (str ? \"&\" : \"\") + \"swfObjectId=\" + _encodeURIComponent(options.swfObjectId);\n }\n if (typeof options.jsVersion === \"string\" && options.jsVersion) {\n str += (str ? \"&\" : \"\") + \"jsVersion=\" + _encodeURIComponent(options.jsVersion);\n }\n return str;\n };\n /**\n * Extract the domain (e.g. \"github.com\") from an origin (e.g. \"https://github.com\") or\n * URL (e.g. \"https://github.com/zeroclipboard/zeroclipboard/\").\n *\n * @returns the domain\n * @private\n */\n var _extractDomain = function(originOrUrl) {\n if (originOrUrl == null || originOrUrl === \"\") {\n return null;\n }\n originOrUrl = originOrUrl.replace(/^\\s+|\\s+$/g, \"\");\n if (originOrUrl === \"\") {\n return null;\n }\n var protocolIndex = originOrUrl.indexOf(\"//\");\n originOrUrl = protocolIndex === -1 ? originOrUrl : originOrUrl.slice(protocolIndex + 2);\n var pathIndex = originOrUrl.indexOf(\"/\");\n originOrUrl = pathIndex === -1 ? originOrUrl : protocolIndex === -1 || pathIndex === 0 ? null : originOrUrl.slice(0, pathIndex);\n if (originOrUrl && originOrUrl.slice(-4).toLowerCase() === \".swf\") {\n return null;\n }\n return originOrUrl || null;\n };\n /**\n * Set `allowScriptAccess` based on `trustedDomains` and `window.location.host` vs. `swfPath`.\n *\n * @returns The appropriate script access level.\n * @private\n */\n var _determineScriptAccess = function() {\n var _extractAllDomains = function(origins) {\n var i, len, tmp, resultsArray = [];\n if (typeof origins === \"string\") {\n origins = [ origins ];\n }\n if (!(typeof origins === \"object\" && origins && typeof origins.length === \"number\")) {\n return resultsArray;\n }\n for (i = 0, len = origins.length; i < len; i++) {\n if (_hasOwn.call(origins, i) && (tmp = _extractDomain(origins[i]))) {\n if (tmp === \"*\") {\n resultsArray.length = 0;\n resultsArray.push(\"*\");\n break;\n }\n if (resultsArray.indexOf(tmp) === -1) {\n resultsArray.push(tmp);\n }\n }\n }\n return resultsArray;\n };\n return function(currentDomain, configOptions) {\n var swfDomain = _extractDomain(configOptions.swfPath);\n if (swfDomain === null) {\n swfDomain = currentDomain;\n }\n var trustedDomains = _extractAllDomains(configOptions.trustedDomains);\n var len = trustedDomains.length;\n if (len > 0) {\n if (len === 1 && trustedDomains[0] === \"*\") {\n return \"always\";\n }\n if (trustedDomains.indexOf(currentDomain) !== -1) {\n if (len === 1 && currentDomain === swfDomain) {\n return \"sameDomain\";\n }\n return \"always\";\n }\n }\n return \"never\";\n };\n }();\n /**\n * Get the currently active/focused DOM element.\n *\n * @returns the currently active/focused element, or `null`\n * @private\n */\n var _safeActiveElement = function() {\n try {\n return _document.activeElement;\n } catch (err) {\n return null;\n }\n };\n /**\n * Add a class to an element, if it doesn't already have it.\n *\n * @returns The element, with its new class added.\n * @private\n */\n var _addClass = function(element, value) {\n if (!element || element.nodeType !== 1) {\n return element;\n }\n if (element.classList) {\n if (!element.classList.contains(value)) {\n element.classList.add(value);\n }\n return element;\n }\n if (value && typeof value === \"string\") {\n var classNames = (value || \"\").split(/\\s+/);\n if (element.nodeType === 1) {\n if (!element.className) {\n element.className = value;\n } else {\n var className = \" \" + element.className + \" \", setClass = element.className;\n for (var c = 0, cl = classNames.length; c < cl; c++) {\n if (className.indexOf(\" \" + classNames[c] + \" \") < 0) {\n setClass += \" \" + classNames[c];\n }\n }\n element.className = setClass.replace(/^\\s+|\\s+$/g, \"\");\n }\n }\n }\n return element;\n };\n /**\n * Remove a class from an element, if it has it.\n *\n * @returns The element, with its class removed.\n * @private\n */\n var _removeClass = function(element, value) {\n if (!element || element.nodeType !== 1) {\n return element;\n }\n if (element.classList) {\n if (element.classList.contains(value)) {\n element.classList.remove(value);\n }\n return element;\n }\n if (typeof value === \"string\" && value) {\n var classNames = value.split(/\\s+/);\n if (element.nodeType === 1 && element.className) {\n var className = (\" \" + element.className + \" \").replace(/[\\n\\t]/g, \" \");\n for (var c = 0, cl = classNames.length; c < cl; c++) {\n className = className.replace(\" \" + classNames[c] + \" \", \" \");\n }\n element.className = className.replace(/^\\s+|\\s+$/g, \"\");\n }\n }\n return element;\n };\n /**\n * Attempt to interpret the element's CSS styling. If `prop` is `\"cursor\"`,\n * then we assume that it should be a hand (\"pointer\") cursor if the element\n * is an anchor element (\"a\" tag).\n *\n * @returns The computed style property.\n * @private\n */\n var _getStyle = function(el, prop) {\n var value = _getComputedStyle(el, null).getPropertyValue(prop);\n if (prop === \"cursor\") {\n if (!value || value === \"auto\") {\n if (el.nodeName === \"A\") {\n return \"pointer\";\n }\n }\n }\n return value;\n };\n /**\n * Get the absolutely positioned coordinates of a DOM element.\n *\n * @returns Object containing the element's position, width, and height.\n * @private\n */\n var _getElementPosition = function(el) {\n var pos = {\n left: 0,\n top: 0,\n width: 0,\n height: 0\n };\n if (el.getBoundingClientRect) {\n var elRect = el.getBoundingClientRect();\n var pageXOffset = _window.pageXOffset;\n var pageYOffset = _window.pageYOffset;\n var leftBorderWidth = _document.documentElement.clientLeft || 0;\n var topBorderWidth = _document.documentElement.clientTop || 0;\n var leftBodyOffset = 0;\n var topBodyOffset = 0;\n if (_getStyle(_document.body, \"position\") === \"relative\") {\n var bodyRect = _document.body.getBoundingClientRect();\n var htmlRect = _document.documentElement.getBoundingClientRect();\n leftBodyOffset = bodyRect.left - htmlRect.left || 0;\n topBodyOffset = bodyRect.top - htmlRect.top || 0;\n }\n pos.left = elRect.left + pageXOffset - leftBorderWidth - leftBodyOffset;\n pos.top = elRect.top + pageYOffset - topBorderWidth - topBodyOffset;\n pos.width = \"width\" in elRect ? elRect.width : elRect.right - elRect.left;\n pos.height = \"height\" in elRect ? elRect.height : elRect.bottom - elRect.top;\n }\n return pos;\n };\n /**\n * Determine is an element is visible somewhere within the document (page).\n *\n * @returns Boolean\n * @private\n */\n var _isElementVisible = function(el) {\n if (!el) {\n return false;\n }\n var styles = _getComputedStyle(el, null);\n var hasCssHeight = _parseFloat(styles.height) > 0;\n var hasCssWidth = _parseFloat(styles.width) > 0;\n var hasCssTop = _parseFloat(styles.top) >= 0;\n var hasCssLeft = _parseFloat(styles.left) >= 0;\n var cssKnows = hasCssHeight && hasCssWidth && hasCssTop && hasCssLeft;\n var rect = cssKnows ? null : _getElementPosition(el);\n 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));\n return isVisible;\n };\n /**\n * Clear all existing timeouts and interval polling delegates.\n *\n * @returns `undefined`\n * @private\n */\n var _clearTimeoutsAndPolling = function() {\n _clearTimeout(_flashCheckTimeout);\n _flashCheckTimeout = 0;\n _clearInterval(_swfFallbackCheckInterval);\n _swfFallbackCheckInterval = 0;\n };\n /**\n * Reposition the Flash object to cover the currently activated element.\n *\n * @returns `undefined`\n * @private\n */\n var _reposition = function() {\n var htmlBridge;\n if (_currentElement && (htmlBridge = _getHtmlBridge(_flashState.bridge))) {\n var pos = _getElementPosition(_currentElement);\n _extend(htmlBridge.style, {\n width: pos.width + \"px\",\n height: pos.height + \"px\",\n top: pos.top + \"px\",\n left: pos.left + \"px\",\n zIndex: \"\" + _getSafeZIndex(_globalConfig.zIndex)\n });\n }\n };\n /**\n * Sends a signal to the Flash object to display the hand cursor if `true`.\n *\n * @returns `undefined`\n * @private\n */\n var _setHandCursor = function(enabled) {\n if (_flashState.ready === true) {\n if (_flashState.bridge && typeof _flashState.bridge.setHandCursor === \"function\") {\n _flashState.bridge.setHandCursor(enabled);\n } else {\n _flashState.ready = false;\n }\n }\n };\n /**\n * Get a safe value for `zIndex`\n *\n * @returns an integer, or \"auto\"\n * @private\n */\n var _getSafeZIndex = function(val) {\n if (/^(?:auto|inherit)$/.test(val)) {\n return val;\n }\n var zIndex;\n if (typeof val === \"number\" && !_isNaN(val)) {\n zIndex = val;\n } else if (typeof val === \"string\") {\n zIndex = _getSafeZIndex(_parseInt(val, 10));\n }\n return typeof zIndex === \"number\" ? zIndex : \"auto\";\n };\n /**\n * Detect the Flash Player status, version, and plugin type.\n *\n * @see {@link https://code.google.com/p/doctype-mirror/wiki/ArticleDetectFlash#The_code}\n * @see {@link http://stackoverflow.com/questions/12866060/detecting-pepper-ppapi-flash-with-javascript}\n *\n * @returns `undefined`\n * @private\n */\n var _detectFlashSupport = function(ActiveXObject) {\n var plugin, ax, mimeType, hasFlash = false, isActiveX = false, isPPAPI = false, flashVersion = \"\";\n /**\n * Derived from Apple's suggested sniffer.\n * @param {String} desc e.g. \"Shockwave Flash 7.0 r61\"\n * @returns {String} \"7.0.61\"\n * @private\n */\n function parseFlashVersion(desc) {\n var matches = desc.match(/[\\d]+/g);\n matches.length = 3;\n return matches.join(\".\");\n }\n function isPepperFlash(flashPlayerFileName) {\n return !!flashPlayerFileName && (flashPlayerFileName = flashPlayerFileName.toLowerCase()) && (/^(pepflashplayer\\.dll|libpepflashplayer\\.so|pepperflashplayer\\.plugin)$/.test(flashPlayerFileName) || flashPlayerFileName.slice(-13) === \"chrome.plugin\");\n }\n function inspectPlugin(plugin) {\n if (plugin) {\n hasFlash = true;\n if (plugin.version) {\n flashVersion = parseFlashVersion(plugin.version);\n }\n if (!flashVersion && plugin.description) {\n flashVersion = parseFlashVersion(plugin.description);\n }\n if (plugin.filename) {\n isPPAPI = isPepperFlash(plugin.filename);\n }\n }\n }\n if (_navigator.plugins && _navigator.plugins.length) {\n plugin = _navigator.plugins[\"Shockwave Flash\"];\n inspectPlugin(plugin);\n if (_navigator.plugins[\"Shockwave Flash 2.0\"]) {\n hasFlash = true;\n flashVersion = \"2.0.0.11\";\n }\n } else if (_navigator.mimeTypes && _navigator.mimeTypes.length) {\n mimeType = _navigator.mimeTypes[\"application/x-shockwave-flash\"];\n plugin = mimeType && mimeType.enabledPlugin;\n inspectPlugin(plugin);\n } else if (typeof ActiveXObject !== \"undefined\") {\n isActiveX = true;\n try {\n ax = new ActiveXObject(\"ShockwaveFlash.ShockwaveFlash.7\");\n hasFlash = true;\n flashVersion = parseFlashVersion(ax.GetVariable(\"$version\"));\n } catch (e1) {\n try {\n ax = new ActiveXObject(\"ShockwaveFlash.ShockwaveFlash.6\");\n hasFlash = true;\n flashVersion = \"6.0.21\";\n } catch (e2) {\n try {\n ax = new ActiveXObject(\"ShockwaveFlash.ShockwaveFlash\");\n hasFlash = true;\n flashVersion = parseFlashVersion(ax.GetVariable(\"$version\"));\n } catch (e3) {\n isActiveX = false;\n }\n }\n }\n }\n _flashState.disabled = hasFlash !== true;\n _flashState.outdated = flashVersion && _parseFloat(flashVersion) < _parseFloat(_minimumFlashVersion);\n _flashState.version = flashVersion || \"0.0.0\";\n _flashState.pluginType = isPPAPI ? \"pepper\" : isActiveX ? \"activex\" : hasFlash ? \"netscape\" : \"unknown\";\n };\n /**\n * Invoke the Flash detection algorithms immediately upon inclusion so we're not waiting later.\n */\n _detectFlashSupport(_ActiveXObject);\n /**\n * A shell constructor for `ZeroClipboard` client instances.\n *\n * @constructor\n */\n var ZeroClipboard = function() {\n if (!(this instanceof ZeroClipboard)) {\n return new ZeroClipboard();\n }\n if (typeof ZeroClipboard._createClient === \"function\") {\n ZeroClipboard._createClient.apply(this, _args(arguments));\n }\n };\n /**\n * The ZeroClipboard library's version number.\n *\n * @static\n * @readonly\n * @property {string}\n */\n _defineProperty(ZeroClipboard, \"version\", {\n value: \"2.2.0-beta.3\",\n writable: false,\n configurable: true,\n enumerable: true\n });\n /**\n * Update or get a copy of the ZeroClipboard global configuration.\n * Returns a copy of the current/updated configuration.\n *\n * @returns Object\n * @static\n */\n ZeroClipboard.config = function() {\n return _config.apply(this, _args(arguments));\n };\n /**\n * Diagnostic method that describes the state of the browser, Flash Player, and ZeroClipboard.\n *\n * @returns Object\n * @static\n */\n ZeroClipboard.state = function() {\n return _state.apply(this, _args(arguments));\n };\n /**\n * Check if Flash is unusable for any reason: disabled, outdated, deactivated, etc.\n *\n * @returns Boolean\n * @static\n */\n ZeroClipboard.isFlashUnusable = function() {\n return _isFlashUnusable.apply(this, _args(arguments));\n };\n /**\n * Register an event listener.\n *\n * @returns `ZeroClipboard`\n * @static\n */\n ZeroClipboard.on = function() {\n return _on.apply(this, _args(arguments));\n };\n /**\n * Unregister an event listener.\n * If no `listener` function/object is provided, it will unregister all listeners for the provided `eventType`.\n * If no `eventType` is provided, it will unregister all listeners for every event type.\n *\n * @returns `ZeroClipboard`\n * @static\n */\n ZeroClipboard.off = function() {\n return _off.apply(this, _args(arguments));\n };\n /**\n * Retrieve event listeners for an `eventType`.\n * If no `eventType` is provided, it will retrieve all listeners for every event type.\n *\n * @returns array of listeners for the `eventType`; if no `eventType`, then a map/hash object of listeners for all event types; or `null`\n */\n ZeroClipboard.handlers = function() {\n return _listeners.apply(this, _args(arguments));\n };\n /**\n * Event emission receiver from the Flash object, forwarding to any registered JavaScript event listeners.\n *\n * @returns For the \"copy\" event, returns the Flash-friendly \"clipData\" object; otherwise `undefined`.\n * @static\n */\n ZeroClipboard.emit = function() {\n return _emit.apply(this, _args(arguments));\n };\n /**\n * Create and embed the Flash object.\n *\n * @returns The Flash object\n * @static\n */\n ZeroClipboard.create = function() {\n return _create.apply(this, _args(arguments));\n };\n /**\n * Self-destruct and clean up everything, including the embedded Flash object.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.destroy = function() {\n return _destroy.apply(this, _args(arguments));\n };\n /**\n * Set the pending data for clipboard injection.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.setData = function() {\n return _setData.apply(this, _args(arguments));\n };\n /**\n * Clear the pending data for clipboard injection.\n * If no `format` is provided, all pending data formats will be cleared.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.clearData = function() {\n return _clearData.apply(this, _args(arguments));\n };\n /**\n * Get a copy of the pending data for clipboard injection.\n * If no `format` is provided, a copy of ALL pending data formats will be returned.\n *\n * @returns `String` or `Object`\n * @static\n */\n ZeroClipboard.getData = function() {\n return _getData.apply(this, _args(arguments));\n };\n /**\n * Sets the current HTML object that the Flash object should overlay. This will put the global\n * Flash object on top of the current element; depending on the setup, this may also set the\n * pending clipboard text data as well as the Flash object's wrapping element's title attribute\n * based on the underlying HTML element and ZeroClipboard configuration.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.focus = ZeroClipboard.activate = function() {\n return _focus.apply(this, _args(arguments));\n };\n /**\n * Un-overlays the Flash object. This will put the global Flash object off-screen; depending on\n * the setup, this may also unset the Flash object's wrapping element's title attribute based on\n * the underlying HTML element and ZeroClipboard configuration.\n *\n * @returns `undefined`\n * @static\n */\n ZeroClipboard.blur = ZeroClipboard.deactivate = function() {\n return _blur.apply(this, _args(arguments));\n };\n /**\n * Returns the currently focused/\"activated\" HTML element that the Flash object is wrapping.\n *\n * @returns `HTMLElement` or `null`\n * @static\n */\n ZeroClipboard.activeElement = function() {\n return _activeElement.apply(this, _args(arguments));\n };\n /**\n * Keep track of the ZeroClipboard client instance counter.\n */\n var _clientIdCounter = 0;\n /**\n * Keep track of the state of the client instances.\n *\n * Entry structure:\n * _clientMeta[client.id] = {\n * instance: client,\n * elements: [],\n * handlers: {}\n * };\n */\n var _clientMeta = {};\n /**\n * Keep track of the ZeroClipboard clipped elements counter.\n */\n var _elementIdCounter = 0;\n /**\n * Keep track of the state of the clipped element relationships to clients.\n *\n * Entry structure:\n * _elementMeta[element.zcClippingId] = [client1.id, client2.id];\n */\n var _elementMeta = {};\n /**\n * Keep track of the state of the mouse event handlers for clipped elements.\n *\n * Entry structure:\n * _mouseHandlers[element.zcClippingId] = {\n * mouseover: function(event) {},\n * mouseout: function(event) {},\n * mouseenter: function(event) {},\n * mouseleave: function(event) {},\n * mousemove: function(event) {}\n * };\n */\n var _mouseHandlers = {};\n /**\n * Extending the ZeroClipboard configuration defaults for the Client module.\n */\n _extend(_globalConfig, {\n autoActivate: true\n });\n /**\n * The real constructor for `ZeroClipboard` client instances.\n * @private\n */\n var _clientConstructor = function(elements) {\n var client = this;\n client.id = \"\" + _clientIdCounter++;\n _clientMeta[client.id] = {\n instance: client,\n elements: [],\n handlers: {}\n };\n if (elements) {\n client.clip(elements);\n }\n ZeroClipboard.on(\"*\", function(event) {\n return client.emit(event);\n });\n ZeroClipboard.on(\"destroy\", function() {\n client.destroy();\n });\n ZeroClipboard.create();\n };\n /**\n * The underlying implementation of `ZeroClipboard.Client.prototype.on`.\n * @private\n */\n var _clientOn = function(eventType, listener) {\n var i, len, events, added = {}, meta = _clientMeta[this.id], handlers = meta && meta.handlers;\n if (!meta) {\n throw new Error(\"Attempted to add new listener(s) to a destroyed ZeroClipboard client instance\");\n }\n if (typeof eventType === \"string\" && eventType) {\n events = eventType.toLowerCase().split(/\\s+/);\n } else if (typeof eventType === \"object\" && eventType && typeof listener === \"undefined\") {\n for (i in eventType) {\n if (_hasOwn.call(eventType, i) && typeof i === \"string\" && i && typeof eventType[i] === \"function\") {\n this.on(i, eventType[i]);\n }\n }\n }\n if (events && events.length) {\n for (i = 0, len = events.length; i < len; i++) {\n eventType = events[i].replace(/^on/, \"\");\n added[eventType] = true;\n if (!handlers[eventType]) {\n handlers[eventType] = [];\n }\n handlers[eventType].push(listener);\n }\n if (added.ready && _flashState.ready) {\n this.emit({\n type: \"ready\",\n client: this\n });\n }\n if (added.error) {\n var flashErrorTypes = [ \"disabled\", \"outdated\", \"unavailable\", \"degraded\", \"deactivated\", \"overdue\" ];\n for (i = 0, len = flashErrorTypes.length; i < len; i++) {\n if (_flashState[flashErrorTypes[i]]) {\n this.emit({\n type: \"error\",\n name: \"flash-\" + flashErrorTypes[i],\n client: this\n });\n break;\n }\n }\n if (_zcSwfVersion !== undefined && ZeroClipboard.version !== _zcSwfVersion) {\n this.emit({\n type: \"error\",\n name: \"version-mismatch\",\n jsVersion: ZeroClipboard.version,\n swfVersion: _zcSwfVersion\n });\n }\n }\n }\n return this;\n };\n /**\n * The underlying implementation of `ZeroClipboard.Client.prototype.off`.\n * @private\n */\n var _clientOff = function(eventType, listener) {\n var i, len, foundIndex, events, perEventHandlers, meta = _clientMeta[this.id], handlers = meta && meta.handlers;\n if (!handlers) {\n return this;\n }\n if (arguments.length === 0) {\n events = _keys(handlers);\n } else if (typeof eventType === \"string\" && eventType) {\n events = eventType.split(/\\s+/);\n } else if (typeof eventType === \"object\" && eventType && typeof listener === \"undefined\") {\n for (i in eventType) {\n if (_hasOwn.call(eventType, i) && typeof i === \"string\" && i && typeof eventType[i] === \"function\") {\n this.off(i, eventType[i]);\n }\n }\n }\n if (events && events.length) {\n for (i = 0, len = events.length; i < len; i++) {\n eventType = events[i].toLowerCase().replace(/^on/, \"\");\n perEventHandlers = handlers[eventType];\n if (perEventHandlers && perEventHandlers.length) {\n if (listener) {\n foundIndex = perEventHandlers.indexOf(listener);\n while (foundIndex !== -1) {\n perEventHandlers.splice(foundIndex, 1);\n foundIndex = perEventHandlers.indexOf(listener, foundIndex);\n }\n } else {\n perEventHandlers.length = 0;\n }\n }\n }\n }\n return this;\n };\n /**\n * The underlying implementation of `ZeroClipboard.Client.prototype.handlers`.\n * @private\n */\n var _clientListeners = function(eventType) {\n var copy = null, handlers = _clientMeta[this.id] && _clientMeta[this.id].handlers;\n if (handlers) {\n if (typeof eventType === \"string\" && eventType) {\n copy = handlers[eventType] ? handlers[eventType].slice(0) : [];\n } else {\n copy = _deepCopy(handlers);\n }\n }\n return copy;\n };\n /**\n * The underlying implementation of `ZeroClipboard.Client.prototype.emit`.\n * @private\n */\n var _clientEmit = function(event) {\n if (_clientShouldEmit.call(this, event)) {\n if (typeof event === \"object\" && event && typeof event.type === \"string\" && event.type) {\n event = _extend({}, event);\n }\n var eventCopy = _extend({}, _createEvent(event), {\n client: this\n });\n _clientDispatchCallbacks.call(this, eventCopy);\n }\n return this;\n };\n /**\n * The underlying implementation of `ZeroClipboard.Client.prototype.clip`.\n * @private\n */\n var _clientClip = function(elements) {\n if (!_clientMeta[this.id]) {\n throw new Error(\"Attempted to clip element(s) to a destroyed ZeroClipboard client instance\");\n }\n elements = _prepClip(elements);\n for (var i = 0; i < elements.length; i++) {\n if (_hasOwn.call(elements, i) && elements[i] && elements[i].nodeType === 1) {\n if (!elements[i].zcClippingId) {\n elements[i].zcClippingId = \"zcClippingId_\" + _elementIdCounter++;\n _elementMeta[elements[i].zcClippingId] = [ this.id ];\n if (_globalConfig.autoActivate === true) {\n _addMouseHandlers(elements[i]);\n }\n } else if (_elementMeta[elements[i].zcClippingId].indexOf(this.id) === -1) {\n _elementMeta[elements[i].zcClippingId].push(this.id);\n }\n var clippedElements = _clientMeta[this.id] && _clientMeta[this.id].elements;\n if (clippedElements.indexOf(elements[i]) === -1) {\n clippedElements.push(elements[i]);\n }\n }\n }\n return this;\n };\n /**\n * The underlying implementation of `ZeroClipboard.Client.prototype.unclip`.\n * @private\n */\n var _clientUnclip = function(elements) {\n var meta = _clientMeta[this.id];\n if (!meta) {\n return this;\n }\n var clippedElements = meta.elements;\n var arrayIndex;\n if (typeof elements === \"undefined\") {\n elements = clippedElements.slice(0);\n } else {\n elements = _prepClip(elements);\n }\n for (var i = elements.length; i--; ) {\n if (_hasOwn.call(elements, i) && elements[i] && elements[i].nodeType === 1) {\n arrayIndex = 0;\n while ((arrayIndex = clippedElements.indexOf(elements[i], arrayIndex)) !== -1) {\n clippedElements.splice(arrayIndex, 1);\n }\n var clientIds = _elementMeta[elements[i].zcClippingId];\n if (clientIds) {\n arrayIndex = 0;\n while ((arrayIndex = clientIds.indexOf(this.id, arrayIndex)) !== -1) {\n clientIds.splice(arrayIndex, 1);\n }\n if (clientIds.length === 0) {\n if (_globalConfig.autoActivate === true) {\n _removeMouseHandlers(elements[i]);\n }\n delete elements[i].zcClippingId;\n }\n }\n }\n }\n return this;\n };\n /**\n * The underlying implementation of `ZeroClipboard.Client.prototype.elements`.\n * @private\n */\n var _clientElements = function() {\n var meta = _clientMeta[this.id];\n return meta && meta.elements ? meta.elements.slice(0) : [];\n };\n /**\n * The underlying implementation of `ZeroClipboard.Client.prototype.destroy`.\n * @private\n */\n var _clientDestroy = function() {\n if (!_clientMeta[this.id]) {\n return;\n }\n this.unclip();\n this.off();\n delete _clientMeta[this.id];\n };\n /**\n * Inspect an Event to see if the Client (`this`) should honor it for emission.\n * @private\n */\n var _clientShouldEmit = function(event) {\n if (!(event && event.type)) {\n return false;\n }\n if (event.client && event.client !== this) {\n return false;\n }\n var meta = _clientMeta[this.id];\n var clippedEls = meta && meta.elements;\n var hasClippedEls = !!clippedEls && clippedEls.length > 0;\n var goodTarget = !event.target || hasClippedEls && clippedEls.indexOf(event.target) !== -1;\n var goodRelTarget = event.relatedTarget && hasClippedEls && clippedEls.indexOf(event.relatedTarget) !== -1;\n var goodClient = event.client && event.client === this;\n if (!meta || !(goodTarget || goodRelTarget || goodClient)) {\n return false;\n }\n return true;\n };\n /**\n * Handle the actual dispatching of events to a client instance.\n *\n * @returns `undefined`\n * @private\n */\n var _clientDispatchCallbacks = function(event) {\n var meta = _clientMeta[this.id];\n if (!(typeof event === \"object\" && event && event.type && meta)) {\n return;\n }\n var async = _shouldPerformAsync(event);\n var wildcardTypeHandlers = meta && meta.handlers[\"*\"] || [];\n var specificTypeHandlers = meta && meta.handlers[event.type] || [];\n var handlers = wildcardTypeHandlers.concat(specificTypeHandlers);\n if (handlers && handlers.length) {\n var i, len, func, context, eventCopy, originalContext = this;\n for (i = 0, len = handlers.length; i < len; i++) {\n func = handlers[i];\n context = originalContext;\n if (typeof func === \"string\" && typeof _window[func] === \"function\") {\n func = _window[func];\n }\n if (typeof func === \"object\" && func && typeof func.handleEvent === \"function\") {\n context = func;\n func = func.handleEvent;\n }\n if (typeof func === \"function\") {\n eventCopy = _extend({}, event);\n _dispatchCallback(func, context, [ eventCopy ], async);\n }\n }\n }\n };\n /**\n * Prepares the elements for clipping/unclipping.\n *\n * @returns An Array of elements.\n * @private\n */\n var _prepClip = function(elements) {\n if (typeof elements === \"string\") {\n elements = [];\n }\n return typeof elements.length !== \"number\" ? [ elements ] : elements;\n };\n /**\n * Add a `mouseover` handler function for a clipped element.\n *\n * @returns `undefined`\n * @private\n */\n var _addMouseHandlers = function(element) {\n if (!(element && element.nodeType === 1)) {\n return;\n }\n var _suppressMouseEvents = function(event) {\n if (!(event || (event = _window.event))) {\n return;\n }\n if (event._source !== \"js\") {\n event.stopImmediatePropagation();\n event.preventDefault();\n }\n delete event._source;\n };\n var _elementMouseOver = function(event) {\n if (!(event || (event = _window.event))) {\n return;\n }\n _suppressMouseEvents(event);\n ZeroClipboard.focus(element);\n };\n element.addEventListener(\"mouseover\", _elementMouseOver, false);\n element.addEventListener(\"mouseout\", _suppressMouseEvents, false);\n element.addEventListener(\"mouseenter\", _suppressMouseEvents, false);\n element.addEventListener(\"mouseleave\", _suppressMouseEvents, false);\n element.addEventListener(\"mousemove\", _suppressMouseEvents, false);\n _mouseHandlers[element.zcClippingId] = {\n mouseover: _elementMouseOver,\n mouseout: _suppressMouseEvents,\n mouseenter: _suppressMouseEvents,\n mouseleave: _suppressMouseEvents,\n mousemove: _suppressMouseEvents\n };\n };\n /**\n * Remove a `mouseover` handler function for a clipped element.\n *\n * @returns `undefined`\n * @private\n */\n var _removeMouseHandlers = function(element) {\n if (!(element && element.nodeType === 1)) {\n return;\n }\n var mouseHandlers = _mouseHandlers[element.zcClippingId];\n if (!(typeof mouseHandlers === \"object\" && mouseHandlers)) {\n return;\n }\n var key, val, mouseEvents = [ \"move\", \"leave\", \"enter\", \"out\", \"over\" ];\n for (var i = 0, len = mouseEvents.length; i < len; i++) {\n key = \"mouse\" + mouseEvents[i];\n val = mouseHandlers[key];\n if (typeof val === \"function\") {\n element.removeEventListener(key, val, false);\n }\n }\n delete _mouseHandlers[element.zcClippingId];\n };\n /**\n * Creates a new ZeroClipboard client instance.\n * Optionally, auto-`clip` an element or collection of elements.\n *\n * @constructor\n */\n ZeroClipboard._createClient = function() {\n _clientConstructor.apply(this, _args(arguments));\n };\n /**\n * Register an event listener to the client.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.on = function() {\n return _clientOn.apply(this, _args(arguments));\n };\n /**\n * Unregister an event handler from the client.\n * If no `listener` function/object is provided, it will unregister all handlers for the provided `eventType`.\n * If no `eventType` is provided, it will unregister all handlers for every event type.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.off = function() {\n return _clientOff.apply(this, _args(arguments));\n };\n /**\n * Retrieve event listeners for an `eventType` from the client.\n * If no `eventType` is provided, it will retrieve all listeners for every event type.\n *\n * @returns array of listeners for the `eventType`; if no `eventType`, then a map/hash object of listeners for all event types; or `null`\n */\n ZeroClipboard.prototype.handlers = function() {\n return _clientListeners.apply(this, _args(arguments));\n };\n /**\n * Event emission receiver from the Flash object for this client's registered JavaScript event listeners.\n *\n * @returns For the \"copy\" event, returns the Flash-friendly \"clipData\" object; otherwise `undefined`.\n */\n ZeroClipboard.prototype.emit = function() {\n return _clientEmit.apply(this, _args(arguments));\n };\n /**\n * Register clipboard actions for new element(s) to the client.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.clip = function() {\n return _clientClip.apply(this, _args(arguments));\n };\n /**\n * Unregister the clipboard actions of previously registered element(s) on the page.\n * If no elements are provided, ALL registered elements will be unregistered.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.unclip = function() {\n return _clientUnclip.apply(this, _args(arguments));\n };\n /**\n * Get all of the elements to which this client is clipped.\n *\n * @returns array of clipped elements\n */\n ZeroClipboard.prototype.elements = function() {\n return _clientElements.apply(this, _args(arguments));\n };\n /**\n * Self-destruct and clean up everything for a single client.\n * This will NOT destroy the embedded Flash object.\n *\n * @returns `undefined`\n */\n ZeroClipboard.prototype.destroy = function() {\n return _clientDestroy.apply(this, _args(arguments));\n };\n /**\n * Stores the pending plain text to inject into the clipboard.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.setText = function(text) {\n if (!_clientMeta[this.id]) {\n throw new Error(\"Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance\");\n }\n ZeroClipboard.setData(\"text/plain\", text);\n return this;\n };\n /**\n * Stores the pending HTML text to inject into the clipboard.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.setHtml = function(html) {\n if (!_clientMeta[this.id]) {\n throw new Error(\"Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance\");\n }\n ZeroClipboard.setData(\"text/html\", html);\n return this;\n };\n /**\n * Stores the pending rich text (RTF) to inject into the clipboard.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.setRichText = function(richText) {\n if (!_clientMeta[this.id]) {\n throw new Error(\"Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance\");\n }\n ZeroClipboard.setData(\"application/rtf\", richText);\n return this;\n };\n /**\n * Stores the pending data to inject into the clipboard.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.setData = function() {\n if (!_clientMeta[this.id]) {\n throw new Error(\"Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance\");\n }\n ZeroClipboard.setData.apply(this, _args(arguments));\n return this;\n };\n /**\n * Clears the pending data to inject into the clipboard.\n * If no `format` is provided, all pending data formats will be cleared.\n *\n * @returns `this`\n */\n ZeroClipboard.prototype.clearData = function() {\n if (!_clientMeta[this.id]) {\n throw new Error(\"Attempted to clear pending clipboard data from a destroyed ZeroClipboard client instance\");\n }\n ZeroClipboard.clearData.apply(this, _args(arguments));\n return this;\n };\n /**\n * Gets a copy of the pending data to inject into the clipboard.\n * If no `format` is provided, a copy of ALL pending data formats will be returned.\n *\n * @returns `String` or `Object`\n */\n ZeroClipboard.prototype.getData = function() {\n if (!_clientMeta[this.id]) {\n throw new Error(\"Attempted to get pending clipboard data from a destroyed ZeroClipboard client instance\");\n }\n return ZeroClipboard.getData.apply(this, _args(arguments));\n };\n if (typeof define === \"function\" && define.amd) {\n define(function() {\n return ZeroClipboard;\n });\n } else if (typeof module === \"object\" && module && typeof module.exports === \"object\" && module.exports) {\n module.exports = ZeroClipboard;\n } else {\n window.ZeroClipboard = ZeroClipboard;\n }\n})(function() {\n return this || window;\n}());"]} \ No newline at end of file diff --git a/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.swf b/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.swf new file mode 100644 index 0000000000000000000000000000000000000000..de3fb358083b7322a944485c0893ddb70a4ecf10 GIT binary patch literal 6586 zcmV;r8AawpS5pqfF8}~|+O;|hc$3$4_xw*umW3pYG4CHRmTj(WK^{#o5R7es9YDkn zLI7j^mVQ|RS#tDCek5ci1n1S})g+`1B~@Q(+R&s)wsqasbxqrKYr9U8hv~YlUAuMd z-dp#6vUC6cmt-50w%^wpU)_7pJ@=e*&pG#;b7iK8@O?sDFB4J+q|3945c2NjUk5^V zrX$fEeO&=%YAlh|ci?Q7FP6!S?`UhAoSbZ(ys0&n9&Oup`|Y>4`M0-i-`;{4E&6ma zqfWIX_07KB27xY352xefnRqIxu(>*t%4T-?d=}M6xJ-0Bn@$)cBjGkJp^a(DjNZ1b zbsG|jgm*+!=`l64TOA)y#KS5h*EZFn$5P?blj?-l5>2RjY-d{qk?qOEGYM^XMa@SyZ45C!E&QOll!U3C7kFYH~EIj%vHR4;gFaxgn#P(RO!fVP)IRRN3y| zcC#r4gYIlwq-_g=2HZ`$+&|)Xl1}d0wQI*5JX%=7CP*JXMvR|tq`tea7cKrx$1yFP z>P*DPM^b7!LcUOQzJ(B6Aknlsrfnl`(n=T+nQ+AVd6Of;L@FMU_oh+_O-)L{kyBbY zQ*9WeH4@jy6Y8|oKc0?fG^YvFCYWg*2UA&H>tcKQ+6wUV~=8?UQg0s)zq#i4=9S3(6yz>rwj$Z19^-LO5=o@ zR^rIS-;UkR`IrdUy46B8WjP)nLd?ZyM(9$K}Lf1ur4a*ggo zox!ed<`@HIztEE5R77K30!WPAq{g!B7Mbf^$J{j7*Te2ZDv8&sX+EE>?h>EDGM|W6 z=7U%Gr)6aBTFj_w9^$eE2k7m0FJ#o)zudfGhZAZ%IiO8tg2}|R*MyaBBSV(aHmr9u z8zD*=-=%BmxSELHrx~%$rmGl}aONrv%z#lH*N-4pgas!I6&Qwe?XIkro)+~CCIQh1 zKCX_gF1*GA!QuXaj(y!M78&pZaXq6YwX`&n&16!^YAZZ-X47clQ$3r=v^yLz^HMX)7!a&rfwR^Hna_wEzLLbg zcS3DtiE0r(JK0*3HH)o_x3oJ1yzGvX*GH|NQiz{QfV#2(ir3T9S+t(69g0ucT6UABc8AC`=-8lG zmSv~xG&E6hFSK^u!lRat$c|>H#ypwBQ;uXMN8ui5s>R$8zCQ7b8at|x#Olmr+<}&C zQk_ua33Vi)xlBkz8%?Vbja5)buu?&jxF^iMWh}0bu}k7W)mm%I!l`65K3ZO~jazxf zTEN;Sf*~raRpI5#stIFUt!tS|s1dQ8jZAyA#f8-}t8gn_Lw5ky8`6A`pT zr3}Ej0LP_zz_HPk!{WPW7ghu9j(HingoOfG!$m?J?&#|{Xk4HYE{hr+8I1oJx3xwe zGbYN6Va4ZbYR#k$q$ag=r>bkH6!T^=g<_=Ajg#G`EYK6n`Ad?WV1_d3nvQ0(623z+ zyQZIT74`C6TvfV@6_r@N3wLZBO{7NDM9Y16rOJi5`8;bGNyj6jnq<};Y^zKHa!-Pn&|BL(V5EP8!3Y5@r0cvab}mJ z<Jh^Z_F7stWiV1M`U!Qhc@Ylx#hyEPmf zuz+2`yARpS;oxDh^FUAMoy!(w-0B6%*>hbguU)zVkjx7xnUU3deR=4;zL2w(!mt!e zu|lPKBp!*QkysE>6E>_CSR{-ri&}52ZsT3GKJ2r8fXxGo7 z>S%YC10?cUZ_#TVzP?&V9?-s_jIczRjTk&eiF7$RZQOW$-LfQQ_U1ah{Pj@nSb^6iyi5-ink?^V#fS=Xo{BJPMVJ16X~CfmR{aw;8r$mFcHk8 zx5T=)EJbOh{iAS$`tJCWREB+PKtsG1(tt-QL#F&mE$wdxoM@x_5m8WGtrrry-lzO6!|oc`t=rqw9@ z8yP!lFljPHFFWy#^wellYic)hWBbY*)Na)as#0g^&`b&TNz6SMas$cb*4Hb6d8^!} z_Kq8Q#|@Rb*ml03Yz9LvpXu7{E2notZ@1nkOi|@mO6o>$lwXiP?k-7C@`t6Yb7O~a zEvSSVYnqmDfvt-jUYD7)TBF z9dKal)9%e`dZy|WCJOWW*d5TwHMNVwx|WDa{l zp!+CRQ^CH29Ro7TVsNym39-yrqH6!Z!2=copUy<9C)tC3a3H`$(A}7c_YcpbA&xLG zmNvSMwTEn!LOosV%Zu>oY7D;pY%qYufF_yW(>puWadjk)sX4CcTuK)WyNZ}4vr|%^ zHj2+L?!*ZgMKxf>5Z2b7Jl@fAOl`Su$m;zqw-4_)(Q=}7sJR|hs%PXl)?8D;C~RK0 z1#tpuOB8X2?r1!IvNAhU-^6e6`^7EWZ}I#2hK8-s;6%gWD<#hIy3UW|O|OMou~x2g ziex3!EfYzd2U|mJmq={;S36httnOWX=jsEi4~k^^fu*f?WgqDUc;ymNK%G zwa);^+#`6nN3lJI_zCQv#P$@nr?EYQ?S0su#r7Pw=doSD_5#>10@yEM zdkN{mhmhH8um(pj;pj79f0IGq!p7A2E7*P&+h?);8p!B3Tzs2@_M!?eu_D66oJ<7?_ zW1PI^J)FGu31ssmwx@9XH1^M6dmm?ij_rG%vtMBS3kZ8Z?)d=rqcXgR-9>DdINA9j z>~oy#`Y^XfuzPqstGGtQvx+i&6u~cJdj;DkIl1mLoc#?>v^VgrrN85_Kl1=^#(*R2 zZ$zvK3@8%9@e)sL;B*=@5QOqJ_Lm^p{3DV1VG-kuf0Bt{{kcfs(DexiATbPy2y9d) z#R1O~&in)pxf>rmZ<8dGpbhYW30BYZWWMP5VW4sBgO@66M6lyO0!{}ZlG9m5h|}q; zCdB1*E<>VjAc6;o=tX&!1CeWh;4LNgS|E;*HuIa`8cX@3Dfo|eP9pyu}MQ_hX-N7B)K4t^X;jo3;3k{dmoj4b&IEV8sKJUM~ z`HEiyK z%2x?7ws&1<_ModbMR44JV;7Fi1p{*Vf_GbK=V^M%Tshb5K}T&;&e4Q{RGts=jC8^v z%_FfYlNiUQNNIbC(ilzBAWboFh1NL3tdJ5Isg1Y;!9s8)Q!Bl94MS-_Fo`JkynVCalUcvq6CYrr=q;4vU&1}|e9hvZs7`mbp zXeiT!B~wl2=v0nQ=jeSodVh|d$2aF%!DnNS9lqOc!ttWB^xE;GpxfNf5hxr*vI2Xx;NLNy;fr3?y8;(!M|tQiwD zX&NMK`&==)*E$1^o~IANW$$uAa6EH0v}HDM3wSZ|6lT@E#ps?g;vN&xi7Pmv=OM5k z)IG&$Cw&+$H+v)lsk7m-vA03(EJnN7j@6Q}p-b&zLdzm&cLdp$3iU*L)jP325Iv|K z!af*1tll*w^a|*gR|?U-76|qO_VuJW^seXtw!z>Lq0k2E-AMju!Kd!b7lQWyBWq*2 z*kh<-j-Bypp1vQA3VHeg2&_QW&E=!j#Xvn6OD_Vw2(!^+^n*~OmvD64@Ho7^b{^^M z%KM8-4XTS#nkyF66QLot&oH;wW7szzbrb^%hhVp(3FX{B8=#Kli_sHB^Y~RfTIa63zYr3m;e50fLmV4MDnqR@j8=xDm0>I&t*HzRD5}JX ziOse-@7G9(_lM&C&?$fDv_F*ahXnjRO4b=aF+0jojag1;!MNWQK6g5jynUKWrF(Xo2+x)(!8 zF;eJ&b64DtqCY-Qe`^s!Jt4T;jn=gnW{0*GW~0esU@NC4-{xl#WyKG#U2`9*>|~dz zz;wNX?F)+qW|_^4ERzB+#!DO_J+y>HkXd8Sv<6enGM?jkJ7R>!aTx*bGT>el;Hd&Z zMCIk_7eS$KgO7d*+n2F@1$={Itj@?-t60YJ^1SGH0ZQ4&hj}HwuDUIiLCQboT7fnPEu9Rv4@MUooiQBWr4eyAEa ziZZ;L$xs8RSQ{#qF+)YK;BdaeoKH@e?qM8b0vBu9Vht{05SX`iKU-UgY8TfGwG;v^ zaP}-*2|Wn;LZE{?H#bC!0SbsxS0jk>XAR3-HR=L+jK^+fOwgdfWGu2wpWu`lo0+U2 zxB(b1?^%`y_pCHGgnVo%huaLb3oQ2;x$K*ZwDzY!zhe{*=JdO4ESTdz161+%fPNq7 zp9B31pg#cmmq33A^hdyS`d2{znyGcUsn(zZm>bUlR*~dEEDL4w5D;D_=dnDL$f{~y z5brV4qap2`n74d|+{|1kT~ux?Ss_RN9>+lc0q8#h{ig+to%0xz)eb=rvzRf4&Rs2_ z;#rg!V;0;hh>B12x2Jk_~ zOm=msWfskN?kWrAYeZ2HpEa^S3&29bdmgRB&bgdLeI;Moi6xsm&Omk1`#d2G^kCq- z8!#lyh8~6@yZ?bl08MvwM5u>cG5RPt@hr3Szae+^ZDB-UkQMoB*M=U0p~rzwma=G5e0q8j{_!zKYy%u9C@6P*&-UBSC@<(A^%!%-I2o|sa#o>As-ySLX zT*=Ks?=>sRCm{GFupt+H3L4ZWzhn!G=@(@$fa=!pyxUIFc;X) z2cH4FTEaeXH?`Q#aPI?FLOqLK!jlb*`4{<$$3F+mgUeDp577${d;y3hj1{!)rONRM znD8DqYCtA}i5_}CL_biHKJX%NKeN=&&Xd}pbMZRH7jMA$gJ3Nij4xIg!*z@=E@J%L z5{xfh$M_O5ev&aBdJcM@17c|`!CR}rmke|9cnhqOm`9&s*=zk0;(o}$HDtY1k(Ikn z)=P_Iy|7T$ef%C(vz_@Id>g(4wli;X5A%=nwln;EQ|B-spu7sl@xn01UMoqmOvA2h zkCA4}7M85(M6+jwF}%2N{R|tFzNaX?Y5?7?|*+B_6ZWcH} ztjC-Y`Zz>iMoZO;flmO3)ffE;clknW6U*F%;AR%*>UqTVB5ppqX~HB{m{2$2$`)Q0 z#Fxz=D;vi9W`4C5b%Q+d9cwo zmKdT8w&awUfPg3W1whjrLfj(y|#w`IO=24XoIjb9-5lRz&1t^i}pU zQeTC)xgtYa@dGT=4lGfo-DZ?&0;)-5uR;5WI3l2$P(7Ccyvx{Y2kFh0>1`JU&$m!X zqD^2$T9bgD?MDxI2uxS8{H+c*hCYpTJV!sy?d7l!yawEin`0RO_cgN{;hVRQDYkF{ zoeNnuv7Mjb_Cg`>IvAe4Rgih%VJ`1)od0h4F*3n-VBj+V*{iel*H*chxR^uGm%!pR zbEQB(#g$PmGhZ&uxY107dNRwLZU#{p!&fa)!I0F1UAADK=H>xkvw*LcfL=^+LvKK# z_YGh#D&}@Y=63t$mA%E%gMF)~%dhx#u`R6TUCzGaTKK=S_aNl|0nDq+Ij4ZJc>n+a literal 0 HcmV?d00001 From 000705d221d77e0781d5220bdd176d90cdbcef10 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Tue, 16 Dec 2014 16:42:33 +0000 Subject: [PATCH 030/295] Remove extra empty column --- .../inc/class.importexport_wizard_basic_export_csv.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/importexport/inc/class.importexport_wizard_basic_export_csv.inc.php b/importexport/inc/class.importexport_wizard_basic_export_csv.inc.php index 98286e3d43..cbfc880a1b 100644 --- a/importexport/inc/class.importexport_wizard_basic_export_csv.inc.php +++ b/importexport/inc/class.importexport_wizard_basic_export_csv.inc.php @@ -98,6 +98,7 @@ class importexport_wizard_basic_export_csv $content['mapping']['all_custom_fields'] = $appname; } unset($content['mapping']['']); + unset($content['mapping'][0]); unset($content['fields']); switch (array_search('pressed', $content['button'])) { From 9e768dcaac2c5948e276d2fc0d94bd7719685b46 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Tue, 16 Dec 2014 17:06:42 +0000 Subject: [PATCH 031/295] Stop taglist's ancestor change event from bubbling on taglist --- etemplate/js/et2_widget_taglist.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/etemplate/js/et2_widget_taglist.js b/etemplate/js/et2_widget_taglist.js index 59857f04fb..708d454cf4 100644 --- a/etemplate/js/et2_widget_taglist.js +++ b/etemplate/js/et2_widget_taglist.js @@ -185,6 +185,10 @@ var et2_taglist = et2_selectbox.extend( .on("beforeload", function() {this.container.prepend('
');}) .on("load", function() {$j('.loading',this.container).remove();}); + // Unbind change handler of widget's ancestor to stop it from bubbling + // taglist has its own onchange + $j(this.getDOMNode()).unbind('change.et2_inputWidget'); + // onChange if(this.options.onchange && typeof this.options.onchange == 'function') { From d3e404fad990d0edad4700f5016789081029cba6 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Tue, 16 Dec 2014 18:57:41 +0000 Subject: [PATCH 032/295] Explicitly configure flash location to work with JS minification --- phpgwapi/js/egw_action/egw_action_popup.js | 2 ++ phpgwapi/js/zeroclipboard/dist/ZeroClipboard.min.js | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/phpgwapi/js/egw_action/egw_action_popup.js b/phpgwapi/js/egw_action/egw_action_popup.js index 62b28c28c8..656d8a3319 100644 --- a/phpgwapi/js/egw_action/egw_action_popup.js +++ b/phpgwapi/js/egw_action/egw_action_popup.js @@ -16,6 +16,8 @@ /phpgwapi/js/zeroclipboard/dist/ZeroClipboard.min.js; */ +ZeroClipboard.config( { swfPath: egw.webserverUrl+"/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.swf" } ); + if (typeof window._egwActionClasses == "undefined") window._egwActionClasses = {}; _egwActionClasses["popup"] = { diff --git a/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.min.js b/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.min.js index 61cb16dd20..7f246e0950 100644 --- a/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.min.js +++ b/phpgwapi/js/zeroclipboard/dist/ZeroClipboard.min.js @@ -7,4 +7,3 @@ * v2.2.0-beta.3 */ !function(a,b){"use strict";var c,d,e,f=a,g=f.document,h=f.navigator,i=f.setTimeout,j=f.clearTimeout,k=f.setInterval,l=f.clearInterval,m=f.getComputedStyle,n=f.encodeURIComponent,o=f.ActiveXObject,p=f.Error,q=f.Number.parseInt||f.parseInt,r=f.Number.parseFloat||f.parseFloat,s=f.Number.isNaN||f.isNaN,t=f.Date.now,u=f.Object.keys,v=f.Object.defineProperty,w=f.Object.prototype.hasOwnProperty,x=f.Array.prototype.slice,y=function(){var a=function(a){return a};if("function"==typeof f.wrap&&"function"==typeof f.unwrap)try{var b=g.createElement("div"),c=f.unwrap(b);1===b.nodeType&&c&&1===c.nodeType&&(a=f.unwrap)}catch(d){}return a}(),z=function(a){return x.call(a,0)},A=function(){var a,c,d,e,f,g,h=z(arguments),i=h[0]||{};for(a=1,c=h.length;c>a;a++)if(null!=(d=h[a]))for(e in d)w.call(d,e)&&(f=i[e],g=d[e],i!==g&&g!==b&&(i[e]=g));return i},B=function(a){var b,c,d,e;if("object"!=typeof a||null==a||"number"==typeof a.nodeType)b=a;else if("number"==typeof a.length)for(b=[],c=0,d=a.length;d>c;c++)w.call(a,c)&&(b[c]=B(a[c]));else{b={};for(e in a)w.call(a,e)&&(b[e]=B(a[e]))}return b},C=function(a,b){for(var c={},d=0,e=b.length;e>d;d++)b[d]in a&&(c[b[d]]=a[b[d]]);return c},D=function(a,b){var c={};for(var d in a)-1===b.indexOf(d)&&(c[d]=a[d]);return c},E=function(a){if(a)for(var b in a)w.call(a,b)&&delete a[b];return a},F=function(a,b){if(a&&1===a.nodeType&&a.ownerDocument&&b&&(1===b.nodeType&&b.ownerDocument&&b.ownerDocument===a.ownerDocument||9===b.nodeType&&!b.ownerDocument&&b===a.ownerDocument))do{if(a===b)return!0;a=a.parentNode}while(a);return!1},G=function(a){var b;return"string"==typeof a&&a&&(b=a.split("#")[0].split("?")[0],b=a.slice(0,a.lastIndexOf("/")+1)),b},H=function(a){var b,c;return"string"==typeof a&&a&&(c=a.match(/^(?:|[^:@]*@|.+\)@(?=http[s]?|file)|.+?\s+(?: at |@)(?:[^:\(]+ )*[\(]?)((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/),c&&c[1]?b=c[1]:(c=a.match(/\)@((?:http[s]?|file):\/\/[\/]?.+?\/[^:\)]*?)(?::\d+)(?::\d+)?/),c&&c[1]&&(b=c[1]))),b},I=function(){var a,b;try{throw new p}catch(c){b=c}return b&&(a=b.sourceURL||b.fileName||H(b.stack)),a},J=function(){var a,c,d;if(g.currentScript&&(a=g.currentScript.src))return a;if(c=g.getElementsByTagName("script"),1===c.length)return c[0].src||b;if("readyState"in c[0])for(d=c.length;d--;)if("interactive"===c[d].readyState&&(a=c[d].src))return a;return"loading"===g.readyState&&(a=c[c.length-1].src)?a:(a=I())?a:b},K=function(){var a,c,d,e=g.getElementsByTagName("script");for(a=e.length;a--;){if(!(d=e[a].src)){c=null;break}if(d=G(d),null==c)c=d;else if(c!==d){c=null;break}}return c||b},L=function(){var a=G(J())||K()||"";return a+"ZeroClipboard.swf"},M={bridge:null,version:"0.0.0",pluginType:"unknown",disabled:null,outdated:null,unavailable:null,degraded:null,deactivated:null,overdue:null,ready:null},N="11.0.0",O={},P={},Q=null,R=0,S=0,T={ready:"Flash communication is established",error:{"flash-disabled":"Flash is disabled or not installed","flash-outdated":"Flash is too outdated to support ZeroClipboard","flash-unavailable":"Flash is unable to communicate bidirectionally with JavaScript","flash-degraded":"Flash is unable to preserve data fidelity when communicating with JavaScript","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.","flash-overdue":"Flash communication was established but NOT within the acceptable time limit","version-mismatch":"ZeroClipboard JS version number does not match ZeroClipboard SWF version number","clipboard-error":"At least one error was thrown while ZeroClipboard was attempting to inject your data into the clipboard","config-mismatch":"ZeroClipboard configuration does not match Flash's reality","swf-not-found":"The ZeroClipboard SWF object could not be loaded, so please check your `swfPath` configuration and/or network connectivity"}},U={swfPath:L(),trustedDomains:a.location.host?[a.location.host]:[],cacheBust:!0,forceEnhancedClipboard:!1,flashLoadTimeout:3e4,autoActivate:!0,bubbleEvents:!0,containerId:"global-zeroclipboard-html-bridge",containerClass:"global-zeroclipboard-container",swfObjectId:"global-zeroclipboard-flash-bridge",hoverClass:"zeroclipboard-is-hover",activeClass:"zeroclipboard-is-active",forceHandCursor:!1,title:null,zIndex:999999999},V=function(a){if("object"==typeof a&&null!==a)for(var b in a)if(w.call(a,b))if(/^(?:forceHandCursor|title|zIndex|bubbleEvents)$/.test(b))U[b]=a[b];else if(null==M.bridge)if("containerId"===b||"swfObjectId"===b){if(!ib(a[b]))throw new Error("The specified `"+b+"` value is not valid as an HTML4 Element ID");U[b]=a[b]}else U[b]=a[b];{if("string"!=typeof a||!a)return B(U);if(w.call(U,a))return U[a]}},W=function(){return{browser:C(h,["userAgent","platform","appName"]),flash:D(M,["bridge"]),zeroclipboard:{version:Ob.version,config:Ob.config()}}},X=function(){return!!(M.disabled||M.outdated||M.unavailable||M.degraded||M.deactivated)},Y=function(a,d){var e,f,g,h={};if("string"==typeof a&&a)g=a.toLowerCase().split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof d)for(e in a)w.call(a,e)&&"string"==typeof e&&e&&"function"==typeof a[e]&&Ob.on(e,a[e]);if(g&&g.length){for(e=0,f=g.length;f>e;e++)a=g[e].replace(/^on/,""),h[a]=!0,O[a]||(O[a]=[]),O[a].push(d);if(h.ready&&M.ready&&Ob.emit({type:"ready"}),h.error){var i=["disabled","outdated","unavailable","degraded","deactivated","overdue"];for(e=0,f=i.length;f>e;e++)if(M[i[e]]===!0){Ob.emit({type:"error",name:"flash-"+i[e]});break}c!==b&&Ob.version!==c&&Ob.emit({type:"error",name:"version-mismatch",jsVersion:Ob.version,swfVersion:c})}}return Ob},Z=function(a,b){var c,d,e,f,g;if(0===arguments.length)f=u(O);else if("string"==typeof a&&a)f=a.split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof b)for(c in a)w.call(a,c)&&"string"==typeof c&&c&&"function"==typeof a[c]&&Ob.off(c,a[c]);if(f&&f.length)for(c=0,d=f.length;d>c;c++)if(a=f[c].toLowerCase().replace(/^on/,""),g=O[a],g&&g.length)if(b)for(e=g.indexOf(b);-1!==e;)g.splice(e,1),e=g.indexOf(b,e);else g.length=0;return Ob},$=function(a){var b;return b="string"==typeof a&&a?B(O[a])||null:B(O)},_=function(a){var b,c,d;return a=jb(a),a&&!pb(a)?"ready"===a.type&&M.overdue===!0?Ob.emit({type:"error",name:"flash-overdue"}):(b=A({},a),ob.call(this,b),"copy"===a.type&&(d=xb(P),c=d.data,Q=d.formatMap),c):void 0},ab=function(){if("boolean"!=typeof M.ready&&(M.ready=!1),!Ob.isFlashUnusable()&&null===M.bridge){var a=U.flashLoadTimeout;"number"==typeof a&&a>=0&&(R=i(function(){"boolean"!=typeof M.deactivated&&(M.deactivated=!0),M.deactivated===!0&&Ob.emit({type:"error",name:"flash-deactivated"})},a)),M.overdue=!1,vb()}},bb=function(){Ob.clearData(),Ob.blur(),Ob.emit("destroy"),wb(),Ob.off()},cb=function(a,b){var c;if("object"==typeof a&&a&&"undefined"==typeof b)c=a,Ob.clearData();else{if("string"!=typeof a||!a)return;c={},c[a]=b}for(var d in c)"string"==typeof d&&d&&w.call(c,d)&&"string"==typeof c[d]&&c[d]&&(P[d]=c[d])},db=function(a){"undefined"==typeof a?(E(P),Q=null):"string"==typeof a&&w.call(P,a)&&delete P[a]},eb=function(a){return"undefined"==typeof a?B(P):"string"==typeof a&&w.call(P,a)?P[a]:void 0},fb=function(a){if(a&&1===a.nodeType){d&&(Fb(d,U.activeClass),d!==a&&Fb(d,U.hoverClass)),d=a,Eb(a,U.hoverClass);var b=a.getAttribute("title")||U.title;if("string"==typeof b&&b){var c=ub(M.bridge);c&&c.setAttribute("title",b)}var e=U.forceHandCursor===!0||"pointer"===Gb(a,"cursor");Lb(e),Kb()}},gb=function(){var a=ub(M.bridge);a&&(a.removeAttribute("title"),a.style.left="0px",a.style.top="-9999px",a.style.width="1px",a.style.top="1px"),d&&(Fb(d,U.hoverClass),Fb(d,U.activeClass),d=null)},hb=function(){return d||null},ib=function(a){return"string"==typeof a&&a&&/^[A-Za-z][A-Za-z0-9_:\-\.]*$/.test(a)},jb=function(a){var b;if("string"==typeof a&&a?(b=a,a={}):"object"==typeof a&&a&&"string"==typeof a.type&&a.type&&(b=a.type),b){b=b.toLowerCase(),!a.target&&(/^(copy|aftercopy|_click)$/.test(b)||"error"===b&&"clipboard-error"===a.name)&&(a.target=e),A(a,{type:b,target:a.target||d||null,relatedTarget:a.relatedTarget||null,currentTarget:M&&M.bridge||null,timeStamp:a.timeStamp||t()||null});var c=T[a.type];return"error"===a.type&&a.name&&c&&(c=c[a.name]),c&&(a.message=c),"ready"===a.type&&A(a,{target:null,version:M.version}),"error"===a.type&&(/^flash-(disabled|outdated|unavailable|degraded|deactivated|overdue)$/.test(a.name)&&A(a,{target:null,minimumVersion:N}),/^flash-(outdated|unavailable|degraded|deactivated|overdue)$/.test(a.name)&&A(a,{version:M.version})),"copy"===a.type&&(a.clipboardData={setData:Ob.setData,clearData:Ob.clearData}),"aftercopy"===a.type&&(a=yb(a,Q)),a.target&&!a.relatedTarget&&(a.relatedTarget=kb(a.target)),lb(a)}},kb=function(a){var b=a&&a.getAttribute&&a.getAttribute("data-clipboard-target");return b?g.getElementById(b):null},lb=function(a){if(a&&/^_(?:click|mouse(?:over|out|down|up|move))$/.test(a.type)){var c=a.target,d="_mouseover"===a.type&&a.relatedTarget?a.relatedTarget:b,e="_mouseout"===a.type&&a.relatedTarget?a.relatedTarget:b,h=Hb(c),i=f.screenLeft||f.screenX||0,j=f.screenTop||f.screenY||0,k=g.body.scrollLeft+g.documentElement.scrollLeft,l=g.body.scrollTop+g.documentElement.scrollTop,m=h.left+("number"==typeof a._stageX?a._stageX:0),n=h.top+("number"==typeof a._stageY?a._stageY:0),o=m-k,p=n-l,q=i+o,r=j+p,s="number"==typeof a.movementX?a.movementX:0,t="number"==typeof a.movementY?a.movementY:0;delete a._stageX,delete a._stageY,A(a,{srcElement:c,fromElement:d,toElement:e,screenX:q,screenY:r,pageX:m,pageY:n,clientX:o,clientY:p,x:o,y:p,movementX:s,movementY:t,offsetX:0,offsetY:0,layerX:0,layerY:0})}return a},mb=function(a){var b=a&&"string"==typeof a.type&&a.type||"";return!/^(?:(?:before)?copy|destroy)$/.test(b)},nb=function(a,b,c,d){d?i(function(){a.apply(b,c)},0):a.apply(b,c)},ob=function(a){if("object"==typeof a&&a&&a.type){var b=mb(a),c=O["*"]||[],d=O[a.type]||[],e=c.concat(d);if(e&&e.length){var g,h,i,j,k,l=this;for(g=0,h=e.length;h>g;g++)i=e[g],j=l,"string"==typeof i&&"function"==typeof f[i]&&(i=f[i]),"object"==typeof i&&i&&"function"==typeof i.handleEvent&&(j=i,i=i.handleEvent),"function"==typeof i&&(k=A({},a),nb(i,j,[k],b))}return this}},pb=function(a){var b=a.target||d||null,f="swf"===a._source;delete a._source;var g=["flash-disabled","flash-outdated","flash-unavailable","flash-degraded","flash-deactivated","flash-overdue"];switch(a.type){case"error":-1!==g.indexOf(a.name)?A(M,{disabled:"flash-disabled"===a.name,outdated:"flash-outdated"===a.name,unavailable:"flash-unavailable"===a.name,degraded:"flash-degraded"===a.name,deactivated:"flash-deactivated"===a.name,overdue:"flash-overdue"===a.name,ready:!1}):"version-mismatch"===a.name&&(c=a.swfVersion,A(M,{disabled:!1,outdated:!1,unavailable:!1,degraded:!1,deactivated:!1,overdue:!1,ready:!1})),Jb();break;case"ready":c=a.swfVersion;var h=M.deactivated===!0;A(M,{disabled:!1,outdated:!1,unavailable:!1,degraded:!1,deactivated:!1,overdue:h,ready:!h}),Jb();break;case"beforecopy":e=b;break;case"copy":var i,j,k=a.relatedTarget;!P["text/html"]&&!P["text/plain"]&&k&&(j=k.value||k.outerHTML||k.innerHTML)&&(i=k.value||k.textContent||k.innerText)?(a.clipboardData.clearData(),a.clipboardData.setData("text/plain",i),j!==i&&a.clipboardData.setData("text/html",j)):!P["text/plain"]&&a.target&&(i=a.target.getAttribute("data-clipboard-text"))&&(a.clipboardData.clearData(),a.clipboardData.setData("text/plain",i));break;case"aftercopy":qb(a),Ob.clearData(),b&&b!==Db()&&b.focus&&b.focus();break;case"_mouseover":Ob.focus(b),U.bubbleEvents===!0&&f&&(b&&b!==a.relatedTarget&&!F(a.relatedTarget,b)&&rb(A({},a,{type:"mouseenter",bubbles:!1,cancelable:!1})),rb(A({},a,{type:"mouseover"})));break;case"_mouseout":Ob.blur(),U.bubbleEvents===!0&&f&&(b&&b!==a.relatedTarget&&!F(a.relatedTarget,b)&&rb(A({},a,{type:"mouseleave",bubbles:!1,cancelable:!1})),rb(A({},a,{type:"mouseout"})));break;case"_mousedown":Eb(b,U.activeClass),U.bubbleEvents===!0&&f&&rb(A({},a,{type:a.type.slice(1)}));break;case"_mouseup":Fb(b,U.activeClass),U.bubbleEvents===!0&&f&&rb(A({},a,{type:a.type.slice(1)}));break;case"_click":e=null,U.bubbleEvents===!0&&f&&rb(A({},a,{type:a.type.slice(1)}));break;case"_mousemove":U.bubbleEvents===!0&&f&&rb(A({},a,{type:a.type.slice(1)}))}return/^_(?:click|mouse(?:over|out|down|up|move))$/.test(a.type)?!0:void 0},qb=function(a){if(a.errors&&a.errors.length>0){var b=B(a);A(b,{type:"error",name:"clipboard-error"}),delete b.success,i(function(){Ob.emit(b)},0)}},rb=function(a){if(a&&"string"==typeof a.type&&a){var b,c=a.target||null,d=c&&c.ownerDocument||g,e={view:d.defaultView||f,canBubble:!0,cancelable:!0,detail:"click"===a.type?1:0,button:"number"==typeof a.which?a.which-1:"number"==typeof a.button?a.button:d.createEvent?0:1},h=A(e,a);c&&d.createEvent&&c.dispatchEvent&&(h=[h.type,h.canBubble,h.cancelable,h.view,h.detail,h.screenX,h.screenY,h.clientX,h.clientY,h.ctrlKey,h.altKey,h.shiftKey,h.metaKey,h.button,h.relatedTarget],b=d.createEvent("MouseEvents"),b.initMouseEvent&&(b.initMouseEvent.apply(b,h),b._source="js",c.dispatchEvent(b)))}},sb=function(){var a=U.flashLoadTimeout;if("number"==typeof a&&a>=0){var b=Math.min(1e3,a/10),c=U.swfObjectId+"_fallbackContent";S=k(function(){var a=g.getElementById(c);Ib(a)&&(Jb(),M.deactivated=null,Ob.emit({type:"error",name:"swf-not-found"}))},b)}},tb=function(){var a=g.createElement("div");return a.id=U.containerId,a.className=U.containerClass,a.style.position="absolute",a.style.left="0px",a.style.top="-9999px",a.style.width="1px",a.style.height="1px",a.style.zIndex=""+Mb(U.zIndex),a},ub=function(a){for(var b=a&&a.parentNode;b&&"OBJECT"===b.nodeName&&b.parentNode;)b=b.parentNode;return b||null},vb=function(){var a,b=M.bridge,c=ub(b);if(!b){var d=Cb(f.location.host,U),e="never"===d?"none":"all",h=Ab(A({jsVersion:Ob.version},U)),i=U.swfPath+zb(U.swfPath,U);c=tb();var j=g.createElement("div");c.appendChild(j),g.body.appendChild(c);var k=g.createElement("div"),l="activex"===M.pluginType;k.innerHTML='"+(l?'':"")+'
 
',b=k.firstChild,k=null,y(b).ZeroClipboard=Ob,c.replaceChild(b,j),sb()}return b||(b=g[U.swfObjectId],b&&(a=b.length)&&(b=b[a-1]),!b&&c&&(b=c.firstChild)),M.bridge=b||null,b},wb=function(){var a=M.bridge;if(a){var d=ub(a);d&&("activex"===M.pluginType&&"readyState"in a?(a.style.display="none",function e(){if(4===a.readyState){for(var b in a)"function"==typeof a[b]&&(a[b]=null);a.parentNode&&a.parentNode.removeChild(a),d.parentNode&&d.parentNode.removeChild(d)}else i(e,10)}()):(a.parentNode&&a.parentNode.removeChild(a),d.parentNode&&d.parentNode.removeChild(d))),Jb(),M.ready=null,M.bridge=null,M.deactivated=null,c=b}},xb=function(a){var b={},c={};if("object"==typeof a&&a){for(var d in a)if(d&&w.call(a,d)&&"string"==typeof a[d]&&a[d])switch(d.toLowerCase()){case"text/plain":case"text":case"air:text":case"flash:text":b.text=a[d],c.text=d;break;case"text/html":case"html":case"air:html":case"flash:html":b.html=a[d],c.html=d;break;case"application/rtf":case"text/rtf":case"rtf":case"richtext":case"air:rtf":case"flash:rtf":b.rtf=a[d],c.rtf=d}return{data:b,formatMap:c}}},yb=function(a,b){if("object"!=typeof a||!a||"object"!=typeof b||!b)return a;var c={};for(var d in a)if(w.call(a,d))if("errors"===d){c[d]=a[d]?a[d].slice():[];for(var e=0,f=c[d].length;f>e;e++)c[d][e].format=b[c[d][e].format]}else if("success"!==d&&"data"!==d)c[d]=a[d];else{c[d]={};var g=a[d];for(var h in g)h&&w.call(g,h)&&w.call(b,h)&&(c[d][b[h]]=g[h])}return c},zb=function(a,b){var c=null==b||b&&b.cacheBust===!0;return c?(-1===a.indexOf("?")?"?":"&")+"noCache="+t():""},Ab=function(a){var b,c,d,e,g="",h=[];if(a.trustedDomains&&("string"==typeof a.trustedDomains?e=[a.trustedDomains]:"object"==typeof a.trustedDomains&&"length"in a.trustedDomains&&(e=a.trustedDomains)),e&&e.length)for(b=0,c=e.length;c>b;b++)if(w.call(e,b)&&e[b]&&"string"==typeof e[b]){if(d=Bb(e[b]),!d)continue;if("*"===d){h.length=0,h.push(d);break}h.push.apply(h,[d,"//"+d,f.location.protocol+"//"+d])}return h.length&&(g+="trustedOrigins="+n(h.join(","))),a.forceEnhancedClipboard===!0&&(g+=(g?"&":"")+"forceEnhancedClipboard=true"),"string"==typeof a.swfObjectId&&a.swfObjectId&&(g+=(g?"&":"")+"swfObjectId="+n(a.swfObjectId)),"string"==typeof a.jsVersion&&a.jsVersion&&(g+=(g?"&":"")+"jsVersion="+n(a.jsVersion)),g},Bb=function(a){if(null==a||""===a)return null;if(a=a.replace(/^\s+|\s+$/g,""),""===a)return null;var b=a.indexOf("//");a=-1===b?a:a.slice(b+2);var c=a.indexOf("/");return a=-1===c?a:-1===b||0===c?null:a.slice(0,c),a&&".swf"===a.slice(-4).toLowerCase()?null:a||null},Cb=function(){var a=function(a){var b,c,d,e=[];if("string"==typeof a&&(a=[a]),"object"!=typeof a||!a||"number"!=typeof a.length)return e;for(b=0,c=a.length;c>b;b++)if(w.call(a,b)&&(d=Bb(a[b]))){if("*"===d){e.length=0,e.push("*");break}-1===e.indexOf(d)&&e.push(d)}return e};return function(b,c){var d=Bb(c.swfPath);null===d&&(d=b);var e=a(c.trustedDomains),f=e.length;if(f>0){if(1===f&&"*"===e[0])return"always";if(-1!==e.indexOf(b))return 1===f&&b===d?"sameDomain":"always"}return"never"}}(),Db=function(){try{return g.activeElement}catch(a){return null}},Eb=function(a,b){if(!a||1!==a.nodeType)return a;if(a.classList)return a.classList.contains(b)||a.classList.add(b),a;if(b&&"string"==typeof b){var c=(b||"").split(/\s+/);if(1===a.nodeType)if(a.className){for(var d=" "+a.className+" ",e=a.className,f=0,g=c.length;g>f;f++)d.indexOf(" "+c[f]+" ")<0&&(e+=" "+c[f]);a.className=e.replace(/^\s+|\s+$/g,"")}else a.className=b}return a},Fb=function(a,b){if(!a||1!==a.nodeType)return a;if(a.classList)return a.classList.contains(b)&&a.classList.remove(b),a;if("string"==typeof b&&b){var c=b.split(/\s+/);if(1===a.nodeType&&a.className){for(var d=(" "+a.className+" ").replace(/[\n\t]/g," "),e=0,f=c.length;f>e;e++)d=d.replace(" "+c[e]+" "," ");a.className=d.replace(/^\s+|\s+$/g,"")}}return a},Gb=function(a,b){var c=m(a,null).getPropertyValue(b);return"cursor"!==b||c&&"auto"!==c||"A"!==a.nodeName?c:"pointer"},Hb=function(a){var b={left:0,top:0,width:0,height:0};if(a.getBoundingClientRect){var c=a.getBoundingClientRect(),d=f.pageXOffset,e=f.pageYOffset,h=g.documentElement.clientLeft||0,i=g.documentElement.clientTop||0,j=0,k=0;if("relative"===Gb(g.body,"position")){var l=g.body.getBoundingClientRect(),m=g.documentElement.getBoundingClientRect();j=l.left-m.left||0,k=l.top-m.top||0}b.left=c.left+d-h-j,b.top=c.top+e-i-k,b.width="width"in c?c.width:c.right-c.left,b.height="height"in c?c.height:c.bottom-c.top}return b},Ib=function(a){if(!a)return!1;var b=m(a,null),c=r(b.height)>0,d=r(b.width)>0,e=r(b.top)>=0,f=r(b.left)>=0,g=c&&d&&e&&f,h=g?null:Hb(a),i="none"!==b.display&&"collapse"!==b.visibility&&(g||!!h&&(c||h.height>0)&&(d||h.width>0)&&(e||h.top>=0)&&(f||h.left>=0));return i},Jb=function(){j(R),R=0,l(S),S=0},Kb=function(){var a;if(d&&(a=ub(M.bridge))){var b=Hb(d);A(a.style,{width:b.width+"px",height:b.height+"px",top:b.top+"px",left:b.left+"px",zIndex:""+Mb(U.zIndex)})}},Lb=function(a){M.ready===!0&&(M.bridge&&"function"==typeof M.bridge.setHandCursor?M.bridge.setHandCursor(a):M.ready=!1)},Mb=function(a){if(/^(?:auto|inherit)$/.test(a))return a;var b;return"number"!=typeof a||s(a)?"string"==typeof a&&(b=Mb(q(a,10))):b=a,"number"==typeof b?b:"auto"},Nb=function(a){function b(a){var b=a.match(/[\d]+/g);return b.length=3,b.join(".")}function c(a){return!!a&&(a=a.toLowerCase())&&(/^(pepflashplayer\.dll|libpepflashplayer\.so|pepperflashplayer\.plugin)$/.test(a)||"chrome.plugin"===a.slice(-13))}function d(a){a&&(i=!0,a.version&&(l=b(a.version)),!l&&a.description&&(l=b(a.description)),a.filename&&(k=c(a.filename)))}var e,f,g,i=!1,j=!1,k=!1,l="";if(h.plugins&&h.plugins.length)e=h.plugins["Shockwave Flash"],d(e),h.plugins["Shockwave Flash 2.0"]&&(i=!0,l="2.0.0.11");else if(h.mimeTypes&&h.mimeTypes.length)g=h.mimeTypes["application/x-shockwave-flash"],e=g&&g.enabledPlugin,d(e);else if("undefined"!=typeof a){j=!0;try{f=new a("ShockwaveFlash.ShockwaveFlash.7"),i=!0,l=b(f.GetVariable("$version"))}catch(m){try{f=new a("ShockwaveFlash.ShockwaveFlash.6"),i=!0,l="6.0.21"}catch(n){try{f=new a("ShockwaveFlash.ShockwaveFlash"),i=!0,l=b(f.GetVariable("$version"))}catch(o){j=!1}}}}M.disabled=i!==!0,M.outdated=l&&r(l)e;e++)a=g[e].replace(/^on/,""),h[a]=!0,j[a]||(j[a]=[]),j[a].push(d);if(h.ready&&M.ready&&this.emit({type:"ready",client:this}),h.error){var k=["disabled","outdated","unavailable","degraded","deactivated","overdue"];for(e=0,f=k.length;f>e;e++)if(M[k[e]]){this.emit({type:"error",name:"flash-"+k[e],client:this});break}c!==b&&Ob.version!==c&&this.emit({type:"error",name:"version-mismatch",jsVersion:Ob.version,swfVersion:c})}}return this},Wb=function(a,b){var c,d,e,f,g,h=Qb[this.id],i=h&&h.handlers;if(!i)return this;if(0===arguments.length)f=u(i);else if("string"==typeof a&&a)f=a.split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof b)for(c in a)w.call(a,c)&&"string"==typeof c&&c&&"function"==typeof a[c]&&this.off(c,a[c]);if(f&&f.length)for(c=0,d=f.length;d>c;c++)if(a=f[c].toLowerCase().replace(/^on/,""),g=i[a],g&&g.length)if(b)for(e=g.indexOf(b);-1!==e;)g.splice(e,1),e=g.indexOf(b,e);else g.length=0;return this},Xb=function(a){var b=null,c=Qb[this.id]&&Qb[this.id].handlers;return c&&(b="string"==typeof a&&a?c[a]?c[a].slice(0):[]:B(c)),b},Yb=function(a){if(bc.call(this,a)){"object"==typeof a&&a&&"string"==typeof a.type&&a.type&&(a=A({},a));var b=A({},jb(a),{client:this});cc.call(this,b)}return this},Zb=function(a){if(!Qb[this.id])throw new Error("Attempted to clip element(s) to a destroyed ZeroClipboard client instance");a=dc(a);for(var b=0;b0,e=!a.target||d&&-1!==c.indexOf(a.target),f=a.relatedTarget&&d&&-1!==c.indexOf(a.relatedTarget),g=a.client&&a.client===this;return b&&(e||f||g)?!0:!1},cc=function(a){var b=Qb[this.id];if("object"==typeof a&&a&&a.type&&b){var c=mb(a),d=b&&b.handlers["*"]||[],e=b&&b.handlers[a.type]||[],g=d.concat(e);if(g&&g.length){var h,i,j,k,l,m=this;for(h=0,i=g.length;i>h;h++)j=g[h],k=m,"string"==typeof j&&"function"==typeof f[j]&&(j=f[j]),"object"==typeof j&&j&&"function"==typeof j.handleEvent&&(k=j,j=j.handleEvent),"function"==typeof j&&(l=A({},a),nb(j,k,[l],c))}}},dc=function(a){return"string"==typeof a&&(a=[]),"number"!=typeof a.length?[a]:a},ec=function(a){if(a&&1===a.nodeType){var b=function(a){(a||(a=f.event))&&("js"!==a._source&&(a.stopImmediatePropagation(),a.preventDefault()),delete a._source)},c=function(c){(c||(c=f.event))&&(b(c),Ob.focus(a))};a.addEventListener("mouseover",c,!1),a.addEventListener("mouseout",b,!1),a.addEventListener("mouseenter",b,!1),a.addEventListener("mouseleave",b,!1),a.addEventListener("mousemove",b,!1),Tb[a.zcClippingId]={mouseover:c,mouseout:b,mouseenter:b,mouseleave:b,mousemove:b}}},fc=function(a){if(a&&1===a.nodeType){var b=Tb[a.zcClippingId];if("object"==typeof b&&b){for(var c,d,e=["move","leave","enter","out","over"],f=0,g=e.length;g>f;f++)c="mouse"+e[f],d=b[c],"function"==typeof d&&a.removeEventListener(c,d,!1);delete Tb[a.zcClippingId]}}};Ob._createClient=function(){Ub.apply(this,z(arguments))},Ob.prototype.on=function(){return Vb.apply(this,z(arguments))},Ob.prototype.off=function(){return Wb.apply(this,z(arguments))},Ob.prototype.handlers=function(){return Xb.apply(this,z(arguments))},Ob.prototype.emit=function(){return Yb.apply(this,z(arguments))},Ob.prototype.clip=function(){return Zb.apply(this,z(arguments))},Ob.prototype.unclip=function(){return $b.apply(this,z(arguments))},Ob.prototype.elements=function(){return _b.apply(this,z(arguments))},Ob.prototype.destroy=function(){return ac.apply(this,z(arguments))},Ob.prototype.setText=function(a){if(!Qb[this.id])throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");return Ob.setData("text/plain",a),this},Ob.prototype.setHtml=function(a){if(!Qb[this.id])throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");return Ob.setData("text/html",a),this},Ob.prototype.setRichText=function(a){if(!Qb[this.id])throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");return Ob.setData("application/rtf",a),this},Ob.prototype.setData=function(){if(!Qb[this.id])throw new Error("Attempted to set pending clipboard data from a destroyed ZeroClipboard client instance");return Ob.setData.apply(this,z(arguments)),this},Ob.prototype.clearData=function(){if(!Qb[this.id])throw new Error("Attempted to clear pending clipboard data from a destroyed ZeroClipboard client instance");return Ob.clearData.apply(this,z(arguments)),this},Ob.prototype.getData=function(){if(!Qb[this.id])throw new Error("Attempted to get pending clipboard data from a destroyed ZeroClipboard client instance");return Ob.getData.apply(this,z(arguments))},"function"==typeof define&&define.amd?define(function(){return Ob}):"object"==typeof module&&module&&"object"==typeof module.exports&&module.exports?module.exports=Ob:a.ZeroClipboard=Ob}(function(){return this||window}()); -//# sourceMappingURL=ZeroClipboard.min.map \ No newline at end of file From d9f6c03f8b8aacd83293a0fee3dcd6a229b53bae Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Wed, 17 Dec 2014 10:34:27 +0000 Subject: [PATCH 033/295] Fix context menu not poping up in F.F --- phpgwapi/js/egw_action/egw_action.js | 2 +- phpgwapi/js/egw_action/egw_action_popup.js | 20 ++++++++------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/phpgwapi/js/egw_action/egw_action.js b/phpgwapi/js/egw_action/egw_action.js index b06c024143..db040059dd 100644 --- a/phpgwapi/js/egw_action/egw_action.js +++ b/phpgwapi/js/egw_action/egw_action.js @@ -1917,7 +1917,7 @@ var EGW_AO_EXEC_THIS = 1; * * @param {object} _implContext is data which should be delivered to the action implementation. * E.g. in case of the popup action implementation, the x and y coordinates where the - * menu should open are transmitted. + * menu should open, and contextmenu event are transmitted. * @param {string} _implType is the action type for which the implementation should be * executed. * @param {number} _execType specifies in which context the execution should take place. diff --git a/phpgwapi/js/egw_action/egw_action_popup.js b/phpgwapi/js/egw_action/egw_action_popup.js index 656d8a3319..50cfe30633 100644 --- a/phpgwapi/js/egw_action/egw_action_popup.js +++ b/phpgwapi/js/egw_action/egw_action_popup.js @@ -262,7 +262,8 @@ function egwPopupActionImplementation() else if (!e.ctrlKey && e.which == 3 || e.which === 0) // tap event indicates by 0 { var _xy = ai._getPageXY(e); - _callback.call(_context, _xy, ai); + var _implContext = {event:e, posx:_xy.posx, posy: _xy.posy}; + _callback.call(_context, _implContext, ai); } e.cancelBubble = !e.ctrlKey || e.which == 1; @@ -622,21 +623,16 @@ function egwPopupActionImplementation() var paste_action = mgr.getActionById('egw_paste'); // Fake UI so we can simulate the position of the drop - if(window.event) + if(this._context.event) { - var event = jQuery.Event(window.event); var ui = { position: {top: 0, left: 0}, offset: {top: 0, left: 0} }; - if(event) - { - event = event.originalEvent; - ui.position = {top: event.pageY, left: event.pageX}; - ui.offset = {top: event.offsetY, left: event.offsetX}; - } + var event = this._context.event.originalEvent; + ui.position = {top: event.pageY, left: event.pageX}; + ui.offset = {top: event.offsetY, left: event.offsetX}; } - // Create default copy menu action if(drag && !jQuery.isEmptyObject(drag)) { @@ -712,9 +708,9 @@ function egwPopupActionImplementation() },true); clipboard_action.group = 2.5; } - var os_clipboard_caption = event.target.innerText.trim(); + var os_clipboard_caption = this._context.event.originalEvent.target.innerHTML.trim(); clipboard_action.set_caption(egw.lang('Copy "%1"', os_clipboard_caption.length>20 ? os_clipboard_caption.substring(0,20)+'...':os_clipboard_caption)); - clipboard_action.data.target = event.target; + clipboard_action.data.target = this._context.event.originalEvent.target; if(typeof _links[copy_action.id] == 'undefined') { _links[copy_action.id] = { From cf838608646d79e564ea56deaa3802e833acddf2 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 17 Dec 2014 12:00:36 +0000 Subject: [PATCH 034/295] * all apps: suppressing private (or removed) custom-fields from history log --- phpgwapi/inc/class.historylog.inc.php | 28 ++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/phpgwapi/inc/class.historylog.inc.php b/phpgwapi/inc/class.historylog.inc.php index 2c4183cecf..a98bcfb6c7 100644 --- a/phpgwapi/inc/class.historylog.inc.php +++ b/phpgwapi/inc/class.historylog.inc.php @@ -76,7 +76,7 @@ class historylog /** * Delete the history-log of one or multiple records of $this->appname * - * @param int/array $record_id one or more id's of $this->appname, or null to delete ALL records of $this->appname + * @param int|array $record_id one or more id's of $this->appname, or null to delete ALL records of $this->appname * @return int number of deleted records/rows (0 is not necessaryly an error, it can just mean there's no record!) */ function delete($record_id) @@ -140,10 +140,10 @@ class historylog /** * Search history-log * - * @param array/int $filter array with filters, or int record_id - * @param string $order='history_id' sorting after history_id is identical to history_timestamp - * @param string $sort='DESC' - * @param int $limit=null only return this many entries + * @param array|int $filter array with filters, or int record_id + * @param string $order ='history_id' sorting after history_id is identical to history_timestamp + * @param string $sort ='DESC' + * @param int $limit =null only return this many entries * @return array of arrays with keys id, record_id, appname, owner (account_id), status, new_value, old_value, * timestamp (Y-m-d H:i:s in servertime), user_ts (timestamp in user-time) */ @@ -205,6 +205,24 @@ class historylog { $total = $GLOBALS['egw']->db->select(self::TABLE,'COUNT(*)',$filter,__LINE__,__FILE__,false,'','phpgwapi',0)->fetchColumn(); } + // filter out private (or no longer defined) custom fields + if ($filter['history_appname']) + { + $to_or[] = "history_status NOT LIKE '#%'"; + // explicitly allow "##" used to store iCal/vCard X-attributes + if (in_array($filter['history_appname'], array('calendar','infolog','addressbook'))) + { + $to_or[] = "history_status LIKE '##%'"; + } + if (($cfs = egw_customfields::get($filter['history_appname']))) + { + $to_or[] = 'history_status IN ('.implode(',', array_map(function($str) + { + return $GLOBALS['egw']->db->quote('#'.$str); + }, array_keys($cfs))).')'; + } + $filter[] = '('.implode(' OR ', $to_or).')'; + } $_query = array(array( 'table' => self::TABLE, 'cols' => array('history_id', 'history_record_id','history_appname','history_owner','history_status','history_new_value', 'history_timestamp','history_old_value'), From 215289a5f5c66e71a8a5b41e29e808b5fbb7bbf1 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Wed, 17 Dec 2014 12:02:01 +0000 Subject: [PATCH 035/295] Fix mail splitter loses its last stored height value after browsing with mobile theme --- mail/js/app.js | 3 ++- mail/templates/default/app.css | 3 --- mail/templates/pixelegg/app.css | 3 --- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/mail/js/app.js b/mail/js/app.js index 2b32ed99fe..89bd22ee82 100644 --- a/mail/js/app.js +++ b/mail/js/app.js @@ -607,7 +607,8 @@ app.classes.mail = AppJS.extend( //this.et2.getWidgetById('mailPreviewHeadersDate').set_disabled(_value); //this.et2.getWidgetById('mailPreviewHeadersSubject').set_disabled(_value); this.et2.getWidgetById('mailPreview').set_disabled(_value); - if (_value==true) + //Dock the splitter always if we are browsing with mobile + if (_value==true || egwIsMobile()) { if (this.mail_previewAreaActive) splitter.dock(); this.mail_previewAreaActive = false; diff --git a/mail/templates/default/app.css b/mail/templates/default/app.css index 08cde7c87e..7aee5f3f83 100644 --- a/mail/templates/default/app.css +++ b/mail/templates/default/app.css @@ -798,9 +798,6 @@ blockquote blockquote blockquote blockquote blockquote blockquote{ /* MOBILE and tablets (Portrait & Landscape) View --------------*/ @media only screen and (max-device-width:1024px) { - div#mail-index_nm { - height: 100% !important; - } /*Disable the preview spliter*/ div#mail-index_mailPreview, div.splitter-bar { display: none !important; diff --git a/mail/templates/pixelegg/app.css b/mail/templates/pixelegg/app.css index f6204299c4..62614bc353 100755 --- a/mail/templates/pixelegg/app.css +++ b/mail/templates/pixelegg/app.css @@ -791,9 +791,6 @@ blockquote blockquote blockquote blockquote blockquote blockquote { } /* MOBILE and tablets (Portrait & Landscape) View --------------*/ @media only screen and (max-device-width: 1024px) { - div#mail-index_nm { - height: 100% !important; - } /*Disable the preview spliter*/ div#mail-index_mailPreview, div.splitter-bar { From 4fe543605df3a1338300feb733b7f34ca8245ef7 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Wed, 17 Dec 2014 13:02:29 +0000 Subject: [PATCH 036/295] Remove max-height from mail tree in order to fix the issue mail tree gets scrollbar after expantion. --- mail/templates/default/app.css | 1 - mail/templates/pixelegg/app.css | 1 - 2 files changed, 2 deletions(-) diff --git a/mail/templates/default/app.css b/mail/templates/default/app.css index 7aee5f3f83..073d132096 100644 --- a/mail/templates/default/app.css +++ b/mail/templates/default/app.css @@ -340,7 +340,6 @@ pre { */ #mail-tree_target { min-height: 35px; - max-height: 450px; display: block; display: -moz-inline-stack; display: -moz-box; diff --git a/mail/templates/pixelegg/app.css b/mail/templates/pixelegg/app.css index 62614bc353..553fa742dd 100755 --- a/mail/templates/pixelegg/app.css +++ b/mail/templates/pixelegg/app.css @@ -338,7 +338,6 @@ pre { */ #mail-tree_target { min-height: 35px; - max-height: 450px; display: block; display: -moz-inline-stack; display: -moz-box; From 6b8698baefe3187aea5d685bc629049c48549511 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Wed, 17 Dec 2014 13:09:37 +0000 Subject: [PATCH 037/295] Fix taglist lack of styling in jdots --- etemplate/templates/default/etemplate2.css | 17 ++++++++++++++++- pixelegg/css/mobile.css | 15 --------------- pixelegg/css/pixelegg.css | 15 --------------- pixelegg/less/magicsuggest.css | 15 --------------- pixelegg/less/magicsuggest.less | 15 --------------- 5 files changed, 16 insertions(+), 61 deletions(-) diff --git a/etemplate/templates/default/etemplate2.css b/etemplate/templates/default/etemplate2.css index 1b6daeac45..4aad753854 100644 --- a/etemplate/templates/default/etemplate2.css +++ b/etemplate/templates/default/etemplate2.css @@ -1353,6 +1353,7 @@ div.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button { .ms-res-ctn { /* It doesn't really work smaller than this */ min-width: 150px; + border: solid 1px #bbbbbb; } .ms-ctn .loading { position: relative; @@ -1360,7 +1361,21 @@ div.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button { top: 5px; } .ms-res-ctn { - overflow-x: hidden; + position:absolute; + background: #FFF; + overflow-y: auto; + z-index: 9999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + border: 1px solid #CCC; + left: -1px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + border-top: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; } div.ms-sel-ctn { padding-right: 0px; diff --git a/pixelegg/css/mobile.css b/pixelegg/css/mobile.css index 50f5078bf4..befbb9c80b 100644 --- a/pixelegg/css/mobile.css +++ b/pixelegg/css/mobile.css @@ -1892,25 +1892,10 @@ div.ms-ctn-bootstrap-focus { border-bottom: 1px solid #CCC; } div.ms-res-ctn { - position: absolute; - background: #FFF; - overflow-y: auto; - z-index: 9999; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - border: 1px solid #CCC; - left: -1px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; -moz-transition: border linear 0.2s, box-shadow linear 0.2s; -o-transition: border linear 0.2s, box-shadow linear 0.2s; transition: border linear 0.2s, box-shadow linear 0.2s; - border-top: 0; - border-top-left-radius: 0; - border-top-right-radius: 0; } div.ms-res-ctn .ms-res-group { line-height: 23px; diff --git a/pixelegg/css/pixelegg.css b/pixelegg/css/pixelegg.css index 56c2d036fa..b783b66ea5 100644 --- a/pixelegg/css/pixelegg.css +++ b/pixelegg/css/pixelegg.css @@ -1881,25 +1881,10 @@ div.ms-ctn-bootstrap-focus { border-bottom: 1px solid #CCC; } div.ms-res-ctn { - position: absolute; - background: #FFF; - overflow-y: auto; - z-index: 9999; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - border: 1px solid #CCC; - left: -1px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; -moz-transition: border linear 0.2s, box-shadow linear 0.2s; -o-transition: border linear 0.2s, box-shadow linear 0.2s; transition: border linear 0.2s, box-shadow linear 0.2s; - border-top: 0; - border-top-left-radius: 0; - border-top-right-radius: 0; } div.ms-res-ctn .ms-res-group { line-height: 23px; diff --git a/pixelegg/less/magicsuggest.css b/pixelegg/less/magicsuggest.css index f75d8d8eab..63d1aa788f 100644 --- a/pixelegg/less/magicsuggest.css +++ b/pixelegg/less/magicsuggest.css @@ -109,25 +109,10 @@ div.ms-ctn-bootstrap-focus { border-bottom: 1px solid #CCC; } div.ms-res-ctn { - position: absolute; - background: #FFF; - overflow-y: auto; - z-index: 9999; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - border: 1px solid #CCC; - left: -1px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; -moz-transition: border linear 0.2s, box-shadow linear 0.2s; -o-transition: border linear 0.2s, box-shadow linear 0.2s; transition: border linear 0.2s, box-shadow linear 0.2s; - border-top: 0; - border-top-left-radius: 0; - border-top-right-radius: 0; } div.ms-res-ctn .ms-res-group { line-height: 23px; diff --git a/pixelegg/less/magicsuggest.less b/pixelegg/less/magicsuggest.less index 36e33746e0..0cff3e4d94 100644 --- a/pixelegg/less/magicsuggest.less +++ b/pixelegg/less/magicsuggest.less @@ -113,25 +113,10 @@ div.ms-ctn-bootstrap-focus{ border-bottom: 1px solid #CCC; } div.ms-res-ctn{ - position: absolute; - background: #FFF; - overflow-y: auto; - z-index: 9999; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - border: 1px solid #CCC; - left: -1px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; -moz-transition: border linear 0.2s, box-shadow linear 0.2s; -o-transition: border linear 0.2s, box-shadow linear 0.2s; transition: border linear 0.2s, box-shadow linear 0.2s; - border-top: 0; - border-top-left-radius: 0; - border-top-right-radius: 0; } div.ms-res-ctn .ms-res-group{ line-height: 23px; From 60f67bfff85e0e0c0bb155cd34f8595e37d7f09f Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 17 Dec 2014 13:58:15 +0000 Subject: [PATCH 038/295] * all apps: preserving for current user unavailable categories (eg. private categories of other user) when editing entries --- etemplate/inc/class.etemplate_request.inc.php | 10 +++++ .../class.etemplate_widget_menupopup.inc.php | 38 ++++++++++++++----- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/etemplate/inc/class.etemplate_request.inc.php b/etemplate/inc/class.etemplate_request.inc.php index 7f36dd36b9..35e3b2b898 100644 --- a/etemplate/inc/class.etemplate_request.inc.php +++ b/etemplate/inc/class.etemplate_request.inc.php @@ -66,6 +66,16 @@ * For an example look in link_widget::ajax_search() * * @property-read boolean $data_modified true if data was modified and therefore needs saving + * @property int $output_mode + * @property array $content + * @property array $changes + * @property array $sel_options + * @property array $readonlys + * @property array $preserv + * @property string $method + * @property array $ignore_validation + * @property array $template + * @property string $app_header */ class etemplate_request { diff --git a/etemplate/inc/class.etemplate_widget_menupopup.inc.php b/etemplate/inc/class.etemplate_widget_menupopup.inc.php index 0e11f30a0d..c24ebf83de 100644 --- a/etemplate/inc/class.etemplate_widget_menupopup.inc.php +++ b/etemplate/inc/class.etemplate_widget_menupopup.inc.php @@ -65,8 +65,14 @@ class etemplate_widget_menupopup extends etemplate_widget unset($this->attrs['options']); } } + elseif($this->attrs['rows'] > 1) + { + $this->attrs['multiple'] = true; + } } + const UNAVAILABLE_CAT_POSTFIX = '-unavailable'; + /** * Validate input * @@ -154,7 +160,19 @@ class etemplate_widget_menupopup extends etemplate_widget break; case 'select-cat': - // ToDo: unavailable cats need to be merged in again + // unavailable cats need to be merged in again + $unavailable_name = $form_name.self::UNAVAILABLE_CAT_POSTFIX; + if (isset(self::$request->preserv[$unavailable_name])) + { + if ($this->attrs['multiple']) + { + $value = array_merge($value, (array)self::$request->preserv[$unavailable_name]); + } + elseif(!$value) // for single cat, we only restore unavailable one, if no other was selected + { + $value = self::$request->preserv[$unavailable_name]; + } + } } $valid =& self::get_array($validated, $form_name, true); if (true) $valid = $value; @@ -212,7 +230,7 @@ class etemplate_widget_menupopup extends etemplate_widget self::$request->sel_options[$form_name] += self::typeOptions($this, // typeOptions thinks # of rows is the first thing in options ($this->attrs['rows'] && strpos($this->attrs['options'], $this->attrs['rows']) !== 0 ? $this->attrs['rows'].','.$this->attrs['options'] : $this->attrs['options']), - $no_lang, $this->attrs['readonly'], self::get_array(self::$request->content, $form_name)); + $no_lang, $this->attrs['readonly'], self::get_array(self::$request->content, $form_name), $form_name); // need to run that here manually, automatic run through etemplate_new::exec() already happend self::fix_encoded_options(self::$request->sel_options[$form_name]); @@ -384,12 +402,13 @@ class etemplate_widget_menupopup extends etemplate_widget * * @param string|etemplate_widget_menupopup $widget_type Type of widget, or actual widget to get attributes since $legacy_options are legacy * @param string $_legacy_options options string of widget - * @param boolean $no_lang=false initial value of no_lang attribute (some types set it to true) - * @param boolean $readonly=false for readonly we dont need to fetch all options, only the one for value - * @param mixed $value=null value for readonly + * @param boolean $no_lang =false initial value of no_lang attribute (some types set it to true) + * @param boolean $readonly =false for readonly we dont need to fetch all options, only the one for value + * @param mixed $value =null value for readonly + * @param string $form_name =null * @return array with value => label pairs */ - public static function typeOptions($widget_type, $_legacy_options, &$no_lang=false, $readonly=false, &$value=null) + public static function typeOptions($widget_type, $_legacy_options, &$no_lang=false, $readonly=false, &$value=null, $form_name=null) { if($widget_type && is_object($widget_type)) { @@ -499,13 +518,12 @@ class etemplate_widget_menupopup extends etemplate_widget } } // preserv unavailible cats (eg. private user-cats) - /* TODO if ($value && ($unavailible = array_diff(is_array($value) ? $value : explode(',',$value),array_keys((array)$options)))) { - $extension_data['unavailible'] = $unavailible; + // unavailable cats need to be merged in again + $unavailable_name = $form_name.self::UNAVAILABLE_CAT_POSTFIX; + self::$request->preserv[$unavailable_name] = $unavailible; } - $cell['size'] = $rows.($type2 ? ','.$type2 : ''); - */ $no_lang = True; break; From cc58d6e6e744e8f65514d47882d26512465bebb6 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 17 Dec 2014 14:00:29 +0000 Subject: [PATCH 039/295] fix funny number of rows --- addressbook/templates/default/edit.xet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addressbook/templates/default/edit.xet b/addressbook/templates/default/edit.xet index df02c8b17a..bc8a3648e5 100644 --- a/addressbook/templates/default/edit.xet +++ b/addressbook/templates/default/edit.xet @@ -171,7 +171,7 @@ - + From 14655677caa28b3dd126a69abef5caa2e202f066 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Wed, 17 Dec 2014 16:20:42 +0000 Subject: [PATCH 040/295] Fix copy to OS clipboard in Firefox. --- phpgwapi/js/egw_action/egw_action_popup.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpgwapi/js/egw_action/egw_action_popup.js b/phpgwapi/js/egw_action/egw_action_popup.js index 50cfe30633..a9b1c9fa9a 100644 --- a/phpgwapi/js/egw_action/egw_action_popup.js +++ b/phpgwapi/js/egw_action/egw_action_popup.js @@ -342,8 +342,8 @@ function egwPopupActionImplementation() menu.instance.dhtmlxmenu.attachEvent("onShow", function(zoneId,ev) { var client = new ZeroClipboard($j('#'+this.idPrefix+'egw_os_clipboard', this.base)); client.on("copy",function(event) { - event.clipboardData.setData('text/plain', _links.egw_os_clipboard.actionObj.data.target.innerText); - event.clipboardData.setData('text/html', _links.egw_os_clipboard.actionObj.data.target.innerHTML); + event.clipboardData.setData('text/plain', $j(_links.egw_os_clipboard.actionObj.data.target).text().trim()); + event.clipboardData.setData('text/html', $j(_links.egw_os_clipboard.actionObj.data.target).html()); }); }); return true; From 76bf4f31dcba53bcae3adafbae6dc047f4e0436b Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Wed, 17 Dec 2014 16:58:09 +0000 Subject: [PATCH 041/295] Fix a tags in nextmatch take fullWidth of parent and causing not be able select next match row on free space area --- etemplate/templates/default/etemplate2.css | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/etemplate/templates/default/etemplate2.css b/etemplate/templates/default/etemplate2.css index 4aad753854..7da6f6c3b5 100644 --- a/etemplate/templates/default/etemplate2.css +++ b/etemplate/templates/default/etemplate2.css @@ -452,7 +452,11 @@ action buttons, left aligned for "extra" controls .et2_nextmatch .egwGridView_grid .et2_customfield_list > tbody > tr > td:first-child { padding-left: 1.2em; } - +/*stops a tags inside next match extends to their parents width, +which caused click on free space infront of a tag stops nm row selection*/ +.et2_nextmatch .egwGridView_grid tr td div.et2_vbox a { + display: table-row; +} /** * Diff widget */ From df483a9a1b905f18c64ab67a557a1c17cec9c85f Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Thu, 18 Dec 2014 09:34:31 +0000 Subject: [PATCH 042/295] Fix styling of mail compose and display for jdots --- mail/templates/default/app.css | 18 +++++++++++++----- mail/templates/default/compose.xet | 10 +++++----- mail/templates/pixelegg/app.css | 18 +++++++++++++----- mail/templates/pixelegg/app.less | 1 + 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/mail/templates/default/app.css b/mail/templates/default/app.css index 073d132096..c16b18d8ea 100644 --- a/mail/templates/default/app.css +++ b/mail/templates/default/app.css @@ -366,6 +366,7 @@ input[type=button] { div.mailUploadSection { border-top: 1px solid silver; margin-top: 16px; + width:99%; } div.mailUploadSection > div.et2_hbox { margin-top: -10px; @@ -549,14 +550,12 @@ div.mail-compose_fileselector { display: -moz-box; /*width: 99%;*/ overflow: hidden; - overflow-y: auto; left: 8px; right: 8px; } .mailDisplayContainer { position: fixed; overflow: hidden; - overflow-y: auto; border: 1px solid silver; top: 120px; } @@ -612,9 +611,6 @@ div.mailDisplayHeaders > span:first-child, div.mailPreviewHeaders > span:first- #mail-display_toolbar { display: inline-flex; } -#mail-compose_mailaccount{ - width: 80%; -} div.mailComposeHeaders > span:first-child { width: 8em; } @@ -845,4 +841,16 @@ and (max-device-width:768){ and (max-device-width : 1024px) and (orientation : landscape) { +} + +span#mail-compose_cc_expander, +span#mail-compose_bcc_expander, +span#mail-compose_folder_expander, +span#mail-compose_replyto_expander { + float: left; + width: 55px; + margin: 3px; + margin-left: 12px; + text-align: right; + padding: 0; } \ No newline at end of file diff --git a/mail/templates/default/compose.xet b/mail/templates/default/compose.xet index a646c310b8..8b3b3d60d0 100644 --- a/mail/templates/default/compose.xet +++ b/mail/templates/default/compose.xet @@ -46,10 +46,10 @@ - + - - + + @@ -76,8 +76,8 @@ - - + + diff --git a/mail/templates/pixelegg/app.css b/mail/templates/pixelegg/app.css index 553fa742dd..dee2a19ecc 100755 --- a/mail/templates/pixelegg/app.css +++ b/mail/templates/pixelegg/app.css @@ -363,6 +363,7 @@ input[type=button] { div.mailUploadSection { border-top: 1px solid silver; margin-top: 16px; + width: 99%; } div.mailUploadSection > div.et2_hbox { margin-top: -10px; @@ -549,14 +550,12 @@ div.mail-compose_fileselector { display: -moz-box; /*width: 99%;*/ overflow: hidden; - overflow-y: auto; left: 8px; right: 8px; } .mailDisplayContainer { position: fixed; overflow: hidden; - overflow-y: auto; border: 1px solid silver; top: 120px; } @@ -611,9 +610,6 @@ div.mailPreviewHeaders > span:first-child { #mail-display_toolbar { display: inline-flex; } -#mail-compose_mailaccount { - width: 80%; -} div.mailComposeHeaders > span:first-child { width: 8em; } @@ -830,6 +826,17 @@ blockquote blockquote blockquote blockquote blockquote blockquote { } } /* Mobile (landscape) Tablet----------- */ +span#mail-compose_cc_expander, +span#mail-compose_bcc_expander, +span#mail-compose_folder_expander, +span#mail-compose_replyto_expander { + float: left; + width: 55px; + margin: 3px; + margin-left: 12px; + text-align: right; + padding: 0; +} #popupMainDiv { padding: 5px; } @@ -1436,6 +1443,7 @@ div#mail-index div#mail-index_mailPreview div#mail-index_mailPreviewHeadersSubje margin: 3px; font-size: 8px; margin-left: 12px; + padding: 0; } #mail-compose .mailComposeHeaders span#mail-compose_cc_expander:hover, #mail-compose .mailComposeHeadersSection span#mail-compose_cc_expander:hover, diff --git a/mail/templates/pixelegg/app.less b/mail/templates/pixelegg/app.less index a2fc2ce4d1..5734e4225f 100755 --- a/mail/templates/pixelegg/app.less +++ b/mail/templates/pixelegg/app.less @@ -599,6 +599,7 @@ div#mail-index{ margin: 3px; font-size: 8px; margin-left: 12px; + padding:0; &:hover {.box_shadow_standard_light_hover; background-color:@color_positive_action;color: @gray_0;} } /*Betreff*/ From cc0aad2d6b0fb2776aff2148d76dcbbbfd4e8b1c Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Thu, 18 Dec 2014 09:37:19 +0000 Subject: [PATCH 043/295] Add span.et2_button_text to be able to give button style to span --- etemplate/templates/default/etemplate2.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/etemplate/templates/default/etemplate2.css b/etemplate/templates/default/etemplate2.css index 7da6f6c3b5..0b038393ab 100644 --- a/etemplate/templates/default/etemplate2.css +++ b/etemplate/templates/default/etemplate2.css @@ -198,17 +198,20 @@ input[type=button] { } button.et2_button_text:hover, .et2_file_spanHover, +span.et2_button_text:hover, input[type=button]:hover { color: #050505; border: 1px solid gray; background-color: #D0D0EE; } button.et2_button_text:active, +span.et2_button_text:active, input[type=button]:active { background-image: url(images/gradient02.png); background-color: #D0D0E0; } button.et2_button_text:focus, +span.et2_button_text:focus, .et2_file_spanActive, input[type=button]:focus { border: 1px solid #2c3d6f; From cbf4051ef39272dff530f923a47b44cb9b25a87e Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 18 Dec 2014 10:04:41 +0000 Subject: [PATCH 044/295] checking sieve enabled on imap-server object not account, so imap plugins can overwrite eg. always set this --- mail/inc/class.mail_ui.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index 319301b2d6..4220eef1d7 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -822,7 +822,7 @@ class mail_ui 'child'=> (int)($acc_id != $_profileID || $folderObjects), // dynamic loading on unfold 'parent' => '', // mark on account if Sieve is enabled - 'data' => array('sieve' => $accountObj->acc_sieve_enabled), + 'data' => array('sieve' => $accountObj->imapServer()->acc_sieve_enabled), ); $this->setOutStructure($oA, $out, self::$delimiter); From 11f1b63a8f43aa8d00626ed0c1f9c867a95d75b3 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Thu, 18 Dec 2014 11:01:23 +0000 Subject: [PATCH 045/295] Fix styling of mail display print view for jdots --- mail/templates/default/app.css | 4 +++- mail/templates/pixelegg/app.css | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/mail/templates/default/app.css b/mail/templates/default/app.css index c16b18d8ea..990b38c98b 100644 --- a/mail/templates/default/app.css +++ b/mail/templates/default/app.css @@ -577,7 +577,7 @@ div.mail-compose_fileselector { height: 121px; position: fixed; bottom: .1em; - border: 1px solid grey; + border-top: 1px solid grey; opacity: 1; -moz-opacity:1; filter: Alpha(opacity=100); @@ -748,6 +748,8 @@ blockquote blockquote blockquote blockquote blockquote blockquote{ @media print { html *, .td_display { font-size: 12pt !important; + border-right: none !important; + border-left: none !important; } .mailDisplayHeaders { border-bottom: 0.1em solid #d7d7d7; diff --git a/mail/templates/pixelegg/app.css b/mail/templates/pixelegg/app.css index dee2a19ecc..03427f9f17 100755 --- a/mail/templates/pixelegg/app.css +++ b/mail/templates/pixelegg/app.css @@ -577,7 +577,7 @@ div.mail-compose_fileselector { height: 121px; position: fixed; bottom: .1em; - border: 1px solid grey; + border-top: 1px solid grey; opacity: 1; -moz-opacity: 1; filter: alpha(opacity=100); @@ -744,6 +744,8 @@ blockquote blockquote blockquote blockquote blockquote blockquote { html *, .td_display { font-size: 12pt !important; + border-right: none !important; + border-left: none !important; } .mailDisplayHeaders { border-bottom: 0.1em solid #d7d7d7; From 3dee5e9a569a542b9116684d70659e2b5d80fe04 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 18 Dec 2014 11:02:42 +0000 Subject: [PATCH 046/295] reload framework if (custom-)template-color changes --- preferences/inc/class.preferences_settings.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/preferences/inc/class.preferences_settings.inc.php b/preferences/inc/class.preferences_settings.inc.php index edf4fbfc30..f53681388c 100644 --- a/preferences/inc/class.preferences_settings.inc.php +++ b/preferences/inc/class.preferences_settings.inc.php @@ -90,7 +90,7 @@ class preferences_settings $GLOBALS['egw']->preferences->read_repository(); } // name of common preferences which require reload of framework, if there values change - $require_reload = array('template_set', 'theme', 'lang'); + $require_reload = array('template_set', 'theme', 'lang', 'template_color', 'template_custom_color'); $old_values = array_intersect_key($GLOBALS['egw_info']['user']['preferences']['common'], array_flip($require_reload)); $attribute = $type == 'group' ? 'user' : $type; From 6d9f4dd712b866856fb6670c8a4177be6d51c0ef Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 18 Dec 2014 13:46:44 +0000 Subject: [PATCH 047/295] fix not working click on virtual structure (eg. "/apps/addressbook/$all"), because it uses mime "egw/addressbook" --- filemanager/js/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filemanager/js/app.js b/filemanager/js/app.js index 09e9606de2..75c62ba248 100644 --- a/filemanager/js/app.js +++ b/filemanager/js/app.js @@ -764,7 +764,7 @@ app.classes.filemanager = AppJS.extend( { } - else if (widget.value.mime == 'httpd/unix-directory') + else if (widget.value.is_dir) // true for "httpd/unix-directory" and "egw/*" { var path = null; // Cannot do this, there are multiple widgets named path From 9cc130e0e78bf2d922c2616c246245c87ffc35b5 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Thu, 18 Dec 2014 17:13:49 +0000 Subject: [PATCH 048/295] Implement template custom color for pixelegg template --- pixelegg/hook_settings.inc.php | 24 ++---- pixelegg/inc/class.pixelegg_framework.inc.php | 81 ++++++++++++++++++- 2 files changed, 88 insertions(+), 17 deletions(-) diff --git a/pixelegg/hook_settings.inc.php b/pixelegg/hook_settings.inc.php index cb19b1555b..46216e180a 100644 --- a/pixelegg/hook_settings.inc.php +++ b/pixelegg/hook_settings.inc.php @@ -31,26 +31,19 @@ if (!$hook_data['setup']) // does not work on setup time } $colors = array( - '#4b89d8' => lang('dark blue'), - '#010101' => lang('black'), - '#a3620a' => lang('brown'), - '#469609' => lang('dark green'), - '#bbde62' => lang('light green'), - '#9541d6' => lang('lila'), - '#f7b21e' => lang('orange'), - '#fe6a07' => lang('dark orange'), - '#fedf9e' => lang('light orange'), - '#f06eaa' => lang('pink'), - '#ed1c24' => lang('red'), - '#fef322' => lang('yellow'), + '#408dd2' => lang('LightBlue'), + '#679fd2' => lang('DarkBlue'), + '#B0C4DE' => lang('LightSteelBlue'), + '#20B2AA' => lang('LightSeaGreen'), + '#84CA8C' => lang('DarkGreen'), + '#b4b4b4' => lang('Gray'), ); asort($colors); $colors['custom'] = lang('Custom color'); // custom allways last $template_colors = array(); foreach($colors as $color => $label) { - $template_colors[$color] = $label.' ('.$color.') '.lang('Sidebox and header'); - $template_colors['@'.$color] = $label.' ('.$color.') '.lang('Sidebox and active tab'); + $template_colors[$color] = $label.' ('.$color.') '.lang('Sidebox, header, and logo'); } /** * Stylite Pixelegg template @@ -91,7 +84,6 @@ $GLOBALS['settings'] = array( 'xmlrpc' => True, 'admin' => False, ), - /* disabled until Pixelegg template supports it 'template_color' => array( 'type' => 'select', 'label' => 'Template color', @@ -111,7 +103,7 @@ $GLOBALS['settings'] = array( 'help' => lang('Use eg. %1 or %2','#FF0000','orange'), 'xmlrpc' => True, 'admin' => False, - ),*/ + ), 'navbar_format' => false, // not used in JDots (defined in common prefs) 'default_app' => false, // not used in JDots, as we can have multiple tabs open ... ); diff --git a/pixelegg/inc/class.pixelegg_framework.inc.php b/pixelegg/inc/class.pixelegg_framework.inc.php index 0498a85173..9793555879 100755 --- a/pixelegg/inc/class.pixelegg_framework.inc.php +++ b/pixelegg/inc/class.pixelegg_framework.inc.php @@ -61,7 +61,35 @@ class pixelegg_framework extends jdots_framework } return parent::header($extra); } + + /** + * Make given color lighter or darker by percentage + * + * @param string $color in hex + * @param int $percent int + * @return string returns color hex format (for instance: #2b2b2b) + */ + function _color_shader($color, $percent) { + $R = hexdec(substr($color,0,2)); + $G = hexdec(substr($color,2,2)); + $B = hexdec(substr($color,4,2)); + + $R = round($R * (100 + $percent) / 100); + $G = round($G * (100 + $percent) / 100); + $B = round($B * (100 + $percent) / 100); + + $R = ($R<255)?$R:255; + $G = ($G<255)?$G:255; + $B = ($B<255)?$B:255; + + $RR = (strlen(dechex($R))==1?"0".dechex($R):dechex($R)); + $GG = (strlen(dechex($G))==1?"0".dechex($G):dechex($G)); + $BB = (strlen(dechex($B))==1?"0".dechex($B):dechex($B)); + + return '#'.$RR.$GG.$BB; + } + /** * Overwrite to NOT add customizable colors from jDots * @@ -70,7 +98,58 @@ class pixelegg_framework extends jdots_framework */ public function _get_css() { - return egw_framework::_get_css(); + if (html::$ua_mobile || $GLOBALS['egw_info']['user']['preferences']['common']['theme'] == 'mobile') return egw_framework::_get_css(); + $ret = parent::_get_css(); + // color to use + $color = str_replace('custom',$GLOBALS['egw_info']['user']['preferences']['common']['template_custom_color'], + $GLOBALS['egw_info']['user']['preferences']['common']['template_color']); + //The hex value of the color + $color_hex = ltrim($color, '#'); + + // Create a drak variant of the color + $color_hex_dark = $this->_color_shader($color_hex, 15); + // Create a draker variant of the color + $color_hex_darker = $this->_color_shader($color_hex, -30); + + if (preg_match('/^(#[0-9A-F]+|[A-Z]+)$/i',$color)) // a little xss check + { + $ret['app_css'] = " +/** + * theme changes to color pixelegg for color: $color + */ + +/* +-Top window framework header +-sidebar actiuve category :hover +-popup toolbar +*/ +div#egw_fw_header, div.egw_fw_ui_category:hover,#loginMainDiv,#loginMainDiv #divAppIconBar #divLogo, +#egw_fw_sidebar #egw_fw_sidemenu .egw_fw_ui_scrollarea_outerdiv .egw_fw_ui_sidemenu_entry_content .egw_fw_ui_category_active:hover, +.dialogFooterToolbar, .ui-widget-header{ + background-color: $color; +} + +/*Login background*/ +#loginMainDiv #divAppIconBar #divLogo img[src$='svg'] { + background-image: -webkit-linear-gradient(top, $color, $color); +} + +/*Center box in login page*/ +#loginMainDiv div#centerBox { + background-image: -webkit-linear-gradient(top,$color_hex_dark,$color_hex_darker); + border-top: solid 1px $color_hex_darker; + border-left: solid 1px $color_hex_darker; + border-right: solid 1px $color_hex_darker; + border-bottom: solid 1px $color_hex_dark; +} + +/*Sidebar menu active category*/ +#egw_fw_sidebar #egw_fw_sidemenu .egw_fw_ui_scrollarea_outerdiv .egw_fw_ui_sidemenu_entry_content .egw_fw_ui_category_active{ + background-color: $color_hex_darker; +} +"; + } + return $ret; } /** From ab57cbefadbdf9a43a7f2c531e3b015c586d37a0 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 19 Dec 2014 07:49:04 +0000 Subject: [PATCH 049/295] make sure admin tree displays following toplevel order: admin, user, groups, apps by returning admin hooks first, despite alphabetical sorting of apps --- admin/inc/class.admin_ui.inc.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/admin/inc/class.admin_ui.inc.php b/admin/inc/class.admin_ui.inc.php index 81536a9ff6..c7a2cf84b9 100644 --- a/admin/inc/class.admin_ui.inc.php +++ b/admin/inc/class.admin_ui.inc.php @@ -495,6 +495,8 @@ class admin_ui { return strcasecmp(lang($a), lang($b)); }); + // make sure admin is first + self::$hook_data = array_merge(array('admin' => self::$hook_data['admin']), self::$hook_data); return self::$hook_data; } From 09ca844bda51069a494ba2cfd73ca1cbcfc0e74d Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Fri, 19 Dec 2014 11:19:20 +0000 Subject: [PATCH 050/295] Fix mail display printing multipage style for jdots --- mail/templates/default/app.css | 3 +++ mail/templates/pixelegg/app.css | 3 +++ 2 files changed, 6 insertions(+) diff --git a/mail/templates/default/app.css b/mail/templates/default/app.css index 990b38c98b..b143d78f06 100644 --- a/mail/templates/default/app.css +++ b/mail/templates/default/app.css @@ -746,6 +746,9 @@ blockquote blockquote blockquote blockquote blockquote blockquote{ } /* MAIL PRINT */ @media print { + html { + height: auto !important; + } html *, .td_display { font-size: 12pt !important; border-right: none !important; diff --git a/mail/templates/pixelegg/app.css b/mail/templates/pixelegg/app.css index 03427f9f17..46994936f4 100755 --- a/mail/templates/pixelegg/app.css +++ b/mail/templates/pixelegg/app.css @@ -741,6 +741,9 @@ blockquote blockquote blockquote blockquote blockquote blockquote { } /* MAIL PRINT */ @media print { + html { + height: auto !important; + } html *, .td_display { font-size: 12pt !important; From 733c263540f617f1e97fd8e210415b2028f7ede3 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 19 Dec 2014 12:27:39 +0000 Subject: [PATCH 051/295] Changelog for 14.2.20141219 --- doc/rpm-build/debian.changes | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/rpm-build/debian.changes b/doc/rpm-build/debian.changes index d4fe20c015..1d10b99bdc 100644 --- a/doc/rpm-build/debian.changes +++ b/doc/rpm-build/debian.changes @@ -1,3 +1,14 @@ +egroupware-epl (14.2.20141219-1) hardy; urgency=low + + * Filemanager: fixed create directory icon in list and select popup, clicking on favorites in select popup + * Filemanager: fixed directory creation in vfs root (you need root permisstions of cause) + * Mail: update title of compose window with subject + * EMailAdmin: disable certificate validation for Sieve, which is enabled by default in PHP 5.6 + * all apps: suppressing private (or removed) custom-fields from history log + * all apps: preserving for current user unavailable categories (eg. private categories of other user) when editing entries + + -- Ralf Becker Fri, 19 Dec 2014 13:27:40 +0100 + egroupware-epl (14.2.20141211-1) hardy; urgency=low * egw-pear: removed, as no longer necessary From 1bec5bb261d3d0cb3d5e0028d477f496eeec9f25 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 19 Dec 2014 12:53:03 +0000 Subject: [PATCH 052/295] fixed offset in patch --- doc/rpm-build/class.uiasyncservice.inc.php.patch | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/rpm-build/class.uiasyncservice.inc.php.patch b/doc/rpm-build/class.uiasyncservice.inc.php.patch index fd826d5afa..f8440c6468 100644 --- a/doc/rpm-build/class.uiasyncservice.inc.php.patch +++ b/doc/rpm-build/class.uiasyncservice.inc.php.patch @@ -1,6 +1,6 @@ Index: egroupware/admin/inc/class.uiasyncservice.inc.php =================================================================== ---- egroupware/admin/inc/class.uiasyncservice.inc.php (Revision 49786) +--- egroupware/admin/inc/class.uiasyncservice.inc.php (Revision 51102) +++ egroupware/admin/inc/class.uiasyncservice.inc.php (Arbeitskopie) @@ -95,16 +95,20 @@ { @@ -44,9 +44,9 @@ Index: egroupware/admin/inc/class.uiasyncservice.inc.php echo "
\n"; Index: egroupware/phpgwapi/inc/class.egw.inc.php =================================================================== ---- egroupware/phpgwapi/inc/class.egw.inc.php (Revision 49786) +--- egroupware/phpgwapi/inc/class.egw.inc.php (Revision 51102) +++ egroupware/phpgwapi/inc/class.egw.inc.php (Arbeitskopie) -@@ -606,11 +606,13 @@ +@@ -605,11 +605,13 @@ _egw_log_exception($ex); } } From 2021a8227e83311e3fc5fdc2db043c18c5a1f4ec Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Fri, 19 Dec 2014 13:52:57 +0000 Subject: [PATCH 053/295] Fix nm_popup dialog does not display full content of button's label --- etemplate/js/et2_extension_nextmatch_actions.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/etemplate/js/et2_extension_nextmatch_actions.js b/etemplate/js/et2_extension_nextmatch_actions.js index ebb6aa2abe..2ec2e138c8 100644 --- a/etemplate/js/et2_extension_nextmatch_actions.js +++ b/etemplate/js/et2_extension_nextmatch_actions.js @@ -431,12 +431,14 @@ function nm_open_popup(_action, _selected) } }); }); + // Need to get the dialog width before make it hidden + var dialog_width = dialog.outerWidth(true); popup.hide(); dialog.dialog({ title: jQuery('.promptheader',popup).text(), modal: true, buttons: d_buttons, - minWidth: dialog.outerWidth(true), + minWidth: dialog_width, close: function(event, ui) { // Need to destroy the dialog, etemplate widget needs divs back where they were dialog.dialog("destroy"); From 6138698b50c8ef29ed002749fd66a54804cb7975 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Fri, 19 Dec 2014 14:15:28 +0000 Subject: [PATCH 054/295] Add focus back to search input field after clicking on cross icon --- etemplate/js/et2_extension_nextmatch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etemplate/js/et2_extension_nextmatch.js b/etemplate/js/et2_extension_nextmatch.js index f21979c02f..4d79656bcd 100644 --- a/etemplate/js/et2_extension_nextmatch.js +++ b/etemplate/js/et2_extension_nextmatch.js @@ -1938,7 +1938,7 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, { self.search.input.after( $j('').click( - function() {self.search.input.val('');} + function() {self.search.input.val('');self.search.input.focus();} ) ); } From 285eb16445e0d134f44ecbeca128becfae659ee2 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 19 Dec 2014 16:32:56 +0000 Subject: [PATCH 055/295] remove egw-pear and always run "pear upgrade-all" before installing new packages, as pear installs fails if an older version of a required package is already installed --- doc/rpm-build/post_install.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/doc/rpm-build/post_install.php b/doc/rpm-build/post_install.php index cc4a2b363d..e805c333f1 100755 --- a/doc/rpm-build/post_install.php +++ b/doc/rpm-build/post_install.php @@ -627,9 +627,8 @@ function check_install_pear_packages() include_once(EGW_API_INC.'/common_functions.inc.php'); // read required packages from apps - $packages = array('PEAR' => true, 'HTTP_WebDAV_Server' => '999.egw-pear'); // pear must be the first, to run it's update first! + $packages = array('PEAR' => true); // pear must be the first, to run it's update first! $channels = array(); - $egw_pear_packages = array(); $setup_info = array(); foreach(scandir($config['source_dir']) as $app) { @@ -670,15 +669,10 @@ function check_install_pear_packages() } } } - if ($app == 'egw-pear') - { - $egw_pear_packages['HTTP_WebDAV_Server'] = $egw_pear_packages['Net_IMAP'] = '999.egw-pear'; - } } //echo 'Installed: '; print_r($packages_installed); - //echo 'egw-pear: '; print_r($egw_pear_packages); //echo 'Required: '; print_r($packages); - $to_install = array_diff(array_keys($packages),array_keys($packages_installed),array_keys($egw_pear_packages)); + $to_install = array_diff(array_keys($packages),array_keys($packages_installed)); $need_upgrade = array(); foreach($packages as $package => $version) @@ -715,6 +709,11 @@ function check_install_pear_packages() } if ($to_install) { + // package install can fail if a required package of one to install is of an older version + // unfortunately there is no option to automatic update the required packages automatic + // as a quick fix for that situation, we always run "pear upgrade-all" first + $cmd = $config['pear'].' upgrade-all'; + echo "$cmd\n"; system($cmd); $cmd = $config['pear'].' install '.implode(' ', $to_install); echo "$cmd\n"; system($cmd); } From 7a40d7a71f6bd014a4591cdaafb43b0e4fb7695f Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 19 Dec 2014 17:37:46 +0000 Subject: [PATCH 056/295] re-add logging again to egw_mailer --- phpgwapi/inc/class.egw_mailer.inc.php | 218 +++++++++++--------------- 1 file changed, 89 insertions(+), 129 deletions(-) diff --git a/phpgwapi/inc/class.egw_mailer.inc.php b/phpgwapi/inc/class.egw_mailer.inc.php index 86bbf0da57..309aa498be 100644 --- a/phpgwapi/inc/class.egw_mailer.inc.php +++ b/phpgwapi/inc/class.egw_mailer.inc.php @@ -158,6 +158,27 @@ class egw_mailer extends Horde_Mime_Mail $this->removeHeader(self::$type2header[$type]); } + /** + * Get set to addressses + * + * @param string $type ='to' type of address to add "to", "cc", "bcc" or "replyto" + * @param boolean $return_array =false true: return array of string, false: Horde_Mail_Rfc822_List + * @return array|Horde_Mail_Rfc822_List supporting arrayAccess and Iterable + */ + function getAddresses($type='to', $return_array=false) + { + if ($return_array) + { + $addresses = array(); + foreach($this->$type as $addr) + { + $addresses[] = (string)$addr; + } + return $addresses; + } + return $this->$type; + } + /** * Write Bcc as header for storing in sent or as draft * @@ -380,15 +401,81 @@ class egw_mailer extends Horde_Mime_Mail /** * Send mail, injecting mail transport from account * - * @ToDo hooks port hook from SmtpSend + * Log mails to log file specified in $GLOBALS['egw_info']['server']['log_mail'] + * or regular error_log for true (can be set either in DB or header.inc.php). + * * @throws egw_exception_not_found for no smtp account available * @throws Horde_Mime_Exception */ function send() { - parent::send($this->account->smtpTransport(), true); // true: keep Message-ID + if (!($message_id = $this->getHeader('Message-ID'))) + { + $message_id = Horde_Mime_Headers_MessageId::create(); + $this->addHeader('Message-ID', $message_id); + } + $body_sha1 = null; // skip sha1, it requires whole mail in memory, which we traing to avoid now + + $mail_id = $GLOBALS['egw']->hooks->process(array( + 'location' => 'send_mail', + 'subject' => $subject=$this->getHeader('Subject'), + 'from' => $this->getHeader('Return-Path') ? $this->getHeader('Return-Path') : $this->getHeader('From'), + 'to' => $to=$this->getAddresses('to', true), + 'cc' => $cc=$this->getAddresses('cc', true), + 'bcc' => $bcc=$this->getAddresses('bcc', true), + 'body_sha1' => $body_sha1, + 'message_id' => (string)$message_id, + ), array(), true); // true = call all apps + + try { + parent::send($this->account->smtpTransport(), true); // true: keep Message-ID + } + catch (Exception $e) { + // in case of errors/exceptions call hook again with previous returned mail_id and error-message to log + $GLOBALS['egw']->hooks->process(array( + 'location' => 'send_mail', + 'subject' => $subject, + 'from' => $this->getHeader('Return-Path') ? $this->getHeader('Return-Path') : $this->getHeader('From'), + 'to' => $to, + 'cc' => $cc, + 'bcc' => $bcc, + 'body_sha1' => $body_sha1, + 'message_id' => (string)$message_id, + 'mail_id' => $mail_id, + 'error' => $e->getMessage(), + ), array(), true); // true = call all apps + } + + // log mails to file specified in $GLOBALS['egw_info']['server']['log_mail'] or error_log for true + if ($GLOBALS['egw_info']['server']['log_mail']) + { + $msg = $GLOBALS['egw_info']['server']['log_mail'] !== true ? date('Y-m-d H:i:s')."\n" : ''; + $msg .= (isset($e) ? 'Mail send' : 'Mail NOT send'). + ' to '.implode(', ', $to).' with subject: "'.$subject.'"'; + + $msg .= ' from instance '.$GLOBALS['egw_info']['user']['domain'].' and IP '.egw_session::getuser_ip(); + $msg .= ' from user #'.$GLOBALS['egw_info']['user']['account_id']; + + if ($GLOBALS['egw_info']['user']['account_id'] && class_exists('common',false)) + { + $msg .= ' ('.common::grab_owner_name($GLOBALS['egw_info']['user']['account_id']).')'; + } + if (isset($e)) + { + $msg .= $GLOBALS['egw_info']['server']['log_mail'] !== true ? "\n" : ': '; + $msg .= 'ERROR '.$e->getMessage(); + } + $msg .= ' cc='.implode(', ', $cc).', bcc='.implode(', ', $bcc); + if ($GLOBALS['egw_info']['server']['log_mail'] !== true) $msg .= "\n\n"; + + error_log($msg,$GLOBALS['egw_info']['server']['log_mail'] === true ? 0 : 3, + $GLOBALS['egw_info']['server']['log_mail']); + } + // rethrow error + if (isset($e)) throw $e; } + /** * Reset all Settings to send multiple Messages */ @@ -688,131 +775,4 @@ class egw_mailer extends Horde_Mime_Mail error_log(__METHOD__."('$name') unsupported attribute '$name' --> returning NULL ".function_backtrace()); return null; } - - /** - * Log mails to log file specified in $GLOBALS['egw_info']['server']['log_mail'] - * or regular error_log for true (can be set either in DB or header.inc.php). - * - * We can NOT supply this method as callback to phpMailer, as phpMailer only accepts - * functions (not methods) and from a function we can NOT access $this->ErrorInfo. - * - * @param boolean $isSent - * @param string $to - * @param string $cc - * @param string $bcc - * @param string $subject - * @param string $body - */ - protected function doCallback($isSent,$to,$cc,$bcc,$subject,$body) - { - if ($GLOBALS['egw_info']['server']['log_mail']) - { - $msg = $GLOBALS['egw_info']['server']['log_mail'] !== true ? date('Y-m-d H:i:s')."\n" : ''; - $msg .= ($isSent ? 'Mail send' : 'Mail NOT send'). - ' to '.$to.' with subject: "'.trim($subject).'"'; - - $msg .= ' from instance '.$GLOBALS['egw_info']['user']['domain'].' and IP '.egw_session::getuser_ip(); - $msg .= ' from user #'.$GLOBALS['egw_info']['user']['account_id']; - - if ($GLOBALS['egw_info']['user']['account_id'] && class_exists('common',false)) - { - $msg .= ' ('.common::grab_owner_name($GLOBALS['egw_info']['user']['account_id']).')'; - } - if (!$isSent) - { - $this->SetError(''); // queries error from (private) smtp and stores it in $this->ErrorInfo - $msg .= $GLOBALS['egw_info']['server']['log_mail'] !== true ? "\n" : ': '; - $msg .= 'ERROR '.str_replace(array('Language string failed to load: smtp_error',"\n","\r"),'', - strip_tags($this->ErrorInfo)); - } - $msg .= " cc=$cc, bcc=$bcc"; - if ($GLOBALS['egw_info']['server']['log_mail'] !== true) $msg .= "\n\n"; - - error_log($msg,$GLOBALS['egw_info']['server']['log_mail'] === true ? 0 : 3, - $GLOBALS['egw_info']['server']['log_mail']); - } - // calling the orginal callback of phpMailer - parent::doCallback($isSent,$to,$cc,$bcc,$subject,$body); - } - - private $addresses = array(); - - /** - * Initiates a connection to an SMTP server. - * Returns false if the operation failed. - * - * Overwriting this method from phpmailer, to make sure we set SMTPSecure to ssl or tls if the standardports for ssl or tls - * are configured for the given profile - * - * @uses SMTP - * @access public - * @return bool - */ - public function SmtpConnect() - { - $port = $this->Port; - $hosts = explode(';',$this->Host); - foreach ($hosts as &$host) - { - $host = trim($host); // make sure there is no whitespace leading or trailling the host string - if (in_array($port,array(465,587)) && strpos($host,'://')===false) - { - //$host = ($port==587?'tls://':'ssl://').trim($host); - $this->SMTPSecure = ($port==587?'tls':'ssl'); - } - //error_log(__METHOD__.__LINE__.' Smtp Host:'.$host.' SmtpSecure:'.($this->SMTPSecure?$this->SMTPSecure:'no')); - } - return parent::SmtpConnect(); - } - - /** - * Sends mail via SMTP using PhpSMTP - * - * Overwriting this method from phpmailer, to allow apps to intercept it - * via "send_mail" hook, eg. to log or authorize sending of mail. - * Hooks can throw phpmailerException($message, phpMailer::STOP_CRITICAL), - * to stop sending the mail out like an SMTP error. - * - * @param string $header The message headers - * @param string $body The message body - * @return bool - */ - public function SmtpSend($header, $body) - { - $matches = null; - $mail_id = $GLOBALS['egw']->hooks->process(array( - 'location' => 'send_mail', - 'subject' => $this->Subject, - 'from' => $this->Sender ? $this->Sender : $this->From, - 'to' => $this->addresses['To'], - 'cc' => $this->addresses['Cc'], - 'bcc' => $this->addresses['Bcc'], - 'body_sha1' => sha1($body), - 'message_id' => preg_match('/^Message-ID: (.*)$/m', $header, $matches) ? $matches[1] : null, - ), array(), true); // true = call all apps - - $this->addresses = array(); // reset addresses for next mail - - try { - // calling the overwritten method - return parent::SmtpSend($header, $body); - } - catch (phpmailerException $e) { - // in case of errors/exceptions call hook again with previous returned mail_id and error-message to log - $GLOBALS['egw']->hooks->process(array( - 'location' => 'send_mail', - 'subject' => $this->Subject, - 'from' => $this->Sender ? $this->Sender : $this->From, - 'to' => $this->addresses['To'], - 'cc' => $this->addresses['Cc'], - 'bcc' => $this->addresses['Bcc'], - 'body_sha1' => sha1($body), - 'message_id' => preg_match('/^Message-ID: (.*)$/m', $header,$matches) ? $matches[1] : null, - 'mail_id' => $mail_id, - 'error' => $e->getMessage(), - ), array(), true); // true = call all apps - // re-throw exception - throw $e; - } - } } From d0e2886f9829a1de74a46d31a93576778cf8c873 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 19 Dec 2014 17:58:44 +0000 Subject: [PATCH 057/295] fix fatal error for Horde_Mime < 2.5.0 --- phpgwapi/inc/class.egw_mailer.inc.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/phpgwapi/inc/class.egw_mailer.inc.php b/phpgwapi/inc/class.egw_mailer.inc.php index 309aa498be..fb899cbe65 100644 --- a/phpgwapi/inc/class.egw_mailer.inc.php +++ b/phpgwapi/inc/class.egw_mailer.inc.php @@ -409,9 +409,10 @@ class egw_mailer extends Horde_Mime_Mail */ function send() { - if (!($message_id = $this->getHeader('Message-ID'))) + if (!($message_id = $this->getHeader('Message-ID')) && + class_exists('Horde_Mime_Headers_MessageId')) // since 2.5.0 { - $message_id = Horde_Mime_Headers_MessageId::create(); + $message_id = Horde_Mime_Headers_MessageId::create('EGroupware'); $this->addHeader('Message-ID', $message_id); } $body_sha1 = null; // skip sha1, it requires whole mail in memory, which we traing to avoid now From aa526a3225c908af43df7caf70a059893c973e73 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Fri, 19 Dec 2014 22:14:54 +0000 Subject: [PATCH 058/295] Fix bug where clearing the entered value would lose the selected application --- etemplate/js/et2_widget_link.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etemplate/js/et2_widget_link.js b/etemplate/js/et2_widget_link.js index b355505ee1..09f1e122ce 100644 --- a/etemplate/js/et2_widget_link.js +++ b/etemplate/js/et2_widget_link.js @@ -811,7 +811,7 @@ var et2_link_entry = et2_inputWidget.extend( this.clear.hide(); this.options.value = _value = {'id':null}; } - if(!_value.app) _value.app = this.options.only_app; + if(!_value.app) _value.app = this.options.only_app || this.app_select.val(); if(_value.id) { // Remove specific display and revert to CSS file From c48065f4c3de19e0b3bfc1ea6173c53618423e23 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Fri, 19 Dec 2014 22:26:29 +0000 Subject: [PATCH 059/295] Add ability for admins to set home portlets as default, for groups, and forced for all. --- etemplate/js/et2_widget_portlet.js | 2 +- home/inc/class.home_link_portlet.inc.php | 11 +- home/inc/class.home_list_portlet.inc.php | 9 + home/inc/class.home_note_portlet.inc.php | 24 +- home/inc/class.home_portlet.inc.php | 14 +- home/inc/class.home_ui.inc.php | 299 +++++++++++++++++++---- home/js/app.js | 75 +++++- home/setup/setup.inc.php | 2 +- home/setup/tables_update.inc.php | 62 +++++ home/templates/default/index.xet | 6 + 10 files changed, 435 insertions(+), 69 deletions(-) create mode 100644 home/setup/tables_update.inc.php diff --git a/etemplate/js/et2_widget_portlet.js b/etemplate/js/et2_widget_portlet.js index 5e8f64608c..1783ad3b78 100644 --- a/etemplate/js/et2_widget_portlet.js +++ b/etemplate/js/et2_widget_portlet.js @@ -267,7 +267,7 @@ var et2_portlet = et2_valueWidget.extend( // Save settings - server might reply with new content if the portlet needs an update, // but ideally it doesn't this.div.addClass("loading"); - this.egw().jsonq("home.home_ui.ajax_set_properties",[this.id, this.options.settings || {}, value], + this.egw().jsonq("home.home_ui.ajax_set_properties",[this.id, this.options.settings || {}, value,this.settings?this.settings.group:false], function(data) { // This section not for us if(!data || typeof data.attributes == 'undefined') return false; diff --git a/home/inc/class.home_link_portlet.inc.php b/home/inc/class.home_link_portlet.inc.php index 437e4c3e99..66dcc6aa0f 100644 --- a/home/inc/class.home_link_portlet.inc.php +++ b/home/inc/class.home_link_portlet.inc.php @@ -125,7 +125,7 @@ class home_link_portlet extends home_portlet if(class_exists($classname)) { $record = new $classname($this->context['entry']['id']); - if($record) + if($record && $record->get_record_array()) { // If there's a custom template, send the full record if($custom_template) @@ -232,4 +232,13 @@ class home_link_portlet extends home_portlet return $actions; } + /** + * This portlet accepts files and links + * + * @return boolean|String[] + */ + public function accept_drop() + { + return array('file','link'); + } } diff --git a/home/inc/class.home_list_portlet.inc.php b/home/inc/class.home_list_portlet.inc.php index 3b5bb7d8a1..39f16b383b 100644 --- a/home/inc/class.home_list_portlet.inc.php +++ b/home/inc/class.home_list_portlet.inc.php @@ -191,4 +191,13 @@ class home_list_portlet extends home_portlet { return true; } + /** + * This portlet accepts files and links + * + * @return boolean|String[] + */ + public function accept_drop() + { + return array('file','link'); + } } diff --git a/home/inc/class.home_note_portlet.inc.php b/home/inc/class.home_note_portlet.inc.php index 920bf8014b..fa118e81c0 100644 --- a/home/inc/class.home_note_portlet.inc.php +++ b/home/inc/class.home_note_portlet.inc.php @@ -39,6 +39,7 @@ class home_note_portlet extends home_portlet $need_reload = true; } + $this->context = $context; } @@ -51,15 +52,23 @@ class home_note_portlet extends home_portlet $id = $_GET['id'] ? $_GET['id'] : $content['id']; $height = $_GET['height'] ? $_GET['height'] : $content['height']; - $prefs = $GLOBALS['egw']->preferences->read_repository(); - $portlets = (array)$prefs['home']['portlets']; - + if($content['group'] && $GLOBALS['egw_info']['apps']['admin']) + { + $prefs = new preferences(is_numeric($group) ? $group : $GLOBALS['egw_info']['user']['account_id']); + } + else + { + $prefs = $GLOBALS['egw']->preferences; + } + $type = is_numeric($group) ? "user" : $group; + $portlets = $prefs->read_repository(); + $portlets = $portlets['home']; if($content['button']) { - $portlets[$id]['note'] = $content['note']; // Save updated preferences - $GLOBALS['egw']->preferences->add('home', 'portlets', $portlets); - $GLOBALS['egw']->preferences->save_repository(True); + $portlets[$id]['note'] = $content['note']; + $prefs->add('home', $id, $portlets[$id],$type); + $prefs->save_repository(True,$type); // Yay for AJAX submit egw_json_response::get()->apply('window.opener.app.home.refresh',array($id)); @@ -76,8 +85,9 @@ class home_note_portlet extends home_portlet $etemplate->setElementAttribute('note', 'width', '99%'); $etemplate->setElementAttribute('note', 'height', $height); $preserve = array( - 'id' => $id, + 'id' => $id, 'height' => $height, + 'group' => $portlets[$id]['group'] ); $etemplate->exec('home.home_note_portlet.edit',$content, array(),array('note'=>false,'save'=>false), $preserve); } diff --git a/home/inc/class.home_portlet.inc.php b/home/inc/class.home_portlet.inc.php index 19428a2d5d..934e1b4717 100644 --- a/home/inc/class.home_portlet.inc.php +++ b/home/inc/class.home_portlet.inc.php @@ -96,7 +96,7 @@ abstract class home_portlet * same id / key to override the default action. */ public abstract function get_actions(); - + /** * If this portlet can accept, display, or otherwise handle multiple * EgroupWare entries. Used for drag and drop processing. How the entries @@ -107,6 +107,18 @@ abstract class home_portlet return false; } + /** + * If this portlet can be created by dropping, these are the drop types + * that are accepted + * + * @return boolean|String[] + */ + public function accept_drop() + { + // In general, no + return false; + } + public function __toString() { return get_called_class() . ' Context:' . array2string($this->context); diff --git a/home/inc/class.home_ui.inc.php b/home/inc/class.home_ui.inc.php index 08d5c13a4f..bd2ede93e1 100644 --- a/home/inc/class.home_ui.inc.php +++ b/home/inc/class.home_ui.inc.php @@ -121,7 +121,6 @@ class home_ui { $children['class'] = $app; $children['onExecute'] = $drop_execute; - $children['acceptedTypes'] = array('file','link'); $children['type'] = 'drop'; $actions["drop_$app"] = $children; } @@ -139,7 +138,9 @@ class home_ui } } } - + + // For admins, add the ability to set current home as a default + self::create_default_actions($actions); return $actions; } @@ -153,9 +154,12 @@ class home_ui { $portlets = array(); - foreach((array)$GLOBALS['egw_info']['user']['preferences']['home']['portlets'] as $id => $context) + foreach((array)$GLOBALS['egw_info']['user']['preferences']['home']as $id => $context) { - if(!$id || in_array($id, array_keys($GLOBALS['egw_info']['user']['apps']))) continue; + if(strpos($id,'portlet_') !== 0 || // Not a portlet + in_array($id, array_keys($GLOBALS['egw_info']['user']['apps'])) || // Some other app put it's pref in here + !is_array($context) // Not a valid portlet (probably user deleted a default) + ) continue; $classname = $context['class']; $portlet = new $classname($context); @@ -181,7 +185,12 @@ class home_ui // Set actions // Must be after settings so actions can take settings into account - $template->setElementAttribute("portlets[" . count($portlets) . "[$id]", 'actions', $portlet->get_actions()); + $actions = $portlet->get_actions(); + + // Add in default for admins + self::create_default_actions($actions, $id); + + $template->setElementAttribute("portlets[" . count($portlets) . "[$id]", 'actions', $actions); $portlets[] = $portlet_content; } @@ -242,6 +251,8 @@ class home_ui 'settings' => $settings, 'actions' => $portlet->get_actions(), ); + // Add in default settings + self::create_default_actions($attributes['actions'], $id); // Set any provided common attributes (size, etc) foreach(home_portlet::$common_attributes as $name) @@ -371,6 +382,7 @@ class home_ui 'caption' => $desc['displayName'], 'hint' => $desc['description'], 'onExecute' => 'javaScript:app.home.add', + 'acceptedTypes' => $instance->accept_drop(), 'allowOnMultiple' => $instance->accept_multiple() ); } @@ -382,79 +394,262 @@ class home_ui return $list; } + /** + * Create an action to set the portlet as default + * + * @param Array $actions Existing action list + * @param String $portlet_id Provide the ID to have the checkbox set + */ + protected static function create_default_actions(&$actions, $portlet_id = null) + { + if($GLOBALS['egw_info']['user']['apps']['admin']) + { + $actions['add_default'] = array( + 'type' => 'popup', + 'caption' => 'Set as default', + 'onExecute' => 'javaScript:app.home.set_default', + 'group' => 'Admins', + 'icon' => 'preference' + ); + // Customize for the given portlet + if($portlet_id !== null) + { + $portlet = $GLOBALS['egw_info']['user']['preferences']['home'][$portlet_id]; + + foreach(array('forced','group','default') as $location) + { + $loc = $GLOBALS['egw']->preferences->$location; + + if($loc['home'][$portlet_id]) + { + // If it's forced, no point in setting default + if($location == 'forced') + { + unset($actions['add_default']); + } + // If it's a group, we'd like to know which + if($location == 'group') + { + $options = array('account_type' => $type); + $groups = accounts::link_query('',$options); + foreach($groups as $gid => $name) + { + $prefs = new preferences($gid); + $prefs->read_repository(); + if (isset($prefs->user['home'][$portlet_id])) + { + $location = $gid; + break; + } + } + } + $actions['remove_default_'.$location] = array( + 'type' => 'popup', + 'caption' => lang('Remove default %1',is_numeric($location) ? accounts::id2name($location) : $location), + 'onExecute' => 'javaScript:app.home.set_default', + 'group' => 'Admins', + 'portlet_group' => $location + ); + } + } + } + } + + // Change action for forced + if($portlet_id && $GLOBALS['egw']->preferences->forced['home'][$portlet_id]) + { + // No one can remove it + $actions['remove_portlet']['enabled'] = false; + $actions['remove_portlet']['caption'] .= ' ('.lang('Forced') .')'; + + // Non-admins can't edit it + if($actions['edit_settings'] && !$GLOBALS['egw_info']['user']['apps']['admin']) + { + $actions['edit_settings']['enabled'] = false; + $actions['edit_settings']['visible'] = false; + } + } + } + /** * Update the settings for a particular portlet, and give updated content * * @param portlet_id String Unique ID (for the user) for a portlet * @param values Array List of property => value pairs + * @param boolean|int|String $group False for current user, ID of the group to create the favorite for, or 'all' for all users * */ - public function ajax_set_properties($portlet_id, $attributes, $values) + public function ajax_set_properties($portlet_id, $attributes, $values, $group = false) { if(!$attributes) { $attributes = array(); } - $response = egw_json_response::get(); - if ($GLOBALS['egw_info']['user']['apps']['preferences']) + + if(!$GLOBALS['egw_info']['user']['apps']['admin']) { - $prefs = $GLOBALS['egw']->preferences->read_repository(); - $portlets = (array)$prefs['home']['portlets']; - if($values =='~reload~') + if($group == 'forced') { - $full_exec = true; - $values = array(); + // Quietly reject + return; } - if($values == '~remove~') + // Not an admin, can only override. + $group = false; + } + if($group && $GLOBALS['egw_info']['user']['apps']['admin']) + { + $prefs = new preferences(is_numeric($group) ? $group : $GLOBALS['egw_info']['user']['account_id']); + } + else + { + $prefs = $GLOBALS['egw']->preferences; + } + $type = is_numeric($group) ? "user" : $group; + + $prefs->read_repository(); + + $response = egw_json_response::get(); + + if($values =='~reload~') + { + $full_exec = true; + $values = array(); + } + if($values == '~remove~') + { + // Already removed client side, needs to be removed permanently + $default = $prefs->default_prefs('home',$portlet_id) || $prefs->group['home'][$portlet_id]; + + if($default) { - unset($portlets[$portlet_id]); - // Already removed client side + // Can't delete forced - not a UI option though + if(!$GLOBALS['egw']->preferences->forced['home'][$portlet_id]) + { + // Set a flag to override default instead of just delete + $GLOBALS['egw']->preferences->add('home',$portlet_id, 'deleted'); + $GLOBALS['egw']->preferences->save_repository(); + } } else { - // Get portlet settings, and merge new with old - $context = $values+(array)$portlets[$portlet_id]; + $prefs->delete('home', $portlet_id); + } + } + else + { + $portlets = $prefs->read(); + $portlets = $portlets['home']; - // Handle add IDs - $classname =& $context['class']; - if(strpos($classname,'add_') == 0 && !class_exists($classname)) + // Remove some constant stuff that winds up here + unset($values['edit_template']); + unset($values['readonly']); + unset($values['disabled']);unset($values['no_lang']); + unset($values['actions']); + unset($values['statustext']); + unset($values['type']);unset($values['label']);unset($values['status']); + unset($values['value']);unset($values['align']); + + // Get portlet settings, and merge new with old + $context = $values+(array)$portlets[$portlet_id]; + $context['group'] = $group; + + + + // Handle add IDs + $classname =& $context['class']; + if(strpos($classname,'add_') == 0 && !class_exists($classname)) + { + $add = true; + $classname = substr($classname, 4); + } + $portlet = $this->get_portlet($portlet_id, $context, $content, $attributes, $full_exec); + + $context['class'] = get_class($portlet); + foreach($portlet->get_properties() as $property) + { + if($values[$property['name']]) { - $add = true; - $classname = substr($classname, 4); + $context[$property['name']] = $values[$property['name']]; } - $portlet = $this->get_portlet($portlet_id, $context, $content, $attributes, $full_exec); - - $context['class'] = get_class($portlet); - foreach($portlet->get_properties() as $property) + elseif($portlets[$portlet_id][$property['name']]) { - if($values[$property['name']]) - { - $context[$property['name']] = $values[$property['name']]; - } - elseif($portlets[$portlet_id][$property['name']]) - { - $context[$property['name']] = $portlets[$portlet_id][$property['name']]; - } + $context[$property['name']] = $portlets[$portlet_id][$property['name']]; } - - // Update client side - $update = array('attributes' => $attributes); - - // New portlet? Flag going straight to edit mode - if($add) - { - $update['edit_settings'] = true; - } - // Send this back to the portlet widget - $response->data($update); - - // Store for preference update - $portlets[$portlet_id] = $context; } - // Save updated preferences - $GLOBALS['egw']->preferences->add('home', 'portlets', $portlets); - $GLOBALS['egw']->preferences->save_repository(True); + // Update client side + $update = array('attributes' => $attributes); + + // New portlet? Flag going straight to edit mode + if($add) + { + $update['edit_settings'] = true; + } + // Send this back to the portlet widget + $response->data($update); + + // Store for preference update + $prefs->add('home', $portlet_id, $context, $type); } + + // Save updated preferences + $prefs->save_repository(True,$type); + } + + /** + * Set the selected portlets as default for a group + * + * @param String $action 'add' or 'delete' + * @param String[] $portlet_ids + * @param int|String $group Group ID or 'default' or 'forced' + */ + public static function ajax_set_default($action, $portlet_ids, $group) + { + // Admins only + if(!$GLOBALS['egw_info']['apps']['admin']) return; + + // Load the appropriate group + if($group) + { + $prefs = new preferences(is_numeric($group) ? $group : $GLOBALS['egw_info']['user']['account_id']); + } + else + { + $prefs = $GLOBALS['egw']->preferences; + } + $prefs->read_repository(); + + $type = is_numeric($group) ? "user" : $group; + + if($action == 'add') + { + foreach($portlet_ids as $id) + { + egw_json_response::get()->call('egw.message', lang("Set default")); + // Current user is setting the default, copy their settings + $settings = $GLOBALS['egw_info']['user']['preferences']['home'][$id]; + $settings['group'] = $group; + $prefs->add('home',$id,$settings,$type); + + // Remove user's copy + $GLOBALS['egw']->preferences->delete('home',$id); + $GLOBALS['egw']->preferences->save_repository(true); + } + } + else if ($action == "delete") + { + foreach($portlet_ids as $id) + { + egw_json_response::get()->call('egw.message', lang("Removed default")); + error_log("Clearing $type $group default $id"); + $result = $prefs->delete('home',$id, $type); + } + } + $prefs->save_repository(false,$type); + + // Update preferences client side for consistency + $prefs = $GLOBALS['egw']->preferences; + $pref = $prefs->read_repository(); + egw_json_response::get()->call('egw.set_preferences', (array)$pref['home'], 'home'); } } diff --git a/home/js/app.js b/home/js/app.js index e09c03ed94..dccd5a29d2 100644 --- a/home/js/app.js +++ b/home/js/app.js @@ -148,7 +148,7 @@ app.classes.home = AppJS.extend( { for(var i = 0; i < portlet._children.length; i++) { - portlet._children[i]._inst.clear(); + if(portlet._children[i]._inst) portlet._children[i]._inst.clear(); } portlet._children = []; } @@ -270,6 +270,65 @@ app.classes.home = AppJS.extend( ); }, + /** + * Set the current selection as default for other users + * + * Only works (and available) for admins, this shows a dialog to select + * the group, and then sets the default for that group. + * + * @param {egwAction} action + * @param {egwActionObject[]} selected + */ + set_default: function(action, selected) { + // Gather just IDs, server will handle the details + var portlet_ids = []; + var group = action.data.portlet_group || false; + if(selected[0].id == 'home.index') + { + // Set all + this.portlet_container.iterateOver(function(portlet) { + portlet_ids.push(portlet.id); + },this,et2_portlet); + } + else + { + for(var i = 0; i < selected.length; i++) + { + portlet_ids.push(selected[i].id); + + // Read the associated group so we can properly remove it + var portlet = egw.preference(selected[i].id,'home'); + if(!group && portlet && portlet.group) + { + group = portlet.group; + } + } + } + + if(action.id.indexOf("remove_default") == 0) + { + // Disable action for feedback + action.set_enabled(false); + + // Pass them to server + egw.json('home_ui::ajax_set_default', ['delete', portlet_ids, group]).sendRequest(true); + return; + } + var dialog = et2_createWidget("dialog",{ + // If you use a template, the second parameter will be the value of the template, as if it were submitted. + callback: function(button_id, value) { + if(button_id != et2_dialog.OK_BUTTON) return; + + // Pass them to server + egw.json('home_ui::ajax_set_default', ['add', portlet_ids, value.group||false]).sendRequest(true); + }, + buttons: et2_dialog.BUTTONS_OK_CANCEL, + title: action.caption, + template:"home.set_default", + value: {content:{}, sel_options: {group:{default: egw.lang('All'), forced: egw.lang('Forced')}}} + }); + }, + /** * Allow a refresh from anywhere by triggering an update with no changes * @@ -363,7 +422,7 @@ app.classes.home = AppJS.extend( egw().jsonq("home.home_ui.ajax_set_properties",[changed[key].id, widget.options.settings,{ row: changed[key].row, col: changed[key].col - }], + },widget.settings?widget.settings.group:false], null, widget, true, widget ); @@ -401,8 +460,8 @@ app.classes.home = AppJS.extend( .toString(16) .substring(1); } - while(this.portlet_container.getWidgetById(id)); - return id; + while(this.portlet_container.getWidgetById('portlet_'+id)); + return 'portlet_'+id; }, /** @@ -456,7 +515,11 @@ app.classes.home = AppJS.extend( new_list.push(value.add); widget._process_edit(button_id,{list: new_list}); // Update client side - widget.getWidgetById('list').set_value(new_list); + var list = widget.getWidgetById('list'); + if(list) + { + list.set_value(new_list); + } }, buttons: et2_dialog.BUTTONS_OK_CANCEL, title: app.home.egw.lang('add'), @@ -542,7 +605,7 @@ app.classes.home = AppJS.extend( } // Aim to match the size - var portlet_dom = $j('[id$='+id+'][data-sizex]',this.portlet_container.getDOMNode); + var portlet_dom = $j('[id$='+id+'][data-sizex]',this.portlet_container.getDOMNode()); var width = portlet_dom.attr('data-sizex') * this.GRID; var height = portlet_dom.attr('data-sizey') * this.GRID; diff --git a/home/setup/setup.inc.php b/home/setup/setup.inc.php index 61414b364b..da0729f0ec 100755 --- a/home/setup/setup.inc.php +++ b/home/setup/setup.inc.php @@ -11,7 +11,7 @@ /* Basic information about this app */ $setup_info['home']['name'] = 'home'; $setup_info['home']['title'] = 'Home'; -$setup_info['home']['version'] = '14.1'; +$setup_info['home']['version'] = '14.1.001'; $setup_info['home']['app_order'] = 1; $setup_info['home']['enable'] = 1; $setup_info['home']['index'] = 'home.home_ui.index&ajax=true'; diff --git a/home/setup/tables_update.inc.php b/home/setup/tables_update.inc.php new file mode 100644 index 0000000000..238e4c9399 --- /dev/null +++ b/home/setup/tables_update.inc.php @@ -0,0 +1,62 @@ +db->select('egw_preferences','preference_owner,preference_app,preference_value',array( + 'preference_app' => 'home', + ),__LINE__,__FILE__) as $row) + { + $preferences[] = $row; + } + foreach($preferences as $row) + { + // The following replacement is required for PostgreSQL to work + $app = trim($row['preference_app']); + + // Move portlets into top level, not a sub-array + if ($row['preference_value'][0] != 'a' && $row['preference_value'][1] != ':') + { + $values = json_decode($row['preference_value'], true); + } + else + { + // Too old, skip it + continue; + } + if($values['portlets'] && is_array($values['portlets'])) + { + error_log("Portlets:"); + foreach($values['portlets'] as $id => $settings) + { + error_log($id); + $values["portlet_$id"] = $settings; + } + unset($values['portlets']); + } + $GLOBALS['egw_setup']->db->insert( + 'egw_preferences',array( + 'preference_value' => json_encode($values), + ),array( + 'preference_owner' => $row['preference_owner'], + 'preference_app' => $app, + ),__LINE__,__FILE__ + ); + } + + return $GLOBALS['setup_info']['home']['currentver'] = '14.1.001'; +} + diff --git a/home/templates/default/index.xet b/home/templates/default/index.xet index 11d4e97a5d..5e69a1d244 100644 --- a/home/templates/default/index.xet +++ b/home/templates/default/index.xet @@ -1,6 +1,12 @@ +