redmine_crm 0.0.23 → 0.0.25
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/Gemfile +1 -1
- data/doc/CHANGELOG +4 -0
- data/lib/redmine_crm.rb +28 -20
- data/lib/redmine_crm/{rcrm_acts_as_taggable.rb → acts_as_taggable/rcrm_acts_as_taggable.rb} +93 -87
- data/lib/redmine_crm/acts_as_taggable/tag.rb +81 -0
- data/lib/redmine_crm/acts_as_taggable/tag_list.rb +111 -0
- data/lib/redmine_crm/acts_as_taggable/tagging.rb +16 -0
- data/lib/redmine_crm/acts_as_viewed/rcrm_acts_as_viewed.rb +274 -0
- data/lib/redmine_crm/{rcrm_acts_as_votable.rb → acts_as_votable/rcrm_acts_as_votable.rb} +8 -11
- data/lib/redmine_crm/acts_as_votable/rcrm_acts_as_voter.rb +20 -0
- data/lib/redmine_crm/{votable.rb → acts_as_votable/votable.rb} +36 -47
- data/lib/redmine_crm/{vote.rb → acts_as_votable/vote.rb} +7 -10
- data/lib/redmine_crm/{voter.rb → acts_as_votable/voter.rb} +29 -34
- data/lib/redmine_crm/currency/formatting.rb +0 -3
- data/lib/redmine_crm/currency/heuristics.rb +1 -1
- data/lib/redmine_crm/currency/loader.rb +1 -1
- data/lib/redmine_crm/helpers/tags_helper.rb +1 -3
- data/lib/redmine_crm/helpers/vote_helper.rb +29 -32
- data/lib/redmine_crm/liquid/drops/issues_drop.rb +66 -0
- data/lib/redmine_crm/liquid/drops/news_drop.rb +54 -0
- data/lib/redmine_crm/liquid/drops/projects_drop.rb +86 -0
- data/lib/redmine_crm/liquid/drops/users_drop.rb +72 -0
- data/lib/redmine_crm/liquid/filters/arrays.rb +178 -0
- data/lib/redmine_crm/liquid/filters/base.rb +208 -0
- data/lib/redmine_crm/version.rb +1 -1
- data/redmine_crm.gemspec +1 -1
- data/test/{acts_as_taggable_test.rb → acts_as_taggable/rcrm_acts_as_taggable_test.rb} +114 -151
- data/test/acts_as_taggable/tag_list_test.rb +38 -0
- data/test/acts_as_taggable/tag_test.rb +74 -0
- data/test/acts_as_taggable/tagging_test.rb +15 -0
- data/test/{viewed_test.rb → acts_as_viewed/rcrm_acts_as_viewed_test.rb} +17 -15
- data/test/{votable_test.rb → acts_as_votable/rcrm_acts_as_votable_test.rb} +3 -3
- data/test/acts_as_votable/rcrm_acts_as_voter_test.rb +12 -0
- data/test/{votable_model_test.rb → acts_as_votable/votable_test.rb} +4 -4
- data/test/{voter_model_test.rb → acts_as_votable/voter_test.rb} +7 -7
- data/test/currency_test.rb +10 -10
- data/test/fixtures/issue.rb +6 -2
- data/test/fixtures/issues.yml +13 -1
- data/test/fixtures/news.rb +3 -0
- data/test/fixtures/news.yml +8 -0
- data/test/fixtures/project.rb +8 -0
- data/test/fixtures/projects.yml +10 -0
- data/test/fixtures/user.rb +5 -1
- data/test/fixtures/users.yml +3 -2
- data/test/fixtures/vote_classes.rb +2 -3
- data/test/liquid/drops/issues_drop_test.rb +34 -0
- data/test/liquid/drops/liquid_test.rb +52 -0
- data/test/liquid/drops/news_drop_test.rb +38 -0
- data/test/liquid/drops/projects_drop_test.rb +44 -0
- data/test/liquid/drops/uses_drop_test.rb +36 -0
- data/test/liquid/filters/arrays_filter_test.rb +24 -0
- data/test/liquid/filters/base_filter_test.rb +63 -0
- data/test/liquid/liquid_helper.rb +32 -0
- data/test/money_helper_test.rb +5 -5
- data/test/schema.rb +21 -9
- data/test/test_helper.rb +26 -25
- metadata +76 -28
- data/lib/redmine_crm/rcrm_acts_as_viewed.rb +0 -287
- data/lib/redmine_crm/rcrm_acts_as_voter.rb +0 -27
- data/lib/redmine_crm/tag.rb +0 -81
- data/lib/redmine_crm/tag_list.rb +0 -112
- data/lib/redmine_crm/tagging.rb +0 -20
- data/test/tag_test.rb +0 -64
- data/test/tagging_test.rb +0 -14
@@ -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
|
@@ -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
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
-
|
26
|
-
|
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
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module RedmineCrm
|
2
|
+
module Liquid
|
3
|
+
class IssuesDrop < ::Liquid::Drop
|
4
|
+
def initialize(issues)
|
5
|
+
@issues = issues
|
6
|
+
end
|
7
|
+
|
8
|
+
def before_method(id)
|
9
|
+
issue = @issues.where(:id => id).first || Issue.new
|
10
|
+
IssueDrop.new issue
|
11
|
+
end
|
12
|
+
|
13
|
+
def all
|
14
|
+
@all ||= @issues.map do |issue|
|
15
|
+
IssueDrop.new issue
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def each(&block)
|
20
|
+
all.each(&block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def size
|
24
|
+
@issues.size
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class IssueDrop < ::Liquid::Drop
|
29
|
+
include ActionView::Helpers::UrlHelper
|
30
|
+
|
31
|
+
delegate :id,
|
32
|
+
:subject,
|
33
|
+
:description,
|
34
|
+
:visible?,
|
35
|
+
:open?,
|
36
|
+
:start_date,
|
37
|
+
:due_date,
|
38
|
+
:overdue?,
|
39
|
+
:completed_percent,
|
40
|
+
:updated_on,
|
41
|
+
:created_on,
|
42
|
+
:to => :@issue
|
43
|
+
|
44
|
+
def initialize(issue)
|
45
|
+
@issue = issue
|
46
|
+
end
|
47
|
+
|
48
|
+
def link
|
49
|
+
link_to @issue.subject, self.url
|
50
|
+
end
|
51
|
+
|
52
|
+
def url
|
53
|
+
Rails.application.routes.url_helpers.issue_path(@issue)
|
54
|
+
end
|
55
|
+
|
56
|
+
def author
|
57
|
+
@user ||= UserDrop.new(@issue.author)
|
58
|
+
end
|
59
|
+
|
60
|
+
def custom_field_values
|
61
|
+
@issue.custom_field_values
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module RedmineCrm
|
2
|
+
module Liquid
|
3
|
+
class NewssDrop < ::Liquid::Drop
|
4
|
+
|
5
|
+
def self.default_drop
|
6
|
+
self.new News.visible.order("#{News.table_name}.created_on")
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(newss)
|
10
|
+
@newss = newss
|
11
|
+
end
|
12
|
+
|
13
|
+
def before_method(id)
|
14
|
+
news = @newss.where(:id => id).first || News.new
|
15
|
+
NewsDrop.new news
|
16
|
+
end
|
17
|
+
|
18
|
+
def last
|
19
|
+
NewsDrop.new News.last
|
20
|
+
end
|
21
|
+
|
22
|
+
def all
|
23
|
+
@all ||= @newss.map do |news|
|
24
|
+
NewsDrop.new news
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def each(&block)
|
29
|
+
all.each(&block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def size
|
33
|
+
@newss.size
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class NewsDrop < ::Liquid::Drop
|
38
|
+
delegate :id, :title, :summary, :description, :visible?, :commentable?, :to => :@news
|
39
|
+
|
40
|
+
def initialize(news)
|
41
|
+
@news = news
|
42
|
+
end
|
43
|
+
|
44
|
+
def author
|
45
|
+
UserDrop.new @news.author
|
46
|
+
end
|
47
|
+
|
48
|
+
def custom_field_values
|
49
|
+
@news.custom_field_values
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module RedmineCrm
|
2
|
+
module Liquid
|
3
|
+
class ProjectsDrop < ::Liquid::Drop
|
4
|
+
|
5
|
+
def self.default_drop
|
6
|
+
self.new Project.visible.order(:name)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(projects)
|
10
|
+
@projects = projects
|
11
|
+
end
|
12
|
+
|
13
|
+
def before_method(identifier)
|
14
|
+
project = @projects.where(:identifier => identifier).first || Project.new
|
15
|
+
ProjectDrop.new project
|
16
|
+
end
|
17
|
+
|
18
|
+
def all
|
19
|
+
@all ||= @projects.map do |project|
|
20
|
+
ProjectDrop.new project
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def active
|
25
|
+
@active ||= @projects.select(&:active?).map do |project|
|
26
|
+
ProjectDrop.new project
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def each(&block)
|
31
|
+
all.each(&block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def size
|
35
|
+
@projects.size
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class ProjectDrop < ::Liquid::Drop
|
40
|
+
include ActionView::Helpers::UrlHelper
|
41
|
+
|
42
|
+
delegate :id,
|
43
|
+
:identifier,
|
44
|
+
:name,
|
45
|
+
:is_public,
|
46
|
+
:description,
|
47
|
+
:visible?,
|
48
|
+
:active?,
|
49
|
+
:archived?,
|
50
|
+
:short_description,
|
51
|
+
:start_date,
|
52
|
+
:due_date,
|
53
|
+
:overdue?,
|
54
|
+
:completed_percent,
|
55
|
+
:to => :@project
|
56
|
+
|
57
|
+
def initialize(project)
|
58
|
+
@project = project
|
59
|
+
end
|
60
|
+
|
61
|
+
def link
|
62
|
+
link_to @project.name, self.url
|
63
|
+
end
|
64
|
+
|
65
|
+
def url
|
66
|
+
Rails.application.routes.url_helpers.project_path(@project)
|
67
|
+
end
|
68
|
+
|
69
|
+
def issues
|
70
|
+
@issues ||= IssuesDrop.new @project.issues.visible
|
71
|
+
end
|
72
|
+
|
73
|
+
def users
|
74
|
+
@users ||= UsersDrop.new @project.users
|
75
|
+
end
|
76
|
+
|
77
|
+
def subprojects
|
78
|
+
@subprojects ||= ProjectsDrop.new @project.children
|
79
|
+
end
|
80
|
+
|
81
|
+
def custom_field_values
|
82
|
+
@project.custom_field_values
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module RedmineCrm
|
2
|
+
module Liquid
|
3
|
+
class UsersDrop < ::Liquid::Drop
|
4
|
+
|
5
|
+
def self.default_drop
|
6
|
+
self.new User.sorted
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(users)
|
10
|
+
@users = users
|
11
|
+
end
|
12
|
+
|
13
|
+
def before_method(login)
|
14
|
+
user = @users.where(:login => login).first || User.new
|
15
|
+
UserDrop.new user
|
16
|
+
end
|
17
|
+
|
18
|
+
def current
|
19
|
+
UserDrop.new User.current
|
20
|
+
end
|
21
|
+
|
22
|
+
def all
|
23
|
+
@all ||= @users.map do |user|
|
24
|
+
UserDrop.new user
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def each(&block)
|
29
|
+
all.each(&block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def size
|
33
|
+
@users.size
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class UserDrop < ::Liquid::Drop
|
38
|
+
delegate :id, :name, :firstname, :lastname, :mail, :active?, :admin?, :logged?, :language, :to => :@user
|
39
|
+
|
40
|
+
def initialize(user)
|
41
|
+
@user = user
|
42
|
+
end
|
43
|
+
|
44
|
+
def avatar
|
45
|
+
ApplicationController.helpers.avatar(@user)
|
46
|
+
end
|
47
|
+
|
48
|
+
def name
|
49
|
+
@user.name
|
50
|
+
end
|
51
|
+
|
52
|
+
def permissions
|
53
|
+
roles = @user.memberships.collect { |m| m.roles }.flatten.uniq
|
54
|
+
roles << (@user.logged? ? Role.non_member : Role.anonymous)
|
55
|
+
roles.map(&:permissions).flatten.uniq.map(&:to_s)
|
56
|
+
end
|
57
|
+
|
58
|
+
def groups
|
59
|
+
@user.groups.map(&:name)
|
60
|
+
end
|
61
|
+
|
62
|
+
def projects
|
63
|
+
ProjectsDrop.new @user.memberships.map(&:project).flatten.select(&:visible?).uniq
|
64
|
+
end
|
65
|
+
|
66
|
+
def custom_field_values
|
67
|
+
@user.custom_field_values
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
module RedmineCrm
|
2
|
+
module Liquid
|
3
|
+
module Filters
|
4
|
+
module Arrays
|
5
|
+
|
6
|
+
# Get the first element of the passed in array
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
# {{ product.images | first | to_img }}
|
10
|
+
#
|
11
|
+
# {{ product.images | first: 3 }}
|
12
|
+
#
|
13
|
+
def first(array, count=1)
|
14
|
+
(count > 1 ? array.first(count) : array.first) if array.respond_to?(:first)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Convert the input into json string
|
18
|
+
#
|
19
|
+
# input - The Array or Hash to be converted
|
20
|
+
#
|
21
|
+
# Returns the converted json string
|
22
|
+
def jsonify(input)
|
23
|
+
as_liquid(input).to_json
|
24
|
+
end
|
25
|
+
|
26
|
+
# Group an array of items by a property
|
27
|
+
#
|
28
|
+
# input - the inputted Enumerable
|
29
|
+
# property - the property
|
30
|
+
#
|
31
|
+
# Returns an array of Hashes, each looking something like this:
|
32
|
+
# {"name" => "larry"
|
33
|
+
# "items" => [...] } # all the items where `property` == "larry"
|
34
|
+
def group_by(input, property)
|
35
|
+
if groupable?(input)
|
36
|
+
input.group_by { |item| item_property(item, property).to_s }
|
37
|
+
.each_with_object([]) do |item, array|
|
38
|
+
array << {
|
39
|
+
"name" => item.first,
|
40
|
+
"items" => item.last,
|
41
|
+
"size" => item.last.size
|
42
|
+
}
|
43
|
+
end
|
44
|
+
else
|
45
|
+
input
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Filter an array of objects
|
50
|
+
#
|
51
|
+
# input - the object array
|
52
|
+
# property - property within each object to filter by
|
53
|
+
# value - desired value
|
54
|
+
#
|
55
|
+
# Returns the filtered array of objects
|
56
|
+
def where(input, property, value, operator='==')
|
57
|
+
return input unless input.respond_to?(:select)
|
58
|
+
input = input.values if input.is_a?(Hash)
|
59
|
+
if operator == '=='
|
60
|
+
input.select do |object|
|
61
|
+
Array(item_property(object, property)).map(&:to_s).include?(value.to_s)
|
62
|
+
end || []
|
63
|
+
elsif operator == '<>'
|
64
|
+
input.select do |object|
|
65
|
+
!Array(item_property(object, property)).map(&:to_s).include?(value.to_s)
|
66
|
+
end || []
|
67
|
+
elsif operator == '>'
|
68
|
+
input.select do |object|
|
69
|
+
item_property(object, property) > value
|
70
|
+
end || []
|
71
|
+
elsif operator == '<'
|
72
|
+
input.select do |object|
|
73
|
+
item_property(object, property) < value
|
74
|
+
end || []
|
75
|
+
elsif operator == 'match'
|
76
|
+
input.select do |object|
|
77
|
+
Array(item_property(object, property)).map(&:to_s).any?{|i| i.match(value.to_s)}
|
78
|
+
end || []
|
79
|
+
else
|
80
|
+
[]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Filter an array of objects by tags
|
85
|
+
#
|
86
|
+
# input - the object array
|
87
|
+
# tags - quoted tags list divided by comma
|
88
|
+
# match - (all- defaut, any, exclude)
|
89
|
+
#
|
90
|
+
# Returns the filtered array of objects
|
91
|
+
def tagged_with(input, tags, match='all')
|
92
|
+
return input unless input.respond_to?(:select)
|
93
|
+
input = input.values if input.is_a?(Hash)
|
94
|
+
tag_list = input.is_a?(Array) ? tags.sort : tags.split(',').map(&:strip).sort
|
95
|
+
case match
|
96
|
+
when "all"
|
97
|
+
input.select do |object|
|
98
|
+
object.respond_to?(:tag_list) &&
|
99
|
+
(tag_list - Array(item_property(object, 'tag_list')).map(&:to_s).sort).empty?
|
100
|
+
end || []
|
101
|
+
when "any"
|
102
|
+
input.select do |object|
|
103
|
+
object.respond_to?(:tag_list) &&
|
104
|
+
(tag_list & Array(item_property(object, 'tag_list')).map(&:to_s).sort).any?
|
105
|
+
end || []
|
106
|
+
when "exclude"
|
107
|
+
input.select do |object|
|
108
|
+
object.respond_to?(:tag_list) &&
|
109
|
+
(tag_list & Array(item_property(object, 'tag_list')).map(&:to_s).sort).empty?
|
110
|
+
end || []
|
111
|
+
else
|
112
|
+
[]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Sort an array of objects
|
117
|
+
#
|
118
|
+
# input - the object array
|
119
|
+
# property - property within each object to filter by
|
120
|
+
# nils ('first' | 'last') - nils appear before or after non-nil values
|
121
|
+
#
|
122
|
+
# Returns the filtered array of objects
|
123
|
+
def sort(input, property = nil, nils = "first")
|
124
|
+
if input.nil?
|
125
|
+
raise ArgumentError, "Cannot sort a null object."
|
126
|
+
end
|
127
|
+
if property.nil?
|
128
|
+
input.sort
|
129
|
+
else
|
130
|
+
if nils == "first"
|
131
|
+
order = - 1
|
132
|
+
elsif nils == "last"
|
133
|
+
order = + 1
|
134
|
+
else
|
135
|
+
raise ArgumentError, "Invalid nils order: " \
|
136
|
+
"'#{nils}' is not a valid nils order. It must be 'first' or 'last'."
|
137
|
+
end
|
138
|
+
|
139
|
+
sort_input(input, property, order)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def pop(array, input = 1)
|
144
|
+
return array unless array.is_a?(Array)
|
145
|
+
new_ary = array.dup
|
146
|
+
new_ary.pop(input.to_i || 1)
|
147
|
+
new_ary
|
148
|
+
end
|
149
|
+
|
150
|
+
def push(array, input)
|
151
|
+
return array unless array.is_a?(Array)
|
152
|
+
new_ary = array.dup
|
153
|
+
new_ary.push(input)
|
154
|
+
new_ary
|
155
|
+
end
|
156
|
+
|
157
|
+
def shift(array, input = 1)
|
158
|
+
return array unless array.is_a?(Array)
|
159
|
+
new_ary = array.dup
|
160
|
+
new_ary.shift(input.to_i || 1)
|
161
|
+
new_ary
|
162
|
+
end
|
163
|
+
|
164
|
+
def unshift(array, input)
|
165
|
+
return array unless array.is_a?(Array)
|
166
|
+
new_ary = array.dup
|
167
|
+
new_ary.unshift(input)
|
168
|
+
new_ary
|
169
|
+
end
|
170
|
+
|
171
|
+
private
|
172
|
+
|
173
|
+
end # module ArrayFilters
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
::Liquid::Template.register_filter(RedmineCrm::Liquid::Filters::Arrays)
|
178
|
+
end
|