honyomi 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bf7508e7109d3ead69a143592dde4cb74b6e4487
4
- data.tar.gz: 31fb3eaaf69b663b3d472e77b82042689b45d146
3
+ metadata.gz: 68f371dc5130aa8dc7f02f3464902d28628ba38a
4
+ data.tar.gz: dceceb65a54d4944993a91ae8d8a75b7576d9a0e
5
5
  SHA512:
6
- metadata.gz: 9fea83150ee7a69e5e1655ced9eb748e6fb4b80ff216732f762225899f749d3083d98341a5aa76af89ac88ee486a7b62a9cfb7100a46248b820522d3fe23749c
7
- data.tar.gz: 66252688b26270c8998b13cb348cc07a89e2a960a39fc4abe9f9375b2d1fba79cbfbe6cad11cae735eae79bf63804e08dca4b4a536e6be052993d8828f1a05e3
6
+ metadata.gz: 7ca2111c247ee0bea1a11e74a3b6d57479e361bd148b76fb8f3873c3e349c079fbf39e3c14ceb6744053b1007b5cb2e6b0e287edbaf2dd7d8a825f2a3bc17ebd
7
+ data.tar.gz: c733a8d9b8420a5b92fb0df4b317931a10ac1bd03cf336bf265e4521ab08abbd26ff1d6711a812cefdbf5b4977dd05c7150921cedef13ebe8a51bb7f07fb330e
data/HISTORY.md CHANGED
@@ -1,6 +1,21 @@
1
1
  # HISTORY - Honyomi
2
2
 
3
- ## 0.1 - 2014-07-18
3
+ ## 0.2 - 2014-10-07
4
+
5
+ * Improve search result
6
+ * Highlight keywords
7
+ * Take over the search query
8
+ * Improve text mode
9
+ * Rename from 'raw' to 'text'
10
+ * Highlight keywords
11
+ * Take over the search query
12
+ * Change rendering tag from <pre> to <div>
13
+ * Change background color
14
+ * Change Navbar to static
15
+ * Add link to honyomi-web
16
+ * Refactor page tag
17
+
18
+ ## 0.1 - 2014-10-02
4
19
 
5
20
  * Search in book
6
21
  * Display the book list
data/README.md CHANGED
@@ -18,6 +18,9 @@ When you faild to install Rroonga, Please refer.
18
18
  And need external tools.
19
19
  * pdftotext - For reading pdf (poppler, xpdf)
20
20
 
21
+ ## Install to server
22
+ * [ongaeshi/honyomi-web](https://github.com/ongaeshi/honyomi-web)
23
+
21
24
  ## Usage
22
25
 
23
26
  ### Create a database
@@ -37,5 +37,75 @@ module Honyomi
37
37
  def strip_page(page)
38
38
  page.gsub(/[ \t]/, "")
39
39
  end
40
+
41
+ def highlight_keywords(src, keywords, css_class)
42
+ # Init highlight_map
43
+ hightlight_map = Array.new(src.length, nil)
44
+
45
+ keywords.each do |keyword|
46
+ pos = 0
47
+
48
+ loop do
49
+ r = src.match(/#{Regexp.escape(keyword)}/i, pos) do |m|
50
+ s = m.begin(0)
51
+ l = keyword.length
52
+ e = s+l
53
+ (s...e).each {|i| hightlight_map[i] = 1 }
54
+ pos = e
55
+ end
56
+
57
+ break if r.nil?
58
+ end
59
+ end
60
+
61
+ # Delete html tag
62
+ index = 0
63
+ in_tag = false
64
+ src.each_char do |char|
65
+ in_tag = true if char == '<'
66
+ hightlight_map[index] = nil if in_tag
67
+ in_tag = false if char == '>'
68
+ index += 1
69
+ end
70
+
71
+ # Output
72
+ result = ""
73
+
74
+ index = 0
75
+ prev = nil
76
+ src.each_char do |char|
77
+ current = hightlight_map[index]
78
+
79
+ if prev.nil? && current
80
+ result += "<span class='#{css_class}'>"
81
+ elsif prev && current.nil?
82
+ result += "</span>"
83
+ end
84
+
85
+ result += char
86
+
87
+ index += 1
88
+ prev = current
89
+ end
90
+ result += "</span>" if prev
91
+
92
+ result
93
+ end
94
+
95
+ def extract_keywords(query)
96
+ query.split.reduce([]) do |a, e|
97
+ e = e.gsub(/^\(|\)|AND|OR$/, "")
98
+
99
+ if e =~ /^"(.+)"$/
100
+ a + [$1]
101
+ elsif e =~ /^-/
102
+ a
103
+ elsif e =~ /:/
104
+ a
105
+ else
106
+ a + [e]
107
+ end
108
+ end
109
+ end
40
110
  end
41
111
  end
@@ -1,3 +1,3 @@
1
1
  module Honyomi
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,5 +1,6 @@
1
1
  require 'haml'
2
2
  require 'honyomi/database'
3
+ require 'honyomi/util'
3
4
  require 'sinatra'
4
5
  require 'sinatra/reloader' if ENV['SINATRA_RELOADER']
5
6
 
@@ -34,15 +35,15 @@ get '/v/:id' do
34
35
 
35
36
  book = @database.books[params[:id].to_i]
36
37
 
37
- if params[:raw] == '1'
38
- raw_all(book)
38
+ if params[:text] == '1'
39
+ text_all(book)
39
40
  elsif params[:pdf] == '1'
40
41
  send_file(book.path, :disposition => 'inline')
41
42
  elsif params[:dl] == '1'
42
43
  send_file(book.path, :disposition => 'download')
43
44
  else
44
45
  if params[:page]
45
- raw_page(book, params[:page].to_i)
46
+ text_page(book, params[:page].to_i)
46
47
  else
47
48
  if @params[:query] && !@params[:query].empty?
48
49
  search_book_home(book)
@@ -56,6 +57,8 @@ end
56
57
  helpers do
57
58
 
58
59
  def home
60
+ @header_info = %Q|#{@database.books.size} books, #{@database.pages.size} pages.|
61
+
59
62
  r = @database.books.map { |book|
60
63
  <<EOF
61
64
  <li>#{book.id}: <a href="/v/#{book.id}">#{book.title}</a> (#{book.page_num}P)</li>
@@ -63,12 +66,9 @@ EOF
63
66
  }.reverse
64
67
 
65
68
  @content = <<EOF
66
- <div class="matches">#{@database.books.size} books, #{@database.pages.size} pages.</div>
67
- <div class="result">
68
- <ul>
69
+ <ul>
69
70
  #{r.join("\n")}
70
- </ul>
71
- </div>
71
+ </ul>
72
72
  EOF
73
73
 
74
74
  haml :index
@@ -83,22 +83,15 @@ EOF
83
83
 
84
84
  def book_home(book)
85
85
  @book_id = book.id
86
- @navbar_href = "/v/#{book.id}"
87
- @navbar_title = book.title
88
- file_mb = File.stat(book.path).size / (1024 * 1024)
89
-
90
- @content = <<EOF
91
- <div class="result">
92
- <div class="matches">#{book.page_num} pages. <a href="/v/#{book.id}?dl=1">Download</a> <span class="result-file-size">(#{file_mb}M)</span>&nbsp;&nbsp;&nbsp;<a href="/v/#{book.id}?pdf=1">Pdf</a>&nbsp;&nbsp;&nbsp;<a href="/v/#{book.id}?raw=1">Raw</a></div>
93
- </div>
94
- EOF
86
+ @header_title = header_title_book(book, @params[:query])
87
+ @header_info = header_info_book(book, @params[:query])
88
+ @content = ""
95
89
  haml :index
96
90
  end
97
91
 
98
92
  def search_book_home(book)
99
93
  @book_id = book.id
100
- @navbar_href = "/v/#{book.id}"
101
- @navbar_title = book.title
94
+ @header_title = header_title_book(book, @params[:query])
102
95
 
103
96
  search_common(@params[:query] + " book: #{book.id}",
104
97
  [["page_no", :asc]],
@@ -106,38 +99,32 @@ EOF
106
99
  )
107
100
  end
108
101
 
109
- def raw_all(book)
110
- pages = @database.book_pages(book.id)
102
+ def text_all(book)
103
+ @book_id = book.id
104
+ @header_title = header_title_book(book, @params[:query])
105
+ @header_info = header_info_book(book, @params[:query])
111
106
 
112
- @navbar_href = "/v/#{book.id}"
113
- @navbar_title = book.title
107
+ pages = @database.book_pages(book.id)
108
+ keywords = Util.extract_keywords(@params[:query])
114
109
 
115
110
  @content = pages.map { |page|
116
- <<EOF
117
- <div class="raw-page" id="#{page.page_no}">
118
- <div class="raw-page-no"><i class="fa fa-file-text-o"></i> <a href="##{page.page_no}">P#{page.page_no}</a></div>
119
- <pre>#{escape_html page.text}</pre>
120
- </div>
121
- EOF
111
+ render_page(page, keywords: keywords, with_number: true)
122
112
  }.join("\n")
123
113
 
124
- haml :raw
114
+ haml :index
125
115
  end
126
116
 
127
- def raw_page(book, page_no)
128
- @navbar_href = "/v/#{book.id}"
129
- @navbar_title = book.title
117
+ def text_page(book, page_no)
130
118
  page = @database.book_pages(book.id)[page_no]
131
- file_mb = File.stat(book.path).size / (1024 * 1024)
119
+ keywords = Util.extract_keywords(@params[:query])
132
120
 
133
- @content = <<EOF
134
- <div class="landing-page" id="#{page.page_no}">
135
- <div class="landing-page-no"><i class="fa fa-file-text-o"></i> P#{page.page_no} &nbsp;&nbsp;&nbsp;
136
- <a href="/v/#{book.id}?dl=1">Download</a> <span class="result-file-size">(#{file_mb}M)</span>&nbsp;&nbsp;&nbsp;<a href="/v/#{book.id}?pdf=1#page=#{page.page_no}">Pdf</a>&nbsp;&nbsp;&nbsp;<a href="/v/#{book.id}?raw=1##{page.page_no}">Raw</a></div>
137
- <pre>#{escape_html page.text}</pre>
138
- </div>
139
- EOF
140
- haml :raw
121
+ @book_id = book.id
122
+ @header_title = header_title_book(book, @params[:query])
123
+ @header_info = header_info_book(book, @params[:query], page)
124
+
125
+ @content = render_page(page, keywords: keywords)
126
+
127
+ haml :index
141
128
  end
142
129
 
143
130
  RPAGE_SIZE = 20
@@ -156,7 +143,7 @@ EOF
156
143
  EOF
157
144
  end
158
145
 
159
- snippet = results.expression.snippet([["<strong>", "</strong>"]], {html_escape: true, normalize: true, max_results: 10})
146
+ snippet = results.expression.snippet([["<span class=\"highlight\">", "</span>"]], {html_escape: true, normalize: true, max_results: 5})
160
147
 
161
148
  books = {}
162
149
 
@@ -164,6 +151,8 @@ EOF
164
151
  books[page.book.path] = 1
165
152
  end
166
153
 
154
+ @header_info = %Q|#{books.size} books, #{results.size} pages|
155
+
167
156
  r = rpage_entries.map do |page|
168
157
  if is_filter
169
158
  query_plus = escape "#{query} book:#{page.book.id}"
@@ -175,11 +164,11 @@ EOF
175
164
 
176
165
  <<EOF
177
166
  <div class="result">
178
- <div class="result-header"><a href="/v/#{page.book.id}?page=#{page.page_no}">#{page.book.title}</a> (P#{page.page_no})</div>
179
- <div class="row result-sub-header">
167
+ <div class="title"><a href="/v/#{page.book.id}?query=#{escape(@params[:query])}&page=#{page.page_no}">#{page.book.title}</a> (P#{page.page_no})</div>
168
+ <div class="row info">
180
169
  #{filter_str}
181
170
  </div>
182
- <div class="result-body">
171
+ <div class="main">
183
172
  #{snippet.execute(page.text).map {|segment| "<div class=\"result-body-element\">" + segment.gsub("\n", "") + "</div>"}.join("\n") }
184
173
  </div>
185
174
  </div>
@@ -187,7 +176,6 @@ EOF
187
176
  end
188
177
 
189
178
  @content = <<EOF
190
- <div class="matches">#{books.size} books, #{results.size} pages</div>
191
179
  <div class="autopagerize_page_element">
192
180
  #{r.join("\n")}
193
181
  </div>
@@ -196,4 +184,37 @@ EOF
196
184
 
197
185
  haml :index
198
186
  end
187
+
188
+ def header_title_book(book, query)
189
+ query = query ? "?query=#{query}" : ""
190
+ "<a href='/#{query}'>HOME</a> &gt; <a href='/v/#{book.id}#{query}'>#{book.title}</a>"
191
+ end
192
+
193
+ def header_info_book(book, query, page = nil)
194
+ query = query ? "&query=#{query}" : ""
195
+ file_mb = File.stat(book.path).size / (1024 * 1024)
196
+
197
+ if page.nil?
198
+ %Q|#{book.page_num} pages. <a href="/v/#{book.id}?dl=1">Download</a> <span class="file-size">(#{file_mb}M)</span>&nbsp;&nbsp;&nbsp;<a href="/v/#{book.id}?pdf=1">Pdf</a>&nbsp;&nbsp;&nbsp;<a href="/v/#{book.id}?text=1#{query}">Text</a>|
199
+ else
200
+ %Q|<i class="fa fa-file-text-o"></i> P#{page.page_no} &nbsp;&nbsp;&nbsp;<a href="/v/#{book.id}?dl=1">Download</a> <span class="file-size">(#{file_mb}M)</span>&nbsp;&nbsp;&nbsp;<a href="/v/#{book.id}?pdf=1#page=#{page.page_no}">Pdf</a>&nbsp;&nbsp;&nbsp;<a href="/v/#{book.id}?text=1#{query}##{page.page_no}">Text</a>|
201
+ end
202
+ end
203
+
204
+ def render_page(page, options = {})
205
+ with_number = options[:with_number] ? %Q|<div class="no"><i class="fa fa-file-text-o"></i> <a href="##{page.page_no}">P#{page.page_no}</a></div>| : ""
206
+
207
+ text = escape_html(page.text)
208
+ text = Util.highlight_keywords(text, options[:keywords], 'highlight') if options[:keywords]
209
+ text = text.gsub("\n\n", "<br/><br/>")
210
+
211
+ <<EOF
212
+ <div class="page" id="#{page.page_no}">
213
+ #{with_number}
214
+ <div class="main">
215
+ #{text}
216
+ </div>
217
+ </div>
218
+ EOF
219
+ end
199
220
  end
@@ -1,58 +1,72 @@
1
- .search-header {
1
+ /* header */
2
+ .header {
3
+ }
4
+
5
+ .header .title {
6
+ font-size: 130%;
2
7
  margin: 0px 0px 10px 0px;
3
8
  }
4
9
 
5
- .matches {
10
+ .header .info {
6
11
  margin: 10px 0px 0px 5px;
7
12
  }
8
13
 
9
- .result {
14
+ /* content */
15
+ .content {
10
16
  margin: 10px 0px 0px 5px;
11
17
  }
12
18
 
13
- .result-header {
19
+ /* .content .home */
20
+ .content ul {
14
21
  font-size: 120%;
22
+ list-style: none;
23
+ padding-left: 0px;
15
24
  }
16
25
 
17
- .result-sub-header {
18
- /* margin: 5px 0px 0px 0px; */
19
- font-size: 100%;
26
+ /* .content .result */
27
+ .result .title {
28
+ margin: 10px 0px 0px 0px;
20
29
  }
21
30
 
22
- .result-file-size {
23
- font-size: 95%;
31
+ .result .title {
32
+ font-size: 120%;
24
33
  }
25
34
 
26
- .result-body {
35
+ .result .info {
36
+ /* margin: 5px 0px 0px 0px; */
37
+ font-size: 100%;
38
+ }
39
+
40
+ .result .main {
27
41
  margin: 5px 0px 0px 0px;
28
42
  font-size: 95%;
29
43
  }
30
44
 
31
- .raw-page {
32
- margin: 0px 20px;
33
- }
45
+ /* .content .text */
34
46
 
35
- .raw-page-no {
36
- padding: 60px 0px 10px 0px;
47
+ .page {
48
+ /* margin: 0px 0px; */
37
49
  }
38
50
 
39
- .landing-page {
40
- margin: 0px 20px;
51
+ .page .no {
52
+ padding: 20px 0px 10px 0px;
41
53
  }
42
54
 
43
- .landing-page-no {
44
- padding: 0px 0px 10px 0px;
55
+ .page .main {
56
+ background-color: #fbfbfb;
57
+ border: solid 1px #d0d0d0;
58
+ font-size: 95%;
45
59
  }
46
60
 
47
- .result ul {
48
- font-size: 120%;
49
- list-style: none;
50
- padding-left: 0px;
61
+ /* common */
62
+ .file-size {
63
+ font-size: 95%;
51
64
  }
52
65
 
53
- .landing-page ul {
54
- font-size: 120%;
55
- list-style: none;
56
- padding-left: 0px;
66
+ .highlight {
67
+ /* background-color: #B4D5FF; */
68
+ /* background-color: #FFF17A; */
69
+ background-color: #FEEFA2;
70
+ font-weight: bold;
57
71
  }
58
72
 
@@ -3,9 +3,15 @@
3
3
  .container
4
4
  .row
5
5
  .col-md-12
6
- %form(class="form-inline" method="post" action="/search")
7
- .form-group
8
- %input(class="form-control" type="text" size=40 name="query" value="#{@params[:query]}")
9
- %input(type="hidden" name="book_id" value="#{@book_id}")
10
- %input(class="btn btn-primary" type="submit" value="Search")
11
- = @content
6
+ .header
7
+ .title
8
+ = @header_title
9
+ %form(class="form-inline" method="post" action="/search")
10
+ .form-group
11
+ %input(class="form-control" type="text" size=40 name="query" value="#{@params[:query]}")
12
+ %input(type="hidden" name="book_id" value="#{@book_id}")
13
+ %input(class="btn btn-primary" type="submit" value="Search")
14
+ .info
15
+ = @header_info
16
+ .content
17
+ = @content
@@ -10,8 +10,8 @@
10
10
  %link(rel="stylesheet" href="/css/honyomi.css")
11
11
  %link(rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css")
12
12
 
13
- %body(style="padding-top:70px;")
14
- .navbar.navbar-default.navbar-fixed-top
13
+ %body
14
+ .navbar.navbar-default.navbar-static-top
15
15
  .navbar-header
16
16
  %button(type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse")
17
17
  %span(class="icon-bar")
@@ -22,7 +22,7 @@
22
22
  .navbar-collapse.collapse
23
23
  %ul(class="nav navbar-nav")
24
24
  %li
25
- <a href="#{@navbar_href}">#{@navbar_title}</a>
25
+ <a href="/help">Help</a>
26
26
 
27
27
  != yield
28
28
  %script(src="https://code.jquery.com/jquery.js")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: honyomi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ongaeshi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-02 00:00:00.000000000 Z
11
+ date: 2014-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: grn_mini
@@ -197,7 +197,6 @@ files:
197
197
  - lib/honyomi/web/public/image/favicon.ico
198
198
  - lib/honyomi/web/views/index.haml
199
199
  - lib/honyomi/web/views/layout.haml
200
- - lib/honyomi/web/views/raw.haml
201
200
  - test/minitest_helper.rb
202
201
  - test/test.pdf
203
202
  - test/test2.pdf
@@ -1,3 +0,0 @@
1
- !!!
2
-
3
- = @content