redmine_crm 0.0.23 → 0.0.43

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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/Gemfile +1 -1
  4. data/README.md +166 -33
  5. data/Rakefile +3 -12
  6. data/bitbucket-pipelines.yml +42 -0
  7. data/config/currency_iso.json +12 -0
  8. data/doc/CHANGELOG +81 -2
  9. data/lib/redmine_crm/acts_as_draftable/draft.rb +40 -0
  10. data/lib/redmine_crm/acts_as_draftable/rcrm_acts_as_draftable.rb +170 -0
  11. data/lib/redmine_crm/acts_as_list/list.rb +282 -0
  12. data/lib/redmine_crm/{rcrm_acts_as_taggable.rb → acts_as_taggable/rcrm_acts_as_taggable.rb} +105 -93
  13. data/lib/redmine_crm/acts_as_taggable/tag.rb +81 -0
  14. data/lib/redmine_crm/acts_as_taggable/tag_list.rb +111 -0
  15. data/lib/redmine_crm/acts_as_taggable/tagging.rb +16 -0
  16. data/lib/redmine_crm/acts_as_viewed/rcrm_acts_as_viewed.rb +274 -0
  17. data/lib/redmine_crm/{rcrm_acts_as_votable.rb → acts_as_votable/rcrm_acts_as_votable.rb} +15 -14
  18. data/lib/redmine_crm/acts_as_votable/rcrm_acts_as_voter.rb +20 -0
  19. data/lib/redmine_crm/{votable.rb → acts_as_votable/votable.rb} +54 -65
  20. data/lib/redmine_crm/{vote.rb → acts_as_votable/vote.rb} +6 -8
  21. data/lib/redmine_crm/{voter.rb → acts_as_votable/voter.rb} +29 -34
  22. data/lib/redmine_crm/assets_manager.rb +43 -0
  23. data/lib/redmine_crm/colors_helper.rb +192 -0
  24. data/lib/redmine_crm/compatibility/application_controller_patch.rb +33 -0
  25. data/lib/redmine_crm/currency/formatting.rb +0 -3
  26. data/lib/redmine_crm/currency/heuristics.rb +1 -1
  27. data/lib/redmine_crm/currency/loader.rb +5 -6
  28. data/lib/redmine_crm/helpers/external_assets_helper.rb +19 -0
  29. data/lib/redmine_crm/helpers/form_tag_helper.rb +76 -0
  30. data/lib/redmine_crm/helpers/tags_helper.rb +1 -3
  31. data/lib/redmine_crm/helpers/vote_helper.rb +29 -32
  32. data/lib/redmine_crm/liquid/drops/issues_drop.rb +191 -0
  33. data/lib/redmine_crm/liquid/drops/news_drop.rb +54 -0
  34. data/lib/redmine_crm/liquid/drops/projects_drop.rb +86 -0
  35. data/lib/redmine_crm/liquid/drops/time_entries_drop.rb +65 -0
  36. data/lib/redmine_crm/liquid/drops/users_drop.rb +68 -0
  37. data/lib/redmine_crm/liquid/filters/arrays.rb +187 -0
  38. data/lib/redmine_crm/liquid/filters/base.rb +217 -0
  39. data/lib/redmine_crm/liquid/filters/colors.rb +31 -0
  40. data/lib/redmine_crm/money_helper.rb +2 -4
  41. data/lib/redmine_crm/version.rb +1 -1
  42. data/lib/redmine_crm.rb +56 -21
  43. data/redmine_crm.gemspec +9 -4
  44. data/test/acts_as_draftable/draft_test.rb +29 -0
  45. data/test/acts_as_draftable/rcrm_acts_as_draftable_test.rb +179 -0
  46. data/test/{acts_as_taggable_test.rb → acts_as_taggable/rcrm_acts_as_taggable_test.rb} +117 -156
  47. data/test/acts_as_taggable/tag_list_test.rb +34 -0
  48. data/test/acts_as_taggable/tag_test.rb +72 -0
  49. data/test/acts_as_taggable/tagging_test.rb +15 -0
  50. data/test/{viewed_test.rb → acts_as_viewed/rcrm_acts_as_viewed_test.rb} +17 -15
  51. data/test/acts_as_votable/rcrm_acts_as_votable_test.rb +19 -0
  52. data/test/acts_as_votable/rcrm_acts_as_voter_test.rb +14 -0
  53. data/test/{votable_model_test.rb → acts_as_votable/votable_test.rb} +34 -5
  54. data/test/{voter_model_test.rb → acts_as_votable/voter_test.rb} +8 -8
  55. data/test/currency_test.rb +10 -10
  56. data/test/database.yml +14 -14
  57. data/test/fixtures/issues.yml +13 -1
  58. data/test/fixtures/news.yml +8 -0
  59. data/test/fixtures/projects.yml +10 -0
  60. data/test/fixtures/users.yml +6 -2
  61. data/test/liquid/drops/issues_drop_test.rb +34 -0
  62. data/test/liquid/drops/news_drop_test.rb +38 -0
  63. data/test/liquid/drops/projects_drop_test.rb +44 -0
  64. data/test/liquid/drops/uses_drop_test.rb +36 -0
  65. data/test/liquid/filters/arrays_filter_test.rb +31 -0
  66. data/test/liquid/filters/base_filter_test.rb +63 -0
  67. data/test/liquid/filters/colors_filter_test.rb +33 -0
  68. data/test/liquid/liquid_helper.rb +34 -0
  69. data/test/models/issue.rb +14 -0
  70. data/test/models/news.rb +3 -0
  71. data/test/models/project.rb +8 -0
  72. data/test/{fixtures → models}/user.rb +5 -1
  73. data/test/{fixtures → models}/vote_classes.rb +0 -21
  74. data/test/money_helper_test.rb +5 -5
  75. data/test/schema.rb +33 -10
  76. data/test/test_helper.rb +20 -72
  77. data/vendor/assets/images/vcard.png +0 -0
  78. data/vendor/assets/javascripts/Chart.bundle.min.js +16 -0
  79. data/vendor/assets/javascripts/select2.js +3 -0
  80. data/vendor/assets/javascripts/select2_helpers.js +186 -0
  81. data/vendor/assets/stylesheets/select2.css +414 -0
  82. metadata +162 -38
  83. data/lib/redmine_crm/rcrm_acts_as_viewed.rb +0 -287
  84. data/lib/redmine_crm/rcrm_acts_as_voter.rb +0 -27
  85. data/lib/redmine_crm/tag.rb +0 -81
  86. data/lib/redmine_crm/tag_list.rb +0 -112
  87. data/lib/redmine_crm/tagging.rb +0 -20
  88. data/test/fixtures/issue.rb +0 -14
  89. data/test/tag_test.rb +0 -64
  90. data/test/tagging_test.rb +0 -14
  91. data/test/votable_test.rb +0 -17
@@ -1,9 +1,7 @@
1
1
  module RedmineCrm
2
2
  module ActsAsVotable
3
3
  module Voter
4
-
5
4
  def self.included(base)
6
-
7
5
  # allow user to define these
8
6
  aliases = {
9
7
  :vote_up_for => [:likes, :upvotes, :up_votes],
@@ -18,7 +16,6 @@ module RedmineCrm
18
16
  }
19
17
 
20
18
  base.class_eval do
21
-
22
19
  has_many :votes, :class_name => 'RedmineCrm::ActsAsVotable::Vote', :as => :voter, :dependent => :destroy do
23
20
  def votables
24
21
  includes(:votable).map(&:votable)
@@ -30,107 +27,105 @@ module RedmineCrm
30
27
  alias_method(new_method, method)
31
28
  end
32
29
  end
33
-
34
30
  end
35
-
36
31
  end
37
32
 
38
33
  # voting
39
- def vote args
40
- args[:votable].vote_by args.merge({:voter => self})
34
+ def vote(args)
35
+ args[:votable].vote_by args.merge(:voter => self)
41
36
  end
42
37
 
43
- def vote_up_for model=nil, args={}
38
+ def vote_up_for(model = nil, args = {})
44
39
  vote :votable => model, :vote_scope => args[:vote_scope], :vote => true
45
40
  end
46
41
 
47
- def vote_down_for model=nil, args={}
42
+ def vote_down_for(model = nil, args = {})
48
43
  vote :votable => model, :vote_scope => args[:vote_scope], :vote => false
49
44
  end
50
45
 
51
- def unvote_for model, args={}
46
+ def unvote_for(model, args = {})
52
47
  model.unvote :voter => self, :vote_scope => args[:vote_scope]
53
48
  end
54
49
 
55
50
  # results
56
- def voted_on? votable, args={}
51
+ def voted_on?(votable, args = {})
57
52
  votes = find_votes(:votable_id => votable.id, :votable_type => votable.class.base_class.name,
58
53
  :vote_scope => args[:vote_scope])
59
- votes.size > 0
54
+ !votes.empty?
60
55
  end
61
56
 
62
- def voted_up_on? votable, args={}
57
+ def voted_up_on?(votable, args = {})
63
58
  votes = find_votes(:votable_id => votable.id, :votable_type => votable.class.base_class.name,
64
59
  :vote_scope => args[:vote_scope], :vote_flag => true)
65
- votes.size > 0
60
+ !votes.empty?
66
61
  end
67
62
 
68
- def voted_down_on? votable, args={}
63
+ def voted_down_on?(votable, args = {})
69
64
  votes = find_votes(:votable_id => votable.id, :votable_type => votable.class.base_class.name,
70
65
  :vote_scope => args[:vote_scope], :vote_flag => false)
71
- votes.size > 0
66
+ !votes.empty?
72
67
  end
73
68
 
74
- def voted_as_when_voting_on votable, args={}
69
+ def voted_as_when_voting_on(votable, args = {})
75
70
  vote = find_votes(:votable_id => votable.id, :votable_type => votable.class.base_class.name,
76
- :vote_scope => args[:vote_scope]).select(:vote_flag).last
71
+ :vote_scope => args[:vote_scope]).select(:vote_flag).last
77
72
  return nil unless vote
78
- return vote.vote_flag
73
+ vote.vote_flag
79
74
  end
80
75
 
81
- def find_votes extra_conditions = {}
76
+ def find_votes(extra_conditions = {})
82
77
  votes.where(extra_conditions)
83
78
  end
84
79
 
85
- def find_up_votes args={}
80
+ def find_up_votes(args = {})
86
81
  find_votes :vote_flag => true, :vote_scope => args[:vote_scope]
87
82
  end
88
83
 
89
- def find_down_votes args={}
84
+ def find_down_votes(args = {})
90
85
  find_votes :vote_flag => false, :vote_scope => args[:vote_scope]
91
86
  end
92
87
 
93
- def find_votes_for_class klass, extra_conditions = {}
94
- find_votes extra_conditions.merge({:votable_type => klass.name})
88
+ def find_votes_for_class(klass, extra_conditions = {})
89
+ find_votes extra_conditions.merge(:votable_type => klass.name)
95
90
  end
96
91
 
97
- def find_up_votes_for_class klass, args={}
92
+ def find_up_votes_for_class(klass, args = {})
98
93
  find_votes_for_class klass, :vote_flag => true, :vote_scope => args[:vote_scope]
99
94
  end
100
95
 
101
- def find_down_votes_for_class klass, args={}
96
+ def find_down_votes_for_class(klass, args = {})
102
97
  find_votes_for_class klass, :vote_flag => false, :vote_scope => args[:vote_scope]
103
98
  end
104
99
 
105
100
  # Including polymporphic relations for eager loading
106
101
  def include_objects
107
- ActsAsVotable::Vote.includes(:votable)
102
+ RedmineCrm::ActsAsVotable::Vote.includes(:votable)
108
103
  end
109
104
 
110
- def find_voted_items extra_conditions = {}
105
+ def find_voted_items(extra_conditions = {})
111
106
  options = extra_conditions.merge :voter_id => id, :voter_type => self.class.base_class.name
112
107
  include_objects.where(options).collect(&:votable)
113
108
  end
114
109
 
115
- def find_up_voted_items extra_conditions = {}
110
+ def find_up_voted_items(extra_conditions = {})
116
111
  find_voted_items extra_conditions.merge(:vote_flag => true)
117
112
  end
118
113
 
119
- def find_down_voted_items extra_conditions = {}
114
+ def find_down_voted_items(extra_conditions = {})
120
115
  find_voted_items extra_conditions.merge(:vote_flag => false)
121
116
  end
122
117
 
123
- def get_voted klass, extra_conditions = {}
118
+ def get_voted(klass, extra_conditions = {})
124
119
  klass.joins(:votes_for).merge find_votes(extra_conditions)
125
120
  end
126
121
 
127
- def get_up_voted klass
122
+ def get_up_voted(klass)
128
123
  klass.joins(:votes_for).merge find_up_votes
129
124
  end
130
125
 
131
- def get_down_voted klass
126
+ def get_down_voted(klass)
132
127
  klass.joins(:votes_for).merge find_down_votes
133
128
  end
134
129
  end
135
130
  end
136
- end
131
+ end
@@ -0,0 +1,43 @@
1
+ module RedmineCrm
2
+ class AssetsManager
3
+ def self.install_assets
4
+ return unless Gem.loaded_specs[GEM_NAME]
5
+ source = File.join(Gem.loaded_specs[GEM_NAME].full_gem_path, 'vendor', 'assets')
6
+ destination = File.join(Dir.pwd, 'public', 'plugin_assets', GEM_NAME)
7
+ return unless File.directory?(source)
8
+
9
+ source_files = Dir[source + '/**/*']
10
+ source_dirs = source_files.select { |d| File.directory?(d) }
11
+ source_files -= source_dirs
12
+
13
+ unless source_files.empty?
14
+ base_target_dir = File.join(destination, File.dirname(source_files.first).gsub(source, ''))
15
+ begin
16
+ FileUtils.mkdir_p(base_target_dir)
17
+ rescue Exception => e
18
+ raise "Could not create directory #{base_target_dir}: " + e.message
19
+ end
20
+ end
21
+
22
+ source_dirs.each do |dir|
23
+ target_dir = File.join(destination, dir.gsub(source, ''))
24
+ begin
25
+ FileUtils.mkdir_p(target_dir)
26
+ rescue Exception => e
27
+ raise "Could not create directory #{target_dir}: " + e.message
28
+ end
29
+ end
30
+
31
+ source_files.each do |file|
32
+ begin
33
+ target = File.join(destination, file.gsub(source, ''))
34
+ unless File.exist?(target) && FileUtils.identical?(file, target)
35
+ FileUtils.cp(file, target)
36
+ end
37
+ rescue Exception => e
38
+ raise "Could not copy #{file} to #{target}: " + e.message
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,192 @@
1
+ module RedmineCrm
2
+ class ColorsHelper
3
+ NAMED_COLORS = {
4
+ 'aliceblue' => 'f0f8ff',
5
+ 'antiquewhite' => 'faebd7',
6
+ 'aqua' => '00ffff',
7
+ 'aquamarine' => '7fffd4',
8
+ 'azure' => 'f0ffff',
9
+ 'beige' => 'f5f5dc',
10
+ 'bisque' => 'ffe4c4',
11
+ 'black' => '000',
12
+ 'blanchedalmond' => 'ffebcd',
13
+ 'blue' => '0000ff',
14
+ 'blueviolet' => '8a2be2',
15
+ 'brown' => 'a52a2a',
16
+ 'burlywood' => 'deb887',
17
+ 'burntsienna' => 'ea7e5d',
18
+ 'cadetblue' => '5f9ea0',
19
+ 'chartreuse' => '7fff00',
20
+ 'chocolate' => 'd2691e',
21
+ 'coral' => 'ff7f50',
22
+ 'cornflowerblue' => '6495ed',
23
+ 'cornsilk' => 'fff8dc',
24
+ 'crimson' => 'dc143c',
25
+ 'cyan' => '00ffff',
26
+ 'darkblue' => '00008b',
27
+ 'darkcyan' => '008b8b',
28
+ 'darkgoldenrod' => 'b8860b',
29
+ 'darkgray' => 'a9a9a9',
30
+ 'darkgreen' => '006400',
31
+ 'darkgrey' => 'a9a9a9',
32
+ 'darkkhaki' => 'bdb76b',
33
+ 'darkmagenta' => '8b008b',
34
+ 'darkolivegreen' => '556b2f',
35
+ 'darkorange' => 'ff8c00',
36
+ 'darkorchid' => '9932cc',
37
+ 'darkred' => '8b0000',
38
+ 'darksalmon' => 'e9967a',
39
+ 'darkseagreen' => '8fbc8f',
40
+ 'darkslateblue' => '483d8b',
41
+ 'darkslategray' => '2f4f4f',
42
+ 'darkslategrey' => '2f4f4f',
43
+ 'darkturquoise' => '00ced1',
44
+ 'darkviolet' => '9400d3',
45
+ 'deeppink' => 'ff1493',
46
+ 'deepskyblue' => '00bfff',
47
+ 'dimgray' => '696969',
48
+ 'dimgrey' => '696969',
49
+ 'dodgerblue' => '1e90ff',
50
+ 'firebrick' => 'b22222',
51
+ 'floralwhite' => 'fffaf0',
52
+ 'forestgreen' => '228b22',
53
+ 'fuchsia' => 'ff00ff',
54
+ 'gainsboro' => 'dcdcdc',
55
+ 'ghostwhite' => 'f8f8ff',
56
+ 'gold' => 'ffd700',
57
+ 'goldenrod' => 'daa520',
58
+ 'gray' => '808080',
59
+ 'green' => '008000',
60
+ 'greenyellow' => 'adff2f',
61
+ 'grey' => '808080',
62
+ 'honeydew' => 'f0fff0',
63
+ 'hotpink' => 'ff69b4',
64
+ 'indianred' => 'cd5c5c',
65
+ 'indigo' => '4b0082',
66
+ 'ivory' => 'fffff0',
67
+ 'khaki' => 'f0e68c',
68
+ 'lavender' => 'e6e6fa',
69
+ 'lavenderblush' => 'fff0f5',
70
+ 'lawngreen' => '7cfc00',
71
+ 'lemonchiffon' => 'fffacd',
72
+ 'lightblue' => 'add8e6',
73
+ 'lightcoral' => 'f08080',
74
+ 'lightcyan' => 'e0ffff',
75
+ 'lightgoldenrodyellow' => 'fafad2',
76
+ 'lightgray' => 'd3d3d3',
77
+ 'lightgreen' => '90ee90',
78
+ 'lightgrey' => 'd3d3d3',
79
+ 'lightpink' => 'ffb6c1',
80
+ 'lightsalmon' => 'ffa07a',
81
+ 'lightseagreen' => '20b2aa',
82
+ 'lightskyblue' => '87cefa',
83
+ 'lightslategray' => '789',
84
+ 'lightslategrey' => '789',
85
+ 'lightsteelblue' => 'b0c4de',
86
+ 'lightyellow' => 'ffffe0',
87
+ 'lime' => '00ff00',
88
+ 'limegreen' => '32cd32',
89
+ 'linen' => 'faf0e6',
90
+ 'magenta' => 'ff00ff',
91
+ 'maroon' => '800000',
92
+ 'mediumaquamarine' => '66cdaa',
93
+ 'mediumblue' => '0000cd',
94
+ 'mediumorchid' => 'ba55d3',
95
+ 'mediumpurple' => '9370db',
96
+ 'mediumseagreen' => '3cb371',
97
+ 'mediumslateblue' => '7b68ee',
98
+ 'mediumspringgreen' => '00fa9a',
99
+ 'mediumturquoise' => '48d1cc',
100
+ 'mediumvioletred' => 'c71585',
101
+ 'midnightblue' => '191970',
102
+ 'mintcream' => 'f5fffa',
103
+ 'mistyrose' => 'ffe4e1',
104
+ 'moccasin' => 'ffe4b5',
105
+ 'navajowhite' => 'ffdead',
106
+ 'navy' => '000080',
107
+ 'oldlace' => 'fdf5e6',
108
+ 'olive' => '808000',
109
+ 'olivedrab' => '6b8e23',
110
+ 'orange' => 'ffa500',
111
+ 'orangered' => 'ff4500',
112
+ 'orchid' => 'da70d6',
113
+ 'palegoldenrod' => 'eee8aa',
114
+ 'palegreen' => '98fb98',
115
+ 'paleturquoise' => 'afeeee',
116
+ 'palevioletred' => 'db7093',
117
+ 'papayawhip' => 'ffefd5',
118
+ 'peachpuff' => 'ffdab9',
119
+ 'peru' => 'cd853f',
120
+ 'pink' => 'ffc0cb',
121
+ 'plum' => 'dda0dd',
122
+ 'powderblue' => 'b0e0e6',
123
+ 'purple' => '800080',
124
+ 'rebeccapurple' => '663399',
125
+ 'red' => 'ff0000',
126
+ 'rosybrown' => 'bc8f8f',
127
+ 'royalblue' => '4169e1',
128
+ 'saddlebrown' => '8b4513',
129
+ 'salmon' => 'fa8072',
130
+ 'sandybrown' => 'f4a460',
131
+ 'seagreen' => '2e8b57',
132
+ 'seashell' => 'fff5ee',
133
+ 'sienna' => 'a0522d',
134
+ 'silver' => 'c0c0c0',
135
+ 'skyblue' => '87ceeb',
136
+ 'slateblue' => '6a5acd',
137
+ 'slategray' => '708090',
138
+ 'slategrey' => '708090',
139
+ 'snow' => 'fffafa',
140
+ 'springgreen' => '00ff7f',
141
+ 'steelblue' => '4682b4',
142
+ 'tan' => 'd2b48c',
143
+ 'teal' => '008080',
144
+ 'thistle' => 'd8bfd8',
145
+ 'tomato' => 'ff6347',
146
+ 'turquoise' => '40e0d0',
147
+ 'violet' => 'ee82ee',
148
+ 'wheat' => 'f5deb3',
149
+ 'white' => 'fff',
150
+ 'whitesmoke' => 'f5f5f5',
151
+ 'yellow' => 'ffff00',
152
+ 'yellowgreen' => '9acd32'
153
+ }
154
+
155
+ class << self
156
+ # Amount should be a decimal between 0 and 1. Lower means darker
157
+
158
+ def darken_color(input_color, amount=0.4)
159
+ hex_color = hex_color(input_color).gsub('#','')
160
+ rgb = hex_color.scan(/../).map {|color| color.hex}
161
+ rgb[0] = (rgb[0].to_i * amount).round
162
+ rgb[1] = (rgb[1].to_i * amount).round
163
+ rgb[2] = (rgb[2].to_i * amount).round
164
+ "#%02x%02x%02x" % rgb
165
+ end
166
+
167
+ # Amount should be a decimal between 0 and 1. Higher lightgreen lighter
168
+ def lighten_color(input_color, amount=0.6)
169
+ hex_color = hex_color(input_color).gsub('#','')
170
+ rgb = hex_color.scan(/../).map {|color| color.hex}
171
+ rgb[0] = [(rgb[0].to_i + 255 * amount).round, 255].min
172
+ rgb[1] = [(rgb[1].to_i + 255 * amount).round, 255].min
173
+ rgb[2] = [(rgb[2].to_i + 255 * amount).round, 255].min
174
+ "#%02x%02x%02x" % rgb
175
+ end
176
+
177
+ def contrasting_text_color(input_color)
178
+ color = hex_color(input_color).gsub('#','')
179
+ convert_to_brightness_value(color) > 382.5 ? darken_color(color) : lighten_color(color)
180
+ end
181
+
182
+ def hex_color(input_color)
183
+ "##{NAMED_COLORS[input_color] || input_color}"
184
+ end
185
+
186
+ def convert_to_brightness_value(input_color)
187
+ (hex_color(input_color).scan(/../).map {|color| color.hex}).sum
188
+ end
189
+
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,33 @@
1
+ module RedmineCrm
2
+ module Patches
3
+ module ApplicationControllerPatch
4
+ def self.included(base) # :nodoc:
5
+ base.extend(ClassMethods)
6
+ base.class_eval do
7
+ unloadable # Send unloadable so it will not be unloaded in development
8
+ end
9
+ end
10
+
11
+ module ClassMethods
12
+ def before_action(*filters, &block)
13
+ before_filter(*filters, &block)
14
+ end
15
+
16
+ def after_action(*filters, &block)
17
+ after_filter(*filters, &block)
18
+ end
19
+
20
+ def skip_before_action(*filters, &block)
21
+ skip_before_filter(*filters, &block)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ unless ActionController::Base.methods.include?(:before_action)
29
+ ActionController::Base.send(
30
+ :include,
31
+ RedmineCrm::Patches::ApplicationControllerPatch
32
+ )
33
+ end
@@ -26,7 +26,6 @@ module RedmineCrm
26
26
  alias_method name, method
27
27
  end
28
28
 
29
-
30
29
  def format(value, currency, *rules)
31
30
  # support for old format parameters
32
31
  rules = normalize_formatting_rules(rules)
@@ -220,8 +219,6 @@ module RedmineCrm
220
219
  "\\1#{rules[:decimal_mark]}\\3")
221
220
  end
222
221
  end
223
-
224
222
  end
225
-
226
223
  end
227
224
  end
@@ -148,4 +148,4 @@ module RedmineCrm
148
148
  end
149
149
  end
150
150
  end
151
- end
151
+ end
@@ -3,13 +3,12 @@ module RedmineCrm
3
3
  module Loader
4
4
  DATA_PATH = File.expand_path("../../../../config", __FILE__)
5
5
 
6
- # Loads and returns the currencies stored in JSON files in the config directory.
6
+ # Loads and returns the currencies stored in JSON files
7
+ # in the config directory.
7
8
  #
8
9
  # @return [Hash]
9
10
  def load_currencies
10
- currencies = parse_currency_file("currency_iso.json")
11
- # currencies.merge! parse_currency_file("currency_non_iso.json")
12
- # currencies.merge! parse_currency_file("currency_backwards_compatible.json")
11
+ parse_currency_file('currency_iso.json')
13
12
  end
14
13
 
15
14
  private
@@ -17,8 +16,8 @@ module RedmineCrm
17
16
  def parse_currency_file(filename)
18
17
  json = File.read("#{DATA_PATH}/#{filename}")
19
18
  json.force_encoding(::Encoding::UTF_8) if defined?(::Encoding)
20
- JSON.parse(json, :symbolize_names => true)
19
+ JSON.parse(json, symbolize_names: true)
21
20
  end
22
21
  end
23
22
  end
24
- end
23
+ end
@@ -0,0 +1,19 @@
1
+ module RedmineCrm
2
+ module ExternalAssetsHelper
3
+ include ActionView::Helpers::JavaScriptHelper
4
+
5
+ def select2_assets
6
+ return if @select2_tag_included
7
+ @select2_tag_included = true
8
+ javascript_include_tag('select2', plugin: GEM_NAME) +
9
+ stylesheet_link_tag('select2', plugin: GEM_NAME) +
10
+ javascript_include_tag('select2_helpers', plugin: GEM_NAME)
11
+ end
12
+
13
+ def chartjs_assets
14
+ return if @chartjs_tag_included
15
+ @chartjs_tag_included = true
16
+ javascript_include_tag('Chart.bundle.min', plugin: GEM_NAME)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,76 @@
1
+ module RedmineCrm
2
+ module FormTagHelper
3
+ # Allows include select2 into your views.
4
+ #
5
+ # ==== Examples
6
+ # select2_tag 'city_id', '<option value="1">Lisbon</option>...'
7
+ # select2_tag 'city_id', options_for_select(...)
8
+ # select2_tag 'tag_list', nil, :multiple => true, :data => [{ id: 0, text: 'deal' }, ...], :tags => true, :include_hidden => false %>
9
+ # select2_tag 'tag_list', options_for_select(...), :multiple => true, :style => 'width: 100%;', :url => '/tags', :placeholder => '+ add tag', :tags => true %>
10
+ #
11
+ # You may use select_tag options and additional options.
12
+ #
13
+ # ==== Additional options
14
+ # * <tt>:url</tt> Allows searches for remote data using the ajax.
15
+ # * <tt>:data</tt> Load dropdown options from a local array if +url+ option not set.
16
+ # * <tt>:placeholder</tt> Supports displaying a placeholder value.
17
+ # * <tt>:include_hidden</tt> Adds hidden field after select when +multiple+ option true. Default value true.
18
+ # * <tt>:allow_clear</tt> Provides support for clearable selections. Default value false.
19
+ # * <tt>:min_input_length</tt> Minimum number of characters required to start a search. Default value 0.
20
+ # * <tt>:format_state</tt> Defines template of search results in the drop-down.
21
+ # * <tt>:tags</tt> Used to enable tagging feature.
22
+ #
23
+ # <b>Note:</b> The HTML specification says when +multiple+ parameter passed to select and all options got deselected
24
+ # web browsers do not send any value to server.
25
+ #
26
+ # In case if you don't want the helper to generate this hidden field you can specify
27
+ # <tt>include_hidden: false</tt> option.
28
+ #
29
+ # <b>Note:</b> Select2 assets must be available on a page.
30
+ # To include select2 assets to a page, you need to use the helper select2_assets.
31
+ # For example:
32
+ # <% content_for :header_tags do %>
33
+ # <%= select2_assets %>
34
+ # <% end %>
35
+ #
36
+ # Also aliased as: select2
37
+ #
38
+ # select2 'city_id', options_for_select(...)
39
+ #
40
+ def select2_tag(name, option_tags = nil, options = {})
41
+ s = select_tag(name, option_tags, options)
42
+
43
+ if options[:multiple] && options.fetch(:include_hidden, true)
44
+ s << hidden_field_tag("#{name}[]", '')
45
+ end
46
+
47
+ s + javascript_tag("select2Tag('#{sanitize_to_id(name)}', #{options.to_json});")
48
+ end
49
+
50
+ alias select2 select2_tag
51
+
52
+ # Transforms select filters of +type+ fields into select2
53
+ #
54
+ # ==== Examples
55
+ # transform_to_select2 'tags', url: auto_complete_tags_url
56
+ # transform_to_select2 'people', format_state: 'formatStateWithAvatar', min_input_length: 1, url: '/managers'
57
+ #
58
+ # ==== Options
59
+ # * <tt>:url</tt> Defines URL to search remote data using the ajax.
60
+ # * <tt>:format_state</tt> Defines template of search results in the drop-down.
61
+ # * <tt>:min_input_length</tt> Minimum number of characters required to start a search. Default value 0.
62
+ # * <tt>:width</tt> Sets the width of the control. Default value '60%'.
63
+ # * <tt>:multiple</tt> Supports multi-value select box. If set to false the selection will not allow multiple choices. Default value true.
64
+ #
65
+ # <b>Note:</b> Select2 assets must be available on a page.
66
+ # To include select2 assets to a page, you need to use the helper select2_assets.
67
+ # For example:
68
+ # <% content_for :header_tags do %>
69
+ # <%= select2_assets %>
70
+ # <% end %>
71
+ #
72
+ def transform_to_select2(type, options = {})
73
+ javascript_tag("setSelect2Filter('#{type}', #{options.to_json});") unless type.empty?
74
+ end
75
+ end
76
+ end
@@ -3,13 +3,11 @@ module RedmineCrm
3
3
  # See the README for an example using tag_cloud.
4
4
  def tag_cloud(tags, classes)
5
5
  return if tags.empty?
6
-
7
6
  max_count = tags.sort_by(&:count).last.count.to_f
8
-
9
7
  tags.each do |tag|
10
8
  index = ((tag.count / max_count) * (classes.size - 1)).round
11
9
  yield tag, classes[index]
12
10
  end
13
11
  end
14
12
  end
15
- end
13
+ end
@@ -1,38 +1,35 @@
1
1
  module RedmineCrm
2
- module ActsAsVotable::Helpers
3
-
4
- # this helper provides methods that help find what words are
5
- # up votes and what words are down votes
6
- #
7
- # It can be called
8
- #
9
- # votable_object.votable_words.that_mean_true
10
- #
11
- module Words
12
-
13
- def votable_words
14
- VotableWords
15
- end
16
-
17
- end
18
-
19
- class VotableWords
20
-
21
- def self.that_mean_true
22
- ['up', 'upvote', 'like', 'liked', 'positive', 'yes', 'good', 'true', 1, true]
2
+ module ActsAsVotable
3
+ module Helpers
4
+ # this helper provides methods that help find what words are
5
+ # up votes and what words are down votes
6
+ #
7
+ # It can be called
8
+ #
9
+ # votable_object.votable_words.that_mean_true
10
+ #
11
+ module Words
12
+ def votable_words
13
+ VotableWords
14
+ end
23
15
  end
24
16
 
25
- def self.that_mean_false
26
- ['down', 'downvote', 'dislike', 'disliked', 'negative', 'no', 'bad', 'false', 0, false]
17
+ class VotableWords
18
+ def self.that_mean_true
19
+ ['up', 'upvote', 'like', 'liked', 'positive', 'yes', 'good', 'true', 1, true]
20
+ end
21
+
22
+ def self.that_mean_false
23
+ ['down', 'downvote', 'dislike', 'disliked', 'negative', 'no', 'bad', 'false', 0, false]
24
+ end
25
+
26
+ # check is word is a true or bad vote
27
+ # if the word is unknown, then it counts it as a true/good
28
+ # vote. this exists to allow all voting to be good by default
29
+ def self.meaning_of(word)
30
+ !that_mean_false.include?(word)
31
+ end
27
32
  end
28
-
29
- # check is word is a true or bad vote
30
- # if the word is unknown, then it counts it as a true/good
31
- # vote. this exists to allow all voting to be good by default
32
- def self.meaning_of word
33
- !that_mean_false.include?(word)
34
- end
35
-
36
33
  end
37
34
  end
38
- end
35
+ end