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,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
+ };