phaseout 0.0.1.danger.very.unstable → 0.0.1
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.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
|