diff --git a/frontend/apps/reader/modules/readerhighlight.lua b/frontend/apps/reader/modules/readerhighlight.lua index 13775e030..a3a1574df 100644 --- a/frontend/apps/reader/modules/readerhighlight.lua +++ b/frontend/apps/reader/modules/readerhighlight.lua @@ -8,6 +8,7 @@ local TimeVal = require("ui/timeval") local UIManager = require("ui/uimanager") local logger = require("logger") local _ = require("gettext") +local T = require("ffi/util").template local ReaderHighlight = InputContainer:new{} @@ -380,6 +381,78 @@ function ReaderHighlight:lookup(selected_word, selected_link) end end +function ReaderHighlight:viewSelectionHTML(debug_view) + if self.ui.document.info.has_pages then + return + end + if self.selected_text and self.selected_text.pos0 and self.selected_text.pos1 then + -- For available flags, see the "#define WRITENODEEX_*" in crengine/src/lvtinydom.cpp + local html_flags = 0x3030 -- valid and classic displayed HTML, with only block nodes indented + if debug_view then + -- Each node on a line, with markers and numbers of skipped chars and siblings shown, + -- with possibly invalid HTML (text nodes not escaped) + html_flags = 0x3353 + end + local html, css_files = self.ui.document:getHTMLFromXPointers(self.selected_text.pos0, + self.selected_text.pos1, html_flags, true) + if html then + -- Make some invisible chars visible + if debug_view then + html = html:gsub("\xC2\xA0", "␣") -- no break space: open box + html = html:gsub("\xC2\xAD", "⋅") -- soft hyphen: dot operator (smaller than middle dot ·) + end + local TextViewer = require("ui/widget/textviewer") + local Font = require("ui/font") + local textviewer + local buttons_table = {} + if css_files then + for i=1, #css_files do + local button = { + text = T(_("View %1"), css_files[i]), + callback = function() + local css_text = self.ui.document:getDocumentFileContent(css_files[i]) + local cssviewer = TextViewer:new{ + title = css_files[i], + text = css_text or _("Failed getting CSS content"), + text_face = Font:getFace("smallinfont"), + justified = false, + } + UIManager:show(cssviewer) + end, + } + -- One button per row, too make room for the possibly long css filename + table.insert(buttons_table, {button}) + end + end + table.insert(buttons_table, {{ + text = debug_view and _("Switch to standard view") or _("Switch to debug view"), + callback = function() + UIManager:close(textviewer) + self:viewSelectionHTML(not debug_view) + end, + }}) + table.insert(buttons_table, {{ + text = _("Close"), + callback = function() + UIManager:close(textviewer) + end, + }}) + textviewer = TextViewer:new{ + title = _("Selection HTML"), + text = html, + text_face = Font:getFace("smallinfont"), + justified = false, + buttons_table = buttons_table, + } + UIManager:show(textviewer) + else + UIManager:show(InfoMessage:new{ + text = _("Failed getting HTML for selection"), + }) + end + end +end + function ReaderHighlight:translate(selected_text) if selected_text.text ~= "" then self.ui:handleEvent(Event:new("TranslateText", self, selected_text.text)) @@ -438,6 +511,14 @@ function ReaderHighlight:onHoldRelease() Device.input.setClipboardText(self.selected_text.text) end, }, + { + text = _("View HTML"), + enabled = not self.ui.document.info.has_pages, + callback = function() + self:viewSelectionHTML() + end, + }, + --[[ { text = _("Translate"), enabled = false, @@ -446,6 +527,7 @@ function ReaderHighlight:onHoldRelease() self:onClose() end, }, + --]] }, { { diff --git a/frontend/document/credocument.lua b/frontend/document/credocument.lua index 718b02b0e..c2a619f69 100644 --- a/frontend/document/credocument.lua +++ b/frontend/document/credocument.lua @@ -367,6 +367,30 @@ function CreDocument:getLinkFromPosition(pos) return self._document:getLinkFromPosition(pos.x, pos.y) end +function CreDocument:getDocumentFileContent(filepath) + if filepath then + return self._document:getDocumentFileContent(filepath) + end +end + +function CreDocument:getTextFromXPointer(xp) + if xp then + return self._document:getTextFromXPointer(xp) + end +end + +function CreDocument:getHTMLFromXPointer(xp, flags, from_final_parent) + if xp then + return self._document:getHTMLFromXPointer(xp, flags, from_final_parent) + end +end + +function CreDocument:getHTMLFromXPointers(xp0, xp1, flags, from_root_node) + if xp0 and xp1 then + return self._document:getHTMLFromXPointers(xp0, xp1, flags, from_root_node) + end +end + function CreDocument:gotoPos(pos) logger.dbg("CreDocument: goto position", pos) self._document:gotoPos(pos) diff --git a/frontend/ui/font.lua b/frontend/ui/font.lua index 3a43eaa8d..a5ba6af5f 100644 --- a/frontend/ui/font.lua +++ b/frontend/ui/font.lua @@ -39,6 +39,8 @@ local Font = { -- font for displaying input content -- we have to use mono here for better distance controlling infont = "droid/DroidSansMono.ttf", + -- small mono font for displaying code + smallinfont = "droid/DroidSansMono.ttf", -- font for info messages infofont = "noto/NotoSans-Regular.ttf", @@ -66,6 +68,7 @@ local Font = { hpkfont = 20, hfont = 24, infont = 22, + smallinfont = 16, infofont = 24, smallinfofont = 22, smallinfofontbold = 22, diff --git a/frontend/ui/widget/textviewer.lua b/frontend/ui/widget/textviewer.lua index 18bc0b8a8..8db7ffe27 100644 --- a/frontend/ui/widget/textviewer.lua +++ b/frontend/ui/widget/textviewer.lua @@ -37,6 +37,7 @@ local TextViewer = InputContainer:new{ width = nil, height = nil, buttons_table = nil, + justified = true, title_face = Font:getFace("x_smalltfont"), text_face = Font:getFace("x_smallinfofont"), @@ -156,7 +157,7 @@ function TextViewer:init() width = self.width - 2*self.text_padding - 2*self.text_margin, height = textw_height - 2*self.text_padding -2*self.text_margin, dialog = self, - justified = true, + justified = self.justified, } self.textw = FrameContainer:new{ padding = self.text_padding,