浏览代码

基于原计量支付web-1.0.0最新开发版为基线版本

NoNZero 9 年之前
当前提交
0eda1bfe00
共有 100 个文件被更改,包括 23069 次插入0 次删除
  1. 二进制
      global/avatar/avtra.jpg
  2. 6 0
      global/avaup/crossdomain.xml
  3. 二进制
      global/avaup/expressInstall.swf
  4. 二进制
      global/avaup/fullAvatarEditor.swf
  5. 90 0
      global/avaup/scripts/fullAvatarEditor.js
  6. 4 0
      global/avaup/scripts/swfobject.js
  7. 66 0
      global/avaup/simpleDemo.html
  8. 88 0
      global/avaup/upload.php
  9. 5482 0
      global/css/bootstrap.css
  10. 9 0
      global/css/bootstrap.min.css
  11. 25 0
      global/css/demo.css
  12. 99 0
      global/css/fixedheadertable.css
  13. 184 0
      global/css/fonts/icomoon.dev.svg
  14. 二进制
      global/css/fonts/icomoon.eot
  15. 51 0
      global/css/fonts/icomoon.svg
  16. 二进制
      global/css/fonts/icomoon.ttf
  17. 二进制
      global/css/fonts/icomoon.woff
  18. 二进制
      global/css/glyphicons-halflings-white.png
  19. 二进制
      global/css/glyphicons-halflings.png
  20. 二进制
      global/css/headerBg.jpg
  21. 5 0
      global/css/icomoon/Read Me.txt
  22. 157 0
      global/css/icomoon/demo-files/demo.css
  23. 30 0
      global/css/icomoon/demo-files/demo.js
  24. 578 0
      global/css/icomoon/demo.html
  25. 二进制
      global/css/icomoon/fonts/icomoon.eot
  26. 51 0
      global/css/icomoon/fonts/icomoon.svg
  27. 二进制
      global/css/icomoon/fonts/icomoon.ttf
  28. 二进制
      global/css/icomoon/fonts/icomoon.woff
  29. 850 0
      global/css/icomoon/selection.json
  30. 148 0
      global/css/icomoon/style.css
  31. 二进制
      global/css/logo.jpg
  32. 二进制
      global/css/logo.png
  33. 二进制
      global/css/missionBg.png
  34. 二进制
      global/css/sidebarAfocue.png
  35. 二进制
      global/css/sidebarBg.jpg
  36. 二进制
      global/css/small.gif
  37. 二进制
      global/css/small_asc.gif
  38. 二进制
      global/css/small_desc.gif
  39. 1066 0
      global/css/style.css
  40. 18 0
      global/css/tablecloth.css
  41. 二进制
      global/css/wave1.png
  42. 二进制
      global/css/wave2.png
  43. 二进制
      global/images/avatar-1.png
  44. 二进制
      global/images/avatar-2.png
  45. 二进制
      global/images/avatar-3.png
  46. 二进制
      global/images/avatar-4.png
  47. 二进制
      global/images/avatar-normal - 副本.png
  48. 二进制
      global/images/avatar-normal.png
  49. 二进制
      global/images/avatar-normald.png
  50. 二进制
      global/images/avatar96.png
  51. 二进制
      global/images/avtra.png
  52. 二进制
      global/img/mainLogo.png
  53. 二进制
      global/img/softtips1.jpg
  54. 二进制
      global/img/topBanner.png
  55. 二进制
      global/img/未标题-1.png
  56. 162 0
      global/js/bootstrap-scrollspy.js
  57. 1437 0
      global/js/bootstrap.js
  58. 7 0
      global/js/bootstrap.min.js
  59. 114 0
      global/js/chartdate.js
  60. 39 0
      global/js/jl.js
  61. 4 0
      global/js/jquery-1.7.1.min.js
  62. 5 0
      global/js/jquery-1.9.1.min.js
  63. 706 0
      global/js/jquery.fixedheadertable.js
  64. 20 0
      global/js/jquery.fixedheadertable.min.js
  65. 808 0
      global/js/jquery.tablesorter.js
  66. 184 0
      global/js/tablecloth.js
  67. 4 0
      global/js/zeroclipboard/.gitignore
  68. 29 0
      global/js/zeroclipboard/CONTRIBUTING.md
  69. 332 0
      global/js/zeroclipboard/Gruntfile.js
  70. 8 0
      global/js/zeroclipboard/LICENSE
  71. 91 0
      global/js/zeroclipboard/README.md
  72. 17 0
      global/js/zeroclipboard/bower.json
  73. 14 0
      global/js/zeroclipboard/composer.json
  74. 1788 0
      global/js/zeroclipboard/dist/ZeroClipboard.Core.js
  75. 10 0
      global/js/zeroclipboard/dist/ZeroClipboard.Core.min.js
  76. 1 0
      global/js/zeroclipboard/dist/ZeroClipboard.Core.min.map
  77. 2314 0
      global/js/zeroclipboard/dist/ZeroClipboard.js
  78. 10 0
      global/js/zeroclipboard/dist/ZeroClipboard.min.js
  79. 1 0
      global/js/zeroclipboard/dist/ZeroClipboard.min.map
  80. 二进制
      global/js/zeroclipboard/dist/ZeroClipboard.swf
  81. 716 0
      global/js/zeroclipboard/docs/api/ZeroClipboard.Core.md
  82. 892 0
      global/js/zeroclipboard/docs/api/ZeroClipboard.md
  83. 439 0
      global/js/zeroclipboard/docs/instructions.md
  84. 9 0
      global/js/zeroclipboard/docs/roadmap.md
  85. 32 0
      global/js/zeroclipboard/docs/security.md
  86. 29 0
      global/js/zeroclipboard/index.js
  87. 83 0
      global/js/zeroclipboard/package.json
  88. 185 0
      global/js/zeroclipboard/src/flash/ClipboardInjector.as
  89. 140 0
      global/js/zeroclipboard/src/flash/JsProxy.as
  90. 38 0
      global/js/zeroclipboard/src/flash/XssUtils.as
  91. 299 0
      global/js/zeroclipboard/src/flash/ZeroClipboard.as
  92. 162 0
      global/js/zeroclipboard/src/js/client/api.js
  93. 476 0
      global/js/zeroclipboard/src/js/client/private.js
  94. 60 0
      global/js/zeroclipboard/src/js/client/state.js
  95. 211 0
      global/js/zeroclipboard/src/js/core/api.js
  96. 1701 0
      global/js/zeroclipboard/src/js/core/private.js
  97. 147 0
      global/js/zeroclipboard/src/js/core/state.js
  98. 21 0
      global/js/zeroclipboard/src/js/end.js
  99. 317 0
      global/js/zeroclipboard/src/js/shared/private.js
  100. 0 0
      global/js/zeroclipboard/src/js/shared/state.js

二进制
global/avatar/avtra.jpg


+ 6 - 0
global/avaup/crossdomain.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<cross-domain-policy>
+	<site-control permitted-cross-domain-policies="all" />
+    <allow-access-from domain="*" />
+    <allow-http-request-headers-from domain="*" headers="*"/>
+</cross-domain-policy>

二进制
global/avaup/expressInstall.swf


二进制
global/avaup/fullAvatarEditor.swf


+ 90 - 0
global/avaup/scripts/fullAvatarEditor.js

@@ -0,0 +1,90 @@
+function fullAvatarEditor() {
+    var id = 'fullAvatarEditor'			//flash文件的ID
+    var file = '/global/avaup/fullAvatarEditor.swf';		//flash文件的路径
+    var version = "10.1.0";						//播放该flash所需的最低版本
+    var expressInstall = '/global/avaup/expressInstall.swf';			//expressInstall.swf的路径
+    var width = 630;							//flash文件的宽度
+    var height = 430;							//flash文件的高度
+    var container = id;							//装载flash文件的容器(如div)的id
+    var flashvars = {};
+    var callback = function() {
+    };
+    var heightChanged = false;
+    //智能获取参数,字符类型为装载flash文件的容器(如div)的id,第一个数字类型的为高度,第二个为宽度,第一个object类型的为参数对象,如此4个参数的顺序可随意。
+    for (var i = 0; i < arguments.length; i++)
+    {
+	if (typeof arguments[i] == 'string')
+	{
+	    container = arguments[i];
+	}
+	else if (typeof arguments[i] == 'number')
+	{
+	    if (heightChanged)
+	    {
+		width = arguments[i];
+	    }
+	    else
+	    {
+		height = arguments[i];
+		heightChanged = true;
+	    }
+	}
+	else if (typeof arguments[i] == 'function')
+	{
+	    callback = arguments[i];
+	}
+	else
+	{
+	    flashvars = arguments[i];
+	}
+    }
+    var vars = {
+	id: id
+    };
+    //合并参数
+    for (var name in flashvars)
+    {
+	if (flashvars[name] != null)
+	{
+	    if (name == 'upload_url' || name == 'src_url')
+	    {
+		vars[name] = encodeURIComponent(flashvars[name]);
+	    }
+	    else
+	    {
+		vars[name] = flashvars[name];
+	    }
+	}
+    }
+    var params = {
+	menu: 'true',
+	scale: 'noScale',
+	allowFullscreen: 'true',
+	allowScriptAccess: 'always',
+	wmode: 'transparent'
+    };
+    var attributes = {
+	id: vars.id,
+	name: vars.id
+    };
+    var swf = null;
+    var callbackFn = function(e) {
+	swf = e.ref;
+	swf.eventHandler = function(json) {
+	    callback.call(swf, json);
+	};
+    };
+    swfobject.embedSWF(
+	    file,
+	    container,
+	    width,
+	    height,
+	    version,
+	    expressInstall,
+	    vars,
+	    params,
+	    attributes,
+	    callbackFn
+	    );
+    return swf;
+}

文件差异内容过多而无法显示
+ 4 - 0
global/avaup/scripts/swfobject.js


+ 66 - 0
global/avaup/simpleDemo.html

@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="utf-8"/>
+        <title>Simple demo</title>
+        <script type="text/javascript" src="scripts/swfobject.js"></script>
+        <script type="text/javascript" src="scripts/fullAvatarEditor.js"></script>
+    </head>
+    <body>
+		<div style="width:630px;margin: 0 auto;">
+			<h1 style="text-align:center">富头像上传编辑器演示</h1>
+			<div>
+				<p id="swfContainer">
+                    本组件需要安装Flash Player后才可使用,请从<a href="http://www.adobe.com/go/getflashplayer">这里</a>下载安装。
+				</p>
+			</div>
+			<p style="text-align:center"><button type="button" id="upload">自定义上传按钮</button></p>
+			<p style="text-align:center">提示:本演示使用的上传接口类型为ASP,如要测试上传,请在服务器环境中演示,更多演示请看<a href="http://www.fullavatareditor.com/demo.html">http://www.fullavatareditor.com/demo.html</a></p>
+        </div>
+		<script type="text/javascript">
+            swfobject.addDomLoadEvent(function () {
+                var swf = new fullAvatarEditor("swfContainer", {
+					    id: 'swf',
+						upload_url: 'asp/Upload.asp',
+						src_upload:2
+					}, function (msg) {
+						switch(msg.code)
+						{
+							case 1 : alert("页面成功加载了组件!");break;
+							case 2 : alert("已成功加载默认指定的图片到编辑面板。");break;
+							case 3 :
+								if(msg.type == 0)
+								{
+									alert("摄像头已准备就绪且用户已允许使用。");
+								}
+								else if(msg.type == 1)
+								{
+									alert("摄像头已准备就绪但用户未允许使用!");
+								}
+								else
+								{
+									alert("摄像头被占用!");
+								}
+							break;
+							case 5 : 
+								if(msg.type == 0)
+								{
+									if(msg.content.sourceUrl)
+									{
+										alert("原图已成功保存至服务器,url为:\n" + msg.content.sourceUrl);
+									}
+									alert("头像已成功保存至服务器,url为:\n" + msg.content.avatarUrls.join("\n"));
+								}
+							break;
+						}
+					}
+				);
+				document.getElementById("upload").onclick=function(){
+					swf.call("upload");
+				};
+            });
+			var _bdhmProtocol = (("https:" == document.location.protocol) ? " https://" : " http://");
+			document.write(unescape("%3Cscript src='" + _bdhmProtocol + "hm.baidu.com/h.js%3F5f036dd99455cb8adc9de73e2f052f72' type='text/javascript'%3E%3C/script%3E"));
+        </script>
+    </body>
+</html>

+ 88 - 0
global/avaup/upload.php

@@ -0,0 +1,88 @@
+<?php
+/* 温馨提示:
+ * 在flash的参数名upload_url中可自行定义一些参数(请求方式:GET),定义后在服务器端获取即可,比如可以应用到用户验证,文件的保存名等。
+ * 本示例未作极致的用户体验与严谨的安全设计(如用户直接访问此页时该如何,万一客户端数据不可信时验证文件的大小、类型等),只保证正常情况下无误,请阁下注意。
+ */
+header('Content-Type: text/html; charset=utf-8');
+$result = array();
+$result['success'] = false;
+$successNum = 0;
+//定义一个变量用以储存当前头像的序号
+$avatarNumber = 1;
+$i = 0;
+$msg = '';
+//上传目录
+$dir = "upload";
+//遍历所有文件域
+while (list($key, $val) = each($_FILES))
+{
+	if ( $_FILES[$key]['error'] > 0)
+    {
+		$msg .= $_FILES[$key]['error'];
+	}
+	else
+	{
+		$fileName = date("YmdHis").'_'.floor(microtime() * 1000).'_'.createRandomCode(8);
+		//处理原始图片(默认的 file 域的名称是__source,可在插件配置参数中自定义。参数名:src_field_name)
+		//如果在插件中定义可以上传原始图片的话,可在此处理,否则可以忽略。
+		if ($key == '__source')
+		{
+			//当前头像基于原图的初始化参数,用于修改头像时保证界面的视图跟保存头像时一致。帮助提升用户体验度。修改头像时设置默认加载的原图的url为此图片的url+该参数即可。
+			$initParams = $_POST["__initParams"];
+			$virtualPath = "$dir/php_source_$fileName.jpg";
+			$result['sourceUrl'] = '/' . $virtualPath.$initParams;
+			move_uploaded_file($_FILES[$key]["tmp_name"], $virtualPath);
+			/*
+				可在此将 $result['sourceUrl'] 储存到数据库
+			*/
+			$successNum++;
+		}
+		//处理头像图片(默认的 file 域的名称:__avatar1,2,3...,可在插件配置参数中自定义,参数名:avatar_field_names)
+		else if (strpos($key, '__avatar') === 0)
+		{
+			$virtualPath = "$dir/php_avatar" . $avatarNumber . "_$fileName.jpg";
+			$result['avatarUrls'][$i] = '/' . $virtualPath;
+			move_uploaded_file($_FILES[$key]["tmp_name"], $virtualPath);
+			/*
+				可在此将 $result['avatarUrls'][$i] 储存到数据库
+			*/
+			$successNum++;
+			$i++;
+		}
+		/*
+		else
+		{
+			如下代码在上传接口upload.php中定义了一个user=xxx的参数:
+			var swf = new fullAvatarEditor("swf", {
+				id: "swf",
+				upload_url: "Upload.php?user=xxx"
+			});
+			在此即可用$_POST["user"]获取xxx。
+		}
+		*/
+	}
+}
+$result['msg'] = $msg;
+if ($successNum > 0)
+{
+	$result['success'] = true;
+}
+//返回图片的保存结果(返回内容为json字符串)
+print json_encode($result);
+
+/**************************************************************
+*  生成指定长度的随机码。
+*  @param int $length 随机码的长度。
+*  @access public
+**************************************************************/
+function createRandomCode($length)
+{
+	$randomCode = "";
+	$randomChars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+	for ($i = 0; $i < $length; $i++)
+	{
+		$randomCode .= $randomChars { mt_rand(0, 35) };
+	}
+	return $randomCode;
+}
+?>

文件差异内容过多而无法显示
+ 5482 - 0
global/css/bootstrap.css


文件差异内容过多而无法显示
+ 9 - 0
global/css/bootstrap.min.css


+ 25 - 0
global/css/demo.css

@@ -0,0 +1,25 @@
+.paginate, .current, .inactivePrev, .inactiveNext, .prev, .next {
+    font-family: Verdana,Helvetica,Arial,sans-serif;
+    font-size:12px;
+    border:1px solid #D8D8D8;
+    float:left;
+    height:20px;
+    line-height:20px;
+    margin-right:2px;
+    overflow:hidden;
+    padding:0 6px;
+    text-decoration:none;
+}
+a:hover .paginate{
+    border-color:#006699;
+}
+
+.current {
+    border-color:#006699;
+    background-color:#006699;
+    color:#fff;
+    font-weight:bold;
+}
+.inactivePrev, .inactiveNext{
+    color:#999;
+}

+ 99 - 0
global/css/fixedheadertable.css

@@ -0,0 +1,99 @@
+/*!
+* jquery.fixedHeaderTable. The jQuery fixedHeaderTable plugin
+*
+* Copyright (c) 2011 Mark Malek
+* http://fixedheadertable.com
+*
+* Licensed under MIT
+* http://www.opensource.org/licenses/mit-license.php
+* 
+* http://docs.jquery.com/Plugins/Authoring
+* jQuery authoring guidelines
+*
+* Launch  : October 2009
+* Version : 1.3
+* Released: May 9th, 2011
+*
+* 
+* all CSS sizing (width,height) is done in pixels (px)
+*/
+
+/* @group Reset */
+
+.fht-table,
+.fht-table thead,
+.fht-table tfoot,
+.fht-table tbody,
+.fht-table tr,
+.fht-table th,
+.fht-table td {
+  margin: 0;
+	padding: 0;
+	vertical-align:middle;
+	}
+.fht-table {
+	}
+.fht-table-wrapper,
+.fht-table-wrapper .fht-thead,
+.fht-table-wrapper .fht-tfoot,
+.fht-table-wrapper .fht-fixed-column .fht-tbody,
+.fht-table-wrapper .fht-fixed-body .fht-tbody,
+.fht-table-wrapper .fht-tbody {
+	overflow: hidden;
+
+	position: relative;
+	}
+
+	.fht-table-wrapper .fht-fixed-body .fht-tbody,
+	.fht-table-wrapper .fht-tbody {
+
+	    overflow: auto;
+		}
+
+		.fht-table-wrapper .fht-table .fht-cell {
+
+			overflow: hidden;
+		    height: 1px;
+			}
+	
+	.fht-table-wrapper .fht-fixed-column,
+	.fht-table-wrapper .fht-fixed-body {
+	    top: 0;
+	    left: 0;
+	    position: absolute;
+	    }
+	    
+	.fht-table-wrapper .fht-fixed-column {
+	    z-index: 1;
+	    }
+
+.fancyTable td, .fancyTable th {
+	border: 1px solid #d4d4d4;
+	padding:3px;
+	white-space:nowrap;
+	}
+	.fancyTable td{
+	min-width:60px
+
+	}
+.fancyTable tbody tr th {
+	background-color: #fff;
+	}
+.fancyTable tbody tr td {
+	background-color: #fff;
+	}
+.fancyTable tbody tr.odd td{
+	background: #fff
+	}
+.fancyTable tbody tr th{
+	font-weight: 600;
+	background: #fff
+	}
+.fancyTable thead tr th,
+.fancyTable thead tr td,
+.fancyTable tfoot tr th, 
+.fancyTable tfoot tr td {
+	background: #fff;
+	font-weight: bold;
+	color:#444;
+	}

文件差异内容过多而无法显示
+ 184 - 0
global/css/fonts/icomoon.dev.svg


二进制
global/css/fonts/icomoon.eot


文件差异内容过多而无法显示
+ 51 - 0
global/css/fonts/icomoon.svg


二进制
global/css/fonts/icomoon.ttf


二进制
global/css/fonts/icomoon.woff


二进制
global/css/glyphicons-halflings-white.png


二进制
global/css/glyphicons-halflings.png


二进制
global/css/headerBg.jpg


+ 5 - 0
global/css/icomoon/Read Me.txt

@@ -0,0 +1,5 @@
+Open *demo.html* to see a list of all the glyphs in your font along with their codes/ligatures.
+
+You won't need any of the files located under the *demo-files* directory when including the generated font in your own projects.
+
+You can import *selection.json* back to the IcoMoon app using the *Import Icons* button (or via Main Menu > Manage Projects) to retrieve your icon selection.

+ 157 - 0
global/css/icomoon/demo-files/demo.css

@@ -0,0 +1,157 @@
+body {
+	padding: 0;
+	margin: 0;
+	font-family: sans-serif;
+	font-size: 1em;
+	line-height: 1.5;
+	color: #555;
+	background: #fff;
+}
+h1 {
+	font-size: 1.5em;
+	font-weight: normal;
+}
+small {
+	font-size: .66666667em;
+}
+a {
+	color: #e74c3c;
+	text-decoration: none;
+}
+a:hover, a:focus {
+	box-shadow: 0 1px #e74c3c;
+}
+.bshadow0, input {
+	box-shadow: inset 0 -2px #e7e7e7;
+}
+input:hover {
+	box-shadow: inset 0 -2px #ccc;
+}
+input, fieldset {
+	font-size: 1em;
+	margin: 0;
+	padding: 0;
+	border: 0;
+}
+input {
+	color: inherit;
+	line-height: 1.5;
+	height: 1.5em;
+	padding: .25em 0;
+}
+input:focus {
+	outline: none;
+	box-shadow: inset 0 -2px #449fdb;
+}
+.glyph {
+	font-size: 16px;
+	width: 15em;
+	padding-bottom: 1em;
+	margin-right: 4em;
+	margin-bottom: 1em;
+	float: left;
+	overflow: hidden;
+}
+.liga {
+	width: 80%;
+	width: calc(100% - 2.5em);
+}
+.talign-right {
+	text-align: right;
+}
+.talign-center {
+	text-align: center;
+}
+.bgc1 {
+	background: #f1f1f1;
+}
+.fgc1 {
+	color: #999;
+}
+.fgc0 {
+	color: #000;
+}
+p {
+	margin-top: 1em;
+	margin-bottom: 1em;
+}
+.mvm {
+	margin-top: .75em;
+	margin-bottom: .75em;
+}
+.mtn {
+	margin-top: 0;
+}
+.mtl, .mal {
+	margin-top: 1.5em;
+}
+.mbl, .mal {
+	margin-bottom: 1.5em;
+}
+.mal, .mhl {
+	margin-left: 1.5em;
+	margin-right: 1.5em;
+}
+.mhmm {
+	margin-left: 1em;
+	margin-right: 1em;
+}
+.mls {
+	margin-left: .25em;
+}
+.ptl {
+	padding-top: 1.5em;
+}
+.pbs, .pvs {
+	padding-bottom: .25em;
+}
+.pvs, .pts {
+	padding-top: .25em;
+}
+.clearfix {
+	zoom: 1;
+}
+.unit {
+	float: left;
+}
+.unitRight {
+	float: right;
+}
+.size1of2 {
+	width: 50%;
+}
+.size1of1 {
+	width: 100%;
+}
+.clearfix:before, .clearfix:after {
+	content: " ";
+	display: table;
+}
+.clearfix:after {
+	clear: both;
+}
+.hidden-true {
+	display: none;
+}
+.textbox0 {
+	width: 3em;
+	background: #f1f1f1;
+	padding: .25em .5em;
+	line-height: 1.5;
+	height: 1.5em;
+}
+#testDrive {
+	padding-top: 24px;
+}
+.fs0 {
+	font-size: 16px;
+}
+.fs1 {
+	font-size: 32px;
+}
+.fs2 {
+	font-size: 32px;
+}
+.fs3 {
+	font-size: 32px;
+}

+ 30 - 0
global/css/icomoon/demo-files/demo.js

@@ -0,0 +1,30 @@
+if (!('boxShadow' in document.body.style)) {
+	document.body.setAttribute('class', 'noBoxShadow');
+}
+
+document.body.addEventListener("click", function(e) {
+	var target = e.target;
+	if (target.tagName === "INPUT" &&
+		target.getAttribute('class').indexOf('liga') === -1) {
+		target.select();
+	}
+});
+
+(function() {
+	var fontSize = document.getElementById('fontSize'),
+		testDrive = document.getElementById('testDrive'),
+		testText = document.getElementById('testText');
+	function updateTest() {
+		testDrive.innerHTML = testText.value || String.fromCharCode(160);
+		if (window.icomoonLiga) {
+			window.icomoonLiga(testDrive);
+		}
+	}
+	function updateSize() {
+		testDrive.style.fontSize = fontSize.value + 'px';
+	}
+	fontSize.addEventListener('change', updateSize, false);
+	testText.addEventListener('input', updateTest, false);
+	testText.addEventListener('change', updateTest, false);
+	updateSize();
+}());

+ 578 - 0
global/css/icomoon/demo.html

@@ -0,0 +1,578 @@
+<!doctype html>
+<html>
+<head>
+	<meta charset="utf-8">
+	<title>IcoMoon Demo</title>
+	<meta name="description" content="An Icon Font Generated By IcoMoon.io">
+	<meta name="viewport" content="width=device-width">
+	<link rel="stylesheet" href="demo-files/demo.css">
+	<link rel="stylesheet" href="style.css"></head>
+<body>
+	<div class="bgc1 clearfix">
+		<h1 class="mhmm mvm"><span class="fgc1">Font Name:</span> icomoon <small class="fgc1">(Glyphs:&nbsp;41)</small></h1>
+	</div>
+	<div class="clearfix mhl ptl">
+		<h1 class="mvm mtn bshadow fgc1">Grid Size: Unknown</h1>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni42"></span><span class="mls"> icon-uni42</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="43" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x43;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni43"></span><span class="mls"> icon-uni43</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="44" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x44;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni47"></span><span class="mls"> icon-uni47</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="47" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x47;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni4D"></span><span class="mls"> icon-uni4D</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="4d" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x4d;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni4E"></span><span class="mls"> icon-uni4E</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="4e" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x4e;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni4F"></span><span class="mls"> icon-uni4F</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="4f" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x4f;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni50"></span><span class="mls"> icon-uni50</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="50" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x50;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni52"></span><span class="mls"> icon-uni52</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="52" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x52;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni53"></span><span class="mls"> icon-uni53</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="53" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x53;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni54"></span><span class="mls"> icon-uni54</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="54" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x54;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni55"></span><span class="mls"> icon-uni55</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="55" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x55;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni56"></span><span class="mls"> icon-uni56</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="56" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x56;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni57"></span><span class="mls"> icon-uni57</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="57" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x57;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni58"></span><span class="mls"> icon-uni58</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="58" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x58;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni59"></span><span class="mls"> icon-uni59</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="59" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x59;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni5A"></span><span class="mls"> icon-uni5A</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="5a" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x5a;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni61"></span><span class="mls"> icon-uni61</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="61" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x61;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni62"></span><span class="mls"> icon-uni62</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="62" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x62;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni63"></span><span class="mls"> icon-uni63</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="63" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x63;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni64"></span><span class="mls"> icon-uni64</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="64" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x64;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni65"></span><span class="mls"> icon-uni65</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="65" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x65;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni66"></span><span class="mls"> icon-uni66</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="66" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x66;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni67"></span><span class="mls"> icon-uni67</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="67" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x67;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni68"></span><span class="mls"> icon-uni68</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="68" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x68;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni69"></span><span class="mls"> icon-uni69</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="69" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x69;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni6A"></span><span class="mls"> icon-uni6A</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="6a" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x6a;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni6B"></span><span class="mls"> icon-uni6B</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="6b" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x6b;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni6C"></span><span class="mls"> icon-uni6C</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="6c" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x6c;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni6D"></span><span class="mls"> icon-uni6D</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="6d" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x6d;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni6F"></span><span class="mls"> icon-uni6F</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="6f" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x6f;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni70"></span><span class="mls"> icon-uni70</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="70" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x70;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni71"></span><span class="mls"> icon-uni71</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="71" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x71;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni72"></span><span class="mls"> icon-uni72</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="72" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x72;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni73"></span><span class="mls"> icon-uni73</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="73" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x73;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni74"></span><span class="mls"> icon-uni74</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="74" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x74;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs1">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-uni75"></span><span class="mls"> icon-uni75</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="75" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x75;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+	</div>
+	<div class="clearfix mhl ptl">
+		<h1 class="mvm mtn bshadow fgc1">Grid Size: 16</h1>
+		<div class="glyph fs2">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-window"></span><span class="mls"> icon-window</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="49" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x49;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs2">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-monitor"></span><span class="mls"> icon-monitor</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="48" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x48;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+	</div>
+	<div class="clearfix mhl ptl">
+		<h1 class="mvm mtn bshadow fgc1">Grid Size: 32</h1>
+		<div class="glyph fs3">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-upload"></span><span class="mls"> icon-upload</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="42" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x42;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs3">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-inbox"></span><span class="mls"> icon-inbox</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="41" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x41;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+		<div class="glyph fs3">
+			<div class="clearfix bshadow0 pbs">
+				<span class="icon-chart"></span><span class="mls"> icon-chart</span>
+			</div>
+			<fieldset class="fs0 size1of1 clearfix hidden-false">
+				<input type="text" readonly value="45" class="unit size1of2" />
+				<input type="text" maxlength="1" readonly value="&#x45;" class="unitRight size1of2 talign-right" />
+			</fieldset>
+			<div class="fs0 bshadow0 clearfix hidden-true">
+				<span class="unit pvs fgc1">liga: </span>
+				<input type="text" readonly value="" class="liga unitRight" />
+			</div>
+		</div>
+	</div>
+
+	<!--[if gt IE 8]><!-->
+	<div class="mhl clearfix mbl">
+		<h1>Font Test Drive</h1>
+		<label>
+			Font Size: <input id="fontSize" type="number" class="textbox0 mbm"
+			min="8" value="48" />
+			px
+		</label>
+		<input id="testText" type="text" class="phl size1of1 mvl"
+		placeholder="Type some text to test..." value=""/>
+		</label>
+		<div id="testDrive" class="icon-">&nbsp;
+		</div>
+	</div>
+	<!--<![endif]-->
+	<div class="bgc1 clearfix">
+		<p class="mhl">Generated by <a href="http://icomoon.io/app">IcoMoon</a></p>
+	</div>
+
+	<script src="demo-files/demo.js"></script>
+</body>
+</html>

二进制
global/css/icomoon/fonts/icomoon.eot


文件差异内容过多而无法显示
+ 51 - 0
global/css/icomoon/fonts/icomoon.svg


二进制
global/css/icomoon/fonts/icomoon.ttf


二进制
global/css/icomoon/fonts/icomoon.woff


文件差异内容过多而无法显示
+ 850 - 0
global/css/icomoon/selection.json


+ 148 - 0
global/css/icomoon/style.css

@@ -0,0 +1,148 @@
+@font-face {
+	font-family: 'icomoon';
+	src:url('fonts/icomoon.eot?miflbf');
+	src:url('fonts/icomoon.eot?#iefixmiflbf') format('embedded-opentype'),
+		url('fonts/icomoon.woff?miflbf') format('woff'),
+		url('fonts/icomoon.ttf?miflbf') format('truetype'),
+		url('fonts/icomoon.svg?miflbf#icomoon') format('svg');
+	font-weight: normal;
+	font-style: normal;
+}
+
+[class^="icon-"], [class*=" icon-"] {
+	font-family: 'icomoon';
+	speak: none;
+	font-style: normal;
+	font-weight: normal;
+	font-variant: normal;
+	text-transform: none;
+	line-height: 1;
+
+	/* Better Font Rendering =========== */
+	-webkit-font-smoothing: antialiased;
+	-moz-osx-font-smoothing: grayscale;
+}
+
+.icon-uni42:before {
+	content: "\43";
+}
+.icon-uni43:before {
+	content: "\44";
+}
+.icon-uni47:before {
+	content: "\47";
+}
+.icon-uni4D:before {
+	content: "\4d";
+}
+.icon-uni4E:before {
+	content: "\4e";
+}
+.icon-uni4F:before {
+	content: "\4f";
+}
+.icon-uni50:before {
+	content: "\50";
+}
+.icon-uni52:before {
+	content: "\52";
+}
+.icon-uni53:before {
+	content: "\53";
+}
+.icon-uni54:before {
+	content: "\54";
+}
+.icon-uni55:before {
+	content: "\55";
+}
+.icon-uni56:before {
+	content: "\56";
+}
+.icon-uni57:before {
+	content: "\57";
+}
+.icon-uni58:before {
+	content: "\58";
+}
+.icon-uni59:before {
+	content: "\59";
+}
+.icon-uni5A:before {
+	content: "\5a";
+}
+.icon-uni61:before {
+	content: "\61";
+}
+.icon-uni62:before {
+	content: "\62";
+}
+.icon-uni63:before {
+	content: "\63";
+}
+.icon-uni64:before {
+	content: "\64";
+}
+.icon-uni65:before {
+	content: "\65";
+}
+.icon-uni66:before {
+	content: "\66";
+}
+.icon-uni67:before {
+	content: "\67";
+}
+.icon-uni68:before {
+	content: "\68";
+}
+.icon-uni69:before {
+	content: "\69";
+}
+.icon-uni6A:before {
+	content: "\6a";
+}
+.icon-uni6B:before {
+	content: "\6b";
+}
+.icon-uni6C:before {
+	content: "\6c";
+}
+.icon-uni6D:before {
+	content: "\6d";
+}
+.icon-uni6F:before {
+	content: "\6f";
+}
+.icon-uni70:before {
+	content: "\70";
+}
+.icon-uni71:before {
+	content: "\71";
+}
+.icon-uni72:before {
+	content: "\72";
+}
+.icon-uni73:before {
+	content: "\73";
+}
+.icon-uni74:before {
+	content: "\74";
+}
+.icon-uni75:before {
+	content: "\75";
+}
+.icon-window:before {
+	content: "\49";
+}
+.icon-monitor:before {
+	content: "\48";
+}
+.icon-upload:before {
+	content: "\42";
+}
+.icon-inbox:before {
+	content: "\41";
+}
+.icon-chart:before {
+	content: "\45";
+}

二进制
global/css/logo.jpg


二进制
global/css/logo.png


二进制
global/css/missionBg.png


二进制
global/css/sidebarAfocue.png


二进制
global/css/sidebarBg.jpg


二进制
global/css/small.gif


二进制
global/css/small_asc.gif


二进制
global/css/small_desc.gif


文件差异内容过多而无法显示
+ 1066 - 0
global/css/style.css


+ 18 - 0
global/css/tablecloth.css

@@ -0,0 +1,18 @@
+/* 
+
+	TableCloth	
+	by Alen Grakalic, brought to you by cssglobe.com
+	
+*/
+
+/* general styles */
+
+table{width:100%;border-collapse:collapse;}
+th, td{text-align:left;padding:3px;border:1px solid #ddd;font-size:12px}
+th {border-bottom:1px solid #aaa;border-right:1px solid #aaa}
+th{background:#f5f5f5;color:#333;font-weight:normal}
+td{background:#fff;}
+thead th{text-align:center;padding:0 5px}
+tr:hover td{background:#fffaf2}
+tr:hover th{background:#ffe7bd}
+tr td:hover{background:#ffeed1}

二进制
global/css/wave1.png


二进制
global/css/wave2.png


二进制
global/images/avatar-1.png


二进制
global/images/avatar-2.png


二进制
global/images/avatar-3.png


二进制
global/images/avatar-4.png


二进制
global/images/avatar-normal - 副本.png


二进制
global/images/avatar-normal.png


二进制
global/images/avatar-normald.png


二进制
global/images/avatar96.png


二进制
global/images/avtra.png


二进制
global/img/mainLogo.png


二进制
global/img/softtips1.jpg


二进制
global/img/topBanner.png


二进制
global/img/未标题-1.png


+ 162 - 0
global/js/bootstrap-scrollspy.js

@@ -0,0 +1,162 @@
+/* =============================================================
+ * bootstrap-scrollspy.js v2.3.2
+ * http://twitter.github.com/bootstrap/javascript.html#scrollspy
+ * =============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============================================================== */
+
+
+!function ($) {
+
+  "use strict"; // jshint ;_;
+
+
+ /* SCROLLSPY CLASS DEFINITION
+  * ========================== */
+
+  function ScrollSpy(element, options) {
+    var process = $.proxy(this.process, this)
+      , $element = $(element).is('body') ? $(window) : $(element)
+      , href
+    this.options = $.extend({}, $.fn.scrollspy.defaults, options)
+    this.$scrollElement = $element.on('scroll.scroll-spy.data-api', process)
+    this.selector = (this.options.target
+      || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
+      || '') + ' .inav li > a'
+    this.$body = $('body')
+    this.refresh()
+    this.process()
+  }
+
+  ScrollSpy.prototype = {
+
+      constructor: ScrollSpy
+
+    , refresh: function () {
+        var self = this
+          , $targets
+
+        this.offsets = $([])
+        this.targets = $([])
+
+        $targets = this.$body
+          .find(this.selector)
+          .map(function () {
+            var $el = $(this)
+              , href = $el.data('target') || $el.attr('href')
+              , $href = /^#\w/.test(href) && $(href)
+            return ( $href
+              && $href.length
+              && [[ $href.position().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]] ) || null
+          })
+          .sort(function (a, b) { return a[0] - b[0] })
+          .each(function () {
+            self.offsets.push(this[0])
+            self.targets.push(this[1])
+          })
+      }
+
+    , process: function () {
+        var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
+          , scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
+          , maxScroll = scrollHeight - this.$scrollElement.height()
+          , offsets = this.offsets
+          , targets = this.targets
+          , activeTarget = this.activeTarget
+          , i
+
+        if (scrollTop >= maxScroll) {
+          return activeTarget != (i = targets.last()[0])
+            && this.activate ( i )
+        }
+
+        for (i = offsets.length; i--;) {
+          activeTarget != targets[i]
+            && scrollTop >= offsets[i]
+            && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
+            && this.activate( targets[i] )
+        }
+      }
+
+    , activate: function (target) {
+        var active
+          , selector
+
+        this.activeTarget = target
+
+        $(this.selector)
+          .parent('.active')
+          .removeClass('active')
+
+        selector = this.selector
+          + '[data-target="' + target + '"],'
+          + this.selector + '[href="' + target + '"]'
+
+        active = $(selector)
+          .parent('li')
+          .addClass('active')
+
+        if (active.parent('.dropdown-menu').length)  {
+          active = active.closest('li.dropdown').addClass('active')
+        }
+
+        active.trigger('activate')
+      }
+
+  }
+
+
+ /* SCROLLSPY PLUGIN DEFINITION
+  * =========================== */
+
+  var old = $.fn.scrollspy
+
+  $.fn.scrollspy = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+        , data = $this.data('scrollspy')
+        , options = typeof option == 'object' && option
+      if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.scrollspy.Constructor = ScrollSpy
+
+  $.fn.scrollspy.defaults = {
+    offset: 10
+  }
+
+
+ /* SCROLLSPY NO CONFLICT
+  * ===================== */
+
+  $.fn.scrollspy.noConflict = function () {
+    $.fn.scrollspy = old
+    return this
+  }
+
+
+ /* SCROLLSPY DATA-API
+  * ================== */
+
+  $(window).on('load', function () {
+    $('[data-spy="scroll"]').each(function () {
+      var $spy = $(this)
+      $spy.scrollspy($spy.data())
+    })
+  })
+
+}(window.jQuery);

文件差异内容过多而无法显示
+ 1437 - 0
global/js/bootstrap.js


文件差异内容过多而无法显示
+ 7 - 0
global/js/bootstrap.min.js


+ 114 - 0
global/js/chartdate.js

@@ -0,0 +1,114 @@
+
+        // 路径配置
+        require.config({
+            paths:{ 
+                'echarts' : 'http://echarts.baidu.com/build/echarts'
+            }
+        });
+        
+        // 使用
+        require(
+            [
+                'echarts',
+                'echarts/chart/pie', // 使用柱状图就加载bar模块,按需加载
+                'echarts/chart/bar'
+            ],
+            function(ec) {
+                // 基于准备好的dom,初始化echarts图表
+                var myChart = ec.init(document.getElementById('chartContainer'));   
+                var option = {
+                  title : {
+                      text: '标段计量分布',
+                      x:'left'
+                  },
+                  tooltip : {
+                      trigger: 'item',
+                      formatter: "{a} <br/>{b}:{c} <br>占总项目:{d}%"
+                  },
+                  legend: {
+                    selectedMode:false,
+                      orient : 'vertical',
+                      x : 'left',
+                      y : 'center',
+                      data:['路基工程','桥涵工程','隧道工程','交叉工程']
+                  },
+                  calculable : true,
+                  series : [
+                      {
+                          name:'标段计量分布',
+                          type:'pie',
+                          radius : '60%',
+                          center: ['60%', 175],
+                          data:[
+                              {value:27814964.00, name:'路基工程'},
+                              {value:41043186.10, name:'桥涵工程'},
+                              {value:42917475.00, name:'隧道工程'},
+                              {value:27634982.00, name:'交叉工程'}
+                          ]
+                      }
+                  ]
+                };
+                // 为echarts对象加载数据 
+                myChart.setOption(option); 
+                var myChart = ec.init(document.getElementById('chartContainer2'));   
+                var option = {
+                  title : {
+                    text: '标段计量进度',
+                    },
+    tooltip : {
+        trigger: 'axis',
+        formatter: "{b}  <br/>{a}:{c}元 <br/>{a1}:{c1}元<br/>{a2}:{c2}%"
+    },
+    legend: {
+        data:['累计合同计量','累计完成计量','完成进度百分比']
+    },
+    xAxis : [
+        {
+            type : 'category',
+            data : ['路基工程','桥涵工程','隧道工程','交叉工程']
+        }
+    ],
+    yAxis : [
+        {
+            type : 'value',
+            name : '金额',
+            position:'left',
+            axisLabel : {
+                formatter: '{value} 元'
+            },
+            splitArea : {show : true}
+        },
+        {
+            type : 'value',
+            name : '完成进度百分比',
+            position:'right',
+            max:'100',
+            axisLabel : {
+                formatter: '{value} %'
+            },
+            splitLine : {show : true}
+        }
+    ],
+    series : [
+        {
+            name:'累计合同计量',
+            type:'bar',
+            data:[27814964.00,41043186.10, 42917475.00, 27634982.00],
+        },
+        {
+            name:'累计完成计量',
+            type:'bar',
+            data:[20571481.02,28770211.71, 23427801.00, 1708798.00],
+        },
+        {
+            name:'完成进度百分比',
+            type:'line',
+            yAxisIndex: 1,
+            data:[73.95,70,54.58,6.18],
+        }
+    ]
+                };
+                // 为echarts对象加载数据 
+                myChart.setOption(option); 
+            }
+        );

+ 39 - 0
global/js/jl.js

@@ -0,0 +1,39 @@
+function autoFlashHeight() {
+    $(".body").height($(window).height());
+    $(".mainContainer").height($(window).height() - 51);
+    $(".adminContent").height($(window).height() - 117);
+    $(".slidePanel").height($(window).height() - 48);
+    $(".jlTable").height($(window).height() - 101);
+    $(".misTable").height($(window).height() - 228);
+    $(".topBanner").height($(window).height() - 65);
+    $(".tablelist").tablesorter({widthFixed: true});
+}
+$(window).resize(autoFlashHeight);
+
+$(function () {
+//滑动二级页面
+    $("#opensidebar").click(function () {
+	$(".slidePanel").animate({right: "0"}, "5000")
+    });
+    $(".closePanel").click(function () {
+	$(".slidePanel").animate({right: "-100%"}, "3000")
+    });
+    //添加工作组选择工作伙伴
+    $(".partner input").click(function () {
+	$(this).parent("li").toggleClass("focus")
+    });
+    $('*[data-toggle=tooltip]').mouseover(function () {
+	$(this).tooltip('show');
+    });
+    function waveloop1() {
+	$("#banner_bolang_bg_1").css({"left": "-236px"}).animate({"left": "-1233px"}, 25000, 'linear', waveloop1);
+    }
+    function waveloop2() {
+	$("#banner_bolang_bg_2").css({"left": "0px"}).animate({"left": "-1009px"}, 60000, 'linear', waveloop2);
+    }
+    waveloop1();
+    waveloop2();
+
+});
+
+

文件差异内容过多而无法显示
+ 4 - 0
global/js/jquery-1.7.1.min.js


文件差异内容过多而无法显示
+ 5 - 0
global/js/jquery-1.9.1.min.js


+ 706 - 0
global/js/jquery.fixedheadertable.js

@@ -0,0 +1,706 @@
+/*!
+ * jquery.fixedHeaderTable. The jQuery fixedHeaderTable plugin
+ *
+ * Copyright (c) 2013 Mark Malek
+ * http://fixedheadertable.com
+ *
+ * Licensed under MIT
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * http://docs.jquery.com/Plugins/Authoring
+ * jQuery authoring guidelines
+ *
+ * Launch  : October 2009
+ * Version : 1.3
+ * Released: May 9th, 2011
+ *
+ *
+ * all CSS sizing (width,height) is done in pixels (px)
+ */
+
+(function ($) {
+
+  $.fn.fixedHeaderTable = function (method) {
+
+    // plugin's default options
+    var defaults = {
+      width:          '100%',
+      height:         '100%',
+      themeClass:     'fht-default',
+      borderCollapse:  true,
+      fixedColumns:    0, // fixed first columns
+      fixedColumn:     false, // For backward-compatibility
+      sortable:        false,
+      autoShow:        true, // hide table after its created
+      footer:          false, // show footer
+      cloneHeadToFoot: false, // clone head and use as footer
+      autoResize:      false, // resize table if its parent wrapper changes size
+      create:          null // callback after plugin completes
+    };
+
+    var settings = {};
+
+    // public methods
+    var methods = {
+      init: function (options) {
+        settings = $.extend({}, defaults, options);
+
+        // iterate through all the DOM elements we are attaching the plugin to
+        return this.each(function () {
+          var $self = $(this); // reference the jQuery version of the current DOM element
+
+          if (helpers._isTable($self)) {
+            methods.setup.apply(this, Array.prototype.slice.call(arguments, 1));
+            $.isFunction(settings.create) && settings.create.call(this);
+          } else {
+            $.error('Invalid table mark-up');
+          }
+        });
+      },
+
+      /*
+       * Setup table structure for fixed headers and optional footer
+       */
+      setup: function () {
+        var $self       = $(this),
+            self        = this,
+            $thead      = $self.find('thead'),
+            $tfoot      = $self.find('tfoot'),
+            tfootHeight = 0,
+            $wrapper,
+            $divHead,
+            $divBody,
+            $fixedBody,
+            widthMinusScrollbar;
+
+        settings.originalTable = $(this).clone();
+        settings.includePadding = helpers._isPaddingIncludedWithWidth();
+        settings.scrollbarOffset = helpers._getScrollbarWidth();
+        settings.themeClassName = settings.themeClass;
+
+        if (settings.width.search('%') > -1) {
+            widthMinusScrollbar = $self.parent().width() - settings.scrollbarOffset;
+        } else {
+            widthMinusScrollbar = settings.width - settings.scrollbarOffset;
+        }
+
+        $self.css({
+          width: widthMinusScrollbar
+        });
+
+
+        if (!$self.closest('.fht-table-wrapper').length) {
+          $self.addClass('fht-table');
+          $self.wrap('<div class="fht-table-wrapper"></div>');
+        }
+
+        $wrapper = $self.closest('.fht-table-wrapper');
+
+        if(settings.fixedColumn == true && settings.fixedColumns <= 0) {
+          settings.fixedColumns = 1;
+        }
+
+        if (settings.fixedColumns > 0 && $wrapper.find('.fht-fixed-column').length == 0) {
+          $self.wrap('<div class="fht-fixed-body"></div>');
+
+          $('<div class="fht-fixed-column"></div>').prependTo($wrapper);
+
+          $fixedBody    = $wrapper.find('.fht-fixed-body');
+        }
+
+        $wrapper.css({
+          width: settings.width,
+          height: settings.height
+        })
+          .addClass(settings.themeClassName);
+
+        if (!$self.hasClass('fht-table-init')) {
+          $self.wrap('<div class="fht-tbody"></div>');
+        }
+
+        $divBody = $self.closest('.fht-tbody');
+
+        var tableProps = helpers._getTableProps($self);
+
+        helpers._setupClone($divBody, tableProps.tbody);
+
+        if (!$self.hasClass('fht-table-init')) {
+          if (settings.fixedColumns > 0) {
+            $divHead = $('<div class="fht-thead"><table class="fht-table"></table></div>').prependTo($fixedBody);
+          } else {
+            $divHead = $('<div class="fht-thead"><table class="fht-table"></table></div>').prependTo($wrapper);
+          }
+
+          $divHead.find('table.fht-table')
+            .addClass(settings.originalTable.attr('class'))
+            .attr('style', settings.originalTable.attr('style'));
+
+          $thead.clone().appendTo($divHead.find('table'));
+        } else {
+          $divHead = $wrapper.find('div.fht-thead');
+        }
+
+        helpers._setupClone($divHead, tableProps.thead);
+
+        $self.css({
+          'margin-top': -$divHead.outerHeight(true)
+        });
+
+        /*
+         * Check for footer
+         * Setup footer if present
+         */
+        if (settings.footer == true) {
+          helpers._setupTableFooter($self, self, tableProps);
+
+          if (!$tfoot.length) {
+            $tfoot = $wrapper.find('div.fht-tfoot table');
+          }
+
+          tfootHeight = $tfoot.outerHeight(true);
+        }
+
+        var tbodyHeight = $wrapper.height() - $thead.outerHeight(true) - tfootHeight - tableProps.border;
+
+        $divBody.css({
+          'height': tbodyHeight
+        });
+
+        $self.addClass('fht-table-init');
+
+        if (typeof(settings.altClass) !== 'undefined') {
+          methods.altRows.apply(self);
+        }
+
+        if (settings.fixedColumns > 0) {
+          helpers._setupFixedColumn($self, self, tableProps);
+        }
+
+        if (!settings.autoShow) {
+          $wrapper.hide();
+        }
+
+        helpers._bindScroll($divBody, tableProps);
+
+        return self;
+      },
+
+      /*
+       * Resize the table
+       * Incomplete - not implemented yet
+       */
+      resize: function() {
+        var self  = this;
+        return self;
+      },
+
+      /*
+       * Add CSS class to alternating rows
+       */
+      altRows: function(arg1) {
+        var $self = $(this),
+        altClass  = (typeof(arg1) !== 'undefined') ? arg1 : settings.altClass;
+
+        $self.closest('.fht-table-wrapper')
+          .find('tbody tr:odd:not(:hidden)')
+          .addClass(altClass);
+      },
+
+      /*
+       * Show a hidden fixedHeaderTable table
+       */
+      show: function(arg1, arg2, arg3) {
+        var $self   = $(this),
+            self      = this,
+            $wrapper  = $self.closest('.fht-table-wrapper');
+
+        // User provided show duration without a specific effect
+        if (typeof(arg1) !== 'undefined' && typeof(arg1) === 'number') {
+          $wrapper.show(arg1, function() {
+            $.isFunction(arg2) && arg2.call(this);
+          });
+
+          return self;
+
+        } else if (typeof(arg1) !== 'undefined' && typeof(arg1) === 'string' &&
+          typeof(arg2) !== 'undefined' && typeof(arg2) === 'number') {
+          // User provided show duration with an effect
+
+          $wrapper.show(arg1, arg2, function() {
+            $.isFunction(arg3) && arg3.call(this);
+          });
+
+          return self;
+
+        }
+
+        $self.closest('.fht-table-wrapper')
+          .show();
+        $.isFunction(arg1) && arg1.call(this);
+
+        return self;
+      },
+
+      /*
+       * Hide a fixedHeaderTable table
+       */
+      hide: function(arg1, arg2, arg3) {
+        var $self     = $(this),
+            self    = this,
+            $wrapper  = $self.closest('.fht-table-wrapper');
+
+        // User provided show duration without a specific effect
+        if (typeof(arg1) !== 'undefined' && typeof(arg1) === 'number') {
+          $wrapper.hide(arg1, function() {
+            $.isFunction(arg3) && arg3.call(this);
+          });
+
+          return self;
+        } else if (typeof(arg1) !== 'undefined' && typeof(arg1) === 'string' &&
+          typeof(arg2) !== 'undefined' && typeof(arg2) === 'number') {
+
+          $wrapper.hide(arg1, arg2, function() {
+            $.isFunction(arg3) && arg3.call(this);
+          });
+
+          return self;
+        }
+
+        $self.closest('.fht-table-wrapper')
+          .hide();
+
+        $.isFunction(arg3) && arg3.call(this);
+
+
+
+        return self;
+      },
+
+      /*
+       * Destory fixedHeaderTable and return table to original state
+       */
+      destroy: function() {
+        var $self    = $(this),
+            self     = this,
+            $wrapper = $self.closest('.fht-table-wrapper');
+
+        $self.insertBefore($wrapper)
+          .removeAttr('style')
+          .append($wrapper.find('tfoot'))
+          .removeClass('fht-table fht-table-init')
+          .find('.fht-cell')
+          .remove();
+
+        $wrapper.remove();
+
+        return self;
+      }
+
+    };
+
+    // private methods
+    var helpers = {
+
+      /*
+       * return boolean
+       * True if a thead and tbody exist.
+       */
+      _isTable: function($obj) {
+        var $self = $obj,
+            hasTable = $self.is('table'),
+            hasThead = $self.find('thead').length > 0,
+            hasTbody = $self.find('tbody').length > 0;
+
+        if (hasTable && hasThead && hasTbody) {
+          return true;
+        }
+
+        return false;
+
+      },
+
+      /*
+       * return void
+       * bind scroll event
+       */
+      _bindScroll: function($obj) {
+        var $self = $obj,
+            $wrapper = $self.closest('.fht-table-wrapper'),
+            $thead = $self.siblings('.fht-thead'),
+            $tfoot = $self.siblings('.fht-tfoot');
+
+        $self.bind('scroll', function() {
+          if (settings.fixedColumns > 0) {
+            var $fixedColumns = $wrapper.find('.fht-fixed-column');
+
+            $fixedColumns.find('.fht-tbody table')
+              .css({
+                  'margin-top': -$self.scrollTop()
+              });
+          }
+
+          $thead.find('table')
+            .css({
+              'margin-left': -this.scrollLeft
+            });
+
+          if (settings.footer || settings.cloneHeadToFoot) {
+            $tfoot.find('table')
+              .css({
+                'margin-left': -this.scrollLeft
+              });
+          }
+        });
+      },
+
+      /*
+       * return void
+       */
+      _fixHeightWithCss: function ($obj, tableProps) {
+        if (settings.includePadding) {
+          $obj.css({
+            'height': $obj.height() + tableProps.border
+          });
+        } else {
+          $obj.css({
+            'height': $obj.parent().height() + tableProps.border
+          });
+        }
+      },
+
+      /*
+       * return void
+       */
+      _fixWidthWithCss: function($obj, tableProps, width) {
+        if (settings.includePadding) {
+          $obj.each(function() {
+            $(this).css({
+              'width': width == undefined ? $(this).width() + tableProps.border : width + tableProps.border
+            });
+          });
+        } else {
+          $obj.each(function() {
+            $(this).css({
+              'width': width == undefined ? $(this).parent().width() + tableProps.border : width + tableProps.border
+            });
+          });
+        }
+
+      },
+
+      /*
+       * return void
+       */
+      _setupFixedColumn: function ($obj, obj, tableProps) {
+        var $self             = $obj,
+            $wrapper          = $self.closest('.fht-table-wrapper'),
+            $fixedBody        = $wrapper.find('.fht-fixed-body'),
+            $fixedColumn      = $wrapper.find('.fht-fixed-column'),
+            $thead            = $('<div class="fht-thead"><table class="fht-table"><thead><tr></tr></thead></table></div>'),
+            $tbody            = $('<div class="fht-tbody"><table class="fht-table"><tbody></tbody></table></div>'),
+            $tfoot            = $('<div class="fht-tfoot"><table class="fht-table"><tfoot><tr></tr></tfoot></table></div>'),
+            fixedBodyWidth    = $wrapper.width(),
+            fixedBodyHeight   = $fixedBody.find('.fht-tbody').height() - settings.scrollbarOffset,
+            $firstThChildren,
+            $firstTdChildren,
+            fixedColumnWidth,
+            $newRow,
+            firstTdChildrenSelector;
+
+        $thead.find('table.fht-table').addClass(settings.originalTable.attr('class'));
+        $tbody.find('table.fht-table').addClass(settings.originalTable.attr('class'));
+        $tfoot.find('table.fht-table').addClass(settings.originalTable.attr('class'));
+
+        $firstThChildren = $fixedBody.find('.fht-thead thead tr > *:lt(' + settings.fixedColumns + ')');
+        fixedColumnWidth = settings.fixedColumns * tableProps.border;
+        $firstThChildren.each(function() {
+          fixedColumnWidth += $(this).outerWidth(true);
+        });
+
+        // Fix cell heights
+        helpers._fixHeightWithCss($firstThChildren, tableProps);
+        helpers._fixWidthWithCss($firstThChildren, tableProps);
+
+        var tdWidths = [];
+        $firstThChildren.each(function() {
+          tdWidths.push($(this).width());
+        });
+
+        firstTdChildrenSelector = 'tbody tr > *:not(:nth-child(n+' + (settings.fixedColumns + 1) + '))';
+        $firstTdChildren = $fixedBody.find(firstTdChildrenSelector)
+          .each(function(index) {
+            helpers._fixHeightWithCss($(this), tableProps);
+            helpers._fixWidthWithCss($(this), tableProps, tdWidths[index % settings.fixedColumns] );
+          });
+
+        // clone header
+        $thead.appendTo($fixedColumn)
+          .find('tr')
+          .append($firstThChildren.clone());
+
+        $tbody.appendTo($fixedColumn)
+          .css({
+            'margin-top': -1,
+            'height': fixedBodyHeight + tableProps.border
+          });
+
+        $firstTdChildren.each(function(index) {
+          if (index % settings.fixedColumns == 0) {
+            $newRow = $('<tr></tr>').appendTo($tbody.find('tbody'));
+
+            if (settings.altClass && $(this).parent().hasClass(settings.altClass)) {
+              $newRow.addClass(settings.altClass);
+            }
+          }
+
+          $(this).clone()
+            .appendTo($newRow);
+        });
+
+        // set width of fixed column wrapper
+        $fixedColumn.css({
+          'height': 0,
+          'width': fixedColumnWidth
+        });
+
+
+        // bind mousewheel events
+        var maxTop = $fixedColumn.find('.fht-tbody .fht-table').height() - $fixedColumn.find('.fht-tbody').height();
+        $fixedColumn.find('.fht-tbody .fht-table').bind('mousewheel', function(event, delta, deltaX, deltaY) {
+          if (deltaY == 0) {
+            return;
+          }
+          var top = parseInt($(this).css('marginTop'), 10) + (deltaY > 0 ? 120 : -120);
+          if (top > 0) {
+            top = 0;
+          }
+          if (top < -maxTop) {
+            top = -maxTop;
+          }
+          $(this).css('marginTop', top);
+          $fixedBody.find('.fht-tbody').scrollTop(-top).scroll();
+          return false;
+        });
+
+
+        // set width of body table wrapper
+        $fixedBody.css({
+          'width': fixedBodyWidth
+        });
+
+        // setup clone footer with fixed column
+        if (settings.footer == true || settings.cloneHeadToFoot == true) {
+          var $firstTdFootChild = $fixedBody.find('.fht-tfoot tr > *:lt(' + settings.fixedColumns + ')'),
+              footwidth;
+
+          helpers._fixHeightWithCss($firstTdFootChild, tableProps);
+          $tfoot.appendTo($fixedColumn)
+            .find('tr')
+            .append($firstTdFootChild.clone());
+          // Set (view width) of $tfoot div to width of table (this accounts for footers with a colspan)
+          footwidth = $tfoot.find('table').innerWidth();
+          $tfoot.css({
+            'top': settings.scrollbarOffset,
+            'width': footwidth
+          });
+        }
+      },
+
+      /*
+       * return void
+       */
+      _setupTableFooter: function ($obj, obj, tableProps) {
+        var $self     = $obj,
+            $wrapper  = $self.closest('.fht-table-wrapper'),
+            $tfoot    = $self.find('tfoot'),
+            $divFoot  = $wrapper.find('div.fht-tfoot');
+
+        if (!$divFoot.length) {
+          if (settings.fixedColumns > 0) {
+            $divFoot = $('<div class="fht-tfoot"><table class="fht-table"></table></div>').appendTo($wrapper.find('.fht-fixed-body'));
+          } else {
+            $divFoot = $('<div class="fht-tfoot"><table class="fht-table"></table></div>').appendTo($wrapper);
+          }
+        }
+        $divFoot.find('table.fht-table').addClass(settings.originalTable.attr('class'));
+
+        switch (true) {
+          case !$tfoot.length && settings.cloneHeadToFoot == true && settings.footer == true:
+
+            var $divHead = $wrapper.find('div.fht-thead');
+
+            $divFoot.empty();
+            $divHead.find('table')
+              .clone()
+              .appendTo($divFoot);
+
+            break;
+          case $tfoot.length && settings.cloneHeadToFoot == false && settings.footer == true:
+
+            $divFoot.find('table')
+              .append($tfoot)
+              .css({
+                'margin-top': -tableProps.border
+              });
+
+            helpers._setupClone($divFoot, tableProps.tfoot);
+
+            break;
+        }
+
+      },
+
+      /*
+       * return object
+       * Widths of each thead cell and tbody cell for the first rows.
+       * Used in fixing widths for the fixed header and optional footer.
+       */
+      _getTableProps: function($obj) {
+        var tableProp = {
+              thead: {},
+              tbody: {},
+              tfoot: {},
+              border: 0
+            },
+            borderCollapse = 1;
+
+        if (settings.borderCollapse == true) {
+          borderCollapse = 2;
+        }
+
+        tableProp.border = ($obj.find('th:first-child').outerWidth() - $obj.find('th:first-child').innerWidth()) / borderCollapse;
+
+        $obj.find('thead tr:first-child > *').each(function(index) {
+          tableProp.thead[index] = $(this).width() + tableProp.border;
+        });
+
+        $obj.find('tfoot tr:first-child > *').each(function(index) {
+          tableProp.tfoot[index] = $(this).width() + tableProp.border;
+        });
+
+        $obj.find('tbody tr:first-child > *').each(function(index) {
+          tableProp.tbody[index] = $(this).width() + tableProp.border;
+        });
+
+        return tableProp;
+      },
+
+      /*
+       * return void
+       * Fix widths of each cell in the first row of obj.
+       */
+      _setupClone: function($obj, cellArray) {
+        var $self    = $obj,
+            selector = ($self.find('thead').length) ?
+              'thead tr:first-child > *' :
+              ($self.find('tfoot').length) ?
+              'tfoot tr:first-child > *' :
+              'tbody tr:first-child > *',
+            $cell;
+
+        $self.find(selector).each(function(index) {
+          $cell = ($(this).find('div.fht-cell').length) ? $(this).find('div.fht-cell') : $('<div class="fht-cell"></div>').appendTo($(this));
+
+          $cell.css({
+            'width': parseInt(cellArray[index], 10)
+          });
+
+          /*
+           * Fixed Header and Footer should extend the full width
+           * to align with the scrollbar of the body
+           */
+          if (!$(this).closest('.fht-tbody').length && $(this).is(':last-child') && !$(this).closest('.fht-fixed-column').length) {
+            var padding = Math.max((($(this).innerWidth() - $(this).width()) / 2), settings.scrollbarOffset);
+            $(this).css({
+              'padding-right': parseInt($(this).css('padding-right')) + padding + 'px'
+            });
+          }
+        });
+      },
+
+      /*
+       * return boolean
+       * Determine how the browser calculates fixed widths with padding for tables
+       * true if width = padding + width
+       * false if width = width
+       */
+      _isPaddingIncludedWithWidth: function() {
+        var $obj = $('<table class="fht-table"><tr><td style="padding: 10px; font-size: 10px;">test</td></tr></table>'),
+            defaultHeight,
+            newHeight;
+
+        $obj.addClass(settings.originalTable.attr('class'));
+        $obj.appendTo('body');
+
+        defaultHeight = $obj.find('td').height();
+
+        $obj.find('td')
+          .css('height', $obj.find('tr').height());
+
+        newHeight = $obj.find('td').height();
+        $obj.remove();
+
+        if (defaultHeight != newHeight) {
+          return true;
+        } else {
+          return false;
+        }
+
+      },
+
+      /*
+       * return int
+       * get the width of the browsers scroll bar
+       */
+      _getScrollbarWidth: function() {
+        var scrollbarWidth = 0;
+
+        if (!scrollbarWidth) {
+          if (/msie/.test(navigator.userAgent.toLowerCase())) {
+            var $textarea1 = $('<textarea cols="10" rows="2"></textarea>')
+                  .css({ position: 'absolute', top: -1000, left: -1000 }).appendTo('body'),
+                $textarea2 = $('<textarea cols="10" rows="2" style="overflow: hidden;"></textarea>')
+                  .css({ position: 'absolute', top: -1000, left: -1000 }).appendTo('body');
+
+            scrollbarWidth = $textarea1.width() - $textarea2.width() + 2; // + 2 for border offset
+            $textarea1.add($textarea2).remove();
+          } else {
+            var $div = $('<div />')
+                  .css({ width: 100, height: 100, overflow: 'auto', position: 'absolute', top: -1000, left: -1000 })
+                  .prependTo('body').append('<div />').find('div')
+                  .css({ width: '100%', height: 200 });
+
+            scrollbarWidth = 100 - $div.width();
+            $div.parent().remove();
+          }
+        }
+
+        return scrollbarWidth;
+      }
+
+    };
+
+
+    // if a method as the given argument exists
+    if (methods[method]) {
+
+      // call the respective method
+      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+
+      // if an object is given as method OR nothing is given as argument
+    } else if (typeof method === 'object' || !method) {
+
+      // call the initialization method
+      return methods.init.apply(this, arguments);
+
+      // otherwise
+    } else {
+
+      // trigger an error
+      $.error('Method "' +  method + '" does not exist in fixedHeaderTable plugin!');
+
+    }
+
+  };
+
+})(jQuery);

文件差异内容过多而无法显示
+ 20 - 0
global/js/jquery.fixedheadertable.min.js


+ 808 - 0
global/js/jquery.tablesorter.js

@@ -0,0 +1,808 @@
+/*
+ * 
+ * TableSorter 2.0 - Client-side table sorting with ease!
+ * Version 2.0
+ * @requires jQuery v1.1.3
+ * 
+ * Copyright (c) 2007 Christian Bach
+ * Examples and docs at: http://tablesorter.com
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ * 
+ */
+/**
+ *
+ * @description Create a sortable table with multi-column sorting capabilitys
+ * 
+ * @example $('#table').tablesorter();
+ * @desc Create a simple tablesorter interface.
+ *
+ * @example $('#table').tablesorter({ sortList:[[0,0],[1,0]] });
+ * @desc Create a tablesorter interface and sort on the first and secound column in ascending order.
+ * 
+ * @example $('#table').tablesorter({ headers: { 0: { sorter: false}, 1: {sorter: false} } });
+ * @desc Create a tablesorter interface and disableing the first and secound column headers.
+ * 
+ * @example $('#table').tablesorter({ 0: {sorter:"integer"}, 1: {sorter:"currency"} });
+ * @desc Create a tablesorter interface and set a column parser for the first and secound column.
+ * 
+ * 
+ * @param Object settings An object literal containing key/value pairs to provide optional settings.
+ * 
+ * @option String cssHeader (optional) 			A string of the class name to be appended to sortable tr elements in the thead of the table. 
+ * 												Default value: "header"
+ * 
+ * @option String cssAsc (optional) 			A string of the class name to be appended to sortable tr elements in the thead on a ascending sort. 
+ * 												Default value: "headerSortUp"
+ * 
+ * @option String cssDesc (optional) 			A string of the class name to be appended to sortable tr elements in the thead on a descending sort. 
+ * 												Default value: "headerSortDown"
+ * 
+ * @option String sortInitialOrder (optional) 	A string of the inital sorting order can be asc or desc. 
+ * 												Default value: "asc"
+ * 
+ * @option String sortMultisortKey (optional) 	A string of the multi-column sort key. 
+ * 												Default value: "shiftKey"
+ * 
+ * @option String textExtraction (optional) 	A string of the text-extraction method to use. 
+ * 												For complex html structures inside td cell set this option to "complex", 
+ * 												on large tables the complex option can be slow. 
+ * 												Default value: "simple"
+ * 
+ * @option Object headers (optional) 			An array containing the forces sorting rules. 
+ * 												This option let's you specify a default sorting rule. 
+ * 												Default value: null
+ * 
+ * @option Array sortList (optional) 			An array containing the forces sorting rules. 
+ * 												This option let's you specify a default sorting rule. 
+ * 												Default value: null
+ * 
+ * @option Array sortForce (optional) 			An array containing the forces sorting rules. 
+ * 												This option let's you specify a default sorting rule. 
+ * 												Default value: null
+ *  
+ * 
+ * @option Boolean widthFixed (optional) 		Boolean flag indicating if tablesorter should apply fixed widths to the table columns.
+ * 												This is usefull when using the pager companion plugin.
+ * 												This options requires the dimension jquery plugin.
+ * 												Default value: false
+ *
+ * @option Boolean cancelSelection (optional) 	Boolean flag indicating if tablesorter should cancel selection of the table headers text.
+ * 												Default value: true
+ * 
+ * @type jQuery
+ *
+ * @name tablesorter
+ * 
+ * @cat Plugins/Tablesorter
+ * 
+ * @author Christian Bach/christian.bach@polyester.se
+ */
+
+(function($) {
+	$.extend({
+		tablesorter: new function() {
+			
+			var parsers = [], widgets = [];
+			
+			this.defaults = {
+				cssHeader: "header",
+				cssAsc: "headerSortUp",
+				cssDesc: "headerSortDown",
+				sortInitialOrder: "asc",
+				sortMultiSortKey: "shiftKey",
+				sortForce: null,
+				textExtraction: "simple",
+				parsers: {}, 
+				widgets: [],		
+				widgetZebra: {css: ["even","odd"]},
+				headers: {},
+				widthFixed: false,
+				cancelSelection: true,
+				sortList: [],
+				headerList: [],
+				dateFormat: "us",
+				debug: false
+			};
+			
+			/* debuging utils */
+			function benchmark(label,stamp) {
+				log(label + "," + (new Date().getTime() - stamp.getTime()) + "ms");
+			}
+			
+			function log(s) {
+				if (typeof console != "undefined" && typeof console.debug != "undefined") {
+					console.log(s);
+				} else {
+					alert(s);
+				}
+			}
+						
+			/* parsers utils */
+			function buildParserCache(table,$headers) {
+				
+				if(table.config.debug) { var parsersDebug = ""; }
+				
+				var list = [], cells = table.tBodies[0].rows[0].cells, l = cells.length;
+				
+				for (var i=0;i < l; i++) {
+					var p = false;
+					
+					if($.meta && ($($headers[i]).data() && $($headers[i]).data().sorter)  ) {
+					
+						p = getParserById($($headers[i]).data().sorter);	
+					
+					} else if((table.config.headers[i] && table.config.headers[i].sorter)) {
+
+						p = getParserById(table.config.headers[i].sorter);
+					}
+					if(!p) {
+						p = detectParserForColumn(table.config,cells[i]);
+					}
+
+					if(table.config.debug) { parsersDebug += "column:" + i + " parser:" +p.id + "\n"; }
+
+					list.push(p);
+				}
+
+				if(table.config.debug) { log(parsersDebug); }
+
+				return list;
+			};
+			
+			function detectParserForColumn(config,node) {
+				var l = parsers.length;
+				for(var i=1; i < l; i++) {
+					if(parsers[i].is($.trim(getElementText(config,node)))) {
+						return parsers[i];
+					}
+				}
+				
+				// 0 is always the generic parser (text)
+				return parsers[0];
+			}
+			
+			function getParserById(name) {
+				var l = parsers.length;
+				for(var i=0; i < l; i++) {
+					if(parsers[i].id.toLowerCase() == name.toLowerCase()) {	
+						return parsers[i];
+					}
+				}
+				return false;
+			}
+			
+			/* utils */
+			function buildCache(table) {
+				
+				if(table.config.debug) { var cacheTime = new Date(); }
+				
+				var totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0,
+					totalCells = table.tBodies[0].rows[0].cells.length,
+					parsers = table.config.parsers, 
+					cache = {row: [], normalized: []};
+				
+					for (var i=0;i < totalRows; ++i) {
+					
+						/** Add the table data to main data array */
+						var c = table.tBodies[0].rows[i], cols = [];
+					
+						cache.row.push($(c));
+						
+						for(var j=0; j < totalCells; ++j) {
+							cols.push(parsers[j].format(getElementText(table.config,c.cells[j]),table,c.cells[j]));	
+						}
+												
+						cols.push(i); // add position for rowCache
+						cache.normalized.push(cols);
+						cols = null;
+					};
+				
+				if(table.config.debug) { benchmark("Building cache for " + totalRows + " rows:", cacheTime); }
+				
+				return cache;
+			};
+			
+			function getElementText(config,node) {
+				
+				if(!node) return "";
+								
+				var t = "";
+				
+				
+				if(typeof(config.textExtraction) == "function") {
+					t = config.textExtraction(node);
+				} else if(config.textExtraction == "complex") { 
+					t = $(node).text();
+				} else {
+					if(node.childNodes[0] && node.childNodes[0].hasChildNodes()) {
+						t = node.childNodes[0].innerHTML;
+					} else {
+						t = node.innerHTML;
+					}
+				}
+				return t;
+			}
+			
+			function appendToTable(table,cache) {
+				
+				if(table.config.debug) {var appendTime = new Date()}
+				
+				var c = cache, 
+					r = c.row, 
+					n= c.normalized, 
+					totalRows = n.length, 
+					checkCell = (n[0].length-1), 
+					tableBody = $("tbody:first",table).empty();
+					rows = [];
+				
+				for (var i=0;i < totalRows; i++) {
+					 	rows.push(r[n[i][checkCell]]);
+						if(table.config.appender == null) {
+							tableBody.append(r[n[i][checkCell]]);
+						}
+				}	
+
+				if(table.config.appender != null) {
+					table.config.appender(table,rows);	
+				}
+				
+				rows = null;
+				
+				//apply table widgets
+				applyWidget(table);
+				
+				if(table.config.debug) { benchmark("Rebuilt table:", appendTime); }
+			
+			};
+			
+			function buildHeaders(table) {
+				
+				if(table.config.debug) { var time = new Date(); }
+				
+				var meta = ($.meta) ? true : false, tableHeadersRows = [];
+			
+				for(var i = 0; i < table.tHead.rows.length; i++) { tableHeadersRows[i]=0; };
+				
+				$tableHeaders = $(checkCellColSpan(table, tableHeadersRows, 0,table.tHead.rows[0].cells.length));
+		
+				$tableHeaders.each(function(index) {
+							
+					this.count = 0;
+					this.column = index;
+					this.order = formatSortingOrder(table.config.sortInitialOrder);
+					
+					if(checkHeaderMetadata(this) || checkHeaderOptions(table,index)) this.sortDisabled = true;
+					
+					if(!this.sortDisabled) {
+						$(this).addClass(table.config.cssHeader);
+					}
+					
+					// add cell to headerList
+					table.config.headerList[index]= this;
+				});
+				
+				if(table.config.debug) { benchmark("Built headers:", time); log($tableHeaders); }
+				
+				return $tableHeaders;
+				
+			};
+						
+		   	function checkCellColSpan(table, headerArr, row) {
+                var arr = [], r = table.tHead.rows, c = r[row].cells;
+				
+				for(var i=headerArr[row]; i < c.length; i++) {
+					var cell = c[i];
+					
+					if ( cell.colSpan > 1) { 
+						arr = arr.concat(checkCellColSpan(table, headerArr,row+cell.rowSpan));
+					} else  {
+						if(table.tHead.length == 1 || (cell.rowSpan > 1 || !r[row+1])) {
+							arr.push(cell);
+						}
+						headerArr[row] = (i+row);
+					}
+				}
+				return arr;
+			};
+			
+			function checkHeaderMetadata(cell) {
+				if(($.meta) && ($(cell).data().sorter === false)) { return true; };
+				return false;
+			}
+			
+			function checkHeaderOptions(table,i) {	
+				if((table.config.headers[i]) && (table.config.headers[i].sorter === false)) { return true; };
+				return false;
+			}
+			
+			function applyWidget(table) {
+				var c = table.config.widgets;
+				var l = c.length;
+				for(var i=0; i < l; i++) {
+					
+					getWidgetById(c[i]).format(table);
+				}
+				
+			}
+			
+			function getWidgetById(name) {
+				var l = widgets.length;
+				for(var i=0; i < l; i++) {
+					if(widgets[i].id.toLowerCase() == name.toLowerCase() ) {
+						return widgets[i]; 
+					}
+				}
+			};
+			
+			function formatSortingOrder(v) {
+				
+				if(typeof(v) != "Number") {
+					i = (v.toLowerCase() == "desc") ? 1 : 0;
+				} else {
+					i = (v == (0 || 1)) ? v : 0;
+				}
+				return i;
+			}
+			
+			function isValueInArray(v, a) {
+				var l = a.length;
+				for(var i=0; i < l; i++) {
+					if(a[i][0] == v) {
+						return true;	
+					}
+				}
+				return false;
+			}
+				
+			function setHeadersCss(table,$headers, list, css) {
+				// remove all header information
+				$headers.removeClass(css[0]).removeClass(css[1]);
+				
+				var h = [];
+				$headers.each(function(offset) {
+						if(!this.sortDisabled) {
+							h[this.column] = $(this);					
+						}
+				});
+
+				var l = list.length; 
+				for(var i=0; i < l; i++) {
+					h[list[i][0]].addClass(css[list[i][1]]);
+				}
+			}
+			
+			function fixColumnWidth(table,$headers) {
+				var c = table.config;
+				if(c.widthFixed) {
+					var colgroup = $('<colgroup>');
+					$("tbody:first tr:first td",table).each(function() {
+						
+						colgroup.append($('<col>').css('width',$(this).width()));
+					
+					});
+					$(table).prepend(colgroup);
+				};
+			}
+			
+			function updateHeaderSortCount(table,sortList) {
+				var c = table.config, l = sortList.length;
+				for(var i=0; i < l; i++) {
+					var s = sortList[i], o = c.headerList[s[0]];
+					o.count = s[1];
+					o.count++;
+				}
+			}
+			
+			/* sorting methods */
+			function multisort(table,sortList,cache) {
+				
+				if(table.config.debug) { var sortTime = new Date(); }
+				
+				var dynamicExp = "var sortWrapper = function(a,b) {", l = sortList.length;
+					
+				for(var i=0; i < l; i++) {
+					
+					var c = sortList[i][0];
+					var order = sortList[i][1];
+					var s = (getCachedSortType(table.config.parsers,c) == "text") ? ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ? "sortNumeric" : "sortNumericDesc");
+					
+					var e = "e" + i;
+					
+					dynamicExp += "var " + e + " = " + s + "(a[" + c + "],b[" + c + "]); ";
+					dynamicExp += "if(" + e + ") { return " + e + "; } ";
+					dynamicExp += "else { ";
+				}
+					
+				for(var i=0; i < l; i++) {
+					dynamicExp += "}; ";
+				}
+				
+				dynamicExp += "return 0; ";	
+				dynamicExp += "}; ";	
+				
+				eval(dynamicExp);
+				
+				cache.normalized.sort(sortWrapper);
+				
+				if(table.config.debug) { benchmark("Sorting on " + sortList.toString() + " and dir " + order+ " time:", sortTime); }
+				
+				return cache;
+			};
+			
+			function sortText(a,b) {
+				return ((a < b) ? -1 : ((a > b) ? 1 : 0));
+			};
+			
+			function sortTextDesc(a,b) {
+				return ((b < a) ? -1 : ((b > a) ? 1 : 0));
+			};	
+			
+	 		function sortNumeric(a,b) {
+				return a-b;
+			};
+			
+			function sortNumericDesc(a,b) {
+				return b-a;
+			};
+			
+			function getCachedSortType(parsers,i) {
+				return parsers[i].type;
+			};
+			
+			/* public methods */
+			this.construct = function(settings) {
+
+				return this.each(function() {
+					
+					
+					
+					
+					var $this, $document,$headers, cache, config, shiftDown = 0, sortOrder;
+					
+					this.config = {};
+					
+					config = $.extend(this.config, $.tablesorter.defaults, settings);
+					
+					if(!this.tHead || !this.tBodies) return true;
+					
+					// store common expression for speed					
+					$this = $(this);
+					
+					// build headers
+					$headers = buildHeaders(this);
+					
+					// try to auto detect column type, and store in tables config
+					this.config.parsers = buildParserCache(this,$headers);
+					
+					
+					// build the cache for the tbody cells
+					cache = buildCache(this);
+					
+					// get the css class names, could be done else where.
+					var sortCSS = [config.cssDesc,config.cssAsc];
+					
+					// fixate columns if the users supplies the fixedWidth option
+					fixColumnWidth(this);
+					
+					// apply event handling to headers
+					// this is to big, perhaps break it out?
+					$headers.click(function(e) {
+						if(!this.sortDisabled) {
+							// store exp, for speed
+							var $cell = $(this);
+	
+							// get current column index
+							var i = this.column;
+							
+							// get current column sort order
+							this.order = this.count++ % 2;
+							
+							
+							
+							// user only whants to sort on one column
+							if(!e[config.sortMultiSortKey]) {
+								
+								// flush the sort list
+								config.sortList = [];
+								
+								if(config.sortForce != null) {
+									var a = config.sortForce; 
+									for(var j=0; j < a.length; j++) { 	
+										config.sortList.push(a[j]);	
+									}
+								}
+								
+								// add column to sort list
+								config.sortList.push([i,this.order]);
+							
+							// multi column sorting	
+							} else {
+								// the user has clicked on an all ready sortet column.
+								if(isValueInArray(i,config.sortList)) {	 
+									
+									// revers the sorting direction for all tables.
+									for(var j=0; j < config.sortList.length; j++) {
+										var s = config.sortList[j], o = config.headerList[s[0]];
+										if(s[0] == i) {
+											o.count = s[1];
+											o.count++;
+											s[1] = o.count % 2;
+										}
+									}	
+								} else {
+									// add column to sort list array
+									config.sortList.push([i,this.order]);
+								}
+							};
+							
+							//set css for headers
+							setHeadersCss($this[0],$headers,config.sortList,sortCSS);
+							
+							// sort the table and append it to the dom
+							appendToTable($this[0],multisort($this[0],config.sortList,cache));
+							
+							// stop normal event by returning false
+							return false;
+						}
+					// cancel selection	
+					}).mousedown(function() {
+						if(config.cancelSelection) {
+							this.onselectstart = function() {return false};
+							//alert(this.onselectstart);
+							return false;
+						}
+					});
+					
+					// apply easy methods that trigger binded events
+					$this.bind("update",function() {
+						
+						// rebuild the cache map
+						cache = buildCache(this);
+						
+					}).bind("sorton",function(e,list) {
+						
+						// update and store the sortlist
+						var sortList = config.sortList = list;
+						
+						// update header count index
+						updateHeaderSortCount(this,sortList);
+						
+						//set css for headers
+						setHeadersCss(this,$headers,sortList,sortCSS);
+						
+						// sort the table and append it to the dom
+						appendToTable(this,multisort(this,sortList,cache));
+						
+					}).bind("appendCache",function() {
+						
+						appendToTable(this,cache);
+					
+					}).bind("applyWidgetId",function(e,id) {
+						
+						getWidgetById(id).format(this);
+						
+					});
+					
+					if($.meta && ($(this).data() && $(this).data().sortlist)) {
+						config.sortList = $(this).data().sortlist;
+					}
+					// if user has supplied a sort list to constructor.
+					if(config.sortList.length > 0) {
+						$this.trigger("sorton",[config.sortList]);	
+					}
+					
+					// apply widgets
+					applyWidget(this);
+				});
+			};
+			
+			this.addParser = function(parser) {
+				var l = parsers.length, a = true;
+				for(var i=0; i < l; i++) {
+					if(parsers[i].id.toLowerCase() == parser.id.toLowerCase()) {
+						a = false;
+					}
+				}
+				if(a) { parsers.push(parser); };
+			};
+			
+			this.addWidget = function(widget) {
+				widgets.push(widget);
+			};
+			
+			this.formatFloat = function(s) {
+
+				var i = parseFloat(s);
+				return (isNaN(i)) ? 0 : i;
+			};
+			this.formatInt = function(s) {
+				var i = parseInt(s);
+				return (isNaN(i)) ? 0 : i;
+			};
+			
+		}
+	});
+	
+	// extend plugin scope
+	$.fn.extend({
+        tablesorter: $.tablesorter.construct
+	});
+	
+	// add default parsers
+	$.tablesorter.addParser({
+		id: "text",
+		is: function(s) {
+			return true;
+		},
+		format: function(s) {
+			return $.trim(s.toLowerCase());
+		},
+		type: "text"
+	});
+	
+	$.tablesorter.addParser({
+		id: "integer",
+		is: function(s) {
+			return s.match(new RegExp(/^\d+$/));
+		},
+		format: function(s) {
+			return $.tablesorter.formatInt(s);
+		},
+		type: "numeric"
+	});
+	
+	$.tablesorter.addParser({
+		id: "currency",
+		is: function(s) {
+			return /^[£$€?.]/.test(s);
+		},
+		format: function(s) {
+			return $.tablesorter.formatFloat(s.replace(new RegExp(/[^0-9.]/g),""));
+		},
+		type: "numeric"
+	});
+	
+	$.tablesorter.addParser({
+		id: "integer",
+		is: function(s) {
+			return /^\d+$/.test(s);
+		},
+		format: function(s) {
+			return $.tablesorter.formatFloat(s);
+		},
+		type: "numeric"
+	});
+	
+	$.tablesorter.addParser({
+		id: "floating",
+		is: function(s) {
+			return s.match(new RegExp(/^(\+|-)?[0-9]+\.[0-9]+((E|e)(\+|-)?[0-9]+)?$/));
+		},
+		format: function(s) {
+			return $.tablesorter.formatFloat(s.replace(new RegExp(/,/),""));
+		},
+		type: "numeric"
+	});
+	
+	$.tablesorter.addParser({
+		id: "ipAddress",
+		is: function(s) {
+			return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);
+		},
+		format: function(s) {
+			var a = s.split(".");
+			var r = "";
+			for (var i = 0, item; item = a[i]; i++) {
+			   if(item.length == 2) {
+					r += "0" + item;
+			   } else {
+					r += item;
+			   }
+			}
+			return $.tablesorter.formatFloat(s);
+		},
+		type: "numeric"
+	});
+	
+	$.tablesorter.addParser({
+		id: "url",
+		is: function(s) {
+			return /^(https?|ftp|file):\/\/$/.test(s);
+		},
+		format: function(s) {
+			return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));
+		},
+		type: "text"
+	});
+	
+	$.tablesorter.addParser({
+		id: "isoDate",
+		is: function(s) {
+			return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);
+		},
+		format: function(s) {
+			return $.tablesorter.formatFloat((s != "") ? new Date(s.replace(new RegExp(/-/g),"/")).getTime() : "0");
+		},
+		type: "numeric"
+	});
+	
+	$.tablesorter.addParser({
+		id: "percent",
+		is: function(s) {
+			return /^\d{1,3}%$/.test(s);
+		},
+		format: function(s) {
+			return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));
+		},
+		type: "numeric"
+	});
+	
+	$.tablesorter.addParser({
+		id: "usLongDate",
+		is: function(s) {
+			return /^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|\'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/.test(s);
+		},
+		format: function(s) {
+			return $.tablesorter.formatFloat(new Date(s).getTime());
+		},
+		type: "numeric"
+	});
+	
+	$.tablesorter.addParser({
+		id: "shortDate",
+		is: function(s) {
+			return /\d{1,2}[\/-]\d{1,2}[\/-]\d{2,4}/.test(s);
+		},
+		format: function(s,table) {
+			var c = table.config;
+			s = s.replace(new RegExp(/-/g),"/");
+			if(c.dateFormat == "us") {
+				/** reformat the string in ISO format */
+				s = s.replace(new RegExp(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{4})/), "$3/$1/$2");
+			} else if(c.dateFormat == "uk") {
+				/** reformat the string in ISO format */
+				s = s.replace(new RegExp(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{4})/), "$3/$2/$1");
+			} else if(c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") {
+				s = s.replace(new RegExp(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{2})/), "$1/$2/$3");	
+			}
+			return $.tablesorter.formatFloat(new Date(s).getTime());
+		},
+		type: "numeric"
+	});
+	
+	$.tablesorter.addParser({
+	    id: "time",
+	    is: function(s) {
+	        return /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);
+	    },
+	    format: function(s) {
+	        return $.tablesorter.formatFloat(new Date("2000/01/01 " + s).getTime());
+	    },
+	  type: "numeric"
+	});
+	
+	
+	$.tablesorter.addParser({
+	    id: "metadata",
+	    is: function(s) {
+	        return false;
+	    },
+	    format: function(s,table,cell) {
+			var c = table.config, p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName;
+	        return $(cell).data()[p];
+	    },
+	  type: "numeric"
+	});
+	
+	// add default widgets
+	$.tablesorter.addWidget({
+		id: "zebra",
+		format: function(table) {
+			$("> tbody:first/tr:visible:even",table).removeClass(table.config.widgetZebra.css[1]).addClass(table.config.widgetZebra.css[0]);
+			$("> tbody:first/tr:visible:odd",table).removeClass(table.config.widgetZebra.css[0]).addClass(table.config.widgetZebra.css[1]);
+		}
+	});
+	
+})(jQuery);

+ 184 - 0
global/js/tablecloth.js

@@ -0,0 +1,184 @@
+/* 
+
+	Tablecloth 
+	written by Alen Grakalic, provided by Css Globe (cssglobe.com)
+	please visit http://cssglobe.com/lab/tablecloth/
+	
+*/
+
+this.tablecloth = function(){
+	
+	// CONFIG 
+	
+	// if set to true then mouseover a table cell will highlight entire column (except sibling headings)
+	var highlightCols = true;
+	
+	// if set to true then mouseover a table cell will highlight entire row	(except sibling headings)
+	var highlightRows = true;	
+	
+	// if set to true then click on a table sell will select row or column based on config
+	var selectable = true;
+	
+	// this function is called when 
+	// add your own code if you want to add action 
+	// function receives object that has been clicked 
+	this.clickAction = function(obj){
+		//alert(obj.innerHTML);
+		
+	};
+
+
+	
+	// END CONFIG (do not edit below this line)
+	
+	
+	var tableover = false;
+	this.start = function(){
+		var tables = document.getElementsByTagName("table");
+		for (var i=0;i<tables.length;i++){
+			tables[i].onmouseover = function(){tableover = true};
+			tables[i].onmouseout = function(){tableover = false};			
+			rows(tables[i]);
+		};
+	};
+	
+	this.rows = function(table){
+		var css = "";
+		var tr = table.getElementsByTagName("tr");
+		for (var i=0;i<tr.length;i++){
+			css = (css == "odd") ? "even" : "odd";
+			tr[i].className = css;
+			var arr = new Array();
+			for(var j=0;j<tr[i].childNodes.length;j++){				
+				if(tr[i].childNodes[j].nodeType == 1) arr.push(tr[i].childNodes[j]);
+			};		
+			for (var j=0;j<arr.length;j++){				
+				arr[j].row = i;
+				arr[j].col = j;
+				if(arr[j].innerHTML == "&nbsp;" || arr[j].innerHTML == "") arr[j].className += " empty";					
+				arr[j].css = arr[j].className;
+				arr[j].onmouseover = function(){
+					over(table,this,this.row,this.col);
+				};
+				arr[j].onmouseout = function(){
+					out(table,this,this.row,this.col);
+				};
+				arr[j].onmousedown = function(){
+					down(table,this,this.row,this.col);
+				};
+				arr[j].onmouseup = function(){
+					up(table,this,this.row,this.col);
+				};				
+				arr[j].onclick = function(){
+					click(table,this,this.row,this.col);
+				};								
+			};
+		};
+	};
+	
+	// appyling mouseover state for objects (th or td)
+	this.over = function(table,obj,row,col){
+		if (!highlightCols && !highlightRows) obj.className = obj.css + " over";  
+		if(check1(obj,col)){
+			if(highlightCols) highlightCol(table,obj,col);
+			if(highlightRows) highlightRow(table,obj,row);		
+		};
+	};
+	// appyling mouseout state for objects (th or td)	
+	this.out = function(table,obj,row,col){
+		if (!highlightCols && !highlightRows) obj.className = obj.css; 
+		unhighlightCol(table,col);
+		unhighlightRow(table,row);
+	};
+	// appyling mousedown state for objects (th or td)	
+	this.down = function(table,obj,row,col){
+		obj.className = obj.css + " down";  
+	};
+	// appyling mouseup state for objects (th or td)	
+	this.up = function(table,obj,row,col){
+		obj.className = obj.css + " over";  
+	};	
+	// onclick event for objects (th or td)	
+	this.click = function(table,obj,row,col){
+		if(check1){
+			if(selectable) {
+				unselect(table);	
+				if(highlightCols) highlightCol(table,obj,col,true);
+				if(highlightRows) highlightRow(table,obj,row,true);
+				document.onclick = unselectAll;
+			}
+		};
+		clickAction(obj); 		
+	};		
+	
+	this.highlightCol = function(table,active,col,sel){
+		var css = (typeof(sel) != "undefined") ? "selected" : "over";
+		var tr = table.getElementsByTagName("tr");
+		for (var i=0;i<tr.length;i++){	
+			var arr = new Array();
+			for(j=0;j<tr[i].childNodes.length;j++){				
+				if(tr[i].childNodes[j].nodeType == 1) arr.push(tr[i].childNodes[j]);
+			};							
+			var obj = arr[col];
+			if (check2(active,obj) && check3(obj)) obj.className = obj.css + " " + css; 		
+		};
+	};
+	this.unhighlightCol = function(table,col){
+		var tr = table.getElementsByTagName("tr");
+		for (var i=0;i<tr.length;i++){
+			var arr = new Array();
+			for(j=0;j<tr[i].childNodes.length;j++){				
+				if(tr[i].childNodes[j].nodeType == 1) arr.push(tr[i].childNodes[j])
+			};				
+			var obj = arr[col];
+			if(check3(obj)) obj.className = obj.css; 
+		};
+	};	
+	this.highlightRow = function(table,active,row,sel){
+		var css = (typeof(sel) != "undefined") ? "selected" : "over";
+		var tr = table.getElementsByTagName("tr")[row];		
+		for (var i=0;i<tr.childNodes.length;i++){		
+			var obj = tr.childNodes[i];
+			if (check2(active,obj) && check3(obj)) obj.className = obj.css + " " + css; 		
+		};
+	};
+	this.unhighlightRow = function(table,row){
+		var tr = table.getElementsByTagName("tr")[row];		
+		for (var i=0;i<tr.childNodes.length;i++){
+			var obj = tr.childNodes[i];			
+			if(check3(obj)) obj.className = obj.css; 			
+		};
+	};
+	this.unselect = function(table){
+		tr = table.getElementsByTagName("tr")
+		for (var i=0;i<tr.length;i++){
+			for (var j=0;j<tr[i].childNodes.length;j++){
+				var obj = tr[i].childNodes[j];	
+				if(obj.className) obj.className = obj.className.replace("selected","");
+			};
+		};
+	};
+	this.unselectAll = function(){
+		if(!tableover){
+			tables = document.getElementsByTagName("table");
+			for (var i=0;i<tables.length;i++){
+				unselect(tables[i])
+			};		
+		};
+	};	
+	this.check1 = function(obj,col){
+		return (!(col == 0 && obj.className.indexOf("empty") != -1));
+	}
+	this.check2 = function(active,obj){
+		return (!(active.tagName == "TH" && obj.tagName == "TH")); 
+	};
+	this.check3 = function(obj){
+		return (obj.className) ? (obj.className.indexOf("selected") == -1) : true; 
+	};	
+	
+	start();
+	
+};
+
+/* script initiates on page load. */
+window.onload = tablecloth;

+ 4 - 0
global/js/zeroclipboard/.gitignore

@@ -0,0 +1,4 @@
+node_modules
+coverage
+npm-debug.log
+bin/*

+ 29 - 0
global/js/zeroclipboard/CONTRIBUTING.md

@@ -0,0 +1,29 @@
+Contributing
+==============
+
+If you find an issue, submitting a pull request is always better than a bug report! Please fork and submit your code fixes.
+
+If you want to build some new features, we have a [roadmap.md](docs/roadmap.md) of features we want. You can add features you want there, or just code the feature and send a pull request.
+
+### Cloning
+
+```sh
+$ git clone https://github.com/zeroclipboard/zeroclipboard.git
+$ cd zeroclipboard/
+$ npm install -g grunt-cli
+$ npm install
+$ grunt
+```
+
+### Developing
+
+```sh
+$ npm install
+$ grunt
+```
+
+### Testing
+
+```sh
+$ grunt test
+```

+ 332 - 0
global/js/zeroclipboard/Gruntfile.js

@@ -0,0 +1,332 @@
+/*jshint -W106 */
+/*jshint node:true, maxstatements: false, maxlen: false */
+
+var os = require("os");
+var path = require("path");
+var loadGruntTasks = require("load-grunt-tasks");
+
+module.exports = function(grunt) {
+  "use strict";
+
+  // Load necessary tasks
+  loadGruntTasks(grunt);
+
+
+  // Metadata
+  var pkg = grunt.file.readJSON("package.json");
+
+  // Make a temp dir for Flash compilation
+  var tmpDir = os.tmpdir ? os.tmpdir() : os.tmpDir();
+  var flashTmpDir = path.join(tmpDir, "zcflash");
+
+  // Shared configuration
+  var localPort = 7320;  // "ZERO"
+
+  // Project configuration.
+  var config = {
+    // Task configuration
+    jshint: {
+      options: {
+        jshintrc: true
+      },
+      gruntfile: ["Gruntfile.js"],
+      component: ["index.js"],
+      js: ["src/js/**/*.js", "!src/js/start.js", "!src/js/end.js"],
+      test: ["test/**/*.js"],
+      dist: ["dist/*.js", "!dist/*.min.js"]
+    },
+    flexpmd: {
+      flash: {
+        src: [flashTmpDir]
+      }
+    },
+    clean: {
+      dist: ["ZeroClipboard.*", "dist/ZeroClipboard.*"],
+      flash: {
+        options: {
+          // Force is required when trying to clean outside of the project dir
+          force: true
+        },
+        src: [flashTmpDir]
+      },
+      meta: ["bower.json", "composer.json", "LICENSE"],
+      coveralls: ["tmp/", "coverage/"]
+    },
+    concat: {
+      options: {
+        stripBanners: false,
+        process: {
+          data: pkg
+        }
+      },
+      core: {
+        src: [
+          "src/meta/source-banner.tmpl",
+          "src/js/start.js",
+          "src/js/shared/state.js",
+          "src/js/shared/private.js",
+          "src/js/core/state.js",
+          "src/js/core/private.js",
+          "src/js/core/api.js",
+          "src/js/end.js"
+        ],
+        dest: "dist/ZeroClipboard.Core.js"
+      },
+      client: {
+        src: [
+          "src/meta/source-banner.tmpl",
+          "src/js/start.js",
+          "src/js/shared/state.js",
+          "src/js/shared/private.js",
+          "src/js/core/state.js",
+          "src/js/core/private.js",
+          "src/js/core/api.js",
+          "src/js/client/state.js",
+          "src/js/client/private.js",
+          "src/js/client/api.js",
+          "src/js/end.js"
+        ],
+        dest: "dist/ZeroClipboard.js"
+      },
+      flash: {
+        files: [
+          {
+            src: [
+              "src/meta/source-banner.tmpl",
+              "src/flash/ZeroClipboard.as"
+            ],
+            dest: path.join(flashTmpDir, "ZeroClipboard.as")
+          },
+          {
+            src: [
+              "src/meta/source-banner.tmpl",
+              "src/flash/ClipboardInjector.as"
+            ],
+            dest: path.join(flashTmpDir, "ClipboardInjector.as")
+          },
+          {
+            src: [
+              "src/meta/source-banner.tmpl",
+              "src/flash/JsProxy.as"
+            ],
+            dest: path.join(flashTmpDir, "JsProxy.as")
+          },
+          {
+            src: [
+              "src/meta/source-banner.tmpl",
+              "src/flash/XssUtils.as"
+            ],
+            dest: path.join(flashTmpDir, "XssUtils.as")
+          }
+        ]
+      }
+    },
+    uglify: {
+      options: {
+        report: "min"
+      },
+      js: {
+        options: {
+          preserveComments: function(node, comment) {
+            return comment &&
+              comment.type === "comment2" &&
+              /^(!|\*|\*!)\r?\n/.test(comment.value);
+          },
+          beautify: {
+            beautify: true,
+            // `indent_level` requires jshint -W106
+            indent_level: 2
+          },
+          mangle: false,
+          compress: false
+        },
+        files: [
+          {
+            src: ["<%= concat.core.dest %>"],
+            dest: "<%= concat.core.dest %>"
+          },
+          {
+            src: ["<%= concat.client.dest %>"],
+            dest: "<%= concat.client.dest %>"
+          }
+        ]
+      },
+      minjs: {
+        options: {
+          preserveComments: function(node, comment) {
+            return comment &&
+              comment.type === "comment2" &&
+              /^(!|\*!)\r?\n/.test(comment.value);
+          },
+          sourceMap: true,
+          sourceMapName: function(dest) {
+            return dest.replace(".min.js", ".min.map");
+          },
+          // Bundles the contents of "`src`" into the "`dest`.map" source map file. This way,
+          // consumers only need to host the "*.min.js" and "*.min.map" files rather than
+          // needing to host all three files: "*.js", "*.min.js", and "*.min.map".
+          sourceMapIncludeSources: true
+        },
+        files: [
+          {
+            src: ["<%= concat.core.dest %>"],
+            dest: "dist/ZeroClipboard.Core.min.js"
+          },
+          {
+            src: ["<%= concat.client.dest %>"],
+            dest: "dist/ZeroClipboard.min.js"
+          }
+        ]
+      }
+    },
+    mxmlc: {
+      options: {
+        rawConfig: "-target-player=11.0.0 -static-link-runtime-shared-libraries=true"
+      },
+      swf: {
+        files: {
+          "dist/ZeroClipboard.swf": ["<%= concat.flash.files[0].dest %>"]
+        }
+      }
+    },
+    template: {
+      options: {
+        data: pkg
+      },
+      bower: {
+        files: {
+          "bower.json": ["src/meta/bower.json.tmpl"]
+        }
+      },
+      composer: {
+        files: {
+          "composer.json": ["src/meta/composer.json.tmpl"]
+        }
+      },
+      LICENSE: {
+        files: {
+          "LICENSE": ["src/meta/LICENSE.tmpl"]
+        }
+      }
+    },
+    chmod: {
+      options: {
+        mode: "444"
+      },
+      dist: ["dist/ZeroClipboard.*"],
+      meta: ["bower.json", "composer.json", "LICENSE"]
+    },
+    connect: {
+      server: {
+        options: {
+          port: localPort
+        }
+      }
+    },
+    qunit: {
+      file: [
+        "test/shared/private.tests.js.html",
+        "test/core/private.tests.js.html",
+        "test/core/api.tests.js.html",
+        "test/client/private.tests.js.html",
+        "test/client/api.tests.js.html",
+        "test/built/ZeroClipboard.Core.tests.js.html",
+        "test/built/ZeroClipboard.tests.js.html"
+        //"test/**/*.tests.js.html"
+      ],
+      http: {
+        options: {
+          urls:
+            grunt.file.expand([
+              "test/shared/private.tests.js.html",
+              "test/core/private.tests.js.html",
+              "test/core/api.tests.js.html",
+              "test/client/private.tests.js.html",
+              "test/client/api.tests.js.html",
+              "test/built/ZeroClipboard.Core.tests.js.html",
+              "test/built/ZeroClipboard.tests.js.html"
+              //"test/**/*.tests.js.html"
+            ]).map(function(testPage) {
+              return "http://localhost:" + localPort + "/" + testPage + "?noglobals=true";
+            })
+        }
+      },
+      coveralls: {
+        options: {
+          "--web-security": false,
+          timeout: 10000,
+          coverage: {
+            baseUrl: ".",
+            src: [
+              "src/js/**/*.js",
+              "!src/js/start.js",
+              "!src/js/end.js",
+              "dist/*.js",
+              "!dist/*.min.js"
+            ],
+            instrumentedFiles: "tmp",
+            htmlReport: "coverage/html",
+            lcovReport: "coverage/lcov",
+            statementsThresholdPct: 60.0,
+            disposeCollector: true
+          },
+          urls:
+            grunt.file.expand([
+              "test/shared/private.tests.js.html",
+              "test/core/private.tests.js.html",
+              "test/core/api.tests.js.html",
+              "test/client/private.tests.js.html",
+              "test/client/api.tests.js.html",
+              "test/built/ZeroClipboard.Core.tests.js.html",
+              "test/built/ZeroClipboard.tests.js.html"
+              //"test/**/*.tests.js.html"
+            ]).map(function(testPage) {
+              return "http://localhost:" + localPort + "/" + testPage + "?noglobals=true";
+            })
+        }
+      }
+    },
+    coveralls: {
+      options: {
+        force: true
+      },
+      all: {
+        src: "<%= qunit.coveralls.options.coverage.lcovReport %>/lcov.info"
+      }
+    },
+    watch: {
+      options: {
+        spawn: false
+      },
+      gruntfile: {
+        files: "<%= jshint.Gruntfile %>",
+        tasks: ["jshint:Gruntfile"]
+      },
+      js: {
+        files: "<%= jshint.js %>",
+        tasks: ["jshint:js", "unittest"]
+      },
+      test: {
+        files: "<%= jshint.test %>",
+        tasks: ["jshint:test", "unittest"]
+      }
+    }
+  };
+  grunt.initConfig(config);
+
+
+  // Task aliases and chains
+  grunt.registerTask("jshint-prebuild", ["jshint:gruntfile", "jshint:component", "jshint:js", "jshint:test"]);
+  grunt.registerTask("prep-flash",      ["clean:flash", "concat:flash"]);
+  grunt.registerTask("validate",        ["jshint-prebuild", "prep-flash", "flexpmd"]);
+  grunt.registerTask("build",           ["clean", "concat", "jshint:dist", "uglify", "mxmlc", "template", "chmod"]);
+  grunt.registerTask("build-travis",    ["clean", "concat", "jshint:dist", "mxmlc", "chmod:dist"]);
+  grunt.registerTask("test",            ["connect", "qunit:file", "qunit:http"]);
+
+  // Default task
+  grunt.registerTask("default", ["validate", "build", "test"]);
+
+  // Travis CI task
+  grunt.registerTask("travis",  ["validate", "build-travis", "test", "qunit:coveralls", "coveralls"]);
+
+};

+ 8 - 0
global/js/zeroclipboard/LICENSE

@@ -0,0 +1,8 @@
+The MIT License (MIT)
+Copyright (c) 2014 Jon Rohan, James M. Greene
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

文件差异内容过多而无法显示
+ 91 - 0
global/js/zeroclipboard/README.md


+ 17 - 0
global/js/zeroclipboard/bower.json

@@ -0,0 +1,17 @@
+{
+  "name": "zeroclipboard",
+  "description": "The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface.",
+  "version": "2.1.6",
+  "main": ["./dist/ZeroClipboard.js", "./dist/ZeroClipboard.swf"],
+  "keywords": ["flash","clipboard","copy","cut","paste","zclip","clip","clippy"],
+  "license": "https://github.com/zeroclipboard/zeroclipboard/blob/master/LICENSE",
+  "authors": [{"name":"Jon Rohan","url":"http://jonrohan.me/"},{"name":"James M. Greene","email":"james.m.greene@gmail.com","url":"http://jamesgreene.net/"}],
+  "homepage": "http://zeroclipboard.org/",
+  "repository": {"type":"git","url":"https://github.com/zeroclipboard/zeroclipboard.git"},
+  "location": "git://github.com/zeroclipboard/zeroclipboard.git",
+  "ignore": [
+    "*",
+    "!/bower.json",
+    "!/dist/**"
+  ]
+}

+ 14 - 0
global/js/zeroclipboard/composer.json

@@ -0,0 +1,14 @@
+{
+  "name": "zeroclipboard/zeroclipboard",
+  "description": "The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface.",
+  "version": "2.1.6",
+  "type": "library",
+  "keywords": ["flash","clipboard","copy","cut","paste","zclip","clip","clippy"],
+  "license": "MIT",
+  "authors": [{"name":"Jon Rohan","homepage":"http://jonrohan.me/","role":"Developer"},{"name":"James M. Greene","email":"james.m.greene@gmail.com","homepage":"http://jamesgreene.net/","role":"Developer"}],
+  "homepage": "http://zeroclipboard.org/",
+  "support": {
+    "source": "https://github.com/zeroclipboard/zeroclipboard.git",
+    "issues": "https://github.com/zeroclipboard/zeroclipboard/issues"
+  }
+}

文件差异内容过多而无法显示
+ 1788 - 0
global/js/zeroclipboard/dist/ZeroClipboard.Core.js


文件差异内容过多而无法显示
+ 10 - 0
global/js/zeroclipboard/dist/ZeroClipboard.Core.min.js


文件差异内容过多而无法显示
+ 1 - 0
global/js/zeroclipboard/dist/ZeroClipboard.Core.min.map


文件差异内容过多而无法显示
+ 2314 - 0
global/js/zeroclipboard/dist/ZeroClipboard.js


文件差异内容过多而无法显示
+ 10 - 0
global/js/zeroclipboard/dist/ZeroClipboard.min.js


文件差异内容过多而无法显示
+ 1 - 0
global/js/zeroclipboard/dist/ZeroClipboard.min.map


二进制
global/js/zeroclipboard/dist/ZeroClipboard.swf


+ 716 - 0
global/js/zeroclipboard/docs/api/ZeroClipboard.Core.md

@@ -0,0 +1,716 @@
+# ZeroClipboard.Core API
+
+This documents details the **ZeroClipboard.Core** API, including various types of properties, methods, and events. **ZeroClipboard.Core** is primarily intended for use in wrapping ZeroClipboard in 3rd party plugins, e.g. [jquery.zeroclipboard](https://github.com/zeroclipboard/jquery.zeroclipboard).
+
+
+## Static
+
+### Static Properties
+
+#### `ZeroClipboard.version`
+
+_[`String`]_ The version of the ZeroClipboard library being used, e.g. `"2.0.0"`.
+
+
+### Static Methods
+
+#### `ZeroClipboard.config(...)`
+
+```js
+var config = ZeroClipboard.config();
+```
+
+_[`Object`]_ Get a copy of the active configuration for ZeroClipboard.
+
+
+```js
+var swfPath = ZeroClipboard.config("swfPath");
+```
+
+_[`*`]_ Get a copy of the actively configured value for this configuration property for ZeroClipboard.
+
+
+```js
+var config = ZeroClipboard.config({
+  forceHandCursor: true
+});
+```
+
+_[`Object`]_ Set the active configuration for ZeroClipboard. Returns a copy of the updated active configuration. For complete details about what can be configured, see [**Configuration Options** below](#configuration-options).
+
+
+#### `ZeroClipboard.create()`
+_[`undefined`]_ Create the Flash bridge SWF object.
+
+
+#### `ZeroClipboard.destroy()`
+_[`undefined`]_ Emit the [`"destroy"`](#destroy) event, remove all event handlers, and destroy the Flash bridge.
+
+
+#### `ZeroClipboard.setData(...)`
+
+```js
+ZeroClipboard.setData("text/plain", "Blah");
+```
+
+_[`undefined`]_ Set the pending `data` of type `format` for clipboard injection.
+
+```js
+ZeroClipboard.setData({
+  "text/plain": "Blah",
+  "text/html": "<b>Blah</b>"
+});
+```
+
+_[`undefined`]_ Set the pending `data` of various formats for clipboard injection.
+
+
+#### `ZeroClipboard.clearData(...)`
+
+```js
+ZeroClipboard.clearData("text/plain");
+```
+
+_[`undefined`]_ Clear the pending data of type `format` for clipboard injection.
+
+```js
+ZeroClipboard.clearData();
+```
+
+_[`undefined`]_ Clear the pending data of ALL formats for clipboard injection.
+
+
+#### `ZeroClipboard.getData(...)`
+
+```js
+var text = ZeroClipboard.getData("text/plain");
+```
+
+_[`String`]_ Get the pending data of type `format` for clipboard injection.
+
+```js
+var dataObj = ZeroClipboard.getData();
+```
+
+_[`Object`]_ Get a copy of the pending data of ALL formats for clipboard injection.
+
+
+#### `ZeroClipboard.focus(...)`
+#### `ZeroClipboard.activate(...)`
+
+```js
+ZeroClipboard.focus(document.getElementById("d_clip_button"));
+```
+
+_[`undefined`]_ Focus/"activate" the provided element by moving the Flash SWF object in front of it. **NOTE:** The preferred method to use is `focus` but the alias `activate` is available for backward compatibility's sake.
+
+
+#### `ZeroClipboard.blur()`
+#### `ZeroClipboard.deactivate()`
+
+_[`undefined`]_ Blur/"deactivate" the currently focused/"activated" element, moving the Flash SWF object off the screen. **NOTE:** The preferred method to use is `blur` but the alias `deactivate` is available for backward compatibility's sake.
+
+
+#### `ZeroClipboard.activeElement()`
+
+```js
+var el = document.getElementById("d_clip_button");
+ZeroClipboard.focus(el);
+var activeEl = ZeroClipboard.activeElement();  // activeEl === el
+```
+
+_[`HTMLElement` or `null`]_ Return the currently "activated" element that the Flash SWF object is in front of it.
+
+
+#### `ZeroClipboard.state()`
+
+_[`Object`]_ Diagnostic method that describes the state of the browser, Flash Player, and ZeroClipboard.
+
+
+#### `ZeroClipboard.isFlashUnavailable()`
+
+_[`Boolean`]_ Indicates if Flash Player is **definitely** unusable (disabled, outdated, unavailable, or deactivated). _**IMPORTANT:**_ This method should be considered private.
+
+
+#### `ZeroClipboard.on(...)`
+
+```js
+var listenerFn = function(e) { var ZeroClipboard = this; /* ... */ };
+ZeroClipboard.on("ready", listenerFn);
+
+var listenerObj = {
+  handleEvent: function(e) { var listenerObj = this; /* ... */ }
+};
+ZeroClipboard.on("error", listenerObj);
+```
+
+_[`undefined`]_ Add a `listener` function/object for an `eventType`.
+
+```js
+ZeroClipboard.on("ready error", function(e) { /* ... */ });
+```
+
+_[`undefined`]_ Add a `listener` function/object for multiple `eventType`s.
+
+```js
+ZeroClipboard.on({
+  "ready": function(e) { /* ... */ },
+  "error": function(e) { /* ... */ }
+});
+```
+
+_[`undefined`]_ Add a set of `eventType` to `listener` function/object mappings.
+
+
+#### `ZeroClipboard.off(...)`
+
+```js
+ZeroClipboard.off("ready", listenerFn);
+ZeroClipboard.off("error", listenerObj);
+```
+
+_[`undefined`]_ Remove a `listener` function/object for an `eventType`.
+
+```js
+ZeroClipboard.off("ready error", listenerFn);
+```
+
+_[`undefined`]_ Remove a `listener` function/object for multiple `eventType`s.
+
+```js
+ZeroClipboard.off({
+  "ready": readyListenerFn,
+  "error": errorListenerFn
+});
+```
+
+_[`undefined`]_ Remove a set of `eventType` to `listener` function/object mappings.
+
+```js
+ZeroClipboard.off("ready");
+```
+
+_[`undefined`]_ Remove ALL listener functions/objects for an `eventType`.
+
+```js
+ZeroClipboard.off();
+```
+
+_[`undefined`]_ Remove ALL listener functions/objects for ALL registered event types.
+
+
+#### `ZeroClipboard.emit(...)`
+
+```js
+ZeroClipboard.emit("ready");
+ZeroClipboard.emit({
+  type: "error",
+  name: "flash-disabled"
+});
+
+var pendingCopyData = ZeroClipboard.emit("copy");
+```
+
+_[`undefined`, or a Flash-friendly data Object for the `"copy"` event]_ Dispatch an event to all
+registered listeners. The emission of some types of events will result in side effects.
+
+
+#### `ZeroClipboard.handlers()`
+
+```js
+var listeners = ZeroClipboard.handlers("ready");
+```
+
+_[`Array`]_ Retrieves a copy of the registered listener functions/objects for the given `eventType`.
+
+
+```js
+var listeners = ZeroClipboard.handlers();
+```
+
+_[`Object`]_ Retrieves a copy of the map of registered listener functions/objects for ALL event types.
+
+
+
+### Static Events
+
+#### `"ready"`
+
+The `ready` event is fired when the Flash SWF completes loading and is ready for action.  Please
+note that you need to set most configuration options [with [`ZeroClipboard.config(...)`](#zeroclipboardconfig)]
+before `ZeroClipboard.create()` is invoked.
+
+```js
+ZeroClipboard.on("ready", function(e) {
+/*
+  e = {
+    type: "ready",
+    message: "Flash communication is established",
+    target: null,
+    relatedTarget: null,
+    currentTarget: flashSwfObjectRef,
+    version: "11.2.202",
+    timeStamp: Date.now()
+  };
+*/
+});
+```
+
+
+#### `"beforecopy"`
+
+On `click`, the Flash object will fire off a `beforecopy` event. This event is generally only
+used for "UI prepartion" if you want to alter anything before the `copy` event fires.
+
+**IMPORTANT:** Handlers of this event are expected to operate synchronously if they intend to be
+finished before the "copy" event is triggered.
+
+```js
+ZeroClipboard.on("beforecopy", function(e) {
+/*
+  e = {
+    type: "beforecopy",
+    target: currentlyActivatedElementOrNull,
+    relatedTarget: dataClipboardElementTargetOfCurrentlyActivatedElementOrNull,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now()
+  };
+*/
+});
+```
+
+
+#### `"copy"`
+
+On `click` (and after the `beforecopy` event), the Flash object will fire off a `copy` event. If
+the HTML object has `data-clipboard-text` or `data-clipboard-target`, then ZeroClipboard will take
+care of getting an initial set of data. It will then invoke any `copy` event handlers, in which you
+can call `event.clipboardData.setData` to set the text, which will complete the loop.
+
+**IMPORTANT:** If a handler of this event intends to modify the pending data for clipboard
+injection, it _MUST_ operate synchronously in order to maintain the temporarily elevated
+permissions granted by the user's `click` event. The most common "gotcha" for this restriction is
+if someone wants to make an asynchronous XMLHttpRequest in response to the `copy` event to get the
+data to inject &mdash; this won't work; make it a _synchronous_ XMLHttpRequest instead, or do the
+work in advance before the `copy` event is fired.
+
+```js
+ZeroClipboard.on("copy", function(e) {
+/*
+  e = {
+    type: "copy",
+    target: currentlyActivatedElementOrNull,
+    relatedTarget: dataClipboardElementTargetOfCurrentlyActivatedElementOrNull,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now(),
+    clipboardData: {
+      setData: ZeroClipboard.setData,
+      clearData: ZeroClipboard.clearData
+    }
+  };
+*/
+});
+```
+
+
+#### `"aftercopy"`
+
+The `aftercopy` event is fired when the text is copied [or failed to copy] to the clipboard.
+
+```js
+ZeroClipboard.on("aftercopy", function(e) {
+/*
+  e = {
+    type: "aftercopy",
+    target: currentlyActivatedElementOrNull,
+    relatedTarget: dataClipboardElementTargetOfCurrentlyActivatedElementOrNull,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now(),
+    success: {
+      "text/plain": true,
+      "text/html": true,
+      "application/rtf": false
+    },
+    data: {
+      "text/plain": "Blah",
+      "text/html": "<b>Blah</b>",
+      "application/rtf": "{\\rtf1\\ansi\n{\\b Blah}}"
+    }
+  };
+*/
+});
+```
+
+
+#### `"destroy"`
+
+The `destroy` event is fired when `ZeroClipboard.destroy()` is invoked.
+
+**IMPORTANT:** Handlers of this event are expected to operate synchronously if they intend to be
+finished before the destruction is complete.
+
+```js
+ZeroClipboard.on("destroy", function(e) {
+/*
+  e = {
+    type: "destroy",
+    target: null,
+    relatedTarget: null,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now(),
+    success: {
+      "text/plain": true,
+      "text/html": true,
+      "application/rtf": false
+    },
+    data: {
+      "text/plain": "Blah",
+      "text/html": "<b>Blah</b>",
+      "application/rtf": "{\\rtf1\\ansi\n{\\b Blah}}"
+    }
+  };
+*/
+});
+```
+
+
+#### `"error"`
+
+The `error` event is fired under a number of conditions, which will be detailed as sub-sections below.
+
+Some consumers may not consider all `error` types to be critical, and thus ZeroClipboard does not take it upon
+itself to implode by calling `ZeroClipboard.destroy()` under error conditions.  However, many consumers may
+want to do just that.
+
+
+##### `error[name = "flash-disabled"]`
+
+This type of `error` event fires when Flash Player is either not installed or not enabled in the browser.
+
+```js
+ZeroClipboard.on("error", function(e) {
+/*
+  e = {
+    type: "error",
+    name: "flash-disabled",
+    messsage: "Flash is disabled or not installed",
+    target: null,
+    relatedTarget: null,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now(),
+    minimumVersion: "11.0.0"
+  };
+*/
+});
+```
+
+
+##### `error[name = "flash-outdated"]`
+
+This type of `error` event fires when Flash Player is installed in the browser but the version is too old
+for ZeroClipboard. ZeroClipboard requires Flash Player 11.0.0 or above.
+
+```js
+ZeroClipboard.on("error", function(e) {
+/*
+  e = {
+    type: "error",
+    name: "flash-outdated",
+    messsage: "Flash is too outdated to support ZeroClipboard",
+    target: null,
+    relatedTarget: null,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now(),
+    minimumVersion: "11.0.0",
+    version: "10.3.183"
+  };
+*/
+});
+```
+
+
+##### `error[name = "flash-unavailable"]`
+
+This type of `error` event fires when the browser's installation of Flash Player cannot communicate bidirectionally with JavaScript.
+
+```js
+ZeroClipboard.on("error", function(e) {
+/*
+  e = {
+    type: "error",
+    name: "flash-unavailable",
+    messsage: "Flash is unable to communicate bidirectionally with JavaScript",
+    target: null,
+    relatedTarget: null,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now(),
+    minimumVersion: "11.0.0",
+    version: "11.2.202"
+  };
+*/
+});
+```
+
+
+##### `error[name = "flash-deactivated"]`
+
+This type of `error` event fires when the browser's installation of Flash Player is either too old
+for the browser [but _not_ too old for ZeroClipboard] or if Flash objects are configured as
+click-to-play and the user does not authorize it within `_globalConfig.flashLoadTimeout`
+milliseconds or does not authorize it at all.
+
+```js
+ZeroClipboard.on("error", function(e) {
+/*
+  e = {
+    type: "error",
+    name: "flash-deactivated",
+    messsage: "Flash is too outdated for your browser and/or is configured as click-to-activate",
+    target: null,
+    relatedTarget: null,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now(),
+    minimumVersion: "11.0.0",
+    version: "11.2.202"
+  };
+*/
+});
+```
+
+
+##### `error[name = "flash-overdue"]`
+
+This type of `error` event fires when the SWF loads successfully but takes longer than
+`_globalConfig.flashLoadTimeout` milliseconds to do so. This would likely be caused by
+one of the following situations:
+ 1. Too short of a `_globalConfig.flashLoadTimeout` duration configured
+ 2. Network latency
+ 3. The user's installation of Flash is configured as click-to-play but then authorized
+    by the user too late such that the SWF does not finish loading before the timeout
+    period has expired (or it may have expired before they authorized it at all).
+
+The appropriate response to this event is left up to the consumer. For instance, if they
+chose to invoke `ZeroClipboard.destroy()` in response to the earlier
+`error[name = "flash-deactivated"]` event but then receive this `error[name = "flash-overdue"]`
+event, they may choose to "restart" their process and construct new ZeroClipboard client instances,
+or they may choose to just log the error to their server so they can consider increasing the
+allowed timeout duration in the future.
+
+This may be especially important for SPA or PJAX-based applications to consider as their users
+may remain on a single page for an extended period of time during which they _possibly_ could
+have enjoyed an improved experience if ZeroClipboard had been "restarted" after an initial hiccup.
+
+```js
+ZeroClipboard.on("error", function(e) {
+/*
+  e = {
+    type: "error",
+    name: "flash-overdue",
+    messsage: "Flash communication was established but NOT within the acceptable time limit",
+    target: null,
+    relatedTarget: null,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now(),
+    minimumVersion: "11.0.0",
+    version: "11.2.202"
+  };
+*/
+});
+```
+
+
+
+## Configuration Options
+
+These are default values for the global configurations options. You should generally update these _before_ you create your clients.
+
+```js
+var _globalConfig = {
+
+  // SWF URL, relative to the page. Default value will be "ZeroClipboard.swf"
+  // under the same path as the ZeroClipboard JS file.
+  swfPath: _swfPath,
+
+  // SWF inbound scripting policy: page domains that the SWF should trust.
+  // (single string, or array of strings)
+  trustedDomains: window.location.host ? [window.location.host] : [],
+
+  // Include a "noCache" query parameter on requests for the SWF.
+  cacheBust: true,
+
+  // Enable use of the fancy "Desktop" clipboard, even on Linux where it is
+  // known to suck.
+  forceEnhancedClipboard: false,
+
+  // How many milliseconds to wait for the Flash SWF to load and respond before assuming that
+  // Flash is deactivated (e.g. click-to-play) in the user's browser. If you don't care about
+  // how long it takes to load the SWF, you can set this to `null`.
+  flashLoadTimeout: 30000,
+
+  // Setting this to `false` would allow users to handle calling `ZeroClipboard.focus(...);`
+  // themselves instead of relying on our per-element `mouseover` handler.
+  autoActivate: true,
+
+  // Bubble synthetic events in JavaScript after they are received by the Flash object.
+  bubbleEvents: true,
+
+  // Sets the ID of the `div` encapsulating the Flash object.
+  // Value is validated against the [HTML4 spec for `ID` tokens][valid_ids].
+  containerId: "global-zeroclipboard-html-bridge",
+ 
+  // Sets the class of the `div` encapsulating the Flash object.
+  containerClass: "global-zeroclipboard-container",
+ 
+  // Sets the ID and name of the Flash `object` element.
+  // Value is validated against the [HTML4 spec for `ID` and `Name` tokens][valid_ids].
+  swfObjectId: "global-zeroclipboard-flash-bridge",
+
+  // The class used to indicate that a clipped element is being hovered over.
+  hoverClass: "zeroclipboard-is-hover",
+
+  // The class used to indicate that a clipped element is active (is being clicked).
+  activeClass: "zeroclipboard-is-active",
+
+
+
+  // Forcibly set the hand cursor ("pointer") for all clipped elements.
+  // IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
+  forceHandCursor: false,
+
+  // Sets the title of the `div` encapsulating the Flash object.
+  // IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
+  title: null,
+
+  // The z-index used by the Flash object.
+  // Max value (32-bit): 2147483647.
+  // IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
+  zIndex: 999999999
+
+};
+```
+
+You can override the defaults by making calls like `ZeroClipboard.config({ swfPath: "new/path" });`
+before you create any clients.
+
+
+### SWF Inbound Scripting Access: The `trustedDomains` option
+
+This allows other SWF files and HTML pages from the allowed domains to access/call publicly
+exposed ActionScript code, e.g. functions shared via `ExternalInterface.addCallback`. In other
+words, it controls the SWF inbound scripting access.
+
+If your ZeroClipboard SWF is served from a different origin/domain than your page, you need to tell
+the SWF that it's OK to trust your page. The default value of `[window.location.host]` is almost
+_**always**_ what you will want unless you specifically want the SWF to communicate with pages from
+other domains (e.g. in `iframe`s or child windows).
+
+For more information about trusted domains, consult the [_official Flash documentation for `flash.system.Security.allowDomain(...)`_](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/Security.html#allowDomain\(\)).
+
+
+### SWF Outbound Scripting Access
+
+The `allowScriptAccess` parameter (for Flash embedding markup) allows the SWF file to access/call
+JavaScript/HTML functionality of HTML pages on allowed domains, e.g. invoking functions via
+`ExternalInterface.call`. In other words, it controls the SWF outbound scripting access.
+
+As of version `v2.0.0-alpha.2`, the `allowScriptAccess` configuration option no longer exists. The
+appropriate value will be determined immediately before the Flash object is embedded on the page.
+The value is based on a relationship between the current domain (`window.location.host`) and the
+value of the `trustedDomains` configuration option.
+
+For more information about `allowScriptAccess`, consult the [_official Flash documentation_](http://helpx.adobe.com/flash/kb/control-access-scripts-host-web.html).
+
+
+### Cross-Protocol Limitations
+
+ZeroClipboard was intentionally configured to _not_ allow the SWF to be served from a secure domain (HTTPS) but scripted by an insecure domain (HTTP).
+
+If you find yourself in this situation (as in [Issue #170](https://github.com/zeroclipboard/zeroclipboard/issues/170)), please consider the following options:  
+ 1. Serve the SWF over HTTP instead of HTTPS. If the page's protocol can vary (e.g. authorized/unauthorized, staging/production, etc.), you should include add the SWF with a relative protocol (`//s3.amazonaws.com/blah/ZeroClipboard.swf`) instead of an absolute protocol (`https://s3.amazonaws.com/blah/ZeroClipboard.swf`).
+ 2. Serve the page over HTTPS instead of HTTP. If the page's protocol can vary, see the note on the previous option (1).
+ 3. Update ZeroClipboard's ActionScript codebase to call the [`allowInsecureDomain`](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/Security.html#allowInsecureDomain\(\)) method, then recompile the SWF with your custom changes.
+
+
+### `file://` Protocol Limitations
+
+If you want to host a page locally on the `file://` protocol, you must specifically configure
+ZeroClipboard to trust ALL domains for SWF interaction via a wildcard. This configuration must be
+set _before_ creating ZeroClipboard client instances as a typical consumer, or before calling
+`ZeroClipboard.create()` in a 3rd party wrapper:
+
+```js
+ZeroClipboard.config({ trustedDomains: ["*"] });
+```
+
+This wildcard configuration should _**NOT**_ be used in environments hosted over HTTP/HTTPS.
+
+
+## Extending `ZeroClipboard`
+
+For developers who want to wrap ZeroClipboard into a 3rd party plugin
+(e.g. [jquery.zeroclipboard](https://github.com/zeroclipboard/jquery.zeroclipboard)), here
+are the important extension points:
+
+
+### Constructor
+
+Although the root `ZeroClipboard` function itself is actually a constructor, it also contains a
+particular hook that checks for the existence of a `ZeroClipboard._createClient` static function
+and invokes it with `this` (the freshly created `ZeroClipboard` instance) as the context and passes
+along all provided arguments to the constructor function, e.g.:
+
+```js
+var counterId = 0;
+ZeroClipboard._createClient = function(elements, otherStuff, etc) {
+  this.id = "" + (counterId++);
+  /* ... */
+};
+
+var $elementsToOperateOn = $(".clip_button");
+
+var client = new ZeroClipboard($elementsToOperateOn);
+```
+
+
+### Prototype Chain
+
+Using the `ZeroClipboard` constructor will allow you to also extend the underlying prototype with
+new instance-based methods, e.g.:
+
+```js
+ZeroClipboard.prototype.clientEmitOrSomeOtherOperationToInvoke = function(e) {
+  e.client = this;
+};
+```
+
+
+### Eventing
+
+Most clients will want to listen for some or all of the `ZeroClipboard.Core` events, and some
+clients will even want to regurgitate the same events to their own client-based listeners. To
+make the latter easier, `ZeroClipboard.Core` will also allow you to add a listener to an
+`eventType` of `"*"`, e.g.:
+
+```js
+ZeroClipboard._createClient = function() {
+  var client = this;
+  ZeroClipboard.on("*", function(e) {
+    client.clientEmitOrSomeOtherOperationToInvoke(e);
+  });
+};
+```
+
+
+### Static Extension
+
+The `ZeroClipboard.Core` API is composed of static methods stored as properties of the
+root `ZeroClipboard` function. As such, additional static methods can be added as desired, if there
+is any actual benefit to doing so, e.g.:
+
+```js
+ZeroClipboard.log = function() {
+  if (typeof console !== "undefined" && console.log) {
+    console.log.apply(console, Array.prototype.slice.call(arguments, 0));
+  }
+};
+```

+ 892 - 0
global/js/zeroclipboard/docs/api/ZeroClipboard.md

@@ -0,0 +1,892 @@
+# ZeroClipboard API
+
+This documents details the ZeroClipboard API, including various types of properties, methods, and events.
+
+
+## Static
+
+### Static Properties
+
+#### `ZeroClipboard.version`
+
+_[`String`]_ The version of the ZeroClipboard library being used, e.g. `"2.0.0"`.
+
+
+### Static Methods
+
+#### `ZeroClipboard.config(...)`
+
+```js
+var config = ZeroClipboard.config();
+```
+
+_[`Object`]_ Get a copy of the active configuration for ZeroClipboard.
+
+
+```js
+var swfPath = ZeroClipboard.config("swfPath");
+```
+
+_[`*`]_ Get a copy of the actively configured value for this configuration property for ZeroClipboard.
+
+
+```js
+var config = ZeroClipboard.config({
+  forceHandCursor: true
+});
+```
+
+_[`Object`]_ Set the active configuration for ZeroClipboard. Returns a copy of the updated active configuration. For complete details about what can be configured, see [**Configuration Options** below](#configuration-options).
+
+
+#### `ZeroClipboard.create()`
+_[`undefined`]_ Create the Flash bridge SWF object. _**IMPORTANT:**_ This method should be considered private.
+
+
+#### `ZeroClipboard.destroy()`
+_[`undefined`]_ Emit the [`"destroy"`](#destroy) event, remove all event handlers, and destroy the Flash bridge.
+
+
+#### `ZeroClipboard.setData(...)`
+
+```js
+ZeroClipboard.setData("text/plain", "Blah");
+```
+
+_[`undefined`]_ Set the pending `data` of type `format` for clipboard injection.
+
+```js
+ZeroClipboard.setData({
+  "text/plain": "Blah",
+  "text/html": "<b>Blah</b>"
+});
+```
+
+_[`undefined`]_ Set the pending `data` of various formats for clipboard injection.
+
+
+#### `ZeroClipboard.clearData(...)`
+
+```js
+ZeroClipboard.clearData("text/plain");
+```
+
+_[`undefined`]_ Clear the pending data of type `format` for clipboard injection.
+
+```js
+ZeroClipboard.clearData();
+```
+
+_[`undefined`]_ Clear the pending data of ALL formats for clipboard injection.
+
+
+#### `ZeroClipboard.getData(...)`
+
+```js
+var text = ZeroClipboard.getData("text/plain");
+```
+
+_[`String`]_ Get the pending data of type `format` for clipboard injection.
+
+```js
+var dataObj = ZeroClipboard.getData();
+```
+
+_[`Object`]_ Get a copy of the pending data of ALL formats for clipboard injection.
+
+
+#### `ZeroClipboard.focus(...)`
+#### `ZeroClipboard.activate(...)`
+
+```js
+ZeroClipboard.focus(document.getElementById("d_clip_button"));
+```
+
+_[`undefined`]_ Focus/"activate" the provided element by moving the Flash SWF object in front of it. **NOTE:** The preferred method to use is `focus` but the alias `activate` is available for backward compatibility's sake.
+
+
+#### `ZeroClipboard.blur()`
+#### `ZeroClipboard.deactivate()`
+
+_[`undefined`]_ Blur/"deactivate" the currently focused/"activated" element, moving the Flash SWF object off the screen. **NOTE:** The preferred method to use is `blur` but the alias `deactivate` is available for backward compatibility's sake.
+
+
+#### `ZeroClipboard.activeElement()`
+
+```js
+var el = document.getElementById("d_clip_button");
+ZeroClipboard.focus(el);
+var activeEl = ZeroClipboard.activeElement();  // activeEl === el
+```
+
+_[`HTMLElement` or `null`]_ Return the currently "activated" element that the Flash SWF object is in front of it.
+
+
+#### `ZeroClipboard.state()`
+
+_[`Object`]_ Diagnostic method that describes the state of the browser, Flash Player, and ZeroClipboard.
+
+
+#### `ZeroClipboard.isFlashUnavailable()`
+
+_[`Boolean`]_ Indicates if Flash Player is **definitely** unusable (disabled, outdated, unavailable, or deactivated). _**IMPORTANT:**_ This method should be considered private.
+
+
+#### `ZeroClipboard.on(...)`
+
+```js
+var listenerFn = function(e) { var ZeroClipboard = this; /* ... */ };
+ZeroClipboard.on("ready", listenerFn);
+
+var listenerObj = {
+  handleEvent: function(e) { var listenerObj = this; /* ... */ }
+};
+ZeroClipboard.on("error", listenerObj);
+```
+
+_[`undefined`]_ Add a `listener` function/object for an `eventType`.
+
+```js
+ZeroClipboard.on("ready error", function(e) { /* ... */ });
+```
+
+_[`undefined`]_ Add a `listener` function/object for multiple `eventType`s.
+
+```js
+ZeroClipboard.on({
+  "ready": function(e) { /* ... */ },
+  "error": function(e) { /* ... */ }
+});
+```
+
+_[`undefined`]_ Add a set of `eventType` to `listener` function/object mappings.
+
+
+#### `ZeroClipboard.off(...)`
+
+```js
+ZeroClipboard.off("ready", listenerFn);
+ZeroClipboard.off("error", listenerObj);
+```
+
+_[`undefined`]_ Remove a `listener` function/object for an `eventType`.
+
+```js
+ZeroClipboard.off("ready error", listenerFn);
+```
+
+_[`undefined`]_ Remove a `listener` function/object for multiple `eventType`s.
+
+```js
+ZeroClipboard.off({
+  "ready": readyListenerFn,
+  "error": errorListenerFn
+});
+```
+
+_[`undefined`]_ Remove a set of `eventType` to `listener` function/object mappings.
+
+```js
+ZeroClipboard.off("ready");
+```
+
+_[`undefined`]_ Remove ALL listener functions/objects for an `eventType`.
+
+```js
+ZeroClipboard.off();
+```
+
+_[`undefined`]_ Remove ALL listener functions/objects for ALL registered event types.
+
+
+#### `ZeroClipboard.emit(...)`
+
+```js
+ZeroClipboard.emit("ready");
+ZeroClipboard.emit({
+  type: "error",
+  name: "flash-disabled"
+});
+
+var pendingCopyData = ZeroClipboard.emit("copy");
+```
+
+_[`undefined`, or a Flash-friendly data `Object` for the `"copy"` event]_ Dispatch an event to all
+registered listeners. The emission of some types of events will result in side effects.
+
+
+#### `ZeroClipboard.handlers(...)`
+
+```js
+var listeners = ZeroClipboard.handlers("ready");
+```
+
+_[`Array`]_ Retrieves a copy of the registered listener functions/objects for the given `eventType`.
+
+
+```js
+var listeners = ZeroClipboard.handlers();
+```
+
+_[`Object`]_ Retrieves a copy of the map of registered listener functions/objects for ALL event types.
+
+
+
+### Static Events
+
+#### `"ready"`
+
+The `ready` event is fired when the Flash SWF completes loading and is ready for action.  Please
+note that you need to set most configuration options [with [`ZeroClipboard.config(...)`](#zeroclipboardconfig)]
+before `ZeroClipboard.create()` is invoked.
+
+```js
+ZeroClipboard.on("ready", function(e) {
+/*
+  e = {
+    type: "ready",
+    message: "Flash communication is established",
+    target: null,
+    relatedTarget: null,
+    currentTarget: flashSwfObjectRef,
+    version: "11.2.202",
+    timeStamp: Date.now()
+  };
+*/
+});
+```
+
+
+#### `"beforecopy"`
+
+On `click`, the Flash object will fire off a `beforecopy` event. This event is generally only
+used for "UI prepartion" if you want to alter anything before the `copy` event fires.
+
+**IMPORTANT:** Handlers of this event are expected to operate synchronously if they intend to be
+finished before the "copy" event is triggered.
+
+```js
+ZeroClipboard.on("beforecopy", function(e) {
+/*
+  e = {
+    type: "beforecopy",
+    target: currentlyActivatedElementOrNull,
+    relatedTarget: dataClipboardElementTargetOfCurrentlyActivatedElementOrNull,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now()
+  };
+*/
+});
+```
+
+
+#### `"copy"`
+
+On `click` (and after the `beforecopy` event), the Flash object will fire off a `copy` event. If
+the HTML object has `data-clipboard-text` or `data-clipboard-target`, then ZeroClipboard will take
+care of getting an initial set of data. It will then invoke any `copy` event handlers, in which you
+can call `event.clipboardData.setData` to set the text, which will complete the loop.
+
+**IMPORTANT:** If a handler of this event intends to modify the pending data for clipboard
+injection, it _MUST_ operate synchronously in order to maintain the temporarily elevated
+permissions granted by the user's `click` event. The most common "gotcha" for this restriction is
+if someone wants to make an asynchronous XMLHttpRequest in response to the `copy` event to get the
+data to inject &mdash; this won't work; make it a _synchronous_ XMLHttpRequest instead, or do the
+work in advance before the `copy` event is fired.
+
+```js
+ZeroClipboard.on("copy", function(e) {
+/*
+  e = {
+    type: "copy",
+    target: currentlyActivatedElementOrNull,
+    relatedTarget: dataClipboardElementTargetOfCurrentlyActivatedElementOrNull,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now(),
+    clipboardData: {
+      setData: ZeroClipboard.setData,
+      clearData: ZeroClipboard.clearData
+    }
+  };
+*/
+});
+```
+
+
+#### `"aftercopy"`
+
+The `aftercopy` event is fired when the text is copied [or failed to copy] to the clipboard.
+
+```js
+ZeroClipboard.on("aftercopy", function(e) {
+/*
+  e = {
+    type: "aftercopy",
+    target: currentlyActivatedElementOrNull,
+    relatedTarget: dataClipboardElementTargetOfCurrentlyActivatedElementOrNull,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now(),
+    success: {
+      "text/plain": true,
+      "text/html": true,
+      "application/rtf": false
+    },
+    data: {
+      "text/plain": "Blah",
+      "text/html": "<b>Blah</b>",
+      "application/rtf": "{\\rtf1\\ansi\n{\\b Blah}}"
+    }
+  };
+*/
+});
+```
+
+
+#### `"destroy"`
+
+The `destroy` event is fired when `ZeroClipboard.destroy()` is invoked.
+
+**IMPORTANT:** Handlers of this event are expected to operate synchronously if they intend to be
+finished before the destruction is complete.
+
+```js
+ZeroClipboard.on("destroy", function(e) {
+/*
+  e = {
+    type: "destroy",
+    target: null,
+    relatedTarget: null,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now(),
+    success: {
+      "text/plain": true,
+      "text/html": true,
+      "application/rtf": false
+    },
+    data: {
+      "text/plain": "Blah",
+      "text/html": "<b>Blah</b>",
+      "application/rtf": "{\\rtf1\\ansi\n{\\b Blah}}"
+    }
+  };
+*/
+});
+```
+
+
+#### `"error"`
+
+The `error` event is fired under a number of conditions, which will be detailed as sub-sections below.
+
+Some consumers may not consider all `error` types to be critical, and thus ZeroClipboard does not take it upon
+itself to implode by calling `ZeroClipboard.destroy()` under error conditions.  However, many consumers may
+want to do just that.
+
+
+##### `error[name = "flash-disabled"]`
+
+This type of `error` event fires when Flash Player is either not installed or not enabled in the browser.
+
+```js
+ZeroClipboard.on("error", function(e) {
+/*
+  e = {
+    type: "error",
+    name: "flash-disabled",
+    messsage: "Flash is disabled or not installed",
+    target: null,
+    relatedTarget: null,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now(),
+    minimumVersion: "11.0.0"
+  };
+*/
+});
+```
+
+
+##### `error[name = "flash-outdated"]`
+
+This type of `error` event fires when Flash Player is installed in the browser but the version is too old
+for ZeroClipboard. ZeroClipboard requires Flash Player 11.0.0 or above.
+
+```js
+ZeroClipboard.on("error", function(e) {
+/*
+  e = {
+    type: "error",
+    name: "flash-outdated",
+    messsage: "Flash is too outdated to support ZeroClipboard",
+    target: null,
+    relatedTarget: null,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now(),
+    minimumVersion: "11.0.0",
+    version: "10.3.183"
+  };
+*/
+});
+```
+
+
+##### `error[name = "flash-unavailable"]`
+
+This type of `error` event fires when the browser's installation of Flash Player cannot communicate bidirectionally with JavaScript.
+
+```js
+ZeroClipboard.on("error", function(e) {
+/*
+  e = {
+    type: "error",
+    name: "flash-unavailable",
+    messsage: "Flash is unable to communicate bidirectionally with JavaScript",
+    target: null,
+    relatedTarget: null,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now(),
+    minimumVersion: "11.0.0",
+    version: "11.2.202"
+  };
+*/
+});
+```
+
+
+##### `error[name = "flash-deactivated"]`
+
+This type of `error` event fires when the browser's installation of Flash Player is either too old
+for the browser [but _not_ too old for ZeroClipboard] or if Flash objects are configured as
+click-to-play and the user does not authorize it within `_globalConfig.flashLoadTimeout`
+milliseconds or does not authorize it at all.
+
+```js
+ZeroClipboard.on("error", function(e) {
+/*
+  e = {
+    type: "error",
+    name: "flash-deactivated",
+    messsage: "Flash is too outdated for your browser and/or is configured as click-to-activate",
+    target: null,
+    relatedTarget: null,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now(),
+    minimumVersion: "11.0.0",
+    version: "11.2.202"
+  };
+*/
+});
+```
+
+
+##### `error[name = "flash-overdue"]`
+
+This type of `error` event fires when the SWF loads successfully but takes longer than
+`_globalConfig.flashLoadTimeout` milliseconds to do so. This would likely be caused by
+one of the following situations:
+ 1. Too short of a `_globalConfig.flashLoadTimeout` duration configured
+ 2. Network latency
+ 3. The user's installation of Flash is configured as click-to-play but then authorized
+    by the user too late such that the SWF does not finish loading before the timeout
+    period has expired (or it may have expired before they authorized it at all).
+
+The appropriate response to this event is left up to the consumer. For instance, if they
+chose to invoke `ZeroClipboard.destroy()` in response to the earlier
+`error[name = "flash-deactivated"]` event but then receive this `error[name = "flash-overdue"]`
+event, they may choose to "restart" their process and construct new ZeroClipboard client instances,
+or they may choose to just log the error to their server so they can consider increasing the
+allowed timeout duration in the future.
+
+This may be especially important for SPA or PJAX-based applications to consider as their users
+may remain on a single page for an extended period of time during which they _possibly_ could
+have enjoyed an improved experience if ZeroClipboard had been "restarted" after an initial hiccup.
+
+```js
+ZeroClipboard.on("error", function(e) {
+/*
+  e = {
+    type: "error",
+    name: "flash-overdue",
+    messsage: "Flash communication was established but NOT within the acceptable time limit",
+    target: null,
+    relatedTarget: null,
+    currentTarget: flashSwfObjectRef,
+    timeStamp: Date.now(),
+    minimumVersion: "11.0.0",
+    version: "11.2.202"
+  };
+*/
+});
+```
+
+
+
+## Instance
+
+The following properties and methods are accessible via a `ZeroClipboard` client instance, e.g.
+
+```js
+var clippedEl = document.getElementById("d_clip_button");
+var client = new ZeroClipboard(clippedEl);
+```
+
+
+### Instance Properties
+
+#### `client.id`
+
+_[`String`]_ A unique identifier for this ZeroClipboard client instance.
+
+
+### Instance Methods
+
+#### `client.destroy()`
+
+_[`undefined`]_ Remove all event handlers and unclip all clipped elements.
+
+
+#### `client.setText(...)`
+
+```js
+client.setText("Blah");
+```
+
+_[`this`]_ Set the pending `data` of type `"text/plain"` for clipboard injection.
+
+
+#### `client.setHtml(...)`
+
+```js
+client.setHtml("<b>Blah</b>");
+```
+
+_[`this`]_ Set the pending `data` of type `"text/html"` for clipboard injection.
+
+
+#### `client.setRichText(...)`
+
+```js
+client.setRichText("{\\rtf1\\ansi\n{\\b Blah}}");
+```
+
+_[`this`]_ Set the pending `data` of type `"application/rtf"` for clipboard injection.
+
+
+#### `client.setData(...)`
+
+```js
+client.setData("text/plain", "Blah");
+```
+
+_[`this`]_ Set the pending `data` of type `format` for clipboard injection.
+
+```js
+client.setData({
+  "text/plain": "Blah",
+  "text/html": "<b>Blah</b>"
+});
+```
+
+_[`this`]_ Set the pending `data` of various formats for clipboard injection. This particular
+function signature (passing in an `Object`) will implicitly clear out any existing pending data.
+
+
+#### `client.clearData(...)`
+
+```js
+client.clearData("text/plain");
+```
+
+_[`this`]_ Clear the pending data of type `format` for clipboard injection.
+
+```js
+client.clearData();
+```
+
+_[`this`]_ Clear the pending data of ALL formats for clipboard injection.
+
+
+#### `client.getData(...)`
+
+```js
+var text = client.getData("text/plain");
+```
+
+_[`String`]_ Get the pending data of type `format` for clipboard injection.
+
+```js
+var dataObj = client.getData();
+```
+
+_[`Object`]_ Get a copy of the pending data of ALL formats for clipboard injection.
+
+
+#### `client.clip(...)`
+
+```js
+client.clip(document.getElementById("d_clip_button"))
+client.clip(document.querySelectorAll(".clip_button"));
+client.clip(jQuery(".clip_button"));
+```
+
+_[`this`]_ Register clipboard actions for new element(s) to the client. This includes
+automatically invoking `ZeroClipboard.focus` on the current element when it is hovered over,
+unless the `autoActivate` configuration property is set to `false`.
+
+
+#### `client.unclip(...)`
+
+```js
+client.unclip(document.getElementById("d_clip_button"))
+client.unclip(document.querySelectorAll(".clip_button"));
+client.unclip(jQuery(".clip_button"));
+client.unclip();
+```
+
+_[`this`]_ Unregister the clipboard actions of previously registered element(s) on the page.
+If no elements are provided, ALL clipped/registered elements will be unregistered.
+
+
+#### `client.elements()`
+
+```js
+var els = client.elements();
+```
+
+_[`Array`]_ Get all of the elements to which this client is clipped/registered.
+
+
+#### `client.on(...)`
+
+```js
+var listenerFn = function(e) { var client = this; /* ... */ };
+client.on("ready", listenerFn);
+
+var listenerObj = {
+  handleEvent: function(e) { var listenerObj = this; /* ... */ }
+};
+client.on("error", listenerObj);
+```
+
+_[`this`]_ Add a `listener` function/object for an `eventType` within this client instance.
+
+```js
+client.on("ready error", function(e) { /* ... */ });
+```
+
+_[`this`]_ Add a `listener` function/object for multiple `eventType`s within this client instance.
+
+```js
+client.on({
+  "ready": function(e) { /* ... */ },
+  "error": function(e) { /* ... */ }
+});
+```
+
+_[`this`]_ Add a set of `eventType` to `listener` function/object mappings within this client instance.
+
+
+#### `client.off(...)`
+
+```js
+client.off("ready", listenerFn);
+client.off("error", listenerObj);
+```
+
+_[`this`]_ Remove a `listener` function/object for an `eventType` within this client instance.
+
+```js
+client.off("ready error", listenerFn);
+```
+
+_[`this`]_ Remove a `listener` function/object for multiple `eventType`s within this client instance.
+
+```js
+client.off({
+  "ready": readyListenerFn,
+  "error": errorListenerFn
+});
+```
+
+_[`this`]_ Remove a set of `eventType` to `listener` function/object mappings within this client instance.
+
+```js
+client.off("ready");
+```
+
+_[`this`]_ Remove ALL listener functions/objects for an `eventType` within this client instance.
+
+```js
+client.off();
+```
+
+_[`this`]_ Remove ALL listener functions/objects for ALL registered event types within this client instance.
+
+
+#### `client.emit(...)`
+
+```js
+client.emit("ready");
+client.emit({
+  type: "error",
+  name: "flash-disabled"
+});
+```
+
+_[`undefined`]_ Dispatch an event to all registered listeners within this client instance.
+
+
+#### `client.handlers(...)`
+
+```js
+var listeners = client.handlers("ready");
+```
+
+_[`Array`]_ Retrieves a copy of the registered listener functions/objects for the given `eventType` within this client instance.
+
+
+```js
+var listeners = client.handlers();
+```
+
+_[`Object`]_ Retrieves a copy of the map of registered listener functions/objects for ALL event types within this client instance.
+
+
+
+### Instance Events
+
+See the [Static Events](#static-events) listing.  The ZeroClipboard client instances regurgitate the `ZeroClipboard.Core` events, ONLY if the event is NOT impertinent to this particular client.  The only difference is that the clients' event dispatching will update the `event` object to include a `client` property that references the relevant client instance, e.g.:
+
+```js
+var client = new ZeroClipboard();
+client.on("ready", function(e) {
+  if (e.client === client && client === this) {
+    console.log("This client instance is ready!");
+  }
+});
+```
+
+
+
+## Configuration Options
+
+These are default values for the global configurations options. You should generally update these _before_ you create your clients.
+
+```js
+var _globalConfig = {
+
+  // SWF URL, relative to the page. Default value will be "ZeroClipboard.swf"
+  // under the same path as the ZeroClipboard JS file.
+  swfPath: _swfPath,
+
+  // SWF inbound scripting policy: page domains that the SWF should trust.
+  // (single string, or array of strings)
+  trustedDomains: window.location.host ? [window.location.host] : [],
+
+  // Include a "noCache" query parameter on requests for the SWF.
+  cacheBust: true,
+
+  // Enable use of the fancy "Desktop" clipboard, even on Linux where it is
+  // known to suck.
+  forceEnhancedClipboard: false,
+
+  // How many milliseconds to wait for the Flash SWF to load and respond before assuming that
+  // Flash is deactivated (e.g. click-to-play) in the user's browser. If you don't care about
+  // how long it takes to load the SWF, you can set this to `null`.
+  flashLoadTimeout: 30000,
+
+  // Setting this to `false` would allow users to handle calling `ZeroClipboard.focus(...);`
+  // themselves instead of relying on our per-element `mouseover` handler.
+  autoActivate: true,
+
+  // Bubble synthetic events in JavaScript after they are received by the Flash object.
+  bubbleEvents: true,
+
+  // Sets the ID of the `div` encapsulating the Flash object.
+  // Value is validated against the [HTML4 spec for `ID` tokens][valid_ids].
+  containerId: "global-zeroclipboard-html-bridge",
+ 
+  // Sets the class of the `div` encapsulating the Flash object.
+  containerClass: "global-zeroclipboard-container",
+ 
+  // Sets the ID and name of the Flash `object` element.
+  // Value is validated against the [HTML4 spec for `ID` and `Name` tokens][valid_ids].
+  swfObjectId: "global-zeroclipboard-flash-bridge",
+
+  // The class used to indicate that a clipped element is being hovered over.
+  hoverClass: "zeroclipboard-is-hover",
+
+  // The class used to indicate that a clipped element is active (is being clicked).
+  activeClass: "zeroclipboard-is-active",
+
+
+
+  // Forcibly set the hand cursor ("pointer") for all clipped elements.
+  // IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
+  forceHandCursor: false,
+
+  // Sets the title of the `div` encapsulating the Flash object.
+  // IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
+  title: null,
+
+  // The z-index used by the Flash object.
+  // Max value (32-bit): 2147483647.
+  // IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
+  zIndex: 999999999
+
+};
+```
+
+You can override the defaults by making calls like `ZeroClipboard.config({ swfPath: "new/path" });`
+before you create any clients.
+
+
+### SWF Inbound Scripting Access: The `trustedDomains` option
+
+This allows other SWF files and HTML pages from the allowed domains to access/call publicly
+exposed ActionScript code, e.g. functions shared via `ExternalInterface.addCallback`. In other
+words, it controls the SWF inbound scripting access.
+
+If your ZeroClipboard SWF is served from a different origin/domain than your page, you need to tell
+the SWF that it's OK to trust your page. The default value of `[window.location.host]` is almost
+_**always**_ what you will want unless you specifically want the SWF to communicate with pages from
+other domains (e.g. in `iframe`s or child windows).
+
+For more information about trusted domains, consult the [_official Flash documentation for `flash.system.Security.allowDomain(...)`_](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/Security.html#allowDomain\(\)).
+
+
+### SWF Outbound Scripting Access
+
+The `allowScriptAccess` parameter (for Flash embedding markup) allows the SWF file to access/call
+JavaScript/HTML functionality of HTML pages on allowed domains, e.g. invoking functions via
+`ExternalInterface.call`. In other words, it controls the SWF outbound scripting access.
+
+As of version `v2.0.0-alpha.2`, the `allowScriptAccess` configuration option no longer exists. The
+appropriate value will be determined immediately before the Flash object is embedded on the page.
+The value is based on a relationship between the current domain (`window.location.host`) and the
+value of the `trustedDomains` configuration option.
+
+For more information about `allowScriptAccess`, consult the [_official Flash documentation_](http://helpx.adobe.com/flash/kb/control-access-scripts-host-web.html).
+
+
+### Cross-Protocol Limitations
+
+ZeroClipboard was intentionally configured to _not_ allow the SWF to be served from a secure domain (HTTPS) but scripted by an insecure domain (HTTP).
+
+If you find yourself in this situation (as in [Issue #170](https://github.com/zeroclipboard/zeroclipboard/issues/170)), please consider the following options:  
+ 1. Serve the SWF over HTTP instead of HTTPS. If the page's protocol can vary (e.g. authorized/unauthorized, staging/production, etc.), you should include add the SWF with a relative protocol (`//s3.amazonaws.com/blah/ZeroClipboard.swf`) instead of an absolute protocol (`https://s3.amazonaws.com/blah/ZeroClipboard.swf`).
+ 2. Serve the page over HTTPS instead of HTTP. If the page's protocol can vary, see the note on the previous option (1).
+ 3. Update ZeroClipboard's ActionScript codebase to call the [`allowInsecureDomain`](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/Security.html#allowInsecureDomain\(\)) method, then recompile the SWF with your custom changes.
+
+
+### `file://` Protocol Limitations
+
+If you want to host a page locally on the `file://` protocol, you must specifically configure
+ZeroClipboard to trust ALL domains for SWF interaction via a wildcard. This configuration must be
+set _before_ creating ZeroClipboard client instances as a typical consumer, or before calling
+`ZeroClipboard.create()` in a 3rd party wrapper:
+
+```js
+ZeroClipboard.config({ trustedDomains: ["*"] });
+```
+
+This wildcard configuration should _**NOT**_ be used in environments hosted over HTTP/HTTPS.

文件差异内容过多而无法显示
+ 439 - 0
global/js/zeroclipboard/docs/instructions.md


+ 9 - 0
global/js/zeroclipboard/docs/roadmap.md

@@ -0,0 +1,9 @@
+# Roadmap
+
+These are things that we have expressed interest in but haven't implemented yet. There is no order, if you feel like you can complete one of the tasks. Feel free to fork the project and send a pull request with the new code.
+
+## HTML5 Clipboard API
+In a perfect world we wouldn't need ZeroClipboard, and the browsers would just take care of it. We would like to write ZeroClipboard to use the browser's clipboard API when available. See Issues [#171](https://github.com/zeroclipboard/zeroclipboard/issues/171) and [~~#105~~](https://github.com/zeroclipboard/zeroclipboard/issues/105).
+
+## Flash Tests
+We want to setup a unit test suite for the Flash SWF and/or its underlying ActionScript files. See Issue [#43](https://github.com/zeroclipboard/zeroclipboard/issues/43).

+ 32 - 0
global/js/zeroclipboard/docs/security.md

@@ -0,0 +1,32 @@
+# Security
+
+We try our best to keep ZeroClipboard secure but there are some rules that you should consider following to keep your site safe.
+
+
+## Existing Configuration
+
+For the existing configuration options available for security, see [Configuration Options](api/ZeroClipboard.md#configuration-options).
+
+
+## Rules
+
+Basically, if an attacker gets access to the main window/global object via an XSS exploit, it's pretty much an instant "GAME OVER" unless **ALL** of the following are true:
+ 1. The `ZeroClipboard` object itself is not globally accessible.
+ 2. The `ZeroClipboard.prototype` object itself is not globally accessible.
+ 3. No `ZeroClipboard` instances are globally accessible.
+ 4. No callback functions for dispatched ZeroClipboard events are globally accessible.
+ 5. If a variable is used to set the path to the SWF via `ZeroClipboard.config`, that variable must not be globally accessible.
+ 6. The DOM is not accessible (due to built-in support for `data-clipboard-text` and `data-clipboard-target` attributes).
+
+ 
+## Examples
+
+ 1. Having `ZeroClipboard` instances globally accessible (versus encapsulated in a closure). This allows an attacker to manually call a client's `setText` method and inject their own text.
+ 2. As with all globally accessible functions in JavaScript, any globally accessible callback functions (hooked to events) can be overridden by an attacker. This isn't terribly dangerous but could be annoying.
+ 3. Overriding any of the `ZeroClipboard` or `ZeroClipboard.prototype` properties or methods, if globally accessible.
+ 4. Adding `data-clipboard-text` or `data-clipboard-target` attributes to every element in the DOM.
+
+ 
+### Responsible Disclosure
+
+If you find any security holes that you believe can be patched, please submit a pull request or file an issue. We will be very appreciative!

+ 29 - 0
global/js/zeroclipboard/index.js

@@ -0,0 +1,29 @@
+/*jshint node:true */
+
+
+// Module exports
+exports = module.exports = setup;
+
+// Module dependencies
+var http = require("http");
+var send = require("send");
+
+
+var root = __dirname;
+var swf = "/ZeroClipboard.swf";
+
+function setup() {
+  return http.createServer(onReq);
+}
+
+function onReq(req, res) {
+  send(req, swf)
+    .root(root)
+    .on("error", onError)
+    .pipe(res);
+}
+
+function onError(err) {
+  res.statusCode = err.status || 500;
+  res.end(err.message);
+}

+ 83 - 0
global/js/zeroclipboard/package.json

@@ -0,0 +1,83 @@
+{
+  "name": "zeroclipboard",
+  "title": "ZeroClipboard",
+  "version": "2.1.6",
+  "description": "The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface.",
+  "keywords": [
+    "flash",
+    "clipboard",
+    "copy",
+    "cut",
+    "paste",
+    "zclip",
+    "clip",
+    "clippy"
+  ],
+  "homepage": "http://zeroclipboard.org/",
+  "licenses": [
+    {
+      "type": "MIT",
+      "url": "https://github.com/zeroclipboard/zeroclipboard/blob/master/LICENSE"
+    }
+  ],
+  "contributors": [
+    {
+      "name": "Jon Rohan",
+      "url": "http://jonrohan.me/"
+    },
+    {
+      "name": "James M. Greene",
+      "email": "james.m.greene@gmail.com",
+      "url": "http://jamesgreene.net/"
+    }
+  ],
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/zeroclipboard/zeroclipboard.git"
+  },
+  "bugs": {
+    "url": "https://github.com/zeroclipboard/zeroclipboard/issues"
+  },
+  "dependencies": {
+    "send": "0"
+  },
+  "devDependencies": {
+    "flex-sdk": "~4.6.0-0",
+    "flexpmd": "^1.3.0-1",
+    "grunt": "^0.4.5",
+    "grunt-chmod": "^1.0.3",
+    "grunt-contrib-clean": "^0.5.0",
+    "grunt-contrib-concat": "^0.4.0",
+    "grunt-contrib-connect": "^0.8.0",
+    "grunt-contrib-jshint": "^0.10.0",
+    "grunt-contrib-uglify": "^0.5.0",
+    "grunt-contrib-watch": "^0.6.1",
+    "grunt-coveralls": "^0.3.0",
+    "grunt-flexpmd": "^0.1.2",
+    "grunt-mxmlc": "^0.5.1",
+    "grunt-qunit-istanbul": "^0.4.5",
+    "grunt-template": "^0.2.3",
+    "jquery": "^2.1.1",
+    "load-grunt-tasks": "^0.6.0",
+    "qunit-composite": "^1.0.1",
+    "qunitjs": "^1.14.0",
+    "spm": "^3.0.1"
+  },
+  "main": "./dist/ZeroClipboard.js",
+  "component": {
+    "scripts": {
+      "zeroclipboard": "./dist/ZeroClipboard.js"
+    }
+  },
+  "spm": {
+    "main": "dist/ZeroClipboard.js",
+    "output": [
+      "dist/ZeroClipboard.swf",
+      "dist/ZeroClipboard.Core.js"
+    ]
+  },
+  "scripts": {
+    "test": "grunt travis --verbose",
+    "postpublish": "spm publish"
+  }
+}

+ 185 - 0
global/js/zeroclipboard/src/flash/ClipboardInjector.as

@@ -0,0 +1,185 @@
+package {
+
+  import flash.system.Capabilities;
+  import flash.system.System;
+  import flash.desktop.Clipboard;
+  import flash.desktop.ClipboardFormats;
+  import flash.utils.ByteArray;
+
+
+  /**
+   * An abstraction for injecting data into the user's clipboard.
+   */
+  internal class ClipboardInjector {
+    /**
+     * Use the fancy "Desktop" clipboard for expanded text support (e.g. HTML, RTF, etc.) if not on Linux
+     */
+    private var useEnhancedClipboard:Boolean = Capabilities.os.slice(0, 5).toLowerCase() !== "linux";
+
+
+    /**
+     * @constructor
+     */
+    public function ClipboardInjector(forceEnhancedClipboard:Boolean = false) {
+      // The JIT Compiler does not compile constructors, so any
+      // cyclomatic complexity higher than 1 is discouraged.
+      this.ctor(forceEnhancedClipboard);
+    }
+
+
+    /**
+     * The real constructor.
+     *
+     * @return `undefined`
+     */
+    private function ctor(forceEnhancedClipboard:Boolean = false): void {
+      // Should we use the fancy "Desktop" clipboard for expanded text support (e.g. HTML, RTF, etc.)?
+      this.useEnhancedClipboard = this.useEnhancedClipboard || forceEnhancedClipboard;
+    }
+
+
+    /**
+     * Inject data into the user's clipboard.
+     *
+     * @return A clipboard "results" object
+     */
+    public function inject(
+      clipData:Object  // NOPMD
+    ): Object {  // NOPMD
+      var results:Object = {};  // NOPMD
+
+      // Set all data formats' results to `false` (failed) initially
+      for (var dataFormat:String in clipData) {
+        if (dataFormat && clipData.hasOwnProperty(dataFormat)) {
+          results[dataFormat] = false;
+        }
+      }
+
+      // If there is any viable data to copy...
+      if (ClipboardInjector.hasData(clipData)) {
+        // ...and we only need to handle plain text...
+        if (!this.useEnhancedClipboard || ClipboardInjector.hasOnlyPlainText(clipData)) {
+          this.injectPlainTextOnly(clipData, results);
+        }
+        // ...else if there is viable data to copy and we can copy enhanced formats
+        else if (this.useEnhancedClipboard) {
+          this.injectEnhancedData(clipData, results);
+        }
+      }
+
+      return results;
+    }
+
+
+
+    /**
+     * Inject plain text into the System clipboard (i.e. Flash 9+ Clipboard).
+     *
+     * @return `undefined`
+     */
+    private function injectPlainTextOnly(
+      clipData:Object,  // NOPMD
+      results:Object  // NOPMD
+    ): void {
+      // Linux currently doesn't use the correct clipboard buffer with the new
+      // Flash 10 API, so we need to use this until we can figure out an alternative
+      try {
+        System.setClipboard(clipData.text);
+        results.text = true;
+      }
+      catch (e:Error) {
+        // Yes, this is already set but FlexPMD complains about empty `catch` blocks
+        results.text = false;
+      }
+    }
+
+
+    /**
+     * Inject plain text, HTML, and RTF into the Desktop clipboard (i.e. Flash 10+ Clipboard).
+     *
+     * @return `undefined`
+     */
+    private function injectEnhancedData(
+      clipData:Object,  // NOPMD
+      results:Object  // NOPMD
+    ): void {
+      // Clear out the clipboard before starting to copy data
+      Clipboard.generalClipboard.clear();
+
+      //
+      // Handle each data type in succession...
+      //
+      // Plain text
+      if (typeof clipData.text === "string" && clipData.text) {
+        try {
+          results.text = Clipboard.generalClipboard.setData(ClipboardFormats.TEXT_FORMAT, clipData.text);
+        }
+        catch (e:Error) {
+          results.text = false;
+        }
+      }
+
+      // HTML
+      if (typeof clipData.html === "string" && clipData.html) {
+        try {
+          results.html = Clipboard.generalClipboard.setData(ClipboardFormats.HTML_FORMAT, clipData.html);
+        }
+        catch (e:Error) {
+          results.html = false;
+        }
+      }
+
+      // Rich Text (RTF)
+      if (typeof clipData.rtf === "string" && clipData.rtf) {
+        try {
+          var bytes:ByteArray = new ByteArray();
+          bytes.writeUTFBytes(clipData.rtf);
+          if (bytes && bytes.length > 0) {
+            results.rtf = Clipboard.generalClipboard.setData(ClipboardFormats.RICH_TEXT_FORMAT, bytes);
+          }
+        }
+        catch (e:Error) {
+          results.rtf = false;
+        }
+      }
+    }
+
+
+    /**
+     * Check if data object contains any keys with associated values that are non-empty Strings.
+     *
+     * @return Boolean
+     */
+    private static function hasData(
+      clipData:Object  // NOPMD
+    ): Boolean {
+      return typeof clipData === "object" && clipData &&
+        (
+          (typeof clipData.text === "string" && clipData.text) ||
+          (typeof clipData.html === "string" && clipData.html) ||
+          (typeof clipData.rtf  === "string" && clipData.rtf )
+        );
+    }
+
+
+    /**
+     * Check if a data object's ONLY injectable data is plain text.
+     *
+     * @return Boolean
+     */
+    private static function hasOnlyPlainText(
+      clipData:Object  // NOPMD
+    ): Boolean {
+      var hasPlainText:Boolean = false;
+      var hasOtherTypes:Boolean = false;
+      if (typeof clipData === "object" && clipData) {
+        hasPlainText = typeof clipData.text === "string" && clipData.text;
+        hasOtherTypes = (
+          (typeof clipData.html === "string" && clipData.html) ||
+          (typeof clipData.rtf  === "string" && clipData.rtf )
+        );
+      }
+      return !hasOtherTypes && hasPlainText;
+    }
+  }
+}

+ 140 - 0
global/js/zeroclipboard/src/flash/JsProxy.as

@@ -0,0 +1,140 @@
+package {
+
+  import flash.external.ExternalInterface;
+  import flash.net.navigateToURL;
+  import flash.net.URLRequest;
+
+
+  /**
+   * An abstraction for communicating with JavaScript from Flash.
+   */
+  internal class JsProxy {
+    private var hosted:Boolean = false;
+    private var bidirectional:Boolean = false;
+    private var disabled:Boolean = false;
+
+
+    /**
+     * @constructor
+     */
+    public function JsProxy(expectedObjectId:String = null) {
+      // The JIT Compiler does not compile constructors, so any
+      // cyclomatic complexity higher than 1 is discouraged.
+      this.ctor(expectedObjectId);
+    }
+
+
+    /**
+     * The real constructor.
+     *
+     * @return `undefined`
+     */
+    private function ctor(expectedObjectId:String = null): void {
+      // Do we authoritatively know that this Flash object is hosted in a browser?
+      this.hosted = ExternalInterface.available === true &&
+        ExternalInterface.objectID &&
+        (expectedObjectId ? (expectedObjectId === ExternalInterface.objectID) : true);
+
+      // Can we retrieve values from JavaScript?
+      // Try this regardless of the return value of `ExternalInterface.call`.
+      try {
+        this.bidirectional = ExternalInterface.call("(function() { return true; })") === true;
+      }
+      catch (e:Error) {
+        // We do NOT authoritatively know if this Flash object is hosted in a browser,
+        // nor if JavaScript is disabled.
+        this.bidirectional = false;
+      }
+
+      // If hosted but cannot bidirectionally communicate with JavaScript,
+      // then JavaScript is disabled on the page!
+      this.disabled = this.hosted && !this.bidirectional;
+    }
+
+
+    /**
+     * Are we authoritatively certain that we can execute JavaScript bidirectionally?
+     *
+     * @return Boolean
+     */
+    public function isComplete(): Boolean {
+      return this.hosted && this.bidirectional;
+    }
+
+
+    /**
+     * Register an ActionScript method as callable from the container's JavaScript
+     *
+     * This will execute the JavaScript ONLY if ExternalInterface is completely
+     * available (hosted in the browser AND supporting bidirectional communication).
+     *
+     * @return `undefined`
+     */
+    public function addCallback(functionName:String, closure:Function): void {
+      if (this.isComplete()) {
+        ExternalInterface.addCallback(functionName, closure);
+      }
+    }
+
+    /**
+     * Execute a function expression or named function, with optional arguments,
+     * and receive its return value.
+     *
+     * This will execute the JavaScript ONLY if ExternalInterface is completely
+     * available (hosted in the browser AND supporting bidirectional communication).
+     *
+     * @example
+     * var jsProxy:JsProxy = new JsProxy("global-zeroclipboard-flash-bridge");
+     * var result:Object = jsProxy.call("ZeroClipboard.emit", [{ type: "copy" }]);
+     * jsProxy.call("(function(eventObj) { return ZeroClipboard.emit(eventObj); })", [{ type: "ready"}]);
+     *
+     * @return `undefined`, or anything
+     */
+    public function call(
+      jsFuncExpr:String,
+      args:Array = null
+    ): * {  // NOPMD
+      var result:* = undefined;  // NOPMD
+      if (jsFuncExpr && this.isComplete()) {
+        if (args == null) {
+          args = [];
+        }
+        result = ExternalInterface.call.apply(ExternalInterface, [jsFuncExpr].concat(args));
+      }
+      return result;
+    }
+
+
+    /**
+     * Execute a function expression or named function, with optional arguments.
+     * No return values will ever be received.
+     *
+     * This will attempt to execute the JavaScript, even if ExternalInterface is
+     * not available; in which case: the worst thing that can happen is that
+     * the JavaScript is not executed (i.e. if JavaScript is disabled, or if
+     * the SWF is not allowed to communicate with JavaScript on its host page).
+     *
+     * @return `undefined`
+     */
+    public function send(jsFuncExpr:String, args:Array = null): void {
+      if (jsFuncExpr) {
+        if (this.isComplete()) {
+          this.call(jsFuncExpr, args);
+        }
+        else if (!this.disabled) {
+          if (args == null) {
+            args = [];
+          }
+          var argsStr:String = "";
+          for (var counter:int = 0; counter < args.length; counter++) {
+            argsStr += JSON.stringify(args[counter]);
+            if ((counter + 1) < args.length) {
+              argsStr += ", ";
+            }
+          }
+          navigateToURL(new URLRequest("javascript:" + jsFuncExpr + "(" + argsStr + ");"), "_self");
+        }
+      }
+    }
+  }
+}

+ 38 - 0
global/js/zeroclipboard/src/flash/XssUtils.as

@@ -0,0 +1,38 @@
+package {
+
+  /**
+   * Utility methods for XSS attack prevention.
+   */
+  internal class XssUtils {
+
+    /**
+     * Sanitize a string to avoid XSS vulnerabilities.
+     *
+     * @return an XSS safe String
+     * @static
+    */
+    public static function sanitizeString(dirty:String): String {
+      return (typeof dirty === "string" && dirty) ? dirty.replace(/\\/g, "\\\\") : "";
+    }
+
+
+    /**
+     * Sanitize the Loader parameters by filtering out all URL query parameters,
+     * leaving ONLY parameters that were specified via FlashVars in the HTML
+     * embedding markup.
+     *
+     * @return a filtered parameters object, a.k.a. FlashVars
+     * @static
+     */
+    public static function filterToFlashVars(
+      parameters:Object  // NOPMD
+    ): Object {  // NOPMD
+      //
+      // TODO: Implement this for real
+      // See:  https://github.com/zeroclipboard/zeroclipboard/pull/336
+      //
+      return parameters;
+    }
+
+  }
+}

+ 299 - 0
global/js/zeroclipboard/src/flash/ZeroClipboard.as

@@ -0,0 +1,299 @@
+package {
+
+  import flash.display.Stage;
+  import flash.display.StageAlign;
+  import flash.display.StageScaleMode;
+  import flash.display.StageQuality;
+  import flash.display.Sprite;
+  import flash.events.Event;
+  import flash.events.MouseEvent;
+  import flash.system.Security;
+
+
+  /**
+   * The ZeroClipboard class creates a simple Sprite button that will put
+   * text in the user's clipboard when clicked.
+   */
+  [SWF(widthPercent="100%", heightPercent="100%", backgroundColor="#FFFFFF")]
+  public class ZeroClipboard extends Sprite {
+
+    /**
+     * Function through which JavaScript events are emitted. Accounts for scenarios
+     * in which ZeroClipboard is used via AMD/CommonJS module loaders, too.
+     */
+    private var jsEmitter:String = null;
+
+    /**
+     * JavaScript proxy object.
+     */
+    private var jsProxy:JsProxy = null;
+
+    /**
+     * Clipboard proxy object.
+     */
+    private var clipboard:ClipboardInjector = null;
+
+
+    /**
+     * @constructor
+     */
+    public function ZeroClipboard() {
+      // The JIT Compiler does not compile constructors, so ANY
+      // cyclomatic complexity higher than 1 is discouraged.
+      this.ctor();
+    }
+
+
+    /**
+     * The real constructor.
+     *
+     * @return `undefined`
+     */
+    private function ctor(): void {
+      // If the `stage` is available, begin!
+      if (stage) {
+        this.init();
+      }
+      else {
+        // Otherwise, wait for the `stage`....
+        this.addEventListener(Event.ADDED_TO_STAGE, this.init);
+      }
+    }
+
+
+    /**
+     * Initialize the class when the Stage is ready.
+     *
+     * @return `undefined`
+     */
+    private function init(): void {
+      // Remove the event listener, if any
+      this.removeEventListener(Event.ADDED_TO_STAGE, this.init);
+
+      // Get the flashvars
+      var flashvars:Object;  // NOPMD
+      flashvars = XssUtils.filterToFlashVars(this.loaderInfo.parameters);
+
+      // Configure the SWF object's ID
+      var swfObjectId:String = "global-zeroclipboard-flash-bridge";
+      if (flashvars.swfObjectId && typeof flashvars.swfObjectId === "string") {
+        var swfId = XssUtils.sanitizeString(flashvars.swfObjectId);
+
+        // Validate the ID against the HTML4 spec for `ID` tokens.
+        if (/^[A-Za-z][A-Za-z0-9_:\-\.]*$/.test(swfId)) {
+          swfObjectId = swfId;
+        }
+      }
+
+      // Allow the SWF object to communicate with a page on a different origin than its own (e.g. SWF served from CDN)
+      if (flashvars.trustedOrigins && typeof flashvars.trustedOrigins === "string") {
+        var origins:Array = XssUtils.sanitizeString(flashvars.trustedOrigins).split(",");
+        Security.allowDomain.apply(Security, origins);
+      }
+
+      // Enable use of the fancy "Desktop" clipboard, even on Linux where it is known to suck
+      var forceEnhancedClipboard:Boolean = false;
+      if (flashvars.forceEnhancedClipboard === "true" || flashvars.forceEnhancedClipboard === true) {
+        forceEnhancedClipboard = true;
+      }
+
+      this.jsEmitter =
+        "(function(eventObj) {\n" +
+        "  var objectId = '" + swfObjectId + "',\n" +
+        "      ZC = null,\n" +
+        "      swf = null;\n" +
+        "  if (typeof ZeroClipboard === 'function' && typeof ZeroClipboard.emit === 'function') {\n" +
+        "    \nZC = ZeroClipboard;\n" +
+        "  }\n" +
+        "  else {\n" +
+        "    swf = document[objectId] || document.getElementById(objectId);\n" +
+        "    if (swf && typeof swf.ZeroClipboard === 'function' && typeof swf.ZeroClipboard.emit === 'function') {\n" +
+        "      ZC = swf.ZeroClipboard;\n" +
+        "    }\n" +
+        "  }\n" +
+        "  if (!ZC) {\n" +
+        "    throw new Error('ERROR: ZeroClipboard SWF could not locate ZeroClipboard JS object!\\n" +
+                             "Expected element ID: ' + objectId);\n" +
+        "  }\n" +
+        "  return ZC.emit(eventObj);\n" +
+        "})";
+
+      // Create an invisible "button" and transparently fill the entire Stage
+      var button:Sprite = this.prepareUI();
+
+      // Configure the clipboard injector
+      this.clipboard = new ClipboardInjector(forceEnhancedClipboard);
+
+      // Establish a communication line with JavaScript
+      this.jsProxy = new JsProxy(swfObjectId);
+
+      // Only proceed if this SWF is hosted in the browser as expected
+      if (this.jsProxy.isComplete()) {
+
+        // Add the MouseEvent listeners
+        this.addMouseHandlers(button);
+
+        // Expose the external functions
+        this.jsProxy.addCallback(
+          "setHandCursor",
+          function(enabled:Boolean) {
+            button.useHandCursor = enabled === true;
+          }
+        );
+
+        // Signal to the browser that we are ready
+        this.emit("ready");
+      }
+      else {
+        // Signal to the browser that something is wrong
+        this.emit("error", {
+          name: "flash-unavailable"
+        });
+      }
+    }
+
+
+    /**
+     * Prepare the Stage and Button.
+     *
+     * @return Button
+     */
+    private function prepareUI(): Sprite {
+      // Set the stage!
+      stage.align = StageAlign.TOP_LEFT;
+      stage.scaleMode = StageScaleMode.EXACT_FIT;
+      stage.quality = StageQuality.BEST;
+
+      // Create an invisible "button" and transparently fill the entire Stage
+      var button:Sprite = new Sprite();
+      button.graphics.beginFill(0xFFFFFF);
+      button.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
+      button.alpha = 0.0;
+
+      // Act like a button. This includes:
+      //  - Showing a hand cursor by default
+      //  - Receiving click events
+      //  - Receiving keypress events of space/"Enter" as click
+      //    events IF AND ONLY IF the Sprite is focused.
+      button.buttonMode = true;
+
+      // Override the hand cursor default
+      button.useHandCursor = false;
+
+      // Add the invisible "button" to the stage!
+      this.addChild(button);
+
+      // Return the button for adding event listeners
+      return button;
+    }
+
+
+    /**
+     * Clears the clipboard and sets new clipboard text. It gets this from the "_clipData"
+     * variable on the JavaScript side. Once the text has been placed in the clipboard, it
+     * then signals to the JavaScript that it is done.
+     *
+     * @return `undefined`
+     */
+    private function onClick(event:MouseEvent): void {
+      var clipData:Object;  // NOPMD
+      var clipInjectSuccess:Object = {};  // NOPMD
+
+      // Allow for any "UI preparation" work before the "copy" event begins
+      this.emit("beforecopy");
+
+      // Request pending clipboard data from the page
+      clipData = this.emit("copy");
+
+      // Inject all pending data into the user's clipboard
+      clipInjectSuccess = this.clipboard.inject(clipData);
+
+      // Compose and serialize a results object, send it back to the page
+      this.emit(
+        "aftercopy",
+        {
+          success: clipInjectSuccess,
+          data: clipData
+        }
+      );
+    }
+
+
+    /**
+     * Emit events to JavaScript.
+     *
+     * @return `undefined`, or the new "_clipData" object
+     */
+    private function emit(
+      eventType:String,
+      eventObj:Object = null  // NOPMD
+    ): Object {  // NOPMD
+      if (eventObj == null) {
+        eventObj = {};
+      }
+      eventObj.type = eventType;
+
+      var result:Object = undefined;  // NOPMD
+      if (this.jsProxy.isComplete()) {
+        result = this.jsProxy.call(this.jsEmitter, [eventObj]);
+      }
+      else {
+        this.jsProxy.send(this.jsEmitter, [eventObj]);
+      }
+      return result;
+    }
+
+
+    /**
+     * Signals to the page that a MouseEvent occurred.
+     *
+     * @return `undefined`
+     */
+    private function onMouseEvent(event:MouseEvent): void {
+      var evtData:Object = {}; // NOPMD
+
+      // If an event is passed in, return what modifier keys are pressed, etc.
+      if (event) {
+        var props:Object;  // NOPMD
+        props = {
+          "altKey": "altKey",
+          "commandKey": "metaKey",
+          "controlKey": "ctrlKey",
+          "shiftKey": "shiftKey",
+          "clickCount": "detail",
+          "movementX": "movementX",
+          "movementY": "movementY",
+          "stageX": "_stageX",
+          "stageY": "_stageY"
+        };
+
+        for (var prop in props) {
+          if (event.hasOwnProperty(prop) && event[prop] != null) {
+            evtData[props[prop]] = event[prop];
+          }
+        }
+        evtData.type = "_" + event.type.toLowerCase();
+        evtData._source = "swf";
+      }
+
+      this.emit(evtData.type, evtData);
+    }
+
+
+    /**
+     * Add mouse event handlers to the button.
+     *
+     * @return `undefined`
+     */
+    private function addMouseHandlers(button:Sprite): Sprite {
+      button.addEventListener(MouseEvent.MOUSE_MOVE, this.onMouseEvent);
+      button.addEventListener(MouseEvent.MOUSE_OVER, this.onMouseEvent);
+      button.addEventListener(MouseEvent.MOUSE_OUT, this.onMouseEvent);
+      button.addEventListener(MouseEvent.MOUSE_DOWN, this.onMouseEvent);
+      button.addEventListener(MouseEvent.MOUSE_UP, this.onMouseEvent);
+      button.addEventListener(MouseEvent.CLICK, this.onClick);
+      button.addEventListener(MouseEvent.CLICK, this.onMouseEvent);
+      return button;
+    }
+  }
+}

+ 162 - 0
global/js/zeroclipboard/src/js/client/api.js

@@ -0,0 +1,162 @@
+/**
+ * Creates a new ZeroClipboard client instance.
+ * Optionally, auto-`clip` an element or collection of elements.
+ *
+ * @constructor
+ */
+ZeroClipboard._createClient = function(/* elements */) {
+  // Invoke the real constructor
+  _clientConstructor.apply(this, _args(arguments));
+};
+
+
+/**
+ * Register an event listener to the client.
+ *
+ * @returns `this`
+ */
+ZeroClipboard.prototype.on = function(/* eventType, listener */) {
+  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(/* eventType, listener */) {
+  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(/* eventType */) {
+  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(/* event */) {
+  return _clientEmit.apply(this, _args(arguments));
+};
+
+
+/**
+ * Register clipboard actions for new element(s) to the client.
+ *
+ * @returns `this`
+ */
+ZeroClipboard.prototype.clip = function(/* elements */) {
+  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(/* elements */) {
+  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) {
+  ZeroClipboard.setData("text/plain", text);
+  return this;
+};
+
+
+/**
+ * Stores the pending HTML text to inject into the clipboard.
+ *
+ * @returns `this`
+ */
+ZeroClipboard.prototype.setHtml = function(html) {
+  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) {
+  ZeroClipboard.setData("application/rtf", richText);
+  return this;
+};
+
+
+/**
+ * Stores the pending data to inject into the clipboard.
+ *
+ * @returns `this`
+ */
+ZeroClipboard.prototype.setData = function(/* format, data */) {
+  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(/* format */) {
+  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(/* format */) {
+  return ZeroClipboard.getData.apply(this, _args(arguments));
+};

+ 476 - 0
global/js/zeroclipboard/src/js/client/private.js

@@ -0,0 +1,476 @@
+/**
+ * The real constructor for `ZeroClipboard` client instances.
+ * @private
+ */
+var _clientConstructor = function(elements) {
+  // Save a closure reference for the following event handlers
+  var client = this;
+
+  // Assign an ID to the client instance
+  client.id = "" + (_clientIdCounter++);
+
+  // Create the meta information store for this client
+  _clientMeta[client.id] = {
+    instance: client,
+    elements: [],
+    handlers: {}
+  };
+
+  // If the elements argument exists, clip it
+  if (elements) {
+    client.clip(elements);
+  }
+
+  // ECHO! Our client's sounding board.
+  ZeroClipboard.on("*", function(event) {
+    return client.emit(event);
+  });
+
+  // Await imminent destruction...
+  ZeroClipboard.on("destroy", function() {
+    client.destroy();
+  });
+
+  // Move on: embed the SWF
+  ZeroClipboard.create();
+};
+
+
+/**
+ * The underlying implementation of `ZeroClipboard.Client.prototype.on`.
+ * @private
+ */
+var _clientOn = function(eventType, listener) {
+  // add user event handler for event
+  var i, len, events,
+      added = {},
+      handlers = _clientMeta[this.id] && _clientMeta[this.id].handlers;
+
+  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);
+    }
+
+    // The following events must be memorized and fired immediately if relevant as they only occur
+    // once per Flash object load.
+
+    // If the SWF was already loaded, we're à gogo!
+    if (added.ready && _flashState.ready) {
+      this.emit({
+        type: "ready",
+        client: this
+      });
+    }
+    if (added.error) {
+      var errorTypes = ["disabled", "outdated", "unavailable", "deactivated", "overdue"];
+      for (i = 0, len = errorTypes.length; i < len; i++) {
+        if (_flashState[errorTypes[i]]) {
+          this.emit({
+            type: "error",
+            name: "flash-" + errorTypes[i],
+            client: this
+          });
+          break;
+        }
+      }
+    }
+  }
+  return this;
+};
+
+
+/**
+ * The underlying implementation of `ZeroClipboard.Client.prototype.off`.
+ * @private
+ */
+var _clientOff = function(eventType, listener) {
+  var i, len, foundIndex, events, perEventHandlers,
+      handlers = _clientMeta[this.id] && _clientMeta[this.id].handlers;
+  if (arguments.length === 0) {
+    // Remove ALL of the handlers for ALL event types
+    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 {
+          // If no `listener` was provided, remove ALL of the handlers for this event type
+          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 {
+      // Make a deep copy of the handlers object
+      copy = _deepCopy(handlers);
+    }
+  }
+  return copy;
+};
+
+
+/**
+ * The underlying implementation of `ZeroClipboard.Client.prototype.emit`.
+ * @private
+ */
+var _clientEmit = function(event) {
+  if (_clientShouldEmit.call(this, event)) {
+    // Don't modify the original Event, if it is an object (as expected)
+    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) {
+  elements = _prepClip(elements);
+
+  for (var i = 0; i < elements.length ; i++) {
+    if (_hasOwn.call(elements, i) && elements[i] && elements[i].nodeType === 1) {
+      // If the element hasn't been clipped to ANY client yet, add a metadata ID and event handler
+      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);
+      }
+
+      // If the element hasn't been clipped to THIS client yet, add it
+      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 no elements were provided, unclip ALL of this client's clipped elements
+  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) {
+      // If the element was clipped to THIS client yet, remove it
+      arrayIndex = 0;
+      while ((arrayIndex = clippedElements.indexOf(elements[i], arrayIndex)) !== -1) {
+        clippedElements.splice(arrayIndex, 1);
+      }
+
+      // If the element isn't clipped to ANY other client, remove its metadata ID and event handler
+      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() {
+  // Unclip all the elements
+  this.unclip();
+
+  // Remove all event handlers
+  this.off();
+
+  // Delete the client's metadata store
+  delete _clientMeta[this.id];
+};
+
+
+
+
+//
+// Helper functions
+//
+
+/**
+ * Inspect an Event to see if the Client (`this`) should honor it for emission.
+ * @private
+ */
+var _clientShouldEmit = function(event) {
+  // If no event is received
+  if (!(event && event.type)) {
+    return false;
+  }
+
+  // If this event's `client` was specifically set to a client other than this client, bail out
+  if (event.client && event.client !== this) {
+    return false;
+  }
+
+  // If this event's targeted element(s) is/are not clipped by this client, bail out
+  // unless the event's `client` was specifically set to this client.
+  var clippedEls = _clientMeta[this.id] && _clientMeta[this.id].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;
+  // At least one of these must be true....
+  if (!(goodTarget || goodRelTarget || goodClient)) {
+    return false;
+  }
+
+  // Otherwise... go for it!
+  return true;
+};
+
+
+/**
+ * Handle the actual dispatching of events to a client instance.
+ *
+ * @returns `this`
+ * @private
+ */
+var _clientDispatchCallbacks = function(event) {
+  if (!(typeof event === "object" && event && event.type)) {
+    return;
+  }
+
+  var async = _shouldPerformAsync(event);
+
+  // User defined handlers for events
+  var wildcardTypeHandlers = (_clientMeta[this.id] && _clientMeta[this.id].handlers["*"]) || [];
+  var specificTypeHandlers = (_clientMeta[this.id] && _clientMeta[this.id].handlers[event.type]) || [];
+  // Execute wildcard handlers before type-specific handlers
+  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 the user provided a string for their callback, grab that function
+      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;
+};
+
+
+/**
+ * Prepares the elements for clipping/unclipping.
+ *
+ * @returns An Array of elements.
+ * @private
+ */
+var _prepClip = function(elements) {
+  // if elements is a string, ignore it
+  if (typeof elements === "string") {
+    elements = [];
+  }
+  // if the elements isn't an array, wrap it with one
+  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;
+  }
+
+  // Create a `mouseout` handler function
+  var _suppressMouseEvents = function(event) {
+    if (!(event || (event = _window.event))) {
+      return;
+    }
+
+    // Don't allow this event to be handled by consumers unless it originated from ZeroClipboard
+    if (event._source !== "js") {
+      event.stopImmediatePropagation();
+      event.preventDefault();
+    }
+    delete event._source;
+  };
+
+  // Create a `mouseover` handler function
+  var _elementMouseOver = function(event) {
+    if (!(event || (event = _window.event))) {
+      return;
+    }
+
+    // Don't allow this event to be handled by consumers unless it originated from ZeroClipboard
+    _suppressMouseEvents(event);
+
+    // Set this as the new currently active element
+    ZeroClipboard.focus(element);
+  };
+
+  // Add the `mouseover` handler function
+  element.addEventListener("mouseover", _elementMouseOver, false);
+
+  // Add other mouse event handler functions
+  element.addEventListener("mouseout", _suppressMouseEvents, false);
+  element.addEventListener("mouseenter", _suppressMouseEvents, false);
+  element.addEventListener("mouseleave", _suppressMouseEvents, false);
+  element.addEventListener("mousemove", _suppressMouseEvents, false);
+
+  // Save these function references to a global variable
+  _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;
+  }
+
+  // Retrieve these function references from a global variable
+  var mouseHandlers = _mouseHandlers[element.zcClippingId];
+  if (!(typeof mouseHandlers === "object" && mouseHandlers)) {
+    return;
+  }
+
+  // Remove the mouse event handlers
+  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 these function references from a global variable
+  delete _mouseHandlers[element.zcClippingId];
+};

+ 60 - 0
global/js/zeroclipboard/src/js/client/state.js

@@ -0,0 +1,60 @@
+/**
+ * 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, {
+
+  // Setting this to `false` would allow users to handle calling
+  // `ZeroClipboard.focus(...);` themselves instead of relying on our
+  // per-element `mouseover` handler.
+  autoActivate: true
+
+});

+ 211 - 0
global/js/zeroclipboard/src/js/core/api.js

@@ -0,0 +1,211 @@
+/**
+ * A shell constructor for `ZeroClipboard` client instances.
+ *
+ * @constructor
+ */
+var ZeroClipboard = function() {
+
+  // Ensure the constructor is invoked with the `new` keyword.
+  if (!(this instanceof ZeroClipboard)) {
+    return new ZeroClipboard();
+  }
+
+  // EXTREMELY IMPORTANT!
+  // Ensure the `ZeroClipboard._createClient` function is invoked if available.
+  // This allows an extension point for 3rd parties to create their own
+  // interpretations of what a ZeroClipboard "Client" should be like.
+  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: "<%= version %>",
+  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(/* options */) {
+  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(/* eventType, listener */) {
+  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(/* eventType, listener */) {
+  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(/* eventType */) {
+  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(/* event */) {
+  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(/* format, data */) {
+  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(/* format */) {
+  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(/* format */) {
+  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(/* element */) {
+  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));
+};

文件差异内容过多而无法显示
+ 1701 - 0
global/js/zeroclipboard/src/js/core/private.js


+ 147 - 0
global/js/zeroclipboard/src/js/core/state.js

@@ -0,0 +1,147 @@
+/**
+ * Keep track of the state of the Flash object.
+ * @private
+ */
+var _flashState = {
+  // Flash object reference
+  bridge: null,
+
+  // Flash metadata
+  version: "0.0.0",
+  pluginType: "unknown",
+
+  // Flash SWF state
+  disabled: null,
+  outdated: null,
+  unavailable: null,
+  deactivated: null,
+  overdue: null,
+  ready: null
+};
+
+
+/**
+ * The minimum Flash Player version required to use ZeroClipboard completely.
+ * @readonly
+ * @private
+ */
+var _minimumFlashVersion = "11.0.0";
+
+
+/**
+ * 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;
+
+
+/**
+ * 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-deactivated": "Flash is too outdated for your browser and/or is configured as click-to-activate",
+    "flash-overdue": "Flash communication was established but NOT within the acceptable time limit"
+  }
+};
+
+
+/**
+ * ZeroClipboard configuration defaults for the Core module.
+ * @private
+ */
+var _globalConfig = {
+
+  // SWF URL, relative to the page. Default value will be "ZeroClipboard.swf"
+  // under the same path as the ZeroClipboard JS file.
+  swfPath: _getDefaultSwfPath(),
+
+  // SWF inbound scripting policy: page domains that the SWF should trust.
+  // (single string, or array of strings)
+  trustedDomains: window.location.host ? [window.location.host] : [],
+
+  // Include a "noCache" query parameter on requests for the SWF.
+  cacheBust: true,
+
+  // Enable use of the fancy "Desktop" clipboard, even on Linux where it is
+  // known to suck.
+  forceEnhancedClipboard: false,
+
+  // How many milliseconds to wait for the Flash SWF to load and respond before assuming that
+  // Flash is deactivated (e.g. click-to-play) in the user's browser. If you don't care about
+  // how long it takes to load the SWF, you can set this to `null`.
+  flashLoadTimeout: 30000,
+
+  // Setting this to `false` would allow users to handle calling `ZeroClipboard.focus(...);`
+  // themselves instead of relying on our per-element `mouseover` handler.
+  autoActivate: true,
+
+  // Bubble synthetic events in JavaScript after they are received by the Flash object.
+  bubbleEvents: true,
+  
+  // Sets the ID of the `div` encapsulating the Flash object.
+  // Value is validated against the HTML4 spec for `ID` tokens.
+  containerId: "global-zeroclipboard-html-bridge",
+ 
+  // Sets the class of the `div` encapsulating the Flash object.
+  containerClass: "global-zeroclipboard-container",
+ 
+  // Sets the ID and name of the Flash `object` element.
+  // Value is validated against the HTML4 spec for `ID` and `Name` tokens.
+  swfObjectId: "global-zeroclipboard-flash-bridge",
+
+  // The class used to indicate that a clipped element is being hovered over.
+  hoverClass: "zeroclipboard-is-hover",
+
+  // The class used to indicate that a clipped element is active (is being clicked).
+  activeClass: "zeroclipboard-is-active",
+
+
+
+  // Forcibly set the hand cursor ("pointer") for all clipped elements.
+  // IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
+  forceHandCursor: false,
+
+  // Sets the title of the `div` encapsulating the Flash object.
+  // IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
+  title: null,
+
+  // The z-index used by the Flash object.
+  // Max value (32-bit): 2147483647.
+  // IMPORTANT: This configuration value CAN be modified while a SWF is actively embedded.
+  zIndex: 999999999
+
+};

+ 21 - 0
global/js/zeroclipboard/src/js/end.js

@@ -0,0 +1,21 @@
+
+
+// The AMDJS logic branch is evaluated first to avoid potential confusion over
+// the CommonJS syntactical sugar offered by AMD.
+if (typeof define === "function" && define.amd) {
+  define(function() {
+    return ZeroClipboard;
+  });
+}
+else if (typeof module === "object" && module && typeof module.exports === "object" && module.exports) {
+  // CommonJS module loaders....
+  module.exports = ZeroClipboard;
+}
+else {
+  window.ZeroClipboard = ZeroClipboard;
+}
+
+})((function() {
+  /*jshint strict: false */
+  return this || window;
+})());

+ 317 - 0
global/js/zeroclipboard/src/js/shared/private.js

@@ -0,0 +1,317 @@
+/**
+ * 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++) {
+    // Only deal with non-null/undefined values
+    if ((arg = args[i]) != null) {
+      // Extend the base object
+      for (prop in arg) {
+        if (_hasOwn.call(arg, prop)) {
+          src = target[prop];
+          copy = arg[prop];
+
+          // Prevent never-ending loops and copying `undefined` valeus
+          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 not a non-null object, just return the original
+  if (typeof source !== "object" || source == null) {
+    copy = source;
+  }
+  // If an Array, iterate and recurse
+  else if (typeof source.length === "number") {
+    copy = [];
+    for (i = 0, len = source.length; i < len; i++) {
+      // Skip empty indices in sparse arrays
+      if (_hasOwn.call(source, i)) {
+        // Recurse
+        copy[i] = _deepCopy(source[i]);
+      }
+    }
+  }
+  // If an Object, enumerate and recurse
+  else {
+    copy = {};
+    for (prop in source) {
+      // Skip prototype properties
+      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() {
+  /*jshint newcap:false */
+  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;
+
+  // Try to leverage the `currentScript` feature
+  if (_document.currentScript && (jsPath = _document.currentScript.src)) {
+    return jsPath;
+  }
+
+  // If it it not available, then seek the script out instead...
+  scripts = _document.getElementsByTagName("script");
+
+  // If there is only one script
+  if (scripts.length === 1) {
+    return scripts[0].src || undefined;
+  }
+
+  // If `script` elements have the `readyState` property in this browser
+  if ("readyState" in scripts[0]) {
+    for (i = scripts.length; i--; ) {
+      if (scripts[i].readyState === "interactive" && (jsPath = scripts[i].src)) {
+        return jsPath;
+      }
+    }
+  }
+
+  // If the document is still parsing, then the last script in the document is the one that is currently loading
+  if (_document.readyState === "loading" && (jsPath = scripts[scripts.length - 1].src)) {
+    return jsPath;
+  }
+
+  // Else take more drastic measures...
+  if ((jsPath = _getCurrentScriptUrlFromError())) {
+    return jsPath;
+  }
+
+  // Otherwise we cannot reliably know which exact script is executing....
+  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");
+
+  // If every `script` has a `src` attribute AND they all come from the same directory
+  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;
+    }
+  }
+
+  // Otherwise we cannot reliably know what script is executing....
+  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";
+};

+ 0 - 0
global/js/zeroclipboard/src/js/shared/state.js


部分文件因为文件数量过多而无法显示