angular-smart-search 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|