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.
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
+