<commit_before>import "./vendor"
import sound from "./sound"
import Fire from "./fire"
import DB from "./db"
import $ from "jquery"
import _ from "ramda"
import Notifications from "./notifications"
import cryptoRandomString from "crypto-random-string"
import localforage from "localforage"
import MutationSummary from "mutation-summary"
import {Kefir} from "kefir"
import {Main} from "elm/Main.elm"

const isDevelopmentMode = process.env["NODE_ENV"] === "development"
const env = process.env
const npmPackageVersion = env["npm_package_version"]

const mutationObserverFocusSelectorStream = Kefir.stream(emitter => {
  
  const focusableEntityListItemSelector = ".focusable-list-item[tabindex=0]"
  const autoFocusSelector = ".auto-focus"
  new MutationSummary({
    callback: summaries => {
      // console.log(summaries)
      
      const autoFocusSummaryAdded = summaries[0].added
      if (!_.isEmpty(autoFocusSummaryAdded)) {
        //note: delaying auto-focus to ensure that it takes priority.
        setTimeout(() => emitter.emit(".auto-focus"), 0)
      }
    },
    queries: [
      {element: autoFocusSelector},
    ],
  })
  
  
  new MutationSummary({
    callback: summaries => {
      // console.log(summaries)
      
      const entityListItemSummary = summaries[0]
      console.log(".entity-list", entityListItemSummary)
      
      // if (!(entityListItemSummary.added.length !== 0
      //       || entityListItemSummary.attributeChanged.tabindex.length !== 0)) {
      //   return
      // }
      // todo: this is a lazy way to ensure that after overlay is closed
      // we focus on EL, and since auto-focus takes priority. check above.
      emitter.emit(".focusable-list-item[tabindex=0]")
    },
    queries: [
      {element: ".focusable-list-item", elementAttributes: "tabindex"},
      {element: ".overlay"},
    ],
  })
  
  
})

window.appBoot = async function appBoot(elmMain = Main) {
  
  const deviceId = getOrCreateDeviceId()
  const $elm = $("#elm-container")
  // $elm.trap();
  
  $elm.on("keydown", `.entity-list`, e => {
    // console.log(e.keyCode, e.key, e.target, e);
    
    // prevent document scrolling
    if (e.key === " " || e.key === "ArrowUp" || e.key === "ArrowDown") {
      e.preventDefault()
    }
    
  })
  
  
  const db = await DB()
  
  const store = localforage.createInstance({
    name: "SimpleGTD.com offline store",
  });
  
  
  const getOfflineStore = async () => {
    const storeKeys = await store.keys()
    const storeValues = await _.compose(
        ps => Promise.all(ps), _.map(k => store.getItem(k)),
    )(storeKeys)
    return _.zipObj(storeKeys, storeValues)
  }
  const initialOfflineStore = await getOfflineStore()
  // console.log(initialOfflineStore)
  
  const flags = _.merge({
    now: Date.now(),
    pouchDBRemoteSyncURI: localStorage.getItem("pouchdb.remote-sync-uri") || "",
    developmentMode: isDevelopmentMode,
    config: {
      debug: WEBPACK_DEV_SERVER,
      deviceId,
      npmPackageVersion,
      isDevelopmentMode,
      initialOfflineStore,
    },
  }, db.allDocsMap)
  
  
  const app = elmMain
      .embed(document.getElementById("elm-container"), flags)
  
  
  const fire = Fire.setup(app, _.values(db.list), deviceId)
  
  db.setupApp(app)
  
  
  app.ports["persistToOfflineStore"].subscribe(([key, value]) => {
    store.setItem(key, value).catch(console.error)
  });
  
  
  Notifications.setup(fire, app).catch(console.error)
  
  const portFocusSelectorStream =
      Kefir.stream(emitter => {
        app.ports["focusSelector"].subscribe((selector) => {
          // console.log("port: focusSelector received selector", selector)
          // emitter.emit(selector)
        })
      })
  
  const addMetadataToFocusSelectorStream =
      (stream, streamName) => stream.map(selector => ({streamName, selector}))
  
  const focusSelectorStreams =
      [addMetadataToFocusSelectorStream(
          portFocusSelectorStream,
          "portFocusSelectorStream",
      ),
       addMetadataToFocusSelectorStream(
           mutationObserverFocusSelectorStream,
           "mutationObserverFocusSelectorStream",
       )]
  Kefir.merge(focusSelectorStreams)
       .observe({
         value(options) {
           // todo: adding any delay causes entity list focus to go haywire.
           // even in focus selector port.
           // we need to completely control focus on entity list.
           // can't depended on mutation observer for the same.
           // requestAnimationFrame(()=>{
           const $toFocus = $(options.selector).first()
      
           // console.log("[Kefir] focusSelector", _.merge(options, {
           // dataKey: $toFocus.data("key"),
           // }))
      
           $toFocus.focus()
           // })
         },
       })
  
  app.ports["positionPopupMenu"].subscribe((ofSelector) => {
    requestAnimationFrame(() => {
      const $popup = $("#popup-menu")
      $popup.position({
        my: "right top",
        at: "right top",
        of: $(ofSelector),
        within: ".overlay",
        collision: "fit",
      })
      $popup.find(".auto-focus").first().focus()
      
      const focusableSelector = ":focusable, input:focusable"
      $popup.on("keydown", focusableSelector, function (e) {
        if (e.key !== "Tab") return
        const $focusable = $popup.find(focusableSelector)
        
        const first = $focusable.first().get(0)<commit_msg>WIP: fix focus<commit_after>import "./vendor"
import sound from "./sound"
import Fire from "./fire"
import DB from "./db"
import $ from "jquery"
import _ from "ramda"
import Notifications from "./notifications"
import cryptoRandomString from "crypto-random-string"
import localforage from "localforage"
import MutationSummary from "mutation-summary"
import {Kefir} from "kefir"
import {Main} from "elm/Main.elm"

const isDevelopmentMode = process.env["NODE_ENV"] === "development"
const env = process.env
const npmPackageVersion = env["npm_package_version"]

const mutationObserverFocusSelectorStream = Kefir.stream(emitter => {
  
  const focusableEntityListItemSelector = ".focusable-list-item[tabindex=0]"
  const autoFocusSelector = ".auto-focus"
  new MutationSummary({
    callback: summaries => {
      // console.log(summaries)
      
      const autoFocusSummaryAdded = summaries[0].added
      if (!_.isEmpty(autoFocusSummaryAdded)) {
        //note: delaying auto-focus to ensure that it takes priority.
        setTimeout(() => emitter.emit(".auto-focus"), 0)
      }
    },
    queries: [
      {element: autoFocusSelector},
    ],
  })
  
  
  new MutationSummary({
    callback: summaries => {
      // console.log(summaries)
      
      const entityListItemSummary = summaries[0]
      console.log(".entity-list", entityListItemSummary)
      
      // if (!(entityListItemSummary.added.length !== 0
      //       || entityListItemSummary.attributeChanged.tabindex.length !== 0)) {
      //   return
      // }
      // todo: this is a lazy way to ensure that after overlay is closed
      // we focus on EL, and since auto-focus takes priority. check above.
      emitter.emit(".focusable-list-item[tabindex=0]")
    },
    queries: [
      {element: ".focusable-list-item", elementAttributes: "tabindex"},
      {element: ".overlay"},
    ],
  })
  
  
})

window.appBoot = async function appBoot(elmMain = Main) {
  
  const deviceId = getOrCreateDeviceId()
  const $elm = $("#elm-container")
  // $elm.trap();
  
  $elm.on("keydown", `.entity-list`, e => {
    // console.log(e.keyCode, e.key, e.target, e);
    
    // prevent document scrolling
    if (e.key === " " || e.key === "ArrowUp" || e.key === "ArrowDown") {
      e.preventDefault()
    }
    
  })
  
  
  const db = await DB()
  
  const store = localforage.createInstance({
    name: "SimpleGTD.com offline store",
  });
  
  
  const getOfflineStore = async () => {
    const storeKeys = await store.keys()
    const storeValues = await _.compose(
        ps => Promise.all(ps), _.map(k => store.getItem(k)),
    )(storeKeys)
    return _.zipObj(storeKeys, storeValues)
  }
  const initialOfflineStore = await getOfflineStore()
  // console.log(initialOfflineStore)
  
  const flags = _.merge({
    now: Date.now(),
    pouchDBRemoteSyncURI: localStorage.getItem("pouchdb.remote-sync-uri") || "",
    developmentMode: isDevelopmentMode,
    config: {
      debug: WEBPACK_DEV_SERVER,
      deviceId,
      npmPackageVersion,
      isDevelopmentMode,
      initialOfflineStore,
    },
  }, db.allDocsMap)
  
  
  const app = elmMain
      .embed(document.getElementById("elm-container"), flags)
  
  
  const fire = Fire.setup(app, _.values(db.list), deviceId)
  
  db.setupApp(app)
  
  
  app.ports["persistToOfflineStore"].subscribe(([key, value]) => {
    store.setItem(key, value).catch(console.error)
  });
  
  
  Notifications.setup(fire, app).catch(console.error)
  
  const portFocusSelectorStream =
      Kefir.stream(emitter => {
        app.ports["focusSelector"].subscribe((selector) => {
          // console.log("port: focusSelector received selector", selector)
          // emitter.emit(selector)
        })
      })
  
  const addMetadataToFocusSelectorStream =
      (stream, streamName) => stream.map(selector => ({streamName, selector}))
  
  const focusSelectorStreams =
      [addMetadataToFocusSelectorStream(
          portFocusSelectorStream,
          "portFocusSelectorStream",
      ),
       addMetadataToFocusSelectorStream(
           mutationObserverFocusSelectorStream,
           "mutationObserverFocusSelectorStream",
       )]
  Kefir.merge(focusSelectorStreams)
       .observe({
         value(options) {
           const $toFocus = $(options.selector).first()
           // console.log("[Kefir] focusSelector", _.merge(options, {
           // dataKey: $toFocus.data("key"),
           // }))
           $toFocus.focus()
         },
       })
  
  app.ports["positionPopupMenu"].subscribe((ofSelector) => {
    requestAnimationFrame(() => {
      const $popup = $("#popup-menu")
      $popup.position({
        my: "right top",
        at: "right top",
        of: $(ofSelector),
        within: ".overlay",
        collision: "fit",
      })
      $popup.find(".auto-focus").first().focus()
      
      const focusableSelector = ":focusable, input:focusable"
      $popup.on("keydown", focusableSelector, function (e) {
        if (e.key !== "Tab") return
        const $focusable = $popup.find(focusableSelector)
        
        const first = $focusable.first().get(0)
{'fraction_non_alphanumeric': 0.1371412279034404, 'fraction_numerical': 0.001520623455616803, 'mean_word_length': 2.676799440950384, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2076439', 'n_tokens_mistral': 3159, 'n_tokens_neox': 3124, 'n_words': 651}