dante-editor-seo 0.0.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +40 -0
- data/.ruby-version +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +23 -0
- data/Gemfile.lock +140 -0
- data/Procfile +1 -0
- data/README.md +187 -0
- data/ROADMAP.md +10 -0
- data/TODO.md +30 -0
- data/app/assets/fonts/dante/dante.eot +0 -0
- data/app/assets/fonts/dante/dante.svg +14 -0
- data/app/assets/fonts/dante/dante.ttf +0 -0
- data/app/assets/fonts/dante/dante.woff +0 -0
- data/app/assets/fonts/dante/fontello.eot +0 -0
- data/app/assets/fonts/dante/fontello.svg +36 -0
- data/app/assets/fonts/dante/fontello.ttf +0 -0
- data/app/assets/fonts/dante/fontello.woff +0 -0
- data/app/assets/images/dante/media-loading-placeholder.png +0 -0
- data/app/assets/javascripts/dante/dante.js.coffee.erb +10 -0
- data/app/assets/javascripts/dante/editor.js.coffee +1250 -0
- data/app/assets/javascripts/dante/menu.js.coffee +216 -0
- data/app/assets/javascripts/dante/popover.js.coffee +75 -0
- data/app/assets/javascripts/dante/tooltip.js.coffee +82 -0
- data/app/assets/javascripts/dante/tooltip_widget.js.coffee +10 -0
- data/app/assets/javascripts/dante/tooltip_widgets/embed.js.coffee +60 -0
- data/app/assets/javascripts/dante/tooltip_widgets/extract.js.coffee +64 -0
- data/app/assets/javascripts/dante/tooltip_widgets/uploader.js.coffee +248 -0
- data/app/assets/javascripts/dante/utils.js.coffee +235 -0
- data/app/assets/javascripts/dante/view.js.coffee +101 -0
- data/app/assets/javascripts/dante.js +12 -0
- data/app/assets/stylesheets/dante/_animations.scss +54 -0
- data/app/assets/stylesheets/dante/_caption.scss +52 -0
- data/app/assets/stylesheets/dante/_debug.scss +11 -0
- data/app/assets/stylesheets/dante/_fonts.scss +17 -0
- data/app/assets/stylesheets/dante/_graf.scss +238 -0
- data/app/assets/stylesheets/dante/_icons.scss +57 -0
- data/app/assets/stylesheets/dante/_media.scss +39 -0
- data/app/assets/stylesheets/dante/_menu.scss +153 -0
- data/app/assets/stylesheets/dante/_needsorder.scss +209 -0
- data/app/assets/stylesheets/dante/_popover.scss +134 -0
- data/app/assets/stylesheets/dante/_post.scss +69 -0
- data/app/assets/stylesheets/dante/_scaffold.scss +20 -0
- data/app/assets/stylesheets/dante/_tooltip.scss +131 -0
- data/app/assets/stylesheets/dante/_utilities.scss +55 -0
- data/app/assets/stylesheets/dante/_variables.scss +46 -0
- data/app/assets/stylesheets/dante.scss +18 -0
- data/bower.json +44 -0
- data/config.rb +86 -0
- data/config.ru +42 -0
- data/dante-editor.gemspec +19 -0
- data/dist/css/dante-editor.css +1116 -0
- data/dist/fonts/dante/dante.eot +0 -0
- data/dist/fonts/dante/dante.svg +14 -0
- data/dist/fonts/dante/dante.ttf +0 -0
- data/dist/fonts/dante/dante.woff +0 -0
- data/dist/fonts/dante/fontello.eot +0 -0
- data/dist/fonts/dante/fontello.svg +36 -0
- data/dist/fonts/dante/fontello.ttf +0 -0
- data/dist/fonts/dante/fontello.woff +0 -0
- data/dist/images/dante/media-loading-placeholder.png +0 -0
- data/dist/js/dante-editor.js +2878 -0
- data/lib/dante-editor/rails.rb +4 -0
- data/lib/dante-editor/version.rb +5 -0
- data/lib/dante-editor.rb +5 -0
- data/license.md +22 -0
- data/rakefile +2 -0
- data/source/assets/images/dante-editor-logo.png +0 -0
- data/source/assets/images/github-logo.png +0 -0
- data/source/assets/javascripts/all.js +3 -0
- data/source/assets/javascripts/dante-editor.js +1 -0
- data/source/assets/javascripts/deps.js +4 -0
- data/source/assets/javascripts/examples/custom_toolbar.js.coffee +30 -0
- data/source/assets/javascripts/spec.js +2 -0
- data/source/assets/javascripts/specs/cleaner.js.coffee +8 -0
- data/source/assets/javascripts/specs/dante_view.js.coffee +74 -0
- data/source/assets/javascripts/specs/editor.js.coffee +78 -0
- data/source/assets/stylesheets/_layout.scss +51 -0
- data/source/assets/stylesheets/_scaffold.scss +8 -0
- data/source/assets/stylesheets/_tooltips.scss +216 -0
- data/source/assets/stylesheets/all.css.scss +5 -0
- data/source/assets/stylesheets/dante-editor.css.scss +1 -0
- data/source/assets/stylesheets/normalize.css +375 -0
- data/source/custom_toolbar.erb +29 -0
- data/source/embeds.html.erb +27 -0
- data/source/icons/dante.json +143 -0
- data/source/icons/embed.svg +13 -0
- data/source/icons/image.svg +13 -0
- data/source/icons/plus.svg +13 -0
- data/source/icons/video.svg +13 -0
- data/source/index.html.erb +18 -0
- data/source/layouts/layout.erb +26 -0
- data/source/layouts/spec.html.erb +22 -0
- data/source/lists.html.erb +18 -0
- data/source/partials/_content.erb +6 -0
- data/source/partials/_example_1.erb +45 -0
- data/source/partials/_example_2.erb +32 -0
- data/source/partials/_example_3.erb +4 -0
- data/source/partials/_lists.erb +13 -0
- data/source/partials/_readme.markdown +24 -0
- data/source/partials/test/_example_1.erb +39 -0
- data/source/tests/dante_view.html.erb +11 -0
- data/source/tests/index.html.erb +39 -0
- data/tmp/.gitkeep +0 -0
- metadata +151 -0
@@ -0,0 +1,1250 @@
|
|
1
|
+
|
2
|
+
utils = Dante.utils
|
3
|
+
|
4
|
+
class Dante.Editor extends Dante.View
|
5
|
+
|
6
|
+
#Named constants for javascript key codes
|
7
|
+
BACKSPACE = 8
|
8
|
+
TAB = 9
|
9
|
+
ENTER = 13
|
10
|
+
SPACEBAR = 32
|
11
|
+
LEFTARROW = 37
|
12
|
+
UPARROW = 38
|
13
|
+
RIGHTARROW = 39
|
14
|
+
DOWNARROW = 40
|
15
|
+
|
16
|
+
events:
|
17
|
+
"mouseup" : "handleMouseUp"
|
18
|
+
"keydown" : "handleKeyDown"
|
19
|
+
"keyup" : "handleKeyUp"
|
20
|
+
"paste" : "handlePaste"
|
21
|
+
"dblclick" : "handleDblclick"
|
22
|
+
"dragstart": "handleDrag"
|
23
|
+
"drop" : "handleDrag"
|
24
|
+
"click .graf--figure .aspectRatioPlaceholder" : "handleGrafFigureSelectImg"
|
25
|
+
"click .graf--figure figcaption" : "handleGrafFigureSelectCaption"
|
26
|
+
|
27
|
+
"mouseover .graf--figure.graf--iframe" : "handleGrafFigureSelectIframe"
|
28
|
+
"mouseleave .graf--figure.graf--iframe" : "handleGrafFigureUnSelectIframe"
|
29
|
+
"keyup .graf--figure figcaption" : "handleGrafCaptionTyping"
|
30
|
+
|
31
|
+
"mouseover .markup--anchor" : "displayPopOver"
|
32
|
+
"mouseout .markup--anchor" : "hidePopOver"
|
33
|
+
|
34
|
+
initialize: (opts = {})=>
|
35
|
+
@editor_options = opts
|
36
|
+
#globals for selected text and node
|
37
|
+
@initial_html = $(@el).html()
|
38
|
+
@current_range = null
|
39
|
+
@current_node = null
|
40
|
+
@el = opts.el || "#editor"
|
41
|
+
@upload_url = opts.upload_url || "/uploads.json"
|
42
|
+
@upload_callback = opts.upload_callback
|
43
|
+
@upload_params = opts.upload_params || null
|
44
|
+
@oembed_url = opts.oembed_url || "http://api.embed.ly/1/oembed?url="
|
45
|
+
@extract_url = opts.extract_url || "http://api.embed.ly/1/extract?key=86c28a410a104c8bb58848733c82f840&url="
|
46
|
+
@default_loading_placeholder = opts.default_loading_placeholder || Dante.defaults.image_placeholder
|
47
|
+
@store_url = opts.store_url
|
48
|
+
@store_method = opts.store_method || "POST"
|
49
|
+
@store_params = opts.store_params || null
|
50
|
+
@spell_check = opts.spellcheck || false
|
51
|
+
@disable_title = opts.disable_title || false
|
52
|
+
@store_interval = opts.store_interval || 15000
|
53
|
+
@paste_element_id = "#dante-paste-div"
|
54
|
+
@tooltip_class = opts.tooltip_class || Dante.Editor.Tooltip
|
55
|
+
|
56
|
+
opts.base_widgets ||= ["uploader", "embed", "embed_extract"]
|
57
|
+
|
58
|
+
@widgets = []
|
59
|
+
|
60
|
+
window.debugMode = opts.debug || false
|
61
|
+
|
62
|
+
$(@el).addClass("debug") if window.debugMode
|
63
|
+
|
64
|
+
if (localStorage.getItem('contenteditable'))
|
65
|
+
$(@el).html localStorage.getItem('contenteditable')
|
66
|
+
|
67
|
+
@store()
|
68
|
+
|
69
|
+
titleplaceholder = opts.title_placeholder || 'Title'
|
70
|
+
@title_placeholder = "<span class='defaultValue defaultValue--root'>#{titleplaceholder}</span><br>"
|
71
|
+
title = opts.title || ''
|
72
|
+
@title = title
|
73
|
+
body = opts.body || ''
|
74
|
+
@body = body
|
75
|
+
bodyplaceholder = opts.body_placeholder || 'Tell your story…'
|
76
|
+
@body_placeholder = "<span class='defaultValue defaultValue--root'>#{bodyplaceholder}</span><br>"
|
77
|
+
embedplaceholder = opts.embed_placeholder || 'Paste a YouTube, Vine, Vimeo, or other video link, and press Enter'
|
78
|
+
@embed_placeholder = "<span class='defaultValue defaultValue--root'>#{embedplaceholder}</span><br>"
|
79
|
+
extractplaceholder = opts.extract_placeholder|| "Paste a link to embed content from another site (e.g. Twitter) and press Enter"
|
80
|
+
@extract_placeholder= "<span class='defaultValue defaultValue--root'>#{extractplaceholder}</span><br>"
|
81
|
+
|
82
|
+
@initializeWidgets(opts)
|
83
|
+
|
84
|
+
|
85
|
+
initializeWidgets: (opts)->
|
86
|
+
#TODO: this could be a hash to access widgets without var
|
87
|
+
#Base widgets
|
88
|
+
base_widgets = opts.base_widgets
|
89
|
+
self = @
|
90
|
+
|
91
|
+
if base_widgets.indexOf("uploader") >= 0
|
92
|
+
@uploader_widget = new Dante.View.TooltipWidget.Uploader(current_editor: @)
|
93
|
+
@widgets.push @uploader_widget
|
94
|
+
|
95
|
+
if base_widgets.indexOf("embed") >= 0
|
96
|
+
@embed_widget = new Dante.View.TooltipWidget.Embed(current_editor: @)
|
97
|
+
@widgets.push @embed_widget
|
98
|
+
|
99
|
+
if base_widgets.indexOf("embed_extract") >= 0
|
100
|
+
@embed_extract_widget = new Dante.View.TooltipWidget.EmbedExtract(current_editor: @)
|
101
|
+
@widgets.push @embed_extract_widget
|
102
|
+
|
103
|
+
#add extra widgets
|
104
|
+
if opts.extra_tooltip_widgets
|
105
|
+
_.each opts.extra_tooltip_widgets, (w)=>
|
106
|
+
if !w.current_editor
|
107
|
+
w.current_editor = self
|
108
|
+
@widgets.push w
|
109
|
+
|
110
|
+
store: ()->
|
111
|
+
#localStorage.setItem("contenteditable", $(@el).html() )
|
112
|
+
return unless @store_url
|
113
|
+
setTimeout ()=>
|
114
|
+
@checkforStore()
|
115
|
+
, @store_interval
|
116
|
+
|
117
|
+
checkforStore: ()->
|
118
|
+
if @content is @getContent()
|
119
|
+
utils.log "content not changed skip store"
|
120
|
+
@store()
|
121
|
+
else
|
122
|
+
utils.log "content changed! update"
|
123
|
+
@content = @getContent()
|
124
|
+
$.ajax
|
125
|
+
url: @store_url
|
126
|
+
method: @store_method
|
127
|
+
data:
|
128
|
+
body: @getContent()
|
129
|
+
store_params: @store_params
|
130
|
+
success: (res)->
|
131
|
+
utils.log "store!"
|
132
|
+
utils.log res
|
133
|
+
complete: (jxhr) =>
|
134
|
+
@store()
|
135
|
+
|
136
|
+
getContent: ()->
|
137
|
+
$(@el).find(".section-inner").html()
|
138
|
+
|
139
|
+
renderBody: ()->
|
140
|
+
"<p class='graf graf--p body'>#{if @body.length > 0 then @body else @body_placeholder}<p>"
|
141
|
+
|
142
|
+
renderTitle: ()->
|
143
|
+
"<h3 class='graf graf--h3'>#{if @title.length > 0 then @title else @title_placeholder}</h3>"
|
144
|
+
|
145
|
+
template: ()=>
|
146
|
+
"<section class='section--first section--last'>
|
147
|
+
|
148
|
+
<div class='section-divider layoutSingleColumn'>
|
149
|
+
<hr class='section-divider'>
|
150
|
+
</div>
|
151
|
+
|
152
|
+
<div class='section-content'>
|
153
|
+
<div class='section-inner layoutSingleColumn'>
|
154
|
+
#{if @disable_title then '' else @renderTitle()}
|
155
|
+
#{@renderBody()}
|
156
|
+
</div>
|
157
|
+
</div>
|
158
|
+
|
159
|
+
</section>"
|
160
|
+
|
161
|
+
baseParagraphTmpl: ()->
|
162
|
+
"<p class='graf--p' name='#{utils.generateUniqueName()}'><br></p>"
|
163
|
+
|
164
|
+
appendMenus: ()=>
|
165
|
+
$("<div id='dante-menu' class='dante-menu'></div>").insertAfter(@el)
|
166
|
+
$("<div class='inlineTooltip'></div>").insertAfter(@el)
|
167
|
+
@editor_menu = new Dante.Editor.Menu(editor: @)
|
168
|
+
@tooltip_view = new @tooltip_class(editor: @ , widgets: @widgets)
|
169
|
+
@pop_over = new Dante.Editor.PopOver(editor: @)
|
170
|
+
@pop_over.render().hide()
|
171
|
+
@tooltip_view.render().hide()
|
172
|
+
|
173
|
+
appendInitialContent: ()=>
|
174
|
+
$(@el).find(".section-inner").html(@initial_html)
|
175
|
+
$(@el).attr("spellcheck", @spell_check)
|
176
|
+
|
177
|
+
start: ()=>
|
178
|
+
@render()
|
179
|
+
$(@el).attr("contenteditable", "true")
|
180
|
+
$(@el).addClass("postField postField--body editable smart-media-plugin")
|
181
|
+
$(@el).wrap("<article class='postArticle'><div class='postContent'><div class='notesSource'></div></div></article>")
|
182
|
+
@appendMenus()
|
183
|
+
@appendInitialContent() unless _.isEmpty @initial_html.trim()
|
184
|
+
@parseInitialMess()
|
185
|
+
|
186
|
+
restart: ()=>
|
187
|
+
@render()
|
188
|
+
|
189
|
+
render: ()=>
|
190
|
+
@template()
|
191
|
+
$(@el).html @template()
|
192
|
+
|
193
|
+
getSelectedText: () ->
|
194
|
+
text = ""
|
195
|
+
if typeof window.getSelection != "undefined"
|
196
|
+
text = window.getSelection().toString()
|
197
|
+
else if typeof document.selection != "undefined" && document.selection.type == "Text"
|
198
|
+
text = document.selection.createRange().text
|
199
|
+
text
|
200
|
+
|
201
|
+
selection: ()=>
|
202
|
+
selection
|
203
|
+
if (window.getSelection)
|
204
|
+
selection = window.getSelection()
|
205
|
+
else if (document.selection && document.selection.type != "Control")
|
206
|
+
selection = document.selection
|
207
|
+
|
208
|
+
getRange: () ->
|
209
|
+
editor = $(@el)[0]
|
210
|
+
range = selection && selection.rangeCount && selection.getRangeAt(0)
|
211
|
+
range = document.createRange() if (!range)
|
212
|
+
if !editor.contains(range.commonAncestorContainer)
|
213
|
+
range.selectNodeContents(editor)
|
214
|
+
range.collapse(false)
|
215
|
+
range
|
216
|
+
|
217
|
+
setRange: (range)->
|
218
|
+
range = range || this.current_range
|
219
|
+
if !range
|
220
|
+
range = this.getRange()
|
221
|
+
range.collapse(false) # set to end
|
222
|
+
|
223
|
+
@selection().removeAllRanges()
|
224
|
+
@selection().addRange(range)
|
225
|
+
@
|
226
|
+
|
227
|
+
getCharacterPrecedingCaret: ->
|
228
|
+
precedingChar = ""
|
229
|
+
sel = undefined
|
230
|
+
range = undefined
|
231
|
+
precedingRange = undefined
|
232
|
+
if window.getSelection
|
233
|
+
sel = window.getSelection()
|
234
|
+
if sel.rangeCount > 0
|
235
|
+
range = sel.getRangeAt(0).cloneRange()
|
236
|
+
range.collapse true
|
237
|
+
range.setStart @getNode(), 0
|
238
|
+
precedingChar = range.toString().slice(0)
|
239
|
+
else if (sel = document.selection) and sel.type isnt "Control"
|
240
|
+
range = sel.createRange()
|
241
|
+
precedingRange = range.duplicate()
|
242
|
+
precedingRange.moveToElementText containerEl
|
243
|
+
precedingRange.setEndPoint "EndToStart", range
|
244
|
+
precedingChar = precedingRange.text.slice(0)
|
245
|
+
precedingChar
|
246
|
+
|
247
|
+
isLastChar: ()->
|
248
|
+
$(@getNode()).text().trim().length is @getCharacterPrecedingCaret().trim().length
|
249
|
+
|
250
|
+
isFirstChar: ()->
|
251
|
+
@getCharacterPrecedingCaret().trim().length is 0
|
252
|
+
|
253
|
+
isSelectingAll: (element)->
|
254
|
+
a = @getSelectedText().killWhiteSpace().length
|
255
|
+
b = $(element).text().killWhiteSpace().length
|
256
|
+
a is b
|
257
|
+
|
258
|
+
#set focus and caret position on element
|
259
|
+
setRangeAt: (element, int=0)->
|
260
|
+
range = document.createRange()
|
261
|
+
sel = window.getSelection()
|
262
|
+
#node = element.firstChild;
|
263
|
+
range.setStart(element, int); #DANGER this is supported by IE 9
|
264
|
+
#range.setStartAfter(element)
|
265
|
+
#range.setEnd(element, int);
|
266
|
+
range.collapse(true)
|
267
|
+
sel.removeAllRanges()
|
268
|
+
sel.addRange(range)
|
269
|
+
element.focus()
|
270
|
+
|
271
|
+
#set focus and caret position on element
|
272
|
+
setRangeAtText: (element, int=0)->
|
273
|
+
range = document.createRange()
|
274
|
+
sel = window.getSelection()
|
275
|
+
node = element.firstChild;
|
276
|
+
range.setStart(node, 0); #DANGER this is supported by IE 9
|
277
|
+
range.setEnd(node, 0);
|
278
|
+
range.collapse(true)
|
279
|
+
sel.removeAllRanges()
|
280
|
+
sel.addRange(range)
|
281
|
+
element.focus()
|
282
|
+
|
283
|
+
focus: (focusStart) ->
|
284
|
+
@.setRange() if (!focusStart)
|
285
|
+
$(@el).focus()
|
286
|
+
@
|
287
|
+
|
288
|
+
#NOT USED
|
289
|
+
focusNode: (node, range)->
|
290
|
+
range.setStartAfter(node)
|
291
|
+
range.setEndBefore(node)
|
292
|
+
range.collapse(false)
|
293
|
+
@.setRange(range)
|
294
|
+
|
295
|
+
#get the element that wraps Caret position while is inside section
|
296
|
+
getNode: ()->
|
297
|
+
node = undefined
|
298
|
+
root = $(@el).find(".section-inner")[0]
|
299
|
+
return if @selection().rangeCount < 1
|
300
|
+
range = @selection().getRangeAt(0)
|
301
|
+
node = range.commonAncestorContainer
|
302
|
+
return null if not node or node is root
|
303
|
+
|
304
|
+
#node = node.parentNode while node and (node.nodeType isnt 1) and (node.parentNode isnt root)
|
305
|
+
#node = node.parentNode while node and (node.parentNode isnt root)
|
306
|
+
|
307
|
+
node = node.parentNode while node and (node.nodeType isnt 1 or not $(node).hasClass("graf")) and (node.parentNode isnt root)
|
308
|
+
if not $(node).hasClass("graf--li")
|
309
|
+
node = node.parentNode while node and (node.parentNode isnt root)
|
310
|
+
|
311
|
+
(if root && root.contains(node) then node else null)
|
312
|
+
|
313
|
+
displayMenu: (sel)->
|
314
|
+
setTimeout ()=>
|
315
|
+
@editor_menu.render()
|
316
|
+
pos = utils.getSelectionDimensions()
|
317
|
+
@relocateMenu(pos)
|
318
|
+
@editor_menu.show()
|
319
|
+
, 10
|
320
|
+
|
321
|
+
handleDrag: ()->
|
322
|
+
return false
|
323
|
+
|
324
|
+
handleGrafCaptionTyping: (ev)->
|
325
|
+
if _.isEmpty(utils.getNode().textContent.trim())
|
326
|
+
$(@getNode()).addClass("is-defaultValue")
|
327
|
+
else
|
328
|
+
$(@getNode()).removeClass("is-defaultValue")
|
329
|
+
|
330
|
+
#get text of selected and displays menu
|
331
|
+
handleTextSelection: (anchor_node)->
|
332
|
+
@editor_menu.hide()
|
333
|
+
text = @getSelectedText()
|
334
|
+
if !$(anchor_node).is(".graf--mixtapeEmbed, .graf--figure") && !_.isEmpty text.trim()
|
335
|
+
@current_node = anchor_node
|
336
|
+
@.displayMenu()
|
337
|
+
|
338
|
+
relocateMenu: (position)->
|
339
|
+
height = @editor_menu.$el.outerHeight()
|
340
|
+
padd = @editor_menu.$el.width() / 2
|
341
|
+
top = position.top + $(window).scrollTop() - height
|
342
|
+
left = position.left + (position.width / 2) - padd
|
343
|
+
@editor_menu.$el.offset({ left: left , top: top })
|
344
|
+
|
345
|
+
hidePlaceholder: (element)->
|
346
|
+
$(element).find("span.defaultValue").remove().html("<br>")
|
347
|
+
|
348
|
+
displayEmptyPlaceholder: (element)->
|
349
|
+
$(".graf--first").html(@title_placeholder)
|
350
|
+
$(".graf--last").html(@body_placeholder)
|
351
|
+
|
352
|
+
displayPopOver: (ev)->
|
353
|
+
@pop_over.displayAt(ev)
|
354
|
+
|
355
|
+
hidePopOver: (ev)->
|
356
|
+
@pop_over.hide(ev)
|
357
|
+
|
358
|
+
handleGrafFigureSelectImg: (ev)->
|
359
|
+
utils.log "FIGURE SELECT"
|
360
|
+
element = ev.currentTarget
|
361
|
+
@markAsSelected( element )
|
362
|
+
$(element).parent(".graf--figure").addClass("is-selected is-mediaFocused")
|
363
|
+
@selection().removeAllRanges()
|
364
|
+
|
365
|
+
handleGrafFigureSelectIframe: (ev)->
|
366
|
+
utils.log "FIGURE IFRAME SELECT"
|
367
|
+
element = ev.currentTarget
|
368
|
+
@iframeSelected = element
|
369
|
+
@markAsSelected( element )
|
370
|
+
$(element).addClass("is-selected is-mediaFocused")
|
371
|
+
@selection().removeAllRanges()
|
372
|
+
|
373
|
+
handleGrafFigureUnSelectIframe: (ev)->
|
374
|
+
utils.log "FIGURE IFRAME UNSELECT"
|
375
|
+
element = ev.currentTarget
|
376
|
+
@iframeSelected = null
|
377
|
+
$(element).removeClass("is-selected is-mediaFocused")
|
378
|
+
|
379
|
+
handleGrafFigureSelectCaption: (ev)->
|
380
|
+
utils.log "FIGCAPTION"
|
381
|
+
element = ev.currentTarget
|
382
|
+
$(element).parent(".graf--figure").removeClass("is-mediaFocused")
|
383
|
+
|
384
|
+
handleMouseUp: (ev)=>
|
385
|
+
utils.log "MOUSE UP"
|
386
|
+
anchor_node = @getNode()
|
387
|
+
|
388
|
+
return if _.isNull(anchor_node)
|
389
|
+
|
390
|
+
@prev_current_node = anchor_node
|
391
|
+
|
392
|
+
@handleTextSelection(anchor_node)
|
393
|
+
@hidePlaceholder(anchor_node)
|
394
|
+
@markAsSelected( anchor_node )
|
395
|
+
@displayTooltipAt( anchor_node )
|
396
|
+
|
397
|
+
scrollTo: (node)->
|
398
|
+
return if utils.isElementInViewport($(node))
|
399
|
+
|
400
|
+
top = node.offset().top
|
401
|
+
#scroll to element top
|
402
|
+
$('html, body').animate
|
403
|
+
scrollTop: top
|
404
|
+
, 20
|
405
|
+
|
406
|
+
#handle arrow direction from keyUp.
|
407
|
+
handleArrow: (ev)=>
|
408
|
+
current_node = $(@getNode())
|
409
|
+
if current_node.length > 0
|
410
|
+
@markAsSelected( current_node )
|
411
|
+
@displayTooltipAt( current_node )
|
412
|
+
|
413
|
+
#handle arrow direction from keyDown.
|
414
|
+
handleArrowForKeyDown: (ev)=>
|
415
|
+
caret_node = @getNode()
|
416
|
+
current_node = $(caret_node)
|
417
|
+
utils.log(ev)
|
418
|
+
ev_type = ev.originalEvent.key || ev.originalEvent.keyIdentifier
|
419
|
+
|
420
|
+
utils.log("ENTER ARROW for key #{ev_type}")
|
421
|
+
|
422
|
+
#handle keys for image figure
|
423
|
+
switch ev_type
|
424
|
+
|
425
|
+
when "Down"
|
426
|
+
#when graff-image selected but none selection is found
|
427
|
+
if _.isUndefined(current_node) or !current_node.exists()
|
428
|
+
if $(".is-selected").exists()
|
429
|
+
current_node = $(".is-selected")
|
430
|
+
|
431
|
+
next_node = current_node.next()
|
432
|
+
|
433
|
+
utils.log "NEXT NODE IS #{next_node.attr('class')}"
|
434
|
+
utils.log "CURRENT NODE IS #{current_node.attr('class')}"
|
435
|
+
|
436
|
+
return unless $(current_node).hasClass("graf")
|
437
|
+
return unless current_node.hasClass("graf--figure") or $(current_node).editableCaretOnLastLine()
|
438
|
+
|
439
|
+
utils.log "ENTER ARROW PASSED RETURNS"
|
440
|
+
|
441
|
+
#if next element is embed select & focus it
|
442
|
+
if next_node.hasClass("graf--figure") && caret_node
|
443
|
+
n = next_node.find(".imageCaption")
|
444
|
+
@scrollTo(n)
|
445
|
+
utils.log "1 down"
|
446
|
+
utils.log n[0]
|
447
|
+
@skip_keyup = true
|
448
|
+
@selection().removeAllRanges()
|
449
|
+
@markAsSelected(next_node)
|
450
|
+
next_node.addClass("is-mediaFocused is-selected")
|
451
|
+
return false
|
452
|
+
#if current node is embed
|
453
|
+
else if next_node.hasClass("graf--mixtapeEmbed")
|
454
|
+
n = current_node.next(".graf--mixtapeEmbed")
|
455
|
+
num = n[0].childNodes.length
|
456
|
+
@setRangeAt n[0], num
|
457
|
+
@scrollTo(n)
|
458
|
+
utils.log "2 down"
|
459
|
+
return false
|
460
|
+
|
461
|
+
if current_node.hasClass("graf--figure") && next_node.hasClass("graf")
|
462
|
+
@scrollTo(next_node)
|
463
|
+
utils.log "3 down, from figure to next graf"
|
464
|
+
#@skip_keyup = true
|
465
|
+
@markAsSelected(next_node)
|
466
|
+
@setRangeAt next_node[0]
|
467
|
+
return false
|
468
|
+
|
469
|
+
when "Up"
|
470
|
+
prev_node = current_node.prev()
|
471
|
+
utils.log "PREV NODE IS #{prev_node.attr('class')}"
|
472
|
+
utils.log "CURRENT NODE IS up #{current_node.attr('class')}"
|
473
|
+
|
474
|
+
return unless $(current_node).hasClass("graf")
|
475
|
+
return unless $(current_node).editableCaretOnFirstLine()
|
476
|
+
|
477
|
+
utils.log "ENTER ARROW PASSED RETURNS"
|
478
|
+
|
479
|
+
if prev_node.hasClass("graf--figure")
|
480
|
+
utils.log "1 up"
|
481
|
+
n = prev_node.find(".imageCaption")
|
482
|
+
@scrollTo(n)
|
483
|
+
@skip_keyup = true
|
484
|
+
@selection().removeAllRanges()
|
485
|
+
@markAsSelected(prev_node)
|
486
|
+
prev_node.addClass("is-mediaFocused")
|
487
|
+
return false
|
488
|
+
|
489
|
+
else if prev_node.hasClass("graf--mixtapeEmbed")
|
490
|
+
n = current_node.prev(".graf--mixtapeEmbed")
|
491
|
+
num = n[0].childNodes.length
|
492
|
+
@setRangeAt n[0], num
|
493
|
+
@scrollTo(n)
|
494
|
+
utils.log "2 up"
|
495
|
+
return false
|
496
|
+
|
497
|
+
if current_node.hasClass("graf--figure") && prev_node.hasClass("graf")
|
498
|
+
@setRangeAt prev_node[0]
|
499
|
+
@scrollTo(prev_node)
|
500
|
+
utils.log "3 up"
|
501
|
+
return false
|
502
|
+
|
503
|
+
else if prev_node.hasClass("graf")
|
504
|
+
n = current_node.prev(".graf")
|
505
|
+
num = n[0].childNodes.length
|
506
|
+
@scrollTo(n)
|
507
|
+
utils.log "4 up"
|
508
|
+
@skip_keyup = true
|
509
|
+
@markAsSelected(prev_node)
|
510
|
+
return false
|
511
|
+
|
512
|
+
#parse text for initial mess
|
513
|
+
parseInitialMess: ()->
|
514
|
+
@setupElementsClasses $(@el).find('.section-inner') , ()=>
|
515
|
+
@handleUnwrappedImages($(@el).find('.section-inner'))
|
516
|
+
|
517
|
+
handleDblclick: ()->
|
518
|
+
utils.log "handleDblclick"
|
519
|
+
node = @getNode()
|
520
|
+
if _.isNull node
|
521
|
+
@setRangeAt(@prev_current_node)
|
522
|
+
return false
|
523
|
+
|
524
|
+
#detects html data , creates a hidden node to paste ,
|
525
|
+
#then clean up the content and copies to currentNode, very clever uh?
|
526
|
+
handlePaste: (ev)=>
|
527
|
+
utils.log("pasted!")
|
528
|
+
@aa = @getNode()
|
529
|
+
|
530
|
+
pastedText = undefined
|
531
|
+
if (window.clipboardData && window.clipboardData.getData) #IE
|
532
|
+
pastedText = window.clipboardData.getData('Text')
|
533
|
+
else if (ev.originalEvent.clipboardData && ev.originalEvent.clipboardData.getData)
|
534
|
+
cbd = ev.originalEvent.clipboardData
|
535
|
+
pastedText = if _.isEmpty(cbd.getData('text/html')) then cbd.getData('text/plain') else cbd.getData('text/html')
|
536
|
+
|
537
|
+
utils.log("Process and handle text...")
|
538
|
+
#detect if is html
|
539
|
+
if pastedText.match(/<\/*[a-z][^>]+?>/gi)
|
540
|
+
utils.log("HTML DETECTED ON PASTE")
|
541
|
+
pastedText = pastedText.replace(/&.*;/g, "")
|
542
|
+
#convert pasted divs in p before copy contents into div
|
543
|
+
pastedText = pastedText.replace(/<div>([\w\W]*?)<\/div>/gi, '<p>$1</p>')
|
544
|
+
|
545
|
+
document.body.appendChild($("<div id='#{@paste_element_id.replace('#', '')}'></div>")[0])
|
546
|
+
$(@paste_element_id).html("<span>#{pastedText}</span>")
|
547
|
+
|
548
|
+
@setupElementsClasses $(@paste_element_id), ()=>
|
549
|
+
nodes = $($(@paste_element_id).html()).insertAfter($(@aa))
|
550
|
+
$(@paste_element_id).remove()
|
551
|
+
#set caret on newly created node
|
552
|
+
last_node = nodes.last()[0]
|
553
|
+
num = last_node.childNodes.length
|
554
|
+
@setRangeAt(last_node, num)
|
555
|
+
new_node = $(@getNode())
|
556
|
+
top = new_node.offset().top
|
557
|
+
@markAsSelected(new_node)
|
558
|
+
@displayTooltipAt($(@el).find(".is-selected"))
|
559
|
+
#scroll to element top
|
560
|
+
@handleUnwrappedImages(nodes)
|
561
|
+
$('html, body').animate
|
562
|
+
scrollTop: top
|
563
|
+
, 200
|
564
|
+
|
565
|
+
return false # Prevent the default handler from running.
|
566
|
+
|
567
|
+
handleUnwrappedImages: (elements)->
|
568
|
+
#http://stackoverflow.com/questions/4998908/convert-data-uri-to-file-then-append-to-formdata
|
569
|
+
_.each elements.find("img"), (image)=>
|
570
|
+
utils.log ("process image here!")
|
571
|
+
@uploader_widget.uploadExistentImage(image)
|
572
|
+
|
573
|
+
handleInmediateDeletion: (element)->
|
574
|
+
@inmediateDeletion = false
|
575
|
+
new_node = $( @baseParagraphTmpl() ).insertBefore( $(element) )
|
576
|
+
new_node.addClass("is-selected")
|
577
|
+
@setRangeAt($(element).prev()[0])
|
578
|
+
$(element).remove()
|
579
|
+
|
580
|
+
#TODO: not used anymore, remove this
|
581
|
+
#when found that the current node is text node
|
582
|
+
#create a new <p> and focus
|
583
|
+
handleUnwrappedNode: (element)->
|
584
|
+
tmpl = $(@baseParagraphTmpl())
|
585
|
+
@setElementName(tmpl)
|
586
|
+
$(element).wrap(tmpl)
|
587
|
+
new_node = $("[name='#{tmpl.attr('name')}']")
|
588
|
+
new_node.addClass("is-selected")
|
589
|
+
@setRangeAt(new_node[0])
|
590
|
+
return false
|
591
|
+
|
592
|
+
###
|
593
|
+
This is a rare hack only for FF (I hope),
|
594
|
+
when there is no range it creates a new element as a placeholder,
|
595
|
+
then finds previous element from that placeholder,
|
596
|
+
then it focus the prev and removes the placeholder.
|
597
|
+
a nasty nasty one...
|
598
|
+
###
|
599
|
+
handleNullAnchor: ()->
|
600
|
+
utils.log "WARNING! this is an empty node"
|
601
|
+
sel = @selection();
|
602
|
+
|
603
|
+
if (sel.isCollapsed && sel.rangeCount > 0)
|
604
|
+
range = sel.getRangeAt(0)
|
605
|
+
span = $( @baseParagraphTmpl())[0]
|
606
|
+
range.insertNode(span)
|
607
|
+
range.setStart(span, 0)
|
608
|
+
range.setEnd(span, 0)
|
609
|
+
sel.removeAllRanges()
|
610
|
+
sel.addRange(range)
|
611
|
+
|
612
|
+
node = $(range.commonAncestorContainer)
|
613
|
+
prev = node.prev()
|
614
|
+
num = prev[0].childNodes.length
|
615
|
+
utils.log prev
|
616
|
+
if prev.hasClass("graf")
|
617
|
+
@setRangeAt(prev[0], num)
|
618
|
+
node.remove()
|
619
|
+
@markAsSelected(@getNode())
|
620
|
+
else if prev.hasClass("graf--mixtapeEmbed")
|
621
|
+
@setRangeAt(prev[0], num)
|
622
|
+
node.remove()
|
623
|
+
@markAsSelected(@getNode())
|
624
|
+
else if !prev
|
625
|
+
@.setRangeAt(@.$el.find(".section-inner p")[0])
|
626
|
+
|
627
|
+
@displayTooltipAt($(@el).find(".is-selected"))
|
628
|
+
|
629
|
+
#used when all the content is removed, then it re render
|
630
|
+
handleCompleteDeletion: (element)->
|
631
|
+
if _.isEmpty( $(element).text().trim() )
|
632
|
+
utils.log "HANDLE COMPLETE DELETION"
|
633
|
+
@selection().removeAllRanges()
|
634
|
+
@render()
|
635
|
+
|
636
|
+
setTimeout =>
|
637
|
+
@setRangeAt($(@el).find(".section-inner p")[0])
|
638
|
+
, 20
|
639
|
+
@completeDeletion = true
|
640
|
+
|
641
|
+
#handles tab navigation
|
642
|
+
handleTab: (anchor_node)->
|
643
|
+
utils.log "HANDLE TAB"
|
644
|
+
classes = ".graf, .graf--mixtapeEmbed, .graf--figure, .graf--figure"
|
645
|
+
next = $(anchor_node).next(classes)
|
646
|
+
|
647
|
+
if $(next).hasClass("graf--figure")
|
648
|
+
next = $(next).find("figcaption")
|
649
|
+
@setRangeAt next[0]
|
650
|
+
@markAsSelected $(next).parent(".graf--figure")
|
651
|
+
@displayTooltipAt next
|
652
|
+
@scrollTo $(next)
|
653
|
+
return false
|
654
|
+
|
655
|
+
if _.isEmpty(next) or _.isUndefined(next[0])
|
656
|
+
next = $(".graf:first")
|
657
|
+
|
658
|
+
@setRangeAt next[0]
|
659
|
+
@markAsSelected next
|
660
|
+
@displayTooltipAt next
|
661
|
+
@scrollTo $(next)
|
662
|
+
|
663
|
+
handleKeyDown: (e)->
|
664
|
+
utils.log "KEYDOWN"
|
665
|
+
|
666
|
+
anchor_node = @getNode() #current node on which cursor is positioned
|
667
|
+
parent = $(anchor_node)
|
668
|
+
|
669
|
+
|
670
|
+
@markAsSelected( anchor_node ) if anchor_node
|
671
|
+
|
672
|
+
if e.which is TAB
|
673
|
+
|
674
|
+
@handleTab(anchor_node)
|
675
|
+
return false
|
676
|
+
|
677
|
+
if e.which == ENTER
|
678
|
+
|
679
|
+
#removes previous selected nodes
|
680
|
+
$(@el).find(".is-selected").removeClass("is-selected")
|
681
|
+
|
682
|
+
utils.log @isLastChar()
|
683
|
+
|
684
|
+
#smart list support
|
685
|
+
if parent.hasClass("graf--p")
|
686
|
+
li = @handleSmartList(parent, e)
|
687
|
+
anchor_node = li if li
|
688
|
+
else if parent.hasClass("graf--li")
|
689
|
+
@handleListLineBreak(parent, e)
|
690
|
+
|
691
|
+
#handle keydowns for each widget
|
692
|
+
utils.log("HANDLING WIDGET KEYDOWNS");
|
693
|
+
_.each @widgets, (w)=>
|
694
|
+
if w.handleEnterKey
|
695
|
+
w.handleEnterKey(e, parent);
|
696
|
+
|
697
|
+
#supress linebreak into embed page text unless last char
|
698
|
+
if parent.hasClass("graf--mixtapeEmbed") or parent.hasClass("graf--iframe") or parent.hasClass("graf--figure")
|
699
|
+
utils.log("supress linebreak from embed !(last char)")
|
700
|
+
return false unless @isLastChar()
|
701
|
+
|
702
|
+
#supress linebreak or create new <p> into embed caption unless last char el
|
703
|
+
if parent.hasClass("graf--iframe") or parent.hasClass("graf--figure")
|
704
|
+
if @isLastChar()
|
705
|
+
@handleLineBreakWith("p", parent)
|
706
|
+
@setRangeAtText($(".is-selected")[0])
|
707
|
+
|
708
|
+
$(".is-selected").trigger("mouseup") #is not making any change
|
709
|
+
return false
|
710
|
+
else
|
711
|
+
return false
|
712
|
+
|
713
|
+
@tooltip_view.cleanOperationClasses($(anchor_node))
|
714
|
+
|
715
|
+
if (anchor_node && @editor_menu.lineBreakReg.test(anchor_node.nodeName))
|
716
|
+
#new paragraph if it the last character
|
717
|
+
if @isLastChar()
|
718
|
+
utils.log "new paragraph if it's the last character"
|
719
|
+
e.preventDefault()
|
720
|
+
@handleLineBreakWith("p", parent)
|
721
|
+
|
722
|
+
setTimeout ()=>
|
723
|
+
node = @getNode()
|
724
|
+
return if _.isUndefined(node)
|
725
|
+
#set name on new element
|
726
|
+
@setElementName($(node))
|
727
|
+
|
728
|
+
if node.nodeName.toLowerCase() is "div"
|
729
|
+
node = @replaceWith("p", $(node))[0]
|
730
|
+
@markAsSelected( $(node) ) #if anchor_node
|
731
|
+
@setupFirstAndLast()
|
732
|
+
|
733
|
+
#empty childs if text is empty
|
734
|
+
if _.isEmpty $(node).text().trim()
|
735
|
+
_.each $(node).children(), (n)->
|
736
|
+
$(n).remove()
|
737
|
+
$(node).append("<br>")
|
738
|
+
|
739
|
+
#shows tooltip
|
740
|
+
@displayTooltipAt($(@el).find(".is-selected"))
|
741
|
+
, 2
|
742
|
+
|
743
|
+
#delete key
|
744
|
+
if (e.which == BACKSPACE)
|
745
|
+
eventHandled = false;
|
746
|
+
@tooltip_view.hide()
|
747
|
+
utils.log("removing from down")
|
748
|
+
utils.log "REACHED TOP" if @reachedTop
|
749
|
+
return false if @prevented or @reachedTop && @isFirstChar()
|
750
|
+
#return false if !anchor_node or anchor_node.nodeType is 3
|
751
|
+
utils.log("pass initial validations")
|
752
|
+
anchor_node = @getNode()
|
753
|
+
utils_anchor_node = utils.getNode()
|
754
|
+
|
755
|
+
utils.log(anchor_node);
|
756
|
+
utils.log(utils_anchor_node);
|
757
|
+
|
758
|
+
#check if any of the widgets can handle a backspace keydown
|
759
|
+
utils.log("HANDLING WIDGET BACKSPACES");
|
760
|
+
_.each @widgets, (w)=>
|
761
|
+
if w.handleBackspaceKey && !handled
|
762
|
+
handled = w.handleBackspaceKey(e, anchor_node);
|
763
|
+
|
764
|
+
if (eventHandled)
|
765
|
+
e.preventDefault();
|
766
|
+
return false;
|
767
|
+
|
768
|
+
if(parent.hasClass("graf--li") and @getCharacterPrecedingCaret().length is 0)
|
769
|
+
return this.handleListBackspace(parent, e);
|
770
|
+
|
771
|
+
#select an image if backspacing into it from a paragraph
|
772
|
+
if($(anchor_node).hasClass("graf--p") && @isFirstChar)
|
773
|
+
if($(anchor_node).prev().hasClass("graf--figure"))
|
774
|
+
e.preventDefault();
|
775
|
+
$(anchor_node).prev().find("img").click();
|
776
|
+
utils.log("Focus on the previous image")
|
777
|
+
|
778
|
+
if $(utils_anchor_node).hasClass("section-content") || $(utils_anchor_node).hasClass("graf--first")
|
779
|
+
utils.log "SECTION DETECTED FROM KEYDOWN #{_.isEmpty($(utils_anchor_node).text())}"
|
780
|
+
return false if _.isEmpty($(utils_anchor_node).text())
|
781
|
+
|
782
|
+
if anchor_node && anchor_node.nodeType is 3
|
783
|
+
#@displayEmptyPlaceholder()
|
784
|
+
utils.log("TextNode detected from Down!")
|
785
|
+
#return false
|
786
|
+
|
787
|
+
#supress del into & delete embed if empty content found on delete key
|
788
|
+
if $(anchor_node).hasClass("graf--mixtapeEmbed") or $(anchor_node).hasClass("graf--iframe")
|
789
|
+
if _.isEmpty $(anchor_node).text().trim() or @isFirstChar()
|
790
|
+
utils.log("Check for inmediate deletion on empty embed text")
|
791
|
+
@inmediateDeletion = @isSelectingAll(anchor_node)
|
792
|
+
@handleInmediateDeletion($(anchor_node)) if @inmediateDeletion
|
793
|
+
return false
|
794
|
+
|
795
|
+
#TODO: supress del when the prev el is embed and current_node is at first char
|
796
|
+
if $(anchor_node).prev().hasClass("graf--mixtapeEmbed")
|
797
|
+
return false if @isFirstChar() && !_.isEmpty( $(anchor_node).text().trim() )
|
798
|
+
|
799
|
+
#spacebar
|
800
|
+
if (e.which == SPACEBAR)
|
801
|
+
utils.log("SPACEBAR")
|
802
|
+
if (parent.hasClass("graf--p"))
|
803
|
+
@handleSmartList(parent, e)
|
804
|
+
#arrows key
|
805
|
+
#if _.contains([37,38,39,40], e.which)
|
806
|
+
#up & down
|
807
|
+
if _.contains([UPARROW, DOWNARROW], e.which)
|
808
|
+
utils.log e.which
|
809
|
+
@handleArrowForKeyDown(e)
|
810
|
+
#return false
|
811
|
+
|
812
|
+
#hides tooltip if anchor_node text is empty
|
813
|
+
if anchor_node
|
814
|
+
unless _.isEmpty($(anchor_node).text())
|
815
|
+
@tooltip_view.hide()
|
816
|
+
$(anchor_node).removeClass("graf--empty")
|
817
|
+
|
818
|
+
#when user types over a selected image (graf--figure)
|
819
|
+
#unselect image , and set range on caption
|
820
|
+
if _.isUndefined(anchor_node) && $(".is-selected").hasClass("is-mediaFocused")
|
821
|
+
@setRangeAt $(".is-selected").find("figcaption")[0]
|
822
|
+
$(".is-selected").removeClass("is-mediaFocused")
|
823
|
+
return false
|
824
|
+
|
825
|
+
handleKeyUp: (e , node)->
|
826
|
+
|
827
|
+
if @skip_keyup
|
828
|
+
@skip_keyup = null
|
829
|
+
utils.log "SKIP KEYUP"
|
830
|
+
return false
|
831
|
+
|
832
|
+
utils.log "KEYUP"
|
833
|
+
|
834
|
+
@editor_menu.hide() #hides menu just in case
|
835
|
+
@reachedTop = false
|
836
|
+
anchor_node = @getNode() #current node on which cursor is positioned
|
837
|
+
utils_anchor_node = utils.getNode()
|
838
|
+
|
839
|
+
@handleTextSelection(anchor_node)
|
840
|
+
|
841
|
+
if (_.contains([BACKSPACE, SPACEBAR, ENTER], e.which))
|
842
|
+
if $(anchor_node).hasClass("graf--li")
|
843
|
+
@removeSpanTag($(anchor_node));
|
844
|
+
|
845
|
+
if (e.which == BACKSPACE)
|
846
|
+
|
847
|
+
#if detect all text deleted , re render
|
848
|
+
if $(utils_anchor_node).hasClass("postField--body")
|
849
|
+
utils.log "ALL GONE from UP"
|
850
|
+
@handleCompleteDeletion($(@el))
|
851
|
+
if @completeDeletion
|
852
|
+
@completeDeletion = false
|
853
|
+
return false
|
854
|
+
|
855
|
+
if $(utils_anchor_node).hasClass("section-content") || $(utils_anchor_node).hasClass("graf--first")
|
856
|
+
utils.log "SECTION DETECTED FROM KEYUP #{_.isEmpty($(utils_anchor_node).text())}"
|
857
|
+
if _.isEmpty($(utils_anchor_node).text())
|
858
|
+
next_graf = $(utils_anchor_node).next(".graf")[0]
|
859
|
+
if next_graf
|
860
|
+
@setRangeAt next_graf
|
861
|
+
$(utils_anchor_node).remove()
|
862
|
+
@setupFirstAndLast()
|
863
|
+
return false
|
864
|
+
|
865
|
+
if _.isNull(anchor_node)
|
866
|
+
@handleNullAnchor()
|
867
|
+
return false
|
868
|
+
|
869
|
+
if $(anchor_node).hasClass("graf--first")
|
870
|
+
utils.log "THE FIRST ONE! UP"
|
871
|
+
|
872
|
+
if @.getSelectedText() is @.getNode().textContent
|
873
|
+
utils.log "remove selection dectected"
|
874
|
+
@.getNode().innerHTML = "<br>"
|
875
|
+
|
876
|
+
@markAsSelected(anchor_node)
|
877
|
+
@setupFirstAndLast()
|
878
|
+
false
|
879
|
+
|
880
|
+
#if anchor_node
|
881
|
+
# @markAsSelected(anchor_node)
|
882
|
+
# @setupFirstAndLast()
|
883
|
+
# @displayTooltipAt($(@el).find(".is-selected"))
|
884
|
+
|
885
|
+
|
886
|
+
#arrows key
|
887
|
+
if _.contains([LEFTARROW, UPARROW, RIGHTARROW, DOWNARROW], e.which)
|
888
|
+
@handleArrow(e)
|
889
|
+
#return false
|
890
|
+
|
891
|
+
#TODO: Separate in little functions
|
892
|
+
handleLineBreakWith: (element_type, from_element)->
|
893
|
+
new_paragraph = $("<#{element_type} class='graf graf--#{element_type} graf--empty is-selected'><br/></#{element_type}>")
|
894
|
+
if from_element.parent().is('[class^="graf--"]')
|
895
|
+
new_paragraph.insertAfter(from_element.parent())
|
896
|
+
else
|
897
|
+
new_paragraph.insertAfter(from_element)
|
898
|
+
#set caret on new <p>
|
899
|
+
@setRangeAt(new_paragraph[0])
|
900
|
+
@scrollTo new_paragraph
|
901
|
+
|
902
|
+
replaceWith: (element_type, from_element)->
|
903
|
+
new_paragraph = $("<#{element_type} class='graf graf--#{element_type} graf--empty is-selected'><br/></#{element_type}>")
|
904
|
+
from_element.replaceWith(new_paragraph)
|
905
|
+
@setRangeAt(new_paragraph[0])
|
906
|
+
@scrollTo new_paragraph
|
907
|
+
new_paragraph
|
908
|
+
|
909
|
+
#shows the (+) tooltip at current element
|
910
|
+
displayTooltipAt: (element)->
|
911
|
+
utils.log ("POSITION FOR TOOLTIP")
|
912
|
+
#utils.log $(element)
|
913
|
+
element = $(element)
|
914
|
+
return if !element || _.isUndefined(element) || _.isEmpty(element) || element[0].tagName is "LI"
|
915
|
+
@tooltip_view.hide()
|
916
|
+
return unless _.isEmpty( element.text() )
|
917
|
+
@positions = element.offset()
|
918
|
+
@tooltip_view.render()
|
919
|
+
@tooltip_view.move(@positions)
|
920
|
+
|
921
|
+
#mark the current row as selected
|
922
|
+
markAsSelected: (element)->
|
923
|
+
|
924
|
+
return if _.isUndefined element
|
925
|
+
|
926
|
+
$(@el).find(".is-selected").removeClass("is-mediaFocused is-selected")
|
927
|
+
$(element).addClass("is-selected")
|
928
|
+
|
929
|
+
$(element).find(".defaultValue").remove()
|
930
|
+
#set reached top if element is first!
|
931
|
+
if $(element).hasClass("graf--first")
|
932
|
+
@reachedTop = true
|
933
|
+
$(element).append("<br>") if $(element).find("br").length is 0
|
934
|
+
|
935
|
+
addClassesToElement: (element)=>
|
936
|
+
n = element
|
937
|
+
name = n.nodeName.toLowerCase()
|
938
|
+
switch name
|
939
|
+
when "p", "pre", "div"
|
940
|
+
unless $(n).hasClass("graf--mixtapeEmbed")
|
941
|
+
$(n).removeClass().addClass("graf graf--#{name}")
|
942
|
+
|
943
|
+
if name is "p" and $(n).find("br").length is 0
|
944
|
+
$(n).append("<br>")
|
945
|
+
|
946
|
+
when "h1", "h2", "h3", "h4", "h5", "h6"
|
947
|
+
if name is "h1"
|
948
|
+
new_el = $("<h2 class='graf graf--h2'>#{$(n).text()}</h2>")
|
949
|
+
$(n).replaceWith(new_el)
|
950
|
+
@setElementName(n)
|
951
|
+
else
|
952
|
+
$(n).removeClass().addClass("graf graf--#{name}")
|
953
|
+
|
954
|
+
when "code"
|
955
|
+
#utils.log n
|
956
|
+
$(n).unwrap().wrap("<p class='graf graf--pre'></p>")
|
957
|
+
n = $(n).parent()
|
958
|
+
|
959
|
+
when "ol", "ul"
|
960
|
+
utils.log "lists"
|
961
|
+
$(n).removeClass().addClass("postList")
|
962
|
+
_.each $(n).find("li"), (li)->
|
963
|
+
$(li).removeClass().addClass("graf graf--li")
|
964
|
+
#postList , and li as graf
|
965
|
+
|
966
|
+
when "img"
|
967
|
+
utils.log "images"
|
968
|
+
@uploader_widget.uploadExistentImage(n)
|
969
|
+
#set figure non editable
|
970
|
+
|
971
|
+
when "a", 'strong', 'em', 'br', 'b', 'u', 'i'
|
972
|
+
utils.log "links"
|
973
|
+
$(n).wrap("<p class='graf graf--p'></p>")
|
974
|
+
n = $(n).parent()
|
975
|
+
#dont know
|
976
|
+
|
977
|
+
when "blockquote"
|
978
|
+
#TODO remove inner elements like P
|
979
|
+
#$(n).find("p").unwrap()
|
980
|
+
n = $(n).removeClass().addClass("graf graf--#{name}")
|
981
|
+
|
982
|
+
when "figure"
|
983
|
+
if $(n).hasClass(".graf--figure")
|
984
|
+
n = $(n)
|
985
|
+
else
|
986
|
+
#TODO: for now leave this relaxed, because this is
|
987
|
+
#overwriting embeds
|
988
|
+
#wrap all the rest
|
989
|
+
$(n).wrap("<p class='graf graf--#{name}'></p>")
|
990
|
+
n = $(n).parent()
|
991
|
+
|
992
|
+
return n
|
993
|
+
|
994
|
+
setupElementsClasses: (element, cb)->
|
995
|
+
if _.isUndefined(element)
|
996
|
+
@element = $(@el).find('.section-inner')
|
997
|
+
else
|
998
|
+
@element = element
|
999
|
+
|
1000
|
+
setTimeout ()=>
|
1001
|
+
#clean context and wrap text nodes
|
1002
|
+
@cleanContents(@element)
|
1003
|
+
@wrapTextNodes(@element)
|
1004
|
+
|
1005
|
+
#setup classes
|
1006
|
+
_.each @element.children(), (n)=>
|
1007
|
+
name = $(n).prop("tagName").toLowerCase()
|
1008
|
+
n = @addClassesToElement(n)
|
1009
|
+
@setElementName(n)
|
1010
|
+
|
1011
|
+
@setupLinks(@element.find("a"))
|
1012
|
+
@setupFirstAndLast()
|
1013
|
+
|
1014
|
+
cb() if _.isFunction(cb)
|
1015
|
+
, 20
|
1016
|
+
|
1017
|
+
cleanContents: (element)->
|
1018
|
+
#TODO: should config tags
|
1019
|
+
if _.isUndefined(element)
|
1020
|
+
@element = $(@el).find('.section-inner')
|
1021
|
+
else
|
1022
|
+
@element = element
|
1023
|
+
|
1024
|
+
s = new Sanitize
|
1025
|
+
elements: ['strong','img', 'em', 'br', 'a', 'blockquote', 'b', 'u', 'i', 'pre', 'p', 'h1', 'h2', 'h3', 'h4', 'ul', 'ol', 'li']
|
1026
|
+
|
1027
|
+
attributes:
|
1028
|
+
'__ALL__': ['class']
|
1029
|
+
a: ['href', 'title', 'target']
|
1030
|
+
img: ['src']
|
1031
|
+
|
1032
|
+
protocols:
|
1033
|
+
a: { href: ['http', 'https', 'mailto'] }
|
1034
|
+
|
1035
|
+
transformers: [(input)->
|
1036
|
+
if (input.node_name == "span" && $(input.node).hasClass("defaultValue") )
|
1037
|
+
return whitelist_nodes: [input.node]
|
1038
|
+
else
|
1039
|
+
return null
|
1040
|
+
(input)->
|
1041
|
+
#page embeds
|
1042
|
+
if(input.node_name == 'div' && $(input.node).hasClass("graf--mixtapeEmbed") )
|
1043
|
+
return whitelist_nodes: [input.node]
|
1044
|
+
else if(input.node_name == 'a' && $(input.node).parent(".graf--mixtapeEmbed").exists() )
|
1045
|
+
return attr_whitelist: ["style"]
|
1046
|
+
else
|
1047
|
+
return null
|
1048
|
+
,
|
1049
|
+
(input)->
|
1050
|
+
#embeds
|
1051
|
+
if( input.node_name == 'figure' && $(input.node).hasClass("graf--iframe") )
|
1052
|
+
return whitelist_nodes: [input.node]
|
1053
|
+
else if(input.node_name == 'div' && $(input.node).hasClass("iframeContainer") && $(input.node).parent(".graf--iframe").exists() )
|
1054
|
+
return whitelist_nodes: [input.node]
|
1055
|
+
else if(input.node_name == 'iframe' && $(input.node).parent(".iframeContainer").exists() )
|
1056
|
+
return whitelist_nodes: [input.node]
|
1057
|
+
else if(input.node_name == 'figcaption' && $(input.node).parent(".graf--iframe").exists() )
|
1058
|
+
return whitelist_nodes: [input.node]
|
1059
|
+
else
|
1060
|
+
return null
|
1061
|
+
,
|
1062
|
+
(input)->
|
1063
|
+
#image embeds
|
1064
|
+
if(input.node_name == 'figure' && $(input.node).hasClass("graf--figure") )
|
1065
|
+
return whitelist_nodes: [input.node]
|
1066
|
+
|
1067
|
+
else if(input.node_name == 'div' && ( $(input.node).hasClass("aspectRatioPlaceholder") && $(input.node).parent(".graf--figure").exists() ))
|
1068
|
+
return whitelist_nodes: [input.node]
|
1069
|
+
|
1070
|
+
else if(input.node_name == 'div' && ( $(input.node).hasClass("aspect-ratio-fill") && $(input.node).parent(".aspectRatioPlaceholder").exists() ))
|
1071
|
+
return whitelist_nodes: [input.node]
|
1072
|
+
|
1073
|
+
else if(input.node_name == 'img' && $(input.node).parent(".graf--figure").exists() )
|
1074
|
+
return whitelist_nodes: [input.node]
|
1075
|
+
|
1076
|
+
else if(input.node_name == 'a' && $(input.node).parent(".graf--mixtapeEmbed").exists() )
|
1077
|
+
return attr_whitelist: ["style"]
|
1078
|
+
|
1079
|
+
else if(input.node_name == 'figcaption' && $(input.node).parent(".graf--figure").exists())
|
1080
|
+
return whitelist_nodes: [input.node]
|
1081
|
+
|
1082
|
+
else if(input.node_name == 'span' && $(input.node).parent(".imageCaption").exists())
|
1083
|
+
return whitelist_nodes: [input.node]
|
1084
|
+
else
|
1085
|
+
return null
|
1086
|
+
]
|
1087
|
+
|
1088
|
+
if @element.exists()
|
1089
|
+
utils.log "CLEAN HTML #{@element[0].tagName}"
|
1090
|
+
@element.html(s.clean_node( @element[0] ))
|
1091
|
+
|
1092
|
+
setupLinks: (elems)->
|
1093
|
+
_.each elems, (n)=>
|
1094
|
+
@setupLink(n)
|
1095
|
+
|
1096
|
+
setupLink: (n)->
|
1097
|
+
parent_name = $(n).parent().prop("tagName").toLowerCase()
|
1098
|
+
$(n).addClass("markup--anchor markup--#{parent_name}-anchor")
|
1099
|
+
href = $(n).attr("href")
|
1100
|
+
$(n).attr("data-href", href)
|
1101
|
+
|
1102
|
+
preCleanNode: (element)->
|
1103
|
+
s = new Sanitize
|
1104
|
+
elements: ['strong', 'em', 'br', 'a', 'b', 'u', 'i', 'ul', 'ol', 'li']
|
1105
|
+
|
1106
|
+
attributes:
|
1107
|
+
a: ['href', 'title', 'target']
|
1108
|
+
|
1109
|
+
protocols:
|
1110
|
+
a: { href: ['http', 'https', 'mailto'] }
|
1111
|
+
|
1112
|
+
$(element).html s.clean_node( element[0] )
|
1113
|
+
|
1114
|
+
element = @addClassesToElement( $(element)[0] )
|
1115
|
+
|
1116
|
+
$(element)
|
1117
|
+
|
1118
|
+
setupFirstAndLast: ()=>
|
1119
|
+
childs = $(@el).find(".section-inner").children()
|
1120
|
+
childs.removeClass("graf--last , graf--first")
|
1121
|
+
childs.first().addClass("graf--first")
|
1122
|
+
childs.last().addClass("graf--last")
|
1123
|
+
|
1124
|
+
wrapTextNodes: (element)->
|
1125
|
+
if _.isUndefined(element)
|
1126
|
+
element = $(@el).find('.section-inner')
|
1127
|
+
else
|
1128
|
+
element = element
|
1129
|
+
|
1130
|
+
element.contents().filter(->
|
1131
|
+
@nodeType is 3 and @data.trim().length > 0
|
1132
|
+
).wrap "<p class='graf grap--p'></p>"
|
1133
|
+
|
1134
|
+
setElementName: (element)->
|
1135
|
+
$(element).attr("name", utils.generateUniqueName())
|
1136
|
+
|
1137
|
+
# LIST METHODS
|
1138
|
+
|
1139
|
+
listify: ($paragraph, listType, regex)->
|
1140
|
+
|
1141
|
+
utils.log "LISTIFY PARAGRAPH"
|
1142
|
+
|
1143
|
+
@removeSpanTag($paragraph);
|
1144
|
+
|
1145
|
+
content = $paragraph.html().replace(/ /g, " ").replace(regex, "")
|
1146
|
+
|
1147
|
+
switch(listType)
|
1148
|
+
when "ul" then $list = $("<ul></ul>")
|
1149
|
+
when "ol" then $list = $("<ol></ol>")
|
1150
|
+
else return false
|
1151
|
+
|
1152
|
+
@addClassesToElement($list[0])
|
1153
|
+
@replaceWith("li", $paragraph)
|
1154
|
+
$li = $(".is-selected")
|
1155
|
+
|
1156
|
+
@setElementName($li[0])
|
1157
|
+
|
1158
|
+
$li.html(content).wrap($list)
|
1159
|
+
|
1160
|
+
if($li.find("br").length == 0)
|
1161
|
+
$li.append("<br/>")
|
1162
|
+
|
1163
|
+
@setRangeAt($li[0])
|
1164
|
+
|
1165
|
+
$li[0]
|
1166
|
+
|
1167
|
+
handleSmartList: ($item, e)->
|
1168
|
+
utils.log("HANDLE A SMART LIST")
|
1169
|
+
|
1170
|
+
chars = @getCharacterPrecedingCaret()
|
1171
|
+
match = chars.match(/^\s*(\-|\*)\s*$/)
|
1172
|
+
if(match)
|
1173
|
+
utils.log("CREATING LIST ITEM")
|
1174
|
+
e.preventDefault()
|
1175
|
+
regex = new RegExp(/\s*(\-|\*)\s*/)
|
1176
|
+
$li = @listify($item, "ul", regex)
|
1177
|
+
else
|
1178
|
+
match = chars.match(/^\s*1(\.|\))\s*$/)
|
1179
|
+
if(match)
|
1180
|
+
utils.log("CREATING LIST ITEM")
|
1181
|
+
e.preventDefault()
|
1182
|
+
|
1183
|
+
regex = new RegExp(/\s*1(\.|\))\s*/)
|
1184
|
+
$li = @listify($item, "ol", regex)
|
1185
|
+
$li
|
1186
|
+
|
1187
|
+
handleListLineBreak: ($li, e)->
|
1188
|
+
utils.log("LIST LINE BREAK")
|
1189
|
+
@tooltip_view.hide()
|
1190
|
+
$list = $li.parent("ol, ul")
|
1191
|
+
$paragraph = $("<p></p>")
|
1192
|
+
utils.log($li.prev());
|
1193
|
+
if($list.children().length is 1 and $li.text() is "")
|
1194
|
+
@replaceWith("p", $list)
|
1195
|
+
|
1196
|
+
else if $li.text() is "" and ($li.next().length isnt 0)
|
1197
|
+
e.preventDefault()
|
1198
|
+
|
1199
|
+
else if ($li.next().length is 0)
|
1200
|
+
if($li.text() is "")
|
1201
|
+
e.preventDefault()
|
1202
|
+
utils.log("BREAK FROM LIST")
|
1203
|
+
$list.after($paragraph)
|
1204
|
+
$li.addClass("graf--removed").remove()
|
1205
|
+
|
1206
|
+
else if ($li.prev().length isnt 0 and $li.prev().text() is "" and @getCharacterPrecedingCaret() is "")
|
1207
|
+
e.preventDefault()
|
1208
|
+
utils.log("PREV IS EMPTY")
|
1209
|
+
content = $li.html()
|
1210
|
+
$list.after($paragraph)
|
1211
|
+
$li.prev().remove()
|
1212
|
+
$li.addClass("graf--removed").remove()
|
1213
|
+
$paragraph.html(content)
|
1214
|
+
|
1215
|
+
if $list and $list.children().length is 0 then $list.remove()
|
1216
|
+
|
1217
|
+
utils.log($li);
|
1218
|
+
if ($li.hasClass("graf--removed"))
|
1219
|
+
utils.log("ELEMENT REMOVED")
|
1220
|
+
@addClassesToElement($paragraph[0])
|
1221
|
+
@setRangeAt($paragraph[0])
|
1222
|
+
@markAsSelected($paragraph[0])
|
1223
|
+
@scrollTo($paragraph)
|
1224
|
+
|
1225
|
+
handleListBackspace: ($li, e)->
|
1226
|
+
|
1227
|
+
$list = $li.parent("ol, ul")
|
1228
|
+
utils.log("LIST BACKSPACE")
|
1229
|
+
|
1230
|
+
if($li.prev().length is 0)
|
1231
|
+
e.preventDefault()
|
1232
|
+
|
1233
|
+
$list.before($li)
|
1234
|
+
content = $li.html()
|
1235
|
+
@replaceWith("p", $li)
|
1236
|
+
$paragraph = $(".is-selected")
|
1237
|
+
$paragraph.removeClass("graf--empty").html(content)
|
1238
|
+
|
1239
|
+
if($list.children().length is 0)
|
1240
|
+
$list.remove()
|
1241
|
+
|
1242
|
+
@setupFirstAndLast()
|
1243
|
+
|
1244
|
+
#Remove Non-default Spans From Elements
|
1245
|
+
removeSpanTag: ($item)->
|
1246
|
+
|
1247
|
+
$spans = $item.find("span")
|
1248
|
+
$(span).replaceWith($(span).html()) for span in $spans when not $(span).hasClass("defaultValue")
|
1249
|
+
$item
|
1250
|
+
|