phaseout 0.0.1.danger.very.unstable → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.mdown +3 -0
- data/app/assets/javascripts/phaseout/application.js.erb +126 -0
- data/app/assets/javascripts/phaseout/templates/action_key_field.jst.eco +9 -0
- data/app/assets/javascripts/phaseout/templates/action_key_item.jst.eco +20 -0
- data/app/assets/javascripts/phaseout/templates/action_key_list.jst.eco +3 -0
- data/app/assets/javascripts/phaseout/templates/action_list.jst.eco +3 -0
- data/app/assets/javascripts/phaseout/templates/action_list_item.jst.eco +8 -0
- data/app/assets/stylesheets/phaseout/application.css.scss +150 -0
- data/app/controllers/phaseout/phaseout_controller.rb +64 -1
- data/app/views/layouts/phaseout/application.html.erb +1 -1
- data/app/views/phaseout/phaseout/index.html.erb +3 -1
- data/config/locales/phaseout.yml +36 -0
- data/config/routes.rb +5 -0
- data/lib/phaseout.rb +8 -3
- data/lib/phaseout/handler.rb +7 -7
- data/lib/phaseout/seo.rb +9 -5
- data/lib/phaseout/seo_action.rb +68 -0
- data/lib/phaseout/seo_fields.rb +40 -23
- data/lib/phaseout/version.rb +1 -1
- data/phaseout.gemspec +3 -0
- metadata +41 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 19abad5ab2f05d4cff49768c76f08060c0af15a4
|
4
|
+
data.tar.gz: 32139d3c6d63428be616303683674e8b1719481e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b00fcf4de916f4677457785bdd9960e00b4518bb67c4418c87ed20023468e9f010773efef5412af983c7bf5c1877ddfff078e0e3caa953e535c19710d0eabb8a
|
7
|
+
data.tar.gz: 87b06a3a15305892f7e9e23c35a9e0ca020210a4ef95ff5daaa195ea8dc060cc61f1f8a0a3769f9d98df3e50952213456e04dfb09df72ae246d01150de070197
|
data/README.mdown
CHANGED
@@ -9,7 +9,10 @@ We are drafting our API, so no tests where written yet, and everything can break
|
|
9
9
|
Add this line to your application's Gemfile:
|
10
10
|
|
11
11
|
```ruby
|
12
|
+
source 'https://rails-assets.org'
|
13
|
+
|
12
14
|
gem 'phaseout'
|
15
|
+
gem 'rails-assets-underscore'
|
13
16
|
```
|
14
17
|
|
15
18
|
And then execute:
|
@@ -0,0 +1,126 @@
|
|
1
|
+
//= require jquery
|
2
|
+
//= require jquery_ujs
|
3
|
+
//= require underscore
|
4
|
+
//= require_tree ./templates
|
5
|
+
|
6
|
+
// TODO: These route methods works, but they're ugly!
|
7
|
+
function seo_action_keys_path(key){
|
8
|
+
var path = "<%= Phaseout::Engine.routes.url_helpers.seo_action_keys_path('PHASEOUT_ACTION_KEY') %>";
|
9
|
+
return path.replace( 'PHASEOUT_ACTION_KEY', key.replace('#', '\%23') );
|
10
|
+
}
|
11
|
+
|
12
|
+
function seo_fields_update_path(key){
|
13
|
+
var path = "<%= Phaseout::Engine.routes.url_helpers.seo_fields_update_path('PHASEOUT_ACTION_KEY') %>";
|
14
|
+
return path.replace( 'PHASEOUT_ACTION_KEY', key.replace('#', '\%23') );
|
15
|
+
}
|
16
|
+
|
17
|
+
function seo_fields_delete_path(key){
|
18
|
+
var path = "<%= Phaseout::Engine.routes.url_helpers.seo_fields_delete_path('PHASEOUT_ACTION_KEY') %>";
|
19
|
+
return path.replace( 'PHASEOUT_ACTION_KEY', key.replace('#', '\%23') );
|
20
|
+
}
|
21
|
+
|
22
|
+
function seo_action_list_path(){
|
23
|
+
return "<%= Phaseout::Engine.routes.url_helpers.seo_action_list_path %>";
|
24
|
+
}
|
25
|
+
|
26
|
+
var PhaseoutTranslations = <%= I18n.t('seo').to_json %>;
|
27
|
+
var PhaseoutFields = <%= Hash[ Phaseout.default_fields.map{ |field| [field, I18n.t( "seo.fields.#{field}" )] } ].to_json %>;
|
28
|
+
|
29
|
+
function click_on_action_key_handler(_action_key){
|
30
|
+
var action_key = _action_key;
|
31
|
+
var action_key_html_id = [action_key['action_id'], action_key['id']].join('_');
|
32
|
+
var item = $('#'+action_key_html_id);
|
33
|
+
var fields_form = item.children('.action_key_fields');
|
34
|
+
|
35
|
+
$('#'+action_key_html_id+' .seo_action_key_link').click((function(){
|
36
|
+
return function(){
|
37
|
+
fields_form.toggle();
|
38
|
+
item.toggleClass('opened');
|
39
|
+
};
|
40
|
+
})());
|
41
|
+
|
42
|
+
fields_form[0].action_key = action_key;
|
43
|
+
fields_form.on('ajax:success', function(xhr, response_data, status){
|
44
|
+
fields_form[0].action_key = response_data;
|
45
|
+
});
|
46
|
+
|
47
|
+
$('#'+action_key_html_id+'_delete').on('ajax:success', function(xhr, response_data, status){
|
48
|
+
$('#'+action_key_html_id).remove();
|
49
|
+
if( $('#'+action_key['action_id']+' .action_key_list li').length == 0 ){
|
50
|
+
$('#'+action_key['action_id']).remove();
|
51
|
+
}
|
52
|
+
});
|
53
|
+
|
54
|
+
$('#'+action_key_html_id+'_button').click(function(){
|
55
|
+
var field_key = $('#'+action_key_html_id+' option:selected').attr('value');
|
56
|
+
|
57
|
+
if( field_key == 'other' ){
|
58
|
+
field_key = window.prompt(PhaseoutTranslations.common.add_prompt);
|
59
|
+
if( field_key == null ){ return null; }
|
60
|
+
}
|
61
|
+
|
62
|
+
if( $('#'+action_key_html_id+'_'+field_key).length > 0 ){
|
63
|
+
alert(PhaseoutTranslations.common.already_added);
|
64
|
+
} else {
|
65
|
+
var template_data = {
|
66
|
+
key: field_key,
|
67
|
+
field: '',
|
68
|
+
action_key: fields_form[0].action_key
|
69
|
+
}
|
70
|
+
fields_form.children('.seo_form_fields_list').append( JST['phaseout/templates/action_key_field'](template_data) );
|
71
|
+
}
|
72
|
+
})
|
73
|
+
}
|
74
|
+
|
75
|
+
function load_action_keys(key, html_id){
|
76
|
+
$.ajax({
|
77
|
+
url: seo_action_keys_path(key),
|
78
|
+
type: 'GET',
|
79
|
+
dataType: 'json',
|
80
|
+
success: function(data){
|
81
|
+
var action_keys = _.sortBy(data, function(obj){ return obj['name']; });
|
82
|
+
$('#'+html_id+' ul').append(JST['phaseout/templates/action_key_list']({ action_keys: action_keys }));
|
83
|
+
for( var index in action_keys ){ click_on_action_key_handler(action_keys[index]); }
|
84
|
+
}
|
85
|
+
});
|
86
|
+
}
|
87
|
+
|
88
|
+
function click_on_action_handler(_action){
|
89
|
+
var action = _action;
|
90
|
+
var header = $('#'+action['id']+'.seo_action_item');
|
91
|
+
var list = $('#'+action['id']+' ul.action_key_list');
|
92
|
+
$('#'+_action['id']+' .seo_action_item_link').click((function(){
|
93
|
+
return function(){
|
94
|
+
if( list.fecthedData ){
|
95
|
+
list.toggle();
|
96
|
+
list.toggleClass('opened');
|
97
|
+
header.toggleClass('opened');
|
98
|
+
} else {
|
99
|
+
header.addClass('opened');
|
100
|
+
list.addClass('opened');
|
101
|
+
list.show();
|
102
|
+
list.fecthedData = true;
|
103
|
+
load_action_keys(action['key'], action['id']);
|
104
|
+
}
|
105
|
+
};
|
106
|
+
})());
|
107
|
+
}
|
108
|
+
|
109
|
+
function load_actions(){
|
110
|
+
$.ajax({
|
111
|
+
url: seo_action_list_path(),
|
112
|
+
type: 'GET',
|
113
|
+
dataType: 'json',
|
114
|
+
success: function(data){
|
115
|
+
var actions = _.sortBy(data, function(obj){ return obj['name']; });
|
116
|
+
$('.seo_action_list').append(JST['phaseout/templates/action_list']({ actions: actions }));
|
117
|
+
for( var index in actions ){ click_on_action_handler(actions[index]); }
|
118
|
+
}
|
119
|
+
});
|
120
|
+
|
121
|
+
$(document).delegate('a[data-delete-field]', 'click', function(){
|
122
|
+
$('#' + $(this).data('delete-field')).remove();
|
123
|
+
});
|
124
|
+
}
|
125
|
+
|
126
|
+
$(document).ready(function(){ load_actions() });
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<li id="<%- @action_key.action_id %>_<%- @action_key.id %>_<%- @key %>" class="seo_field_item">
|
2
|
+
<label for="<%- @action_key.action_id %>_<%- @action_key.id %>_<%- @key %>_textarea">
|
3
|
+
<%- PhaseoutFields[@key] || @key %>
|
4
|
+
</label>
|
5
|
+
<textarea id="<%- @action_key.action_id %>_<%- @action_key.id %>_<%- @key %>_textarea" name="seo_field[<%- @key %>]"><%- @field %></textarea>
|
6
|
+
<a href="javascript:void(0)" class="delete_field" data-delete-field="<%- @action_key.action_id %>_<%- @action_key.id %>_<%- @key %>" data-confirm="<%- PhaseoutTranslations.common.are_you_sure %>">
|
7
|
+
<%- PhaseoutTranslations.common.delete %>
|
8
|
+
</a>
|
9
|
+
</li>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<li id="<%- @action_id %>_<%- @id %>" class="seo_action_key_item">
|
2
|
+
<a id="<%- @action_id %>_<%- @id %>_delete" href="<%- seo_fields_delete_path @key %>" class="seo_action_key_delete" data-method="delete" data-remote="true"><%- PhaseoutTranslations.common.delete %> [X]</a>
|
3
|
+
<a id="<%- @action_id %>_<%- @id %>_link" href="javascript:void(0)" class="seo_action_key_link"><%- @name %></a>
|
4
|
+
<form action="<%- seo_fields_update_path @key %>" class="action_key_fields" style="display: none" data-method="put" data-remote="true">
|
5
|
+
<ul class="seo_form_fields_list">
|
6
|
+
<% for key, field of @fields: %>
|
7
|
+
<%- JST['phaseout/templates/action_key_field'](action_key: this, key: key, field: field) %>
|
8
|
+
<% end %>
|
9
|
+
</ul>
|
10
|
+
<div class="seo_fields_buttons">
|
11
|
+
<select class="seo_fields_to_add">
|
12
|
+
<% for field_method, humanized_field of PhaseoutFields : %>
|
13
|
+
<option value="<%- field_method %>"><%- humanized_field %></option>
|
14
|
+
<% end %>
|
15
|
+
</select>
|
16
|
+
<input id="<%- @action_id %>_<%- @id %>_button" type="button" value="<%- PhaseoutTranslations.common.add %>" class="seo_fields_add_button"/>
|
17
|
+
<input type="submit" value="<%- PhaseoutTranslations.common.update %>" class="submit_seo_fields"/>
|
18
|
+
</div>
|
19
|
+
</form>
|
20
|
+
</li>
|
@@ -0,0 +1,150 @@
|
|
1
|
+
body {
|
2
|
+
margin: 0px;
|
3
|
+
padding: 0px;
|
4
|
+
background: #EEFFEE;
|
5
|
+
}
|
6
|
+
|
7
|
+
h1 {
|
8
|
+
margin: 0px;
|
9
|
+
padding: 5px 40px;
|
10
|
+
font: 16pt Arial normal;
|
11
|
+
color: #EEFFEE;
|
12
|
+
background: #003300;
|
13
|
+
}
|
14
|
+
|
15
|
+
.seo_action_list {
|
16
|
+
margin: 20px 20px;
|
17
|
+
padding: 0px;
|
18
|
+
list-style: none;
|
19
|
+
font: 10pt Verdana normal;
|
20
|
+
}
|
21
|
+
|
22
|
+
.seo_action_item {
|
23
|
+
margin: 0px;
|
24
|
+
padding: 0px;
|
25
|
+
background: #CCFFCC;
|
26
|
+
|
27
|
+
h3 {
|
28
|
+
margin: 5px 0px;
|
29
|
+
padding: 7px 20px;
|
30
|
+
font-size: 12pt;
|
31
|
+
font-weight: normal;
|
32
|
+
background: #AACCAA;
|
33
|
+
a {
|
34
|
+
display: block;
|
35
|
+
color: #330000;
|
36
|
+
text-decoration: none;
|
37
|
+
&:hover {
|
38
|
+
text-decoration: underline;
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
&.opened {
|
44
|
+
h3 {
|
45
|
+
background: #669966;
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
.action_key_list {
|
51
|
+
padding: 5px 0px;
|
52
|
+
list-style: none;
|
53
|
+
}
|
54
|
+
|
55
|
+
.seo_action_key_item {
|
56
|
+
margin: 5px 35px;
|
57
|
+
position: relative;
|
58
|
+
|
59
|
+
.seo_action_key_delete {
|
60
|
+
top: 3px;
|
61
|
+
right: 20px;
|
62
|
+
position: absolute;
|
63
|
+
color: #330000;
|
64
|
+
text-decoration: none;
|
65
|
+
|
66
|
+
&:hover {
|
67
|
+
text-decoration: underline;
|
68
|
+
}
|
69
|
+
|
70
|
+
&:hover + .seo_action_key_link {
|
71
|
+
background: #AACCAA;
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
.seo_action_key_link {
|
76
|
+
padding: 3px 5px;
|
77
|
+
display: block;
|
78
|
+
color: #330000;
|
79
|
+
text-decoration: none;
|
80
|
+
|
81
|
+
&:hover {
|
82
|
+
background: #AACCAA;
|
83
|
+
text-decoration: underline;
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
&.opened {
|
88
|
+
background: #FFFFAA;
|
89
|
+
|
90
|
+
.seo_action_key_link {
|
91
|
+
color: #331100;
|
92
|
+
background: #FF9933;
|
93
|
+
|
94
|
+
&:hover {
|
95
|
+
color: #FFDDAA;
|
96
|
+
background: #AA6633;
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
.seo_action_key_delete {
|
101
|
+
color: #331100;
|
102
|
+
}
|
103
|
+
|
104
|
+
.seo_action_key_delete:hover {
|
105
|
+
color: #FFDDAA;
|
106
|
+
|
107
|
+
& + .seo_action_key_link {
|
108
|
+
color: #FFDDAA;
|
109
|
+
background: #AA6633;
|
110
|
+
}
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
.seo_fields_buttons {
|
115
|
+
margin: 15px 0px 0px 0px;
|
116
|
+
padding: 0px 20px 10px;
|
117
|
+
display: block;
|
118
|
+
position: relative;
|
119
|
+
|
120
|
+
.submit_seo_fields {
|
121
|
+
right: 20px;
|
122
|
+
position: absolute;
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
.seo_form_fields_list {
|
128
|
+
margin: 0px 20px 0px -20px;
|
129
|
+
list-style: none;
|
130
|
+
|
131
|
+
label {
|
132
|
+
display: block;
|
133
|
+
}
|
134
|
+
|
135
|
+
textarea {
|
136
|
+
width: 100%;
|
137
|
+
height: 80px;
|
138
|
+
}
|
139
|
+
|
140
|
+
.seo_field_item {
|
141
|
+
margin: 15px 0px 0px 0px;
|
142
|
+
position: relative;
|
143
|
+
|
144
|
+
.delete_field {
|
145
|
+
top: 0px;
|
146
|
+
right: 0px;
|
147
|
+
position: absolute;
|
148
|
+
}
|
149
|
+
}
|
150
|
+
}
|
@@ -1,7 +1,70 @@
|
|
1
1
|
module Phaseout
|
2
2
|
class PhaseoutController < ::Phaseout::ApplicationController
|
3
3
|
|
4
|
-
def
|
4
|
+
def update
|
5
|
+
@seo_fields = Phaseout::SEOFields.find params[:key]
|
6
|
+
if @seo_fields
|
7
|
+
@seo_fields.values = params[:seo_field].to_h.symbolize_keys
|
8
|
+
@seo_fields.save
|
9
|
+
render json: @seo_fields.to_json
|
10
|
+
else
|
11
|
+
not_found
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def delete
|
16
|
+
@seo_fields = Phaseout::SEOFields.find params[:key]
|
17
|
+
if @seo_fields
|
18
|
+
@seo_fields.delete
|
19
|
+
render json: { status: :ok }.to_json
|
20
|
+
else
|
21
|
+
not_found
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def actions
|
26
|
+
streamed_json_response do |stream|
|
27
|
+
::Phaseout::SEOAction.all do |seo_action|
|
28
|
+
stream.call seo_action
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def action_keys
|
34
|
+
streamed_json_response do |stream|
|
35
|
+
::Phaseout::SEOFields.all(params[:key]) do |fields|
|
36
|
+
stream.call fields
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
def streamed_json_response(&block)
|
43
|
+
headers['Content-Type'] = 'application/json'
|
44
|
+
headers['X-Accel-Buffering'] = 'no'
|
45
|
+
headers['Cache-Control'] ||= 'no-cache'
|
46
|
+
headers.delete 'Content-Length'
|
47
|
+
|
48
|
+
response.stream.write '['
|
49
|
+
|
50
|
+
first = true
|
51
|
+
stream_block = lambda do |data|
|
52
|
+
if first
|
53
|
+
first = false
|
54
|
+
response.stream.write data.to_json
|
55
|
+
else
|
56
|
+
response.stream.write ",#{data.to_json}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
yield stream_block
|
61
|
+
|
62
|
+
response.stream.write ']'
|
63
|
+
response.stream.close
|
64
|
+
end
|
65
|
+
|
66
|
+
def not_found(data = { status: :not_found })
|
67
|
+
render json: data.to_json, status: 404
|
5
68
|
end
|
6
69
|
|
7
70
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
pt-BR:
|
2
|
+
seo:
|
3
|
+
common:
|
4
|
+
add: 'Adicionar'
|
5
|
+
update: 'Atualizar'
|
6
|
+
delete: 'Apagar'
|
7
|
+
add_prompt: 'Adicione um campo customizado:'
|
8
|
+
are_you_sure: 'Tem certeza?'
|
9
|
+
already_added: 'Campo já adicionado!'
|
10
|
+
fields:
|
11
|
+
page_title: 'Título da Página'
|
12
|
+
meta_description: 'Meta Descrição'
|
13
|
+
meta_keywords: 'Meta Palavras Chave'
|
14
|
+
og_url: 'Facebook URL'
|
15
|
+
og_title: 'Facebook Título'
|
16
|
+
og_image: 'Facebook Imagem'
|
17
|
+
og_description: 'Facebook Descrição'
|
18
|
+
other: 'Outro'
|
19
|
+
en:
|
20
|
+
seo:
|
21
|
+
common:
|
22
|
+
add: 'Add'
|
23
|
+
update: 'Update'
|
24
|
+
delete: 'Delete'
|
25
|
+
add_prompt: 'Add a custom field:'
|
26
|
+
are_you_sure: 'Are you sure?'
|
27
|
+
already_added: 'Field already added!'
|
28
|
+
fields:
|
29
|
+
page_title: 'Page Title'
|
30
|
+
meta_description: 'Meta Description'
|
31
|
+
meta_keywords: 'Meta Keywords'
|
32
|
+
og_url: 'Facebook URL'
|
33
|
+
og_title: 'Facebook Title'
|
34
|
+
og_image: 'Facebook Image'
|
35
|
+
og_description: 'Facebook Description'
|
36
|
+
other: 'Other'
|
data/config/routes.rb
CHANGED
@@ -1,3 +1,8 @@
|
|
1
1
|
Phaseout::Engine.routes.draw do
|
2
2
|
root to: 'phaseout#index'
|
3
|
+
|
4
|
+
get '/actions', to: 'phaseout#actions', as: :seo_action_list
|
5
|
+
get '/action/:key/keys', to: 'phaseout#action_keys', as: :seo_action_keys
|
6
|
+
put '/fields/:key/update', to: 'phaseout#update', as: :seo_fields_update
|
7
|
+
delete '/fields/:key/delete', to: 'phaseout#delete', as: :seo_fields_delete
|
3
8
|
end
|
data/lib/phaseout.rb
CHANGED
@@ -3,6 +3,9 @@ require 'redis-namespace'
|
|
3
3
|
|
4
4
|
require 'phaseout/version'
|
5
5
|
require 'phaseout/engine'
|
6
|
+
require 'phaseout/seo_action'
|
7
|
+
require 'phaseout/seo_fields'
|
8
|
+
require 'phaseout/seo_helper'
|
6
9
|
require 'phaseout/seo'
|
7
10
|
require 'phaseout/handler'
|
8
11
|
|
@@ -14,8 +17,10 @@ module Phaseout
|
|
14
17
|
def self.redis
|
15
18
|
@redis ||= config_redis(Redis.new)
|
16
19
|
end
|
17
|
-
end
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
+
def self.default_fields
|
22
|
+
@default_fields ||= ::Phaseout::SEOHelper.instance_methods + [:other]
|
23
|
+
end
|
21
24
|
end
|
25
|
+
|
26
|
+
ActiveSupport.on_load(:action_view){ include Phaseout::SEOHelper }
|
data/lib/phaseout/handler.rb
CHANGED
@@ -9,12 +9,12 @@ module Phaseout
|
|
9
9
|
|
10
10
|
def call(&action_block)
|
11
11
|
if seo_fields
|
12
|
-
@controller.seo_tags = seo_fields.to_html
|
12
|
+
@controller.seo_tags = seo_fields.to_html @controller
|
13
13
|
else
|
14
|
-
@controller.seo_tags = @default.to_html
|
15
|
-
set_blank_field if @blank_field && @editable
|
14
|
+
@controller.seo_tags = @default.to_html @controller
|
16
15
|
end
|
17
16
|
action_block.call
|
17
|
+
set_blank_field if @controller.status == 200 && @blank_field && @editable
|
18
18
|
true
|
19
19
|
end
|
20
20
|
|
@@ -23,7 +23,7 @@ module Phaseout
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def key
|
26
|
-
@key ||= [ 'seo_key:', @controller.class.name, '#', @action, '
|
26
|
+
@key ||= I18n.transliterate( [ 'seo_key:', @controller.class.name, '#', @action, ':', eval_pattern(@key_pattern) ].join.gsub(/\s+/, '_').underscore )
|
27
27
|
end
|
28
28
|
|
29
29
|
def seo_fields
|
@@ -40,13 +40,13 @@ module Phaseout
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def class_index_key
|
43
|
-
['action:', @controller.class.name, '#', @action].join
|
43
|
+
['action:', @controller.class.name, '#', @action].join.gsub(/\s+/, '_').underscore
|
44
44
|
end
|
45
45
|
|
46
46
|
protected
|
47
47
|
def set_blank_field
|
48
|
-
Phaseout.
|
49
|
-
Phaseout
|
48
|
+
Phaseout::SEOAction.new(class_index_key).add key
|
49
|
+
Phaseout::SEOFields.new(key, as).save
|
50
50
|
end
|
51
51
|
|
52
52
|
def eval_pattern(pattern)
|
data/lib/phaseout/seo.rb
CHANGED
@@ -1,12 +1,9 @@
|
|
1
|
-
require 'phaseout/seo_fields'
|
2
|
-
require 'phaseout/seo_helper'
|
3
|
-
|
4
1
|
module Phaseout
|
5
2
|
module SEO
|
6
3
|
extend ActiveSupport::Concern
|
7
4
|
|
8
5
|
def seo_tags
|
9
|
-
@_seo_tags
|
6
|
+
@_seo_tags || ''
|
10
7
|
end
|
11
8
|
|
12
9
|
def seo_tags=(value)
|
@@ -18,8 +15,15 @@ module Phaseout
|
|
18
15
|
end
|
19
16
|
|
20
17
|
module ClassMethods
|
21
|
-
def
|
18
|
+
def seo_group_name
|
19
|
+
@_seo_group_name ||= Hash.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def seo_tags_for(action, as: action, key: as, editable: true, grouped_as: nil, &block)
|
23
|
+
seo_action = Phaseout::SEOAction.new self.name, action
|
24
|
+
seo_group_name[seo_action.key] = grouped_as || seo_action.key
|
22
25
|
around_block = lambda do |controller, action_block|
|
26
|
+
return action_block.call unless request.format.html?
|
23
27
|
Phaseout::Handler.new(controller, action, as, key, editable, &block).call &action_block
|
24
28
|
end
|
25
29
|
around_action around_block, only: action
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Phaseout
|
2
|
+
class SEOAction
|
3
|
+
attr_reader :controller, :action
|
4
|
+
|
5
|
+
def initialize(controller_or_key, action = nil)
|
6
|
+
if action
|
7
|
+
@controller, @action = controller_or_key, action
|
8
|
+
else
|
9
|
+
@controller, @action = controller_or_key.split '#'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def key
|
14
|
+
I18n.transliterate([ @controller, @action ].join '#' ).gsub(/\s+/, '_').underscore
|
15
|
+
end
|
16
|
+
|
17
|
+
def id
|
18
|
+
I18n.transliterate([ @controller, @action ].join '-' ).gsub(/\s+/, '_').underscore
|
19
|
+
end
|
20
|
+
|
21
|
+
def fields(&block)
|
22
|
+
if block_given?
|
23
|
+
SEOFields.all self.key, &block
|
24
|
+
else
|
25
|
+
@fields ||= SEOFields.all self.key
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def name
|
30
|
+
controller.camelize.constantize.seo_group_name[key] || key
|
31
|
+
end
|
32
|
+
|
33
|
+
def add(field_key)
|
34
|
+
Phaseout.redis.sadd key, field_key
|
35
|
+
end
|
36
|
+
|
37
|
+
def remove(field_key)
|
38
|
+
Phaseout.redis.srem key, field_key
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_json
|
42
|
+
{
|
43
|
+
id: id,
|
44
|
+
key: key,
|
45
|
+
name: name,
|
46
|
+
action: action,
|
47
|
+
controller: controller
|
48
|
+
}.to_json
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.find(key)
|
52
|
+
self.new "action:#{key}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.all(&block)
|
56
|
+
unless block_given?
|
57
|
+
values = []
|
58
|
+
self.all{ |action| values << action }
|
59
|
+
return values
|
60
|
+
end
|
61
|
+
|
62
|
+
pattern = "#{Phaseout.redis.namespace}:action:*"
|
63
|
+
Phaseout.redis.scan_each(match: pattern) do |value|
|
64
|
+
yield self.new( value.match(/#{ Phaseout.redis.namespace }\:action\:/).post_match )
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/phaseout/seo_fields.rb
CHANGED
@@ -2,9 +2,10 @@ module Phaseout
|
|
2
2
|
class SEOFields
|
3
3
|
attr_reader :key, :human_name
|
4
4
|
attr_accessor :values, :default
|
5
|
+
alias :fields :values
|
5
6
|
|
6
7
|
def initialize(key, human_name, values = Hash.new, &block)
|
7
|
-
@key, @human_name, @values = key, human_name, values
|
8
|
+
@key, @human_name, @values = I18n.transliterate(key).gsub(/\s+/, '_').underscore, human_name, values
|
8
9
|
yield(self) if block_given?
|
9
10
|
end
|
10
11
|
|
@@ -14,6 +15,29 @@ module Phaseout
|
|
14
15
|
end.join.html_safe
|
15
16
|
end
|
16
17
|
|
18
|
+
def action_key
|
19
|
+
@action_key ||= @key.match('seo_key:').post_match.match(':').pre_match
|
20
|
+
end
|
21
|
+
|
22
|
+
def action
|
23
|
+
@action ||= ::Phaseout::SEOAction.new action_key
|
24
|
+
end
|
25
|
+
|
26
|
+
def id
|
27
|
+
@key.match(/\#.+\:/).post_match.gsub(/\s+/, '_').underscore
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_json
|
31
|
+
{
|
32
|
+
id: id,
|
33
|
+
key: @key.match('seo_key:').post_match,
|
34
|
+
fields: @values,
|
35
|
+
name: @human_name,
|
36
|
+
action_id: action_key.gsub('#', '_').underscore,
|
37
|
+
action_key: action_key
|
38
|
+
}.to_json
|
39
|
+
end
|
40
|
+
|
17
41
|
def dump
|
18
42
|
Marshal.dump self
|
19
43
|
end
|
@@ -22,6 +46,11 @@ module Phaseout
|
|
22
46
|
Phaseout.redis.set key, self.dump
|
23
47
|
end
|
24
48
|
|
49
|
+
def delete
|
50
|
+
Phaseout::SEOAction.find(action_key).remove key
|
51
|
+
Phaseout.redis.del key
|
52
|
+
end
|
53
|
+
|
25
54
|
def evaluated_values(controller)
|
26
55
|
@_values ||= if @default
|
27
56
|
@default.evaluated_values(controller).merge @values
|
@@ -47,7 +76,7 @@ module Phaseout
|
|
47
76
|
end
|
48
77
|
|
49
78
|
def inspect
|
50
|
-
"#<Phaseout::SEO #{
|
79
|
+
"#<Phaseout::SEO #{action_key} #{@human_name}>"
|
51
80
|
end
|
52
81
|
alias :to_s :inspect
|
53
82
|
|
@@ -55,7 +84,7 @@ module Phaseout
|
|
55
84
|
if block_given?
|
56
85
|
@values[method.to_sym] = block
|
57
86
|
else
|
58
|
-
@values[method.to_sym] = args
|
87
|
+
@values[method.to_sym] = args unless args.empty?
|
59
88
|
end
|
60
89
|
end
|
61
90
|
|
@@ -72,29 +101,17 @@ module Phaseout
|
|
72
101
|
dump ? Marshal.load(dump) : nil
|
73
102
|
end
|
74
103
|
|
75
|
-
def self.
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
values.each do |value|
|
81
|
-
yield value.match(/#{ Phaseout.redis.namespace }\:action\:/).post_match
|
82
|
-
end
|
83
|
-
cursor, values = Phaseout.redis.scan cursor, match: pattern
|
84
|
-
cursor = cursor.to_i
|
104
|
+
def self.all(action_key, &block)
|
105
|
+
unless block_given?
|
106
|
+
values = []
|
107
|
+
self.all(action_key){ |field| values << field }
|
108
|
+
return values
|
85
109
|
end
|
86
|
-
end
|
87
110
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
while cursor != 0
|
92
|
-
cursor = cursor.to_i
|
93
|
-
keys.each{ |value| yield self.find(value.match('seo_key:').post_match) }
|
94
|
-
cursor, keys = Phaseout.redis.sscan class_index_key, cursor
|
95
|
-
cursor = cursor.to_i
|
111
|
+
class_index_key = "#{Phaseout.redis.namespace}:action:#{action_key}"
|
112
|
+
Phaseout.redis.sscan_each(class_index_key) do |value|
|
113
|
+
yield self.find value.match('seo_key:').post_match
|
96
114
|
end
|
97
115
|
end
|
98
|
-
|
99
116
|
end
|
100
117
|
end
|
data/lib/phaseout/version.rb
CHANGED
data/phaseout.gemspec
CHANGED
@@ -22,6 +22,9 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_dependency 'redis'
|
23
23
|
spec.add_dependency 'redis-namespace'
|
24
24
|
|
25
|
+
spec.add_dependency 'eco'
|
26
|
+
spec.add_dependency 'coffee-script'
|
27
|
+
|
25
28
|
spec.add_development_dependency 'rake'
|
26
29
|
spec.add_development_dependency 'bundler'
|
27
30
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phaseout
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.1
|
4
|
+
version: 0.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dalton Pinto
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-12-
|
12
|
+
date: 2014-12-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redis
|
@@ -39,6 +39,34 @@ dependencies:
|
|
39
39
|
- - ">="
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: eco
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :runtime
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: coffee-script
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
42
70
|
- !ruby/object:Gem::Dependency
|
43
71
|
name: rake
|
44
72
|
requirement: !ruby/object:Gem::Requirement
|
@@ -79,15 +107,24 @@ files:
|
|
79
107
|
- LICENSE.txt
|
80
108
|
- README.mdown
|
81
109
|
- Rakefile
|
110
|
+
- app/assets/javascripts/phaseout/application.js.erb
|
111
|
+
- app/assets/javascripts/phaseout/templates/action_key_field.jst.eco
|
112
|
+
- app/assets/javascripts/phaseout/templates/action_key_item.jst.eco
|
113
|
+
- app/assets/javascripts/phaseout/templates/action_key_list.jst.eco
|
114
|
+
- app/assets/javascripts/phaseout/templates/action_list.jst.eco
|
115
|
+
- app/assets/javascripts/phaseout/templates/action_list_item.jst.eco
|
116
|
+
- app/assets/stylesheets/phaseout/application.css.scss
|
82
117
|
- app/controllers/phaseout/application_controller.rb
|
83
118
|
- app/controllers/phaseout/phaseout_controller.rb
|
84
119
|
- app/views/layouts/phaseout/application.html.erb
|
85
120
|
- app/views/phaseout/phaseout/index.html.erb
|
121
|
+
- config/locales/phaseout.yml
|
86
122
|
- config/routes.rb
|
87
123
|
- lib/phaseout.rb
|
88
124
|
- lib/phaseout/engine.rb
|
89
125
|
- lib/phaseout/handler.rb
|
90
126
|
- lib/phaseout/seo.rb
|
127
|
+
- lib/phaseout/seo_action.rb
|
91
128
|
- lib/phaseout/seo_fields.rb
|
92
129
|
- lib/phaseout/seo_helper.rb
|
93
130
|
- lib/phaseout/version.rb
|
@@ -107,9 +144,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
107
144
|
version: '0'
|
108
145
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
146
|
requirements:
|
110
|
-
- - "
|
147
|
+
- - ">="
|
111
148
|
- !ruby/object:Gem::Version
|
112
|
-
version:
|
149
|
+
version: '0'
|
113
150
|
requirements: []
|
114
151
|
rubyforge_project:
|
115
152
|
rubygems_version: 2.4.2
|