Explorar el Código

Add loopUntilElementAppears async function to API

jherve hace 1 año
padre
commit
77cea6985e
Se han modificado 4 ficheros con 54 adiciones y 1 borrados
  1. 2 0
      spago.dhall
  2. 6 1
      src/LinkedIn.purs
  3. 3 0
      src/LinkedIn/Loadable.js
  4. 43 0
      src/LinkedIn/Loadable.purs

+ 2 - 0
spago.dhall

@@ -19,6 +19,8 @@ You can edit this file as you like.
   , "free"
   , "free"
   , "int64"
   , "int64"
   , "integers"
   , "integers"
+  , "js-promise"
+  , "js-promise-aff"
   , "lists"
   , "lists"
   , "maybe"
   , "maybe"
   , "node-buffer"
   , "node-buffer"

+ 6 - 1
src/LinkedIn.purs

@@ -1,4 +1,4 @@
-module LinkedIn (APIError(..), encodeToJson, getContext, getContextJson, extractFromDocument, extractFromDocumentJson, forceExtract) where
+module LinkedIn (APIError(..), encodeToJson, getContext, getContextJson, extractFromDocument, extractFromDocumentJson, forceExtract, loopUntilElementAppears) where
 
 
 import Prelude
 import Prelude
 
 
@@ -14,10 +14,12 @@ import Data.Traversable (class Traversable)
 import Effect (Effect)
 import Effect (Effect)
 import LinkedIn.CanBeQueried (class CanBeQueried)
 import LinkedIn.CanBeQueried (class CanBeQueried)
 import LinkedIn.Extractible (class Extractible)
 import LinkedIn.Extractible (class Extractible)
+import LinkedIn.Loadable (waitFor)
 import LinkedIn.Output (OutputError, run, toOutput)
 import LinkedIn.Output (OutputError, run, toOutput)
 import LinkedIn.Output.Types (Output)
 import LinkedIn.Output.Types (Output)
 import LinkedIn.PageUrl (PageUrl, pageUrlP)
 import LinkedIn.PageUrl (PageUrl, pageUrlP)
 import Parsing (runParser)
 import Parsing (runParser)
+import Promise.Aff (Promise, fromAff)
 import Type.Proxy (Proxy)
 import Type.Proxy (Proxy)
 import Web.DOM (Document)
 import Web.DOM (Document)
 import Web.DOM.Document (url)
 import Web.DOM.Document (url)
@@ -66,6 +68,9 @@ toOutput' ctx dom = withExceptT (\err -> ErrorExtraction err) $ toOutput ctx dom
 encodeToJson :: Either String Output -> Json
 encodeToJson :: Either String Output -> Json
 encodeToJson = encodeJson
 encodeToJson = encodeJson
 
 
+loopUntilElementAppears ∷ String → Document → Effect (Promise Boolean)
+loopUntilElementAppears selector q = fromAff $ waitFor 200 50 selector q
+
 -- | Force extraction of data from a page, when the context given by the URL is imprecise
 -- | Force extraction of data from a page, when the context given by the URL is imprecise
 -- | or plain wrong (e.g. for local files).
 -- | or plain wrong (e.g. for local files).
 -- | Can be call e.g. `forceExtract (Proxy :: Proxy JobOfferPage) dom`
 -- | Can be call e.g. `forceExtract (Proxy :: Proxy JobOfferPage) dom`

+ 3 - 0
src/LinkedIn/Loadable.js

@@ -0,0 +1,3 @@
+const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
+
+export const sleepImpl = ms => () => wait(ms);

+ 43 - 0
src/LinkedIn/Loadable.purs

@@ -0,0 +1,43 @@
+module LinkedIn.Loadable where
+
+import Prelude
+
+import Control.Monad.Except (runExceptT)
+import Data.Either (Either(..), isRight)
+import Effect (Effect)
+import Effect.Aff (Aff, launchAff_)
+import Effect.Class (liftEffect)
+import Effect.Class.Console (log)
+import LinkedIn.QueryRunner (queryOne)
+import LinkedIn.Queryable (class Queryable)
+import Promise (Promise)
+import Promise.Aff (toAffE)
+
+foreign import sleepImpl :: Int -> Effect (Promise Unit)
+
+sleep :: Int -> Aff Unit
+sleep = sleepImpl >>> toAffE
+
+waitForElement' ∷ ∀ q. Queryable q ⇒ Int → Int → String → q → Effect Unit
+waitForElement' loopDelay maxLoops selector q = launchAff_ do
+  res <- waitForElement loopDelay maxLoops selector q
+  case res of
+    Left l -> log $ "failed after " <> show l
+    Right r -> log $ "succeeded after " <> show r
+
+waitForElement ∷ ∀ q. Queryable q ⇒ Int → Int → String → q → Aff (Either Int Int)
+waitForElement loopDelay maxLoops selector q = waitingLoop 0
+  where
+    waitingLoop :: Int -> Aff (Either Int Int)
+    waitingLoop iter | iter >= maxLoops = pure $ Left iter
+    waitingLoop iter = do
+      n <- liftEffect $ runExceptT $ queryOne selector q
+      case n of
+        Right _ -> pure $ Right iter
+        Left _ -> do
+          sleep loopDelay
+          waitingLoop (iter + 1)
+
+-- Returns true if the element was found after waiting for maxLoops
+waitFor ∷ ∀ q. Queryable q ⇒ Int → Int → String → q → Aff Boolean
+waitFor loopDelay maxLoops selector q = pure <<< isRight =<< waitForElement loopDelay maxLoops selector q