PageSourceSearch

https://assembliesofyahweh.com/wp-content/plugins/zephyr-project-manager/assets/js/zpm-global.js?ver=16.56.0

js assembliesofyahweh.com collected 2026-10-02 13:25:13 UTC 29,131 bytes, 893 lines download raw bytes

1jQuery(document).ready(function () {
2
3	var $body = jQuery('body');
4
5	$body.on('click', '[zpm-image-uploader-button], [zpm-image-uploader-preview]', function () {
6		const $container = jQuery(this).closest('[zpm-image-uploader]');
7		const $image = $container.find('[zpm-image-uploader-preview]');
8
9		ZephyrProjects.upload_file(null, function (res) {
10			$container.trigger('zpm/image/uploaded', res);
11			$image.attr('src', res.url).addClass('zpm-image-loaded');
12			$container.addClass('zpm-has-image');
13		});
14	});
15
16	jQuery('body').on('click', '[zpm-image-uploader-clear-button]', function () {
17		const $container = jQuery(this).closest('[zpm-image-uploader]');
18		const $image = $container.find('[zpm-image-uploader-preview]');
19		$container.trigger('zpm/image/uploaded', '');
20		$image.attr('src', '').removeClass('zpm-image-loaded');
21		$container.removeClass('zpm-has-image');
22	});
23
24	jQuery(document).on('click', function (e) {
25		const $target = jQuery(e.target);
26
27		if (!$target.hasClass('.zpm-dropdown') && $target.closest('.zpm-dropdown').length == 0 && typeof $target.attr('zpm-open-dropdown') == 'undefined') {
28			jQuery('body').find('.zpm-dropdown').removeClass('zpm-open');
29		}
30	});
31
32	jQuery('body').on('change', '#zpm-dynamic-task-filter-completed-tasks', function () {
33		const $container = jQuery('body');
34		
35		if (jQuery(this).is(':checked')) {
36			$container.attr('zpm-dynamic-task-filter-completed', 'true');
37		} else {
38			$container.attr('zpm-dynamic-task-filter-completed', '');
39		}
40	});
41
42	jQuery('body').on('click', '.zpm-pagination-btn', function (e) {
43		e.preventDefault();
44		const $btn = jQuery(this);
45		const $container = $btn.closest('.zpm-pagination-container');
46		const page = parseInt($btn.text());
47
48		if ($btn.hasClass('active')) return;
49
50		if (typeof $container.data('ajax') !== 'undefined') {
51			$container.data('ajax').abort();
52		}
53
54		$container.find('.zpm-pagination-btn').removeClass('active');
55		$btn.addClass('active');
56		$container.trigger('zpm/page_changed', {
57			page
58		});
59	});
60
61	jQuery('body').on('click', '[data-print-project-pdf-button]', function() {
62		const id = jQuery(this).data('print-project-pdf-button');
63		const $btn = jQuery(this);
64		$btn.text($btn.data('loading-text'));
65		const $loader = ZephyrProjects.loaderNotification(zpm_localized.strings.downloading);
66
67		ZephyrProjects.ajax({
68			action: 'zpm_getProjectOverview',
69			id
70		}, function(res) {
71			$loader.remove();
72			jQuery('body').append(res.data.html);
73			const $el = jQuery('body').find('[data-project-overview="' + id + '"]');
74			const name = $el.find('[data-project-overview-name]').text();
75			$btn.text($btn.data('text'));
76			// $el.hide();
77
78			ZephyrProjects.createPDF($el[0], name, function(res) {
79				console.log('zpm/pdf/done', res);
80				$el.remove();
81			});
82		});
83	});
84
85	jQuery('body').on('zpm/page_changed', '[data-subtask-pagination]', function (e, data) {
86		const $pagination = jQuery(this);
87		const parentID = $pagination.data('parent-id');
88		const containerElementID = $pagination.data('container-id');
89		const $container = jQuery('body').find('#' + containerElementID);
90		const perPage = $pagination.data('per-page');
91		const $notification = ZephyrProjects.loaderNotification(zpm_localized.strings.loading);
92		const ajax = ZephyrProjects.ajax({
93			action: 'zpm_getSubtasks',
94			task_id: parentID,
95			page: data.page,
96			perPage: perPage
97		}, function (res) {
98			$notification.remove();
99			$pagination.html(res.data.buttonsHtml);
100			console.log('zpm/paginationTest', res.data);
101			$container.html(res.data.html);
102		});
103		$pagination.data('ajax', ajax);
104	});
105
106	jQuery('body').on('zpm/page_changed', '[data-project-tasks-pagination]', function (e, data) {
107		const $pagination = jQuery(this);
108		const projectID = $pagination.data('project-id');
109		const containerElementID = $pagination.data('container-id');
110		const $container = jQuery('body').find('#' + containerElementID);
111		const perPage = $pagination.data('per-page');
112		const $notification = ZephyrProjects.loaderNotification(zpm_localized.strings.loading);
113		const ajax = ZephyrProjects.ajax({
114			action: 'zpm_getProjectTasks',
115			projectID,
116			page: data.page,
117			perPage: perPage
118		}, function (res) {
119			$notification.remove();
120			$pagination.html(res.data.buttonsHtml);
121			console.log('zpm/paginationTest', res.data);
122			$container.html(res.data.html);
123		});
124		$pagination.data('ajax', ajax);
125	});
126
127	jQuery('body').on('click', '[data-zpm-project-template]', function() {
128		const id = jQuery(this).data('zpm-project-template');
129		const $item = jQuery(this);
130		jQuery('body').find('[data-zpm-project-template]').removeClass('active');
131		$item.addClass('active');
132		console.log('id', id);
133		jQuery('body').find('#zpm_modal_add_project').text(zpm_localized.strings.creating);
134		ZephyrProjects.ajax({
135			action: 'zpm_createProjectFromTemplate',
136			id
137		}, function(res) {
138			console.log('zpm/res', res);
139			jQuery.event.trigger({ type: 'zephyr_project_created', ndata: res.data });
140			jQuery('body').find('#zpm_project_manager_display').removeClass('zpm_hide');
141			jQuery('body').find('.zpm_no_results_message').hide();
142			jQuery('body').find('#zpm_template_list .zpm_project_grid').prepend(res.data.html);
143			ZephyrProjects.close_modal();
144
145			if (typeof res.data.url !== 'undefined' && res.data.url !== '') {
146				window.location.href = res.data.url;
147			}
148		});
149	});
150
151	if (ZephyrProjects.isProjectsPage()) {
152		// $ = jQuery;
153		var selector = 'zpm-task-list__project';
154
155		if (!ZephyrProjects.isAdmin()) {
156			selector = 'zpm-project-task-list';
157		}
158
159		var drake = dragula({
160			copySortSource: true
161		});
162
163		var container = document.getElementById(selector);
164		drake.containers.push(container);
165		var projectId = jQuery('#zpm-project-id').val();
166
167		drake.on('dragend', function (one, two, three) {
168			var taskIdsOrder = [];
169			var parentList = jQuery('#' + selector);
170
171			parentList.find('.zpm_task_list_row').each(function () {
172				var taskId = jQuery(this).data('task-id');
173				taskIdsOrder.push(taskId);
174			});
175
176			ZephyrProjects.ajax({
177				action: 'zpm_updateProjectSetting',
178				project_id: projectId,
179				key: 'task_order',
180				value: taskIdsOrder
181			}, function (res) {
182
183			});
184		});
185	}
186
187	ZephyrProjects.initReorderables();
188
189	
190	jQuery('body').on('zpm/reordered', '.zpm-priority-list', function(e, orders) {
191		ZephyrProjects.ajax({
192			action: 'zpm_updatePriorityOrders',
193			orders
194		}, function(res) {
195
196		});
197	});
198
199	jQuery('body').on('zpm/reordered', '.zpm-status-list', function(e, orders) {
200		ZephyrProjects.ajax({
201			action: 'zpm_updateStatusOrders',
202			orders
203		}, function(res) {
204
205		});
206	});
207
208	// Export all tasks
209	jQuery('body').on('click', '.zpm-export-tasks__btn, [data-export-tasks-csv]', function () {
210		ZephyrProjects.modal('task-export-modal', ZephyrProjects.getTemplate('taskExportModal'), true);
211	});
212
213	jQuery('body').on('click', '[data-archive-task]', function () {
214		const id = jQuery(this).data('task-id');
215		const archived = jQuery(this).attr('data-archived');
216		let isArchived = false;
217
218		if (archived == 'true' && archived !== false) {
219			isArchived = true;
220		}
221
222		if (isArchived) {
223			jQuery(this).attr('data-archived', 'false');
224			jQuery(this).text(zpm_localized.strings.archive);
225		} else {
226			jQuery(this).attr('data-archived', 'true');
227			jQuery(this).text(zpm_localized.strings.unarchive);
228		}
229
230		ZephyrProjects.archiveTask(id, !isArchived, function () {
231		});
232	});
233
234	jQuery('body').on('click', '.zpm-remove-parent', function () {
235		jQuery(this).parent().remove();
236	});
237
238	jQuery('body').on('change', '[data-task-duration]', function () {
239		const taskID = jQuery(this).data('task-duration');
240		const duration = jQuery(this).val();
241
242		if (typeof taskID !== 'undefined') {
243			ZephyrProjects.updateTaskMeta(taskID, 'duration', duration);
244		}
245	});
246
247// Remove project from dashboard
248	jQuery('body').on('click', '#zpm-remove-from-dashboard', function (e) {
249		e.stopPropagation();
250		e.preventDefault();
251		var parent = jQuery(this).closest('.zpm_project_item');
252		var projectId = parent.data('project-id');
253		parent.closest('.zpm_project_grid_cell').remove();
254		ZephyrProjects.ajax({
255			action: 'zpm_removeProjectFromDashboard',
256			id: projectId
257		}, function () { });
258	});
259
260	let zpmIsBulkEditing = false;
261
262	jQuery('body').on('click', '[data-toggle-task-bulk-selection]', function () {
263		zpmIsBulkEditing = !zpmIsBulkEditing;
264
265		if (!zpmIsBulkEditing) {
266			jQuery('body').find('[data-task-bulk-selector]').removeAttr('checked');
267			jQuery(this).text(zpm_localized.strings.select_multiple);
268		} else {
269			jQuery(this).text(zpm_localized.strings.deselect_all);
270		}
271
272		jQuery('body').toggleClass('zpm-task-list--bulk-edit');
273	});
274
275	jQuery('body').on('click', '[data-bulk-delete-button]', function () {
276		const selectedTasks = zpmGetSelectedTasks();
277
278		if (selectedTasks.length === 0) {
279			ZephyrProjects.notification(zpm_localized.strings.nothing_selected);
280		} else {
281			// Perform here.
282			if (confirm('Are you sure that you would like to permanently delete the ' + selectedTasks.length + ' selected tasks?')) {
283				ZephyrProjects.ajax({
284					action: 'zpm_bulkDeleteTasks',
285					tasks: selectedTasks
286				}, function (res) {
287
288				});
289				jQuery.each(selectedTasks, function (key, id) {
290					jQuery('body').find('.zpm_task_list_row[data-task-id="' + id + '"]').remove();
291				});
292				jQuery('body').find('[data-toggle-task-bulk-selection]').click();
293			}
294		}
295	});
296
297	jQuery('body').on('click', '[data-bulk-archive-button]', function () {
298		const selectedTasks = zpmGetSelectedTasks();
299
300		if (selectedTasks.length === 0) {
301			ZephyrProjects.notification(zpm_localized.strings.nothing_selected);
302		} else {
303			// Perform here.
304			if (confirm('Are you sure that you would like to archive the ' + selectedTasks.length + ' selected tasks?')) {
305				ZephyrProjects.ajax({
306					action: 'zpm_bulkArchiveTasks',
307					tasks: selectedTasks
308				}, function (res) {
309
310				});
311				jQuery.each(selectedTasks, function (key, id) {
312					jQuery('body').find('.zpm_task_list_row[data-task-id="' + id + '"]').remove();
313				});
314				jQuery('body').find('[data-toggle-task-bulk-selection]').click();
315			}
316		}
317	});
318
319	jQuery('body').on('click', '[data-bulk-task-edit-select-all]', function() {
320		jQuery('body').find('.zpm-task-bulk-selector').attr('checked', 'checked').prop('checked', 'checked').val(true).trigger('change');
321	});
322
323	jQuery('body').on('click', '[data-bulk-edit-button]', function () {
324		const selectedTasks = zpmGetSelectedTasks();
325
326		if (selectedTasks.length == 0) {
327			ZephyrProjects.notification(zpm_localized.strings.nothing_selected);
328		} else {
329			// Perform here.
330			ZephyrProjects.open_modal('zpm-edit-multiple-tasks-modal');
331		}
332	});
333
334	jQuery('body').on('click', '[data-create-task-list]', function () {
335		const items = [];
336
337		jQuery('body').find('[data-task-list]').find('[data-task-list-item]').each(function () {
338			items.push(jQuery(this).val());
339		});
340
341		ZephyrProjects.close_modal('#zpm-new-task-list-modal');
342
343		const $list = jQuery('body').find('#zpm-new-task-list-modal [data-task-list]');
344		$list.html('');
345		const itemHtml = jQuery('body').find('[data-zpm-template="taskListItem"]').html();
346		$list.append(itemHtml);
347
348		const $assignees = jQuery('body').find('#zpm-task-list-assignees');
349		const $project = jQuery('body').find('#zpm-task-list-project');
350		const $parentID = jQuery('body').find('#zpm-task-list-parent-id');
351		const $loader = ZephyrProjects.loaderNotification(zpm_localized.strings.creating);
352		const $subtaskList = jQuery('body').find('#zpm-subtask-list');
353
354		ZephyrProjects.ajax({
355			action: 'zpm_createTaskList',
356			list: items,
357			assignees: $assignees.val(),
358			project: $project.val(),
359			parentID: $parentID.val()
360		}, function (res) {
361			if ($parentID.val() === '-1') {
362				jQuery('body').find('#zpm-task-list__task, #zpm-task-list__project').prepend(res.data.html);
363			} else {
364				$subtaskList.prepend(res.data.html);
365				jQuery('body').find('#zpm-no-subtasks').hide();
366			}
367
368			$assignees.val('').trigger('chosen:updated');
369			$project.val('-1').trigger('chosen:updated');
370			$parentID.val('-1');
371			$loader.remove();
372		});
373	});
374
375	jQuery('body').on('click', '[data-update-multiple-tasks-button]', function () {
376		const selectedTasks = zpmGetSelectedTasks();
377		const values = {};
378		const $modal = jQuery(this).closest('.zpm-modal');
379		const $selectedFields = $modal.find('[data-edit-multiple-task-container].active');
380
381		$selectedFields.each(function () {
382			const $field = jQuery(this).find('[data-edit-multiple-task-input]');
383			const key = $field.data('edit-multiple-task-input');
384			values[key] = $field.val();
385		});
386
387		// ZephyrProjects.close_modal('#zpm-edit-multiple-tasks-modal');
388		jQuery(this).text(zpm_localized.strings.saving_changes);
389		console.log(values);
390
391		ZephyrProjects.ajax({
392			action: 'zpm_bulkUpdateTasks',
393			tasks: selectedTasks,
394			values: values
395		}, function (res) {
396			window.location.reload();
397		});
398	});
399
400	jQuery('body').on('keydown', '[data-task-list-item]', function (e) {
401		const $taskList = jQuery('body').find('[data-task-list]');
402		const $lastItem = $taskList.find('[data-task-list-item]').last();
403		const isLast = jQuery(this).is($lastItem);
404		const $container = jQuery(this).closest('.zpm-form__group');
405
406		// Add New Item
407		if ((e.keyCode == 10 || e.keyCode == 13) && !e.ctrlKey) {
408			const itemHtml = jQuery('body').find('[data-zpm-template="taskListItem"]').html();
409			$container.after(itemHtml);
410			const $newElement = $container.next().find('[data-task-list-item]');
411
412			setTimeout(function () {
413				$newElement.focus();
414			}, 100);
415		}
416
417		// Delete Item
418		if (e.which == 46) {
419			jQuery(this).closest('.zpm-form__group').remove();
420
421			setTimeout(function () {
422				$taskList.find('[data-task-list-item]').last().focus();
423			}, 100);
424		}
425	});
426
427	jQuery('body').on('click', '[data-add-task-list-button]', function (e) {
428		const project = jQuery(this).data('project');
429		const parentID = jQuery(this).data('parent-id');
430		ZephyrProjects.open_modal('zpm-new-task-list-modal');
431		const $taskList = jQuery('body').find('[data-task-list]');
432		$taskList.find('[data-task-list-item]').first().focus();
433
434		if (typeof project !== 'undefined') {
435			jQuery('body').find('#zpm-task-list-project').val(project).trigger('chosen:updated');
436		}
437
438		if (typeof parentID !== 'undefined') {
439			jQuery('body').find('#zpm-task-list-parent-id').val(parentID);
440		}
441	});
442
443	jQuery('body').on('click', '[data-edit-multiple-task-toggle]', function () {
444		const $container = jQuery(this).closest('[data-edit-multiple-task-container]');
445		$container.toggleClass('active');
446	});
447
448	jQuery('body').on('click', '[data-import-ical-button]', function () {
449		ZephyrProjects.upload_file(null, function (res) {
450			ZephyrProjects.ajax({
451				action: 'zpm_importIcal',
452				url: res.url
453			}, function (res) {
454				console.log('imported', res.data.tasks);
455				ZephyrProjects.notification('Successfully imported ' + res.data.tasks.length + ' tasks.');
456				window.location.reload();
457			});
458		});
459	});
460
461	jQuery('#zpm-task-preview__info').on('change', 'input, select, textarea', function () {
462		ZephyrProjects.saveTaskPanel();
463		ZephyrProjects.notification('Changes Saved');
464	});
465
466	jQuery('#zpm-project-preview__info').on('change', 'input, select, textarea', function () {
467		if (!jQuery(this).hasClass('zpm-panel__no-update')) {
468			ZephyrProjects.saveProjectPanel();
469			ZephyrProjects.notification('Changes Saved');
470		}
471	});
472
473	jQuery('body').on('click', function (e) {
474		var target = jQuery(e.target);
475		if (target.closest('#zpm-project-preview__bar').length <= 0 && target.closest('.zpm_project_item').length <= 0) {
476			ZephyrProjects.closeProjectPanel();
477		}
478
479		if (target.closest('#zpm-task-preview__bar').length <= 0 && target.closest('.zpm_task_list_row').length <= 0) {
480			ZephyrProjects.closeTaskPanel();
481		}
482	});
483
484	ZephyrProjects.initSubtaskDraggables();
485
486	jQuery('body').on('input', '#zpm-edit-task--duration', function () {
487		let duration = jQuery(this).val();
488		const start = jQuery('body').find('#zpm_edit_task_start_date').val();
489
490		if (start !== '') {
491			if (duration == 0) duration = 1;
492			const newDate = moment(start).add(duration - 1, 'days').format(ZephyrProjects.getMomentFormat());
493			console.log('zpm/duration/new_due_date', newDate);
494			jQuery('body').find('#zpm_edit_task_due_date').val(newDate).trigger('change');
495		}
496
497		console.log('zpm/duration/changed', duration, start);
498	});
499
500	jQuery('body').on('change', '#zpm_edit_task_due_date', function () {
501		const $due = jQuery(this);
502		const $start = jQuery('body').find('#zpm_edit_task_start_date');
503		let due = jQuery(this).val();
504		let start = $start.val();
505		const $duration = jQuery('body').find('#zpm-edit-task--duration');
506
507		if (due !== '') {
508			start = moment(start);
509			due = moment(due);
510			let duration = due.diff(start, 'days');
511			duration += 1;
512
513			if (duration <= 0) {
514				if ($duration.val() !== '') {
515					duration = $duration.val();
516
517					if (isNaN(duration)) duration = 0;
518
519					$start.val(due.subtract(duration, 'days').format(ZephyrProjects.getMomentFormat()));
520				}
521			}
522
523			if (isNaN(duration)) duration = 0;
524
525			$duration.val(duration);
526			// $start.val(due.add(duration, 'days').format(ZephyrProjects.getMomentFormat()));
527			console.log('zpm/due_date/changed', duration, start);
528		}
529	});
530
531	jQuery('body').on('change', '#zpm_edit_task_start_date', function () {
532		const $start = jQuery(this);
533		const $due = jQuery('body').find('#zpm_edit_task_due_date');
534		let due = $due.val();
535		let start = jQuery(this).val();
536		const $duration = jQuery('body').find('#zpm-edit-task--duration');
537
538		if (start !== '') {
539			start = moment(start);
540			due = moment(due);
541			let duration = due.diff(start, 'days');
542			duration += 1;
543
544			if (duration <= 0) {
545				if ($duration.val() !== '') {
546					duration = $duration.val();
547
548					if (isNaN(duration)) duration = 0;
549
550					$due.val(start.add(duration, 'days').format(ZephyrProjects.getMomentFormat()));
551				}
552			}
553
554			if (isNaN(duration)) duration = 0;
555
556			$duration.val(duration);
557
558			console.log('zpm/due_date/changed', duration, start);
559		}
560	});
561
562	jQuery('body').on('change', '#zpm_edit_task_due_date', function () {
563		const today = moment();
564		const val = jQuery(this).val();
565		const $estimated = jQuery('body').find('[data-task-estimated-end]');
566
567		if (val === '' || $estimated.length === 0) return;
568
569		const date = moment(val);
570
571		if (date.isBefore(today)) {
572			$estimated.addClass('zpm-overdue-text');
573		} else {
574			$estimated.removeClass('zpm-overdue-text');
575		}
576
577		$estimated.text(date.format('D MMM YYYY'));
578	});
579
580	jQuery('body').on('input', '#zpm-new-task-duration', function () {
581		let duration = jQuery(this).val();
582		const start = jQuery('body').find('#zpm_new_task_start_date').val();
583
584		if (start !== '') {
585			if (duration == 0) duration = 1;
586			const newDate = moment(start).add(duration - 1, 'days').format(ZephyrProjects.getMomentFormat());
587			console.log('zpm/duration/new_due_date', newDate);
588			jQuery('body').find('#zpm_new_task_due_date').val(newDate).trigger('change');
589		}
590
591		console.log('zpm/duration/changed', duration, start);
592	});
593
594	jQuery('body').on('change', '#zpm_new_task_due_date', function () {
595		let due = jQuery(this).val();
596		let start = jQuery('body').find('#zpm_new_task_start_date').val();
597
598		if (due !== '') {
599			start = moment(start);
600			due = moment(due);
601			let duration = due.diff(start, 'days');
602			duration += 1;
603
604			if (duration < 0) return;
605
606			if (isNaN(duration)) duration = 0;
607
608			jQuery('body').find('#zpm-new-task-duration').val(duration).trigger('change');
609			console.log('zpm/due_date/changed', duration, start);
610		}
611	});
612
613	jQuery('body').on('change', '#zpm_new_task_start_date', function () {
614		let due = jQuery('body').find('#zpm_edit_task_due_date').val();
615		let start = jQuery(this).val();
616
617		if (due !== '') {
618			start = moment(start);
619			due = moment(due);
620			let duration = due.diff(start, 'days');
621			duration += 1;
622
623			if (duration < 0) return;
624
625			if (isNaN(duration)) duration = 0;
626
627			jQuery('body').find('#zpm-new-task-duration').val(duration).trigger('change');
628			console.log('zpm/due_date/changed', duration, start);
629		}
630	});
631
632	jQuery('body').on('change', '[data-ajax-name="blockingTasks"]', function () {
633		const $select = jQuery(this);
634		const dates = [];
635		const selectVal = $select.val();
636
637		$select.find('[data-due]').each(function () {
638			const val = jQuery(this).val();
639			const due = jQuery(this).data('due');
640			const isSelected = jQuery.inArray(val, selectVal) !== -1;
641
642			if (isSelected && due !== '') {
643				dates.push(moment(due));
644			}
645		});
646
647		const latest = moment.max(dates);
648
649		if (dates.length !== 0 && typeof latest !== 'undefined' && latest !== null) {
650			console.log('zpm/blocking/changed', {
651				latest, dates
652			});
653			const $startDate = jQuery('body').find('#zpm_edit_task_start_date');
654			let startDate = $startDate.val();
655
656			if (startDate !== '') {
657				startDate = moment(startDate);
658
659				if (latest.isBefore(startDate)) {
660					console.log('zpm/blocking', 'Start date is already later than the latest blocking task');
661					return;
662				}
663			}
664
665			$startDate.val(latest.add(1, 'days').format(ZephyrProjects.getMomentFormat()));
666			jQuery('body').find('#zpm-edit-task--duration').trigger('input').trigger('keydown');
667		}
668	});
669
670	jQuery('body').on('change', '#zpm-edit-task__status', function () {
671		const $status = jQuery(this);
672		const original = $status.attr('data-original');
673		const $start = jQuery('body').find('#zpm_edit_task_start_date');
674		const originalStart = $start.data('original');
675		const today = moment().format(ZephyrProjects.getMomentFormat());
676
677		if (typeof original == 'undefined') return;
678		if (typeof originalStart == 'undefined') return;
679
680		console.log('zpm/status', original, originalStart, today);
681
682		if (original == 'not_started' && today !== originalStart) {
683			if (confirm(zpm_localized.strings.automatically_update_dates)) {
684				$start.val(today).trigger('change');
685				$status.attr('data-original', $status.val()).prop('data-original', $status.val());
686			}
687		}
688	});
689
690	const $autoResizeTextareas = jQuery('body').find('textarea.zpm-auto-resize');
691
692	$autoResizeTextareas.each(function () {
693		const textarea = jQuery(this)[0];
694		textarea.style.height = 'auto';
695		textarea.style.height = textarea.scrollHeight + 'px';
696	});
697
698	jQuery('body').on('click', '[data-submit-task-export-button]', function () {
699		const $options = jQuery('body').find('[data-task-export-options]');
700		const data = {};
701		data.headers = [];
702		data.from = $options.find('[data-from]').val();
703		data.to = $options.find('[data-to]').val();
704		data.status = $options.find('[data-status]').val();
705		data.exportNames = $options.find('[data-export-names]').is(':checked');
706
707		console.log(data);
708
709		$options.find('[data-header]').each(function () {
710			if (jQuery(this).is(':checked')) {
711				data.headers.push(jQuery(this).data('header'));
712			}
713		});
714
715		const $btn = jQuery(this);
716		$btn.text(zpm_localized.strings.loading);
717
718		ZephyrProjects.ajax({
719			action: 'zpm_exportTasksToCSV',
720			options: data
721		}, function (response) {
722			ZephyrProjects.remove_modal('task-export-modal');
723			ZephyrProjects.close_modal();
724			var link = document.createElement('a');
725			document.body.appendChild(link);
726			link.download = 'ZPM Tasks.csv';
727			link.href = response;
728			link.click();
729		});
730	});
731
732	jQuery('body').on('input', 'textarea.zpm-auto-resize', function () {
733		const textarea = jQuery(this)[0];
734		textarea.style.height = 'auto';
735		textarea.style.height = textarea.scrollHeight + 'px';
736	});
737
738	jQuery('body').on('click', '#zpm-project-tab--discussion', function() {
739		jQuery('body').find('.zpm-unread-badge').remove();
740	})
741
742	jQuery('body').on('change', '#zpm-edit-project__status', function () {
743		const $status = jQuery(this);
744		const original = $status.attr('data-original');
745		const $start = jQuery('body').find('#zpm_edit_project_start_date');
746		const originalStart = $start.data('original');
747		const today = moment().format(ZephyrProjects.getMomentFormat());
748
749		if (typeof original == 'undefined') return;
750		if (typeof originalStart == 'undefined') return;
751
752		console.log('zpm/status', original, originalStart, today);
753
754		if (original == 'not_started' && today !== originalStart) {
755			if (confirm(zpm_localized.strings.automatically_update_dates)) {
756				$start.val(today).trigger('change');
757				$status.attr('data-original', $status.val()).prop('data-original', $status.val());
758			}
759		}
760	});
761
762	jQuery('body').on('input', '.zpm-milestone__task-name', function () {
763		const taskID = jQuery(this).closest('[data-task-id]').data('task-id');
764		const name = jQuery(this).html();
765		ZephyrProjects.updateTaskField(taskID, 'name', name);
766	});
767
768	jQuery('body').on('click', '#zpm-project-invite-user', function() {
769		const id = jQuery(this).data('project-id');
770
771		ZephyrProjects.promptInput({
772			title: zpm_localized.strings.invite_user,
773			content: zpm_localized.strings.invite_user_prompt,
774			confirmText: zpm_localized.strings.invite_user,
775			callback: function(email) {
776				ZephyrProjects.ajax({
777					action: 'zpm_inviteUser',
778					project_id: id,
779					email: email
780				}, function(res) {
781					console.log(res)
782				});
783			}
784		})
785	});
786
787	/* Text Editor */
788	jQuery('.zpm_editor_toolbar a').click(function (e) {
789		e.preventDefault();
790		e.stopPropagation();
791
792		var command = $(this).data('command');
793
794		if (command == 'h1' || command == 'h2' || command == 'p') {
795			document.execCommand('formatBlock', false, command);
796		}
797
798		if (command == 'forecolor' || command == 'backcolor') {
799			document.execCommand(jQuery(this).data('command'), false, $(this).data('value'));
800		}
801
802		if (command == 'createlink' || command == 'insertimage') {
803			url = prompt('Enter the link here: ', 'http:\/\/');
804			document.execCommand(jQuery(this).data('command'), false, url);
805		}
806
807		if (command == 'addCode') {
808			document.execCommand("insertHTML", false, "<code class='cca_code_snippet' style='display: block;'>" + document.getSelection() + "</code>");
809		} else {
810			document.execCommand(jQuery(this).data('command'), false, null);
811		}
812	});
813
814	jQuery('body').on('change', '[data-zpm-project-sorting]', function () {
815		// const sortingMethod = jQuery(this).val();
816		const page = jQuery('body').find('.zpm-pagination__current-page').data('page');
817		ZephyrProjects.paginateProjects(page, zpm_localized.settings.projects_per_page, zpm_localized.is_admin == '');
818
819		// ZephyrProjects.ajax({
820		// 	action: 'zpm_sortProjects',
821		// 	sortingMethod: sortingMethod,
822		// 	page: page
823		// }, function() {
824
825		// });
826	});
827
828	jQuery('body').on('zpm/image/uploaded', '#zpm-edit-project-image-uploader', function (e, data) {
829		console.log('project image uploaded');
830		const projectID = jQuery(this).closest('[data-project-id]').data('project-id');
831
832		ZephyrProjects.ajax({
833			action: 'zpm_updateProjectMeta',
834			id: projectID,
835			key: 'image',
836			value: data.url
837		}, function (res) {
838
839		});
840	});
841
842	jQuery('body').find('[data-zpm-tooltip]').each(function () {
843		jQuery(this).append('<div class="zpm-tooltip">' + jQuery(this).data('zpm-tooltip') + '</div>');
844		jQuery(this).addClass('zpm-tooltip-container');
845	});
846
847	jQuery(document).on('keydown', function (event) {
848		const $activeModal = jQuery('body').find('.zpm-modal.active');
849		const $saveTaskBtn = jQuery('body').find('#zpm_save_changes_task');
850		const hasActiveModal = $activeModal.length > 0;
851		const isTaskPage = $saveTaskBtn.length > 0;
852
853		// ESCAPE shortcut
854		if (event.key == "Escape") {
855			if (hasActiveModal) {
856				ZephyrProjects.close_modal();
857			} else {
858				if (isTaskPage) {
859					window.history.back();
860				}
861			}
862			// if (ZephyrProjects.isModalOpen('zpm_create_task')) {
863			// 	ZephyrProjects.close_modal('#zpm_create_task');
864			// }
865
866			// if (ZephyrProjects.isModalOpen('zpm_project_modal')) {
867			// 	ZephyrProjects.close_modal('#zpm_project_modal');
868			// }
869		}
870
871		// CTRL + ENTER Shortcut
872		if ((event.keyCode == 10 || event.keyCode == 13) && event.ctrlKey) {
873			if (hasActiveModal) {
874				$activeModal.find('button[type="submit"]').last().click();
875			} else {
876				if (isTaskPage) {
877					$saveTaskBtn.click();
878				}
879			}
880		}
881	});
882});
883
884function zpmGetSelectedTasks() {
885	const selectedTasks = jQuery('body').find('[data-task-bulk-selector]:checked');
886	const selectedIDs = [];
887
888	selectedTasks.each(function () {
889		selectedIDs.push(jQuery(this).data('task-bulk-selector'));
890	});
891
892	return selectedIDs;
893}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.