commit
5ecea7e118
6 changed files with 192 additions and 159 deletions
|
@ -1,12 +1,16 @@
|
|||
root = true
|
||||
|
||||
# Tab indentation
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[{*.html,*.ejs}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
|
|
|
@ -19,6 +19,9 @@ require('./lib/common/login')
|
|||
require('../vendor/md-toc')
|
||||
var Viz = require('viz.js')
|
||||
|
||||
import getUIElements from './lib/editor/ui-elements'
|
||||
const ui = getUIElements()
|
||||
|
||||
// auto update last change
|
||||
window.createtime = null
|
||||
window.lastchangetime = null
|
||||
|
@ -634,7 +637,7 @@ function generateCleanHTML (view) {
|
|||
}
|
||||
|
||||
export function exportToRawHTML (view) {
|
||||
const filename = `${renderFilename(window.ui.area.markdown)}.html`
|
||||
const filename = `${renderFilename(ui.area.markdown)}.html`
|
||||
const src = generateCleanHTML(view)
|
||||
$(src).find('a.anchor').remove()
|
||||
const html = src[0].outerHTML
|
||||
|
@ -646,8 +649,8 @@ export function exportToRawHTML (view) {
|
|||
|
||||
// extract markdown body to html and compile to template
|
||||
export function exportToHTML (view) {
|
||||
const title = renderTitle(window.ui.area.markdown)
|
||||
const filename = `${renderFilename(window.ui.area.markdown)}.html`
|
||||
const title = renderTitle(ui.area.markdown)
|
||||
const filename = `${renderFilename(ui.area.markdown)}.html`
|
||||
const src = generateCleanHTML(view)
|
||||
// generate toc
|
||||
const toc = $('#ui-toc').clone()
|
||||
|
|
|
@ -12,14 +12,14 @@ require('../css/site.css')
|
|||
|
||||
require('highlight.js/styles/github-gist.css')
|
||||
|
||||
var toMarkdown = require('to-markdown')
|
||||
import toMarkdown from 'to-markdown'
|
||||
|
||||
var saveAs = require('file-saver').saveAs
|
||||
var randomColor = require('randomcolor')
|
||||
import { saveAs } from 'file-saver'
|
||||
import randomColor from 'randomcolor'
|
||||
|
||||
var _ = require('lodash')
|
||||
import _ from 'lodash'
|
||||
|
||||
var List = require('list.js')
|
||||
import List from 'list.js'
|
||||
|
||||
import {
|
||||
checkLoginStateChanged,
|
||||
|
@ -75,10 +75,10 @@ import {
|
|||
removeHistory
|
||||
} from './history'
|
||||
|
||||
var renderer = require('./render')
|
||||
var preventXSS = renderer.preventXSS
|
||||
import { preventXSS } from './render'
|
||||
|
||||
import Editor from './lib/editor'
|
||||
import EditorConfig from './lib/editor/config'
|
||||
|
||||
import getUIElements from './lib/editor/ui-elements'
|
||||
|
||||
|
@ -314,60 +314,14 @@ if (!textit) {
|
|||
const editorInstance = new Editor()
|
||||
var editor = editorInstance.init(textit)
|
||||
|
||||
// TODO: global referncing in jquery-textcomplete patch
|
||||
// FIXME: global referncing in jquery-textcomplete patch
|
||||
window.editor = editor
|
||||
|
||||
var inlineAttach = inlineAttachment.editors.codemirror4.attach(editor)
|
||||
defaultTextHeight = parseInt($('.CodeMirror').css('line-height'))
|
||||
|
||||
var selection = null
|
||||
|
||||
function updateStatusBar () {
|
||||
if (!editorInstance.statusBar) return
|
||||
var cursor = editor.getCursor()
|
||||
var cursorText = 'Line ' + (cursor.line + 1) + ', Columns ' + (cursor.ch + 1)
|
||||
if (selection) {
|
||||
var anchor = selection.anchor
|
||||
var head = selection.head
|
||||
var start = head.line <= anchor.line ? head : anchor
|
||||
var end = head.line >= anchor.line ? head : anchor
|
||||
var selectionText = ' — Selected '
|
||||
var selectionCharCount = Math.abs(head.ch - anchor.ch)
|
||||
// borrow from brackets EditorStatusBar.js
|
||||
if (start.line !== end.line) {
|
||||
var lines = end.line - start.line + 1
|
||||
if (end.ch === 0) {
|
||||
lines--
|
||||
}
|
||||
selectionText += lines + ' lines'
|
||||
} else if (selectionCharCount > 0) {
|
||||
selectionText += selectionCharCount + ' columns'
|
||||
}
|
||||
if (start.line !== end.line || selectionCharCount > 0) {
|
||||
cursorText += selectionText
|
||||
}
|
||||
}
|
||||
editorInstance.statusCursor.text(cursorText)
|
||||
var fileText = ' — ' + editor.lineCount() + ' Lines'
|
||||
editorInstance.statusFile.text(fileText)
|
||||
var docLength = editor.getValue().length
|
||||
editorInstance.statusLength.text('Length ' + docLength)
|
||||
if (docLength > (docmaxlength * 0.95)) {
|
||||
editorInstance.statusLength.css('color', 'red')
|
||||
editorInstance.statusLength.attr('title', 'Your almost reach note max length limit.')
|
||||
} else if (docLength > (docmaxlength * 0.8)) {
|
||||
editorInstance.statusLength.css('color', 'orange')
|
||||
editorInstance.statusLength.attr('title', 'You nearly fill the note, consider to make more pieces.')
|
||||
} else {
|
||||
editorInstance.statusLength.css('color', 'white')
|
||||
editorInstance.statusLength.attr('title', 'You could write up to ' + docmaxlength + ' characters in this note.')
|
||||
}
|
||||
}
|
||||
|
||||
// initalize ui reference
|
||||
// TODO: fix ui exporting
|
||||
const ui = getUIElements()
|
||||
window.ui = ui
|
||||
|
||||
// page actions
|
||||
var opts = {
|
||||
|
@ -853,7 +807,7 @@ function changeMode (type) {
|
|||
// add and update status bar
|
||||
if (!editorInstance.statusBar) {
|
||||
editorInstance.addStatusBar()
|
||||
updateStatusBar()
|
||||
editorInstance.updateStatusBar()
|
||||
}
|
||||
// work around foldGutter might not init properly
|
||||
editor.setOption('foldGutter', false)
|
||||
|
@ -1868,7 +1822,7 @@ socket.on('disconnect', function (data) {
|
|||
socket.on('reconnect', function (data) {
|
||||
// sync back any change in offline
|
||||
emitUserStatus(true)
|
||||
cursorActivity()
|
||||
cursorActivity(editor)
|
||||
socket.emit('online users')
|
||||
})
|
||||
socket.on('connect', function (data) {
|
||||
|
@ -1941,10 +1895,6 @@ function initMarkAndCheckGutter (mark, author, timestamp) {
|
|||
}
|
||||
return mark
|
||||
}
|
||||
var gutterStylePrefix = 'border-left: 3px solid '
|
||||
var gutterStylePostfix = '; height: ' + defaultTextHeight + 'px; margin-left: 3px;'
|
||||
var textMarkderStylePrefix = 'background-image: linear-gradient(to top, '
|
||||
var textMarkderStylePostfix = ' 1px, transparent 1px);'
|
||||
var addStyleRule = (function () {
|
||||
var added = {}
|
||||
var styleElement = document.createElement('style')
|
||||
|
@ -2061,11 +2011,11 @@ function updateAuthorshipInner () {
|
|||
for (let i = 0; i < addTextMarkers.length; i++) {
|
||||
let textMarker = addTextMarkers[i]
|
||||
let author = authors[textMarker.userid]
|
||||
var rgbcolor = hex2rgb(author.color)
|
||||
var colorString = 'rgba(' + rgbcolor.red + ',' + rgbcolor.green + ',' + rgbcolor.blue + ',0.7)'
|
||||
var styleString = textMarkderStylePrefix + colorString + textMarkderStylePostfix
|
||||
let className = 'authorship-inline-' + author.color.substr(1)
|
||||
var rule = '.' + className + '{' + styleString + '}'
|
||||
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 rule = `.${className} { ${styleString} }`
|
||||
addStyleRule(rule)
|
||||
editor.markText(textMarker.pos[0], textMarker.pos[1], {
|
||||
className: 'authorship-inline ' + className,
|
||||
|
@ -2079,12 +2029,12 @@ function iterateLine (line) {
|
|||
var author = currMark ? authors[currMark.gutter.userid] : null
|
||||
if (currMark && author) {
|
||||
let className = 'authorship-gutter-' + author.color.substr(1)
|
||||
var gutters = line.gutterMarkers
|
||||
const gutters = line.gutterMarkers
|
||||
if (!gutters || !gutters['authorship-gutters'] ||
|
||||
!gutters['authorship-gutters'].className ||
|
||||
!gutters['authorship-gutters'].className.indexOf(className) < 0) {
|
||||
var styleString = gutterStylePrefix + author.color + gutterStylePostfix
|
||||
var rule = '.' + className + '{' + styleString + '}'
|
||||
const styleString = `border-left: 3px solid ${author.color}; height: ${defaultTextHeight}px; margin-left: 3px;`
|
||||
const rule = `.${className} { ${styleString} }`
|
||||
addStyleRule(rule)
|
||||
var gutter = $('<div>', {
|
||||
class: 'authorship-gutter ' + className,
|
||||
|
@ -2104,7 +2054,7 @@ function iterateLine (line) {
|
|||
}
|
||||
}
|
||||
}
|
||||
editor.on('update', function () {
|
||||
editorInstance.on('update', function () {
|
||||
$('.authorship-gutter:not([data-original-title])').tooltip({
|
||||
container: '.CodeMirror-lines',
|
||||
placement: 'right',
|
||||
|
@ -2128,12 +2078,12 @@ socket.on('check', function (data) {
|
|||
socket.on('permission', function (data) {
|
||||
updatePermission(data.permission)
|
||||
})
|
||||
var docmaxlength = null
|
||||
|
||||
var permission = null
|
||||
socket.on('refresh', function (data) {
|
||||
// console.log(data);
|
||||
docmaxlength = data.docmaxlength
|
||||
editor.setOption('maxLength', docmaxlength)
|
||||
EditorConfig.docmaxlength = data.docmaxlength
|
||||
editor.setOption('maxLength', EditorConfig.docmaxlength)
|
||||
updateInfo(data)
|
||||
updatePermission(data.permission)
|
||||
if (!window.loaded) {
|
||||
|
@ -2655,7 +2605,7 @@ function enforceMaxLength (cm, change) {
|
|||
return false
|
||||
}
|
||||
var ignoreEmitEvents = ['setValue', 'ignoreHistory']
|
||||
editor.on('beforeChange', function (cm, change) {
|
||||
editorInstance.on('beforeChange', function (cm, change) {
|
||||
if (debug) { console.debug(change) }
|
||||
removeNullByte(cm, change)
|
||||
if (enforceMaxLength(cm, change)) {
|
||||
|
@ -2683,13 +2633,13 @@ editor.on('beforeChange', function (cm, change) {
|
|||
}
|
||||
if (cmClient && !socket.connected) { cmClient.editorAdapter.ignoreNextChange = true }
|
||||
})
|
||||
editor.on('cut', function () {
|
||||
editorInstance.on('cut', function () {
|
||||
// na
|
||||
})
|
||||
editor.on('paste', function () {
|
||||
editorInstance.on('paste', function () {
|
||||
// na
|
||||
})
|
||||
editor.on('changes', function (cm, changes) {
|
||||
editorInstance.on('changes', function (editor, changes) {
|
||||
updateHistory()
|
||||
var docLength = editor.getValue().length
|
||||
// workaround for big documents
|
||||
|
@ -2713,7 +2663,7 @@ editor.on('changes', function (cm, changes) {
|
|||
}
|
||||
}
|
||||
})
|
||||
editor.on('focus', function (cm) {
|
||||
editorInstance.on('focus', function (editor) {
|
||||
for (var i = 0; i < window.onlineUsers.length; i++) {
|
||||
if (window.onlineUsers[i].id === window.personalInfo.id) {
|
||||
window.onlineUsers[i].cursor = editor.getCursor()
|
||||
|
@ -2722,18 +2672,10 @@ editor.on('focus', function (cm) {
|
|||
window.personalInfo['cursor'] = editor.getCursor()
|
||||
socket.emit('cursor focus', editor.getCursor())
|
||||
})
|
||||
editor.on('cursorActivity', function (cm) {
|
||||
updateStatusBar()
|
||||
cursorActivity()
|
||||
})
|
||||
editor.on('beforeSelectionChange', function (doc, selections) {
|
||||
if (selections) { selection = selections.ranges[0] } else { selection = null }
|
||||
updateStatusBar()
|
||||
})
|
||||
|
||||
var cursorActivity = _.debounce(cursorActivityInner, cursorActivityDebounce)
|
||||
const cursorActivity = _.debounce(cursorActivityInner, cursorActivityDebounce)
|
||||
|
||||
function cursorActivityInner () {
|
||||
function cursorActivityInner (editor) {
|
||||
if (editorHasFocus() && !Visibility.hidden()) {
|
||||
for (var i = 0; i < window.onlineUsers.length; i++) {
|
||||
if (window.onlineUsers[i].id === window.personalInfo.id) {
|
||||
|
@ -2744,7 +2686,44 @@ function cursorActivityInner () {
|
|||
socket.emit('cursor activity', editor.getCursor())
|
||||
}
|
||||
}
|
||||
editor.on('blur', function (cm) {
|
||||
|
||||
editorInstance.on('cursorActivity', editorInstance.updateStatusBar)
|
||||
editorInstance.on('cursorActivity', cursorActivity)
|
||||
|
||||
editorInstance.on('beforeSelectionChange', editorInstance.updateStatusBar)
|
||||
editorInstance.on('beforeSelectionChange', function (doc, selections) {
|
||||
// check selection and whether the statusbar has added
|
||||
if (selections && editorInstance.statusSelection) {
|
||||
const selection = selections.ranges[0]
|
||||
|
||||
const anchor = selection.anchor
|
||||
const head = selection.head
|
||||
const start = head.line <= anchor.line ? head : anchor
|
||||
const end = head.line >= anchor.line ? head : anchor
|
||||
const selectionCharCount = Math.abs(head.ch - anchor.ch)
|
||||
|
||||
let selectionText = ' — Selected '
|
||||
|
||||
// borrow from brackets EditorStatusBar.js
|
||||
if (start.line !== end.line) {
|
||||
var lines = end.line - start.line + 1
|
||||
if (end.ch === 0) {
|
||||
lines--
|
||||
}
|
||||
selectionText += lines + ' lines'
|
||||
} else if (selectionCharCount > 0) {
|
||||
selectionText += selectionCharCount + ' columns'
|
||||
}
|
||||
|
||||
if (start.line !== end.line || selectionCharCount > 0) {
|
||||
editorInstance.statusSelection.text(selectionText)
|
||||
} else {
|
||||
editorInstance.statusSelection.text('')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
editorInstance.on('blur', function (cm) {
|
||||
for (var i = 0; i < window.onlineUsers.length; i++) {
|
||||
if (window.onlineUsers[i].id === window.personalInfo.id) {
|
||||
window.onlineUsers[i].cursor = null
|
||||
|
|
5
public/js/lib/editor/config.js
Normal file
5
public/js/lib/editor/config.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
let config = {
|
||||
docmaxlength: null
|
||||
}
|
||||
|
||||
export default config
|
|
@ -1,4 +1,5 @@
|
|||
import * as utils from './utils'
|
||||
import config from './config'
|
||||
|
||||
/* config section */
|
||||
const isMac = CodeMirror.keyMap.default === CodeMirror.keyMap.macDefault
|
||||
|
@ -116,22 +117,37 @@ export default class Editor {
|
|||
utils.wrapTextWith(this.editor, cm, 'Backspace')
|
||||
}
|
||||
}
|
||||
this.eventListeners = {}
|
||||
}
|
||||
|
||||
getStatusBarTemplate (callback) {
|
||||
$.get(window.serverurl + '/views/statusbar.html', template => {
|
||||
on (event, cb) {
|
||||
if (!this.eventListeners[event]) {
|
||||
this.eventListeners[event] = [cb]
|
||||
} else {
|
||||
this.eventListeners[event].push(cb)
|
||||
}
|
||||
|
||||
this.editor.on(event, (...args) => {
|
||||
this.eventListeners[event].forEach(cb => cb.bind(this)(...args))
|
||||
})
|
||||
}
|
||||
|
||||
getStatusBarTemplate () {
|
||||
return new Promise((resolve, reject) => {
|
||||
$.get(window.serverurl + '/views/statusbar.html').done(template => {
|
||||
this.statusBarTemplate = template
|
||||
if (callback) callback()
|
||||
resolve()
|
||||
}).fail(reject)
|
||||
})
|
||||
}
|
||||
|
||||
addStatusBar () {
|
||||
if (!this.statusBarTemplate) {
|
||||
this.getStatusBarTemplate(this.addStatusBar)
|
||||
return
|
||||
}
|
||||
this.getStatusBarTemplate.then(this.addStatusBar)
|
||||
} else {
|
||||
this.statusBar = $(this.statusBarTemplate)
|
||||
this.statusCursor = this.statusBar.find('.status-cursor')
|
||||
this.statusCursor = this.statusBar.find('.status-cursor > .status-line-column')
|
||||
this.statusSelection = this.statusBar.find('.status-cursor > .status-selection')
|
||||
this.statusFile = this.statusBar.find('.status-file')
|
||||
this.statusIndicators = this.statusBar.find('.status-indicators')
|
||||
this.statusIndent = this.statusBar.find('.status-indent')
|
||||
|
@ -150,6 +166,29 @@ export default class Editor {
|
|||
this.setSpellcheck()
|
||||
this.setPreferences()
|
||||
}
|
||||
}
|
||||
|
||||
updateStatusBar () {
|
||||
if (!this.statusBar) return
|
||||
|
||||
var cursor = this.editor.getCursor()
|
||||
var cursorText = 'Line ' + (cursor.line + 1) + ', Columns ' + (cursor.ch + 1)
|
||||
this.statusCursor.text(cursorText)
|
||||
var fileText = ' — ' + editor.lineCount() + ' Lines'
|
||||
this.statusFile.text(fileText)
|
||||
var docLength = editor.getValue().length
|
||||
this.statusLength.text('Length ' + docLength)
|
||||
if (docLength > (config.docmaxlength * 0.95)) {
|
||||
this.statusLength.css('color', 'red')
|
||||
this.statusLength.attr('title', 'Your almost reach note max length limit.')
|
||||
} else if (docLength > (config.docmaxlength * 0.8)) {
|
||||
this.statusLength.css('color', 'orange')
|
||||
this.statusLength.attr('title', 'You nearly fill the note, consider to make more pieces.')
|
||||
} else {
|
||||
this.statusLength.css('color', 'white')
|
||||
this.statusLength.attr('title', 'You could write up to ' + config.docmaxlength + ' characters in this note.')
|
||||
}
|
||||
}
|
||||
|
||||
setIndent () {
|
||||
var cookieIndentType = Cookies.get('indent_type')
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
<div class="status-bar">
|
||||
<div class="status-info">
|
||||
<div class="status-cursor"></div>
|
||||
<div class="status-cursor">
|
||||
<span class="status-line-column"></span>
|
||||
<span class="status-selection"></span>
|
||||
</div>
|
||||
<div class="status-file"></div>
|
||||
</div>
|
||||
<div class="status-indicators">
|
||||
|
|
Loading…
Reference in a new issue