OwlCyberSecurity - MANAGER
Edit File: dkb-global.js.tВlВchargement
/* * Metadata - jQuery plugin for parsing metadata from elements * * Copyright (c) 2006 John Resig, Yehuda Katz, J�örn Zaefferer, Paul McLanahan * * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * * Revision: $Id$ * */ /** * Sets the type of metadata to use. Metadata is encoded in JSON, and each property * in the JSON will become a property of the element itself. * * There are three supported types of metadata storage: * * attr: Inside an attribute. The name parameter indicates *which* attribute. * * class: Inside the class attribute, wrapped in curly braces: { } * * elem: Inside a child element (e.g. a script tag). The * name parameter indicates *which* element. * * The metadata for an element is loaded the first time the element is accessed via jQuery. * * As a result, you can define the metadata type, use $(expr) to load the metadata into the elements * matched by expr, then redefine the metadata type and run another $(expr) for other elements. * * @name $.metadata.setType * * @example <p id="one" class="some_class {item_id: 1, item_label: 'Label'}">This is a p</p> * @before $.metadata.setType("class") * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" * @desc Reads metadata from the class attribute * * @example <p id="one" class="some_class" data="{item_id: 1, item_label: 'Label'}">This is a p</p> * @before $.metadata.setType("attr", "data") * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" * @desc Reads metadata from a "data" attribute * * @example <p id="one" class="some_class"><script>{item_id: 1, item_label: 'Label'}</script>This is a p</p> * @before $.metadata.setType("elem", "script") * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" * @desc Reads metadata from a nested script element * * @param String type The encoding type * @param String name The name of the attribute to be used to get metadata (optional) * @cat Plugins/Metadata * @descr Sets the type of encoding to be used when loading metadata for the first time * @type undefined * @see metadata() */ (function($) { $.extend({ metadata : { defaults : { type: 'class', name: 'metadata', cre: /({.*})/, single: 'metadata' }, setType: function( type, name ){ this.defaults.type = type; this.defaults.name = name; }, get: function( elem, opts ){ var settings = $.extend({},this.defaults,opts); // check for empty string in single property if ( !settings.single.length ) settings.single = 'metadata'; var data = $.data(elem, settings.single); // returned cached data if it already exists if ( data ) return data; data = "{}"; if ( settings.type == "class" ) { var m = settings.cre.exec( elem.className ); if ( m ) data = m[1]; } else if ( settings.type == "elem" ) { if( !elem.getElementsByTagName ) return undefined; var e = elem.getElementsByTagName(settings.name); if ( e.length ) data = $.trim(e[0].innerHTML); } else if ( elem.getAttribute != undefined ) { var attr = elem.getAttribute( settings.name ); if ( attr ) data = attr; } if ( data.indexOf( '{' ) <0 ) data = "{" + data + "}"; data = eval("(" + data + ")"); // NOSONAR $.data( elem, settings.single, data ); return data; } } }); /** * Returns the metadata object for the first member of the jQuery object. * * @name metadata * @descr Returns element's metadata object * @param Object opts An object contianing settings to override the defaults * @type jQuery * @cat Plugins/Metadata */ $.fn.metadata = function( opts ){ return $.metadata.get( this[0], opts ); }; })(jQuery); // Expose jQuery to the global object window.jQuery = window.$ = jQuery; /* * Wird vermutlich nur noch in Zusammenhang mit jquery modal player verwendet (2.5.2017). Suche nach jQuery.tmpl( * * jQuery Templates Plugin 1.0.0pre * http://github.com/jquery/jquery-tmpl * Requires jQuery 1.4.2 * * Copyright Software Freedom Conservancy, Inc. * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license */ (function( jQuery, undefined ){ var oldManip = jQuery.fn.domManip, tmplItmAtt = "_tmplitem", htmlExpr = /^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /, newTmplItems = {}, wrappedItems = {}, appendToTmplItems, topTmplItem = { key: 0, data: {} }, itemKey = 0, cloneIndex = 0, stack = []; function newTmplItem( options, parentItem, fn, data ) { // Returns a template item data structure for a new rendered instance of a template (a 'template item'). // The content field is a hierarchical array of strings and nested items (to be // removed and replaced by nodes field of dom elements, once inserted in DOM). var newItem = { data: data || (data === 0 || data === false) ? data : (parentItem ? parentItem.data : {}), _wrap: parentItem ? parentItem._wrap : null, tmpl: null, parent: parentItem || null, nodes: [], calls: tiCalls, nest: tiNest, wrap: tiWrap, html: tiHtml, update: tiUpdate }; if ( options ) { jQuery.extend( newItem, options, { nodes: [], parent: parentItem }); } if ( fn ) { // Build the hierarchical content to be used during insertion into DOM newItem.tmpl = fn; newItem._ctnt = newItem._ctnt || newItem.tmpl( jQuery, newItem ); newItem.key = ++itemKey; // Keep track of new template item, until it is stored as jQuery Data on DOM element (stack.length ? wrappedItems : newTmplItems)[itemKey] = newItem; } return newItem; } // Override appendTo etc., in order to provide support for targeting multiple elements. (This code would disappear if integrated in jquery core). jQuery.each({ appendTo: "append", prependTo: "prepend", insertBefore: "before", insertAfter: "after", replaceAll: "replaceWith" }, function( name, original ) { jQuery.fn[ name ] = function( selector ) { var ret = [], insert = jQuery( selector ), elems, i, l, tmplItems, parent = this.length === 1 && this[0].parentNode; appendToTmplItems = newTmplItems || {}; if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) { insert[ original ]( this[0] ); ret = this; } else { for ( i = 0, l = insert.length; i < l; i++ ) { cloneIndex = i; elems = (i > 0 ? this.clone(true) : this).get(); jQuery( insert[i] )[ original ]( elems ); ret = ret.concat( elems ); } cloneIndex = 0; ret = this.pushStack( ret, name, insert.selector ); } tmplItems = appendToTmplItems; appendToTmplItems = null; jQuery.tmpl.complete( tmplItems ); return ret; }; }); jQuery.fn.extend({ // Use first wrapped element as template markup. // Return wrapped set of template items, obtained by rendering template against data. tmpl: function( data, options, parentItem ) { return jQuery.tmpl( this[0], data, options, parentItem ); }, // Find which rendered template item the first wrapped DOM element belongs to tmplItem: function() { return jQuery.tmplItem( this[0] ); }, // Consider the first wrapped element as a template declaration, and get the compiled template or store it as a named template. template: function( name ) { return jQuery.template( name, this[0] ); }, domManip: function( args, table, callback, options ) { if ( args[0] && jQuery.isArray( args[0] )) { var dmArgs = jQuery.makeArray( arguments ), elems = args[0], elemsLength = elems.length, i = 0, tmplItem; while ( i < elemsLength && !(tmplItem = jQuery.data( elems[i++], "tmplItem" ))) {} if ( tmplItem && cloneIndex ) { dmArgs[2] = function( fragClone ) { // Handler called by oldManip when rendered template has been inserted into DOM. jQuery.tmpl.afterManip( this, fragClone, callback ); }; } oldManip.apply( this, dmArgs ); } else { oldManip.apply( this, arguments ); } cloneIndex = 0; if ( !appendToTmplItems ) { jQuery.tmpl.complete( newTmplItems ); } return this; } }); jQuery.extend({ // Return wrapped set of template items, obtained by rendering template against data. tmpl: function( tmpl, data, options, parentItem ) { var ret, topLevel = !parentItem; if ( topLevel ) { // This is a top-level tmpl call (not from a nested template using {{tmpl}}) parentItem = topTmplItem; tmpl = jQuery.template[tmpl] || jQuery.template( null, tmpl ); wrappedItems = {}; // Any wrapped items will be rebuilt, since this is top level } else if ( !tmpl ) { // The template item is already associated with DOM - this is a refresh. // Re-evaluate rendered template for the parentItem tmpl = parentItem.tmpl; newTmplItems[parentItem.key] = parentItem; parentItem.nodes = []; if ( parentItem.wrapped ) { updateWrapped( parentItem, parentItem.wrapped ); } // Rebuild, without creating a new template item return jQuery( build( parentItem, null, parentItem.tmpl( jQuery, parentItem ) )); } if ( !tmpl ) { return []; // Could throw... } if ( typeof data === "function" ) { data = data.call( parentItem || {} ); } if ( options && options.wrapped ) { updateWrapped( options, options.wrapped ); } ret = jQuery.isArray( data ) ? jQuery.map( data, function( dataItem ) { return dataItem ? newTmplItem( options, parentItem, tmpl, dataItem ) : null; }) : [ newTmplItem( options, parentItem, tmpl, data ) ]; return topLevel ? jQuery( build( parentItem, null, ret ) ) : ret; }, // Return rendered template item for an element. tmplItem: function( elem ) { var tmplItem; if ( elem instanceof jQuery ) { elem = elem[0]; } while ( elem && elem.nodeType === 1 && !(tmplItem = jQuery.data( elem, "tmplItem" )) && (elem = elem.parentNode) ) {} return tmplItem || topTmplItem; }, // Set: // Use $.template( name, tmpl ) to cache a named template, // where tmpl is a template string, a script element or a jQuery instance wrapping a script element, etc. // Use $( "selector" ).template( name ) to provide access by name to a script block template declaration. // Get: // Use $.template( name ) to access a cached template. // Also $( selectorToScriptBlock ).template(), or $.template( null, templateString ) // will return the compiled template, without adding a name reference. // If templateString includes at least one HTML tag, $.template( templateString ) is equivalent // to $.template( null, templateString ) template: function( name, tmpl ) { if (tmpl) { // Compile template and associate with name if ( typeof tmpl === "string" ) { // This is an HTML string being passed directly in. tmpl = buildTmplFn( tmpl ) } else if ( tmpl instanceof jQuery ) { tmpl = tmpl[0] || {}; } if ( tmpl.nodeType ) { // If this is a template block, use cached copy, or generate tmpl function and cache. tmpl = jQuery.data( tmpl, "tmpl" ) || jQuery.data( tmpl, "tmpl", buildTmplFn( tmpl.innerHTML )); // Issue: In IE, if the container element is not a script block, the innerHTML will remove quotes from attribute values whenever the value does not include white space. // This means that foo="${x}" will not work if the value of x includes white space: foo="${x}" -> foo=value of x. // To correct this, include space in tag: foo="${ x }" -> foo="value of x" } return typeof name === "string" ? (jQuery.template[name] = tmpl) : tmpl; } // Return named compiled template return name ? (typeof name !== "string" ? jQuery.template( null, name ): (jQuery.template[name] || // If not in map, and not containing at least on HTML tag, treat as a selector. // (If integrated with core, use quickExpr.exec) jQuery.template( null, htmlExpr.test( name ) ? name : jQuery( name )))) : null; }, encode: function( text ) { // Do HTML encoding replacing < > & and ' and " by corresponding entities. return ("" + text).split("<").join("<").split(">").join(">").split('"').join(""").split("'").join("'"); } }); jQuery.extend( jQuery.tmpl, { tag: { "tmpl": { _default: { $2: "null" }, open: "if($notnull_1){__=__.concat($item.nest($1,$2));}" // tmpl target parameter can be of type function, so use $1, not $1a (so not auto detection of functions) // This means that {{tmpl foo}} treats foo as a template (which IS a function). // Explicit parens can be used if foo is a function that returns a template: {{tmpl foo()}}. }, "wrap": { _default: { $2: "null" }, open: "$item.calls(__,$1,$2);__=[];", close: "call=$item.calls();__=call._.concat($item.wrap(call,__));" }, "each": { _default: { $2: "$index, $value" }, open: "if($notnull_1){$.each($1a,function($2){with(this){", close: "}});}" }, "if": { open: "if(($notnull_1) && $1a){", close: "}" }, "else": { _default: { $1: "true" }, open: "}else if(($notnull_1) && $1a){" }, "html": { // Unecoded expression evaluation. open: "if($notnull_1){__.push($1a);}" }, "=": { // Encoded expression evaluation. Abbreviated form is ${}. _default: { $1: "$data" }, open: "if($notnull_1){__.push($.encode($1a));}" }, "!": { // Comment tag. Skipped by parser open: "" } }, // This stub can be overridden, e.g. in jquery.tmplPlus for providing rendered events complete: function( items ) { newTmplItems = {}; }, // Call this from code which overrides domManip, or equivalent // Manage cloning/storing template items etc. afterManip: function afterManip( elem, fragClone, callback ) { // Provides cloned fragment ready for fixup prior to and after insertion into DOM var content = fragClone.nodeType === 11 ? jQuery.makeArray(fragClone.childNodes) : fragClone.nodeType === 1 ? [fragClone] : []; // Return fragment to original caller (e.g. append) for DOM insertion callback.call( elem, fragClone ); // Fragment has been inserted:- Add inserted nodes to tmplItem data structure. Replace inserted element annotations by jQuery.data. storeTmplItems( content ); cloneIndex++; } }); //========================== Private helper functions, used by code above ========================== function build( tmplItem, nested, content ) { // Convert hierarchical content into flat string array // and finally return array of fragments ready for DOM insertion var frag, ret = content ? jQuery.map( content, function( item ) { return (typeof item === "string") ? // Insert template item annotations, to be converted to jQuery.data( "tmplItem" ) when elems are inserted into DOM. (tmplItem.key ? item.replace( /(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g, "$1 " + tmplItmAtt + "=\"" + tmplItem.key + "\" $2" ) : item) : // This is a child template item. Build nested template. build( item, tmplItem, item._ctnt ); }) : // If content is not defined, insert tmplItem directly. Not a template item. May be a string, or a string array, e.g. from {{html $item.html()}}. tmplItem; if ( nested ) { return ret; } // top-level template ret = ret.join(""); // Support templates which have initial or final text nodes, or consist only of text // Also support HTML entities within the HTML markup. ret.replace( /^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/, function( all, before, middle, after) { frag = jQuery( middle ).get(); storeTmplItems( frag ); if ( before ) { frag = unencode( before ).concat(frag); } if ( after ) { frag = frag.concat(unencode( after )); } }); return frag ? frag : unencode( ret ); } function unencode( text ) { // Use createElement, since createTextNode will not render HTML entities correctly var el = document.createElement( "div" ); el.innerHTML = text; return jQuery.makeArray(el.childNodes); } // Generate a reusable function that will serve to render a template against data function buildTmplFn( markup ) { return new Function("jQuery","$item", // Use the variable __ to hold a string array while building the compiled template. (See https://github.com/jquery/jquery-tmpl/issues#issue/10). "var $=jQuery,call,__=[],$data=$item.data;" + // Introduce the data as local variables using with(){} "with($data){__.push('" + // Convert the template into pure JavaScript jQuery.trim(markup) .replace( /([\\'])/g, "\\$1" ) .replace( /[\r\t\n]/g, " " ) .replace( /\$\{([^\}]*)\}/g, "{{= $1}}" ) .replace( /\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g, function( all, slash, type, fnargs, target, parens, args ) { var tag = jQuery.tmpl.tag[ type ], def, expr, exprAutoFnDetect; if ( !tag ) { throw "Unknown template tag: " + type; } def = tag._default || []; if ( parens && !/\w$/.test(target)) { target += parens; parens = ""; } if ( target ) { target = unescape( target ); args = args ? ("," + unescape( args ) + ")") : (parens ? ")" : ""); // Support for target being things like a.toLowerCase(); // In that case don't call with template item as 'this' pointer. Just evaluate... expr = parens ? (target.indexOf(".") > -1 ? target + unescape( parens ) : ("(" + target + ").call($item" + args)) : target; exprAutoFnDetect = parens ? expr : "(typeof(" + target + ")==='function'?(" + target + ").call($item):(" + target + "))"; } else { exprAutoFnDetect = expr = def.$1 || "null"; } fnargs = unescape( fnargs ); return "');" + tag[ slash ? "close" : "open" ] .split( "$notnull_1" ).join( target ? "typeof(" + target + ")!=='undefined' && (" + target + ")!=null" : "true" ) .split( "$1a" ).join( exprAutoFnDetect ) .split( "$1" ).join( expr ) .split( "$2" ).join( fnargs || def.$2 || "" ) + "__.push('"; }) + "');}return __;" ); } function updateWrapped( options, wrapped ) { // Build the wrapped content. options._wrap = build( options, true, // Suport imperative scenario in which options.wrapped can be set to a selector or an HTML string. jQuery.isArray( wrapped ) ? wrapped : [htmlExpr.test( wrapped ) ? wrapped : jQuery( wrapped ).html()] ).join(""); } function unescape( args ) { return args ? args.replace( /\\'/g, "'").replace(/\\\\/g, "\\" ) : null; } function outerHtml( elem ) { var div = document.createElement("div"); div.appendChild( elem.cloneNode(true) ); return div.innerHTML; } // Store template items in jQuery.data(), ensuring a unique tmplItem data data structure for each rendered template instance. function storeTmplItems( content ) { var keySuffix = "_" + cloneIndex, elem, elems, newClonedItems = {}, i, l, m; for ( i = 0, l = content.length; i < l; i++ ) { if ( (elem = content[i]).nodeType !== 1 ) { continue; } elems = elem.getElementsByTagName("*"); for ( m = elems.length - 1; m >= 0; m-- ) { processItemKey( elems[m] ); } processItemKey( elem ); } function processItemKey( el ) { var pntKey, pntNode = el, pntItem, tmplItem, key; // Ensure that each rendered template inserted into the DOM has its own template item, if ( (key = el.getAttribute( tmplItmAtt ))) { while ( pntNode.parentNode && (pntNode = pntNode.parentNode).nodeType === 1 && !(pntKey = pntNode.getAttribute( tmplItmAtt ))) { } if ( pntKey !== key ) { // The next ancestor with a _tmplitem expando is on a different key than this one. // So this is a top-level element within this template item // Set pntNode to the key of the parentNode, or to 0 if pntNode.parentNode is null, or pntNode is a fragment. pntNode = pntNode.parentNode ? (pntNode.nodeType === 11 ? 0 : (pntNode.getAttribute( tmplItmAtt ) || 0)) : 0; if ( !(tmplItem = newTmplItems[key]) ) { // The item is for wrapped content, and was copied from the temporary parent wrappedItem. tmplItem = wrappedItems[key]; tmplItem = newTmplItem( tmplItem, newTmplItems[pntNode]||wrappedItems[pntNode] ); tmplItem.key = ++itemKey; newTmplItems[itemKey] = tmplItem; } if ( cloneIndex ) { cloneTmplItem( key ); } } el.removeAttribute( tmplItmAtt ); } else if ( cloneIndex && (tmplItem = jQuery.data( el, "tmplItem" )) ) { // This was a rendered element, cloned during append or appendTo etc. // TmplItem stored in jQuery data has already been cloned in cloneCopyEvent. We must replace it with a fresh cloned tmplItem. cloneTmplItem( tmplItem.key ); newTmplItems[tmplItem.key] = tmplItem; pntNode = jQuery.data( el.parentNode, "tmplItem" ); pntNode = pntNode ? pntNode.key : 0; } if ( tmplItem ) { pntItem = tmplItem; // Find the template item of the parent element. // (Using !=, not !==, since pntItem.key is number, and pntNode may be a string) while ( pntItem && pntItem.key != pntNode ) { // Add this element as a top-level node for this rendered template item, as well as for any // ancestor items between this item and the item of its parent element pntItem.nodes.push( el ); pntItem = pntItem.parent; } // Delete content built during rendering - reduce API surface area and memory use, and avoid exposing of stale data after rendering... delete tmplItem._ctnt; delete tmplItem._wrap; // Store template item as jQuery data on the element jQuery.data( el, "tmplItem", tmplItem ); } function cloneTmplItem( key ) { key = key + keySuffix; tmplItem = newClonedItems[key] = (newClonedItems[key] || newTmplItem( tmplItem, newTmplItems[tmplItem.parent.key + keySuffix] || tmplItem.parent )); } } } //---- Helper functions for template item ---- function tiCalls( content, tmpl, data, options ) { if ( !content ) { return stack.pop(); } stack.push({ _: content, tmpl: tmpl, item:this, data: data, options: options }); } function tiNest( tmpl, data, options ) { // nested template, using {{tmpl}} tag return jQuery.tmpl( jQuery.template( tmpl ), data, options, this ); } function tiWrap( call, wrapped ) { // nested template, using {{wrap}} tag var options = call.options || {}; options.wrapped = wrapped; // Apply the template, which may incorporate wrapped content, return jQuery.tmpl( jQuery.template( call.tmpl ), call.data, options, call.item ); } function tiHtml( filter, textOnly ) { var wrapped = this._wrap; return jQuery.map( jQuery( jQuery.isArray( wrapped ) ? wrapped.join("") : wrapped ).filter( filter || "*" ), function(e) { return textOnly ? e.innerText || e.textContent : e.outerHTML || outerHtml(e); }); } function tiUpdate() { var coll = this.nodes; jQuery.tmpl( null, null, null, this).insertBefore( coll[0] ); jQuery( coll ).remove(); } })( jQuery ); /** * Wird noch verwendet (2.5.2017). Bspw. im Finanzstatus jQuery.scrollTo(...) (nicht zu verwechseln mit window.scrollTo(x,y)) * * jQuery.ScrollTo * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com * Dual licensed under MIT and GPL. * Date: 5/25/2009 * * @projectDescription Easy element scrolling using jQuery. * http://flesler.blogspot.com/2007/10/jqueryscrollto.html * Works with jQuery +1.2.6. Tested on FF 2/3, IE 6/7/8, Opera 9.5/6, Safari 3, Chrome 1 on WinXP. * * @author Ariel Flesler * @version 1.4.2 * * @id jQuery.scrollTo * @id jQuery.fn.scrollTo * @param {String, Number, DOMElement, jQuery, Object} target Where to scroll the matched elements. * The different options for target are: * - A number position (will be applied to all axes). * - A string position ('44', '100px', '+=90', etc ) will be applied to all axes * - A jQuery/DOM element ( logically, child of the element to scroll ) * - A string selector, that will be relative to the element to scroll ( 'li:eq(2)', etc ) * - A hash { top:x, left:y }, x and y can be any kind of number/string like above. * - A percentage of the container's dimension/s, for example: 50% to go to the middle. * - The string 'max' for go-to-end. * @param {Number} duration The OVERALL length of the animation, this argument can be the settings object instead. * @param {Object,Function} settings Optional set of settings or the onAfter callback. * @option {String} axis Which axis must be scrolled, use 'x', 'y', 'xy' or 'yx'. * @option {Number} duration The OVERALL length of the animation. * @option {String} easing The easing method for the animation. * @option {Boolean} margin If true, the margin of the target element will be deducted from the final position. * @option {Object, Number} offset Add/deduct from the end position. One number for both axes or { top:x, left:y }. * @option {Object, Number} over Add/deduct the height/width multiplied by 'over', can be { top:x, left:y } when using both axes. * @option {Boolean} queue If true, and both axis are given, the 2nd axis will only be animated after the first one ends. * @option {Function} onAfter Function to be called after the scrolling ends. * @option {Function} onAfterFirst If queuing is activated, this function will be called after the first scrolling ends. * @return {jQuery} Returns the same jQuery object, for chaining. * * @desc Scroll to a fixed position * @example $('div').scrollTo( 340 ); * * @desc Scroll relatively to the actual position * @example $('div').scrollTo( '+=340px', { axis:'y' } ); * * @dec Scroll using a selector (relative to the scrolled element) * @example $('div').scrollTo( 'p.paragraph:eq(2)', 500, { easing:'swing', queue:true, axis:'xy' } ); * * @ Scroll to a DOM element (same for jQuery object) * @example var second_child = document.getElementById('container').firstChild.nextSibling; * $('#container').scrollTo( second_child, { duration:500, axis:'x', onAfter:function(){ * alert('scrolled!!'); * }}); * * @desc Scroll on both axes, to different values * @example $('div').scrollTo( { top: 300, left:'+=200' }, { axis:'xy', offset:-20 } ); */ ;(function( $ ){ var $scrollTo = $.scrollTo = function( target, duration, settings ){ $(window).scrollTo( target, duration, settings ); }; $scrollTo.defaults = { axis:'xy', duration: parseFloat($.fn.jquery) >= 1.3 ? 0 : 1 }; // Returns the element that needs to be animated to scroll the window. // Kept for backwards compatibility (specially for localScroll & serialScroll) $scrollTo.window = function( scope ){ return $(window)._scrollable(); }; // Hack, hack, hack :) // Returns the real elements to scroll (supports window/iframes, documents and regular nodes) $.fn._scrollable = function(){ return this.map(function(){ var elem = this, isWin = !elem.nodeName || $.inArray( elem.nodeName.toLowerCase(), ['iframe','#document','html','body'] ) != -1; if( !isWin ) return elem; var doc = (elem.contentWindow || elem).document || elem.ownerDocument || elem; return $.browser.safari || doc.compatMode == 'BackCompat' ? doc.body : doc.documentElement; }); }; $.fn.scrollTo = function( target, duration, settings ){ if( typeof duration == 'object' ){ settings = duration; duration = 0; } if( typeof settings == 'function' ) settings = { onAfter:settings }; if( target == 'max' ) target = 9e9; settings = $.extend( {}, $scrollTo.defaults, settings ); // Speed is still recognized for backwards compatibility duration = duration || settings.speed || settings.duration; // Make sure the settings are given right settings.queue = settings.queue && settings.axis.length > 1; if( settings.queue ) // Let's keep the overall duration duration /= 2; settings.offset = both( settings.offset ); settings.over = both( settings.over ); return this._scrollable().each(function(){ var elem = this, $elem = $(elem), targ = target, toff, attr = {}, win = $elem.is('html,body'); switch( typeof targ ){ // A number will pass the regex case 'number': case 'string': if( /^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(targ) ){ targ = both( targ ); // We are done break; } // Relative selector, no break! targ = $(targ,this); case 'object': // DOMElement / jQuery if( targ.is || targ.style ) // Get the real position of the target toff = (targ = $(targ)).offset(); } $.each( settings.axis.split(''), function( i, axis ){ var Pos = axis == 'x' ? 'Left' : 'Top', pos = Pos.toLowerCase(), key = 'scroll' + Pos, old = elem[key], max = $scrollTo.max(elem, axis); if( toff ){// jQuery / DOMElement attr[key] = toff[pos] + ( win ? 0 : old - $elem.offset()[pos] ); // If it's a dom element, reduce the margin if( settings.margin ){ attr[key] -= parseInt(targ.css('margin'+Pos)) || 0; attr[key] -= parseInt(targ.css('border'+Pos+'Width')) || 0; } attr[key] += settings.offset[pos] || 0; if( settings.over[pos] ) // Scroll to a fraction of its width/height attr[key] += targ[axis=='x'?'width':'height']() * settings.over[pos]; }else{ var val = targ[pos]; // Handle percentage values attr[key] = val.slice && val.slice(-1) == '%' ? parseFloat(val) / 100 * max : val; } // Number or 'number' if( /^\d+$/.test(attr[key]) ) // Check the limits attr[key] = attr[key] <= 0 ? 0 : Math.min( attr[key], max ); // Queueing axes if( !i && settings.queue ){ // Don't waste time animating, if there's no need. if( old != attr[key] ) // Intermediate animation animate( settings.onAfterFirst ); // Don't animate this axis again in the next iteration. delete attr[key]; } }); animate( settings.onAfter ); function animate( callback ){ $elem.animate( attr, duration, settings.easing, callback && function(){ callback.call(this, target, settings); }); }; }).end(); }; // Max scrolling position, works on quirks mode // It only fails (not too badly) on IE, quirks mode. $scrollTo.max = function( elem, axis ){ var Dim = axis == 'x' ? 'Width' : 'Height', scroll = 'scroll'+Dim; if( !$(elem).is('html,body') ) return elem[scroll] - $(elem)[Dim.toLowerCase()](); var size = 'client' + Dim, html = elem.ownerDocument.documentElement, body = elem.ownerDocument.body; return Math.max( html[scroll], body[scroll] ) - Math.min( html[size] , body[size] ); }; function both( val ){ return typeof val == 'object' ? val : { top:val, left:val }; }; })( jQuery ); /** * deprecated * * This will create/augment a global variable "iTim" with the following goals in mind: * - store global references centrally somewhere beneath iTim (e.g. iTim.Page.yourStuff) * - provide (just basic) tool functions without having to rely on some larger framework (see iTim.ns, iTim.url, iTim.format) * - deploy a minimum of polyfills (atob/btoa, JSON) */ (function(window) { var iTim = window.iTim || {}; var de = document.documentElement; iTim.debug = !!iTim.debug; /** * Merges all arguments with index 1 to n into argument 0 by assigning each property. */ iTim.extend = function(obj) { for (var i = 1, length = arguments.length; i < length; ++i) { for ( var p in arguments[i]) { obj[p] = arguments[i][p]; } } return obj; }; iTim.extend(iTim, { /** * Simply logs all arguments into the console if applicable. * Tries to work around IE not supporting console.log.apply * @return Object The last argument given */ log: function() { if (this.debug && window.console) { if (!console.log.apply) { // for ie var evilEval = []; for (var i = 0, l = arguments.length; i < l; ++i) { evilEval.push('arguments[' + i + ']'); } console.log(evilEval.join(',')); } else { console.log.apply(console, arguments); } } return arguments[arguments.length - 1]; }, /** * Iterate over an object: * * by numeric index, if a length property is present * * by properties * Executes fn with "this" bound to scope, if given. If not, this is bound to the value at a given index. * Arguments for fn: * * this -> the value * * arg0 -> the index * * arg1 -> the value (again) * * arg2 -> the object being iterated over */ each: function(obj, fn, scope) { fn = scope ? (function (oldFn) { return function () { oldFn.apply(scope, arguments); }; })(fn) : fn; if (obj.length) { for ( var i = 0, length = obj.length; i < length; ++i) { if (false === fn.call(obj[i], i, obj[i], obj)) { return; } } } else { for ( var i in obj) if (obj.hasOwnProperty(i)) { if (false === fn.call(obj[i], i, obj[i], obj)) { return; } } } }, /** * Defines all properties needed to "successfully evaluate the reference" given in ns. * * Example: * * ns = "Nested.Nonexisting.Example.Namespace" * * root = window.iTim * * obj = {foo: '123'} * * call: iTim.ns("Nested.Nonexisting.Example.Namespace", iTim, {foo: "123"}); * * This results in this statement being valid: * alert(iTim.Nested.Nonexisting.Example.Namespace.foo); // prints "123" * * root is optional and defaults to window. * obj is optional and will be merged into the topmost oject in the path. */ ns: function(ns, root, obj) { root = root || window; iTim.each(ns.split('.'), function() { root = root[this] = root[this] || {}; }); if (obj) { this.extend(root, obj); } return root; }, /** * Normalizes all whitespace to a single space and removes leading and trailing whitespace. */ trim: function (s) { s = (s || '').replace(/^\s+|\s+$/g, ''); s = s.replace(/\s+/g, ' '); return s; }, /** * Creates a new object of which the prototype is bound to obj. * A reference to the "super" object is stored in __prototype. * A method therefore can call its "super" implementation as follows: * this.__prototype.myMethodName.apply(this, arguments); */ object: function(obj) { var F = function() {}; F.prototype = obj; var newObj = new F(); newObj.__prototype = obj; return newObj; }, /** * Augments obj or a newly created object with methods createEvent, subscribe, unsubscribe, fire to make it observable. */ observable: function (obj) { obj = obj || {}; this.extend(obj, { listeners: null, createEvent: function (eventName) { this.listeners = this.listeners || {}; if (this.listeners[eventName]) { throw 'event already registered: ' + eventName; } this.listeners[eventName] = []; }, subscribe: function (eventName, fn) { this.listeners[eventName].push(fn); }, unsubscribe: function (eventName, fn) { iTim.each(this.listeners[eventName], function (index, listener) { if (listener === fn) { this.listeners[eventName].splice(index, 1); return false; } }, this); }, fire: function (eventName, obj, scope) { scope = scope || window; iTim.each(this.listeners[eventName], function () { this.call(scope, obj); }); } }); return obj; }, /** * Returns a function that calls fn() only if it hasn't been invoked with the same argument before. */ memoize: function (fn, memo) { memo = memo || {}; return function (arg) { if (memo[arg]) { return memo[arg]; } return memo[arg] = fn.call(this, arg); }; }, /** * Replaces all occurrences of placeholders like {0} or {1} by the given argument at * the corresponding + 1. Example: * iTim.format('The {0} dog {1} over some {2} animal for the {3}th time.', 'stupid', 'trips', 'red', 5); */ format: function(template) { var args = arguments; return template.replace(/(\\?)\{(\d+)\}/g, function(match, escaped, name) { if (escaped) return match; return args[++name]; }); }, /** * Returns a function that executes fn with "this" bound to scope. */ bind: function(fn, scope) { return function() { return fn.apply(scope, arguments); }; }, /** * Returns a "location"-like object containing additional properties * for a given href that detail things like Query-Parameters or directories in the path. * (A detailed description can be found in the wiki.) * The resulting object supports a method resolve(url) which can be used to merge * another href/url-object into a new one (experimental). */ url: function (str) { var url = { href: '' + str, resolve: function (u) { if (!u.pathname) { u = iTim.url(u); } if (u.host) { return u; } var d = []; if (!u.absolute) { d.push.apply(d, this.directories); } d.push.apply(d, u.directories); var i = 0; while (d[i] !== undefined) { if (d[i] == '.') { d.splice(i,1); } else if(d[i] == '..') { if (i > 0) { d.splice(i - 1, 2); --i; } else { d.splice(i, 1); } } else { ++i; } } var r = d.join('/') + '/' + u.file + u.search + u.hash; if (this.absolute) { r = this.protocol + (this.host && this.protocol ? '//' : '') + this.host + (r.charAt(0) != '/' ? '/' : '') + r; } else if (u.absolute) { r = (r.charAt(0) != '/' ? '/' : '') + r; } return iTim.url(r); } }; str = { str: '' + str, toString: function(){ return this.str; }, get: function (x, p) { var r = x.exec(this.str); this.str = this.str.replace(x, ''); return r ? r[+p || 0] : ''; } }; url.hash = str.get(/#.*$/); url.search = str.get(/\?.*$/); url.protocol = str.get(/^\w+:/); url.hostname = str.toString().indexOf('//') == 0 ? str.get(/^(\/\/)([\w.\-]+)/, 2) : ''; url.port = str.get(/^:(\d+)/, 1); url.host = url.hostname + (url.port ? ':' + url.port : ''); url.pathname = str.toString(); url.path = str.get(/^.*\/[.]{0,2}/); url.absolute = url.path.charAt(0) == '/' || !!url.host; url.local = !url.host || url.host == location.host; url.extension = str.get(/\.\w+$/); url.filename = str.toString(); url.file = url.filename + url.extension; url.directories = []; url.path.replace(/([^\/]+|\/\/)/g, function (m, c) { if (c == '//') { url.directories.push(''); } else { url.directories.push(c); } }); function params(s) { var p = {}; s.replace(/([\w_]+)(?:\[\])?=([^&]+)/g, function (m, n, c) { if (p[n] !== undefined) { if (typeof p[n] == 'string') { p[n] = [p[n]]; } p[n].push(c); } else { p[n] = c; } }); return p; } url.searchParams = params(url.search); url.hashParams = params(url.hash); url.params = this.extend({}, url.searchParams, url.hashParams); return url; }, /** * Pass an object with properties width, height, toWidth, toHeight and fitTo. * fitTo may be: inside, outside, scale, height, width, stretch. * See PHP Panya::resize() for documentation. */ resize: function (opt) { with (opt) { var fitTo = fitTo || 'inside'; var width = +width || 1; var height = +height || 1; var toWidth = +toWidth || 0; var toHeight = +toHeight || 0; var fromWidth = width; var fromHeight = height; var toRatio = toWidth && toHeight ? toWidth / toHeight : null; if (!toRatio) { if (fitTo == 'scale') { if (!toHeight) { toHeight = toWidth; } else { toWidth = toHeight; } } else if (!toWidth) { fitTo = 'height'; } else if (!toHeight) { fitTo = 'width'; } else { fitTo = 'none'; } } var ratio = width / height; switch (fitTo) { case 'inside': if (ratio > toRatio) { if (width > toWidth) { height = toWidth / width * height; width = toWidth; } } else { if (height > toHeight) { width = toHeight / height * width; height = toHeight; } } break; case 'outside': if (ratio > toRatio) { width = toHeight / height * width; height = toHeight; } else { height = toWidth / width * height; width = toWidth; } break; case 'scale': width *= toWidth; height *= toHeight; break; case 'stretch': width = toWidth; height = toHeight; break; case 'width': if (width > toWidth) { height = toWidth / width * height; width = toWidth; } break; case 'height': if (height > toHeight) { width = toHeight / height * width; height = toHeight; } break; } var changed = fromWidth != width || fromHeight != height; var format = ratio > 1 ? 'landscape' : (ratio < 1 ? 'portrait' : 'square'); var result = { fitTo: fitTo, width: width, height: height, toHeight: toHeight, toWidth: toWidth, changed: changed, fromRatio: ratio, toRatio: toRatio, ratio: width / height, format: format, left: (toWidth - width) / 2, top: (toHeight - height) / 2 }; return result; } }, /** * Converts a hyphen/underscore divided string into camel-case. */ ccase: function (s) { return ('' + s).replace(/[-_]([a-z])/g, function (m, l) { return l.toUpperCase(); }); }, /** * Returns str with regex symbols having been escaped. */ escapeRegex: function (str) { return (str || '').replace(/[.\\(){}\[\]*+^$\-?]/g, function (m) { return '\\' + m; }); }, /** * Returns a globally unique id. * If an object is passed in, that objects id property is set to that value. */ id: (function () { var nextId = 1; return function (el) { var id = 'itim_' + nextId++; if (el) { if (el.id) { id = el.id; } else { el.id = id; } } return id; }; })(), /** * Polls global scope for a given property and calls fn if found. */ waitFor: function (symbol, fn) { return function(){ if (window[symbol]) { return fn.apply(this, arguments); } var tries = 0, args = arguments, that = this; var interval = setInterval(function() { if (window[symbol] || tries++ > 150) { clearInterval(interval); } if (window[symbol]) { fn.apply(that, args); } }, 70); }; }, /** * Put anything in here that might help centralize analytics. */ Tracking: {}, /** * Put everything in here that would otherwise end in the global scope. (Please -- Pretty please?) */ Page: {}, /** * Fill this hash to enable iTim.translate() to provide basic localization. */ translations: {}, /** * Returns localized text for a given key and the language currently active. * Returns defaultLabel, if no translation exists. * Returns key in any other case. */ translate: function (key, defaultLabel) { return this.translations[key] || defaultLabel || key; }, init : function() { var de = document.documentElement; var isIframe = false; try { isIframe = window.frameElement || window.parent != self; } catch (ex) { isIframe = true; } this.currentLang = this.currentLang || de.getAttribute("xml:lang") || de.getAttribute("lang"); if (!this.currentLang) { var meta = document.getElementsByTagName("meta"); for ( var i = 0, length = meta.length; i < length; ++i) { var tag = meta[i]; if ((tag.getAttribute("http-equiv") || tag.getAttribute("name") || "").match(/^(?:content-language|lang)$/i)) { this.currentLang = tag.getAttribute("content"); } } } this.currentLang = this.currentLang || (navigator.browserLanguage || navigator.language).substring(0, 2); de.className += " js " + this.currentLang + (isIframe ? ' iframe ' : ''); } }); window.iTim = iTim; })(window); (function (iTim) { /** * TODO: remove jquery dependency * Use this to store option hashes centrally. * These stored options hashes can "inherit" from another stored hash. * Inheritance is resolved upon setting and/or retrieval with get(opt) */ iTim.StoredOptions = { items: {}, keyInherits: 'inherits', /** * Retrieve an option hash. If opt is a key in this.items, a copy of that hash is created. * While the inheritance key is set on the resulting objects these are resolved * until none applies. * The resulting object is always a copy. */ get: function (opt) { if (!opt) { return {}; } if (this.items[opt]) { return this.items[opt]; } if (opt[this.keyInherits]) { var parent = this.get(opt[this.keyInherits]); parent = this.get(parent); opt = jQuery.extend(true, {}, parent, opt); delete opt[this.keyInherits]; return opt; } return opt; }, /** * Saves a hash under the given name. * Try to not reference DOM Elements in here as deep merges on retrieval could have * unforeseen results. */ set: function (name, opt) { if (opt[this.keyInherits]) { opt = this.get(opt); } return this.items[name] = opt; } }; })(iTim); /* itools Accordion version 1.2 */ (function ($) { var options = { }; var AccordionElementClass = function (el, opt) { this.options = {}; this.accordion = el; this.debug = false; this.accordionItems = {}; this.accordionItemsContent = []; this.init = function (object, opt) { var defaults = { "api": true, "multi": false, "initOpen": false, "slideSpeed": 500, "debug": false, "levelClasses": true, "moreText": { "use": false, "openText": "mehr (Default Text)", "closeText": "weniger (Default Text)" }, "selectors": { "activeClass": "open", "item": ".accordionItem", "content": ".accordionContent", "eventContainer": ".accordionLink", "moreTextTarget": ".accordionLinkTarget", "itemLevel": "accordionItemLevel" }, "autoScroll":{ "use": true, "scrollToPlugin": { "use": true, "speed": 300, "offset": 98 } }, "callbacks": { "init": this.callbackInit, "clicked": this.callbackClicked } }; this.options = jQuery.extend(true, defaults, opt); if(this.options.debug) { console.log("Current options:", this.options); } this.accordion.addClass("jQueryPluginAccordionProceed"); this.initAccordion(); this.initOpenElements(); }; this.initOpenElements = function () { var opt = this.options; if(typeof(this.options.initOpen) == 'number' || jQuery.isArray(this.options.initOpen)) { var elements = $(this.options.selectors.eventContainer, this.accordion); if(typeof(this.options.initOpen) == 'number') { this.options.initOpen = [this.options.initOpen]; } for (var i=0;i<this.options.initOpen.length;i++) { $(elements[this.options.initOpen[i]]).trigger("click"); if(!this.options.multi) { break; } } } if (location.hash && location.hash != '#') { if($('body').find(location.hash).length > 0) { if(this.options.debug) { console.log("Has tag was found:", location.hash); } var link = $(location.hash + ' ' + opt.selectors.eventContainer, this.accordion); if(this.options.debug) { console.log("Has tag-element was found:", link); } if (link.length) { link.click(); } } } }, this.callbackClicked = function(element) { //maybe do the tracking //console.log("callbackClicked"); }, this.callbackInit = function(element) { //maybe do the tracking //console.log("callbackInit"); }, this.scrollToElement = function (link) { var opt = this.options; if(!opt.autoScroll.use) { return; } jumpTarget = link.closest(opt.selectors.item); if(!jumpTarget.length) { return; } if(opt.autoScroll.scrollToPlugin.use && $.fn.scrollTo) { var headerOffset = parseInt(jQuery('#contentHome').css('padding-top')); $.scrollTo(jumpTarget,opt.autoScroll.scrollToPlugin.speed, { axis:'y', offset:-(headerOffset+10)}); } else { $(document.documentElement).scrollTop(jumpTarget.offset().top-opt.autoScroll.scrollToPlugin.offset); } }, this.hideContent = function (element, all) { all = all || false; var obj = this; var opt = this.options; if(opt.multi) { return; } this.accordionItems.removeClass(opt.selectors.activeClass).find(opt.selectors.content).hide(); }, this.proceedAccordion = function (link) { var opt = this.options; var accordion = this.accordion; var obj = this; var link = $(link); var item = link.closest(opt.selectors.item); var content = $(item.find(opt.selectors.content).get(0)); if(!content.length && opt.debug) { console.log("FAILED: no content found: "+content.length); } if(!opt.multi && !item.hasClass(opt.selectors.activeClass)) { obj.hideContent(item); } item.toggleClass(opt.selectors.activeClass); var scroll = link.parent().attr("class").indexOf('open') >= 0 ? true : false; var scrollPos = (jQuery(window).height() / 1.5) + jQuery(window).scrollTop(); if (scroll && !((link.offset().top + 46) > scrollPos)) { scroll = false; } content.slideToggle(opt.slideSpeed, function() { if (scroll) { obj.scrollToElement(link); } obj.handleMoreText(item, link); }); }, this.handleMoreText = function (item,link) { var opt = this.options; if (!opt.moreText.use) { return; } var openText = opt.moreText.openText; var closeText = opt.moreText.closeText; if(link.data("opentext")) { openText = link.data("opentext"); } if(link.data("closetext")) { closeText = link.data("closetext"); } if (!openText || !closeText) { return; } if(opt.debug) { console.log("Proceed: handleMoreText", openText, closeText); } var textTarget = link; if(opt.selectors.moreTextTarget && item.find(opt.selectors.moreTextTarget).length) { textTarget = item.find(opt.selectors.moreTextTarget); } if(link.data("texttarget") && item.find(link.data("texttarget")).length) { textTarget = item.find(link.data("texttarget")); } if (item.hasClass(opt.selectors.activeClass)) { textTarget.html(closeText); } else { textTarget.html(openText); } }, this.initAccordion = function () { var opt = this.options; var accordion = this.accordion; var obj = this; this.accordion.find(opt.selectors.content).hide(); this.accordionItems = this.accordion.find(this.options.selectors.item); if(opt.callbacks.init) { this.callbackInit = opt.callbacks.init; } if(opt.callbacks.clicked) { this.callbackClicked = opt.callbacks.clicked; } $(this.options.selectors.eventContainer, this.accordion).on('click', function(event) { obj.proceedAccordion($(this)); obj.callbackClicked($(this)); return false; }); if(this.options.levelClasses) { /* adLevelClass for better CSS Filtering */ $(opt.selectors.item + ' > ' + opt.selectors.content + ' > ' + opt.selectors.item + ' > ' + opt.selectors.content + ' > ' + opt.selectors.item + ' > ' + opt.selectors.content + ' > ' + opt.selectors.item + '', this.accordion).addClass(opt.selectors.itemLevel+'4'); $(opt.selectors.item + ' > ' + opt.selectors.content + ' > ' + opt.selectors.item + ' > ' + opt.selectors.content + ' > ' + opt.selectors.item, this.accordion).not('.'+opt.selectors.itemLevel+'4').addClass(opt.selectors.itemLevel+'3'); $(opt.selectors.item + ' > ' + opt.selectors.content + ' > ' + opt.selectors.item , this.accordion).not('.'+opt.selectors.itemLevel+'3,'+ '.'+opt.selectors.itemLevel+'4').addClass(opt.selectors.itemLevel+'2'); $(opt.selectors.item, this.accordion).not('.'+opt.selectors.itemLevel+'4, '+'.'+opt.selectors.itemLevel+'3, '+'.'+opt.selectors.itemLevel+'2').addClass(opt.selectors.itemLevel+'1'); } this.callbackInit(); }; this.init(el, opt); }; $.extend($.fn, { AccordionPlugin: function (inOpt) { inOpt = inOpt || {}; var instance = null; this.each(function (i) { var obj = $(this).data('AccordionPlugin'); var opt = $.extend(true, {}, options, inOpt); // deep merge if(!obj) { obj = new AccordionElementClass($(this),opt); $(this).data('AccordionPlugin', obj); } if (i == 0 && opt.api) { instance = obj; } }); return instance ? instance : this; } }); })(jQuery); /** * Wee bit more accessible slider. * * Provides the following default behaviour: * - scroll direction is determined by comparing the positions of items -- if more * items change their vertical position, the slider is considered to be "vertical" * - listens for mousewheel, focus and resize events to adjust scroll position/redraw * - whether items fit onto one page may be specified configuring thresholds/percentages * * See options for details. * * requires jquery.scrollTo.js * requires iTim.js * requires jquery.js * requires jquery.mousewheel.js */ (function ($) { var options = { // pass true to receive the last instance to meddle with api: false, // all events and data-properties will use this namespace namespace: '.scrollk', // in ms scrollDuration: 500, // how far may a consecutive set of items overflow the clipping region (percentage) before being broken into multiple pages thresholdItemWrapsPage: 1.1, // set to false, if item container need not be adjusted to accomodate the total item width (probably required for horizontal scrolling) fixItemContainerWidth: true, // if a little extra is required to make it fit (percentage) factorCorrectContainerWidth: 1.01, // select element that determines the visible portion of the slider selectClippingContainer: '.slider', // select element that wraps items and should be augmented to match their items selectItemContainer: '.sliderItems', selectItem: '.item', selectButtonPrevious: '.previous', selectButtonNext: '.next', // this class is added to buttons that will trigger an actual page change classButtonActive: 'active', // this class is added to buttons that cannot trigger a page change as their scrolling direction is blocked classButtonInactive: 'inactive', // adjust position to show items on focus inside them? listenForFocusEvents: true, focusWholePage: true, // should mouse wheel scrolling scroll the slider? listenForMouseWheelEvents: true, // should resizing repaint the slider? listenForViewportChangeEvents: true, // auto|v|h direction: 'auto', directionProperties: { h: { scrollToAxis: 'x', scrollPosition: 'left', scrollOffset: 'scrollLeft', width: 'width', outerWidth: 'outerWidth' }, v: { scrollToAxis: 'y', scrollPosition: 'top', scrollOffset: 'scrollTop', width: 'height', outerWidth: 'outerHeight' } }, onInit: function () {}, onPageChanged: function () {}, onPagesRefreshed: function () {} }; var instances = []; var scrollk = { el: null, direction: null, directionProperties: null, opt: null, clippingContainer: null, itemContainer: null, items: null, pages: null, init: function (el, opt) { this.opt = $.extend(true, {}, options, opt || {}); this.el = $(el); this.el.data('scrollk' + this.opt.namespace, this); instances.push(this); iTim.observable(this); this.createEvent('init'); this.createEvent('pageChanged'); this.createEvent('pagesRefreshed'); this.subscribe('init', this.opt.onInit); this.subscribe('pageChanged', this.opt.onPageChanged); this.subscribe('pagesRefreshed', this.opt.onPagesRefreshed); this.clippingContainer = this.el.find(this.el.find(this.opt.selectClippingContainer)); this.itemContainer = this.el.find(this.el.find(this.opt.selectItemContainer)); this.items = this.el.find(this.el.find(this.opt.selectItem)); this.buttonPrevious = this.el.find(this.el.find(this.opt.selectButtonPrevious)); this.buttonNext = this.el.find(this.el.find(this.opt.selectButtonNext)); if (this.opt.listenForFocusEvents) { this.el.find('a, tabindex, input, select, textarea').on('focus' + this.opt.namespace, iTim.bind(this.onItemSelected, this)); } if (this.opt.listenForMouseWheelEvents) { this.el.on('mousewheel' + this.opt.namespace, iTim.bind(this.onMouseWheel, this)); } if (this.opt.listenForViewportChangeEvents) { $(window).bind('resize', iTim.bind(this.onViewportChange, this)) } this.buttonPrevious.on('click' + this.opt.namespace, iTim.bind(this.onPrevious, this)); this.buttonNext.on('click' + this.opt.namespace, iTim.bind(this.onNext, this)); this.determineDirection(); this.scrollTo(this.getSelectedItemFromScrollOffset()); this.fire('init', null, this); }, onItemSelected: function (e) { var item = $(e.target).closest(this.opt.selectItem); if (!item.length) { return; } this.scrollTo(item, !this.opt.focusWholePage); }, onMouseWheel: function (e, delta) { if (delta < 0) { this.onNext(e); } else { this.onPrevious(e); } }, onViewportChange: function () { var timeout = null; return function () { clearTimeout(timeout); setTimeout(iTim.bind(function () { this.refreshPages(); this.scrollTo(this.getSelectedItemFromScrollOffset()); }, this), 50); }; }(), scrollTo: function (item, scrollToItemOnly) { var offset = this.clippingContainer[this.directionProperties.scrollOffset](); var page = this.getPageForItem(item); if (!page) { return; } var position = Math.ceil(this.getPosition(scrollToItemOnly ? item : page[0])); this.clippingContainer.stop().scrollTo(position, this.opt.scrollDuration, { axis: this.directionProperties.scrollToAxis, onAfter: iTim.bind(function () { this.fire('pageChanged', page, this); this.updateControlState(); }, this) }); }, getPageForItem: function (item) { item = $(item); if (!item.length) { return null; } var page = item.data('page' + this.opt.namespace); if (!page) { this.refreshPages(); return this.getPageForItem(item); } return page; }, refreshPages: function () { this.items = this.el.find(this.el.find(this.opt.selectItem)); var clipWidth = this.clippingContainer[this.directionProperties.width](); var lastPageStart = 0; var page = []; var pages = [page]; var itemsWidth = 0; this.items.each(iTim.bind(function (i, item) { item = $(item); var width = this.getItemWidth(item); var position = this.getPosition(item); itemsWidth += width; if (page.length && position + width > lastPageStart + this.opt.thresholdItemWrapsPage * clipWidth) { lastPageStart = position; page = []; pages.push(page); } item.data('page' + this.opt.namespace, page); page.push(item); }, this)); this.pages = pages; if (this.opt.fixItemContainerWidth) { itemsWidth = Math.ceil(itemsWidth * this.opt.factorCorrectContainerWidth); this.itemContainer[this.directionProperties.width](itemsWidth); } this.fire('pagesRefreshed', { pages: pages }, this); }, getPosition: function (el) { el = $(el); var position = el.position(); return Math.max(0, position[this.directionProperties.scrollPosition]); }, updateControlState: function () { var hasPreviousPage = this.hasPreviousPage(); var hasNextPage = this.hasNextPage(); this.buttonPrevious.toggleClass(this.opt.classButtonActive, hasPreviousPage); this.buttonNext.toggleClass(this.opt.classButtonActive, hasNextPage); this.buttonPrevious.toggleClass(this.opt.classButtonInactive, !hasPreviousPage); this.buttonNext.toggleClass(this.opt.classButtonInactive, !hasNextPage); }, getSelectedItemFromScrollOffset: function () { var offset = this.clippingContainer[this.directionProperties.scrollOffset](); var rightBorder = offset + Math.ceil(this.clippingContainer[this.directionProperties.width]()); var selectedItem = null; this.items.each(iTim.bind(function (i, item) { var position = Math.ceil(this.getPosition(item)); var width = Math.ceil(this.getItemWidth(item)); if (position > offset && position + width >= rightBorder) { if (!selectedItem) { selectedItem = item; } return false; } selectedItem = item; }, this)); return $(selectedItem); }, getItemWidth: function (item) { item = $(item); return item[this.directionProperties.outerWidth](true); }, onNext: function (e) { var hasNextPage = this.hasNextPage(); if (hasNextPage || e.type != 'mousewheel') { e.preventDefault(); } if (!hasNextPage) { return; } this.scrollTo(this.getNextPage()[0]); }, getNextPage: function () { var page = this.getPageForItem(this.getSelectedItemFromScrollOffset()); var newPage = this.pages[$.inArray(page, this.pages) + 1]; return newPage || null; }, hasNextPage: function () { return !!this.getNextPage(); }, onPrevious: function (e) { var hasPreviousPage = this.hasPreviousPage(); if (hasPreviousPage || e.type != 'mousewheel') { e.preventDefault(); } if (!hasPreviousPage) { return; } this.scrollTo(this.getPreviousPage()[0]); }, getPreviousPage: function () { var page = this.getPageForItem(this.getSelectedItemFromScrollOffset()); var newPage = this.pages[$.inArray(page, this.pages) - 1]; return newPage || null; }, hasPreviousPage: function () { return !!this.getPreviousPage(); }, determineDirection: function () { if (this.opt.direction != 'auto') { this.direction = this.opt.direction; return; } var x = []; var y = []; this.items.each(iTim.bind(function (i, item) { item = $(item); var position = item.position(); if (-1 == $.inArray(position.left, x)) { x.push(position.left); } if (-1 == $.inArray(position.top, y)) { y.push(position.top); } if (i == 5) { return false; } }, this)); if (x.length < y.length) { this.direction = 'v'; } else { this.direction = 'h'; } this.directionProperties = this.opt.directionProperties[this.direction]; } }; $.scrollk = { options: options, baseScrollk: scrollk, instances: instances }; $.fn.scrollk = function (settings) { var instance = null; this.each(function () { instance = iTim.object(scrollk); instance.init(this, settings); }); if (settings && settings.api) { return instance; } else { return this; } }; })(jQuery); (function ($) { iTim.ns('$.modalOverlay', null, { /** * Inherit from this object to provide simple means of running a method for each plugin * in the items hash. Any of those methods may choose to call the callback cb * given in basePlugin.callMethod(context, cb) whenever it returns from an asynchronous * process. * If the plugin does not return before the time specified in timeToError passes * a timeout occurs. The vallback given by the context is executed and the error property * of this instance is set to true. */ baseController: { items: null, order: null, error: null, timeToError: 15 * 1000, timeoutError: null, /** * Calls method on each plugin of this instance with * "who" as the context. * Upon completion or timeout, cb is called. */ run: function (method, who, cb) { cb = cb || function () {}; clearTimeout(this.timeoutError); this.timeoutError = null; this.error = false; var running = 0; var asyncReturn = null; var ready = iTim.bind(function () { --running; if (asyncReturn && !running) { asyncReturn(); } }, this); var runCallback = iTim.bind(function () { cb.call(who, this, method); }, this); this.timeoutError = setTimeout(iTim.bind(function () { if (running) { iTim.log('async controller timeout', method, running, who); this.error = true; runCallback(); } }, this), this.timeToError); iTim.each(this.order, function (i, item) { item = this.items[item]; if (item && item.callMethod(method, who, ready)) { ++running; } }, this); if (!running) { runCallback(); } else { asyncReturn = iTim.bind(function () { runCallback(); }, this); } }, /** * Executes a queue of methods. */ runSequence: function (methods, who, cb) { var method = methods.shift(); this.run(method, who, iTim.bind(function () { if (methods.length) { this.runSequence(methods, who, cb); } else if (cb) { cb.call(who, this, methods); } }, this)); }, /** * Adds a plugin to this controller. * The pluginname is pushed to the order stack. */ set: function (name, obj) { if (!this.items[name]) { this.order.push(name); obj.pluginName = name; } this.items[name] = obj; }, /** * Puts a plugin into first position. */ before: function (name, obj) { this.order.unshift(name); this.items[name] = obj; }, /** * Create a new instance from this instance. * Copy items and order properties to prevent both instances using the * same stack. */ create: function () { var newObj = iTim.object(this); if (this.items) { newObj.items = iTim.extend({}, this.items); newObj.order = this.order.slice(); } return newObj; }, init: function () { this.items = {}; this.order = []; return this; } }, /** * Base object for all plugins. Plugins should not save state for specific * contexts. Use methods opt() and lang() instead to rettrieve configuration * from each calling context. * Each method to be called by the controller should alwys at some point call * the given callback if timeouts should be prevented. */ basePlugin: { /** * Set an an options hash, that should be adopted into the context options. * Retrieve config for each context with this.opt(context) */ pluginOptions: null, /** * Set a (flat) hash of translations, that should be adopted into the context options. * Retrieve entries for each context with this.lang(context, key) */ pluginLang: null, /** * This options hash will be deep-merged into the context's options hash. * Use this to promote default configuration for the content. */ contextOptions: null, /** * This is called by the controller when a specific action is required. * Returns true if the required method exists. * Callback cb should be called when that method returns. */ callMethod: function (method, who, cb) { if (this[method]) { this[method](who, cb); return true; } else { return false; } }, /** * As plugins should not save state for a given context, this is used * to get an option value from the context-specific settings for this plugin. */ opt: function (context) { return context.opt.plugins[this.pluginName]; }, /** * Use this to retrieve the value from one of the language keys. */ lang: function (context, key) { return context.opt.lang[iTim.format('{0}.{1}', this.pluginName, key)] || ''; }, /** * Create a new instance of this plugin. * Use with care as property values will be used be the object. * Merges obj into the new instance. */ create: function (obj) { var instance = iTim.object(this); iTim.extend(instance, obj || {}); if (obj.pluginOptions && this.pluginOptions) { instance.pluginOptions = $.extend(true, {}, this.pluginOptions, obj.pluginOptions); } if (obj.contextOptions && this.contextOptions) { instance.contextOptions = $.extend(true, {}, this.contextOptions, obj.contextOptions); } return instance; } } }); })(jQuery); /** * modalOverlay jQuery plugin * */ (function ($, iTim) { var modal = iTim.ns('$.modalOverlay'); /** * Default configuration for modal overlays. * Every plugin added will append entries in .lang and .plugins properties. * Plugins may define default content properties, too. * Examine during runtime to determine default config as a whole or see * jqueryModalPlugins.js for builtin plugin examples. */ var options = { // whether calls to $.fn.modalOverlay should return first instance instead of jquery result set api: false, // used to namespace events, data, etc. namespace: '.modalOverlay', // skin to be used, usually results in a class of the container like "overlayDefault skin: 'default', // determines whether clicks on the dimmed background should close the overlay modal: false, // shortcuts to css classes being used by this instance classes: { container: 'modalOverlay', bg: 'overlayBg', logo: 'overlayLogo', layer: 'overlayContent', content: 'overlayContentInner', player: 'overlayPlayer', hasModal: 'hasModalOverlay', preloading: 'overlayPreloading', transitioning: 'overlayTransitioning', visible: 'overlayVisible', inactive: 'overlayItemInactive' }, templates: { container: iTim.format('<div class="modalOverlay"><div class="overlayBg"></div><div class="overlayLogo"></div></div>'), layer: '<div class="overlayContent" role="dialog"><div class="overlayContentInner">' + '<div class="overlayPlayer"></div></div></div>' }, // augmented by plugins during runtime content: { // actual content to be displayed href: null, // name of the player to be used (e.g. "image") player: null, width: null, height: null, // if this content is part of a gallery gallery: null }, // configurations per plugin plugins: {}, // configuration for this instance's player player: {}, // key-value-pairs of language dependent strings // each plugin's .pluginLang property will be merged into this when added // example: "buttonClose.text": "Close" lang: {}, // state info appended to options for convenience galleryIndex: null, preloaded: null, // will be set to the index of the lightbox instance using this options hash modalId: null }; var instances = []; var currentInstance = null; var instanceBefore = null; /** * Plugins are stateless in respect to the overlays they augment. * This controller will call a method for each display phase on each plugin. */ var plugins = modal.baseController.create().init(); /** * Hash of known players. * Use $.modalOverlay.addPlayer to append players. */ var players = {}; /** * Extend this base object via .create({...}) */ var basePlayer = modal.basePlugin.create({ regexFilePattern: null, playerName: null, canPlay: function (opt) { if (!this.regexFilePattern || !opt.content.href) { return false; } var url = iTim.url(opt.content.href); return this.regexFilePattern.test(url.pathname); }, opt: function (context) { return $.extend(true, {}, context.opt.plugins[this.pluginName], context.opt.player); }, insertHtml: function (context, cb) { context.select('player').addClass(iTim.ccase('overlayPlayer-' + this.playerName)); cb(); } }); /** * Enables the retrieval of mroe default options from * options hashes. */ var extractors = modal.baseController.create().init(); /** * Base object of modalOverlay plugin. */ var baseModalOverlay = modal.basePlugin.create({ el: null, containerEl: null, linkEl: null, opt: null, initialized: false, isVisible: false, state: null, bindLink: function (linkEl) { this.linkEl = $(linkEl).bind('click' + this.opt.namespace, iTim.bind(function (e) { this.sendShow(function () {}); e.preventDefault(); }, this)); }, /** * Lazily create the surrounding container of all overlays and * this instance's overlay. * Binds the click handler to the overlay bg. */ ensureElements: function () { this.containerEl = this.containerEl || $('.' + this.opt.classes.container); if (!this.containerEl.length) { this.containerEl = $(this.opt.templates.container).appendTo(document.body); this.plugins.run('initContainer', this, function () {}); $(window).bind('resize' + this.opt.namespace, iTim.bind(function () { if (currentInstance) { currentInstance.plugins.run('viewportChanged', currentInstance); } }, this)); } this.containerEl.find('.' + this.opt.classes.bg).unbind(this.opt.namespace).bind('click' + this.opt.namespace, function (e) { if (!currentInstance.opt.modal) { currentInstance.sendHide(function () {}); } }); if (!this.el || !this.el.length) { this.el = $(this.opt.templates.layer).appendTo(this.containerEl).data('modalOverlay' + this.opt.namespace, this); } }, /** * If this.opt.classes contains the key given in sel, the class specified there is used, else * sel is treated as a full selector. * Searches this overlay (including itself and travelling upwards) for the first occurrance of that selector * and returns it. */ select: function (sel) { return this.opt.classes[sel] ? $(this.el).find('.' + this.opt.classes[sel]).andSelf().closest('.' + this.opt.classes[sel]) : $(this.el).find(sel).andSelf().closest(sel); }, /** * Calls this.select(sel) and toggles its this.opt.classes.inactive on it. */ toggleItem: function (sel, active) { if (active) { return this.activateItem(sel); } else { return this.deactivateItem(sel); } }, activateItem: function (sel) { return this.select(sel).removeClass(this.opt.classes.inactive).attr('aria-disabled', false); }, deactivateItem: function (sel) { return this.select(sel).addClass(this.opt.classes.inactive).attr('aria-disabled', true); }, insertHtml: function (who, cb) { // insert basic html this.ensureElements(); $(document.body).addClass(this.opt.classes.hasModal); this.containerEl.addClass(iTim.ccase('overlay-' + this.opt.skin)); setTimeout(function () { cb(); }, 10); }, preload: function (who, cb) { // preload and asynchronously return with calling cb() if needed this.el.addClass(this.opt.classes.preloading); setTimeout(function () { cb(); }, 10); }, insertContent: function (who, cb) { // insert actual content; this should result in final layer dimensions setTimeout(function () { cb(); picturefill(); // DKBIB-5085 bindModalOverlay(false); }, 10); }, beforeTransitionIn: function (who, cb) { // plugins: last chance to set visual properties without being seen (e.g. positionining) this.el.removeClass(this.opt.classes.preloading); this.el.addClass(this.opt.classes.transitioning); if (jQuery('#overlayTargetLink') != undefined && who.linkEl!= null && who.linkEl[0].parentElement.getAttribute('xpart') != undefined) { jQuery('#overlayTargetLink').attr('href', who.linkEl[0].parentElement.getAttribute('xpart')); } setTimeout(function () { cb(); }, 10); }, transitionIn: function (who, cb) { // plugins: animate showing this.el.addClass(this.opt.classes.visible); setTimeout(function () { cb(); }, 10); }, afterTransitionIn: function (who, cb) { // show this this.el.removeClass(this.opt.classes.transitioning); setTimeout(function () { cb(); }, 10); }, beforeTransitionOut: function (who, cb) { this.el.addClass(this.opt.classes.transitioning); setTimeout(function () { cb(); }, 10); }, transitionOut: function (who, cb) { // plugins: animate hiding setTimeout(function () { cb(); }, 10); }, afterTransitionOut: function (who, cb) { // hide this this.el.hide(); this.el.removeClass(this.opt.classes.transitioning); if (!currentInstance || (currentInstance && currentInstance.opt.skin != this.opt.skin)) { this.containerEl.removeClass(iTim.ccase('overlay_' + this.opt.skin)); } cb(); }, hideContainer: function (who, cb) { this.removeHtml(); $(document.body).removeClass(this.opt.classes.hasModal); cb(); }, removeHtml: function () { // remove all html this.el.remove(); this.el = null; }, viewportChanged: function (who, cb) { // do nought cb(); }, sendHideForChange: function (cb) { this.state.closing = true; this.state.changing = true; this.isVisible = false; currentInstance = null; this.plugins.runSequence([ 'beforeTransitionOut', 'transitionOut', 'afterTransitionOut' ], this, iTim.bind(function () { this.state.closing = false; this.state.changing = false; cb && cb(); }, this)); }, sendHideFast: function (cb) { this.state.closing = true; this.isVisible = false; currentInstance = null; this.plugins.runSequence([ 'hideContainer' ], this, iTim.bind(function () { this.state.closing = false; cb && cb(); }, this)); }, sendHide: function (cb) { this.state.closing = true; this.isVisible = false; currentInstance = null; this.plugins.runSequence([ 'beforeTransitionOut', 'transitionOut', 'afterTransitionOut', 'hideContainer' ], this, iTim.bind(function () { this.state.closing = false; cb && cb(); }, this)); }, sendShow: function (cb) { cb = cb || function () {}; if (!this.state.changing) { this.state.opening = true; } // this layer is already visible, so do nothing if (this.isVisible) { cb(); return; } // another layer is currently visible, hide it, then show this layer if (currentInstance && currentInstance != this) { lastInstance = currentInstance; this.isVisible = true; this.plugins.runSequence([ 'insertHtml', 'preload' ], this, iTim.bind(function () { lastInstance.sendHideForChange(); currentInstance = this; this.plugins.runSequence([ 'insertContent', 'beforeTransitionIn', 'transitionIn', 'afterTransitionIn' ], this, iTim.bind(function () { this.state.opening = false; this.state.changing = false; cb && cb(); }, this)); }, this)); // no other layer is visible, show this layer } else if (!currentInstance) { currentInstance = this; this.plugins.runSequence([ 'insertHtml', 'preload', 'insertContent', 'beforeTransitionIn', 'transitionIn', 'afterTransitionIn' ], this, iTim.bind(function () { this.state.opening = false; this.state.changing = false; cb && cb(); }, this)); } }, sendShowForChange: function (cb) { this.state.changing = true; return this.sendShow(cb); }, /** * Send an event on this instance's dom container. */ trigger: function (name, args) { args = [$.extend({ modalOverlay: this }, args || {})]; return this.el.trigger(name, args); }, init: function () { if (this.initialized) { return; } this.state = { changing: false, opening: false, closing: false }; // create a new plugin controller from global plugins controller this.plugins = plugins.create(); var player = this.player = players[this.opt.content.player]; // insert the overlay and its player as first elements into the plugin controller this.plugins.before('player', player); this.plugins.before('container', this); // disable all plugins, that have been removed from the options hash // and set plugin config to default if "true" iTim.each(this.opt.plugins, function (i, plugin) { if (!plugin || plugin.disabled) { this.plugins.set(i, false); } else if (plugin === true) { this.opt.plugins[i] = $.extend(true, {}, this.plugins.items[i].pluginOptions); } }, this); this.initialized = true; } }); /** * Make plugin configuration and base objects public in $.modalOverlay */ var common = { baseModalOverlay: baseModalOverlay, basePlayer: basePlayer, players: players, instances: instances, options: options, plugins: plugins, extractors: extractors, show: function (opt, cb) { return this.setup(opt, function (modal) { modal.sendShow(cb); }); }, setup: function (opt, cb) { var modal = null; if (!isNaN(+opt)) { modal = instances[opt]; } else if (opt && !isNaN(+opt.modalId)) { modal = instances[opt.modalId]; } else if (opt.opt && !isNaN(+opt.opt.modalId)) { modal = opt; } if (!modal) { modal = iTim.object(baseModalOverlay); opt.modalId = instances.push(modal) - 1; this.extract(opt, function (opt) { modal.opt = $.extend(true, {}, options, opt); modal.init(); if (cb) { cb(modal); } }); } return modal; }, addPlayer: function (name, player) { player.playerName = name; this.players[name] = player; this.addPlugin(name, player); }, addPlugin: function (name, plugin) { $.extend(true, this.options, plugin.contextOptions || {}); if (plugin.pluginLang) { iTim.each(plugin.pluginLang, function (key, value) { key = iTim.format('{0}.{1}', name, key); this.options.lang[key] = value; }, this); } this.options.plugins[name] = plugin.pluginOptions || {}; if (!plugin.playerName) { this.plugins.set(name, plugin); } else { plugin.pluginName = plugin.playerName; } }, /** * Add an extractor to be run on the option hashes when an overlay * is being instantiated. */ addExtractor: function (name, extractor) { extractor.extractorName = name; extractors.set(name, extractor); }, /** * Runs the extractors on an options hash given by context. * Pass an onComplete callback to be run on completion of * possible asynchronous tasks. */ extract: function (context, onComplete) { onComplete = onComplete || function () {}; if (typeof context == 'string') { context = { opt: { content: { href: context } } }; } if (!context.opt) { context = { opt: context }; } extractors.run('extract', context, function () { onComplete(context.opt); }); return context.opt; }, hide: function (cb) { if (currentInstance) { currentInstance.sendHide(cb); } }, close: function (cb) { return this.hide(cb); }, closeFast: function (cb) { if (currentInstance) { currentInstance.sendHideFast(cb); } }, get: function (opt) { return currentInstance; } }; $.extend($.modalOverlay, common); /** * Adds $(...).modalOverlay plugin method to be called on links. */ $.extend($.fn, { modalOverlay: function (opt) { opt = opt || {}; var jq = this; var firstInstance = null; // iterate over result set this.each(function (i) { var el = $(this); var setup = $.extend(true, {}, options, opt); var instance = el.data('modalOverlay' + setup.namespace); if (!instance) { el.contextual(function (linkOpt) { setup = $.extend(true, {}, opt, linkOpt); instance = common.setup(setup); el.data('modalOverlay' + setup.namespace, instance); instance.bindLink(el); }); } if (i == 0) { firstInstance = instance; } }); // if control object should be returned if (opt.api) { return firstInstance; } else { return jq; } } }); })(jQuery, iTim); (function ($) { var modal = $.modalOverlay; var options = { useMetaData: true, propertyConfigData: 'data-contextual', onComplete: function () {}, getDescription: function (link) { // find first .linkDescription inside of link or directly following it return $(link).find('.linkDescription').andSelf().nextAll('.linkDescription').andSelf().filter('.linkDescription').eq(0); }, extracted: null, link: null }; var extractors = modal.baseController.create().init(); extractors.set('linkDefault', modal.basePlugin.create({ extract: function (context, cb) { var link = $(context.link); $.extend(true, context.extracted, { content: { title: link.attr('title'), href: link.attr('href') } }); if (context.useMetaData) { $.extend(true, context.extracted, $(link).metadata()); } var data = link.data(context.propertyConfigData); if (data) { $.extend(true, context.extracted, JSON.parse(link.data(context.propertyConfigData))); } cb(); } })); var linkDescriptions = [null]; extractors.set('description', modal.basePlugin.create({ extract: function (context, cb) { var link = $(context.link); var description = context.getDescription(link); if (description) { context.extracted.content.descriptionCacheKey = linkDescriptions.push(description) - 1; } cb(); } })); var common = { addExtractor: function (name, extractor) { extractor.extractorName = name; extractors.set(name, extractor); }, extract: function (opt) { if (opt.nodeType) { opt = { link: opt }; } var context = $.extend({}, options, opt); context.extracted = context.extracted || {}; extractors.run('extract', context, function () { context.onComplete(context.extracted); }); return context.extracted; }, extractors: extractors, options: options, linkDescriptions: linkDescriptions }; $.extend({ contextual: common }); $.extend($.fn, { contextual: function (opt) { opt = opt || {}; if (typeof opt == 'function') { opt = { onComplete: opt }; } if (!this.length) { if (opt.onComplete) { opt.onComplete(); } return {}; } opt.link = this.get(0); return common.extract(opt); } }); })(jQuery); (function ($, iTim) { var modal = $.modalOverlay; $.modalOverlay.addPlayer('ajax', modal.basePlayer.create({ contextOptions: { content: { ajaxContent: null } }, pluginOptions: { ajax: { }, getContent: function (responseText, context) { responseText = this.getContent(responseText, context.opt.content.href); return responseText; } }, // either a known html-producing file type or an empty extension, // which would indicate a directory-only or firstspirit preview url regexFilePattern: /\.(html|jsp|php|shtml|htm|do)$|\/[^.]*$/i, canPlay: function (opt) { var url = iTim.url(opt.content.href); return this.__prototype.canPlay.apply(this, arguments) && (url.host == location.host || !url.host); }, getContent: function (responseText, href) { responseText = this.getBody(responseText); responseText = this.removeScripts(responseText); responseText = this.rewriteUrls(responseText, href); return responseText; }, rewriteUrls: function (responseText, href) { var base = iTim.url(location).resolve(href); responseText = responseText.replace(/(href|src)=(['"])([\s\S]+?)\2/gi, function (match, attr, del, value) { if (value.match(/^(?:javascript|mailto):|^#.*$/i)) { return match; } return iTim.format('{0}={1}{2}{1}', attr, del, base.resolve(value).href); }); return responseText; }, getBody: function (responseText) { return responseText.replace(/(?:^[\s\S]*<body[\s\S]*?>)|(?:<\/body>[\s\S]*$)/gi, ''); }, removeScripts: function (responseText) { return responseText.replace(/<script[\s\S]*?<\/script>/gi, ''); }, preload: function (context, cb) { if (context.opt.content.ajaxContent) { cb(); return; } var opt = this.opt(context); var config = $.extend({}, opt.ajax, { cache: false, url: context.opt.content.href, complete: iTim.bind(function (xhr) { context.opt.preloaded = true; context.opt.content.ajaxContent = opt.getContent.call(this, xhr.responseText, context); cb(); }, this) }); $.ajax(config); }, insertHtml: function (context, cb) { context.select('player').html('<div class="overlayPlayerContent"/>'); this.__prototype.insertHtml.apply(this, arguments); }, insertContent: function (context, cb) { context.select('.overlayPlayerContent').append(context.opt.content.ajaxContent); cb(); } })); })(jQuery, iTim); (function ($) { $.modalOverlay.addPlugin('copyright', $.modalOverlay.basePlugin.create({ contextOptions: { content: { copyright: null } }, pluginOptions: { selectEl: '.overlayNavigationBottom > .overlayNavigationInner' }, pluginLang: { // {0}: current year, // {1}: copyright text from lightbox instance // {2}: for convenience: copyright-html-entity text: '{2} {0}' }, insertHtml: function (context, cb) { context.select(this.opt(context).selectEl).append('<span class="overlayCopyright"></span>'); cb(); }, insertContent: function (context, cb) { var text = iTim.format(this.lang(context, 'text'), new Date().getFullYear(), context.opt.content.copyright || '', '©'); context.select('.overlayCopyright').append(text); cb(); } })); })(jQuery); (function ($) { var galleryDescriptions = [null]; $.contextual.addExtractor('galleryDescription', $.modalOverlay.basePlugin.create({ extract: function (context, cb) { var link = $(context.link); var description = context.getGalleryDescription(link); if (description) { context.extracted.content.galleryDescriptionCacheKey = galleryDescriptions.push(description) - 1; } cb(); } })); $.contextual.options.getGalleryDescription = function (link) { return $(link).closest('.module').find('.galleryDescription').eq(0); }; $.contextual.galleryDescriptions = galleryDescriptions; $.modalOverlay.addPlugin('galleryDescription', $.modalOverlay.basePlugin.create({ contextOptions: { content: { galleryDescriptionCacheKey: null, galleryDescription: null } }, pluginOptions: { where: 'append', method: 'clone', selectEl: 'content' }, insertHtml: function (context, cb) { var opt = this.opt(context); context.select(opt.selectEl)[opt.where]('<div class="overlayGalleryDescription"></div>'); cb(); }, insertContent: function (context, cb) { var opt = this.opt(context); var description = galleryDescriptions[context.opt.content.galleryDescriptionCacheKey]; if (!description && context.opt.content.galleryDescription) { description = context.opt.content.galleryDescription; if (typeof description == 'function') { description = description.apply(context); } description = $('<div class="overlayDescriptionText"></div>').append(description); } var hasDescription = !!(description && description.length); context.toggleItem('.overlayGalleryDescription', hasDescription); if (!hasDescription) { cb(); return; } if (opt.method == 'clone') { description = description.clone(true); } context.select('.overlayGalleryDescription').append(description); cb(); } })); })(jQuery); /** * Adds a player to jquery modal, that displays content in an iframe. * Auto-selected if: * - file extension is some html or serverside langugage * - a directory is being requested */ (function ($, iTim) { var modal = $.modalOverlay; $.modalOverlay.addPlayer('iframe', modal.basePlayer.create({ contextOptions: { content: { originalHeight: null }, templates: { iframe: '<iframe style="visibility: hidden; {{if scrolling == "no"}}overflow: hidden;{{/if}}" class="overlayPlayerContent" id="{{= id }}" name="{{= id }}" height="{{= height }}" width="{{= width }}" frameborder="0" marginwidth="0" marginheight="0" scrolling="{{= scrolling }}" {{if ie}}allowtransparency="true"{{/if}} {{if ie6}}src="javascript:false;document.write(\'\');"{{/if}} ></iframe>' } }, pluginOptions: { // false|true|'fallback' scrolling: 'fallback', adjustIframeHeightToContent: false, // select elements inside iframe that define its min-height selectContentBody: '.pageWrapper, body', // set to null to prevent polling pollingInterval: 100, // will be added to documentElement of iframe classInLightbox: 'inLightbox', tryAdjustIframeHeight: function (context) { var opt = this.opt(context); var iframe = context.select('.overlayPlayerContent'); try { var contents = iframe.contents(); var documentElement = contents.get(0).documentElement; if (-1 == documentElement.className.indexOf(opt.classInLightbox)) { documentElement.className += ' ' + opt.classInLightbox; } var body = contents.find(opt.selectContentBody); var height = body.outerHeight(true); if (!context.opt.content.originalHeight) { context.opt.content.originalHeight = context.opt.content.height; } context.opt.content.height = height; iframe.css({ height: height }); } catch (ex) { // iframe cross-domain issues, height cannot be altered iTim.log('cross-domain error in $.modalOverlay.players.iframe:', ex); this.trySetFallbackScrollbars(context); this.stopPolling(); } } }, // either a known html-producing file type or an empty extension, // which would indicate a directory-only or firstspirit preview url regexFilePattern: /\.(html|jsp|php|shtml|htm|do)$|\/[^.]*$/i, canPlay: function (opt) { var url = iTim.url(opt.content.href); // true if file extension matches or targeting a directory return this.__prototype.canPlay.apply(this, arguments) || (url.pathname && url.pathname == url.path); }, id: 'overlayIframe', numberOfInstances: 0, pollingInterval: null, preload: function (context, cb) { var opt = this.opt(context); var url = iTim.url(location).resolve(context.opt.content.href).href; var player = this; var iframe = $.tmpl(context.opt.templates.iframe, { id: this.id + (this.numberOfInstances++), ie: $.browser.msie, ie6: $.browser.msie && +$.browser.version < 7, height: context.opt.content.height, width: context.opt.content.width, scrolling: opt.scrolling == 'yes' || opt.scrolling === true ? 'yes' : (opt.scrolling == 'no' || opt.scrolling == 'fallback' || !opt.scrolling ? 'no' : 'auto') }).appendTo(context.select('player')); iframe.bind('load error', function (e) { if (this.src == url) { context.opt.preloaded = true; player.startPolling(context); cb(); } }).attr('src', url); }, startPolling: function (context) { var opt = this.opt(context); opt.tryAdjustIframeHeight.call(this, context); if (opt.pollingInterval != null) { this.pollingInterval = setInterval(iTim.bind(function () { if (modal.get() != context) { this.stopPolling(); } opt.tryAdjustIframeHeight.call(this, context); }, this), opt.pollingInterval); } }, stopPolling: function () { clearInterval(this.pollingInterval); }, trySetFallbackScrollbars: function (context) { if (this.opt(context).scrolling == 'fallback') { context.select('.overlayPlayerContent').attr('scrolling', 'auto').css('overflow', 'auto'); } }, insertContent: function (context, cb) { context.select('.overlayPlayerContent').css({ visibility: 'visible' }); cb(); }, beforeTransitionOut: function (context, cb) { this.stopPolling(); cb(); }, print: function () { $.modalOverlay.get().select('.overlayPlayerContent').get(0).contentWindow.print(); } })); })(jQuery, iTim); (function ($, iTim) { var modal = $.modalOverlay; $.modalOverlay.addPlayer('image', modal.basePlayer.create({ regexFilePattern: /\.(jpe?g|png|gif)$/i, preload: function (context, cb) { var image = new Image(); var content = context.opt.content; image.onload = function () { context.opt.preloaded = true; content.width = content.width || this.width; content.height = content.height || this.height; cb(); }; image.src = context.opt.content.href; image = null; }, insertContent: function (context, cb) { var content = context.opt.content; var alt = content.alt || content.title || ''; context.select('player').append(iTim.format('<img class="overlayPlayerContent" alt="{0}" src="{1}" width="{2}" height="{3}" />', alt, content.href, content.width, content.height)); cb(); } })); })(jQuery, iTim); (function ($, iTim) { var modal = $.modalOverlay; $.modalOverlay.addPlayer('inline', modal.basePlayer.create({ pluginOptions: { clone: false }, canPlay: function (opt) { return opt.content.href && iTim.url(opt.content.href).hash == opt.content.href && $(opt.content.href).length; }, preload: function (context, cb) { var el = $(context.opt.content.href); if (el.is(':visible')) { context.opt.content.width = context.opt.content.width || el.width(); context.opt.content.height = context.opt.content.height || el.height(); } context.opt.preloaded = true; cb(); }, insertHtml: function (context, cb) { context.select('player').html('<div class="overlayPlayerContent"/>'); this.__prototype.insertHtml.apply(this, arguments); }, insertContent: function (context, cb) { var el = $(context.opt.content.href); if (this.opt(context).clone) { el = el.clone(true); } el.data('parentElement', el.parent()); el.appendTo(context.select('.overlayPlayerContent')); cb(); }, afterTransitionOut: function (context, cb) { if (!this.opt(context).clone) { var el = $(context.opt.content.href); el.appendTo(el.data('parentElement')); } cb(); } })); })(jQuery, iTim); (function ($) { var modal = $.modalOverlay; var async = $.modalOverlay; modal.addPlugin('loader', async.basePlugin.create({ el: null, pluginOptions: { // horizontal spriteset, no gaps, square sprites // divided evenly onto half a second bgUrl: '/icons/loader.png', isStaticImage: false, minDisplayTime: 1000 }, error: false, spriteSize: null, numberOfFrames: null, animationInterval: null, insertHtml: function (context, cb) { var plugin = this; var opt = this.opt(context); var runAnimation = iTim.bind(function () { var startTime = new Date().getTime(); this.el.show(); if (!opt.isStaticImage) { var interval = 500 / this.numberOfFrames; this.animationInterval = setInterval(function () { var time = new Date().getTime() - startTime; var ticks = Math.floor(time / interval); plugin.el.css({ backgroundPosition: -plugin.spriteSize * (ticks % plugin.numberOfFrames) + 'px 0' }); }, interval); } }, this); this.tryInitEl(context, function () { if (!plugin.error && !context.opt.preloaded) { runAnimation(); } cb(); }); }, tryInitEl: function (context, cb) { if (this.el) { cb(); return; } this.el = $('<div class="overlayLoader"></div>').appendTo(context.containerEl); var preload = new Image(); var plugin = this; var opt = this.opt(context); preload.onload = function () { plugin.spriteSize = this.height; if (opt.isStaticImage) { plugin.numberOfFrames = 1; } else { plugin.numberOfFrames = Math.floor(this.width / this.height); } plugin.el.css({ background: iTim.format('url({0}) no-repeat 0 0', this.src), width: plugin.spriteSize + 'px', height: plugin.spriteSize + 'px', // center on origin margin: iTim.format('-{0}px 0 0 -{0}px', plugin.spriteSize / 2) }); preload.onerror = preload.onload = null; preload = null; cb(); }; preload.onerror = function () { plugin.error = true; preload.onerror = preload.onload = null; preload = null; cb(); }; preload.src = this.opt(context).bgUrl; }, preload: function (context, cb) { if (context.opt.preloaded) { cb(); return; } setTimeout(function () { cb(); }, this.opt(context).minDisplayTime); }, beforeTransitionIn: function (context, cb) { this.el.hide(); clearInterval(this.animationInterval); cb(); } })); })(jQuery); (function ($) { var modal = $.modalOverlay; var basePlugin = modal.basePlugin; /** * Adds an extractor that tries to determine basic properties from * the content url. * Both Query String and Hash are searched for the parameters: * - modalWidth and -Height * - modalContent, if the base file should not be used as target content * - modalParent, if another page should be used as base for the overlay * - modalOptions for stored options to be used */ modal.addExtractor('modalHrefFromDeeplink', basePlugin.create({ extract: function (context, cb) { var content = context.opt.content; var url = iTim.url(content.href); var inherits = url.params.modalOptions || context.opt.inherits; if (url.params.modalContent) { content.deepLinkParent = url.pathname; content.deepLinkHref = content.href; content.href = url.params.modalContent; } if (url.params.modalParent) { content.deepLinkParent = url.params.modalParent; } content.width = +url.params.modalWidth || content.width; content.height = +url.params.modalHeight || content.height; if (!content.width) { delete content.width; } if (!content.height) { delete content.height; } if (inherits) { context.opt[iTim.StoredOptions.keyInherits] = inherits; } cb(); } })); /** * Resolve all references to stored options if applicable. */ modal.addExtractor('storedOptions', basePlugin.create({ extract: function (context, cb) { context.opt = iTim.StoredOptions.get(context.opt); cb(); } })); /** * Build galleries for all contents, that contain a "gallery" property. */ var galleries = modal.galleries = {}; modal.addExtractor('gallery', basePlugin.create({ extract: function (context, cb) { var content = context.opt.content; if (!content.gallery) { cb(); return; } var gallery = galleries[content.gallery] = galleries[content.gallery] || []; context.opt.galleryIndex = gallery.push(context.opt.modalId) - 1; cb(); } })); /** * Handler to activate next item in gallery. */ modal.galleryNext = function () { var context = this.get(); if (!context) { return; } var gallery = galleries[context.opt.content.gallery]; var index = context.opt.galleryIndex; var layer = modal.setup(gallery[(index + 1) % gallery.length]); layer.sendShow(); return layer; }; /** * Handler to activate previous item in gallery. */ modal.galleryPrevious = function () { var context = this.get(); if (!context) { return; } var gallery = galleries[context.opt.content.gallery]; var index = context.opt.galleryIndex; var layer = modal.setup(gallery[(index + gallery.length - 1) % gallery.length]); layer.sendShow(); return layer; }; /** * Returns, whether gallery has additional items. */ modal.galleryHasNext = function () { var context = this.get(); if (!context) { return false; } var gallery = galleries[context.opt.content.gallery]; if (!gallery) { return false; } var index = context.opt.galleryIndex; return index + 1 < gallery.length; }; /** * Returns, whether gallery has items before the current one. */ modal.galleryHasPrevious = function () { var context = this.get(); if (!context) { return false; } var gallery = galleries[context.opt.content.gallery]; if (!gallery) { return false; } var index = context.opt.galleryIndex; return index - 1 >= 0; }; /** * If no player is given by the content, test each player if it applies and * use the first one matching. */ modal.addExtractor('defaultPlayer', basePlugin.create({ extract: function (context, cb) { var content = context.opt.content; if (content.player) { cb(); return; } var url = iTim.url(content.href); $.each(modal.players, function (name) { if (this.canPlay(context.opt)) { content.player = name; return false; } }); cb(); } })); /** * The basic plugin to use for navigation targets. These can be toolbars * of overlays. * Navigation buttons will be appended to these. */ modal.baseNavigationPlugin = basePlugin.create({ navigationName: 'default', isToolbar: true, pluginOptions: { where: 'append', selectEl: 'content' }, insertHtml: function (context, cb) { var opt = this.opt(context); context.select(opt.selectEl)[opt.where](iTim.format('<div class="overlayNavigation {0} {1}"><div class="overlayNavigationInner"></div></div>', iTim.ccase('overlayNavigation_' + this.navigationName), this.isToolbar ? 'overlayToolbar' : '')); cb(); } }); /** * Toolbar to be shown above of the player. */ modal.addPlugin('toolbarTop', modal.baseNavigationPlugin.create({ navigationName: 'top', pluginOptions: { where: 'prepend' } })); /** * Toolbar to be shown below the player. */ modal.addPlugin('toolbarBottom', modal.baseNavigationPlugin.create({ navigationName: 'bottom' })); /** * A navigation to be shown overlaying the whole content in most cases. * As this is no toolbar, no print buttons, etc. will be appended. */ modal.addPlugin('navigationAbove', modal.baseNavigationPlugin.create({ navigationName: 'above', isToolbar: false, pluginOptions: { selectEl: 'player' } })); /** * Appends shadow elements to the layer consisting of images that scale * with the layer content. Disable this, if not needed. */ modal.addPlugin('shadow', basePlugin.create({ pluginOptions: { selectEl: 'layer', t: '../../images/shadow/shadowTop.png', rt: '../../images/shadow/shadowRightTop.png', r: '../../images/shadow/shadowRight.png', rb: '../../images/shadow/shadowRightBottom.png', b: '../../images/shadow/shadowBottom.png', lb: '../../images/shadow/shadowLeftBottom.png', l: '../../images/shadow/shadowLeft.png', lt: '../../images/shadow/shadowLeftTop.png' }, insertHtml: function (context, cb) { var html = ''; var opt = this.opt(context); $.each(opt, function (key) { if (!/^\w\w?$/.test(key) || !this) { return; } html += iTim.format('<img alt="" src="{1}" class="shadow {0}" />', 'shadow-' + key, this); }); context.select(opt.selectEl).prepend(iTim.format('<div class="overlayShadow">{0}</div>', html)); cb(); } })); /** * Appends the title container to each toolbar. * Disabled, if content object does not contain a title property. */ modal.addPlugin('title', basePlugin.create({ pluginOptions: { selectEl: '.overlayNavigationTop > .overlayNavigationInner' }, insertHtml: function (context, cb) { context.select(this.opt(context).selectEl).prepend('<div role="heading" class="overlayTitle" id="overlayTitle"></div>'); cb(); }, insertContent: function (context, cb) { var content = context.opt.content; context.toggleItem('.overlayTitle', content.title).html(content.title || ''); cb(); } })); /** * Adds a simple textual pager to to each toolbar. */ modal.addPlugin('galleryPaging', basePlugin.create({ pluginOptions: { selectEl: '.overlayNavigationTop > .overlayNavigationInner' }, pluginLang: { pageOf: 'Page <span class="overlayPage overlayPageActive">{0}</span> of <span class="overlayPageNumber">{1}</span>' }, insertHtml: function (context, cb) { var nav = context.select(this.opt(context).selectEl); var paging = $('<div role="log" class="overlayPaging"></div>').appendTo(nav); cb(); }, insertContent: function (context, cb) { var content = context.opt.content; var gallery = galleries[content.gallery]; var galleryEl = context.toggleItem('.overlayPaging', !!content.gallery); if (gallery) { galleryEl.html(iTim.format(this.lang(context, 'pageOf'), $.inArray(context.opt.modalId, gallery) + 1, galleries[content.gallery].length)); } cb(); } })); /** * Base plugin for buttons, that should be appended to all toolbars. */ var baseButton = modal.baseButton = basePlugin.create({ buttonName: 'default', onClick: null, pluginLang: { // to be overridden by subclass text: null }, pluginOptions: { selectEl: '.overlayToolbar > .overlayNavigationInner', tabindex: 10 }, contextOptions: { templates: { button: '<span tabindex="{{= tabindex }}" role="button" class="overlayButton {{= cls }}" title="{{= title }}"><span class="overlayIcon"></span><span class="overlayText">{{= title }}</span></span>' } }, insertHtml: function (context, cb) { var opt = this.opt(context); var button = $.tmpl(context.opt.templates.button, { cls: iTim.ccase('overlayButton_' + this.buttonName), title: this.lang(context, 'text'), tabindex: opt.tabindex }).appendTo(context.select(opt.selectEl)); button.bind('click', iTim.bind(function (e) { this.onClick(context); }, this)); button.bind('keypress', iTim.bind(function (e) { if (e.keyCode == 13) { this.onClick(context); } }, this)); cb(); } }); /** * Adds a print button to all toolbars. * Calls player's print() method on click if exists, else window's print() function. */ modal.addPlugin('buttonPrint', baseButton.create({ buttonName: 'print', pluginOptions: { selectEl: '.overlayNavigationBottom > .overlayNavigationInner', tabindex: 40 }, contextOptions: { content: { printable: true } }, pluginLang: { text: 'Print' }, onClick: function (context) { if (context.player.print) { try { context.player.print(); } catch (ex) { print(); } } else { print(); } }, insertContent: function (context, cb) { context.toggleItem('.overlayButtonPrint', context.opt.content.printable); cb(); } })); /** * If content specifies a download property, that url will be opened in * the current window. */ /** * If content specifies a download property, that url will be opened in * the current window. */ modal.addPlugin('buttonDownload', baseButton.create({ buttonName: 'download', pluginOptions: { selectEl: '.overlayNavigationBottom > .overlayNavigationInner', tabindex: 50 }, pluginLang: { text: 'Download' }, onClick: function (context) { this.opt(context).handleClick.call(this, context); }, contextOptions: function () { content: { downloadHref: null } }, pluginOptions: { openNewWindow: false, handleClick: function (context) { if (this.opt(context).openNewWindow) { open(context.opt.content.downloadHref); } else { location = context.opt.content.downloadHref; } } }, insertContent: function (context, cb) { context.toggleItem('.overlayButtonDownload', !!context.opt.content.downloadHref); cb(); } })); /** * If a gallery is specfied, buttons to move between that galleries elements are * added to all navigations inside the given container. */ modal.addPlugin('galleryNav', basePlugin.create({ pluginOptions: { hotKeys: true, isCircular: true, order: 'previous next', selectEl: '.overlayNavigationTop > .overlayNavigationInner, .overlayNavigationAbove > .overlayNavigationInner' }, pluginLang: { next: 'Next', previous: 'Previous' }, initContainer: function () { $(document).bind('keyup', iTim.bind(function (e) { var context = modal.get(); if (context) { var opt = this.opt(context); if (!opt.hotKeys) { return; } var gallery = galleries[context.opt.content.gallery]; if (!gallery) { return; } if (e.metaKey || e.ctrlKey || e.altKey) { return; } var index = $.inArray(context.opt.modalId, gallery); switch (e.keyCode) { case 27: context.sendHide(); e.preventDefault(); break; case 37: if (!opt.isCircular && !modal.galleryHasPrevious()) { return; } e.preventDefault(); modal.galleryPrevious(); break; case 39: case 32: if (!opt.isCircular && !modal.galleryHasNext()) { return; } e.preventDefault(); modal.galleryNext(); break; } } }, this)); }, insertHtml: function (context, cb) { var opt = this.opt(context); var nav = context.select(opt.selectEl); var gallery = galleries[context.opt.content.gallery]; var buttons = {}; buttons.previous = $.tmpl(context.opt.templates.button, { cls: 'overlayButtonPrevious', title: this.lang(context, 'previous'), tabindex: 30 }).bind('click', function (e) { e.preventDefault(); if (!opt.isCircular && !modal.galleryHasPrevious()) { return; } modal.galleryPrevious(); }).bind('keypress', function (e) { if (e.keyCode == 13) { e.preventDefault(); if (!opt.isCircular && !modal.galleryHasPrevious()) { return; } modal.galleryPrevious(); } }); buttons.next = $.tmpl(context.opt.templates.button, { cls: 'overlayButtonNext', title: this.lang(context, 'next'), tabindex: 20 }).bind('click', function (e) { e.preventDefault(); if (!opt.isCircular && !modal.galleryHasNext()) { return; } modal.galleryNext(); }).bind('keypress', function (e) { if (e.keyCode == 13) { e.preventDefault(); if (!opt.isCircular && !modal.galleryHasNext()) { return; } modal.galleryNext(); } }); opt.order.replace(/\w+/g, function (match) { nav.append(buttons[match]); return ''; }); cb(); }, insertContent: function (context, cb) { var opt = this.opt(context); var gallery = galleries[context.opt.content.gallery]; context.toggleItem('.overlayButtonNext, .overlayButtonPrevious', gallery && gallery.length > 1); var hasNext = !opt.isCircular && !modal.galleryHasNext(); var hasPrevious = !opt.isCircular && !modal.galleryHasPrevious(); var next = context.select('.overlayButtonNext').toggleClass('overlayGalleryItemInactive', hasNext).attr('aria-disabled', hasNext); context.select('.overlayButtonPrevious').toggleClass('overlayGalleryItemInactive', hasPrevious).attr('aria-disabled', hasPrevious); cb(); } })); /** * Appends a close button to each navigation. */ modal.addPlugin('buttonClose', baseButton.create({ buttonName: 'close', pluginOptions: { selectEl: '.overlayNavigationTop > .overlayNavigationInner', tabindex: 10 }, pluginLang: { text: 'Close' }, onClick: function (context) { context.sendHide(); } })); /** * Adds the description container */ modal.addPlugin('description', basePlugin.create({ contextOptions: { content: { descriptionCacheKey: null, description: null } }, pluginOptions: { where: 'append', method: 'clone', selectEl: 'content' }, insertHtml: function (context, cb) { var opt = this.opt(context); context.select(opt.selectEl)[opt.where]('<div class="overlayDescription" id="overlayDescription"></div>'); cb(); }, insertContent: function (context, cb) { var opt = this.opt(context); var description = $.contextual.linkDescriptions[context.opt.content.descriptionCacheKey]; if (!description && context.opt.content.description) { description = context.opt.content.description; if (typeof description == 'function') { description = description.apply(context); } description = $('<div class="overlayDescriptionText"></div>').append(description); } var hasDescription = !!(description && description.length); context.toggleItem('.overlayDescription', hasDescription); if (!hasDescription) { cb(); return; } if (opt.method == 'clone') { description = description.clone(true); } context.select('.overlayDescription').append(description); cb(); } })); /** * Constrains all content inside overlayContentInner to the width of the content if defined. */ modal.addPlugin('constrainToContentWidth', basePlugin.create({ pluginOptions: { // which elements to constrain, sets a fixed width selectEl: '.overlayContentInner' }, beforeTransitionIn: function (context, cb) { context.select(this.opt(context).selectEl).each(function () { var el = $(this); var calcWidth = context.opt.content.width ? context.opt.content.width : Math.min(context.select('content').width(), el.width()) + 'px'; var calcHeight = context.opt.content.height ? context.opt.content.height : Math.min(context.select('content').height(), el.height()) + 'px'; if ("auto" == context.opt.content.originalHeight) { el.css({ width: calcWidth, height: calcHeight}); } else { el.css({ width: calcWidth}); } }); cb(); } })); /** * Positions the layer inside the given constraints */ modal.addPlugin('position', basePlugin.create({ pluginOptions: { selectEl: 'layer', // possible values: screen, else this is treated as a selector constrainTo: 'screen', // possible values: center, else a left-/top-based position in px position: 'center', // override for vertical direction verticalConstrainTo: null, verticalPosition: null, // override for horizontal direction horizontalConstrainTo: null, horizontalPosition: null }, viewportChanged: function (context, cb) { var opt = this.opt(context); var el = context.select(opt.selectEl); var width = el.outerWidth(false); var height = el.outerHeight(false); var verticalConstrainTo = opt.constrainTo; var horizontalConstrainTo = verticalConstrainTo; var verticalPosition = opt.position; var horizontalPosition = verticalPosition; if (opt.verticalConstrainTo != null) { verticalConstrainTo = opt.verticalConstrainTo; } if (opt.verticalPosition != null) { verticalPosition = opt.verticalPosition; } if (opt.horizontalConstrainTo != null) { horizontalConstrainTo = opt.horizontalConstrainTo; } if (opt.horizontalPosition != null) { horizontalPosition = opt.horizontalPosition; } var left = 0; var constrainWidth = $(window).width(); if (horizontalConstrainTo == 'screen') { context.containerEl.css({ left: $(document).scrollLeft() + 'px' }); } else { context.containerEl.css({ left: 0 }); constrainWidth = $(horizontalConstrainTo).width(); } if (horizontalPosition == 'center') { left += Math.max(0, (constrainWidth - width) / 2) >>> 0; } else { left += horizontalPosition; } var top = 0; var constrainHeight = $(window).height(); if (verticalConstrainTo == 'screen') { context.containerEl.css({ top: $(document).scrollTop() + 'px' }); } else { context.containerEl.css({ top: 0 }); constrainHeight = $(verticalConstrainTo).height(); } if (verticalPosition == 'center') { var $htmlNode = jQuery('html'); var spaceTop = ($htmlNode.hasClass('portal_app') && $htmlNode.hasClass('is_apple_device')) ? 40 : 15; top += $(document).scrollTop() + (Math.max(spaceTop, (constrainHeight - height) / 2) >>> 0); } else { top += verticalPosition; } el.css({ top: top + 'px', left: left + 'px' }); // background size calculate var body_ = document.body, html_ = document.documentElement; var bgHeight = Math.max( body_.scrollHeight, body_.offsetHeight, html_.clientHeight, html_.scrollHeight, html_.offsetHeight); var bgWidth = Math.max( body_.scrollWidth, body_.offsetWidth, html_.clientWidth, html_.scrollWidth, html_.offsetWidth); jQuery(context.containerEl[0].firstChild).css({ height: bgHeight + 'px', width: bgWidth + 'px' }); cb(); }, beforeTransitionIn: function (context, cb) { return this.viewportChanged.apply(this, arguments); } })); /** * Fades in and out. * Resets opacity styles on complete. */ modal.addPlugin('transitions', basePlugin.create({ pluginOptions: { duration: 0.4 * 1000, easing: 'swing', selectEl: 'layer' }, beforeTransitionIn: function (context, cb) { context.select(this.opt(context).selectEl).css({ opacity: 0, visibility: 'visible' }); cb(); }, transitionIn: function (context, cb) { context.select(this.opt(context).selectEl).animate({ opacity: 1 }, { duration: this.opt(context).duration, easing: this.opt(context).easing, complete: cb }); }, afterTransitionIn: function (context, cb) { context.select(this.opt(context).selectEl).css({ opacity: '', visibility: '' }); cb(); }, transitionOut: function (context, cb) { context.select(this.opt(context).selectEl).animate({ opacity: 0 }, { duration: this.opt(context).duration, easing: this.opt(context).easing, complete: cb }); } })); /** * Captures click events on links or form submission or mosuewheel scrolling. */ modal.addPlugin('eventCapture', basePlugin.create({ pluginOptions: { forms: true, links: true, mousewheel: false }, initContainer: function (context, cb) { context.containerEl.bind('DOMMouseScroll mousewheel', iTim.bind(function (e) { var context = $.modalOverlay.get(); if (context && this.opt(context).mousewheel) { e.preventDefault(); } }, this)); cb(); }, beforeTransitionIn: function (context, cb) { var el = context.select('.overlayPlayerContent'); this.bindCaptureHandlers(el, context); cb(); }, bindCaptureHandlers: function (el, context) { var plugin = this; var opt = this.opt(context); var base = iTim.url(location).resolve(context.opt.content.href || ''); if (opt.forms) { el.find('form').each(function () { var wasInvalid = false; // bind to default validation event $(this).bind('invalid-form', function () { wasInvalid = true; }).bind('submit', function (e) { // if this attempt to submit was denied by validation, do not trigger ajax submit if (wasInvalid) { wasInvalid = false; return; } e.preventDefault(); var url = base.resolve($(this).attr('action')).href; $.ajax({ type: this.method || 'get', url: url, data: $(this).serializeArray(), complete: function (res) { el.html($.modalOverlay.players.ajax.getContent(res.responseText, url)); plugin.bindCaptureHandlers(el, context); } }); }); }); } if (opt.links) { el.find('a[href]:not([href="#"], [href=""], [href*="mailto:"], [href*="javascript:"], [target=_blank], [target=_top], [target=_parent])').bind('click', function (e) { e.preventDefault(); var url = base.resolve($(this).attr('href')).href; $.ajax({ type: 'get', url: url, complete: function (res) { el.html($.modalOverlay.players.ajax.getContent(res.responseText, url)); plugin.bindCaptureHandlers(el, context); } }); }); } } })); /** * Send event for each phase. * Each handler will be triggered bound to the active instance with a jquery event arg. */ modal.addPlugin('events', basePlugin.create({ pluginOptions: { namespace: '.overlayEvents', initContainer: null, insertHtml: null, preload: null, insertContent: null, beforeTransitionIn: null, transitionIn: null, afterTransitionIn: null, beforeTransitionOut: null, transitionOut: null, afterTransitionOut: null, hideContainer: null, viewportChanged: null }, callMethod: function (method, who, cb) { // init event triggered by this.initContainer var opt = this.opt(who); if (undefined != this.opt(who)[method]) { opt[method].call(who); } return this.__prototype.callMethod.apply(this, arguments); } })); })(jQuery); /** * Preloads items adjacent to the currently visible lightbox. */ (function ($) { var modal = $.modalOverlay; var async = $.modalOverlay; modal.addPlugin('preloadGalleryItems', async.basePlugin.create({ el: null, pluginOptions: { numberOfAdjacentItems: 2 }, afterTransitionIn: function (context, cb) { var gallery = modal.galleries[context.opt.content.gallery]; if (!gallery) { cb(); return; } var num = this.opt(context).numberOfAdjacentItems; var item = null; var index = null; for (var i = context.opt.galleryIndex - num, length = context.opt.galleryIndex + num; i < length; ++i) { if (i == context.opt.galleryIndex) { continue; } if (i < 0) { index = gallery[gallery.length + i]; } else { index = gallery[i % gallery.length]; } item = modal.instances[gallery[index]]; if (!item) { continue; } item.plugins.items.player.callMethod('preload', item, function () {}); } cb(); } })); })(jQuery); (function ($) { var modal = $.modalOverlay; modal.addPlugin('weeBitMoreA11y', $.modalOverlay.basePlugin.create({ a11yLabel: null, lastInstanceClosedByHash: null, pluginLang: { loading: 'Please wait' }, pluginOptions: { monitorHash: true }, initContainer: function (context, cb) { this.a11yLabel = $('<label aria-live="polite" class="overlayA11yLabel" tabindex="0"></label>').appendTo(context.containerEl); if (this.opt(context).monitorHash) { $(window).bind('hashchange', iTim.bind(this.onHashChange, this)); } cb(); }, onHashChange: function () { if (location.hash != '#lightbox') { if (modal.get()) { this.lastInstanceClosedByHash = modal.get(); modal.close(); } } else { if (this.lastInstanceClosedByHash && this.lastInstanceClosedByHash != modal.get()) { this.lastInstanceClosedByHash.sendShow(); this.lastInstanceClosedByHash = null; } } }, insertHtml: function (context, cb) { location = '#lightbox'; if (context.state.opening) { this.disablePageInputs(context); } cb(); }, disablePageInputs: function (context) { context.containerEl.siblings().find('span[tabindex], div[tabindex], input, textarea, select, a, iframe').each(function (i, el) { el = $(el); if (null == el.data('originalTabIndex' + context.opt.namespace)) { el.data('originalTabIndex' + context.opt.namespace, el.attr('tabindex')); } el.attr('tabindex', -1) }); }, preload: function (context, cb) { if (!context.opt.preloaded) { this.a11yLabel.html(this.lang(context, 'loading')); } cb(); }, insertContent: function (context, cb) { // not very useful? // context.el.attr('aria-describedby', 'overlayHelp'); this.a11yLabel.empty(); context.select('.overlayPlayerContent').attr({ 'id': 'overlayPlayerContent', 'aria-describedby': 'overlayDescription', 'aria-labelledby': 'overlayTitle' }); context.select('.overlayButtonClose').attr('aria-flowto', 'overlayPlayerContent'); cb(); }, afterTransitionIn: function (context, cb) { cb(); context.select('.overlayButtonClose:first').focus(); }, afterTransitionOut: function (context, cb) { if (!context.state.changing) { this.enablePageInputs(context); if (context.linkEl) { context.linkEl.focus(); } } cb(); }, enablePageInputs: function (context) { context.containerEl.siblings().find('span[tabindex], div[tabindex], input, textarea, select, a, iframe').each(function (i, el) { el = $(el); el.attr('tabindex', el.data('originalTabIndex' + context.opt.namespace)); }); } })); })(jQuery); jQuery(function($){ // inputs with default text // Beispiel: <dkb:dateinput aspect="fromSigningDate" cssclass="text small {'default':'TT.MM.JJJJ'}" /> // deprecatd (use placeholder instead) $('input:text, .text').each(function () { var input = $(this),data = input.metadata(); if (!data['default']) { return; } if (!input.val()) { input.val(data['default']); } input.bind('focusin', function (e) { if (data['default'] == input.val()) { input.val(''); } }).bind('focusout', function (e) { if (!input.val()) { input.val(data['default']); } }); }); // stageModule Navigation border styling $('.stageModule ul.tabs-list').bind('click', function(){ if($(this).find('li:nth-child(2)').hasClass('current')){ $(this).find('li').addClass('noBorder'); }else{ $(this).find('li').removeClass('noBorder'); } }); // filter content $('.categories').each(function () { var isDropdownVisible = false; var menu = $(this).bind('mouseleave', function () { isDropdownVisible = false; menu.removeClass('open'); }); var links = menu.find('ul > li > a').bind('click', function (e) { if (isDropdownVisible) { isDropdownVisible = false; menu.removeClass('open'); return; } isDropdownVisible = true; menu.addClass('open'); e.preventDefault(); }); var selectCategory = function(){ if($('body').find(location.hash).length > 0) { var category = location.hash; var link = category ? links.filter(iTim.format('[href={0}]', category)) : []; if (!link.length) { link = links.eq(0); category = link.attr('href'); } links.parent().removeClass('activeLink'); link.parent().addClass('activeLink'); $(category).addClass('active').siblings('.category').removeClass('active'); } }; $(window).bind('hashchange', selectCategory); selectCategory(); }); //teaserUSP slider - addClass 'active' to first element $('.teaserUSP .slideStart').each( function(){ $(this).find('.slider .sliderItems .teaser').first().addClass('active'); }); // Club Slider $('.slider').closest('.slideStart').scrollk({ selectItem: '.teaser', selectButtonPrevious: '.prev .icons', selectButtonNext: '.next .icons', classButtonActive: 'show', onPagesRefreshed: function () { this.el.find('.pager').toggle(this.pages.length > 1); } }); // Checkbox aktiviert Select $('.ticketTable .inputParent').each(function (i, input) { input = $(input); input.attr('data-enables', '#' + iTim.id(input.closest('tr').find('.inputChild').get(0))); }); }); (function ($, iTim) { var storedOptions = iTim.StoredOptions; var defaultOptions = $.extend(true, $.modalOverlay.options, { modal: true, content: { width: 540 }, plugins: { description: { where: 'before', selectEl: '.overlayNavigationBottom' }, galleryDescription: false, navigationAbove: false, buttonPrint: false, copyright: false, weeBitMoreA11y: false, galleryNav: { isCircular: false }, inline: { clone: false }, title: false, buttonPrint: false, buttonDownload: false, eventCapture: false, shadow: false }, lang: {} }); storedOptions.set('overlayDefault', defaultOptions); jQuery(function () { // import translations $.each($.modalOverlay.options.lang, function (key, label) { defaultOptions.lang[key] = iTim.translate('lightbox_' + key.replace('.', '_'), label); }); // kept for backwards-compatibility storedOptions.set('messageBox', { inherits: 'overlayDefault' }); storedOptions.set('iFrameContent', { inherits: 'overlayDefault' }); storedOptions.set('messageBoxRemote', { inherits: 'overlayDefault', skin: 'messageBoxRemote', content: { player: 'iframe', width: 550 } }); bindModalOverlay(true); }); })(jQuery, iTim); function bindModalOverlay(isInitialCall) { jQuery('a.modal, button.modal').each(function(){ var $a = jQuery(this); if (!$a.hasClass('modalOverlayBound')) { if (isInitialCall) { $a.modalOverlay({ inherits: 'overlayDefault' }); } else { //link ist innerhalb eines dialogs $a.on('click', function(e) { e.preventDefault; e.stopPropagation(); jQuery(this).off('click'); handleLinkToModalFromAModal(this); return false; }); } $a.addClass('modalOverlayBound'); } }); jQuery('a.innerOverlayCustomClose, button.innerOverlayCustomClose, input.innerOverlayCustomClose').off('click').on('click', function(){ jQuery.modalOverlay.close(); return false; }); } function handleLinkToModalFromAModal(btn) { //move button outside of current Modal jQuery('body').append(btn); jQuery(btn).prop('id', 'hiddenModalTrigger').css('display','none'); //close current modal jQuery.modalOverlay.closeFast(); //now bind default onclick handler to the new href jQuery(btn).modalOverlay({ inherits: 'overlayDefault' }); // clicke den button nun zeitversetzt an, damit das neue modal fenster geoeffnet wird window.setTimeout(function () { jQuery('#hiddenModalTrigger').click(); jQuery(btn).prop('id', ''); }, 100); } /** * Bei einem Partial Load muss das Plugin an die neuen DOM-Elemente gebunden werden */ jQuery(document).on('abx_partial_load', function() { bindModalOverlay(true); }); /** * Wird noch verwendet (last check: 2.5.2017) von AccountMoving * * Searches the document for input elements with an attribute "data-enables" ("toggle inputs"). * * Each such attribute contains a selector that points toward an element * containing other input and select elements. * * Depending on whether the toggle input is checked or not the state of its target group is * toggled accordingly. * * Example HTML: * <p id="groupOtherAccount"> * <input type="radio" name="Account" data-enables="#groupOtherAccount"> * <input type="text" name="someText"> * </p> * */ jQuery(function($){ var toggleInputs = function (checkbox, doNotToggleGroupMembers) { checkbox = $(checkbox); var container = $(checkbox.data('enables')); var inputs = container.find('input, select').not(checkbox); var checked = checkbox.is(':checked'); var selectboxMethod = checked ? '_enableSelectbox' : '_disableSelectbox'; container.toggleClass('disabled', !checked); inputs.prop('disabled', !checked); inputs.filter('select').each(function () { $.selectbox && $.selectbox[selectboxMethod](this); }); if (!doNotToggleGroupMembers) { $('[name=' + checkbox.attr('name') + ']').not(checkbox).each(function () { toggleInputs(this, true); }); } }; $('[data-enables]').each(function () { var checkbox = $(this); toggleInputs(this, true); checkbox.add('input[name=' + checkbox.attr('name') + ']:not(data-enables)').click(function(e){ toggleInputs(checkbox); }); }); }); /** * Wird noch verwendet (last check: 2.5.2017). * * im Club (DkbClubCategory > Detail und Overview) * dkb-web\web\parts\shop\category\includes\teaserDetail.jsp * dkb-web\web\parts\shop\category\includes\teaserOverview.jsp * KWK und Shop * dkb-web\web\parts\shop\product\includes\teaser.jsp */ jQuery(function ($) { $(window).bind('load', function () { $('.faderModule').each(function (i, el) { el = $(el); /*fadeIn duration depending on context*/ var defaultFadeIn = 400; var uspFadeIn = 0; var fadeInDuration; if($(this).parent().hasClass('teaserUSP')){ fadeInDuration = uspFadeIn; } else { fadeInDuration = defaultFadeIn; } var index = 0; el.find('.prev').bind('click keypress', function (e) { if (!(e.type == 'click' || e.keyCode == 13)) { return; } e.preventDefault(); var oldIndex = index; index = Math.max(0, index - 1); if (oldIndex == 0) { index=items.length - 1; } update(oldIndex, index); }); el.find('.next').bind('click keypress', function (e) { if (!(e.type == 'click' || e.keyCode == 13)) { return; } e.preventDefault(); var oldIndex = index; index = Math.min(items.length - 1, index + 1); if (oldIndex == index) { index=0; } update(oldIndex, index); }); var update = function (oldIndex, index) { if (oldIndex == index) { //alert('sdsd'); //return; } var itemBefore = items.filter('.active').removeClass('active'); items.eq(index).addClass('active').fadeIn(fadeInDuration).queue(function () { itemBefore.hide(); $(this).dequeue(); }); var hasPrev = index > 0; var hasNext = index < items.length - 1; //el.find('.prev .icons').toggleClass('show', hasPrev).attr('aria-disabled', !hasPrev); //el.find('.next .icons').toggleClass('show', hasNext).attr('aria-disabled', !hasNext); }; var items = el.find('.teaser'); var height = 0; items.each(function () { var itemHeight = $(this).height(); if (height < itemHeight) { height = itemHeight; } }); el.find('.sliderItems').add(items).css({ height: height }); el.addClass('activated'); items.filter(':gt(0)').hide(); }); }); }); /* * Dient zum registrieren von JavaScript-Funktionen zu Events * Wenn das angegebene Event gefeuert wurde, wird die ebenfalls angegebene * JS-Methode ausgef�hrt */ function addEvent(obj, event, functionToCall) { if (obj.addEventListener) { obj.addEventListener(event, functionToCall, false); return true; } else if (obj.attachEvent) { var r = obj.attachEvent("on" + event, functionToCall); return r; } else { return false; } } /* * Select deselct all entrys in a dkb:table. */ function toggleAll(name, control) { var f = control.form; for (var i = 0; i < f.length; i++) { if (f[i].name == name) { f[i].checked = control.checked; } } } /** * Toggles the disabled attribute of an select element and its children (options) * * @param selectElement * @param disabled */ function toggleDisabledSelect(selectElement, disabled) { if (!selectElement) { return; } selectElement.disabled = disabled; var options = selectElement.getElementsByTagName("option"); for (var i = 0; i < options.length; i++) { options[i].disabled = disabled; } } /* * Zeigt ein InfoPopUp an * Zu �bergeben sind die Id des Divs, das in den Vordergrund geschoben werden soll * und das aufrufende Html-Objekt um die Position zu bestimmen */ function showInfoPopUp(idTarget, caller) { jQuery(caller).mouseover(function (e) { // Set the X and Y axis of the tooltip jQuery('#' + idTarget).css('display', 'block'); jQuery('#' + idTarget).css('top', e.pageY + 10); jQuery('#' + idTarget).css('left', e.pageX + 20); }).mousemove(function (e) { // Keep changing the X and Y axis for the tooltip, thus, the tooltip move along with the mouse jQuery('#' + idTarget).css('top', e.pageY + 10); jQuery('#' + idTarget).css('left', e.pageX + 20); }).mouseout(function () { jQuery('#' + idTarget).css('display', 'none'); }); } /* * Entfernt die Markierung (Bold) der "title" Zeile in einer Tabelle. * Erh�lt �ber 'this' die Referenz auf ein Tabellenzelle. */ function markAsRead(caller) { if (null != caller && 'A' == caller.tagName && null != caller.parentNode) { var cell = caller; while ('TR' != cell.tagName && null != cell) { cell = getParent(cell); } // resolve title column var tr = cell; for (var i = 0; i < tr.childNodes.length; i++) { cell = tr.childNodes[i]; if (cell.nodeName != '#text' && cell.id == 'title') break; } if (null != cell) { for (var i = 0; i < cell.childNodes.length; i++) { var current = cell.childNodes[i]; if (current.nodeName != '#text' && current.tagName == 'STRONG') { var tmp; for (var j = 0; j < current.childNodes.length; j++) { tmp = current.childNodes[j]; if (current.childNodes[j].nodeName != '#text') break; } if (null != tmp) { cell.removeChild(current); cell.appendChild(tmp); } } } } } } function getParent(caller) { if (null != caller.parentNode) { return caller.parentNode; } else return null; } //ajax request sometimes caused a hanging request in //https, apache, ie constellation //so we abort after 10 seconds function callInProgress(xmlhttp) { console.debug("checking XMLRequest status..."); switch (xmlhttp.readyState) { case 1: case 2: case 3: return true; break; // Case 4 and 0 default: return false; break; } } function showFailureMessage() { // alert('Request timeout. Click Ok to continue'); } function hideShowCovered(caller) { var self = caller; var el = caller; function isContained(el) { while (el) { if (el == self.element) { return true; } el = el.parentNode; } return false; }; var tags = new Array("select"); var p = getAbsolutePos(el); var EX1 = p.x; var EX2 = el.offsetWidth + EX1; var EY1 = p.y; var EY2 = el.offsetHeight + EY1; if (el.style.display == "none") { EX1 = EX2 = EY1 = EY2 = 0; } for (var k = tags.length; k > 0;) { var ar = document.getElementsByTagName(tags[--k]); var cc = null; for (var i = ar.length; i > 0;) { cc = ar[--i]; if (isContained(cc)) { cc.style.visibility = "visible"; continue; } p = getAbsolutePos(cc); var CX1 = p.x; var CX2 = cc.offsetWidth + CX1; var CY1 = p.y; var CY2 = cc.offsetHeight + CY1; if ((CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) { cc.style.visibility = "visible"; } else { cc.style.visibility = "hidden"; } } } }; var getAbsolutePos = function (el) { var r = {x: el.offsetLeft, y: el.offsetTop}; if (el.offsetParent) { var tmp = getAbsolutePos(el.offsetParent); r.x += tmp.x; r.y += tmp.y; } return r; }; function setDateFields(name, radioValue) { var radio = document.getElementsByName(name); for (var index = 0; index < radio.length; index++) { if (radio[index].value == radioValue) { radio[index].checked = true; } } } /** * ersetzt die Zeichen * @param {Object} charToReplace */ function replaceSpecialChars(charToReplace) { var map = specialCharMap(); var newChar = map[charToReplace]; newChar = (newChar == undefined) ? ' ' : newChar; return newChar; } /** * Liste der Sonderzeichen fuer das Ersetzen von Sonderzeichen bei Ueberweisungen */ function specialCharMap() { var map = { '�': 'A', '�': 'A', '�': 'A', '�': 'e', '�': 'AE', '�': 'A', '�': 'E', '�': 'E', '�': 'E', '�': 'E', '�': 'I', '�': 'I', '�': 'I', '�': 'I', '�': 'I', '�': 'I', '�': 'N', '�': 'O', '�': 'O', '�': 'O', '�': 'O', '�': 'OE', '�': 'U', '�': 'U', '�': 'UE', '�': 'Y', '�': 'O', '?': 'S', '?': 'Z', '?': 'z', '?': 'Y', '�': 'ss', '�': 'a', '�': 'a', '�': 'a', '�': 'a', '�': 'a', '�': 'ae', '�': 'a', '�': 'a', '�': 'c', '�': 'e', '�': 'e', '�': 'e', '�': 'e', '�': 'i', '�': 'i', '�': 'i', '�': 'i', '�': 'n', '�': 'o', '�': 'o', '�': 'o', '�': 'o', '�': 'oe', '�': 'u', '�': 'u', '�': 'u', '�': 'u', '�': 'ue', '�': 'y', '�': 'ss' } return map; } function getNumberFromInput(field) { var fields = document.getElementsByName(field); if (fields.length == 0) return 0; var value = fields[0].value; value = value.replace('.', ''); value = value.replace(',', '.'); return parseFloat(value); } function setInputToNumber(field, value) { var fields = document.getElementsByName(field); if (fields.length == 0) return; var s = '' + value.toFixed(2); s = s.replace('.', ','); fields[0].value = s; } if (Abaxx.widgets.sessionInfo) { Abaxx.widgets.sessionInfo.resetSessionTimeout = function () { if (typeof currentSessionInfo != 'undefined') { currentSessionInfo.resetSessionTimeout(); } } } ;// end function // modales overlay oeffnen function dkbModalOverlay(divId) { var modalOverlay = jQuery.modalOverlay.show({ inherits: divId, content: {href: '#' + divId} }); jQuery('#' + divId).show(); return modalOverlay; } /** * SEPA 2.0 */ var SEPA_2_0 = { prepareBicHandling: function (codes) { this.maskIbanInput('#creditorAccountNo'); if (jQuery('html').hasClass('is_android')) { jQuery('#creditorAccountNo').bind("blur", function (event) { // DKBP-994 Eingabe bei verlassen des Feldes formatieren SEPA_2_0.maskIbanManually(this); }); } jQuery('#creditorAccountNo').bind("change keypress keyup input", function (event) { //DKBP-3486 (Refactoring von DKBP-993) if (jQuery('html').hasClass('is_android')) { var text = jQuery("#creditorAccountNo").val().replace(/[^a-zA-Z0-9.\s]/g, ''); jQuery("#creditorAccountNo").val(text); } SEPA_2_0.showOrHideBic(codes); }); jQuery("input:checkbox[name='foreignAccountRemittance']").click(function () { SEPA_2_0.showOrHideBic(codes); }); SEPA_2_0.showOrHideBic(codes); }, prepareIbanHandling: function () { if (jQuery('html').hasClass('is_android')) { jQuery('#creditorAccountNo').bind("blur", function (event) { // DKBP-994 Eingabe bei verlassen des Feldes formatieren SEPA_2_0.maskIbanManually(this); }); } jQuery('#creditorAccountNo').bind("change keyup keypress input", function (event) { //DKBP-3486 (Refactoring von DKBP-993) if (jQuery('html').hasClass('is_android')) { var text = jQuery("#creditorAccountNo").val().replace(/[^a-zA-Z0-9.\s]/g, ''); jQuery("#creditorAccountNo").val(text); } SEPA_2_0.handleGermanIban(); }); this.maskIbanInput('#creditorAccountNo'); jQuery("input:checkbox[name='foreignAccountRemittance']").click(function () { SEPA_2_0.handleGermanIban(); }); SEPA_2_0.handleGermanIban(); }, maskIbanManually: function (selector) { var plainIban = selector.value.replace(/\s/g, ""); var maskedIban = ""; for (var i = 0; i < plainIban.length; i+=4) { var subIban = plainIban.substring(i,Math.min(i+4,plainIban.length)) maskedIban += subIban; if (subIban.length == 4) { maskedIban+=" "; } } selector.value = maskedIban; }, maskIbanInput: function (selector) { //DKBIB-7673 - keine formatierung bei allen android ger�ten if (!jQuery('html').hasClass('is_android')) { jQuery(selector).mask('AAAA AAAA AAAA AAAA AAAA AAAA AAAA AAA'); } }, showOrHideBic: function (codes) { var $creditorBankcode = jQuery('#creditorBankcode'); var isForeignRemittanceChecked = jQuery("input:checkbox[name='foreignAccountRemittance']").is(':checked'); var $creditorAccountNoInput = jQuery.trim(jQuery('#creditorAccountNo').val()); if ($creditorAccountNoInput.length > 0) { var iban = $creditorAccountNoInput; var ibanLangCode = iban.substring(0, 2).toUpperCase(); var isNotEWR = iban.length >= 2 && codes.indexOf(ibanLangCode) == -1; var notIBAN = iban.length >= 1 && !/^[a-zA-Z]+/.test(iban.substring(0, 1)); if (iban.length == 1 && !notIBAN) { return; } var $creditotBankName = jQuery('#creditorBankName'); if ($creditotBankName.length > 0) { if (isNotEWR || notIBAN || ibanLangCode == 'DE') { $creditotBankName.show(); } else { $creditotBankName.hide(); } } if ($creditorBankcode.length > 0) { if (isNotEWR || notIBAN || isForeignRemittanceChecked) { $creditorBankcode.show(); } else { $creditorBankcode.hide(); var $creditorBic = jQuery('#creditorBic'); if ($creditorBic.length > 0) { $creditorBic.val(''); } } } } else if (isForeignRemittanceChecked) { $creditorBankcode.show(); } else { $creditorBankcode.hide(); } }, handleGermanIban: function () { var $creditorAccountNoInput = jQuery.trim(jQuery('#creditorAccountNo').val()); if ($creditorAccountNoInput.length > 0) { var iban = $creditorAccountNoInput; var ibanLangCode = iban.substring(0, 2).toUpperCase(); var isForeignRemittanceChecked = jQuery("input:checkbox[name='foreignAccountRemittance']").is(':checked'); try { // maybe not all of this inputs are available if (!isForeignRemittanceChecked && iban.length >= 2 && !/^[a-zA-Z]+/.test(iban.substring(0, 1))) { jQuery('#creditorBankcode').show(); jQuery('#creditorBankName').show(); } else { if (!isForeignRemittanceChecked && ibanLangCode == 'DE') { jQuery('#creditorBankcode').hide(); jQuery('#creditorBic').val(''); } else { jQuery('#creditorBankcode').show(); jQuery('#creditorBankName').show(); } } } catch (e) { //console.log('handleGermanIban'); //console.log(e); } } }, isAndroidFF: function () { return jQuery('html').hasClass('is_android') && navigator.userAgent.toLowerCase().indexOf('firefox') > -1; } }; function setCreditorAccountNoIbanLabel() { var labelCreditorAccountNoIban = jQuery("label[id='labelCreditorAccountNoIban']"); var labelCreditorIban = jQuery("label[id='labelCreditorIban']"); if (jQuery("input:checkbox[name='foreignAccountRemittance']").is(':checked')) { labelCreditorAccountNoIban.show(); labelCreditorIban.hide(); } else { labelCreditorAccountNoIban.hide(); labelCreditorIban.show(); } } /** * IE11 kennt startsWith nicht */ if (!String.prototype.startsWith) { String.prototype.startsWith = function (searchString, position) { position = position || 0; return this.indexOf(searchString, position) === position; }; } /** * Funktion zur Sortierung von DOM-Elementen * Beispiel: * <pre> * $element.children().sortDomElements(function(a,b) { * // spezifische Vergleichsfuntion, die aus Vergleich von a mit b 0/-1/1 zur�ckliefert * }); * </pre> * * @param compareFunction */ jQuery.fn.sortDomElements = function (compareFunction) { return Array.prototype.sort.call(this, compareFunction).each(function (i) { this.parentNode.appendChild(this); }); }; // Polyfill f�r debounce-Funktion (aus Underscore.js) // 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. // Beispiel: // window.addEventListener('resize', debounce(function() { ... }), 250); if (typeof debounce !== "function") { debounce = 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); }; }; } // Polyfill f�r IE CustomEvent (siehe https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent) (function () { if ( typeof window.CustomEvent === "function" ) return false; function CustomEvent ( event, params ) { params = params || { bubbles: false, cancelable: false, detail: null }; var evt = document.createEvent( 'CustomEvent' ); evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail ); return evt; } window.CustomEvent = CustomEvent; })(); /** * Testet ob DynaTrace verf�gbar ist */ function isDynaTraceAvailable() { return typeof dT_ != "undefined" && typeof dtrum != "undefined"; }; // Browser sleep check start var lastBrowserSleepCheck = 0; var browserSleepCheckCallback = {}; var browserSleepCheckInterval; function browserSleepCheck() { if ((new Date().getTime() - lastBrowserSleepCheck) > 2000) { for (var key in browserSleepCheckCallback) { if (typeof browserSleepCheckCallback[key] == 'function') { browserSleepCheckCallback[key](); } } } lastBrowserSleepCheck = new Date().getTime(); } window.onload = function () { try { clearInterval(browserSleepCheckInterval); } catch (e) { } lastBrowserSleepCheck = new Date().getTime(); browserSleepCheckInterval = window.setInterval(browserSleepCheck, 1000); }; // Browser sleep check end jQuery.ajaxSetup({cache: false}); var jsMediaQueryInitialized = false; function initializeJsMediaQuery() { var header_helpers = function (class_array) { var i = class_array.length; var head = jQuery('head'); while (i--) { if (head.has('.' + class_array[i]).length === 0) { head.append('<meta class="' + class_array[i] + '" />'); } } }; header_helpers([ 'foundation-mq-xxsmall', 'foundation-mq-xsmall', 'foundation-mq-small', 'foundation-mq-medium', 'foundation-mq-large', 'foundation-mq-xlarge', 'foundation-mq-xxlarge', 'foundation-data-attribute-namespace']); jsMediaQueryInitialized = true; } function mediaQueryBySize(size) { if (!jsMediaQueryInitialized) { initializeJsMediaQuery(); } return jQuery('head').find('.foundation-mq-' + size).css('font-family').replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g, ''); } function mediaQueryXXSmall() { return mediaQueryBySize('xxsmall'); } function mediaQueryXSmall() { return mediaQueryBySize('xsmall'); } function mediaQuerySmall() { return mediaQueryBySize('small'); } function mediaQueryMedium() { return mediaQueryBySize('medium'); } function mediaQueryLarge() { return mediaQueryBySize('large'); } function mediaQueryXlarge() { return mediaQueryBySize('xlarge'); } function mediaQueryXXLarge() { return mediaQueryBySize('xxlarge'); } function matchMediaQuery(mq) { return window.matchMedia(mq).matches; } function is_xxsmall_up() { return matchMediaQuery(mediaQueryXXSmall()); } function is_xsmall_up() { return matchMediaQuery(mediaQueryXSmall()); } function is_small_up() { return matchMediaQuery(mediaQuerySmall()); } function is_medium_up() { return matchMediaQuery(mediaQueryMedium()); } function is_large_up() { return matchMediaQuery(mediaQueryLarge()); } function is_xxsmall_only() { return is_xxsmall_up() && !is_xsmall_up(); } function is_xsmall_only() { return is_xsmall_up() && !is_small_up(); } function is_small_only() { return is_small_up() && !is_medium_up(); } function is_medium_only() { return is_medium_up() && !is_large_up(); } function is_large_only() { return is_medium_up() && is_large_up(); } function is_touch_device() { try { document.createEvent("TouchEvent"); return true; } catch (e) { return false; } } function is_small_and_down() { var result = !is_medium_up(); if (result) { was_small_down = true; } return result; } function is_medium_and_down() { var result = !is_large_up(); if (result) { was_medium_down = true; } return result; } var was_small_down = false; var was_medium_down = false; if (jQuery.ui != undefined) { jQuery.widget("ui.dialog", jQuery.ui.dialog, { open: function () { this._super(); this.uiDialog.find(':button').blur(); // remove focus from buttons } }); } jQuery(document).ready(function () { if (typeof beforeInitResponsive == 'function') { beforeInitResponsive(); } initResponsive(); }); function initResponsive() { fixPushTanHintMessage(); handleSize(true); enhanceTablePager(); bindOwlCarouselStartseite(); //IE11 Anweisung fuer Transform var ua = window.navigator.userAgent; var msie = ua.indexOf("MSIE "); if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)) { jQuery(".owl-prev").click(function () { jQuery(".owl-wrapper").css('transform', ''); }); jQuery(".owl-next").click(function () { jQuery(".owl-wrapper").css('transform', ''); }); } forceRepaintingcheckboxOnChange(); initTabmodulJsVersion(); handleMultilineSelectCheckbox(); chiptanResponsive(); initTooltips(); closeDialog(); handleDatepickerDialog(); handleWebtreckId(); initDropdown(); //initReiterModul(); jQuery(window).resize(function () { handleSize(); }); // DKBIB-8297 if (typeof handleDynatraceTracking == 'function') { handleDynatraceTracking(); } } //DKBIB-5687: not showing keypad on mobile devices when datepicker is selected function handleDatepickerDialog() { jQuery('input.hasDatepicker').click(function () { if (is_medium_and_down()) { jQuery(this).prop("readonly", true); jQuery(this).next('img.ui-datepicker-trigger').click(); } else { jQuery(this).prop("readonly", false); } }); } //DKBIB-6089: closing layer problem function closeDialog() { // modale Dialog via Klick außerhalb und Klick auf Close-Icon schließbar machen (für mobile auf touchstart, da es sich sonst unter Umständen nicht schließt) jQuery('body').bind("dialogopen", function (event, ui) { if (window.location.href.indexOf('/mailbox') >= 0 || window.location.href.indexOf('/postfach') >= 0) { // Sonderlocke für Mailbox Dialoge. // Hier ist der State am Server wichtig und daher erfolgt das Schließen des Dialogs immer mit Server-Roundtrip. jQuery(".abx-web-hasPopup .ui-widget-overlay").click(function (e) { if (jQuery(".abx-web-hasPopup").length === 0) { return; } Abaxx.dkbMailbox.closeDialog(Abaxx.popups.getPopup(false)) }); jQuery('.ui-dialog-titlebar-close').on('touchstart click', function (e) { Abaxx.dkbMailbox.closeDialog(Abaxx.popups.getPopup(false)); return false; // stops event propagation (damit nach touchstart nicht noch ein click event folgt) }); } else { jQuery('.ui-dialog-titlebar-close').on('touchstart click', function (e) { Abaxx.popups.closePopup(); return false; // stops event propagation (damit nach touchstart nicht noch ein click event folgt) }); jQuery(".abx-web-hasPopup .ui-widget-overlay").click(function (e) { if (jQuery(".abx-web-hasPopup").length === 0) { return; } Abaxx.popups.closePopup(); }); } }); //close video and photo modal-dialog jQuery(document).on("click", ".overlayBg", function (event) { if (jQuery(".hasModalOverlay").length == 0) { return; } jQuery.modalOverlay.hide(); }); } // todo: only trigger when resolution really changes... function handleSize(ignoreHasViewPortChanged) { if (ignoreHasViewPortChanged == true || hasViewPortChanged()) { handleHeadlineForApplicationNav(); addDetailRow(); handleRowSpan(); css_browser_selector(navigator.userAgent); handleTypeNumber(); addFixForOpenKeybordOnMobile(); handleError(); if (is_large_up()) { closeMobileMenu(); } } } var lastDetectedViewportConst; // ACHTUNG: nur 1 mal pro aufloesungsaenderung aufrufbar (liefert nur 1 mal true wenn sich die aufloesung aendert) function hasViewPortChanged() { if (lastDetectedViewportConst == undefined || lastDetectedViewportConst != detectedCurrentViewportConst()) { lastDetectedViewportConst = detectedCurrentViewportConst(); return true; } return false; } function detectedCurrentViewportConst() { if (is_xxsmall_only()) { return 0; } else if (is_xsmall_only()) { return 1; } else if (is_small_only()) { return 2; } else if (is_medium_only()) { return 3; } else if (is_large_only()) { return 4; } } function handleTypeNumber() { // Betrag u. TAN if (is_small_and_down()) { /* jQuery('.typeNumberOnSmall').each(function () { jQuery(this).prop('type', 'number'); jQuery(this).prop('lang', 'de'); jQuery(this).prop('pattern', '[0-9]+([\\.|,][0-9]+)?'); jQuery(this).prop('step', 'any'); });*/ jQuery('.typeTanOnSmall').each(function () { jQuery(this).prop('type', 'tel'); }); } else if (was_small_down) { jQuery('.typeNumberOnSmall, .typeTanOnSmall').each(function () { jQuery(this).removeAttr('type'); jQuery(this).removeAttr('lang'); jQuery(this).removeAttr('pattern'); jQuery(this).removeAttr('step'); }); } jQuery('.verticalAlignCenter').each(function() { jQuery(this).css('margin-top', (jQuery(this).parent().innerHeight()-jQuery(this).outerHeight())/2); }); } function expandableTableToggleDetailsRow(event) { $target = jQuery(event.target); if (!($target.is('input') || $target.is('label.radio') || $target.is('td.mailboxRowSelector') || $target.is('a'))) { var $mainRow = jQuery(this); if (jQuery(this).hasClass('new_row_for_small')) { // dann ist die mainrow (mit dem pfeil) nicht unbedingte die angeklickte zeile $mainRow = jQuery(this).next().prevUntil('tr:not(.new_row_for_small)').last().prev(); } else if (jQuery(this).hasClass('inline-header-row')) { // dann ist diese zeile ueber handlePortfolioOverview hinzu gekommen und die mainrow ist die naechste $mainRow = jQuery(this).next(); } if ($mainRow.hasClass('noActions')) { // noActions --> nicht aufklappen return; } var userClosedRow = $mainRow.hasClass('expand'); // close open detailrows jQuery(this).closest('table').find('tr.expand').each(function () { jQuery(this).removeClass('expand'); }); if (!userClosedRow) { // wenn benutzer nicht auf schliessen geklickt hat $mainRow.addClass('expand'); var $nextTr = $mainRow.next(); if (!$nextTr.hasClass('detailsRow')) { // kann auch uebernaechste sein siehe handleNewRowOnSmall() if ($nextTr.hasClass('new_row_for_small')) { $nextTr.addClass('expand'); } $nextTr = $mainRow.nextUntil('.detailsRow').last().next() } if ($nextTr.hasClass('detailsRow')) { $nextTr.addClass('expand'); } } } } function handleRowSpan() { if (is_small_and_down()) { jQuery('td.use_row_span_2').each(function () { jQuery(this).attr('rowspan','2') }); } else { jQuery('td.use_row_span_2[rowspan]').each(function () { jQuery(this).removeAttr('rowspan'); }); } } function addDetailRow() { if (jQuery('html.ea_expand_table').length > 0) { jQuery(".expandableTable").addClass('forceAllwaysExpand'); } if (is_medium_and_down() || jQuery('.expandableTable.forceAllwaysExpand').length > 0) { handleNewRowOnSmall(); // colspanFallback wird genommen, wenn kein colspan ermittelt werden kann. ansonsten kann es zu darstellungsproblemen // z.b. bei nachtraeglich eingeblendeten tabellen kommen var colspanFallback = 10; var $expandableTables = jQuery('.expandableTable.forceAllwaysExpand'); if (is_medium_and_down()) { $expandableTables = jQuery('.expandableTable'); } $expandableTables.each(function () { var $table = jQuery(this); var colspan = $table.data("dkbExpandableTableDetailsRowColspan"); if (!colspan) { colspan = $table.find("thead > tr:not(.summary-top):first > th:visible").length || colspanFallback; } var $mainRows = $table.find('.mainRow, .mbo-folderview-row'); var $detailRows = $table.find('.detailsRow'); if ($detailRows.length > 0) { //update colspan necessary for resize on forceAllwaysExpand $detailRows.find('td').attr('colspan', colspan); } if ($detailRows.length < $mainRows.length && $table.find('td.actions').length > 0) { // nur wenn tabelle eine spalte mit actions hat aber noch keine detailrow // falls keine sichtbaren header gefunden, lieber zu grossen als zu kleinen colspan waehlen $table.find('.mainRow, .mbo-folderview-row').each(function () { var $mainRow = jQuery(this); var detailsRowId = "detailsRow-" + $mainRow.attr('id'); if (jQuery('#' + detailsRowId).get(0)) { return; } var oldTrClassSelector = 'mainRow'; if ($mainRow.hasClass('mbo-folderview-row')) { oldTrClassSelector = 'mbo-folderview-row'; } // for each row var detailsRowTr = document.createElement('tr'); detailsRowTr.className = 'detailsRow'; detailsRowTr.id = detailsRowId; var detailsRowTd = document.createElement('td'); detailsRowTd.setAttribute('colspan', colspan); detailsRowTr.appendChild(detailsRowTd); var $hrefList = $mainRow.find('.actions a'); if ($hrefList.length == 0) { $mainRow.addClass('noActions'); } $hrefList.each(function () { //for each href in column actions var $action = jQuery(this); var href = $action.attr('href'); if (href != undefined && (href.indexOf('$event') > -1 || $action.prop('onclick') != undefined || $action.prop('onClick') != undefined || $action.hasClass('is_action_button'))) { // ACHTUNG: attr nicht durch prop austauschen!!!! das sonst href="#" komplett anders interpretiert wird var clonedHref = $action.get(0).cloneNode(true); if (jQuery(clonedHref).find('span.icons').length == 0) { //mailbox buttons jQuery(clonedHref).each(function () { var $href = jQuery(this); if ($href.html().trim().length == 0 && $href.prop('title')) { $href.html($href.prop('title')) } }); } jQuery(clonedHref).find('span.icons').each(function () { // wenn es ein icon ist, und keinen Text, aber einen title hat --> verwende title als text var $icon = jQuery(this); if ($icon.html().trim().length == 0 && $icon.prop('title')) { $icon.html($icon.prop('title')) } }); detailsRowTd.appendChild(clonedHref); } }); var next = $mainRow.next(); if (next.length === 0 || next.hasClass(oldTrClassSelector) || next.hasClass('sum') || next.hasClass('loading-bar-row') || next.hasClass('inline-header-row') || next.hasClass('borderDailyBalanceDesc') || next.hasClass('borderDailyBalanceAsc')) { $mainRow.after(detailsRowTr); } else { $mainRow.nextUntil('.' + oldTrClassSelector + ', .sum, .loading-bar-row, .borderDailyBalanceDesc, .borderDailyBalanceAsc').last().after(detailsRowTr); } }); } }); $expandableTables .off("click.expandableTable") .on("click.expandableTable", ".mainRow, .inline-header-row, .mbo-folderview-row, .new_row_for_small", expandableTableToggleDetailsRow); } var oldValue = ''; jQuery('.expandableTable.dateHandling').each(function () { var $table = jQuery(this); if (($table.hasClass('doDateHandlingForSmall') && is_small_only()) || is_xsmall_only() || is_xxsmall_only()) { if ($table.find(".valueDateRow").length === 0) { var colspan = $table.find("thead > tr:first > th:visible").length; var headerText = ($table.find("thead th .valueDateHeader").text() || "Wertstellung") + ": "; $table.find('.mainRow, .mbo-folderview-row').each(function () { // for each row var content = jQuery(this).find('span.valueDate'); if (content != undefined && content.length > 0) { if (oldValue !== content.html()) { oldValue = createValueDateRow(jQuery(this), content, colspan, headerText); } } }); } } else { jQuery($table).find(".valueDateRow").remove(); } }); } function handleNewRowOnSmall() { if (is_small_and_down()) { jQuery('td.use_new_row_on_small:not(.handledNewRowOnSmallDone)').each(function () { var $this = jQuery(this); if ($this.attr("row")) { var oldRow = jQuery("tr.new_row_for_small [row=" + $this.attr("row") + "]"); if (oldRow.length > 0) { oldRow.closest('tr').remove(); } } // detect colspan var useColspan = 1; if ($this.hasClass('use_colspan_2')) { useColspan = 2; } else if ($this.hasClass('use_colspan_3')) { useColspan = 3; } else if ($this.hasClass('use_colspan_4')) { useColspan = 4; } else if ($this.hasClass('use_colspan_5')) { useColspan = 5; } else if ($this.hasClass('use_colspan_6')) { useColspan = 6; } var add_col_before = 0; if ($this.hasClass('add_col_before_1')) { add_col_before = 1; } else if ($this.hasClass('add_col_before_2')) { add_col_before = 2; } else if ($this.hasClass('add_col_before_3')) { add_col_before = 3; } else if ($this.hasClass('add_col_before_4')) { add_col_before = 4; } else if ($this.hasClass('add_col_before_5')) { add_col_before = 5; } // clone old TD in new TR var newTr = document.createElement('tr'); var clonedTd = $this.get(0).cloneNode(true); clonedTd.className = ''; //clear if ($this.hasClass('special_executionDay')) { jQuery(clonedTd).html(jQuery(clonedTd).html().replace(/<br>/g, " ")); } if ($this.hasClass("is_loading")) { jQuery(clonedTd).addClass("is_loading"); } jQuery(clonedTd).attr('colspan', useColspan); for (var i = 0; i < add_col_before; i++) { newTr.appendChild(document.createElement('td')); } newTr.appendChild(clonedTd); var $oldRow = $this.closest('tr'); newTr.className = 'hide-for-medium-up new_row_for_small'; if ($oldRow.hasClass('expand')) { newTr.className += ' expand'; } $oldRow.addClass('old_row_for_small'); if ($oldRow.next().hasClass('new_row_for_small')) { // wenn mehrere spalten nach unten geschoben (bsp: vollmachten) $oldRow.nextUntil('tr:not(.new_row_for_small)').after(newTr); } else { // wenn nur eine Spalte nach unten geschoben $oldRow.after(newTr); } // visibility if (!$this.hasClass('hide')) { $this.addClass('show-for-medium-up'); //Ursprüngliches Input-Field muss auf disabled gesetzt werden, da es sonst mit im Request enthalten ist $this.children("input").prop("disabled", true); } $this.addClass('handledNewRowOnSmallDone'); // move header if (!$this.hasClass('skip_header')) { var $table = $this.closest('table'); var $oldTh; if ($this.attr("headers")) { // if table was generated by xx:table or dkb:table, the td contains an id reference to its header. $oldTh = jQuery("th[id='" + $this.attr("headers") + "']"); } if ($oldTh == undefined || $oldTh.length === 0) { $oldTh = $table.find('th:nth-child(' + (useColspan + 1) + ')'); } if ($oldTh != undefined && $oldTh.length > 0) { if (!$oldTh.hasClass('handledNewRowOnSmallDone')) { $oldTh.addClass('handledNewRowOnSmallDone'); if (!$oldTh.hasClass('hide-for-small-down') && !$oldTh.hasClass('hide')) { $oldTh.addClass('hide-for-small-down'); } // copy old TH in First TH: this will only work if the first column is not hide-for-small var $firstTh = $table.find('th:visible:nth(' + (add_col_before) + ')'); var headlineForSmall = '<span class="show-for-small-down">' + $firstTh.html() + $oldTh.html() + '</span>'; var headlineForMediumUp = '<span class="show-for-medium-up">' + $firstTh.html() + '</span>'; $firstTh.html(headlineForSmall + headlineForMediumUp); } } } }); } } // Chain A Pseudo-Class Problem: http://stackoverflow.com/questions/14201694 (festgestellt mit chrome auf samsung s6 (sm-g920F) - Jira: DKBIB-4050) function forceRepaintingcheckboxOnChange() { jQuery('input[type=checkbox]').on('change', function () { if (is_small_and_down()) { try { // When the checkbox state was changed, then force the browser to repaint the label (and the checkbox symbol in label:after Background) var $nextNode = jQuery(this).next(); // finde zugehoeriges Label if (!$nextNode.is('label')) { $nextNode = $nextNode.next(); } if ($nextNode.is('label')) { $nextNode.css('display', 'none').css('display', ''); } } catch (err) { } } }); } function createValueDateRow(currentObj, content, colspan, headerText) { var dateRowTr = document.createElement('tr'); var dateRowTd = document.createElement('td'); var oldValue = content.html(); dateRowTr.className = 'valueDateRow'; dateRowTd.setAttribute('colspan', colspan); dateRowTr.appendChild(dateRowTd); dateRowTd.innerHTML = headerText + content.html(); currentObj.get(0).parentNode.insertBefore(dateRowTr, currentObj.get(0)); return oldValue; } /** * Wird auf Startseite verwendet * root › Inhalt › _index › 020_subjectsNaviModule * * (eigentlich auch via CMS DocumentTypes SubjectNaviContainer und Privatkunden_Startseite_ThemenEinstieg; * aber es gibt keine Dokumente mehr dazu) * * @requires owlCarousel */ function bindOwlCarouselStartseite() { if (typeof jQuery.fn.owlCarousel !== 'undefined') { var owl = jQuery(".subjectsNaviModule > ul"); owl.owlCarousel({ itemsCustom: [ [0, 1], [390, 2], [440, 2], [512, 2], [595, 3], [768, 5], [1024, 5], [1200, 5], [1400, 5], [1600, 5] ], navigation: true, addClassActive: true, rewindNav: true }); } } /* function handleDateInputForMobile(dateInputSelector) { var originalDateInput = jQuery(dateInputSelector); if (jQuery(originalDateInput)) { var abaxxDatepicker = jQuery(originalDateInput).parents('.abaxx-datepicker'); if (jQuery(abaxxDatepicker)) { if (!jQuery(originalDateInput).hasClass('show-for-large-up')) { // check ob code bereits durchgefuehrt wurde jQuery(originalDateInput).addClass('show-for-large-up'); jQuery(abaxxDatepicker).find('.ui-datepicker-trigger').addClass('show-for-large-up'); var originalInputId = jQuery(originalDateInput).prop('id'); var nativeDateInput = jQuery(document.createElement('input')) .attr('type', 'date') .attr('original_id', originalInputId) .attr('id', originalInputId + '_s') .attr('value', jQuery(originalDateInput).prop('value')) .attr('class', jQuery(originalDateInput).prop('class') + ' show-for-medium-down') .removeClass('show-for-large-up') .val(tryFormatDate(jQuery(originalDateInput).prop('value'),'dd.mm.yy','yy-mm-dd')); jQuery(abaxxDatepicker).append(nativeDateInput); jQuery(nativeDateInput).val(jQuery(nativeDateInput).prop('value')); jQuery('[id="' + originalInputId + '_s"]').bind("change", function (e) { // kopieren den wert zurueck in das originalfeld var originalInputId = jQuery(this).attr('original_id'); var $originalInput = jQuery('[id="' + originalInputId + '"]'); $originalInput.prop('value', tryFormatDate(jQuery(this).prop('value'), 'yy-mm-dd', 'dd.mm.yy')); $originalInput.change(); // damit on change callbacks getriggert werden (bei kk umsaetzen) }); } } } } */ function tryFormatDate(datestring, oldPattern, newPattern) { var formatedDate = ''; try { formatedDate = jQuery.datepicker.formatDate(newPattern, jQuery.datepicker.parseDate(oldPattern, datestring)); } catch (err) { //console.log('Error tryFormatDate: oldPattern:' + oldPattern + ' newPattern:' + ' datestring:' +datestring); } // console.log('from: ' + datestring + ' --> ' + formatedDate); return formatedDate; } function initTooltips() { //TOOLTIPPS jQuery(document).on('click', function (e) { hideTooltipp(jQuery('.toolTippLink')); }); jQuery(".toolTippLink").each(function () { jQuery(this).click(function (e) { //e.stopPropagation(); jQuery(this).trigger('touchstart'); }); }); jQuery(".toolTippLink").on('touchstart click', function (e) { e.preventDefault(); e.stopPropagation(); showTooltipp(this); }); jQuery(".tooltipp, .toolTippInner:before").on('click touchstart', function (e) { e.stopPropagation(); e.preventDefault(); hideTooltipp(jQuery(this).closest('.toolTippLink')); }); jQuery(".toolTippLink").hover( function () { showTooltippHover(this); }, function () { hideTooltippHover(this); } ); //END: TOOLTIPPS } function showTooltippHover(tt) { if (is_large_up() || !is_touch_device()) { showTooltipp(tt); } } function hideTooltippHover(tt) { if (is_large_up() || !is_touch_device()) { hideTooltipp(tt); } } function showTooltipp(tt) { jQuery(tt).addClass('hover'); if (!jQuery(tooltipp).hasClass('large')) { var tooltipp = jQuery(tt).find('.tooltipp'); // wenn Inhalt zu hoch wird, mach den tooltip breiter var contentHeight = jQuery(tt).find('.toolTippInner').outerHeight(); if (contentHeight > 130) { jQuery(tooltipp).addClass('large'); } } if (is_large_up() && jQuery(tt).parents('.tooltipp_bottom').hasClass('force_tooltipp_left')) { jQuery(tooltipp).addClass('tooltipp_left'); } else { // richte den tooltip aus, wenn er nach rechts aus dem Sichtbaren Bild ragt var tooltippWidth = jQuery(tooltipp).outerWidth(); var posLeft = jQuery(tt).offset().left + 10; // + abstand zum container var pageWidth = jQuery('html').outerWidth(); //console.log('tooltippWidth:' + tooltippWidth +'\nposLeft: ' + posLeft + '\npageWidth:' + pageWidth); if (tooltippWidth + posLeft > pageWidth) { if (is_small_and_down()) { jQuery(tooltipp).css('left', (pageWidth - posLeft - tooltippWidth) + 'px'); } else { jQuery(tooltipp).addClass('tooltipp_left'); } } else { if (is_small_and_down()) { } else { jQuery(tooltipp).removeClass('tooltipp_left'); } } } if (is_small_and_down()) { // richte den Tooltip aus, wenn er nach oben aus dem Sichtbaren bereich rutscht var scrolltop = jQuery(window).scrollTop(); var ttOffsetTop = jQuery(tt).offset().top; var heightBanner = jQuery('.grid4.band').outerHeight(); var ttHeight = jQuery(tooltipp).outerHeight(); //console.log('scrolltop:' + scrolltop +'\nttOffsetTop: ' + ttOffsetTop + '\nheightBanner:' + heightBanner + '\nttHeight:' + ttHeight); jQuery(tooltipp).css('top', '-' + ((Math.min(ttHeight, (ttOffsetTop - heightBanner - scrolltop))) - 10) + 'px'); jQuery(document).on('touchstart', closeToolTipOnTouchStart); } } // bevor dieser Code optimiert wird: siehe Jira DKBIB-4184 function closeToolTipOnTouchStart() { hideTooltipp(jQuery('.toolTippLink')); jQuery(document).off('touchstart', closeToolTipOnTouchStart); } function hideTooltipp(tt) { jQuery(tt).removeClass("hover"); jQuery(tt).find('.tooltipp').css('left', '').css('top', ''); } /** * Wenn es ein applicationNav Element gibt: * Wird der Text des aktuellen Reiters mit der aktuellen headline (H1) zu einer neuen Smartphone-Headline zusammengebaut. */ function handleHeadlineForApplicationNav() { var appNavRoot = jQuery('.applicationNav'); if (jQuery(appNavRoot).length > 0) { var h1 = jQuery('h1'); var h1_small = jQuery('h1.show-for-small-down'); if (jQuery(appNavRoot).closest('.dontCopyAppnavToH1').length == 0) { if (is_small_and_down() && jQuery(h1).length > 0 && jQuery(h1_small).length == 0) { // --> (es gibt applicationNav element) && (es gibt ein H1) && (es gibt noch keine Smartphone-Headline) var appNavRootHeadline = jQuery(jQuery(appNavRoot).get(0)).find('li.selected .text'); if (jQuery(appNavRootHeadline).length == 0) { // keines selektiert --> dann ist es keine klassische nav (siehe onlinecachback) jQuery(appNavRoot).addClass('noneSelected') } if (jQuery(appNavRootHeadline).length > 0) { var h1Clone = jQuery(h1).get(0).cloneNode(true); jQuery(h1Clone).find('a').each(function () { // entferne Druckicon wenn vorhanden jQuery(this).remove(); }); jQuery(h1).addClass('hide-for-small-down'); jQuery(h1Clone).addClass('show-for-small-down'); var h1Headline = jQuery.trim(jQuery(h1Clone).html()); var h1SubHeadline = jQuery.trim(jQuery(appNavRootHeadline).html()); if (h1Headline == h1SubHeadline) { jQuery(h1Clone).html(h1Headline); } else { jQuery(h1Clone).html(h1Headline + ": " + h1SubHeadline); } jQuery(h1).after(jQuery(h1Clone)); } } } var amountclass = 'amount_child_' + jQuery(jQuery(appNavRoot).get(0)).find('li').length; if (!jQuery(appNavRoot).hasClass(amountclass)) { jQuery(appNavRoot).addClass(amountclass); } } } function nullOrEmpty(obj) { return obj == null || obj == undefined || jQuery.trim(obj).length == 0; } function is_android() { return jQuery('html').hasClass('is_android'); } function is_app() { return jQuery('html').hasClass('portal_app') || jQuery('html').hasClass('map_app'); } function is_ipad() { return jQuery('html').hasClass('is_pad'); } function div2(class1, class2) { var d1 = div(class1); var d2 = div(class2); d1.appendChild(d2); return d1; } function div(className) { var div = document.createElement('div'); if (className) { div.setAttribute("class", className) } return div; } function enhanceTablePager() { jQuery('.pagingModule').each(function () { if (jQuery(this).find('a.butPrev0').length > 0) { jQuery(this).addClass('hasArrowLeft'); } if (jQuery(this).find('a.butNext0').length > 0) { jQuery(this).addClass('hasArrowRight'); } }); } /* CSS Browser Selector v0.4.0 (Nov 02, 2010) Rafael Lima (http://rafael.adm.br) http://rafael.adm.br/css_browser_selector License: http://creativecommons.org/licenses/by/2.5/ Contributors: http://rafael.adm.br/css_browser_selector#contributors */ function css_browser_selector(u) { var ua = u.toLowerCase(), is = function (t) { return ua.indexOf(t) > -1 }, g = 'gecko', w = 'webkit', s = 'safari', o = 'opera', m = 'mobile', h = document.documentElement, b = [(!(/opera|webtv/i.test(ua)) && /msie\s(\d)/.test(ua)) ? ('ie ie' + RegExp.$1) : is('firefox/2') ? g + ' ff2' : is('firefox/3.5') ? g + ' ff3 ff3_5' : is('firefox/3.6') ? g + ' ff3 ff3_6' : is('firefox/3') ? g + ' ff3' : is('gecko/') ? g : is('opera') ? o + (/version\/(\d+)/.test(ua) ? ' ' + o + RegExp.$1 : (/opera(\s|\/)(\d+)/.test(ua) ? ' ' + o + RegExp.$2 : '')) : is('konqueror') ? 'konqueror' : is('blackberry') ? m + ' blackberry' : is('android') ? m + ' android' : is('chrome') ? w + ' chrome' : is('iron') ? w + ' iron' : is('applewebkit/') ? w + ' ' + s + (/version\/(\d+)/.test(ua) ? ' ' + s + RegExp.$1 : '') : is('mozilla/') ? g : '', is('j2me') ? m + ' j2me' : is('iphone') ? m + ' iphone' : is('ipod') ? m + ' ipod' : is('ipad') ? m + ' ipad' : is('mac') ? 'mac' : is('darwin') ? 'mac' : is('webtv') ? 'webtv' : is('win') ? 'win' + (is('windows nt 6.0') ? ' vista' : '') : is('freebsd') ? 'freebsd' : (is('x11') || is('linux')) ? 'linux' : '', 'js']; var $html = jQuery('html'); for (var i = 0; i < b.length; i++) { if ('js' == b[i] || b[i].indexOf('ie') == 0) { // js / ie9 / ie8 soll nicht entfernt werden if (!$html.hasClass(b[i])) { $html.addClass(b[i]); } } else { if (is_large_up()) { $html.addClass(b[i]); } else { $html.removeClass(b[i]); } } } if (navigator.appName == 'Netscape' && u.match(/Trident.*rv\:11\./)) { $html.addClass('msie'); } }; function addFixForOpenKeybordOnMobile() { if (is_medium_only() || is_small_and_down() || is_ipad() || is_app()) { jQuery(document) .on('focus', 'input, textarea', function () { jQuery('html').addClass('pint-disable'); }) //4307 .on('blur', 'input, textarea', function () { jQuery('html').removeClass('pint-disable'); }); } } /** * Notwendig für Fehler bzw. Infomarkierung. * Erhält ein Input-Element den focus wird die Klasse "labelfocus" gesetzt. Verliert das Element den focus wird die Klasse wieder entfernt. * Die Positionierung eines evtl. vorhandenen Fehler- oder Infotextes erfolgt bei "inlineLabels" relativ zum Eingabefeld. */ function labelFocus() { // onClick workaround for MAC browser that didn't focus non text input elements jQuery("form :input").click(function() { this.focus(); }).focus(function(){ var $labels = jQuery( '[for|="'+encodeURI(this.id)+'"]'); $labels.addClass("labelfocus"); jQuery(this).parent().andSelf().siblings('.label').addClass('labelfocus'); if (is_medium_up()) { // für inline labels die Ausrichtung der Fehler-/Infomarkierung setzen if ($labels.length > 0 && jQuery($labels[0]).hasClass('inlineLabel')) { var labelRect = $labels[0].getBoundingClientRect(); var inputRect = this.getBoundingClientRect(); // console.log('input: ' + inputRect.top + ', label: ' + labelRect.top); $labels.children('.error, .sytemInfo').css({ "left": inputRect.left - labelRect.left }); } } }).blur(function() { jQuery('[for|="'+encodeURI(this.id)+'"]').removeClass("labelfocus"); jQuery(this).parent().andSelf().siblings('.label').removeClass('labelfocus'); }); } jQuery(document).ready(labelFocus); jQuery(document).on('abx_partial_load', labelFocus); // berechne die hoehe des error/info inhaltes und passe css.hoehe, css.top und evtl. css.left entsprechend an // notwendig bei mehrzeiligen errors/infos sowie inlinelabels // Achtung Abhängigkeit zu fixPushTanHintMessage (muss vorher durch sein) function handleError() { try { jQuery('.abx-captcha-input.abx-captcha-error').find('label:not(.error)').addClass('error'); jQuery('label.error span.error, label span.sytemInfo').each(function () { var $span = jQuery(this); if (is_medium_up()) { // nur wenn nicht schon initialisiert if (!$span.attr('old_hight')) { // stelle einen Zustand her, sodass die height ermittelt werden kann var $parentTabmodul = $span.closest('.tabModul.js_version'); $parentTabmodul.removeClass('js_version'); //showTab $span.attr('old_hight', $span.css('height')); var $label = $span.closest('label'); var hadClassPersistentError = false; if ($label.hasClass('persistentError')) { hadClassPersistentError = true; $label.removeClass('persistentError') } var oldLabelStyleDisplay = $label.get(0).style.display; $label.get(0).style.display = 'inline-block'; var isInlineLabel = $label.hasClass('inlineLabel'); var isRadioLabel = $label.hasClass('radio'); var labelHeight = $label.height(); var noTextlabel = false; if (isRadioLabel || isInlineLabel) { labelHeight = Math.min($label.height(), $label.css('line-height').replace('px', '')); labelHeight = (labelHeight == 0 ? 21 : labelHeight); // wenn das Label keinen Text enthält ... } var $parent = $span.closest('label.error'); $parent.addClass('labelfocus'); $span.css('width', $span.width()); $span.css('position', 'relative'); // ermittle die hoehe var calcHeight = $span.height(); // setze den urspruenglichen zustand her $parentTabmodul.addClass('js_version'); //showTab $span.css('width', ''); $span.css('position', ''); $parent.removeClass('labelfocus'); if (oldLabelStyleDisplay == undefined || oldLabelStyleDisplay.trim().length == 0){ oldLabelStyleDisplay = ''; } $label.get(0).style.display = oldLabelStyleDisplay; //console.log('calcHeight:' + calcHeight + ' labelHeight:' + labelHeight + ' isInlineLabel:' + isInlineLabel + ' newTop:' + ( - calcHeight - (isInlineLabel ? 0 : 25) + labelHeight)); // setze die neue hoehe und die neu ausrichtung $span.css('height', calcHeight + 'px'); var newTop = -calcHeight - 25 + labelHeight; if (isInlineLabel) { newTop = -$span.outerHeight() - labelHeight; if (noTextlabel) { newTop = newTop - 5; } // console.log('calcHeight:' + jQuery(this).outerHeight() + ' $span.outerHeight():' + $span.outerHeight() + ' labelHeight:' + labelHeight + ' newTop:' + newTop); var inputId = $label.attr('for'); if (inputId && inputId.indexOf(";") > 0) { // wenn das Label die "Syntax" aspect="erster;zweiter" verwendet, wird eine entsprechende Id mit Semikolon generiert // hierbei können derzeit ohnehin keine unterschiedlichen Infos pro Eingabefeld verwendet werden, daher wird das erste genommen inputId = inputId.substr(0, inputId.indexOf(";")); } var inputOfLabel = jQuery.find('#' + inputId); if (inputOfLabel && inputOfLabel.length > 0) { var labelRect = $label[0].getBoundingClientRect(); var inputRect = inputOfLabel[0].getBoundingClientRect(); $span.css('left', inputRect.left - labelRect.left); $span.attr('old_hight', ''); // Flag ob bei Veränderung der Breite nochmal geprüft werden soll, muss explizit zurückgesetzt werden, da sich die Breite verändert hat } } else if (isRadioLabel) { newTop = -calcHeight - labelHeight - 4; } $span.css('top', newTop + 'px'); if (hadClassPersistentError) { $label.addClass('persistentError') } } } else if ($span.attr('old_hight')) { // entferne die oben gesetzten CSS Attribute $span.css('height', ''); $span.css('top', ''); $span.attr('old_hight', ''); } }); if (jQuery('.mergeErrors_onSmall') && is_small_and_down() && !jQuery('#mergedErrorsDiv').length > 0) { var firstError = jQuery('.mergeErrors_onSmall').find('.formBox label:first span.error').text(); if (firstError) { var errorDiv = document.createElement('div'); errorDiv.setAttribute('class', 'clearfix module text errorMessage'); errorDiv.setAttribute('id', 'mergedErrorsDiv'); var errorUl = document.createElement('ul'); errorDiv.appendChild(errorUl); var errorLi = document.createElement('li'); errorLi.innerHTML = firstError.trim(); errorUl.appendChild(errorLi); var errorSpan = document.createElement('span'); errorSpan.setAttribute('class', 'icons cross'); errorLi.appendChild(errorSpan); jQuery('.mergeErrors_onSmall').prepend(errorDiv); } } } catch (err) { // console.log('Error handleError: ' + err ); } } function initTabmodulJsVersion() { jQuery('.tabModul.js_version, .stageModule.js_version').each(function () { var current = jQuery(this).find('.tabs-list li.current a'); if (jQuery(current).length == 0) { current = jQuery(this).find('.tabs-list li:first-child a'); if (jQuery(current).length > 0) { jQuery(current).parents('li').addClass('current'); } } if (jQuery(current).length == 0) { // im shop gibt es module ohne header jQuery(this).find('.tabbody:first').addClass('current'); } handleTabClicked(current); jQuery(this).find('.tabs-list a').each(function () { jQuery(this).addClass('noSpinner'); jQuery(this).bind("click", function (e) { e.preventDefault(); e.stopPropagation(); handleTabClicked(jQuery(this)); }); }); }); } function handleTabClicked($clickedEle) { if ($clickedEle != undefined) { var attrHref = $clickedEle.attr('href'); var $tabmodule = $clickedEle.parents('.tabModul, .stageModule'); $tabmodule.find('.tabs-list li.current').removeClass('current'); $clickedEle.parents('li').addClass('current'); $tabmodule.find('.tabbody').each(function () { jQuery(this).removeClass('current'); if (jQuery(this).hasClass(attrHref)) { jQuery(this).addClass('current'); } }); } } /* fix für DKBIB-4373*/ function fixPushTanHintMessage() { var pushtanHint = jQuery('.pushtTanHint'); var pushtanHint_target = jQuery('#pushtTanHint_target'); if (jQuery(pushtanHint).length > 0 && jQuery(pushtanHint_target).length > 0) { jQuery(pushtanHint_target).replaceWith(jQuery(pushtanHint).get(0).outerHTML); jQuery(pushtanHint).remove(); } } function hasLocalStorage() { return typeof localStorage != "undefined"; } /** * Wird aus dem CMS aufgerufen (/Footer/OuterFooter) */ function forceViewportDesktop(_true) { if (_true) { console.log("forcing desktop view"); CLX.writeCookie("clxDesktopView", "true", null, "/", null, true, "Lax"); document.location.reload(true); } else { console.log("using responsive view"); CLX.writeCookie("clxDesktopView", "false", null, "/", null, true, "Lax"); document.location.reload(true); } return false; } function openMobileMenu() { if (is_medium_only() || is_small_and_down()) { jQuery('#mobile_menu').data('mmenu').open(); } } function closeMobileMenu() { var mmenu = jQuery('#mobile_menu').data('mmenu'); if (mmenu != undefined) { mmenu.close(); } } function handleMultilineSelectCheckbox() { jQuery('.multiline-select span.checkbox > span.aspect-error > input').each(function () { // wenn multiline-select einen Validierungsfehler hat greifft das css nicht // aufgrund der neuen Struktur muss mit Javascript nachgeholfen werden updateCheckboxStateToParentSpan(jQuery(this)); jQuery(this).on('change', function () { updateCheckboxStateToParentSpan(jQuery(this)); }); }); } function updateCheckboxStateToParentSpan(input) { var $input = jQuery(input); if ($input.parent().hasClass('aspect-error')) { if ($input.prop('checked') == true) { $input.parent().addClass('is_checked'); } else { $input.parent().removeClass('is_checked'); } } } function chiptanResponsive() { var $flickerTarget = jQuery('#flicketcode_target'); if ($flickerTarget.length > 0) { handleChipTanWhenLoaded($flickerTarget); } } var chipTanWhenLoadedIndex = 0; function handleChipTanWhenLoaded($flickerTarget) { if (chipTanWhenLoadedIndex < 100) { chipTanWhenLoadedIndex++; if ($flickerTarget.find('#rsct_opptan_hint').length > 0) { // found if (jQuery(window).width() - jQuery(document).width() < -10) { //10px messungenauigkeit RsctOpttan.opttanObject.rotate('opttan_mr'); //DKBIB-7219 } $flickerTarget.find('#rsct_opptan_hint').addClass('use_new_row_on_small'); handleNewRowOnSmall() } else { // not found --> whait some mili secondes setTimeout(handleChipTanWhenLoaded, 100, $flickerTarget); } } } function handleWebtreckId() { /*DKBIB-6313*/ jQuery('a[onclick*="ENV_COUNT"]').each(function (index, button) { jQuery(button).attr('onclick', jQuery(button).attr("onclick").replace('{ENV_COUNT}', index + 1)); }); } ; jQuery(document).ready(function () { initTANInput(); initInputFileds(); }); //Initialisiert InputField maxLength workaround f�r Android-Ger�te function initInputFileds() { if (jQuery('html').hasClass('is_android')) { jQuery('input[class*="text"][maxlength]').each(function () { jQuery(this).bind('keyup paste', function (evt) { var max = this.getAttribute("maxlength"); if (this.value.length > max) { this.value = this.value.substr(0, max); } }); }); } } //Initialisiert Leerzeichenhandling f�r alle TAN-Input Felder function initTANInput() { //Entfernt Leerzeichen in der PIN bei der Eingabe oder beim Einf�gen jQuery('#tanInputSelector').bind('input', function (e) { cleanWhitespaces(e); }); } //Entfernt Leerzeichen in der TAN bei der Eingabe oder beim Einf�gen function cleanWhitespaces(evt) { var tanInputElement = evt.target; //Nach dem Editieren wird Leeerzeichen ersetzt, Timeout ist notwendig um zu gew�hrleisten dass input Feld nach dem reinkopieren bereits bef�llt ist. window.setTimeout(replaceSpace, 100, tanInputElement); } //Ersetzt Zeichen im Eingabefeld mit Hilfe der Definition in der Callbackmethode function replaceSpecialChar(input, callback) { var oldValue = input.value; var oldPosition = input.selectionStart; var newValue = callback(oldValue); if (newValue.length - oldValue.length != 0) { input.value = newValue; if (is_android()) { // hack vor DKBIB-7856 unfocus(input); jQuery(input).focus(); } var newPosition = newValue.length - (oldValue.length - oldPosition); // von hinten ermitteln, weil sich der text vor dem cursor veraendert hat input.setSelectionRange(newPosition, newPosition); } } //Ersetzt alle Umlaute function replaceUmlaute(input) { replaceSpecialChar(input, function (oldValue) { return oldValue.replace(/\u00c4/g, 'Ae').replace(/\u00e4/g, 'ae').replace(/\u00d6/g, 'Oe').replace(/\u00f6/g, 'oe').replace(/\u00dc/g, 'Ue').replace(/\u00fc/g, 'ue').replace(/\u00df/g, 'ss'); }); } //ersetzt Leerzeichen function replaceSpace(input) { replaceSpecialChar(input, function (oldValue) { return oldValue.replace(/\040/g, ''); }); } //Workaround f�r den Android Bug (siehe DKBIB-7856) function unfocus(ele) { var tempInputId = 'tempInputForUnfocus'; var tempInput = document.createElement('input'); tempInput.id = tempInputId; jQuery(ele).after(jQuery(tempInput)); jQuery('#' + tempInputId).focus(); jQuery('#' + tempInputId).remove(); } ; jQuery(document).ready(function() { initSpinner(); prepareSpinnerOnce(); }); var ajaxLoadingClass = 'ajax_loading'; function initSpinner() { jQuery('form').submit(function (event) { if (event != undefined && event.delegateTarget != undefined && jQuery(event.delegateTarget).hasClass('noSpinner')) { return; //--> no Spinner } if (jQuery(this).prop('target').length == 0) { // falls target vorhanden, dann oeffnet sich eh ein neues fenster showSpinner(); } }); jQuery('a:not(.noSpinner):not(.pager-navigator-link):not(.sortColumn):not(.evt-download):not(.modal)').each(function() { var attrHref = jQuery(this).attr('href'); // nicht durch .prop() austauschen!!!! if (!nullOrEmpty(jQuery(this).prop('href')) && (nullOrEmpty(attrHref) || (!attrHref.toUpperCase().indexOf('JAVA') == 0 && !attrHref.toUpperCase().indexOf('MAILTO') == 0 && !attrHref.toUpperCase().indexOf('#') == 0)) && (nullOrEmpty(jQuery(this).prop('target')) || jQuery(this).prop('target').length == 0) && (nullOrEmpty(jQuery(this).prop('onclick')) || jQuery(this).prop('onclick').length == 0) && !jQuery(this).parent().hasClass('accordionLink')) { jQuery(this).bind('click',function(e) { if (e != null && e != undefined) { const ctrlOrMetaKeyPressed = e.ctrlKey || e.metaKey; if (!jQuery(this).hasClass('noSpinner') && e.which != 2 && (!ctrlOrMetaKeyPressed)) { // e.which == 2 --> mausrad showSpinner(); } } }); } }); } function prepareSpinnerOnce() { if (!jQuery('html').hasClass('noSpinner') && jQuery('.' + ajaxLoadingClass).length < 1) { var root = div(ajaxLoadingClass); root.setAttribute("style", "display:none"); var spinner_container = div('spinner_container'); var spinner = div('spinner'); if (is_android()) { var spinner_inner = div('spinner_inner'); var spinner_layer = div('spinner_layer'); spinner_layer.appendChild(div2('circle-clipper left','circle')); spinner_layer.appendChild(div2('gap-patch left','circle')); spinner_layer.appendChild(div2('circle-clipper right','circle')); spinner_inner.appendChild(spinner_layer); spinner.appendChild(spinner_inner); } else { for (var i = 0; i < 13; i++) { spinner.appendChild(div()); } } spinner_container.appendChild(spinner); root.appendChild(div('ui-widget-overlay')); root.appendChild(spinner_container); jQuery('body').prepend(root); // handle miniSpinner jQuery('.miniSpinnerBlue, .miniSpinnerWhite').each(function() { var $miniSpinner = jQuery(this); if (!$miniSpinner.hasClass('initialized')) { for (var i = 0; i < 13; i++) { $miniSpinner.append(div()); } $miniSpinner.addClass('initialized'); } }); } } function showSpinner() { var $ajaxLoading = jQuery('.' + ajaxLoadingClass); if ($ajaxLoading.length > 0) { $ajaxLoading.show(); jQuery('#mm-blocker').hide(); window.setTimeout(function(){ jQuery('.' + ajaxLoadingClass + ' .spinner_container').on('click touchstart', function (){ // hideable after 10 seconds hideSpinner(); }); }, 5 * 1000); } return true; } function hideSpinner() { jQuery('.' + ajaxLoadingClass).hide(); }; /* * (c) Crealogix (Deutschland) AG, Projekt DKB. */ jQuery(document).ready(function () { if (jQuery('html').hasClass('headless_mode')) { jQuery('a[target="_blank"]').prop('target','_self'); }}); function reloadSSOFrame(baseURL, path_to_process) { jQuery('#ib_headless_frame').attr('src', baseURL + path_to_process); } function logoutSSOFrame(baseURL) { jQuery('#ib_headless_frame').attr('src', baseURL + '/DkbTransactionBanking/banner.xhtml?$event=logout'); } ; /* * (c) Crealogix (Deutschland) AG, Projekt DKB. */ /** * Kümmert sich um die "Client-seitige Session". * * Ziel des Client-seitigen Sessionhandlings ist: * - dass die verbleibende Sessionzeit angezeigt wird * - dass ein Logout Auswirkung auf weitere Browser-Tabs hat * - dass Benutzeraktivität die Session automatisch verlängert * * Der Code fragt in regelmäßigen Abständen nach der verbleibenden Restdauer der Session. * Sofern der User aktiv ist, wird hierbei auch automatisch die User-Session verlängert (unabhängig von der technischen AppServer-Session, die ja bei jeder Serverinteraktion verlängert wird). * Sofern die Session abgelaufen ist, wird der User auf die Logout-Seite weitergeleitet. * * @namespace Abaxx.dkb_session_handler * @requires jQuery */ Abaxx.define('dkb_session_handler', function () { 'use strict'; var settings = {}; var sessionEndTimeMs; var sessionPollingIntervalId = null; // Hilfsvariable um doppelte Requests zu vermeiden var sessionUpdateRunning = false; // Flag ob die Usersession verlängert werden soll var renewSession = false; // Hilfsvariable um doppelte Initialisierung zu vermeiden var initCompleted = false; // Zeitstempel einer User Aktivität var currentUserActivityTimestamp = null; // Zeitstempel der vorherigen User Aktivität var previousUserActivityTimestamp = null; /** * Initialisiert den Session Countdown * @param options */ function init(options) { if (initCompleted) { return; } var defaults = { uiCountdownId: null, timeoutTarget: null, sessionUrl: null, updateIntervalInMs: 1000 * 60, initialSessionDurationInMs: 5 * 60 * 1000 }; settings = jQuery.extend({}, defaults, options); if (!settings.sessionUrl) { console.log('Error in dkb_session_handler config'); return; } sessionEndTimeMs = new Date().getTime() + settings.initialSessionDurationInMs; setupActivityListeners(); setupUiUpdateInterval(); setupSessionEndTimePollingInterval(); initCompleted = true; } /** * Signalisiert, dass der User noch aktiv ist (bspw. geklickt, gescrollt, etc.) */ function trackUserActivity() { if (!previousUserActivityTimestamp) { previousUserActivityTimestamp = new Date(); } currentUserActivityTimestamp = new Date(); } /** * Liefert true wenn die User Session verlängert werden soll. * Wenn die letzte Useraktivität länger als die Sessiondauer zurückliegt, dann Session nicht mehr verlängern. * * @return {boolean} true wenn die User Session verlängert werden soll */ function renewSessionDueToUserActivity() { if (!previousUserActivityTimestamp || !currentUserActivityTimestamp) { return false; } var elapsedMillis = currentUserActivityTimestamp.getTime() - previousUserActivityTimestamp.getTime(); if (elapsedMillis < settings.initialSessionDurationInMs) { previousUserActivityTimestamp = currentUserActivityTimestamp; return true; } return false; } /** * Listener für alle relevanten Events registrieren */ function setupActivityListeners() { document.addEventListener('keyup', trackUserActivity); document.addEventListener('wheel', trackUserActivity); document.addEventListener('scroll', trackUserActivity, true); document.addEventListener('click', trackUserActivity); document.addEventListener('touchend', trackUserActivity); document.addEventListener('mousemove', trackUserActivity); document.addEventListener('mouseup', trackUserActivity); document.addEventListener('visibilitychange', function() { if (document.visibilityState === 'visible') { trackUserActivity(); } }); // eigenes Event, das von anderen Codestellen erzeugt werden muss, um die Session aufgrund von Nutzeraktivität zu verlängern document.addEventListener('$dkb_user_active', trackUserActivity); } /** * Das UI alle 500 Millisekunden hinsichtlich der Sessionendzeit aktualisieren. */ function setupUiUpdateInterval() { if (settings.uiCountdownId) { window.setInterval(function () { updateSessionCountdown(); }, 500); } } /** * Die Sessionendzeit alle paar Sekunden vom Server abfragen. */ function setupSessionEndTimePollingInterval() { if (!sessionPollingIntervalId) { sessionPollingIntervalId = window.setInterval(function () { updateSessionStateFromServer(); }, settings.updateIntervalInMs); } } /** * Stoppt das Polling nach der Sessionendzeit */ function stopSessionEndTimePollingInterval() { if (sessionPollingIntervalId) { window.clearInterval(sessionPollingIntervalId); sessionPollingIntervalId = null; } } /** * Falls die verbleibende Sessionendzeit kürzer als das Polling-Delay ist, müssen wir in der angegebenen Zeit nochmal prüfen. * Andernfalls kann das Polling weiterlaufen. */ function updateSessionPollingInterval(remainingSessionTimeInMs) { if (remainingSessionTimeInMs < settings.updateIntervalInMs) { stopSessionEndTimePollingInterval(); window.setTimeout(function () { updateSessionStateFromServer(); }, remainingSessionTimeInMs); } else { setupSessionEndTimePollingInterval(); } } /** * @returns {number} die Restzeit der Session in Millisekunden */ function getRemainingSessionDurationInMs() { return sessionEndTimeMs - new Date().getTime(); } /** * Aktualisert die Session. * <p>Wird bspw. verwendet bei Klick auf Refresh-Icon in der Session-Info-Bar.</p> */ function callSessionRefresh() { renewSession = true; updateSessionStateFromServer(); } /** * Ruft die Session-Info Ressource ab, um die Session-Endzeit zu erhalten. * Ist die Session abgelaufen oder antwortet der Server mit einem Fehler, wird direkt zur Timeout-Seite navigiert. */ function updateSessionStateFromServer() { if (sessionUpdateRunning) { return; } var params = (renewSession || renewSessionDueToUserActivity()) ? {} : {'$ignore.request': true}; sessionUpdateRunning = true; jQuery.ajax(settings.sessionUrl, { global: false, dataType: 'json', data: params, timeout: 6000, success: function (result) { if (result[0].publicSession) { // der User hat sich vermutlich in einem anderen Tab abgemeldet sessionEndTimeMs = -1; navigateToTimeoutTarget(); } else { var remainingSessionInMs = result[0].remainingSessionDurationMs; if (remainingSessionInMs && remainingSessionInMs > 0) { // neue Sessionendzeit berechnen - ist etwas ungenau aufgrund der Dauer des Requests, aber damit leben wir sessionEndTimeMs = new Date().getTime() + remainingSessionInMs; updateSessionPollingInterval(remainingSessionInMs); } else { // die verbleibende Session-Zeit ist bereits unter 0 oder nicht vorhanden navigateToTimeoutTarget(); } } sessionUpdateRunning = false; renewSession = false; currentUserActivityTimestamp = null; }, error: function (result, status) { // Fehlerfälle werden ignoriert, damit der Nutzer nicht fälschlicherweise weitergeleitet wird sessionUpdateRunning = false; renewSession = false; currentUserActivityTimestamp = null; } }); } /** * Aktualisiert den Session Countdown. * Wenn der Countdown einen bestimmten Grenzwert unterschreitet, wird er hervorgehoben und eingeblendet, falls noch nicht sichtbar. */ function updateSessionCountdown() { var remainingDurationInMs = getRemainingSessionDurationInMs(); if (remainingDurationInMs > 0) { var countDownElement = document.getElementById(settings.uiCountdownId); if (countDownElement) { countDownElement.innerHTML = Abaxx.util.formatTime(remainingDurationInMs); // hervorheben wenn nur noch 3 Minuten verbleiben bzw. Hervorhebung entfernen wenn mehr als 3 Minuten var $countdownElement = jQuery(countDownElement); if (remainingDurationInMs > (3 * 60 * 1000)) { $countdownElement.removeClass('dkbred'); } else { $countdownElement.addClass('dkbred'); displayHiddenSessionInfo(); } } } } /** * Navigiert zur Timeout-Seite */ function navigateToTimeoutTarget() { if (settings.timeoutTarget) { window.location = settings.timeoutTarget; } } /** * Sorgt dafür, dass die Session-Info angezeigt wird. * * Initial ist diese ausgeblendet, da die letzte Anmeldung angezeigt wird. */ function displayHiddenSessionInfo() { var $sessionInfoElement = jQuery('#session-info'); if ($sessionInfoElement.length) { $sessionInfoElement.removeClass('hidden'); } var $lastLoginContainerElement = jQuery('#lastLoginContainer'); if ($lastLoginContainerElement.length) { $lastLoginContainerElement.addClass('hidden'); } } return { init: init, refreshSession: callSessionRefresh }; }); jQuery(document).ready(function() { handleFooterAccordion(); }); jQuery(window).resize(function () { handleFooterAccordion(); }); /** * JavaScript zu CMS Modul FooterContainer. Wird global eingebunden, da auf fast allen Seiten ein Footer zu sehen ist. */ function handleFooterAccordion(){ var start_width = 600; // diese zeile nicht entfernen, wird fuer forceDesktopView benoetigt if (is_medium_and_down()) { var $footer = jQuery(".richfooter.mobileAccordion"); if ($footer.length > 0) { if (!$footer.hasClass('initialized')) { $footer.addClass('initialized'); $footer.find('.footer_col').each(function () { var opener = jQuery(this).find("> .h4"); var content = opener.next(); var container = jQuery(this).closest(".mobileAccordion"); //Prepare opener opener.append("<span class='trigger_icon'></span>"); opener.bind("click", function () { if (window.innerWidth <= start_width) { if (opener.hasClass('open')) { content.stop(false, true).slideUp(); opener.removeClass('open'); } else { container.find('.open').removeClass('open').next().stop(false, true).slideUp(); content.stop(false, true).slideDown(); opener.addClass('open'); } } }); }); } if(window.innerWidth <= start_width ){ $footer.find(".footer_col > ul").slideUp(0); $footer.find(".footer_col > .h4.open").removeClass('open'); $footer.find(".footer_col > .h4.initopen").addClass("open"); $footer.find(".footer_col > .h4.initopen + ul").slideDown(0); //jQuery(".richfooter.mobileAccordion .footer_col > h4.initopen").removeClass("initopen"); } else { $footer.find(".footer_col > ul").slideDown(0); } } } //fixing the footer lists after resizing then closing the window if (window.innerWidth > start_width) { jQuery('.footer_col ul').css({"display": "block"}); } }; function addMboUnReadCounter(unreadCounterMap) { if (typeof unreadCounterMap === 'undefined' || jQuery.isEmptyObject(unreadCounterMap)) { return; // do nothing } jQuery('li.label_Mein_Banking li.label_Postfach').each(function () { var $nodePostfach = jQuery(this); var sum = 0; for (var key in unreadCounterMap) { sum = sum + unreadCounterMap[key]; $nodePostfach.find('li.label_' + key).each(function () { var $spanUnreadcounter = jQuery(this).find('span.unreadCounter'); if ($spanUnreadcounter.length == 0) { $spanUnreadcounter = jQuery('<span class="unreadCounter"></span>'); jQuery(this).append($spanUnreadcounter); } if (unreadCounterMap[key] > 99) { $spanUnreadcounter.addClass('has99').html('99+'); } else if (!unreadCounterMap[key] > 0) { $spanUnreadcounter.remove(); } else { $spanUnreadcounter.html(unreadCounterMap[key]); } }); } var counterValueMobile = sum == 0 ? '' : (sum > 99 ? '99+' : sum); var $sumSpanUnreadcounter = $nodePostfach.children('span.unreadCounter'); var $sumSpanUnreadcounterMobile = $nodePostfach.children('span.unreadCounter_mobile'); if (sum > 0 && $sumSpanUnreadcounter.length == 0) { $sumSpanUnreadcounter = jQuery('<span class="unreadCounter"></span>'); $sumSpanUnreadcounterMobile = jQuery('<span class="unreadCounter_mobile"></span>'); $nodePostfach.find('a').first().before($sumSpanUnreadcounter).before($sumSpanUnreadcounterMobile); } if (!sum > 0 && $sumSpanUnreadcounterMobile.length != 0) { // keine ungelesenen nachrichten mehr $sumSpanUnreadcounterMobile.remove(); } else { $sumSpanUnreadcounter.html(sum); if (sum > 99) { $sumSpanUnreadcounterMobile.addClass('has99').html('99'); } else { $sumSpanUnreadcounterMobile.html(counterValueMobile); } } jQuery('.mobile_menu_btn .unread_count').each(function () { if (sum > 99) { jQuery(this).removeClass('no_number').addClass('has99').html('99'); } else if (sum > 0) { jQuery(this).removeClass('no_number').html(sum) } else { jQuery(this).addClass('no_number'); } }); }); }; jQuery(document).ready(function() { prepareMobileMenuIfNeeded(); jQuery("#desktop_menu li > a").bind('click', function (e) {wt.sendinfo({linkId:"desktopmenu_"+jQuery(this).attr("href"),sendOnUnload:1});}); jQuery(window).resize(function () { prepareMobileMenuIfNeeded(); }); }); var scrollPosBeforeMenu = 0; // initialisieren des mobilemenu function prepareMobileMenuIfNeeded() { if (is_medium_only() || is_small_and_down()) { var menuMobileNode = jQuery("#mobile_menu"); var menuDesktopNode = jQuery("#desktop_menu"); if (jQuery(menuMobileNode).length > 0 && jQuery(menuMobileNode).html().trim().length == 0) { // mobile menu ist noch nicht initialisiert if (jQuery(menuDesktopNode).length == 0) { //console.log('ERROR - cannot find #desktop_menu'); } else { // kopiere das menu fuer die mobile darstellung jQuery(menuMobileNode).get(0).appendChild(jQuery(menuDesktopNode).find(".navigationMain").get(0).cloneNode(true)); // markiere den aktuell ausgewaehlten menupunkt als offen jQuery(menuMobileNode).find('ul>li.selected').each(function () { jQuery(this).addClass('mm-opened'); }); } jQuery('.mobile_menu_btn').addClass('menu_not_empty'); // unhide button, if menu not empty jQuery(menuMobileNode).mmenu({ //Options slidingSubmenus: false, offCanvas: { position: "left", zposition: "next" }, // configuration classNames: { fixedElements: { fixed: "header" } }, onClick: { close: false } }, { //configs panelNodetype: "div, ul, ol" }); jQuery("#mobile_menu li > a.mm-next").each(function () { jQuery(this).attr('href', '#'); // hebelt den auf/zuklapp mechanismus der mmenu bibliothek aus (sonst fehler bei s3 mini) }); var $mobileMenuNode = jQuery('#mobile_menu'); var $aToMove = $mobileMenuNode.find('#native-app-preferences-menu-link'); var $oldParent = $aToMove.parent(); $mobileMenuNode.prepend($aToMove); $oldParent.remove(); // sorgt dafuer das im mobile menu immer nur 1 element aufgeklappt ist // und fuer den ein / ausblendeffekt jQuery("#mobile_menu li > a.mm-next").bind("touchstart click", function (e) { e.preventDefault(); e.stopPropagation(); if (is_touch_device() && e.type == 'click') { return; // da sonst der code evtl 2 mal durchlaufen wird (bsp s3 mini) } var $href = jQuery(this); var closeTime = 200; if (!$href.parent().hasClass("mm-opened") && !$href.parent().hasClass("current")) { var waitForClose = false; $href.closest("ul").find(".mm-opened, .current").each(function () { //schliesse alle noch offenen Menupunkte jQuery(this).removeClass("mm-opened").removeClass('current'); jQuery(this).children('.mm-panel').slideUp(closeTime, function () { jQuery(this).css('display', ''); }); waitForClose = true; }); // blende angeklickten menupunkt an $href.parent().addClass("mm-opened"); var $panel = $href.parent().children('.mm-panel'); $panel.slideUp(0); window.setTimeout(function () { // einblendgeschwindikeit abhaengig von anzahl Eintraege $panel.slideDown(($panel.children('ul').children('li').length * 100), function () { jQuery(this).css('display', ''); }); }, waitForClose ? closeTime : 0); } else { // schliesse angeklickten menupunkt $href.closest("ul").find(".mm-opened").removeClass("mm-opened").children('.mm-panel').slideDown(0).slideUp(closeTime, function () { jQuery(this).css('display', ''); }); } }); // Bind additional Eventhandlers if (jQuery(menuMobileNode).data("mmenu") !== undefined) { jQuery(menuMobileNode).data("mmenu").bind("open", function (panel) { jQuery(menuMobileNode).find('.mm-opened').removeClass('mm-opened'); jQuery(menuMobileNode).find('ul>li.selected').each(function () { jQuery(this).addClass('mm-opened'); }); jQuery(window).scrollTop(0); jQuery('#mm-blocker').fadeIn(300) }).bind("closed", function () { jQuery(window).scrollTop(scrollPosBeforeMenu); }).bind("close", function () { jQuery('#mm-blocker').fadeOut(300); }); } jQuery(".mobile_menu_btn").on('click touchstart', function (e) { if (jQuery("html").hasClass('mm-opened')) { e.preventDefault(); e.stopPropagation(); jQuery(menuMobileNode).data("mmenu").close(); } else { scrollPosBeforeMenu = jQuery(window).scrollTop(); if (is_small_and_down()) { jQuery('#search').fadeOut(200); } } }); // Flaeche unterhalb mobilem Menu einbauen, damit ein schliessen onclick hinzu kommen kann (DKBAPP-233) var closeArea = document.createElement('div'); closeArea.className = "closeMenuOnClick"; jQuery('#menu').append(closeArea); jQuery('.closeMenuOnClick').on('click touchstart', function (e) {closeMobileMenu()}); jQuery("#mobile_menu li > a").bind('click', function (e) {wt.sendinfo({linkId: "mobilemenu_"+jQuery(this).attr("href"),sendOnUnload:1});}); } } }; /** * In der Ansicht 'small' werden Tabellenspalten teilweise zusammengelegt. Der Inhalt der ausgeblendeten Spalte wird zu dem der sichtbaren Spalte geklont. * Hinweis: F�r dkb:table steht dkb:multisort zur Verf�gung. F�r xx:table wird diese Funktion aktuell noch verwendet. */ Abaxx.core.companionScript("data-dkb-collapsable-table-column-headers", function ($table) { var $collapsableTableHeaders = $table.find('th.collapse-when-small'); var $targetTableHeader = $table.find('.take-collapsed-th'); if (!$targetTableHeader.length) { return; // kein Ziel zum Aufnehmen der Elemente vorhanden } $collapsableTableHeaders.each(function (index, element) { // jeden gefundenen TableHeader-Inhalt clonen und beim Target einf�gen var $headerContent = jQuery(element).children().first().clone(true); $targetTableHeader.append($headerContent); }); }); /** * Dropwdown Button Funktionalit�t */ function initDropdown() { jQuery('.sbLink:not(.sbToggleBound)').addClass('sbToggleBound').children('.sbToggleable, .sbToggle').on('click', function (e) { e.preventDefault(); var $this = jQuery(this); if (!$this.is('.sbDisabled')) { // pr�fen ob Dropdown bereits offen var $sbLink = $this.closest('.sbLink'); if ($sbLink && $sbLink.is('.active')) { // schlie�en $sbLink.removeClass('active').find(".sbOptions").removeClass('focused'); $this.blur(); } else { // sonst andere Dropdowns schlie�en jQuery('.sbLink').removeClass('active').find('.sbOptions').removeClass('focused'); // Dropdown �ffnen $this.siblings('.sbOptions').toggleClass('focused'); $sbLink.toggleClass('active'); // Klick irgendwo au�erhalb f�hrt auch zum Schlie�en jQuery(document).unbind('.selectBoxToggle'); setTimeout(function () { jQuery(document).bind('click.selectBoxToggle', function () { jQuery('.sbOptions').removeClass('focused'); jQuery('.sbLink').removeClass('active'); }); }, 10); } } else { $this.blur(); } }); } ; /* * (c) Crealogix (Deutschland) AG, Projekt DKB. */ Abaxx.define("dkb_paymenttransaction", function () { "use strict"; var showDailyBalanceTable = false; var showDailyBalanceDiagram = false; var url = ''; /** * Liegt der Umsatz vor dem Jahr 2017? * @param currentTransactionDate * @returns {boolean} */ function isTransactionDateBefore2017 (currentTransactionDate) { var dateToCompareWith = new Date(2017, 0, 1); var dateParts = currentTransactionDate.split("."); var transactionDateCompare = new Date(dateParts[2], dateParts[1] - 1, dateParts[0]); var isTransactionDateBefore2017 = transactionDateCompare < dateToCompareWith; return isTransactionDateBefore2017; } /** * Hinzuf�gen der Tagessaldozeilen in die Umsatztabelle. * @param rowId * @param isAscending * @param pageSize * @param todaysDate * @param currentTransactionDate * @param beforeTransactionDate * @param nextTransactionDate * @param dailyBalance * @param dailyBalanceLabel */ function addDailyBalanceTableRow (rowId, isAscending, pageSize, todaysDate, currentTransactionDate, beforeTransactionDate, nextTransactionDate, dailyBalance, dailyBalanceLabel) { var borderDailyBalance = getCssClass(isAscending); var tableRow = '<tr id="umsatzTabelle_dailyBalance_' + rowId + '" class="valueDate ' + borderDailyBalance + '">' +'<td class="transactionText transactionTextDailyBalance"> ' + currentTransactionDate + '</td>' +'<td class="hide-for-xsmall-down">' + (dailyBalance === '' ? '' : dailyBalanceLabel) + '</td>' +'<td class="show-for-large-up"></td>' +'<td class="dailyBalanceText">' + dailyBalance + '</td>' +'<td class="alignRight actions nowidth"></td>' +'</tr>'; if (todaysDate != currentTransactionDate && !isTransactionDateBefore2017(currentTransactionDate)) { if (isAscending) { if (currentTransactionDate != nextTransactionDate) { jQuery("#umsatzTabelle_" + rowId).after(tableRow); } } else { if (currentTransactionDate != beforeTransactionDate || rowId % pageSize == 0) { jQuery("#umsatzTabelle_" + rowId).before(tableRow); } } } } /** * Hinzuf�gen der Tagessaldozeilen in der Druckansicht. * @param rowId * @param isAscending * @param todaysDate * @param currentTransactionDate * @param beforeTransactionDate * @param nextTransactionDate * @param dailyBalance * @param showDailyBalancesInit */ function addDailyBalanceTableRowPrintView (rowId, isAscending, todaysDate, currentTransactionDate, beforeTransactionDate, nextTransactionDate, dailyBalance, dailyBalanceLabel) { var showDailyBalances = false; if (localStorage.getItem("showDailyBalance") != null) { showDailyBalances = localStorage.getItem("showDailyBalance"); } var borderDailyBalance = getCssClass(isAscending); var tableRow = '<tr id="umsatzTabelle_dailyBalance_' + rowId + '" class="valueDate '+borderDailyBalance+'" style="display:none">' +'<td class="hide-for-xsmall-down"></td>' +'<td style="font-color:#222222;" class="transactionText"> ' + (dailyBalance === '' ? '' : dailyBalanceLabel +' vom ') + currentTransactionDate + '</td>' +'<td class="show-for-large-up"></td>' +'<td style="text-align: right; font-size:13px; font-color:#222222; font-weight:bold">' + dailyBalance + '</td>' +'</tr>'; if (todaysDate != currentTransactionDate && !isTransactionDateBefore2017(currentTransactionDate)) { if (isAscending) { if (currentTransactionDate != nextTransactionDate) { jQuery("#umsatzTabelle_" + rowId).after(tableRow); } } else { if (currentTransactionDate != beforeTransactionDate) { jQuery("#umsatzTabelle_" + rowId).before(tableRow); } } } if (showDailyBalances == 'true') { jQuery("tr[id^='umsatzTabelle_dailyBalance_']").show(); } else { jQuery("tr[id^='umsatzTabelle_dailyBalance_']").hide(); } } /** * Tagessalden in der Tabelle darstellen / nicht darstellen. */ function toggleDailyBalanceInTable () { var isChecked = jQuery('#showDailyBalanceInTableCheckBox').is(':checked'); jQuery('#showDailyBalance').prop("checked", isChecked); // Selektion im Formular localStorage.setItem("showDailyBalance", isChecked); if (isChecked) { showDailyBalanceInTable(); } else { hideDailyBalanceInTable(); } jQuery.ajax(url + '&value=' + isChecked); } function getCssClass(isAscending) { var borderDailyBalance; if (isAscending) { borderDailyBalance = "borderDailyBalanceAsc"; } else { borderDailyBalance = "borderDailyBalanceDesc"; } return borderDailyBalance; } /** * Erzwingt die Darstellung der Tabelle. */ function forceDailyBalanceInTable () { jQuery('#showDailyBalance').prop("checked", true); jQuery("tr[id^='umsatzTabelle_dailyBalance_']").show(); showDailyBalanceInTable(); jQuery.ajax(url + '&value=true'); } /** * Textmeldung (Erkl�rung) zu Tagessalden anzeigen. */ function displayDailyBalanceMessage () { if (showDailyBalanceTable == true || showDailyBalanceDiagram == true) { jQuery("#dailyBalanceMessage").show(); } else { jQuery("#dailyBalanceMessage").hide(); } } /** * Die Zeile Tagessalden in der Umsatztabelle einblenden. */ function showDailyBalanceInTable () { jQuery('#showDailyBalanceLabel').addClass('checked'); jQuery("tr[id^='umsatzTabelle_dailyBalance_']").show(); jQuery('#showDailyBalance').prop("checked", true); jQuery('#showDailyBalanceInTableCheckBox').prop("checked", true); showDailyBalanceTable = true; displayDailyBalanceMessage(); } /** * Die Zeile Tagessalden in der Umsatztabelle ausblenden. */ function hideDailyBalanceInTable () { jQuery('#showDailyBalanceLabel').removeClass('checked'); jQuery("tr[id^='umsatzTabelle_dailyBalance_']").hide(); jQuery('#showDailyBalance').prop("checked", false); jQuery('#showDailyBalanceInTableCheckBox').prop("checked", false); showDailyBalanceTable = false; displayDailyBalanceMessage(); } /** * Diagramm zu den Tagessalden darstellen / nicht darstellen. */ function toggleDailyBalanceDiagram () { if (jQuery('#dailyBalanceDiagram').is(":visible")) { closeDailyBalanceDiagram(); } else { openDailyBalanceDiagram(); } } /** * Diagramm zu den Tagessalden darstellen. */ function openDailyBalanceDiagram () { jQuery('#iconExpandDiagram').attr('class', 'icons iconExpandLess'); jQuery('#showDailyBalance').prop("checked", true); // Hidden field in form localStorage.setItem("showDailyBalanceDiagram", true); drawDiagram(); jQuery('#dailyBalanceDiagram').show(); showDailyBalanceDiagram = true; displayDailyBalanceMessage(); } /** * Diagramm zu den Tagessalden ausblenden. */ function closeDailyBalanceDiagram () { jQuery('#iconExpandDiagram').attr('class', 'icons iconExpandMore'); jQuery('#showDailyBalance').prop("checked", false); // Hidden field in form localStorage.setItem("showDailyBalanceDiagram", false); jQuery('#dailyBalanceDiagram').hide(); showDailyBalanceDiagram = false; displayDailyBalanceMessage(); } /** * Initialisierung nach Pageload/reload * @param isExtendedView * @param showDailyBalancesInit * @param dailyBalanceDiagramInit */ function init (isExtendedView, showDailyBalancesInit, dailyBalanceDiagramInit, partURL) { var showDiagram; var showDailyBalances = false; url = partURL; if (localStorage.getItem("showDailyBalance") != null) { showDailyBalances = localStorage.getItem("showDailyBalance"); } else { showDailyBalances = showDailyBalancesInit; } if (isExtendedView == 'false') { if (localStorage.getItem("showDailyBalanceDiagram") != null) { showDiagram = localStorage.getItem("showDailyBalanceDiagram"); } else { showDiagram = dailyBalanceDiagramInit; } if (showDiagram === 'true') { openDailyBalanceDiagram(); } else { closeDailyBalanceDiagram(); } if (showDailyBalances === 'true') { showDailyBalanceInTable(); } else { hideDailyBalanceInTable(); } jQuery.ajax(partURL + '&value=' + showDailyBalances); } } /** * Die Tagessaldenwerte aus der JSP besorgen. * @returns {Array} */ function diagramValues () { var dataObj = []; var diagramValuesObj = jQuery.parseJSON(diagramValuesJson); jQuery.each(diagramValuesObj, function (index, value) { var parts = value["date"].split('-'); // Jahr Monat Tag var dateFormatted = new Date(parts[1] + "/" + parts[2] + "/" + parts[0]); dataObj.push([dateFormatted.getTime(), value["balance"]]); }); return dataObj; } /** * Diagramm (Hipchart) initialisieren. */ function drawDiagram () { jQuery('#dailyBalanceDiagram').highcharts({ chart: { type: 'line', spacing: [0, 3, 0, 3], height: 150, style: { fontFamily: 'Arial, Helvetica, sans-serif' } }, title: { text: null }, subtitle: { text: null }, xAxis: { type: 'datetime', dateTimeLabelFormats: { // don't display the dummy year millisecond: '%d.%m.%y', second: '%d.%m.%y', minute: '%d.%m.%y', hour: '%d.%m.%y', day: '%d.%m', week: '%d.%m.%y', month: '%m.%Y', year: '%Y' }, crosshair: true, minPadding: 0.1, title: { text: '' } }, yAxis: { title: { text: null }, softmin: 0, labels: { align: 'left', x: 3, y: 16, format: '{value:.2f} \u20AC' }, showFirstLabel: false }, tooltip: { pointFormat: '{point.y:.2f} \u20AC', backgroundColor: null, borderWidth: 0, borderRadius: 0, shadow: false, useHTML: true, headerFormat: '', followPointer: false, pointFormatter: function () { var date = new Date(this.x); var warningClass = this.y < 0 ? 'red' : ''; return '<div class="info"><p><span class="highcharts-tooltip-value ' + warningClass + '">' + Highcharts.numberFormat(this.y) + ' €</span></p><p><span class="highcharts-tooltip-value-secondary">' + date.getDate() + '.' + (date.getMonth() + 1) + '.' + date.getFullYear() + '</span></p></div>'; } }, legend: { enabled: false }, plotOptions: { series: { step: 'left', color: '#127ed0', negativeColor: '#EE2300', marker: { enabled: true, radius: 0, states: { hover: { radius: 5, } } } } }, series: [{ name: 'Kontoname', // Define the data points. All series have a dummy year data: diagramValues() }] }); window.setTimeout(function(){ jQuery(window).trigger('resize'); }); } return { init: init, addDailyBalanceTableRow: addDailyBalanceTableRow, addDailyBalanceTableRowPrintView: addDailyBalanceTableRowPrintView, toggleDailyBalanceDiagram: toggleDailyBalanceDiagram, toggleDailyBalanceInTable: toggleDailyBalanceInTable, forceDailyBalanceInTable: forceDailyBalanceInTable }; }); /* http://keith-wood.name/keypad.html Keypad field entry extension for jQuery v1.5.1. Written by Keith Wood (kbwood{at}iinet.com.au) August 2008. Available under the MIT (https://github.com/jquery/jquery/blob/master/MIT-LICENSE.txt) license. Please attribute the author if you use it. */ (function($) { // hide the namespace /* Keypad manager. Use the singleton instance of this class, $.keypad, to interact with the plugin. Settings for keypad fields are maintained in instance objects, allowing multiple different settings on the same page. */ function Keypad() { this._curInst = null; // The current instance in use this._disabledFields = []; // List of keypad fields that have been disabled this._keypadShowing = false; // True if the popup panel is showing , false if not this._keyCode = 0; this._specialKeys = []; this.addKeyDef('CLOSE', 'close', function(inst) { plugin._curInst = (inst._inline ? inst : plugin._curInst); plugin._hidePlugin(); }); this.addKeyDef('CLEAR', 'clear', function(inst) { plugin._clearValue(inst); }); this.addKeyDef('BACK', 'back', function(inst) { plugin._backValue(inst); }); this.addKeyDef('SHIFT', 'shift', function(inst) { plugin._shiftKeypad(inst); }); this.addKeyDef('SPACE_BAR', 'spacebar', function(inst) { plugin._selectValue(inst, ' '); }, true); this.addKeyDef('SPACE', 'space'); this.addKeyDef('HALF_SPACE', 'half-space'); this.addKeyDef('ENTER', 'enter', function(inst) { plugin._selectValue(inst, '\x0D'); }, true); this.addKeyDef('TAB', 'tab', function(inst) { plugin._selectValue(inst, '\x09'); }, true); // Standard US keyboard alphabetic layout this.qwertyAlphabetic = ['qwertyuiop', 'asdfghjkl', 'zxcvbnm']; // Standard US keyboard layout this.qwertyLayout = ['!@#$%^&*()_=' + this.HALF_SPACE + this.SPACE + this.CLOSE, this.HALF_SPACE + '`~[]{}<>\\|/' + this.SPACE + '789', 'qwertyuiop\'"' + this.HALF_SPACE + '456', this.HALF_SPACE + 'asdfghjkl;:' + this.SPACE + '123', this.SPACE + 'zxcvbnm,.?' + this.SPACE + this.HALF_SPACE + '-0+', '' + this.TAB + this.ENTER + this.SPACE_BAR + this.SHIFT + this.HALF_SPACE + this.BACK + this.CLEAR]; this.regional = []; // Available regional settings, indexed by language code this.regional[''] = { // Default regional settings buttonText: '...', // Display text for trigger button buttonStatus: 'Open the keypad', // Status text for trigger button closeText: 'Close', // Display text for close link closeStatus: 'Close the keypad', // Status text for close link clearText: 'Clear', // Display text for clear link clearStatus: 'Erase all the text', // Status text for clear link backText: 'Back', // Display text for back link backStatus: 'Erase the previous character', // Status text for back link spacebarText: ' ', // Display text for space bar spacebarStatus: 'Space', // Status text for space bar enterText: 'Enter', // Display text for carriage return enterStatus: 'Carriage return', // Status text for carriage return tabText: '→', // Display text for tab tabStatus: 'Horizontal tab', // Status text for tab shiftText: 'Shift', // Display text for shift link shiftStatus: 'Toggle upper/lower case characters', // Status text for shift link alphabeticLayout: this.qwertyAlphabetic, // Default layout for alphabetic characters fullLayout: this.qwertyLayout, // Default layout for full keyboard isAlphabetic: this.isAlphabetic, // Function to determine if character is alphabetic isNumeric: this.isNumeric, // Function to determine if character is numeric toUpper: this.toUpper, // Function to convert characters to upper case isRTL: false // True if right-to-left language, false if left-to-right }; this._defaults = { // Global defaults for all the keypad instances showOn: 'focus', // 'focus' for popup on focus, // 'button' for trigger button, or 'both' for either buttonImage: '', // URL for trigger button image buttonImageOnly: false, // True if the image appears alone, false if it appears on a button showAnim: 'show', // Name of jQuery animation for popup showOptions: {}, // Options for enhanced animations duration: 'normal', // Duration of display/closure appendText: '', // Display text following the text field, e.g. showing the format useThemeRoller: false, // True to add ThemeRoller classes keypadClass: '', // Additional CSS class for the keypad for an instance prompt: '', // Display text at the top of the keypad layout: ['123' + this.CLOSE, '456' + this.CLEAR, '789' + this.BACK, this.SPACE + '0'], // Layout of keys separator: '', // Separator character between keys target: null, // Input target for an inline keypad keypadOnly: true, // True for entry only via the keypad, false for real keyboard too randomiseAlphabetic: false, // True to randomise the alphabetic key positions, false to keep in order randomiseNumeric: false, // True to randomise the numeric key positions, false to keep in order randomiseOther: false, // True to randomise the other key positions, false to keep in order randomiseAll: false, // True to randomise all key positions, false to keep in order beforeShow: null, // Callback before showing the keypad onKeypress: null, // Callback when a key is selected onClose: null // Callback when the panel is closed }; $.extend(this._defaults, this.regional['']); this.mainDiv = $('<div class="' + this._mainDivClass + '" style="display: none;"></div>'); } $.extend(Keypad.prototype, { /* Class name added to elements to indicate already configured with keypad. */ markerClassName: 'hasKeypad', /* Name of the data property for instance settings. */ propertyName: 'keypad', _mainDivClass: 'shadowBox', // The main keypad division class _inlineClass: 'keypad-inline', // The inline marker class _appendClass: 'keypad-append', // The append marker class _triggerClass: 'keypad-trigger', // The trigger marker class _disableClass: 'keypad-disabled', // The disabled covering marker class _inlineEntryClass: 'keypad-keyentry', // The inline entry marker class _rtlClass: 'keypad-rtl', // The right-to-left marker class _rowClass: 'keypad-row', // The keypad row marker class _promptClass: 'keypad-prompt', // The prompt marker class _specialClass: 'keypad-special', // The special key marker class _namePrefixClass: 'keypad-', // The key name marker class prefix _keyClass: 'keypad-key', // The key marker class _keyDownClass: 'keypad-key-down', // The key down marker class /* Override the default settings for all keypad instances. @param settings (object) the new settings to use as defaults @return (Keypad) this object */ setDefaults: function(settings) { $.extend(this._defaults, settings || {}); return this; }, /* Add the definition of a special key. @param id (string) the identifier for this key - access via $.keypad.<id> @param name (string) the prefix for localisation strings and the suffix for a class name @param action (function) the action performed for this key - receives inst as a parameter @param noHighlight (boolean) true to suppress highlight when using ThemeRoller @return (Keypad) this object */ addKeyDef: function(id, name, action, noHighlight) { if (this._keyCode == 32) { throw 'Only 32 special keys allowed'; } this[id] = String.fromCharCode(this._keyCode++); this._specialKeys.push({code: this[id], id: id, name: name, action: action, noHighlight: noHighlight}); return this; }, /* Attach the keypad to a jQuery selection. @param target (element) the control to affect @param options (object) the custom options for this instance */ _attachPlugin: function(target, options) { target = $(target); if (target.hasClass(this.markerClassName)) { return; } var inline = !target[0].nodeName.toLowerCase().match(/input|textarea/); var inst = {options: $.extend({}, this._defaults, options), _inline: inline, _mainDiv: (inline ? $('<div class="' + this._inlineClass + '"></div>') : plugin.mainDiv), ucase: false}; this._setInput(target, inst); this._connectKeypad(target, inst); if (inline) { target.append(inst._mainDiv). bind('click.' + this.propertyName, function() { inst._input.focus(); }); this._updateKeypad(inst); } else if (target.is(':disabled')) { this._disablePlugin(target); } }, /* Determine the input field for the keypad. @param target (jQuery) the target control @param inst (object) the instance settings */ _setInput: function(target, inst) { inst._input = $(!inst._inline ? target : inst.options.target || '<input type="text" class="' + this._inlineEntryClass + '" disabled="disabled"/>'); if (inst._inline) { target.find('input').remove(); if (!inst.options.target) { target.append(inst._input); } } }, /* Attach the keypad to a text field. @param target (jQuery) the target text field @param inst (object) the instance settings */ _connectKeypad: function(target, inst) { target = $(target); var appendText = inst.options.appendText; if (appendText) { target[inst.options.isRTL ? 'before' : 'after']( '<span class="' + this._appendClass + '">' + appendText + '</span>'); } if (!inst._inline) { if (inst.options.showOn == 'focus' || inst.options.showOn == 'both') { // pop-up keypad when in the marked field target.bind('focus.' + this.propertyName, this._showPlugin). bind('keydown.' + this.propertyName, this._doKeyDown); } if (inst.options.showOn == 'button' || inst.options.showOn == 'both') { // pop-up keypad when button clicked var buttonStatus = inst.options.buttonStatus; var buttonImage = inst.options.buttonImage; var trigger = $(inst.options.buttonImageOnly ? $('<a href="#vt" class="vt-control date-picker-control" tabindex="0" />') : $('<button type="button" title="' + buttonStatus + '"></button>'). html(buttonImage == '' ? inst.options.buttonText : $('<img src="' + buttonImage + '" alt="' + buttonStatus + '" title="' + buttonStatus + '"/>'))); target[inst.options.isRTL ? 'before' : 'after'](trigger); trigger.addClass(this._triggerClass).click(function() { if (plugin._keypadShowing && plugin._lastField == target[0]) { plugin._hidePlugin(); } else { plugin._showPlugin(target[0]); } return false; }); } } inst.saveReadonly = target.attr('readonly'); target.addClass(this.markerClassName). data(this.propertyName, inst) [inst.options.keypadOnly ? 'attr' : 'removeAttr']('readonly', true). bind('setData.' + this.propertyName, function(event, key, value) { inst.options[key] = value; }).bind('getData.' + this.propertyName, function(event, key) { return inst.options[key]; }); }, /* Retrieve or reconfigure the settings for a control. @param target (element) the control to affect @param options (object) the new options for this instance or (string) an individual property name @param value (any) the individual property value (omit if options is an object or to retrieve the value of a setting) @return (any) if retrieving a value */ _optionPlugin: function(target, options, value) { target = $(target); var inst = target.data(this.propertyName); if (!options || (typeof options == 'string' && value == null)) { // Get option var name = options; options = (inst || {}).options; return (options && name ? options[name] : options); } if (!target.hasClass(this.markerClassName)) { return; } options = options || {}; if (typeof options == 'string') { var name = options; options = {}; options[name] = value; } if (this._curInst == inst) { this._hidePlugin(); } $.extend(inst.options, options); this._setInput(target, inst); this._updateKeypad(inst); }, /* Detach keypad from its control. @param target (element) the target text field */ _destroyPlugin: function(target) { target = $(target); if (!target.hasClass(this.markerClassName)) { return; } var inst = target.data(this.propertyName); if (this._curInst == inst) { this._hidePlugin(); } target.siblings('.' + this._appendClass).remove().end(). siblings('.' + this._triggerClass).remove().end(). prev('.' + this._inlineEntryClass).remove(); target.removeClass(this.markerClassName).empty(). unbind('.' + this.propertyName). removeData(this.propertyName) [inst.saveReadonly ? 'attr' : 'removeAttr']('readonly', true); inst._input.removeData(this.propertyName); }, /* Enable the keypad for a jQuery selection. @param target (element) the target text field */ _enablePlugin: function(target) { target = $(target); if (!target.hasClass(this.markerClassName)) { return; } var nodeName = target[0].nodeName.toLowerCase(); if (nodeName.match(/input|textarea/)) { target[0].disabled = false; target.siblings('button.' + this._triggerClass). each(function() { this.disabled = false; }).end(). siblings('img.' + this._triggerClass). css({opacity: '1.0', cursor: ''}); } else if (nodeName.match(/div|span/)) { target.children('.' + this._disableClass).remove(); var inst = target.data(this.propertyName); inst._mainDiv.find('button').removeAttr('disabled'); } this._disabledFields = $.map(this._disabledFields, function(value) { return (value == target[0] ? null : value); }); // delete entry }, /* Disable the keypad for a jQuery selection. @param target (element) the target text field */ _disablePlugin: function(target) { target = $(target); if (!target.hasClass(this.markerClassName)) { return; } var nodeName = target[0].nodeName.toLowerCase(); if (nodeName.match(/input|textarea/)) { target[0].disabled = true; target.siblings('button.' + this._triggerClass). each(function() { this.disabled = true; }).end(). siblings('img.' + this._triggerClass). css({opacity: '0.5', cursor: 'default'}); } else if (nodeName.match(/div|span/)) { var inline = target.children('.' + this._inlineClass); var offset = inline.offset(); var relOffset = {left: 0, top: 0}; inline.parents().each(function() { if ($(this).css('position') == 'relative') { relOffset = $(this).offset(); return false; } }); target.prepend('<div class="' + this._disableClass + '" style="width: ' + inline.outerWidth() + 'px; height: ' + inline.outerHeight() + 'px; left: ' + (offset.left - relOffset.left) + 'px; top: ' + (offset.top - relOffset.top) + 'px;"></div>'); var inst = target.data(this.propertyName); inst._mainDiv.find('button').attr('disabled', 'disabled'); } this._disabledFields = $.map(this._disabledFields, function(value) { return (value == target[0] ? null : value); }); // delete entry this._disabledFields[this._disabledFields.length] = target[0]; }, /* Is the text field disabled as a keypad? @param target (element) the target text field @return (boolean) true if disabled, false if enabled */ _isDisabledPlugin: function(target) { return (target && $.inArray(target, this._disabledFields) > -1); }, /* Pop-up the keypad for a given text field. @param field (element) the text field attached to the keypad or (event) if triggered by focus */ _showPlugin: function(field) { field = field.target || field; if (plugin._isDisabledPlugin(field) || plugin._lastField == field) { // already here return; } var inst = $.data(field, plugin.propertyName); plugin._hidePlugin(null, ''); plugin._lastField = field; plugin._pos = plugin._findPos(field); plugin._pos[1] += field.offsetHeight; // add the height var isFixed = false; $(field).parents().each(function() { isFixed |= $(this).css('position') == 'fixed'; return !isFixed; }); var offset = {left: plugin._pos[0], top: plugin._pos[1]}; plugin._pos = null; // determine sizing offscreen inst._mainDiv.css({position: 'absolute', display: 'block', top: '-1000px', width: 'auto'}); plugin._updateKeypad(inst); // and adjust position before showing offset = plugin._checkOffset(inst, offset, isFixed); inst._mainDiv.css({position: (isFixed ? 'fixed' : 'absolute'), display: 'none', left: offset.left + 'px', top: offset.top + 'px'}); var duration = inst.options.duration; var showAnim = inst.options.showAnim; var postProcess = function() { plugin._keypadShowing = true; }; if ($.effects && ($.effects[showAnim] || ($.effects.effect && $.effects.effect[showAnim]))) { var data = inst._mainDiv.data(); // Update old effects data for (var key in data) { if (key.match(/^ec\.storage\./)) { data[key] = inst._mainDiv.css(key.replace(/ec\.storage\./, '')); } } inst._mainDiv.data(data).show(showAnim, inst.options.showOptions, duration, postProcess); } else { inst._mainDiv[showAnim || 'show']((showAnim ? duration : 0), postProcess); } if (inst._input[0].type != 'hidden') { inst._input[0].focus(); } plugin._curInst = inst; }, /* Generate the keypad content. @param inst (object) the instance settings */ _updateKeypad: function(inst) { var borders = this._getBorders(inst._mainDiv); inst._mainDiv.empty().append(this._generateHTML(inst)). removeClass().addClass(inst.options.keypadClass + (inst.options.useThemeRoller ? ' ui-widget ui-widget-content' : '') + (inst.options.isRTL ? ' ' + this._rtlClass : '') + ' ' + (inst._inline ? this._inlineClass : this._mainDivClass)); if ($.isFunction(inst.options.beforeShow)) { inst.options.beforeShow.apply((inst._input ? inst._input[0] : null), [inst._mainDiv, inst]); } }, /* Retrieve the size of left and top borders for an element. @param elem (jQuery object) the element of interest @return (number[2]) the left and top borders */ _getBorders: function(elem) { var convert = function(value) { return {thin: 1, medium: 3, thick: 5}[value] || value; }; return [parseFloat(convert(elem.css('border-left-width'))), parseFloat(convert(elem.css('border-top-width')))]; }, /* Check positioning to remain on screen. @param inst (object) the instance settings @param offset (object) the current offset @param isFixed (boolean) true if the text field is fixed in position @return (object) the updated offset */ _checkOffset: function(inst, offset, isFixed) { var pos = inst._input ? this._findPos(inst._input[0]) : null; var browserWidth = window.innerWidth || document.documentElement.clientWidth; var browserHeight = window.innerHeight || document.documentElement.clientHeight; var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; var scrollY = document.documentElement.scrollTop || document.body.scrollTop; // recalculate width as otherwise set to 100% var width = 0; inst._mainDiv.find(':not(div)').each(function() { width = Math.max(width, this.offsetLeft + $(this).outerWidth(true)); }); inst._mainDiv.css('width', width + 1); // reposition keypad panel horizontally if outside the browser window if (inst.options.isRTL || (offset.left + inst._mainDiv.outerWidth() - scrollX) > browserWidth) { offset.left = Math.max((isFixed ? 0 : scrollX), pos[0] + (inst._input ? inst._input.outerWidth() : 0) - (isFixed ? scrollX : 0) - inst._mainDiv.outerWidth()); } else { offset.left = Math.max((isFixed ? 0 : scrollX), offset.left - (isFixed ? scrollX : 0)); } // reposition keypad panel vertically if outside the browser window if ((offset.top + inst._mainDiv.outerHeight() - scrollY) > browserHeight) { offset.top = Math.max((isFixed ? 0 : scrollY), pos[1] - (isFixed ? scrollY : 0) - inst._mainDiv.outerHeight()); } else { offset.top = Math.max((isFixed ? 0 : scrollY), offset.top - (isFixed ? scrollY : 0)); } return offset; }, /* Find an object's position on the screen. @param obj (element) the element to find the position for @return (int[2]) the element's position */ _findPos: function(obj) { while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) { obj = obj.nextSibling; } var position = $(obj).offset(); return [position.left, position.top]; }, /* Hide the keypad from view. @param field (element) the text field attached to the keypad @param duration (string) the duration over which to close the keypad */ _hidePlugin: function(field, duration) { var inst = this._curInst; if (!inst || (field && inst != $.data(field, this.propertyName))) { return; } if (this._keypadShowing) { duration = (duration != null ? duration : inst.options.duration); var showAnim = inst.options.showAnim; if ($.effects && ($.effects[showAnim] || ($.effects.effect && $.effects.effect[showAnim]))) { inst._mainDiv.hide(showAnim, inst.options.showOptions, duration); } else { inst._mainDiv[(showAnim == 'slideDown' ? 'slideUp' : (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))](showAnim ? duration : 0); } } if ($.isFunction(inst.options.onClose)) { inst.options.onClose.apply((inst._input ? inst._input[0] : null), // trigger custom callback [inst._input.val(), inst]); } if (this._keypadShowing) { this._keypadShowing = false; this._lastField = null; } if (inst._inline) { inst._input.val(''); } this._curInst = null; }, /* Handle keystrokes. @param e (event) the key event */ _doKeyDown: function(e) { if (e.keyCode == 9) { // Tab out plugin.mainDiv.stop(true, true); plugin._hidePlugin(); } }, /* Close keypad if clicked elsewhere. @param event (event) the mouseclick details */ _checkExternalClick: function(event) { if (!plugin._curInst) { return; } var target = $(event.target); if (!target.parents().andSelf().hasClass(plugin._mainDivClass) && !target.hasClass(plugin.markerClassName) && !target.parents().andSelf().hasClass(plugin._triggerClass) && plugin._keypadShowing) { plugin._hidePlugin(); } }, /* Toggle between upper and lower case. @param inst (object) the instance settings */ _shiftKeypad: function(inst) { inst.ucase = !inst.ucase; this._updateKeypad(inst); inst._input.focus(); // for further typing }, /* Erase the text field. @param inst (object) the instance settings */ _clearValue: function(inst) { this._setValue(inst, '', 0); this._notifyKeypress(inst, plugin.DEL); }, /* Erase the last character. @param inst (object) the instance settings */ _backValue: function(inst) { var field = inst._input[0]; var value = inst._input.val(); var range = [value.length, value.length]; if (field.setSelectionRange) { // Mozilla range = (inst._input.attr('readonly') || inst._input.attr('disabled') ? range : [field.selectionStart, field.selectionEnd]); } else if (field.createTextRange) { // IE range = (inst._input.attr('readonly') || inst._input.attr('disabled') ? range : this._getIERange(field)); } this._setValue(inst, (value.length == 0 ? '' : value.substr(0, range[0] - 1) + value.substr(range[1])), range[0] - 1); this._notifyKeypress(inst, plugin.BS); }, /* Update the text field with the selected value. @param inst (object) the instance settings @param value (string) the new character to add */ _selectValue: function(inst, value) { this.insertValue(inst._input[0], value); this._setValue(inst, inst._input.val()); this._notifyKeypress(inst, value); }, /* Update the text field with the selected value. @param input (element) the input field or (jQuery) jQuery collection @param value (string) the new character to add */ insertValue: function(input, value) { input = (input.jquery ? input : $(input)); var field = input[0]; var newValue = input.val(); var range = [newValue.length, newValue.length]; if (field.setSelectionRange) { // Mozilla range = (input.attr('readonly') || input.attr('disabled') ? range : [field.selectionStart, field.selectionEnd]); } else if (field.createTextRange) { // IE range = (input.attr('readonly') || input.attr('disabled') ? range : this._getIERange(field)); } input.val(newValue.substr(0, range[0]) + value + newValue.substr(range[1])); pos = range[0] + value.length; if (input.is(':visible')) { input.focus(); // for further typing } if (field.setSelectionRange) { // Mozilla if (input.is(':visible')) { field.setSelectionRange(pos, pos); } } else if (field.createTextRange) { // IE range = field.createTextRange(); range.move('character', pos); range.select(); } }, /* Get the coordinates for the selected area in the text field in IE. @param field (element) the target text field @return (int[2]) the start and end positions of the selection */ _getIERange: function(field) { field.focus(); var selectionRange = document.selection.createRange().duplicate(); // Use two ranges: before and selection var beforeRange = this._getIETextRange(field); beforeRange.setEndPoint('EndToStart', selectionRange); // Check each range for trimmed newlines by shrinking the range by one // character and seeing if the text property has changed. If it has not // changed then we know that IE has trimmed a \r\n from the end. var checkCRLF = function(range) { var origText = range.text; var text = origText; var finished = false; while (true) { if (range.compareEndPoints('StartToEnd', range) == 0) { break; } else { range.moveEnd('character', -1); if (range.text == origText) { text += '\r\n'; } else { break; } } } return text; }; var beforeText = checkCRLF(beforeRange); var selectionText = checkCRLF(selectionRange); return [beforeText.length, beforeText.length + selectionText.length]; }, /* Create an IE text range for the text field. @param field (element) the target text field @return (object) the corresponding text range */ _getIETextRange: function(field) { var isInput = (field.nodeName.toLowerCase() == 'input'); var range = (isInput ? field.createTextRange() : document.body.createTextRange()); if (!isInput) { range.moveToElementText(field); // Selects all the text for a textarea } return range; }, /* Set the text field to the selected value, and trigger any on change event. @param inst (object) the instance settings @param value (string) the new value for the text field */ _setValue: function(inst, value) { var maxlen = inst._input.attr('maxlength'); if (maxlen > -1) { value = value.substr(0, maxlen); } inst._input.val(value); if (!$.isFunction(inst.options.onKeypress)) { inst._input.trigger('change'); // fire the change event } }, _notifyKeypress: function(inst, key) { if ($.isFunction(inst.options.onKeypress)) { // trigger custom callback inst.options.onKeypress.apply((inst._input ? inst._input[0] : null), [key, inst._input.val(), inst]); } }, /* Generate the HTML for the current state of the keypad. @param inst (object) the instance settings @return (jQuery) the HTML for this keypad */ _generateHTML: function(inst) { var html = (!inst.options.prompt ? '' : '<div class="' + this._promptClass + (inst.options.useThemeRoller ? ' ui-widget-header ui-corner-all' : '') + '">' + inst.options.prompt + '</div>'); var layout = this._randomiseLayout(inst); for (var i = 0; i < layout.length; i++) { html += '<div class="' + this._rowClass + '">'; var keys = layout[i].split(inst.options.separator); for (var j = 0; j < keys.length; j++) { if (inst.ucase) { keys[j] = inst.options.toUpper(keys[j]); } var keyDef = this._specialKeys[keys[j].charCodeAt(0)]; if (keyDef) { html += (keyDef.action ? '<button type="button" class="' + this._specialClass + ' ' + this._namePrefixClass + keyDef.name + (inst.options.useThemeRoller ? ' ui-corner-all ui-state-default' + (keyDef.noHighlight ? '' : ' ui-state-highlight') : '') + '" title="' + inst.options[keyDef.name + 'Status'] + '">' + (inst.options[keyDef.name + 'Text'] || ' ') + '</button>' : '<div class="' + this._namePrefixClass + keyDef.name + '"></div>'); } else { html += '<button type="button" class="' + this._keyClass + (inst.options.useThemeRoller ? ' ui-corner-all ui-state-default' : '') + '">' + (keys[j] == ' ' ? ' ' : keys[j]) + '</button>'; } } html += '</div>'; } html = $(html); var thisInst = inst; var activeClasses = this._keyDownClass + (inst.options.useThemeRoller ? ' ui-state-active' : ''); html.find('button').mousedown(function() { $(this).addClass(activeClasses); }). mouseup(function() { $(this).removeClass(activeClasses); }). mouseout(function() { $(this).removeClass(activeClasses); }). filter('.' + this._keyClass).click(function() { plugin._selectValue(thisInst, $(this).text()); }); $.each(this._specialKeys, function(i, keyDef) { html.find('.' + plugin._namePrefixClass + keyDef.name).click(function() { keyDef.action.apply(thisInst._input, [thisInst]); }); }); return html; }, /* Check whether characters should be randomised, and, if so, produce the randomised layout. @param inst (object) the instance settings @return (string[]) the layout with any requested randomisations applied */ _randomiseLayout: function(inst) { if (!inst.options.randomiseNumeric && !inst.options.randomiseAlphabetic && !inst.options.randomiseOther && !inst.options.randomiseAll) { return inst.options.layout; } var numerics = []; var alphas = []; var others = []; var newLayout = []; // Find characters of different types for (var i = 0; i < inst.options.layout.length; i++) { newLayout[i] = ''; var keys = inst.options.layout[i].split(inst.options.separator); for (var j = 0; j < keys.length; j++) { if (this._isControl(keys[j])) { continue; } if (inst.options.randomiseAll) { others.push(keys[j]); } else if (inst.options.isNumeric(keys[j])) { numerics.push(keys[j]); } else if (inst.options.isAlphabetic(keys[j])) { alphas.push(keys[j]); } else { others.push(keys[j]); } } } // Shuffle them if (inst.options.randomiseNumeric) { this._shuffle(numerics); } if (inst.options.randomiseAlphabetic) { this._shuffle(alphas); } if (inst.options.randomiseOther || inst.options.randomiseAll) { this._shuffle(others); } var n = 0; var a = 0; var o = 0; // And replace them in the layout for (var i = 0; i < inst.options.layout.length; i++) { var keys = inst.options.layout[i].split(inst.options.separator); for (var j = 0; j < keys.length; j++) { newLayout[i] += (this._isControl(keys[j]) ? keys[j] : (inst.options.randomiseAll ? others[o++] : (inst.options.isNumeric(keys[j]) ? numerics[n++] : (inst.options.isAlphabetic(keys[j]) ? alphas[a++] : others[o++])))) + inst.options.separator; } } return newLayout; }, /* Is a given character a control character? @param ch (char) the character to test @return (boolean) true if a control character, false if not */ _isControl: function(ch) { return ch < ' '; }, /* Is a given character alphabetic? @param ch (char) the character to test @return (boolean) true if alphabetic, false if not */ isAlphabetic: function(ch) { return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); }, /* Is a given character numeric? @param ch (char) the character to test @return (boolean) true if numeric, false if not */ isNumeric: function(ch) { return (ch >= '0' && ch <= '9'); }, /* Convert a character to upper case. @param ch (char) the character to convert @return (char) its uppercase version */ toUpper: function(ch) { return ch.toUpperCase(); }, /* Randomise the contents of an array. @param values (string[]) the array to rearrange */ _shuffle: function(values) { for (var i = values.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * values.length); var ch = values[i]; values[i] = values[j]; values[j] = ch; } } }); // The list of commands that return values and don't permit chaining var getters = ['isDisabled']; /* Determine whether a command is a getter and doesn't permit chaining. @param command (string, optional) the command to run @param otherArgs ([], optional) any other arguments for the command @return true if the command is a getter, false if not */ function isNotChained(command, otherArgs) { if (command == 'option' && (otherArgs.length == 0 || (otherArgs.length == 1 && typeof otherArgs[0] == 'string'))) { return true; } return $.inArray(command, getters) > -1; } /* Invoke the keypad functionality. @param options (object) the new settings to use for these instances (optional) or (string) the command to run (optional) @return (jQuery) for chaining further calls or (any) getter value */ $.fn.keypad = function(options) { var otherArgs = Array.prototype.slice.call(arguments, 1); if (isNotChained(options, otherArgs)) { return plugin['_' + options + 'Plugin'].apply(plugin, [this[0]].concat(otherArgs)); } return this.each(function() { if (typeof options == 'string') { if (!plugin['_' + options + 'Plugin']) { throw 'Unknown command: ' + options; } plugin['_' + options + 'Plugin'].apply(plugin, [this].concat(otherArgs)); } else { plugin._attachPlugin(this, options || {}); } }); }; /* Initialise the keypad functionality. */ var plugin = $.keypad = new Keypad(); // Singleton instance // Add the keypad division and external click check $(function() { $(document.body).append(plugin.mainDiv). mousedown(plugin._checkExternalClick); }); })(jQuery); /* http://keith-wood.name/keypad.html German localisation for the jQuery keypad extension Written by Uwe Jakobs(u.jakobs{at}imageco.de) September 2009. */ /** * Anpassung an toUpper-Funktion */ (function($) { // hide the namespace $.keypad.qwertzAlphabetic = ['qwertzuiopüß', 'asdfghjklöä', 'yxcvbnm']; $.keypad.qwertzLayout = ['!"§$%&/()=?`' + $.keypad.BACK + $.keypad.HALF_SPACE + '$£€/', '<>°^@{[]}\\~´;:' + $.keypad.HALF_SPACE + '789*', $.keypad.qwertzAlphabetic[0] + '+*' + $.keypad.HALF_SPACE + '456-', $.keypad.HALF_SPACE + $.keypad.qwertzAlphabetic[1] + '#\'' + $.keypad.SPACE + '123+', '|' + $.keypad.qwertzAlphabetic[2] + 'µ,.-_' + $.keypad.SPACE + $.keypad.HALF_SPACE +'.0,=', $.keypad.SHIFT + $.keypad.SPACE + $.keypad.SPACE_BAR + $.keypad.SPACE + $.keypad.SPACE + $.keypad.SPACE + $.keypad.CLEAR + $.keypad.SPACE + $.keypad.SPACE + $.keypad.HALF_SPACE + $.keypad.CLOSE]; $.keypad.regional['de'] = { buttonText: '...', buttonStatus: 'Öffnen', closeText: 'schließen', closeStatus: 'schließen', clearText: 'löschen', clearStatus: 'Gesamten Inhalt löschen', backText: 'zurück', backStatus: 'Letzte Eingabe löschen', shiftText: 'umschalten', shiftStatus: 'Zwischen Groß- und Kleinschreibung wechseln', spacebarText: ' ', spacebarStatus: '', enterText: 'Enter', enterStatus: '', tabText: '→', tabStatus: '', alphabeticLayout: $.keypad.qwertzAlphabetic, fullLayout: $.keypad.qwertzLayout, isAlphabetic: $.keypad.isAlphabetic, isNumeric: $.keypad.isNumeric, // "monkey patch" - ß bleibt ß (sonst "ß".toUpperCase() === "SS") toUpper: function(ch) { return "ß" === ch ? "ß" : ch.toUpperCase(); }, isRTL: false}; $.keypad.setDefaults($.keypad.regional['de']); })(jQuery); // jQuery.event.swipe // 0.5 // Stephen Band // Dependencies // jQuery.event.move 1.2 // One of swipeleft, swiperight, swipeup or swipedown is triggered on // moveend, when the move has covered a threshold ratio of the dimension // of the target node, or has gone really fast. Threshold and velocity // sensitivity changed with: // // jQuery.event.special.swipe.settings.threshold // jQuery.event.special.swipe.settings.sensitivity (function (module) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(['jquery'], module); } else { // Browser globals module(jQuery); } })(function(jQuery, undefined){ var add = jQuery.event.add, remove = jQuery.event.remove, // Just sugar, so we can have arguments in the same order as // add and remove. trigger = function(node, type, data) { jQuery.event.trigger(type, data, node); }, settings = { // Ratio of distance over target finger must travel to be // considered a swipe. threshold: 0.4, // Faster fingers can travel shorter distances to be considered // swipes. 'sensitivity' controls how much. Bigger is shorter. sensitivity: 6 }; function moveend(e) { var w, h, event; w = e.target.offsetWidth; h = e.target.offsetHeight; // Copy over some useful properties from the move event event = { distX: e.distX, distY: e.distY, velocityX: e.velocityX, velocityY: e.velocityY, finger: e.finger }; // Find out which of the four directions was swiped if (e.distX > e.distY) { if (e.distX > -e.distY) { if (e.distX/w > settings.threshold || e.velocityX * e.distX/w * settings.sensitivity > 1) { event.type = 'swiperight'; trigger(e.currentTarget, event); } } else { if (-e.distY/h > settings.threshold || e.velocityY * e.distY/w * settings.sensitivity > 1) { event.type = 'swipeup'; trigger(e.currentTarget, event); } } } else { if (e.distX > -e.distY) { if (e.distY/h > settings.threshold || e.velocityY * e.distY/w * settings.sensitivity > 1) { event.type = 'swipedown'; trigger(e.currentTarget, event); } } else { if (-e.distX/w > settings.threshold || e.velocityX * e.distX/w * settings.sensitivity > 1) { event.type = 'swipeleft'; trigger(e.currentTarget, event); } } } } function getData(node) { var data = jQuery.data(node, 'event_swipe'); if (!data) { data = { count: 0 }; jQuery.data(node, 'event_swipe', data); } return data; } jQuery.event.special.swipe = jQuery.event.special.swipeleft = jQuery.event.special.swiperight = jQuery.event.special.swipeup = jQuery.event.special.swipedown = { setup: function( data, namespaces, eventHandle ) { var data = getData(this); // If another swipe event is already setup, don't setup again. if (data.count++ > 0) { return; } add(this, 'moveend', moveend); return true; }, teardown: function() { var data = getData(this); // If another swipe event is still setup, don't teardown. if (--data.count > 0) { return; } remove(this, 'moveend', moveend); return true; }, settings: settings }; }); /* * (c) Crealogix (Deutschland) AG, Projekt DKB. */ /* owl carusel file -- jQuery OwlCarousel v1.3.3 */ /*JS Lint helpers: */ /*global dragMove: false, dragEnd: false, $, jQuery, alert, window, document */ /*jslint nomen: true, continue:true */ if (typeof Object.create !== "function") { Object.create = function (obj) { function F() {} F.prototype = obj; return new F(); }; } (function ($, window, document) { var Carousel = { init : function (options, el) { var base = this; base.$elem = jQuery(el); base.options = $.extend({}, $.fn.owlCarousel.options, base.$elem.data(), options); base.userOptions = options; base.loadContent(); }, loadContent : function () { var base = this, url; function getData(data) { var i, content = ""; if (typeof base.options.jsonSuccess === "function") { base.options.jsonSuccess.apply(this, [data]); } else { for (i in data.owl) { if (data.owl.hasOwnProperty(i)) { content += data.owl[i].item; } } base.$elem.html(content); } base.logIn(); } if (typeof base.options.beforeInit === "function") { base.options.beforeInit.apply(this, [base.$elem]); } if (typeof base.options.jsonPath === "string") { url = base.options.jsonPath; $.getJSON(url, getData); } else { base.logIn(); } }, logIn : function () { var base = this; base.$elem.data("owl-originalStyles", base.$elem.attr("style")); base.$elem.data("owl-originalClasses", base.$elem.attr("class")); base.$elem.css({opacity: 0}); base.orignalItems = base.options.items; base.checkBrowser(); base.wrapperWidth = 0; base.checkVisible = null; base.setVars(); }, setVars : function () { var base = this; if (base.$elem.children().length === 0) {return false; } base.baseClass(); base.eventTypes(); base.$userItems = base.$elem.children(); base.itemsAmount = base.$userItems.length; base.wrapItems(); base.$owlItems = base.$elem.find(".owl-item"); base.$owlWrapper = base.$elem.find(".owl-wrapper"); base.playDirection = "next"; base.prevItem = 0; base.prevArr = [0]; base.currentItem = 0; base.customEvents(); base.onStartup(); }, onStartup : function () { var base = this; base.updateItems(); base.calculateAll(); base.buildControls(); base.updateControls(); base.response(); base.moveEvents(); base.stopOnHover(); base.owlStatus(); if (base.options.transitionStyle !== false) { base.transitionTypes(base.options.transitionStyle); } if (base.options.autoPlay === true) { base.options.autoPlay = 5000; } base.play(); base.$elem.find(".owl-wrapper").css("display", "block"); if (!base.$elem.is(":visible")) { base.watchVisibility(); } else { base.$elem.css("opacity", 1); } base.onstartup = false; base.eachMoveUpdate(); if (typeof base.options.afterInit === "function") { base.options.afterInit.apply(this, [base.$elem]); } }, eachMoveUpdate : function () { var base = this; if (base.options.lazyLoad === true) { base.lazyLoad(); } if (base.options.autoHeight === true) { base.autoHeight(); } base.onVisibleItems(); if (typeof base.options.afterAction === "function") { base.options.afterAction.apply(this, [base.$elem]); } }, updateVars : function () { var base = this; if (typeof base.options.beforeUpdate === "function") { base.options.beforeUpdate.apply(this, [base.$elem]); } base.watchVisibility(); base.updateItems(); base.calculateAll(); base.updatePosition(); base.updateControls(); base.eachMoveUpdate(); if (typeof base.options.afterUpdate === "function") { base.options.afterUpdate.apply(this, [base.$elem]); } }, reload : function () { var base = this; window.setTimeout(function () { base.updateVars(); }, 0); }, watchVisibility : function () { var base = this; if (base.$elem.is(":visible") === false) { base.$elem.css({opacity: 0}); window.clearInterval(base.autoPlayInterval); window.clearInterval(base.checkVisible); } else { return false; } base.checkVisible = window.setInterval(function () { if (base.$elem.is(":visible")) { base.reload(); base.$elem.animate({opacity: 1}, 200); window.clearInterval(base.checkVisible); } }, 500); }, wrapItems : function () { var base = this; base.$userItems.wrapAll("<div class=\"owl-wrapper\">").wrap("<div class=\"owl-item\"></div>"); base.$elem.find(".owl-wrapper").wrap("<div class=\"owl-wrapper-outer\">"); base.wrapperOuter = base.$elem.find(".owl-wrapper-outer"); base.$elem.css("display", "block"); }, baseClass : function () { var base = this, hasBaseClass = base.$elem.hasClass(base.options.baseClass), hasThemeClass = base.$elem.hasClass(base.options.theme); if (!hasBaseClass) { base.$elem.addClass(base.options.baseClass); } if (!hasThemeClass) { base.$elem.addClass(base.options.theme); } }, updateItems : function () { var base = this, width, i; if (base.options.responsive === false) { return false; } if (base.options.singleItem === true) { base.options.items = base.orignalItems = 1; base.options.itemsCustom = false; base.options.itemsDesktop = false; base.options.itemsDesktopSmall = false; base.options.itemsTablet = false; base.options.itemsTabletSmall = false; base.options.itemsMobile = false; return false; } width = jQuery(base.options.responsiveBaseWidth).width(); if (width > (base.options.itemsDesktop[0] || base.orignalItems)) { base.options.items = base.orignalItems; } if (base.options.itemsCustom !== false) { //Reorder array by screen size base.options.itemsCustom.sort(function (a, b) {return a[0] - b[0]; }); for (i = 0; i < base.options.itemsCustom.length; i += 1) { if(base.options.itemsCustom[i] != undefined){ if (base.options.itemsCustom[i][0] <= width) { base.options.items = base.options.itemsCustom[i][1]; } } } } else { if (width <= base.options.itemsDesktop[0] && base.options.itemsDesktop !== false) { base.options.items = base.options.itemsDesktop[1]; } if (width <= base.options.itemsDesktopSmall[0] && base.options.itemsDesktopSmall !== false) { base.options.items = base.options.itemsDesktopSmall[1]; } if (width <= base.options.itemsTablet[0] && base.options.itemsTablet !== false) { base.options.items = base.options.itemsTablet[1]; } if (width <= base.options.itemsTabletSmall[0] && base.options.itemsTabletSmall !== false) { base.options.items = base.options.itemsTabletSmall[1]; } if (width <= base.options.itemsMobile[0] && base.options.itemsMobile !== false) { base.options.items = base.options.itemsMobile[1]; } } //if number of items is less than declared if (base.options.items > base.itemsAmount && base.options.itemsScaleUp === true) { base.options.items = base.itemsAmount; } }, response : function () { var base = this, smallDelay, lastWindowWidth; if (base.options.responsive !== true) { return false; } lastWindowWidth = jQuery(window).width(); base.resizer = function () { if (jQuery(window).width() !== lastWindowWidth) { if (base.options.autoPlay !== false) { window.clearInterval(base.autoPlayInterval); } window.clearTimeout(smallDelay); smallDelay = window.setTimeout(function () { lastWindowWidth = jQuery(window).width(); base.updateVars(); }, base.options.responsiveRefreshRate); } }; jQuery(window).resize(base.resizer); }, updatePosition : function () { var base = this; base.jumpTo(base.currentItem); if (base.options.autoPlay !== false) { base.checkAp(); } }, appendItemsSizes : function () { var base = this, roundPages = 0, lastItem = base.itemsAmount - base.options.items; base.$owlItems.each(function (index) { var $this = jQuery(this); $this .css({"width": base.itemWidth}) .data("owl-item", Number(index)); if (index % base.options.items === 0 || index === lastItem) { if (!(index > lastItem)) { roundPages += 1; } } $this.data("owl-roundPages", roundPages); }); }, appendWrapperSizes : function () { var base = this, width = base.$owlItems.length * base.itemWidth; base.$owlWrapper.css({ "width": width * 2, "left": 0 }); base.appendItemsSizes(); }, calculateAll : function () { var base = this; base.calculateWidth(); base.appendWrapperSizes(); base.loops(); base.max(); }, calculateWidth : function () { var base = this; base.itemWidth = Math.round(base.$elem.width() / base.options.items); }, max : function () { var base = this, maximum = ((base.itemsAmount * base.itemWidth) - base.options.items * base.itemWidth) * -1; if (base.options.items > base.itemsAmount) { base.maximumItem = 0; maximum = 0; base.maximumPixels = 0; } else { base.maximumItem = base.itemsAmount - base.options.items; base.maximumPixels = maximum; } return maximum; }, min : function () { return 0; }, loops : function () { var base = this, prev = 0, elWidth = 0, i, item, roundPageNum; base.positionsInArray = [0]; base.pagesInArray = []; for (i = 0; i < base.itemsAmount; i += 1) { elWidth += base.itemWidth; base.positionsInArray.push(-elWidth); if (base.options.scrollPerPage === true) { item = jQuery(base.$owlItems[i]); roundPageNum = item.data("owl-roundPages"); if (roundPageNum !== prev) { base.pagesInArray[prev] = base.positionsInArray[i]; prev = roundPageNum; } } } }, buildControls : function () { var base = this; if (base.options.navigation === true || base.options.pagination === true) { base.owlControls = jQuery("<div class=\"owl-controls\"/>").toggleClass("clickable", !base.browser.isTouch).appendTo(base.$elem); } if (base.options.pagination === true) { base.buildPagination(); } if (base.options.navigation === true) { base.buildButtons(); } }, buildButtons : function () { var base = this, buttonsWrapper = jQuery("<div class=\"owl-buttons\"/>"); base.owlControls.append(buttonsWrapper); base.buttonPrev = jQuery("<div/>", { "class" : "owl-prev", "html" : base.options.navigationText[0] || "" }); base.buttonNext = jQuery("<div/>", { "class" : "owl-next", "html" : base.options.navigationText[1] || "" }); buttonsWrapper .append(base.buttonPrev) .append(base.buttonNext); buttonsWrapper.on("touchstart.owlControls mousedown.owlControls", "div[class^=\"owl\"]", function (event) { event.preventDefault(); }); buttonsWrapper.on("touchend.owlControls mouseup.owlControls", "div[class^=\"owl\"]", function (event) { event.preventDefault(); if (jQuery(this).hasClass("owl-next")) { base.next(); } else { base.prev(); } }); }, buildPagination : function () { var base = this; base.paginationWrapper = jQuery("<div class=\"owl-pagination\"/>"); base.owlControls.append(base.paginationWrapper); base.paginationWrapper.on("touchend.owlControls mouseup.owlControls", ".owl-page", function (event) { event.preventDefault(); if (Number(jQuery(this).data("owl-page")) !== base.currentItem) { base.goTo(Number(jQuery(this).data("owl-page")), true); } }); }, updatePagination : function () { var base = this, counter, lastPage, lastItem, i, paginationButton, paginationButtonInner; if (base.options.pagination === false) { return false; } base.paginationWrapper.html(""); counter = 0; lastPage = base.itemsAmount - base.itemsAmount % base.options.items; for (i = 0; i < base.itemsAmount; i += 1) { if (i % base.options.items === 0) { counter += 1; if (lastPage === i) { lastItem = base.itemsAmount - base.options.items; } paginationButton = jQuery("<div/>", { "class" : "owl-page" }); paginationButtonInner = jQuery("<span></span>", { "text": base.options.paginationNumbers === true ? counter : "", "class": base.options.paginationNumbers === true ? "owl-numbers" : "" }); paginationButton.append(paginationButtonInner); paginationButton.data("owl-page", lastPage === i ? lastItem : i); paginationButton.data("owl-roundPages", counter); base.paginationWrapper.append(paginationButton); } } base.checkPagination(); }, checkPagination : function () { var base = this; if (base.options.pagination === false) { return false; } base.paginationWrapper.find(".owl-page").each(function () { if (jQuery(this).data("owl-roundPages") === jQuery(base.$owlItems[base.currentItem]).data("owl-roundPages")) { base.paginationWrapper .find(".owl-page") .removeClass("active"); jQuery(this).addClass("active"); } }); }, checkNavigation : function () { var base = this; if (base.options.navigation === false) { return false; } if (base.options.rewindNav === false) { if (base.currentItem === 0 && base.maximumItem === 0) { base.buttonPrev.addClass("disabled"); base.buttonNext.addClass("disabled"); } else if (base.currentItem === 0 && base.maximumItem !== 0) { base.buttonPrev.addClass("disabled"); base.buttonNext.removeClass("disabled"); } else if (base.currentItem === base.maximumItem) { base.buttonPrev.removeClass("disabled"); base.buttonNext.addClass("disabled"); } else if (base.currentItem !== 0 && base.currentItem !== base.maximumItem) { base.buttonPrev.removeClass("disabled"); base.buttonNext.removeClass("disabled"); } } }, updateControls : function () { var base = this; base.updatePagination(); base.checkNavigation(); if (base.owlControls) { if (base.options.items >= base.itemsAmount) { base.owlControls.hide(); } else { base.owlControls.show(); } } }, destroyControls : function () { var base = this; if (base.owlControls) { base.owlControls.remove(); } }, next : function (speed) { var base = this; if (base.isTransition) { return false; } base.currentItem += base.options.scrollPerPage === true ? base.options.items : 1; if (base.currentItem > base.maximumItem + (base.options.scrollPerPage === true ? (base.options.items - 1) : 0)) { if (base.options.rewindNav === true) { base.currentItem = 0; speed = "rewind"; } else { base.currentItem = base.maximumItem; return false; } } base.goTo(base.currentItem, speed); }, prev : function (speed) { var base = this; if (base.isTransition) { return false; } if (base.options.scrollPerPage === true && base.currentItem > 0 && base.currentItem < base.options.items) { base.currentItem = 0; } else { base.currentItem -= base.options.scrollPerPage === true ? base.options.items : 1; } if (base.currentItem < 0) { if (base.options.rewindNav === true) { base.currentItem = base.maximumItem; speed = "rewind"; } else { base.currentItem = 0; return false; } } base.goTo(base.currentItem, speed); }, goTo : function (position, speed, drag) { var base = this, goToPixel; if (base.isTransition) { return false; } if (typeof base.options.beforeMove === "function") { base.options.beforeMove.apply(this, [base.$elem]); } if (position >= base.maximumItem) { position = base.maximumItem; } else if (position <= 0) { position = 0; } base.currentItem = base.owl.currentItem = position; if (base.options.transitionStyle !== false && drag !== "drag" && base.options.items === 1 && base.browser.support3d === true) { base.swapSpeed(0); if (base.browser.support3d === true) { base.transition3d(base.positionsInArray[position]); } else { base.css2slide(base.positionsInArray[position], 1); } base.afterGo(); base.singleItemTransition(); return false; } goToPixel = base.positionsInArray[position]; if (base.browser.support3d === true) { base.isCss3Finish = false; if (speed === true) { base.swapSpeed("paginationSpeed"); window.setTimeout(function () { base.isCss3Finish = true; }, base.options.paginationSpeed); } else if (speed === "rewind") { base.swapSpeed(base.options.rewindSpeed); window.setTimeout(function () { base.isCss3Finish = true; }, base.options.rewindSpeed); } else { base.swapSpeed("slideSpeed"); window.setTimeout(function () { base.isCss3Finish = true; }, base.options.slideSpeed); } base.transition3d(goToPixel); } else { if (speed === true) { base.css2slide(goToPixel, base.options.paginationSpeed); } else if (speed === "rewind") { base.css2slide(goToPixel, base.options.rewindSpeed); } else { base.css2slide(goToPixel, base.options.slideSpeed); } } base.afterGo(); }, jumpTo : function (position) { var base = this; if (typeof base.options.beforeMove === "function") { base.options.beforeMove.apply(this, [base.$elem]); } if (position >= base.maximumItem || position === -1) { position = base.maximumItem; } else if (position <= 0) { position = 0; } base.swapSpeed(0); if (base.browser.support3d === true) { base.transition3d(base.positionsInArray[position]); } else { base.css2slide(base.positionsInArray[position], 1); } base.currentItem = base.owl.currentItem = position; base.afterGo(); }, afterGo : function () { var base = this; base.prevArr.push(base.currentItem); base.prevItem = base.owl.prevItem = base.prevArr[base.prevArr.length - 2]; base.prevArr.shift(0); if (base.prevItem !== base.currentItem) { base.checkPagination(); base.checkNavigation(); base.eachMoveUpdate(); if (base.options.autoPlay !== false) { base.checkAp(); } } if (typeof base.options.afterMove === "function" && base.prevItem !== base.currentItem) { base.options.afterMove.apply(this, [base.$elem]); } }, stop : function () { var base = this; base.apStatus = "stop"; window.clearInterval(base.autoPlayInterval); }, checkAp : function () { var base = this; if (base.apStatus !== "stop") { base.play(); } }, play : function () { var base = this; base.apStatus = "play"; if (base.options.autoPlay === false) { return false; } window.clearInterval(base.autoPlayInterval); base.autoPlayInterval = window.setInterval(function () { base.next(true); }, base.options.autoPlay); }, swapSpeed : function (action) { var base = this; if (action === "slideSpeed") { base.$owlWrapper.css(base.addCssSpeed(base.options.slideSpeed)); } else if (action === "paginationSpeed") { base.$owlWrapper.css(base.addCssSpeed(base.options.paginationSpeed)); } else if (typeof action !== "string") { base.$owlWrapper.css(base.addCssSpeed(action)); } }, addCssSpeed : function (speed) { return { "-webkit-transition": "all " + speed + "ms ease", "-moz-transition": "all " + speed + "ms ease", "-o-transition": "all " + speed + "ms ease", "transition": "all " + speed + "ms ease" }; }, removeTransition : function () { return { "-webkit-transition": "", "-moz-transition": "", "-o-transition": "", "transition": "" }; }, doTranslate : function (pixels) { return { "-webkit-transform": "translate3d(" + pixels + "px, 0px, 0px)", "-moz-transform": "translate3d(" + pixels + "px, 0px, 0px)", "-o-transform": "translate3d(" + pixels + "px, 0px, 0px)", "-ms-transform": "translate3d(" + pixels + "px, 0px, 0px)", "transform": "translate3d(" + pixels + "px, 0px,0px)" }; }, transition3d : function (value) { var base = this; base.$owlWrapper.css(base.doTranslate(value)); }, css2move : function (value) { var base = this; base.$owlWrapper.css({"left" : value}); }, css2slide : function (value, speed) { var base = this; base.isCssFinish = false; base.$owlWrapper.stop(true, true).animate({ "left" : value }, { duration : speed || base.options.slideSpeed, complete : function () { base.isCssFinish = true; } }); }, checkBrowser : function () { var base = this, translate3D = "translate3d(0px, 0px, 0px)", tempElem = document.createElement("div"), regex, asSupport, support3d, isTouch; tempElem.style.cssText = " -moz-transform:" + translate3D + "; -ms-transform:" + translate3D + "; -o-transform:" + translate3D + "; -webkit-transform:" + translate3D + "; transform:" + translate3D; regex = /translate3d\(0px, 0px, 0px\)/g; asSupport = tempElem.style.cssText.match(regex); support3d = (asSupport !== null && asSupport.length === 1); isTouch = "ontouchstart" in window || window.navigator.msMaxTouchPoints; base.browser = { "support3d" : support3d, "isTouch" : isTouch }; }, moveEvents : function () { var base = this; if (base.options.mouseDrag !== false || base.options.touchDrag !== false) { base.gestures(); base.disabledEvents(); } }, eventTypes : function () { var base = this, types = ["s", "e", "x"]; base.ev_types = {}; if (base.options.mouseDrag === true && base.options.touchDrag === true) { types = [ "touchstart.owl mousedown.owl", "touchmove.owl mousemove.owl", "touchend.owl touchcancel.owl mouseup.owl" ]; } else if (base.options.mouseDrag === false && base.options.touchDrag === true) { types = [ "touchstart.owl", "touchmove.owl", "touchend.owl touchcancel.owl" ]; } else if (base.options.mouseDrag === true && base.options.touchDrag === false) { types = [ "mousedown.owl", "mousemove.owl", "mouseup.owl" ]; } base.ev_types.start = types[0]; base.ev_types.move = types[1]; base.ev_types.end = types[2]; }, disabledEvents : function () { var base = this; base.$elem.on("dragstart.owl", function (event) { event.preventDefault(); }); base.$elem.on("mousedown.disableTextSelect", function (e) { return jQuery(e.target).is('input, textarea, select, option'); }); }, gestures : function () { /*jslint unparam: true*/ var base = this, locals = { offsetX : 0, offsetY : 0, baseElWidth : 0, relativePos : 0, position: null, minSwipe : null, maxSwipe: null, sliding : null, dargging: null, targetElement : null }; base.isCssFinish = true; function getTouches(event) { if (event.touches !== undefined) { return { x : event.touches[0].pageX, y : event.touches[0].pageY }; } if (event.touches === undefined) { if (event.pageX !== undefined) { return { x : event.pageX, y : event.pageY }; } if (event.pageX === undefined) { return { x : event.clientX, y : event.clientY }; } } } function swapEvents(type) { if (type === "on") { jQuery(document).on(base.ev_types.move, dragMove); jQuery(document).on(base.ev_types.end, dragEnd); } else if (type === "off") { jQuery(document).off(base.ev_types.move); jQuery(document).off(base.ev_types.end); } } function dragStart(event) { var ev = event.originalEvent || event || window.event, position; if (ev.which === 3) { return false; } if (base.itemsAmount <= base.options.items) { return; } if (base.isCssFinish === false && !base.options.dragBeforeAnimFinish) { return false; } if (base.isCss3Finish === false && !base.options.dragBeforeAnimFinish) { return false; } if (base.options.autoPlay !== false) { window.clearInterval(base.autoPlayInterval); } if (base.browser.isTouch !== true && !base.$owlWrapper.hasClass("grabbing")) { base.$owlWrapper.addClass("grabbing"); } base.newPosX = 0; base.newRelativeX = 0; jQuery(this).css(base.removeTransition()); position = jQuery(this).position(); locals.relativePos = position.left; locals.offsetX = getTouches(ev).x - position.left; locals.offsetY = getTouches(ev).y - position.top; swapEvents("on"); locals.sliding = false; locals.targetElement = ev.target || ev.srcElement; } function dragMove(event) { var ev = event.originalEvent || event || window.event, minSwipe, maxSwipe; base.newPosX = getTouches(ev).x - locals.offsetX; base.newPosY = getTouches(ev).y - locals.offsetY; base.newRelativeX = base.newPosX - locals.relativePos; if (typeof base.options.startDragging === "function" && locals.dragging !== true && base.newRelativeX !== 0) { locals.dragging = true; base.options.startDragging.apply(base, [base.$elem]); } if ((base.newRelativeX > 8 || base.newRelativeX < -8) && (base.browser.isTouch === true)) { if (ev.preventDefault !== undefined) { ev.preventDefault(); } else { ev.returnValue = false; } locals.sliding = true; } if ((base.newPosY > 10 || base.newPosY < -10) && locals.sliding === false) { jQuery(document).off("touchmove.owl"); } minSwipe = function () { return base.newRelativeX / 5; }; maxSwipe = function () { return base.maximumPixels + base.newRelativeX / 5; }; base.newPosX = Math.max(Math.min(base.newPosX, minSwipe()), maxSwipe()); if (base.browser.support3d === true) { base.transition3d(base.newPosX); } else { base.css2move(base.newPosX); } } function dragEnd(event) { var ev = event.originalEvent || event || window.event, newPosition, handlers, owlStopEvent; ev.target = ev.target || ev.srcElement; locals.dragging = false; if (base.browser.isTouch !== true) { base.$owlWrapper.removeClass("grabbing"); } if (base.newRelativeX < 0) { base.dragDirection = base.owl.dragDirection = "left"; } else { base.dragDirection = base.owl.dragDirection = "right"; } if (base.newRelativeX !== 0) { newPosition = base.getNewPosition(); base.goTo(newPosition, false, "drag"); if (locals.targetElement === ev.target && base.browser.isTouch !== true) { jQuery(ev.target).on("click.disable", function (ev) { ev.stopImmediatePropagation(); ev.stopPropagation(); ev.preventDefault(); jQuery(ev.target).off("click.disable"); }); handlers = $._data(ev.target, "events").click; owlStopEvent = handlers.pop(); handlers.splice(0, 0, owlStopEvent); } } swapEvents("off"); } base.$elem.on(base.ev_types.start, ".owl-wrapper", dragStart); }, getNewPosition : function () { var base = this, newPosition = base.closestItem(); if (newPosition > base.maximumItem) { base.currentItem = base.maximumItem; newPosition = base.maximumItem; } else if (base.newPosX >= 0) { newPosition = 0; base.currentItem = 0; } return newPosition; }, closestItem : function () { var base = this, array = base.options.scrollPerPage === true ? base.pagesInArray : base.positionsInArray, goal = base.newPosX, closest = null; $.each(array, function (i, v) { if (goal - (base.itemWidth / 20) > array[i + 1] && goal - (base.itemWidth / 20) < v && base.moveDirection() === "left") { closest = v; if (base.options.scrollPerPage === true) { base.currentItem = $.inArray(closest, base.positionsInArray); } else { base.currentItem = i; } } else if (goal + (base.itemWidth / 20) < v && goal + (base.itemWidth / 20) > (array[i + 1] || array[i] - base.itemWidth) && base.moveDirection() === "right") { if (base.options.scrollPerPage === true) { closest = array[i + 1] || array[array.length - 1]; base.currentItem = $.inArray(closest, base.positionsInArray); } else { closest = array[i + 1]; base.currentItem = i + 1; } } }); return base.currentItem; }, moveDirection : function () { var base = this, direction; if (base.newRelativeX < 0) { direction = "right"; base.playDirection = "next"; } else { direction = "left"; base.playDirection = "prev"; } return direction; }, customEvents : function () { /*jslint unparam: true*/ var base = this; base.$elem.on("owl.next", function () { base.next(); }); base.$elem.on("owl.prev", function () { base.prev(); }); base.$elem.on("owl.play", function (event, speed) { base.options.autoPlay = speed; base.play(); base.hoverStatus = "play"; }); base.$elem.on("owl.stop", function () { base.stop(); base.hoverStatus = "stop"; }); base.$elem.on("owl.goTo", function (event, item) { base.goTo(item); }); base.$elem.on("owl.jumpTo", function (event, item) { base.jumpTo(item); }); }, stopOnHover : function () { var base = this; if (base.options.stopOnHover === true && base.browser.isTouch !== true && base.options.autoPlay !== false) { base.$elem.on("mouseover", function () { base.stop(); }); base.$elem.on("mouseout", function () { if (base.hoverStatus !== "stop") { base.play(); } }); } }, lazyLoad : function () { var base = this, i, $item, itemNumber, $lazyImg, follow; if (base.options.lazyLoad === false) { return false; } for (i = 0; i < base.itemsAmount; i += 1) { $item = jQuery(base.$owlItems[i]); if ($item.data("owl-loaded") === "loaded") { continue; } itemNumber = $item.data("owl-item"); $lazyImg = $item.find(".lazyOwl"); if (typeof $lazyImg.data("src") !== "string") { $item.data("owl-loaded", "loaded"); continue; } if ($item.data("owl-loaded") === undefined) { $lazyImg.hide(); $item.addClass("loading").data("owl-loaded", "checked"); } if (base.options.lazyFollow === true) { follow = itemNumber >= base.currentItem; } else { follow = true; } if (follow && itemNumber < base.currentItem + base.options.items && $lazyImg.length) { base.lazyPreload($item, $lazyImg); } } }, lazyPreload : function ($item, $lazyImg) { var base = this, iterations = 0, isBackgroundImg; if ($lazyImg.prop("tagName") === "DIV") { $lazyImg.css("background-image", "url(" + $lazyImg.data("src") + ")"); isBackgroundImg = true; } else { $lazyImg[0].src = $lazyImg.data("src"); } function showImage() { $item.data("owl-loaded", "loaded").removeClass("loading"); $lazyImg.removeAttr("data-src"); if (base.options.lazyEffect === "fade") { $lazyImg.fadeIn(400); } else { $lazyImg.show(); } if (typeof base.options.afterLazyLoad === "function") { base.options.afterLazyLoad.apply(this, [base.$elem]); } } function checkLazyImage() { iterations += 1; if (base.completeImg($lazyImg.get(0)) || isBackgroundImg === true) { showImage(); } else if (iterations <= 100) {//if image loads in less than 10 seconds window.setTimeout(checkLazyImage, 100); } else { showImage(); } } checkLazyImage(); }, autoHeight : function () { var base = this, $currentimg = jQuery(base.$owlItems[base.currentItem]).find("img"), iterations; function addHeight() { var $currentItem = jQuery(base.$owlItems[base.currentItem]).height(); base.wrapperOuter.css("height", $currentItem + "px"); if (!base.wrapperOuter.hasClass("autoHeight")) { window.setTimeout(function () { base.wrapperOuter.addClass("autoHeight"); }, 0); } } function checkImage() { iterations += 1; if (base.completeImg($currentimg.get(0))) { addHeight(); } else if (iterations <= 100) { //if image loads in less than 10 seconds window.setTimeout(checkImage, 100); } else { base.wrapperOuter.css("height", ""); //Else remove height attribute } } if ($currentimg.get(0) !== undefined) { iterations = 0; checkImage(); } else { addHeight(); } }, completeImg : function (img) { var naturalWidthType; if (!img.complete) { return false; } naturalWidthType = typeof img.naturalWidth; if (naturalWidthType !== "undefined" && img.naturalWidth === 0) { return false; } return true; }, onVisibleItems : function () { var base = this, i; if (base.options.addClassActive === true) { base.$owlItems.removeClass("active"); } base.visibleItems = []; for (i = base.currentItem; i < base.currentItem + base.options.items; i += 1) { base.visibleItems.push(i); if (base.options.addClassActive === true) { jQuery(base.$owlItems[i]).addClass("active"); } } base.owl.visibleItems = base.visibleItems; }, transitionTypes : function (className) { var base = this; //Currently available: "fade", "backSlide", "goDown", "fadeUp" base.outClass = "owl-" + className + "-out"; base.inClass = "owl-" + className + "-in"; }, singleItemTransition : function () { var base = this, outClass = base.outClass, inClass = base.inClass, $currentItem = base.$owlItems.eq(base.currentItem), $prevItem = base.$owlItems.eq(base.prevItem), prevPos = Math.abs(base.positionsInArray[base.currentItem]) + base.positionsInArray[base.prevItem], origin = Math.abs(base.positionsInArray[base.currentItem]) + base.itemWidth / 2, animEnd = 'webkitAnimationEnd oAnimationEnd MSAnimationEnd animationend'; base.isTransition = true; base.$owlWrapper .addClass('owl-origin') .css({ "-webkit-transform-origin" : origin + "px", "-moz-perspective-origin" : origin + "px", "perspective-origin" : origin + "px" }); function transStyles(prevPos) { return { "position" : "relative", "left" : prevPos + "px" }; } $prevItem .css(transStyles(prevPos, 10)) .addClass(outClass) .on(animEnd, function () { base.endPrev = true; $prevItem.off(animEnd); base.clearTransStyle($prevItem, outClass); }); $currentItem .addClass(inClass) .on(animEnd, function () { base.endCurrent = true; $currentItem.off(animEnd); base.clearTransStyle($currentItem, inClass); }); }, clearTransStyle : function (item, classToRemove) { var base = this; item.css({ "position" : "", "left" : "" }).removeClass(classToRemove); if (base.endPrev && base.endCurrent) { base.$owlWrapper.removeClass('owl-origin'); base.endPrev = false; base.endCurrent = false; base.isTransition = false; } }, owlStatus : function () { var base = this; base.owl = { "userOptions" : base.userOptions, "baseElement" : base.$elem, "userItems" : base.$userItems, "owlItems" : base.$owlItems, "currentItem" : base.currentItem, "prevItem" : base.prevItem, "visibleItems" : base.visibleItems, "isTouch" : base.browser.isTouch, "browser" : base.browser, "dragDirection" : base.dragDirection }; }, clearEvents : function () { var base = this; base.$elem.off(".owl owl mousedown.disableTextSelect"); jQuery(document).off(".owl owl"); jQuery(window).off("resize", base.resizer); }, unWrap : function () { var base = this; if (base.$elem.children().length !== 0) { base.$owlWrapper.unwrap(); base.$userItems.unwrap().unwrap(); if (base.owlControls) { base.owlControls.remove(); } } base.clearEvents(); base.$elem .attr("style", base.$elem.data("owl-originalStyles") || "") .attr("class", base.$elem.data("owl-originalClasses")); }, destroy : function () { var base = this; base.stop(); window.clearInterval(base.checkVisible); base.unWrap(); base.$elem.removeData(); }, reinit : function (newOptions) { var base = this, options = $.extend({}, base.userOptions, newOptions); base.unWrap(); base.init(options, base.$elem); }, addItem : function (htmlString, targetPosition) { var base = this, position; if (!htmlString) {return false; } if (base.$elem.children().length === 0) { base.$elem.append(htmlString); base.setVars(); return false; } base.unWrap(); if (targetPosition === undefined || targetPosition === -1) { position = -1; } else { position = targetPosition; } if (position >= base.$userItems.length || position === -1) { base.$userItems.eq(-1).after(htmlString); } else { base.$userItems.eq(position).before(htmlString); } base.setVars(); }, removeItem : function (targetPosition) { var base = this, position; if (base.$elem.children().length === 0) { return false; } if (targetPosition === undefined || targetPosition === -1) { position = -1; } else { position = targetPosition; } base.unWrap(); base.$userItems.eq(position).remove(); base.setVars(); } }; $.fn.owlCarousel = function (options) { return this.each(function () { if (jQuery(this).data("owl-init") === true) { return false; } jQuery(this).data("owl-init", true); var carousel = Object.create(Carousel); carousel.init(options, this); $.data(this, "owlCarousel", carousel); }); }; $.fn.owlCarousel.options = { items : 5, itemsCustom : false, itemsDesktop : [1199, 4], itemsDesktopSmall : [979, 3], itemsTablet : [768, 2], itemsTabletSmall : false, itemsMobile : [479, 1], singleItem : false, itemsScaleUp : false, slideSpeed : 200, paginationSpeed : 800, rewindSpeed : 1000, autoPlay : false, stopOnHover : false, navigation : false, navigationText : ["prev", "next"], rewindNav : true, scrollPerPage : false, pagination : true, paginationNumbers : false, responsive : true, responsiveRefreshRate : 200, responsiveBaseWidth : window, baseClass : "owl-carousel", theme : "owl-theme", lazyLoad : false, lazyFollow : true, lazyEffect : "fade", autoHeight : false, jsonPath : false, jsonSuccess : false, dragBeforeAnimFinish : true, mouseDrag : true, touchDrag : true, addClassActive : false, transitionStyle : false, beforeUpdate : false, afterUpdate : false, beforeInit : false, afterInit : false, beforeMove : false, afterMove : false, afterAction : false, startDragging : false, afterLazyLoad: false }; }(jQuery, window, document)); /** * Verwendung in DocumentType 'Bildergalerie' Template 'Galeria_Uebersicht' * * @requires dkbModalOverlay * @requires handleCarouselResize * @requires showOwlCarousel * @requires picturefill */ function showGallery (url, counter) { jQuery.get(url, function (data) { var container_outer = document.createElement('div'); container_outer.setAttribute("id", 'modalDivContainer_outer'); container_outer.setAttribute("style", 'display: none;'); var container_inner = document.createElement('div'); container_inner.setAttribute("id", 'modalDivContainer'); container_outer.appendChild(container_inner); document.body.appendChild(container_outer); var containerObj = jQuery('#modalDivContainer'); containerObj.html(data); var modalOverlay = dkbModalOverlay('modalDivContainer'); var $overlay = jQuery(modalOverlay.containerEl); $overlay.addClass('owlDialog'); var maxWidth = '540'; handleCarouselResize(jQuery('.owlDialog'), maxWidth, false); containerObj.find('.no_owl').removeClass('no_owl'); showOwlCarousel(containerObj); jQuery(window).resize(function () { handleCarouselResize(jQuery('.owlDialog'), maxWidth, false); }); window.setTimeout(function () { jQuery(".owl-carousel").data("owlCarousel").reload(); //recalculate owl - muss zeitversetzt werden - da sonst layout bug bei ca 320px width }, 100); picturefill(); jQuery(".owl-carousel").data("owlCarousel").jumpTo(counter); }); } /** * wird aus dem CMS aufgerufen. Unter anderem: * root / Inhalt / banking / Zahlungsverkehr / FotoUeberweisung / Neu_hier * * @requires dkbModalOverlay * @requires handleCarouselResize * @requires showOwlCarousel */ function showCarouselInDialog(containerId, maxWidth) { var $existingDialog = jQuery('#' + containerId + '_owlDialog'); if ($existingDialog.length > 0 ) { $existingDialog.remove(); } var $container = jQuery('#' + containerId); $container.wrap('<div id="' + containerId +'_parent" ></div>'); $container.removeClass('hidden'); var modalOverlay = dkbModalOverlay(containerId); var $overlay = jQuery(modalOverlay.containerEl); $overlay.addClass('owlDialog'); $overlay.prop('id', containerId + '_owlDialog'); handleCarouselResize(jQuery('.owlDialog'), maxWidth, false); $container.find('.no_owl').removeClass('no_owl'); showOwlCarousel($container); jQuery(window).resize(function () { handleCarouselResize(jQuery('.owlDialog'), maxWidth, false); }); jQuery('#' + containerId + '_parent').css('display', 'none'); //man weiss leider nicht, wann das carousel fertig initialisiert ist, daher 3 calls um flackern zu reduzieren window.setTimeout(function () {jQuery(".owl-carousel").data("owlCarousel").reload();}, 100); window.setTimeout(function () {jQuery(".owl-carousel").data("owlCarousel").reload();}, 300); window.setTimeout(function () {jQuery(".owl-carousel").data("owlCarousel").reload();}, 600); } /** * Hilftsfunktion f�r OwlCarousel-Zeug * * @see showCarouselInDialog * @see showGallery */ function handleCarouselResize($overlay, maxWidth, ignoreHasViewPortChanged) { if (jQuery(window).outerWidth() * 0.9 > maxWidth) { $overlay.find('.overlayPlayerContent').css('width', maxWidth + 'px'); $overlay.addClass('DialogFixedWidth'); } else if ($overlay.hasClass('DialogFixedWidth')) { $overlay.removeClass('DialogFixedWidth'); $overlay.find('.overlayPlayerContent').css('width',''); } } /** * Hilfsfunktion f�r OwlCarousel-Zeug * * @requires owlCarousel * @see showCarouselInDialog * @see showGallery */ function showOwlCarousel($owlParent) { if(typeof jQuery.fn.owlCarousel !== 'undefined') { var $carousel = $owlParent.find(".always_display.owl-carousel"); if ($carousel.closest('.no_owl').length == 0) { var slidingActivated = true; if ($owlParent.find('.owlitem').length == 1) { slidingActivated = false; } //Converted owl Slides to Owl $carousel.owlCarousel({ navigation: true, // Show next and prev buttons slideSpeed: 300, paginationSpeed: 400, singleItem: true, addClassActive: true, rewindNav: true, touchDrag: slidingActivated, mouseDrag: slidingActivated }); } } }; /* * jQuery mmenu v5.0.4 * @requires jQuery 1.7.0 or later * * mmenu.frebsite.nl * * Copyright (c) Fred Heusschen * www.frebsite.nl * * Licensed under the MIT license: * http://en.wikipedia.org/wiki/MIT_License */ !function (t) { function n() { t[s].glbl || (d = {$wndw: t(window), $html: t("html"), $body: t("body")}, a = {}, l = {}, r = {}, t.each([a, l, r], function (e, t) { t.add = function (e) { e = e.split(" "); for (var n in e)t[e[n]] = t.mm(e[n]) } }), a.mm = function (e) { return"mm-" + e }, a.add("wrapper menu vertical panel nopanel current highest opened subopened header hasheader title btn prev next first last listview nolistview selected divider spacer hidden fullsubopen"), a.umm = function (e) { return"mm-" == e.slice(0, 3) && (e = e.slice(3)), e }, l.mm = function (e) { return"mm-" + e }, l.add("parent sub"), r.mm = function (e) { return e + ".mm" }, r.add("transitionend webkitTransitionEnd mousedown mouseup touchstart touchmove touchend click keydown"), t[s]._c = a, t[s]._d = l, t[s]._e = r, t[s].glbl = d) } var s = "mmenu", i = "5.0.4"; if (!t[s]) { t[s] = function (e, t, n) { this.$menu = e, this._api = ["bind", "init", "update", "setSelected", "getInstance", "openPanel", "closePanel", "closeAllPanels"], this.opts = t, this.conf = n, this.vars = {}, this.cbck = {}, "function" == typeof this.___deprecated && this.___deprecated(), this._initMenu(), this._initAnchors(); var s = this.$menu.children(this.conf.panelNodetype); return this._initAddons(), this.init(s), "function" == typeof this.___debug && this.___debug(), this }, t[s].version = i, t[s].addons = {}, t[s].uniqueId = 0, t[s].defaults = {extensions: [], onClick: {setSelected: !0}, slidingSubmenus: !0}, t[s].configuration = {classNames: {panel: "Panel", vertical: "Vertical", selected: "Selected", divider: "Divider", spacer: "Spacer"}, clone: !1, openingInterval: 25, panelNodetype: "ul, ol, div", transitionDuration: 400}, t[s].prototype = {init: function (e) { e = e.not("." + a.nopanel), e = this._initPanels(e), this.trigger("init", e), this.trigger("update") }, update: function () { this.trigger("update") }, setSelected: function (e) { this.$menu.find("." + a.listview).children().removeClass(a.selected), e.addClass(a.selected), this.trigger("setSelected", e) }, openPanel: function (e) { var n = e.parent(); if (n.hasClass(a.vertical)) { var s = n.parents("." + a.subopened); if (s.length)return this.openPanel(s.first()); n.addClass(a.opened) } else { if (e.hasClass(a.current))return; var i = t(this.$menu).children("." + a.panel), l = i.filter("." + a.current); i.removeClass(a.highest).removeClass(a.current).not(e).not(l).not("." + a.vertical).addClass(a.hidden), e.hasClass(a.opened) ? l.addClass(a.highest).removeClass(a.opened).removeClass(a.subopened) : (e.addClass(a.highest), l.addClass(a.subopened)), e.removeClass(a.hidden).addClass(a.current), setTimeout(function () { e.removeClass(a.subopened).addClass(a.opened) }, this.conf.openingInterval) } this.trigger("openPanel", e) }, closePanel: function (e) { var t = e.parent(); t.hasClass(a.vertical) && (t.removeClass(a.opened), this.trigger("closePanel", e)) }, closeAllPanels: function () { this.$menu.find("." + a.listview).children().removeClass(a.selected).filter("." + a.vertical).removeClass(a.opened); var e = this.$menu.children("." + a.panel), t = e.first(); this.$menu.children("." + a.panel).not(t).removeClass(a.subopened).removeClass(a.opened).removeClass(a.current).removeClass(a.highest).addClass(a.hidden), this.openPanel(t) }, togglePanel: function (e) { var t = e.parent(); t.hasClass(a.vertical) && this[t.hasClass(a.opened) ? "closePanel" : "openPanel"](e) }, getInstance: function () { return this }, bind: function (e, t) { this.cbck[e] = this.cbck[e] || [], this.cbck[e].push(t) }, trigger: function () { var t = this, n = Array.prototype.slice.call(arguments), s = n.shift(); if (this.cbck[s])for (e in this.cbck[s])this.cbck[s][e].apply(t, n) }, _initMenu: function () { this.opts.offCanvas && this.conf.clone && (this.$menu = this.$menu.clone(!0), this.$menu.add(this.$menu.find("*")).filter("[id]").each(function () { t(this).attr("id", a.mm(t(this).attr("id"))) })), this.$menu.contents().each(function () { 3 == t(this)[0].nodeType && t(this).remove() }), this.$menu.parent().addClass(a.wrapper); var e = [a.menu]; this.opts.slidingSubmenus || e.push(a.vertical), this.opts.extensions = this.opts.extensions.length ? "mm-" + this.opts.extensions.join(" mm-") : "", this.opts.extensions && e.push(this.opts.extensions), this.$menu.addClass(e.join(" ")) }, _initPanels: function (e) { var n = this; this.__findAddBack(e, "ul, ol").not("." + a.nolistview).addClass(a.listview); var s = this.__findAddBack(e, "." + a.listview).children(); this.__refactorClass(s, this.conf.classNames.selected, "selected"), this.__refactorClass(s, this.conf.classNames.divider, "divider"), this.__refactorClass(s, this.conf.classNames.spacer, "spacer"), this.__refactorClass(this.__findAddBack(e, "." + this.conf.classNames.panel), this.conf.classNames.panel, "panel"); var i = t(), r = e.add(this.__findAddBack(e, "." + a.listview).children().children(this.conf.panelNodetype)).not("." + a.nopanel); this.__refactorClass(r, this.conf.classNames.vertical, "vertical"), this.opts.slidingSubmenus || r.addClass(a.vertical), r.each(function () { var e = t(this), s = e; e.is("ul, ol") ? (e.wrap('<div class="' + a.panel + '" />'), s = e.parent()) : s.addClass(a.panel); var l = e.attr("id"); e.removeAttr("id"), s.attr("id", l || n.__getUniqueId()), e.hasClass(a.vertical) && (e.removeClass(n.conf.classNames.vertical), s.add(s.parent()).addClass(a.vertical)), i = i.add(s); var r = s.children().first(), d = s.children().last(); r.is("." + a.listview) && r.addClass(a.first), d.is("." + a.listview) && d.addClass(a.last) }); var d = t("." + a.panel, this.$menu); i.each(function () { var e = t(this), n = e.parent(), s = n.children("a, span"); if (!n.is("." + a.menu) && !e.data(l.parent)) { if (n.data(l.sub, e), e.data(l.parent, n), n.parent().is("." + a.listview)) { var i = e.attr("id"), r = t('<a class="' + a.next + '" href="#' + i + '" data-target="#' + i + '" />').insertBefore(s); s.is("a") || r.addClass(a.fullsubopen) } if (!n.hasClass(a.vertical)) { var d = n.closest("." + a.panel); if (d.length) { var i = d.attr("id"); e.prepend('<div class="' + a.header + '"><a class="' + a.btn + " " + a.prev + '" href="#' + i + '" data-target="#' + i + '"></a><a class="' + a.title + '">' + s.text() + "</a></div>"), e.addClass(a.hasheader) } } } }); var o = this.__findAddBack(e, "." + a.listview).children("." + a.selected).removeClass(a.selected).last().addClass(a.selected); o.add(o.parentsUntil("." + a.menu, "li")).filter("." + a.vertical).addClass(a.opened).end().not("." + a.vertical).each(function () { t(this).parentsUntil("." + a.menu, "." + a.panel).not("." + a.vertical).first().addClass(a.opened).parentsUntil("." + a.menu, "." + a.panel).not("." + a.vertical).first().addClass(a.opened).addClass(a.subopened) }), o.children("." + a.panel).not("." + a.vertical).addClass(a.opened).parentsUntil("." + a.menu, "." + a.panel).not("." + a.vertical).first().addClass(a.opened).addClass(a.subopened); var c = d.filter("." + a.opened); return c.length || (c = i.first()), c.addClass(a.opened).last().addClass(a.current), i.not("." + a.vertical).not(c.last()).addClass(a.hidden).end().appendTo(this.$menu), i }, _initAnchors: function () { var e = this; d.$body.on(r.click + "-oncanvas", "a[href]", function (n) { var i = t(this), l = !1, r = e.$menu.find(i).length; for (var o in t[s].addons)if (l = t[s].addons[o].clickAnchor.call(e, i, r))break; if (!l && r) { var c = i.attr("href"); if (c.length > 1 && "#" == c.slice(0, 1)) { var h = t(c, e.$menu); h.is("." + a.panel) && (l = !0, e[i.parent().hasClass(a.vertical) ? "togglePanel" : "openPanel"](h)) } } if (l && n.preventDefault(), !l && r && i.is("." + a.listview + " > li > a") && !i.is('[rel="external"]') && !i.is('[target="_blank"]')) { e.__valueOrFn(e.opts.onClick.setSelected, i) && e.setSelected(t(n.target).parent()); var u = e.__valueOrFn(e.opts.onClick.preventDefault, i, "#" == c.slice(0, 1)); u && n.preventDefault(), e.__valueOrFn(e.opts.onClick.blockUI, i, !u) && d.$html.addClass(a.blocking), e.__valueOrFn(e.opts.onClick.close, i, u) && e.close() } }) }, _initAddons: function () { for (var e in t[s].addons)t[s].addons[e].add.call(this), t[s].addons[e].add = function () { }; for (var e in t[s].addons)t[s].addons[e].setup.call(this) }, __api: function () { var e = this, n = {}; return t.each(this._api, function () { var t = this; n[t] = function () { var s = e[t].apply(e, arguments); return"undefined" == typeof s ? n : s } }), n }, __valueOrFn: function (e, t, n) { return"function" == typeof e ? e.call(t[0]) : "undefined" == typeof e && "undefined" != typeof n ? n : e }, __refactorClass: function (e, t, n) { return e.filter("." + t).removeClass(t).addClass(a[n]) }, __findAddBack: function (e, t) { return e.find(t).add(e.filter(t)) }, __filterListItems: function (e) { return e.not("." + a.divider).not("." + a.hidden) }, __transitionend: function (e, t, n) { var s = !1, i = function () { s || t.call(e[0]), s = !0 }; e.one(r.transitionend, i), e.one(r.webkitTransitionEnd, i), setTimeout(i, 1.1 * n) }, __getUniqueId: function () { return a.mm(t[s].uniqueId++) }}, t.fn[s] = function (e, i) { return n(), e = t.extend(!0, {}, t[s].defaults, e), i = t.extend(!0, {}, t[s].configuration, i), this.each(function () { var n = t(this); if (!n.data(s)) { var a = new t[s](n, e, i); n.data(s, a.__api()) } }) }, t[s].support = {touch: "ontouchstart"in window || navigator.msMaxTouchPoints}; var a, l, r, d } }(jQuery); /* * jQuery mmenu offCanvas addon * mmenu.frebsite.nl * * Copyright (c) Fred Heusschen */ !function (e) { var t = "mmenu", o = "offCanvas"; e[t].addons[o] = {setup: function () { if (this.opts[o]) { var n = this.opts[o], i = this.conf[o]; a = e[t].glbl, this._api = e.merge(this._api, ["open", "close", "setPage"]), ("top" == n.position || "bottom" == n.position) && (n.zposition = "front"), "string" != typeof i.pageSelector && (i.pageSelector = "> " + i.pageNodetype), a.$allMenus = (a.$allMenus || e()).add(this.$menu), this.vars.opened = !1; var r = [s.offcanvas]; "left" != n.position && r.push(s.mm(n.position)), "back" != n.zposition && r.push(s.mm(n.zposition)), this.$menu.addClass(r.join(" ")).parent().removeClass(s.wrapper), this.setPage(a.$page), this._initBlocker(), this["_initWindow_" + o](), this.$menu[i.menuInjectMethod + "To"](i.menuWrapperSelector) } }, add: function () { s = e[t]._c, n = e[t]._d, i = e[t]._e, s.add("offcanvas slideout modal background opening blocker page"), n.add("style"), i.add("resize") }, clickAnchor: function (e) { if (!this.opts[o])return!1; var t = this.$menu.attr("id"); if (t && t.length && (this.conf.clone && (t = s.umm(t)), e.is('[href="#' + t + '"]')))return this.open(), !0; if (a.$page) { var t = a.$page.attr("id"); return t && t.length && e.is('[href="#' + t + '"]') ? (this.close(), !0) : !1 } }}, e[t].defaults[o] = {position: "left", zposition: "back", modal: !1, moveBackground: !0}, e[t].configuration[o] = {pageNodetype: "div", pageSelector: null, menuWrapperSelector: "body", menuInjectMethod: "prepend"}, e[t].prototype.open = function () { if (!this.vars.opened) { var e = this; this._openSetup(), setTimeout(function () { e._openFinish() }, this.conf.openingInterval), this.trigger("open") } }, e[t].prototype._openSetup = function () { var e = this; this.closeAllOthers(), a.$page.data(n.style, a.$page.attr("style") || ""), a.$wndw.trigger(i.resize + "-offcanvas", [!0]); var t = [s.opened]; this.opts[o].modal && t.push(s.modal), this.opts[o].moveBackground && t.push(s.background), "left" != this.opts[o].position && t.push(s.mm(this.opts[o].position)), "back" != this.opts[o].zposition && t.push(s.mm(this.opts[o].zposition)), this.opts.extensions && t.push(this.opts.extensions), a.$html.addClass(t.join(" ")), setTimeout(function () { e.vars.opened = !0 }, this.conf.openingInterval), this.$menu.addClass(s.current + " " + s.opened) }, e[t].prototype._openFinish = function () { var e = this; this.__transitionend(a.$page, function () { e.trigger("opened") }, this.conf.transitionDuration), a.$html.addClass(s.opening), this.trigger("opening") }, e[t].prototype.close = function () { if (this.vars.opened) { var e = this; this.__transitionend(a.$page, function () { e.$menu.removeClass(s.current).removeClass(s.opened), a.$html.removeClass(s.opened).removeClass(s.modal).removeClass(s.background).removeClass(s.mm(e.opts[o].position)).removeClass(s.mm(e.opts[o].zposition)), e.opts.extensions && a.$html.removeClass(e.opts.extensions), a.$page.attr("style", a.$page.data(n.style)), e.vars.opened = !1, e.trigger("closed") }, this.conf.transitionDuration), a.$html.removeClass(s.opening), this.trigger("close"), this.trigger("closing") } }, e[t].prototype.closeAllOthers = function () { a.$allMenus.not(this.$menu).each(function () { var o = e(this).data(t); o && o.close && o.close() }) }, e[t].prototype.setPage = function (t) { t && t.length || (t = e(this.conf[o].pageSelector, a.$body), t.length > 1 && (t = t.wrapAll("<" + this.conf[o].pageNodetype + " />").parent())), t.attr("id", t.attr("id") || this.__getUniqueId()), t.addClass(s.page + " " + s.slideout), a.$page = t, this.trigger("setPage", t) }, e[t].prototype["_initWindow_" + o] = function () { a.$wndw.off(i.keydown + "-offcanvas").on(i.keydown + "-offcanvas", function (e) { return a.$html.hasClass(s.opened) && 9 == e.keyCode ? (e.preventDefault(), !1) : void 0 }); var e = 0; a.$wndw.off(i.resize + "-offcanvas").on(i.resize + "-offcanvas", function (t, o) { if (o || a.$html.hasClass(s.opened)) { var n = a.$wndw.height(); (o || n != e) && (e = n, a.$page.css("minHeight", n)) } }) }, e[t].prototype._initBlocker = function () { var t = this; a.$blck || (a.$blck = e('<div id="' + s.blocker + '" class="' + s.slideout + '" />')), a.$blck.appendTo(a.$body).off(i.touchstart + "-offcanvas " + i.touchmove + "-offcanvas").on(i.touchstart + "-offcanvas " + i.touchmove + "-offcanvas", function (e) { e.preventDefault(), e.stopPropagation(), a.$blck.trigger(i.mousedown + "-offcanvas") }).off(i.mousedown + "-offcanvas").on(i.mousedown + "-offcanvas", function (e) { e.preventDefault(), a.$html.hasClass(s.modal) || (t.closeAllOthers(), t.close()) }) }; var s, n, i, a }(jQuery); /* * jQuery mmenu autoHeight addon * mmenu.frebsite.nl * * Copyright (c) Fred Heusschen */ !function (t) { var e = "mmenu", i = "autoHeight"; t[e].addons[i] = {setup: function () { if (this.opts.offCanvas) { switch (this.opts.offCanvas.position) { case"left": case"right": return } var n = this, o = this.opts[i]; if (this.conf[i], h = t[e].glbl, "boolean" == typeof o && o && (o = {height: "auto"}), "object" != typeof o && (o = {}), o = this.opts[i] = t.extend(!0, {}, t[e].defaults[i], o), "auto" == o.height) { this.$menu.addClass(s.autoheight); var u = function (t) { var e = this.$menu.children("." + s.current); _top = parseInt(e.css("top"), 10) || 0, _bot = parseInt(e.css("bottom"), 10) || 0, this.$menu.addClass(s.measureheight), t = t || this.$menu.children("." + s.current), t.is("." + s.vertical) && (t = t.parents("." + s.panel).not("." + s.vertical).first()), this.$menu.height(t.outerHeight() + _top + _bot).removeClass(s.measureheight) }; this.bind("update", u), this.bind("openPanel", u), this.bind("closePanel", u), this.bind("open", u), h.$wndw.off(a.resize + "-autoheight").on(a.resize + "-autoheight", function () { u.call(n) }) } } }, add: function () { s = t[e]._c, n = t[e]._d, a = t[e]._e, s.add("autoheight measureheight"), a.add("resize") }, clickAnchor: function () { }}, t[e].defaults[i] = {height: "default"}; var s, n, a, h }(jQuery); /* * jQuery mmenu backButton addon * mmenu.frebsite.nl * * Copyright (c) Fred Heusschen */ !function (o) { var t = "mmenu", n = "backButton"; o[t].addons[n] = {setup: function () { if (this.opts.offCanvas) { var i = this, e = this.opts[n]; if (this.conf[n], a = o[t].glbl, "boolean" == typeof e && (e = {close: e}), "object" != typeof e && (e = {}), e = o.extend(!0, {}, o[t].defaults[n], e), e.close) { var c = "#" + i.$menu.attr("id"); this.bind("opened", function () { location.hash != c && history.pushState(null, document.title, c) }), o(window).on("popstate", function (o) { a.$html.hasClass(s.opened) ? (o.stopPropagation(), i.close()) : location.hash == c && (o.stopPropagation(), i.open()) }) } } }, add: function () { return window.history && window.history.pushState ? (s = o[t]._c, i = o[t]._d, e = o[t]._e, void 0) : (o[t].addons[n].setup = function () { }, void 0) }, clickAnchor: function () { }}, o[t].defaults[n] = {close: !1}; var s, i, e, a }(jQuery); /* * jQuery mmenu buttonbars addon * mmenu.frebsite.nl * * Copyright (c) Fred Heusschen */ !function (t) { var n = "mmenu", i = "buttonbars"; t[n].addons[i] = {setup: function () { this.opts[i], this.conf[i], s = t[n].glbl, this.bind("init", function (n) { this.__refactorClass(t("div", n), this.conf.classNames[i].buttonbar, "buttonbar"), t("." + a.buttonbar, n).each(function () { var n = t(this), i = n.children().not("input"), o = n.children().filter("input"); n.addClass(a.buttonbar + "-" + i.length), o.each(function () { var n = t(this), a = i.filter('label[for="' + n.attr("id") + '"]'); a.length && n.insertBefore(a) }) }) }) }, add: function () { a = t[n]._c, o = t[n]._d, r = t[n]._e, a.add("buttonbar") }, clickAnchor: function () { }}, t[n].configuration.classNames[i] = {buttonbar: "Buttonbar"}; var a, o, r, s }(jQuery); /* * jQuery mmenu counters addon * mmenu.frebsite.nl * * Copyright (c) Fred Heusschen */ !function (t) { var n = "mmenu", e = "counters"; t[n].addons[e] = {setup: function () { var c = this, o = this.opts[e]; this.conf[e], s = t[n].glbl, "boolean" == typeof o && (o = {add: o, update: o}), "object" != typeof o && (o = {}), o = this.opts[e] = t.extend(!0, {}, t[n].defaults[e], o), this.bind("init", function (n) { this.__refactorClass(t("em", n), this.conf.classNames[e].counter, "counter") }), o.add && this.bind("init", function (n) { n.each(function () { var n = t(this).data(a.parent); n && (n.children("em." + i.counter).length || n.prepend(t('<em class="' + i.counter + '" />'))) }) }), o.update && this.bind("update", function () { this.$menu.find("." + i.panel).each(function () { var n = t(this), e = n.data(a.parent); if (e) { var s = e.children("em." + i.counter); s.length && (n = n.children("." + i.listview), n.length && s.html(c.__filterListItems(n.children()).length)) } }) }) }, add: function () { i = t[n]._c, a = t[n]._d, c = t[n]._e, i.add("counter search noresultsmsg") }, clickAnchor: function () { }}, t[n].defaults[e] = {add: !1, update: !1}, t[n].configuration.classNames[e] = {counter: "Counter"}; var i, a, c, s }(jQuery); /* * jQuery mmenu dividers addon * mmenu.frebsite.nl * * Copyright (c) Fred Heusschen */ !function (i) { var e = "mmenu", s = "dividers"; i[e].addons[s] = {setup: function () { var n = this, a = this.opts[s]; if (this.conf[s], l = i[e].glbl, "boolean" == typeof a && (a = {add: a, fixed: a}), "object" != typeof a && (a = {}), a = this.opts[s] = i.extend(!0, {}, i[e].defaults[s], a), this.bind("init", function () { this.__refactorClass(i("li", this.$menu), this.conf.classNames[s].collapsed, "collapsed") }), a.add && this.bind("init", function (e) { switch (a.addTo) { case"panels": var s = e; break; default: var s = i(a.addTo, this.$menu).filter("." + d.panel) } i("." + d.divider, s).remove(), s.find("." + d.listview).not("." + d.vertical).each(function () { var e = ""; n.__filterListItems(i(this).children()).each(function () { var s = i.trim(i(this).children("a, span").text()).slice(0, 1).toLowerCase(); s != e && s.length && (e = s, i('<li class="' + d.divider + '">' + s + "</li>").insertBefore(this)) }) }) }), a.collapse && this.bind("init", function (e) { i("." + d.divider, e).each(function () { var e = i(this), s = e.nextUntil("." + d.divider, "." + d.collapsed); s.length && (e.children("." + d.subopen).length || (e.wrapInner("<span />"), e.prepend('<a href="#" class="' + d.subopen + " " + d.fullsubopen + '" />'))) }) }), a.fixed) { var o = function (e) { e = e || this.$menu.children("." + d.current); var s = e.find("." + d.divider).not("." + d.hidden); if (s.length) { this.$menu.addClass(d.hasdividers); var n = e.scrollTop() || 0, t = ""; e.is(":visible") && e.find("." + d.divider).not("." + d.hidden).each(function () { i(this).position().top + n < n + 1 && (t = i(this).text()) }), this.$fixeddivider.text(t) } else this.$menu.removeClass(d.hasdividers) }; this.$fixeddivider = i('<ul class="' + d.listview + " " + d.fixeddivider + '"><li class="' + d.divider + '"></li></ul>').prependTo(this.$menu).children(), this.bind("openPanel", o), this.bind("init", function (e) { e.off(t.scroll + "-dividers " + t.touchmove + "-dividers").on(t.scroll + "-dividers " + t.touchmove + "-dividers", function () { o.call(n, i(this)) }) }) } }, add: function () { d = i[e]._c, n = i[e]._d, t = i[e]._e, d.add("collapsed uncollapsed fixeddivider hasdividers"), t.add("scroll") }, clickAnchor: function (i, e) { if (this.opts[s].collapse && e) { var n = i.parent(); if (n.is("." + d.divider)) { var t = n.nextUntil("." + d.divider, "." + d.collapsed); return n.toggleClass(d.opened), t[n.hasClass(d.opened) ? "addClass" : "removeClass"](d.uncollapsed), !0 } } return!1 }}, i[e].defaults[s] = {add: !1, addTo: "panels", fixed: !1, collapse: !1}, i[e].configuration.classNames[s] = {collapsed: "Collapsed"}; var d, n, t, l }(jQuery); /* * jQuery mmenu dragOpen addon * mmenu.frebsite.nl * * Copyright (c) Fred Heusschen */ !function (e) { function t(e, t, n) { return t > e && (e = t), e > n && (e = n), e } var n = "mmenu", o = "dragOpen"; e[n].addons[o] = {setup: function () { if (this.opts.offCanvas) { var i = this, a = this.opts[o], p = this.conf[o]; if (r = e[n].glbl, "boolean" == typeof a && (a = {open: a}), "object" != typeof a && (a = {}), a = this.opts[o] = e.extend(!0, {}, e[n].defaults[o], a), a.open) { var d, f, c, u, h, l = {}, m = 0, g = !1, v = !1, w = 0, _ = 0; switch (this.opts.offCanvas.position) { case"left": case"right": l.events = "panleft panright", l.typeLower = "x", l.typeUpper = "X", v = "width"; break; case"top": case"bottom": l.events = "panup pandown", l.typeLower = "y", l.typeUpper = "Y", v = "height" } switch (this.opts.offCanvas.position) { case"right": case"bottom": l.negative = !0, u = function (e) { e >= r.$wndw[v]() - a.maxStartPos && (m = 1) }; break; default: l.negative = !1, u = function (e) { e <= a.maxStartPos && (m = 1) } } switch (this.opts.offCanvas.position) { case"left": l.open_dir = "right", l.close_dir = "left"; break; case"right": l.open_dir = "left", l.close_dir = "right"; break; case"top": l.open_dir = "down", l.close_dir = "up"; break; case"bottom": l.open_dir = "up", l.close_dir = "down" } switch (this.opts.offCanvas.zposition) { case"front": h = function () { return this.$menu }; break; default: h = function () { return e("." + s.slideout) } } var b = this.__valueOrFn(a.pageNode, this.$menu, r.$page); "string" == typeof b && (b = e(b)); var y = new Hammer(b[0], a.vendors.hammer); y.on("panstart", function (e) { u(e.center[l.typeLower]), r.$slideOutNodes = h(), g = l.open_dir }).on(l.events + " panend", function (e) { m > 0 && e.preventDefault() }).on(l.events, function (e) { if (d = e["delta" + l.typeUpper], l.negative && (d = -d), d != w && (g = d >= w ? l.open_dir : l.close_dir), w = d, w > a.threshold && 1 == m) { if (r.$html.hasClass(s.opened))return; m = 2, i._openSetup(), i.trigger("opening"), r.$html.addClass(s.dragging), _ = t(r.$wndw[v]() * p[v].perc, p[v].min, p[v].max) } 2 == m && (f = t(w, 10, _) - ("front" == i.opts.offCanvas.zposition ? _ : 0), l.negative && (f = -f), c = "translate" + l.typeUpper + "(" + f + "px )", r.$slideOutNodes.css({"-webkit-transform": "-webkit-" + c, transform: c})) }).on("panend", function () { 2 == m && (r.$html.removeClass(s.dragging), r.$slideOutNodes.css("transform", ""), i[g == l.open_dir ? "_openFinish" : "close"]()), m = 0 }) } } }, add: function () { return"function" != typeof Hammer || Hammer.VERSION < 2 ? (e[n].addons[o].setup = function () { }, void 0) : (s = e[n]._c, i = e[n]._d, a = e[n]._e, s.add("dragging"), void 0) }, clickAnchor: function () { }}, e[n].defaults[o] = {open: !1, maxStartPos: 100, threshold: 50, vendors: {hammer: {}}}, e[n].configuration[o] = {width: {perc: .8, min: 140, max: 440}, height: {perc: .8, min: 140, max: 880}}; var s, i, a, r }(jQuery); /* * jQuery mmenu fixedElements addon * mmenu.frebsite.nl * * Copyright (c) Fred Heusschen */ !function (i) { var s = "mmenu", a = "fixedElements"; i[s].addons[a] = {setup: function () { if (this.opts.offCanvas) { this.opts[a], this.conf[a], t = i[s].glbl; var d = function (i) { var s = this.conf.classNames[a].fixed; this.__refactorClass(i.find("." + s), s, "fixed").appendTo(t.$body).addClass(n.slideout) }; d.call(this, t.$page), this.bind("setPage", d) } }, add: function () { n = i[s]._c, d = i[s]._d, e = i[s]._e, n.add("fixed") }, clickAnchor: function () { }}, i[s].configuration.classNames[a] = {fixed: "Fixed"}; var n, d, e, t }(jQuery); /* * jQuery mmenu footer addon * mmenu.frebsite.nl * * Copyright (c) Fred Heusschen */ !function (t) { var e = "mmenu", o = "footer"; t[e].addons[o] = {setup: function () { var i = this.opts[o]; if (this.conf[o], a = t[e].glbl, "boolean" == typeof i && (i = {add: i, update: i}), "object" != typeof i && (i = {}), i = this.opts[o] = t.extend(!0, {}, t[e].defaults[o], i), i.add) { var s = i.content ? i.content : i.title; t('<div class="' + n.footer + '" />').appendTo(this.$menu).append(s), this.$menu.addClass(n.hasfooter) } if (this.$footer = this.$menu.children("." + n.footer), i.update && this.$footer && this.$footer.length) { var d = function (e) { e = e || this.$menu.children("." + n.current); var s = t("." + this.conf.classNames[o].panelFooter, e).html() || i.title; this.$footer[s ? "removeClass" : "addClass"](n.hidden), this.$footer.html(s) }; this.bind("openPanel", d), this.bind("init", function () { d.call(this, this.$menu.children("." + n.current)) }) } }, add: function () { n = t[e]._c, i = t[e]._d, s = t[e]._e, n.add("footer hasfooter") }, clickAnchor: function () { }}, t[e].defaults[o] = {add: !1, content: !1, title: "", update: !1}, t[e].configuration.classNames[o] = {panelFooter: "Footer"}; var n, i, s, a }(jQuery); /* * jQuery mmenu header addon * mmenu.frebsite.nl * * Copyright (c) Fred Heusschen */ !function (e) { var t = "mmenu", a = "header"; e[t].addons[a] = {setup: function () { var i = this.opts[a]; if (this.conf[a], s = e[t].glbl, "boolean" == typeof i && (i = {add: i, update: i}), "object" != typeof i && (i = {}), "undefined" == typeof i.content && (i.content = ["prev", "title", "next"]), i = this.opts[a] = e.extend(!0, {}, e[t].defaults[a], i), i.add) { if (i.content instanceof Array) { for (var d = e("<div />"), h = 0, l = i.content.length; l > h; h++)switch (i.content[h]) { case"prev": case"next": case"close": d.append('<a class="' + n[i.content[h]] + " " + n.btn + '" href="#"></a>'); break; case"title": d.append('<a class="' + n.title + '"></a>'); break; default: d.append(i.content[h]) } d = d.html() } else var d = i.content; e('<div class="' + n.header + '" />').prependTo(this.$menu).append(d), this.$menu.addClass(n.hasheader), this.bind("init", function (e) { e.removeClass(n.hasheader) }) } if (this.$header = this.$menu.children("." + n.header), i.update && this.$header && this.$header.length) { var c = this.$header.find("." + n.title), o = this.$header.find("." + n.prev), f = this.$header.find("." + n.next), p = this.$header.find("." + n.close), u = function (e) { e = e || this.$menu.children("." + n.current); var t = e.find("." + this.conf.classNames[a].panelHeader), s = e.find("." + this.conf.classNames[a].panelPrev), d = e.find("." + this.conf.classNames[a].panelNext), h = e.data(r.parent), l = t.html(), p = s.attr("href"), u = d.attr("href"), v = !1, m = s.html(), $ = d.html(); switch (l || (l = e.children("." + n.header).children("." + n.title).html()), l || (l = i.title), p || (p = e.children("." + n.header).children("." + n.prev).attr("href")), i.titleLink) { case"anchor": var v = h ? h.children("a").not("." + n.next).attr("href") : !1; break; case"panel": var v = p } c[v ? "attr" : "removeAttr"]("href", v), c[l ? "removeClass" : "addClass"](n.hidden), c.html(l), o[p ? "attr" : "removeAttr"]("href", p), o[p || m ? "removeClass" : "addClass"](n.hidden), o.html(m), f[u ? "attr" : "removeAttr"]("href", u), f[u || $ ? "removeClass" : "addClass"](n.hidden), f.html($) }; if (this.bind("openPanel", u), this.bind("init", function () { u.call(this, this.$menu.children("." + n.current)) }), this.opts.offCanvas) { var v = function (e) { p.attr("href", "#" + e.attr("id")) }; v.call(this, s.$page), this.bind("setPage", v) } } }, add: function () { n = e[t]._c, r = e[t]._d, i = e[t]._e, n.add("close") }, clickAnchor: function () { }}, e[t].defaults[a] = {add: !1, title: "Menu", titleLink: "panel", update: !1}, e[t].configuration.classNames[a] = {panelHeader: "Header", panelNext: "Next", panelPrev: "Prev"}; var n, r, i, s }(jQuery); /* * jQuery mmenu searchfield addon * mmenu.frebsite.nl * * Copyright (c) Fred Heusschen */ !function (e) { function s(e) { switch (e) { case 9: case 16: case 17: case 18: case 37: case 38: case 39: case 40: return!0 } return!1 } var a = "mmenu", n = "searchfield"; e[a].addons[n] = {setup: function () { var o = this, d = this.opts[n], c = this.conf[n]; r = e[a].glbl, "boolean" == typeof d && (d = {add: d, search: d}), "object" != typeof d && (d = {}), d = this.opts[n] = e.extend(!0, {}, e[a].defaults[n], d), this.bind("init", function (a) { if (d.add) { switch (d.addTo) { case"menu": var n = this.$menu; break; case"panels": var n = a; break; default: var n = e(d.addTo, this.$menu).filter("." + t.panel) } n.each(function () { var s = e(this); if (!s.is("." + t.panel) || !s.is("." + t.vertical)) { if (!s.children("." + t.search).length) { var a = c.form ? "form" : "div", n = e("<" + a + ' class="' + t.search + '" />'); if (c.form && "object" == typeof c.form)for (var l in c.form)n.attr(l, c.form[l]); n.append('<input placeholder="' + d.placeholder + '" type="text" autocomplete="off" />').prependTo(s), s.addClass(t.hassearch) } if (d.noResults && (s.is("." + t.menu) && (s = s.children("." + t.panel).first()), !s.children("." + t.noresultsmsg).length)) { var i = s.children("." + t.listview); e('<div class="' + t.noresultsmsg + '" />').append(d.noResults)[i.length ? "insertBefore" : "prependTo"](i.length ? i : s) } } }) } d.search && e("." + t.search, this.$menu).each(function () { var a = e(this); if ("menu" == d.addTo)var n = e("." + t.panel, o.$menu), r = o.$menu; else var n = a.closest("." + t.panel), r = n; var c = a.children("input"), h = o.__findAddBack(n, "." + t.listview).children("li"), u = h.filter("." + t.divider), f = o.__filterListItems(h), p = "> a", v = p + ", > span", m = function () { var s = c.val().toLowerCase(); n.scrollTop(0), f.add(u).addClass(t.hidden).find("." + t.fullsubopensearch).removeClass(t.fullsubopen).removeClass(t.fullsubopensearch), f.each(function () { var a = e(this), n = p; (d.showTextItems || d.showSubPanels && a.find("." + t.next)) && (n = v), e(n, a).text().toLowerCase().indexOf(s) > -1 && a.add(a.prevAll("." + t.divider).first()).removeClass(t.hidden) }), d.showSubPanels && n.each(function () { var s = e(this); o.__filterListItems(s.find("." + t.listview).children()).each(function () { var s = e(this), a = s.data(l.sub); s.removeClass(t.nosubresults), a && a.find("." + t.listview).children().removeClass(t.hidden) }) }), e(n.get().reverse()).each(function (s) { var a = e(this), n = a.data(l.parent); n && (o.__filterListItems(a.find("." + t.listview).children()).length ? (n.hasClass(t.hidden) && n.children("." + t.next).not("." + t.fullsubopen).addClass(t.fullsubopen).addClass(t.fullsubopensearch), n.removeClass(t.hidden).removeClass(t.nosubresults).prevAll("." + t.divider).first().removeClass(t.hidden)) : "menu" == d.addTo && (a.hasClass(t.opened) && setTimeout(function () { o.openPanel(n.closest("." + t.panel)) }, 1.5 * (s + 1) * o.conf.openingInterval), n.addClass(t.nosubresults))) }), r[f.not("." + t.hidden).length ? "removeClass" : "addClass"](t.noresults), this.update() }; c.off(i.keyup + "-searchfield " + i.change + "-searchfield").on(i.keyup + "-searchfield", function (e) { s(e.keyCode) || m.call(o) }).on(i.change + "-searchfield", function () { m.call(o) }) }) }) }, add: function () { t = e[a]._c, l = e[a]._d, i = e[a]._e, t.add("search hassearch noresultsmsg noresults nosubresults fullsubopensearch"), i.add("change keyup") }, clickAnchor: function () { }}, e[a].defaults[n] = {add: !1, addTo: "menu", search: !1, placeholder: "Search", noResults: "No results found.", showTextItems: !1, showSubPanels: !0}, e[a].configuration[n] = {form: !1}; var t, l, i, r }(jQuery); /* * jQuery mmenu sectionIndexer addon * mmenu.frebsite.nl * * Copyright (c) Fred Heusschen */ !function (e) { var a = "mmenu", r = "sectionIndexer"; e[a].addons[r] = {setup: function () { var n = this, s = this.opts[r]; this.conf[r], d = e[a].glbl, "boolean" == typeof s && (s = {add: s}), "object" != typeof s && (s = {}), s = this.opts[r] = e.extend(!0, {}, e[a].defaults[r], s), this.bind("init", function (a) { if (s.add) { switch (s.addTo) { case"panels": var r = a; break; default: var r = e(s.addTo, this.$menu).filter("." + i.panel) } r.find("." + i.divider).closest("." + i.panel).addClass(i.hasindexer) } if (!this.$indexer && this.$menu.children("." + i.hasindexer).length) { this.$indexer = e('<div class="' + i.indexer + '" />').prependTo(this.$menu).append('<a href="#a">a</a><a href="#b">b</a><a href="#c">c</a><a href="#d">d</a><a href="#e">e</a><a href="#f">f</a><a href="#g">g</a><a href="#h">h</a><a href="#i">i</a><a href="#j">j</a><a href="#k">k</a><a href="#l">l</a><a href="#m">m</a><a href="#n">n</a><a href="#o">o</a><a href="#p">p</a><a href="#q">q</a><a href="#r">r</a><a href="#s">s</a><a href="#t">t</a><a href="#u">u</a><a href="#v">v</a><a href="#w">w</a><a href="#x">x</a><a href="#y">y</a><a href="#z">z</a><a href="##">#</a>'), this.$indexer.children().on(h.mouseover + "-searchfield " + i.touchmove + "-searchfield", function () { var a = e(this).attr("href").slice(1), r = n.$menu.children("." + i.current), h = r.find("." + i.listview), d = !1, s = r.scrollTop(), t = h.position().top + parseInt(h.css("margin-top"), 10) + parseInt(h.css("padding-top"), 10) + s; r.scrollTop(0), h.children("." + i.divider).not("." + i.hidden).each(function () { d === !1 && a == e(this).text().slice(0, 1).toLowerCase() && (d = e(this).position().top + t) }), r.scrollTop(d !== !1 ? d : s) }); var d = function (e) { n.$menu[(e.hasClass(i.hasindexer) ? "add" : "remove") + "Class"](i.hasindexer) }; this.bind("openPanel", d), d.call(this, this.$menu.children("." + i.current)) } }) }, add: function () { i = e[a]._c, n = e[a]._d, h = e[a]._e, i.add("indexer hasindexer"), h.add("mouseover touchmove") }, clickAnchor: function (e) { return e.parent().is("." + i.indexer) ? !0 : void 0 }}, e[a].defaults[r] = {add: !1, addTo: "panels"}; var i, n, h, d }(jQuery); /* * jQuery mmenu toggles addon * mmenu.frebsite.nl * * Copyright (c) Fred Heusschen */ !function (t) { var e = "mmenu", c = "toggles"; t[e].addons[c] = {setup: function () { var n = this; this.opts[c], this.conf[c], l = t[e].glbl, this.bind("init", function (e) { this.__refactorClass(t("input", e), this.conf.classNames[c].toggle, "toggle"), this.__refactorClass(t("input", e), this.conf.classNames[c].check, "check"), t("input." + s.toggle + ", input." + s.check, e).each(function () { var e = t(this), c = e.closest("li"), i = e.hasClass(s.toggle) ? "toggle" : "check", l = e.attr("id") || n.__getUniqueId(); c.children('label[for="' + l + '"]').length || (e.attr("id", l), c.prepend(e), t('<label for="' + l + '" class="' + s[i] + '"></label>').insertBefore(c.children("a, span").last())) }) }) }, add: function () { s = t[e]._c, n = t[e]._d, i = t[e]._e, s.add("toggle check") }, clickAnchor: function () { }}, t[e].configuration.classNames[c] = {toggle: "Toggle", check: "Check"}; var s, n, i, l }(jQuery); /*! picturefill - v3.0.2 - 2016-02-12 * https://scottjehl.github.io/picturefill/ * Copyright (c) 2016 https://github.com/scottjehl/picturefill/blob/master/Authors.txt; Licensed MIT */ /*! Gecko-Picture - v1.0 * https://github.com/scottjehl/picturefill/tree/3.0/src/plugins/gecko-picture * Firefox's early picture implementation (prior to FF41) is static and does * not react to viewport changes. This tiny module fixes this. */ (function(window) { /*jshint eqnull:true */ var ua = navigator.userAgent; if ( window.HTMLPictureElement && ((/ecko/).test(ua) && ua.match(/rv\:(\d+)/) && RegExp.$1 < 45) ) { addEventListener("resize", (function() { var timer; var dummySrc = document.createElement("source"); var fixRespimg = function(img) { var source, sizes; var picture = img.parentNode; if (picture.nodeName.toUpperCase() === "PICTURE") { source = dummySrc.cloneNode(); picture.insertBefore(source, picture.firstElementChild); setTimeout(function() { picture.removeChild(source); }); } else if (!img._pfLastSize || img.offsetWidth > img._pfLastSize) { img._pfLastSize = img.offsetWidth; sizes = img.sizes; img.sizes += ",100vw"; setTimeout(function() { img.sizes = sizes; }); } }; var findPictureImgs = function() { var i; var imgs = document.querySelectorAll("picture > img, img[srcset][sizes]"); for (i = 0; i < imgs.length; i++) { fixRespimg(imgs[i]); } }; var onResize = function() { clearTimeout(timer); timer = setTimeout(findPictureImgs, 99); }; var mq = window.matchMedia && matchMedia("(orientation: landscape)"); var init = function() { onResize(); if (mq && mq.addListener) { mq.addListener(onResize); } }; dummySrc.srcset = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; if (/^[c|i]|d$/.test(document.readyState || "")) { init(); } else { document.addEventListener("DOMContentLoaded", init); } return onResize; })()); } })(window); /*! Picturefill - v3.0.2 * http://scottjehl.github.io/picturefill * Copyright (c) 2015 https://github.com/scottjehl/picturefill/blob/master/Authors.txt; * License: MIT */ (function( window, document, undefined ) { // Enable strict mode "use strict"; // HTML shim|v it for old IE (IE9 will still need the HTML video tag workaround) document.createElement( "picture" ); var warn, eminpx, alwaysCheckWDescriptor, evalId; // local object for method references and testing exposure var pf = {}; var isSupportTestReady = false; var noop = function() {}; var image = document.createElement( "img" ); var getImgAttr = image.getAttribute; var setImgAttr = image.setAttribute; var removeImgAttr = image.removeAttribute; var docElem = document.documentElement; var types = {}; var cfg = { //resource selection: algorithm: "" }; var srcAttr = "data-pfsrc"; var srcsetAttr = srcAttr + "set"; // ua sniffing is done for undetectable img loading features, // to do some non crucial perf optimizations var ua = navigator.userAgent; var supportAbort = (/rident/).test(ua) || ((/ecko/).test(ua) && ua.match(/rv\:(\d+)/) && RegExp.$1 > 35 ); var curSrcProp = "currentSrc"; var regWDesc = /\s+\+?\d+(e\d+)?w/; var regSize = /(\([^)]+\))?\s*(.+)/; var setOptions = window.picturefillCFG; /** * Shortcut property for https://w3c.github.io/webappsec/specs/mixedcontent/#restricts-mixed-content ( for easy overriding in tests ) */ // baseStyle also used by getEmValue (i.e.: width: 1em is important) var baseStyle = "position:absolute;left:0;visibility:hidden;display:block;padding:0;border:none;font-size:1em;width:1em;overflow:hidden;clip:rect(0px, 0px, 0px, 0px)"; var fsCss = "font-size:100%!important;"; var isVwDirty = true; var cssCache = {}; var sizeLengthCache = {}; var DPR = window.devicePixelRatio; var units = { px: 1, "in": 96 }; var anchor = document.createElement( "a" ); /** * alreadyRun flag used for setOptions. is it true setOptions will reevaluate * @type {boolean} */ var alreadyRun = false; // Reusable, non-"g" Regexes // (Don't use \s, to avoid matching non-breaking space.) var regexLeadingSpaces = /^[ \t\n\r\u000c]+/, regexLeadingCommasOrSpaces = /^[, \t\n\r\u000c]+/, regexLeadingNotSpaces = /^[^ \t\n\r\u000c]+/, regexTrailingCommas = /[,]+$/, regexNonNegativeInteger = /^\d+$/, // ( Positive or negative or unsigned integers or decimals, without or without exponents. // Must include at least one digit. // According to spec tests any decimal point must be followed by a digit. // No leading plus sign is allowed.) // https://html.spec.whatwg.org/multipage/infrastructure.html#valid-floating-point-number regexFloatingPoint = /^-?(?:[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?[0-9]+)?$/; var on = function(obj, evt, fn, capture) { if ( obj.addEventListener ) { obj.addEventListener(evt, fn, capture || false); } else if ( obj.attachEvent ) { obj.attachEvent( "on" + evt, fn); } }; /** * simple memoize function: */ var memoize = function(fn) { var cache = {}; return function(input) { if ( !(input in cache) ) { cache[ input ] = fn(input); } return cache[ input ]; }; }; // UTILITY FUNCTIONS // Manual is faster than RegEx // http://jsperf.com/whitespace-character/5 function isSpace(c) { return (c === "\u0020" || // space c === "\u0009" || // horizontal tab c === "\u000A" || // new line c === "\u000C" || // form feed c === "\u000D"); // carriage return } /** * gets a mediaquery and returns a boolean or gets a css length and returns a number * @param css mediaqueries or css length * @returns {boolean|number} * * based on: https://gist.github.com/jonathantneal/db4f77009b155f083738 */ var evalCSS = (function() { var regLength = /^([\d\.]+)(em|vw|px)$/; var replace = function() { var args = arguments, index = 0, string = args[0]; while (++index in args) { string = string.replace(args[index], args[++index]); } return string; }; var buildStr = memoize(function(css) { return "return " + replace((css || "").toLowerCase(), // interpret `and` /\band\b/g, "&&", // interpret `,` /,/g, "||", // interpret `min-` as >= /min-([a-z-\s]+):/g, "e.$1>=", // interpret `max-` as <= /max-([a-z-\s]+):/g, "e.$1<=", //calc value /calc([^)]+)/g, "($1)", // interpret css values /(\d+[\.]*[\d]*)([a-z]+)/g, "($1 * e.$2)", //make eval less evil /^(?!(e.[a-z]|[0-9\.&=|><\+\-\*\(\)\/])).*/ig, "" ) + ";"; }); return function(css, length) { var parsedLength; if (!(css in cssCache)) { cssCache[css] = false; if (length && (parsedLength = css.match( regLength ))) { cssCache[css] = parsedLength[ 1 ] * units[parsedLength[ 2 ]]; } else { /*jshint evil:true */ try{ cssCache[css] = new Function("e", buildStr(css))(units); // NOSONAR } catch(e) {} /*jshint evil:false */ } } return cssCache[css]; }; })(); var setResolution = function( candidate, sizesattr ) { if ( candidate.w ) { // h = means height: || descriptor.type === 'h' do not handle yet... candidate.cWidth = pf.calcListLength( sizesattr || "100vw" ); candidate.res = candidate.w / candidate.cWidth ; } else { candidate.res = candidate.d; } return candidate; }; /** * * @param opt */ var picturefill = function( opt ) { if (!isSupportTestReady) {return;} var elements, i, plen; var options = opt || {}; if ( options.elements && options.elements.nodeType === 1 ) { if ( options.elements.nodeName.toUpperCase() === "IMG" ) { options.elements = [ options.elements ]; } else { options.context = options.elements; options.elements = null; } } elements = options.elements || pf.qsa( (options.context || document), ( options.reevaluate || options.reselect ) ? pf.sel : pf.selShort ); if ( (plen = elements.length) ) { pf.setupRun( options ); alreadyRun = true; // Loop through all elements for ( i = 0; i < plen; i++ ) { pf.fillImg(elements[ i ], options); } pf.teardownRun( options ); } }; /** * outputs a warning for the developer * @param {message} * @type {Function} */ warn = ( window.console && console.warn ) ? function( message ) { console.warn( message ); } : noop ; if ( !(curSrcProp in image) ) { curSrcProp = "src"; } // Add support for standard mime types. types[ "image/jpeg" ] = true; types[ "image/gif" ] = true; types[ "image/png" ] = true; function detectTypeSupport( type, typeUri ) { // based on Modernizr's lossless img-webp test // note: asynchronous var image = new window.Image(); image.onerror = function() { types[ type ] = false; picturefill(); }; image.onload = function() { types[ type ] = image.width === 1; picturefill(); }; image.src = typeUri; return "pending"; } // test svg support types[ "image/svg+xml" ] = document.implementation.hasFeature( "http://www.w3.org/TR/SVG11/feature#Image", "1.1" ); /** * updates the internal vW property with the current viewport width in px */ function updateMetrics() { isVwDirty = false; DPR = window.devicePixelRatio; cssCache = {}; sizeLengthCache = {}; pf.DPR = DPR || 1; units.width = Math.max(window.innerWidth || 0, docElem.clientWidth); units.height = Math.max(window.innerHeight || 0, docElem.clientHeight); units.vw = units.width / 100; units.vh = units.height / 100; evalId = [ units.height, units.width, DPR ].join("-"); units.em = pf.getEmValue(); units.rem = units.em; } function chooseLowRes( lowerValue, higherValue, dprValue, isCached ) { var bonusFactor, tooMuch, bonus, meanDensity; //experimental if (cfg.algorithm === "saveData" ){ if ( lowerValue > 2.7 ) { meanDensity = dprValue + 1; } else { tooMuch = higherValue - dprValue; bonusFactor = Math.pow(lowerValue - 0.6, 1.5); bonus = tooMuch * bonusFactor; if (isCached) { bonus += 0.1 * bonusFactor; } meanDensity = lowerValue + bonus; } } else { meanDensity = (dprValue > 1) ? Math.sqrt(lowerValue * higherValue) : lowerValue; } return meanDensity > dprValue; } function applyBestCandidate( img ) { var srcSetCandidates; var matchingSet = pf.getSet( img ); var evaluated = false; if ( matchingSet !== "pending" ) { evaluated = evalId; if ( matchingSet ) { srcSetCandidates = pf.setRes( matchingSet ); pf.applySetCandidate( srcSetCandidates, img ); } } img[ pf.ns ].evaled = evaluated; } function ascendingSort( a, b ) { return a.res - b.res; } function setSrcToCur( img, src, set ) { var candidate; if ( !set && src ) { set = img[ pf.ns ].sets; set = set && set[set.length - 1]; } candidate = getCandidateForSrc(src, set); if ( candidate ) { src = pf.makeUrl(src); img[ pf.ns ].curSrc = src; img[ pf.ns ].curCan = candidate; if ( !candidate.res ) { setResolution( candidate, candidate.set.sizes ); } } return candidate; } function getCandidateForSrc( src, set ) { var i, candidate, candidates; if ( src && set ) { candidates = pf.parseSet( set ); src = pf.makeUrl(src); for ( i = 0; i < candidates.length; i++ ) { if ( src === pf.makeUrl(candidates[ i ].url) ) { candidate = candidates[ i ]; break; } } } return candidate; } function getAllSourceElements( picture, candidates ) { var i, len, source, srcset; // SPEC mismatch intended for size and perf: // actually only source elements preceding the img should be used // also note: don't use qsa here, because IE8 sometimes doesn't like source as the key part in a selector var sources = picture.getElementsByTagName( "source" ); for ( i = 0, len = sources.length; i < len; i++ ) { source = sources[ i ]; source[ pf.ns ] = true; srcset = source.getAttribute( "srcset" ); // if source does not have a srcset attribute, skip if ( srcset ) { candidates.push( { srcset: srcset, media: source.getAttribute( "media" ), type: source.getAttribute( "type" ), sizes: source.getAttribute( "sizes" ) } ); } } } /** * Srcset Parser * By Alex Bell | MIT License * * @returns Array [{url: _, d: _, w: _, h:_, set:_(????)}, ...] * * Based super duper closely on the reference algorithm at: * https://html.spec.whatwg.org/multipage/embedded-content.html#parse-a-srcset-attribute */ // 1. Let input be the value passed to this algorithm. // (TO-DO : Explain what "set" argument is here. Maybe choose a more // descriptive & more searchable name. Since passing the "set" in really has // nothing to do with parsing proper, I would prefer this assignment eventually // go in an external fn.) function parseSrcset(input, set) { function collectCharacters(regEx) { var chars, match = regEx.exec(input.substring(pos)); if (match) { chars = match[ 0 ]; pos += chars.length; return chars; } } var inputLength = input.length, url, descriptors, currentDescriptor, state, c, // 2. Let position be a pointer into input, initially pointing at the start // of the string. pos = 0, // 3. Let candidates be an initially empty source set. candidates = []; /** * Adds descriptor properties to a candidate, pushes to the candidates array * @return undefined */ // (Declared outside of the while loop so that it's only created once. // (This fn is defined before it is used, in order to pass JSHINT. // Unfortunately this breaks the sequencing of the spec comments. :/ ) function parseDescriptors() { // 9. Descriptor parser: Let error be no. var pError = false, // 10. Let width be absent. // 11. Let density be absent. // 12. Let future-compat-h be absent. (We're implementing it now as h) w, d, h, i, candidate = {}, desc, lastChar, value, intVal, floatVal; // 13. For each descriptor in descriptors, run the appropriate set of steps // from the following list: for (i = 0 ; i < descriptors.length; i++) { desc = descriptors[ i ]; lastChar = desc[ desc.length - 1 ]; value = desc.substring(0, desc.length - 1); intVal = parseInt(value, 10); floatVal = parseFloat(value); // If the descriptor consists of a valid non-negative integer followed by // a U+0077 LATIN SMALL LETTER W character if (regexNonNegativeInteger.test(value) && (lastChar === "w")) { // If width and density are not both absent, then let error be yes. if (w || d) {pError = true;} // Apply the rules for parsing non-negative integers to the descriptor. // If the result is zero, let error be yes. // Otherwise, let width be the result. if (intVal === 0) {pError = true;} else {w = intVal;} // If the descriptor consists of a valid floating-point number followed by // a U+0078 LATIN SMALL LETTER X character } else if (regexFloatingPoint.test(value) && (lastChar === "x")) { // If width, density and future-compat-h are not all absent, then let error // be yes. if (w || d || h) {pError = true;} // Apply the rules for parsing floating-point number values to the descriptor. // If the result is less than zero, let error be yes. Otherwise, let density // be the result. if (floatVal < 0) {pError = true;} else {d = floatVal;} // If the descriptor consists of a valid non-negative integer followed by // a U+0068 LATIN SMALL LETTER H character } else if (regexNonNegativeInteger.test(value) && (lastChar === "h")) { // If height and density are not both absent, then let error be yes. if (h || d) {pError = true;} // Apply the rules for parsing non-negative integers to the descriptor. // If the result is zero, let error be yes. Otherwise, let future-compat-h // be the result. if (intVal === 0) {pError = true;} else {h = intVal;} // Anything else, Let error be yes. } else {pError = true;} } // (close step 13 for loop) // 15. If error is still no, then append a new image source to candidates whose // URL is url, associated with a width width if not absent and a pixel // density density if not absent. Otherwise, there is a parse error. if (!pError) { candidate.url = url; if (w) { candidate.w = w;} if (d) { candidate.d = d;} if (h) { candidate.h = h;} if (!h && !d && !w) {candidate.d = 1;} if (candidate.d === 1) {set.has1x = true;} candidate.set = set; candidates.push(candidate); } } // (close parseDescriptors fn) /** * Tokenizes descriptor properties prior to parsing * Returns undefined. * (Again, this fn is defined before it is used, in order to pass JSHINT. * Unfortunately this breaks the logical sequencing of the spec comments. :/ ) */ function tokenize() { // 8.1. Descriptor tokeniser: Skip whitespace collectCharacters(regexLeadingSpaces); // 8.2. Let current descriptor be the empty string. currentDescriptor = ""; // 8.3. Let state be in descriptor. state = "in descriptor"; while (true) { // 8.4. Let c be the character at position. c = input.charAt(pos); // Do the following depending on the value of state. // For the purpose of this step, "EOF" is a special character representing // that position is past the end of input. // In descriptor if (state === "in descriptor") { // Do the following, depending on the value of c: // Space character // If current descriptor is not empty, append current descriptor to // descriptors and let current descriptor be the empty string. // Set state to after descriptor. if (isSpace(c)) { if (currentDescriptor) { descriptors.push(currentDescriptor); currentDescriptor = ""; state = "after descriptor"; } // U+002C COMMA (,) // Advance position to the next character in input. If current descriptor // is not empty, append current descriptor to descriptors. Jump to the step // labeled descriptor parser. } else if (c === ",") { pos += 1; if (currentDescriptor) { descriptors.push(currentDescriptor); } parseDescriptors(); return; // U+0028 LEFT PARENTHESIS (() // Append c to current descriptor. Set state to in parens. } else if (c === "\u0028") { currentDescriptor = currentDescriptor + c; state = "in parens"; // EOF // If current descriptor is not empty, append current descriptor to // descriptors. Jump to the step labeled descriptor parser. } else if (c === "") { if (currentDescriptor) { descriptors.push(currentDescriptor); } parseDescriptors(); return; // Anything else // Append c to current descriptor. } else { currentDescriptor = currentDescriptor + c; } // (end "in descriptor" // In parens } else if (state === "in parens") { // U+0029 RIGHT PARENTHESIS ()) // Append c to current descriptor. Set state to in descriptor. if (c === ")") { currentDescriptor = currentDescriptor + c; state = "in descriptor"; // EOF // Append current descriptor to descriptors. Jump to the step labeled // descriptor parser. } else if (c === "") { descriptors.push(currentDescriptor); parseDescriptors(); return; // Anything else // Append c to current descriptor. } else { currentDescriptor = currentDescriptor + c; } // After descriptor } else if (state === "after descriptor") { // Do the following, depending on the value of c: // Space character: Stay in this state. if (isSpace(c)) { // EOF: Jump to the step labeled descriptor parser. } else if (c === "") { parseDescriptors(); return; // Anything else // Set state to in descriptor. Set position to the previous character in input. } else { state = "in descriptor"; pos -= 1; } } // Advance position to the next character in input. pos += 1; // Repeat this step. } // (close while true loop) } // 4. Splitting loop: Collect a sequence of characters that are space // characters or U+002C COMMA characters. If any U+002C COMMA characters // were collected, that is a parse error. while (true) { collectCharacters(regexLeadingCommasOrSpaces); // 5. If position is past the end of input, return candidates and abort these steps. if (pos >= inputLength) { return candidates; // (we're done, this is the sole return path) } // 6. Collect a sequence of characters that are not space characters, // and let that be url. url = collectCharacters(regexLeadingNotSpaces); // 7. Let descriptors be a new empty list. descriptors = []; // 8. If url ends with a U+002C COMMA character (,), follow these substeps: // (1). Remove all trailing U+002C COMMA characters from url. If this removed // more than one character, that is a parse error. if (url.slice(-1) === ",") { url = url.replace(regexTrailingCommas, ""); // (Jump ahead to step 9 to skip tokenization and just push the candidate). parseDescriptors(); // Otherwise, follow these substeps: } else { tokenize(); } // (close else of step 8) // 16. Return to the step labeled splitting loop. } // (Close of big while loop.) } /* * Sizes Parser * * By Alex Bell | MIT License * * Non-strict but accurate and lightweight JS Parser for the string value <img sizes="here"> * * Reference algorithm at: * https://html.spec.whatwg.org/multipage/embedded-content.html#parse-a-sizes-attribute * * Most comments are copied in directly from the spec * (except for comments in parens). * * Grammar is: * <source-size-list> = <source-size># [ , <source-size-value> ]? | <source-size-value> * <source-size> = <media-condition> <source-size-value> * <source-size-value> = <length> * http://www.w3.org/html/wg/drafts/html/master/embedded-content.html#attr-img-sizes * * E.g. "(max-width: 30em) 100vw, (max-width: 50em) 70vw, 100vw" * or "(min-width: 30em), calc(30vw - 15px)" or just "30vw" * * Returns the first valid <css-length> with a media condition that evaluates to true, * or "100vw" if all valid media conditions evaluate to false. * */ function parseSizes(strValue) { // (Percentage CSS lengths are not allowed in this case, to avoid confusion: // https://html.spec.whatwg.org/multipage/embedded-content.html#valid-source-size-list // CSS allows a single optional plus or minus sign: // http://www.w3.org/TR/CSS2/syndata.html#numbers // CSS is ASCII case-insensitive: // http://www.w3.org/TR/CSS2/syndata.html#characters ) // Spec allows exponential notation for <number> type: // http://dev.w3.org/csswg/css-values/#numbers var regexCssLengthWithUnits = /^(?:[+-]?[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?[0-9]+)?(?:ch|cm|em|ex|in|mm|pc|pt|px|rem|vh|vmin|vmax|vw)$/i; // (This is a quick and lenient test. Because of optional unlimited-depth internal // grouping parens and strict spacing rules, this could get very complicated.) var regexCssCalc = /^calc\((?:[0-9a-z \.\+\-\*\/\(\)]+)\)$/i; var i; var unparsedSizesList; var unparsedSizesListLength; var unparsedSize; var lastComponentValue; var size; // UTILITY FUNCTIONS // (Toy CSS parser. The goals here are: // 1) expansive test coverage without the weight of a full CSS parser. // 2) Avoiding regex wherever convenient. // Quick tests: http://jsfiddle.net/gtntL4gr/3/ // Returns an array of arrays.) function parseComponentValues(str) { var chrctr; var component = ""; var componentArray = []; var listArray = []; var parenDepth = 0; var pos = 0; var inComment = false; function pushComponent() { if (component) { componentArray.push(component); component = ""; } } function pushComponentArray() { if (componentArray[0]) { listArray.push(componentArray); componentArray = []; } } // (Loop forwards from the beginning of the string.) while (true) { chrctr = str.charAt(pos); if (chrctr === "") { // ( End of string reached.) pushComponent(); pushComponentArray(); return listArray; } else if (inComment) { if ((chrctr === "*") && (str[pos + 1] === "/")) { // (At end of a comment.) inComment = false; pos += 2; pushComponent(); continue; } else { pos += 1; // (Skip all characters inside comments.) continue; } } else if (isSpace(chrctr)) { // (If previous character in loop was also a space, or if // at the beginning of the string, do not add space char to // component.) if ( (str.charAt(pos - 1) && isSpace( str.charAt(pos - 1) ) ) || !component ) { pos += 1; continue; } else if (parenDepth === 0) { pushComponent(); pos +=1; continue; } else { // (Replace any space character with a plain space for legibility.) chrctr = " "; } } else if (chrctr === "(") { parenDepth += 1; } else if (chrctr === ")") { parenDepth -= 1; } else if (chrctr === ",") { pushComponent(); pushComponentArray(); pos += 1; continue; } else if ( (chrctr === "/") && (str.charAt(pos + 1) === "*") ) { inComment = true; pos += 2; continue; } component = component + chrctr; pos += 1; } } function isValidNonNegativeSourceSizeValue(s) { if (regexCssLengthWithUnits.test(s) && (parseFloat(s) >= 0)) {return true;} if (regexCssCalc.test(s)) {return true;} // ( http://www.w3.org/TR/CSS2/syndata.html#numbers says: // "-0 is equivalent to 0 and is not a negative number." which means that // unitless zero and unitless negative zero must be accepted as special cases.) if ((s === "0") || (s === "-0") || (s === "+0")) {return true;} return false; } // When asked to parse a sizes attribute from an element, parse a // comma-separated list of component values from the value of the element's // sizes attribute (or the empty string, if the attribute is absent), and let // unparsed sizes list be the result. // http://dev.w3.org/csswg/css-syntax/#parse-comma-separated-list-of-component-values unparsedSizesList = parseComponentValues(strValue); unparsedSizesListLength = unparsedSizesList.length; // For each unparsed size in unparsed sizes list: for (i = 0; i < unparsedSizesListLength; i++) { unparsedSize = unparsedSizesList[i]; // 1. Remove all consecutive <whitespace-token>s from the end of unparsed size. // ( parseComponentValues() already omits spaces outside of parens. ) // If unparsed size is now empty, that is a parse error; continue to the next // iteration of this algorithm. // ( parseComponentValues() won't push an empty array. ) // 2. If the last component value in unparsed size is a valid non-negative // <source-size-value>, let size be its value and remove the component value // from unparsed size. Any CSS function other than the calc() function is // invalid. Otherwise, there is a parse error; continue to the next iteration // of this algorithm. // http://dev.w3.org/csswg/css-syntax/#parse-component-value lastComponentValue = unparsedSize[unparsedSize.length - 1]; if (isValidNonNegativeSourceSizeValue(lastComponentValue)) { size = lastComponentValue; unparsedSize.pop(); } else { continue; } // 3. Remove all consecutive <whitespace-token>s from the end of unparsed // size. If unparsed size is now empty, return size and exit this algorithm. // If this was not the last item in unparsed sizes list, that is a parse error. if (unparsedSize.length === 0) { return size; } // 4. Parse the remaining component values in unparsed size as a // <media-condition>. If it does not parse correctly, or it does parse // correctly but the <media-condition> evaluates to false, continue to the // next iteration of this algorithm. // (Parsing all possible compound media conditions in JS is heavy, complicated, // and the payoff is unclear. Is there ever an situation where the // media condition parses incorrectly but still somehow evaluates to true? // Can we just rely on the browser/polyfill to do it?) unparsedSize = unparsedSize.join(" "); if (!(pf.matchesMedia( unparsedSize ) ) ) { continue; } // 5. Return size and exit this algorithm. return size; } // If the above algorithm exhausts unparsed sizes list without returning a // size value, return 100vw. return "100vw"; } // namespace pf.ns = ("pf" + new Date().getTime()).substr(0, 9); // srcset support test pf.supSrcset = "srcset" in image; pf.supSizes = "sizes" in image; pf.supPicture = !!window.HTMLPictureElement; // UC browser does claim to support srcset and picture, but not sizes, // this extended test reveals the browser does support nothing if (pf.supSrcset && pf.supPicture && !pf.supSizes) { (function(image2) { image.srcset = "data:,a"; image2.src = "data:,a"; pf.supSrcset = image.complete === image2.complete; pf.supPicture = pf.supSrcset && pf.supPicture; })(document.createElement("img")); } // Safari9 has basic support for sizes, but does't expose the `sizes` idl attribute if (pf.supSrcset && !pf.supSizes) { (function() { var width2 = "data:image/gif;base64,R0lGODlhAgABAPAAAP///wAAACH5BAAAAAAALAAAAAACAAEAAAICBAoAOw=="; var width1 = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; var img = document.createElement("img"); var test = function() { var width = img.width; if (width === 2) { pf.supSizes = true; } alwaysCheckWDescriptor = pf.supSrcset && !pf.supSizes; isSupportTestReady = true; // force async setTimeout(picturefill); }; img.onload = test; img.onerror = test; img.setAttribute("sizes", "9px"); img.srcset = width1 + " 1w," + width2 + " 9w"; img.src = width1; })(); } else { isSupportTestReady = true; } // using pf.qsa instead of dom traversing does scale much better, // especially on sites mixing responsive and non-responsive images pf.selShort = "picture>img,img[srcset]"; pf.sel = pf.selShort; pf.cfg = cfg; /** * Shortcut property for `devicePixelRatio` ( for easy overriding in tests ) */ pf.DPR = (DPR || 1 ); pf.u = units; // container of supported mime types that one might need to qualify before using pf.types = types; pf.setSize = noop; /** * Gets a string and returns the absolute URL * @param src * @returns {String} absolute URL */ pf.makeUrl = memoize(function(src) { anchor.href = src; return anchor.href; }); /** * Gets a DOM element or document and a selctor and returns the found matches * Can be extended with jQuery/Sizzle for IE7 support * @param context * @param sel * @returns {NodeList|Array} */ pf.qsa = function(context, sel) { return ( "querySelector" in context ) ? context.querySelectorAll(sel) : []; }; /** * Shortcut method for matchMedia ( for easy overriding in tests ) * wether native or pf.mMQ is used will be decided lazy on first call * @returns {boolean} */ pf.matchesMedia = function() { if ( window.matchMedia && (matchMedia( "(min-width: 0.1em)" ) || {}).matches ) { pf.matchesMedia = function( media ) { return !media || ( matchMedia( media ).matches ); }; } else { pf.matchesMedia = pf.mMQ; } return pf.matchesMedia.apply( this, arguments ); }; /** * A simplified matchMedia implementation for IE8 and IE9 * handles only min-width/max-width with px or em values * @param media * @returns {boolean} */ pf.mMQ = function( media ) { return media ? evalCSS(media) : true; }; /** * Returns the calculated length in css pixel from the given sourceSizeValue * http://dev.w3.org/csswg/css-values-3/#length-value * intended Spec mismatches: * * Does not check for invalid use of CSS functions * * Does handle a computed length of 0 the same as a negative and therefore invalid value * @param sourceSizeValue * @returns {Number} */ pf.calcLength = function( sourceSizeValue ) { var value = evalCSS(sourceSizeValue, true) || false; if (value < 0) { value = false; } return value; }; /** * Takes a type string and checks if its supported */ pf.supportsType = function( type ) { return ( type ) ? types[ type ] : true; }; /** * Parses a sourceSize into mediaCondition (media) and sourceSizeValue (length) * @param sourceSizeStr * @returns {*} */ pf.parseSize = memoize(function( sourceSizeStr ) { var match = ( sourceSizeStr || "" ).match(regSize); return { media: match && match[1], length: match && match[2] }; }); pf.parseSet = function( set ) { if ( !set.cands ) { set.cands = parseSrcset(set.srcset, set); } return set.cands; }; /** * returns 1em in css px for html/body default size * function taken from respondjs * @returns {*|number} */ pf.getEmValue = function() { var body; if ( !eminpx && (body = document.body) ) { var div = document.createElement( "div" ), originalHTMLCSS = docElem.style.cssText, originalBodyCSS = body.style.cssText; div.style.cssText = baseStyle; // 1em in a media query is the value of the default font size of the browser // reset docElem and body to ensure the correct value is returned docElem.style.cssText = fsCss; body.style.cssText = fsCss; body.appendChild( div ); eminpx = div.offsetWidth; body.removeChild( div ); //also update eminpx before returning eminpx = parseFloat( eminpx, 10 ); // restore the original values docElem.style.cssText = originalHTMLCSS; body.style.cssText = originalBodyCSS; } return eminpx || 16; }; /** * Takes a string of sizes and returns the width in pixels as a number */ pf.calcListLength = function( sourceSizeListStr ) { // Split up source size list, ie ( max-width: 30em ) 100%, ( max-width: 50em ) 50%, 33% // // or (min-width:30em) calc(30% - 15px) if ( !(sourceSizeListStr in sizeLengthCache) || cfg.uT ) { var winningLength = pf.calcLength( parseSizes( sourceSizeListStr ) ); sizeLengthCache[ sourceSizeListStr ] = !winningLength ? units.width : winningLength; } return sizeLengthCache[ sourceSizeListStr ]; }; /** * Takes a candidate object with a srcset property in the form of url/ * ex. "images/pic-medium.png 1x, images/pic-medium-2x.png 2x" or * "images/pic-medium.png 400w, images/pic-medium-2x.png 800w" or * "images/pic-small.png" * Get an array of image candidates in the form of * {url: "/foo/bar.png", resolution: 1} * where resolution is http://dev.w3.org/csswg/css-values-3/#resolution-value * If sizes is specified, res is calculated */ pf.setRes = function( set ) { var candidates; if ( set ) { candidates = pf.parseSet( set ); for ( var i = 0, len = candidates.length; i < len; i++ ) { setResolution( candidates[ i ], set.sizes ); } } return candidates; }; pf.setRes.res = setResolution; pf.applySetCandidate = function( candidates, img ) { if ( !candidates.length ) {return;} var candidate, i, j, length, bestCandidate, curSrc, curCan, candidateSrc, abortCurSrc; var imageData = img[ pf.ns ]; var dpr = pf.DPR; curSrc = imageData.curSrc || img[curSrcProp]; curCan = imageData.curCan || setSrcToCur(img, curSrc, candidates[0].set); // if we have a current source, we might either become lazy or give this source some advantage if ( curCan && curCan.set === candidates[ 0 ].set ) { // if browser can abort image request and the image has a higher pixel density than needed // and this image isn't downloaded yet, we skip next part and try to save bandwidth abortCurSrc = (supportAbort && !img.complete && curCan.res - 0.1 > dpr); if ( !abortCurSrc ) { curCan.cached = true; // if current candidate is "best", "better" or "okay", // set it to bestCandidate if ( curCan.res >= dpr ) { bestCandidate = curCan; } } } if ( !bestCandidate ) { candidates.sort( ascendingSort ); length = candidates.length; bestCandidate = candidates[ length - 1 ]; for ( i = 0; i < length; i++ ) { candidate = candidates[ i ]; if ( candidate.res >= dpr ) { j = i - 1; // we have found the perfect candidate, // but let's improve this a little bit with some assumptions ;-) if (candidates[ j ] && (abortCurSrc || curSrc !== pf.makeUrl( candidate.url )) && chooseLowRes(candidates[ j ].res, candidate.res, dpr, candidates[ j ].cached)) { bestCandidate = candidates[ j ]; } else { bestCandidate = candidate; } break; } } } if ( bestCandidate ) { candidateSrc = pf.makeUrl( bestCandidate.url ); imageData.curSrc = candidateSrc; imageData.curCan = bestCandidate; if ( candidateSrc !== curSrc ) { pf.setSrc( img, bestCandidate ); } pf.setSize( img ); } }; pf.setSrc = function( img, bestCandidate ) { var origWidth; img.src = bestCandidate.url; // although this is a specific Safari issue, we don't want to take too much different code paths if ( bestCandidate.set.type === "image/svg+xml" ) { origWidth = img.style.width; img.style.width = (img.offsetWidth + 1) + "px"; // next line only should trigger a repaint // if... is only done to trick dead code removal if ( img.offsetWidth + 1 ) { img.style.width = origWidth; } } }; pf.getSet = function( img ) { var i, set, supportsType; var match = false; var sets = img [ pf.ns ].sets; for ( i = 0; i < sets.length && !match; i++ ) { set = sets[i]; if ( !set.srcset || !pf.matchesMedia( set.media ) || !(supportsType = pf.supportsType( set.type )) ) { continue; } if ( supportsType === "pending" ) { set = supportsType; } match = set; break; } return match; }; pf.parseSets = function( element, parent, options ) { var srcsetAttribute, imageSet, isWDescripor, srcsetParsed; var hasPicture = parent && parent.nodeName.toUpperCase() === "PICTURE"; var imageData = element[ pf.ns ]; if ( imageData.src === undefined || options.src ) { imageData.src = getImgAttr.call( element, "src" ); if ( imageData.src ) { setImgAttr.call( element, srcAttr, imageData.src ); } else { removeImgAttr.call( element, srcAttr ); } } if ( imageData.srcset === undefined || options.srcset || !pf.supSrcset || element.srcset ) { srcsetAttribute = getImgAttr.call( element, "srcset" ); imageData.srcset = srcsetAttribute; srcsetParsed = true; } imageData.sets = []; if ( hasPicture ) { imageData.pic = true; getAllSourceElements( parent, imageData.sets ); } if ( imageData.srcset ) { imageSet = { srcset: imageData.srcset, sizes: getImgAttr.call( element, "sizes" ) }; imageData.sets.push( imageSet ); isWDescripor = (alwaysCheckWDescriptor || imageData.src) && regWDesc.test(imageData.srcset || ""); // add normal src as candidate, if source has no w descriptor if ( !isWDescripor && imageData.src && !getCandidateForSrc(imageData.src, imageSet) && !imageSet.has1x ) { imageSet.srcset += ", " + imageData.src; imageSet.cands.push({ url: imageData.src, d: 1, set: imageSet }); } } else if ( imageData.src ) { imageData.sets.push( { srcset: imageData.src, sizes: null } ); } imageData.curCan = null; imageData.curSrc = undefined; // if img has picture or the srcset was removed or has a srcset and does not support srcset at all // or has a w descriptor (and does not support sizes) set support to false to evaluate imageData.supported = !( hasPicture || ( imageSet && !pf.supSrcset ) || (isWDescripor && !pf.supSizes) ); if ( srcsetParsed && pf.supSrcset && !imageData.supported ) { if ( srcsetAttribute ) { setImgAttr.call( element, srcsetAttr, srcsetAttribute ); element.srcset = ""; } else { removeImgAttr.call( element, srcsetAttr ); } } if (imageData.supported && !imageData.srcset && ((!imageData.src && element.src) || element.src !== pf.makeUrl(imageData.src))) { if (imageData.src === null) { element.removeAttribute("src"); } else { element.src = imageData.src; } } imageData.parsed = true; }; pf.fillImg = function(element, options) { var imageData; var extreme = options.reselect || options.reevaluate; // expando for caching data on the img if ( !element[ pf.ns ] ) { element[ pf.ns ] = {}; } imageData = element[ pf.ns ]; // if the element has already been evaluated, skip it // unless `options.reevaluate` is set to true ( this, for example, // is set to true when running `picturefill` on `resize` ). if ( !extreme && imageData.evaled === evalId ) { return; } if ( !imageData.parsed || options.reevaluate ) { pf.parseSets( element, element.parentNode, options ); } if ( !imageData.supported ) { applyBestCandidate( element ); } else { imageData.evaled = evalId; } }; pf.setupRun = function() { if ( !alreadyRun || isVwDirty || (DPR !== window.devicePixelRatio) ) { updateMetrics(); } }; // If picture is supported, well, that's awesome. if ( pf.supPicture ) { picturefill = noop; pf.fillImg = noop; } else { // Set up picture polyfill by polling the document (function() { var isDomReady; var regReady = window.attachEvent ? /d$|^c/ : /d$|^c|^i/; var run = function() { var readyState = document.readyState || ""; timerId = setTimeout(run, readyState === "loading" ? 200 : 999); if ( document.body ) { pf.fillImgs(); isDomReady = isDomReady || regReady.test(readyState); if ( isDomReady ) { clearTimeout( timerId ); } } }; var timerId = setTimeout(run, document.body ? 9 : 99); // Also attach picturefill on resize and readystatechange // http://modernjavascript.blogspot.com/2013/08/building-better-debounce.html var debounce = function(func, wait) { var timeout, timestamp; var later = function() { var last = (new Date()) - timestamp; if (last < wait) { timeout = setTimeout(later, wait - last); } else { timeout = null; func(); } }; return function() { timestamp = new Date(); if (!timeout) { timeout = setTimeout(later, wait); } }; }; var lastClientWidth = docElem.clientHeight; var onResize = function() { isVwDirty = Math.max(window.innerWidth || 0, docElem.clientWidth) !== units.width || docElem.clientHeight !== lastClientWidth; lastClientWidth = docElem.clientHeight; if ( isVwDirty ) { pf.fillImgs(); } }; on( window, "resize", debounce(onResize, 99 ) ); on( document, "readystatechange", run ); })(); } pf.picturefill = picturefill; //use this internally for easy monkey patching/performance testing pf.fillImgs = picturefill; pf.teardownRun = noop; /* expose methods for testing */ picturefill._ = pf; window.picturefillCFG = { pf: pf, push: function(args) { var name = args.shift(); if (typeof pf[name] === "function") { pf[name].apply(pf, args); } else { cfg[name] = args[0]; if (alreadyRun) { pf.fillImgs( { reselect: true } ); } } } }; while (setOptions && setOptions.length) { window.picturefillCFG.push(setOptions.shift()); } /* expose picturefill */ window.picturefill = picturefill; /* expose picturefill */ if ( typeof module === "object" && typeof module.exports === "object" ) { // CommonJS, just export module.exports = picturefill; } else if ( typeof define === "function" && define.amd ) { // AMD support define( "picturefill", function() { return picturefill; } ); } // IE8 evals this sync, so it must be the last thing we do if ( !pf.supPicture ) { types[ "image/webp" ] = detectTypeSupport("image/webp", "data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA==" ); } } )( window, document ); /* * (c) Crealogix (Deutschland) AG, Projekt DKB. * * pint - a small javascript library that pins and unpins a menu bar on top of the screen. * * it uses two css classes to operate visibility of the top menu bar: * - pint-visible * - pint-hidden * pint uses a block element with position fixed to pin it to the top of the screen. If users * scrolls down the pinned element will get a new css class pint-hidden which in turn moves the top * out of sight. When the user scrolls up it puts the class pint-visible to the element which in * turn move the top back again into sight. It is a little bit tricky with the proper measures * of the top element so have a close look at the according css file (_dkb_search.css) * * When the user reaches the end of the page the top menu bar will be displayed as well. * * possible improvements: * parameter to control behaviour of the library * - at which screen size this library will operate. * - Toggle for menu at page end visible * */ jQuery("#dkb_banking_header").ready(function() { var ost = 0; //old screen top value var initialHeaderHeight = 0; // Works on firefox, chrome and ie. // mobile safari now ok. function is_page_end() { //Aufgrund der unterschiedlichen Contentl�nge in Gesch�ftskunden und Privatkunden, wurden 10px Tolleranz hinzugef�gt return (jQuery(window).scrollTop() < 1) ? true : ((document.body.scrollHeight - document.body.clientHeight ) - jQuery(window).scrollTop()) < 10; } function hidePint($header) { $header.addClass("pint-hidden").removeClass("pint-visible"); } function showPint($header) { if (! jQuery("#mobile_menu").hasClass("mm-opened")) { headerStickyReactivate($header); $header.css('position', 'fixed'); $header.addClass("pint-visible").removeClass("pint-hidden"); } } function headerStickyDeactivate($header) { $header.css('top','0px').css('position','absolute'); } function headerStickyReactivate($header) { $header.css('top','').css('position',''); } jQuery(document).ready(function() { handleStickyHeader(); jQuery(window).scroll(function() { handleStickyHeader(); }); jQuery(window).resize(function(){ initialHeaderHeight = 0; handleStickyHeader(); }); }); function handleStickyHeader() { var $htmlNode = jQuery('html'); if ($htmlNode.hasClass('headless_mode')) { return; } var $header = jQuery('#dkb_banking_header'); if (initialHeaderHeight == 0) { $header.css('padding-bottom','0'); initialHeaderHeight = $header.outerHeight(); } var newMarginContentTop = initialHeaderHeight + 25; jQuery('#contentHome').css('padding-top', newMarginContentTop + 'px'); if (($htmlNode.hasClass('portal_app') || $htmlNode.hasClass('map_app')) && $htmlNode.hasClass('is_apple_device') && jQuery('body').hasClass('hasModalOverlay')) { hidePint($header); } else { var nst = jQuery(this).scrollTop(); //console.log('nst: ' + nst + " - ost: " + ost + " - newMarginContentTop:" + newMarginContentTop); if (nst < newMarginContentTop) { if (!$header.hasClass("pint-visible") || nst <= 0) { $header.removeClass("pint-visible"); headerStickyDeactivate($header); } } else { if (nst < ost) { // scroll up showPint($header); } else { if (is_page_end() && is_touch_device()) { showPint($header); } else { hidePint($header); } } //DKBIB-5699: Stickyheader problem if keypad is visible if ($htmlNode.hasClass('pint-disable')) { headerStickyDeactivate($header); } } ost = nst; } } }); /** * jquery.mask.js * @version: v1.14.8 * @author: Igor Escobar * * Created by Igor Escobar on 2012-03-10. Please report any bug at http://blog.igorescobar.com * * Copyright (c) 2012 Igor Escobar http://blog.igorescobar.com * * The MIT License (http://www.opensource.org/licenses/mit-license.php) * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /* jshint laxbreak: true */ /* jshint maxcomplexity:17 */ /* global define */ 'use strict'; // UMD (Universal Module Definition) patterns for JavaScript modules that work everywhere. // https://github.com/umdjs/umd/blob/master/jqueryPluginCommonjs.js (function (factory, jQuery, Zepto) { if (typeof define === 'function' && define.amd) { define(['jquery'], factory); } else if (typeof exports === 'object') { module.exports = factory(require('jquery')); } else { factory(jQuery || Zepto); } }(function ($) { var Mask = function (el, mask, options) { var p = { invalid: [], getCaret: function () { try { var sel, pos = 0, ctrl = el.get(0), dSel = document.selection, cSelStart = ctrl.selectionStart; // IE Support if (dSel && navigator.appVersion.indexOf('MSIE 10') === -1) { sel = dSel.createRange(); sel.moveStart('character', -p.val().length); pos = sel.text.length; } // Firefox support else if (cSelStart || cSelStart === '0') { pos = cSelStart; } return pos; } catch (e) {} }, setCaret: function(pos) { try { if (el.is(':focus')) { var range, ctrl = el.get(0); // Firefox, WebKit, etc.. if (ctrl.setSelectionRange) { ctrl.setSelectionRange(pos, pos); } else { // IE range = ctrl.createTextRange(); range.collapse(true); range.moveEnd('character', pos); range.moveStart('character', pos); range.select(); } } } catch (e) {} }, events: function() { el .on('keydown.mask', function(e) { el.data('mask-keycode', e.keyCode || e.which); el.data('mask-previus-value', el.val()); }) .on($.jMaskGlobals.useInput ? 'input.mask' : 'keyup.mask', p.behaviour) .on('paste.mask drop.mask', function() { setTimeout(function() { el.keydown().keyup(); }, 100); }) .on('change.mask', function(){ el.data('changed', true); }) .on('blur.mask', function(){ if (oldValue !== p.val() && !el.data('changed')) { el.trigger('change'); } el.data('changed', false); }) // it's very important that this callback remains in this position // otherwhise oldValue it's going to work buggy .on('blur.mask', function() { oldValue = p.val(); }) // select all text on focus .on('focus.mask', function (e) { if (options.selectOnFocus === true) { $(e.target).select(); } }) // clear the value if it not complete the mask .on('focusout.mask', function() { if (options.clearIfNotMatch && !regexMask.test(p.val())) { p.val(''); } }); }, getRegexMask: function() { var maskChunks = [], translation, pattern, optional, recursive, oRecursive, r; for (var i = 0; i < mask.length; i++) { translation = jMask.translation[mask.charAt(i)]; if (translation) { pattern = translation.pattern.toString().replace(/.{1}$|^.{1}/g, ''); optional = translation.optional; recursive = translation.recursive; if (recursive) { maskChunks.push(mask.charAt(i)); oRecursive = {digit: mask.charAt(i), pattern: pattern}; } else { maskChunks.push(!optional && !recursive ? pattern : (pattern + '?')); } } else { maskChunks.push(mask.charAt(i).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')); } } r = maskChunks.join(''); if (oRecursive) { r = r.replace(new RegExp('(' + oRecursive.digit + '(.*' + oRecursive.digit + ')?)'), '($1)?') .replace(new RegExp(oRecursive.digit, 'g'), oRecursive.pattern); } return new RegExp(r); }, destroyEvents: function() { el.off(['input', 'keydown', 'keyup', 'paste', 'drop', 'blur', 'focusout', ''].join('.mask ')); }, val: function(v) { var isInput = el.is('input'), method = isInput ? 'val' : 'text', r; if (arguments.length > 0) { if (el[method]() !== v) { el[method](v); } r = el; } else { r = el[method](); } return r; }, calculateCaretPosition: function(caretPos, newVal) { var newValL = newVal.length, oValue = el.data('mask-previus-value'), oValueL = oValue.length; // edge cases when erasing digits if (el.data('mask-keycode') === 8 && oValue !== newVal) { caretPos = caretPos - (newVal.slice(0, caretPos).length - oValue.slice(0, caretPos).length); // edge cases when typing new digits } else if (oValue !== newVal) { // if the cursor is at the end keep it there if (caretPos >= oValueL) { caretPos = newValL; } else { caretPos = caretPos + (newVal.slice(0, caretPos).length - oValue.slice(0, caretPos).length); } } return caretPos; }, behaviour: function(e) { e = e || window.event; p.invalid = []; var keyCode = el.data('mask-keycode'); if ($.inArray(keyCode, jMask.byPassKeys) === -1) { var newVal = p.getMasked(), caretPos = p.getCaret(); setTimeout(function(caretPos, newVal) { p.setCaret(p.calculateCaretPosition(caretPos, newVal)); }, 10, caretPos, newVal); p.val(newVal); p.setCaret(caretPos); return p.callbacks(e); } }, getMasked: function(skipMaskChars, val) { var buf = [], value = val === undefined ? p.val() : val + '', m = 0, maskLen = mask.length, v = 0, valLen = value.length, offset = 1, addMethod = 'push', resetPos = -1, lastMaskChar, check; if (options.reverse) { addMethod = 'unshift'; offset = -1; lastMaskChar = 0; m = maskLen - 1; v = valLen - 1; check = function () { return m > -1 && v > -1; }; } else { lastMaskChar = maskLen - 1; check = function () { return m < maskLen && v < valLen; }; } var lastUntranslatedMaskChar; while (check()) { var maskDigit = mask.charAt(m), valDigit = value.charAt(v), translation = jMask.translation[maskDigit]; if (translation) { if (valDigit.match(translation.pattern)) { buf[addMethod](valDigit); if (translation.recursive) { if (resetPos === -1) { resetPos = m; } else if (m === lastMaskChar) { m = resetPos - offset; } if (lastMaskChar === resetPos) { m -= offset; } } m += offset; } else if (valDigit === lastUntranslatedMaskChar) { // matched the last untranslated (raw) mask character that we encountered // likely an insert offset the mask character from the last entry; fall // through and only increment v lastUntranslatedMaskChar = undefined; } else if (translation.optional) { m += offset; v -= offset; } else if (translation.fallback) { buf[addMethod](translation.fallback); m += offset; v -= offset; } else { p.invalid.push({p: v, v: valDigit, e: translation.pattern}); } v += offset; } else { if (!skipMaskChars) { buf[addMethod](maskDigit); } if (valDigit === maskDigit) { v += offset; } else { lastUntranslatedMaskChar = maskDigit; } m += offset; } } var lastMaskCharDigit = mask.charAt(lastMaskChar); if (maskLen === valLen + 1 && !jMask.translation[lastMaskCharDigit]) { buf.push(lastMaskCharDigit); } return buf.join(''); }, callbacks: function (e) { var val = p.val(), changed = val !== oldValue, defaultArgs = [val, e, el, options], callback = function(name, criteria, args) { if (typeof options[name] === 'function' && criteria) { options[name].apply(this, args); } }; callback('onChange', changed === true, defaultArgs); callback('onKeyPress', changed === true, defaultArgs); callback('onComplete', val.length === mask.length, defaultArgs); callback('onInvalid', p.invalid.length > 0, [val, e, el, p.invalid, options]); } }; el = $(el); var jMask = this, oldValue = p.val(), regexMask; mask = typeof mask === 'function' ? mask(p.val(), undefined, el, options) : mask; // public methods jMask.mask = mask; jMask.options = options; jMask.remove = function() { var caret = p.getCaret(); p.destroyEvents(); p.val(jMask.getCleanVal()); p.setCaret(caret); return el; }; // get value without mask jMask.getCleanVal = function() { return p.getMasked(true); }; // get masked value without the value being in the input or element jMask.getMaskedVal = function(val) { return p.getMasked(false, val); }; jMask.init = function(onlyMask) { onlyMask = onlyMask || false; options = options || {}; jMask.clearIfNotMatch = $.jMaskGlobals.clearIfNotMatch; jMask.byPassKeys = $.jMaskGlobals.byPassKeys; jMask.translation = $.extend({}, $.jMaskGlobals.translation, options.translation); jMask = $.extend(true, {}, jMask, options); regexMask = p.getRegexMask(); if (onlyMask) { p.events(); p.val(p.getMasked()); } else { if (options.placeholder) { el.attr('placeholder' , options.placeholder); } // this is necessary, otherwise if the user submit the form // and then press the "back" button, the autocomplete will erase // the data. Works fine on IE9+, FF, Opera, Safari. if (el.data('mask')) { el.attr('autocomplete', 'off'); } // detect if is necessary let the user type freely. // for is a lot faster than forEach. for (var i = 0, maxlength = true; i < mask.length; i++) { var translation = jMask.translation[mask.charAt(i)]; if (translation && translation.recursive) { maxlength = false; break; } } if (maxlength) { el.attr('maxlength', mask.length); } p.destroyEvents(); p.events(); var caret = p.getCaret(); p.val(p.getMasked()); p.setCaret(caret); } }; jMask.init(!el.is('input')); }; $.maskWatchers = {}; var HTMLAttributes = function () { var input = $(this), options = {}, prefix = 'data-mask-', mask = input.attr('data-mask'); if (input.attr(prefix + 'reverse')) { options.reverse = true; } if (input.attr(prefix + 'clearifnotmatch')) { options.clearIfNotMatch = true; } if (input.attr(prefix + 'selectonfocus') === 'true') { options.selectOnFocus = true; } if (notSameMaskObject(input, mask, options)) { return input.data('mask', new Mask(this, mask, options)); } }, notSameMaskObject = function(field, mask, options) { options = options || {}; var maskObject = $(field).data('mask'), stringify = JSON.stringify, value = $(field).val() || $(field).text(); try { if (typeof mask === 'function') { mask = mask(value); } return typeof maskObject !== 'object' || stringify(maskObject.options) !== stringify(options) || maskObject.mask !== mask; } catch (e) {} }, eventSupported = function(eventName) { var el = document.createElement('div'), isSupported; eventName = 'on' + eventName; isSupported = (eventName in el); if ( !isSupported ) { el.setAttribute(eventName, 'return;'); isSupported = typeof el[eventName] === 'function'; } el = null; return isSupported; }; $.fn.mask = function(mask, options) { options = options || {}; var selector = this.selector, globals = $.jMaskGlobals, interval = globals.watchInterval, watchInputs = options.watchInputs || globals.watchInputs, maskFunction = function() { if (notSameMaskObject(this, mask, options)) { return $(this).data('mask', new Mask(this, mask, options)); } }; $(this).each(maskFunction); if (selector && selector !== '' && watchInputs) { clearInterval($.maskWatchers[selector]); $.maskWatchers[selector] = setInterval(function(){ $(document).find(selector).each(maskFunction); }, interval); } return this; }; $.fn.masked = function(val) { return this.data('mask').getMaskedVal(val); }; $.fn.unmask = function() { clearInterval($.maskWatchers[this.selector]); delete $.maskWatchers[this.selector]; return this.each(function() { var dataMask = $(this).data('mask'); if (dataMask) { dataMask.remove().removeData('mask'); } }); }; $.fn.cleanVal = function() { return this.data('mask').getCleanVal(); }; $.applyDataMask = function(selector) { selector = selector || $.jMaskGlobals.maskElements; var $selector = (selector instanceof $) ? selector : $(selector); $selector.filter($.jMaskGlobals.dataMaskAttr).each(HTMLAttributes); }; var globals = { maskElements: 'input,td,span,div', dataMaskAttr: '*[data-mask]', dataMask: true, watchInterval: 300, watchInputs: true, // old versions of chrome dont work great with input event useInput: !/Chrome\/[2-4][0-9]|SamsungBrowser/.test(window.navigator.userAgent) && eventSupported('input'), watchDataMask: false, byPassKeys: [9, 16, 17, 18, 36, 37, 38, 39, 40, 91], translation: { '0': {pattern: /\d/}, '9': {pattern: /\d/, optional: true}, '#': {pattern: /\d/, recursive: true}, 'A': {pattern: /[a-zA-Z0-9]/}, 'S': {pattern: /[a-zA-Z]/} } }; $.jMaskGlobals = $.jMaskGlobals || {}; globals = $.jMaskGlobals = $.extend(true, {}, globals, $.jMaskGlobals); // looking for inputs with data-mask attribute if (globals.dataMask) { $.applyDataMask(); } setInterval(function() { if ($.jMaskGlobals.watchDataMask) { $.applyDataMask(); } }, globals.watchInterval); }, window.jQuery, window.Zepto)); // DKBIB-8297 start // Dynatrace-Tracking von externen Links // Hinweis: Dynatrace nur ab Abnahme-Umgebung verf�gbar function handleDynatraceTracking() { if (!isDynaTraceAvailable()) { return; } jQuery('a[target=_blank]').each(function () { jQuery(this).off('click', trackTargetBlankLinkClick).on('click', trackTargetBlankLinkClick); }); } var dtTrackInProgress = false; function trackTargetBlankLinkClick(e) { var $link = jQuery(this); var targetHref = $link.attr('href'); if (targetHref != undefined && targetHref.indexOf('http') == 0) { e.preventDefault(); e.stopPropagation(); var $link = jQuery(this); var trackMsg = $link.attr('name'); var targetHref = $link.attr('href'); if (trackMsg == undefined) { trackMsg = $link.html(); } if (trackMsg == undefined || trackMsg.length < 3) { trackMsg = targetHref; } dtTrackAndRedirectToBlank(trackMsg, targetHref); } } function dtTrackAndRedirectToBlank(_trackMsg, _url) { if (dtTrackInProgress == false) { dtTrackInProgress = true; dtrum.leaveAction(dtrum.enterAction(_trackMsg,'click')); setTimeout(function(){ window.open(_url,'_blank') }, 200); setTimeout(function(){ dtTrackInProgress = false; }, 500); } } // DKBIB-8297 end; /** * Copyright 2016 Google Inc. All Rights Reserved. * * Licensed under the W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE. * * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document * */ (function(window, document) { 'use strict'; // Exits early if all IntersectionObserver and IntersectionObserverEntry // features are natively supported. if ('IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype) { // Minimal polyfill for Edge 15's lack of `isIntersecting` // See: https://github.com/w3c/IntersectionObserver/issues/211 if (!('isIntersecting' in window.IntersectionObserverEntry.prototype)) { Object.defineProperty(window.IntersectionObserverEntry.prototype, 'isIntersecting', { get: function () { return this.intersectionRatio > 0; } }); } return; } /** * An IntersectionObserver registry. This registry exists to hold a strong * reference to IntersectionObserver instances currently observing a target * element. Without this registry, instances without another reference may be * garbage collected. */ var registry = []; /** * Creates the global IntersectionObserverEntry constructor. * https://w3c.github.io/IntersectionObserver/#intersection-observer-entry * @param {Object} entry A dictionary of instance properties. * @constructor */ function IntersectionObserverEntry(entry) { this.time = entry.time; this.target = entry.target; this.rootBounds = entry.rootBounds; this.boundingClientRect = entry.boundingClientRect; this.intersectionRect = entry.intersectionRect || getEmptyRect(); this.isIntersecting = !!entry.intersectionRect; // Calculates the intersection ratio. var targetRect = this.boundingClientRect; var targetArea = targetRect.width * targetRect.height; var intersectionRect = this.intersectionRect; var intersectionArea = intersectionRect.width * intersectionRect.height; // Sets intersection ratio. if (targetArea) { // Round the intersection ratio to avoid floating point math issues: // https://github.com/w3c/IntersectionObserver/issues/324 this.intersectionRatio = Number((intersectionArea / targetArea).toFixed(4)); } else { // If area is zero and is intersecting, sets to 1, otherwise to 0 this.intersectionRatio = this.isIntersecting ? 1 : 0; } } /** * Creates the global IntersectionObserver constructor. * https://w3c.github.io/IntersectionObserver/#intersection-observer-interface * @param {Function} callback The function to be invoked after intersection * changes have queued. The function is not invoked if the queue has * been emptied by calling the `takeRecords` method. * @param {Object=} opt_options Optional configuration options. * @constructor */ function IntersectionObserver(callback, opt_options) { var options = opt_options || {}; if (typeof callback != 'function') { throw new Error('callback must be a function'); } if (options.root && options.root.nodeType != 1) { throw new Error('root must be an Element'); } // Binds and throttles `this._checkForIntersections`. this._checkForIntersections = throttle( this._checkForIntersections.bind(this), this.THROTTLE_TIMEOUT); // Private properties. this._callback = callback; this._observationTargets = []; this._queuedEntries = []; this._rootMarginValues = this._parseRootMargin(options.rootMargin); // Public properties. this.thresholds = this._initThresholds(options.threshold); this.root = options.root || null; this.rootMargin = this._rootMarginValues.map(function(margin) { return margin.value + margin.unit; }).join(' '); } /** * The minimum interval within which the document will be checked for * intersection changes. */ IntersectionObserver.prototype.THROTTLE_TIMEOUT = 100; /** * The frequency in which the polyfill polls for intersection changes. * this can be updated on a per instance basis and must be set prior to * calling `observe` on the first target. */ IntersectionObserver.prototype.POLL_INTERVAL = null; /** * Use a mutation observer on the root element * to detect intersection changes. */ IntersectionObserver.prototype.USE_MUTATION_OBSERVER = true; /** * Starts observing a target element for intersection changes based on * the thresholds values. * @param {Element} target The DOM element to observe. */ IntersectionObserver.prototype.observe = function(target) { var isTargetAlreadyObserved = this._observationTargets.some(function(item) { return item.element == target; }); if (isTargetAlreadyObserved) { return; } if (!(target && target.nodeType == 1)) { throw new Error('target must be an Element'); } this._registerInstance(); this._observationTargets.push({element: target, entry: null}); this._monitorIntersections(); this._checkForIntersections(); }; /** * Stops observing a target element for intersection changes. * @param {Element} target The DOM element to observe. */ IntersectionObserver.prototype.unobserve = function(target) { this._observationTargets = this._observationTargets.filter(function(item) { return item.element != target; }); if (!this._observationTargets.length) { this._unmonitorIntersections(); this._unregisterInstance(); } }; /** * Stops observing all target elements for intersection changes. */ IntersectionObserver.prototype.disconnect = function() { this._observationTargets = []; this._unmonitorIntersections(); this._unregisterInstance(); }; /** * Returns any queue entries that have not yet been reported to the * callback and clears the queue. This can be used in conjunction with the * callback to obtain the absolute most up-to-date intersection information. * @return {Array} The currently queued entries. */ IntersectionObserver.prototype.takeRecords = function() { var records = this._queuedEntries.slice(); this._queuedEntries = []; return records; }; /** * Accepts the threshold value from the user configuration object and * returns a sorted array of unique threshold values. If a value is not * between 0 and 1 and error is thrown. * @private * @param {Array|number=} opt_threshold An optional threshold value or * a list of threshold values, defaulting to [0]. * @return {Array} A sorted list of unique and valid threshold values. */ IntersectionObserver.prototype._initThresholds = function(opt_threshold) { var threshold = opt_threshold || [0]; if (!Array.isArray(threshold)) threshold = [threshold]; return threshold.sort().filter(function(t, i, a) { if (typeof t != 'number' || isNaN(t) || t < 0 || t > 1) { throw new Error('threshold must be a number between 0 and 1 inclusively'); } return t !== a[i - 1]; }); }; /** * Accepts the rootMargin value from the user configuration object * and returns an array of the four margin values as an object containing * the value and unit properties. If any of the values are not properly * formatted or use a unit other than px or %, and error is thrown. * @private * @param {string=} opt_rootMargin An optional rootMargin value, * defaulting to '0px'. * @return {Array<Object>} An array of margin objects with the keys * value and unit. */ IntersectionObserver.prototype._parseRootMargin = function(opt_rootMargin) { var marginString = opt_rootMargin || '0px'; var margins = marginString.split(/\s+/).map(function(margin) { var parts = /^(-?\d*\.?\d+)(px|%)$/.exec(margin); if (!parts) { throw new Error('rootMargin must be specified in pixels or percent'); } return {value: parseFloat(parts[1]), unit: parts[2]}; }); // Handles shorthand. margins[1] = margins[1] || margins[0]; margins[2] = margins[2] || margins[0]; margins[3] = margins[3] || margins[1]; return margins; }; /** * Starts polling for intersection changes if the polling is not already * happening, and if the page's visibility state is visible. * @private */ IntersectionObserver.prototype._monitorIntersections = function() { if (!this._monitoringIntersections) { this._monitoringIntersections = true; // If a poll interval is set, use polling instead of listening to // resize and scroll events or DOM mutations. if (this.POLL_INTERVAL) { this._monitoringInterval = setInterval( this._checkForIntersections, this.POLL_INTERVAL); } else { addEvent(window, 'resize', this._checkForIntersections, true); addEvent(document, 'scroll', this._checkForIntersections, true); if (this.USE_MUTATION_OBSERVER && 'MutationObserver' in window) { this._domObserver = new MutationObserver(this._checkForIntersections); this._domObserver.observe(document, { attributes: true, childList: true, characterData: true, subtree: true }); } } } }; /** * Stops polling for intersection changes. * @private */ IntersectionObserver.prototype._unmonitorIntersections = function() { if (this._monitoringIntersections) { this._monitoringIntersections = false; clearInterval(this._monitoringInterval); this._monitoringInterval = null; removeEvent(window, 'resize', this._checkForIntersections, true); removeEvent(document, 'scroll', this._checkForIntersections, true); if (this._domObserver) { this._domObserver.disconnect(); this._domObserver = null; } } }; /** * Scans each observation target for intersection changes and adds them * to the internal entries queue. If new entries are found, it * schedules the callback to be invoked. * @private */ IntersectionObserver.prototype._checkForIntersections = function() { var rootIsInDom = this._rootIsInDom(); var rootRect = rootIsInDom ? this._getRootRect() : getEmptyRect(); this._observationTargets.forEach(function(item) { var target = item.element; var targetRect = getBoundingClientRect(target); var rootContainsTarget = this._rootContainsTarget(target); var oldEntry = item.entry; var intersectionRect = rootIsInDom && rootContainsTarget && this._computeTargetAndRootIntersection(target, rootRect); var newEntry = item.entry = new IntersectionObserverEntry({ time: now(), target: target, boundingClientRect: targetRect, rootBounds: rootRect, intersectionRect: intersectionRect }); if (!oldEntry) { this._queuedEntries.push(newEntry); } else if (rootIsInDom && rootContainsTarget) { // If the new entry intersection ratio has crossed any of the // thresholds, add a new entry. if (this._hasCrossedThreshold(oldEntry, newEntry)) { this._queuedEntries.push(newEntry); } } else { // If the root is not in the DOM or target is not contained within // root but the previous entry for this target had an intersection, // add a new record indicating removal. if (oldEntry && oldEntry.isIntersecting) { this._queuedEntries.push(newEntry); } } }, this); if (this._queuedEntries.length) { this._callback(this.takeRecords(), this); } }; /** * Accepts a target and root rect computes the intersection between then * following the algorithm in the spec. * TODO(philipwalton): at this time clip-path is not considered. * https://w3c.github.io/IntersectionObserver/#calculate-intersection-rect-algo * @param {Element} target The target DOM element * @param {Object} rootRect The bounding rect of the root after being * expanded by the rootMargin value. * @return {?Object} The final intersection rect object or undefined if no * intersection is found. * @private */ IntersectionObserver.prototype._computeTargetAndRootIntersection = function(target, rootRect) { // If the element isn't displayed, an intersection can't happen. if (window.getComputedStyle(target).display == 'none') return; var targetRect = getBoundingClientRect(target); var intersectionRect = targetRect; var parent = getParentNode(target); var atRoot = false; while (!atRoot) { var parentRect = null; var parentComputedStyle = parent.nodeType == 1 ? window.getComputedStyle(parent) : {}; // If the parent isn't displayed, an intersection can't happen. if (parentComputedStyle.display == 'none') return; if (parent == this.root || parent == document) { atRoot = true; parentRect = rootRect; } else { // If the element has a non-visible overflow, and it's not the <body> // or <html> element, update the intersection rect. // Note: <body> and <html> cannot be clipped to a rect that's not also // the document rect, so no need to compute a new intersection. if (parent != document.body && parent != document.documentElement && parentComputedStyle.overflow != 'visible') { parentRect = getBoundingClientRect(parent); } } // If either of the above conditionals set a new parentRect, // calculate new intersection data. if (parentRect) { intersectionRect = computeRectIntersection(parentRect, intersectionRect); if (!intersectionRect) break; } parent = getParentNode(parent); } return intersectionRect; }; /** * Returns the root rect after being expanded by the rootMargin value. * @return {Object} The expanded root rect. * @private */ IntersectionObserver.prototype._getRootRect = function() { var rootRect; if (this.root) { rootRect = getBoundingClientRect(this.root); } else { // Use <html>/<body> instead of window since scroll bars affect size. var html = document.documentElement; var body = document.body; rootRect = { top: 0, left: 0, right: html.clientWidth || body.clientWidth, width: html.clientWidth || body.clientWidth, bottom: html.clientHeight || body.clientHeight, height: html.clientHeight || body.clientHeight }; } return this._expandRectByRootMargin(rootRect); }; /** * Accepts a rect and expands it by the rootMargin value. * @param {Object} rect The rect object to expand. * @return {Object} The expanded rect. * @private */ IntersectionObserver.prototype._expandRectByRootMargin = function(rect) { var margins = this._rootMarginValues.map(function(margin, i) { return margin.unit == 'px' ? margin.value : margin.value * (i % 2 ? rect.width : rect.height) / 100; }); var newRect = { top: rect.top - margins[0], right: rect.right + margins[1], bottom: rect.bottom + margins[2], left: rect.left - margins[3] }; newRect.width = newRect.right - newRect.left; newRect.height = newRect.bottom - newRect.top; return newRect; }; /** * Accepts an old and new entry and returns true if at least one of the * threshold values has been crossed. * @param {?IntersectionObserverEntry} oldEntry The previous entry for a * particular target element or null if no previous entry exists. * @param {IntersectionObserverEntry} newEntry The current entry for a * particular target element. * @return {boolean} Returns true if a any threshold has been crossed. * @private */ IntersectionObserver.prototype._hasCrossedThreshold = function(oldEntry, newEntry) { // To make comparing easier, an entry that has a ratio of 0 // but does not actually intersect is given a value of -1 var oldRatio = oldEntry && oldEntry.isIntersecting ? oldEntry.intersectionRatio || 0 : -1; var newRatio = newEntry.isIntersecting ? newEntry.intersectionRatio || 0 : -1; // Ignore unchanged ratios if (oldRatio === newRatio) return; for (var i = 0; i < this.thresholds.length; i++) { var threshold = this.thresholds[i]; // Return true if an entry matches a threshold or if the new ratio // and the old ratio are on the opposite sides of a threshold. if (threshold == oldRatio || threshold == newRatio || threshold < oldRatio !== threshold < newRatio) { return true; } } }; /** * Returns whether or not the root element is an element and is in the DOM. * @return {boolean} True if the root element is an element and is in the DOM. * @private */ IntersectionObserver.prototype._rootIsInDom = function() { return !this.root || containsDeep(document, this.root); }; /** * Returns whether or not the target element is a child of root. * @param {Element} target The target element to check. * @return {boolean} True if the target element is a child of root. * @private */ IntersectionObserver.prototype._rootContainsTarget = function(target) { return containsDeep(this.root || document, target); }; /** * Adds the instance to the global IntersectionObserver registry if it isn't * already present. * @private */ IntersectionObserver.prototype._registerInstance = function() { if (registry.indexOf(this) < 0) { registry.push(this); } }; /** * Removes the instance from the global IntersectionObserver registry. * @private */ IntersectionObserver.prototype._unregisterInstance = function() { var index = registry.indexOf(this); if (index != -1) registry.splice(index, 1); }; /** * Returns the result of the performance.now() method or null in browsers * that don't support the API. * @return {number} The elapsed time since the page was requested. */ function now() { return window.performance && performance.now && performance.now(); } /** * Throttles a function and delays its execution, so it's only called at most * once within a given time period. * @param {Function} fn The function to throttle. * @param {number} timeout The amount of time that must pass before the * function can be called again. * @return {Function} The throttled function. */ function throttle(fn, timeout) { var timer = null; return function () { if (!timer) { timer = setTimeout(function() { fn(); timer = null; }, timeout); } }; } /** * Adds an event handler to a DOM node ensuring cross-browser compatibility. * @param {Node} node The DOM node to add the event handler to. * @param {string} event The event name. * @param {Function} fn The event handler to add. * @param {boolean} opt_useCapture Optionally adds the even to the capture * phase. Note: this only works in modern browsers. */ function addEvent(node, event, fn, opt_useCapture) { if (typeof node.addEventListener == 'function') { node.addEventListener(event, fn, opt_useCapture || false); } else if (typeof node.attachEvent == 'function') { node.attachEvent('on' + event, fn); } } /** * Removes a previously added event handler from a DOM node. * @param {Node} node The DOM node to remove the event handler from. * @param {string} event The event name. * @param {Function} fn The event handler to remove. * @param {boolean} opt_useCapture If the event handler was added with this * flag set to true, it should be set to true here in order to remove it. */ function removeEvent(node, event, fn, opt_useCapture) { if (typeof node.removeEventListener == 'function') { node.removeEventListener(event, fn, opt_useCapture || false); } else if (typeof node.detatchEvent == 'function') { node.detatchEvent('on' + event, fn); } } /** * Returns the intersection between two rect objects. * @param {Object} rect1 The first rect. * @param {Object} rect2 The second rect. * @return {?Object} The intersection rect or undefined if no intersection * is found. */ function computeRectIntersection(rect1, rect2) { var top = Math.max(rect1.top, rect2.top); var bottom = Math.min(rect1.bottom, rect2.bottom); var left = Math.max(rect1.left, rect2.left); var right = Math.min(rect1.right, rect2.right); var width = right - left; var height = bottom - top; return (width >= 0 && height >= 0) && { top: top, bottom: bottom, left: left, right: right, width: width, height: height }; } /** * Shims the native getBoundingClientRect for compatibility with older IE. * @param {Element} el The element whose bounding rect to get. * @return {Object} The (possibly shimmed) rect of the element. */ function getBoundingClientRect(el) { var rect; try { rect = el.getBoundingClientRect(); } catch (err) { // Ignore Windows 7 IE11 "Unspecified error" // https://github.com/w3c/IntersectionObserver/pull/205 } if (!rect) return getEmptyRect(); // Older IE if (!(rect.width && rect.height)) { rect = { top: rect.top, right: rect.right, bottom: rect.bottom, left: rect.left, width: rect.right - rect.left, height: rect.bottom - rect.top }; } return rect; } /** * Returns an empty rect object. An empty rect is returned when an element * is not in the DOM. * @return {Object} The empty rect. */ function getEmptyRect() { return { top: 0, bottom: 0, left: 0, right: 0, width: 0, height: 0 }; } /** * Checks to see if a parent element contains a child element (including inside * shadow DOM). * @param {Node} parent The parent element. * @param {Node} child The child element. * @return {boolean} True if the parent node contains the child node. */ function containsDeep(parent, child) { var node = child; while (node) { if (node == parent) return true; node = getParentNode(node); } return false; } /** * Gets the parent node of an element or its host element if the parent node * is a shadow root. * @param {Node} node The node whose parent to get. * @return {Node|null} The parent node or null if no parent exists. */ function getParentNode(node) { var parent = node.parentNode; if (parent && parent.nodeType == 11 && parent.host) { // If the parent is a shadow root, return the host element. return parent.host; } if (parent && parent.assignedSlot) { // If the parent is distributed in a <slot>, return the parent of a slot. return parent.assignedSlot.parentNode; } return parent; } // Exposes the constructors globally. window.IntersectionObserver = IntersectionObserver; window.IntersectionObserverEntry = IntersectionObserverEntry; }(window, document)); /* German initialisation for the jQuery UI date picker plugin. */ /*jslint white:true */ /*global jQuery */ /* Written by Milian Wolff (mail@milianw.de). */ Abaxx.core.onReady(function () { "use strict"; jQuery.datepicker.regional.de = { closeText:'Schließen', prevText:'Zurück', nextText:'Vor', currentText:'Heute', monthNames:['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'], monthNamesShort:['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'], dayNames:['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'], dayNamesShort:['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'], dayNamesMin:['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'], weekHeader:'Wo', firstDay:1, isRTL:false, showMonthAfterYear:false, yearSuffix:'', // localization for timepicker plugin: amNames: ["AM", "A"], pmNames: ["PM", "P"], timeOnlyTitle: "Uhrzeit wählen", timeText: "Uhrzeit", hourText: "Stunden", minuteText: "Minuten", secondText: "Sekunden", millisecText: "Millisekunden", timezonText: "Zeitzone" }; // $.datepicker.setDefaults($.datepicker.regional.de); }); /* * jQuery timepicker addon * By: Trent Richardson [http://trentrichardson.com] * Version 1.1.1 * Last Modified: 11/07/2012 * * Copyright 2012 Trent Richardson * You may use this project under MIT or GPL licenses. * http://trentrichardson.com/Impromptu/GPL-LICENSE.txt * http://trentrichardson.com/Impromptu/MIT-LICENSE.txt */ /*jslint evil: true, white: false, undef: false, nomen: false */ (function($) { /* * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded" */ $.ui.timepicker = $.ui.timepicker || {}; if ($.ui.timepicker.version) { return; } /* * Extend jQueryUI, get it started with our version number */ $.extend($.ui, { timepicker: { version: "1.1.1" } }); /* * Timepicker manager. * Use the singleton instance of this class, $.timepicker, to interact with the time picker. * Settings for (groups of) time pickers are maintained in an instance object, * allowing multiple different settings on the same page. */ function Timepicker() { this.regional = []; // Available regional settings, indexed by language code this.regional[''] = { // Default regional settings currentText: 'Now', closeText: 'Done', amNames: ['AM', 'A'], pmNames: ['PM', 'P'], timeFormat: 'HH:mm', timeSuffix: '', timeOnlyTitle: 'Choose Time', timeText: 'Time', hourText: 'Hour', minuteText: 'Minute', secondText: 'Second', millisecText: 'Millisecond', timezoneText: 'Time Zone', isRTL: false }; this._defaults = { // Global defaults for all the datetime picker instances showButtonPanel: true, timeOnly: false, showHour: true, showMinute: true, showSecond: false, showMillisec: false, showTimezone: false, showTime: true, stepHour: 1, stepMinute: 1, stepSecond: 1, stepMillisec: 1, hour: 0, minute: 0, second: 0, millisec: 0, timezone: null, useLocalTimezone: false, defaultTimezone: "+0000", hourMin: 0, minuteMin: 0, secondMin: 0, millisecMin: 0, hourMax: 23, minuteMax: 59, secondMax: 59, millisecMax: 999, minDateTime: null, maxDateTime: null, onSelect: null, hourGrid: 0, minuteGrid: 0, secondGrid: 0, millisecGrid: 0, alwaysSetTime: true, separator: ' ', altFieldTimeOnly: true, altTimeFormat: null, altSeparator: null, altTimeSuffix: null, pickerTimeFormat: null, pickerTimeSuffix: null, showTimepicker: true, timezoneIso8601: false, timezoneList: null, addSliderAccess: false, sliderAccessArgs: null, controlType: 'slider', defaultValue: null, parse: 'strict' }; $.extend(this._defaults, this.regional['']); } $.extend(Timepicker.prototype, { $input: null, $altInput: null, $timeObj: null, inst: null, hour_slider: null, minute_slider: null, second_slider: null, millisec_slider: null, timezone_select: null, hour: 0, minute: 0, second: 0, millisec: 0, timezone: null, defaultTimezone: "+0000", hourMinOriginal: null, minuteMinOriginal: null, secondMinOriginal: null, millisecMinOriginal: null, hourMaxOriginal: null, minuteMaxOriginal: null, secondMaxOriginal: null, millisecMaxOriginal: null, ampm: '', formattedDate: '', formattedTime: '', formattedDateTime: '', timezoneList: null, units: ['hour','minute','second','millisec'], control: null, /* * Override the default settings for all instances of the time picker. * @param settings object - the new settings to use as defaults (anonymous object) * @return the manager object */ setDefaults: function(settings) { extendRemove(this._defaults, settings || {}); return this; }, /* * Create a new Timepicker instance */ _newInst: function($input, o) { var tp_inst = new Timepicker(), inlineSettings = {}, fns = {}, overrides, i; for (var attrName in this._defaults) { if(this._defaults.hasOwnProperty(attrName)){ var attrValue = $input.attr('time:' + attrName); if (attrValue) { try { inlineSettings[attrName] = eval(attrValue); // NOSONAR } catch (err) { inlineSettings[attrName] = attrValue; } } } } overrides = { beforeShow: function (input, dp_inst) { if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) { return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst); } }, onChangeMonthYear: function (year, month, dp_inst) { // Update the time as well : this prevents the time from disappearing from the $input field. tp_inst._updateDateTime(dp_inst); if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) { tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst); } }, onClose: function (dateText, dp_inst) { if (tp_inst.timeDefined === true && $input.val() !== '') { tp_inst._updateDateTime(dp_inst); } if ($.isFunction(tp_inst._defaults.evnts.onClose)) { tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst); } } }; for (i in overrides) { if (overrides.hasOwnProperty(i)) { fns[i] = o[i] || null; } } tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, o, overrides, { evnts:fns, timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker'); }); tp_inst.amNames = $.map(tp_inst._defaults.amNames, function(val) { return val.toUpperCase(); }); tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function(val) { return val.toUpperCase(); }); // controlType is string - key to our this._controls if(typeof(tp_inst._defaults.controlType) === 'string'){ if($.fn[tp_inst._defaults.controlType] === undefined){ tp_inst._defaults.controlType = 'select'; } tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType]; } // controlType is an object and must implement create, options, value methods else{ tp_inst.control = tp_inst._defaults.controlType; } if (tp_inst._defaults.timezoneList === null) { var timezoneList = ['-1200', '-1100', '-1000', '-0930', '-0900', '-0800', '-0700', '-0600', '-0500', '-0430', '-0400', '-0330', '-0300', '-0200', '-0100', '+0000', '+0100', '+0200', '+0300', '+0330', '+0400', '+0430', '+0500', '+0530', '+0545', '+0600', '+0630', '+0700', '+0800', '+0845', '+0900', '+0930', '+1000', '+1030', '+1100', '+1130', '+1200', '+1245', '+1300', '+1400']; if (tp_inst._defaults.timezoneIso8601) { timezoneList = $.map(timezoneList, function(val) { return val == '+0000' ? 'Z' : (val.substring(0, 3) + ':' + val.substring(3)); }); } tp_inst._defaults.timezoneList = timezoneList; } tp_inst.timezone = tp_inst._defaults.timezone; tp_inst.hour = tp_inst._defaults.hour; tp_inst.minute = tp_inst._defaults.minute; tp_inst.second = tp_inst._defaults.second; tp_inst.millisec = tp_inst._defaults.millisec; tp_inst.ampm = ''; tp_inst.$input = $input; if (o.altField) { tp_inst.$altInput = $(o.altField).css({ cursor: 'pointer' }).focus(function() { $input.trigger("focus"); }); } if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) { tp_inst._defaults.minDate = new Date(); } if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) { tp_inst._defaults.maxDate = new Date(); } // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime.. if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) { tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime()); } if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) { tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime()); } if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) { tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime()); } if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) { tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime()); } tp_inst.$input.bind('focus', function() { tp_inst._onFocus(); }); return tp_inst; }, /* * add our sliders to the calendar */ _addTimePicker: function(dp_inst) { var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val(); this.timeDefined = this._parseTime(currDT); this._limitMinMaxDateTime(dp_inst, false); this._injectTimePicker(); }, /* * parse the time string from input value or _setTime */ _parseTime: function(timeString, withDate) { if (!this.inst) { this.inst = $.datepicker._getInst(this.$input[0]); } if (withDate || !this._defaults.timeOnly) { var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat'); try { var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults); if (!parseRes.timeObj) { return false; } $.extend(this, parseRes.timeObj); } catch (err) { $.datepicker.log("Error parsing the date/time string: " + err + "\ndate/time string = " + timeString + "\ntimeFormat = " + this._defaults.timeFormat + "\ndateFormat = " + dp_dateFormat); return false; } return true; } else { var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults); if (!timeObj) { return false; } $.extend(this, timeObj); return true; } }, /* * generate and inject html for timepicker into ui datepicker */ _injectTimePicker: function() { var $dp = this.inst.dpDiv, o = this.inst.settings, tp_inst = this, litem = '', uitem = '', max = {}, gridSize = {}, size = null; // Prevent displaying twice if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) { var noDisplay = ' style="display:none;"', html = '<div class="ui-timepicker-div'+ (o.isRTL? ' ui-timepicker-rtl' : '') +'"><dl>' + '<dt class="ui_tpicker_time_label"' + ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' + '<dd class="ui_tpicker_time"' + ((o.showTime) ? '' : noDisplay) + '></dd>'; // Create the markup for(var i=0,l=this.units.length; i<l; i++){ litem = this.units[i]; uitem = litem.substr(0,1).toUpperCase() + litem.substr(1); // Added by Peter Medeiros: // - Figure out what the hour/minute/second max should be based on the step values. // - Example: if stepMinute is 15, then minMax is 45. max[litem] = parseInt((o[litem+'Max'] - ((o[litem+'Max'] - o[litem+'Min']) % o['step'+uitem])), 10); gridSize[litem] = 0; html += '<dt class="ui_tpicker_'+ litem +'_label"' + ((o['show'+uitem]) ? '' : noDisplay) + '>' + o[litem +'Text'] + '</dt>' + '<dd class="ui_tpicker_'+ litem +'"><div class="ui_tpicker_'+ litem +'_slider"' + ((o['show'+uitem]) ? '' : noDisplay) + '></div>'; if (o['show'+uitem] && o[litem+'Grid'] > 0) { html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>'; if(litem == 'hour'){ for (var h = o[litem+'Min']; h <= max[litem]; h += parseInt(o[litem+'Grid'], 10)) { gridSize[litem]++; var tmph = $.datepicker.formatTime(useAmpm(o.pickerTimeFormat || o.timeFormat)? 'hht':'HH', {hour:h}, o); html += '<td data-for="'+litem+'">' + tmph + '</td>'; } } else{ for (var m = o[litem+'Min']; m <= max[litem]; m += parseInt(o[litem+'Grid'], 10)) { gridSize[litem]++; html += '<td data-for="'+litem+'">' + ((m < 10) ? '0' : '') + m + '</td>'; } } html += '</tr></table></div>'; } html += '</dd>'; } // Timezone html += '<dt class="ui_tpicker_timezone_label"' + ((o.showTimezone) ? '' : noDisplay) + '>' + o.timezoneText + '</dt>'; html += '<dd class="ui_tpicker_timezone" ' + ((o.showTimezone) ? '' : noDisplay) + '></dd>'; // Create the elements from string html += '</dl></div>'; var $tp = $(html); // if we only want time picker... if (o.timeOnly === true) { $tp.prepend('<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' + '</div>'); $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide(); } // add sliders, adjust grids, add events for(var i=0,l=tp_inst.units.length; i<l; i++){ litem = tp_inst.units[i]; uitem = litem.substr(0,1).toUpperCase() + litem.substr(1); // add the slider tp_inst[litem+'_slider'] = tp_inst.control.create(tp_inst, $tp.find('.ui_tpicker_'+litem+'_slider'), litem, tp_inst[litem], o[litem+'Min'], max[litem], o['step'+uitem]); // adjust the grid and add click event if (o['show'+uitem] && o[litem+'Grid'] > 0) { size = 100 * gridSize[litem] * o[litem+'Grid'] / (max[litem] - o[litem+'Min']); $tp.find('.ui_tpicker_'+litem+' table').css({ width: size + "%", marginLeft: o.isRTL? '0' : ((size / (-2 * gridSize[litem])) + "%"), marginRight: o.isRTL? ((size / (-2 * gridSize[litem])) + "%") : '0', borderCollapse: 'collapse' }).find("td").click(function(e){ var $t = $(this), h = $t.html(), n = parseInt(h.replace(/[^0-9]/g),10), ap = h.replace(/[^apm]/ig), f = $t.data('for'); // loses scope, so we use data-for if(f == 'hour'){ if(ap.indexOf('p') !== -1 && n < 12){ n += 12; } else{ if(ap.indexOf('a') !== -1 && n === 12){ n = 0; } } } tp_inst.control.value(tp_inst, tp_inst[f+'_slider'], litem, n); tp_inst._onTimeChange(); tp_inst._onSelectHandler(); }) .css({ cursor: 'pointer', width: (100 / gridSize[litem]) + '%', textAlign: 'center', overflow: 'hidden' }); } // end if grid > 0 } // end for loop // Add timezone options this.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find("select"); $.fn.append.apply(this.timezone_select, $.map(o.timezoneList, function(val, idx) { return $("<option />").val(typeof val == "object" ? val.value : val).text(typeof val == "object" ? val.label : val); })); if (typeof(this.timezone) != "undefined" && this.timezone !== null && this.timezone !== "") { var local_date = new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12); var local_timezone = $.timepicker.timeZoneOffsetString(local_date); if (local_timezone == this.timezone) { selectLocalTimeZone(tp_inst); } else { this.timezone_select.val(this.timezone); } } else { if (typeof(this.hour) != "undefined" && this.hour !== null && this.hour !== "") { this.timezone_select.val(o.defaultTimezone); } else { selectLocalTimeZone(tp_inst); } } this.timezone_select.change(function() { tp_inst._defaults.useLocalTimezone = false; tp_inst._onTimeChange(); }); // End timezone options // inject timepicker into datepicker var $buttonPanel = $dp.find('.ui-datepicker-buttonpane'); if ($buttonPanel.length) { $buttonPanel.before($tp); } else { $dp.append($tp); } this.$timeObj = $tp.find('.ui_tpicker_time'); if (this.inst !== null) { var timeDefined = this.timeDefined; this._onTimeChange(); this.timeDefined = timeDefined; } // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/ if (this._defaults.addSliderAccess) { var sliderAccessArgs = this._defaults.sliderAccessArgs, rtl = this._defaults.isRTL; sliderAccessArgs.isRTL = rtl; setTimeout(function() { // fix for inline mode if ($tp.find('.ui-slider-access').length === 0) { $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs); // fix any grids since sliders are shorter var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true); if (sliderAccessWidth) { $tp.find('table:visible').each(function() { var $g = $(this), oldWidth = $g.outerWidth(), oldMarginLeft = $g.css(rtl? 'marginRight':'marginLeft').toString().replace('%', ''), newWidth = oldWidth - sliderAccessWidth, newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%', css = { width: newWidth, marginRight: 0, marginLeft: 0 }; css[rtl? 'marginRight':'marginLeft'] = newMarginLeft; $g.css(css); }); } } }, 10); } // end slideAccess integration } }, /* * This function tries to limit the ability to go outside the * min/max date range */ _limitMinMaxDateTime: function(dp_inst, adjustSliders) { var o = this._defaults, dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay); if (!this._defaults.showTimepicker) { return; } // No time so nothing to check here if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) { var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'), minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0); if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null) { this.hourMinOriginal = o.hourMin; this.minuteMinOriginal = o.minuteMin; this.secondMinOriginal = o.secondMin; this.millisecMinOriginal = o.millisecMin; } if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() == dp_date.getTime()) { this._defaults.hourMin = minDateTime.getHours(); if (this.hour <= this._defaults.hourMin) { this.hour = this._defaults.hourMin; this._defaults.minuteMin = minDateTime.getMinutes(); if (this.minute <= this._defaults.minuteMin) { this.minute = this._defaults.minuteMin; this._defaults.secondMin = minDateTime.getSeconds(); if (this.second <= this._defaults.secondMin) { this.second = this._defaults.secondMin; this._defaults.millisecMin = minDateTime.getMilliseconds(); } else { if (this.millisec < this._defaults.millisecMin) { this.millisec = this._defaults.millisecMin; } this._defaults.millisecMin = this.millisecMinOriginal; } } else { this._defaults.secondMin = this.secondMinOriginal; this._defaults.millisecMin = this.millisecMinOriginal; } } else { this._defaults.minuteMin = this.minuteMinOriginal; this._defaults.secondMin = this.secondMinOriginal; this._defaults.millisecMin = this.millisecMinOriginal; } } else { this._defaults.hourMin = this.hourMinOriginal; this._defaults.minuteMin = this.minuteMinOriginal; this._defaults.secondMin = this.secondMinOriginal; this._defaults.millisecMin = this.millisecMinOriginal; } } if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) { var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'), maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0); if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null) { this.hourMaxOriginal = o.hourMax; this.minuteMaxOriginal = o.minuteMax; this.secondMaxOriginal = o.secondMax; this.millisecMaxOriginal = o.millisecMax; } if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() == dp_date.getTime()) { this._defaults.hourMax = maxDateTime.getHours(); if (this.hour >= this._defaults.hourMax) { this.hour = this._defaults.hourMax; this._defaults.minuteMax = maxDateTime.getMinutes(); if (this.minute >= this._defaults.minuteMax) { this.minute = this._defaults.minuteMax; this._defaults.secondMax = maxDateTime.getSeconds(); } else if (this.second >= this._defaults.secondMax) { this.second = this._defaults.secondMax; this._defaults.millisecMax = maxDateTime.getMilliseconds(); } else { if (this.millisec > this._defaults.millisecMax) { this.millisec = this._defaults.millisecMax; } this._defaults.millisecMax = this.millisecMaxOriginal; } } else { this._defaults.minuteMax = this.minuteMaxOriginal; this._defaults.secondMax = this.secondMaxOriginal; this._defaults.millisecMax = this.millisecMaxOriginal; } } else { this._defaults.hourMax = this.hourMaxOriginal; this._defaults.minuteMax = this.minuteMaxOriginal; this._defaults.secondMax = this.secondMaxOriginal; this._defaults.millisecMax = this.millisecMaxOriginal; } } if (adjustSliders !== undefined && adjustSliders === true) { var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10), minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10), secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10), millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10); if (this.hour_slider) { this.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax }); this.control.value(this, this.hour_slider, 'hour', this.hour); } if (this.minute_slider) { this.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax }); this.control.value(this, this.minute_slider, 'minute', this.minute); } if (this.second_slider) { this.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax }); this.control.value(this, this.second_slider, 'second', this.second); } if (this.millisec_slider) { this.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax }); this.control.value(this, this.millisec_slider, 'millisec', this.millisec); } } }, /* * when a slider moves, set the internal time... * on time change is also called when the time is updated in the text field */ _onTimeChange: function() { var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false, minute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false, second = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false, millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false, timezone = (this.timezone_select) ? this.timezone_select.val() : false, o = this._defaults, pickerTimeFormat = o.pickerTimeFormat || o.timeFormat, pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix; if (typeof(hour) == 'object') { hour = false; } if (typeof(minute) == 'object') { minute = false; } if (typeof(second) == 'object') { second = false; } if (typeof(millisec) == 'object') { millisec = false; } if (typeof(timezone) == 'object') { timezone = false; } if (hour !== false) { hour = parseInt(hour, 10); } if (minute !== false) { minute = parseInt(minute, 10); } if (second !== false) { second = parseInt(second, 10); } if (millisec !== false) { millisec = parseInt(millisec, 10); } var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0]; // If the update was done in the input field, the input field should not be updated. // If the update was done using the sliders, update the input field. var hasChanged = (hour != this.hour || minute != this.minute || second != this.second || millisec != this.millisec || (this.ampm.length > 0 && (hour < 12) != ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1)) || ((this.timezone === null && timezone != this.defaultTimezone) || (this.timezone !== null && timezone != this.timezone))); if (hasChanged) { if (hour !== false) { this.hour = hour; } if (minute !== false) { this.minute = minute; } if (second !== false) { this.second = second; } if (millisec !== false) { this.millisec = millisec; } if (timezone !== false) { this.timezone = timezone; } if (!this.inst) { this.inst = $.datepicker._getInst(this.$input[0]); } this._limitMinMaxDateTime(this.inst, true); } if (useAmpm(o.timeFormat)) { this.ampm = ampm; } // Updates the time within the timepicker this.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o); if (this.$timeObj) { if(pickerTimeFormat === o.timeFormat){ this.$timeObj.text(this.formattedTime + pickerTimeSuffix); } else{ this.$timeObj.text($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix); } } this.timeDefined = true; if (hasChanged) { this._updateDateTime(); } }, /* * call custom onSelect. * bind to sliders slidestop, and grid click. */ _onSelectHandler: function() { var onSelect = this._defaults.onSelect || this.inst.settings.onSelect; var inputEl = this.$input ? this.$input[0] : null; if (onSelect && inputEl) { onSelect.apply(inputEl, [this.formattedDateTime, this]); } }, /* * update our input with the new date time.. */ _updateDateTime: function(dp_inst) { dp_inst = this.inst || dp_inst; var dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)), dateFmt = $.datepicker._get(dp_inst, 'dateFormat'), formatCfg = $.datepicker._getFormatConfig(dp_inst), timeAvailable = dt !== null && this.timeDefined; this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg); var formattedDateTime = this.formattedDate; /* * remove following lines to force every changes in date picker to change the input value * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker. * If the user manually empty the value in the input field, the date picker will never change selected value. */ //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) { // return; //} if (this._defaults.timeOnly === true) { formattedDateTime = this.formattedTime; } else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) { formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix; } this.formattedDateTime = formattedDateTime; if (!this._defaults.showTimepicker) { this.$input.val(this.formattedDate); } else if (this.$altInput && this._defaults.altFieldTimeOnly === true) { this.$altInput.val(this.formattedTime); this.$input.val(this.formattedDate); } else if (this.$altInput) { this.$input.val(formattedDateTime); var altFormattedDateTime = '', altSeparator = this._defaults.altSeparator ? this._defaults.altSeparator : this._defaults.separator, altTimeSuffix = this._defaults.altTimeSuffix ? this._defaults.altTimeSuffix : this._defaults.timeSuffix; if (this._defaults.altFormat) altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg); else altFormattedDateTime = this.formattedDate; if (altFormattedDateTime) altFormattedDateTime += altSeparator; if (this._defaults.altTimeFormat) altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix; else altFormattedDateTime += this.formattedTime + altTimeSuffix; this.$altInput.val(altFormattedDateTime); } else { this.$input.val(formattedDateTime); } this.$input.trigger("change"); }, _onFocus: function() { if (!this.$input.val() && this._defaults.defaultValue) { this.$input.val(this._defaults.defaultValue); var inst = $.datepicker._getInst(this.$input.get(0)), tp_inst = $.datepicker._get(inst, 'timepicker'); if (tp_inst) { if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) { try { $.datepicker._updateDatepicker(inst); } catch (err) { $.datepicker.log(err); } } } } }, /* * Small abstraction to control types * We can add more, just be sure to follow the pattern: create, options, value */ _controls: { // slider methods slider: { create: function(tp_inst, obj, unit, val, min, max, step){ var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60 return obj.prop('slide', null).slider({ orientation: "horizontal", value: rtl? val*-1 : val, min: rtl? max*-1 : min, max: rtl? min*-1 : max, step: step, slide: function(event, ui) { tp_inst.control.value(tp_inst, $(this), unit, rtl? ui.value*-1:ui.value); tp_inst._onTimeChange(); }, stop: function(event, ui) { tp_inst._onSelectHandler(); } }); }, options: function(tp_inst, obj, unit, opts, val){ if(tp_inst._defaults.isRTL){ if(typeof(opts) == 'string'){ if(opts == 'min' || opts == 'max'){ if(val !== undefined) return obj.slider(opts, val*-1); return Math.abs(obj.slider(opts)); } return obj.slider(opts); } var min = opts.min, max = opts.max; opts.min = opts.max = null; if(min !== undefined) opts.max = min * -1; if(max !== undefined) opts.min = max * -1; return obj.slider(opts); } if(typeof(opts) == 'string' && val !== undefined) return obj.slider(opts, val); return obj.slider(opts); }, value: function(tp_inst, obj, unit, val){ if(tp_inst._defaults.isRTL){ if(val !== undefined) return obj.slider('value', val*-1); return Math.abs(obj.slider('value')); } if(val !== undefined) return obj.slider('value', val); return obj.slider('value'); } }, // select methods select: { create: function(tp_inst, obj, unit, val, min, max, step){ var sel = '<select class="ui-timepicker-select" data-unit="'+ unit +'" data-min="'+ min +'" data-max="'+ max +'" data-step="'+ step +'">', ul = tp_inst._defaults.timeFormat.indexOf('t') !== -1? 'toLowerCase':'toUpperCase', m = 0; for(var i=min; i<=max; i+=step){ sel += '<option value="'+ i +'"'+ (i==val? ' selected':'') +'>'; if(unit == 'hour' && useAmpm(tp_inst._defaults.pickerTimeFormat || tp_inst._defaults.timeFormat)) sel += $.datepicker.formatTime("hh TT", {hour:i}, tp_inst._defaults); else if(unit == 'millisec' || i >= 10) sel += i; else sel += '0'+ i.toString(); sel += '</option>'; } sel += '</select>'; obj.children('select').remove(); $(sel).appendTo(obj).change(function(e){ tp_inst._onTimeChange(); tp_inst._onSelectHandler(); }); return obj; }, options: function(tp_inst, obj, unit, opts, val){ var o = {}, $t = obj.children('select'); if(typeof(opts) == 'string'){ if(val === undefined) return $t.data(opts); o[opts] = val; } else o = opts; return tp_inst.control.create(tp_inst, obj, $t.data('unit'), $t.val(), o.min || $t.data('min'), o.max || $t.data('max'), o.step || $t.data('step')); }, value: function(tp_inst, obj, unit, val){ var $t = obj.children('select'); if(val !== undefined) return $t.val(val); return $t.val(); } } } // end _controls }); $.fn.extend({ /* * shorthand just to use timepicker.. */ timepicker: function(o) { o = o || {}; var tmp_args = Array.prototype.slice.call(arguments); if (typeof o == 'object') { tmp_args[0] = $.extend(o, { timeOnly: true }); } return $(this).each(function() { $.fn.datetimepicker.apply($(this), tmp_args); }); }, /* * extend timepicker to datepicker */ datetimepicker: function(o) { o = o || {}; var tmp_args = arguments; if (typeof(o) == 'string') { if (o == 'getDate') { return $.fn.datepicker.apply($(this[0]), tmp_args); } else { return this.each(function() { var $t = $(this); $t.datepicker.apply($t, tmp_args); }); } } else { return this.each(function() { var $t = $(this); $t.datepicker($.timepicker._newInst($t, o)._defaults); }); } } }); /* * Public Utility to parse date and time */ $.datepicker.parseDateTime = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) { var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings); if (parseRes.timeObj) { var t = parseRes.timeObj; parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec); } return parseRes.date; }; /* * Public utility to parse time */ $.datepicker.parseTime = function(timeFormat, timeString, options) { var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {}); // Strict parse requires the timeString to match the timeFormat exactly var strictParse = function(f, s, o){ // pattern for standard and localized AM/PM markers var getPatternAmpm = function(amNames, pmNames) { var markers = []; if (amNames) { $.merge(markers, amNames); } if (pmNames) { $.merge(markers, pmNames); } markers = $.map(markers, function(val) { return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&'); }); return '(' + markers.join('|') + ')?'; }; // figure out position of time elements.. cause js cant do named captures var getFormatPositions = function(timeFormat) { var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|t{1,2}|z|'.*?')/g), orders = { h: -1, m: -1, s: -1, l: -1, t: -1, z: -1 }; if (finds) { for (var i = 0; i < finds.length; i++) { if (orders[finds[i].toString().charAt(0)] == -1) { orders[finds[i].toString().charAt(0)] = i + 1; } } } return orders; }; var regstr = '^' + f.toString() .replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[lz]|'.*?')/g, function (match) { switch (match.charAt(0).toLowerCase()) { case 'h': return '(\\d?\\d)'; case 'm': return '(\\d?\\d)'; case 's': return '(\\d?\\d)'; case 'l': return '(\\d?\\d?\\d)'; case 'z': return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?'; case 't': return getPatternAmpm(o.amNames, o.pmNames); default: // literal escaped in quotes return '(' + match.replace(/\'/g, "").replace(/(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g, function (m) { return "\\" + m; }) + ')?'; } }) .replace(/\s/g, '\\s?') + o.timeSuffix + '$', order = getFormatPositions(f), ampm = '', treg; treg = s.match(new RegExp(regstr, 'i')); var resTime = { hour: 0, minute: 0, second: 0, millisec: 0 }; if (treg) { if (order.t !== -1) { if (treg[order.t] === undefined || treg[order.t].length === 0) { ampm = ''; resTime.ampm = ''; } else { ampm = $.inArray(treg[order.t].toUpperCase(), o.amNames) !== -1 ? 'AM' : 'PM'; resTime.ampm = o[ampm == 'AM' ? 'amNames' : 'pmNames'][0]; } } if (order.h !== -1) { if (ampm == 'AM' && treg[order.h] == '12') { resTime.hour = 0; // 12am = 0 hour } else { if (ampm == 'PM' && treg[order.h] != '12') { resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12 } else { resTime.hour = Number(treg[order.h]); } } } if (order.m !== -1) { resTime.minute = Number(treg[order.m]); } if (order.s !== -1) { resTime.second = Number(treg[order.s]); } if (order.l !== -1) { resTime.millisec = Number(treg[order.l]); } if (order.z !== -1 && treg[order.z] !== undefined) { var tz = treg[order.z].toUpperCase(); switch (tz.length) { case 1: // Z tz = o.timezoneIso8601 ? 'Z' : '+0000'; break; case 5: // +hhmm if (o.timezoneIso8601) { tz = tz.substring(1) == '0000' ? 'Z' : tz.substring(0, 3) + ':' + tz.substring(3); } break; case 6: // +hh:mm if (!o.timezoneIso8601) { tz = tz == 'Z' || tz.substring(1) == '00:00' ? '+0000' : tz.replace(/:/, ''); } else { if (tz.substring(1) == '00:00') { tz = 'Z'; } } break; } resTime.timezone = tz; } return resTime; } return false; };// end strictParse // First try JS Date, if that fails, use strictParse var looseParse = function(f,s,o){ try{ var d = new Date('2012-01-01 '+ s); return { hour: d.getHours(), minutes: d.getMinutes(), seconds: d.getSeconds(), millisec: d.getMilliseconds(), timezone: $.timepicker.timeZoneOffsetString(d) }; } catch(err){ try{ return strictParse(f,s,o); } catch(err2){ $.datepicker.log("Unable to parse \ntimeString: "+ s +"\ntimeFormat: "+ f); } } return false; }; // end looseParse if(typeof o.parse === "function"){ return o.parse(timeFormat, timeString, o) } if(o.parse === 'loose'){ return looseParse(timeFormat, timeString, o); } return strictParse(timeFormat, timeString, o); }; /* * Public utility to format the time * format = string format of the time * time = a {}, not a Date() for timezones * options = essentially the regional[].. amNames, pmNames, ampm */ $.datepicker.formatTime = function(format, time, options) { options = options || {}; options = $.extend({}, $.timepicker._defaults, options); time = $.extend({ hour: 0, minute: 0, second: 0, millisec: 0, timezone: '+0000' }, time); var tmptime = format, ampmName = options.amNames[0], hour = parseInt(time.hour, 10); if (hour > 11) { ampmName = options.pmNames[0]; } tmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[lz]|('.*?'|".*?"))/g, function(match) { switch (match) { case 'HH': return ('0' + hour).slice(-2); case 'H': return hour; case 'hh': return ('0' + convert24to12(hour)).slice(-2); case 'h': return convert24to12(hour); case 'mm': return ('0' + time.minute).slice(-2); case 'm': return time.minute; case 'ss': return ('0' + time.second).slice(-2); case 's': return time.second; case 'l': return ('00' + time.millisec).slice(-3); case 'z': return time.timezone === null? options.defaultTimezone : time.timezone; case 'T': return ampmName.charAt(0).toUpperCase(); case 'TT': return ampmName.toUpperCase(); case 't': return ampmName.charAt(0).toLowerCase(); case 'tt': return ampmName.toLowerCase(); default: return match.replace(/\'/g, "") || "'"; } }); tmptime = $.trim(tmptime); return tmptime; }; /* * the bad hack :/ override datepicker so it doesnt close on select // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378 */ $.datepicker._base_selectDate = $.datepicker._selectDate; $.datepicker._selectDate = function(id, dateStr) { var inst = this._getInst($(id)[0]), tp_inst = this._get(inst, 'timepicker'); if (tp_inst) { tp_inst._limitMinMaxDateTime(inst, true); inst.inline = inst.stay_open = true; //This way the onSelect handler called from calendarpicker get the full dateTime this._base_selectDate(id, dateStr); inst.inline = inst.stay_open = false; this._notifyChange(inst); this._updateDatepicker(inst); } else { this._base_selectDate(id, dateStr); } }; /* * second bad hack :/ override datepicker so it triggers an event when changing the input field * and does not redraw the datepicker on every selectDate event */ $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker; $.datepicker._updateDatepicker = function(inst) { // don't popup the datepicker if there is another instance already opened var input = inst.input[0]; if ($.datepicker._curInst && $.datepicker._curInst != inst && $.datepicker._datepickerShowing && $.datepicker._lastInput != input) { return; } if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) { this._base_updateDatepicker(inst); // Reload the time control when changing something in the input text field. var tp_inst = this._get(inst, 'timepicker'); if (tp_inst) { tp_inst._addTimePicker(inst); if (tp_inst._defaults.useLocalTimezone) { //checks daylight saving with the new date. var date = new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay, 12); selectLocalTimeZone(tp_inst, date); tp_inst._onTimeChange(); } } } }; /* * third bad hack :/ override datepicker so it allows spaces and colon in the input field */ $.datepicker._base_doKeyPress = $.datepicker._doKeyPress; $.datepicker._doKeyPress = function(event) { var inst = $.datepicker._getInst(event.target), tp_inst = $.datepicker._get(inst, 'timepicker'); if (tp_inst) { if ($.datepicker._get(inst, 'constrainInput')) { var ampm = useAmpm(tp_inst._defaults.timeFormat), dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')), datetimeChars = tp_inst._defaults.timeFormat.toString() .replace(/[hms]/g, '') .replace(/TT/g, ampm ? 'APM' : '') .replace(/Tt/g, ampm ? 'AaPpMm' : '') .replace(/tT/g, ampm ? 'AaPpMm' : '') .replace(/T/g, ampm ? 'AP' : '') .replace(/tt/g, ampm ? 'apm' : '') .replace(/t/g, ampm ? 'ap' : '') + " " + tp_inst._defaults.separator + tp_inst._defaults.timeSuffix + (tp_inst._defaults.showTimezone ? tp_inst._defaults.timezoneList.join('') : '') + (tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) + dateChars, chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode); return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1); } } return $.datepicker._base_doKeyPress(event); }; /* * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField */ $.datepicker._base_updateAlternate = $.datepicker._updateAlternate; /* Update any alternate field to synchronise with the main field. */ $.datepicker._updateAlternate = function(inst) { var tp_inst = this._get(inst, 'timepicker'); if(tp_inst){ var altField = tp_inst._defaults.altField; if (altField) { // update alternate field too var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat, date = this._getDate(inst), formatCfg = $.datepicker._getFormatConfig(inst), altFormattedDateTime = '', altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator, altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix, altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat; altFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix; if(!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly){ if(tp_inst._defaults.altFormat) altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, (date === null ? new Date() : date), formatCfg) + altSeparator + altFormattedDateTime; else altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime; } $(altField).val(altFormattedDateTime); } } else{ $.datepicker._base_updateAlternate(inst); } }; /* * Override key up event to sync manual input changes. */ $.datepicker._base_doKeyUp = $.datepicker._doKeyUp; $.datepicker._doKeyUp = function(event) { var inst = $.datepicker._getInst(event.target), tp_inst = $.datepicker._get(inst, 'timepicker'); if (tp_inst) { if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) { try { $.datepicker._updateDatepicker(inst); } catch (err) { $.datepicker.log(err); } } } return $.datepicker._base_doKeyUp(event); }; /* * override "Today" button to also grab the time. */ $.datepicker._base_gotoToday = $.datepicker._gotoToday; $.datepicker._gotoToday = function(id) { var inst = this._getInst($(id)[0]), $dp = inst.dpDiv; this._base_gotoToday(id); var tp_inst = this._get(inst, 'timepicker'); selectLocalTimeZone(tp_inst); var now = new Date(); this._setTime(inst, now); $('.ui-datepicker-today', $dp).click(); }; /* * Disable & enable the Time in the datetimepicker */ $.datepicker._disableTimepickerDatepicker = function(target) { var inst = this._getInst(target); if (!inst) { return; } var tp_inst = this._get(inst, 'timepicker'); $(target).datepicker('getDate'); // Init selected[Year|Month|Day] if (tp_inst) { tp_inst._defaults.showTimepicker = false; tp_inst._updateDateTime(inst); } }; $.datepicker._enableTimepickerDatepicker = function(target) { var inst = this._getInst(target); if (!inst) { return; } var tp_inst = this._get(inst, 'timepicker'); $(target).datepicker('getDate'); // Init selected[Year|Month|Day] if (tp_inst) { tp_inst._defaults.showTimepicker = true; tp_inst._addTimePicker(inst); // Could be disabled on page load tp_inst._updateDateTime(inst); } }; /* * Create our own set time function */ $.datepicker._setTime = function(inst, date) { var tp_inst = this._get(inst, 'timepicker'); if (tp_inst) { var defaults = tp_inst._defaults; // calling _setTime with no date sets time to defaults tp_inst.hour = date ? date.getHours() : defaults.hour; tp_inst.minute = date ? date.getMinutes() : defaults.minute; tp_inst.second = date ? date.getSeconds() : defaults.second; tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec; //check if within min/max times.. tp_inst._limitMinMaxDateTime(inst, true); tp_inst._onTimeChange(); tp_inst._updateDateTime(inst); } }; /* * Create new public method to set only time, callable as $().datepicker('setTime', date) */ $.datepicker._setTimeDatepicker = function(target, date, withDate) { var inst = this._getInst(target); if (!inst) { return; } var tp_inst = this._get(inst, 'timepicker'); if (tp_inst) { this._setDateFromField(inst); var tp_date; if (date) { if (typeof date == "string") { tp_inst._parseTime(date, withDate); tp_date = new Date(); tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec); } else { tp_date = new Date(date.getTime()); } if (tp_date.toString() == 'Invalid Date') { tp_date = undefined; } this._setTime(inst, tp_date); } } }; /* * override setDate() to allow setting time too within Date object */ $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker; $.datepicker._setDateDatepicker = function(target, date) { var inst = this._getInst(target); if (!inst) { return; } var tp_date = (date instanceof Date) ? new Date(date.getTime()) : date; this._updateDatepicker(inst); this._base_setDateDatepicker.apply(this, arguments); this._setTimeDatepicker(target, tp_date, true); }; /* * override getDate() to allow getting time too within Date object */ $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker; $.datepicker._getDateDatepicker = function(target, noDefault) { var inst = this._getInst(target); if (!inst) { return; } var tp_inst = this._get(inst, 'timepicker'); if (tp_inst) { // if it hasn't yet been defined, grab from field if(inst.lastVal === undefined){ this._setDateFromField(inst, noDefault); } var date = this._getDate(inst); if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) { date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec); } return date; } return this._base_getDateDatepicker(target, noDefault); }; /* * override parseDate() because UI 1.8.14 throws an error about "Extra characters" * An option in datapicker to ignore extra format characters would be nicer. */ $.datepicker._base_parseDate = $.datepicker.parseDate; $.datepicker.parseDate = function(format, value, settings) { var date; try { date = this._base_parseDate(format, value, settings); } catch (err) { // Hack! The error message ends with a colon, a space, and // the "extra" characters. We rely on that instead of // attempting to perfectly reproduce the parsing algorithm. date = this._base_parseDate(format, value.substring(0,value.length-(err.length-err.indexOf(':')-2)), settings); $.datepicker.log("Error parsing the date string: " + err + "\ndate string = " + value + "\ndate format = " + format); } return date; }; /* * override formatDate to set date with time to the input */ $.datepicker._base_formatDate = $.datepicker._formatDate; $.datepicker._formatDate = function(inst, day, month, year) { var tp_inst = this._get(inst, 'timepicker'); if (tp_inst) { tp_inst._updateDateTime(inst); return tp_inst.$input.val(); } return this._base_formatDate(inst); }; /* * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate */ $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker; $.datepicker._optionDatepicker = function(target, name, value) { var inst = this._getInst(target), name_clone; if (!inst) { return null; } var tp_inst = this._get(inst, 'timepicker'); if (tp_inst) { var min = null, max = null, onselect = null, overrides = tp_inst._defaults.evnts, fns = {}, prop; if (typeof name == 'string') { // if min/max was set with the string if (name === 'minDate' || name === 'minDateTime') { min = value; } else if (name === 'maxDate' || name === 'maxDateTime') { max = value; } else if (name === 'onSelect') { onselect = value; } else if (overrides.hasOwnProperty(name)) { if (typeof (value) === 'undefined') { return overrides[name]; } fns[name] = value; name_clone = {}; //empty results in exiting function after overrides updated } } else if (typeof name == 'object') { //if min/max was set with the JSON if (name.minDate) { min = name.minDate; } else if (name.minDateTime) { min = name.minDateTime; } else if (name.maxDate) { max = name.maxDate; } else if (name.maxDateTime) { max = name.maxDateTime; } for (prop in overrides) { if (overrides.hasOwnProperty(prop) && name[prop]) { fns[prop] = name[prop]; } } } for (prop in fns) { if (fns.hasOwnProperty(prop)) { overrides[prop] = fns[prop]; if (!name_clone) { name_clone = $.extend({}, name);} delete name_clone[prop]; } } if (name_clone && isEmptyObject(name_clone)) { return; } if (min) { //if min was set if (min === 0) { min = new Date(); } else { min = new Date(min); } tp_inst._defaults.minDate = min; tp_inst._defaults.minDateTime = min; } else if (max) { //if max was set if (max === 0) { max = new Date(); } else { max = new Date(max); } tp_inst._defaults.maxDate = max; tp_inst._defaults.maxDateTime = max; } else if (onselect) { tp_inst._defaults.onSelect = onselect; } } if (value === undefined) { return this._base_optionDatepicker.call($.datepicker, target, name); } return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value); }; /* * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype, * it will return false for all objects */ var isEmptyObject = function(obj) { var prop; for (prop in obj) { if (obj.hasOwnProperty(obj)) { return false; } } return true; }; /* * jQuery extend now ignores nulls! */ var extendRemove = function(target, props) { $.extend(target, props); for (var name in props) { if (props[name] === null || props[name] === undefined) { target[name] = props[name]; } } return target; }; /* * Determine by the time format if should use ampm * Returns true if should use ampm, false if not */ var useAmpm = function(timeFormat){ return (timeFormat.indexOf('t') !== -1 && timeFormat.indexOf('h') !== -1); }; /* * Converts 24 hour format into 12 hour * Returns 12 hour without leading 0 */ var convert24to12 = function(hour) { if (hour > 12) { hour = hour - 12; } if (hour == 0) { hour = 12; } return String(hour); }; /* * Splits datetime string into date ans time substrings. * Throws exception when date can't be parsed * Returns [dateString, timeString] */ var splitDateTime = function(dateFormat, dateTimeString, dateSettings, timeSettings) { try { // The idea is to get the number separator occurances in datetime and the time format requested (since time has // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split. var separator = timeSettings && timeSettings.separator ? timeSettings.separator : $.timepicker._defaults.separator, format = timeSettings && timeSettings.timeFormat ? timeSettings.timeFormat : $.timepicker._defaults.timeFormat, timeParts = format.split(separator), // how many occurances of separator may be in our format? timePartsLen = timeParts.length, allParts = dateTimeString.split(separator), allPartsLen = allParts.length; if (allPartsLen > 1) { return [ allParts.splice(0,allPartsLen-timePartsLen).join(separator), allParts.splice(0,timePartsLen).join(separator) ]; } } catch (err) { $.datepicker.log('Could not split the date from the time. Please check the following datetimepicker options' + "\nthrown error: " + err + "\ndateTimeString" + dateTimeString + "\ndateFormat = " + dateFormat + "\nseparator = " + timeSettings.separator + "\ntimeFormat = " + timeSettings.timeFormat); if (err.indexOf(":") >= 0) { // Hack! The error message ends with a colon, a space, and // the "extra" characters. We rely on that instead of // attempting to perfectly reproduce the parsing algorithm. var dateStringLength = dateTimeString.length - (err.length - err.indexOf(':') - 2), timeString = dateTimeString.substring(dateStringLength); return [$.trim(dateTimeString.substring(0, dateStringLength)), $.trim(dateTimeString.substring(dateStringLength))]; } else { throw err; } } return [dateTimeString, '']; }; /* * Internal function to parse datetime interval * Returns: {date: Date, timeObj: Object}, where * date - parsed date without time (type Date) * timeObj = {hour: , minute: , second: , millisec: } - parsed time. Optional */ var parseDateTimeInternal = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) { var date; var splitRes = splitDateTime(dateFormat, dateTimeString, dateSettings, timeSettings); date = $.datepicker._base_parseDate(dateFormat, splitRes[0], dateSettings); if (splitRes[1] !== '') { var timeString = splitRes[1], parsedTime = $.datepicker.parseTime(timeFormat, timeString, timeSettings); if (parsedTime === null) { throw 'Wrong time format'; } return { date: date, timeObj: parsedTime }; } else { return { date: date }; } }; /* * Internal function to set timezone_select to the local timezone */ var selectLocalTimeZone = function(tp_inst, date) { if (tp_inst && tp_inst.timezone_select) { tp_inst._defaults.useLocalTimezone = true; var now = typeof date !== 'undefined' ? date : new Date(); var tzoffset = $.timepicker.timeZoneOffsetString(now); if (tp_inst._defaults.timezoneIso8601) { tzoffset = tzoffset.substring(0, 3) + ':' + tzoffset.substring(3); } tp_inst.timezone_select.val(tzoffset); } }; /* * Create a Singleton Insance */ $.timepicker = new Timepicker(); /** * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5) * @param date * @return string */ $.timepicker.timeZoneOffsetString = function(date) { var off = date.getTimezoneOffset() * -1, minutes = off % 60, hours = (off - minutes) / 60; return (off >= 0 ? '+' : '-') + ('0' + (hours * 101).toString()).substr(-2) + ('0' + (minutes * 101).toString()).substr(-2); }; /** * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to * enforce date range limits. * n.b. The input value must be correctly formatted (reformatting is not supported) * @param Element startTime * @param Element endTime * @param obj options Options for the timepicker() call * @return jQuery */ $.timepicker.timeRange = function(startTime, endTime, options) { return $.timepicker.handleRange('timepicker', startTime, endTime, options); }; /** * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to * enforce date range limits. * @param Element startTime * @param Element endTime * @param obj options Options for the `timepicker()` call. Also supports `reformat`, * a boolean value that can be used to reformat the input values to the `dateFormat`. * @param string method Can be used to specify the type of picker to be added * @return jQuery */ $.timepicker.dateTimeRange = function(startTime, endTime, options) { $.timepicker.dateRange(startTime, endTime, options, 'datetimepicker'); }; /** * Calls `method` on the `startTime` and `endTime` elements, and configures them to * enforce date range limits. * @param Element startTime * @param Element endTime * @param obj options Options for the `timepicker()` call. Also supports `reformat`, * a boolean value that can be used to reformat the input values to the `dateFormat`. * @param string method Can be used to specify the type of picker to be added * @return jQuery */ $.timepicker.dateRange = function(startTime, endTime, options, method) { method = method || 'datepicker'; $.timepicker.handleRange(method, startTime, endTime, options); }; /** * Calls `method` on the `startTime` and `endTime` elements, and configures them to * enforce date range limits. * @param string method Can be used to specify the type of picker to be added * @param Element startTime * @param Element endTime * @param obj options Options for the `timepicker()` call. Also supports `reformat`, * a boolean value that can be used to reformat the input values to the `dateFormat`. * @return jQuery */ $.timepicker.handleRange = function(method, startTime, endTime, options) { $.fn[method].call(startTime, $.extend({ onClose: function(dateText, inst) { checkDates(this, endTime, dateText); }, onSelect: function(selectedDateTime) { selected(this, endTime, 'minDate'); } }, options, options.start)); $.fn[method].call(endTime, $.extend({ onClose: function(dateText, inst) { checkDates(this, startTime, dateText); }, onSelect: function(selectedDateTime) { selected(this, startTime, 'maxDate'); } }, options, options.end)); // timepicker doesn't provide access to its 'timeFormat' option, // nor could I get datepicker.formatTime() to behave with times, so I // have disabled reformatting for timepicker if (method != 'timepicker' && options.reformat) { $([startTime, endTime]).each(function() { var format = $(this)[method].call($(this), 'option', 'dateFormat'), date = new Date($(this).val()); if ($(this).val() && date) { $(this).val($.datepicker.formatDate(format, date)); } }); } checkDates(startTime, endTime, startTime.val()); function checkDates(changed, other, dateText) { if (other.val() && (new Date(startTime.val()) > new Date(endTime.val()))) { other.val(dateText); } } selected(startTime, endTime, 'minDate'); selected(endTime, startTime, 'maxDate'); function selected(changed, other, option) { if (!$(changed).val()) { return; } var date = $(changed)[method].call($(changed), 'getDate'); // timepicker doesn't implement 'getDate' and returns a jQuery if (date.getTime) { $(other)[method].call($(other), 'option', option, date); } } return $([startTime.get(0), endTime.get(0)]); }; /* * Keep up with the version */ $.timepicker.version = "1.1.1"; })(jQuery); /* * * Copyright (c) 1999-2007, abaXX Technology AG * Copyright (c) 2015, CREALOGIX AG * */ /*jslint devel:true, browser:true, nomen:true, plusplus:true, regexp:true, unparam: true, vars:true, white:true */ /*global Abaxx,jQuery,Ajax,CKEDITOR,Calendar,Base64,includedScriptFiles */ /** * The date input package provides additional javascript functionality for the xx:date input tag. It provides access to * the configuration (date pattern, first day, ...). See calendar-setup.js for details. <br/> * The syncDateInputs method allows * to sync two date input fields. It ensures that the date of one field is always lower or equal than the date in the * other field. If the value in one field is modified the css class 'dateinput-value-changed' is added to the modified field * and it is activated (focus + select value). To use the functionality add the method to the onchange handler of the two * date input tags.<br/> * @example * <xx:dateinput id="appointmentEditor-StartTime" onchange="Abaxx.widgets.dateInput.syncDateInputs('appointmentEditor-StartTime', 'appointmentEditor-EndTime', true)" aspect="startTime"/> * @example * <xx:dateinput id="appointmentEditor-EndTime" onchange="Abaxx.widgets.dateInput.syncDateInputs('appointmentEditor-StartTime', 'appointmentEditor-EndTime', false)" aspect="endTime"/> * @namespace Abaxx.widgets.dateInput * */ Abaxx.define("widgets.dateInput", function() { "use strict"; var getDate = function(id) { var $input = jQuery("[id='" + id + "']"); if ($input.datepicker) { return $input.datepicker("getDate"); } Abaxx.log.error("No datepicker found for input '" + id + "'"); return undefined; }; var isAfter = function(d1, d2) { try { var date1 = getDate(d1); var date2 = getDate(d2); return date1.getTime() > date2.getTime(); } catch(t) { return false; } }; var syncDateInputs = function(startDateId, endDateId, startToEnd) { var startDateField = jQuery("[id='" + startDateId +"']"); var endDateField = jQuery("[id='" + endDateId +"']"); if (startToEnd) { if (isAfter(startDateId, endDateId)) { endDateField.val(startDateField.val()).addClass("dateinput-value-changed").select().focus(); startDateField.removeClass("dateinput-value-changed"); } else { startDateField.removeClass("dateinput-value-changed"); endDateField.removeClass("dateinput-value-changed"); } } else { if (isAfter(startDateId, endDateId)) { startDateField.val(endDateField.val()).addClass("dateinput-value-changed").select().focus(); endDateField.removeClass("dateinput-value-changed"); } else { startDateField.removeClass("dateinput-value-changed"); endDateField.removeClass("dateinput-value-changed"); } } }; /** * * @param date * @param blockSaturday * @param blockSunday * @param blockedDates * @returns [true] if the date should be selectable in the date picker, [false] otherwise. */ function isSelectableDate(date, blockSaturday, blockSunday, blockedDates) { var dayOfWeek = date.getDay(), formattedDate; if (blockSaturday && dayOfWeek === 6) { return [false]; } if (blockSunday && dayOfWeek === 0) { return [false]; } if (blockedDates) { formattedDate = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate(); if (jQuery.inArray(formattedDate, blockedDates) != -1) { return [false]; } } return [true]; } var registerDateInputs = function () { jQuery("[data-abx-widget=dateinput]:not([disabled])").each(function (id, element) { var input = jQuery(element); var tagOptions = input.data("abxOptions"); var existingWidget = input.data("datepicker"); if (existingWidget != null) { return; } var yearRange = "c-10:c+10"; if (tagOptions.pastLimit) { yearRange = tagOptions.pastLimit.year + yearRange.substring(yearRange.indexOf(":")); } if (tagOptions.futureLimit) { yearRange = yearRange.substring(0, yearRange.indexOf(":") + 1) + tagOptions.futureLimit.year; } var localeDefaults = jQuery.extend({}, jQuery.datepicker.regional[ tagOptions.language ] || {}); var configuredMinDate = tagOptions.pastLimit ? new Date(tagOptions.pastLimit.year, tagOptions.pastLimit.month, tagOptions.pastLimit.day) : null; var configuredMaxDate = tagOptions.futureLimit ? new Date(tagOptions.futureLimit.year, tagOptions.futureLimit.month, tagOptions.futureLimit.day) : null; var options = jQuery.extend(localeDefaults, { showOn: tagOptions.showOn, buttonImage: tagOptions.triggerElementId ? null : tagOptions.datePickerImage, buttonText: tagOptions.datePickerText ? tagOptions.datePickerText : null, buttonImageOnly: tagOptions.buttonImageOnly, firstDay:1, showButtonPanel: true, constrainInput: false, controlType: "select", dateFormat: tagOptions.dateFormat, timeFormat: tagOptions.timeFormat, separator: tagOptions.separator, beforeShowDay:function (date) { jQuery('#ui-datepicker-div').addClass('dkb-datepicker'); // DKB return isSelectableDate(date, tagOptions.blockSaturdays, tagOptions.blockSundays, tagOptions.blockedDates); }, minDate: configuredMinDate, maxDate: configuredMaxDate, configuredMinDate: configuredMinDate, configuredMaxDate: configuredMaxDate, hideIfNoPrevNext:true, changeMonth:tagOptions.changeMonthYear ? tagOptions.changeMonthYear : null, changeYear:tagOptions.changeMonthYear ? tagOptions.changeMonthYear : null, yearRange: yearRange, beforeShow:function () { input.css("z-index", Abaxx.core.nextZIndex()); }, onSelect:function (text, datepicker) { input.attr("clearValueOnClose", ''); var date; if (tagOptions.mode == 'datepicker' && jQuery(this).datepicker) { date = jQuery(this).datepicker('getDate'); } else if (jQuery(this).datetimepicker) { date = jQuery(this).datetimepicker('getDate'); } if (date) { date.setSeconds(0, 0); if (tagOptions.mode == 'datepicker') { jQuery(this).datepicker('setDate', date); } else { jQuery(this).datetimepicker('setDate', date); } } applyLimit(jQuery(this), tagOptions.syncBefore, true); applyLimit(jQuery(this), tagOptions.syncAfter, false); if (tagOptions.onpick) { new Function("a","b",tagOptions.onpick + "(a,b)" )(text, datepicker); // NOSONAR } jQuery(this).change(); }, onClose:function (text, datepicker) { input.css("z-index", ""); applyLimit(jQuery(this), tagOptions.syncBefore, true); applyLimit(jQuery(this), tagOptions.syncAfter, false); if (tagOptions.onpick) { new Function("a","b",tagOptions.onpick + "(a,b)" )(text, datepicker); // NOSONAR } jQuery(this).change(); input.prop("disabled", false); if (input.attr("clearValueOnClose") === 'true') { input.attr("clearValueOnClose", ''); input.val(""); } } }); if (tagOptions.mode == 'datepicker') { input.datepicker(options); } else { input.datetimepicker(options); } if (tagOptions.triggerElementId) { jQuery("[id='" + tagOptions.triggerElementId + "']").on("click.date-input-trigger", function(event) { event.preventDefault(); input.prop("disabled", true); // prevent focus so that virtual keyboards are not displayed if (input.val() === '' && tagOptions.initialDate != '') { input.attr("clearValueOnClose", 'true'); // string because input.attr() returns a string input.datepicker('setDate', tagOptions.initialDate); } input.datepicker("show"); }) } if (input.css("position") === "static") { input.css("position", "relative"); } if (tagOptions.syncBefore) { input.change(function () { syncDateInputs(input.attr("id"), tagOptions.syncBefore, true); }); } if (tagOptions.syncAfter) { input.change(function () { syncDateInputs(tagOptions.syncAfter, input.attr("id"), false); }); } // DKB start jQuery(".hasDatepicker").keypress(function () { jQuery('#ui-datepicker-div').addClass('dkb-datepicker'); }); //if (typeof handleDateInputForMobile === 'function') { // handleDateInputForMobile(input); //} // DKB end }); }; var applyLimit = function (datepickerInstance, syncTarget, isMin) { if (syncTarget) { var syncInstance = jQuery("[id='" + syncTarget + "']"); var dateToSync = datepickerInstance.datepicker('getDate'); var configuredLimit = syncInstance.datepicker("option", isMin ? "configuredMinDate" : "configuredMaxDate"); syncInstance.datepicker("option", isMin ? "minDate" : "maxDate", effectiveLimit(dateToSync, configuredLimit, isMin)); } }; var effectiveLimit = function (providedLimit, configuredLimit, isMin) { if (configuredLimit == null) { return providedLimit; } if (providedLimit == null) { return configuredLimit; } if (isMin) { return configuredLimit.getTime() <= providedLimit.getTime() ? providedLimit : configuredLimit; } else { return configuredLimit.getTime() >= providedLimit.getTime() ? providedLimit : configuredLimit; } }; var syncDatePicker = function () { jQuery("[data-abx-widget=dateinput]").each(function (id, element) { var input = jQuery(element); var tagOptions = input.data("abxOptions"); if (tagOptions.syncBefore) { var syncBefore = jQuery("[id='" + tagOptions.syncBefore + "']"); var safeBefore = syncBefore.val(); applyLimit(jQuery(input), tagOptions.syncBefore, true); syncBefore.val(safeBefore); } if (tagOptions.syncAfter) { var syncAfter = jQuery("[id='" + tagOptions.syncAfter + "']"); var safeAfter = syncAfter.val(); applyLimit(jQuery(input), tagOptions.syncAfter, false); syncAfter.val(safeAfter); } }); }; Abaxx.core.onReady(registerDateInputs); Abaxx.core.onReady(syncDatePicker); return { syncDateInputs: syncDateInputs, isSelectableDate: isSelectableDate }; }); /** * Copyright (c) 2009 by Crealogix E-Banking Solutions AG. All rights reserved. * * Creates the "browser info" cookies used for Sec Pack 1. * <p> * The idea of these cookies is, that if an attacker tries to steal an Airlock session but * is not using precisely the same browser setup then the server will detect the change of * browser context and abort the session. However, it would obviously not be difficult for * a smart attacker to work around this obstacle, so these measures only provide a very * superficial level of weak security. * <p> * The function writeCookies does not create the same cookies as the older browserInfo.js * script used to do, because the old script performed client-side user agent analysis and * delivered a lot of values that were unreliable and indeed useless. Instead, just a few * cookies are created, containing concatenated values that might realistically be useful * for server-side analysis. No user agent analysis is performed - if needed for logging, * it should be performed server-side using the value supplied in the request header. * * @author JonB */ CLX = {}; CLX.writeEncodedCookie = function(key, value, maxAge, path, domain, secure, sameSite) { CLX.writeCookie(key, encodeURIComponent(value), maxAge, path, domain, secure, sameSite); }; CLX.deleteCookie = function(key, path, domain) { CLX.writeCookie(key, "", 0, path, domain, false); }; CLX.writeCookie = function(key, value, maxAge, path, domain, secure, sameSite) { var cookieValue = key + "=" + value; if (maxAge === 0 || maxAge > 0) { cookieValue += "; max-age=" + (maxAge * 60000) } if (path) { cookieValue += "; path=" + path } if (domain) { cookieValue += "; domain=" + domain } if (secure) { cookieValue += "; secure" } if(sameSite) { cookieValue += "; SameSite=" + sameSite } document.cookie = cookieValue; }; /** * Creates browser info cookies using the supplied cookie name prefix */ CLX.writeBrowserInfoCookies = function() { var prefix = "BRSINFO_", /** * The value used to control the lifetime of the cookie */ SESSION_LIFETIME = -1, /** * The path for the cookies */ ROOT = "/", /** * The protocol used for a secure connection */ HTTPS = "https", /** * String representation of the boolean value */ TRUE = "true", /** * The delimiter between the key and value of an individual element of the cookie */ KEY_VALUE_DELIM = "=", /** * The delimiter for concatenating multiple key/value elements into a single cookie string */ ELEMENT_DELIM = ";", /** * The name of the environment info cookie */ ENVIRONMENT = "env", /** * The key for the boolean value signifying if Java is enabled, only written if true */ JAVA_ENABLED = "javaEnabled", /** * The key for the window dimensions detail */ WINDOW_SIZE = "windowSize", /** * The delimiter for the window width and height */ WINDOW_SIZE_DELIM = "x", /** * The name of the plugins info cookie */ PLUGINS = "browserPlugins", /** * The regular expression used to identify the last token of a plugin filename * (delimited by white space, forward slash or backslash) */ PLUGIN_FILENAME_EXPR = /[^\s\/\\]+$/, /** * The delimiter used between plugin filenames */ PLUGIN_DELIM = ";", /** * The name of the screen info cookie */ SCREEN = "screen", /** * The screen properties to pack into a cookie */ SCREEN_PROPS = ["width", "height", "colorDepth"], /** * The navigator object */ nav = window.navigator, /** * Writes (or replaces) the cookie associated with the supplied name */ writeCookie = function(name, value) { var protocol, isHttps; // See if the current document was loaded via HTTPS: if so, create a secure cookie protocol = window.location.protocol; isHttps = protocol.indexOf(HTTPS) === 0; CLX.writeEncodedCookie(prefix + name, value, SESSION_LIFETIME, ROOT, null, isHttps, "lax"); }, /** * Deletes the cookie associated with the supplied name, if it exists */ deleteCookie = function(name) { CLX.deleteCookie(prefix + name, ROOT); }, /** * Writes the cookie containing environment values (javaEnabled, windowSize) */ writeEnvironmentCookie = function() { // Add the window dimensions var cookieVal = WINDOW_SIZE + KEY_VALUE_DELIM + window.screen.width + WINDOW_SIZE_DELIM + window.screen.height; // See if Java is enabled (only add to cookie value if it is enabled) if (nav.javaEnabled()) { cookieVal += ELEMENT_DELIM + JAVA_ENABLED + KEY_VALUE_DELIM + TRUE; } // Write the cookie writeCookie(ENVIRONMENT, cookieVal); }, /** * Writes the cookie containing browser plugin details (concatenated plugin filenames) */ writePluginsCookie = function() { var cookieVal = "", filename, i; if (nav.plugins && nav.plugins.length) { // Loop over the plugin filenames and append together for (i = 0; i < nav.plugins.length; ++i) { filename = nav.plugins[i].filename; if (filename) { // The regular expression extracts just the last part of the filename cookieVal += filename.match(PLUGIN_FILENAME_EXPR) + PLUGIN_DELIM; } } // Write the cookie writeCookie(PLUGINS, cookieVal); } else { // No plugins to read (maybe running in IE). Delete the cookie, if it exists. deleteCookie(PLUGINS); } }, /** * Writes the cookie containing screen details (width, height, colorDepth) */ writeScreenCookie = function() { var cookieVal = "", screen = window.screen, propName, i; if (screen) { // Loop over the configured attributes and build the cookie value for (i = 0; i < SCREEN_PROPS.length; ++i) { if (i > 0) { cookieVal += ELEMENT_DELIM; } propName = SCREEN_PROPS[i]; cookieVal += propName + KEY_VALUE_DELIM + screen[propName]; } // Write the cookie writeCookie(SCREEN, cookieVal); } else { // No screen to examine. Delete the cookie, if it exists deleteCookie(SCREEN); } }; // Write the cookies writeEnvironmentCookie(); writePluginsCookie(); writeScreenCookie(); }; CLX.writeBrowserInfoCookies(); /** * Funktionen f�r den Finanzstatus */ Abaxx.define('dkb_financialstatus_view', function () { 'use strict'; var settings = { // die Intervall-Id f�r die regelmae�igen Polling Versuche updateIntervalId: undefined, // maximale Polling-Laufzeit (via CMS konfiguriert) maxPollingDurationInSec: 0, // Zeitstempel (in Millisekunden) f�r ein hartes Ende der Polling-Versuche (abgeleitet von maxUpdateDurationInSec) retryEndTimeMs: undefined, // die URL f�r das Ansto�en einer Aktualisierung f�r ein Konto/eine Kontengruppe updateUrl: undefined, // die URL f�r das Polling nach aktualisierten Konten pollingUrl: undefined, // Flag ob bereits ein Request laeuft xhrRunning: false, // zaehlt die Anzahl der Refresh-Versuche updateAttempts: 0 }; /** * Aktualisiert die Action Zeile in der mobilen Ansicht und disabled diese waehrend * dem Laden. * * @param rowIds IDs der Zeilen, die aktualisiert werden m�ssen */ var updateActions = function (rowIds) { addDetailRow(); for (var i = 0; i < rowIds.length; i++) { var rowId = rowIds[i]; var $row = jQuery('#' + rowId); // wenn kein Status LOADING mehr in der Zeile, dann sind Aktionen wieder m�glich if ($row.find('[data-dkb-status=\'LOADING\']').length === 0) { $row.removeClass('noActions'); stopLoadingForRow($row); } else { $row.addClass('noActions'); jQuery('#detailsRow-' + rowId).remove(); } } }; /** * Liefert die Verz�gerung f�r einen Updateversuch. * Nach 10 Versuchen, wird die Verz�gerung auf 10 Sekunden gesetzt. Nach weiteren 10 wird die Verz�gerung auf 30 Sekunden gesetzt. * Hinweis: Zur Verz�gerung kommt tats�chlich immer noch ca. 1 Sekunde aus dem setInterval-Delay hinzu * * @param attempts Updateversuche * @returns {number} */ function getDelayInMs(attempts) { var delayInMs = 0; // kein Delay (es gilt nur das Delay von setInterval) if (attempts > 10) { delayInMs = 1000 * 10; // nur noch alle 10 Sekunden } if (attempts > 20) { delayInMs = 1000 * 30; // ab jetzt nur noch alle 30 Sekunden } return delayInMs; } /** * Tabelle neu laden um den aktualisierten Status (Titel, Saldo, Icon, Message) anzuzeigen. * Intervall wird beendet, wenn alle Elemente der Tabelle geladen wurden oder die optionale, maximale Laufzeit f�r Updateversuche erreicht wurde. */ var refreshFinStat = function () { var loadingRows = collectAllLoadingRows(); // abbrechen wenn es keine Items mehr gibt, die geladen werden m�ssen if (loadingRows.length < 1) { clearInterval(settings.updateIntervalId); settings.updateIntervalId = undefined; settings.updateAttempts = 0; resetPollingEnd(); clearAllLoadingIndicators(); Abaxx.log.debug('Refresh finished. Loading rows remaining: ' + loadingRows.length); return; } if (loadingRows.length > 0 && !settings.xhrRunning) { settings.xhrRunning = true; settings.updateAttempts++; var delayInMs = getDelayInMs(settings.updateAttempts); var lastAttempt = maxRetryDurationReached(); Abaxx.log.debug('Update attempt #' + settings.updateAttempts + ' with delay: ' + delayInMs + ' last try? ' + lastAttempt); window.setTimeout(function () { loadNewFinStatState(loadingRows, settings.pollingUrl, {lastAttempt: lastAttempt}); }, delayInMs); } }; /** * L�dt das neue HTML vom Server (partialLoad). Es werden dabei nur die Zeilen im Status "loading" aktualisiert. * @param loadingRows IDs der Zeilen die aktualisiert werden sollen * @param url URL Ziel f�r Partial Load * @param data Data f�r Partial Load Request * @return {jQuery.Deferred} */ var loadNewFinStatState = function (loadingRows, url, data) { var selector = buildCssQueryString(loadingRows); // partialLoad da die aktualisierung der Tabelle synchron stattfinden muss um anschliessend // Dropdown-Listen initalisieren zu koennen var options = { reloadScripts: false, data: data }; return Abaxx.ajax.partialLoad(selector, url, options) .then(function () { // binding bei Dropdow-Listen geht durch partialLoad verloren -> erneut initialisieren initDropdown(); handleRowSpan(); updateActions(loadingRows); settings.xhrRunning = false; Abaxx.log.debug('partial reload finished'); }); }; /** * Setzt das "Polling-Ende" zur�ck */ function resetPollingEnd() { settings.retryEndTimeMs = undefined; } /** * Sammelt alle IDs der Zeilen, die den Zustand "LOADING" haben. * Diese Zeilen m�ssen aktualisiert werden. * * @return Array - enthaellt id's mit dem Status 'LOADING' */ var collectAllLoadingRows = function () { var loadingElements = document.querySelectorAll('[data-dkb-status=\'LOADING\']'); var rowsToLoad = []; for (var i = 0; i < loadingElements.length; i++) { rowsToLoad.push(loadingElements[i].getAttributeNode('data-dkb-rowId').value); } return rowsToLoad; }; /** * Sammelt alle IDs der Zeilen, die der uebergebenen Bankverbindung angeh�ren * * @param bankConnectionId Id der Bankverbindung * @returns {Array} */ var collectAllRowsForBankConnection = function (bankConnectionId) { var allElements = document.querySelectorAll('[data-dkb-bankConnection=\'' + bankConnectionId + '\']'); var rowsToLoad = []; for (var i = 0; i < allElements.length; i++) { rowsToLoad.push(allElements[i].getAttributeNode('data-dkb-rowId').value); } return rowsToLoad; }; /** * Erstellt einen kommaseparierten String aus den id's der Zeilen die noch nicht geladen wurden. * * @param rowIds * @returns String - ein kommaseparierten String aus dem uebergebenen array */ var buildCssQueryString = function (rowIds) { var elements = []; elements.push('#overallBalance'); // die optionale Gesamtsalden-Zeile aller Gruppen muss immer aktualsiert werden for (var i = 0; i < rowIds.length; i++) { var rowId = rowIds[i]; elements.push('#' + rowId); // die optionale Saldenzeile pro Gruppe ebenfalls aktualisieren var groupIndex = groupIndexFromRowId(rowId); var groupSumRowId = '#summe-gruppe-' + groupIndex; if (elements.indexOf(groupSumRowId) === -1) { elements.push(groupSumRowId); } // Status Information pro Konto anzeigen falls vorhanden var rowIndex = rowIndexFromRowId(rowId); var groupStatusRowId = '#status-info-' + rowIndex; if (elements.indexOf(groupStatusRowId) === -1) { elements.push(groupStatusRowId); } } return elements.join(','); }; /** * Ermittelt den Gruppen-Index anhand der RowId. * * @param rowId z.B. "gruppe-${groupLoop.index}_${rowIndex}" * @returns {string} */ function groupIndexFromRowId(rowId) { return rowId.substring(rowId.indexOf('-') + 1, rowId.indexOf('_')); } /** * Ermittelt den Index der Zeile (Gruppe_Zeile) * * @param rowId * @returns {string|*} */ function rowIndexFromRowId(rowId) { return rowId.substring(rowId.indexOf('-') + 1, rowId.length); } /** * Startet den Check f�r Updates und initialisiert das DOM * * @param updateUrl URL f�r das Ansto�en einer Aktualisierung f�r ein Konto/eine Kontengruppe * @param pollingUrl URL f�r das Polling nach aktualisierten Konten * @param maxUpdateDurationInSec maximale Zeit in der auf Updates gepr�ft wird (optional) */ function init(updateUrl, pollingUrl, maxUpdateDurationInSec) { if (updateUrl) { settings.updateUrl = updateUrl; } if (pollingUrl) { settings.pollingUrl = pollingUrl; } if (maxUpdateDurationInSec && maxUpdateDurationInSec > 0) { settings.maxPollingDurationInSec = maxUpdateDurationInSec; } if (settings.maxPollingDurationInSec > 0 && !settings.retryEndTimeMs) { settings.retryEndTimeMs = new Date().getTime() + settings.maxPollingDurationInSec * 1000; } var rowsToLoad = collectAllLoadingRows(); if (rowsToLoad.length > 0) { updateActions(rowsToLoad); if (!settings.updateIntervalId) { settings.updateIntervalId = setInterval(refreshFinStat, 1000); } } else { clearAllLoadingIndicators(); initDropdown(); } } /** * L�st eine Kontoaktualisierung aus * Client-seitig wird der Zustand aller Konten mit gleicher Bankverbindung direkt auf "LOADING" gesetzt. * Im Anschluss an den Server-Request (die eigentliche Aktualisierung) wird wieder die Initialisierung aufgerufen, um f�r noch nicht fertig geladenen Konten das Polling zu starten. * * @param element der Aktualisieren-Link/-Button */ var updateAccount = function (element) { var mainRow = jQuery(element).closest('tr'); if (mainRow.hasClass('detailsRow')) { var rowIndex = rowIndexFromRowId(mainRow.attr('id')); mainRow = jQuery(document).find('#' + rowIndex); } var bankConnectionId = mainRow.find('[data-dkb-bankconnection]').attr('data-dkb-bankconnection'); var rowIds = collectAllRowsForBankConnection(bankConnectionId); for (var i = 0; i < rowIds.length; i++) { var rowId = rowIds[i]; var $row = jQuery('#' + rowId); showLoaderForRow($row) } // triggert das Laden via PartialLoad - danach nochmal pr�fen, ob es loading rows gibt var rowIndex = element.getAttribute('data-dkb-row'); var groupIndex = element.getAttribute('data-dkb-group'); loadNewFinStatState(rowIds, settings.updateUrl, {row: rowIndex, group: groupIndex}).then(reinit, reinit); }; /** * Neu Initialisierung */ function reinit() { resetPollingEnd(); init(); } /** * @returns {boolean} true wenn die maximale Laufzeit f�r Updateversuche gesetzt wurde und verstrichen ist */ function maxRetryDurationReached() { if (!settings.retryEndTimeMs) { return false; } var remainingMs = settings.retryEndTimeMs - new Date().getTime(); return remainingMs <= 0; } /** * Alle Loading Indicator zur�cksetzen */ function clearAllLoadingIndicators() { jQuery('.is_loading').removeClass('is_loading'); } /** * Zeigt die Ladeanimation fuer die uebergeben Zeile an * * @param $row */ function showLoaderForRow($row) { $row.find('[data-dkb-status]').attr('data-dkb-status', 'LOADING'); $row.removeClass('expand'); $row.addClass('noActions'); $row.find('div.otherActions').hide(); $row.find('td').addClass('is_loading'); var $nextTr = $row.next(); if ($nextTr.hasClass('new_row_for_small')) { var newRow = $nextTr; newRow.find('td').addClass('is_loading'); $nextTr = $nextTr.next(); } if ($nextTr.hasClass('status-row')) { var statusRow = $nextTr; statusRow.hide(); $nextTr = $nextTr.next(); } if ($nextTr.hasClass('detailsRow')) { var $detailTr = $nextTr; $detailTr.hide(); $nextTr = $nextTr.next(); } if ($nextTr.hasClass('loading-bar-row')) { $nextTr.addClass('is_loading'); } } /** * Stoppt den Loading Indicator f�r die gegebene Zeile * <p>Die Zeile mit dem Loading Indicator ist entweder die n�chste oder �bern�chste Zeile (abh�ngig ob addDetailRow() ausgef�hrt wurde).</p> * @param $row jQuery Object */ function stopLoadingForRow($row) { var $nextTr = $row.next(); var $loadingIndicatorTr = $nextTr; if ($nextTr.hasClass('detailsRow')) { $loadingIndicatorTr = $nextTr.next(); } $loadingIndicatorTr.removeClass('is_loading'); } /** * Validiert das Eingabefeld * * @param fieldSelector */ function validateMandatoryInputField(fieldSelector) { var $field = jQuery(fieldSelector); if ($field.length > 0) { if (!jQuery.trim($field.val()).length) { $field.addClass('error'); } else { $field.removeClass('error'); } } } return { init: init, updateAccount: updateAccount, }; });