selectBoxIt 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +52 -0
- data/Rakefile +2 -0
- data/app/assets/javascripts/selectBoxIt/jquery.selectBoxIt.js +3259 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.add.js +183 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.ariaAccessibility.js +117 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.copyAttributes.js +63 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.core.js +1802 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.destroy.js +58 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.disable.js +137 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.dynamicPositioning.js +102 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.enable.js +76 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.endClosure.js +1 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.keyboardNavigation.js +143 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.keyboardSearch.js +209 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.mobile.js +158 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.remove.js +90 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.selectOption.js +36 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.setOption.js +33 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.setOptions.js +32 -0
- data/app/assets/javascripts/selectBoxIt/modules/jquery.selectBoxIt.wait.js +19 -0
- data/app/assets/stylesheets/selectBoxIt/jquery.selectBoxIt.css +278 -0
- data/lib/selectBoxIt.rb +6 -0
- data/lib/selectBoxIt/engine.rb +4 -0
- data/lib/selectBoxIt/version.rb +3 -0
- data/selectBoxIt.gemspec +23 -0
- metadata +100 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
|
|
2
|
+
// Keyboard Search Module
|
|
3
|
+
// ======================
|
|
4
|
+
|
|
5
|
+
// _Set Current Search Option
|
|
6
|
+
// -------------------------
|
|
7
|
+
// Sets the currently selected dropdown list search option
|
|
8
|
+
|
|
9
|
+
selectBoxIt._setCurrentSearchOption = function(currentOption) {
|
|
10
|
+
|
|
11
|
+
var self = this;
|
|
12
|
+
|
|
13
|
+
// Does not change the current option if `showFirstOption` is false and the matched search item is the hidden first option.
|
|
14
|
+
// Otherwise, the current option value is updated
|
|
15
|
+
if ((self.options["aggressiveChange"] || self.options["selectWhenHidden"] || self.listItems.eq(currentOption).is(":visible")) && self.listItems.eq(currentOption).data("disabled") !== true) {
|
|
16
|
+
|
|
17
|
+
// Calls the `blur` event of the currently selected dropdown list option
|
|
18
|
+
self.listItems.eq(self.currentFocus).blur();
|
|
19
|
+
|
|
20
|
+
// Sets `currentIndex` to the currently selected dropdown list option
|
|
21
|
+
self.currentIndex = currentOption;
|
|
22
|
+
|
|
23
|
+
// Sets `currentFocus` to the currently selected dropdown list option
|
|
24
|
+
self.currentFocus = currentOption;
|
|
25
|
+
|
|
26
|
+
// Focuses the currently selected dropdown list option
|
|
27
|
+
self.listItems.eq(self.currentFocus).focusin();
|
|
28
|
+
|
|
29
|
+
// Updates the scrollTop so that the currently selected dropdown list option is visible to the user
|
|
30
|
+
self._scrollToView("search");
|
|
31
|
+
|
|
32
|
+
// Triggers the custom `search` event on the original select box
|
|
33
|
+
self.triggerEvent("search");
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Maintains chainability
|
|
38
|
+
return self;
|
|
39
|
+
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// _Search Algorithm
|
|
43
|
+
// -----------------
|
|
44
|
+
// Uses regular expressions to find text matches
|
|
45
|
+
selectBoxIt._searchAlgorithm = function(currentIndex, alphaNumeric) {
|
|
46
|
+
|
|
47
|
+
var self = this,
|
|
48
|
+
|
|
49
|
+
// Boolean to determine if a pattern match exists
|
|
50
|
+
matchExists = false,
|
|
51
|
+
|
|
52
|
+
// Iteration variable used in the outermost for loop
|
|
53
|
+
x,
|
|
54
|
+
|
|
55
|
+
// Iteration variable used in the nested for loop
|
|
56
|
+
y,
|
|
57
|
+
|
|
58
|
+
// Variable used to cache the length of the text array (Small enhancement to speed up traversing)
|
|
59
|
+
arrayLength,
|
|
60
|
+
|
|
61
|
+
// Variable storing the current search
|
|
62
|
+
currentSearch,
|
|
63
|
+
|
|
64
|
+
// Variable storing the textArray property
|
|
65
|
+
textArray = self.textArray,
|
|
66
|
+
|
|
67
|
+
// Variable storing the current text property
|
|
68
|
+
currentText = self.currentText;
|
|
69
|
+
|
|
70
|
+
// Loops through the text array to find a pattern match
|
|
71
|
+
for (x = currentIndex, arrayLength = textArray.length; x < arrayLength; x += 1) {
|
|
72
|
+
|
|
73
|
+
currentSearch = textArray[x];
|
|
74
|
+
|
|
75
|
+
// Nested for loop to help search for a pattern match with the currently traversed array item
|
|
76
|
+
for (y = 0; y < arrayLength; y += 1) {
|
|
77
|
+
|
|
78
|
+
// Searches for a match
|
|
79
|
+
if (textArray[y].search(alphaNumeric) !== -1) {
|
|
80
|
+
|
|
81
|
+
// `matchExists` is set to true if there is a match
|
|
82
|
+
matchExists = true;
|
|
83
|
+
|
|
84
|
+
// Exits the nested for loop
|
|
85
|
+
y = arrayLength;
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
} // End nested for loop
|
|
90
|
+
|
|
91
|
+
// If a match does not exist
|
|
92
|
+
if (!matchExists) {
|
|
93
|
+
|
|
94
|
+
// Sets the current text to the last entered character
|
|
95
|
+
self.currentText = self.currentText.charAt(self.currentText.length - 1).
|
|
96
|
+
|
|
97
|
+
// Escapes the regular expression to make sure special characters are seen as literal characters instead of special commands
|
|
98
|
+
replace(/[|()\[{.+*?$\\]/g, "\\$0");
|
|
99
|
+
|
|
100
|
+
currentText = self.currentText;
|
|
101
|
+
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Resets the regular expression with the new value of `self.currentText`
|
|
105
|
+
alphaNumeric = new RegExp(currentText, "gi");
|
|
106
|
+
|
|
107
|
+
// Searches based on the first letter of the dropdown list options text if the currentText < 3 characters
|
|
108
|
+
if (currentText.length < 3) {
|
|
109
|
+
|
|
110
|
+
alphaNumeric = new RegExp(currentText.charAt(0), "gi");
|
|
111
|
+
|
|
112
|
+
// If there is a match based on the first character
|
|
113
|
+
if ((currentSearch.charAt(0).search(alphaNumeric) !== -1)) {
|
|
114
|
+
|
|
115
|
+
// Sets properties of that dropdown list option to make it the currently selected option
|
|
116
|
+
self._setCurrentSearchOption(x);
|
|
117
|
+
|
|
118
|
+
if((currentSearch.substring(0, currentText.length).toLowerCase() !== currentText.toLowerCase()) || self.options["similarSearch"]) {
|
|
119
|
+
|
|
120
|
+
// Increments the current index by one
|
|
121
|
+
self.currentIndex += 1;
|
|
122
|
+
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Exits the search
|
|
126
|
+
return false;
|
|
127
|
+
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// If `self.currentText` > 1 character
|
|
133
|
+
else {
|
|
134
|
+
|
|
135
|
+
// If there is a match based on the entire string
|
|
136
|
+
if ((currentSearch.search(alphaNumeric) !== -1)) {
|
|
137
|
+
|
|
138
|
+
// Sets properties of that dropdown list option to make it the currently selected option
|
|
139
|
+
self._setCurrentSearchOption(x);
|
|
140
|
+
|
|
141
|
+
// Exits the search
|
|
142
|
+
return false;
|
|
143
|
+
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// If the current text search is an exact match
|
|
149
|
+
if (currentSearch.toLowerCase() === self.currentText.toLowerCase()) {
|
|
150
|
+
|
|
151
|
+
// Sets properties of that dropdown list option to make it the currently selected option
|
|
152
|
+
self._setCurrentSearchOption(x);
|
|
153
|
+
|
|
154
|
+
// Resets the current text search to a blank string to start fresh again
|
|
155
|
+
self.currentText = "";
|
|
156
|
+
|
|
157
|
+
// Exits the search
|
|
158
|
+
return false;
|
|
159
|
+
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Returns true if there is not a match at all
|
|
165
|
+
return true;
|
|
166
|
+
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// Search
|
|
170
|
+
// ------
|
|
171
|
+
// Calls searchAlgorithm()
|
|
172
|
+
selectBoxIt.search = function(alphaNumericKey, callback, rememberPreviousSearch) {
|
|
173
|
+
|
|
174
|
+
var self = this;
|
|
175
|
+
|
|
176
|
+
// If the search method is being called internally by the plugin, and not externally as a method by a user
|
|
177
|
+
if (rememberPreviousSearch) {
|
|
178
|
+
|
|
179
|
+
// Continued search with history from past searches. Properly escapes the regular expression
|
|
180
|
+
self.currentText += alphaNumericKey.replace(/[|()\[{.+*?$\\]/g, "\\$0");
|
|
181
|
+
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
else {
|
|
185
|
+
|
|
186
|
+
// Brand new search. Properly escapes the regular expression
|
|
187
|
+
self.currentText = alphaNumericKey.replace(/[|()\[{.+*?$\\]/g, "\\$0");
|
|
188
|
+
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Searches globally
|
|
192
|
+
var searchResults = self._searchAlgorithm(self.currentIndex, new RegExp(self.currentText, "gi"));
|
|
193
|
+
|
|
194
|
+
// Searches the list again if a match is not found. This is needed, because the first search started at the array indece of the currently selected dropdown list option, and does not search the options before the current array indece.
|
|
195
|
+
// If there are many similar dropdown list options, starting the search at the indece of the currently selected dropdown list option is needed to properly traverse the text array.
|
|
196
|
+
if (searchResults) {
|
|
197
|
+
|
|
198
|
+
// Searches the dropdown list values starting from the beginning of the text array
|
|
199
|
+
self._searchAlgorithm(0, self.currentText);
|
|
200
|
+
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Provide callback function support
|
|
204
|
+
self._callbackSupport(callback);
|
|
205
|
+
|
|
206
|
+
// Maintains chainability
|
|
207
|
+
return self;
|
|
208
|
+
|
|
209
|
+
};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
|
|
2
|
+
// Mobile Module
|
|
3
|
+
// =============
|
|
4
|
+
|
|
5
|
+
// Set Mobile Text
|
|
6
|
+
// ---------------
|
|
7
|
+
// Updates the text of the drop down
|
|
8
|
+
selectBoxIt._updateMobileText = function() {
|
|
9
|
+
|
|
10
|
+
var self = this,
|
|
11
|
+
currentOption,
|
|
12
|
+
currentDataText,
|
|
13
|
+
currentText;
|
|
14
|
+
|
|
15
|
+
currentOption = self.selectBox.find("option").filter(":selected");
|
|
16
|
+
|
|
17
|
+
currentDataText = currentOption.attr("data-text");
|
|
18
|
+
|
|
19
|
+
currentText = currentDataText ? currentDataText: currentOption.text();
|
|
20
|
+
|
|
21
|
+
// Sets the new dropdown list text to the value of the original dropdown list
|
|
22
|
+
self._setText(self.dropdownText, currentText);
|
|
23
|
+
|
|
24
|
+
if(self.list.find('li[data-val="' + currentOption.val() + '"]').find("i").attr("class")) {
|
|
25
|
+
|
|
26
|
+
self.dropdownImage.attr("class", self.list.find('li[data-val="' + currentOption.val() + '"]').find("i").attr("class")).addClass("selectboxit-default-icon");
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Apply Native Select
|
|
33
|
+
// -------------------
|
|
34
|
+
// Applies the original select box directly over the new drop down
|
|
35
|
+
|
|
36
|
+
selectBoxIt._applyNativeSelect = function() {
|
|
37
|
+
|
|
38
|
+
// Stores the plugin context inside of the self variable
|
|
39
|
+
var self = this;
|
|
40
|
+
|
|
41
|
+
// Appends the native select box to the drop down (allows for relative positioning using the position() method)
|
|
42
|
+
self.dropdownContainer.append(self.selectBox);
|
|
43
|
+
|
|
44
|
+
self.dropdown.attr("tabindex", "-1");
|
|
45
|
+
|
|
46
|
+
// Positions the original select box directly over top the new dropdown list using position absolute and "hides" the original select box using an opacity of 0. This allows the mobile browser "wheel" interface for better usability.
|
|
47
|
+
self.selectBox.css({
|
|
48
|
+
|
|
49
|
+
"display": "block",
|
|
50
|
+
|
|
51
|
+
"visibility": "visible",
|
|
52
|
+
|
|
53
|
+
"width": self._realOuterWidth(self.dropdown),
|
|
54
|
+
|
|
55
|
+
"height": self.dropdown.outerHeight(),
|
|
56
|
+
|
|
57
|
+
"opacity": "0",
|
|
58
|
+
|
|
59
|
+
"position": "absolute",
|
|
60
|
+
|
|
61
|
+
"top": "0",
|
|
62
|
+
|
|
63
|
+
"left": "0",
|
|
64
|
+
|
|
65
|
+
"cursor": "pointer",
|
|
66
|
+
|
|
67
|
+
"z-index": "999999",
|
|
68
|
+
|
|
69
|
+
"margin": self.dropdown.css("margin"),
|
|
70
|
+
|
|
71
|
+
"padding": "0",
|
|
72
|
+
|
|
73
|
+
"-webkit-appearance": "menulist-button"
|
|
74
|
+
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
if(self.originalElem.disabled) {
|
|
78
|
+
|
|
79
|
+
self.triggerEvent("disable");
|
|
80
|
+
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return this;
|
|
84
|
+
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// Mobile Events
|
|
88
|
+
// -------------
|
|
89
|
+
// Listens to mobile-specific events
|
|
90
|
+
selectBoxIt._mobileEvents = function() {
|
|
91
|
+
|
|
92
|
+
var self = this;
|
|
93
|
+
|
|
94
|
+
self.selectBox.on({
|
|
95
|
+
|
|
96
|
+
"changed.selectBoxIt": function() {
|
|
97
|
+
|
|
98
|
+
self.hasChanged = true;
|
|
99
|
+
|
|
100
|
+
self._updateMobileText();
|
|
101
|
+
|
|
102
|
+
// Triggers the `option-click` event on mobile
|
|
103
|
+
self.triggerEvent("option-click");
|
|
104
|
+
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
"mousedown.selectBoxIt": function() {
|
|
108
|
+
|
|
109
|
+
// If the select box has not been changed, the defaultText option is being used
|
|
110
|
+
if(!self.hasChanged && self.options.defaultText && !self.originalElem.disabled) {
|
|
111
|
+
|
|
112
|
+
self._updateMobileText();
|
|
113
|
+
|
|
114
|
+
self.triggerEvent("option-click");
|
|
115
|
+
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
"enable.selectBoxIt": function() {
|
|
121
|
+
|
|
122
|
+
// Moves SelectBoxIt onto the page
|
|
123
|
+
self.selectBox.removeClass('selectboxit-rendering');
|
|
124
|
+
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
"disable.selectBoxIt": function() {
|
|
128
|
+
|
|
129
|
+
// Moves SelectBoxIt off the page
|
|
130
|
+
self.selectBox.addClass('selectboxit-rendering');
|
|
131
|
+
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// Mobile
|
|
139
|
+
// ------
|
|
140
|
+
// Applies the native "wheel" interface when a mobile user is interacting with the dropdown
|
|
141
|
+
|
|
142
|
+
selectBoxIt._mobile = function(callback) {
|
|
143
|
+
|
|
144
|
+
// Stores the plugin context inside of the self variable
|
|
145
|
+
var self = this;
|
|
146
|
+
|
|
147
|
+
if(self.isMobile) {
|
|
148
|
+
|
|
149
|
+
self._applyNativeSelect();
|
|
150
|
+
|
|
151
|
+
self._mobileEvents();
|
|
152
|
+
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Maintains chainability
|
|
156
|
+
return this;
|
|
157
|
+
|
|
158
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
|
|
2
|
+
// Remove Options Module
|
|
3
|
+
// =====================
|
|
4
|
+
|
|
5
|
+
// remove
|
|
6
|
+
// ------
|
|
7
|
+
// Removes drop down list options
|
|
8
|
+
// using an index
|
|
9
|
+
|
|
10
|
+
selectBoxIt.remove = function(indexes, callback) {
|
|
11
|
+
|
|
12
|
+
var self = this,
|
|
13
|
+
dataType = $.type(indexes),
|
|
14
|
+
value,
|
|
15
|
+
x = 0,
|
|
16
|
+
dataLength,
|
|
17
|
+
elems = "";
|
|
18
|
+
|
|
19
|
+
// If an array is passed in
|
|
20
|
+
if(dataType === "array") {
|
|
21
|
+
|
|
22
|
+
// Loops through the array
|
|
23
|
+
for(dataLength = indexes.length; x <= dataLength - 1; x += 1) {
|
|
24
|
+
|
|
25
|
+
// Stores the currently traversed array item in the local `value` variable
|
|
26
|
+
value = indexes[x];
|
|
27
|
+
|
|
28
|
+
// If the currently traversed array item is an object literal
|
|
29
|
+
if($.type(value) === "number") {
|
|
30
|
+
|
|
31
|
+
if(elems.length) {
|
|
32
|
+
|
|
33
|
+
// Adds an element to the removal string
|
|
34
|
+
elems += ", option:eq(" + value + ")";
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
else {
|
|
39
|
+
|
|
40
|
+
// Adds an element to the removal string
|
|
41
|
+
elems += "option:eq(" + value + ")";
|
|
42
|
+
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Removes all of the appropriate options from the select box
|
|
50
|
+
self.selectBox.find(elems).remove();
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// If a number is passed in
|
|
55
|
+
else if(dataType === "number") {
|
|
56
|
+
|
|
57
|
+
self.selectBox.find("option").eq(indexes).remove();
|
|
58
|
+
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// If anything besides a number or array is passed in
|
|
62
|
+
else {
|
|
63
|
+
|
|
64
|
+
// Removes all of the options from the original select box
|
|
65
|
+
self.selectBox.find("option").remove();
|
|
66
|
+
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// If the dropdown property exists
|
|
70
|
+
if(self.dropdown) {
|
|
71
|
+
|
|
72
|
+
// Rebuilds the dropdown
|
|
73
|
+
self.refresh(function() {
|
|
74
|
+
|
|
75
|
+
// Provide callback function support
|
|
76
|
+
self._callbackSupport(callback);
|
|
77
|
+
|
|
78
|
+
}, true);
|
|
79
|
+
|
|
80
|
+
} else {
|
|
81
|
+
|
|
82
|
+
// Provide callback function support
|
|
83
|
+
self._callbackSupport(callback);
|
|
84
|
+
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Maintains chainability
|
|
88
|
+
return self;
|
|
89
|
+
|
|
90
|
+
};
|