dante-editor-seo 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|