mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Back to loading mathjax via blob urls
Fucking stupid Content Security Policy
This commit is contained in:
parent
8d27d68dff
commit
bd99a17186
58
src/calibre/gui2/viewer2/mathjax.py
Normal file
58
src/calibre/gui2/viewer2/mathjax.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||||
|
|
||||||
|
PATCHED_MATHJAX = '''
|
||||||
|
|
||||||
|
function postprocess_mathjax(link_uid) {
|
||||||
|
Array.prototype.forEach.call(document.getElementsByTagName('a'), function(a) {
|
||||||
|
var href = a.getAttribute('href');
|
||||||
|
if (href && href.startsWith('#')) {
|
||||||
|
a.setAttribute('href', 'javascript: void(0)')
|
||||||
|
a.setAttribute('data-' + link_uid, JSON.stringify({'frag':href.slice(1)}))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.documentElement.dispatchEvent(new CustomEvent("calibre-mathjax-init-done"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function monkeypatch(mathjax_files) {
|
||||||
|
var orig = window.MathJax.Ajax.fileURL.bind(window.MathJax.Ajax);
|
||||||
|
|
||||||
|
window.MathJax.Ajax.fileURL = function(mathjax_name) {
|
||||||
|
var ans = orig(mathjax_name);
|
||||||
|
var name = ans.replace(/^\\//g, '');
|
||||||
|
if (name.startsWith('../fonts')) name = name.slice(3);
|
||||||
|
ans = mathjax_files[name];
|
||||||
|
if (!ans) ans = '';
|
||||||
|
if (typeof ans !== 'string') {
|
||||||
|
mathjax_files[name] = window.URL.createObjectURL(ans);
|
||||||
|
ans = mathjax_files[name];
|
||||||
|
}
|
||||||
|
if (ans === name && !name.startsWith('blob:')) {
|
||||||
|
if (ans.endsWith('.eot') || ans.endsWith('.otf')) return '';
|
||||||
|
console.log('WARNING: Failed to resolve MathJax file: ' + mathjax_name);
|
||||||
|
}
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
window.MathJax.Ajax.fileRev = function(mathjax_name) { return ''; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function init_mathjax(link_uid, mathjax_files) {
|
||||||
|
monkeypatch(mathjax_files);
|
||||||
|
window.MathJax.Hub.Register.StartupHook("End", postprocess_mathjax.bind(this, link_uid))
|
||||||
|
}
|
||||||
|
|
||||||
|
document.documentElement.addEventListener("calibre-mathjax-init", function(ev) {
|
||||||
|
|
||||||
|
window.MathJax = ev.detail.MathJax;
|
||||||
|
window.MathJax.AuthorInit = init_mathjax.bind(this, ev.detail.link_uid, ev.detail.mathjax_files);
|
||||||
|
|
||||||
|
__SRC__
|
||||||
|
});
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def monkeypatch_mathjax(src):
|
||||||
|
return PATCHED_MATHJAX.replace('__SRC__', src, 1)
|
@ -62,7 +62,7 @@ class UrlSchemeHandler(QWebEngineUrlSchemeHandler):
|
|||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QWebEngineUrlSchemeHandler.__init__(self, parent)
|
QWebEngineUrlSchemeHandler.__init__(self, parent)
|
||||||
self.mathjax_tdir = None
|
self.mathjax_tdir = self.mathjax_manifest = None
|
||||||
|
|
||||||
def requestStarted(self, rq):
|
def requestStarted(self, rq):
|
||||||
if bytes(rq.requestMethod()) != b'GET':
|
if bytes(rq.requestMethod()) != b'GET':
|
||||||
@ -99,16 +99,28 @@ class UrlSchemeHandler(QWebEngineUrlSchemeHandler):
|
|||||||
data = b'[' + manifest + b',' + metadata + b']'
|
data = b'[' + manifest + b',' + metadata + b']'
|
||||||
self.send_reply(rq, mime_type, data)
|
self.send_reply(rq, mime_type, data)
|
||||||
elif name.startswith('mathjax/'):
|
elif name.startswith('mathjax/'):
|
||||||
|
from calibre.gui2.viewer2.mathjax import monkeypatch_mathjax
|
||||||
|
if name == 'mathjax/manifest.json':
|
||||||
if self.mathjax_tdir is None:
|
if self.mathjax_tdir is None:
|
||||||
|
import json
|
||||||
from calibre.srv.books import get_mathjax_manifest
|
from calibre.srv.books import get_mathjax_manifest
|
||||||
self.mathjax_tdir = PersistentTemporaryDirectory(prefix='v2mjx-')
|
self.mathjax_tdir = PersistentTemporaryDirectory(prefix='v2mjx-')
|
||||||
get_mathjax_manifest(self.mathjax_tdir)
|
self.mathjax_manifest = json.dumps(get_mathjax_manifest(self.mathjax_tdir)['files'])
|
||||||
|
self.send_reply(rq, 'application/json', self.mathjax_manifest)
|
||||||
|
return
|
||||||
path = os.path.abspath(os.path.join(self.mathjax_tdir, name))
|
path = os.path.abspath(os.path.join(self.mathjax_tdir, name))
|
||||||
if path.startswith(self.mathjax_tdir):
|
if path.startswith(self.mathjax_tdir):
|
||||||
mt = guess_type(name)
|
mt = guess_type(name)
|
||||||
|
try:
|
||||||
with lopen(path, 'rb') as f:
|
with lopen(path, 'rb') as f:
|
||||||
raw = f.read()
|
raw = f.read()
|
||||||
|
except EnvironmentError as err:
|
||||||
|
prints("Failed to get mathjax file: {} with error: {}".format(name, err))
|
||||||
|
rq.fail(rq.RequestFailed)
|
||||||
|
return
|
||||||
|
if 'MathJax.js' in name:
|
||||||
|
raw = monkeypatch_mathjax(raw.decode('utf-8')).encode('utf-8')
|
||||||
|
|
||||||
self.send_reply(rq, mt, raw)
|
self.send_reply(rq, mt, raw)
|
||||||
|
|
||||||
def send_reply(self, rq, mime_type, data):
|
def send_reply(self, rq, mime_type, data):
|
||||||
|
@ -15,6 +15,7 @@ def get_url(mathjax_files, name):
|
|||||||
ans = mathjax_files[name] = window.URL.createObjectURL(ans)
|
ans = mathjax_files[name] = window.URL.createObjectURL(ans)
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
def monkeypatch(mathjax_files):
|
def monkeypatch(mathjax_files):
|
||||||
StyleString = window.MathJax.Ajax.StyleString.bind(window.MathJax.Ajax)
|
StyleString = window.MathJax.Ajax.StyleString.bind(window.MathJax.Ajax)
|
||||||
|
|
||||||
@ -72,7 +73,18 @@ def apply_mathjax(mathjax_files, link_uid, proceed):
|
|||||||
script = E.script(type='text/javascript')
|
script = E.script(type='text/javascript')
|
||||||
document.head.appendChild(script)
|
document.head.appendChild(script)
|
||||||
if runtime.is_standalone_viewer:
|
if runtime.is_standalone_viewer:
|
||||||
script.src = f'{runtime.FAKE_PROTOCOL}://{runtime.FAKE_HOST}/mathjax/MathJax.js'
|
script.onload = def():
|
||||||
|
ev = new CustomEvent("calibre-mathjax-init", {
|
||||||
|
'detail': {
|
||||||
|
'MathJax': m,
|
||||||
|
'link_uid': link_uid,
|
||||||
|
'mathjax_files': mathjax_files,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
document.documentElement.dispatchEvent(ev)
|
||||||
|
document.documentElement.addEventListener("calibre-mathjax-init-done", def(ev):
|
||||||
|
proceed()
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
m.AuthorInit = init_mathjax.bind(this, mathjax_files, link_uid, proceed)
|
m.AuthorInit = init_mathjax.bind(this, mathjax_files, link_uid, proceed)
|
||||||
script.src = get_url(mathjax_files, 'MathJax.js')
|
script.src = get_url(mathjax_files, 'MathJax.js')
|
||||||
|
@ -168,7 +168,7 @@ class View:
|
|||||||
'human_scroll': self.on_human_scroll,
|
'human_scroll': self.on_human_scroll,
|
||||||
}
|
}
|
||||||
entry_point = None if runtime.is_standalone_viewer else 'read_book.iframe'
|
entry_point = None if runtime.is_standalone_viewer else 'read_book.iframe'
|
||||||
self.iframe_wrapper = IframeWrapper(handlers, document.getElementById(iframe_id), entry_point, _('Bootstrapping book reader...'))
|
self.iframe_wrapper = IframeWrapper(handlers, document.getElementById(iframe_id), entry_point, _('Bootstrapping book reader...'), runtime.FAKE_PROTOCOL, runtime.FAKE_HOST)
|
||||||
self.search_overlay = SearchOverlay(self)
|
self.search_overlay = SearchOverlay(self)
|
||||||
self.content_popup_overlay = ContentPopupOverlay(self)
|
self.content_popup_overlay = ContentPopupOverlay(self)
|
||||||
self.overlay = Overlay(self)
|
self.overlay = Overlay(self)
|
||||||
|
@ -59,9 +59,57 @@ def get_file(book, name, proceed):
|
|||||||
xhr.responseType = 'blob'
|
xhr.responseType = 'blob'
|
||||||
xhr.send()
|
xhr.send()
|
||||||
|
|
||||||
|
def mathjax_file_received(name, proceed, end_type, xhr, ev):
|
||||||
|
if end_type is 'abort':
|
||||||
|
return
|
||||||
|
if end_type is not 'load':
|
||||||
|
show_error(_('Failed to load MathJax file'), _(
|
||||||
|
'Could not load the file: {} with error: {}').format(name, xhr.error_html))
|
||||||
|
return
|
||||||
|
if not xhr.responseType or xhr.responseType is 'text':
|
||||||
|
result = xhr.responseText
|
||||||
|
else if xhr.responseType is 'blob' or xhr.responseType is 'json':
|
||||||
|
result = xhr.response
|
||||||
|
else:
|
||||||
|
show_error(_('Failed to load MathJax file'), _(
|
||||||
|
'Could not load the file: {} unknown response type: {}')
|
||||||
|
.format(name, xhr.responseType))
|
||||||
|
return
|
||||||
|
if name is 'manifest.json':
|
||||||
|
get_mathjax_files.manifest = result
|
||||||
|
get_mathjax_files_stage2.files_to_get = list(Object.keys(result))
|
||||||
|
get_mathjax_files_stage2.file_data = {}
|
||||||
|
get_mathjax_files_stage2(proceed)
|
||||||
|
return
|
||||||
|
|
||||||
|
get_mathjax_files_stage2.file_data[name] = result
|
||||||
|
get_mathjax_files_stage2.files_to_get.remove(name)
|
||||||
|
if not get_mathjax_files_stage2.files_to_get.length:
|
||||||
|
proceed(get_mathjax_files_stage2.file_data)
|
||||||
|
|
||||||
|
def get_mathjax_manifest(proceed):
|
||||||
|
xhr = ajax('mathjax/manifest.json', mathjax_file_received.bind(None, 'manifest.json', proceed), ok_code=0)
|
||||||
|
xhr.responseType = 'json'
|
||||||
|
xhr.send()
|
||||||
|
|
||||||
|
|
||||||
|
def get_mathjax_files_stage2(proceed):
|
||||||
|
if not get_mathjax_files_stage2.files_to_get.length:
|
||||||
|
proceed(get_mathjax_files_stage2.file_data)
|
||||||
|
return
|
||||||
|
for filename in get_mathjax_files_stage2.files_to_get:
|
||||||
|
xhr = ajax(f'mathjax/{filename}', mathjax_file_received.bind(None, filename, proceed), ok_code=0)
|
||||||
|
xhr.responseType = 'blob'
|
||||||
|
xhr.send()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_mathjax_files(proceed):
|
def get_mathjax_files(proceed):
|
||||||
proceed({})
|
if not get_mathjax_files.manifest:
|
||||||
|
get_mathjax_manifest(proceed)
|
||||||
|
else:
|
||||||
|
get_mathjax_files_stage2(proceed)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def update_url_state(replace):
|
def update_url_state(replace):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user