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,8 @@
1
+ // Set box-sizing globally to handle padding and border widths
2
+ *,
3
+ *:before,
4
+ *:after {
5
+ box-sizing: border-box;
6
+ }
7
+
8
+
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Tooltips!
3
+ */
4
+
5
+ $tooltip-arrow-size: 6px;
6
+ $tooltip-arrow-height: $tooltip-arrow-size * 2;
7
+
8
+ /* Base styles for the element that has a tooltip */
9
+ [data-tooltip],
10
+ .tooltip {
11
+ position: relative;
12
+ cursor: pointer;
13
+ }
14
+
15
+ /* Base styles for the entire tooltip */
16
+ [data-tooltip]:before,
17
+ [data-tooltip]:after,
18
+ .tooltip:before,
19
+ .tooltip:after {
20
+ position: absolute;
21
+ visibility: hidden;
22
+ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
23
+ filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
24
+ opacity: 0;
25
+ -webkit-transition:
26
+ opacity 0.2s ease-in-out,
27
+ visibility 0.2s ease-in-out,
28
+ -webkit-transform 0.2s cubic-bezier(0.71, 1.7, 0.77, 1.24);
29
+ -moz-transition:
30
+ opacity 0.2s ease-in-out,
31
+ visibility 0.2s ease-in-out,
32
+ -moz-transform 0.2s cubic-bezier(0.71, 1.7, 0.77, 1.24);
33
+ transition:
34
+ opacity 0.2s ease-in-out,
35
+ visibility 0.2s ease-in-out,
36
+ transform 0.2s cubic-bezier(0.71, 1.7, 0.77, 1.24);
37
+ -webkit-transform: translate3d(0, 0, 0);
38
+ -moz-transform: translate3d(0, 0, 0);
39
+ transform: translate3d(0, 0, 0);
40
+ pointer-events: none;
41
+ }
42
+
43
+ /* Show the entire tooltip on hover and focus */
44
+ [data-tooltip]:hover:before,
45
+ [data-tooltip]:hover:after,
46
+ [data-tooltip]:focus:before,
47
+ [data-tooltip]:focus:after,
48
+ .tooltip:hover:before,
49
+ .tooltip:hover:after,
50
+ .tooltip:focus:before,
51
+ .tooltip:focus:after {
52
+ visibility: visible;
53
+ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
54
+ filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
55
+ opacity: 1;
56
+ }
57
+
58
+ /* Base styles for the tooltip's directional arrow */
59
+ .tooltip:before,
60
+ [data-tooltip]:before {
61
+ z-index: 1001;
62
+ border: $tooltip-arrow-size solid transparent;
63
+ background: transparent;
64
+ content: "";
65
+ }
66
+
67
+ /* Base styles for the tooltip's content area */
68
+ .tooltip:after,
69
+ [data-tooltip]:after {
70
+ white-space: nowrap;
71
+ z-index: 1000;
72
+ padding: 7px 8px;
73
+ background-color: #000;
74
+ background-color: hsla(0, 0%, 20%, 0.9);
75
+ color: #fff;
76
+ content: attr(data-tooltip);
77
+ font-size: 12px;
78
+ line-height: 1.2;
79
+ border-radius: 3px;
80
+ }
81
+
82
+ /* Directions */
83
+
84
+ /* Top (default) */
85
+ [data-tooltip]:before,
86
+ [data-tooltip]:after,
87
+ .tooltip:before,
88
+ .tooltip:after,
89
+ .tooltip-top:before,
90
+ .tooltip-top:after {
91
+ bottom: 100%;
92
+ left: 50%;
93
+ }
94
+
95
+ [data-tooltip]:before,
96
+ .tooltip:before,
97
+ .tooltip-top:before {
98
+ margin-left: -$tooltip-arrow-size;
99
+ margin-bottom: -$tooltip-arrow-height;
100
+ border-top-color: #000;
101
+ border-top-color: hsla(0, 0%, 20%, 0.9);
102
+ }
103
+
104
+ /* Horizontally align top/bottom tooltips */
105
+ [data-tooltip]:after,
106
+ .tooltip:after,
107
+ .tooltip-top:after {
108
+ margin-left: -80px;
109
+ }
110
+
111
+ [data-tooltip]:hover:before,
112
+ [data-tooltip]:hover:after,
113
+ [data-tooltip]:focus:before,
114
+ [data-tooltip]:focus:after,
115
+ .tooltip:hover:before,
116
+ .tooltip:hover:after,
117
+ .tooltip:focus:before,
118
+ .tooltip:focus:after,
119
+ .tooltip-top:hover:before,
120
+ .tooltip-top:hover:after,
121
+ .tooltip-top:focus:before,
122
+ .tooltip-top:focus:after {
123
+ -webkit-transform: translateY(-$tooltip-arrow-height);
124
+ -moz-transform: translateY(-$tooltip-arrow-height);
125
+ transform: translateY(-$tooltip-arrow-height);
126
+ }
127
+
128
+ /* Left */
129
+ .tooltip-left:before,
130
+ .tooltip-left:after {
131
+ right: 100%;
132
+ bottom: 50%;
133
+ left: auto;
134
+ }
135
+
136
+ .tooltip-left:before {
137
+ margin-left: 0;
138
+ margin-right: -$tooltip-arrow-height;
139
+ margin-bottom: 0;
140
+ border-top-color: transparent;
141
+ border-left-color: #000;
142
+ border-left-color: hsla(0, 0%, 20%, 0.9);
143
+ }
144
+
145
+ .tooltip-left:hover:before,
146
+ .tooltip-left:hover:after,
147
+ .tooltip-left:focus:before,
148
+ .tooltip-left:focus:after {
149
+ -webkit-transform: translateX(-$tooltip-arrow-height);
150
+ -moz-transform: translateX(-$tooltip-arrow-height);
151
+ transform: translateX(-$tooltip-arrow-height);
152
+ }
153
+
154
+ /* Bottom */
155
+ .tooltip-bottom:before,
156
+ .tooltip-bottom:after {
157
+ top: 100%;
158
+ bottom: auto;
159
+ left: 50%;
160
+ }
161
+
162
+ .tooltip-bottom:before {
163
+ margin-top: -12px;
164
+ margin-bottom: 0;
165
+ border-top-color: transparent;
166
+ border-bottom-color: #000;
167
+ border-bottom-color: hsla(0, 0%, 20%, 0.9);
168
+ }
169
+
170
+ .tooltip-bottom:hover:before,
171
+ .tooltip-bottom:hover:after,
172
+ .tooltip-bottom:focus:before,
173
+ .tooltip-bottom:focus:after {
174
+ -webkit-transform: translateY($tooltip-arrow-height);
175
+ -moz-transform: translateY($tooltip-arrow-height);
176
+ transform: translateY($tooltip-arrow-height);
177
+ }
178
+
179
+ /* Right */
180
+ .tooltip-right:before,
181
+ .tooltip-right:after {
182
+ bottom: 50%;
183
+ left: 100%;
184
+ }
185
+
186
+ .tooltip-right:before {
187
+ margin-bottom: 0;
188
+ margin-left: -$tooltip-arrow-height;
189
+ border-top-color: transparent;
190
+ border-right-color: #000;
191
+ border-right-color: hsla(0, 0%, 20%, 0.9);
192
+ }
193
+
194
+ .tooltip-right:hover:before,
195
+ .tooltip-right:hover:after,
196
+ .tooltip-right:focus:before,
197
+ .tooltip-right:focus:after {
198
+ -webkit-transform: translateX($tooltip-arrow-height);
199
+ -moz-transform: translateX($tooltip-arrow-height);
200
+ transform: translateX($tooltip-arrow-height);
201
+ }
202
+
203
+ /* Move directional arrows down a bit for left/right tooltips */
204
+ .tooltip-left:before,
205
+ .tooltip-right:before {
206
+ top: 50%;
207
+ margin-top: -$tooltip-arrow-size;
208
+ bottom: auto;
209
+ }
210
+
211
+ /* Vertically center tooltip content for left/right tooltips */
212
+ .tooltip-left:after,
213
+ .tooltip-right:after {
214
+ margin-left: 0;
215
+ margin-bottom: -16px;
216
+ }
@@ -0,0 +1,20 @@
1
+ { Entity } = require('draft-js')
2
+
3
+ findEntities = (entityType, instance, contentBlock, callback)->
4
+ #TODO pass editor prop to link!!!!!
5
+ contentBlock.findEntityRanges (character) =>
6
+ entityKey = character.getEntity()
7
+ return (
8
+ res = entityKey isnt null &&
9
+ Entity.get(entityKey).getType() is entityType
10
+ if res
11
+ opts =
12
+ showPopLinkOver: instance.showPopLinkOver
13
+ hidePopLinkOver: instance.hidePopLinkOver
14
+ Entity.mergeData(entityKey, opts)
15
+ res
16
+ );
17
+ ,
18
+ callback
19
+
20
+ module.exports = findEntities
@@ -0,0 +1,120 @@
1
+ { ContentState
2
+ genKey
3
+ Entity
4
+ CharacterMetadata
5
+ ContentBlock
6
+ convertFromHTML
7
+ getSafeBodyFromHTML
8
+ } = require('draft-js')
9
+
10
+ { List
11
+ OrderedSet
12
+ Repeat
13
+ fromJS
14
+ } = require('immutable')
15
+
16
+
17
+ # { compose
18
+ # } = require('underscore')
19
+
20
+ # underscore compose function
21
+ compose = ->
22
+ args = arguments
23
+ start = args.length - 1
24
+ ->
25
+ i = start
26
+ result = args[start].apply(this, arguments)
27
+ while i--
28
+ result = args[i].call(this, result)
29
+ result
30
+
31
+ # from https://gist.github.com/N1kto/6702e1c2d89a33a15a032c234fc4c34e
32
+
33
+ ###
34
+ # Helpers
35
+ ###
36
+
37
+ # Prepares img meta data object based on img attributes
38
+ getBlockSpecForElement = (imgElement)=>
39
+ contentType: 'image',
40
+ imgSrc: imgElement.getAttribute('src')
41
+
42
+ # Wraps meta data in HTML element which is 'understandable' by Draft, I used <blockquote />.
43
+ wrapBlockSpec = (blockSpec)=>
44
+ if blockSpec == null
45
+ return null
46
+
47
+ tempEl = document.createElement('blockquote')
48
+ # stringify meta data and insert it as text content of temp HTML element. We will later extract
49
+ # and parse it.
50
+ tempEl.innerText = JSON.stringify(blockSpec)
51
+ return tempEl
52
+
53
+ # Replaces <img> element with our temp element
54
+ replaceElement = (oldEl, newEl)=>
55
+ if !(newEl instanceof HTMLElement)
56
+ return
57
+
58
+ upEl = getUpEl(oldEl)
59
+ #parentNode = oldEl.parentNode
60
+ #return parentNode.replaceChild(newEl, oldEl)
61
+ return upEl.parentNode.insertBefore(newEl, upEl);
62
+
63
+ getUpEl = (el)=>
64
+ original_el = el
65
+ while el.parentNode
66
+ if el.parentNode.tagName isnt 'BODY'
67
+ el = el.parentNode
68
+ return el if el.parentNode.tagName is 'BODY'
69
+
70
+ elementToBlockSpecElement = compose(wrapBlockSpec, getBlockSpecForElement)
71
+
72
+ imgReplacer = (imgElement)=>
73
+ replaceElement(imgElement, elementToBlockSpecElement(imgElement))
74
+
75
+ ###
76
+ # Main function
77
+ ###
78
+
79
+ # takes HTML string and returns DraftJS ContentState
80
+ customHTML2Content = (HTML, blockRn)->
81
+ tempDoc = new DOMParser().parseFromString(HTML, 'text/html')
82
+ # replace all <img /> with <blockquote /> elements
83
+
84
+ a = tempDoc.querySelectorAll('img').forEach( (item)->
85
+ return imgReplacer(item)
86
+ )
87
+
88
+ # use DraftJS converter to do initial conversion. I don't provide DOMBuilder and
89
+ # blockRenderMap arguments here since it should fall back to its default ones, which are fine
90
+ console.log tempDoc.body.innerHTML
91
+ contentBlocks = convertFromHTML(tempDoc.body.innerHTML,
92
+ getSafeBodyFromHTML,
93
+ blockRn
94
+ )
95
+
96
+ # now replace <blockquote /> ContentBlocks with 'atomic' ones
97
+ contentBlocks = contentBlocks.map (block)->
98
+ console.log "CHECK BLOCK", block.getType()
99
+ if (block.getType() isnt 'blockquote')
100
+ return block
101
+
102
+ json = ""
103
+ try
104
+ json = JSON.parse(block.getText())
105
+ catch
106
+ return block
107
+
108
+ newBlock = block.merge({
109
+ type: "image",
110
+ text: ""
111
+ data:
112
+ url: json.imgSrc
113
+ forceUpload: true
114
+ });
115
+
116
+ tempDoc = null
117
+ return ContentState.createFromBlockArray(contentBlocks)
118
+
119
+
120
+ module.exports = customHTML2Content
File without changes
@@ -0,0 +1,63 @@
1
+ axios = require("axios")
2
+ Immutable = require('immutable')
3
+
4
+ class SaveBehavior
5
+ constructor: (options)->
6
+ @getLocks = options.getLocks
7
+ @config = options.config
8
+ @editorContent = options.editorContent
9
+ @editorState = options.editorState
10
+
11
+ handleStore: (ev)->
12
+ @store()
13
+
14
+ store: (content)->
15
+ return unless @config.data_storage.url
16
+ return if @getLocks() > 0
17
+
18
+ clearTimeout(@timeout)
19
+
20
+ @timeout = setTimeout =>
21
+ @checkforStore(content)
22
+ , @config.data_storage.interval
23
+
24
+ getTextFromEditor: (content)->
25
+ content.blocks.map (o)=>
26
+ o.text
27
+ .join("\n")
28
+
29
+ getUrl: ->
30
+ url = @config.data_storage.url
31
+ if typeof(url) is "function" then url() else url
32
+
33
+ getMethod: ->
34
+ method = @config.data_storage.method
35
+ if typeof(method) is "function" then method() else method
36
+
37
+
38
+ checkforStore: (content)->
39
+ # ENTER DATA STORE
40
+ isChanged = !Immutable.is(Immutable.fromJS(@.editorContent), Immutable.fromJS(content))
41
+ # console.log("CONTENT CHANGED:", isChanged)
42
+
43
+ return unless isChanged
44
+
45
+ @config.xhr.before_handler() if @config.xhr.before_handler
46
+ # console.log "SAVING TO: #{@getMethod()} #{@getUrl()}"
47
+
48
+ axios
49
+ method: @getMethod()
50
+ url: @getUrl()
51
+ data:
52
+ editor_content: JSON.stringify(content)
53
+ text_content: @getTextFromEditor(content)
54
+ .then (result)=>
55
+ # console.log "STORING CONTENT", result
56
+ @config.data_storage.success_handler(result) if @config.data_storage.success_handler
57
+ @config.xhr.success_handler(result) if @config.xhr.success_handler
58
+ .catch (error)=>
59
+ # console.log("ERROR: got error saving content at #{@config.data_storage.url} - #{error}")
60
+ @config.xhr.failure_handler(error) if @config.xhr.failure_handler
61
+
62
+
63
+ module.exports = SaveBehavior
@@ -0,0 +1,53 @@
1
+ /*
2
+ Returns the `boundingClientRect` of the passed selection.
3
+ */
4
+ export const getSelectionRect = (selected) => {
5
+ const _rect = selected.getRangeAt(0).getBoundingClientRect();
6
+ // selected.getRangeAt(0).getBoundingClientRect()
7
+ let rect = _rect && _rect.top ? _rect : selected.getRangeAt(0).getClientRects()[0];
8
+ if (!rect) {
9
+ if (selected.anchorNode && selected.anchorNode.getBoundingClientRect) {
10
+ rect = selected.anchorNode.getBoundingClientRect();
11
+ rect.isEmptyline = true;
12
+ } else {
13
+ return null;
14
+ }
15
+ }
16
+ return rect;
17
+ };
18
+
19
+ /*
20
+ Returns the native selection node.
21
+ */
22
+ export const getSelection = (root) => {
23
+ let t = null;
24
+ if (root.getSelection) {
25
+ t = root.getSelection();
26
+ } else if (root.document.getSelection) {
27
+ t = root.document.getSelection();
28
+ } else if (root.document.selection) {
29
+ t = root.document.selection.createRange().text;
30
+ }
31
+ return t;
32
+ };
33
+
34
+ /*
35
+ Recursively finds the DOM Element of the block where the cursor is currently present.
36
+ If not found, returns null.
37
+ */
38
+ export const getSelectedBlockNode = (root) => {
39
+ const selection = root.getSelection();
40
+ if (selection.rangeCount === 0) {
41
+ return null;
42
+ }
43
+ let node = selection.getRangeAt(0).startContainer;
44
+ // console.log(node);
45
+ do {
46
+ if (node.getAttribute && node.getAttribute('data-block') === 'true') {
47
+ return node;
48
+ }
49
+ node = node.parentNode;
50
+ // console.log(node);
51
+ } while (node !== null);
52
+ return null;
53
+ };