ecrire 0.22.1 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.travis.yml +5 -0
  4. data/Gemfile +19 -0
  5. data/README.md +2 -0
  6. data/Rakefile +1 -1
  7. data/lib/ecrire/app/assets/javascripts/admin/editor/content.coffee +46 -76
  8. data/lib/ecrire/app/assets/javascripts/admin/editor/ext.coffee +3 -0
  9. data/lib/ecrire/app/assets/javascripts/admin/editor/extensions/clipboard.coffee +2 -1
  10. data/lib/ecrire/app/assets/javascripts/admin/editor/extensions/code.coffee +1 -2
  11. data/lib/ecrire/app/assets/javascripts/admin/editor/extensions/image.coffee +73 -1
  12. data/lib/ecrire/app/assets/javascripts/admin/editor/parsers/image.coffee +6 -115
  13. data/lib/ecrire/app/assets/javascripts/admin/editor.coffee +1 -0
  14. data/lib/ecrire/app/assets/javascripts/admin/{editor/navigation → navigation}/delete.js.coffee +1 -2
  15. data/lib/ecrire/app/assets/javascripts/admin/{editor/navigation → navigation}/draft.js.coffee +1 -3
  16. data/lib/ecrire/app/assets/javascripts/admin/{editor/navigation → navigation}/help.js.coffee +1 -1
  17. data/lib/ecrire/app/assets/javascripts/admin/{editor/navigation → navigation}/save.js.coffee +2 -2
  18. data/lib/ecrire/app/assets/javascripts/admin/{editor/navigation → navigation}/sticky.js.coffee +1 -2
  19. data/lib/ecrire/app/assets/javascripts/admin/{editor/navigation → navigation}/toggle.js.coffee +1 -2
  20. data/lib/ecrire/app/assets/javascripts/admin/posts/header.coffee +96 -40
  21. data/lib/ecrire/app/assets/javascripts/admin/posts/new.js.coffee +1 -2
  22. data/lib/ecrire/app/assets/javascripts/admin/posts/tag.js.coffee +7 -0
  23. data/lib/ecrire/app/assets/javascripts/admin/posts/tags.js.coffee +15 -0
  24. data/lib/ecrire/app/assets/javascripts/admin/posts/title.coffee +38 -9
  25. data/lib/ecrire/app/assets/javascripts/admin/tags/list.js.coffee +34 -0
  26. data/lib/ecrire/app/assets/javascripts/admin.js +1 -1
  27. data/lib/ecrire/app/assets/javascripts/application.js +2 -3
  28. data/lib/ecrire/app/assets/javascripts/shared/overlay.js.coffee +1 -2
  29. data/lib/ecrire/app/assets/javascripts/shared/popup.js.coffee +1 -2
  30. data/lib/ecrire/app/assets/stylesheets/admin/base.css.scss +1 -2
  31. data/lib/ecrire/app/assets/stylesheets/admin/editor/base.css.scss +0 -7
  32. data/lib/ecrire/app/assets/stylesheets/admin/editor/content.css.scss +30 -12
  33. data/lib/ecrire/app/assets/stylesheets/admin/editor/header.css.scss +154 -32
  34. data/lib/ecrire/app/assets/stylesheets/admin/posts.css.scss +8 -1
  35. data/lib/ecrire/app/assets/stylesheets/admin/tags.css.scss +78 -0
  36. data/lib/ecrire/app/assets/stylesheets/admin/title.css.scss +51 -0
  37. data/lib/ecrire/app/assets/stylesheets/admin/variables.css.scss +3 -0
  38. data/lib/ecrire/app/assets/stylesheets/shared/popup.css.scss +2 -0
  39. data/lib/ecrire/app/controllers/admin/application_controller.rb +6 -0
  40. data/lib/ecrire/app/controllers/admin/images_controller.rb +5 -6
  41. data/lib/ecrire/app/controllers/admin/posts/tags_controller.rb +35 -0
  42. data/lib/ecrire/app/controllers/admin/posts_controller.rb +13 -12
  43. data/lib/ecrire/app/controllers/admin/tags_controller.rb +4 -0
  44. data/lib/ecrire/app/controllers/admin/titles_controller.rb +39 -0
  45. data/lib/ecrire/app/controllers/application_controller.rb +13 -3
  46. data/lib/ecrire/app/controllers/ecrire/posts_controller.rb +6 -5
  47. data/lib/ecrire/app/helpers/posts_helper.rb +0 -12
  48. data/lib/ecrire/app/models/admin/image.rb +4 -7
  49. data/lib/ecrire/app/models/admin/post.rb +2 -7
  50. data/lib/ecrire/app/models/admin/tag.rb +4 -0
  51. data/lib/ecrire/app/models/admin/title.rb +4 -0
  52. data/lib/ecrire/app/models/post.rb +30 -22
  53. data/lib/ecrire/app/models/tag.rb +5 -0
  54. data/lib/ecrire/app/models/title.rb +62 -0
  55. data/lib/ecrire/app/views/admin/images/errors.json.jbuilder +1 -0
  56. data/lib/ecrire/app/views/admin/posts/edit.html.erb +61 -21
  57. data/lib/ecrire/app/views/admin/posts/header/_dropping.html.erb +12 -0
  58. data/lib/ecrire/app/views/admin/posts/header/_error.html.erb +18 -0
  59. data/lib/ecrire/app/views/admin/posts/header/_uploading.html.erb +21 -0
  60. data/lib/ecrire/app/views/admin/posts/new.html.erb +23 -0
  61. data/lib/ecrire/app/views/admin/posts/tags/_tag.html.erb +10 -0
  62. data/lib/ecrire/app/views/admin/posts/tags/create.js.erb +1 -0
  63. data/lib/ecrire/app/views/admin/posts/tags/dialog/_tag.html.erb +3 -0
  64. data/lib/ecrire/app/views/admin/posts/tags/dialog/_tags.html.erb +12 -0
  65. data/lib/ecrire/app/views/admin/posts/tags/index.js.erb +1 -0
  66. data/lib/ecrire/app/views/admin/posts/tags/update.js.erb +2 -0
  67. data/lib/ecrire/app/views/admin/titles/_title.html.erb +11 -0
  68. data/lib/ecrire/app/views/admin/titles/_titles.html.erb +22 -0
  69. data/lib/ecrire/app/views/admin/titles/create.js.erb +1 -0
  70. data/lib/ecrire/app/views/admin/titles/edit.js.erb +1 -0
  71. data/lib/ecrire/app/views/admin/titles/errors.js.erb +5 -0
  72. data/lib/ecrire/app/views/admin/titles/index.js.erb +1 -0
  73. data/lib/ecrire/app/views/admin/titles/update.js.erb +1 -0
  74. data/lib/ecrire/app/views/layouts/admin/application.html.erb +1 -1
  75. data/lib/ecrire/app/views/sessions/_navigation.html.erb +1 -1
  76. data/lib/ecrire/application.rb +1 -1
  77. data/lib/ecrire/config/routes.rb +2 -2
  78. data/lib/ecrire/db/migrate/20150305123321_move_labels_to_titles.rb +27 -0
  79. data/lib/ecrire/db/migrate/20150318549479_create_tags.rb +13 -0
  80. data/lib/ecrire/db/schema.rb +25 -22
  81. data/lib/ecrire/onboarding/assets/javascripts/base.js +1 -1
  82. data/lib/ecrire/onboarding/assets/javascripts/databases/information.js.coffee +1 -1
  83. data/lib/ecrire/onboarding/assets/javascripts/message.js.coffee +1 -1
  84. data/lib/ecrire/template/Gemfile +4 -3
  85. data/lib/ecrire/template/assets/javascripts/base.js.coffee +1 -0
  86. data/lib/ecrire/version.rb +1 -1
  87. data/test/editor/controllers/base_controller_test.rb +1 -0
  88. data/test/editor/models/post_test.rb +26 -56
  89. data/test/editor/models/title_test.rb +31 -0
  90. data/test/editor/test_helper.rb +2 -0
  91. data/test/fixtures/posts.yml +0 -4
  92. data/test/fixtures/tags.yml +2 -0
  93. data/test/fixtures/titles.yml +11 -0
  94. data/test/initializations/railtie_test.rb +2 -2
  95. data/test/themes/template/secrets.yml +6 -0
  96. metadata +49 -24
  97. data/lib/ecrire/app/assets/stylesheets/admin/editor/image.css.scss +0 -58
  98. data/lib/ecrire/app/controllers/admin/labels_controller.rb +0 -18
  99. data/lib/ecrire/app/models/label.rb +0 -3
  100. data/lib/ecrire/app/views/admin/images/errors.js.erb +0 -1
  101. data/lib/ecrire/app/views/admin/posts/title.html.erb +0 -10
  102. data/test/editor/controllers/admin/images_controller_test.rb +0 -6
  103. data/test/editor/controllers/admin/posts_controller_test.rb +0 -90
  104. data/test/editor/controllers/images_controller_test.rb +0 -2
  105. data/test/editor/controllers/partials_controller_test.rb +0 -2
  106. data/test/editor/controllers/posts_controller_test.rb +0 -21
  107. data/test/editor/helpers/posts_helper_test.rb +0 -3
  108. data/test/editor/models/partial_test.rb +0 -4
  109. data/test/fixtures/partials.yml +0 -9
  110. /data/lib/ecrire/app/views/admin/images/{update.js.erb → create.js.erb} +0 -0
  111. /data/{lib/ecrire/template/assets/javascripts/post.js.coffee → test/themes/onboarding/.keep} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1ca953837db65f9e27113c5399ce13c2353939bf
4
- data.tar.gz: 2289e12808f0202798eb783bbd30fd055cbbc8e6
3
+ metadata.gz: f76b1ffb5a76e8b346bdd15ab2fc6b2b9ddffcbf
4
+ data.tar.gz: 996185339a3a617b693bc5781891d926d3334f73
5
5
  SHA512:
6
- metadata.gz: e64e5dd7ce4c0aba279e3385837b6e3d6057e29c6f2db4f221f0da51c59780575dbe872b82366a0d97e7fc73c9ac5a612f6ca44633f2558f662ef47b398ae2e8
7
- data.tar.gz: e208f922deb272f90de0d89df47c7299c10a33ff267109589e0d1f83cdcc43eb19bde09e8a299a98b996fe9d21b0fec6234ec52caeaa9e2ccf2fc3879215ccc8
6
+ metadata.gz: 36e7377ebb0b601c51dfeed39a3b12a8eb4af0bf5068cb2acd2e5b033969473e4560a8b374b6ffca757259e9dcd8ea6768840327b9abbefbee9fa36d02656c9b
7
+ data.tar.gz: d8bf17c5c38fb86e482d44f8d30e809142617a81decd9a2340ba5c4b4378ee45c195d7589843f2538a6b3688617a1361ead70f23105141225012c83620c831a2
data/.gitignore CHANGED
@@ -15,6 +15,7 @@
15
15
  log
16
16
  /tmp
17
17
 
18
- secrets.yml
19
18
  .DS_Store
20
19
  Gemfile.lock
20
+
21
+ /lib/ecrire/template/secrets.yml
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ 2.1.0
4
+
5
+ script: "bundle exec rake test"
data/Gemfile CHANGED
@@ -2,3 +2,22 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
+ gem 'rails', '~> 4.2'
6
+ gem 'observejs', git: 'https://github.com/pothibo/observejs.git'
7
+ gem 'warden', '~> 1.2'
8
+ gem 'bcrypt', '~> 3.1'
9
+ gem 'nokogiri', '~> 1.6'
10
+ gem 's3', '~> 0.3'
11
+ gem 'pg', '~> 0.17'
12
+ gem 'kaminari', '~> 0.15'
13
+ gem 'kramdown', '~> 1.5'
14
+
15
+ gem 'sprockets-rails', '~> 2.1'
16
+ gem 'sass-rails', '~> 4.0', '>= 4.0.3'
17
+ gem 'coffee-rails', '~> 4.0'
18
+ gem 'turbolinks', '~> 2.2'
19
+ gem 'bourbon', '~> 3.2'
20
+ gem 'uglifier', '~> 2.5'
21
+ gem 'jbuilder', '~> 2.2'
22
+
23
+ gem 'byebug'
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Ecrire
2
2
 
3
+ [![Build Status](https://travis-ci.org/pothibo/ecrire.svg?branch=master)](https://travis-ci.org/pothibo/ecrire)
4
+
3
5
  Ecrire is a blog built *on top* of Ruby on Rails. The goal of this blog engine is to make it **easy** to start a blog while keeping control over the content. You can see this as an alternative to WordPress.
4
6
 
5
7
  ## The editor
data/Rakefile CHANGED
@@ -38,7 +38,7 @@ namespace :database do
38
38
  end
39
39
 
40
40
  task :purge do
41
- [User, Post, Image, Partial, Label].each(&:delete_all)
41
+ [User, Post, Image, Partial, Title].each(&:delete_all)
42
42
  end
43
43
 
44
44
  end
@@ -1,4 +1,4 @@
1
- Joint.bind 'Editor.Content', class @Editor
1
+ ObserveJS.bind 'Editor.Content', class @Editor
2
2
 
3
3
  loaded: =>
4
4
  @on 'keydown', @linefeed
@@ -38,13 +38,11 @@ Joint.bind 'Editor.Content', class @Editor
38
38
 
39
39
 
40
40
 
41
- outdated: (mutations) =>
41
+ outdated: (observedMutations) =>
42
42
  @observer.hold =>
43
- for mutation in mutations
44
- @appended(node, mutation.target) for node in mutation.addedNodes
45
- @removed(node, mutation.target) for node in mutation.removedNodes
46
- if mutation.type == 'characterData'
47
- @update mutation.target
43
+ mutations = new Mutations(observedMutations, @element())
44
+ if mutations.target?
45
+ @updated(mutations)
48
46
 
49
47
  event = new CustomEvent('Editor:updated', {bubbles: true})
50
48
  @element().dispatchEvent(event)
@@ -83,7 +81,11 @@ Joint.bind 'Editor.Content', class @Editor
83
81
 
84
82
 
85
83
 
86
- update: (node) ->
84
+ updated: (mutations) ->
85
+ if mutations.target.contentEditable == 'false'
86
+ return
87
+
88
+ node = mutations.target
87
89
  while node? && node.parentElement != @element()
88
90
  node = node.parentElement
89
91
 
@@ -92,7 +94,10 @@ Joint.bind 'Editor.Content', class @Editor
92
94
  walker = @walker(node)
93
95
 
94
96
  sel = window.getSelection()
95
- offset = @lineOffset(node, (sel.focusNode || node), sel.focusOffset)
97
+ if sel.type == 'None'
98
+ offset = 0
99
+ else
100
+ offset = @lineOffset(node, (sel.focusNode || node), sel.focusOffset)
96
101
 
97
102
  if node.previousElementSibling?
98
103
  node = node.previousElementSibling
@@ -106,66 +111,6 @@ Joint.bind 'Editor.Content', class @Editor
106
111
  cursor.update(@walker(line))
107
112
  @scrollLineIntoView(cursor.focus())
108
113
 
109
-
110
- removed: (node, line) =>
111
- while line? && line.parentElement != @element()
112
- line = line.parentElement
113
-
114
- if node.nodeType != 1 || (node instanceof HTMLBRElement && node.parentElement?)
115
- node.remove()
116
-
117
- if line?
118
- sel = window.getSelection()
119
- offset = @lineOffset(line, sel.focusNode, sel.focusOffset)
120
- cursor = new Editor.Cursor(offset)
121
-
122
- lines = @parse(@cloneNodesFrom(line))
123
-
124
- @observer.hold =>
125
- line = cursor.focus(@updateDOM(line, lines)[0])
126
- cursor.update(@walker(line))
127
-
128
- if @element().childNodes.length == 0
129
- p = "<p>".toHTML()
130
- @element().appendChild(p)
131
- cursor = new Editor.Cursor(offset)
132
- cursor.update(@walker(p), 0)
133
-
134
-
135
-
136
- appended: (node) =>
137
- el = node
138
- while el? && el.parentElement != @element()
139
- el = el.parentElement
140
-
141
- return unless el?
142
-
143
- elements = el.querySelectorAll('[contenteditable=false]')
144
-
145
- for element in elements
146
- if element.contains(node)
147
- return
148
-
149
- if node instanceof HTMLBRElement
150
- node.remove()
151
- return
152
-
153
- node = el
154
-
155
- sel = window.getSelection()
156
- offset = @lineOffset(el, sel.focusNode, sel.focusOffset)
157
- cursor = new Editor.Cursor(offset)
158
-
159
- lines = @parse(@cloneNodesFrom(node))
160
-
161
- @observer.hold =>
162
- lines = @updateDOM(node, lines)
163
- if node != lines[0]
164
- cursor.update(@walker(lines[0]))
165
- @scrollLineIntoView(lines[0])
166
-
167
-
168
-
169
114
  scrollLineIntoView: (line) =>
170
115
  height = window.innerHeight
171
116
  rect = line.getBoundingClientRect()
@@ -263,18 +208,11 @@ Joint.bind 'Editor.Content', class @Editor
263
208
  node1 = node1.cloneNode(true)
264
209
  node2 = node2.cloneNode(true)
265
210
 
266
- for el in node1.querySelectorAll('[contenteditable=false]')
267
- el.remove()
268
-
269
- for el in node2.querySelectorAll('[contenteditable=false]')
270
- el.remove()
271
-
272
211
  node1.nodeName == node2.nodeName &&
273
212
  node1.innerHTML.trim() == node2.innerHTML.trim()
274
213
 
275
214
 
276
215
 
277
-
278
216
  parse: (fragment) =>
279
217
  for p in @parsers
280
218
  line = fragment.firstChild
@@ -380,5 +318,37 @@ class LineFeed
380
318
  @fragment.appendChild(node)
381
319
 
382
320
 
321
+ class Mutations
322
+ constructor: (mutations, editor) ->
323
+ @removed = []
324
+ @appended = []
325
+ @updated = []
326
+
327
+ for mutation in mutations
328
+ @setTarget(mutation.target, editor)
329
+ if mutation.addedNodes.length > 0
330
+ @appended.push mutation.target
331
+ else if mutation.type == 'characterData'
332
+ @updated.push mutation.target
333
+ else
334
+ @removed.push mutation.target
335
+
336
+ setTarget: (target, editor) ->
337
+ return unless target.parentElement? && target != editor
338
+ if @target? && @target.compareDocumentPosition(target) & Node.DOCUMENT_POSITION_FOLLOWING
339
+ @target = target
340
+ else
341
+ @target = target
342
+
343
+ status: =>
344
+ if @appended.length > 0
345
+ "appended"
346
+ else if @updated.length > 0
347
+ 'updated'
348
+ else if @removed.length > 0
349
+ 'removed'
350
+ else
351
+ 'none'
352
+
383
353
  Editor.Parsers = []
384
354
  Editor.Extensions = []
@@ -23,6 +23,9 @@ HTMLDivElement::toString = ->
23
23
  HTMLPreElement::toString = ->
24
24
  @textContent
25
25
 
26
+ HTMLElement::toString = ->
27
+ @textContent
28
+
26
29
  HTMLHeadingElement::toString = HTMLParagraphElement::toString = ->
27
30
  @textContent
28
31
 
@@ -105,8 +105,9 @@ Editor.Extensions.push class ClipBoard
105
105
  for n in line.childNodes
106
106
  if n == node
107
107
  break
108
- else if n.childNodes.length > 0
108
+ else if n.contains(node)
109
109
  offset += @nodeOffset(node, n)
110
+ break
110
111
  else
111
112
  offset += n.textContent.length
112
113
 
@@ -1,4 +1,4 @@
1
- Joint.bind 'Editor.Code', class
1
+ ObserveJS.bind 'Editor.Code', class
2
2
  loaded: =>
3
3
  document.addEventListener 'keydown', @filter, true
4
4
 
@@ -7,4 +7,3 @@ Joint.bind 'Editor.Code', class
7
7
  when 13 then @linefeed(e)
8
8
 
9
9
  linefeed: (e) =>
10
-
@@ -1,8 +1,14 @@
1
- Joint.bind 'Editor.Image', class
1
+ ObserveJS.bind 'Editor.Image', class
2
2
  loaded: =>
3
3
  @element().addEventListener 'dragover', @over
4
4
  @element().addEventListener 'dragleave', @cancel
5
5
  @element().addEventListener 'drop', @drop
6
+ @on 'click', @container(), @open
7
+ @on 'change', @element().querySelector('input'), @upload
8
+ if @element().querySelector('figcaption').hasAttribute('name')
9
+ @show()
10
+ else
11
+ @placehold()
6
12
 
7
13
  over: (e) =>
8
14
  e.preventDefault()
@@ -15,5 +21,71 @@ Joint.bind 'Editor.Image', class
15
21
  drop: (e) =>
16
22
  e.preventDefault()
17
23
  @element().classList.remove 'dropping'
24
+ e.file = e.dataTransfer.files[0]
25
+ @upload(e)
18
26
 
27
+ show: =>
28
+ img = @retrieve('img')
29
+ img.src = @element().querySelector('figcaption').getAttribute('name')
30
+ @container().appendChild(img)
19
31
 
32
+ placehold: =>
33
+ placeholder = @retrieve('.placeholder')
34
+ @container().appendChild(placeholder)
35
+
36
+ container: =>
37
+ @container.element ||= @element().querySelector('div[contenteditable=false]')
38
+
39
+ open: =>
40
+ @container().querySelector('input').click()
41
+
42
+ uploaded: (e) =>
43
+ xml = new DOMParser().parseFromString(e.target.response, 'text/xml')
44
+ url = xml.querySelector('Location').textContent
45
+ img = @retrieve('img')
46
+ img.src = url
47
+ progressBar = @retrieve('.progressbar')
48
+ @container().insertBefore(img, progressBar)
49
+ progressBar.remove()
50
+ @retrieve('.placeholder').remove()
51
+ @element().querySelector('figcaption').lastChild.textContent = "(#{url})"
52
+
53
+ upload: (e) =>
54
+ @container().appendChild(@retrieve('.progressbar'))
55
+ unless e.file?
56
+ e.file = e.target.files[0]
57
+ id = PostBody.getAttribute('postid')
58
+ policy = PostBody.getAttribute('policy')
59
+ signature = PostBody.getAttribute('signature')
60
+ bucket = PostBody.getAttribute('bucket')
61
+ namespace = PostBody.getAttribute('namespace')
62
+ access_key = PostBody.getAttribute('access_key')
63
+
64
+ url = "https://s3.amazonaws.com/#{bucket}/"
65
+ dir = [id]
66
+ if namespace?
67
+ dir.splice(0,0, namespace)
68
+
69
+ dir = dir.join '/'
70
+
71
+ data = new FormData()
72
+ data.append 'AWSAccessKeyId', access_key
73
+ data.append 'success_action_status', 201
74
+ data.append 'acl', 'private'
75
+ data.append 'policy', policy
76
+ data.append 'signature', signature
77
+ data.append 'key', "#{dir}/#{e.file.name}"
78
+ data.append 'Content-Type', e.file.type
79
+ data.append 'file', e.file
80
+
81
+ xhr = new XMLHttpRequest()
82
+ xhr.open('POST', url, true)
83
+ xhr.onload = @uploaded
84
+ xhr.onprogress = @progress
85
+ xhr.send(data)
86
+
87
+ progress: (e) =>
88
+ return unless e.lengthComputable
89
+ percentComplete = e.loaded / e.total * 100.0;
90
+ progressBar = @retrieve('.progressbar')
91
+ progressBar.firstElementChild.style.width = "#{percentComplete}%";
@@ -9,121 +9,12 @@ Editor.Parsers.push class
9
9
  @match?
10
10
 
11
11
  render: =>
12
- @container = new Container()
12
+ @figure = EditorElements.content.querySelector("[as='Editor.Image']").cloneNode(true)
13
13
 
14
- @uploader = new Editor.ImageUploader(@show)
15
-
16
-
17
- @picture = "<div class='image' as='Editor.Image'>".toHTML()
18
-
19
- @title = "<em></em>".toHTML()
20
- @title.appendChild document.createTextNode(@match[1])
21
- @title.appendChild document.createTextNode(@match[3])
14
+ @caption = @figure.querySelector('figcaption')
15
+ @caption.appendChild document.createTextNode(@match[1])
16
+ @caption.appendChild document.createTextNode(@match[3])
22
17
  if @match[4]?
23
- @title.setAttribute('name', @match[4])
24
-
25
- @picture.appendChild @container.toHTML(@match[4])
26
- @picture.appendChild @title
27
-
28
- @container.input.addEventListener 'change', @update
29
- @picture.addEventListener 'drop', @drop
30
-
31
- return @picture
32
-
33
- show: (e, url) =>
34
- @container.image(url)
35
- @title.lastChild.textContent = "(#{url})"
36
-
37
- update: (e) =>
38
- unless e.file?
39
- e.file = e.target.files[0]
40
- @container.loading()
41
- @uploader.send(e)
42
-
43
- drop: (e) =>
44
- e.preventDefault()
45
- e.file = e.dataTransfer.files[0]
46
- @update(e)
47
-
48
-
49
- class Container
50
- constructor: ->
51
- @el = "<div contenteditable=false></div>".toHTML()
52
- @el.addEventListener 'click', @open
53
-
54
- if !(@input = @el.querySelector('input'))?
55
- @input = "<input type='file'>".toHTML()
56
-
57
- @el.appendChild(@input)
58
-
59
- image: (url) =>
60
- @el.style.backgroundImage = "url(#{url})"
61
- @el.innerHTML = ''
62
- @el.classList.remove 'loading'
63
-
64
- loading: =>
65
- @loading = =>
66
- @el.classList.add 'loading'
67
- @el.innerHTML = ''
68
-
69
- @loading()
70
-
71
- placeholder: =>
72
- el = "<p>Drop an image or click here to upload a picture.</p>".toHTML()
73
- @placeholder = =>
74
- @el.innerHTML = ''
75
- @el.appendChild(el)
76
-
77
- @placeholder()
78
-
79
- open: (e) =>
80
- @input.click()
81
-
82
- toHTML: (url) =>
83
- if url?
84
- @image(url)
85
- else if @el.classList.contains('loading')
86
- @loading()
87
- else
88
- @placeholder()
89
-
90
- @el
91
-
92
-
93
- class Editor.ImageUploader
94
- constructor: (@callback) ->
95
-
96
- uploaded: (e) =>
97
- xml = new DOMParser().parseFromString(e.target.response, 'text/xml')
98
- url = xml.querySelector('Location').textContent
99
- @callback(e, url)
100
-
101
- send: (e) =>
102
- id = PostBody.getAttribute('postid')
103
- policy = PostBody.getAttribute('policy')
104
- signature = PostBody.getAttribute('signature')
105
- bucket = PostBody.getAttribute('bucket')
106
- namespace = PostBody.getAttribute('namespace')
107
- access_key = PostBody.getAttribute('access_key')
108
-
109
- url = "https://s3.amazonaws.com/#{bucket}/"
110
- dir = [id]
111
- if namespace?
112
- dir.splice(0,0, namespace)
113
-
114
- dir = dir.join '/'
115
-
116
- data = new FormData()
117
- data.append 'AWSAccessKeyId', access_key
118
- data.append 'success_action_status', 201
119
- data.append 'acl', 'private'
120
- data.append 'policy', policy
121
- data.append 'signature', signature
122
- data.append 'key', "#{dir}/#{e.file.name}"
123
- data.append 'Content-Type', e.file.type
124
- data.append 'file', e.file
18
+ @caption.setAttribute('name', @match[4])
125
19
 
126
- xhr = new XMLHttpRequest()
127
- xhr.open('POST', url, true)
128
- xhr.onload = @uploaded
129
- xhr.send(data)
20
+ return @figure
@@ -0,0 +1 @@
1
+ #= require_tree ./editor
@@ -1,4 +1,4 @@
1
- Joint.bind 'Post.Delete', class
1
+ ObserveJS.bind 'Post.Delete', class
2
2
  loaded: =>
3
3
  @on 'change', @element().querySelector('input[type=checkbox]'), @toggle
4
4
 
@@ -8,4 +8,3 @@ Joint.bind 'Post.Delete', class
8
8
  button.removeAttribute('disabled')
9
9
  else
10
10
  button.setAttribute('disabled', 'disabled')
11
-
@@ -1,4 +1,4 @@
1
- Joint.bind 'Editor.Draft', class
1
+ ObserveJS.bind 'Editor.Draft', class
2
2
  resetInterval: 4000
3
3
  loaded: =>
4
4
  @on 'Editor:updated', document, @update
@@ -38,5 +38,3 @@ Joint.bind 'Editor.Draft', class
38
38
  unless @cached?
39
39
  @cached = e.target.textContent
40
40
  return
41
-
42
-
@@ -1,4 +1,4 @@
1
- Joint.bind 'Post.Documentation', class
1
+ ObserveJS.bind 'Post.Documentation', class
2
2
  loaded: =>
3
3
  @on 'posts:help', @show
4
4
 
@@ -1,4 +1,4 @@
1
- Joint.bind 'Editor.Save', class
1
+ ObserveJS.bind 'Editor.Save', class
2
2
  loaded: =>
3
3
  @button = @element().querySelector('button')
4
4
  @time = @element().querySelector('div.update > p')
@@ -62,7 +62,7 @@ Joint.bind 'Editor.Save', class
62
62
  e.stopPropagation()
63
63
 
64
64
  form = document.querySelector("[as='Editor.Save']")
65
- xhr = new Joint.XHR(form)
65
+ xhr = new ObserveJS.XHR(form)
66
66
  xhr.data.set('post[content]', PostBody.instance.toString())
67
67
  xhr.data.set('context', 'content')
68
68
  xhr.send()
@@ -1,4 +1,4 @@
1
- Joint.bind 'Post.Sticky', class
1
+ ObserveJS.bind 'Post.Sticky', class
2
2
  loaded: =>
3
3
  @on 'scroll', document, @scrolled
4
4
 
@@ -8,4 +8,3 @@ Joint.bind 'Post.Sticky', class
8
8
  @element().style.paddingTop = "#{Math.abs(top)}px"
9
9
  else
10
10
  @element().style.paddingTop = ''
11
-
@@ -1,4 +1,4 @@
1
- Joint.bind 'Navigation.Toggle', class
1
+ ObserveJS.bind 'Navigation.Toggle', class
2
2
  loaded: =>
3
3
  @on 'click', @toggle
4
4
 
@@ -7,4 +7,3 @@ Joint.bind 'Navigation.Toggle', class
7
7
  Menu.style.marginTop = '0'
8
8
  else
9
9
  Menu.style.marginTop = ''
10
-