dante-editor 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e5f8c0fc81095096da19c3e387d79bedab7a3ec3
4
- data.tar.gz: f11b2bc0404231a18de30c42b59169ae674db5af
3
+ metadata.gz: b5dcd7a183c79a6f6271bbae21e2a1ec3a615252
4
+ data.tar.gz: 4f54e71e88490742c38c48143f053bb1a12460ce
5
5
  SHA512:
6
- metadata.gz: 61923bfbcb46e98d3314997362b4f13a3041a60e34b8dc97b4ab4c91c8f436a7a7e1c76c751fa3d55148cfe30746c6fd4be68fa7d5479a73f89145ebe03169a4
7
- data.tar.gz: 3bca3b2e85212118e3f6dcb114fa7ed75cca273cc58d75f9cdd1f7843837dd507a69446e679792d696340796071b022e82ba8bfeab6535813f824f473984bc56
6
+ metadata.gz: 0317884b66ddf24193390df958943c6b05594e0304ffaa935571f6b4602362b2319d770ae6cfab7209376d1d25f28817d4619ac776d0fe06485aa7420d4c6a9b
7
+ data.tar.gz: 45458e4453f33a46da6ae21493be5411d6c6e65e70af57df9bd98e4810a802af07d9bed087749b14c30ca715c1575feb5536d98e890ff7e726b259f7ff45d344
data/Gemfile CHANGED
@@ -13,6 +13,7 @@ gem "wdm", "~> 0.1.0", :platforms => [:mswin, :mingw]
13
13
  gem "github-markup"
14
14
  gem "redcarpet"
15
15
  gem "sinatra"
16
+ gem 'sinatra-contrib'
16
17
  gem "pry"
17
18
 
18
19
  gemspec
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  #Dante Editor
2
2
 
3
+ > Hey!, Did you know there is a new version of Dante?, check it out at https://github.com/michelson/dante2
4
+
5
+
3
6
  [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/michelson/Dante?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4
7
 
5
8
  (This library is free and will stay free, but needs your support to sustain its development. There are lots of desirable new features and maintenance to do. If you work for a company using Dante or have the means to do so, please consider financial support)
@@ -10,14 +13,13 @@
10
13
 
11
14
  ##Motivation:
12
15
 
13
- So far I have tried all the Medium.com wysiwyg clones out there, these are really great, and each have their pros and cons. [But none of them has all the features that the real medium editor provides.](http://howtox.com/medium-editor-clones-in-js/)
14
- so I wonder, How complicated could it be to write my own Medium wysiwyg clone?
16
+ So far we have tried all the Medium.com wysiwyg clones out there, those are really great, and each have their pros and cons. [But none of them has all the features that the real medium editor provides.](http://howtox.com/medium-editor-clones-in-js/) So we wondered, How complicated could be write our own version of Medium's wysiwyg?
15
17
 
16
18
  ## Demo:
17
19
 
18
20
  [http://michelson.github.io/Dante/](http://michelson.github.io/Dante/)
19
21
 
20
- Until now I´ve been able to implement the following features:
22
+ Until now We´ve implemented the following features:
21
23
 
22
24
  ## Features:
23
25
 
@@ -89,12 +91,16 @@ Until now I´ve been able to implement the following features:
89
91
  + **store_url:** default: to none , url to store data with interval
90
92
  + **store_method** default: to POST , http verb to use when store_url is present.
91
93
  + **store_success_handler** default: to none. Option to set a function to handle success response for save operation, works only if store_url is present.
94
+ + **failure_xhr_handler**: handles ajax store failure
92
95
  + **store_interval:** default: 1500 (1.5 secs), used when store_url is present.
93
96
 
97
+ + **before_xhr_handler:** default: none, callback for handle beforeSend on **all** ajax calls
98
+ + **success_xhr_handler:** default: none, callback for handle success event on **all** ajax calls
99
+
94
100
  #### Uploader:
95
101
 
96
102
  + **upload_url:** default: /uploads.json
97
- + **upload_callback** default: empty, allows optional way to handle the server response when image is uploaded This is useful when you don't have control on the backend response.
103
+ + **upload_callback:** default: empty, allows optional way to handle the server response when image is uploaded This is useful when you don't have control on the backend response. the callback will return the xhr response , the node and the context. **When this option is empty the default behavior will expect a json response with the url `{url: "path/to/img.jpg"}`** (before 0.1.8 the expected reponse was a string containing the url)
98
104
  + **image_delete_callback**: default: none, returns the image data before deletion. use this if you want to destroy image from the server.
99
105
  + **image_caption_placeholder** default: "Type caption for image (optional)"
100
106
 
@@ -136,6 +142,11 @@ in Gemfile
136
142
 
137
143
  ```gem "dante-editor"```
138
144
 
145
+ Sanitize.js and Underscore.js are Dante dependencies- If you don't already have those installed, add those to your gemfile as well.
146
+
147
+ ```gem 'underscore-rails'```
148
+ ```gem 'rails-sanitize-js'```
149
+
139
150
  ### stylesheets:
140
151
 
141
152
  ```@import "dante";```
@@ -144,6 +155,9 @@ in Gemfile
144
155
 
145
156
  ```//= require 'dante'```
146
157
 
158
+ If you just added the Underscore.js and Sanitize.js gems, add this as well:
159
+ ```//= require sanitize```
160
+ ```//= require underscore```
147
161
 
148
162
  ## Donate
149
163
 
@@ -16,13 +16,26 @@ class Dante.View.Behavior.Save extends Dante.View.Behavior
16
16
  store: ()->
17
17
  return unless @editor.store_url
18
18
  utils.log "HANDLE DATA STORE"
19
+
19
20
  clearTimeout(@timeout)
21
+
20
22
  @timeout = setTimeout =>
21
23
  @checkforStore()
22
24
  , @editor.store_interval
23
25
 
26
+ getLocks: ->
27
+ @editor.locks
28
+
24
29
  checkforStore: ()->
25
30
  utils.log "ENTER DATA STORE"
31
+
32
+ return unless @editor.store_url
33
+
34
+ # check upload in progress
35
+ if @getLocks() > 0
36
+ Debug "LOCKED!!"
37
+ return if @getLocks() > 0
38
+
26
39
  if @content is @editor.getContent()
27
40
  utils.log "content not changed skip store"
28
41
  @store()
@@ -35,6 +48,12 @@ class Dante.View.Behavior.Save extends Dante.View.Behavior
35
48
  dataType: "json"
36
49
  data:
37
50
  body: @editor.getContent()
51
+ beforeSend: (res)=>
52
+ @editor.before_xhr_handler(res) if @editor.before_xhr_handler
38
53
  success: (res)=>
39
54
  utils.log "STORING CONTENT"
40
55
  @editor.store_success_handler(res) if @editor.store_success_handler
56
+ @editor.success_xhr_handler(res) if @editor.success_xhr_handler
57
+ error: (status)=>
58
+ utils.log "FAIL STORING CONTENT"
59
+ @editor.failure_xhr_handler(status) if @editor.failure_xhr_handler
@@ -57,14 +57,20 @@ class Dante.View.Behavior.Suggest extends Dante.View.Behavior
57
57
  method: "get"
58
58
  dataType: "json"
59
59
  #data: { "#{@editor.suggest_query_param}": q }
60
- .success (data)=>
61
- if @editor.suggest_handler
62
- @fetch_results = @editor.suggest_handler(data)
63
- else
64
- @fetch_results = data
65
- cb(e) if cb
66
- .error (data, err)=>
67
- console.log "error fetching results"
60
+ beforeSend: (res)=>
61
+ @editor.before_xhr_handler(res) if @editor.before_xhr_handler
62
+ success: (data)=>
63
+ if @editor.suggest_handler
64
+ @fetch_results = @editor.suggest_handler(data)
65
+ else
66
+ @fetch_results = data
67
+ cb(e) if cb
68
+
69
+ @editor.success_xhr_handler(data) if @editor.success_xhr_handler
70
+
71
+ error: (data, err)=>
72
+ console.log "error fetching results"
73
+
68
74
  , @editor.suggest_query_timeout
69
75
 
70
76
  insideQuery: ()->
@@ -49,6 +49,9 @@ class Dante.Editor extends Dante.View
49
49
  @store_url = opts.store_url
50
50
  @store_method = opts.store_method || "POST"
51
51
  @store_success_handler = opts.store_success_handler
52
+ @before_xhr_handler = opts.before_xhr_handler
53
+ @success_xhr_handler = opts.success_xhr_handler
54
+ @failure_xhr_handler = opts.failure_xhr_handler
52
55
 
53
56
  @spell_check = opts.spellcheck || false
54
57
  @disable_title = opts.disable_title || false
@@ -71,6 +74,8 @@ class Dante.Editor extends Dante.View
71
74
  @behaviors = []
72
75
  @popovers = []
73
76
 
77
+ @locks = 0
78
+
74
79
  window.debugMode = opts.debug || false
75
80
 
76
81
  $(@el).addClass("debug") if window.debugMode
@@ -46,7 +46,7 @@ class Dante.Editor.Menu extends Dante.View
46
46
  if item == "divider"
47
47
  html += "<li class='dante-menu-divider'></li>"
48
48
  else
49
- html += "<li class='dante-menu-button'><i class=\"dante-icon icon-#{item}\" data-action=\"#{item}\"></i></li>"
49
+ html += "<li class='dante-menu-button'><i class=\"dante-icon dante-icon-#{item}\" data-action=\"#{item}\"></i></li>"
50
50
 
51
51
  html += "</ul>"
52
52
  html
@@ -202,15 +202,15 @@ class Dante.Editor.Menu extends Dante.View
202
202
  utils.log "nothing to select"
203
203
 
204
204
  if tag.match /(?:h[1-6])/i
205
- @toggleMenuButtons(@el, ".icon-bold, .icon-italic")
205
+ @toggleMenuButtons(@el, ".dante-icon-bold, .dante-icon-italic")
206
206
 
207
207
  else if tag is "indent"
208
- @toggleMenuButtons(@el, ".icon-h3, .icon-h4, .icon-blockquote")
208
+ @toggleMenuButtons(@el, ".dante-icon-h3, .dante-icon-h4, .dante-icon-blockquote")
209
209
 
210
210
  @highlight(tag)
211
211
 
212
212
  highlight: (tag)->
213
- $(".icon-#{tag}").parent("li").addClass("active")
213
+ $(".dante-icon-#{tag}").parent("li").addClass("active")
214
214
 
215
215
  toggleMenuButtons: (el,buttons)->
216
216
  $(el).find(buttons).parent("li").addClass("dante-menu-button--disabled")
@@ -32,9 +32,9 @@ class Dante.Editor.ImageTooltip extends Dante.Editor.PopOver
32
32
  handleActiveClass: ->
33
33
  @findElement().find(".dante-menu-button").removeClass("active")
34
34
  if @findSelectedImage().hasClass("graf--layoutOutsetLeft")
35
- @findElement().find(".icon-image-left").parent().addClass("active")
35
+ @findElement().find(".dante-icon-image-left").parent().addClass("active")
36
36
  else
37
- @findElement().find(".icon-image-center").parent().addClass("active")
37
+ @findElement().find(".dante-icon-image-center").parent().addClass("active")
38
38
 
39
39
  activateLink: (element)->
40
40
  setTimeout =>
@@ -53,19 +53,19 @@ class Dante.Editor.ImageTooltip extends Dante.Editor.PopOver
53
53
  <ul class='dante-menu-buttons'>
54
54
 
55
55
  <li class='dante-menu-button align-left'>
56
- <span class='tooltip-icon icon-image-left'></span>
56
+ <span class='tooltip-icon dante-icon-image-left'></span>
57
57
  </li>
58
58
 
59
59
  <li class='dante-menu-button align-wide hidden'>
60
- <span class='tooltip-icon icon-image-wide'></span>
60
+ <span class='tooltip-icon dante-icon-image-wide'></span>
61
61
  </li>
62
62
 
63
63
  <li class='dante-menu-button align-fill hidden'>
64
- <span class='tooltip-icon icon-image-fill'></span>
64
+ <span class='tooltip-icon dante-icon-image-fill'></span>
65
65
  </li>
66
66
 
67
67
  <li class='dante-menu-button align-center'>
68
- <span class='tooltip-icon icon-image-center'></span>
68
+ <span class='tooltip-icon dante-icon-image-center'></span>
69
69
  </li>
70
70
 
71
71
  </ul>
@@ -53,7 +53,9 @@ class Dante.Editor.PopOverTypeAhead extends Dante.Editor.PopOver
53
53
  data = $(ev.currentTarget).data()
54
54
  $(".markup--query").replaceWith(@linkTemplate(data))
55
55
  @hide(0)
56
- #@setRangeAt(new_paragraph[0])
56
+ # save content to server
57
+ @editor.save_behavior.store()
58
+
57
59
 
58
60
  linkTemplate: (data)->
59
61
  "<a href='#'
@@ -17,11 +17,11 @@ class Dante.Editor.Tooltip extends Dante.View
17
17
  _.each @widgets, (b)->
18
18
  data_action_value = if b.action_value then "data-action-value='#{b.action_value}'" else ""
19
19
  menu += "<button class='inlineTooltip-button scale' title='#{b.title}' data-action='inline-menu-#{b.action}' #{data_action_value}>
20
- <span class='tooltip-icon #{b.icon}'></span>
20
+ <span class='tooltip-icon dante-#{b.icon}'></span>
21
21
  </button>"
22
22
 
23
23
  "<button class='inlineTooltip-button control' title='Close Menu' data-action='inline-menu'>
24
- <span class='tooltip-icon icon-plus'></span>
24
+ <span class='tooltip-icon dante-icon-plus'></span>
25
25
  </button>
26
26
  <div class='inlineTooltip-menu'>
27
27
  #{menu}
@@ -40,7 +40,7 @@ class Dante.View.TooltipWidget.Embed extends Dante.View.TooltipWidget
40
40
  getEmbedFromNode: (node)=>
41
41
  @node = $(node)
42
42
  @node_name = @node.attr("name")
43
- @node.addClass("spinner")
43
+ @node.addClass("dante--spinner")
44
44
  url = "#{@current_editor.oembed_url}#{$(@node).text()}&scheme=https"
45
45
  $.getJSON(url)
46
46
  .success (data)=>
@@ -56,5 +56,5 @@ class Dante.View.TooltipWidget.Embed extends Dante.View.TooltipWidget
56
56
  replaced_node.find(".markup--anchor").attr("href", url ).text(url)
57
57
  @hide()
58
58
  .error (res)=>
59
- @node.removeClass("spinner")
59
+ @node.removeClass("dante--spinner")
60
60
 
@@ -46,7 +46,7 @@ class Dante.View.TooltipWidget.EmbedExtract extends Dante.View.TooltipWidget
46
46
  getExtractFromNode: (node)=>
47
47
  @node = $(node)
48
48
  @node_name = @node.attr("name")
49
- @node.addClass("spinner")
49
+ @node.addClass("dante--spinner")
50
50
 
51
51
  $.getJSON("#{@current_editor.extract_url}#{$(@node).text()}")
52
52
  .success (data)=>
@@ -66,7 +66,7 @@ class Dante.View.TooltipWidget.EmbedExtract extends Dante.View.TooltipWidget
66
66
  image_node.removeClass("mixtapeImage--empty u-ignoreBlock")
67
67
  @hide()
68
68
  .error (data)=>
69
- @node.removeClass("spinner")
69
+ @node.removeClass("dante--spinner")
70
70
 
71
71
  getExtract: (url)=>
72
72
  $.getJSON("#{@current_editor.extract_url}#{url}").done (data)->
@@ -183,8 +183,8 @@ class Dante.View.TooltipWidget.Uploader extends Dante.View.TooltipWidget
183
183
 
184
184
  uploadFile: (file, node)=>
185
185
  n = node
186
- handleUp = (jqxhr)=>
187
- @uploadCompleted jqxhr, n
186
+ handleUp = (json_response)=>
187
+ @uploadCompleted json_response, n
188
188
 
189
189
  $.ajax
190
190
  type: "post"
@@ -196,11 +196,24 @@ class Dante.View.TooltipWidget.Uploader extends Dante.View.TooltipWidget
196
196
  cache: false
197
197
  contentType: false
198
198
 
199
+ beforeSend: (res)=>
200
+ @current_editor.locks += 1
201
+
202
+ @current_editor.before_xhr_handler(res) if @current_editor.before_xhr_handler
203
+
199
204
  success: (response) =>
200
- response = @current_editor.upload_callback(response) if @current_editor.upload_callback
201
- handleUp(response)
205
+ @current_editor.locks -= 1
206
+
207
+ if @current_editor.upload_callback
208
+ @current_editor.upload_callback(response, n, @)
209
+ else
210
+ handleUp(response)
211
+
212
+ @current_editor.success_xhr_handler(response) if @current_editor.success_xhr_handler
213
+
202
214
  return
203
- error: (jqxhr)=>
215
+ error: (jqxhr, status)=>
216
+ @current_editor.locks -= 1
204
217
  utils.log("ERROR: got error uploading file #{jqxhr.responseText}")
205
218
 
206
219
  processData: false
@@ -218,42 +231,8 @@ class Dante.View.TooltipWidget.Uploader extends Dante.View.TooltipWidget
218
231
  utils.log "complete"
219
232
  utils.log complete
220
233
 
221
- uploadCompleted: (url, node)=>
234
+ uploadCompleted: (json, node)=>
222
235
  node.find("img")
223
- .attr("src", url)
224
- .data("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 should scape the default behavior
234
- ###
235
- handleBackspaceKey: (e, node) =>
236
- # this is not needed here since we are handling backspace for images in image behavior
237
- ###
238
- utils.log "handleBackspaceKey on uploader widget"
239
-
240
- # remove graf figure if is selected but not in range (not focus on caption)
241
- if $(node).hasClass("is-selected") && $(node).hasClass("graf--figure")
242
- # exit if selection is on caption
243
- anchor_node = @current_editor.selection().anchorNode
244
-
245
- # return false unless backspace is in the first char
246
- if ( anchor_node? && $(anchor_node.parentNode).hasClass("imageCaption"))
247
- if @current_editor.isFirstChar()
248
- return true
249
- else
250
- return false
251
-
252
- else if $(".is-selected").hasClass("is-mediaFocused")
253
- # assume that select node is the current media element
254
- # if it's focused when backspace it means that it should be removed
255
- utils.log("Replacing selected node")
256
- @current_editor.replaceWith("p", $(".is-selected"))
257
- @current_editor.setRangeAt($(".is-selected")[0])
258
- return true
259
- ###
236
+ .attr("src", json.url)
237
+ .data("src", json.url)
238
+ #return false
@@ -24,7 +24,7 @@
24
24
  margin-bottom: 30px;
25
25
  }
26
26
 
27
- .graf--p.spinner{
27
+ .graf--p.dante--spinner{
28
28
  position:relative;
29
29
  }
30
30
 
@@ -12,25 +12,25 @@
12
12
  }
13
13
  }
14
14
 
15
- .icon-h2:before { content: ""; }
16
- .icon-h3:before { content: "H1"; }
17
- .icon-h4:before { content: "H2"; }
18
- .icon-p:before { content: "P"; }
19
- .icon-code:before { content: ""; }
20
- .icon-insertorderedlist:before { content: ""; }
21
- .icon-insertunorderedlist:before { content: ""; }
22
- .icon-inserthorizontalrule:before { content: ""; }
23
- .icon-indent:before { content: ""; }
24
- .icon-outdent:before { content: ""; }
25
- .icon-bold:before { content: ""; }
26
- .icon-italic:before { content: ""; }
27
- .icon-underline:before { content: ""; }
28
- .icon-createlink:before { content: ""; }
29
- .icon-blockquote:before { content: ""; }
15
+ .dante-icon-h2:before { content: ""; }
16
+ .dante-icon-h3:before { content: "H1"; }
17
+ .dante-icon-h4:before { content: "H2"; }
18
+ .dante-icon-p:before { content: "P"; }
19
+ .dante-icon-code:before { content: ""; }
20
+ .dante-icon-insertorderedlist:before { content: ""; }
21
+ .dante-icon-insertunorderedlist:before { content: ""; }
22
+ .dante-icon-inserthorizontalrule:before { content: ""; }
23
+ .dante-icon-indent:before { content: ""; }
24
+ .dante-icon-outdent:before { content: ""; }
25
+ .dante-icon-bold:before { content: ""; }
26
+ .dante-icon-italic:before { content: ""; }
27
+ .dante-icon-underline:before { content: ""; }
28
+ .dante-icon-createlink:before { content: ""; }
29
+ .dante-icon-blockquote:before { content: ""; }
30
30
 
31
- .icon-h2:before,
32
- .icon-h3:before,
33
- .icon-h4:before {
31
+ .dante-icon-h2:before,
32
+ .dante-icon-h3:before,
33
+ .dante-icon-h4:before {
34
34
  font-weight: bold;
35
35
  }
36
36
 
@@ -50,13 +50,13 @@
50
50
  }
51
51
  }
52
52
 
53
- .icon-image-center:before { content: "\e900"; }
54
- .icon-image-fill:before { content: "\e901"; }
55
- .icon-image-left:before { content: "\e902"; }
56
- .icon-image-wide:before { content: "\e903"; }
53
+ .dante-icon-image-center:before { content: "\e900"; }
54
+ .dante-icon-image-fill:before { content: "\e901"; }
55
+ .dante-icon-image-left:before { content: "\e902"; }
56
+ .dante-icon-image-wide:before { content: "\e903"; }
57
57
 
58
- .icon-video:before { content: "\e600"; }
59
- .icon-image:before { content: "\e601"; }
60
- .icon-plus:before { content: "\e602"; }
61
- .icon-embed:before { content: "\e603"; }
58
+ .dante-icon-video:before { content: "\e600"; }
59
+ .dante-icon-image:before { content: "\e601"; }
60
+ .dante-icon-plus:before { content: "\e602"; }
61
+ .dante-icon-embed:before { content: "\e603"; }
62
62
 
@@ -115,6 +115,7 @@
115
115
  text-align: center;
116
116
  color: $dante-menu-icon-color;
117
117
  cursor: pointer;
118
+ vertical-align: top;
118
119
  font-size: $dante-menu-icon-size;
119
120
  line-height: $dante-menu-height;
120
121
  //height: $menu-button-height;
@@ -29,12 +29,12 @@
29
29
  to {-webkit-transform: rotate(360deg);}
30
30
  }
31
31
 
32
- .spinner {
32
+ .dante--spinner {
33
33
  min-width: 24px;
34
34
  min-height: 24px;
35
35
  }
36
36
 
37
- .spinner:before {
37
+ .dante--spinner:before {
38
38
  content: 'Loading…';
39
39
  position: absolute;
40
40
  top: 50%;
@@ -45,7 +45,7 @@
45
45
  margin-left: -10px;
46
46
  }
47
47
 
48
- .spinner:not(:required):before {
48
+ .dante--spinner:not(:required):before {
49
49
  content: '';
50
50
  border-radius: 50%;
51
51
  border: 2px solid rgba(0, 0, 0, .3);
data/config.ru CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'middleman/rack'
3
+ require "sinatra/base"
4
+ require "sinatra/json"
3
5
 
4
6
  class UploadServer < Sinatra::Base
5
7
 
@@ -11,14 +13,15 @@ class UploadServer < Sinatra::Base
11
13
 
12
14
  # Handle POST-request (Receive and save the uploaded file)
13
15
  post "/new.?:format?" do
14
-
16
+ content_type :json
17
+
15
18
  name = [Time.now.to_i , params['file'][:filename]].join("-")
16
19
  path = File.join(File.dirname(__FILE__), 'tmp/images', name)
17
20
  File.open(path, "wb") do |f|
18
21
  f.write(params['file'][:tempfile].read)
19
22
  end
20
23
 
21
- return "/uploads/images/#{name}"
24
+ json :url=> "/uploads/images/#{name}"
22
25
  end
23
26
 
24
27
  end
@@ -21,11 +21,11 @@
21
21
  @-webkit-keyframes spinner {
22
22
  to {
23
23
  -webkit-transform: rotate(360deg); } }
24
- .spinner {
24
+ .dante--spinner {
25
25
  min-width: 24px;
26
26
  min-height: 24px; }
27
27
 
28
- .spinner:before {
28
+ .dante--spinner:before {
29
29
  content: 'Loading…';
30
30
  position: absolute;
31
31
  top: 50%;
@@ -35,7 +35,7 @@
35
35
  margin-top: -10px;
36
36
  margin-left: -10px; }
37
37
 
38
- .spinner:not(:required):before {
38
+ .dante--spinner:not(:required):before {
39
39
  content: '';
40
40
  border-radius: 50%;
41
41
  border: 2px solid rgba(0, 0, 0, 0.3);
@@ -201,54 +201,54 @@
201
201
  text-decoration: inherit;
202
202
  text-transform: none; }
203
203
 
204
- .icon-h2:before {
204
+ .dante-icon-h2:before {
205
205
  content: ""; }
206
206
 
207
- .icon-h3:before {
207
+ .dante-icon-h3:before {
208
208
  content: "H1"; }
209
209
 
210
- .icon-h4:before {
210
+ .dante-icon-h4:before {
211
211
  content: "H2"; }
212
212
 
213
- .icon-p:before {
213
+ .dante-icon-p:before {
214
214
  content: "P"; }
215
215
 
216
- .icon-code:before {
216
+ .dante-icon-code:before {
217
217
  content: ""; }
218
218
 
219
- .icon-insertorderedlist:before {
219
+ .dante-icon-insertorderedlist:before {
220
220
  content: ""; }
221
221
 
222
- .icon-insertunorderedlist:before {
222
+ .dante-icon-insertunorderedlist:before {
223
223
  content: ""; }
224
224
 
225
- .icon-inserthorizontalrule:before {
225
+ .dante-icon-inserthorizontalrule:before {
226
226
  content: ""; }
227
227
 
228
- .icon-indent:before {
228
+ .dante-icon-indent:before {
229
229
  content: ""; }
230
230
 
231
- .icon-outdent:before {
231
+ .dante-icon-outdent:before {
232
232
  content: ""; }
233
233
 
234
- .icon-bold:before {
234
+ .dante-icon-bold:before {
235
235
  content: ""; }
236
236
 
237
- .icon-italic:before {
237
+ .dante-icon-italic:before {
238
238
  content: ""; }
239
239
 
240
- .icon-underline:before {
240
+ .dante-icon-underline:before {
241
241
  content: ""; }
242
242
 
243
- .icon-createlink:before {
243
+ .dante-icon-createlink:before {
244
244
  content: ""; }
245
245
 
246
- .icon-blockquote:before {
246
+ .dante-icon-blockquote:before {
247
247
  content: ""; }
248
248
 
249
- .icon-h2:before,
250
- .icon-h3:before,
251
- .icon-h4:before {
249
+ .dante-icon-h2:before,
250
+ .dante-icon-h3:before,
251
+ .dante-icon-h4:before {
252
252
  font-weight: bold; }
253
253
 
254
254
  .tooltip-icon:before {
@@ -262,28 +262,28 @@
262
262
  -webkit-font-smoothing: antialiased;
263
263
  -moz-osx-font-smoothing: grayscale; }
264
264
 
265
- .icon-image-center:before {
265
+ .dante-icon-image-center:before {
266
266
  content: "\e900"; }
267
267
 
268
- .icon-image-fill:before {
268
+ .dante-icon-image-fill:before {
269
269
  content: "\e901"; }
270
270
 
271
- .icon-image-left:before {
271
+ .dante-icon-image-left:before {
272
272
  content: "\e902"; }
273
273
 
274
- .icon-image-wide:before {
274
+ .dante-icon-image-wide:before {
275
275
  content: "\e903"; }
276
276
 
277
- .icon-video:before {
277
+ .dante-icon-video:before {
278
278
  content: "\e600"; }
279
279
 
280
- .icon-image:before {
280
+ .dante-icon-image:before {
281
281
  content: "\e601"; }
282
282
 
283
- .icon-plus:before {
283
+ .dante-icon-plus:before {
284
284
  content: "\e602"; }
285
285
 
286
- .icon-embed:before {
286
+ .dante-icon-embed:before {
287
287
  content: "\e603"; }
288
288
 
289
289
  .dante-menu {
@@ -359,6 +359,7 @@
359
359
  text-align: center;
360
360
  color: #FFFFFF;
361
361
  cursor: pointer;
362
+ vertical-align: top;
362
363
  font-size: 16px;
363
364
  line-height: 42px;
364
365
  -webkit-user-select: none;
@@ -695,7 +696,7 @@
695
696
  .graf--pullquote {
696
697
  margin-bottom: 30px; }
697
698
 
698
- .graf--p.spinner {
699
+ .graf--p.dante--spinner {
699
700
  position: relative; }
700
701
 
701
702
  .graf--h2 {
@@ -9,7 +9,7 @@
9
9
  defaults: {
10
10
  image_placeholder: '../images/dante/media-loading-placeholder.png'
11
11
  },
12
- version: "0.1.7"
12
+ version: "0.1.8"
13
13
  };
14
14
 
15
15
  }).call(this);
@@ -504,6 +504,9 @@
504
504
  this.store_url = opts.store_url;
505
505
  this.store_method = opts.store_method || "POST";
506
506
  this.store_success_handler = opts.store_success_handler;
507
+ this.before_xhr_handler = opts.before_xhr_handler;
508
+ this.success_xhr_handler = opts.success_xhr_handler;
509
+ this.failure_xhr_handler = opts.failure_xhr_handler;
507
510
  this.spell_check = opts.spellcheck || false;
508
511
  this.disable_title = opts.disable_title || false;
509
512
  this.store_interval = opts.store_interval || 1500;
@@ -520,6 +523,7 @@
520
523
  this.widgets = [];
521
524
  this.behaviors = [];
522
525
  this.popovers = [];
526
+ this.locks = 0;
523
527
  window.debugMode = opts.debug || false;
524
528
  if (window.debugMode) {
525
529
  $(this.el).addClass("debug");
@@ -2376,8 +2380,21 @@
2376
2380
  })(this), this.editor.store_interval);
2377
2381
  };
2378
2382
 
2383
+ Save.prototype.getLocks = function() {
2384
+ return this.editor.locks;
2385
+ };
2386
+
2379
2387
  Save.prototype.checkforStore = function() {
2380
2388
  utils.log("ENTER DATA STORE");
2389
+ if (!this.editor.store_url) {
2390
+ return;
2391
+ }
2392
+ if (this.getLocks() > 0) {
2393
+ Debug("LOCKED!!");
2394
+ }
2395
+ if (this.getLocks() > 0) {
2396
+ return;
2397
+ }
2381
2398
  if (this.content === this.editor.getContent()) {
2382
2399
  utils.log("content not changed skip store");
2383
2400
  return this.store();
@@ -2391,11 +2408,29 @@
2391
2408
  data: {
2392
2409
  body: this.editor.getContent()
2393
2410
  },
2411
+ beforeSend: (function(_this) {
2412
+ return function(res) {
2413
+ if (_this.editor.before_xhr_handler) {
2414
+ return _this.editor.before_xhr_handler(res);
2415
+ }
2416
+ };
2417
+ })(this),
2394
2418
  success: (function(_this) {
2395
2419
  return function(res) {
2396
2420
  utils.log("STORING CONTENT");
2397
2421
  if (_this.editor.store_success_handler) {
2398
- return _this.editor.store_success_handler(res);
2422
+ _this.editor.store_success_handler(res);
2423
+ }
2424
+ if (_this.editor.success_xhr_handler) {
2425
+ return _this.editor.success_xhr_handler(res);
2426
+ }
2427
+ };
2428
+ })(this),
2429
+ error: (function(_this) {
2430
+ return function(status) {
2431
+ utils.log("FAIL STORING CONTENT");
2432
+ if (_this.editor.failure_xhr_handler) {
2433
+ return _this.editor.failure_xhr_handler(status);
2399
2434
  }
2400
2435
  };
2401
2436
  })(this)
@@ -2492,18 +2527,28 @@
2492
2527
  return _this.json_request = $.ajax({
2493
2528
  url: "" + _this.editor.suggest_url + "?" + _this.editor.suggest_query_param + "=" + q,
2494
2529
  method: "get",
2495
- dataType: "json"
2496
- }).success(function(data) {
2497
- if (_this.editor.suggest_handler) {
2498
- _this.fetch_results = _this.editor.suggest_handler(data);
2499
- } else {
2500
- _this.fetch_results = data;
2501
- }
2502
- if (cb) {
2503
- return cb(e);
2530
+ dataType: "json",
2531
+ beforeSend: function(res) {
2532
+ if (_this.editor.before_xhr_handler) {
2533
+ return _this.editor.before_xhr_handler(res);
2534
+ }
2535
+ },
2536
+ success: function(data) {
2537
+ if (_this.editor.suggest_handler) {
2538
+ _this.fetch_results = _this.editor.suggest_handler(data);
2539
+ } else {
2540
+ _this.fetch_results = data;
2541
+ }
2542
+ if (cb) {
2543
+ cb(e);
2544
+ }
2545
+ if (_this.editor.success_xhr_handler) {
2546
+ return _this.editor.success_xhr_handler(data);
2547
+ }
2548
+ },
2549
+ error: function(data, err) {
2550
+ return console.log("error fetching results");
2504
2551
  }
2505
- }).error(function(data, err) {
2506
- return console.log("error fetching results");
2507
2552
  });
2508
2553
  };
2509
2554
  })(this), this.editor.suggest_query_timeout);
@@ -2608,7 +2653,6 @@
2608
2653
  __extends(Uploader, _super);
2609
2654
 
2610
2655
  function Uploader() {
2611
- this.handleBackspaceKey = __bind(this.handleBackspaceKey, this);
2612
2656
  this.uploadCompleted = __bind(this.uploadCompleted, this);
2613
2657
  this.updateProgressBar = __bind(this.updateProgressBar, this);
2614
2658
  this.uploadFile = __bind(this.uploadFile, this);
@@ -2808,8 +2852,8 @@
2808
2852
  var handleUp, n;
2809
2853
  n = node;
2810
2854
  handleUp = (function(_this) {
2811
- return function(jqxhr) {
2812
- return _this.uploadCompleted(jqxhr, n);
2855
+ return function(json_response) {
2856
+ return _this.uploadCompleted(json_response, n);
2813
2857
  };
2814
2858
  })(this);
2815
2859
  return $.ajax({
@@ -2825,16 +2869,30 @@
2825
2869
  })(this),
2826
2870
  cache: false,
2827
2871
  contentType: false,
2872
+ beforeSend: (function(_this) {
2873
+ return function(res) {
2874
+ _this.current_editor.locks += 1;
2875
+ if (_this.current_editor.before_xhr_handler) {
2876
+ return _this.current_editor.before_xhr_handler(res);
2877
+ }
2878
+ };
2879
+ })(this),
2828
2880
  success: (function(_this) {
2829
2881
  return function(response) {
2882
+ _this.current_editor.locks -= 1;
2830
2883
  if (_this.current_editor.upload_callback) {
2831
- response = _this.current_editor.upload_callback(response);
2884
+ _this.current_editor.upload_callback(response, n, _this);
2885
+ } else {
2886
+ handleUp(response);
2887
+ }
2888
+ if (_this.current_editor.success_xhr_handler) {
2889
+ _this.current_editor.success_xhr_handler(response);
2832
2890
  }
2833
- handleUp(response);
2834
2891
  };
2835
2892
  })(this),
2836
2893
  error: (function(_this) {
2837
- return function(jqxhr) {
2894
+ return function(jqxhr, status) {
2895
+ _this.current_editor.locks -= 1;
2838
2896
  return utils.log("ERROR: got error uploading file " + jqxhr.responseText);
2839
2897
  };
2840
2898
  })(this),
@@ -2857,45 +2915,8 @@
2857
2915
  }
2858
2916
  };
2859
2917
 
2860
- Uploader.prototype.uploadCompleted = function(url, node) {
2861
- return node.find("img").attr("src", url).data("src", url);
2862
- };
2863
-
2864
-
2865
- /*
2866
- * Handles the behavior of deleting images when using the backspace key
2867
- *
2868
- * @param {Event} e - The backspace event that is being handled
2869
- * @param {Node} node - The node the backspace was used in, assumed to be from te editor's getNode() function
2870
- *
2871
- * @return {Boolean} true if this function should scape the default behavior
2872
- */
2873
-
2874
- Uploader.prototype.handleBackspaceKey = function(e, node) {
2875
-
2876
- /*
2877
- utils.log "handleBackspaceKey on uploader widget"
2878
-
2879
- * remove graf figure if is selected but not in range (not focus on caption)
2880
- if $(node).hasClass("is-selected") && $(node).hasClass("graf--figure")
2881
- * exit if selection is on caption
2882
- anchor_node = @current_editor.selection().anchorNode
2883
-
2884
- * return false unless backspace is in the first char
2885
- if ( anchor_node? && $(anchor_node.parentNode).hasClass("imageCaption"))
2886
- if @current_editor.isFirstChar()
2887
- return true
2888
- else
2889
- return false
2890
-
2891
- else if $(".is-selected").hasClass("is-mediaFocused")
2892
- * assume that select node is the current media element
2893
- * if it's focused when backspace it means that it should be removed
2894
- utils.log("Replacing selected node")
2895
- @current_editor.replaceWith("p", $(".is-selected"))
2896
- @current_editor.setRangeAt($(".is-selected")[0])
2897
- return true
2898
- */
2918
+ Uploader.prototype.uploadCompleted = function(json, node) {
2919
+ return node.find("img").attr("src", json.url).data("src", json.url);
2899
2920
  };
2900
2921
 
2901
2922
  return Uploader;
@@ -2957,7 +2978,7 @@
2957
2978
  var url;
2958
2979
  this.node = $(node);
2959
2980
  this.node_name = this.node.attr("name");
2960
- this.node.addClass("spinner");
2981
+ this.node.addClass("dante--spinner");
2961
2982
  url = "" + this.current_editor.oembed_url + ($(this.node).text()) + "&scheme=https";
2962
2983
  return $.getJSON(url).success((function(_this) {
2963
2984
  return function(data) {
@@ -2976,7 +2997,7 @@
2976
2997
  };
2977
2998
  })(this)).error((function(_this) {
2978
2999
  return function(res) {
2979
- return _this.node.removeClass("spinner");
3000
+ return _this.node.removeClass("dante--spinner");
2980
3001
  };
2981
3002
  })(this));
2982
3003
  };
@@ -3040,7 +3061,7 @@
3040
3061
  EmbedExtract.prototype.getExtractFromNode = function(node) {
3041
3062
  this.node = $(node);
3042
3063
  this.node_name = this.node.attr("name");
3043
- this.node.addClass("spinner");
3064
+ this.node.addClass("dante--spinner");
3044
3065
  return $.getJSON("" + this.current_editor.extract_url + ($(this.node).text())).success((function(_this) {
3045
3066
  return function(data) {
3046
3067
  var iframe_src, image_node, replaced_node, tmpl;
@@ -3063,7 +3084,7 @@
3063
3084
  };
3064
3085
  })(this)).error((function(_this) {
3065
3086
  return function(data) {
3066
- return _this.node.removeClass("spinner");
3087
+ return _this.node.removeClass("dante--spinner");
3067
3088
  };
3068
3089
  })(this));
3069
3090
  };
@@ -3119,9 +3140,9 @@
3119
3140
  _.each(this.widgets, function(b) {
3120
3141
  var data_action_value;
3121
3142
  data_action_value = b.action_value ? "data-action-value='" + b.action_value + "'" : "";
3122
- return menu += "<button class='inlineTooltip-button scale' title='" + b.title + "' data-action='inline-menu-" + b.action + "' " + data_action_value + "> <span class='tooltip-icon " + b.icon + "'></span> </button>";
3143
+ return menu += "<button class='inlineTooltip-button scale' title='" + b.title + "' data-action='inline-menu-" + b.action + "' " + data_action_value + "> <span class='tooltip-icon dante-" + b.icon + "'></span> </button>";
3123
3144
  });
3124
- return "<button class='inlineTooltip-button control' title='Close Menu' data-action='inline-menu'> <span class='tooltip-icon icon-plus'></span> </button> <div class='inlineTooltip-menu'> " + menu + " </div>";
3145
+ return "<button class='inlineTooltip-button control' title='Close Menu' data-action='inline-menu'> <span class='tooltip-icon dante-icon-plus'></span> </button> <div class='inlineTooltip-menu'> " + menu + " </div>";
3125
3146
  };
3126
3147
 
3127
3148
  Tooltip.prototype.findWidgetByAction = function(name) {
@@ -3461,9 +3482,9 @@
3461
3482
  ImageTooltip.prototype.handleActiveClass = function() {
3462
3483
  this.findElement().find(".dante-menu-button").removeClass("active");
3463
3484
  if (this.findSelectedImage().hasClass("graf--layoutOutsetLeft")) {
3464
- return this.findElement().find(".icon-image-left").parent().addClass("active");
3485
+ return this.findElement().find(".dante-icon-image-left").parent().addClass("active");
3465
3486
  } else {
3466
- return this.findElement().find(".icon-image-center").parent().addClass("active");
3487
+ return this.findElement().find(".dante-icon-image-center").parent().addClass("active");
3467
3488
  }
3468
3489
  };
3469
3490
 
@@ -3480,7 +3501,7 @@
3480
3501
  };
3481
3502
 
3482
3503
  ImageTooltip.prototype.template = function() {
3483
- return "<div class='dante-popover popover--Aligntooltip popover--top'> <div class='popover-inner'> <ul class='dante-menu-buttons'> <li class='dante-menu-button align-left'> <span class='tooltip-icon icon-image-left'></span> </li> <li class='dante-menu-button align-wide hidden'> <span class='tooltip-icon icon-image-wide'></span> </li> <li class='dante-menu-button align-fill hidden'> <span class='tooltip-icon icon-image-fill'></span> </li> <li class='dante-menu-button align-center'> <span class='tooltip-icon icon-image-center'></span> </li> </ul> </div> <div class='popover-arrow'> </div> </div>";
3504
+ return "<div class='dante-popover popover--Aligntooltip popover--top'> <div class='popover-inner'> <ul class='dante-menu-buttons'> <li class='dante-menu-button align-left'> <span class='tooltip-icon dante-icon-image-left'></span> </li> <li class='dante-menu-button align-wide hidden'> <span class='tooltip-icon dante-icon-image-wide'></span> </li> <li class='dante-menu-button align-fill hidden'> <span class='tooltip-icon dante-icon-image-fill'></span> </li> <li class='dante-menu-button align-center'> <span class='tooltip-icon dante-icon-image-center'></span> </li> </ul> </div> <div class='popover-arrow'> </div> </div>";
3484
3505
  };
3485
3506
 
3486
3507
  ImageTooltip.prototype.positionPopOver = function(target) {
@@ -3573,7 +3594,8 @@
3573
3594
  console.log("Select option here!");
3574
3595
  data = $(ev.currentTarget).data();
3575
3596
  $(".markup--query").replaceWith(this.linkTemplate(data));
3576
- return this.hide(0);
3597
+ this.hide(0);
3598
+ return this.editor.save_behavior.store();
3577
3599
  };
3578
3600
 
3579
3601
  PopOverTypeAhead.prototype.linkTemplate = function(data) {
@@ -3726,7 +3748,7 @@
3726
3748
  if (item === "divider") {
3727
3749
  return html += "<li class='dante-menu-divider'></li>";
3728
3750
  } else {
3729
- return html += "<li class='dante-menu-button'><i class=\"dante-icon icon-" + item + "\" data-action=\"" + item + "\"></i></li>";
3751
+ return html += "<li class='dante-menu-button'><i class=\"dante-icon dante-icon-" + item + "\" data-action=\"" + item + "\"></i></li>";
3730
3752
  }
3731
3753
  });
3732
3754
  html += "</ul>";
@@ -3919,9 +3941,9 @@
3919
3941
  utils.log("nothing to select");
3920
3942
  }
3921
3943
  if (tag.match(/(?:h[1-6])/i)) {
3922
- _this.toggleMenuButtons(_this.el, ".icon-bold, .icon-italic");
3944
+ _this.toggleMenuButtons(_this.el, ".dante-icon-bold, .dante-icon-italic");
3923
3945
  } else if (tag === "indent") {
3924
- _this.toggleMenuButtons(_this.el, ".icon-h3, .icon-h4, .icon-blockquote");
3946
+ _this.toggleMenuButtons(_this.el, ".dante-icon-h3, .dante-icon-h4, .dante-icon-blockquote");
3925
3947
  }
3926
3948
  return _this.highlight(tag);
3927
3949
  };
@@ -3929,7 +3951,7 @@
3929
3951
  };
3930
3952
 
3931
3953
  Menu.prototype.highlight = function(tag) {
3932
- return $(".icon-" + tag).parent("li").addClass("active");
3954
+ return $(".dante-icon-" + tag).parent("li").addClass("active");
3933
3955
  };
3934
3956
 
3935
3957
  Menu.prototype.toggleMenuButtons = function(el, buttons) {
@@ -1,5 +1,5 @@
1
1
  require "dante-editor/version"
2
2
 
3
3
  module DanteEditor
4
- VERSION = "0.1.7"
4
+ VERSION = "0.1.8"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dante-editor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Michelson
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-06-19 00:00:00.000000000 Z
12
+ date: 2016-11-25 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: dante-editor yet another Medium editor clone.
15
15
  email: