mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-31 14:33:54 -04:00
Move the comments editor into its own iframe
This commit is contained in:
parent
1c909c7a6d
commit
01eebe0857
@ -2,55 +2,152 @@
|
|||||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
from __python__ import bound_methods, hash_literals
|
from __python__ import bound_methods, hash_literals
|
||||||
|
|
||||||
|
from elementmaker import E
|
||||||
|
from gettext import gettext as _
|
||||||
|
|
||||||
from elementmaker import maker_for_document
|
from dom import clear, ensure_id
|
||||||
|
from iframe_comm import IframeClient, IframeWrapper
|
||||||
|
|
||||||
|
|
||||||
class CommentsEditorBoss:
|
class CommentsEditorBoss:
|
||||||
pass
|
|
||||||
|
def __init__(self):
|
||||||
|
handlers = {
|
||||||
|
'initialize': self.initialize,
|
||||||
|
'set_html': self.set_html,
|
||||||
|
'get_html': self.get_html,
|
||||||
|
}
|
||||||
|
self.comm = IframeClient(handlers)
|
||||||
|
|
||||||
|
def initialize(self, data):
|
||||||
|
window.onerror = self.onerror
|
||||||
|
clear(document.body)
|
||||||
|
document.body.style.margin = '0'
|
||||||
|
document.body.style.padding = '0'
|
||||||
|
document.documentElement.style.height = document.body.style.height = '100%'
|
||||||
|
document.documentElement.style.overflow = document.body.style.overflow = 'hidden'
|
||||||
|
document.body.style.fontFamily = window.default_font_family
|
||||||
|
document.body.appendChild(E.div(style='width: 100%; height: 100%; padding: 0; margin: 0; border: solid 3px transparent; box-sizing: border-box'))
|
||||||
|
document.body.lastChild.contentEditable = True
|
||||||
|
document.body.lastChild.focus()
|
||||||
|
|
||||||
|
def onerror(self, msg, script_url, line_number, column_number, error_object):
|
||||||
|
if error_object is None:
|
||||||
|
# This happens for cross-domain errors (probably javascript injected
|
||||||
|
# into the browser via extensions/ userscripts and the like). It also
|
||||||
|
# happens all the time when using Chrome on Safari
|
||||||
|
console.log(f'Unhandled error from external javascript, ignoring: {msg} {script_url} {line_number}')
|
||||||
|
else:
|
||||||
|
console.log(error_object)
|
||||||
|
|
||||||
|
def set_html(self, data):
|
||||||
|
document.body.lastChild.innerHTML = data.html
|
||||||
|
|
||||||
|
def get_html(self, data):
|
||||||
|
self.comm.send_message('html', html=document.body.lastChild.innerHTML)
|
||||||
|
|
||||||
|
|
||||||
|
registry = {}
|
||||||
|
|
||||||
|
def add_editor(editor):
|
||||||
|
for k in Object.keys(registry):
|
||||||
|
if not document.getElementById(k):
|
||||||
|
v'delete registry[k]'
|
||||||
|
registry[editor.id] = editor
|
||||||
|
|
||||||
|
|
||||||
|
class Editor:
|
||||||
|
|
||||||
|
def __init__(self, iframe):
|
||||||
|
handlers = {
|
||||||
|
'ready': self.on_iframe_ready,
|
||||||
|
'html': self.on_html_received,
|
||||||
|
}
|
||||||
|
self.iframe_wrapper = IframeWrapper(handlers, iframe, 'book_list.comments_editor', _('Loading comments editor...'))
|
||||||
|
self.id = ensure_id(iframe)
|
||||||
|
self.ready = False
|
||||||
|
self.pending_set_html = None
|
||||||
|
self.get_html_callbacks = v'[]'
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
self.iframe_wrapper.init()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def iframe(self):
|
||||||
|
return self.iframe_wrapper.iframe
|
||||||
|
|
||||||
|
def on_iframe_ready(self, msg):
|
||||||
|
self.ready = True
|
||||||
|
return self.after_iframe_initialized
|
||||||
|
|
||||||
|
def after_iframe_initialized(self):
|
||||||
|
if self.pending_set_html is not None:
|
||||||
|
self.set_html(self.pending_set_html)
|
||||||
|
self.pending_set_html = None
|
||||||
|
if self.get_html_callbacks.length:
|
||||||
|
self.get_html(self.get_html_callback)
|
||||||
|
|
||||||
|
def set_html(self, html):
|
||||||
|
if not self.ready:
|
||||||
|
self.pending_set_html = html
|
||||||
|
return
|
||||||
|
self.iframe_wrapper.send_message('set_html', html=html)
|
||||||
|
|
||||||
|
def get_html(self, proceed):
|
||||||
|
self.get_html_callbacks.push(proceed)
|
||||||
|
if self.ready:
|
||||||
|
self.iframe_wrapper.send_message('get_html')
|
||||||
|
|
||||||
|
def on_html_received(self, data):
|
||||||
|
if self.get_html_callbacks.length:
|
||||||
|
for f in self.get_html_callbacks:
|
||||||
|
f(data.html)
|
||||||
|
self.get_html_callbacks = v'[]'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def create_editor():
|
||||||
|
iframe = E.iframe(sandbox='allow-scripts', seamless=True, style='flex-grow: 10', id=self.id)
|
||||||
|
editor = Editor(iframe)
|
||||||
|
add_editor(editor)
|
||||||
|
return iframe, editor
|
||||||
|
|
||||||
|
|
||||||
def create_comments_editor(container):
|
def create_comments_editor(container):
|
||||||
ans = window.document.createElement('iframe')
|
iframe, editor = create_editor()
|
||||||
ans.setAttribute('sandbox', 'allow-scripts')
|
toolbar1 = E.div(style='flex-grow: 0')
|
||||||
ans.setAttribute('seamless', '')
|
container.setAttribute('style', (container.getAttribute('style') or '') + ';display: flex; flex-direction: column; align-items: stretch')
|
||||||
ans.style.width = '100%'
|
container.appendChild(toolbar1)
|
||||||
container.appendChild(ans)
|
container.appendChild(iframe)
|
||||||
document = ans.contentWindow.document
|
return editor
|
||||||
E = maker_for_document(document)
|
|
||||||
toolbar1 = E.div(style='flex-grow: 1')
|
|
||||||
content = E.div(class_='content', style='flex-grow: 10')
|
|
||||||
content.onkeydown = def(evt):
|
|
||||||
evt.preventDefault()
|
|
||||||
content.contentEditable = True
|
|
||||||
document.body.appendChild(E.div(
|
|
||||||
style='display: flex; flex-direction: column; align-items: stretch',
|
|
||||||
toolbar1, content
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def focus_comments_editor(container):
|
def focus_comments_editor(container):
|
||||||
iframe = container.querySelector('iframe')
|
iframe = container.querySelector('iframe')
|
||||||
document = iframe.contentWindow.document
|
|
||||||
document.querySelector('.content').focus()
|
|
||||||
iframe.contentWindow.focus()
|
iframe.contentWindow.focus()
|
||||||
|
|
||||||
|
|
||||||
def set_comments_html(container, html):
|
def set_comments_html(container, html):
|
||||||
iframe = container.querySelector('iframe')
|
iframe = container.querySelector('iframe')
|
||||||
document = iframe.contentWindow.document
|
eid = iframe.getAttribute('id')
|
||||||
document.querySelector('.content').innerHTML = html
|
editor = registry[eid]
|
||||||
|
editor.set_html(html or '')
|
||||||
|
|
||||||
|
|
||||||
def get_comments_html(container):
|
def get_comments_html(container, proceed):
|
||||||
iframe = container.querySelector('iframe')
|
iframe = container.querySelector('iframe')
|
||||||
document = iframe.contentWindow.document
|
eid = iframe.getAttribute('id')
|
||||||
return document.querySelector('.content').innerHTML
|
editor = registry[eid]
|
||||||
|
editor.get_html(proceed)
|
||||||
|
|
||||||
|
|
||||||
def develop(container):
|
def develop(container):
|
||||||
container.setAttribute('style', 'width: 100%; min-height: 90vh; display: flex; flex-direction: column; align-items: stretch')
|
container.setAttribute('style', 'width: 100%; min-height: 90vh; display: flex; flex-direction: column; align-items: stretch')
|
||||||
create_comments_editor(container)
|
editor = create_comments_editor(container)
|
||||||
set_comments_html(container, '<p>Testing, <i>testing</i> 123...')
|
set_comments_html(container, '<p>Testing, <i>testing</i> 123...')
|
||||||
focus_comments_editor(container)
|
focus_comments_editor(container)
|
||||||
|
editor.init()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
main.boss = CommentsEditorBoss()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user