/* START ************************************************************/
/* OBS måste ligga högst upp för att kunna användas längre ned i koden */
// Ungefär som PHPs sprintf funktion för att ersätta i strängar
//console.log("{0} is dead, but {1} is alive! {0} {2}".sprintf("ASP", "ASP.NET"));
String.prototype.sprintf = function () {
var args = arguments;
return this.replace(/{(\d+)}/g, function (match, number) {
return typeof args[number] != 'undefined' ?
args[number] :
match;
});
};
function sprintf() {
// discuss at: http://phpjs.org/functions/sprintf/
// original by: Ash Searle (http://hexmen.com/blog/)
// improved by: Michael White (http://getsprink.com)
// improved by: Jack
// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// improved by: Dj
// improved by: Allidylls
// input by: Paulo Freitas
// input by: Brett Zamir (http://brett-zamir.me)
// example 1: sprintf("%01.2f", 123.1);
// returns 1: 123.10
// example 2: sprintf("[%10s]", 'monkey');
// returns 2: '[ monkey]'
// example 3: sprintf("[%'#10s]", 'monkey');
// returns 3: '[####monkey]'
// example 4: sprintf("%d", 123456789012345);
// returns 4: '123456789012345'
// example 5: sprintf('%-03s', 'E');
// returns 5: 'E00'
var regex = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuideEfFgG])/g;
var a = arguments;
var i = 0;
var format = a[i++];
// pad()
var pad = function (str, len, chr, leftJustify) {
if (!chr) {
chr = ' ';
}
var padding = (str.length >= len) ? '' : new Array(1 + len - str.length >>> 0)
.join(chr);
return leftJustify ? str + padding : padding + str;
};
// justify()
var justify = function (value, prefix, leftJustify, minWidth, zeroPad, customPadChar) {
var diff = minWidth - value.length;
if (diff > 0) {
if (leftJustify || !zeroPad) {
value = pad(value, minWidth, customPadChar, leftJustify);
} else {
value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
}
}
return value;
};
// formatBaseX()
var formatBaseX = function (value, base, prefix, leftJustify, minWidth, precision, zeroPad) {
// Note: casts negative numbers to positive ones
var number = value >>> 0;
prefix = prefix && number && {
'2': '0b',
'8': '0',
'16': '0x'
}[base] || '';
value = prefix + pad(number.toString(base), precision || 0, '0', false);
return justify(value, prefix, leftJustify, minWidth, zeroPad);
};
// formatString()
var formatString = function (value, leftJustify, minWidth, precision, zeroPad, customPadChar) {
if (precision != null) {
value = value.slice(0, precision);
}
return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar);
};
// doFormat()
var doFormat = function (substring, valueIndex, flags, minWidth, _, precision, type) {
var number, prefix, method, textTransform, value;
if (substring === '%%') {
return '%';
}
// parse flags
var leftJustify = false;
var positivePrefix = '';
var zeroPad = false;
var prefixBaseX = false;
var customPadChar = ' ';
var flagsl = flags.length;
for (var j = 0; flags && j < flagsl; j++) {
switch (flags.charAt(j)) {
case ' ':
positivePrefix = ' ';
break;
case '+':
positivePrefix = '+';
break;
case '-':
leftJustify = true;
break;
case "'":
customPadChar = flags.charAt(j + 1);
break;
case '0':
zeroPad = true;
customPadChar = '0';
break;
case '#':
prefixBaseX = true;
break;
}
}
// parameters may be null, undefined, empty-string or real valued
// we want to ignore null, undefined and empty-string values
if (!minWidth) {
minWidth = 0;
} else if (minWidth === '*') {
minWidth = +a[i++];
} else if (minWidth.charAt(0) == '*') {
minWidth = +a[minWidth.slice(1, -1)];
} else {
minWidth = +minWidth;
}
// Note: undocumented perl feature:
if (minWidth < 0) {
minWidth = -minWidth;
leftJustify = true;
}
if (!isFinite(minWidth)) {
throw new Error('sprintf: (minimum-)width must be finite');
}
if (!precision) {
precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type === 'd') ? 0 : undefined;
} else if (precision === '*') {
precision = +a[i++];
} else if (precision.charAt(0) == '*') {
precision = +a[precision.slice(1, -1)];
} else {
precision = +precision;
}
// grab value using valueIndex if required?
value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];
switch (type) {
case 's':
return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar);
case 'c':
return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad);
case 'b':
return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
case 'o':
return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
case 'x':
return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
case 'X':
return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad)
.toUpperCase();
case 'u':
return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
case 'i':
case 'd':
number = +value || 0;
// Plain Math.round doesn't just truncate
number = Math.round(number - number % 1);
prefix = number < 0 ? '-' : positivePrefix;
value = prefix + pad(String(Math.abs(number)), precision, '0', false);
return justify(value, prefix, leftJustify, minWidth, zeroPad);
case 'e':
case 'E':
case 'f': // Should handle locales (as per setlocale)
case 'F':
case 'g':
case 'G':
number = +value;
prefix = number < 0 ? '-' : positivePrefix;
method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
value = prefix + Math.abs(number)[method](precision);
return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform]();
default:
return substring;
}
};
return format.replace(regex, doFormat);
}
function parse_url(str, component) {
// http://kevin.vanzonneveld.net
// + original by: Steven Levithan (http://blog.stevenlevithan.com)
// + reimplemented by: Brett Zamir (http://brett-zamir.me)
// + input by: Lorenzo Pisani
// + input by: Tony
// + improved by: Brett Zamir (http://brett-zamir.me)
// % note: Based on http://stevenlevithan.com/demo/parseuri/js/assets/parseuri.js
// % note: blog post at http://blog.stevenlevithan.com/archives/parseuri
// % note: demo at http://stevenlevithan.com/demo/parseuri/js/assets/parseuri.js
// % note: Does not replace invalid characters with '_' as in PHP, nor does it return false with
// % note: a seriously malformed URL.
// % note: Besides function name, is essentially the same as parseUri as well as our allowing
// % note: an extra slash after the scheme/protocol (to allow file:/// as in PHP)
// * example 1: parse_url('http://username:password@hostname/path?arg=value#anchor');
// * returns 1: {scheme: 'http', host: 'hostname', user: 'username', pass: 'password', path: '/path', query: 'arg=value', fragment: 'anchor'}
var query, key = ['source', 'scheme', 'authority', 'userInfo', 'user', 'pass', 'host', 'port',
'relative', 'path', 'directory', 'file', 'query', 'fragment'
],
ini = (this.php_js && this.php_js.ini) || {},
mode = (ini['phpjs.parse_url.mode'] &&
ini['phpjs.parse_url.mode'].local_value) || 'php',
parser = {
php: /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/\/?)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ // Added one optional slash to post-scheme to catch file:/// (should restrict this)
};
var m = parser[mode].exec(str),
uri = {},
i = 14;
while (i--) {
if (m[i]) {
uri[key[i]] = m[i];
}
}
if (component) {
return uri[component.replace('PHP_URL_', '').toLowerCase()];
}
if (mode !== 'php') {
var name = (ini['phpjs.parse_url.queryKey'] &&
ini['phpjs.parse_url.queryKey'].local_value) || 'queryKey';
parser = /(?:^|&)([^&=]*)=?([^&]*)/g;
uri[name] = {};
query = uri[key[12]] || '';
query.replace(parser, function ($0, $1, $2) {
if ($1) {
uri[name][$1] = $2;
}
});
}
delete uri.source;
return uri;
}
/* Tvärtom mot jquerys param-funktion
T.ex för att hämta ut en querystring
var qstr = window.location.search;
var q = deparam(test);
console.log(q);
*/
deparam = (function (d, x, params, pair, i) {
return function (qs) {
// start bucket; can't cheat by setting it in scope declaration or it overwrites
params = {};
// remove preceding non-querystring, correct spaces, and split
qs = qs.substring(qs.indexOf('?') + 1).replace(x, ' ').split('&');
// march and parse
for (i = qs.length; i > 0;) {
pair = qs[--i].split('=');
params[d(pair[0])] = d(pair[1]);
}
return params;
}; //-- fn deparam
})(decodeURIComponent, /\+/g);
/*
Parsar en URL och skickar tillbaka allting i ett objekt
T.ex http://xpectum.localhost/edit.php?id=195#test=1
{
"query": {
"id": "195"
},
"path": "/edit.php",
"host": "xpectum.localhost",
"scheme": "http",
"fragment": {
"test": "1"
}
}
*/
function parse_and_get_url(url) {
url = parse_url(url);
query = (typeof url.query != "undefined" ? deparam(url.query) : new Object());
hash = (typeof url.fragment != "undefined" ? deparam(url.fragment) : new Object());
url.query = query;
url.fragment = hash;
return url;
}
// Execute a JavaScript function by name as a string
// http://stackoverflow.com/questions/359788/how-to-execute-a-javascript-function-when-i-have-its-name-as-a-string/359910#359910
function execute_function_by_name(function_name, context /*, args */ ) {
var args = Array.prototype.slice.call(arguments, 2);
var namespaces = function_name.split(".");
var func = namespaces.pop();
for (var i = 0; i < namespaces.length; i++) {
context = context[namespaces[i]];
}
if (typeof context[func] == "function") {
return context[func].apply(context, args);
}
}
// Konverterar newline (\n) till " "
function nl2br(str) {
return str.replace(/\n/g, " ");
};
// Konverterar " " till newline (\n)
function br2nl(str) {
return str.replace(/ /gi, "\n");
//return str.replace(/ /mg,"\n");
//return str.replace(/ /gi, "\n");
};
/* SLUT ************************************************************/
// //youtube API
// //vimeo API
load_js_for_page_via_getscript("https://player.vimeo.com/api/player.js");
load_js_for_page_via_getscript("jsVideoUrlParser/jsVideoUrlParser.min.js", "../../js/plugins/");
// Loads JS-files, if any, in order.
function load_js_for_page_via_getscript(js_urls, path = '', cache = false) {
if (Array.isArray(js_urls)) {
js_urls = js_urls.join(',');
}
if (!js_urls || typeof js_urls !== 'string') {
return $.Deferred().resolve().promise();
}
var urls = js_urls
.split(',')
.map(s => s.trim())
.filter(Boolean);
if (!urls.length) {
return $.Deferred().resolve().promise();
}
var chain = $.Deferred().resolve();
urls.forEach(function (scr) {
chain = chain.then(function () {
return $.ajax({ url: path + scr, dataType: 'script', cache: cache })
});
});
return chain.promise();
}
// Loads JS-files, if any. NOTE! Loaded in parallel, not in order. Not used.
function load_js_for_page_via_getscript_parallel(js_urls, path) {
// Kollar om det finns js script som ska laddas
if (!$.isEmptyObject(js_urls)) {
var urls = js_urls.split(',');
var _urls = $.map(urls, function(scr) {
return $.getScript( (path||"") + scr );
});
//console.log(_urls);
urls.push($.Deferred(function( deferred ){
$( deferred.resolve );
}));
return $.when.apply($, _urls);
} else {
// Finns inga script att ladda, retunerar en solved promise
$.Deferred(function( deferred ){
$( deferred.resolve );
})
return $.when.apply($, js_urls);
}
}
// Laddar js-script, eller json osv för en sida
function load_js_for_page_via_ajax(js_url, callback) {
callback = typeof callback !== 'undefined' ? callback : false;
var js_urls = js_url.split(',');
$.each(js_urls, function (js_url_key, js_url) {
$.ajax({
url: js_url
})
.done(function (jqXHR, textStatus) {
//console.log("scriptet '" + js_url + "' har laddats")
if (callback) {
callback(jqXHR, $(this)[0].dataTypes);
}
})
.fail(function (jqXHR, textStatus, errorThrown) {
//console.log($(jqXHR.responseText).text());
// Kollar om felmeddelande innnehåller HTML och konvertar det i så fall till text
if ($(jqXHR.responseText).length > 0) {
var responseText = $(jqXHR.responseText).text();
} else {
var responseText = jqXHR.responseText;
}
switch (jqXHR.status) {
case 0:
error_text = "Could not connect.\n Verify Network.";
break;
case 404:
error_text = "Page not found [404].";
break;
case 500:
error_text = "Internal Server Error [500].";
break;
default:
error_text = textStatus + ". " + errorThrown + ". " + responseText;
}
$("#course_page_content").html("
" + error_text + "
" + errorThrown + ". " + responseText + "
");
});
});
}
// Laddar en eller flera css för en sida
function load_css_for_page(css_urls, callback, cache = true) {
const urls = (css_urls || "")
.split(",")
.map(u => u.trim())
.filter(Boolean);
if (!urls.length) {
if (typeof callback === "function") callback();
return;
}
const existing = new Set(
$(".page_styles").map((_, el) => $(el).attr("data-src") || "").get()
);
const loaders = urls
.filter(url => !existing.has(url))
.map(url => {
const dfd = $.Deferred();
/*
TODO: the CSS isn't added to the when the querystring is added.
Cache hardcoded to true for now, because otherwise the CSS isn't added Need to find a better solution for this.
*/
cache = true;
const finalUrl = cache
? url
: url + (url.includes("?") ? "&_=" : "?_=") + Date.now();
$("", {
rel: "stylesheet",
type: "text/css",
href: finalUrl,
class: "page_styles",
"data-src": url // original URL for duplicate check
})
.on("load", () => dfd.resolve())
.on("error", () => dfd.reject(url))
.appendTo("head");
return dfd.promise();
});
$.when.apply($, loaders).always(() => {
if (typeof callback === "function") callback();
});
}
// Kollar vilka stylesheet som inte ska användas och tar bort dom
function remove_unused_css_for_page(css_urls_to_load) {
var urls = [];
if (!$.isEmptyObject(css_urls_to_load)) {
urls = css_urls_to_load.split(",");
}
var css_urls_existing = [];
var $page_styles = $('.page_styles');
// Hömtar existrerade stylesheet som redan är laddade
$.each($page_styles, function (style_key, style) {
css_urls_existing.push( $(style).attr('href') );
});
// Tar ut skillnaden av vilka stylesheet som finns och vilka som ska vara kvar
var css_urls_to_remove = $(css_urls_existing).not(urls).get();
// Tar bort de stylesheets som inte ska vara kvar
$.each($page_styles, function (style_key, style) {
if( $.inArray($(style).attr('href'), css_urls_to_remove) >= 0 ) {
$(style).remove();
}
})
}
function remove_css_for_page() {
$('.page_styles').remove();
}
// Hämtar ut filändelse
function get_extension(filename) {
var lastIndex = filename.lastIndexOf('.');
var name = filename.substr(0, lastIndex).toLowerCase();
var extension = filename.split('.').pop().toLowerCase();
var file_info = {
"name": name,
"extension": extension
};
return file_info;
}
// Sättar att en sida är visad och uppdaterar datumet och hur länge man varit inne på sidan, eller sätter en sida som ej visad och tar bort datumet och tiden visad
/*function set_page_viewed(pagekey, viewed)
{
user_log.pages[pagekey].viewed = viewed;
if(viewed)
{
user_log.pages[pagekey].date_viewed = get_and_format_date("", 3)
user_log.pages[pagekey].time_visited += 0;
}
else
{
user_log.pages[pagekey].date_viewed = "";
user_log.pages[pagekey].time_visited = 0;
}
}*/
// Kollar om man är i kursen eller i editorn genom att se om kursstruktiuren är definierad
function is_in_course_or_editor() {
var is_in_course_or_editor = 'editor';
if (course.pages != undefined) {
is_in_course_or_editor = 'course'
}
return is_in_course_or_editor;
}
function get_and_format_date(thedate, return_type) {
var return_date;
if (thedate == "") {
var thedate = new Date();
}
if (!is_valid_date(thedate)) {
var thedate = new Date(Date.parse(thedate));
}
if (is_valid_date(thedate)) {
var dd = thedate.getDate();
var mm = thedate.getMonth() + 1; //Januari är 0
var hh = thedate.getHours();
var min = thedate.getMinutes();
var sec = thedate.getSeconds();
var yyyy = thedate.getFullYear();
if (dd < 10) {
dd = '0' + dd
}
if (mm < 10) {
mm = '0' + mm
}
if (hh < 10) {
hh = '0' + hh
}
if (min < 10) {
min = '0' + min
}
if (sec < 10) {
sec = '0' + sec
}
switch (return_type) {
case 1: // Datumobjekt
var return_date = thedate; //new Date(yyyy, mm, dd, hh, min, sec);
break;
case 2: // Sträng
var return_date = yyyy + "-" + mm + "-" + dd + " " + hh + ":" + min + ":" + sec;
break;
case 3: // ISO 8601 YYYY-MM-DDThh:mm:ssTZD
var return_date = yyyy + "-" + mm + "-" + dd + "T" + hh + ":" + min + ":" + sec + "+01:00";
break;
default: // Sträng
var return_date = yyyy + "-" + mm + "-" + dd + " " + hh + ":" + min + ":" + sec;
}
} else {
// ogiltigt datum
return_date = -1;
}
return return_date;
}
function is_valid_date(d) {
if (Object.prototype.toString.call(d) !== "[object Date]")
return false;
return !isNaN(d.getTime());
}
// Sortera en "associative array", egentligen ett objekt
function by_sorted_value(obj, callback, context) {
var tuples = [];
for (var key in obj) tuples.push([key, obj[key]]);
tuples.sort(function (a, b) {
return a[1] < b[1] ? 1 : a[1] > b[1] ? -1 : 0
});
var length = tuples.length;
while (length--) callback.call(context, tuples[length][0], tuples[length][1]);
}
/*
// Dynamic sort function that sorts objects by their value that you pass
var People = [
{Name: "Name", Surname: "Surname"},
{Name:"AAA", Surname:"ZZZ"},
{Name: "Name", Surname: "AAA"}
];
...and it will work when you do:
People.sort(dynamicSort("Name"));
People.sort(dynamicSort("Surname"));
People.sort(dynamicSort("-Surname"));
*/
function dynamic_sort(property) {
var sortOrder = 1;
if (property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a, b) {
var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
return result * sortOrder;
}
}
/*
// Dynamic sort function that sorts objects by their value that you pass
var People = [
{Name: "Name", Surname: "Surname"},
{Name:"AAA", Surname:"ZZZ"},
{Name: "Name", Surname: "AAA"}
];
...and it will work when you do:
People.sort(dynamicSortMultiple("Name", "-Surname"))
*/
function dynamic_sort_multiple() {
/*
* save the arguments object as it will be overwritten
* note that arguments object is an array-like object
* consisting of the names of the properties to sort by
*/
var props = arguments;
return function (obj1, obj2) {
var i = 0,
result = 0,
numberOfProperties = props.length;
/* try getting a different result from 0 (equal)
* as long as we have extra properties to compare
*/
while (result === 0 && i < numberOfProperties) {
result = dynamicSort(props[i])(obj1, obj2);
i++;
}
return result;
}
}
/*
function date_diff(date1, date2) {
return date1.getTime() - date2.getTime();
}
*/
// Hämtar en sida i kursen
function get_page_for_course(page) {
var counter = 0;
var return_page = -1;
// Loopar igenom kursstrukturen
$.each(course.pages, function (key, value) {
//console.log(key + ": " + value);
if (counter == page || value.name == page) {
return_page = value;
return false;
}
counter++;
});
return return_page;
}
/*console.log(myself(10));
function myself (n) {
if (n <= 1) {
return 1;
}
return n * myself(n-1);
}*/
// Skapar en ny kurslogg
function set_new_user_log(user_log) {
if (!preview) {
var course_id = course_info.published_info.course_id_kursstart;
var exam_id = course_info.published_info.course_id_kursstart;
ajax_load("../../courses_shared/set_user_log.php?course_id=" + course_id + "&exam_id=" + exam_id, {
type: "insert",
user_log: user_log,
total_course_time: 0
}, function (data) {
//console.log(data);
});
} else {
// Kollar om webbläsaren stödjer localStorage
if (Modernizr.localstorage) {
localStorage["user_log_course_" + course_info.course_id] = JSON.stringify(user_log);
}
}
}
var ajax_loader_delay = 1000;
var ajax_loader_message_timer = false;
// Visar ajaxloader med eller utan fördröjning. Med fördröjning kan vara bra för snabb uppkoppling då den bara visas om det tar lång tid
function ajax_loader(enable, no_delay) {
var no_delay = typeof no_delay !== 'undefined' ? no_delay : false;
clearTimeout(ajax_loader_message_timer);
if (enable) {
if( no_delay ) {
// Utan fördröjning
$("#ajax_loader_container").fadeIn("fast");
} else {
// Med fördröjning
ajax_loader_message_timer = setTimeout(function () {
$("#ajax_loader_container").fadeIn("fast");
clearTimeout(ajax_loader_message_timer);
ajax_loader_message_timer = false;
}, ajax_loader_delay);
}
} else {
if (ajax_loader_message_timer)
clearTimeout(ajax_loader_message_timer);
ajax_loader_message_timer = false;
$("#ajax_loader_container").fadeOut("fast");
}
}
// En generell ajax funktion. Retunerar eventuellt data eller true om det gick bra och false vid fel
function ajax_load(url, post_data, callback) {
ajax_loader(true);
$.post(url, post_data)
.done(function (data, textStatus, jqXHR) {
ajax_loader(false);
// Testar om det går att parsa det retunerade datat
try {
data = $.parseJSON(data);
} catch (err) {
// Kollar om felmeddelande innnehåller HTML och konvertar det i så fall till text
if ($(jqXHR.responseText).length > 0) {
var data = {
status: err + '\n' + $(jqXHR.responseText).text()
};
} else {
var data = {
status: err + '\n' + jqXHR.responseText
};
}
};
switch (data.status) {
case "success": // Allt gick bra
$('#course_content #page_error').remove();
callback(data);
break;
case "logged_out": // Användaren har blivit utloggad
var url = parse_and_get_url(window.location);
window.location = 'https://www.kursstart.se/?session_end=true';
break;
default: // Error, something went wrong. Shows error message.
var error_message = {
title: i18next.t('theme.error.error'),
text: i18next.t('theme.error.error_occured') + '\n' + i18next.t("theme.error.error_help_text") + '\n\n'
};
// Klonar orginalobjektet så att inte det ändras. Funkar inte att klona med $.extend.
var page_position = JSON.parse(JSON.stringify(course.pages[current_page_key].position));
var separator = ' > ';
var nr_of_submenus = page_position.length - 1;
var breadcrumbs_trail = [];
//breadcrumbs_trail.push( '' + $element.find('a').first().text().replace('•','') + '' );
for (i = 0; i <= nr_of_submenus; i++) {
$element = $(escape_for_jquery("#menu" + JSON.stringify(page_position)))
page_name = $element.find('a').first().text().replace('•', '');
breadcrumbs_trail.push(page_name);
page_position.pop();
}
// Huvudnivå
breadcrumbs_trail.push(i18next.t("theme.menu.contents"));
// Vänder på arrayen så att det visas från huvudmeny och framåt
breadcrumbs_trail.reverse();
var post_data = {
subject: 'Make My Course - Felmeddelande',
body: nl2br('
');
}
$('#course_content #page_error h3').off('click').on('click', function () {
$(this).parent().remove();
});
return false;
});
}
function play_video(video) {
// Check for flashcard, in that case don't autoplay HTML5 video.
if($('#page_contents .flashcards_container').length == 0) {
if (video !== undefined ) { // Funkar inte för t.ex youtube
// Autospelar om det inte är mobil
if (!is_ipad()) {
video.play();
};
}
// Bugg på iPad som gör att bilden i videon fryser och bara ljudet fortsätter, om man inte pausar och kör igång igen.
/*if(is_ipad()){
video.pause();
setTimeout(function(){
video.play();
}, 1000);
}*/
}
}
function pause_video(video) {
video.pause();
}
function stop_video(video) {
video.stop();
}
// Uppdaterar kursloggen
function set_user_log(auto_continue_to_next_page, auto_continue_play_video, course_finished, user_points_for_course) {
uto_continue_to_next_page = typeof auto_continue_to_next_page !== 'undefined' ? auto_continue_to_next_page : false;
auto_continue_play_video = typeof auto_continue_play_video !== 'undefined' ? auto_continue_play_video : false;
course_finished = typeof course_finished !== 'undefined' ? course_finished : false;
user_points_for_course = typeof user_points_for_course !== 'undefined' ? user_points_for_course : 0;
ajax_loader(true);
if (!$.isEmptyObject($("video")[0])) {
$("video")[0].pause();
}
if (course_finished) {
update_type = "update_and_set_as_finished";
} else {
update_type = "update";
}
//preview = false
if (!preview) {
var course_id = course_info.published_info.course_id_kursstart;
var exam_id = course_info.published_info.course_id_kursstart;
ajax_load("../../courses_shared/set_user_log.php?course_id=" + course_id + "&exam_id=" + exam_id, {
type: update_type,
user_log: user_log,
total_course_time: total_course_time,
user_points_for_course: user_points_for_course
}, function (data) {
ajax_loader(false);
//console.log(data);
if (auto_continue_to_next_page) {
get_page(1);
}
if (auto_continue_play_video) {
if (!$.isEmptyObject($("video")[0])) {
hide_event_container($("#event_container"));
if (is_ipad()) $("video").css({
visibility: "visible"
});
play_video($("video")[0]);
}
}
}, "json");
} else {
// Kollar om webbläsaren stödjer localStorage
if (Modernizr.localstorage) {
ajax_loader(false);
localStorage["user_log_course_" + course_info.course_id] = JSON.stringify(user_log);
if (auto_continue_to_next_page) {
get_page(1);
}
if (auto_continue_play_video) {
if (!$.isEmptyObject($("video")[0])) {
hide_event_container($("#event_container"));
if (is_ipad()) $("video").css({
visibility: "visible"
});
play_video($("video")[0]);
}
}
show_page_info();
}
}
/*if(show_only_debug_buttons)
{
show_page_info();
}*/
//console.log(user_log);
}
// Koll så att man inte kan gå bakåt om man är på första sidan eller fortsätta om man är på sista sidan
// Skickar man in tomt så försöker den hämta från course_log. Skicka in "none" eller "tomt" eller nåt för att gömma alla knappar
function show_control_buttons(buttons_to_show) {
buttons_to_show = typeof buttons_to_show !== 'undefined' ? buttons_to_show : "";
// Börjar med att gömma alla knappar och kontrollpanelen
var view_control_buttons = false;
// OBS! GÅR EJ ATT FEJDE UT KNAPPARNA HÄR! <--- Blir nån slags bugg. Kanske att den inte hinner med att fejda ut.
$("#control_buttons").hide();
$("#control_buttons .button").hide();
$("#control_buttons .button").removeClass("button_disabled");
// Kollar om det är sidans inställningar för vilka knappar som ska synas som ska användas eller om det är det man skickar in i funktionen
// Lägger vilka knappar som ska synas i en array
var control_buttons_to_show = "";
if (buttons_to_show != "") {
control_buttons_to_show = buttons_to_show.split(",");
} else {
if (!$.isEmptyObject(course.pages[current_page_key].show_control_buttons)) {
control_buttons_to_show = course.pages[current_page_key].show_control_buttons.split(",");
}
}
if (control_buttons_to_show.length != 0) {
// Kollar om knapparna ska synas först när en film är klar
var control_buttons_to_show_when_movie_finished = false;
if ($.inArray("movie_finished", control_buttons_to_show) != -1) {
control_buttons_to_show_when_movie_finished = true;
}
$.each(control_buttons_to_show, function (control_button_key, control_button) {
switch ($.trim(control_button)) {
case "all":
$("#control_buttons .button").fadeIn("fast");
view_control_buttons = true;
break;
case "next":
//console.log("Visa framåt");
$("#next_button").fadeIn("fast");
view_control_buttons = true;
break;
case "previous":
//console.log("Visa bakåt");
$("#prev_button").fadeIn("fast");
view_control_buttons = true;
break;
case "course_menu":
//console.log("Visa snabbmeny");
$("#show_course_menu_button").fadeIn("fast");
view_control_buttons = true;
break;
case "return":
//console.log("Visa snabbmeny");
$("#return_button").fadeIn("fast");
view_control_buttons = true;
break;
}
});
if (view_control_buttons) {
if (control_buttons_to_show_when_movie_finished) {
$("video").bind("ended", function () {
$("#control_buttons").fadeIn("fast");
check_course_postition_for_buttons();
});
} else {
$("#control_buttons").fadeIn("fast");
check_course_postition_for_buttons();
}
}
}
// Kod för debugknapparna
if (preview) {
$("#debug_next_button").fadeOut("fast");
$("#debug_prev_button").fadeOut("fast");
$('#debug_select_page').fadeOut("fast");
if (current_page_key == course.pages.length - 1) {
$("#debug_next_button").fadeOut("fast");
} else {
$("#debug_next_button").fadeIn("fast");
}
if (current_page_key == 0) {
$("#debug_prev_button").fadeOut("fast");
} else {
$("#debug_prev_button").fadeIn("fast");
}
$('#debug_select_page').fadeIn("fast");
/* Activate fill in correct answers button, if company is xpectum (6), on pages with template ids:
3: questions-01
- 49: questions-02
- 87: questions-01-image
- 89: questions-01-audio
*/
if(user_info.foretagId == 6) {
$('#debug_wrapper .debug_buttons .toolbar.knowledge_test_toolbar').removeClass('hidden');
$('#debug_wrapper .debug_fill_in_correct_answers_info').removeClass('hidden');
var current_template_id = course.pages[current_page_key].template_id;
var show_on_template_ids = [ 3, 49, 87, 89 ];
$('#debug_fill_in_correct_answers_button').addClass('disabled');
if ( $.inArray( current_template_id, show_on_template_ids ) !== -1 ) {
$('#debug_fill_in_correct_answers_button').removeClass('disabled');
}
}
}
}
$(function () {
// Kör en timer för att behålla referensen till parent-fönstret, ifall det laddas om.
if (typeof preview !== 'undefined') {
if (preview) {
childTimer = window.setInterval(function () {
try {
if (window.opener != null) { // Kollar om den är öppnad från en parent, annars tas timern bort
window.opener.preview_window = window;
} else {
window.clearInterval(childTimer);
}
} catch (e) {}
}, 1000);
window.onUnload = function () {
try {
window.clearInterval(childTimer);
window.opener.preview_window = null;
} catch (e) {}
}
}
}
});
function check_course_postition_for_buttons() {
// Loopar igenom alla kontrollknappar och tar bort alla förutom prev_button och next. För att rensa upp i bottombar om det skapats extraknappar för t.ex övningar och övningsgenomgångar
$control_buttons = $('#control_buttons #control_buttons_left, #control_buttons #control_buttons_right').children();
$.each($control_buttons, function (control_button_key, control_button) {
switch ($(control_button).attr('id')) {
case 'prev_button':
case 'next_button':
case 'show_course_menu_button':
break;
default:
$(control_button).remove();
}
});
// Om kursen inte är linjär så ska snabbvals-knappen också rensas bort. Den ska bara synas i linjära kurser
if (course_info.course_linear == 0) {
$('#control_buttons #control_buttons_left #show_course_menu_button').remove();
}
$('#control_buttons_left, #control_buttons_right').show();
// Kollar om man är på första eller sista sidan för då ska inte bakåt respektive framåt-knappen inte synas
if (current_page_key == course.pages.length - 1) {
$("#next_button").fadeOut("fast");
} else {
//$("#next_button").fadeIn("fast");
}
if (current_page_key == 0) {
$("#prev_button").fadeOut("fast");
} else {
//$("#prev_button").fadeIn("fast");
}
}
/**
* Hämtar numret på nuvarande sida och antalet sidor i kursen
*/
function get_course_pos() {
var course_pos = new Object();
course_pos.current = user_log.pages.length; //current_page_key + 1;
course_pos.total = course.pages.length;
course_pos.percent = Math.floor(100 * (course_pos.current) / course_pos.total)
course_pos.latest_viewed_page = get_latest_viewed_page();
course_pos.latest_viewed_page++;
return course_pos;
}
/**
* Uppdaterar info om var kursdeltagaren är i kursen
*/
function update_course_pos() {
var course_pos = get_course_pos();
$('#course-pos .current').html(course_pos.current);
$('#course-pos .total').html(course_pos.total);
}
function get_latest_viewed_page() {
var latest_pagekey = -1;
var timestamps = new Object();
var sorted_timestamps = new Object();
//console.log(get_and_format_date("", 1).toLocaleString());
// Loopar igenom användarloggen
$.each(user_log.pages, function (key, value) {
if (!!value) {
//console.log(key + ': ' + value.name + ' : ' + value.date_viewed + ' : ' + get_and_format_date(value.date_viewed,1) );
// Check if the date is valid
if (get_and_format_date(value.date_viewed,1) == -1) {
// The date isn't valid, set it to todays date and current time
timestamps[key] = get_and_format_date("", 3);
user_log.pages[key].date_viewed = get_and_format_date("", 3);
}
timestamps[key] = get_and_format_date(value.date_viewed, 1).getTime();
}
});
// Sorterar arrayen numeriskt och stigande, dvs högst värdet sist mao sidan där man var sist
by_sorted_value(timestamps, function (key, value) {
sorted_timestamps[key] = value;
latest_pagekey = key;
});
return parseInt(latest_pagekey);
}
// Skriver ut information om sidan
function show_page_info() {
var view_once = false;
var view_in_menu = true;
if (typeof course.pages[current_page_key].view_once != 'undefined') view_once = boolean_check_and_convert(course.pages[current_page_key].view_once);
if (typeof course.pages[current_page_key].view_in_menu != 'undefined') view_in_menu = boolean_check_and_convert(course.pages[current_page_key].view_in_menu);
// Tömmer debug-infon så att det inte ligger kvar gammal info där när man byter sida
debug_page_info = $('#debug_page_info .debug_page_info_name').next('td');
$.each(debug_page_info, function (key, value) {
if (!$(value).has('textarea').length) {
$(value).empty();
} else {
$(value).val('');
}
});
debug_page_info = $("#debug_page_info table td")
$.each(debug_page_info, function (key, value) {
if (typeof $(value).attr('class') != 'undefined') {
class_name = $(value).attr('class');
switch (class_name) {
case "done":
// Förutsätter att sidan är klar
var done = true;
// Annar hämtar statusen från course_log
if (course.pages[current_page_key][class_name] != undefined) {
done = course.pages[current_page_key][class_name];
}
$(value).html(String(done));
break;
case "type":
$(value).html(pagetypes[Number(course.pages[current_page_key][class_name])] + " (" + course.pages[current_page_key][class_name] + ")");
break;
case "view_once":
$(value).html(view_once.toString());
break;
case "view_in_menu":
$(value).html(view_in_menu.toString());
break;
case "description":
$(debug_page_info).children("#description_text").val(course.pages[current_page_key][class_name]);
break;
case "todo":
$(debug_page_info).children("#todo_text").val(course.pages[current_page_key][class_name]);
break;
case "user_log":
$(debug_page_info).children("#user_log_text").val(JSON.stringify(user_log.pages[current_page_key], null, '\t'));
break;
case "position":
$(value).html(JSON.stringify(course.pages[current_page_key][class_name]));
break;
default:
$(value).html(course.pages[current_page_key][class_name]);
}
}
});
}
// Hämtar eventuella undertexter
function get_subtitles(movie_url) {
// Vilka språk som finns sätts i kursstrukturen, course.js.php
/*var languages = [{
"label": "Svensk undertext",
"srclang": "sv"
},{
"label": "English subtitle",
"srclang": "en"
},{
"label": "Norske undertekst",
"srclang": "no"
}];*/
// Sätter standard filformat
var subtitle_formats = ["vtt", "srt", "sbv", "lrc", "ttml"];
var subtitle_file_extension = "." + subtitle_formats[0];
// Hämtar defaultspråket
var querystring = window.location.search;
var querystring = deparam(querystring);
// Hämtar ut filnamnet på filmen, exklusive sökvägen
var str = movie_url;
var regex = /([^/]+$)/i;
var movie_url_filname = str.match(regex);
if (movie_url_filname != null) {
movie_url_filname = movie_url_filname[0];
var subtitles = [];
var index = 0;
load_language(subtitles, index, languages, movie_url, subtitle_file_extension, language_settings.language, false);
}
}
use_captionator = false;
// Kollar vilka undertexter som finns och lägger dom i en array. Lägger sedan till dom tiil video-elementet
function load_language(subtitles, index, languages, movie_url, subtitle_file_extension, language, found_subtitle) {
if (index < languages.length) {
$.get(movie_url + "." + languages[index].srclang + subtitle_file_extension)
.done(function (data) {
//console.log(data);
subtitles.push("");
index++;
found_subtitle = true;
load_language(subtitles, index, languages, movie_url, subtitle_file_extension, language, found_subtitle);
})
.fail(function (jqXHR, textStatus, errorThrown) {
//console.log($(jqXHR.responseText).text());
switch (jqXHR.status) {
case 0:
error_text = "Could not connect.\n Verify Network.";
break;
case 404:
error_text = "Page not found [404].";
break;
case 500:
error_text = "Internal Server Error [500].";
break;
default:
error_text = "Unknown error. " + $(jqXHR.responseText).text();
}
//$("#course_page_content").html("
" + error_text + "
");
//console.log(error_text);
index++;
load_language(subtitles, index, languages, movie_url, subtitle_file_extension, language, found_subtitle);
});
} else {
if (found_subtitle) {
var video_object = $("video")[0];
$(video_object).append(subtitles.join(""));
use_captionator = captionator.captionify();
}
set_language();
}
}
// Växlar mellan undertexter
function switch_subtitles() {
if (typeof $("video")[0] !== 'undefined') {
// Hämtar undertexterna
var texttracks = $("video")[0].textTracks;
if (typeof texttracks == "object") {
if (use_captionator) {
// Firefox
//OFF, HIDDEN eller SHOWING
$.each(texttracks, function (texttrack_key, texttrack) {
texttracks[texttrack_key].mode = captionator.TextTrack.OFF;
if (texttracks[texttrack_key].language == language_settings.language && language_settings.subtitle == true) {
texttracks[texttrack_key].mode = captionator.TextTrack.SHOWING;
}
});
} else {
// Safari, Chrome
// hidden eller showing. disabled verkar inte funka
$.each(texttracks, function (texttrack_key, texttrack) {
texttracks[texttrack_key].mode = "hidden";
if (texttracks[texttrack_key].language == language_settings.language && language_settings.subtitle == true) {
texttracks[texttrack_key].mode = "showing";
}
});
}
}
}
}
// Visar / gömmer undertexter
function toggle_subtitles(show) {
language_settings.subtitle = show;
$.cookie("language_settings", JSON.stringify(language_settings));
switch_subtitles();
}
// Byter språk
function set_language() {
if (typeof languages !== 'undefined') {
if (languages instanceof Array) {
if (languages.length != 0) {
$("*[lang]").hide();
$("*[lang='" + language_settings.language + "']").show();
switch_subtitles();
}
}
}
}
// Måste även gömma elemnten som skapats annars ligger dom i vägen t.ex när man byter sida.
function hide_captionator() {
if (use_captionator) {
$(".captionator-cue-canvas").remove();
window.addEventListener("resize", function (eventData) {
$(".captionator-cue-canvas").remove();
});
}
}
// Loopar igenom alla språk och skapar olika typer av knappar
function init_change_language_buttons(type) {
var language_buttons = ["
"];
switch (type) {
case "buttons":
$.each(languages, function (lng_key, lng) {
language_buttons.push("
" + lng.label + " →
");
});
break;
case "flags":
$.each(languages, function (lng_key, lng) {
language_buttons.push("
");
});
break;
}
language_buttons.push("
");
return language_buttons;
}
// Lägger in knapparna där man kan välja språk
function show_languages() {
if (typeof languages !== 'undefined') {
if (languages instanceof Array) {
if (languages.length != 0) {
language_buttons = init_change_language_buttons("flags");
if ($("#course_tools #language_settings").length == 0) {
$("#course_tools").append("")
}
$("#course_tools #language_settings").html(language_buttons.join(""));
$("#course_tools #language_settings li span").click(function () {
language_settings.language = $(this).data("language");
$.cookie("language_settings", JSON.stringify(language_settings));
set_language();
});
if (preview) {
//$("#change_language").show()
}
}
}
}
}
// Hitta en sida med ett visst databas id. Används främst för förhandsgranskning från publiceringsverktyget
function find_page_with_page_id(page_id) {
var found_page_key = 0;
$.each(course.pages, function (page_key, page) {
if (page.id == page_id) {
found_page_key = page_key;
return false;
}
});
return found_page_key;
}
// Hämatr en sida från orginal kursstrukturen, den som inte är "tillplattad". Retunerar sidan med eventuella childpages
function get_page_by_position(position) { // Sträng '0,4' eller array [0,4]
// Om ingen postion skickats in hämtas nuvarande sida
if (arguments.length == 0) {
position = course.pages[current_page_key].position;
} else {
// Kollar om det inte är en array och konverterar det i så fall och gör om till int
if (!Array.isArray(position)) {
position = position.split(',').map(Number);
}
}
var str = "";
for (var i = 0; i < position.length; i++) {
if (i == 0) {
str = "original_course.pages[" + position[i] + "]";
} else {
str += ".children[" + position[i] + "]";
}
}
str += ";";
return eval(str);
}
// Hämtar parent sidan
function get_parent_page(page_index_or_position) {
// Om ingen index eller position skickats in hämtas nuvarande sida
if (arguments.length == 0)
page_index_or_position = current_page_key;
// Hämtar positionen om det är index som skickats in
var parent_page_position = "";
if ($.isArray(page_index_or_position)) {
// Klonar orginalobjektet så att inte det ändras. Funkar inte att klona med $.extend.
parent_page_position = JSON.parse(JSON.stringify(page_index_or_position));
} else {
// Klonar orginalobjektet så att inte det ändras
parent_page_position = $.extend(true, {}, course.pages[page_index_or_position].position);
//Gör om det från ett object till array
parent_page_position = $.map(parent_page_position, function (el) {
return el
});
}
// Tar bort sista elementet i arrayen
parent_page_position.pop();
if (parent_page_position != "") {
parent_page = get_page_by_position(parent_page_position);
} else {
parent_page = "";
}
return parent_page;
}
/*********************************************************
Escape all needed characters for jQuery.
Because jQuery uses CSS syntax for selecting elements, some characters are interpreted as CSS notation. For example, ID attributes, after an initial letter (a-z or A-Z), may also use periods and colons, in addition to letters, numbers, hyphens, and underscores (see W3C Basic HTML Data Types). The colon (":") and period (".") are problematic within the context of a jQuery selector because they indicate a pseudo-class and class, respectively.
In order to tell jQuery to treat these characters literally rather than as CSS notation, they must be "escaped" by placing two backslashes in front of them.
https://learn.jquery.com/using-jquery-core/faq/how-do-i-select-an-element-by-an-id-that-has-characters-used-in-css-notation/
*/
function escape_for_jquery(str) {
return str.replace(/(:|\.|\[|\]|,)/g, "\\$1");
}
/*********************************************************/
// Lägger till/ändrar querystringen till rätt ID för sidan
function add_page_querystring() {
url = parse_and_get_url(window.location);
// Standard värden
query_keys = new Object();
query_keys.course_id = url.query.course_id;
query_keys.page_id = course.pages[current_page_key].id;
query_keys.lng = url.query.lng;
if (url.query.preview != undefined) {
query_keys.preview = url.query.preview;
}
if (url.query.demo_token != undefined) {
query_keys.demo_token = url.query.demo_token;
}
if (url.query.responsive_preview != undefined) {
query_keys.responsive_preview = url.query.responsive_preview;
}
if (url.query.hash != undefined) {
query_keys.hash = url.query.hash
if(query_keys.hash.slice(-1) != '='){ // Add "=" (if missing) at the end of encrypted hash since it gets removed when parsing the url
query_keys.hash += '=';
}
}
// Om sidan övning eller övningsgenomgång så utökas querystringen med ytterligare id för att hålla koll på vilken sidan man är på och ibland att man bara ska kunna se ett visst span av sidor i övningsgenomgånar. I annat fall sätt querystringen till defaultvärden.
switch (course.pages[current_page_key].type) {
case 13: // Övning
if (url.query.debug != undefined) {
query_keys.debug = url.query.debug;
}
break;
case 15: // Övningsgenomgång
query_keys.question_page_key = url.query.question_page_key;
query_keys.review_page_key = url.query.review_page_key;
if (url.query.review_pages_span != undefined) {
query_keys.review_pages_span = url.query.review_pages_span;
}
break;
}
url.query = query_keys;
new_url = url.scheme + '://' + url.host + url.path + (!$.isEmptyObject(url.query) ? '?' + $.param(url.query) : "") + (!$.isEmptyObject(url.hash) ? '#' + $.param(url.hash) : "");
window.history.replaceState({}, document.title, new_url);
}
events = "";
current_event_key = "";
function get_page(offset) {
var animate_page_change_speed = "medium";
// Kollar om sidan finns eller om någonting blivit galet, sätter i så fall så att man hamnar på första sidan.
if (course.pages[current_page_key] == undefined) {
current_page_key = 0;
}
if (course.pages[current_page_key].type == 14) {
// Minskar ner när det är övningsexempel-sidor för att man ska se skillnaderna mellan sidorna bättre.
animate_page_change_speed = 'none';
}
show_hide_page_contents(animate_page_change_speed, 'opacity', 'hide', function(){
hide_captionator();
// Rensar och sätter variabler
events = "";
current_event_key = "";
var current_time = 0;
// När man klickat i menyn så sätts variabler tillbaka för att kolleb om man är på samlingssidan för alla övningar och kunskapstester.
if ($('#course_menu_pages').multilevelpushmenu) {
if (multilevelpushmenu_clicked) {
multilevelpushmenu_dont_change = false;
got_here_from_exercises_or_knowledge_tests = false;
// Nollställer querystringen från question_page_key så att man inte kan hamna mitt i en sida i en övning, t.ex övningsprovet
url = parse_and_get_url(window.location);
if (url.query.question_page_key != undefined) {
url.query.question_page_key = 0;
new_url = url.scheme + '://' + url.host + url.path + (!$.isEmptyObject(url.query) ? '?' + $.param(url.query) : "") + (!$.isEmptyObject(url.hash) ? '#' + $.param(url.hash) : "");
window.history.replaceState({}, document.title, new_url);
}
}
}
// Rensar eventuella test-timers för säkerhets skull.
for (var i = test_timers.length; i--;) {
clearInterval(test_timers[i]);
test_timers.splice(i, 1);
}
// Om sidan är "välj övning" så hoppa till nästa sida/kapitel, istället för nästa undersida. Mao det ska inte gå att stega in i övningsexempel/övning med framåtknappen
/*
Sidtyper:
12: Välj övning
13: Övning
14: Övningsexempel
15: Övningsgenomgång
16: Övningar och Kunskapstester
*/
if (course.pages[current_page_key].type == 12 && offset == 1) {
var page_position = JSON.parse(JSON.stringify(course.pages[current_page_key].position)); // Klonar page_position så att man inte ändrar i orginalet
var last_page_pos = page_position[page_position.length - 1];
last_page_pos += 1;
page_position[page_position.length - 1] = last_page_pos;
var page = get_page_by_position(page_position);
current_page_key = page.page_index;
offset = 0;
}
//Om sidan är en övning, övningsgenomgång eller övningsexempel och man har backat dit från en annan sida så ska man hamna på "Välj övning"-sidan
var exercise_page_types = [13, 14, 15];
if ($.inArray(course.pages[current_page_key].type, exercise_page_types) == -1 && offset == -1) {
// Kollar om sidan man kommer till är en övning, övningsgenomgång eller övningsexempel för i så fall ska man hamna på "Välj övning"-sidan
if ($.inArray(course.pages[current_page_key + offset].type, exercise_page_types) !== -1) {
var page_position = JSON.parse(JSON.stringify(course.pages[current_page_key].position)); // Klonar page_position så att man inte ändrar i orginalet
var last_page_pos = page_position[page_position.length - 1];
last_page_pos -= 1;
page_position[page_position.length - 1] = last_page_pos;
var page = get_page_by_position(page_position);
current_page_key = page.page_index;
offset = 0;
}
}
// Aktuellt sid-ID
current_page_key = current_page_key + offset;
if (current_page_key > course.pages.length - 1) {
current_page_key = 0;
}
if (preview) {
//$('#debug_select_page').val(current_page_key);
debug_show_page_list();
}
add_page_querystring();
// Om kursen inte är linjär så sparar inte kunskapstester; quiz, sant eller falskt och jeopardy
if (!course_info.course_linear) {
var dont_save_page_types = [3, 7, 9];
if ($.inArray(course.pages[current_page_key].type, dont_save_page_types) > -1) {
// Tar bort eventuella svar på sidan
if (!$.isEmptyObject(user_log.pages[current_page_key])) {
if (!$.isEmptyObject(user_log.pages[current_page_key].answers)) {
delete user_log.pages[current_page_key].answers;
delete user_log.pages[current_page_key].points;
}
}
}
}
// Tar bort allting som eventuellt lagts till utöver sidinnheållet, t.ex explanation_container för övningsexempel
// Bara #course_guide, course_page_content ska finnas under #course_content
$content_to_remove = $('#course_content').children().not('#course_guide, #page_name, #course_page_content, #video_controllers, .bottom_bar_dummy, #bottom_bar');
$content_to_remove.remove();
// Containern
var course_page_content = $("#course_page_content");
// Kollar om sidan är visad förut och om den bara ska visas en gång
view_once = false;
if (typeof course.pages[current_page_key].view_once != 'undefined') view_once = boolean_check_and_convert(course.pages[current_page_key].view_once);
if (!$.isEmptyObject(user_log.pages[current_page_key]) && boolean_check_and_convert(view_once)) {
get_page(1);
} else {
// Sidans innehåll
var content = course.pages[current_page_key].content;
// Sidas rubrik
// Finns även kategori, vet inte om det behövs
// course.pages[current_page_key].category
var theme_page_name = $('#course_content > #page_name');
var page_name_and_content = content;
if (!theme_page_name.length) {
page_name_and_content = "
" + course.pages[current_page_key].name + "
" + page_name_and_content;
} else {
$('#course_content > #page_name h2').html(course.pages[current_page_key].name);
}
content = '' + page_name_and_content + ''
// Sätter standardvärden för videoprogress och gömmer den tills videon kommer igång
var video_progress_percent = 0;
$("#video_progress").width(video_progress_percent + "%");
/*$("#video_controllers").fadeOut("fast");
// Bugg i WebKit, controllerna fejdas inte bort*/
$("#video_controllers").hide();
show_control_buttons();
if ($('#course_menu_pages').multilevelpushmenu) {
if (multilevelpushmenu_clicked) {
set_active_menu_page(offset);
}
}
/*
Check if template id is 3,49,87,89 and load the required js and css for knowledge test pages if they are missing. Since these are added in the course structure only after publishing the course.
*/
let knowledge_test_template_ids = [3, 49, 87, 89];
if($.inArray(course.pages[current_page_key].template_id, knowledge_test_template_ids) !== -1){
// console.group('old:');
// console.log( "js_url: " + course.pages[current_page_key].js_url );
// console.log( "css_url: " + course.pages[current_page_key].css_url );
// console.groupEnd();
let js_urls_fix = ['../../courses_shared/tests/knowledge-test.questions-1.0.js', '../../courses_shared/tests/quiz.js', '../../courses_shared/tests/knowledge-test.correction-1.0.js'];
let css_urls_fix = ['../../courses_shared/tests/quiz.css', '../../courses_shared/tests/knowledge-test.questions-1.0.css'];
// If template id is 49, add fixed-height.css after quiz.css. NOT NEEDED?
/* if (course.pages[current_page_key].template_id === 49) {
css_urls_fix.splice(1, 0, '../../templates/fixed-height.css');
} */
/*
Ensure required knowledge-test assets are present exactly once and in canonical order.
Keep other existing assets in their current order and append required assets after them.
*/
function mergeRequiredUrls(currentCsv, requiredUrls){
var currentUrls = (currentCsv || '')
.split(',')
.map(function(url){ return url.trim(); })
.filter(Boolean);
var requiredSet = new Set(requiredUrls);
var others = currentUrls.filter(function(url){
return !requiredSet.has(url);
});
return others.concat(requiredUrls).join(',');
}
course.pages[current_page_key].js_url = mergeRequiredUrls(course.pages[current_page_key].js_url, js_urls_fix);
course.pages[current_page_key].css_url = mergeRequiredUrls(course.pages[current_page_key].css_url, css_urls_fix);
// console.group('new:');
// console.log( "js_url: " + course.pages[current_page_key].js_url );
// console.log( "css_url: " + course.pages[current_page_key].css_url );
// console.groupEnd();
}
// Kollar om det finns css som ska laddas
load_css_for_page(course.pages[current_page_key].css_url, function(){
ajax_loader(true);
// Eventuell CSS laddad
remove_unused_css_for_page(course.pages[current_page_key].css_url);
insert_page_contents(course_page_content, content, function(){
//$('#course_content #page_name h2').html('Lägger in innehållet')
// Lägger in innehållet
set_readmore_button();
// Sätter poster-bild
set_video_poster_image(course_page_content);
// Lägger till undertext
set_video_subtitle(course_page_content);
// Lägger till attributet target="_blank" på alla länkar i elementen .text.
$('#page_contents .text a').attr('target', '_blank');
load_js_for_page_via_getscript(course.pages[current_page_key].js_url).done(function() {
// Alla eventuella script laddade
show_hide_page_contents(animate_page_change_speed, 'opacity', 'show', function(){
// Visar innehållet
ajax_loader(false);
if ($('#course_menu_pages').multilevelpushmenu) {
if (multilevelpushmenu_dont_change == false) {
if (!multilevelpushmenu_clicked) {
set_active_menu_page(offset);
} else {
multilevelpushmenu_clicked = false;
}
}
};
});
}).fail(function(error) {
// one or more scripts failed to load
//console.log('one or more scripts failed to load');
}).always(function() {
// always called, both on success and error
//console.log('always called, both on success and error');
});
});
});
//countup_start();
//create_breadcrumbs_trail();
//show_control_buttons();
show_languages();
// Uppdaterar info om sidposition
//update_course_pos();
// Uppdaterar guiden sida x av y
$("#course_guide_text").fadeOut("fast", function () {
var dont_show_on_page_types = [12, 13, 15];
if ($.inArray(course.pages[current_page_key].type, dont_show_on_page_types) == -1) {
page_nr = course.pages[current_page_key].position[course.pages[current_page_key].position.length - 1] + 1;
page_nr_of = original_course.pages.length;
// Kollar sidan är ett kapitel och börjar i så fall räkna från 1
//if( course.pages[current_page_key].children_nr_of !== undefined ) {
if (current_page_is_chapter()) {
page_nr = 1;
page_nr_of = course.pages[current_page_key].children_nr_of + 1;
}
// Kollar om man är inuti ett kapitel
//if( course.pages[current_page_key].position.length > 1 && course.pages[current_page_key].children_nr_of == undefined ) {
if (course.pages[current_page_key].position.length > 1 && !current_page_is_chapter()) {
page_nr++; // Plussar på ett eftersom huvudsidan i kapitlet är nr 1
page_nr_of = get_parent_page(current_page_key).children_nr_of + 1; // Hämtar huvudsidan i kapitle och kollar hur många sidor det innehåller
}
// Kollar om det är en ensam övningsexempel mall utan några undersidor och fixar till sidnumreringen
if(course.pages[current_page_key].type == 14 && !current_page_is_chapter()){
parent_page = get_parent_page(current_page_key);
if(parent_page.type != 14){
page_nr = 1;
page_nr_of = 1;
$("#prev_button").fadeOut("fast");
$("#next_button").fadeOut("fast");
}
}
/*
Byter ut och formaterar strängen beroende på hur det ska visas upp. Utseendet och vad som ska skrivas ut ställs in i respektive tema.
%1$s : Sida
%2$s : x
%3$s : av
%4$s : y
%1$s %2$s %3$s %4$s = Sida x av y
%2$s / %4$s = x / y
show_in_root: true // Visas även i huvudnivån/rootnivån i kursen och inte bara inuti kapitel
show_with_content: true // Flyttar in sidvisningen inuti kursinehållet
*/
var page_nr_settings = $.parseJSON($('#course_guide_text').attr('data-settings'));
$("#course_guide_text").html(sprintf(page_nr_settings.formatting, i18next.t("theme.text.page"), page_nr, i18next.t("theme.text.of"), page_nr_of));
// Flyttar in course_guide in tillsammans med innehållet
if (page_nr_settings.show_with_content) {
// Kollar om den redan är flyttad
if ($('#course_content > #course_guide').length == 0) {
var $course_guide = $("#course_tools #course_guide");
var $course_guide = $course_guide.detach().prependTo('#course_content');
}
}
// Visar inte antalet sidor om man är i huvudnivån
if (page_nr_settings.show_in_root == true) {
$('#course_guide_text').fadeIn("fast");
//}else if( page_nr_settings.show_in_root == false && course.pages[current_page_key].position.length > 1 || course.pages[current_page_key].children_nr_of !== undefined ) {
} else if (page_nr_settings.show_in_root == false && course.pages[current_page_key].position.length > 1 || current_page_is_chapter()) {
$('#course_guide_text').fadeIn("fast");
}
}
});
// Uppdaterar progressbaren
var progress_percent = Math.floor(100 * (current_page_key + 1) / course.pages.length);
$("#progress").width(progress_percent + "%");
// Om kursen är linjär så ska snabbvals-menyn uppdateras varje gång man byter sida.
if (typeof set_course_menu_pages === "function") { // Kollar så att funktionen finns för säkerhets skull
if (course_info.course_linear == 1) {
set_course_menu_pages();
}
}
// Kollar om sidan redan finns i användarloggen och uppdaterar isf den
if (!$.isEmptyObject(user_log.pages[current_page_key]) && user_log.pages[current_page_key] != "") {
//console.log("Uppdaterar tidigare besökt sida");
user_log.pages[current_page_key].name = course.pages[current_page_key].name;
user_log.pages[current_page_key].viewed = true;
user_log.pages[current_page_key].date_viewed = get_and_format_date("", 3);
user_log.pages[current_page_key].time_visited = (user_log.pages[current_page_key].time_visited == undefined ? 1 : user_log.pages[current_page_key].time_visited += 1);
} else { // Annars lägger till sidan i användarloggen
//console.log("Lägger till ny ej tidigare besökt sida");
if(user_log.pages == ""){
user_log.pages = [];
}
new_page = {
"name": course.pages[current_page_key].name,
"viewed": true,
"date_viewed": get_and_format_date("", 3),
"time_visited": 1
};
user_log.pages[current_page_key] = new_page;
}
//console.log( JSON.stringify(user_log.pages[current_page_key], null, 2));
// Sparar hur länge man var inne på föregående sida och totaltiden
//user_log.pages[current_page_key-offset].time_visited = $('#countup_seconds').countdown('getTimes')[6];
//total_course_time = $('#countup_total_seconds').countdown('getTimes')[6];
// Sparar användarloggen
set_user_log(false, true, false);
}
});
}
/// Lägger in innehållet
function insert_page_contents(course_page_content, content, callback){
switch (course.pages[current_page_key].type) {
case 1: // text/html
// Lägger till sidinnehållet i containern
course_page_content.html(content);
set_language();
break;
case 10: // text/html fullskärm, täcker hela ytan
// Lägger till sidinnehållet i containern
course_page_content.html(content);
set_language();
break;
case 2: // video
/*$("#course_page_content").html(content);
set_language();
break;*/
case 11: // video med kontrollfrågor
case 6: // film med frågor och respons
// All denna kod för video borde läggas i en funktion så att man kan ladda filmer med event dynamiskt, tex olika filmer beroende på om man är godkänd eller inte. Se sortabel.js och true_false_result.js
// Skapar eventkontainern för video
content += "";
//course.pages[current_page_key].movie_url = "inledning_jonas_lundin";
//autoplay=\"autoplay\" controls=\"controls\"
// Skapar videokontainer // Hmm vilken codecs ska man använda för mp4? Verkar som man ska använda avc1.42E01E, mp4a.40.2 istället för H.264, AAC,
// Firefox och Chrome kör .webm
// Safari och IE kör .mp4
// För att undvika buffring
rnd = "?rnd=" + Math.floor(Math.random() * 10000);
content += "";
//\
// Lägger till sidinnehållet i containern
course_page_content.html(content);
if (typeof languages !== 'undefined') {
if (languages instanceof Array) {
if (languages.length != 0) {
// Hämtar eventuella undertexter
get_subtitles(course.pages[current_page_key].movie_url);
$("video").bind("ended", function () {
hide_captionator();
});
}
}
}
// Visar controllern på iPad eftersom det inte går att autostarta video
// Visar även controllern på alla filmer förutom filmer med frågor och respons
if (is_ipad() || preview || course.pages[current_page_key].type == 2) {
toggleControls($("video")[0]);
}
$("#video_controllers").fadeIn("fast");
// Kollar om det finns några events
if (!$.isEmptyObject(course.pages[current_page_key].events)) {
// Hämtar events för video
events = course.pages[current_page_key].events;
}
$("#course_page_content video").bind("timeupdate", function () {
// Tiden som spelats
// I hela sekunder
current_time = parseInt(this.currentTime);
total_time = parseInt(this.duration);
//console.log(current_time + " / " + total_time);
// Uppdaterar video progressbaren
video_progress_percent = Math.floor(100 * (current_time) / total_time);
$("#video_progress").width(video_progress_percent + "%");
// Kollar om det finns några events
if (!$.isEmptyObject(course.pages[current_page_key].events)) {
// Rensar alla triggade event förutom de som bara får visas en gång vid start/omstart av en film
if (current_time == 0) {
$.each(events, function (key, value) {
if (value.repeatable) {
value.triggered = false;
}
});
}
// Föregående tid (används för att "throttla" antalet anrop till eventfunktionen)
old_time = 0;
// Hämtar nästa event från eventlistan (movie_properties)
if (current_time > old_time) get_next_movie_event(events, current_time, $(this), $("#event_container"));
old_time = current_time;
}
});
// Kollar om filmen ska kunna spelas upp igen direkt när den slutat
movie_buttons_container = ($("#course_page_content #movie_buttons_container"));
if (movie_buttons_container.length > 0) {
$("video").bind("ended", function () {
if (is_ipad()) $("video").css({
visibility: "hidden"
});
$("#movie_buttons_container").fadeIn("fast");
});
$("#watch_movie_again_button").off('click').click(function () {
$("#movie_buttons_container").fadeOut("fast");
if (is_ipad()) $("video").css({
visibility: "visible"
});
play_video($("video")[0]);
});
}
break;
case 3: // sant eller falskt
// Lägger till sidinnehållet i containern
course_page_content.html(content);
set_language();
break;
case 4: // rangordna
// Lägger till sidinnehållet i containern
course_page_content.html(content);
set_language();
break;
case 5: // utvärdering
// Lägger till sidinnehållet i containern
course_page_content.html(content);
set_language();
break;
case 7: // Quiz checkbox, radio fritext
// Lägger till sidinnehållet i containern
course_page_content.html(content);
set_language();
break;
case 8: // Dra och släpp Quiz
// Lägger till sidinnehållet i containern
course_page_content.html(content);
set_language();
break;
case 9: // Jeopardy
// Lägger till sidinnehållet i containern
course_page_content.html(content);
set_language();
break;
default:
// Lägger till sidinnehållet i containern
course_page_content.html(content);
set_language();
break;
}
var $has_attached_files = $(course_page_content).find('#attached_files');
if ($has_attached_files.length != 0) {
if( $(course_page_content).find('.gen_sound_index').length != 0 ) {
$($has_attached_files).insertBefore( $(course_page_content).find('.gen_sound_index') );
}
load_css_for_page('../../js/plugins/fine-uploader-all-5.16.2/fine-uploader-mmc-course.css', function(){
var attached_files = $.parseJSON( $has_attached_files.attr('data-attached_files') );
var header = attached_files.length > 1 ? i18next.t('files:text.attached_files') : i18next.t('files:text.attached_file');
var html = ['
');
$has_attached_files.html( html.join('') );
setTimeout(function() {
$has_attached_files.addClass('show');
$has_attached_files.off("click").click(function () {
$has_attached_files.focus();
});
}, 2000);
//$("#course_content #attached_files").draggable({handle: "#course_content #attached_files h3", containment: '#course_wrapper'});
//$('#page_contents').css('padding');
});
}
callback();
}
function attached_file_icon(contentType){
var icon = "";
var icon_fallback = "";
switch (contentType) {
case 'image/jpeg':
icon = '../../js/plugins/fine-uploader-all-5.16.2/placeholders/if_jpgs_774688.svg';
icon_fallback = '../../js/plugins/fine-uploader-all-5.16.2/placeholders/if_jpgs_774688.png';
break;
case 'image/png':
icon = '../../js/plugins/fine-uploader-all-5.16.2/placeholders/if_pngs_774683.svg';
icon_fallback = '../../js/plugins/fine-uploader-all-5.16.2/placeholders/if_pngs_774683.png';
break;
case 'application/pdf':
icon = '../../js/plugins/fine-uploader-all-5.16.2/placeholders/if_pdfs_774684.svg';
icon_fallback = '../../js/plugins/fine-uploader-all-5.16.2/placeholders/if_pdfs_774684.png';
break;
}
return '\
\
\
';
}
// Visar eller döljer innehållet
function show_hide_page_contents(animate_page_change_speed, type, state, callback) {
switch (type) {
case 'opacity':
if($('#page_transition').length == 0) {
$('').appendTo('head');
}
$("#course_page_content").removeClass('fade-transition-fast fade-transition-medium');
switch (animate_page_change_speed) {
case 'medium':
$("#course_page_content").addClass('fade-transition-medium');
break;
case 'fast':
$("#course_page_content").addClass('fade-transition-fast');
break;
case 'none':
break;
default:
$("#course_page_content").addClass('fade-transition-medium');
break;
}
if (state === 'show' && animate_page_change_speed !== 'none' ) {
// fejd in
$("#course_page_content").removeClass('do-fade').one('transitionend', function () {
callback();
scroll_to_top_of_page();
});
} else if (animate_page_change_speed === 'none') {
callback();
} else {
// fejd ut
$("#course_page_content").addClass('do-fade').one('transitionend', function () {
callback();
});
}
break;
}
}
function scroll_to_top_of_page(){
// Scrollar högst upp på sidan
$('html,body').animate({
scrollTop: 0
}, 800);
}
// Kollar om en fil finns och kör i så fall callback med jqXHR och datatyp
// does_file_exist("http://www.xpectum.se/kurser/vid/FAR/intervjuer_intern_extern_redovisning.vtt");
// does_file_exist("http://www.xpectum.se/kurser/vid/bokforing1/4_typer_av_konton.vtt");
// does_file_exist('../../../kurser/vid/bokforing1/4_typer_av_konton2.vtt', function (jqXHR, dataTypes) {
// if (dataTypes[0] === "text" && dataTypes[1] !== "html") {
// console.log( 'Funkar!' );
// }
// })
// does_file_exist("../../../images/xpectum_logotype.png");
function does_file_exist(url_to_file, callback) {
$.ajax({
url: url_to_file
})
.done(function (jqXHR, textStatus) {
//console.log("scriptet '" + js_url + "' har laddats")
//console.log( $(this)[0].dataTypes );
if (callback) {
callback(jqXHR, $(this)[0].dataTypes);
} else {
return true;
}
})
.fail(function (jqXHR, textStatus, errorThrown) {
return false;
});
}
/*
Kollar och konverterar, om det behövs, strängar till riktiga boolean-värden
Exempel:
console.log( boolean_check_and_convert('false') ); // False
console.log( boolean_check_and_convert(false) ); // False
console.log( boolean_check_and_convert('true') ); // True
console.log( boolean_check_and_convert(true) ); // True
console.log( boolean_check_and_convert('abc') ); // False
console.log( boolean_check_and_convert(123) ); // False
*/
function boolean_check_and_convert(bool_string) {
switch (typeof bool_string) {
case 'string':
switch (bool_string.toLowerCase().trim()) {
case "true":
case "yes":
case "1":
return true;
case "false":
case "no":
case "0":
case null:
return false;
default:
return false;
}
break;
case 'boolean':
return bool_string;
break;
default:
return false;
}
}
// Hämtar alla videoelement och sätter en poster bild utifrån samma filnamn som filmen
function set_video_poster_image($element) {
var $video_elements = $element.find('video');
if ($video_elements.length > 0) {
$.each($video_elements, function (video_key, $video_element) {
var poster_img = get_extension($($video_element).find('source').attr("src"));
$($video_element).attr("poster", poster_img.name + ".jpg");
});
}
}
// Hämtar alla videoelement och sätter en subtitle utifrån samma filnamn som filmen
function set_video_subtitle($element) {
user_video_subtitle_settings = {
show: false,
language: ''
};
/*
Saves it in localStorage for all courses
Change to this localStorage_key, if it is to be saved per course:
'user_video_subtitle_settings_course_' + course_info.course_id]
*/
var localStorage_key = 'user_video_subtitle_settings_course';
if (Modernizr.localstorage) {
if( localStorage[localStorage_key] != undefined ){
user_video_subtitle_settings = JSON.parse(localStorage[localStorage_key]);
}
}
// Alla språk. Om undertext-filen inte har någon suffix (_sv, _en, _no) så utgår vi från att det är en svensk undertext
var languages = {
"" : "Svenska",
"sv" : "Svenska",
"no" : "Norsk",
"en" : "English"
};
var $video_elements = $element.find('video');
if ($video_elements.length > 0) {
// Loops through all videos
$.each($video_elements, function (video_key, $video_element) {
var subtitle = get_extension($($video_element).find('source').attr("src"));
var subtitle_files = [];
// Loops through all available languages and collect info
$.each(languages, function (language_key, language_name) {
var language_suffix = '';
var language = 'sv';
if(language_key !== ''){
var language_suffix = '_' + language_key;
var language = language_key;
}
var subtitle_file = subtitle.name + language_suffix + '.vtt';
subtitle_files.push({"src": subtitle_file.toLowerCase(), "language_name": language_name, "language": language});
});
// Check for subtitle files and adds them as tracks
get_subtitle_tracks(subtitle_files, $video_element, function () {
});
// Check for user changes of subtitle and which language is choosen. To be saved in localStorage
$($video_element)[0].textTracks.onchange = function(event) {
user_video_subtitle_settings.show = false;
user_video_subtitle_settings.language = '';
$.each(this, function (texttrack_key, texttrack) {
if(texttrack.mode == 'showing'){
user_video_subtitle_settings.show = true
user_video_subtitle_settings.language = texttrack.language
}
})
// TODO: change language/subtitle settings for all videos on page (video carousels)
// Cant do it here because it triggers onchange again on all videos and it becomes an infinite loop (?)
// Save the subtitle settings (is subitle showing and in what langugae) for current course in localStorage.
// TODO: save settings in database, so it works everywhere ?
if (Modernizr.localstorage) {
localStorage[localStorage_key] = JSON.stringify(user_video_subtitle_settings);
}
};
});
}
}
// Check for subtitle files and adds them as tracks
function get_subtitle_tracks(subtitle_files, $video_element, callback) {
var progress = 0;
$.each(subtitle_files, function (subtitle_file_key, subtitle_file) {
$.ajax({
url: subtitle_file.src
})
.done(function (jqXHR, textStatus) {
default_language = '';
// If localStorage setting exist set chosen language
if(user_video_subtitle_settings.language == subtitle_file.language){
default_language = ' default';
}
$($video_element).append('