function explode (delimiter, string, limit) { // http://kevin.vanzonneveld.net // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + improved by: kenneth // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + improved by: d3x // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // * example 1: explode(' ', 'Kevin van Zonneveld'); // * returns 1: {0: 'Kevin', 1: 'van', 2: 'Zonneveld'} // * example 2: explode('=', 'a=bc=d', 2); // * returns 2: ['a', 'bc=d'] var emptyArray = { 0: '' }; // third argument is not required if ( arguments.length < 2 || typeof arguments[0] == 'undefined' || typeof arguments[1] == 'undefined' ) { return null; } if ( delimiter === '' || delimiter === false || delimiter === null ) { return false; } if ( typeof delimiter == 'function' || typeof delimiter == 'object' || typeof string == 'function' || typeof string == 'object' ) { return emptyArray; } if ( delimiter === true ) { delimiter = '1'; } if (!limit) { return string.toString().split(delimiter.toString()); } else { // support for limit argument var splitted = string.toString().split(delimiter.toString()); var partA = splitted.splice(0, limit - 1); var partB = splitted.join(delimiter.toString()); partA.push(partB); return partA; } } function implode (glue, pieces) { // http://kevin.vanzonneveld.net // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + improved by: Waldo Malqui Silva // + improved by: Itsacon (http://www.itsacon.net/) // + bugfixed by: Brett Zamir (http://brett-zamir.me) // * example 1: implode(' ', ['Kevin', 'van', 'Zonneveld']); // * returns 1: 'Kevin van Zonneveld' // * example 2: implode(' ', {first:'Kevin', last: 'van Zonneveld'}); // * returns 2: 'Kevin van Zonneveld' var i = '', retVal = '', tGlue = ''; if (arguments.length === 1) { pieces = glue; glue = ''; } if (typeof(pieces) === 'object') { if (pieces instanceof Array) { return pieces.join(glue); } else { for (i in pieces) { retVal += tGlue + pieces[i]; tGlue = glue; } return retVal; } } else { return pieces; } } function round (value, precision, mode) { // http://kevin.vanzonneveld.net // + original by: Philip Peterson // + revised by: Onno Marsman // + input by: Greenseed // + revised by: T.Wild // + input by: meo // + input by: William // + bugfixed by: Brett Zamir (http://brett-zamir.me) // + input by: Josep Sanz (http://www.ws3.es/) // + revised by: Rafał Kukawski (http://blog.kukawski.pl/) // % note 1: Great work. Ideas for improvement: // % note 1: - code more compliant with developer guidelines // % note 1: - for implementing PHP constant arguments look at // % note 1: the pathinfo() function, it offers the greatest // % note 1: flexibility & compatibility possible // * example 1: round(1241757, -3); // * returns 1: 1242000 // * example 2: round(3.6); // * returns 2: 4 // * example 3: round(2.835, 2); // * returns 3: 2.84 // * example 4: round(1.1749999999999, 2); // * returns 4: 1.17 // * example 5: round(58551.799999999996, 2); // * returns 5: 58551.8 var m, f, isHalf, sgn; // helper variables precision |= 0; // making sure precision is integer m = Math.pow(10, precision); value *= m; sgn = (value > 0) | -(value < 0); // sign of the number isHalf = value % 1 === 0.5 * sgn; f = Math.floor(value); if (isHalf) { switch (mode) { case 'PHP_ROUND_HALF_DOWN': value = f + (sgn < 0); // rounds .5 toward zero break; case 'PHP_ROUND_HALF_EVEN': value = f + (f % 2 * sgn); // rouds .5 towards the next even integer break; case 'PHP_ROUND_HALF_ODD': value = f + !(f % 2); // rounds .5 towards the next odd integer break; default: value = f + (sgn > 0); // rounds .5 away from zero } } return (isHalf ? value : Math.round(value)) / m; } function htmlentities (string, quote_style) { // http://kevin.vanzonneveld.net // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + improved by: nobbler // + tweaked by: Jack // + bugfixed by: Onno Marsman // + revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + bugfixed by: Brett Zamir (http://brett-zamir.me) // + input by: Ratheous // - depends on: get_html_translation_table // * example 1: htmlentities('Kevin & van Zonneveld'); // * returns 1: 'Kevin & van Zonneveld' // * example 2: htmlentities("foo'bar","ENT_QUOTES"); // * returns 2: 'foo'bar' var hash_map = {}, symbol = '', tmp_str = '', entity = ''; tmp_str = string.toString(); if (false === (hash_map = this.get_html_translation_table('HTML_ENTITIES', quote_style))) { return false; } hash_map["'"] = '''; for (symbol in hash_map) { entity = hash_map[symbol]; tmp_str = tmp_str.split(symbol).join(entity); } return tmp_str; } function get_html_translation_table (table, quote_style) { // http://kevin.vanzonneveld.net // + original by: Philip Peterson // + revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + bugfixed by: noname // + bugfixed by: Alex // + bugfixed by: Marco // + bugfixed by: madipta // + improved by: KELAN // + improved by: Brett Zamir (http://brett-zamir.me) // + bugfixed by: Brett Zamir (http://brett-zamir.me) // + input by: Frank Forte // + bugfixed by: T.Wild // + input by: Ratheous // % note: It has been decided that we're not going to add global // % note: dependencies to php.js, meaning the constants are not // % note: real constants, but strings instead. Integers are also supported if someone // % note: chooses to create the constants themselves. // * example 1: get_html_translation_table('HTML_SPECIALCHARS'); // * returns 1: {'"': '"', '&': '&', '<': '<', '>': '>'} var entities = {}, hash_map = {}, decimal = 0, symbol = ''; var constMappingTable = {}, constMappingQuoteStyle = {}; var useTable = {}, useQuoteStyle = {}; // Translate arguments constMappingTable[0] = 'HTML_SPECIALCHARS'; constMappingTable[1] = 'HTML_ENTITIES'; constMappingQuoteStyle[0] = 'ENT_NOQUOTES'; constMappingQuoteStyle[2] = 'ENT_COMPAT'; constMappingQuoteStyle[3] = 'ENT_QUOTES'; useTable = !isNaN(table) ? constMappingTable[table] : table ? table.toUpperCase() : 'HTML_SPECIALCHARS'; useQuoteStyle = !isNaN(quote_style) ? constMappingQuoteStyle[quote_style] : quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT'; if (useTable !== 'HTML_SPECIALCHARS' && useTable !== 'HTML_ENTITIES') { throw new Error("Table: " + useTable + ' not supported'); // return false; } entities['38'] = '&'; if (useTable === 'HTML_ENTITIES') { entities['160'] = ' '; entities['161'] = '¡'; entities['162'] = '¢'; entities['163'] = '£'; entities['164'] = '¤'; entities['165'] = '¥'; entities['166'] = '¦'; entities['167'] = '§'; entities['168'] = '¨'; entities['169'] = '©'; entities['170'] = 'ª'; entities['171'] = '«'; entities['172'] = '¬'; entities['173'] = '­'; entities['174'] = '®'; entities['175'] = '¯'; entities['176'] = '°'; entities['177'] = '±'; entities['178'] = '²'; entities['179'] = '³'; entities['180'] = '´'; entities['181'] = 'µ'; entities['182'] = '¶'; entities['183'] = '·'; entities['184'] = '¸'; entities['185'] = '¹'; entities['186'] = 'º'; entities['187'] = '»'; entities['188'] = '¼'; entities['189'] = '½'; entities['190'] = '¾'; entities['191'] = '¿'; entities['192'] = 'À'; entities['193'] = 'Á'; entities['194'] = 'Â'; entities['195'] = 'Ã'; entities['196'] = 'Ä'; entities['197'] = 'Å'; entities['198'] = 'Æ'; entities['199'] = 'Ç'; entities['200'] = 'È'; entities['201'] = 'É'; entities['202'] = 'Ê'; entities['203'] = 'Ë'; entities['204'] = 'Ì'; entities['205'] = 'Í'; entities['206'] = 'Î'; entities['207'] = 'Ï'; entities['208'] = 'Ð'; entities['209'] = 'Ñ'; entities['210'] = 'Ò'; entities['211'] = 'Ó'; entities['212'] = 'Ô'; entities['213'] = 'Õ'; entities['214'] = 'Ö'; entities['215'] = '×'; entities['216'] = 'Ø'; entities['217'] = 'Ù'; entities['218'] = 'Ú'; entities['219'] = 'Û'; entities['220'] = 'Ü'; entities['221'] = 'Ý'; entities['222'] = 'Þ'; entities['223'] = 'ß'; entities['224'] = 'à'; entities['225'] = 'á'; entities['226'] = 'â'; entities['227'] = 'ã'; entities['228'] = 'ä'; entities['229'] = 'å'; entities['230'] = 'æ'; entities['231'] = 'ç'; entities['232'] = 'è'; entities['233'] = 'é'; entities['234'] = 'ê'; entities['235'] = 'ë'; entities['236'] = 'ì'; entities['237'] = 'í'; entities['238'] = 'î'; entities['239'] = 'ï'; entities['240'] = 'ð'; entities['241'] = 'ñ'; entities['242'] = 'ò'; entities['243'] = 'ó'; entities['244'] = 'ô'; entities['245'] = 'õ'; entities['246'] = 'ö'; entities['247'] = '÷'; entities['248'] = 'ø'; entities['249'] = 'ù'; entities['250'] = 'ú'; entities['251'] = 'û'; entities['252'] = 'ü'; entities['253'] = 'ý'; entities['254'] = 'þ'; entities['255'] = 'ÿ'; } if (useQuoteStyle !== 'ENT_NOQUOTES') { entities['34'] = '"'; } if (useQuoteStyle === 'ENT_QUOTES') { entities['39'] = '''; } entities['60'] = '<'; entities['62'] = '>'; // ascii decimals to real symbols for (decimal in entities) { symbol = String.fromCharCode(decimal); hash_map[symbol] = entities[decimal]; } return hash_map; } function str_pad (input, pad_length, pad_string, pad_type) { // http://kevin.vanzonneveld.net // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + namespaced by: Michael White (http://getsprink.com) // + input by: Marco van Oort // + bugfixed by: Brett Zamir (http://brett-zamir.me) // * example 1: str_pad('Kevin van Zonneveld', 30, '-=', 'STR_PAD_LEFT'); // * returns 1: '-=-=-=-=-=-Kevin van Zonneveld' // * example 2: str_pad('Kevin van Zonneveld', 30, '-', 'STR_PAD_BOTH'); // * returns 2: '------Kevin van Zonneveld-----' var half = '', pad_to_go; var str_pad_repeater = function (s, len) { var collect = '', i; while (collect.length < len) { collect += s; } collect = collect.substr(0, len); return collect; }; input += ''; pad_string = pad_string !== undefined ? pad_string : ' '; if (pad_type != 'STR_PAD_LEFT' && pad_type != 'STR_PAD_RIGHT' && pad_type != 'STR_PAD_BOTH') { pad_type = 'STR_PAD_RIGHT'; } if ((pad_to_go = pad_length - input.length) > 0) { if (pad_type == 'STR_PAD_LEFT') { input = str_pad_repeater(pad_string, pad_to_go) + input; } else if (pad_type == 'STR_PAD_RIGHT') { input = input + str_pad_repeater(pad_string, pad_to_go); } else if (pad_type == 'STR_PAD_BOTH') { half = str_pad_repeater(pad_string, Math.ceil(pad_to_go / 2)); input = half + input + half; input = input.substr(0, pad_length); } } return input; } function phpdate (format, timestamp) { // http://kevin.vanzonneveld.net // + original by: Carlos R. L. Rodrigues (http://www.jsfromhell.com) // + parts by: Peter-Paul Koch (http://www.quirksmode.org/js/beat.html) // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + improved by: MeEtc (http://yass.meetcweb.com) // + improved by: Brad Touesnard // + improved by: Tim Wiel // + improved by: Bryan Elliott // // + improved by: Brett Zamir (http://brett-zamir.me) // + improved by: David Randall // + input by: Brett Zamir (http://brett-zamir.me) // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + improved by: Brett Zamir (http://brett-zamir.me) // + improved by: Brett Zamir (http://brett-zamir.me) // + improved by: Theriault // + derived from: gettimeofday // + input by: majak // + bugfixed by: majak // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + input by: Alex // + bugfixed by: Brett Zamir (http://brett-zamir.me) // + improved by: Theriault // + improved by: Brett Zamir (http://brett-zamir.me) // + improved by: Theriault // + improved by: Thomas Beaucourt (http://www.webapp.fr) // + improved by: JT // + improved by: Theriault // + improved by: Rafał Kukawski (http://blog.kukawski.pl) // + bugfixed by: omid (http://phpjs.org/functions/380:380#comment_137122) // + input by: Martin // + input by: Alex Wilson // % note 1: Uses global: php_js to store the default timezone // % note 2: Although the function potentially allows timezone info (see notes), it currently does not set // % note 2: per a timezone specified by date_default_timezone_set(). Implementers might use // % note 2: this.php_js.currentTimezoneOffset and this.php_js.currentTimezoneDST set by that function // % note 2: in order to adjust the dates in this function (or our other date functions!) accordingly // * example 1: date('H:m:s \\m \\i\\s \\m\\o\\n\\t\\h', 1062402400); // * returns 1: '09:09:40 m is month' // * example 2: date('F j, Y, g:i a', 1062462400); // * returns 2: 'September 2, 2003, 2:26 am' // * example 3: date('Y W o', 1062462400); // * returns 3: '2003 36 2003' // * example 4: x = date('Y m d', (new Date()).getTime()/1000); // * example 4: (x+'').length == 10 // 2009 01 09 // * returns 4: true // * example 5: date('W', 1104534000); // * returns 5: '53' // * example 6: date('B t', 1104534000); // * returns 6: '999 31' // * example 7: date('W U', 1293750000.82); // 2010-12-31 // * returns 7: '52 1293750000' // * example 8: date('W', 1293836400); // 2011-01-01 // * returns 8: '52' // * example 9: date('W Y-m-d', 1293974054); // 2011-01-02 // * returns 9: '52 2011-01-02' var that = this, jsdate, f, formatChr = /\\?([a-z])/gi, formatChrCb, // Keep this here (works, but for code commented-out // below for file size reasons) //, tal= [], _pad = function (n, c) { if ((n = n + '').length < c) { return new Array((++c) - n.length).join('0') + n; } return n; }, txt_words = ["Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; formatChrCb = function (t, s) { return f[t] ? f[t]() : s; }; f = { // Day d: function () { // Day of month w/leading 0; 01..31 return _pad(f.j(), 2); }, D: function () { // Shorthand day name; Mon...Sun return f.l().slice(0, 3); }, j: function () { // Day of month; 1..31 return jsdate.getDate(); }, l: function () { // Full day name; Monday...Sunday return txt_words[f.w()] + 'day'; }, N: function () { // ISO-8601 day of week; 1[Mon]..7[Sun] return f.w() || 7; }, S: function () { // Ordinal suffix for day of month; st, nd, rd, th var j = f.j(); return j < 4 | j > 20 && ['st', 'nd', 'rd'][j%10 - 1] || 'th'; }, w: function () { // Day of week; 0[Sun]..6[Sat] return jsdate.getDay(); }, z: function () { // Day of year; 0..365 var a = new Date(f.Y(), f.n() - 1, f.j()), b = new Date(f.Y(), 0, 1); return Math.round((a - b) / 864e5) + 1; }, // Week W: function () { // ISO-8601 week number var a = new Date(f.Y(), f.n() - 1, f.j() - f.N() + 3), b = new Date(a.getFullYear(), 0, 4); return _pad(1 + Math.round((a - b) / 864e5 / 7), 2); }, // Month F: function () { // Full month name; January...December return txt_words[6 + f.n()]; }, m: function () { // Month w/leading 0; 01...12 return _pad(f.n(), 2); }, M: function () { // Shorthand month name; Jan...Dec return f.F().slice(0, 3); }, n: function () { // Month; 1...12 return jsdate.getMonth() + 1; }, t: function () { // Days in month; 28...31 return (new Date(f.Y(), f.n(), 0)).getDate(); }, // Year L: function () { // Is leap year?; 0 or 1 var j = f.Y(); return j%4==0 & j%100!=0 | j%400==0; }, o: function () { // ISO-8601 year var n = f.n(), W = f.W(), Y = f.Y(); return Y + (n === 12 && W < 9 ? -1 : n === 1 && W > 9); }, Y: function () { // Full year; e.g. 1980...2010 return jsdate.getFullYear(); }, y: function () { // Last two digits of year; 00...99 return (f.Y() + "").slice(-2); }, // Time a: function () { // am or pm return jsdate.getHours() > 11 ? "pm" : "am"; }, A: function () { // AM or PM return f.a().toUpperCase(); }, B: function () { // Swatch Internet time; 000..999 var H = jsdate.getUTCHours() * 36e2, // Hours i = jsdate.getUTCMinutes() * 60, // Minutes s = jsdate.getUTCSeconds(); // Seconds return _pad(Math.floor((H + i + s + 36e2) / 86.4) % 1e3, 3); }, g: function () { // 12-Hours; 1..12 return f.G() % 12 || 12; }, G: function () { // 24-Hours; 0..23 return jsdate.getHours(); }, h: function () { // 12-Hours w/leading 0; 01..12 return _pad(f.g(), 2); }, H: function () { // 24-Hours w/leading 0; 00..23 return _pad(f.G(), 2); }, i: function () { // Minutes w/leading 0; 00..59 return _pad(jsdate.getMinutes(), 2); }, s: function () { // Seconds w/leading 0; 00..59 return _pad(jsdate.getSeconds(), 2); }, u: function () { // Microseconds; 000000-999000 return _pad(jsdate.getMilliseconds() * 1000, 6); }, // Timezone e: function () { // Timezone identifier; e.g. Atlantic/Azores, ... // The following works, but requires inclusion of the very large // timezone_abbreviations_list() function. /* return this.date_default_timezone_get(); */ throw 'Not supported (see source code of date() for timezone on how to add support)'; }, I: function () { // DST observed?; 0 or 1 // Compares Jan 1 minus Jan 1 UTC to Jul 1 minus Jul 1 UTC. // If they are not equal, then DST is observed. var a = new Date(f.Y(), 0), // Jan 1 c = Date.UTC(f.Y(), 0), // Jan 1 UTC b = new Date(f.Y(), 6), // Jul 1 d = Date.UTC(f.Y(), 6); // Jul 1 UTC return 0 + ((a - c) !== (b - d)); }, O: function () { // Difference to GMT in hour format; e.g. +0200 var tzo = jsdate.getTimezoneOffset(), a = Math.abs(tzo); return (tzo > 0 ? "-" : "+") + _pad(Math.floor(a / 60) * 100 + a % 60, 4); }, P: function () { // Difference to GMT w/colon; e.g. +02:00 var O = f.O(); return (O.substr(0, 3) + ":" + O.substr(3, 2)); }, T: function () { // Timezone abbreviation; e.g. EST, MDT, ... // The following works, but requires inclusion of the very // large timezone_abbreviations_list() function. /* var abbr = '', i = 0, os = 0, default = 0; if (!tal.length) { tal = that.timezone_abbreviations_list(); } if (that.php_js && that.php_js.default_timezone) { default = that.php_js.default_timezone; for (abbr in tal) { for (i=0; i < tal[abbr].length; i++) { if (tal[abbr][i].timezone_id === default) { return abbr.toUpperCase(); } } } } for (abbr in tal) { for (i = 0; i < tal[abbr].length; i++) { os = -jsdate.getTimezoneOffset() * 60; if (tal[abbr][i].offset === os) { return abbr.toUpperCase(); } } } */ return 'UTC'; }, Z: function () { // Timezone offset in seconds (-43200...50400) return -jsdate.getTimezoneOffset() * 60; }, // Full Date/Time c: function () { // ISO-8601 date. return 'Y-m-d\\Th:i:sP'.replace(formatChr, formatChrCb); }, r: function () { // RFC 2822 return 'D, d M Y H:i:s O'.replace(formatChr, formatChrCb); }, U: function () { // Seconds since UNIX epoch return jsdate / 1000 | 0; } }; this.phpdate = function (format, timestamp) { that = this; jsdate = (timestamp == null ? new Date() : // Not provided (timestamp instanceof Date) ? new Date(timestamp) : // JS Date() new Date(timestamp * 1000) // UNIX timestamp (auto-convert to int) ); return format.replace(formatChr, formatChrCb); }; return this.phpdate(format, timestamp); } jQuery.fn.center = function () { this.css("position","absolute"); this.css("top", ( $(window).height() - this.height() ) / 2+$(window).scrollTop() + "px"); this.css("left", ( $(window).width() - this.width() ) / 2+$(window).scrollLeft() + "px"); return this; }; jQuery.fn.extend({ /** * Returns get parameters. * * If the desired param does not exist, null will be returned * * To get the document params: * @example value = $(document).getUrlParam("paramName"); * * To get the params of a html-attribut (uses src attribute) * @example value = $('#imgLink').getUrlParam("paramName"); */ getUrlParam: function(strParamName){ strParamName = escape(unescape(strParamName)); var returnVal = new Array(); var qString = null; if ($(this).attr("nodeName")=="#document") { //document-handler if (window.location.search.search(strParamName) > -1 ){ qString = window.location.search.substr(1,window.location.search.length).split("&"); } } else if ($(this).attr("src")!="undefined") { var strHref = $(this).attr("src") if ( strHref.indexOf("?") > -1 ){ var strQueryString = strHref.substr(strHref.indexOf("?")+1); qString = strQueryString.split("&"); } } else if ($(this).attr("href")!="undefined") { var strHref = $(this).attr("href") if ( strHref.indexOf("?") > -1 ){ var strQueryString = strHref.substr(strHref.indexOf("?")+1); qString = strQueryString.split("&"); } } else { return null; } if (qString==null) return null; for (var i=0;i -1; var isIE = navigator.userAgent.indexOf("MSIE") > 1 && !isOpera; var isMoz = navigator.userAgent.indexOf("Mozilla/5.") == 0 && !isOpera; function textboxSelect (oTextbox, iStart, iEnd) { switch(arguments.length) { case 1: oTextbox.select(); break; case 2: iEnd = oTextbox.value.length; /* falls through */ case 3: if (isIE) { var oRange = oTextbox.createTextRange(); oRange.moveStart("character", iStart); oRange.moveEnd("character", -oTextbox.value.length + iEnd); oRange.select(); } else if (isMoz){ oTextbox.setSelectionRange(iStart, iEnd); } } oTextbox.focus(); } function textboxReplaceSelect (oTextbox, sText) { if (isIE) { var oRange = document.selection.createRange(); oRange.text = sText; oRange.collapse(true); oRange.select(); } else if (isMoz) { var iStart = oTextbox.selectionStart; oTextbox.value = oTextbox.value.substring(0, iStart) + sText + oTextbox.value.substring(oTextbox.selectionEnd, oTextbox.value.length); oTextbox.setSelectionRange(iStart + sText.length, iStart + sText.length); } oTextbox.focus(); } /*jslint browser: true */ /*global jQuery: true */ /** * jQuery Cookie plugin * * Copyright (c) 2010 Klaus Hartl (stilbuero.de) * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * */ // TODO JsDoc /** * Create a cookie with the given key and value and other optional parameters. * * @example $.cookie('the_cookie', 'the_value'); * @desc Set the value of a cookie. * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true }); * @desc Create a cookie with all available options. * @example $.cookie('the_cookie', 'the_value'); * @desc Create a session cookie. * @example $.cookie('the_cookie', null); * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain * used when the cookie was set. * * @param String key The key of the cookie. * @param String value The value of the cookie. * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. * If set to null or omitted, the cookie will be a session cookie and will not be retained * when the the browser exits. * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will * require a secure protocol (like HTTPS). * @type undefined * * @name $.cookie * @cat Plugins/Cookie * @author Klaus Hartl/klaus.hartl@stilbuero.de */ /** * Get the value of a cookie with the given key. * * @example $.cookie('the_cookie'); * @desc Get the value of a cookie. * * @param String key The key of the cookie. * @return The value of the cookie. * @type String * * @name $.cookie * @cat Plugins/Cookie * @author Klaus Hartl/klaus.hartl@stilbuero.de */ jQuery.cookie = function (key, value, options) { // key and value given, set cookie... if (arguments.length > 1 && (value === null || typeof value !== "object")) { options = jQuery.extend({}, options); if (value === null) { options.expires = -1; } if (typeof options.expires === 'number') { var days = options.expires, t = options.expires = new Date(); t.setDate(t.getDate() + days); } return (document.cookie = [ // encodeURIComponent(key), '=', key, '=', options.raw ? String(value) : encodeURIComponent(String(value)), options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE options.path ? '; path=' + options.path : '', options.domain ? '; domain=' + options.domain : '', options.secure ? '; secure' : '' ].join('')); } // key and possibly options given, get cookie... options = value || {}; var result, decode = options.raw ? function (s) { return s; } : decodeURIComponent; return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null; }; var flyoutManualClose = false; function FlyOut(object, closeObject) { var closeObject = closeObject ? closeObject : false; var flyoutObjects = $(object); for (var i=0; i * * Based on Pause-resume-animation jQuery plugin by Joe Weitzel * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or(at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Changelog: * * 0.1 2010-06-13 Initial release */ (function() { var $ = jQuery, pauseId = 'jQuery.pause', uuid = 1, oldAnimate = $.fn.animate, anims = {}; function now() { return new Date().getTime(); } $.fn.animate = function(prop, speed, easing, callback) { var optall = $.speed(speed, easing, callback); optall.complete = optall.old; // unwrap callback return this.each(function() { // check pauseId if (! this[pauseId]) this[pauseId] = uuid++; // start animation var opt = $.extend({}, optall); oldAnimate.apply($(this), [prop, $.extend({}, opt)]); // store data anims[this[pauseId]] = { run: true, prop: prop, opt: opt, start: now(), done: 0 }; }); }; $.fn.pause = function() { return this.each(function() { // check pauseId if (! this[pauseId]) this[pauseId] = uuid++; // fetch data var data = anims[this[pauseId]]; if (data && data.run) { data.done += now() - data.start; if (data.done > data.opt.duration) { // remove stale entry delete anims[this[pauseId]]; } else { // pause animation $(this).stop(); data.run = false; } } }); }; $.fn.resume = function() { return this.each(function() { // check pauseId if (! this[pauseId]) this[pauseId] = uuid++; // fetch data var data = anims[this[pauseId]]; if (data && ! data.run) { // resume animation data.opt.duration -= data.done; data.done = 0; data.run = true; data.start = now(); oldAnimate.apply($(this), [data.prop, $.extend({}, data.opt)]); } }); }; })(); /** * Farbtastic Color Picker 1.2 * © 2008 Steven Wittens * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ jQuery.fn.farbtastic = function (callback) { $.farbtastic(this, callback); return this; }; jQuery.farbtastic = function (container, callback) { var container = $(container).get(0); return container.farbtastic || (container.farbtastic = new jQuery._farbtastic(container, callback)); } jQuery._farbtastic = function (container, callback) { // Store farbtastic object var fb = this; // Insert markup $(container).html('
'); var e = $('.farbtastic', container); fb.wheel = $('.wheel', container).get(0); // Dimensions fb.radius = 84; fb.square = 100; fb.width = 194; // Fix background PNGs in IE6 if (navigator.appVersion.match(/MSIE [0-6]\./)) { $('*', e).each(function () { if (this.currentStyle.backgroundImage != 'none') { var image = this.currentStyle.backgroundImage; image = this.currentStyle.backgroundImage.substring(5, image.length - 2); $(this).css({ 'backgroundImage': 'none', 'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')" }); } }); } /** * Link to the given element(s) or callback. */ fb.linkTo = function (callback) { // Unbind previous nodes if (typeof fb.callback == 'object') { $(fb.callback).unbind('keyup', fb.updateValue); } // Reset color fb.color = null; // Bind callback or elements if (typeof callback == 'function') { fb.callback = callback; } else if (typeof callback == 'object' || typeof callback == 'string') { fb.callback = $(callback); fb.callback.bind('keyup', fb.updateValue); if (fb.callback.get(0).value) { fb.setColor(fb.callback.get(0).value); } } return this; } fb.updateValue = function (event) { if (this.value && this.value != fb.color) { fb.setColor(this.value); } } /** * Change color with HTML syntax #123456 */ fb.setColor = function (color) { var unpack = fb.unpack(color); if (fb.color != color && unpack) { fb.color = color; fb.rgb = unpack; fb.hsl = fb.RGBToHSL(fb.rgb); fb.updateDisplay(); } return this; } /** * Change color with HSL triplet [0..1, 0..1, 0..1] */ fb.setHSL = function (hsl) { fb.hsl = hsl; fb.rgb = fb.HSLToRGB(hsl); fb.color = fb.pack(fb.rgb); fb.updateDisplay(); return this; } ///////////////////////////////////////////////////// /** * Retrieve the coordinates of the given event relative to the center * of the widget. */ fb.widgetCoords = function (event) { var x, y; var el = event.target || event.srcElement; var reference = fb.wheel; if (typeof event.offsetX != 'undefined') { // Use offset coordinates and find common offsetParent var pos = { x: event.offsetX, y: event.offsetY }; // Send the coordinates upwards through the offsetParent chain. var e = el; while (e) { e.mouseX = pos.x; e.mouseY = pos.y; pos.x += e.offsetLeft; pos.y += e.offsetTop; e = e.offsetParent; } // Look for the coordinates starting from the wheel widget. var e = reference; var offset = { x: 0, y: 0 } while (e) { if (typeof e.mouseX != 'undefined') { x = e.mouseX - offset.x; y = e.mouseY - offset.y; break; } offset.x += e.offsetLeft; offset.y += e.offsetTop; e = e.offsetParent; } // Reset stored coordinates e = el; while (e) { e.mouseX = undefined; e.mouseY = undefined; e = e.offsetParent; } } else { // Use absolute coordinates var pos = fb.absolutePosition(reference); x = (event.pageX || 0*(event.clientX + $('html').get(0).scrollLeft)) - pos.x; y = (event.pageY || 0*(event.clientY + $('html').get(0).scrollTop)) - pos.y; } // Subtract distance to middle return { x: x - fb.width / 2, y: y - fb.width / 2 }; } /** * Mousedown handler */ fb.mousedown = function (event) { // Capture mouse if (!document.dragging) { $(document).bind('mousemove', fb.mousemove).bind('mouseup', fb.mouseup); document.dragging = true; } // Check which area is being dragged var pos = fb.widgetCoords(event); fb.circleDrag = Math.max(Math.abs(pos.x), Math.abs(pos.y)) * 2 > fb.square; // Process fb.mousemove(event); return false; } /** * Mousemove handler */ fb.mousemove = function (event) { // Get coordinates relative to color picker center var pos = fb.widgetCoords(event); // Set new HSL parameters if (fb.circleDrag) { var hue = Math.atan2(pos.x, -pos.y) / 6.28; if (hue < 0) hue += 1; fb.setHSL([hue, fb.hsl[1], fb.hsl[2]]); } else { var sat = Math.max(0, Math.min(1, -(pos.x / fb.square) + .5)); var lum = Math.max(0, Math.min(1, -(pos.y / fb.square) + .5)); fb.setHSL([fb.hsl[0], sat, lum]); } return false; } /** * Mouseup handler */ fb.mouseup = function () { // Uncapture mouse $(document).unbind('mousemove', fb.mousemove); $(document).unbind('mouseup', fb.mouseup); document.dragging = false; } /** * Update the markers and styles */ fb.updateDisplay = function () { // Markers var angle = fb.hsl[0] * 6.28; $('.h-marker', e).css({ left: Math.round(Math.sin(angle) * fb.radius + fb.width / 2) + 'px', top: Math.round(-Math.cos(angle) * fb.radius + fb.width / 2) + 'px' }); $('.sl-marker', e).css({ left: Math.round(fb.square * (.5 - fb.hsl[1]) + fb.width / 2) + 'px', top: Math.round(fb.square * (.5 - fb.hsl[2]) + fb.width / 2) + 'px' }); // Saturation/Luminance gradient $('.color', e).css('backgroundColor', fb.pack(fb.HSLToRGB([fb.hsl[0], 1, 0.5]))); // Linked elements or callback if (typeof fb.callback == 'object') { // Set background/foreground color $(fb.callback).css({ backgroundColor: fb.color, color: fb.hsl[2] > 0.5 ? '#000' : '#fff' }); // Change linked value $(fb.callback).each(function() { if (this.value && this.value != fb.color) { this.value = fb.color; } }); } else if (typeof fb.callback == 'function') { fb.callback.call(fb, fb.color); } } /** * Get absolute position of element */ fb.absolutePosition = function (el) { var r = { x: el.offsetLeft, y: el.offsetTop }; // Resolve relative to offsetParent if (el.offsetParent) { var tmp = fb.absolutePosition(el.offsetParent); r.x += tmp.x; r.y += tmp.y; } return r; }; /* Various color utility functions */ fb.pack = function (rgb) { var r = Math.round(rgb[0] * 255); var g = Math.round(rgb[1] * 255); var b = Math.round(rgb[2] * 255); return '#' + (r < 16 ? '0' : '') + r.toString(16) + (g < 16 ? '0' : '') + g.toString(16) + (b < 16 ? '0' : '') + b.toString(16); } fb.unpack = function (color) { if (color.length == 7) { return [parseInt('0x' + color.substring(1, 3)) / 255, parseInt('0x' + color.substring(3, 5)) / 255, parseInt('0x' + color.substring(5, 7)) / 255]; } else if (color.length == 4) { return [parseInt('0x' + color.substring(1, 2)) / 15, parseInt('0x' + color.substring(2, 3)) / 15, parseInt('0x' + color.substring(3, 4)) / 15]; } } fb.HSLToRGB = function (hsl) { var m1, m2, r, g, b; var h = hsl[0], s = hsl[1], l = hsl[2]; m2 = (l <= 0.5) ? l * (s + 1) : l + s - l*s; m1 = l * 2 - m2; return [this.hueToRGB(m1, m2, h+0.33333), this.hueToRGB(m1, m2, h), this.hueToRGB(m1, m2, h-0.33333)]; } fb.hueToRGB = function (m1, m2, h) { h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; if (h * 2 < 1) return m2; if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6; return m1; } fb.RGBToHSL = function (rgb) { var min, max, delta, h, s, l; var r = rgb[0], g = rgb[1], b = rgb[2]; min = Math.min(r, Math.min(g, b)); max = Math.max(r, Math.max(g, b)); delta = max - min; l = (min + max) / 2; s = 0; if (l > 0 && l < 1) { s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l)); } h = 0; if (delta > 0) { if (max == r && max != g) h += (g - b) / delta; if (max == g && max != b) h += (2 + (b - r) / delta); if (max == b && max != r) h += (4 + (r - g) / delta); h /= 6; } return [h, s, l]; } // Install mousedown handler (the others are set on the document on-demand) $('*', e).mousedown(fb.mousedown); // Init color fb.setColor('#000000'); // Set linked elements/callback if (callback) { fb.linkTo(callback); } } /** * http://github.com/valums/file-uploader * * Multiple file upload component with progress-bar, drag-and-drop. * © 2010 Andrew Valums ( andrew(at)valums.com ) * * Licensed under GNU GPL 2 or later and GNU LGPL 2 or later, see license.txt. */ // // Helper functions // var qq = qq || {}; /** * Adds all missing properties from second obj to first obj */ qq.extend = function(first, second){ for (var prop in second){ first[prop] = second[prop]; } }; /** * Searches for a given element in the array, returns -1 if it is not present. * @param {Number} [from] The index at which to begin the search */ qq.indexOf = function(arr, elt, from){ if (arr.indexOf) return arr.indexOf(elt, from); from = from || 0; var len = arr.length; if (from < 0) from += len; for (; from < len; from++){ if (from in arr && arr[from] === elt){ return from; } } return -1; }; qq.getUniqueId = (function(){ var id = 0; return function(){ return id++; }; })(); // // Events qq.attach = function(element, type, fn){ if (element.addEventListener){ element.addEventListener(type, fn, false); } else if (element.attachEvent){ element.attachEvent('on' + type, fn); } }; qq.detach = function(element, type, fn){ if (element.removeEventListener){ element.removeEventListener(type, fn, false); } else if (element.attachEvent){ element.detachEvent('on' + type, fn); } }; qq.preventDefault = function(e){ if (e.preventDefault){ e.preventDefault(); } else{ e.returnValue = false; } }; // // Node manipulations /** * Insert node a before node b. */ qq.insertBefore = function(a, b){ b.parentNode.insertBefore(a, b); }; qq.remove = function(element){ element.parentNode.removeChild(element); }; qq.contains = function(parent, descendant){ // compareposition returns false in this case if (parent == descendant) return true; if (parent.contains){ return parent.contains(descendant); } else { return !!(descendant.compareDocumentPosition(parent) & 8); } }; /** * Creates and returns element from html string * Uses innerHTML to create an element */ qq.toElement = (function(){ var div = document.createElement('div'); return function(html){ div.innerHTML = html; var element = div.firstChild; div.removeChild(element); return element; }; })(); // // Node properties and attributes /** * Sets styles for an element. * Fixes opacity in IE6-8. */ qq.css = function(element, styles){ if (styles.opacity != null){ if (typeof element.style.opacity != 'string' && typeof(element.filters) != 'undefined'){ styles.filter = 'alpha(opacity=' + Math.round(100 * styles.opacity) + ')'; } } qq.extend(element.style, styles); }; qq.hasClass = function(element, name){ var re = new RegExp('(^| )' + name + '( |$)'); return re.test(element.className); }; qq.addClass = function(element, name){ if (!qq.hasClass(element, name)){ element.className += ' ' + name; } }; qq.removeClass = function(element, name){ var re = new RegExp('(^| )' + name + '( |$)'); element.className = element.className.replace(re, ' ').replace(/^\s+|\s+$/g, ""); }; qq.setText = function(element, text){ element.innerText = text; element.textContent = text; }; // // Selecting elements qq.children = function(element){ var children = [], child = element.firstChild; while (child){ if (child.nodeType == 1){ children.push(child); } child = child.nextSibling; } return children; }; qq.getByClass = function(element, className){ if (element.querySelectorAll){ return element.querySelectorAll('.' + className); } var result = []; var candidates = element.getElementsByTagName("*"); var len = candidates.length; for (var i = 0; i < len; i++){ if (qq.hasClass(candidates[i], className)){ result.push(candidates[i]); } } return result; }; /** * obj2url() takes a json-object as argument and generates * a querystring. pretty much like jQuery.param() * * how to use: * * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');` * * will result in: * * `http://any.url/upload?otherParam=value&a=b&c=d` * * @param Object JSON-Object * @param String current querystring-part * @return String encoded querystring */ qq.obj2url = function(obj, temp, prefixDone){ var uristrings = [], prefix = '&', add = function(nextObj, i){ var nextTemp = temp ? (/\[\]$/.test(temp)) // prevent double-encoding ? temp : temp+'['+i+']' : i; if ((nextTemp != 'undefined') && (i != 'undefined')) { uristrings.push( (typeof nextObj === 'object') ? qq.obj2url(nextObj, nextTemp, true) : (Object.prototype.toString.call(nextObj) === '[object Function]') ? encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj()) : encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj) ); } }; if (!prefixDone && temp) { prefix = (/\?/.test(temp)) ? (/\?$/.test(temp)) ? '' : '&' : '?'; uristrings.push(temp); uristrings.push(qq.obj2url(obj)); } else if ((Object.prototype.toString.call(obj) === '[object Array]') && (typeof obj != 'undefined') ) { // we wont use a for-in-loop on an array (performance) for (var i = 0, len = obj.length; i < len; ++i){ add(obj[i], i); } } else if ((typeof obj != 'undefined') && (obj !== null) && (typeof obj === "object")){ // for anything else but a scalar, we will use for-in-loop for (var i in obj){ add(obj[i], i); } } else { uristrings.push(encodeURIComponent(temp) + '=' + encodeURIComponent(obj)); } return uristrings.join(prefix) .replace(/^&/, '') .replace(/%20/g, '+'); }; // // // Uploader Classes // // var qq = qq || {}; /** * Creates upload button, validates upload, but doesn't create file list or dd. */ qq.FileUploaderBasic = function(o){ this._options = { // set to true to see the server response debug: false, action: '/server/upload', params: {}, button: null, multiple: true, maxConnections: 3, // validation allowedExtensions: [], sizeLimit: 0, minSizeLimit: 0, // events // return false to cancel submit onSubmit: function(id, fileName){}, onProgress: function(id, fileName, loaded, total){}, onComplete: function(id, fileName, responseJSON){}, onCancel: function(id, fileName){}, // messages messages: { typeError: "{file} has invalid extension. Only {extensions} are allowed.", sizeError: "{file} is too large, maximum file size is {sizeLimit}.", minSizeError: "{file} is too small, minimum file size is {minSizeLimit}.", emptyError: "{file} is empty, please select files again without it.", onLeave: "The files are being uploaded, if you leave now the upload will be cancelled." }, showMessage: function(message){ alert(message); } }; qq.extend(this._options, o); // number of files being uploaded this._filesInProgress = 0; this._handler = this._createUploadHandler(); if (this._options.button){ this._button = this._createUploadButton(this._options.button); } this._preventLeaveInProgress(); }; qq.FileUploaderBasic.prototype = { setParams: function(params){ this._options.params = params; }, getInProgress: function(){ return this._filesInProgress; }, _createUploadButton: function(element){ var self = this; return new qq.UploadButton({ element: element, multiple: this._options.multiple && qq.UploadHandlerXhr.isSupported(), onChange: function(input){ self._onInputChange(input); } }); }, _createUploadHandler: function(){ var self = this, handlerClass; if(qq.UploadHandlerXhr.isSupported()){ handlerClass = 'UploadHandlerXhr'; } else { handlerClass = 'UploadHandlerForm'; } var handler = new qq[handlerClass]({ debug: this._options.debug, action: this._options.action, maxConnections: this._options.maxConnections, onProgress: function(id, fileName, loaded, total){ self._onProgress(id, fileName, loaded, total); self._options.onProgress(id, fileName, loaded, total); }, onComplete: function(id, fileName, result){ self._onComplete(id, fileName, result); self._options.onComplete(id, fileName, result); }, onCancel: function(id, fileName){ self._onCancel(id, fileName); self._options.onCancel(id, fileName); } }); return handler; }, _preventLeaveInProgress: function(){ var self = this; qq.attach(window, 'beforeunload', function(e){ if (!self._filesInProgress){return;} var e = e || window.event; // for ie, ff e.returnValue = self._options.messages.onLeave; // for webkit return self._options.messages.onLeave; }); }, _onSubmit: function(id, fileName){ this._filesInProgress++; }, _onProgress: function(id, fileName, loaded, total){ }, _onComplete: function(id, fileName, result){ this._filesInProgress--; if (result.error){ this._options.showMessage(result.error); } }, _onCancel: function(id, fileName){ this._filesInProgress--; }, _onInputChange: function(input){ if (this._handler instanceof qq.UploadHandlerXhr){ this._uploadFileList(input.files); } else { if (this._validateFile(input)){ this._uploadFile(input); } } this._button.reset(); }, _uploadFileList: function(files){ for (var i=0; i this._options.sizeLimit){ this._error('sizeError', name); return false; } else if (size && size < this._options.minSizeLimit){ this._error('minSizeError', name); return false; } return true; }, _error: function(code, fileName){ var message = this._options.messages[code]; function r(name, replacement){ message = message.replace(name, replacement); } r('{file}', this._formatFileName(fileName)); r('{extensions}', this._options.allowedExtensions.join(', ')); r('{sizeLimit}', this._formatSize(this._options.sizeLimit)); r('{minSizeLimit}', this._formatSize(this._options.minSizeLimit)); this._options.showMessage(message); }, _formatFileName: function(name){ if (name.length > 33){ name = name.slice(0, 19) + '...' + name.slice(-13); } return name; }, _isAllowedExtension: function(fileName){ var ext = (-1 !== fileName.indexOf('.')) ? fileName.replace(/.*[.]/, '').toLowerCase() : ''; var allowed = this._options.allowedExtensions; if (!allowed.length){return true;} for (var i=0; i 99); return Math.max(bytes, 0.1).toFixed(1) + ['kB', 'MB', 'GB', 'TB', 'PB', 'EB'][i]; } }; /** * Class that creates upload widget with drag-and-drop and file list * @inherits qq.FileUploaderBasic */ qq.FileUploader = function(o){ // call parent constructor qq.FileUploaderBasic.apply(this, arguments); // additional options qq.extend(this._options, { element: null, // if set, will be used instead of qq-upload-list in template listElement: null, template: '
' + '
Drop files here to upload
' + '
Upload a file
' + '
    ' + '
    ', // template for one item in file list fileTemplate: '
  • ' + '' + '' + '' + 'Cancel' + 'Failed' + '
  • ', classes: { // used to get elements from templates button: 'qq-upload-button', drop: 'qq-upload-drop-area', dropActive: 'qq-upload-drop-area-active', list: 'qq-upload-list', file: 'qq-upload-file', spinner: 'qq-upload-spinner', size: 'qq-upload-size', cancel: 'qq-upload-cancel', // added to list item when upload completes // used in css to hide progress spinner success: 'qq-upload-success', fail: 'qq-upload-fail' } }); // overwrite options with user supplied qq.extend(this._options, o); this._element = this._options.element; this._element.innerHTML = this._options.template; this._listElement = this._options.listElement || this._find(this._element, 'list'); this._classes = this._options.classes; this._button = this._createUploadButton(this._find(this._element, 'button')); this._bindCancelEvent(); this._setupDragDrop(); }; // inherit from Basic Uploader qq.extend(qq.FileUploader.prototype, qq.FileUploaderBasic.prototype); qq.extend(qq.FileUploader.prototype, { /** * Gets one of the elements listed in this._options.classes **/ _find: function(parent, type){ var element = qq.getByClass(parent, this._options.classes[type])[0]; if (!element){ throw new Error('element not found ' + type); } return element; }, _setupDragDrop: function(){ var self = this, dropArea = this._find(this._element, 'drop'); var dz = new qq.UploadDropZone({ element: dropArea, onEnter: function(e){ qq.addClass(dropArea, self._classes.dropActive); e.stopPropagation(); }, onLeave: function(e){ e.stopPropagation(); }, onLeaveNotDescendants: function(e){ qq.removeClass(dropArea, self._classes.dropActive); }, onDrop: function(e){ dropArea.style.display = 'none'; qq.removeClass(dropArea, self._classes.dropActive); self._uploadFileList(e.dataTransfer.files); } }); dropArea.style.display = 'none'; qq.attach(document, 'dragenter', function(e){ if (!dz._isValidFileDrag(e)) return; dropArea.style.display = 'block'; }); qq.attach(document, 'dragleave', function(e){ if (!dz._isValidFileDrag(e)) return; var relatedTarget = document.elementFromPoint(e.clientX, e.clientY); // only fire when leaving document out if ( ! relatedTarget || relatedTarget.nodeName == "HTML"){ dropArea.style.display = 'none'; } }); }, _onSubmit: function(id, fileName){ qq.FileUploaderBasic.prototype._onSubmit.apply(this, arguments); this._addToList(id, fileName); }, _onProgress: function(id, fileName, loaded, total){ qq.FileUploaderBasic.prototype._onProgress.apply(this, arguments); var item = this._getItemByFileId(id); var size = this._find(item, 'size'); size.style.display = 'inline'; var text; if (loaded != total){ text = Math.round(loaded / total * 100) + '% from ' + this._formatSize(total); } else { text = this._formatSize(total); } qq.setText(size, text); }, _onComplete: function(id, fileName, result){ qq.FileUploaderBasic.prototype._onComplete.apply(this, arguments); // mark completed var item = this._getItemByFileId(id); qq.remove(this._find(item, 'cancel')); qq.remove(this._find(item, 'spinner')); if (result.success){ qq.addClass(item, this._classes.success); } else { qq.addClass(item, this._classes.fail); } }, _addToList: function(id, fileName){ var item = qq.toElement(this._options.fileTemplate); item.qqFileId = id; var fileElement = this._find(item, 'file'); qq.setText(fileElement, this._formatFileName(fileName)); this._find(item, 'size').style.display = 'none'; this._listElement.appendChild(item); }, _getItemByFileId: function(id){ var item = this._listElement.firstChild; // there can't be txt nodes in dynamically created list // and we can use nextSibling while (item){ if (item.qqFileId == id) return item; item = item.nextSibling; } }, /** * delegate click event for cancel link **/ _bindCancelEvent: function(){ var self = this, list = this._listElement; qq.attach(list, 'click', function(e){ e = e || window.event; var target = e.target || e.srcElement; if (qq.hasClass(target, self._classes.cancel)){ qq.preventDefault(e); var item = target.parentNode; self._handler.cancel(item.qqFileId); qq.remove(item); } }); } }); qq.UploadDropZone = function(o){ this._options = { element: null, onEnter: function(e){}, onLeave: function(e){}, // is not fired when leaving element by hovering descendants onLeaveNotDescendants: function(e){}, onDrop: function(e){} }; qq.extend(this._options, o); this._element = this._options.element; this._disableDropOutside(); this._attachEvents(); }; qq.UploadDropZone.prototype = { _disableDropOutside: function(e){ // run only once for all instances if (!qq.UploadDropZone.dropOutsideDisabled ){ qq.attach(document, 'dragover', function(e){ if (e.dataTransfer){ e.dataTransfer.dropEffect = 'none'; e.preventDefault(); } }); qq.UploadDropZone.dropOutsideDisabled = true; } }, _attachEvents: function(){ var self = this; qq.attach(self._element, 'dragover', function(e){ if (!self._isValidFileDrag(e)) return; var effect = e.dataTransfer.effectAllowed; if (effect == 'move' || effect == 'linkMove'){ e.dataTransfer.dropEffect = 'move'; // for FF (only move allowed) } else { e.dataTransfer.dropEffect = 'copy'; // for Chrome } e.stopPropagation(); e.preventDefault(); }); qq.attach(self._element, 'dragenter', function(e){ if (!self._isValidFileDrag(e)) return; self._options.onEnter(e); }); qq.attach(self._element, 'dragleave', function(e){ if (!self._isValidFileDrag(e)) return; self._options.onLeave(e); var relatedTarget = document.elementFromPoint(e.clientX, e.clientY); // do not fire when moving a mouse over a descendant if (qq.contains(this, relatedTarget)) return; self._options.onLeaveNotDescendants(e); }); qq.attach(self._element, 'drop', function(e){ if (!self._isValidFileDrag(e)) return; e.preventDefault(); self._options.onDrop(e); }); }, _isValidFileDrag: function(e){ var dt = e.dataTransfer, // do not check dt.types.contains in webkit, because it crashes safari 4 isWebkit = navigator.userAgent.indexOf("AppleWebKit") > -1; // dt.effectAllowed is none in Safari 5 // dt.types.contains check is for firefox return dt && dt.effectAllowed != 'none' && (dt.files || (!isWebkit && dt.types.contains && dt.types.contains('Files'))); } }; qq.UploadButton = function(o){ this._options = { element: null, // if set to true adds multiple attribute to file input multiple: false, // name attribute of file input name: 'file', onChange: function(input){}, hoverClass: 'qq-upload-button-hover', focusClass: 'qq-upload-button-focus' }; qq.extend(this._options, o); this._element = this._options.element; // make button suitable container for input qq.css(this._element, { position: 'relative', overflow: 'hidden', // Make sure browse button is in the right side // in Internet Explorer direction: 'ltr' }); this._input = this._createInput(); }; qq.UploadButton.prototype = { /* returns file input element */ getInput: function(){ return this._input; }, /* cleans/recreates the file input */ reset: function(){ if (this._input.parentNode){ qq.remove(this._input); } qq.removeClass(this._element, this._options.focusClass); this._input = this._createInput(); }, _createInput: function(){ var input = document.createElement("input"); if (this._options.multiple){ input.setAttribute("multiple", "multiple"); } input.setAttribute("type", "file"); input.setAttribute("name", this._options.name); qq.css(input, { position: 'absolute', // in Opera only 'browse' button // is clickable and it is located at // the right side of the input right: 0, top: 0, fontFamily: 'Arial', // 4 persons reported this, the max values that worked for them were 243, 236, 236, 118 fontSize: '118px', margin: 0, padding: 0, cursor: 'pointer', opacity: 0 }); this._element.appendChild(input); var self = this; qq.attach(input, 'change', function(){ self._options.onChange(input); }); qq.attach(input, 'mouseover', function(){ qq.addClass(self._element, self._options.hoverClass); }); qq.attach(input, 'mouseout', function(){ qq.removeClass(self._element, self._options.hoverClass); }); qq.attach(input, 'focus', function(){ qq.addClass(self._element, self._options.focusClass); }); qq.attach(input, 'blur', function(){ qq.removeClass(self._element, self._options.focusClass); }); // IE and Opera, unfortunately have 2 tab stops on file input // which is unacceptable in our case, disable keyboard access if (window.attachEvent){ // it is IE or Opera input.setAttribute('tabIndex', "-1"); } return input; } }; /** * Class for uploading files, uploading itself is handled by child classes */ qq.UploadHandlerAbstract = function(o){ this._options = { debug: false, action: '/upload.php', // maximum number of concurrent uploads maxConnections: 999, onProgress: function(id, fileName, loaded, total){}, onComplete: function(id, fileName, response){}, onCancel: function(id, fileName){} }; qq.extend(this._options, o); this._queue = []; // params for files in queue this._params = []; }; qq.UploadHandlerAbstract.prototype = { log: function(str){ if (this._options.debug && window.console) console.log('[uploader] ' + str); }, /** * Adds file or file input to the queue * @returns id **/ add: function(file){}, /** * Sends the file identified by id and additional query params to the server */ upload: function(id, params){ var len = this._queue.push(id); var copy = {}; qq.extend(copy, params); this._params[id] = copy; // if too many active uploads, wait... if (len <= this._options.maxConnections){ this._upload(id, this._params[id]); } }, /** * Cancels file upload by id */ cancel: function(id){ this._cancel(id); this._dequeue(id); }, /** * Cancells all uploads */ cancelAll: function(){ for (var i=0; i= max && i < max){ var nextId = this._queue[max-1]; this._upload(nextId, this._params[nextId]); } } }; /** * Class for uploading files using form and iframe * @inherits qq.UploadHandlerAbstract */ qq.UploadHandlerForm = function(o){ qq.UploadHandlerAbstract.apply(this, arguments); this._inputs = {}; }; // @inherits qq.UploadHandlerAbstract qq.extend(qq.UploadHandlerForm.prototype, qq.UploadHandlerAbstract.prototype); qq.extend(qq.UploadHandlerForm.prototype, { add: function(fileInput){ fileInput.setAttribute('name', 'qqfile'); var id = 'qq-upload-handler-iframe' + qq.getUniqueId(); this._inputs[id] = fileInput; // remove file input from DOM if (fileInput.parentNode){ qq.remove(fileInput); } return id; }, getName: function(id){ // get input value and remove path to normalize return this._inputs[id].value.replace(/.*(\/|\\)/, ""); }, _cancel: function(id){ this._options.onCancel(id, this.getName(id)); delete this._inputs[id]; var iframe = document.getElementById(id); if (iframe){ // to cancel request set src to something else // we use src="javascript:false;" because it doesn't // trigger ie6 prompt on https iframe.setAttribute('src', 'javascript:false;'); qq.remove(iframe); } }, _upload: function(id, params){ var input = this._inputs[id]; if (!input){ throw new Error('file with passed id was not added, or already uploaded or cancelled'); } var fileName = this.getName(id); var iframe = this._createIframe(id); var form = this._createForm(iframe, params); form.appendChild(input); var self = this; this._attachLoadEvent(iframe, function(){ self.log('iframe loaded'); var response = self._getIframeContentJSON(iframe); self._options.onComplete(id, fileName, response); self._dequeue(id); delete self._inputs[id]; // timeout added to fix busy state in FF3.6 setTimeout(function(){ qq.remove(iframe); }, 1); }); form.submit(); qq.remove(form); return id; }, _attachLoadEvent: function(iframe, callback){ qq.attach(iframe, 'load', function(){ // when we remove iframe from dom // the request stops, but in IE load // event fires if (!iframe.parentNode){ return; } // fixing Opera 10.53 if (iframe.contentDocument && iframe.contentDocument.body && iframe.contentDocument.body.innerHTML == "false"){ // In Opera event is fired second time // when body.innerHTML changed from false // to server response approx. after 1 sec // when we upload file with iframe return; } callback(); }); }, /** * Returns json object received by iframe from server. */ _getIframeContentJSON: function(iframe){ // iframe.contentWindow.document - for IE<7 var doc = iframe.contentDocument ? iframe.contentDocument: iframe.contentWindow.document, response; this.log("converting iframe's innerHTML to JSON"); this.log("innerHTML = " + doc.body.innerHTML); try { response = eval("(" + doc.body.innerHTML + ")"); } catch(err){ response = {}; } return response; }, /** * Creates iframe with unique name */ _createIframe: function(id){ // We can't use following code as the name attribute // won't be properly registered in IE6, and new window // on form submit will open // var iframe = document.createElement('iframe'); // iframe.setAttribute('name', id); var iframe = qq.toElement('