phrasing 2.1.3 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +11 -6
- data/README.md +28 -3
- data/app/assets/javascripts/editor.js +1 -9
- data/app/assets/javascripts/phrasing.js.erb +6 -2
- data/app/assets/javascripts/phrasing_engine.js +2 -0
- data/app/assets/stylesheets/phrasing.css.scss +5 -0
- data/app/assets/stylesheets/phrasing_edit_mode_bubble.css.scss +1 -1
- data/app/assets/stylesheets/phrasing_engine.css +583 -292
- data/app/controllers/phrasing_phrase_versions_controller.rb +9 -0
- data/app/controllers/phrasing_phrases_controller.rb +10 -4
- data/app/helpers/inline_helper.rb +23 -9
- data/app/models/phrasing_phrase.rb +24 -63
- data/app/models/phrasing_phrase_version.rb +3 -0
- data/app/views/layouts/phrasing.html.haml +1 -0
- data/app/views/phrasing/_menu.html.haml +3 -3
- data/app/views/phrasing_phrases/edit.html.haml +19 -3
- data/app/views/phrasing_phrases/index.html.haml +13 -10
- data/config/routes.rb +1 -0
- data/db/migrate/20120313191745_create_phrasing_phrases.rb +0 -1
- data/db/migrate/20131010101010_create_phrasing_phrase_versions.rb +9 -0
- data/lib/phrasing.rb +3 -1
- data/lib/phrasing/implementation.rb +5 -1
- data/lib/phrasing/version.rb +1 -1
- data/lib/tasks/phrasing_tasks.rake +26 -13
- data/phrasing.gemspec +5 -2
- metadata +59 -14
- checksums.yaml +0 -7
@@ -0,0 +1,9 @@
|
|
1
|
+
class PhrasingPhraseVersionsController < ActionController::Base
|
2
|
+
|
3
|
+
def destroy
|
4
|
+
@phrasing_phrase_version = PhrasingPhraseVersion.find(params[:id])
|
5
|
+
@phrasing_phrase_version.destroy
|
6
|
+
redirect_to edit_phrasing_phrase_path(@phrasing_phrase_version.phrasing_phrase.id)
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
@@ -16,7 +16,7 @@ class PhrasingPhrasesController < ActionController::Base
|
|
16
16
|
value_like = PhrasingPhrase.arel_table[:value].matches("%#{params[:search]}%")
|
17
17
|
@phrasing_phrases = query.where(key_like.or(value_like)).order(:key)
|
18
18
|
else
|
19
|
-
@phrasing_phrases = query.order(:key)
|
19
|
+
@phrasing_phrases = query.where("value is not null").order(:key) + query.where("value is null").order(:key)
|
20
20
|
end
|
21
21
|
|
22
22
|
@locale_names = PhrasingPhrase.uniq.pluck(:locale)
|
@@ -53,11 +53,17 @@ class PhrasingPhrasesController < ActionController::Base
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def upload
|
56
|
-
PhrasingPhrase.import_yaml(params["file"].tempfile)
|
57
|
-
redirect_to phrasing_phrases_path, notice: "YAML file uploaded successfully!"
|
56
|
+
number_of_changes = PhrasingPhrase.import_yaml(params["file"].tempfile)
|
57
|
+
redirect_to phrasing_phrases_path, notice: "YAML file uploaded successfully! Number of phrases changed: #{number_of_changes}."
|
58
58
|
rescue Exception => e
|
59
59
|
logger.info "\n#{e.class}\n#{e.message}"
|
60
|
-
|
60
|
+
message = if params[:file].nil?
|
61
|
+
"Please choose a file."
|
62
|
+
else
|
63
|
+
"Please upload a valid YAML file."
|
64
|
+
end
|
65
|
+
|
66
|
+
flash[:alert] = "There was an error processing your upload! #{message}"
|
61
67
|
render action: 'import_export', status: 400
|
62
68
|
end
|
63
69
|
|
@@ -1,12 +1,17 @@
|
|
1
1
|
module InlineHelper
|
2
|
+
# Normal phrase
|
3
|
+
# phrase("headline", url: www.infinum.co/yabadaba, inverse: true, interpolation: {min: 15, max: 20})
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
# Data model phrase
|
6
|
+
# phrase(@record, :title, inverse: true, class: phrase-record-title)
|
7
|
+
|
8
|
+
def phrase(*args)
|
9
|
+
if args[0].class == String or args[0].class == Symbol
|
10
|
+
key, options = args[0].to_s, args[1]
|
11
|
+
phrasing_phrase(key,options)
|
8
12
|
else
|
9
|
-
|
13
|
+
record, field_name, options = args[0], args[1], args[2]
|
14
|
+
inline(record, field_name, options || {})
|
10
15
|
end
|
11
16
|
end
|
12
17
|
|
@@ -16,18 +21,28 @@ module InlineHelper
|
|
16
21
|
klass = 'phrasable'
|
17
22
|
klass += ' phrasable_on' if edit_mode_on?
|
18
23
|
klass += ' inverse' if options[:inverse]
|
24
|
+
klass += options[:class] if options[:class]
|
19
25
|
|
20
26
|
url = phrasing_polymorphic_url(record, field_name)
|
21
27
|
|
22
28
|
content_tag(:span, { class: klass, contenteditable: edit_mode_on?, spellcheck: false, "data-url" => url}) do
|
23
|
-
(record.send(field_name) || record.try(:key)
|
29
|
+
(record.send(field_name) || record.try(:key)).to_s.html_safe
|
24
30
|
end
|
25
|
-
|
26
31
|
end
|
27
32
|
|
28
33
|
alias_method :model_phrase, :inline
|
29
34
|
|
30
35
|
private
|
36
|
+
|
37
|
+
def phrasing_phrase(key, options = {})
|
38
|
+
key = key.to_s
|
39
|
+
if can_edit_phrases?
|
40
|
+
@record = PhrasingPhrase.where(key: key).first || PhrasingPhrase.create_phrase(key)
|
41
|
+
inline(@record, :value, options || {})
|
42
|
+
else
|
43
|
+
options.try(:[], :interpolation) ? t(key, options[:interpolation]).html_safe : t(key).html_safe
|
44
|
+
end
|
45
|
+
end
|
31
46
|
|
32
47
|
def edit_mode_on?
|
33
48
|
if cookies["editing_mode"].nil?
|
@@ -38,7 +53,6 @@ module InlineHelper
|
|
38
53
|
end
|
39
54
|
end
|
40
55
|
|
41
|
-
|
42
56
|
def phrasing_polymorphic_url(record, attribute)
|
43
57
|
resource = Phrasing.route
|
44
58
|
"#{root_url}#{resource}/remote_update_phrase?klass=#{record.class.to_s}&id=#{record.id}&attribute=#{attribute}"
|
@@ -1,20 +1,18 @@
|
|
1
1
|
class PhrasingPhrase < ActiveRecord::Base
|
2
2
|
|
3
|
-
unless ENV['PHRASING_DEBUG']
|
4
|
-
self.logger = Logger.new('/dev/null')
|
5
|
-
end
|
6
|
-
|
7
3
|
validates_presence_of :key, :locale
|
8
4
|
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
validate :uniqueness_of_key_on_locale_scope, on: :create
|
6
|
+
|
7
|
+
has_many :versions, dependent: :destroy, class_name: "PhrasingPhraseVersion"
|
8
|
+
|
9
|
+
after_update :version_it
|
12
10
|
|
13
11
|
def self.create_phrase(key)
|
14
12
|
phrasing_phrase = PhrasingPhrase.new
|
15
|
-
phrasing_phrase.key = key.to_s
|
16
|
-
phrasing_phrase.value = key.to_s.humanize
|
17
13
|
phrasing_phrase.locale = I18n.locale
|
14
|
+
phrasing_phrase.key = key.to_s
|
15
|
+
phrasing_phrase.value = key.to_s
|
18
16
|
phrasing_phrase.save!
|
19
17
|
phrasing_phrase
|
20
18
|
end
|
@@ -22,80 +20,43 @@ class PhrasingPhrase < ActiveRecord::Base
|
|
22
20
|
module Serialize
|
23
21
|
|
24
22
|
def import_yaml(yaml)
|
23
|
+
number_of_changes = 0
|
25
24
|
hash = YAML.load(yaml)
|
26
25
|
hash.each do |locale, data|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
|
-
# {"foo"=>{"a"=>"1", "b"=>"2"}} ----> {"foo.a"=>1, "foo.b"=>2}
|
37
|
-
def hash_flatten(hash)
|
38
|
-
result = {}
|
39
|
-
hash.each do |key, value|
|
40
|
-
if value.is_a? Hash
|
41
|
-
hash_flatten(value).each { |k,v| result["#{key}.#{k}"] = v }
|
42
|
-
else
|
43
|
-
result[key] = value
|
26
|
+
data.each do |key, value|
|
27
|
+
phrase = where(key: key, locale: locale).first || new(key: key, locale: locale)
|
28
|
+
if phrase.value != value
|
29
|
+
phrase.value = value
|
30
|
+
number_of_changes += 1
|
31
|
+
phrase.save
|
32
|
+
end
|
44
33
|
end
|
45
34
|
end
|
46
|
-
|
35
|
+
number_of_changes
|
47
36
|
end
|
48
37
|
|
49
38
|
def export_yaml
|
50
39
|
hash = {}
|
51
|
-
where("value is not null").each do |
|
52
|
-
|
40
|
+
where("value is not null").each do |phrase|
|
41
|
+
hash[phrase.locale] ||= {}
|
42
|
+
hash[phrase.locale][phrase.key] = phrase.value
|
53
43
|
end
|
54
44
|
hash.to_yaml
|
55
45
|
end
|
56
46
|
|
57
|
-
# ({"a"=>{"b"=>{"e"=>"f"}}}, ["a","b","c"], "d") ----> {"a"=>{"b"=>{"c"=>"d", "e"=>"f"}}}
|
58
|
-
def hash_fatten!(hash, keys, value)
|
59
|
-
if keys.length == 1
|
60
|
-
hash[keys.first] = value
|
61
|
-
else
|
62
|
-
head = keys.first
|
63
|
-
rest = keys[1..-1]
|
64
|
-
hash[head] ||= {}
|
65
|
-
hash_fatten!(hash[head], rest, value)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
47
|
end
|
70
48
|
|
71
49
|
extend Serialize
|
72
50
|
|
73
51
|
private
|
74
52
|
|
75
|
-
def
|
76
|
-
|
77
|
-
check_ambiguity_on_successors
|
78
|
-
end
|
79
|
-
|
80
|
-
def check_ambiguity_on_ancestors
|
81
|
-
stripped_key = key
|
82
|
-
while stripped_key.include?('.')
|
83
|
-
stripped_key = stripped_key.split('.')[0..-2].join('.')
|
84
|
-
if PhrasingPhrase.where(key: stripped_key).count > 0
|
85
|
-
errors.add(:key, "can't be named '#{key}', there already exists a key named '#{stripped_key}'. Ambiguous calling!")
|
86
|
-
end
|
87
|
-
end
|
53
|
+
def uniqueness_of_key_on_locale_scope
|
54
|
+
errors.add(:key, "Duplicate entry #{key} for locale #{locale}") unless PhrasingPhrase.where(key: key).where(locale: locale).empty?
|
88
55
|
end
|
89
56
|
|
90
|
-
def
|
91
|
-
|
92
|
-
|
93
|
-
errors.add(:key, "can't be named '#{key}', there already exists one or multiple keys beginning with '#{key_successor}'. Ambiguous calling!")
|
57
|
+
def version_it
|
58
|
+
if value_was != value
|
59
|
+
PhrasingPhraseVersion.create(phrasing_phrase_id: id,value: value)
|
94
60
|
end
|
95
61
|
end
|
96
|
-
|
97
|
-
def key_muts_not_end_with_a_dot
|
98
|
-
errors.add(:key, "mustn't end with a dot") if key[-1] == "."
|
99
|
-
end
|
100
|
-
|
101
62
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
#header
|
2
2
|
%h1= link_to "Phrasing", phrasing_phrases_path
|
3
3
|
%ul
|
4
|
-
- if root_path
|
5
|
-
%li= link_to "Home page", root_path
|
6
4
|
%li= link_to "Phrases", phrasing_phrases_path
|
7
5
|
%li= link_to "Import / Export", import_export_phrasing_phrases_path
|
8
|
-
%li= link_to "Help", help_phrasing_phrases_path
|
6
|
+
%li= link_to "Help", help_phrasing_phrases_path
|
7
|
+
- if root_path
|
8
|
+
%li= link_to "Home page", root_path
|
@@ -1,7 +1,23 @@
|
|
1
1
|
.edit
|
2
2
|
%h2= @phrasing_phrase.key
|
3
|
-
=
|
3
|
+
= link_to "Delete Phrase", phrasing_phrase_path(@phrasing_phrase), class: "btn btn-danger delete-phrase", method: :delete, onclick: "return confirm('Are you sure?');"
|
4
4
|
= form_for @phrasing_phrase, :url => { :action => "update" } do |f|
|
5
5
|
= f.text_area :value, :rows => 12
|
6
|
-
= f.submit "Update"
|
7
|
-
|
6
|
+
= f.submit "Update", class: "btn btn-success submit-edit-phrase"
|
7
|
+
%br
|
8
|
+
- unless @phrasing_phrase.versions.empty?
|
9
|
+
%br
|
10
|
+
%h2 Previous Versions
|
11
|
+
%br
|
12
|
+
%table.phrase-versions
|
13
|
+
%tr
|
14
|
+
%th Value
|
15
|
+
%th Created_at
|
16
|
+
%th
|
17
|
+
%th
|
18
|
+
- @phrasing_phrase.versions.reverse.each do |version|
|
19
|
+
%tr
|
20
|
+
%td.phrasing-version-value= version.value.html_safe
|
21
|
+
%td.phrasing-version-created_at= version.created_at.strftime("%d-%m-%Y %H:%M:%S")
|
22
|
+
%td= link_to "Revert", phrasing_phrase_path(@phrasing_phrase.id, phrasing_phrase: {value: version.value}), class: "btn btn-success", method: :put
|
23
|
+
%td= link_to "Delete", phrasing_phrase_version_path(version.id), class: "btn btn-danger", method: :delete, onclick: "return confirm('Are you sure?');"
|
@@ -3,15 +3,18 @@
|
|
3
3
|
- locale_options = options_for_select([nil] + @locale_names.map{|l| [l,l]}, params[:locale])
|
4
4
|
= select_tag 'locale', locale_options
|
5
5
|
= text_field_tag :search, params[:search], :placeholder => 'Search for keys or values', :size => 40
|
6
|
-
= submit_tag 'Search'
|
6
|
+
= submit_tag 'Search', class: "btn btn-success"
|
7
7
|
- if @phrasing_phrases.any?
|
8
|
-
%table
|
9
|
-
%
|
10
|
-
%th Key
|
11
|
-
%th Value
|
12
|
-
- @phrasing_phrases.each do |t|
|
8
|
+
%table.all-phrases
|
9
|
+
%thead
|
13
10
|
%tr
|
14
|
-
%
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
%th Key
|
12
|
+
%th Value
|
13
|
+
%tbody
|
14
|
+
- @phrasing_phrases.each do |t|
|
15
|
+
%tr{onclick: "document.location = '/#{Phrasing.route}/#{t.id}/edit'"}
|
16
|
+
%td.key
|
17
|
+
= link_to edit_phrasing_phrase_path(t) do
|
18
|
+
= t.key
|
19
|
+
%td.value
|
20
|
+
= t.value.try(:html_safe)
|
data/config/routes.rb
CHANGED
data/lib/phrasing.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'phrasing'
|
2
2
|
require "phrasing/implementation"
|
3
3
|
require "phrasing/simple"
|
4
|
+
require 'jquery-rails'
|
5
|
+
require 'jquery-cookie-rails'
|
4
6
|
|
5
7
|
module Phrasing
|
6
8
|
module Rails
|
@@ -8,7 +10,7 @@ module Phrasing
|
|
8
10
|
initializer :assets, :group => :all do
|
9
11
|
::Rails.application.config.assets.paths << ::Rails.root.join('app', 'assets', 'fonts')
|
10
12
|
::Rails.application.config.assets.paths << ::Rails.root.join('app', 'assets', 'images')
|
11
|
-
::Rails.application.config.assets.precompile += ['editor.js', 'phrasing_engine.css', 'icomoon.dev.svg', 'icomoon.svg', 'icomoon.eot', 'icomoon.ttf', 'icomoon.woff', 'phrasing_information_icon.png']
|
13
|
+
::Rails.application.config.assets.precompile += ['editor.js', 'phrasing_engine.css', 'phrasing_engine.js', 'icomoon.dev.svg', 'icomoon.svg', 'icomoon.eot', 'icomoon.ttf', 'icomoon.woff', 'phrasing_information_icon.png']
|
12
14
|
end
|
13
15
|
end
|
14
16
|
end
|
@@ -11,7 +11,11 @@ module Phrasing
|
|
11
11
|
|
12
12
|
value = super(locale, key, scope, options)
|
13
13
|
if value.is_a?(String) || value.nil?
|
14
|
-
PhrasingPhrase.
|
14
|
+
phrasing_phrase = PhrasingPhrase.new
|
15
|
+
phrasing_phrase.locale = locale.to_s
|
16
|
+
phrasing_phrase.key = scoped_key
|
17
|
+
phrasing_phrase.value = value
|
18
|
+
phrasing_phrase.save
|
15
19
|
end
|
16
20
|
value
|
17
21
|
end
|
data/lib/phrasing/version.rb
CHANGED
@@ -3,14 +3,17 @@ namespace :phrasing do
|
|
3
3
|
task :install do
|
4
4
|
Rake::Task["phrasing_rails_engine:install:migrations"].invoke
|
5
5
|
Rake::Task["phrasing:install_initializer"].invoke
|
6
|
-
Rake::Task["phrasing:
|
6
|
+
Rake::Task["phrasing:install_phrasing_helper"].invoke
|
7
7
|
end
|
8
8
|
|
9
9
|
desc "Create the initializer file"
|
10
10
|
task :install_initializer do
|
11
11
|
filepath = Rails.root.join *%w(config initializers phrasing.rb)
|
12
|
-
File.
|
13
|
-
|
12
|
+
if File.exists?(filepath)
|
13
|
+
alert "Phrasing config file already exists.\n"
|
14
|
+
else
|
15
|
+
File.open(filepath, 'w') do |f|
|
16
|
+
f << <<-CONFIG
|
14
17
|
Phrasing.setup do |config|
|
15
18
|
config.route = 'phrasing'
|
16
19
|
end
|
@@ -20,17 +23,21 @@ end
|
|
20
23
|
Phrasing.whitelist = []
|
21
24
|
# Phrasing.allow_update_on_all_models_and_attributes = true;
|
22
25
|
CONFIG
|
26
|
+
end
|
27
|
+
notice("created")
|
28
|
+
puts " config/intiializers/phrasing.rb"
|
23
29
|
end
|
24
|
-
greenify("You can change the default route and whitelist editable attributes in the phrasing initializer created in the config/intiializers folder.")
|
25
30
|
end
|
26
31
|
|
27
32
|
|
28
33
|
desc "Create the PhrasingHelper file"
|
29
|
-
task :
|
34
|
+
task :install_phrasing_helper do
|
30
35
|
filepath = Rails.root.join *%w(app helpers phrasing_helper.rb)
|
31
|
-
|
32
|
-
|
33
|
-
|
36
|
+
if File.exists?(filepath)
|
37
|
+
alert "Phrasing helper file already exists.\n"
|
38
|
+
else
|
39
|
+
File.open(filepath, 'w') do |f|
|
40
|
+
f << <<-MODULE
|
34
41
|
module PhrasingHelper
|
35
42
|
# You must implement the can_edit_phrases? method.
|
36
43
|
# Example:
|
@@ -44,14 +51,20 @@ module PhrasingHelper
|
|
44
51
|
end
|
45
52
|
end
|
46
53
|
MODULE
|
47
|
-
|
48
|
-
|
49
|
-
|
54
|
+
end
|
55
|
+
notice("created")
|
56
|
+
puts " app/helpers/phrasing_helper.rb"
|
57
|
+
notice "Now run 'rake db:migrate'.\n"
|
58
|
+
end
|
50
59
|
end
|
51
60
|
|
52
61
|
|
53
62
|
end
|
54
63
|
|
55
|
-
def
|
56
|
-
|
64
|
+
def notice(text)
|
65
|
+
print "\033[#{32}m#{text}\033[0m"
|
66
|
+
end
|
67
|
+
|
68
|
+
def alert(text)
|
69
|
+
print "\033[#{31}m#{text}\033[0m"
|
57
70
|
end
|