├── LICENSE
├── README.md
├── ZeroClipboard.swf
├── bower.json
└── jquery.zclip.js
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011, SteamDev
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | jquery-zclip
2 | ============
3 |
4 | jQuery ZeroClipboard
5 |
6 | Copyright 2011, SteamDev
7 |
8 | Originally forked from: http://steamdev.com/zclip
9 |
10 | Released under the MIT license, see [LICENSE](LICENSE).
11 |
12 | ### Usage
13 |
14 | ```javascript
15 | jQuery({selector}).zclip({options});
16 | ```
17 |
18 | - ```selector```: any valid jquery object selector
19 | - ```options```: Object, see section below.
20 |
21 |
22 | ### Options
23 |
24 | Option | Default value | Description
25 | ------------- | ------------------------- | ------------
26 | path | ```'ZeroClipboard.swf'``` | The path to ZeroClipboard.swf
27 | copy | ```null``` | String to copy or function that returns a string to copy
28 | afterCopy | ```null``` | Function to execute after copying
29 | beforeCopy | ```null``` | Function to execute before copying
30 | clickAfter | ```true``` | Relay a click event to the element bound to after copying
31 | setHandCursor | ```true``` | Set the cursor to pointer
32 | setCSSEffects | ```true``` | Add ```hover``` and ```active``` classes to the element bound to
33 |
34 | NOTE: Since v1.1.5, default options can be set globally by setting the value of ```ZeroclipBoard.defaults.{option}```.
35 |
--------------------------------------------------------------------------------
/ZeroClipboard.swf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/patricklodder/jquery-zclip/39e8f553a29006aa91fe1b7c5d0d7f559276e180/ZeroClipboard.swf
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-zclip",
3 | "description": "JQuery wrapper library for ZeroClipboard. Provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie.",
4 | "version": "1.1.5",
5 | "main": ["./jquery.zclip.js", "./ZeroClipboard.swf"],
6 | "keywords": ["flash","clipboard","copy","cut","paste","zclip","clip","clippy", "zeroclipboard", "jquery"],
7 | "license": "https://github.com/patricklodder/jquery-zclip/blob/master/LICENSE",
8 | "authors": [{"name":"SteamDev","url":"http://www.steamdev.com/zclip/"},{"name":"Patrick Lodder","url":"https://github.com/patricklodder"}],
9 | "homepage": "https://github.com/patricklodder/jquery-zclip",
10 | "repository": {"type":"git","url":"https://github.com/patricklodder/jquery-zclip.git"},
11 | "location": "git://github.com/patricklodder/jquery-zclip.git"
12 | }
13 |
--------------------------------------------------------------------------------
/jquery.zclip.js:
--------------------------------------------------------------------------------
1 | /*
2 | * zClip :: jQuery ZeroClipboard v1.1.5
3 | * Originally forked from: http://steamdev.com/zclip
4 | *
5 | * Copyright 2011, SteamDev
6 | *
7 | * Released under the MIT license.
8 | * https://github.com/patricklodder/jquery-zclip/blob/master/LICENSE
9 | */
10 |
11 | (function (jQuery) {
12 |
13 | jQuery.fn.zclip = function (params) {
14 |
15 | if (typeof params == "object" && !params.length) {
16 |
17 | var settings = jQuery.extend({}, ZeroClipboard.defaults, params);
18 |
19 | return this.each(function () {
20 |
21 | var o = jQuery(this);
22 |
23 | if (o.is(':visible') && (typeof settings.copy == 'string' || jQuery.isFunction(settings.copy))) {
24 |
25 | ZeroClipboard.setMoviePath(settings.path);
26 | var clip = new ZeroClipboard.Client();
27 |
28 | if (jQuery.isFunction(settings.copy)) {
29 | o.bind('zClip_copy', settings.copy);
30 | }
31 |
32 | if (jQuery.isFunction(settings.beforeCopy)) {
33 | o.bind('zClip_beforeCopy', settings.beforeCopy);
34 | }
35 |
36 | if (jQuery.isFunction(settings.afterCopy)) {
37 | o.bind('zClip_afterCopy', settings.afterCopy);
38 | }
39 |
40 | clip.setHandCursor(settings.setHandCursor);
41 |
42 | clip.setCSSEffects(settings.setCSSEffects);
43 |
44 | clip.addEventListener('mouseOver', function (client) {
45 | o.trigger('mouseenter');
46 | });
47 |
48 | clip.addEventListener('mouseOut', function (client) {
49 | o.trigger('mouseleave');
50 | });
51 |
52 | clip.addEventListener('mouseDown', function (client) {
53 |
54 | o.trigger('mousedown');
55 |
56 | if (jQuery.isFunction(settings.beforeCopy)) {
57 | o.trigger('zClip_beforeCopy');
58 | }
59 |
60 | if (!jQuery.isFunction(settings.copy)) {
61 | clip.setText(settings.copy);
62 | } else {
63 | clip.setText(o.triggerHandler('zClip_copy'));
64 | }
65 |
66 | });
67 |
68 | clip.addEventListener('complete', function (client, text) {
69 |
70 | if (jQuery.isFunction(settings.afterCopy)) {
71 |
72 | o.trigger('zClip_afterCopy');
73 |
74 | } else {
75 | if (text.length > 500) {
76 | text = text.substr(0, 500) + "...\n\n(" + (text.length - 500) + " characters not shown)";
77 | }
78 |
79 | o.removeClass('hover');
80 | alert("Copied text to clipboard:\n\n " + text);
81 | }
82 |
83 | if (settings.clickAfter) {
84 | o.trigger('click');
85 | }
86 |
87 | });
88 |
89 | clip.glue(o[0], o.parent()[0]);
90 |
91 | jQuery(window).bind('load resize', function () {clip.reposition();});
92 |
93 | }
94 |
95 | });
96 |
97 | } else if (typeof params == "string") {
98 |
99 | return this.each(function () {
100 |
101 | var o = jQuery(this);
102 |
103 | params = params.toLowerCase();
104 | var zclipId = o.data('zclipId');
105 | var clipElm = jQuery('#' + zclipId + '.zclip');
106 | var clientId = clipElm.attr('id').replace(/^.*_/g, '') || null;
107 |
108 | if (params == "remove") {
109 |
110 | clipElm.remove();
111 | o.removeClass('active hover');
112 | o.unbind('zClip_copy');
113 | o.unbind('zClip_beforeCopy');
114 | o.unbind('zClip_afterCopy');
115 | ZeroClipboard.unregister(clientId);
116 |
117 | } else if (params == "hide") {
118 |
119 | clipElm.hide();
120 | o.removeClass('active hover');
121 |
122 | } else if (params == "show") {
123 |
124 | clipElm.show();
125 |
126 | }
127 |
128 | });
129 |
130 | }
131 |
132 | };
133 |
134 | })(jQuery);
135 |
136 | // ZeroClipboard
137 | // Simple Set Clipboard System
138 | // Author: Joseph Huckaby
139 | var ZeroClipboard = {
140 |
141 | version: "1.0.7",
142 | clients: {},
143 | // registered upload clients on page, indexed by id
144 | moviePath: 'ZeroClipboard.swf',
145 | // URL to movie
146 | nextId: 1,
147 | // ID of next movie
148 |
149 | defaults: {
150 | path: 'ZeroClipboard.swf',
151 | clickAfter: true,
152 | setHandCursor: true,
153 | setCSSEffects: true,
154 |
155 | copy: null,
156 | // a string or function that returns string
157 |
158 | beforeCopy: null,
159 | afterCopy: null
160 | },
161 |
162 | jQuery: function (thingy) {
163 | // simple DOM lookup utility function
164 | if (typeof(thingy) == 'string') thingy = document.getElementById(thingy);
165 | if (!thingy.addClass) {
166 | // extend element with a few useful methods
167 | thingy.hide = function () {
168 | this.style.display = 'none';
169 | };
170 | thingy.show = function () {
171 | this.style.display = '';
172 | };
173 | thingy.addClass = function (name) {
174 | this.removeClass(name);
175 | this.className += ' ' + name;
176 | };
177 | thingy.removeClass = function (name) {
178 | var classes = this.className.split(/\s+/);
179 | var idx = -1;
180 | for (var k = 0; k < classes.length; k++) {
181 | if (classes[k] == name) {
182 | idx = k;
183 | k = classes.length;
184 | }
185 | }
186 | if (idx > -1) {
187 | classes.splice(idx, 1);
188 | this.className = classes.join(' ');
189 | }
190 | return this;
191 | };
192 | thingy.hasClass = function (name) {
193 | return !!this.className.match(new RegExp("\\s*" + name + "\\s*"));
194 | };
195 | }
196 | return thingy;
197 | },
198 |
199 | setMoviePath: function (path) {
200 | // set path to ZeroClipboard.swf
201 | this.moviePath = path;
202 | },
203 |
204 | dispatch: function (id, eventName, args) {
205 | // receive event from flash movie, send to client
206 | var client = this.clients[id];
207 | if (client) {
208 | client.receiveEvent(eventName, args);
209 | }
210 | },
211 |
212 | register: function (id, client) {
213 | // register new client to receive events
214 | this.clients[id] = client;
215 | },
216 |
217 | unregister: function (id) {
218 | if (typeof(id) === 'number' && this.clients.hasOwnProperty(id)) {
219 | delete this.clients[id];
220 | }
221 | },
222 |
223 | getDOMObjectPosition: function (obj, stopObj) {
224 | // get absolute coordinates for dom element
225 | var info = {
226 | left: 0,
227 | top: 0,
228 | width: obj.width ? obj.width : obj.offsetWidth,
229 | height: obj.height ? obj.height : obj.offsetHeight
230 | };
231 |
232 | if (obj && (obj != stopObj)) {
233 | info.left += obj.offsetLeft;
234 | info.top += obj.offsetTop;
235 | }
236 |
237 | return info;
238 | },
239 |
240 | Client: function (elem) {
241 | // constructor for new simple upload client
242 | this.handlers = {};
243 |
244 | // unique ID
245 | this.id = ZeroClipboard.nextId++;
246 | this.movieId = 'ZeroClipboardMovie_' + this.id;
247 |
248 | // register client with singleton to receive flash events
249 | ZeroClipboard.register(this.id, this);
250 |
251 | // create movie
252 | if (elem) this.glue(elem);
253 | }
254 | };
255 |
256 | ZeroClipboard.Client.prototype = {
257 |
258 | id: 0,
259 | // unique ID for us
260 | ready: false,
261 | // whether movie is ready to receive events or not
262 | movie: null,
263 | // reference to movie object
264 | clipText: '',
265 | // text to copy to clipboard
266 | handCursorEnabled: true,
267 | // whether to show hand cursor, or default pointer cursor
268 | cssEffects: true,
269 | // enable CSS mouse effects on dom container
270 | handlers: null,
271 | // user event handlers
272 | glue: function (elem, appendElem, stylesToAdd) {
273 | // glue to DOM element
274 | // elem can be ID or actual DOM element object
275 | this.domElement = ZeroClipboard.jQuery(elem);
276 |
277 | // float just above object, or zIndex 99 if dom element isn't set
278 | var zIndex = 99;
279 | if (this.domElement.style.zIndex) {
280 | zIndex = parseInt(this.domElement.style.zIndex, 10) + 1;
281 | }
282 |
283 | if (typeof(appendElem) == 'string') {
284 | appendElem = ZeroClipboard.jQuery(appendElem);
285 | } else if (typeof(appendElem) == 'undefined') {
286 | appendElem = document.getElementsByTagName('body')[0];
287 | }
288 |
289 | // find X/Y position of domElement
290 | var box = ZeroClipboard.getDOMObjectPosition(this.domElement, appendElem);
291 |
292 | // create floating DIV above element
293 | this.div = document.createElement('div');
294 | this.div.className = "zclip";
295 | this.div.id = "zclip-" + this.movieId;
296 | jQuery(this.domElement).data('zclipId', 'zclip-' + this.movieId);
297 | var style = this.div.style;
298 | style.position = 'absolute';
299 | style.left = '' + box.left + 'px';
300 | style.top = '' + box.top + 'px';
301 | style.width = '' + box.width + 'px';
302 | style.height = '' + box.height + 'px';
303 | style.zIndex = zIndex;
304 |
305 | if (typeof(stylesToAdd) == 'object') {
306 | for (var addedStyle in stylesToAdd) {
307 | style[addedStyle] = stylesToAdd[addedStyle];
308 | }
309 | }
310 |
311 | // style.backgroundColor = '#f00'; // debug
312 | appendElem.appendChild(this.div);
313 |
314 | this.div.innerHTML = this.getHTML(box.width, box.height);
315 | },
316 |
317 | getHTML: function (width, height) {
318 | // return HTML for movie
319 | var html = '';
320 | var flashvars = 'id=' + this.id + '&width=' + width + '&height=' + height;
321 |
322 | if (navigator.userAgent.match(/MSIE/)) {
323 | // IE gets an OBJECT tag
324 | var protocol = location.href.match(/^https/i) ? 'https://' : 'http://';
325 | html += '';
326 | } else {
327 | // all other browsers get an EMBED tag
328 | html += '';
329 | }
330 | return html;
331 | },
332 |
333 | hide: function () {
334 | // temporarily hide floater offscreen
335 | if (this.div) {
336 | this.div.style.left = '-2000px';
337 | }
338 | },
339 |
340 | show: function () {
341 | // show ourselves after a call to hide()
342 | this.reposition();
343 | },
344 |
345 | destroy: function () {
346 | // destroy control and floater
347 | if (this.domElement && this.div) {
348 | this.hide();
349 | this.div.innerHTML = '';
350 |
351 | var body = document.getElementsByTagName('body')[0];
352 | try {
353 | body.removeChild(this.div);
354 | } catch (e) {
355 | //do nothing
356 | }
357 |
358 | this.domElement = null;
359 | this.div = null;
360 | }
361 | },
362 |
363 | reposition: function (elem) {
364 | // reposition our floating div, optionally to new container
365 | // warning: container CANNOT change size, only position
366 | if (elem) {
367 | this.domElement = ZeroClipboard.jQuery(elem);
368 | if (!this.domElement) this.hide();
369 | }
370 |
371 | if (this.domElement && this.div) {
372 | var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
373 | var style = this.div.style;
374 | style.left = '' + box.left + 'px';
375 | style.top = '' + box.top + 'px';
376 | }
377 | },
378 |
379 | setText: function (newText) {
380 | // set text to be copied to clipboard
381 | this.clipText = newText;
382 | if (this.ready) {
383 | this.movie.setText(newText);
384 | }
385 | },
386 |
387 | addEventListener: function (eventName, func) {
388 | // add user event listener for event
389 | // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel
390 | eventName = eventName.toString().toLowerCase().replace(/^on/, '');
391 | if (!this.handlers[eventName]) {
392 | this.handlers[eventName] = [];
393 | }
394 | this.handlers[eventName].push(func);
395 | },
396 |
397 | setHandCursor: function (enabled) {
398 | // enable hand cursor (true), or default arrow cursor (false)
399 | this.handCursorEnabled = enabled;
400 | if (this.ready) {
401 | this.movie.setHandCursor(enabled);
402 | }
403 | },
404 |
405 | setCSSEffects: function (enabled) {
406 | // enable or disable CSS effects on DOM container
407 | this.cssEffects = !! enabled;
408 | },
409 |
410 | receiveEvent: function (eventName, args) {
411 | // receive event from flash
412 | eventName = eventName.toString().toLowerCase().replace(/^on/, '');
413 |
414 | // special behavior for certain events
415 | switch (eventName) {
416 | case 'load':
417 | // movie claims it is ready, but in IE this isn't always the case...
418 | // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function
419 | this.movie = document.getElementById(this.movieId);
420 | var self = this;
421 |
422 | if (!this.movie) {
423 | setTimeout(function () {
424 | self.receiveEvent('load', null);
425 | }, 1);
426 | return;
427 | }
428 |
429 | // firefox on pc needs a "kick" in order to set these in certain cases
430 | if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {
431 | setTimeout(function () {
432 | self.receiveEvent('load', null);
433 | }, 100);
434 | this.ready = true;
435 | return;
436 | }
437 |
438 | this.ready = true;
439 | try {
440 | this.movie.setText(this.clipText);
441 | } catch (e) {}
442 | try {
443 | this.movie.setHandCursor(this.handCursorEnabled);
444 | } catch (e) {}
445 | break;
446 |
447 | case 'mouseover':
448 | if (this.domElement && this.cssEffects) {
449 | this.domElement.addClass('hover');
450 | if (this.recoverActive) {
451 | this.domElement.addClass('active');
452 | }
453 |
454 | }
455 | break;
456 |
457 | case 'mouseout':
458 | if (this.domElement && this.cssEffects) {
459 | this.recoverActive = false;
460 | if (this.domElement.hasClass('active')) {
461 | this.domElement.removeClass('active');
462 | this.recoverActive = true;
463 | }
464 | this.domElement.removeClass('hover');
465 |
466 | }
467 | break;
468 |
469 | case 'mousedown':
470 | if (this.domElement && this.cssEffects) {
471 | this.domElement.addClass('active');
472 | }
473 | break;
474 |
475 | case 'mouseup':
476 | if (this.domElement && this.cssEffects) {
477 | this.domElement.removeClass('active');
478 | this.recoverActive = false;
479 | }
480 | break;
481 | } // switch eventName
482 | if (this.handlers[eventName]) {
483 | for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {
484 | var func = this.handlers[eventName][idx];
485 |
486 | if (jQuery.isFunction(func)) {
487 | // actual function reference
488 | func(this, args);
489 | } else if ((typeof(func) == 'object') && (func.length == 2)) {
490 | // PHP style object + method, i.e. [myObject, 'myMethod']
491 | func[0][func[1]](this, args);
492 | } else if (typeof(func) == 'string') {
493 | // name of function
494 | window[func](this, args);
495 | }
496 | } // foreach event handler defined
497 | } // user defined handler for event
498 | }
499 |
500 | };
501 |
--------------------------------------------------------------------------------