sinatra-zero_clipboard 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +5 -0
- data/README.md +62 -0
- data/Rakefile +1 -0
- data/data/sinatra-zero_clipboard/assets/ZeroClipboard.js +365 -0
- data/data/sinatra-zero_clipboard/assets/ZeroClipboard.min.js +8 -0
- data/data/sinatra-zero_clipboard/assets/ZeroClipboard.swf +0 -0
- data/examples/sample_application.rb +79 -0
- data/lib/sinatra/zero_clipboard.rb +9 -0
- data/lib/sinatra/zero_clipboard/assets.rb +39 -0
- data/lib/sinatra/zero_clipboard/assets_helper.rb +16 -0
- data/lib/sinatra/zero_clipboard/version.rb +5 -0
- data/sinatra-zero_clipboard.gemspec +30 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/unit/sinatra/zero_clipboard/assets_helper_spec.rb +41 -0
- data/spec/unit/sinatra/zero_clipboard/assets_spec.rb +42 -0
- metadata +195 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
Copyright (c) 2013, Oliver Feldt <oliver.feldt@googlemail.com>
|
2
|
+
|
3
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
4
|
+
|
5
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/sinatra-zero_clipboard.png)](http://badge.fury.io/rb/sinatra-zero_clipboard)
|
2
|
+
# Sinatra::ZeroClipboard
|
3
|
+
|
4
|
+
**Sinatra::ZeroClipboard** is a sinatra plugin to access [ZeroClipboard](https://github.com/jonrohan/ZeroClipboard),
|
5
|
+
a **Flash-based cross-browser clipboard library**. Accessing the clipboard from pure Javascript is still disabled
|
6
|
+
on most browser due to security concerns, but sometimes needed in a project to improve user experience.
|
7
|
+
This gem should mitigate this nuisance until better options are broadly available.
|
8
|
+
|
9
|
+
## Requirements:
|
10
|
+
|
11
|
+
server-side:
|
12
|
+
* sinatra >= 1.4.2
|
13
|
+
|
14
|
+
client-side:
|
15
|
+
* Javascript & Flash-enabled Browser
|
16
|
+
|
17
|
+
## Usage:
|
18
|
+
|
19
|
+
#### Add gem to your Gemfile
|
20
|
+
gem "sinatra-zero_clipboard"
|
21
|
+
|
22
|
+
#### Require the gem
|
23
|
+
``` ruby
|
24
|
+
require 'sinatra/zero_clipboard'
|
25
|
+
```
|
26
|
+
|
27
|
+
#### Register helper for asset routes
|
28
|
+
``` ruby
|
29
|
+
class SampleApplication < Sinatra::Base
|
30
|
+
# ...
|
31
|
+
register Sinatra::ZeroClipboard::Assets
|
32
|
+
# ...
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
#### Add asset links to HTML head
|
37
|
+
``` haml
|
38
|
+
%html
|
39
|
+
%head
|
40
|
+
= zero_clipboard_assets
|
41
|
+
```
|
42
|
+
|
43
|
+
#### Add a button
|
44
|
+
``` haml
|
45
|
+
%button{ id: "clip_button", data-clipboard-text: "Default text", data-clipboard-target: "text_to_copy" }
|
46
|
+
%span Copy to Clipboard
|
47
|
+
```
|
48
|
+
|
49
|
+
#### Add a target
|
50
|
+
``` haml
|
51
|
+
%textarea{ id: "text_to_copy", rows: "3" cols: "40"} I'm getting copied, Yeah!
|
52
|
+
```
|
53
|
+
|
54
|
+
#### Add ZeroClipboard Javascript binding
|
55
|
+
``` javascript
|
56
|
+
var clip = new ZeroClipboard(document.getElementById("clip_button"), {
|
57
|
+
moviePath: "swf/ZeroClipboard.swf"
|
58
|
+
});
|
59
|
+
```
|
60
|
+
|
61
|
+
## More Information
|
62
|
+
For more ZeroClipboard Javascript options look [here](https://github.com/jonrohan/ZeroClipboard)
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,365 @@
|
|
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.7
|
8
|
+
*/(function() {
|
9
|
+
"use strict";
|
10
|
+
var _getStyle = function(el, prop) {
|
11
|
+
var y = el.style[prop];
|
12
|
+
if (el.currentStyle) y = el.currentStyle[prop]; else if (window.getComputedStyle) y = document.defaultView.getComputedStyle(el, null).getPropertyValue(prop);
|
13
|
+
if (y == "auto" && prop == "cursor") {
|
14
|
+
var possiblePointers = [ "a" ];
|
15
|
+
for (var i = 0; i < possiblePointers.length; i++) {
|
16
|
+
if (el.tagName.toLowerCase() == possiblePointers[i]) {
|
17
|
+
return "pointer";
|
18
|
+
}
|
19
|
+
}
|
20
|
+
}
|
21
|
+
return y;
|
22
|
+
};
|
23
|
+
var _elementMouseOver = function(event) {
|
24
|
+
if (!ZeroClipboard.prototype._singleton) return;
|
25
|
+
if (!event) {
|
26
|
+
event = window.event;
|
27
|
+
}
|
28
|
+
var target;
|
29
|
+
if (this !== window) {
|
30
|
+
target = this;
|
31
|
+
} else if (event.target) {
|
32
|
+
target = event.target;
|
33
|
+
} else if (event.srcElement) {
|
34
|
+
target = event.srcElement;
|
35
|
+
}
|
36
|
+
ZeroClipboard.prototype._singleton.setCurrent(target);
|
37
|
+
};
|
38
|
+
var _addEventHandler = function(element, method, func) {
|
39
|
+
if (element.addEventListener) {
|
40
|
+
element.addEventListener(method, func, false);
|
41
|
+
} else if (element.attachEvent) {
|
42
|
+
element.attachEvent("on" + method, func);
|
43
|
+
}
|
44
|
+
};
|
45
|
+
var _removeEventHandler = function(element, method, func) {
|
46
|
+
if (element.removeEventListener) {
|
47
|
+
element.removeEventListener(method, func, false);
|
48
|
+
} else if (element.detachEvent) {
|
49
|
+
element.detachEvent("on" + method, func);
|
50
|
+
}
|
51
|
+
};
|
52
|
+
var _addClass = function(element, value) {
|
53
|
+
if (element.addClass) {
|
54
|
+
element.addClass(value);
|
55
|
+
return element;
|
56
|
+
}
|
57
|
+
if (value && typeof value === "string") {
|
58
|
+
var classNames = (value || "").split(/\s+/);
|
59
|
+
if (element.nodeType === 1) {
|
60
|
+
if (!element.className) {
|
61
|
+
element.className = value;
|
62
|
+
} else {
|
63
|
+
var className = " " + element.className + " ", setClass = element.className;
|
64
|
+
for (var c = 0, cl = classNames.length; c < cl; c++) {
|
65
|
+
if (className.indexOf(" " + classNames[c] + " ") < 0) {
|
66
|
+
setClass += " " + classNames[c];
|
67
|
+
}
|
68
|
+
}
|
69
|
+
element.className = setClass.replace(/^\s+|\s+$/g, "");
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
73
|
+
return element;
|
74
|
+
};
|
75
|
+
var _removeClass = function(element, value) {
|
76
|
+
if (element.removeClass) {
|
77
|
+
element.removeClass(value);
|
78
|
+
return element;
|
79
|
+
}
|
80
|
+
if (value && typeof value === "string" || value === undefined) {
|
81
|
+
var classNames = (value || "").split(/\s+/);
|
82
|
+
if (element.nodeType === 1 && element.className) {
|
83
|
+
if (value) {
|
84
|
+
var className = (" " + element.className + " ").replace(/[\n\t]/g, " ");
|
85
|
+
for (var c = 0, cl = classNames.length; c < cl; c++) {
|
86
|
+
className = className.replace(" " + classNames[c] + " ", " ");
|
87
|
+
}
|
88
|
+
element.className = className.replace(/^\s+|\s+$/g, "");
|
89
|
+
} else {
|
90
|
+
element.className = "";
|
91
|
+
}
|
92
|
+
}
|
93
|
+
}
|
94
|
+
return element;
|
95
|
+
};
|
96
|
+
var _getDOMObjectPosition = function(obj) {
|
97
|
+
var info = {
|
98
|
+
left: 0,
|
99
|
+
top: 0,
|
100
|
+
width: obj.width || obj.offsetWidth || 0,
|
101
|
+
height: obj.height || obj.offsetHeight || 0,
|
102
|
+
zIndex: 9999
|
103
|
+
};
|
104
|
+
var zi = _getStyle(obj, "zIndex");
|
105
|
+
if (zi && zi != "auto") {
|
106
|
+
info.zIndex = parseInt(zi, 10);
|
107
|
+
}
|
108
|
+
while (obj) {
|
109
|
+
var borderLeftWidth = parseInt(_getStyle(obj, "borderLeftWidth"), 10);
|
110
|
+
var borderTopWidth = parseInt(_getStyle(obj, "borderTopWidth"), 10);
|
111
|
+
info.left += isNaN(obj.offsetLeft) ? 0 : obj.offsetLeft;
|
112
|
+
info.left += isNaN(borderLeftWidth) ? 0 : borderLeftWidth;
|
113
|
+
info.top += isNaN(obj.offsetTop) ? 0 : obj.offsetTop;
|
114
|
+
info.top += isNaN(borderTopWidth) ? 0 : borderTopWidth;
|
115
|
+
obj = obj.offsetParent;
|
116
|
+
}
|
117
|
+
return info;
|
118
|
+
};
|
119
|
+
var _noCache = function(path) {
|
120
|
+
var client = ZeroClipboard.prototype._singleton;
|
121
|
+
if (client.options.useNoCache) {
|
122
|
+
return (path.indexOf("?") >= 0 ? "&nocache=" : "?nocache=") + (new Date).getTime();
|
123
|
+
} else {
|
124
|
+
return "";
|
125
|
+
}
|
126
|
+
};
|
127
|
+
var _vars = function(options) {
|
128
|
+
var str = [];
|
129
|
+
if (options.trustedDomains) {
|
130
|
+
if (typeof options.trustedDomains === "string") {
|
131
|
+
str.push("trustedDomain=" + options.trustedDomains);
|
132
|
+
} else {
|
133
|
+
str.push("trustedDomain=" + options.trustedDomains.join(","));
|
134
|
+
}
|
135
|
+
}
|
136
|
+
return str.join("&");
|
137
|
+
};
|
138
|
+
var _inArray = function(elem, array) {
|
139
|
+
if (array.indexOf) {
|
140
|
+
return array.indexOf(elem);
|
141
|
+
}
|
142
|
+
for (var i = 0, length = array.length; i < length; i++) {
|
143
|
+
if (array[i] === elem) {
|
144
|
+
return i;
|
145
|
+
}
|
146
|
+
}
|
147
|
+
return -1;
|
148
|
+
};
|
149
|
+
var _prepGlue = function(elements) {
|
150
|
+
if (typeof elements === "string") throw new TypeError("ZeroClipboard doesn't accept query strings.");
|
151
|
+
if (!elements.length) return [ elements ];
|
152
|
+
return elements;
|
153
|
+
};
|
154
|
+
var ZeroClipboard = function(elements, options) {
|
155
|
+
if (elements) (ZeroClipboard.prototype._singleton || this).glue(elements);
|
156
|
+
if (ZeroClipboard.prototype._singleton) return ZeroClipboard.prototype._singleton;
|
157
|
+
ZeroClipboard.prototype._singleton = this;
|
158
|
+
this.options = {};
|
159
|
+
for (var kd in _defaults) this.options[kd] = _defaults[kd];
|
160
|
+
for (var ko in options) this.options[ko] = options[ko];
|
161
|
+
this.handlers = {};
|
162
|
+
if (ZeroClipboard.detectFlashSupport()) _bridge();
|
163
|
+
};
|
164
|
+
var currentElement, gluedElements = [];
|
165
|
+
ZeroClipboard.prototype.setCurrent = function(element) {
|
166
|
+
currentElement = element;
|
167
|
+
this.reposition();
|
168
|
+
if (element.getAttribute("title")) {
|
169
|
+
this.setTitle(element.getAttribute("title"));
|
170
|
+
}
|
171
|
+
this.setHandCursor(_getStyle(element, "cursor") == "pointer");
|
172
|
+
};
|
173
|
+
ZeroClipboard.prototype.setText = function(newText) {
|
174
|
+
if (newText && newText !== "") {
|
175
|
+
this.options.text = newText;
|
176
|
+
if (this.ready()) this.flashBridge.setText(newText);
|
177
|
+
}
|
178
|
+
};
|
179
|
+
ZeroClipboard.prototype.setTitle = function(newTitle) {
|
180
|
+
if (newTitle && newTitle !== "") this.htmlBridge.setAttribute("title", newTitle);
|
181
|
+
};
|
182
|
+
ZeroClipboard.prototype.setSize = function(width, height) {
|
183
|
+
if (this.ready()) this.flashBridge.setSize(width, height);
|
184
|
+
};
|
185
|
+
ZeroClipboard.prototype.setHandCursor = function(enabled) {
|
186
|
+
if (this.ready()) this.flashBridge.setHandCursor(enabled);
|
187
|
+
};
|
188
|
+
ZeroClipboard.version = "1.1.7";
|
189
|
+
var _defaults = {
|
190
|
+
moviePath: "ZeroClipboard.swf",
|
191
|
+
trustedDomains: null,
|
192
|
+
text: null,
|
193
|
+
hoverClass: "zeroclipboard-is-hover",
|
194
|
+
activeClass: "zeroclipboard-is-active",
|
195
|
+
allowScriptAccess: "sameDomain",
|
196
|
+
useNoCache: true
|
197
|
+
};
|
198
|
+
ZeroClipboard.setDefaults = function(options) {
|
199
|
+
for (var ko in options) _defaults[ko] = options[ko];
|
200
|
+
};
|
201
|
+
ZeroClipboard.destroy = function() {
|
202
|
+
ZeroClipboard.prototype._singleton.unglue(gluedElements);
|
203
|
+
var bridge = ZeroClipboard.prototype._singleton.htmlBridge;
|
204
|
+
bridge.parentNode.removeChild(bridge);
|
205
|
+
delete ZeroClipboard.prototype._singleton;
|
206
|
+
};
|
207
|
+
ZeroClipboard.detectFlashSupport = function() {
|
208
|
+
var hasFlash = false;
|
209
|
+
try {
|
210
|
+
if (new ActiveXObject("ShockwaveFlash.ShockwaveFlash")) {
|
211
|
+
hasFlash = true;
|
212
|
+
}
|
213
|
+
} catch (error) {
|
214
|
+
if (navigator.mimeTypes["application/x-shockwave-flash"]) {
|
215
|
+
hasFlash = true;
|
216
|
+
}
|
217
|
+
}
|
218
|
+
return hasFlash;
|
219
|
+
};
|
220
|
+
var _bridge = function() {
|
221
|
+
var client = ZeroClipboard.prototype._singleton;
|
222
|
+
var container = document.getElementById("global-zeroclipboard-html-bridge");
|
223
|
+
if (!container) {
|
224
|
+
var html = ' <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" id="global-zeroclipboard-flash-bridge" width="100%" height="100%"> <param name="movie" value="' + client.options.moviePath + _noCache(client.options.moviePath) + '"/> <param name="allowScriptAccess" value="' + client.options.allowScriptAccess + '"/> <param name="scale" value="exactfit"/> <param name="loop" value="false"/> <param name="menu" value="false"/> <param name="quality" value="best" /> <param name="bgcolor" value="#ffffff"/> <param name="wmode" value="transparent"/> <param name="flashvars" value="' + _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>';
|
225
|
+
container = document.createElement("div");
|
226
|
+
container.id = "global-zeroclipboard-html-bridge";
|
227
|
+
container.setAttribute("class", "global-zeroclipboard-container");
|
228
|
+
container.setAttribute("data-clipboard-ready", false);
|
229
|
+
container.style.position = "absolute";
|
230
|
+
container.style.left = "-9999px";
|
231
|
+
container.style.top = "-9999px";
|
232
|
+
container.style.width = "15px";
|
233
|
+
container.style.height = "15px";
|
234
|
+
container.style.zIndex = "9999";
|
235
|
+
container.innerHTML = html;
|
236
|
+
document.body.appendChild(container);
|
237
|
+
}
|
238
|
+
client.htmlBridge = container;
|
239
|
+
client.flashBridge = document["global-zeroclipboard-flash-bridge"] || container.children[0].lastElementChild;
|
240
|
+
};
|
241
|
+
ZeroClipboard.prototype.resetBridge = function() {
|
242
|
+
this.htmlBridge.style.left = "-9999px";
|
243
|
+
this.htmlBridge.style.top = "-9999px";
|
244
|
+
this.htmlBridge.removeAttribute("title");
|
245
|
+
this.htmlBridge.removeAttribute("data-clipboard-text");
|
246
|
+
_removeClass(currentElement, this.options.activeClass);
|
247
|
+
currentElement = null;
|
248
|
+
this.options.text = null;
|
249
|
+
};
|
250
|
+
ZeroClipboard.prototype.ready = function() {
|
251
|
+
var ready = this.htmlBridge.getAttribute("data-clipboard-ready");
|
252
|
+
return ready === "true" || ready === true;
|
253
|
+
};
|
254
|
+
ZeroClipboard.prototype.reposition = function() {
|
255
|
+
if (!currentElement) return false;
|
256
|
+
var pos = _getDOMObjectPosition(currentElement);
|
257
|
+
this.htmlBridge.style.top = pos.top + "px";
|
258
|
+
this.htmlBridge.style.left = pos.left + "px";
|
259
|
+
this.htmlBridge.style.width = pos.width + "px";
|
260
|
+
this.htmlBridge.style.height = pos.height + "px";
|
261
|
+
this.htmlBridge.style.zIndex = pos.zIndex + 1;
|
262
|
+
this.setSize(pos.width, pos.height);
|
263
|
+
};
|
264
|
+
ZeroClipboard.dispatch = function(eventName, args) {
|
265
|
+
ZeroClipboard.prototype._singleton.receiveEvent(eventName, args);
|
266
|
+
};
|
267
|
+
ZeroClipboard.prototype.on = function(eventName, func) {
|
268
|
+
var events = eventName.toString().split(/\s/g);
|
269
|
+
for (var i = 0; i < events.length; i++) {
|
270
|
+
eventName = events[i].toLowerCase().replace(/^on/, "");
|
271
|
+
if (!this.handlers[eventName]) this.handlers[eventName] = func;
|
272
|
+
}
|
273
|
+
if (this.handlers.noflash && !ZeroClipboard.detectFlashSupport()) {
|
274
|
+
this.receiveEvent("onNoFlash", null);
|
275
|
+
}
|
276
|
+
};
|
277
|
+
ZeroClipboard.prototype.addEventListener = ZeroClipboard.prototype.on;
|
278
|
+
ZeroClipboard.prototype.off = function(eventName, func) {
|
279
|
+
var events = eventName.toString().split(/\s/g);
|
280
|
+
for (var i = 0; i < events.length; i++) {
|
281
|
+
eventName = events[i].toLowerCase().replace(/^on/, "");
|
282
|
+
for (var event in this.handlers) {
|
283
|
+
if (event === eventName && this.handlers[event] === func) {
|
284
|
+
delete this.handlers[event];
|
285
|
+
}
|
286
|
+
}
|
287
|
+
}
|
288
|
+
};
|
289
|
+
ZeroClipboard.prototype.removeEventListener = ZeroClipboard.prototype.off;
|
290
|
+
ZeroClipboard.prototype.receiveEvent = function(eventName, args) {
|
291
|
+
eventName = eventName.toString().toLowerCase().replace(/^on/, "");
|
292
|
+
var element = currentElement;
|
293
|
+
switch (eventName) {
|
294
|
+
case "load":
|
295
|
+
if (args && parseFloat(args.flashVersion.replace(",", ".").replace(/[^0-9\.]/gi, "")) < 10) {
|
296
|
+
this.receiveEvent("onWrongFlash", {
|
297
|
+
flashVersion: args.flashVersion
|
298
|
+
});
|
299
|
+
return;
|
300
|
+
}
|
301
|
+
this.htmlBridge.setAttribute("data-clipboard-ready", true);
|
302
|
+
break;
|
303
|
+
case "mouseover":
|
304
|
+
_addClass(element, this.options.hoverClass);
|
305
|
+
break;
|
306
|
+
case "mouseout":
|
307
|
+
_removeClass(element, this.options.hoverClass);
|
308
|
+
this.resetBridge();
|
309
|
+
break;
|
310
|
+
case "mousedown":
|
311
|
+
_addClass(element, this.options.activeClass);
|
312
|
+
break;
|
313
|
+
case "mouseup":
|
314
|
+
_removeClass(element, this.options.activeClass);
|
315
|
+
break;
|
316
|
+
case "datarequested":
|
317
|
+
var targetId = element.getAttribute("data-clipboard-target"), targetEl = !targetId ? null : document.getElementById(targetId);
|
318
|
+
if (targetEl) {
|
319
|
+
var textContent = targetEl.value || targetEl.textContent || targetEl.innerText;
|
320
|
+
if (textContent) this.setText(textContent);
|
321
|
+
} else {
|
322
|
+
var defaultText = element.getAttribute("data-clipboard-text");
|
323
|
+
if (defaultText) this.setText(defaultText);
|
324
|
+
}
|
325
|
+
break;
|
326
|
+
case "complete":
|
327
|
+
this.options.text = null;
|
328
|
+
break;
|
329
|
+
}
|
330
|
+
if (this.handlers[eventName]) {
|
331
|
+
var func = this.handlers[eventName];
|
332
|
+
if (typeof func == "function") {
|
333
|
+
func.call(element, this, args);
|
334
|
+
} else if (typeof func == "string") {
|
335
|
+
window[func].call(element, this, args);
|
336
|
+
}
|
337
|
+
}
|
338
|
+
};
|
339
|
+
ZeroClipboard.prototype.glue = function(elements) {
|
340
|
+
elements = _prepGlue(elements);
|
341
|
+
for (var i = 0; i < elements.length; i++) {
|
342
|
+
if (_inArray(elements[i], gluedElements) == -1) {
|
343
|
+
gluedElements.push(elements[i]);
|
344
|
+
_addEventHandler(elements[i], "mouseover", _elementMouseOver);
|
345
|
+
}
|
346
|
+
}
|
347
|
+
};
|
348
|
+
ZeroClipboard.prototype.unglue = function(elements) {
|
349
|
+
elements = _prepGlue(elements);
|
350
|
+
for (var i = 0; i < elements.length; i++) {
|
351
|
+
_removeEventHandler(elements[i], "mouseover", _elementMouseOver);
|
352
|
+
var arrayIndex = _inArray(elements[i], gluedElements);
|
353
|
+
if (arrayIndex != -1) gluedElements.splice(arrayIndex, 1);
|
354
|
+
}
|
355
|
+
};
|
356
|
+
if (typeof module !== "undefined") {
|
357
|
+
module.exports = ZeroClipboard;
|
358
|
+
} else if (typeof define === "function" && define.amd) {
|
359
|
+
define(function() {
|
360
|
+
return ZeroClipboard;
|
361
|
+
});
|
362
|
+
} else {
|
363
|
+
window.ZeroClipboard = ZeroClipboard;
|
364
|
+
}
|
365
|
+
})();
|
@@ -0,0 +1,8 @@
|
|
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.7
|
8
|
+
*/(function(){"use strict";var a=function(a,b){var c=a.style[b];a.currentStyle?c=a.currentStyle[b]:window.getComputedStyle&&(c=document.defaultView.getComputedStyle(a,null).getPropertyValue(b));if(c=="auto"&&b=="cursor"){var d=["a"];for(var e=0;e<d.length;e++)if(a.tagName.toLowerCase()==d[e])return"pointer"}return c},b=function(a){if(!l.prototype._singleton)return;a||(a=window.event);var b;this!==window?b=this:a.target?b=a.target:a.srcElement&&(b=a.srcElement),l.prototype._singleton.setCurrent(b)},c=function(a,b,c){a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent&&a.attachEvent("on"+b,c)},d=function(a,b,c){a.removeEventListener?a.removeEventListener(b,c,!1):a.detachEvent&&a.detachEvent("on"+b,c)},e=function(a,b){if(a.addClass)return a.addClass(b),a;if(b&&typeof b=="string"){var c=(b||"").split(/\s+/);if(a.nodeType===1)if(!a.className)a.className=b;else{var d=" "+a.className+" ",e=a.className;for(var f=0,g=c.length;f<g;f++)d.indexOf(" "+c[f]+" ")<0&&(e+=" "+c[f]);a.className=e.replace(/^\s+|\s+$/g,"")}}return a},f=function(a,b){if(a.removeClass)return a.removeClass(b),a;if(b&&typeof b=="string"||b===undefined){var c=(b||"").split(/\s+/);if(a.nodeType===1&&a.className)if(b){var d=(" "+a.className+" ").replace(/[\n\t]/g," ");for(var e=0,f=c.length;e<f;e++)d=d.replace(" "+c[e]+" "," ");a.className=d.replace(/^\s+|\s+$/g,"")}else a.className=""}return a},g=function(b){var c={left:0,top:0,width:b.width||b.offsetWidth||0,height:b.height||b.offsetHeight||0,zIndex:9999},d=a(b,"zIndex");d&&d!="auto"&&(c.zIndex=parseInt(d,10));while(b){var e=parseInt(a(b,"borderLeftWidth"),10),f=parseInt(a(b,"borderTopWidth"),10);c.left+=isNaN(b.offsetLeft)?0:b.offsetLeft,c.left+=isNaN(e)?0:e,c.top+=isNaN(b.offsetTop)?0:b.offsetTop,c.top+=isNaN(f)?0:f,b=b.offsetParent}return c},h=function(a){var b=l.prototype._singleton;return b.options.useNoCache?(a.indexOf("?")>=0?"&nocache=":"?nocache=")+(new Date).getTime():""},i=function(a){var b=[];return a.trustedDomains&&(typeof a.trustedDomains=="string"?b.push("trustedDomain="+a.trustedDomains):b.push("trustedDomain="+a.trustedDomains.join(","))),b.join("&")},j=function(a,b){if(b.indexOf)return b.indexOf(a);for(var c=0,d=b.length;c<d;c++)if(b[c]===a)return c;return-1},k=function(a){if(typeof a=="string")throw new TypeError("ZeroClipboard doesn't accept query strings.");return a.length?a:[a]},l=function(a,b){a&&(l.prototype._singleton||this).glue(a);if(l.prototype._singleton)return l.prototype._singleton;l.prototype._singleton=this,this.options={};for(var c in o)this.options[c]=o[c];for(var d in b)this.options[d]=b[d];this.handlers={},l.detectFlashSupport()&&p()},m,n=[];l.prototype.setCurrent=function(b){m=b,this.reposition(),b.getAttribute("title")&&this.setTitle(b.getAttribute("title")),this.setHandCursor(a(b,"cursor")=="pointer")},l.prototype.setText=function(a){a&&a!==""&&(this.options.text=a,this.ready()&&this.flashBridge.setText(a))},l.prototype.setTitle=function(a){a&&a!==""&&this.htmlBridge.setAttribute("title",a)},l.prototype.setSize=function(a,b){this.ready()&&this.flashBridge.setSize(a,b)},l.prototype.setHandCursor=function(a){this.ready()&&this.flashBridge.setHandCursor(a)},l.version="1.1.7";var o={moviePath:"ZeroClipboard.swf",trustedDomains:null,text:null,hoverClass:"zeroclipboard-is-hover",activeClass:"zeroclipboard-is-active",allowScriptAccess:"sameDomain",useNoCache:!0};l.setDefaults=function(a){for(var b in a)o[b]=a[b]},l.destroy=function(){l.prototype._singleton.unglue(n);var a=l.prototype._singleton.htmlBridge;a.parentNode.removeChild(a),delete l.prototype._singleton},l.detectFlashSupport=function(){var a=!1;try{new ActiveXObject("ShockwaveFlash.ShockwaveFlash")&&(a=!0)}catch(b){navigator.mimeTypes["application/x-shockwave-flash"]&&(a=!0)}return a};var p=function(){var a=l.prototype._singleton,b=document.getElementById("global-zeroclipboard-html-bridge");if(!b){var c=' <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" id="global-zeroclipboard-flash-bridge" width="100%" height="100%"> <param name="movie" value="'+a.options.moviePath+h(a.options.moviePath)+'"/> <param name="allowScriptAccess" value="'+a.options.allowScriptAccess+'"/> <param name="scale" value="exactfit"/> <param name="loop" value="false"/> <param name="menu" value="false"/> <param name="quality" value="best" /> <param name="bgcolor" value="#ffffff"/> <param name="wmode" value="transparent"/> <param name="flashvars" value="'+i(a.options)+'"/> <embed src="'+a.options.moviePath+h(a.options.moviePath)+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="100%" height="100%" name="global-zeroclipboard-flash-bridge" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" wmode="transparent" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+i(a.options)+'" scale="exactfit"> </embed> </object>';b=document.createElement("div"),b.id="global-zeroclipboard-html-bridge",b.setAttribute("class","global-zeroclipboard-container"),b.setAttribute("data-clipboard-ready",!1),b.style.position="absolute",b.style.left="-9999px",b.style.top="-9999px",b.style.width="15px",b.style.height="15px",b.style.zIndex="9999",b.innerHTML=c,document.body.appendChild(b)}a.htmlBridge=b,a.flashBridge=document["global-zeroclipboard-flash-bridge"]||b.children[0].lastElementChild};l.prototype.resetBridge=function(){this.htmlBridge.style.left="-9999px",this.htmlBridge.style.top="-9999px",this.htmlBridge.removeAttribute("title"),this.htmlBridge.removeAttribute("data-clipboard-text"),f(m,this.options.activeClass),m=null,this.options.text=null},l.prototype.ready=function(){var a=this.htmlBridge.getAttribute("data-clipboard-ready");return a==="true"||a===!0},l.prototype.reposition=function(){if(!m)return!1;var a=g(m);this.htmlBridge.style.top=a.top+"px",this.htmlBridge.style.left=a.left+"px",this.htmlBridge.style.width=a.width+"px",this.htmlBridge.style.height=a.height+"px",this.htmlBridge.style.zIndex=a.zIndex+1,this.setSize(a.width,a.height)},l.dispatch=function(a,b){l.prototype._singleton.receiveEvent(a,b)},l.prototype.on=function(a,b){var c=a.toString().split(/\s/g);for(var d=0;d<c.length;d++)a=c[d].toLowerCase().replace(/^on/,""),this.handlers[a]||(this.handlers[a]=b);this.handlers.noflash&&!l.detectFlashSupport()&&this.receiveEvent("onNoFlash",null)},l.prototype.addEventListener=l.prototype.on,l.prototype.off=function(a,b){var c=a.toString().split(/\s/g);for(var d=0;d<c.length;d++){a=c[d].toLowerCase().replace(/^on/,"");for(var e in this.handlers)e===a&&this.handlers[e]===b&&delete this.handlers[e]}},l.prototype.removeEventListener=l.prototype.off,l.prototype.receiveEvent=function(a,b){a=a.toString().toLowerCase().replace(/^on/,"");var c=m;switch(a){case"load":if(b&&parseFloat(b.flashVersion.replace(",",".").replace(/[^0-9\.]/gi,""))<10){this.receiveEvent("onWrongFlash",{flashVersion:b.flashVersion});return}this.htmlBridge.setAttribute("data-clipboard-ready",!0);break;case"mouseover":e(c,this.options.hoverClass);break;case"mouseout":f(c,this.options.hoverClass),this.resetBridge();break;case"mousedown":e(c,this.options.activeClass);break;case"mouseup":f(c,this.options.activeClass);break;case"datarequested":var d=c.getAttribute("data-clipboard-target"),g=d?document.getElementById(d):null;if(g){var h=g.value||g.textContent||g.innerText;h&&this.setText(h)}else{var i=c.getAttribute("data-clipboard-text");i&&this.setText(i)}break;case"complete":this.options.text=null}if(this.handlers[a]){var j=this.handlers[a];typeof j=="function"?j.call(c,this,b):typeof j=="string"&&window[j].call(c,this,b)}},l.prototype.glue=function(a){a=k(a);for(var d=0;d<a.length;d++)j(a[d],n)==-1&&(n.push(a[d]),c(a[d],"mouseover",b))},l.prototype.unglue=function(a){a=k(a);for(var c=0;c<a.length;c++){d(a[c],"mouseover",b);var e=j(a[c],n);e!=-1&&n.splice(e,1)}},typeof module!="undefined"?module.exports=l:typeof define=="function"&&define.amd?define(function(){return l}):window.ZeroClipboard=l})();
|
Binary file
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra/zero_clipboard'
|
3
|
+
require 'slim'
|
4
|
+
|
5
|
+
class SampleApplication < Sinatra::Base
|
6
|
+
# register our helper to setup neccessary asset routes
|
7
|
+
register Sinatra::ZeroClipboard::Assets
|
8
|
+
|
9
|
+
use Rack::CommonLogger
|
10
|
+
|
11
|
+
enable :inline_templates
|
12
|
+
|
13
|
+
get '/' do
|
14
|
+
slim :index
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
SampleApplication.run!
|
20
|
+
|
21
|
+
__END__
|
22
|
+
@@ layout
|
23
|
+
doctype html
|
24
|
+
html
|
25
|
+
head
|
26
|
+
-# use helper to include links in our HTML
|
27
|
+
== zero_clipboard_assets
|
28
|
+
body
|
29
|
+
== yield
|
30
|
+
|
31
|
+
@@ index
|
32
|
+
-# Add a button
|
33
|
+
-#
|
34
|
+
-# date-clipboard-text is the default text which would be copied if the target was missing
|
35
|
+
-# data-clipboard-target is the target element from which we copy our text
|
36
|
+
-#
|
37
|
+
button id="clip_button" data-clipboard-text="Default clipboard text" data-clipboard-target="text_to_copy" title="Click me to copy to clipboard."
|
38
|
+
span Copy to Clipboard
|
39
|
+
|
40
|
+
.label
|
41
|
+
label for="text_to_copy" Change copy text here
|
42
|
+
-# Add a Target
|
43
|
+
-#
|
44
|
+
-# set the id
|
45
|
+
textarea id="text_to_copy" rows="3" cols="40" Copy me!
|
46
|
+
|
47
|
+
.label
|
48
|
+
label for="testarea" Paste text here for comparison
|
49
|
+
textarea id="testarea" rows="3" cols="40"
|
50
|
+
|
51
|
+
#debug_output
|
52
|
+
|
53
|
+
javascript:
|
54
|
+
// Add ZeroClipboard Javascript binding
|
55
|
+
//
|
56
|
+
// You'll find the needed flash movie under /swf/ZeroClipboard.swf
|
57
|
+
//
|
58
|
+
// For more ZeroClipboard documentation go to: https://github.com/jonrohan/ZeroClipboard
|
59
|
+
var clip = new ZeroClipboard(document.getElementById("clip_button"), {
|
60
|
+
moviePath: "swf/ZeroClipboard.swf"
|
61
|
+
});
|
62
|
+
|
63
|
+
clip.on('load', function (client) {
|
64
|
+
debug_output("Flash movie loaded and ready.");
|
65
|
+
});
|
66
|
+
|
67
|
+
clip.on('noflash', function (client) {
|
68
|
+
debug_output("Your browser has no flash.");
|
69
|
+
});
|
70
|
+
|
71
|
+
clip.on('complete', function (client, args) {
|
72
|
+
debug_output("Copied text to clipboard: " + args.text);
|
73
|
+
});
|
74
|
+
|
75
|
+
function debug_output(text) {
|
76
|
+
p = document.createElement("p")
|
77
|
+
p.innerHTML = text
|
78
|
+
document.getElementById("debug_output").appendChild(p)
|
79
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Sinatra
|
2
|
+
module ZeroClipboard
|
3
|
+
|
4
|
+
module Assets
|
5
|
+
ASSETS = {
|
6
|
+
development: {
|
7
|
+
swf: { "ZeroClipboard.swf" => "2fa578220e56ec9d382e26e2dbb82ad0b9550ac2" },
|
8
|
+
js: { "ZeroClipboard.js" => "e3f0c042f93fe9aeaa570ba09e774a308681f2ed" }
|
9
|
+
},
|
10
|
+
production: {
|
11
|
+
swf: { "ZeroClipboard.swf" => "2fa578220e56ec9d382e26e2dbb82ad0b9550ac2" },
|
12
|
+
js: { "ZeroClipboard.min.js" => "20699686261a143ba1972b18a3ef3f0b3dbcd95c" }
|
13
|
+
}
|
14
|
+
}
|
15
|
+
ASSETS.default = ASSETS[:production]
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def generate_zero_clipboard_asset_routes(application)
|
19
|
+
ASSETS[application.settings.environment].each do |file_type, files|
|
20
|
+
files.each_pair do |file_name, sha1_checksum|
|
21
|
+
application.get "/#{file_type}/#{file_name}", :provides => file_type do
|
22
|
+
cache_control :public, :must_revalidate, :max_age => 3600
|
23
|
+
etag sha1_checksum
|
24
|
+
|
25
|
+
File.read(File.join(Gem.datadir("sinatra-zero_clipboard"), "assets", file_name))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def registered(application)
|
32
|
+
generate_zero_clipboard_asset_routes(application)
|
33
|
+
application.helpers AssetsHelper
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Sinatra
|
2
|
+
module ZeroClipboard
|
3
|
+
|
4
|
+
module AssetsHelper
|
5
|
+
def zero_clipboard_assets
|
6
|
+
environment = Assets::ASSETS.has_key?(settings.environment) ? settings.environment : :production
|
7
|
+
html_fragments = Assets::ASSETS[environment][:js].keys.each_with_object([]) do |file_name, memo|
|
8
|
+
memo << "<script type=\"text/javascript\" src=\"#{url("/js/#{file_name}")}\"></script>"
|
9
|
+
end
|
10
|
+
|
11
|
+
html_fragments.join("\n")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "sinatra/zero_clipboard/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "sinatra-zero_clipboard"
|
8
|
+
spec.version = Sinatra::ZeroClipboard::VERSION
|
9
|
+
spec.authors = ["Oliver Feldt"]
|
10
|
+
spec.email = ["oliver.feldt@googlemail.com"]
|
11
|
+
spec.description = "Sinatra integration for ZeroClipboard"
|
12
|
+
spec.summary = "Adds helpers to enable the use of the clipboard on websites"
|
13
|
+
spec.homepage = "https://github.com/ofeldt/sinatra-zero_clipboard"
|
14
|
+
spec.license = "ISC"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rack", "~> 1.5.2"
|
23
|
+
spec.add_development_dependency "rack-test", "~> 0.6.2"
|
24
|
+
spec.add_development_dependency "rspec", "~> 2.13.0"
|
25
|
+
spec.add_development_dependency "simplecov", "~> 0.7.1"
|
26
|
+
spec.add_development_dependency "slim", "~> 1.3.8"
|
27
|
+
spec.add_development_dependency "pry", "~> 0.9.12.1"
|
28
|
+
|
29
|
+
spec.add_runtime_dependency "sinatra", "~> 1.4.2"
|
30
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler"
|
3
|
+
|
4
|
+
Bundler.setup(:default, :test)
|
5
|
+
|
6
|
+
require 'simplecov'
|
7
|
+
SimpleCov.start do
|
8
|
+
add_filter "spec"
|
9
|
+
end
|
10
|
+
|
11
|
+
require "sinatra"
|
12
|
+
require "rspec"
|
13
|
+
require "rack"
|
14
|
+
require "rack/test"
|
15
|
+
require "pry"
|
16
|
+
require File.expand_path("../../lib/sinatra/zero_clipboard", __FILE__)
|
17
|
+
|
18
|
+
# setting up test environment
|
19
|
+
Sinatra::Base.set :environment, :test
|
20
|
+
Sinatra::Base.set :run, false
|
21
|
+
Sinatra::Base.set :raise_errors, true
|
22
|
+
Sinatra::Base.set :logging, false
|
23
|
+
|
24
|
+
module Sinatra::ZeroClipboard::RSpecHelper
|
25
|
+
def app(reset = false)
|
26
|
+
@test_app = Class.new(Sinatra::Application) if reset || @test_app.nil?
|
27
|
+
@test_app
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
RSpec.configure do |config|
|
32
|
+
config.include Rack::Test::Methods
|
33
|
+
config.include Sinatra::ZeroClipboard::RSpecHelper
|
34
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Sinatra::ZeroClipboard::AssetsHelper do
|
4
|
+
context "#zero_clipboard_assets" do
|
5
|
+
before(:each) do
|
6
|
+
app(:reset)
|
7
|
+
app.register Sinatra::ZeroClipboard::Assets
|
8
|
+
app.get("/") { zero_clipboard_assets }
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should return html fragments" do
|
12
|
+
get("/")
|
13
|
+
|
14
|
+
expect(last_response.body).to eq('<script type="text/javascript" src="http://example.org/js/ZeroClipboard.min.js"></script>')
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should return non-minified version in development environment" do
|
18
|
+
app.settings.environment = :development
|
19
|
+
|
20
|
+
get("/")
|
21
|
+
|
22
|
+
expect(last_response.body).to eq('<script type="text/javascript" src="http://example.org/js/ZeroClipboard.js"></script>')
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should return minified version in test environment" do
|
26
|
+
app.settings.environment = :test
|
27
|
+
|
28
|
+
get("/")
|
29
|
+
|
30
|
+
expect(last_response.body).to eq('<script type="text/javascript" src="http://example.org/js/ZeroClipboard.min.js"></script>')
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should return minified version in production environment" do
|
34
|
+
app.settings.environment = :production
|
35
|
+
|
36
|
+
get("/")
|
37
|
+
|
38
|
+
expect(last_response.body).to eq('<script type="text/javascript" src="http://example.org/js/ZeroClipboard.min.js"></script>')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Sinatra::ZeroClipboard::Assets do
|
4
|
+
before(:each) { app(:reset) }
|
5
|
+
|
6
|
+
context "#registered" do
|
7
|
+
it "should register our asset module as helper" do
|
8
|
+
expect(app).to_not be_a(Sinatra::ZeroClipboard::Assets)
|
9
|
+
|
10
|
+
app.register(Sinatra::ZeroClipboard::Assets)
|
11
|
+
|
12
|
+
expect(app).to be_a(Sinatra::ZeroClipboard::Assets)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "#generate_zero_clipboard_asset_routes" do
|
17
|
+
[:development, :test, :production].each do |environment|
|
18
|
+
context "in #{environment} mode" do
|
19
|
+
Sinatra::ZeroClipboard::Assets::ASSETS[environment].each_pair do |file_type, file_list|
|
20
|
+
file_list.each_pair do |file_name, sha1_checksum|
|
21
|
+
before(:each) do
|
22
|
+
app.settings.environment = environment
|
23
|
+
app.register Sinatra::ZeroClipboard::Assets
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should register routes for #{file_type}/#{file_name}" do
|
27
|
+
get("/#{file_type}/#{file_name}")
|
28
|
+
|
29
|
+
expect(last_response.status).to eq(200)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should set an ETag for #{file_type}/#{file_name} in response headers for caching" do
|
33
|
+
get("/#{file_type}/#{file_name}")
|
34
|
+
|
35
|
+
expect(last_response.headers["ETag"]).to match(/#{sha1_checksum}/)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sinatra-zero_clipboard
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Oliver Feldt
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-05-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rack
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.5.2
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.5.2
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rack-test
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.6.2
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.6.2
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 2.13.0
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 2.13.0
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: simplecov
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 0.7.1
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.7.1
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: slim
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.3.8
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.3.8
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: pry
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.9.12.1
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 0.9.12.1
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: sinatra
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ~>
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 1.4.2
|
134
|
+
type: :runtime
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ~>
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 1.4.2
|
142
|
+
description: Sinatra integration for ZeroClipboard
|
143
|
+
email:
|
144
|
+
- oliver.feldt@googlemail.com
|
145
|
+
executables: []
|
146
|
+
extensions: []
|
147
|
+
extra_rdoc_files: []
|
148
|
+
files:
|
149
|
+
- .gitignore
|
150
|
+
- .rspec
|
151
|
+
- Gemfile
|
152
|
+
- LICENSE.txt
|
153
|
+
- README.md
|
154
|
+
- Rakefile
|
155
|
+
- data/sinatra-zero_clipboard/assets/ZeroClipboard.js
|
156
|
+
- data/sinatra-zero_clipboard/assets/ZeroClipboard.min.js
|
157
|
+
- data/sinatra-zero_clipboard/assets/ZeroClipboard.swf
|
158
|
+
- examples/sample_application.rb
|
159
|
+
- lib/sinatra/zero_clipboard.rb
|
160
|
+
- lib/sinatra/zero_clipboard/assets.rb
|
161
|
+
- lib/sinatra/zero_clipboard/assets_helper.rb
|
162
|
+
- lib/sinatra/zero_clipboard/version.rb
|
163
|
+
- sinatra-zero_clipboard.gemspec
|
164
|
+
- spec/spec_helper.rb
|
165
|
+
- spec/unit/sinatra/zero_clipboard/assets_helper_spec.rb
|
166
|
+
- spec/unit/sinatra/zero_clipboard/assets_spec.rb
|
167
|
+
homepage: https://github.com/ofeldt/sinatra-zero_clipboard
|
168
|
+
licenses:
|
169
|
+
- ISC
|
170
|
+
post_install_message:
|
171
|
+
rdoc_options: []
|
172
|
+
require_paths:
|
173
|
+
- lib
|
174
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
175
|
+
none: false
|
176
|
+
requirements:
|
177
|
+
- - '>='
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
180
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
181
|
+
none: false
|
182
|
+
requirements:
|
183
|
+
- - '>='
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '0'
|
186
|
+
requirements: []
|
187
|
+
rubyforge_project:
|
188
|
+
rubygems_version: 1.8.25
|
189
|
+
signing_key:
|
190
|
+
specification_version: 3
|
191
|
+
summary: Adds helpers to enable the use of the clipboard on websites
|
192
|
+
test_files:
|
193
|
+
- spec/spec_helper.rb
|
194
|
+
- spec/unit/sinatra/zero_clipboard/assets_helper_spec.rb
|
195
|
+
- spec/unit/sinatra/zero_clipboard/assets_spec.rb
|