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,109 @@
1
+
2
+ React = require('react')
3
+ ReactDOM = require('react-dom')
4
+
5
+ {
6
+ Entity,
7
+ RichUtils
8
+ AtomicBlockUtils
9
+ EditorBlock
10
+ } = require('draft-js')
11
+
12
+ axios = require("axios")
13
+
14
+ { updateDataOfBlock } = require('../../model/index.js')
15
+
16
+ class EmbedBlock extends React.Component
17
+ constructor: (props) ->
18
+ super props
19
+ #api_key = "86c28a410a104c8bb58848733c82f840"
20
+
21
+ @state =
22
+ embed_data: @defaultData()
23
+ error: ""
24
+
25
+ defaultData: ->
26
+ existing_data = @.props.block.getData().toJS()
27
+ existing_data.embed_data || {}
28
+
29
+ # will update block state
30
+ updateData: =>
31
+ blockProps = @.props.blockProps
32
+ block = @.props.block
33
+ getEditorState = @props.blockProps.getEditorState
34
+ setEditorState = @props.blockProps.setEditorState
35
+ data = block.getData();
36
+ newData = data.merge(@state)
37
+ setEditorState(updateDataOfBlock(getEditorState(), block, newData))
38
+
39
+ dataForUpdate: =>
40
+
41
+ @.props.blockProps.data.toJS()
42
+
43
+ componentDidMount: =>
44
+
45
+ return unless @.props.blockProps.data
46
+
47
+ # ensure data isnt already loaded
48
+ # unless @dataForUpdate().endpoint or @dataForUpdate().provisory_text
49
+
50
+ unless @dataForUpdate().endpoint or @dataForUpdate().provisory_text
51
+ #debugger
52
+ return
53
+
54
+ axios
55
+ method: 'get'
56
+ url: "#{@dataForUpdate().endpoint}#{@dataForUpdate().provisory_text}&scheme=https"
57
+ .then (result)=>
58
+
59
+ @setState
60
+ embed_data: result.data #JSON.parse(data.responseText)
61
+ , @updateData
62
+ .catch (error)=>
63
+
64
+ @setState
65
+ error: error.response.data.error_message
66
+ console.log("TODO: error")
67
+
68
+ classForImage: ->
69
+ if @state.embed_data.images then "" else "mixtapeImage--empty u-ignoreBlock"
70
+ #if @state.embed_data.thumbnail_url then "" else "mixtapeImage--empty u-ignoreBlock"
71
+
72
+ picture: ->
73
+ if @state.embed_data.images and @state.embed_data.images.length > 0 then @state.embed_data.images[0].url else ""
74
+
75
+ render: ->
76
+ #block = @.props;
77
+ #foo = @.props.blockProps;
78
+ #data = Entity.get(block.block.getEntityAt(0)).getData();
79
+ console.log "ERROR", @state.error
80
+ return(
81
+ <span>
82
+ {
83
+ if @picture()
84
+ <a target='_blank'
85
+ className="js-mixtapeImage mixtapeImage #{@classForImage()}"
86
+ href={@state.embed_data.url}
87
+ style={{backgroundImage: "url('#{@picture()}')"}}>
88
+ </a>
89
+ }
90
+
91
+ {
92
+ if @state.error
93
+ <h2>{@state.error}</h2>
94
+ }
95
+
96
+ <a className='markup--anchor markup--mixtapeEmbed-anchor'
97
+ target='_blank' href={@state.embed_data.url}>
98
+ <strong className='markup--strong markup--mixtapeEmbed-strong'>
99
+ {@state.embed_data.title}
100
+ </strong>
101
+ <em className='markup--em markup--mixtapeEmbed-em'>
102
+ {@state.embed_data.description}
103
+ </em>
104
+ </a>
105
+ {@state.embed_data.provider_url}
106
+ </span>
107
+ )
108
+
109
+ module.exports = EmbedBlock
@@ -0,0 +1,316 @@
1
+ React = require('react')
2
+ ReactDOM = require('react-dom')
3
+
4
+ {
5
+ Entity,
6
+ RichUtils
7
+ AtomicBlockUtils
8
+ EditorBlock
9
+ EditorState
10
+ } = require('draft-js')
11
+
12
+ axios = require("axios")
13
+
14
+ { updateDataOfBlock } = require('../../model/index.js')
15
+
16
+
17
+ class ImageBlock extends React.Component
18
+
19
+ constructor: (props) ->
20
+ super props
21
+
22
+ existing_data = @.props.block.getData().toJS()
23
+
24
+ @config = @props.blockProps.config
25
+ @file = @props.blockProps.data.get('file')
26
+ @state =
27
+ loading: false
28
+ selected: false
29
+ loading_progress: 0
30
+ enabled: false
31
+ caption: @defaultPlaceholder()
32
+ direction: existing_data.direction || "center"
33
+ width: 0
34
+ height: 0
35
+ file: null
36
+ url: @blockPropsSrc() || @defaultUrl(existing_data)
37
+ aspect_ratio: @defaultAspectRatio(existing_data)
38
+
39
+ blockPropsSrc: ()=>
40
+ # console.log @.props.blockProps.data.src
41
+ @.props.blockProps.data.src
42
+ ###
43
+ debugger
44
+ block = @.props;
45
+ entity = block.block.getEntityAt(0)
46
+ if entity
47
+ data = Entity.get(entity).getData().src
48
+ else
49
+ null
50
+ ###
51
+
52
+ defaultUrl: (data)=>
53
+ return data.url if data.url
54
+
55
+ if data.url
56
+ if data.file then URL.createObjectURL(data.file) else data.url
57
+ else
58
+ @props.blockProps.data.src
59
+
60
+ defaultPlaceholder: ->
61
+ @props.blockProps.config.image_caption_placeholder
62
+
63
+ defaultAspectRatio: (data)=>
64
+ if data.aspect_ratio
65
+ width: data.aspect_ratio['width']
66
+ height: data.aspect_ratio['height']
67
+ ratio: data.aspect_ratio['ratio']
68
+ else
69
+ width: 0
70
+ height: 0
71
+ ratio: 100
72
+
73
+ getAspectRatio: (w, h)->
74
+ maxWidth = 1000
75
+ maxHeight = 1000
76
+ ratio = 0
77
+ width = w # Current image width
78
+ height = h # Current image height
79
+
80
+ # Check if the current width is larger than the max
81
+ if width > maxWidth
82
+ ratio = maxWidth / width # get ratio for scaling image
83
+ height = height * ratio # Reset height to match scaled image
84
+ width = width * ratio # Reset width to match scaled image
85
+
86
+ # Check if current height is larger than max
87
+ else if height > maxHeight
88
+ ratio = maxHeight / height # get ratio for scaling image
89
+ width = width * ratio # Reset width to match scaled image
90
+ height = height * ratio # Reset height to match scaled image
91
+
92
+ fill_ratio = height / width * 100
93
+ result = { width: width, height: height, ratio: fill_ratio }
94
+ # console.log result
95
+ result
96
+
97
+ # will update block state
98
+ updateData: =>
99
+ blockProps = @.props.blockProps
100
+ block = @.props.block
101
+ getEditorState = @props.blockProps.getEditorState
102
+ setEditorState = @props.blockProps.setEditorState
103
+ data = block.getData()
104
+ newData = data.merge(@state).merge(forceUpload: false)
105
+ setEditorState(updateDataOfBlock(getEditorState(), block, newData))
106
+
107
+ replaceImg: =>
108
+ @img = new Image();
109
+ @img.src = this.refs.image_tag.src
110
+ @setState
111
+ url: @img.src
112
+ self = @
113
+ # exit only when not blob and not forceUload
114
+ return if !@img.src.includes("blob:") and !@props.block.data.get("forceUpload")
115
+ @img.onload = ()=>
116
+ @setState
117
+ width: @img.width
118
+ height: @img.height
119
+ aspect_ratio: self.getAspectRatio(@img.width, @img.height)
120
+
121
+ @handleUpload()
122
+
123
+ startLoader: =>
124
+ @setState
125
+ loading: true
126
+
127
+ stopLoader: =>
128
+ @setState
129
+ loading: false
130
+
131
+ handleUpload: =>
132
+ @startLoader()
133
+ @props.blockProps.addLock()
134
+ @updateData()
135
+ @uploadFile()
136
+
137
+ componentDidMount: ->
138
+ @replaceImg()
139
+
140
+ aspectRatio: =>
141
+ maxWidth: "#{@state.aspect_ratio.width}"
142
+ maxHeight: "#{@state.aspect_ratio.height}"
143
+ ratio: "#{@state.aspect_ratio.height}"
144
+
145
+ updateDataSelection: =>
146
+ getEditorState = @props.blockProps.getEditorState
147
+ setEditorState = @props.blockProps.setEditorState
148
+ newselection = getEditorState().getSelection().merge(
149
+ anchorKey: @.props.block.getKey()
150
+ focusKey: @.props.block.getKey()
151
+ )
152
+
153
+ setEditorState(
154
+ EditorState.forceSelection(getEditorState(), newselection)
155
+ )
156
+
157
+ handleGrafFigureSelectImg: (e)=>
158
+ e.preventDefault()
159
+ @setState
160
+ selected: true
161
+ , @updateDataSelection
162
+
163
+ #main_editor.onChange(main_editor.state.editorState)
164
+
165
+ coords: ->
166
+ maxWidth: "#{@state.aspect_ratio.width}px"
167
+ maxHeight: "#{@state.aspect_ratio.height}px"
168
+
169
+ getBase64Image: (img) ->
170
+ canvas = document.createElement("canvas")
171
+ canvas.width = img.width
172
+ canvas.height = img.height
173
+ ctx = canvas.getContext("2d")
174
+ ctx.drawImage img, 0, 0
175
+ dataURL = canvas.toDataURL("image/png")
176
+
177
+ return dataURL
178
+
179
+ formatData: ->
180
+ formData = new FormData()
181
+ if @file
182
+ #file = @.props.blockProps.data.get('file')
183
+
184
+ formData.append('file', @file)
185
+ return formData
186
+ else
187
+ formData.append('url',
188
+ @.props.blockProps.data.get("url")
189
+ )
190
+ return formData
191
+
192
+ getUploadUrl: =>
193
+ url = @config.upload_url
194
+ if typeof(url) is "function" then url() else url
195
+
196
+
197
+ uploadFile: =>
198
+ # console.log "FORM DATA:" , @formatData()
199
+ axios
200
+ method: 'post'
201
+ url: @getUploadUrl()
202
+ data: @formatData()
203
+ onUploadProgress: (e)=>
204
+ @updateProgressBar(e)
205
+ .then (result)=>
206
+ @uploadCompleted(result.data)
207
+ @props.blockProps.removeLock()
208
+ @stopLoader()
209
+ @file = null
210
+
211
+ if @config.upload_callback
212
+ @config.upload_callback(response, @)
213
+
214
+ .catch (error)=>
215
+ @props.blockProps.removeLock()
216
+ @stopLoader()
217
+
218
+ console.log("ERROR: got error uploading file #{error}")
219
+ if @config.upload_error_callback
220
+ @config.upload_error_callback(error, @)
221
+
222
+ handleUp = (json_response)=>
223
+ @uploadCompleted json_response, n
224
+
225
+ uploadCompleted: (json)=>
226
+ @setState
227
+ url: json.url
228
+ , @updateData
229
+
230
+ updateProgressBar: (e)=>
231
+ complete = @state.loading_progress
232
+ if (e.lengthComputable)
233
+ complete = e.loaded / e.total * 100
234
+ complete = complete ? complete : 0
235
+ @setState
236
+ loading_progress: complete
237
+ console.log "complete: #{complete}"
238
+
239
+ placeHolderEnabled: =>
240
+ @state.enabled or @.props.block.getText()
241
+
242
+ placeholderText: =>
243
+ return "" if @placeHolderEnabled()
244
+ "Write caption for image (optional)"
245
+
246
+ handleFocus: (e)=>
247
+ # console.log "focus on placeholder"
248
+ setTimeout =>
249
+ @setState
250
+ enabled: true
251
+ , 0
252
+
253
+ render: =>
254
+
255
+ return (
256
+ <div ref="image_tag2"
257
+ suppressContentEditableWarning={true}>
258
+ <div
259
+ className="aspectRatioPlaceholder is-locked"
260
+ style={@coords()}
261
+ onClick={@handleGrafFigureSelectImg}>
262
+ <div style={{paddingBottom: "#{@state.aspect_ratio.ratio}%" }}} className='aspect-ratio-fill'>
263
+ </div>
264
+ <img src={@state.url}
265
+ ref="image_tag"
266
+ height={@state.aspect_ratio.height}
267
+ width={@state.aspect_ratio.width}
268
+ className='graf-image'
269
+ />
270
+ <Loader
271
+ toggle={@state.loading}
272
+ progress={@state.loading_progress}
273
+ />
274
+ </div>
275
+ <figcaption className='imageCaption'
276
+ onMouseDown={@handleFocus}>
277
+
278
+ {
279
+ if !@state.enabled
280
+ <span className="danteDefaultPlaceholder">
281
+ {@placeholderText()}
282
+ </span>
283
+ }
284
+
285
+ <EditorBlock {...@props}
286
+ editable=true
287
+ className="imageCaption"
288
+ />
289
+ </figcaption>
290
+ </div>
291
+ )
292
+
293
+ class Loader extends React.Component
294
+
295
+ render: ->
296
+ return (
297
+ <div>
298
+ { if @props.toggle
299
+ <div className="image-upoader-loader">
300
+ <p>
301
+ {
302
+ if @props.progress is 100
303
+ "processing image..."
304
+ else
305
+ <span>
306
+ <span>loading</span>
307
+ {Math.round @props.progress}
308
+ </span>
309
+ }
310
+ </p>
311
+ </div>
312
+ }
313
+ </div>
314
+ )
315
+
316
+ module.exports = ImageBlock
@@ -0,0 +1,60 @@
1
+
2
+ React = require('react')
3
+ ReactDOM = require('react-dom')
4
+
5
+ {
6
+ Entity,
7
+ RichUtils
8
+ AtomicBlockUtils
9
+ EditorBlock
10
+ } = require('draft-js')
11
+
12
+ #utils = require("../../utils/utils")
13
+
14
+
15
+ class PlaceholderBlock extends React.Component
16
+ constructor: (props) ->
17
+ super props
18
+ @state =
19
+ enabled: false
20
+ data: @.props.blockProps.data.toJS()
21
+
22
+ placeholderText: =>
23
+ return "" if @state.enabled
24
+ @.props.blockProps.data.toJS().placeholder || @placeholderFromProps() || @defaultText()
25
+ #if @.props.blockProps.data then @.props.blockProps.data.placeholder else @defaultText()
26
+
27
+
28
+ placeholderFromProps: =>
29
+ @.props.block.toJS().placeholder
30
+
31
+ defaultText: =>
32
+ "write something "
33
+
34
+ componentDidMount: ->
35
+
36
+ handleFocus: (e)=>
37
+ # console.log "focus on placeholder"
38
+ setTimeout =>
39
+ @setState
40
+ enabled: true
41
+ , 0
42
+
43
+ classForDefault: =>
44
+ if !@state.enabled then "defaultValue defaultValue--root" else ""
45
+
46
+ render: ->
47
+ return(
48
+ <span className={@classForDefault()}
49
+ onMouseDown={@handleFocus}>
50
+
51
+ {@placeholderText()}
52
+
53
+ <EditorBlock {...@props}
54
+ className="imageCaption"
55
+ placeholder="escrive alalal"
56
+ />
57
+ </span>
58
+ )
59
+
60
+ module.exports = PlaceholderBlock