redmine_extensions 0.2.0 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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