placeholder-gem 3.0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 UC Berkeley - ETS
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # Placeholder Gem
2
+
3
+ [Placeholders.js HTML polyfill][placeholder] as a Ruby gem.
4
+
5
+ ## Getting Started
6
+
7
+ Add the gem to your Gemfile:
8
+
9
+ ```ruby
10
+ gem "placeholder-gem"
11
+ ```
12
+
13
+ And run
14
+
15
+ ```bash
16
+ bundle install
17
+ ```
18
+ in the terminal to download the resources.
19
+
20
+ ### Adding the files to your projects
21
+
22
+ In order for the files to load, you'll need to do add them.
23
+
24
+ `application.js`:
25
+
26
+ ```javascript
27
+ //= require placeholder
28
+ ```
29
+
30
+ and you should be good to go.
31
+
32
+ ## Updating this plug-in
33
+
34
+ If you would like to update this gem you should take the following steps:
35
+
36
+ 1. `rake download VERSION=vX.X.X`. If you don't specify the version, it will get the latest one.
37
+ 1. `rake tag VERSION=vX.X.X` will tag the version you've specified as the standard version.
38
+ 1. Make a Pull request
39
+
40
+ Then the maintainer of the gem will need to do the following steps:
41
+
42
+ 1. Update the version [lib/placeholder-gem/version.rb](lib/placeholder-gem/version.rb)
43
+ 1. Run ``gem build placeholder-gem.gemspec`` to package the gem
44
+ 1. Once satisfied, push the gem up to RubyGems.org with ``gem push placeholder-gem-<VERSION>.gem``
45
+ 1. Update [the changelog](CHANGELOG.md)
46
+
47
+ [placeholder]: https://github.com/jamesallardice/Placeholders.js
data/Rakefile ADDED
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+
8
+ Bundler::GemHelper.install_tasks
9
+
10
+ require 'rake'
11
+ require 'open-uri'
12
+ require 'json'
13
+
14
+ dir_assets = 'vendor/assets/'
15
+ dir_js = dir_assets + 'javascripts'
16
+
17
+ desc 'Downloads the Placeholder.js JavaScript files from GitHub'
18
+ task :download do |t|
19
+
20
+ def create_dir dir, version
21
+ dir_name = File.join(dir, version)
22
+ Dir.mkdir(dir_name) unless Dir.exist?(dir_name)
23
+ end
24
+
25
+ def download_file urls, dir, filename, version
26
+ Dir.chdir(File.join(dir, version)) do
27
+ if File.exists?(filename)
28
+ puts " #{dir + '/' + version + '/' + filename} already exists"
29
+ next
30
+ end
31
+ code = ''
32
+ urls.reverse_each do |url|
33
+ puts " #{url}"
34
+ code += open(url).read
35
+ end
36
+ open(filename, "w") { |file| file.write(code)}
37
+ puts " Concatenating to #{dir + '/' + version + '/' + filename}"
38
+ puts " Done!"
39
+ end
40
+ end
41
+
42
+ # Specify which version you want
43
+ version = ENV['VERSION']
44
+ version ||= 'latest'
45
+ puts "Target version: #{version.chomp('/')}"
46
+
47
+ # Get the different versions
48
+ tags_url = 'https://api.github.com/repos/jamesallardice/Placeholders.js/tags'
49
+ result = JSON.parse(open(tags_url).read)
50
+ versions = result.map { |item| item['name'] }
51
+
52
+ puts "Available versions: #{versions.inspect}"
53
+
54
+ # Figuring out which version to get
55
+ if versions.include? version
56
+ get_version = version
57
+ else
58
+ get_version = versions.first
59
+
60
+ if !(versions.include? version) && version != 'latest'
61
+ puts "Warning: The version you've specified: '#{version}' wasn't found, using the latest version instead: '#{get_version}'"
62
+ end
63
+ end
64
+
65
+ # Get the right commit
66
+ commit = result.select { |item| item['name'] == get_version }.first['commit']['sha']
67
+ puts "We'll use the following commit to get the files: #{commit}"
68
+
69
+ # Creating the necessary directories
70
+ create_dir dir_js, get_version
71
+
72
+ # Download all the right files
73
+ url_root = 'https://raw.github.com/jamesallardice/Placeholders.js/' + commit + '/'
74
+ url_tree = 'https://api.github.com/repos/jamesallardice/Placeholders.js/git/trees/' + commit + '?recursive=1'
75
+ urls = []
76
+
77
+ result_tree = JSON.parse(open(url_tree).read)
78
+
79
+ result_tree['tree'].each do |file|
80
+ if file['path'] =~ /lib\/\w+.js/
81
+ url = url_root + file['path']
82
+ urls.push(url)
83
+ end
84
+ end
85
+ puts "Searching #{url_tree}"
86
+ puts "Downloading..."
87
+ download_file urls, dir_js, 'placeholder.js', get_version
88
+
89
+ end
90
+
91
+ desc 'Tag the default file versions for asset helpers'
92
+ task :tag do |t|
93
+ Rake::Task['tag_default'].invoke
94
+ end
95
+
96
+ task :tag_default do |t|
97
+
98
+ def copy_files dir, version
99
+ Dir.entries(File.join(dir, version)).each do |file|
100
+ file_source = File.join(dir, version, file)
101
+ file_destination = File.join(dir, file)
102
+ if File.file?(file_source)
103
+ FileUtils.cp file_source, file_destination, { verbose: true }
104
+ end
105
+ end
106
+ end
107
+
108
+ version = ENV['VERSION']
109
+ version ||= 'latest'
110
+
111
+ puts "Target version: #{version.chomp('/')}"
112
+
113
+ Dir.chdir(dir_js) do
114
+ version_directories = Dir.glob("*").select { |fn| File.directory?(fn) }.sort.reverse
115
+
116
+ puts "Available versions: #{version_directories.inspect}"
117
+ if !(version_directories.include? version)
118
+ if version != 'latest'
119
+ puts "WARN: Specified version='#{version}' not found, setting to latest version: '#{version_directories.first}'"
120
+ end
121
+ version = version_directories.first
122
+ end
123
+ end
124
+
125
+ copy_files dir_js, version
126
+ end
@@ -0,0 +1,6 @@
1
+ require "rails/engine"
2
+
3
+ module PlaceholderGem
4
+ class Engine < Rails::Engine
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ module PlaceholderGem
2
+ VERSION = "3.0.0.0"
3
+ end
@@ -0,0 +1,436 @@
1
+ /*
2
+ * The MIT License
3
+ *
4
+ * Copyright (c) 2012 James Allardice
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
7
+ * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
+ * 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:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11
+ *
12
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14
+ * 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
15
+ * THE SOFTWARE.
16
+ */
17
+
18
+ // Defines the global Placeholders object along with various utility methods
19
+ (function (global) {
20
+
21
+ "use strict";
22
+
23
+ // Cross-browser DOM event binding
24
+ function addEventListener(elem, event, fn) {
25
+ if (elem.addEventListener) {
26
+ return elem.addEventListener(event, fn, false);
27
+ }
28
+ if (elem.attachEvent) {
29
+ return elem.attachEvent("on" + event, fn);
30
+ }
31
+ }
32
+
33
+ // Check whether an item is in an array (we don't use Array.prototype.indexOf so we don't clobber any existing polyfills - this is a really simple alternative)
34
+ function inArray(arr, item) {
35
+ var i, len;
36
+ for (i = 0, len = arr.length; i < len; i++) {
37
+ if (arr[i] === item) {
38
+ return true;
39
+ }
40
+ }
41
+ return false;
42
+ }
43
+
44
+ // Move the caret to the index position specified. Assumes that the element has focus
45
+ function moveCaret(elem, index) {
46
+ var range;
47
+ if (elem.createTextRange) {
48
+ range = elem.createTextRange();
49
+ range.move("character", index);
50
+ range.select();
51
+ } else if (elem.selectionStart) {
52
+ elem.focus();
53
+ elem.setSelectionRange(index, index);
54
+ }
55
+ }
56
+
57
+ // Attempt to change the type property of an input element
58
+ function changeType(elem, type) {
59
+ try {
60
+ elem.type = type;
61
+ return true;
62
+ } catch (e) {
63
+ // You can't change input type in IE8 and below
64
+ return false;
65
+ }
66
+ }
67
+
68
+ // Expose public methods
69
+ global.Placeholders = {
70
+ Utils: {
71
+ addEventListener: addEventListener,
72
+ inArray: inArray,
73
+ moveCaret: moveCaret,
74
+ changeType: changeType
75
+ }
76
+ };
77
+
78
+ }(this));
79
+ (function (global) {
80
+
81
+ "use strict";
82
+
83
+ var validTypes = [
84
+ "text",
85
+ "search",
86
+ "url",
87
+ "tel",
88
+ "email",
89
+ "password",
90
+ "number",
91
+ "textarea"
92
+ ],
93
+
94
+ // The list of keycodes that are not allowed when the polyfill is configured to hide-on-input
95
+ badKeys = [
96
+
97
+ // The following keys all cause the caret to jump to the end of the input value
98
+ 27, // Escape
99
+ 33, // Page up
100
+ 34, // Page down
101
+ 35, // End
102
+ 36, // Home
103
+
104
+ // Arrow keys allow you to move the caret manually, which should be prevented when the placeholder is visible
105
+ 37, // Left
106
+ 38, // Up
107
+ 39, // Right
108
+ 40, // Down
109
+
110
+ // The following keys allow you to modify the placeholder text by removing characters, which should be prevented when the placeholder is visible
111
+ 8, // Backspace
112
+ 46 // Delete
113
+ ],
114
+
115
+ // Styling variables
116
+ placeholderStyleColor = "#ccc",
117
+ placeholderClassName = "placeholdersjs",
118
+ classNameRegExp = new RegExp("(?:^|\\s)" + placeholderClassName + "(?!\\S)"),
119
+
120
+ // These will hold references to all elements that can be affected. NodeList objects are live, so we only need to get those references once
121
+ inputs, textareas,
122
+
123
+ // The various data-* attributes used by the polyfill
124
+ ATTR_CURRENT_VAL = "data-placeholder-value",
125
+ ATTR_ACTIVE = "data-placeholder-active",
126
+ ATTR_INPUT_TYPE = "data-placeholder-type",
127
+ ATTR_FORM_HANDLED = "data-placeholder-submit",
128
+ ATTR_EVENTS_BOUND = "data-placeholder-bound",
129
+ ATTR_OPTION_FOCUS = "data-placeholder-focus",
130
+ ATTR_OPTION_LIVE = "data-placeholder-live",
131
+ ATTR_MAXLENGTH = "data-placeholder-maxlength",
132
+
133
+ // Various other variables used throughout the rest of the script
134
+ test = document.createElement("input"),
135
+ head = document.getElementsByTagName("head")[0],
136
+ root = document.documentElement,
137
+ Placeholders = global.Placeholders,
138
+ Utils = Placeholders.Utils,
139
+ hideOnInput, liveUpdates, keydownVal, styleElem, styleRules, placeholder, timer, form, elem, len, i;
140
+
141
+ // No-op (used in place of public methods when native support is detected)
142
+ function noop() {}
143
+
144
+ // Hide the placeholder value on a single element. Returns true if the placeholder was hidden and false if it was not (because it wasn't visible in the first place)
145
+ function hidePlaceholder(elem, keydownValue) {
146
+ var type,
147
+ maxLength,
148
+ valueChanged = (!!keydownValue && elem.value !== keydownValue),
149
+ isPlaceholderValue = (elem.value === elem.getAttribute(ATTR_CURRENT_VAL));
150
+
151
+ if ((valueChanged || isPlaceholderValue) && elem.getAttribute(ATTR_ACTIVE) === "true") {
152
+ elem.removeAttribute(ATTR_ACTIVE);
153
+ elem.value = elem.value.replace(elem.getAttribute(ATTR_CURRENT_VAL), "");
154
+ elem.className = elem.className.replace(classNameRegExp, "");
155
+
156
+ // Restore the maxlength value
157
+ maxLength = elem.getAttribute(ATTR_MAXLENGTH);
158
+ if (maxLength) {
159
+ elem.setAttribute("maxLength", maxLength);
160
+ elem.removeAttribute(ATTR_MAXLENGTH);
161
+ }
162
+
163
+ // If the polyfill has changed the type of the element we need to change it back
164
+ type = elem.getAttribute(ATTR_INPUT_TYPE);
165
+ if (type) {
166
+ elem.type = type;
167
+ }
168
+ return true;
169
+ }
170
+ return false;
171
+ }
172
+
173
+ // Show the placeholder value on a single element. Returns true if the placeholder was shown and false if it was not (because it was already visible)
174
+ function showPlaceholder(elem) {
175
+ var type,
176
+ maxLength,
177
+ val = elem.getAttribute(ATTR_CURRENT_VAL);
178
+ if (elem.value === "" && val) {
179
+ elem.setAttribute(ATTR_ACTIVE, "true");
180
+ elem.value = val;
181
+ elem.className += " " + placeholderClassName;
182
+
183
+ // Store and remove the maxlength value
184
+ maxLength = elem.getAttribute(ATTR_MAXLENGTH);
185
+ if (!maxLength) {
186
+ elem.setAttribute(ATTR_MAXLENGTH, elem.maxLength);
187
+ elem.removeAttribute("maxLength");
188
+ }
189
+
190
+ // If the type of element needs to change, change it (e.g. password inputs)
191
+ type = elem.getAttribute(ATTR_INPUT_TYPE);
192
+ if (type) {
193
+ elem.type = "text";
194
+ } else if (elem.type === "password") {
195
+ if (Utils.changeType(elem, "text")) {
196
+ elem.setAttribute(ATTR_INPUT_TYPE, "password");
197
+ }
198
+ }
199
+ return true;
200
+ }
201
+ return false;
202
+ }
203
+
204
+ function handleElem(node, callback) {
205
+
206
+ var handleInputs, handleTextareas, elem, len, i;
207
+
208
+ // Check if the passed in node is an input/textarea (in which case it can't have any affected descendants)
209
+ if (node && node.getAttribute(ATTR_CURRENT_VAL)) {
210
+ callback(node);
211
+ } else {
212
+
213
+ // If an element was passed in, get all affected descendants. Otherwise, get all affected elements in document
214
+ handleInputs = node ? node.getElementsByTagName("input") : inputs;
215
+ handleTextareas = node ? node.getElementsByTagName("textarea") : textareas;
216
+
217
+ // Run the callback for each element
218
+ for (i = 0, len = handleInputs.length + handleTextareas.length; i < len; i++) {
219
+ elem = i < handleInputs.length ? handleInputs[i] : handleTextareas[i - handleInputs.length];
220
+ callback(elem);
221
+ }
222
+ }
223
+ }
224
+
225
+ // Return all affected elements to their normal state (remove placeholder value if present)
226
+ function disablePlaceholders(node) {
227
+ handleElem(node, hidePlaceholder);
228
+ }
229
+
230
+ // Show the placeholder value on all appropriate elements
231
+ function enablePlaceholders(node) {
232
+ handleElem(node, showPlaceholder);
233
+ }
234
+
235
+ // Returns a function that is used as a focus event handler
236
+ function makeFocusHandler(elem) {
237
+ return function () {
238
+
239
+ // Only hide the placeholder value if the (default) hide-on-focus behaviour is enabled
240
+ if (hideOnInput && elem.value === elem.getAttribute(ATTR_CURRENT_VAL) && elem.getAttribute(ATTR_ACTIVE) === "true") {
241
+
242
+ // Move the caret to the start of the input (this mimics the behaviour of all browsers that do not hide the placeholder on focus)
243
+ Utils.moveCaret(elem, 0);
244
+
245
+ } else {
246
+
247
+ // Remove the placeholder
248
+ hidePlaceholder(elem);
249
+ }
250
+ };
251
+ }
252
+
253
+ // Returns a function that is used as a blur event handler
254
+ function makeBlurHandler(elem) {
255
+ return function () {
256
+ showPlaceholder(elem);
257
+ };
258
+ }
259
+
260
+ // Functions that are used as a event handlers when the hide-on-input behaviour has been activated - very basic implementation of the "input" event
261
+ function makeKeydownHandler(elem) {
262
+ return function (e) {
263
+ keydownVal = elem.value;
264
+
265
+ //Prevent the use of the arrow keys (try to keep the cursor before the placeholder)
266
+ if (elem.getAttribute(ATTR_ACTIVE) === "true") {
267
+ if (keydownVal === elem.getAttribute(ATTR_CURRENT_VAL) && Utils.inArray(badKeys, e.keyCode)) {
268
+ if (e.preventDefault) {
269
+ e.preventDefault();
270
+ }
271
+ return false;
272
+ }
273
+ }
274
+ };
275
+ }
276
+ function makeKeyupHandler(elem) {
277
+ return function () {
278
+ hidePlaceholder(elem, keydownVal);
279
+
280
+ // If the element is now empty we need to show the placeholder
281
+ if (elem.value === "") {
282
+ elem.blur();
283
+ Utils.moveCaret(elem, 0);
284
+ }
285
+ };
286
+ }
287
+ function makeClickHandler(elem) {
288
+ return function () {
289
+ if (elem === document.activeElement && elem.value === elem.getAttribute(ATTR_CURRENT_VAL) && elem.getAttribute(ATTR_ACTIVE) === "true") {
290
+ Utils.moveCaret(elem, 0);
291
+ }
292
+ };
293
+ }
294
+
295
+ // Returns a function that is used as a submit event handler on form elements that have children affected by this polyfill
296
+ function makeSubmitHandler(form) {
297
+ return function () {
298
+
299
+ // Turn off placeholders on all appropriate descendant elements
300
+ disablePlaceholders(form);
301
+ };
302
+ }
303
+
304
+ // Bind event handlers to an element that we need to affect with the polyfill
305
+ function newElement(elem) {
306
+
307
+ // If the element is part of a form, make sure the placeholder string is not submitted as a value
308
+ if (elem.form) {
309
+ form = elem.form;
310
+
311
+ // Set a flag on the form so we know it's been handled (forms can contain multiple inputs)
312
+ if (!form.getAttribute(ATTR_FORM_HANDLED)) {
313
+ Utils.addEventListener(form, "submit", makeSubmitHandler(form));
314
+ form.setAttribute(ATTR_FORM_HANDLED, "true");
315
+ }
316
+ }
317
+
318
+ // Bind event handlers to the element so we can hide/show the placeholder as appropriate
319
+ Utils.addEventListener(elem, "focus", makeFocusHandler(elem));
320
+ Utils.addEventListener(elem, "blur", makeBlurHandler(elem));
321
+
322
+ // If the placeholder should hide on input rather than on focus we need additional event handlers
323
+ if (hideOnInput) {
324
+ Utils.addEventListener(elem, "keydown", makeKeydownHandler(elem));
325
+ Utils.addEventListener(elem, "keyup", makeKeyupHandler(elem));
326
+ Utils.addEventListener(elem, "click", makeClickHandler(elem));
327
+ }
328
+
329
+ // Remember that we've bound event handlers to this element
330
+ elem.setAttribute(ATTR_EVENTS_BOUND, "true");
331
+ elem.setAttribute(ATTR_CURRENT_VAL, placeholder);
332
+
333
+ // If the element doesn't have a value and is not focussed, set it to the placeholder string
334
+ if (hideOnInput || elem !== document.activeElement) {
335
+ showPlaceholder(elem);
336
+ }
337
+ }
338
+
339
+ Placeholders.nativeSupport = test.placeholder !== void 0;
340
+
341
+ if (!Placeholders.nativeSupport) {
342
+
343
+ // Get references to all the input and textarea elements currently in the DOM (live NodeList objects to we only need to do this once)
344
+ inputs = document.getElementsByTagName("input");
345
+ textareas = document.getElementsByTagName("textarea");
346
+
347
+ // Get any settings declared as data-* attributes on the root element (currently the only options are whether to hide the placeholder on focus or input and whether to auto-update)
348
+ hideOnInput = root.getAttribute(ATTR_OPTION_FOCUS) === "false";
349
+ liveUpdates = root.getAttribute(ATTR_OPTION_LIVE) !== "false";
350
+
351
+ // Create style element for placeholder styles (instead of directly setting style properties on elements - allows for better flexibility alongside user-defined styles)
352
+ styleElem = document.createElement("style");
353
+ styleElem.type = "text/css";
354
+
355
+ // Create style rules as text node
356
+ styleRules = document.createTextNode("." + placeholderClassName + " { color:" + placeholderStyleColor + "; }");
357
+
358
+ // Append style rules to newly created stylesheet
359
+ if (styleElem.styleSheet) {
360
+ styleElem.styleSheet.cssText = styleRules.nodeValue;
361
+ } else {
362
+ styleElem.appendChild(styleRules);
363
+ }
364
+
365
+ // Prepend new style element to the head (before any existing stylesheets, so user-defined rules take precedence)
366
+ head.insertBefore(styleElem, head.firstChild);
367
+
368
+ // Set up the placeholders
369
+ for (i = 0, len = inputs.length + textareas.length; i < len; i++) {
370
+ elem = i < inputs.length ? inputs[i] : textareas[i - inputs.length];
371
+
372
+ // Get the value of the placeholder attribute, if any. IE10 emulating IE7 fails with getAttribute, hence the use of the attributes node
373
+ placeholder = elem.attributes.placeholder;
374
+ if (placeholder) {
375
+
376
+ // IE returns an empty object instead of undefined if the attribute is not present
377
+ placeholder = placeholder.nodeValue;
378
+
379
+ // Only apply the polyfill if this element is of a type that supports placeholders, and has a placeholder attribute with a non-empty value
380
+ if (placeholder && Utils.inArray(validTypes, elem.type)) {
381
+ newElement(elem);
382
+ }
383
+ }
384
+ }
385
+
386
+ // If enabled, the polyfill will repeatedly check for changed/added elements and apply to those as well
387
+ timer = setInterval(function () {
388
+ for (i = 0, len = inputs.length + textareas.length; i < len; i++) {
389
+ elem = i < inputs.length ? inputs[i] : textareas[i - inputs.length];
390
+
391
+ // Only apply the polyfill if this element is of a type that supports placeholders, and has a placeholder attribute with a non-empty value
392
+ placeholder = elem.attributes.placeholder;
393
+ if (placeholder) {
394
+ placeholder = placeholder.nodeValue;
395
+ if (placeholder && Utils.inArray(validTypes, elem.type)) {
396
+
397
+ // If the element hasn't had event handlers bound to it then add them
398
+ if (!elem.getAttribute(ATTR_EVENTS_BOUND)) {
399
+ newElement(elem);
400
+ }
401
+
402
+ // If the placeholder value has changed or not been initialised yet we need to update the display
403
+ if (placeholder !== elem.getAttribute(ATTR_CURRENT_VAL) || (elem.type === "password" && !elem.getAttribute(ATTR_INPUT_TYPE))) {
404
+
405
+ // Attempt to change the type of password inputs (fails in IE < 9)
406
+ if (elem.type === "password" && !elem.getAttribute(ATTR_INPUT_TYPE) && Utils.changeType(elem, "text")) {
407
+ elem.setAttribute(ATTR_INPUT_TYPE, "password");
408
+ }
409
+
410
+ // If the placeholder value has changed and the placeholder is currently on display we need to change it
411
+ if (elem.value === elem.getAttribute(ATTR_CURRENT_VAL)) {
412
+ elem.value = placeholder;
413
+ }
414
+
415
+ // Keep a reference to the current placeholder value in case it changes via another script
416
+ elem.setAttribute(ATTR_CURRENT_VAL, placeholder);
417
+ }
418
+ }
419
+ } else if (elem.getAttribute(ATTR_ACTIVE)) {
420
+ hidePlaceholder(elem);
421
+ elem.removeAttribute(ATTR_CURRENT_VAL);
422
+ }
423
+ }
424
+
425
+ // If live updates are not enabled cancel the timer
426
+ if (!liveUpdates) {
427
+ clearInterval(timer);
428
+ }
429
+ }, 100);
430
+ }
431
+
432
+ // Expose public methods
433
+ Placeholders.disable = Placeholders.nativeSupport ? noop : disablePlaceholders;
434
+ Placeholders.enable = Placeholders.nativeSupport ? noop : enablePlaceholders;
435
+
436
+ }(this));
@@ -0,0 +1,436 @@
1
+ /*
2
+ * The MIT License
3
+ *
4
+ * Copyright (c) 2012 James Allardice
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
7
+ * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
+ * 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:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11
+ *
12
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14
+ * 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
15
+ * THE SOFTWARE.
16
+ */
17
+
18
+ // Defines the global Placeholders object along with various utility methods
19
+ (function (global) {
20
+
21
+ "use strict";
22
+
23
+ // Cross-browser DOM event binding
24
+ function addEventListener(elem, event, fn) {
25
+ if (elem.addEventListener) {
26
+ return elem.addEventListener(event, fn, false);
27
+ }
28
+ if (elem.attachEvent) {
29
+ return elem.attachEvent("on" + event, fn);
30
+ }
31
+ }
32
+
33
+ // Check whether an item is in an array (we don't use Array.prototype.indexOf so we don't clobber any existing polyfills - this is a really simple alternative)
34
+ function inArray(arr, item) {
35
+ var i, len;
36
+ for (i = 0, len = arr.length; i < len; i++) {
37
+ if (arr[i] === item) {
38
+ return true;
39
+ }
40
+ }
41
+ return false;
42
+ }
43
+
44
+ // Move the caret to the index position specified. Assumes that the element has focus
45
+ function moveCaret(elem, index) {
46
+ var range;
47
+ if (elem.createTextRange) {
48
+ range = elem.createTextRange();
49
+ range.move("character", index);
50
+ range.select();
51
+ } else if (elem.selectionStart) {
52
+ elem.focus();
53
+ elem.setSelectionRange(index, index);
54
+ }
55
+ }
56
+
57
+ // Attempt to change the type property of an input element
58
+ function changeType(elem, type) {
59
+ try {
60
+ elem.type = type;
61
+ return true;
62
+ } catch (e) {
63
+ // You can't change input type in IE8 and below
64
+ return false;
65
+ }
66
+ }
67
+
68
+ // Expose public methods
69
+ global.Placeholders = {
70
+ Utils: {
71
+ addEventListener: addEventListener,
72
+ inArray: inArray,
73
+ moveCaret: moveCaret,
74
+ changeType: changeType
75
+ }
76
+ };
77
+
78
+ }(this));
79
+ (function (global) {
80
+
81
+ "use strict";
82
+
83
+ var validTypes = [
84
+ "text",
85
+ "search",
86
+ "url",
87
+ "tel",
88
+ "email",
89
+ "password",
90
+ "number",
91
+ "textarea"
92
+ ],
93
+
94
+ // The list of keycodes that are not allowed when the polyfill is configured to hide-on-input
95
+ badKeys = [
96
+
97
+ // The following keys all cause the caret to jump to the end of the input value
98
+ 27, // Escape
99
+ 33, // Page up
100
+ 34, // Page down
101
+ 35, // End
102
+ 36, // Home
103
+
104
+ // Arrow keys allow you to move the caret manually, which should be prevented when the placeholder is visible
105
+ 37, // Left
106
+ 38, // Up
107
+ 39, // Right
108
+ 40, // Down
109
+
110
+ // The following keys allow you to modify the placeholder text by removing characters, which should be prevented when the placeholder is visible
111
+ 8, // Backspace
112
+ 46 // Delete
113
+ ],
114
+
115
+ // Styling variables
116
+ placeholderStyleColor = "#ccc",
117
+ placeholderClassName = "placeholdersjs",
118
+ classNameRegExp = new RegExp("(?:^|\\s)" + placeholderClassName + "(?!\\S)"),
119
+
120
+ // These will hold references to all elements that can be affected. NodeList objects are live, so we only need to get those references once
121
+ inputs, textareas,
122
+
123
+ // The various data-* attributes used by the polyfill
124
+ ATTR_CURRENT_VAL = "data-placeholder-value",
125
+ ATTR_ACTIVE = "data-placeholder-active",
126
+ ATTR_INPUT_TYPE = "data-placeholder-type",
127
+ ATTR_FORM_HANDLED = "data-placeholder-submit",
128
+ ATTR_EVENTS_BOUND = "data-placeholder-bound",
129
+ ATTR_OPTION_FOCUS = "data-placeholder-focus",
130
+ ATTR_OPTION_LIVE = "data-placeholder-live",
131
+ ATTR_MAXLENGTH = "data-placeholder-maxlength",
132
+
133
+ // Various other variables used throughout the rest of the script
134
+ test = document.createElement("input"),
135
+ head = document.getElementsByTagName("head")[0],
136
+ root = document.documentElement,
137
+ Placeholders = global.Placeholders,
138
+ Utils = Placeholders.Utils,
139
+ hideOnInput, liveUpdates, keydownVal, styleElem, styleRules, placeholder, timer, form, elem, len, i;
140
+
141
+ // No-op (used in place of public methods when native support is detected)
142
+ function noop() {}
143
+
144
+ // Hide the placeholder value on a single element. Returns true if the placeholder was hidden and false if it was not (because it wasn't visible in the first place)
145
+ function hidePlaceholder(elem, keydownValue) {
146
+ var type,
147
+ maxLength,
148
+ valueChanged = (!!keydownValue && elem.value !== keydownValue),
149
+ isPlaceholderValue = (elem.value === elem.getAttribute(ATTR_CURRENT_VAL));
150
+
151
+ if ((valueChanged || isPlaceholderValue) && elem.getAttribute(ATTR_ACTIVE) === "true") {
152
+ elem.removeAttribute(ATTR_ACTIVE);
153
+ elem.value = elem.value.replace(elem.getAttribute(ATTR_CURRENT_VAL), "");
154
+ elem.className = elem.className.replace(classNameRegExp, "");
155
+
156
+ // Restore the maxlength value
157
+ maxLength = elem.getAttribute(ATTR_MAXLENGTH);
158
+ if (maxLength) {
159
+ elem.setAttribute("maxLength", maxLength);
160
+ elem.removeAttribute(ATTR_MAXLENGTH);
161
+ }
162
+
163
+ // If the polyfill has changed the type of the element we need to change it back
164
+ type = elem.getAttribute(ATTR_INPUT_TYPE);
165
+ if (type) {
166
+ elem.type = type;
167
+ }
168
+ return true;
169
+ }
170
+ return false;
171
+ }
172
+
173
+ // Show the placeholder value on a single element. Returns true if the placeholder was shown and false if it was not (because it was already visible)
174
+ function showPlaceholder(elem) {
175
+ var type,
176
+ maxLength,
177
+ val = elem.getAttribute(ATTR_CURRENT_VAL);
178
+ if (elem.value === "" && val) {
179
+ elem.setAttribute(ATTR_ACTIVE, "true");
180
+ elem.value = val;
181
+ elem.className += " " + placeholderClassName;
182
+
183
+ // Store and remove the maxlength value
184
+ maxLength = elem.getAttribute(ATTR_MAXLENGTH);
185
+ if (!maxLength) {
186
+ elem.setAttribute(ATTR_MAXLENGTH, elem.maxLength);
187
+ elem.removeAttribute("maxLength");
188
+ }
189
+
190
+ // If the type of element needs to change, change it (e.g. password inputs)
191
+ type = elem.getAttribute(ATTR_INPUT_TYPE);
192
+ if (type) {
193
+ elem.type = "text";
194
+ } else if (elem.type === "password") {
195
+ if (Utils.changeType(elem, "text")) {
196
+ elem.setAttribute(ATTR_INPUT_TYPE, "password");
197
+ }
198
+ }
199
+ return true;
200
+ }
201
+ return false;
202
+ }
203
+
204
+ function handleElem(node, callback) {
205
+
206
+ var handleInputs, handleTextareas, elem, len, i;
207
+
208
+ // Check if the passed in node is an input/textarea (in which case it can't have any affected descendants)
209
+ if (node && node.getAttribute(ATTR_CURRENT_VAL)) {
210
+ callback(node);
211
+ } else {
212
+
213
+ // If an element was passed in, get all affected descendants. Otherwise, get all affected elements in document
214
+ handleInputs = node ? node.getElementsByTagName("input") : inputs;
215
+ handleTextareas = node ? node.getElementsByTagName("textarea") : textareas;
216
+
217
+ // Run the callback for each element
218
+ for (i = 0, len = handleInputs.length + handleTextareas.length; i < len; i++) {
219
+ elem = i < handleInputs.length ? handleInputs[i] : handleTextareas[i - handleInputs.length];
220
+ callback(elem);
221
+ }
222
+ }
223
+ }
224
+
225
+ // Return all affected elements to their normal state (remove placeholder value if present)
226
+ function disablePlaceholders(node) {
227
+ handleElem(node, hidePlaceholder);
228
+ }
229
+
230
+ // Show the placeholder value on all appropriate elements
231
+ function enablePlaceholders(node) {
232
+ handleElem(node, showPlaceholder);
233
+ }
234
+
235
+ // Returns a function that is used as a focus event handler
236
+ function makeFocusHandler(elem) {
237
+ return function () {
238
+
239
+ // Only hide the placeholder value if the (default) hide-on-focus behaviour is enabled
240
+ if (hideOnInput && elem.value === elem.getAttribute(ATTR_CURRENT_VAL) && elem.getAttribute(ATTR_ACTIVE) === "true") {
241
+
242
+ // Move the caret to the start of the input (this mimics the behaviour of all browsers that do not hide the placeholder on focus)
243
+ Utils.moveCaret(elem, 0);
244
+
245
+ } else {
246
+
247
+ // Remove the placeholder
248
+ hidePlaceholder(elem);
249
+ }
250
+ };
251
+ }
252
+
253
+ // Returns a function that is used as a blur event handler
254
+ function makeBlurHandler(elem) {
255
+ return function () {
256
+ showPlaceholder(elem);
257
+ };
258
+ }
259
+
260
+ // Functions that are used as a event handlers when the hide-on-input behaviour has been activated - very basic implementation of the "input" event
261
+ function makeKeydownHandler(elem) {
262
+ return function (e) {
263
+ keydownVal = elem.value;
264
+
265
+ //Prevent the use of the arrow keys (try to keep the cursor before the placeholder)
266
+ if (elem.getAttribute(ATTR_ACTIVE) === "true") {
267
+ if (keydownVal === elem.getAttribute(ATTR_CURRENT_VAL) && Utils.inArray(badKeys, e.keyCode)) {
268
+ if (e.preventDefault) {
269
+ e.preventDefault();
270
+ }
271
+ return false;
272
+ }
273
+ }
274
+ };
275
+ }
276
+ function makeKeyupHandler(elem) {
277
+ return function () {
278
+ hidePlaceholder(elem, keydownVal);
279
+
280
+ // If the element is now empty we need to show the placeholder
281
+ if (elem.value === "") {
282
+ elem.blur();
283
+ Utils.moveCaret(elem, 0);
284
+ }
285
+ };
286
+ }
287
+ function makeClickHandler(elem) {
288
+ return function () {
289
+ if (elem === document.activeElement && elem.value === elem.getAttribute(ATTR_CURRENT_VAL) && elem.getAttribute(ATTR_ACTIVE) === "true") {
290
+ Utils.moveCaret(elem, 0);
291
+ }
292
+ };
293
+ }
294
+
295
+ // Returns a function that is used as a submit event handler on form elements that have children affected by this polyfill
296
+ function makeSubmitHandler(form) {
297
+ return function () {
298
+
299
+ // Turn off placeholders on all appropriate descendant elements
300
+ disablePlaceholders(form);
301
+ };
302
+ }
303
+
304
+ // Bind event handlers to an element that we need to affect with the polyfill
305
+ function newElement(elem) {
306
+
307
+ // If the element is part of a form, make sure the placeholder string is not submitted as a value
308
+ if (elem.form) {
309
+ form = elem.form;
310
+
311
+ // Set a flag on the form so we know it's been handled (forms can contain multiple inputs)
312
+ if (!form.getAttribute(ATTR_FORM_HANDLED)) {
313
+ Utils.addEventListener(form, "submit", makeSubmitHandler(form));
314
+ form.setAttribute(ATTR_FORM_HANDLED, "true");
315
+ }
316
+ }
317
+
318
+ // Bind event handlers to the element so we can hide/show the placeholder as appropriate
319
+ Utils.addEventListener(elem, "focus", makeFocusHandler(elem));
320
+ Utils.addEventListener(elem, "blur", makeBlurHandler(elem));
321
+
322
+ // If the placeholder should hide on input rather than on focus we need additional event handlers
323
+ if (hideOnInput) {
324
+ Utils.addEventListener(elem, "keydown", makeKeydownHandler(elem));
325
+ Utils.addEventListener(elem, "keyup", makeKeyupHandler(elem));
326
+ Utils.addEventListener(elem, "click", makeClickHandler(elem));
327
+ }
328
+
329
+ // Remember that we've bound event handlers to this element
330
+ elem.setAttribute(ATTR_EVENTS_BOUND, "true");
331
+ elem.setAttribute(ATTR_CURRENT_VAL, placeholder);
332
+
333
+ // If the element doesn't have a value and is not focussed, set it to the placeholder string
334
+ if (hideOnInput || elem !== document.activeElement) {
335
+ showPlaceholder(elem);
336
+ }
337
+ }
338
+
339
+ Placeholders.nativeSupport = test.placeholder !== void 0;
340
+
341
+ if (!Placeholders.nativeSupport) {
342
+
343
+ // Get references to all the input and textarea elements currently in the DOM (live NodeList objects to we only need to do this once)
344
+ inputs = document.getElementsByTagName("input");
345
+ textareas = document.getElementsByTagName("textarea");
346
+
347
+ // Get any settings declared as data-* attributes on the root element (currently the only options are whether to hide the placeholder on focus or input and whether to auto-update)
348
+ hideOnInput = root.getAttribute(ATTR_OPTION_FOCUS) === "false";
349
+ liveUpdates = root.getAttribute(ATTR_OPTION_LIVE) !== "false";
350
+
351
+ // Create style element for placeholder styles (instead of directly setting style properties on elements - allows for better flexibility alongside user-defined styles)
352
+ styleElem = document.createElement("style");
353
+ styleElem.type = "text/css";
354
+
355
+ // Create style rules as text node
356
+ styleRules = document.createTextNode("." + placeholderClassName + " { color:" + placeholderStyleColor + "; }");
357
+
358
+ // Append style rules to newly created stylesheet
359
+ if (styleElem.styleSheet) {
360
+ styleElem.styleSheet.cssText = styleRules.nodeValue;
361
+ } else {
362
+ styleElem.appendChild(styleRules);
363
+ }
364
+
365
+ // Prepend new style element to the head (before any existing stylesheets, so user-defined rules take precedence)
366
+ head.insertBefore(styleElem, head.firstChild);
367
+
368
+ // Set up the placeholders
369
+ for (i = 0, len = inputs.length + textareas.length; i < len; i++) {
370
+ elem = i < inputs.length ? inputs[i] : textareas[i - inputs.length];
371
+
372
+ // Get the value of the placeholder attribute, if any. IE10 emulating IE7 fails with getAttribute, hence the use of the attributes node
373
+ placeholder = elem.attributes.placeholder;
374
+ if (placeholder) {
375
+
376
+ // IE returns an empty object instead of undefined if the attribute is not present
377
+ placeholder = placeholder.nodeValue;
378
+
379
+ // Only apply the polyfill if this element is of a type that supports placeholders, and has a placeholder attribute with a non-empty value
380
+ if (placeholder && Utils.inArray(validTypes, elem.type)) {
381
+ newElement(elem);
382
+ }
383
+ }
384
+ }
385
+
386
+ // If enabled, the polyfill will repeatedly check for changed/added elements and apply to those as well
387
+ timer = setInterval(function () {
388
+ for (i = 0, len = inputs.length + textareas.length; i < len; i++) {
389
+ elem = i < inputs.length ? inputs[i] : textareas[i - inputs.length];
390
+
391
+ // Only apply the polyfill if this element is of a type that supports placeholders, and has a placeholder attribute with a non-empty value
392
+ placeholder = elem.attributes.placeholder;
393
+ if (placeholder) {
394
+ placeholder = placeholder.nodeValue;
395
+ if (placeholder && Utils.inArray(validTypes, elem.type)) {
396
+
397
+ // If the element hasn't had event handlers bound to it then add them
398
+ if (!elem.getAttribute(ATTR_EVENTS_BOUND)) {
399
+ newElement(elem);
400
+ }
401
+
402
+ // If the placeholder value has changed or not been initialised yet we need to update the display
403
+ if (placeholder !== elem.getAttribute(ATTR_CURRENT_VAL) || (elem.type === "password" && !elem.getAttribute(ATTR_INPUT_TYPE))) {
404
+
405
+ // Attempt to change the type of password inputs (fails in IE < 9)
406
+ if (elem.type === "password" && !elem.getAttribute(ATTR_INPUT_TYPE) && Utils.changeType(elem, "text")) {
407
+ elem.setAttribute(ATTR_INPUT_TYPE, "password");
408
+ }
409
+
410
+ // If the placeholder value has changed and the placeholder is currently on display we need to change it
411
+ if (elem.value === elem.getAttribute(ATTR_CURRENT_VAL)) {
412
+ elem.value = placeholder;
413
+ }
414
+
415
+ // Keep a reference to the current placeholder value in case it changes via another script
416
+ elem.setAttribute(ATTR_CURRENT_VAL, placeholder);
417
+ }
418
+ }
419
+ } else if (elem.getAttribute(ATTR_ACTIVE)) {
420
+ hidePlaceholder(elem);
421
+ elem.removeAttribute(ATTR_CURRENT_VAL);
422
+ }
423
+ }
424
+
425
+ // If live updates are not enabled cancel the timer
426
+ if (!liveUpdates) {
427
+ clearInterval(timer);
428
+ }
429
+ }, 100);
430
+ }
431
+
432
+ // Expose public methods
433
+ Placeholders.disable = Placeholders.nativeSupport ? noop : disablePlaceholders;
434
+ Placeholders.enable = Placeholders.nativeSupport ? noop : enablePlaceholders;
435
+
436
+ }(this));
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: placeholder-gem
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.0.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Edward Look
9
+ - Christian Vuerings
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2013-10-28 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: railties
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '3.1'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '3.1'
31
+ - !ruby/object:Gem::Dependency
32
+ name: bundler
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: 1.2.2
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: 1.2.2
47
+ - !ruby/object:Gem::Dependency
48
+ name: tzinfo
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: nokogiri
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ - !ruby/object:Gem::Dependency
80
+ name: coveralls
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ type: :development
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ description: Include Placeholder.js in your Rails projects
96
+ email:
97
+ - edwlook@gmail.com
98
+ - vueringschristian@gmail.com
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - lib/placeholder-gem/version.rb
104
+ - lib/placeholder-gem.rb
105
+ - vendor/assets/javascripts/placeholder.js
106
+ - vendor/assets/javascripts/v3.0.0/placeholder.js
107
+ - MIT-LICENSE
108
+ - Rakefile
109
+ - README.md
110
+ homepage: http://github.com/ets-berkeley-edu/placeholder-gem
111
+ licenses: []
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ! '>='
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ! '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ requirements: []
129
+ rubyforge_project:
130
+ rubygems_version: 1.8.23
131
+ signing_key:
132
+ specification_version: 3
133
+ summary: Placeholder.js Javascript Polyfill for HTML5 as a gem
134
+ test_files: []