placeholder-gem 3.0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []