danwrong-evil 0.1 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1 -0
- data/LICENSE +22 -0
- data/Manifest +33 -7
- data/README.textile +20 -0
- data/Rakefile +21 -2
- data/assets/config.ru +10 -2
- data/assets/evil-lib.js +222 -0
- data/assets/evil.css +204 -10
- data/assets/evil.js +20 -0
- data/assets/logo.png +0 -0
- data/evil.gemspec +32 -19
- data/lib/evil/application.rb +85 -17
- data/lib/evil/extensions.rb +71 -0
- data/lib/evil/helpers.rb +62 -0
- data/lib/evil/models/config_pair.rb +7 -0
- data/lib/evil/models/template.rb +10 -9
- data/lib/evil/models.rb +0 -12
- data/lib/evil/open_id.rb +101 -0
- data/lib/evil/plugin/base.rb +56 -0
- data/lib/evil/plugin/configuration.rb +77 -0
- data/lib/evil/plugin/environment.rb +15 -0
- data/lib/evil/plugin/filesystem.rb +18 -0
- data/lib/evil/plugin/tag.rb +81 -0
- data/lib/evil/plugin.rb +21 -0
- data/lib/evil/setup/generator.rb +13 -1
- data/lib/evil/setup/migration.rb +4 -11
- data/lib/evil.rb +34 -1
- data/test/app/evil_test.rb +64 -0
- data/test/dev_env.rb +10 -0
- data/test/test_helper.rb +12 -0
- data/test/units/plugin/base_test.rb +47 -0
- data/test/units/plugin/tag_test.rb +108 -0
- data/views/_banner.haml +8 -0
- data/views/_errors.haml +9 -0
- data/views/index.haml +41 -0
- data/views/layout.haml +13 -0
- data/views/login.haml +5 -0
- data/views/plugins/_fields.haml +7 -0
- data/views/plugins/edit.haml +2 -0
- data/views/plugins/fields/_password.haml +3 -0
- data/views/plugins/fields/_text.haml +3 -0
- data/views/plugins/new.haml +6 -0
- data/views/templates/_fields.haml +23 -0
- data/views/templates/edit.haml +3 -0
- data/views/templates/new.haml +3 -0
- metadata +115 -13
- data/lib/evil/models/plugin.rb +0 -13
- data/test/harness/config.ru +0 -9
- data/test/harness/evil.db +0 -0
- data/test/harness/public/javascripts/evil.js +0 -0
- data/test/harness/public/stylesheets/evil.css +0 -24
- data/test/harness/tmp/restart.txt +0 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
module Evil
|
2
|
+
module Plugin
|
3
|
+
|
4
|
+
class TagExecution
|
5
|
+
|
6
|
+
def initialize(tag, options, context, &block)
|
7
|
+
@options = evaluate(options, context)
|
8
|
+
@context = context
|
9
|
+
@tag = tag
|
10
|
+
@proc = block
|
11
|
+
end
|
12
|
+
|
13
|
+
def body(locals={})
|
14
|
+
@context.stack do
|
15
|
+
locals.each { |k, v| @context[k.to_s] = v }
|
16
|
+
return @tag.render_body(@context).to_s
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute
|
21
|
+
self.instance_exec(@options, &@proc)
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
execute.to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def evaluate(options, context)
|
31
|
+
options.inject({}) do |evaluated, pair|
|
32
|
+
opt, value = pair
|
33
|
+
evaluated[opt] = context[value]; evaluated
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class Tag < Liquid::Block
|
39
|
+
Syntax = /((#{Liquid::TagAttributes}\s?,?\s?)*)/
|
40
|
+
|
41
|
+
class << self
|
42
|
+
attr_accessor :tag_proc
|
43
|
+
attr_accessor :plugin
|
44
|
+
|
45
|
+
def from(&block)
|
46
|
+
tag = Class.new(self)
|
47
|
+
tag.tag_proc = block; tag
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def initialize(tag_name, markup, tokens)
|
52
|
+
super
|
53
|
+
|
54
|
+
if markup =~ Syntax
|
55
|
+
@options = parse_options($1)
|
56
|
+
else
|
57
|
+
raise Liquid::SyntaxError.new("Syntax Error in tag '#{tagname}' - Valid syntax: #{tagname} [ opt : 'val', opt : 'val' ]")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def render(context)
|
62
|
+
TagExecution.new(self, @options, context, &self.class.tag_proc).to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
def render_body(context)
|
66
|
+
render_all(@nodelist, context)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def parse_options(opt_string)
|
72
|
+
pairs = opt_string.split(',')
|
73
|
+
pairs.inject({}) do |opts, pair|
|
74
|
+
opt, value = pair.split(':')
|
75
|
+
opts[opt.strip.to_sym] = value.strip; opts
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
data/lib/evil/plugin.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Evil
|
2
|
+
module Plugin
|
3
|
+
autoload :Base, 'evil/plugin/base'
|
4
|
+
autoload :Tag, 'evil/plugin/tag'
|
5
|
+
autoload :Environment, 'evil/plugin/environment'
|
6
|
+
autoload :Filesystem, 'evil/plugin/filesystem'
|
7
|
+
autoload :Configuration, 'evil/plugin/configuration'
|
8
|
+
|
9
|
+
def self.evaluate(plugin_source)
|
10
|
+
Environment.module_eval plugin_source
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.from_file(file)
|
14
|
+
evaluate(File.read(file))
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.find_plugin(name)
|
18
|
+
Environment.plugins.find { |p| p.name == name }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/evil/setup/generator.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'evil/models'
|
3
3
|
require 'evil/setup/migration'
|
4
|
+
require 'digest/sha1'
|
4
5
|
|
5
6
|
module Evil
|
6
7
|
module Setup
|
@@ -14,11 +15,14 @@ module Evil
|
|
14
15
|
public/images
|
15
16
|
public/stylesheets
|
16
17
|
public/javascripts
|
18
|
+
plugins
|
17
19
|
}
|
18
20
|
|
19
21
|
ASSETS = [
|
20
22
|
['evil.css', 'public/stylesheets/evil.css'],
|
21
23
|
['evil.js', 'public/javascripts/evil.js'],
|
24
|
+
['evil-lib.js', 'public/javascripts/evil-lib.js'],
|
25
|
+
['logo.png', 'public/images/logo.png'],
|
22
26
|
['config.ru', 'config.ru']
|
23
27
|
]
|
24
28
|
|
@@ -30,12 +34,14 @@ module Evil
|
|
30
34
|
puts "Generating Evil application..."
|
31
35
|
create_dir_tree!
|
32
36
|
copy_assets!
|
37
|
+
set_cookie_secret!
|
33
38
|
puts "Initializing database..."
|
34
39
|
create_database!
|
35
40
|
end
|
36
41
|
|
37
42
|
def create_dir_tree!
|
38
43
|
DIR_LAYOUT.each do |dir|
|
44
|
+
puts "Directory #{@path}/#{dir}"
|
39
45
|
mkdir_p "#{@path}/#{dir}"
|
40
46
|
end
|
41
47
|
end
|
@@ -51,10 +57,16 @@ module Evil
|
|
51
57
|
|
52
58
|
def copy_assets!
|
53
59
|
ASSETS.each do |file, dest|
|
60
|
+
puts "File #{File.join(@path, dest)}"
|
54
61
|
cp File.join(ASSET_PATH, file), File.join(@path, dest)
|
55
62
|
end
|
56
63
|
end
|
57
|
-
|
64
|
+
|
65
|
+
def set_cookie_secret!
|
66
|
+
rackup = File.read(File.join(@path, 'config.ru'))
|
67
|
+
rackup.gsub!(/__SECRET__/, Digest::SHA1.hexdigest("__EVIL__#{Time.now.to_s}__#{rand(999999)}"))
|
68
|
+
File.open(File.join(@path, 'config.ru'), 'w') { |f| f.write(rackup) }
|
69
|
+
end
|
58
70
|
end
|
59
71
|
end
|
60
72
|
end
|
data/lib/evil/setup/migration.rb
CHANGED
@@ -8,27 +8,20 @@ module Evil
|
|
8
8
|
def create_evil_tables
|
9
9
|
create_table :evil_templates do |t|
|
10
10
|
t.integer :ttl, :position
|
11
|
-
t.string :title, :route
|
11
|
+
t.string :title, :route, :content_type, :encoding
|
12
12
|
t.text :source
|
13
13
|
t.timestamps
|
14
|
-
end unless Evil::Models::Template.table_exists?
|
15
|
-
|
16
|
-
create_table :evil_plugins do |t|
|
17
|
-
t.string :name, :description, :author
|
18
|
-
t.text :source, :url
|
19
|
-
t.boolean :enabled
|
20
|
-
t.timestamps
|
21
|
-
end unless Evil::Models::Plugin.table_exists?
|
14
|
+
end unless Evil::Models::Template.table_exists?
|
22
15
|
|
23
16
|
unless Evil::Models::ConfigPair.table_exists?
|
24
17
|
create_table :evil_config_pairs do |t|
|
25
|
-
t.
|
18
|
+
t.string :plugin
|
26
19
|
t.string :key
|
27
20
|
t.text :value
|
28
21
|
t.timestamps
|
29
22
|
end
|
30
23
|
|
31
|
-
add_index :evil_config_pairs, :
|
24
|
+
add_index :evil_config_pairs, :plugin
|
32
25
|
end
|
33
26
|
|
34
27
|
create_table :evil_whitelists do |t|
|
data/lib/evil.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
require 'liquid'
|
2
|
+
require 'liquid_inheritance'
|
3
|
+
require 'httparty'
|
4
|
+
|
1
5
|
module Evil
|
2
6
|
module Setup
|
3
7
|
autoload :DbTool, 'evil/setup/db_tool'
|
@@ -5,11 +9,40 @@ module Evil
|
|
5
9
|
autoload :Migration, 'evil/setup/migration'
|
6
10
|
end
|
7
11
|
|
12
|
+
autoload :OpenID, 'evil/open_id'
|
13
|
+
autoload :Helpers, 'evil/helpers'
|
14
|
+
autoload :Extensions, 'evil/extensions'
|
15
|
+
|
16
|
+
autoload :Plugin, 'evil/plugin'
|
17
|
+
|
8
18
|
autoload :Application, 'evil/application'
|
9
19
|
|
10
20
|
class << self
|
11
21
|
attr_accessor :gem_root, :app_root
|
22
|
+
|
23
|
+
def heroku?
|
24
|
+
Object.const_defined?(:Heroku)
|
25
|
+
end
|
12
26
|
end
|
13
27
|
end
|
14
28
|
|
15
|
-
Evil.gem_root = File.join(File.dirname(__FILE__), '..')
|
29
|
+
Evil.gem_root = File.join(File.dirname(__FILE__), '..')
|
30
|
+
|
31
|
+
class Proc
|
32
|
+
def bind(object)
|
33
|
+
block, time = self, Time.now
|
34
|
+
(class << object; self end).class_eval do
|
35
|
+
method_name = "__bind_#{time.to_i}_#{time.usec}"
|
36
|
+
define_method(method_name, &block)
|
37
|
+
method = instance_method(method_name)
|
38
|
+
remove_method(method_name)
|
39
|
+
method
|
40
|
+
end.bind(object)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Object
|
45
|
+
def instance_exec(*arguments, &block)
|
46
|
+
block.bind(self)[*arguments]
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../test_helper')
|
2
|
+
require 'evil/application'
|
3
|
+
|
4
|
+
class EvilTest < Test::Unit::TestCase
|
5
|
+
include Sinatra::Test
|
6
|
+
|
7
|
+
context 'running the evil application' do
|
8
|
+
setup do
|
9
|
+
@app = Evil::Application
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'while not logged in' do
|
13
|
+
|
14
|
+
context 'GET /admin' do
|
15
|
+
setup do
|
16
|
+
get '/admin'
|
17
|
+
end
|
18
|
+
|
19
|
+
should 'not be authorized' do
|
20
|
+
assert_equal 401, response.status
|
21
|
+
assert_match /openid_url/, response.body
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'while logged in' do
|
28
|
+
setup do
|
29
|
+
@env = { 'rack.session' => { :identity_url => 'www.danwebb.net' } }
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'GET /admin' do
|
33
|
+
setup do
|
34
|
+
get '/admin', {}, @env
|
35
|
+
end
|
36
|
+
|
37
|
+
should 'be successful' do
|
38
|
+
assert response.ok?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'GET /admin/templates/1 with existing template' do
|
43
|
+
setup do
|
44
|
+
get '/admin/templates/1', {}, @env
|
45
|
+
end
|
46
|
+
|
47
|
+
should 'be successful' do
|
48
|
+
assert response.ok?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'GET /admin/templates/nothinghere with non-existing template' do
|
53
|
+
setup do
|
54
|
+
get '/admin/templates/nothinghere', {}, @env
|
55
|
+
end
|
56
|
+
|
57
|
+
should 'be not found' do
|
58
|
+
assert_equal 404, response.status
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
data/test/dev_env.rb
ADDED
data/test/test_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), '../lib'))
|
2
|
+
require 'rubygems'
|
3
|
+
require 'evil'
|
4
|
+
require 'test/unit'
|
5
|
+
require 'shoulda'
|
6
|
+
require 'sinatra/test'
|
7
|
+
require 'mocha'
|
8
|
+
|
9
|
+
require 'redgreen' rescue nil
|
10
|
+
|
11
|
+
Sinatra::Default.set :environment, 'test'
|
12
|
+
Evil.app_root = File.join(File.dirname(__FILE__), 'example')
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class BaseTest < Test::Unit::TestCase
|
2
|
+
should 'initialize with a name and a block that recieves the new instance' do
|
3
|
+
plugin = Evil::Plugin::Base.new 'Test Plugin' do |p|
|
4
|
+
assert_instance_of Evil::Plugin::Base, p
|
5
|
+
end
|
6
|
+
|
7
|
+
assert_equal 'Test Plugin', plugin.name
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'given a plugin instance with a description and setup set' do
|
11
|
+
setup do
|
12
|
+
@setup_proc = Proc.new {}
|
13
|
+
|
14
|
+
@plugin = Evil::Plugin::Base.new 'Test Plugin' do |p|
|
15
|
+
p.description 'A plugin for testing plugins'
|
16
|
+
|
17
|
+
p.setup &@setup_proc
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
should 'have a description set' do
|
23
|
+
assert_equal 'A plugin for testing plugins', @plugin.description
|
24
|
+
end
|
25
|
+
|
26
|
+
should 'call the setup proc when init called' do
|
27
|
+
@setup_proc.expects(:call)
|
28
|
+
|
29
|
+
@plugin.init
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
should 'create and register a tag instance when plugin initialize with a tag call' do
|
35
|
+
Evil::Plugin::Tag.expects(:from).returns(t = Class.new(Liquid::Tag))
|
36
|
+
Liquid::Template.expects(:register_tag).with(:thing, t)
|
37
|
+
|
38
|
+
Evil::Plugin::Base.new 'Test Plugin' do |p|
|
39
|
+
p.tag :thing do
|
40
|
+
'a tag'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../../test_helper')
|
2
|
+
require 'liquid'
|
3
|
+
|
4
|
+
class TagTest < Test::Unit::TestCase
|
5
|
+
context 'with a custom tag defined that returns a string' do
|
6
|
+
setup do
|
7
|
+
Liquid::Template.register_tag('test', Evil::Plugin::Tag.from { |params|
|
8
|
+
'hello'
|
9
|
+
})
|
10
|
+
end
|
11
|
+
|
12
|
+
should 'output the string' do
|
13
|
+
template = Liquid::Template.parse('{% test %}{% endtest %}')
|
14
|
+
|
15
|
+
assert_equal 'hello', template.render
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'with a custom tag defined that returns a parameter' do
|
20
|
+
setup do
|
21
|
+
Liquid::Template.register_tag('test', Evil::Plugin::Tag.from { |params|
|
22
|
+
params[:a]
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
should 'output that parameter if passed as a constant' do
|
27
|
+
template = Liquid::Template.parse('{% test a: "thing" %}{% endtest %}')
|
28
|
+
|
29
|
+
assert_equal 'thing', template.render
|
30
|
+
end
|
31
|
+
|
32
|
+
should 'output that parameter if passed as a variable' do
|
33
|
+
template = Liquid::Template.parse('{% test a: var %}{% endtest %}')
|
34
|
+
|
35
|
+
assert_equal 'thing', template.render('var' => 'thing')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'with a custom tag defined that uses the body method' do
|
40
|
+
setup do
|
41
|
+
Liquid::Template.register_tag('test', Evil::Plugin::Tag.from { |params|
|
42
|
+
times = params[:times] || 1
|
43
|
+
out = ''
|
44
|
+
times.times { |i| out << body(:i => i) }
|
45
|
+
out
|
46
|
+
})
|
47
|
+
end
|
48
|
+
|
49
|
+
should 'output the contents of the tag' do
|
50
|
+
template = Liquid::Template.parse('{% test %}a{% endtest %}')
|
51
|
+
|
52
|
+
assert_equal 'a', template.render
|
53
|
+
end
|
54
|
+
|
55
|
+
should 'remember the i variable passed to body' do
|
56
|
+
template = Liquid::Template.parse('{% test %}{{ i }}{% endtest %}')
|
57
|
+
|
58
|
+
assert_equal '0', template.render
|
59
|
+
end
|
60
|
+
|
61
|
+
should 'be different value of i for each repetition of body' do
|
62
|
+
template = Liquid::Template.parse('{% test times: 10 %}{{ i }}{% endtest %}')
|
63
|
+
|
64
|
+
assert_equal '0123456789', template.render
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'with 2 custom tags defined' do
|
69
|
+
setup do
|
70
|
+
Liquid::Template.register_tag('test', Evil::Plugin::Tag.from { |params|
|
71
|
+
times = params[:times] || 1
|
72
|
+
out = ''
|
73
|
+
times.times { |i| out << body(:i => i) }
|
74
|
+
out
|
75
|
+
})
|
76
|
+
|
77
|
+
Liquid::Template.register_tag('test2', Evil::Plugin::Tag.from { |params|
|
78
|
+
params[:a]
|
79
|
+
})
|
80
|
+
end
|
81
|
+
|
82
|
+
should 'be able to nest tags' do
|
83
|
+
template = Liquid::Template.parse("{% test times: 2 %}{% test2 a: 4 %}{% endtest2 %}{% endtest %}")
|
84
|
+
|
85
|
+
assert_equal '44', template.render
|
86
|
+
end
|
87
|
+
|
88
|
+
should 'be able to use vars from outer tag in inner tag' do
|
89
|
+
template = Liquid::Template.parse("{% test times: 2 %}{% test2 a: i %}{% endtest2 %}{% endtest %}")
|
90
|
+
|
91
|
+
assert_equal '01', template.render
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'with a custom tag with more than one parameter defined' do
|
96
|
+
setup do
|
97
|
+
Liquid::Template.register_tag('test', Evil::Plugin::Tag.from { |params|
|
98
|
+
[params[:a], params[:b]].join('|')
|
99
|
+
})
|
100
|
+
end
|
101
|
+
|
102
|
+
should 'output both parameters' do
|
103
|
+
template = Liquid::Template.parse("{% test a: 'g', b: 'a' %}{% endtest %}")
|
104
|
+
|
105
|
+
assert_equal 'g|a', template.render
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/views/_banner.haml
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
- if session[:identity_url]
|
2
|
+
#banner
|
3
|
+
%a{ :href => '/admin' }
|
4
|
+
%img#logo{ :src => '/images/logo.png', :alt => 'Evil' }
|
5
|
+
%form{ :method => 'post', :action => '/admin/openid/logout', :id => 'logout' }
|
6
|
+
Logged in as
|
7
|
+
%em= session[:identity_url]
|
8
|
+
%input.submit{ :type => 'submit', :value => 'Log out' }
|
data/views/_errors.haml
ADDED
data/views/index.haml
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
#overview
|
2
|
+
%table#template-overview
|
3
|
+
%thead
|
4
|
+
%tr.title
|
5
|
+
%th{ :colspan => 3 } Templates
|
6
|
+
%tr
|
7
|
+
%th Name
|
8
|
+
%th URL Pattern
|
9
|
+
%th TTL
|
10
|
+
%th
|
11
|
+
%tbody
|
12
|
+
- @templates.each_with_index do |template, i|
|
13
|
+
%tr{ :class => ('alt' if i % 2 == 1) }
|
14
|
+
%td= template.title
|
15
|
+
%td= template.route
|
16
|
+
%td= template.route.empty? ? 'N/A' : template.ttl
|
17
|
+
%td.tools
|
18
|
+
%a{ :href => "/admin/templates/#{template.id}"} Edit
|
19
|
+
%tfoot
|
20
|
+
%tr
|
21
|
+
%td{ :colspan => 4 }
|
22
|
+
%a{ :href => '/admin/templates/new' } Add Template...
|
23
|
+
|
24
|
+
%table#plugin-overview
|
25
|
+
%thead
|
26
|
+
%tr.title
|
27
|
+
%th{ :colspan => 3 } Plugin Configuration
|
28
|
+
%tr
|
29
|
+
%th Name
|
30
|
+
%th
|
31
|
+
%tbody
|
32
|
+
- @plugins.each_with_index do |plugin, i|
|
33
|
+
%tr{ :class => ('alt' if i % 2 == 1) }
|
34
|
+
%td= plugin
|
35
|
+
%td.tools
|
36
|
+
%a{ :href => "/admin/plugins/#{urlencode(plugin)}"} Edit
|
37
|
+
%tfoot
|
38
|
+
%tr
|
39
|
+
%td{ :colspan => 3 }
|
40
|
+
%a{ :href => '/admin/plugins/new' } Add Configuration...
|
41
|
+
|
data/views/layout.haml
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
!!!
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%title Evil Admin
|
5
|
+
%link{ :rel => 'stylesheet', :href => '/stylesheets/evil.css', :type => 'text/css' }
|
6
|
+
%body
|
7
|
+
= partial(:banner)
|
8
|
+
#content
|
9
|
+
= yield
|
10
|
+
%script{ :type => 'text/javascript', :src => 'http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js' }
|
11
|
+
%script{ :type => 'text/javascript', :src => '/javascripts/evil-lib.js' }
|
12
|
+
%script{ :type => 'text/javascript', :src => '/javascripts/evil.js' }
|
13
|
+
|
data/views/login.haml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
%p
|
2
|
+
%label{ :for => 'template_title' }
|
3
|
+
Title *
|
4
|
+
%input#template_title.text{ :name => 'template[title]', :value => @template.title }
|
5
|
+
%p
|
6
|
+
%label{ :for => 'template_route' }
|
7
|
+
Route
|
8
|
+
%input#template_route.text{ :name => 'template[route]', :value => @template.route }
|
9
|
+
%p
|
10
|
+
%label{ :for => 'template_source' }
|
11
|
+
Source *
|
12
|
+
%textarea#template_source{ :name => 'template[source]' }= @template.source
|
13
|
+
%p
|
14
|
+
%label{ :for => 'template_ttl' }
|
15
|
+
Expires every (seconds)
|
16
|
+
%input#template_ttl.text{ :name => 'template[ttl]', :value => @template.ttl || 600 }
|
17
|
+
%p
|
18
|
+
%label{ :for => 'template_content_type' }
|
19
|
+
Content Type
|
20
|
+
%input#template_content_type.short{ :name => 'template[content_type]', :value => @template.content_type || 'text/html' }
|
21
|
+
%input#template_encoding.short{ :name => 'template[encoding]', :value => @template.encoding || 'utf-8' }
|
22
|
+
%p
|
23
|
+
%input.submit{ :value => 'Save', :type => 'submit' }
|