honyomi 0.1.0 → 0.2.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 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