angular-smart-search 0.0.5 → 0.0.6
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 +4 -4
- data/app/assets/javascripts/angular-smart-search.js +135 -68
- data/lib/angular-smart-search.rb +0 -0
- data/lib/angular-smart-search/version.rb +1 -1
- metadata +16 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04cb4a6f9b79c9b5ea2f7eb89b4596550f584c30
|
4
|
+
data.tar.gz: 12e620cc49c2ccc19b7cff616eae6af86de53cdf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7cc5b239350f9d22de67291d61a3641d82614210ddcefd1aab076a8416c7c7a4062695ac66d6cccb2d5dcec2aee34db1574235b0a2225c33cf0287ce51239d75
|
7
|
+
data.tar.gz: 41194c15087798de012a842e53ba4033d0452658f7cf8ff6c9a42c722d929ae51204d1ddbffb9620ca1925709274f096557c45815007976777ea3cdff9bae247
|
@@ -1,5 +1,5 @@
|
|
1
1
|
// author: Samuel Mueller
|
2
|
-
// version: 0.0.
|
2
|
+
// version: 0.0.6
|
3
3
|
// license: MIT
|
4
4
|
// homepage: http://github.com/ssmm/angular-smart-search
|
5
5
|
(function() {
|
@@ -26,18 +26,27 @@
|
|
26
26
|
return {
|
27
27
|
restrict: "A",
|
28
28
|
scope: true,
|
29
|
-
replace: true,
|
30
|
-
template: templateFactory(),
|
31
29
|
compile: function(element, attributes, transclude) {
|
32
|
-
var id_field;
|
30
|
+
var detailOverlay, id_field, template;
|
33
31
|
|
32
|
+
if (attributes.detailOverlay) {
|
33
|
+
detailOverlay = jQuery("#" + attributes.detailOverlay);
|
34
|
+
if (!detailOverlay[0]) {
|
35
|
+
detailOverlay = void 0;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
template = angular.element(templateFactory.getTemplate(angular.isDefined(detailOverlay)));
|
39
|
+
if (detailOverlay) {
|
40
|
+
angular.element(template.find("detail-overlay")).append(detailOverlay.html());
|
41
|
+
}
|
42
|
+
element.replaceWith(template);
|
34
43
|
id_field = angular.element("<input ng-model='result.id' type='text' style='width: 30px; display: none;'>");
|
35
44
|
id_field.attr("id", attributes.id);
|
36
45
|
id_field.attr("name", attributes.name);
|
37
46
|
element.append(id_field);
|
38
47
|
return {
|
39
48
|
post: function($scope, $element, $attributes) {
|
40
|
-
var allowedFormats,
|
49
|
+
var allowedFormats, detailOverlayTrigger, hideOverlay, outerQueryTimeout, queryState, quickQueryInput, searchInput, searchOverlay, service, showOverlay;
|
41
50
|
|
42
51
|
queryState = new QueryState();
|
43
52
|
$scope.queryState = queryState;
|
@@ -48,18 +57,35 @@
|
|
48
57
|
$scope.result = angular.fromJson($attributes.init)[0];
|
49
58
|
$scope.queryState.setTo("successful");
|
50
59
|
}
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
overlay.css("top",
|
58
|
-
overlay.css("left",
|
59
|
-
return overlay.show("fade");
|
60
|
+
quickQueryInput = $element.find("[quick-query-input]");
|
61
|
+
searchInput = $element.find("[search-input]");
|
62
|
+
detailOverlayTrigger = $element.find("[detail-overlay-trigger]");
|
63
|
+
searchOverlay = $element.children("search-overlay");
|
64
|
+
detailOverlay = $element.children("detail-overlay");
|
65
|
+
showOverlay = function(overlay, origin, action) {
|
66
|
+
overlay.css("top", origin.top - padding);
|
67
|
+
overlay.css("left", origin.left - padding);
|
68
|
+
return overlay.show("fade", action);
|
69
|
+
};
|
70
|
+
$scope.showSearchOverlay = function() {
|
71
|
+
return showOverlay(searchOverlay, quickQueryInput.position(), function() {
|
72
|
+
return searchInput.focus();
|
73
|
+
});
|
74
|
+
};
|
75
|
+
$scope.showDetailOverlay = function() {
|
76
|
+
$scope.item = $scope.result;
|
77
|
+
return showOverlay(detailOverlay, detailOverlayTrigger.position());
|
60
78
|
};
|
61
|
-
|
62
|
-
return overlay.hide("fade");
|
79
|
+
hideOverlay = function(overlay, action) {
|
80
|
+
return overlay.hide("fade", action);
|
81
|
+
};
|
82
|
+
$scope.hideSearchOverlay = function() {
|
83
|
+
return hideOverlay(searchOverlay, function() {
|
84
|
+
return quickQueryInput.focus();
|
85
|
+
});
|
86
|
+
};
|
87
|
+
$scope.hideDetailOverlay = function() {
|
88
|
+
return hideOverlay(detailOverlay);
|
63
89
|
};
|
64
90
|
$scope.search = function(query) {
|
65
91
|
return $http.get("" + service + ".json?fulltext=" + query).success(function(data) {
|
@@ -70,7 +96,7 @@
|
|
70
96
|
$scope.pick = function(item) {
|
71
97
|
queryState.setTo("successful");
|
72
98
|
$scope.result = item;
|
73
|
-
return $scope.
|
99
|
+
return $scope.hideSearchOverlay();
|
74
100
|
};
|
75
101
|
$scope.hover = function(item) {
|
76
102
|
return $scope.currentItem = item;
|
@@ -78,26 +104,32 @@
|
|
78
104
|
outerQueryTimeout = null;
|
79
105
|
return $scope.outerQueryChanged = function(query) {
|
80
106
|
window.clearTimeout(outerQueryTimeout);
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
return outerQueryTimeout = window.setTimeout(function() {
|
86
|
-
queryState.setTo("pending");
|
87
|
-
$http.get("" + service + ".json?" + query.format.name + "=" + query.query).success(function(data) {
|
88
|
-
if (data[0] && data[0].id) {
|
89
|
-
queryState.setTo("successful");
|
90
|
-
return $scope.result = data[0];
|
91
|
-
} else {
|
92
|
-
return queryState.setTo("unsuccessful");
|
93
|
-
}
|
94
|
-
}).error(function() {
|
95
|
-
return queryState.setTo("error");
|
96
|
-
});
|
97
|
-
return $scope.$apply();
|
98
|
-
}, 1200);
|
107
|
+
if (!query) {
|
108
|
+
if ($scope.result) {
|
109
|
+
return queryState.setTo("successful");
|
110
|
+
}
|
99
111
|
} else {
|
100
|
-
|
112
|
+
query = searchQueryFactory(query, allowedFormats);
|
113
|
+
if (query) {
|
114
|
+
queryState.setTo("changed");
|
115
|
+
queryState.query = query;
|
116
|
+
return outerQueryTimeout = window.setTimeout(function() {
|
117
|
+
queryState.setTo("pending");
|
118
|
+
$http.get("" + service + ".json?" + query.format.name + "=" + query.query).success(function(data) {
|
119
|
+
if (data[0] && data[0].id) {
|
120
|
+
queryState.setTo("successful");
|
121
|
+
return $scope.result = data[0];
|
122
|
+
} else {
|
123
|
+
return queryState.setTo("unsuccessful");
|
124
|
+
}
|
125
|
+
}).error(function() {
|
126
|
+
return queryState.setTo("error");
|
127
|
+
});
|
128
|
+
return $scope.$apply();
|
129
|
+
}, 1200);
|
130
|
+
} else {
|
131
|
+
return queryState.setTo("invalid-format");
|
132
|
+
}
|
101
133
|
}
|
102
134
|
};
|
103
135
|
}
|
@@ -107,6 +139,45 @@
|
|
107
139
|
}
|
108
140
|
]);
|
109
141
|
|
142
|
+
angular.module("angular-smart-search").provider("markupStore", [
|
143
|
+
function() {
|
144
|
+
var infoIconClass, overlayClass, searchIconClass, successIconClass;
|
145
|
+
|
146
|
+
successIconClass = "icon-info-sign icon-large";
|
147
|
+
infoIconClass = "icon-info-sign";
|
148
|
+
searchIconClass = "icon-search";
|
149
|
+
overlayClass = "smart-search-overlay";
|
150
|
+
this.setSuccessIconClass = function(attr) {
|
151
|
+
return successIconClass = attr;
|
152
|
+
};
|
153
|
+
this.setInfoIconClass = function(attr) {
|
154
|
+
return infoIconClass = attr;
|
155
|
+
};
|
156
|
+
this.setSearchIconClass = function(attr) {
|
157
|
+
return searchIconClass = attr;
|
158
|
+
};
|
159
|
+
this.setOverlayClass = function(attr) {
|
160
|
+
return overlayClass = attr;
|
161
|
+
};
|
162
|
+
return this.$get = function() {
|
163
|
+
return {
|
164
|
+
successIconClass: function() {
|
165
|
+
return successIconClass;
|
166
|
+
},
|
167
|
+
infoIconClass: function() {
|
168
|
+
return infoIconClass;
|
169
|
+
},
|
170
|
+
searchIconClass: function() {
|
171
|
+
return searchIconClass;
|
172
|
+
},
|
173
|
+
overlayClass: function() {
|
174
|
+
return overlayClass;
|
175
|
+
}
|
176
|
+
};
|
177
|
+
};
|
178
|
+
}
|
179
|
+
]);
|
180
|
+
|
110
181
|
angular.module("angular-smart-search").provider("searchQueryFactory", [
|
111
182
|
function() {
|
112
183
|
var Query, detectFormat, formats;
|
@@ -121,7 +192,7 @@
|
|
121
192
|
|
122
193
|
for (_i = 0, _len = allowedFormats.length; _i < _len; _i++) {
|
123
194
|
name = allowedFormats[_i];
|
124
|
-
if (formats[name].pattern.exec(query)) {
|
195
|
+
if (formats[name] && formats[name].pattern.exec(query)) {
|
125
196
|
return formats[name];
|
126
197
|
}
|
127
198
|
}
|
@@ -152,42 +223,38 @@
|
|
152
223
|
}
|
153
224
|
]);
|
154
225
|
|
155
|
-
angular.module("angular-smart-search").
|
226
|
+
angular.module("angular-smart-search").service("templateFactory", [
|
156
227
|
"markupStore", function(markupStore) {
|
157
|
-
|
158
|
-
return " <div> <!-- input section you see initially --> <div class='input-prepend input-append'> <!-- gray display section --> <span class='add-on' style='min-width: 200px;'> <!-- result if found --> <span ng-show='queryState.is(\"successful\")'> <i class='" + (markupStore.successIconClass()) + "'></i> {{result.displayText}} </span> <!-- query states --> <span ng-show='queryState.is(\"changed\")'> <em>{{queryState.query.format.name}} detected</em> </span> <span ng-show='queryState.is(\"pending\")'> <em>searching...</em> </span> <span ng-show='queryState.is(\"unsuccessful\")'> <em>Not found</em> </span> <span ng-show='queryState.is(\"invalid-format\")'> <em>Invalid format</em> </span> <span ng-show='queryState.is(\"error\")'> <em>Error</em> </span> </span> <!-- quick query field --> <input ng-change='outerQueryChanged(quickQuery)' ng-model='quickQuery' queryfield style='width: 100px;' type='text'> <!-- button that triggers detail search overlay --> <button type='button' class='btn' ng-click='show()'> <i class='" + (markupStore.searchIconClass()) + "'></i> </button> </div> <!-- detail search overlay, initially hidden --> <div class='" + (markupStore.overlayClass()) + "' ng-mouseleave='hide()' overlay> <div class='row-fluid'> <div class='span12'> <div class='input-append'> <input detail-queryfield ng-model='detailQuery' type='text'> <button type='button' class='btn' ng-click='search(detailQuery)'> <i class='" + (markupStore.searchIconClass()) + "'></i> </button> </div> </div> </div> <div class='horizontal-space'></div> <div class='row-fluid'> <div class='span12'> <table at-table class='table table-bordered table-hover' fill-last-page pagination='wildPagination'> <thead></thead> <tbody> <tr ng-mouseover='hover(item)'> <td at-implicit attribute='id' class='sortable 50px'></td> <td at-implicit attribute='displayText' class='sortable 280px' title='Result'></td> <td class='50px' title=''> <button type='button' class='btn btn-mini' ng-click='pick(item)'>pick</button> </td> </tr> </tbody> </table> <at-pagination instance='wildPagination' items-per-page='3' list='resultList'></at-pagination> </div> </div> </div> </div> ";
|
159
|
-
};
|
160
|
-
}
|
161
|
-
]);
|
162
|
-
|
163
|
-
angular.module("angular-smart-search").provider("markupStore", [
|
164
|
-
function() {
|
165
|
-
var overlayClass, searchIconClass, successIconClass;
|
228
|
+
var detailOverlay, detailOverlayTrigger, inputSection, overlayStyle, resultIcon, searchOverlay, showDetailOverlayAction, successIcon;
|
166
229
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
230
|
+
overlayStyle = "style=' display: none; position: absolute; background-color: white; padding: 30px; border: solid; border-width: 1px; border-color: rgb(221, 221, 221); border-radius: 10px; '";
|
231
|
+
detailOverlayTrigger = "<i detail-overlay-trigger class='" + (markupStore.infoIconClass()) + "' ng-click='showDetailOverlay()'></i>";
|
232
|
+
successIcon = "<i class='" + (markupStore.successIconClass()) + "'></i>";
|
233
|
+
showDetailOverlayAction = function(withDetailOverlay) {
|
234
|
+
if (withDetailOverlay) {
|
235
|
+
return "ng-click='showDetailOverlay()'";
|
236
|
+
}
|
172
237
|
};
|
173
|
-
|
174
|
-
|
238
|
+
resultIcon = function(withDetailOverlay) {
|
239
|
+
if (withDetailOverlay) {
|
240
|
+
return detailOverlayTrigger;
|
241
|
+
} else {
|
242
|
+
return successIcon;
|
243
|
+
}
|
175
244
|
};
|
176
|
-
|
177
|
-
return
|
245
|
+
inputSection = function(withDetailOverlay) {
|
246
|
+
return " <div> <!-- input section you see initially --> <div class='input-prepend input-append'> <!-- gray display section --> <span class='add-on' style='min-width: 200px;'> <!-- result if found --> <span ng-show='queryState.is(\"successful\")' " + (showDetailOverlayAction(withDetailOverlay)) + "> " + (resultIcon(withDetailOverlay)) + " {{result.displayText}} </span> <!-- query states --> <span ng-show='queryState.is(\"changed\")'> <em>{{queryState.query.format.name}} detected</em> </span> <span ng-show='queryState.is(\"pending\")'> <em>searching...</em> </span> <span ng-show='queryState.is(\"unsuccessful\")'> <em>Not found</em> </span> <span ng-show='queryState.is(\"invalid-format\")'> <em>Invalid format</em> </span> <span ng-show='queryState.is(\"error\")'> <em>Error</em> </span> </span> <!-- quick query field --> <input ng-change='outerQueryChanged(quickQuery)' ng-model='quickQuery' quick-query-input style='width: 100px;' type='text'> <!-- button that triggers detail search overlay --> <button type='button' class='btn' ng-click='showSearchOverlay()'> <i class='" + (markupStore.searchIconClass()) + "'></i> </button> </div> " + (detailOverlay()) + " " + (searchOverlay()) + " </div> ";
|
178
247
|
};
|
179
|
-
|
180
|
-
return
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
}
|
190
|
-
};
|
248
|
+
searchOverlay = function() {
|
249
|
+
return " <search-overlay " + overlayStyle + " class='" + (markupStore.overlayClass()) + "' ng-mouseleave='hideSearchOverlay()'> <div class='row-fluid'> <div class='span12'> <div class='input-append'> <form> <input search-input ng-model='detailQuery' type='text'> <button type='submit' class='btn' ng-click='search(detailQuery)'> <i class='" + (markupStore.searchIconClass()) + "'></i> </button> </form> </div> </div> </div> <div class='horizontal-space'></div> <div class='row-fluid'> <div class='span12'> <table at-table class='table table-bordered table-hover' fill-last-page pagination='wildPagination'> <thead></thead> <tbody> <tr ng-mouseover='hover(item)'> <td at-implicit attribute='id' class='sortable 50px'></td> <td at-implicit attribute='displayText' class='sortable 280px' title='Result'></td> <td class='50px' title=''> <button type='button' class='btn btn-mini' ng-click='pick(item)'>pick</button> </td> </tr> </tbody> </table> <at-pagination instance='wildPagination' items-per-page='3' list='resultList'></at-pagination> </div> </div> </search-overlay> ";
|
250
|
+
};
|
251
|
+
detailOverlay = function() {
|
252
|
+
return " <detail-overlay " + overlayStyle + " class='" + (markupStore.overlayClass()) + "' ng-mouseleave='hideDetailOverlay()'> </detail-overlay> ";
|
253
|
+
};
|
254
|
+
return {
|
255
|
+
getTemplate: function(withDetailOverlay) {
|
256
|
+
return inputSection(withDetailOverlay);
|
257
|
+
}
|
191
258
|
};
|
192
259
|
}
|
193
260
|
]);
|
data/lib/angular-smart-search.rb
CHANGED
File without changes
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: angular-smart-search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Mueller
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-07-
|
11
|
+
date: 2013-07-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: listen
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
description: angular smart search
|
42
56
|
email:
|
43
57
|
- mueller.samu@gmail.com
|
@@ -73,4 +87,3 @@ signing_key:
|
|
73
87
|
specification_version: 4
|
74
88
|
summary: angular smart search
|
75
89
|
test_files: []
|
76
|
-
has_rdoc:
|