Skip to content

Commit 97d8d5e

Browse files
记事本编辑器增加添加表情、代码块、图片等功能
1 parent 968e533 commit 97d8d5e

File tree

7 files changed

+227
-11
lines changed

7 files changed

+227
-11
lines changed

app/assets/javascripts/emoji-modal.coffee

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,10 @@ window.EmojiModalView = Backbone.View.extend
8383
target = $(e.currentTarget)
8484
code = target.data('code')
8585
@saveFavoritEmoji(code)
86-
window._topicView.insertString(":#{code}: ")
86+
if window._topicView
87+
window._topicView.insertString(":#{code}: ")
88+
else if window._noteView
89+
window._noteView.insertString(":#{code}: ")
8790
return false
8891

8992
preview: (e) ->

app/assets/javascripts/notes.coffee

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,19 @@ window.NoteView = Backbone.View.extend
33
events:
44
"click .editor-toolbar .edit a": "toggleEditView"
55
"click .editor-toolbar .preview a": "togglePreviewView"
6+
"click #note-upload-image": "browseUpload"
7+
"click .insert-codes a": "appendCodesFromHint"
8+
"click .pickup-emoji": "pickupEmoji"
69

710
initialize: (opts) ->
811
@parentView = opts.parentView
12+
@initDropzone()
13+
@initContentImageZoom()
14+
@initCloseWarning()
15+
@initComponents()
916
$("<div id='preview' class='markdown' style='display:none;'></div>").insertAfter( $('#note_body') )
1017

18+
1119
toggleEditView: (e) ->
1220
$(e.target).parent().addClass('active')
1321
$('.preview a').parent().removeClass('active')
@@ -25,3 +33,191 @@ window.NoteView = Backbone.View.extend
2533
$('#preview').html(data)
2634
false
2735
false
36+
37+
initDropzone: ->
38+
self = @
39+
editor = $("textarea.note-editor")
40+
editor.wrap "<div class=\"note-editor-dropzone\"></div>"
41+
42+
editor_dropzone = $('.note-editor-dropzone')
43+
editor_dropzone.on 'paste', (event) =>
44+
self.handlePaste(event)
45+
46+
dropzone = editor_dropzone.dropzone(
47+
url: "/photos"
48+
dictDefaultMessage: ""
49+
clickable: true
50+
paramName: "file"
51+
maxFilesize: 20
52+
uploadMultiple: false
53+
headers:
54+
"X-CSRF-Token": $("meta[name=\"csrf-token\"]").attr("content")
55+
previewContainer: false
56+
processing: ->
57+
$(".div-dropzone-alert").alert "close"
58+
self.showUploading()
59+
dragover: ->
60+
editor.addClass "div-dropzone-focus"
61+
return
62+
dragleave: ->
63+
editor.removeClass "div-dropzone-focus"
64+
return
65+
drop: ->
66+
editor.removeClass "div-dropzone-focus"
67+
editor.focus()
68+
return
69+
success: (header, res) ->
70+
self.appendImageFromUpload([res.url])
71+
return
72+
error: (temp, msg) ->
73+
App.alert(msg)
74+
return
75+
totaluploadprogress: (num) ->
76+
return
77+
sending: ->
78+
return
79+
queuecomplete: ->
80+
self.restoreUploaderStatus()
81+
return
82+
)
83+
84+
initComponents : ->
85+
# 绑定文本框 tab 按键事件
86+
$("textarea.note-editor").unbind "keydown.tab"
87+
$("textarea.note-editor").bind "keydown.tab", "tab", (el) =>
88+
return @insertSpaces(el)
89+
90+
$("textarea.note-editor").autogrow()
91+
92+
uploadFile: (item, filename) ->
93+
self = @
94+
formData = new FormData()
95+
formData.append "file", item, filename
96+
$.ajax
97+
url: '/photos'
98+
type: "POST"
99+
data: formData
100+
dataType: "JSON"
101+
processData: false
102+
contentType: false
103+
beforeSend: ->
104+
self.showUploading()
105+
success: (e, status, res) ->
106+
self.appendImageFromUpload([res.responseJSON.url])
107+
self.restoreUploaderStatus()
108+
error: (res) ->
109+
App.alert("上传失败")
110+
self.restoreUploaderStatus()
111+
complete: ->
112+
self.restoreUploaderStatus()
113+
114+
handlePaste: (e) ->
115+
self = @
116+
pasteEvent = e.originalEvent
117+
if pasteEvent.clipboardData and pasteEvent.clipboardData.items
118+
image = self.isImage(pasteEvent)
119+
if image
120+
e.preventDefault()
121+
self.uploadFile image.getAsFile(), "image.png"
122+
123+
isImage: (data) ->
124+
i = 0
125+
while i < data.clipboardData.items.length
126+
item = data.clipboardData.items[i]
127+
if item.type.indexOf("image") isnt -1
128+
return item
129+
i++
130+
return false
131+
132+
browseUpload: (e) ->
133+
$(".note-editor").focus()
134+
$('.note-editor-dropzone').click()
135+
return false
136+
137+
showUploading: () ->
138+
$("#note-upload-image").hide()
139+
if $("#note-upload-image").parent().find("span.loading").length == 0
140+
$("#note-upload-image").before("<span class='loading'><i class='fa fa-circle-o-notch fa-spin'></i></span>")
141+
142+
restoreUploaderStatus: ->
143+
$("#note-upload-image").parent().find("span.loading").remove()
144+
$("#note-upload-image").show()
145+
146+
appendImageFromUpload : (srcs) ->
147+
src_merged = ""
148+
for src in srcs
149+
src_merged = "![](#{src})\n"
150+
@insertString(src_merged)
151+
return false
152+
153+
initContentImageZoom : () ->
154+
exceptClasses = ["emoji", "twemoji"]
155+
imgEls = $(".markdown img")
156+
for el in imgEls
157+
if exceptClasses.indexOf($(el).attr("class")) == -1
158+
$(el).wrap("<a href='#{$(el).attr("src")}' class='zoom-image' data-action='zoom'></a>")
159+
160+
# Bind click event
161+
if App.turbolinks || App.mobile
162+
$('a.zoom-image').attr("target","_blank")
163+
else
164+
$('a.zoom-image').fluidbox
165+
overlayColor: "#FFF"
166+
closeTrigger: [ {
167+
selector: 'window'
168+
event: 'scroll'
169+
} ]
170+
true
171+
172+
initCloseWarning: () ->
173+
text = $("textarea.closewarning")
174+
return false if text.length == 0
175+
msg = "离开本页面将丢失未保存页面!" if !msg
176+
$("input[type=submit]").click ->
177+
$(window).unbind("beforeunload")
178+
text.change ->
179+
if text.val().length > 0
180+
$(window).bind "beforeunload", (e) ->
181+
if $.browser.msie
182+
e.returnValue = msg
183+
else
184+
return msg
185+
else
186+
$(window).unbind("beforeunload")
187+
188+
# 往话题编辑器里面的光标前插入两个空白字符
189+
insertSpaces : (e) ->
190+
@insertString(' ')
191+
return false
192+
193+
# 往话题编辑器里面插入代码模版
194+
appendCodesFromHint : (e) ->
195+
link = $(e.currentTarget)
196+
language = link.data("lang")
197+
txtBox = $(".note-editor")
198+
caret_pos = txtBox.caret('pos')
199+
prefix_break = ""
200+
if txtBox.val().length > 0
201+
prefix_break = "\n"
202+
src_merged = "#{prefix_break }```#{language}\n\n```\n"
203+
source = txtBox.val()
204+
before_text = source.slice(0, caret_pos)
205+
txtBox.val(before_text + src_merged + source.slice(caret_pos+1, source.count))
206+
txtBox.caret('pos',caret_pos + src_merged.length - 5)
207+
txtBox.focus()
208+
txtBox.trigger('click')
209+
return false
210+
211+
insertString: (str) ->
212+
$target = $(".note-editor")
213+
start = $target[0].selectionStart
214+
end = $target[0].selectionEnd
215+
$target.val($target.val().substring(0, start) + str + $target.val().substring(end));
216+
$target[0].selectionStart = $target[0].selectionEnd = start + str.length
217+
$target.focus()
218+
219+
pickupEmoji: () ->
220+
if !window._emojiModal
221+
window._emojiModal = new EmojiModalView()
222+
window._emojiModal.show()
223+
false
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<div class="editor-toolbar">
2+
<div class="opts pull-right">
3+
<a href="#" class="pickup-emoji"><i class="fa fa-smile-o"></i></a>
4+
<span class="dropdown dropdown-small" id="editor-toolbar-insert-code">
5+
<a href="#editor-toolbar-insert-code" data-toggle="dropdown" title="<%= t("notes.insert_codes") %>" href="#editor-toolbar-insert-code"><i class="fa fa-code"></i></a>
6+
<ul class="dropdown-menu insert-codes" role="menu">
7+
<%= insert_code_menu_items_tag %>
8+
</ul>
9+
</span>
10+
<%= link_to(icon_tag("image"), "#", id: "note-upload-image", rel: "twipsy", title: t("notes.add_image") )%>
11+
</div>
12+
<ul class="nav nav-pills" style="clear:none;">
13+
<li class="edit active"><%= link_to(t("common.editor_toolbar_edit"), "#") %></li>
14+
<li class="preview"><%= link_to(t("common.editor_toolbar_preview"), "#") %></li>
15+
</ul>
16+
</div>

app/views/notes/_form.html.erb

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
1-
<%= simple_form_for(@note, html: { class: "" }) do |f| %>
1+
<%= simple_form_for @note, html: { class: "form" } do |f| %>
22
<%= render "shared/error_messages", target: @note %>
33

44
<div class="form-group">
5-
<div class="editor-toolbar">
6-
<ul class="nav nav-pills">
7-
<li class="edit active"><%= link_to(t("common.editor_toolbar_edit"), "#") %></li>
8-
<li class="preview"><%= link_to(t("common.editor_toolbar_preview"), "#") %></li>
9-
</ul>
10-
</div>
5+
<%= render "editor_toolbar" %>
116

12-
<%= f.text_area :body, rows: 20, class: 'form-control topic-editor' %>
7+
<%= f.text_area :body, rows: 20, class: 'form-control note-editor' %>
138

149
<p class="help-block">
1510
<%= t("notes.please_use") %> <a href="<%= markdown_path %>" target="_blank">Markdown</a> <%= t("notes.document_format_to_write") %>

config/locales/nodes.en.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
"en":
22
nodes:
3-
hot_node: "Popular Node"
3+
hot_node: "Popular Node"
4+
add_image: "Upload image"
5+
insert_codes: "Insert Codes"

config/locales/nodes.zh-CN.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
"zh-CN":
22
nodes:
3-
hot_node: "热门节点"
3+
hot_node: "热门节点"
4+
add_image: "上传图片"
5+
insert_codes: "插入代码"

config/locales/nodes.zh-TW.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
"zh-TW":
22
nodes:
33
hot_node: "熱門節點"
4+
add_image: "上傳圖片"
5+
insert_codes: "插入代碼"

0 commit comments

Comments
 (0)