dante2-editor 0.2.0

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 (96) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +33 -0
  3. data/Gemfile +25 -0
  4. data/Gemfile.lock +42 -0
  5. data/README.md +107 -0
  6. data/app/assets/index.html +55 -0
  7. data/app/assets/license.html +52 -0
  8. data/app/assets/options.html +57 -0
  9. data/app/assets/store.json +1 -0
  10. data/app/components/App.cjsx +1083 -0
  11. data/app/components/blocks/embed.cjsx +109 -0
  12. data/app/components/blocks/image.cjsx +316 -0
  13. data/app/components/blocks/placeholder.cjsx +60 -0
  14. data/app/components/blocks/video.cjsx +75 -0
  15. data/app/components/debug.cjsx +96 -0
  16. data/app/components/decorators/link.cjsx +61 -0
  17. data/app/components/popovers/addButton.cjsx +247 -0
  18. data/app/components/popovers/image.cjsx +160 -0
  19. data/app/components/popovers/link.cjsx +87 -0
  20. data/app/components/popovers/toolTip.cjsx +326 -0
  21. data/app/data/poc.js +15 -0
  22. data/app/demo.js +7 -0
  23. data/app/images/dante/media-loading-placeholder.png +0 -0
  24. data/app/images/site/dante-demo.png +0 -0
  25. data/app/images/site/dante-editor-logo.png +0 -0
  26. data/app/images/site/github-logo.png +0 -0
  27. data/app/initialize.js +4 -0
  28. data/app/model/index.js +194 -0
  29. data/app/styles/dante.scss +22 -0
  30. data/app/styles/dante/_animations.scss +54 -0
  31. data/app/styles/dante/_caption.scss +61 -0
  32. data/app/styles/dante/_debug.scss +124 -0
  33. data/app/styles/dante/_fonts.scss +17 -0
  34. data/app/styles/dante/_graf.scss +242 -0
  35. data/app/styles/dante/_icons.scss +62 -0
  36. data/app/styles/dante/_media.scss +39 -0
  37. data/app/styles/dante/_menu.scss +201 -0
  38. data/app/styles/dante/_needsorder.scss +209 -0
  39. data/app/styles/dante/_popover.scss +212 -0
  40. data/app/styles/dante/_post.scss +67 -0
  41. data/app/styles/dante/_scaffold.scss +24 -0
  42. data/app/styles/dante/_tooltip.scss +130 -0
  43. data/app/styles/dante/_utilities.scss +59 -0
  44. data/app/styles/dante/_variables.scss +96 -0
  45. data/app/styles/dante/blame.scss +246 -0
  46. data/app/styles/draft.css +297 -0
  47. data/app/styles/fonts/dante/dante.eot +0 -0
  48. data/app/styles/fonts/dante/dante.svg +18 -0
  49. data/app/styles/fonts/dante/dante.ttf +0 -0
  50. data/app/styles/fonts/dante/dante.woff +0 -0
  51. data/app/styles/fonts/dante/fontello.eot +0 -0
  52. data/app/styles/fonts/dante/fontello.svg +36 -0
  53. data/app/styles/fonts/dante/fontello.ttf +0 -0
  54. data/app/styles/fonts/dante/fontello.woff +0 -0
  55. data/app/styles/layout/layout.scss +64 -0
  56. data/app/styles/layout/normalize.css +375 -0
  57. data/app/styles/layout/scaffold.scss +8 -0
  58. data/app/styles/layout/tooltips.scss +216 -0
  59. data/app/utils/find_entities.coffee +20 -0
  60. data/app/utils/html2content.coffee +120 -0
  61. data/app/utils/logger.coffee +0 -0
  62. data/app/utils/save_content.coffee +63 -0
  63. data/app/utils/selection.js +53 -0
  64. data/config.ru +64 -0
  65. data/dante2.gemspec +19 -0
  66. data/docs/app.css +2 -0
  67. data/docs/app.css.map +1 -0
  68. data/docs/app.js +3 -0
  69. data/docs/app.js.map +1 -0
  70. data/docs/dante-vendors.js +28 -0
  71. data/docs/dante-vendors.js.map +1 -0
  72. data/docs/dante.css +2 -0
  73. data/docs/dante.css.map +1 -0
  74. data/docs/dante.js +4 -0
  75. data/docs/dante.js.map +1 -0
  76. data/docs/doc.html +57 -0
  77. data/docs/fonts/dante.eot +0 -0
  78. data/docs/fonts/dante.svg +18 -0
  79. data/docs/fonts/dante.ttf +0 -0
  80. data/docs/fonts/dante.woff +0 -0
  81. data/docs/fonts/fontello.eot +0 -0
  82. data/docs/fonts/fontello.svg +36 -0
  83. data/docs/fonts/fontello.ttf +0 -0
  84. data/docs/fonts/fontello.woff +0 -0
  85. data/docs/images/dante-editor-logo.png +0 -0
  86. data/docs/images/github-logo.png +0 -0
  87. data/docs/index.html +55 -0
  88. data/docs/license.html +52 -0
  89. data/lib/dante2-editor.rb +5 -0
  90. data/lib/dante2-editor/rails.rb +16 -0
  91. data/lib/dante2-editor/version.rb +5 -0
  92. data/package.json +61 -0
  93. data/rakefile +1 -0
  94. data/webpack.config.js +148 -0
  95. data/yarn.lock +4704 -0
  96. metadata +139 -0
@@ -0,0 +1,160 @@
1
+
2
+ React = require('react')
3
+ ReactDOM = require('react-dom')
4
+
5
+ {
6
+ Entity
7
+ RichUtils
8
+ AtomicBlockUtils
9
+ EditorState
10
+ } = require('draft-js')
11
+
12
+ {
13
+ getSelectionRect
14
+ getSelection
15
+ } = require("../../utils/selection.js")
16
+
17
+ {
18
+ getCurrentBlock
19
+ getNode
20
+ } = require('../../model/index.js')
21
+
22
+
23
+ class DanteImagePopover extends React.Component
24
+
25
+ constructor: (props) ->
26
+ super props
27
+
28
+ @state =
29
+ position:
30
+ top: 0
31
+ left:0
32
+ show: false
33
+ scaled: false
34
+ buttons: [
35
+ {type: "left" }
36
+ {type: "center" }
37
+ {type: "fill" }
38
+ {type: "wide" }
39
+ ]
40
+
41
+ display: (b)=>
42
+ if b then @show() else @hide()
43
+
44
+ show: =>
45
+ @setState
46
+ show: true
47
+
48
+ hide: =>
49
+ @setState
50
+ show: false
51
+
52
+ setPosition: (coords)->
53
+ @setState
54
+ position: coords
55
+
56
+ _toggleScaled: (ev)=>
57
+ if @state.scaled then @collapse() else @scale()
58
+
59
+ scale: =>
60
+ @setState
61
+ scaled: true
62
+
63
+ collapse: =>
64
+ @setState
65
+ scaled: false
66
+
67
+ relocate: ()=>
68
+ editorState = @props.editorState
69
+
70
+ if editorState.getSelection().isCollapsed()
71
+
72
+ currentBlock = getCurrentBlock(editorState)
73
+ blockType = currentBlock.getType()
74
+
75
+ contentState = editorState.getCurrentContent()
76
+ selectionState = editorState.getSelection()
77
+
78
+ block = contentState.getBlockForKey(selectionState.anchorKey)
79
+
80
+ nativeSelection = getSelection(window)
81
+ if !nativeSelection.rangeCount
82
+ return;
83
+
84
+ node = getNode()
85
+
86
+ selectionBoundary = getSelectionRect(nativeSelection)
87
+ coords = selectionBoundary
88
+
89
+ parent = ReactDOM.findDOMNode(@props.editor);
90
+ parentBoundary = parent.getBoundingClientRect();
91
+
92
+ @display(blockType is "image")
93
+
94
+ if blockType is "image"
95
+ selectionBoundary = node.anchorNode.parentNode.parentNode.parentNode.getBoundingClientRect()
96
+ el = @refs.image_popover
97
+ padd = el.offsetWidth / 2
98
+ @setPosition
99
+ top: selectionBoundary.top - parentBoundary.top + 60
100
+ left: selectionBoundary.left + (selectionBoundary.width / 2) - padd
101
+
102
+ else
103
+ @hide()
104
+
105
+ componentWillReceiveProps: (newProps)=>
106
+ @collapse()
107
+
108
+ getStyle: ->
109
+ return {} if !@state.position
110
+
111
+ handleClick: (item)=>
112
+ @props.editor.setDirection(item.type)
113
+
114
+ render: ->
115
+ return (
116
+
117
+ <div ref="image_popover"
118
+ className="dante-popover popover--Aligntooltip popover--top popover--animated #{'is-active' if @state.show}"
119
+ style={{top: @state.position.top, left: @state.position.left}}>
120
+
121
+ <div className='popover-inner'>
122
+
123
+ <ul className='dante-menu-buttons'>
124
+
125
+ {
126
+ @state.buttons.map (item, i)=>
127
+ <DanteImagePopoverItem
128
+ item={item}
129
+ handleClick={@handleClick}
130
+ key={i}
131
+ />
132
+ }
133
+
134
+ </ul>
135
+
136
+ </div>
137
+
138
+ <div className='popover-arrow'>
139
+ </div>
140
+ </div>
141
+
142
+ )
143
+
144
+ class DanteImagePopoverItem extends React.Component
145
+
146
+ handleClick: (e)=>
147
+ e.preventDefault()
148
+ @props.handleClick(@props.item)
149
+
150
+ render: =>
151
+ return (
152
+ <li
153
+ className="dante-menu-button align-#{@props.item.type}"
154
+ onMouseDown={@handleClick}>
155
+ <span className="tooltip-icon dante-icon-image-#{@props.item.type}"></span>
156
+ </li>
157
+ )
158
+
159
+ module.exports = DanteImagePopover
160
+
@@ -0,0 +1,87 @@
1
+
2
+ React = require('react')
3
+ ReactDOM = require('react-dom')
4
+
5
+ {
6
+ getCurrentBlock
7
+ } = require('../../model/index.js')
8
+
9
+ class DanteAnchorPopover extends React.Component
10
+
11
+ constructor: (props) ->
12
+
13
+ super props
14
+ @state =
15
+ position:
16
+ top: 0
17
+ left:0
18
+ show: false
19
+ url: ""
20
+
21
+
22
+ display: (b)=>
23
+ if b then @show() else @hide()
24
+
25
+ show: =>
26
+ @setState
27
+ show: true
28
+
29
+ hide: =>
30
+ @setState
31
+ show: false
32
+
33
+ setPosition: (coords)->
34
+ @setState
35
+ position: coords
36
+
37
+ relocate: (node=null)=>
38
+ return unless node
39
+
40
+ editorState = @props.editorState
41
+ currentBlock = getCurrentBlock(editorState)
42
+ blockType = currentBlock.getType()
43
+
44
+ contentState = editorState.getCurrentContent()
45
+ selectionState = editorState.getSelection()
46
+
47
+ selectionBoundary = node.getBoundingClientRect()
48
+ coords = selectionBoundary
49
+
50
+ el = @refs.dante_popover
51
+ padd = el.offsetWidth / 2
52
+
53
+ parent = ReactDOM.findDOMNode(@props.editor);
54
+ parentBoundary = parent.getBoundingClientRect()
55
+
56
+ {
57
+ top: selectionBoundary.top - parentBoundary.top + 160
58
+ left: selectionBoundary.left + (selectionBoundary.width/2) - (padd)
59
+ }
60
+
61
+
62
+ render: =>
63
+ position = @state.position
64
+ style = {
65
+ left: position.left,
66
+ top: position.top,
67
+ visibility: "#{if @state.show then 'visible' else 'hidden'}"
68
+ }
69
+ return (
70
+ <div
71
+ ref="dante_popover"
72
+ className='dante-popover popover--tooltip popover--Linktooltip popover--bottom is-active'
73
+ style={style}
74
+ onMouseOver={@props.handleOnMouseOver}
75
+ onMouseOut={@props.handleOnMouseOut}
76
+ >
77
+ <div className='popover-inner'>
78
+ <a href={@props.url} target='_blank'>
79
+ {@state.url}
80
+ </a>
81
+ </div>
82
+ <div className='popover-arrow'>
83
+ </div>
84
+ </div>
85
+ )
86
+
87
+ module.exports = DanteAnchorPopover
@@ -0,0 +1,326 @@
1
+ React = require('react')
2
+ ReactDOM = require('react-dom')
3
+
4
+ {
5
+ convertToRaw,
6
+ CompositeDecorator,
7
+ getVisibleSelectionRect,
8
+ getDefaultKeyBinding,
9
+ getSelectionOffsetKeyForNode,
10
+ KeyBindingUtil,
11
+ ContentState,
12
+ Editor,
13
+ EditorState,
14
+ Entity,
15
+ RichUtils
16
+ } = require('draft-js')
17
+
18
+ {
19
+ getSelectionRect
20
+ getSelection
21
+ } = require("../../utils/selection.js")
22
+
23
+ {
24
+ getCurrentBlock
25
+ } = require('../../model/index.js')
26
+
27
+
28
+ class DanteTooltip extends React.Component
29
+
30
+ constructor: (props) ->
31
+ super props
32
+ @getVisibleSelectionRect = getVisibleSelectionRect
33
+ @state =
34
+ link_mode: false
35
+ show: false
36
+ position: {}
37
+
38
+ _clickInlineHandler: (ev, style)=>
39
+ ev.preventDefault()
40
+
41
+ @props.onChange(
42
+ RichUtils.toggleInlineStyle(@props.editorState, style)
43
+ )
44
+
45
+ setTimeout ()=>
46
+ @relocate()
47
+ , 0
48
+
49
+ display: (b)=>
50
+ if b then @show() else @hide()
51
+
52
+ show: =>
53
+ @setState
54
+ show: true
55
+
56
+ hide: =>
57
+ @setState
58
+ link_mode: false
59
+ show: false
60
+
61
+ setPosition: (coords)->
62
+ @setState
63
+ position: coords
64
+
65
+
66
+ isDescendant: (parent, child)->
67
+ node = child.parentNode
68
+ while node != null
69
+ if (node is parent)
70
+ return true
71
+ node = node.parentNode
72
+ return false
73
+
74
+ relocate: ()=>
75
+
76
+ currentBlock = getCurrentBlock(@props.editorState);
77
+ blockType = currentBlock.getType()
78
+ # display tooltip only for unstyled
79
+
80
+ if @.props.configTooltip.selectionElements.indexOf(blockType) < 0
81
+ @hide()
82
+ return
83
+
84
+ return if @state.link_mode
85
+ return if !@state.show
86
+
87
+
88
+ el = @refs.dante_menu
89
+ padd = el.offsetWidth / 2
90
+
91
+ nativeSelection = getSelection(window);
92
+ if !nativeSelection.rangeCount
93
+ return
94
+
95
+ selectionBoundary = getSelectionRect(nativeSelection);
96
+
97
+ parent = ReactDOM.findDOMNode(@props.editor);
98
+ parentBoundary = parent.getBoundingClientRect();
99
+
100
+ # hide if selected node is not in editor
101
+ if !@isDescendant(parent, nativeSelection.anchorNode)
102
+ @hide()
103
+ return
104
+
105
+
106
+ top = selectionBoundary.top - parentBoundary.top - -90 - 5
107
+ left = selectionBoundary.left + (selectionBoundary.width / 2) - padd
108
+
109
+ if !top or !left
110
+ return
111
+
112
+ # console.log "SET SHOW FOR TOOLTIP INSERT MENU"
113
+ @setState
114
+ show: true
115
+ position:
116
+ left: left
117
+ top: top
118
+
119
+ _clickBlockHandler: (ev, style)=>
120
+ ev.preventDefault()
121
+
122
+ @props.onChange(
123
+ RichUtils.toggleBlockType(@props.editorState, style)
124
+ )
125
+
126
+ setTimeout ()=>
127
+ @relocate()
128
+ , 0
129
+
130
+ displayLinkMode: =>
131
+ if @state.link_mode then "dante-menu--linkmode" else ""
132
+
133
+ displayActiveMenu: =>
134
+ if @state.show then "dante-menu--active" else ""
135
+
136
+ _enableLinkMode: (ev)=>
137
+ ev.preventDefault()
138
+ @setState
139
+ link_mode: true
140
+
141
+ _disableLinkMode: (ev)=>
142
+ ev.preventDefault()
143
+ @setState
144
+ link_mode: false
145
+ url: ""
146
+
147
+ hideMenu: ->
148
+ @hide()
149
+
150
+ handleInputEnter: (e)=>
151
+ if (e.which is 13)
152
+ return @confirmLink(e)
153
+
154
+ confirmLink: (e)=>
155
+ e.preventDefault()
156
+ editorState = @.props.editorState
157
+ urlValue = e.currentTarget.value
158
+ contentState = editorState.getCurrentContent()
159
+ selection = editorState.getSelection()
160
+
161
+ opts = {
162
+ url: urlValue
163
+ showPopLinkOver: @props.showPopLinkOver
164
+ hidePopLinkOver: @props.hidePopLinkOver
165
+ }
166
+
167
+ entityKey = Entity.create('LINK', 'MUTABLE', opts);
168
+
169
+ if selection.isCollapsed()
170
+ console.log "COLLAPSED SKIPPING LINK"
171
+ return
172
+
173
+ @props.onChange(
174
+ RichUtils.toggleLink(
175
+ editorState,
176
+ selection,
177
+ entityKey
178
+ )
179
+ )
180
+
181
+ @_disableLinkMode(e)
182
+
183
+ getPosition: ->
184
+ pos = @state.position
185
+ pos
186
+
187
+ inlineItems: =>
188
+ @props.widget_options.block_types.filter (o)=>
189
+ o.type is "inline"
190
+
191
+ blockItems: =>
192
+ @props.widget_options.block_types.filter (o)=>
193
+ o.type is "block"
194
+
195
+ getDefaultValue: =>
196
+ @refs.dante_menu_input.value = "" if @refs.dante_menu_input
197
+
198
+ currentBlock = getCurrentBlock(@props.editorState);
199
+ blockType = currentBlock.getType()
200
+ selection = @props.editor.state.editorState.getSelection()
201
+ selectedEntity = null
202
+ defaultUrl = null
203
+ currentBlock.findEntityRanges (character) =>
204
+ entityKey = character.getEntity()
205
+ selectedEntity = entityKey
206
+ return entityKey isnt null && Entity.get(entityKey).getType() is 'LINK'
207
+ , (start, end) =>
208
+ selStart = selection.getAnchorOffset()
209
+ selEnd = selection.getFocusOffset()
210
+ if selection.getIsBackward()
211
+ selStart = selection.getFocusOffset()
212
+ selEnd = selection.getAnchorOffset()
213
+
214
+ if start is selStart && end is selEnd
215
+ defaultUrl = Entity.get(selectedEntity).getData().url
216
+ @refs.dante_menu_input.value = defaultUrl
217
+
218
+ render: ->
219
+ return (
220
+ <div id="dante-menu"
221
+ ref="dante_menu"
222
+ className="dante-menu #{@displayActiveMenu()} #{@displayLinkMode()}"
223
+ style={@getPosition()}>
224
+
225
+ <div className="dante-menu-linkinput">
226
+ <input className="dante-menu-input"
227
+ ref="dante_menu_input"
228
+ placeholder="Paste or type a link"
229
+ onKeyPress={@handleInputEnter}
230
+ defaultValue={@getDefaultValue()}
231
+ />
232
+
233
+ <div className="dante-menu-button"
234
+ onMouseDown={@_disableLinkMode}>
235
+ x
236
+ </div>
237
+ </div>
238
+
239
+ <ul className="dante-menu-buttons">
240
+ {
241
+ @blockItems().map (item, i)=>
242
+ <DanteTooltipItem
243
+ key={i}
244
+ item={item}
245
+ handleClick={@_clickBlockHandler}
246
+ editorState={@props.editorState}
247
+ type={"block"}
248
+ currentStyle={@props.editorState.getCurrentInlineStyle}
249
+ />
250
+ }
251
+ {
252
+ <DanteTooltipLink
253
+ editorState={@props.editorState}
254
+ enableLinkMode={@_enableLinkMode}
255
+ />
256
+ }
257
+ {
258
+ @inlineItems().map (item, i)=>
259
+ <DanteTooltipItem
260
+ key={i}
261
+ item={item}
262
+ type={"inline"}
263
+ editorState={@props.editorState}
264
+ handleClick={@_clickInlineHandler}
265
+ />
266
+ }
267
+ </ul>
268
+ </div>
269
+ )
270
+
271
+ class DanteTooltipItem extends React.Component
272
+
273
+ handleClick: (ev)=>
274
+ @props.handleClick(ev, @props.item.style)
275
+
276
+ activeClass: =>
277
+ if @isActive() then "active" else ""
278
+
279
+ isActive: =>
280
+ if @props.type is "block"
281
+ @activeClassBlock()
282
+ else
283
+ @activeClassInline()
284
+
285
+ activeClassInline: =>
286
+ return unless @props.editorState
287
+ #console.log @props.item
288
+ @props.editorState.getCurrentInlineStyle().has(@props.item.style)
289
+
290
+ activeClassBlock: =>
291
+ #console.log "EDITOR STATE", @props.editorState
292
+ return unless @props.editorState
293
+ selection = @props.editorState.getSelection()
294
+ blockType = @props.editorState
295
+ .getCurrentContent()
296
+ .getBlockForKey(selection.getStartKey())
297
+ .getType()
298
+ @props.item.style is blockType
299
+
300
+ render: =>
301
+ return (
302
+ <li className="dante-menu-button #{@activeClass()}"
303
+ onMouseDown={@handleClick}>
304
+ <i className="dante-icon dante-icon-#{@props.item.label}"
305
+ data-action="bold"></i>
306
+ </li>
307
+ )
308
+
309
+ class DanteTooltipLink extends React.Component
310
+
311
+ promptForLink: (ev)=>
312
+ selection = @props.editorState.getSelection()
313
+ if (!selection.isCollapsed())
314
+ @props.enableLinkMode(ev)
315
+
316
+ render: ->
317
+ return (
318
+ <li className="dante-menu-button"
319
+ onMouseDown={@.promptForLink}>
320
+ <i className="dante-icon icon-createlink"
321
+ data-action="createlink">link</i>
322
+ </li>
323
+ )
324
+
325
+
326
+ module.exports = DanteTooltip