awesomplete 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8bc888afcc2ca4a3fb55078e2a8d1b7cbc881d00
4
+ data.tar.gz: cf91eb1821b5042bb612a0cbcd519881044c8c64
5
+ SHA512:
6
+ metadata.gz: 2f084423cc21279899d57af715b5d37b868d67d7a58ea232d5fe4b4ebefe635506d9aa88a4bd4f701074c6686c64d7b5607d1ebeb0e6ee1f876d5cab60f4094a
7
+ data.tar.gz: d4fd43cccab1963e5d6413df6d46f3e86abcd53bed39928de1ac883367a0bc7029408eb386a0168381f5b5666f72a766727875cd5cd03b3c5c744f20b7d32c2f
@@ -0,0 +1,20 @@
1
+ Copyright 2015 fishbullet
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.
@@ -0,0 +1,58 @@
1
+ ## [Awesomplete](http://leaverou.github.io/awesomplete) For Rails ##
2
+
3
+ This is small gem add to your Rails app [Awesomplete](https://github.com/LeaVerou/awesomplete) autocomplete.
4
+
5
+ This is the working version.
6
+ ```rbcon
7
+ # Developed and tested on:
8
+ Ruby 2.1.0
9
+ Rails ~> 4.0.0
10
+ ```
11
+ ## Getting started
12
+ 1. Add to `Gemfile` and `bundle install`.
13
+
14
+ ```ruby
15
+ gem 'awesomplete'
16
+ ```
17
+
18
+ 2. Add to `app/assets/javascripts/application.js`:
19
+
20
+ ```js
21
+ //=require awesomplete
22
+ ```
23
+
24
+ 3. Add to `app/assets/stylesheets/application.css`
25
+
26
+ ```css
27
+ *= require awesomplete
28
+ ```
29
+
30
+ Restart server. That's it.
31
+
32
+ ## Helpers
33
+ Now you can write small and awesomplete inputs.
34
+ I find it is very cool for small collections, check it out:
35
+
36
+ ```erb
37
+
38
+ ```
39
+
40
+ ## Configure module
41
+ You can configurate this autocomplete by two ways:
42
+
43
+ 1. In `data-` options in views:
44
+
45
+ ```erb
46
+ #TODO
47
+ ```
48
+
49
+ 2. In `javascripts` initializer (e.g. `app/assets/javascripts/some_script.js`):
50
+
51
+ ```javascript
52
+ #TODO
53
+ ```
54
+ * * *
55
+
56
+ Kiselenko Roman
57
+
58
+ This project rocks and uses MIT-LICENSE.
@@ -0,0 +1,8 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ Bundler::GemHelper.install_tasks
8
+
@@ -0,0 +1,359 @@
1
+ /**
2
+ * Simple, lightweight, usable local autocomplete library for modern browsers
3
+ * Because there weren’t enough autocomplete scripts in the world? Because I’m completely insane and have NIH syndrome? Probably both. :P
4
+ * @author Lea Verou http://leaverou.github.io/awesomplete
5
+ * MIT license
6
+ */
7
+
8
+ (function () {
9
+
10
+ var _ = self.Awesomplete = function (input, o) {
11
+ var me = this;
12
+
13
+ // Setup
14
+
15
+ this.input = input;
16
+ input.setAttribute("aria-autocomplete", "list");
17
+
18
+ o = o || {};
19
+
20
+ configure.call(this, {
21
+ minChars: 2,
22
+ maxItems: 10,
23
+ autoFirst: false,
24
+ filter: _.FILTER_CONTAINS,
25
+ sort: _.SORT_BYLENGTH,
26
+ item: function (text, input) {
27
+ return $.create("li", {
28
+ innerHTML: text.replace(RegExp($.regExpEscape(input.trim()), "gi"), "<mark>$&</mark>"),
29
+ "aria-selected": "false"
30
+ });
31
+ },
32
+ replace: function (text) {
33
+ this.input.value = text;
34
+ }
35
+ }, o);
36
+
37
+ this.index = -1;
38
+
39
+ // Create necessary elements
40
+
41
+ this.container = $.create("div", {
42
+ className: "awesomplete",
43
+ around: input
44
+ });
45
+
46
+ this.ul = $.create("ul", {
47
+ hidden: "",
48
+ inside: this.container
49
+ });
50
+
51
+ this.status = $.create("span", {
52
+ className: "visually-hidden",
53
+ role: "status",
54
+ "aria-live": "assertive",
55
+ "aria-relevant": "additions",
56
+ inside: this.container
57
+ });
58
+
59
+ // Bind events
60
+
61
+ $.bind(this.input, {
62
+ "input": this.evaluate.bind(this),
63
+ "blur": this.close.bind(this),
64
+ "keydown": function(evt) {
65
+ var c = evt.keyCode;
66
+
67
+ if (c === 13 && me.selected) { // Enter
68
+ evt.preventDefault();
69
+ me.select();
70
+ }
71
+ else if (c === 27) { // Esc
72
+ me.close();
73
+ }
74
+ else if (c === 38 || c === 40) { // Down/Up arrow
75
+ evt.preventDefault();
76
+ me[c === 38? "previous" : "next"]();
77
+ }
78
+ }
79
+ });
80
+
81
+ $.bind(this.input.form, {"submit": me.close.bind(me)});
82
+
83
+ $.bind(this.ul, {"mousedown": function(evt) {
84
+ var li = evt.target;
85
+
86
+ if (li !== this) {
87
+
88
+ while (li && !/li/i.test(li.nodeName)) {
89
+ li = li.parentNode;
90
+ }
91
+
92
+ if (li) {
93
+ me.select(li);
94
+ }
95
+ }
96
+ }});
97
+
98
+ if (input.hasAttribute("list")) {
99
+ this.list = "#" + input.getAttribute("list");
100
+ input.removeAttribute("list");
101
+ }
102
+ else {
103
+ this.list = input.getAttribute("data-list") || o.list || [];
104
+ }
105
+
106
+ _.all.push(this);
107
+ };
108
+
109
+ _.prototype = {
110
+ set list(list) {
111
+ if (Array.isArray(list)) {
112
+ this._list = list;
113
+ }
114
+ else if (typeof list === "string" && list.indexOf(",") > -1) {
115
+ this._list = list.split(/\s*,\s*/);
116
+ }
117
+ else { // Element or CSS selector
118
+ list = $(list);
119
+
120
+ if (list && list.children) {
121
+ this._list = slice.apply(list.children).map(function (el) {
122
+ return el.innerHTML.trim();
123
+ });
124
+ }
125
+ }
126
+
127
+ if (document.activeElement === this.input) {
128
+ this.evaluate();
129
+ }
130
+ },
131
+
132
+ get selected() {
133
+ return this.index > -1;
134
+ },
135
+
136
+ close: function () {
137
+ this.ul.setAttribute("hidden", "");
138
+ this.index = -1;
139
+
140
+ $.fire(this.input, "awesomplete-close");
141
+ },
142
+
143
+ open: function () {
144
+ this.ul.removeAttribute("hidden");
145
+
146
+ if (this.autoFirst && this.index === -1) {
147
+ this.goto(0);
148
+ }
149
+
150
+ $.fire(this.input, "awesomplete-open");
151
+ },
152
+
153
+ next: function () {
154
+ var count = this.ul.children.length;
155
+
156
+ this.goto(this.index < count - 1? this.index + 1 : -1);
157
+ },
158
+
159
+ previous: function () {
160
+ var count = this.ul.children.length;
161
+
162
+ this.goto(this.selected? this.index - 1 : count - 1);
163
+ },
164
+
165
+ // Should not be used, highlights specific item without any checks!
166
+ goto: function (i) {
167
+ var lis = this.ul.children;
168
+
169
+ if (this.selected) {
170
+ lis[this.index].setAttribute("aria-selected", "false");
171
+ }
172
+
173
+ this.index = i;
174
+
175
+ if (i > -1 && lis.length > 0) {
176
+ lis[i].setAttribute("aria-selected", "true");
177
+ this.status.textContent = lis[i].textContent;
178
+ }
179
+ },
180
+
181
+ select: function (selected) {
182
+ selected = selected || this.ul.children[this.index];
183
+
184
+ if (selected) {
185
+ var prevented;
186
+
187
+ $.fire(this.input, "awesomplete-select", {
188
+ text: selected.textContent,
189
+ preventDefault: function () {
190
+ prevented = true;
191
+ }
192
+ });
193
+
194
+ if (!prevented) {
195
+ this.replace(selected.textContent);
196
+ this.close();
197
+ $.fire(this.input, "awesomplete-selectcomplete");
198
+ }
199
+ }
200
+ },
201
+
202
+ evaluate: function() {
203
+ var me = this;
204
+ var value = this.input.value;
205
+
206
+ if (value.length >= this.minChars && this._list.length > 0) {
207
+ this.index = -1;
208
+ // Populate list with options that match
209
+ this.ul.innerHTML = "";
210
+
211
+ this._list
212
+ .filter(function(item) {
213
+ return me.filter(item, value);
214
+ })
215
+ .sort(this.sort)
216
+ .every(function(text, i) {
217
+ me.ul.appendChild(me.item(text, value));
218
+
219
+ return i < me.maxItems - 1;
220
+ });
221
+
222
+ this.open();
223
+ }
224
+ else {
225
+ this.close();
226
+ }
227
+ }
228
+ };
229
+
230
+ // Static methods/properties
231
+
232
+ _.all = [];
233
+
234
+ _.FILTER_CONTAINS = function (text, input) {
235
+ return RegExp($.regExpEscape(input.trim()), "i").test(text);
236
+ };
237
+
238
+ _.FILTER_STARTSWITH = function (text, input) {
239
+ return RegExp("^" + $.regExpEscape(input.trim()), "i").test(text);
240
+ };
241
+
242
+ _.SORT_BYLENGTH = function (a, b) {
243
+ if (a.length !== b.length) {
244
+ return a.length - b.length;
245
+ }
246
+
247
+ return a < b? -1 : 1;
248
+ };
249
+
250
+ // Private functions
251
+
252
+ function configure(properties, o) {
253
+ for (var i in properties) {
254
+ var initial = properties[i],
255
+ attrValue = this.input.getAttribute("data-" + i.toLowerCase());
256
+
257
+ if (typeof initial === "number") {
258
+ this[i] = +attrValue;
259
+ }
260
+ else if (initial === false) { // Boolean options must be false by default anyway
261
+ this[i] = attrValue !== null;
262
+ }
263
+ else if (initial instanceof Function) {
264
+ this[i] = null;
265
+ }
266
+ else {
267
+ this[i] = attrValue;
268
+ }
269
+
270
+ this[i] = this[i] || o[i] || initial;
271
+ }
272
+ }
273
+
274
+ // Helpers
275
+
276
+ var slice = Array.prototype.slice;
277
+
278
+ function $(expr, con) {
279
+ return typeof expr === "string"? (con || document).querySelector(expr) : expr || null;
280
+ }
281
+
282
+ function $$(expr, con) {
283
+ return slice.call((con || document).querySelectorAll(expr));
284
+ }
285
+
286
+ $.create = function(tag, o) {
287
+ var element = document.createElement(tag);
288
+
289
+ for (var i in o) {
290
+ var val = o[i];
291
+
292
+ if (i === "inside") {
293
+ $(val).appendChild(element);
294
+ }
295
+ else if (i === "around") {
296
+ var ref = $(val);
297
+ ref.parentNode.insertBefore(element, ref);
298
+ element.appendChild(ref);
299
+ }
300
+ else if (i in element) {
301
+ element[i] = val;
302
+ }
303
+ else {
304
+ element.setAttribute(i, val);
305
+ }
306
+ }
307
+
308
+ return element;
309
+ };
310
+
311
+ $.bind = function(element, o) {
312
+ if (element) {
313
+ for (var event in o) {
314
+ var callback = o[event];
315
+
316
+ event.split(/\s+/).forEach(function (event) {
317
+ element.addEventListener(event, callback);
318
+ });
319
+ }
320
+ }
321
+ };
322
+
323
+ $.fire = function(target, type, properties) {
324
+ var evt = document.createEvent("HTMLEvents");
325
+
326
+ evt.initEvent(type, true, true );
327
+
328
+ for (var j in properties) {
329
+ evt[j] = properties[j];
330
+ }
331
+
332
+ target.dispatchEvent(evt);
333
+ };
334
+
335
+ $.regExpEscape = function (s) {
336
+ return s.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
337
+ }
338
+
339
+ // Initialization
340
+
341
+ function init() {
342
+ $$("input.awesomplete").forEach(function (input) {
343
+ new Awesomplete(input);
344
+ });
345
+ }
346
+
347
+ // DOM already loaded?
348
+ if (document.readyState !== "loading") {
349
+ init();
350
+ }
351
+ else {
352
+ // Wait for it
353
+ document.addEventListener("DOMContentLoaded", init);
354
+ }
355
+
356
+ _.$ = $;
357
+ _.$$ = $$;
358
+
359
+ })();
@@ -0,0 +1,97 @@
1
+ [hidden] { display: none; }
2
+
3
+ .visually-hidden {
4
+ position: absolute;
5
+ clip: rect(0, 0, 0, 0);
6
+ }
7
+
8
+ div.awesomplete {
9
+ display: inline-block;
10
+ position: relative;
11
+ }
12
+
13
+ div.awesomplete > input {
14
+ display: block;
15
+ }
16
+
17
+ div.awesomplete > ul {
18
+ position: absolute;
19
+ left: 0;
20
+ z-index: 1;
21
+ min-width: 100%;
22
+ box-sizing: border-box;
23
+ list-style: none;
24
+ padding: 0;
25
+ border-radius: .3em;
26
+ margin: .2em 0 0;
27
+ background: hsla(0,0%,100%,.9);
28
+ background: linear-gradient(to bottom right, white, hsla(0,0%,100%,.8));
29
+ border: 1px solid rgba(0,0,0,.3);
30
+ box-shadow: .05em .2em .6em rgba(0,0,0,.2);
31
+ text-shadow: none;
32
+ }
33
+
34
+ div.awesomplete > ul[hidden],
35
+ div.awesomplete > ul:empty {
36
+ display: none;
37
+ }
38
+
39
+ @supports (transform: scale(0)) {
40
+ div.awesomplete > ul {
41
+ transition: .3s cubic-bezier(.4,.2,.5,1.4);
42
+ transform-origin: 1.43em -.43em;
43
+ }
44
+
45
+ div.awesomplete > ul[hidden],
46
+ div.awesomplete > ul:empty {
47
+ opacity: 0;
48
+ transform: scale(0);
49
+ display: block;
50
+ transition-timing-function: ease;
51
+ }
52
+ }
53
+
54
+ /* Pointer */
55
+ div.awesomplete > ul:before {
56
+ content: "";
57
+ position: absolute;
58
+ top: -.43em;
59
+ left: 1em;
60
+ width: 0; height: 0;
61
+ padding: .4em;
62
+ background: white;
63
+ border: inherit;
64
+ border-right: 0;
65
+ border-bottom: 0;
66
+ -webkit-transform: rotate(45deg);
67
+ transform: rotate(45deg);
68
+ }
69
+
70
+ div.awesomplete > ul > li {
71
+ position: relative;
72
+ padding: .2em .5em;
73
+ cursor: pointer;
74
+ }
75
+
76
+ div.awesomplete > ul > li:hover {
77
+ background: hsl(200, 40%, 80%);
78
+ color: black;
79
+ }
80
+
81
+ div.awesomplete > ul > li[aria-selected="true"] {
82
+ background: hsl(205, 40%, 40%);
83
+ color: white;
84
+ }
85
+
86
+ div.awesomplete mark {
87
+ background: hsl(65, 100%, 50%);
88
+ }
89
+
90
+ div.awesomplete li:hover mark {
91
+ background: hsl(68, 101%, 41%);
92
+ }
93
+
94
+ div.awesomplete li[aria-selected="true"] mark {
95
+ background: hsl(86, 102%, 21%);
96
+ color: inherit;
97
+ }
@@ -0,0 +1,5 @@
1
+ module Awesomplete
2
+ class Engine < ::Rails::Engine
3
+ config.assets.paths << "app/assets"
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module Awesomplete
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :awesomplete do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: awesomplete
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - fishbullet
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 4.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 4.0.0
27
+ description: Add assets to your Rails app assets path. Based on http://leaverou.github.io/awesomplete
28
+ email:
29
+ - shindu666@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - MIT-LICENSE
35
+ - README.md
36
+ - Rakefile
37
+ - app/assets/javascripts/awesomplete.js
38
+ - app/assets/stylesheets/awesomplete.css
39
+ - lib/awesomplete.rb
40
+ - lib/awesomplete/version.rb
41
+ - lib/tasks/awesomplete_tasks.rake
42
+ homepage: http://www.some.com
43
+ licenses:
44
+ - MIT
45
+ metadata: {}
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ requirements: []
61
+ rubyforge_project:
62
+ rubygems_version: 2.4.3
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: This is small gem add to your Rails app awesomplete autocomplete.
66
+ test_files: []