Updated Branches: refs/heads/master 57a60e165 -> 680772c1a
Replaced ID / timestamp popovers with copy-to-clipboard. From: Ross Allen <ross...@mesosphe.re> Review: https://reviews.apache.org/r/12730 Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/04d5d9b4 Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/04d5d9b4 Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/04d5d9b4 Branch: refs/heads/master Commit: 04d5d9b405ef98b1c668c211b81cce2626e55fc7 Parents: 57a60e1 Author: Benjamin Mahler <bmah...@twitter.com> Authored: Thu Jul 18 16:13:29 2013 -0700 Committer: Benjamin Mahler <bmah...@twitter.com> Committed: Thu Jul 18 16:14:22 2013 -0700 ---------------------------------------------------------------------- src/Makefile.am | 5 +- src/webui/master/static/app.js | 83 +++- src/webui/master/static/framework.html | 41 +- src/webui/master/static/frameworks.html | 50 ++- src/webui/master/static/home.html | 115 ++--- src/webui/master/static/index.html | 1 + src/webui/master/static/mesos.css | 24 ++ .../master/static/obj/zeroclipboard-1.1.7.swf | Bin 0 -> 1635 bytes src/webui/master/static/slave.html | 52 ++- src/webui/master/static/slaves.html | 33 +- src/webui/master/static/zeroclipboard-1.1.7.js | 432 +++++++++++++++++++ .../master/static/zeroclipboard-1.1.7.min.js | 8 + 12 files changed, 720 insertions(+), 124 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/04d5d9b4/src/Makefile.am ---------------------------------------------------------------------- diff --git a/src/Makefile.am b/src/Makefile.am index d7eb946..4fdc41b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -405,7 +405,10 @@ nobase_dist_webui_DATA += \ webui/master/static/cubism.v1.min.js \ webui/master/static/d3.v2.js \ webui/master/static/d3.v2.min.js \ - webui/master/static/relative-date.js + webui/master/static/relative-date.js \ + webui/master/static/zeroclipboard-1.1.7.js \ + webui/master/static/zeroclipboard-1.1.7.min.js \ + webui/master/static/obj/zeroclipboard-1.1.7.swf # Need to distribute/install bootstrap. nobase_dist_webui_DATA += \ http://git-wip-us.apache.org/repos/asf/mesos/blob/04d5d9b4/src/webui/master/static/app.js ---------------------------------------------------------------------- diff --git a/src/webui/master/static/app.js b/src/webui/master/static/app.js index 2bfcedf..53d3a7f 100644 --- a/src/webui/master/static/app.js +++ b/src/webui/master/static/app.js @@ -16,6 +16,9 @@ angular.module('mesos', ['ui.bootstrap']). $dialogProvider.options({dialogFade: true}); + ZeroClipboard.setDefaults({ + moviePath: '/static/obj/zeroclipboard-1.1.7.swf' + }); }]) .filter('truncateMesosID', function() { return function(id) { @@ -64,12 +67,12 @@ angular.module('mesos', ['ui.bootstrap']). } else { return (bytes / (1024 * 1024 * 1024)).toFixed() + ' GB'; } - } + }; }) // Defines the ui-if tag. This removes/adds an element from the DOM depending on a condition // Originally created by @tigbro, for the @jquery-mobile-angular-adapter // https://github.com/tigbro/jquery-mobile-angular-adapter - .directive('uiIf', [function () { + .directive('uiIf', [function() { return { transclude: 'element', priority: 1000, @@ -104,6 +107,82 @@ angular.module('mesos', ['ui.bootstrap']). }; } }; + }]) + // Defines the 'clipboard' directive, which integrates copying to the user's + // clipboard with an Adobe Flash object via the ZeroClipboard library. + // + // Text to be copied on click is specified with the 'data-clipboard-text' + // attribute. + // + // The 'mouseenter' and 'mouseleave' events from the Flash object are exposed + // to the directive's element via the 'clipboardhover' event. There is no + // differentiation between enter/leave; they are both called 'clipboardhover'. + // + // Example: + // + // <button class="btn btn-mini" clipboard + // data-clipboard-text="I'm in your clipboard!"> + // </button> + // + // See: http://zeroclipboard.github.io/ZeroClipboard/ + .directive('clipboard', [function() { + return { + restrict: 'A', + scope: true, + template: '<i class="icon-file"></i>', + + link: function(scope, element, attrs) { + var clip = new ZeroClipboard(element[0]); + + clip.on('mouseover', function() { + $(this).trigger('clipboardhover'); + }); + + clip.on('mouseout', function() { + // TODO(ssorallen): Why is 'scope' incorrect here? It has to be + // retrieved from the element explicitly to be correct. + var elScope = angular.element(this).scope(); + + // Restore tooltip content to its original value if it was changed by + // this Clipboard instance. + if (elScope && elScope.tt_content_orig) { + elScope.tt_content = elScope.tt_content_orig; + delete elScope.tt_content_orig; + } + + $(this).trigger('clipboardhover'); + }); + + clip.on('complete', function() { + // TODO(ssorallen): Why is 'scope' incorrect here? It has to be + // retrieved from the element explicitly to be correct. + var elScope = angular.element(this).scope(); + + if (elScope) { + // Store the tooltip's original content so it can be restored when + // the tooltip is hidden. + elScope.tt_content_orig = elScope.tt_content; + + // Angular UI's Tooltip sets content on the element's scope in a + // variable named 'tt_content'. The Tooltip has no public interface, + // so set the value directly here to change the value of the tooltip + // when content is successfully copied. + elScope.tt_content = 'copied!'; + elScope.$apply(); + } + }); + + clip.on('load', function() { + // The 'load' event fires only if the Flash file loads successfully. + // The copy buttons will only display if the class 'flash' exists + // on an ancestor. + // + // Browsers with no flash support will not append the 'flash' class + // and will therefore not see the copy buttons. + $('html').addClass('flash'); + }); + } + }; }]); function setNavbarActiveTab(tab_name) { http://git-wip-us.apache.org/repos/asf/mesos/blob/04d5d9b4/src/webui/master/static/framework.html ---------------------------------------------------------------------- diff --git a/src/webui/master/static/framework.html b/src/webui/master/static/framework.html index 97d25b7..a0d5fe4 100644 --- a/src/webui/master/static/framework.html +++ b/src/webui/master/static/framework.html @@ -24,21 +24,28 @@ <dd>{{framework.user}}</dd> <dt>Registered:</dt> <dd> - <a href="javascript:void(0)" - popover="{{framework.registered_time * 1000 | mesosDate}}" - popover-placement="bottom" - popover-title="Registered"> - {{framework.registered_time * 1000 | relativeDate}} - </a> + <abbr title="{{framework.registered_time * 1000 | mesosDate}}"> + {{framework.registered_time * 1000 | relativeDate}}</abbr> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{framework.registered_time * 1000 | mesosDate}}" + tooltip="Copy timestamp" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + </button> </dd> <dt>Re-registered:</dt> - <dd> - <a href="javascript:void(0)" - popover="{{framework.reregistered_time * 1000 | mesosDate}}" - popover-placement="bottom" - popover-title="Reregistered"> - {{framework.reregistered_time * 1000 | relativeDate}} - </a> + <dd ng-show="!framework.reregistered_time">-</dd> + <dd ng-show="framework.reregistered_time"> + <abbr title="{{framework.reregistered_time * 1000 | mesosDate}}"> + {{framework.reregistered_time * 1000 | relativeDate}}</abbr> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{framework.reregistered_time * 1000 | mesosDate}}" + tooltip="Copy timestamp" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + </button> </dd> <dt>Active tasks:</dt> <dd>{{framework.tasks.length | number}}</dd> @@ -75,14 +82,14 @@ </thead> <tbody> <tr ng-repeat="task in framework.tasks | orderBy:tables['active_tasks'].selected_column:tables['active_tasks'].reverse"> - <td>{{task.id}}</td> - <td>{{task.name}}</td> - <td>{{task.state | truncateMesosState}}</td> <td> <a href="#/slaves/{{task.slave_id}}/frameworks/{{task.framework_id}}/executors/{{task.executor_id}}"> - {{slaves[task.slave_id].hostname}} + {{task.id}} </a> </td> + <td>{{task.name}}</td> + <td>{{task.state | truncateMesosState}}</td> + <td>{{slaves[task.slave_id].hostname}}</td> </tr> </tbody> </table> http://git-wip-us.apache.org/repos/asf/mesos/blob/04d5d9b4/src/webui/master/static/frameworks.html ---------------------------------------------------------------------- diff --git a/src/webui/master/static/frameworks.html b/src/webui/master/static/frameworks.html index bcae436..30ae7b9 100644 --- a/src/webui/master/static/frameworks.html +++ b/src/webui/master/static/frameworks.html @@ -55,34 +55,44 @@ <tbody> <tr ng-repeat="framework in _.values(frameworks) | orderBy:tables['frameworks'].selected_column:tables['frameworks'].reverse"> <td> - <a href="javascript:void(0)" - popover="{{framework.id}}" - popover-placement="bottom" - popover-title="ID"> - {{framework.id | truncateMesosID}} - </a> + <a href="{{'#/frameworks/' + framework.id}}"> + {{(framework.id | truncateMesosID) || framework.name}}</a> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{framework.id}}" + tooltip="Copy ID" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + </button> </td> <td>{{framework.user}}</td> - <td><a href="{{'#/frameworks/' + framework.id}}">{{framework.name}}</a></td> + <td>{{framework.name}}</td> <td>{{framework.tasks.length}}</td> <td>{{framework.resources.cpus | number}}</td> <td>{{framework.resources.mem * (1024 * 1024) | dataSize}}</td> <td>{{framework.max_share * 100 | number}}%</td> <td> - <a href="javascript:void(0)" - popover="{{framework.registered_time * 1000 | mesosDate}}" - popover-placement="bottom" - popover-title="Registered"> - {{framework.registered_time * 1000 | relativeDate}} - </a> + <abbr title="{{framework.registered_time * 1000 | mesosDate}}"> + {{framework.registered_time * 1000 | relativeDate}}</abbr> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{framework.registered_time * 1000 | mesosDate}}" + tooltip="Copy timestamp" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + </button> </td> - <td> - <a href="javascript:void(0)" - popover="{{framework.reregistered_time * 1000 | mesosDate}}" - popover-placement="bottom" - popover-title="Reregistered"> - {{framework.reregistered_time * 1000 | relativeDate}} - </a> + <td ng-show="!framework.reregistered_time">-</td> + <td ng-show="framework.reregistered_time"> + <abbr title="{{framework.reregistered_time * 1000 | mesosDate}}"> + {{framework.reregistered_time * 1000 | relativeDate}}</abbr> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{framework.registered_time * 1000 | mesosDate}}" + tooltip="Copy timestamp" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + </button> </td> </tr> </tbody> http://git-wip-us.apache.org/repos/asf/mesos/blob/04d5d9b4/src/webui/master/static/home.html ---------------------------------------------------------------------- diff --git a/src/webui/master/static/home.html b/src/webui/master/static/home.html index d45cc94..4a76fcf 100644 --- a/src/webui/master/static/home.html +++ b/src/webui/master/static/home.html @@ -23,21 +23,28 @@ <dd>{{state.pid.split("@")[1]}}</dd> <dt>Built:</dt> <dd> - <a href="javascript:void(0)" - popover="{{state.build_time * 1000 | mesosDate}}" - popover-placement="right" - popover-title="Built"> - {{state.build_time * 1000 | relativeDate}} - </a> by <i>{{state.build_user}}</i> + <abbr title="{{state.build_time * 1000 | mesosDate}}"> + {{state.build_time * 1000 | relativeDate}}</abbr> + by <i>{{state.build_user}}</i> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{state.build_time * 1000 | mesosDate}}" + tooltip="Copy timestamp" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + </button> </dd> <dt>Started:</dt> <dd> - <a href="javascript:void(0)" - popover="{{state.start_time * 1000 | mesosDate}}" - popover-placement="right" - popover-title="Started"> - {{state.start_time * 1000 | relativeDate}} - </a> + <abbr title="{{state.start_time * 1000 | mesosDate}}"> + {{state.start_time * 1000 | relativeDate}}</abbr> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{state.start_time * 1000 | mesosDate}}" + tooltip="Copy timestamp" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + </button> </dd> </dl> @@ -173,34 +180,44 @@ <tbody> <tr ng-repeat="framework in _.values(frameworks) | orderBy:tables['frameworks'].selected_column:tables['frameworks'].reverse"> <td> - <a href="javascript:void(0)" - popover="{{framework.id}}" - popover-placement="bottom" - popover-title="ID"> - {{framework.id | truncateMesosID}} - </a> + <a href="{{'#/frameworks/' + framework.id}}"> + {{(framework.id | truncateMesosID) || framework.name}}</a> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{framework.id}}" + tooltip="Copy ID" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + </button> </td> <td>{{framework.user}}</td> - <td><a href="{{'#/frameworks/' + framework.id}}">{{framework.name}}</a></td> + <td>{{framework.name}}</td> <td>{{framework.tasks.length}}</td> <td>{{framework.resources.cpus | number}}</td> <td>{{framework.resources.mem * (1024 * 1024) | dataSize}}</td> <td>{{framework.max_share * 100 | number}}%</td> <td> - <a href="javascript:void(0)" - popover="{{framework.registered_time * 1000 | mesosDate}}" - popover-placement="bottom" - popover-title="Registered"> - {{framework.registered_time * 1000 | relativeDate}} - </a> + <abbr title="{{framework.registered_time * 1000 | mesosDate}}"> + {{framework.registered_time * 1000 | relativeDate}}</abbr> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{framework.registered_time * 1000 | mesosDate}}" + tooltip="Copy timestamp" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + </button> </td> - <td> - <a href="javascript:void(0)" - popover="{{framework.reregistered_time * 1000 | mesosDate}}" - popover-placement="bottom" - popover-title="Reregistered"> - {{framework.reregistered_time * 1000 | relativeDate}} - </a> + <td ng-show="!framework.reregistered_time">-</td> + <td ng-show="framework.reregistered_time"> + <abbr title="{{framework.reregistered_time * 1000 | mesosDate}}"> + {{framework.reregistered_time * 1000 | relativeDate}}</abbr> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{framework.reregistered_time * 1000 | mesosDate}}" + tooltip="Copy timestamp" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + </button> </td> </tr> </tbody> @@ -241,27 +258,29 @@ </thead> <tr ng-repeat="slave in _.values(slaves) | orderBy:tables['slaves'].selected_column:tables['slaves'].reverse"> <td> - <a href="javascript:void(0)" - popover="{{slave.id}}" - popover-placement="bottom" - popover-title="ID"> - {{slave.id | truncateMesosID}} - </a> + <a href="#/slaves/{{slave.id}}">{{slave.id | truncateMesosID}}</a> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{slave.id}}" + tooltip="Copy ID" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + </button> </td> - <td> - <a href="#/slaves/{{slave.id}}"> - {{slave.hostname}} - </a> + <td>{{slave.hostname}}</td> <td>{{slave.resources.cpus | number}}</td> <td>{{slave.resources.mem * (1024 * 1024) | dataSize}}</td> <td>{{slave.resources.disk * (1024 * 1024) | dataSize}}</td> <td> - <a href="javascript:void(0)" - popover="{{slave.registered_time * 1000 | mesosDate}}" - popover-placement="bottom" - popover-title="Registered"> - {{slave.registered_time * 1000 | relativeDate}} - </a> + <abbr title="{{slave.registered_time * 1000 | mesosDate}}"> + {{slave.registered_time * 1000 | relativeDate}}</abbr> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{slave.registered_time * 1000 | mesosDate}}" + tooltip="Copy timestamp" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + </button> </td> </tr> </table> http://git-wip-us.apache.org/repos/asf/mesos/blob/04d5d9b4/src/webui/master/static/index.html ---------------------------------------------------------------------- diff --git a/src/webui/master/static/index.html b/src/webui/master/static/index.html index 342082d..a9107c7 100644 --- a/src/webui/master/static/index.html +++ b/src/webui/master/static/index.html @@ -83,6 +83,7 @@ <script src="/static/bootstrap/js/jquery-1.7.1.min.js"></script> <script src="/static/underscore-1.4.3.min.js"></script> + <script src="/static/zeroclipboard-1.1.7.js"></script> <script src="/static/angular-1.0.7.min.js"></script> <script src="/static/ui-bootstrap-tpls-0.4.0.min.js"></script> http://git-wip-us.apache.org/repos/asf/mesos/blob/04d5d9b4/src/webui/master/static/mesos.css ---------------------------------------------------------------------- diff --git a/src/webui/master/static/mesos.css b/src/webui/master/static/mesos.css index 34f6067..d1413b7 100644 --- a/src/webui/master/static/mesos.css +++ b/src/webui/master/static/mesos.css @@ -43,6 +43,30 @@ th.unselected:after { padding-left: 5px; content: "ã"; } + +.inline .btn-mini, +.table-condensed .btn-mini { + margin-bottom: -2px; + margin-top: -5px; + visibility: hidden; +} + +.inline .zeroclipboard-is-hover, +.table-condensed .zeroclipboard-is-hover, +.flash dd:hover .btn-mini, +.flash td:hover .btn-mini { + visibility: visible; +} + +.zeroclipboard-is-hover { + background-color: #e6e6e6; + background-position: 0 -15px; +} + +.zeroclipboard-is-active { + background-image: none; +} + .badge-type { -moz-border-radius: 3px; -webkit-border-radius: 3px; http://git-wip-us.apache.org/repos/asf/mesos/blob/04d5d9b4/src/webui/master/static/obj/zeroclipboard-1.1.7.swf ---------------------------------------------------------------------- diff --git a/src/webui/master/static/obj/zeroclipboard-1.1.7.swf b/src/webui/master/static/obj/zeroclipboard-1.1.7.swf new file mode 100755 index 0000000..880e64e Binary files /dev/null and b/src/webui/master/static/obj/zeroclipboard-1.1.7.swf differ http://git-wip-us.apache.org/repos/asf/mesos/blob/04d5d9b4/src/webui/master/static/slave.html ---------------------------------------------------------------------- diff --git a/src/webui/master/static/slave.html b/src/webui/master/static/slave.html index c923644..0849401 100644 --- a/src/webui/master/static/slave.html +++ b/src/webui/master/static/slave.html @@ -32,21 +32,28 @@ <dd>{{state.master_hostname}}</dd> <dt>Started:</dt> <dd> - <a href="javascript:void(0)" - popover="{{state.start_time * 1000 | mesosDate}}" - popover-placement="right" - popover-title="Started"> - {{state.start_time * 1000 | relativeDate}} - </a> + <abbr title="{{state.start_time * 1000 | mesosDate}}"> + {{state.start_time * 1000 | relativeDate}}</abbr> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{state.start_time * 1000 | mesosDate}}" + tooltip="Copy timestamp" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + </button> </dd> <dt>Built:</dt> <dd> - <a href="javascript:void(0)" - popover="{{state.build_time * 1000 | mesosDate}}" - popover-placement="right" - popover-title="Built"> - {{state.build_time * 1000 | relativeDate}} - </a> by <i>{{state.build_user}}</i> + <abbr title="{{state.build_time * 1000 | mesosDate}}"> + {{state.build_time * 1000 | relativeDate}}</abbr> + by <i>{{state.build_user}}</i> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{state.build_time * 1000 | mesosDate}}" + tooltip="Copy timestamp" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + </button> </dd> <dt>Host:</dt> <dd> @@ -139,19 +146,18 @@ <tbody> <tr ng-repeat="framework in _.values(slave.frameworks) | orderBy:tables['frameworks'].selected_column:tables['frameworks'].reverse"> <td> - <a href="javascript:void(0)" - popover="{{framework.id}}" - popover-placement="bottom" - popover-title="ID"> - {{framework.id | truncateMesosID}} - </a> - </td> - <td>{{framework.user}}</td> - <td> <a href="{{'#/slaves/' + slave_id + '/frameworks/' + framework.id}}"> - {{framework.name}} - </a> + {{(framework.id | truncateMesosID) || framework.name}}</a> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{framework.id}}" + tooltip="Copy ID" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + </button> </td> + <td>{{framework.user}}</td> + <td>{{framework.name}}</td> <td>{{framework.num_tasks | number}}</td> <td>{{framework.cpus | number}}</td> <td>{{framework.mem * (1024 * 1024) | dataSize}}</td> http://git-wip-us.apache.org/repos/asf/mesos/blob/04d5d9b4/src/webui/master/static/slaves.html ---------------------------------------------------------------------- diff --git a/src/webui/master/static/slaves.html b/src/webui/master/static/slaves.html index d9fd0f3..9d4a805 100644 --- a/src/webui/master/static/slaves.html +++ b/src/webui/master/static/slaves.html @@ -40,24 +40,31 @@ </thead> <tr ng-repeat="slave in _.values(slaves) | orderBy:tables['slaves'].selected_column:tables['slaves'].reverse"> <td> - <a href="javascript:void(0)" - popover="{{slave.id}}" - popover-placement="bottom" - popover-title="ID"> - {{slave.id | truncateMesosID}} - </a> + <a href="#/slaves/{{slave.id}}">{{slave.id | truncateMesosID}}</a> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{slave.id}}" + tooltip="Copy ID" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + <i class="icon-file"></i> + </button> </td> - <td><a href="#/slaves/{{slave.id}}">{{slave.hostname}}</a></td> + <td>{{slave.hostname}}</td> <td>{{slave.resources.cpus | number}}</td> <td>{{slave.resources.mem * (1024 * 1024) | dataSize}}</td> <td>{{slave.resources.disk * (1024 * 1024) | dataSize}}</td> <td> - <a href="javascript:void(0)" - popover="{{slave.registered_time * 1000 | mesosDate}}" - popover-placement="bottom" - popover-title="Registered"> - {{slave.registered_time * 1000 | relativeDate}} - </a> + <abbr title="{{slave.registered_time * 1000 | mesosDate}}"> + {{slave.registered_time * 1000 | relativeDate}}</abbr> + <button class="btn btn-mini" + clipboard + data-clipboard-text="{{slave.registered_time * 1000 | mesosDate}}" + tooltip="Copy timestamp" + tooltip-placement="right" + tooltip-trigger="clipboardhover"> + <i class="icon-file"></i> + </button> </td> </tr> </table> http://git-wip-us.apache.org/repos/asf/mesos/blob/04d5d9b4/src/webui/master/static/zeroclipboard-1.1.7.js ---------------------------------------------------------------------- diff --git a/src/webui/master/static/zeroclipboard-1.1.7.js b/src/webui/master/static/zeroclipboard-1.1.7.js new file mode 100644 index 0000000..d45551d --- /dev/null +++ b/src/webui/master/static/zeroclipboard-1.1.7.js @@ -0,0 +1,432 @@ +/*! + * 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 2013 Jon Rohan, James M. Greene, . + * Released under the MIT license + * http://zeroclipboard.github.io/ZeroClipboard/ + * v1.2.0-beta.2 + */(function() { + "use strict"; + var _camelizeCssPropName = function() { + var matcherRegex = /\-([a-z])/g, replacerFn = function(match, group) { + return group.toUpperCase(); + }; + return function(prop) { + return prop.replace(matcherRegex, replacerFn); + }; + }(); + var _getStyle = function(el, prop) { + var value, camelProp, tagName, possiblePointers, i, len; + if (window.getComputedStyle) { + value = window.getComputedStyle(el, null).getPropertyValue(prop); + } else { + camelProp = _camelizeCssPropName(prop); + if (el.currentStyle) { + value = el.currentStyle[camelProp]; + } else { + value = el.style[camelProp]; + } + } + if (value === "auto" && prop === "cursor") { + tagName = el.tagName.toLowerCase(); + possiblePointers = [ "a" ]; + for (i = 0, len = possiblePointers.length; i < len; i++) { + if (tagName === possiblePointers[i]) { + return "pointer"; + } + } + } + return value; + }; + var _elementMouseOver = function(event) { + if (!ZeroClipboard.prototype._singleton) return; + if (!event) { + event = window.event; + } + var target; + if (this !== window) { + target = this; + } else if (event.target) { + target = event.target; + } else if (event.srcElement) { + target = event.srcElement; + } + ZeroClipboard.prototype._singleton.setCurrent(target); + }; + var _addEventHandler = function(element, method, func) { + if (element.addEventListener) { + element.addEventListener(method, func, false); + } else if (element.attachEvent) { + element.attachEvent("on" + method, func); + } + }; + var _removeEventHandler = function(element, method, func) { + if (element.removeEventListener) { + element.removeEventListener(method, func, false); + } else if (element.detachEvent) { + element.detachEvent("on" + method, func); + } + }; + var _addClass = function(element, value) { + if (element.addClass) { + element.addClass(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; + }; + var _removeClass = function(element, value) { + if (element.removeClass) { + element.removeClass(value); + return element; + } + if (value && typeof value === "string" || value === undefined) { + var classNames = (value || "").split(/\s+/); + if (element.nodeType === 1 && element.className) { + if (value) { + 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, ""); + } else { + element.className = ""; + } + } + } + return element; + }; + var _getZoomFactor = function() { + var rect, physicalWidth, logicalWidth, zoomFactor = 1; + if (typeof document.body.getBoundingClientRect === "function") { + rect = document.body.getBoundingClientRect(); + physicalWidth = rect.right - rect.left; + logicalWidth = document.body.offsetWidth; + zoomFactor = Math.round(physicalWidth / logicalWidth * 100) / 100; + } + return zoomFactor; + }; + var _getDOMObjectPosition = function(obj) { + var info = { + left: 0, + top: 0, + width: 0, + height: 0, + zIndex: 999999999 + }; + var zi = _getStyle(obj, "z-index"); + if (zi && zi !== "auto") { + info.zIndex = parseInt(zi, 10); + } + if (typeof obj.getBoundingClientRect === "function") { + var rect = obj.getBoundingClientRect(); + var pageXOffset, pageYOffset, zoomFactor; + if ("pageXOffset" in window && "pageYOffset" in window) { + pageXOffset = window.pageXOffset; + pageYOffset = window.pageYOffset; + } else { + zoomFactor = _getZoomFactor(); + pageXOffset = Math.round(document.documentElement.scrollLeft / zoomFactor); + pageYOffset = Math.round(document.documentElement.scrollTop / zoomFactor); + } + var leftBorderWidth = document.documentElement.clientLeft || 0; + var topBorderWidth = document.documentElement.clientTop || 0; + info.left = rect.left + pageXOffset - leftBorderWidth; + info.top = rect.top + pageYOffset - topBorderWidth; + info.width = rect.width; + info.height = rect.height; + } + return info; + }; + var _noCache = function(path) { + var client = ZeroClipboard.prototype._singleton; + if (client.options.useNoCache) { + return (path.indexOf("?") >= 0 ? "&nocache=" : "?nocache=") + (new Date).getTime(); + } else { + return ""; + } + }; + var _vars = function(options) { + var str = []; + if (options.trustedDomains) { + var domains; + if (typeof options.trustedDomains === "string" && options.trustedDomains) { + domains = [ options.trustedDomains ]; + } else if ("length" in options.trustedDomains) { + domains = options.trustedDomains; + } + str.push("trustedDomain=" + encodeURIComponent(domains.join(","))); + } + if (typeof options.amdModuleId === "string" && options.amdModuleId) { + str.push("amdModuleId=" + encodeURIComponent(options.amdModuleId)); + } + if (typeof options.cjsModuleId === "string" && options.cjsModuleId) { + str.push("cjsModuleId=" + encodeURIComponent(options.cjsModuleId)); + } + return str.join("&"); + }; + var _inArray = function(elem, array) { + if (array.indexOf) { + return array.indexOf(elem); + } + for (var i = 0, length = array.length; i < length; i++) { + if (array[i] === elem) { + return i; + } + } + return -1; + }; + var _prepGlue = function(elements) { + if (typeof elements === "string") throw new TypeError("ZeroClipboard doesn't accept query strings."); + if (!elements.length) return [ elements ]; + return elements; + }; + var _dispatchCallback = function(func, element, instance, args, async) { + if (async) { + window.setTimeout(function() { + func.call(element, instance, args); + }, 0); + } else { + func.call(element, instance, args); + } + }; + var ZeroClipboard = function(elements, options) { + if (elements) (ZeroClipboard.prototype._singleton || this).glue(elements); + if (ZeroClipboard.prototype._singleton) return ZeroClipboard.prototype._singleton; + ZeroClipboard.prototype._singleton = this; + this.options = {}; + for (var kd in _defaults) this.options[kd] = _defaults[kd]; + for (var ko in options) this.options[ko] = options[ko]; + this.handlers = {}; + if (ZeroClipboard.detectFlashSupport()) _bridge(); + }; + var currentElement, gluedElements = []; + ZeroClipboard.prototype.setCurrent = function(element) { + currentElement = element; + this.reposition(); + if (element.getAttribute("title")) { + this.setTitle(element.getAttribute("title")); + } + this.setHandCursor(_getStyle(element, "cursor") === "pointer"); + }; + ZeroClipboard.prototype.setText = function(newText) { + if (newText && newText !== "") { + this.options.text = newText; + if (this.ready()) this.flashBridge.setText(newText); + } + }; + ZeroClipboard.prototype.setTitle = function(newTitle) { + if (newTitle && newTitle !== "") this.htmlBridge.setAttribute("title", newTitle); + }; + ZeroClipboard.prototype.setSize = function(width, height) { + if (this.ready()) this.flashBridge.setSize(width, height); + }; + ZeroClipboard.prototype.setHandCursor = function(enabled) { + if (this.ready()) this.flashBridge.setHandCursor(enabled); + }; + ZeroClipboard.version = "1.2.0-beta.2"; + var _defaults = { + moviePath: "ZeroClipboard.swf", + trustedDomains: null, + text: null, + hoverClass: "zeroclipboard-is-hover", + activeClass: "zeroclipboard-is-active", + allowScriptAccess: "sameDomain", + useNoCache: true + }; + ZeroClipboard.setDefaults = function(options) { + for (var ko in options) _defaults[ko] = options[ko]; + }; + ZeroClipboard.destroy = function() { + ZeroClipboard.prototype._singleton.unglue(gluedElements); + var bridge = ZeroClipboard.prototype._singleton.htmlBridge; + bridge.parentNode.removeChild(bridge); + delete ZeroClipboard.prototype._singleton; + }; + ZeroClipboard.detectFlashSupport = function() { + var hasFlash = false; + if (typeof ActiveXObject === "function") { + try { + if (new ActiveXObject("ShockwaveFlash.ShockwaveFlash")) { + hasFlash = true; + } + } catch (error) {} + } + if (!hasFlash && navigator.mimeTypes["application/x-shockwave-flash"]) { + hasFlash = true; + } + return hasFlash; + }; + var _amdModuleId = null; + var _cjsModuleId = null; + var _bridge = function() { + var client = ZeroClipboard.prototype._singleton; + var container = document.getElementById("global-zeroclipboard-html-bridge"); + if (!container) { + var opts = {}; + for (var ko in client.options) opts[ko] = client.options[ko]; + opts.amdModuleId = _amdModuleId; + opts.cjsModuleId = _cjsModuleId; + var flashvars = _vars(opts); + var html = ' <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" id="global-zeroclipboard-flash-bridge" width="100%" height="100%"> <param name="movie" value="' + client.options.moviePath + _noCache(client.options.moviePath) + '"/> <param name="allowScriptAccess" value="' + client.options.allowScriptAccess + '"/> <param name="scale" value="exactfit"/> <param name="loop" value="false"/> <param name="menu" value="false"/> <param name="quality" value="best" /> <param name="bgcolor" value="#ffffff"/> <param name="wmode" value="transparent"/> <param name="flashvars" value="' + flashvars + '"/> <embed src="' + client.options.moviePath + _noCache(client.options.moviePath) + '" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="100%" height="100%" name="global-zeroclipboard-flash-bridge" allowScriptAccess="always" allo wFullScreen="false" type="application/x-shockwave-flash" wmode="transparent" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="' + flashvars + '" scale="exactfit"> </embed> </object>'; + container = document.createElement("div"); + container.id = "global-zeroclipboard-html-bridge"; + container.setAttribute("class", "global-zeroclipboard-container"); + container.setAttribute("data-clipboard-ready", false); + container.style.position = "absolute"; + container.style.left = "-9999px"; + container.style.top = "-9999px"; + container.style.width = "15px"; + container.style.height = "15px"; + container.style.zIndex = "9999"; + container.innerHTML = html; + document.body.appendChild(container); + } + client.htmlBridge = container; + client.flashBridge = document["global-zeroclipboard-flash-bridge"] || container.children[0].lastElementChild; + }; + ZeroClipboard.prototype.resetBridge = function() { + this.htmlBridge.style.left = "-9999px"; + this.htmlBridge.style.top = "-9999px"; + this.htmlBridge.removeAttribute("title"); + this.htmlBridge.removeAttribute("data-clipboard-text"); + _removeClass(currentElement, this.options.activeClass); + currentElement = null; + this.options.text = null; + }; + ZeroClipboard.prototype.ready = function() { + var ready = this.htmlBridge.getAttribute("data-clipboard-ready"); + return ready === "true" || ready === true; + }; + ZeroClipboard.prototype.reposition = function() { + if (!currentElement) return false; + var pos = _getDOMObjectPosition(currentElement); + this.htmlBridge.style.top = pos.top + "px"; + this.htmlBridge.style.left = pos.left + "px"; + this.htmlBridge.style.width = pos.width + "px"; + this.htmlBridge.style.height = pos.height + "px"; + this.htmlBridge.style.zIndex = pos.zIndex + 1; + this.setSize(pos.width, pos.height); + }; + ZeroClipboard.dispatch = function(eventName, args) { + ZeroClipboard.prototype._singleton.receiveEvent(eventName, args); + }; + ZeroClipboard.prototype.on = function(eventName, func) { + var events = eventName.toString().split(/\s/g); + for (var i = 0; i < events.length; i++) { + eventName = events[i].toLowerCase().replace(/^on/, ""); + if (!this.handlers[eventName]) this.handlers[eventName] = func; + } + if (this.handlers.noflash && !ZeroClipboard.detectFlashSupport()) { + this.receiveEvent("onNoFlash", null); + } + }; + ZeroClipboard.prototype.addEventListener = ZeroClipboard.prototype.on; + ZeroClipboard.prototype.off = function(eventName, func) { + var events = eventName.toString().split(/\s/g); + for (var i = 0; i < events.length; i++) { + eventName = events[i].toLowerCase().replace(/^on/, ""); + for (var event in this.handlers) { + if (event === eventName && this.handlers[event] === func) { + delete this.handlers[event]; + } + } + } + }; + ZeroClipboard.prototype.removeEventListener = ZeroClipboard.prototype.off; + ZeroClipboard.prototype.receiveEvent = function(eventName, args) { + eventName = eventName.toString().toLowerCase().replace(/^on/, ""); + var element = currentElement; + var performCallbackAsync = true; + switch (eventName) { + case "load": + if (args && parseFloat(args.flashVersion.replace(",", ".").replace(/[^0-9\.]/gi, "")) < 10) { + this.receiveEvent("onWrongFlash", { + flashVersion: args.flashVersion + }); + return; + } + this.htmlBridge.setAttribute("data-clipboard-ready", true); + break; + case "mouseover": + _addClass(element, this.options.hoverClass); + break; + case "mouseout": + _removeClass(element, this.options.hoverClass); + this.resetBridge(); + break; + case "mousedown": + _addClass(element, this.options.activeClass); + break; + case "mouseup": + _removeClass(element, this.options.activeClass); + break; + case "datarequested": + var targetId = element.getAttribute("data-clipboard-target"), targetEl = !targetId ? null : document.getElementById(targetId); + if (targetEl) { + var textContent = targetEl.value || targetEl.textContent || targetEl.innerText; + if (textContent) this.setText(textContent); + } else { + var defaultText = element.getAttribute("data-clipboard-text"); + if (defaultText) this.setText(defaultText); + } + performCallbackAsync = false; + break; + case "complete": + this.options.text = null; + break; + } + if (this.handlers[eventName]) { + var func = this.handlers[eventName]; + if (typeof func === "string" && typeof window[func] === "function") { + func = window[func]; + } + if (typeof func === "function") { + _dispatchCallback(func, element, this, args, performCallbackAsync); + } + } + }; + ZeroClipboard.prototype.glue = function(elements) { + elements = _prepGlue(elements); + for (var i = 0; i < elements.length; i++) { + if (_inArray(elements[i], gluedElements) == -1) { + gluedElements.push(elements[i]); + _addEventHandler(elements[i], "mouseover", _elementMouseOver); + } + } + }; + ZeroClipboard.prototype.unglue = function(elements) { + elements = _prepGlue(elements); + for (var i = 0; i < elements.length; i++) { + _removeEventHandler(elements[i], "mouseover", _elementMouseOver); + var arrayIndex = _inArray(elements[i], gluedElements); + if (arrayIndex != -1) gluedElements.splice(arrayIndex, 1); + } + }; + if (typeof define === "function" && define.amd) { + define([ "require", "exports", "module" ], function(require, exports, module) { + _amdModuleId = module && module.id || null; + return ZeroClipboard; + }); + } else if (typeof module !== "undefined" && module) { + _cjsModuleId = module.id || null; + module.exports = ZeroClipboard; + } else { + window.ZeroClipboard = ZeroClipboard; + } +})(); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mesos/blob/04d5d9b4/src/webui/master/static/zeroclipboard-1.1.7.min.js ---------------------------------------------------------------------- diff --git a/src/webui/master/static/zeroclipboard-1.1.7.min.js b/src/webui/master/static/zeroclipboard-1.1.7.min.js new file mode 100755 index 0000000..32535fd --- /dev/null +++ b/src/webui/master/static/zeroclipboard-1.1.7.min.js @@ -0,0 +1,8 @@ +/*! + * zeroclipboard + * The Zero Clipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie, and a JavaScript interface. + * Copyright 2012 Jon Rohan, James M. Greene, . + * Released under the MIT license + * http://jonrohan.github.com/ZeroClipboard/ + * v1.1.7 + */(function(){"use strict";var a=function(a,b){var c=a.style[b];a.currentStyle?c=a.currentStyle[b]:window.getComputedStyle&&(c=document.defaultView.getComputedStyle(a,null).getPropertyValue(b));if(c=="auto"&&b=="cursor"){var d=["a"];for(var e=0;e<d.length;e++)if(a.tagName.toLowerCase()==d[e])return"pointer"}return c},b=function(a){if(!l.prototype._singleton)return;a||(a=window.event);var b;this!==window?b=this:a.target?b=a.target:a.srcElement&&(b=a.srcElement),l.prototype._singleton.setCurrent(b)},c=function(a,b,c){a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent&&a.attachEvent("on"+b,c)},d=function(a,b,c){a.removeEventListener?a.removeEventListener(b,c,!1):a.detachEvent&&a.detachEvent("on"+b,c)},e=function(a,b){if(a.addClass)return a.addClass(b),a;if(b&&typeof b=="string"){var c=(b||"").split(/\s+/);if(a.nodeType===1)if(!a.className)a.className=b;else{var d=" "+a.className+" ",e=a.className;for(var f=0,g=c.length;f<g;f++)d.indexOf(" "+c[f]+" ")<0&&(e+=" "+c[f]);a.classN ame=e.replace(/^\s+|\s+$/g,"")}}return a},f=function(a,b){if(a.removeClass)return a.removeClass(b),a;if(b&&typeof b=="string"||b===undefined){var c=(b||"").split(/\s+/);if(a.nodeType===1&&a.className)if(b){var d=(" "+a.className+" ").replace(/[\n\t]/g," ");for(var e=0,f=c.length;e<f;e++)d=d.replace(" "+c[e]+" "," ");a.className=d.replace(/^\s+|\s+$/g,"")}else a.className=""}return a},g=function(b){var c={left:0,top:0,width:b.width||b.offsetWidth||0,height:b.height||b.offsetHeight||0,zIndex:9999},d=a(b,"zIndex");d&&d!="auto"&&(c.zIndex=parseInt(d,10));while(b){var e=parseInt(a(b,"borderLeftWidth"),10),f=parseInt(a(b,"borderTopWidth"),10);c.left+=isNaN(b.offsetLeft)?0:b.offsetLeft,c.left+=isNaN(e)?0:e,c.top+=isNaN(b.offsetTop)?0:b.offsetTop,c.top+=isNaN(f)?0:f,b=b.offsetParent}return c},h=function(a){return(a.indexOf("?")>=0?"&":"?")+"nocache="+(new Date).getTime()},i=function(a){var b=[];return a.trustedDomains&&(typeof a.trustedDomains=="string"?b.push("trustedDomain="+a.trustedDoma ins):b.push("trustedDomain="+a.trustedDomains.join(","))),b.join("&")},j=function(a,b){if(b.indexOf)return b.indexOf(a);for(var c=0,d=b.length;c<d;c++)if(b[c]===a)return c;return-1},k=function(a){if(typeof a=="string")throw new TypeError("ZeroClipboard doesn't accept query strings.");return a.length?a:[a]},l=function(a,b){a&&(l.prototype._singleton||this).glue(a);if(l.prototype._singleton)return l.prototype._singleton;l.prototype._singleton=this,this.options={};for(var c in o)this.options[c]=o[c];for(var d in b)this.options[d]=b[d];this.handlers={},l.detectFlashSupport()&&p()},m,n=[];l.prototype.setCurrent=function(b){m=b,this.reposition(),b.getAttribute("title")&&this.setTitle(b.getAttribute("title")),this.setHandCursor(a(b,"cursor")=="pointer")},l.prototype.setText=function(a){a&&a!==""&&(this.options.text=a,this.ready()&&this.flashBridge.setText(a))},l.prototype.setTitle=function(a){a&&a!==""&&this.htmlBridge.setAttribute("title",a)},l.prototype.setSize=function(a,b){this.ready() &&this.flashBridge.setSize(a,b)},l.prototype.setHandCursor=function(a){this.ready()&&this.flashBridge.setHandCursor(a)},l.version="1.1.7";var o={moviePath:"ZeroClipboard.swf",trustedDomains:null,text:null,hoverClass:"zeroclipboard-is-hover",activeClass:"zeroclipboard-is-active",allowScriptAccess:"sameDomain"};l.setDefaults=function(a){for(var b in a)o[b]=a[b]},l.destroy=function(){l.prototype._singleton.unglue(n);var a=l.prototype._singleton.htmlBridge;a.parentNode.removeChild(a),delete l.prototype._singleton},l.detectFlashSupport=function(){var a=!1;try{new ActiveXObject("ShockwaveFlash.ShockwaveFlash")&&(a=!0)}catch(b){navigator.mimeTypes["application/x-shockwave-flash"]&&(a=!0)}return a};var p=function(){var a=l.prototype._singleton,b=document.getElementById("global-zeroclipboard-html-bridge");if(!b){var c=' <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" id="global-zeroclipboard-flash-bridge" width="100%" height="100%"> <param name="movie" value="'+a.op tions.moviePath+h(a.options.moviePath)+'"/> <param name="allowScriptAccess" value="'+a.options.allowScriptAccess+'"/> <param name="scale" value="exactfit"/> <param name="loop" value="false"/> <param name="menu" value="false"/> <param name="quality" value="best" /> <param name="bgcolor" value="#ffffff"/> <param name="wmode" value="transparent"/> <param name="flashvars" value="'+i(a.options)+'"/> <embed src="'+a.options.moviePath+h(a.options.moviePath)+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="100%" height="100%" name="global-zeroclipboard-flash-bridge" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" wmode="transparent" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+i(a.options)+'" scale="exactfit"> </embed> </object>';b=document.createElement("div"),b.id="global-zeroclipboard-html-bridge",b.setAttribute("class","global-zeroclipboard-container"),b.setAttribute("data-clipboard-ready",!1),b.style.position="absolute",b.style.left="-9999px",b.style.top="-9999px",b.style.width="15px",b.style.height="15px",b.style.zIndex="9999",b.innerHTML=c,document.body.appendChild(b)}a.htmlBridge=b,a.flashBridge=document["global-zeroclipboard-flash-bridge"]||b.children[0].lastElementChild};l.prototype.resetBridge=function(){this.htmlBridge.style.left="-9999px",this.htmlBridge.style.top="-9999px",this.htmlBridge.removeAttribute("title"),this.htmlBridge.removeAttribute("data-clipboard-text"),f(m,this.options.activeClass),m=null,this.options.text=null},l.prototype.ready=function(){var a=this.htmlBridge.getAttribute("data-clipboard-ready");return a==="true"||a===!0},l.prototype.reposition=function(){if(!m)return!1;var a=g(m);this.htmlBridge.style.top=a.top+"px",this.htmlBridge.style.left=a.left+"px",this .htmlBridge.style.width=a.width+"px",this.htmlBridge.style.height=a.height+"px",this.htmlBridge.style.zIndex=a.zIndex+1,this.setSize(a.width,a.height)},l.dispatch=function(a,b){l.prototype._singleton.receiveEvent(a,b)},l.prototype.on=function(a,b){var c=a.toString().split(/\s/g);for(var d=0;d<c.length;d++)a=c[d].toLowerCase().replace(/^on/,""),this.handlers[a]||(this.handlers[a]=b);this.handlers.noflash&&!l.detectFlashSupport()&&this.receiveEvent("onNoFlash",null)},l.prototype.addEventListener=l.prototype.on,l.prototype.off=function(a,b){var c=a.toString().split(/\s/g);for(var d=0;d<c.length;d++){a=c[d].toLowerCase().replace(/^on/,"");for(var e in this.handlers)e===a&&this.handlers[e]===b&&delete this.handlers[e]}},l.prototype.removeEventListener=l.prototype.off,l.prototype.receiveEvent=function(a,b){a=a.toString().toLowerCase().replace(/^on/,"");var c=m;switch(a){case"load":if(b&&parseFloat(b.flashVersion.replace(",",".").replace(/[^0-9\.]/gi,""))<10){this.receiveEvent("onWrongFlas h",{flashVersion:b.flashVersion});return}this.htmlBridge.setAttribute("data-clipboard-ready",!0);break;case"mouseover":e(c,this.options.hoverClass);break;case"mouseout":f(c,this.options.hoverClass),this.resetBridge();break;case"mousedown":e(c,this.options.activeClass);break;case"mouseup":f(c,this.options.activeClass);break;case"datarequested":var d=c.getAttribute("data-clipboard-target"),g=d?document.getElementById(d):null;if(g){var h=g.value||g.textContent||g.innerText;h&&this.setText(h)}else{var i=c.getAttribute("data-clipboard-text");i&&this.setText(i)}break;case"complete":this.options.text=null}if(this.handlers[a]){var j=this.handlers[a];typeof j=="function"?j.call(c,this,b):typeof j=="string"&&window[j].call(c,this,b)}},l.prototype.glue=function(a){a=k(a);for(var d=0;d<a.length;d++)j(a[d],n)==-1&&(n.push(a[d]),c(a[d],"mouseover",b))},l.prototype.unglue=function(a){a=k(a);for(var c=0;c<a.length;c++){d(a[c],"mouseover",b);var e=j(a[c],n);e!=-1&&n.splice(e,1)}},typeof module!="und efined"?module.exports=l:typeof define=="function"&&define.amd?define(function(){return l}):window.ZeroClipboard=l})(); \ No newline at end of file