mirror of https://github.com/koreader/koreader
add fulltext search for EPUB documents
parent
8ddca4bf49
commit
bd0975896d
@ -1 +1 @@
|
|||||||
Subproject commit af763e714395a9bf1a2356f7fb99a020c0387684
|
Subproject commit 5a83d4aaded90420306380613ccdc4613a53a9ce
|
@ -0,0 +1,100 @@
|
|||||||
|
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||||
|
local ButtonDialog = require("ui/widget/buttondialog")
|
||||||
|
local UIManager = require("ui/uimanager")
|
||||||
|
local Geom = require("ui/geometry")
|
||||||
|
local Screen = require("ui/screen")
|
||||||
|
local DEBUG = require("dbg")
|
||||||
|
local _ = require("gettext")
|
||||||
|
|
||||||
|
local ReaderSearch = InputContainer:new{
|
||||||
|
direction = 0, -- 0 for search forward, 1 for search backward
|
||||||
|
case_insensitive = 1, -- default to case insensitive
|
||||||
|
}
|
||||||
|
|
||||||
|
function ReaderSearch:init()
|
||||||
|
self.ui.menu:registerToMainMenu(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReaderSearch:addToMainMenu(tab_item_table)
|
||||||
|
table.insert(tab_item_table.plugins, {
|
||||||
|
text = _("Fulltext search"),
|
||||||
|
tap_input = {
|
||||||
|
title = _("Input text to search for"),
|
||||||
|
type = "text",
|
||||||
|
callback = function(input)
|
||||||
|
self:onShowSearchDialog(input)
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReaderSearch:onShowSearchDialog(text)
|
||||||
|
local do_search = function(search_func, text, param)
|
||||||
|
return function()
|
||||||
|
local res = search_func(self, text, param)
|
||||||
|
if res then
|
||||||
|
self.ui.link:onGotoLink(res[1].start)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.search_dialog = ButtonDialog:new{
|
||||||
|
alpha = 0.5,
|
||||||
|
buttons = {
|
||||||
|
{
|
||||||
|
{
|
||||||
|
text = "|<",
|
||||||
|
callback = do_search(self.searchFromStart, text),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text = "<",
|
||||||
|
callback = do_search(self.searchNext, text, 1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text = ">",
|
||||||
|
callback = do_search(self.searchNext, text, 0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text = ">|",
|
||||||
|
callback = do_search(self.searchFromEnd, text),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tap_close_callback = function()
|
||||||
|
DEBUG("highlight clear")
|
||||||
|
self.ui.highlight:clear()
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
local res = do_search(self.searchFromCurrent, text, 0)()
|
||||||
|
UIManager:show(self.search_dialog)
|
||||||
|
UIManager:setDirty(self.dialog, "partial")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReaderSearch:search(pattern, origin)
|
||||||
|
local direction = self.direction
|
||||||
|
local case = self.case_insensitive
|
||||||
|
return self.ui.document:findText(pattern, origin, direction, case)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReaderSearch:searchFromStart(pattern)
|
||||||
|
self.direction = 0
|
||||||
|
return self:search(pattern, -1)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReaderSearch:searchFromEnd(pattern)
|
||||||
|
self.direction = 1
|
||||||
|
return self:search(pattern, -1)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ReaderSearch:searchFromCurrent(pattern, direction)
|
||||||
|
self.direction = direction
|
||||||
|
return self:search(pattern, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ignore current page and search next occurrence
|
||||||
|
function ReaderSearch:searchNext(pattern, direction)
|
||||||
|
self.direction = direction
|
||||||
|
return self:search(pattern, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
return ReaderSearch
|
@ -0,0 +1,94 @@
|
|||||||
|
require("commonrequire")
|
||||||
|
local DocumentRegistry = require("document/documentregistry")
|
||||||
|
local ReaderUI = require("apps/reader/readerui")
|
||||||
|
local DEBUG = require("dbg")
|
||||||
|
|
||||||
|
local sample_epub = "spec/front/unit/data/juliet.epub"
|
||||||
|
|
||||||
|
describe("Readersearch module", function()
|
||||||
|
describe("search API for EPUB documents", function()
|
||||||
|
local doc, search, rolling
|
||||||
|
setup(function()
|
||||||
|
local readerui = ReaderUI:new{
|
||||||
|
document = DocumentRegistry:openDocument(sample_epub),
|
||||||
|
}
|
||||||
|
doc = readerui.document
|
||||||
|
search = readerui.search
|
||||||
|
rolling = readerui.rolling
|
||||||
|
end)
|
||||||
|
it("should search backward", function()
|
||||||
|
rolling:gotoPage(10)
|
||||||
|
assert.truthy(search:searchFromCurrent("Verona", 1))
|
||||||
|
for i = 1, 100, 10 do
|
||||||
|
rolling:gotoPage(i)
|
||||||
|
local words = search:searchFromCurrent("Verona", 1)
|
||||||
|
if words then
|
||||||
|
for _, word in ipairs(words) do
|
||||||
|
local pageno = doc:getPageFromXPointer(word.start)
|
||||||
|
--DEBUG("found at pageno", pageno)
|
||||||
|
assert.truthy(pageno <= i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
it("should search forward", function()
|
||||||
|
rolling:gotoPage(10)
|
||||||
|
assert.truthy(search:searchFromCurrent("Verona", 0))
|
||||||
|
for i = 1, 100, 10 do
|
||||||
|
rolling:gotoPage(i)
|
||||||
|
local words = search:searchFromCurrent("Verona", 0)
|
||||||
|
if words then
|
||||||
|
for _, word in ipairs(words) do
|
||||||
|
local pageno = doc:getPageFromXPointer(word.start)
|
||||||
|
--DEBUG("found at pageno", pageno)
|
||||||
|
assert.truthy(pageno >= i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
it("should find the first occurrence", function()
|
||||||
|
for i = 10, 100, 10 do
|
||||||
|
rolling:gotoPage(i)
|
||||||
|
local words = search:searchFromStart("Verona")
|
||||||
|
assert.truthy(words)
|
||||||
|
local pageno = doc:getPageFromXPointer(words[1].start)
|
||||||
|
assert.are.equal(8, pageno)
|
||||||
|
end
|
||||||
|
for i = 1, 5, 1 do
|
||||||
|
rolling:gotoPage(i)
|
||||||
|
local words = search:searchFromStart("Verona")
|
||||||
|
assert(words == nil)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
it("should find the last occurrence", function()
|
||||||
|
for i = 100, 200, 10 do
|
||||||
|
rolling:gotoPage(i)
|
||||||
|
local words = search:searchFromEnd("Verona")
|
||||||
|
assert.truthy(words)
|
||||||
|
local pageno = doc:getPageFromXPointer(words[1].start)
|
||||||
|
assert.are.equal(208, pageno)
|
||||||
|
end
|
||||||
|
for i = 230, 235, 1 do
|
||||||
|
rolling:gotoPage(i)
|
||||||
|
local words = search:searchFromEnd("Verona")
|
||||||
|
assert(words == nil)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
it("should find all occurrences", function()
|
||||||
|
local count = 0
|
||||||
|
rolling:gotoPage(1)
|
||||||
|
local words = search:searchFromCurrent("Verona", 0)
|
||||||
|
while words do
|
||||||
|
count = count + #words
|
||||||
|
for _, word in ipairs(words) do
|
||||||
|
--DEBUG("found word", word.start)
|
||||||
|
end
|
||||||
|
doc:gotoXPointer(words[1].start)
|
||||||
|
words = search:searchNext("Verona", 0)
|
||||||
|
end
|
||||||
|
assert.are.equal(13, count)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
describe("search API for PDF documents", function()
|
||||||
|
end)
|
||||||
|
end)
|
Loading…
Reference in New Issue