Пример #1
0
  handleNoteListKeyDown (e) {
    if (e.metaKey || e.ctrlKey) return true

    if (e.keyCode === 65 && !e.shiftKey) {
      e.preventDefault()
      ee.emit('top:new-note')
    }

    if (e.keyCode === 68) {
      e.preventDefault()
      ee.emit('detail:delete')
    }

    if (e.keyCode === 69) {
      e.preventDefault()
      ee.emit('detail:focus')
    }

    if (e.keyCode === 38) {
      e.preventDefault()
      this.selectPriorNote()
    }

    if (e.keyCode === 40) {
      e.preventDefault()
      this.selectNextNote()
    }
  }
Пример #2
0
 .then(() => {
   let dispatchHandler = () => {
     dispatch({
       type: 'REMOVE_NOTE',
       note: note
     })
   }
   ee.once('list:moved', dispatchHandler)
   ee.emit('list:next')
   ee.emit('list:focus')
 })
Пример #3
0
 .then((note) => {
   const noteHash = note.key
   dispatch({
     type: 'UPDATE_NOTE',
     note: note
   })
   hashHistory.push({
     pathname: location.pathname,
     query: {key: noteHash}
   })
   ee.emit('list:jump', noteHash)
   ee.emit('detail:focus')
   this.props.close()
 })
Пример #4
0
 handlelinkClick (e) {
   const noteHash = e.target.href.split('/').pop()
   const regexIsNoteLink = /^(.{20})-(.{20})$/
   if (regexIsNoteLink.test(noteHash)) {
     eventEmitter.emit('list:jump', noteHash)
   }
 }
Пример #5
0
  selectPriorNote () {
    if (this.notes == null || this.notes.length === 0) {
      return
    }
    let { selectedNoteKeys } = this.state
    const { shiftKeyDown } = this.state

    let targetIndex = this.getTargetIndex()

    if (targetIndex === 0) {
      return
    }
    targetIndex--

    if (!shiftKeyDown) { selectedNoteKeys = [] }
    const priorNoteKey = this.getNoteKeyFromTargetIndex(targetIndex)
    if (selectedNoteKeys.includes(priorNoteKey)) {
      selectedNoteKeys.pop()
    } else {
      selectedNoteKeys.push(priorNoteKey)
    }

    this.focusNote(selectedNoteKeys, priorNoteKey)

    ee.emit('list:moved')
  }
Пример #6
0
  selectNextNote () {
    if (this.notes == null || this.notes.length === 0) {
      return
    }
    let { selectedNoteKeys } = this.state
    const { shiftKeyDown } = this.state

    let targetIndex = this.getTargetIndex()
    const isTargetLastNote = targetIndex === this.notes.length - 1

    if (isTargetLastNote && shiftKeyDown) {
      return
    } else if (isTargetLastNote) {
      targetIndex = 0
    } else {
      targetIndex++
      if (targetIndex < 0) targetIndex = 0
      else if (targetIndex > this.notes.length - 1) targetIndex = this.notes.length - 1
    }

    if (!shiftKeyDown) { selectedNoteKeys = [] }
    const nextNoteKey = this.getNoteKeyFromTargetIndex(targetIndex)
    if (selectedNoteKeys.includes(nextNoteKey)) {
      selectedNoteKeys.pop()
    } else {
      selectedNoteKeys.push(nextNoteKey)
    }

    this.focusNote(selectedNoteKeys, nextNoteKey)

    ee.emit('list:moved')
  }
Пример #7
0
  selectNextNote () {
    if (this.notes == null || this.notes.length === 0) {
      return
    }
    let { router } = this.context
    let { location } = this.props

    let targetIndex = _.findIndex(this.notes, (note) => {
      return note.storage + '-' + note.key === location.query.key
    })

    if (targetIndex === this.notes.length - 1) {
      targetIndex = 0
    } else {
      targetIndex++
      if (targetIndex < 0) targetIndex = 0
      else if (targetIndex > this.notes.length - 1) targetIndex === this.notes.length - 1
    }

    router.push({
      pathname: location.pathname,
      query: {
        key: this.notes[targetIndex].storage + '-' + this.notes[targetIndex].key
      }
    })
    ee.emit('list:moved')
  }
Пример #8
0
 }, () => {
   if (newStatus === 'CODE') {
     this.refs.code.focus()
   } else {
     this.refs.preview.focus()
   }
   eventEmitter.emit('topbar:togglelockbutton', this.state.status)
 })
Пример #9
0
  handleNoteListKeyDown (e) {
    if (e.metaKey || e.ctrlKey) return true

    // A key
    if (e.keyCode === 65 && !e.shiftKey) {
      e.preventDefault()
      ee.emit('top:new-note')
    }

    // D key
    if (e.keyCode === 68) {
      e.preventDefault()
      this.deleteNote()
    }

    // E key
    if (e.keyCode === 69) {
      e.preventDefault()
      ee.emit('detail:focus')
    }

    // L or S key
    if (e.keyCode === 76 || e.keyCode === 83) {
      e.preventDefault()
      ee.emit('top:focus-search')
    }

    // UP or K key
    if (e.keyCode === 38 || e.keyCode === 75) {
      e.preventDefault()
      this.selectPriorNote()
    }

    // DOWN or J key
    if (e.keyCode === 40 || e.keyCode === 74) {
      e.preventDefault()
      this.selectNextNote()
    }

    if (e.shiftKey) {
      this.setState({ shiftKeyDown: true })
    }
  }
Пример #10
0
 handlePreviewMouseUp (e) {
   const { config } = this.props
   if (config.editor.switchPreview === 'BLUR' && new Date() - this.previewMouseDownedAt < 200) {
     this.setState({
       status: 'CODE'
     }, () => {
       this.refs.code.focus()
     })
     eventEmitter.emit('topbar:togglelockbutton', this.state.status)
   }
 }
Пример #11
0
  jumpNoteByHashHandler (event, noteHash) {
    // first argument event isn't used.
    if (this.notes === null || this.notes.length === 0) {
      return
    }

    const selectedNoteKeys = [noteHash]
    this.focusNote(selectedNoteKeys, noteHash)

    ee.emit('list:moved')
  }
Пример #12
0
 focus () {
   if (this.state.status === 'PREVIEW') {
     this.setState({
       status: 'CODE'
     }, () => {
       this.refs.code.focus()
     })
   } else {
     this.refs.code.focus()
   }
   eventEmitter.emit('topbar:togglelockbutton', this.state.status)
 }
Пример #13
0
  handlelinkClick (e) {
    e.preventDefault()
    e.stopPropagation()

    const href = e.target.href
    const linkHash = href.split('/').pop()

    const regexNoteInternalLink = /main.html#(.+)/
    if (regexNoteInternalLink.test(linkHash)) {
      const targetId = mdurl.encode(linkHash.match(regexNoteInternalLink)[1])
      const targetElement = this.refs.root.contentWindow.document.getElementById(targetId)

      if (targetElement != null) {
        this.getWindow().scrollTo(0, targetElement.offsetTop)
      }
      return
    }

    // this will match the new uuid v4 hash and the old hash
    // e.g.
    // :note:1c211eb7dcb463de6490 and
    // :note:7dd23275-f2b4-49cb-9e93-3454daf1af9c
    const regexIsNoteLink = /^:note:([a-zA-Z0-9-]{20,36})$/
    if (regexIsNoteLink.test(linkHash)) {
      eventEmitter.emit('list:jump', linkHash.replace(':note:', ''))
      return
    }

    // this will match the old link format storage.key-note.key
    // e.g.
    // 877f99c3268608328037-1c211eb7dcb463de6490
    const regexIsLegacyNoteLink = /^(.{20})-(.{20})$/
    if (regexIsLegacyNoteLink.test(linkHash)) {
      eventEmitter.emit('list:jump', linkHash.split('-')[1])
      return
    }

    // other case
    shell.openExternal(href)
  }
Пример #14
0
 handleSearchChange (e) {
   const { router } = this.context
   const keyword = this.refs.searchInput.value
   if (this.state.isAlphabet || this.state.isConfirmTranslation) {
     router.push(`/searched/${encodeURIComponent(keyword)}`)
   } else {
     e.preventDefault()
   }
   this.setState({
     search: keyword
   })
   ee.emit('top:search', keyword)
 }
Пример #15
0
 handleBlur (e) {
   if (this.state.isLocked) return
   this.setState({ keyPressed: [] })
   let { config } = this.props
   if (config.editor.switchPreview === 'BLUR') {
     let cursorPosition = this.refs.code.editor.getCursor()
     this.setState({
       status: 'PREVIEW'
     }, () => {
       this.refs.preview.focus()
       this.refs.preview.scrollTo(cursorPosition.line)
     })
     eventEmitter.emit('topbar:togglelockbutton', this.state.status)
   }
 }
Пример #16
0
  handleKeyDown (e) {
    // reset states
    this.setState({
      isAlphabet: false,
      isIME: false
    })

    // Clear search on ESC
    if (e.keyCode === 27) {
      return this.handleSearchClearButton(e)
    }

    // Next note on DOWN key
    if (e.keyCode === 40) {
      ee.emit('list:next')
      e.preventDefault()
    }

    // Prev note on UP key
    if (e.keyCode === 38) {
      ee.emit('list:prior')
      e.preventDefault()
    }

    // When the key is an alphabet, del, enter or ctr
    if (e.keyCode <= 90 || e.keyCode >= 186 && e.keyCode <= 222) {
      this.setState({
        isAlphabet: true
      })
    // When the key is an IME input (Japanese, Chinese)
    } else if (e.keyCode === 229) {
      this.setState({
        isIME: true
      })
    }
  }
Пример #17
0
  componentDidUpdate (prevProps) {
    const { location } = this.props
    const { selectedNoteKeys } = this.state
    const visibleNoteKeys = this.notes.map(note => note.key)
    const note = this.notes[0]
    const prevKey = prevProps.location.query.key
    const noteKey = visibleNoteKeys.includes(prevKey) ? prevKey : note && note.key

    if (note && location.query.key == null) {
      const { router } = this.context
      if (!location.pathname.match(/\/searched/)) this.contextNotes = this.getContextNotes()

      // A visible note is an active note
      if (!selectedNoteKeys.includes(noteKey)) {
        if (selectedNoteKeys.length === 1) selectedNoteKeys.pop()
        selectedNoteKeys.push(noteKey)
        ee.emit('list:moved')
      }

      router.replace({
        pathname: location.pathname,
        query: {
          key: noteKey
        }
      })
      return
    }

    // Auto scroll
    if (_.isString(location.query.key) && prevProps.location.query.key === location.query.key) {
      const targetIndex = this.getTargetIndex()
      if (targetIndex > -1) {
        const list = this.refs.list
        const item = list.childNodes[targetIndex]

        if (item == null) return false

        const overflowBelow = item.offsetTop + item.clientHeight - list.clientHeight - list.scrollTop > 0
        if (overflowBelow) {
          list.scrollTop = item.offsetTop + item.clientHeight - list.clientHeight
        }
        const overflowAbove = list.scrollTop > item.offsetTop
        if (overflowAbove) {
          list.scrollTop = item.offsetTop
        }
      }
    }
  }
Пример #18
0
        .then((data) => {
          let dispatchHandler = () => {
            dispatch({
              type: 'DELETE_NOTE',
              storageKey: data.storageKey,
              noteKey: data.noteKey
            })
          }

          if (location.query.key === uniqueKey) {
            ee.once('list:moved', dispatchHandler)
            ee.emit('list:next')
          } else {
            dispatchHandler()
          }
        })
Пример #19
0
function set (updates) {
  const currentConfig = get()
  const newConfig = Object.assign({}, DEFAULT_CONFIG, currentConfig, updates)
  if (!validate(newConfig)) throw new Error('INVALID CONFIG')
  _save(newConfig)

  if (newConfig.ui.theme === 'dark') {
    document.body.setAttribute('data-theme', 'dark')
  } else if (newConfig.ui.theme === 'white') {
    document.body.setAttribute('data-theme', 'white')
  } else if (newConfig.ui.theme === 'solarized-dark') {
    document.body.setAttribute('data-theme', 'solarized-dark')
  } else if (newConfig.ui.theme === 'monokai') {
    document.body.setAttribute('data-theme', 'monokai')
  } else {
    document.body.setAttribute('data-theme', 'default')
  }

  i18n.setLocale(newConfig.ui.language)

  let editorTheme = document.getElementById('editorTheme')
  if (editorTheme == null) {
    editorTheme = document.createElement('link')
    editorTheme.setAttribute('id', 'editorTheme')
    editorTheme.setAttribute('rel', 'stylesheet')
    document.head.appendChild(editorTheme)
  }
  const newTheme = consts.THEMES.some((theme) => theme === newConfig.editor.theme)
    ? newConfig.editor.theme
    : 'default'

  if (newTheme !== 'default') {
    if (newTheme.startsWith('solarized')) {
      editorTheme.setAttribute('href', '../node_modules/codemirror/theme/solarized.css')
    } else {
      editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + newTheme + '.css')
    }
  }

  ipcRenderer.send('config-renew', {
    config: get()
  })
  ee.emit('config-renew')
}
Пример #20
0
  handleTrashButtonClick (e) {
    let { note } = this.state
    const { isTrashed } = note

    if (isTrashed) {
      let dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
        type: 'warning',
        message: 'Confirm note deletion',
        detail: 'This will permanently remove this note.',
        buttons: ['Confirm', 'Cancel']
      })
      if (dialogueButtonIndex === 1) return
      let { note, dispatch } = this.props
      dataApi
        .deleteNote(note.storage, note.key)
        .then((data) => {
          let dispatchHandler = () => {
            dispatch({
              type: 'DELETE_NOTE',
              storageKey: data.storageKey,
              noteKey: data.noteKey
            })
          }
          ee.once('list:moved', dispatchHandler)
        })
    } else {
      note.isTrashed = true

      this.setState({
        note
      }, () => {
        this.save()
      })
    }
    ee.emit('list:next')
  }
Пример #21
0
  handleTrashButtonClick (e) {
    const { note } = this.state
    const { isTrashed } = note
    const { confirmDeletion } = this.props.config.ui

    if (isTrashed) {
      if (confirmDeleteNote(confirmDeletion, true)) {
        const {note, dispatch} = this.props
        dataApi
          .deleteNote(note.storage, note.key)
          .then((data) => {
            const dispatchHandler = () => {
              dispatch({
                type: 'DELETE_NOTE',
                storageKey: data.storageKey,
                noteKey: data.noteKey
              })
            }
            ee.once('list:next', dispatchHandler)
          })
          .then(() => ee.emit('list:next'))
      }
    } else {
      if (confirmDeleteNote(confirmDeletion, false)) {
        note.isTrashed = true

        this.setState({
          note
        }, () => {
          this.save()
        })

        ee.emit('list:next')
      }
    }
  }
Пример #22
0
 this.changeDelay = setTimeout(() => {
   // notify the snippet editor that the name or prefix of snippet has been changed
   this.snippetEditor.onSnippetNameOrPrefixChanged(this.state.currentSnippet)
   eventEmitter.emit('snippetList:reload')
 }, 500)
Пример #23
0
 exportAsMd () {
   ee.emit('export:save-md')
 }
Пример #24
0
 exportAsTxt () {
   ee.emit('export:save-text')
 }
Пример #25
0
 }, () => {
   this.save()
   this.refs.content.reload()
   ee.emit('list:next')
 })
Пример #26
0
 handleLockButtonMouseDown (e) {
   e.preventDefault()
   ee.emit('editor:lock')
   this.setState({ isLocked: !this.state.isLocked })
   if (this.state.isLocked) this.focus()
 }
Пример #27
0
 handleFullScreenButton (e) {
   ee.emit('editor:fullscreen')
 }
Пример #28
0
 }, () => {
   this.save()
   ee.emit('list:next')
 })
Пример #29
0
 .then(() => ee.emit('list:next'))
Пример #30
0
 }, () => {
   this.refs.code.focus()
   eventEmitter.emit('topbar:togglelockbutton', this.state.status)
 })