dante2-editor 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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