M src/Internal/Elements.hs => src/Internal/Elements.hs +26 -3
@@ 9,23 9,31 @@ import Control.Concurrent.MVar
import Internal
import Data.Aeson
-import Data.Text (Text, pack)
+import Data.Text as Txt (Text, pack, append)
import GHC.Generics
-- Selector engines
import qualified Text.XML.Cursor as X
import qualified XML.Selectors.CSS as CSS
+import Network.URI (parseURIReference)
+import Data.Maybe
+
getTitle :: Session -> IO Text
getTitle session = getTitle' <$> documentRoot <$> document <$> readMVar session
-getTitle' (Element "title" _ childs) = Txt.concat [txt | NodeContent txt <- childs]
-getTitle' (Element "h1" _ childs) = Txt.concat [txt | NodeContent txt <- childs]
+getTitle' (Element "title" _ childs) = nodesText childs
+getTitle' (Element "h1" _ childs) = nodesText childs
getTitle' (Element _ _ childs)
-- FIXME: Caught Rhapsode bug repaired here, needs that filtering condition.
| title:_ <- [getTitle' el | NodeElement el <- childs, getTitle' el /= ""] = title
| otherwise = ""
+nodesText (NodeElement (Element _ _ childs):nodes) = nodesText childs `append` nodesText nodes
+nodesText (NodeContent txt:nodes) = txt `append` nodesText nodes
+nodesText (_:nodes) = nodesText nodes
+nodesText [] = ""
+
---
data Find = Find { using :: Text, value :: String } deriving Generic
@@ 34,4 42,19 @@ find :: Find -> X.Cursor -> Either (Bool, String) [X.Cursor]
find (Find "css selector" sel) root = case CSS.parsePath sel of
Right sel' -> Right $ CSS.toAxis sel' root
Left msg -> Left (True, msg)
+find (Find "link text" sel) root = Right $ allLinks (== pack sel) root
+find (Find "partial link text" sel) root = Right $ allLinks (Txt.isInfixOf $ pack sel) root
find (Find type_ _) _ = Left (False, "Invalid selector type: " ++ Txt.unpack type_)
+
+allLinks test = X.descendant X.>=>
+ -- Missing some misc. elements Rhapsode treats as links
+ (X.hasAttribute "src" `union` X.hasAttribute "href") X.>=>
+ X.checkElement test'
+ where
+ test' (Element _ attrs childs) =
+ isJust (parseURIReference <$> unpack <$>
+ (M.lookup "src" attrs *> M.lookup "href" attrs)) ||
+ -- Emulate Rhapsode's mandatory whitespace-collapse
+ test (Txt.unwords $ Txt.words $ nodesText childs)
+
+union a b cursor = a cursor ++ b cursor
M src/Messages.hs => src/Messages.hs +5 -1
@@ 15,7 15,9 @@ data Message =
ElementNotFound |
NoResults |
PromptPreview |
- ErrURL deriving Show
+ ErrURL |
+ LinkSearchExact | LinkSearch
+ deriving Show
l :: [Text] -> Message -> Html
---- Begin localizations
@@ 40,6 42,8 @@ l ("en":_) PromptPreview = em "Click a search result to preview it here"
l ("en":_) ErrURL = do
h1 "Invalid Link!"
p "The provided URL was not absolute."
+l ("en":_) LinkSearchExact = "Links (Exact)"
+l ("en":_) LinkSearch = "Links"
---- End localizations
l (_:langs) msg = l langs msg
l [] msg = string $ show msg
M src/UI/Search.hs => src/UI/Search.hs +3 -1
@@ 25,7 25,9 @@ engines :: [(
)]
engines = [
(const "URL", offerToLoad),
- (const "CSS", queryEls "css selector")
+ (const "CSS", queryEls "css selector"),
+ (flip l LinkSearchExact, queryEls "link text"), -- Only useful if it promotes results higher.
+ (flip l LinkSearch, queryEls "partial link text")
]
result href' = a ! href (stringValue href') ! target "preview"