Bug 11516: make OPAC search term highlighting work in results browser
[koha.git] / koha-tmpl / opac-tmpl / bootstrap / lib / respond.src.js
1 /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
2 /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
3
4 window.matchMedia = window.matchMedia || (function( doc, undefined ) {
5
6   "use strict";
7
8   var bool,
9       docElem = doc.documentElement,
10       refNode = docElem.firstElementChild || docElem.firstChild,
11       // fakeBody required for <FF4 when executed in <head>
12       fakeBody = doc.createElement( "body" ),
13       div = doc.createElement( "div" );
14
15   div.id = "mq-test-1";
16   div.style.cssText = "position:absolute;top:-100em";
17   fakeBody.style.background = "none";
18   fakeBody.appendChild(div);
19
20   return function(q){
21
22     div.innerHTML = "&shy;<style media=\"" + q + "\"> #mq-test-1 { width: 42px; }</style>";
23
24     docElem.insertBefore( fakeBody, refNode );
25     bool = div.offsetWidth === 42;
26     docElem.removeChild( fakeBody );
27
28     return {
29       matches: bool,
30       media: q
31     };
32
33   };
34
35 }( document ));
36
37
38
39
40
41 /*! Respond.js v1.1.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs  */
42 (function( win ){
43
44         "use strict";
45
46         //exposed namespace
47         var respond = {};
48         win.respond = respond;
49
50         //define update even in native-mq-supporting browsers, to avoid errors
51         respond.update = function(){};
52
53         //expose media query support flag for external use
54         respond.mediaQueriesSupported   = win.matchMedia && win.matchMedia( "only all" ).matches;
55
56         //if media queries are supported, exit here
57         if( respond.mediaQueriesSupported ){
58                 return;
59         }
60
61         //define vars
62         var doc = win.document,
63                 docElem = doc.documentElement,
64                 mediastyles = [],
65                 rules = [],
66                 appendedEls = [],
67                 parsedSheets = {},
68                 resizeThrottle = 30,
69                 head = doc.getElementsByTagName( "head" )[0] || docElem,
70                 base = doc.getElementsByTagName( "base" )[0],
71                 links = head.getElementsByTagName( "link" ),
72                 requestQueue = [],
73
74                 //loop stylesheets, send text content to translate
75                 ripCSS = function(){
76
77                         for( var i = 0; i < links.length; i++ ){
78                                 var sheet = links[ i ],
79                                 href = sheet.href,
80                                 media = sheet.media,
81                                 isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
82
83                                 //only links plz and prevent re-parsing
84                                 if( !!href && isCSS && !parsedSheets[ href ] ){
85                                         // selectivizr exposes css through the rawCssText expando
86                                         if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
87                                                 translate( sheet.styleSheet.rawCssText, href, media );
88                                                 parsedSheets[ href ] = true;
89                                         } else {
90                                                 if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base) ||
91                                                         href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
92                                                         requestQueue.push( {
93                                                                 href: href,
94                                                                 media: media
95                                                         } );
96                                                 }
97                                         }
98                                 }
99                         }
100                         makeRequests();
101                 },
102
103                 //recurse through request queue, get css text
104                 makeRequests    = function(){
105                         if( requestQueue.length ){
106                                 var thisRequest = requestQueue.shift();
107
108                                 ajax( thisRequest.href, function( styles ){
109                                         translate( styles, thisRequest.href, thisRequest.media );
110                                         parsedSheets[ thisRequest.href ] = true;
111
112                                         // by wrapping recursive function call in setTimeout
113                                         // we prevent "Stack overflow" error in IE7
114                                         win.setTimeout(function(){ makeRequests(); },0);
115                                 } );
116                         }
117                 },
118
119                 //find media blocks in css text, convert to style blocks
120                 translate = function( styles, href, media ){
121                         var qs = styles.match(  /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ),
122                                 ql = qs && qs.length || 0;
123
124                         //try to get CSS path
125                         href = href.substring( 0, href.lastIndexOf( "/" ) );
126
127                         var repUrls     = function( css ){
128                                         return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" );
129                                 },
130                                 useMedia = !ql && media;
131
132                         //if path exists, tack on trailing slash
133                         if( href.length ){ href += "/"; }
134
135                         //if no internal queries exist, but media attr does, use that
136                         //note: this currently lacks support for situations where a media attr is specified on a link AND
137                                 //its associated stylesheet has internal CSS media queries.
138                                 //In those cases, the media attribute will currently be ignored.
139                         if( useMedia ){
140                                 ql = 1;
141                         }
142
143                         for( var i = 0; i < ql; i++ ){
144                                 var fullq, thisq, eachq, eql;
145
146                                 //media attr
147                                 if( useMedia ){
148                                         fullq = media;
149                                         rules.push( repUrls( styles ) );
150                                 }
151                                 //parse for styles
152                                 else{
153                                         fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1;
154                                         rules.push( RegExp.$2 && repUrls( RegExp.$2 ) );
155                                 }
156
157                                 eachq = fullq.split( "," );
158                                 eql     = eachq.length;
159
160                                 for( var j = 0; j < eql; j++ ){
161                                         thisq = eachq[ j ];
162                                         mediastyles.push( {
163                                                 media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all",
164                                                 rules : rules.length - 1,
165                                                 hasquery : thisq.indexOf("(") > -1,
166                                                 minw : thisq.match( /\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ),
167                                                 maxw : thisq.match( /\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" )
168                                         } );
169                                 }
170                         }
171
172                         applyMedia();
173                 },
174
175                 lastCall,
176
177                 resizeDefer,
178
179                 // returns the value of 1em in pixels
180                 getEmValue = function() {
181                         var ret,
182                                 div = doc.createElement('div'),
183                                 body = doc.body,
184                                 fakeUsed = false;
185
186                         div.style.cssText = "position:absolute;font-size:1em;width:1em";
187
188                         if( !body ){
189                                 body = fakeUsed = doc.createElement( "body" );
190                                 body.style.background = "none";
191                         }
192
193                         body.appendChild( div );
194
195                         docElem.insertBefore( body, docElem.firstChild );
196
197                         ret = div.offsetWidth;
198
199                         if( fakeUsed ){
200                                 docElem.removeChild( body );
201                         }
202                         else {
203                                 body.removeChild( div );
204                         }
205
206                         //also update eminpx before returning
207                         ret = eminpx = parseFloat(ret);
208
209                         return ret;
210                 },
211
212                 //cached container for 1em value, populated the first time it's needed
213                 eminpx,
214
215                 //enable/disable styles
216                 applyMedia = function( fromResize ){
217                         var name = "clientWidth",
218                                 docElemProp = docElem[ name ],
219                                 currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp,
220                                 styleBlocks     = {},
221                                 lastLink = links[ links.length-1 ],
222                                 now = (new Date()).getTime();
223
224                         //throttle resize calls
225                         if( fromResize && lastCall && now - lastCall < resizeThrottle ){
226                                 win.clearTimeout( resizeDefer );
227                                 resizeDefer = win.setTimeout( applyMedia, resizeThrottle );
228                                 return;
229                         }
230                         else {
231                                 lastCall = now;
232                         }
233
234                         for( var i in mediastyles ){
235                                 if( mediastyles.hasOwnProperty( i ) ){
236                                         var thisstyle = mediastyles[ i ],
237                                                 min = thisstyle.minw,
238                                                 max = thisstyle.maxw,
239                                                 minnull = min === null,
240                                                 maxnull = max === null,
241                                                 em = "em";
242
243                                         if( !!min ){
244                                                 min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
245                                         }
246                                         if( !!max ){
247                                                 max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
248                                         }
249
250                                         // if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true
251                                         if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){
252                                                 if( !styleBlocks[ thisstyle.media ] ){
253                                                         styleBlocks[ thisstyle.media ] = [];
254                                                 }
255                                                 styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] );
256                                         }
257                                 }
258                         }
259
260                         //remove any existing respond style element(s)
261                         for( var j in appendedEls ){
262                                 if( appendedEls.hasOwnProperty( j ) ){
263                                         if( appendedEls[ j ] && appendedEls[ j ].parentNode === head ){
264                                                 head.removeChild( appendedEls[ j ] );
265                                         }
266                                 }
267                         }
268
269                         //inject active styles, grouped by media type
270                         for( var k in styleBlocks ){
271                                 if( styleBlocks.hasOwnProperty( k ) ){
272                                         var ss = doc.createElement( "style" ),
273                                                 css = styleBlocks[ k ].join( "\n" );
274
275                                         ss.type = "text/css";
276                                         ss.media = k;
277
278                                         //originally, ss was appended to a documentFragment and sheets were appended in bulk.
279                                         //this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one!
280                                         head.insertBefore( ss, lastLink.nextSibling );
281
282                                         if ( ss.styleSheet ){
283                                                 ss.styleSheet.cssText = css;
284                                         }
285                                         else {
286                                                 ss.appendChild( doc.createTextNode( css ) );
287                                         }
288
289                                         //push to appendedEls to track for later removal
290                                         appendedEls.push( ss );
291                                 }
292                         }
293                 },
294                 //tweaked Ajax functions from Quirksmode
295                 ajax = function( url, callback ) {
296                         var req = xmlHttp();
297                         if (!req){
298                                 return;
299                         }
300                         req.open( "GET", url, true );
301                         req.onreadystatechange = function () {
302                                 if ( req.readyState !== 4 || req.status !== 200 && req.status !== 304 ){
303                                         return;
304                                 }
305                                 callback( req.responseText );
306                         };
307                         if ( req.readyState === 4 ){
308                                 return;
309                         }
310                         req.send( null );
311                 },
312                 //define ajax obj
313                 xmlHttp = (function() {
314                         var xmlhttpmethod = false;
315                         try {
316                                 xmlhttpmethod = new win.XMLHttpRequest();
317                         }
318                         catch( e ){
319                                 xmlhttpmethod = new win.ActiveXObject( "Microsoft.XMLHTTP" );
320                         }
321                         return function(){
322                                 return xmlhttpmethod;
323                         };
324                 })();
325
326         //translate CSS
327         ripCSS();
328
329         //expose update for re-running respond later on
330         respond.update = ripCSS;
331
332         //adjust on resize
333         function callMedia(){
334                 applyMedia( true );
335         }
336         if( win.addEventListener ){
337                 win.addEventListener( "resize", callMedia, false );
338         }
339         else if( win.attachEvent ){
340                 win.attachEvent( "onresize", callMedia );
341         }
342 })(this);