1 /* 2 * vim:set spell spl=en fo=wan1croqlt tw=80 ts=2 sw=2 sts=2 sta et ai cin fenc=utf-8 ff=unix: 3 * 4 * Copyright (C) 2008, 2009 Mihai Şucan 5 * 6 * This file is part of libmacrame. 7 * 8 * Libmacrame is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * Libmacrame is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with Libmacrame. If not, see <http://www.gnu.org/licenses/>. 20 * 21 * $URL: http://code.google.com/p/libmacrame $ 22 * $Date: 2009-04-17 19:06:03 +0300 $ 23 * 24 */ 25 26 /** 27 * @author <a lang="ro" href="http://www.robodesign.ro/mihai">Mihai Şucan</a> 28 * @version Pre-alpha release. In-design phase, unstable API. 29 * @fileOverview The libmacrame core code. 30 */ 31 32 33 (function () { 34 35 /* 36 * This defines the global alias to use for the libmacrame object. Set this to 37 * false if you don't want any global object. 38 */ 39 var _alias = '$'; 40 41 /** 42 * The global libmacrame object which can't be changed, and which must be used 43 * by any plugins extending the functionality of the library. 44 * 45 * @function 46 * @name libmacrame 47 * @see $ By default, the entire libmacrame object is aliased by $, for quicker 48 * access. 49 * @see $.init The function being called, when you call libmacrame(). 50 * 51 * @param {String} selector 52 * @param {Document|Element} [context=document] 53 */ 54 function libmacrame (selector, context) { 55 return $.init(selector, context); 56 } 57 58 if (_alias) { 59 window[_alias] = libmacrame; 60 } 61 62 window.libmacrame = libmacrame; 63 64 /** 65 * The $ symbol is simply an alias of {@link libmacrame}, for quicker access to 66 * the main namespace and main function, which is {@link $.init}. 67 * 68 * @class The libmacrame namespace. 69 * @name $ 70 * @see libmacrame 71 * @see $.init This is the function called when you call $() 72 * 73 * @param {String} selector 74 * @param {Document|Element} [context=document] 75 */ 76 var $ = libmacrame; 77 78 /* 79 * This regular expression used to quickly match ID and class name CSS 80 * selectors. 81 */ 82 var re_id_class = /^(#|\.)?([a-zA-Z][a-zA-Z\d_-]*)$/; 83 84 /** 85 * Find DOM elements. 86 * 87 * <p>This function currently allows you to use CSS selectors to find the DOM 88 * elements you want. 89 * 90 * <p>TODO: This is not done yet. 91 * 92 * @requires A Web browser which implements <a 93 * href="http://www.w3.org/TR/selectors-api/">Selectors API</a>. Currently this 94 * means <a href="http://opera.com">Opera</a> 10+, <a 95 * href="http://mozilla.com">Firefox</a> 3.1+ and <a 96 * href="http://apple.com/safari">Safari</a> 4+. 97 * 98 * @example 99 * // Find the element with id='foo': 100 * 101 * <code>$('#foo');</code> 102 * 103 * @example 104 * // Find the elements having a class token 'foo': 105 * 106 * <code>$('.foo');</code> 107 * 108 * @example 109 * // Find all the <code><span></code> elements which are direct child 110 * // children of <code><p></code> elements: 111 * 112 * <code>$('p > span');</code> 113 * 114 * @param {String} selector The CSS selector. You can also use multiple 115 * selectors, separated by comma. Basically, you can use anything supported by 116 * querySelectorAll(). 117 * 118 * @param {Document|Element} [context=document] The context where the CSS 119 * selector will be used for finding the matching elements. 120 * 121 * @returns {Element|NodeList} The element found, or the list of elements 122 * matching the selector. 123 */ 124 $.init = function (selector, context) { 125 if (!selector || typeof selector != 'string') { 126 return selector; 127 } 128 129 if (!context) { 130 context = document; 131 } 132 133 var elem = false, 134 match = re_id_class.exec(selector); 135 136 // If the selector is not an ID/class name, then just use the query selector. 137 if (!match) { 138 return context.querySelectorAll(selector); 139 } 140 141 if (match[1] == '#' && match[2]) { 142 elem = context.getElementById(match[2]); 143 } else if (match[1] == '.' && match[2]) { 144 elem = context.getElementsByClassName(match[2]); 145 } else if (match[2]) { 146 elem = context.getElementsByTagName(match[2]); 147 } else { 148 elem = context.querySelectorAll(selector); 149 } 150 151 return elem; 152 }; 153 154 /** 155 * @namespace Holds browser information. 156 */ 157 $.browser = {}; 158 159 var ua = '', b = {}; 160 161 if (window.navigator && window.navigator.userAgent) { 162 ua = window.navigator.userAgent.toLowerCase(); 163 } 164 165 /** 166 * Determine the browser version. 167 * 168 * @param {String} name The browser name you want to search for, in the User 169 * Agent string. The string is not escaped, thus you must use regular expression 170 * syntax. 171 * 172 * @param {Number} [pos=1] The index of the matching parenthesis in the regular 173 * expressiong. The value of the index will be returned by this function 174 * (ua.match(regex)). 175 * 176 * @returns {String|null} The matching version number. 177 */ 178 b.findVer = function (name, pos) { 179 var regex = '\\b' + name + '[\\/: ]([0-9a-z.+-]+)'; 180 var res = ua.match(new RegExp(regex)); 181 if (!pos) { 182 pos = 1; 183 } 184 185 return res ? res[pos] : null; 186 }; 187 188 /** 189 * @name $.browser.opera 190 * @type Boolean 191 */ 192 b.opera = window.opera ? true : /\bopera\b/.test(ua); 193 194 /** 195 * @name $.browser.operaVersion 196 */ 197 b.operaVersion = null; 198 199 if (window.opera && window.opera.version) { 200 b.operaVersion = typeof window.opera.version == 'function' 201 ? window.opera.version() : window.opera.version; 202 } else if (b.opera) { 203 b.operaVersion = b.findVer('opera'); 204 } 205 206 /** 207 * Webkit is the render engine used primarily by Safari. It's also used by 208 * Google Chrome and GNOME Epiphany. 209 * 210 * @name $.browser.webkit 211 * @type Boolean 212 */ 213 b.webkit = /\b(applewebkit|webkit)\b/.test(ua); 214 215 /** 216 * @name $.browser.webkitVersion 217 */ 218 b.webkitVersion = b.webkit ? b.findVer('(applewebkit|webkit)', 2) : null; 219 220 /** 221 * Epiphany is the default Web browser of the GNOME desktop environment. 222 * 223 * @name $.browser.epiphany 224 * @type Boolean 225 */ 226 b.epiphany = /\bepiphany\b/.test(ua); 227 228 /** 229 * @name $.browser.epiphanyVersion 230 */ 231 b.epiphanyVersion = b.epiphany ? b.findVer('epiphany') : null; 232 233 /** 234 * Firefox uses the Gecko render engine. 235 * 236 * 237 * @name $.browser.firefox 238 * @type Boolean 239 */ 240 // In some variations of the User Agent strings provided by Epiphany and Opera, 241 // Firefox is mentioned. 242 b.firefox = /\bfirefox\b/.test(ua) && !b.opera && !b.epiphany; 243 244 /** 245 * @name $.browser.firefoxVersion 246 */ 247 b.firefoxVersion = b.firefox ? b.findVer('firefox') : null; 248 249 /** 250 * Gecko is the render engine used by Firefox and related products. 251 * 252 * @name $.browser.gecko 253 * @type Boolean 254 */ 255 // Typically, the user agent string of WebKit also mentions Gecko. Additionally, 256 // Opera mentions Gecko for tricking some sites. 257 b.gecko = /\bgecko\b/.test(ua) && !b.opera && !b.webkit; 258 // TODO: b.geckoRevision 259 260 /** 261 * @name $.browser.geckoBuild 262 */ 263 b.geckoBuild = b.gecko ? b.findVer('gecko') : null; 264 265 /** 266 * KHTML is the render engine used by Konqueror. 267 * 268 * @name $.browser.khtml 269 * @type Boolean 270 */ 271 // Epiphany does mention KHTML... 272 b.khtml = /\bkhtml\b/.test(ua) && !b.epiphany; 273 274 /** 275 * @name $.browser.khtmlVersion 276 */ 277 b.khtmlVersion = b.khtml ? b.findVer('khtml') : null; 278 279 /** 280 * Konqueror is the Web browser of the KDE desktop environment. 281 * 282 * @name $.browser.konqueror 283 * @type Boolean 284 */ 285 b.konqueror = /\bkonqueror\b/.test(ua); 286 287 /** 288 * @name $.browser.konquerorVersion 289 */ 290 b.konquerorVersion = b.konqueror ? b.findVer('konqueror') : null; 291 292 /** 293 * Google Chrome uses WebKit as the render engine. 294 * 295 * @name $.browser.chrome 296 * @type Boolean 297 */ 298 b.chrome = /\bchrome\b/.test(ua); 299 300 /** 301 * @name $.browser.chromeVersion 302 */ 303 b.chromeVersion = b.chrome ? b.findVer('chrome') : null; 304 305 /** 306 * Microsoft Internet Explorer. The future of computing. 307 * 308 * @name $.browser.msie 309 * @type Boolean 310 */ 311 // Again, Opera allows users to easily fake the UA. 312 b.msie = /\bmsie\b/.test(ua) && !b.opera; 313 314 /** 315 * @name $.browser.msieVersion 316 */ 317 b.msieVersion = b.msie ? b.findVer('msie') : null; 318 319 /** 320 * Presto is the render engine used by Opera. 321 * 322 * @name $.browser.presto 323 * @type Boolean 324 */ 325 // Older versions of Opera did not mention Presto in the UA string. 326 b.presto = /\bpresto\b/.test(ua) || b.opera; 327 328 /** 329 * @name $.browser.prestoVersion 330 */ 331 b.prestoVersion = b.presto ? b.findVer('presto') : null; 332 333 /** 334 * @name $.browser.mozilla 335 * @type Boolean 336 */ 337 // Everyone mentions Mozilla. Hehe. 338 b.mozilla = /\bmozilla\b/.test(ua) && !b.opera && !b.webkit && !b.presto; 339 340 /** 341 * Safari is the default Web browser of Mac OS, from Apple. It uses the WebKit 342 * render engine. 343 * 344 * @name $.browser.safari 345 * @type Boolean 346 */ 347 // Google Chrome mentions Safari and Epiphany does this as well. 348 b.safari = /\bsafari\b/.test(ua) && b.webkit && !b.epiphany && !b.chrome; 349 350 /** 351 * @name $.browser.safariVersion 352 */ 353 b.safariVersion = b.safari ? b.findVer('safari') : null; 354 355 356 /** 357 * The browser name. If the browser is unrecognized, it will contain the browser 358 * engine name. If all fails, the property will be null. 359 * 360 * @name $.browser.name 361 * @type String 362 */ 363 // Here the order is important: start with the browsers, and end with the engine 364 // names. 365 b.name = b.epiphany ? 'epiphany' : ( 366 b.firefox ? 'firefox' : ( 367 b.konqueror ? 'konqueror' : ( 368 b.opera ? 'opera' : ( 369 b.msie ? 'msie' : ( 370 b.chrome ? 'chrome' : ( 371 b.safari ? 'safari' : ( 372 b.presto ? 'presto' : ( 373 b.khtml ? 'khtml' : ( 374 b.webkit ? 'webkit' : ( 375 b.gecko ? 'gecko' : ( 376 b.mozilla ? 'mozilla' : null))))))))))); 377 378 /** 379 * The version of the browser or render engine. 380 * 381 * @name $.browser.version 382 * @type String 383 */ 384 b.version = b[b.name + 'Version']; 385 386 /** 387 * Browser operating system 388 * 389 * @name $.browser.os 390 * @type String 391 */ 392 b.os = (ua.match(/\b(windows|linux)\b/) || [])[1]; 393 394 delete b.findVer; 395 396 $.browser = b; 397 398 delete b, ua; 399 400 /** 401 * This function extends objects. 402 * 403 * @example 404 * <code>var <var>obj1</var> = {a: 'a1', b: 'b1', d: 'd1'}, 405 * <var>obj2</var> = {a: 'a2', b: 'b2', c: 'c2'}; 406 * 407 * $.extend(<var>obj1</var>, <var>obj2</var>);</code> 408 * 409 * // Now <var>obj1.c == 'c2'</var>, while <var>obj1.a</var>, <var>obj1.b</var> 410 * // and <var>obj1.d</var> remain the same. 411 * 412 * // If <code>$.extend(true, <var>obj1</var>, <var>obj2</var>)</code> is 413 * // called, then <var>obj1.a</var>, <var>obj1.b</var>, <var>obj1.c</var> 414 * // become all the same as in <var>obj2</var>. 415 * 416 * @example 417 * <code>var <var>obj1</var> = {a: 'a1', b: 'b1', extend: $.extend}; 418 * <var>obj1</var>.extend({c: 'c1', d: 'd1'});</code> 419 * 420 * // In this case the destination object which is to be extend is 421 * // <var>obj1</var>. 422 * 423 * @param {Boolean} [overwrite=false] If the first argument is a boolean, then 424 * it will be considered as a boolean flag for overwriting (or not) any existing 425 * methods and properties in the destination object. Thus, any method and 426 * property from the source object will take over those in the destination. The 427 * argument is optional, and if it's omitted, then no method/property will be 428 * overwritten. 429 * 430 * @param {Object} [destination=this] The second argument is the optional 431 * destination object: the object which will be extended. By default, the 432 * <var>this</var> object will be extended. 433 * 434 * @param {Object} source The third argument must provide list of methods and 435 * properties which will be added to the destination object. 436 */ 437 $.extend = function extend () { 438 var i = 0, 439 len = arguments.length, 440 name, src, sval, dval; 441 442 if (typeof arguments[0] == 'boolean') { 443 force = arguments[0]; 444 dest = arguments[1]; 445 src = arguments[2]; 446 } else { 447 force = false; 448 dest = arguments[0]; 449 src = arguments[1]; 450 } 451 452 if (typeof src == 'undefined') { 453 src = dest; 454 dest = this; 455 } 456 457 if (typeof dest == 'undefined') { 458 return; 459 } 460 461 for (name in src) { 462 sval = src[name]; 463 dval = dest[name]; 464 if (force || typeof dval == 'undefined') { 465 dest[name] = sval; 466 } 467 } 468 }; 469 470 })(); 471 472