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,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