caboose-cms 0.3.20 → 0.3.22
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 +8 -8
- data/app/controllers/caboose/ab_options_controller.rb +57 -0
- data/app/controllers/caboose/ab_variants_controller.rb +88 -0
- data/app/controllers/caboose/application_controller.rb +69 -3
- data/app/helpers/caboose/pages_helper.rb +5 -0
- data/app/models/caboose/ab_option.rb +7 -0
- data/app/models/caboose/ab_variant.rb +22 -0
- data/app/models/caboose/core_plugin.rb +6 -2
- data/app/models/caboose/schema.rb +8 -0
- data/app/models/caboose/utilities/schema.rb +8 -2
- data/app/views/caboose/ab_variants/admin_edit.html.erb +99 -0
- data/app/views/caboose/ab_variants/admin_index.html.erb +17 -0
- data/app/views/caboose/ab_variants/admin_new.html.erb +36 -0
- data/config/routes.rb +12 -0
- data/lib/caboose/version.rb +1 -1
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MzhlOGU4ZDRlZmYxZGIzODk0Zjk0NDhhM2IwYjM2ZTViMjlmZTA2ZA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
OWUwZmM5MjdkNmEwNWJkMWIzYjlkN2Q4NTBiMjliZmNkNDM5MzZiNQ==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YjNhYjE1MzU1ZmU4NTQzOWFjMDY5ZmVjM2UwY2NhMzFmNDViMjE0ZTBhY2Ux
|
10
|
+
NDA1ODFiMGQyZGMzNWQ1MTcxZjMxMGI1MjAzZDliYjNlYzdlNWE4YTY4Yzc0
|
11
|
+
OTRmMzkwMmFkODcxYmVkM2I5MzAzMmI1YWU2NDI3NDQwZjJmYWU=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZmQ2YTQ4N2Q4M2U3MGJkYWYwNmNhYjczZDU4YTEzZmYwODM2NDBhN2RlMDRm
|
14
|
+
NDBkMGU4ZGJiZDAxMjI2NWRkMGQzMjc2ZTVkOTQ5YTNiYWFkNTMwNjMyNmE5
|
15
|
+
MTg5N2M5Yjc4ZjY3Yjg3Y2FhOTkwMTY5M2Q3NGIxM2UyM2Q1N2Y=
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Caboose
|
2
|
+
class AbOptionsController < ApplicationController
|
3
|
+
layout 'caboose/admin'
|
4
|
+
|
5
|
+
# GET /admin/ab_variants/:variant_id/options
|
6
|
+
def admin_index
|
7
|
+
return unless user_is_allowed_to 'view', 'ab_variants'
|
8
|
+
v = AbVariant.find(params[:variant_id])
|
9
|
+
render :json => v.ab_options
|
10
|
+
end
|
11
|
+
|
12
|
+
# POST admin/ab-variants/:variant_id/options'
|
13
|
+
def admin_create
|
14
|
+
return unless user_is_allowed_to 'edit','ab_variants'
|
15
|
+
|
16
|
+
resp = StdClass.new({
|
17
|
+
'error' => nil,
|
18
|
+
'redirect' => nil
|
19
|
+
})
|
20
|
+
|
21
|
+
opt = AbOption.create(
|
22
|
+
:ab_variant_id => params[:variant_id],
|
23
|
+
:text => params[:text]
|
24
|
+
)
|
25
|
+
resp.redirect = "/admin/ab-variants/#{params[:variant_id]}"
|
26
|
+
render :json => resp
|
27
|
+
end
|
28
|
+
|
29
|
+
# PUT /admin/ab_options/:id
|
30
|
+
def admin_update
|
31
|
+
return unless user_is_allowed_to 'edit', 'ab_variants'
|
32
|
+
|
33
|
+
resp = StdClass.new
|
34
|
+
opt = AbOption.find(params[:id])
|
35
|
+
|
36
|
+
save = true
|
37
|
+
params.each do |k,v|
|
38
|
+
case k
|
39
|
+
when 'text'
|
40
|
+
opt.text = v
|
41
|
+
break
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
resp.success = save && opt.save
|
46
|
+
render :json => resp
|
47
|
+
end
|
48
|
+
|
49
|
+
# DELETE /admin/ab_options/:id
|
50
|
+
def admin_delete
|
51
|
+
return unless user_is_allowed_to 'delete', 'ab_variants'
|
52
|
+
AbOption.find(params[:id]).destroy
|
53
|
+
render :json => true
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Caboose
|
2
|
+
class AbVariantsController < ApplicationController
|
3
|
+
layout 'caboose/admin'
|
4
|
+
|
5
|
+
def before_action
|
6
|
+
@page = Page.page_with_uri('/admin')
|
7
|
+
end
|
8
|
+
|
9
|
+
# GET /admin/ab_variants
|
10
|
+
def admin_index
|
11
|
+
return unless user_is_allowed_to 'view', 'ab_variants'
|
12
|
+
|
13
|
+
@gen = PageBarGenerator.new(params, {'name' => '', 'analytics_name' => ''}, {
|
14
|
+
'model' => 'Caboose::AbVariant',
|
15
|
+
'sort' => 'name',
|
16
|
+
'desc' => 'false',
|
17
|
+
'base_url' => '/admin/ab-variants'
|
18
|
+
})
|
19
|
+
@variants = @gen.items
|
20
|
+
end
|
21
|
+
|
22
|
+
# GET /admin/ab_variants/new
|
23
|
+
def admin_new
|
24
|
+
return unless user_is_allowed_to 'add', 'ab_variants'
|
25
|
+
@variant = AbVariant.new
|
26
|
+
end
|
27
|
+
|
28
|
+
# GET /admin/ab_variants/:id
|
29
|
+
def admin_edit
|
30
|
+
return unless user_is_allowed_to 'edit', 'ab_variants'
|
31
|
+
@variant = AbVariant.find(params[:id])
|
32
|
+
end
|
33
|
+
|
34
|
+
# POST /admin/ab-variants
|
35
|
+
def admin_create
|
36
|
+
return unless user_is_allowed_to 'edit', 'ab_variants'
|
37
|
+
|
38
|
+
resp = StdClass.new({
|
39
|
+
'error' => nil,
|
40
|
+
'redirect' => nil
|
41
|
+
})
|
42
|
+
|
43
|
+
variant = AbVariant.new
|
44
|
+
variant.name = params[:name]
|
45
|
+
variant.analytics_name = params[:name].gsub(' ', '_').downcase
|
46
|
+
|
47
|
+
if (variant.name.length == 0)
|
48
|
+
resp.error = "A name is required."
|
49
|
+
elsif variant.save
|
50
|
+
resp.redirect = "/admin/ab-variants/#{variant.id}"
|
51
|
+
end
|
52
|
+
|
53
|
+
render json: resp
|
54
|
+
end
|
55
|
+
|
56
|
+
# PUT /admin/ab_variants/:id
|
57
|
+
def admin_update
|
58
|
+
return unless user_is_allowed_to 'edit', 'ab_variants'
|
59
|
+
|
60
|
+
resp = StdClass.new
|
61
|
+
variant = AbVariant.find(params[:id])
|
62
|
+
|
63
|
+
save = true
|
64
|
+
params.each do |k,v|
|
65
|
+
case k
|
66
|
+
when 'name'
|
67
|
+
variant.name = v
|
68
|
+
break
|
69
|
+
when 'analytics_name'
|
70
|
+
variant.analytics_name = v
|
71
|
+
break
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
resp.success = save && variant.save
|
76
|
+
render :json => resp
|
77
|
+
end
|
78
|
+
|
79
|
+
# DELETE /admin/ab_variants/:id
|
80
|
+
def admin_destroy
|
81
|
+
return unless user_is_allowed_to 'delete', 'ab_variants'
|
82
|
+
AbVariants.find(params[:id]).destroy
|
83
|
+
resp = StdClass.new('redirect' => '/admin/ab-variants')
|
84
|
+
render :json => resp
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
@@ -13,6 +13,7 @@ module Caboose
|
|
13
13
|
@page = Page.page_with_uri(request.fullpath)
|
14
14
|
|
15
15
|
session['use_redirect_urls'] = true if session['use_redirect_urls'].nil?
|
16
|
+
assign_ab_variants
|
16
17
|
|
17
18
|
@crumb_trail = Caboose::Page.crumb_trail(@page)
|
18
19
|
@subnav = {}
|
@@ -23,10 +24,10 @@ module Caboose
|
|
23
24
|
|
24
25
|
# Sets an instance variable of the logged in user
|
25
26
|
@logged_in_user = logged_in_user
|
26
|
-
|
27
|
+
|
27
28
|
before_action
|
28
29
|
end
|
29
|
-
|
30
|
+
|
30
31
|
# Parses any parameters in the URL and adds them to the params
|
31
32
|
def parse_url_params
|
32
33
|
return if !Caboose.use_url_params
|
@@ -96,6 +97,8 @@ module Caboose
|
|
96
97
|
return session["app_user"]
|
97
98
|
end
|
98
99
|
|
100
|
+
# DEPRECATED: Use user_is_allowed_to(action, resource)
|
101
|
+
#
|
99
102
|
# Checks to see if a user has permission to perform the given action
|
100
103
|
# on the given resource.
|
101
104
|
# Redirects to login if not logged in.
|
@@ -115,7 +118,31 @@ module Caboose
|
|
115
118
|
|
116
119
|
return true
|
117
120
|
end
|
118
|
-
|
121
|
+
|
122
|
+
# Checks to see if a user has permission
|
123
|
+
# to perform action on resource
|
124
|
+
#
|
125
|
+
# Redirects to login if not logged in
|
126
|
+
# Redirects to error page with message if not allowed
|
127
|
+
#
|
128
|
+
# useful for creating super-readable code, for example:
|
129
|
+
# > return unless user_is_allowed_to 'edit', 'pages'
|
130
|
+
# Even your mom could read that code.
|
131
|
+
def user_is_allowed_to(action, resource)
|
132
|
+
unless logged_in?
|
133
|
+
redirect_to "/login?return_url=" + URI.encode(request.fullpath)
|
134
|
+
return false
|
135
|
+
end
|
136
|
+
|
137
|
+
@user = logged_in_user
|
138
|
+
unless @user.is_allowed(resource, action)
|
139
|
+
@error = "You don't have permission to #{action} #{resource}"
|
140
|
+
render :template => "caboose/extras/error"
|
141
|
+
return false
|
142
|
+
end
|
143
|
+
return true
|
144
|
+
end
|
145
|
+
|
119
146
|
# Redirects to login if not logged in.
|
120
147
|
def verify_logged_in
|
121
148
|
if (!logged_in?)
|
@@ -147,5 +174,44 @@ module Caboose
|
|
147
174
|
return "" if v.nil?
|
148
175
|
return v.val
|
149
176
|
end
|
177
|
+
|
178
|
+
#===========================================================================
|
179
|
+
# AB Testing
|
180
|
+
#===========================================================================
|
181
|
+
|
182
|
+
# Sets the ab_variants for the user's session
|
183
|
+
def assign_ab_variants
|
184
|
+
return if session['ab_variants']
|
185
|
+
|
186
|
+
h = {}
|
187
|
+
arr = []
|
188
|
+
AbVariant.find_each do |var|
|
189
|
+
next if var.ab_options.nil? || var.ab_options.count == 0
|
190
|
+
i = rand(var.ab_options.count)
|
191
|
+
h[var.analytics_name] = var.ab_options[i].text
|
192
|
+
arr << "#{var.analytics_name}=#{i+1}"
|
193
|
+
end
|
194
|
+
session['ab_variants'] = h
|
195
|
+
session['ab_variants_analytics_string'] = "|#{arr.join('|')}|"
|
196
|
+
end
|
197
|
+
|
198
|
+
# Get the variant option text for the given variant name.
|
199
|
+
def ab_option_for(analytics_name)
|
200
|
+
assign_ab_variants if session['ab_variants'].nil?
|
201
|
+
return session['ab_variants'][analytics_name] if !session['ab_variants'][analytics_name].nil?
|
202
|
+
|
203
|
+
# Otherwise, add the new variant to the session
|
204
|
+
var = AbVariant.find(:analytics_name => analytics_name).first
|
205
|
+
i = rand(var.ab_options.count)
|
206
|
+
session['ab_variants'][var.analytics_name] = var.ab_options[i].text
|
207
|
+
session['ab_variants_analytics_string'] << "#{var.analytics_name}=#{i+1}|"
|
208
|
+
end
|
209
|
+
|
210
|
+
# Gets the string to be sent to google analytics
|
211
|
+
def analytics_string
|
212
|
+
assign_ab_variants if session['ab_variants_analytics_string'].nil?
|
213
|
+
return "#{session['ab_variants_analytics_string']}"
|
214
|
+
end
|
215
|
+
|
150
216
|
end
|
151
217
|
end
|
@@ -20,5 +20,10 @@ module Caboose
|
|
20
20
|
return str
|
21
21
|
end
|
22
22
|
|
23
|
+
def ab_variants_analytics_code
|
24
|
+
str = session['ab_variants_analytics_string']
|
25
|
+
return "var _gaq = _gaq || [];\n_gaq.push(['_setCustomVar', 1, 'caboose_ab_variants', #{Caboose.json(str)}]);"
|
26
|
+
end
|
27
|
+
|
23
28
|
end
|
24
29
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Class for A-B testing variants. A variant is a set of changes
|
2
|
+
# to the same element on a page. For example, a variant can be used
|
3
|
+
# to change the button text, or images displayed, or even more
|
4
|
+
# complicated behavior
|
5
|
+
class Caboose::AbVariant < ActiveRecord::Base
|
6
|
+
self.table_name = "ab_variants"
|
7
|
+
|
8
|
+
has_many :ab_options, :order => 'id', :dependent => :destroy
|
9
|
+
attr_accessible :name, :analytics_name
|
10
|
+
|
11
|
+
def get_session_option
|
12
|
+
return "" unless self.ab_options
|
13
|
+
opt = self.ab_options.sample
|
14
|
+
return {text: opt.text, id: opt.id}
|
15
|
+
end
|
16
|
+
|
17
|
+
#def random_option
|
18
|
+
# return nil self.ab_options.nil? || self.ab_options.count == 0
|
19
|
+
# return self.ab_options.sample
|
20
|
+
#end
|
21
|
+
|
22
|
+
end
|
@@ -20,12 +20,13 @@ class Caboose::CorePlugin < Caboose::CaboosePlugin
|
|
20
20
|
'text' => 'Settings',
|
21
21
|
'children' => []
|
22
22
|
}
|
23
|
-
|
23
|
+
|
24
24
|
item['children'] << { 'id' => 'users' , 'text' => 'Users' , 'href' => '/admin/users' , 'modal' => false } if user.is_allowed('users' , 'view')
|
25
25
|
item['children'] << { 'id' => 'roles' , 'text' => 'Roles' , 'href' => '/admin/roles' , 'modal' => false } if user.is_allowed('roles' , 'view')
|
26
26
|
item['children'] << { 'id' => 'permissions' , 'text' => 'Permissions' , 'href' => '/admin/permissions' , 'modal' => false } if user.is_allowed('permissions' , 'view')
|
27
|
+
item['children'] << { 'id' => 'blocktypes' , 'text' => 'AB Test Variants' , 'href' => '/admin/ab-variants' , 'modal' => false } if user.is_allowed('abvariants' , 'view')
|
27
28
|
item['children'] << { 'id' => 'variables' , 'text' => 'Variables' , 'href' => '/admin/settings' , 'modal' => false } if user.is_allowed('settings' , 'view')
|
28
|
-
item['children'] << { 'id' => 'blocktypes' , 'text' => 'Page Block Types' , 'href' => '/admin/page-block-types' , 'modal' => false } if user.is_allowed('pageblocktypes' , 'view')
|
29
|
+
item['children'] << { 'id' => 'blocktypes' , 'text' => 'Page Block Types' , 'href' => '/admin/page-block-types' , 'modal' => false } if user.is_allowed('pageblocktypes' , 'view')
|
29
30
|
|
30
31
|
nav << item if item['children'].count > 0
|
31
32
|
|
@@ -39,6 +40,9 @@ class Caboose::CorePlugin < Caboose::CaboosePlugin
|
|
39
40
|
item['children'] << { 'id' => 'posts' , 'text' => 'Posts' , 'href' => '/admin/posts' , 'modal' => false } if user.is_allowed('posts' , 'view')
|
40
41
|
|
41
42
|
nav << item if item['children'].count > 0
|
43
|
+
if user.is_allowed('ab-variants','view')
|
44
|
+
nav << { 'id' => 'ab_variants', 'text' => 'AB Testing', 'href' => '/admin/ab-variants', 'modal' => false }
|
45
|
+
end
|
42
46
|
return nav
|
43
47
|
end
|
44
48
|
|
@@ -143,6 +143,14 @@ class Caboose::Schema < Caboose::Utilities::Schema
|
|
143
143
|
[ :page_id , :integer ],
|
144
144
|
[ :action , :string ]
|
145
145
|
],
|
146
|
+
Caboose::AbVariant => [
|
147
|
+
[ :name , :string ],
|
148
|
+
[ :analytics_name , :string ],
|
149
|
+
],
|
150
|
+
Caboose::AbOption => [
|
151
|
+
[ :text , :string ],
|
152
|
+
[ :ab_variant_id , :integer ]
|
153
|
+
],
|
146
154
|
Caboose::DatabaseSession => [
|
147
155
|
[ :session_id , :string , :null => false ],
|
148
156
|
[ :data , :text ],
|
@@ -45,11 +45,17 @@ class Caboose::Utilities::Schema
|
|
45
45
|
c = ActiveRecord::Base.connection
|
46
46
|
self.schema.each do |model, columns|
|
47
47
|
tbl = model.table_name
|
48
|
-
|
48
|
+
puts "Creating table #{tbl}..."
|
49
49
|
c.create_table tbl if !c.table_exists?(tbl)
|
50
50
|
columns.each do |col|
|
51
|
-
|
51
|
+
puts "Creating column #{tbl}.#{col[0]}..."
|
52
52
|
|
53
|
+
# Special case for attachments
|
54
|
+
if col[1] == :attachment
|
55
|
+
c.add_attachment tbl, col[1] if !c.column_exists?(tbl, "#{col[1]}_file_size")
|
56
|
+
next
|
57
|
+
end
|
58
|
+
|
53
59
|
# Skip if the column exists with the proper data type
|
54
60
|
next if c.column_exists?(tbl, col[0], col[1])
|
55
61
|
|
@@ -0,0 +1,99 @@
|
|
1
|
+
<h1>Editing AB Test Variant</h1>
|
2
|
+
|
3
|
+
<div id="abvariant_<%= @variant.id %>_name"></div>
|
4
|
+
<div id="abvariant_<%= @variant.id %>_analytics_name"></div>
|
5
|
+
|
6
|
+
<p>Google analytics search term: <code>caboose_ab_variants="*|<%= @variant.analytics_name %>=1|*"</code></p>
|
7
|
+
<h2>Options</h2>
|
8
|
+
<% if @variant.ab_options && @variant.ab_options.count > 0 %>
|
9
|
+
<table>
|
10
|
+
<% @variant.ab_options.each do |opt| %>
|
11
|
+
<tr>
|
12
|
+
<td><div id="aboption_<%= opt.id %>_text"></div></td>
|
13
|
+
<td><input type='button' value='Delete' onclick="delete_option(<%= opt.id %>);" /></td>
|
14
|
+
</tr>
|
15
|
+
<% end %>
|
16
|
+
</table>
|
17
|
+
<% else %>
|
18
|
+
<p>This variant doesn't have any options.</p>
|
19
|
+
<% end %>
|
20
|
+
|
21
|
+
<div id="message"></div>
|
22
|
+
<p>
|
23
|
+
<input type='button' value='Back' onclick="window.location='/admin/ab-variants';" >
|
24
|
+
<input type='button' value='Add New Option' onclick="add_option();" >
|
25
|
+
</p>
|
26
|
+
|
27
|
+
<% content_for :caboose_js do %>
|
28
|
+
<%= javascript_include_tag "caboose/model/all" %>
|
29
|
+
<script type="text/javascript">
|
30
|
+
|
31
|
+
function delete_option(option_id, confirm)
|
32
|
+
{
|
33
|
+
if (!confirm)
|
34
|
+
{
|
35
|
+
var p = $('<p/>').addClass('note warning')
|
36
|
+
.append("Are you sure you want to delete the option? ")
|
37
|
+
.append($('<input/>').attr('type','button').val('Yes').click(function() { delete_option(option_id, true); })).append(' ')
|
38
|
+
.append($('<input/>').attr('type','button').val('No').click(function() { $('#message').empty(); }));
|
39
|
+
$('#message').empty().append(p);
|
40
|
+
return;
|
41
|
+
}
|
42
|
+
$('#message').empty().html($('<p/>').addClass('loading').html("Deleting option..."));
|
43
|
+
$.ajax({
|
44
|
+
url: '/admin/ab-options/' + option_id,
|
45
|
+
type: 'delete',
|
46
|
+
success: function(resp) {
|
47
|
+
if (resp.error) $('#message').html("<p class='note error'>" + resp.error + "</p>");
|
48
|
+
else window.location.reload(true);
|
49
|
+
}
|
50
|
+
});
|
51
|
+
}
|
52
|
+
|
53
|
+
function add_option() {
|
54
|
+
$('#message').html("<p class='loading'>Adding new A/B Option...</p>");
|
55
|
+
$.ajax({
|
56
|
+
url: '/admin/ab-variants/<%= @variant.id %>/options',
|
57
|
+
type: 'post',
|
58
|
+
data: {
|
59
|
+
text: ""
|
60
|
+
},
|
61
|
+
success: function(resp) {
|
62
|
+
if (resp.error) $('#message').html("<p class='note error'>" + resp.error + "</p>");
|
63
|
+
if (resp.redirect) window.location.reload(true);
|
64
|
+
}
|
65
|
+
});
|
66
|
+
}
|
67
|
+
|
68
|
+
$(document).ready(function() {
|
69
|
+
|
70
|
+
m = new ModelBinder({
|
71
|
+
name: 'abvariant',
|
72
|
+
id: <%= @variant.id %>,
|
73
|
+
update_url: '/admin/ab-variants/<%= @variant.id %>',
|
74
|
+
authenticity_token: '<%= form_authenticity_token %>',
|
75
|
+
attributes: [
|
76
|
+
{ name: 'name' , nice_name: 'Variant Name' , type: 'text', value: <%= raw Caboose.json(@variant.name) %> , width: 800 },
|
77
|
+
{ name: 'analytics_name' , nice_name: 'Google Analytics Name' , type: 'text', value: <%= raw Caboose.json(@variant.analytics_name) %> , width: 800 }
|
78
|
+
]
|
79
|
+
});
|
80
|
+
|
81
|
+
<% if @variant.ab_options && @variant.ab_options.count > 0 %>
|
82
|
+
<% i = 1 %>
|
83
|
+
<% @variant.ab_options.each do |opt| %>
|
84
|
+
m = new ModelBinder({
|
85
|
+
name: 'aboption',
|
86
|
+
id: <%= opt.id %>,
|
87
|
+
update_url: '/admin/ab-options/<%= opt.id %>',
|
88
|
+
authenticity_token: '<%= form_authenticity_token %>',
|
89
|
+
attributes: [
|
90
|
+
{ name: 'text', nice_name: 'Option <%= i %>', type: 'text', value: <%= raw Caboose.json(opt.text) %> , width: 800 }
|
91
|
+
]
|
92
|
+
});
|
93
|
+
<% i = i + 1 %>
|
94
|
+
<% end %>
|
95
|
+
<% end %>
|
96
|
+
});
|
97
|
+
|
98
|
+
</script>
|
99
|
+
<% end %>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<h1>A/B Test Variants</h1>
|
2
|
+
|
3
|
+
<p><a href='/admin/ab-variants/new'>New Variant</a></p>
|
4
|
+
<% if (@variants.count > 0) %>
|
5
|
+
<table class='data'>
|
6
|
+
<tr><%= raw @gen.sortable_table_headings({'name' => 'Variant Name', 'analytics_name' => 'Analytics Name'}) %></tr>
|
7
|
+
<% @variants.each do |v| %>
|
8
|
+
<tr onclick="window.location='/admin/ab-variants/<%= v.id %>';">
|
9
|
+
<td><%= v.name %></td>
|
10
|
+
<td><%= v.analytics_name %></td>
|
11
|
+
</tr>
|
12
|
+
<% end %>
|
13
|
+
</table>
|
14
|
+
<p><%= raw @gen.generate %></p>
|
15
|
+
<% else %>
|
16
|
+
<p>No A/B variants found.</p>
|
17
|
+
<% end %>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<h1>New AB Test</h1>
|
2
|
+
|
3
|
+
<form action='/admin/ab-variants' method='post' id='ab_variant_form'>
|
4
|
+
<input type='hidden' name='authenticity_token' value='<%=form_authenticity_token %>'>
|
5
|
+
<p><input type='text' name='name' id='name' placeholder='AB Variant Name' style='width: 500px;'></p>
|
6
|
+
<div id='message'></div>
|
7
|
+
<p>
|
8
|
+
<input type='button' value='< Back' onclick="window.location='/admin/ab-variants';">
|
9
|
+
<input type='submit' value='Add New A/B Variant' onclick="add_ab_variant(); return false;">
|
10
|
+
</p>
|
11
|
+
</form>
|
12
|
+
|
13
|
+
<% content_for :caboose_js do %>
|
14
|
+
<script type='text/javascript'>
|
15
|
+
|
16
|
+
function add_ab_variant()
|
17
|
+
{
|
18
|
+
$('#message').html("<p class='loading'>Adding A/B Variant...</p>");
|
19
|
+
$.ajax({
|
20
|
+
url: '/admin/ab-variants',
|
21
|
+
type: 'post',
|
22
|
+
data: $('#ab_variant_form').serialize(),
|
23
|
+
success: function(resp) {
|
24
|
+
if (resp.error) $('#message').html("<p class='note error'>" + resp.error + "</p>");
|
25
|
+
if (resp.redirect) window.location = resp.redirect;
|
26
|
+
}
|
27
|
+
});
|
28
|
+
}
|
29
|
+
|
30
|
+
var modal = false;
|
31
|
+
$(window).load(function() {
|
32
|
+
modal = new CabooseModal(800);
|
33
|
+
});
|
34
|
+
|
35
|
+
</script>
|
36
|
+
<% end %>
|
data/config/routes.rb
CHANGED
@@ -115,6 +115,18 @@ Caboose::Engine.routes.draw do
|
|
115
115
|
get "admin/posts" => "posts#admin_index"
|
116
116
|
post "admin/posts" => "posts#admin_add"
|
117
117
|
delete "admin/posts/:id" => "posts#admin_delete"
|
118
|
+
|
119
|
+
get "admin/ab-variants" => "ab_variants#admin_index"
|
120
|
+
get "admin/ab-variants/new" => "ab_variants#admin_new"
|
121
|
+
get "admin/ab-variants/:id" => "ab_variants#admin_edit"
|
122
|
+
put "admin/ab-variants/:id" => "ab_variants#admin_update"
|
123
|
+
post "admin/ab-variants" => "ab_variants#admin_create"
|
124
|
+
delete "admin/ab-variants/:id" => "ab_variants#admin_delete"
|
125
|
+
|
126
|
+
get "admin/ab-variants/:variant_id/options" => "ab_options#admin_index"
|
127
|
+
put "admin/ab-options/:id" => "ab_options#admin_update"
|
128
|
+
post "admin/ab-variants/:variant_id/options" => "ab_options#admin_create"
|
129
|
+
delete "admin/ab-options/:id" => "ab_options#admin_delete"
|
118
130
|
|
119
131
|
match '*path' => 'pages#show'
|
120
132
|
root :to => 'pages#show'
|
data/lib/caboose/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: caboose-cms
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.22
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- William Barry
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-01-
|
11
|
+
date: 2014-01-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -166,6 +166,8 @@ files:
|
|
166
166
|
- app/assets/stylesheets/caboose/station_modal.css
|
167
167
|
- app/assets/stylesheets/caboose/station_sidebar.css
|
168
168
|
- app/assets/stylesheets/caboose/tinymce.css
|
169
|
+
- app/controllers/caboose/ab_options_controller.rb
|
170
|
+
- app/controllers/caboose/ab_variants_controller.rb
|
169
171
|
- app/controllers/caboose/admin_controller.rb
|
170
172
|
- app/controllers/caboose/application_controller.rb
|
171
173
|
- app/controllers/caboose/login_controller.rb
|
@@ -186,6 +188,8 @@ files:
|
|
186
188
|
- app/helpers/caboose/pages_helper.rb
|
187
189
|
- app/helpers/caboose/permissions_helper.rb
|
188
190
|
- app/helpers/caboose/products_helper.rb
|
191
|
+
- app/models/caboose/ab_option.rb
|
192
|
+
- app/models/caboose/ab_variant.rb
|
189
193
|
- app/models/caboose/approval_request.rb
|
190
194
|
- app/models/caboose/asset.rb
|
191
195
|
- app/models/caboose/authenticator.rb
|
@@ -221,6 +225,9 @@ files:
|
|
221
225
|
- app/models/caboose/std_class.rb
|
222
226
|
- app/models/caboose/user.rb
|
223
227
|
- app/models/caboose/utilities/schema.rb
|
228
|
+
- app/views/caboose/ab_variants/admin_edit.html.erb
|
229
|
+
- app/views/caboose/ab_variants/admin_index.html.erb
|
230
|
+
- app/views/caboose/ab_variants/admin_new.html.erb
|
224
231
|
- app/views/caboose/admin/index.html.erb
|
225
232
|
- app/views/caboose/application/show.html.erb
|
226
233
|
- app/views/caboose/extras/error.html.erb
|