Skip to content

Commit a8b664f

Browse files
committed
Add a toolbar to Codemirror editor
Signed-off-by: Edgar Zanella Alvarenga <e@vaz.io>
1 parent 82c7f9d commit a8b664f

5 files changed

Lines changed: 202 additions & 0 deletions

File tree

public/css/index.css

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,24 @@ body.night{
2020
background: #333 !important;
2121
}
2222

23+
.toolbar {
24+
background-color: #1c1c1e;
25+
border: 1px solid #343434;
26+
}
27+
28+
.toolbar > .btn-toolbar > .btn-group > .btn {
29+
background-color: #1c1c1e;
30+
padding: 5px;
31+
font-size: 1em;
32+
}
33+
34+
.toolbar > .btn-toolbar > .btn-group > .btn:hover {
35+
background-color: #383a3e;
36+
37+
padding: 5px;
38+
}
39+
40+
2341
.CodeMirror {
2442
font-family: "Source Code Pro", Consolas, monaco, monospace;
2543
letter-spacing: 0.025em;

public/js/index.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import {
3030
import {
3131
debug,
3232
DROPBOX_APP_KEY,
33+
GOOGLE_API_KEY,
34+
GOOGLE_CLIENT_ID,
3335
noteid,
3436
noteurl,
3537
urlpath,
@@ -566,6 +568,9 @@ var previousFocusOnEditor = null
566568

567569
function checkEditorStyle () {
568570
var desireHeight = editorInstance.statusBar ? (ui.area.edit.height() - editorInstance.statusBar.outerHeight()) : ui.area.edit.height()
571+
if (editorInstance.toolBar) {
572+
desireHeight = desireHeight - editorInstance.toolBar.outerHeight()
573+
}
569574
// set editor height and min height based on scrollbar style and mode
570575
var scrollbarStyle = editor.getOption('scrollbarStyle')
571576
if (scrollbarStyle === 'overlay' || appState.currentMode === modeType.both) {
@@ -804,6 +809,10 @@ function changeMode (type) {
804809
editorInstance.addStatusBar()
805810
editorInstance.updateStatusBar()
806811
}
812+
// add and update tool bar
813+
if (!editorInstance.toolBar) {
814+
editorInstance.addToolBar()
815+
}
807816
// work around foldGutter might not init properly
808817
editor.setOption('foldGutter', false)
809818
editor.setOption('foldGutter', true)

public/js/lib/editor/index.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as utils from './utils'
22
import config from './config'
33
import statusBarTemplate from './statusbar.html'
4+
import toolBarTemplate from './toolbar.html'
45

56
/* config section */
67
const isMac = CodeMirror.keyMap.default === CodeMirror.keyMap.macDefault
@@ -136,6 +137,92 @@ export default class Editor {
136137
})
137138
}
138139

140+
addToolBar () {
141+
this.toolBar = $(toolBarTemplate)
142+
//console.log('PLACE', $('#toolbarPlace'))
143+
//$('#toolbarPlace').html(this.toolBar)
144+
this.toolbarPanel = this.editor.addPanel(this.toolBar[0], {
145+
position: 'top'
146+
})
147+
148+
var insertDemo = $('#insertDemo')
149+
var makeBold = $('#makeBold')
150+
var makeItalic = $('#makeItalic')
151+
var makeStrike = $('#makeStrike')
152+
var makeHeader = $('#makeHeader')
153+
var makeCode = $('#makeCode')
154+
var makeQuote = $('#makeQuote')
155+
var makeGenericList = $('#makeGenericList')
156+
var makeOrderedList = $('#makeOrderedList')
157+
var makeCheckList = $('#makeCheckList')
158+
var makeLink = $('#makeLink')
159+
var makeImage = $('#makeImage')
160+
var makeTable = $('#makeTable')
161+
var makeLine = $('#makeLine')
162+
var makeComment = $('#makeComment')
163+
164+
makeBold.click(() => {
165+
utils.wrapTextWith(this.editor, this.editor, '**')
166+
this.editor.focus()
167+
})
168+
169+
makeItalic.click(() => {
170+
utils.wrapTextWith(this.editor, this.editor, '*')
171+
this.editor.focus()
172+
})
173+
174+
makeStrike.click(() => {
175+
utils.wrapTextWith(this.editor, this.editor, '~~')
176+
this.editor.focus()
177+
})
178+
179+
makeHeader.click(() => {
180+
utils.insertHeader(this.editor)
181+
})
182+
183+
makeCode.click(() => {
184+
utils.wrapTextWith(this.editor, this.editor, '```')
185+
this.editor.focus()
186+
})
187+
188+
makeQuote.click(() => {
189+
utils.insertOnStartOfLines(this.editor, '> ')
190+
})
191+
192+
makeGenericList.click(() => {
193+
utils.insertOnStartOfLines(this.editor, '* ')
194+
})
195+
196+
makeOrderedList.click(() => {
197+
utils.insertOnStartOfLines(this.editor, '1. ')
198+
})
199+
200+
makeCheckList.click(() => {
201+
utils.insertOnStartOfLines(this.editor, '- [ ] ')
202+
})
203+
204+
makeLink.click(() => {
205+
utils.insertText(this.editor, '[](https://)', 1)
206+
})
207+
208+
makeImage.click(() => {
209+
utils.insertText(this.editor, '![](https://)', 4)
210+
})
211+
212+
makeTable.click(() => {
213+
utils.insertText(this.editor, '\n\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |\n')
214+
})
215+
216+
makeLine.click(() => {
217+
utils.insertText(this.editor, '\n----\n')
218+
})
219+
220+
makeComment.click(() => {
221+
utils.insertText(this.editor, '> []', 4)
222+
})
223+
224+
}
225+
139226
addStatusBar () {
140227
this.statusBar = $(statusBarTemplate)
141228
this.statusCursor = this.statusBar.find('.status-cursor > .status-line-column')

public/js/lib/editor/toolbar.html

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<div class="toolbar">
2+
<div class="btn-toolbar" role="toolbar" aria-label="Editor toolbar">
3+
<div class="btn-group" role="group">
4+
<a id="makeBold" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Bold">
5+
<i class="fa fa-bold fa-fw"></i>
6+
</a>
7+
<a id="makeItalic" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Italic">
8+
<i class="fa fa-italic fa-fw"></i>
9+
</a>
10+
<a id="makeStrike" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Strikethrough">
11+
<i class="fa fa-strikethrough fa-fw"></i>
12+
</a>
13+
<a id="makeHeader" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Heading">
14+
<i class="fa fa-h1 fa-fw">H</i>
15+
</a>
16+
<a id="makeCode" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Quote">
17+
<i class="fa fa-code fa-fw"></i>
18+
</a>
19+
<a id="makeQuote" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Quote">
20+
<i class="fa fa-quote-right fa-fw"></i>
21+
</a>
22+
<a id="makeGenericList" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="List">
23+
<i class="fa fa-list fa-fw"></i>
24+
</a>
25+
<a id="makeOrderedList" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Numbered List">
26+
<i class="fa fa-list-ol fa-fw"></i>
27+
</a>
28+
<a id="makeCheckList" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Check List">
29+
<i class="fa fa-check-square fa-fw"></i>
30+
</a>
31+
<a id="makeLink" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Link">
32+
<i class="fa fa-link fa-fw"></i>
33+
</a>
34+
<a id="makeImage" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Image">
35+
<i class="fa fa-image fa-fw"></i>
36+
</a>
37+
<a id="makeTable" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Table">
38+
<i class="fa fa-table fa-fw"></i>
39+
</a>
40+
<a id="makeLine" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Line">
41+
<i class="fa fa-minus fa-fw"></i>
42+
</a>
43+
<a id="makeComment" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Line">
44+
<i class="fa fa-comment fa-fw"></i>
45+
</a>
46+
</div>
47+
</div>
48+
</div>

public/js/lib/editor/utils.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,43 @@ export function wrapTextWith (editor, cm, symbol) {
4646
}
4747
}
4848
}
49+
50+
export function insertText (cm, text, cursorEnd = 0) {
51+
var cursor = cm.getCursor()
52+
cm.replaceSelection(text, cursor, cursor)
53+
cm.focus()
54+
cm.setCursor({line: cursor.line, ch: cursor.ch + cursorEnd})
55+
}
56+
57+
export function insertHeader (cm) {
58+
let cursor = cm.getCursor()
59+
let startOfLine = {line: cursor.line, ch: 0}
60+
let startOfLineText = cm.getRange(startOfLine, {line: cursor.line, ch: 1})
61+
// See if it is already a header
62+
if (startOfLineText === '#') {
63+
cm.replaceRange('#', startOfLine, startOfLine)
64+
} else {
65+
cm.replaceRange('# ', startOfLine, startOfLine)
66+
}
67+
cm.focus()
68+
}
69+
70+
export function insertOnStartOfLines (cm, symbol, cursorEnd) {
71+
let cursor = cm.getCursor()
72+
var ranges = cm.listSelections()
73+
74+
for (let i = 0; i < ranges.length; i++) {
75+
var range = ranges[i]
76+
if (!range.empty()) {
77+
const from = range.from()
78+
const to = range.to()
79+
for (let j = from.line; j <= to.line; ++j) {
80+
cm.replaceRange(symbol, {line: j, ch: 0}, {line: j, ch: 0})
81+
}
82+
} else {
83+
cm.replaceRange(symbol, {line: cursor.line, ch: 0}, {line: cursor.line, ch: 0})
84+
}
85+
}
86+
cm.setCursor({line: cursor.line, ch: (cursorEnd)? cursorEnd : cursor.ch})
87+
cm.focus()
88+
}

0 commit comments

Comments
 (0)