redmine_extensions 0.2.0 → 0.2.2

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/redmine_extensions/application.js +3 -1
  3. data/app/assets/javascripts/redmine_extensions/blocking.js +6 -0
  4. data/app/assets/javascripts/redmine_extensions/blocking_module.js +58 -0
  5. data/app/assets/javascripts/redmine_extensions/blocking_polyfill.js +59 -0
  6. data/app/assets/javascripts/redmine_extensions/blocking_schedule.js +125 -0
  7. data/app/assets/javascripts/redmine_extensions/easy_togglers.js +1 -1
  8. data/app/assets/javascripts/redmine_extensions/redmine_extensions.js +1 -237
  9. data/app/controllers/easy_settings_controller.rb +5 -16
  10. data/app/helpers/redmine_extensions/application_helper.rb +16 -1
  11. data/app/models/easy_setting.rb +0 -1
  12. data/db/migrate/20150705172511_create_easy_settings.rb +1 -1
  13. data/db/migrate/20160519161300_create_entity_assignments.rb +1 -1
  14. data/lib/generators/redmine_extensions/entity/templates/custom_field.rb.erb +7 -7
  15. data/lib/generators/redmine_extensions/entity/templates/index.api.rsb.erb +5 -5
  16. data/lib/generators/redmine_extensions/entity/templates/mail_added.html.erb.erb +1 -1
  17. data/lib/generators/redmine_extensions/entity/templates/mail_added.text.erb.erb +2 -2
  18. data/lib/generators/redmine_extensions/entity/templates/mail_updated.text.erb.erb +2 -2
  19. data/lib/generators/redmine_extensions/entity/templates/routes.rb.erb +12 -12
  20. data/lib/generators/redmine_extensions/plugin/USAGE +1 -0
  21. data/lib/generators/redmine_extensions/plugin/plugin_generator.rb +3 -1
  22. data/lib/redmine_extensions.rb +2 -2
  23. data/lib/redmine_extensions/core_ext.rb +3 -3
  24. data/lib/redmine_extensions/easy_query_adapter.rb +4 -4
  25. data/lib/redmine_extensions/easy_settings.rb +5 -5
  26. data/lib/redmine_extensions/easy_settings/params_wrapper.rb +0 -1
  27. data/lib/redmine_extensions/engine.rb +13 -11
  28. data/lib/redmine_extensions/hooks.rb +19 -5
  29. data/lib/redmine_extensions/html_formatting.rb +3 -3
  30. data/lib/redmine_extensions/migration.rb +9 -0
  31. data/lib/redmine_extensions/patch_manager.rb +26 -4
  32. data/lib/redmine_extensions/rails_patches/route_set_generator_patch.rb +3 -13
  33. data/lib/redmine_extensions/redmine_patches/controllers/application_controller_patch.rb +7 -9
  34. data/lib/redmine_extensions/version.rb +1 -1
  35. metadata +30 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d8cb8428973f6c3353ad74154a7e78037c8e368e
4
- data.tar.gz: 83333323c82696c521141ba162396926da14e9d5
3
+ metadata.gz: da8777314a9bae88694949647545b995d50c9309
4
+ data.tar.gz: 249040470908720afa5ea03f5b2abb6397ddc6d8
5
5
  SHA512:
6
- metadata.gz: ab40411071438c646db1a43352981b6c0761fc00d9836d8de6d68f6155143df67b7b48a25b8a464f561c8e6feef997d211c77abb7f2ae5dddb2c664806d2fa09
7
- data.tar.gz: 9f6334ced28ff923275659a8ce4ca113cf0d911580441f8e9f198acbdde69f4f095738610b929d57aaeda809a17369926771ab267cab5e637c3020bb072d7284
6
+ metadata.gz: 7ca1694b0b46c1227f68bd10ec343972463cbc10d28e7270deaf36c049fcae38d048d31956556308abb17c4afad23f1d2bd426c4c29104b31ffa55bf23531ca4
7
+ data.tar.gz: 68a7929556ee214804c81bbaa6d5ef94f8d9d088fd0ea0720cff306390363fc26f42c9366756424cd15f59a19aff245cc0ee99cdbc73f034ade563698e6a8172
@@ -10,4 +10,6 @@
10
10
  // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
11
  // about supported directives.
12
12
  //
13
- //= require_tree .
13
+ //= require ./easy_togglers
14
+ //= require ./jquery.entityarray
15
+ //= require ./redmine_extensions
@@ -0,0 +1,6 @@
1
+ /**
2
+ * code, that cannot be delayed after window.onload or deferred
3
+ */
4
+ //= require ./blocking_polyfill
5
+ //= require ./blocking_schedule
6
+ //= require ./blocking_module
@@ -0,0 +1,58 @@
1
+ (function () {
2
+ "use strict";
3
+ /**
4
+ * @type {Object.<String,Array.<Function>>}
5
+ */
6
+ var waitingModules = {};
7
+ /**
8
+ * @type {Object<String,boolean>}
9
+ */
10
+ var registeredModules = {};
11
+
12
+
13
+ window.EASY = window.EASY || {};
14
+ /**
15
+ * Module constructor. Execute [func] only if [moduleName] is registered
16
+ * Works also, if EASY.registerModule is called after module definition
17
+ * @param {String} moduleName
18
+ * @param {Function} func
19
+ * @param {...*} rest - parameters for [func]
20
+ */
21
+ EASY.module = function easyModule(moduleName, func, rest) {
22
+ if (registeredModules[moduleName]) {
23
+ if (rest !== undefined) {
24
+ func.apply(window, Array.prototype.slice.call(arguments, 2));
25
+ } else {
26
+ func();
27
+ }
28
+ return;
29
+ }
30
+ var modules = waitingModules[moduleName];
31
+ if (!modules) {
32
+ waitingModules[moduleName] = modules = [];
33
+ }
34
+ if (rest) {
35
+ var args = Array.prototype.slice.call(arguments, 2);
36
+ modules.push(function () {
37
+ func.apply(window, args);
38
+ })
39
+ } else {
40
+ modules.push(func);
41
+ }
42
+ };
43
+ /**
44
+ * Enables modules with [moduleName] name
45
+ * If any modules are in waitingModules, they are executed immediately.
46
+ * @param {String} moduleName
47
+ */
48
+ EASY.registerModule = function registerModule(moduleName) {
49
+ registeredModules[moduleName] = true;
50
+ if (waitingModules[moduleName]) {
51
+ var modules = waitingModules[moduleName];
52
+ for (var i = 0; i < modules.length; i++) {
53
+ modules[i]();
54
+ }
55
+ delete waitingModules[moduleName];
56
+ }
57
+ };
58
+ })();
@@ -0,0 +1,59 @@
1
+
2
+ (function($, window, undefined) {
3
+ // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
4
+ // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
5
+
6
+ // requestAnimationFrame polyfill by Erik Moller
7
+ // fixes from Paul Irish and Tino Zijdel
8
+
9
+ var lastTime = 0,
10
+ running,
11
+ animate = function (elem) {
12
+ if (running) {
13
+ window.requestAnimationFrame(animate, elem);
14
+ jQuery.fx.tick();
15
+ }
16
+ },
17
+ vendors = ['ms', 'moz', 'webkit', 'o'];
18
+
19
+ for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
20
+ window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
21
+ window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
22
+ || window[vendors[x]+'CancelRequestAnimationFrame'];
23
+ }
24
+
25
+ if (!window.requestAnimationFrame)
26
+ window.requestAnimationFrame = function(fn, element) {
27
+ var currTime = new Date().getTime(),
28
+ delta = currTime - lastTime,
29
+ timeToCall = Math.max(0, 16 - delta);
30
+
31
+ var id = window.setTimeout(function() {
32
+ fn(currTime + timeToCall);
33
+ },
34
+ timeToCall
35
+ );
36
+
37
+ lastTime = currTime + timeToCall;
38
+
39
+ return id;
40
+ };
41
+
42
+ if (!window.cancelAnimationFrame) {
43
+ window.cancelAnimationFrame = function(id) {
44
+ clearTimeout(id);
45
+ };
46
+ }
47
+
48
+ jQuery.fx.timer = function (timer) {
49
+ if (timer() && jQuery.timers.push(timer) && !running) {
50
+ running = true;
51
+ animate(timer.elem);
52
+ }
53
+ };
54
+
55
+ jQuery.fx.stop = function() {
56
+ running = false;
57
+ };
58
+
59
+ }(jQuery, this));
@@ -0,0 +1,125 @@
1
+ (function () {
2
+ "use strict";
3
+ /**
4
+ * @typedef {Function} SchedulePrerequisite
5
+ * @return {boolean}
6
+ */
7
+ /**
8
+ * @typedef {{func:Function,[priority]:number,[pre]:SchedulePrerequisite}} ScheduleTask
9
+ */
10
+ var lateMaxDelay = 3;
11
+ var lateDelay = lateMaxDelay;
12
+ /** @type {Array.<ScheduleTask>} */
13
+ var mainArray = [];
14
+ /** @type {Array.<ScheduleTask>} */
15
+ var lateArray = [];
16
+ /** @type {Array.<ScheduleTask|null>} */
17
+ var prerequisiteArray = [];
18
+
19
+ /** @param {ScheduleTask} a
20
+ * @param {ScheduleTask} b
21
+ */
22
+ var sortFunction = function (a, b) {
23
+ return b.priority - a.priority;
24
+ };
25
+
26
+ var tick = function () {
27
+ var count1 = 0;
28
+ if (mainArray.length > 0) {
29
+ count1 = mainArray.length;
30
+ mainArray.sort(sortFunction);
31
+ for (var i = 0; i < mainArray.length; i++) {
32
+ mainArray[i].func();
33
+ }
34
+ mainArray = [];
35
+ lateDelay = lateMaxDelay;
36
+ }
37
+ var count2 = executePrerequisites();
38
+ var count3 = 0;
39
+ if (lateArray.length) {
40
+ if (lateDelay === 0) {
41
+ lateArray.sort(sortFunction);
42
+ // console.log(lateArray.map(function (p1) {
43
+ // return p1.priority
44
+ // }));
45
+ var limitPriority = lateArray[0].priority - 5;
46
+ for (i = 0; i < lateArray.length; i++) {
47
+ if (lateArray[i].priority <= limitPriority) break;
48
+ lateArray[i].func.call(window);
49
+ }
50
+ if (i === lateArray.length) {
51
+ count3 = lateArray.length;
52
+ lateArray = [];
53
+ lateDelay = lateMaxDelay;
54
+ } else {
55
+ lateArray = lateArray.slice(i);
56
+ count3 = i;
57
+ }
58
+ } else {
59
+ lateDelay--;
60
+ }
61
+ }
62
+ if (EASY.schedule.out && (count1 || count2 || count3)) {
63
+ console.log("EE: " + count1 + " REQ: " + count2 + " LATE: " + count3);
64
+ }
65
+ };
66
+ var isNotNull = function (a) {
67
+ return a !== null;
68
+ };
69
+ /** @return {number} */
70
+ var executePrerequisites = function () {
71
+ if (prerequisiteArray.length === 0) return 0;
72
+ var count = 0;
73
+ for (var i = 0; i < prerequisiteArray.length; i++) {
74
+ if (prerequisiteArray[i].pre()) {
75
+ count++;
76
+ prerequisiteArray[i].func.call(window);
77
+ prerequisiteArray[i] = null;
78
+ }
79
+ }
80
+ if (count) {
81
+ prerequisiteArray = prerequisiteArray.filter(isNotNull);
82
+ count += executePrerequisites();
83
+ }
84
+ return count;
85
+ };
86
+
87
+ var cycle = function scheduleCycle() {
88
+ tick();
89
+ window.requestAnimationFrame(cycle);
90
+ };
91
+ document.addEventListener("DOMContentLoaded", cycle);
92
+ window.EASY = window.EASY || {};
93
+ /**
94
+ *
95
+ * @type {{out: boolean, late: EASY.schedule.late, require: EASY.schedule.require, main: EASY.schedule.main}}
96
+ */
97
+ EASY.schedule = {
98
+ out: false,
99
+ /**
100
+ * Functions, which should be executed right after "DOMContentLoaded" event
101
+ * @param {Function} func
102
+ * @param {number} [priority]
103
+ */
104
+ main: function (func, priority) {
105
+ mainArray.push({func: func, priority: priority || 0})
106
+ },
107
+ /**
108
+ * Functions, which should wait for prerequisite fulfillment
109
+ * @param {Function} func
110
+ * @param {SchedulePrerequisite} prerequisite
111
+ */
112
+ require: function (func, prerequisite) {
113
+ prerequisiteArray.push({func: func, pre: prerequisite})
114
+ },
115
+ /**
116
+ * Functions, which should be executed after several render loops after "DOMContentLoaded" event
117
+ * @param {Function} func
118
+ * @param {number} [priority]
119
+ */
120
+ late: function (func, priority) {
121
+ lateArray.push({func: func, priority: priority || 0})
122
+ }
123
+ };
124
+ })();
125
+
@@ -55,4 +55,4 @@ var EasyToggler = new function() {
55
55
  };
56
56
  };
57
57
 
58
- $(document).ready(EasyToggler.ensureToggle);
58
+ EASY.schedule.main(EasyToggler.ensureToggle);
@@ -31,242 +31,6 @@ REDMINE_EXTENSIONS = {
31
31
 
32
32
  };
33
33
 
34
-
35
- // TODO delete - it will be added to extensions
36
- (function($, undefined) {
37
-
38
- var plugin = 'easygrouploader';
39
- if( $.fn[plugin] )
40
- return;
41
- var defaults = {
42
- next_button_cols: 1,
43
- load_opened: false,
44
- load_limit: 25,
45
- texts: {
46
- 'next': 'Next',
47
- }
48
- };
49
-
50
- $.fn[plugin] = function(options, methodParams) {
51
- $.each($(this), function(idx) {
52
- var instance = $(this).data('plugin_' + plugin);
53
- if (!instance) {
54
- instance = new EasyGroupLoader(this, options);
55
- $(this).data('plugin_' + plugin, instance);
56
- } else if (typeof options === 'string') {
57
- switch (options) {
58
- case 'load_groups':
59
- if (instance.options.load_opened)
60
- instance.load_all_groups();
61
- }
62
- }
63
- });
64
- return $(this);
65
- };
66
-
67
-
68
- function EasyGroupLoader(elem, options) {
69
- this.groupsContainer = $(elem);
70
- this.options = $.extend({}, defaults, options);
71
- this.loadUrl = options.loadUrl || elem.data('url');
72
- this.callback = options.callback;
73
- this.texts = this.options.texts;
74
-
75
- this.init();
76
- }
77
-
78
- EasyGroupLoader.prototype.init = function()
79
- {
80
- var self = this;
81
- this.groupsContainer.on('click', '.group .expander', function(evt) {
82
- var $row = $(this).closest('tr.group');
83
- var group = $row.data('group') || new Group(self, $row);
84
-
85
- if (!group.loaded) {
86
- if (!group.header.hasClass('group-loaded')) {
87
- group.load();
88
- group.toggle();
89
- }
90
- } else {
91
- group.toggle();
92
- if(typeof(self.callback) === 'function')
93
- self.callback();
94
- }
95
-
96
- });
97
- if (this.options.load_opened)
98
- this.load_all_groups();
99
- };
100
-
101
- EasyGroupLoader.prototype.initInlineEdit = function()
102
- {
103
- $('.multieditable-container:not(.multieditable-initialized)', this.groupsContainer).each(function() {
104
- initInlineEditForContainer(this);
105
- });
106
- initProjectEdit();
107
- initEasyAutocomplete();
108
- };
109
-
110
- EasyGroupLoader.prototype.load_all_groups = function()
111
- {
112
- var group;
113
- var self = this;
114
- var groups_to_load = [];
115
- var entity_count = 0;
116
- $('.group', this.groupsContainer).not('.group-loaded').each(function() {
117
- group = $(this).data('group') || new Group(self, $(this));
118
- if (!group.loaded) {
119
- groups_to_load.push(group);
120
- entity_count += group.count;
121
- }
122
- if (entity_count >= self.options.load_limit) {
123
- self.load_groups(groups_to_load);
124
- entity_count = 0;
125
- groups_to_load = [];
126
- }
127
- });
128
- if (groups_to_load.length > 0) {
129
- this.load_groups(groups_to_load);
130
- }
131
- };
132
-
133
- EasyGroupLoader.prototype.load_groups = function(groups_to_load) {
134
- var self = this;
135
- var group_names = groups_to_load.map(function(group) {
136
- return group.group_value;
137
- });
138
- // var url = EPExtensions.setAttrToUrl(, 'group_to_load', group_names);
139
- $.ajax(this.loadUrl, {
140
- method: 'GET',
141
- data: { group_to_load: group_names },
142
- success: function(data, textStatus, request) {
143
- var parsed = (typeof data === 'object') ? data : $.parseJSON(data);
144
-
145
- $.each(groups_to_load, function(idx, group) {
146
- group.parseData(parsed[group.group_name]);
147
- group.toggle();
148
- });
149
- self.initInlineEdit();
150
- }
151
- });
152
- };
153
-
154
- function Group(loader, header)
155
- {
156
- this.loader = loader;
157
- this.header = header;
158
- this.header.data('group', this);
159
- this.group_name = this.header.data('group-name');
160
- this.group_value = this.group_name;
161
- if( $.isArray(this.group_name) ) {
162
- // potencialne nebezpecne - TODO: vymyslet spravny oddelovac
163
- this.group_name = '["' + this.group_name.join('", "') + '"]';
164
- }
165
- this.count = parseInt(this.header.data('entity-count'));
166
- this.pages = this.header.data('pages') || 1;
167
- this.loaded = this.header.hasClass('preloaded');
168
- }
169
-
170
- Group.prototype.toggle = function() {
171
- EPExtensions.issuesToggleRowGroup(this.header);
172
- };
173
-
174
- Group.prototype.load = function() {
175
- var $hrow = this.header;
176
- var self = this;
177
-
178
- if (!$hrow.hasClass('group-loaded')) {
179
- $hrow.addClass('group-loaded');
180
- $.ajax(this.loader.loadUrl, {
181
- method: 'GET',
182
- data: {
183
- group_to_load: this.group_value
184
- },
185
- success: function(data, textStatus, request) {
186
- self.parseData(data);
187
- self.loader.initInlineEdit();
188
- if(typeof(self.loader.callback) === 'function')
189
- self.loader.callback();
190
- }
191
- });
192
- }
193
- };
194
-
195
- Group.prototype.parseData = function(data) {
196
- var $hrow = this.header;
197
-
198
- this.rows = $(data);
199
- $hrow.after(this.rows);
200
- $hrow.data('group-page', 1);
201
- this.loaded = true;
202
- if (this.pages > 1) {
203
- this.createNextButton();
204
- // .find doesn't work on this set
205
- this.rows.filter("tr:last").after(this.next_button);
206
- }
207
- };
208
-
209
- Group.prototype.loadNext = function() {
210
- var $hrow = this.header;
211
- var page = $hrow.data('group-page') + 1;
212
- var self = this;
213
-
214
- if (page <= this.pages) {
215
- $.ajax(this.loader.loadUrl, {
216
- method: 'GET',
217
- data: {
218
- page: page,
219
- group_to_load: this.group_value
220
- },
221
- success: function(data, textStatus, request) {
222
- self.next_button.before(data);
223
-
224
- self.loader.initInlineEdit();
225
- $hrow.data('group-page', page);
226
- if (self.pages === page) {
227
- self.next_button.remove();
228
- }
229
- }
230
- });
231
- }
232
- };
233
-
234
- Group.prototype.createNextButton = function() {
235
- //var next_link_url = EPExtensions.setAttrToUrl(this.loader.loadUrl, 'group_to_load', this.group_value);
236
- var next_link_url = this.loader.loadUrl + ( this.loader.loadUrl.indexOf('?') >= 0 ? '&' : '?' ) + $.param({group_to_load: this.group_value});
237
- this.next_link = $('<a>', {href: next_link_url, 'class': 'button'}).text(this.loader.texts['next']).append($("<i>", {"class": "icon-arrow"}));
238
- this.next_button = $('<tr/>', {'class': 'easy-next-button'}).html($('<td>', {colspan: this.loader.options.next_button_cols, "class": "text-center"}).html(this.next_link));
239
-
240
- var self = this;
241
-
242
- this.next_link.click(function(evt) {
243
- evt.preventDefault();
244
- self.loadNext();
245
- });
246
- };
247
-
248
- })(jQuery);
249
-
250
- window.cancelAnimFrame = ( function() {
251
- return window.cancelAnimationFrame ||
252
- window.webkitCancelRequestAnimationFrame ||
253
- window.mozCancelRequestAnimationFrame ||
254
- window.oCancelRequestAnimationFrame ||
255
- window.msCancelRequestAnimationFrame ||
256
- clearTimeout;
257
- } )();
258
-
259
- window.requestAnimFrame = (function(){
260
- return window.requestAnimationFrame ||
261
- window.webkitRequestAnimationFrame ||
262
- window.mozRequestAnimationFrame ||
263
- window.oRequestAnimationFrame ||
264
- window.msRequestAnimationFrame ||
265
- function(callback){
266
- return window.setTimeout(callback, 1000 / 60);
267
- };
268
- })();
269
-
270
34
  window.showFlashMessage = (function(type, message, delay){
271
35
  var $content = $("#content");
272
36
  $content.find(".flash").remove();
@@ -291,7 +55,7 @@ window.showFlashMessage = (function(type, message, delay){
291
55
  var $element = $(element);
292
56
  if(delay){
293
57
  setTimeout(function(){
294
- requestAnimFrame(function(){
58
+ window.requestAnimationFrame(function(){
295
59
  closeFlashMessage($element);
296
60
  });
297
61
  }, delay);
@@ -3,20 +3,9 @@
3
3
  #
4
4
  class EasySettingsController < ApplicationController
5
5
 
6
- before_filter :require_admin, only: [:edit, :update]
7
- before_filter :find_optional_project
8
- before_filter :find_plugin, only: [:edit, :update]
9
-
10
- def new
11
- end
12
-
13
- def create
14
- if @easy_settings.save
15
- redirect_to :back
16
- else
17
- render :new
18
- end
19
- end
6
+ before_action :require_admin, only: [:edit, :update]
7
+ before_action :find_optional_project
8
+ before_action :find_plugin, only: [:edit, :update]
20
9
 
21
10
  def edit
22
11
  @settings = Setting.send("plugin_#{@plugin.id}")
@@ -25,11 +14,11 @@ class EasySettingsController < ApplicationController
25
14
 
26
15
  def update
27
16
  if params[:settings]
28
- Setting.send("plugin_#{@plugin.id}=", params[:settings])
17
+ Setting.send("plugin_#{@plugin.id}=", params[:settings].permit!)
29
18
  end
30
19
 
31
20
  if params[:easy_setting]
32
- @easy_settings = EasySettings::ParamsWrapper.from_params(params[:easy_setting], project: @project, prefix: @plugin.id)
21
+ @easy_settings = EasySettings::ParamsWrapper.from_params(params[:easy_setting].permit!, project: @project, prefix: @plugin.id)
33
22
 
34
23
  if @easy_settings.save
35
24
  # All good
@@ -108,6 +108,21 @@ module RedmineExtensions
108
108
  end
109
109
  end
110
110
 
111
+ def late_javascript_tag(content_or_options_with_block = nil, html_options = {}, &block)
112
+ content =
113
+ if block_given?
114
+ html_options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
115
+ capture(&block)
116
+ else
117
+ content_or_options_with_block
118
+ end
119
+ html_options.reverse_merge!({type:'application/javascript'})
120
+ priority = html_options.delete(:priority) || 0
121
+ content = " EASY.schedule.late(function(){#{content} }, #{priority});"
122
+
123
+ content_tag(:script, javascript_cdata_section(content), html_options)
124
+ end
125
+
111
126
 
112
127
  # ==== Options
113
128
  # * <tt>class: Hash or String</tt> - This option can be used to add custom CSS classes. It can be *String* or *Hash*.
@@ -240,7 +255,7 @@ module RedmineExtensions
240
255
 
241
256
  content_tag(:span, :class => 'easy-multiselect-tag-container') do
242
257
  text_field_tag('', '', (options[:html_options] || {}).merge(id: options[:id])) +
243
- javascript_tag("$('##{options[:id]}').easymultiselect({multiple: #{options[:multiple]}, rootElement: #{options[:rootElement].to_json}, inputName: '#{name}', preload: #{options[:preload]}, combo: #{options[:combo]}, source: #{source}, selected: #{selected_values.to_json}, show_toggle_button: #{options[:show_toggle_button]}, select_first_value: #{options[:select_first_value]}, load_immediately: #{options[:load_immediately]}, autocomplete_options: #{(options[:jquery_auto_complete_options]||{}).to_json} });")
258
+ late_javascript_tag("$('##{options[:id]}').easymultiselect({multiple: #{options[:multiple]}, rootElement: #{options[:rootElement].to_json}, inputName: '#{name}', preload: #{options[:preload]}, combo: #{options[:combo]}, source: #{source}, selected: #{selected_values.to_json}, show_toggle_button: #{options[:show_toggle_button]}, select_first_value: #{options[:select_first_value]}, load_immediately: #{options[:load_immediately]}, autocomplete_options: #{(options[:jquery_auto_complete_options]||{}).to_json} });")
244
259
  end
245
260
  end
246
261
 
@@ -73,7 +73,6 @@ class EasySetting < ActiveRecord::Base
73
73
  after_save :mapper_after_save
74
74
  after_destroy :invalidate_cache
75
75
 
76
- attr_protected :id
77
76
  serialize :value
78
77
 
79
78
  @@mapper = EasySettings::Mapper.new
@@ -1,4 +1,4 @@
1
- class CreateEasySettings < ActiveRecord::Migration
1
+ class CreateEasySettings < RedmineExtensions::Migration
2
2
  def up
3
3
  if table_exists?(:easy_settings)
4
4
  add_column(:easy_settings, :type, :string, null: true) unless column_exists?(:easy_settings, :type)
@@ -1,4 +1,4 @@
1
- class CreateEntityAssignments < ActiveRecord::Migration
1
+ class CreateEntityAssignments < RedmineExtensions::Migration
2
2
  def self.up
3
3
  unless table_exists?(:easy_entity_assignments)
4
4
  create_table :easy_entity_assignments do |t|
@@ -1,7 +1,7 @@
1
- class <%= model_name %>CustomField < CustomField
2
-
3
- def type_name
4
- :label_<%= @model_name_pluralize_underscored %>
5
- end
6
-
7
- end
1
+ class <%= model_name %>CustomField < CustomField
2
+
3
+ def type_name
4
+ :label_<%= @model_name_pluralize_underscored %>
5
+ end
6
+
7
+ end
@@ -1,5 +1,5 @@
1
- api.array :<%= model_name_pluralize_underscored %>, api_meta(total_count: @entity_count, offset: @offset, limit: @limit) do
2
- @entities.each do |<%= model_name_underscored %>|
3
- render_api_<%= model_name_underscored %>(api, <%= model_name_underscored %>)
4
- end
5
- end
1
+ api.array :<%= model_name_pluralize_underscored %>, api_meta(total_count: @entity_count, offset: @offset, limit: @limit) do
2
+ @entities.each do |<%= model_name_underscored %>|
3
+ render_api_<%= model_name_underscored %>(api, <%= model_name_underscored %>)
4
+ end
5
+ end
@@ -1 +1 @@
1
- <h1><%%= link_to(@<%= model_name_underscored %>.to_s, @<%= model_name_underscored %>_url) %></h1>
1
+ <h1><%%= link_to(@<%= model_name_underscored %>.to_s, @<%= model_name_underscored %>_url) %></h1>
@@ -1,2 +1,2 @@
1
- <%%= @<%= model_name_underscored %>.to_s %>
2
- <%%= @<%= model_name_underscored %>_url %>
1
+ <%%= @<%= model_name_underscored %>.to_s %>
2
+ <%%= @<%= model_name_underscored %>_url %>
@@ -1,2 +1,2 @@
1
- <%%= @<%= model_name_underscored %>.to_s %>
2
- <%%= @<%= model_name_underscored %>_url %>
1
+ <%%= @<%= model_name_underscored %>.to_s %>
2
+ <%%= @<%= model_name_underscored %>_url %>
@@ -1,13 +1,13 @@
1
- <% if project? %>
2
- resources :projects do
3
- resources :<%= model_name_pluralize_underscored %>
4
- end
5
- <% end %>
6
- resources :<%= model_name_pluralize_underscored %> do
7
- collection do
8
- get 'autocomplete'
9
- get 'bulk_edit'
10
- post 'bulk_update'
11
- get 'context_menu'
12
- end
1
+ <% if project? %>
2
+ resources :projects do
3
+ resources :<%= model_name_pluralize_underscored %>
4
+ end
5
+ <% end %>
6
+ resources :<%= model_name_pluralize_underscored %> do
7
+ collection do
8
+ get 'autocomplete'
9
+ get 'bulk_edit'
10
+ post 'bulk_update'
11
+ get 'context_menu'
12
+ end
13
13
  end
@@ -2,6 +2,7 @@ Description:
2
2
  The plugin generator creates stubs for new Redmine plugin.
3
3
  Plugin is prepared for use in Redmine and Easy Redmine as well.
4
4
  You can use --customer flag to generate a special plugin if you can make just a few changes to code. Backup this plugin before Redmine or Easy Redmine upgrade and move back for keep you changes.
5
+ You can use --path flag to specify parent directory.
5
6
 
6
7
  Example:
7
8
  rails g redmine_extensions:plugin NameOfNewPlugin
@@ -5,13 +5,15 @@ module RedmineExtensions
5
5
  attr_reader :plugin_path, :plugin_name_underscored, :plugin_pretty_name, :plugin_title
6
6
 
7
7
  class_option :customer, type: :boolean, default: false, banner: '', :desc => 'plugin will act as customer modification. It is useful for changing few things and be uptodate with the core.'
8
+ class_option :path, type: :string, default: nil, banner: '', :desc => 'relative path to parent directory for plugin.'
8
9
 
9
10
  def initialize(*args)
10
11
  super
11
12
 
12
13
  @plugin_name_underscored = options[:customer] ? "modification_#{file_name.underscore}" : file_name.underscore
13
14
  @plugin_pretty_name = plugin_name_underscored.titleize
14
- @plugin_path = "plugins/#{plugin_name_underscored}"
15
+
16
+ @plugin_path = (options[:path] || "plugins") + "/#{plugin_name_underscored}"
15
17
  @plugin_title = @plugin_name_underscored.camelize
16
18
  end
17
19
 
@@ -1,2 +1,2 @@
1
- require "redmine_extensions/engine"
2
- require 'redmine_extensions/core_ext'
1
+ require_relative "./redmine_extensions/engine"
2
+ require_relative './redmine_extensions/core_ext'
@@ -1,3 +1,3 @@
1
- require 'redmine_extensions/core_ext/object'
2
- require 'redmine_extensions/core_ext/string'
3
- require 'redmine_extensions/core_ext/date_range'
1
+ require_relative './core_ext/object'
2
+ require_relative './core_ext/string'
3
+ require_relative './core_ext/date_range'
@@ -3,8 +3,8 @@ require 'query'
3
3
  module RedmineExtensions
4
4
  module QueryColumnAdapter
5
5
  def self.included(base)
6
- base.extend(ClassMethods)
7
- base.send(:include, InstanceMethods)
6
+ base.extend ClassMethods
7
+ base.include InstanceMethods
8
8
 
9
9
  base.class_eval do
10
10
  attr_accessor :includes
@@ -168,8 +168,8 @@ end
168
168
  if Redmine::Plugin.installed?(:easy_extensions)
169
169
  # EasyQuery exist
170
170
  else
171
- QueryColumn.__send__(:include, RedmineExtensions::QueryColumnAdapter)
171
+ QueryColumn.include RedmineExtensions::QueryColumnAdapter
172
172
  RedmineExtensions::PatchManager.register_model_patch('Query', 'RedmineExtensions::QueryAdapter')
173
173
  EasyQuery = EasyQueryAdapter
174
- EasyQuery.__send__(:prepend, RedmineExtensions::QueryAdapterDefaults)
174
+ EasyQuery.prepend RedmineExtensions::QueryAdapterDefaults
175
175
  end
@@ -1,8 +1,8 @@
1
1
  module EasySettings
2
2
  end
3
3
 
4
- require 'redmine_extensions/easy_settings/key'
5
- require 'redmine_extensions/easy_settings/key_dsl'
6
- require 'redmine_extensions/easy_settings/mapper'
7
- require 'redmine_extensions/easy_settings/form_model'
8
- require 'redmine_extensions/easy_settings/params_wrapper'
4
+ require_relative './easy_settings/key'
5
+ require_relative './easy_settings/key_dsl'
6
+ require_relative './easy_settings/mapper'
7
+ require_relative './easy_settings/form_model'
8
+ require_relative './easy_settings/params_wrapper'
@@ -7,7 +7,6 @@ module EasySettings
7
7
  if !raw_params.is_a?(Hash) && !raw_params.is_a?(ActionController::Parameters)
8
8
  raw_params = {}
9
9
  end
10
-
11
10
  new(raw_params, project, prefix)
12
11
  end
13
12
 
@@ -1,8 +1,8 @@
1
1
  require 'active_support/dependencies'
2
- require 'redmine_extensions/patch_manager'
3
- require 'redmine_extensions/redmine_patches/patches'
2
+ require_relative './patch_manager'
3
+ require_relative './redmine_patches/patches'
4
4
 
5
- require 'redmine_extensions/query_output'
5
+ require_relative './query_output'
6
6
 
7
7
  module RedmineExtensions
8
8
  class Engine < ::Rails::Engine
@@ -16,18 +16,20 @@ module RedmineExtensions
16
16
 
17
17
  config.autoload_paths << config.root.join('lib')
18
18
  config.eager_load_paths << config.root.join('app', 'models', 'easy_queries')
19
+ config.assets.precompile << 'redmine_extensions/applications.js'
20
+ config.assets.precompile << 'redmine_extensions/blocking.js'
19
21
 
20
22
  #config.to_prepare goes after Reloader.to_prepare
21
- ActionDispatch::Reloader.to_prepare do
23
+ RedmineExtensions::Reloader.to_prepare do
22
24
  RedmineExtensions::QueryOutput.register_output RedmineExtensions::QueryOutputs::ListOutput
23
25
  RedmineExtensions::QueryOutput.register_output RedmineExtensions::QueryOutputs::TilesOutput
24
26
  # RedmineExtensions::BasePresenter.register 'RedmineExtensions::EasyQueryPresenter', 'EasyQuery'
25
27
  # ApplicationController.send :include, RedmineExtensions::RailsPatches::ControllerQueryHelpers
26
- ApplicationController.send :include, RedmineExtensions::RenderingHelper
28
+ ApplicationController.include RedmineExtensions::RenderingHelper
27
29
  end
28
30
 
29
31
  initializer 'redmine_extensions.initialize' do |app|
30
- ActionDispatch::Routing::RouteSet::Generator.send(:include, RedmineExtensions::RailsPatches::RouteSetGeneratorPatch)
32
+ ActionDispatch::Routing::RouteSet::Generator.prepend RedmineExtensions::RailsPatches::RouteSetGeneratorPatch
31
33
  end
32
34
 
33
35
  initializer 'redmine_extensions.append_migrations' do |app|
@@ -58,23 +60,23 @@ module RedmineExtensions
58
60
  include RedmineExtensions::RailsPatches::ActiveRecord
59
61
  end
60
62
  ActiveSupport.on_load(:action_view) do
61
- default_form_builder.send(:include, RedmineExtensions::RailsPatches::FormBuilderPatch)
63
+ default_form_builder.include RedmineExtensions::RailsPatches::FormBuilderPatch
62
64
  end
63
65
  end
64
66
 
65
67
  initializer 'redmine_extensions.initialize_easy_plugins', after: :load_config_initializers do
66
- require 'redmine_extensions/hooks'
68
+ require_relative './hooks'
67
69
 
68
70
  unless Redmine::Plugin.installed?(:easy_extensions)
69
71
  ActiveSupport.run_load_hooks(:easyproject, self)
70
72
  end
71
73
 
72
- require 'redmine_extensions/easy_query_adapter'
73
- require 'redmine_extensions/easy_entity_formatters/easy_entity_formatter'
74
+ require_relative './easy_query_adapter'
75
+ require_relative './easy_entity_formatters/easy_entity_formatter'
74
76
  end
75
77
 
76
78
  # initializer :add_html_formatting do |app|
77
- # require "redmine_extensions/html_formatting"
79
+ # require_relative "./html_formatting"
78
80
  # Redmine::WikiFormatting.register(:HTML, RedmineExtensions::HTMLFormatting::Formatter, RedmineExtensions::HTMLFormatting::Helper)
79
81
  # end
80
82
 
@@ -1,16 +1,30 @@
1
1
  module RedmineExtensions
2
2
  class Hooks < Redmine::Hook::ViewListener
3
+ @visited = false
4
+ def easy_extensions_blocking_javascripts_hook(context={})
5
+ if defined?(EasyExtensions)
6
+ @visited = true
7
+ context[:template].require_asset('redmine_extensions/blocking')
8
+ end
9
+ end
3
10
 
4
- def view_layouts_base_html_head(context={})
11
+ def easy_extensions_javascripts_hook(context={})
5
12
  if defined?(EasyExtensions)
6
- context[:hook_caller].javascript_include_tag('redmine_extensions/application')
7
- else
13
+ context[:template].require_asset('redmine_extensions/blocking') unless @visited
14
+ context[:template].require_asset('redmine_extensions/application')
15
+ # context[:hook_caller].javascript_include_tag('redmine_extensions/application')
16
+ end
17
+ end
18
+
19
+ def view_layouts_base_html_head(context={})
20
+ unless defined?(EasyExtensions)
21
+ javascript_include_tag('redmine_extensions/blocking_polyfill') +
22
+ javascript_include_tag('redmine_extensions/blocking_schedule') +
23
+ javascript_include_tag('redmine_extensions/blocking_module') +
8
24
  javascript_include_tag('redmine_extensions/jquery.entityarray') +
9
25
  javascript_include_tag('redmine_extensions/redmine_extensions') +
10
26
  javascript_include_tag('redmine_extensions/easy_togglers')
11
27
  end
12
-
13
28
  end
14
-
15
29
  end
16
30
  end
@@ -1,3 +1,3 @@
1
- require 'redmine_extensions/html_formatting/internals'
2
- require 'redmine_extensions/html_formatting/formatter'
3
- require 'redmine_extensions/html_formatting/helper'
1
+ require_relative './html_formatting/internals'
2
+ require_relative './html_formatting/formatter'
3
+ require_relative './html_formatting/helper'
@@ -0,0 +1,9 @@
1
+ module RedmineExtensions
2
+ if Rails.version.start_with?('5')
3
+ class Migration < ActiveRecord::Migration[4.2]
4
+ end
5
+ else
6
+ class Migration < ActiveRecord::Migration
7
+ end
8
+ end
9
+ end
@@ -116,8 +116,8 @@ module RedmineExtensions
116
116
  controller_klass = controller_klass_name.constantize
117
117
 
118
118
  @registered_easy_page_helpers.each do |helper_klass_name|
119
- if m = helper_klass_name.match(/\A(\S+)Helper\z/)
120
- helper_klass_symbol = m[1]
119
+ if helper_klass_name.end_with?('Helper')
120
+ helper_klass_symbol = helper_klass_name[0, helper_klass_name.index('Helper')]
121
121
  end
122
122
 
123
123
  controller_klass.class_eval "helper :#{helper_klass_symbol.underscore}" if helper_klass_symbol
@@ -352,18 +352,40 @@ module RedmineExtensions
352
352
  pm_klass = patching_module.constantize
353
353
  oktp_klass = original_klass_to_patch.constantize
354
354
 
355
- oktp_klass.send(:include, pm_klass) # unless oktp_klass.include?(pm_klass)
355
+ if @options[:prepend]
356
+ oktp_klass.prepend pm_klass # unless oktp_klass.include?(pm_klass)
357
+ else
358
+ oktp_klass.include pm_klass # unless oktp_klass.include?(pm_klass)
359
+ end
356
360
  end
357
361
 
358
362
  end
359
363
 
360
364
  end
365
+
366
+ module Reloader
367
+ def self.to_prepare(*args, &block)
368
+ if defined? ActiveSupport::Reloader
369
+ ActiveSupport::Reloader.to_prepare(*args, &block)
370
+ else
371
+ ActionDispatch::Reloader.to_prepare(*args, &block)
372
+ end
373
+ end
374
+
375
+ def self.to_cleanup(*args, &block)
376
+ if defined? ActiveSupport::Reloader
377
+ ActiveSupport::Reloader.to_complete(*args, &block)
378
+ else
379
+ ActionDispatch::Reloader.to_cleanup(*args, &block)
380
+ end
381
+ end
382
+ end
361
383
  end
362
384
 
363
385
  ActiveSupport.on_load(:easyproject, yield: true) do
364
386
  RedmineExtensions::PatchManager.apply_persisting_patches
365
387
  end
366
388
 
367
- ActionDispatch::Reloader.to_prepare do
389
+ RedmineExtensions::Reloader.to_prepare do
368
390
  RedmineExtensions::PatchManager.apply_reloadable_patches
369
391
  end
@@ -1,20 +1,10 @@
1
1
  module RedmineExtensions
2
2
  module RailsPatches
3
3
  module RouteSetGeneratorPatch
4
-
5
- def self.included(base)
6
-
7
- base.class_eval do
8
- def use_relative_controller_with_redmine_extensions!
9
- return if current_controller && current_controller.start_with?('redmine_extensions')
10
- use_relative_controller_without_redmine_extensions!
11
- end
12
-
13
- alias_method_chain :use_relative_controller!, :redmine_extensions
14
- end
15
-
4
+ def use_relative_controller!
5
+ return if current_controller && current_controller.start_with?('redmine_extensions')
6
+ super
16
7
  end
17
-
18
8
  end
19
9
  end
20
10
  end
@@ -2,8 +2,8 @@ module RedmineExtensions
2
2
  module ApplicationControllerPatch
3
3
 
4
4
  def self.included(base)
5
- base.extend(ClassMethods)
6
- base.send(:include, InstanceMethods)
5
+ base.extend ClassMethods
6
+ base.include InstanceMethods
7
7
 
8
8
  base.class_eval do
9
9
  helper_method :easy_extensions?
@@ -29,13 +29,11 @@ module RedmineExtensions
29
29
 
30
30
  private
31
31
 
32
- def save_easy_settings(project = nil)
33
- if params[:easy_setting].is_a?(Hash) || params[:easy_setting].is_a?(ActionController::Parameters)
34
- wrapper = EasySettings::ParamsWrapper.from_params(params.delete(:easy_setting), project: project)
35
- wrapper.save
36
- wrapper
37
- end
38
- end
32
+ def save_easy_settings(project = nil)
33
+ wrapper = EasySettings::ParamsWrapper.from_params(params.require(:easy_setting).permit!, project: project)
34
+ wrapper.save
35
+ wrapper
36
+ end
39
37
 
40
38
  end
41
39
 
@@ -1,3 +1,3 @@
1
1
  module RedmineExtensions
2
- VERSION = '0.2.0'
2
+ VERSION = '0.2.2'
3
3
  end
metadata CHANGED
@@ -1,43 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redmine_extensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Easy Software Ltd
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-26 00:00:00.000000000 Z
11
+ date: 2017-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '4.2'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '6'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - "~>"
27
+ - - ">="
25
28
  - !ruby/object:Gem::Version
26
29
  version: '4.2'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '6'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: actionpack
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
- - - "~>"
37
+ - - ">="
32
38
  - !ruby/object:Gem::Version
33
39
  version: '4.2'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '6'
34
43
  type: :runtime
35
44
  prerelease: false
36
45
  version_requirements: !ruby/object:Gem::Requirement
37
46
  requirements:
38
- - - "~>"
47
+ - - ">="
39
48
  - !ruby/object:Gem::Version
40
49
  version: '4.2'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '6'
41
53
  - !ruby/object:Gem::Dependency
42
54
  name: sqlite3
43
55
  requirement: !ruby/object:Gem::Requirement
@@ -133,6 +145,10 @@ files:
133
145
  - LICENSE
134
146
  - Rakefile
135
147
  - app/assets/javascripts/redmine_extensions/application.js
148
+ - app/assets/javascripts/redmine_extensions/blocking.js
149
+ - app/assets/javascripts/redmine_extensions/blocking_module.js
150
+ - app/assets/javascripts/redmine_extensions/blocking_polyfill.js
151
+ - app/assets/javascripts/redmine_extensions/blocking_schedule.js
136
152
  - app/assets/javascripts/redmine_extensions/easy_togglers.js
137
153
  - app/assets/javascripts/redmine_extensions/jquery.entityarray.js
138
154
  - app/assets/javascripts/redmine_extensions/redmine_extensions.js
@@ -231,6 +247,7 @@ files:
231
247
  - lib/redmine_extensions/html_formatting/formatter.rb
232
248
  - lib/redmine_extensions/html_formatting/helper.rb
233
249
  - lib/redmine_extensions/html_formatting/internals.rb
250
+ - lib/redmine_extensions/migration.rb
234
251
  - lib/redmine_extensions/patch_manager.rb
235
252
  - lib/redmine_extensions/query_output.rb
236
253
  - lib/redmine_extensions/query_outputs/list_output.rb
@@ -276,22 +293,22 @@ required_rubygems_version: !ruby/object:Gem::Requirement
276
293
  version: '0'
277
294
  requirements: []
278
295
  rubyforge_project:
279
- rubygems_version: 2.5.2
296
+ rubygems_version: 2.6.7
280
297
  signing_key:
281
298
  specification_version: 4
282
299
  summary: Redmine Extensions is set of usefull features for Redmine. Main focus is
283
300
  on development helpers, but many users can find it helpfull
284
301
  test_files:
285
- - spec/rails_helper.rb
286
- - spec/factories/time_entries.rb
302
+ - spec/factories/easy_queries.rb
287
303
  - spec/factories/easy_settings.rb
288
304
  - spec/factories/issues.rb
289
305
  - spec/factories/projects.rb
306
+ - spec/factories/time_entries.rb
290
307
  - spec/factories/trackers.rb
291
- - spec/factories/easy_queries.rb
292
308
  - spec/factories/users.rb
309
+ - spec/features/autocomplete_spec.rb
310
+ - spec/models/easy_setting_spec.rb
293
311
  - spec/presenters/redmine_extensions/easy_setting_presenter_spec.rb
294
- - spec/support/plugin_generator.rb
312
+ - spec/rails_helper.rb
295
313
  - spec/spec_helper.rb
296
- - spec/models/easy_setting_spec.rb
297
- - spec/features/autocomplete_spec.rb
314
+ - spec/support/plugin_generator.rb