copy 0.0.41 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +62 -3
- data/copy.gemspec +3 -3
- data/lib/copy/admin/copy.css +6 -2
- data/lib/copy/admin/edit.html.erb +5 -1
- data/lib/copy/admin/index.js.erb +3 -2
- data/lib/copy/generators/site/config.ru +4 -6
- data/lib/copy/generators/site/views/layout.html.erb +3 -1
- data/lib/copy/server.rb +13 -4
- data/lib/copy/storage/mongodb.rb +0 -1
- data/lib/copy/storage/redis.rb +1 -3
- data/lib/copy/storage/relational.rb +0 -2
- data/lib/copy/version.rb +1 -1
- data/test/server_test.rb +14 -2
- data/test/test_app/views/_one.html.erb +1 -0
- data/test/test_app/views/_three.html.erb +1 -0
- data/test/test_app/views/about/_two.html.erb +2 -0
- data/test/test_app/views/renders_partials.html.erb +4 -0
- metadata +15 -7
data/README.md
CHANGED
@@ -1,8 +1,67 @@
|
|
1
|
-
|
1
|
+
# Copy is a simple, Sinatra-based content management system.
|
2
2
|
|
3
|
-
|
3
|
+
`$ gem install copy` and then generate a new site `$ copy -n mynewsite`
|
4
4
|
|
5
|
-
|
5
|
+
mynewsite/
|
6
|
+
├── Gemfile <- Uncomment the gems you need for storage.
|
7
|
+
├── config.ru <- Configure storage, user, and password here.
|
8
|
+
├── public <- The public root of your new site.
|
9
|
+
│ ├── favicon.ico Ships with a few helpful defaults.
|
10
|
+
│ ├── images
|
11
|
+
│ ├── javascripts
|
12
|
+
│ │ └── main.js
|
13
|
+
│ ├── robots.txt
|
14
|
+
│ └── stylesheets
|
15
|
+
│ └── main.css
|
16
|
+
└── views <- Your views, layouts, and partials live here.
|
17
|
+
├── index.html.erb
|
18
|
+
└── layout.html.erb
|
19
|
+
|
20
|
+
The layout (`layout.html.erb`) yields to all the views. It's not required so delete it if your views contain full html documents.
|
21
|
+
|
22
|
+
Copy automatically maps URLs to files in your `views` directory.
|
23
|
+
|
24
|
+
* `/` → `index.html.erb`
|
25
|
+
* `/about` → `about.html.erb` or `about/index.html.erb`
|
26
|
+
* `/about/us` → `about/us.html.erb`
|
27
|
+
|
28
|
+
Copy lets you define blocks of editable text in your views.
|
29
|
+
|
30
|
+
<% copy :contact do %>
|
31
|
+
1 _Infinite_ Loop
|
32
|
+
Cupertino, CA 95014
|
33
|
+
408.996.1010
|
34
|
+
<% end %>
|
35
|
+
|
36
|
+
The text provided in the block will be saved and can then be edited live on the site. All content is formatted with Markdown. [See demo](http://copy-demo.heroku.com) for a live example or [view the source](https://github.com/javan/copy-demo).
|
37
|
+
|
38
|
+
Single line blocks will be edited in a text field as opposed to a textarea. Perfect for headlines.
|
39
|
+
|
40
|
+
<h1><% copy :title %>Like a boss!<% end %></h1>
|
41
|
+
|
42
|
+
**Partials** can be rendered from any view with the `partial` helper. Their filenames are always prefixed with an underscore.
|
43
|
+
|
44
|
+
* `<%= partial 'nav' %>` renders `_nav.html.erb`
|
45
|
+
* `<%= partial 'shared/details' %>` renders `shared/_details.html.erb`
|
46
|
+
|
47
|
+
----
|
48
|
+
|
49
|
+
### Storage
|
50
|
+
|
51
|
+
Copy supports multiple backends for storage: redis, mongodb, mysql, postgres, and sqlite.
|
52
|
+
|
53
|
+
Choosing and configuring your storage option is done in one line in your `config.ru` file by providing a connection URI.
|
54
|
+
|
55
|
+
Examples:
|
56
|
+
|
57
|
+
* `set :storage, 'mongodb://user:pass@host:port/database'`
|
58
|
+
* `set :storage, 'postgres://user:pass@host/database'`
|
59
|
+
|
60
|
+
----
|
61
|
+
|
62
|
+
### Editing copy on your live site
|
63
|
+
|
64
|
+
Browse to `/_copy` and drag the "Edit Copy" link to your bookmarks bar. Return to your site, click the bookmark (you'll be prompted for your username and password) and then click on the highlighted text to edit it. That's it!
|
6
65
|
|
7
66
|
----
|
8
67
|
|
data/copy.gemspec
CHANGED
@@ -8,9 +8,9 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
9
|
s.authors = ["Javan Makhmali"]
|
10
10
|
s.email = ["javan@javan.us"]
|
11
|
-
s.homepage = ""
|
12
|
-
s.summary = %q{
|
13
|
-
s.description = %q{
|
11
|
+
s.homepage = "https://github.com/javan/copy"
|
12
|
+
s.summary = %q{Simple, Sinatra-based CMS.}
|
13
|
+
s.description = %q{Serves mostly static pages with blocks of editable copy.}
|
14
14
|
|
15
15
|
s.rubyforge_project = "copy"
|
16
16
|
|
data/lib/copy/admin/copy.css
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
<div id="_copy">
|
2
2
|
<form class="_copy_edit_form" data-content-name="<%= @name %>" action="/_copy/<%= @name %>">
|
3
|
-
|
3
|
+
<% if @doc =~ /\n/ %>
|
4
|
+
<textarea name="content"><%=h @doc %></textarea>
|
5
|
+
<% else %>
|
6
|
+
<input type="text" name="content" value="<%=h @doc %>" />
|
7
|
+
<% end %>
|
4
8
|
<p class="_copy_footer _copy_footer_left">
|
5
9
|
<input class="_copy_submit" type="submit" value="Save" />
|
6
10
|
or <a class="_copy_cancel" href="#">cancel</a>
|
data/lib/copy/admin/index.js.erb
CHANGED
@@ -31,7 +31,7 @@ jQuery.noConflict();
|
|
31
31
|
success: function(html) {
|
32
32
|
$('body').prepend(html);
|
33
33
|
$('#_copy').css({ margin:'-'+($('#_copy').height() / 2)+'px 0 0 -'+($('#_copy').width() / 2)+'px' });
|
34
|
-
$('#_copy
|
34
|
+
$('#_copy [name="content"]').get(0).focus();
|
35
35
|
}
|
36
36
|
});
|
37
37
|
});
|
@@ -39,6 +39,7 @@ jQuery.noConflict();
|
|
39
39
|
$('._copy_cancel').live('click', function() {
|
40
40
|
$('#_copy').remove();
|
41
41
|
clickable();
|
42
|
+
return false;
|
42
43
|
});
|
43
44
|
|
44
45
|
$('._copy_edit_form').live('submit', function() {
|
@@ -48,7 +49,7 @@ jQuery.noConflict();
|
|
48
49
|
$.ajax({
|
49
50
|
type: 'PUT',
|
50
51
|
url: form.attr('action'),
|
51
|
-
data: { content: form.find('
|
52
|
+
data: { content: form.find('[name="content"]').val(), wrap_tag: original.get(0).tagName.toLowerCase() },
|
52
53
|
success: function(html) {
|
53
54
|
$('#_copy').remove();
|
54
55
|
original.replaceWith(html);
|
@@ -1,9 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
require 'rubygems'
|
5
|
-
require 'copy'
|
6
|
-
end
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
Bundler.require(:default)
|
7
4
|
|
8
5
|
Copy::Server.config do
|
9
6
|
# Sets a Cache-Control header for the duration specified.
|
@@ -20,6 +17,7 @@ Copy::Server.config do
|
|
20
17
|
# set :copy_password, ENV['COPY_PASSWORD']
|
21
18
|
|
22
19
|
# Enter the URL to your data store.
|
20
|
+
# Be sure to uncomment the correlating gems in your Gemfile.
|
23
21
|
# "redis://", "mongodb://", "mysql://", "postgres://", and "sqlite://" are supported.
|
24
22
|
# Heroku friendly: http://devcenter.heroku.com/articles/mongohq
|
25
23
|
#
|
@@ -4,9 +4,11 @@
|
|
4
4
|
<meta charset="utf-8">
|
5
5
|
<title>I love Copy</title>
|
6
6
|
<link rel="stylesheet" href="/stylesheets/main.css">
|
7
|
-
<script src="/javascripts/main.js"></script>
|
8
7
|
</head>
|
9
8
|
<body>
|
9
|
+
|
10
10
|
<%= yield %>
|
11
|
+
|
12
|
+
<script src="/javascripts/main.js"></script>
|
11
13
|
</body>
|
12
14
|
</html>
|
data/lib/copy/server.rb
CHANGED
@@ -9,6 +9,9 @@ module Copy
|
|
9
9
|
set :root, File.dirname(File.expand_path(__FILE__))
|
10
10
|
|
11
11
|
helpers do
|
12
|
+
include Rack::Utils
|
13
|
+
alias_method :h, :escape_html
|
14
|
+
|
12
15
|
def protected!
|
13
16
|
unless authorized?
|
14
17
|
response['WWW-Authenticate'] = %(Basic realm="Copy Admin Area")
|
@@ -68,6 +71,12 @@ module Copy
|
|
68
71
|
# Append the output buffer.
|
69
72
|
@_out_buf << format_text(name, content, options)
|
70
73
|
end
|
74
|
+
|
75
|
+
def partial(template)
|
76
|
+
template_array = template.to_s.split('/')
|
77
|
+
template = template_array[0..-2].join('/') + "/_#{template_array[-1]}.#{@_route.format}"
|
78
|
+
send(@_route.renderer, template.to_sym, :layout => false)
|
79
|
+
end
|
71
80
|
end
|
72
81
|
|
73
82
|
def self.config(&block)
|
@@ -105,11 +114,11 @@ module Copy
|
|
105
114
|
end
|
106
115
|
|
107
116
|
get '*' do
|
108
|
-
|
109
|
-
if
|
117
|
+
@_route = Copy::Router.new(params[:splat].first, settings.views)
|
118
|
+
if @_route.success?
|
110
119
|
set_cache_control_header
|
111
|
-
content_type(
|
112
|
-
send(
|
120
|
+
content_type(@_route.format)
|
121
|
+
send(@_route.renderer, @_route.template, :layout => @_route.layout)
|
113
122
|
else
|
114
123
|
not_found
|
115
124
|
end
|
data/lib/copy/storage/mongodb.rb
CHANGED
data/lib/copy/storage/redis.rb
CHANGED
data/lib/copy/version.rb
CHANGED
data/test/server_test.rb
CHANGED
@@ -112,6 +112,12 @@ class ServerCopyHelperTest < Test::Unit::TestCase
|
|
112
112
|
assert last_response.ok?
|
113
113
|
assert_match %Q(<span class="_copy_editable" data-name="headline">Important!</span>), last_response.body
|
114
114
|
end
|
115
|
+
|
116
|
+
test "partial rendering" do
|
117
|
+
get 'renders_partials'
|
118
|
+
assert last_response.ok?, last_response.errors
|
119
|
+
assert_match "before\none\ntwo\nthree\nafter", last_response.body
|
120
|
+
end
|
115
121
|
end
|
116
122
|
|
117
123
|
class ServerAdminTest < Test::Unit::TestCase
|
@@ -146,12 +152,18 @@ class ServerAdminTest < Test::Unit::TestCase
|
|
146
152
|
|
147
153
|
test "GET /_copy/:name" do
|
148
154
|
Copy::Storage.stubs(:connected?).returns(true)
|
149
|
-
Copy::Storage.expects(:get).with('fun').returns('party')
|
155
|
+
Copy::Storage.expects(:get).with('fun').returns('"party"')
|
150
156
|
|
151
157
|
authorize!
|
152
158
|
get '/_copy/fun'
|
153
159
|
assert last_response.ok?, last_response.errors
|
154
|
-
|
160
|
+
# Single line content renders in a text field
|
161
|
+
assert_match 'value=""party""', last_response.body
|
162
|
+
|
163
|
+
# Multiline renders in a textarea
|
164
|
+
Copy::Storage.expects(:get).with('fun').returns("<b>party\n")
|
165
|
+
get '/_copy/fun'
|
166
|
+
assert_match "<b>party\n</textarea>", last_response.body
|
155
167
|
end
|
156
168
|
|
157
169
|
test "PUT /_copy/:name" do
|
@@ -0,0 +1 @@
|
|
1
|
+
one
|
@@ -0,0 +1 @@
|
|
1
|
+
three
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: copy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 0.0.41
|
10
|
+
version: 0.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Javan Makhmali
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-05-
|
18
|
+
date: 2011-05-19 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -62,7 +62,7 @@ dependencies:
|
|
62
62
|
version: "0"
|
63
63
|
type: :development
|
64
64
|
version_requirements: *id003
|
65
|
-
description:
|
65
|
+
description: Serves mostly static pages with blocks of editable copy.
|
66
66
|
email:
|
67
67
|
- javan@javan.us
|
68
68
|
executables:
|
@@ -106,17 +106,21 @@ files:
|
|
106
106
|
- test/router_test.rb
|
107
107
|
- test/server_test.rb
|
108
108
|
- test/storage_test.rb
|
109
|
+
- test/test_app/views/_one.html.erb
|
110
|
+
- test/test_app/views/_three.html.erb
|
111
|
+
- test/test_app/views/about/_two.html.erb
|
109
112
|
- test/test_app/views/about/index.html.erb
|
110
113
|
- test/test_app/views/about/us.html.erb
|
111
114
|
- test/test_app/views/data/people.csv.erb
|
112
115
|
- test/test_app/views/data/people.xml.erb
|
113
116
|
- test/test_app/views/index.html.erb
|
114
117
|
- test/test_app/views/layout.html.erb
|
118
|
+
- test/test_app/views/renders_partials.html.erb
|
115
119
|
- test/test_app/views/with_copy_helper.html.erb
|
116
120
|
- test/test_app/views/with_copy_helper_one_line.html.erb
|
117
121
|
- test/test_helper.rb
|
118
122
|
has_rdoc: true
|
119
|
-
homepage:
|
123
|
+
homepage: https://github.com/javan/copy
|
120
124
|
licenses: []
|
121
125
|
|
122
126
|
post_install_message:
|
@@ -148,17 +152,21 @@ rubyforge_project: copy
|
|
148
152
|
rubygems_version: 1.4.2
|
149
153
|
signing_key:
|
150
154
|
specification_version: 3
|
151
|
-
summary:
|
155
|
+
summary: Simple, Sinatra-based CMS.
|
152
156
|
test_files:
|
153
157
|
- test/router_test.rb
|
154
158
|
- test/server_test.rb
|
155
159
|
- test/storage_test.rb
|
160
|
+
- test/test_app/views/_one.html.erb
|
161
|
+
- test/test_app/views/_three.html.erb
|
162
|
+
- test/test_app/views/about/_two.html.erb
|
156
163
|
- test/test_app/views/about/index.html.erb
|
157
164
|
- test/test_app/views/about/us.html.erb
|
158
165
|
- test/test_app/views/data/people.csv.erb
|
159
166
|
- test/test_app/views/data/people.xml.erb
|
160
167
|
- test/test_app/views/index.html.erb
|
161
168
|
- test/test_app/views/layout.html.erb
|
169
|
+
- test/test_app/views/renders_partials.html.erb
|
162
170
|
- test/test_app/views/with_copy_helper.html.erb
|
163
171
|
- test/test_app/views/with_copy_helper_one_line.html.erb
|
164
172
|
- test/test_helper.rb
|