maglove 0.5.4 → 0.5.5

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: 68e99357e1c9657d692067ffc9ccc18ec8abf2b3
4
- data.tar.gz: 3ff5da3c4f3b972aa400d3eb63cad8bfc59945f0
3
+ metadata.gz: de2a076857bf9fc5e27988f5c13650ecfc6a92a7
4
+ data.tar.gz: cab8e9e7dfc96f8ced3101d779544500630fc4cd
5
5
  SHA512:
6
- metadata.gz: 82928b5fe88f1a0c3480dea707b37c9686f6245032490a28c0de387b252f251719f539740eaa659321fb7dd9bd08da8bb7e36ad3c763239d3ddc352e31d8b9b7
7
- data.tar.gz: fb52aa0ae644a31f511542d71fdb2a46b63e3dfdb29cf9408f095ddaa7018f46298b46ad033266a3d2c7bac709457e9a4bc9482f556c62287c75a58497fc1920
6
+ metadata.gz: b8bca796f465d49329fd353433171e0c2c62c3ee6e1bc4ac9c2a2ae6d2f62af9d5d060b3ea149563efcca17c0f5d3e2deccbddd77a10d386e31ca9775ff5f12f
7
+ data.tar.gz: 83c0ceec58dab01e8386b215a9ca241426fd943121e0b9b4c529af50351c8250a8024438fa66325036aa125aecb8cd6894099ef74d429e936946b73d18eaa41d
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- maglove (0.5.4)
4
+ maglove (0.5.5)
5
5
  activesupport (~> 4.2)
6
6
  bundler (~> 1.10)
7
7
  coffee-script (~> 2.4)
@@ -10,11 +10,6 @@ module MagLove
10
10
  MagLove::Server.new(options.theme).run!
11
11
  end
12
12
 
13
- task :hpub, port: "8080" do |args, options|
14
- info("▸ starting hpub server at http://127.0.0.1:#{options.port}/manifest.json")
15
- MagLove::Hpub::Server.new(options.port).run!
16
- end
17
-
18
13
  end
19
14
  end
20
15
  end
@@ -0,0 +1,185 @@
1
+ module MagLove
2
+ class Server
3
+ module Hpub
4
+
5
+ class IssueServlet < WEBrick::HTTPServlet::AbstractServlet
6
+ include Commander::Methods
7
+
8
+ def do_GET(req, res)
9
+ theme = File.basename(req.path, ".*")
10
+ config = theme_config(nil, theme)
11
+ working_dir = Dir.mktmpdir
12
+ data_dir = Gem.datadir("maglove")
13
+
14
+ # Create book.json
15
+ book_json = {
16
+ "hpub" => 1,
17
+ "title" => config["name"],
18
+ "author" => ["MagLove"],
19
+ "creator" => ["MagLove"],
20
+ "date" => Time.now.strftime("%Y-%m-%d %H:%M:%S UTC"),
21
+ "url" => "book://www.magloft.com",
22
+ "orientation" => "both",
23
+ "-baker-background" => "#FFFFFF",
24
+ "-baker-index-height" => 240,
25
+ "-baker-media-autoplay" => false,
26
+ "-baker-rendering" => "three-cards",
27
+ "-baker-page-numbers-color" => "#333",
28
+ "-baker-vertical-bounce" => true,
29
+ "-baker-page-turn-tap" => true,
30
+ "-baker-start-at-page" => 1,
31
+ "-baker-max-zoom-level" => 2.0,
32
+ "zoomable" => true,
33
+ "contents" => config["templates"].map{|t| "#{t}.html"}
34
+ }
35
+ File.open("#{working_dir}/book.json", "w"){|f| f.write(book_json.to_json) }
36
+
37
+ # Copy assets
38
+ FileUtils.cp_r("dist/fonts", "#{working_dir}/fonts")
39
+ FileUtils.cp_r("dist/themes/#{theme}/thumbs", "#{working_dir}/thumbs")
40
+ FileUtils.cp("dist/themes/#{theme}/thumbs/#{config["templates"][0]}.png", "#{working_dir}/cover.png")
41
+ FileUtils.mkdir_p("#{working_dir}/stylesheets")
42
+ FileUtils.cp("#{data_dir}/hpub/index.css", "#{working_dir}/stylesheets/index.css")
43
+ FileUtils.mkdir_p("#{working_dir}/themes")
44
+ FileUtils.cp_r("dist/themes/#{theme}", "#{working_dir}/themes/#{theme}")
45
+
46
+ # Create index html
47
+ index_contents = File.read("#{data_dir}/hpub/index.haml")
48
+ engine = Haml::Engine.new(index_contents)
49
+ index_html = engine.render(Object.new, config)
50
+ File.open("#{working_dir}/index.html", "w"){|f| f.write(index_html) }
51
+
52
+ # Compile themes
53
+ Hamloft::Options.defaults[:asset_uri] = "."
54
+ theme_glob("templates/*.{html,haml,twig}", theme).each do |file|
55
+ # compile template
56
+ template = File.basename(file, ".*")
57
+ locals = {}
58
+ locals_contents = theme_contents(file.sub(/\.[^.]+\z/, ".yml"), theme)
59
+ if locals_contents
60
+ locals = YAML.load(locals_contents).with_indifferent_access
61
+ end
62
+ asset = theme_asset(file, theme, locals)
63
+
64
+ # wrap in page
65
+ page_contents = File.read("#{data_dir}/hpub/page.haml")
66
+ engine = Haml::Engine.new(page_contents)
67
+ page_html = engine.render(Object.new, {template: template, theme: theme, contents: compile_html(asset.contents)})
68
+
69
+ # Write to file
70
+ File.open("#{working_dir}/#{template}.html", "w"){|f| f.write(page_html) }
71
+ end
72
+
73
+ # Delete zip file
74
+ zip_path = "#{working_dir}/themes/#{theme}/#{theme}.tar.gz"
75
+ FileUtils.rm_f(zip_path) if File.exists?(zip_path)
76
+
77
+ # Create zip archive
78
+ FileUtils.rm_f("dist/#{theme}.hpub") if File.exists?("dist/#{theme}.hpub")
79
+ Zip::File.open("dist/#{theme}.hpub", Zip::File::CREATE) do |zipfile|
80
+ Dir[File.join(working_dir, '**', '**')].each do |file|
81
+ zipfile.add(file.sub("#{working_dir}/", ''), file)
82
+ end
83
+ end
84
+
85
+ # respond
86
+ res.status = 200
87
+ res['Content-Type'] = "application/zip"
88
+ res.body = File.read("dist/#{theme}.hpub")
89
+ end
90
+
91
+ private
92
+
93
+ def compile_html(contents)
94
+ doc = Nokogiri::HTML.fragment(contents.force_encoding("UTF-8"))
95
+
96
+ # unwrap widgets
97
+ doc.css("._typeloft_widget").each do |node|
98
+
99
+ # remove unneeded attributes
100
+ node.attributes.each do |key, attribute|
101
+ node.attributes[key].remove if key != "style" and key != "class"
102
+ end
103
+
104
+ # clean up classes
105
+ if not node.attributes["class"].nil?
106
+ classList = node.attributes["class"].value.split(" ")
107
+ classList.reject!{|cls| ["_typeloft_widget", "ui-resizable", "_typeloft_widget_selected", "_typeloft_widget_hover"].include?(cls)}
108
+ node.attributes["class"].value = classList.join(" ")
109
+ end
110
+ end
111
+
112
+ # remove scripts
113
+ doc.css('script').remove()
114
+
115
+ # unwrap drop containers
116
+ doc.css("._typeloft_widget_drop_container").each do |node|
117
+ node.children.each do |child|
118
+ node.parent << child
119
+ end
120
+ node.remove
121
+ end
122
+
123
+ # remove data-typeloft-slug attributes
124
+ doc.xpath( './/*[@data-typeloft-slug]|*[@data-typeloft-slug]' ).each do |node|
125
+ node.attributes["data-typeloft-slug"].remove
126
+ end
127
+
128
+ # remove contenteditable attributes
129
+ doc.xpath( './/*[@contenteditable]|*[@contenteditable]' ).each do |node|
130
+ node.attributes["contenteditable"].remove
131
+ end
132
+
133
+ # remove widget containers
134
+ doc.css("._typeloft_widget_container").remove()
135
+
136
+ # remove typeloft classes
137
+ doc.xpath(".//*[@*[contains(., '_typeloft_')]]").each do |node|
138
+ classes = node[:class].split(' ').select{|cls| !cls.include?('_typeloft_')}
139
+ node[:class] = classes.join(' ')
140
+ end
141
+
142
+ # convert iframe https links to http
143
+ doc.search('iframe[src*="https://"]').each do |node|
144
+ src = node[:src].sub('https://', 'http://')
145
+ node[:src] = src
146
+ end
147
+
148
+ # fetch html
149
+ clean_html_chars(doc.to_s)
150
+ end
151
+
152
+ def clean_html_chars(characters)
153
+ ["\u1680", "\u180E", "\u2000", "\u2001", "\u2002", "\u2003", "\u2004", "\u2005", "\u2006", "\u2007", "\u2008", "\u2009", "\u200A", "\u200B", "\u202F", "\u205F", "\u3000", "\uFEFF"].each do |char|
154
+ characters = characters.force_encoding("UTF-8").gsub(char, "&nbsp&nbsp")
155
+ end
156
+ characters.force_encoding("BINARY").gsub(0xC2.chr+0xA0.chr+" ","&nbsp;&nbsp;").gsub(0xC2.chr+0xA0.chr,"&nbsp;")
157
+ end
158
+ end
159
+
160
+ class ManifestServlet < WEBrick::HTTPServlet::AbstractServlet
161
+ include Commander::Methods
162
+
163
+ def do_GET(req, res)
164
+ res.content_type = "application/json"
165
+ manifest = []
166
+ Dir.glob("dist/themes/*") do |dir|
167
+ theme = File.basename(dir)
168
+ config = theme_config(nil, theme)
169
+ manifest.push({
170
+ name: theme,
171
+ title: config["name"],
172
+ product_id: nil,
173
+ info: config["description"],
174
+ date: Time.now.strftime("%Y-%m-%d %H:%M:%S"),
175
+ url: "http://#{req.host}:#{req.port}/issue/#{theme}.hpub",
176
+ cover: "http://#{req.host}:#{req.port}/themes/#{theme}/thumbs/#{config["templates"][0]}.png"
177
+ })
178
+ end
179
+ res.body = manifest.to_json
180
+ end
181
+ end
182
+
183
+ end
184
+ end
185
+ end
@@ -56,6 +56,9 @@ module MagLove
56
56
  res.content_type = "text/css"
57
57
  res.body = parser.parse(less_contents).to_css
58
58
  end
59
+
60
+ self.webrick.mount "/issue", Hpub::IssueServlet
61
+ self.webrick.mount "/manifest.json", Hpub::ManifestServlet
59
62
  end
60
63
 
61
64
  def mount_template(path, view, options={})
@@ -1,3 +1,3 @@
1
1
  module MagLove
2
- VERSION = "0.5.4"
2
+ VERSION = "0.5.5"
3
3
  end
data/lib/maglove.rb CHANGED
@@ -43,6 +43,6 @@ require "maglove/phantom_script"
43
43
  require "maglove/application"
44
44
  require "maglove/asset/theme"
45
45
  require "maglove/asset/base_theme"
46
+ require "maglove/server/hpub"
46
47
  require "maglove/server"
47
- require "maglove/hpub/server"
48
48
  require "maglove/template/tumblr"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: maglove
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.4
4
+ version: 0.5.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Strebitzer
@@ -392,9 +392,9 @@ files:
392
392
  - lib/maglove/helper/command_helper.rb
393
393
  - lib/maglove/helper/log_helper.rb
394
394
  - lib/maglove/helper/theme_helper.rb
395
- - lib/maglove/hpub/server.rb
396
395
  - lib/maglove/phantom_script.rb
397
396
  - lib/maglove/server.rb
397
+ - lib/maglove/server/hpub.rb
398
398
  - lib/maglove/template/tumblr.rb
399
399
  - lib/maglove/tilt/coffee_template.rb
400
400
  - lib/maglove/tilt/haml_template.rb
@@ -1,214 +0,0 @@
1
- module MagLove
2
- module Hpub
3
-
4
- class IssueServlet < WEBrick::HTTPServlet::AbstractServlet
5
- include Commander::Methods
6
-
7
- def do_GET(req, res)
8
- theme = File.basename(req.path, ".*")
9
- config = theme_config(nil, theme)
10
- working_dir = Dir.mktmpdir
11
- data_dir = Gem.datadir("maglove")
12
-
13
- # Create book.json
14
- book_json = {
15
- "hpub" => 1,
16
- "title" => config["name"],
17
- "author" => ["MagLove"],
18
- "creator" => ["MagLove"],
19
- "date" => Time.now.strftime("%Y-%m-%d %H:%M:%S UTC"),
20
- "url" => "book://www.magloft.com",
21
- "orientation" => "both",
22
- "-baker-background" => "#FFFFFF",
23
- "-baker-index-height" => 240,
24
- "-baker-media-autoplay" => false,
25
- "-baker-rendering" => "three-cards",
26
- "-baker-page-numbers-color" => "#333",
27
- "-baker-vertical-bounce" => true,
28
- "-baker-page-turn-tap" => true,
29
- "-baker-start-at-page" => 1,
30
- "-baker-max-zoom-level" => 2.0,
31
- "zoomable" => true,
32
- "contents" => config["templates"].map{|t| "#{t}.html"}
33
- }
34
- File.open("#{working_dir}/book.json", "w"){|f| f.write(book_json.to_json) }
35
-
36
- # Copy assets
37
- FileUtils.cp_r("dist/fonts", "#{working_dir}/fonts")
38
- FileUtils.cp_r("dist/themes/#{theme}/thumbs", "#{working_dir}/thumbs")
39
- FileUtils.cp("dist/themes/#{theme}/thumbs/#{config["templates"][0]}.png", "#{working_dir}/cover.png")
40
- FileUtils.mkdir_p("#{working_dir}/stylesheets")
41
- FileUtils.cp("#{data_dir}/hpub/index.css", "#{working_dir}/stylesheets/index.css")
42
- FileUtils.mkdir_p("#{working_dir}/themes")
43
- FileUtils.cp_r("dist/themes/#{theme}", "#{working_dir}/themes/#{theme}")
44
-
45
- # Create index html
46
- index_contents = File.read("#{data_dir}/hpub/index.haml")
47
- engine = Haml::Engine.new(index_contents)
48
- index_html = engine.render(Object.new, config)
49
- File.open("#{working_dir}/index.html", "w"){|f| f.write(index_html) }
50
-
51
- # Compile themes
52
- Hamloft::Options.defaults[:asset_uri] = "."
53
- theme_glob("templates/*.{html,haml,twig}", theme).each do |file|
54
- # compile template
55
- template = File.basename(file, ".*")
56
- locals = {}
57
- locals_contents = theme_contents(file.sub(/\.[^.]+\z/, ".yml"), theme)
58
- if locals_contents
59
- locals = YAML.load(locals_contents).with_indifferent_access
60
- end
61
- asset = theme_asset(file, theme, locals)
62
-
63
- # wrap in page
64
- page_contents = File.read("#{data_dir}/hpub/page.haml")
65
- engine = Haml::Engine.new(page_contents)
66
- page_html = engine.render(Object.new, {template: template, theme: theme, contents: compile_html(asset.contents)})
67
-
68
- # Write to file
69
- File.open("#{working_dir}/#{template}.html", "w"){|f| f.write(page_html) }
70
- end
71
-
72
- # Delete zip file
73
- zip_path = "#{working_dir}/themes/#{theme}/#{theme}.tar.gz"
74
- FileUtils.rm_f(zip_path) if File.exists?(zip_path)
75
-
76
- # Create zip archive
77
- FileUtils.rm_f("dist/#{theme}.hpub") if File.exists?("dist/#{theme}.hpub")
78
- Zip::File.open("dist/#{theme}.hpub", Zip::File::CREATE) do |zipfile|
79
- Dir[File.join(working_dir, '**', '**')].each do |file|
80
- zipfile.add(file.sub("#{working_dir}/", ''), file)
81
- end
82
- end
83
-
84
- # respond
85
- res.status = 200
86
- res['Content-Type'] = "application/zip"
87
- res.body = File.read("dist/#{theme}.hpub")
88
- end
89
-
90
- private
91
-
92
- def compile_html(contents)
93
- doc = Nokogiri::HTML.fragment(contents.force_encoding("UTF-8"))
94
-
95
- # unwrap widgets
96
- doc.css("._typeloft_widget").each do |node|
97
-
98
- # remove unneeded attributes
99
- node.attributes.each do |key, attribute|
100
- node.attributes[key].remove if key != "style" and key != "class"
101
- end
102
-
103
- # clean up classes
104
- if not node.attributes["class"].nil?
105
- classList = node.attributes["class"].value.split(" ")
106
- classList.reject!{|cls| ["_typeloft_widget", "ui-resizable", "_typeloft_widget_selected", "_typeloft_widget_hover"].include?(cls)}
107
- node.attributes["class"].value = classList.join(" ")
108
- end
109
- end
110
-
111
- # remove scripts
112
- doc.css('script').remove()
113
-
114
- # unwrap drop containers
115
- doc.css("._typeloft_widget_drop_container").each do |node|
116
- node.children.each do |child|
117
- node.parent << child
118
- end
119
- node.remove
120
- end
121
-
122
- # remove data-typeloft-slug attributes
123
- doc.xpath( './/*[@data-typeloft-slug]|*[@data-typeloft-slug]' ).each do |node|
124
- node.attributes["data-typeloft-slug"].remove
125
- end
126
-
127
- # remove contenteditable attributes
128
- doc.xpath( './/*[@contenteditable]|*[@contenteditable]' ).each do |node|
129
- node.attributes["contenteditable"].remove
130
- end
131
-
132
- # remove widget containers
133
- doc.css("._typeloft_widget_container").remove()
134
-
135
- # remove typeloft classes
136
- doc.xpath(".//*[@*[contains(., '_typeloft_')]]").each do |node|
137
- classes = node[:class].split(' ').select{|cls| !cls.include?('_typeloft_')}
138
- node[:class] = classes.join(' ')
139
- end
140
-
141
- # convert iframe https links to http
142
- doc.search('iframe[src*="https://"]').each do |node|
143
- src = node[:src].sub('https://', 'http://')
144
- node[:src] = src
145
- end
146
-
147
- # fetch html
148
- clean_html_chars(doc.to_s)
149
- end
150
-
151
- def clean_html_chars(characters)
152
- ["\u1680", "\u180E", "\u2000", "\u2001", "\u2002", "\u2003", "\u2004", "\u2005", "\u2006", "\u2007", "\u2008", "\u2009", "\u200A", "\u200B", "\u202F", "\u205F", "\u3000", "\uFEFF"].each do |char|
153
- characters = characters.force_encoding("UTF-8").gsub(char, "&nbsp&nbsp")
154
- end
155
- characters.force_encoding("BINARY").gsub(0xC2.chr+0xA0.chr+" ","&nbsp;&nbsp;").gsub(0xC2.chr+0xA0.chr,"&nbsp;")
156
- end
157
- end
158
-
159
- class Server
160
- include Commander::Methods
161
- attr_accessor :port, :webrick
162
-
163
- def initialize(port=8080)
164
- self.port = port
165
-
166
- # create server
167
- self.webrick = WEBrick::HTTPServer.new(
168
- Port: self.port,
169
- DocumentRoot: "dist/",
170
- Logger: WEBrick::Log.new("/dev/null"),
171
- AccessLog: []
172
- )
173
-
174
- # Manifest JSON
175
- mount("/manifest.json") do |req, res|
176
- res.content_type = "application/json"
177
- res.body = build_manifest_json
178
- end
179
-
180
- self.webrick.mount "/issue", IssueServlet
181
- end
182
-
183
- def build_manifest_json
184
- manifest = []
185
- Dir.glob("dist/themes/*") do |dir|
186
- theme = File.basename(dir)
187
- config = theme_config(nil, theme)
188
- manifest.push({
189
- name: theme,
190
- title: config["name"],
191
- product_id: nil,
192
- info: config["description"],
193
- date: Time.now.strftime("%Y-%m-%d %H:%M:%S"),
194
- url: "http://127.0.0.1:#{self.port}/issue/#{theme}.hpub",
195
- cover: "http://127.0.0.1:#{self.port}/themes/#{theme}/thumbs/#{config["templates"][0]}.png"
196
- })
197
- end
198
- manifest.to_json
199
- end
200
-
201
- def mount(path, &block)
202
- self.webrick.mount_proc(path, &block)
203
- end
204
-
205
- def run!
206
- trap 'INT' do
207
- self.webrick.shutdown
208
- end
209
- self.webrick.start
210
- end
211
-
212
- end
213
- end
214
- end