dante-editor-seo 0.0.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +40 -0
- data/.ruby-version +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +23 -0
- data/Gemfile.lock +140 -0
- data/Procfile +1 -0
- data/README.md +187 -0
- data/ROADMAP.md +10 -0
- data/TODO.md +30 -0
- data/app/assets/fonts/dante/dante.eot +0 -0
- data/app/assets/fonts/dante/dante.svg +14 -0
- data/app/assets/fonts/dante/dante.ttf +0 -0
- data/app/assets/fonts/dante/dante.woff +0 -0
- data/app/assets/fonts/dante/fontello.eot +0 -0
- data/app/assets/fonts/dante/fontello.svg +36 -0
- data/app/assets/fonts/dante/fontello.ttf +0 -0
- data/app/assets/fonts/dante/fontello.woff +0 -0
- data/app/assets/images/dante/media-loading-placeholder.png +0 -0
- data/app/assets/javascripts/dante/dante.js.coffee.erb +10 -0
- data/app/assets/javascripts/dante/editor.js.coffee +1250 -0
- data/app/assets/javascripts/dante/menu.js.coffee +216 -0
- data/app/assets/javascripts/dante/popover.js.coffee +75 -0
- data/app/assets/javascripts/dante/tooltip.js.coffee +82 -0
- data/app/assets/javascripts/dante/tooltip_widget.js.coffee +10 -0
- data/app/assets/javascripts/dante/tooltip_widgets/embed.js.coffee +60 -0
- data/app/assets/javascripts/dante/tooltip_widgets/extract.js.coffee +64 -0
- data/app/assets/javascripts/dante/tooltip_widgets/uploader.js.coffee +248 -0
- data/app/assets/javascripts/dante/utils.js.coffee +235 -0
- data/app/assets/javascripts/dante/view.js.coffee +101 -0
- data/app/assets/javascripts/dante.js +12 -0
- data/app/assets/stylesheets/dante/_animations.scss +54 -0
- data/app/assets/stylesheets/dante/_caption.scss +52 -0
- data/app/assets/stylesheets/dante/_debug.scss +11 -0
- data/app/assets/stylesheets/dante/_fonts.scss +17 -0
- data/app/assets/stylesheets/dante/_graf.scss +238 -0
- data/app/assets/stylesheets/dante/_icons.scss +57 -0
- data/app/assets/stylesheets/dante/_media.scss +39 -0
- data/app/assets/stylesheets/dante/_menu.scss +153 -0
- data/app/assets/stylesheets/dante/_needsorder.scss +209 -0
- data/app/assets/stylesheets/dante/_popover.scss +134 -0
- data/app/assets/stylesheets/dante/_post.scss +69 -0
- data/app/assets/stylesheets/dante/_scaffold.scss +20 -0
- data/app/assets/stylesheets/dante/_tooltip.scss +131 -0
- data/app/assets/stylesheets/dante/_utilities.scss +55 -0
- data/app/assets/stylesheets/dante/_variables.scss +46 -0
- data/app/assets/stylesheets/dante.scss +18 -0
- data/bower.json +44 -0
- data/config.rb +86 -0
- data/config.ru +42 -0
- data/dante-editor.gemspec +19 -0
- data/dist/css/dante-editor.css +1116 -0
- data/dist/fonts/dante/dante.eot +0 -0
- data/dist/fonts/dante/dante.svg +14 -0
- data/dist/fonts/dante/dante.ttf +0 -0
- data/dist/fonts/dante/dante.woff +0 -0
- data/dist/fonts/dante/fontello.eot +0 -0
- data/dist/fonts/dante/fontello.svg +36 -0
- data/dist/fonts/dante/fontello.ttf +0 -0
- data/dist/fonts/dante/fontello.woff +0 -0
- data/dist/images/dante/media-loading-placeholder.png +0 -0
- data/dist/js/dante-editor.js +2878 -0
- data/lib/dante-editor/rails.rb +4 -0
- data/lib/dante-editor/version.rb +5 -0
- data/lib/dante-editor.rb +5 -0
- data/license.md +22 -0
- data/rakefile +2 -0
- data/source/assets/images/dante-editor-logo.png +0 -0
- data/source/assets/images/github-logo.png +0 -0
- data/source/assets/javascripts/all.js +3 -0
- data/source/assets/javascripts/dante-editor.js +1 -0
- data/source/assets/javascripts/deps.js +4 -0
- data/source/assets/javascripts/examples/custom_toolbar.js.coffee +30 -0
- data/source/assets/javascripts/spec.js +2 -0
- data/source/assets/javascripts/specs/cleaner.js.coffee +8 -0
- data/source/assets/javascripts/specs/dante_view.js.coffee +74 -0
- data/source/assets/javascripts/specs/editor.js.coffee +78 -0
- data/source/assets/stylesheets/_layout.scss +51 -0
- data/source/assets/stylesheets/_scaffold.scss +8 -0
- data/source/assets/stylesheets/_tooltips.scss +216 -0
- data/source/assets/stylesheets/all.css.scss +5 -0
- data/source/assets/stylesheets/dante-editor.css.scss +1 -0
- data/source/assets/stylesheets/normalize.css +375 -0
- data/source/custom_toolbar.erb +29 -0
- data/source/embeds.html.erb +27 -0
- data/source/icons/dante.json +143 -0
- data/source/icons/embed.svg +13 -0
- data/source/icons/image.svg +13 -0
- data/source/icons/plus.svg +13 -0
- data/source/icons/video.svg +13 -0
- data/source/index.html.erb +18 -0
- data/source/layouts/layout.erb +26 -0
- data/source/layouts/spec.html.erb +22 -0
- data/source/lists.html.erb +18 -0
- data/source/partials/_content.erb +6 -0
- data/source/partials/_example_1.erb +45 -0
- data/source/partials/_example_2.erb +32 -0
- data/source/partials/_example_3.erb +4 -0
- data/source/partials/_lists.erb +13 -0
- data/source/partials/_readme.markdown +24 -0
- data/source/partials/test/_example_1.erb +39 -0
- data/source/tests/dante_view.html.erb +11 -0
- data/source/tests/index.html.erb +39 -0
- data/tmp/.gitkeep +0 -0
- metadata +151 -0
@@ -0,0 +1,248 @@
|
|
1
|
+
utils = Dante.utils
|
2
|
+
|
3
|
+
class Dante.View.TooltipWidget.Uploader extends Dante.View.TooltipWidget
|
4
|
+
|
5
|
+
initialize: (opts={})->
|
6
|
+
#super
|
7
|
+
#@name = "menu-image"
|
8
|
+
@icon = opts.icon || "icon-image"
|
9
|
+
@title = opts.title || "Add an image"
|
10
|
+
@action = opts.action || "menu-image"
|
11
|
+
@current_editor = opts.current_editor
|
12
|
+
|
13
|
+
handleClick: (ev)->
|
14
|
+
@imageSelect(ev)
|
15
|
+
|
16
|
+
insertTemplate: ()->
|
17
|
+
"<figure contenteditable='false' class='graf graf--figure is-defaultValue' name='#{utils.generateUniqueName()}' tabindex='0'>
|
18
|
+
<div style='' class='aspectRatioPlaceholder is-locked'>
|
19
|
+
<div style='padding-bottom: 100%;' class='aspect-ratio-fill'></div>
|
20
|
+
<img src='' data-height='' data-width='' data-image-id='' class='graf-image' data-delayed-src=''>
|
21
|
+
</div>
|
22
|
+
<figcaption contenteditable='true' data-default-value='Type caption for image (optional)' class='imageCaption'>
|
23
|
+
<span class='defaultValue'>Type caption for image (optional)</span>
|
24
|
+
<br>
|
25
|
+
</figcaption>
|
26
|
+
</figure>"
|
27
|
+
|
28
|
+
#UPLOADER
|
29
|
+
#replace existing img tag , and wrap it in insertTamplate
|
30
|
+
#TODO: take the url and upload it
|
31
|
+
uploadExistentImage: (image_element, opts = {})->
|
32
|
+
|
33
|
+
utils.log ("process image here!")
|
34
|
+
tmpl = $(@insertTemplate())
|
35
|
+
tmpl.find("img").attr('src', @current_editor.default_loading_placeholder )
|
36
|
+
#is a child element or a first level element ?
|
37
|
+
|
38
|
+
if $(image_element).parents(".graf").length > 0
|
39
|
+
#return if its already wrapped in graf--figure
|
40
|
+
if $(image_element).parents(".graf").hasClass("graf--figure")
|
41
|
+
return
|
42
|
+
utils.log "UNO"
|
43
|
+
tmpl.insertBefore( $(image_element).parents(".graf") )
|
44
|
+
node = @current_editor.getNode()
|
45
|
+
if node
|
46
|
+
@current_editor.preCleanNode($(node))
|
47
|
+
@current_editor.addClassesToElement(node)
|
48
|
+
else
|
49
|
+
utils.log "DOS"
|
50
|
+
img = $(image_element).parentsUntil(".section-inner").first()
|
51
|
+
$(img).replaceWith(tmpl)
|
52
|
+
|
53
|
+
utils.log $("[name='#{tmpl.attr('name')}']").attr("name")
|
54
|
+
@replaceImg(image_element, $("[name='#{tmpl.attr('name')}']"))
|
55
|
+
|
56
|
+
#in case we found that graf--image is nested element, unwrap * nested times
|
57
|
+
n = $("[name='#{tmpl.attr('name')}']").parentsUntil(".section-inner").length
|
58
|
+
unless n is 0
|
59
|
+
for i in [0..n-1] by 1
|
60
|
+
$("[name='#{tmpl.attr('name')}']").unwrap()
|
61
|
+
|
62
|
+
utils.log "FIG"
|
63
|
+
#utils.log $("[name='#{tmpl.attr('name')}']").attr("name")
|
64
|
+
|
65
|
+
replaceImg: (image_element, figure)->
|
66
|
+
utils.log figure.attr("name")
|
67
|
+
utils.log figure
|
68
|
+
$(image_element).remove()
|
69
|
+
img = new Image()
|
70
|
+
img.src = image_element.src
|
71
|
+
self = this
|
72
|
+
img.onload = ()->
|
73
|
+
utils.log "replace image with loaded info"
|
74
|
+
utils.log figure.attr("name")
|
75
|
+
utils.log(this.width + 'x' + this.height);
|
76
|
+
|
77
|
+
ar = self.getAspectRatio(this.width, this.height)
|
78
|
+
#debugger
|
79
|
+
figure.find(".aspectRatioPlaceholder").css
|
80
|
+
'max-width': ar.width
|
81
|
+
'max-height': ar.height
|
82
|
+
|
83
|
+
figure.find(".graf-image").attr
|
84
|
+
"data-height": this.height
|
85
|
+
"data-width": this.width
|
86
|
+
|
87
|
+
figure.find(".aspect-ratio-fill").css
|
88
|
+
"padding-bottom": "#{ar.ratio}%"
|
89
|
+
|
90
|
+
#TODO: upload file to server
|
91
|
+
#@uploadFile file, replaced_node
|
92
|
+
|
93
|
+
figure.find("img").attr("src", image_element.src)
|
94
|
+
|
95
|
+
displayAndUploadImages: (file)->
|
96
|
+
@displayCachedImage file
|
97
|
+
|
98
|
+
imageSelect: (ev)->
|
99
|
+
$selectFile = $('<input type="file" multiple="multiple">').click()
|
100
|
+
self = @
|
101
|
+
$selectFile.change ()->
|
102
|
+
t = this
|
103
|
+
self.uploadFiles(t.files)
|
104
|
+
|
105
|
+
displayCachedImage: (file)->
|
106
|
+
@current_editor.tooltip_view.hide()
|
107
|
+
|
108
|
+
reader = new FileReader()
|
109
|
+
reader.onload = (e)=>
|
110
|
+
img = new Image
|
111
|
+
img.src = e.target.result
|
112
|
+
node = @current_editor.getNode()
|
113
|
+
self = this
|
114
|
+
img.onload = ()->
|
115
|
+
new_tmpl = $(self.insertTemplate())
|
116
|
+
|
117
|
+
replaced_node = $( new_tmpl ).insertBefore($(node))
|
118
|
+
|
119
|
+
img_tag = new_tmpl.find('img.graf-image').attr('src', e.target.result)
|
120
|
+
img_tag.height = this.height
|
121
|
+
img_tag.width = this.width
|
122
|
+
|
123
|
+
utils.log "UPLOADED SHOW FROM CACHE"
|
124
|
+
|
125
|
+
ar = self.getAspectRatio(this.width, this.height)
|
126
|
+
|
127
|
+
replaced_node.find(".aspectRatioPlaceholder").css
|
128
|
+
'max-width': ar.width
|
129
|
+
'max-height': ar.height
|
130
|
+
|
131
|
+
replaced_node.find(".graf-image").attr
|
132
|
+
"data-height": this.height
|
133
|
+
"data-width": this.width
|
134
|
+
|
135
|
+
replaced_node.find(".aspect-ratio-fill").css
|
136
|
+
"padding-bottom": "#{ar.ratio}%"
|
137
|
+
|
138
|
+
self.uploadFile file, replaced_node
|
139
|
+
|
140
|
+
reader.readAsDataURL(file)
|
141
|
+
|
142
|
+
getAspectRatio: (w , h)->
|
143
|
+
maxWidth = 700
|
144
|
+
maxHeight = 700
|
145
|
+
ratio = 0
|
146
|
+
width = w # Current image width
|
147
|
+
height = h # Current image height
|
148
|
+
|
149
|
+
# Check if the current width is larger than the max
|
150
|
+
if width > maxWidth
|
151
|
+
ratio = maxWidth / width # get ratio for scaling image
|
152
|
+
height = height * ratio # Reset height to match scaled image
|
153
|
+
width = width * ratio # Reset width to match scaled image
|
154
|
+
|
155
|
+
# Check if current height is larger than max
|
156
|
+
else if height > maxHeight
|
157
|
+
ratio = maxHeight / height # get ratio for scaling image
|
158
|
+
width = width * ratio # Reset width to match scaled image
|
159
|
+
height = height * ratio # Reset height to match scaled image
|
160
|
+
|
161
|
+
fill_ratio = height / width * 100
|
162
|
+
result = { width: width, height: height, ratio: fill_ratio }
|
163
|
+
utils.log result
|
164
|
+
result
|
165
|
+
|
166
|
+
formatData: (file, upload_params)->
|
167
|
+
formData = new FormData()
|
168
|
+
formData.append('file', file)
|
169
|
+
formData.append('upload_params', upload_params)
|
170
|
+
return formData
|
171
|
+
|
172
|
+
uploadFiles: (files)=>
|
173
|
+
acceptedTypes =
|
174
|
+
"image/png": true
|
175
|
+
"image/jpeg": true
|
176
|
+
"image/gif": true
|
177
|
+
|
178
|
+
i = 0
|
179
|
+
while i < files.length
|
180
|
+
file = files[i]
|
181
|
+
if acceptedTypes[file.type] is true
|
182
|
+
$(@placeholder).append "<progress class=\"progress\" min=\"0\" max=\"100\" value=\"0\">0</progress>"
|
183
|
+
@displayAndUploadImages(file)
|
184
|
+
i++
|
185
|
+
|
186
|
+
uploadFile: (file, node)=>
|
187
|
+
n = node
|
188
|
+
handleUp = (jqxhr)=>
|
189
|
+
@uploadCompleted jqxhr, n
|
190
|
+
|
191
|
+
$.ajax
|
192
|
+
type: "post"
|
193
|
+
url: @current_editor.upload_url
|
194
|
+
xhr: =>
|
195
|
+
xhr = new XMLHttpRequest()
|
196
|
+
xhr.upload.onprogress = @updateProgressBar
|
197
|
+
xhr
|
198
|
+
cache: false
|
199
|
+
contentType: false
|
200
|
+
|
201
|
+
success: (response) =>
|
202
|
+
response = @current_editor.upload_callback(response) if @current_editor.upload_callback
|
203
|
+
handleUp(response)
|
204
|
+
return
|
205
|
+
error: (jqxhr)=>
|
206
|
+
utils.log("ERROR: got error uploading file #{jqxhr.responseText}")
|
207
|
+
|
208
|
+
processData: false
|
209
|
+
data: @formatData(file, @upload_params)
|
210
|
+
|
211
|
+
updateProgressBar: (e)=>
|
212
|
+
$progress = $('.progress:first', this.$el)
|
213
|
+
complete = ""
|
214
|
+
|
215
|
+
if (e.lengthComputable)
|
216
|
+
complete = e.loaded / e.total * 100
|
217
|
+
complete = complete ? complete : 0
|
218
|
+
#$progress.attr('value', complete)
|
219
|
+
#$progress.html(complete)
|
220
|
+
utils.log "complete"
|
221
|
+
utils.log complete
|
222
|
+
|
223
|
+
uploadCompleted: (url, node)=>
|
224
|
+
node.find("img").attr("src", url)
|
225
|
+
#return false
|
226
|
+
|
227
|
+
###
|
228
|
+
# Handles the behavior of deleting images when using the backspace key
|
229
|
+
#
|
230
|
+
# @param {Event} e - The backspace event that is being handled
|
231
|
+
# @param {Node} node - The node the backspace was used in, assumed to be from te editor's getNode() function
|
232
|
+
#
|
233
|
+
# @return {Boolean} true if this function handled the backspace event, otherwise false
|
234
|
+
###
|
235
|
+
handleBackspaceKey: (e, node) =>
|
236
|
+
|
237
|
+
#remove graf figure is is selected but not in range (not focus on caption)
|
238
|
+
if $(".is-selected").hasClass("graf--figure") && !anchor_node?
|
239
|
+
utils.log("Replacing selected node")
|
240
|
+
@current_editor.replaceWith("p", $(".is-selected"))
|
241
|
+
|
242
|
+
e.preventDefault() #without this line, the browser may interpret the backspace as a "go pack a page" command
|
243
|
+
|
244
|
+
@current_editor.setRangeAt($(".is-selected")[0])
|
245
|
+
return true
|
246
|
+
|
247
|
+
return false
|
248
|
+
|
@@ -0,0 +1,235 @@
|
|
1
|
+
String.prototype.killWhiteSpace = ()->
|
2
|
+
this.replace(/\s/g, '')
|
3
|
+
|
4
|
+
String.prototype.reduceWhiteSpace = ()->
|
5
|
+
this.replace(/\s+/g, ' ')
|
6
|
+
|
7
|
+
utils = {}
|
8
|
+
window.Dante.utils = utils
|
9
|
+
|
10
|
+
utils.log = (message, force) ->
|
11
|
+
if (window.debugMode || force)
|
12
|
+
#console.log('%cDANTE DEBUGGER: %c' + message, 'font-family:arial,sans-serif;color:#1abf89;line-height:2em;', 'font-family:cursor,monospace;color:#333;');
|
13
|
+
#console.log('%cDANTE DEBUGGER: %c', 'font-family:arial,sans-serif;color:#1abf89;line-height:2em;', 'font-family:cursor,monospace;color:#333;');
|
14
|
+
console.log( message );
|
15
|
+
|
16
|
+
utils.getBase64Image = (img) ->
|
17
|
+
canvas = document.createElement("canvas")
|
18
|
+
canvas.width = img.width
|
19
|
+
canvas.height = img.height
|
20
|
+
ctx = canvas.getContext("2d")
|
21
|
+
ctx.drawImage img, 0, 0
|
22
|
+
dataURL = canvas.toDataURL("image/png")
|
23
|
+
|
24
|
+
# escape data:image prefix
|
25
|
+
# dataURL.replace /^data:image\/(png|jpg);base64,/, ""
|
26
|
+
|
27
|
+
# or just return dataURL
|
28
|
+
return dataURL
|
29
|
+
|
30
|
+
utils.generateUniqueName = ()->
|
31
|
+
Math.random().toString(36).slice(8)
|
32
|
+
|
33
|
+
#http://stackoverflow.com/questions/5605401/insert-link-in-contenteditable-element
|
34
|
+
utils.saveSelection = ()->
|
35
|
+
if window.getSelection
|
36
|
+
sel = window.getSelection()
|
37
|
+
if sel.getRangeAt and sel.rangeCount
|
38
|
+
ranges = []
|
39
|
+
i = 0
|
40
|
+
len = sel.rangeCount
|
41
|
+
|
42
|
+
while i < len
|
43
|
+
ranges.push sel.getRangeAt(i)
|
44
|
+
++i
|
45
|
+
return ranges
|
46
|
+
else return document.selection.createRange() if document.selection and document.selection.createRange
|
47
|
+
null
|
48
|
+
|
49
|
+
utils.restoreSelection = (savedSel) ->
|
50
|
+
if savedSel
|
51
|
+
if window.getSelection
|
52
|
+
sel = window.getSelection()
|
53
|
+
sel.removeAllRanges()
|
54
|
+
i = 0
|
55
|
+
len = savedSel.length
|
56
|
+
|
57
|
+
while i < len
|
58
|
+
sel.addRange savedSel[i]
|
59
|
+
++i
|
60
|
+
else savedSel.select() if document.selection and savedSel.select
|
61
|
+
return
|
62
|
+
|
63
|
+
utils.getNode = ()->
|
64
|
+
range = undefined
|
65
|
+
sel = undefined
|
66
|
+
container = undefined
|
67
|
+
if document.selection and document.selection.createRange
|
68
|
+
|
69
|
+
# IE case
|
70
|
+
range = document.selection.createRange()
|
71
|
+
range.parentElement()
|
72
|
+
else if window.getSelection
|
73
|
+
sel = window.getSelection()
|
74
|
+
if sel.getRangeAt
|
75
|
+
range = sel.getRangeAt(0) if sel.rangeCount > 0
|
76
|
+
else
|
77
|
+
|
78
|
+
# Old WebKit selection object has no getRangeAt, so
|
79
|
+
# create a range from other selection properties
|
80
|
+
range = document.createRange()
|
81
|
+
range.setStart sel.anchorNode, sel.anchorOffset
|
82
|
+
range.setEnd sel.focusNode, sel.focusOffset
|
83
|
+
|
84
|
+
# Handle the case when the selection was selected backwards (from the end to the start in the document)
|
85
|
+
if range.collapsed isnt sel.isCollapsed
|
86
|
+
range.setStart sel.focusNode, sel.focusOffset
|
87
|
+
range.setEnd sel.anchorNode, sel.anchorOffset
|
88
|
+
if range
|
89
|
+
container = range.commonAncestorContainer
|
90
|
+
|
91
|
+
# Check if the container is a text node and return its parent if so
|
92
|
+
(if container.nodeType is 3 then container.parentNode else container)
|
93
|
+
|
94
|
+
#http://stackoverflow.com/questions/12603397/calculate-width-height-of-the-selected-text-javascript
|
95
|
+
utils.getSelectionDimensions = ->
|
96
|
+
sel = document.selection
|
97
|
+
range = undefined
|
98
|
+
width = 0
|
99
|
+
height = 0
|
100
|
+
left = 0
|
101
|
+
top = 0
|
102
|
+
if sel
|
103
|
+
unless sel.type is "Control"
|
104
|
+
range = sel.createRange()
|
105
|
+
width = range.boundingWidth
|
106
|
+
height = range.boundingHeight
|
107
|
+
else if window.getSelection
|
108
|
+
sel = window.getSelection()
|
109
|
+
if sel.rangeCount
|
110
|
+
range = sel.getRangeAt(0).cloneRange()
|
111
|
+
if range.getBoundingClientRect
|
112
|
+
rect = range.getBoundingClientRect()
|
113
|
+
width = rect.right - rect.left
|
114
|
+
height = rect.bottom - rect.top
|
115
|
+
|
116
|
+
width: width
|
117
|
+
height: height
|
118
|
+
top: rect.top
|
119
|
+
left: rect.left
|
120
|
+
|
121
|
+
#http://stackoverflow.com/questions/3972014/get-caret-position-in-contenteditable-div
|
122
|
+
utils.getCaretPosition = (editableDiv) ->
|
123
|
+
caretPos = 0
|
124
|
+
containerEl = null
|
125
|
+
sel = undefined
|
126
|
+
range = undefined
|
127
|
+
if window.getSelection
|
128
|
+
sel = window.getSelection()
|
129
|
+
if sel.rangeCount
|
130
|
+
range = sel.getRangeAt(0)
|
131
|
+
caretPos = range.endOffset if range.commonAncestorContainer.parentNode is editableDiv
|
132
|
+
else if document.selection and document.selection.createRange
|
133
|
+
range = document.selection.createRange()
|
134
|
+
if range.parentElement() is editableDiv
|
135
|
+
tempEl = document.createElement("span")
|
136
|
+
editableDiv.insertBefore tempEl, editableDiv.firstChild
|
137
|
+
tempRange = range.duplicate()
|
138
|
+
tempRange.moveToElementText tempEl
|
139
|
+
tempRange.setEndPoint "EndToEnd", range
|
140
|
+
caretPos = tempRange.text.length
|
141
|
+
caretPos
|
142
|
+
|
143
|
+
#http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
|
144
|
+
utils.isElementInViewport = (el) ->
|
145
|
+
#special bonus for those using jQuery
|
146
|
+
el = el[0] if typeof jQuery is "function" and el instanceof jQuery
|
147
|
+
rect = el.getBoundingClientRect()
|
148
|
+
#or $(window).height()
|
149
|
+
rect.top >= 0 and rect.left >= 0 and rect.bottom <= (window.innerHeight or document.documentElement.clientHeight) and rect.right <= (window.innerWidth or document.documentElement.clientWidth) #or $(window).width()
|
150
|
+
|
151
|
+
#http://brianmhunt.github.io/articles/taming-contenteditable/
|
152
|
+
|
153
|
+
LINE_HEIGHT = 20
|
154
|
+
|
155
|
+
is_caret_at_start_of_node = (node, range) ->
|
156
|
+
# See: http://stackoverflow.com/questions/7451468
|
157
|
+
pre_range = document.createRange()
|
158
|
+
pre_range.selectNodeContents(node)
|
159
|
+
pre_range.setEnd(range.startContainer, range.startOffset)
|
160
|
+
return pre_range.toString().trim().length == 0
|
161
|
+
|
162
|
+
is_caret_at_end_of_node = (node, range) ->
|
163
|
+
post_range = document.createRange()
|
164
|
+
post_range.selectNodeContents(node)
|
165
|
+
post_range.setStart(range.endContainer, range.endOffset)
|
166
|
+
return post_range.toString().trim().length == 0
|
167
|
+
|
168
|
+
$.fn.editableIsCaret = ->
|
169
|
+
return window.getSelection().type == 'Caret'
|
170
|
+
# alt test:
|
171
|
+
# return sel.rangeCount == 1 and sel.getRangeAt(0).collapsed
|
172
|
+
|
173
|
+
$.fn.editableRange = ->
|
174
|
+
# Return the range for the selection
|
175
|
+
sel = window.getSelection()
|
176
|
+
return unless sel.rangeCount > 0
|
177
|
+
return sel.getRangeAt(0)
|
178
|
+
|
179
|
+
$.fn.editableCaretRange = ->
|
180
|
+
return unless @editableIsCaret()
|
181
|
+
return @editableRange()
|
182
|
+
|
183
|
+
$.fn.editableSetRange = (range) ->
|
184
|
+
sel = window.getSelection()
|
185
|
+
sel.removeAllRanges() if sel.rangeCount > 0
|
186
|
+
sel.addRange(range)
|
187
|
+
|
188
|
+
$.fn.editableFocus = (at_start=true) ->
|
189
|
+
return unless @attr('contenteditable')
|
190
|
+
sel = window.getSelection()
|
191
|
+
sel.removeAllRanges() if sel.rangeCount > 0
|
192
|
+
range = document.createRange()
|
193
|
+
range.selectNodeContents(@[0])
|
194
|
+
range.collapse(at_start)
|
195
|
+
sel.addRange(range)
|
196
|
+
|
197
|
+
$.fn.editableCaretAtStart = ->
|
198
|
+
range = @editableRange()
|
199
|
+
return false unless range
|
200
|
+
return is_caret_at_start_of_node(@[0], range)
|
201
|
+
|
202
|
+
$.fn.editableCaretAtEnd = ->
|
203
|
+
range = @editableRange()
|
204
|
+
return false unless range
|
205
|
+
return is_caret_at_end_of_node(@[0], range)
|
206
|
+
|
207
|
+
$.fn.editableCaretOnFirstLine = ->
|
208
|
+
range = @editableRange()
|
209
|
+
return false unless range
|
210
|
+
# At the start of a node, the getClientRects() is [], so we have to
|
211
|
+
# use the getBoundingClientRect (which seems to work).
|
212
|
+
if is_caret_at_start_of_node(@[0], range)
|
213
|
+
return true
|
214
|
+
else if is_caret_at_end_of_node(@[0], range)
|
215
|
+
ctop = @[0].getBoundingClientRect().bottom - LINE_HEIGHT
|
216
|
+
else
|
217
|
+
ctop = range.getClientRects()[0].top
|
218
|
+
etop = @[0].getBoundingClientRect().top
|
219
|
+
return ctop < etop + LINE_HEIGHT
|
220
|
+
|
221
|
+
$.fn.editableCaretOnLastLine = ->
|
222
|
+
range = @editableRange()
|
223
|
+
return false unless range
|
224
|
+
if is_caret_at_end_of_node(@[0], range)
|
225
|
+
return true
|
226
|
+
else if is_caret_at_start_of_node(@[0], range)
|
227
|
+
# We are on the first line.
|
228
|
+
cbtm = @[0].getBoundingClientRect().top + LINE_HEIGHT
|
229
|
+
else
|
230
|
+
cbtm = range.getClientRects()[0].bottom
|
231
|
+
ebtm = @[0].getBoundingClientRect().bottom
|
232
|
+
return cbtm > ebtm - LINE_HEIGHT
|
233
|
+
|
234
|
+
$.fn.exists = ->
|
235
|
+
@.length > 0
|
@@ -0,0 +1,101 @@
|
|
1
|
+
#a very light backbone.view like version
|
2
|
+
|
3
|
+
class Dante.View
|
4
|
+
|
5
|
+
constructor: (opts = {})->
|
6
|
+
@el = opts.el if opts.el
|
7
|
+
@._ensureElement()
|
8
|
+
@initialize.apply(@, arguments)
|
9
|
+
@._ensureEvents()
|
10
|
+
|
11
|
+
initialize: (opts={})->
|
12
|
+
|
13
|
+
events: ->
|
14
|
+
|
15
|
+
render: ()->
|
16
|
+
return @
|
17
|
+
|
18
|
+
remove: ()->
|
19
|
+
@._removeElement()
|
20
|
+
@.stopListening()
|
21
|
+
return @
|
22
|
+
|
23
|
+
_removeElement: ()->
|
24
|
+
@.$el.remove();
|
25
|
+
|
26
|
+
setElement: (element)->
|
27
|
+
#@.undelegateEvents()
|
28
|
+
@._setElement(element)
|
29
|
+
#@.delegateEvents()
|
30
|
+
return @
|
31
|
+
|
32
|
+
setEvent: (opts)->
|
33
|
+
if !_.isEmpty(opts)
|
34
|
+
_.each opts, (f, key)=>
|
35
|
+
key_arr = key.split(" ")
|
36
|
+
|
37
|
+
if _.isFunction(f)
|
38
|
+
func = f
|
39
|
+
else if _.isString(f)
|
40
|
+
func = @[f]
|
41
|
+
else
|
42
|
+
throw "error event needs a function or string"
|
43
|
+
|
44
|
+
element = if key_arr.length > 1 then key_arr.splice(1 , 3).join(" ") else null
|
45
|
+
|
46
|
+
$( @el ).on( key_arr[0], element, _.bind(func, this) )
|
47
|
+
|
48
|
+
_ensureElement: ()->
|
49
|
+
@.setElement(_.result(@, 'el'))
|
50
|
+
|
51
|
+
_ensureEvents: ()->
|
52
|
+
@.setEvent(_.result(@, 'events'))
|
53
|
+
|
54
|
+
_setElement: (el)->
|
55
|
+
@.$el = if el instanceof $ then el else $(el)
|
56
|
+
@.el = @.$el[0]
|
57
|
+
|
58
|
+
|
59
|
+
# Helper function to correctly set up the prototype chain, for subclasses.
|
60
|
+
# Similar to `goog.inherits`, but uses a hash of prototype properties and
|
61
|
+
# class properties to be extended.
|
62
|
+
|
63
|
+
# This is borrowed from Backbone .extend function
|
64
|
+
|
65
|
+
extend = (protoProps, staticProps) ->
|
66
|
+
parent = this
|
67
|
+
child = undefined
|
68
|
+
# The constructor function for the new subclass is either defined by you
|
69
|
+
# (the "constructor" property in your `extend` definition), or defaulted
|
70
|
+
# by us to simply call the parent's constructor.
|
71
|
+
if protoProps and _.has(protoProps, 'constructor')
|
72
|
+
child = protoProps.constructor
|
73
|
+
else
|
74
|
+
|
75
|
+
child = ->
|
76
|
+
parent.apply this, arguments
|
77
|
+
|
78
|
+
# Add static properties to the constructor function, if supplied.
|
79
|
+
_.extend child, parent, staticProps
|
80
|
+
# Set the prototype chain to inherit from `parent`, without calling
|
81
|
+
# `parent`'s constructor function.
|
82
|
+
|
83
|
+
Surrogate = ->
|
84
|
+
@constructor = child
|
85
|
+
return
|
86
|
+
|
87
|
+
Surrogate.prototype = parent.prototype
|
88
|
+
child.prototype = new Surrogate
|
89
|
+
# Add prototype properties (instance properties) to the subclass,
|
90
|
+
# if supplied.
|
91
|
+
if protoProps
|
92
|
+
_.extend child.prototype, protoProps
|
93
|
+
# Set a convenience property in case the parent's prototype is needed
|
94
|
+
# later.
|
95
|
+
child.__super__ = parent.prototype
|
96
|
+
child
|
97
|
+
|
98
|
+
#Set up inheritance for the model, collection, router, view and history.
|
99
|
+
#Dante.View.extend = utils.extend;
|
100
|
+
|
101
|
+
Dante.View.extend = extend
|
@@ -0,0 +1,12 @@
|
|
1
|
+
//Editor components
|
2
|
+
//= require dante/dante
|
3
|
+
//= require dante/utils
|
4
|
+
//= require dante/view
|
5
|
+
//= require dante/editor
|
6
|
+
//= require dante/tooltip_widget
|
7
|
+
//= require dante/tooltip_widgets/uploader
|
8
|
+
//= require dante/tooltip_widgets/embed
|
9
|
+
//= require dante/tooltip_widgets/extract
|
10
|
+
//= require dante/tooltip
|
11
|
+
//= require dante/popover
|
12
|
+
//= require dante/menu
|
@@ -0,0 +1,54 @@
|
|
1
|
+
@-webkit-keyframes pop-upwards {
|
2
|
+
0% {
|
3
|
+
-webkit-transform: matrix(.97, 0, 0, 1, 0, 12);
|
4
|
+
transform: matrix(.97, 0, 0, 1, 0, 12);
|
5
|
+
opacity: 0;
|
6
|
+
}
|
7
|
+
20% {
|
8
|
+
-webkit-transform: matrix(.99, 0, 0, 1, 0, 2);
|
9
|
+
transform: matrix(.99, 0, 0, 1, 0, 2);
|
10
|
+
opacity: .7;
|
11
|
+
}
|
12
|
+
40% {
|
13
|
+
-webkit-transform: matrix(1, 0, 0, 1, 0, -1);
|
14
|
+
transform: matrix(1, 0, 0, 1, 0, -1);
|
15
|
+
opacity: 1;
|
16
|
+
}
|
17
|
+
70% {
|
18
|
+
-webkit-transform: matrix(1, 0, 0, 1, 0, 0);
|
19
|
+
transform: matrix(1, 0, 0, 1, 0, 0);
|
20
|
+
opacity: 1;
|
21
|
+
}
|
22
|
+
100% {
|
23
|
+
-webkit-transform: matrix(1, 0, 0, 1, 0, 0);
|
24
|
+
transform: matrix(1, 0, 0, 1, 0, 0);
|
25
|
+
opacity: 1;
|
26
|
+
}
|
27
|
+
}
|
28
|
+
@keyframes pop-upward {
|
29
|
+
0% {
|
30
|
+
-webkit-transform: matrix(.97, 0, 0, 1, 0, 12);
|
31
|
+
transform: matrix(.97, 0, 0, 1, 0, 12);
|
32
|
+
opacity: 0;
|
33
|
+
}
|
34
|
+
20% {
|
35
|
+
-webkit-transform: matrix(.99, 0, 0, 1, 0, 2);
|
36
|
+
transform: matrix(.99, 0, 0, 1, 0, 2);
|
37
|
+
opacity: .7;
|
38
|
+
}
|
39
|
+
40% {
|
40
|
+
-webkit-transform: matrix(1, 0, 0, 1, 0, -1);
|
41
|
+
transform: matrix(1, 0, 0, 1, 0, -1);
|
42
|
+
opacity: 1;
|
43
|
+
}
|
44
|
+
70% {
|
45
|
+
-webkit-transform: matrix(1, 0, 0, 1, 0, 0);
|
46
|
+
transform: matrix(1, 0, 0, 1, 0, 0);
|
47
|
+
opacity: 1;
|
48
|
+
}
|
49
|
+
100% {
|
50
|
+
-webkit-transform: matrix(1, 0, 0, 1, 0, 0);
|
51
|
+
transform: matrix(1, 0, 0, 1, 0, 0);
|
52
|
+
opacity: 1;
|
53
|
+
}
|
54
|
+
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
.imageCaption {
|
2
|
+
& {
|
3
|
+
position: absolute;
|
4
|
+
left: -172px;
|
5
|
+
width: 150px;
|
6
|
+
top: 0;
|
7
|
+
text-align: right;
|
8
|
+
margin-top: 0;
|
9
|
+
font-family: "freight-text-pro",Georgia,Cambria,"Times New Roman",Times,serif;
|
10
|
+
letter-spacing: 0.01rem;
|
11
|
+
font-weight: 400;
|
12
|
+
font-style: italic;
|
13
|
+
font-size: 14px;
|
14
|
+
line-height: 1.4;
|
15
|
+
color: rgba(0,0,0,0.6);
|
16
|
+
outline: 0;
|
17
|
+
z-index: 300;
|
18
|
+
}
|
19
|
+
&:before {
|
20
|
+
width: 25%;
|
21
|
+
margin-left: 75%;
|
22
|
+
border-top: 1px solid rgba(0,0,0,0.15);
|
23
|
+
display: block;
|
24
|
+
content: "";
|
25
|
+
margin-bottom: 10px;
|
26
|
+
}
|
27
|
+
}
|
28
|
+
@media (max-width: 1200px) {
|
29
|
+
.imageCaption,
|
30
|
+
.postField--outsetCenterImage > .imageCaption {
|
31
|
+
position: relative;
|
32
|
+
width: 100%;
|
33
|
+
text-align: center;
|
34
|
+
left: 0;
|
35
|
+
margin-top: 10px;
|
36
|
+
}
|
37
|
+
.imageCaption:before {
|
38
|
+
display: none;
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
figure.is-defaultValue .imageCaption,
|
43
|
+
.graf--sectionCaption.is-defaultValue {
|
44
|
+
display: none;
|
45
|
+
}
|
46
|
+
|
47
|
+
.graf--figure.is-mediaFocused .imageCaption,
|
48
|
+
.graf--figure.is-defaultValue.is-selected .imageCaption,
|
49
|
+
section.is-mediaFocused .graf--sectionCaption,
|
50
|
+
.graf--sectionCaption.is-defaultValue.is-selected {
|
51
|
+
display: block;
|
52
|
+
}
|