PageSourceSearch

https://matrix.f3df.com/javascripts/core.js?1790783316

js f3df.com collected 2026-09-30 22:18:15 UTC 444,235 bytes, 14,359 lines download raw bytes

1// general
2var controller;
3var id;
4var class_id;
5
6// lessons
7var current_lesson_id;
8var unhide_text;
9var hide_text;
10var confirm_text;
11
12// assignments
13var assignment_id;
14
15// quiz configure
16var configure_controller;
17var configure_id;
18
19// questions configure
20var questions_controller;
21var questions_id;
22
23// user popups
24var disable_user_popups_flag = false;
25var user_timer = null;
26var user_href = null;
27
28// toggle
29var last_toggled_id = null;
30
31// navigation
32var hover_timer = null;
33var hover_timer_triggered = false;
34var hover_tab_id;
35var hover_class_id;
36var hover_student_class_id;
37
38// click to chat
39var chat_alert_displayed = false;
40var loaded_sound_manager = false;
41
42// new mobile
43var menuStatus;
44var shiftContent;
45var contentHeight;
46var menuContentHeight;
47
48// close facebox after x sec if wanted
49var FACEBOX_CLOSING_TIME = 2500;
50
51// for tinymce and popup messages with ajax
52var tinyPop = true;
53var closeAlertTimer;
54
55//mobile app notifications counter
56var mobile_messages_count = 0;
57var mobile_notifications_count = 0;
58
59// widget panel original
60var context_uri = false;
61
62// edit tool id
63var tool_to_edit_id = null;
64
65// transfer variables
66var select_all_learners = null;
67var select_learners = null;
68
69// keep base controller
70var base_controller = null;
71
72// stacked picker
73var stacked_picker = null;
74
75// copilot picker
76var copilot_picker = null;
77var copilot_callback = null;
78
79// session timeout
80var pause_session_timeout = false;
81
82// new mobile initialization
83
84function initScrollers() {
85	menuScroller = new iScroll('menu-content', {vScrollbar: false});
86	contentScroller = new iScroll('phone-body', {vScrollbar: false});
87}
88
89function init_container_height(){
90	setTimeout(function(){
91		var container = $('.user #contentWrap');
92		var sub_head = $('#contentHeader').length ? $('#contentHeader').outerHeight() : 0;
93		var header = $('header').length ? $('header').outerHeight() : 0;
94		var footer = $('footer').length ? $('footer').outerHeight() : 0;
95		if (navigator.appVersion.indexOf('Trident') > 0) {
96			// Will exclude Edge and target IE11
97			container = $('#contentWrap');
98			header = $('.catalog_class').length > 0 && $('.transparent_header').length == 0 ? $('header').outerHeight() : 0;
99		}
100		container.css('min-height', 'calc(100vh - ' + (sub_head + header + footer) + 'px)');
101	}, 100);
102}
103
104function removeScrollers() {
105	menuScroller.destroy();
106	contentScroller.destroy();
107	menuScroller = null;
108	contentScroller = null;
109}
110
111function refreshScrollers() {
112	menuScroller.refresh();
113	contentScroller.refresh();
114}
115
116$(function() {
117	var original_init = $.prototype.init;
118	$.prototype.init = function (e, t) {
119		try {
120			$.extend(this, new original_init(e == '#' ? [] : e, t));
121		} catch(error) {
122		}
123	};
124	$.prototype.init.prototype = original_init.prototype;
125	//init_container_height();
126});
127
128function updateHeight() {
129	shiftContent = (is_mobile_app_mode() ? globalWindowWidth : $(window).width()) - 70;
130	contentHeight = (is_mobile_app_mode() ? globalWindowHeight : $(window).height()) - $('#phone-header').height() - $('#phone-footer').height() + 3;
131	menuContentHeight = (is_mobile_app_mode() ? globalWindowHeight : $(window).height()) - $('#menu-content').offset().top;
132
133	$("#menu").width(shiftContent);
134	$("#mnu-header .nav_search").width(shiftContent - 80);
135
136	$('#phone-body').css('height', contentHeight + 'px');
137	$('#menu').css('height', (is_mobile_app_mode() ? globalWindowHeight : $(window).height()) + 'px');
138	$('#menu-content').css('height', menuContentHeight + 'px');
139
140	refreshScrollers();
141}
142
143function init_mobile() {
144	if(!is_mobile_app_mode()){
145		$(window).resize(updateHeight);
146	}
147
148	setTimeout(function() {
149		updateHeight();
150	}, 500);
151
152	$("#menu").css('display', 'none');
153
154	$("#btn-menu").click(function() {
155		if (menuStatus != true) {
156			$("#menu").css('display', 'block');
157
158			$("#wrapper").animate({
159				left : shiftContent + "px"
160			}, 300, function() {
161				menuStatus = true;
162				refreshScrollers();
163			});
164
165			$("#wrapper #phone-header").animate({
166				left : shiftContent + "px"
167			}, 300);
168			$("#wrapper #phone-footer").animate({
169				left : shiftContent + "px"
170			}, 300);
171
172			return false;
173		} else {
174			$("#wrapper").animate({
175				left : "0"
176			}, 300, function() {
177				menuStatus = false;
178			});
179
180			$("#wrapper #phone-header").animate({
181				left : "0"
182			}, 300);
183
184			$("#wrapper #phone-footer").animate({
185				left : "0"
186			}, 300, function() {
187				$("#menu").css('display', 'none');
188			});
189
190			return false;
191		}
192	});
193
194	initScrollers();
195	refreshScrollers();
196}
197
198function init_log_in() {
199	$(".signin").click(function(e) {
200		e.preventDefault();
201		$("fieldset#signin_menu").toggle();
202		$(".signin").toggleClass("menu-open");
203		$('#userid').focus();
204	});
205
206	$("fieldset#signin_menu").mouseup(function() {
207		return false;
208	});
209
210	$(document).mouseup(function(e) {
211		if ($(e.target).parent("a.signin").length == 0) {
212			$(".signin").removeClass("menu-open");
213			$("fieldset#signin_menu").hide();
214		}
215	});
216}
217
218// Minimum content height
219
220function init_min_height() {
221	if($('.carouselWrap').length == 0){
222		update_min_height();
223		$(window).resize(update_min_height);
224	}
225
226	//Overriding the initial properties from default-styles.css
227	/*$('.catalog_class footer').show();
228	$('body.catalog_class').css('overflow', 'auto');*/
229}
230
231function update_min_height() {
232	var header = $('header');
233	var footer = $('footer');
234	var windowHeight = $(window).height() - header.height() - footer.height();
235	if($('#calendar2').length && $('table.calendar').hasClass('monthly')) {
236		windowHeight = $('#calendar2').outerHeight() + 30 > windowHeight ? $('#calendar2').outerHeight() + 30 : windowHeight;
237	}
238	// Thin main menu height
239	if ($('nav#leftColumn ol.thinMainNav').length)
240		$('nav#leftColumn ol.thinMainNav').height($(window).height() - $('header').height());
241
242	if(typeof globalWindowWidth == 'undefined'){
243		globalWindowWidth = $(window).width();
244	}
245
246	if (/iPad/i.test(navigator.userAgent) && globalWindowWidth > 768 && $('.hasEditor').length) {
247		$('#wrapper').css('overflow', 'hidden');
248	}
249
250	resizeFixedLeftColumn();
251	if ($('body').hasClass('section_nav_page')) section_nav_height();
252}
253
254// Fixed left column height
255
256function set_vars(){
257	window.first_resizeFixedLeftColumn_call = false;
258	window.loadFixedLeftColumn = true;
259// Vars for fixed grading column defined outside function to prevent shudder in IE11 and Edge
260	if ($('.grading_fixed_col').length > 0) {
261		window.rightColumn_top = $('.rightColumn').offset().top;
262 		position_of_topbar = $('#fixedSectionHeader').css('position')
263		let left_column = document.body.classList.contains('evo') ? $('.leftColumn') : $('#leftColumn');
264		//this condition is to be executed only on the old ui.
265		if(position_of_topbar == 'fixed' || position_of_topbar == 'sticky'){
266			window.fixed_header_bottom = left_column.offset().top + $('#fixedSectionHeader').outerHeight();
267		}
268	}
269}
270set_vars();
271$(window).on('loadcomplete', function(){
272	//added to fix issue where varible where not updated for ajax pages
273	set_vars();
274});
275function fixedLeftColumnHeight(leftcolumn_height) {
276	var fixed_nav_bottom = $(window).scrollTop() - ( $('footer').offset().top - $(window).height());
277
278	if (fixed_nav_bottom > 0) {
279		// footer visible
280		if (is_mobile_device()) {
281			fixed_nav_bottom = fixed_nav_bottom + ((window.screen.availHeight - globalWindowHeight)/2)
282		}
283		$('#leftColumn').css({'height': leftcolumn_height - fixed_nav_bottom + 2, 'min-height': 0});
284	} else {
285		$('#leftColumn').css('min-height', leftcolumn_height + 2);
286	}
287
288	if (document.querySelector("body.evo")) {
289		if ($('.ctr_user_cart #leftColumn').length != 0) {
290			$('#leftColumn').css({'height': leftcolumn_height - 60});
291		} else {
292			$('#leftColumn').css({'height': leftcolumn_height - 20});
293		}
294	}
295
296	if ($('nicescroll-rails').length == 0)
297		init_niceScroll()
298}
299
300function resizeFixedLeftColumn() {
301	if ($('body').hasClass('catalog_class') && $(window).width() >= 768) {
302		var header_height = ($('body').hasClass('transparent_header')) ? 0 : $('header').outerHeight();
303		var leftcolumn_height = ($('body').hasClass('portal')) ? $(window).height() - $('.portal #contentHeader').outerHeight() - header_height : $(window).height() - header_height;
304
305		if (Excalibur.evo && $('body').hasClass('portal') && $('nav#leftColumn div#checkout_summary')) {
306			leftcolumn_height = $('footer').offset().top - $('.portal #contentHeader').outerHeight() - $(window).scrollTop() + 21;
307		}
308
309		// Set bottom of fixed left nav based on footer position
310		if (loadFixedLeftColumn == true) {
311			setTimeout(function(){
312				fixedLeftColumnHeight(leftcolumn_height);
313				loadFixedLeftColumn = false
314			}, 100);
315		} else {
316			fixedLeftColumnHeight(leftcolumn_height)
317		}
318	}
319
320	// Fixed right column height
321	if ($('.grading_fixed_col').length > 0) {
322		if ($('.grading_fixed_col').css('opacity') == 0) {
323			$('.grading_fixed_col').css('opacity','1');
324		}
325
326		if ($(window).width() >= 980) {
327			var scroll_pos = $('#contentWrap').outerHeight() - globalWindowHeight - $(window).scrollTop() + $('header').outerHeight();
328
329			$('.grading_fixed_col, .column_resize_handle').css('top', right
329Column_top);
330			if ($('#fixedSectionHeader').hasClass('student') && (!document.querySelector("body.evo"))) {
331				// student view - change top according according to scroll position
332				var top_pos = $('.rightColumn').offset().top - $(window).scrollTop() - 14;
333				if (top_pos > fixed_header_bottom) {
334					$('.grading_fixed_col, .column_resize_handle').css('top', top_pos);
335				} else {
336					// highest top position
337					$('.grading_fixed_col, .column_resize_handle').css('top', fixed_header_bottom);
338				}
339			}
340
341			if (scroll_pos < 0) {
342				// Footer is visible
343				$('.grading_fixed_col, .column_resize_handle').css('bottom', - scroll_pos + 'px');
344			} else {
345				// Footer isn't visible
346				$('.grading_fixed_col, .column_resize_handle').css('bottom', '0');
347			}
348		}
349	}
350}
351$(window).scroll(function() {
352  if ($('body').hasClass('catalog_class') || $('.grading_fixed_col').length > 0) {
353		// Fix scroll position which sometimes breaks NiceScroll on page load.
354		if (!first_resizeFixedLeftColumn_call && $(window).scrollTop() > 0) {
355			$(window).scrollTop(0);
356			first_resizeFixedLeftColumn_call = true;
357		}
358		resizeFixedLeftColumn();
359	}
360});
361
362function init_niceScroll() {
363  // if ($('.grading_fixed_col').length > 0) {
364  //   // Teacher rubric grading pages
365  //   if (is_mobile_device()) {
366  //     $(".grading_fixed_col, .grade-floating-rubric-scroll").css({'-webkit-overflow-scrolling':'touch'});
367  //   } else {
368  //     $(".grading_fixed_col, .grade-floating-rubric-scroll").niceScroll({
369  //       cursorwidth: "7px",
370  //       cursorcolor: "#000",
371  //       cursoropacitymax: 0.4,
372  //       autohidemode: ($('#fixedSectionHeader').hasClass('student') ? true : false),
373  //       railpadding: {top: 2, right: 1, left: 1, bottom: 1},
374  //       nativeparentscrolling: false,
375  //       railalign: (is_rtl_mode() ? 'left' : 'right')
376  //     });
377  //     // Only force show the scrollbar on the teacher view
378  //     if (!$('#fixedSectionHeader').hasClass('student')) {
379  //       $('.nicescroll-rails-vr').addClass('do_not_hide');
380  //     }
381  //   }
382  // } else {
383    // Catalog item and checkout pages
384    if (is_mobile_device()) {
385      $(".catalog_class #leftColumn").css({'overflow':'auto'});
386    } else {
387      $(".catalog_class #leftColumn").niceScroll({
388        cursorcolor: "#000",
389        cursoropacitymax: 0.4,
390        cursorborder:"1px solid transparent",
391        autohidemode: false,
392        railalign: (is_rtl_mode() ? 'left' : 'right')
393      });
394    }
395  //}
396}
397
398// The action toolbar renders the right-aligned ribbon as .action-toolbar--right,
399// so both container classes have to be matched wherever the legacy one was.
400const MSG_SIBLING_PREFIX = 'div.info:not(.keepopen) + .pageHeading.mobile_only + ';
401const MSG_SIBLING_RIBBONS = MSG_SIBLING_PREFIX + '.optionsRibbon.optionsRight, ' + MSG_SIBLING_PREFIX + '.action-toolbar--right';
402
403function msgHide(){
404	$(MSG_SIBLING_RIBBONS).hide();
405
406	if ($('body').hasClass('catalog_class') && $('div.alert_block.info:not(.keepopen)').length > 0 && $(window).width() > $('#wrapper').outerWidth()) {
407		$('.catalog_class').addClass('offscreen_nicescroll'); // Hide niceScroll while alert closes and page height changes
408	}
409
410	$('div.info:not(.keepopen)').animate({
411		height: '0', opacity: '0'
412	}, 500, function () {
413		$(this).css('display', 'none');
414		$(MSG_SIBLING_RIBBONS).css('top', 0).show();
415		if ($('body').hasClass('catalog_class')) {
416			resizeFixedLeftColumn(); // Resize niceScroll scroll bar after page height change
417			$('.catalog_class').removeClass('offscreen_nicescroll'); // remove class
418		}
419		if ($('#fixedSectionHeader').length) {
420			resizeSectionHeader(true);
421			if ($('.grading_fixed_col').length) {
422				// reset grading column after alert is removed
423				rightColumn_top = $('.rightColumn').offset().top;
424				fixed_header_bottom = $('#leftColumn').offset().top + $('#fixedSectionHeader').outerHeight();
425				resizeFixedLeftColumn();
426			}
427		}
428	});
429}
430
431// initialize sound manager
432
433function init_sound_manager(soundHandler) {
434	soundManager.setup({
435		url: '/flash/soundmanager2.swf?2',
436		debugMode: false,
437		onready: function() {
438			loaded_sound_manager = true;
439
440			soundManager.createSound({
441				id : 'user_sound',
442				url : '/audio/user.mp3'
443			});
444
445			soundManager.createSound({
446				id : 'message_sound',
447				url : '/audio/message.mp3'
448			});
449
450			if (soundHandler){
451				soundHandler();
452			}
453		}
454	});
455}
456
457// process tables for IE7
458
459function process_tables() {
460	$('td[colspan^="100"]').each(function(i) {
461		var width = 0;
462
463		$(this).parent().next().children().each(function(j) {
464			var colspan = $(this).attr('colspan');
465			width += (colspan == null ? 1 : parseInt(colspan));
466		});
467
468		$(this).attr('colspan', width);
469	});
470}
471
472// dynamic site width
473
474function update_site_width() {
475	var site_width = (is_mobile_app_mode() ? globalWindowWidth : $(window).width()) 
475- 26;
476	$('#footer_center').width(site_width);
477}
478
479function init_update_site_width() {
480	$('#main_content, #footer_center').css('max-width', (1400 - 26) + 'px'); // #main_content padding (24px) + #main_content border = 26
481	$('#logo_block').css('margin-left', 13 + 'px'); // half of padding + border above
482	$('#main_content').css('margin-left', '0px');
483	$('#buttons_right, #main_content').css('margin-right', '0px');
484	update_site_width();
485	$(window).resize(update_site_width);
486}
487
488// navigation
489
490function init_navigation() {
491	if ($('html').hasClass("iPad")) {
492		$('#main_nav li').click(function(event) {
493			$(this).parent().find('.highlight').removeClass('highlight');
494			$(this).siblings().find('.dropdown').hide();
495			$(this).find('a:first').addClass('highlight');
496
497			if ($(this).find(".dropdown").is(':hidden')) {
498				$(this).find(".dropdown").show();
499			} else {
500				$(this).find(".dropdown").hide();
501				$(this).parent().find('.highlight').removeClass('highlight');
502			}
503
504			event.stopPropagation();
505		});
506	} else {
507		$('ul#main_nav > li').hover(function() {
508			$(this).find('a:first').addClass("highlight");
509			$(this).find('.dropdown').stop(true, true).show();
510		}, function() {
511			$(this).find('a:first').removeClass("highlight");
512			$(this).find('.dropdown').stop(true, true).hide();
513		});
514	}
515
516	// click inside drop down on right
517	$('#advSearchHolder').click(function() {
518		if ($('.dropdownOn').length == 0) {
519			$('#advSearchHolder').removeClass('dropdownOff').addClass('dropdownOn');
520
521			if ($('.advSearchOn').length != 0) {
522				$('.search').removeClass('advSearchOn').addClass('advSearchOff');
523			}
524
525			return false;
526		}
527	});
528
529	$('.adminDropdown').click(function(event) {
530		if ($(this).find(".header_dropdown").is(':hidden')) {
531			$(this).find(".header_dropdown").show();
532			$('#leftColumn .dropdown_holder').removeClass('dropdownOff').addClass('dropdownOn');
533		} else {
534			$(this).find(".header_dropdown").hide();
535			$('#leftColumn .dropdown_holder').removeClass('dropdownOn').addClass('dropdownOff');
536		}
537
538		event.stopPropagation();
539	});
540
541	$('.search').click(function(event) {
542		if ($('.advSearchOn').length == 0) {
543			$('.search').removeClass('advSearchOff').addClass('advSearchOn');
544
545			if ($('.dropdownOn').length != 0) {
546				$('#advSearchHolder').removeClass('dropdownOn').addClass('dropdownOff');
547			}
548
549			$('#search_phrase').focus();
550			return false;
551		}
552		event.stopPropagation();
553	});
554
555	$("#wrapper").click(function() {
556		if ($('.dropdownOn').length != 0) {
557			$('.dropdown_holder').removeClass('dropdownOn').addClass('dropdownOff');
558			$('#advSearchHolder').removeClass('dropdownOn').addClass('dropdownOff');
559			$('#leftColumn .dropdown_holder').removeClass('dropdownOn').addClass('dropdownOff');
560			$('.header_dropdown').hide();
561			$('.assignment_type').removeClass('dropdownOn');
562		}
563
564		if ($('.advSearchOn').length != 0) {
565			$('.search').removeClass('advSearchOn').addClass('advSearchOff');
566		}
567
568		/* only for iPad */
569		if ($('#main_nav a.highlight').length != 0) {
570			$('#main_nav .dropdown').hide();
571			$('#main_nav a.highlight').removeClass('highlight');
572		}
573	});
574
575	/* drop down scrolling for IE6 */
576	if ($.browser.msie && parseInt($.browser.version, 10) == 6) {
577		$('div.scroll ul').each(function() {
578			var $this = $(this);
579
580			if ($this.children('li').length > 10) {
581				$this.parent().css('height', '270px');
582			}
583		});
584	}
585}
586
587// open window
588
589function open_new_window(url){
590	if(is_mobile_app_mode()){
591		window.parent.postMessage("{\"method\": \"loadBrowser\", \"href\": \"" + url + "\"}", "*");
592	}else {
593		window.open(url);
594	}
595}
596
597// date picker
598
599// Not the input's title: the helpers build that from model+attribute names ("event begin at").
600function datepickerAriaLabel() {
601    return window.datepickerLabel || 'Date picker';
602}
603
604// The div is a singleton shared with pickers built elsewhere, so release everything on close.
605function datepickerOpenFor(inputEl) {
606    const inst = $.datepicker._curInst;
607    return !!$.datepicker._datepickerShowing && !!inst && !!inst.input && inst.input[0] === inputEl;
608}
609
610function releaseSharedDatepickerState() {
611    const $shared = $('#ui-datepicker-div');
612    $shared
613        .off('keydown.datepicker-accessibility')
614        .removeAttr('role')
615        .removeAttr('aria-label')
616        .removeData('focus-date')
617        .removeData('focus-nav')
618        .removeData('keyboard-nav');
619    // Bound on the buttons and day cells, so the div's .off() above does not reach them.
620    $shared.find('.ui-datepicker-buttonpane button, td[data-handler="selectDay"] a')
621        .off('click.datepicker-accessibility');
622    if (datepickerRedrawObserver) { datepickerRedrawObserver.disconnect(); datepickerRedrawObserver = null; }
623}
624
625function setDatepickerExpanded(inputEl, isOpen) {
626    const $input = $(inputEl);
627    // combobox because aria-expanded is not supported on the implicit textbox role.
628    $input.attr({ 'role': 'combobox', 'aria-haspopup': 'dialog', 'aria-expanded': isOpen ? 'true' : 'false' });
629    if (isOpen) { $input.attr('aria-controls', 'ui-datepicker-div'); }
630    else { $input.removeAttr('aria-controls'); }
631    if (!isOpen) { $('#datepicker-announcer').removeData('last'); }
632}
633
634function datepickerMonthLabel(dpDiv) {
635    const $title = $(dpDiv).find('.ui-datepicker-title');
636    if (!$title.length || $title.find('select').length) { return datepickerAriaLabel(); }
637    return $title.text().replace(/\s+/g, ' ').trim() || datepickerAriaLabel();
638}
639
640function datepickerAnnouncer() {
641    let $announcer = $('#datepicker-announcer');
642    if (!$announcer.length) {
643        $announcer = $('<div id="datepicker-announcer" class="sr-only" role="status" aria-live="polite"></div>').appendTo('body');
644    }
645    return $announcer;
646}
647
648function announceDatepickerMonth(text) {
649    const $announcer = datepickerAnnouncer();
650    if ($announcer.data('last') === text) { return; }
651    $announcer.data('last', text);
652    setTimeout(function() { $announcer.text(text); }, 0);
653}
654
655function restoreDatepickerRovingTabindex(dpDiv) {
656    const $datepicker = $(dpDiv);
657    const $dateCells = $datepicker.find('td:not(.ui-datepicker-unselectable) a.ui-state-default');
658    if (!$dateCells.length) { return; }
659    // Leave an intact roving position alone — a timepicker slider stop is not a redraw.
660    if ($dateCells.filter('[tabindex="0"]').length === 1) { return; }
661    $dateCells.attr('tabindex', '-1').removeClass('ui-state-focus ui-state-hover');
662    $datepicker.find('.ui-datepicker-prev, .ui-datepicker-next').attr('tabindex', '0');
663    const $currentDay = $datepicker.find('.ui-datepicker-current-day a');
664    const $today = datepickerTodayCell($datepicker);
665    ($currentDay.length ? $currentDay : ($today.length ? $today : $dateCells.first()))
666        .attr('tabindex', '0').addClass('ui-state-focus');
667}
668
669// An empty field emits no current-day cell: _generateHTML compares against new Date(9999, 9, 9).
670function datepickerTodayCell(dpDiv) {
671    return $(dpDiv).find('td.ui-datepicker-today:not(.ui-datepicker-unselectable) a.ui-state-default');
672}
673
674// Restores the pattern after any redraw — _doKeyUp and Ctrl+arrow redraw without notifying.
675let datepickerRedrawObserver = null;
676function watchDatepickerRedraws(dpDiv, inputEl) {
677    if (datepickerRedrawObserver) { datepickerRedrawObserver.disconnect(); datepickerRedrawObserver = null; }
678    if (typeof MutationObserver === 'undefined' || !$(dpDiv).length) { return; }
679    datepickerRedrawObserver = new MutationObserver(function() {
680        if (!datepickerOpenFor(inputEl)) { return; }
681        applyDatepickerAria(dpDiv, datepickerAriaLabel(), inputEl);
682        restoreDatepickerRovingTabindex(dpDiv);
683    });
684    datepickerRedrawObserver.observe($(dpDiv)[0], { childList: true });
685}
686
687function seedDatepickerAnnouncement(dpDiv) {
688    datepickerAnnouncer().data('last', datepickerMonthLabel(dpDiv));
689}
690
691function datepickerMonthChanged(inst) {
692    const keyboardNav = !!inst.dpDiv.data('keyboard-nav');
693    inst.dpDiv.removeData('keyboard-nav');
694    const label = datepickerAriaLabel();
695    const inputEl = inst.input[0];
696    setTimeout(function() {
697        if (!datepickerOpenFor(inputEl)) { return; }
698        applyDatepickerAria(inst.dpDiv, label, inputEl);
699        announceDatepickerMonth(datepickerMonthLabel(inst.dpDiv));
700    }, 0);
701    applyDatepickerFocusManagement(inst.dpDiv, inputEl, keyboardNav);
702}
703
704function bindDatepickerOpenKeys(inputEl) {
705    // A disabled field can never open the picker, so it must not advertise one.
706    if (!inputEl || $(inputEl).is(':disabled')) { return; }
707    $(inputEl).on('keydown.datepicker-open', function(e) {
708        if (e.keyCode !== 40) { return; }
709        e.preventDefault();
710        const openForThis = datepickerOpenFor(this);
711        if (openForThis) {
712            // Scoped to date cells: the addon's slider handles are also <span tabindex="0">.
713            const $target = $('#ui-datepicker-div').find('a.ui-state-default[tabindex="0"]').first();
714            if ($target.length) { $target.focus(); }
715        } else {
716            $(this).data('datepicker-keyboard-open', true);
717            $(this).datepicker('show');
718        }
719    });
720    setDatepickerExpanded(inputEl, false);
721    datepickerAnnouncer();
722}
723
724function applyDatepickerAria(dpDiv, label, inputEl) {
725    if (inputEl && !datepickerOpenFor(inputEl)) {
726        setDatepickerExpanded(inputEl, false);
727        return;
728    }
729    const $datepicker = $(dpDiv);
730    $datepicker.attr({'role': 'dialog', 'aria-label': label});
731    if (inputEl) { setDatepickerExpanded(inputEl, true); }
732
733    const $calendar = $datepicker.find('.ui-datepicker-calendar');
734    $calendar.attr({'role': 'grid', 'aria-label': datepickerMonthLabel(dpDiv)});
735    $calendar.find('tr').attr('role', 'row');
736    $calendar.find('td:not(.ui-datepicker-unselectable)').attr({'role': 'gridcell', 'aria-selected': 'false'});
737    $calendar.find('td.ui-datepicker-unselectable').attr({'role': 'gridcell', 'aria-disabled': 'true'});
738    $calendar.find('.ui-datepicker-current-day').attr('aria-selected', 'true');
739
740    const $navButtons = $datepicker.find('.ui-datepicker-prev, .ui-datepicker-next');
741    $navButtons.attr('role', 'button');
742    $navButtons.filter('.ui-state-disabled').attr('aria-disabled', 'true');
743    $navButtons.not('.ui-state-disabled').removeAttr('aria-disabled');
744
745    if (inputEl) { bindDatepickerButtonPaneFocus(dpDiv, inputEl); }
746}
747
748// On the buttons, not delegated on the div: onClose offs the div's handlers mid-click.
749// Returns focus to the field without showOn:'focus' reopening the picker. No-op when focu
749s is
750// already there: .focus() fires no event then, so the flag would survive and swallow the next open.
751function returnFocusToDatepickerField(inputEl) {
752    if (document.activeElement === inputEl) { return; }
753    $(inputEl).data('datepicker-suppress-open', true);
754    $(inputEl).focus();
755}
756
757function bindDatepickerButtonPaneFocus(dpDiv, inputEl) {
758    const $datepicker = $(dpDiv);
759    const $input = $(inputEl);
760    $datepicker.find('.ui-datepicker-buttonpane button')
761        .off('click.datepicker-accessibility')
762        .on('click.datepicker-accessibility', function() {
763            if ($(this).hasClass('ui-datepicker-close')) {
764                setTimeout(function() { returnFocusToDatepickerField(inputEl); }, 10);
765                return;
766            }
767            setTimeout(function() {
768                if (!datepickerOpenFor(inputEl)) { return; }
769                const $target = $datepicker.find('a.ui-state-default[tabindex="0"]').first();
770                if ($target.length) { $target.focus(); }
771            }, 0);
772        });
773
774    // Mouse selection too: _selectDate hides the picker and its own restore is dead code. Also
775    // reached by keyboard selection, which triggers a click on the cell.
776    $datepicker.find('td[data-handler="selectDay"] a')
777        .off('click.datepicker-accessibility')
778        .on('click.datepicker-accessibility', function() {
779            setTimeout(function() {
780                // pick_date_time stays open for the time controls, so only restore when it closed.
781                if (datepickerOpenFor(inputEl)) { return; }
782                returnFocusToDatepickerField(inputEl);
783            }, 10);
784        });
785}
786
787function datepickerCellForDate(dpDiv, date) {
788    const $cells = $(dpDiv).find('td[data-month="' + date.getMonth() + '"][data-year="' + date.getFullYear() + '"]')
789        .not('.ui-datepicker-unselectable').find('a.ui-state-default');
790    return $cells.filter(function() { return parseInt($(this).text(), 10) === date.getDate(); }).first();
791}
792
793function datepickerDateOfCell($cell) {
794    const $td = $cell.closest('td');
795    const year = parseInt($td.attr('data-year'), 10);
796    const month = parseInt($td.attr('data-month'), 10);
797    const day = parseInt($cell.text(), 10);
798    if (isNaN(year) || isNaN(month) || isNaN(day)) { return null; }
799    return new Date(year, month, day);
800}
801
802function applyDatepickerFocusManagement(dpDiv, inputEl, moveFocus) {
803    setTimeout(function() {
804        if (inputEl && !datepickerOpenFor(inputEl)) { return; }
805        const $datepicker = $(dpDiv);
806        const $input = $(inputEl);
807        $datepicker.off('keydown.datepicker-accessibility');
808        const $dateCells = $datepicker.find('td:not(.ui-datepicker-unselectable) a.ui-state-default');
809
810        const focusDateStamp = $datepicker.data('focus-date');
811        const focusNav = $datepicker.data('focus-nav');
812        $datepicker.removeData('focus-date').removeData('focus-nav');
813
814        if ($dateCells.length) {
815            $dateCells.attr('tabindex', '-1').removeClass('ui-state-focus ui-state-hover');
816            $datepicker.find('.ui-datepicker-prev, .ui-datepicker-next').attr('tabindex', '0');
817
818            let $focusTarget = focusDateStamp ? datepickerCellForDate($datepicker, new Date(focusDateStamp)) : null;
819            if (!$focusTarget || !$focusTarget.length) {
820                const $currentDay = $datepicker.find('.ui-datepicker-current-day a');
821                const $today = datepickerTodayCell($datepicker);
822                // Must match restoreDatepickerRovingTabindex's chain, or two cells get highlighted.
823                $focusTarget = $currentDay.length ? $currentDay : ($today.length ? $today : $dateCells.first());
824            }
825            $focusTarget.attr('tabindex', '0').addClass('ui-state-focus');
826
827            const $navToRefocus = focusNav ? $datepicker.find('.ui-datepicker-' + focusNav) : $();
828            if ($navToRefocus.length && $navToRefocus.attr('data-handler')) {
829                $navToRefocus.focus();
830            } else if (moveFocus !== false) {
831                $focusTarget.focus();
832            }
833        }
834
835        const moveFocusByDays = function($from, delta) {
836            const fromDate = datepickerDateOfCell($from);
837            if (!fromDate) { return null; }
838            const target = new Date(fromDate.getFullYear(), fromDate.getMonth(), fromDate.getDate() + delta);
839            const $inView = datepickerCellForDate($datepicker, target);
840            if ($inView.length) { return $inView; }
841            const $nav = $datepicker.find(delta < 0 ? '.ui-datepicker-prev' : '.ui-datepicker-next');
842            // Disabled arrows render without [data-handler], so the click is a no-op: set no flag.
843            if (!$nav.attr('data-handler')) { return null; }
844            $datepicker.data('focus-date', target.getTime());
845            $datepicker.data('keyboard-nav', true);
846            $nav.trigger('click');
847            return null;
848        };
849        const stepMonths = function($from, offset) {
850            const fromDate = datepickerDateOfCell($from);
851            if (fromDate) {
852                const firstOfTarget = new Date(fromDate.getFullYear(), fromDate.getMonth() + offset, 1);
853                const daysInTarget = new Date(firstOfTarget.getFullYear(), firstOfTarget.getMonth() + 1, 0).getDate();
854                const day = Math.min(fromDate.getDate(), daysInTarget);
855                $datepicker.data('focus-date', new Date(firstOfTarget.getFullYear(), firstOfTarget.getMonth(), day).getTime());
856            }
857            $datepicker.data('keyboard-nav', true);
858            $.datepicker._adjustDate($input[0], offset, 'M');
859        };
860
861        $datepicker.on('keydown.datepicker-accessibility', function(e) {
862            const $allDates = $datepicker.find('td:not(.ui-datepicker-unselectable) a.ui-state-default');
863            const $active = $allDates.filter('[tabindex="0"]');
864            const onDateCell = $(e.target).is('a.ui-state-default');
865            const onNavButton = $(e.target).is('.ui-datepicker-prev, .ui-datepicker-next');
866            let $next = null;
867
868            if (onDateCell && (e.keyCode === 37 || e.keyCode === 39 || e.keyCode === 38 || e.keyCode === 40)) {
869                e.preventDefault();
870                const delta = { 37: -1, 39: 1, 38: -7, 40: 7 }[e.keyCode];
871                $next = moveFocusByDays($active, delta);
872            } else if (onNavButton && (e.keyCode === 13 || e.keyCode === 32)) { // Enter/Space on ◀/▶
873                e.preventDefault();
874                const $nav = $(e.target);
875                if ($nav.attr('data-handler')) {
876                    $datepicker.data('focus-nav', $nav.hasClass('ui-datepicker-prev') ? 'prev' : 'next');
877                    $datepicker.data('keyboard-nav', true);
878                    $nav.trigger('click');
879                }
880            } else if (onDateCell && (e.keyCode === 36 || e.keyCode === 35)) { // Home/End — first/last day of week
881                e.preventDefault();
882                const $rowDates = $(e.target).closest('tr').find('td:not(.ui-datepicker-unselectable) a.ui-state-default');
883                $next = (e.keyCode === 36) ? $rowDates.first() : $rowDates.last(
883);
884            } else if (onDateCell && (e.keyCode === 33 || e.keyCode === 34)) { // PageUp/PageDown — month, +Shift year
885                e.preventDefault();
886                stepMonths($active, (e.keyCode === 33 ? -1 : 1) * (e.shiftKey ? 12 : 1));
887            } else if (onDateCell && (e.keyCode === 32 || e.keyCode === 13)) { // Space/Enter — select
888                e.preventDefault();
889                $active.trigger('click');
890                setTimeout(function() {
891                    if ($.datepicker._datepickerShowing) {
892                        $datepicker.find('a.ui-state-default[tabindex="0"]').first().focus();
893                    } else {
894                        returnFocusToDatepickerField(inputEl);
895                    }
896                }, 10);
897            } else if (e.keyCode === 27) { // Escape — close, return focus, suppress reopen
898                e.preventDefault();
899                e.stopPropagation();
900                ($input.datepicker ? $input.datepicker('hide') : $datepicker.hide());
901                setTimeout(() => returnFocusToDatepickerField(inputEl), 10);
902            } else if (e.keyCode === 9) { // Tab boundary — close and advance past the input
903                const $focusable = $datepicker.find(
904                    '[tabindex="0"], input:not([disabled]):not([tabindex="-1"]), ' +
905                    'select:not([disabled]):not([tabindex="-1"]), button:not([disabled]):not([tabindex="-1"])'
906                ).filter(':visible');
907                const idx = $focusable.index(e.target);
908                if ((e.shiftKey && idx === 0) || (!e.shiftKey && idx === $focusable.length - 1)) {
909                    const isShift = e.shiftKey;
910                    e.preventDefault();
911                    e.stopPropagation();
912                    ($input.datepicker ? $input.datepicker('hide') : $datepicker.hide());
913                    // PAST the input, not back to it: focusing it would reopen via showOn:focus.
914                    setTimeout(function() {
915                        const scope = $input.closest('.modal, #facebox, .facebox, [role="dialog"]');
916                        // Exclude the closing picker: mid-fade, still :visible, and at body level.
917                        const $closing = $('#ui-datepicker-div');
918                        const tabbable = (scope.length ? scope : $(document)).find(
919                            'a[href]:not([tabindex="-1"]), ' +
920                            'input:not([disabled]):not([tabindex="-1"]), ' +
921                            'select:not([disabled]):not([tabindex="-1"]), ' +
922                            'textarea:not([disabled]):not([tabindex="-1"]), ' +
923                            'button:not([disabled]):not([tabindex="-1"]), ' +
924                            '[tabindex]:not([tabindex="-1"])'
925                        ).not($closing).not($closing.find('*')).filter(':visible').toArray();
926                        if (isShift) {
927                            returnFocusToDatepickerField(inputEl);
928                            return;
929                        }
930                        const inputIdx = tabbable.indexOf($input[0]);
931                        const target = inputIdx === -1 ? null : tabbable[inputIdx + 1];
932                        if (target) { $(target).focus(); } else { returnFocusToDatepickerField(inputEl); }
933                    }, 10);
934                }
935            }
936
937            if ($next && $next.length) {
938                $active.attr('tabindex', '-1').removeClass('ui-state-focus');
939                $next.attr('tabindex', '0').addClass('ui-state-focus').focus();
940            }
941        });
942    }, 0);
943}
944
945function setDatepickerPos(input, inst) {
946    if ($(input).data('datepicker-suppress-open')) {
947        $(input).removeData('datepicker-suppress-open');
948        return false;
949    }
950    const keyboardOpen = !!$(input).data('datepicker-keyboard-open');
951    $(input).removeData('datepicker-keyboard-open');
952    const rect = input.getBoundingClientRect();
953    setTimeout(function () {
954        const scrollTop = inst.dpDiv.css('position') === 'fixed' ? 0 : $(window).scrollTop();
955        inst.dpDiv.css({ top: rect.top + input.offsetHeight + scrollTop });
956
957        applyDatepickerAria(inst.dpDiv, datepickerAriaLabel(), input);
958        seedDatepickerAnnouncement(inst.dpDiv);
959        watchDatepickerRedraws(inst.dpDiv, input);
960        applyDatepickerFocusManagement(inst.dpDiv, input, keyboardOpen);
961    }, 0);
962}
963
964function save_date_picker(date, picker, name, callback) {
965	var input = $('#' + name);
966	setDatepickerExpanded(input, false);
967	releaseSharedDatepickerState();
968	var altField = $('#' + name + '_alt');
969	var altValue = altField.val();
970	var year = '', month = '', day = '';
971
972	if(altValue && altValue.trim() !== ''){
973		// Parse from stable ISO format (YYYY-MM-DD)
974		var parts = altValue.split('-');
975		if(parts.length === 3){
976			var y = parseInt(parts[0], 10);
977			var m = parseInt(parts[1], 10);
978			var d = parseInt(parts[2], 10);
979			if (!isNaN(y) && !isNaN(m) && !isNaN(d)) {
980				year = y;
981				month = m;
982				day = d;
983			} else {
984				year = '';
985				month = '';
986				day = '';
987			}
988		}
989	}
990
991	$('#' + name + '_year').val(year);
992	$('#' + name + '_month').val(month);
993	$('#' + name + '_day').val(day);
994
995	if(callback){
996		callback(year, month, day)
997	}
998}
999
1000// date time picker
1001
1002function save_date_time_picker(date, picker, name, use_24) {
1003	setDatepickerExpanded($('#' + name), false);
1004	releaseSharedDatepickerState();
1005	var input = $('#' + name).val().trim();
1006	var altField = $('#' + name + '_alt');
1007	var altValue = altField.val();
1008
1009	if (input == '' || !altValue || altValue.trim() === '') {
1010		$('#' + name + '_year').val('');
1011		$('#' + name + '_month').val('');
1012		$('#' + name + '_day').val('');
1013		$('#' + name + '_hours').val('');
1014		$('#' + name + '_minutes').val('');
1015	} else {
1016		// Parse from stable ISO format (YYYY-MM-DD HH:MM:SS)
1017		var parts = altValue.split(' ');
1018		if(parts.length === 2){
1019			var dateParts = parts[0].split('-');
1020			var timeParts = parts[1].split(':');
1021			
1022			if(dateParts.length === 3 && timeParts.length >= 2){
1023				var year = parseInt(dateParts[0], 10);
1024				var month = parseInt(dateParts[1], 10);
1025				var day = parseInt(dateParts[2], 10);
1026				var hours = parseInt(timeParts[0], 10);
1027				var minutes = parseInt(timeParts[1], 10);
1028				if (!isNaN(year) && !isNaN(month) && !isNaN(day) && !isNaN(hours) && !isNaN(minutes)) {
1029					$('#' + name + '_year').val(year);
1030					$('#' + name + '_month').val(month);
1031					$('#' + name + '_day').val(day);
1032					$('#' + name + '_hours').val(hours);
1033					$('#' + name + '_minutes').val(minutes);
1034				} else {
1035					$('#' + name + '_year').val('');
1036					$('#' + name + '_month').val('');
1037					$('#' + name + '_day').val('');
1038					$('#' + name + '_hours').val('');
1039					$('#' + name + '_minutes').val('');
1040				}
1041			}
1042		}
1043	}
1044}
1045
1046// set_self_registration
1047
1048function set_self_registration(value) {
1049	if (value == 'WithAccessCode') {
1050		$('#configure_access_codes').show();
1051	} else {
1052		$('#configure_access_codes').hide();
1053	}
1054
1055	ajax_request('/registration_codes/set_type?value=' + value);
1056}
1057
1058function text_field_for_organization(checkbox) {
1059    if (checkbox.checked) {
1060        hide_element('default_org_option');
1061    } else {
1062        show_element('default_org_option');
1063    }
1064
1065	ajax_request('/account_fields/set_text_field_for_organization?value=' + check_s(checkbox));
1066}
1067
1068function start_with_default_org_in_dropdown(checkbox) {
1069    ajax_request('/account_fields/set_start_with_default_org_in_dropdown?value=' + check_s(checkbox));
1070}
1071
1072function org_dropdown_other_option(checkbox) {
1073    ajax_request('/account_fields/set_org_dropdown_other_option?value=' + check_s(checkbox));
1074}
1075
1076// custom dropdown on signup
1077
1078function toggle_custom_organization_input_view(value){
1079    if (value === 'other') {
1080        $('.custom_organization_input').show();
1081    } else {
1082        $('.custom_organization_input').hide();
1083    }
1084}
1085
1086// view as
1087
1088function view_as_student(class_id) {
1089	$.facebox({
1090		'ajax' : '/teacher_class/view_as_student/' + class_id + '?from=' + encodeURIComponent(window.location.pathname + window.location.search)
1091	});
1092}
1093
1094function view_as_teacher(class_id) {
1095	window.location.href = '/student_class/view_as_teacher/' + class_id + '?from=' + encodeURIComponent(window.location.pathname + window.location.search);
1096}
1097
1098// canned messages
1099
1100function set_default_message(action_id, dropdown) {
1101	if (dropdown.value == 0) {
1102		$.facebox({
1103			'ajax' : '/canned_messages_admin/add_message/' + action_id
1104		});
1105	} else {
1106		ajax_request('/canned_messages_admin/set_default_message/' + action_id + '?value=' + dropdown.value);
1107	}
1108}
1109
1110/*
1111 * what happens when you click "Save"?
1112 */
1113
1114function select_message(action_id, dropdown) {
1115	if (dropdown.value == 0) {
1116		$.facebox({
1117			'ajax' : '/canned_messages_admin/add_message/' + action_id
1118		});
1119	} else {
1120		$.ajax({
1121			url : '/add_accounts_using_form/set_message?message_id=' + dropdown.value,
1122			async : false,
1123			success : function(data) {
1124				$('#message_subject').html('<p>' + data.subject + '</p>');
1125				$('#message_content').html(data.content);
1126			}
1127		});
1128	}
1129}
1130
1131// time zone
1132
1133function check_time_zone(time) {
1134	var browser_time = new Date();
1135	var server_time = new Date(time.year, time.month - 1, time.day, time.hour, time.min);
1136	var diff_time = Math.abs(browser_time.getTime() - server_time.getTime());
1137
1138	// 15 minutes is 900000 milliseconds
1139	if (diff_time > 900000) {
1140		show_element('time_warning');
1141	}
1142}
1143
1144// time
1145
1146function write_time() {
1147	if ($('input#time').length == 0) {
1148		var now = new Date();
1149		var time = now.getFullYear() + '-' + (now.getMonth() + 1) + '-' + now.getDate() + ' ' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();
1150		$('.signupForm, .formAutoWidths, #signup_form').prepend("<input type='hidden' id='time' name='time' value='" + time + "' />");
1151	}
1152}
1153
1154// dark mode toggle
1155
1156function dark_mode_toggle() {
1157	if (document.documentElement.getAttribute('data-theme') == "dark") {
1158		document.documentElement.setAttribute('data-theme', '');
1159		$(".tox-tinymce iframe").contents().find("body").removeClass('dark_editor');
1160	} else {
1161		document.documentElement.setAttribute('data-theme', 'dark');
1162		$(".tox-tinymce iframe").contents().find("body").addClass('dark_editor');
1163	}
1164
1165	if ($('.grade_book').length > 0) {
1166		gradebook_colors();
1167		draw_gradebook();
1168	}
1169
1170	$.post('/account/set_dark_mode', function(){
1171		if( $('body rapi-doc').length > 0 )
1172			location.reload();
1173	});
1174}
1175
1176// configure notifications
1177
1178function set_email_notification(attribute, checkbox) {
1179	ajax_request('/notifications/set_email_notification?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false'));
1180}
1181
1182function set_mobile_notification(attribute, checkbox) {
1183	ajax_request('/notifications/set_mobile_notification?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false'));
1184}
1185
1186// full admins
1187
1188function set_full_admin(checkbox, administrator_id) {
1189    ajax_request('/administrators/set_full_admin?administrator_id=' + administrator_id + '&value=' + (checkbox.checked ? 'true' : 'false'));
1190}
1191
1192// billing contacts
1193
1194function billing_contact(checkbox, administrator_id) {
1195	ajax_request('/administrators/set_billing_contact?administrator_id=' + administrator_id + '&value=' + (checkbox.checked ? 'true' : 'false'));
1196}
1197
1198// contact messages
1199
1200function contact_messages(checkbox, administrator_id) {
1201  ajax_request('/administrators/set_contact_messages?administrator_id=' + administrator_id + '&value=' + (checkbox.checked ? 'true' : 'false'));
1202}
1203
1204// e-commerce access
1205
1206function ecommerce_access(checkbox, administrator_id) {
1207	ajax_request('/administrators/set_ecommerce_access?administrator_id=' + administrator_id + '&value=' + (checkbox.checked ? 'true' : 'false'));
1208}
1209
1210// resources
1211
1212function update_resources(controller, id, lesson, section, folder, popup) {
1213	var subject = $('#resource_subject');
1214	var type = $('#resource_type');
1215	var library = $('#resource_library');
1216	var url = '/' + controller + '/new_from_favorites/' + id + '?';
1217	var args = [];
1218	var name = $('#resource_name').val();
1219
1220	if (name) {
1221		args.push('resource_name=' + name);
1222	}
1223
1224	if (lesson){
1225		args.push('lesson_id=' + lesson);
1226	}
1227
1228	if (section){
1229		args.push('section_id=' + section);
1230	}
1231
1232	if (folder){
1233		args.push('folder=' + folder);
1234	}
1235
1236	if (subject){
1237		args.push('subject=' + subject.val());
1238	}
1239
1240	if (type){
1241		args.push('type=' + type.val());
1242	}
1243
1244	if (library){
1245		args.push('library=' + library.val());
1246	}
1247
1248	url += args.join('&');
1249
1250	if (popup) {
1251		$.facebox({
1252			'ajax' : url
1253		});
1254	} else {
1255		window.location.href = url;
1256	}
1257}
1258
1259// click to chat
1260
1261function playChatSound() {
1262	soundManager.play('user_sound');
1263}
1264
1265function display_chat_alert(from_id, from_name, chat_room_id) {
1266	if (chat_alert_displayed) {
1267		return;
1268	}
1269
1270	chat_alert_displayed = true;
1271	var alerts = $('#alerts');
1272	from_name = from_name.replace('"', '\"');
1273
1274	if (is_mobile_app_mode()) {
1275		alerts.html('<div class="alert_block info keepopen" role="alert"><div class="alert_flex"><div class="alert_icon"><i class="info inverted"></i></div><p>' + chat_request_text + ' ' + from_name + ': <a href="javascript:accept_chat_request_app(' + chat_room_id + ');">' + accept_text + '</a> | <a href="javascript:ignore_chat_request(' + chat_room_id + ');">' + ignore_text + '</a></p></div></div>');
1276
1277	} else {
1278		alerts.html('<div class="alert_block info keepopen" role="alert"><div class="alert_flex"><div class="alert_icon"><i class="info inverted"></i></div><p>' + chat_request_text + ' ' + from_name + ': <a href="javascript:accept_chat_request(' + chat_room_id + ');">' + accept_text + '</a> | <a href="javascript:ignore_chat_request(' + chat_room_id + ');">' + ignore_text + '</a></p></div></div>');
1279	}
1280
1281	alerts.show();
1282
1283	if (loaded_sound_manager) {
1284		playChatSound();
1285	} else {
1286		$.getScript('/javascripts/soundmanager2-jsmin.js', function() {
1287			init_sound_manager(playChatSound);
1288		});
1289	}
1290}
1291
1292function hide_chat_alert() {
1293	var alerts = $('#alerts');
1294	alerts.html('');
1295	alerts.hide();
1296	chat_alert_displayed = false;
1297}
1298
1299function click_to_chat(user_id) {
1300	$.ajax({
1301		type: 'POST',
1302		url : '/click_to_chat/start_chat?user_id=' + user_id,
1303		success : function(json, text_status, jqXHR) {
1304			launch_chat('/click_to_chat/launch?chat_room_id=' + json.chat_room_id + '&chat_room_name=' + encodeURIComponent(json.user_name.replace(/'/g, "%27")) + '&invited_user_id=' + user_id);
1305		},
1306		error : function(jqXHR, text_status, errorThrown) {
1307			$.alert({content: 'error ' + text_status});
1308		}
1309	});
1310}
1311
1312function accept_chat_request(chat_room_id) {
1313	$.ajax({
1314		type: 'POST',
1315		url : '/click_to_chat/join_chat?chat_room_id=' + chat_room_id,
1316		success : function(json, text_status, jqXHR) {
1317			if (json.status) {
1318				hide_chat_alert();
1319				launch_chat('/click_to_chat/launch?chat_room_id=' + chat_room_id + '&chat_room_name=' + encodeURIComponent(json.user_name.replace(/'/g, "%27")));
1320			} else {
1321				$('#alerts .info p').html(chat_request_canceled_text);
1322				setTimeout(hide_chat_alert, 5000);
1323			}
1324		},
1325		error : function(jqXHR, text_status, errorThrown) {
1326			$.alert({content: 'error ' + text_status});
1327		}
1328	});
1329}
1330
1331function ignore_chat_request(chat_room_id) {
1332	hide_chat_alert();
1333	ajax_request('/click_to_chat/ignore?chat_room_id=' + chat_room_id);
1334}
1335
1336// chat
1337
1338function start_chat(chat_url, redirect_url) {
1339	if (is_mobile_app_mode()) {
1340		start_chat_app(chat_url, redirect_url);
1341	} else {
1342		launch_chat(chat_url);
1343	}
1344}
1345
1346function launch_chat(url) {
1347	var chatroom_id = create_chat(url);
1348
1349	$(window).on('click', function(event) {
1350		if (event.target.href) {
1351			$(window).off('unload beforeunload');
1352		}
1353	});
1354
1355	$(window).on('unload beforeunload', function(event) {
1356		ajax_request('/chat_room/leaving/' + chatroom_id);
1357	});
1358}
1359
1360function relaunch_chat(url) {
1361	launch_chat(url + '&event=relaunched');
1362}
1363
1364function create_chat(url) {
1365	var args = get_args(url);
1366	var chatroom_id = args['chat_room_id']; // should always be present
1367	var chatroom_name = (args['chat_room_name'] ? decodeURIComponent(args['chat_room_name']) : 'Chat');
1368	var invited_user_id = (args['invited_user_id'] || 'null');
1369
1370	var popout_link = '<a href="javascript:void(0)" onclick="pop_out_chat(\'' + url + '\')" class="popout"><i class="popout inverted"></i><span class="textOffScreen">Popout window</span></a>';
1371	var chatContainer = '<div id="chatContainer" chatroom_id="' + chatroom_id + '"><div class="header"><h4>' + chatroom_name.replace(/\+/g, " ").replace(/%27/g, "'") + '</h4>' + popout_link + '<a href="javascript:void(0)" onclick="close_chat(' + chatroom_id + ', ' + invited_user_id + ')" class="close"><i class="xCross inverted"></i><span class="textOffScreen">Close chat</span></a></div><div id="chatIframe"><iframe src="' + url + '"></iframe></div></div>';
1372
1373	if ($('#chatContainer').length > 0) {
1374		// different chat room already embedded
1375		window.open(url+'&event=popped_out&disable_popin=true', '_blank', 'height=611px,width=500px,toolbar=yes,directories=no,status=yes,menubar=no,scrollbars=yes,resizable=yes,modal=no');
1376	} else {
1377		// embed chat room in frame
1378		$('#contentWrap').append(chatContainer);
1379	}
1380
1381	return chatroom_id;
1382}
1383
1384function pop_out_chat(url) {
1385	url = (url.indexOf('?') > -1 ? url + '&event=popped_out' : url + '?event=popped_out');
1386	var childWindow = window.open(url, '_blank', 'height=611px,width=500px,toolbar=yes,directories=no,status=yes,menubar=no,scrollbars=yes,resizable=yes,modal=no');
1387	$('#chatContainer').remove();
1388}
1389
1390function pop_in_close() {
1391	// http://stackoverflow.com/questions/4458630/unable-to-unbind-the-window-beforeunload-event-in-jquery
1392	window.onbeforeunload = null; // suppress default call to close_chat()
1393	window.opener.launch_chat(window.location.href.replace('event=popped_out', 'event=popped_in'));
1394	window.close();
1395}
1396
1397function close_chat(chat_room_id, invited_user_id, multi) {
1398	$('#chatContainer').remove();
1399
1400	if (invited_user_id == null) {
1401		ajax_request('/chat_room/leaving/' + chat_room_id + (multi == null ? '' : '?multi=true'), {
1402			asynchronous : false
1403		});
1404	} else {
1405		ajax_request('/chat_room/leaving/' + chat_room_id + '?invited_user_id=' + invited_user_id + (multi == null ? '' : '&multi=true'), {
1406			asynchronous : false
1407		});
1408	}
1409}
1410
1411// user popups
1412
1413function over_user() {
1414	if (user_timer == null) {
1415		// pop up after one second
1416		user_href = $(this);
1417		user_timer = setTimeout(popup_user, 1000);
1418	}
1419}
1420
1421function clear_user_timer() {
1422	if (user_timer) {
1423		clearTimeout(user_timer);
1424		user_timer = null;
1425	}
1426}
1427
1428function popup_user() {
1429	if (user_href.attr('rel')) {
1430		return;
1431	}
1432
1433	// mark and cache
1434	user_href.attr('rel', 'popup');
1435
1436	// exiting title interferes with tooltip
1437	user_href.removeAttr('title');
1438
1439	// get user id
1440	var href = user_href.attr('href');
1441	var parts = href.split("/");
1442	var user_id = parts[3];
1443	var url = '/popup/user/' + user_id;
1444
1445	// fetch tooltip HTML
1446	var html;
1447
1448	$.ajax({
1449		url : url,
1450		async : false, // make this async?
1451		success : function(data) {
1452			html = data;
1453		}
1454	});
1455
1456	// attach tooltip
1457	var tool_tip = $(html);
1458
1459	// add after element
1460	user_href.after(tool_tip);
1461
1462	// can't use delay because it triggers AJAX before delay, not after
1463	user_href.tooltip({
1464		events : {
1465			def : 'mouseenter,mouseleave'
1466		},
1467		relative : true,
1468		position : user_href.offset().top < 200 || user_href.parents('.profileTable').length ? "bottom left" : "top left",
1469		effect : 'slide',
1470		delay: 1000 // one second
1471	});
1472
1473	if(user_href.offset().top < 200 || user_href.parents('.profileTable').length){
1474		user_href.siblings('.tooltip').addClass('tooltipBot');
1475	}
1476
1477	// attach facebox hook
1478	//tool_tip.find('a[rel*=facebox]').facebox();
1479	tool_tip.find('a[rel*=facebox]').each( function() {
1480		if(!$(this).hasClass("_processed")) {
1481			$(this).addClass("_processed").facebox();
1482		}
1483	});
1484
1485	if ($.browser.mozilla) {
1486		var triggerCount = 0;
1487
1488		user_href.mouseenter(function() {
1489			triggerCount++;
1490
1491			if (triggerCount == 1) {
1492				user_href.trigger('mouseenter');
1493			} else {
1494				triggerCount = 0;
1495			}
1496		});
1497
1498		user_href.mouseleave(function() {
1499			triggerCount++;
1500
1501			if (triggerCount == 1) {
1502				user_href.trigger('mouseleave');
1503			} else {
1504				triggerCount = 0;
1505			}
1506		});
1507	}
1508
1509	// need to retrigger event to show tooltip; tried tooltip.show() but this didn't work
1510	user_href.trigger('mouseenter');
1511}
1512
1513function out_user() {
1514	clear_user_timer();
1515}
1516
1517function send_popup_message(user_id) {
1518	var subject = get_value('subject');
1519	var content = get_value('content');
1520
1521	$.ajax({
1522		type : 'POST',
1523		url : '/popup/submit_message/' + user_id + '?subject=' + encodeURIComponent(subject) + '&content=' + encodeURIComponent(content),
1524		success : function(data) {
1525			$.facebox(data);
1526		}
1527	});
1528}
1529
1530function disable_user_popups() {
1531	disable_user_popups_flag = true;
1532}
1533
1534function disable_user_popups_in(container) {
1535	var user_hrefs = $(container + ' a[href^="/user/show/"]');
1536	user_hrefs.off('mouseover');
1537	user_hrefs.off('mouseout');
1538}
1539
1540function enable_user_popups() {
1541	if (disable_user_popups_flag) {
1542		return;
1543	}
1544
1545	var user_hrefs = $('a[href^="/user/show/"]');
1546
1547	user_hrefs.on('mouseover', over_user);
1548	user_hrefs.on('mouseout', out_user);
1549}
1550
1551// pop-ups
1552
1553function popup_clicked(element) {
1554	let url = $(element).attr('href');
1555	if (window.tinyMCE) url += (url.split('?')[1] ? '&' : '?') + 'editor_js_loaded=true';
1556
1557	// Store the trigger element and its href so focus can be restored when the popup closes.
1558	// The href is used as a selector to re-find the element after page_router AJAX navigation
1559	// replaces the DOM (e.g. after saving a to-do item).
1560	$._facebox_trigger = element;
1561	$._facebox_trigger_href = $(element).attr('href');
1562
1563	$.facebox({
1564		'ajax' : url
1565	});
1566
1567	return false;
1568}
1569
1570// Restore focus to the element that triggered the popup after it closes
1571$(document).on('afterClose.facebox', function() {
1572	var trigger = $._facebox_trigger;
1573	var href = $._facebox_trigger_href;
1574	$._facebox_trigger = null;
1575	$._facebox_trigger_href = null;
1576
1577	if (trigger) {
1578		// If the original element is still in the DOM, focus it directly
1579		if ($.contains(document, trigger)) {
1580			$(trigger).focus();
1581		} else if (href) {
1582			// Element was removed (e.g. page_router replaced the DOM after save).
1583			// Re-find it by href after the new content loads.
1584			$(window).one('loadcomplete', function() {
1585				var newTrigger = $('a[href="' + href + '"][aria-haspopup="true"]');
1586				if (newTrigger.length) {
1587					newTrigger.first().focus();
1588				}
1589			});
1590		}
1591	}
1592});
1593
1594function send_message_popup(element, form_id) {
1595	var selected_users = $('#' + form_id).find("input[name*='select[]']:checked");
1596	var select_all = $('#' + form_id).find("input[name*='select_all']");
1597	var user_ids = '';
1598  var filter = $('form input[name=filter]');
1599
1600	if (selected_users.length > 0 || select_all.length > 0) {
1601		if (select_all.length > 0) {
1602			user_ids += '&select_all=true';
1603
1604			if (filter.length > 0) {
1605        user_ids += '&filter=' + encodeURIComponent(filter.last().val());
1606      }
1607		} else {
1608			for (var i = 0; i < selected_users.length; i++) {
1609				user_ids += '&select[]=' + $(selected_users[i]).val();
1610			}
1611		}
1612		$.ajax({
1613			type: 'POST',
1614			url: $(element).attr('href'),
1615			data: user_ids,
1616			success: function(response) {
1617				$.facebox(response);
1618			},
1619			error: function(response) {
1620				$.alert({ content: response.responseText });
1621			}
1622		});
1623
1624	} else {
1625		$.alert({content: "No items were selected."});
1626	}
1627
1628	return false;
1629}
1630
1631function open_merge_popup(element, form_id) {
1632	var selected_users = $('#' + form_id).find("input[name*='select[]']:checked");
1633	var select_all = $('#' + form_id).find("input[name*='select_all']");
1634	var user_ids = '';
1635	var filter = $('form input[name=filter]');
1636
1637	if (selected_users.length > 0 || select_all.length > 0) {
1638		if (select_all.length > 0) {
1639			user_ids += '&select_all=true';
1640
1641			if (filter.length > 0) {
1642				user_ids += '&filter=' + encodeURIComponent(filter.last().val());
1643			}
1644		} else {
1645			for (var i = 0; i < selected_users.length; i++) {
1646				user_ids += '&select[]=' + $(selected_users[i]).val();
1647			}
1648		}
1649
1650		$.ajax({
1651			type: 'POST',
1652			url: $(element).attr('href'),
1653			data: user_ids,
1654			success: function(response) {
1655				$.facebox(response);
1656			},
1657			error: function(response) {
1658				$.alert({ content: response.responseText });
1659			}
1660		});
1661	} else {
1662		$.alert({content: no_items_selected});
1663	}
1664
1665	return false;
1666}
1667
1668// merge users popup: inline "add user" search + list management
1669
1670function merge_open_picker(btn) {
1671	merge_setup_picker_interceptor();
1672
1673	window.__merge_detail_url = $(btn).data('detail-url');
1674	window.__merge_picker_active = true;
1675
1676	// exclude users already in the merge list
1677	var url = $(btn).data('url');
1678	var excluded = $('#merge_users_form input[name="select[]"]').map(function() { return this.value; }).get();
1679	if (excluded.length) {
1680		url += (url.indexOf('?') === -1 ? '?' : '&') + 'excluded=' + encodeURIComponent(excluded.join(','));
1681	}
1682
1683	// open the people picker stacked over the merge popup.
1684	$.facebox.open({ ajax: url });
1685
1686	return false;
1687}
1688
1689// Intercept the people picker's "Select" button, but only while it was opened from
1690// the merge popup. Capture-phase + a flag so it beats the picker's own submit
1691// handler regardless of when filter.js loads, and so it never navigates the page.
1692function merge_setup_picker_interceptor() {
1693	if (window.__merge_picker_interceptor) { return; }
1694	window.__merge_picker_interceptor = true;
1695
1696	// Reset __merge_picker_active on every facebox close, not just the success path.
1697	if ($.facebox && $.facebox.close) {
1698		var __orig_facebox_close = $.facebox.close;
1699		$.facebox.close = function() {
1700			window.__merge_picker_active = false;
1701			return __orig_facebox_close.apply(this, arguments);
1702		};
1703	}
1704
1705	document.addEventListener('click', function(e) {
1706		if (!window.__merge_picker_active) { return; }
1707
1708		var target = e.target;
1709		var btn = (target && target.closest) ? target.closest('button[type="submit"]') : null;
1710		var picker = document.getElementById('people_picker');
1711
1712		if (!btn || !picker || !picker.contains(btn)) { return; }
1713
1714		e.preventDefault();
1715		e.stopImmediatePropagation();
1716
1717		var ids = ((typeof pp_obj !== 'undefined' && pp_obj.selected) || '').toString();
1718
1719		if (!ids) { $.alert({ content: $('#merge_users_table').data('addEmpty') || 'Select at least one user to add.' }); return; }
1720
1721		// fetch the picked users' details, append their rows to the merge popup
1722		// (still in the DOM under the picker), then close the picker
1723		$.getJSON(window.__merge_detail_url, { user_ids: ids.split(',') }, function(data) {
1724			var picked = (data && data.results) || [];
1725
1726			for (var i = 0; i < picked.length; i++) {
1727				var u = picked[i];
1728				merge_append_user_row({
1729					id: u.id,
1730					text: ((u.first_name || '') + ' ' + (u.last_name || '')).trim(),
1731					userid: u.userid
1732				});
1733			}
1734
1735			window.__merge_picker_active = false;
1736			$.facebox.close();
1737		}).fail(function() {
1738			// leave the picker open and __merge_picker_active true so a retry Select is
1739			// still intercepted (not handed to the picker's own navigating submit)
1740			$.alert({ content: $('#merge_users_table').data('addFailed') || 'Could not add the selected user(s). Please try again.' });
1741		});
1742	}, true);
1743}
1744
1745function merge_append_user_row(user) {
1746	if (!user || !user.id) { return; }
1747
1748	// skip if the user is already in the list
1749	if ($('#merge_users_form input[name="select[]"][value="' + user.id + '"]').length > 0) { return; }
1750
1751	var $row = $('<tr class="merge_user_row"></tr>');
1752
1753	var $keep = $('<td align="center"></td>');
1754	$('<input type="radio" name="keep_id">')
1755		.attr('value', user.id)
1756		.attr('id', 'merge_keep_' + user.id)
1757		.attr('aria-label', ($('#merge_users_table').data('accountToKeep') || 'Account to keep') + ': ' + user.text)
1758		.appendTo($keep);
1759	// platform hides the native radio and renders the control via "+ label:before"
1760	$('<label></label>').attr('for', 'merge_keep_' + user.id).appendTo($keep);
1761	$('<input type="hidden" name="select[]">').attr('value', user.id).appendTo($keep);
1762	$row.append($keep);
1763
1764	$row.append($('<td></td>').text(user.text));
1765	$row.append($('<td></td>').text(user.id));
1766	$row.append($('<td></td>').text(user.userid || ''));
1767
1768	var $remove = $('<td align="center"></td>');
1769	$('<a href="javascript:void(0);" class="merge_remove_user"><i class="delete"></i></a>')
1770		.attr('title', $('#merge_users_table').data('remove') || 'Remove')
1771		.attr('onclick', 'merge_remove_user(this); return false;')
1772		.appendTo($remove);
1773	$row.append($remove);
1774
1775	$('#merge_users_table tbody').append($row);
1776}
1777
1778function merge_remove_user(btn) {
1779	$(btn).closest('tr').remove();
1780
1781	// if the removed row held the "keep" selection, default to the first remaining row
1782	if ($('#merge_users_form input[name="keep_id"]:checked').length === 0) {
1783		$('#merge_users_table tbody tr:first input[name="keep_id"]').prop('checked', true);
1784	}
1785
1786	return false;
1787}
1788
1789function merge_continue(btn) {
1790	var rows = $('#merge_users_table tbody tr');
1791
1792	if (rows.length < 2) {
1793		$.alert({ content: $('#merge_users_table').data('minTwo') || 'Select at least two users to merge.' });
1794		return false;
1795	}
1796
1797	if ($('#merge_users_form input[name="keep_id"]:checked').length === 0) {
1798		$.alert({ content: $('#merge_users_table').data('selectKeep') || 'Select the account to keep.' });
1799		return false;
1800	}
1801
1802	$.confirm({
1803		content: $(btn).data('mergeConfirm'),
1804		confirm: function() {
1805			// Submit the form to MembersController#submit_merge, which enqueues the
1806			// completion-merge job and redirects back to the list with a flash notice.
1807			document.getElementById('merge_users_form').submit();
1808		}
1809	});
1810
1811	return false;
1812}
1813
1814function popup_clicked_mobile_app(href) {
1815	$.facebox({
1816		'ajax' : href
1817	});
1818}
1819
1820function popup_form(name, html, preprocess) {
1821	// cleanup duplicate popup forms in the new UI - just keep the last one
1822	var forms = $('form[id="' + name + '"]');
1823	if (forms.length > 1) {
1824		forms.each(function(index) {
1825			if (index < (forms.length - 1)) {
1826				$(this).parents('.popup').remove();
1827			}
1828		});
1829	}
1830
1831	tinyPop = true;
1832	if (html != null) {
1833		$('#' + name).submit(function() {
1834			var button = $(this).find('button');
1835			button.attr('disabled', '');
1836			tinyPop = false;
1837			$(this).ajaxSubmit({
1838				beforeSerialize : function() {
1839					popup_form_before_serialize(html);
1840				},
1841				success: function(data) {
1842					popup_form_ajax_success(data, preprocess) || button.prop('disabled', false);
1843				},
1844				error: function(){
1845					button.prop('disabled', false);
1846				}
1847			});
1848
1849			return false;
1850		});
1851	} else {
1852		$('#' + name).submit(function() {
1853			var button = $(this).find('button');
1854			button.attr('disabled', '');
1855			$(this).ajaxSubmit({
1856				success: function(data) {
1857					popup_form_ajax_success(data, preprocess) || button.prop('disabled', false);
1858				},
1859				error: function(){
1860					button.prop('disabled', false);
1861				}
1862			});
1863
1864			return false;
1865		});
1866	}
1867}
1868
1869function popup_form_ajax_success(data, preprocess){
1870	try {
1871		data = preprocess ? preprocess(data) : data;
1872		var json = jQuery.parseJSON(data);
1873		console.log("JSON", json);
1874		if (json.url.split('#')[0] == window.location.href.split('#')[0])
1875			location.reload();
1876	 	else{
1877
1878			 // we don't want any confirmations at that point
1879			if (typeof(tinymce) != 'undefined' && tinymce.activeEditor && $(document.body).hasClass('evo') && ($(document.body).find('.modal.is-open').find(tinymce.activeEditor.getElement()).length > 0))
1880				tinymce.activeEditor.setDirty(false);
1881
1882			window.location.href = json.url;
1883		}
1884
1885		return true;
1886
1887	} catch (e) {
1888		if( data )
1889			$.facebox(data);
1890		else
1891			$.facebox.close();
1892	}
1893}
1894
1895function resources_popup_form(name) {
1896	$('#' + name).submit(function() {
1897		var button = $(this).find('button');
1898		button.attr('disabled', '');
1899		var errors = [];
1900	  $('.tag-group-required').each(function(){
1901	    if($(this).val().length == 0){ errors.push($(this).attr('id')); }
1902	  });
1903	  if(errors.length > 0){
1904	  	$('#faceboxContent #alerts').html(tag_groups_error_string()).show();
1905	    $('#' + errors[0]).focus();
1906	  	button.prop('disabled', false);
1907	  }else{
1908		  	var form = $(this);
1909		    var copilot_check = form.find('#add_anchor');
1910		  	copilot_check.removeAttr('disabled');
1911			form.ajaxSubmit({
1912				success: function(data) {
1913					if( copilot_check.length && copilot_check.is(':checked') ){
1914						try {
1915							Excalibur.Ai.check_url(JSON.parse(data).url, true);
1916							$.facebox.close();
1917						}
1918						catch (e) {
1919							if( data )
1920								$.facebox(data);
1921							else
1922								$.facebox.close();
1923						}
1924					}
1925					else
1926						popup_form_ajax_success(data) || button.prop('disabled', false);
1927				},
1928				error: function(){
1929					button.prop('disabled', false);
1930				}
1931			});
1932	  }
1933
1934		return false;
1935	});
1936}
1937
1938function resources_html_popup_form(name, html, preprocess) {
1939	$('#' + name).submit(function() {
1940		var errors = [];
1941	  $('.tag-group-required').each(function(){
1942	    if($(this).val().length == 0){ errors.push($(this).attr('id')); }
1943	  });
1944	  if(errors.length > 0){
1945	  	$('#faceboxContent #alerts').html(tag_groups_error_string()).show();
1946	    $('#' + errors[0]).focus();
1947	  }else{
1948			var button = $(this).find('button');
1949			button.attr('disabled', '');
1950		    var form = $(this);
1951		    var copilot_check = form.find('#add_anchor');
1952		    copilot_check.removeAttr('disabled');
1953		    form.ajaxSubmit({
1954				beforeSerialize : function() {
1955					popup_form_before_serialize(html);
1956				},
1957				success: function(data) {
1958					if( copilot_check.length && copilot_check.is(':checked') ){
1959						try {
1960							Excalibur.Ai.check_url(JSON.parse(data).url, true);
1961							$.facebox.close();
1962						}
1963						catch (e) {
1964							if( data )
1965								$.facebox(data);
1966							else
1967								$.facebox.close();
1968						}
1969					}
1970					else
1971						popup_form_ajax_success(data, preprocess) || button.prop('disabled', false);
1972				},
1973				error: function(){
1974					button.prop('disabled', false);
1975				}
1976			});
1977		}
1978		return false;
1979	});
1980}
1981
1982function popup_form_before_serialize(html) {
1983	try {
1984		if (typeof(tinyMCE) != 'undefined'){
1985			html = html.replace('[', '_');
1986			html = html.replace(']', '');
1987
1988			function cleanHTML(string) {
1989				if (string) {
1990					string = string.replace('<!DOCTYPE html>','');
1991					string = string.replace('<html>','');
1992					string = string.replace('</html>','');
1993					string = string.replace('<head>','');
1994					string = string.replace('</head>','');
1995					string = string.replace('<body>','');
1996					string = string.replace('</body>','');
1997					string = string.replace(' class="_hovered"', '');
1998					string = string.replace(/^\s+|\s+$/g, '');
1999				}
2000
2001				return string;
2002			}
2003
2004			$('#' + html).html(cleanHTML(tinyMCE.activeEditor.getContent()));
2005		} else {
2006			var editor = FCKeditorAPI.GetInstance(html);
2007			html = html.replace('[', '\\[');
2008			html = html.replace(']', '\\]');
2009			$('#' + html).val(editor.GetHTML());
2010		}
2011	} catch(e) {
2012	}
2013}
2014
2015function tag_groups_error_string() {
2016	return '<div class="error alert_block" role="alert">
2016' +
2017	  		  '<div class="alert_flex">' +
2018	  		    '<div class="alert_icon">' +
2019	  		      '<i class="error inverted"></i>' +
2020	  		    '</div>' +
2021	  		    //TODO: translate
2022	  		    '<p>Please select the required tags.</p>' +
2023	  		  '</div>' +
2024	  		'</div>';
2025}
2026
2027// creating an alias so we don't change a lot of resources views
2028function popup_form_with_tag_groups(name) {
2029	resources_popup_form(name);
2030}
2031
2032// form_element should be a jQuery DOM object
2033function is_popup_form(form_element) {
2034	return form_element.closest('#faceboxContent').length > 0;
2035}
2036
2037// lessons
2038
2039function init_lessons(the_class_id, the_current_lesson_id, the_unhide_text, the_hide_text, the_confirm_text) {
2040	class_id = the_class_id;
2041	current_lesson_id = the_current_lesson_id;
2042	unhide_text = the_unhide_text;
2043	hide_text = the_hide_text;
2044	confirm_text = the_confirm_text;
2045}
2046
2047function show_section_adjustments(element) {
2048	$(element).find('> tbody').addClass('highlightLesson');
2049	$(element).find('.accordionLink').attr("aria-expanded", true);
2050    $(element).find('.accordionLink > span:nth-of-type(1)').attr('class','hide');
2051    $(element).find('.accordionLink > span:nth-of-type(2)').attr('class','');
2052
2053	if (is_mobile_device() || $(element).find('tr').hasClass('current_lesson')) {
2054		$(element).find('.modern_module_row ~ tr').show();
2055	} else {
2056		$(element).find('.modern_module_row ~ tr').show(400);
2057	}
2058}
2059
2060function hide_section_adjustments(element) {
2061	$(element).find('> tbody').removeClass('highlightLesson');
2062	$(element).find('.accordionLink').attr("aria-expanded", false);
2063	$(element).find('.accordionLink > span:nth-of-type(1)').attr('class','');
2064	$(element).find('.accordionLink > span:nth-of-type(2)').attr('class','hide');
2065	$(element).find('.modern_module_row ~ tr').hide();
2066}
2067
2068function teacher_show_sections(linkElement, showText, hideText, class_id) {
2069	$.ajax({
2070		url : '/teacher_lessons/show_sections/' + class_id,
2071		success: function(){
2072			$(linkElement).html('<i class="arrowUp"></i>'+hideText).attr('onclick', 'teacher_hide_sections(this, \''+showText+'\', \''+hideText+'\', '+class_id+')');
2073
2074			show_section_adjustments($('.instructor_module_view > table'));
2075			update_min_height();
2076		}
2077	});
2078}
2079
2080function teacher_hide_sections(linkElement, showText, hideText, class_id) {
2081	$.ajax({
2082		url : '/teacher_lessons/hide_sections/' + class_id,
2083		success: function() {
2084			$(linkElement).html('<i class="arrowDown"></i>'+showText).attr('onclick', 'teacher_show_sections(this, \''+showText+'\', \''+hideText+'\', '+class_id+')');
2085
2086			hide_section_adjustments($('.instructor_module_view > table'));
2087			show_section_adjustments($('.instructor_module_view > table tr.current_lesson').parent().parent());
2088			update_min_height();
2089		}
2090	});
2091}
2092
2093function student_show_sections(linkElement, showText, hideText, controller, class_id, child_id) {
2094	$.ajax({
2095		url : '/' + controller + '/show_sections/' + class_id + (child_id == null ? '' : '?child=' + child_id),
2096		success: function() {
2097			$(linkElement).html('<i class="arrowUp"></i>'+hideText).attr('onclick', 'student_hide_sections(this, \''+showText+'\', \''+hideText+'\', \''+controller+'\', '+class_id+', '+child_id+')');
2098
2099			show_section_adjustments($('.learner_module_view > table'));
2100			update_min_height();
2101		}
2102	});
2103}
2104
2105function student_hide_sections(linkElement, showText, hideText, controller, class_id, child_id) {
2106	$.ajax({
2107		url : '/' + controller + '/hide_sections/' + class_id + (child_id == null ? '' : '?child=' + child_id),
2108		success: function() {
2109			$(linkElement).html('<i class="arrowDown"></i>'+showText).attr('onclick', 'student_show_sections(this, \''+showText+'\', \''+hideText+'\', \''+controller+'\', '+class_id+', '+child_id+')');
2110
2111			hide_section_adjustments($('.learner_module_view > table'));
2112			show_section_adjustments($('.learner_module_view > table tr.current_lesson').parent().parent());
2113			update_min_height();
2114		}
2115	});
2116}
2117
2118function ta_show_sections(linkElement, showText, hideText, class_id) {
2119	$.ajax({
2120		url : '/teacher_lessons/show_sections/' + class_id,
2121		success: function() {
2122			$(linkElement).html('<i class="arrowUp"></i>'+hideText).attr('onclick', 'teacher_hide_sections(this, \''+showText+'\', \''+hideText+'\', '+class_id+')');
2123
2124			show_section_adjustments($('.instructor_module_view > table'));
2125			update_min_height();
2126		}
2127	});
2128}
2129
2130function ta_hide_sections(linkElement, showText, hideText, class_id) {
2131	$.ajax({
2132		url : '/teacher_lessons/hide_sections/' + class_id,
2133		success: function() {
2134			$(linkElement).html('<i class="arrowDown"></i>'+showText).attr('onclick', 'teacher_show_sections(this, \''+showText+'\', \''+hideText+'\', '+class_id+')');
2135
2136			hide_section_adjustments($('.instructor_module_view > table'));
2137			show_section_adjustments($('.instructor_module_view > table tr.current_lesson').parent().parent());
2138			update_min_height();
2139		}
2140	});
2141}
2142
2143// drag and drop
2144
2145function init_draggable_categories() {
2146	$("#category_list").sortable({
2147		handle : 'td.draggable_handle',
2148		update : function(event, ui) {
2149			var after = ui.item.index('.draggable') + 1;
2150			var category_id = ui.item.find(':input:first').val();
2151			window.location.href = '/class_catalog_categories/move/' + category_id + '?position=' + after;
2152		}
2153	});
2154
2155	$("#category_list").disableSelection();
2156}
2157
2158function init_draggable_categories_in_catalog() {
2159	var flex_height,
2160		tile_html;
2161
2162	$('.catalog_boxes.catalog_categories > div').mousedown(function(e) {
2163		flex_height = $(this).outerHeight();
2164		tile_html = $(this).html();
2165	});
2166
2167	$(".catalog_boxes.catalog_categories").sortable({
2168		revert: 300,
2169		containment: 'document',
2170		tolerance: 'pointer',
2171		handle : '.draggable_handle',
2172		placeholder: {
2173			// Added duplicated content so that the flex row stays the same height
2174			element: function() {
2175				return $('<div class="ui-sortable-placeholder" style="visibility:hidden">' + tile_html + '</div>');
2176			},
2177			update: function() {
2178
2179			}
2180		},
2181		create: function (e, ui) {
2182			$('.catalog_boxes.catalog_categories.ui-sortable').removeClass('no_flex').show();
2183
2184			// set width on container to fix last item in row glitch
2185			$('.hasRightColumn .catalog_boxes.catalog_categories.ui-sortable').css('width', $('.catalog_boxes.catalog_categories.ui-sortable').width());
2186		},
2187		start: function (e, ui) {
2188			// Set the height of ui-sortable-help so it doesn't change when removed from the flex flow
2189			ui.helper.css('height', flex_height);
2190		},
2191		update : function(event, ui) {
2192			var after = ui.item.index('.catalog_categories > .draggable') + 1;
2193			var category_id = ui.item.attr('id');
2194
2195			$.ajax({
2196				url : '/class_catalog_categories/move/' + category_id + '?position=' + after + '&catalog=true',
2197				async : false
2198			});
2199		}
2200	});
2201
2202	$(".catalog_boxes.catalog_categories").disableSelection();
2203}
2204
2205function init_draggable_items(category_id) {
2206	var flex_height,
2207		tile_html;
2208
2209	$('.catalog_boxes.catalog_courses > div').mousedown(function(e) {
2210		flex_height = $(this).outerHeight();
2211		tile_html = $(this).html();
2212	});
2213
2214	$(".catalog_boxes.catalog_courses").sortable({
2215		revert: 300,
2216		containment: 'document',
2217		tolerance: 'pointer',
2218		handle : '.draggable_handle',
2219		placeholder: {
2220			// Added duplicated content so that the flex row stays the same height
2221			element: function() {
2222				return $('<div class="ui-sortable-placeholder" style="visibility:hidden">' + tile_html + '</div>');
2223			},
2224			update: function() {
2225
2226			}
2227		},
2228		create: function (e, ui) {
2229			$('.catalog_boxes.catalog_courses.ui-sortable').removeClass('no_flex').show();
2230
2231			// set width on container to fix last item in row glitch
2232			$('.hasRightColumn .catalog_boxes.catalog_courses.ui-sortable').css('width', $('.catalog_boxes.catalog_courses.ui-sortable').width());
2233		},
2234		start: function (e, ui) {
2235			// Set the height of ui-sortable-help so it doesn't change when removed from the flex flow
2236			ui.helper.css('height', flex_height);
2237		},
2238		update : function(event, ui) {
2239			var after = ui.item.index('.catalog_courses > .draggable') + 1;
2240			var category_item_id = ui.item.attr('category_item_id');
2241
2242			$.ajax({
2243				url : '/class_catalog_categories/move_item?category_id=' + category_id + '&category_item_id=' + category_item_id + '&position=' + after,
2244				async : false
2245			});
2246		}
2247	});
2248
2249	$(".catalog_boxes.catalog_courses").disableSelection();
2250}
2251
2252function init_draggable_dashboard_items(selector, controller) {
2253    var flex_height,
2254      tile_html;
2255
2256    $(selector + ' > div').mousedown(function(e) {
2257        flex_height = $(this).outerHeight();
2258        tile_html = $(this).html();
2259    });
2260
2261    $(selector).sortable({
2262        revert: 300,
2263        containment: 'document',
2264        tolerance: 'pointer',
2265        handle : '.draggable_handle',
2266        placeholder: {
2267            // Added duplicated content so that the flex row stays the same height
2268            element: function() {
2269                return $('<div class="ui-sortable-placeholder" style="visibility:hidden">' + tile_html + '</div>');
2270            },
2271            update: function() {
2272
2273            }
2274        },
2275        create: function (e, ui) {
2276            $(selector + '.ui-sortable').removeClass('no_flex').show();
2277
2278            // set width on container to fix last item in row glitch
2279            $('.hasRightColumn ' + selector + '.ui-sortable').css('width', $(selector + '.ui-sortable').width());
2280        },
2281        start: function (e, ui) {
2282            // Set the height of ui-sortable-help so it doesn't change when removed from the flex flow
2283            ui.helper.css('height', flex_height);
2284        },
2285        update : function(event, ui) {
2286            var order = [];
2287            var position = 0;
2288
2289            $.each($(selector + ' > .draggable'), function(i, v) {
2290                var info = $(v).data('order').split('_');
2291                position++;
2292                order.push({position: position, id: info[1], type: info[0]})
2293            });
2294
2295            $.ajax({
2296                type: 'POST',
2297                url: '/' + controller + '/move',
2298                async: false,
2299                data: {order: JSON.stringify(order)},
2300                success: function(response) {
2301                    var options = $('.optionsRibbon.optionsRight.optionsRibbon_multi_ul');
2302
2303                    if (options.find('a.reset_order').length == 0) {
2304                        options.prepend('<ul><li><a href="/'+ controller +'/reset_order" excalibur-click="Excalibur.Router.load_left_column" title="' + reset_order_text + '" class="reset_order"><i class="refresh single"></i><span class="textOffScreen">' + reset_order_text + '</span></a></li></ul>');
2305                    }
2306                }
2307            });
2308        }
2309    });
2310
2311    $(".catalog_boxes.catalog_courses").disableSelection();
2312}
2313
2314
2315function init_draggable_lessons(class_id) {
2316	var row_height;
2317	$('.instructor_module_view table').mousedown(function(e) {
2318		row_height = $(this).outerHeight();
2319	});
2320
2321	$(".instructor_module_view").sortable({
2322		handle : '.draggable_handle',
2323		placeholder: {
2324			// Make the placeholder a different element so that it doesn't interfere with the :nth-child row coloring.
2325			element: function() {
2326				return $('<div class="ui-sortable-placeholder" style="visibility:hidden; height:' + row_height +'px"></div>');
2327			},
2328			update: function() {
2329
2330			}
2331		},
2332		update : function(event, ui) {
2333			var after = ui.item.index('.draggable') + 1;
2334			var lesson_id = ui.item.find(':input:first').val();
2335
2336			if (!lesson_id) {
2337				lesson_id = ui.item[0].id;
2338			}
2339
2340			$.ajax({
2341				url : '/teacher_lessons/move/' + class_id + '?lesson_id=' + lesson_id + '&position=' + after,
2342				async : false
2343			});
2344		}
2345	});
2346
2347	$(".instructor_module_view").disableSelection();
2348}
2349
2350function init_draggable_lessons_tiles(class_id) {
2351	var flex_height,
2352		tile_html,
2353		current_index;
2354	$('.lesson_boxes > div').mousedown(function(e) {
2355		flex_height = $(this).outerHeight();
2356		tile_html = $(this).html().replace(/<a/g, '<div').replace(/<\/a>/g, '</div>');
2357		current_index = $(this).parent().find('.imgCrop .current').closest('.draggable').index() + 1;
2358	});
2359
2360	$(".lesson_boxes").sortable({
2361		revert: 300,
2362		containment: 'document',
2363		tolerance: 'pointer',
2364		handle : '.draggable_handle',
2365		placeholder: {
2366			// Added duplicated content so that the flex row stays the same height
2367			element: function() {
2368				return $('<a class="ui-sortable-placeholder" style="visibility:hidden;">' + tile_html + '</a>');
2369			},
2370			update: function() {
2371
2372			}
2373		},
2374		create: function (e, ui) {
2375			$('.lesson_boxes.ui-sortable').removeClass('no_flex').show();
2376
2377			// set width on container to fix last item in row glitch
2378			$('.hasRightColumn .lesson_boxes.ui-sortable').css('width', $('.lesson_boxes.ui-sortable').width());
2379		},
2380		start: function (e, ui) {
2381			// Set the height of ui-sortable-help so it doesn't change when removed from the flex flow
2382			ui.helper.css('height', flex_height);
2383		},
2384		update : function(event, ui) {
2385			var after = ui.item.index('.lesson_boxes > .draggable') + 1;
2386			var lesson_id = ui.item.find(':input:first').val();
2387
2388			if (!lesson_id) {
2389				lesson_id = ui.item[0].id;
2390			}
2391
2392			var current_code = $('.lesson_boxes .imgCrop .current').clone();
2393			$('.lesson_boxes .imgCrop .current').remove();
2394			$('.lesson_boxes > div:nth-child(' + current_index + ') .imgCrop').prepend( current_code );
2395
2396			$.ajax({
2397				url : '/teacher_lessons/move/' + class_id + '?lesson_id=' + lesson_id + '&position=' + after,
2398				async : false
2399			});
2400		}
2401	});
2402
2403	$(".lesson_boxes").disableSelection();
2404
2405	checkbox_highlight_tiles('.lesson_boxes');
2406}
2407
2408function checkbox_highlight_tiles(container){
2409	$(container + ' :checkbox').change(function(){
2410		if($(this).is(':checked')){
2411			$(this).closest(container + ' > *').addClass('highlight');
2412		}else{
2413			$(this).closest(container + ' > *').removeClass('highlight');
2414		}
2415	});
2416}
2417
2418function init_draggable_goals(path_id) {
2419  var row_height;
2420
2421  $('.goal_list table').mousedown(function(e) {
2422    row_height = $(this).outerHeight();
2423  });
2424
2425  $(".goal_list").sortable({
2426    handle : '.draggable_handle',
2427    placeholder: {
2428      // Make the placeholder a different element so that it doesn't interfere with the :nth-child row coloring.
2429      element: function() {
2430        return $('<div class="ui-sortable-placeholder" style="visibility:hidden; height:' + row_height +'px"></div>');
2431      },
2432      update: function() {
2433
2434      }
2435    },
2436		update : function(event, ui) {
2437			var after = ui.item.index('.draggable') + 1;
2438			var goal_id = ui.item.find(':input:first').val().replace("check_", "");
2439
2440      $($('.goal_list h2 span span')).each( function(index) {
2441        $(this).text(index + 1);
2442      });
2443
2444			$.ajax({
2445				url : '/path_admin_goals/move/' + path_id + '?goal_id=' + goal_id + '&position=' + after,
2446				async : false
2447			});
2448		}
2449	});
2450
2451  $(".goal_list").disableSelection();
2452}
2453
2454function init_draggable_bundle_items(bundle_id) {
2455    var row_height;
2456
2457    $('.goal_list table').mousedown(function(e) {
2458        row_height = $(this).outerHeight();
2459	});
2460
2461    $(".goal_list").sortable({
2462        handle : '.draggable_handle',
2463        placeholder: {
2464            // Make the placeholder a different element so that it doesn't interfere with the :nth-child row coloring.
2465            element: function() {
2466                return $('<div class="ui-sortable-placeholder" style="visibility:hidden; height:' + row_height +'px"></div>');
2467            },
2468            update: function() {
2469
2470            }
2471        },
2472        update : function(event, ui) {
2473            var after = ui.item.index('.draggable') + 1;
2474            var item_id = ui.item.find(':input:first').val().replace("check_", "");
2475
2476            $($('.goal_list h2 span span')).each( function(index) {
2477                $(this).text(index + 1);
2478            });
2479
2480            $.ajax({
2481                url : '/bundle/move/' + bundle_id + '?item_id=' + item_id + '&position=' + after,
2482                async : false
2483            });
2484        }
2485    });
2486
2487    $(".goal_list").disableSelection();
2488}
2489
2490function init_draggable_subscription_items(subscription_id) {
2491    var row_height;
2492
2493    $('.goal_list table').mousedown(function(e) {
2494        row_height = $(this).outerHeight();
2495	});
2496
2497    $(".goal_list").sortable({
2498        handle : '.draggable_handle',
2499        placeholder: {
2500            // Make the placeholder a different element so that it doesn't interfere with the :nth-child row coloring.
2501            element: function() {
2502                return $('<div class="ui-sortable-placeholder" style="visibility:hidden; height:' + row_height +'px"></div>');
2503            },
2504            update: function() {
2505
2506            }
2507        },
2508        update : function(event, ui) {
2509            var after = ui.item.index('.draggable') + 1;
2510            var item_id = ui.item.find(':input:first').val().replace("check_", "");
2511
2512            $($('.goal_list h2 span span')).each( function(index) {
2513                $(this).text(index + 1);
2514            });
2515
2516            $.ajax({
2517                url : '/subscription/move/' + subscription_id + '?item_id=' + item_id + '&position=' + after,
2518                async : false
2519            });
2520        }
2521    });
2522
2523    $(".goal_list").disableSelection();
2524}
2525
2526function init_draggable_sections(class_id, lesson_id) {
2527	$('#section_list').sortable({
2528		handle : 'td.draggable_section_handle',
2529		update : function(event, ui) {
2530			var after = ui.item.index('.draggable') + 1;
2531			var section_id = ui.item.find(':input:first').val();
2532
2533			$.ajax({
2534				url : '/teacher_section/move/' + class_id + '?lesson_id=' + lesson_id + '&section_id=' + section_id + '&position=' + after,
2535				async : false
2536			});
2537		}
2538	});
2539
2540	$('#section_list').disableSelection();
2541}
2542
2543function init_draggable_levels(controller_path, game_id, id) {
2544	$('#levels_list').sortable({
2545		handle : 'td.draggable_level_handle',
2546		update : function(event, ui) {
2547			let after = ui.item.index('.draggable') + 1;
2548			let level_id = ui.item.data('level');
2549			let url = '/' + controller_path + '/move_level';
2550			if(id) {
2551				url += '/' + id;
2552			}
2553			url += '?game=' + game_id + '&level_id=' + level_id + '&position=' + after,
2554			$.ajax({
2555				url : url,
2556				async : false
2557			});
2558		}
2559	});
2560
2561	$('#section_list').disableSelection();
2562}
2563
2564function init_draggable_questions(url, question_bank_id) {
2565    $("#question_list_" + question_bank_id).sortable({
2566		handle : 'td.draggable_handle',
2567		update : function(event, ui) {
2568            var after = ui.item.index('.drag_list_' + question_bank_id) + 1;
2569			var question_id = ui.item.find(':input:first').val();
2570
2571			$.ajax({
2572                url: url + '?question_bank_id=' + question_bank_id + '&question_id=' + question_id + '&position=' + after,
2573				async : false
2574			});
2575		}
2576	});
2577
2578	$("#question_list").disableSelection();
2579}
2580
2581function init_draggable_question_banks(url) {
2582    $("#question_bank_list").sortable({
2583        handle: 'td.draggable_handle',
2584        update: function (event, ui) {
2585            var question_bank_id = ui.item.data('id');
2586            var after = ui.item.index('.drag_bank_list') + 1;
2587            window.location = url + '?question_bank_id=' + question_bank_id + '&position=' + after;
2588        }
2589    });
2590
2591    $("#question_bank_list").disableSelection();
2592}
2593
2594function init_draggable_checkboxes(url, section_id) {
2595	$("#checkbox_list_" + section_id).sortable({
2596	handle : 'td.draggable_handle',
2597	update : function(event, ui) {
2598					var after = ui.item.index('.drag_list_' + section_id) + 1;
2599					var checkbox_id = ui.item.find(':input:first').val();
2600
2601		$.ajax({
2602							url: url + '&section_id=' + section_id + '&checkbox_id=' + checkbox_id + '&position=' + after,
2603			async : false
2604		});
2605	}
2606});
2607
2608$("#checkbox_list").disableSelection();
2609}
2610
2611function init_draggable_resources() {
2612	$("#resource_list").sortable({
2613		handle : 'td.draggable_handle',
2614		start : function(event, ui) {
2615			ui.item.data('before_block', resource_block_index(ui.item[0]));
2616		},
2617		update : function(event, ui) {
2618			save_resource_position(ui.item, resource_row_position(ui.item));
2619			move_resource_blocks(ui.item.data('before_block'), resource_block_index(ui.item[0]));
2620			redo_resource_move_states();
2621		}
2622	});
2623
2624	$("#resource_list").disableSelection();
2625
2626	init_resource_move_controls();
2627}
2628
2629function resource_rows() {
2630	return $('#resource_list tr.draggable');
2631}
2632
2633function resource_row_position(row) {
2634	return resource_rows().index(row) + 1;
2635}
2636
2637// One save in flight at a time. insert_at reads the old position, shuffles the rows in
2638// between, then writes, with no transaction and no row lock (vendor/gems/acts_as_list
2639// .../list.rb:435), and #move does not wrap it either - so two overlapping saves read the
2640// same old_position, both shuffle, and can leave two rows sharing a position. Nothing
2641// errors when that happens, which is what makes it worth preventing on the client.
2642//
2643// Nothing is dispatched on unload for the same reason: anything sent then necessarily
2644// races the request already in flight, and a corrupt list is worse than a move that did
2645// not save. So a press made and then navigated away from within one round trip is lost.
2646// Closing that needs a transaction and a row lock in #move, which is a server change
2647// across every init_draggable_* caller and its own ticket.
2648//
2649// Deliberately not held on #resource_list: the router swaps the centre column out from
2650// under an in-flight save, and a queue tied to the table would strand its own tail. A
2651// window property rather than a top-level declaration, which a double include would
2652// throw on (see widgets.js).
2653function resource_move_queue() {
2654	window.resource_move_state = window.resource_move_state || { pending : [], sending : false };
2655
2656	return window.resource_move_state;
2657}
2658
2659function send_next_resource_position() {
2660	const queue = resource_move_queue();
2661
2662	if (queue.sending || !queue.pending.length) {
2663		return;
2664	}
2665
2666	// Off the queue at dispatch rather than at completion, so nothing can observe it as
2667	// still pending and send it a second time.
2668	const url = queue.pending.shift();
2669
2670	queue.sending = true;
2671
2672	$.ajax({ url : url }).fail(function() {
2673		// The order on screen is no longer the stored one, so re-read it rather
2674		// than leave the user looking at a move that did not save.
2675		window.location.reload();
2676	}).always(function() {
2677		queue.sending = false;
2678		send_next_resource_position();
2679	});
2680}
2681
2682function save_resource_position(row, position) {
2683	const url = $('#resource_list').data('move-url');
2684
2685	// insert_at reads the old position, shuffles the rows in between, then writes, with
2686	// no transaction and no row lock (vendor/gems/acts_as_list .../list.rb:435). Presses
2687	// are quick enough to overlap, and two saves in flight can interleave against a stale
2688	// read and store an order that is not the one on screen - silently, since neither
2689	// request errors. Send them one at a time, in press order.
2690	resource_move_queue().pending.push(
2691		url + ((url.indexOf('?') == -1) ? '?' : '&') +
2692		'resource_id=' + row.find(':input:first').val() + '&position=' + position
2693	);
2694
2695	send_next_resource_position();
2696}
2697
2698
2699// The #resource_<n> content blocks below the table are numbered over non-folder
2700// resources only, so a row's block is the count of non-folder rows up to it. A folder
2701// row owns no block and returns 0: returning the running count would name the block of
2702// the nearest resource above it, which move_resource_blocks would then move instead.
2703function resource_block_index(row) {
2704	const rows = resource_rows().toArray();
2705	let index = 0;
2706
2707	for (let i = 0; i < rows.length; i++) {
2708		const has_block = ($(rows[i]).find('a[href^="#resource_"]').length > 0);
2709
2710		if (has_block) {
2711			index++;
2712		}
2713
2714		if (rows[i] === row) {
2715			return has_block ? index : 0;
2716		}
2717	}
2718
2719	return 0;
2720}
2721
2722function move_resource_blocks(before, after) {
2723	if (!before || !after || (before == after)) {
2724		return;
2725	}
2726
2727	const moved = $('#resource_' + before)[0];
2728	const target = $('#resource_' + after)[0];
2729
2730	if (!moved || !target) {
2731		return;
2732	}
2733
2734	// Native move: .html() and the jQuery insert methods re-execute the block's <script src>.
2735	target.parentNode.insertBefore(moved, (after > before) ? target.nextSibling : target);
2736
2737	// The ids encode position, so renumber them for the next move.
2738	$(moved).parent().children('div[id^="resource_"]').each(function(index) {
2739		this.id = 'resource_' + (index + 1);
2740	});
2741}
2742
2743function redo_resource_move_states() {
2744	const rows = resource_rows();
2745
2746	rows.each(function(index) {
2747		$(this).find('.resource_move_up').attr('aria-disabled', (index === 0));
2748		$(this).find('.resource_move_down').attr('aria-disabled', (index === (rows.length - 1)));
2749	});
2750}
2751
2752function resource_move_announcer() {
2753	let announcer = $('#resource-move-announcer');
2754
2755	if (!announcer.length) {
2756		// Lives on body: the router replaces the centre column wholesale, which would
2757		// destroy a region rendered inside the table.
2758		announcer = $('<div id="resource-move-announcer" class="sr-only" role="status" aria-live="polite"></div>').appendTo('body');
2759	}
2760
2761	return announcer;
2762}
2763
2764function announce_resource_move(row, position) {
2765	const list = $('#resource_list');
2766	const name = row.find('a').first().text().replace(/\s+/g, ' ').trim();
2767	const text = name + ': ' + list.data('position-label') + ' ' + position + ' ' +
2768	             list.data('of-label') + ' ' + resource_rows().length;
2769	const announcer = resource_move_announcer();
2770
2771	setTimeout(function() { announcer.text(text); }, 0);
2772}
2773
2774function move_resource(el, direction) {
2775	if ($(el).attr('aria-disabled') == 'true') {
2776		return;
2777	}
2778
2779	const row = $(el).closest('tr');
2780	const sibling = (direction == 'up') ? row.prev('tr') : row.next('tr');
2781
2782	if (!sibling.length) {
2783		return;
2784	}
2785
2786	const before_block = resource_block_index(row[0]);
2787
2788	if (direction == 'up') {
2789		row.insertBefore(sibling);
2790	} else {
2791		row.insertAfter(sibling);
2792	}
2793
2794	const position = resource_row_position(row);
2795
2796	save_resource_position(row, position);
2797	move_resource_blocks(before_block, resource_block_index(row[0]));
2798	redo_resource_move_states();
2799	announce_resource_move(row, position);
2800
2801	el.focus(); // the DOM move blurs it, and repeated moves need it back
2802}
2803
2804function init_resource_move_controls() {
2805	// The controls render under the high contrast theme only, so elsewhere there is
2806	// nothing to bind and no reason to leave a live region on the page.
2807	if (!$('#resource_list .resource_move').length) {
2808		return;
2809	}
2810
2811	resource_move_announcer(); // must pre-exist the first move or that move is not announced
2812
2813	// Delegated and namespaced: the router re-renders the table and init runs again with it.
2814	$(document).off('click.resource_move').on('click.resource_move', '#resource_list .resource_move', function() {
2815		move_resource(this, $(this).hasClass('resource_move_up') ? 'up' : 'down');
2816	});
2817}
2818
2819function init_draggable_slides(id) {
2820	$("#slide_list").sortable({
2821		handle : 'td.draggable_handle',
2822		update : function(event, ui) {
2823			var after = ui.item.index('#slide_list .draggable') + 1;
2824			var slide_id = ui.item.find(':input:first').val();
2825      var url = '/portal_slide/move/' + slide_id + '?portal_id=' + id + '&position=' + after;
2826
2827			$.ajax({
2828				url : url,
2829				async : false
2830			});
2831		}
2832	});
2833
2834	$("#slide_list").disableSelection();
2835}
2836
2837function init_draggable_panels(id) {
2838  $("#panel_list").sortable({
2839    handle : 'td.draggable_handle',
2840    update : function(event, ui) {
2841      var after = ui.item.index('#panel_list .draggable') + 1;
2842      var panel_id = ui.item.find(':input:first').val();
2843      var url = '/portal_panel/move/' + panel_id + '?portal_id=' + id + '&position=' + after;
2844
2845      $.ajax({
2846        url : url,
2847        async : false
2848      });
2849    }
2850  });
2851
2852  $("#panel_list").disableSelection();
2853}
2854
2855function init_draggable_menu_items(id) {
2856	$("#menu_list").sortable({
2857		handle : 'td.draggable_handle',
2858		update : function(event, ui) {
2859			var after = ui.item.index('#menu_list .draggable') + 1;
2860			var menu_id = ui.item.find(':input:first').val();
2861			var url = '/portal_menu/move/' + menu_id + '?portal_id=' + id + '&position=' + after;
2862
2863			$.ajax({
2864				url : url,
2865				async : false
2866			});
2867		}
2868	});
2869
2870	$("#menu_list").disableSelection();
2871}
2872
2873function init_draggable_footer_items(id) {
2874	$("#footer_list").sortable({
2875		handle : 'td.draggable_handle',
2876		update : function(event, ui) {
2877			var after = ui.item.index('#footer_list .draggable') + 1;
2878			var footer_id = ui.item.find(':input:first').val();
2879			var url = '/portal_footer/move/' + footer_id + '?portal_id=' + id + '&position=' + after;
2880
2881      $.ajax({
2882				url : url,
2883				async : false
2884			});
2885		}
2886	});
2887
2888	$("#footer_list").disableSelection();
2889}
2890
2891function init_draggable_boxes(name, the_id, controller) {
2892	var tbody_id = "#" + name + "_list";
2893
2894	$(tbody_id).sortable({
2895		handle : 'td.draggable_handle',
2896		update : function(event, ui) {
2897			var after = ui.item.index(tbody_id + ' .draggable') + 1;
2898			var box_id = ui.item.find(':input:first').val();
2899
2900			$.ajax({
2901				url : '/' + controller + '/move/' + the_id + '?box_id=' + box_id + '&position=' + after,
2902				async : false
2903			});
2904		}
2905	});
2906
2907	$(tbody_id).disableSelection();
2908}
2909
2910function init_draggable_policy_documents(controller) {
2911	$("#policy_documents_list").sortable({
2912		handle : 'td.draggable_handle',
2913		update : function(event, ui) {
2914			var after = ui.item.index('#policy_documents_list .draggable') + 1;
2915			var policy_document_id = ui.item.find(':input:first').val();
2916
2917			$.ajax({
2918				url : '/' + controller + '/move/' + policy_document_id + '?position=' + after,
2919				async : false
2920			});
2921		}
2922	});
2923
2924	$("#shortcuts_list").disableSelection();
2925}
2926
2927function init_draggable_invoice_templates(controller) {
2928	$("#invoice_templates_list").sortable({
2929		handle : 'td.draggable_handle',
2930		update : function(event, ui) {
2931			var after = ui.item.index('#invoice_templates_list .draggable') + 1;
2932			var invoice_template_id = ui.item.find(':input:first').val();
2933
2934			$.ajax({
2935				url : '/' + controller + '/move/' + invoice_template_id + '?position=' + after,
2936				async : false
2937			});
2938		}
2939	});
2940
2941	$("#shortcuts_list").disableSelection();
2942}
2943
2944function init_draggable_shortcuts() {
2945	$("#shortcuts_list").sortable({
2946		handle : 'td.draggable_handle',
2947		update : function(event, ui) {
2948			var after = ui.item.index('#shortcuts_list .draggable') + 1;
2949			var shortcut_id = ui.item.find(':input:first').val();
2950
2951			$.ajax({
2952				url : '/shortcuts/move/' + shortcut_id + '?position=' + after,
2953				async : false
2954			});
2955		}
2956	});
2957
2958	$("#shortcuts_list").disableSelection();
2959}
2960
2961function init_draggable_footers() {
2962	$("#footers_list").sortable({
2963		handle : 'td.draggable_handle',
2964		update : function(event, ui) {
2965			var after = ui.item.index('#footers_list .draggable') + 1;
2966			var picture_id = ui.item.find(':input:first').val();
2967
2968			$.ajax({
2969				url : '/footers/move/' + picture_id + '?position=' + after,
2970				async : false
2971			});
2972		}
2973	});
2974
2975	$("#footers_list").disableSelection();
2976}
2977
2978function init_draggable_tiers() {
2979	$("#tier_list").sortable({
2980		handle : 'td.draggable_handle',
2981		update : function(event, ui) {
2982			var after = ui.item.index('.draggable') + 1;
2983			var tier_id = ui.item.find(':input:first').val();
2984			$.get('/subscription_tiers/move/' + tier_id + '?position=' + after);
2985		}
2986	});
2987
2988	$("#category_list").disableSelection();
2989}
2990
2991function init_draggable_quiz_items() {
2992	var in_dropzone = false;
2993
2994	$('.quiz_match_choice').draggable({
2995        containment: '.leftColumn',
2996		start: function(event, ui) {
2997			$(this).attr('aria-grabbed','true');
2998			$('.quiz_match_dropzone').attr('aria-dropeffect','move');
2999
3000			$('.quiz_match_table').addClass('quiz_match_highlight');
3001		},
3002		stop: function(event, ui) {
3003			$(this).attr('aria-grabbed','false');
3004			$('.quiz_match_dropzone').attr('aria-dropeffect','none');
3005
3006			$('.quiz_match_table').removeClass('quiz_match_highlight');
3007			if (!in_dropzone) {
3008				$(this).appendTo($('.quiz_match_choices'));
3009                var answer_total = 0;
3010                $('.quiz_match_dropzone input').each(function(){
3011                    answer_total += parseInt($(this).val());
3012                });
3013                if(answer_total == parseInt($(this).data('index'))){
3014                    $('.quiz_match_dropzone input').removeAttr('name');
3015                }
3016			}
3017			$(this).removeAttr('style');
3018			//refresh answers
3019			$('.quiz_match_dropzone').each(function(index){
3020				if($(this).find('.quiz_match_choice').length == 0){
3021					$(this).find('input').val(0);
3022				}
3023			});
3024		}
3025	});
3026
3027	$('.quiz_match_dropzone').droppable({
3028		tolerance: 'pointer',
3029		over: function(event, ui) {
3030			$(this).addClass('quiz_match_over');
3031		},
3032		out: function(event, ui) {
3033			in_dropzone = false;
3034			$(this).removeClass('quiz_match_over');
3035		},
3036		drop: function(event, ui) {
3037			in_dropzone = true;
3038			$(this).removeClass('quiz_match_over');
3039			$(this).find('.quiz_match_choice').appendTo($('.quiz_match_choices'));
3040			ui.draggable.appendTo($(this)).removeAttr('style');
3041			$(this).find('input').val(ui.draggable.data('index'));
3042			$('.quiz_match_dropzone input').each(function(){
3043				$(this).attr('name', $(this).data('name'));
3044			});
3045		}
3046	});
3047
3048	if($('.quiz_match_choices > div').length > 0){
3049		// randomize choices in the front end
3050		var $quiz_match_choices = document.getElementsByClassName('quiz_match_choices')[0];
3051		for (var i = $quiz_match_choices.children.length; i >= 0; i--) {
3052			$quiz_match_choices.appendChild($quiz_match_choices.children[Math.random() * i | 0]);
3053		}
3054	}
3055
3056	// show chices after they are randomized
3057	$('.quiz_match_choices > div').show();
3058
3059	$('.quiz_match_choices').droppable({
3060		tolerance: 'pointer',
3061		over: function(event, ui) {
3062			$('.quiz_match_choices').addClass('quiz_match_over');
3063		},
3064		out: function(event, ui) {
3065			$('.quiz_match_choices').removeClass('quiz_match_over');
3066		},
3067		drop: function(event, ui) {
3068			$('.quiz_match_choices').removeClass('quiz_match_over');
3069		}
3070	});
3071
3072	$(document).keydown(
3073		function(e) {
3074			// When within .quiz_match
3075			if ($(':focus').closest('.quiz_match').length > 0) {
3076
3077				// Right / Down arrow
3078				if (e.keyCode == 39 || e.keyCode == 40) {
3079					if ($('.tabbable').index($(':focus')) + 1 == $('.tabbable').length) {
3080						$('.tabbable').eq(0).focus();
3081					} else {
3082						$('.tabbable').eq($('.tabbable').index($(':focus')) + 1).focus();
3083					}
3084				}
3085
3086				// Up / Left arrow
3087				if (e.keyCode == 37 || e.keyCode == 38) {
3088					$('.tabbable').eq($('.tabbable').index($(':focus')) - 1).focus();
3089				}
3090
3091				// Space bar / Enter
3092				if(e.which == 32 || e.keyCode == 13) {
3093
3094					if ($(':focus').hasClass('quiz_match_choice')) {
3095						// Selected a choice
3096
3097						$('.quiz_match_table').addClass('quiz_match_highlight'); // add class to table
3098						$('.quiz_match_dropzone').attr('aria-dropeffect','move'); // highlight portential dropzones
3099
3100						// Make empty dropzones tabbable
3101						$(".quiz_match_dropzone").each(function(index) {
3102							if ($(this).children().length == 0) {
3103								$(this).addClass('tabbable').attr('tabindex',0);
3104							}
3105						});
3106
3107						if ($(':focus').parent().hasClass('quiz_match_dropzone')) {
3108							// If selecting a choice inside a dropzone
3109
3110							$(':focus').parent().removeClass('tabbable').attr('tabindex',null); // prevent tab to this choice's dropzone
3111
3112							if ($('.ui-draggable-dragging').length > 0) {
3113								// If already dragging a choice
3114								// Add in selected dropzone
3115								$('.ui-draggable-dragging').appendTo($(':focus').parent());
3116								$(':focus').appendTo($('.quiz_match_choices'));
3117								// Highlight the first option in the options holder
3118								$('.quiz_match_choices > div:first-child').focus();
3119								remove_quiz_match_highlight();
3120							} else {
3121								// If not dragging a choice
3122
3123								$('.quiz_match_choices').attr('aria-dropeffect','move').addClass('tabbable').attr('tabindex',0);
3124								$(':focus').attr('aria-grabbed','true').addClass('ui-draggable-dragging');
3125							}
3126
3127						} else {
3128							// If selecting a choice in choices div
3129
3130							if ($('.ui-draggable-dragging').length > 0) {
3131								// If already dragging a choice
3132								// Insert after selected choice
3133								$('.ui-draggable-dragging').insertAfter($(':focus'));
3134								// Highlight focussed item
3135								$('.ui-draggable-dragging').focus();
3136								remove_quiz_match_highlight();
3137							} else {
3138								// If not dragging a choice
3139
3140								$('.quiz_match_choice').attr('aria-grabbed','false').removeClass('ui-draggable-dragging'); // remove any drag classes
3141								$(':focus').attr('aria-grabbed','true').addClass('ui-draggable-dragging'); // add new drag class
3142							}
3143						}
3144
3145					} else if ($(':focus').hasClass('quiz_match_dropzone')) {
3146						// Selected a dropzone
3147
3148						if ($(':focus > div').length == 0) {
3149							in_dropzone = true;
3150							$('.ui-draggable-dragging').appendTo($(':focus')); // append choice to the dropzone
3151
3152							if ($('.quiz_match_choices > div').length != 0) {
3153								// Highlight the first option in the options holder
3154								$('.quiz_match_choices > div:first-child').focus();
3155							} else {
3156								// Highlight the current option
3157								$('.ui-draggable-dragging').focus();
3158							}
3159						}
3160						remove_quiz_match_highlight();
3161
3162					} else if ($(':focus').hasClass('quiz_match_choices')) {
3163						// Select the choices div
3164
3165						$('.ui-draggable-dragging').appendTo($('.quiz_match_choices'));
3166						$('.quiz_match_choices > div:first-child').focus();
3167						remove_quiz_match_highlight();
3168					}
3169
3170				}
3171
3172				function remove_quiz_match_highlight() {
3173					$('.ui-draggable-dragging').attr('aria-grabbed','false').removeClass('ui-draggable-dragging');
3174					$('div[aria-dropeffect="move"]').attr('aria-dropeffect','none');
3175					$('.quiz_match_table').removeClass('quiz_match_highlight');
3176					$('.quiz_match_choices, .quiz_match_dropzone').removeClass('tabbable').attr('tabindex',null);
3177				}
3178
3179			}
3180		}
3181	);
3182}
3183
3184function set_carousel_speed(panel_id, select, portal_id) {
3185  $.ajax({
3186    url : '/carousel_panel/set_speed/' + panel_id + '?portal_id=' + portal_id + '&value=' + select.value,
3187    async : false
3188	});
3189}
3190
3191// libraries
3192
3193function update_libraries(url, return_url) {
3194	var checkboxes = $('input.library_checkbox');
3195	var file_search = $('#file-search');
3196	var name = $('input#compact_filter_phrase').length ? $('input#compact_filter_phrase') : file_search;
3197	var person = $('input#users');
3198
3199	for (var i = 0; i < checkboxes.length; i += 1) {
3200		var checkbox = checkboxes[i];
3201
3202		if (checkbox.checked) {
3203			url += '&' + checkbox.name + '=true';
3204		}
3205	}
3206
3207	var users_filter = $('#users_filter');
3208
3209	if (users_filter.length > 0) {
3210		url += '&users[]=' + users_filter.val();
3211	}
3212
3213	if( Excalibur.File_explorer.override_view_type ){
3214		url += '&view_type=' + Excalibur.File_explorer.override_view_type;
3215	}
3216
3217	var subject_filter = $('#subject_filter');
3218
3219	if (subject_filter.length > 0) {
3220		url += '&subject=' + subject_filter.val();
3221	}
3222
3223	var classification_filter = $('#classification_filter');
3224
3225	if (classification_filter.length > 0) {
3226	  if (resources_file_formats.includes(classification_filter.val())) {
3227      url += '&format=' + classification_filter.val();
3228    } else {
3229      url += '&classification=' + classification_filter.val();
3230    }
3231	}
3232	var filter_bar = $('.type-filter-bar');
3233	if( filter_bar.length ){
3234		if( filter_bar.find('> div[type].selected').length )
3235			url += '&format=' + filter_bar.find('> div[type].selected').attr('type');
3236		else if( filter_bar.find('div li[type].selected').length )
3237			url += '&classification=' + filter_bar.find('div li[type].selected').attr('type');
3238	}
3239
3240	var filter_bar = $('.type-filter-bar');
3241	if( filter_bar.length ){
3242		if( filter_bar.find('> div[type].selected').length )
3243			url += '&format=' + filter_bar.find('> div[type].selected').attr('type');
3244		else if( filter_bar.find('div li[type].selected').length )
3245			url += '&classification=' + filter_bar.find('div li[type].selected').attr('type');
3246	}
3247
3248	if (name.val() != '') {
3249		url += '&name=' + encodeURIComponent(name.val());
3250	}
3251
3252	if ((person.length > 0) && (person.val().trim() != '')) {
3253		url += '&users=' + encodeURIComponent(person.val().trim());
3254	}
3255
3256	url += '&filter_active=true';
3257
3258	var sort_url = $('th .asc, th .desc').attr('href');
3259
3260	if (typeof sort_url != 'undefined' && sort_url.length > 0){
3261		sort_val = get_param_from_url(sort_url, 'sort');
3262		if (typeof sort_val != 'undefined' && sort_val.length > 0) {
3263			sort_val = (sort_val.indexOf('-') !== -1 ) ? sort_val.replace('-', '') 
3263: (sort_val + '-');
3264			url += '&sort=' + sort_val
3265		}
3266	} else {
3267		sort_val = get_param_from_url(window.location.href, 'sort');
3268		if (typeof sort_val != 'undefined' && sort_val.length > 0) {
3269			url += '&sort=' + sort_val
3270		}
3271	}
3272
3273	url = update_library_tag_groups_url(url);
3274
3275	if( file_search.length ){
3276		if(return_url)
3277			return url;
3278		else
3279			Excalibur.Router.load(url, '.file-explorer');
3280	}
3281	else
3282		window.location.href = url;
3283}
3284
3285function update_library_tag_groups_url(url) {
3286	if($('.library_tag_group').length > 0){
3287		var tag_ids = [];
3288		$('.library_tag_group').each(function(){
3289			if($(this).val().length > 0){
3290				tag_ids.push($(this).val());
3291			}
3292		});
3293
3294		var tags_query = 'tags=' + tag_ids.join(',');
3295		url = decodeURIComponent(url);
3296
3297		if (url.indexOf('?') == -1) {
3298			url = url + '?from_form=true&' + tags_query;
3299		} else if(url.indexOf('tags=') > -1) {
3300			url = url.replace(/tags=[0-9,]{0,}/i, tags_query);
3301			if(tag_ids.length == 0) {
3302				url = url.replace('tags=', '');
3303			}
3304		} else {
3305			url = url + '&' + tags_query;
3306		}
3307	}
3308
3309	return url;
3310}
3311
3312function update_library_tag_groups() {
3313	var url = window.location.href;
3314	url = update_library_tag_groups_url(url);
3315	window.location.href = url;
3316}
3317
3318// policy documents
3319
3320function set_policy_document_enabled(controller, policy_document_id, checkbox) {
3321	ajax_request('/' + controller + '/set_enabled/' + policy_document_id + '?value=' + check_s(checkbox));
3322}
3323
3324// help desk
3325
3326function set_help_desk_org_restriction(checkbox) {
3327	ajax_request('/help_desk_configure/set_organization_restriction?value=' + check_s(checkbox));
3328}
3329
3330// URL parameter parsing
3331
3332function get_args(url) {
3333	var args = [];
3334	var question = url.indexOf('?');
3335
3336	if (question != -1) {
3337		var params = url.substring(question + 1).split('&');
3338
3339		for (var i = 0; i < params.length; i++) {
3340			var pair = params[i].split('=');
3341			args[pair[0]] = pair[1];
3342		}
3343	}
3344
3345	return args;
3346}
3347
3348// configure sync
3349
3350function sync_now(el, sync_type, org_id) {
3351  var el = $(el);
3352  var query = '?return_controller=' + sync_type;
3353
3354  var users_radio = $('input[name="sync[users_from]"]:checked');
3355  var sections_radio = $('input[name="sync[sections_from]"]:checked');
3356
3357  if (users_radio.length > 0) {
3358    query = query + '&users=' + users_radio.val();
3359  }
3360
3361  if (sections_radio.length > 0) {
3362    //if (query.length == 0) {
3363    //  query = query + '?';
3364    // } else {
3365    //   query = query + '&';
3366    //}
3367
3368    query = query + '&sections=' + sections_radio.val();
3369  }
3370
3371  if (org_id !== undefined){
3372	  query = query + '&org_id=' + org_id;
3373  }
3374
3375  window.location = '/sis/sync' + query;
3376}
3377
3378function one_roster_sync_now(el, sync_type, org_id) {
3379	var el = $(el);
3380	var query = '?return_controller=' + sync_type;
3381
3382	var users_radio = $('input[name="sync[users_from]"]:checked');
3383	var sections_radio = $('input[name="sync[sections_from]"]:checked');
3384
3385	if (users_radio.length > 0) {
3386		query = query + '&users=' + users_radio.val();
3387	}
3388
3389	if (sections_radio.length > 0) {
3390		query = query + '&sections=' + sections_radio.val();
3391	}
3392
3393	if (org_id !== undefined){
3394		query = query + '&org_id=' + org_id;
3395	}
3396
3397	window.location = '/one_roster/sync' + query;
3398}
3399
3400function sync_organization_now(el, sync_type, org_id) {
3401  var el = $(el);
3402  var query = '?return_controller=' + sync_type;
3403
3404  var users_radio = $('input[name="sync[users_from]"]:checked');
3405  var sections_radio = $('input[name="sync[sections_from]"]:checked');
3406
3407  if (users_radio.length > 0) {
3408    query = query + '&users=' + users_radio.val();
3409  }
3410
3411  if (sections_radio.length > 0) {
3412    query = query + '&sections=' + sections_radio.val();
3413  }
3414
3415  if (org_id !== undefined){
3416	  query = query + '&org_id=' + org_id;
3417  }
3418
3419  window.location = '/sis/sync_organization' + query;
3420}
3421
3422function new_sync_now(el, c, args) {
3423	var el = $(el);
3424	var autoCommitCheckBox= document.getElementById("auto_commit");
3425	var bypassCommitThresholdCheckBox= document.getElementById("bypass_commit_threshold");
3426	var checks = $('#sis_schools input[type="checkbox"]:checked').map(function() {
3427		return $(this).val();
3428	}).get()
3429
3430	query = '?auto_commit=' + autoCommitCheckBox.checked + '&bypass_commit_threshold=' + bypassCommitThresholdCheckBox.checked + '&schools=' +checks;
3431	window.location = '/one_roster/' + args + query;
3432}
3433
3434function csv_sync_schools(el, c, id) {
3435  let users_radio = $('input[name="sync[users_from]"]:checked');
3436  let sections_radio = $('input[name="sync[sections_from]"]:checked');
3437  let checkBox = document.getElementById("auto_commit");
3438
3439  query = '?auto_commit=' + checkBox.checked;
3440
3441  if (id !== -1) {
3442    query = query + '&schools=' + id;
3443  } else {
3444    let checks = $('#sis_schools tbody input[type="checkbox"]:checked').map(function() {
3445      return $(this).val();
3446    }).get();
3447
3448    query = query + '&schools=' + checks;
3449  }
3450
3451  if (users_radio.length > 0) {
3452    query = query + '&users=' + users_radio.val();
3453  }
3454
3455  if (sections_radio.length > 0) {
3456    query = query + '&sections=' + sections_radio.val();
3457  }
3458
3459  window.location = '/csv_sis/prepare_schools' + query;
3460}
3461
3462function sync_setting(checkbox, id, attribute) {
3463	ajax_request('/sis/update_setting/' + id + '?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false'));
3464}
3465
3466function sync_other_settings(element, id, attribute) {
3467  ajax_request('/sis/update_setting/' + id + '?attribute=' + attribute + '&value=' + element.value);
3468}
3469
3470function sync_organization_setting(checkbox, id, attribute) {
3471	ajax_request('/sis/update_organization_setting/' + id + '?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false'));
3472}
3473
3474function sync_organization_other_settings(element, id, attribute) {
3475  ajax_request('/sis/update_organization_setting/' + id + '?attribute=' + attribute + '&value=' + element.value);
3476}
3477
3478function sync_sso_activate(select, id) {
3479  $.confirm({
3480    confirm: function() {
3481      ajax_request('/clever_sso/update/' + id + '?clever_enabled=' + select.value);
3482    },
3483    cancel: function() {
3484      if (select.value == 'true') {
3485        select.value = 'false';
3486      } else {
3487        select.value = 'true';
3488      }
3489    }
3490  });
3491}
3492
3493function sync_auto_activate(select, id) {
3494  $.confirm({
3495    confirm: function() {
3496      ajax_request('/sis/set_auto_sync/' + id + '?sis_auto_sync=' + select.value);
3497    },
3498    cancel: function() {
3499      if (select.value == 'true') {
3500        select.value = 'false';
3501      } else {
3502        select.value = 'true';
3503      }
3504    }
3505  });
3506}
3507
3508function sync_organization_auto_activate(select, id) {
3509  $.confirm({
3510    confirm: function() {
3511      ajax_request('/sis/set_organization_auto_sync/' + id + '?sis_auto_sync=' + select.value);
3512    },
3513    cancel: function() {
3514      if (select.value === 'true') {
3515        select.value = 'false';
3516      } else {
3517        select.value = 'true';
3518      }
3519    }
3520  });
3521}
3522
3523function sync_check_for_ids(id) {
3524	$('a.start-onboarding').on('click', function(){
3525		var interval = setInterval(function(){
3526			$.ajax({
3527				type: "POST",
3528				url: "/clever/check_if_district_is_set",
3529				data: {id: id},
3530				dataType: "json",
3531				success: function(data) {
3532					console.log(data);
3533
3534					if (data.status == 'success') {
3535						clearInterval(interval);
3536						window.location = '/clever';
3537					}
3538				}
3539			});
3540		}, 2500);
3541	});
3542}
3543
3544function one_roster_execute_query() {
3545	var query = $("#console").val();
3546
3547	$('#QueryResultsWrapper').html('<h2>Please wait...</h2>');
3548
3549	$.get('/one_roster/execute_query', {query: query, ajax_request: true}, function(html) {
3550		$('#QueryResultsWrapper').html(html);
3551		to_load();
3552	});
3553}
3554
3555// waitlist approval
3556
3557function update_waitlist_approval(class_id, radio_button) {
3558	window.location.href = '/class_configure/set_waitlist_approval/' + class_id + '?value=' + radio_button.value;
3559}
3560
3561// update access
3562
3563function update_visibility(url, radio_button) {
3564	window.location.href = url + (url.includes('?') ? '&' : '?') + 'value=' + radio_button.value;
3565}
3566
3567function update_locking(url, radio_button) {
3568	window.location.href = url + (url.includes('?') ? '&' : '?') + 'value=' + radio_button.value;
3569}
3570
3571// configure account
3572
3573function account_setting(checkbox, attribute, refresh) {
3574	if (refresh) {
3575		$.post('/account/set_attribute?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false'), function() {
3576			stash_settings_focus(checkbox);
3577			location.reload();
3578		})
3579	} else {
3580		ajax_request('/account/set_attribute?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false'));
3581	}
3582}
3583
3584// WCAG 3.2.2 (On Input): stash the changed control's id before the reload so restore_settings_focus() can return keyboard focus to it afterward.
3585// Timestamped because the reload is not guaranteed: a failed POST or an abandoned navigation would otherwise leave the id behind to steal focus on a later unrelated page load.
3586
3587function stash_settings_focus(el) {
3588	if (el && el.id) {
3589		try { sessionStorage.setItem('settings_refocus_id', JSON.stringify({id: el.id, at: Date.now()}));
3590		} catch (e) {
3591			console.error('stash_settings_focus: sessionStorage unavailable', e);
3592		}
3593	}
3594}
3595
3596function restore_settings_focus() {
3597	const max_age_ms = 10000;
3598
3599	let raw;
3600	try { raw = sessionStorage.getItem('settings_refocus_id');
3601	} catch (e) {
3602		console.error('restore_settings_focus: sessionStorage unavailable', e);
3603		return;
3604	}
3605
3606	if (!raw) return;
3607
3608	try { sessionStorage.removeItem('settings_refocus_id');
3609	} catch (e) {
3610		console.error('restore_settings_focus: could not clear stashed id', e);
3611	}
3612
3613	let stash;
3614	try { stash = JSON.parse(raw);
3615	} catch (e) {
3616		console.error('restore_settings_focus: could not parse stashed value', e);
3617		return;
3618	}
3619
3620	if (!stash || !stash.id) return;
3621
3622	// ignore a stash whose reload never happened
3623	if ((Date.now() - stash.at) > max_age_ms) return;
3624
3625	const el = document.getElementById(stash.id);
3626	if (el && typeof el.focus === 'function') el.focus();
3627}
3628
3629// high contrast theme toggle
3630
3631function high_contrast_theme_toggle() {
3632	var current_state = $('link[title="theme"]').attr('href').includes('high_contrast');
3633	var new_value = !current_state;
3634	
3635	account_setting({checked: new_value}, 'use_accessible_theme', true);
3636}
3637
3638// configure privacy setting
3639
3640function privacy_setting(checkbox, attribute, refresh) {
3641	if (refresh) {
3642		$.post('/profile_privacy/set_attribute?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false'), function() {
3643			location.reload();
3644		})
3645	} else {
3646		ajax_request('/profile_privacy/set_attribute?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false'));
3647	}
3648}
3649
3650function set_top_tab(radio) {
3651	stash_settings_focus(radio);
3652	window.location.href = '/account/set_top_tab?value=' + encodeURIComponent(radio.value);
3653}
3654
3655// mini-navigation
3656
3657function language_setting(dropdown) {
3658	window.location.href = '/account/set_language?value=' + encodeURIComponent(dropdown.value);
3659}
3660
3661function time_zone_setting(dropdown) {
3662	ajax_request('/account/set_time_zone?value=' + encodeURIComponent(dropdown.value));
3663}
3664
3665function set_user_session_timeout(dropdown) {
3666	window.location.href = '/account/set_session_timeout?value=' + dropdown.value;
3667}
3668
3669function google_docs_setting(checkbox) {
3670	if (checkbox.checked) {
3671		window.location.href = '/google_docs_configure/enable';
3672	} else {
3673		window.location.href = '/google_docs_configure/disable';
3674	}
3675}
3676
3677function infinite_scroll(container, callback) {
3678	$(container).scroll(function(e) {
3679		if (e.target.scrollTop >= (e.target.scrollHeight - e.target.clientHeight)) {
3680			callback();
3681			$(container).unbind('scroll');
3682		}
3683	});
3684}
3685
3686function set_unsubscribed_from_newsletter(checkbox) {
3687	ajax_request('/account/set_unsubscribed_from_newsletter?value=' + (checkbox.checked ? 'false' : 'true'));
3688}
3689
3690function google_drive_docs_activation_checkbox(el) {
3691  if (el.checked == true) {
3692    var wi = window.open('/google_drive/enable', 'Google Drive Authorization', 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=no, copyhistory=no, width=600, height=750');
3693
3694    check_google_drive_docs_activation(wi);
3695  } else {
3696    $.confirm({
3697      content : 'Are you sure you want to deactivate Google Drive?',
3698      confirm : function() {
3699        $.ajax({
3700          type : "POST",
3701          url : "/google_drive/disable",
3702          dataType : "json",
3703          success : function(json) {
3704            if (json.status == 'ok') {
3705              location.reload();
3706            } else if (json.status == 'bad') {
3707              $.alert({
3708                content : 'Couldn\'t disable Google Drive.'
3709              });
3710            } else {
3711              $.alert({
3712                content : 'Something went wrong.'
3713              });
3714            }
3715          }
3716        });
3717      }
3718    });
3719  }
3720}
3721
3722function google_drive_docs_activation(auto_open_add_popup = true) {
3723  var wi = window.open('/google_drive/enable', 'Google Drive Authorization', 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=no, copyhistory=no, width=600, height=750');
3724  check_google_drive_docs_activation(wi, auto_open_add_popup ? 'auto' : null);
3725}
3726
3727function check_google_drive_docs_activation(wi, type){
3728  var counter = 0;
3729
3730  var interval = setInterval(function(){
3731    $.ajax({
3732      type: "POST",
3733      url: "/google_drive/check_activation",
3734      dataType: "json",
3735      async: false,
3736      success: function(json){
3737        if (json.status == 'ok') {
3738          if (type == 'auto') {
3739            $.facebox({'ajax':'/google_docs/add'});
3740            clearInterval(interval);
3741          } else {
3742            location.reload();
3743          }
3744        }
3745      }
3746    });
3747
3748    counter++;
3749
3750    if (counter == 40) {
3751      wi.close();
3752      clearInterval(interval);
3753
3754      $.alert({content: 'The process took too long!'});
3755    }
3756  }, 2000);
3757}
3758
3759function google_drive_docs_disable() {
3760  $.ajax({
3761    type: "POST",
3762    url: "/google_drive/disable",
3763    dataType: "json",
3764    success: function(json) {
3765      if (json.status == 'ok') {
3766        google_drive_enable();
3767      } else if (json.status == 'bad') {
3768        $.alert({content: 'Couldn\'t disable Google Drive.'});
3769      } else {
3770        $.alert({content: 'Something went wrong.'});
3771      }
3772    }
3773  });
3774}
3775
3776function onedrive_activation_checkbox(el, business) {
3777  if (business && (business == true)) {
3778    var controller = 'one_drive_business';
3779    var service = 'OneDrive for Business';
3780  } else {
3781    var controller = 'one_drive';
3782    var service = 'OneDrive';
3783  }
3784
3785  if (el.checked == true) {
3786    var wi = window.open('/' + controller + '/enable', service + ' Authorization', 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=no, copyhistory=no, width=600, height=750');
3787
3788    check_onedrive_activation(wi, el, business);
3789  } else {
3790    $.confirm({
3791      content : 'Are you sure you want to deactivate ' + service + '?',
3792      cancel: function() {
3793        $(el).attr('checked', true);
3794      },
3795      confirm : function() {
3796        $.ajax({
3797          type : "POST",
3798          url : "/" + controller + "/disable",
3799          dataType : "json",
3800          success : function(json) {
3801            if (json.status == 'ok') {
3802              location.reload();
3803            } else if (json.status == 'bad') {
3804              $(el).attr('checked', false);
3805
3806              $.alert({
3807                content : 'Couldn\'t disable ' + service + '.'
3808              });
3809            } else {
3810              $(el).attr('checked', false);
3811
3812              $.alert({
3813                content : 'Something went wrong.'
3814              });
3815            }
3816          }
3817        });
3818      }
3819    });
3820  }
3821}
3822
3823function check_onedrive_activation(wi, el, business){
3824  if (business && (business == true)) {
3825    var controller = 'one_drive_business';
3826  } else {
3827    var controller = 'one_drive';
3828  }
3829
3830  var counter = 0;
3831
3832  var interval = setInterval(function(){
3833    $.ajax({
3834      type: "POST",
3835      url: "/" + controller + "/check_activation",
3836      dataType: "json",
3837      async: false,
3838      success: function(json){
3839        if (json.status == 'ok') {
3840          location.reload();
3841        } else {
3842          $(el).attr('checked', false);
3843        }
3844      }
3845    });
3846
3847    counter++;
3848
3849    if (counter == 40) {
3850      wi.close();
3851      clearInterval(interval);
3852
3853      $(el).attr('checked', false);
3854      $.alert({content: 'The process took too long!'});
3855    }
3856  }, 2000);
3857}
3858
3859function google_meet_access(iframe) {
3860  var wi = window.open('/google_meet/authorize', 'Google Meet Authorization', 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=no, copyhistory=no, width=600, height=750');
3861  check_google_meet_access(wi, iframe);
3862}
3863
3864function google_meet_access_checkbox(el) {
3865  if (el.checked == true) {
3866    var wi = window.open('/google_meet/authorize', 'Google Meet Authorization', 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=no, copyhistory=no, width=600, height=750');
3867    check_google_meet_access(wi, window);
3868  } else {
3869    $.confirm({
3870      content : 'Are you sure you want to deactivate Google Meet?',
3871      confirm : function() {
3872        $.ajax({
3873          type : "POST",
3874          url : "/google_meet/disable",
3875          dataType : "json",
3876          success : function(json) {
3877            if (json.status == 'ok') {
3878              location.reload();
3879            } else if (json.status == 'bad') {
3880              $.alert({
3881                content : 'Couldn\'t disable Google Meet.'
3882              });
3883            } else {
3884              $.alert({
3885                content : 'Something went wrong.'
3886              });
3887            }
3888          }
3889        });
3890      }
3891    });
3892  }
3893}
3894
3895function check_google_meet_access(wi, iframe){
3896  var counter = 0;
3897
3898  var interval = setInterval(function(){
3899    $.ajax({
3900      type: "POST",
3901      url: "/google_meet/check_activation",
3902      dataType: "json",
3903      async: false,
3904      success: function(json){
3905        if (json.status == 'ok') {
3906          wi.close();
3907          clearInterval(interval);
3908          iframe.location.reload();
3909        }
3910      }
3911    });
3912
3913    counter++;
3914
3915    if (counter == 50) {
3916      wi.close();
3917      clearInterval(interval);
3918
3919      $.alert({content: 'The process took too long!'});
3920    }
3921  }, 2000);
3922}
3923
3924// configure catalog
3925
3926function configure_catalog(attribute, invert, checkbox) {
3927	var value = ( invert ? !checkbox.checked : checkbox.checked);
3928	ajax_request('/class_catalogs_configure/set_attribute?attribute=' + attribute + '&value=' + (value == true ? 'true' : 'false'));
3929}
3930
3931// class catalog
3932
3933function jump_to_class(controller, dropdown) {
3934	if (dropdown.value && (dropdown.value != 0)) {
3935		window.location.href = '/' + controller + '/show/' + dropdown.value;
3936	}
3937}
3938
3939// pop-ups
3940
3941function update_home_popup(value) {
3942	ajax_request('/home/display_popup?value=' + (value ? 'true' : 'false'), {asynchronous : false});
3943}
3944
3945function update_ui_popup(value) {
3946	ajax_request('/home/display_ui_popup?value=' + (value ? 'true' : 'false'), {asynchronous : false});
3947}
3948
3949function update_teacher_popup(class_id, value) {
3950	ajax_request('/teacher_class/display_popup/' + class_id + '?value=' + (value ? 'true' : 'false'), {asynchronous : false});
3951}
3952
3953function update_student_popup(class_id, value) {
3954	ajax_request('/student_class/display_popup/' + class_id + '?value=' + (value ? 'true' : 'false'), {asynchronous : false});
3955}
3956
3957// configure attribute
3958
3959function configure_attribute(attribute, controller, object_id, checkbox) {
3960  ajax_request('/' + controller + '/set_attribute/' + object_id + '?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false'));
3961}
3962
3963function configure_attribute_and_refresh(attribute, controller, object_id, checkbox, from) {
3964	window.location.href = '/' + controller + '/set_attribute_and_refresh/' + object_id + '?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false') + '&from=' + from;
3965}
3966
3967// configure compliance
3968
3969function configure_compliance(controller, object_id, checkbox) {
3970  window.location.href = '/' + controller + '/set_required_for_compliance/' + object_id + '?value=' + (checkbox.checked ? 'true' : 'false');
3971}
3972
3973// configure class
3974
3975function configure_class(attribute, class_id, checkbox) {
3976	ajax_request('/class_configure/set_attribute/' + class_id + '?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false'));
3977}
3978
3979function configure_class_and_refresh(attribute, class_id, checkbox, from) {
3980	window.location.href = '/class_configure/set_attribute_and_refresh/' + class_id + '?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false') + '&from=' + from;
3981}
3982
3983function configure_enable_lessons_grid_view(class_id, checkbox) {
3984	window.location.href = '/class_configure/enable_lessons_grid_view/' + class_id + '?value=' + (checkbox.checked ? 'true' : 'false');
3985}
3986
3987function configure_enable_lessons_row_view(class_id, checkbox) {
3988	window.location.href = '/class_configure/enable_lessons_row_view/' + class_id + '?value=' + (checkbox.checked ? 'true' : 'false');
3989}
3990
3991function configure_class_inverted(attribute, class_id, checkbox) {
3992	ajax_request('/class_configure/set_attribute/' + class_id + '?
3992attribute=' + attribute + '&value=' + (checkbox.checked ? 'false' : 'true'));
3993}
3994
3995function configure_site_wide_restriction(controller, the_id, game_id, checkbox, from) {
3996	ajax_request('/' + controller + '/set_only_for_site_wide/' + the_id + '?game=' + game_id + '&value=' + (checkbox.checked ? 'true' : 'false') + '&from=' + encodeURIComponent(from));
3997}
3998
3999function configure_game_enabled(controller, the_id, game_id, checkbox, from) {
4000	ajax_request('/' + controller + '/set_enabled/' + the_id + '?game=' + game_id + '&value=' + (checkbox.checked ? 'true' : 'false') + '&from=' + encodeURIComponent(from));
4001}
4002
4003function configure_game(controller, the_id, attribute, game_id, checkbox) {
4004	ajax_request('/' + controller + '/set_attribute/' + the_id + '?game=' + game_id + '&attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false'));
4005}
4006
4007function configure_leaderboard(controller, the_id, game_id, checkbox, from) {
4008	window.location.href = '/' + controller + '/set_leaderboard/' + the_id + '?game=' + game_id + '&value=' + (checkbox.checked ? 'true' : 'false') + '&from=' + encodeURIComponent(from);
4009}
4010
4011function configure_game_teams(controller, the_id, game_id, checkbox, from) {
4012	window.location.href = '/' + controller + '/set_support_teams/' + the_id + '?game=' + game_id + '&value=' + (checkbox.checked ? 'true' : 'false') + '&from=' + encodeURIComponent(from);
4013}
4014
4015function set_student_top_tab(class_id, radio_button) {
4016    ajax_request('/class_configure/set_student_top_tab/' + class_id + '?attribute=' + radio_button.value);
4017}
4018
4019function set_teacher_top_tab(class_id, radio_button) {
4020    ajax_request('/class_configure/set_teacher_top_tab/' + class_id + '?attribute=' + radio_button.value);
4021}
4022
4023function set_path_tile_display(class_id, radio_button) {
4024	ajax_request('/class_configure/set_path_tile_display/' + class_id + '?attribute=' + radio_button.value);
4025}
4026
4027function configure_open_enrollment(class_id, checkbox) {
4028	ajax_request('/class_configure/set_open_enrollment/' + class_id + '?value=' + (checkbox.checked ? 'true' : 'false'));
4029}
4030
4031function configure_reenrollment(class_id, checkbox, reload) {
4032	var url = '/class_configure/set_reenrollment/' + class_id + '?value=' + (checkbox.checked ? 'true' : 'false');
4033	if (reload) {
4034		window.location.href = url;
4035	} else {
4036		ajax_request(url);
4037	}
4038}
4039
4040function configure_repurchase(class_id, checkbox) {
4041	ajax_request('/class_configure/set_repurchase/' + class_id + '?value=' + (checkbox.checked ? 'true' : 'false'));
4042}
4043
4044function configure_enable_grades(class_id, checkbox) {
4045	window.location.href = '/class_configure/set_enable_grades/' + class_id + '?value=' + (checkbox.checked ? 'true' : 'false');
4046}
4047
4048function configure_enable_grade_map(class_id, checkbox) {
4049	window.location.href = '/class_configure/set_enable_grade_map/' + class_id + '?value=' + (checkbox.checked ? 'true' : 'false');
4050}
4051
4052function configure_enable_rubrics(class_id, checkbox) {
4053	window.location.href = '/class_configure/set_enable_rubrics/' + class_id + '?value=' + (checkbox.checked ? 'true' : 'false');
4054}
4055
4056function set_class_default_grade_release(class_id, value) {
4057  ajax_request('/class_configure/set_default_grade_release/' + class_id + '?value=' + value);
4058}
4059
4060function set_class_rubric_points_ordering(class_id, value) {
4061	ajax_request('/class_configure/set_rubric_points_ordering/' + class_id + '?value=' + value);
4062}
4063
4064function configure_enable_student_posts(class_id, checkbox) {
4065	window.location.href = '/class_configure/set_enable_student_posts/' + class_id + '?value=' + (checkbox.checked ? 'true' : 'false');
4066}
4067
4068function set_class_announcement_comments(class_id, checkbox) {
4069  ajax_request('/class_configure/set_announcement_comments/' + class_id + '?value=' + (checkbox.checked ? 'true' : 'false'));
4070}
4071
4072function set_weight_using_categories(class_id, checkbox) {
4073	window.location.href = '/class_configure/set_weight_using_categories/' + class_id + '?value=' + (checkbox.checked ? 'true' : 'false');
4074}
4075
4076function configure_weighting(class_id, scheme) {
4077	ajax_request('/class_configure/set_weighting/' + class_id + '?value=' + scheme);
4078}
4079
4080function configure_lessons_in_order(class_id, checkbox) {
4081	ajax_request('/class_configure/set_lessons_in_order/' + class_id + '?value=' + (checkbox.checked ? 'true' : 'false'));
4082}
4083
4084function configure_sections_in_order(class_id, checkbox) {
4085	ajax_request('/class_configure/set_sections_in_order/' + class_id + '?value=' + (checkbox.checked ? 'true' : 'false'));
4086}
4087
4088function configure_auto_complete_on_visit(class_id, checkbox) {
4089	ajax_request('/class_configure/set_auto_complete_on_visit/' + class_id + '?value=' + (checkbox.checked ? 'true' : 'false'));
4090}
4091
4092function configure_require_video_completion(class_id, checkbox) {
4093	ajax_request('/class_configure/set_require_video_completion/' + class_id + '?value=' + (checkbox.checked ? 'true' : 'false'));
4094}
4095
4096function update_app_request(school_id, name, title, checkbox) {
4097  $.confirm({
4098    content: ($(checkbox).is(":checked") ? "Are you sure you want to enable " + title + " so the customer can install it?" : "Are you sure you want to un-enable " + title + "?"),
4099    confirm: function() {
4100		window.location.href = '/school/update_app_request/' + school_id + '?name=' + name + '&value=' + (checkbox.checked ? 'true' : 'false');
4101    },
4102    cancel: function() {
4103      if ($(checkbox).is(":checked"))
4104        $(checkbox).prop( "checked", false );
4105      else
4106        $(checkbox).prop( "checked", true );
4107    }
4108  });
4109}
4110
4111function set_mastery_calculation2(dropdown) {
4112	if (dropdown.value == 'Decaying average') {
4113		$('#decaying_average_weight').show();
4114	} else {
4115		$('#decaying_average_weight').hide();
4116	}
4117}
4118
4119function set_mastery_value_threshold2(dropdown) {
4120	if (dropdown.value == '') {
4121		$('#mastery_count_threshold').hide();
4122		$('#mastery_progress_calculation').hide();
4123	} else {
4124		$('#mastery_count_threshold').show();
4125		$('#mastery_progress_calculation').show();
4126	}
4127}
4128
4129// section configuration
4130
4131function set_section_optional_for_completion(class_id, lesson_id, section_id, checkbox) {
4132    ajax_request('/teacher_section/set_optional_for_completion/' + class_id + '?lesson_id=' + lesson_id + '&section_id=' + section_id + '&value=' + (checkbox.checked ? 'false' : 'true'));
4133}
4134
4135function set_assignment_optional_for_completion(assignment_id, checkbox) {
4136    ajax_request('/teacher_assignment/set_optional_for_completion/' + assignment_id + '?value=' + (checkbox.checked ? 'false' : 'true'));
4137}
4138
4139// lesson configuration
4140
4141function set_lesson_optional_for_completion(class_id, lesson_id, checkbox) {
4142	ajax_request('/teacher_lesson/set_optional_for_completion/' + class_id + '?lesson_id=' + lesson_id + '&value=' + (checkbox.checked ? 'false' : 'true'));
4143}
4144
4145// path configuration
4146
4147function set_path_feature(path_id, checkbox) {
4148	ajax_request('/path_configure/set_attribute/' + path_id + '?attribute=' + checkbox.value + '&value=' + (checkbox.checked ? 'true' : 'false'));
4149}
4150
4151function configure_open_enrollment_path(path_id, checkbox) {
4152	ajax_request('/path_configure/set_open_enrollment/' + path_id + '?value=' + (checkbox.checked ? 'true' : 'false'));
4153}
4154
4155function set_path_announcement_comments(path_id, checkbox) {
4156	ajax_request('/path_configure/set_announcement_comments/' + path_id + '?value=' + (checkbox.checked ? 'true' : 'false'));
4157}
4158
4159function set_sequencing(path_id, radio_button) {
4160	ajax_request('/path_configure/set_sequencing/' + path_id + '?value=' + radio_button.value);
4161}
4162
4163function configure_enable_path_student_posts(path_id, checkbox) {
4164	ajax_request('/path_configure/set_enable_student_posts/' + path_id + '?value=' + (checkbox.checked ? 'true' : 'false'));
4165}
4166
4167function configure_path(attribute, path_id, checkbox) {
4168  ajax_request('/path_configure/set_attribute/' + path_id + '?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false'));
4169}
4170
4171// goal configuration
4172
4173function set_goal_optional_for_completion(path_id, goal_id, checkbox) {
4174	ajax_request('/path_admin_goal/set_optional_for_completion/' + path_id + '?goal=' + goal_id + '&value=' + (checkbox.checked ? 'false' : 'true'));
4175}
4176
4177// bundles
4178
4179function configure_bundle(attribute, bundle_id, checkbox) {
4180  ajax_request('/bundle_configure/set_attribute/' + bundle_id + '?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false'));
4181}
4182
4183// subscriptions
4184
4185function configure_subscription(attribute, subscription_id, checkbox) {
4186  ajax_request('/subscription_configure/set_attribute/' + subscription_id + '?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false'));
4187}
4188
4189// logo
4190
4191function set_left_bar_picture(value) {
4192	ajax_request('/logo/set_left_bar_picture?value=' + value);
4193}
4194
4195// tile color
4196
4197function configure_tile_color(controller, object_id, value){
4198	if(/^([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(value)){
4199		ajax_request('/' + controller + '/set_tile_color/' + object_id + '?value=' + encodeURIComponent('#' + value));
4200	}
4201}
4202
4203function configure_recommendations(type, checkbox) {
4204	ajax_request('/goals_admin/configure_recommendation?type=' + type + '&value=' + (checkbox.checked ? 'true' : 'false'));
4205}
4206
4207function configure_goals(type, checkbox) {
4208	ajax_request('/goals_admin/configure_goal?type=' + type + '&value=' + (checkbox.checked ? 'true' : 'false'));
4209}
4210
4211function update_checkbox_response(id, section_id, checkbox_id, checkbox) {
4212	ajax_request('/student_checkbox_section/update_checkbox_response/' + id + '?section_id=' + section_id + '&checkbox_id=' + checkbox_id + '&value=' + (checkbox.checked ? 'true' : 'false'));
4213}
4214
4215// tile color
4216
4217var reset_color;
4218
4219function submit_quick_tile_editor(box_index, controller, object_id, lesson_id, lesson_index, game) {
4220	var name = $('#tile_name_' + box_index).val();
4221	var tile_color = '#' + $('#tile_color_' + box_index).val();
4222	if($('#tile_picture_' + box_index).length > 0){
4223		var picture = $('#tile_picture_' + box_index).val();
4224	}
4225	var $parent_obj = $('[id^="quick_edit_box_' + box_index + '_"]').parent();
4226
4227	// name
4228	var name_element = $('#tile_name_' + box_index);
4229
4230	if (name_element.length) {
4231		var name = name_element.val();
4232	}
4233
4234	// color
4235	var tile_element = $('#tile_color_' + box_index);
4236
4237	if (tile_element.length) {
4238		var tile_color_value = tile_element.val().replace(/\s/g, "");
4239		var tile_color = tile_color_value === 'transparent' ? 'transparent' : '#' + tile_color_value;
4240	}
4241
4242	// picture
4243	var tile_picture_element = $('#tile_picture_' + box_index);
4244
4245	if (tile_picture_element.length) {
4246		var picture = tile_picture_element.val();
4247	}
4248
4249	// values
4250	var values = {};
4251
4252	if (typeof name != 'undefined' && name.length > 0) {
4253		values['name'] = name;
4254	}
4255
4256	reset_color_button_id = '#reset_tile_color_' + (lesson_id ? lesson_id : object_id);
4257
4258	if (reset_color || typeof reset_color == 'undefined') {
4259		// only repaint on an explicit reset: when the color was never touched the
4260		// picker still holds the tile's own color (seeded from --tile-color-bar),
4261		// so painting it here would flood the tile body with its bar color
4262		if (reset_color) {
4263			if ($parent_obj.parent().prop('tagName') == "TD" ){
4264	            $parent_obj.parent().css('background-color', tile_color);
4265			} else {
4266	            $parent_obj.css('background-color', tile_color);
4267			}
4268		}
4269        $(reset_color_button_id).hide();
4270        if (typeof lesson_index != 'undefined') {
4271        	JSON.stringify(values['tile_color'],null)
4272        }
4273	} else if (typeof tile_color != 'undefined' && (tile_color === 'transparent' || tile_color === '#' || (tile_color.length > 1 && /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(tile_color)))) {
4274        values['tile_color'] = tile_color === '#' ? '' : tile_color;
4275        $(reset_color_button_id).show();
4276    }
4277
4278	if (typeof picture != 'undefined' && picture.length > 0) {
4279		values['picture'] = picture;
4280	}
4281
4282  if (typeof game != 'undefined') {
4283    values['game'] = game;
4284  }
4285
4286	if (!$.isEmptyObject(values)) {
4287		// in the case of lessons, object_id is the class_id and we also pass the lesson_id
4288		$.post('/' + controller + '/set_quick_tile_values/' + object_id + (typeof lesson_id != 'undefined' ? '?lesson_id=' + lesson_id : ''), values, function () {
4289			for (var key in values) {
4290				switch (key) {
4291					case 'name':
4292						if ($parent_obj.parents('.has_quick_editor').length > 0) {
4293
4294                            if (lesson_index){
4295                                tile_name = lesson_index + '. '+ values[key];
4296                            }else {
4297                                tile_name = values[key];
4298                            }
4299							if ($parent_obj.parents('.modern_module_list').length > 0){
4300								$parent_obj.siblings().children('div.header').children().children('h2 > span, h3 > span').html(tile_name);
4301							} else {
4302								// catalog/lesson/group tiles use h2.class_name, dashboard class and path tiles use h3.class_name
4303								$parent_obj.children('div.header').children().children('h2, h3').html(tile_name);
4304							}
4305
4306						}else{
4307							if($('#fixedSectionHeader').length > 0){
4308								$('#fixedSectionHeader .centerHeading a').html(values[key]);
4309							} else if ($('.teacherLessonHeading').length > 0) {
4310								$('.teacherLessonHeading .centerHeading a').html(values[key]);
4311							} else {
4312								$('.sectionTitle h2, .sectionTitle h1, #leftColumn h1').html(values[key]);
4313							}
4314						}
4315						break;
4316					case 'tile_color':
4317						if ($('body').hasClass('catalog_class')) {
4318							$('head').append('<style>' +
4319								'html:not([dir=rtl]) .catalog_class #contentWrap:before,' +
4320								'[dir=rtl] .catalog_class #contentWrap:after,' +
4321								'.catalog_class #leftColumn {' +
4322								'background-color: ' + values[key] +
4323								'}
4323' +
4324								'</style>');
4325						} else {
4326							var tile_id = box_index.replace(/^[a-z_]+/, '');
4327							var $tile_element = $('#' + tile_id);
4328							
4329							if ($tile_element.attr('data-tile-color-bar') === 'true') {
4330								$tile_element.css('--tile-color-bar', values[key]);
4331							} else {
4332								if ($parent_obj.parent().hasClass('modern_module_wrap')) {
4333									$parent_obj.parent().css('background-color', values[key]);
4334								} else {
4335									$parent_obj.css('background-color', values[key]);
4336								}
4337							}
4338						}
4339
4340						break;
4341					case 'picture':
4342						if ($parent_obj.parents('.has_quick_editor').length > 0) {
4343							$parent_obj.find('.imgCrop').css('background-image', 'url(\'' + values[key] + '\')');
4344						} else {
4345							if ($('body').hasClass('catalog_class')) {
4346								$('.leftColumn .imgCrop').css('background-image', 'url(\'' + values[key] + '\')');
4347							} else {
4348								if ($('.leftColumn .img_crop_wrap > img').length > 0) {
4349									console.log('updating img src');
4350									$('.leftColumn .img_crop_wrap > img').attr('src', values[key]);
4351								} else {
4352									console.log('updating div bg image');
4353									if (lesson_id) {
4354										$(`.leftColumn #${lesson_id} .imgCrop`).css('background-image', 'url(\'' + values[key] + '\')');
4355									} else {
4356										$(`.leftColumn #${object_id} .imgCrop`).css('background-image', 'url(\'' + values[key] + '\')');
4357									}
4358								}
4359							}
4360						}
4361
4362						// Clear input fields so user can make multiple changes without refreshing
4363						var uploaderWrapperId = 'UploaderWrapper' + box_index;
4364						var $uploaderWrapper = $('#' + uploaderWrapperId);
4365						$uploaderWrapper.find('#SingleFileUpload').remove();
4366						$uploaderWrapper.hide();
4367						$uploaderWrapper.siblings('.optionsRibbon, .action-toolbar').show();
4368
4369						break;
4370				}
4371			}
4372		});
4373	}
4374}
4375
4376//default image editor
4377function submit_image_editor(image) {
4378	var $url_input = $('#tile_picture_' + image);
4379	if($url_input.length > 0 && $url_input.val().length > 0){
4380		var url = $url_input.val();
4381        var $parent_obj = $('#quick_edit_box_' + image).parent();
4382        var values = {
4383            image: image,
4384			      url: url
4385        };
4386
4387		$.post('/custom_tile_images/save_image/', values, function() {
4388			$parent_obj.find('.imgCrop').css('background-image', 'url(\'' + values.url +'\')');
4389            $parent_obj.removeClass('default_image');
4390		});
4391	}
4392}
4393
4394function reset_tile_picture(image){
4395	var box_id = '#quick_edit_box_' + image;
4396    $tile = $(box_id).parent();
4397    $.post('/custom_tile_images/delete_image/', {image: image}, function() {
4398        $tile.find('.imgCrop').css('background-image', 'url(\'' + $tile.data('original_url') +'\')');
4399        $(box_id).hide();
4400        $tile.addClass('default_image');
4401    });
4402}
4403
4404function submit_image_job_title(id) {
4405  var $url_input = $('#job_title_picture_' + id);
4406  if($url_input.length > 0 && $url_input.val().length > 0){
4407    var url = $url_input.val();
4408    var $parent_obj = $('#quick_edit_box_' + id).parent();
4409    var values = {
4410      url: url
4411    };
4412
4413    $.post('/job_title/save_image/' + id, values, function () {
4414		$parent_obj.css('background-image', 'url(\'' + url + '\')');
4415	});
4416  }
4417}
4418
4419function reset_job_title_picture(id){
4420	var box_id = '#quick_edit_box_' + id;
4421    $tile = $(box_id).parent();
4422    $.post('/job_title/delete_image/' + id, function () {
4423		$tile.css('background-image', 'url(\'' + $tile.data('original_url') + '\')');
4424		$(box_id).hide();
4425	});
4426}
4427
4428// mastery image quick edit
4429
4430function submit_image_curriculum(id) {
4431  var $url_input = $('#curriculum_picture_' + id);
4432  if($url_input.length > 0 && $url_input.val().length > 0){
4433    var url = $url_input.val();
4434    var $parent_obj = $('#quick_edit_box_' + id).parent();
4435    var values = {
4436      url: url
4437    };
4438
4439    $.post('/mastery/save_image/' + id, values, function () {
4440      $parent_obj.css('background-image', 'url(\'' + url + '\')');
4441    });
4442  }
4443}
4444
4445function reset_curriculum_picture(id){
4446  var box_id = '#quick_edit_box_' + id;
4447  $tile = $(box_id).parent();
4448  $.post('/mastery/delete_image/' + id, function () {
4449    $tile.css('background-image', 'url(\'' + $tile.data('original_url') + '\')');
4450    $(box_id).hide();
4451  });
4452}
4453
4454// submit and reset cover photo
4455
4456function submit_background_photo(replace_image) {
4457  if($('#background_photo').length > 0){
4458    var photo = $('#background_photo').val();
4459  }
4460  if(typeof photo != 'undefined' && photo.length > 0){
4461    $.post('/user/submit_background_photo', { photo: photo }, function( data ) {
4462      if (replace_image) {
4463        $('.profile_background').css('background-image', 'url(\'' + photo +'\')');
4464      } else {
4465        show_info(data.message)
4466      }
4467    });
4468  }
4469}
4470
4471function reset_background_photo(theme_cover) {
4472        $.post('/user/remove_background_photo', {}, function() {
4473              $('.profile_background').css('background-image', 'url(\'' + theme_cover + '\')');
4474        });
4475}
4476
4477function init_quick_edit_box(box_id){
4478	$box = $(box_id);
4479	$box.find('.options_btn').hide();
4480	$box.find('.uploader-list').show();
4481}
4482
4483function update_tile_color_input(input_id, color){
4484	reset_color = false;
4485
4486	$(input_id).siblings('button').show();
4487
4488	if (color === 'transparent') {
4489		// Handle transparent separately - set empty value for jscolor
4490		$(input_id).css('background-color', 'transparent').val('');
4491	} else {
4492		$(input_id).css('background-color', color).val(color.replace('#', ''));
4493	}
4494}
4495
4496function reset_tile_color(controller, object_id, input_id, lesson_id, game){
4497	reset_color = true;
4498	var child, child_id;
4499	var attributes = '';
4500
4501	if (lesson_id) {
4502    attributes = '&lesson_id=' + lesson_id.toString();
4503    child_id = lesson_id.toString();
4504  } else if (game) {
4505    attributes = '&game=' + game.toString();
4506    child_id = game.toString();
4507	} else {
4508		child_id = object_id;
4509	}
4510
4511	if ($('#'+ child_id ).prop('tagName') == 'TABLE'){
4512		child = $('table#' + child_id)[0];
4513	} else {
4514		child = $('div#' + child_id)[0];
4515	}
4516	var parent = child.parentNode;
4517	var position = Array.prototype.indexOf.call(parent.children, child);
4518
4519	color =  Functions.Helpers.hexc($('.tile_colors.m_r_auto')[0].children[position % 4].style.backgroundColor).toUpperCase();
4520
4521	default_color_index = (position % 4 + 1);
4522
4523	$(input_id).css('background-color', color).val(color.replace('#', ''));
4524
4525	reset_color_button_id = '#reset_tile_color_' + child_id;
4526	$(reset_color_button_id).hide();
4527
4528	ajax_request('/' + controller + '/set_tile_color/' + object_id + '?value=' +  default_color_index + attributes);
4529}
4530
4531// EVO UI: Reset tile color to original value from the tile element
4532function reset_tile_color_evo(input_id) {
4533	reset_color = false;
4534
4535	var $input = $(input_id);
4536
4537	// Find the tile element
4538	var $quickEditBox = $input.closest('.quick_edit_box');
4539	var $tile = null;
4540
4541	// Case 1: Tile view - the parent div has data-tile-color-bar (e.g., <div class="draggable" ...>)
4542	var $parent = $quickEditBox.parent();
4543	if ($parent.attr('data-tile-color-bar') === 'true') {
4544		$tile = $parent;
4545	}
4546	
4547	// Case 2: List view - look for a td.modern_module_wrap ancestor with data-tile-color-bar
4548	if (!$tile) {
4549		$tile = $quickEditBox.closest('.modern_module_wrap[data-tile-color-bar="true"]');
4550	}
4551
4552	// Get the initial color from the --tile-color-bar CSS variable
4553	var initialColor = 'transparent';
4554	if ($tile && $tile.length > 0 && $tile.attr('data-tile-color-bar') === 'true') {
4555		var tileColorBar = window.getComputedStyle($tile[0]).getPropertyValue('--tile-color-bar').trim();
4556		if (tileColorBar && tileColorBar !== 'transparent') {
4557			initialColor = tileColorBar.startsWith('#') ? tileColorBar : Functions.Helpers.hexc(tileColorBar);
4558		}
4559	}
4560
4561	$input.css('background-color', initialColor).val(initialColor.replace('#', ''));
4562
4563	if ($input[0].jscolor) {
4564		$input[0].jscolor.fromString(initialColor);
4565	}
4566
4567	$input.siblings('button').show();
4568}
4569
4570// fonts
4571
4572function select_font(dropdown) {
4573	window.location.href = '/portal/set_font?value=' + dropdown.value;
4574}
4575
4576function select_font_size(dropdown) {
4577	window.location.href = '/portal/set_font_size?value=' + dropdown.value;
4578}
4579
4580// icons
4581
4582function set_icon_for_profile(checkbox) {
4583	window.location.href = '/icons/set_icon_for_profile?value=' + check_s(checkbox);
4584}
4585
4586// disable social share
4587
4588function set_disable_social_share(checkbox) {
4589    ajax_request('/portal/set_disable_social_share?value=' + check_s(checkbox));
4590}
4591
4592// suppress embed links
4593
4594function set_suppress_embed_links(checkbox) {
4595	ajax_request('/portal/set_suppress_embed_links?value=' + check_s(checkbox));
4596}
4597
4598// wide screen support
4599
4600function set_wide_screen_support(checkbox) {
4601	window.location.href = '/portal/set_wide_screen_support?value=' + check_s(checkbox);
4602}
4603
4604// max user content width
4605
4606function set_max_user_content_width(select) {
4607	window.location.href = '/portal/set_max_user_content_width?value=' + select.options[select.selectedIndex].value;
4608}
4609
4610// thinner navigation
4611
4612function set_use_thinner_nav(checkbox) {
4613	window.location.href = '/portal/set_use_thinner_nav?value=' + check_s(checkbox);
4614}
4615
4616// dark mode
4617
4618function set_enable_dark_mode(checkbox) {
4619	window.location.href = '/portal/set_enable_dark_mode?value=' + check_s(checkbox);
4620}
4621
4622// mini-navigation
4623
4624function set_site_mini_nav(tab) {
4625	ajax_request('/portal/set_mini_nav?value=' + tab);
4626}
4627
4628// dropdown navigation
4629
4630function set_disable_dropdown_nav(checkbox) {
4631	ajax_request('/portal/set_disable_dropdown_nav?value=' + check_s(checkbox));
4632}
4633
4634// tiles
4635
4636function set_show_tile_view_by_default(checkbox) {
4637	ajax_request('/portal/set_show_tile_view_by_default?value=' + check_s(checkbox));
4638}
4639
4640// captcha
4641
4642function set_use_captcha(checkbox) {
4643	$.post('/portal/set_use_captcha?value=' + check_s(checkbox), function(){
4644		location.reload();
4645	});
4646}
4647
4648function set_invisible_captcha(checkbox) {
4649	ajax_request('/portal/set_invisible_captcha?value=' + check_s(checkbox));
4650}
4651
4652// lti_enabled
4653
4654function set_lti_enabled(checkbox) {
4655	$.post('/admin_lti/set_lti_enabled?value=' + check_s(checkbox), function(){
4656		location.reload();
4657	});
4658}
4659
4660// lti_auto_enroll
4661
4662function set_lti_auto_enroll(checkbox) {
4663	ajax_request('/admin_lti/set_lti_auto_enroll?value=' + check_s(checkbox));
4664}
4665
4666
4667// lti_auto_create
4668
4669function set_lti_auto_create(checkbox) {
4670	ajax_request('/admin_lti/set_lti_auto_create?value=' + check_s(checkbox));
4671}
4672
4673// dst_event_recalculation
4674
4675function set_dst_event_recalculation(checkbox) {
4676	ajax_request('/portal/set_dst_event_recalculation?value=' + check_s(checkbox));
4677	show_info('The calendar events are being recalculated. You will receive a message when the recalculation is complete.');
4678}
4679
4680// portal type
4681
4682// TODO: could be done better
4683function set_portal_type(controller, value, id) {
4684  if (id == false) {
4685    window.location.href = '/' + controller + '/set_portal_type?value=' + value;
4686  } else {
4687    window.location.href = '/' + controller + '/set_portal_type/' + id + '?value=' + value;
4688  }
4689}
4690
4691// organization SSO
4692
4693function set_org_sso_policy(controller, value, id, sso_provider) {
4694	if (id == false) {
4695		window.location.href = '/' + controller + '/set_org_sso_policy?value=' + value + '&sso_provider=' + sso_provider;
4696	} else {
4697		window.location.href = '/' + controller + '/set_org_sso_policy/' + id + '?value=' + value + '&sso_provider=' + sso_provider;
4698	}
4699}
4700
4701// use accessible portal carousel
4702
4703function set_accessible_carousel(checkbox) {
4704    ajax_request('/portal/set_accessible_carousel?value=' + check_s(checkbox));
4705}
4706
4707// use high contrast theme
4708
4709function set_high_contrast_theme(checkbox) {
4710    $.post('/portal/set_high_contrast_theme?value=' + check_s(checkbox), function(){
4711        if (checkbox.checked) {
4712            $.post('/portal/set_allow_high_contrast_theme?value=false', function(){
4713                location.reload();
4714            });
4715        } else {
4716            location.reload();
4717        }
4718	});
4719}
4720
4721function set_allow_high_contrast_theme(checkbox) {
4722    $.post('/portal/set_allow_high_contrast_theme?value=' + check_s(checkbox), function(){
4723        location.reload();
4724	});
4725}
4726
4727// enable tile colors in new UI
4728
4729function set_enable_tile_colors_new_ui(checkbox) {
4730    ajax_request('/portal/set_enable_tile_colors_new_ui?value=' + check_s(checkbox));
4731}
4732
4733// language
4734
4735function set_show_language_in_footer(checkbox) {
4736	window.location.href = '/portal/set_show_language_in_footer?value=' + check_s(checkbox);
4737}
4738
4739// new user interface
4740
4741function set_enable_new_ui(checkbox) {
4742	window.location.href = '/portal/set_enable_new_ui?value=' + check_s(checkbox);
4743}
4744
4745// super admin evo toggle
4746
4747function set_evo_enabled(checkbox) {
4748	window.location.href = '/portal/set_evo_enabled?value=' + check_s(checkbox);
4749}
4750
4751// evo enabled for account type
4752function set_evo_enabled_for_account_type(checkbox, account_type) {
4753	window.location.href = '/portal/set_evo_enabled_for_account_type?account_type=' + account_type + '&value=' + check_s(checkbox);
4754}
4755
4756// evo global super admin toggle
4757function set_evo_enabled_for_whole_portal(checkbox) {
4758	$.confirm({
4759		content: $(checkbox).data('confirm'),
4760		confirm: function() {
4761			window.location.href = '/portal/set_evo_enabled_for_whole_portal?value=' + check_s(checkbox);
4762		},
4763		cancel: function() {
4764			if ($(checkbox).is(":checked"))
4765				$(checkbox).prop( "checked", false );
4766			else
4767				$(checkbox).prop( "checked", true );
4768		}
4769	});
4770}
4771
4772// ssl
4773
4774function set_ssl_support(checkbox) {
4775	window.location.href = '/portal/set_ssl_support?value=' + check_s(checkbox);
4776}
4777
4778// terminology
4779
4780function set_disable_plural_mapping(checkbox) {
4781	window.location.href = '/substitutions/set_disable_plural_mapping?value=' + check_s(checkbox);
4782}
4783
4784// home tabs
4785
4786function set_enable_top_tab(attribute, checkbox) {
4787	window.location.href = '/portal/set_enable_top_tab?attribute=' + attribute + '&value=' + check_s(checkbox);
4788}
4789
4790function set_landing_tab(value) {
4791	window.location.href = '/portal/set_landing_tab?value=' + value;
4792}
4793
4794// left bar
4795
4796function set_display_my_classes(checkbox) {
4797	window.location.href = '/portal/set_display_my_classes?value=' + check_s(checkbox);
4798}
4799
4800function set_display_my_paths(checkbox) {
4801	window.location.href = '/portal/set_display_my_paths?value=' + check_s(checkbox);
4802}
4803
4804function set_display_my_groups(checkbox) {
4805	window.location.href = '/portal/set_display_my_groups?value=' + check_s(checkbox);
4806}
4807
4808// simple login
4809
4810function set_simple_login(checkbox) {
4811  ajax_request('/configure_sso/set_simple_login?value=' + check_s(checkbox));
4812}
4813
4814// password reset
4815
4816function set_password_reset(checkbox) {
4817  ajax_request('/configure_sso/set_password_reset?value=' + check_s(checkbox));
4818}
4819
4820function toggle_auth0_custom_fields(){
4821	if ($('#auth0_settings_auto_create').is(':checked') || $('#auth0_settings_auto_create_auth0_user').is(':checked')) {
4822		$('#auth0_custom_fields').show();
4823	}else{
4824		$('#auth0_custom_fields').hide();
4825	}
4826}
4827
4828function set_auto_create_saml(checkbox){
4829	if (check_s(checkbox) == 'true') {
4830		$('#saml_custom_fields').show();
4831		$('#saml_account_field_matching').show();
4832	}else{
4833		$('#saml_custom_fields').hide();
4834		$('#saml_account_field_matching').hide();
4835	}
4836}
4837
4838function set_auto_create_auth0_user(checkbox){
4839	if (check_s(checkbox) == 'true') {
4840		$('#email_verif').show();
4841	}else{
4842		$('#email_verif').hide();
4843	}
4844}
4845
4846function set_auto_create_oauth2(checkbox){
4847	if (check_s(checkbox) == 'true') {
4848		$('#oauth2_custom_fields').show();
4849	}else{
4850		$('#oauth2_custom_fields').hide();
4851	}
4852}
4853
4854// UTM tags
4855
4856function set_store_utm_tags(checkbox) {
4857	ajax_request('/portal/set_store_utm_tags?value=' + check_s(checkbox));
4858}
4859
4860// configure group
4861
4862function configure_group(attribute, group_id, checkbox) {
4863	ajax_request('/group_configure/set_attribute/' + group_id + '?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false'));
4864}
4865
4866function configure_group_top_tab(group_id, radio_button) {
4867	window.location.href = '/group_configure/set_top_tab/' + group_id + '?attribute=' + radio_button.value;
4868}
4869
4870function set_group_start_tab(item_id, checkbox) {
4871	window.location.href = '/group_configure/set_start_tab/' + item_id + '?attribute=' + checkbox.value + '&value=' + (checkbox.checked ? 'true' : 'false');
4872}
4873
4874function set_group_announcement_comments(group_id, checkbox) {
4875	ajax_request('/group_configure/set_announcement_comments/' + group_id + '?value=' + (checkbox.checked ? 'true' : 'false'));
4876}
4877
4878// configure organization
4879
4880function configure_organization(attribute, invert, org_id, checkbox) {
4881	var value = (invert ? !checkbox.checked : checkbox.checked);
4882	ajax_request('/organization/set_attribute/' + org_id + '?attribute=' + attribute + '&value=' + value);
4883}
4884
4885function configure_organization_with_refresh(attribute, invert, org_id, checkbox, from) {
4886	var value = (invert ? !checkbox.checked : checkbox.checked);
4887  window.location.href = '/organization/set_attribute_with_refresh/' + org_id + '?attribute=' + attribute + '&value=' + value + '&from=' + encodeURIComponent(from);
4888}
4889
4890// organizations
4891
4892function set_partition_organizations(checkbox) {
4893	window.location.href = '/organizations/set_partition_organizations?value=' + (checkbox.checked ? 'true' : 'false');
4894}
4895
4896function set_cascading_admin_permissions(checkbox) {
4897	ajax_request('/organizations/set_cascading_admin_permissions?value=' + (checkbox.checked ? 'true' : 'false'));
4898}
4899
4900function set_cascading_manager_permissions(checkbox) {
4901	ajax_request('/organizations/set_cascading_manager_permissions?value=' + (checkbox.checked ? 'true' : 'false'));
4902}
4903
4904function set_allow_override_timeout_for_organizations(checkbox) {
4905	ajax_request('/organizations/set_allow_override_timeout_for_organizations?value=' + (checkbox.checked ? 'true' : 'false'));
4906}
4907
4908function set_custom_dashboard_for_all_sub_orgs(checkbox) {
4909    ajax_request('/organizations/set_custom_dashboard_for_all_sub_orgs?value=' + (checkbox.checked ? 'true' : 'false'));
4910}
4911
4912function set_allow_admin_multi_org_for_role(checkbox, role) {
4913	ajax_request('/organizations/set_allow_admin_multi_org_for_role?role=' + role + '&value=' + (checkbox.checked ? 'true' : 'false'));
4914}
4915
4916function set_missing_organization(dropdown) {
4917	ajax_request('/organizations/set_missing_organization?value=' + dropdown.value);
4918}
4919
4920function change_override_timeout_for_students(checkbox) {
4921	if(checkbox.checked)
4922		$('#override-students-timeout-container').show();
4923	else
4924		$('#override-students-timeout-container').hide();
4925}
4926
4927// portal tabs
4928
4929function set_profile_account_field(dropdown) {
4930    ajax_request('/profile_tabs/set_profile_account_field?value=' + dropdown.value);
4931}
4932
4933function set_profile_field_name(checkbox) {
4934	ajax_request('/profile_tabs/set_profile_field_name?value=' + (checkbox.checked ? 'true' : 'false'));
4935}
4936
4937// affiliate groups
4938
4939function configure_default_affiliate_group(group_id) {
4940    ajax_request('/affiliate_tiers/set_default?group_id=' + group_id);
4941}
4942
4943function assign_affiliate_group(element) {
4944
4945    var ids = [];
4946    $('#affiliates input[type="checkbox"]:checked').each(function(){
4947    	ids.push($(this).val());
4948    });
4949
4950	$.facebox({
4951        'ajax' : $(element).attr('href') + '?ids=' + ids.join(',')
4952    });
4953
4954    return false;
4955}
4956
4957// left bar
4958
4959function expand_online() {
4960	expand('online_bar');
4961	ajax_request('/navigation/expand_online');
4962}
4963
4964function collapse_online() {
4965	collapse('online_bar');
4966	ajax_request('/navigation/collapse_online');
4967}
4968
4969function expand_classes() {
4970	expand('classes_bar');
4971	ajax_request('/navigation/expand_classes');
4972}
4973
4974function collapse_classes() {
4975	collapse('classes_bar');
4976	ajax_request('/navigation/collapse_classes');
4977}
4978
4979function expand_groups() {
4980	expand('groups_bar');
4981	ajax_request('/navigation/expand_groups');
4982}
4983
4984function collapse_groups() {
4985	collapse('groups_bar');
4986	ajax_request('/navigation/collapse_groups');
4987}
4988
4989function expand_shortcuts() {
4990	expand('shortcuts_bar');
4991	ajax_request('/navigation/expand_shortcuts');
4992}
4993
4994function collapse_shortcuts() {
4995	collapse('shortcuts_bar');
4996	ajax_request('/navigation/collapse_shortcuts');
4997}
4998
4999// to-do list
5000
5001function over_todo(number) {
5002	set_style_element('todo_options' + number, {
5003		display : "inline-block"
5004	});
5005}
5006
5007function out_todo(number) {
5008	hide_element('todo_options' + number);
5009}
5010
5011function delete_todo(number) {
5012	ajax_request('/task/destroy/' + number);
5013	fade_element('todo' + number);
5014}
5015
5016// publish student review
5017
5018function publish_student_review(class_id, review_id, checkbox) {
5019	ajax_request('/teacher_reviews/set_publish/' + class_id + '?review=' + review_id + '&value=' + (checkbox.checked ? 'true' : 'false'));
5020}
5021
5022// enable coupon
5023
5024function set_enable_coupon(coupon_id, checkbox) {
5025	ajax_request('/coupon/set_enabled/' + coupon_id + '?value=' + (checkbox.checked ? 'true' : 'false'));
5026}
5027
5028// catalog calendar
5029
5030function set_catalog_calendar(checkbox) {
5031	ajax_request('/class_catalog_configure/set_catalog_calendar?value=' + (checkbox.checked ? 'true' : 'false'));
5032}
5033
5034// location filtering
5035
5036function set_catalog_location_filtering(checkbox) {
5037	ajax_request('/class_catalog_configure/set_catalog_location_filtering?value=' + (checkbox.checked ? 'true' : 'false'));
5038}
5039
5040// catalog search
5041
5042function set_catalog_search(checkbox) {
5043	ajax_request('/class_catalog_configure/set_catalog_search?value=' + (checkbox.checked ? 'true' : 'false'));
5044}
5045
5046function search_catalog(url) {
5047	var phrase = $('#catalog_search').val();
5048
5049	if (url.indexOf('?') == -1) {
5050		window.location.href = url + "?phrase=" + phrase;
5051	} else {
5052		window.location.href = url + "&phrase=" + phrase;
5053	}
5054}
5055
5056function process_search_catalog(event, url) {
5057	if (event.keyCode == 13) {
5058		search_catalog(url);
5059		return false;
5060	} else {
5061		return true;
5062	}
5063}
5064
5065// search
5066
5067function submit_compact_search(url) {
5068	//var phrase = get_value('compact_search_phrase');
5069	var phrase = $('.compact_search_phrase').last().val();
5070
5071	if (url.indexOf('?') == -1) {
5072		window.location.href = url + "?phrase=" + phrase;
5073	} else {
5074		window.location.href = url + "&phrase=" + phrase;
5075	}
5076}
5077
5078function process_search(event, url) {
5079	if (event.keyCode == 13) {
5080		submit_compact_search(url);
5081		return false;
5082	} else {
5083		return true;
5084	}
5085}
5086
5087// gateway
5088
5089function update_lesson(select) {
5090	if (select.selectedIndex == 0) {
5091		hide_element('lesson_info');
5092	} else {
5093		show_element('lesson_info');
5094	}
5095}
5096
5097function update_gateway(select) {
5098	if (select.selectedIndex == 0) {
5099		hide_element('gateway');
5100	} else {
5101		show_element('gateway');
5102	}
5103}
5104
5105function update_threshold(checkbox) {
5106	if (checkbox.checked) {
5107		show_element('threshold');
5108	} else {
5109		hide_element('threshold');
5110	}
5111}
5112
5113// accounts misc options
5114
5115function set_enable_catalog_accounts(checkbox) {
5116	ajax_request('/accounts/set_enable_catalog_accounts?value=' + check_s(checkbox));
5117}
5118
5119function set_default_to_school_address(checkbox) {
5120	ajax_request('/accounts/set_default_to_school_address?value=' + check_s(checkbox));
5121}
5122
5123// grading
5124
5125function update_excused(checkbox) {
5126	if (checkbox.checked) {
5127		hide_element('score_area');
5128		hide_element('edit_attachments');
5129		hide_element('adjust_score');
5130		hide_element('missing_area');
5131		hide_element('absent_area');
5132		hide_element('incomplete_area');
5133		hide_element('rubric');
5134		set_checked('excused', true);
5135		set_checked('absent', false);
5136		set_checked('missing', false);
5137		set_checked('incomplete', false);
5138	} else {
5139		show_element('score_area');
5140		show_element('edit_attachments');
5141		show_element('adjust_score');
5142		show_element('missing_area');
5143		show_element('absent_area');
5144		show_element('incomplete_area');
5145		show_element('rubric');
5146		set_checked('excused', false);
5147	}
5148}
5149
5150function update_absent(checkbox) {
5151	if (checkbox.checked) {
5152		hide_element('score_area');
5153		hide_element('edit_attachments');
5154		hide_element('adjust_score');
5155		hide_element('excused_area');
5156		hide_element('missing_area');
5157		hide_element('incomplete_area');
5158		hide_element('rubric');
5159		set_checked('excused', false);
5160		set_checked('absent', true);
5161		set_checked('missing', false);
5162		set_checked('incomplete', false);
5163	} else {
5164		show_element('score_area');
5165		show_element('edit_attachments');
5166		show_element('adjust_score');
5167		show_element('excused_area');
5168		show_element('missing_area');
5169		show_element('incomplete_area');
5170		show_element('rubric');
5171		set_checked('absent', false);
5172	}
5173}
5174
5175function update_missing(checkbox) {
5176	if (checkbox.checked) {
5177		hide_element('score_area');
5178		hide_element('edit_attachments');
5179		hide_element('adjust_score');
5180		hide_element('excused_area');
5181		hide_element('absent_area');
5182		hide_element('incomplete_area');
5183		hide_element('rubric');
5184		set_checked('excused', false);
5185		set_checked('absent', false);
5186		set_checked('missing', true);
5187		set_checked('incomplete', false);
5188	} else {
5189		show_element('score_area');
5190		show_element('edit_attachments');
5191		show_element('adjust_score');
5192		show_element('excused_area');
5193		show_element('absent_area');
5194		show_element('incomplete_area');
5195		show_element('rubric');
5196		set_checked('missing', false);
5197	}
5198}
5199
5200function update_incomplete(checkbox) {
5201	if (checkbox.checked) {
5202		hide_element('score_area');
5203		hide_element('edit_attachments');
5204		hide_element('adjust_score');
5205		hide_element('excused_area');
5206		hide_element('absent_area');
5207		hide_element('missing_area');
5208		hide_element('rubric');
5209		set_checked('excused', false);
5210		set_checked('absent', false);
5211		set_checked('missing', false);
5212		set_checked('incomplete', true);
5213	} else {
5214		show_element('score_area');
5215		show_element('edit_attachments');
5216		show_element('adjust_score');
5217		show_element('excused_area');
5218		show_element('absent_area');
5219		show_element('missing_area');
5220		show_element('rubric');
5221		set_checked('incomplete', false);
5222	}
5223}
5224
5225// student comments
5226
5227function set_allow_student_comments(assignment_id, checkbox) {
5228	ajax_request('/teacher_freeform_assignment/set_allow_student_comments/' + assignment_id + '?value=' + check_s(checkbox));
5229}
5230
5231// multiple choice
5232
5233function enable_feedback() {
5234	show_element('feedback');
5235}
5236
5237function disable_feedback() {
5238	hide_element('feedback');
5239}
5240
5241// freeform
5242
5243function enable_correct_answer() {
5244    show_element('correct_answer');
5245}
5246
5247function disable_correct_answer() {
5248    hide_element('correct_answer');
5249}
5250
5251// true/false
5252
5253var correct_answer = null;
5254
5255function set_correct_answer(value) {
5256	correct_answer = value;
5257
5258	if (value) {
5259		hide_element('correction');
5260	} else if (correction_box) {
5261		show_element('correction');
5262	}
5263}
5264
5265var correction_box = null;
5266
5267function set_correction_box(value) {
5268	correction_box = value;
5269
5270	if (value) {
5271		if (correct_answer == false) {
5272			show_element('correction');
5273		}
5274	} else {
5275		hide_element('correction');
5276	}
5277}
5278
5279function answered_false() {
5280	show_element('correction');
5281}
5282
5283function answered_true() {
5284	hide_element('correction');
5285	$('#correct_answer').val('');
5286}
5287
5288// sections
5289
5290function set_assignment_given(checkbox, assignment_controller, assignment_id, from) {
5291	if (checkbox.checked) {
5292		window.location.href = '/' + assignment_controller + '/give/' + assignment_id + '?from=' + from;
5293	} else {
5294		window.location.href = '/' + assignment_controller + '/ungive/' + assignment_id + '?from=' + from;
5295	}
5296}
5297
5298function set_section_hidden(checkbox, class_id, lesson_id, section_id, is_assignment) {
5299	ajax_request('/teacher_section/' + ( is_assignment ? 'set_hidden_assignment/' : 'set_hidden/' ) + class_id + '?lesson_id=' + lesson_id + '&section_id=' + section_id + '&value=' + check_s(checkbox));
5300}
5301
5302// portal pages
5303
5304function set_portal_page_enabled(portal_page_id, checkbox, portal_id) {
5305	ajax_request('/portal_page/set_enabled?id=' + portal_page_id + '&portal_id=' + portal_id + '&value=' + check_s(checkbox));
5306}
5307
5308// custom html
5309
5310function set_portal_custom_html_enabled(portal_custom_html_id, checkbox, portal_id) {
5311	window.location.href = '/portal_custom_htmls/set_enabled?id=' + portal_custom_html_id + '&value=' + check_s(checkbox);
5312}
5313
5314// profile pages
5315
5316function set_profile_tab_enabled(profile_tab_id, checkbox) {
5317	var n = $('input:checkbox[id^="profile_tab_"]:checked').length;
5318
5319	if (n > 0) {
5320		ajax_request('/profile_tab/set_enabled?id=' + profile_tab_id + '&value=' + check_s(checkbox));
5321	} else {
5322		$('#' + checkbox.id).attr('checked', 'checked');
5323		show_error('You cannot disable all User profile tabs. At least one should be enabled.');
5324	}
5325}
5326
5327// portal slides
5328
5329function set_portal_slide_enabled(portal_slide_id, checkbox, portal_id) {
5330	ajax_request('/portal_slide/set_enabled?id=' + portal_slide_id + '&portal_id=' + portal_id + '&value=' + check_s(checkbox));
5331}
5332
5333// portal icons
5334
5335function set_show_visitors(portal_icon_id, checkbox) {
5336	ajax_request('/portal_icon/set_show_visitors?id=' + portal_icon_id + '&value=' + check_s(checkbox));
5337}
5338
5339function set_show_users(portal_icon_id, checkbox) {
5340	window.location.href = '/portal_icon/set_show_users?id=' + portal_icon_id + '&value=' + check_s(checkbox);
5341}
5342
5343// portal panels
5344
5345function set_portal_panel_enabled(portal_panel_id, checkbox, portal_id) {
5346  ajax_request('/portal_panel/set_enabled?id=' + portal_panel_id + '&portal_id=' + portal_id + '&value=' + check_s(checkbox));
5347}
5348
5349// footers
5350
5351function set_footer_enabled(footer_id, checkbox) {
5352	window.location.href = '/footers/set_enabled?footer_id=' + footer_id + '&value=' + check_s(checkbox);
5353}
5354
5355// boxes
5356
5357function set_box_enabled(box_id, id, checkbox) {
5358	if (id == null) {
5359		ajax_request('/box/set_enabled?box_id=' + box_id + '&value=' + check_s(checkbox));
5360	} else {
5361		ajax_request('/box/set_enabled/' + id + '?box_id=' + box_id + '&value=' + check_s(checkbox));
5362	}
5363}
5364
5365function set_box_hideable(box_id, id, checkbox) {
5366	if (id == null) {
5367		ajax_request('/box/set_hideable?box_id=' + box_id + '&value=' + check_s(checkbox));
5368	} else {
5369		ajax_request('/box/set_hideable/' + id + '?box_id=' + box_id + '&value=' + check_s(checkbox));
5370	}
5371}
5372
5373// monitoring
5374
5375function set_monitoring(checkbox) {
5376    window.location.href = '/policies/set_monitoring?value=' + check_s(checkbox);
5377}
5378
5379function set_public_monitoring(checkbox) {
5380    ajax_request('/policies/set_public_monitoring?value=' + check_s(checkbox));
5381}
5382
5383function set_announcement_comments(checkbox) {
5384    ajax_request('/policies/set_announcement_comments?value=' + check_s(checkbox));
5385}
5386
5387function set_grade_synopsis(checkbox) {
5388    ajax_request('/policies/set_grade_synopsis?value=' + check_s(checkbox));
5389}
5390
5391// email sync
5392
5393function email_sync(type) {
5394	ajax_request('/inbox/email_sync' + '?type=' + type);
5395}
5396
5397function sms_sync(type) {
5398	ajax_request('/inbox/sms_sync' + '?type=' + type);
5399}
5400
5401// teacher assignments
5402
5403function set_allow_late(controller, assignment_id, checkbox) {
5404	ajax_request('/' + controller + '/set_allow_late/' + assignment_id + '?value=' + check_s(checkbox));
5405}
5406
5407function set_maximum_submissions(controller, assignment_id, dropdown) {
5408	ajax_request('/' + controller + '/set_maximum_submissions/' + assignment_id + '?value=' + dropdown.value);
5409}
5410
5411function override_allow_late(controller, assignment_id, student_id, checkbox) {
5412	ajax_request('/' + controller + '/override_allow_late/' + assignment_id + '?student=' + student_id + '&value=' + check_s(checkbox));
5413}
5414
5415function override_maximum_submissions(controller, assignment_id, student_id, dropdown) {
5416	ajax_request('/' + controller + '/override_maximum_submissions/' + assignment_id + '?student=' + student_id + '&value=' + dropdown.value);
5417}
5418
5419// attachments
5420
5421function add_attachment(suffix, max, remove_string, the_width, custom) {
5422	var p = document.createElement("p");
5423
5424	var line = document.createElement("input");
5425	line.setAttribute("name", "attachments" + suffix + "[]");
5426	line.setAttribute("type", "file");
5427	line.setAttribute("class", "textInput");
5428
5429	if (the_width != null) {
5430		if (custom) {
5431			line.setAttribute("style", "width: " + the_width + "px;float:left");
5432		} else {
5433			line.setAttribute("style", "width: " + the_width + "px;");
5434		}
5435	}
5436
5437	p.appendChild(line);
5438
5439	if (!custom) {
5440		var text1 = document.createTextNode(' [');
5441		p.appendChild(text1);
5442	}
5443
5444	var a = document.createElement("a");
5445	a.setAttribute("style", "cursor:pointer;");
5446
5447	if (custom) {
5448		a.setAttribute("style", "cursor:pointer;float:right;margin-top:6px");
5449	}
5450
5451	a.onclick = function(evt) {
5452		remove_attachment(this, suffix);
5453	};
5454
5455	if (custom) {
5456		var text2 = document.createElement('i');
5457		text2.setAttribute("class", "delete");
5458		a.appendChild(text2);
5459		p.appendChild(a);
5460	} else {
5461		var text2 = document.createTextNode(remove_string);
5462		a.appendChild(text2);
5463		p.appendChild(a);
5464	}
5465
5466	if (!custom) {
5467		var text3 = document.createTextNode(']');
5468		p.appendChild(text3);
5469	}
5470
5471	var element = document.getElementById("attachments" + suffix);
5472	element.appendChild(p);
5473
5474	var count = element.childNodes.length;
5475
5476	if (count == 1) {
5477		hide_element("add_attachment" + suffix + "_option");
5478	}
5479
5480	if ((count < max) || (max == 0)) {
5481		show_element("add_another_attachment" + suffix + "_option");
5482	} else {
5483		hide_element("add_another_attachment" + suffix + "_option");
5484	}
5485}
5486
5487function remove_attachment(href, suffix) {
5488	var node = href.parentNode;
5489	node.parentNode.removeChild(node);
5490
5491	var element = document.getElementById("attachments" + suffix);
5492	var count = element.childNodes.length;
5493
5494	if (count == 0) {
5495		hide_element("add_another_attachment" + suffix + "_option");
5496		show_element("add_attachment" + suffix + "_option");
5497	} else {
5498		show_element("add_another_attachment" + suffix + "_option");
5499	}
5500}
5501
5502// original assignment instructions
5503
5504function pop_up_assignment_instructions(controller, id) {
5505	if(is_mobile_app_mode()){
5506		window.parent.postMessage("{\"method\": \"loadBrowser\", \"href\": \"" + '/' + controller + '/instructions/' + id + "\"}", "*");
5507	}else{
5508		window.open('/' + controller + '/instructions/' + id, 'instructions', 'height=560px,width=500px,toolbar=yes,directories=no,status=yes,menubar=no,scrollbars=yes,resizable=yes,modal=no');
5509	}
5510}
5511
5512// correct answer for freeform assignments
5513
5514function pop_up_correct_answer(controller, id) {
5515	if(is_mobile_app_mode()){
5516		window.parent.postMessage("{\"method\": \"loadBrowser\", \"href\": \"" + '/' + controller + '/correct_answer/' + id + "\"}", "*");
5517	}else {
5518		window.open('/' + controller + '/correct_answer/' + id, 'correctanswer', 'height=560px,width=500px,toolbar=yes,directories=no,status=yes,menubar=no,scrollbars=yes,resizable=yes,modal=no');
5519	}
5520}
5521
5522// account field
5523
5524function pop_up_field(user_id, field_id) {
5525	if(is_mobile_app_mode()){
5526		window.parent.postMessage("{\"method\": \"loadBrowser\", \"href\": \"" + '/user/field/' + user_id + '?field=' + field_id + "\"}", "*");
5527	}else {
5528		window.open('/user/field/' + user_id + '?field=' + field_id, 'field', 'height=560px,width=500px,toolbar=yes,directories=no,status=yes,menubar=no,scrollbars=yes,resizable=yes,modal=no');
5529	}
5530}
5531
5532// changes
5533
5534function toggle_child(checkbox, child_id) {
5535	if (checkbox.checked) {
5536		select_all_checkboxes('child_' + child_id);
5537	} else {
5538		clear_all_checkboxes('child_' + child_id);
5539	}
5540}
5541
5542function toggle_common_changes(checkbox) {
5543	if (checkbox.checked) {
5544		select_all_checkboxes_by_id('common_');
5545	} else {
5546		clear_all_checkboxes_by_id('common_');
5547	}
5548}
5549
5550function toggle_common_change(checkbox, count) {
5551  if (checkbox.checked) {
5552    select_all_checkboxes_by_id('common_' + count);
5553  } else {
5554    clear_all_checkboxes_by_id('common_' + count);
5555  }
5556}
5557
5558function select_all_checkboxes(prefix) {
5559	var checkboxes = $('input:checkbox[name^=' + prefix + ']');
5560
5561	for (var i = 0; i < checkboxes.length; i++) {
5562		checkboxes[i].checked = true;
5563	}
5564}
5565
5566function clear_all_checkboxes(prefix) {
5567	var checkboxes = $('input:checkbox[name^=' + prefix + ']');
5568
5569	for (var i = 0; i < checkboxes.length; i++) {
5570		checkboxes[i].checked = false;
5571	}
5572}
5573
5574function select_all_checkboxes_by_id(prefix) {
5575  var checkboxes = $('input:checkbox[id^=' + prefix + ']');
5576
5577  for (var i = 0; i < checkboxes.length; i++) {
5578    checkboxes[i].checked = true;
5579  }
5580}
5581
5582function clear_all_checkboxes_by_id(prefix) {
5583  var checkboxes = $('input:checkbox[id^=' + prefix + ']');
5584
5585  for (var i = 0; i < checkboxes.length; i++) {
5586    checkboxes[i].checked = false;
5587  }
5588}
5589
5590function toggle_all_teams(checkbox) {
5591	if (checkbox.checked) {
5592		var checkboxes = $('input:checkbox[name^="teams[]"]');
5593
5594		for (var i = 0; i < checkboxes.length; i++) {
5595			checkboxes[i].checked = true;
5596		}
5597	} else {
5598		var checkboxes = $('input:checkbox[name^="teams[]"]');
5599
5600		for (var i = 0; i < checkboxes.length; i++) {
5601			checkboxes[i].checked = false;
5602		}
5603	}
5604}
5605
5606// edit_state
5607
5608function update_state(select, name) {
5609	var country = select.options[select.selectedIndex].value;
5610
5611	if (country == 'United States' || country == 'Brazil') {
5612		show_element(name + '_state_div');
5613		hide_element(name + '_other_state_div');
5614		$.get('/account_fields/get_states_for_country?value='+ country, function(data) {
5615			$('select#' + name + '_state').empty();
5616			$.each(data.names, function (index, state) {
5617				$('select#' + name + '_state').append('<option value="'+state.code+'">'+state.name+'</option>');
5618			});
5619		});
5620		$('select#' + name + '_state').attr('disabled', false);
5621		$('input#' + name + '_other_state').attr('disabled', true);
5622	} else {
5623		hide_element(name + '_state_div');
5624		show_element(name + '_other_state_div');
5625		$('select#' + name + '_state').attr('disabled', true);
5626		$('input#' + name + '_other_state').attr('disabled', false);
5627	}
5628}
5629
5630// district policies
5631
5632function set_district_policy(attribute, invert, checkbox) {
5633	var value = ( invert ? !checkbox.checked : checkbox.checked);
5634	ajax_request('/policies/set_district_attribute?attribute=' + attribute + '&value=' + (value == true ? 'true' : 'false'));
5635}
5636
5637// lesson
5638
5639function update_all_day_lesson(checkbox) {
5640	if (checkbox.checked) {
5641		show_element('all_day');
5642		hide_element('not_all_day');
5643		hide_element('duration');
5644	} else {
5645		show_element('not_all_day');
5646		hide_element('all_day');
5647		show_element('duration');
5648	}
5649}
5650
5651// event
5652
5653function update_all_day(checkbox) {
5654	if (checkbox.checked) {
5655		show_element('all_day');
5656		hide_element('not_all_day');
5657		set_checked('is_conference', false);
5658	} else {
5659		show_element('not_all_day');
5660		hide_element('all_day');
5661	}
5662}
5663
5664// recurring event
5665
5666function update_recurring(checkbox, is_zoomus) {
5667	if (checkbox.checked) {
5668		show_element('recurring');
5669        hide_element('based_on_week');
5670        $("#is_weekly_based").prop( "checked", false );
5671		hide_element('event_rsvp');
5672		set_checked('event_rsvp', false);
5673		hide_element('event_rsvp_label');
5674		if(!is_zoomus) {
5675            hide_element('is_conference');
5676            set_checked('is_conference', false);
5677			hide_element('event_conference_label');
5678        }
5679		if(get_value('event_repeats') == "Monthly"){
5680            show_element('is_weekly_based');
5681            show_element('is_weekly_based_label');
5682		}
5683	} else {
5684		show_element('event_rsvp');
5685		show_element('event_rsvp_label');
5686        hide_element('is_weekly_based');
5687        hide_element('is_weekly_based_label');
5688        $("#is_weekly_based").prop( "checked", false );
5689        show_element('based_on_week');
5690		hide_element('recurring');
5691        if(!is_zoomus) {
5692            show_element('is_conference');
5693            show_element('event_conference_label')
5694        }
5695	}
5696}
5697
5698function update_rsvp_field(checkbox) {
5699	if (checkbox.checked) {
5700		hide_element('event_recurring');
5701		hide_element('event_recurring_label');
5702	} else {
5703		show_element('event_recurring');
5704		show_element('event_recurring_label');
5705	}
5706}
5707
5708function update_weekly_based(checkbox) {
5709    if (checkbox.checked) {
5710    	show_element('based_on_week');
5711    } else {
5712        hide_element('based_on_week');
5713    }
5714}
5715
5716// ends none
5717
5718function update_ends_none(radio_button) {
5719	if (radio_button.checked) {
5720		hide_element('ends_on');
5721		hide_element('ends_after');
5722		hide_element('after_occurrences');
5723	}
5724}
5725
5726// ends after
5727
5728function update_ends_after(radio_button) {
5729	if (radio_button.checked) {
5730		hide_element('ends_on');
5731		show_element('after_occurrences');
5732		$('#event_ends_occurrences').width( 60 );
5733		show_element('ends_after');
5734	}
5735}
5736
5737// ends on
5738
5739function update_ends_at(radio_button) {
5740	if (radio_button.checked) {
5741		show_element('ends_on');
5742		hide_element('ends_after');
5743		hide_element('after_occurrences');
5744	}
5745}
5746
5747function get_repeats_value(){
5748	$('#event_repeats').width( 80 );
5749	$('#event_repeat_every').width( 60 );
5750	$('#event_ends_occurrences').width( 60 );
5751	var e = document.getElementById("event_repeats");
5752	var repeats = e.options[e.selectedIndex].text;
5753	set_repeats_options(repeats);
5754}
5755
5756// repeats options
5757
5758function set_repeats_options(dropdown){
5759	if(dropdown == 'Daily'){
5760		show_element('repeats_every_days');
5761		hide_element('repeats_every_weeks');
5762		hide_element('repeats_every_months');
5763		hide_element('repeats_every_years');
5764        hide_element('weekly_based');
5765        hide_element('is_weekly_based');
5766        hide_element('is_weekly_based_label');
5767        $("#is_weekly_based").prop( "checked", false );
5768        hide_element('based_on_week');
5769	}else if(dropdown == 'Weekly'){
5770		show_element('repeats_every_weeks');
5771		hide_element('repeats_every_days');
5772		hide_element('repeats_every_months');
5773		hide_element('repeats_every_years');
5774        hide_element('weekly_based');
5775        hide_element('is_weekly_based');
5776        hide_element('is_weekly_based_label');
5777        $("#is_weekly_based").prop( "checked", false );
5778        hide_element('based_on_week');
5779	}else if(dropdown == 'Monthly'){
5780		hide_element('repeats_every_days');
5781		hide_element('repeats_every_weeks');
5782		show_element('repeats_every_months');
5783		hide_element('repeats_every_years');
5784		show_element('weekly_based');
5785        show_element('is_weekly_based');
5786        show_element('is_weekly_based_label');
5787	}else if(dropdown == 'Yearly'){
5788		hide_element('repeats_every_days');
5789		hide_element('repeats_every_weeks');
5790		hide_element('repeats_every_months');
5791		show_element('repeats_every_years');
5792        hide_element('weekly_based');
5793        hide_element('is_weekly_based');
5794        hide_element('is_weekly_based_label');
5795        $("#is_weekly_based").prop( "checked", false );
5796        hide_element('based_on_week');
5797	}
5798}
5799
5800// repeats scheduled reports
5801
5802function get_repeats_value_scheduled_reports(){
5803	$('#report_id').width( 480 );
5804	$('#repeats').width( 90 );
5805	$('#repeat_every').width( 50 );
5806	var e = document.getElementById("repeats");
5807	var repeats = e.options[e.selectedIndex].text;
5808	set_repeats_scheduled_reports(repeats);
5809}
5810
5811function set_repeats_scheduled_reports(dropdown){
5812	if(dropdown == 'Minutely') {
5813		show_element('repeats_every_minutes');
5814		hide_element('repeats_every_days');
5815		hide_element('repeats_every_weeks');
5816		hide_element('repeats_every_months');
5817		hide_element('repeats_every_years');
5818	}else if(dropdown == 'Daily'){
5819		hide_element('repeats_every_minutes');
5820		show_element('repeats_every_days');
5821		hide_element('repeats_every_weeks');
5822		hide_element('repeats_every_months');
5823		hide_element('repeats_every_years');
5824	}else if(dropdown == 'Weekly'){
5825		hide_element('repeats_every_minutes');
5826		show_element('repeats_every_weeks');
5827		hide_element('repeats_every_days');
5828		hide_element('repeats_every_months');
5829		hide_element('repeats_every_years');
5830	}else if(dropdown == 'Monthly'){
5831		hide_element('repeats_every_minutes');
5832		hide_element('repeats_every_days');
5833		hide_element('repeats_every_weeks');
5834		show_element('repeats_every_months');
5835		hide_element('repeats_every_years');
5836	}else if(dropdown == 'Yearly'){
5837		hide_element('repeats_every_minutes');
5838		hide_element('repeats_every_days');
5839		hide_element('repeats_every_weeks');
5840		hide_element('repeats_every_months');
5841		show_element('repeats_every_years');
5842	}
5843}
5844
5845function update_repeats_schedule_job(checkbox) {
5846	if (checkbox.checked) {
5847		show_element('repeats_job');
5848	} else {
5849		hide_element('repeats_job');
5850	}
5851}
5852
5853// reports new popup
5854
5855// period type
5856
5857function update_period_type_range(radio_button) {
5858	if (radio_button.checked) {
5859		hide_element('period_type_last');
5860		hide_element('period_type_current');
5861		show_element('period_type_range');
5862	}
5863}
5864
5865function update_period_type_last(radio_button) {
5866	if (radio_button.checked) {
5867		show_element('period_type_last');
5868		hide_element('period_type_current');
5869		hide_element('period_type_range');
5870	}
5871}
5872
5873function update_period_type_current(radio_button) {
5874	if (radio_button.checked) {
5875		hide_element('period_type_last');
5876		show_element('period_type_current');
5877		hide_element('period_type_range');
5878	}
5879}
5880
5881// my reports
5882
5883function set_my_report(report_id, checkbox, is_my_catalog) {
5884	ajax_request('/reports/set_my_report?report_id=' + report_id + '&value=' + (checkbox.checked ? 'true' : 'false'));
5885
5886	if (!checkbox.checked && is_my_catalog) {
5887		$("div#report_" + report_id).remove();
5888	}
5889}
5890
5891// web conferencing on-click processing
5892
5893function common_checked_conference_gateway(supports_recurring = false) {
5894  set_checked('event_all_day', false);
5895  $("#event_all_day").prop( "checked", false );
5896  show_element('not_all_day');
5897  hide_element('all_day');
5898  if(!supports_recurring){
5899	  hide_element('event_recurring');
5900	  hide_element('event_recurring_label');
5901  }
5902}
5903
5904function common_unchecked_conference_gateway(supports_recurring = false) {
5905  $('#event_form button[type="submit"]').off('click');
5906  if(!supports_recurring){
5907	  show_element('event_recurring');
5908	  show_element('event_recurring_label');
5909  }
5910}
5911
5912function process_onclick_web_conferencing(checkbox, no_token, auth_url, client_name, pop_params, supports_recurring = false) {
5913  if (checkbox.checked) {
5914    common_checked_conference_gateway(supports_recurring);
5915
5916    if (no_token) {
5917			if(is_mobile_app_mode()){
5918				window.parent.postMessage("{\"method\": \"loadBrowser\", \"href\": \"'" + auth_url + "\"}", "*");
5919			}else{
5920        var conferencing_window = window.open("", "conferencingWindow");
5921				if(!(typeof conferencing_window === 'undefined' || conferencing_window === null)) {
5922					conferencing_window.close();
5923				}
5924				window.open(auth_url, 'conferencingWindow', pop_params);
5925			}
5926		}
5927
5928    $('#event_form button[type="submit"]').click(function() {
5929      $('#conference_status').html('<p>Communicating with ' + client_name + '... <img style="margin-left:10px" src="/images/loading-16.gif" /></p>').show();
5930    });
5931  } else {
5932    common_unchecked_conference_gateway(supports_recurring);
5933  }
5934}
5935
5936// report
5937
5938function update_current_month(checkbox) {
5939  if (checkbox.checked) {
5940    show_element('organizations_option');
5941    hide_element('output_option');
5942  } else {
5943    hide_element('organizations_option');
5944    show_element('output_option');
5945  }
5946}
5947
5948// grade
5949
5950function update_adjust(checkbox) {
5951	if (checkbox.checked) {
5952		show_element('adjust');
5953	} else {
5954		hide_element('adjust');
5955	}
5956}
5957
5958function update_adjust_link(el) {
5959	if ($('#adjust').is(':visible')) {
5960		$(el).parent().find('input[name="adjustment[enable]"]').val(false);
5961	} else {
5962		$(el).parent().find('input[name="adjustment[enable]"]').val(true);
5963	}
5964
5965	$('#adjust').toggle();
5966}
5967
5968// groups
5969
5970function show_public() {
5971	show_element('public');
5972	hide_element('private');
5973}
5974
5975function show_private() {
5976	show_element('private');
5977	hide_element('public');
5978}
5979
5980// lessons
5981
5982function set_current_lesson_tile() {
5983	var checked_lesson_ids = [];
5984
5985	$('#lessons input:checkbox').each(function () {
5986		if (this.checked) {
5987			var lesson_id;
5988
5989			if (this.value.indexOf('check_') !== -1)
5990				lesson_id = this.value.substring(6); // present in the row view
5991			else
5992				lesson_id = this.value; // tile view
5993
5994			checked_lesson_ids.push(lesson_id);
5995		}
5996	});
5997
5998	// TODO: translate
5999	if (checked_lesson_ids.length == 0) {
6000		$.alert({content: 'Please select one lesson to make current'});
6001	} else if (checked_lesson_ids.length > 1) {
6002		$.alert({content: 'You have selected more than one lesson, but you can only make one lesson current'});
6003	} else {
6004		var lesson_id = checked_lesson_ids[0];
6005
6006		if (current_lesson_id == lesson_id) {
6007			current_lesson_id = null;
6008
6009			$.get('/teacher_lessons/clear_current/' + class_id, function () {
6010				window.location.reload();
6011			});
6012		} else {
6013			current_lesson_id = lesson_id;
6014
6015			$.get('/teacher_lessons/set_current/' + class_id + '?lesson_id=' + lesson_id, function () {
6016				window.location.reload();
6017			});
6018		}
6019	}
6020}
6021
6022// TODO: this one isn't even used. But it's quite nice since it doesn't redraw. Perhaps use it instead?
6023
6024function set_current_lesson_row() {
6025  var checked_lessons = [];
6026  var lesson_position = 1;
6027  $('.instructor_module_view input:checkbox').each(function(){
6028    if(this.checked){
6029      checked_lessons.push(lesson_position);
6030    }
6031    lesson_position++;
6032  });
6033  if(checked_lessons.length == 0){
6034    $.alert({content: 'Please select one lesson to make current'});
6035  }else if(checked_lessons.length > 1){
6036    $.alert({content: 'You have selected more than one lesson, but you can only make one lesson current'});
6037  }else{
6038    var position = checked_lessons[0];
6039    $('.instructor_module_view .imgCrop .current').addClass('hide');
6040    $('.instructor_module_view > table:nth-of-type(' + position + ') .imgCrop .current').removeClass('hide');
6041
6042    if (current_lesson == position) {
6043      current_lesson = null;
6044      $.get('/teacher_lessons/clear_current/' + class_id, function(){
6045        $('.instructor_module_view > table:nth-of-type(' + position + ') .imgCrop .current').addClass('hide');
6046        //window.location.reload();
6047      });
6048    } else {
6049      current_lesson = position;
6050      $.get('/teacher_lessons/set_current/' + class_id + '?position=' + position, function(){
6051        //window.location.reload();
6052      });
6053    }
6054  }
6055}
6056
6057// launch SCORM
6058
6059function launch_scorm(url, title, height, width) {
6060	window.open(url, 'SCORM', 'height=' + height + ',width=' + width + ',toolbar=no,directories=no,location=no,status=yes,menubar=no,scrollbars=yes,resizable=yes,modal=no');
6061}
6062
6063function refreshScormNavigation(type){
6064	if ($('#'+type+'_launch_mode_always').is(':checked')) {
6065		$('#set_navigation').hide();
6066	} else {
6067		$('#set_navigation').show();
6068	}
6069}
6070
6071// configure quiz
6072
6073function init_quiz_configure(the_controller, the_id) {
6074	configure_controller = the_controller;
6075	configure_id = the_id;
6076}
6077
6078// school policies
6079
6080function set_walled_community(checkbox) {
6081	ajax_request('/policies/set_walled_community?value=' + check_s(checkbox));
6082}
6083
6084function set_attribute(attribute, invert, checkbox, confirm_on_true, confirm_on_false) {
6085	var value = (invert ? !checkbox.checked : checkbox.checked);
6086	var confirm = (value && confirm_on_true) || (!value && confirm_on_false);
6087	var uncheck = function () {
6088		$(checkbox).prop("checked", !$(checkbox).prop("checked"));
6089	};
6090
6091	var ajaxCall = function() {
6092		var url = '/policies/set_attribute?attribute=' + attribute + '&value=' + (value == true ? 'true' : 'false');
6093
6094		$.ajax({
6095			url: url,
6096			method: 'post',
6097			dataType: 'json',
6098			success: function(data) {
6099				if(data && data.info ) {
6100					show_warning( data.info );
6101					uncheck();
6102				}
6103			}
6104		});
6105	};
6106
6107	if( confirm )
6108		$.confirm({ content: confirm, confirm: ajaxCall, cancel: uncheck });
6109	else
6110		ajaxCall();
6111}
6112
6113function set_attribute_with_refresh(attribute, invert, checkbox, from) {
6114    var value = (invert ? !checkbox.checked : checkbox.checked);
6115    window.location.href = '/policies/set_attribute_with_refresh?attribute=' + attribute + '&value=' + (value == true ? 'true' : 'false') + '&from=' + encodeURIComponent(from);
6116}
6117
6118function set_organization_cascade_settings(organization_id, checkbox) {
6119	var value = checkbox.checked;
6120
6121	var url = '/organization_visitor_portal/set_cascade_settings/' + organization_id + '?value=' + (value == true ? 'true' : 'false');
6122	ajax_request(url);
6123}
6124
6125function set_organization_inherit_school_conferencing_configuration(organization_id, checkbox) {
6126	var value = checkbox.checked;
6127
6128	var url = '/organization_conferencing/set_inherit_school_configuration/' + organization_id + '?value=' + (value == true ? 'true' : 'false');
6129	$.ajax({ url : url, type : 'POST', success: function() { window.location.reload(); } });
6130}
6131
6132function set_organization_gateway_config(organization_id, gateway_type, mode, radio) {
6133	var url = '/organization_conferencing/set_gateway_config/' + organization_id + '?gateway_type=' + gateway_type + '&mode=' + mode;
6134	$.ajax({
6135		url: url,
6136		type: 'POST',
6137		success: function() { window.location.reload(); }
6138	});
6139}
6140
6141function set_organization_conferencing_cascade_settings(organization_id, checkbox) {
6142	var value = checkbox.checked;
6143
6144	var url = '/organization_conferencing/set_cascade_settings/' + organization_id + '?value=' + (value == true ? 'true' : 'false');
6145	ajax_request(url);
6146}
6147
6148function set_organization_inherit_school_payment_gateway_configuration(organization_id, checkbox) {
6149	var value = checkbox.checked;
6150
6151	var url = '/organization_ecommerce/set_inherit_school_payment_gateway_configuration/' + organization_id + '?value=' + (value == true ? 'true' : 'false');
6152	$.ajax({ url : url, type : 'POST', success: function() { window.location.reload(); } });
6153}
6154
6155function set_organization_payment_gateway_cascade_settings(organization_id, checkbox) {
6156	var value = checkbox.checked;
6157
6158	var url = '/organization_ecommerce/set_payment_gateway_cascade_settings/' + organization_id + '?value=' + (value == true ? 'true' : 'false');
6159	ajax_request(url);
6160}
6161
6162/* roles */
6163
6164function set_role_enabled(role_id, checkbox) {
6165	var value = checkbox.checked;
6166	window.location.href = '/roles/set_enabled?role_id=' + role_id + '&value=' + checkbox.checked;
6167}
6168
6169function set_avatar_attribute(attribute, invert, checkbox, refresh) {
6170  var value = (invert ? !checkbox.checked : checkbox.checked);
6171
6172  if (refresh) {
6173    ajax_request('/avatars/set_attribute?attribute=' + attribute + '&value=' + (value == true ? 'true' : 'false'), {asynchronous : false});
6174    window.location.href = '/avatars';
6175  } else {
6176    ajax_request('/avatars/set_attribute?attribute=' + attribute + '&value=' + (value == true ? 'true' : 'false'));
6177  }
6178}
6179
6180function set_zapier_attribute(field) {
6181	var values = [];
6182
6183	$('input[name^="zapier_events"]').each(function(){
6184		if($(this).is(':checked')){
6185			values.push($(this).attr('id').replace('zapier_events_', ''));
6186		}
6187	});
6188
6189	ajax_request('/zapier_configure/set_attribute?value=' + values.join(','));
6190}
6191
6192function set_level_display(dropdown) {
6193	ajax_request('/policies/set_level_display?value=' + dropdown.value);
6194}
6195
6196function set_agent_setting(attribute, invert, checkbox, refresh, class_id) {
6197	var value = (invert ? !checkbox.checked : checkbox.checked);
6198
6199	if (refresh) {
6200		ajax_request('/class_configure/set_agent_attribute/' + class_id + '?attribute=' + attribute + '&value=' + (value == true ? 'true' : 'false'), {asynchronous : false});
6201		window.location.href = '/class_configure/agent/' + class_id;
6202	} else {
6203		ajax_request('/class_configure/set_agent_attribute/' + class_id + '?attribute=' + attribute + '&value=' + (value == true ? 'true' : 'false'));
6204	}
6205}
6206
6207/* two factor authentication */
6208
6209function toggle_require_2fa_for_role(role, checkbox) {
6210	ajax_request('/two_factor_auth/require_for_role?role=' + role + '&value=' + (checkbox.checked ? 'true' : 'false'));
6211}
6212
6213function set_timeout_for_2fa(dropdown) {
6214	ajax_request('/two_factor_auth/set_timeout?value=' + dropdown.value);
6215}
6216
6217function set_enforce_2fa_days(dropdown) {
6218	ajax_request('/two_factor_auth/set_enforce_days?value=' + dropdown.value);
6219}
6220
6221function set_remind_2fa_days(dropdown) {
6222	ajax_request('/two_factor_auth/set_remind_days?value=' + dropdown.value);
6223}
6224
6225// ecommerce
6226
6227function set_ecommerce_attribute(attribute, checkbox) {
6228    ajax_request('/ecommerce/set_attribute?attribute=' + attribute + '&value=' + (checkbox.checked == true ? 'true' : 'false'));
6229}
6230
6231function set_toggle_tax_code(checkbox, tax_code) {
6232    $('.tax_code').attr('disabled', true);
6233    window.location.href = '/tax_codes/set_enable_tax_code?tax_code=' + tax_code + '&value=' + (checkbox.checked ? 'true' : 'false');
6234}
6235
6236function set_cc_processing_gateway(school_id, radio_button) {
6237	ajax_request('/payment_gateways/set_credit_card_processor_gateway?payment_gateway_id=' + radio_button.value);
6238}
6239
6240function set_enable_payment_gateway(payment_gateway_id, checkbox, user_subscriptions_count) {
6241	if ((!checkbox.checked) && (user_subscriptions_count > 0)) {
6242		prompt = "Please note that there are "+ user_subscriptions_count + " active subscriptions created with this payment gateway. By disabling this gateway, all subscriptions will be cancelled. Are you sure you want to proceed?";
6243		$.confirm({
6244			content: prompt,
6245			confirm: function() {
6246				ajax_request('/payment_gateways/set_enable_payment_gateway?payment_gateway_id=' + payment_gateway_id + '&value=' + 'false');
6247			},
6248			cancel: function() {
6249				checkbox.checked = true;
6250			}
6251		});
6252	} else {
6253		ajax_request('/payment_gateways/set_enable_payment_gateway?payment_gateway_id=' + payment_gateway_id + '&value=' + (checkbox.checked ? 'true' : 'false'));
6254	}
6255}
6256
6257function set_lock_payment_gateway(payment_gateway_id, checkbox) {
6258	prompt = "Are you sure you want to proceed?";
6259	$.confirm({
6260		content: prompt,
6261		confirm: function() {
6262			url = '/payment_gateways/set_lock_payment_gateway?payment_gateway_id=' + payment_gateway_id + '&value=' + (checkbox.checked ? 'true' : 'false');
6263			$.get(url, function(response) { $('#edit_td_' + payment_gateway_id).html(response.edit_td); });
6264		},
6265		cancel: function() {
6266			checkbox.checked = !checkbox.checked;
6267		}
6268	});
6269}
6270
6271function set_organization_cc_processing_gateway(organization_id, radio_button) {
6272	ajax_request('/organization_payment_gateways/set_credit_card_processor_gateway?payment_gateway_id=' + radio_button.value + '&organization_id=' + organization_id);
6273}
6274
6275function set_organization_enable_payment_gateway(payment_gateway_id, checkbox, user_subscriptions_count, organization_id) {
6276	if ((!checkbox.checked) && (user_subscriptions_count > 0)) {
6277		prompt = "Please note that there are "+ user_subscriptions_count + " active subscriptions created with this payment gateway. By disabling this gateway, all subscriptions will be cancelled. Are you sure you want to proceed?";
6278		$.confirm({
6279			content: prompt,
6280			confirm: function() {
6281				ajax_request('/organization_payment_gateways/set_enable_payment_gateway?payment_gateway_id=' + payment_gateway_id + '&value=' + 'false' + '&organization_id=' + organization_id);
6282			},
6283			cancel: function() {
6284				checkbox.checked = true;
6285			}
6286		});
6287	} else {
6288		ajax_request('/organization_payment_gateways/set_enable_payment_gateway?payment_gateway_id=' + payment_gateway_id + '&value=' + (checkbox.checked ? 'true' : 'false') + '&organization_id=' + organization_id);
6289	}
6290}
6291
6292function set_organization_lock_payment_gateway(payment_gateway_id, checkbox, organization_id) {
6293	prompt = "Are you sure you want to proceed?";
6294	$.confirm({
6295		content: prompt,
6296		confirm: function() {
6297			url = '/organization_payment_gateways/set_lock_payment_gateway?payment_gateway_id=' + payment_gateway_id + '&value=' + (checkbox.checked ? 'true' : 'false') + '&organization_id=' + organization_id;
6298			$.get(url, function(response) { $('#edit_td_' + payment_gateway_id).html(response.edit_td); });
6299		},
6300		cancel: function() {
6301			checkbox.checked = !checkbox.checked;
6302		}
6303	});
6304}
6305
6306// catalog
6307
6308function set_catalog_format(dropdown) {
6309	ajax_request('/class_catalogs_configure/set_format?value=' + dropdown.value);
6310}
6311
6312function set_category_ordering(dropdown, from) {
6313	ajax_request('/class_catalogs_configure/set_category_ordering?value=' + dropdown.value);
6314}
6315
6316function set_class_ordering(dropdown) {
6317	ajax_request('/class_catalogs_configure/set_class_ordering?value=' + dropdown.value);
6318}
6319function set_default_organization(dropdown, org_id) {
6320	var new_id = $(dropdown).val();
6321	$(document.querySelectorAll('[id ^= "resource_'+org_id+'"]')).each(function(){
6322		$(this).val(new_id);
6323	});
6324
6325	set_proceed_to_move_submit_btn();
6326}
6327
6328function set_main_default_organization(org_id) {
6329	var arr = $(document.querySelectorAll('[id ^= "resource_'+org_id+'"]')).map(function() { return $(this).val(); }).get();
6330	arr.shift();
6331	var uniqueNames = [];
6332	$.each(arr, function(i, el){
6333		if($.inArray(el, uniqueNames) === -1) uniqueNames.push(el);
6334	});
6335
6336	if(uniqueNames.length > 1) {
6337		$("#resource_"+org_id+"_all_organizations_id").val('--');
6338	} else {
6339		$("#resource_"+org_id+"_all_organizations_id").val(uniqueNames[0]);
6340	}
6341
6342	set_proceed_to_move_submit_btn();
6343}
6344
6345function set_proceed_to_move_submit_btn() {
6346	var arr = $(document.querySelectorAll('[id $= "organization_id"]')).map(function() { return $(this).val(); }).get();
6347	$('#proceed_to_move_submit_btn').prop( "disabled", arr.includes("--"));
6348}
6349
6350// portal
6351
6352function set_enable_indexing(checkbox) {
6353	ajax_request('/portal/set_enable_indexing?value=' + (checkbox.checked ? 'true' : 'false'));
6354}
6355
6356function set_enable_seo_urls(checkbox) {
6357	ajax_request('/portal/set_enable_seo_urls?value=' + (checkbox.checked ? 'true' : 'false'));
6358}
6359
6360function set_show_contact(checkbox) {
6361	ajax_request('/portal/set_show_contact?value=' + (checkbox.checked ? 'true' : 'false'));
6362}
6363
6364// dashboard
6365
6366function set_dashboard_organization(checkbox) {
6367	ajax_request('/home_configure/display_organization?value=' + (checkbox.checked ? 'true' : 'false'));
6368}
6369
6370// submit the hidden form so large payload goes in POST body
6371
6372function archive_users(link) {
6373    var $link = (window.jQuery ? jQuery(link) : null);
6374    var formSelector = ($link && $link.data('form')) || '#archive_users_form';
6375    var form = document.querySelector(formSelector);
6376
6377    if (!form) { if (window.console) console.error('archive_users: form not found'); return false; }
6378
6379    // ensure POST
6380    form.method = 'post';
6381
6382    // double-submit guard
6383    if ($link) { $link.prop('disabled', true); }
6384
6385    // submit
6386    if (form.requestSubmit) {
6387        form.requestSubmit();
6388    } else {
6389        form.submit();
6390    }
6391    return false;
6392}
6393
6394// people
6395
6396function update_administrator(checkbox, index) {
6397	if (checkbox.checked) {
6398		show_element('administrator_' + index);
6399	} else {
6400		hide_element('administrator_' + index);
6401	}
6402}
6403
6404function confirm_teacher_role_remove(checkbox, message) {
6405	if (!checkbox.checked) {
6406		var confirmation = confirm(message);
6407		if (!confirmation) {
6408			// If the user cancels, prevent unchecking the checkbox
6409			checkbox.checked = true;
6410		}
6411	}
6412}
6413function update_account_type(administrator) {
6414	if (administrator) {
6415		show_element('full_administrator');
6416	} else {
6417		hide_element('full_administrator');
6418	}
6419}
6420
6421// rsvp
6422
6423function update_rsvp(controller, id, calendar_id, event_id, refresh, radio_button, facebox_refresh_url) {
6424	if (refresh) {
6425		window.location.href = '/' + controller + '/update_rsvp/' + id + '?calendar=' + calendar_id + '&event=' + event_id + '&value=' + radio_button.value + '&refresh=true';
6426	} else {
6427		if(typeof facebox_refresh_url == 'undefined'){
6428			ajax_request('/' + controller + '/update_rsvp/' + id + '?calendar=' + calendar_id + '&event=' + event_id + '&value=' + radio_button.value);
6429		}else{
6430			$.get('/' + controller + '/update_rsvp/' + id + '?calendar=' + calendar_id + '&event=' + event_id + '&value=' + radio_button.value, function(){
6431				$.facebox({'ajax': facebox_refresh_url});
6432			});
6433		}
6434	}
6435}
6436
6437// skills
6438
6439function set_default_learning_circle_scope(dropdown) {
6440	ajax_request('/goals_admin/set_default_learning_circle_scope?value=' + dropdown.value);
6441}
6442
6443// tips
6444
6445function show_tip(name) {
6446	show_element('show_' + name);
6447	hide_element('hide_' + name);
6448	ajax_request('/tips/show?value=' + name);
6449}
6450
6451function hide_tip(name) {
6452	show_element('hide_' + name);
6453	hide_element('show_' + name);
6454	ajax_request('/tips/hide?value=' + name);
6455}
6456
6457// questions
6458
6459function submit_freeform(operation, validation_method) {
6460  if (typeof validation_method === 'function' ? validation_method() : true) {
6461    set_value('operation', operation);
6462    submit_form('response');
6463  } else {
6464    // Content needs change?
6465    $.alert({title: 'Alert', content: 'There is no content!'});
6466  }
6467}
6468
6469function submit_new_question(operation) {
6470	set_value('operation', operation);
6471	submit_form('question');
6472}
6473
6474function freeform_validation() {
6475  var editor = tinyMCE.activeEditor;
6476  if (typeof editor !== 'undefined') {
6477    var content = editor.getContent();
6478    var files_count = 0;
6479    files_count += $('.uploader-list').children('div').length;
6480    files_count += $('.uploader-uploaded-list').children('div').length;
6481    files_count += $('input[id*=remove_attachment_]:not(:checked)').length;
6482    if (content.trim().length > 0) {
6483      return true;
6484    } else if (content.trim().length == 0 && files_count > 0) {
6485      return true;
6486    }
6487  }
6488  return false;
6489}
6490
6491function dropbox_validation() {
6492  var files_count = 0;
6493  files_count += $('.uploader-list').children('div').length;
6494  files_count += $('.uploader-uploaded-list').children('div').length;
6495  return files_count ? true : false;
6496}
6497
6498// reports
6499
6500function submit_report(operation) {
6501  set_value('operation', operation);
6502  submit_form('report');
6503}
6504
6505function submit_new_report(operation) {
6506	set_value('operation', operation);
6507}
6508
6509// printing
6510
6511function print_this_page(print_args) {
6512	if(is_mobile_app_mode()){
6513		// PDF export is not supported in mobile app mode
6514		$.alert({content: 'Printing is not supported in the mobile app.'});
6515	}else {
6516		if (window.location.hash == "") {
6517			new_location = window.location + (window.location.search == "" ? "?" : "&") + 'print=true'
6518		} else {
6519			new_location = window.location.pathname + (window.location.search == "" ? "?" : "&") + 'print=true' + window.location.hash;
6520		}
6521
6522		if (typeof print_args !== 'undefined') {
6523			let args_array = [];
6524			for (const arg in print_args) {
6525				args_array.push(arg + '=' + print_args[arg]);
6526			}
6527			new_location = new_location + '&' + args_array.join('&');
6528		}
6529
6530		new_window = window.open(new_location);
6531		if (new_window) {
6532			new_window.onload = function () {
6533				new_window.document.title = window.document.title;
6534				new_window.print();
6535				setTimeout(function(){
6536					new_window.close();
6537				}, 300);
6538			};
6539		}
6540	}
6541}
6542
6543function no_print_column(new_window, selector){
6544	elements = new_window.document.querySelectorAll(selector);
6545
6546	for (var i = 0; i < elements.length; i++) {
6547		elements[i].style.display="none";
6548	}
6549}
6550
6551function fix_colspan_userid_passwords() {
6552	var mediaQueryList = window.matchMedia('print');
6553	mediaQueryList.addListener(function(mql) {
6554		if (mql.matches) {
6555			$("table th#to-print[colspan=2]").attr('colspan',0); //fix colspan from members/userid_passwords
6556			console.log('onbeforeprint');
6557		} else {
6558			$("table th#to-print").attr('colspan',2); //fix colspan from members/userid_passwords
6559			console.log('onafterprint');
6560		}
6561	});
6562}
6563
6564/**===================
6565 * ===================
6566 * DEMO PRINT Function
6567 * ===================
6568 * ====== START ======
6569 * */
6570
6571function print_pdf(options) {
6572	var location = window.location;
6573  var pathname = (location.pathname.indexOf('/', 1) == -1 ? location.pathname + '/index' : location.pathname);
6574  var query_string = [];
6575
6576  if (options) {
6577    $.each(options, function(key, value) {
6578      query_string.push(key + '=' + encodeURIComponent(value));
6579    });
6580
6581    query_string = '?' + query_string.join('&');
6582  } else {
6583    query_string = location.search;
6584  }
6585
6586  if(is_mobile_app_mode()){
6587    window.parent.postMessage("{\"method\": \"loadBrowser\", \"href\": \"" + location.protocol + "//" + location.host + pathname + ".pdf" + query_string + "\"}", "*");
6588  }else{
6589    window.open(location.protocol + "//" + location.host + pathname + ".pdf" + query_string);
6590  }
6591}
6592
6593function popup_with_print(data, title, window_parent) {
6594	var windowUrl = 'Student list';
6595	var uniqueName = new Date();
6596	var windowName = 'Print' + uniqueName.getTime();
6597	var printWindow = window.open(windowUrl, windowName, 'left=0,top=0,width=1000,height=700');
6598
6599	printWindow.document.write('<html><head><title>' + title + '</title>');
6600	printWindow.document.write('<link href="/stylesheets/base-colors-user.css" media="screen,print" rel="stylesheet" type="text/css" /> \
6601    		<link href="/stylesheets/themes/monochrome_user.css" media="screen,print" rel="stylesheet" title="theme" type="text/css"> \
6602    		<link href="/stylesheets/default-styles.css" media="screen,print" rel="stylesheet" type="text/css" /> \
6603    		<link href="/stylesheets/styles-user.css" media="screen,print" rel="stylesheet" type="text/css" /> \
6604    		<link href="/stylesheets/extra-user.css" media="screen,print" rel="stylesheet" type="text/css" /> \
6605    		<link href="/stylesheets/fonts/font-all.css" media="screen,print" rel="stylesheet" type="text/css" /> \
6606    		<link href="/stylesheets/facebox.css?2" media="screen,print" rel="stylesheet" type="text/css" /> \
6607    		<link href="/stylesheets/print.css?2" media="screen,print" rel="stylesheet" type="text/css" />');
6608	printWindow.document.write('</head><body >');
6609	printWindow.document.write(data);
6610	printWindow.document.write('</body></html>');
6611	printWindow.document.close();
6612
6613	printWindow.focus();
6614	printWindow.print();
6615	setTimeout(function(){
6616		printWindow.close();
6617		window_parent.close();
6618	}, 1000);
6619}
6620
6621/**===================
6622 * ======= END =======
6623 * ===================
6624 * */
6625
6626function print_pdf_select(selected) {
6627	var location = window.location;
6628	var pathname = (location.pathname.indexOf('/', 1) == -1 ? location.pathname + '/index' : location.pathname);
6629	var url = location.protocol + "//" + location.host + pathname + ".pdf" + location.search;
6630
6631	// should really avoid adding duplicate select[] if already in locaation.search
6632	for (var i = 0; i < selected.length; i++) {
6633		if (i == 0) {
6634			if (location.search.length == 0) {
6635				url += '?';
6636			} else {
6637				url += '&';
6638			}
6639		} else {
6640			url += '&';
6641		}
6642
6643		url += ("select[]=" + selected[i]);
6644	}
6645
6646	if(is_mobile_app_mode()){
6647		window.parent.postMessage("{\"method\": \"loadBrowser\", \"href\": \"" + url + "\"}", "*");
6648	}else{
6649		window.open(url);
6650	}
6651}
6652
6653function help_page(anchor, superuser) {
6654	var url = ((anchor == null) ? '/help' : '/help/#' + anchor);
6655
6656	if (superuser) {
6657		window.open(url, 'Help', 'height=700px,width=520px,location=yes,toolbar=no,directories=yes,status=yes,menubar=yes,scrollbars=yes,resizable=yes,modal=no');
6658	} else {
6659		window.open(url, 'Help', 'height=700px,width=520px,toolbar=no,directories=no,status=yes,menubar=no,scrollbars=yes,resizable=yes,modal=yes');
6660	}
6661}
6662
6663function getScrollXY() {
6664	var scrOfX = 0, scrOfY = 0;
6665
6666	if ( typeof (window.pageYOffset) == 'number') {
6667		// Netscape compliant
6668		scrOfY = window.pageYOffset;
6669		scrOfX = window.pageXOffset;
6670	} else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
6671		// DOM compliant
6672		scrOfY = document.body.scrollTop;
6673		scrOfX = document.body.scrollLeft;
6674	} else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
6675		// IE6 standards compliant mode
6676		scrOfY = document.documentElement.scrollTop;
6677		scrOfX = document.documentElement.scrollLeft;
6678	}
6679
6680	return [scrOfX, scrOfY];
6681}
6682
6683// event is `this`: an <a href="..."> exposes it as the `.href` DOM property,
6684// but a <button> (rendered when the click itself is intercepted, e.g. by the
6685// action toolbar) does not, even though it still carries a plain href
6686// attribute -- fall back to reading that directly.
6687function submit_form_action_url(event) {
6688	return event.href || event.getAttribute('href');
6689}
6690
6691function submit_form_with_confirm(form_id, event, prompt) {
6692	$.confirm({
6693		content: prompt,
6694		confirm: function(){
6695			var form = $('#' + form_id);
6696			form.attr('method', 'POST');
6697			form.attr('action', submit_form_action_url(event));
6698			form.submit();
6699		}
6700	});
6701}
6702
6703function submit_form_without_confirm(form_id, event) {
6704	var form = $('#' + form_id);
6705	form.attr('method', 'POST');
6706	form.attr('action', submit_form_action_url(event));
6707	form.submit();
6708}
6709
6710// launch video
6711
6712function launch_video(id, url, height, width, mobile_app, resume_video) {
6713	var extra_params = "&require_video_completion=" + (typeof window.require_video_completion !== 'undefined').toString() + "&resume_video=" + (typeof resume_video !== 'undefined').toString();
6714
6715	if (typeof window.autoplay !== 'undefined' && window.autoplay) {
6716		extra_params += "&autoplay=true"
6717	}
6718
6719	if (mobile_app) {
6720		window.parent.postMessage("{\"method\": \"loadBrowser\", \"href\": \"/video_player?id=" + id + "&url=" + url + extra_params + "\"}", "*");
6721	} else {
6722		window.open('/video_player?id=' + id + '&url=' + url + extra_params, 'VIDEO', 'height=' + height + 'px,width=' + width + 'px,toolbar=no,directories=no,location=no,status=yes,menubar=no,scrollbars=yes,resizable=yes,modal=no');
6723	}
6724}
6725
6726// launch popup
6727
6728function popup(title, url, height, width) {
6729	window.open(url, title, 'height=' + height + 'px,width=' + width + 'px,toolbar=no,directories=no,location=no,status=yes,menubar=no,scrollbars=yes,resizable=yes,modal=no');
6730}
6731
6732// table item selection
6733
6734function toggle_all(checkbox, disable_message, target) {
6735	disable_message = disable_message || false;
6736	target = target || false;
6737
6738	var form = $(checkbox).closest('form');
6739	console.log('form = ' + form);
6740	var form_id = form.attr('id');
6741	console.log('form_id = ' + form_id);
6742	var checkboxes;
6743	var data = form.data('table');
6744
6745	if (target) {
6746		checkboxes = $(target).find('tr td:nth-child(1) input[type=checkbox]');
6747	} else {
6748		checkboxes = form.find('tr td:nth-child(1) input[type=checkbox], tr td:nth-child(2) input[type=checkbox]');
6749	}
6750
6751	console.log('data = ' + data + ', data.count = ' + data.count + ', data.size = ' + data.size + ' disable_message = ' + disable_message);
6752	if ((data != null) && (data.count > data.size) && !disable_message) {
6753		console.log('should check if to show message');
6754		if (checkbox.checked) {
6755			var tr = form.find('tr:eq(0)');
6756			console.log('should show message');
6757			tr.after("<tr><td style='background:#E0F1ff;' colspan='100'>" + you_have_selected_all_text + " <a class='select_all' href='javascript:select_all_items(\"" + form_id + "\");' style='vertical-align:0;'>" + select_all_items_text + "</a>" + "</td></tr>");
6758		} else {
6759			console.log('should delete message');
6760			form.find('tr:eq(1)').remove();
6761		}
6762	}
6763
6764	for (var i = 0; i < checkboxes.length; i++) {
6765		var row_checkbox = checkboxes[i];
6766		row_checkbox.checked = checkbox.checked;
6767		var row = $(row_checkbox).closest('tr');
6768
6769		if (checkbox.checked) {
6770			row.addClass('highlight');
6771		} else {
6772			row.removeClass('highlight');
6773		}
6774	}
6775
6776	if ((data != null) && data.popup) {
6777		if (checkbox.checked) {
6778			show_options_bar(form);
6779		} else {
6780			hide_options_bar(form);
6781		}
6782	}
6783}
6784
6785function toggle(checkbox, event) {
6786	// toggle the table row background color
6787	var form = $(checkbox).closest('form');
6788
6789	if ((event.shiftKey == 1) && (last_toggled_id != null) && (last_toggled_id != checkbox.value)) {
6790		var checkboxes = form.find('input[type=checkbox]');
6791
6792		// find the one that was last tagged
6793		for (var i = 0; i < checkboxes.length; i++) {
6794			var row_checkbox = checkboxes[i];
6795
6796			if (row_checkbox.value == last_toggled_id) {
6797				start = i;
6798			}
6799
6800			if (row_checkbox.value == checkbox.value) {
6801				stop = i;
6802			}
6803		}
6804
6805		if (start > stop) {
6806			var tmp = start;
6807			start = stop;
6808			stop = tmp;
6809		}
6810
6811		for (var i = start; i <= stop; i++) {
6812			var row_checkbox = checkboxes[i];
6813			row_checkbox.checked = checkbox.checked;
6814			var row = $(row_checkbox).closest('tr');
6815			checkbox.checked ? row.addClass('highlight') : row.removeClass('highlight');
6816		}
6817	} else {
6818		var row = $(checkbox).closest('tr');
6819		checkbox.checked ? row.addClass('highlight') : row.removeClass('highlight');
6820	}
6821
6822	// remember the last toggle
6823	last_toggled_id = checkbox.value;
6824
6825	// update top bar
6826	update_options_bar(form);
6827}
6828
6829function checked_toggle(id) {
6830	var checkbox = $(":checkbox[value=" + id + "]");
6831	var row = $(checkbox).closest('tr');
6832	row.css('background', '#FFF6BA');
6833}
6834
6835function toggle_all_lessons(value, link) {
6836	$('#lessons').find('input[name="select[]"]').prop('checked', value);
6837	$(link).attr('onclick', 'toggle_all_lessons(' + (value ? 'false' : 'true') + ', this)');
6838
6839	if (value) {
6840		$(link).html('<i class="checkboxUnchecked"></i>' + deselect_all_text);
6841		$('.lesson_boxes > div').addClass('highlight');
6842		$('.modern_module_row').addClass('highlight');
6843	} else {
6844		$(link).html('<i class="checkboxChecked"></i>' + select_all_text);
6845		$('.lesson_boxes > div').removeClass('highlight');
6846		$('.modern_module_row').removeClass('highlight');
6847	}
6848}
6849
6850function toggle_all_groups(value, link) {
6851	var container = $('.catalog_boxes');
6852	container.find('input[name="select[]"]').prop('checked', value);
6853	$(link).attr('onclick', 'toggle_all_groups(' + (value ? 'false' : 'true') + ', this)');
6854
6855	if (value) {
6856		$(link).html('<i class="checkboxUnchecked"></i>' + deselect_all_text);
6857		container.find(' > *').addClass('highlight');
6858	} else {
6859		$(link).html('<i class="checkboxChecked"></i>' + select_all_text);
6860		container.find(' > *').removeClass('highlight');
6861	}
6862}
6863
6864function toggle_all_chat_rooms(value, link) {
6865	var container = $('.catalog_boxes');
6866	container.find('input[name="select[]"]').prop('checked', value);
6867	$(link).attr('onclick', 'toggle_all_chat_rooms(' + (value ? 'false' : 'true') + ', this)');
6868
6869	if (value) {
6870		$(link).html('<i class="checkboxUnchecked"></i>' + deselect_all_text);
6871		container.find(' > *').addClass('highlight');
6872	} else {
6873		$(link).html('<i class="checkboxChecked"></i>' + select_all_text);
6874		container.find(' > *').removeClass('highlight');
6875	}
6876}
6877
6878function toggle_all_games(value, link) {
6879  var container = $('.catalog_boxes');
6880  container.find('input[name="select[]"]').prop('checked', value);
6881  $(link).attr('onclick', 'toggle_all_games(' + (value ? 'false' : 'true') + ', this)');
6882
6883  if (value) {
6884    $(link).html('<i class="checkboxUnchecked"></i>' + deselect_all_text);
6885    container.find(' > *').addClass('highlight');
6886  } else {
6887    $(link).html('<i class="checkboxChecked"></i>' + select_all_text);
6888    container.find(' > *').removeClass('highlight');
6889  }
6890}
6891
6892function toggle_all_goals(value, link) {
6893	$('.goal_list').find('input[name="select[]"]').prop('checked', value);
6894	$(link).attr('onclick', 'toggle_all_goals(' + (value ? 'false' : 'true') + ', this)');
6895
6896	if (value) {
6897		$(link).html('<i class="checkboxUnchecked"></i>' + deselect_all_text);
6898		$('.goal_list .modern_module_row').addClass('highlight');
6899	} else {
6900		$(link).html('<i class="checkboxChecked"></i>' + select_all_text);
6901		$('.goal_list .modern_module_row').removeClass('highlight');
6902	}
6903}
6904
6905function toggle_all_bundle_items(value, link) {
6906    $('.goal_list').find('input[name="select[]"]').prop('checked', value);
6907    $(link).attr('onclick', 'toggle_all_bundle_items(' + (value ? 'false' : 'true') + ', this)');
6908
6909    if (value) {
6910        $(link).html('<i class="checkboxUnchecked"></i>' + deselect_all_text);
6911        $('.goal_list .modern_module_row').addClass('highlight');
6912    } else {
6913        $(link).html('<i class="checkboxChecked"></i>' + select_all_text);
6914        $('.goal_list .modern_module_row').removeClass('highlight');
6915    }
6916}
6917
6918function toggle_all_subscription_items(value, link) {
6919    $('.goal_list').find('input[name="select[]"]').prop('checked', value);
6920    $(link).attr('onclick', 'toggle_all_subscription_items(' + (value ? 'false' : 'true') + ', this)');
6921
6922    if (value) {
6923        $(link).html('<i class="checkboxUnchecked"></i>' + deselect_all_text);
6924        $('.goal_list .modern_module_row').addClass('highlight');
6925    } else {
6926        $(link).html('<i class="checkboxChecked"></i>' + select_all_text);
6927        $('.goal_list .modern_module_row').removeClass('highlight');
6928    }
6929}
6930
6931function goal_row_click(event, element_id){
6932  if (!$(event.target).is("label") && !$(event.target).is("a")) {
6933    window.location = document.getElementById(element_id).querySelector('.goal_list h2 > a').href;
6934  }
6935}
6936
6937function bundle_item_row_click(event, element_id){
6938    if (!$(event.target).is("label") && !$(event.target).is("a")) {
6939        window.location = document.getElementById(element_id).querySelector('.goal_list h2 > a').href;
6940    }
6941}
6942
6943function subscription_item_row_click(event, element_id){
6944    if (!$(event.target).is("label") && !$(event.target).is("a")) {
6945        window.location = document.getElementById(element_id).querySelector('.goal_list h2 > a').href;
6946    }
6947}
6948function toggle_all_users(value, link) {
6949	$('.user_boxes').find('input[name="select[]"]').prop('checked', value);
6950	$(link).attr('onclick', 'toggle_all_users(' + (value ? 'false' : 'true') + ', this)');
6951
6952	if (value) {
6953		$(link).html('<i class="checkboxUnchecked"></i>' + deselect_all_text);
6954		$('.user_boxes > a').addClass('highlight');
6955
6956		if ($('.search-navigation').length > 0) {
6957			$('#select_all_warning').html("<p>" + you_have_selected_all_text + " <a href='javascript:select_all_tiled_users();'>" + select_all_items_text + "</a></p>").show();
6958		}
6959	} else {
6960		$(link).html('<i class="checkboxChecked"></i>' + select_all_text);
6961		$('.user_boxes > a').removeClass('highlight');
6962		$('#select_all_warning').hide();
6963	}
6964}
6965
6966function toggle_all_awards(value, link) {
6967	$('.user_boxes').find('input[name="select[]"]').prop('checked', value);
6968	$(link).attr('onclick', 'toggle_all_awards(' + (value ? 'false' : 'true') + ', this)');
6969
6970	if (value) {
6971		$(link).html('<i class="checkboxUnchecked"></i>' + deselect_all_text);
6972		$('.user_boxes > *').addClass('highlight');
6973
6974		if ($('.search-navigation').length > 0) {
6975			$('#select_all_warning').html("<p>" + you_have_selected_all_text + " <a href='javascript:select_all_tiled_awards();'>" + select_all_items_text + "</a></p>").show();
6976		}
6977	} else {
6978		$(link).html('<i class="checkboxChecked"></i>' + select_all_text);
6979		$('.user_boxes > *').removeClass('highlight');
6980		$('#select_all_warning').hide();
6981	}
6982}
6983function init_options_bar(form_id) {
6984	var form = $('#' + form_id);
6985	update_options_bar(form);
6986}
6987
6988function update_options_bar(form) {
6989	var data = form.data('table');
6990
6991	if (data != null && data.popup) {
6992		if (form.find("input[type=checkbox][name='select[]']:checked").length) {
6993			show_options_bar(form);
6994		} else {
6995			hide_options_bar(form);
6996		}
6997	}
6998}
6999
7000function show_options_bar(container) {
7001	var div = container.find('.optionsRibbonTable_separate');
7002
7003	if (div.length) {
7004		div.css('display', '');
7005	}
7006}
7007
7008function hide_options_bar(container) {
7009	var div = container.find('.optionsRibbonTable_separate');
7010
7011	if (div.length) {
7012		div.css('display', 'none');
7013	}
7014}
7015
7016function show_options_bar_for(form_id) {
7017	var form = $('#' + form_id);
7018	var data = form.data('table');
7019
7020	if (data != null && data.popup) {
7021		var table = form.find('table');
7022		show_options_bar(table);
7023	}
7024}
7025
7026function select_all_items(form_id) {
7027	var form = $('#' + form_id);
7028	var form_id = form.attr('id');
7029	var tr = form.find('tr:eq(1)');
7030	var td = tr.find('td');
7031	td.html(all_items_selected_text + " <a class='select_all' href='javascript:unselect_all_items(\"" + form_id + "\");' style='vertical-align:0;'>" + clear_selection_text + "</a>");
7032	td.after("<input type='hidden' name='select_all' value='true'>");
7033}
7034
7035function unselect_all_items(form_id) {
7036	var form = $('#' + form_id);
7037	form.find('tr:eq(1)').remove();
7038	var checkboxes = form.find('input[type=checkbox]');
7039
7040	for (var i = 0; i < checkboxes.length; i++) {
7041		var checkbox = checkboxes[i];
7042		checkbox.checked = false;
7043		var row = $(checkbox).closest('tr');
7044		row.removeClass('highlight');
7045	}
7046
7047	var data = form.data('table');
7048
7049	if (data != null && data.popup) {
7050		var table = form.find('table');
7051		hide_options_bar(table);
7052	}
7053}
7054
7055function select_all_tiled_users() {
7056	$('.user_boxes').before("<input type='hidden' name='select_all' id='select_all_flag' value='true'>");
7057	$('#select_all_warning').html("<p>" + all_items_selected_text + " <a class='select_all' href='javascript:unselect_all_tiled_users();' style='vertical-align:0;'>" + clear_selection_text + "</a></p>");
7058}
7059
7060function unselect_all_tiled_users() {
7061	$('#select_all_flag').remove();
7062	toggle_all_users(false, '#toggle_users_link');
7063}
7064
7065function set_select(form_id, checkbox) {
7066	var checkboxes = $('input[name="' + form_id + '[]"]');
7067
7068	for (var i = 0; i < checkboxes.length; i++) {
7069		checkboxes[i].checked = checkbox.checked;
7070	}
7071}
7072
7073// checkbox utility
7074
7075function check_s(checkbox) {
7076	return (checkbox.checked == true ? 'true' : 'false');
7077}
7078
7079// optionsRibbon toggle
7080
7081function optionsRibbonToggle(name1, name2, thisLink) {
7082	$(thisLink).closest('ul').siblings().removeClass('selected');
7083	$(thisLink).closest('ul').addClass('selected');
7084	show_element(name1);
7085	hide_element(name2);
7086}
7087
7088// abstractions
7089
7090function expand(label) {
7091	show_element('remaining_' + label);
7092	hide_element(label);
7093}
7094
7095function collapse(label) {
7096	show_element(label);
7097	hide_element('remaining_' + label);
7098}
7099
7100function show_element(name) {
7101	$('#' + name).show();
7102	if ($('#' + name).find('textarea').hasClass('hasEditor')) {
7103		$('.tox div.tox-editor-header').each(function(){
7104			$(this).removeAttr('style');
7105		})
7106	}
7107}
7108
7109function hide_element(name) {
7110	$('#' + name).hide();
7111}
7112
7113function set_style_element(name, style) {
7114	$('#' + name).css(style);
7115}
7116
7117function highlight_element(name, parent) {
7118	if( parent) {
7119		$('#' + name).parent().effect("highlight", {}, 3000);
7120	} else {
7121		$('#' + name).effect("highlight", {}, 3000);
7122	}
7123}
7124
7125function fade_element(name) {
7126	$('#' + name).fadeOut();
7127}
7128
7129function remove_element(name) {
7130	$('#' + name).remove();
7131}
7132
7133function focus_element(name) {
7134	if(!is_mobile_app_mode()){
7135            var el = $('#' + name);
7136            if (el.val() && (el.is('input') || el.is('textarea'))) {
7137                var length = el.val().length;
7138                el.focus()[0].setSelectionRange(length, length);
7139            } else {
7140                el.focus();
7141            }
7142	}
7143}
7144
7145function clear_value(name) {
7146	$('#' + name).val('');
7147}
7148
7149function get_value(name) {
7150	return $('#' + name).val();
7151}
7152
7153function set_value(name, value) {
7154	$('#' + name).val(value);
7155}
7156
7157function is_checked(name) {
7158	return $('#' + name).attr('checked');
7159}
7160
7161function set_checked(name, value) {
7162	return $('#' + name).attr('checked', value);
7163}
7164
7165function set_html(name, value) {
7166	$('#' + name).html(value);
7167}
7168
7169function ajax_request(url, options) {
7170	if (options == null) {
7171		$.ajax({
7172			url : url,
7173			type : 'POST'
7174		});
7175	} else {
7176		$.ajax({
7177			url : url,
7178			type : 'POST',
7179			async : options.asynchronous
7180		});
7181	}
7182}
7183
7184function get_ajax_response(url, data, async) {
7185	var result;
7186
7187	if (async == null) {
7188		$.ajax({
7189			url : url,
7190			type : 'POST',
7191			dataType: data,
7192			success: function(response) {
7193				result = response;
7194			}
7195		});
7196	} else {
7197		$.ajax({
7198			url : url,
7199			type : 'POST',
7200			dataType: data,
7201			async : async,
7202			success: function(response) {
7203				result = response;
7204			}
7205		});
7206	}
7207
7208	return result;
7209}
7210
7211function get_ajax_response_async(url, data, callback) {
7212	$.ajax({
7213		url : url,
7214		type : 'POST',
7215		dataType: data,
7216		success: callback
7217	});
7218}
7219
7220function ajax_update(name, url, options) {
7221	$.post(url, function(data) {
7222		set_html(name, data);
7223	});
7224}
7225function ajax_update_data(name, url, options) {
7226	data = options;
7227	$.post(url, data, function(data) {
7228		set_html(name, data);
7229	});
7230}
7231
7232function submit_form(name) {
7233	$('#' + name).submit();
7234}
7235
7236function link_to_ajax(link_element, container_selector) {
7237	Excalibur.Location_tools.add_load_indicator($(container_selector), 100);
7238
7239	$.get($(link_element).attr('href'), function(data){
7240		setTimeout(function(){ $(container_selector).removeClass('extended-load').html(data); }, 200);
7241	});
7242
7243	return false;
7244}
7245
7246// reusable excalibur-click functions
7247
7248function toggle_visibility() {
7249	if (this.attr('aria-expanded') == 'true') {
7250		this.attr('aria-expanded', false);
7251	} else {
7252		this.attr('aria-expanded', true);
7253	}
7254
7255	this.find('> *').toggle();// toggle visibility icons
7256	$('#' + this.attr('data-element')).toggle();// toggle element
7257}
7258
7259// portal login
7260
7261function find_portal() {
7262	$('nav.mainNav ol > li:last-child div').removeClass('dDownShow');
7263
7264	$.facebox({
7265		'ajax' : '/info/find_portal?name=' + $('#portal_name').val()
7266	});
7267}
7268
7269function find_portal_new() {
7270	if($('#portal_name').val().length > 0) {
7271		$.facebox({
7272			'ajax': '/info/find_portal?name=' + $('#portal_name').val()
7273		});
7274	}else{
7275		$('#portal_name').css('border', '1px solid red').focus();
7276	}
7277}
7278
7279function submit_signup(){
7280	add_progress($('.signupForm button[type="submit"]'));
7281}
7282
7283// form concatenation for authorize.net integration
7284
7285function concat_form_fields() {
7286	$('#x_exp_date').val($('#x_month').val() + $('#x_year').val().substr(2,2));
7287}
7288
7289// display utilities
7290
7291function fade_alert() {
7292	closeAlertTimer = setInterval(function() {
7293		$('div.info').animate({
7294			height : '0',
7295			opacity : '0'
7296		}, 500, function() {
7297			$(this).css('display', 'none');
7298		});
7299	}, 3000);
7300}
7301
7302function get_maximum_upload_size() {
7303	return window.maxUploadLimit + 'mb';
7304}
7305
7306// show timer function
7307
7308function show_quiz_timer(id) {
7309	$("#" + id).on("change", function(){
7310		if ( $(this).is(':checked') ) {
7311			show_element('timer');
7312		} else {
7313			hide_element('timer');
7314		}
7315	});
7316}
7317
7318// show options
7319
7320function show_assignment_option_check(changed, hidden) {
7321  $("#" + changed).on("change", function(){
7322    if ( $(this).is(':checked') ) {
7323      show_element(hidden);
7324    } else {
7325      hide_element(hidden);
7326    }
7327  });
7328}
7329
7330function show_assignment_option_radio(changed, value, hidden) {
7331	$("input[id^='" + changed + "']").on("change", function () {
7332		var show = false;
7333
7334		if (Array.isArray(value)) {
7335			show = value.includes($(this).val());
7336		} else {
7337			show = $(this).val() == value;
7338		}
7339
7340		if (show) {
7341			show_element(hidden);
7342		} else {
7343			hide_element(hidden);
7344		}
7345	});
7346}
7347
7348// login credentials
7349
7350function display_login_credentials(secure_protocol, current_host, ssl_host, user_id, auth_token) {
7351	if (ssl_host.toUpperCase() == current_host.toUpperCase()) {
7352		$.ajax({
7353			type : 'POST',
7354			url : secure_protocol + '://' + current_host + '/user/get_login_info/' + user_id + (auth_token ? '?one_time_auth_token=' + auth_token : ''),
7355			dataType : 'json',
7356			success : function(json, text_status, jqXHR) {
7357				$('#userid_placeholder').html(json.userid);
7358				$('#password_placeholder').html(json.password);
7359			},
7360			error : function(jqXHR, text_status, errorThrown) {
7361				$.alert({content: 'error ' + text_status});
7362			}
7363		});
7364	} else {
7365		$.ajax({
7366			type : 'POST',
7367			url : 'https://' + current_host + '/authentication/get_auth_token',
7368			dataType : 'json',
7369			success : function(json, text_status, jqXHR) {
7370				display_login_credentials(secure_protocol, ssl_host, ssl_host, user_id, json.auth_token);
7371			},
7372			error : function(jqXHR, text_status, errorThrown) {
7373				$.alert({content: 'error ' + text_status});
7374			}
7375		});
7376	}
7377}
7378
7379function display_users_credentials(secure_protocol, current_host, ssl_host, controller, id, auth_token, key, user_allowed) {
7380	if (ssl_host.toUpperCase() == current_host.toUpperCase() || user_allowed) {
7381		var select = [];
7382
7383		$('tr[id^="user_"]').each(function() {
7384			select.push($(this).attr('id').split('_')[1]);
7385		});
7386
7387		$.ajax({
7388			type : 'POST',
7389			data : {
7390				'select' : select
7391			},
7392			url : secure_protocol + '://' + current_host + '/' + controller + '/get_login_info' + (id ? ('/' + id) : '') + (auth_token ? '?one_time_auth_token=' 
7392+ auth_token : '') + (key ? (auth_token ? '&key=' : '?key=') + key : ''),
7393			dataType : 'json',
7394			success : function(json, text_status, jqXHR) {
7395				for (var i = 0; i < json.users.length; i++) {
7396					var user = json.users[i];
7397					$('#userid_placeholder_' + user.id).html(user.userid);
7398					$('#password_placeholder_' + user.id).html(user.password);
7399				}
7400			},
7401			error : function(jqXHR, text_status, errorThrown) {
7402				$.alert({content: 'error ' + text_status});
7403			}
7404		});
7405	} else {
7406		$.ajax({
7407			type : 'GET',
7408			url : 'https://' + current_host + '/authentication/get_auth_token',
7409			dataType : 'json',
7410			success : function(json, text_status, jqXHR) {
7411				display_users_credentials(secure_protocol, ssl_host, ssl_host, controller, id, json.auth_token, key);
7412			},
7413			error : function(jqXHR, text_status, errorThrown) {
7414				$.alert({content: 'error ' + text_status});
7415			}
7416		});
7417	}
7418}
7419
7420// OnChange function for grading
7421
7422function no_grading() {
7423	var id = 'assignmentScore';
7424	var el = $('#facebox [name="assignment[grading]"]');
7425	var visible = $('#' + id).css("display");
7426
7427	if (visible === 'none') {
7428		el.parent().find('> label').addClass('min-w-76');
7429	}
7430
7431	el.on('change', function() {
7432		var val = $(this).val().toLowerCase();
7433		var chd = $(this).parent().find('span:first-child');
7434		var max_score_div = $('#' + id);
7435		var max_score_input = max_score_div.find("#assignment_max_score");
7436
7437		if (val === 'not graded') {
7438			max_score_div.hide();
7439			chd.next('label').addClass('min-w-76');
7440			if(isBlank(max_score_input.val())){
7441				max_score_input.val(100);
7442			}
7443		} else {
7444			max_score_div.show();
7445			$(this).parent().find('> label').removeClass('min-w-76');
7446		}
7447	});
7448}
7449
7450function no_grading_list() {
7451	var el = $('[name$="[grading]"]');
7452
7453	el.on('change', function() {
7454		var id = $(this).parent().attr('id');
7455		var val = $(this).val().toLowerCase();
7456		var mel = $('.max_score_' + id + ', .max_weight_' + id);
7457
7458		if (val === 'not graded') {
7459			mel.find('span:first-child').show();
7460			mel.find('span:last-child').hide();
7461		} else {
7462			mel.find('span:first-child').hide();
7463			mel.find('span:last-child').show();
7464		}
7465	});
7466}
7467
7468/* rule action message support */
7469
7470function show_message_content() {
7471	$('#message_type input').click(function() {
7472		if ($('#rule_action_message_type_custom').is(':checked')) {
7473		    $('.tox div.tox-editor-header').each(function(){
7474		        $(this).removeAttr('style');
7475		    });
7476
7477		    $('#canned_message').hide();
7478		    $('#custom_message').show();
7479		    $('#notification_type').show();
7480		    $('#send_copy_to_manager').show();
7481		} else if ($('#rule_action_message_type_canned').is(':checked')) {
7482		    $('#canned_message').show();
7483		    $('#custom_message').hide();
7484		    $('#notification_type').show();
7485		    $('#send_copy_to_manager').show();
7486		} else {
7487		    $('#canned_message').hide();
7488		    $('#custom_message').hide();
7489		    $('#notification_type').hide();
7490		    $('#send_copy_to_manager').hide();
7491		}
7492	});
7493}
7494
7495/**
7496 * =====================================================================
7497 * Session timeout functionality. Save everything in cookies so it will
7498 * be available inside every window of the browser.
7499 * Cookies expire on browser close ( = no expiration date specified )
7500 * =====================================================================
7501 * ===============================START=================================
7502 * =====================================================================
7503 */
7504
7505// session timeout -> Everything goes into cookies
7506// session_timeout_warning should not be cookie in order to open the warning pop-up in every window
7507
7508var next_countdown_value = null;
7509var session_timeout_warning = false;
7510var SESSION_WARNING_SECONDS = 30;
7511var SCAN_FRAME_SECONDS = 5;
7512var sessionTimeoutWorker = null;
7513
7514function session_timeout_after(seconds) {
7515	set_lms_cookie('session_timeout_seconds', parseInt(seconds), '/');
7516	start_session_timeout_timer();
7517	session_activity_monitor(session_activity_detected_callback);
7518	reset_session_timeout_timer();
7519}
7520
7521function start_session_timeout_timer() {
7522	// terminate old worker
7523	if (sessionTimeoutWorker) {
7524		sessionTimeoutWorker.terminate();
7525	}
7526
7527	sessionTimeoutWorker = new Worker('/javascripts/session_timeout_worker.js');
7528	sessionTimeoutWorker.onmessage = function (event) {
7529		if (event.data[0] === 'decrementSessionCountdown') {
7530			decrement_session_countdown();
7531		}
7532	}
7533
7534	sessionTimeoutWorker.postMessage(['initializeTimer']);
7535}
7536
7537function session_activity_detected_callback(is_frame){
7538	if (is_frame) {
7539		window.parent.session_activity_detected();
7540	} else {
7541		session_activity_detected();
7542	}
7543}
7544
7545function reset_session_timeout_timer() {
7546	set_lms_cookie('session_timeout_countdown', get_lms_cookie('session_timeout_seconds'), '/');
7547	next_countdown_value = parseInt(get_lms_cookie('session_timeout_seconds')) - 1;
7548	session_timeout_warning = false;
7549}
7550
7551function decrement_session_countdown() {
7552	// this was originally created for scorm. When scorm opens in a new window, we want to pause the session time out
7553	// to avoid logging the user out when she's working with the system in a window we cannot track.
7554	if(typeof(pause_session_timeout) !== 'undefined' && pause_session_timeout) {
7555		set_lms_cookie('session_timeout_countdown', next_countdown_value, '/');
7556		return;
7557	}
7558
7559	// make sure that only one window updates the countdown cookie
7560	if ((parseInt(get_lms_cookie('session_timeout_countdown')) - 1) == next_countdown_value) {
7561		set_lms_cookie('session_timeout_countdown', parseInt(get_lms_cookie('session_timeout_countdown')) - 1, '/');
7562	}
7563
7564	next_countdown_value = parseInt(get_lms_cookie('session_timeout_countdown')) - 1;
7565
7566	if ((parseInt(get_lms_cookie('session_timeout_countdown')) <= SESSION_WARNING_SECONDS) && session_timeout_warning == false) {
7567		session_timeout_warning = true;
7568		$.facebox({'ajax' : '/session_timeout/idle'});
7569	} else if (parseInt(get_lms_cookie('session_timeout_countdown')) <= 0) {
7570		window.location = '/log_out?timeout=true';
7571	} else if ((parseInt(get_lms_cookie('session_timeout_countdown')) > SESSION_WARNING_SECONDS) && session_timeout_warning == true) {
7572		session_timeout_warning = false;
7573		$.facebox.close();
7574	}
7575}
7576
7577function session_activity_detected() {
7578	if (session_timeout_warning && $('#facebox').find('.idle').length != 0) {
7579		$.facebox.close();
7580	}
7581
7582	reset_session_timeout_timer();
7583}
7584
7585//////////////////////////////////////////
7586// Session Activity Monitoring
7587//////////////////////////////////////////
7588
7589function session_activity_monitor(on_detect_activity_callback) {
7590	element_activity_detector(document, function(){ on_detect_activity_callback(false) });
7591	// frame_activity_monitor(undefined, on_detect_activity_callback);
7592	flowplayer_activity_detector(on_detect_activity_callback);
7593	youtube_activity_detector(on_detect_activity_callback);
7594	vimeo_activity_detector(on_detect_activity_callback);
7595}
7596
7597function element_activity_detector(element, on_detect_activity_callback ) {
7598	// the purpose of this variable is to throttle the callbacks
7599	var last_activity_reported_at = 0;
7600
7601	$(element).on('click mouseup mousedown touchend touchstart touchmove mousewheel mousemove keypress keydown', function(e) {
7602		if(Date.now() - last_activity_reported_at >= 1000) {
7603			last_activity_reported_at = Date.now();
7604			on_detect_activity_callback();
7605		}
7606	});
7607}
7608
7609function youtube_activity_detector(on_detect_activity_callback) {
7610	function report_youtube_activity() {
7611		if(youtube_players.some(function(player){ return typeof(player.getPlayerState) !== 'undefined' && player.getPlayerState() === YT.PlayerState.PLAYING })) {
7612			on_detect_activity_callback();
7613		}
7614		setTimeout(report_youtube_activity, 10000);
7615	}
7616
7617	var youtube_setup_checks = 0
7618	function setup_youtube_after_load() {
7619		// put a limit on the number of checks if sth goes wrong
7620		if(typeof(youtube_players) !== 'undefined' && youtube_players.length > 0){
7621			report_youtube_activity();
7622		} else {
7623			youtube_setup_checks +=1
7624			if(youtube_setup_checks < 11)
7625				setTimeout(setup_youtube_after_load, 1000);
7626		}
7627	}
7628
7629	setup_youtube_after_load();
7630}
7631
7632function vimeo_activity_detector(on_detect_activity_callback){
7633	// keep state if a video is playing
7634	var video_playing = false;
7635
7636	// check every 10 seconds if a video is playing and callback
7637	function report_video_activity() {
7638		if (video_playing) {
7639			on_detect_activity_callback();
7640		}
7641		setTimeout(report_video_activity, 10000);
7642	}
7643
7644	function set_vimeo_callbacks() {
7645		vimeo_players.forEach(function(player) {
7646			player.on('play', function() {
7647				video_playing = true;
7648			});
7649
7650			player.on('pause', function() {
7651				video_playing = false;
7652			});
7653
7654			player.on('ended', function() {
7655				video_playing = false;
7656			});
7657		});
7658	}
7659
7660	var vimeo_setup_checks = 0
7661	function setup_vimeo_after_load() {
7662		// put a limit on the number of checks if sth goes wrong
7663		if(typeof(vimeo_players) !== 'undefined' && vimeo_players.length > 0) {
7664			set_vimeo_callbacks();
7665			report_video_activity();
7666		} else {
7667			vimeo_setup_checks += 1
7668			if(vimeo_setup_checks < 11)
7669				setTimeout(setup_vimeo_after_load, 1000);
7670		}
7671	}
7672
7673	setup_vimeo_after_load();
7674}
7675
7676function flowplayer_activity_detector(on_detect_activity_callback){
7677	// keep state if a video is playing
7678	var video_playing = false;
7679
7680	// activity status update event
7681	$(window).on('videoActivityDetector.statusUpdate', function(e, statusData){
7682		if (statusData && statusData.hasOwnProperty('videoPlaying')) {
7683			if (statusData.videoPlaying) {
7684				video_playing = true;
7685				on_detect_activity_callback();
7686			} else {
7687				video_playing = false;
7688			}
7689		}
7690	});
7691
7692	// check every 10 seconds if a video is playing call the callback
7693	function report_video_activity() {
7694		if (video_playing) {
7695			on_detect_activity_callback();
7696		}
7697		setTimeout(report_video_activity, 10000);
7698	}
7699
7700	report_video_activity();
7701}
7702
7703// Frame activity monitor
7704function frame_activity_monitor(win, on_detect_activity_callback) {
7705	function getInnerFrame(win) {
7706		win = (win || window);
7707		var frames = win.frames;
7708
7709		if (frames.length > 0) {
7710			var i;
7711
7712			for (i=0; i < frames.length; i++) {
7713				element_activity_detector(frames[i], function(){ on_detect_activity_callback(true) });
7714
7715				getInnerFrame(frames[i]);
7716			}
7717		} else {
7718			return win;
7719		}
7720	}
7721
7722	if (win) {
7723		setInterval(function() {
7724			if (win.length) {
7725				getInnerFrame(win);
7726			}
7727		}, SCAN_FRAME_SECONDS * 1000);
7728	} else if (window.frames.length > 0) {
7729		setInterval(function() {
7730			getInnerFrame();
7731		}, SCAN_FRAME_SECONDS * 1000);
7732	}
7733}
7734
7735//////////////////////////////////////////
7736// END Session Activity Monitoring
7737//////////////////////////////////////////
7738
7739function display_timeout() {
7740	if ($('#facebox').find('.timeout').length == 0) {
7741		$.facebox({'ajax': '/session_timeout/timeout'});
7742	}
7743}
7744
7745function display_sync_popup(class_id, sync_job_id) {
7746  if ($('#facebox').find('.sync_popup').length == 0) {
7747    $.facebox({'ajax': '/session_group/sync_from_job/' + class_id + '?sync_job_id=' + sync_job_id});
7748  }
7749}
7750
7751function display_moved() {
7752  if ($('#facebox').find('.moved').length == 0) {
7753    $.facebox({'ajax': '/portal_moved/message'});
7754  }
7755}
7756
7757function display_deleted() {
7758	if ($('#facebox').find('.deleted').length == 0) {
7759		$.facebox({'ajax': '/info/deleted'});
7760	}
7761}
7762
7763function display_sso_error(message, title) {
7764	if ($('body').hasClass('portal') && $('#facebox').find('.sso').length == 0) {
7765		Excalibur.facebox({'ajax': '/sso/error?error=' + encodeURIComponent(message) + (title ? '&title=' + encodeURIComponent(title) : '')});
7766	} else if ($('body').hasClass('loginPage')) {
7767		var alertBlock = $('<div class="alert_block error" style="width:auto" role="alert"><div class="alert_flex"><div class="alert_icon"><i class="error inverted"></i></div><p></p></div></div>');
7768		alertBlock.find('p').text(message);
7769		$('#loginForm #alerts').empty().append(alertBlock).show();
7770	}
7771}
7772
7773/**
7774 * ======================================
7775 * Standard GET/SET functions for COOKIES
7776 * ======================================
7777 */
7778
7779function get_lms_cookie(name) {
7780	var value = document.cookie;
7781	var start = value.indexOf(" " + name + "=");
7782
7783	if (start == -1) {
7784		start = value.indexOf(name + "=");
7785	}
7786
7787	if (start == -1) {
7788		value = null;
7789	} else {
7790		start = value.indexOf("=", start) + 1;
7791		var end = value.indexOf(";", start);
7792
7793		if (end == -1) {
7794			end = value.length;
7795		}
7796
7797		value = unescape(value.substring(start, end));
7798	}
7799
7800	return value;
7801}
7802
7803function set_lms_cookie(name, value, path, exdays) {
7804	var exdate = new Date();
7805	exdate.setDate(exdate.getDate() + exdays);
7806	value = escape(value);
7807
7808	if (path != null) {
7809		value += "; path=" + path;
7810	}
7811
7812	if (exdays != null) {
7813		value += "; expires=" + exdate.toUTCString();
7814	}
7815
7816	document.cookie = name + "=" + value;
7817}
7818
7819/**
7820 * =====================================================================
7821 * Here is where the dropdown for messages magic happens:
7822 * - infinite scroll with ajax
7823 * - view message / send message popups
7824 * - keep mouse wheel scroll inside the div
7825 * - auto-suggest multiple receivers with remove option ( tag style )
7826 * - ajax delete
7827 * - reply, reply to forum and send message using ajax
7828 * - IE focus forcer...
7829 * =====================================================================
7830 * ===============================START=================================
7831 * =====================================================================
7832 */
7833
7834/* Message box get message */
7835var box_offset = 0;
7836var box_limit = 10;
7837var scroll_check_mess =  scroll_check_not = true;
7838
7839function call_for_messages(container, controller) {
7840	var holder = $(container).find('.dropDown ul');
7841	isolatedScroll($(container).find('.dropDown .scroll'));
7842	holder.html('').append('<div class="loader"></div>');
7843	box_offset = 0;
7844
7845	if (holder.find('li').length == 0) {
7846		ajax_call_for_messages(holder, container, controller);
7847
7848		if (container == '.messagesHolder' && scroll_check_mess) {
7849			exec_scroll(holder, container, controller);
7850		}
7850 else if (container == '.notificationsHolder' && scroll_check_not) {
7851			exec_scroll(holder, container, controller);
7852		}
7853	}
7854
7855	if (container == '.messagesHolder') {
7856		just_read_message();
7857	} else if (container == '.notificationsHolder') {
7858		just_read_notification();
7859	}
7860}
7861
7862function ajax_call_for_messages(holder, container, controller) {
7863	$.ajax({
7864		type : "POST",
7865		url : "/" + controller + "/get_messages",
7866		data : {
7867			offset : box_offset,
7868			limit : box_limit
7869		},
7870		dataType : "json",
7871		async : false,
7872		success : function(data) {
7873			var k_read_at = false;
7874
7875			holder.find('.loader').remove();
7876
7877			if (data.count == 0) {
7878				var empty_message_icon = (controller == 'inbox' ? 'messages' : 'notifications');
7879				var empty_message = (controller == 'inbox' ? no_messages_text : no_notifications_text);
7880				holder.html('').append('<p class="center px14">' + empty_message + '<br><img src="/images/icons/large/empty-' + empty_message_icon + '.svg" width="100" /></p>');
7881			} else if (data.count >= box_offset) {
7882				for (var i = 0; i < data.messages.length; i++) {
7883					var message = data.messages[i];
7884					var class_name = message.class_name;
7885					var forum = (message.forum ? message.forum : null);
7886					var html = '';
7887
7888					html += '<li class="ms-holder message-' + message.id + '" id="message-' + message.id + '">';
7889					html += '<a href="/' + controller + '/show?popup=true&' + (controller == 'inbox' ? 'message' : 'notification' ) + '=' + message.id + '"  onclick="return popup_clicked(this);" class="ms-main-open" role="button">';
7890					html += '<span class="ms-image"><img src="' + message.photo + '" width="30" height="30" alt="" /></span>';
7891					html += '<span class="ms-user">' + message.first_name + ' ' + message.last_name;
7892					html += ( class_name ? ' - <span class="ms-class-name">' + class_name + '</span>' : '');
7893					html += ( forum ? ' <span class="ms-arrow"></span> ' + forum : '');
7894					html += '</span>';
7895					html += '<span class="ms-subject">' + message.name + '</span>';
7896					html += '<span class="ms-date">' + message.date + '</span>';
7897          html += '</a>';
7898
7899          html += '<a href="#" excalibur-click="load_un_read_bindings" class="ms-status-holder" role="button">';
7900
7901					if (message.read_at) {
7902            html += '<span class="ms-status left" data-tooltip="' + mark_as_unread_text + '"><i class="tick icnColor"></i><span class="textOffScreen">Mark as unread</span></span>';
7903					} else {
7904            html += '<span class="ms-status unread left" data-tooltip="' + mark_as_read_text + '"><i class="xCross icnColor"></i><span class="textOffScreen">Mark as read</span></span>';
7905						k_read_at = true;
7906					}
7907
7908					html += '</a>';
7909					html += '</li>';
7910
7911					holder.append(html);
7912
7913          $('#message-' + message.id + ' a.ms-main-open').on('click', function() {
7914            var parent =  $(this).parent();
7915
7916            if (parent.hasClass('ms-unread')) {
7917              parent.find('.ms-status-holder').html('<span class="ms-status" title="' + mark_as_unread_text + '"><i class="tick icnColor"></i><span class="textOffScreen">Mark as unread</span></span>');
7918
7919              // change the newAlert counter value after unread message was opened
7920              var newAlert = $(this).parents(container).find('.newAlert');
7921              var messIcon = newAlert.next('i');
7922
7923              if (newAlert.length != 0) {
7924                var newAlertValue = parseInt(newAlert.text());
7925
7926                if (newAlertValue > 1) {
7927                  newAlert.text(newAlertValue - 1);
7928                } else {
7929                  messIcon.removeClass('messages').addClass('unread');
7930                  newAlert.remove();
7931                }
7932              }
7933            }
7934          });
7935
7936				}
7937			}
7938
7939			if ( k_read_at ) {
7940				$(container).find('.markAllAsRead').show();
7941			}
7942
7943			box_offset += 10;
7944			isolatedScroll($(container).find('.dropDown .scroll'));
7945		}
7946	});
7947}
7948
7949function load_un_read_bindings() {
7950    var el = this;
7951    var id = el.parent('li').attr('id').split('-')[1];
7952
7953    if (el.parents('.notificationsHolder').length > 0) {
7954      un_read_update_status('notifications', '.notificationsHolder', id);
7955    } else if (el.parents('.messagesDropDown').length > 0) {
7956      un_read_update_status('inbox', '.messagesHolder', id);
7957    }
7958}
7959
7960function un_read_update_status(controller, container, id) {
7961  $.post('/' + controller + '/mark_un_read', {posting: id}, function(response) {
7962    if (response.status === 'ok') {
7963      un_read_action(container, id);
7964    } else {
7965      alert(response.message);
7966    }
7967  });
7968}
7969
7970function un_read_action(container, id) {
7971  var el = $(container + ' li.message-' + id);
7972  var status = el.find('span.ms-status i');
7973
7974  if (status.attr('class').indexOf('xCross') != -1) {
7975    status.removeClass('xCross').addClass('tick');
7976    status.parent('span').attr('data-tooltip', mark_as_unread_text);
7977    status.parent('span').find('.textOffScreen').text(mark_as_unread_text);
7978    un_read_update_counters(container, -1);
7979  } else {
7980    status.removeClass('tick').addClass('xCross');
7981    status.parent('span').attr('data-tooltip', mark_as_read_text);
7982    status.parent('span').find('.textOffScreen').text(mark_as_read_text);
7983    un_read_update_counters(container, 1);
7984  }
7985}
7986
7987function un_read_update_counters(container, value) {
7988  var counter = $(container + ' span.newAlert');
7989
7990  if (counter.length == 0) {
7991    $(container + ' > a').prepend('<span class="newAlert"></span>');
7992    counter = $(container).find('span.newAlert');
7993  }
7994
7995  var count = ((counter.text() == '' || isNaN(counter.text())) ? 0 : parseInt(counter.text())) + value;
7996
7997  if (count > 0) {
7998    counter.html(count);
7999    $(container + ' a.markAllAsRead').show();
8000
8001    if (container == '.messagesHolder' && $(container + '  a  i').hasClass('unread')) {
8002      $(container + ' > a  i').removeClass('unread').addClass('messages');
8003    }
8004  } else {
8005    counter.remove();
8006    $(container + ' a.markAllAsRead').hide();
8007
8008    if (container == '.messagesHolder' && $(container + '  a  i').hasClass('messages')) {
8009      $(container + ' > a  i').removeClass('messages').addClass('unread');
8010    }
8011  }
8012}
8013
8014// scroll
8015
8016function exec_scroll(holder, container, controller) {
8017	$(container).find('.scroll').scroll(function(e) {
8018		if (e.target.scrollTop >= (e.target.scrollHeight - e.target.clientHeight)) {
8019			ajax_call_for_messages(holder, container, controller);
8020		}
8021	});
8022
8023	if (controller == 'inbox') {
8024		scroll_check_mess = false;
8025	} else if (controller = 'notifications') {
8026		scroll_check_not = false;
8027	}
8028}
8029
8030// Isolate the scroll inside the element from the page
8031
8032function isolatedScroll(element) {
8033	element.bind('mousewheel DOMMouseScroll', function(e) {
8034		var delta = (e.wheelDelta || (e.originalEvent && e.originalEvent.wheelDelta) || -e.detail);
8035		var bottomOverflow = ((this.scrollTop + $(this).outerHeight() - this.scrollHeight) >= 0);
8036		var topOverflow = (this.scrollTop <= 0);
8037
8038		if ((delta < 0 && bottomOverflow) || (delta > 0 && topOverflow)) {
8039			e.preventDefault();
8040		}
8041	});
8042
8043	return element;
8044}
8045
8046function call_for_jobs(container) {
8047  $.get('/profile_jobs/jobs', function(html) {
8048    $(container + ' ul').html(html);
8049  });
8050}
8051
8052// memory variable with the user selections field,
8053// it's an array of Objects, every Object being a selection
8054// we need it to re-populate the field if error in sending process
8055var select2_memory = {};
8056select2_memory.to = [];
8057select2_memory.cc = [];
8058select2_memory.bcc = [];
8059var select2_data = [];
8060var select2_data_size = 0;
8061
8062var select2_data_cc = [];
8063var select2_data_cc_size = 0;
8064
8065// Auto suggest input for the send message box
8066
8067function autoSuggestInit(element, selected_elems_size, selected_elems) {
8068	var el = $(element), results, preload_data, ln, fn, tln, tfn, tlnfn, tfnln, q;
8069	var recipient_type = element.split("#")[1];
8070
8071	select2_memory.to = [];
8072	select2_memory.cc = [];
8073	select2_memory.bcc = [];
8074
8075	if (selected_elems != undefined && (selected_elems.length > 0)) {
8076		select2_memory[recipient_type] = selected_elems;
8077	}
8078
8079	var max_selection_size;
8080	if (recipient_type == 'to') {
8081		select2_data = select2_memory.to;
8082		select2_data_size = parseInt(selected_elems_size);
8083		max_selection_size = (select2_data.length > 0 ? (select2_data.length + 10) : 10);
8084	} else if (recipient_type == 'cc') {
8085		select2_data_cc = select2_memory.cc;
8086		select2_data_cc_size = parseInt(selected_elems_size);
8087		max_selection_size = (select2_data_cc.length > 0 ? (select2_data_cc.length + 10) : 10);
8088	} else {
8089		max_selection_size = 10;
8090	}
8091
8092	el.select2({
8093		multiple : true,
8094		maximumSelectionSize : max_selection_size, // for limitation of people number in the "to" fields
8095		minimumInputLength : 2, // minimum chars to start the suggest query
8096		ajax : {
8097			type : "GET",
8098			url : "/inbox/suggest_users",
8099			dataType : 'json',
8100			quietMillis : 500, // bigger delay before ajax is called
8101			data : function(term) {
8102				q = term;
8103				return {
8104					name : q
8105				};
8106			},
8107			results : function(data) {
8108				results = {
8109					results : []
8110				};
8111				preload_data = data.results;
8112
8113				$.each(preload_data, function() {
8114					ln = this.last_name;
8115					fn = this.first_name;
8116					tln = ln.toUpperCase();
8117					tfn = fn.toUpperCase();
8118					tfnln = tfn + ' ' + tln;
8119					tlnfn = tln + ' ' + tfn;
8120
8121					q = q.trim();
8122					q = q.toUpperCase();
8123
8124					if (tln.indexOf(q) >= 0 || tfn.indexOf(q) >= 0 || tfnln.indexOf(q) >= 0 || tlnfn.indexOf(q) >= 0) {
8125						results.results.push({
8126							id : this.id,
8127							text : fn + ' ' + ln
8128						});
8129					}
8130				});
8131
8132				// the #to input will contain the ids: id1,id2,id3
8133				return results;
8134			}
8135		}
8136	}).on('change', function() {
8137		select2_memory[$(this).attr('id')] = $(this).select2('data');
8138
8139		if ($(this).attr('id') == 'to') {
8140			select2_data = select2_memory[$(this).attr('id')];
8141			select2_data_size = select2_data.length;
8142		}
8143		if ($(this).attr('id') == 'cc') {
8144			select2_cc_data = select2_memory[$(this).attr('id')];
8145			select2_cc_data_size = select2_cc_data.length;
8146		}
8147	});
8148
8149	if (select2_memory[recipient_type].length > 0) {
8150		el.data().select2.updateSelection(select2_memory[recipient_type]);
8151
8152		if (select2_data_size > 5 && recipient_type == 'to') {
8153			setTimeout(function() {
8154				add_sender_placeholder(select2_data, select2_data_size, '#s2id_to');
8155			}, 100);
8156		}
8157		if (select2_data_cc_size > 5 && recipient_type == 'cc' ) {
8158			setTimeout(function() {
8159				add_sender_placeholder(select2_data_cc, select2_data_cc_size, '#s2id_cc');
8160			}, 100);
8161		}
8162	}
8163}
8164
8165function autoSuggestSpecificInit(element, selected_elems_size, selected_elems) {
8166	var el = $(element), results, preload_data, ln, fn, tln, tfn, tlnfn, tfnln, q;
8167	var recipient_type = element.split("#")[1];
8168
8169	select2_memory.to = [];
8170
8171	if (selected_elems != undefined && (selected_elems.length > 0)) {
8172		select2_memory[recipient_type] = selected_elems;
8173	}
8174
8175	select2_data = select2_memory.to;
8176	select2_data_size = parseInt(selected_elems_size);
8177
8178	el.select2({
8179		multiple : true,
8180		maximumSelectionSize : 1, // for limitation of people number in the "to" fields
8181		minimumInputLength : 2, // minimum chars to start the suggest query
8182		ajax : {
8183			type : "GET",
8184			url : "/inbox/suggest_specific_users",
8185			dataType : 'json',
8186			quietMillis : 500, // bigger delay before ajax is called
8187			data : function(term) {
8188				q = term;
8189				return {
8190					name : q
8191				};
8192			},
8193			results : function(data) {
8194				results = {
8195					results : []
8196				};
8197				preload_data = data.results;
8198
8199				$.each(preload_data, function() {
8200					ln = this.last_name;
8201					fn = this.first_name;
8202					tln = ln.toUpperCase();
8203					tfn = fn.toUpperCase();
8204					tfnln = tfn + tln;
8205					tlnfn = tln + tfn;
8206
8207					q = q.replace(" ", "");
8208					q = q.toUpperCase();
8209
8210					if (tln.indexOf(q) >= 0 || tfn.indexOf(q) >= 0 || tfnln.indexOf(q) >= 0 || tlnfn.indexOf(q) >= 0) {
8211						results.results.push({
8212							id : this.id,
8213							text : fn + ' ' + ln
8214						});
8215					}
8216				});
8217
8218				// the #to input will contain the ids: id1,id2,id3
8219				return results;
8220			}
8221		}
8222	}).on('change', function() {
8223		select2_memory[$(this).attr('id')] = $(this).select2('data');
8224
8225		if ($(this).attr('id') == 'to') {
8226			select2_data = select2_memory[$(this).attr('id')];
8227			select2_data_size = select2_data.length;
8228		}
8229		if ($(this).attr('id') == 'cc') {
8230			select2_data_cc = select2_memory[$(this).attr('id')];
8231			select2_data_cc_size = select2_data_cc.length;
8232		}
8233	});
8234
8235	if (select2_memory[recipient_type].length > 0) {
8236		el.data().select2.updateSelection(select2_memory[recipient_type]);
8237
8238		if (select2_data_size > 5) {
8239			setTimeout(function(){
8240				add_sender_placeholder(select2_data, select2_data_size, '#s2id_to');
8241			}, 100);
8242		} else if (select2_data_cc > 5) {
8243			setTimeout(function () {
8244				add_sender_placeholder(select2_data_cc, select2_data_cc_size, '#s2id_cc');
8245			}, 100);
8246		}
8247	}
8248}
8249
8250// Auto suggest input also supporting arbitrary emails
8251
8252function autoSuggestEmailInit(element, selected_elems_size, selected_elems) {
8253	var el = $(element), results, preload_data, ln, fn, tln, tfn, tlnfn, tfnln, q;
8254	var select2_memory = [];
8255
8256	if (selected_elems != undefined && (selected_elems.length > 0)) {
8257		select2_memory = selected_elems;
8258	}
8259
8260	var max_selection_size = (select2_memory.length > 0 ? (select2_memory.length + 10) : 10);
8261
8262	el.select2({
8263		multiple : true,
8264		maximumSelectionSize : max_selection_size, // for limitation of people number in the fields
8265		minimumInputLength : 2, // minimum chars to start the suggest query
8266		containerCssClass: 'select2-popup-input',
8267		ajax : {
8268			type : "GET",
8269			url : "/report/suggest_users_and_email",
8270			dataType : 'json',
8271			quietMillis : 500, // bigger delay before ajax is called
8272			data : function(term) {
8273				q = term;
8274				return {
8275					name : q
8276				};
8277			},
8278			results : function(data) {
8279				results = {
8280					results : []
8281				};
8282				preload_data = data.results;
8283
8284				$.each(preload_data, function() {
8285					ln = this.last_name;
8286					fn = this.first_name;
8287					tln = ln.toUpperCase();
8288					tfn = fn.toUpperCase();
8289					tfnln = tfn + ' ' + tln;
8290					tlnfn = tln + ' ' + tfn;
8291
8292					q = q.trim();
8293					q = q.toUpperCase();
8294
8295					if (tln.indexOf(q) >= 0 || tfn.indexOf(q) >= 0 || tfnln.indexOf(q) >= 0 || tlnfn.indexOf(q) >= 0) {
8296						if (ln.length > 0) {
8297							// It's an existing user
8298							results.results.push({
8299								id : 'user|' + this.id,
8300								text : fn + ' ' + ln
8301							});
8302						} else {
8303							// It's an email address
8304							results.results.push({
8305								id : this.id,
8306								text : fn
8307							});
8308						}
8309					}
8310				});
8311
8312				return results;
8313			}
8314		}
8315	}).on('change', function() {
8316		select2_memory = $(this).select2('data');
8317		select2_data = select2_memory;
8318		select2_data_size = select2_data.length;
8319	});
8320
8321	if (select2_memory.length > 0) {
8322		el.data().select2.updateSelection(select2_memory);
8323
8324		if (select2_data_size > 5) {
8325			setTimeout(function() {
8326				add_sender_placeholder(select2_data, select2_data_size, '#s2id_send_to_emails');
8327			}, 100);
8328		}
8329	}
8330}
8331
8332function popup_delete(element) {
8333	var url = $(element).attr('href');
8334	var id = url.split('=')[1];
8335	var extra = url.split('=')[0].split('?')[1];
8336	var parent;
8337
8338	if (extra == 'message') {
8339		parent = '.messagesHolder';
8340	} else {
8341		parent = '.notificationsHolder';
8342	}
8343
8344	$.confirm({
8345		content : are_you_sure_text,
8346		confirm : function() {
8347			$.ajax({
8348				type : "POST",
8349				url : url,
8350				complete : function() {
8351					var el = $(parent).find('.message-' + id);
8352
8353					if (el.length != 0) {
8354						el.remove();
8355					}
8356
8357					$.facebox.close();
8358				}
8359			});
8360		}
8361	});
8362
8363	return false;
8364}
8365
8366function scroll_to_bottom(element) {
8367	setTimeout(function() {
8368		var el = $(element).find('> h2').last();
8369
8370		$(element).animate({
8371			scrollTop : el.offset().top - 115
8372		}, 0);
8373	}, 50);
8374}
8375
8376// send message and replies using ajax
8377
8378function ajax_send(element) {
8379	var url = $('.messageSendPopup').parent('form').attr('action');
8380
8381	if ((typeof(tinymce) == 'undefined') || (tinymce.get('popupContent') == null)) {
8382		var content = $('.messageSendPopup #popupContent').html();
8383	} else {
8384		var content = tinymce.get('popupContent').getContent();
8385	}
8386
8387	var obj = {
8388		url : url,
8389		data : {
8390			to : $('.messageSendPopup #to').val(),
8391			cc : $('.messageSendPopup #cc').val(),
8392			bcc : $('.messageSendPopup #bcc').val(),
8393			subject : $('.messageSendPopup #subject').val(),
8394			content : content,
8395      field : $('.messageSendPopup #field').val()
8396		}
8397	};
8398
8399	ajax_send_message(obj, element);
8400	return false;
8401}
8402
8403function ajax_reply(element) {
8404	var url = $('.replyPopup').parent('form').attr('action').split('?');
8405
8406	if ((typeof(tinymce) == 'undefined') || (tinymce.get('popupContent') == null)) {
8407		var content_container = $('.replyPopup #popupContent');
8408
8409		if (content_container.is("textarea")) {
8410			var content = content_container.val();
8411		} else {
8412			var content = content_container.html();
8413		}
8414	} else {
8415		var content = tinymce.get('popupContent').getContent();
8416	}
8417
8418	var obj = {
8419		url : url[0],
8420		data : {
8421			to : $('.replyPopup #to').val(),
8422			cc : $('.replyPopup #cc').val(),
8423			bcc : $('.replyPopup #bcc').val(),
8424			message : url[1].split('=')[1],
8425			subject : $('.replyPopup #subject').val(),
8426			content : content,
8427			reply_to_all : $('.replyPopup #reply-to-all').val(),
8428			ajax : true
8429		}
8430	};
8431
8432	ajax_send_message(obj, element);
8433	return false;
8434}
8435
8436function ajax_reply_to_forum(element) {
8437	var url = $('.replyPopup').parents('form').attr('action').split('?');
8438
8439	var obj = {
8440		url : url[0],
8441		data : {
8442			message : url[1].split('=')[1],
8443			notification : url[1].split('=')[1],
8444			content : tinymce.get('popupContent').getContent(),
8445			ajax : true
8446		}
8447	};
8448
8449	ajax_send_message(obj, element);
8450	return false;
8451}
8452
8453function ajax_send_message(obj, element) {
8454	element.disabled = true;
8455
8456	$.ajax({
8457		type : 'POST',
8458		url : obj.url,
8459		data : obj.data,
8460		dataType : 'json'
8461	}).done(function(data) {
8462		if (data.error) {
8463			element.disabled = false;
8464			const $popup = ($('body.evo').length ? $('.modal.is-open') : $('#facebox'));
8465			$popup.find('.alert_block.error').remove();
8466			$popup.find('#alerts').after('<div class="alert_block error" role="alert"><div class="alert_flex"><div class="alert_icon"><i class="error inverted"></i></div><p>' + data.error + '</p><a href=""><i class="xCrossSmall"></i><span class="textOffScreen">Close alert</span></a></div></div>');
8467
8468		} else {
8469			tinyPop = false;
8470
8471			if (select2_memory) {
8472				select2_memory.to = [];
8473				select2_memory.cc = [];
8474				select2_memory.bcc = [];
8475				$('.messageSendPopup #to').val('');
8476			}
8477
8478			$.facebox.close();
8479
8480			$('#centreColumn').find('> .info').remove();
8481			$('#centreColumn').find('#alerts').after('<div class="alert_block info" role="alert"><div class="alert_flex"><div class="alert_icon"><i class="info inverted"></i></div><p>' + data.info + '</p><a href=""><i class="xCrossSmall"></i><span class="textOffScreen">Close alert</span></a></div></div>');
8482
8483			// reset the fade_alert() interval
8484			clearInterval(closeAlertTimer);
8485			fade_alert();
8486
8487			tinyPop = true;
8488		}
8489	});
8490}
8491
8492function tinyMceFocusForce(editor_id) {
8493	var check_interval = setInterval(function() {
8494		if (tinymce.get(editor_id)) {
8495			tinymce.get(editor_id).focus();
8496			clearInterval(check_interval);
8497		}
8498	}, 10);
8499}
8500
8501// notifications
8502
8503var notification_main_wrapper = '.notificationsPopUpHolder';
8504var notifications_timer = null;
8505var notification_close_after = 5000;
8506var notifications_timer_cycles = 0;
8507var notifications_play_sound = false;
8508var notifications_close_arrow;
8509
8510function init_notifications_popup(sounds) {
8511	notifications_play_sound = sounds;
8512
8513	if(!is_mobile_app_mode()) {
8514		notifications_close_arrow = $(notification_main_wrapper).find('.notificationsBottom span');
8515		notifications_click_outside();
8516
8517		notifications_close_arrow.on('click', function (data) {
8518			$.each($(notification_main_wrapper).find('> div > ul li'), function () {
8519				$(this).animate({height: '0'}, 300, function () {
8520					$(this).remove();
8521					notifications_hide_arrow();
8522				});
8523			});
8524		});
8525	}
8526}
8527
8528function notifications_click_outside() {
8529	$('html *').on('click', function(e) {
8530		if ($(this).hasClass('closeNotifications') || $(this).parent('span').hasClass('closeNotifications')) {
8531			$('.notificationsPopUpHolder').find('li').animate({'height' : '0'}, 300, function() {
8532				$(this).remove();
8533				notifications_hide_arrow();
8534			});
8535		}
8536
8537		if (($(this).parents('.notificationsPopUpHolder').length == 1) || ($(this).parents('#facebox').length == 1)) {
8538			//e.stopPropagation();
8539		} else {
8540			$('.notificationsPopUpHolder').find('li').animate({'height' : '0'}, 300, function() {
8541				$(this).remove();
8542				notifications_hide_arrow();
8543			});
8544		}
8545	});
8546}
8547
8548function notifications_listener(e) {
8549  var data = e.detail.data;
8550
8551  var messages = data.messages;
8552  var notifications = data.alerts;
8553  var new_messages = (messages && (messages.length > 0));
8554  var new_notifications = (notifications && (notifications.length > 0));
8555  var notifications_to_pop = [];
8556  var show_dropdown = false;
8557
8558  update_top_nav_counter(data.new_messages_count, '.messagesHolder', '.mobileMessagesHolder');
8559  update_top_nav_counter(data.new_notifications_count, '.notificationsHolder', '.mobileNotificationsHolder');
8560
8561  if (new_messages || new_notifications) {
8562    if (notifications_play_sound == true) {
8563      notifications_sound();
8564    }
8565
8566    if (new_messages) {
8567      $.each(messages, function (key, value) {
8568        $('.notificationsPopUpHolder ul').append(notifications_html('message', value));
8569        notifications_animate(notification_main_wrapper + ' .message-' + value.id);
8570        show_dropdown = true;
8571      });
8572    }
8573
8574    if (new_notifications) {
8575      $.each(notifications, function (key, value) {
8576        if (value.popup == true) {
8577          notifications_to_pop.push(value);
8578        } else {
8579          $('.notificationsPopUpHolder ul').append(notifications_html('notification', value));
8580          notifications_animate(notification_main_wrapper + ' .notification-' + value.id);
8581          show_dropdown = true;
8582        }
8583      });
8584    }
8585
8586    if (show_dropdown == true) {
8587      $(notification_main_wrapper).find('.notificationsBottom').css('display', 'block');
8588    }
8589
8590    notifications_popups(notifications_to_pop);
8591
8592    if (is_mobile_app_mode()) {
8593      send_header_to_app();
8594      window.parent.postMessage('{"method": "notificationsPopup", "content": "1"}', '*');
8595    }
8596  }
8597}
8598
8599function notifications_popups(notifications) {
8600	var stack = {};
8601
8602	stack.className = 'vex-theme-os';
8603	stack.initialDialogsClassName = 'vex-theme-os vex-theme-stack-demo';
8604
8605	stack.advanceDemoDialogs = function () {
8606		var $remaining = $('.stack > .vex:not(".vex-closing")');
8607		$('.stack').show();
8608		$.each($remaining.removeClass('v0 v1 v2 v3 v4').toArray().reverse(), function (i, item) {
8609			$(item).addClass('v' + i);
8610		});
8611	};
8612
8613	$.each(notifications, function (index, notification) {
8614		$.ajax({
8615			url: '/notifications/show',
8616			data: {small: true, popup: true, notification: notification.id},
8617			dataType: 'html',
8618			async: false,
8619			success: function (html) {
8620				vex.dialog.alert({
8621					appendLocation: '.stack',
8622					unsafeMessage: html,
8623					className: stack.initialDialogsClassName,
8624					callback: function (value) {
8625						setTimeout(function () {
8626							stack.advanceDemoDialogs();
8627						}, 0);
8628					}
8629				});
8630				window.focusTrap && focusTrap.deactivate();
8631
8632				window.focusTrap && focusTrap.deactivate();
8633
8634				stack.advanceDemoDialogs();
8635
8636        var timer = 0;
8637
8638        $.each($($.parseHTML(html, document, true)).find('script'), function(index, value) {
8639          setTimeout(function() {
8640            if (value.src == '') {
8641              eval(value.text);
8642            } else {
8643              eval($.getScript(value.src));
8644            }
8645          }, timer);
8646
8647          timer = timer + 100;
8648        });
8649
8650				$(window).trigger('notificationLoaded');
8651			}
8652		});
8653	});
8654}
8655
8656function notifications_html(type, notification) {
8657	var html = '';
8658	var url;
8659
8660	if (type == 'notification') {
8661		url = '/notifications/show?popup=true&amp;notification=' + notification.id;
8662		icon = 'signal3';
8663	} else {
8664		url = '/inbox/show?popup=true&amp;message=' + notification.id;
8665		icon = 'messages';
8666	}
8667
8668	html += '<li class="ms-holder ' + type + '-' + notification.id + '" style="height: 57px;">';
8669	html += '<a href="' + url + '" onclick="return popup_clicked(this);" role="button">';
8670	html += '<span class="ms-image"><img src="' + notification.photo + '" width="30" height="30" alt=""></span>';
8671	html += '<span class="ms-user">' + notification.first_name + ' ' + notification.last_name + '</span>';
8672	html += (notification.class_name ? ' - <span class="ms-class-name">' + notification.class_name + '</span>' : '');
8673	html += (notification.forum ? ' <span class="ms-arrow"></span> ' + notification.forum : '');
8674	html += '<span class="ms-subject">' + notification.name + '</span>';
8675	html += '<span class="ms-date">' + notification.date + '</span>';
8676	html += '<span class="ms-status"><i class="' + icon + ' icnColor"></i></span>';
8677	html += '</a>';
8678	html += '</li>';
8679
8680	return html;
8681}
8682
8683function notifications_animate(element) {
8684	var TimeOut;
8685	var height = '57px';
8686
8687	$(element).animate({height: height}, 300);
8688
8689	TimeOut = setTimeout(function () {
8690		$(element).animate({height: '0'}, 300, function () {
8691			$(this).remove();
8692			notifications_hide_arrow();
8693		});
8694	}, notification_close_after);
8695
8696	$(element).mouseout(function () {
8697		TimeOut = setTimeout(function () {
8698			$(element).animate({height: '0'}, 300, function () {
8699				$(this).remove();
8700				notifications_hide_arrow();
8701			});
8702		}, notification_close_after);
8703	});
8704
8705	$(element).mouseover(function () {
8706		clearTimeout(TimeOut);
8707	});
8708}
8709
8710function notifications_hide_arrow() {
8711	if ($(notification_main_wrapper).find('> div > ul li').length == 0) {
8712		$(notification_main_wrapper).find('.notificationsBottom').hide();
8713	}
8714}
8715
8716function notifications_sound() {
8717	if (self == top) {
8718		var sound = new Audio('/audio/notification-2.wav');
8719		sound.play();
8720	} else {
8721		window.parent.postMessage('{"method": "playNotificationSound", "src": "/audio/notification-2.wav"}', '*');
8722	}
8723}
8724
8725function notification_mute() {
8726	var el = $('.audioNotifications');
8727	var enable = el.data('enable');
8728
8729	$.getJSON('/account/set_notifications_sound_enabled', {value: enable}, function (data) {
8730		if (data.status == 'ok') {
8731			if (enable == true) {
8732				el.data('enable', false);
8733				el.find('i').removeClass('audioOff').addClass('audioOn');
8734				el.find('span.textOffScreen').html('Notification audio off');
8735				notifications_play_sound = true;
8736			} else if (enable == false) {
8737				el.data('enable', true);
8738				el.find('i').removeClass('audioOn').addClass('audioOff');
8739				el.find('span.textOffScreen').html('Notification audio on');
8740				notifications_play_sound = false;
8741			}
8742		}
8743	});
8744}
8745
8746function notification_mute_app(enable) {
8747	$.getJSON('/account/set_notifications_sound_enabled', {value: enable}, function (data) {
8748		if (data.status == 'ok') {
8749			if (enable == true) {
8750				notifications_play_sound = true;
8751			} else if (enable == false) {
8752				notifications_play_sound = false;
8753			}
8754		}
8755	});
8756}
8757
8758// notifications counter
8759
8760function just_read_notification(id) {
8761	if (id) {
8762		update_unread_status_in_dd('.notificationsDropDown', id);
8763	}
8764
8765	update_unread_notifications();
8766	notifications_arrow_navigation();
8767}
8768
8769function update_unread_notifications() {
8770	$.getJSON('/notifications/get_unread_count', function(data) {
8771		update_top_nav_counter(data.count, '.notificationsHolder', '.mobileNotificationsHolder');
8772	});
8773}
8774
8775// messages counter
8776
8777function just_read_message(id) {
8778	if (id) {
8779		update_unread_status_in_dd('.messagesDropDown', id);
8780	}
8781
8782	update_unread_messages();
8783	notifications_arrow_navigation();
8784}
8785
8786function update_unread_messages() {
8787	$.getJSON('/inbox/get_unread_count', function(data) {
8788		update_top_nav_counter(data.count, '.messagesHolder', '.mobileMessagesHolder');
8789	});
8790}
8791
8792// update status icon in dropdowns
8793
8794function update_unread_status_in_dd(wrapper, id) {
8795	var dd = $(wrapper);
8796	var dd_is_open = dd.hasClass('dDownShow');
8797
8798	if (dd_is_open === true) {
8799		var element = dd.find('#message-' + id).find('span.ms-status i');
8800
8801		if (element.hasClass('xCross')) {
8802			element.removeClass('xCross').addClass('tick');
8803		}
8804	}
8805}
8806
8807// notifications/messages popup navigation
8808var arrow_navig_usage = true;
8809
8810function notifications_arrow_navigation() {
8811	$(document).keydown(function(e) {
8812		switch(e.which) {
8813			case 37: // left
8814				if (arrow_navig_usage == true && $('#facebox .popup_left').length != 0 && $('#facebox .popup_left').is(':visible')) {
8815					$('#facebox .popup_left').trigger('click');
8816					e.preventDefault();
8817
8818					arrow_navig_usage = false;
8819					setTimeout(function() { arrow_navig_usage = true; }, 800);
8820				}
8821				break;
8822
8823			case 39: // right
8824				if (arrow_navig_usage == true && $('#facebox .popup_right').length != 0 && $('#facebox .popup_right').is(':visible')) {
8825					$('#facebox .popup_right').trigger('click');
8826					e.preventDefault();
8827
8828					arrow_navig_usage = false;
8829					setTimeout(function() { arrow_navig_usage = true; }, 800);
8830				}
8831				break;
8832
8833			default: return; // exit this handler for other keys
8834		}
8835	});
8836}
8837
8838// counters
8839
8840function update_top_nav_counter(count, parent, mobile_parent) {
8841	var selector = $(parent);
8842	var mobile_selector = $(mobile_parent);
8843
8844	if (selector.length == 0) {
8845		return; // not found
8846	}
8847
8848	execute_update_top_nav_counter(count, selector);
8849
8850	if (mobile_selector.length == 0) {
8851		return; // not found
8852	}
8853
8854	execute_update_top_nav_counter(count, mobile_selector);
8855
8856	if (is_mobile_app_mode() &&
8857		(
8858			(
8859				parent == '.messagesHolder' &&
8860				(mobile_messages_count == 0 || count < mobile_messages_count)
8861			) || (
8862				parent == '.notificationsHolder' &&
8863				(mobile_notifications_count == 0 || count < mobile_notifications_count)
8864			)
8865		)) {
8866		switch (parent) {
8867			case '.messagesHolder':
8868				mobile_messages_count = count;
8869				break;
8870			case '.notificationsHolder':
8871				mobile_notifications_count = count;
8872				break;
8873		}
8874		send_header_to_app();
8875	}
8876}
8877
8878function execute_update_top_nav_counter(count, selector) {
8879	var alert_el = selector.find('.newAlert');
8880	var link_el = selector.find('> a:first-child');
8881
8882	if (alert_el.length != 0) {
8883		var inline_count = parseInt(alert_el.text());
8884
8885		if (inline_count != count) {
8886			if (count > 0) {
8887				alert_el.text(count.toString());
8888			} else {
8889				alert_el.next('i').removeClass('messages').addClass('unread');
8890				alert_el.remove();
8891			}
8892		}
8893	} else {
8894		if (count > 0) {
8895			link_el.prepend('<span class="newAlert">' + count + '</span>').find('i').addClass('messages').removeClass('unread');
8896		}
8897	}
8898}
8899
8900// mark as read
8901
8902function mark_all_as_read(controller, parent, mobile_parent) {
8903	$.confirm({
8904		content : are_you_sure_text,
8905		confirm : function() {
8906			$.ajax({
8907				type : "POST",
8908				url : "/" + controller + "/mark_all_as_read",
8909				dataType : "json",
8910				async : false,
8911				success : function(data) {
8912					if (data.status == 'done') {
8913						update_top_nav_counter(0, parent, mobile_parent);
8914
8915						$(parent).find('.dropDown li').each(function(index, value) {
8916							$(value).removeClass('ms-unread');
8917						});
8918
8919						$(parent).find('.markAllAsRead').hide();
8920					}
8921				}
8922			});
8923		}
8924	});
8925}
8926
8927/**
8928 * =====================================================================
8929 * ================================END==================================
8930 * =====================================================================
8931 */
8932
8933function set_back_link_url(url){
8934	$('.backLink').attr('href', url);
8935}
8936
8937function init_portal_login() {
8938	$('#access_code_form').submit(function(e) {
8939		e.preventDefault();
8940		$('#submit_access_code').click();
8941		return false;
8942	});
8943
8944	$('#submit_access_code').click(function(e) {
8945		$.post($('#access_code_form').attr('action'), $('#access_code_form').serialize(), function(data) {
8946			switch (data.status) {
8947				case 'submit':
8948					document.location = '/join_with_access_code/form?registration_code=' + encodeURIComponent($('#registration_code').val());
8949					break;
8950
8951				case 'problem':
8952					$('#access_code_form').siblings('#alerts').html('<div class="alert_block error" style="width:auto" role="alert"><div class="alert_flex"><div class="alert_icon"><i class="error inverted"></i></div><p>' + data.text + '</p></div></div>').show();
8953					break;
8954			}
8955		});
8956
8957		return false;
8958	});
8959
8960	$('#illini_btn, #saml2_btn, #clever_btn, #google_apps_btn, #sso_custom_btn, #office365_sso_btn, #oauth2_sso_btn').click(function(e){
8961		e.preventDefault();
8962
8963		var href = $(this).attr('href');
8964
8965		// React Native WebView and regular browsers should just navigate normally
8966		if($(this).hasClass('is-mobile-app')){
8967			if(window.ReactNativeWebView){
8968				// React Native WebView - just navigate, the WebView will handle it
8969				document.location = href;
8970			} else if(window.parent !== window){
8971				console.log('Legacy mobile app: sending postMessage');
8972				window.parent.postMessage("{\"method\": \"loadBrowser\", \"href\": \""+href+"\", \"refresh_on_close\": \"1\"}", "*");
8973			} else {
8974				// No mobile wrapper detected, just navigate normally
8975				console.log('No mobile wrapper: navigating to SSO');
8976				document.location = href;
8977			}
8978		}else{
8979			document.location = href;
8980		}
8981
8982		return false;
8983	});
8984
8985	var switchForms = {
8986		container : $('[data-active_window]'),
8987
8988		config : {
8989			speed : 200
8990		},
8991
8992		init : function() {
8993			$('[data-change_active]').on('click', this.toggleForm);
8994		},
8995
8996		toggleForm : function(e) {
8997			changeButton = $(this);
8998			$('div.warning, div.info, div.error').remove();
8999
9000			switchForms.container.each(function() {
9001				$this = $(this);
9002				// Find active change and show
9003				if ($this.data('active_window') == changeButton.data('change_active')) {
9004					$this.slideDown(switchForms.config.speed);
9005					$this.find('input[type="text"]').first().focus();
9006				} else {
9007					$this.slideUp(switchForms.config.speed);
9008				}
9009
9010			});
9011
9012			e.preventDefault();
9013		}
9014	};
9015
9016	switchForms.init();
9017
9018	setTimeout(function() {
9019		focus_element('userid');
9020	}, 0);
9021}
9022
9023function ajax_submit_login(login_submit_url, form_data) {
9024	var progress = add_progress($('#submit_button'));
9025	var progress_2fa = add_progress_2fa($('#two-factor-auth'));
9026
9027	$.support.cors = true;
9028
9029	$.ajax({
9030		url: login_submit_url,
9031		data: form_data || $('#login_form').serialize(),
9032		dataType: 'json',
9033		method: 'post',
9034		success: function(data) {
9035			switch (data.status) {
9036				case 'redirect':
9037					document.location = data.url;
9038					break;
9039
9040				case 'html':
9041					$('#login_form').replaceWith(data.text);
9042					break;
9043
9044				case 'problem':
9045					$('#login_form').siblings('#alerts').html('<div class="alert_block error" style="width:auto" role="alert"><div class="alert_flex"><div class="alert_icon"><i class="error inverted"></i></div><p>' + data.text + '</p></div></div>').show();
9046					var fields = $('#two-factor-auth').find('.input-list > input');
9047					fields.val("");
9048					fields.first().focus();
9049					progress.stop();
9050					progress_2fa.stop();
9051					break;
9052			}
9053		},
9054		error: function(x, t, m) {
9055			$('#login_form').siblings('#alerts').html('<div class="alert_block error" style="width:auto" role="alert"><div class="alert_flex"><div class="alert_icon"><i class="error inverted"></i></div><p>'+m+'</p></div></div>').show();
9056			progress.stop();
9057			progress_2fa.stop();
9058		}
9059	});
9060
9061	return false;
9062}
9063
9064/* Login popup stuff */
9065
9066function request_password() {
9067	$('div.warning, div.info, div.error').remove();
9068
9069	var email = $('#email').val();
9070	var login = '';
9071
9072	$.ajax({
9073		type: "POST",
9074		url: "/log_in/request_password_ajax",
9075		data: {email: email},
9076		dataType: "json",
9077		//async: false, // if is async it works. don't know the effect of enabling it, couldn't find any !!!
9078		success: function(data) {
9079			var info = data;
9080
9081			if ($('#simple_login').val() == 'true') {
9082        login = 'admin';
9083      } else {
9084        login = 'credentials';
9085      }
9086
9087			if (info.ok) {
9088				// this extra code adds a little animation effect
9089				$('.frmLogin[data-active_window="password"]').slideUp(200);
9090				$('.frmLogin[data-active_window="' + login + '"]').slideDown(200).prepend("<div class='info closeAlert keepopen' style='display:none'><p>" + info.message + "</p><a href=''></a></div>");
9091				$('.frmLogin[data-active_window="' + login + '"] .info').delay(250).fadeIn(400);
9092
9093				$('.frmLogin[data-active_window="' + login + '"] .info > a').bind('click', function(e) {
9094					$(this).parent().animate({
9095						height : '0',
9096						opacity : '0',
9097						margin : '0'
9098					});
9099
9100					e.preventDefault();
9101				});
9102			} else {
9103				// this extra code adds a little animation effect
9104				$('.frmLogin[data-active_window="password"]').prepend("<div class='alert_block warning close_alert' style='display:none' role='alert'><div class='alert_flex'><div class='alert_icon'><i class='error inverted'></i></div><p>" + info.message + "</p><a href=''><i class='xCrossSmall'></i><span class='textOffScreen'>Close alert</span></a></div></div>");
9105				$('.frmLogin[data-active_window="password"] .warning').fadeIn(400);
9106
9107				$('.frmLogin[data-active_window="password"] .warning > div > a').bind('click', function(e) {
9108					$(this).parent().parent().animate({
9109						height : '0',
9110						opacity : '0',
9111						margin : '0'
9112					});
9113
9114					e.preventDefault();
9115				});
9116			}
9117		},
9118		error : function(request, status) {
9119			console.log(request);
9120			console.log(status);
9121		}
9122	});
9123
9124	return false;
9125}
9126
9127// close popup function
9128function close_facebox_popup() {
9129	remove_close_button(); // if the autoclose is on we don't need close button anymore
9130
9131	setTimeout(function(){
9132		$.facebox.close();
9133	}, FACEBOX_CLOSING_TIME);
9134
9135}
9136
9137// remove the close from the facebox
9138function remove_close_button() {
9139	$('#facebox').find('a.close').remove();
9140}
9141
9142function add_mobile_heading(heading, heading1_override) {
9143	if($(document.body).hasClass('evo')) return;
9144	var sub_header = $('.inline_tabs_options .tabnav .selected').clone().children().remove().end().text();
9145	var mobile_page_heading = $('#mobile_page_heading');
9146	if( !mobile_page_heading.closest('.inline_heading_tabs_options').length )
9147		heading1_override = heading1_override.length ? heading1_override : sub_header;
9148	if ($('.pageHeading').length) {
9149		mobile_page_heading.html(heading);
9150		if(heading1_override.length){
9151			mobile_page_heading.next().html(heading1_override);
9152			$('.pageHeading').addClass('switch_heading');
9153		}
9154	}
9155
9156	// update page title based on heading as well
9157  var title = $('head title').text();
9158	var titlePieces = title.split(' - ');
9159	if (titlePieces.length > 2) {
9160		$('head title').text(title.replace(titlePieces[1], heading));
9161	}
9162}
9163
9164// alert
9165
9166function show_error(message) {
9167	var alerts = $('#alerts');
9168	alerts.html('<div class="alert_block error close_alert" role="alert"><div class="alert_flex"><div class="alert_icon"><i class="error inverted"></i></div><p>' + message + '</p><a href=""><i class="xCrossSmall"></i><span class="textOffScreen">Close alert</span></a></div></div>');
9169	alerts.show();
9170	$('html, body').animate({scrollTop: 0}, 300);
9171}
9172
9173function show_warning(message) {
9174	var alerts = $('#alerts');
9175	alerts.html('<div class="warning close_alert alert_block" role="alert"><div class="alert_flex"><div class="alert_icon"><i class="flag inverted"></i></div><p>' + message + '</p><a href=""><i class="xCrossSmall"><span class="textOffScreen">Close Alert</span></i></a></div></div>');
9176	alerts.show();
9177	$('html, body').animate({scrollTop: 0}, 300);
9178}
9179
9180function show_info(message) {
9181	var alerts = $('#alerts');
9182	alerts.html('<div class="alert_block info close_alert" role="alert"><div class="alert_flex"><div class="alert_icon"><i class="error inverted"></i></div><p>' + message + '</p><a href=""><i class="xCrossSmall"></i><span class="textOffScreen">Close alert</span></a></div></div>');
9183	alerts.show();
9184	$('html, body').animate({scrollTop: 0}, 300);
9185}
9186
9187// add progress
9188
9189function add_progress(elem, options){
9190	// disable button
9191	elem.attr('disabled','disabled').addClass('in-progress');
9192	var opts = {
9193		lines: 11, // The number of lines to draw
9194		length: 4, // The length of each line
9195		width: 2, // The line thickness
9196		radius: 5, // The radius of the inner circle
9197		corners: 1, // Corner roundness (0..1)
9198		rotate: 0, // The rotation offset
9199		direction: 1, // 1: clockwise, -1: counterclockwise
9200		color: '#FFF', // #rgb or #rrggbb or array of colors
9201		speed: 1, // Rounds per second
9202		trail: 60, // Afterglow percentage
9203		shadow: false, // Whether to render a shadow
9204		hwaccel: false, // Whether to use hardware acceleration
9205		className: 'spinner', // The CSS class to assign to the spinner
9206		zIndex: 2e9, // The z-index (defaults to 2000000000)
9207		top: 'auto', // Top position relative to parent in px
9208		left: 'auto' // Left position relative to parent in px
9209	};
9210	var spinner = new Spinner( $.extend(opts, options) ).spin();
9211	var progress = {
9212		elem: elem,
9213		spinner: spinner,
9214		stop: function() {
9215			this.spinner.stop();
9216			this.elem.removeAttr('disabled').removeClass('in-progress');
9217		}
9218	};
9219	elem.append(spinner.el);
9220	return progress;
9221}
9222
9223function add_progress_2fa(elem, options){
9224	elem.addClass('in-progress');
9225	var opts = {
9226		lines: 11, // The number of lines to draw
9227		length: 4, // The length of each line
9228		width: 2, // The line thickness
9229		radius: 5, // The radius of the inner circle
9230		corners: 1, // Corner roundness (0..1)
9231		rotate: 0, // The rotation offset
9232		direction: 1, // 1: clockwise, -1: counterclockwise
9233		color: '#282626', // #rgb or #rrggbb or array of colors
9234		speed: 1, // Rounds per second
9235		trail: 60, // Afterglow percentage
9236		shadow: false, // Whether to render a shadow
9237		hwaccel: false, // Whether to use hardware acceleration
9238		className: 'spinner', // The CSS class to assign to the spinner
9239		zIndex: 2e9, // The z-index (defaults to 2000000000)
9240		top: 'auto', // Top position relative to parent in px
9241		left: 'auto' // Left position relative to parent in px
9242	};
9243	var spinner = new Spinner( $.extend(opts, options) ).spin();
9244	var progress = {
9245		elem: elem,
9246		spinner: spinner,
9247		stop: function() {
9248			this.spinner.stop();
9249			this.elem.removeClass('in-progress');
9250		}
9251	};
9252	elem.append(spinner.el);
9253	return progress;
9254}
9255
9256/* Payment processing popup for plans purchase */
9257
9258function show_processing(message) {
9259	if ($('#facebox_overlay').length == 0)
9260	  $('body').append('<div id="facebox_overlay" class="facebox_overlayBG fullscreen_progress"></div>');
9261	$('.facebox_overlayBG').css('opacity','0.4');
9262
9263	data = '<div class="header center"> \
9264	          <h2>' + processing + '</h2> \
9265	        </div> \
9266	        <div class="fullscreen_msg_content center"> \
9267	          <div class="spinner_holder mt5"></div> \
9268	          <p class="mb0">' + message + '<br>' + do_not_press_refresh_or_back_button + '</p> \
9269	        </div>';
9270
9271	$('body').append('<div id="fullscreen_msg_holder" class="fullscreen_progress"><div id="fullscreen_msg" role="dialog" tabindex="-1"></div></div>');
9272	$('#fullscreen_msg').html(data).focus();
9273	var opts = {
9274		lines: 11, // The number of lines to draw
9275		length: 10, // The length of each line
9276		width: 4, // The line thickness
9277		radius: 13, // The radius of the inner circle
9278		corners: 1, // Corner roundness (0..1)
9279		rotate: 0, // The rotation offset
9280		direction: 1, // 1: clockwise, -1: counterclockwise
9281		color: '#5e5f5f', // #rgb or #rrggbb or array of colors
9282		speed: 1, // Rounds per second
9283		trail: 60, // Afterglow percentage
9284		shadow: false, // Whether to render a shadow
9285		hwaccel: false, // Whether to use hardware acceleration
9286		className: 'spinner', // The CSS class to assign to the spinner
9287		zIndex: 2e9, // The z-index (defaults to 2000000000)
9288		top: 'auto', // Top position relative to parent in px
9289		left: 'auto' // Left position relative to parent in px
9290	};
9291	var spinner = new Spinner(opts).spin();
9292	$('.spinner_holder').append(spinner.el);
9293	var fullscreen_progress = {
9294		stop: function() {
9295			$('.fullscreen_progress').remove();
9296		}
9297	};
9298	return fullscreen_progress;
9299}
9300
9301// over plan charges
9302
9303// note that "secure_protocol", host, etc. could be set once in lite.js during startup
9304
9305function pay_over_plan_charges(secure_protocol, current_host, ssl_host, message) {
9306	return secure_ajax_pay(secure_protocol, 'matrix_billing', 'submit_pay_over_plan_charges', 'payment_received', current_host, ssl_host, message);
9307}
9308
9309function start_plan_using_credit_card(secure_protocol, controller, current_host, ssl_host, message) {
9310	return secure_ajax_pay(secure_protocol, controller, 'create_credit_card', 'payment_plan_activated', current_host, ssl_host, message);
9311}
9312
9313function change_plan_using_credit_card(secure_protocol, controller, current_host, ssl_host, message) {
9314	return secure_ajax_pay(secure_protocol, controller, 'save_credit_card', 'payment_plan_changed', current_host, ssl_host, message);
9315}
9316
9317function change_credit_card(secure_protocol, controller, current_host, ssl_host, message) {
9318	return secure_ajax_pay(secure_protocol, controller, 'save_change_credit_card', 'credit_card_changed', current_host, ssl_host, message);
9319}
9320
9321function secure_ajax_pay(secure_protocol, controller, action, success_action, current_host, ssl_host, message, data, auth_token) {
9322	var fullscreen_progress;
9323	if (ssl_host.toUpperCase() == current_host.toUpperCase()) {
9324		$.ajax({
9325			type : 'GET',
9326			data : data || $('#ecommerce_form').formSerialize(),
9327			url : secure_protocol + '://' + current_host + '/' + controller + '/' + action + (auth_token ? '?one_time_auth_token=' + auth_token : ''),
9328			dataType : 'jsonp',
9329			beforeSend: function(){
9330				fullscreen_progress = show_processing(message);
9331			},
9332			success : function(json, text_status, jqXHR) {
9333				if (json.error != null) {
9334					fullscreen_progress.stop();
9335					show_error(json.error);
9336				} else {
9337					var stripe_card_error = '';
9338					if (json.stripe_card_error) { stripe_card_error = '?stripe_card_error=true'}
9339					window.location.href = '/' + controller + '/' + success_action + stripe_card_error;
9340				}
9341			},
9342			error : function(jqXHR, text_status, errorThrown) {
9343				fullscreen_progress.stop();
9344				show_error(text_status);
9345			}
9346		});
9347	} else {
9348		$.ajax({
9349			type : 'GET',
9350			url : 'http://' + current_host + '/authentication/get_auth_token',
9351			dataType : 'jsonp',
9352			beforeSend: function(){
9353				fullscreen_progress = show_processing(message);
9354			},
9355			success : function(json, text_status, jqXHR) {
9356				secure_ajax_pay(secure_protocol, controller, action, success_action, ssl_host, ssl_host, message, data, json.auth_token);
9357			},
9358			error : function(jqXHR, text_status, errorThrown) {
9359				fullscreen_progress.stop();
9360				show_error(text_status);
9361			}
9362		});
9363	}
9364
9365	return false;
9366}
9367
9368/* re-initialize checkboxes */
9369function update_checkboxes() {
9370	$("input[type='checkbox']").each(function(index) {
9371		if (!$(this).next().is('label')) {
9372			$(this).after('<label for="' + $(this).attr('id') + '"></label>');
9373			$(this).addClass("emptyLabel");
9374		}
9375	});
9376}
9377
9378/* tabs utility function */
9379function tabs_selected_pointer(element, container, type, extra) {
9380	$(container+' .tabnav .tabnav__tab').removeClass('selected').attr("aria-selected","false").attr("tabindex","-1");
9381	$(container+' div.tab-content').removeClass('active-tab').hide().attr("aria-hidden","true");
9382	$(container+' #'+$(element).attr('rel')).show().addClass('active-tab').attr("aria-hidden","false");
9383	$(element).addClass('selected').attr("aria-selected","true").attr("tabindex","0");
9384
9385	if ( type == 'hc' ) {
9386		$('.facebox-content.help_centre').find('#hc_content_selector').remove();
9387		$('.facebox-content.help_centre').find('#help_phrase').val('');
9388	} else if ( type == 'pp' ) {
9389		if ( extra == true ){
9390			$('.tabs-extra-class').show();
9391		} else {
9392			$('.tabs-extra-class').hide();
9393		}
9394	}
9395
9396	if ($('body').hasClass('catalog_class')) {
9397		resizeFixedLeftColumn();
9398	}
9399
9400	$(element).parents('.dropDownHolder').find('.tabnav__toggle, [role="tab"]').first().removeClass('highlight');
9401	$(element).parents('.dropDownHolder').find('.dropDown').removeClass('dDownShow');
9402}
9403
9404// Moves the tabs from the dropdown to the nav so they can be adjusted again
9405// Legacy tabnav functions - DEPRECATED
9406// These functions are kept for backward compatibility but should not be used in new code.
9407// Use the new TabNav class instead.
9408
9409function reset_tabs(containerId) {
9410	TabNav.resetTabs();
9411}
9412
9413function tabnav_adjustment(containerId) {
9414	TabNav.refresh();
9415}
9416
9417/* help center */
9418function open_tab() {
9419	$('#helpTabs a[rel="popup_help_center_overview"]').parent().next().children('a').trigger('click');
9420}
9421
9422function hc_load_content_with_ajax(container) {
9423	var $this = $(container);
9424	var scroll = $this.find('.scroll');
9425	var help_list = $this.find('.helpList a');
9426
9427	$.each(help_list, function(index, value){
9428		$(this).click(function(e){
9429			e.preventDefault();
9430
9431			var wrapper = $(this).parents('.tab-content');
9432			var response = get_ajax_response($(this).attr('href'), 'html', false);
9433			var html = '<div id="hc_content_selector">' + response + '</div>';
9434
9435			$('.facebox-content.help_centre').find('#hc_content_selector').remove();
9436
9437			$(html).insertAfter(wrapper);
9438
9439			$('#hc_content_selector').height(wrapper.height()).find('.help_centre_content').height((wrapper.height() - $('.help_centre_heading').outerHeight()));
9440
9441			wrapper.hide();
9442
9443			hc_content_links();
9444
9445			$('.facebox-content.help_centre').find('#help_phrase').val('');
9446
9447			isolatedScroll($('.help_centre_content'));
9448		});
9449	});
9450
9451	hc_help_for_page();
9452
9453	hc_search_with_ajax();
9454
9455	isolatedScroll(scroll);
9456}
9457
9458function hc_content_links() {
9459	$('img.imgL-blue').remove();
9460
9461	$('a.back_to_list').click(function(e){
9462		$('.facebox-content.help_centre').find('#hc_content_selector').remove();
9463		$('.facebox-content.help_centre').find('#help_phrase').val('');
9464		$('.active-tab').show();
9465	});
9466
9467	$.each($('#hc_content_selector a[href*="/help/"]'), function(index, value){
9468		$(this).click(function(e){
9469			e.preventDefault();
9470
9471			var wrapper = $(this).parents('#hc_content_selector');
9472			var response = get_ajax_response($(this).attr('href'), 'html', false);
9473			var html = '<div id="hc_content_selector">' + response + '</div>';
9474
9475			$('.facebox-content.help_centre').find('#hc_content_selector').remove();
9476
9477			$(html).insertAfter($('.facebox-content .active-tab'));
9478
9479			$('#hc_content_selector').height(wrapper.height()).find('.help_centre_content').height((wrapper.height() - $('.help_centre_heading').outerHeight()));
9480
9481			hc_content_links();
9482
9483			$('.facebox-content.help_centre').find('#help_phrase').val('');
9484
9485			isolatedScroll($('.help_centre_content'));
9486		});
9487	});
9488
9489	$('#hc_content_selector a[href*="#"]:not([href*="#help-"])').each(function(){
9490		$(this).click(function(e){
9491			e.preventDefault();
9492			var link_name = $(this).attr('href').replace('#', '');
9493			link_name = link_name.replace('%20', ' ');
9494			var scrollTop = $('#hc_content_selector a[name="'+link_name+'"]').position().top;
9495			$('.help_centre_content').scrollTop(scrollTop - 170);
9496		});
9497	});
9498}
9499
9500function hc_help_for_page() {
9501	var block = $('#popup_help_center_overview').find('.help_for_page');
9502
9503	if (block.length != 0) {
9504		block.click(function(e){
9505			e.preventDefault();
9506
9507			var link = $(this).attr('href');
9508			var section = link.split('?')[0].split('/')[2];
9509			var topic = get_param_from_url(link, 'topic');
9510
9511			$('#helpTabs a[rel="popup_help_center_' + section + '"]').trigger('click');
9512			$('#popup_help_center_' + section).find('a[href="/help/' + section + '?topic=' + topic + '"]').trigger('click');
9513		});
9514	}
9515}
9516
9517function hc_go_to_topic($this) {
9518	if(typeof $this == "string"){
9519		var link = $this;
9520	}else{
9521		$($this).on('click', function(e) { e.preventDefault(); });
9522		var link = $($this).attr('href');
9523	}
9524	$.ajax({
9525		type: 'GET',
9526		url: '/help',
9527		dataType: 'html',
9528		async: false,
9529		success: function(data) {
9530			$.facebox(data);
9531			var section = link.split('?')[0].split('/')[2];
9532			var topic = get_param_from_url(link, 'topic');
9533			$('#helpTabs a[rel="popup_help_center_' + section + '"]').trigger('click');
9534			$('#popup_help_center_' + section).find('a[href="/help/' + section + '?topic=' + topic + '"]').trigger('click');
9535		}
9536	});
9537}
9538
9539function hc_search_with_ajax() {
9540	$('.facebox-content.help_centre').find('button[name="search_button"]').click(function(e){
9541		e.preventDefault();
9542
9543		var search_string = $(this).prev('input').val();
9544		var search_name = $(this).prev('input').attr('name');
9545		var wrapper = $('.help_centre');
9546		var active = wrapper.find('.active-tab');
9547		var response = get_ajax_response($(this).parents('form').attr('action') + '?' + search_name + '=' + search_string, 'html', false);
9548		var html = '<div id="hc_content_selector">' + response + '</div>';
9549
9550		$('.facebox-content.help_centre').find('#hc_content_selector').remove();
9551
9552		wrapper.append(html);
9553
9554		$('#hc_content_selector').height(active.height()).find('.help_centre_content').height((active.height() - $('.help_centre_heading').outerHeight()));
9555
9556		active.hide();
9557
9558		hc_content_links();
9559
9560		isolatedScroll($('.help_centre_content'));
9561	});
9562}
9563
9564function hc_edit_ajax_submit(options) {
9565	$('.hc-edit').find('button[type="submit"]').on('click', function(e) {
9566		e.preventDefault();
9567
9568		var form = $('.hc-edit');
9569		var action = form.attr('action');
9570		var content = tinymce.get('hc_content').getContent();
9571		var saved = false;
9572
9573		$.ajax({
9574			type: 'POST',
9575			url: action,
9576			data: {content: content},
9577			dataType: 'json',
9578			async: false,
9579			success: function(data) {
9580				if (data.status == 'ok') {
9581					saved = true;
9582				} else {
9583					$.alert({content: options.error});
9584				}
9585			}
9586		});
9587
9588		if (saved == true) {
9589			var link = decodeURIComponent(action).split('?');
9590			var topic = get_param_from_url('?'+link[2], 'topic');
9591			var section = link[1].replace('from=/help/', '').replace('/', '');
9592
9593			$('#helpTabs a[rel="popup_help_center_' + section + '"]').trigger('click');
9594			$('#popup_help_center_' + section).find('a[href="/help/' + section + '?topic=' + topic + '"]').trigger('click');
9595		}
9596	});
9597}
9598
9599function help_hack_for_tinymce_correct_destroy(id) {
9600	if (id.indexOf('#') == 0) {
9601		id = id.substr(1);
9602	}
9603
9604	if (id.indexOf('.') == 0) {
9605		id = id.substr(1);
9606	}
9607
9608	if (typeof(tinymce) != 'undefined') {
9609		if (tinymce.get(id))
9610			tinymce.get(id).destroy();
9611	}
9612}
9613
9614function get_param_from_url(string, key, all) {
9615	var query = string.split("?")[1];
9616	var data = (typeof query == 'undefined') ? [] : query.split("&");
9617	var result = {};
9618	for(var i=0; i<data.length; i++) {
9619		var item = data[i].split("=");
9620		result[item[0]] = item[1];
9621	}
9622	if (all) {
9623		return result;
9624	} else {
9625		return result[key];
9626	}
9627}
9628
9629function submit_classes_export(t, controller, action, age) {
9630	var t = $(t);
9631	var form = $('form#classes');
9632
9633	form.attr('action', ('/' + controller + (action ? ('/' + action + (age ? '?age=' + age : '')) : '')));
9634
9635	form.submit();
9636}
9637
9638// tool provider edit form fields
9639
9640function show_tp_fields(t) {
9641	var t = $(t);
9642	var s = t.selected().val();
9643	var w = t.parents('form').find('.domain-url-xml');
9644
9645	if (s == 'URL') {
9646		w.find('label').first().text('Url:');
9647		w.find('textarea').parent('p').show();
9648	} else if (s == 'Domain') {
9649		w.find('label').first().text('Domain:');
9650		w.find('textarea').parent('p').show();
9651	} else if (s == 'URL/XML') {
9652		w.find('label').first().text('Url:');
9653		w.find('textarea').parent('p').hide();
9654		w.find('textarea').val('');
9655	} else {
9656		$.alert({content: 'Not Good!'});
9657	}
9658}
9659
9660// export more classes gradebook
9661
9662function check_checked(t) {
9663	var form = $(t).parents('form');
9664
9665  if (form.length == 0) {
9666    form = $(".tableForm");
9667  }
9668
9669	if (form.find('input[type="checkbox"]:checked').length > 0) {
9670		return true;
9671	} else {
9672		$.alert({content: 'Nothing selected. Select at least one item.'});
9673		return false;
9674	}
9675}
9676
9677// tool info autocomplet when tool provider selected
9678
9679function handle_lti_version_data(select){
9680	if(select.value === "LtiV1p3"){
9681		$(".lti_v1p1_data").hide();
9682		$(".lti_v1p3_data").show();
9683	}else{
9684		$(".lti_v1p1_data").show();
9685		$(".lti_v1p3_data").hide();
9686	}
9687}
9688
9689function do_tp_autofill(t,x, resource) {
9690	var tool_provider_id = t;
9691	var form = $('form#'+x);
9692  	var resource = resource || 'resource';
9693
9694	if (!tool_provider_id) {
9695		form.find('input#' + resource + '_name').val('');
9696		form.find('textarea#' + resource + '_description').val('');
9697		form.find('input#' + resource + '_config_url').val('');
9698        $("#p_tool_public_key").hide();
9699        $('#' + resource + '_tool_public_key').val('');
9700        $('#' + resource + '_deployment_id').val('');
9701	} else {
9702		get_tp_data(tool_provider_id, form, resource);
9703	}
9704}
9705
9706function get_tp_data(tool_provider_id, wrapper, resource) {
9707	$.ajax({
9708		type: "POST",
9709		url: "/tool_provider/get_info/" + tool_provider_id,
9710		dataType: "json",
9711		success: function(data) {
9712			$.each(data, function(k,v) {
9713				wrapper.find('[id="' + resource + '_' + k + '"]').val(v);
9714
9715                if(k === 'lti_type' && v === 'LtiV1p3'){
9716									$(".lti_v1p1_data").hide();
9717									$(".lti_v1p3_data").show();
9718                }
9719                if(k === 'lti_type' && v === 'Lti'){
9720									$(".lti_v1p1_data").show();
9721									$(".lti_v1p3_data").hide();
9722				}
9723			});
9724		}
9725	});
9726}
9727
9728function launch_lti(t, controller) {
9729	var t = $(t);
9730	var id = t.attr('href').split('/')[3];
9731	var url = decodeURIComponent(location.protocol + "//" + location.host + '/' + (controller || 'lti') + '/launch/' + id);
9732	var title = t.text();
9733	var data = t.data();
9734
9735	var w = data.width || '1000px';
9736	var h = data.height || '800px';
9737
9738	window.open(url, "'" + title + "'", "scrollbars=1, width=" + w + ", height=" + h);
9739}
9740
9741function custom_lti_launch(t, no_email) {
9742  if (no_email == true) {
9743    $.alert({content: 'You must first set your account email in profile settings!'});
9744    return false;
9745  }
9746
9747  var t = $(t);
9748  var id = t.attr('href').replace( /^\D+/g, '').split('?')[0];
9749  var url = location.protocol + "//" + location.host + '/assignment_lti/launch?assignment_id=' + id;
9750  var title = t.text();
9751
9752  if(is_mobile_app_mode()){
9753    window.parent.postMessage("{\"method\": \"loadBrowser\", \"href\": \"" + decodeURIComponent(url) + "\"}", "*");
9754  }else{
9755    window.open(decodeURIComponent(url), "'" + title + "'", "scrollbars=1,width=1000px,height=600px,resizable=true");
9756  }
9757}
9758
9759function h5p_launch(t, no_email) {
9760	if (no_email == true) {
9761		$.alert({content: 'You must first set your account email in profile settings!'});
9762		return false;
9763	}
9764
9765	var t = $(t);
9766	var id = t.attr('href').replace( /.+?\/show\//, '').split('?')[0];
9767	var url = location.protocol + "//" + location.host + '/assignment_h5p/launch?assignment_id=' + id;
9768	var title = t.text();
9769
9770	if(is_mobile_app_mode()){
9771		window.parent.postMessage("{\"method\": \"loadBrowser\", \"href\": \"" + decodeURIComponent(url) + "\"}", "*");
9772	}else{
9773		window.open(decodeURIComponent(url), "'" + title + "'", "scrollbars=1,width=1000px,height=600px,resizable=true");
9774	}
9775}
9776
9777function turnitin_launch(t, method, no_email, query) {
9778	if (no_email == true) {
9779		$.alert({content: 'You must first set your account email in profile settings!'});
9780		return false;
9781	}
9782
9783	var t = $(t);
9784	var id = t.attr('href').replace( /^\D+/g, '').split('?')[0];
9785	var url = location.protocol + "//" + location.host + '/turnitin_lti/launch?assignment_id=' + id;
9786	var title = t.text();
9787
9788	url += "&section=" + method;
9789
9790	if (query) {
9791		var query_size = Object.keys(query).length;
9792
9793		url += "&";
9794		k = 1;
9795
9796		$.each(query, function(key, val) {
9797			url += key + "=" + val;
9798			url += (k < query_size ? '&' : '');
9799			k++;
9800		});
9801	}
9802
9803	if(is_mobile_app_mode()){
9804		window.parent.postMessage("{\"method\": \"loadBrowser\", \"href\": \"" + decodeURIComponent(url) + "\"}", "*");
9805	}else{
9806		window.open(decodeURIComponent(url), "'" + title + "'", "scrollbars=1,width=1000px,height=600px,resizable=true");
9807	}
9808}
9809
9810function check_turnitin_sync(class_id, assignment_id) {
9811	var interval = setInterval(function() {
9812		$.ajax({
9813			type: 'POST',
9814			url: '/turnitin_lti/check_for_synchronization/' + class_id,
9815			data: {assignment_id: assignment_id},
9816			dataType: 'json',
9817			async: false,
9818			success: function(json){
9819				if (json.status == 'ok') {
9820					$('.sync-message').css('background-color', '#21A1B2').find('p').text(json.message);
9821					clearInterval(interval);
9822					setTimeout(function(){ location.reload(); }, 1500);
9823				}
9824			}
9825		});
9826	}, 3000);
9827}
9828
9829function turnitin_forced_sync(el, id) {
9830	$.post("/teacher_turnitin_assignment/forced_sync", {id: id});
9831	setTimeout(function(){ location.reload(); }, 700);
9832}
9833
9834function sync_sections(url){
9835	$.post(url, $('#classes').serialize(), function(data){
9836		$.facebox(data);
9837	});
9838}
9839
9840function overwrite_box_with(max) {
9841	$("#facebox").css('max-width', max + 'px');
9842	$("#facebox #faceboxContent").css('width', '100%');
9843}
9844
9845// this is the filter search button show/hide engine
9846
9847function init_filter_effect(button, wrapper, extra, ajax) {
9848	button = (button || '.show-filter-field');
9849	wrapper = (wrapper || '.compactFilterContainer');
9850	extra = (extra || true);
9851	ajax = (ajax || false);
9852
9853	var $button = $(button);
9854	var $buttonParent = $button.parent();
9855	// jQuery's .parent('li') returns an empty set when the parent isn't an
9856	// <li> (the action-toolbar case: button is a direct child of
9857	// .action-toolbar__group) -- fall back to the button itself so
9858	// show_filter_field/hide_filter_field get a real element either way.
9859	var search_button = $buttonParent.is('li') ? $buttonParent : $button;
9860	var filter_wrapper = $(wrapper);
9861
9862	if (ajax == true) {
9863		$.ajax({url: '/library/set_filter_session'});
9864	}
9865
9866	if (search_button.is(":visible")) {
9867		show_filter_field(search_button, filter_wrapper, extra);
9868	} else {
9869		hide_filter_field(search_button, filter_wrapper, extra);
9870	}
9871
9872	if ($('input#compact_filter_phrase').length != 0) {
9873		focus_element('compact_filter_phrase');
9874	}
9875}
9876
9877function show_filter_field(button, wrapper, extra) {
9878	if (!button.is('li')) {
9879		// action-toolbar: button is a direct child of .action-toolbar__group,
9880		// not wrapped in an <li> -- just hide it, no sibling border upkeep.
9881		button.hide();
9882	} else if (button.parent().not(':only-child') && button.is(':only-child')) {
9883		button.parent().hide();
9884	} else {
9885		button.hide();
9886
9887		if (button.prev('li').length == 0) {
9888			button.next('li').css('border-left-width', '0');
9889		}
9890	}
9891
9892	wrapper.show().find('input').focus();
9893}
9894
9895function hide_filter_field(button, wrapper, extra) {
9896	var input = wrapper.hide().find('input');
9897
9898	if (!button.is('li')) {
9899		button.show();
9900	} else if (button.parent().not(':only-child') && button.is(':only-child')) {
9901		button.parent().show();
9902	} else {
9903		button.show().next('li').css('border-left-width', '1px');
9904	}
9905
9906	if (input.val() != '') {
9907		input.val('').keyup().blur();
9908	}
9909
9910	if (extra == true) {
9911		var drop_downs = wrapper.find('select').not('#subject_filter');
9912		var k = 0;
9913
9914		$.each(drop_downs, function(key,val) {
9915			k++;
9916
9917			$(val).find('option[value="0"]').attr("selected", "selected");
9918
9919			if (k == drop_downs.length) {
9920				$(val).trigger('change');
9921			}
9922		});
9923	}
9924}
9925
9926function close_filter(url, button, wrapper, ajax) {
9927	var checkboxes = $(wrapper + ' input:checkbox:not(:checked)');
9928	var name = $('input#compact_filter_phrase');
9929
9930	if (ajax == true) {
9931		$.ajax({url: '/library/set_filter_session', async: false});
9932	}
9933
9934	if (checkboxes.length > 0 || (name.length != 0 && name.val() != '')) {
9935		if (url.indexOf('library') !== -1) {
9936			url = removeUrlQueryParameter(window.location.href, 'name');
9937			url = removeUrlQueryParameter(url, 'filter_active');
9938		}
9939		window.location.href = url;
9940	} else {
9941		if ($(button).closest('ul').not(':only-child') && $(button).parent('li').is(':only-child')) {
9942			$(button).closest('ul').show();
9943		} else {
9944			$(button).parent('li').show().next('li').css('border-left-width', '1px');
9945		}
9946
9947		$(wrapper).hide();
9948	}
9949}
9950
9951function removeUrlQueryParameter(url, paramKey) {
9952    return url
9953        .replace(new RegExp('[?&]' + paramKey + '=[^&#]*(#.*)?$'), '$1')
9954        .replace(new RegExp('([?&])' + paramKey + '=[^&]*&'), '$1');
9955}
9956
9957function getUrlQueryParameter(url, name) {
9958    name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
9959    var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
9960    var results = regex.exec(url);
9961    return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
9962}
9963
9964// turnitin originality sync
9965// TODO: AT: Refactor the next to function for originality - if the refresh is kept !!!
9966
9967function do_turnitin_originality_sync_refresh(klass, assignment) {
9968  var pendings = $('#centreColumn').find('.originality-status-completed');
9969  var error, error_count = 0;
9970  var synced = 0;
9971
9972  if (pendings.length > 0) {
9973    $('#centreColumn').find('#fixedSectionHeader').prepend('<div class="sync-message" style="width:auto;margin:1px 0 15px;background-color:#F4A30D;position:relative;padding:1px 10px;"><p><img src="/images/loading-16.gif" style="float:left;margin:2px 15px 0 0;" /> <span style="color:#fff;">Refreshing similarities report, for the users on this page, from Turnitin...</span></p></div>');
9974
9975    resizeSectionHeader();
9976
9977    var time = 1000;
9978
9979    $.each(pendings, function(k,v) {
9980      setTimeout(function(){
9981        var pending = $(v);
9982        var paper_id = pending.data('paper');
9983        var student_id = pending.data('student');
9984
9985        $.ajax({
9986          type: "POST",
9987          url: "/turnitin_lti/get_originality_status",
9988          data: {assignment_id: assignment, klass_id: klass, paper_id: paper_id, student_id: student_id},
9989          dataType: 'json',
9990          success: function(data) {
9991            if (data.error) {
9992              error_count++;
9993              error = data.error;
9994
9995              $('.sync-message').css('background-color', '#C83131');
9996              $('.sync-message').find('img').remove();
9997              $('.sync-message span').html(error);
9998
9999              return false;
10000            } else {
10001              if (data.text == 'Pending') {
10002                $('span[data-student="' + data.student + '"]').html(data.text);
10003              } else {
10004                synced++;
10005
10006                $('span[data-student="' + data.student + '"]').html('<a href="' + assignment + '" class="tableLink2" onclick="turnitin_launch(this, \'originality\', false, {\'student\': ' + data.student + ', \'paperid\': ' + data.paper + '}); return false;">' + data.text + '</a>');
10007              }
10008            }
10009
10010            if (error_count > 0) {
10011              return false;
10012            }
10013
10014            if ((error_count == 0) && (pendings.length == synced)) {
10015              $('.sync-message').css('background-color', '#21A1B2');
10016              $('.sync-message').find('img').remove();
10017              $('.sync-message span').html("Similarities successfully synchronized.");
10018            }
10019          }
10020        });
10021      }, time);
10022
10023      time += 1000;
10024    });
10025  }
10026}
10027
10028function do_turnitin_originality_sync(klass, assignment) {
10029	var pendings = $('#centreColumn').find('.pending-needs-sync');
10030	var error, error_count = 0;
10031	var synced = 0;
10032
10033	if (pendings.length > 0) {
10034		$('#centreColumn').find('#fixedSectionHeader').prepend('<div class="sync-message" style="width:auto;margin:1px 0 15px;background-color:#F4A30D;position:relative;padding:1px 10px;"><p><img src="/images/loading-16.gif" style="float:left;margin:2px 15px 0 0;" /> <span style="color:#fff;">Fetching pending similarities from Turnitin...</span></p></div>');
10035
10036		resizeSectionHeader();
10037
10038		var synchronize_turnitin = function() {
10039			$.each(pendings, function() {
10040				var pending = $(this);
10041				var paper_id = pending.data('paper');
10042				var student_id = pending.data('student');
10043
10044				$.ajax({
10045					type: "POST",
10046					url: "/turnitin_lti/get_originality_status",
10047					data: {assignment_id: assignment, klass_id: klass, paper_id: paper_id, student_id: student_id},
10048					dataType: 'json',
10049					async: false,
10050					success: function(data) {
10051						if (data.error) {
10052							error_count++;
10053							error = data.error;
10054
10055							$('.sync-message').css('background-color', '#C83131');
10056							$('.sync-message').find('img').remove();
10057							$('.sync-message span').html(error);
10058
10059							return false;
10060						} else {
10061							if (data.text == 'Pending') {
10062								$('span[data-student="' + data.student + '"]').html(data.text);
10063							} else {
10064								synced++;
10065
10066								$('span[data-student="' + data.student + '"]').html('<a href="' + assignment + '" class="tableLink2" onclick="turnitin_launch(this, \'originality\', false, {\'student\': ' + data.student + ', \'paperid\': ' + data.paper + '}); return false;">' + data.text + '</a>');
10067							}
10068						}
10069					}
10070				});
10071
10072				if (error_count > 0) {
10073					return false;
10074				}
10075			});
10076
10077			if ((error_count == 0) && (pendings.length == synced)) {
10078				$('.sync-message').css('background-color', '#21A1B2');
10079				$('.sync-message').find('img').remove();
10080				$('.sync-message span').html("Similarities successfully synchronized.");
10081
10082				clearInterval(interval);
10083			}
10084		};
10085
10086		interval = setInterval(function(){ synchronize_turnitin(); }, 2500);
10087	}
10088}
10089
10090var check_submission_id = null;
10091var check_submission_student = null;
10092var check_submission_date = null;
10093
10094function check_for_submissions(id, student, date) {
10095  if ($('#lti_launch_frame').length > 0) {
10096    check_submission_id = id;
10097    check_submission_student = student;
10098
10099    if (date) {
10100      check_submission_date = date;
10101    }
10102  }
10103
10104	// WHY: match the launch functions by name, not the substring "submit". The
10105	// action toolbar renders these intercepted-click options as <button>s, and
10106	// its submit_form actions (Remove/Archive/...) carry submit_form_with_confirm
10107	// in their onclick -- a [onclick*="submit"] clause would bind those too and
10108	// poll for a submission that never happens. The list must name every launch
10109	// function used on a page that calls check_for_submissions: the legacy
10110	// [onclick*="h5p"] clause matched launch_lti only through its controller
10111	// argument ('assignment_h5p_v1p3'), which is not something to rely on.
10112	$('.optionsRibbon a[onclick*="submit"], .optionsRibbon a[onclick*="h5p"], ' +
10113	  '.action-toolbar [onclick*="turnitin_launch"], .action-toolbar [onclick*="h5p_launch"], ' +
10114	  '.action-toolbar [onclick*="custom_lti_launch"], .action-toolbar [onclick*="launch_lti"]').on('click', function(e){
10115    check_for_submissions_implementation(id, student, date)
10116	});
10117}
10118
10119function check_for_submissions_from_frame() {
10120  if (check_submission_date) {
10121    check_for_submissions_implementation(check_submission_id, check_submission_student, check_submission_date);
10122  } else {
10123    check_for_submissions_implementation(check_submission_id, check_submission_student);
10124  }
10125}
10126
10127function check_for_submissions_implementation(id, student, date) {
10128  var attempts = $('span.number-of-attempts');
10129  var result;
10130  var query_string = window.location.search;
10131  var cycles = 60;
10132  var cycle = 0;
10133  var timer = 2000;
10134
10135  function check() {
10136    var time = setTimeout(function(){
10137      $.ajax({
10138        type: 'POST',
10139        url: '/assignment/check_for_submission/' + id,
10140        data: {student_id: student, date: date},
10141        dataType: 'json',
10142        async: false,
10143        success: function(data) {
10144          result = parseInt(data.count);
10145        }
10146      });
10147
10148      if ((parseInt(attempts.text()) < result) || (date && result > 0)) {
10149        if (query_string == '') {
10150          window.location = window.location.href + '?submitted=true';
10151        } else if (query_string.indexOf('submitted=true') > -1) {
10152          window.location = window.location.href;
10153        } else {
10154          window.location = window.location.href + '&submitted=true';
10155        }
10156      }
10157
10158      cycle++;
10159
10160      if (cycle <= cycles) {
10161        if ((timer < 7000) && (cycle % 3 == 0)) {
10162          timer += 500;
10163        }
10164
10165        check();
10166      }
10167    }, timer);
10168  }
10169
10170  check();
10171}
10172
10173function style_select_action() {
10174	$('select[name="klass[style]"]').on('change', function(){
10175		var selected = $(this).find('option:selected').val();
10176
10177		if (selected == 'Instructor' || selected == 'Blended') {
10178			show_element('duration');
10179			hide_element('duration_text');
10180			hide_element('duration_text textarea');
10181		} else if (selected == 'Self paced' || selected == 'Micro class') {
10182			hide_element('duration');
10183			show_element('duration_text');
10184			show_element('duration_text textarea');
10185		}
10186	});
10187}
10188
10189function replace_relative_paths(string){
10190	string = string.replace(/href="\//g, 'target="contentFrame" href="'+window.location.protocol+'//' + window.location.host + '/');
10191	string = string.replace(/href='\//g, 'target=\'contentFrame\' href=\''+window.location.protocol+'//' + window.location.host + '/');
10192	string = string.replace(/src="\//g, 'src="'+window.location.protocol+'//' + window.location.host + '/');
10193	string = string.replace(/src='\//g, 'src=\''+window.location.protocol+'//' + window.location.host + '/');
10194	string = string.replace(/action="\//g, 'target="contentFrame" action="'+window.location.protocol+'//' + window.location.host + '/');
10195	string = string.replace(/action='\//g, 'target=\'contentFrame\' action=\''+window.location.protocol+'//' + window.location.host + '/');
10196
10197	return string;
10198}
10199
10200function refresh_private_key(el) {
10201	$.confirm({
10202		content : 'Are you sure you want to reset your private key?',
10203		confirm : function() {
10204			$.ajax({
10205				type : "POST",
10206				url : "/single_sign_on/refresh_private",
10207				dataType : "json",
10208				success : function(data) {
10209					$('#school_sso_custom_secret').val(data.key);
10210				}
10211			});
10212		}
10213	});
10214}
10215
10216function org_refresh_private_key(el, org_id) {
10217	$.confirm({
10218		content : 'Are you sure you want to reset your private key?',
10219		confirm : function() {
10220			$.ajax({
10221				type : "POST",
10222				url : "/org_single_sign_on/refresh_private/" + org_id,
10223				dataType : "json",
10224				success : function(data) {
10225					$('#sso_provider_sso_custom_secret').val(data.key);
10226				}
10227			});
10228		}
10229	});
10230}
10231
10232// resource library filtering
10233
10234function init_resource_library_filter(controller, action, id, lesson, section, folder, game, popup) {
10235	var name = $('#resource_name');
10236	var subject = $('#resource_subject');
10237	var classification = $('#resource_type');
10238	var library = $('#resource_library');
10239	var assignment_type = $('#resource_assignment_type');
10240
10241	name.keyup(function(e) {
10242		typewatch(function() { resource_library_filter(controller, action, id, lesson, section, folder, game, popup, name, subject, classification, library); }, 1000);
10243	});
10244
10245	subject.on('change', function(e) {
10246		resource_library_filter(controller, action, id, lesson, section, folder, game, popup, name, subject, classification, library, assignment_type);
10247	});
10248
10249	classification.on('change', function(e) {
10250		resource_library_filter(controller, action, id, lesson, section, folder, game, popup, name, subject, classification, library, assignment_type);
10251	});
10252
10253	library.on('change', function(e) {
10254		resource_library_filter(controller, action, id, lesson, section, folder, game, popup, name, subject, classification, library, assignment_type);
10255	});
10256
10257	assignment_type.on('change', function(e) {
10258		resource_library_filter(controller, action, id, lesson, section, folder, game, popup, name, subject, classification, library, assignment_type);
10259	});
10260}
10261
10262function resource_library_filter(controller, action, id, lesson, section, folder, game, popup, name, subject, classification, library, assignment_type) {
10263	var wrapper = $("#ResourceLibraryFilterWrapper");
10264	var url = '/' + controller + '/' + action + (id ? '/' + id : '') + '?';
10265	var args = [];
10266
10267	if (tool_to_edit_id) {
10268		args.push('tool_to_edit_id=' + tool_to_edit_id);
10269	}
10270
10271	if (base_controller) {
10272		args.push('base_controller=' + base_controller);
10273	}
10274
10275  if (select_all_learners) {
10276    args.push('select_all=' + select_all_learners);
10277  }
10278
10279  if (stacked_picker) {
10280    args.push('stacked_picker=' + stacked_picker);
10281  }
10282
10283  if (copilot_picker) {
10284      args.push('copilot_picker=' + copilot_picker);
10285      args.push('copilot_callback=' + copilot_callback);
10286  }
10287
10288  if (select_learners) {
10289    args.push(select_learners);
10290  }
10291
10292	if (name) {
10293		args.push('resource_name=' + encodeURIComponent(name.val()));
10294	}
10295
10296	if (lesson) {
10297		args.push('lesson_id=' + lesson);
10298	}
10299
10300	if (section) {
10301		args.push('section_id=' + section);
10302	}
10303
10304	if (folder) {
10305		args.push('folder=' + folder);
10306	}
10307
10308	if (game) {
10309		args.push('game=' + game);
10310	}
10311
10312	if (subject) {
10313		var value = subject.val();
10314
10315		if (value) {
10316			args.push('subject=' + value);
10317		}
10318	}
10319
10320	if (classification) {
10321		var value = classification.val();
10322
10323		if (value) {
10324			args.push('classification=' + value);
10325		}
10326	}
10327
10328	if (library) {
10329		var value = library.val();
10330
10331		if (value) {
10332			args.push('library=' + value);
10333		}
10334	}
10335
10336	if (assignment_type) {
10337		var value = assignment_type.val();
10338
10339		if (value) {
10340			args.push('assignment_type=' + value);
10341		}
10342	}
10343
10344	args.push('ajax=true');
10345	url += args.join('&');
10346
10347	$.ajax({
10348		type: "POST",
10349		url: url,
10350		dataType: 'html',
10351		beforeSend: function(){
10352			ajax_add_loader(wrapper, true);
10353		},
10354		success: function(html) {
10355			wrapper.find('.content').html(html);
10356			close_ajax_loader();
10357
10358			if (wrapper.find('.facebox-content').length == 1) {
10359				isolatedScroll(wrapper.find('.facebox-content'));
10360			}
10361		}
10362	});
10363}
10364
10365function ajax_add_loader(container, remove_footer_height) {
10366	container.css('position', 'relative');
10367
10368	if ($('#AppendedLoader').length == 0) {
10369		if (container.find('.footer').length >= 1 && !remove_footer_height) {
10370			container.append('<div id="AppendedLoader" style="position:absolute; z-index: 5; top:0; left: 0; background: rgba(255, 255, 255, 0.8) url(\'/images/loading-animation-' + (is_grey_page_mode() ? 'grey' : 'white') + '-retina.gif\') no-repeat center center / 100px; width: 100%; height: ' + (container.height() - container.find('.footer').height()) + 'px;"></div>');
10371		} else {
10372			container.append('<div id="AppendedLoader" style="position:absolute; z-index: 5; top:0; left: 0; background: rgba(255, 255, 255, 0.8) url(\'/images/loading-animation-' + (is_grey_page_mode() ? 'grey' : 'white') + '-retina.gif\') no-repeat center center / 100px; width: 100%; height: ' + container.height() + 'px;"></div>');
10373		}
10374	}
10375}
10376
10377function close_ajax_loader() {
10378	if ($('#AppendedLoader').length >= 1) {
10379		$('#AppendedLoader').remove();
10380	}
10381}
10382
10383/* type watch */
10384var typewatch = (function(){
10385	var time = 0;
10386
10387	return function(callback, ms){
10388		clearTimeout (time);
10389		time = setTimeout(callback, ms);
10390	};
10391})();
10392
10393// Infinite scroll for add existing
10394
10395var infinite_stop;
10396var infinite_pause;
10397
10398function init_add_existing(count, limit, controller, action, id, subject, name, library, classification, lesson_id) {
10399	if (count > limit) {
10400		infinite_stop = false;
10401		infinite_pause = true;
10402
10403		init_add_existing_infinite_scroll(controller, action, id, subject, name, library, classification, lesson_id);
10404	}
10405
10406	add_existing_submit_button();
10407}
10408
10409// lesson_id is hack, replace with container_id
10410
10411function init_add_existing_infinite_scroll(controller, action, id, subject, name, library, classification, lesson_id) {
10412	$("#facebox .facebox-content, .modal.is-open .facebox-content").scroll(function() {
10413		if (infinite_pause) {
10414			if ($(this).scrollTop() >= ($(this)[0].scrollHeight - $(this).height() - 50)) {
10415				infinite_pause = false;
10416				add_existing_more(controller, action, id, subject, name, library, classification, lesson_id);
10417			}
10418		}
10419	});
10420}
10421
10422function add_existing_more(controller, action, id, subject, name, library, classification, lesson_id) {
10423	let wrapper = $('#facebox .facebox-content').last();
10424	if (wrapper.length === 0) {
10425		wrapper = $('.modal.is-open .facebox-content').last();
10426	}
10427	let more = $('.add-existing-more').last(),
10428		offset = more.data('offset'),
10429		limit = more.data('limit'),
10430		size = more.data('size'),
10431		count = more.data('count'),
10432 	url = '/' + controller + '/' + action + (id ? '/' + id : '');
10433
10434	url += '?';
10435	url += 'offset=' + (offset + limit);
10436	url += '&limit=' + limit;
10437	url += '&count=' + count;
10438
10439	if (tool_to_edit_id){
10440		url += '&tool_to_edit_id=' + tool_to_edit_id;
10441	}
10442
10443	if (stacked_picker){
10444		url += '&stacked_picker=' + stacked_picker;
10445	}
10446
10447    if (copilot_picker){
10448        url += '&copilot_picker=' + copilot_picker;
10449        url += '&copilot_callback=' + copilot_callback;
10450    }
10451
10452	if (base_controller){
10453		url += '&base_controller=' + base_controller;
10454	}
10455
10456	if (lesson_id && lesson_id.length > 0) {
10457		url += '&lesson_id=' + lesson_id;
10458	}
10459
10460	if (subject && subject.length > 0) {
10461		url += '&subject=' + subject;
10462	}
10463
10464	if (name && name.length > 0) {
10465		url += '&resource_name=' + name;
10466	}
10467
10468	if (library && library.length > 0) {
10469		url += '&library=' + library;
10470	}
10471
10472	if (classification && classification.length > 0) {
10473		url += '&classification=' + classification;
10474	}
10475
10476	if (!infinite_stop) {
10477		$.ajax({
10478			type: "POST",
10479			url: url,
10480			beforeSend: function(){
10481				more.append('<img src="/images/loading-animation-white-retina.gif" width="100" />');
10482			},
10483			success: function(data) {
10484				more.remove();
10485				infinite_pause = true;
10486
10487				wrapper.append(data);
10488
10489				add_existing_submit_button();
10490
10491				var results_count = $('.add-existing-more').last().data('size');
10492
10493				if (results_count == 0) {
10494					infinite_pause = false;
10495					infinite_stop = true;
10496
10497					$('.add-existing-more').text('No more results'); /* translate */
10498				}
10499			}
10500		});
10501	}
10502}
10503
10504function add_existing_submit_button() {
10505	// support for multi-select
10506	$("#ResourceLibraryFilterWrapper").find('input[type="checkbox"]').on('change', function(){
10507		var count = $("#ResourceLibraryFilterWrapper").find('input[type="checkbox"]:checked').length;
10508        toggle_selector_submit_button(count > 0);
10509	});
10510
10511	// support for single-select
10512    $("#ResourceLibraryFilterWrapper").find('input[type="radio"]').on('change', function(){
10513        var count = $("#ResourceLibraryFilterWrapper").find('input[type="radio"]:checked').length;
10514        toggle_selector_submit_button(count > 0);
10515    });
10516}
10517
10518function toggle_selector_submit_button(value) {
10519    if (value) {
10520        $('#ResourceLibraryFilterWrapper .footer button').removeAttr('disabled');
10521        $('#ResourceLibraryFilterWrapper .footer button').removeAttr('style');
10522    } else {
10523        $('#ResourceLibraryFilterWrapper .footer button').attr('disabled', 'disabled').css('background-color', '#aeaeae');
10524    }
10525}
10526
10527// game
10528
10529function game_settings_display() {
10530	var leaderboard = $('#game_leaderboard');
10531	var leaderboard_wrapper = $('.leaderboardSettings');
10532
10533	leaderboard.on('change', function() {
10534		if (this.checked) {
10535			leaderboard_wrapper.show();
10536		} else {
10537			leaderboard_wrapper.hide();
10538		}
10539	});
10540}
10541
10542function update_game_display_count(controller, the_id, game_id) {
10543  $('#game_display_count').on('change', function() {
10544    ajax_request('/' + controller + '/set_leaderboard_count/' + the_id + '?game=' + game_id + '&value=' + this.value);
10545  });
10546}
10547
10548function popup_player_history(selector, admin_controller, id, the_id) {
10549  var selector = $(selector);
10550
10551  selector.on('click', function() {
10552    $.facebox({'ajax' : '/' + admin_controller + '/player/' + the_id + '?game=' + id + '&player_id=' + $(this).data('id')});
10553  });
10554}
10555
10556function popup_team_history(selector, admin_controller, id, the_id) {
10557	var selector = $(selector);
10558
10559	selector.on('click', function() {
10560		$.facebox({'ajax' : '/' + admin_controller + '/team/' + the_id + '?game=' + id + '&team_id=' + $(this).data('id')});
10561	});
10562}
10563
10564function toggle_select_choice(element) {
10565	var selector = $(element);
10566	var parent = selector.parents('p');
10567	var value = selector.val().toLowerCase().replace(/ /g, '_');
10568
10569	if (value == 'immediately') {
10570		parent.find('span').hide();
10571	} else {
10572		parent.find('span:not(.time_wrap)').hide();
10573		parent.find('span:not(.time_wrap)').find('select').val('');
10574		parent.find('span:not(.time_wrap)').find('input').val('');
10575		parent.find('.' + value).show();
10576	}
10577}
10578
10579// deselect the action from the commit
10580
10581function deselect_sync_action(el, sync_id) {
10582	$.ajax({
10583		type: 'POST',
10584		url: '/sis/select_action/',
10585		data: {action_id: $(el).val(), sync_id: sync_id, value: $(el).is(':checked')},
10586		success: function(data) {
10587			console.log(data);
10588		},
10589		error: function(data) {
10590			console.log(data);
10591		}
10592	});
10593}
10594
10595/* dashboard calendar */
10596
10597var smallCalendarNav = null;
10598
10599function init_small_calendar_keyboard() {
10600	var $wrapper = $('.calendar-small-wrapper');
10601	if ($wrapper.length === 0) return;
10602
10603	// Ensure all day links are not focusable by default (only via navigation mode)
10604	$wrapper.find('td a').attr('tabindex', '-1');
10605
10606	smallCalendarNav = new CalendarKeyboardNav({
10607		container: $wrapper[0],
10608		containerSelector: '.calendar-small-wrapper',
10609		navigationType: 'grid',
10610		editMode: false,
10611		
10612		getInitialCell: function() {
10613			var $target = $wrapper.find('td.current');
10614			if ($target.length === 0) {
10615				$target = $wrapper.find('td').first();
10616			}
10617			return $target;
10618		},
10619		
10620		onEnterNav: function() {
10621			var $target = this.getInitialCell();
10622			var $link = $target.find('a');
10623			if ($link.length) {
10624				$link.attr('tabindex', '0').focus();
10625				var $cell = $link.closest('td');
10626				this.currentRow = parseInt($cell.attr('data-row')) || 0;
10627				this.currentCol = parseInt($cell.attr('data-col')) || 0;
10628			}
10629		},
10630		
10631		onExitNav: function() {
10632			$wrapper.find('td a').attr('tabindex', '-1');
10633			$wrapper.focus();
10634		},
10635		
10636		getCellSelector: function(row, col) {
10637			return $wrapper.find('td[data-row="' + row + '"][data-col="' + col + '"]');
10638		},
10639		
10640		onActivateCell: function($current) {
10641			var $cell = $current.is('td') ? $current : $current.closest('td');
10642			if ($cell.length) {
10643				var $link = $cell.find('a');
10644				if ($link.length) {
10645					window.location.href = $link.attr('href');
10646				}
10647			}
10648		}
10649	});
10650	
10651	// Override focusCell to focus the link inside the td
10652	var originalFocusCell = smallCalendarNav.focusCell.bind(smallCalendarNav);
10653	smallCalendarNav.focusCell = function($cell) {
10654		if (!$cell || $cell.length === 0) return;
10655		
10656		$wrapper.find('td a').attr('tabindex', '-1');
10657		
10658		var $link = $cell.is('a') ? $cell : $cell.find('a');
10659		if ($link.length) {
10660			$link.attr('tabindex', '0').focus();
10661		}
10662		
10663		var $td = $cell.is('td') ? $cell : $cell.closest('td');
10664		this.currentRow = parseInt($td.attr('data-row')) || 0;
10665		this.currentCol = parseInt($td.attr('data-col')) || 0;
10666		
10667		this.scrollIntoView($link.length ? $link : $cell);
10668	};
10669}
10670
10671function get_dashboard_calendar(month, year, day) {
10672	$.get('/my_calendar/month_small/?year=' + year + '&month=' + month + (typeof day != 'undefined' ? '&day=' + day : ''), function(data) {
10673		$('#small_calendar_container').html(data);
10674		$('.small-month-name').html($('#new_small_month_name').val());
10675		init_small_calendar_keyboard();
10676	});
10677
10678	$('#previous_small_calendar_link').attr('href', 'javascript:get_dashboard_calendar(' + (month == 1 ? 12 : month - 1) + ', ' + (month == 1 ? year - 1 : year) + ')');
10679	$('#next_small_calendar_link').attr('href', 'javascript:get_dashboard_calendar(' + (month == 12 ? 1 : month + 1) + ', ' + (month == 12 ? year + 1 : year) + ')');
10680
10681	// update aria labels for the arrows for accessibility
10682	var previous_month = new Date();
10683	previous_month.setMonth((month == 1 ? 12 : month - 1) - 1)
10684	previous_month = previous_month.toLocaleString('en-US', { month: 'short' });
10685	var previous_year = (month == 1 ? year - 1 : year);
10686
10687	document.getElementById('previous_small_calendar_link').ariaLabel = previous_month + " " + previous_year;
10688
10689	var next_month = new Date();
10690	next_month.setMonth((month == 12 ? 1 : month + 1) - 1)
10691	next_month = next_month.toLocaleString('en-US', { month: 'short' });
10692	var next_year = (month == 12 ? year + 1 : year);
10693
10694	document.getElementById('next_small_calendar_link').ariaLabel = next_month + " " + next_year;
10695}
10696
10697/* x_api_servers */
10698function set_current_x_api_server(x_api_id) {
10699	ajax_request('/x_api_servers/set_default/' + x_api_id);
10700}
10701
10702function try_connection(x_api_server_id) {
10703  $.ajax({
10704    url  : '/x_api_servers/try_connection/' + x_api_server_id,
10705    type : 'post',
10706    success : function(data) {
10707      console.log(data);
10708    },
10709    error: function (xhr, ajaxOptions, thrownError) {
10710      console.log('Fail');
10711    }
10712  });
10713}
10714
10715/* sis filter */
10716function sis_filter_schools(el) {
10717  var selected_value = $(el).find('option:selected').val();
10718  var location = window.location.href;
10719
10720  if (location.match(/\?./)) {
10721    location = location.split("?")[0];
10722  }
10723
10724  if (selected_value) {
10725    window.location = location + '?school_id=' + selected_value;
10726  } else {
10727    window.location = location;
10728  }
10729}
10730
10731function validateZoomUSCredentials(apiKey, apiSecret) {
10732	$.ajax({
10733    url  : '/zoomus/validate_account_credentials/',
10734    type : 'post',
10735    data : {
10736    	key    : apiKey,
10737    	secret : apiSecret
10738    },
10739
10740    success : function(data) {
10741      if(data['status'] == true) {
10742      	$(".zoomus-apikeys-submit-form ").off('submit').submit();
10743      } else {
10744      	alert(data['status']);
10745      }
10746    },
10747
10748    error: function (xhr, ajaxOptions, thrownError) {
10749      // Error
10750    }
10751  });
10752}
10753
10754function validateWebExCredentials(apiKey, apiSecret, site_name) {
10755	$.ajax({
10756    url  : '/webex/validate_account_credentials/',
10757    type : 'post',
10758    data : {
10759    	key    : apiKey,
10760    	secret : apiSecret,
10761    	site   : site_name
10762    },
10763
10764    success : function(data) {
10765      if(data['status'] == true) {
10766      	$(".webex-apikeys-submit-form").off('submit').submit();
10767      } else {
10768      	alert(data['status']);
10769      }
10770    },
10771
10772    error: function (xhr, ajaxOptions, thrownError) {
10773      // Error
10774    }
10775  });
10776}
10777
10778$(document).ready(function() {
10779  $(".zoomus-apikeys-submit-form").submit(function(event) {
10780  	apiKey    = $('#zoomus_account_consumer_key').val();
10781  	apiSecret = $('#zoomus_account_consumer_secret').val();
10782
10783	  validateZoomUSCredentials(apiKey, apiSecret);
10784	  event.preventDefault();
10785	});
10786
10787	$(".webex-apikeys-submit-form").submit(function(event) {
10788  	apiKey    = $('#webex_account_consumer_key').val();
10789  	apiSecret = $('#webex_account_consumer_secret').val();
10790  	site_name = $('#webex_account_site_name').val();
10791
10792	  validateWebExCredentials(apiKey, apiSecret, site_name);
10793	  event.preventDefault();
10794	});
10795});
10796
10797// display "student_access" option if "Personal" library is NOT checked # in application_helper/edit_library
10798
10799function update_scope_user_student_access(radio_button) {
10800	if (radio_button.checked) {
10801		$('.student_access_library').hide();
10802	}
10803}
10804
10805 function update_scopes_student_access(radio_button) {
10806	 if (radio_button.checked) {
10807		 $('.student_access_library').show();
10808	 }
10809 }
10810
10811function select_current_theme(controller, radio_button, id) {
10812	if (radio_button.checked) {
10813		if (id == null) {
10814			window.location.href = '/' + controller + '/select_current_theme?theme_id=' + radio_button.value;
10815		} else {
10816			window.location.href = '/' + controller + '/select_current_theme/' + id + '?theme_id=' + radio_button.value;
10817		}
10818	}
10819}
10820
10821function select_current_accessible_theme(controller, radio_button, id) {
10822    if (radio_button.checked) {
10823        if (id == null) {
10824            window.location.href = '/' + controller + '/select_current_accessible_theme?theme_id=' + radio_button.value;
10825        } else {
10826            window.location.href = '/' + controller + '/select_current_accessible_theme/' + id + '?theme_id=' + radio_button.value;
10827        }
10828    }
10829}
10830
10831function set_accessibility_theme(controller, checkbox, id) {
10832	if (id == null) {
10833		window.location.href = '/' + controller + '/set_accessibility_theme?value=' + check_s(checkbox);
10834	} else {
10835		window.location.href = '/' + controller + '/set_accessibility_theme/' + id + '?value=' + check_s(checkbox);
10836	}
10837}
10838
10839function clear_errors() {
10840	$('#facebox div.error').remove();
10841	$('div.block div.error').remove();
10842}
10843
10844// disable submit button unless checkbox is checked. used mostly for agree terms and conditions.
10845var toggle_submit_button = function(el){
10846	$('form').find(':button[type=submit]').attr('disabled', !el.checked);
10847};
10848
10849// disable submit button unless all checkboxes are checked. used mostly for agree terms and conditions.
10850var toggle_submit_button2 = function(total_policies){
10851	var checked_number = $('input[name="terms[]"]:checked').length;
10852	$('form').find(':button[type=submit]:not(.policy-consent-accept)').attr('disabled', (checked_number != total_policies));
10853};
10854
10855function switch_test_variable(element) {
10856  if ($(element).is(':checked')) {
10857    window.location.href = '/testing_support/list?' + $(element).attr('id') + '=true';
10858  } else {
10859    window.location.href = '/testing_support/list?' + $(element).attr('id') + '=false';
10860  }
10861}
10862
10863// Get bankcode based on card type as per payubiz documentation.
10864function watch_bankcode() {
10865	$('#ccnum').on('change', function() {
10866		bankcode = detectCardType($(this).val());
10867		$('#bankcode').val(bankcode);
10868	});
10869
10870	function detectCardType(number) {
10871		number = $.trim(number);
10872		var re = {
10873			CC: /^4[0-9]{12}(?:[0-9]{3})?$|^5[1-5][0-9]{14}$/, // visa or master card
10874			AMEX: /^3[47][0-9]{13}$/, // american_express
10875			DINR: /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/ // diners
10876		};
10877
10878		for (var key in re) {
10879			if (re[key].test(number)) {
10880				return key
10881			}
10882		}
10883	}
10884}
10885
10886function show_credit_card_block(flag) {
10887	if (flag) {
10888    $('#payu_biz_cc_block').show();
10889	} else {
10890    $('#payu_biz_cc_block').hide();
10891	}
10892}
10893
10894function payu_biz_sync_cc_names() {
10895  $('#user_first_name').blur(function() {
10896    if ($('#firstname').length > 0) {
10897      $('[id="firstname"]').val(this.value);
10898    }
10899  });
10900  $('#user_last_name').blur(function() {
10901    if ($('#lastname').length > 0) {
10902      $('[id="lastname"]').val(this.value);
10903    }
10904  });
10905  $('#user_email').blur(function() {
10906    if ($('#email').length > 0) {
10907      $('[id="email"]').val(this.value);
10908    }
10909  });
10910}
10911
10912// tabs
10913
10914function init_draggable_tabs(object_id, tabs_controller) {
10915  $("#tab_list").sortable({
10916    handle : 'td.draggable_handle',
10917    update : function(event, ui) {
10918      var tab_ids = $('#tab_list tr').map( function() { return $(this).attr('data-tab_id'); } ).toArray();
10919      window.location.href = '/' + tabs_controller + '/update_tabs_order/' + object_id + '?tab_ids=' + tab_ids.join(',');
10920    }
10921  });
10922
10923  $("#tab_list").disableSelection();
10924}
10925
10926function set_tab(item_id, tabs_controller, checkbox) {
10927  window.location.href = '/' + tabs_controller + '/set_tab/' + item_id + '?attribute=' + checkbox.value + '&value=' + (checkbox.checked ? 'true' : 'false');
10928}
10929
10930function set_start_tab(item_id, checkbox) {
10931	window.location.href = '/class_configure/set_start_tab/' + item_id + '?attribute=' + checkbox.value + '&value=' + (checkbox.checked ? 'true' : 'false');
10932}
10933
10934function init_draggable_profile_tabs() {
10935	$("#tab_list").sortable({
10936		handle : 'td.draggable_handle',
10937		update : function(event, ui) {
10938			var tab_ids = $('#tab_list tr').map( function() { return $(this).attr('data-tab_id'); } ).toArray();
10939			window.location.href = '/profile_tabs/update_tabs_order?tab_ids=' + tab_ids.join(',');
10940		}
10941	});
10942
10943	$("#tab_list").disableSelection();
10944}
10945
10946function nospaces(t){
10947    if(t.value.match(/\s/g)){
10948        t.value=t.value.replace(/\s/g,'');
10949    }
10950}
10951
10952// return card type based on credit card (paypal pro).
10953function watch_card_type() {
10954    $('#credit_card_number').on('change', function () {
10955        cardtype = detectCardTypePaypalPro($(this).val());
10956        $('#credit_card_card_type').val(cardtype);
10957    });
10958}
10959
10960function detectCardTypePaypalPro(number) {
10961	number = $.trim(number);
10962	var re = {
10963		visa: /^4[0-9]{12}(?:[0-9]{3})?$/,
10964		mastercard: /^5[1-5][0-9]{14}$/,
10965		amex: /^3[47][0-9]{13}$/,
10966		discover: /^6(?:011|5[0-9]{2})[0-9]{12}$/
10967	};
10968
10969	for (var key in re) {
10970		if (re[key].test(number)) {
10971			return key
10972		}
10973	}
10974}
10975
10976function isNumberKey(evt){
10977    var charCode = (evt.which) ? evt.which : evt.keyCode;
10978    if (charCode > 31 && (charCode < 48 || charCode > 57))
10979        return false;
10980    return true;
10981}
10982
10983function numericOnly() {
10984    $(".numericOnly").bind('keypress', function (e) {
10985            if (e.keyCode == '9' || e.keyCode == '16') {
10986                return;
10987            }
10988            var code;
10989            if (e.keyCode) code = e.keyCode;
10990            else if (e.which) code = e.which;
10991            if (e.which == 46)
10992                return true;
10993            if (code == 8 || code == 46)
10994                return true;
10995            if (code < 48 || code > 57)
10996                return false;
10997        }
10998    );
10999    $(".numericOnly").bind("paste", function (e) {
11000        e.preventDefault();
11001    });
11002    $(".numericOnly").bind('mouseenter', function (e) {
11003        var val = $(this).val();
11004        if (val != '0') {
11005			val = val.replace(/[^0-9.]+/g, "");
11006            $(this).val(val);
11007        }
11008    });
11009}
11010
11011// Toggle switch
11012function toggle_the_switch(element, toggle_elements){
11013	$(toggle_elements).toggle();
11014	$(element).parent().siblings('span').toggleClass('selected');
11015}
11016
11017// grading scale changed
11018
11019function update_max_score(select) {
11020	if ($('#assignment_max_score').length > 0) {
11021		var selected_points = $(select.options[select.selectedIndex]).attr('data-points');
11022		if (selected_points.length > 0) {
11023			$('.max-info').show();
11024			$('#assignment_max_score').hide();
11025			$('#assignment_max_score').val(parseInt(selected_points));
11026		} else {
11027			$('.max-info').hide();
11028			$('#assignment_max_score').show();
11029		}
11030	}
11031}
11032
11033// comment thread
11034
11035function grading_save_thread_comment(id, student_id, peer_id, result_id, origin, gradebook) {
11036  var textarea = $('.grading-thread-comment-textarea #comment');
11037  var gradebook_check = gradebook || false;
11038  var editor = tinyMCE.get($(textarea).attr('id'));
11039  var content = editor.getContent();
11040
11041  if (isStringEmpty(content)) {
11042    $.alert({content: "The comment can't be empty"});
11043  } else {
11044    var data = {student_id: student_id, peer_id: peer_id, content: content, origin: origin, gradebook: gradebook_check};
11045
11046    if (result_id != false) {
11047      data.result_id = result_id;
11048      grading_save_comment(id, data, editor);
11049    } else {
11050      $.ajax({
11051        url: '/teacher_assignment/get_result_id/' + id,
11052        data: {student: student_id},
11053        async: false,
11054        success: function (response) {
11055          if (response.result_id != false) {
11056            data.result_id = response.result_id;
11057          }
11058
11059          grading_save_comment(id, data, editor);
11060        }
11061      });
11062    }
11063  }
11064}
11065
11066function grading_save_comment(id, data, editor) {
11067  $.ajax({
11068    type: 'POST',
11069    url: '/comment_thread/save/' + id,
11070    data: data,
11071    async: false,
11072    success: function(response) {
11073      if (response.status == 'bad') {
11074        $.alert({content: response.message});
11075      } else {
11076        $('.grading-thread-comment-list').append(response);
11077        editor.setContent('');
11078        editor.isNotDirty = 1;
11079      }
11080    }
11081  });
11082}
11083
11084function grading_comment_thread_events(id, gradebook) {
11085  var active = false;
11086  var gradebook_check = gradebook || false;
11087
11088  $('.grading-thread-comment-list').on('click', function(e) {
11089    var el = $(e.target);
11090    var comment_wrapper = el.parents('.comment');
11091    var comment_id = comment_wrapper.data('id');
11092    var content_wrapper = comment_wrapper.find('.content');
11093    var content = content_wrapper.html();
11094
11095    if (el.hasClass('delete')) {
11096      if (active == true) {
11097        return false;
11098      }
11099
11100      $.confirm({
11101        content: "Do you really want to delete this comment?",
11102        confirm: function() {
11103          var comment_wrapper = el.parents('.comment');
11104          var comment_id = comment_wrapper.data('id');
11105
11106          $.post('/comment_thread/delete/' + id, {comment: comment_id}, function(response) {
11107            if (response.status == 'ok') {
11108              comment_wrapper.remove();
11109            } else {
11110              $.alert({content: response.message});
11111            }
11112          });
11113        }
11114      });
11115    }
11116
11117    if (el.hasClass('edit')) {
11118      if (active == true) {
11119        return false;
11120      }
11121
11122	  var textarea = $('.grading-thread-comment-textarea #comment');
11123	  var editor = tinyMCE.get($(textarea).attr('id'));
11124	  editor.remove();
11125	  $(textarea).hide();
11126	  $('p.grading-thread-comment-options').hide();
11127
11128      $.ajax({
11129        type: 'POST',
11130        url: '/comment_thread/edit/' + id,
11131        data: {comment: comment_id},
11132        dataType: 'html',
11133        success: function(html) {
11134          content_wrapper.html('').html(html + '<div class="update-options alignR"><a href="javascript:void(0)" class="ml10 inline-update">Update</a><a href="javascript:void(0)" class="ml10 inline-cancel">Cancel</a></div>');
11135          // workaround FF tinymce editor issue
11136		  if(typeof reinit_tinymce_editor !== 'undefined' && typeof reinit_tinymce_editor === 'function'){
11137              reinit_tinymce_editor(comment_id);
11138		  }
11139        }
11140      });
11141
11142      active = true;
11143    }
11144
11145    if (el.hasClass('inline-update')) {
11146		var editor = tinyMCE.get($('#comment_text_' + comment_id).attr('id'));
11147		content = editor.getContent();
11148
11149		var option_directionality = editor.options.get('directionality');
11150		var option_language = editor.options.get('language');
11151		var option_height = editor.options.get('height');
11152
11153      if (content.trim() == '') {
11154        $.alert({content: "The comment can't be empty"});
11155      } else {
11156        $.post('/comment_thread/update/' + id, {comment: comment_id, content: content, gradebook: gradebook_check}, function(response) {
11157          if (response.status == 'bad') {
11158            $.alert({content: response.message});
11159            comment_thread_get_original(id, comment_id, editor, comment_wrapper, gradebook_check)
11160          } else {
11161			editor.remove();
11162			comment_wrapper.html(response);
11163
11164			$('.grading-thread-comment-textarea #comment').show();
11165			$('p.grading-thread-comment-options').show();
11166			tinyMCEenable("#comment", option_directionality, option_height, option_language, "");
11167          }
11168
11169          active = false;
11170        });
11171      }
11172    }
11173
11174    if (el.hasClass('inline-cancel')) {
11175      var editor = tinyMCE.get($('#comment_text_' + comment_id).attr('id'));
11176
11177	  var option_directionality = editor.options.get('directionality');
11178	  var option_language = editor.options.get('language');
11179	  var option_height = editor.options.get('height');
11180
11181      comment_thread_get_original(id, comment_id, editor, comment_wrapper, gradebook_check);
11182      active = false;
11183
11184	  var textarea = $('.grading-thread-comment-textarea #comment');
11185	  $(textarea).show();
11186	  $('p.grading-thread-comment-options').show();
11187	  tinyMCEenable("#comment", option_directionality, option_height, option_language, "");
11188    }
11189  });
11190}
11191
11192function comment_thread_get_original(id, comment_id, editor, wrapper, gradebook) {
11193  var gradebook_check = gradebook || false;
11194
11195  $.ajax({
11196    type: 'POST',
11197    url: '/comment_thread/get_original/' + id,
11198    data: {comment: comment_id, gradebook: gradebook_check},
11199    dataType: 'html',
11200    success: function(response) {
11201      editor.remove();
11202      wrapper.html(response);
11203    }
11204  });
11205}
11206
11207/* rubric points ordering*/
11208function set_rubric_points_ordering(order) {
11209	ajax_request('/standard_grading_scales/set_rubric_points_ordering?rubric_points_ordering=' + order );
11210}
11211
11212/* validate user email fields */
11213function validateEmail(email) {
11214  var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
11215  return re.test(email.trim());
11216}
11217
11218function validatePassword(password) {
11219	if (typeof strong_password_regex == 'undefined' || typeof school_strong_passwords == 'undefined') {
11220		return true;
11221	}
11222
11223	if (school_strong_passwords) {
11224		return strong_password_regex.test(password);
11225	} else {
11226		return password.length >= regular_password_min_chars;
11227	}
11228}
11229
11230function remove_validation_error(el) {
11231	$('label[for=' + el.id + ']').find('i.error').remove();
11232	$(el).removeAttr('aria-invalid');
11233	$('#' + el.id + '_error_msg').remove();
11234}
11235
11236function validate_and_show_error(el) {
11237	var el_val = $(el).val().trim();
11238	if ((el_val != '') && !validateEmail(el_val)) {
11239		display_validation_error(el, 'Please enter a valid email');
11240	} else {
11241		remove_validation_error(el);
11242	}
11243}
11244
11245function display_validation_error(el, text) {
11246	remove_validation_error(el);
11247
11248	// Add error icon with tooltip
11249	$('label[for=' + el.id + ']').append("<i class='error icnColor floatR mr0' id='"+ el.id +"_tippy'></i>");
11250	$(el).attr('aria-invalid', 'true');
11251	tippy('#' + el.id + '_tippy', {
11252		content: text,
11253		arrow: true,
11254		theme: 'error',
11255		maxWidth: '350px',
11256		placement: (is_rtl_mode() ? 'top-start' : 'top-end'),
11257		allowHTML: false
11258	});
11259
11260	// Add visible error message below the field
11261	var errorMsg = $('<div class="validation-error-message" id="' + el.id + '_error_msg" role="alert" aria-live="polite"><i class="error"></i> ' + text + '</div>');
11262	$(el).after(errorMsg);
11263}
11264
11265function validate_and_show_error_user_email(el) {
11266	validate_and_show_error(el);
11267
11268	var ec_el = document.getElementById('user_email_confirmation');
11269	var ec_el_val = $(ec_el).val().trim();
11270	var el_val = $(el).val().trim();
11271
11272	if (el_val === '') {
11273		$(ec_el).val('');
11274		remove_validation_error(ec_el);
11275	}else if (ec_el_val.toLowerCase() !== el_val.toLowerCase()) {
11276		if (ec_el_val === '') {
11277			display_validation_error(ec_el, 'Please enter a valid email');
11278		}else {
11279			display_validation_error(ec_el, 'Email and Confirm email does not match');
11280		}
11281	}
11282}
11283
11284function validate_and_show_error_user_email_confirmation(el) {
11285	validate_and_show_error(el);
11286
11287	var el_val = $(el).val().trim();
11288
11289	if ((el_val !== '') && validateEmail(el_val) && (el_val.toLowerCase() !== $('#user_email').val().trim().toLowerCase())) {
11290		display_validation_error(el, 'Email and Confirm email does not match');
11291	}
11292}
11293
11294function validate_user_email_and_confirmation() {
11295	validate_and_show_error_user_email(document.getElementById('user_email'));
11296	validate_and_show_error_user_email_confirmation(document.getElementById('user_email_confirmation'));
11297}
11298
11299function validate_and_show_error_user_password(el) {
11300	var pswc_el = document.getElementById('user_password_confirmation');
11301
11302	if ($(el).val() === '' || validatePassword($(el).val())) {
11303		remove_validation_error(el);
11304	}
11305
11306	if ($(el).val() === '') {
11307		$(pswc_el).val('');
11308		remove_validation_error(pswc_el);
11309	} else if (!validatePassword($(el).val())) {
11310		display_validation_error(el, 'Please enter a valid password');
11311	} else if ($(pswc_el).val() !== $(el).val()) {
11312		if ($(pswc_el).val() === '') {
11313			display_validation_error(pswc_el, 'Please enter a valid password');
11314		} else {
11315			display_validation_error(pswc_el, 'Password and Confirm password does not match');
11316		}
11317	}
11318}
11319
11320function validate_and_show_error_user_password_confirmation(el) {
11321	if ($(el).val() === '') {
11322		display_validation_error(el, 'Please enter a valid password');
11323	}else if ($(el).val() !== $('#user_password').val()) {
11324		display_validation_error(el, 'Password and Confirm password does not match');
11325	}else {
11326		remove_validation_error(el);
11327	}
11328}
11329
11330function validate_user_password_and_confirmation() {
11331	validate_and_show_error_user_password(document.getElementById('user_password'));
11332	validate_and_show_error_user_password_confirmation(document.getElementById('user_password_confirmation'));
11333}
11334
11335$(document).ready(function() {
11336	$(document).on('keyup', '#user_email, #user_email_confirmation', function() {
11337		validate_user_email_and_confirmation();
11338	});
11339
11340	$(document).on('keyup', '#user_password, #user_password_confirmation', function() {
11341		validate_user_password_and_confirmation();
11342	});
11343
11344	$(document).on('keyup', '#user_sms_email', function() {
11345		validate_and_show_error(this);
11346	});
11347});
11348
11349// Disable submit button until all required fields are filled.
11350
11351function validate_user_signup_form(fields, form_id, submit_btn) {
11352
11353	submit_btn.attr('disabled', 'disabled');
11354	var email_fields = ['email','email_confirmation','sms_email'];
11355
11356	if( $('#user_country').length) {
11357		$('#user_country').bind('change', function() {
11358			if ($(this).val() == 'United States' || $(this).val() == 'Brazil') {
11359				$.each( fields, function(i, e) { if( e == 'other_state' ) fields[i] = 'state'; } );
11360			}
11361			else {
11362				$.each( fields, function(i, e) { if( e == 'state' ) fields[i] = 'other_state'; } );
11363			}
11364		});
11365	}
11366	if ($('#user_other_state_div').is(':visible')) {
11367		$.each( fields, function(i, e) { if( e == 'state' ) fields[i] = 'other_state'; } );
11368	}
11369
11370	$('form#'+ form_id).find('[id^=user_],input[id="organization"],input[name="terms[]"]').bind("change keyup", function() {
11371
11372		var empty = false;
11373		$.each( fields, function( i, v ) {
11374			if ((v == 'state') || (v == 'other_state')) {
11375				if (($('input#user_' + v).val() == '') || ($('select#user_' + v).val() == '')) {
11376					empty = true;
11377				}
11378			} else {
11379				// organization field
11380				if (v == 'organization') {
11381					if ($('#user_organization_id').val() == 'other') {
11382						empty = $('form#' + form_id +' #' + v).val() == '';
11383					} else {
11384						empty = $('#user_organization_id').val() == '';
11385					}
11386				} else {
11387					if (($('#user_' + v).val() == '') || ($('form#'+ form_id +' #'+ v).val() == '')) {
11388						empty = true;
11389					}
11390				}
11391			}
11392
11393			// confirmation fields
11394			if (($('#user_' + v + '_confirmation').length > 0)) {
11395				if (v == 'email') {
11396					var confirmation_is_equal = ($('#user_email_confirmation').val().trim().toLowerCase() == $('#user_email').val().trim().toLowerCase());
11397				} else {
11398					var confirmation_is_equal = ($('#user_' + v + '_confirmation').val().trim() == $('#user_' + v).val().trim());
11399				}
11400				if ($('#user_' + v + '_confirmation').val() == '' || !confirmation_is_equal) {
11401					empty = true;
11402				}
11403			}
11404
11405			// date fields
11406			if (($('#user_' + v + '_1i').length > 0) && (($('#user_' + v + '_1i').val() == '') || ($('#user_' + v + '_2i').val() == '') || ($('#user_' + v + '_3i').val() == ''))) {
11407				empty = true;
11408			}
11409		}); // fields - each
11410
11411		$.each( email_fields, function( i, v ) {
11412			if (($('#user_' + v).length > 0) && ($('#user_' + v).val() != '') && !validateEmail($('#user_' + v).val())) {
11413				empty = true;
11414			}
11415		}); // email_fields - each
11416
11417		// password strength validation
11418		if (!validatePassword($('#user_password').val())) {
11419			empty = true;
11420		}
11421
11422		var checked_terms = $('input[name="terms[]"]:checked').length;
11423		var total_terms = $('input[name="terms[]"]').length;
11424
11425		if( !empty && ((total_terms == 0) || (checked_terms == total_terms)) )
11426			submit_btn.removeAttr('disabled');
11427		else
11428			submit_btn.attr('disabled', 'disabled');
11429	}); // keyup
11430}
11431
11432/* message form */
11433
11434function show_extra_field_in_message_form(elem, target_input_area) {
11435	$('.' + target_input_area).show();
11436	$(elem).remove();
11437	return false;
11438}
11439function start_message_sortable() {
11440	$(".drag-link ul").sortable({
11441		connectWith: ".drag-link ul",
11442		zIndex: 9999,
11443		update: function (event, ui) {
11444			var $elem = ui.item;
11445			var parent = $elem.closest('ul');
11446			parent.find('.select2-search-field').appendTo(parent);
11447		},
11448		start: function (event, ui) {
11449			var input = ui.item.closest('p').find('> input');
11450			var id = ui.item.data().select2Data.id;
11451			input.val(input.val().replace((',' + id), '').replace(id, ''));
11452			input.val().charAt(0) == "," && input.val(input.val().substring(1));
11453			ui.item.closest('ul').addClass('allow-overflow');
11454		},
11455		stop: function (event, ui) {
11456			var $elem = ui.item;
11457			var parent = $elem.closest('ul');
11458			var id = $elem.data().select2Data.id;
11459			var input = parent.closest('p').find('> input');
11460			input.val((input.val() == "" ? id : (input.val() + ',' + id)));
11461			$(".drag-link ul").removeClass('allow-overflow');
11462		}
11463	}).disableSelection();
11464}
11465function add_sender_placeholder(select2_data, select2_data_size, input_id){
11466  if (select2_data.length <= 5) {
11467    return false;
11468  }
11469
11470  var input = $(input_id);
11471  var placeholder = $('<div class="senders-placeholder active"><span class="more">more</span></div>').insertBefore( input );
11472  var more_users = select2_data_size;
11473  var width_alotted = placeholder.width() - 200;
11474  var width_accumulated = 0;
11475  for (i=0; i < select2_data.length; i++) {
11476    var temp = $('<span>' + select2_data[i].text + '</span>').insertBefore(placeholder.find('.more'));
11477    width_accumulated += temp.width();
11478    if (width_accumulated > width_alotted && placeholder.find('> *').length > 2) {
11479      temp.remove();
11480      break;
11481    }
11482    more_users -= 1;
11483  }
11484	placeholder.find('.more').text(more_users + ' more');
11485  placeholder.on('click', function(e){
11486    if (select2_data.length == select2_data_size) {
11487      e.preventDefault();
11488      e.stopPropagation();
11489      placeholder.closest('form').one('click', function(e){
11490        add_sender_placeholder(select2_data, select2_data_size, input_id);
11491        e.preventDefault();
11492        e.stopPropagation();
11493      });
11494      placeholder.remove();
11495  } else {
11496    $.alert({content: "You can edit this field only if selected users are upto 50."});
11497  }
11498  });
11499  if (more_users == 0) {
11500    placeholder.remove();
11501  }
11502}
11503
11504/* widgets */
11505
11506function widget_show_hide(el) {
11507	$.post($(el).attr('href'), function(response) {
11508		location.reload();
11509	});
11510}
11511
11512function confirmation_first(el, message) {
11513  $.confirm({
11514    content: message,
11515    confirm: function(){
11516      window.location.href = $(el).attr('href');
11517    }
11518  });
11519}
11520
11521/* Wallet: toggle show/hide coupon code */
11522
11523function set_hide_details(user_id, wallet_entry_id, checkbox) {
11524	ajax_request('/wallet/set_hide_details/' + user_id + '?wallet_entry_id=' + wallet_entry_id + '&value=' + (checkbox.checked ? 'true' : 'false'));
11525}
11526
11527/* show message popup */
11528
11529function toogle_extra_users_list(id1, id2) {
11530	$('#' + id1).hide();
11531	$('#' + id2).show();
11532}
11533
11534/* select2 aria */
11535
11536// Copy aria-label from the underlying control onto select2's auto-generated
11537// search input so screen-reader users hear a meaningful label when focusing
11538// the widget instead of an unnamed text field.
11539function propagate_select2_aria_label(id) {
11540    const $el = $(id);
11541    const label = $el.attr('aria-label');
11542    if (!label) return;
11543    const $container = $el.select2('container');
11544    if ($container && $container.length) {
11545        $container.find('input.select2-input').attr('aria-label', label);
11546    }
11547}
11548
11549// Patch Select2 3.4.5 (which generates no ARIA) with the combobox/listbox
11550// design pattern required by WCAG 2.1 SC 4.1.2.
11551function patch_select2_aria(id, isAjax) {
11552    const $el = $(id);
11553    const s2 = $el.data('select2');
11554    if (!s2) return;
11555    const $container = s2.container;
11556    if (!$container || !$container.length) return;
11557
11558    const $input = $container.find('input.select2-input');
11559    const listboxId = id.replace(/[^a-zA-Z0-9]/g, '_').replace(/^_+/, '') + '_listbox';
11560    const isMultiple = s2.opts.multiple || $el.prop('multiple');
11561
11562    // In single-select mode the search input lives inside the hidden dropdown, so
11563    // attaching combobox ARIA to it produces a broken partial implementation.
11564    // Only multi-select widgets have the input visible in the container.
11565    if (!isMultiple) return;
11566
11567    const ns = '.s2aria_' + listboxId;
11568
11569    $input.attr({
11570        'role': 'combobox',
11571        'aria-expanded': 'false',
11572        'aria-autocomplete': 'list',
11573        'aria-controls': listboxId
11574    });
11575
11576    // Set listbox id and role at init time so aria-controls is not dangling before first open.
11577    // The <ul class="select2-results"> exists inside s2.dropdown from Select2 init.
11578    const $initResults = s2.dropdown.find('.select2-results');
11579    if ($initResults.length) {
11580        // Select2 only detaches the dropdown from <body> in destroy(), which nothing calls, so a
11581        // popup that is closed and reopened leaves an orphaned listbox still holding this id.
11582        // Release it before claiming it or aria-controls resolves to that stale, emptied node.
11583        $('[id="' + listboxId + '"]').not($initResults).removeAttr('id');
11584        const initAttrs = {'id': listboxId, 'role': 'listbox'};
11585        if (isMultiple) { initAttrs['aria-multiselectable'] = 'true'; }
11586        $initResults.attr(initAttrs);
11587    }
11588
11589    function patchResults() {
11590        // Bail if this instance is not currently open — prevents clobbering another widget's
11591        // listbox when a late AJAX response fires while a different filter's dropdown is open.
11592        if (!s2.opened()) return;
11593        const $results = s2.dropdown.find('.select2-results');
11594        if (!$results.length) return;
11595        const listboxAttrs = {'role': 'listbox', 'id': listboxId};
11596        if (isMultiple) { listboxAttrs['aria-multiselectable'] = 'true'; }
11597        $results.attr(listboxAttrs);
11598        let selectedVals = $el.select2('val') || [];
11599        if (!Array.isArray(selectedVals)) { selectedVals = selectedVals ? [selectedVals] : []; }
11600        $results.find('li.select2-result-selectable').each(function(i) {
11601            const optionData = $(this).data('select2-data');
11602            const isSelected = optionData && selectedVals.indexOf(String(optionData.id)) !== -1;
11603            const attrs = {'role': 'option', 'aria-selected': isSelected ? 'true' : 'false', 'id': listboxId + '_' + i};
11604            if (isAjax) { attrs['aria-setsize'] = '-1'; attrs['aria-posinset'] = i + 1; }
11605            $(this).attr(attrs);
11606        });
11607        // Status items injected into the same <ul> — give them role="option" aria-disabled="true"
11608        // so the listbox has no invalid children. Includes select2-selection-limit (rendered at
11609        // select2.js:1600 when maximumSelectionSize is reached).
11610        $results.children('li.select2-searching, li.select2-no-results, li.select2-more-results, li.select2-selection-limit')
11611                .attr({'role': 'option', 'aria-disabled': 'true'});
11612        // Sync aria-activedescendant now that all options have ids — select2-highlight fires
11613        // before patchResults() on first open, so the initial highlight would otherwise be missed.
11614        const $highlighted = $results.find('.select2-highlighted');
11615        const highlightedId = $highlighted.attr('id');
11616        if (highlightedId) {
11617            $input.attr('aria-activedescendant', highlightedId);
11618        } else {
11619            $input.removeAttr('aria-activedescendant');
11620        }
11621    }
11622
11623    // Override the instance's opening() method so patchResults() runs 
11623inside Select2's own
11624    // call chain, after AbstractSelect2.opening() has moved the dropdown to <body> and set
11625    // id="select2-drop", and after updateResults(true) has populated results for static data.
11626    const originalOpening = s2.opening;
11627    s2.opening = function() {
11628        originalOpening.apply(this, arguments);
11629        $input.attr('aria-expanded', 'true');
11630        patchResults();
11631    };
11632
11633    // Wrap opts.query so patchResults() runs after every results render, including the
11634    // "No matches found" path. select2-loaded is not triggered when results.length === 0
11635    // (select2.js:1675-1678 returns early), and the keyup handler holds a direct reference
11636    // to the original updateResults so overriding s2.updateResults misses keypress events.
11637    const originalQuery = s2.opts.query;
11638    s2.opts.query = function(options) {
11639        const originalCallback = options.callback;
11640        options.callback = function(data) {
11641            originalCallback(data);
11642            patchResults();
11643        };
11644        originalQuery.call(this, options);
11645    };
11646
11647    // Tear down any listeners from a prior patch_select2_aria call on this element before
11648    // rebinding — prevents handler stacking when the same element is re-initialised
11649    // (e.g. init_filterable_select called twice on a fixed id like 'tags_selector').
11650    $el.off(ns);
11651    $input.off(ns);
11652
11653    // For AJAX filters: results arrive after the initial open (select2-loaded fires after
11654    // each AJAX response), so we also patch via the event to catch those updates.
11655    $el.on('select2-loaded' + ns, function() {
11656        patchResults();
11657    });
11658
11659    // Re-patch after every selection change so aria-selected stays in sync.
11660    // MultiSelect2.onSelect triggers 'selected' (not 'select2-selected') — bind both.
11661    $el.on('select2-selected' + ns + ' selected' + ns + ' select2-removed' + ns, function() {
11662        patchResults();
11663    });
11664
11665    // Label each chip's remove button so screen readers can announce what is selected.
11666    // Selected items are hidden by Select2 CSS and never appear in the listbox,
11667    // so aria-selected on options cannot expose selection state — the chips must.
11668    // Use MutationObserver so chips are patched immediately on DOM insertion,
11669    // independent of which Select2 event fires (differs between static and AJAX filters).
11670    const removeLabel = $el.attr('data-remove-label') || '';
11671    function patchChip($chip) {
11672        const text = $chip.find('div').first().text();
11673        if (text) { $chip.find('.select2-search-choice-close').attr('aria-label', removeLabel ? removeLabel + ' ' + text : text); }
11674    }
11675    const $choices = $container.find('.select2-choices');
11676    if ($choices.length) {
11677        new MutationObserver(function(mutations) {
11678            mutations.forEach(function(m) {
11679                $(m.addedNodes).filter('.select2-search-choice').each(function() { patchChip($(this)); });
11680            });
11681        }).observe($choices[0], { childList: true });
11682    }
11683    // Patch any pre-selected chips that exist at init time.
11684    $container.find('.select2-search-choice').each(function() { patchChip($(this)); });
11685
11686    $el.on('select2-close' + ns, function() {
11687        $input.attr('aria-expanded', 'false');
11688        $input.removeAttr('aria-activedescendant');
11689    });
11690
11691    $el.on('select2-highlight' + ns, function() {
11692        if (!s2.opened()) return;
11693        const $highlighted = s2.dropdown.find('.select2-highlighted');
11694        const highlightedId = $highlighted.attr('id');
11695        if (highlightedId) $input.attr('aria-activedescendant', highlightedId);
11696    });
11697
11698    // Patch status <li>s rendered by updateResults early-return paths (formatInputTooShort,
11699    // formatInputTooLong, selection limit) which call results.html() then return before
11700    // opts.query is ever invoked. Defer 0 ms so select2's synchronous render completes first.
11701    $input.on('keyup-change' + ns + ' input' + ns + ' paste' + ns, function() {
11702        setTimeout(patchResults, 0);
11703    });
11704}
11705
11706/* categories, tags select2 */
11707
11708function init_filterable_select(id, inputs, suggest_url) {
11709  $('input#' + id).select2({
11710    multiple : true,
11711    allowClear: true,
11712    maximumSelectionSize : 40, // for limitation of people number in the "to" fields
11713    minimumInputLength : 2, // minimum chars to start the suggest query
11714    initSelection : function (element, callback) {
11715      var data = [];
11716      $.each(inputs, function (i, v) {
11717        data.push({id: v, text: v});
11718      });
11719      callback(data);
11720    },
11721    ajax : {
11722      type : "GET",
11723      url : suggest_url,
11724      dataType : 'json',
11725      quietMillis : 500, // bigger delay before ajax is called
11726      data : function(term) {
11727        return {
11728          q : term
11729        };
11730      },
11731      results : function(data) {
11732        var results = {
11733          results : []
11734        };
11735
11736        $.each(data, function() {
11737          results.results.push({
11738            id : this.id,
11739            text : this.value
11740          });
11741        });
11742
11743        return results;
11744      }
11745    }
11746  });
11747  propagate_select2_aria_label('input#' + id);
11748  patch_select2_aria('input#' + id, true);
11749}
11750
11751/* tags select2 */
11752
11753function init_subjects_select(id, subjects, suggest_url) {
11754  $('input#' + id).select2({
11755    multiple : true,
11756    allowClear: true,
11757    maximumSelectionSize : 40, // for limitation of people number in the "to" fields
11758    minimumInputLength : 2, // minimum chars to start the suggest query
11759    initSelection : function (element, callback) {
11760      var data = [];
11761      $.each(subjects, function (i, v) {
11762        data.push({id: v[0], value: v[0], text: v[1]});
11763      });
11764      callback(data);
11765    },
11766    ajax : {
11767      type : "GET",
11768      url : suggest_url,
11769      dataType : 'json',
11770      quietMillis : 500, // bigger delay before ajax is called
11771      data : function(term) {
11772        return {
11773          subject : term
11774        };
11775      },
11776      results : function(data) {
11777        var results = {
11778          results : []
11779        };
11780
11781        $.each(data, function() {
11782          results.results.push({
11783            id : this.id,
11784            value: this.value,
11785            text : this.label
11786          });
11787        });
11788
11789        return results;
11790      }
11791    }
11792  });
11793  propagate_select2_aria_label('input#' + id);
11794  patch_select2_aria('input#' + id, true);
11795}
11796
11797function quotas_select() {
11798	$('#users').select2({
11799		multiple: true,
11800		maximumSelectionSize : 40, // for limitation of people number in the "to" fields
11801		minimumInputLength : 2, // minimum chars to start the suggest query
11802		ajax: {
11803			type : "GET",
11804			url: '/copilot_admin/suggest_users',
11805			dataType: 'json',
11806			quietMillis: 300,
11807			data: function (term) {
11808				q = term;
11809				return {
11810					name : q
11811				};
11812			},
11813			results: function (data) {
11814				results = {
11815					results : []
11816				};
11817				preload_data = data.results;
11818
11819				$.each(preload_data, function() {
11820					ln = this.last_name;
11821					fn = this.first_name;
11822					tln = ln.toUpperCase();
11823					tfn = fn.toUpperCase();
11824					tfnln = tfn + ' ' + tln;
11825					tlnfn = tln + ' ' + tfn;
11826
11827					q = q.trim();
11828					q = q.toUpperCase();
11829
11830					if (tln.indexOf(q) >= 0 || tfn.indexOf(q) >= 0 || tfnln.indexOf(q) >= 0 || tlnfn.indexOf(q) >= 0) {
11831						results.results.push({
11832							id : this.id,
11833							text : fn + ' ' + ln
11834						});
11835					}
11836				});
11837
11838				// the #users input will contain the ids: id1,id2,id3
11839				return results;
11840			}
11841		}
11842	});
11843}
11844
11845/* parse and create a variable object */
11846function getUrlVars(from) {
11847  var vars = {}, hash;
11848  var hashes = from.slice(from.indexOf('?') + 1).split('&');
11849
11850  for(var i = 0; i < hashes.length; i++)
11851  {
11852    hash = hashes[i].split('=');
11853    vars[hash[0]] = hash[1];
11854  }
11855
11856  return vars;
11857}
11858
11859// check file processing job status
11860
11861var only_one_file_check = true;
11862
11863function check_document_processing_status(id) {
11864  if (only_one_file_check == false) {
11865    return false;
11866  }
11867
11868  only_one_file_check = false;
11869
11870  setInterval(function() {
11871    $.get('/file_processing/check_status/' + id, function(response) {
11872      if (response.status == 'reload') {
11873        location.reload();
11874      }
11875    });
11876  }, 3000);
11877}
11878
11879// kaltura
11880
11881function kaltura_resource_create(url, title) {
11882  var parent_form = window.parent.$("form#kaltura_uploader_form");
11883
11884  parent_form.append('<input type="hidden" name="attachment_url" id="attachment_url" value="' + url + '">');
11885  parent_form.append('<input type="hidden" name="attachment_name" id="attachment_name" value="' + title + '">');
11886
11887  parent_form.submit();
11888}
11889
11890function kaltura_attachment_create(url, title) {
11891  var parent_wrapper = window.parent.$("div#kaltura_uploader_form");
11892  var main_wrapper = parent_wrapper.find("#kaltura_wrapper").val();
11893  var objects = {};
11894
11895  if ((main_wrapper == "post_filecontainer") || (main_wrapper == "announcement_filecontainer")) {
11896    objects[title] = url;
11897    window.parent.append_multiple_files(objects);
11898    window.parent.$.facebox.close();
11899  }
11900}
11901
11902/* change message fields */
11903
11904function toggleMessageFields(el) {
11905  changeLinksText(el);
11906  changeInputsLabelAndId(el);
11907}
11908
11909var inputMap = {
11910  'to': ['Cc', 'Bcc'],
11911  'cc': ['To', 'Bcc'],
11912  'bcc': ['To', 'Cc']
11913};
11914
11915function changeLinksText(el){
11916  $('#cc_link').text(inputMap[el.value][0]);
11917  $('#bcc_link').text(inputMap[el.value][1]);
11918}
11919
11920function changeInputsLabelAndId(el){
11921  $('.cc_label').text(inputMap[el.value][0] + ':');
11922  $('.bcc_label').text(inputMap[el.value][1] + ':');
11923  changeFieldsSequence(el.value);
11924}
11925
11926function changeFieldsSequence(element){
11927  for (var i = 0; i <= 2; i++) {
11928    $('.message-fields.select2-offscreen')[i]['id'] = fieldsList(element)[i];
11929  }
11930}
11931
11932function fieldsList(element) {
11933  var inputMap = {
11934    'to': ['to', 'cc', 'bcc'],
11935    'cc': ['cc', 'to', 'bcc'],
11936    'bcc': ['bcc', 'to', 'cc']
11937  };
11938  return inputMap[element]
11939}
11940
11941// app center search
11942
11943function app_center_search() {
11944  var storage = [];
11945
11946  $('.catalog_boxes > div').each(function(i) {
11947    $(this).data('initial-index', i);
11948  });
11949
11950  $("#app_center_search").on("keyup", function() {
11951    var value = $(this).val().toLowerCase();
11952    var to_remove = [];
11953
11954    $(".catalog_boxes > div").filter(function() {
11955      if ($(this).text().toLowerCase().indexOf(value) < 0) {
11956        storage.push($(this));
11957        $(this).detach();
11958      }
11959    });
11960
11961    $.each(storage, function(i, v) {
11962      if ($(v).text().toLowerCase().indexOf(value) > -1) {
11963        to_remove.push(i);
11964        $('.catalog_boxes').append(v);
11965      }
11966    });
11967
11968    $.each(to_remove, function(i,v) {
11969      storage.splice(v, 1);
11970    });
11971
11972    $('.catalog_boxes > div').sort(function(a, b) {
11973      return $(a).data('initial-index') - $(b).data('initial-index');
11974    }).appendTo('.catalog_boxes');
11975  });
11976}
11977
11978function app_center_search_new() {
11979  var phrase, categories;
11980
11981  $('#filter_form #phrase').keyup(function(e) {
11982    typewatch(function() {
11983      redirect();
11984    }, 1000);
11985  });
11986
11987  $('.users_filter').on('change', function(e) {
11988    redirect();
11989  });
11990
11991  var redirect = function() {
11992    let path = window.location.href.split('?')[0]
11993    let query = [];
11994
11995    phrase = $('#filter_form #phrase').val().trim();
11996
11997    if (phrase != '') {
11998      query.push('phrase=' + phrase);
11999    }
12000
12001    categories = $('#filter_form .users_filter:checked');
12002
12003    $.each(categories, function(i,v) {
12004      query.push($(v).attr('name') + '=true');
12005    });
12006
12007    window.location.href = path + (query.length > 0 ? '?' + query.join('&') : '');
12008  }
12009}
12010
12011// Google Fonts
12012
12013var google_fonts_data;
12014var google_fonts_data_initial;
12015var google_fonts_offset = 0;
12016var google_fonts_limit = 50;
12017var google_fonts_loading;
12018var google_fonts_scroll_pause = false;
12019var google_fonts_scroll_stop = false;
12020var google_fonts_selected = [];
12021
12022function get_google_fonts() {
12023  google_fonts_offset = 0;
12024  google_fonts_limit = 50;
12025  google_fonts_scroll_pause = false;
12026  google_fonts_scroll_stop = false;
12027
12028  $.each(google_fonts_selected, function(i, v) {
12029    $('#google_fonts_form').append('<input type="hidden" name="google_font[]" value="' + v + '" >');
12030  });
12031
12032  $('.google_fonts_top input').on("keyup", delay(function() {
12033    var term = $(this).val();
12034
12035    if (term.length > 1) {
12036      google_fonts_data = google_font_search(term);
12037    } else {
12038      google_fonts_data = google_fonts_data_initial;
12039    }
12040
12041    google_fonts_scroll_pause = false;
12042    google_fonts_scroll_stop = false;
12043    google_fonts_offset = 0;
12044    list_google_fonts();
12045  }));
12046
12047  function delay(fn) {
12048    var timer = 0;
12049    return function() {
12050	  $('.fonts_holder').html(google_fonts_loading);
12051      clearTimeout(timer);
12052      timer = setTimeout(fn.bind(this, arguments), 700 || 0);
12053    }
12054  }
12055
12056  $.get('/google_fonts/list', function(json) {
12057    google_fonts_data = json.items;
12058    google_fonts_data_initial = json.items;
12059    google_fonts_loading = $('.fonts_holder').find('.fonts_loading');
12060
12061    list_google_fonts();
12062
12063    $("#facebox .facebox-content, .modal.is-open .facebox-content").scroll(function() {
12064      if (!google_fonts_scroll_pause) {
12065        if ($(this).scrollTop() >= ($(this)[0].scrollHeight - $(this).height() - 50)) {
12066
12067          google_fonts_scroll_pause = true;
12068
12069          if (!google_fonts_scroll_stop) {
12070            list_google_fonts();
12071          }
12072        }
12073      }
12074    });
12075  });
12076}
12077
12078function list_google_fonts() {
12079  var fonts = [];
12080  var embed_link = "https://fonts.googleapis.com/css2?";
12081
12082  if (google_fonts_data.length == 0) {
12083    $('.fonts_holder').find('.fonts_loading').remove();
12084    $('.fonts_holder').append("<li><span class='no-results'>No fonts found</span></li>");
12085    return false;
12086  }
12087
12088  if (google_fonts_offset < google_fonts_data.length) {
12089    for (var i = google_fonts_offset; i < (google_fonts_offset + google_fonts_limit); i++) {
12090      if (google_fonts_data[i]) {
12091        google_fonts_data[i].index = i;
12092
12093        fonts.push(google_fonts_data[i]);
12094
12095        if (i == google_fonts_offset) {
12096          embed_link = embed_link + "family=" + google_fonts_data[i].family;
12097        } else {
12098          embed_link = embed_link + "&family=" + google_fonts_data[i].family;
12099        }
12100      }
12101    }
12102
12103    $('.fonts_holder').append("<link href=\"" + embed_link + "\" rel=\"stylesheet\">");
12104
12105    setTimeout(function() {
12106      $('.fonts_holder').find('.fonts_loading').remove();
12107
12108      $.each(fonts, function(i,font) {
12109        $('.fonts_holder').append("<li>" +
12110          "<input id=\"google_font_" + font.index + "\" name=\"google_font_" + font.index + "\" type=\"checkbox\" value=\"" + font.family + "\"" + ((google_fonts_selected && (google_fonts_selected.indexOf(font.family) !== -1)) ? ' checked' : '') + " onchange=\"check_google_font(this)\">" +
12111          "<label for=\"google_font_" + font.index + "\"><span>Font family: <b>" + font.family + "</b>, category: <b>" + font.category + "</b></span><span style=\"font-family: '" + font.family + "', " + font.category + ";\">Lorem ipsum dolor sit amet, consectetur adipiscing elit. In pellentesque orci ex, eget pellentesque ex efficitur eu.</label>" +
12112          "</li>");
12113      });
12114
12115      google_fonts_offset = google_fonts_offset + fonts.length;
12116      google_fonts_scroll_pause = false;
12117
12118      if (google_fonts_offset < google_fonts_data.length) {
12119        $('.fonts_holder').append(google_fonts_loading);
12120      }
12121    }, 1000);
12122  }
12123
12124  if (google_fonts_offset >= google_fonts_data.length) {
12125    google_fonts_scroll_stop = true;
12126    $('.fonts_holder').find('.fonts_loading').remove();
12127  }
12128}
12129
12130function check_google_font(el) {
12131  var $this = $(el);
12132
12133  if ($this.is(':checked')) {
12134    google_fonts_selected.push($this.val());
12135    $('#google_fonts_form').append('<input type="hidden" name="google_font[]" value="' + $this.val() + '" >');
12136  } else {
12137    var index = google_fonts_selected.indexOf($this.val());
12138
12139    if (index > -1) {
12140      google_fonts_selected.splice(index, 1);
12141      $('#google_fonts_form input:hidden').filter(function(){return this.value == $this.val()}).remove();
12142    }
12143  }
12144}
12145
12146function google_font_search(term) {
12147  return $.grep(google_fonts_data_initial, function(font, index) {
12148    return (font.family.toLowerCase().indexOf(term.toLowerCase()) !== -1);
12149  });
12150}
12151
12152// MS Immersive Reader
12153
12154function launchImmersiveReaderFromInlineHtml($this, contentLanguage) {
12155  const elements = $('[data-immersive-reader="true"]');
12156	let content = '';
12157
12158	if (elements.length > 0) {
12159		let contentArray = [];
12160		let clonedElements = elements.clone();
12161
12162		clonedElements.each(function() {
12163			var $element = $(this);
12164
12165			// Remove all script tags
12166			$element.find('script').remove();
12167
12168			// Replace audio player with text
12169			$element.find('.resource-flowplayer-audio').each(function() {
12170				$(this).replaceWith('<p>[Audio file available]</p>');
12171			});
12172
12173			// Replace video player with text
12174			$element.find('.resource-flowplayer-video').each(function() {
12175				$(this).replaceWith('<p>[Video file available]</p>');
12176			});
12177
12178			contentArray.push($element.html());
12179		});
12180
12181		content = contentArray.join('\n\n');
12182	} else {
12183		const buttonHolder = $($this).parent('.immersive-reader-button-holder');
12184
12185		let element = buttonHolder.nextAll('.materialStyle').first();
12186
12187		if (element.length == 0) {
12188			element = buttonHolder.nextAll('.widget-view-mode')
12189			                      .children('.materialStyle')
12190								  .first();
12191		}
12192
12193		if (element.length == 0) {
12194			element = buttonHolder.nextAll('.micro-card-container')
12195								  .children('.micro-card')
12196								  .children('.materialStyle')
12197								  .first();
12198		}
12199
12200		if (element.length == 1) {
12201			content = element.html();
12202		} else {
12203			return false;
12204		}
12205	}
12206
12207	const data = {
12208		chunks: [{
12209			mimeType: 'text/html',
12210			content: content,
12211			lang: contentLanguage
12212		}]
12213	};
12214
12215	$.get('/immersive_reader_token/fetch', function(response) {
12216		if (response.status == 'ok') {
12217			ImmersiveReader.launchAsync(response.token, response.subdomain, data);
12218		} else {
12219			$.alert({content: response.message})
12220		}
12221	});
12222}
12223
12224// Update unarchive user count
12225
12226function edit_unarchive_user_percentage() {
12227  element = $('#reactivate_user_percentage');
12228  element.prop("disabled", false);
12229  element.data('original_value', element.val());
12230  toggle_unarchive_buttons();
12231}
12232
12233function save_unarchive_user_percentage(school_id) {
12234  element = $('#reactivate_user_percentage');
12235  $.post('/school/update_archived_user_percentage/' + school_id, { value: element.val() });
12236  element.data('original_value', element.val());
12237  toggle_unarchive_buttons();
12238  element.prop("disabled", true);
12239}
12240
12241function cancel_unarchive_user_percentage() {
12242  element = $('#reactivate_user_percentage');
12243  element.val(element.data('original_value'));
12244  toggle_unarchive_buttons();
12245  element.prop("disabled", true);
12246}
12247
12248function toggle_unarchive_buttons() {
12249  $('#save_unarchive').toggle();
12250  $('#cancel_unarchive').toggle();
12251  $('#edit_unarchive').toggle();
12252}
12253
12254// Peer reviews
12255
12256function dismiss_assigning_error(el, controller, id, student_id) {
12257  $.post('/' + controller + '/dismiss_error/' + id, {student: student_id}, function(response) {
12258    var parent = $(el).parent('p');
12259
12260    parent.fadeOut(500, function() {
12261      parent.remove();
12262    });
12263  });
12264}
12265
12266function scroll_to_top(offset) {
12267	$('html, body').animate({
12268		scrollTop: offset
12269	}, 50);
12270}
12271
12272function set_require_safe_exam_browser_for_assignment(id, checkbox) {
12273	$.post('/teacher_assignment/set_requires_safe_exam_browser/' + id, {value: check_s(checkbox)});
12274	var additional_options = $('#seb_enabled_options');
12275
12276	if (checkbox.checked) {
12277		additional_options.show();
12278		$('.access_code_section').hide();
12279	} else {
12280		additional_options.hide();
12281		$('.access_code_section').show();
12282	}
12283}
12284
12285// SCORM preview image upload progress
12286
12287function preview_image_upload_progress(id) {
12288	const file_input = document.getElementById(id);
12289	const reader = new FileReader();
12290	const progress_bar = $('#' + id + '_progress');
12291
12292	file_input.addEventListener('change', function (){
12293		const selected_file = file_input.files[0];
12294
12295		if (selected_file) {
12296			reader.addEventListener('loadstart', function (e) {
12297				progress_bar.css({
12298					'background': "#fff",
12299					'border': '1px solid #ccc',
12300					'width': '278px',
12301					'height': '20px',
12302					'text-align': 'right',
12303					'font-weight': 'bold'
12304				});
12305
12306				progress_bar.html('0%');
12307				progress_bar.show();
12308			});
12309
12310			reader.addEventListener('load', function (e) {
12311				progress_bar.html('100%');
12312				progress_bar.css('background', '#85C3CC');
12313			});
12314
12315			reader.addEventListener('progress', function (e) {
12316				if (e.lengthComputable) {
12317					const percentLoaded = Math.round((e.loaded / e.total) * 100);
12318
12319					if (percentLoaded < 100) {
12320						progress_bar.html(percentLoaded + '%');
12321						progress_bar.css('background', 'linear-gradient(90deg, #85C3CC ' + percentLoaded + '%, #fff ' + percentLoaded + '%)');
12322					}
12323				}
12324			});
12325
12326			reader.readAsDataURL(selected_file);
12327		}
12328	});
12329}
12330
12331//
12332
12333function generate_alexa_key() {
12334  $.get('/account/generate_alexa_login_key', function(data) {
12335    if (data.key) {
12336      $('span.alexa-key-holder').html(data.key);
12337    } else {
12338      $.alert({content: "There was an error generating the login key. Please try again."});
12339    }
12340  });
12341}
12342
12343// SCORM launch with preview image
12344
12345function launch_scorm_iframe(id, url) {
12346	var iframe = $("#" + id);
12347	iframe.parent().show();
12348	iframe.attr('src', url);
12349	$("#" + id + "_play_button").hide();
12350}
12351
12352function mobile_cache_page( crc, url ){
12353	if(window.webkit)
12354		webkit.messageHandlers.cordova_iab.postMessage(JSON.stringify({'data': {'crc': crc, 'url': url}, 'method': 'app.AcceleratorAPI.loadPage'}));
12355	else
12356		setTimeout(function(){
12357			//get a better solution later timing is off
12358			webkit.messageHandlers.cordova_iab.postMessage(JSON.stringify({'data': {'crc': crc, 'url': url}, 'method': 'app.AcceleratorAPI.loadPage'}));
12359		},200);
12360
12361}
12362
12363// scheduled posts
12364
12365function delete_scheduled_post(url, posting_id) {
12366	$.confirm({
12367		content: 'Are you sure you want to delete it?',
12368		confirm: function () {
12369			ajax_request(url);
12370
12371			$.when($('#scheduled_post_' + posting_id).fadeOut()).done(function () {
12372				update_min_height();
12373				$('#scheduled_post_' + posting_id).remove();
12374
12375				if ($('.scheduled_posting_row').length === 0) {
12376					$('#scheduled_post_option_btn').hide();
12377					$.facebox.close();
12378				}
12379			});
12380		}
12381	});
12382}
12383
12384// switch between mobile and desktop filter mode
12385
12386function check_new_filter(mobile_holder_selector = "div.mobile_only div.categories_holder", desktop_holder_selector = "div.desktop_only.categories_holder") {
12387	var window_width = (window.innerWidth > 0) ? window.innerWidth : screen.width;
12388
12389	if ((window_width > 979) && ($(mobile_holder_selector + " form#filter_form").length > 0)) {
12390		// move form from div.mobile_only to div.desktop_only
12391		$(desktop_holder_selector).append($(mobile_holder_selector + "form#filter_form"));
12392		$(desktop_holder_selector + " form#filter_form").show();
12393	}else if ((window_width <= 979) && ($(desktop_holder_selector + " form#filter_form").length > 0)) {
12394		// move form from div.desktop_only to div.mobile_only
12395		$(mobile_holder_selector).append($(desktop_holder_selector + " form#filter_form"));
12396		if ($('a[data-element="filter_form"]').attr('aria-expanded') === 'true') {
12397			$(mobile_holder_selector + " form#filter_form").show();
12398		}else {
12399			$(mobile_holder_selector + " form#filter_form").hide();
12400		}
12401	}
12402}
12403
12404// check cookies status
12405
12406function check_cookies_status() {
12407	$.getJSON("/info/check_cookies_status", function (data) {
12408		if (data.cookies_disabled) {
12409			window.location.href = "/info/no_cookies";
12410		}
12411	});
12412}
12413
12414// group catalog filter
12415
12416function update_groups_filter(url) {
12417	var checkboxes = $('input[type=checkbox].groups_filter');
12418	var dropdowns = $('select.groups_filter');
12419	var name = $('input#name_filter');
12420
12421	for (var i = 0; i < checkboxes.length; i += 1) {
12422		var checkbox = checkboxes[i];
12423
12424		if (checkbox.checked) {
12425			url += '&' + checkbox.name + '=true';
12426		}
12427	}
12428
12429	for (var i = 0; i < dropdowns.length; i += 1) {
12430		var dropdown = dropdowns[i];
12431		url += '&' + dropdown.name + '=' + dropdown.value;
12432	}
12433
12434	if (name.val() != '') {
12435		url += '&name_filter=' + encodeURIComponent(name.val());
12436	}
12437
12438	let focusedId = document.activeElement && document.activeElement.id;
12439	$(window).one('loadcomplete', function() {
12440		if (focusedId) {
12441			let el = document.getElementById(focusedId);
12442			if (el && typeof el.focus === 'function') el.focus();
12443		}
12444	});
12445	Excalibur.Router.load( url, '#mainContent' );
12446}
12447
12448function init_group_name_filter(url, query) {
12449	$(document).on("keydown", "#filter_form", function(event) {
12450		return event.key != "Enter";
12451	});
12452
12453	var input = $('input#name_filter');
12454
12455	input.keyup(function(e) {
12456		typewatch(function() {
12457			var value = input.val().trim();
12458
12459			if (value != query) {
12460				update_groups_filter(url);
12461			}
12462		}, 1000);
12463	});
12464}
12465
12466// class catalog: switch between mobile and desktop filter mode
12467
12468function check_class_catalog_filter() {
12469	var window_width = (window.innerWidth > 0) ? window.innerWidth : screen.width;
12470
12471	if ((window_width > 979) && ($("#class_mobile_filter_holder form#filter_form").length > 0)) {
12472		$("#class_desktop_filter_holder").append($("#class_mobile_filter_holder form#filter_form"));
12473		$("#class_desktop_filter_holder form#filter_form").show();
12474	}else if ((window_width <= 979) && ($("#class_desktop_filter_holder form#filter_form").length > 0)) {
12475		$("#class_mobile_filter_holder").append($("#class_desktop_filter_holder form#filter_form"));
12476		if ($('a[data-element="filter_form"]').attr('aria-expanded') === 'true') {
12477			$("#class_mobile_filter_holder form#filter_form").show();
12478		}else {
12479			$("#class_mobile_filter_holder form#filter_form").hide();
12480		}
12481	}
12482}
12483
12484// course catalog filter
12485
12486function update_course_catalog_filter(url) {
12487	if ($('#is_calendar_mode').val() == 'true') {
12488		update_calendar(window.current_year, window.current_month, window.current_day);
12489		return;
12490	}
12491
12492	Excalibur.Location_tools.add_load_indicator($('#class_catalog_container'), 100);
12493	$('.clear_filter').show();
12494
12495	$.get(url + generate_course_filter_params(), function(data){
12496		setTimeout(function(){ $('#class_catalog_container').removeClass('extended-load').html(data); }, 200);
12497
12498		$(window).off('loadcomplete.course_rating').on('loadcomplete.course_rating', function () {
12499			jQuery('.ratingStatic').each(function () {
12500				jQuery(this).addRatingStatic(jQuery(this).data().rating);
12501			});
12502		});
12503	});
12504}
12505
12506function init_course_name_filter(url, query) {
12507	$(document).off('keydown', 'input#name_filter');
12508	$(document).on("keydown", "#filter_form", function(event) {
12509		return event.key != "Enter";
12510	});
12511
12512	var input = $('input#name_filter');
12513
12514	input.keyup(function(e) {
12515		typewatch(function() {
12516			var value = input.val().trim();
12517
12518			if (value != '' && value != query) {
12519				query = value;
12520				update_course_catalog_filter(url + '?&phrase=' + encodeURIComponent(value));
12521			} else if (value == '' && value != query) {
12522				query = value;
12523				update_course_catalog_filter(url);
12524			}
12525		}, 1000);
12526	});
12527}
12528
12529function generate_course_filter_params() {
12530	var url = '';
12531	var dropdowns = $('select.course_filter');
12532	var name = $('input#name_filter');
12533
12534	for (var i = 0; i < dropdowns.length; i += 1) {
12535		var dropdown = dropdowns[i];
12536		url += '&' + dropdown.name + '=' + encodeURIComponent(dropdown.value);
12537	}
12538
12539	if (name.val() != '') {
12540		url += '&phrase=' + encodeURIComponent(name.val());
12541	}
12542
12543	if (window.visitor_mode) {
12544		url += '&visitor_mode=true';
12545	}
12546
12547	return url;
12548}
12549
12550// users filter
12551
12552function init_users_filter(id, url, query) {
12553	var input = $('input#' + id);
12554
12555	if (id == 'name_filter') {
12556		var extra_params = '&name_changed=true&email_changed=false&';
12557	}else {
12558		var extra_params = '&name_changed=false&email_changed=true&';
12559	}
12560
12561	input.keyup(function(e) {
12562		typewatch(function() {
12563			var value = input.val().trim();
12564
12565			if (value != '' && value != query) {
12566				update_users_filter(url + extra_params + id + '=' + encodeURIComponent(value));
12567			} else if (value == '' && value != query) {
12568				update_users_filter(url);
12569			}
12570		}, 1000);
12571	});
12572}
12573
12574function update_users_filter(url) {
12575	var checkboxes = $('input[type=checkbox].users_filter');
12576	var dropdowns = $('select.users_filter');
12577	var name = $('input#name_filter');
12578	var email = $('input#email_filter');
12579
12580	for (var i = 0; i < checkboxes.length; i += 1) {
12581		var checkbox = checkboxes[i];
12582
12583		if (checkbox.checked) {
12584			url += '&' + checkbox.name + '=true';
12585		}
12586	}
12587
12588	for (var i = 0; i < dropdowns.length; i += 1) {
12589		var dropdown = dropdowns[i];
12590		url += '&' + dropdown.name + '=' + dropdown.value;
12591	}
12592
12593	if (name.val() != '') {
12594		url += '&name_filter=' + encodeURIComponent(name.val());
12595	}
12596
12597	if (email.val() != '') {
12598		url += '&email_filter=' + encodeURIComponent(email.val());
12599	}
12600
12601	Excalibur.Router.load( url, '#mainContent' );
12602}
12603
12604// reports filter
12605
12606function init_reports_name_filter(url, query) {
12607	$(document).on("keydown", "#filter_form", function(event) {
12608		return event.key != "Enter";
12609	});
12610
12611	var input = $('input#name_filter');
12612
12613	input.keyup(function(e) {
12614		typewatch(function() {
12615			var value = input.val().trim();
12616
12617			if (value != '' && value != query) {
12618				update_reports_catalog_filter(url + '?&phrase=' + encodeURIComponent(value));
12619			} else if (value == '' && value != query) {
12620				update_reports_catalog_filter(url);
12621			}
12622		}, 1000);
12623	});
12624}
12625
12626function update_reports_catalog_filter(url) {
12627	var checkboxes = $('input[type=checkbox].report_filter');
12628	var report_type = $('select#report_type');
12629	var name = $('input#name_filter');
12630
12631	for (var i = 0; i < checkboxes.length; i += 1) {
12632		var checkbox = checkboxes[i];
12633
12634		if (checkbox.checked) {
12635			url += '&' + checkbox.name + '=true';
12636		}
12637	}
12638
12639	if (report_type.length > 0) {
12640		url += '&report_type=' + report_type.val();
12641	}
12642
12643	if (name.val() != '') {
12644		url += '&name_filter=' + encodeURIComponent(name.val());
12645	}
12646
12647	Excalibur.Router.load( url, '#mainContent' );
12648}
12649
12650function clear_filter() {
12651	var filter_url = $(this).attr("filter-url")
12652
12653	Excalibur.Router.load( filter_url, (window.visitor_mode ? '#contentBody' : '#mainContent') );
12654}
12655
12656function show_or_hide_saved_items(item_type, item_id) {
12657	var dropdown = $('#saved_' + item_type + 's_' + item_id);
12658
12659	if (!dropdown.data('visible')) {
12660		$('#' + item_type + '_' + item_id + ' ul').show();
12661		dropdown.data('visible', true);
12662		dropdown.find('i').removeClass('arrowDown').addClass('arrowUp');
12663	}else {
12664		$('#' + item_type + '_' + item_id + ' ul').hide();
12665		dropdown.data('visible', false);
12666		dropdown.find('i').removeClass('arrowUp').addClass('arrowDown');
12667	}
12668}
12669
12670// list widget ajax - list_widget_content('.classes_widget', 'get_classes_list');
12671
12672function list_widget_content(selector, action) {
12673  var data = $(this).data();
12674  var selector = data.selector;
12675  var action = data.controller_action;
12676  var cell_id = data.cell_id;
12677
12678  $(selector + ' .tabnav .tabnav__tab').removeClass('selected');
12679  $(this).addClass('selected');
12680
12681  $('.switch_widget_view').hide();
12682
12683  $.post('/user_dashboard/' + action, {method: data.action, cell_id: cell_id} , function(response) {
12684    $('#' + data.name).html(response);
12685    list_widget_load_carousel(selector);
12686  });
12687}
12688
12689function list_widget_content2(selector, action) {
12690	var data = $(this).data();
12691	var selector = data.selector;
12692	var url = data.url;
12693	var cell_id = data.cell_id;
12694
12695	$(selector + ' .tabnav .tabnav__tab').removeClass('selected');
12696	$(this).addClass('selected');
12697
12698	$('.switch_widget_view').hide();
12699
12700	reset_tabs(selector)
12701	tabnav_adjustment(selector);
12702
12703	if( Excalibur.Mobile.is_mobile_app() && (Excalibur.$view.hasClass('offline-mode') || !navigator.onLine) )
12704		$.get( (url + '.html'), function(response){
12705			$('#' + data.name).html(response);
12706			list_widget_load_carousel(selector);
12707		});
12708	else
12709		$.post(url, {method: data.action, cell_id: cell_id} , function(response) {
12710			$('#' + data.name).html(response);
12711			list_widget_load_carousel(selector);
12712		});
12713}
12714
12715function list_widget_load_carousel(selector) {
12716  if (!$(selector).hasClass('expanded_widget')) {
12717		selector = selector + " .full_width_slider.swiper-container";
12718
12719		if ($(selector).length === 0) {
12720			selector = ".full_width_widget .full_width_slider.swiper-container";
12721		}
12722
12723    create_full_width_carousel(selector);
12724  }
12725}
12726
12727function widget_classes_initiate(method, view) {
12728  $.each($('.switch_widget_view'), function(i, v) {
12729    $(v).data('method', method);
12730  });
12731
12732  if (typeof view !== 'undefined') {
12733    $('.switch_widget_view').hide();
12734
12735    if (view == 'list') {
12736      $('.switch_widget_view.tile_view').css('display', 'block');
12737    } else if (view == 'tile') {
12738      $('.switch_widget_view.list_view').css('display', 'block');
12739    }
12740  }
12741}
12742
12743function widget_classes_paginate_catch() {
12744  var container = $('#ClassListsWidget');
12745
12746  container.find('.search-navigation a').on('click', function(e) {
12747    e.preventDefault();
12748    $.get($(this).attr('href'), {ajax: true}, function(response) {
12749      container.find('.ajaxLoadedContent').html(response);
12750    });
12751  });
12752}
12753
12754function toggle_classes_widget_search(el, method) {
12755  var container = $('#ClassListsWidget');
12756  var input = container.find('input.quick_search');
12757  var search_wrapper = container.find('.optionsRibbonClassesWidget');
12758
12759  if (search_wrapper.is(':visible')) {
12760    search_wrapper.hide();
12761    input.val('');
12762    $.get('/user_dashboard/get_classes_list', {method: method, ajax: true, phrase: ''}, function(response) {
12763      container.find('.ajaxLoadedContent').html(response);
12764    });
12765  } else {
12766    search_wrapper.show();
12767  }
12768}
12769
12770function toggle_classes_widget_search2(el, method) {
12771	var container = $('#ClassListsWidget');
12772	var input = container.find('input.quick_search');
12773	var search_wrapper = container.find('.optionsRibbonClassesWidget');
12774
12775	if (search_wrapper.is(':visible')) {
12776		search_wrapper.hide();
12777		input.val('');
12778		$.get('/class_lists_widget/' + method, {ajax: true, phrase: ''}, function(response) {
12779			container.find('.ajaxLoadedContent').html(response);
12780		});
12781	} else {
12782		search_wrapper.show();
12783	}
12784}
12785
12786function toggle_classes_widget_search2(el, method) {
12787	var container = $('#ClassListsWidget');
12788	var input = container.find('input.quick_search');
12789	var search_wrapper = container.find('.optionsRibbonClassesWidget');
12790
12791	if (search_wrapper.is(':visible')) {
12792		search_wrapper.hide();
12793		input.val('');
12794		$.get('/class_lists_widget/' + method, {ajax: true, phrase: ''}, function(response) {
12795			container.find('.ajaxLoadedContent').html(response);
12796		});
12797	} else {
12798		search_wrapper.show();
12799	}
12800}
12801
12802function widget_classes_search(method) {
12803  var container = $('#ClassListsWidget');
12804  var input = container.find('input.quick_search');
12805
12806  input.keyup(function(e) {
12807    typewatch(function() {
12808      $.get('/user_dashboard/get_classes_list', {method: method, ajax: true, phrase: input.val()}, function(response) {
12809        container.find('.ajaxLoadedContent').html(response);
12810      });
12811    }, 1000);
12812  });
12813}
12814
12815function widget_classes_search2(method) {
12816	var container = $('#ClassListsWidget');
12817	var input = container.find('input.quick_search');
12818
12819	input.keyup(function(e) {
12820		typewatch(function() {
12821			$.get('/class_lists_widget/' + method, {ajax: true, phrase: input.val()}, function(response) {
12822				container.find('.ajaxLoadedContent').html(response);
12823			});
12824		}, 1000);
12825	});
12826}
12827
12828function widget_classes_search2(method) {
12829	var container = $('#ClassListsWidget');
12830	var input = container.find('input.quick_search');
12831
12832	input.keyup(function(e) {
12833		typewatch(function() {
12834			$.get('/class_lists_widget/' + method, {ajax: true, phrase: input.val()}, function(response) {
12835				container.find('.ajaxLoadedContent').html(response);
12836			});
12837		}, 1000);
12838	});
12839}
12840
12841function widget_users_paginate_catch() {
12842	var container = $('#UserListsWidget');
12843
12844	container.find('.search-navigation a').on('click', function(e) {
12845		e.preventDefault();
12846		$.get($(this).attr('href'), {ajax: true}, function(response) {
12847			container.find('.ajaxLoadedContent').html(response);
12848		});
12849	});
12850}
12851
12852function toggle_users_widget_search(el, method) {
12853	var container = $('#UserListsWidget');
12854	var input = container.find('input.quick_search');
12855	var search_wrapper = container.find('.optionsRibbonUsersWidget');
12856
12857	if (search_wrapper.is(':visible')) {
12858		search_wrapper.hide();
12859		input.val('');
12860		$.get('/user_lists_widget/' + method, {ajax: true, phrase: ''}, function(response) {
12861			container.find('.ajaxLoadedContent').html(response);
12862		});
12863	} else {
12864		search_wrapper.show();
12865	}
12866}
12867
12868function widget_users_search(method) {
12869	var container = $('#UserListsWidget');
12870	var input = container.find('input.quick_search');
12871
12872	input.keyup(function(e) {
12873		typewatch(function() {
12874			$.get('/user_lists_widget/' + method, {ajax: true, phrase: input.val()}, function(response) {
12875				container.find('.ajaxLoadedContent').html(response);
12876			});
12877		}, 1000);
12878	});
12879}
12880
12881function switch_widget_view() {
12882  var data = $(this).data();
12883  $.post('/user_dashboard/change_classes_widget_view', {view: data.view}, function(response) {
12884    $.get('/user_dashboard/get_classes_list', {method: data.method, cell_id: data.cell_id}, function(response) {
12885      $('#ClassListsWidget').html(response);
12886    });
12887  });
12888}
12889
12890function switch_widget_view2() {
12891	var data = $(this).data();
12892	$.post('/class_lists_widget/toggle_view', {view: data.view}, function(response) {
12893		$.get('/class_lists_widget/' + data.method, {cell_id: data.cell_id}, function(response) {
12894			$('#ClassListsWidget').html(response);
12895		});
12896	});
12897}
12898
12899// transfer students
12900
12901function transfer(element) {
12902  var selected = $('input[name="select[]"]:checked');
12903  var select_all = $('input[name="select_all"]').val() == "true";
12904
12905  if (selected.length == 0) {
12906    $.alert({content: "No items were selected."});
12907  } else {
12908    var url = $(element).attr('href') + "?";
12909    var selected_array = [];
12910
12911    if (select_all) {
12912      url = url + 'select_all=true&';
12913    }
12914
12915    $.each(selected, function(i, v) {
12916      selected_array.push("select[]=" + $(v).attr('id'));
12917    });
12918
12919    url = url + selected_array.join('&');
12920
12921    $.facebox({'ajax' : url});
12922  }
12923}
12924
12925function remove_slide_filter() {
12926  var data = $(this).data();
12927
12928  // container
12929  var slide_title_element = $('.slide-' + data.id + ' a.slide_title');
12930  var container_type = slide_title_element.data('container_type');
12931  var container_id = slide_title_element.data('id');
12932
12933  var panel = $('.section_carousel_panel_' + data.id);
12934
12935  $.post('/banner_slide/remove_slide_filter/' + container_id, {slide_id: data.id, container_type: container_type}, function(response) {
12936    if (response.status == 'ok') {
12937      var manager = window.conditionalFilterManager;
12938
12939      panel.find('.add_filter').show();
12940      panel.find('.has_filter').hide();
12941      panel.find('.has_filter .filter_conditions').text('');
12942
12943      // the slide has an add and an edit trigger, each with its own registration holding the deleted filter id
12944      if (manager) {
12945        manager.filterIds().forEach(function(id) {
12946          if (panel.find('#' + id).length) {
12947            var options = manager.filterOptions(id);
12948            options.filter_id = null;
12949            manager.setFilterOptions(id, options);
12950          }
12951        });
12952      }
12953    } else {
12954      console.log(response.message);
12955    }
12956  });
12957}
12958
12959function set_logged_out_cookie() {
12960  sessionStorage.setItem("logged_out_session", "true");
12961}
12962
12963function login_as_stealth_mode(element) {
12964  var form = $(element).parents('form#user_log_in');
12965  form.find('input[name=update_history]').remove();
12966  form.submit();
12967}
12968
12969function toggle_mobile_app_use_overwritten(checkbox, id) {
12970	$.post('/branded_mobile_app_support/set_use_overwritten_fields/' + id, {value: checkbox.checked});
12971}
12972
12973// onboarding schools
12974
12975function onboard_wizard(id, next) {
12976  if ($('#facebox_overlay').length == 0) {
12977    $('body').append('<div id="facebox_overlay" class="facebox_overlayBG"></div>');
12978  }
12979
12980  if ($('#fullscreen_msg_holder').length > 0) {
12981    $('#fullscreen_msg_holder').remove();
12982  }
12983
12984  $('.facebox_overlayBG').css('opacity','0.4');
12985  $('body').addClass('no-scroll blur_site');
12986  $('body').append('<div id="fullscreen_msg_holder" class="fullscreen_progress"><div id="fullscreen_msg" role="dialog" tabindex="-1"></div></div>');
12987
12988  let now = new Date();
12989  let time = now.getFullYear() + '-' + (now.getMonth() + 1) + '-' + now.getDate() + ' ' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();
12990
12991  $.get("/school/onboard/" + id, {time: time}, function(data) {
12992    $('#fullscreen_msg').html(data).focus();
12993
12994    if (next) {
12995      // language was selected
12996      $('#onboarding_save_language').trigger('click');
12997    }
12998
12999    $(".get_started_wizard input[name=language]").change(function() {
13000      if (onboarding_language_id == parseInt($(this).val())) {
13001        $.each(onboarding_active_buttons, function(i,v) {
13002          if (v != 'panel1') {
13003            $("button#" + v).removeAttr('disabled');
13004          }
13005        });
13006
13007        $.each(onboarding_completed_buttons, function(i,v) {
13008          if (v != 'panel1') {
13009            $("button#" + v).addClass('completed');
13010          }
13011        });
13012      } else {
13013        $.each(onboarding_active_buttons, function(i,v) {
13014          if (v != 'panel1') {
13015            $("button#" + v).attr('disabled', true);
13016          }
13017        });
13018
13019        $.each(onboarding_completed_buttons, function(i,v) {
13020          if (v != 'panel1') {
13021            $("button#" + v).removeClass('completed');
13022          }
13023        });
13024      }
13025    })
13026
13027    $(".get_started_wizard input[name=theme]").change(function() {
13028      $.get('/school/get_stylesheet/' + id, {name: $(this).val()}, function(response) {
13029        $("<link/>", {rel: "stylesheet", type: "text/css", href: response.url}).appendTo("head");
13030      })
13031    })
13032
13033    $('.get_started_wizard .single_file_upload_button').click(function() {
13034      var interval = setInterval(function() {
13035        if ($('.get_started_wizard .uploader-list input[type=\'hidden\']').length > 0) {
13036          var next_button = $('.get_started_wizard .wizard_content').find('button[panel-id="panel6"][data-next_tab="finish"]');
13037          next_button.html(next_button.data('next_text'));
13038          clearInterval(interval);
13039        }
13040      }, 1500);
13041    })
13042  });
13043}
13044
13045function onboarding_save_language() {
13046  var data = $(this).data();
13047  var current_language = data.current_language;
13048  var selected_language = $(this).parents('form').find('input[name=language]:checked').val();
13049
13050  if (current_language == selected_language) {
13051    wizard_nav_click(this);
13052  } else {
13053    let now = new Date();
13054    let time = now.getFullYear() + '-' + (now.getMonth() + 1) + '-' + now.getDate() + ' ' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();
13055
13056    $.post('/select_language/submit_language', {language: selected_language, time: time, aja
13056x: true}, function(response) {
13057      onboard_wizard(response.school_id, true);
13058    });
13059  }
13060}
13061
13062function onboarding_yourself_data() {
13063  onboarding_wizzard_data.school.country = $("#school_country").val();
13064  onboarding_wizzard_data.school.time_zone = $("#school_time_zone").val();
13065
13066  if ($("#school_state").is(':visible')) {
13067    onboarding_wizzard_data.school.state = $("#school_state").val();
13068  }
13069
13070  if ($("#school_other_state").is(':visible')) {
13071    onboarding_wizzard_data.school.state = $("#school_other_state").val();
13072  }
13073
13074  onboarding_wizzard_data.marketing.role = $("#role_name").val();
13075
13076  if ($("#role_detail").is(':visible')) {
13077    onboarding_wizzard_data.marketing.role_detail = $("#role_detail").val();
13078  }
13079
13080  onboarding_wizzard_data.marketing.channel = $("#marketing_channel").val();
13081  onboarding_wizzard_data.marketing.channel_details = $("#marketing_channel_detail").val();
13082}
13083
13084function onboarding_organization_data() {
13085  onboarding_wizzard_data.marketing.industry = $("#organization_industry").val();
13086  onboarding_wizzard_data.marketing.audience = $("#organization_audience").val();
13087  onboarding_wizzard_data.marketing.plan = $("#organization_plans").val();
13088  onboarding_wizzard_data.marketing.training = $("#marketing_training").val();
13089  onboarding_wizzard_data.marketing.training_detail = $("#marketing_training_detail").val();
13090}
13091
13092function onboarding_theme_data() {
13093	if($(document.body).hasClass('evo')) {
13094		onboarding_wizzard_data.selected_evo_theme_colors = window.selected_evo_theme_colors;
13095	}else {
13096		onboarding_wizzard_data.theme = $("[name=theme]:checked").val();
13097	}
13098}
13099
13100function onboarding_logo_data() {
13101  if ($(".get_started_wizard #UploaderWrapper input#photo").length > 0) {
13102    onboarding_wizzard_data.logo = $(".get_started_wizard #UploaderWrapper input#photo").val();
13103  } else {
13104    onboarding_wizzard_data.logo = null;
13105  }
13106}
13107
13108// validate
13109
13110function onboarding_validate() {
13111  if (onboarding_tab == 'yourself' && ($("#role_name").val() == '' || $("#marketing_channel").val() == '' || $("#school_country").val() == '' || ($("#school_state").val() == '' && $("#school_other_state").val() == '') || $("#school_time_zone").val() == '')) {
13112    return false;
13113  }
13114
13115  if (onboarding_tab == 'organization' && ($("#organization_industry").val() == "" || $("#organization_audience").val() == '' || $("#marketing_training").val() == '' || $("#organization_plans").val() == '')) {
13116    return false;
13117  }
13118
13119  return true;
13120}
13121
13122function update_data() {
13123  switch(onboarding_tab) {
13124    case 'yourself':
13125      onboarding_yourself_data();
13126      break;
13127    case 'organization':
13128      onboarding_organization_data();
13129      break;
13130    case 'theme':
13131      onboarding_theme_data();
13132      break;
13133    case 'logo':
13134      onboarding_logo_data();
13135      break;
13136  }
13137}
13138
13139function wizard_nav_click(element) {
13140  var data = $(this).data();
13141
13142  if (data.direction != 'previous') {
13143    if (!onboarding_validate()) {
13144
13145      $.alert({content: "Please complete all the mandatory fields"});
13146      return false;
13147    }
13148  }
13149
13150  update_data();
13151
13152  var element = element || this;
13153  var new_panel_id =  element.attr('panel-id');
13154  var wizard_nav_item = $('#' + new_panel_id);
13155  var wizard_panel = element.closest('.wizard_wrapper');
13156
13157  wizard_nav_item.siblings().removeClass('selected').attr("aria-selected","false");
13158  wizard_nav_item.prev().addClass('completed');
13159  wizard_nav_item.addClass('selected').attr("aria-selected","true").prop("disabled", false);
13160
13161  wizard_panel.find('.wizard_content[aria-hidden="false"]').attr("aria-hidden","true");
13162  wizard_panel.find('.wizard_content[aria-labelledby="' + new_panel_id + '"]').attr('aria-labelledby',new_panel_id).attr("aria-hidden","false");
13163
13164  onboarding_tab = $(element).data('next_tab');
13165
13166  onboarding_active_buttons = [];
13167  $.each($('.wizard_nav button'), function(i,v) {
13168    if(!$(this).is(':disabled')) {
13169      onboarding_active_buttons.push($(this).attr('id'));
13170    }
13171  });
13172
13173  onboarding_completed_buttons = [];
13174  $.each($('.wizard_nav button.completed'), function(i,v) {
13175    onboarding_completed_buttons.push($(this).attr('id'));
13176  });
13177}
13178
13179function change_marketing_channel(value) {
13180  $('.marketing_channel_detail_cell, .marketing_channel_detail_cell span').hide();
13181
13182  if ($('.marketing_channel_detail_cell span[data-value="' + value + '"]').length) {
13183    $('.marketing_channel_detail_cell, .marketing_channel_detail_cell span[data-value="' + value + '"]').show();
13184  }
13185}
13186
13187function select_single_wizard_item(element, value) {
13188  if ($(element + ' span[data-value="' + value + '"]').length) {
13189    $(element).show();
13190  } else {
13191    $(element).hide();
13192  }
13193}
13194
13195function wizard_complete(id) {
13196  var data = $(this).data();
13197
13198  $.post('/school/onboard_save/' + data.school_id, onboarding_wizzard_data, function(response) {
13199    if (response.status == 'ok') {
13200      location.reload();
13201    } else {
13202      $.alert({content: response.error});
13203    }
13204  });
13205}
13206
13207function stackedSinglePickerCallback(input, selector, url) {
13208  var value = $(input).val();
13209  var name = $('.facebox-content ' + selector);
13210
13211  // fix for the hidden editor on facebox stack comeback
13212  $('#facebox .mce-tinymce').show();
13213
13214  if (window.pickerSelectedId && typeof(window.pickerSelectedId) != 'undefined' && window.pickerSelectedId != value) {
13215    $(input).val(window.pickerSelectedId);
13216    $(".facebox-content .single_file_upload_button").html("<i class=\"edit\"></i>" + change_text);
13217    name.attr('style','float:left;padding:0;margin:6px 16px 0 0');
13218
13219    if (name.find('a').length == 0) {
13220      name.append("<a href=\"" + url + "/" + window.pickerSelectedId + "\">" + window.pickerSelectedName + "</a>");
13221    } else {
13222      name.find('a').attr('href', url + "/" + window.pickerSelectedId);
13223      name.find('a').text(window.pickerSelectedName);
13224    }
13225
13226    window.pickerSelectedId = null;
13227    window.pickerSelectedName = null;
13228  }
13229}
13230
13231function stackedClassSectionPickerCallback(class_id, class_name, selector, url) {
13232  var class_id = $(class_id);
13233  var name = $('.facebox-content ' + selector);
13234
13235  if (window.pickerSelectedId && typeof(window.pickerSelectedId) != 'undefined' && window.pickerSelectedId != class_id.val()) {
13236    class_id.val(window.pickerSelectedId);
13237    $(class_name).val(window.pickerSelectedName);
13238    $(".facebox-content .single_file_upload_button").html("<i class=\"edit\"></i>" + change_text);
13239    name.attr('style','float:left;padding:0;margin:6px 16px 0 0');
13240
13241    if (name.find('a').length == 0) {
13242      name.append("<a href=\"" + url + "/" + window.pickerSelectedId + "\">" + window.pickerSelectedName + "</a>");
13243    } else {
13244      name.find('a').attr('href', url + "/" + window.pickerSelectedId);
13245      name.find('a').text(window.pickerSelectedName);
13246    }
13247
13248    window.pickerSelectedId = null;
13249    window.pickerSelectedName = null;
13250  }
13251
13252  // fix for the hidden editor on facebox stack comeback
13253  $('#facebox .mce-tinymce').show();
13254}
13255
13256// network admin login
13257
13258function login_to_site(school_id, extra_params) {
13259	if (school_id) {
13260		var url = '/network/visit?school_id=' + school_id.toString();
13261
13262		if (extra_params) {
13263			url += extra_params;
13264		}
13265
13266		window.location.href = url;
13267	} else{
13268		show_error('Invalid site was selected.');
13269	}
13270}
13271
13272// init panopto login
13273
13274function init_panopto_login(data) {
13275	execute_panopto_login(data);
13276
13277	$(window).on('loadcomplete', function () {
13278		execute_panopto_login(data);
13279	})
13280}
13281
13282function execute_panopto_login(data) {
13283  const panopto_videos = $('.panoptoVideo');
13284  const json = JSON.parse(atob(data.replace(/_/g, '/').replace(/-/g, '+')));
13285
13286  if (panopto_videos.length > 0 || json.silent_login) {
13287    $('#panoptoLoginElement').remove();
13288
13289    const loginElement = document.createElement('div');
13290    loginElement.id = 'panoptoLoginElement';
13291    loginElement.style.display = 'none';
13292
13293    const iframe = document.createElement('iframe');
13294    iframe.id = 'panoptoLoginIframe';
13295    iframe.name = 'panoptoLoginIframe';
13296    loginElement.appendChild(iframe);
13297
13298    const form = document.createElement('form');
13299    form.id = 'panoptoLoginForm';
13300    form.name = 'panoptoLoginForm';
13301    form.action = json.launch_url;
13302    form.method = 'post';
13303    form.enctype = 'application/x-www-form-urlencoded';
13304    form.target = 'panoptoLoginIframe';
13305
13306    Object.entries(json.launch_data).forEach(([key, value]) => {
13307      const input = document.createElement('input');
13308      input.type = 'hidden';
13309      input.name = key;
13310      input.value = value;
13311      form.appendChild(input);
13312    });
13313
13314    loginElement.appendChild(form);
13315    document.body.appendChild(loginElement);
13316
13317    if (!json.silent_login) {
13318      // Load videos after the launch iframe loads
13319      iframe.addEventListener('load', function() {
13320        panopto_videos.each(function(_idx, video) {
13321          video.src = video.dataset.src;
13322        });
13323      });
13324    }
13325
13326    // Submit the form
13327    form.submit();
13328  }
13329}
13330
13331function lesson_period_date_changed(year, month, day) {
13332	period_date_changed(year, month, day, "lesson_period_number_select" )
13333}
13334
13335function class_session_period_date_changed(year, month, day) {
13336	period_date_changed(year, month, day, "class_session_period_number_select" )
13337}
13338
13339function period_date_changed(year, month, day, period_select_class_name) {
13340	let period_options = $("." + period_select_class_name + " > option")
13341
13342	// enable all options
13343	period_options.each(function() {
13344		$(this).removeAttr("disabled");
13345	});
13346
13347	if(year !== '') {
13348		let new_date = new Date(year, month-1, day);
13349
13350		let disabled_options = disabled_periods_for_wday[new_date.getDay()];
13351		if(disabled_options.length > 0){
13352			let first_available = true;
13353			$("." + period_select_class_name).val('');
13354
13355			period_options.each(function() {
13356				let value = $(this).val();
13357				if(value !== ''){
13358					if(disabled_options.includes(parseInt(value))){ // disable any option which is disabled for this date
13359						$(this).attr("disabled", "disabled");
13360					} else if(first_available){ // select the first option which is not disabled
13361						$("." + period_select_class_name).val(value);
13362						first_available = false;
13363					}
13364				}
13365			});
13366		}
13367	}
13368}
13369
13370// proficiency edit
13371
13372function proficiency_tag_edit() {
13373  $('.proficiency_edit').hide();
13374  $('.proficiency_edit_cancel').show();
13375  $('.add_more_proficiency_tag_').show();
13376  $('span[class*=proficiency_tag_] a').css('display', 'inline');
13377}
13378
13379function proficiency_tag_edit_cancel() {
13380  $('.proficiency_edit').show();
13381  $('.proficiency_edit_cancel').hide();
13382  $('.add_more_proficiency_tag_').hide();
13383  $('span[class*=proficiency_tag_] a').hide();
13384}
13385
13386function proficiency_tag_remove(element) {
13387  $.confirm({
13388    content: 'Are you sure you want to delete the proficiency?',
13389    confirm: function() {
13390      let el = $(element);
13391      let elements_count = $('span[class^=proficiency_tag_]').length;
13392
13393      $.post(el.attr('href'), function(response) {
13394        el.parent('span').remove();
13395
13396        if (elements_count == 1) {
13397          $('.add_more_proficiency_tag_').hide();
13398          $('.proficiency_edit_cancel').hide();
13399          $('.proficiency_add').show();
13400        }
13401      });
13402    }
13403  });
13404}
13405
13406
13407// security roles
13408
13409function show_permission_model_columns(link, model_name) {
13410	if($(link).attr('aria-expanded') === 'true'){
13411		$(link).attr('aria-expanded', 'false');
13412		$(link).find('i').attr('class', 'arrowRight');
13413		$('#permissions_' + model_name).hide();
13414	}else {
13415		$(link).attr('aria-expanded', 'true');
13416		$(link).find('i').attr('class', 'arrowDown');
13417		$('#permissions_' + model_name).show();
13418	}
13419}
13420
13421function display_filter_form_data(dropdown) {
13422	$.get('/restricted_roles/get_filter?filter_type=' + dropdown.value, function (html) {
13423		$('#restricted_role_filter').html(html);
13424	})
13425}
13426// Adblocker detection
13427
13428function show_adblocker_warning(title, content) {
13429	if(typeof(PageAnalytics) === 'undefined') {
13430		$.alert({title: title, content: content});
13431	}
13432}
13433
13434//bug_filters
13435function add_bug_filter(operation) {
13436	prompt = "Add filter for " + operation;
13437	$.confirm({
13438		content: prompt,
13439		confirm: function() {
13440			url = '/bugs/submit_filter?filter=' + operation;
13441			$.get(url, function(response) {});
13442			location.reload(true);
13443		},
13444		cancel: function() {
13445		}
13446	});
13447}
13448
13449// recommendations ajax
13450
13451function load_recommendation_action_via_ajax(el) {
13452  let location = $(el).attr('href');
13453  let action_type = (location.includes('dismiss') ? 'dismiss' : 'restore');
13454  let selected_tab = $('.recommendations_widget .tabnav a.selected');
13455  let not_selected_tab = $('.recommendations_widget .tabnav a:not(.selected)');
13456
13457  $.confirm({
13458    confirm: function() {
13459      $.get(location, function(response) {
13460        let method = selected_tab.data('action');
13461        let selected_count = parseInt(selected_tab.find('span').text());
13462        let not_selected_count = parseInt(not_selected_tab.find('span').text());
13463
13464        if (action_type == 'restore' && not_selected_count == 1) {
13465          selected_tab.removeClass('selected');
13466          not_selected_tab.addClass('selected');
13467          not_selected_tab.addClass('hide');
13468          method = not_selected_tab.data('action');
13469          selected_tab.hide();
13470        } else if (action_type == 'dismiss' && not_selected_count == 0) {
13471          not_selected_tab.show();
13472        }
13473
13474        // update counters
13475        selected_tab.find('span').text(selected_count - 1);
13476        not_selected_tab.find('span').text(not_selected_count + 1);
13477
13478        // update content
13479        widget_load_content_via_ajax('recommendations_widget_content', recommendations_class_name, recommendations_load_content_method, {cell_id: recommendations_cell_id, method: method});
13480      });
13481    }
13482  });
13483}
13484
13485// scale questions
13486
13487function set_scale_type(type) {
13488  let labels = $("div.labels");
13489
13490  if (type == 'star') {
13491    labels.hide();
13492    labels.find('input').val('');
13493  } else {
13494    labels.show();
13495  }
13496}
13497
13498// matrix questions
13499
13500function set_matrix_options(type, limit) {
13501  let number = $("#question_" + type + "s").val();
13502
13503  for (let i = 1; i <= limit; i++) {
13504    let element = $('p.matrix_' + type + '_label_' + i);
13505
13506    if (i <= number) {
13507      element.show();
13508    } else {
13509      element.hide();
13510      element.find('input').val('');
13511    }
13512  }
13513}
13514
13515// unlock next lesson when lesson/section completed
13516
13517function unlock_next_lesson_poll(class_id, lesson_id, student_id) {
13518	var url = '/student_lesson/check_lesson_status?id=' + class_id + '&lesson_id=' + lesson_id + '&student_id=' + student_id;
13519	var unlock_next_lesson_poll_interval = setInterval(function () {
13520		$.get(url, function (response) {
13521			if (response.completed) {
13522				$.each($('[id="dynamic_button"]'), function (key, button) {
13523					var next_url = $(button).data('next_url');
13524					var next_text = $(button).data('next_text');
13525					$(button).removeClass('locked').attr('href', next_url);
13526					$(button).text(next_text);
13527					$(button).find('i').replaceWith('<img src="/images/icons/large-arrow-white.svg" alt="" />');
13528				});
13529
13530				clearInterval(unlock_next_lesson_poll_interval);
13531			}
13532		});
13533	}, 30000);
13534
13535	$(window).on('beforexload', function () {
13536		clearInterval(unlock_next_lesson_poll_interval);
13537	});
13538}
13539
13540// close SCORM iframe
13541
13542function cors_close_scorm_embed(redirect_to) {
13543	if ((typeof redirect_to !== 'undefined') && (redirect_to !== '')) {
13544		window.addEventListener("message", function(event) {
13545			var data = JSON.parse(event.data);
13546
13547			if(/scorm_lms_finish_ended/.test(event.data)){
13548				if (typeof data.scorm_lms_finish_ended != 'undefined') {
13549					document.location = redirect_to;
13550				}
13551			}
13552		});
13553	}
13554
13555	var scorm_iframe = document.getElementById('scorm_iframe');
13556
13557	if (scorm_iframe) {
13558		scorm_iframe.contentWindow.postMessage('{"cors_close_scorm_embed": true}', '*');
13559	}
13560}
13561
13562function init_scorm_page_listener() {
13563	$(window).off('beforexload.scorm').on('beforexload.scorm', function () {
13564		cors_close_scorm_embed('');
13565		$(window).off('beforexload.scorm');
13566	});
13567}
13568
13569// session change
13570
13571function session_change_update() {
13572  $('input[type=radio][id^=children_]').on('change', function() {
13573    let element = $('.module_course_header .modern_module_row a.modern_module_wrap');
13574    let url = element.attr('href');
13575    let match = url.match(/class_id=[0-9]+&/g);
13576    element.attr('href', url.replace(match, 'class_id=' + $(this).val() + '&'));
13577  });
13578}
13579
13580// recommendations
13581
13582function dismiss_recommendation(event, id, goal_id, recommendation_id) {
13583  event.stopPropagation();
13584
13585  $.confirm({
13586    confirm: function() {
13587      $.post('/learning_goal/dismiss_recommendation/' + goal_id, {recommendation_id: recommendation_id}, function(response) {
13588        let count = $('.skills_widget .headingLinkWrap').find('a[data-action="get_recommendations"] span');
13589        count.text(parseInt(count.text()) - 1);
13590        $('#' + id).remove();
13591      })
13592    }
13593  })
13594}
13595
13596// resource catalog inifinte scroll
13597
13598var resources_scroll_stop = false;
13599var resource_scroll_options;
13600var resource_ajax_view;
13601var resource_ajax_wrapper;
13602
13603function scroll_for_more_resources() {
13604  $(window).scroll(function () {
13605    if ($('#centreColumn .leftColumn.resources_catalog').length != 0 && !resources_scroll_stop && resource_scroll_options != false) {
13606      if ($(window).scrollTop() >= $(document).height() - $(window).height() - 50) {
13607        resources_scroll_stop = true;
13608
13609        let data = clean_args_for_null(JSON.parse(resource_scroll_options));
13610        data.ajax_request = true;
13611        data.partial_view = resource_ajax_view;
13612
13613        $.post('/library', data, function(html) {
13614          $(resource_ajax_wrapper).find('script').remove();
13615          $(resource_ajax_wrapper).find('.resource_catalog_loader').remove();
13616          $(resource_ajax_wrapper).append(html);
13617          resources_scroll_stop = false;
13618        });
13619      }
13620    }
13621  });
13622}
13623
13624function resources_go_to_details(url) {
13625  window.location = url;
13626}
13627
13628function clean_args_for_null(args) {
13629  for (var attribute in args) {
13630    if (args[attribute] === null || args[attribute] === undefined) {
13631      delete args[attribute];
13632    }
13633  }
13634  return args;
13635}
13636
13637function search_simple_filter() {
13638  var url = window.location.pathname;
13639
13640  $('#filter').keyup(function(e) {
13641    typewatch(function() {
13642			var payload = {ajax_request: true};
13643      var value = $("#filter").val().trim();
13644
13645      if (!(value === undefined) && !(value == "")) {
13646          payload["filter"] = value;
13647      }
13648
13649      $.get(url, payload, function(html) {
13650        $('#SearchResultsWrapper').html(html);
13651        to_load();
13652      });
13653    }, 1000);
13654  });
13655}
13656
13657function init_simple_ordering() {
13658	var elements = document.getElementById('SearchResultsWrapper').querySelectorAll('a.sort-by, a.asc, a.desc, a.no-loader');
13659
13660	elements.forEach( (element) => {
13661		element.classList.add('bypass-ajax');
13662
13663		element.addEventListener("click", function (e) {
13664			e.preventDefault();
13665
13666			$.get(element.href, {ajax_request: true}, function(html) {
13667				$('#SearchResultsWrapper').html(html);
13668				to_load();
13669			});
13670
13671		}, true);
13672	});
13673}
13674
13675function set_days_before_adding_attendance(dropdown, class_id) {
13676  ajax_request('/teacher_attendance/set_days_before_adding_attendance/' + class_id + '?value=' + encodeURIComponent(dropdown.value));
13677}
13678
13679
13680function disable_and_submit_form_on_click() {
13681	this.form().submit();
13682	this.prop('disabled', true);
13683}
13684
13685function confirm_grade_release_change(el, initial_value, create) {
13686  var elem = $(el);
13687
13688  if (create == true) {
13689    setTimeout(function() {elem.prop('checked', true);}, 200);
13690  } else if (initial_value == 'Manual' && elem.val() == 'Instant') {
13691    $.confirm({
13692      content: "Changing this option will release all your given grades on save!",
13693      confirm: function() {
13694        console.log($(el))
13695        elem.prop('checked', true);
13696      }
13697    });
13698  } else {
13699    setTimeout(function() {elem.prop('checked', true);}, 200);
13700  }
13701}
13702
13703// configure class
13704
13705function set_bug_filter(bug_history_id, checkbox) {
13706	ajax_request('/bugs/set_filter/' + bug_history_id + '?value=' + (checkbox.checked ? 'true' : 'false'));
13707}
13708
13709/**
13710 * Check for empty string including spaces and new lines also strip out html <p> tag
13711 * @param string (text or html)
13712 * @return {boolean} true if string is empty
13713 */
13714function isStringEmpty(string) {
13715	var string_has_html =  string.split('').map(c =>c.trim()).join('');
13716	var string_text_remove_p = string_has_html.replace('<p>','').replace('</p>','');
13717	return (string_text_remove_p == '')? true : false;
13718}
13719
13720
13721// copilot
13722
13723function add_competencies_in_place() {
13724    let wrapper = $('.selected_competencies');
13725
13726    $.each(window.copilotSelectedCompetencies, function(i, v) {
13727        let id = v[0].split(',')[0];
13728        let id_type = v[0];
13729        let title = v[1];
13730
13731        if ($('.copilot_competency_' + id).length == 0) {
13732            $.get('/curriculum/get_proficiencies/' + id, function(html) {
13733                wrapper.append('<div class="copilot_competency_' + id + '"><div><span>' + title + '</span> <a href="javascript:void(0)" class="delete_competency" onclick="delete_selected_competency(' + id + ')"><i class="blockCircle"></i></a></div><input type="hidden" name="options[competencies][ids][]" value="' + id_type + '"><br></div>');
13734                wrapper.append('<div class="copilot_proficiencies_' + id + '">' + html + '</div>');
13735            })
13736        }
13737    });
13738
13739    $("button[excalibur-click=\"Excalibur.Ai.start_confirm\"]").prop("disabled", false)
13740}
13741
13742function delete_selected_competency(id) {
13743    $('.copilot_proficiencies_' + id).remove();
13744    $('.copilot_competency_' + id).remove();
13745}
13746
13747function copilot_get_voices(show) {
13748    if (show) {
13749        $('.copilot_voices').show();
13750        $('.copilot_voices_autoplay').show();
13751        copilot_show_voices(false);
13752    } else {
13753        $('.copilot_voices').empty().hide();
13754        $('.copilot_voices_autoplay').hide();
13755    }
13756}
13757
13758function copilot_show_voices(selected_voice) {
13759    $.get('/copilot_voices', function(response) {
13760        if (response.status == 'ok') {
13761            $.each(response.voices, function(i, e) {
13762                var selected = selected_voice ? (selected_voice == e.id) : (i == 0);
13763                var html = '<div class="voice ' + e.id + '">';
13764                html += '<input' + (selected ? ' checked="checked"' : '') + ' id="options_copilot_voice_' + e.id + '" name="options[copilot_voice]" type="radio" value="' + e.id + '">';
13765                html += '<label for="options_copilot_voice_' + e.id + '">'  + e.name + '&nbsp;&nbsp;&nbsp;';
13766                html += '<audio id="' + e.id + '" src="' + e.preview + '"></audio>';
13767                html += '<a href="javascript:void(0)" class="play_voice" onclick="document.getElementById(\'' + e.id + '\').play()"><i class="audioPlay"></i></a>';
13768                html += '<a href="javascript:void(0)" class="stop_voice" onclick="document.getElementById(\'' + e.id + '\').load()" style="display: none"><i class="audioStop"></i></a>';
13769                html += '<br><span>' + e.description + '</span>';
13770                html += '</label>';
13771
13772                $('.copilot_voices').append(html);
13773
13774                voice_player(e.id);
13775            });
13776        }
13777    });
13778}
13779
13780function voice_player(id) {
13781    var wrapper = $('.' + id);
13782    var audio = wrapper.find('audio');
13783
13784    audio[0].muted = false;
13785
13786    audio.on('ended loadstart', (event) => {
13787        wrapper.find('.play_voice').show();
13788        wrapper.find('.pause_voice').hide();
13789        wrapper.find('.stop_voice').hide();
13790    });
13791
13792    audio.on('play', (event) => {
13793        wrapper.find('.play_voice').hide();
13794        wrapper.find('.pause_voice').show();
13795        wrapper.find('.stop_voice').show();
13796    });
13797
13798		audio.on('pause', (event) => {
13799			wrapper.find('.play_voice').show();
13800			wrapper.find('.pause_voice').hide();
13801		});
13802}
13803
13804function voice_autoplay(id) {
13805    setTimeout(function() {
13806        var element = document.getElementById(id);
13807        element.muted = false;
13808        element.play();
13809    }, 2000);
13810}
13811
13812function crosscheck_apply_changes(controller, id, lesson_id, section_id) {
13813    $.confirm({
13814        content: 'Warning: Are you sure you want to replace the content of the section?',
13815        confirm: function() {
13816            $.post('/' + controller + '/apply_crosscheck/' + id, {lesson_id: lesson_id, section_id: section_id}, function(response) {
13817                window.location.reload();
13818            });
13819        }
13820    });
13821}
13822
13823function crosscheck_dismiss_changes(controller, id, lesson_id, section_id) {
13824    $.confirm({
13825        content: 'Warning: If you dismiss the changes they are gone for good?',
13826        confirm: function() {
13827            $.post('/' + controller + '/dismiss_crosscheck/' + id, {lesson_id: lesson_id, section_id: section_id}, function(response) {
13828                window.location.reload();
13829            });
13830        }
13831    });
13832}
13833
13834function crosscheck_dismiss_checked(controller, id, lesson_id, section_id) {
13835    $.post('/' + controller + '/dismiss_checked_message/' + id, {lesson_id: lesson_id, section_id: section_id});
13836}
13837
13838function configure_copilot(attribute, checkbox, from) {
13839	window.location.href = '/copilot_admin/set_attribute?attribute=' + attribute + '&value=' + (checkbox.checked ? 'true' : 'false') + '&from=' + from;
13840}
13841
13842function insert_strong_password_regex(element) {
13843	$('#password_regex').val($(element).text());
13844	$('#password_regex_description').val($(element).attr('title'));
13845}
13846
13847function password_strength_changed(element) {
13848	switch ($(element).val()) {
13849		case 'custom':
13850			$('#custom_password_regex').show();
13851			break;
13852
13853		case 'weak':
13854			$('#custom_password_regex').hide();
13855			break;
13856
13857		case 'strong_1':
13858		case 'strong_2':
13859		case 'strong_3':
13860		default:
13861			$('#custom_password_regex').hide();
13862			$('#password_regex').val($(element).data('password_regex'));
13863			$('#password_regex_description').val($('label[for="' + element.id + '"]').text());
13864	}
13865}
13866
13867function set_klass_lti_auto_create(element, class_id) {
13868	ajax_request('/class_configure/set_lti_auto_create/' + class_id + '?value=' + element.value);
13869}
13870
13871function disable_link_after_click(event, element) {
13872	if (element.getAttribute('data-clicked')) {
13873		// Prevent the default action if the link has already been clicked
13874		event.preventDefault();
13875	} else {
13876		// Mark the link as clicked
13877		element.setAttribute('data-clicked', 'true');
13878	}
13879}
13880
13881//function to switch permission grid to write mode
13882function toggleEdit(parentClass) {
13883	if(parentClass){
13884		var parentElement = document.querySelector('.'+parentClass);
13885		var readMode = parentElement.querySelectorAll('.readModeContainer');
13886		var writeMode = parentElement.querySelectorAll('.editModeContainer');
13887		var saveButton = parentElement.querySelectorAll('#saveToggleButton');
13888		var editButton = parentElement.querySelectorAll('#editToggleButton');
13889		for (var i = 0; i < readMode.length; i++) {
13890			readMode[i].classList.toggle("permissionHideContainer");
13891		}
13892		for (var j =0; j < writeMode.length; j++) {
13893			writeMode[j].classList.toggle("permissionHideContainer");
13894		}
13895		editButton[0].style.display = 'none';
13896		saveButton[0].style.display = 'block';
13897	}
13898}
13899
13900//function to switch permission grid to read mode
13901function saveChanges(parentClass) {
13902	if(parentClass){
13903		var parentElement = document.querySelector('.'+parentClass);
13904		var readMode = parentElement.querySelectorAll('.readModeContainer');
13905		var writeMode = parentElement.querySelectorAll('.editModeContainer');
13906
13907		var saveButton = parentElement.querySelectorAll('#saveToggleButton');
13908		var editButton = parentElement.querySelectorAll('#editToggleButton');
13909
13910		for (var i = 0; i < readMode.length; i++) {
13911			readMode[i].classList.toggle("permissionHideContainer");
13912		}
13913		for (var j =0; j < writeMode.length; j++) {
13914			writeMode[j].classList.toggle("permissionHideContainer");
13915		}
13916		editButton[0].style.display = 'block';
13917		saveButton[0].style.display = 'none';
13918	}
13919}
13920
13921function cancelChanges() {
13922	//cancel permission logic should go here.
13923	location.reload();
13924}
13925
13926function disable_see_all_passwords(checkbox, confirm_msg) {
13927	$.confirm({
13928		content: confirm_msg,
13929		confirm: function() {
13930			window.location.href = '/policies/disable_administrator_see_passwords';
13931		},
13932		cancel: function () {
13933			$(checkbox).prop("checked", !$(checkbox).prop("checked"));
13934		}
13935	});
13936}
13937
13938function setRememberMeExpirationLimit(dropdown) {
13939	ajax_request('/policies/set_attribute?attribute=remember_me_expiration_limit&value=' + dropdown.value);
13940}
13941
13942function setRemoteCheckValidateResponse(checkbox) {
13943	$('#validate_by_' + checkbox.value).show();
13944
13945	switch (checkbox.value) {
13946		case 'code':
13947			$('#validate_by_text').hide();
13948			break;
13949
13950		case 'text':
13951			$('#validate_by_code').hide();
13952			break;
13953	}
13954}
13955
13956function add_account_field_matching(available_account_fields) {
13957	let id = Math.floor(100000 + Math.random() * 900000);
13958	let html = '<p><select id="matching[account_field][' + id + ']" name="matching[account_field][' + id + ']">';
13959
13960	$.each(available_account_fields, function(i, v) {
13961		html += '<option value="' + v.value + '">' + v.name + '</option>';
13962	});
13963
13964	html += '</select> <i class="arrowRight"></i> <input class="textInput" id="matching[attribute][' + id + ']" name="matching[attribute][' + id + ']" placeholder="Enter SAML attribute ..." type="text"> <i class="delete" onclick="remove_account_field_matching(this)"></i></p>';
13965
13966	$('#account_field_matching').append(html);
13967}
13968
13969function remove_account_field_matching(element) {
13970	$(element).parent().remove();
13971}
13972
13973function isBlank(string) {
13974	return string === null || string === undefined || string.trim() === '';
13975}
13976
13977function deselect_roles(role_ids, checkbox, prefix = "", is_teacher = false, confirm_teacher_message = "") {
13978	if (checkbox.checked) {
13979		for (let role_id of role_ids) {
13980			var element_id = (prefix == "" ? 'role_' + role_id : prefix + '_role_' + role_id);
13981			$('#' + element_id).prop('checked', false);
13982		}
13983	} else {
13984		if (is_teacher) {
13985			var confirmation = confirm(confirm_teacher_message);
13986
13987			if (!confirmation) {
13988				// if the user cancels, prevent unchecking the checkbox
13989				checkbox.checked = true;
13990			}
13991		}
13992	}
13993}
13994
13995function initScrollToTop() {
13996  const handleScroll = () => {
13997    let scrollToTopBtn = document.getElementById("scrollToTopBtn");
13998    if (!scrollToTopBtn) return;
13999
14000    if (document.documentElement.scrollTop > 300) {
14001      scrollToTopBtn.classList.add("show");
14002    } else {
14003      scrollToTopBtn.classList.remove("show");
14004    }
14005  };
14006
14007  const handleClick = (e) => {
14008    e.preventDefault();
14009    window.scrollTo({
14010      top: 0,
14011      behavior: "smooth"
14012    });
14013  };
14014
14015  // Remove any existing scroll listeners to prevent duplicates
14016  window.removeEventListener("scroll", handleScroll);
14017
14018  // Add scroll listener after partial page update
14019  window.addEventListener("scroll", handleScroll);
14020
14021  document.addEventListener("click", (e) => {
14022    if (e.target.closest("#scrollToTopBtn")) {
14023      handleClick(e);
14024    }
14025  });
14026}
14027
14028$(document).ready(function () {
14029  initScrollToTop();
14030});
14031
14032$(document).ready(function () {
14033  // Enable space key functionality for anchor tags with role="button"
14034  $(document).on('keydown', 'a[role="button"]', function(e) {
14035    if (e.key === ' ' || e.keyCode === 32) {
14036      e.preventDefault();
14037      // Native click() so real DOM listeners fire too; suppress the default
14038      // for "#"/absent hrefs so Space doesn't scroll to top (jQuery's trigger()
14039      // does neither of these, see PR discussion).
14040      const href = this.getAttribute('href');
14041      if (!href || href === '#') {
14042        const el = this;
14043        const suppressHashJump = function(ev) { ev.preventDefault(); };
14044        el.addEventListener('click', suppressHashJump);
14045        try {
14046          el.click();
14047        } finally {
14048          el.removeEventListener('click', suppressHashJump);
14049        }
14050      } else {
14051        this.click();
14052      }
14053    }
14054  });
14055});
14056
14057// lti provider configurations
14058
14059function setProviderConfigurationEnabled(controller, providerConfigurationID, checkbox) {
14060	ajax_request('/' + controller + '/set_enabled/' + providerConfigurationID + '?value=' + check_s(checkbox));
14061}
14062
14063function removeInput(element) {
14064	element.parentElement.remove();
14065}
14066
14067function addInput(element, name) {
14068	element.parentElement.insertAdjacentHTML("afterend", "<p><label></label> <input class='textInput' type='text' name='" + name + "'> " +
14069		"<a onclick=\"removeInput(this)\"><i class=\"remove\"></i></a>\n" +
14070		"<a onclick=\"addInput(this, '" + name + "')\"><i class=\"add\"></i></a></p>");
14071}
14072
14073// AICC
14074
14075function set_aicc_attribute(checkbox) {
14076	$.post('/admin_aicc/set_attribute?attribute=' + checkbox.name +'&value=' + check_s(checkbox), function(){
14077		location.reload();
14078	});
14079}
14080
14081function set_klass_aicc_auto_create(element, class_id) {
14082	ajax_request('/class_configure/set_aicc_auto_create/' + class_id + '?value=' + element.value);
14083}
14084
14085// set default_enrollment_on_class_copy
14086
14087function set_default_enrollment_on_class_copy(checkbox) {
14088	$.post('/class_default_settings/set_default_enrollment_on_class_copy?attribute=' + checkbox.name +'&value=' + check_s(checkbox), function(){
14089		location.reload();
14090	});
14091}
14092
14093function toggle_element_visibility(checkbox, selector, inverted) {
14094	if (inverted) {
14095		if (checkbox.checked) {
14096			$(selector).hide();
14097		} else {
14098			$(selector).show();
14099		}
14100	} else {
14101		if (checkbox.checked) {
14102			$(selector).show();
14103		} else {
14104			$(selector).hide();
14105		}
14106	}
14107}
14108
14109// panopto silent login
14110
14111function set_panopto_silent_login(checkbox) {
14112	$.post('/panopto_configure/set_panopto_silent_login?value=' + check_s(checkbox), function(){
14113		location.reload();
14114	});
14115}
14116
14117function set_klass_panopto_silent_login(element, class_id) {
14118	ajax_request('/class_configure/set_panopto_silent_login/' + class_id + '?value=' + element.value);
14119}
14120
14121// batch submit for large forms
14122
14123function displayModalProgress(percentage, text) {
14124  let progressContainer = document.getElementById('progressBarContainer');
14125  let overlay = document.getElementById('progressBarOverlay');
14126
14127  if (!overlay) {
14128    document.body.insertAdjacentHTML('beforeend', `
14129      <div id="progressBarOverlay"></div>
14130    `);
14131    overlay = document.getElementById('progressBarOverlay');
14132  }
14133
14134  if (!progressContainer) {
14135    document.body.insertAdjacentHTML('beforeend', `
14136      <div id="progressBarContainer">
14137        <div id="progressText"></div>
14138        <div style="height: 20px; background: #f0f0f0; margin-top: 10px; border-radius: 5px; overflow: hidden;">
14139          <div id="progressFill" style="height: 100%; width: 0; background: #4CAF50;"></div>
14140        </div>
14141      </div>
14142    `);
14143    progressContainer = document.getElementById('progressBarContainer');
14144  }
14145
14146  document.getElementById('progressText').textContent = text;
14147  document.getElementById('progressFill').style.width = `${percentage}%`;
14148
14149  if (percentage >= 100) {
14150    setTimeout(() => {
14151      if (overlay) document.body.removeChild(overlay);
14152      if (progressContainer) document.body.removeChild(progressContainer);
14153    }, 1000);
14154  }
14155}
14156
14157function batchSubmit(form) {
14158  const formAction = form.getAttribute('action');
14159  const rows = form.querySelectorAll('tr[data-batch]');
14160  let maxBatch = 0;
14161
14162  rows.forEach(row => {
14163    const batchNumber = parseInt(row.getAttribute('data-batch'), 10);
14164    if (batchNumber > maxBatch) {
14165      maxBatch = batchNumber;
14166    }
14167  });
14168
14169  const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
14170  const batchPromises = [];
14171
14172  for (let currentBatch = 0; currentBatch <= maxBatch; currentBatch++) {
14173    const batchPromise = new Promise((resolve, reject) => {
14174      const batchFormData = new FormData();
14175      batchFormData.append('batch', currentBatch);
14176      batchFormData.append('total_batches', maxBatch);
14177
14178      form.querySelectorAll('.hidden input[type="hidden"]').forEach(input => {
14179        batchFormData.append(input.name, input.value);
14180      });
14181
14182      form.querySelectorAll(`tr[data-batch="${currentBatch}"]`).forEach(row => {
14183        const inputs = row.querySelectorAll('input, select');
14184        inputs.forEach(input => {
14185          if (input.name) {
14186            if (input.type !== 'hidden') {
14187              batchFormData.append(input.name, input.value);
14188            } else if (input.name.includes('_alt') || input.name.includes('(year)') || input.name.includes('(month)') || input.name.includes('(day)') || input.name.includes('(hours)') || input.name.includes('(minutes)')) {
14189              batchFormData.append(input.name, input.value);
14190            }
14191          }
14192        });
14193      });
14194
14195      fetch(formAction, {
14196        method: 'POST',
14197        body: batchFormData,
14198        headers: {
14199          'X-Requested-With': 'XMLHttpRequest',
14200          'X-CSRF-Token': csrfToken
14201        },
14202        credentials: 'same-origin'
14203      })
14204        .then(response => {
14205          if (!response.ok) {
14206            throw new Error(`Batch ${currentBatch} failed: ${response.statusText}`);
14207          }
14208          return response.text();
14209        })
14210        .then(data => {
14211          resolve(data);
14212        })
14213        .catch(error => {
14214          console.error(error);
14215          reject(error);
14216        });
14217    });
14218
14219    batchPromises.push(batchPromise);
14220  }
14221
14222  displayModalProgress(0, `Submitting batch 1 of ${maxBatch + 1}...`);
14223
14224  let completedBatches = 0;
14225
14226  Promise.all(batchPromises.map((promise, index) => {
14227    return promise.then(result => {
14228      completedBatches++;
14229      const percentage = (completedBatches / (maxBatch + 1)) * 100;
14230      displayModalProgress(percentage, `Submitting batch ${completedBatches + 1} of ${maxBatch + 1}...`);
14231      return result;
14232    });
14233  }))
14234  .then(results => {
14235    displayModalProgress(100, 'All batches sent successfully!');
14236    setTimeout(() => {
14237      const fromParam = new URLSearchParams(window.location.search).get('from');
14238      const info = results.map(result => {
14239        try {
14240          return JSON.parse(result).info;
14241        } catch (e) {
14242          return null;
14243        }
14244      })
14245      .filter(infoItem => infoItem !== null && infoItem !== '')
14246      .join(', ');
14247
14248      if (fromParam) {
14249        if (info) {
14250          $(window).one('loadcomplete', function () {
14251            show_info(info);
14252          });
14253        }
14254        Excalibur.Router.load(fromParam);
14255      } else {
14256        window.location.reload();
14257      }
14258    }, 1000);
14259  })
14260  .catch(error => {
14261    console.error("Batch submission failed:", error);
14262    show_error("Error submitting batches: " + error.message);
14263  });
14264
14265  return false;
14266}
14267
14268function multi_select_popup(element) {
14269	const form = $(element).closest('form');
14270	const selected_items = form.find("input[name*='select[]']:checked");
14271	const select_all = form.find("input[onclick*='toggle_all']:checked");
14272	let payload = {};
14273
14274	if (selected_items.length > 0 || select_all.length > 0) {
14275		if (select_all.length > 0) {
14276			payload['select_all'] = true;
14277		} else {
14278			payload['select'] = []
14279
14280			selected_items.each(function() {
14281				payload['select'].push($(this).val());
14282			});
14283		}
14284
14285		$.post($(element).attr('href'), payload, function(response) {
14286			$.facebox(response);
14287		});
14288	} else {
14289		$.alert({content: no_items_selected});
14290	}
14291
14292	return false;
14293}
14294
14295function secondary_organizations_selector(secOrgSelector, primOrgSelector, opts) {
14296	let secondaryOrganizationsElement = $(secOrgSelector);
14297	let primaryOrganizationsElement = primOrgSelector ? $(primOrgSelector) : null;
14298
14299	if (!secondaryOrganizationsElement.length) return;
14300
14301	function rebuild_secondary_options(primaryId) {
14302		const selectedIds = secondaryOrganizationsElement.val() || [];
14303		let selectedSet = {};
14304		primaryId = primaryId ? String(primaryId) : "";
14305
14306		selectedIds.forEach(function(id) { selectedSet[String(id)] = true; });
14307
14308		if (secondaryOrganizationsElement.data("select2")) {
14309			secondaryOrganizationsElement.select2("destroy");
14310		}
14311
14312		secondaryOrganizationsElement.empty();
14313
14314		opts.forEach(function(org) {
14315			if (String(org[1]) === primaryId) {
14316				return;
14317			}
14318
14319			const option = new Option(org[0], org[1], false, !!selectedSet[String(org[1])]);
14320			secondaryOrganizationsElement.append(option);
14321		});
14322
14323		secondaryOrganizationsElement.select2({ width: "100%" });
14324		secondaryOrganizationsElement.val(selectedIds.filter(function(id) { return String(id) !== primaryId; }));
14325		secondaryOrganizationsElement.trigger("change");
14326	}
14327
14328	if (secondaryOrganizationsElement.data("select2")) {
14329		secondaryOrganizationsElement.select2("destroy");
14330	}
14331	secondaryOrganizationsElement.select2({ width: "100%" });
14332
14333	primaryOrganizationsElement.on("change", function() {
14334		rebuild_secondary_options($(this).val());
14335	});
14336}
14337
14338// banner slide custom filter callback
14339
14340function bannerSlideFilterCallback(response) {
14341	const manager = window.conditionalFilterManager;
14342	const visiblePanel = $('div[class^=section_carousel_panel_].show');
14343	const filterContainer = visiblePanel.find('.has_filter');
14344	const saveUrl = manager.currentFilterOptions().save_url;
14345
14346	visiblePanel.find('.add_filter').hide();
14347	filterContainer.find('.filter_conditions').text(response.name);
14348	filterContainer.show();
14349
14350	// the slide renders an add and an edit trigger, each with its own registration, so both need the new id
14351	manager.filterIds().forEach(function (id) {
14352		const options = manager.filterOptions(id);
14353
14354		if (options.save_url && options.save_url === saveUrl) {
14355			options.filter_id = response.id;
14356			manager.setFilterOptions(id, options);
14357		}
14358	});
14359}

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.