每日一库:ZeroClipboard.js
介绍:The Zero Clipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie, and a JavaScript interface
地址:http://jonrohan.github.com/ZeroClipboard/#demo
源码解析:
1 /*! 2 * zeroclipboard 3 * The Zero Clipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie, and a JavaScript interface. 4 * Copyright 2012 Jon Rohan, James M. Greene, . 5 * Released under the MIT license 6 * http://jonrohan.github.com/ZeroClipboard/ 7 * v1.1.6 8 */ 9 10 (function() { 11 "use strict"; 12 13 var _getStyle = function(el, prop) { //获取样式 14 var y = el.style[prop]; 15 if (el.currentStyle) y = el.currentStyle[prop]; else if (window.getComputedStyle) y = document.defaultView.getComputedStyle(el, null).getPropertyValue(prop); 16 if (y == "auto" && prop == "cursor") { //auto没处理 17 var possiblePointers = [ "a" ]; 18 for (var i = 0; i < possiblePointers.length; i++) { 19 if (el.tagName.toLowerCase() == possiblePointers[i]) { 20 return "pointer"; 21 } 22 } 23 } 24 return y; 25 }; 26 27 var _addEventHandler = function(element, method, func) { //注册事件 28 if (element.addEventListener) { 29 element.addEventListener(method, func, false); 30 } else if (element.attachEvent) { 31 element.attachEvent("on" + method, func); 32 } 33 }; 34 35 var _removeEventHandler = function(element, method, func) { //注销事件 36 if (element.removeEventListener) { 37 element.removeEventListener(method, func, false); 38 } else if (element.detachEvent) { 39 element.detachEvent("on" + method, func); 40 } 41 }; 42 43 var _inArray = function(elem, array) { 44 if (array.indexOf) { 45 return array.indexOf(elem); 46 } 47 for (var i = 0, length = array.length; i < length; i++) { 48 if (array[i] === elem) { 49 return i; 50 } 51 } 52 return -1; 53 }; 54 55 56 var _addClass = function(element, value) { 57 if (element.addClass) { 58 element.addClass(value); 59 return element; 60 } 61 62 if (value && typeof value === "string") { 63 var classNames = (value || "").split(/\s+/); //可以一次添加多个classname 64 if (element.nodeType === 1) { 65 if (!element.className) { 66 element.className = value; 67 } else { 68 69 var className = " " + element.className + " ", setClass = element.className; 70 for (var c = 0, cl = classNames.length; c < cl; c++) { 71 if (className.indexOf(" " + classNames[c] + " ") < 0) { 72 setClass += " " + classNames[c]; 73 } 74 } 75 element.className = setClass.replace(/^\s+|\s+$/g, ""); 76 77 78 } 79 } 80 } 81 82 return element; 83 }; 84 85 var _removeClass = function(element, value) { 86 if (element.removeClass) { 87 element.removeClass(value); 88 return element; 89 } 90 if (value && typeof value === "string" || value === undefined) { 91 var classNames = (value || "").split(/\s+/); 92 if (element.nodeType === 1 && element.className) { 93 if (value) { 94 var className = (" " + element.className + " ").replace(/[\n\t]/g, " "); 95 for (var c = 0, cl = classNames.length; c < cl; c++) { 96 className = className.replace(" " + classNames[c] + " ", " "); 97 } 98 element.className = className.replace(/^\s+|\s+$/g, ""); 99 } else { 100 element.className = ""; 101 } 102 } 103 } 104 return element; 105 }; 106 107 var _getDOMObjectPosition = function(obj) { 108 var info = { 109 left: 0, 110 top: 0, 111 width: obj.width || obj.offsetWidth || 0, 112 height: obj.height || obj.offsetHeight || 0, 113 zIndex: 9999 114 }; 115 var zi = _getStyle(obj, "zIndex"); 116 if (zi && zi != "auto") { 117 info.zIndex = parseInt(zi, 10); 118 } 119 while (obj) { 120 var borderLeftWidth = parseInt(_getStyle(obj, "borderLeftWidth"), 10); 121 var borderTopWidth = parseInt(_getStyle(obj, "borderTopWidth"), 10); 122 info.left += isNaN(obj.offsetLeft) ? 0 : obj.offsetLeft; 123 info.left += isNaN(borderLeftWidth) ? 0 : borderLeftWidth; 124 info.top += isNaN(obj.offsetTop) ? 0 : obj.offsetTop; 125 info.top += isNaN(borderTopWidth) ? 0 : borderTopWidth; 126 obj = obj.offsetParent; 127 } 128 return info; 129 }; 130 131 var _elementMouseOver = function(event) { //mouseover以后关联为当前元素 132 if (!ZeroClipboard.prototype._singleton) return; 133 if (!event) { 134 event = window.event; 135 } 136 var target; 137 if (this !== window) { 138 target = this; 139 } else if (event.target) { 140 target = event.target; 141 } else if (event.srcElement) { 142 target = event.srcElement; 143 } 144 ZeroClipboard.prototype._singleton.setCurrent(target); 145 }; 146 147 var _noCache = function(path) { //不要缓存 148 return (path.indexOf("?") >= 0 ? "&" : "?") + "nocache=" + (new Date).getTime(); 149 }; 150 151 var _vars = function(options) { 152 var str = []; 153 if (options.trustedDomains) { 154 if (options.trustedDomains.length) { 155 str.push("trustedDomain=" + options.trustedDomains.join(",")); 156 } else { 157 str.push("trustedDomain=" + options.trustedDomains); 158 } 159 } 160 return str.join("&"); 161 }; 162 163 164 165 var _prepGlue = function(elements) { //_prep preparation数组化 166 if (typeof elements === "string") throw new TypeError("ZeroClipboard doesn't accept query strings."); 167 if (!elements.length) return [ elements ]; 168 return elements; 169 }; 170 171 var ZeroClipboard = function(elements, options) { 172 if (elements) (ZeroClipboard.prototype._singleton || this).glue(elements); 173 if (ZeroClipboard.prototype._singleton) return ZeroClipboard.prototype._singleton; 174 ZeroClipboard.prototype._singleton = this; 175 this.options = {}; 176 for (var kd in _defaults) this.options[kd] = _defaults[kd]; 177 for (var ko in options) this.options[ko] = options[ko]; 178 this.handlers = {}; //存处理函数 179 if (ZeroClipboard.detectFlashSupport()) _bridge(); 180 }; 181 182 var currentElement, gluedElements = []; //当前关联元素 所有关联元素 183 184 ZeroClipboard.prototype.getCurrent = function(element) { 185 return currentElement; 186 }; 187 188 189 ZeroClipboard.prototype.setCurrent = function(element) { 190 currentElement = element; 191 this.reposition(); 192 this.setText(this.options.text || element.getAttribute("data-clipboard-text")); 193 if (element.getAttribute("title")) { 194 this.setTitle(element.getAttribute("title")); 195 } 196 this.setHandCursor(_getStyle(element, "cursor") == "pointer"); 197 }; 198 199 ZeroClipboard.prototype.setText = function(newText) { 200 if (newText && newText !== "") { 201 this.options.text = newText; 202 if (this.ready()) this.flashBridge.setText(newText); 203 } 204 }; 205 206 ZeroClipboard.prototype.setTitle = function(newTitle) { 207 if (newTitle && newTitle !== "") this.htmlBridge.setAttribute("title", newTitle); 208 }; 209 210 ZeroClipboard.prototype.setSize = function(width, height) { 211 if (this.ready()) this.flashBridge.setSize(width, height); 212 }; 213 214 ZeroClipboard.prototype.setHandCursor = function(enabled) { 215 if (this.ready()) this.flashBridge.setHandCursor(enabled); 216 }; 217 218 ZeroClipboard.version = "1.1.6"; 219 220 var _defaults = { 221 moviePath: "ZeroClipboard.swf", 222 trustedDomains: null, //信任;信托;照管 223 text: '', 224 hoverClass: "zeroclipboard-is-hover", 225 activeClass: "zeroclipboard-is-active" 226 }; 227 228 ZeroClipboard.setDefaults = function(options) { 229 for (var ko in options) _defaults[ko] = options[ko]; 230 }; 231 232 ZeroClipboard.destroy = function() { 233 ZeroClipboard.prototype._singleton.unglue(gluedElements); 234 var bridge = ZeroClipboard.prototype._singleton.htmlBridge; 235 bridge.parentNode.removeChild(bridge); 236 delete ZeroClipboard.prototype._singleton; 237 }; 238 239 ZeroClipboard.detectFlashSupport = function() { 240 var hasFlash = false; 241 try { 242 if (new ActiveXObject("ShockwaveFlash.ShockwaveFlash")) { 243 hasFlash = true; 244 } 245 } catch (error) { 246 if (navigator.mimeTypes["application/x-shockwave-flash"]) { 247 hasFlash = true; 248 } 249 } 250 return hasFlash; 251 }; 252 253 var _bridge = function() { 254 var client = ZeroClipboard.prototype._singleton; 255 client.htmlBridge = document.getElementById("global-zeroclipboard-html-bridge"); 256 if (client.htmlBridge) { 257 client.flashBridge = document["global-zeroclipboard-flash-bridge"]; 258 return; 259 } 260 var html = ' <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" id="global-zeroclipboard-flash-bridge" width="100%" height="100%"> <param name="movie" value="' + client.options.moviePath + _noCache(client.options.moviePath) + '"/> <param name="allowScriptAccess" value="always" /> <param name="scale" value="exactfit"> <param name="loop" value="false" /> <param name="menu" value="false" /> <param name="quality" value="best" /> <param name="bgcolor" value="#ffffff" /> <param name="wmode" value="transparent"/> <param name="flashvars" value="' + _vars(client.options) + '"/> <embed src="' + client.options.moviePath + _noCache(client.options.moviePath) + '" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="100%" height="100%" name="global-zeroclipboard-flash-bridge" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" wmode="transparent" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="' + _vars(client.options) + '" scale="exactfit"> </embed> </object>'; 261 client.htmlBridge = document.createElement("div"); 262 client.htmlBridge.id = "global-zeroclipboard-html-bridge"; 263 client.htmlBridge.setAttribute("class", "global-zeroclipboard-container"); 264 client.htmlBridge.setAttribute("data-clipboard-ready", false); 265 client.htmlBridge.style.position = "absolute"; 266 client.htmlBridge.style.left = "-9999px"; 267 client.htmlBridge.style.top = "-9999px"; 268 client.htmlBridge.style.width = "15px"; 269 client.htmlBridge.style.height = "15px"; 270 client.htmlBridge.style.zIndex = "9999"; 271 client.htmlBridge.innerHTML = html; 272 document.body.appendChild(client.htmlBridge); 273 client.flashBridge = document["global-zeroclipboard-flash-bridge"]; 274 }; 275 276 ZeroClipboard.prototype.resetBridge = function() { 277 this.htmlBridge.style.left = "-9999px"; 278 this.htmlBridge.style.top = "-9999px"; 279 this.htmlBridge.removeAttribute("title"); 280 this.htmlBridge.removeAttribute("data-clipboard-text"); 281 _removeClass(currentElement, this.options.activeClass); 282 currentElement = null; 283 }; 284 285 ZeroClipboard.prototype.ready = function() { 286 var ready = this.htmlBridge.getAttribute("data-clipboard-ready"); 287 return ready === "true" || ready === true; 288 }; 289 290 ZeroClipboard.prototype.reposition = function() { //可调整位置 291 if (!currentElement) return false; 292 var pos = _getDOMObjectPosition(currentElement); 293 this.htmlBridge.style.top = pos.top + "px"; 294 this.htmlBridge.style.left = pos.left + "px"; 295 this.htmlBridge.style.width = pos.width + "px"; 296 this.htmlBridge.style.height = pos.height + "px"; 297 this.htmlBridge.style.zIndex = pos.zIndex + 1; 298 this.setSize(pos.width, pos.height); 299 }; 300 301 ZeroClipboard.dispatch = function(eventName, args) { 302 ZeroClipboard.prototype._singleton.receiveEvent(eventName, args); 303 }; 304 305 ZeroClipboard.prototype.on = function(eventName, func) { 306 var events = eventName.toString().split(/\s/g); //可以同时注册多个事件 307 for (var i = 0; i < events.length; i++) { 308 eventName = events[i].toLowerCase().replace(/^on/, ""); 309 if (!this.handlers[eventName]) this.handlers[eventName] = func; 310 } 311 if (this.handlers.noflash && !ZeroClipboard.detectFlashSupport()) { 312 this.receiveEvent("onNoFlash", null); 313 } 314 }; 315 316 ZeroClipboard.prototype.addEventListener = ZeroClipboard.prototype.on; 317 318 ZeroClipboard.prototype.receiveEvent = function(eventName, args) { //receive收到;接到;接纳;接待 319 eventName = eventName.toString().toLowerCase().replace(/^on/, ""); 320 var element = currentElement; 321 switch (eventName) { 322 case "load": 323 if (args && parseFloat(args.flashVersion.replace(",", ".").replace(/[^0-9\.]/gi, "")) < 10) { 324 this.receiveEvent("onWrongFlash", { 325 flashVersion: args.flashVersion 326 }); 327 return; 328 } 329 this.htmlBridge.setAttribute("data-clipboard-ready", true); 330 break; 331 case "mouseover": 332 _addClass(element, this.options.hoverClass); //element 绑定元素 333 break; 334 case "mouseout": 335 _removeClass(element, this.options.hoverClass); 336 this.resetBridge(); 337 break; 338 case "mousedown": 339 _addClass(element, this.options.activeClass); 340 break; 341 case "mouseup": 342 _removeClass(element, this.options.activeClass); 343 break; 344 case "complete": 345 this.options.text = null; 346 break; 347 } 348 349 if (this.handlers[eventName]) { 350 var func = this.handlers[eventName]; 351 if (typeof func == "function") { 352 func.call(element, this, args); 353 } else if (typeof func == "string") { 354 window[func].call(element, this, args); 355 } 356 } 357 }; 358 359 360 ZeroClipboard.prototype.glue = function(elements) { //glue胶合;紧附于 361 elements = _prepGlue(elements); 362 for (var i = 0; i < elements.length; i++) { 363 if (_inArray(elements[i], gluedElements) == -1) { 364 gluedElements.push(elements[i]); 365 _addEventHandler(elements[i], "mouseover", _elementMouseOver); 366 } 367 } 368 }; 369 370 ZeroClipboard.prototype.unglue = function(elements) { 371 elements = _prepGlue(elements); 372 for (var i = 0; i < elements.length; i++) { 373 _removeEventHandler(elements[i], "mouseover", _elementMouseOver); 374 var arrayIndex = _inArray(elements[i], gluedElements); 375 if (arrayIndex != -1) gluedElements.splice(arrayIndex, 1); 376 } 377 }; 378 379 if (typeof module !== "undefined") { 380 module.exports = ZeroClipboard; 381 } else { 382 window.ZeroClipboard = ZeroClipboard; 383 } 384 385 })();