From 136d895d155f28c2e75b3af206549acaa2a354ed Mon Sep 17 00:00:00 2001
From: Philip Molares
Date: Mon, 15 Feb 2021 09:42:51 +0100
Subject: Linter: Fix all lint errors

Signed-off-by: Philip Molares <philip.molares@udo.edu>
---
 public/js/cover.js             |   10 +-
 public/js/extra.js             |   74 +-
 public/js/history.js           |    6 +-
 public/js/index.js             | 2171 ++++++++++++++++++++++++++--------------
 public/js/lib/appState.js      |    2 +-
 public/js/lib/common/login.js  |    2 +-
 public/js/lib/editor/config.js |    2 +-
 public/js/lib/editor/index.js  |  123 +--
 public/js/lib/editor/utils.js  |   46 +-
 public/js/lib/syncscroll.js    |   22 +-
 public/js/render.js            |   34 +-
 public/js/reveal-markdown.js   |  102 +-
 public/js/slide.js             |  141 +--
 public/js/utils.js             |   12 +-
 14 files changed, 1707 insertions(+), 1040 deletions(-)

(limited to 'public/js')

diff --git a/public/js/cover.js b/public/js/cover.js
index ed10afbf..bad92574 100644
--- a/public/js/cover.js
+++ b/public/js/cover.js
@@ -262,8 +262,8 @@ function updateItemFromNow () {
   }
 }
 
-var clearHistory = false
-var deleteId = null
+let clearHistory = false
+let deleteId = null
 
 function deleteHistory () {
   checkIfAuth(() => {
@@ -431,9 +431,9 @@ $('.search').keyup(() => {
 
 // focus user field after opening login modal
 $('.signin-modal').on('shown.bs.modal', function () {
-  let fieldLDAP = $('input[name=username]')
-  let fieldEmail = $('input[name=email]')
-  let fieldOpenID = $('input[name=openid_identifier]')
+  const fieldLDAP = $('input[name=username]')
+  const fieldEmail = $('input[name=email]')
+  const fieldOpenID = $('input[name=openid_identifier]')
   if (fieldLDAP.length === 1) {
     fieldLDAP.focus()
   } else if (fieldEmail.length === 1) {
diff --git a/public/js/extra.js b/public/js/extra.js
index 44db742a..7f06ebda 100644
--- a/public/js/extra.js
+++ b/public/js/extra.js
@@ -29,7 +29,7 @@ require('prismjs/components/prism-gherkin')
 require('./lib/common/login')
 require('./locale')
 require('../vendor/md-toc')
-var Viz = require('viz.js')
+const Viz = require('viz.js')
 const ui = getUIElements()
 
 // auto update last change
@@ -314,8 +314,9 @@ export function finishView (view) {
   // sequence diagram
   const sequences = view.find('div.sequence-diagram.raw').removeClass('raw')
   sequences.each((key, value) => {
+    let $value
     try {
-      var $value = $(value)
+      $value = $(value)
       const $ele = $(value).parent().parent()
 
       const sequence = $value
@@ -337,15 +338,16 @@ export function finishView (view) {
   // flowchart
   const flow = view.find('div.flow-chart.raw').removeClass('raw')
   flow.each((key, value) => {
+    let $value
     try {
-      var $value = $(value)
+      $value = $(value)
       const $ele = $(value).parent().parent()
 
       const chart = window.flowchart.parse($value.text())
       $value.html('')
       chart.drawSVG(value, {
         'line-width': 2,
-        'fill': 'none',
+        fill: 'none',
         'font-size': '16px',
         'font-family': "'Andale Mono', monospace"
       })
@@ -359,13 +361,14 @@ export function finishView (view) {
     }
   })
   // graphviz
-  var graphvizs = view.find('div.graphviz.raw').removeClass('raw')
+  const graphvizs = view.find('div.graphviz.raw').removeClass('raw')
   graphvizs.each(function (key, value) {
+    let $value
     try {
-      var $value = $(value)
-      var $ele = $(value).parent().parent()
+      $value = $(value)
+      const $ele = $(value).parent().parent()
 
-      var graphviz = Viz($value.text())
+      const graphviz = Viz($value.text())
       if (!graphviz) throw Error('viz.js output empty graph')
       $value.html(graphviz)
 
@@ -380,8 +383,9 @@ export function finishView (view) {
   // mermaid
   const mermaids = view.find('div.mermaid.raw').removeClass('raw')
   mermaids.each((key, value) => {
+    let $value
     try {
-      var $value = $(value)
+      $value = $(value)
       const $ele = $(value).closest('pre')
 
       window.mermaid.mermaidAPI.parse($value.text())
@@ -389,7 +393,7 @@ export function finishView (view) {
       $ele.text($value.text())
       window.mermaid.init(undefined, $ele)
     } catch (err) {
-      var errormessage = err
+      let errormessage = err
       if (err.str) {
         errormessage = err.str
       }
@@ -402,9 +406,10 @@ export function finishView (view) {
   // abc.js
   const abcs = view.find('div.abc.raw').removeClass('raw')
   abcs.each((key, value) => {
+    let $value
     try {
-      var $value = $(value)
-      var $ele = $(value).parent().parent()
+      $value = $(value)
+      const $ele = $(value).parent().parent()
 
       window.ABCJS.renderAbc(value, $value.text())
 
@@ -493,7 +498,7 @@ export function finishView (view) {
         let code = ''
         if (codeDiv.length > 0) code = codeDiv.html()
         else code = langDiv.html()
-        var result
+        let result
         if (!reallang) {
           result = {
             value: code
@@ -571,7 +576,7 @@ export function postProcess (code) {
   }
   // show yaml meta paring error
   if (md.metaError) {
-    var warning = result.find('div#meta-error')
+    let warning = result.find('div#meta-error')
     if (warning && warning.length > 0) {
       warning.text(md.metaError)
     } else {
@@ -583,14 +588,14 @@ export function postProcess (code) {
 }
 window.postProcess = postProcess
 
-var domevents = Object.getOwnPropertyNames(document).concat(Object.getOwnPropertyNames(Object.getPrototypeOf(Object.getPrototypeOf(document)))).concat(Object.getOwnPropertyNames(Object.getPrototypeOf(window))).filter(function (i) {
+const domevents = Object.getOwnPropertyNames(document).concat(Object.getOwnPropertyNames(Object.getPrototypeOf(Object.getPrototypeOf(document)))).concat(Object.getOwnPropertyNames(Object.getPrototypeOf(window))).filter(function (i) {
   return !i.indexOf('on') && (document[i] === null || typeof document[i] === 'function')
 }).filter(function (elem, pos, self) {
   return self.indexOf(elem) === pos
 })
 
 export function removeDOMEvents (view) {
-  for (var i = 0, l = domevents.length; i < l; i++) {
+  for (let i = 0, l = domevents.length; i < l; i++) {
     view.find('[' + domevents[i] + ']').removeAttr(domevents[i])
   }
 }
@@ -739,13 +744,13 @@ export function generateToc (id) {
   const target = $(`#${id}`)
   target.html('')
   /* eslint-disable no-unused-vars */
-  var toc = new window.Toc('doc', {
-    'level': 3,
-    'top': -1,
-    'class': 'toc',
-    'ulClass': 'nav',
-    'targetId': id,
-    'process': getHeaderContent
+  const toc = new window.Toc('doc', {
+    level: 3,
+    top: -1,
+    class: 'toc',
+    ulClass: 'nav',
+    targetId: id,
+    process: getHeaderContent
   })
   /* eslint-enable no-unused-vars */
   if (target.text() === 'undefined') { target.html('') }
@@ -858,7 +863,7 @@ const linkifyAnchors = (level, containingElement) => {
   const headers = containingElement.getElementsByTagName(`h${level}`)
 
   for (let i = 0, l = headers.length; i < l; i++) {
-    let header = headers[i]
+    const header = headers[i]
     if (header.getElementsByClassName('anchor').length === 0) {
       if (typeof header.id === 'undefined' || header.id === '') {
         header.id = createHeaderId(getHeaderContent(header))
@@ -903,7 +908,7 @@ export function deduplicatedHeaderId (view) {
   if (window.linkifyHeaderStyle === 'gfm') {
     // consistent with GitHub, GitLab, Pandoc & co.
     // all headers contained in the document, in order of appearance
-    const allHeaders = view.find(`:header`).toArray()
+    const allHeaders = view.find(':header').toArray()
     // list of finaly assigned header IDs
     const headerIds = new Set()
     for (let j = 0; j < allHeaders.length; j++) {
@@ -938,12 +943,12 @@ export function renderTOC (view) {
     const target = $(`#${id}`)
     target.html('')
     /* eslint-disable no-unused-vars */
-    let TOC = new window.Toc('doc', {
-      'level': 3,
-      'top': -1,
-      'class': 'toc',
-      'targetId': id,
-      'process': getHeaderContent
+    const TOC = new window.Toc('doc', {
+      level: 3,
+      top: -1,
+      class: 'toc',
+      targetId: id,
+      process: getHeaderContent
     })
     /* eslint-enable no-unused-vars */
     if (target.text() === 'undefined') { target.html('') }
@@ -991,7 +996,7 @@ function highlightRender (code, lang) {
   return result.value
 }
 
-export let md = markdownit('default', {
+export const md = markdownit('default', {
   html: true,
   breaks: true,
   langPrefix: '',
@@ -1044,7 +1049,7 @@ md.use(markdownitContainer, 'info', { render: renderContainer })
 md.use(markdownitContainer, 'warning', { render: renderContainer })
 md.use(markdownitContainer, 'danger', { render: renderContainer })
 
-let defaultImageRender = md.renderer.rules.image
+const defaultImageRender = md.renderer.rules.image
 md.renderer.rules.image = function (tokens, idx, options, env, self) {
   tokens[idx].attrJoin('class', 'raw')
   return defaultImageRender(...arguments)
@@ -1203,7 +1208,8 @@ function meta (state, start, end, silent) {
   if (!get(state, start).match(/^---$/)) return false
 
   const data = []
-  for (var line = start + 1; line < end; line++) {
+  let line
+  for (line = start + 1; line < end; line++) {
     const str = get(state, line)
     if (str.match(/^(\.{3}|-{3})$/)) break
     if (state.tShift[line] < 0) break
diff --git a/public/js/history.js b/public/js/history.js
index e0154185..b8935eb3 100644
--- a/public/js/history.js
+++ b/public/js/history.js
@@ -147,7 +147,7 @@ export function writeHistory (title, tags) {
 }
 
 function writeHistoryToStorage (title, tags) {
-  let data = store.get('notehistory')
+  const data = store.get('notehistory')
   let notehistory
   if (data && typeof data === 'string') {
     notehistory = JSON.parse(data)
@@ -220,7 +220,7 @@ export function getStorageHistory (callback) {
     if (typeof data === 'string') { data = JSON.parse(data) }
     callback(data)
   }
-  // eslint-disable-next-line standard/no-callback-literal
+  // eslint-disable-next-line node/no-callback-literal
   callback([])
 }
 
@@ -263,7 +263,7 @@ function parseToHistory (list, notehistory, callback) {
     for (let i = 0; i < notehistory.length; i++) {
       // migrate LZString encoded id to base64url encoded id
       try {
-        let id = LZString.decompressFromBase64(notehistory[i].id)
+        const id = LZString.decompressFromBase64(notehistory[i].id)
         if (id && checkNoteIdValid(id)) {
           notehistory[i].id = encodeNoteId(id)
         }
diff --git a/public/js/index.js b/public/js/index.js
index adc95461..03cae1b4 100644
--- a/public/js/index.js
+++ b/public/js/index.js
@@ -85,19 +85,49 @@ require('../css/site.css')
 
 require('highlight.js/styles/github-gist.css')
 
-var defaultTextHeight = 20
-var viewportMargin = 20
-var defaultEditorMode = 'gfm'
-
-var idleTime = 300000 // 5 mins
-var updateViewDebounce = 100
-var cursorMenuThrottle = 50
-var cursorActivityDebounce = 50
-var cursorAnimatePeriod = 100
-var supportContainers = ['success', 'info', 'warning', 'danger']
-var supportCodeModes = ['javascript', 'typescript', 'jsx', 'htmlmixed', 'htmlembedded', 'css', 'xml', 'clike', 'clojure', 'ruby', 'python', 'shell', 'php', 'sql', 'haskell', 'coffeescript', 'yaml', 'pug', 'lua', 'cmake', 'nginx', 'perl', 'sass', 'r', 'dockerfile', 'tiddlywiki', 'mediawiki', 'go', 'gherkin'].concat(hljs.listLanguages())
-var supportCharts = ['sequence', 'flow', 'graphviz', 'mermaid', 'abc']
-var supportHeaders = [
+let defaultTextHeight = 20
+let viewportMargin = 20
+const defaultEditorMode = 'gfm'
+
+const idleTime = 300000 // 5 mins
+const updateViewDebounce = 100
+const cursorMenuThrottle = 50
+const cursorActivityDebounce = 50
+const cursorAnimatePeriod = 100
+const supportContainers = ['success', 'info', 'warning', 'danger']
+const supportCodeModes = [
+  'javascript',
+  'typescript',
+  'jsx',
+  'htmlmixed',
+  'htmlembedded',
+  'css',
+  'xml',
+  'clike',
+  'clojure',
+  'ruby',
+  'python',
+  'shell',
+  'php',
+  'sql',
+  'haskell',
+  'coffeescript',
+  'yaml',
+  'pug',
+  'lua',
+  'cmake',
+  'nginx',
+  'perl',
+  'sass',
+  'r',
+  'dockerfile',
+  'tiddlywiki',
+  'mediawiki',
+  'go',
+  'gherkin'
+].concat(hljs.listLanguages())
+const supportCharts = ['sequence', 'flow', 'graphviz', 'mermaid', 'abc']
+const supportHeaders = [
   {
     text: '# h1',
     search: '#'
@@ -225,7 +255,7 @@ const supportExtraTags = [
     text: '[random color tag]',
     search: '[]',
     command: function () {
-      var color = randomColor()
+      const color = randomColor()
       return '[color=' + color + ']'
     }
   }
@@ -259,7 +289,7 @@ let visibleMD = false
 let visibleLG = false
 const isTouchDevice = 'ontouchstart' in document.documentElement
 let currentStatus = statusType.offline
-let lastInfo = {
+const lastInfo = {
   needRestore: false,
   cursor: null,
   scroll: null,
@@ -285,14 +315,14 @@ let lastInfo = {
 let personalInfo = {}
 let onlineUsers = []
 const fileTypes = {
-  'pl': 'perl',
-  'cgi': 'perl',
-  'js': 'javascript',
-  'php': 'php',
-  'sh': 'bash',
-  'rb': 'ruby',
-  'html': 'html',
-  'py': 'python'
+  pl: 'perl',
+  cgi: 'perl',
+  js: 'javascript',
+  php: 'php',
+  sh: 'bash',
+  rb: 'ruby',
+  html: 'html',
+  py: 'python'
 }
 
 // editor settings
@@ -302,7 +332,7 @@ if (!textit) {
 }
 
 const editorInstance = new Editor()
-var editor = editorInstance.init(textit)
+const editor = editorInstance.init(textit)
 
 // FIXME: global referncing in jquery-textcomplete patch
 window.editor = editor
@@ -313,7 +343,7 @@ defaultTextHeight = parseInt($('.CodeMirror').css('line-height'))
 const ui = getUIElements()
 
 // page actions
-var opts = {
+const opts = {
   lines: 11, // The number of lines to draw
   length: 20, // The length of each line
   width: 2, // The line thickness
@@ -333,11 +363,11 @@ var opts = {
 }
 
 /* eslint-disable no-unused-vars */
-var spinner = new Spinner(opts).spin(ui.spinner[0])
+const spinner = new Spinner(opts).spin(ui.spinner[0])
 /* eslint-enable no-unused-vars */
 
 // idle
-var idle = new Idle({
+const idle = new Idle({
   onAway: function () {
     idle.isAway = true
     emitUserStatus()
@@ -356,7 +386,7 @@ ui.area.codemirror.on('touchstart', function () {
   idle.onActive()
 })
 
-var haveUnreadChanges = false
+let haveUnreadChanges = false
 
 function setHaveUnreadChanges (bool) {
   if (!window.loaded) return
@@ -379,7 +409,9 @@ function updateTitleReminder () {
 function setRefreshModal (status) {
   $('#refreshModal').modal('show')
   $('#refreshModal').find('.modal-body > div').hide()
-  $('#refreshModal').find('.' + status).show()
+  $('#refreshModal')
+    .find('.' + status)
+    .show()
 }
 
 function setNeedRefresh () {
@@ -395,9 +427,9 @@ setloginStateChangeEvent(function () {
 })
 
 // visibility
-var wasFocus = false
+let wasFocus = false
 Visibility.change(function (e, state) {
-  var hidden = Visibility.hidden()
+  const hidden = Visibility.hidden()
   if (hidden) {
     if (editorHasFocus()) {
       wasFocus = true
@@ -421,7 +453,7 @@ $(document).ready(function () {
   idle.checkAway()
   checkResponsive()
   // if in smaller screen, we don't need advanced scrollbar
-  var scrollbarStyle
+  let scrollbarStyle
   if (visibleXS) {
     scrollbarStyle = 'native'
   } else {
@@ -434,7 +466,7 @@ $(document).ready(function () {
   checkEditorStyle()
 
   /* cache dom references */
-  var $body = $('body')
+  const $body = $('body')
 
   /* we need this only on touch devices */
   if (isTouchDevice) {
@@ -463,7 +495,9 @@ $(document).ready(function () {
   $('[data-toggle="tooltip"]').tooltip()
   // shortcuts
   // allow on all tags
-  key.filter = function (e) { return true }
+  key.filter = function (e) {
+    return true
+  }
   key('ctrl+alt+e', function (e) {
     changeMode(modeType.edit)
   })
@@ -488,13 +522,18 @@ $(window).resize(function () {
 })
 // when page unload
 $(window).on('unload', function () {
-// updateHistoryInner();
+  // updateHistoryInner();
 })
 $(window).on('error', function () {
   // setNeedRefresh();
 })
 
-setupSyncAreas(ui.area.codemirrorScroll, ui.area.view, ui.area.markdown, editor)
+setupSyncAreas(
+  ui.area.codemirrorScroll,
+  ui.area.view,
+  ui.area.markdown,
+  editor
+)
 
 function autoSyncscroll () {
   if (editorHasFocus()) {
@@ -504,8 +543,8 @@ function autoSyncscroll () {
   }
 }
 
-var windowResizeDebounce = 200
-var windowResize = _.debounce(windowResizeInner, windowResizeDebounce)
+const windowResizeDebounce = 200
+const windowResize = _.debounce(windowResizeInner, windowResizeDebounce)
 
 function windowResizeInner (callback) {
   checkLayout()
@@ -520,7 +559,9 @@ function windowResizeInner (callback) {
         clearMap()
         autoSyncscroll()
         updateScrollspy()
-        if (callback && typeof callback === 'function') { callback() }
+        if (callback && typeof callback === 'function') {
+          callback()
+        }
       }, 1)
     } else {
       // force it load all docs at once to prevent scroll knob blink
@@ -530,18 +571,22 @@ function windowResizeInner (callback) {
         autoSyncscroll()
         editor.setOption('viewportMargin', viewportMargin)
         // add or update user cursors
-        for (var i = 0; i < onlineUsers.length; i++) {
-          if (onlineUsers[i].id !== personalInfo.id) { buildCursor(onlineUsers[i]) }
+        for (let i = 0; i < onlineUsers.length; i++) {
+          if (onlineUsers[i].id !== personalInfo.id) {
+            buildCursor(onlineUsers[i])
+          }
         }
         updateScrollspy()
-        if (callback && typeof callback === 'function') { callback() }
+        if (callback && typeof callback === 'function') {
+          callback()
+        }
       }, 1)
     }
   }
 }
 
 function checkLayout () {
-  var navbarHieght = $('.navbar').outerHeight()
+  const navbarHieght = $('.navbar').outerHeight()
   $('body').css('padding-top', navbarHieght + 'px')
 }
 
@@ -557,22 +602,28 @@ function checkResponsive () {
   visibleLG = $('.visible-lg').is(':visible')
 
   if (visibleXS && appState.currentMode === modeType.both) {
-    if (editorHasFocus()) { changeMode(modeType.edit) } else { changeMode(modeType.view) }
+    if (editorHasFocus()) {
+      changeMode(modeType.edit)
+    } else {
+      changeMode(modeType.view)
+    }
   }
 
   emitUserStatus()
 }
 
-var lastEditorWidth = 0
-var previousFocusOnEditor = null
+let lastEditorWidth = 0
+let previousFocusOnEditor = null
 
 function checkEditorStyle () {
-  var desireHeight = editorInstance.statusBar ? (ui.area.edit.height() - editorInstance.statusBar.outerHeight()) : ui.area.edit.height()
+  let desireHeight = editorInstance.statusBar
+    ? ui.area.edit.height() - editorInstance.statusBar.outerHeight()
+    : ui.area.edit.height()
   if (editorInstance.toolBar) {
     desireHeight = desireHeight - editorInstance.toolBar.outerHeight()
   }
   // set editor height and min height based on scrollbar style and mode
-  var scrollbarStyle = editor.getOption('scrollbarStyle')
+  const scrollbarStyle = editor.getOption('scrollbarStyle')
   if (scrollbarStyle === 'overlay' || appState.currentMode === modeType.both) {
     ui.area.codemirrorScroll.css('height', desireHeight + 'px')
     ui.area.codemirrorScroll.css('min-height', '')
@@ -590,9 +641,11 @@ function checkEditorStyle () {
       maxWidth: $(window).width() * 0.7,
       minWidth: $(window).width() * 0.2,
       create: function (e, ui) {
-        $(this).parent().on('resize', function (e) {
-          e.stopPropagation()
-        })
+        $(this)
+          .parent()
+          .on('resize', function (e) {
+            e.stopPropagation()
+          })
       },
       start: function (e) {
         editor.setOption('viewportMargin', Infinity)
@@ -622,23 +675,31 @@ function checkEditorStyle () {
     ui.area.resize.handle = $('.ui-resizable-handle')
   }
   if (!ui.area.resize.syncToggle.length) {
-    ui.area.resize.syncToggle = $('<button class="btn btn-lg btn-default ui-sync-toggle" title="Toggle sync scrolling"><i class="fa fa-link fa-fw"></i></button>')
-    ui.area.resize.syncToggle.hover(function () {
-      previousFocusOnEditor = editorHasFocus()
-    }, function () {
-      previousFocusOnEditor = null
-    })
+    ui.area.resize.syncToggle = $(
+      '<button class="btn btn-lg btn-default ui-sync-toggle" title="Toggle sync scrolling"><i class="fa fa-link fa-fw"></i></button>'
+    )
+    ui.area.resize.syncToggle.hover(
+      function () {
+        previousFocusOnEditor = editorHasFocus()
+      },
+      function () {
+        previousFocusOnEditor = null
+      }
+    )
     ui.area.resize.syncToggle.click(function () {
       appState.syncscroll = !appState.syncscroll
       checkSyncToggle()
     })
     ui.area.resize.handle.append(ui.area.resize.syncToggle)
     ui.area.resize.syncToggle.hide()
-    ui.area.resize.handle.hover(function () {
-      ui.area.resize.syncToggle.stop(true, true).delay(200).fadeIn(100)
-    }, function () {
-      ui.area.resize.syncToggle.stop(true, true).delay(300).fadeOut(300)
-    })
+    ui.area.resize.handle.hover(
+      function () {
+        ui.area.resize.syncToggle.stop(true, true).delay(200).fadeIn(100)
+      },
+      function () {
+        ui.area.resize.syncToggle.stop(true, true).delay(300).fadeOut(300)
+      }
+    )
   }
 }
 
@@ -651,37 +712,53 @@ function checkSyncToggle () {
       window.preventSyncScrollToEdit = false
       syncScrollToEdit()
     }
-    ui.area.resize.syncToggle.find('i').removeClass('fa-unlink').addClass('fa-link')
+    ui.area.resize.syncToggle
+      .find('i')
+      .removeClass('fa-unlink')
+      .addClass('fa-link')
   } else {
-    ui.area.resize.syncToggle.find('i').removeClass('fa-link').addClass('fa-unlink')
+    ui.area.resize.syncToggle
+      .find('i')
+      .removeClass('fa-link')
+      .addClass('fa-unlink')
   }
 }
 
-var checkEditorScrollbar = _.debounce(function () {
+const checkEditorScrollbar = _.debounce(function () {
   editor.operation(checkEditorScrollbarInner)
 }, 50)
 
 function checkEditorScrollbarInner () {
   // workaround simple scroll bar knob
   // will get wrong position when editor height changed
-  var scrollInfo = editor.getScrollInfo()
+  const scrollInfo = editor.getScrollInfo()
   editor.scrollTo(null, scrollInfo.top - 1)
   editor.scrollTo(null, scrollInfo.top)
 }
 
 function checkTocStyle () {
   // toc right
-  var paddingRight = parseFloat(ui.area.markdown.css('padding-right'))
-  var right = ($(window).width() - (ui.area.markdown.offset().left + ui.area.markdown.outerWidth() - paddingRight))
+  const paddingRight = parseFloat(ui.area.markdown.css('padding-right'))
+  const right =
+    $(window).width() -
+    (ui.area.markdown.offset().left +
+      ui.area.markdown.outerWidth() -
+      paddingRight)
   ui.toc.toc.css('right', right + 'px')
   // affix toc left
-  var newbool
-  var rightMargin = (ui.area.markdown.parent().outerWidth() - ui.area.markdown.outerWidth()) / 2
+  let newbool
+  const rightMargin =
+    (ui.area.markdown.parent().outerWidth() - ui.area.markdown.outerWidth()) /
+    2
   // for ipad or wider device
   if (rightMargin >= 133) {
     newbool = true
-    var affixLeftMargin = (ui.toc.affix.outerWidth() - ui.toc.affix.width()) / 2
-    var left = ui.area.markdown.offset().left + ui.area.markdown.outerWidth() - affixLeftMargin
+    const affixLeftMargin =
+      (ui.toc.affix.outerWidth() - ui.toc.affix.width()) / 2
+    const left =
+      ui.area.markdown.offset().left +
+      ui.area.markdown.outerWidth() -
+      affixLeftMargin
     ui.toc.affix.css('left', left + 'px')
     ui.toc.affix.css('width', rightMargin + 'px')
   } else {
@@ -708,12 +785,12 @@ function checkTocStyle () {
 
 function showStatus (type, num) {
   currentStatus = type
-  var shortStatus = ui.toolbar.shortStatus
-  var status = ui.toolbar.status
-  var label = $('<span class="label"></span>')
-  var fa = $('<i class="fa"></i>')
-  var msg = ''
-  var shortMsg = ''
+  const shortStatus = ui.toolbar.shortStatus
+  const status = ui.toolbar.status
+  const label = $('<span class="label"></span>')
+  const fa = $('<i class="fa"></i>')
+  let msg = ''
+  let shortMsg = ''
 
   shortStatus.html('')
   status.html('')
@@ -738,7 +815,7 @@ function showStatus (type, num) {
   }
 
   label.append(fa)
-  var shortLabel = label.clone()
+  const shortLabel = label.clone()
 
   shortLabel.append(' ' + shortMsg)
   shortStatus.append(shortLabel)
@@ -761,7 +838,7 @@ function toggleMode () {
   }
 }
 
-var lastMode = null
+let lastMode = null
 
 function changeMode (type) {
   // lock navbar to prevent it hide after changeMode
@@ -771,8 +848,8 @@ function changeMode (type) {
     lastMode = appState.currentMode
     appState.currentMode = type
   }
-  var responsiveClass = 'col-lg-6 col-md-6 col-sm-6'
-  var scrollClass = 'ui-scrollable'
+  const responsiveClass = 'col-lg-6 col-md-6 col-sm-6'
+  const scrollClass = 'ui-scrollable'
   ui.area.codemirror.removeClass(scrollClass)
   ui.area.edit.removeClass(responsiveClass)
   ui.area.view.removeClass(scrollClass)
@@ -798,11 +875,20 @@ function changeMode (type) {
       break
   }
   // save mode to url
-  if (history.replaceState && window.loaded) history.replaceState(null, '', serverurl + '/' + noteid + '?' + appState.currentMode.name)
+  if (history.replaceState && window.loaded) {
+    history.replaceState(
+      null,
+      '',
+      serverurl + '/' + noteid + '?' + appState.currentMode.name
+    )
+  }
   if (appState.currentMode === modeType.view) {
     editor.getInputField().blur()
   }
-  if (appState.currentMode === modeType.edit || appState.currentMode === modeType.both) {
+  if (
+    appState.currentMode === modeType.edit ||
+    appState.currentMode === modeType.both
+  ) {
     // add and update status bar
     if (!editorInstance.statusBar) {
       editorInstance.addStatusBar()
@@ -820,7 +906,10 @@ function changeMode (type) {
     $(document.body).css('background-color', 'white')
     updateView()
   } else {
-    $(document.body).css('background-color', ui.area.codemirror.css('background-color'))
+    $(document.body).css(
+      'background-color',
+      ui.area.codemirror.css('background-color')
+    )
   }
   // check resizable editor style
   if (appState.currentMode === modeType.both) {
@@ -864,15 +953,18 @@ function changeMode (type) {
   ui.toolbar.both.removeClass('active')
   ui.toolbar.edit.removeClass('active')
   ui.toolbar.view.removeClass('active')
-  var modeIcon = ui.toolbar.mode.find('i')
+  const modeIcon = ui.toolbar.mode.find('i')
   modeIcon.removeClass('fa-pencil').removeClass('fa-eye')
-  if (ui.area.edit.is(':visible') && ui.area.view.is(':visible')) { // both
+  if (ui.area.edit.is(':visible') && ui.area.view.is(':visible')) {
+    // both
     ui.toolbar.both.addClass('active')
     modeIcon.addClass('fa-eye')
-  } else if (ui.area.edit.is(':visible')) { // edit
+  } else if (ui.area.edit.is(':visible')) {
+    // edit
     ui.toolbar.edit.addClass('active')
     modeIcon.addClass('fa-eye')
-  } else if (ui.area.view.is(':visible')) { // view
+  } else if (ui.area.view.is(':visible')) {
+    // view
     ui.toolbar.view.addClass('active')
     modeIcon.addClass('fa-pencil')
   }
@@ -883,17 +975,27 @@ function lockNavbar () {
   $('.navbar').addClass('locked')
 }
 
-var unlockNavbar = _.debounce(function () {
+const unlockNavbar = _.debounce(function () {
   $('.navbar').removeClass('locked')
 }, 200)
 
 function showMessageModal (title, header, href, text, success) {
-  var modal = $('.message-modal')
+  const modal = $('.message-modal')
   modal.find('.modal-title').html(title)
   modal.find('.modal-body h5').html(header)
-  if (href) { modal.find('.modal-body a').attr('href', href).text(text) } else { modal.find('.modal-body a').removeAttr('href').text(text) }
-  modal.find('.modal-footer button').removeClass('btn-default btn-success btn-danger')
-  if (success) { modal.find('.modal-footer button').addClass('btn-success') } else { modal.find('.modal-footer button').addClass('btn-danger') }
+  if (href) {
+    modal.find('.modal-body a').attr('href', href).text(text)
+  } else {
+    modal.find('.modal-body a').removeAttr('href').text(text)
+  }
+  modal
+    .find('.modal-footer button')
+    .removeClass('btn-default btn-success btn-danger')
+  if (success) {
+    modal.find('.modal-footer button').addClass('btn-success')
+  } else {
+    modal.find('.modal-footer button').addClass('btn-danger')
+  }
   modal.modal('show')
 }
 
@@ -923,9 +1025,9 @@ ui.toolbar.extra.slide.attr('href', noteurl + '/slide')
 ui.toolbar.download.markdown.click(function (e) {
   e.preventDefault()
   e.stopPropagation()
-  var filename = renderFilename(ui.area.markdown) + '.md'
-  var markdown = editor.getValue()
-  var blob = new Blob([markdown], {
+  const filename = renderFilename(ui.area.markdown) + '.md'
+  const markdown = editor.getValue()
+  const blob = new Blob([markdown], {
     type: 'text/markdown;charset=utf-8'
   })
   saveAs(blob, filename, true)
@@ -945,12 +1047,12 @@ ui.toolbar.download.rawhtml.click(function (e) {
 // export to dropbox
 ui.toolbar.export.dropbox.click(function (event) {
   event.preventDefault()
-  var filename = renderFilename(ui.area.markdown) + '.md'
-  var options = {
+  const filename = renderFilename(ui.area.markdown) + '.md'
+  const options = {
     files: [
       {
-        'url': noteurl + '/download',
-        'filename': filename
+        url: noteurl + '/download',
+        filename: filename
       }
     ],
     error: function (errorMessage) {
@@ -971,25 +1073,48 @@ ui.toolbar.export.snippet.click(function () {
       $('#snippetExportModalVersion').val(data.version)
       $('#snippetExportModalLoading').hide()
       $('#snippetExportModal').modal('toggle')
-      $('#snippetExportModalProjects').find('option').remove().end().append('<option value="init" selected="selected" disabled="disabled">Select From Available Projects</option>')
+      $('#snippetExportModalProjects')
+        .find('option')
+        .remove()
+        .end()
+        .append(
+          '<option value="init" selected="selected" disabled="disabled">Select From Available Projects</option>'
+        )
       if (data.projects) {
         data.projects.sort(function (a, b) {
-          return (a.path_with_namespace < b.path_with_namespace) ? -1 : ((a.path_with_namespace > b.path_with_namespace) ? 1 : 0)
+          return a.path_with_namespace < b.path_with_namespace
+            ? -1
+            : a.path_with_namespace > b.path_with_namespace
+              ? 1
+              : 0
         })
         data.projects.forEach(function (project) {
-          if (!project.snippets_enabled ||
-                        (project.permissions.project_access === null && project.permissions.group_access === null) ||
-                        (project.permissions.project_access !== null && project.permissions.project_access.access_level < 20)) {
+          if (
+            !project.snippets_enabled ||
+            (project.permissions.project_access === null &&
+              project.permissions.group_access === null) ||
+            (project.permissions.project_access !== null &&
+              project.permissions.project_access.access_level < 20)
+          ) {
             return
           }
-          $('<option>').val(project.id).text(project.path_with_namespace).appendTo('#snippetExportModalProjects')
+          $('<option>')
+            .val(project.id)
+            .text(project.path_with_namespace)
+            .appendTo('#snippetExportModalProjects')
         })
         $('#snippetExportModalProjects').prop('disabled', false)
       }
       $('#snippetExportModalLoading').hide()
     })
     .fail(function (data) {
-      showMessageModal('<i class="fa fa-gitlab"></i> Import from Snippet', 'Unable to fetch gitlab parameters :(', '', '', false)
+      showMessageModal(
+        '<i class="fa fa-gitlab"></i> Import from Snippet',
+        'Unable to fetch gitlab parameters :(',
+        '',
+        '',
+        false
+      )
     })
     .always(function () {
       ui.spinner.hide()
@@ -998,10 +1123,10 @@ ui.toolbar.export.snippet.click(function () {
 // import from dropbox
 ui.toolbar.import.dropbox.click(function (event) {
   event.preventDefault()
-  var options = {
+  const options = {
     success: function (files) {
       ui.spinner.show()
-      var url = files[0].link
+      const url = files[0].link
       importFromUrl(url)
     },
     linkType: 'direct',
@@ -1026,25 +1151,48 @@ ui.toolbar.import.snippet.click(function () {
       $('#snippetImportModalConfirm').prop('disabled', false)
       $('#snippetImportModalLoading').hide()
       $('#snippetImportModal').modal('toggle')
-      $('#snippetImportModalProjects').find('option').remove().end().append('<option value="init" selected="selected" disabled="disabled">Select From Available Projects</option>')
+      $('#snippetImportModalProjects')
+        .find('option')
+        .remove()
+        .end()
+        .append(
+          '<option value="init" selected="selected" disabled="disabled">Select From Available Projects</option>'
+        )
       if (data.projects) {
         data.projects.sort(function (a, b) {
-          return (a.path_with_namespace < b.path_with_namespace) ? -1 : ((a.path_with_namespace > b.path_with_namespace) ? 1 : 0)
+          return a.path_with_namespace < b.path_with_namespace
+            ? -1
+            : a.path_with_namespace > b.path_with_namespace
+              ? 1
+              : 0
         })
         data.projects.forEach(function (project) {
-          if (!project.snippets_enabled ||
-                        (project.permissions.project_access === null && project.permissions.group_access === null) ||
-                        (project.permissions.project_access !== null && project.permissions.project_access.access_level < 20)) {
+          if (
+            !project.snippets_enabled ||
+            (project.permissions.project_access === null &&
+              project.permissions.group_access === null) ||
+            (project.permissions.project_access !== null &&
+              project.permissions.project_access.access_level < 20)
+          ) {
             return
           }
-          $('<option>').val(project.id).text(project.path_with_namespace).appendTo('#snippetImportModalProjects')
+          $('<option>')
+            .val(project.id)
+            .text(project.path_with_namespace)
+            .appendTo('#snippetImportModalProjects')
         })
         $('#snippetImportModalProjects').prop('disabled', false)
       }
       $('#snippetImportModalLoading').hide()
     })
     .fail(function (data) {
-      showMessageModal('<i class="fa fa-gitlab"></i> Import from Snippet', 'Unable to fetch gitlab parameters :(', '', '', false)
+      showMessageModal(
+        '<i class="fa fa-gitlab"></i> Import from Snippet',
+        'Unable to fetch gitlab parameters :(',
+        '',
+        '',
+        false
+      )
     })
     .always(function () {
       ui.spinner.hide()
@@ -1060,15 +1208,15 @@ $('a[href="#"]').click(function (e) {
 })
 
 // modal actions
-var revisions = []
-var revisionViewer = null
-var revisionInsert = []
-var revisionDelete = []
-var revisionInsertAnnotation = null
-var revisionDeleteAnnotation = null
-var revisionList = ui.modal.revision.find('.ui-revision-list')
-var revision = null
-var revisionTime = null
+let revisions = []
+let revisionViewer = null
+let revisionInsert = []
+let revisionDelete = []
+let revisionInsertAnnotation = null
+let revisionDeleteAnnotation = null
+const revisionList = ui.modal.revision.find('.ui-revision-list')
+let revision = null
+let revisionTime = null
 ui.modal.revision.on('show.bs.modal', function (e) {
   $.get(noteurl + '/revision')
     .done(function (data) {
@@ -1087,7 +1235,7 @@ ui.modal.revision.on('show.bs.modal', function (e) {
 })
 function checkRevisionViewer () {
   if (revisionViewer) {
-    var container = $(revisionViewer.display.wrapper).parent()
+    const container = $(revisionViewer.display.wrapper).parent()
     $(revisionViewer.display.scroller).css('height', container.height() + 'px')
     revisionViewer.refresh()
   }
@@ -1097,23 +1245,27 @@ $(window).resize(checkRevisionViewer)
 function parseRevisions (_revisions) {
   if (_revisions.length !== revisions) {
     revisions = _revisions
-    var lastRevision = null
+    let lastRevision = null
     if (revisionList.children().length > 0) {
       lastRevision = revisionList.find('.active').attr('data-revision-time')
     }
     revisionList.html('')
-    for (var i = 0; i < revisions.length; i++) {
-      var revision = revisions[i]
-      var item = $('<a class="list-group-item"></a>')
+    for (let i = 0; i < revisions.length; i++) {
+      const revision = revisions[i]
+      const item = $('<a class="list-group-item"></a>')
       item.attr('data-revision-time', revision.time)
       if (lastRevision === revision.time) item.addClass('active')
-      var itemHeading = $('<h5 class="list-group-item-heading"></h5>')
-      itemHeading.html('<i class="fa fa-clock-o"></i> ' + moment(revision.time).format('llll'))
-      var itemText = $('<p class="list-group-item-text"></p>')
-      itemText.html('<i class="fa fa-file-text"></i> Length: ' + revision.length)
+      const itemHeading = $('<h5 class="list-group-item-heading"></h5>')
+      itemHeading.html(
+        '<i class="fa fa-clock-o"></i> ' + moment(revision.time).format('llll')
+      )
+      const itemText = $('<p class="list-group-item-text"></p>')
+      itemText.html(
+        '<i class="fa fa-file-text"></i> Length: ' + revision.length
+      )
       item.append(itemHeading).append(itemText)
       item.click(function (e) {
-        var time = $(this).attr('data-revision-time')
+        const time = $(this).attr('data-revision-time')
         selectRevision(time)
       })
       revisionList.append(item)
@@ -1129,52 +1281,59 @@ function selectRevision (time) {
     .done(function (data) {
       revision = data
       revisionTime = time
-      var lastScrollInfo = revisionViewer.getScrollInfo()
+      const lastScrollInfo = revisionViewer.getScrollInfo()
       revisionList.children().removeClass('active')
-      revisionList.find('[data-revision-time="' + time + '"]').addClass('active')
-      var content = revision.content
+      revisionList
+        .find('[data-revision-time="' + time + '"]')
+        .addClass('active')
+      const content = revision.content
       revisionViewer.setValue(content)
       revisionViewer.scrollTo(null, lastScrollInfo.top)
       revisionInsert = []
       revisionDelete = []
       // mark the text which have been insert or delete
       if (revision.patch.length > 0) {
-        var bias = 0
-        for (var j = 0; j < revision.patch.length; j++) {
-          var patch = revision.patch[j]
-          var currIndex = patch.start1 + bias
-          for (var i = 0; i < patch.diffs.length; i++) {
-            var diff = patch.diffs[i]
+        let bias = 0
+        for (let j = 0; j < revision.patch.length; j++) {
+          const patch = revision.patch[j]
+          let currIndex = patch.start1 + bias
+          for (let i = 0; i < patch.diffs.length; i++) {
+            const diff = patch.diffs[i]
             // ignore if diff only contains line breaks
-            if ((diff[1].match(/\n/g) || []).length === diff[1].length) continue
-            var prePos
-            var postPos
+            if ((diff[1].match(/\n/g) || []).length === diff[1].length) { continue }
+            let prePos, postPos
             switch (diff[0]) {
               case 0: // retain
                 currIndex += diff[1].length
                 break
               case 1: // insert
                 prePos = revisionViewer.posFromIndex(currIndex)
-                postPos = revisionViewer.posFromIndex(currIndex + diff[1].length)
+                postPos = revisionViewer.posFromIndex(
+                  currIndex + diff[1].length
+                )
                 revisionInsert.push({
                   from: prePos,
                   to: postPos
                 })
                 revisionViewer.markText(prePos, postPos, {
-                  css: 'background-color: rgba(230,255,230,0.7); text-decoration: underline;'
+                  css:
+                    'background-color: rgba(230,255,230,0.7); text-decoration: underline;'
                 })
                 currIndex += diff[1].length
                 break
               case -1: // delete
                 prePos = revisionViewer.posFromIndex(currIndex)
                 revisionViewer.replaceRange(diff[1], prePos)
-                postPos = revisionViewer.posFromIndex(currIndex + diff[1].length)
+                postPos = revisionViewer.posFromIndex(
+                  currIndex + diff[1].length
+                )
                 revisionDelete.push({
                   from: prePos,
                   to: postPos
                 })
                 revisionViewer.markText(prePos, postPos, {
-                  css: 'background-color: rgba(255,230,230,0.7); text-decoration: line-through;'
+                  css:
+                    'background-color: rgba(255,230,230,0.7); text-decoration: line-through;'
                 })
                 bias += diff[1].length
                 currIndex += diff[1].length
@@ -1198,7 +1357,7 @@ function selectRevision (time) {
 }
 function initRevisionViewer () {
   if (revisionViewer) return
-  var revisionViewerTextArea = document.getElementById('revisionViewer')
+  const revisionViewerTextArea = document.getElementById('revisionViewer')
   revisionViewer = CodeMirror.fromTextArea(revisionViewerTextArea, {
     mode: defaultEditorMode,
     viewportMargin: viewportMargin,
@@ -1213,14 +1372,19 @@ function initRevisionViewer () {
     autoRefresh: true,
     scrollbarStyle: 'overlay'
   })
-  revisionInsertAnnotation = revisionViewer.annotateScrollbar({ className: 'CodeMirror-insert-match' })
-  revisionDeleteAnnotation = revisionViewer.annotateScrollbar({ className: 'CodeMirror-delete-match' })
+  revisionInsertAnnotation = revisionViewer.annotateScrollbar({
+    className: 'CodeMirror-insert-match'
+  })
+  revisionDeleteAnnotation = revisionViewer.annotateScrollbar({
+    className: 'CodeMirror-delete-match'
+  })
   checkRevisionViewer()
 }
 $('#revisionModalDownload').click(function () {
   if (!revision) return
-  var filename = renderFilename(ui.area.markdown) + '_' + revisionTime + '.md'
-  var blob = new Blob([revision.content], {
+  const filename =
+    renderFilename(ui.area.markdown) + '_' + revisionTime + '.md'
+  const blob = new Blob([revision.content], {
     type: 'text/markdown;charset=utf-8'
   })
   saveAs(blob, filename, true)
@@ -1232,17 +1396,34 @@ $('#revisionModalRevert').click(function () {
 })
 // snippet projects
 ui.modal.snippetImportProjects.change(function () {
-  var accesstoken = $('#snippetImportModalAccessToken').val()
-  var baseURL = $('#snippetImportModalBaseURL').val()
-  var project = $('#snippetImportModalProjects').val()
-  var version = $('#snippetImportModalVersion').val()
+  const accesstoken = $('#snippetImportModalAccessToken').val()
+  const baseURL = $('#snippetImportModalBaseURL').val()
+  const project = $('#snippetImportModalProjects').val()
+  const version = $('#snippetImportModalVersion').val()
   $('#snippetImportModalLoading').show()
   $('#snippetImportModalContent').val('/projects/' + project)
-  $.get(baseURL + '/api/' + version + '/projects/' + project + '/snippets?access_token=' + accesstoken)
+  $.get(
+    baseURL +
+      '/api/' +
+      version +
+      '/projects/' +
+      project +
+      '/snippets?access_token=' +
+      accesstoken
+  )
     .done(function (data) {
-      $('#snippetImportModalSnippets').find('option').remove().end().append('<option value="init" selected="selected" disabled="disabled">Select From Available Snippets</option>')
+      $('#snippetImportModalSnippets')
+        .find('option')
+        .remove()
+        .end()
+        .append(
+          '<option value="init" selected="selected" disabled="disabled">Select From Available Snippets</option>'
+        )
       data.forEach(function (snippet) {
-        $('<option>').val(snippet.id).text(snippet.title).appendTo($('#snippetImportModalSnippets'))
+        $('<option>')
+          .val(snippet.id)
+          .text(snippet.title)
+          .appendTo($('#snippetImportModalSnippets'))
       })
       $('#snippetImportModalLoading').hide()
       $('#snippetImportModalSnippets').prop('disabled', false)
@@ -1259,44 +1440,68 @@ ui.modal.snippetImportProjects.change(function () {
 })
 // snippet snippets
 ui.modal.snippetImportSnippets.change(function () {
-  var snippet = $('#snippetImportModalSnippets').val()
-  $('#snippetImportModalContent').val($('#snippetImportModalContent').val() + '/snippets/' + snippet)
+  const snippet = $('#snippetImportModalSnippets').val()
+  $('#snippetImportModalContent').val(
+    $('#snippetImportModalContent').val() + '/snippets/' + snippet
+  )
 })
 
 function scrollToTop () {
   if (appState.currentMode === modeType.both) {
-    if (editor.getScrollInfo().top !== 0) { editor.scrollTo(0, 0) } else {
-      ui.area.view.animate({
-        scrollTop: 0
-      }, 100, 'linear')
+    if (editor.getScrollInfo().top !== 0) {
+      editor.scrollTo(0, 0)
+    } else {
+      ui.area.view.animate(
+        {
+          scrollTop: 0
+        },
+        100,
+        'linear'
+      )
     }
   } else {
-    $('body, html').stop(true, true).animate({
-      scrollTop: 0
-    }, 100, 'linear')
+    $('body, html').stop(true, true).animate(
+      {
+        scrollTop: 0
+      },
+      100,
+      'linear'
+    )
   }
 }
 
 function scrollToBottom () {
   if (appState.currentMode === modeType.both) {
-    var scrollInfo = editor.getScrollInfo()
-    var scrollHeight = scrollInfo.height
-    if (scrollInfo.top !== scrollHeight) { editor.scrollTo(0, scrollHeight * 2) } else {
-      ui.area.view.animate({
-        scrollTop: ui.area.view[0].scrollHeight
-      }, 100, 'linear')
+    const scrollInfo = editor.getScrollInfo()
+    const scrollHeight = scrollInfo.height
+    if (scrollInfo.top !== scrollHeight) {
+      editor.scrollTo(0, scrollHeight * 2)
+    } else {
+      ui.area.view.animate(
+        {
+          scrollTop: ui.area.view[0].scrollHeight
+        },
+        100,
+        'linear'
+      )
     }
   } else {
-    $('body, html').stop(true, true).animate({
-      scrollTop: $(document.body)[0].scrollHeight
-    }, 100, 'linear')
+    $('body, html')
+      .stop(true, true)
+      .animate(
+        {
+          scrollTop: $(document.body)[0].scrollHeight
+        },
+        100,
+        'linear'
+      )
   }
 }
 
 window.scrollToTop = scrollToTop
 window.scrollToBottom = scrollToBottom
 
-var enoughForAffixToc = true
+let enoughForAffixToc = true
 
 // scrollspy
 function generateScrollspy () {
@@ -1320,29 +1525,53 @@ function generateScrollspy () {
 }
 
 function updateScrollspy () {
-  var headers = ui.area.markdown.find('h1, h2, h3').toArray()
-  var headerMap = []
-  for (var i = 0; i < headers.length; i++) {
-    headerMap.push($(headers[i]).offset().top - parseInt($(headers[i]).css('margin-top')))
+  const headers = ui.area.markdown.find('h1, h2, h3').toArray()
+  const headerMap = []
+  for (let i = 0; i < headers.length; i++) {
+    headerMap.push(
+      $(headers[i]).offset().top - parseInt($(headers[i]).css('margin-top'))
+    )
   }
-  applyScrollspyActive($(window).scrollTop(), headerMap, headers,
-    $('.scrollspy-body'), 0)
-  var offset = ui.area.view.scrollTop() - ui.area.view.offset().top
-  applyScrollspyActive(ui.area.view.scrollTop(), headerMap, headers,
-    $('.scrollspy-view'), offset - 10)
+  applyScrollspyActive(
+    $(window).scrollTop(),
+    headerMap,
+    headers,
+    $('.scrollspy-body'),
+    0
+  )
+  const offset = ui.area.view.scrollTop() - ui.area.view.offset().top
+  applyScrollspyActive(
+    ui.area.view.scrollTop(),
+    headerMap,
+    headers,
+    $('.scrollspy-view'),
+    offset - 10
+  )
 }
 
 function applyScrollspyActive (top, headerMap, headers, target, offset) {
-  var index = 0
-  for (var i = headerMap.length - 1; i >= 0; i--) {
-    if (top >= (headerMap[i] + offset) && headerMap[i + 1] && top < (headerMap[i + 1] + offset)) {
+  let index = 0
+  for (let i = headerMap.length - 1; i >= 0; i--) {
+    if (
+      top >= headerMap[i] + offset &&
+      headerMap[i + 1] &&
+      top < headerMap[i + 1] + offset
+    ) {
       index = i
       break
     }
   }
-  var header = $(headers[index])
-  var active = target.find('a[href="#' + header.attr('id') + '"]')
-  active.closest('li').addClass('active').parent().closest('li').addClass('active').parent().closest('li').addClass('active')
+  const header = $(headers[index])
+  const active = target.find('a[href="#' + header.attr('id') + '"]')
+  active
+    .closest('li')
+    .addClass('active')
+    .parent()
+    .closest('li')
+    .addClass('active')
+    .parent()
+    .closest('li')
+    .addClass('active')
 }
 
 // clipboard modal
@@ -1354,7 +1583,7 @@ $('#clipboardModalClear').click(function () {
   $('#clipboardModalContent').html('')
 })
 $('#clipboardModalConfirm').click(function () {
-  var data = $('#clipboardModalContent').html()
+  const data = $('#clipboardModalContent').html()
   if (data) {
     parseToEditor(data)
     $('#clipboardModal').modal('hide')
@@ -1372,22 +1601,34 @@ $('#gistImportModalClear').click(function () {
   $('#gistImportModalContent').val('')
 })
 $('#gistImportModalConfirm').click(function () {
-  var gisturl = $('#gistImportModalContent').val()
+  const gisturl = $('#gistImportModalContent').val()
   if (!gisturl) return
   $('#gistImportModal').modal('hide')
   $('#gistImportModalContent').val('')
   if (!isValidURL(gisturl)) {
-    showMessageModal('<i class="fa fa-github"></i> Import from Gist', 'Not a valid URL :(', '', '', false)
+    showMessageModal(
+      '<i class="fa fa-github"></i> Import from Gist',
+      'Not a valid URL :(',
+      '',
+      '',
+      false
+    )
   } else {
-    var hostname = url('hostname', gisturl)
+    const hostname = url('hostname', gisturl)
     if (hostname !== 'gist.github.com') {
-      showMessageModal('<i class="fa fa-github"></i> Import from Gist', 'Not a valid Gist URL :(', '', '', false)
+      showMessageModal(
+        '<i class="fa fa-github"></i> Import from Gist',
+        'Not a valid Gist URL :(',
+        '',
+        '',
+        false
+      )
     } else {
       ui.spinner.show()
       $.get('https://api.github.com/gists/' + url('-1', gisturl))
         .done(function (data) {
           if (data.files) {
-            var contents = ''
+            let contents = ''
             Object.keys(data.files).forEach(function (key) {
               contents += key
               contents += '\n---\n'
@@ -1396,11 +1637,23 @@ $('#gistImportModalConfirm').click(function () {
             })
             replaceAll(contents)
           } else {
-            showMessageModal('<i class="fa fa-github"></i> Import from Gist', 'Unable to fetch gist files :(', '', '', false)
+            showMessageModal(
+              '<i class="fa fa-github"></i> Import from Gist',
+              'Unable to fetch gist files :(',
+              '',
+              '',
+              false
+            )
           }
         })
         .fail(function (data) {
-          showMessageModal('<i class="fa fa-github"></i> Import from Gist', 'Not a valid Gist URL :(', '', JSON.stringify(data), false)
+          showMessageModal(
+            '<i class="fa fa-github"></i> Import from Gist',
+            'Not a valid Gist URL :(',
+            '',
+            JSON.stringify(data),
+            false
+          )
         })
         .always(function () {
           ui.spinner.hide()
@@ -1417,21 +1670,32 @@ $('#snippetImportModalClear').click(function () {
   $('#snippetImportModalSnippets').prop('disabled', true)
 })
 $('#snippetImportModalConfirm').click(function () {
-  var snippeturl = $('#snippetImportModalContent').val()
+  const snippeturl = $('#snippetImportModalContent').val()
   if (!snippeturl) return
   $('#snippetImportModal').modal('hide')
   $('#snippetImportModalContent').val('')
   if (!/^.+\/snippets\/.+$/.test(snippeturl)) {
-    showMessageModal('<i class="fa fa-github"></i> Import from Snippet', 'Not a valid Snippet URL :(', '', '', false)
+    showMessageModal(
+      '<i class="fa fa-github"></i> Import from Snippet',
+      'Not a valid Snippet URL :(',
+      '',
+      '',
+      false
+    )
   } else {
     ui.spinner.show()
-    var accessToken = '?access_token=' + $('#snippetImportModalAccessToken').val()
-    var fullURL = $('#snippetImportModalBaseURL').val() + '/api/' + $('#snippetImportModalVersion').val() + snippeturl
+    const accessToken =
+      '?access_token=' + $('#snippetImportModalAccessToken').val()
+    const fullURL =
+      $('#snippetImportModalBaseURL').val() +
+      '/api/' +
+      $('#snippetImportModalVersion').val() +
+      snippeturl
     $.get(fullURL + accessToken)
       .done(function (data) {
-        var content = '# ' + (data.title || 'Snippet Import')
-        var fileInfo = data.file_name.split('.')
-        fileInfo[1] = (fileInfo[1]) ? fileInfo[1] : 'md'
+        let content = '# ' + (data.title || 'Snippet Import')
+        const fileInfo = data.file_name.split('.')
+        fileInfo[1] = fileInfo[1] ? fileInfo[1] : 'md'
         $.get(fullURL + '/raw' + accessToken)
           .done(function (raw) {
             if (raw) {
@@ -1447,82 +1711,147 @@ $('#snippetImportModalConfirm').click(function () {
             }
           })
           .fail(function (data) {
-            showMessageModal('<i class="fa fa-gitlab"></i> Import from Snippet', 'Not a valid Snippet URL :(', '', JSON.stringify(data), false)
+            showMessageModal(
+              '<i class="fa fa-gitlab"></i> Import from Snippet',
+              'Not a valid Snippet URL :(',
+              '',
+              JSON.stringify(data),
+              false
+            )
           })
           .always(function () {
             ui.spinner.hide()
           })
       })
       .fail(function (data) {
-        showMessageModal('<i class="fa fa-gitlab"></i> Import from Snippet', 'Not a valid Snippet URL :(', '', JSON.stringify(data), false)
+        showMessageModal(
+          '<i class="fa fa-gitlab"></i> Import from Snippet',
+          'Not a valid Snippet URL :(',
+          '',
+          JSON.stringify(data),
+          false
+        )
       })
   }
 })
 
 // snippet export modal
 $('#snippetExportModalConfirm').click(function () {
-  var accesstoken = $('#snippetExportModalAccessToken').val()
-  var baseURL = $('#snippetExportModalBaseURL').val()
-  var version = $('#snippetExportModalVersion').val()
+  const accesstoken = $('#snippetExportModalAccessToken').val()
+  const baseURL = $('#snippetExportModalBaseURL').val()
+  const version = $('#snippetExportModalVersion').val()
 
-  var data = {
+  const data = {
     title: $('#snippetExportModalTitle').val(),
     file_name: $('#snippetExportModalFileName').val(),
     code: editor.getValue(),
     visibility_level: $('#snippetExportModalVisibility').val(),
-    visibility: $('#snippetExportModalVisibility').val() === '0' ? 'private' : ($('#snippetExportModalVisibility').val() === '10' ? 'internal' : 'private')
-  }
-
-  if (!data.title || !data.file_name || !data.code || !data.visibility_level || !$('#snippetExportModalProjects').val()) return
+    visibility:
+      $('#snippetExportModalVisibility').val() === '0'
+        ? 'private'
+        : $('#snippetExportModalVisibility').val() === '10'
+          ? 'internal'
+          : 'private'
+  }
+
+  if (
+    !data.title ||
+    !data.file_name ||
+    !data.code ||
+    !data.visibility_level ||
+    !$('#snippetExportModalProjects').val()
+  ) { return }
   $('#snippetExportModalLoading').show()
-  var fullURL = baseURL + '/api/' + version + '/projects/' + $('#snippetExportModalProjects').val() + '/snippets?access_token=' + accesstoken
-  $.post(fullURL
-    , data
-    , function (ret) {
-      $('#snippetExportModalLoading').hide()
-      $('#snippetExportModal').modal('hide')
-      var redirect = baseURL + '/' + $("#snippetExportModalProjects option[value='" + $('#snippetExportModalProjects').val() + "']").text() + '/snippets/' + ret.id
-      showMessageModal('<i class="fa fa-gitlab"></i> Export to Snippet', 'Export Successful!', redirect, 'View Snippet Here', true)
-    }
-  )
+  const fullURL =
+    baseURL +
+    '/api/' +
+    version +
+    '/projects/' +
+    $('#snippetExportModalProjects').val() +
+    '/snippets?access_token=' +
+    accesstoken
+  $.post(fullURL, data, function (ret) {
+    $('#snippetExportModalLoading').hide()
+    $('#snippetExportModal').modal('hide')
+    const redirect =
+      baseURL +
+      '/' +
+      $(
+        "#snippetExportModalProjects option[value='" +
+          $('#snippetExportModalProjects').val() +
+          "']"
+      ).text() +
+      '/snippets/' +
+      ret.id
+    showMessageModal(
+      '<i class="fa fa-gitlab"></i> Export to Snippet',
+      'Export Successful!',
+      redirect,
+      'View Snippet Here',
+      true
+    )
+  })
 })
 
 function parseToEditor (data) {
-  var turndownService = new TurndownService({
+  const turndownService = new TurndownService({
     defaultReplacement: function (innerHTML, node) {
       return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML
     }
   })
-  var parsed = turndownService.turndown(data)
-  if (parsed) { replaceAll(parsed) }
+  const parsed = turndownService.turndown(data)
+  if (parsed) {
+    replaceAll(parsed)
+  }
 }
 
 function replaceAll (data) {
-  editor.replaceRange(data, {
-    line: 0,
-    ch: 0
-  }, {
-    line: editor.lastLine(),
-    ch: editor.lastLine().length
-  }, '+input')
+  editor.replaceRange(
+    data,
+    {
+      line: 0,
+      ch: 0
+    },
+    {
+      line: editor.lastLine(),
+      ch: editor.lastLine().length
+    },
+    '+input'
+  )
 }
 
 function importFromUrl (url) {
   // console.debug(url);
   if (!url) return
   if (!isValidURL(url)) {
-    showMessageModal('<i class="fa fa-cloud-download"></i> Import from URL', 'Not a valid URL :(', '', '', false)
+    showMessageModal(
+      '<i class="fa fa-cloud-download"></i> Import from URL',
+      'Not a valid URL :(',
+      '',
+      '',
+      false
+    )
     return
   }
   $.ajax({
     method: 'GET',
     url: url,
     success: function (data) {
-      var extension = url.split('.').pop()
-      if (extension === 'html') { parseToEditor(data) } else { replaceAll(data) }
+      const extension = url.split('.').pop()
+      if (extension === 'html') {
+        parseToEditor(data)
+      } else {
+        replaceAll(data)
+      }
     },
     error: function (data) {
-      showMessageModal('<i class="fa fa-cloud-download"></i> Import from URL', 'Import failed :(', '', JSON.stringify(data), false)
+      showMessageModal(
+        '<i class="fa fa-cloud-download"></i> Import from URL',
+        'Import failed :(',
+        '',
+        JSON.stringify(data),
+        false
+      )
     },
     complete: function () {
       ui.spinner.hide()
@@ -1584,8 +1913,8 @@ $('.ui-delete-modal-confirm').click(function () {
 })
 
 function toggleNightMode () {
-  var $body = $('body')
-  var isActive = ui.toolbar.night.hasClass('active')
+  const $body = $('body')
+  const isActive = ui.toolbar.night.hasClass('active')
   if (isActive) {
     $body.removeClass('night')
     appState.nightMode = false
@@ -1613,8 +1942,8 @@ function updatePermission (newPermission) {
     permission = newPermission
     if (window.loaded) refreshView()
   }
-  var label = null
-  var title = null
+  let label = null
+  let title = null
   switch (permission) {
     case 'freely':
       label = '<i class="fa fa-leaf"></i> Freely'
@@ -1641,7 +1970,11 @@ function updatePermission (newPermission) {
       title = 'Only owner can view & edit'
       break
   }
-  if (personalInfo.userid && window.owner && personalInfo.userid === window.owner) {
+  if (
+    personalInfo.userid &&
+    window.owner &&
+    personalInfo.userid === window.owner
+  ) {
     label += ' <i class="fa fa-caret-down"></i>'
     ui.infobar.permission.label.removeClass('disabled')
   } else {
@@ -1651,7 +1984,7 @@ function updatePermission (newPermission) {
 }
 
 function havePermission () {
-  var bool = false
+  let bool = false
   switch (permission) {
     case 'freely':
       bool = true
@@ -1680,8 +2013,8 @@ function havePermission () {
 window.havePermission = havePermission
 
 // socket.io actions
-var io = require('socket.io-client')
-var socket = io.connect({
+const io = require('socket.io-client')
+const socket = io.connect({
   path: urlpath ? '/' + urlpath + '/socket.io/' : '',
   query: {
     noteId: noteid
@@ -1690,13 +2023,17 @@ var socket = io.connect({
   reconnectionAttempts: 20 // retry 20 times on connect failed
 })
 // overwrite original event for checking login state
-var on = socket.on
+const on = socket.on
 socket.on = function () {
-  if (!checkLoginStateChanged() && !needRefresh) { return on.apply(socket, arguments) }
+  if (!checkLoginStateChanged() && !needRefresh) {
+    return on.apply(socket, arguments)
+  }
 }
-var emit = socket.emit
+const emit = socket.emit
 socket.emit = function () {
-  if (!checkLoginStateChanged() && !needRefresh) { emit.apply(socket, arguments) }
+  if (!checkLoginStateChanged() && !needRefresh) {
+    emit.apply(socket, arguments)
+  }
 }
 socket.on('info', function (data) {
   console.error(data)
@@ -1714,7 +2051,9 @@ socket.on('info', function (data) {
 })
 socket.on('error', function (data) {
   console.error(data)
-  if (data.message && data.message.indexOf('AUTH failed') === 0) { location.href = serverurl + '/403' }
+  if (data.message && data.message.indexOf('AUTH failed') === 0) {
+    location.href = serverurl + '/403'
+  }
 })
 socket.on('delete', function () {
   if (personalInfo.login) {
@@ -1723,13 +2062,13 @@ socket.on('delete', function () {
     })
   } else {
     getHistory(function (notehistory) {
-      var newnotehistory = removeHistory(noteid, notehistory)
+      const newnotehistory = removeHistory(noteid, notehistory)
       saveHistory(newnotehistory)
       location.href = serverurl
     })
   }
 })
-var retryTimer = null
+let retryTimer = null
 socket.on('maintenance', function () {
   cmClient.revision = -1
 })
@@ -1739,7 +2078,9 @@ socket.on('disconnect', function (data) {
     saveInfo()
     lastInfo.history = editor.getHistory()
   }
-  if (!editor.getOption('readOnly')) { editor.setOption('readOnly', true) }
+  if (!editor.getOption('readOnly')) {
+    editor.setOption('readOnly', true)
+  }
   if (!retryTimer) {
     retryTimer = setInterval(function () {
       if (!needRefresh) socket.connect()
@@ -1755,7 +2096,7 @@ socket.on('reconnect', function (data) {
 socket.on('connect', function (data) {
   clearInterval(retryTimer)
   retryTimer = null
-  personalInfo['id'] = socket.id
+  personalInfo.id = socket.id
   showStatus(statusType.connected)
   socket.emit('version')
 })
@@ -1769,40 +2110,58 @@ socket.on('version', function (data) {
     }
   }
 })
-var authors = []
-var authorship = []
-var authorMarks = {} // temp variable
-var addTextMarkers = [] // temp variable
+let authors = []
+let authorship = []
+let authorMarks = {} // temp variable
+let addTextMarkers = [] // temp variable
 function updateInfo (data) {
   // console.debug(data);
-  if (data.hasOwnProperty('createtime') && window.createtime !== data.createtime) {
+  if (
+    Object.prototype.hasOwnProperty.call(data, 'createtime') &&
+    window.createtime !== data.createtime
+  ) {
     window.createtime = data.createtime
     updateLastChange()
   }
-  if (data.hasOwnProperty('updatetime') && window.lastchangetime !== data.updatetime) {
+  if (
+    Object.prototype.hasOwnProperty.call(data, 'updatetime') &&
+    window.lastchangetime !== data.updatetime
+  ) {
     window.lastchangetime = data.updatetime
     updateLastChange()
   }
-  if (data.hasOwnProperty('owner') && window.owner !== data.owner) {
+  if (
+    Object.prototype.hasOwnProperty.call(data, 'owner') &&
+    window.owner !== data.owner
+  ) {
     window.owner = data.owner
     window.ownerprofile = data.ownerprofile
     updateOwner()
   }
-  if (data.hasOwnProperty('lastchangeuser') && window.lastchangeuser !== data.lastchangeuser) {
+  if (
+    Object.prototype.hasOwnProperty.call(data, 'lastchangeuser') &&
+    window.lastchangeuser !== data.lastchangeuser
+  ) {
     window.lastchangeuser = data.lastchangeuser
     window.lastchangeuserprofile = data.lastchangeuserprofile
     updateLastChangeUser()
     updateOwner()
   }
-  if (data.hasOwnProperty('authors') && authors !== data.authors) {
+  if (
+    Object.prototype.hasOwnProperty.call(data, 'authors') &&
+    authors !== data.authors
+  ) {
     authors = data.authors
   }
-  if (data.hasOwnProperty('authorship') && authorship !== data.authorship) {
+  if (
+    Object.prototype.hasOwnProperty.call(data, 'authorship') &&
+    authorship !== data.authorship
+  ) {
     authorship = data.authorship
     updateAuthorship()
   }
 }
-var updateAuthorship = _.debounce(function () {
+const updateAuthorship = _.debounce(function () {
   editor.operation(updateAuthorshipInner)
 }, 50)
 function initMark () {
@@ -1822,46 +2181,59 @@ function initMarkAndCheckGutter (mark, author, timestamp) {
   }
   return mark
 }
-var addStyleRule = (function () {
-  var added = {}
-  var styleElement = document.createElement('style')
-  document.documentElement.getElementsByTagName('head')[0].appendChild(styleElement)
-  var styleSheet = styleElement.sheet
+const addStyleRule = (function () {
+  const added = {}
+  const styleElement = document.createElement('style')
+  document.documentElement
+    .getElementsByTagName('head')[0]
+    .appendChild(styleElement)
+  const styleSheet = styleElement.sheet
 
   return function (css) {
     if (added[css]) {
       return
     }
     added[css] = true
-    styleSheet.insertRule(css, (styleSheet.cssRules || styleSheet.rules).length)
+    styleSheet.insertRule(
+      css,
+      (styleSheet.cssRules || styleSheet.rules).length
+    )
   }
-}())
+})()
 function updateAuthorshipInner () {
   // ignore when ot not synced yet
   if (havePendingOperation()) return
   authorMarks = {}
   for (let i = 0; i < authorship.length; i++) {
-    var atom = authorship[i]
-    let author = authors[atom[0]]
+    const atom = authorship[i]
+    const author = authors[atom[0]]
     if (author) {
-      var prePos = editor.posFromIndex(atom[1])
-      var preLine = editor.getLine(prePos.line)
-      var postPos = editor.posFromIndex(atom[2])
-      var postLine = editor.getLine(postPos.line)
+      const prePos = editor.posFromIndex(atom[1])
+      const preLine = editor.getLine(prePos.line)
+      const postPos = editor.posFromIndex(atom[2])
+      const postLine = editor.getLine(postPos.line)
       if (prePos.ch === 0 && postPos.ch === postLine.length) {
         for (let j = prePos.line; j <= postPos.line; j++) {
           if (editor.getLine(j)) {
-            authorMarks[j] = initMarkAndCheckGutter(authorMarks[j], author, atom[3])
+            authorMarks[j] = initMarkAndCheckGutter(
+              authorMarks[j],
+              author,
+              atom[3]
+            )
           }
         }
       } else if (postPos.line - prePos.line >= 1) {
-        var startLine = prePos.line
-        var endLine = postPos.line
+        let startLine = prePos.line
+        let endLine = postPos.line
         if (prePos.ch === preLine.length) {
           startLine++
         } else if (prePos.ch !== 0) {
-          let mark = initMarkAndCheckGutter(authorMarks[prePos.line], author, atom[3])
-          var _postPos = {
+          const mark = initMarkAndCheckGutter(
+            authorMarks[prePos.line],
+            author,
+            atom[3]
+          )
+          const _postPos = {
             line: prePos.line,
             ch: preLine.length
           }
@@ -1877,8 +2249,12 @@ function updateAuthorshipInner () {
         if (postPos.ch === 0) {
           endLine--
         } else if (postPos.ch !== postLine.length) {
-          let mark = initMarkAndCheckGutter(authorMarks[postPos.line], author, atom[3])
-          var _prePos = {
+          const mark = initMarkAndCheckGutter(
+            authorMarks[postPos.line],
+            author,
+            atom[3]
+          )
+          const _prePos = {
             line: postPos.line,
             ch: 0
           }
@@ -1893,11 +2269,19 @@ function updateAuthorshipInner () {
         }
         for (let j = startLine; j <= endLine; j++) {
           if (editor.getLine(j)) {
-            authorMarks[j] = initMarkAndCheckGutter(authorMarks[j], author, atom[3])
+            authorMarks[j] = initMarkAndCheckGutter(
+              authorMarks[j],
+              author,
+              atom[3]
+            )
           }
         }
       } else {
-        let mark = initMarkAndCheckGutter(authorMarks[prePos.line], author, atom[3])
+        const mark = initMarkAndCheckGutter(
+          authorMarks[prePos.line],
+          author,
+          atom[3]
+        )
         if (JSON.stringify(prePos) !== JSON.stringify(postPos)) {
           mark.textmarkers.push({
             userid: author.userid,
@@ -1910,38 +2294,45 @@ function updateAuthorshipInner () {
   }
   addTextMarkers = []
   editor.eachLine(iterateLine)
-  var allTextMarks = editor.getAllMarks()
+  const allTextMarks = editor.getAllMarks()
   for (let i = 0; i < allTextMarks.length; i++) {
-    let _textMarker = allTextMarks[i]
-    var pos = _textMarker.find()
-    var found = false
+    const _textMarker = allTextMarks[i]
+    const pos = _textMarker.find()
+    let found = false
     for (let j = 0; j < addTextMarkers.length; j++) {
-      let textMarker = addTextMarkers[j]
-      let author = authors[textMarker.userid]
-      let className = 'authorship-inline-' + author.color.substr(1)
-      var obj = {
+      const textMarker = addTextMarkers[j]
+      const author = authors[textMarker.userid]
+      const className = 'authorship-inline-' + author.color.substr(1)
+      const obj = {
         from: textMarker.pos[0],
         to: textMarker.pos[1]
       }
-      if (JSON.stringify(pos) === JSON.stringify(obj) && _textMarker.className &&
-                _textMarker.className.indexOf(className) > -1) {
+      if (
+        JSON.stringify(pos) === JSON.stringify(obj) &&
+        _textMarker.className &&
+        _textMarker.className.indexOf(className) > -1
+      ) {
         addTextMarkers.splice(j, 1)
         j--
         found = true
         break
       }
     }
-    if (!found && _textMarker.className && _textMarker.className.indexOf('authorship-inline') > -1) {
+    if (
+      !found &&
+      _textMarker.className &&
+      _textMarker.className.indexOf('authorship-inline') > -1
+    ) {
       _textMarker.clear()
     }
   }
   for (let i = 0; i < addTextMarkers.length; i++) {
-    let textMarker = addTextMarkers[i]
-    let author = authors[textMarker.userid]
+    const textMarker = addTextMarkers[i]
+    const author = authors[textMarker.userid]
     const rgbcolor = hex2rgb(author.color)
     const colorString = `rgba(${rgbcolor.red},${rgbcolor.green},${rgbcolor.blue},0.7)`
     const styleString = `background-image: linear-gradient(to top, ${colorString} 1px, transparent 1px);`
-    let className = `authorship-inline-${author.color.substr(1)}`
+    const className = `authorship-inline-${author.color.substr(1)}`
     const rule = `.${className} { ${styleString} }`
     addStyleRule(rule)
     editor.markText(textMarker.pos[0], textMarker.pos[1], {
@@ -1951,19 +2342,22 @@ function updateAuthorshipInner () {
   }
 }
 function iterateLine (line) {
-  var lineNumber = line.lineNo()
-  var currMark = authorMarks[lineNumber]
-  var author = currMark ? authors[currMark.gutter.userid] : null
+  const lineNumber = line.lineNo()
+  const currMark = authorMarks[lineNumber]
+  const author = currMark ? authors[currMark.gutter.userid] : null
   if (currMark && author) {
-    let className = 'authorship-gutter-' + author.color.substr(1)
+    const className = 'authorship-gutter-' + author.color.substr(1)
     const gutters = line.gutterMarkers
-    if (!gutters || !gutters['authorship-gutters'] ||
-        !gutters['authorship-gutters'].className ||
-        !gutters['authorship-gutters'].className.indexOf(className) < 0) {
+    if (
+      !gutters ||
+      !gutters['authorship-gutters'] ||
+      !gutters['authorship-gutters'].className ||
+      !gutters['authorship-gutters'].className.indexOf(className) < 0
+    ) {
       const styleString = `border-left: 3px solid ${author.color}; height: ${defaultTextHeight}px; margin-left: 3px;`
       const rule = `.${className} { ${styleString} }`
       addStyleRule(rule)
-      var gutter = $('<div>', {
+      const gutter = $('<div>', {
         class: 'authorship-gutter ' + className,
         title: author.name
       })
@@ -1973,8 +2367,8 @@ function iterateLine (line) {
     editor.setGutterMarker(line, 'authorship-gutters', null)
   }
   if (currMark && currMark.textmarkers.length > 0) {
-    for (var i = 0; i < currMark.textmarkers.length; i++) {
-      let textMarker = currMark.textmarkers[i]
+    for (let i = 0; i < currMark.textmarkers.length; i++) {
+      const textMarker = currMark.textmarkers[i]
       if (textMarker.userid !== currMark.gutter.userid) {
         addTextMarkers.push(textMarker)
       }
@@ -1985,17 +2379,17 @@ editorInstance.on('update', function () {
   $('.authorship-gutter:not([data-original-title])').tooltip({
     container: '.CodeMirror-lines',
     placement: 'right',
-    delay: { 'show': 500, 'hide': 100 }
+    delay: { show: 500, hide: 100 }
   })
   $('.authorship-inline:not([data-original-title])').tooltip({
     container: '.CodeMirror-lines',
     placement: 'bottom',
-    delay: { 'show': 500, 'hide': 100 }
+    delay: { show: 500, hide: 100 }
   })
   // clear tooltip which described element has been removed
   $('[id^="tooltip"]').each(function (index, element) {
-    var $ele = $(element)
-    if ($('[aria-describedby="' + $ele.attr('id') + '"]').length <= 0) $ele.remove()
+    const $ele = $(element)
+    if ($('[aria-describedby="' + $ele.attr('id') + '"]').length <= 0) { $ele.remove() }
   })
 })
 socket.on('check', function (data) {
@@ -2006,7 +2400,7 @@ socket.on('permission', function (data) {
   updatePermission(data.permission)
 })
 
-var permission = null
+let permission = null
 socket.on('refresh', function (data) {
   // console.debug(data);
   editorInstance.config.docmaxlength = data.docmaxlength
@@ -2015,13 +2409,17 @@ socket.on('refresh', function (data) {
   updatePermission(data.permission)
   if (!window.loaded) {
     // auto change mode if no content detected
-    var nocontent = editor.getValue().length <= 0
+    const nocontent = editor.getValue().length <= 0
     if (nocontent) {
-      if (visibleXS) { appState.currentMode = modeType.edit } else { appState.currentMode = modeType.both }
+      if (visibleXS) {
+        appState.currentMode = modeType.edit
+      } else {
+        appState.currentMode = modeType.both
+      }
     }
     // parse mode from url
     if (window.location.search.length > 0) {
-      var urlMode = modeType[window.location.search.substr(1)]
+      const urlMode = modeType[window.location.search.substr(1)]
       if (urlMode) appState.currentMode = urlMode
     }
     changeMode(appState.currentMode)
@@ -2041,23 +2439,34 @@ socket.on('refresh', function (data) {
       scrollToHash()
     }, 1)
   }
-  if (editor.getOption('readOnly')) { editor.setOption('readOnly', false) }
+  if (editor.getOption('readOnly')) {
+    editor.setOption('readOnly', false)
+  }
 })
 
-var EditorClient = ot.EditorClient
-var SocketIOAdapter = ot.SocketIOAdapter
-var CodeMirrorAdapter = ot.CodeMirrorAdapter
-var cmClient = null
-var synchronized_ = null
+const EditorClient = ot.EditorClient
+const SocketIOAdapter = ot.SocketIOAdapter
+const CodeMirrorAdapter = ot.CodeMirrorAdapter
+let cmClient = null
+let synchronized_ = null
 
 function havePendingOperation () {
-  return !!((cmClient && cmClient.state && cmClient.state.hasOwnProperty('outstanding')))
+  return !!(
+    cmClient &&
+    cmClient.state &&
+    Object.prototype.hasOwnProperty.call(cmClient, 'outstanding')
+  )
 }
 
 socket.on('doc', function (obj) {
-  var body = obj.str
-  var bodyMismatch = editor.getValue() !== body
-  var setDoc = !cmClient || (cmClient && (cmClient.revision === -1 || (cmClient.revision !== obj.revision && !havePendingOperation()))) || obj.force
+  const body = obj.str
+  const bodyMismatch = editor.getValue() !== body
+  const setDoc =
+    !cmClient ||
+    (cmClient &&
+      (cmClient.revision === -1 ||
+        (cmClient.revision !== obj.revision && !havePendingOperation()))) ||
+    obj.force
 
   saveInfo()
   if (setDoc && bodyMismatch) {
@@ -2079,8 +2488,10 @@ socket.on('doc', function (obj) {
 
   if (!cmClient) {
     cmClient = window.cmClient = new EditorClient(
-      obj.revision, obj.clients,
-      new SocketIOAdapter(socket), new CodeMirrorAdapter(editor)
+      obj.revision,
+      obj.clients,
+      new SocketIOAdapter(socket),
+      new CodeMirrorAdapter(editor)
     )
     synchronized_ = cmClient.state
   } else if (setDoc) {
@@ -2115,91 +2526,120 @@ socket.on('operation', function () {
 })
 
 socket.on('online users', function (data) {
-  if (debug) { console.debug(data) }
+  if (debug) {
+    console.debug(data)
+  }
   onlineUsers = data.users
   updateOnlineStatus()
-  $('.CodeMirror-other-cursors').children().each(function (key, value) {
-    var found = false
-    for (var i = 0; i < data.users.length; i++) {
-      var user = data.users[i]
-      if ($(this).attr('id') === user.id) { found = true }
-    }
-    if (!found) {
-      $(this).stop(true).fadeOut('normal', function () {
-        $(this).remove()
-      })
+  $('.CodeMirror-other-cursors')
+    .children()
+    .each(function (key, value) {
+      let found = false
+      for (let i = 0; i < data.users.length; i++) {
+        const user = data.users[i]
+        if ($(this).attr('id') === user.id) {
+          found = true
+        }
+      }
+      if (!found) {
+        $(this)
+          .stop(true)
+          .fadeOut('normal', function () {
+            $(this).remove()
+          })
+      }
+    })
+  for (let i = 0; i < data.users.length; i++) {
+    const user = data.users[i]
+    if (user.id !== socket.id) {
+      buildCursor(user)
+    } else {
+      personalInfo = user
     }
-  })
-  for (var i = 0; i < data.users.length; i++) {
-    var user = data.users[i]
-    if (user.id !== socket.id) { buildCursor(user) } else { personalInfo = user }
   }
 })
 socket.on('user status', function (data) {
-  if (debug) { console.debug(data) }
-  for (var i = 0; i < onlineUsers.length; i++) {
+  if (debug) {
+    console.debug(data)
+  }
+  for (let i = 0; i < onlineUsers.length; i++) {
     if (onlineUsers[i].id === data.id) {
       onlineUsers[i] = data
     }
   }
   updateOnlineStatus()
-  if (data.id !== socket.id) { buildCursor(data) }
+  if (data.id !== socket.id) {
+    buildCursor(data)
+  }
 })
 socket.on('cursor focus', function (data) {
-  if (debug) { console.debug(data) }
-  for (var i = 0; i < onlineUsers.length; i++) {
+  if (debug) {
+    console.debug(data)
+  }
+  for (let i = 0; i < onlineUsers.length; i++) {
     if (onlineUsers[i].id === data.id) {
       onlineUsers[i].cursor = data.cursor
     }
   }
-  if (data.id !== socket.id) { buildCursor(data) }
+  if (data.id !== socket.id) {
+    buildCursor(data)
+  }
   // force show
-  var cursor = $('div[data-clientid="' + data.id + '"]')
+  const cursor = $('div[data-clientid="' + data.id + '"]')
   if (cursor.length > 0) {
     cursor.stop(true).fadeIn()
   }
 })
 socket.on('cursor activity', function (data) {
-  if (debug) { console.debug(data) }
-  for (var i = 0; i < onlineUsers.length; i++) {
+  if (debug) {
+    console.debug(data)
+  }
+  for (let i = 0; i < onlineUsers.length; i++) {
     if (onlineUsers[i].id === data.id) {
       onlineUsers[i].cursor = data.cursor
     }
   }
-  if (data.id !== socket.id) { buildCursor(data) }
+  if (data.id !== socket.id) {
+    buildCursor(data)
+  }
 })
 socket.on('cursor blur', function (data) {
-  if (debug) { console.debug(data) }
-  for (var i = 0; i < onlineUsers.length; i++) {
+  if (debug) {
+    console.debug(data)
+  }
+  for (let i = 0; i < onlineUsers.length; i++) {
     if (onlineUsers[i].id === data.id) {
       onlineUsers[i].cursor = null
     }
   }
-  if (data.id !== socket.id) { buildCursor(data) }
+  if (data.id !== socket.id) {
+    buildCursor(data)
+  }
   // force hide
-  var cursor = $('div[data-clientid="' + data.id + '"]')
+  const cursor = $('div[data-clientid="' + data.id + '"]')
   if (cursor.length > 0) {
     cursor.stop(true).fadeOut()
   }
 })
 
-var options = {
+const options = {
   valueNames: ['id', 'name'],
-  item: '<li class="ui-user-item">' +
-        '<span class="id" style="display:none;"></span>' +
-        '<a href="#">' +
-            '<span class="pull-left"><i class="ui-user-icon"></i></span><span class="ui-user-name name"></span><span class="pull-right"><i class="fa fa-circle ui-user-status"></i></span>' +
-        '</a>' +
-        '</li>'
+  item:
+    '<li class="ui-user-item">' +
+    '<span class="id" style="display:none;"></span>' +
+    '<a href="#">' +
+    '<span class="pull-left"><i class="ui-user-icon"></i></span><span class="ui-user-name name"></span><span class="pull-right"><i class="fa fa-circle ui-user-status"></i></span>' +
+    '</a>' +
+    '</li>'
 }
-var onlineUserList = new List('online-user-list', options)
-var shortOnlineUserList = new List('short-online-user-list', options)
+const onlineUserList = new List('online-user-list', options)
+const shortOnlineUserList = new List('short-online-user-list', options)
 
 function updateOnlineStatus () {
   if (!window.loaded || !socket.connected) return
-  var _onlineUsers = deduplicateOnlineUsers(onlineUsers)
+  const _onlineUsers = deduplicateOnlineUsers(onlineUsers)
   showStatus(statusType.online, _onlineUsers.length)
-  var items = onlineUserList.items
+  const items = onlineUserList.items
   // update or remove current list items
   for (let i = 0; i < items.length; i++) {
     let found = false
@@ -2211,7 +2651,7 @@ function updateOnlineStatus () {
         break
       }
     }
-    let id = items[i].values().id
+    const id = items[i].values().id
     if (found) {
       onlineUserList.get('id', id)[0].values(_onlineUsers[foundindex])
       shortOnlineUserList.get('id', id)[0].values(_onlineUsers[foundindex])
@@ -2246,23 +2686,57 @@ function sortOnlineUserList (list) {
   // sort order by isSelf, login state, idle state, alphabet name, color brightness
   list.sort('', {
     sortFunction: function (a, b) {
-      var usera = a.values()
-      var userb = b.values()
-      var useraIsSelf = (usera.id === personalInfo.id || (usera.login && usera.userid === personalInfo.userid))
-      var userbIsSelf = (userb.id === personalInfo.id || (userb.login && userb.userid === personalInfo.userid))
+      const usera = a.values()
+      const userb = b.values()
+      const useraIsSelf =
+        usera.id === personalInfo.id ||
+        (usera.login && usera.userid === personalInfo.userid)
+      const userbIsSelf =
+        userb.id === personalInfo.id ||
+        (userb.login && userb.userid === personalInfo.userid)
       if (useraIsSelf && !userbIsSelf) {
         return -1
       } else if (!useraIsSelf && userbIsSelf) {
         return 1
       } else {
-        if (usera.login && !userb.login) { return -1 } else if (!usera.login && userb.login) { return 1 } else {
-          if (!usera.idle && userb.idle) { return -1 } else if (usera.idle && !userb.idle) { return 1 } else {
-            if (usera.name && userb.name && usera.name.toLowerCase() < userb.name.toLowerCase()) {
+        if (usera.login && !userb.login) {
+          return -1
+        } else if (!usera.login && userb.login) {
+          return 1
+        } else {
+          if (!usera.idle && userb.idle) {
+            return -1
+          } else if (usera.idle && !userb.idle) {
+            return 1
+          } else {
+            if (
+              usera.name &&
+              userb.name &&
+              usera.name.toLowerCase() < userb.name.toLowerCase()
+            ) {
               return -1
-            } else if (usera.name && userb.name && usera.name.toLowerCase() > userb.name.toLowerCase()) {
+            } else if (
+              usera.name &&
+              userb.name &&
+              usera.name.toLowerCase() > userb.name.toLowerCase()
+            ) {
               return 1
             } else {
-              if (usera.color && userb.color && usera.color.toLowerCase() < userb.color.toLowerCase()) { return -1 } else if (usera.color && userb.color && usera.color.toLowerCase() > userb.color.toLowerCase()) { return 1 } else { return 0 }
+              if (
+                usera.color &&
+                userb.color &&
+                usera.color.toLowerCase() < userb.color.toLowerCase()
+              ) {
+                return -1
+              } else if (
+                usera.color &&
+                userb.color &&
+                usera.color.toLowerCase() > userb.color.toLowerCase()
+              ) {
+                return 1
+              } else {
+                return 0
+              }
             }
           }
         }
@@ -2272,11 +2746,11 @@ function sortOnlineUserList (list) {
 }
 
 function renderUserStatusList (list) {
-  var items = list.items
-  for (var j = 0; j < items.length; j++) {
-    var item = items[j]
-    var userstatus = $(item.elm).find('.ui-user-status')
-    var usericon = $(item.elm).find('.ui-user-icon')
+  const items = list.items
+  for (let j = 0; j < items.length; j++) {
+    const item = items[j]
+    const userstatus = $(item.elm).find('.ui-user-status')
+    const usericon = $(item.elm).find('.ui-user-icon')
     if (item.values().login && item.values().photo) {
       usericon.css('background-image', 'url(' + item.values().photo + ')')
       // add 1px more to right, make it feel aligned
@@ -2286,18 +2760,26 @@ function renderUserStatusList (list) {
     } else {
       usericon.css('background-color', item.values().color)
     }
-    userstatus.removeClass('ui-user-status-offline ui-user-status-online ui-user-status-idle')
-    if (item.values().idle) { userstatus.addClass('ui-user-status-idle') } else { userstatus.addClass('ui-user-status-online') }
+    userstatus.removeClass(
+      'ui-user-status-offline ui-user-status-online ui-user-status-idle'
+    )
+    if (item.values().idle) {
+      userstatus.addClass('ui-user-status-idle')
+    } else {
+      userstatus.addClass('ui-user-status-online')
+    }
   }
 }
 
 function deduplicateOnlineUsers (list) {
-  var _onlineUsers = []
-  for (var i = 0; i < list.length; i++) {
-    var user = $.extend({}, list[i])
-    if (!user.userid) { _onlineUsers.push(user) } else {
-      var found = false
-      for (var j = 0; j < _onlineUsers.length; j++) {
+  const _onlineUsers = []
+  for (let i = 0; i < list.length; i++) {
+    const user = $.extend({}, list[i])
+    if (!user.userid) {
+      _onlineUsers.push(user)
+    } else {
+      let found = false
+      for (let j = 0; j < _onlineUsers.length; j++) {
         if (_onlineUsers[j].userid === user.userid) {
           // keep self color when login
           if (user.id === personalInfo.id) {
@@ -2312,29 +2794,39 @@ function deduplicateOnlineUsers (list) {
           break
         }
       }
-      if (!found) { _onlineUsers.push(user) }
+      if (!found) {
+        _onlineUsers.push(user)
+      }
     }
   }
   return _onlineUsers
 }
 
-var userStatusCache = null
+let userStatusCache = null
 
 function emitUserStatus (force) {
   if (!window.loaded) return
-  var type = null
-  if (visibleXS) { type = 'xs' } else if (visibleSM) { type = 'sm' } else if (visibleMD) { type = 'md' } else if (visibleLG) { type = 'lg' }
+  let type = null
+  if (visibleXS) {
+    type = 'xs'
+  } else if (visibleSM) {
+    type = 'sm'
+  } else if (visibleMD) {
+    type = 'md'
+  } else if (visibleLG) {
+    type = 'lg'
+  }
 
-  personalInfo['idle'] = idle.isAway
-  personalInfo['type'] = type
+  personalInfo.idle = idle.isAway
+  personalInfo.type = type
 
-  for (var i = 0; i < onlineUsers.length; i++) {
+  for (let i = 0; i < onlineUsers.length; i++) {
     if (onlineUsers[i].id === personalInfo.id) {
       onlineUsers[i] = personalInfo
     }
   }
 
-  var userStatus = {
+  const userStatus = {
     idle: idle.isAway,
     type: type
   }
@@ -2348,24 +2840,24 @@ function emitUserStatus (force) {
 function checkCursorTag (coord, ele) {
   if (!ele) return // return if element not exists
   // set margin
-  var tagRightMargin = 0
-  var tagBottomMargin = 2
+  const tagRightMargin = 0
+  const tagBottomMargin = 2
   // use sizer to get the real doc size (won't count status bar and gutters)
-  var docWidth = ui.area.codemirrorSizer.width()
+  const docWidth = ui.area.codemirrorSizer.width()
   // get editor size (status bar not count in)
-  var editorHeight = ui.area.codemirror.height()
+  const editorHeight = ui.area.codemirror.height()
   // get element size
-  var width = ele.outerWidth()
-  var height = ele.outerHeight()
-  var padding = (ele.outerWidth() - ele.width()) / 2
+  const width = ele.outerWidth()
+  const height = ele.outerHeight()
+  const padding = (ele.outerWidth() - ele.width()) / 2
   // get coord position
-  var left = coord.left
-  var top = coord.top
+  const left = coord.left
+  const top = coord.top
   // get doc top offset (to workaround with viewport)
-  var docTopOffset = ui.area.codemirrorSizerInner.position().top
+  const docTopOffset = ui.area.codemirrorSizerInner.position().top
   // set offset
-  var offsetLeft = -3
-  var offsetTop = defaultTextHeight
+  let offsetLeft = -3
+  let offsetTop = defaultTextHeight
   // only do when have width and height
   if (width > 0 && height > 0) {
     // flip x when element right bound larger than doc width
@@ -2374,8 +2866,12 @@ function checkCursorTag (coord, ele) {
     }
     // flip y when element bottom bound larger than doc height
     // and element top position is larger than element height
-    if (top + docTopOffset + height + offsetTop + tagBottomMargin > Math.max(editor.doc.height, editorHeight) && top + docTopOffset > height + tagBottomMargin) {
-      offsetTop = -(height)
+    if (
+      top + docTopOffset + height + offsetTop + tagBottomMargin >
+        Math.max(editor.doc.height, editorHeight) &&
+      top + docTopOffset > height + tagBottomMargin
+    ) {
+      offsetTop = -height
     }
   }
   // set position
@@ -2386,10 +2882,10 @@ function checkCursorTag (coord, ele) {
 function buildCursor (user) {
   if (appState.currentMode === modeType.view) return
   if (!user.cursor) return
-  var coord = editor.charCoords(user.cursor, 'windows')
+  const coord = editor.charCoords(user.cursor, 'windows')
   coord.left = coord.left < 4 ? 4 : coord.left
   coord.top = coord.top < 0 ? 0 : coord.top
-  var iconClass = 'fa-user'
+  let iconClass = 'fa-user'
   switch (user.type) {
     case 'xs':
       iconClass = 'fa-mobile'
@@ -2405,19 +2901,29 @@ function buildCursor (user) {
       break
   }
   if ($('div[data-clientid="' + user.id + '"]').length <= 0) {
-    let cursor = $('<div data-clientid="' + user.id + '" class="CodeMirror-other-cursor" style="display:none;"></div>')
+    const cursor = $(
+      '<div data-clientid="' +
+        user.id +
+        '" class="CodeMirror-other-cursor" style="display:none;"></div>'
+    )
     cursor.attr('data-line', user.cursor.line)
     cursor.attr('data-ch', user.cursor.ch)
     cursor.attr('data-offset-left', 0)
     cursor.attr('data-offset-top', 0)
 
-    let cursorbar = $('<div class="cursorbar">&nbsp;</div>')
+    const cursorbar = $('<div class="cursorbar">&nbsp;</div>')
     cursorbar[0].style.height = defaultTextHeight + 'px'
     cursorbar[0].style.borderLeft = '2px solid ' + user.color
 
-    var icon = '<i class="fa ' + iconClass + '"></i>'
+    const icon = '<i class="fa ' + iconClass + '"></i>'
 
-    let cursortag = $('<div class="cursortag">' + icon + '&nbsp;<span class="name">' + user.name + '</span></div>')
+    const cursortag = $(
+      '<div class="cursortag">' +
+        icon +
+        '&nbsp;<span class="name">' +
+        user.name +
+        '</span></div>'
+    )
     // cursortag[0].style.background = color;
     cursortag[0].style.color = user.color
 
@@ -2425,28 +2931,43 @@ function buildCursor (user) {
     cursortag.delay(2000).fadeOut('fast')
     cursor.hover(
       function () {
-        if (cursor.attr('data-mode') === 'hover') { cursortag.stop(true).fadeIn('fast') }
+        if (cursor.attr('data-mode') === 'hover') {
+          cursortag.stop(true).fadeIn('fast')
+        }
       },
       function () {
-        if (cursor.attr('data-mode') === 'hover') { cursortag.stop(true).fadeOut('fast') }
-      })
+        if (cursor.attr('data-mode') === 'hover') {
+          cursortag.stop(true).fadeOut('fast')
+        }
+      }
+    )
 
-    var hideCursorTagDelay = 2000
-    var hideCursorTagTimer = null
+    const hideCursorTagDelay = 2000
+    let hideCursorTagTimer = null
 
-    var switchMode = function (ele) {
-      if (ele.attr('data-mode') === 'state') { ele.attr('data-mode', 'hover') } else if (ele.attr('data-mode') === 'hover') { ele.attr('data-mode', 'state') }
+    const switchMode = function (ele) {
+      if (ele.attr('data-mode') === 'state') {
+        ele.attr('data-mode', 'hover')
+      } else if (ele.attr('data-mode') === 'hover') {
+        ele.attr('data-mode', 'state')
+      }
     }
 
-    var switchTag = function (ele) {
-      if (ele.css('display') === 'none') { ele.stop(true).fadeIn('fast') } else { ele.stop(true).fadeOut('fast') }
+    const switchTag = function (ele) {
+      if (ele.css('display') === 'none') {
+        ele.stop(true).fadeIn('fast')
+      } else {
+        ele.stop(true).fadeOut('fast')
+      }
     }
 
-    var hideCursorTag = function () {
-      if (cursor.attr('data-mode') === 'hover') { cursortag.fadeOut('fast') }
+    const hideCursorTag = function () {
+      if (cursor.attr('data-mode') === 'hover') {
+        cursortag.fadeOut('fast')
+      }
     }
     cursor.on('touchstart', function (e) {
-      var display = cursortag.css('display')
+      const display = cursortag.css('display')
       cursortag.stop(true).fadeIn('fast')
       clearTimeout(hideCursorTagTimer)
       hideCursorTagTimer = setTimeout(hideCursorTag, hideCursorTagDelay)
@@ -2456,7 +2977,9 @@ function buildCursor (user) {
       }
     })
     cursortag.on('mousedown touchstart', function (e) {
-      if (cursor.attr('data-mode') === 'state') { switchTag(cursortag) }
+      if (cursor.attr('data-mode') === 'state') {
+        switchTag(cursortag)
+      }
       switchMode(cursor)
       e.preventDefault()
       e.stopPropagation()
@@ -2469,19 +2992,21 @@ function buildCursor (user) {
     cursor[0].style.top = coord.top + 'px'
     $('.CodeMirror-other-cursors').append(cursor)
 
-    if (!user.idle) { cursor.stop(true).fadeIn() }
+    if (!user.idle) {
+      cursor.stop(true).fadeIn()
+    }
 
     checkCursorTag(coord, cursortag)
   } else {
-    let cursor = $('div[data-clientid="' + user.id + '"]')
+    const cursor = $('div[data-clientid="' + user.id + '"]')
     cursor.attr('data-line', user.cursor.line)
     cursor.attr('data-ch', user.cursor.ch)
 
-    let cursorbar = cursor.find('.cursorbar')
+    const cursorbar = cursor.find('.cursorbar')
     cursorbar[0].style.height = defaultTextHeight + 'px'
     cursorbar[0].style.borderLeft = '2px solid ' + user.color
 
-    let cursortag = cursor.find('.cursortag')
+    const cursortag = cursor.find('.cursortag')
     cursortag.find('i').removeClass().addClass('fa').addClass(iconClass)
     cursortag.find('.name').text(user.name)
 
@@ -2489,16 +3014,23 @@ function buildCursor (user) {
       cursor[0].style.left = coord.left + 'px'
       cursor[0].style.top = coord.top + 'px'
     } else {
-      cursor.animate({
-        'left': coord.left,
-        'top': coord.top
-      }, {
-        duration: cursorAnimatePeriod,
-        queue: false
-      })
+      cursor.animate(
+        {
+          left: coord.left,
+          top: coord.top
+        },
+        {
+          duration: cursorAnimatePeriod,
+          queue: false
+        }
+      )
     }
 
-    if (user.idle && cursor.css('display') !== 'none') { cursor.stop(true).fadeOut() } else if (!user.idle && cursor.css('display') === 'none') { cursor.stop(true).fadeIn() }
+    if (user.idle && cursor.css('display') !== 'none') {
+      cursor.stop(true).fadeOut()
+    } else if (!user.idle && cursor.css('display') === 'none') {
+      cursor.stop(true).fadeIn()
+    }
 
     checkCursorTag(coord, cursortag)
   }
@@ -2506,18 +3038,23 @@ function buildCursor (user) {
 
 // editor actions
 function removeNullByte (cm, change) {
-  var str = change.text.join('\n')
+  const str = change.text.join('\n')
   // eslint-disable-next-line no-control-regex
   if (/\u0000/g.test(str) && change.update) {
-    // eslint-disable-next-line no-control-regex
-    change.update(change.from, change.to, str.replace(/\u0000/g, '').split('\n'))
+    change.update(
+      change.from,
+      change.to,
+      // eslint-disable-next-line no-control-regex
+      str.replace(/\u0000/g, '').split('\n')
+    )
   }
 }
 function enforceMaxLength (cm, change) {
-  var maxLength = cm.getOption('maxLength')
+  const maxLength = cm.getOption('maxLength')
   if (maxLength && change.update) {
-    var str = change.text.join('\n')
-    var delta = str.length - (cm.indexFromPos(change.to) - cm.indexFromPos(change.from))
+    let str = change.text.join('\n')
+    let delta =
+      str.length - (cm.indexFromPos(change.to) - cm.indexFromPos(change.from))
     if (delta <= 0) {
       return false
     }
@@ -2530,14 +3067,16 @@ function enforceMaxLength (cm, change) {
   }
   return false
 }
-var ignoreEmitEvents = ['setValue', 'ignoreHistory']
+const ignoreEmitEvents = ['setValue', 'ignoreHistory']
 editorInstance.on('beforeChange', function (cm, change) {
-  if (debug) { console.debug(change) }
+  if (debug) {
+    console.debug(change)
+  }
   removeNullByte(cm, change)
   if (enforceMaxLength(cm, change)) {
     $('.limit-modal').modal('show')
   }
-  var isIgnoreEmitEvent = (ignoreEmitEvents.indexOf(change.origin) !== -1)
+  const isIgnoreEmitEvent = ignoreEmitEvents.indexOf(change.origin) !== -1
   if (!isIgnoreEmitEvent) {
     if (!havePermission()) {
       change.canceled = true
@@ -2557,7 +3096,9 @@ editorInstance.on('beforeChange', function (cm, change) {
       updateTitleReminder()
     }
   }
-  if (cmClient && !socket.connected) { cmClient.editorAdapter.ignoreNextChange = true }
+  if (cmClient && !socket.connected) {
+    cmClient.editorAdapter.ignoreNextChange = true
+  }
 })
 editorInstance.on('cut', function () {
   // na
@@ -2567,9 +3108,9 @@ editorInstance.on('paste', function () {
 })
 editorInstance.on('changes', function (editor, changes) {
   updateHistory()
-  var docLength = editor.getValue().length
+  const docLength = editor.getValue().length
   // workaround for big documents
-  var newViewportMargin = 20
+  let newViewportMargin = 20
   if (docLength > 20000) {
     newViewportMargin = 1
   } else if (docLength > 10000) {
@@ -2582,7 +3123,10 @@ editorInstance.on('changes', function (editor, changes) {
     windowResize()
   }
   checkEditorScrollbar()
-  if (ui.area.codemirrorScroll[0].scrollHeight > ui.area.view[0].scrollHeight && editorHasFocus()) {
+  if (
+    ui.area.codemirrorScroll[0].scrollHeight > ui.area.view[0].scrollHeight &&
+    editorHasFocus()
+  ) {
     postUpdateEvent = function () {
       syncScrollToView()
       postUpdateEvent = null
@@ -2590,12 +3134,12 @@ editorInstance.on('changes', function (editor, changes) {
   }
 })
 editorInstance.on('focus', function (editor) {
-  for (var i = 0; i < onlineUsers.length; i++) {
+  for (let i = 0; i < onlineUsers.length; i++) {
     if (onlineUsers[i].id === personalInfo.id) {
       onlineUsers[i].cursor = editor.getCursor()
     }
   }
-  personalInfo['cursor'] = editor.getCursor()
+  personalInfo.cursor = editor.getCursor()
   socket.emit('cursor focus', editor.getCursor())
 })
 
@@ -2603,12 +3147,12 @@ const cursorActivity = _.debounce(cursorActivityInner, cursorActivityDebounce)
 
 function cursorActivityInner (editor) {
   if (editorHasFocus() && !Visibility.hidden()) {
-    for (var i = 0; i < onlineUsers.length; i++) {
+    for (let i = 0; i < onlineUsers.length; i++) {
       if (onlineUsers[i].id === personalInfo.id) {
         onlineUsers[i].cursor = editor.getCursor()
       }
     }
-    personalInfo['cursor'] = editor.getCursor()
+    personalInfo.cursor = editor.getCursor()
     socket.emit('cursor activity', editor.getCursor())
   }
 }
@@ -2632,7 +3176,7 @@ editorInstance.on('beforeSelectionChange', function (doc, selections) {
 
     // borrow from brackets EditorStatusBar.js
     if (start.line !== end.line) {
-      var lines = end.line - start.line + 1
+      let lines = end.line - start.line + 1
       if (end.ch === 0) {
         lines--
       }
@@ -2650,19 +3194,19 @@ editorInstance.on('beforeSelectionChange', function (doc, selections) {
 })
 
 editorInstance.on('blur', function (cm) {
-  for (var i = 0; i < onlineUsers.length; i++) {
+  for (let i = 0; i < onlineUsers.length; i++) {
     if (onlineUsers[i].id === personalInfo.id) {
       onlineUsers[i].cursor = null
     }
   }
-  personalInfo['cursor'] = null
+  personalInfo.cursor = null
   socket.emit('cursor blur')
 })
 
 function saveInfo () {
-  var scrollbarStyle = editor.getOption('scrollbarStyle')
-  var left = $(window).scrollLeft()
-  var top = $(window).scrollTop()
+  const scrollbarStyle = editor.getOption('scrollbarStyle')
+  const left = $(window).scrollLeft()
+  const top = $(window).scrollTop()
   switch (appState.currentMode) {
     case modeType.edit:
       if (scrollbarStyle === 'native') {
@@ -2688,10 +3232,10 @@ function saveInfo () {
 }
 
 function restoreInfo () {
-  var scrollbarStyle = editor.getOption('scrollbarStyle')
+  const scrollbarStyle = editor.getOption('scrollbarStyle')
   if (lastInfo.needRestore) {
-    var line = lastInfo.edit.cursor.line
-    var ch = lastInfo.edit.cursor.ch
+    const line = lastInfo.edit.cursor.line
+    const ch = lastInfo.edit.cursor.ch
     editor.setCursor(line, ch)
     editor.setSelections(lastInfo.edit.selections)
     switch (appState.currentMode) {
@@ -2700,8 +3244,8 @@ function restoreInfo () {
           $(window).scrollLeft(lastInfo.edit.scroll.left)
           $(window).scrollTop(lastInfo.edit.scroll.top)
         } else {
-          let left = lastInfo.edit.scroll.left
-          let top = lastInfo.edit.scroll.top
+          const left = lastInfo.edit.scroll.left
+          const top = lastInfo.edit.scroll.top
           editor.scrollIntoView()
           editor.scrollTo(left, top)
         }
@@ -2711,10 +3255,8 @@ function restoreInfo () {
         $(window).scrollTop(lastInfo.view.scroll.top)
         break
       case modeType.both:
-        let left = lastInfo.edit.scroll.left
-        let top = lastInfo.edit.scroll.top
         editor.scrollIntoView()
-        editor.scrollTo(left, top)
+        editor.scrollTo(lastInfo.edit.scroll.left, lastInfo.edit.scroll.top)
         ui.area.view.scrollLeft(lastInfo.view.scroll.left)
         ui.area.view.scrollTop(lastInfo.view.scroll.top)
         break
@@ -2731,27 +3273,30 @@ function refreshView () {
   updateViewInner()
 }
 
-var updateView = _.debounce(function () {
+const updateView = _.debounce(function () {
   editor.operation(updateViewInner)
 }, updateViewDebounce)
 
-var lastResult = null
-var postUpdateEvent = null
+let lastResult = null
+let postUpdateEvent = null
 
 function updateViewInner () {
   if (appState.currentMode === modeType.edit || !isDirty) return
-  var value = editor.getValue()
-  var lastMeta = md.meta
+  const value = editor.getValue()
+  const lastMeta = md.meta
   md.meta = {}
   delete md.metaError
-  var rendered = md.render(value)
+  let rendered = md.render(value)
   if (md.meta.type && md.meta.type === 'slide') {
     ui.area.view.addClass('black')
-    var slideOptions = {
+    const slideOptions = {
       separator: '^(\r\n?|\n)---(\r\n?|\n)$',
       verticalSeparator: '^(\r\n?|\n)----(\r\n?|\n)$'
     }
-    var slides = window.RevealMarkdown.slidify(editor.getValue(), slideOptions)
+    const slides = window.RevealMarkdown.slidify(
+      editor.getValue(),
+      slideOptions
+    )
     ui.area.markdown.html(slides)
     window.RevealMarkdown.initialize()
     // prevent XSS
@@ -2769,14 +3314,22 @@ function updateViewInner () {
     }
     // only render again when meta changed
     if (JSON.stringify(md.meta) !== JSON.stringify(lastMeta)) {
-      parseMeta(md, ui.area.codemirror, ui.area.markdown, $('#ui-toc'), $('#ui-toc-affix'))
+      parseMeta(
+        md,
+        ui.area.codemirror,
+        ui.area.markdown,
+        $('#ui-toc'),
+        $('#ui-toc-affix')
+      )
       rendered = md.render(value)
     }
     // prevent XSS
     rendered = preventXSS(rendered)
-    var result = postProcess(rendered).children().toArray()
+    const result = postProcess(rendered).children().toArray()
     partialUpdate(result, lastResult, ui.area.markdown.children().toArray())
-    if (result && lastResult && result.length !== lastResult.length) { updateDataAttrs(result, ui.area.markdown.children().toArray()) }
+    if (result && lastResult && result.length !== lastResult.length) {
+      updateDataAttrs(result, ui.area.markdown.children().toArray())
+    }
     lastResult = $(result).clone()
   }
   removeDOMEvents(ui.area.markdown)
@@ -2794,12 +3347,14 @@ function updateViewInner () {
   clearMap()
   // buildMap();
   updateTitleReminder()
-  if (postUpdateEvent && typeof postUpdateEvent === 'function') { postUpdateEvent() }
+  if (postUpdateEvent && typeof postUpdateEvent === 'function') {
+    postUpdateEvent()
+  }
 }
 
-var updateHistoryDebounce = 600
+const updateHistoryDebounce = 600
 
-var updateHistory = _.debounce(updateHistoryInner, updateHistoryDebounce)
+const updateHistory = _.debounce(updateHistoryInner, updateHistoryDebounce)
 
 function updateHistoryInner () {
   writeHistory(renderFilename(ui.area.markdown), renderTags(ui.area.markdown))
@@ -2807,50 +3362,59 @@ function updateHistoryInner () {
 
 function updateDataAttrs (src, des) {
   // sync data attr startline and endline
-  for (var i = 0; i < src.length; i++) {
+  for (let i = 0; i < src.length; i++) {
     copyAttribute(src[i], des[i], 'data-startline')
     copyAttribute(src[i], des[i], 'data-endline')
   }
 }
 
 function partialUpdate (src, tar, des) {
-  if (!src || src.length === 0 || !tar || tar.length === 0 || !des || des.length === 0) {
+  if (
+    !src ||
+    src.length === 0 ||
+    !tar ||
+    tar.length === 0 ||
+    !des ||
+    des.length === 0
+  ) {
     ui.area.markdown.html(src)
     return
   }
-  if (src.length === tar.length) { // same length
+  if (src.length === tar.length) {
+    // same length
     for (let i = 0; i < src.length; i++) {
       copyAttribute(src[i], des[i], 'data-startline')
       copyAttribute(src[i], des[i], 'data-endline')
-      var rawSrc = cloneAndRemoveDataAttr(src[i])
-      var rawTar = cloneAndRemoveDataAttr(tar[i])
+      const rawSrc = cloneAndRemoveDataAttr(src[i])
+      const rawTar = cloneAndRemoveDataAttr(tar[i])
       if (rawSrc.outerHTML !== rawTar.outerHTML) {
         // console.debug(rawSrc);
         // console.debug(rawTar);
         $(des[i]).replaceWith(src[i])
       }
     }
-  } else { // diff length
-    var start = 0
+  } else {
+    // diff length
+    let start = 0
     // find diff start position
     for (let i = 0; i < tar.length; i++) {
       // copyAttribute(src[i], des[i], 'data-startline');
       // copyAttribute(src[i], des[i], 'data-endline');
-      let rawSrc = cloneAndRemoveDataAttr(src[i])
-      let rawTar = cloneAndRemoveDataAttr(tar[i])
+      const rawSrc = cloneAndRemoveDataAttr(src[i])
+      const rawTar = cloneAndRemoveDataAttr(tar[i])
       if (!rawSrc || !rawTar || rawSrc.outerHTML !== rawTar.outerHTML) {
         start = i
         break
       }
     }
     // find diff end position
-    var srcEnd = 0
-    var tarEnd = 0
+    let srcEnd = 0
+    let tarEnd = 0
     for (let i = 0; i < src.length; i++) {
       // copyAttribute(src[i], des[i], 'data-startline');
       // copyAttribute(src[i], des[i], 'data-endline');
-      let rawSrc = cloneAndRemoveDataAttr(src[i])
-      let rawTar = cloneAndRemoveDataAttr(tar[i])
+      const rawSrc = cloneAndRemoveDataAttr(src[i])
+      const rawTar = cloneAndRemoveDataAttr(tar[i])
       if (!rawSrc || !rawTar || rawSrc.outerHTML !== rawTar.outerHTML) {
         start = i
         break
@@ -2858,12 +3422,12 @@ function partialUpdate (src, tar, des) {
     }
     // tar end
     for (let i = 1; i <= tar.length + 1; i++) {
-      let srcLength = src.length
-      let tarLength = tar.length
+      const srcLength = src.length
+      const tarLength = tar.length
       // copyAttribute(src[srcLength - i], des[srcLength - i], 'data-startline');
       // copyAttribute(src[srcLength - i], des[srcLength - i], 'data-endline');
-      let rawSrc = cloneAndRemoveDataAttr(src[srcLength - i])
-      let rawTar = cloneAndRemoveDataAttr(tar[tarLength - i])
+      const rawSrc = cloneAndRemoveDataAttr(src[srcLength - i])
+      const rawTar = cloneAndRemoveDataAttr(tar[tarLength - i])
       if (!rawSrc || !rawTar || rawSrc.outerHTML !== rawTar.outerHTML) {
         tarEnd = tar.length - i
         break
@@ -2871,25 +3435,35 @@ function partialUpdate (src, tar, des) {
     }
     // src end
     for (let i = 1; i <= src.length + 1; i++) {
-      let srcLength = src.length
-      let tarLength = tar.length
+      const srcLength = src.length
+      const tarLength = tar.length
       // copyAttribute(src[srcLength - i], des[srcLength - i], 'data-startline');
       // copyAttribute(src[srcLength - i], des[srcLength - i], 'data-endline');
-      let rawSrc = cloneAndRemoveDataAttr(src[srcLength - i])
-      let rawTar = cloneAndRemoveDataAttr(tar[tarLength - i])
+      const rawSrc = cloneAndRemoveDataAttr(src[srcLength - i])
+      const rawTar = cloneAndRemoveDataAttr(tar[tarLength - i])
       if (!rawSrc || !rawTar || rawSrc.outerHTML !== rawTar.outerHTML) {
         srcEnd = src.length - i
         break
       }
     }
     // check if tar end overlap tar start
-    var overlap = 0
-    for (var i = start; i >= 0; i--) {
-      var rawTarStart = cloneAndRemoveDataAttr(tar[i - 1])
-      var rawTarEnd = cloneAndRemoveDataAttr(tar[tarEnd + 1 + start - i])
-      if (rawTarStart && rawTarEnd && rawTarStart.outerHTML === rawTarEnd.outerHTML) { overlap++ } else { break }
+    let overlap = 0
+    for (let i = start; i >= 0; i--) {
+      const rawTarStart = cloneAndRemoveDataAttr(tar[i - 1])
+      const rawTarEnd = cloneAndRemoveDataAttr(tar[tarEnd + 1 + start - i])
+      if (
+        rawTarStart &&
+        rawTarEnd &&
+        rawTarStart.outerHTML === rawTarEnd.outerHTML
+      ) {
+        overlap++
+      } else {
+        break
+      }
+    }
+    if (debug) {
+      console.debug('overlap:' + overlap)
     }
-    if (debug) { console.debug('overlap:' + overlap) }
     // show diff content
     if (debug) {
       console.debug('start:' + start)
@@ -2898,10 +3472,10 @@ function partialUpdate (src, tar, des) {
     }
     tarEnd += overlap
     srcEnd += overlap
-    var repeatAdd = (start - srcEnd) < (start - tarEnd)
-    var repeatDiff = Math.abs(srcEnd - tarEnd) - 1
+    const repeatAdd = start - srcEnd < start - tarEnd
+    const repeatDiff = Math.abs(srcEnd - tarEnd) - 1
     // push new elements
-    var newElements = []
+    const newElements = []
     if (srcEnd >= start) {
       for (let j = start; j <= srcEnd; j++) {
         if (!src[j]) continue
@@ -2914,7 +3488,7 @@ function partialUpdate (src, tar, des) {
       }
     }
     // push remove elements
-    var removeElements = []
+    const removeElements = []
     if (tarEnd >= start) {
       for (let j = start; j <= tarEnd; j++) {
         if (!des[j]) continue
@@ -2931,28 +3505,38 @@ function partialUpdate (src, tar, des) {
       console.debug('ADD ELEMENTS')
       console.debug(newElements.join('\n'))
     }
-    if (des[start]) { $(newElements.join('')).insertBefore(des[start]) } else { $(newElements.join('')).insertAfter(des[start - 1]) }
+    if (des[start]) {
+      $(newElements.join('')).insertBefore(des[start])
+    } else {
+      $(newElements.join('')).insertAfter(des[start - 1])
+    }
     // remove elements
-    if (debug) { console.debug('REMOVE ELEMENTS') }
+    if (debug) {
+      console.debug('REMOVE ELEMENTS')
+    }
     for (let j = 0; j < removeElements.length; j++) {
       if (debug) {
         console.debug(removeElements[j].outerHTML)
       }
-      if (removeElements[j]) { $(removeElements[j]).remove() }
+      if (removeElements[j]) {
+        $(removeElements[j]).remove()
+      }
     }
   }
 }
 
 function cloneAndRemoveDataAttr (el) {
   if (!el) return
-  var rawEl = $(el).clone()
+  const rawEl = $(el).clone()
   rawEl.removeAttr('data-startline data-endline')
   rawEl.find('[data-startline]').removeAttr('data-startline data-endline')
   return rawEl[0]
 }
 
 function copyAttribute (src, des, attr) {
-  if (src && src.getAttribute(attr) && des) { des.setAttribute(attr, src.getAttribute(attr)) }
+  if (src && src.getAttribute(attr) && des) {
+    des.setAttribute(attr, src.getAttribute(attr))
+  }
 }
 
 if ($('.cursor-menu').length <= 0) {
@@ -2960,69 +3544,83 @@ if ($('.cursor-menu').length <= 0) {
 }
 
 function reverseSortCursorMenu (dropdown) {
-  var items = dropdown.find('.textcomplete-item')
+  const items = dropdown.find('.textcomplete-item')
   items.sort(function (a, b) {
     return $(b).attr('data-index') - $(a).attr('data-index')
   })
   return items
 }
 
-var checkCursorMenu = _.throttle(checkCursorMenuInner, cursorMenuThrottle)
+const checkCursorMenu = _.throttle(checkCursorMenuInner, cursorMenuThrottle)
 
 function checkCursorMenuInner () {
   // get element
-  var dropdown = $('.cursor-menu > .dropdown-menu')
+  const dropdown = $('.cursor-menu > .dropdown-menu')
   // return if not exists
   if (dropdown.length <= 0) return
   // set margin
-  var menuRightMargin = 10
-  var menuBottomMargin = 4
+  const menuRightMargin = 10
+  const menuBottomMargin = 4
   // use sizer to get the real doc size (won't count status bar and gutters)
-  var docWidth = ui.area.codemirrorSizer.width()
+  const docWidth = ui.area.codemirrorSizer.width()
   // get editor size (status bar not count in)
-  var editorHeight = ui.area.codemirror.height()
+  const editorHeight = ui.area.codemirror.height()
   // get element size
-  var width = dropdown.outerWidth()
-  var height = dropdown.outerHeight()
+  const width = dropdown.outerWidth()
+  const height = dropdown.outerHeight()
   // get cursor
-  var cursor = editor.getCursor()
+  const cursor = editor.getCursor()
   // set element cursor data
-  if (!dropdown.hasClass('CodeMirror-other-cursor')) { dropdown.addClass('CodeMirror-other-cursor') }
+  if (!dropdown.hasClass('CodeMirror-other-cursor')) {
+    dropdown.addClass('CodeMirror-other-cursor')
+  }
   dropdown.attr('data-line', cursor.line)
   dropdown.attr('data-ch', cursor.ch)
   // get coord position
-  var coord = editor.charCoords({
-    line: cursor.line,
-    ch: cursor.ch
-  }, 'windows')
-  var left = coord.left
-  var top = coord.top
+  const coord = editor.charCoords(
+    {
+      line: cursor.line,
+      ch: cursor.ch
+    },
+    'windows'
+  )
+  const left = coord.left
+  const top = coord.top
   // get doc top offset (to workaround with viewport)
-  var docTopOffset = ui.area.codemirrorSizerInner.position().top
+  const docTopOffset = ui.area.codemirrorSizerInner.position().top
   // set offset
-  var offsetLeft = 0
-  var offsetTop = defaultTextHeight
+  let offsetLeft = 0
+  let offsetTop = defaultTextHeight
   // set up side down
   window.upSideDown = false
-  var lastUpSideDown = window.upSideDown = false
+  let lastUpSideDown = (window.upSideDown = false)
   // only do when have width and height
   if (width > 0 && height > 0) {
     // make element right bound not larger than doc width
-    if (left + width + offsetLeft + menuRightMargin > docWidth) { offsetLeft = -(left + width - docWidth + menuRightMargin) }
+    if (left + width + offsetLeft + menuRightMargin > docWidth) {
+      offsetLeft = -(left + width - docWidth + menuRightMargin)
+    }
     // flip y when element bottom bound larger than doc height
     // and element top position is larger than element height
-    if (top + docTopOffset + height + offsetTop + menuBottomMargin > Math.max(editor.doc.height, editorHeight) && top + docTopOffset > height + menuBottomMargin) {
+    if (
+      top + docTopOffset + height + offsetTop + menuBottomMargin >
+        Math.max(editor.doc.height, editorHeight) &&
+      top + docTopOffset > height + menuBottomMargin
+    ) {
       offsetTop = -(height + menuBottomMargin)
       // reverse sort menu because upSideDown
       dropdown.html(reverseSortCursorMenu(dropdown))
       window.upSideDown = true
     }
-    var textCompleteDropdown = $(editor.getInputField()).data('textComplete').dropdown
+    const textCompleteDropdown = $(editor.getInputField()).data('textComplete')
+      .dropdown
     lastUpSideDown = textCompleteDropdown.upSideDown
     textCompleteDropdown.upSideDown = window.upSideDown
   }
   // make menu scroll top only if upSideDown changed
-  if (window.upSideDown !== lastUpSideDown) { dropdown.scrollTop(dropdown[0].scrollHeight) }
+  if (window.upSideDown !== lastUpSideDown) {
+    dropdown.scrollTop(dropdown[0].scrollHeight)
+  }
   // set element offset data
   dropdown.attr('data-offset-left', offsetLeft)
   dropdown.attr('data-offset-top', offsetTop)
@@ -3033,33 +3631,37 @@ function checkCursorMenuInner () {
 
 function checkInIndentCode () {
   // if line starts with tab or four spaces is a code block
-  var line = editor.getLine(editor.getCursor().line)
-  var isIndentCode = ((line.substr(0, 4) === '    ') || (line.substr(0, 1) === '\t'))
+  const line = editor.getLine(editor.getCursor().line)
+  const isIndentCode =
+    line.substr(0, 4) === '    ' || line.substr(0, 1) === '\t'
   return isIndentCode
 }
 
-var isInCode = false
+let isInCode = false
 
 function checkInCode () {
   isInCode = checkAbove(matchInCode) || checkInIndentCode()
 }
 
 function checkAbove (method) {
-  var cursor = editor.getCursor()
-  var text = []
-  for (var i = 0; i < cursor.line; i++) { // contain current line
+  const cursor = editor.getCursor()
+  let text = []
+  for (let i = 0; i < cursor.line; i++) {
+    // contain current line
     text.push(editor.getLine(i))
   }
-  text = text.join('\n') + '\n' + editor.getLine(cursor.line).slice(0, cursor.ch)
+  text =
+    text.join('\n') + '\n' + editor.getLine(cursor.line).slice(0, cursor.ch)
   // console.debug(text);
   return method(text)
 }
 
 function checkBelow (method) {
-  var cursor = editor.getCursor()
-  var count = editor.lineCount()
-  var text = []
-  for (var i = cursor.line + 1; i < count; i++) { // contain current line
+  const cursor = editor.getCursor()
+  const count = editor.lineCount()
+  let text = []
+  for (let i = cursor.line + 1; i < count; i++) {
+    // contain current line
     text.push(editor.getLine(i))
   }
   text = editor.getLine(cursor.line).slice(cursor.ch) + '\n' + text.join('\n')
@@ -3068,7 +3670,7 @@ function checkBelow (method) {
 }
 
 function matchInCode (text) {
-  var match
+  let match
   match = text.match(/`{3,}/g)
   if (match && match.length % 2) {
     return true
@@ -3082,8 +3684,8 @@ function matchInCode (text) {
   }
 }
 
-var isInContainer = false
-var isInContainerSyntax = false
+let isInContainer = false
+let isInContainerSyntax = false
 
 function checkInContainer () {
   isInContainer = checkAbove(matchInContainer) && !checkInIndentCode()
@@ -3091,13 +3693,12 @@ function checkInContainer () {
 
 function checkInContainerSyntax () {
   // if line starts with :::, it's in container syntax
-  var line = editor.getLine(editor.getCursor().line)
-  isInContainerSyntax = (line.substr(0, 3) === ':::')
+  const line = editor.getLine(editor.getCursor().line)
+  isInContainerSyntax = line.substr(0, 3) === ':::'
 }
 
 function matchInContainer (text) {
-  var match
-  match = text.match(/:{3,}/g)
+  const match = text.match(/:{3,}/g)
   if (match && match.length % 2) {
     return true
   } else {
@@ -3106,194 +3707,244 @@ function matchInContainer (text) {
 }
 
 $(editor.getInputField())
-  .textcomplete([
-    { // emoji strategy
-      match: /(^|\n|\s)\B:([-+\w]*)$/,
-      search: function (term, callback) {
-        var line = editor.getLine(editor.getCursor().line)
-        term = line.match(this.match)[2]
-        var list = []
-        $.map(window.emojify.emojiNames, function (emoji) {
-          if (emoji.indexOf(term) === 0) { // match at first character
-            list.push(emoji)
+  .textcomplete(
+    [
+      {
+        // emoji strategy
+        match: /(^|\n|\s)\B:([-+\w]*)$/,
+        search: function (term, callback) {
+          const line = editor.getLine(editor.getCursor().line)
+          term = line.match(this.match)[2]
+          const list = []
+          $.map(window.emojify.emojiNames, function (emoji) {
+            if (emoji.indexOf(term) === 0) {
+              // match at first character
+              list.push(emoji)
+            }
+          })
+          $.map(window.emojify.emojiNames, function (emoji) {
+            if (emoji.indexOf(term) !== -1) {
+              // match inside the word
+              list.push(emoji)
+            }
+          })
+          callback(list)
+        },
+        template: function (value) {
+          return (
+            '<img class="emoji" src="' +
+            serverurl +
+            '/build/emojify.js/dist/images/basic/' +
+            value +
+            '.png"></img> ' +
+            value
+          )
+        },
+        replace: function (value) {
+          return '$1:' + value + ': '
+        },
+        index: 1,
+        context: function (text) {
+          checkInCode()
+          checkInContainer()
+          checkInContainerSyntax()
+          return !isInCode && !isInContainerSyntax
+        }
+      },
+      {
+        // Code block language strategy
+        langs: supportCodeModes,
+        charts: supportCharts,
+        match: /(^|\n)```(\w+)$/,
+        search: function (term, callback) {
+          const line = editor.getLine(editor.getCursor().line)
+          term = line.match(this.match)[2]
+          const list = []
+          $.map(this.langs, function (lang) {
+            if (lang.indexOf(term) === 0 && lang !== term) {
+              list.push(lang)
+            }
+          })
+          $.map(this.charts, function (chart) {
+            if (chart.indexOf(term) === 0 && chart !== term) {
+              list.push(chart)
+            }
+          })
+          callback(list)
+        },
+        replace: function (lang) {
+          let ending = ''
+          if (!checkBelow(matchInCode)) {
+            ending = '\n\n```'
           }
-        })
-        $.map(window.emojify.emojiNames, function (emoji) {
-          if (emoji.indexOf(term) !== -1) { // match inside the word
-            list.push(emoji)
+          if (this.langs.indexOf(lang) !== -1) {
+            return '$1```' + lang + '=' + ending
+          } else if (this.charts.indexOf(lang) !== -1) {
+            return '$1```' + lang + ending
           }
-        })
-        callback(list)
-      },
-      template: function (value) {
-        return '<img class="emoji" src="' + serverurl + '/build/emojify.js/dist/images/basic/' + value + '.png"></img> ' + value
-      },
-      replace: function (value) {
-        return '$1:' + value + ': '
-      },
-      index: 1,
-      context: function (text) {
-        checkInCode()
-        checkInContainer()
-        checkInContainerSyntax()
-        return !isInCode && !isInContainerSyntax
-      }
-    },
-    { // Code block language strategy
-      langs: supportCodeModes,
-      charts: supportCharts,
-      match: /(^|\n)```(\w+)$/,
-      search: function (term, callback) {
-        var line = editor.getLine(editor.getCursor().line)
-        term = line.match(this.match)[2]
-        var list = []
-        $.map(this.langs, function (lang) {
-          if (lang.indexOf(term) === 0 && lang !== term) { list.push(lang) }
-        })
-        $.map(this.charts, function (chart) {
-          if (chart.indexOf(term) === 0 && chart !== term) { list.push(chart) }
-        })
-        callback(list)
-      },
-      replace: function (lang) {
-        var ending = ''
-        if (!checkBelow(matchInCode)) {
-          ending = '\n\n```'
+        },
+        done: function () {
+          const cursor = editor.getCursor()
+          let text = []
+          text.push(editor.getLine(cursor.line - 1))
+          text.push(editor.getLine(cursor.line))
+          text = text.join('\n')
+          // console.debug(text);
+          if (text === '\n```') {
+            editor.doc.cm.execCommand('goLineUp')
+          }
+        },
+        context: function (text) {
+          return isInCode
         }
-        if (this.langs.indexOf(lang) !== -1) { return '$1```' + lang + '=' + ending } else if (this.charts.indexOf(lang) !== -1) { return '$1```' + lang + ending }
       },
-      done: function () {
-        var cursor = editor.getCursor()
-        var text = []
-        text.push(editor.getLine(cursor.line - 1))
-        text.push(editor.getLine(cursor.line))
-        text = text.join('\n')
-        // console.debug(text);
-        if (text === '\n```') { editor.doc.cm.execCommand('goLineUp') }
-      },
-      context: function (text) {
-        return isInCode
-      }
-    },
-    { // Container strategy
-      containers: supportContainers,
-      match: /(^|\n):::(\s*)(\w*)$/,
-      search: function (term, callback) {
-        var line = editor.getLine(editor.getCursor().line)
-        term = line.match(this.match)[3].trim()
-        var list = []
-        $.map(this.containers, function (container) {
-          if (container.indexOf(term) === 0 && container !== term) { list.push(container) }
-        })
-        callback(list)
-      },
-      replace: function (lang) {
-        var ending = ''
-        if (!checkBelow(matchInContainer)) {
-          ending = '\n\n:::'
+      {
+        // Container strategy
+        containers: supportContainers,
+        match: /(^|\n):::(\s*)(\w*)$/,
+        search: function (term, callback) {
+          const line = editor.getLine(editor.getCursor().line)
+          term = line.match(this.match)[3].trim()
+          const list = []
+          $.map(this.containers, function (container) {
+            if (container.indexOf(term) === 0 && container !== term) {
+              list.push(container)
+            }
+          })
+          callback(list)
+        },
+        replace: function (lang) {
+          let ending = ''
+          if (!checkBelow(matchInContainer)) {
+            ending = '\n\n:::'
+          }
+          if (this.containers.indexOf(lang) !== -1) {
+            return '$1:::$2' + lang + ending
+          }
+        },
+        done: function () {
+          const cursor = editor.getCursor()
+          let text = []
+          text.push(editor.getLine(cursor.line - 1))
+          text.push(editor.getLine(cursor.line))
+          text = text.join('\n')
+          // console.debug(text);
+          if (text === '\n:::') {
+            editor.doc.cm.execCommand('goLineUp')
+          }
+        },
+        context: function (text) {
+          return !isInCode && isInContainer
         }
-        if (this.containers.indexOf(lang) !== -1) { return '$1:::$2' + lang + ending }
-      },
-      done: function () {
-        var cursor = editor.getCursor()
-        var text = []
-        text.push(editor.getLine(cursor.line - 1))
-        text.push(editor.getLine(cursor.line))
-        text = text.join('\n')
-        // console.debug(text);
-        if (text === '\n:::') { editor.doc.cm.execCommand('goLineUp') }
-      },
-      context: function (text) {
-        return !isInCode && isInContainer
-      }
-    },
-    { // header
-      match: /(?:^|\n)(\s{0,3})(#{1,6}\w*)$/,
-      search: function (term, callback) {
-        callback($.map(supportHeaders, function (header) {
-          return header.search.indexOf(term) === 0 ? header.text : null
-        }))
-      },
-      replace: function (value) {
-        return '$1' + value
-      },
-      context: function (text) {
-        return !isInCode
-      }
-    },
-    { // extra tags for list
-      match: /(^[>\s]*[-+*]\s(?:\[[x ]\]|.*))(\[\])(\w*)$/,
-      search: function (term, callback) {
-        var list = []
-        $.map(supportExtraTags, function (extratag) {
-          if (extratag.search.indexOf(term) === 0) { list.push(extratag.command()) }
-        })
-        $.map(supportReferrals, function (referral) {
-          if (referral.search.indexOf(term) === 0) { list.push(referral.text) }
-        })
-        callback(list)
       },
-      replace: function (value) {
-        return '$1' + value
+      {
+        // header
+        match: /(?:^|\n)(\s{0,3})(#{1,6}\w*)$/,
+        search: function (term, callback) {
+          callback(
+            $.map(supportHeaders, function (header) {
+              return header.search.indexOf(term) === 0 ? header.text : null
+            })
+          )
+        },
+        replace: function (value) {
+          return '$1' + value
+        },
+        context: function (text) {
+          return !isInCode
+        }
       },
-      context: function (text) {
-        return !isInCode
-      }
-    },
-    { // extra tags for blockquote
-      match: /(?:^|\n|\s)(>.*|\s|)((\^|)\[(\^|)\](\[\]|\(\)|:|)\s*\w*)$/,
-      search: function (term, callback) {
-        var line = editor.getLine(editor.getCursor().line)
-        var quote = line.match(this.match)[1].trim()
-        var list = []
-        if (quote.indexOf('>') === 0) {
+      {
+        // extra tags for list
+        match: /(^[>\s]*[-+*]\s(?:\[[x ]\]|.*))(\[\])(\w*)$/,
+        search: function (term, callback) {
+          const list = []
           $.map(supportExtraTags, function (extratag) {
-            if (extratag.search.indexOf(term) === 0) { list.push(extratag.command()) }
+            if (extratag.search.indexOf(term) === 0) {
+              list.push(extratag.command())
+            }
           })
+          $.map(supportReferrals, function (referral) {
+            if (referral.search.indexOf(term) === 0) {
+              list.push(referral.text)
+            }
+          })
+          callback(list)
+        },
+        replace: function (value) {
+          return '$1' + value
+        },
+        context: function (text) {
+          return !isInCode
         }
-        $.map(supportReferrals, function (referral) {
-          if (referral.search.indexOf(term) === 0) { list.push(referral.text) }
-        })
-        callback(list)
-      },
-      replace: function (value) {
-        return '$1' + value
-      },
-      context: function (text) {
-        return !isInCode
-      }
-    },
-    { // referral
-      match: /(^\s*|\n|\s{2})((\[\]|\[\]\[\]|\[\]\(\)|!|!\[\]|!\[\]\[\]|!\[\]\(\))\s*\w*)$/,
-      search: function (term, callback) {
-        callback($.map(supportReferrals, function (referral) {
-          return referral.search.indexOf(term) === 0 ? referral.text : null
-        }))
-      },
-      replace: function (value) {
-        return '$1' + value
       },
-      context: function (text) {
-        return !isInCode
-      }
-    },
-    { // externals
-      match: /(^|\n|\s)\{\}(\w*)$/,
-      search: function (term, callback) {
-        callback($.map(supportExternals, function (external) {
-          return external.search.indexOf(term) === 0 ? external.text : null
-        }))
+      {
+        // extra tags for blockquote
+        match: /(?:^|\n|\s)(>.*|\s|)((\^|)\[(\^|)\](\[\]|\(\)|:|)\s*\w*)$/,
+        search: function (term, callback) {
+          const line = editor.getLine(editor.getCursor().line)
+          const quote = line.match(this.match)[1].trim()
+          const list = []
+          if (quote.indexOf('>') === 0) {
+            $.map(supportExtraTags, function (extratag) {
+              if (extratag.search.indexOf(term) === 0) {
+                list.push(extratag.command())
+              }
+            })
+          }
+          $.map(supportReferrals, function (referral) {
+            if (referral.search.indexOf(term) === 0) {
+              list.push(referral.text)
+            }
+          })
+          callback(list)
+        },
+        replace: function (value) {
+          return '$1' + value
+        },
+        context: function (text) {
+          return !isInCode
+        }
       },
-      replace: function (value) {
-        return '$1' + value
+      {
+        // referral
+        match: /(^\s*|\n|\s{2})((\[\]|\[\]\[\]|\[\]\(\)|!|!\[\]|!\[\]\[\]|!\[\]\(\))\s*\w*)$/,
+        search: function (term, callback) {
+          callback(
+            $.map(supportReferrals, function (referral) {
+              return referral.search.indexOf(term) === 0 ? referral.text : null
+            })
+          )
+        },
+        replace: function (value) {
+          return '$1' + value
+        },
+        context: function (text) {
+          return !isInCode
+        }
       },
-      context: function (text) {
-        return !isInCode
+      {
+        // externals
+        match: /(^|\n|\s)\{\}(\w*)$/,
+        search: function (term, callback) {
+          callback(
+            $.map(supportExternals, function (external) {
+              return external.search.indexOf(term) === 0 ? external.text : null
+            })
+          )
+        },
+        replace: function (value) {
+          return '$1' + value
+        },
+        context: function (text) {
+          return !isInCode
+        }
       }
+    ],
+    {
+      appendTo: $('.cursor-menu')
     }
-  ], {
-    appendTo: $('.cursor-menu')
-  })
+  )
   .on({
     'textComplete:beforeSearch': function (e) {
       // NA
@@ -3307,22 +3958,22 @@ $(editor.getInputField())
     'textComplete:show': function (e) {
       $(this).data('autocompleting', true)
       editor.setOption('extraKeys', {
-        'Up': function () {
+        Up: function () {
           return false
         },
-        'Right': function () {
+        Right: function () {
           editor.doc.cm.execCommand('goCharRight')
         },
-        'Down': function () {
+        Down: function () {
           return false
         },
-        'Left': function () {
+        Left: function () {
           editor.doc.cm.execCommand('goCharLeft')
         },
-        'Enter': function () {
+        Enter: function () {
           return false
         },
-        'Backspace': function () {
+        Backspace: function () {
           editor.doc.cm.execCommand('delCharBefore')
         }
       })
diff --git a/public/js/lib/appState.js b/public/js/lib/appState.js
index 87aaf737..f409908c 100644
--- a/public/js/lib/appState.js
+++ b/public/js/lib/appState.js
@@ -1,6 +1,6 @@
 import modeType from './modeType'
 
-let state = {
+const state = {
   syncscroll: true,
   currentMode: modeType.view,
   nightMode: false
diff --git a/public/js/lib/common/login.js b/public/js/lib/common/login.js
index 3f7a3e4d..88e8f8cf 100644
--- a/public/js/lib/common/login.js
+++ b/public/js/lib/common/login.js
@@ -7,7 +7,7 @@ let checkAuth = false
 let profile = null
 let lastLoginState = getLoginState()
 let lastUserId = getUserId()
-var loginStateChangeEvent = null
+let loginStateChangeEvent = null
 
 export function setloginStateChangeEvent (func) {
   loginStateChangeEvent = func
diff --git a/public/js/lib/editor/config.js b/public/js/lib/editor/config.js
index 9508b847..338ef6dc 100644
--- a/public/js/lib/editor/config.js
+++ b/public/js/lib/editor/config.js
@@ -1,4 +1,4 @@
-let config = {
+const config = {
   docmaxlength: null
 }
 
diff --git a/public/js/lib/editor/index.js b/public/js/lib/editor/index.js
index d86ebf3c..c84a3725 100644
--- a/public/js/lib/editor/index.js
+++ b/public/js/lib/editor/index.js
@@ -35,30 +35,30 @@ export default class Editor {
       },
       Enter: 'newlineAndIndentContinueMarkdownList',
       Tab: function (cm) {
-        var tab = '\t'
+        const tab = '\t'
 
         // contruct x length spaces
-        var spaces = Array(parseInt(cm.getOption('indentUnit')) + 1).join(' ')
+        const spaces = Array(parseInt(cm.getOption('indentUnit')) + 1).join(' ')
 
         // auto indent whole line when in list or blockquote
-        var cursor = cm.getCursor()
-        var line = cm.getLine(cursor.line)
+        const cursor = cm.getCursor()
+        const line = cm.getLine(cursor.line)
 
         // this regex match the following patterns
         // 1. blockquote starts with "> " or ">>"
         // 2. unorder list starts with *+-
         // 3. order list starts with "1." or "1)"
-        var regex = /^(\s*)(>[> ]*|[*+-]\s|(\d+)([.)]))/
+        const regex = /^(\s*)(>[> ]*|[*+-]\s|(\d+)([.)]))/
 
-        var match
-        var multiple = cm.getSelection().split('\n').length > 1 ||
+        let match
+        const multiple = cm.getSelection().split('\n').length > 1 ||
           cm.getSelections().length > 1
 
         if (multiple) {
           cm.execCommand('defaultTab')
         } else if ((match = regex.exec(line)) !== null) {
-          var ch = match[1].length
-          var pos = {
+          const ch = match[1].length
+          const pos = {
             line: cursor.line,
             ch: ch
           }
@@ -77,8 +77,8 @@ export default class Editor {
       },
       'Cmd-Left': 'goLineLeftSmart',
       'Cmd-Right': 'goLineRight',
-      'Home': 'goLineLeftSmart',
-      'End': 'goLineRight',
+      Home: 'goLineLeftSmart',
+      End: 'goLineRight',
       'Ctrl-C': function (cm) {
         if (!isMac && cm.getOption('keyMap').substr(0, 3) === 'vim') {
           document.execCommand('copy')
@@ -140,27 +140,27 @@ export default class Editor {
   }
 
   addToolBar () {
-    var inlineAttach = inlineAttachment.editors.codemirror4.attach(this.editor)
+    const inlineAttach = inlineAttachment.editors.codemirror4.attach(this.editor)
     this.toolBar = $(toolBarTemplate)
     this.toolbarPanel = this.editor.addPanel(this.toolBar[0], {
       position: 'top'
     })
 
-    var makeBold = $('#makeBold')
-    var makeItalic = $('#makeItalic')
-    var makeStrike = $('#makeStrike')
-    var makeHeader = $('#makeHeader')
-    var makeCode = $('#makeCode')
-    var makeQuote = $('#makeQuote')
-    var makeGenericList = $('#makeGenericList')
-    var makeOrderedList = $('#makeOrderedList')
-    var makeCheckList = $('#makeCheckList')
-    var makeLink = $('#makeLink')
-    var makeImage = $('#makeImage')
-    var makeTable = $('#makeTable')
-    var makeLine = $('#makeLine')
-    var makeComment = $('#makeComment')
-    var uploadImage = $('#uploadImage')
+    const makeBold = $('#makeBold')
+    const makeItalic = $('#makeItalic')
+    const makeStrike = $('#makeStrike')
+    const makeHeader = $('#makeHeader')
+    const makeCode = $('#makeCode')
+    const makeQuote = $('#makeQuote')
+    const makeGenericList = $('#makeGenericList')
+    const makeOrderedList = $('#makeOrderedList')
+    const makeCheckList = $('#makeCheckList')
+    const makeLink = $('#makeLink')
+    const makeImage = $('#makeImage')
+    const makeTable = $('#makeTable')
+    const makeLine = $('#makeLine')
+    const makeComment = $('#makeComment')
+    const uploadImage = $('#uploadImage')
 
     makeBold.click(() => {
       utils.wrapTextWith(this.editor, this.editor, '**')
@@ -223,7 +223,7 @@ export default class Editor {
     })
 
     uploadImage.bind('change', function (e) {
-      var files = e.target.files || e.dataTransfer.files
+      const files = e.target.files || e.dataTransfer.files
       e.dataTransfer = {}
       e.dataTransfer.files = files
       inlineAttach.onDrop(e)
@@ -256,12 +256,12 @@ export default class Editor {
   updateStatusBar () {
     if (!this.statusBar) return
 
-    var cursor = this.editor.getCursor()
-    var cursorText = 'Line ' + (cursor.line + 1) + ', Columns ' + (cursor.ch + 1)
+    const cursor = this.editor.getCursor()
+    const cursorText = 'Line ' + (cursor.line + 1) + ', Columns ' + (cursor.ch + 1)
     this.statusCursor.text(cursorText)
-    var fileText = ' — ' + editor.lineCount() + ' Lines'
+    const fileText = ' — ' + editor.lineCount() + ' Lines'
     this.statusFile.text(fileText)
-    var docLength = editor.getValue().length
+    const docLength = editor.getValue().length
     this.statusLength.text('Length ' + docLength)
     if (docLength > (config.docmaxlength * 0.95)) {
       this.statusLength.css('color', 'red')
@@ -276,9 +276,9 @@ export default class Editor {
   }
 
   setIndent () {
-    var cookieIndentType = Cookies.get('indent_type')
-    var cookieTabSize = parseInt(Cookies.get('tab_size'))
-    var cookieSpaceUnits = parseInt(Cookies.get('space_units'))
+    const cookieIndentType = Cookies.get('indent_type')
+    let cookieTabSize = parseInt(Cookies.get('tab_size'))
+    let cookieSpaceUnits = parseInt(Cookies.get('space_units'))
     if (cookieIndentType) {
       if (cookieIndentType === 'tab') {
         this.editor.setOption('indentWithTabs', true)
@@ -296,9 +296,9 @@ export default class Editor {
       this.editor.setOption('tabSize', cookieTabSize)
     }
 
-    var type = this.statusIndicators.find('.indent-type')
-    var widthLabel = this.statusIndicators.find('.indent-width-label')
-    var widthInput = this.statusIndicators.find('.indent-width-input')
+    const type = this.statusIndicators.find('.indent-type')
+    const widthLabel = this.statusIndicators.find('.indent-width-label')
+    const widthInput = this.statusIndicators.find('.indent-width-input')
 
     const setType = () => {
       if (this.editor.getOption('indentWithTabs')) {
@@ -318,7 +318,7 @@ export default class Editor {
     setType()
 
     const setUnit = () => {
-      var unit = this.editor.getOption('indentUnit')
+      const unit = this.editor.getOption('indentUnit')
       if (this.editor.getOption('indentWithTabs')) {
         Cookies.set('tab_size', unit, {
           expires: 365,
@@ -364,7 +364,7 @@ export default class Editor {
       }
     })
     widthInput.on('change', () => {
-      var val = parseInt(widthInput.val())
+      let val = parseInt(widthInput.val())
       if (!val) val = this.editor.getOption('indentUnit')
       if (val < 1) val = 1
       else if (val > 10) val = 10
@@ -382,18 +382,18 @@ export default class Editor {
   }
 
   setKeymap () {
-    var cookieKeymap = Cookies.get('keymap')
+    const cookieKeymap = Cookies.get('keymap')
     if (cookieKeymap) {
       this.editor.setOption('keyMap', cookieKeymap)
     }
 
-    var label = this.statusIndicators.find('.ui-keymap-label')
-    var sublime = this.statusIndicators.find('.ui-keymap-sublime')
-    var emacs = this.statusIndicators.find('.ui-keymap-emacs')
-    var vim = this.statusIndicators.find('.ui-keymap-vim')
+    const label = this.statusIndicators.find('.ui-keymap-label')
+    const sublime = this.statusIndicators.find('.ui-keymap-sublime')
+    const emacs = this.statusIndicators.find('.ui-keymap-emacs')
+    const vim = this.statusIndicators.find('.ui-keymap-vim')
 
     const setKeymapLabel = () => {
-      var keymap = this.editor.getOption('keyMap')
+      const keymap = this.editor.getOption('keyMap')
       Cookies.set('keymap', keymap, {
         expires: 365,
         sameSite: window.cookiePolicy
@@ -419,15 +419,15 @@ export default class Editor {
   }
 
   setTheme () {
-    var cookieTheme = Cookies.get('theme')
+    const cookieTheme = Cookies.get('theme')
     if (cookieTheme) {
       this.editor.setOption('theme', cookieTheme)
     }
 
-    var themeToggle = this.statusTheme.find('.ui-theme-toggle')
+    const themeToggle = this.statusTheme.find('.ui-theme-toggle')
 
     const checkTheme = () => {
-      var theme = this.editor.getOption('theme')
+      const theme = this.editor.getOption('theme')
       if (theme === 'one-dark') {
         themeToggle.removeClass('active')
       } else {
@@ -436,7 +436,7 @@ export default class Editor {
     }
 
     themeToggle.click(() => {
-      var theme = this.editor.getOption('theme')
+      let theme = this.editor.getOption('theme')
       if (theme === 'one-dark') {
         theme = 'default'
       } else {
@@ -455,9 +455,9 @@ export default class Editor {
   }
 
   setSpellcheck () {
-    var cookieSpellcheck = Cookies.get('spellcheck')
+    const cookieSpellcheck = Cookies.get('spellcheck')
     if (cookieSpellcheck) {
-      var mode = null
+      let mode = null
       if (cookieSpellcheck === 'true' || cookieSpellcheck === true) {
         mode = 'spell-checker'
       } else {
@@ -468,10 +468,10 @@ export default class Editor {
       }
     }
 
-    var spellcheckToggle = this.statusSpellcheck.find('.ui-spellcheck-toggle')
+    const spellcheckToggle = this.statusSpellcheck.find('.ui-spellcheck-toggle')
 
     const checkSpellcheck = () => {
-      var mode = this.editor.getOption('mode')
+      const mode = this.editor.getOption('mode')
       if (mode === defaultEditorMode) {
         spellcheckToggle.removeClass('active')
       } else {
@@ -480,7 +480,7 @@ export default class Editor {
     }
 
     spellcheckToggle.click(() => {
-      var mode = this.editor.getOption('mode')
+      let mode = this.editor.getOption('mode')
       if (mode === defaultEditorMode) {
         mode = 'spell-checker'
       } else {
@@ -501,7 +501,7 @@ export default class Editor {
 
     // workaround spellcheck might not activate beacuse the ajax loading
     if (window.num_loaded < 2) {
-      var spellcheckTimer = setInterval(
+      const spellcheckTimer = setInterval(
         () => {
           if (window.num_loaded >= 2) {
             if (this.editor.getOption('mode') === 'spell-checker') {
@@ -516,7 +516,7 @@ export default class Editor {
   }
 
   resetEditorKeymapToBrowserKeymap () {
-    var keymap = this.editor.getOption('keyMap')
+    const keymap = this.editor.getOption('keyMap')
     if (!this.jumpToAddressBarKeymapValue) {
       this.jumpToAddressBarKeymapValue = CodeMirror.keyMap[keymap][jumpToAddressBarKeymapName]
       delete CodeMirror.keyMap[keymap][jumpToAddressBarKeymapName]
@@ -524,14 +524,15 @@ export default class Editor {
   }
 
   restoreOverrideEditorKeymap () {
-    var keymap = this.editor.getOption('keyMap')
+    const keymap = this.editor.getOption('keyMap')
     if (this.jumpToAddressBarKeymapValue) {
       CodeMirror.keyMap[keymap][jumpToAddressBarKeymapName] = this.jumpToAddressBarKeymapValue
       this.jumpToAddressBarKeymapValue = null
     }
   }
+
   setOverrideBrowserKeymap () {
-    var overrideBrowserKeymap = $(
+    const overrideBrowserKeymap = $(
       '.ui-preferences-override-browser-keymap label > input[type="checkbox"]'
     )
     if (overrideBrowserKeymap.is(':checked')) {
@@ -547,10 +548,10 @@ export default class Editor {
   }
 
   setPreferences () {
-    var overrideBrowserKeymap = $(
+    const overrideBrowserKeymap = $(
       '.ui-preferences-override-browser-keymap label > input[type="checkbox"]'
     )
-    var cookieOverrideBrowserKeymap = Cookies.get(
+    const cookieOverrideBrowserKeymap = Cookies.get(
       'preferences-override-browser-keymap'
     )
     if (cookieOverrideBrowserKeymap && cookieOverrideBrowserKeymap === 'true') {
diff --git a/public/js/lib/editor/utils.js b/public/js/lib/editor/utils.js
index d87c7e41..70428b28 100644
--- a/public/js/lib/editor/utils.js
+++ b/public/js/lib/editor/utils.js
@@ -3,17 +3,17 @@ export function wrapTextWith (editor, cm, symbol) {
   if (!cm.getSelection()) {
     return CodeMirror.Pass
   } else {
-    let ranges = cm.listSelections()
+    const ranges = cm.listSelections()
     for (let i = 0; i < ranges.length; i++) {
-      let range = ranges[i]
+      const range = ranges[i]
       if (!range.empty()) {
         const from = range.from()
         const to = range.to()
 
         if (symbol !== 'Backspace') {
-          let selection = cm.getRange(from, to)
-          let anchorIndex = editor.indexFromPos(ranges[i].anchor)
-          let headIndex = editor.indexFromPos(ranges[i].head)
+          const selection = cm.getRange(from, to)
+          const anchorIndex = editor.indexFromPos(ranges[i].anchor)
+          const headIndex = editor.indexFromPos(ranges[i].head)
           cm.replaceRange(symbol + selection + symbol, from, to, '+input')
           if (anchorIndex > headIndex) {
             ranges[i].anchor.ch += symbol.length
@@ -24,18 +24,18 @@ export function wrapTextWith (editor, cm, symbol) {
           }
           cm.setSelections(ranges)
         } else {
-          let preEndPos = {
+          const preEndPos = {
             line: to.line,
             ch: to.ch + symbol.length
           }
-          let preText = cm.getRange(to, preEndPos)
-          let preIndex = wrapSymbols.indexOf(preText)
-          let postEndPos = {
+          const preText = cm.getRange(to, preEndPos)
+          const preIndex = wrapSymbols.indexOf(preText)
+          const postEndPos = {
             line: from.line,
             ch: from.ch - symbol.length
           }
-          let postText = cm.getRange(postEndPos, from)
-          let postIndex = wrapSymbols.indexOf(postText)
+          const postText = cm.getRange(postEndPos, from)
+          const postIndex = wrapSymbols.indexOf(postText)
           // check if surround symbol are list in array and matched
           if (preIndex > -1 && postIndex > -1 && preIndex === postIndex) {
             cm.replaceRange('', to, preEndPos, '+delete')
@@ -48,25 +48,25 @@ export function wrapTextWith (editor, cm, symbol) {
 }
 
 export function insertText (cm, text, cursorEnd = 0) {
-  let cursor = cm.getCursor()
+  const cursor = cm.getCursor()
   cm.replaceSelection(text, cursor, cursor)
   cm.focus()
   cm.setCursor({ line: cursor.line, ch: cursor.ch + cursorEnd })
 }
 
 export function insertLink (cm, isImage) {
-  let cursor = cm.getCursor()
-  let ranges = cm.listSelections()
+  const cursor = cm.getCursor()
+  const ranges = cm.listSelections()
   const linkEnd = '](https://)'
   const symbol = (isImage) ? '![' : '['
 
   for (let i = 0; i < ranges.length; i++) {
-    let range = ranges[i]
+    const range = ranges[i]
     if (!range.empty()) {
       const from = range.from()
       const to = range.to()
-      let anchorIndex = editor.indexFromPos(ranges[i].anchor)
-      let headIndex = editor.indexFromPos(ranges[i].head)
+      const anchorIndex = editor.indexFromPos(ranges[i].anchor)
+      const headIndex = editor.indexFromPos(ranges[i].head)
       let selection = cm.getRange(from, to)
       selection = symbol + selection + linkEnd
       cm.replaceRange(selection, from, to)
@@ -87,9 +87,9 @@ export function insertLink (cm, isImage) {
 }
 
 export function insertHeader (cm) {
-  let cursor = cm.getCursor()
-  let startOfLine = { line: cursor.line, ch: 0 }
-  let startOfLineText = cm.getRange(startOfLine, { line: cursor.line, ch: 1 })
+  const cursor = cm.getCursor()
+  const startOfLine = { line: cursor.line, ch: 0 }
+  const startOfLineText = cm.getRange(startOfLine, { line: cursor.line, ch: 1 })
   // See if it is already a header
   if (startOfLineText === '#') {
     cm.replaceRange('#', startOfLine, startOfLine)
@@ -100,11 +100,11 @@ export function insertHeader (cm) {
 }
 
 export function insertOnStartOfLines (cm, symbol) {
-  let cursor = cm.getCursor()
-  let ranges = cm.listSelections()
+  const cursor = cm.getCursor()
+  const ranges = cm.listSelections()
 
   for (let i = 0; i < ranges.length; i++) {
-    let range = ranges[i]
+    const range = ranges[i]
     if (!range.empty()) {
       const from = range.from()
       const to = range.to()
diff --git a/public/js/lib/syncscroll.js b/public/js/lib/syncscroll.js
index d492fbc9..f033d00d 100644
--- a/public/js/lib/syncscroll.js
+++ b/public/js/lib/syncscroll.js
@@ -155,12 +155,12 @@ const buildMap = _.throttle(buildMapInner, buildMapThrottle)
 // Optimizations are required only for big texts.
 function buildMapInner (callback) {
   if (!viewArea || !markdownArea) return
-  let i, offset, nonEmptyList, pos, a, b, _lineHeightMap, linesCount, acc, _scrollMap
+  let i, pos, a, b, acc
 
-  offset = viewArea.scrollTop() - viewArea.offset().top
-  _scrollMap = []
-  nonEmptyList = []
-  _lineHeightMap = []
+  const offset = viewArea.scrollTop() - viewArea.offset().top
+  const _scrollMap = []
+  const nonEmptyList = []
+  const _lineHeightMap = []
   viewTop = 0
   viewBottom = viewArea[0].scrollHeight - viewArea.height()
 
@@ -181,7 +181,7 @@ function buildMapInner (callback) {
     acc += Math.round(h / lineHeight)
   }
   _lineHeightMap.push(acc)
-  linesCount = acc
+  const linesCount = acc
 
   for (i = 0; i < linesCount; i++) {
     _scrollMap.push(-1)
@@ -290,11 +290,12 @@ export function syncScrollToEdit (event, preventAnimate) {
     posTo += Math.ceil(posToNextDiff)
   }
 
+  let duration = 0
   if (preventAnimate) {
     editArea.scrollTop(posTo)
   } else {
     const posDiff = Math.abs(scrollInfo.top - posTo)
-    var duration = posDiff / 50
+    duration = posDiff / 50
     duration = duration >= 100 ? duration : 100
     editArea.stop(true, true).animate({
       scrollTop: posTo
@@ -331,11 +332,11 @@ export function syncScrollToView (event, preventAnimate) {
   }
   if (viewScrolling) return
 
-  let lineNo, posTo
+  let posTo
   let topDiffPercent, posToNextDiff
   const scrollInfo = editor.getScrollInfo()
   const textHeight = editor.defaultTextHeight()
-  lineNo = Math.floor(scrollInfo.top / textHeight)
+  const lineNo = Math.floor(scrollInfo.top / textHeight)
   // if reach the last line, will start lerp to the bottom
   const diffToBottom = (scrollInfo.top + scrollInfo.clientHeight) - (scrollInfo.height - textHeight)
   if (scrollInfo.height > scrollInfo.clientHeight && diffToBottom > 0) {
@@ -350,11 +351,12 @@ export function syncScrollToView (event, preventAnimate) {
     posTo += Math.floor(posToNextDiff)
   }
 
+  let duration = 0
   if (preventAnimate) {
     viewArea.scrollTop(posTo)
   } else {
     const posDiff = Math.abs(viewArea.scrollTop() - posTo)
-    var duration = posDiff / 50
+    duration = posDiff / 50
     duration = duration >= 100 ? duration : 100
     viewArea.stop(true, true).animate({
       scrollTop: posTo
diff --git a/public/js/render.js b/public/js/render.js
index ebda2984..af6fb3d4 100644
--- a/public/js/render.js
+++ b/public/js/render.js
@@ -1,40 +1,40 @@
 /* eslint-env browser, jquery */
 // allow some attributes
 
-var filterXSS = require('xss')
+const filterXSS = require('xss')
 
-var whiteListAttr = ['id', 'class', 'style']
+const whiteListAttr = ['id', 'class', 'style']
 window.whiteListAttr = whiteListAttr
 // allow link starts with '.', '/' and custom protocol with '://', exclude link starts with javascript://
-var linkRegex = /^(?!javascript:\/\/)([\w|-]+:\/\/)|^([.|/])+/i
+const linkRegex = /^(?!javascript:\/\/)([\w|-]+:\/\/)|^([.|/])+/i
 // allow data uri, from https://gist.github.com/bgrins/6194623
-var dataUriRegex = /^\s*data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base64)?,([a-z0-9!$&',()*+;=\-._~:@/?%\s]*)\s*$/i
+const dataUriRegex = /^\s*data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base64)?,([a-z0-9!$&',()*+;=\-._~:@/?%\s]*)\s*$/i
 // custom white list
-var whiteList = filterXSS.whiteList
+const whiteList = filterXSS.whiteList
 // allow ol specify start number
-whiteList['ol'] = ['start']
+whiteList.ol = ['start']
 // allow li specify value number
-whiteList['li'] = ['value']
+whiteList.li = ['value']
 // allow style tag
-whiteList['style'] = []
+whiteList.style = []
 // allow kbd tag
-whiteList['kbd'] = []
+whiteList.kbd = []
 // allow ifram tag with some safe attributes
-whiteList['iframe'] = ['allowfullscreen', 'name', 'referrerpolicy', 'src', 'width', 'height']
+whiteList.iframe = ['allowfullscreen', 'name', 'referrerpolicy', 'src', 'width', 'height']
 // allow summary tag
-whiteList['summary'] = []
+whiteList.summary = []
 // allow ruby tag
-whiteList['ruby'] = []
+whiteList.ruby = []
 // allow rp tag for ruby
-whiteList['rp'] = []
+whiteList.rp = []
 // allow rt tag for ruby
-whiteList['rt'] = []
+whiteList.rt = []
 // allow figure tag
-whiteList['figure'] = []
+whiteList.figure = []
 // allow figcaption tag
-whiteList['figcaption'] = []
+whiteList.figcaption = []
 
-var filterXSSOptions = {
+const filterXSSOptions = {
   allowCommentTag: true,
   whiteList: whiteList,
   escapeHtml: function (html) {
diff --git a/public/js/reveal-markdown.js b/public/js/reveal-markdown.js
index c49bb9a2..89cd0887 100644
--- a/public/js/reveal-markdown.js
+++ b/public/js/reveal-markdown.js
@@ -17,28 +17,28 @@ import { md } from './extra'
     root.RevealMarkdown.initialize()
   }
 }(this, function () {
-  var DEFAULT_SLIDE_SEPARATOR = '^\r?\n---\r?\n$'
-  var DEFAULT_NOTES_SEPARATOR = '^note:'
-  var DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR = '\\.element\\s*?(.+?)$'
-  var DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR = '\\.slide:\\s*?(\\S.+?)$'
+  const DEFAULT_SLIDE_SEPARATOR = '^\r?\n---\r?\n$'
+  const DEFAULT_NOTES_SEPARATOR = '^note:'
+  const DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR = '\\.element\\s*?(.+?)$'
+  const DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR = '\\.slide:\\s*?(\\S.+?)$'
 
-  var SCRIPT_END_PLACEHOLDER = '__SCRIPT_END__'
+  const SCRIPT_END_PLACEHOLDER = '__SCRIPT_END__'
 
   /**
    * Retrieves the markdown contents of a slide section
    * element. Normalizes leading tabs/whitespace.
    */
   function getMarkdownFromSlide (section) {
-    var template = section.querySelector('script')
+    const template = section.querySelector('script')
 
     // strip leading whitespace so it isn't evaluated as code
-    var text = (template || section).textContent
+    let text = (template || section).textContent
 
     // restore script end tags
     text = text.replace(new RegExp(SCRIPT_END_PLACEHOLDER, 'g'), '</script>')
 
-    var leadingWs = text.match(/^\n?(\s*)/)[1].length
-    var leadingTabs = text.match(/^\n?(\t*)/)[1].length
+    const leadingWs = text.match(/^\n?(\s*)/)[1].length
+    const leadingTabs = text.match(/^\n?(\t*)/)[1].length
 
     if (leadingTabs > 0) {
       text = text.replace(new RegExp('\\n?\\t{' + leadingTabs + '}', 'g'), '\n')
@@ -56,12 +56,12 @@ import { md } from './extra'
    * to the output markdown slide.
    */
   function getForwardedAttributes (section) {
-    var attributes = section.attributes
-    var result = []
+    const attributes = section.attributes
+    const result = []
 
-    for (var i = 0, len = attributes.length; i < len; i++) {
-      var name = attributes[i].name
-      var value = attributes[i].value
+    for (let i = 0, len = attributes.length; i < len; i++) {
+      const name = attributes[i].name
+      const value = attributes[i].value
 
       // disregard attributes that are used for markdown loading/parsing
       if (/data-(markdown|separator|vertical|notes)/gi.test(name)) continue
@@ -95,7 +95,7 @@ import { md } from './extra'
   function createMarkdownSlide (content, options) {
     options = getSlidifyOptions(options)
 
-    var notesMatch = content.split(new RegExp(options.notesSeparator, 'mgi'))
+    const notesMatch = content.split(new RegExp(options.notesSeparator, 'mgi'))
 
     if (notesMatch.length === 2) {
       content = notesMatch[0] + '<aside class="notes" data-markdown>' + notesMatch[1].trim() + '</aside>'
@@ -115,15 +115,15 @@ import { md } from './extra'
   function slidify (markdown, options) {
     options = getSlidifyOptions(options)
 
-    var separatorRegex = new RegExp(options.separator + (options.verticalSeparator ? '|' + options.verticalSeparator : ''), 'mg')
-    var horizontalSeparatorRegex = new RegExp(options.separator)
+    const separatorRegex = new RegExp(options.separator + (options.verticalSeparator ? '|' + options.verticalSeparator : ''), 'mg')
+    const horizontalSeparatorRegex = new RegExp(options.separator)
 
-    var matches
-    var lastIndex = 0
-    var isHorizontal
-    var wasHorizontal = true
-    var content
-    var sectionStack = []
+    let matches
+    let lastIndex = 0
+    let isHorizontal
+    let wasHorizontal = true
+    let content
+    const sectionStack = []
 
     // iterate until all blocks between separators are stacked up
     while ((matches = separatorRegex.exec(markdown)) !== null) {
@@ -153,10 +153,10 @@ import { md } from './extra'
     // add the remaining slide
     (wasHorizontal ? sectionStack : sectionStack[sectionStack.length - 1]).push(markdown.substring(lastIndex))
 
-    var markdownSections = ''
+    let markdownSections = ''
 
     // flatten the hierarchical stack, and insert <section data-markdown> tags
-    for (var i = 0, len = sectionStack.length; i < len; i++) {
+    for (let i = 0, len = sectionStack.length; i < len; i++) {
       // vertical
       if (sectionStack[i] instanceof Array) {
         markdownSections += '<section ' + options.attributes + '>'
@@ -180,17 +180,17 @@ import { md } from './extra'
    * handles loading of external markdown.
    */
   function processSlides () {
-    var sections = document.querySelectorAll('[data-markdown]')
-    var section
+    const sections = document.querySelectorAll('[data-markdown]')
+    let section
 
-    for (var i = 0, len = sections.length; i < len; i++) {
+    for (let i = 0, len = sections.length; i < len; i++) {
       section = sections[i]
 
       if (section.getAttribute('data-markdown').length) {
-        var xhr = new XMLHttpRequest()
-        var url = section.getAttribute('data-markdown')
+        const xhr = new XMLHttpRequest()
+        const url = section.getAttribute('data-markdown')
 
-        var datacharset = section.getAttribute('data-charset')
+        const datacharset = section.getAttribute('data-charset')
 
         // see https://developer.mozilla.org/en-US/docs/Web/API/element.getAttribute#Notes
         if (datacharset !== null && datacharset !== '') {
@@ -247,18 +247,18 @@ import { md } from './extra'
    * http://stackoverflow.com/questions/5690269/disabling-chrome-cache-for-website-development/7000899#answer-11786277
    */
   function addAttributeInElement (node, elementTarget, separator) {
-    var mardownClassesInElementsRegex = new RegExp(separator, 'mg')
-    var mardownClassRegex = new RegExp('([^"= ]+?)="([^"=]+?)"', 'mg')
-    var nodeValue = node.nodeValue
-    var matches
-    var matchesClass
+    const mardownClassesInElementsRegex = new RegExp(separator, 'mg')
+    const mardownClassRegex = /([^"= ]+?)="([^"=]+?)"/mg
+    let nodeValue = node.nodeValue
+    let matches
+    let matchesClass
     if ((matches = mardownClassesInElementsRegex.exec(nodeValue))) {
-      var classes = matches[1]
+      const classes = matches[1]
       nodeValue = nodeValue.substring(0, matches.index) + nodeValue.substring(mardownClassesInElementsRegex.lastIndex)
       node.nodeValue = nodeValue
       while ((matchesClass = mardownClassRegex.exec(classes))) {
-        var name = matchesClass[1]
-        var value = matchesClass[2]
+        const name = matchesClass[1]
+        const value = matchesClass[2]
         if (name.substr(0, 5) === 'data-' || window.whiteListAttr.indexOf(name) !== -1) { elementTarget.setAttribute(name, escapeAttrValue(value)) }
       }
       return true
@@ -272,13 +272,13 @@ import { md } from './extra'
    */
   function addAttributes (section, element, previousElement, separatorElementAttributes, separatorSectionAttributes) {
     if (element != null && element.childNodes !== undefined && element.childNodes.length > 0) {
-      var previousParentElement = element
-      for (var i = 0; i < element.childNodes.length; i++) {
-        var childElement = element.childNodes[i]
+      let previousParentElement = element
+      for (let i = 0; i < element.childNodes.length; i++) {
+        const childElement = element.childNodes[i]
         if (i > 0) {
           let j = i - 1
           while (j >= 0) {
-            var aPreviousChildElement = element.childNodes[j]
+            const aPreviousChildElement = element.childNodes[j]
             if (typeof aPreviousChildElement.setAttribute === 'function' && aPreviousChildElement.tagName !== 'BR') {
               previousParentElement = aPreviousChildElement
               break
@@ -286,7 +286,7 @@ import { md } from './extra'
             j = j - 1
           }
         }
-        var parentSection = section
+        let parentSection = section
         if (childElement.nodeName === 'section') {
           parentSection = childElement
           previousParentElement = childElement
@@ -309,21 +309,21 @@ import { md } from './extra'
    * DOM to HTML.
    */
   function convertSlides () {
-    var sections = document.querySelectorAll('[data-markdown]')
+    const sections = document.querySelectorAll('[data-markdown]')
 
-    for (var i = 0, len = sections.length; i < len; i++) {
-      var section = sections[i]
+    for (let i = 0, len = sections.length; i < len; i++) {
+      const section = sections[i]
 
       // Only parse the same slide once
       if (!section.getAttribute('data-markdown-parsed')) {
         section.setAttribute('data-markdown-parsed', true)
 
-        var notes = section.querySelector('aside.notes')
-        var markdown = getMarkdownFromSlide(section)
+        const notes = section.querySelector('aside.notes')
+        let markdown = getMarkdownFromSlide(section)
         markdown = markdown.replace(/&lt;/g, '<').replace(/&gt;/g, '>')
-        var rendered = md.render(markdown)
+        let rendered = md.render(markdown)
         rendered = preventXSS(rendered)
-        var result = window.postProcess(rendered)
+        const result = window.postProcess(rendered)
         section.innerHTML = result[0].outerHTML
         addAttributes(section, section, null, section.getAttribute('data-element-attributes') ||
         section.parentNode.getAttribute('data-element-attributes') ||
diff --git a/public/js/slide.js b/public/js/slide.js
index b8374cbb..5a28993f 100644
--- a/public/js/slide.js
+++ b/public/js/slide.js
@@ -26,7 +26,7 @@ function extend () {
 
   for (const source of arguments) {
     for (const key in source) {
-      if (source.hasOwnProperty(key)) {
+      if (Object.prototype.hasOwnProperty.call(source, key)) {
         target[key] = source[key]
       }
     }
@@ -36,18 +36,21 @@ function extend () {
 }
 
 // Optional libraries used to extend on reveal.js
-const deps = [{
-  src: `${serverurl}/build/reveal.js/lib/js/classList.js`,
-  condition () {
-    return !document.body.classList
-  }
-}, {
-  src: `${serverurl}/build/reveal.js/plugin/notes/notes.js`,
-  async: true,
-  condition () {
-    return !!document.body.classList
+const deps = [
+  {
+    src: `${serverurl}/build/reveal.js/lib/js/classList.js`,
+    condition () {
+      return !document.body.classList
+    }
+  },
+  {
+    src: `${serverurl}/build/reveal.js/plugin/notes/notes.js`,
+    async: true,
+    condition () {
+      return !!document.body.classList
+    }
   }
-}]
+]
 
 const slideOptions = {
   separator: '^(\r\n?|\n)---(\r\n?|\n)$',
@@ -73,60 +76,64 @@ const defaultOptions = {
 // options from yaml meta
 const meta = JSON.parse($('#meta').text())
 const metaSlideOptions = !!meta && !!meta.slideOptions ? meta.slideOptions : {}
-var options = {
-  autoPlayMedia: metaSlideOptions.autoPlayMedia,
-  autoSlide: metaSlideOptions.autoSlide,
-  autoSlideStoppable: metaSlideOptions.autoSlideStoppable,
-  backgroundTransition: metaSlideOptions.backgroundTransition,
-  center: metaSlideOptions.center,
-  controls: metaSlideOptions.controls,
-  controlsBackArrows: metaSlideOptions.controlsBackArrows,
-  controlsLayout: metaSlideOptions.controlsLayout,
-  controlsTutorial: metaSlideOptions.controlsTutorial,
-  defaultTiming: metaSlideOptions.defaultTiming,
-  display: metaSlideOptions.display,
-  embedded: metaSlideOptions.embedded,
-  fragmentInURL: metaSlideOptions.fragmentInURL,
-  fragments: metaSlideOptions.fragments,
-  hash: metaSlideOptions.hash,
-  height: metaSlideOptions.height,
-  help: metaSlideOptions.help,
-  hideAddressBar: metaSlideOptions.hideAddressBar,
-  hideCursorTime: metaSlideOptions.hideCursorTime,
-  hideInactiveCursor: metaSlideOptions.hideInactiveCursor,
-  history: metaSlideOptions.history,
-  keyboard: metaSlideOptions.keyboard,
-  loop: metaSlideOptions.loop,
-  margin: metaSlideOptions.margin,
-  maxScale: metaSlideOptions.maxScale,
-  minScale: metaSlideOptions.minScale,
-  minimumTimePerSlide: metaSlideOptions.minimumTimePerSlide,
-  mobileViewDistance: metaSlideOptions.mobileViewDistance,
-  mouseWheel: metaSlideOptions.mouseWheel,
-  navigationMode: metaSlideOptions.navigationMode,
-  overview: metaSlideOptions.overview,
-  parallaxBackgroundHorizontal: metaSlideOptions.parallaxBackgroundHorizontal,
-  parallaxBackgroundImage: metaSlideOptions.parallaxBackgroundImage,
-  parallaxBackgroundSize: metaSlideOptions.parallaxBackgroundSize,
-  parallaxBackgroundVertical: metaSlideOptions.parallaxBackgroundVertical,
-  preloadIframes: metaSlideOptions.preloadIframes,
-  previewLinks: metaSlideOptions.previewLinks,
-  progress: metaSlideOptions.progress,
-  rtl: metaSlideOptions.rtl,
-  showNotes: metaSlideOptions.showNotes,
-  shuffle: metaSlideOptions.shuffle,
-  slideNumber: metaSlideOptions.slideNumber,
-  theme: metaSlideOptions.theme,
-  totalTime: metaSlideOptions.totalTime,
-  touch: metaSlideOptions.touch,
-  transition: metaSlideOptions.transition,
-  transitionSpeed: metaSlideOptions.transitionSpeed,
-  viewDistance: metaSlideOptions.viewDistance,
-  width: metaSlideOptions.width
-} || {}
+let options =
+  {
+    autoPlayMedia: metaSlideOptions.autoPlayMedia,
+    autoSlide: metaSlideOptions.autoSlide,
+    autoSlideStoppable: metaSlideOptions.autoSlideStoppable,
+    backgroundTransition: metaSlideOptions.backgroundTransition,
+    center: metaSlideOptions.center,
+    controls: metaSlideOptions.controls,
+    controlsBackArrows: metaSlideOptions.controlsBackArrows,
+    controlsLayout: metaSlideOptions.controlsLayout,
+    controlsTutorial: metaSlideOptions.controlsTutorial,
+    defaultTiming: metaSlideOptions.defaultTiming,
+    display: metaSlideOptions.display,
+    embedded: metaSlideOptions.embedded,
+    fragmentInURL: metaSlideOptions.fragmentInURL,
+    fragments: metaSlideOptions.fragments,
+    hash: metaSlideOptions.hash,
+    height: metaSlideOptions.height,
+    help: metaSlideOptions.help,
+    hideAddressBar: metaSlideOptions.hideAddressBar,
+    hideCursorTime: metaSlideOptions.hideCursorTime,
+    hideInactiveCursor: metaSlideOptions.hideInactiveCursor,
+    history: metaSlideOptions.history,
+    keyboard: metaSlideOptions.keyboard,
+    loop: metaSlideOptions.loop,
+    margin: metaSlideOptions.margin,
+    maxScale: metaSlideOptions.maxScale,
+    minScale: metaSlideOptions.minScale,
+    minimumTimePerSlide: metaSlideOptions.minimumTimePerSlide,
+    mobileViewDistance: metaSlideOptions.mobileViewDistance,
+    mouseWheel: metaSlideOptions.mouseWheel,
+    navigationMode: metaSlideOptions.navigationMode,
+    overview: metaSlideOptions.overview,
+    parallaxBackgroundHorizontal: metaSlideOptions.parallaxBackgroundHorizontal,
+    parallaxBackgroundImage: metaSlideOptions.parallaxBackgroundImage,
+    parallaxBackgroundSize: metaSlideOptions.parallaxBackgroundSize,
+    parallaxBackgroundVertical: metaSlideOptions.parallaxBackgroundVertical,
+    preloadIframes: metaSlideOptions.preloadIframes,
+    previewLinks: metaSlideOptions.previewLinks,
+    progress: metaSlideOptions.progress,
+    rtl: metaSlideOptions.rtl,
+    showNotes: metaSlideOptions.showNotes,
+    shuffle: metaSlideOptions.shuffle,
+    slideNumber: metaSlideOptions.slideNumber,
+    theme: metaSlideOptions.theme,
+    totalTime: metaSlideOptions.totalTime,
+    touch: metaSlideOptions.touch,
+    transition: metaSlideOptions.transition,
+    transitionSpeed: metaSlideOptions.transitionSpeed,
+    viewDistance: metaSlideOptions.viewDistance,
+    width: metaSlideOptions.width
+  } || {}
 
 for (const key in options) {
-  if (options.hasOwnProperty(key) && options[key] === undefined) {
+  if (
+    Object.prototype.hasOwnProperty.call(options, key) &&
+    options[key] === undefined
+  ) {
     delete options[key]
   }
 }
@@ -165,14 +172,14 @@ window.viewAjaxCallback = () => {
 function renderSlide (event) {
   if (window.location.search.match(/print-pdf/gi)) {
     const slides = $('.slides')
-    let title = document.title
+    const title = document.title
     finishView(slides)
     document.title = title
     Reveal.layout()
   } else {
     const markdown = $(event.currentSlide)
     if (!markdown.attr('data-rendered')) {
-      let title = document.title
+      const title = document.title
       finishView(markdown)
       markdown.attr('data-rendered', 'true')
       document.title = title
@@ -181,7 +188,7 @@ function renderSlide (event) {
   }
 }
 
-Reveal.addEventListener('ready', event => {
+Reveal.addEventListener('ready', (event) => {
   renderSlide(event)
   const markdown = $(event.currentSlide)
   // force browser redraw
diff --git a/public/js/utils.js b/public/js/utils.js
index 91e7f133..d42a18e7 100644
--- a/public/js/utils.js
+++ b/public/js/utils.js
@@ -1,9 +1,9 @@
 import base64url from 'base64url'
 
-let uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
+const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
 
 export function checkNoteIdValid (id) {
-  let result = id.match(uuidRegex)
+  const result = id.match(uuidRegex)
   if (result && result.length === 1) {
     return true
   } else {
@@ -13,16 +13,16 @@ export function checkNoteIdValid (id) {
 
 export function encodeNoteId (id) {
   // remove dashes in UUID and encode in url-safe base64
-  let str = id.replace(/-/g, '')
-  let hexStr = Buffer.from(str, 'hex')
+  const str = id.replace(/-/g, '')
+  const hexStr = Buffer.from(str, 'hex')
   return base64url.encode(hexStr)
 }
 
 export function decodeNoteId (encodedId) {
   // decode from url-safe base64
-  let id = base64url.toBuffer(encodedId).toString('hex')
+  const id = base64url.toBuffer(encodedId).toString('hex')
   // add dashes between the UUID string parts
-  let idParts = []
+  const idParts = []
   idParts.push(id.substr(0, 8))
   idParts.push(id.substr(8, 4))
   idParts.push(id.substr(12, 4))
-- 
cgit v1.2.3