Description:
prob manage
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r882:50181c2869eb - - The requested commit is too big and content was truncated. 7 files changed. Show full diff

@@ -0,0 +1,290
1 + /*!
2 + * Tempus Dominus v6.2.4 (https://getdatepicker.com/)
3 + * Copyright 2013-2022 Jonathan Peterson
4 + * Licensed under MIT (https://github.com/Eonasdan/tempus-dominus/blob/master/LICENSE)
5 + */
6 + (function(g,f){typeof exports==='object'&&typeof module!=='undefined'?module.exports=f():typeof define==='function'&&define.amd?define(f):(g=typeof globalThis!=='undefined'?globalThis:g||self,(g.tempusDominus=g.tempusDominus||{},g.tempusDominus.plugins=g.tempusDominus.plugins||{},g.tempusDominus.plugins.customDateFormat=f()));})(this,(function(){'use strict';class CustomDateFormat {
7 + constructor(dateTime, errorMessages) {
8 + this.REGEX_FORMAT = /\[([^\]]+)]|y{1,4}|M{1,4}|d{1,4}|H{1,2}|h{1,2}|t|T|m{1,2}|s{1,2}|Z{1,2}/g;
9 + // noinspection SpellCheckingInspection
10 + this.englishFormats = {
11 + LTS: 'h:mm:ss T',
12 + LT: 'h:mm T',
13 + L: 'MM/dd/yyyy',
14 + LL: 'MMMM d, yyyy',
15 + LLL: 'MMMM d, yyyy h:mm T',
16 + LLLL: 'dddd, MMMM d, yyyy h:mm T',
17 + };
18 + this.formattingTokens = /(\[[^[]*])|([-_:/.,()\s]+)|(T|t|yyyy|yy?|MM?M?M?|Do|dd?|hh?|HH?|mm?|ss?|z|ZZ?)/g;
19 + this.match1 = /\d/; // 0 - 9
20 + this.match2 = /\d\d/; // 00 - 99
21 + this.match3 = /\d{3}/; // 000 - 999
22 + this.match4 = /\d{4}/; // 0000 - 9999
23 + this.match1to2 = /\d\d?/; // 0 - 99
24 + this.matchSigned = /[+-]?\d+/; // -inf - inf
25 + this.matchOffset = /[+-]\d\d:?(\d\d)?|Z/; // +00:00 -00:00 +0000 or -0000 +00 or Z
26 + this.matchWord = /\d*[^-_:/,()\s\d]+/; // Word
27 + this.zoneExpressions = [
28 + this.matchOffset,
29 + (obj, input) => {
30 + obj.offset = this.offsetFromString(input);
31 + },
32 + ];
33 + this.expressions = {
34 + t: [
35 + this.matchWord,
36 + (ojb, input) => {
37 + ojb.afternoon = this.meridiemMatch(input);
38 + },
39 + ],
40 + T: [
41 + this.matchWord,
42 + (ojb, input) => {
43 + ojb.afternoon = this.meridiemMatch(input);
44 + },
45 + ],
46 + fff: [
47 + this.match3,
48 + (ojb, input) => {
49 + ojb.milliseconds = +input;
50 + },
51 + ],
52 + s: [this.match1to2, this.addInput('seconds')],
53 + ss: [this.match1to2, this.addInput('seconds')],
54 + m: [this.match1to2, this.addInput('minutes')],
55 + mm: [this.match1to2, this.addInput('minutes')],
56 + H: [this.match1to2, this.addInput('hours')],
57 + h: [this.match1to2, this.addInput('hours')],
58 + HH: [this.match1to2, this.addInput('hours')],
59 + hh: [this.match1to2, this.addInput('hours')],
60 + d: [this.match1to2, this.addInput('day')],
61 + dd: [this.match2, this.addInput('day')],
62 + Do: [
63 + this.matchWord,
64 + (ojb, input) => {
65 + [ojb.day] = input.match(/\d+/);
66 + if (!this.localization.ordinal)
67 + return;
68 + for (let i = 1; i <= 31; i += 1) {
69 + if (this.localization.ordinal(i).replace(/[\[\]]/g, '') === input) {
70 + ojb.day = i;
71 + }
72 + }
73 + },
74 + ],
75 + M: [this.match1to2, this.addInput('month')],
76 + MM: [this.match2, this.addInput('month')],
77 + MMM: [
78 + this.matchWord,
79 + (obj, input) => {
80 + const months = this.getAllMonths();
81 + const monthsShort = this.getAllMonths('short');
82 + const matchIndex = (monthsShort || months.map((_) => _.slice(0, 3))).indexOf(input) + 1;
83 + if (matchIndex < 1) {
84 + throw new Error();
85 + }
86 + obj.month = matchIndex % 12 || matchIndex;
87 + },
88 + ],
89 + MMMM: [
90 + this.matchWord,
91 + (obj, input) => {
92 + const months = this.getAllMonths();
93 + const matchIndex = months.indexOf(input) + 1;
94 + if (matchIndex < 1) {
95 + throw new Error();
96 + }
97 + obj.month = matchIndex % 12 || matchIndex;
98 + },
99 + ],
100 + y: [this.matchSigned, this.addInput('year')],
101 + yy: [
102 + this.match2,
103 + (obj, input) => {
104 + obj.year = this.parseTwoDigitYear(input);
105 + },
106 + ],
107 + yyyy: [this.match4, this.addInput('year')],
108 + Z: this.zoneExpressions,
109 + ZZ: this.zoneExpressions,
110 + };
111 + this.parseFormattedInput = (input) => {
112 + if (!this.localization.format) {
113 + this.errorMessages.customDateFormatError('No format was provided');
114 + }
115 + try {
116 + if (['x', 'X'].indexOf(this.localization.format) > -1)
117 + return new this.DateTime((this.localization.format === 'X' ? 1000 : 1) * input);
118 + const parser = this.makeParser(this.localization.format);
119 + const { year, month, day, hours, minutes, seconds, milliseconds, zone } = parser(input);
120 + const now = new this.DateTime();
121 + const d = day || (!year && !month ? now.getDate() : 1);
122 + const y = year || now.getFullYear();
123 + let M = 0;
124 + if (!(year && !month)) {
125 + M = month > 0 ? month - 1 : now.getMonth();
126 + }
127 + const h = hours || 0;
128 + const m = minutes || 0;
129 + const s = seconds || 0;
130 + const ms = milliseconds || 0;
131 + if (zone) {
132 + return new this.DateTime(Date.UTC(y, M, d, h, m, s, ms + zone.offset * 60 * 1000));
133 + }
134 + return new this.DateTime(y, M, d, h, m, s, ms);
135 + }
136 + catch (e) {
137 + this.errorMessages.customDateFormatError(`Unable to parse provided input: ${input}, format: ${this.localization.format}`);
138 + return new this.DateTime(''); // Invalid Date
139 + }
140 + };
141 + this.DateTime = dateTime;
142 + this.errorMessages = errorMessages;
143 + }
144 + getAllMonths(format = 'long') {
145 + const applyFormat = new Intl.DateTimeFormat(this.localization.locale, { month: format }).format;
146 + return [...Array(12).keys()].map((m) => applyFormat(new Date(2021, m)));
147 + }
148 + replaceExtendedTokens(format) {
149 + return format.replace(/(\[[^\]]+])|(MMMM|MM|dd|dddd)/g, (_, a, b) => a || b.slice(1));
150 + }
151 + replaceTokens(formatStr, formats) {
152 + return formatStr.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g, (_, a, b) => {
153 + const B = b && b.toUpperCase();
154 + return a || this.englishFormats[b] || this.replaceExtendedTokens(formats[B]);
155 + });
156 + }
157 + parseTwoDigitYear(input) {
158 + input = +input;
159 + return input + (input > 68 ? 1900 : 2000);
160 + }
161 + ;
162 + offsetFromString(string) {
163 + if (!string)
164 + return 0;
165 + if (string === 'Z')
166 + return 0;
167 + const parts = string.match(/([+-]|\d\d)/g);
168 + const minutes = +(parts[1] * 60) + (+parts[2] || 0);
169 + return minutes === 0 ? 0 : parts[0] === '+' ? -minutes : minutes; // eslint-disable-line no-nested-ternary
170 + }
171 + addInput(property) {
172 + return (time, input) => {
173 + time[property] = +input;
174 + };
175 + }
176 + ;
177 + meridiemMatch(input) {
178 + const meridiem = new Intl.DateTimeFormat(this.localization.locale, {
179 + hour: 'numeric',
180 + hour12: true,
181 + })
182 + .formatToParts(new Date(2022, 3, 4, 13))
183 + .find((p) => p.type === 'dayPeriod')?.value;
184 + return input.toLowerCase() === meridiem.toLowerCase();
185 + }
186 + ;
187 + correctHours(time) {
188 + const { afternoon } = time;
189 + if (afternoon !== undefined) {
190 + const { hours } = time;
191 + if (afternoon) {
192 + if (hours < 12) {
193 + time.hours += 12;
194 + }
195 + }
196 + else if (hours === 12) {
197 + time.hours = 0;
198 + }
199 + delete time.afternoon;
200 + }
201 + }
202 + makeParser(format) {
203 + format = this.replaceTokens(format, this.localization.dateFormats);
204 + const array = format.match(this.formattingTokens);
205 + const { length } = array;
206 + for (let i = 0; i < length; i += 1) {
207 + const token = array[i];
208 + const parseTo = this.expressions[token];
209 + const regex = parseTo && parseTo[0];
210 + const parser = parseTo && parseTo[1];
211 + if (parser) {
212 + array[i] = { regex, parser };
213 + }
214 + else {
215 + array[i] = token.replace(/^\[|]$/g, '');
216 + }
217 + }
218 + return (input) => {
219 + const time = {};
220 + for (let i = 0, start = 0; i < length; i += 1) {
221 + const token = array[i];
222 + if (typeof token === 'string') {
223 + start += token.length;
224 + }
225 + else {
226 + const { regex, parser } = token;
227 + const part = input.slice(start);
228 + const match = regex.exec(part);
229 + const value = match[0];
230 + parser.call(this, time, value);
231 + input = input.replace(value, '');
232 + }
233 + }
234 + this.correctHours(time);
235 + return time;
236 + };
237 + }
238 + format(dateTime) {
239 + if (!dateTime)
240 + return dateTime;
241 + if (JSON.stringify(dateTime) === 'null')
242 + return 'Invalid Date';
243 + const format = this.replaceTokens(this.localization.format || `${this.englishFormats.L}, ${this.englishFormats.LT}`, this.localization.dateFormats);
244 + const formatter = (template) => new Intl.DateTimeFormat(this.localization.locale, template).format(dateTime);
245 + const matches = {
246 + yy: formatter({ year: '2-digit' }),
247 + yyyy: dateTime.year,
248 + M: formatter({ month: 'numeric' }),
249 + MM: dateTime.monthFormatted,
250 + MMM: this.getAllMonths('short')[dateTime.getMonth()],
251 + MMMM: this.getAllMonths()[dateTime.getMonth()],
252 + d: dateTime.date,
253 + dd: dateTime.dateFormatted,
254 + ddd: formatter({ weekday: "short" }),
255 + dddd: formatter({ weekday: "long" }),
256 + H: dateTime.getHours(),
257 + HH: dateTime.hoursFormatted,
258 + h: dateTime.hours > 12 ? dateTime.hours - 12 : dateTime.hours,
259 + hh: dateTime.twelveHoursFormatted,
260 + t: dateTime.meridiem(),
261 + T: dateTime.meridiem().toUpperCase(),
262 + m: dateTime.minutes,
263 + mm: dateTime.minutesFormatted,
264 + s: dateTime.seconds,
265 + ss: dateTime.secondsFormatted,
266 + fff: dateTime.getMilliseconds(),
267 + //z: dateTime.getTimezoneOffset() todo zones are stupid
268 + };
269 + return format.replace(this.REGEX_FORMAT, (match, $1) => {
270 + return $1 || matches[match];
271 + });
272 + }
273 + }
274 + var index = (_, tdClasses, __) => {
275 + const customDateFormat = new CustomDateFormat(tdClasses.DateTime, tdClasses.ErrorMessages);
276 + // noinspection JSUnusedGlobalSymbols
277 + tdClasses.Dates.prototype.formatInput = function (date) {
278 + customDateFormat.localization = this.optionsStore.options.localization;
279 + return customDateFormat.format(date);
280 + };
281 + // noinspection JSUnusedGlobalSymbols
282 + tdClasses.Dates.prototype.parseInput = function (input) {
283 + customDateFormat.localization = this.optionsStore.options.localization;
284 + return customDateFormat.parseFormattedInput(input);
285 + };
286 + tdClasses.DateTime.fromString = function (input, localization) {
287 + customDateFormat.localization = localization;
288 + return customDateFormat.parseFormattedInput(input);
289 + };
290 + };return index;}));
new file 100644
@@ -154,19 +154,14
154 end
154 end
155
155
156 def manage
156 def manage
157 - @problems = Problem.order(date_added: :desc)
157 + @problems = Problem.order(date_added: :desc).includes(:tags)
158 end
158 end
159
159
160 def do_manage
160 def do_manage
161 - if params.has_key? 'change_date_added' and params[:date_added].strip.empty? == false
161 + change_date_added if params[:change_date_added] == '1' && params[:date_added].strip.empty? == false
162 - change_date_added
162 + add_to_contest if params.has_key? 'add_to_contest'
163 - elsif params.has_key? 'add_to_contest'
163 + set_available(params[:enable] == 'yes') if params[:change_enable] == '1'
164 - add_to_contest
164 + if params[:add_group] == '1'
165 - elsif params.has_key? 'enable_problem'
166 - set_available(true)
167 - elsif params.has_key? 'disable_problem'
168 - set_available(false)
169 - elsif params.has_key? 'add_group'
170 group = Group.find(params[:group_id])
165 group = Group.find(params[:group_id])
171 ok = []
166 ok = []
172 failed = []
167 failed = []
@@ -180,10 +175,10
180 end
175 end
181 flash[:success] = "The following problems are added to the group #{group.name}: " + ok.join(', ') if ok.count > 0
176 flash[:success] = "The following problems are added to the group #{group.name}: " + ok.join(', ') if ok.count > 0
182 flash[:alert] = "The following problems are already in the group #{group.name}: " + failed.join(', ') if failed.count > 0
177 flash[:alert] = "The following problems are already in the group #{group.name}: " + failed.join(', ') if failed.count > 0
183 - elsif params.has_key? 'add_tags'
178 + end
184 - get_problems_from_params.each do |p|
179 +
185 - p.tag_ids += params[:tag_ids]
180 + if params[:add_tags] == '1'
186 - end
181 + get_problems_from_params.each { |p| p.tag_ids += params[:tag_ids] }
187 end
182 end
188
183
189 redirect_to :action => 'manage'
184 redirect_to :action => 'manage'
@@ -45,8 +45,14
45
45
46 import "select2"
46 import "select2"
47 import "chart"
47 import "chart"
48 +
49 + //tempus dominus
48 import { TempusDominus } from "@eonasdan/tempus-dominus"
50 import { TempusDominus } from "@eonasdan/tempus-dominus"
51 + import * as TD from "@eonasdan/tempus-dominus-esm"
52 + import * as customDateFormat from '@eonasdan/tempus-dominus/customDateFormat'
53 + window.TD = TD
49 window.TempusDominus = TempusDominus
54 window.TempusDominus = TempusDominus
55 + window.customDateFormat = customDateFormat
50
56
51 //my own customization
57 //my own customization
52 import 'custom'
58 import 'custom'
@@ -36,7 +36,7
36 = f.label :add_group, 'Add selected problems to user group'
36 = f.label :add_group, 'Add selected problems to user group'
37 = f.check_box :add_group, class: 'form-check-input'
37 = f.check_box :add_group, class: 'form-check-input'
38 .col-md-auto
38 .col-md-auto
39 - = f.select "group_id", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), {}, class: 'select2 form-control'
39 + = f.select "group_id", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), {}, class: 'select2 form-control', data: {width: "400px"}
40 .col-md-6
40 .col-md-6
41 .row.mb-3.align-items-center
41 .row.mb-3.align-items-center
42 .col-md-auto
42 .col-md-auto
@@ -57,37 +57,6
57 .col-auto
57 .col-auto
58 = f.submit :go, class: 'btn btn-primary'
58 = f.submit :go, class: 'btn btn-primary'
59
59
60 -
61 - -#
62 - %ul.form-inline
63 - %li
64 - Change "Date added" to
65 - .input-group.date
66 - = text_field_tag :date_added, class: 'form-control'
67 - %span.input-group-addon
68 - %span.glyphicon.glyphicon-calendar
69 - -# = select_date Date.current, :prefix => 'date_added'
70 - &nbsp;&nbsp;&nbsp;
71 - = submit_tag 'Change', :name => 'change_date_added', class: 'btn btn-primary btn-sm'
72 - %li
73 - Set "Available" to
74 - = submit_tag 'True', :name => 'enable_problem', class: 'btn btn-primary btn-sm'
75 - = submit_tag 'False', :name => 'disable_problem', class: 'btn btn-primary btn-sm'
76 -
77 - - if GraderConfiguration.multicontests?
78 - %li
79 - Add selected problems to contest
80 - = select("contest","id",Contest.all.collect {|c| [c.title, c.id]})
81 - = submit_tag 'Add', :name => 'add_to_contest', class: 'btn btn-primary btn-sm'
82 - %li
83 - Add selected problems to user group
84 - = select_tag "group_id", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), id: 'group_name',class: 'select2'
85 - = submit_tag 'Add', name: 'add_group', class: 'btn btn-primary'
86 - %li
87 - Add the following tags to the selected problems
88 - = select_tag "tag_ids", options_from_collection_for_select( Tag.all, 'id','name'), id: 'tags_name',class: 'select2', multiple: true, data: {placeholder: 'Select tags by clicking', width: "200px"}
89 - = submit_tag 'Add', name: 'add_tags', class: 'btn btn-primary'
90 -
91 %table.table.table-hover.datatable
60 %table.table.table-hover.datatable
92 %thead
61 %thead
93 %tr{style: "text-align: left;"}
62 %tr{style: "text-align: left;"}
@@ -110,7 +79,7
110 %td= problem.full_name
79 %td= problem.full_name
111 %td
80 %td
112 - problem.tags.each do |t|
81 - problem.tags.each do |t|
113 - %span.label.label-default= t.name
82 + %span.badge.text-bg-secondary= t.name
114 %td= problem.available
83 %td= problem.available
115 %td= problem.date_added
84 %td= problem.date_added
116 - if GraderConfiguration.multicontests?
85 - if GraderConfiguration.multicontests?
@@ -149,33 +118,34
149 }
118 }
150 });
119 });
151
120
152 - $('.input-group.date').datetimepicker({
153 - format: 'DD/MMM/YYYY',
154 - showTodayButton: true,
155 - locale: 'en',
156 - widgetPositioning: {horizontal: 'auto', vertical: 'bottom'},
157 -
158 - });
159 -
160 $('.datatable').DataTable({
121 $('.datatable').DataTable({
161 paging: false
122 paging: false
162 });
123 });
163 $('.select2').select2();
124 $('.select2').select2();
164
125
165
126
166 - new TempusDominus(document.getElementById('date_added'), {
127 + td = new TempusDominus(document.getElementById('date_added'), {
167 display: {
128 display: {
168 icons: {
129 icons: {
169 time: 'mi mi-td-time',
130 time: 'mi mi-td-time',
170 date: 'mi mi-td-date',
131 date: 'mi mi-td-date',
171 up: 'mi mi-td-up',
132 up: 'mi mi-td-up',
172 down: 'mi mi-td-down',
133 down: 'mi mi-td-down',
173 - previous: 'bi bi-chevron-left',
134 + previous: 'mi mi-td-previous',
174 - next: 'bi bi-chevron-right',
135 + next: 'mi mi-td-next',
175 - today: 'bi bi-calendar-check',
136 + today: 'mi mi-td-today',
176 - clear: 'bi bi-trash',
137 + clear: 'mi mi-td-clear',
177 - close: 'bi bi-x',
138 + close: 'mi mi-td-close',
178 },
139 },
140 + components: {
141 + hours: false,
142 + minutes: false,
143 + seconds: false
144 + }
145 + },
146 + localization: {
147 + locale: 'en-uk',
148 + format: 'dd/MMM/yyyy',
179 }
149 }
180 });
150 });
181
151
@@ -56,4 +56,6
56
56
57 #pin "ace-rails-ap"
57 #pin "ace-rails-ap"
58 pin "chart", to: 'chart.js' # @3.9.1
58 pin "chart", to: 'chart.js' # @3.9.1
59 - pin "@eonasdan/tempus-dominus", to: "@eonasdan--tempus-dominus.js" # @6.2.4
59 + pin "@eonasdan/tempus-dominus", to: "tempus-dominus/@eonasdan--tempus-dominus.js" # @6.2.4
60 + pin "@eonasdan/tempus-dominus-esm", to: "tempus-dominus/tempus-dominus.esm.js" # @6.2.4
61 + pin "@eonasdan/tempus-dominus/customDateFormat", to: "tempus-dominus/customDateFormat.js" # @6.2.4
file renamed from vendor/javascript/@eonasdan--tempus-dominus.js to vendor/javascript/tempus-dominus/@eonasdan--tempus-dominus.js
You need to be logged in to leave comments. Login now