sskatex 0.9.20
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 +7 -0
- data/COPYING +23 -0
- data/README.md +58 -0
- data/data/sskatex/js/escape_nonascii_html.js +12 -0
- data/data/sskatex/js/tex_to_html.js +15 -0
- data/lib/sskatex.rb +354 -0
- data/test/block/det.html +2 -0
- data/test/block/sup.html +1 -0
- data/test/span/det.html +2 -0
- data/test/span/sup.html +1 -0
- data/test/test_all.rb +34 -0
- data/test/tex/det.tex +2 -0
- data/test/tex/sup.tex +1 -0
- metadata +104 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3b5feb74566bcc5031cb615e5bacf5e795c6e465
|
4
|
+
data.tar.gz: a5163ab70c56af3d2aba6f7670883e5114348922
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7d3e59e7a9d7005779e656528c09714b50d27c5def895baa2dd97560003e22a2342059698359043c548e222dc2d8d23fde368ba97e206de0878798f3a70476fb
|
7
|
+
data.tar.gz: baa2384e98b60595061776f234fcc7be036c9ef51f2a586e294e9b3487f39d0d515cc0e7c48679e994558d78f00491ec09c8533956e4c7b386efc07522c9b5e7
|
data/COPYING
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
SsKaTeX - Server-side KaTeX for Ruby
|
2
|
+
(not including KaTeX itself)
|
3
|
+
MIT License
|
4
|
+
Copyright (C) 2017 Christian Cornelssen <ccorn@1tein.de>
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
7
|
+
copy of this software and associated documentation files (the
|
8
|
+
"Software"), to deal in the Software without restriction, including
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be included
|
15
|
+
in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
18
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
20
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
21
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
22
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
23
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# SsKaTeX
|
2
|
+
## Server-side KaTeX for Ruby
|
3
|
+
|
4
|
+
This is a TeX-to-HTML+MathML+CSS converter class using the Javascript-based
|
5
|
+
[KaTeX], interpreted by one of the Javascript engines supported by [ExecJS].
|
6
|
+
The intended purpose is to eliminate the need for math-rendering Javascript
|
7
|
+
in the client's HTML browser. Therefore the name: SsKaTeX means *server-side*
|
8
|
+
KaTeX.
|
9
|
+
|
10
|
+
Javascript execution context initialization can be done once and then reused
|
11
|
+
for formula renderings with the same general configuration. As a result, the
|
12
|
+
performance is reasonable. Consider this a fast and lightweight alternative to
|
13
|
+
[mathjax-node-cli].
|
14
|
+
|
15
|
+
Requirements for using SsKaTeX:
|
16
|
+
|
17
|
+
* Ruby gem [ExecJS],
|
18
|
+
* A Javascript engine supported by ExecJS, e.g. via one of
|
19
|
+
- Ruby gem [therubyracer],
|
20
|
+
- Ruby gem [therubyrhino],
|
21
|
+
- Ruby gem [duktape.rb],
|
22
|
+
- [Node.js],
|
23
|
+
* `katex.min.js` from [KaTeX].
|
24
|
+
|
25
|
+
Although the converter only needs `katex.min.js`, you may need to serve the
|
26
|
+
rest of the KaTeX package, that is, CSS and fonts, as resources to the
|
27
|
+
targeted web browsers. The upside is that your HTML templates need no longer
|
28
|
+
include Javascripts for Math (neither `katex.js` nor any search-and-replace
|
29
|
+
script). Your HTML templates should continue referencing the KaTeX CSS.
|
30
|
+
If you host your own copy of the CSS, also keep hosting the fonts.
|
31
|
+
|
32
|
+
Minimal usage example:
|
33
|
+
|
34
|
+
tex_to_html = SsKaTeX.new(katex_js: 'path-to-katex/katex.min.js')
|
35
|
+
# Here you could verify contents of tex_to_html.js_source for security...
|
36
|
+
|
37
|
+
body_html = '<p>By Pythagoras, %s. Furthermore:</p>' %
|
38
|
+
tex_to_html.call('a^2 + b^2 = c^2', false) # inline math
|
39
|
+
body_html << # block display
|
40
|
+
tex_to_html.call('\frac{1}{2} + \frac{1}{3} + \frac{1}{6} = 1', true)
|
41
|
+
# etc, etc.
|
42
|
+
|
43
|
+
More configuration options are described in the Rdoc. Most options, with the
|
44
|
+
notable exception of `katex_opts`, do not affect usage nor output, but may be
|
45
|
+
needed to make SsKaTeX work with all the external parts (JS engine and KaTeX).
|
46
|
+
Since KaTeX is distributed separately from the SsKaTeX gem, configuration of
|
47
|
+
the latter must support the specification of Javascript file locations. This
|
48
|
+
implies that execution of arbitrary Javascript code is possible. Specifically,
|
49
|
+
options with `js` in their names should be accepted from trusted sources only.
|
50
|
+
Applications using SsKaTeX need to check this.
|
51
|
+
|
52
|
+
[duktape.rb]: https://github.com/judofyr/duktape.rb#duktaperb
|
53
|
+
[ExecJS]: https://github.com/rails/execjs#execjs
|
54
|
+
[KaTeX]: https://khan.github.io/KaTeX/
|
55
|
+
[mathjax-node-cli]: https://github.com/mathjax/mathjax-node-cli
|
56
|
+
[Node.js]: https://nodejs.org/
|
57
|
+
[therubyracer]: https://github.com/cowboyd/therubyracer#therubyracer
|
58
|
+
[therubyrhino]: https://github.com/cowboyd/therubyrhino#therubyrhino
|
@@ -0,0 +1,12 @@
|
|
1
|
+
// -*- coding: utf-8 -*-
|
2
|
+
//
|
3
|
+
// Copyright (C) 2017 Christian Cornelssen <ccorn@1tein.de>
|
4
|
+
//
|
5
|
+
// This file is part of SsKaTeX which is licensed under the MIT.
|
6
|
+
|
7
|
+
// Transform non-ASCII characters and '\0' in given string to HTML numeric character references
|
8
|
+
function escape_nonascii_html(str) {
|
9
|
+
return str.replace(/[^\x01-\x7F]/g, function (u) {
|
10
|
+
return "&#x" + u.charCodeAt(0).toString(16) + ";";
|
11
|
+
});
|
12
|
+
};
|
@@ -0,0 +1,15 @@
|
|
1
|
+
// -*- coding: utf-8 -*-
|
2
|
+
//
|
3
|
+
// Copyright (C) 2017 Christian Cornelssen <ccorn@1tein.de>
|
4
|
+
//
|
5
|
+
// This file is part of SsKaTeX which is licensed under the MIT.
|
6
|
+
|
7
|
+
// Given a LaTeX math string, a boolean display_mode
|
8
|
+
// (true for block display, false for inline),
|
9
|
+
// and a dict katex_opts with general KaTeX options,
|
10
|
+
// return a string with corresponding HTML+MathML output.
|
11
|
+
// The implementation is allowed to set katex_opts.displayMode .
|
12
|
+
function tex_to_html(tex, display_mode, katex_opts) {
|
13
|
+
katex_opts.displayMode = display_mode;
|
14
|
+
return escape_nonascii_html(katex.renderToString(tex, katex_opts));
|
15
|
+
};
|
data/lib/sskatex.rb
ADDED
@@ -0,0 +1,354 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2017 Christian Cornelssen <ccorn@1tein.de>
|
5
|
+
#
|
6
|
+
# This file is part of SsKaTeX which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
|
9
|
+
require 'json'
|
10
|
+
|
11
|
+
# This is a TeX-to-HTML+MathML+CSS converter class using the Javascript-based
|
12
|
+
# KaTeX[https://khan.github.io/KaTeX/], interpreted by one of the Javascript
|
13
|
+
# engines supported by ExecJS[https://github.com/rails/execjs#execjs].
|
14
|
+
# The intended purpose is to eliminate the need for math-rendering Javascript
|
15
|
+
# in the client's HTML browser. Therefore the name: SsKaTeX means _server-side_
|
16
|
+
# KaTeX.
|
17
|
+
#
|
18
|
+
# Javascript execution context initialization can be done once and then reused
|
19
|
+
# for formula renderings with the same general configuration. As a result, the
|
20
|
+
# performance is reasonable. Consider this a fast and lightweight alternative to
|
21
|
+
# mathjax-node-cli[https://github.com/mathjax/mathjax-node-cli].
|
22
|
+
#
|
23
|
+
# Requirements for using SsKaTeX:
|
24
|
+
#
|
25
|
+
# - Ruby gem ExecJS[https://github.com/rails/execjs#execjs],
|
26
|
+
# - A Javascript engine supported by ExecJS, e.g. via one of
|
27
|
+
# - Ruby gem therubyracer[https://github.com/cowboyd/therubyracer#therubyracer],
|
28
|
+
# - Ruby gem therubyrhino[https://github.com/cowboyd/therubyrhino#therubyrhino],
|
29
|
+
# - Ruby gem duktape.rb[https://github.com/judofyr/duktape.rb#duktaperb],
|
30
|
+
# - Node.js[https://nodejs.org/],
|
31
|
+
# - +katex.min.js+ from KaTeX[https://khan.github.io/KaTeX/].
|
32
|
+
#
|
33
|
+
# Although the converter only needs +katex.min.js+, you may need to serve the
|
34
|
+
# rest of the KaTeX package, that is, CSS and fonts, as resources to the
|
35
|
+
# targeted web browsers. The upside is that your HTML templates need no longer
|
36
|
+
# include Javascripts for Math (neither +katex.js+ nor any search-and-replace
|
37
|
+
# script). Your HTML templates should continue referencing the KaTeX CSS.
|
38
|
+
# If you host your own copy of the CSS, also keep hosting the fonts.
|
39
|
+
#
|
40
|
+
# Minimal usage example:
|
41
|
+
#
|
42
|
+
# tex_to_html = SsKaTeX.new(katex_js: 'path-to-katex/katex.min.js')
|
43
|
+
# # Here you could verify contents of tex_to_html.js_source for security...
|
44
|
+
#
|
45
|
+
# body_html = '<p>By Pythagoras, %s. Furthermore:</p>' %
|
46
|
+
# tex_to_html.call('a^2 + b^2 = c^2', false) # inline math
|
47
|
+
# body_html << # block display
|
48
|
+
# tex_to_html.call('\frac{1}{2} + \frac{1}{3} + \frac{1}{6} = 1', true)
|
49
|
+
# # etc, etc.
|
50
|
+
#
|
51
|
+
# More configuration options are described in the Rdoc. Most options, with the
|
52
|
+
# notable exception of #katex_opts, do not affect usage nor output, but may be
|
53
|
+
# needed to make SsKaTeX work with all the external parts (JS engine and KaTeX).
|
54
|
+
# Since KaTeX is distributed separately from the SsKaTeX gem, configuration of
|
55
|
+
# the latter must support the specification of Javascript file locations. This
|
56
|
+
# implies that execution of arbitrary Javascript code is possible. Specifically,
|
57
|
+
# options with +js+ in their names should be accepted from trusted sources only.
|
58
|
+
# Applications using SsKaTeX need to check this.
|
59
|
+
class SsKaTeX
|
60
|
+
|
61
|
+
# Original value of the +EXECJS_RUNTIME+ environment variable, if any.
|
62
|
+
# Used when deferring ExecJS's engine auto-selection.
|
63
|
+
ENV_EXECJS_RUNTIME = ENV['EXECJS_RUNTIME']
|
64
|
+
begin
|
65
|
+
::ENV['EXECJS_RUNTIME'] = 'Disabled' # Defer automatic JS engine selection
|
66
|
+
require 'execjs'
|
67
|
+
ensure
|
68
|
+
::ENV['EXECJS_RUNTIME'] = ENV_EXECJS_RUNTIME
|
69
|
+
end
|
70
|
+
|
71
|
+
# Root directory for auxiliary files of this gem
|
72
|
+
DATADIR = File.expand_path(File.join(File.dirname(__FILE__),
|
73
|
+
'..', 'data', 'sskatex'))
|
74
|
+
|
75
|
+
# The default for the #js_dir configuration option.
|
76
|
+
# Path of a directory with Javascript helper files.
|
77
|
+
DEFAULT_JS_DIR = File.join(DATADIR, 'js')
|
78
|
+
|
79
|
+
# The default path to +katex.js+, cf. the #katex_js configuration option.
|
80
|
+
# For a relative path, the starting point is the current working directory.
|
81
|
+
DEFAULT_KATEX_JS = File.join('katex', 'katex.min.js')
|
82
|
+
|
83
|
+
# The default for the #js_libs configuration option.
|
84
|
+
# A list of UTF-8-encoded Javascript helper files to load.
|
85
|
+
# Relative paths are interpreted relative to #js_dir.
|
86
|
+
DEFAULT_JS_LIBS = ['escape_nonascii_html.js', 'tex_to_html.js']
|
87
|
+
|
88
|
+
# This is a module with miscellaneous utility functions needed by SsKaTeX.
|
89
|
+
module Utils
|
90
|
+
# Dictionary for escape sequences used in Javascript string literals
|
91
|
+
JS_ESCAPE = {
|
92
|
+
"\\" => "\\\\",
|
93
|
+
"\"" => "\\\"",
|
94
|
+
# Escaping single quotes not necessary in double-quoted string literals
|
95
|
+
#"'" => "\\'",
|
96
|
+
# JS does not recognize \a nor GNU's \e
|
97
|
+
# \b is ambiguous in regexps, as in Perl and Ruby
|
98
|
+
#"\b" => "\\b",
|
99
|
+
"\f" => "\\f",
|
100
|
+
"\n" => "\\n",
|
101
|
+
"\r" => "\\r",
|
102
|
+
"\t" => "\\t",
|
103
|
+
"\v" => "\\v",
|
104
|
+
}
|
105
|
+
private_constant :JS_ESCAPE
|
106
|
+
|
107
|
+
# ExecJS uses <tt>runtime = Runtimes.const_get(name)</tt> without checks.
|
108
|
+
# That is fragile and potentially insecure with arbitrary user input.
|
109
|
+
# Instead we use a fixed dictionary restricted to valid contents.
|
110
|
+
# Note that there are aliases like <tt>SpiderMonkey = Spidermonkey</tt>.
|
111
|
+
JSRUN_FROMSYM = {}.tap do |dict|
|
112
|
+
ExecJS::Runtimes.constants.each do |name|
|
113
|
+
runtime = ExecJS::Runtimes.const_get(name)
|
114
|
+
dict[name] = runtime if runtime.is_a?(ExecJS::Runtime)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Subclasses of +ExecJS::Runtime+ provide +.name+ (which is too verbose),
|
119
|
+
# but not, say, +.symbol+. This dictionary associates each JS runtime
|
120
|
+
# class with a representative symbol. For aliases like <tt>SpiderMonkey =
|
121
|
+
# Spidermonkey</tt>, an unspecified choice is made.
|
122
|
+
JSRUN_TOSYM = JSRUN_FROMSYM.invert
|
123
|
+
|
124
|
+
class << self # class-level methods
|
125
|
+
# Turn a string into an equivalent Javascript literal, double-quoted.
|
126
|
+
# Similar to +.to_json+, but escape all non-ASCII codes as well.
|
127
|
+
def js_quote(str)
|
128
|
+
# No portable way of escaping Unicode points above 0xFFFF
|
129
|
+
'"%s"' % str.encode(Encoding::UTF_8).
|
130
|
+
gsub(/[\0-\u{001F}\"\\\u{0080}-\u{FFFF}]/u) do |c|
|
131
|
+
JS_ESCAPE[c] || "\\u%04x" % c.ord
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# This should really be provided by +ExecJS::Runtimes+:
|
136
|
+
# A list of available JS engines, as symbols, in the order of preference.
|
137
|
+
def js_runtimes
|
138
|
+
ExecJS::Runtimes.runtimes.select(&:available?).map(&JSRUN_TOSYM)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Configuration dicts may contain keys in both string and symbol form.
|
142
|
+
# This bloats the output of +.to_json+ with duplicate key-value pairs.
|
143
|
+
# While this does not affect the result, it looks strange in logfiles.
|
144
|
+
# Therefore here is a function that recursively dedups dict keys,
|
145
|
+
# removing symbolic keys if there are corresponding string keys.
|
146
|
+
# Nondestructive.
|
147
|
+
def dedup_keys(conf)
|
148
|
+
# Lazy solution would be: JSON.parse(conf.to_json)
|
149
|
+
case conf
|
150
|
+
when Hash
|
151
|
+
conf.reject {|key, _| key.is_a?(Symbol) && conf.has_key?(key.to_s)}.
|
152
|
+
tap {|dict| dict.each {|key, value| dict[key] = dedup_keys(value)}}
|
153
|
+
when Array
|
154
|
+
conf.map {|value| dedup_keys(value)}
|
155
|
+
else
|
156
|
+
conf
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# This can be used for monitoring or debugging. When set to a
|
163
|
+
# proc {|level, &block| ...}
|
164
|
+
# the #logger will be used internally as
|
165
|
+
# logger.call(level) {msg}
|
166
|
+
# with the log message constructed in the given block. _level_ is one of:
|
167
|
+
#
|
168
|
+
# +:verbose+::
|
169
|
+
# For information about the effective engine configuration.
|
170
|
+
# Issued on first use of a changed configuration option.
|
171
|
+
# +:debug+::
|
172
|
+
# For the Javascript expressions used when converting TeX.
|
173
|
+
# Issued once per TeX snippet.
|
174
|
+
#
|
175
|
+
# For example, to ignore +:debug+ yet trace +:verbose+ messages, set
|
176
|
+
# .logger = lambda {|level, &block| warn(block.call) if level == :verbose}
|
177
|
+
# The default after construction is to log nothing.
|
178
|
+
attr_accessor :logger
|
179
|
+
|
180
|
+
# A dictionary with the used configuration options.
|
181
|
+
# The resulting effective option values can be read from the same-named
|
182
|
+
# attributes #katex_js, #katex_opts, #js_dir, #js_libs, #js_run.
|
183
|
+
# See also #config=.
|
184
|
+
def config
|
185
|
+
@config
|
186
|
+
end
|
187
|
+
|
188
|
+
# Reconfigure the conversion engine by passing in a dictionary, without
|
189
|
+
# affecting the #logger setting. Changes become effective on first use.
|
190
|
+
#
|
191
|
+
# Note: The dict will be shared by reference. Its deep object tree should
|
192
|
+
# remain unchanged at least until #js_context or #call has been invoked.
|
193
|
+
# Thereafter changes do not matter until #config= is assigned again.
|
194
|
+
def config=(cfg)
|
195
|
+
@js_context = nil
|
196
|
+
@js_source = nil
|
197
|
+
@katex_opts = nil
|
198
|
+
@katex_js = nil
|
199
|
+
@js_libs = nil
|
200
|
+
@js_dir = nil
|
201
|
+
@js_runtime = nil
|
202
|
+
@js_run = nil
|
203
|
+
@config = cfg
|
204
|
+
end
|
205
|
+
|
206
|
+
# Create a new instance configured with keyword arguments. Disable logging.
|
207
|
+
# The keyword arguments can be retrieved as dictionary #config, and the
|
208
|
+
# resulting effective option values can be read from the same-named attributes
|
209
|
+
# #katex_js, #katex_opts, #js_dir, #js_libs, #js_run.
|
210
|
+
def initialize(cfg = {})
|
211
|
+
@logger = lambda {|level, &block|}
|
212
|
+
self.config = cfg
|
213
|
+
end
|
214
|
+
|
215
|
+
# A symbol for the Javascript engine to be used. Recognized identifiers
|
216
|
+
# include: +:RubyRacer+, +:RubyRhino+, +:Duktape+, +:MiniRacer+, +:Node+,
|
217
|
+
# +:JavaScriptCore+, +:Spidermonkey+, +:JScript+, +:V8+, and +:Disabled+;
|
218
|
+
# that last one would raise an error on first run (by #js_context).
|
219
|
+
# Which engines are actually available depends on your installation.
|
220
|
+
#
|
221
|
+
# #js_run is determined on demand as follows and then cached for reuse.
|
222
|
+
# If #config[ +:js_run+ ] is not defined, the contents of the environment
|
223
|
+
# variable +EXECJS_RUNTIME+ will be considered instead; and if that is not
|
224
|
+
# defined, an automatic choice will be made. For more information, set the
|
225
|
+
# #logger to show +:verbose+ messages and consult the documentation of
|
226
|
+
# ExecJS[https://github.com/rails/execjs#execjs].
|
227
|
+
def js_run
|
228
|
+
@js_run ||= begin
|
229
|
+
log = lambda {|&block| @logger.call(:verbose, &block)}
|
230
|
+
|
231
|
+
log.call {"Available JS runtimes: #{Utils.js_runtimes.join(', ')}"}
|
232
|
+
jsrun = (@config[:js_run] ||
|
233
|
+
ENV_EXECJS_RUNTIME ||
|
234
|
+
Utils::JSRUN_TOSYM[ExecJS::Runtimes.best_available] ||
|
235
|
+
'Disabled').to_s.to_sym
|
236
|
+
log.call {"Selected JS runtime: #{jsrun}"}
|
237
|
+
jsrun
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# The +ExecJS::Runtime+ subclass to be used, corresponding to #js_run.
|
242
|
+
def js_runtime
|
243
|
+
@js_runtime ||= Utils::JSRUN_FROMSYM[js_run]
|
244
|
+
end
|
245
|
+
|
246
|
+
# The path to a directory with Javascript helper files as specified by
|
247
|
+
# #config[ +:js_dir+ ], or its default which is the subdirectory +js+ in the
|
248
|
+
# data directory of SsKaTeX. There is no need to change that setting unless
|
249
|
+
# you want to experiment with Javascript details.
|
250
|
+
def js_dir
|
251
|
+
@js_dir ||= @config[:js_dir] || DEFAULT_JS_DIR
|
252
|
+
end
|
253
|
+
|
254
|
+
# A list of UTF-8-encoded Javascript helper files to load.
|
255
|
+
# Can be overridden with #config[ +:js_libs+ ].
|
256
|
+
# Relative paths are interpreted relative to #js_dir.
|
257
|
+
# The default setting (in YAML notation) is
|
258
|
+
#
|
259
|
+
# js_libs:
|
260
|
+
# - escape_nonascii_html.js
|
261
|
+
# - tex_to_html.js
|
262
|
+
#
|
263
|
+
# And there is no need to change that unless you want to experiment with
|
264
|
+
# Javascript details.
|
265
|
+
#
|
266
|
+
# Files available in the default #js_dir are:
|
267
|
+
#
|
268
|
+
# +escape_nonascii_html.js+::
|
269
|
+
# defines a function +escape_nonascii_html+ that converts non-ASCII
|
270
|
+
# characters to HTML numeric character references.
|
271
|
+
# Intended as postprocessing filter.
|
272
|
+
# +tex_to_html.js+::
|
273
|
+
# defines a function +tex_to_html+(_tex_, _display_mode_, _katex_opts_)
|
274
|
+
# that takes a LaTeX math string, a boolean display mode (+true+ for block
|
275
|
+
# display, +false+ for inline), and a dict with general KaTeX options, and
|
276
|
+
# returns a string with corresponding HTML+MathML output. The implementation
|
277
|
+
# is allowed to set +katex_opts.displayMode+. SsKaTeX applies +tex_to_html+
|
278
|
+
# to each math fragment encountered.
|
279
|
+
# The implementation given here uses +katex.renderToString+ and
|
280
|
+
# postprocesses the output with +escape_nonascii_html+.
|
281
|
+
def js_libs
|
282
|
+
@js_libs ||= @config[:js_libs] || DEFAULT_JS_LIBS
|
283
|
+
end
|
284
|
+
|
285
|
+
# The path to your copy of +katex.min.js+ as specified by
|
286
|
+
# #config[ +:katex_js+ ] or its default <tt>'katex/katex.min.js'</tt>.
|
287
|
+
# For a relative path, the starting point is the current working directory.
|
288
|
+
def katex_js
|
289
|
+
@katex_js ||= @config[:katex_js] || DEFAULT_KATEX_JS
|
290
|
+
end
|
291
|
+
|
292
|
+
# A dictionary filled with the contents of #config[ +:katex_opts+ ] if given.
|
293
|
+
# These are general KaTeX options such as +throwOnError+, +errorColor+,
|
294
|
+
# +colorIsTextColor+, and +macros+. See the KaTeX
|
295
|
+
# documentation[https://github.com/Khan/KaTeX#rendering-options] for details.
|
296
|
+
# Use <tt>throwOnError: false</tt> if you want parse errors highlighted in the
|
297
|
+
# HTML output rather than raised as exceptions when compiling.
|
298
|
+
# Note that +displayMode+ is computed dynamically and should not be specified
|
299
|
+
# here. Keys can be symbols or strings; if a key is given in both forms, the
|
300
|
+
# symbol will be ignored.
|
301
|
+
def katex_opts
|
302
|
+
@katex_opts ||= Utils.dedup_keys(@config[:katex_opts] || {})
|
303
|
+
end
|
304
|
+
|
305
|
+
# The concatenation of the contents of the files in #js_libs, in #katex_js,
|
306
|
+
# and a JS variable definition for #katex_opts, each item followed by a
|
307
|
+
# newline. Created at first use. Can be used to validate JS contents if used
|
308
|
+
# before #js_context.
|
309
|
+
def js_source
|
310
|
+
@js_source ||= begin
|
311
|
+
log = lambda {|&block| @logger.call(:verbose, &block)}
|
312
|
+
|
313
|
+
# Concatenate sources
|
314
|
+
js = ''
|
315
|
+
js_libs.each do |libfile|
|
316
|
+
absfile = File.expand_path(libfile, js_dir)
|
317
|
+
log.call {"Loading JS file: #{absfile}"}
|
318
|
+
js << IO.read(absfile, external_encoding: Encoding::UTF_8) << "\n"
|
319
|
+
end
|
320
|
+
log.call {"Loading KaTeX JS file: #{katex_js}"}
|
321
|
+
js << IO.read(katex_js, external_encoding: Encoding::UTF_8) << "\n"
|
322
|
+
|
323
|
+
# Initialize JS variable katex_opts
|
324
|
+
js_katex_opts = "var katex_opts = #{katex_opts.to_json}"
|
325
|
+
log.call {"JS eval: #{js_katex_opts}"}
|
326
|
+
js << js_katex_opts << "\n"
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
# The JS engine context resulting from compilation of #js_source by the
|
331
|
+
# #js_runtime selected with #js_run. Created at first use e.g. by #call.
|
332
|
+
def js_context
|
333
|
+
@js_context ||= js_runtime.compile(js_source)
|
334
|
+
end
|
335
|
+
|
336
|
+
# Given a TeX math fragment _tex_ as well as a boolean _display_mode_ (true
|
337
|
+
# for block, false for inline), run the JS engine (using #js_context) and let
|
338
|
+
# KaTeX compile the math fragment. Return the resulting HTML string.
|
339
|
+
# Can raise errors if something in the process fails.
|
340
|
+
def call(tex, display_mode)
|
341
|
+
ctx = js_context
|
342
|
+
js = "tex_to_html(#{Utils.js_quote(tex)}, #{display_mode.to_json}, katex_opts)"
|
343
|
+
@logger.call(:debug) {"JS eval: #{js}"}
|
344
|
+
ans = ctx.eval(js)
|
345
|
+
raise (<<MSG) unless ans && ans.start_with?('<') && ans.end_with?('>')
|
346
|
+
KaTeX conversion failed!
|
347
|
+
Input:
|
348
|
+
#{tex}
|
349
|
+
Output:
|
350
|
+
#{ans}
|
351
|
+
MSG
|
352
|
+
ans
|
353
|
+
end
|
354
|
+
end
|
data/test/block/det.html
ADDED
@@ -0,0 +1,2 @@
|
|
1
|
+
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi mathvariant="normal">Δ</mi><mo>=</mo><mfrac><mrow><mn>1</mn></mrow><mrow><mn>2</mn></mrow></mfrac><mrow><mo fence="true">∣</mo><mtable><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>a</mi></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>b</mi></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>c</mi></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>d</mi></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>e</mi></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>f</mi></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>g</mi></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>h</mi></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>i</mi></mrow></mstyle></mtd></mtr></mtable><mo fence="true">∣</mo></mrow></mrow><annotation encoding="application/x-tex">\Delta = \frac{1}{2}
|
2
|
+
\begin{vmatrix}a & b & c \\ d & e & f \\ g & h & i\end{vmatrix}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:2.08597em;"></span><span class="strut bottom" style="height:3.636em;vertical-align:-1.5500299999999998em;"></span><span class="base"><span class="mord mathrm">Δ</span><span class="mrel">=</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathrm">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathrm">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="minner"><span class="mopen"><span class="delimsizing mult"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.08597em;"><span style="top:-1.05597em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-1.6619700000000002em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-2.26797em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-2.87397em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-3.47997em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-4.08597em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.5500299999999998em;"></span></span></span></span></span><span class="mord"><span class="mtable"><span class="col-align-c"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.05em;"><span style="top:-4.21em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit">a</span></span></span><span style="top:-3.0099999999999993em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit">d</span></span></span><span style="top:-1.8099999999999994em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit" style="margin-right:0.03588em;">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.5500000000000007em;"></span></span></span></span><span class="arraycolsep" style="width:0.5em;"></span><span class="arraycolsep" style="width:0.5em;"></span><span class="col-align-c"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.05em;"><span style="top:-4.21em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit">b</span></span></span><span style="top:-3.0099999999999993em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit">e</span></span></span><span style="top:-1.8099999999999994em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit">h</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.5500000000000007em;"></span></span></span></span><span class="arraycolsep" style="width:0.5em;"></span><span class="arraycolsep" style="width:0.5em;"></span><span class="col-align-c"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.05em;"><span style="top:-4.21em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit">c</span></span></span><span style="top:-3.0099999999999993em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit" style="margin-right:0.10764em;">f</span></span></span><span style="top:-1.8099999999999994em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.5500000000000007em;"></span></span></span></span></span></span><span class="mclose"><span class="delimsizing mult"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.08597em;"><span style="top:-1.05597em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-1.6619700000000002em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-2.26797em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-2.87397em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-3.47997em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-4.08597em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.5500299999999998em;"></span></span></span></span></span></span></span></span></span></span>
|
data/test/block/sup.html
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math><semantics><mrow><msup><mi>a</mi><mn>2</mn></msup><mo>+</mo><msup><mi>b</mi><mn>2</mn></msup><mo>=</mo><msup><mi>c</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">a^2+b^2=c^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.8641079999999999em;"></span><span class="strut bottom" style="height:0.9474379999999999em;vertical-align:-0.08333em;"></span><span class="base"><span class="mord"><span class="mord mathit">a</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathrm mtight">2</span></span></span></span></span></span></span></span><span class="mbin">+</span><span class="mord"><span class="mord mathit">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathrm mtight">2</span></span></span></span></span></span></span></span><span class="mrel">=</span><span class="mord"><span class="mord mathit">c</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathrm mtight">2</span></span></span></span></span></span></span></span></span></span></span></span>
|
data/test/span/det.html
ADDED
@@ -0,0 +1,2 @@
|
|
1
|
+
<span class="katex"><span class="katex-mathml"><math><semantics><mrow><mi mathvariant="normal">Δ</mi><mo>=</mo><mfrac><mrow><mn>1</mn></mrow><mrow><mn>2</mn></mrow></mfrac><mrow><mo fence="true">∣</mo><mtable><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>a</mi></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>b</mi></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>c</mi></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>d</mi></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>e</mi></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>f</mi></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>g</mi></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>h</mi></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="false"><mrow><mi>i</mi></mrow></mstyle></mtd></mtr></mtable><mo fence="true">∣</mo></mrow></mrow><annotation encoding="application/x-tex">\Delta = \frac{1}{2}
|
2
|
+
\begin{vmatrix}a & b & c \\ d & e & f \\ g & h & i\end{vmatrix}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:2.08597em;"></span><span class="strut bottom" style="height:3.636em;vertical-align:-1.5500299999999998em;"></span><span class="base"><span class="mord mathrm">Δ</span><span class="mrel">=</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathrm mtight">2</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathrm mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="minner"><span class="mopen"><span class="delimsizing mult"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.08597em;"><span style="top:-1.05597em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-1.6619700000000002em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-2.26797em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-2.87397em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-3.47997em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-4.08597em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.5500299999999998em;"></span></span></span></span></span><span class="mord"><span class="mtable"><span class="col-align-c"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.05em;"><span style="top:-4.21em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit">a</span></span></span><span style="top:-3.0099999999999993em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit">d</span></span></span><span style="top:-1.8099999999999994em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit" style="margin-right:0.03588em;">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.5500000000000007em;"></span></span></span></span><span class="arraycolsep" style="width:0.5em;"></span><span class="arraycolsep" style="width:0.5em;"></span><span class="col-align-c"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.05em;"><span style="top:-4.21em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit">b</span></span></span><span style="top:-3.0099999999999993em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit">e</span></span></span><span style="top:-1.8099999999999994em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit">h</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.5500000000000007em;"></span></span></span></span><span class="arraycolsep" style="width:0.5em;"></span><span class="arraycolsep" style="width:0.5em;"></span><span class="col-align-c"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.05em;"><span style="top:-4.21em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit">c</span></span></span><span style="top:-3.0099999999999993em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit" style="margin-right:0.10764em;">f</span></span></span><span style="top:-1.8099999999999994em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathit">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.5500000000000007em;"></span></span></span></span></span></span><span class="mclose"><span class="delimsizing mult"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.08597em;"><span style="top:-1.05597em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-1.6619700000000002em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-2.26797em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-2.87397em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-3.47997em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span><span style="top:-4.08597em;"><span class="pstrut" style="height:2.606em;"></span><span class="delimsizinginner delim-size1"><span>∣</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.5500299999999998em;"></span></span></span></span></span></span></span></span></span>
|
data/test/span/sup.html
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
<span class="katex"><span class="katex-mathml"><math><semantics><mrow><msup><mi>a</mi><mn>2</mn></msup><mo>+</mo><msup><mi>b</mi><mn>2</mn></msup><mo>=</mo><msup><mi>c</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">a^2+b^2=c^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="strut" style="height:0.8141079999999999em;"></span><span class="strut bottom" style="height:0.897438em;vertical-align:-0.08333em;"></span><span class="base"><span class="mord"><span class="mord mathit">a</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathrm mtight">2</span></span></span></span></span></span></span></span><span class="mbin">+</span><span class="mord"><span class="mord mathit">b</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathrm mtight">2</span></span></span></span></span></span></span></span><span class="mrel">=</span><span class="mord"><span class="mord mathit">c</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathrm mtight">2</span></span></span></span></span></span></span></span></span></span></span>
|
data/test/test_all.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2017 Christian Cornelssen <ccorn@1tein.de>
|
5
|
+
#
|
6
|
+
# This file is part of SsKaTeX which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
|
9
|
+
require 'minitest/autorun'
|
10
|
+
require 'sskatex'
|
11
|
+
|
12
|
+
class SsKaTeXTest < Minitest::Test
|
13
|
+
def setup
|
14
|
+
@tex2html = SsKaTeX.new
|
15
|
+
@tex2html.logger = lambda do |level, &block|
|
16
|
+
# warn(block.call) if level == :verbose
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
TESTDIR = File.dirname(__FILE__)
|
21
|
+
|
22
|
+
# Generate test methods
|
23
|
+
Dir[File.join(TESTDIR, 'tex', '*.tex')].each do |f|
|
24
|
+
testcase = File.basename(f, '.tex').tr('^a-zA-Z0-9_', '_')
|
25
|
+
['block', 'span'].each do |mode|
|
26
|
+
define_method("test_#{testcase}_#{mode}") do
|
27
|
+
tex = IO.read(f, external_encoding: Encoding::UTF_8).chomp
|
28
|
+
html = IO.read(File.join(TESTDIR, mode, testcase) + '.html',
|
29
|
+
external_encoding: Encoding::UTF_8).chomp
|
30
|
+
assert_equal @tex2html.call(tex, mode == 'block'), html
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/test/tex/det.tex
ADDED
data/test/tex/sup.tex
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
a^2+b^2=c^2
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sskatex
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.20
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Christian Cornelssen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-11-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: execjs
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.7'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: duktape
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 1.6.1
|
37
|
+
type: :development
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '1.6'
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 1.6.1
|
47
|
+
description: |
|
48
|
+
This is a TeX-to-HTML+MathML+CSS converter class using the Javascript-based
|
49
|
+
KaTeX, interpreted by one of the Javascript engines supported by ExecJS.
|
50
|
+
The intended purpose is to eliminate the need for math-rendering Javascript
|
51
|
+
in the client's HTML browser. Therefore the name: SsKaTeX means Server-side
|
52
|
+
KaTeX.
|
53
|
+
|
54
|
+
Javascript execution context initialization can be done once and then reused
|
55
|
+
for formula renderings with the same general configuration. As a result, the
|
56
|
+
performance is reasonable.
|
57
|
+
|
58
|
+
The configuration supports arbitrary locations of the external file katex.min.js
|
59
|
+
as well as custom Javascript for pre- and postprocessing.
|
60
|
+
For that reason, the configuration must not be left to untrusted users.
|
61
|
+
email: ccorn@1tein.de
|
62
|
+
executables: []
|
63
|
+
extensions: []
|
64
|
+
extra_rdoc_files: []
|
65
|
+
files:
|
66
|
+
- COPYING
|
67
|
+
- README.md
|
68
|
+
- data/sskatex/js/escape_nonascii_html.js
|
69
|
+
- data/sskatex/js/tex_to_html.js
|
70
|
+
- lib/sskatex.rb
|
71
|
+
- test/block/det.html
|
72
|
+
- test/block/sup.html
|
73
|
+
- test/span/det.html
|
74
|
+
- test/span/sup.html
|
75
|
+
- test/test_all.rb
|
76
|
+
- test/tex/det.tex
|
77
|
+
- test/tex/sup.tex
|
78
|
+
homepage: https://github.com/ccorn/sskatex
|
79
|
+
licenses:
|
80
|
+
- MIT
|
81
|
+
metadata: {}
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options:
|
84
|
+
- "-a"
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '2.0'
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
requirements:
|
98
|
+
- Javascript engine supported by the ExecJS gem
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 2.6.11
|
101
|
+
signing_key:
|
102
|
+
specification_version: 4
|
103
|
+
summary: Server-side KaTeX for Ruby
|
104
|
+
test_files: []
|