picky-generators 4.2.4 → 4.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/prototypes/all_in_one/sinatra/app.rb +1 -7
- data/prototypes/all_in_one/sinatra/book.rb +10 -10
- data/prototypes/all_in_one/sinatra/images/picky.png +0 -0
- data/prototypes/all_in_one/sinatra/javascripts/picky.min.js +19 -17
- data/prototypes/all_in_one/sinatra/stylesheets/application.css +82 -18
- data/prototypes/all_in_one/sinatra/stylesheets/images/background.png +0 -0
- data/prototypes/all_in_one/sinatra/stylesheets/images/cancel.svg +10 -0
- data/prototypes/all_in_one/sinatra/stylesheets/picky.css +277 -135
- data/prototypes/all_in_one/sinatra/views/search.haml +232 -58
- data/prototypes/client/sinatra/app.rb +19 -30
- data/prototypes/client/sinatra/book.rb +9 -9
- data/prototypes/client/sinatra/images/picky.png +0 -0
- data/prototypes/client/sinatra/javascripts/picky.min.js +19 -17
- data/prototypes/client/sinatra/stylesheets/application.css +82 -18
- data/prototypes/client/sinatra/stylesheets/images/background.png +0 -0
- data/prototypes/client/sinatra/stylesheets/images/cancel.svg +10 -0
- data/prototypes/client/sinatra/stylesheets/picky.css +277 -135
- data/prototypes/client/sinatra/views/search.haml +232 -58
- metadata +14 -12
- data/prototypes/all_in_one/sinatra/views/configure.haml +0 -188
- data/prototypes/client/sinatra/views/configure.haml +0 -188
@@ -1,60 +1,232 @@
|
|
1
1
|
!!!
|
2
2
|
%html{ :lang => 'en' }
|
3
3
|
%head
|
4
|
-
%link{:href => "stylesheets/picky.css", :media => "screen", :rel => "stylesheet", :type => "text/css"}/
|
5
4
|
%link{:href => "stylesheets/application.css", :media => "screen", :rel => "stylesheet", :type => "text/css"}/
|
6
|
-
|
5
|
+
%link{:href => "stylesheets/picky.css", :media => "screen", :rel => "stylesheet", :type => "text/css"}/
|
7
6
|
= js 'jquery-1.5.0.min'
|
8
7
|
= js 'history.min'
|
9
8
|
= js 'history.adapter.jquery.min'
|
10
9
|
= js 'picky.min'
|
11
10
|
|
12
11
|
%body
|
13
|
-
%
|
14
|
-
|
15
|
-
%
|
16
|
-
|
17
|
-
%
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
A simple word,
|
24
|
-
= succeed "." do
|
25
|
-
%a{:href => "#", :onclick => "pickyClient.insert('alan');"} alan
|
26
|
-
%span.explanation
|
27
|
-
(Finds Alan in the title, and Alans who wrote books. The title is ranked higher due to weighing.)
|
28
|
-
%span
|
29
|
-
%p
|
30
|
-
With qualifier,
|
31
|
-
= succeed "." do
|
32
|
-
%a{:href => "#", :onclick => "pickyClient.insert('title:women');"} title:women
|
33
|
-
%span.explanation
|
34
|
-
(Finds "women*" just in titles.)
|
35
|
-
%span
|
36
|
-
%p
|
37
|
-
With similarity,
|
38
|
-
= succeed "." do
|
39
|
-
%a{:href => "#", :onclick => "pickyClient.insert('pinchn~');"} pinchn~
|
40
|
-
%span.explanation (Finds "pynchon", note: Only title in example with similarity. Uses a combination of double metaphone and Levenshtein.)
|
41
|
-
%p
|
42
|
-
More complex,
|
43
|
-
= succeed "." do
|
44
|
-
%a{:href => "#", :onclick => "pickyClient.insert('title:lyterature~');"} title:lyterature~
|
45
|
-
%span.explanation (Finds similar titles)
|
46
|
-
%p
|
47
|
-
With choice,
|
48
|
-
= succeed "." do
|
49
|
-
%a{:href => "#", :onclick => "pickyClient.insert('sp');"} sp
|
50
|
-
%span.explanation (Finds "sp*" in multiple categories. Choose the one you're looking for.)
|
51
|
-
%p
|
52
|
-
More complex,
|
53
|
-
= succeed "." do
|
54
|
-
%a{:href => "#", :onclick => "pickyClient.insert('soc* p');"} soc* p
|
55
|
-
%span.explanation (This is where Picky really shines, "the title started with soc, and the author starts with p")
|
12
|
+
%hgroup
|
13
|
+
/ Replace these headers with your code
|
14
|
+
%img{ :class => 'picky', :src => "images/picky.png"}/
|
15
|
+
%h1 Picky
|
16
|
+
%h2
|
17
|
+
Scaffold: A great start into your
|
18
|
+
%em fantastic
|
19
|
+
search engine!
|
20
|
+
☛
|
21
|
+
%a{ :href => "http://florianhanke.com/picky" } Picky Homepage
|
56
22
|
.content
|
57
23
|
= Picky::Helper.cached_interface
|
24
|
+
%section
|
25
|
+
%h1 Examples:
|
26
|
+
%p
|
27
|
+
%a{:href => "", :onclick => "pickyClient.insert('alan');"} alan
|
28
|
+
finds Alan in the title, and Alans who wrote books. The title is ranked higher due to weighing.
|
29
|
+
%p
|
30
|
+
%a{:href => "", :onclick => "pickyClient.insert('title:women');"} title:women
|
31
|
+
finds "women*" just in titles.
|
32
|
+
%p
|
33
|
+
%a{:href => "", :onclick => "pickyClient.insert('pinchn~');"} pinchn~
|
34
|
+
finds the similar "pynchon".
|
35
|
+
%p
|
36
|
+
%a{:href => "", :onclick => "pickyClient.insert('title:lyterature~');"} title:lyterature~
|
37
|
+
finds similar titles.
|
38
|
+
%p
|
39
|
+
%a{:href => "", :onclick => "pickyClient.insert('sp');"} sp
|
40
|
+
finds "sp*" in multiple categories. Choose the one you're looking for.
|
41
|
+
%p
|
42
|
+
%a{:href => "", :onclick => "pickyClient.insert('soc* p');"} soc* p
|
43
|
+
means "find something that starts with soc, and another thing starting with p".
|
44
|
+
%section
|
45
|
+
%h1 Already made it this far? You're good!
|
46
|
+
%p I think you're ready for configuring me for your own purposes.
|
47
|
+
%h2 Configuring the Picky client.
|
48
|
+
%p
|
49
|
+
There are two places where you configure the Picky client:
|
50
|
+
%ol
|
51
|
+
%li
|
52
|
+
%a{ :href => '#controller' } In the controller.
|
53
|
+
(client to Picky server)
|
54
|
+
%li
|
55
|
+
%a{ :href => '#view' } In the view.
|
56
|
+
(javascript client interface)
|
57
|
+
%h2#controller Controller
|
58
|
+
%p
|
59
|
+
Open the file
|
60
|
+
%strong app.rb
|
61
|
+
and take a peek inside.
|
62
|
+
%p
|
63
|
+
First you need both a client instance for a
|
64
|
+
%strong full
|
65
|
+
or a
|
66
|
+
%strong live search
|
67
|
+
depending on what you need (Full gets results with IDs, Live without and is used for updating the counter).
|
68
|
+
%p
|
69
|
+
In the example, I called it
|
70
|
+
%strong BookSearch
|
71
|
+
\.
|
72
|
+
%code
|
73
|
+
%pre
|
74
|
+
:preserve
|
75
|
+
BookSearch = Picky::Client.new host: 'localhost',
|
76
|
+
port: 8080,
|
77
|
+
path: '/books'
|
78
|
+
%p
|
79
|
+
Both clients offer the options:
|
80
|
+
%dl
|
81
|
+
%dt
|
82
|
+
%strong host
|
83
|
+
%dd The Picky search server host.
|
84
|
+
%dt
|
85
|
+
%strong port
|
86
|
+
%dd The Picky search server port (see unicorn.rb in the server).
|
87
|
+
%dt
|
88
|
+
%strong path
|
89
|
+
%dd The Picky search path (see app.rb in the server).
|
90
|
+
%p
|
91
|
+
Then, use these Client instances in your actions. For example like this:
|
92
|
+
%code
|
93
|
+
%pre
|
94
|
+
:preserve
|
95
|
+
get '/search/full' do
|
96
|
+
results = BookSearch.search params[:query],
|
97
|
+
:ids => params[:ids],
|
98
|
+
:offset => params[:offset]
|
99
|
+
results.extend Picky::Convenience
|
100
|
+
results.populate_with Book do |book|
|
101
|
+
book.to_s
|
102
|
+
end
|
103
|
+
ActiveSupport::JSON.encode results
|
104
|
+
end
|
105
|
+
%p
|
106
|
+
This part gets a
|
107
|
+
%strong hash
|
108
|
+
with the results:
|
109
|
+
%code
|
110
|
+
%pre
|
111
|
+
:preserve
|
112
|
+
results = BookSearch.search params[:query],
|
113
|
+
:ids => params[:ids],
|
114
|
+
:offset => params[:offset]
|
115
|
+
%p
|
116
|
+
This part takes the
|
117
|
+
%strong hash
|
118
|
+
and extends it with a few useful and convenient methods:
|
119
|
+
%code
|
120
|
+
%pre results.extend Picky::Convenience
|
121
|
+
%p
|
122
|
+
One of these methods is the
|
123
|
+
%strong populate_with
|
124
|
+
method which takes a
|
125
|
+
%strong model
|
126
|
+
as parameter, and then gets the corresponding
|
127
|
+
%strong model instances
|
128
|
+
for each id in the result.
|
129
|
+
%code
|
130
|
+
%pre
|
131
|
+
:preserve
|
132
|
+
results.populate_with Book do |book|
|
133
|
+
book.to_s
|
134
|
+
end
|
135
|
+
The
|
136
|
+
%strong book.to_s
|
137
|
+
simulates rendering a book.
|
138
|
+
You can do whatever with the book instance if you just return a rendered thing that's supposed to be shown in the front end.
|
139
|
+
%p
|
140
|
+
If you don't want to render in the controller, you can do so in a view. In the controller just call
|
141
|
+
%code
|
142
|
+
%pre
|
143
|
+
results.populate_with Book
|
144
|
+
and then render the books in a view using:
|
145
|
+
%code
|
146
|
+
%pre
|
147
|
+
:preserve
|
148
|
+
results.entries do |book|
|
149
|
+
render book # or book.to_s, or however you like to render the book.
|
150
|
+
end
|
151
|
+
%p
|
152
|
+
At the end, encode the hash in JSON:
|
153
|
+
%code
|
154
|
+
%pre
|
155
|
+
ActiveSupport::JSON.encode results
|
156
|
+
That's it for the controller.
|
157
|
+
%p
|
158
|
+
All the steps in one:
|
159
|
+
%code
|
160
|
+
%pre
|
161
|
+
:preserve
|
162
|
+
BookSearch = Picky::Client.new host: 'localhost',
|
163
|
+
port: 8080,
|
164
|
+
path: '/books'
|
165
|
+
|
166
|
+
get '/search/full' do
|
167
|
+
results = BookSearch.search params[:query],
|
168
|
+
ids: params[:ids],
|
169
|
+
offset: params[:offset]
|
170
|
+
|
171
|
+
results.extend Picky::Convenience
|
172
|
+
results.populate_with Book do |book|
|
173
|
+
book.to_s
|
174
|
+
end
|
175
|
+
|
176
|
+
ActiveSupport::JSON.encode results
|
177
|
+
end
|
178
|
+
%h2#view View
|
179
|
+
%p
|
180
|
+
The view is even easier. Just add the line
|
181
|
+
%code
|
182
|
+
%pre
|
183
|
+
:preserve
|
184
|
+
= Picky::Helper.cached_interface
|
185
|
+
if you use just one language, or
|
186
|
+
%code
|
187
|
+
%pre
|
188
|
+
:preserve
|
189
|
+
= Picky::Helper.interface button: 'search',
|
190
|
+
no_results: 'No results!',
|
191
|
+
more: 'more'
|
192
|
+
if you use multiple languages.
|
193
|
+
(You'd use the options
|
194
|
+
%code
|
195
|
+
%pre
|
196
|
+
:preserve
|
197
|
+
button: t(:'search.button'),
|
198
|
+
no_results: t(:'search.no_results'),
|
199
|
+
more: t(:'search.more')
|
200
|
+
of course, with proper i18n)
|
201
|
+
The same options can be used for
|
202
|
+
%strong #cached_interface
|
203
|
+
but they will be cached, so you can only set them once and then reused.
|
204
|
+
%p
|
205
|
+
You're almost finished. Take a look at the file
|
206
|
+
%strong views/search.haml
|
207
|
+
where you'll find javascript at the end. It looks something like this:
|
208
|
+
%code
|
209
|
+
%pre
|
210
|
+
:preserve
|
211
|
+
:javascript
|
212
|
+
pickyClient = new PickyClient({
|
213
|
+
// A full query displays the rendered results.
|
214
|
+
//
|
215
|
+
full: '/search/full',
|
216
|
+
|
217
|
+
// etc.
|
218
|
+
Just take a look at the possible javascript client options in that file.
|
219
|
+
%p
|
220
|
+
%strong Good luck my friend!
|
221
|
+
%em *waves several stubby pink tentacles*
|
222
|
+
%footer
|
223
|
+
Website design by
|
224
|
+
%a{ :href => 'http://twitter.com/thijs' } Thijs van der Vossen
|
225
|
+
of
|
226
|
+
%a{ :href => 'http://fngtps.com' } Fingertips
|
227
|
+
with modifications by
|
228
|
+
= succeed('.') do
|
229
|
+
%a{ :href => 'http://twitter.com/hanke' } Florian Hanke
|
58
230
|
:javascript
|
59
231
|
$(window).load(function() {
|
60
232
|
pickyClient = new PickyClient({
|
@@ -63,13 +235,12 @@
|
|
63
235
|
full: '/search/full',
|
64
236
|
// fullResults: 100, // Optional. Amount of ids to search for, default 20.
|
65
237
|
|
66
|
-
// A live query just updates the count
|
67
|
-
// to render (could go straight to the search server).
|
238
|
+
// A live query just updates the count.
|
68
239
|
//
|
69
240
|
live: '/search/live',
|
70
241
|
// liveResults: 0, // Optional. Amount of ids to search for, default 0.
|
71
242
|
|
72
|
-
// showResultsLimit:
|
243
|
+
// showResultsLimit: 100, // Optional. Default is 10.
|
73
244
|
|
74
245
|
// Wrap each li group (like author-title, or title-isbn etc.) of results
|
75
246
|
// in this element.
|
@@ -77,7 +248,7 @@
|
|
77
248
|
//
|
78
249
|
// wrapResults: '<div class="hello"><ol class="world"></ol></div>',
|
79
250
|
|
80
|
-
// before: function(
|
251
|
+
// before: function(query, params) { }, // Optional. Before Picky sends any data. Return modified query.
|
81
252
|
// success: function(data, query) { }, // Optional. Just after Picky receives data. (Get a PickyData object)
|
82
253
|
// after: function(data, query) { }, // Optional. After Picky has handled the data and updated the view.
|
83
254
|
|
@@ -103,14 +274,17 @@
|
|
103
274
|
choices: {
|
104
275
|
en:{
|
105
276
|
'title': {
|
106
|
-
format: "<strong>%1$s</strong>",
|
277
|
+
format: "Called <strong>%1$s</strong>",
|
107
278
|
filter: function(text) { return text.toUpperCase(); },
|
108
|
-
ignoreSingle:
|
279
|
+
ignoreSingle: true
|
109
280
|
},
|
110
|
-
'author
|
111
|
-
'
|
112
|
-
'
|
113
|
-
'author,
|
281
|
+
'author': 'Written by %1$s',
|
282
|
+
'subjects': 'Being about %1$s',
|
283
|
+
'publisher': 'Published by %1$s',
|
284
|
+
'author,title': 'Called %1$s, written by %2$s',
|
285
|
+
'title,author': 'Called %2$s, written by %1$s',
|
286
|
+
'title,subjects': 'Called %1$s, about %2$s',
|
287
|
+
'author,subjects': '%1$s who wrote about %2$s'
|
114
288
|
}
|
115
289
|
},
|
116
290
|
|
@@ -122,9 +296,9 @@
|
|
122
296
|
en:{
|
123
297
|
title: 'titled',
|
124
298
|
author: 'written by',
|
125
|
-
year: 'published in'
|
126
|
-
|
127
|
-
|
299
|
+
year: 'published in',
|
300
|
+
publisher: 'published by',
|
301
|
+
subjects: 'with subjects'
|
128
302
|
}
|
129
303
|
}
|
130
304
|
});
|
@@ -2,22 +2,21 @@ require 'rubygems'
|
|
2
2
|
require 'bundler'
|
3
3
|
Bundler.require
|
4
4
|
|
5
|
-
#
|
5
|
+
# Load the "model".
|
6
6
|
#
|
7
|
-
|
8
|
-
set :public, File.dirname(__FILE__)
|
9
|
-
set :views, File.expand_path('../views', __FILE__)
|
10
|
-
set :haml, :format => :html5
|
7
|
+
require File.expand_path 'book', File.dirname(__FILE__)
|
11
8
|
|
12
|
-
|
13
|
-
#
|
14
|
-
require File.expand_path '../book', __FILE__
|
9
|
+
set :haml, { :format => :html5 }
|
15
10
|
|
16
|
-
# Sets up
|
11
|
+
# Sets up two query instances.
|
17
12
|
#
|
18
|
-
|
13
|
+
BooksSearch = Picky::Client.new :host => 'localhost', :port => 8080, :path => '/books'
|
14
|
+
|
15
|
+
set :static, true
|
16
|
+
set :public, File.dirname(__FILE__)
|
17
|
+
set :views, File.expand_path('views', File.dirname(__FILE__))
|
19
18
|
|
20
|
-
# Root, the search
|
19
|
+
# Root, the search interface.
|
21
20
|
#
|
22
21
|
get '/' do
|
23
22
|
@query = params[:q]
|
@@ -25,41 +24,31 @@ get '/' do
|
|
25
24
|
haml :'/search'
|
26
25
|
end
|
27
26
|
|
28
|
-
#
|
29
|
-
#
|
30
|
-
# You get the results from the picky server and then
|
31
|
-
# populate the result hash with rendered models.
|
27
|
+
# For full results, you get the ids from the picky server
|
28
|
+
# and then populate the result with models (rendered, even).
|
32
29
|
#
|
33
30
|
get '/search/full' do
|
34
|
-
results =
|
31
|
+
results = BooksSearch.search params[:query], :ids => params[:ids], :offset => params[:offset]
|
35
32
|
results.extend Picky::Convenience
|
36
33
|
results.populate_with Book do |book|
|
37
|
-
book.
|
34
|
+
book.to_s
|
38
35
|
end
|
39
36
|
|
40
37
|
#
|
41
|
-
# Or
|
38
|
+
# Or use:
|
42
39
|
# results.populate_with Book
|
43
40
|
#
|
44
|
-
# Then
|
41
|
+
# Then:
|
45
42
|
# rendered_entries = results.entries.map do |book| (render each book here) end
|
46
43
|
#
|
47
44
|
|
48
|
-
|
45
|
+
ActiveSupport::JSON.encode results
|
49
46
|
end
|
50
47
|
|
51
|
-
#
|
52
|
-
#
|
53
|
-
# We don't parse/reencode the returned json string using search_unparsed.
|
48
|
+
# For live results, you'd actually go directly to the search server without taking the detour.
|
54
49
|
#
|
55
50
|
get '/search/live' do
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
# Configure. The configuration info page.
|
60
|
-
#
|
61
|
-
get '/configure' do
|
62
|
-
haml :'/configure'
|
51
|
+
BooksSearch.search_unparsed params[:query], :offset => params[:offset]
|
63
52
|
end
|
64
53
|
|
65
54
|
helpers do
|
@@ -9,34 +9,34 @@ require 'csv'
|
|
9
9
|
# * a number of subjects
|
10
10
|
#
|
11
11
|
class Book
|
12
|
-
|
12
|
+
|
13
13
|
@@books_mapping = {}
|
14
|
-
|
14
|
+
|
15
15
|
# Load the books on startup.
|
16
16
|
#
|
17
17
|
file_name = File.expand_path 'library.csv', File.dirname(__FILE__)
|
18
18
|
CSV.open(file_name, 'r').each do |row|
|
19
19
|
@@books_mapping[row.shift.to_i] = row
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
# Find uses a lookup table.
|
23
23
|
#
|
24
24
|
def self.find ids, _ = {}
|
25
25
|
ids.map { |id| new(id, *@@books_mapping[id]) }
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
attr_reader :id
|
29
|
-
|
29
|
+
|
30
30
|
def initialize id, title, author, year, publisher, subjects
|
31
31
|
@id, @title, @author, @year, @publisher, @subjects = id, title, author, year, publisher, subjects
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
# "Rendering" ;)
|
35
35
|
#
|
36
36
|
# Note: This is just an example. Please do not render in the model.
|
37
37
|
#
|
38
|
-
def
|
39
|
-
"<li class='book'><
|
38
|
+
def to_s
|
39
|
+
"<li class='book'><h3><a href='http://google.com?q=#{@title}'>#{@title}</a></h3><em>#{@author}</em><p>#{@year}, #{@publisher}</p><p>#{@subjects}</p></li>"
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
end
|
Binary file
|
@@ -1,17 +1,19 @@
|
|
1
|
-
Array.prototype.index=function(
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
1
|
+
Array.prototype.index=function(a){for(var b=0,j=this.length;b<j;b++)if(this[b]==a)return b;return null};Array.prototype.include=function(a){return this.index(a)!==null};Array.prototype.remove=function(a){this.splice(a,1);return this};Array.prototype.compare=function(a){return this.join("")==a.join("")};Array.prototype.each=function(a){for(var b=0,j=this.length;b<j;b++)a(b,this[b]);return this};Array.prototype.map=function(a){for(var b=0,j=this.length;b<j;b++)this[b]=a(b,this[b]);return this};var dictionary={common:{join:{de:"und",fr:"et",it:"e",en:"and",ch:"und"},"with":{de:"mit",fr:"avec",it:"con",en:"with",ch:"mit"},of:{de:"von",fr:"de",it:"di",en:"of",ch:"vo"},to:{de:"bis",fr:"\u00e0",it:"alla",en:"to",ch:"bis"}},results:{addination:{more:{de:"Weitere Resultate",fr:"Autres r\u00e9sultats",it:"Altri risultati",en:"More results",ch:"Mee Resultaat"}},header:{de:"Ergebnisse",fr:"R\u00e9sultats",it:"Risultati",en:"Results",ch:"Erg\u00e4bnis"}}},t=function(a){for(var b=PickyI18n.locale||
|
2
|
+
"en",j=a.split(".").concat(b),i=dictionary,k=0,n=j.length;k<n;k++){i=i[j[k]];if(i==undefined){i="Translation missing: "+a+"."+b;break}}return i};function Allocation(a,b,j,i,k,n){var p=this;this.type=a;this.weight=b;this.count=j;this.combination=i;this.ids=k||[];this.entries=this.rendered=n||[];this.isType=function(s){return s==p.type}}function Allocations(a){this.allocations=[];for(var b=0,j=a.length;b<j;b++){var i=a[b];this.allocations.push(new Allocation(i[0],i[1],i[2],i[3],i[4],i[5]))}this.length=this.allocations.length;this.remove=function(k){this.allocations.splice(k,1)};this.each=function(k){this.allocations.each(k)}}
|
3
|
+
function PickyData(a){var b=a.total,j=a.duration,i=a.offset,k=new Allocations(a.allocations||[]);this.original_hash=a;this.total=b;this.duration=j;this.offset=i;this.allocations=k;this.renderedAmount=function(){var n=0;k.each(function(p,s){n+=s.rendered.length});return n};this.isEmpty=function(){return b==0}};var PickyView=function(a,b){var j=b.showResultsLimit||10,i=b.input,k=b.reset,n=b.button,p=b.counter,s=b.form,x=b.moreSelector,u=b.results,v=b.noResults,z=new PickyAddination(this,u),f=new PickyAllocationsCloud(this,b),d=new PickyResultsRenderer(z,b),g=function(){k.fadeTo(166,1)},o=function(){f.hide();u.empty();v.hide()},m=function(c){i.val(c);k.fadeTo(166,0);s.attr("class","empty");p.empty();o()};this.reset=m;var h=function(){return i.val()};this.text=h;var q=function(c){p.text(c);c>0&&c<=5&&p.fadeTo("fast",
|
4
|
+
0.5).fadeTo("fast",1)},e=function(c){if(c.isEmpty())return"none";if(c.total>j&&c.allocations.length>1)return"support";return"ok"};this.insert=function(c){i.val(c);i.select()};this.fullResultsCallback=function(c){var r=e(c);s.attr("class",r);if(c.isEmpty()){o();q(0);v.show();g()}else if(c.total>j&&c.allocations.length>1){o();g();f.show(c);q(c.total)}else if(c.offset==0){o();q(c.total);d.render(u,c);u.show();g();i.focus()}else{r=$(x).position().top;z.remove();d.render(u,c);$("body").animate({scrollTop:r-
|
5
|
+
12},500)}};this.liveResultsCallback=function(c){var r=e(c);s.attr("class",r);q(c.total)};this.allocationChosen=function(c){c=c.data.query;a.insert(c);a.allocationChosen(c)};this.addinationClicked=function(c){a.addinationClicked(h(),c)};(function(){i.keyup(function(c){if(h()==""){m();a.searchTextCleared()}else g();a.searchTextEntered(h(),c)});p.click(function(){a.searchButtonClicked(h())});n.click(function(){a.searchButtonClicked(h())});k.click(function(){m();a.clearButtonClicked();i.focus()})})();
|
6
|
+
i.focus()};var PickyBackend=function(a){var b=function(j,i,k){var n=k||{};n=$.extend({query:j},k);$.getJSON(a,n,function(p){i&&i(new PickyData(p))})};this.search=function(j,i,k,n){b(j,function(p){i&&i(n,p)},k)}},LiveBackend=function(a){var b=a.live||alert("A live backend path must be provided."),j=new PickyBackend(b);this.search=function(i,k,n,p){p=p||{};latestRequestTimestamp=new Date;p.live=latestRequestTimestamp;n=$.extend({ids:a.liveResults||0,offset:0},n);j.search(i,function(s,x){if(!s.live||s.live==latestRequestTimestamp)k&&
|
7
|
+
k(x)},n,p)}},FullBackend=function(a){var b=a.full||alert("A full backend path must be provided."),j=new PickyBackend(b);this.search=function(i,k,n,p){p=p||{};latestRequestTimestamp=new Date;p.full=latestRequestTimestamp;n=$.extend({ids:a.fullResults||20,offset:0},n);j.search(i,function(s,x){if(!s.full||s.full==latestRequestTimestamp)k&&k(x)},n,p)}};var PickyController=function(a){var b=new PickyView(this,a),j=a.backends,i=a.beforeInsert||function(){},k=a.before||function(){},n=a.success||function(){},p=a.after||function(){},s=a.liveRendered||false,x=a.liveSearchInterval||180,u,v=function(e){return(e=e&&e.match(/q=([^&]+)/))&&decodeURIComponent(e[1]).replace(/\+/g," ").replace(/#/g,"")||""};this.extractQuery=v;var z=function(){var e=window.History&&window.History.getState();return v(e&&e.url)};this.lastFullQuery=z;var f=function(e,c,r,y){var w=
|
8
|
+
k(c,y);if(w!=undefined)c=w;u=[e,c,r,y];w=c;if(w!=z()){w=w==""?"":"?q="+escape(w).replace(/\*/g,"%2A");window.History&&window.History.getState()&&window.History.pushState&&window.History.pushState(null,null,w)}if(c=="")b.reset();else(e=j[e])&&e.search(c,r,y)};this.resend=function(){u&&f.apply(this,u)};var d=function(e,c){e=n(e,c)||e;b.fullResultsCallback(e);p(e,c)},g=function(e,c){clearInterval(m);f("full",e,d,c||{})};a=function(e,c){e=n(e,c)||e;b.liveResultsCallback(e);p(e,c)};var o=s?d:a,m,h=function(){var e=
|
9
|
+
b.text();f("live",e,o,{});clearInterval(m)};m=setInterval(h,x);clearInterval(m);var q=function(e,c,r){var y=i(e);if(y!=undefined)e=y;b.insert(e);r&&g(e,c)};this.insert=q;this.clearButtonClicked=function(){clearInterval(m)};this.searchTextCleared=function(){clearInterval(m)};this.searchTextEntered=function(e,c){if($.inArray(c.keyCode,[0,8,13,32,46,48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90])>-1)if(c.keyCode==13)g(e);else{clearInterval(m);
|
10
|
+
m=setInterval(h,x)}};this.searchButtonClicked=function(e){g(e)};this.allocationChosen=function(e){g(e)};this.addinationClicked=function(e,c){g(e,{offset:c.data.offset})};window.History&&window.History.Adapter.bind(window,"statechange",function(){var e=window.History.getState();e=v(e.url);e!=undefined&&e!=(u&&u.length>1&&u[1])&&q(e,{},true)})};var PickyI18n={},PickyClient=function(a){PickyI18n.locale=$("html").attr("lang").split("-")[0]||"en";a.locale=a.locale||PickyI18n.locale;a.qualifiers=a.qualifiers||{};a.explanations=a.explanations||{};a.choices=a.choices||{};a.explanation_delimiters={ch:"und",de:"und",en:"and",fr:"et",it:"e"};var b=a.backends;if(b){b.live||alert("Both a full and live backend must be provided.");b.full||alert("Both a full and live backend must be provided.")}else a.backends={live:new LiveBackend(a),full:new FullBackend(a)};
|
11
|
+
b=a.enclosingSelector||".picky";var j=a.formSelector||b+" form";a.form=$(j);a.input=$(a.inputSelector||j+" input[type=search]");a.reset=$(a.resetSelector||j+" div.reset");a.button=$(a.buttonSelector||j+" input[type=button]");a.counter=$(a.counterSelector||j+" div.status");a.results=$(a.resultsSelector||b+" div.results");a.noResults=$(a.noResultsSelector||b+" div.no_results");a.moreSelector=a.moreSelector||b+" div.results div.addination:last";a.allocations=$(a.allocationsSelector||b+" .allocations");
|
12
|
+
a.shownAllocations=a.allocations.find(".shown");a.showMoreAllocations=a.allocations.find(".more");a.hiddenAllocations=a.allocations.find(".hidden");a.maxSuggestions=a.maxSuggestions||3;a.results=$(a.resultsSelector||b+" div.results");a.resultsDivider=a.resultsDivider||"";a.nonPartial=a.nonPartial||[];a.wrapResults=a.wrapResults||"<ol></ol>";var i=a.controller&&new a.controller(a)||new PickyController(a);var k=this.insert=function(n,p,s){i.insert(n,p||{},s||true)};this.resend=i.resend;this.insertFromURL=
|
13
|
+
function(n){if(n)k(n);else(n=i.lastFullQuery())&&k(n)}};var PickyAddination=function(a,b){this.remove=function(){b.find(".addination").remove()};this.render=function(j){var i=j.total,k,n=j.renderedAmount();k=j.offset+n;n=k+n;j=j.total;if(j<n)n=j;k={offset:k,start:k+1,end:n};if(k.offset<i){i=$("<div class='addination'>"+t("results.addination.more")+"</div>");i.bind("click",{offset:k.offset},a.addinationClicked);return i}else return""}};var PickyResultsRenderer=function(a,b){var j=b.locale,i=b.explanations||{},k=b.explanation_delimiters||{},n=b.resultsDivider,p=b.wrapResults,s=b.nonPartial,x=function(d){var g=d[d.length-1];if(g===undefined)return[];d=d.slice(0,d.length-1);if(d==[])d=[d];if(!s.include(g[0]))if(g[1].match(/[^\*~]$/))g[1]+="*";d.push(g);return d};this.asteriskifyLastToken=x;var u=function(d){for(var g=i[j]||{},o=[],m,h=0,q=d.length;h<q;h++){m=d[h];var e=m[0];e=g[e]||e;o.push([e,m[1]])}return o};this.explainCategory=
|
14
|
+
u;var v=function(d,g){return[d.replace(/([\w\s\u00c4\u00e4\u00d6\u00f6\u00dc\u00fc\u00e9\u00e8\u00e0\,]+)/,"<strong>$1</strong>"),g].join(" ")};this.strongify=v;var z=function(d,g){var o=k[j],m="",h=[],q=[];u(x(g)).each(function(e,c){var r=c[0],y=c[1];y=y.replace(/[\w,]+:(.+)/,"$1");if(m==""||r==m){h.push(y);m=r}else{var w=v(m,h.join(" "));h=[];h.push(y);m=r;q.push(w)}});q.push(v(m,h.join(" ")));q=q.join(" "+o+" ");return q='<span class="explanation">'+d+" "+q+"</span>"};this.explain=z;var f=function(d,
|
15
|
+
g){var o='<div class="header">';o+=z(g.type,g.combination);if(d.offset>0)o+='<div class="tothetop"><a href="#" onclick="javascript:$(\'body\').animate({scrollTop: 0}, 500);">↑</a></div>';o+="</div>";return o};this.renderHeader=f;this.render=function(d,g){g.allocations.each(function(o,m){if(m.entries.length>0){d.append(f(g,m)).append(m.entries.join(n));d.children("li").wrapAll(p)}});d.append(a.render(g))}};function AllocationRenderer(a){function b(f){var d={},g={},o={},m=[],h;h=0;for(l=f.length;h<l;h++){var q=f[h][0];if(q in d){d[q].push(f[h][1]);g[q].push(f[h][2]);m.push(h)}else{d[q]=[f[h][1]];g[q]=[f[h][2]];o[h]=q}}for(h in o){f[h][1]=d[o[h]];f[h][2]=g[o[h]]}for(h=m.length-1;h>=0;h--)f.remove(m[h]);return f}function j(f){f.map(function(d){return"%"+(d+1)+"$s"});return f.join(" ")}function i(f){if(f.length==0)return"";f=b(f);f.sort(function(e,c){return e[0]<c[0]?-1:1});for(var d=[],g=0,o=f.length;g<
|
16
|
+
o;g++)d.push(f[g][0]);var m=d.length==1,h=v[d.join(",")];if(h===undefined)h=v[d]=j(d);if(typeof h==="string"){v[d]={format:h,ignoreSingle:true};h=v[d]}var q=h.format;f.each(function(e,c){var r=c[0],y=c[1],w=c[2];w.map(function(B,A){var C=y[B];if(C.charAt(C.length-1)=="*")A+="...";return A});h.filter&&w.map(function(B,A){return h.filter(A)});if(m&&!(h&&h.ignoreSingle)){r=x[r]||r;return q=w.join(" ")+" ("+r+")"}w.map(function(B,A){return A.replace(/[\w,]+:(.+)/,"$1")});q=q.replace(RegExp("%"+
|
17
|
+
(e+1)+"\\$s","g"),w.join(" "))});return q}function k(f){for(var d=[],g=0,o=u.length;g<o;g++)d.push([]);d.push([]);g=0;for(o=f.length;g<o;g++){for(var m=f[g],h=m[0],q=false,e=0,c=u.length;e<c;e++)if(u[e].include(h)){d[e].push(m);q=true;break}q||d[d.length-1].push(m)}var r;for(f=d.length-1;f>=0;f--){r=d[f];if(r.length>0)break}r=r[r.length-1];z.include(r[0])||(r[1]=r[1].valueOf()+"*");return d}function n(f){var d=[];k(f).each(function(g,o){var m=i(o);m&&d.push(m)});return d.join(" ")}var p=a.locale,
|
18
|
+
s=a.qualifiers&&a.qualifiers[p]||{},x=a.explanations&&a.explanations[p]||{},u=a.groups||[],v=a.choices&&a.choices[p]||{},z=a.nonPartial||[];this.explanation=this.query=this.text="";this.contract=b;this.makeUpMissingFormat=j;this.rendered=i;this.groupify=k;this.querify=function(f){var d=[],g,o,m;for(m in f){g=f[m][0];g=s[g]||g;o=(o=f[m][1])||"";o=o.charAt(o.length-1)=="*"?"*":"";d[m]=g+":"+f[m][2]+o}return d.join(" ")};this.suggestify=n;this.render=function(f){return n(f.combination)}};var PickyAllocationsCloud=function(a,b){var j=b.allocations,i=b.shownAllocations,k=b.showMoreAllocations,n=b.hiddenAllocations,p=b.maxSuggestions,s=function(){j.hide()},x=function(f){s();a.allocationChosen(f)},u=new AllocationRenderer(b),v=function(f){var d=[];f.each(function(g,o){var m=u.querify(o.combination),h=u.render(o);h=$('<li><div class="text">'+h+'</div><div class="count">'+o.count+"</div></li>");h.bind("click",{query:m},x);d.push(h)});return d},z=function(f){if(f.length==0)return j.hide();
|
19
|
+
i.empty();k.hide();n.empty().hide();if(f.length>p){$.each(f.slice(0,p-1),function(d,g){i.append(g)});$.each(f.slice(p-1),function(d,g){n.append(g)});k.show()}else $.each(f,function(d,g){i.append(g)});return j.show()};k.click(function(){k.hide();n.show()});this.hide=s;this.show=function(f){z(v(f.allocations));j.show()}};
|