// jQuery-plugin som väntar på att ett element ska laddas in $.fn.onAvailable = function(fn){ var sel = this.selector; var timer; var self = this; if(this.length > 0) { fn.call(this); } else { timer = setInterval(function(){ if($(sel).length > 0) { fn.call($(sel)); clearInterval(timer); } }, 50); } }; 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 ajax_loader(enable) { if(enable) { // $("#ajax_loader_container").fadeIn("fast"); $("#ajax_loader_container").show(); } else { // $("#ajax_loader_container").fadeOut("fast"); $("#ajax_loader_container").hide(); } }; // Asynchronous version of showing the ajax_loader. For long runnting tasks the main thread is too busy for showing the loader. This function makes sure that its shown before continuing. function ajax_loader_async(enable) { return new Promise((resolve, reject) => { if(enable) { $("#ajax_loader_container").show(function() { resolve(); }); } else { $("#ajax_loader_container").hide(function() { resolve(); }); } }); } // Simulates PHP's date function Date.prototype.format=function(e){var t="";var n=Date.replaceChars;for(var r=0;r=0&&e.charAt(r-1)=="\\"){t+=i}else if(n[i]){t+=n[i].call(this)}else if(i!="\\"){t+=i}}return t};Date.replaceChars = { shortMonths : ['jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'], longMonths : ['januari', 'februari', 'mars', 'april', 'maj', 'juni', 'juli', 'augusti', 'september', 'oktober', 'november', 'december'], shortDays : ['sön', 'mån', 'tis', 'ons', 'tor', 'fre', 'lör'], longDays : ['söndag', 'måndag', 'tisdag', 'onsdag', 'torsdag', 'fredag', 'lördag'],d:function(){return(this.getDate()<10?"0":"")+this.getDate()},D:function(){return Date.replaceChars.shortDays[this.getDay()]},j:function(){return this.getDate()},l:function(){return Date.replaceChars.longDays[this.getDay()]},N:function(){return this.getDay()+1},S:function(){return this.getDate()%10==1&&this.getDate()!=11?"st":this.getDate()%10==2&&this.getDate()!=12?"nd":this.getDate()%10==3&&this.getDate()!=13?"rd":"th"},w:function(){return this.getDay()},z:function(){var e=new Date(this.getFullYear(),0,1);return Math.ceil((this-e)/864e5)},W:function(){var e=new Date(this.getFullYear(),0,1);return Math.ceil(((this-e)/864e5+e.getDay()+1)/7)},F:function(){return Date.replaceChars.longMonths[this.getMonth()]},m:function(){return(this.getMonth()<9?"0":"")+(this.getMonth()+1)},M:function(){return Date.replaceChars.shortMonths[this.getMonth()]},n:function(){return this.getMonth()+1},t:function(){var e=new Date;return(new Date(e.getFullYear(),e.getMonth(),0)).getDate()},L:function(){var e=this.getFullYear();return e%400==0||e%100!=0&&e%4==0},o:function(){var e=new Date(this.valueOf());e.setDate(e.getDate()-(this.getDay()+6)%7+3);return e.getFullYear()},Y:function(){return this.getFullYear()},y:function(){return(""+this.getFullYear()).substr(2)},a:function(){return this.getHours()<12?"am":"pm"},A:function(){return this.getHours()<12?"AM":"PM"},B:function(){return Math.floor(((this.getUTCHours()+1)%24+this.getUTCMinutes()/60+this.getUTCSeconds()/3600)*1e3/24)},g:function(){return this.getHours()%12||12},G:function(){return this.getHours()},h:function(){return((this.getHours()%12||12)<10?"0":"")+(this.getHours()%12||12)},H:function(){return(this.getHours()<10?"0":"")+this.getHours()},i:function(){return(this.getMinutes()<10?"0":"")+this.getMinutes()},s:function(){return(this.getSeconds()<10?"0":"")+this.getSeconds()},u:function(){var e=this.getMilliseconds();return(e<10?"00":e<100?"0":"")+e},e:function(){return"Not Yet Supported"},I:function(){var e=null;for(var t=0;t<12;++t){var n=new Date(this.getFullYear(),t,1);var r=n.getTimezoneOffset();if(e===null)e=r;else if(re)break}return this.getTimezoneOffset()==e|0},O:function(){return(-this.getTimezoneOffset()<0?"-":"+")+(Math.abs(this.getTimezoneOffset()/60)<10?"0":"")+Math.abs(this.getTimezoneOffset()/60)+"00"},P:function(){return(-this.getTimezoneOffset()<0?"-":"+")+(Math.abs(this.getTimezoneOffset()/60)<10?"0":"")+Math.abs(this.getTimezoneOffset()/60)+":00"},T:function(){var e=this.getMonth();this.setMonth(0);var t=this.toTimeString().replace(/^.+ \(?([^\)]+)\)?$/,"$1");this.setMonth(e);return t},Z:function(){return-this.getTimezoneOffset()*60},c:function(){return this.format("Y-m-d\\TH:i:sP")},r:function(){return this.toString()},U:function(){return this.getTime()/1e3}}; // Shuffle array function fisher_yates ( my_array ) { var i = my_array.length; if ( i == 0 ) return false; while ( --i ) { var j = Math.floor( Math.random() * ( i + 1 ) ); var tempi = my_array[i]; var tempj = my_array[j]; my_array[i] = tempj; my_array[j] = tempi; } }; // 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 ; }); }; // Exakt som PHPs printf funtion // http://php.net/manual/en/function.sprintf.php /* num = 5; location = 'tree'; format = 'The %2$s contains %1$d monkeys'; console.log(sprintf($format, $num, $location));; */ 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); } // 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"); }; function html_escape(str) { return String(str) .replace(/&/g, '&') .replace(/"/g, '"') .replace(/'/g, ''') .replace(//g, '>'); } function addslashes (str) { // http://kevin.vanzonneveld.net // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + improved by: Ates Goral (http://magnetiq.com) // + improved by: marrtins // + improved by: Nate // + improved by: Onno Marsman // + input by: Denny Wardhana // + improved by: Brett Zamir (http://brett-zamir.me) // + improved by: Oskar Larsson Högfeldt (http://oskar-lh.name/) // * example 1: addslashes("kevin's birthday"); // * returns 1: 'kevin\'s birthday' return (str + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0'); } function stripslashes (str) { // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + improved by: Ates Goral (http://magnetiq.com) // + fixed by: Mick@el // + improved by: marrtins // + bugfixed by: Onno Marsman // + improved by: rezna // + input by: Rick Waldron // + reimplemented by: Brett Zamir (http://brett-zamir.me) // + input by: Brant Messenger (http://www.brantmessenger.com/) // + bugfixed by: Brett Zamir (http://brett-zamir.me) // * example 1: stripslashes('Kevin\'s code'); // * returns 1: "Kevin's code" // * example 2: stripslashes('Kevin\\\'s code'); // * returns 2: "Kevin\'s code" return (str + '').replace(/\\(.?)/g, function (s, n1) { switch (n1) { case '\\': return '\\'; case '0': return '\u0000'; case '': return ''; default: return n1; } }); } // För att parsa en URL t.ex hämta ut querystring 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/make_my_course/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; } /* Euclidean GCD */ function gcd(a,b) {if(b>a) {temp = a; a = b; b = temp} while(b!=0) {m=a%b; a=b; b=m;} return a;} /* Räknar ut aspect_ratio genom dividera bredd och höjd med gcd, retunerar en sträng i det typisk kolon-separerade formatet, t.ex 16:9 */ function get_aspect_ratio(x,y) {c=gcd(x,y); return ""+(x/c)+":"+(y/c)} /** * Conserve aspect ratio of the original region. Useful when shrinking/enlarging * images to fit into a certain area. * * @param {Number} srcWidth Source area width * @param {Number} srcHeight Source area height * @param {Number} maxWidth Fittable area maximum available width * @param {Number} maxHeight Fittable area maximum available height * @return {Object} { width, heigth } */ function calculate_aspect_ratio_fit(srcWidth, srcHeight, maxWidth, maxHeight) { var ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight); return { width: Math.round(srcWidth * ratio), height: Math.round(srcHeight * ratio) }; } // En generell ajax funktion som visar resultat via pnotify. Retunerar true om det gick bra och false vid fel function ajax_save(url, post_data, callback) { ajax_loader(true); $.post(url, post_data) .done(function(data, textStatus, jqXHR) { ajax_loader(false); $.pnotify_remove_all(); // Kollar om eventuellt felmeddelande innnehåller HTML och konvertar det i så fall till text try { var jqXHR_responseText = $(jqXHR.responseText).text(); } catch(err) { var jqXHR_responseText = jqXHR.responseText; } // Testar om det går att parsa det retunerade datat try { data = $.parseJSON(data); } catch(err) { var data = { status: "failed", message: err + '\n' + jqXHR_responseText }; }; switch(data.status) { case "success": // Allt gick bra var pnotify_options = { title: "Sparat", text: "Ändringarna är sparade" }; $.pnotify( pnotify_options ); callback(data); break; default: // Någonting har gått snett. Visar felmeddelande var pnotify_options = { title: "Error", text: "Ett fel inträffade" + "

" + data.message + "

Försök igen eller kontakta oss för support. support@xpectum.se

", type: "error", hide: false }; $.pnotify( pnotify_options ); var post_data = { subject: 'Make My Course - Felmeddelande', body: nl2br('

' + pnotify_options.title + '

Användare: ' + JSON.stringify(user, null, 2) + '

Kurs: ' + course.course_id + ': ' + course.name + '

' + JSON.stringify(pnotify_options, null, 2) + jqXHR_responseText + '

'), from: 'support@makemycourse.com', to: 'peter@xpectum.se' }; //$.post('ajax.log-errors.php', post_data) return false; } }) .fail(function(jqXHR, textStatus, errorThrown) { ajax_loader(false); var pnotify_options = { title: "Ett fel inträffade", type: "error", hide: false }; switch(jqXHR.status) { case 0: pnotify_options.text = "Kunde inte ansluta. Kontrollera din internetanslutning. " + "Försök igen eller kontakta oss för support. support@xpectum.se" + $(jqXHR.responseText).text(); break; case 404: pnotify_options.text = "Sidan hittades inte [404]. " + "Försök igen eller kontakta oss för support. support@xpectum.se" + $(jqXHR.responseText).text(); break; case 500: pnotify_options.text = "Internal Server Error [500]. " + "Försök igen eller kontakta oss för support. support@xpectum.se" + $(jqXHR.responseText).text(); break; default: pnotify_options.text = "Ett okänt fel inträffade. " + "Försök igen eller kontakta oss för support. support@xpectum.se" + $(jqXHR.responseText).text(); } $.pnotify( pnotify_options ); return false; }); } // 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); $.pnotify_remove_all(); // Kollar om eventuellt felmeddelande innnehåller HTML och konvertar det i så fall till text try { var jqXHR_responseText = $(jqXHR.responseText).text(); } catch(err) { var jqXHR_responseText = jqXHR.responseText; } // Testar om det går att parsa det retunerade datat try { data = $.parseJSON(data); } catch(err) { var data = { status: "failed", message: err + '\n' + jqXHR_responseText }; }; switch(data.status) { case "success": // Allt gick bra callback(data); break; default: // Någonting har gått snett. Visar felmeddelande var pnotify_options = { title: "Error", text: "Ett fel inträffade" + "

" + data.message + "

Försök igen eller kontakta oss för support. support@xpectum.se

", type: "error", hide: false }; $.pnotify( pnotify_options ); var post_data = { subject: 'Make My Course - Felmeddelande', body: nl2br('

' + pnotify_options.title + '

Användare: ' + JSON.stringify(user, null, 2) + '

Kurs: ' + course.course_id + ': ' + course.name + '

' + JSON.stringify(pnotify_options, null, 2) + jqXHR_responseText + '

'), from: 'support@makemycourse.com', to: 'peter@xpectum.se' }; //$.post('ajax.log-errors.php', post_data) return false; } }) .fail(function(jqXHR, textStatus, errorThrown) { ajax_loader(false); var pnotify_options = { title: "Ett fel inträffade", type: "error", hide: false }; switch(jqXHR.status) { case 0: pnotify_options.text = "Kunde inte ansluta. Kontrollera din internetanslutning. " + "Försök igen eller kontakta oss för support. support@xpectum.se" + $(jqXHR.responseText).text(); break; case 404: pnotify_options.text = "Sidan hittades inte [404]. " + "Försök igen eller kontakta oss för support. support@xpectum.se" + $(jqXHR.responseText).text(); break; case 500: pnotify_options.text = "Internal Server Error [500]. " + "Försök igen eller kontakta oss för support. support@xpectum.se" + $(jqXHR.responseText).text(); break; default: pnotify_options.text = "Ett okänt fel inträffade. " + "Försök igen eller kontakta oss för support. support@xpectum.se" + $(jqXHR.responseText).text(); } $.pnotify( pnotify_options ); return false; }); } // Exporterar bilderna på sidan function export_images(elements, callback) { // För att exportera bilden i 2x storlek: // $(element).cropit('exportZoom', 2); // Exporeter en bild var deferred = $.Deferred(); function export_image(elements, callback, i) { var element = elements[i]; // Hämtar filnamnet och kollar om det finns någon bild inlagd var file_name_original = $(element).attr('data-file_name_original'); // console.log( file_name_original ); // console.log( $(element).find('.existing-image') ); // console.log( $(element).find('.existing-image').length ); // console.log( file_name_original != undefined ); // console.log( file_name_original != '' ); if( file_name_original != undefined && file_name_original != '' && $(element).find('.existing-image').length == 0 ) { var file_type = $(element).attr('data-file_type') // Exporterar var imageData = $(element).cropit('export', { type: file_type, quality: 1, originalSize: true }); // Hämtar bildens mått var img_width = $(element).attr('data-width'); var img_height = $(element).attr('data-height'); var post_data = { image_data: imageData, file_type: file_type, file_name_original: file_name_original, img_width: img_width, img_height: img_height }; ajax_load('js/plugins/cropit/ajax.export-image.php', post_data, function(data) { var file_info = data.file_info; // Uppdaterar nödvändiga attribut if( $(element).attr("data-file_id") == undefined ) { $(element).attr("data-file_id", "-1"); // Ny bild } $(element).attr("data-file_name", file_info["basename"]); $(element).attr("data-file_name_original", file_info["filename_original"]); $(element).attr("data-copyright", file_info["copyright"]); $(element).attr("data-description", file_info["description"]); // Lägger till json-information om bilden för säkerhet skull, kan kanske vara bra att ha. $(element).attr('file_info', JSON.stringify(file_info)); // Öppnar den exporterade bilden i ny flik (för utveckling) // window.open(imageData); if (i + 1 < elements.length) { callback('"' + file_name_original + '" på position ' + i + ' exporterad.'); export_image(elements, callback, i + 1); } else { if (callback) { callback('"' + file_name_original + '" på position ' + i + ' exporterad.'); } deferred.resolve(); } }); } else { //Fanns ingen bild inlagd, fortsätter spara eventuellt övriga bilder if (i + 1 < elements.length) { callback('Finns ingen bild på position ' + i); export_image(elements, callback, i + 1); } else { if (callback) { callback('Finns ingen bild på position ' + i); } deferred.resolve(); } } } export_image(elements, callback, 0); return deferred; } function delete_files(){ var deferred = $.Deferred(); if (fine_uploader.s3Uploader == '') { deferred.resolve(); } else { // Kollar om det finns några filer som ska tas bort var deleted_files = $('#page_contents #attached_files').attr('data-deleted_files') if ( deleted_files != undefined ){ var deleted_files = $.parseJSON(deleted_files); fine_uploader.s3Uploader._options.callbacks.onDeleteComplete = function(id, xhr, isError) { //console.log( 'onDeleteComplete: ' + id ); // console.log( id ); // console.log( JSON.stringify(xhr, null, 2)); // console.log( isError ); // if(!isError){ // } //fine_uploader.enable_close_button(); } $.each(deleted_files, function(key, deleted_file) { fine_uploader.s3Uploader.deleteFile(deleted_file.id); }); $('#page_contents #attached_files').attr('data-deleted_files', ''); fine_uploader.update_attached_files(); deferred.resolve(); } else { deferred.resolve(); } } return deferred; } function export_files() { var deferred = $.Deferred(); if (fine_uploader.s3Uploader == '') { deferred.resolve(); } else { // Kollar om fine_uploader är initierad var files_for_upload = fine_uploader.s3Uploader.getUploads({ status: qq.status.SUBMITTED }); // Kollar om det finns några filer som ska laddas upp if (files_for_upload.length == 0) { deferred.resolve(); } else { fine_uploader.s3Uploader._options.callbacks.onAllComplete = function(succeeded, failed) { if (failed.length > 0) { //alert("Error: Some files were not uploaded"); var pnotify_options = { title: "Ett fel inträffade", text: "

" +i18next.t('files:messages.uploadFailed') + "

", type: "error", hide: false }; $.pnotify( pnotify_options ); deferred.fail(); } else { if (succeeded.length > 0 ) { //alert("Success!"); } fine_uploader.update_attached_files(); deferred.resolve(); } for (var i = 0; i < succeeded.length; i++) { //console.log( succeeded[i] + ' : ' + fine_uploader.s3Uploader.getName(succeeded[i] ) ); $('#s3-uploader .qq-file-id-' + succeeded[i] + ' span').removeClass('qq-editable'); fine_uploader.set_delete_button(succeeded[i]); } } fine_uploader.s3Uploader.uploadStoredFiles(); } } return deferred; } function save_page_contents(page_id) { //clear_curtain(); ajax_loader(true); // Kollar om det finns några filer som ska tas bort och gör i så fall det var delete_files_done = delete_files(); $.when(delete_files_done).done(function() { // Kollar om det finns några filer som ska laddas upp och gör i så fall det var export_files_done = export_files(); $.when(export_files_done).done(function() { // Kollar om sidan innehåller några bilder och exporterar dom först innan sparning var $image_elements = $('.shell_content #page_contents .image-editor'); if( $image_elements.length > 0 ) { var d1 = export_images($image_elements, function(data) { // Skriver ut callback för debug //console.log(data); }); // Alla bilder är exporterade. Sparar. $.when(d1).done(function() { // Sparar save_page_contents_and_json(page_id); }); } else { // Annars sparar som vanligt save_page_contents_and_json(page_id); } }); }); } function save_page_contents_and_json(page_id) { // Datat var data = new Object(); // Innehållet i jsonformat var page_contents = ""; page_contents = $(".shell_content #page_contents .page_content"); var json_page_contents = []; // Innehållet i html var html = []; // Filer var file_name = ""; var file_full_path = ""; var file_id = ""; var file_name_original = ""; var copyright = ""; var description = ""; var type = ""; var page_has_files = false; // Om innehållet som sparas ska escapas var escape_content = true; var editor_content = { "semantics": "", "css": "", "js": "", "facit": "", "settings": "" }; var counter = 1; remove_files_from_db = false; $.each(page_contents, function(content_key, content) { switch($(content).attr("data-type")) { case "image": file_name = ( $(content).attr("data-file_name") != undefined ? $(content).attr("data-file_name") : "" ); element_id = $(content).attr("id"); // Sparar undar information om bilden file = { element_id: element_id, file_id: "", file_name: "", file_name_original: "", copyright: "", description: "", type: "image", classes: "" }; if(file_name != "") { page_has_files = true; // Bildens hela sökväg file_info = get_extension(file_name); file_course_path = "../../../kurser/"; file_full_path = file_course_path + file_slug["file_slug"] + file_name; file_2x_full_path = file_course_path + file_slug["file_slug"] + file_info.name + '@2x.' + file_info.extension; //file_id = file_id = ( $(content).attr("data-file_id") != undefined ? $(content).attr("data-file_id") : -1 ); file_id = file_id = $(content).attr("data-file_id"); file_name_original = $(content).attr("data-file_name_original"); copyright = $(content).attr("data-copyright"); description = $(content).attr("data-description"); classes = ( $(content).attr("data-classes") != undefined ? $(content).attr("data-classes") : "" ); // HTML // Lägg till klasserna från stilarna html.push('
'); file.element_id = element_id; file.file_id = file_id; file.file_name = file_name; file.file_name_original = file_name_original; file.copyright = copyright; file.description = description; file.classes = classes; } json_page_contents.push ( { file: file } ); break; case "text": text_id = '0' + $(content).attr('data-id'); text_object = {}; caption = ''; data_caption = ''; if ($(content).text() != '') { html_text = tidy_html5($(content).html(), tidy_html5_options); $(content).html(html_text); } else { html_text = $(content).html(); } if($('#text-caption-' + text_id).length) { caption = $('#text-caption-' + text_id).val(); data_caption = ' data-caption="' + caption + '"'; text_object = { text: html_text, caption: caption }; } else { text_object = { text: html_text }; } json_page_contents.push ( text_object ); // HTML html_content = parse_readmore(html_text); html.push("
" + html_content + "
"); break; case "super_page": escape_content = false; // JSON.stringify(); id_suffix = $(this).find(".editor").attr("data-id_suffix"); // Innehållet i varje editor-tab editor_content[id_suffix] = editors[id_suffix].getSession().getValue(); // Kollar om det är sista editorn, då läggs hela strängen in i arrayen if(content_key == page_contents.length - 1) { json_page_contents.push ( editor_content ); } // HTML switch(id_suffix) { case "css": html_content = '' + "\n\n"; break; case "semantics": html_content = editor_content['semantics'] + "\n\n"; break; case "js": html_content = '' + "\n\n"; break; default: html_content = ''; break; } html.push("
" + html_content + "
"); //html.push( html_content ); break; case "video": // json_page_content.push ( { video: file_name } ); var video_id = $(content).attr('data-id'); var video_src = $(content).find('#video_src' + video_id).val(); if(video_src != "") { video = { element_id: $(content).attr('id'), video_src: video_src, video_provider: $(content).attr('data-video_provider'), copyright: "" , //$(content).attr("data-copyright"), width: $(content).attr('data-width'), height: $(content).attr('data-height'), header: $(content).find('#header' + video_id).val(), description: $(content).find('#description' + video_id).html(), }; json_page_contents.push ( { video: video } ); // HTML video_description = parse_readmore(video.description); html.push("
" + video_choose.get_video_provider_html(video.video_provider, video.video_src, video.width, video.height, false, video.header, video_description) + "
"); } break; case "evaluation": var evaluation = $(content).find('dl').attr('data-json'); var evaluation_json = $.parseJSON(evaluation); json_page_contents.push ( { evaluation: evaluation_json } ); // HTML html.push("
" + $(content).html() + "
"); break; case "freetext_answer": json_page_contents.push ( { freetext_answer: "" } ); html_content = $(content).html(); html.push("

"); break; case "freetext_solution": json_page_contents.push ( { freetext_solution: $(content).find('.text').html() } ); // HTML html_content = parse_readmore( $(content).find('.text').html() ); html.push("

" + html_content + "
"); break; case "questions": json_page_contents.push ( { "questions" : questions_course.pages[current_page_key].questions } ); html.push ('

'); break; case "jeopardy": json_page_contents.push ( { "jeopardy" : jeopardy_course.pages[current_page_key].jeopardy } ); html.push ('
'); break; case "true_or_false": json_page_contents.push ( { "true_or_false" : true_or_false_course.pages[current_page_key].true_or_false } ); html.push ('
'); break; case "gallup_questions": json_page_contents.push ( { "gallup_questions" : questions_course.pages[current_page_key].questions } ); html.push ('
'); break; // #tobbe_edit case "fritext_fraga_2017": question_id = '0' + $(content).attr('data-id'); question_object = {}; comment_id = '0' + (parseInt($(content).attr('data-id'))+1);//used to display comment of a question question_object = { fritext_fraga_2017: $(content).html(), comment: $('#content_'+comment_id+'.comment').html() }; json_page_contents.push ( question_object ); // HTML html_content = $(content).html(); // Kollar om frågan har någon kommentar var comment = ""; if(!$.isEmptyObject(question_object.comment) && question_object.comment != '') { comment = '

' + i18next.t("fritext_fraga:comment") + ':

' + question_object.comment + '
'; } html.push('
' + html_content + '
\
\ \
'); break; // #tobbe_edit case "word_match": text_id = '0' + $(content).attr('data-id'); text_object = {}; text_object = { word_match: $(content).html() }; json_page_contents.push ( text_object ); // HTML html_content = $(content).html(); html.push("
"); html.push("
" + html_content + "
"); html.push(""); html.push("
"); break; // #tobbe_edit case "hotspots": page_has_files = true; remove_files_from_db = true; question_id = '0' + $(content).attr('data-id'); question_object = {}; question_object = { hotspots: $(content).html() }; json_page_contents.push ( question_object ); bg_img_file_object = {}; bg_img_file_object = { "file": { "file_name": $(content).find('#active_bg').attr('data-bg-file-name'), "file_name_original": $(content).find('#active_bg').attr('data-original-bg-file-name'), "element_id": "", "file_id": -1, "copyright": "", "description": "", "type": "image", "classes": "" } } json_page_contents.push ( bg_img_file_object ); var images = $(content).find('.hot_spot'); $(images).each(function(number) { img_files_object = { "file": { "file_name": $(this).attr('data-file-name'), "file_name_original": $(this).attr('data-original-file-name'), "element_id": "", "file_id": -1, "copyright": "", "description": "", "type": "image", "classes": "" } } json_page_contents.push ( img_files_object ); }); // HTML html_content = $(content).html(); html.push("
" + html_content + "
"); break; // #tobbe_edit case "sound": page_has_files = true; remove_files_from_db = true; question_id = '0' + $(content).attr('data-id'); question_object = {}; question_object = { sound: $(content).html() }; json_page_contents.push ( question_object ); var audio_files = $(content).find('.has_audio_file'); $(audio_files).each(function(number) { audio_files_object = { "file": { "file_name": $(this).attr('data-file-name'), "file_name_original": $(this).attr('data-original-file-name'), "element_id": "", "file_id": -1, "copyright": "", "description": "", "type": "audio", "classes": "" } } json_page_contents.push ( audio_files_object ); }); // HTML html_content = $(content).html(); html.push("
" + html_content + "
"); break; // #tobbe_edit case "gen_sound": remove_files_from_db = true; if ($('#gen_sound_url').attr('src') != '') { question_id = '0' + $(content).attr('data-id'); question_object = {}; question_object = { gen_sound: $(content).html() }; json_page_contents.push ( question_object ); page_has_files = true; audio_file_object = {}; audio_file_object = { "file": { "file_name": $(content).find('.gen_sound_result_container').attr('data-file-name'), "file_name_original": $(content).find('.gen_sound_result_container').attr('data-original-file-name'), "element_id": "", "file_id": -1, "copyright": "", "description": "", "type": "audio", "classes": "" } } json_page_contents.push ( audio_file_object ); // HTML html_content = $(content).html(); html.push(""); html.push("
" + html_content + "
"); } break; // #tobbe_edit case "questions_sound": remove_files_from_db = true; if ($('#questions_sound_url').attr('src') != '') { question_id = '0' + $(content).attr('data-id'); question_object = {}; question_object = { questions_sound: $(content).html() }; json_page_contents.push ( question_object ); page_has_files = true; audio_file_object = {}; audio_file_object = { "file": { "file_name": $(content).find('.questions_sound_container').attr('data-file-name'), "file_name_original": $(content).find('.questions_sound_container').attr('data-original-file-name'), "element_id": "", "file_id": -1, "copyright": "", "description": "", "type": "audio", "classes": "" } } json_page_contents.push ( audio_file_object ); // HTML html_content = $(content).html(); html.push(""); html.push("
" + html_content + "
"); } break; case "flashcards": remove_files_from_db = true; // Since the whole html content is saved for some reason (lots of excessive html-code), remove the div that show the max-length for entered text, "
" + html_content + "
"); break; case "attached_files": var attached_files = $('#page_contents #attached_files').attr('data-attached_files'); json_page_contents.push( { attached_files: $.parseJSON(attached_files) } ); html.push("
"); break; case "embed": escape_content = false; embed_id = '0' + $(content).attr('data-id'); if ($(content).text() != '') { html_embed = tidy_html5($(content).html(), tidy_html5_options); $(content).html(html_embed); } else { html_embed = $(content).html(); } embed_object = { embed: html_embed }; json_page_contents.push ( embed_object ); // HTML html_content = html_embed; html.push("
" + html_content + "
"); break; case "wordlist": // Save the chosen dictionary / wordlist for the page wordlist_object = { "wordlist": { "src": $('#choose_dictionary').val() } }; json_page_contents.push ( wordlist_object ); } // Tar bort eventeulla font-family förutom för supermallen if($(content).attr("data-type") != "super_page"){ if(json_page_contents[counter-1] != undefined) { // Tar bort eventeulla font-family i JSON som lagts till av editorn (inklistrad text?) var regexp_data_json = /(<[a-z]+ style=\\"font-family:.+?">)(.*?)(<\/[a-z]+>)/gim temp_data_json_string = JSON.stringify(json_page_contents[counter-1]); temp_data_json_string = temp_data_json_string.replace(regexp_data_json, '$2'); json_page_contents[counter-1] = JSON.parse(temp_data_json_string); } if(html[counter-1] != undefined) { // Tar bort eventeulla font-family i HTML som lagts till av editorn (inklistrad text?) var regexp_data_html = /(<[a-z]+ style="font-family:.+?">)(.*?)(<\/[a-z]+>)/gim html[counter-1] = html[counter-1].replace(regexp_data_html, '$2'); } } counter++; }); data.page_contents = json_page_contents; // JSON data_json = JSON.stringify(data); // HTML //html = "
" + html.join("") + "
"; html = html.join(""); var post_data = { page_id: page_id, data: data_json, html: html, page_has_files: page_has_files, escape_content: escape_content, remove_files_from_db: remove_files_from_db }; ajax_save("ajax.save_page_content.php", post_data, function(page_contents) { if(page_has_files) { update_page_contents_file_data(page_contents); } edit_course_structure.update_page_changed_metadata($('#pages_list ol li[data-id="' + page_id + '"')); ajax_loader(false); }); ajax_loader(false); } function parse_readmore(html) { // Kollar om det finns en "läs mer"-tag readmore_tag = ""; // Ersätter read more
med en kommentar html = html.replace('
', readmore_tag); html = html.replace('
', readmore_tag); readmore_pos = html.indexOf(readmore_tag); if(readmore_pos > -1) { html = html.replace(readmore_tag, '

'); html += "

"; } return html; } // Uppdaterar info för sparade bilderna function update_page_contents_file_data(page_contents) { var file = ""; $.each(page_contents.data.page_contents, function(content_key, content) { if(!$.isEmptyObject(content.file)) { file = content.file; if(file.file_id != "") { var element = $("#" + file.element_id); var element_cropit_preview = element.find('.cropit-preview'); var element_cropit_preview_image = element.find('.cropit-preview-image'); // Uppdaterar bilddatat och bilder bara om det är en ny bild if (element_cropit_preview.find('.existing-image').length == 0) { // Uppdaterad file-id från databasen element.attr("data-file_id", file.file_id) var file_info = get_extension( file.file_name ); // Lägger in den sparade bilden från servern element_cropit_preview.prepend('') // Återställer cropit element_cropit_preview.find('.cropit-preview').removeClass('cropit-image-loaded'); element_cropit_preview_image.attr('src', ''); element_cropit_preview_image.attr('style', 'transform-origin: left top 0px; will-change: transform;'); element.find('.cropit-tools .cropit-image-input').val(''); // Gömmer zoom och rotate eftersom det inte går att göra på en sparad bild show_hide_tools(element, 'hide', '.rotate-ccw', '.cropit-image-zoom-input'); } } } }); } // Skapar en random querystring för att motverka cachning function nocache_querystring() { return "?" + (new Date().getTime()); } // Tillåtna tecken i textfält, körs t.ex när man klistrar in text function sanitize_string(text, remove_newline) { //console.log( 'sanitize_string()' ); // Ersätter skumma ÅÄÖ när man kopierar från t.ex PDF samt ersätter "riktiga" bindestreck med standard minus-tecknet search_chr = ["‐", "А", "Å", "Ä", "Ö", "É", "Á", "Ü", "Í", "Ó", "Ú", "Ý", "а", "å", "ä", "ö", "é", "á", "ü", "í", "ó", "ú", "ý"]; replace_chr = ["-", "A", "Å", "Ä", "Ö", "É", "Á", "Ü", "Í", "Ó", "Ú", "Ý", "a", "å", "ä", "ö", "é", "á", "ü", "í", "ó", "ú", "ý"]; text = str_replace(search_chr, replace_chr, text); // Ersätter alla enterslag och tabbar med \n text = text.replace(/[\t\n\r]/g, '\n'); text = $.trim(text); // Tar bort övriga ej tillåtna tecken text = text.replace(/[^\wåäöøæðþæœçüëïÿéáéíóúýèàìòùêâîôû\d\s-\+"'`´\\\/!?<>:;,.()\[\]{}#=$€£¢¥*@%&§«»\n]/ig, ""); if( remove_newline ) { text = text.replace(/[\n]/ig, ""); } return text; } // Tillåtna tecken i sidnamn och taggar function validate_keystroke_for_input(e) { //console.log( 'validate_keystroke_for_input()' ); // Tangentens värde som sträng keystroke = String.fromCharCode(e.keyCode); //if(/[\wåäöøæü/.+-/!@%&()?=<>\d\s\b]/ig.test(keystroke)) { if( /[\wåäöøæðþæœçüëïÿéáéíóúýèàìòùêâîôû\d\s-\+"'`´\\\/!?<>:;,.()\[\]{}#=$€£¢¥*@%&§«»]/ig.test(keystroke) ) { return true; } else { var pnotify_options = { title: "Ett fel inträffade", text: "

Ej giltigt tecken: " + keystroke + "

", type: "error", hide: true }; $.pnotify( pnotify_options ); return false; } } function strip_formatting(elem, e, do_sanitize_string, paste_max_length, element_max_length, remove_newline) { if(elem.attr('data-max-length') !== undefined) { paste_max_length = elem.attr('data-max-length'); element_max_length = elem.attr('data-max-length'); } var _onPaste_StripFormatting_IEPaste = false; var text = ""; if (e.originalEvent && e.originalEvent.clipboardData && e.originalEvent.clipboardData.getData) { e.preventDefault(); text = e.originalEvent.clipboardData.getData('text/plain'); //text = sanitize_string(text); //window.document.execCommand('insertText', false, text); } else if (e.clipboardData && e.clipboardData.getData) { e.preventDefault(); text = e.clipboardData.getData('text/plain'); //text = sanitize_string(text); //window.document.execCommand('insertText', false, text); } else if (window.clipboardData && window.clipboardData.getData) { // Stop stack overflow if (!_onPaste_StripFormatting_IEPaste) { _onPaste_StripFormatting_IEPaste = true; e.preventDefault(); window.document.execCommand('ms-pasteTextOnly', false); } _onPaste_StripFormatting_IEPaste = false; } if( do_sanitize_string ) { text = sanitize_string(text, remove_newline); } // Kollar om det finns någon begränsning på hur mycket man kan klistra in på en gång if( paste_max_length != -1 && paste_max_length != '') { text = text.substring(0, paste_max_length); } // Kollar om det finns någon begränsning på själva elementet som man klistrar in i, // anpassar i så fall den inklistrade texten så att man inte överskrider maxlängden if( element_max_length != -1 && element_max_length != '' ) { if( elem.text().length < element_max_length ) { text = text.substring(0, paste_max_length - elem.text().length); window.document.execCommand('insertText', false, text); } } else { window.document.execCommand('insertText', false, text); } } // Städar upp en sträng när man klistrar in text /************************************************************ $element = vilket elemet som ska kollas som man klistrar in i. do_sanitize_string = Tar bort onödiga/ej tillåtna tecken och formaterar om vissa tecken. paste_max_length = Hur mycket man kan klistra in på en gång. element_max_length = Om det finns någon begränsning hur mycket text det får vara i elementet. remove_newline = Ta bort newline / carriage return ************************************************************/ function sanitize_and_strip_formatting_on_paste($element, do_sanitize_string, paste_max_length, element_max_length, remove_newline, insert_paragraph_on_empty) { $element.off('paste').on('paste', function(e) { insert_paragraph_on_empty = typeof insert_paragraph_on_empty !== 'undefined' ? insert_paragraph_on_empty : true; if(insert_paragraph_on_empty) { if($element.prop('nodeName') != "INPUT"){ // Fungerar inte på input-element, bara på "content editable" contenteditable_insert_paragraph($(this)); } } $(this).removeClass('required_missing'); strip_formatting($(this), e, do_sanitize_string, paste_max_length, element_max_length, remove_newline); }); } // Lägger alltid till en p-tagg ifall fältet är tomt och flyttar cursorn mellan taggarna. Så att det blir konsekvent och texten blir uppdelad i paragrafer. function contenteditable_insert_paragraph($element) { content_lenght = $element.html().length; if(content_lenght == 0){ $element.html("

"); $element.setCaret(0); } } // Kontrollerar när man skriver och lägger dit

ifall det är borttaget function contenteditable_insert_paragraph_keyup($element) { //$(".text").keypress(function (e) { $element.keypress(function (e) { // Förutom när man tycker tab för att gå till ett annat textfält if (e.keyCode != 9 ) { contenteditable_insert_paragraph($(this)); } }); } // Kollar om man skrivit in någon text annars ta bort allting så att placeholdern syns. function contenteditable_remove_empty_onblur($element) { //console.log( $element ); //$(".text").blur(function() { $element.blur(function() { $html = $(this).html(); /* console.log( $html == '

' ); console.log( $html == '


' ); console.log( $html == '

' ); console.log( $html == '
' ); console.log( $(this).text() == '' ); console.log( $(this).text() == '​' ); */ // OBS!! Innehåller en zero width character ​ T.ex '

' // Den är ditlagd med contenteditable_insert_paragraph() för att man ska kunna sätta cursorn mellan p-taggarna //if ( $html == '

' || $html == '


' || $html == '

' || $html == '
' || $(this).text() == '' || $(this).text() == '​' ) { if ( $(this).text() == '' || $(this).text() == '​' ) { $(this).html(''); } else { if ( $html.indexOf("​") > 0 ) { $(this).html( $html.replace(/​/g, '') ); } } }); } // Sätter alla inställningar för contenteditable textfäld och input fält. Dvs giltiga tecken, ta bort skräp, rensa om den inte har någon innehåll osv. function set_contenteditable_and_input_text_settings($text_elements, $input_elements){ if($text_elements != ''){ //contenteditable_insert_paragraph($text_elements); contenteditable_insert_paragraph_keyup($text_elements); contenteditable_remove_empty_onblur($text_elements); sanitize_and_strip_formatting_on_paste($text_elements, true, -1, -1, false, true); } if($input_elements != ''){ sanitize_and_strip_formatting_on_paste($input_elements, true, -1, -1, false, false); } var $text_and_input_elements = $.merge( $.merge( [], $text_elements ), $input_elements ); $($text_and_input_elements).keypress(function(e) { // Tangentens värde som sträng $(this).removeClass('required_missing'); return validate_keystroke_for_input(e); }); if($text_elements != ''){ set_contenteditable_max_length ($text_elements) } } // Sets max length on contenteditable and shows number of characters left function set_contenteditable_max_length ($text_elements){ $text_elements.off('keydown').keydown(function(e){ var max_length = $(this).attr('data-max-length'); if(max_length !== undefined) { max_length = Number(max_length); var text = $.trim($(this).text()); var max_length_element = $(this).next('.max-length'); if(max_length_element.length == 0) { $(this).after(''); max_length_element = $(this).next('.max-length'); max_length_element.fadeIn('fast') } else { max_length_element.html((max_length - text.length)); } if (text.length >= max_length) { max_length_element.addClass('error'); } else { max_length_element.removeClass('error') } // Kontrollerar maxlängden //List of keycodes of printable characters from: //http://stackoverflow.com/questions/12467240/determine-if-javascript-e-keycode-is-a-printable-non-control-character var printable = (e.keyCode > 47 && e.keyCode < 58) || // number keys e.keyCode == 32 || e.keyCode == 13 || // spacebar & return key(s) (if you want to allow carriage returns) (e.keyCode > 64 && e.keyCode < 91) || // letter keys (e.keyCode > 95 && e.keyCode < 112) || // numpad keys (e.keyCode > 185 && e.keyCode < 193) || // ;=,-./` (in order) (e.keyCode > 218 && e.keyCode < 223); // [\]' (in order) //console.log( e.keyCode + ' : ' + printable); if (printable) { if (text.length >= max_length) { e.preventDefault(); return false; } } } }); } /************************************************************** JavaScript equivalent to PHP's str_replace http://locutus.io/php/strings/str_replace/ Examples: # code expected result 1: str_replace(' ', '.', 'Kevin van Zonneveld') 'Kevin.van.Zonneveld' 2: str_replace(['{name}', 'l'], ['hello', 'm'], '{name}, lars') 'hemmo, mars' 3: str_replace(Array('S','F'),'x','ASDFASDF') 'AxDxAxDx' 4: var countObj = {} str_replace(['A','D'], ['x','y'], 'ASDFASDF', countObj) var $result = countObj.value 4 **************************************************************/ function str_replace (search, replace, subject, countObj) { var i = 0 var j = 0 var temp = '' var repl = '' var sl = 0 var fl = 0 var f = [].concat(search) var r = [].concat(replace) var s = subject var ra = Object.prototype.toString.call(r) === '[object Array]' var sa = Object.prototype.toString.call(s) === '[object Array]' s = [].concat(s) var $global = (typeof window !== 'undefined' ? window : global) $global.$locutus = $global.$locutus || {} var $locutus = $global.$locutus $locutus.php = $locutus.php || {} if (typeof (search) === 'object' && typeof (replace) === 'string') { temp = replace replace = [] for (i = 0; i < search.length; i += 1) { replace[i] = temp } temp = '' r = [].concat(replace) ra = Object.prototype.toString.call(r) === '[object Array]' } if (typeof countObj !== 'undefined') { countObj.value = 0 } for (i = 0, sl = s.length; i < sl; i++) { if (s[i] === '') { continue } for (j = 0, fl = f.length; j < fl; j++) { temp = s[i] + '' repl = ra ? (r[j] !== undefined ? r[j] : '') : r[0] s[i] = (temp).split(f[j]).join(repl) if (typeof countObj !== 'undefined') { countObj.value += ((temp.split(f[j])).length - 1) } } } return sa ? s : s[0] } // Kollar om no_menus är true och fixar så att innehållet tar upp hela sidan url = parse_and_get_url(window.location); if( url.query.no_menus == "true" ) { $('.shell_content').css('width', '100%'); } // Returns a function, that, as long as it continues to be invoked, will not // be triggered. The function will be called after it stops being called for // N milliseconds. If `immediate` is passed, trigger the function on the // leading edge, instead of the trailing. function debounce(func, wait, immediate) { var timeout; return function() { var context = this, args = arguments; var later = function() { timeout = null; if (!immediate) func.apply(context, args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; }; /** * Checks if a file exists */ /*function is_file(url, callback) { var file_exists = false; $.ajax({ url: + url, dataType:'HEAD', error: function(data) { callback(file_exists); }, success: function(data) { file_exists = true; callback(file_exists); } }); }*/ // 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; } /* // Laddar js för en sida sequentiellt. Kör callback när ett script laddats och när allt är klart. Saknar felkontroll. // queue #1 var d1 = load_js_sequential_for_page(["script1.js, script2.js"], function(data) { // Optional - Executed each time a script has loaded }); // queue #2 - optional var d2 = load_js_sequential_for_page(["script3.js"], function(data) { // Optional - Executed each time a script has loaded }); // // optional, trigger a callback when all queues are complete $.when(d1, d2).done(function() { // Executed when the entire list of scripts has been loaded }); */ /*function load_js_sequential_for_page(js_urls, callback) { if(!Array.isArray(js_urls)) { js_urls = js_urls.split(",") } var deferred = $.Deferred(); function load_js(js_urls, callback, i) { $.ajax({ url: js_urls[i], dataType: "script", cache: true, success: function() { if (i + 1 < js_urls.length) { callback(js_urls[i]); load_js(js_urls, callback, i + 1); } else { if (callback) { callback(js_urls[i]); } deferred.resolve(); } } }); } load_js(js_urls, callback, 0); return deferred; }*/ // Laddar in eventuella JS-filer function load_js_for_page_via_getscript(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, nocache) { if (!$.isEmptyObject(css_urls)) { var urls = css_urls.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') ); }); // Kollar vilka stylesheet som inte redan finns och behöver ladds var urls_to_load = []; $.each(urls, function (url_key, url) { if( $.inArray(url, css_urls_existing) == -1 ) { urls_to_load.push(url); } }); if (typeof nocache=='undefined') nocache=false; // default don't refresh $.when.apply($, $.map(urls_to_load, function(url){ if (nocache) url += '?_ts=' + new Date().getTime(); // refresh? return $.get(url, function(){ $('', {rel:'stylesheet', type:'text/css', 'href':url, class:'page_styles'}).appendTo('head'); }); }) ).then(function(){ if (typeof callback=='function') callback(); }); } else { 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(); } // 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; } // Initierar cropit function init_cropit(element) { var file_type = ''; var file_name = ''; var img_width = 0; var img_height = 0; //var file_info = ''; element.cropit({ minZoom: 'fit', maxZoom: 1, smallImage: 'allow', initialZoom: 'fit', freeMove: false, onFileChange: function() { ajax_loader(true); }, onFileReaderError: function() { ajax_loader(false); }, onImageLoading: function() { // Tar bort bakgrundsbilden i bild-placeholdern när bilden laddas in $(element).addClass('existing-image'); // Återställer till default-värdensa $(element).cropit('minZoom', 1); $(element).cropit('maxZoom', 1); // Låser bakgrunden med Curtain //curtain($('.shell_content')); // Kollar om användare har laddat in någon bild tidigare i cropit eller om det finns en befintlig sparad bild. Sparar i så fall undan den ifall man skulle behöva lägga tillbaka den. T.ex om man lägger in en ny bild som är för liten och man svarar nej på frågan om man verkligen vill använda den. if( $(element).find('.existing-image').length != 0 ) { // Finns en befintlig sparad bild $(element).find('.cropit-preview .existing-image').insertAfter( $(element).find('.cropit-preview') ).addClass('hidden'); // Flyttar undan och gömmer den } else { if( $(element).find('.cropit-preview').hasClass('cropit-image-loaded') ) { // Sparar undan bildens position, zoom osv ifall användaren ångrar sig och vill lägga tillbaka bilden if (typeof $(element).attr('data-undo-image') == typeof undefined) { var copy_style = { 'offset' : $(element).cropit('offset'), 'zoom' : $(element).cropit('zoom'), 'style' : $(element).find('.cropit-preview-image').css('transform') }; $(element).attr('data-copy-style', JSON.stringify(copy_style) ); $cropit_preview_image_copy = $(element).find('.cropit-preview-image').clone(); // Klonar elementet $cropit_preview_image_copy.removeClass('cropit-preview-image').addClass('cropit-preview-image-copy') // Ändrar klassen så att man vet att det är en kopia och inte råkar selecta den $cropit_preview_image_copy.insertAfter( $(element).find('.cropit-preview') ).addClass('hidden'); // Flyttar undan och gömmer den } } } }, onImageLoaded: function() { ajax_loader(false); if (typeof $(element).attr('data-undo-image') !== typeof undefined) { // Parsar det sparade värden på bilden som läggs tillbaka var data_copy_style = JSON.parse( $(element).attr('data-copy-style') ); // Sätter zoom och postition $(element).cropit('zoom', data_copy_style.zoom ); $(element).cropit('offset', { x: data_copy_style.offset.x, y: data_copy_style.offset.y }); // Hämtar ut vettiga värden från transform matrisen transform_matrix_values = extract_transform_matrix_values( data_copy_style.style ); // Kollar hur många gånger bilden behöver roteras if( transform_matrix_values != 0 ) { needs_to_rotate_90_times = transform_matrix_values.rotation.degrees / 90; if( needs_to_rotate_90_times < 0 ) { needs_to_rotate_90_times = Math.abs(needs_to_rotate_90_times); for (i = 1; i <= needs_to_rotate_90_times; i++) { $(element).cropit('rotateCCW'); } } else { for (i = 1; i <= needs_to_rotate_90_times; i++) { $(element).cropit('rotateCW'); } } } // Rensar upp bland sparade värden $(element).find('.cropit-image-input').val(''); remove_copies_and_temp_attributes($(element)); } else { // Räknar ut max zoom utifrån hur stor den största retina bilden som ska skapas är var max_zoom_level = (1 / retina_max_multiplier).toFixed(1); $(element).cropit('maxZoom', max_zoom_level); toggle_fit_in_fill_in ("fit_in", $(element)); var cropit_file_info = get_file_info($(element)); $(element).attr('data-cropit_file_info', JSON.stringify( cropit_file_info ) ); // Kollar så att bilden har tillräckling hög upplösning if( cropit_file_info.image_size.width < cropit_file_info.template_size_atx[cropit_file_info.template_size_atx.length-1].size.width && cropit_file_info.image_size.height < cropit_file_info.template_size_atx[cropit_file_info.template_size_atx.length-1].size.height ) { // Skickar upp ett meddelande som frågar om man vill använda bilden fastän den är för liten $("body").append('
\

Ej tillräckligt hög upplösning

\

Upplösningen på bilden är för liten vilket innebär att det kan bli dålig kvalité på högupplösta skärmar. Använd en version av bilden med högre upplösning, minst ' + cropit_file_info.template_size_atx[cropit_file_info.template_size_atx.length-1].size.width + ' x ' + cropit_file_info.template_size_atx[cropit_file_info.template_size_atx.length-1].size.height + ' pixlar.
Bilden du valt är ' + cropit_file_info.image_size.width + ' x ' + cropit_file_info.image_size.height + ' pixlar.

\

Du kommer inte kunna beskära, förstora eller förminska bilden. Vill du ändå fortsätta och använda den här bilden?

\

\ Ja\ Nej\

\
'); add_curtain_popup([$('#image_resolution_question_dialog')]); // Om man svarar "Ja" $("#image_resolution_question_dialog_ok").off('click').click(function() { remove_curtain_popup([$('#image_resolution_question_dialog')]); add_file_data($(element)); remove_copies_and_temp_attributes($(element)); }); // Om man svarar "Nej" dvs den gamla bilden ska läggas tillbaka $("#image_resolution_question_dialog_cancel").off('click').click(function() { remove_curtain_popup([$('#image_resolution_question_dialog')]); // Lägger tillbaka föregående bild beroende om den fanns tidigare i cropit eller om det var en befintlig sparad bild. if( $(element).find('.existing-image').length != 0 ) { // Det finns en tidigare sparad bild $(element).find('.cropit-preview').removeClass('cropit-image-loaded'); $(element).find('.cropit-preview-image').attr('src', ''); $(element).find('.cropit-preview').prepend($(element).find('.existing-image')); $(element).find('.existing-image').removeClass('hidden'); show_hide_tools($(element), 'show', '.image-info', '.rotate-cw', '.rotate-ccw', '.cropit-image-zoom-input', '.image-styles-tools' ); $(element).find('.cropit-image-input').val(''); } else { // Fanns ingen bild sedan tidigare, varken i cropit eller sparat sedan tidigare, återställer allting. $(element).cropit('imageSrc', ''); show_hide_tools($(element), 'hide', '.image-info', '.rotate-cw', '.rotate-ccw', '.cropit-image-zoom-input', '.image-styles-tools' ); $(element).find('.cropit-preview-image').attr('src', ''); $(element).find('.cropit-preview-image-copy').attr('src', ''); $(element).find('.cropit-image-input').val(''); $(element).removeClass('existing-image'); } }); } else { add_file_data($(element)); remove_copies_and_temp_attributes($(element)); } } // Visar verktygen. Visar bara zoom om bilden går att zoom. if( $(element).cropit('isZoomable') ) { show_hide_tools(element, 'show', '.image-info', '.rotate-ccw', '.image-styles-tools', '.cropit-image-zoom-input' ); $('.cropit-tools .fit_in_fill_in').show(); // Borde egenltigen ligga i show_hide_tools men får inte till det set_margin($(element)); } else { show_hide_tools(element, 'show', '.image-info', '.rotate-ccw', '.image-styles-tools' ); show_hide_tools(element, 'hide', '.cropit-image-zoom-input'); $('.cropit-tools .fit_in_fill_in').hide(); // Borde egenltigen ligga i show_hide_tools men får inte till det } } }); var cropit_file_info = get_file_info($(element)); $(element).attr('data-cropit_file_info', JSON.stringify( cropit_file_info ) ); // Tar bort eventuell kopior/backup av befintlig bild som skapats och eventuella attribut function remove_copies_and_temp_attributes (element){ $(element).removeAttr('data-copy-style'); $(element).removeAttr('data-undo-image') $(element).find('.cropit-preview-image-copy').remove(); $(element).find('.existing-image').remove(); $(element).find('.cropit-preview-image-copy').remove(); $(element).removeAttr('data-dragndrop_file_name_original'); } // Lägger till data för filen, filtyp, namn osv function add_file_data (element) { // Hämtar bilddata var file_data = element.cropit('imageSrc'); // Hämtar filtyp file_data = file_data.split(';')[0]; file_type = file_data.split(':')[1]; $(element).attr('data-file_type', file_type); // Hämtar filnamnet (om bilden laddas via filväljaren) file_path = $(element).find('.cropit-image-input').val(); if(file_path !== '') { file_name = file_path.split('\\').pop(); file_name = file_name.split('\/').pop(); } else { file_name = $(element).attr('data-dragndrop_file_name_original'); } $(element).attr('data-file_name_original', file_name); $(element).find('.cropit-tools .image-info').html( '

' + i18next.t("cropit:text.filename") + ':

"' + file_name + '"' ); // Efter att namnet på filen är satt, se till så att filväljaren sätts tillbaka till "file". Så att det fungerar att välja en fil från datorn. $(element).find('.cropit-image-input').attr('type','file').val(); } // Kontrollerar om det redan finns en bild /*var image_exists = false; if($(element).find('.existing-image').length != 0) { image_exists = true; }*/ // Hämtar filnamnet (om bilden dras och släpps) $('.cropit-preview-image-container').on('drop', function(event) { event.preventDefault && event.preventDefault(); ajax_loader(true); var files = event.dataTransfer.files || event.target.files; var file = files[0]; file_name = file.name; $(element).find('.cropit-image-input').val(''); $(element).attr('data-dragndrop_file_name_original', file_name); }); // Roterar medsols $(element).off('click', '.rotate-cw').on('click', '.rotate-cw', function(e) { e.preventDefault(); element.cropit('rotateCW'); }); // Roterar motsols $(element).off('click', '.rotate-ccw').on('click', '.rotate-ccw', function(e) { e.preventDefault(); element.cropit('rotateCCW'); }); $(element).off('click', '.fill_in').on('click', '.fill_in', function() { toggle_fit_in_fill_in('fill_in', $(element)); }); $(element).off('click', '.fit_in').on('click', '.fit_in', function() { toggle_fit_in_fill_in('fit_in', $(element)); }) $(element).find('.cropit-image-zoom-input').on('input', function () { $(element).find('.fit_in_fill_in .tgl-btn').addClass('user_scaled'); }); $(element).find('.fit_in_fill_in .toggle_fit_in_fill_in').change(function() { if( $(this).is(":checked") ) { toggle_fit_in_fill_in('fill_in', $(element)); } else { toggle_fit_in_fill_in('fit_in', $(element)); } }); // Exporterar den beskärda bilden $(element).off('click', '.export').on('click', '.export', function() { export_image($(element)); }); // Events för bilders verktygsfält var image_editor = $(element); var image_tools = $(element).find('.cropit-tools'); var active_image_editor; var active_image_tools; // Visar bildverktygen när man hovrar över bilden // $(image_editor).mouseenter(function() { // $(this).find('.cropit-tools').fadeIn(100); // }); // Gömmer bildverktygen när muspekaren lämnat bilden // $(image_editor).mouseleave(function() { // $(this).find('.cropit-tools').fadeOut(100); // }); // Visar bildverktygen när man trycker på cropit-knappen $(image_editor).on('click', '.cropit-tools-toggle', function() { // Det aktuella verktygsfältet var cropitTools = $(this).closest('.image-editor').find('.cropit-tools'); // Status på verktygsfältet var isVisible = cropitTools.is(':visible'); // Sätter en CSS-klass på knappen för att behålla den synlig isVisible ? $(this).removeClass('active').find('.fa').toggleClass('fa-pencil fa-times') : $(this).addClass('active').find('.fa').toggleClass('fa-times fa-pencil'); // Visar eller döljer verktygsfältet beroende på status isVisible ? cropitTools.fadeOut(100) : cropitTools.fadeIn(100); }); // Grupperar alla verktyg i klassen .cropit-tools if($(element).find('.cropit-tools').length === 0) { $(element).find('.cropit-tool').wrapAll('
'); } // Grupperar vissa verktyg i rader .tool-row // Filväljaren // if($(element).find('.cropit-tools .tool-row .cropit-image-input').length === 0) { // $(element).find('.cropit-tools .cropit-image-input').wrapAll('
'); // } if($(element).find('.cropit-tools .tool-row .file-container').length === 0) { $(element).find('.cropit-tools .file-container').wrapAll('
'); } // Zoom-range-slider if($(element).find('.cropit-tools .tool-row .cropit-image-zoom-input').length === 0) { $(element).find('.cropit-tools .cropit-image-zoom-input').wrapAll('
'); } // Rotera, passa in och fyll ut if($(element).find('.cropit-tools .tool-row .fit_in_fill_in').length === 0) { $(element).find('.cropit-tools .rotate-cw, .cropit-tools .rotate-ccw, .cropit-tools .fit_in_fill_in').wrapAll('
'); } // Övriga $(element).find('.cropit-tools > .cropit-tool').wrapAll('
'); // Info om bilden if( $(element).find('.cropit-tools .image-info').length === 0 ) { var file_name_original = "" if( $(element).attr('data-file_name_original') != undefined ) { file_name_original = '"' + $(element).attr('data-file_name_original') + '"'; } $(element).find('.cropit-tools').append('

' + i18next.t("cropit:text.filename") + ':

' + file_name_original + '
'); } // Bildstilar if($(element).find('.cropit-tools .image-styles-tools').length === 0) { $(element).find('.cropit-tools').append('
'); } // Gömmer verktygen beroende på om det finns en bild sedan förut eller inte if($(element).find('.existing-image').length != 0) { // Finns en sparad bild show_hide_tools(element, 'hide', '.rotate-cw', '.rotate-ccw', '.cropit-image-zoom-input' ); } else { show_hide_tools(element, 'hide', '.image-info', '.rotate-cw', '.rotate-ccw', '.cropit-image-zoom-input', '.image-styles-tools' ); } // Eftersom file input elementen ligger ovanför knappen så läggs "hover"-funktionen till med jquer istället för CSS $(element).find('.cropit-tools .file-container').hover( function() { $( this ).find('button').addClass( 'hover' ); }, function() { $( this ).find('button').removeClass( 'hover' ); } ); // Skriver ut hur stor bilden minst bör vara för att det ska kunna skapas @x storlekar if($(element).find('.cropit-tools .file-container .image_size_info').length === 0) { $(element).find('.cropit-tools .file-container').append( '' + i18next.t('cropit:text.image_size', {widht: cropit_file_info.template_size_atx[cropit_file_info.template_size_atx.length-1].size.width, height: cropit_file_info.template_size_atx[cropit_file_info.template_size_atx.length-1].size.height}) + '' ); } $(element).find('.cropit-tool-library-button').off('click').click(function() { init_media_library($(element)) }); image_styles.init(); $(element).localize(); } // Initierar media biblioteket function init_media_library(element){ // - - - Media Library (användarvy) - - - // $('#media-library').localize(); add_curtain_popup( [$('#media-library')]); open_media_library(element); } function open_media_library(element){ var container = $('#media-library-images'); // Kollar om det redan finns filer laddade, annars läggs dom till if(container.find('img').length === 0){ ajax_loader(true); var files = $.parseJSON( $("#media-library").attr('data-images')); var html = []; var html_root_files = []; var current_directory = ""; html.push('
'); //if(files.length > 0) { // Kollar så att det hittades några filer if(Object.keys(files).length) { $.each(files, function(directory_key, directory) { if (directory_key !== "media_library"){ html.push('

' + directory_key + '

'); } if( typeof directory.files != "undefined" && directory.files !== null ) { $.each(directory.files, function(file_key, file) { //console.log( file ); image_filepath = file.file_path + '/' + file.base_name; //(directory_key != '' ? directory_key + '/' : '') + file.base_name; image_thumbnail_filepath = file.file_path + '/' + file.file_name + '_thumbnail.jpg'; // (directory_key != '' ? directory_key + '/' : '') + file.file_name + '_thumbnail.jpg'; image_thumbnail_at2x_filepath = file.file_path + '/' + file.file_name + '_thumbnail@2x.jpg'; // (directory_key != '' ? directory_key + '/' : '') + file.file_name + '_thumbnail@2x.jpg'; image_html = ''; media_item = '
' + image_html + '
' if (directory_key !== "media_library") { // Lägger alla filer som ligger i rooten längst ned //html.push('
' + file.file_name + '' + file.file_size + '' + new Date(file.file_modification_timestamp * 1000).format(lng_dateformats_js[1] + ' H:i:s') + '
'); html.push(media_item); } else { //html_root_files.push('
' + file.file_name + '' + file.file_size + '' + new Date(file.file_modification_timestamp * 1000).format(lng_dateformats_js[1] + ' H:i:s') + '
'); html_root_files.push(media_item); } }); } }); html = html.concat('
' + html_root_files + '
'); container.fadeIn('fast'); $('#upload-selected-media').hide(); ajax_loader(false); } html.push("
"); container.html( html.join("") ); if(Object.keys(files).length) { container.find('dt[data-status]').nextUntil('dt').hide(); container.find('dt').off('click').click(function() { if ( $(this).attr('data-status') == "closed" ) { set_folders_state($(this), 'open'); } else { set_folders_state($(this), 'closed'); } $(this).nextUntil('dt').slideToggle('fast'); }); } container.localize(); // Remove any missing translations and uses the folder name instead $.each($('#media-library-images dt h3 span'), function(header_key, header_text) { $(header_text).html($(header_text).html().replace('medialib.','')); }) // Väntar tills alla bilderna är laddade on_images_loaded(container, function() { container.fadeIn('fast'); ajax_loader(false); }); } // Sätter vald/klickad bild $('#media-library').find('#upload-selected-media').off('click').click(function(){ if(!$(this).hasClass('disabled')){ var lib_img_url = $('#media-library').find('.media-library-item.item-active').attr('data-url'); /* För att kunna sätta filsökvägen måste man ändra type från "file" till "text". Detta ändras sedan tillbaka efter att namnet och övrig info om filen är satt. Se add_file_data() */ $(element).find('.cropit-image-input').attr('type','text').val(lib_img_url); $(element).cropit('imageSrc', lib_img_url); remove_curtain_popup($('#media-library')); } }); $('#media-library').find('#close-media-library').off('click').click(function(){ remove_curtain_popup($('#media-library')); }); // Stänger fönster och lägger till vald bild $('#media-library').find('.media-library-item').off('click').on('click', function(){ $('#media-library').find('.media-library-item').removeClass('item-active'); $(this).addClass('item-active'); $('#media-library').find('#upload-selected-media').removeClass('disabled'); }); } // Öppnar/stänger katalogerstrukturer function set_folders_state($elements, state) { $elements.attr('data-status', state); $icons = $elements.find('i.fa'); switch (state) { case 'open': $icons.removeClass('fa-folder-o'); $icons.addClass('fa-folder-open-o'); break; case 'closed': $icons.addClass('fa-folder-o'); $icons.removeClass('fa-folder-open-o'); break; } } /* This function will check for already loaded images and attach an event listener to all the others so that it can tell when every image in a given container is loaded.. var container = document.getElementById("container"); onImagesLoaded(container, function() { alert("All the images have loaded"); }); */ function on_images_loaded(container, event) { var images = $(container).find('img'); //container.getElementsByTagName("img"); var loaded = images.length; for (var i = 0; i < images.length; i++) { if (images[i].complete) { loaded--; } else { //images[i].addEventListener("load", function() { $(images[i]).one( "load", function() { loaded--; if (loaded == 0) { event(); } }); //images[i].addEventListener('error', function() { $(images[i]).one( "error", function() { // No image (thumbnail) found, see if original image is stored in data-attribut if($(this).attr('data-url') != undefined){ $(this).attr('src', $(this).attr('data-url')); $(this).attr('srcset', $(this).attr('data-url')); } else { // No data-attrb found use src without thumbnail $(this).attr('src', $(this).attr('src').replace('_thumbnail','')); $(this).attr('srcset', ''); //$(this).replaceWith('
image not found
') /* $(this).off(); $(this).addClass('missing'); $(this).attr('alt',$(this).attr('src')); loaded--; if (loaded == 0) { event(); } */ } }); } if (loaded == 0) { event(); } } } // Byter mellan "Passa in" och "fyll ut" function toggle_fit_in_fill_in (type, element) { var cropit_file_info = $.parseJSON( $(element).attr('data-cropit_file_info') ); switch(type) { case "fill_in": // Förstorar bilden så att det tar upp hela bildytan, utan att ändra ratio $(element).find('.fit_in_fill_in .tgl-btn').removeClass('user_scaled'); $(element).find('.fit_in_fill_in .toggle_fit_in_fill_in').prop('checked', true); // Räknar ut hur mycket bilden måste skalas upp för att fyll ut hela mallen oavsett om bilden beskärs. Utan att skals upp för mycket och retina storlek. var width_ratio = cropit_file_info.template_size.width / $(element).cropit('imageSize')['width']; var height_ratio = cropit_file_info.template_size.height / $(element).cropit('imageSize')['height']; var fill_zoom = Math.max(width_ratio, height_ratio); $(element).cropit('zoom', fill_zoom); break; case "fit_in": // Passar in bilden i bildytan $(element).find('.fit_in_fill_in .tgl-btn').removeClass('user_scaled'); $(element).find('.fit_in_fill_in .toggle_fit_in_fill_in').prop('checked', false); /*var cropit_file_info = $.parseJSON( $(element).attr('data-cropit_file_info') ); $(element).cropit('zoom', cropit_file_info.zoom );*/ // Räknar ut hur mycket bilden måste skalas ner för att hela bilden ska synas och passa in i mallen var aspect_ratio_fit = calculate_aspect_ratio_fit($(element).cropit('imageSize')['width'], $(element).cropit('imageSize')['height'], cropit_file_info.template_size.width, cropit_file_info.template_size.height); var width_ratio = aspect_ratio_fit.width / $(element).cropit('imageSize')['width']; var height_ratio = aspect_ratio_fit.height / $(element).cropit('imageSize')['height']; var fill_zoom = Math.max(width_ratio, height_ratio); $(element).cropit('zoom', fill_zoom); break; } } // Visar / gömmer verktyg utifrån inskickade argument /* först argumentet: cropit elmentet andra argumentet: 'show' eller 'hide' övriga argument: klasserna på de verktyg som ska visas eller gömmas */ function show_hide_tools() { var tools = Array.prototype.slice.call(arguments); var element = tools[0] var show_or_hide = tools[1]; for (var i = 2; i < tools.length; i++) { if( show_or_hide == 'show' ) { element.find(tools[i]).closest('.tool-row').removeClass('tool-row-hidden'); } else { element.find(tools[i]).closest('.tool-row').addClass('tool-row-hidden'); } } } // Räknar ut zoom för att kunna "zooma ut" så det blir marginal runt bilden // 2 betyder att den kan zooma ut 2 ggr bildens ursprungliga storlek function set_margin (element) { // Räknar ut max zoom utifrån hur stor den största retina bilden som ska skapas är var max_zoom_level = (1 / retina_max_multiplier).toFixed(1); if($(element).cropit('minZoom') === 1) { $(element).cropit('minZoom', 2); // Om bilden är tillräckling stor för att vara zoom-bar så sätts max-zoom till max-retina storleken. Annars sätt den till 1. if( $(element).cropit('isZoomable') ) { $(element).cropit('maxZoom', max_zoom_level); } else { $(element).cropit('maxZoom', 1); } show_hide_tools(element, 'show', '.cropit-image-zoom-input'); } else { $(element).cropit('minZoom', 1); $(element).cropit('maxZoom', max_zoom_level); if( !$(element).cropit('isZoomable') ) { show_hide_tools(element, 'hide', '.cropit-image-zoom-input'); } } } /* Tar ut värden från en css transform matrix och konverterar till x, y, scale och rotate med QR - tekniken (finns även LU). Hämtat från http://stackoverflow.com/a/30583749 input: 'matrix(1.03923, 0.6, -0.416756, 1.14503, 3.11237, 8.72513)' Motsvarar i CSS: rotate(30deg) scale(1.2) skew(10deg) translate(3px, 8px); output: { "scale": { "x": 1.1999995803749266, "y": 1.2000030253761313 }, "translate": { "x": "3.11237", "y": "8.72513" }, "rotation": 0.5235989774905885, "skew": { "x": 0.17453426377567574, "y": 0 } } var test_matrix = extract_transform_matrix_values('matrix(1.03923, 0.6, -0.416756, 1.14503, 3.11237, 8.72513)') console.log( JSON.stringify(test_matrix, null, 2)); var test_transform = create_transform_css(test_matrix); console.log(test_transform); */ function extract_transform_matrix_values (element_or_string) { if( element_or_string !== null && typeof element_or_string === 'object' ) { var transform_matrix = $(element_or_string).css('transform'); } else { var transform_matrix = element_or_string; } var transform_matrix_values = transform_matrix.split('(')[1].split(')')[0].split(','); transform_matrix_values = transform_matrix_values.map(function(value){ return value.replace(/ /g, ''); }); var a = transform_matrix_values[0], b = transform_matrix_values[1], c = transform_matrix_values[2], d = transform_matrix_values[3], e = transform_matrix_values[4], f = transform_matrix_values[5] /* var tmp_scale = Math.sqrt(a*a + b*b); var tmp_angle = Math.round(Math.atan2(b, a) * (180/Math.PI)); console.log('Rotate: ' + tmp_angle + 'deg'); */ var acos = Math.acos, // caching for readability below atan = Math.atan, sqrt = Math.sqrt, pi = Math.PI, translate = {x: parseFloat(e), y: parseFloat(f)}, rotation = {rad: 0, degrees: 0}, scale = {x: 1, y: 1}, skew = {x: 0, y: 0}, determ = a * d - b * c; // get determinant // Using QR-like decomposition. if (a || b) { var r = sqrt(a*a + b*b); rotation.rad = b > 0 ? acos(a / r) : -acos(a / r); scale = {x: r, y: determ / r}; skew.x = atan((a*c + b*d) / (r*r)); } else if (c || d) { var s = sqrt(c*c + d*d); rotation.rad = pi * 0.5 - (d > 0 ? acos(-c / s) : -acos(c / s)); scale = {x: determ/s, y: s}; skew.y = atan((a*c + b*d) / (s*s)); } else { // a = b = c = d = 0 scale = {x:0, y:0}; // = invalid matrix } scale.x = scale.x; scale.y = scale.y; translate.x = translate.x; translate.y = translate.y; rotation.degrees = rotation.rad / (Math.PI / 180), skew.x = skew.x; skew.y = skew.y; return { scale : scale, translate: translate, rotation : rotation, skew : skew }; } /* Skarar css transform sträng utifrån json input: { "scale": { "x": 1.2, "y": 1.2 }, "translate": { "x": 3.11, "y": 8.73 }, "rotation": { "rad": 0.5235989774905885, "degrees": 30 }, "skew": { "x": 0.2, "y": 0 } } output: 'translate(150px, 100px) scale(0.5) rotate(30deg)' */ function create_transform_css (transform_matrix_values) { return 'translate(' + transform_matrix_values.translate.x + 'px, ' + transform_matrix_values.translate.y + 'px) scale(' + transform_matrix_values.scale.x + ', ' + transform_matrix_values.scale.y + ') rotate(' + transform_matrix_values.rotation.degrees.toFixed(1) + 'deg) skew(' + transform_matrix_values.skew.x + 'deg, ' + transform_matrix_values.skew.y + 'deg)'; } function get_file_info (element) { var template_width = parseInt($(element).attr('data-width')); var template_height = parseInt($(element).attr('data-height')); // Räknar ut alla möjliga storlekar utifrån retina_multipliers @1x, @2x, @3x osv var template_size_at_x = []; $.each(retina_multipliers, function (retina_multiplier_key, retina_multiplier) { template_size_at_x.push( { 'retina_multiplier' : retina_multiplier, 'size' : { 'width' : template_width * retina_multiplier, 'height' : template_height * retina_multiplier } } ); }); var cropit_file_info = { 'zoom' : $(element).cropit('zoom'), 'current_preview_size' : { 'width' : parseInt( $(element).cropit('previewSize')['width'] * $(element).cropit('zoom') ), 'height' : parseInt( $(element).cropit('previewSize')['height'] * $(element).cropit('zoom') ) }, 'current_image_size' : { 'width' : parseInt( $(element).cropit('imageSize')['width'] * $(element).cropit('zoom') ), 'height' : parseInt( $(element).cropit('imageSize')['height'] * $(element).cropit('zoom') ) }, 'preview_size' : $(element).cropit('previewSize'), 'template_size' : { 'width' : template_width, 'height' : template_height }, 'image_size' : $(element).cropit('imageSize'), 'template_size_atx' : template_size_at_x }; return cropit_file_info; } /********************************************************* 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" ); } /*********************************************************/ // Slår ihop en array till en sträng med komma mellan förutom i slutet där man kan lägga in en bindeord, t.ex och/eller. /* Exempel: $array = array("1 år", "2 månader", "3 dagar"); console.log( conjunction_array($array, "och")); Output: 1 år, 2 månader och 3 dagar" */ function conjunction_array(array, conjunction, end_conjunction) { if (array.length <= 1) { return array.join(""); } ll = array.pop(); return array.join(conjunction + ' ') + ' ' + end_conjunction + ' ' + ll; } /* Samma som PHP array_chunk, dvs delar upp en array i definierade delar */ function array_chunk (arr, len) { var chunks = [], i = 0, n = arr.length; while (i < n) { chunks.push(arr.slice(i, i += len)); } return chunks; } /* 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; } } // Visar sidinstruktioner function show_page_instructions(e) { // Instruktionsfältet var instructions = $(e.target).closest('#page_instructions'); // Hämtar vilken cookie som ska sättas var cookie_name = $(e.target).closest('.instructions-buttons').attr('data-cookie'); cookie_name = 'page-instructions-' + cookie_name + '-status'; // Tar bort CSS-klassen .compact från #page_instructions $(instructions).removeClass('compact'); // Sparar status till en cookie createCookie(cookie_name, 'show', 7); } // Gömmer sidinstruktioner function hide_page_instructions(e) { // Instruktionsfältet var instructions = $(e.target).closest('#page_instructions'); // Hämtar vilken cookie som ska sättas var cookie_name = $(e.target).closest('.instructions-buttons').attr('data-cookie'); cookie_name = 'page-instructions-' + cookie_name + '-status'; // Lägger till CSS-klassen .compact till #page_instructions $(instructions).addClass('compact'); // Sparar stagittus till en cookie createCookie(cookie_name, 'hide', 7); } // Cookie functions function createCookie(name,value,days) { if (days) { var date = new Date(); date.setTime(date.getTime()+(days*24*60*60*1000)); var expires = "; expires="+date.toGMTString(); } else var expires = ""; document.cookie = name+"="+value+expires+"; path=/"; } function readCookie(name) { var nameEQ = name + "="; var ca = document.cookie.split(';'); for(var i=0;i < ca.length;i++) { var c = ca[i]; while (c.charAt(0)==' ') c = c.substring(1,c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); } return null; } function eraseCookie(name) { createCookie(name,"",-1); } // Hämtar cursorns postion $.fn.getCaret = function(n) { var d = $(this)[0]; var s, r; r = document.createRange(); r.selectNodeContents(d); s = window.getSelection(); //console.log('position: '+s.anchorOffset+' of '+s.anchorNode.textContent.length); return s.anchorOffset; }; // Sätter cursorns postion $.fn.setCaret = function(n) { var d = $(this)[0]; d.focus(); var r = document.createRange(); var s = window.getSelection(); if(n == 'last'){ // Sätter sist i texten n = s.anchorNode.textContent.length } // Kollar om det finns något innehåll if(d.childNodes.length > 0){ r.setStart(d.childNodes[0], n); r.collapse(true); s.removeAllRanges(); s.addRange(r); //console.log('position: '+s.anchorOffset+' of '+s.anchorNode.textContent.length); } return this; }; /* Städar upp ett filnamn enligt https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html */ function sanitaze_filename_aws_s3(str) { str = $.trim(str); // Ersätter alla enterslag och tabbar med _ str = str.replace(/[\t\n\r]/g, '_'); // Ersätter skumma ÅÄÖ när man kopierar från t.ex PDF samt ersätter "riktiga" bindestreck med standard minus-tecknet search_chr = ['å', 'ä', 'ö', "+", "ø", "æ", "é", "á", "ü", "å", "ä", "ö", "é", "á", "ü"]; replace_chr = ['a', 'a', 'o', "_", "o", "a", "e", "a", "u", "a", "a", "o", "e", "a", "u"]; str = str_replace(search_chr, replace_chr, str); // Tar bort övriga ej tillåtna tecken str = str.replace(/[^a-z0-9_.-]/ig, ""); return str; } function htmlEncode(value){ //create a in-memory div, set it's inner text(which jQuery automatically encodes) //then grab the encoded contents back out. The div never exists on the page. return $('
').text(value).html(); } function htmlDecode(value){ return $('
').html(value).text(); } function find_closest_number_in_array (num, arr) { var curr = arr[0]; var diff = Math.abs (num - curr); for (var val = 0; val < arr.length; val++) { var newdiff = Math.abs (num - arr[val]); if (newdiff < diff) { diff = newdiff; curr = arr[val]; } } return curr; } // 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); } } /** * Initate a range slider * * Template example: *

Per nascetur torquent ad hac vitae netus...

* * After intiating add events for the range slider and/ord range value like this: * $(range_element_container_selector + ' ' + range_element_selector).on('input', function () { // update code for when changing the slider... }) * $(range_element_container_selector + ' ' + range_value_element_selector).on('input', function () { // update code for when changing the input value... }) * * //NOTE: If the unit text is very long, change the moduls to show fewer ticks. Or add
between the words. * * //TODO: Instead of preset array with values, be able to set a range? For example 0-100. * * @param {string} range_element_container_selector - The container element selector for the range slider * @param {array} range_values - Range as array, i.e [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100] * @param {string} range_modulus - Only show every x tick, for example if there are many. I.e 2 to show every other range value. * @param {json} range_unit - Range unit, i.e "%", "$" etc. In long (used for value) and short (used for ticks) format. Example: {"long":"seconds", "short":"s"} If you want a space use " ". You can also use
, it will be removed for the range input value but not for the ticks. Great for if the unit text is long. * @param {string} range_unit_placement - "befoer" or "after" range unit values. * @param {string} range_default_value - Defualt range value * @param {string} range_value_state - "disabled" / "enabled". Be able to change the range via the text input. The closest range value of the input range value will be selected. * @param {boolean} set_default_events - Clear the default events and set to default, or do not. For example, when initating for the first time set this to "true" and when updating the settings set it to "false". */ function range_slider_init( range_element_container_selector, range_values, range_modulus, range_unit, range_unit_placement, range_default_value, range_value_state, set_default_events ) { //console.log( arguments ); // Select all elements with the selector strings var $range_element = $(range_element_container_selector + ' .range_slider'); var $range_value_element = $(range_element_container_selector + ' .range_slider_value'); var $range_value_unit_element = $(range_element_container_selector + ' .range_slider_value_unit'); var $range_ticks_element = $(range_element_container_selector + ' .range_slider_ticks'); $range_element.attr('data-range_values', JSON.stringify(range_values)); range_unit = (range_unit == "" ? " " : range_unit); // Set if the range value input should be editable $range_value_element.attr('disabled', 'disabled'); // Save the intial state to be able to enable/disable without changing the intial state $range_value_element.attr('data-init_state', range_value_state); if(range_value_state == "enabled"){ $range_value_element.removeAttr('disabled') } // Create the "ticks" from the range array var range_ticks_html = ''; var range_tick_html = ''; for (var index = 0; index < range_values.length; index++) { if(index % range_modulus === 0 ){ // Only show every x tick, for example if there are many. // Set the range unit placement for the ticks switch (range_unit_placement) { case "before": range_tick_html = range_unit.short + range_values[index]; break; case "after": range_tick_html = range_values[index] + range_unit.short; break; default: range_tick_html = range_values[index] + range_unit.short; break; } range_ticks_html += '
' + range_tick_html + '
'; } } $range_ticks_element.html(range_ticks_html); $range_element.attr('max', range_values.length - 1); $range_value_element.attr('max', range_values[range_values.length-1]); $range_value_element.css("width", (range_values[range_values.length-1].toString().length + 1) + 'ch' ); // Remove any
for the range value input. For the ticks there is no problem using
in the range unit, for example if the unit text is long var regex = //gi; $range_value_unit_element.html(range_unit.long.replace(regex, '')); $range_value_element.val(range_default_value); // Set the range unit placement for the range input value switch (range_unit_placement) { case "before": $($range_value_unit_element).parent().append($range_value_unit_element); $($range_value_unit_element).parent().append($range_value_element); $range_value_element.css("text-align", "left"); break; case "after": $($range_value_unit_element).parent().append($range_value_element); $($range_value_unit_element).parent().append($range_value_unit_element); $range_value_element.css("text-align", "right"); break; default: $($range_value_unit_element).parent().append($range_value_element); $($range_value_unit_element).parent().append($range_value_unit_element); $range_value_element.css("text-align", "right"); break; } // If setting the value via the input, find the nearest value for the slider and set it to that value. var closest_value = find_closest_number_in_array($range_value_element.val(), range_values); $range_element.val($.inArray(closest_value, range_values)); $($range_value_element).val(range_values[$range_element.val()]); if(set_default_events){ $range_element.off('input').on('input', function () { var range_values = $.parseJSON($range_element.attr('data-range_values')); $($range_value_element).val(range_values[$range_element.val()]); }); $range_value_element.off('input').on('input', function () { var range_values = $.parseJSON($range_element.attr('data-range_values')); var closest_value = find_closest_number_in_array($range_value_element.val(), range_values); $($range_element).val($.inArray(closest_value, range_values)); }); } } /** * Enable or disable a range slider * @param {string} range_element_container_selector - The container element selector for the range slider * @param {string} state - "disabled" / "enabled". */ function range_slider_set_state(range_element_container_selector, state){ // Select all elements with the selector strings var $range_element = $(range_element_container_selector + ' .range_slider'); var $range_value_element = $(range_element_container_selector + ' .range_slider_value'); var $range_value_unit_element = $(range_element_container_selector + ' .range_slider_value_unit'); var $range_ticks_element = $(range_element_container_selector + ' .range_slider_ticks'); var $range_elements = [$range_element, $range_value_element, $range_value_unit_element, $range_ticks_element] $.each($range_elements, function(range_element_input_key, range_element) { if(state == 'disabled'){ $(range_element).attr('disabled', 'disabled') $(range_element).addClass('disabled'); } else { // Check inital state and only enable if the state wasn't disabled from the beginning. if($(range_element).attr('data-init_state') != 'disabled'){ $(range_element).removeAttr('disabled'); } $(range_element).removeClass('disabled'); } }) }