ecrire 0.20.0 → 0.21.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.
- checksums.yaml +4 -4
- data/README.md +47 -45
- data/lib/ecrire/app/assets/javascripts/admin/editor/content.coffee +103 -48
- data/lib/ecrire/app/assets/javascripts/admin/editor/ext.coffee +9 -3
- data/lib/ecrire/app/assets/javascripts/admin/editor/extensions/clipboard.coffee +26 -10
- data/lib/ecrire/app/assets/javascripts/admin/editor/extensions/code.coffee +10 -0
- data/lib/ecrire/app/assets/javascripts/admin/editor/navigation/save.js.coffee +5 -8
- data/lib/ecrire/app/assets/javascripts/admin/editor/parsers/code.coffee +7 -3
- data/lib/ecrire/app/assets/javascripts/admin/editor/parsers/image.coffee +1 -1
- data/lib/ecrire/app/assets/stylesheets/admin/editor/content.css.scss +30 -1
- data/lib/ecrire/app/assets/stylesheets/shared/popup.css.scss +5 -0
- data/lib/ecrire/app/controllers/ecrire/posts_controller.rb +1 -1
- data/lib/ecrire/app/views/admin/posts/_documentation.html.erb +1 -1
- data/lib/ecrire/db/schema.rb +8 -13
- data/lib/ecrire/tasks/assets.rake +1 -1
- data/lib/ecrire/tasks/database.rake +6 -0
- data/lib/ecrire/template/Gemfile +1 -1
- data/lib/ecrire/template/Procfile +2 -0
- data/lib/ecrire/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b9187d5d3cf47bd6d98975d2c7e98f78fca7e724
|
4
|
+
data.tar.gz: bb54f17491247dfe317ca7ba9ef3fe78089936c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d7887948635cf02da8caaed5c802c34e2f8ca0baa3e6d53f8cf04caccec39444a542a67a45a9b2026b739b9ca5ff290544f0908e9b3fefb96b4724e2ab8c9d60
|
7
|
+
data.tar.gz: b12bfee9bd7bde93f8d37b514df86f01add1c972884998af6fa05a930aae3e610eee4b1f9000fe1c5ac281940dc0b42fa9f40bc288498c617c2741965e1375d5
|
data/README.md
CHANGED
@@ -1,62 +1,64 @@
|
|
1
1
|
# Ecrire
|
2
2
|
|
3
|
-
|
3
|
+
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
4
|
|
5
|
-
|
5
|
+
## The editor
|
6
|
+
The editor was built around the Markdown syntax. The content change as you type to offer you a very good approximation of how your post will look like once publish.
|
6
7
|
|
7
|
-
|
8
|
+
Here's the available feature:
|
9
|
+
- Headers
|
10
|
+
- Unordered list
|
11
|
+
- Ordered list
|
12
|
+
- Code with syntax highlighting
|
13
|
+
- Image with auto-upload to S3
|
14
|
+
- Links
|
15
|
+
- Bold and Italic words
|
8
16
|
|
9
|
-
|
17
|
+
More feature will be implemented as the Editor mature.
|
10
18
|
|
11
|
-
|
19
|
+
## Theme
|
20
|
+
When you start a new blog with Ecrire, it will generate a folder for you. Everything in that folder is for you to modify. You won't break anything. It also features a few characteristic that you may recognize if you are a Rails developer.
|
12
21
|
|
13
|
-
|
22
|
+
- SASS
|
23
|
+
- Coffeescript
|
24
|
+
- Assets caching through Sprockets
|
25
|
+
- View using layouts, views and partials
|
26
|
+
- Controllers
|
27
|
+
- Helpers
|
28
|
+
- Static pages
|
14
29
|
|
15
|
-
|
30
|
+
When you install your theme, the documentation will be available direclty within your blog so you can go back to it when you need it.
|
16
31
|
|
17
|
-
|
32
|
+
## How to install
|
18
33
|
|
34
|
+
```bash
|
35
|
+
$ gem install ecrire
|
36
|
+
$ ecrire new my.blog.com
|
37
|
+
$ cd my.blog.com/
|
38
|
+
$ ecrire server
|
39
|
+
```
|
19
40
|
|
20
|
-
|
41
|
+
From there, you can access your new blog via the browser and start configuring your database.
|
21
42
|
|
22
|
-
|
43
|
+
## Heroku
|
23
44
|
|
24
|
-
|
25
|
-
``` gem install ecrire ```
|
45
|
+
Once you have finished your changes in your local environment, here's how you can publish your blog on Heroku.
|
26
46
|
|
27
|
-
|
28
|
-
|
47
|
+
~~~bash
|
48
|
+
$ heroku git:remote -a name-of-your-app-on-heroku
|
49
|
+
$ git push origin heroku
|
50
|
+
$ heroku run rake db:migrate
|
51
|
+
~~~
|
29
52
|
|
30
|
-
|
31
|
-
``` bundle install ```
|
53
|
+
Your blog is now up and running on Heroku! But you need to create a user on Heroku for now, here's how you do it.
|
32
54
|
|
33
|
-
|
55
|
+
~~~ruby
|
56
|
+
$ heroku run ecrire console
|
57
|
+
irb(main)> user = User.new
|
58
|
+
irb(main)> user.email = "your@email.com"
|
59
|
+
irb(main)> user.password = "yourpassword"
|
60
|
+
irb(main)> user.save!
|
61
|
+
irb(main)> exit
|
62
|
+
~~~
|
34
63
|
|
35
|
-
|
36
|
-
|
37
|
-
You can access the blog & configuration setup with your browser by going at the following address.
|
38
|
-
``` http://localhost:3000 ```
|
39
|
-
|
40
|
-
### Licence
|
41
|
-
|
42
|
-
The MIT License (MIT)
|
43
|
-
|
44
|
-
Copyright (c) 2014 pothibo
|
45
|
-
|
46
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
47
|
-
of this software and associated documentation files (the "Software"), to deal
|
48
|
-
in the Software without restriction, including without limitation the rights
|
49
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
50
|
-
copies of the Software, and to permit persons to whom the Software is
|
51
|
-
furnished to do so, subject to the following conditions:
|
52
|
-
|
53
|
-
The above copyright notice and this permission notice shall be included in
|
54
|
-
all copies or substantial portions of the Software.
|
55
|
-
|
56
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
57
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
58
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
59
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
60
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
61
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
62
|
-
THE SOFTWARE.
|
64
|
+
You can now log in to your blog in production and start writing for real!
|
@@ -59,21 +59,23 @@ Joint.bind 'Editor.Content', class @Editor
|
|
59
59
|
|
60
60
|
sel = window.getSelection()
|
61
61
|
node = focusNode = sel.focusNode
|
62
|
-
offset = sel.focusOffset
|
63
|
-
|
64
|
-
str = focusNode.textContent
|
65
|
-
focusNode.textContent = str.substr(0, offset) + "\n" + str.substr(offset)
|
66
62
|
|
67
63
|
while node? && node.parentElement != @element()
|
68
64
|
node = node.parentElement
|
69
|
-
|
70
|
-
offset = @lineOffset(node, focusNode, offset) + 1
|
71
65
|
|
72
|
-
|
66
|
+
offset = @lineOffset(node, focusNode, sel.focusOffset)
|
67
|
+
|
68
|
+
lineFeed = new LineFeed(@cloneNodesFrom(node))
|
69
|
+
lineFeed.injectAt(offset)
|
70
|
+
|
71
|
+
cursor = new Editor.Cursor(offset + 1)
|
72
|
+
|
73
|
+
lines = @parse(lineFeed.fragment)
|
73
74
|
|
74
75
|
@observer.hold =>
|
75
|
-
|
76
|
-
@
|
76
|
+
line = cursor.focus(@updateDOM(node, lines)[0])
|
77
|
+
cursor.update(@walker(line))
|
78
|
+
@scrollLineIntoView(cursor.focus())
|
77
79
|
|
78
80
|
|
79
81
|
event = new CustomEvent('Editor:updated', {bubbles: true})
|
@@ -97,13 +99,12 @@ Joint.bind 'Editor.Content', class @Editor
|
|
97
99
|
offset += node.toString().length + 1
|
98
100
|
|
99
101
|
lines = @parse(@cloneNodesFrom(node))
|
102
|
+
cursor = new Editor.Cursor(offset)
|
100
103
|
|
101
104
|
@observer.hold =>
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
@setCursorAt(lines[0], offset)
|
106
|
-
break
|
105
|
+
line = cursor.focus(@updateDOM(node, lines)[0])
|
106
|
+
cursor.update(@walker(line))
|
107
|
+
@scrollLineIntoView(cursor.focus())
|
107
108
|
|
108
109
|
|
109
110
|
removed: (node, line) =>
|
@@ -116,18 +117,19 @@ Joint.bind 'Editor.Content', class @Editor
|
|
116
117
|
if line?
|
117
118
|
sel = window.getSelection()
|
118
119
|
offset = @lineOffset(line, sel.focusNode, sel.focusOffset)
|
120
|
+
cursor = new Editor.Cursor(offset)
|
119
121
|
|
120
122
|
lines = @parse(@cloneNodesFrom(line))
|
121
123
|
|
122
124
|
@observer.hold =>
|
123
|
-
|
124
|
-
|
125
|
-
@setCursorAt(lines[0], offset)
|
125
|
+
line = cursor.focus(@updateDOM(line, lines)[0])
|
126
|
+
cursor.update(@walker(line))
|
126
127
|
|
127
128
|
if @element().childNodes.length == 0
|
128
129
|
p = "<p>".toHTML()
|
129
130
|
@element().appendChild(p)
|
130
|
-
|
131
|
+
cursor = new Editor.Cursor(offset)
|
132
|
+
cursor.update(@walker(p), 0)
|
131
133
|
|
132
134
|
|
133
135
|
|
@@ -152,16 +154,25 @@ Joint.bind 'Editor.Content', class @Editor
|
|
152
154
|
|
153
155
|
sel = window.getSelection()
|
154
156
|
offset = @lineOffset(el, sel.focusNode, sel.focusOffset)
|
157
|
+
cursor = new Editor.Cursor(offset)
|
155
158
|
|
156
159
|
lines = @parse(@cloneNodesFrom(node))
|
157
160
|
|
158
161
|
@observer.hold =>
|
159
162
|
lines = @updateDOM(node, lines)
|
160
163
|
if node != lines[0]
|
161
|
-
@
|
164
|
+
cursor.update(@walker(lines[0]))
|
165
|
+
@scrollLineIntoView(lines[0])
|
162
166
|
|
163
167
|
|
164
168
|
|
169
|
+
scrollLineIntoView: (line) =>
|
170
|
+
height = window.innerHeight
|
171
|
+
rect = line.getBoundingClientRect()
|
172
|
+
|
173
|
+
if rect.bottom > height
|
174
|
+
line.scrollIntoView()
|
175
|
+
|
165
176
|
updateDOM: (anchor, fragment) =>
|
166
177
|
return unless anchor?
|
167
178
|
current = anchor.parentElement.lastChild
|
@@ -213,6 +224,10 @@ Joint.bind 'Editor.Content', class @Editor
|
|
213
224
|
|
214
225
|
|
215
226
|
lineOffset: (line, node, offset) =>
|
227
|
+
|
228
|
+
if node.nodeType == document.ELEMENT_NODE
|
229
|
+
return node.textContent.length
|
230
|
+
|
216
231
|
if node.textContent.length == 0
|
217
232
|
return 0
|
218
233
|
|
@@ -221,34 +236,6 @@ Joint.bind 'Editor.Content', class @Editor
|
|
221
236
|
|
222
237
|
|
223
238
|
|
224
|
-
setCursorAt: (line, offset) ->
|
225
|
-
sel = window.getSelection()
|
226
|
-
|
227
|
-
while true
|
228
|
-
length = line.toString().length
|
229
|
-
if length >= offset
|
230
|
-
break
|
231
|
-
offset -= Math.max(length + 1, 1)
|
232
|
-
|
233
|
-
if line.nextSibling?
|
234
|
-
line = line.nextSibling
|
235
|
-
continue
|
236
|
-
break
|
237
|
-
|
238
|
-
walker = @walker(line)
|
239
|
-
range = line.getRange(offset , walker)
|
240
|
-
|
241
|
-
height = window.innerHeight
|
242
|
-
rect = line.getBoundingClientRect()
|
243
|
-
|
244
|
-
if rect.bottom > height
|
245
|
-
line.scrollIntoView()
|
246
|
-
|
247
|
-
sel.removeAllRanges()
|
248
|
-
sel.addRange(range)
|
249
|
-
|
250
|
-
|
251
|
-
|
252
239
|
cloneNodesFrom: (node) =>
|
253
240
|
fragment = document.createDocumentFragment()
|
254
241
|
while node
|
@@ -313,7 +300,75 @@ Joint.bind 'Editor.Content', class @Editor
|
|
313
300
|
|
314
301
|
texts.join '\n'
|
315
302
|
|
303
|
+
class @Editor.Cursor
|
304
|
+
constructor: (offset) ->
|
305
|
+
@selection = window.getSelection()
|
306
|
+
@origin = @selection.focusNode
|
307
|
+
|
308
|
+
@offset = offset
|
309
|
+
|
310
|
+
focus: (line) ->
|
311
|
+
while true
|
312
|
+
length = line.toString().length
|
313
|
+
if length >= @offset
|
314
|
+
break
|
315
|
+
@offset -= Math.max(length + 1, 1)
|
316
|
+
|
317
|
+
if line.nextSibling?
|
318
|
+
line = line.nextSibling
|
319
|
+
continue
|
320
|
+
break
|
321
|
+
|
322
|
+
@focus = ->
|
323
|
+
line
|
324
|
+
|
325
|
+
@focus()
|
326
|
+
|
327
|
+
update: (walker, force = false) ->
|
328
|
+
line = walker.root
|
329
|
+
|
330
|
+
if !force && @selection.focusNode == @origin && line.contains(@origin)
|
331
|
+
return
|
332
|
+
|
333
|
+
range = line.getRange(@offset, walker)
|
334
|
+
|
335
|
+
@selection.removeAllRanges()
|
336
|
+
@selection.addRange(range)
|
337
|
+
|
338
|
+
class LineFeed
|
339
|
+
constructor: (@fragment) ->
|
340
|
+
|
341
|
+
injectAt: (offset) ->
|
342
|
+
node = @fragment.firstChild
|
343
|
+
while node && offset > 0
|
344
|
+
length = node.textContent.length
|
345
|
+
if offset > length
|
346
|
+
offset -= length + 1
|
347
|
+
node = node.nextSibling
|
348
|
+
else
|
349
|
+
break
|
350
|
+
|
351
|
+
if !node?
|
352
|
+
@append(@fragment.lastChild)
|
353
|
+
else
|
354
|
+
@insert(node, offset)
|
355
|
+
|
356
|
+
append: (lastChild) ->
|
357
|
+
node = lastChild.cloneNode(true)
|
358
|
+
node.textContent = ''
|
359
|
+
@fragment.appendChild(node)
|
360
|
+
|
361
|
+
insert: (root, offset) ->
|
362
|
+
node = root.cloneNode(true)
|
363
|
+
|
364
|
+
root.textContent = root.textContent.substr(0, offset)
|
365
|
+
node.textContent = node.textContent.substr(offset)
|
366
|
+
|
367
|
+
if root.nextSibling?
|
368
|
+
@fragment.insertBefore(node, root.nextSibling)
|
369
|
+
else
|
370
|
+
@fragment.appendChild(node)
|
371
|
+
|
316
372
|
|
317
373
|
Editor.Parsers = []
|
318
374
|
Editor.Extensions = []
|
319
|
-
|
@@ -14,10 +14,16 @@ HTMLOListElement::toString = HTMLUListElement::toString = ->
|
|
14
14
|
li.textContent
|
15
15
|
texts.join("\n")
|
16
16
|
|
17
|
-
|
18
|
-
@
|
17
|
+
HTMLDivElement::toString = ->
|
18
|
+
if @classList.contains('image')
|
19
|
+
@lastChild.textContent
|
20
|
+
else
|
21
|
+
@textContent
|
22
|
+
|
23
|
+
HTMLPreElement::toString = ->
|
24
|
+
@textContent
|
19
25
|
|
20
|
-
|
26
|
+
HTMLHeadingElement::toString = HTMLParagraphElement::toString = ->
|
21
27
|
@textContent
|
22
28
|
|
23
29
|
HTMLElement::offset = (node, walker) ->
|
@@ -42,7 +42,7 @@ Editor.Extensions.push class ClipBoard
|
|
42
42
|
|
43
43
|
|
44
44
|
replace: (texts, sel) =>
|
45
|
-
|
45
|
+
|
46
46
|
node = sel.extentNode
|
47
47
|
line = node
|
48
48
|
nodes = [node]
|
@@ -62,14 +62,15 @@ Editor.Extensions.push class ClipBoard
|
|
62
62
|
t.textContent
|
63
63
|
).join()
|
64
64
|
|
65
|
-
|
65
|
+
|
66
66
|
line.textContent = line.textContent.substr(0, offsets.start) + text + line.textContent.substr(offsets.end)
|
67
67
|
|
68
68
|
fragment = @editor.parse(@editor.cloneNodesFrom(line))
|
69
69
|
|
70
70
|
@editor.updateDOM(line, fragment)
|
71
71
|
|
72
|
-
|
72
|
+
cursor = new Editor.Cursor(offsets.start + text.length)
|
73
|
+
cursor.update(@editor.walker(cursor.focus(line)), true)
|
73
74
|
|
74
75
|
|
75
76
|
insert: (texts, sel) =>
|
@@ -84,15 +85,30 @@ Editor.Extensions.push class ClipBoard
|
|
84
85
|
node.textContent += text
|
85
86
|
node.textContent += str.substr(sel.anchorOffset)
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
88
|
+
line = node
|
89
|
+
while line.parentElement != @editor.element()
|
90
|
+
line = line.parentElement
|
91
|
+
|
92
|
+
offset = @nodeOffset(node,line) + sel.anchorOffset + text.length
|
93
|
+
|
94
|
+
fragment = @editor.parse(@editor.cloneNodesFrom(line))
|
91
95
|
|
92
|
-
|
96
|
+
lines = @editor.updateDOM(line, fragment)
|
93
97
|
|
94
|
-
|
98
|
+
cursor = new Editor.Cursor(offset)
|
99
|
+
cursor.update(@editor.walker(cursor.focus(lines[0])), true)
|
95
100
|
|
96
|
-
|
101
|
+
nodeOffset: (node, line) ->
|
102
|
+
if !line.contains(node)
|
103
|
+
raise "Looking for a node that is not inside the given line"
|
104
|
+
return
|
97
105
|
|
106
|
+
offset = 0
|
107
|
+
|
108
|
+
for n in line.childNodes
|
109
|
+
if n == node
|
110
|
+
break
|
111
|
+
else
|
112
|
+
offset += n.textContent.length
|
98
113
|
|
114
|
+
offset
|
@@ -9,7 +9,7 @@ Joint.bind 'Editor.Save', class
|
|
9
9
|
@on 'click', @button, @save
|
10
10
|
@on 'beforeunload', window, @confirm
|
11
11
|
|
12
|
-
@button.
|
12
|
+
@button.textContent = @button.getAttribute('persisted')
|
13
13
|
@refresh()
|
14
14
|
@cache()
|
15
15
|
@interval = setInterval(@refresh, 1000)
|
@@ -28,7 +28,7 @@ Joint.bind 'Editor.Save', class
|
|
28
28
|
if refresh
|
29
29
|
cache = PostBody.instance.toString()
|
30
30
|
@button.setAttribute('disabled', 'disabled')
|
31
|
-
@button.
|
31
|
+
@button.textContent = @button.getAttribute('persisted')
|
32
32
|
cache
|
33
33
|
@cache()
|
34
34
|
|
@@ -42,10 +42,7 @@ Joint.bind 'Editor.Save', class
|
|
42
42
|
xhr.send()
|
43
43
|
|
44
44
|
saved: (e) =>
|
45
|
-
if e.
|
46
|
-
event = new CustomEvent('Editor:message', { bubbles: true})
|
47
|
-
event.MessageHTML = e.MessageHTML
|
48
|
-
@element().dispatchEvent(event)
|
45
|
+
if e.UpdatedAtTime
|
49
46
|
@time.setAttribute('time', e.UpdatedAtTime)
|
50
47
|
@refresh()
|
51
48
|
@cache(true)
|
@@ -54,8 +51,8 @@ Joint.bind 'Editor.Save', class
|
|
54
51
|
return unless @cache()?
|
55
52
|
if @cache() != PostBody.instance.toString()
|
56
53
|
@button.removeAttribute('disabled')
|
57
|
-
@button.
|
54
|
+
@button.textContent = @button.getAttribute('dirty')
|
58
55
|
else
|
59
56
|
@button.setAttribute('disabled', 'disabled')
|
60
|
-
@button.
|
57
|
+
@button.textContent = @button.getAttribute('persisted')
|
61
58
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
Editor.Parsers.push class
|
2
|
-
rule: /^((~{3,})([a-z]+)
|
2
|
+
rule: /^((~{3,})([a-z]+)?)(.+)?(~{3,}$)?/mi
|
3
3
|
|
4
4
|
constructor: (node) ->
|
5
5
|
@nodes = [node]
|
@@ -28,11 +28,15 @@ Editor.Parsers.push class
|
|
28
28
|
|
29
29
|
render: =>
|
30
30
|
pre = "<pre>".toHTML()
|
31
|
-
code = "<code>".toHTML()
|
31
|
+
code = "<code as='Editor.Code'>".toHTML()
|
32
|
+
|
32
33
|
if @match[3]?
|
33
34
|
code.classList.add("language-#{@match[3]}")
|
35
|
+
|
34
36
|
texts = @nodes.map (n) -> n.textContent
|
35
|
-
|
37
|
+
|
38
|
+
code.textContent = texts.join('\n')
|
39
|
+
|
36
40
|
Prism.highlightElement(code)
|
37
41
|
pre.appendChild(code)
|
38
42
|
pre
|
@@ -14,7 +14,7 @@ Editor.Parsers.push class
|
|
14
14
|
@uploader = new Editor.ImageUploader(@show)
|
15
15
|
|
16
16
|
|
17
|
-
@picture = "<
|
17
|
+
@picture = "<div class='image' as='Editor.Image'>".toHTML()
|
18
18
|
|
19
19
|
@title = "<em></em>".toHTML()
|
20
20
|
@title.appendChild document.createTextNode(@match[1])
|
@@ -3,6 +3,31 @@ body.edit.posts > main > section {
|
|
3
3
|
@include flex(1);
|
4
4
|
outline: none;
|
5
5
|
font-size: 1.2em;
|
6
|
+
padding-bottom: 10em;
|
7
|
+
|
8
|
+
h1 {
|
9
|
+
font-size: 2.6em;
|
10
|
+
}
|
11
|
+
|
12
|
+
h2 {
|
13
|
+
font-size: 2.3em;
|
14
|
+
}
|
15
|
+
|
16
|
+
h3 {
|
17
|
+
font-size: 2.0em;
|
18
|
+
}
|
19
|
+
|
20
|
+
h4 {
|
21
|
+
font-size: 1.7em;
|
22
|
+
}
|
23
|
+
|
24
|
+
h5 {
|
25
|
+
font-size: 1.6em;
|
26
|
+
}
|
27
|
+
|
28
|
+
h6 {
|
29
|
+
font-size: 1.3em;
|
30
|
+
}
|
6
31
|
|
7
32
|
& > *, & > ul > li, & > ol > li {
|
8
33
|
white-space: pre-wrap;
|
@@ -15,7 +40,11 @@ body.edit.posts > main > section {
|
|
15
40
|
margin-left: 2em;
|
16
41
|
}
|
17
42
|
|
18
|
-
& >
|
43
|
+
& > pre {
|
44
|
+
background: rgba(0,0,0, 0.1);
|
45
|
+
}
|
46
|
+
|
47
|
+
& > div.image {
|
19
48
|
@include display(flex);
|
20
49
|
@include flex-direction(column);
|
21
50
|
@include transition(background-color 0.3s);
|
data/lib/ecrire/db/schema.rb
CHANGED
@@ -17,14 +17,9 @@ ActiveRecord::Schema.define(version: 20150120093481) do
|
|
17
17
|
enable_extension "plpgsql"
|
18
18
|
enable_extension "hstore"
|
19
19
|
|
20
|
-
create_table "abtests", force: :cascade do |t|
|
21
|
-
t.datetime "created_at"
|
22
|
-
t.datetime "updated_at"
|
23
|
-
end
|
24
|
-
|
25
20
|
create_table "images", force: :cascade do |t|
|
26
|
-
t.string "url"
|
27
|
-
t.string "key"
|
21
|
+
t.string "url"
|
22
|
+
t.string "key"
|
28
23
|
t.integer "post_id"
|
29
24
|
t.datetime "created_at"
|
30
25
|
t.datetime "updated_at"
|
@@ -32,7 +27,7 @@ ActiveRecord::Schema.define(version: 20150120093481) do
|
|
32
27
|
end
|
33
28
|
|
34
29
|
create_table "labels", force: :cascade do |t|
|
35
|
-
t.string "name",
|
30
|
+
t.string "name", null: false
|
36
31
|
t.datetime "created_at"
|
37
32
|
t.datetime "updated_at"
|
38
33
|
end
|
@@ -42,15 +37,15 @@ ActiveRecord::Schema.define(version: 20150120093481) do
|
|
42
37
|
create_table "partials", force: :cascade do |t|
|
43
38
|
t.datetime "created_at"
|
44
39
|
t.datetime "updated_at"
|
45
|
-
t.string "title",
|
40
|
+
t.string "title", null: false
|
46
41
|
t.text "content"
|
47
42
|
t.text "stylesheet"
|
48
43
|
t.text "javascript"
|
49
44
|
end
|
50
45
|
|
51
46
|
create_table "posts", force: :cascade do |t|
|
52
|
-
t.string "title",
|
53
|
-
t.string "slug",
|
47
|
+
t.string "title", null: false
|
48
|
+
t.string "slug", null: false
|
54
49
|
t.text "content"
|
55
50
|
t.text "stylesheet"
|
56
51
|
t.datetime "published_at"
|
@@ -65,8 +60,8 @@ ActiveRecord::Schema.define(version: 20150120093481) do
|
|
65
60
|
add_index "posts", ["title"], name: "index_posts_on_title", unique: true, using: :btree
|
66
61
|
|
67
62
|
create_table "users", force: :cascade do |t|
|
68
|
-
t.string "email",
|
69
|
-
t.string "encrypted_password",
|
63
|
+
t.string "email", null: false
|
64
|
+
t.string "encrypted_password", null: false
|
70
65
|
t.datetime "created_at"
|
71
66
|
t.datetime "updated_at"
|
72
67
|
end
|
@@ -8,7 +8,7 @@ module Sprockets
|
|
8
8
|
module Rails
|
9
9
|
class Task < Rake::SprocketsTask
|
10
10
|
def output
|
11
|
-
File.join(Ecrire::Railtie.paths['public'].
|
11
|
+
File.join(Ecrire::Railtie.paths['public'].expanded.first, app.config.assets.prefix)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
data/lib/ecrire/template/Gemfile
CHANGED
data/lib/ecrire/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ecrire
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.21.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pier-Olivier Thibault
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Blog engine on Rails
|
14
14
|
email: pothibo@gmail.com
|
@@ -29,6 +29,7 @@ files:
|
|
29
29
|
- lib/ecrire/app/assets/javascripts/admin/editor/content.coffee
|
30
30
|
- lib/ecrire/app/assets/javascripts/admin/editor/ext.coffee
|
31
31
|
- lib/ecrire/app/assets/javascripts/admin/editor/extensions/clipboard.coffee
|
32
|
+
- lib/ecrire/app/assets/javascripts/admin/editor/extensions/code.coffee
|
32
33
|
- lib/ecrire/app/assets/javascripts/admin/editor/extensions/image.coffee
|
33
34
|
- lib/ecrire/app/assets/javascripts/admin/editor/navigation/delete.js.coffee
|
34
35
|
- lib/ecrire/app/assets/javascripts/admin/editor/navigation/draft.js.coffee
|
@@ -192,8 +193,10 @@ files:
|
|
192
193
|
- lib/ecrire/railtie/onboarding.rb
|
193
194
|
- lib/ecrire/railtie/theme.rb
|
194
195
|
- lib/ecrire/tasks/assets.rake
|
196
|
+
- lib/ecrire/tasks/database.rake
|
195
197
|
- lib/ecrire/tasks/routes.rake
|
196
198
|
- lib/ecrire/template/Gemfile
|
199
|
+
- lib/ecrire/template/Procfile
|
197
200
|
- lib/ecrire/template/Rakefile
|
198
201
|
- lib/ecrire/template/assets/images/.keep
|
199
202
|
- lib/ecrire/template/assets/javascripts/base.js.coffee
|
@@ -268,7 +271,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
268
271
|
version: '0'
|
269
272
|
requirements: []
|
270
273
|
rubyforge_project:
|
271
|
-
rubygems_version: 2.
|
274
|
+
rubygems_version: 2.2.2
|
272
275
|
signing_key:
|
273
276
|
specification_version: 4
|
274
277
|
summary: Blog engine
|