dante-editor-seo 0.0.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +40 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +23 -0
  6. data/Gemfile.lock +140 -0
  7. data/Procfile +1 -0
  8. data/README.md +187 -0
  9. data/ROADMAP.md +10 -0
  10. data/TODO.md +30 -0
  11. data/app/assets/fonts/dante/dante.eot +0 -0
  12. data/app/assets/fonts/dante/dante.svg +14 -0
  13. data/app/assets/fonts/dante/dante.ttf +0 -0
  14. data/app/assets/fonts/dante/dante.woff +0 -0
  15. data/app/assets/fonts/dante/fontello.eot +0 -0
  16. data/app/assets/fonts/dante/fontello.svg +36 -0
  17. data/app/assets/fonts/dante/fontello.ttf +0 -0
  18. data/app/assets/fonts/dante/fontello.woff +0 -0
  19. data/app/assets/images/dante/media-loading-placeholder.png +0 -0
  20. data/app/assets/javascripts/dante/dante.js.coffee.erb +10 -0
  21. data/app/assets/javascripts/dante/editor.js.coffee +1250 -0
  22. data/app/assets/javascripts/dante/menu.js.coffee +216 -0
  23. data/app/assets/javascripts/dante/popover.js.coffee +75 -0
  24. data/app/assets/javascripts/dante/tooltip.js.coffee +82 -0
  25. data/app/assets/javascripts/dante/tooltip_widget.js.coffee +10 -0
  26. data/app/assets/javascripts/dante/tooltip_widgets/embed.js.coffee +60 -0
  27. data/app/assets/javascripts/dante/tooltip_widgets/extract.js.coffee +64 -0
  28. data/app/assets/javascripts/dante/tooltip_widgets/uploader.js.coffee +248 -0
  29. data/app/assets/javascripts/dante/utils.js.coffee +235 -0
  30. data/app/assets/javascripts/dante/view.js.coffee +101 -0
  31. data/app/assets/javascripts/dante.js +12 -0
  32. data/app/assets/stylesheets/dante/_animations.scss +54 -0
  33. data/app/assets/stylesheets/dante/_caption.scss +52 -0
  34. data/app/assets/stylesheets/dante/_debug.scss +11 -0
  35. data/app/assets/stylesheets/dante/_fonts.scss +17 -0
  36. data/app/assets/stylesheets/dante/_graf.scss +238 -0
  37. data/app/assets/stylesheets/dante/_icons.scss +57 -0
  38. data/app/assets/stylesheets/dante/_media.scss +39 -0
  39. data/app/assets/stylesheets/dante/_menu.scss +153 -0
  40. data/app/assets/stylesheets/dante/_needsorder.scss +209 -0
  41. data/app/assets/stylesheets/dante/_popover.scss +134 -0
  42. data/app/assets/stylesheets/dante/_post.scss +69 -0
  43. data/app/assets/stylesheets/dante/_scaffold.scss +20 -0
  44. data/app/assets/stylesheets/dante/_tooltip.scss +131 -0
  45. data/app/assets/stylesheets/dante/_utilities.scss +55 -0
  46. data/app/assets/stylesheets/dante/_variables.scss +46 -0
  47. data/app/assets/stylesheets/dante.scss +18 -0
  48. data/bower.json +44 -0
  49. data/config.rb +86 -0
  50. data/config.ru +42 -0
  51. data/dante-editor.gemspec +19 -0
  52. data/dist/css/dante-editor.css +1116 -0
  53. data/dist/fonts/dante/dante.eot +0 -0
  54. data/dist/fonts/dante/dante.svg +14 -0
  55. data/dist/fonts/dante/dante.ttf +0 -0
  56. data/dist/fonts/dante/dante.woff +0 -0
  57. data/dist/fonts/dante/fontello.eot +0 -0
  58. data/dist/fonts/dante/fontello.svg +36 -0
  59. data/dist/fonts/dante/fontello.ttf +0 -0
  60. data/dist/fonts/dante/fontello.woff +0 -0
  61. data/dist/images/dante/media-loading-placeholder.png +0 -0
  62. data/dist/js/dante-editor.js +2878 -0
  63. data/lib/dante-editor/rails.rb +4 -0
  64. data/lib/dante-editor/version.rb +5 -0
  65. data/lib/dante-editor.rb +5 -0
  66. data/license.md +22 -0
  67. data/rakefile +2 -0
  68. data/source/assets/images/dante-editor-logo.png +0 -0
  69. data/source/assets/images/github-logo.png +0 -0
  70. data/source/assets/javascripts/all.js +3 -0
  71. data/source/assets/javascripts/dante-editor.js +1 -0
  72. data/source/assets/javascripts/deps.js +4 -0
  73. data/source/assets/javascripts/examples/custom_toolbar.js.coffee +30 -0
  74. data/source/assets/javascripts/spec.js +2 -0
  75. data/source/assets/javascripts/specs/cleaner.js.coffee +8 -0
  76. data/source/assets/javascripts/specs/dante_view.js.coffee +74 -0
  77. data/source/assets/javascripts/specs/editor.js.coffee +78 -0
  78. data/source/assets/stylesheets/_layout.scss +51 -0
  79. data/source/assets/stylesheets/_scaffold.scss +8 -0
  80. data/source/assets/stylesheets/_tooltips.scss +216 -0
  81. data/source/assets/stylesheets/all.css.scss +5 -0
  82. data/source/assets/stylesheets/dante-editor.css.scss +1 -0
  83. data/source/assets/stylesheets/normalize.css +375 -0
  84. data/source/custom_toolbar.erb +29 -0
  85. data/source/embeds.html.erb +27 -0
  86. data/source/icons/dante.json +143 -0
  87. data/source/icons/embed.svg +13 -0
  88. data/source/icons/image.svg +13 -0
  89. data/source/icons/plus.svg +13 -0
  90. data/source/icons/video.svg +13 -0
  91. data/source/index.html.erb +18 -0
  92. data/source/layouts/layout.erb +26 -0
  93. data/source/layouts/spec.html.erb +22 -0
  94. data/source/lists.html.erb +18 -0
  95. data/source/partials/_content.erb +6 -0
  96. data/source/partials/_example_1.erb +45 -0
  97. data/source/partials/_example_2.erb +32 -0
  98. data/source/partials/_example_3.erb +4 -0
  99. data/source/partials/_lists.erb +13 -0
  100. data/source/partials/_readme.markdown +24 -0
  101. data/source/partials/test/_example_1.erb +39 -0
  102. data/source/tests/dante_view.html.erb +11 -0
  103. data/source/tests/index.html.erb +39 -0
  104. data/tmp/.gitkeep +0 -0
  105. 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(/&nbsp;/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
+