diff --git a/frontend/apps/reader/modules/readerlink.lua b/frontend/apps/reader/modules/readerlink.lua index a6b423132..ce42261a0 100644 --- a/frontend/apps/reader/modules/readerlink.lua +++ b/frontend/apps/reader/modules/readerlink.lua @@ -5,8 +5,10 @@ local UIManager = require("ui/uimanager") local Geom = require("ui/geometry") local Screen = require("device").screen local Device = require("device") +local logger = require("logger") local Event = require("ui/event") local _ = require("gettext") +local T = require("ffi/util").template local ReaderLink = InputContainer:new{ location_stack = {} @@ -141,13 +143,57 @@ function ReaderLink:onTap(_, ges) end function ReaderLink:onGotoLink(link) + logger.dbg("onGotoLink:", link) if self.ui.document.info.has_pages then - table.insert(self.location_stack, self.ui.paging:getBookLocation()) - self.ui:handleEvent(Event:new("GotoPage", link.page + 1)) + -- internal pdf links have a "page" attribute, while external ones have an "uri" attribute + if link.page then -- Internal link + logger.dbg("Internal link:", link) + table.insert(self.location_stack, self.ui.paging:getBookLocation()) + self.ui:handleEvent(Event:new("GotoPage", link.page + 1)) + return true + end + link = link.uri -- external link else - table.insert(self.location_stack, self.ui.rolling:getBookLocation()) - self.ui:handleEvent(Event:new("GotoXPointer", link)) + -- For crengine, internal links may look like : + -- #_doc_fragment_0_Organisation (link from anchor) + -- /body/DocFragment/body/ul[2]/li[5]/text()[3].16 (xpointer from full-text search) + -- If the XPointer does not exist (or is a full url), we will jump to page 1 + -- Best to check that this link exists in document with the following, + -- which accepts both of the above legitimate xpointer as input. + if self.ui.document:isXPointerInDocument(link) then + logger.dbg("Internal link:", link) + table.insert(self.location_stack, self.ui.rolling:getBookLocation()) + self.ui:handleEvent(Event:new("GotoXPointer", link)) + return true + end end + logger.dbg("External link:", link) + -- Check if it is a wikipedia link + local wiki_lang, wiki_page = link:match([[https?://([^%.]+).wikipedia.org/wiki/([^/]+)]]) + if wiki_lang and wiki_page then + logger.dbg("Wikipedia link:", wiki_lang, wiki_page) + -- Ask for user confirmation before launching lookup (on a + -- wikipedia page saved as epub, full of wikipedia links, it's + -- too easy to click on links when wanting to change page...) + local ConfirmBox = require("ui/widget/confirmbox") + UIManager:show(ConfirmBox:new{ + text = T(_("Would you like to read this Wikipedia %1 full page?\n\n%2\n"), wiki_lang:upper(), wiki_page:gsub("_", " ")), + cancel_on_tap_outside = true, + ok_callback = function() + UIManager:nextTick(function() + self.ui:handleEvent(Event:new("LookupWikipedia", wiki_page, false, true, wiki_lang)) + end) + end + }) + else + -- local Notification = require("ui/widget/notification") + local InfoMessage = require("ui/widget/infomessage") + UIManager:show(InfoMessage:new{ + text = T(_("Invalid or external link:\n%1"), link), + timeout = 1.0, + }) + end + -- don't propagate, user will notice and tap elsewhere if he wants to change page return true end diff --git a/frontend/ui/widget/confirmbox.lua b/frontend/ui/widget/confirmbox.lua index 0caad48a0..71bc666ff 100644 --- a/frontend/ui/widget/confirmbox.lua +++ b/frontend/ui/widget/confirmbox.lua @@ -22,6 +22,8 @@ local ImageWidget = require("ui/widget/imagewidget") local TextBoxWidget = require("ui/widget/textboxwidget") local HorizontalSpan = require("ui/widget/horizontalspan") local ButtonTable = require("ui/widget/buttontable") +local GestureRange = require("ui/gesturerange") +local Geom = require("ui/geometry") local UIManager = require("ui/uimanager") local Device = require("device") local Screen = Device.screen @@ -44,6 +46,23 @@ local ConfirmBox = InputContainer:new{ } function ConfirmBox:init() + if Device:isTouchDevice() then + self.ges_events.TapClose = { + GestureRange:new{ + ges = "tap", + range = Geom:new{ + x = 0, y = 0, + w = Screen:getWidth(), + h = Screen:getHeight(), + } + } + } + end + if Device:hasKeys() then + self.key_events = { + Close = { {"Back"}, doc = "cancel" } + } + end local content = HorizontalGroup:new{ align = "center", ImageWidget:new{ @@ -110,10 +129,20 @@ function ConfirmBox:onCloseWidget() end function ConfirmBox:onClose() + -- Call cancel_callback, parent may expect a choice + self.cancel_callback() UIManager:close(self) return true end +function ConfirmBox:onTapClose(arg, ges) + if ges.pos:notIntersectWith(self[1][1].dimen) then + self:onClose() + return true + end + return false +end + function ConfirmBox:onSelect() logger.dbg("selected:", self.selected.x) if self.selected.x == 1 then