ecrire 0.22.1 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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
-