12061Sjkh<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"> 250479Speter<html lang="en"> 32061Sjkh<head profile="http://www.w3.org/2006/03/hcard"> 438666Sjb<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> 532427Sjb<title>libxo: The Easy Way to Generate text, XML, JSON, and HTML output</title> 6111131Sru<style type="text/css">/* 7111131Sru * $Id$ 838666Sjb * 938666Sjb * Copyright (c) 2006-2011, Juniper Networks, Inc. 1038666Sjb * All rights reserved. 1138666Sjb * This SOFTWARE is licensed under the LICENSE provided in the 1264049Salex * ../Copyright file. By downloading, installing, copying, or otherwise 1364049Salex * using the SOFTWARE, you agree to be bound by the terms of that 14116679Ssimokawa * LICENSE. 1566071Smarkm */ 16116679Ssimokawa 1773504Sobrien#media-inspector { 1838666Sjb display:none 1932427Sjb} 2038666Sjb@media screen { 21108451Sschweikh #media-inspector { z-index: 1 } 2238666Sjb} 2338666Sjb@media print { 2438666Sjb #media-inspector { z-index: 2 } 2538666Sjb} 2617308Speter 2791606Skeramidapre { 2819175Sbde font-family: Consolas, Menlo, Monaco,Lucida Console, Liberation Mono, 2996205Sjwd DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, 3096205Sjwd monospace, serif; 3138042Sbde margin-bottom: 10px; 3296205Sjwd} 3396205Sjwd 3438042Sbde@media screen { 3596205Sjwd hr.noprint { 3696205Sjwd display: none; 3717308Speter } 3896205Sjwd 3996205Sjwd h1, h2, h3, h4, h5 { 4017308Speter font-size: 14pt; 4196205Sjwd color: black; 4296205Sjwd margin: 0; 4396205Sjwd padding: 0; 4496205Sjwd } 4596205Sjwd h1 a, h2 a, h3 a, h4 a, h5 a { 4696205Sjwd font-size: 12pt; 4796205Sjwd color: black; 4896205Sjwd } 4996205Sjwd 5096205Sjwd div#top { 5196205Sjwd display: table; 5296205Sjwd } 5398775Sdillon 5498723Sdillon div#top-left { 5598723Sdillon display: table-cell; 5698723Sdillon width: 400px; 5798723Sdillon border: 1px solid black; 5838666Sjb border-right: 0px; 5938666Sjb } 6017308Speter 6195509Sru div#top-right { 6295793Sru display: table-cell; 63116679Ssimokawa width: 100%; 64120760Sru border: 1px solid black; 65116679Ssimokawa } 66120760Sru 672061Sjkh div.section-number { 6897769Sru display: none; 6997252Sru } 70119579Sru 7197252Sru div.fake-content { 7295730Sru display: block; 7395793Sru background-color: #d0d0f0; 74111617Sru } 7595730Sru 76116679Ssimokawa div.fake-active { 7795730Sru display: block; 78116679Ssimokawa background-color: #f0d0d0; 7995730Sru } 80110035Sru 81107516Sru div#nav-bar { 82110035Sru display: inline-block; 83117234Sru float: right; 84110035Sru } 85117229Sru 86117234Sru div#nav-bar button#nav-next { 8754324Smarcel margin-right: 1em; 8817308Speter } 89119519Smarcel 90119519Smarcel div#nav-bar button { 91119519Smarcel border-radius: 4px; 92119519Smarcel } 93119519Smarcel 94119519Smarcel div.content { 95119579Sru display: none; 96119519Smarcel } 97119519Smarcel 98119519Smarcel div.active { 99119519Smarcel display: block; 100119519Smarcel } 10138666Sjb 10217308Speter a.toc-active { 103119519Smarcel background-color: #dddddd; 104119579Sru } 10538666Sjb 106110035Sru div.self-section-number { 1072302Spaul display: none; 10839206Sjkh } 10939206Sjkh 11039206Sjkh div#debug-log { 11173349Sru white-space: pre-wrap; 11217308Speter } 11354324Smarcel 11454324Smarcel h1, h2, h3, h4, h5 { 11554324Smarcel margin: 0; 11654324Smarcel } 11754324Smarcel 11854324Smarcel div#toc { 11954324Smarcel overflow-y: scroll; 120118531Sru } 12154324Smarcel 12254324Smarcel div#toc > ul.toc { 12354324Smarcel margin-left: 2px; 12454324Smarcel } 12554324Smarcel 12654324Smarcel table.header { 127110035Sru display: none; 12854324Smarcel } 129110035Sru 130110035Sru p#title span.filename { 13154324Smarcel display: none; 13254324Smarcel } 13354324Smarcel 13454324Smarcel p#title { 13554324Smarcel margin-top: 20px; 136110035Sru } 13754324Smarcel 13854324Smarcel ul.top-toc { 13954324Smarcel display: none; 140118531Sru } 141118531Sru 14254324Smarcel ul.top-toc-open { 14354324Smarcel display: block; 14454324Smarcel } 14595730Sru 14695730Sru div.padding { 14795730Sru width: 300px; 14895730Sru } 14995730Sru 15095730Sru} 15195730Sru 15238666Sjb@media print { 153107374Sru div.self-section-number, div.section-number { 15417308Speter display: block-inline; 15555678Smarcel } 156110035Sru 157117793Sru button { 158110035Sru display: none; 159110035Sru } 160110035Sru 1612061Sjkh h1 { 16217308Speter font-size: 14pt; 163107516Sru /* line-height: 21pt;*/ 164107374Sru page-break-after: avoid; 16555678Smarcel } 166107516Sru h1.np { 167107516Sru page-break-before: always; 168107516Sru } 169107516Sru h1 a { 170107516Sru color: #333333; 171107516Sru } 172107516Sru h2 { 173107516Sru font-size: 12pt; 174122204Skris /* line-height: 15pt; */ 17555678Smarcel page-break-after: avoid; 17655678Smarcel } 177116696Sru h2 a { 17855678Smarcel color: black; 17955678Smarcel } 180107516Sru h3 { 181107516Sru font-size: 10pt; 182107516Sru page-break-after: avoid; 183107516Sru } 18455678Smarcel h3 a { 18555678Smarcel color: black; 186111131Sru } 187111131Sru h4 { 188111131Sru font-size: 10pt; 189111131Sru page-break-after: avoid; 190111131Sru } 191111131Sru h4 a { 192111131Sru color: black; 193103985Sphk } 194103985Sphk h5 { 195103985Sphk font-size: 10pt; 196103985Sphk page-break-after: avoid; 197111089Sphk } 198111131Sru h5 a { 199111131Sru color: black; 200111131Sru } 201111131Sru} 202111131Sru 203111131Srup.section-contents, p.section-contents + ul { 204111131Sru background-color: #f8f8ff; 205111131Sru padding: 1em 0px 1em 3em; 206111131Sru border: 1px dotted #0000c0; 207111133Sru} 208103985Sphk 209111131Srup.section-contents + ul { 210111131Sru margin: 0px 1em 0px 3em; 211103985Sphk border-top: 0px; 212111131Sru} 213103985Sphk 214118531Srup.section-contents { 215118531Sru margin: 3em 1em 0px 3em; 216103985Sphk font-weight: bold; 217103985Sphk border-bottom: 0px; 218111131Sru padding-bottom: 0px; 219111131Sru} 220103985Sphk</style> 221103985Sphk<style type="text/css" title="Xml2Rfc (sans serif)"> 222111131Srua { 223111131Sru text-decoration: none; 224111131Sru} 225111131Srua.smpl { 226111131Sru color: black; 227103985Sphk} 228a:hover { 229 text-decoration: underline; 230} 231a:active { 232 text-decoration: underline; 233} 234address { 235 margin-top: 1em; 236 margin-left: 2em; 237 font-style: normal; 238} 239body { 240 color: black; 241 font-family: verdana, helvetica, arial, sans-serif; 242 font-size: 10pt; 243} 244cite { 245 font-style: normal; 246} 247dd { 248 margin-right: 2em; 249} 250dl { 251 margin-left: 2em; 252} 253 254dl.empty dd { 255 margin-top: .5em; 256} 257dl p { 258 margin-left: 0em; 259} 260dt { 261 margin-top: .5em; 262} 263img { 264 margin-left: 3em; 265} 266li { 267 margin-left: 2em; 268 margin-right: 2em; 269} 270ol { 271 margin-left: 2em; 272 margin-right: 2em; 273} 274ol p { 275 margin-left: 0em; 276} 277p { 278 margin-left: 2em; 279 margin-right: 2em; 280} 281pre { 282 margin-left: 3em; 283 background-color: lightyellow; 284 padding: .25em; 285 padding-top: 12px; 286 margin-right: 1em; 287 -moz-box-shadow: 0 0 4px #000000; 288 -webkit-box-shadow: 0 0 4px #000000; 289 box-shadow: 0 0 4px #000000; 290} 291pre.text2 { 292 border-style: dotted; 293 border-width: 1px; 294 background-color: #f0f0f0; 295 width: 69em; 296} 297pre.inline { 298 background-color: white; 299 padding: 0em; 300} 301pre.text { 302 border-style: dotted; 303 border-width: 1px; 304 background-color: #f8f8f8; 305 width: 69em; 306} 307pre.drawing { 308 border-style: solid; 309 border-width: 1px; 310 background-color: #f8f8f8; 311 padding: 2em; 312} 313table { 314 margin-left: 2em; 315} 316table.tt { 317 vertical-align: top; 318} 319table.full { 320 border-style: outset; 321 border-width: 1px; 322 margin-left: 3em; 323 background-color: lightyellow; 324 padding: .25em; 325 -moz-box-shadow: 0 0 4px #000000; 326 -webkit-box-shadow: 0 0 4px #000000; 327 box-shadow: 0 0 4px #000000; 328} 329table.headers { 330 border-style: outset; 331 border-width: 1px; 332} 333table.tt td { 334 vertical-align: top; 335} 336table.full td { 337 border-style: inset; 338 border-width: 1px; 339} 340table.tt th { 341 vertical-align: top; 342} 343table.full th { 344 border-style: inset; 345 border-width: 1px; 346} 347table.headers th { 348 border-style: none none inset none; 349 border-width: 1px; 350} 351table.header { 352 width: 95%; 353 font-size: 10pt; 354 color: white; 355} 356td.top { 357 vertical-align: top; 358} 359td.topnowrap { 360 vertical-align: top; 361 white-space: nowrap; 362} 363td.header { 364 background-color: gray; 365 width: 50%; 366} 367td.header a { 368 color: white; 369} 370td.reference { 371 vertical-align: top; 372 white-space: nowrap; 373 padding-right: 1em; 374} 375thead { 376 display:table-header-group; 377} 378ul.toc { 379 list-style: none; 380 margin-left: 1.5em; 381 margin-right: 0em; 382 padding-left: 0em; 383} 384li.tocline0 { 385 line-height: 150%; 386 font-weight: bold; 387 font-size: 10pt; 388 margin-left: 0em; 389 margin-right: 0em; 390} 391li.tocline1 { 392 line-height: normal; 393 font-weight: normal; 394 font-size: 9pt; 395 margin-left: 0em; 396 margin-right: 0em; 397} 398li.tocline2 { 399 font-size: 0pt; 400} 401ul p { 402 margin-left: 0em; 403} 404ul.ind { 405 list-style: none; 406 margin-left: 1.5em; 407 margin-right: 0em; 408 padding-left: 0em; 409} 410li.indline0 { 411 font-weight: bold; 412 line-height: 200%; 413 margin-left: 0em; 414 margin-right: 0em; 415} 416li.indline1 { 417 font-weight: normal; 418 line-height: 150%; 419 margin-left: 0em; 420 margin-right: 0em; 421} 422 423.comment { 424 background-color: yellow; 425} 426.center { 427 text-align: center; 428} 429.error { 430 color: red; 431 font-style: italic; 432 font-weight: bold; 433} 434.figure { 435 font-weight: bold; 436 text-align: center; 437 font-size: 9pt; 438} 439.filename { 440 color: #333333; 441 font-weight: bold; 442 font-size: 12pt; 443 line-height: 21pt; 444 text-align: center; 445} 446.fn { 447 font-weight: bold; 448} 449.hidden { 450 display: none; 451} 452.left { 453 text-align: left; 454} 455.right { 456 text-align: right; 457} 458.title { 459 color: #990000; 460 font-size: 18pt; 461 line-height: 18pt; 462 font-weight: bold; 463 text-align: center; 464 margin-top: 36pt; 465} 466.vcardline { 467 display: block; 468} 469.warning { 470 font-size: 14pt; 471 background-color: yellow; 472} 473 474 475@media print { 476 .noprint { 477 display: none; 478 } 479 480 a { 481 color: black; 482 text-decoration: none; 483 } 484 485 table.header { 486 width: 90%; 487 } 488 489 td.header { 490 width: 50%; 491 color: black; 492 background-color: white; 493 vertical-align: top; 494 font-size: 12pt; 495 } 496 497 ul.toc a::after { 498 content: leader('.') target-counter(attr(href), page); 499 } 500 501 a.iref { 502 content: target-counter(attr(href), page); 503 } 504 505 .print2col { 506 column-count: 2; 507 -moz-column-count: 2; 508 column-fill: auto; 509 } 510} 511 512@page { 513 @top-left { 514 content: ""; 515 516 } 517 @top-right { 518 content: "May 2018"; 519 520 } 521 @top-center { 522 content: "LIBXO-MANUAL"; 523 524 } 525 @bottom-left { 526 content: "Shafer"; 527 528 } 529 @bottom-center { 530 content: ""; 531 532 } 533 @bottom-right { 534 content: "[Page " counter(page) "]"; 535 536 } 537} 538 539@page:first { 540 @top-left { 541 content: normal; 542 } 543 @top-right { 544 content: normal; 545 } 546 @top-center { 547 content: normal; 548 } 549} 550 551div.tooltip { 552 border: solid 1px #666666; 553 padding: 0px; 554 position: absolute; 555 z-index: 100; 556 display: none; 557 color: #333333; 558 top: 20px; 559 left: 90px; 560 background-color: #ffffcc; 561 layer-background-color: #ffffcc; 562} 563 564div.fancy-tooltip-empty-header { 565 text-align: left; 566 font-weight: bold; 567 margin: 2px; 568} 569 570div.fancy-tooltip-header { 571 text-align: left; 572 font-weight: bold; 573 margin: 2px 2px 0px 2px; 574 border-bottom: 1px solid black; 575} 576 577div.fancy-tooltip-body { 578 font-weight: normal; 579 margin: 4px; 580} 581 582div.fancy-tooltip-body ul, div.fancy-tooltip-body li { 583 padding: 1px 4px 1px 4px; 584 margin: 1px 2px 1px 8px; 585} 586 587span.digress { 588 background-color: #778899; 589 font: courier new, courier, monospace; 590 color: black; 591 font-weight: bold; 592 font-size: 10px; 593 border: 1px solid #aaaaaa; 594} 595 596span.digress-anchor { 597 margin: 10pt 20pt 10pt 50pt; 598} 599 600a.digress-anchor:link, a.digress-anchor:visited, 601 a.digress-anchor-hover, a.digress-anchor,active { 602 text-decoration: none; 603 color: black; 604} 605 606</style> 607<script type="text/javascript">/*! 608 * jQuery JavaScript Library v1.7 609 * http://jquery.com/ 610 * 611 * Copyright 2011, John Resig 612 * Dual licensed under the MIT or GPL Version 2 licenses. 613 * http://jquery.org/license 614 * 615 * Includes Sizzle.js 616 * http://sizzlejs.com/ 617 * Copyright 2011, The Dojo Foundation 618 * Released under the MIT, BSD, and GPL Licenses. 619 * 620 * Date: Thu Nov 3 16:18:21 2011 -0400 621 */ 622(function( window, undefined ) { 623 624// Use the correct document accordingly with window argument (sandbox) 625var document = window.document, 626 navigator = window.navigator, 627 location = window.location; 628var jQuery = (function() { 629 630// Define a local copy of jQuery 631var jQuery = function( selector, context ) { 632 // The jQuery object is actually just the init constructor 'enhanced' 633 return new jQuery.fn.init( selector, context, rootjQuery ); 634 }, 635 636 // Map over jQuery in case of overwrite 637 _jQuery = window.jQuery, 638 639 // Map over the $ in case of overwrite 640 _$ = window.$, 641 642 // A central reference to the root jQuery(document) 643 rootjQuery, 644 645 // A simple way to check for HTML strings or ID strings 646 // Prioritize #id over <tag> to avoid XSS via location.hash (#9521) 647 quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, 648 649 // Check if a string has a non-whitespace character in it 650 rnotwhite = /\S/, 651 652 // Used for trimming whitespace 653 trimLeft = /^\s+/, 654 trimRight = /\s+$/, 655 656 // Check for digits 657 rdigit = /\d/, 658 659 // Match a standalone tag 660 rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, 661 662 // JSON RegExp 663 rvalidchars = /^[\],:{}\s]*$/, 664 rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, 665 rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, 666 rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, 667 668 // Useragent RegExp 669 rwebkit = /(webkit)[ \/]([\w.]+)/, 670 ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, 671 rmsie = /(msie) ([\w.]+)/, 672 rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, 673 674 // Matches dashed string for camelizing 675 rdashAlpha = /-([a-z]|[0-9])/ig, 676 rmsPrefix = /^-ms-/, 677 678 // Used by jQuery.camelCase as callback to replace() 679 fcamelCase = function( all, letter ) { 680 return ( letter + "" ).toUpperCase(); 681 }, 682 683 // Keep a UserAgent string for use with jQuery.browser 684 userAgent = navigator.userAgent, 685 686 // For matching the engine and version of the browser 687 browserMatch, 688 689 // The deferred used on DOM ready 690 readyList, 691 692 // The ready event handler 693 DOMContentLoaded, 694 695 // Save a reference to some core methods 696 toString = Object.prototype.toString, 697 hasOwn = Object.prototype.hasOwnProperty, 698 push = Array.prototype.push, 699 slice = Array.prototype.slice, 700 trim = String.prototype.trim, 701 indexOf = Array.prototype.indexOf, 702 703 // [[Class]] -> type pairs 704 class2type = {}; 705 706jQuery.fn = jQuery.prototype = { 707 constructor: jQuery, 708 init: function( selector, context, rootjQuery ) { 709 var match, elem, ret, doc; 710 711 // Handle $(""), $(null), or $(undefined) 712 if ( !selector ) { 713 return this; 714 } 715 716 // Handle $(DOMElement) 717 if ( selector.nodeType ) { 718 this.context = this[0] = selector; 719 this.length = 1; 720 return this; 721 } 722 723 // The body element only exists once, optimize finding it 724 if ( selector === "body" && !context && document.body ) { 725 this.context = document; 726 this[0] = document.body; 727 this.selector = selector; 728 this.length = 1; 729 return this; 730 } 731 732 // Handle HTML strings 733 if ( typeof selector === "string" ) { 734 // Are we dealing with HTML string or an ID? 735 if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { 736 // Assume that strings that start and end with <> are HTML and skip the regex check 737 match = [ null, selector, null ]; 738 739 } else { 740 match = quickExpr.exec( selector ); 741 } 742 743 // Verify a match, and that no context was specified for #id 744 if ( match && (match[1] || !context) ) { 745 746 // HANDLE: $(html) -> $(array) 747 if ( match[1] ) { 748 context = context instanceof jQuery ? context[0] : context; 749 doc = ( context ? context.ownerDocument || context : document ); 750 751 // If a single string is passed in and it's a single tag 752 // just do a createElement and skip the rest 753 ret = rsingleTag.exec( selector ); 754 755 if ( ret ) { 756 if ( jQuery.isPlainObject( context ) ) { 757 selector = [ document.createElement( ret[1] ) ]; 758 jQuery.fn.attr.call( selector, context, true ); 759 760 } else { 761 selector = [ doc.createElement( ret[1] ) ]; 762 } 763 764 } else { 765 ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); 766 selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; 767 } 768 769 return jQuery.merge( this, selector ); 770 771 // HANDLE: $("#id") 772 } else { 773 elem = document.getElementById( match[2] ); 774 775 // Check parentNode to catch when Blackberry 4.6 returns 776 // nodes that are no longer in the document #6963 777 if ( elem && elem.parentNode ) { 778 // Handle the case where IE and Opera return items 779 // by name instead of ID 780 if ( elem.id !== match[2] ) { 781 return rootjQuery.find( selector ); 782 } 783 784 // Otherwise, we inject the element directly into the jQuery object 785 this.length = 1; 786 this[0] = elem; 787 } 788 789 this.context = document; 790 this.selector = selector; 791 return this; 792 } 793 794 // HANDLE: $(expr, $(...)) 795 } else if ( !context || context.jquery ) { 796 return ( context || rootjQuery ).find( selector ); 797 798 // HANDLE: $(expr, context) 799 // (which is just equivalent to: $(context).find(expr) 800 } else { 801 return this.constructor( context ).find( selector ); 802 } 803 804 // HANDLE: $(function) 805 // Shortcut for document ready 806 } else if ( jQuery.isFunction( selector ) ) { 807 return rootjQuery.ready( selector ); 808 } 809 810 if ( selector.selector !== undefined ) { 811 this.selector = selector.selector; 812 this.context = selector.context; 813 } 814 815 return jQuery.makeArray( selector, this ); 816 }, 817 818 // Start with an empty selector 819 selector: "", 820 821 // The current version of jQuery being used 822 jquery: "1.7", 823 824 // The default length of a jQuery object is 0 825 length: 0, 826 827 // The number of elements contained in the matched element set 828 size: function() { 829 return this.length; 830 }, 831 832 toArray: function() { 833 return slice.call( this, 0 ); 834 }, 835 836 // Get the Nth element in the matched element set OR 837 // Get the whole matched element set as a clean array 838 get: function( num ) { 839 return num == null ? 840 841 // Return a 'clean' array 842 this.toArray() : 843 844 // Return just the object 845 ( num < 0 ? this[ this.length + num ] : this[ num ] ); 846 }, 847 848 // Take an array of elements and push it onto the stack 849 // (returning the new matched element set) 850 pushStack: function( elems, name, selector ) { 851 // Build a new jQuery matched element set 852 var ret = this.constructor(); 853 854 if ( jQuery.isArray( elems ) ) { 855 push.apply( ret, elems ); 856 857 } else { 858 jQuery.merge( ret, elems ); 859 } 860 861 // Add the old object onto the stack (as a reference) 862 ret.prevObject = this; 863 864 ret.context = this.context; 865 866 if ( name === "find" ) { 867 ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; 868 } else if ( name ) { 869 ret.selector = this.selector + "." + name + "(" + selector + ")"; 870 } 871 872 // Return the newly-formed element set 873 return ret; 874 }, 875 876 // Execute a callback for every element in the matched set. 877 // (You can seed the arguments with an array of args, but this is 878 // only used internally.) 879 each: function( callback, args ) { 880 return jQuery.each( this, callback, args ); 881 }, 882 883 ready: function( fn ) { 884 // Attach the listeners 885 jQuery.bindReady(); 886 887 // Add the callback 888 readyList.add( fn ); 889 890 return this; 891 }, 892 893 eq: function( i ) { 894 return i === -1 ? 895 this.slice( i ) : 896 this.slice( i, +i + 1 ); 897 }, 898 899 first: function() { 900 return this.eq( 0 ); 901 }, 902 903 last: function() { 904 return this.eq( -1 ); 905 }, 906 907 slice: function() { 908 return this.pushStack( slice.apply( this, arguments ), 909 "slice", slice.call(arguments).join(",") ); 910 }, 911 912 map: function( callback ) { 913 return this.pushStack( jQuery.map(this, function( elem, i ) { 914 return callback.call( elem, i, elem ); 915 })); 916 }, 917 918 end: function() { 919 return this.prevObject || this.constructor(null); 920 }, 921 922 // For internal use only. 923 // Behaves like an Array's method, not like a jQuery method. 924 push: push, 925 sort: [].sort, 926 splice: [].splice 927}; 928 929// Give the init function the jQuery prototype for later instantiation 930jQuery.fn.init.prototype = jQuery.fn; 931 932jQuery.extend = jQuery.fn.extend = function() { 933 var options, name, src, copy, copyIsArray, clone, 934 target = arguments[0] || {}, 935 i = 1, 936 length = arguments.length, 937 deep = false; 938 939 // Handle a deep copy situation 940 if ( typeof target === "boolean" ) { 941 deep = target; 942 target = arguments[1] || {}; 943 // skip the boolean and the target 944 i = 2; 945 } 946 947 // Handle case when target is a string or something (possible in deep copy) 948 if ( typeof target !== "object" && !jQuery.isFunction(target) ) { 949 target = {}; 950 } 951 952 // extend jQuery itself if only one argument is passed 953 if ( length === i ) { 954 target = this; 955 --i; 956 } 957 958 for ( ; i < length; i++ ) { 959 // Only deal with non-null/undefined values 960 if ( (options = arguments[ i ]) != null ) { 961 // Extend the base object 962 for ( name in options ) { 963 src = target[ name ]; 964 copy = options[ name ]; 965 966 // Prevent never-ending loop 967 if ( target === copy ) { 968 continue; 969 } 970 971 // Recurse if we're merging plain objects or arrays 972 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { 973 if ( copyIsArray ) { 974 copyIsArray = false; 975 clone = src && jQuery.isArray(src) ? src : []; 976 977 } else { 978 clone = src && jQuery.isPlainObject(src) ? src : {}; 979 } 980 981 // Never move original objects, clone them 982 target[ name ] = jQuery.extend( deep, clone, copy ); 983 984 // Don't bring in undefined values 985 } else if ( copy !== undefined ) { 986 target[ name ] = copy; 987 } 988 } 989 } 990 } 991 992 // Return the modified object 993 return target; 994}; 995 996jQuery.extend({ 997 noConflict: function( deep ) { 998 if ( window.$ === jQuery ) { 999 window.$ = _$; 1000 } 1001 1002 if ( deep && window.jQuery === jQuery ) { 1003 window.jQuery = _jQuery; 1004 } 1005 1006 return jQuery; 1007 }, 1008 1009 // Is the DOM ready to be used? Set to true once it occurs. 1010 isReady: false, 1011 1012 // A counter to track how many items to wait for before 1013 // the ready event fires. See #6781 1014 readyWait: 1, 1015 1016 // Hold (or release) the ready event 1017 holdReady: function( hold ) { 1018 if ( hold ) { 1019 jQuery.readyWait++; 1020 } else { 1021 jQuery.ready( true ); 1022 } 1023 }, 1024 1025 // Handle when the DOM is ready 1026 ready: function( wait ) { 1027 // Either a released hold or an DOMready/load event and not yet ready 1028 if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { 1029 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). 1030 if ( !document.body ) { 1031 return setTimeout( jQuery.ready, 1 ); 1032 } 1033 1034 // Remember that the DOM is ready 1035 jQuery.isReady = true; 1036 1037 // If a normal DOM Ready event fired, decrement, and wait if need be 1038 if ( wait !== true && --jQuery.readyWait > 0 ) { 1039 return; 1040 } 1041 1042 // If there are functions bound, to execute 1043 readyList.fireWith( document, [ jQuery ] ); 1044 1045 // Trigger any bound ready events 1046 if ( jQuery.fn.trigger ) { 1047 jQuery( document ).trigger( "ready" ).unbind( "ready" ); 1048 } 1049 } 1050 }, 1051 1052 bindReady: function() { 1053 if ( readyList ) { 1054 return; 1055 } 1056 1057 readyList = jQuery.Callbacks( "once memory" ); 1058 1059 // Catch cases where $(document).ready() is called after the 1060 // browser event has already occurred. 1061 if ( document.readyState === "complete" ) { 1062 // Handle it asynchronously to allow scripts the opportunity to delay ready 1063 return setTimeout( jQuery.ready, 1 ); 1064 } 1065 1066 // Mozilla, Opera and webkit nightlies currently support this event 1067 if ( document.addEventListener ) { 1068 // Use the handy event callback 1069 document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); 1070 1071 // A fallback to window.onload, that will always work 1072 window.addEventListener( "load", jQuery.ready, false ); 1073 1074 // If IE event model is used 1075 } else if ( document.attachEvent ) { 1076 // ensure firing before onload, 1077 // maybe late but safe also for iframes 1078 document.attachEvent( "onreadystatechange", DOMContentLoaded ); 1079 1080 // A fallback to window.onload, that will always work 1081 window.attachEvent( "onload", jQuery.ready ); 1082 1083 // If IE and not a frame 1084 // continually check to see if the document is ready 1085 var toplevel = false; 1086 1087 try { 1088 toplevel = window.frameElement == null; 1089 } catch(e) {} 1090 1091 if ( document.documentElement.doScroll && toplevel ) { 1092 doScrollCheck(); 1093 } 1094 } 1095 }, 1096 1097 // See test/unit/core.js for details concerning isFunction. 1098 // Since version 1.3, DOM methods and functions like alert 1099 // aren't supported. They return false on IE (#2968). 1100 isFunction: function( obj ) { 1101 return jQuery.type(obj) === "function"; 1102 }, 1103 1104 isArray: Array.isArray || function( obj ) { 1105 return jQuery.type(obj) === "array"; 1106 }, 1107 1108 // A crude way of determining if an object is a window 1109 isWindow: function( obj ) { 1110 return obj && typeof obj === "object" && "setInterval" in obj; 1111 }, 1112 1113 isNumeric: function( obj ) { 1114 return obj != null && rdigit.test( obj ) && !isNaN( obj ); 1115 }, 1116 1117 type: function( obj ) { 1118 return obj == null ? 1119 String( obj ) : 1120 class2type[ toString.call(obj) ] || "object"; 1121 }, 1122 1123 isPlainObject: function( obj ) { 1124 // Must be an Object. 1125 // Because of IE, we also have to check the presence of the constructor property. 1126 // Make sure that DOM nodes and window objects don't pass through, as well 1127 if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { 1128 return false; 1129 } 1130 1131 try { 1132 // Not own constructor property must be Object 1133 if ( obj.constructor && 1134 !hasOwn.call(obj, "constructor") && 1135 !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { 1136 return false; 1137 } 1138 } catch ( e ) { 1139 // IE8,9 Will throw exceptions on certain host objects #9897 1140 return false; 1141 } 1142 1143 // Own properties are enumerated firstly, so to speed up, 1144 // if last one is own, then all properties are own. 1145 1146 var key; 1147 for ( key in obj ) {} 1148 1149 return key === undefined || hasOwn.call( obj, key ); 1150 }, 1151 1152 isEmptyObject: function( obj ) { 1153 for ( var name in obj ) { 1154 return false; 1155 } 1156 return true; 1157 }, 1158 1159 error: function( msg ) { 1160 throw msg; 1161 }, 1162 1163 parseJSON: function( data ) { 1164 if ( typeof data !== "string" || !data ) { 1165 return null; 1166 } 1167 1168 // Make sure leading/trailing whitespace is removed (IE can't handle it) 1169 data = jQuery.trim( data ); 1170 1171 // Attempt to parse using the native JSON parser first 1172 if ( window.JSON && window.JSON.parse ) { 1173 return window.JSON.parse( data ); 1174 } 1175 1176 // Make sure the incoming data is actual JSON 1177 // Logic borrowed from http://json.org/json2.js 1178 if ( rvalidchars.test( data.replace( rvalidescape, "@" ) 1179 .replace( rvalidtokens, "]" ) 1180 .replace( rvalidbraces, "")) ) { 1181 1182 return ( new Function( "return " + data ) )(); 1183 1184 } 1185 jQuery.error( "Invalid JSON: " + data ); 1186 }, 1187 1188 // Cross-browser xml parsing 1189 parseXML: function( data ) { 1190 var xml, tmp; 1191 try { 1192 if ( window.DOMParser ) { // Standard 1193 tmp = new DOMParser(); 1194 xml = tmp.parseFromString( data , "text/xml" ); 1195 } else { // IE 1196 xml = new ActiveXObject( "Microsoft.XMLDOM" ); 1197 xml.async = "false"; 1198 xml.loadXML( data ); 1199 } 1200 } catch( e ) { 1201 xml = undefined; 1202 } 1203 if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { 1204 jQuery.error( "Invalid XML: " + data ); 1205 } 1206 return xml; 1207 }, 1208 1209 noop: function() {}, 1210 1211 // Evaluates a script in a global context 1212 // Workarounds based on findings by Jim Driscoll 1213 // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context 1214 globalEval: function( data ) { 1215 if ( data && rnotwhite.test( data ) ) { 1216 // We use execScript on Internet Explorer 1217 // We use an anonymous function so that context is window 1218 // rather than jQuery in Firefox 1219 ( window.execScript || function( data ) { 1220 window[ "eval" ].call( window, data ); 1221 } )( data ); 1222 } 1223 }, 1224 1225 // Convert dashed to camelCase; used by the css and data modules 1226 // Microsoft forgot to hump their vendor prefix (#9572) 1227 camelCase: function( string ) { 1228 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); 1229 }, 1230 1231 nodeName: function( elem, name ) { 1232 return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); 1233 }, 1234 1235 // args is for internal usage only 1236 each: function( object, callback, args ) { 1237 var name, i = 0, 1238 length = object.length, 1239 isObj = length === undefined || jQuery.isFunction( object ); 1240 1241 if ( args ) { 1242 if ( isObj ) { 1243 for ( name in object ) { 1244 if ( callback.apply( object[ name ], args ) === false ) { 1245 break; 1246 } 1247 } 1248 } else { 1249 for ( ; i < length; ) { 1250 if ( callback.apply( object[ i++ ], args ) === false ) { 1251 break; 1252 } 1253 } 1254 } 1255 1256 // A special, fast, case for the most common use of each 1257 } else { 1258 if ( isObj ) { 1259 for ( name in object ) { 1260 if ( callback.call( object[ name ], name, object[ name ] ) === false ) { 1261 break; 1262 } 1263 } 1264 } else { 1265 for ( ; i < length; ) { 1266 if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { 1267 break; 1268 } 1269 } 1270 } 1271 } 1272 1273 return object; 1274 }, 1275 1276 // Use native String.trim function wherever possible 1277 trim: trim ? 1278 function( text ) { 1279 return text == null ? 1280 "" : 1281 trim.call( text ); 1282 } : 1283 1284 // Otherwise use our own trimming functionality 1285 function( text ) { 1286 return text == null ? 1287 "" : 1288 text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); 1289 }, 1290 1291 // results is for internal usage only 1292 makeArray: function( array, results ) { 1293 var ret = results || []; 1294 1295 if ( array != null ) { 1296 // The window, strings (and functions) also have 'length' 1297 // The extra typeof function check is to prevent crashes 1298 // in Safari 2 (See: #3039) 1299 // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 1300 var type = jQuery.type( array ); 1301 1302 if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { 1303 push.call( ret, array ); 1304 } else { 1305 jQuery.merge( ret, array ); 1306 } 1307 } 1308 1309 return ret; 1310 }, 1311 1312 inArray: function( elem, array, i ) { 1313 var len; 1314 1315 if ( array ) { 1316 if ( indexOf ) { 1317 return indexOf.call( array, elem, i ); 1318 } 1319 1320 len = array.length; 1321 i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; 1322 1323 for ( ; i < len; i++ ) { 1324 // Skip accessing in sparse arrays 1325 if ( i in array && array[ i ] === elem ) { 1326 return i; 1327 } 1328 } 1329 } 1330 1331 return -1; 1332 }, 1333 1334 merge: function( first, second ) { 1335 var i = first.length, 1336 j = 0; 1337 1338 if ( typeof second.length === "number" ) { 1339 for ( var l = second.length; j < l; j++ ) { 1340 first[ i++ ] = second[ j ]; 1341 } 1342 1343 } else { 1344 while ( second[j] !== undefined ) { 1345 first[ i++ ] = second[ j++ ]; 1346 } 1347 } 1348 1349 first.length = i; 1350 1351 return first; 1352 }, 1353 1354 grep: function( elems, callback, inv ) { 1355 var ret = [], retVal; 1356 inv = !!inv; 1357 1358 // Go through the array, only saving the items 1359 // that pass the validator function 1360 for ( var i = 0, length = elems.length; i < length; i++ ) { 1361 retVal = !!callback( elems[ i ], i ); 1362 if ( inv !== retVal ) { 1363 ret.push( elems[ i ] ); 1364 } 1365 } 1366 1367 return ret; 1368 }, 1369 1370 // arg is for internal usage only 1371 map: function( elems, callback, arg ) { 1372 var value, key, ret = [], 1373 i = 0, 1374 length = elems.length, 1375 // jquery objects are treated as arrays 1376 isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; 1377 1378 // Go through the array, translating each of the items to their 1379 if ( isArray ) { 1380 for ( ; i < length; i++ ) { 1381 value = callback( elems[ i ], i, arg ); 1382 1383 if ( value != null ) { 1384 ret[ ret.length ] = value; 1385 } 1386 } 1387 1388 // Go through every key on the object, 1389 } else { 1390 for ( key in elems ) { 1391 value = callback( elems[ key ], key, arg ); 1392 1393 if ( value != null ) { 1394 ret[ ret.length ] = value; 1395 } 1396 } 1397 } 1398 1399 // Flatten any nested arrays 1400 return ret.concat.apply( [], ret ); 1401 }, 1402 1403 // A global GUID counter for objects 1404 guid: 1, 1405 1406 // Bind a function to a context, optionally partially applying any 1407 // arguments. 1408 proxy: function( fn, context ) { 1409 if ( typeof context === "string" ) { 1410 var tmp = fn[ context ]; 1411 context = fn; 1412 fn = tmp; 1413 } 1414 1415 // Quick check to determine if target is callable, in the spec 1416 // this throws a TypeError, but we will just return undefined. 1417 if ( !jQuery.isFunction( fn ) ) { 1418 return undefined; 1419 } 1420 1421 // Simulated bind 1422 var args = slice.call( arguments, 2 ), 1423 proxy = function() { 1424 return fn.apply( context, args.concat( slice.call( arguments ) ) ); 1425 }; 1426 1427 // Set the guid of unique handler to the same of original handler, so it can be removed 1428 proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; 1429 1430 return proxy; 1431 }, 1432 1433 // Mutifunctional method to get and set values to a collection 1434 // The value/s can optionally be executed if it's a function 1435 access: function( elems, key, value, exec, fn, pass ) { 1436 var length = elems.length; 1437 1438 // Setting many attributes 1439 if ( typeof key === "object" ) { 1440 for ( var k in key ) { 1441 jQuery.access( elems, k, key[k], exec, fn, value ); 1442 } 1443 return elems; 1444 } 1445 1446 // Setting one attribute 1447 if ( value !== undefined ) { 1448 // Optionally, function values get executed if exec is true 1449 exec = !pass && exec && jQuery.isFunction(value); 1450 1451 for ( var i = 0; i < length; i++ ) { 1452 fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); 1453 } 1454 1455 return elems; 1456 } 1457 1458 // Getting an attribute 1459 return length ? fn( elems[0], key ) : undefined; 1460 }, 1461 1462 now: function() { 1463 return ( new Date() ).getTime(); 1464 }, 1465 1466 // Use of jQuery.browser is frowned upon. 1467 // More details: http://docs.jquery.com/Utilities/jQuery.browser 1468 uaMatch: function( ua ) { 1469 ua = ua.toLowerCase(); 1470 1471 var match = rwebkit.exec( ua ) || 1472 ropera.exec( ua ) || 1473 rmsie.exec( ua ) || 1474 ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || 1475 []; 1476 1477 return { browser: match[1] || "", version: match[2] || "0" }; 1478 }, 1479 1480 sub: function() { 1481 function jQuerySub( selector, context ) { 1482 return new jQuerySub.fn.init( selector, context ); 1483 } 1484 jQuery.extend( true, jQuerySub, this ); 1485 jQuerySub.superclass = this; 1486 jQuerySub.fn = jQuerySub.prototype = this(); 1487 jQuerySub.fn.constructor = jQuerySub; 1488 jQuerySub.sub = this.sub; 1489 jQuerySub.fn.init = function init( selector, context ) { 1490 if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { 1491 context = jQuerySub( context ); 1492 } 1493 1494 return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); 1495 }; 1496 jQuerySub.fn.init.prototype = jQuerySub.fn; 1497 var rootjQuerySub = jQuerySub(document); 1498 return jQuerySub; 1499 }, 1500 1501 browser: {} 1502}); 1503 1504// Populate the class2type map 1505jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { 1506 class2type[ "[object " + name + "]" ] = name.toLowerCase(); 1507}); 1508 1509browserMatch = jQuery.uaMatch( userAgent ); 1510if ( browserMatch.browser ) { 1511 jQuery.browser[ browserMatch.browser ] = true; 1512 jQuery.browser.version = browserMatch.version; 1513} 1514 1515// Deprecated, use jQuery.browser.webkit instead 1516if ( jQuery.browser.webkit ) { 1517 jQuery.browser.safari = true; 1518} 1519 1520// IE doesn't match non-breaking spaces with \s 1521if ( rnotwhite.test( "\xA0" ) ) { 1522 trimLeft = /^[\s\xA0]+/; 1523 trimRight = /[\s\xA0]+$/; 1524} 1525 1526// All jQuery objects should point back to these 1527rootjQuery = jQuery(document); 1528 1529// Cleanup functions for the document ready method 1530if ( document.addEventListener ) { 1531 DOMContentLoaded = function() { 1532 document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); 1533 jQuery.ready(); 1534 }; 1535 1536} else if ( document.attachEvent ) { 1537 DOMContentLoaded = function() { 1538 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). 1539 if ( document.readyState === "complete" ) { 1540 document.detachEvent( "onreadystatechange", DOMContentLoaded ); 1541 jQuery.ready(); 1542 } 1543 }; 1544} 1545 1546// The DOM ready check for Internet Explorer 1547function doScrollCheck() { 1548 if ( jQuery.isReady ) { 1549 return; 1550 } 1551 1552 try { 1553 // If IE is used, use the trick by Diego Perini 1554 // http://javascript.nwbox.com/IEContentLoaded/ 1555 document.documentElement.doScroll("left"); 1556 } catch(e) { 1557 setTimeout( doScrollCheck, 1 ); 1558 return; 1559 } 1560 1561 // and execute any waiting functions 1562 jQuery.ready(); 1563} 1564 1565// Expose jQuery as an AMD module, but only for AMD loaders that 1566// understand the issues with loading multiple versions of jQuery 1567// in a page that all might call define(). The loader will indicate 1568// they have special allowances for multiple jQuery versions by 1569// specifying define.amd.jQuery = true. Register as a named module, 1570// since jQuery can be concatenated with other files that may use define, 1571// but not use a proper concatenation script that understands anonymous 1572// AMD modules. A named AMD is safest and most robust way to register. 1573// Lowercase jquery is used because AMD module names are derived from 1574// file names, and jQuery is normally delivered in a lowercase file name. 1575if ( typeof define === "function" && define.amd && define.amd.jQuery ) { 1576 define( "jquery", [], function () { return jQuery; } ); 1577} 1578 1579return jQuery; 1580 1581})(); 1582 1583 1584// String to Object flags format cache 1585var flagsCache = {}; 1586 1587// Convert String-formatted flags into Object-formatted ones and store in cache 1588function createFlags( flags ) { 1589 var object = flagsCache[ flags ] = {}, 1590 i, length; 1591 flags = flags.split( /\s+/ ); 1592 for ( i = 0, length = flags.length; i < length; i++ ) { 1593 object[ flags[i] ] = true; 1594 } 1595 return object; 1596} 1597 1598/* 1599 * Create a callback list using the following parameters: 1600 * 1601 * flags: an optional list of space-separated flags that will change how 1602 * the callback list behaves 1603 * 1604 * By default a callback list will act like an event callback list and can be 1605 * "fired" multiple times. 1606 * 1607 * Possible flags: 1608 * 1609 * once: will ensure the callback list can only be fired once (like a Deferred) 1610 * 1611 * memory: will keep track of previous values and will call any callback added 1612 * after the list has been fired right away with the latest "memorized" 1613 * values (like a Deferred) 1614 * 1615 * unique: will ensure a callback can only be added once (no duplicate in the list) 1616 * 1617 * stopOnFalse: interrupt callings when a callback returns false 1618 * 1619 */ 1620jQuery.Callbacks = function( flags ) { 1621 1622 // Convert flags from String-formatted to Object-formatted 1623 // (we check in cache first) 1624 flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; 1625 1626 var // Actual callback list 1627 list = [], 1628 // Stack of fire calls for repeatable lists 1629 stack = [], 1630 // Last fire value (for non-forgettable lists) 1631 memory, 1632 // Flag to know if list is currently firing 1633 firing, 1634 // First callback to fire (used internally by add and fireWith) 1635 firingStart, 1636 // End of the loop when firing 1637 firingLength, 1638 // Index of currently firing callback (modified by remove if needed) 1639 firingIndex, 1640 // Add one or several callbacks to the list 1641 add = function( args ) { 1642 var i, 1643 length, 1644 elem, 1645 type, 1646 actual; 1647 for ( i = 0, length = args.length; i < length; i++ ) { 1648 elem = args[ i ]; 1649 type = jQuery.type( elem ); 1650 if ( type === "array" ) { 1651 // Inspect recursively 1652 add( elem ); 1653 } else if ( type === "function" ) { 1654 // Add if not in unique mode and callback is not in 1655 if ( !flags.unique || !self.has( elem ) ) { 1656 list.push( elem ); 1657 } 1658 } 1659 } 1660 }, 1661 // Fire callbacks 1662 fire = function( context, args ) { 1663 args = args || []; 1664 memory = !flags.memory || [ context, args ]; 1665 firing = true; 1666 firingIndex = firingStart || 0; 1667 firingStart = 0; 1668 firingLength = list.length; 1669 for ( ; list && firingIndex < firingLength; firingIndex++ ) { 1670 if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { 1671 memory = true; // Mark as halted 1672 break; 1673 } 1674 } 1675 firing = false; 1676 if ( list ) { 1677 if ( !flags.once ) { 1678 if ( stack && stack.length ) { 1679 memory = stack.shift(); 1680 self.fireWith( memory[ 0 ], memory[ 1 ] ); 1681 } 1682 } else if ( memory === true ) { 1683 self.disable(); 1684 } else { 1685 list = []; 1686 } 1687 } 1688 }, 1689 // Actual Callbacks object 1690 self = { 1691 // Add a callback or a collection of callbacks to the list 1692 add: function() { 1693 if ( list ) { 1694 var length = list.length; 1695 add( arguments ); 1696 // Do we need to add the callbacks to the 1697 // current firing batch? 1698 if ( firing ) { 1699 firingLength = list.length; 1700 // With memory, if we're not firing then 1701 // we should call right away, unless previous 1702 // firing was halted (stopOnFalse) 1703 } else if ( memory && memory !== true ) { 1704 firingStart = length; 1705 fire( memory[ 0 ], memory[ 1 ] ); 1706 } 1707 } 1708 return this; 1709 }, 1710 // Remove a callback from the list 1711 remove: function() { 1712 if ( list ) { 1713 var args = arguments, 1714 argIndex = 0, 1715 argLength = args.length; 1716 for ( ; argIndex < argLength ; argIndex++ ) { 1717 for ( var i = 0; i < list.length; i++ ) { 1718 if ( args[ argIndex ] === list[ i ] ) { 1719 // Handle firingIndex and firingLength 1720 if ( firing ) { 1721 if ( i <= firingLength ) { 1722 firingLength--; 1723 if ( i <= firingIndex ) { 1724 firingIndex--; 1725 } 1726 } 1727 } 1728 // Remove the element 1729 list.splice( i--, 1 ); 1730 // If we have some unicity property then 1731 // we only need to do this once 1732 if ( flags.unique ) { 1733 break; 1734 } 1735 } 1736 } 1737 } 1738 } 1739 return this; 1740 }, 1741 // Control if a given callback is in the list 1742 has: function( fn ) { 1743 if ( list ) { 1744 var i = 0, 1745 length = list.length; 1746 for ( ; i < length; i++ ) { 1747 if ( fn === list[ i ] ) { 1748 return true; 1749 } 1750 } 1751 } 1752 return false; 1753 }, 1754 // Remove all callbacks from the list 1755 empty: function() { 1756 list = []; 1757 return this; 1758 }, 1759 // Have the list do nothing anymore 1760 disable: function() { 1761 list = stack = memory = undefined; 1762 return this; 1763 }, 1764 // Is it disabled? 1765 disabled: function() { 1766 return !list; 1767 }, 1768 // Lock the list in its current state 1769 lock: function() { 1770 stack = undefined; 1771 if ( !memory || memory === true ) { 1772 self.disable(); 1773 } 1774 return this; 1775 }, 1776 // Is it locked? 1777 locked: function() { 1778 return !stack; 1779 }, 1780 // Call all callbacks with the given context and arguments 1781 fireWith: function( context, args ) { 1782 if ( stack ) { 1783 if ( firing ) { 1784 if ( !flags.once ) { 1785 stack.push( [ context, args ] ); 1786 } 1787 } else if ( !( flags.once && memory ) ) { 1788 fire( context, args ); 1789 } 1790 } 1791 return this; 1792 }, 1793 // Call all the callbacks with the given arguments 1794 fire: function() { 1795 self.fireWith( this, arguments ); 1796 return this; 1797 }, 1798 // To know if the callbacks have already been called at least once 1799 fired: function() { 1800 return !!memory; 1801 } 1802 }; 1803 1804 return self; 1805}; 1806 1807 1808 1809 1810var // Static reference to slice 1811 sliceDeferred = [].slice; 1812 1813jQuery.extend({ 1814 1815 Deferred: function( func ) { 1816 var doneList = jQuery.Callbacks( "once memory" ), 1817 failList = jQuery.Callbacks( "once memory" ), 1818 progressList = jQuery.Callbacks( "memory" ), 1819 state = "pending", 1820 lists = { 1821 resolve: doneList, 1822 reject: failList, 1823 notify: progressList 1824 }, 1825 promise = { 1826 done: doneList.add, 1827 fail: failList.add, 1828 progress: progressList.add, 1829 1830 state: function() { 1831 return state; 1832 }, 1833 1834 // Deprecated 1835 isResolved: doneList.fired, 1836 isRejected: failList.fired, 1837 1838 then: function( doneCallbacks, failCallbacks, progressCallbacks ) { 1839 deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); 1840 return this; 1841 }, 1842 always: function() { 1843 return deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); 1844 }, 1845 pipe: function( fnDone, fnFail, fnProgress ) { 1846 return jQuery.Deferred(function( newDefer ) { 1847 jQuery.each( { 1848 done: [ fnDone, "resolve" ], 1849 fail: [ fnFail, "reject" ], 1850 progress: [ fnProgress, "notify" ] 1851 }, function( handler, data ) { 1852 var fn = data[ 0 ], 1853 action = data[ 1 ], 1854 returned; 1855 if ( jQuery.isFunction( fn ) ) { 1856 deferred[ handler ](function() { 1857 returned = fn.apply( this, arguments ); 1858 if ( returned && jQuery.isFunction( returned.promise ) ) { 1859 returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); 1860 } else { 1861 newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); 1862 } 1863 }); 1864 } else { 1865 deferred[ handler ]( newDefer[ action ] ); 1866 } 1867 }); 1868 }).promise(); 1869 }, 1870 // Get a promise for this deferred 1871 // If obj is provided, the promise aspect is added to the object 1872 promise: function( obj ) { 1873 if ( obj == null ) { 1874 obj = promise; 1875 } else { 1876 for ( var key in promise ) { 1877 obj[ key ] = promise[ key ]; 1878 } 1879 } 1880 return obj; 1881 } 1882 }, 1883 deferred = promise.promise({}), 1884 key; 1885 1886 for ( key in lists ) { 1887 deferred[ key ] = lists[ key ].fire; 1888 deferred[ key + "With" ] = lists[ key ].fireWith; 1889 } 1890 1891 // Handle state 1892 deferred.done( function() { 1893 state = "resolved"; 1894 }, failList.disable, progressList.lock ).fail( function() { 1895 state = "rejected"; 1896 }, doneList.disable, progressList.lock ); 1897 1898 // Call given func if any 1899 if ( func ) { 1900 func.call( deferred, deferred ); 1901 } 1902 1903 // All done! 1904 return deferred; 1905 }, 1906 1907 // Deferred helper 1908 when: function( firstParam ) { 1909 var args = sliceDeferred.call( arguments, 0 ), 1910 i = 0, 1911 length = args.length, 1912 pValues = new Array( length ), 1913 count = length, 1914 pCount = length, 1915 deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? 1916 firstParam : 1917 jQuery.Deferred(), 1918 promise = deferred.promise(); 1919 function resolveFunc( i ) { 1920 return function( value ) { 1921 args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; 1922 if ( !( --count ) ) { 1923 deferred.resolveWith( deferred, args ); 1924 } 1925 }; 1926 } 1927 function progressFunc( i ) { 1928 return function( value ) { 1929 pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; 1930 deferred.notifyWith( promise, pValues ); 1931 }; 1932 } 1933 if ( length > 1 ) { 1934 for ( ; i < length; i++ ) { 1935 if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { 1936 args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); 1937 } else { 1938 --count; 1939 } 1940 } 1941 if ( !count ) { 1942 deferred.resolveWith( deferred, args ); 1943 } 1944 } else if ( deferred !== firstParam ) { 1945 deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); 1946 } 1947 return promise; 1948 } 1949}); 1950 1951 1952 1953 1954jQuery.support = (function() { 1955 1956 var div = document.createElement( "div" ), 1957 documentElement = document.documentElement, 1958 all, 1959 a, 1960 select, 1961 opt, 1962 input, 1963 marginDiv, 1964 support, 1965 fragment, 1966 body, 1967 testElementParent, 1968 testElement, 1969 testElementStyle, 1970 tds, 1971 events, 1972 eventName, 1973 i, 1974 isSupported; 1975 1976 // Preliminary tests 1977 div.setAttribute("className", "t"); 1978 div.innerHTML = " <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/><nav></nav>"; 1979 1980 1981 all = div.getElementsByTagName( "*" ); 1982 a = div.getElementsByTagName( "a" )[ 0 ]; 1983 1984 // Can't get basic test support 1985 if ( !all || !all.length || !a ) { 1986 return {}; 1987 } 1988 1989 // First batch of supports tests 1990 select = document.createElement( "select" ); 1991 opt = select.appendChild( document.createElement("option") ); 1992 input = div.getElementsByTagName( "input" )[ 0 ]; 1993 1994 support = { 1995 // IE strips leading whitespace when .innerHTML is used 1996 leadingWhitespace: ( div.firstChild.nodeType === 3 ), 1997 1998 // Make sure that tbody elements aren't automatically inserted 1999 // IE will insert them into empty tables 2000 tbody: !div.getElementsByTagName( "tbody" ).length, 2001 2002 // Make sure that link elements get serialized correctly by innerHTML 2003 // This requires a wrapper element in IE 2004 htmlSerialize: !!div.getElementsByTagName( "link" ).length, 2005 2006 // Get the style information from getAttribute 2007 // (IE uses .cssText instead) 2008 style: /top/.test( a.getAttribute("style") ), 2009 2010 // Make sure that URLs aren't manipulated 2011 // (IE normalizes it by default) 2012 hrefNormalized: ( a.getAttribute( "href" ) === "/a" ), 2013 2014 // Make sure that element opacity exists 2015 // (IE uses filter instead) 2016 // Use a regex to work around a WebKit issue. See #5145 2017 opacity: /^0.55/.test( a.style.opacity ), 2018 2019 // Verify style float existence 2020 // (IE uses styleFloat instead of cssFloat) 2021 cssFloat: !!a.style.cssFloat, 2022 2023 // Make sure unknown elements (like HTML5 elems) are handled appropriately 2024 unknownElems: !!div.getElementsByTagName( "nav" ).length, 2025 2026 // Make sure that if no value is specified for a checkbox 2027 // that it defaults to "on". 2028 // (WebKit defaults to "" instead) 2029 checkOn: ( input.value === "on" ), 2030 2031 // Make sure that a selected-by-default option has a working selected property. 2032 // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) 2033 optSelected: opt.selected, 2034 2035 // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) 2036 getSetAttribute: div.className !== "t", 2037 2038 // Tests for enctype support on a form(#6743) 2039 enctype: !!document.createElement("form").enctype, 2040 2041 // Will be defined later 2042 submitBubbles: true, 2043 changeBubbles: true, 2044 focusinBubbles: false, 2045 deleteExpando: true, 2046 noCloneEvent: true, 2047 inlineBlockNeedsLayout: false, 2048 shrinkWrapBlocks: false, 2049 reliableMarginRight: true 2050 }; 2051 2052 // Make sure checked status is properly cloned 2053 input.checked = true; 2054 support.noCloneChecked = input.cloneNode( true ).checked; 2055 2056 // Make sure that the options inside disabled selects aren't marked as disabled 2057 // (WebKit marks them as disabled) 2058 select.disabled = true; 2059 support.optDisabled = !opt.disabled; 2060 2061 // Test to see if it's possible to delete an expando from an element 2062 // Fails in Internet Explorer 2063 try { 2064 delete div.test; 2065 } catch( e ) { 2066 support.deleteExpando = false; 2067 } 2068 2069 if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { 2070 div.attachEvent( "onclick", function() { 2071 // Cloning a node shouldn't copy over any 2072 // bound event handlers (IE does this) 2073 support.noCloneEvent = false; 2074 }); 2075 div.cloneNode( true ).fireEvent( "onclick" ); 2076 } 2077 2078 // Check if a radio maintains its value 2079 // after being appended to the DOM 2080 input = document.createElement("input"); 2081 input.value = "t"; 2082 input.setAttribute("type", "radio"); 2083 support.radioValue = input.value === "t"; 2084 2085 input.setAttribute("checked", "checked"); 2086 div.appendChild( input ); 2087 fragment = document.createDocumentFragment(); 2088 fragment.appendChild( div.lastChild ); 2089 2090 // WebKit doesn't clone checked state correctly in fragments 2091 support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; 2092 2093 div.innerHTML = ""; 2094 2095 // Figure out if the W3C box model works as expected 2096 div.style.width = div.style.paddingLeft = "1px"; 2097 2098 // We don't want to do body-related feature tests on frameset 2099 // documents, which lack a body. So we use 2100 // document.getElementsByTagName("body")[0], which is undefined in 2101 // frameset documents, while document.body isn’t. (7398) 2102 body = document.getElementsByTagName("body")[ 0 ]; 2103 // We use our own, invisible, body unless the body is already present 2104 // in which case we use a div (#9239) 2105 testElement = document.createElement( body ? "div" : "body" ); 2106 testElementStyle = { 2107 visibility: "hidden", 2108 width: 0, 2109 height: 0, 2110 border: 0, 2111 margin: 0, 2112 background: "none" 2113 }; 2114 if ( body ) { 2115 jQuery.extend( testElementStyle, { 2116 position: "absolute", 2117 left: "-999px", 2118 top: "-999px" 2119 }); 2120 } 2121 for ( i in testElementStyle ) { 2122 testElement.style[ i ] = testElementStyle[ i ]; 2123 } 2124 testElement.appendChild( div ); 2125 testElementParent = body || documentElement; 2126 testElementParent.insertBefore( testElement, testElementParent.firstChild ); 2127 2128 // Check if a disconnected checkbox will retain its checked 2129 // value of true after appended to the DOM (IE6/7) 2130 support.appendChecked = input.checked; 2131 2132 support.boxModel = div.offsetWidth === 2; 2133 2134 if ( "zoom" in div.style ) { 2135 // Check if natively block-level elements act like inline-block 2136 // elements when setting their display to 'inline' and giving 2137 // them layout 2138 // (IE < 8 does this) 2139 div.style.display = "inline"; 2140 div.style.zoom = 1; 2141 support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); 2142 2143 // Check if elements with layout shrink-wrap their children 2144 // (IE 6 does this) 2145 div.style.display = ""; 2146 div.innerHTML = "<div style='width:4px;'></div>"; 2147 support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); 2148 } 2149 2150 div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>"; 2151 tds = div.getElementsByTagName( "td" ); 2152 2153 // Check if table cells still have offsetWidth/Height when they are set 2154 // to display:none and there are still other visible table cells in a 2155 // table row; if so, offsetWidth/Height are not reliable for use when 2156 // determining if an element has been hidden directly using 2157 // display:none (it is still safe to use offsets if a parent element is 2158 // hidden; don safety goggles and see bug #4512 for more information). 2159 // (only IE 8 fails this test) 2160 isSupported = ( tds[ 0 ].offsetHeight === 0 ); 2161 2162 tds[ 0 ].style.display = ""; 2163 tds[ 1 ].style.display = "none"; 2164 2165 // Check if empty table cells still have offsetWidth/Height 2166 // (IE < 8 fail this test) 2167 support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); 2168 div.innerHTML = ""; 2169 2170 // Check if div with explicit width and no margin-right incorrectly 2171 // gets computed margin-right based on width of container. For more 2172 // info see bug #3333 2173 // Fails in WebKit before Feb 2011 nightlies 2174 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right 2175 if ( document.defaultView && document.defaultView.getComputedStyle ) { 2176 marginDiv = document.createElement( "div" ); 2177 marginDiv.style.width = "0"; 2178 marginDiv.style.marginRight = "0"; 2179 div.appendChild( marginDiv ); 2180 support.reliableMarginRight = 2181 ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; 2182 } 2183 2184 // Technique from Juriy Zaytsev 2185 // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ 2186 // We only care about the case where non-standard event systems 2187 // are used, namely in IE. Short-circuiting here helps us to 2188 // avoid an eval call (in setAttribute) which can cause CSP 2189 // to go haywire. See: https://developer.mozilla.org/en/Security/CSP 2190 if ( div.attachEvent ) { 2191 for( i in { 2192 submit: 1, 2193 change: 1, 2194 focusin: 1 2195 } ) { 2196 eventName = "on" + i; 2197 isSupported = ( eventName in div ); 2198 if ( !isSupported ) { 2199 div.setAttribute( eventName, "return;" ); 2200 isSupported = ( typeof div[ eventName ] === "function" ); 2201 } 2202 support[ i + "Bubbles" ] = isSupported; 2203 } 2204 } 2205 2206 // Run fixed position tests at doc ready to avoid a crash 2207 // related to the invisible body in IE8 2208 jQuery(function() { 2209 var container, outer, inner, table, td, offsetSupport, 2210 conMarginTop = 1, 2211 ptlm = "position:absolute;top:0;left:0;width:1px;height:1px;margin:0;", 2212 vb = "visibility:hidden;border:0;", 2213 style = "style='" + ptlm + "border:5px solid #000;padding:0;'", 2214 html = "<div " + style + "><div></div></div>" + 2215 "<table " + style + " cellpadding='0' cellspacing='0'>" + 2216 "<tr><td></td></tr></table>"; 2217 2218 // Reconstruct a container 2219 body = document.getElementsByTagName("body")[0]; 2220 if ( !body ) { 2221 // Return for frameset docs that don't have a body 2222 // These tests cannot be done 2223 return; 2224 } 2225 2226 container = document.createElement("div"); 2227 container.style.cssText = vb + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; 2228 body.insertBefore( container, body.firstChild ); 2229 2230 // Construct a test element 2231 testElement = document.createElement("div"); 2232 testElement.style.cssText = ptlm + vb; 2233 2234 testElement.innerHTML = html; 2235 container.appendChild( testElement ); 2236 outer = testElement.firstChild; 2237 inner = outer.firstChild; 2238 td = outer.nextSibling.firstChild.firstChild; 2239 2240 offsetSupport = { 2241 doesNotAddBorder: ( inner.offsetTop !== 5 ), 2242 doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) 2243 }; 2244 2245 inner.style.position = "fixed"; 2246 inner.style.top = "20px"; 2247 2248 // safari subtracts parent border width here which is 5px 2249 offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); 2250 inner.style.position = inner.style.top = ""; 2251 2252 outer.style.overflow = "hidden"; 2253 outer.style.position = "relative"; 2254 2255 offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); 2256 offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); 2257 2258 body.removeChild( container ); 2259 testElement = container = null; 2260 2261 jQuery.extend( support, offsetSupport ); 2262 }); 2263 2264 testElement.innerHTML = ""; 2265 testElementParent.removeChild( testElement ); 2266 2267 // Null connected elements to avoid leaks in IE 2268 testElement = fragment = select = opt = body = marginDiv = div = input = null; 2269 2270 return support; 2271})(); 2272 2273// Keep track of boxModel 2274jQuery.boxModel = jQuery.support.boxModel; 2275 2276 2277 2278 2279var rbrace = /^(?:\{.*\}|\[.*\])$/, 2280 rmultiDash = /([A-Z])/g; 2281 2282jQuery.extend({ 2283 cache: {}, 2284 2285 // Please use with caution 2286 uuid: 0, 2287 2288 // Unique for each copy of jQuery on the page 2289 // Non-digits removed to match rinlinejQuery 2290 expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), 2291 2292 // The following elements throw uncatchable exceptions if you 2293 // attempt to add expando properties to them. 2294 noData: { 2295 "embed": true, 2296 // Ban all objects except for Flash (which handle expandos) 2297 "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", 2298 "applet": true 2299 }, 2300 2301 hasData: function( elem ) { 2302 elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; 2303 return !!elem && !isEmptyDataObject( elem ); 2304 }, 2305 2306 data: function( elem, name, data, pvt /* Internal Use Only */ ) { 2307 if ( !jQuery.acceptData( elem ) ) { 2308 return; 2309 } 2310 2311 var privateCache, thisCache, ret, 2312 internalKey = jQuery.expando, 2313 getByName = typeof name === "string", 2314 2315 // We have to handle DOM nodes and JS objects differently because IE6-7 2316 // can't GC object references properly across the DOM-JS boundary 2317 isNode = elem.nodeType, 2318 2319 // Only DOM nodes need the global jQuery cache; JS object data is 2320 // attached directly to the object so GC can occur automatically 2321 cache = isNode ? jQuery.cache : elem, 2322 2323 // Only defining an ID for JS objects if its cache already exists allows 2324 // the code to shortcut on the same path as a DOM node with no cache 2325 id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando, 2326 isEvents = name === "events"; 2327 2328 // Avoid doing any more work than we need to when trying to get data on an 2329 // object that has no data at all 2330 if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { 2331 return; 2332 } 2333 2334 if ( !id ) { 2335 // Only DOM nodes need a new unique ID for each element since their data 2336 // ends up in the global cache 2337 if ( isNode ) { 2338 elem[ jQuery.expando ] = id = ++jQuery.uuid; 2339 } else { 2340 id = jQuery.expando; 2341 } 2342 } 2343 2344 if ( !cache[ id ] ) { 2345 cache[ id ] = {}; 2346 2347 // Avoids exposing jQuery metadata on plain JS objects when the object 2348 // is serialized using JSON.stringify 2349 if ( !isNode ) { 2350 cache[ id ].toJSON = jQuery.noop; 2351 } 2352 } 2353 2354 // An object can be passed to jQuery.data instead of a key/value pair; this gets 2355 // shallow copied over onto the existing cache 2356 if ( typeof name === "object" || typeof name === "function" ) { 2357 if ( pvt ) { 2358 cache[ id ] = jQuery.extend( cache[ id ], name ); 2359 } else { 2360 cache[ id ].data = jQuery.extend( cache[ id ].data, name ); 2361 } 2362 } 2363 2364 privateCache = thisCache = cache[ id ]; 2365 2366 // jQuery data() is stored in a separate object inside the object's internal data 2367 // cache in order to avoid key collisions between internal data and user-defined 2368 // data. 2369 if ( !pvt ) { 2370 if ( !thisCache.data ) { 2371 thisCache.data = {}; 2372 } 2373 2374 thisCache = thisCache.data; 2375 } 2376 2377 if ( data !== undefined ) { 2378 thisCache[ jQuery.camelCase( name ) ] = data; 2379 } 2380 2381 // Users should not attempt to inspect the internal events object using jQuery.data, 2382 // it is undocumented and subject to change. But does anyone listen? No. 2383 if ( isEvents && !thisCache[ name ] ) { 2384 return privateCache.events; 2385 } 2386 2387 // Check for both converted-to-camel and non-converted data property names 2388 // If a data property was specified 2389 if ( getByName ) { 2390 2391 // First Try to find as-is property data 2392 ret = thisCache[ name ]; 2393 2394 // Test for null|undefined property data 2395 if ( ret == null ) { 2396 2397 // Try to find the camelCased property 2398 ret = thisCache[ jQuery.camelCase( name ) ]; 2399 } 2400 } else { 2401 ret = thisCache; 2402 } 2403 2404 return ret; 2405 }, 2406 2407 removeData: function( elem, name, pvt /* Internal Use Only */ ) { 2408 if ( !jQuery.acceptData( elem ) ) { 2409 return; 2410 } 2411 2412 var thisCache, i, l, 2413 2414 // Reference to internal data cache key 2415 internalKey = jQuery.expando, 2416 2417 isNode = elem.nodeType, 2418 2419 // See jQuery.data for more information 2420 cache = isNode ? jQuery.cache : elem, 2421 2422 // See jQuery.data for more information 2423 id = isNode ? elem[ jQuery.expando ] : jQuery.expando; 2424 2425 // If there is already no cache entry for this object, there is no 2426 // purpose in continuing 2427 if ( !cache[ id ] ) { 2428 return; 2429 } 2430 2431 if ( name ) { 2432 2433 thisCache = pvt ? cache[ id ] : cache[ id ].data; 2434 2435 if ( thisCache ) { 2436 2437 // Support space separated names 2438 if ( jQuery.isArray( name ) ) { 2439 name = name; 2440 } else if ( name in thisCache ) { 2441 name = [ name ]; 2442 } else { 2443 2444 // split the camel cased version by spaces 2445 name = jQuery.camelCase( name ); 2446 if ( name in thisCache ) { 2447 name = [ name ]; 2448 } else { 2449 name = name.split( " " ); 2450 } 2451 } 2452 2453 for ( i = 0, l = name.length; i < l; i++ ) { 2454 delete thisCache[ name[i] ]; 2455 } 2456 2457 // If there is no data left in the cache, we want to continue 2458 // and let the cache object itself get destroyed 2459 if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { 2460 return; 2461 } 2462 } 2463 } 2464 2465 // See jQuery.data for more information 2466 if ( !pvt ) { 2467 delete cache[ id ].data; 2468 2469 // Don't destroy the parent cache unless the internal data object 2470 // had been the only thing left in it 2471 if ( !isEmptyDataObject(cache[ id ]) ) { 2472 return; 2473 } 2474 } 2475 2476 // Browsers that fail expando deletion also refuse to delete expandos on 2477 // the window, but it will allow it on all other JS objects; other browsers 2478 // don't care 2479 // Ensure that `cache` is not a window object #10080 2480 if ( jQuery.support.deleteExpando || !cache.setInterval ) { 2481 delete cache[ id ]; 2482 } else { 2483 cache[ id ] = null; 2484 } 2485 2486 // We destroyed the cache and need to eliminate the expando on the node to avoid 2487 // false lookups in the cache for entries that no longer exist 2488 if ( isNode ) { 2489 // IE does not allow us to delete expando properties from nodes, 2490 // nor does it have a removeAttribute function on Document nodes; 2491 // we must handle all of these cases 2492 if ( jQuery.support.deleteExpando ) { 2493 delete elem[ jQuery.expando ]; 2494 } else if ( elem.removeAttribute ) { 2495 elem.removeAttribute( jQuery.expando ); 2496 } else { 2497 elem[ jQuery.expando ] = null; 2498 } 2499 } 2500 }, 2501 2502 // For internal use only. 2503 _data: function( elem, name, data ) { 2504 return jQuery.data( elem, name, data, true ); 2505 }, 2506 2507 // A method for determining if a DOM node can handle the data expando 2508 acceptData: function( elem ) { 2509 if ( elem.nodeName ) { 2510 var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; 2511 2512 if ( match ) { 2513 return !(match === true || elem.getAttribute("classid") !== match); 2514 } 2515 } 2516 2517 return true; 2518 } 2519}); 2520 2521jQuery.fn.extend({ 2522 data: function( key, value ) { 2523 var parts, attr, name, 2524 data = null; 2525 2526 if ( typeof key === "undefined" ) { 2527 if ( this.length ) { 2528 data = jQuery.data( this[0] ); 2529 2530 if ( this[0].nodeType === 1 && !jQuery._data( this[0], "parsedAttrs" ) ) { 2531 attr = this[0].attributes; 2532 for ( var i = 0, l = attr.length; i < l; i++ ) { 2533 name = attr[i].name; 2534 2535 if ( name.indexOf( "data-" ) === 0 ) { 2536 name = jQuery.camelCase( name.substring(5) ); 2537 2538 dataAttr( this[0], name, data[ name ] ); 2539 } 2540 } 2541 jQuery._data( this[0], "parsedAttrs", true ); 2542 } 2543 } 2544 2545 return data; 2546 2547 } else if ( typeof key === "object" ) { 2548 return this.each(function() { 2549 jQuery.data( this, key ); 2550 }); 2551 } 2552 2553 parts = key.split("."); 2554 parts[1] = parts[1] ? "." + parts[1] : ""; 2555 2556 if ( value === undefined ) { 2557 data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); 2558 2559 // Try to fetch any internally stored data first 2560 if ( data === undefined && this.length ) { 2561 data = jQuery.data( this[0], key ); 2562 data = dataAttr( this[0], key, data ); 2563 } 2564 2565 return data === undefined && parts[1] ? 2566 this.data( parts[0] ) : 2567 data; 2568 2569 } else { 2570 return this.each(function() { 2571 var $this = jQuery( this ), 2572 args = [ parts[0], value ]; 2573 2574 $this.triggerHandler( "setData" + parts[1] + "!", args ); 2575 jQuery.data( this, key, value ); 2576 $this.triggerHandler( "changeData" + parts[1] + "!", args ); 2577 }); 2578 } 2579 }, 2580 2581 removeData: function( key ) { 2582 return this.each(function() { 2583 jQuery.removeData( this, key ); 2584 }); 2585 } 2586}); 2587 2588function dataAttr( elem, key, data ) { 2589 // If nothing was found internally, try to fetch any 2590 // data from the HTML5 data-* attribute 2591 if ( data === undefined && elem.nodeType === 1 ) { 2592 2593 var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); 2594 2595 data = elem.getAttribute( name ); 2596 2597 if ( typeof data === "string" ) { 2598 try { 2599 data = data === "true" ? true : 2600 data === "false" ? false : 2601 data === "null" ? null : 2602 jQuery.isNumeric( data ) ? parseFloat( data ) : 2603 rbrace.test( data ) ? jQuery.parseJSON( data ) : 2604 data; 2605 } catch( e ) {} 2606 2607 // Make sure we set the data so it isn't changed later 2608 jQuery.data( elem, key, data ); 2609 2610 } else { 2611 data = undefined; 2612 } 2613 } 2614 2615 return data; 2616} 2617 2618// checks a cache object for emptiness 2619function isEmptyDataObject( obj ) { 2620 for ( var name in obj ) { 2621 2622 // if the public data object is empty, the private is still empty 2623 if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { 2624 continue; 2625 } 2626 if ( name !== "toJSON" ) { 2627 return false; 2628 } 2629 } 2630 2631 return true; 2632} 2633 2634 2635 2636 2637function handleQueueMarkDefer( elem, type, src ) { 2638 var deferDataKey = type + "defer", 2639 queueDataKey = type + "queue", 2640 markDataKey = type + "mark", 2641 defer = jQuery._data( elem, deferDataKey ); 2642 if ( defer && 2643 ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && 2644 ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { 2645 // Give room for hard-coded callbacks to fire first 2646 // and eventually mark/queue something else on the element 2647 setTimeout( function() { 2648 if ( !jQuery._data( elem, queueDataKey ) && 2649 !jQuery._data( elem, markDataKey ) ) { 2650 jQuery.removeData( elem, deferDataKey, true ); 2651 defer.fire(); 2652 } 2653 }, 0 ); 2654 } 2655} 2656 2657jQuery.extend({ 2658 2659 _mark: function( elem, type ) { 2660 if ( elem ) { 2661 type = ( type || "fx" ) + "mark"; 2662 jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); 2663 } 2664 }, 2665 2666 _unmark: function( force, elem, type ) { 2667 if ( force !== true ) { 2668 type = elem; 2669 elem = force; 2670 force = false; 2671 } 2672 if ( elem ) { 2673 type = type || "fx"; 2674 var key = type + "mark", 2675 count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); 2676 if ( count ) { 2677 jQuery._data( elem, key, count ); 2678 } else { 2679 jQuery.removeData( elem, key, true ); 2680 handleQueueMarkDefer( elem, type, "mark" ); 2681 } 2682 } 2683 }, 2684 2685 queue: function( elem, type, data ) { 2686 var q; 2687 if ( elem ) { 2688 type = ( type || "fx" ) + "queue"; 2689 q = jQuery._data( elem, type ); 2690 2691 // Speed up dequeue by getting out quickly if this is just a lookup 2692 if ( data ) { 2693 if ( !q || jQuery.isArray(data) ) { 2694 q = jQuery._data( elem, type, jQuery.makeArray(data) ); 2695 } else { 2696 q.push( data ); 2697 } 2698 } 2699 return q || []; 2700 } 2701 }, 2702 2703 dequeue: function( elem, type ) { 2704 type = type || "fx"; 2705 2706 var queue = jQuery.queue( elem, type ), 2707 fn = queue.shift(), 2708 hooks = {}; 2709 2710 // If the fx queue is dequeued, always remove the progress sentinel 2711 if ( fn === "inprogress" ) { 2712 fn = queue.shift(); 2713 } 2714 2715 if ( fn ) { 2716 // Add a progress sentinel to prevent the fx queue from being 2717 // automatically dequeued 2718 if ( type === "fx" ) { 2719 queue.unshift( "inprogress" ); 2720 } 2721 2722 jQuery._data( elem, type + ".run", hooks ); 2723 fn.call( elem, function() { 2724 jQuery.dequeue( elem, type ); 2725 }, hooks ); 2726 } 2727 2728 if ( !queue.length ) { 2729 jQuery.removeData( elem, type + "queue " + type + ".run", true ); 2730 handleQueueMarkDefer( elem, type, "queue" ); 2731 } 2732 } 2733}); 2734 2735jQuery.fn.extend({ 2736 queue: function( type, data ) { 2737 if ( typeof type !== "string" ) { 2738 data = type; 2739 type = "fx"; 2740 } 2741 2742 if ( data === undefined ) { 2743 return jQuery.queue( this[0], type ); 2744 } 2745 return this.each(function() { 2746 var queue = jQuery.queue( this, type, data ); 2747 2748 if ( type === "fx" && queue[0] !== "inprogress" ) { 2749 jQuery.dequeue( this, type ); 2750 } 2751 }); 2752 }, 2753 dequeue: function( type ) { 2754 return this.each(function() { 2755 jQuery.dequeue( this, type ); 2756 }); 2757 }, 2758 // Based off of the plugin by Clint Helfers, with permission. 2759 // http://blindsignals.com/index.php/2009/07/jquery-delay/ 2760 delay: function( time, type ) { 2761 time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; 2762 type = type || "fx"; 2763 2764 return this.queue( type, function( next, hooks ) { 2765 var timeout = setTimeout( next, time ); 2766 hooks.stop = function() { 2767 clearTimeout( timeout ); 2768 }; 2769 }); 2770 }, 2771 clearQueue: function( type ) { 2772 return this.queue( type || "fx", [] ); 2773 }, 2774 // Get a promise resolved when queues of a certain type 2775 // are emptied (fx is the type by default) 2776 promise: function( type, object ) { 2777 if ( typeof type !== "string" ) { 2778 object = type; 2779 type = undefined; 2780 } 2781 type = type || "fx"; 2782 var defer = jQuery.Deferred(), 2783 elements = this, 2784 i = elements.length, 2785 count = 1, 2786 deferDataKey = type + "defer", 2787 queueDataKey = type + "queue", 2788 markDataKey = type + "mark", 2789 tmp; 2790 function resolve() { 2791 if ( !( --count ) ) { 2792 defer.resolveWith( elements, [ elements ] ); 2793 } 2794 } 2795 while( i-- ) { 2796 if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || 2797 ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || 2798 jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && 2799 jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { 2800 count++; 2801 tmp.add( resolve ); 2802 } 2803 } 2804 resolve(); 2805 return defer.promise(); 2806 } 2807}); 2808 2809 2810 2811 2812var rclass = /[\n\t\r]/g, 2813 rspace = /\s+/, 2814 rreturn = /\r/g, 2815 rtype = /^(?:button|input)$/i, 2816 rfocusable = /^(?:button|input|object|select|textarea)$/i, 2817 rclickable = /^a(?:rea)?$/i, 2818 rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, 2819 getSetAttribute = jQuery.support.getSetAttribute, 2820 nodeHook, boolHook, fixSpecified; 2821 2822jQuery.fn.extend({ 2823 attr: function( name, value ) { 2824 return jQuery.access( this, name, value, true, jQuery.attr ); 2825 }, 2826 2827 removeAttr: function( name ) { 2828 return this.each(function() { 2829 jQuery.removeAttr( this, name ); 2830 }); 2831 }, 2832 2833 prop: function( name, value ) { 2834 return jQuery.access( this, name, value, true, jQuery.prop ); 2835 }, 2836 2837 removeProp: function( name ) { 2838 name = jQuery.propFix[ name ] || name; 2839 return this.each(function() { 2840 // try/catch handles cases where IE balks (such as removing a property on window) 2841 try { 2842 this[ name ] = undefined; 2843 delete this[ name ]; 2844 } catch( e ) {} 2845 }); 2846 }, 2847 2848 addClass: function( value ) { 2849 var classNames, i, l, elem, 2850 setClass, c, cl; 2851 2852 if ( jQuery.isFunction( value ) ) { 2853 return this.each(function( j ) { 2854 jQuery( this ).addClass( value.call(this, j, this.className) ); 2855 }); 2856 } 2857 2858 if ( value && typeof value === "string" ) { 2859 classNames = value.split( rspace ); 2860 2861 for ( i = 0, l = this.length; i < l; i++ ) { 2862 elem = this[ i ]; 2863 2864 if ( elem.nodeType === 1 ) { 2865 if ( !elem.className && classNames.length === 1 ) { 2866 elem.className = value; 2867 2868 } else { 2869 setClass = " " + elem.className + " "; 2870 2871 for ( c = 0, cl = classNames.length; c < cl; c++ ) { 2872 if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { 2873 setClass += classNames[ c ] + " "; 2874 } 2875 } 2876 elem.className = jQuery.trim( setClass ); 2877 } 2878 } 2879 } 2880 } 2881 2882 return this; 2883 }, 2884 2885 removeClass: function( value ) { 2886 var classNames, i, l, elem, className, c, cl; 2887 2888 if ( jQuery.isFunction( value ) ) { 2889 return this.each(function( j ) { 2890 jQuery( this ).removeClass( value.call(this, j, this.className) ); 2891 }); 2892 } 2893 2894 if ( (value && typeof value === "string") || value === undefined ) { 2895 classNames = ( value || "" ).split( rspace ); 2896 2897 for ( i = 0, l = this.length; i < l; i++ ) { 2898 elem = this[ i ]; 2899 2900 if ( elem.nodeType === 1 && elem.className ) { 2901 if ( value ) { 2902 className = (" " + elem.className + " ").replace( rclass, " " ); 2903 for ( c = 0, cl = classNames.length; c < cl; c++ ) { 2904 className = className.replace(" " + classNames[ c ] + " ", " "); 2905 } 2906 elem.className = jQuery.trim( className ); 2907 2908 } else { 2909 elem.className = ""; 2910 } 2911 } 2912 } 2913 } 2914 2915 return this; 2916 }, 2917 2918 toggleClass: function( value, stateVal ) { 2919 var type = typeof value, 2920 isBool = typeof stateVal === "boolean"; 2921 2922 if ( jQuery.isFunction( value ) ) { 2923 return this.each(function( i ) { 2924 jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); 2925 }); 2926 } 2927 2928 return this.each(function() { 2929 if ( type === "string" ) { 2930 // toggle individual class names 2931 var className, 2932 i = 0, 2933 self = jQuery( this ), 2934 state = stateVal, 2935 classNames = value.split( rspace ); 2936 2937 while ( (className = classNames[ i++ ]) ) { 2938 // check each className given, space seperated list 2939 state = isBool ? state : !self.hasClass( className ); 2940 self[ state ? "addClass" : "removeClass" ]( className ); 2941 } 2942 2943 } else if ( type === "undefined" || type === "boolean" ) { 2944 if ( this.className ) { 2945 // store className if set 2946 jQuery._data( this, "__className__", this.className ); 2947 } 2948 2949 // toggle whole className 2950 this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; 2951 } 2952 }); 2953 }, 2954 2955 hasClass: function( selector ) { 2956 var className = " " + selector + " ", 2957 i = 0, 2958 l = this.length; 2959 for ( ; i < l; i++ ) { 2960 if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { 2961 return true; 2962 } 2963 } 2964 2965 return false; 2966 }, 2967 2968 val: function( value ) { 2969 var hooks, ret, isFunction, 2970 elem = this[0]; 2971 2972 if ( !arguments.length ) { 2973 if ( elem ) { 2974 hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; 2975 2976 if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { 2977 return ret; 2978 } 2979 2980 ret = elem.value; 2981 2982 return typeof ret === "string" ? 2983 // handle most common string cases 2984 ret.replace(rreturn, "") : 2985 // handle cases where value is null/undef or number 2986 ret == null ? "" : ret; 2987 } 2988 2989 return undefined; 2990 } 2991 2992 isFunction = jQuery.isFunction( value ); 2993 2994 return this.each(function( i ) { 2995 var self = jQuery(this), val; 2996 2997 if ( this.nodeType !== 1 ) { 2998 return; 2999 } 3000 3001 if ( isFunction ) { 3002 val = value.call( this, i, self.val() ); 3003 } else { 3004 val = value; 3005 } 3006 3007 // Treat null/undefined as ""; convert numbers to string 3008 if ( val == null ) { 3009 val = ""; 3010 } else if ( typeof val === "number" ) { 3011 val += ""; 3012 } else if ( jQuery.isArray( val ) ) { 3013 val = jQuery.map(val, function ( value ) { 3014 return value == null ? "" : value + ""; 3015 }); 3016 } 3017 3018 hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; 3019 3020 // If set returns undefined, fall back to normal setting 3021 if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { 3022 this.value = val; 3023 } 3024 }); 3025 } 3026}); 3027 3028jQuery.extend({ 3029 valHooks: { 3030 option: { 3031 get: function( elem ) { 3032 // attributes.value is undefined in Blackberry 4.7 but 3033 // uses .value. See #6932 3034 var val = elem.attributes.value; 3035 return !val || val.specified ? elem.value : elem.text; 3036 } 3037 }, 3038 select: { 3039 get: function( elem ) { 3040 var value, i, max, option, 3041 index = elem.selectedIndex, 3042 values = [], 3043 options = elem.options, 3044 one = elem.type === "select-one"; 3045 3046 // Nothing was selected 3047 if ( index < 0 ) { 3048 return null; 3049 } 3050 3051 // Loop through all the selected options 3052 i = one ? index : 0; 3053 max = one ? index + 1 : options.length; 3054 for ( ; i < max; i++ ) { 3055 option = options[ i ]; 3056 3057 // Don't return options that are disabled or in a disabled optgroup 3058 if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && 3059 (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { 3060 3061 // Get the specific value for the option 3062 value = jQuery( option ).val(); 3063 3064 // We don't need an array for one selects 3065 if ( one ) { 3066 return value; 3067 } 3068 3069 // Multi-Selects return an array 3070 values.push( value ); 3071 } 3072 } 3073 3074 // Fixes Bug #2551 -- select.val() broken in IE after form.reset() 3075 if ( one && !values.length && options.length ) { 3076 return jQuery( options[ index ] ).val(); 3077 } 3078 3079 return values; 3080 }, 3081 3082 set: function( elem, value ) { 3083 var values = jQuery.makeArray( value ); 3084 3085 jQuery(elem).find("option").each(function() { 3086 this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; 3087 }); 3088 3089 if ( !values.length ) { 3090 elem.selectedIndex = -1; 3091 } 3092 return values; 3093 } 3094 } 3095 }, 3096 3097 attrFn: { 3098 val: true, 3099 css: true, 3100 html: true, 3101 text: true, 3102 data: true, 3103 width: true, 3104 height: true, 3105 offset: true 3106 }, 3107 3108 attr: function( elem, name, value, pass ) { 3109 var ret, hooks, notxml, 3110 nType = elem.nodeType; 3111 3112 // don't get/set attributes on text, comment and attribute nodes 3113 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { 3114 return undefined; 3115 } 3116 3117 if ( pass && name in jQuery.attrFn ) { 3118 return jQuery( elem )[ name ]( value ); 3119 } 3120 3121 // Fallback to prop when attributes are not supported 3122 if ( !("getAttribute" in elem) ) { 3123 return jQuery.prop( elem, name, value ); 3124 } 3125 3126 notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); 3127 3128 // All attributes are lowercase 3129 // Grab necessary hook if one is defined 3130 if ( notxml ) { 3131 name = name.toLowerCase(); 3132 hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); 3133 } 3134 3135 if ( value !== undefined ) { 3136 3137 if ( value === null ) { 3138 jQuery.removeAttr( elem, name ); 3139 return undefined; 3140 3141 } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { 3142 return ret; 3143 3144 } else { 3145 elem.setAttribute( name, "" + value ); 3146 return value; 3147 } 3148 3149 } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { 3150 return ret; 3151 3152 } else { 3153 3154 ret = elem.getAttribute( name ); 3155 3156 // Non-existent attributes return null, we normalize to undefined 3157 return ret === null ? 3158 undefined : 3159 ret; 3160 } 3161 }, 3162 3163 removeAttr: function( elem, value ) { 3164 var propName, attrNames, name, l, 3165 i = 0; 3166 3167 if ( elem.nodeType === 1 ) { 3168 attrNames = ( value || "" ).split( rspace ); 3169 l = attrNames.length; 3170 3171 for ( ; i < l; i++ ) { 3172 name = attrNames[ i ].toLowerCase(); 3173 propName = jQuery.propFix[ name ] || name; 3174 3175 // See #9699 for explanation of this approach (setting first, then removal) 3176 jQuery.attr( elem, name, "" ); 3177 elem.removeAttribute( getSetAttribute ? name : propName ); 3178 3179 // Set corresponding property to false for boolean attributes 3180 if ( rboolean.test( name ) && propName in elem ) { 3181 elem[ propName ] = false; 3182 } 3183 } 3184 } 3185 }, 3186 3187 attrHooks: { 3188 type: { 3189 set: function( elem, value ) { 3190 // We can't allow the type property to be changed (since it causes problems in IE) 3191 if ( rtype.test( elem.nodeName ) && elem.parentNode ) { 3192 jQuery.error( "type property can't be changed" ); 3193 } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { 3194 // Setting the type on a radio button after the value resets the value in IE6-9 3195 // Reset value to it's default in case type is set after value 3196 // This is for element creation 3197 var val = elem.value; 3198 elem.setAttribute( "type", value ); 3199 if ( val ) { 3200 elem.value = val; 3201 } 3202 return value; 3203 } 3204 } 3205 }, 3206 // Use the value property for back compat 3207 // Use the nodeHook for button elements in IE6/7 (#1954) 3208 value: { 3209 get: function( elem, name ) { 3210 if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { 3211 return nodeHook.get( elem, name ); 3212 } 3213 return name in elem ? 3214 elem.value : 3215 null; 3216 }, 3217 set: function( elem, value, name ) { 3218 if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { 3219 return nodeHook.set( elem, value, name ); 3220 } 3221 // Does not return so that setAttribute is also used 3222 elem.value = value; 3223 } 3224 } 3225 }, 3226 3227 propFix: { 3228 tabindex: "tabIndex", 3229 readonly: "readOnly", 3230 "for": "htmlFor", 3231 "class": "className", 3232 maxlength: "maxLength", 3233 cellspacing: "cellSpacing", 3234 cellpadding: "cellPadding", 3235 rowspan: "rowSpan", 3236 colspan: "colSpan", 3237 usemap: "useMap", 3238 frameborder: "frameBorder", 3239 contenteditable: "contentEditable" 3240 }, 3241 3242 prop: function( elem, name, value ) { 3243 var ret, hooks, notxml, 3244 nType = elem.nodeType; 3245 3246 // don't get/set properties on text, comment and attribute nodes 3247 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { 3248 return undefined; 3249 } 3250 3251 notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); 3252 3253 if ( notxml ) { 3254 // Fix name and attach hooks 3255 name = jQuery.propFix[ name ] || name; 3256 hooks = jQuery.propHooks[ name ]; 3257 } 3258 3259 if ( value !== undefined ) { 3260 if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { 3261 return ret; 3262 3263 } else { 3264 return ( elem[ name ] = value ); 3265 } 3266 3267 } else { 3268 if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { 3269 return ret; 3270 3271 } else { 3272 return elem[ name ]; 3273 } 3274 } 3275 }, 3276 3277 propHooks: { 3278 tabIndex: { 3279 get: function( elem ) { 3280 // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set 3281 // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ 3282 var attributeNode = elem.getAttributeNode("tabindex"); 3283 3284 return attributeNode && attributeNode.specified ? 3285 parseInt( attributeNode.value, 10 ) : 3286 rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? 3287 0 : 3288 undefined; 3289 } 3290 } 3291 } 3292}); 3293 3294// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) 3295jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; 3296 3297// Hook for boolean attributes 3298boolHook = { 3299 get: function( elem, name ) { 3300 // Align boolean attributes with corresponding properties 3301 // Fall back to attribute presence where some booleans are not supported 3302 var attrNode, 3303 property = jQuery.prop( elem, name ); 3304 return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? 3305 name.toLowerCase() : 3306 undefined; 3307 }, 3308 set: function( elem, value, name ) { 3309 var propName; 3310 if ( value === false ) { 3311 // Remove boolean attributes when set to false 3312 jQuery.removeAttr( elem, name ); 3313 } else { 3314 // value is true since we know at this point it's type boolean and not false 3315 // Set boolean attributes to the same name and set the DOM property 3316 propName = jQuery.propFix[ name ] || name; 3317 if ( propName in elem ) { 3318 // Only set the IDL specifically if it already exists on the element 3319 elem[ propName ] = true; 3320 } 3321 3322 elem.setAttribute( name, name.toLowerCase() ); 3323 } 3324 return name; 3325 } 3326}; 3327 3328// IE6/7 do not support getting/setting some attributes with get/setAttribute 3329if ( !getSetAttribute ) { 3330 3331 fixSpecified = { 3332 name: true, 3333 id: true 3334 }; 3335 3336 // Use this for any attribute in IE6/7 3337 // This fixes almost every IE6/7 issue 3338 nodeHook = jQuery.valHooks.button = { 3339 get: function( elem, name ) { 3340 var ret; 3341 ret = elem.getAttributeNode( name ); 3342 return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? 3343 ret.nodeValue : 3344 undefined; 3345 }, 3346 set: function( elem, value, name ) { 3347 // Set the existing or create a new attribute node 3348 var ret = elem.getAttributeNode( name ); 3349 if ( !ret ) { 3350 ret = document.createAttribute( name ); 3351 elem.setAttributeNode( ret ); 3352 } 3353 return ( ret.nodeValue = value + "" ); 3354 } 3355 }; 3356 3357 // Apply the nodeHook to tabindex 3358 jQuery.attrHooks.tabindex.set = nodeHook.set; 3359 3360 // Set width and height to auto instead of 0 on empty string( Bug #8150 ) 3361 // This is for removals 3362 jQuery.each([ "width", "height" ], function( i, name ) { 3363 jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { 3364 set: function( elem, value ) { 3365 if ( value === "" ) { 3366 elem.setAttribute( name, "auto" ); 3367 return value; 3368 } 3369 } 3370 }); 3371 }); 3372 3373 // Set contenteditable to false on removals(#10429) 3374 // Setting to empty string throws an error as an invalid value 3375 jQuery.attrHooks.contenteditable = { 3376 get: nodeHook.get, 3377 set: function( elem, value, name ) { 3378 if ( value === "" ) { 3379 value = "false"; 3380 } 3381 nodeHook.set( elem, value, name ); 3382 } 3383 }; 3384} 3385 3386 3387// Some attributes require a special call on IE 3388if ( !jQuery.support.hrefNormalized ) { 3389 jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { 3390 jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { 3391 get: function( elem ) { 3392 var ret = elem.getAttribute( name, 2 ); 3393 return ret === null ? undefined : ret; 3394 } 3395 }); 3396 }); 3397} 3398 3399if ( !jQuery.support.style ) { 3400 jQuery.attrHooks.style = { 3401 get: function( elem ) { 3402 // Return undefined in the case of empty string 3403 // Normalize to lowercase since IE uppercases css property names 3404 return elem.style.cssText.toLowerCase() || undefined; 3405 }, 3406 set: function( elem, value ) { 3407 return ( elem.style.cssText = "" + value ); 3408 } 3409 }; 3410} 3411 3412// Safari mis-reports the default selected property of an option 3413// Accessing the parent's selectedIndex property fixes it 3414if ( !jQuery.support.optSelected ) { 3415 jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { 3416 get: function( elem ) { 3417 var parent = elem.parentNode; 3418 3419 if ( parent ) { 3420 parent.selectedIndex; 3421 3422 // Make sure that it also works with optgroups, see #5701 3423 if ( parent.parentNode ) { 3424 parent.parentNode.selectedIndex; 3425 } 3426 } 3427 return null; 3428 } 3429 }); 3430} 3431 3432// IE6/7 call enctype encoding 3433if ( !jQuery.support.enctype ) { 3434 jQuery.propFix.enctype = "encoding"; 3435} 3436 3437// Radios and checkboxes getter/setter 3438if ( !jQuery.support.checkOn ) { 3439 jQuery.each([ "radio", "checkbox" ], function() { 3440 jQuery.valHooks[ this ] = { 3441 get: function( elem ) { 3442 // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified 3443 return elem.getAttribute("value") === null ? "on" : elem.value; 3444 } 3445 }; 3446 }); 3447} 3448jQuery.each([ "radio", "checkbox" ], function() { 3449 jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { 3450 set: function( elem, value ) { 3451 if ( jQuery.isArray( value ) ) { 3452 return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); 3453 } 3454 } 3455 }); 3456}); 3457 3458 3459 3460 3461var rnamespaces = /\.(.*)$/, 3462 rformElems = /^(?:textarea|input|select)$/i, 3463 rperiod = /\./g, 3464 rspaces = / /g, 3465 rescape = /[^\w\s.|`]/g, 3466 rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, 3467 rhoverHack = /\bhover(\.\S+)?/, 3468 rkeyEvent = /^key/, 3469 rmouseEvent = /^(?:mouse|contextmenu)|click/, 3470 rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, 3471 quickParse = function( selector ) { 3472 var quick = rquickIs.exec( selector ); 3473 if ( quick ) { 3474 // 0 1 2 3 3475 // [ _, tag, id, class ] 3476 quick[1] = ( quick[1] || "" ).toLowerCase(); 3477 quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); 3478 } 3479 return quick; 3480 }, 3481 quickIs = function( elem, m ) { 3482 return ( 3483 (!m[1] || elem.nodeName.toLowerCase() === m[1]) && 3484 (!m[2] || elem.id === m[2]) && 3485 (!m[3] || m[3].test( elem.className )) 3486 ); 3487 }, 3488 hoverHack = function( events ) { 3489 return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); 3490 }; 3491 3492/* 3493 * Helper functions for managing events -- not part of the public interface. 3494 * Props to Dean Edwards' addEvent library for many of the ideas. 3495 */ 3496jQuery.event = { 3497 3498 add: function( elem, types, handler, data, selector ) { 3499 3500 var elemData, eventHandle, events, 3501 t, tns, type, namespaces, handleObj, 3502 handleObjIn, quick, handlers, special; 3503 3504 // Don't attach events to noData or text/comment nodes (allow plain objects tho) 3505 if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { 3506 return; 3507 } 3508 3509 // Caller can pass in an object of custom data in lieu of the handler 3510 if ( handler.handler ) { 3511 handleObjIn = handler; 3512 handler = handleObjIn.handler; 3513 } 3514 3515 // Make sure that the handler has a unique ID, used to find/remove it later 3516 if ( !handler.guid ) { 3517 handler.guid = jQuery.guid++; 3518 } 3519 3520 // Init the element's event structure and main handler, if this is the first 3521 events = elemData.events; 3522 if ( !events ) { 3523 elemData.events = events = {}; 3524 } 3525 eventHandle = elemData.handle; 3526 if ( !eventHandle ) { 3527 elemData.handle = eventHandle = function( e ) { 3528 // Discard the second event of a jQuery.event.trigger() and 3529 // when an event is called after a page has unloaded 3530 return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? 3531 jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : 3532 undefined; 3533 }; 3534 // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events 3535 eventHandle.elem = elem; 3536 } 3537 3538 // Handle multiple events separated by a space 3539 // jQuery(...).bind("mouseover mouseout", fn); 3540 types = hoverHack(types).split( " " ); 3541 for ( t = 0; t < types.length; t++ ) { 3542 3543 tns = rtypenamespace.exec( types[t] ) || []; 3544 type = tns[1]; 3545 namespaces = ( tns[2] || "" ).split( "." ).sort(); 3546 3547 // If event changes its type, use the special event handlers for the changed type 3548 special = jQuery.event.special[ type ] || {}; 3549 3550 // If selector defined, determine special event api type, otherwise given type 3551 type = ( selector ? special.delegateType : special.bindType ) || type; 3552 3553 // Update special based on newly reset type 3554 special = jQuery.event.special[ type ] || {}; 3555 3556 // handleObj is passed to all event handlers 3557 handleObj = jQuery.extend({ 3558 type: type, 3559 origType: tns[1], 3560 data: data, 3561 handler: handler, 3562 guid: handler.guid, 3563 selector: selector, 3564 namespace: namespaces.join(".") 3565 }, handleObjIn ); 3566 3567 // Delegated event; pre-analyze selector so it's processed quickly on event dispatch 3568 if ( selector ) { 3569 handleObj.quick = quickParse( selector ); 3570 if ( !handleObj.quick && jQuery.expr.match.POS.test( selector ) ) { 3571 handleObj.isPositional = true; 3572 } 3573 } 3574 3575 // Init the event handler queue if we're the first 3576 handlers = events[ type ]; 3577 if ( !handlers ) { 3578 handlers = events[ type ] = []; 3579 handlers.delegateCount = 0; 3580 3581 // Only use addEventListener/attachEvent if the special events handler returns false 3582 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { 3583 // Bind the global event handler to the element 3584 if ( elem.addEventListener ) { 3585 elem.addEventListener( type, eventHandle, false ); 3586 3587 } else if ( elem.attachEvent ) { 3588 elem.attachEvent( "on" + type, eventHandle ); 3589 } 3590 } 3591 } 3592 3593 if ( special.add ) { 3594 special.add.call( elem, handleObj ); 3595 3596 if ( !handleObj.handler.guid ) { 3597 handleObj.handler.guid = handler.guid; 3598 } 3599 } 3600 3601 // Add to the element's handler list, delegates in front 3602 if ( selector ) { 3603 handlers.splice( handlers.delegateCount++, 0, handleObj ); 3604 } else { 3605 handlers.push( handleObj ); 3606 } 3607 3608 // Keep track of which events have ever been used, for event optimization 3609 jQuery.event.global[ type ] = true; 3610 } 3611 3612 // Nullify elem to prevent memory leaks in IE 3613 elem = null; 3614 }, 3615 3616 global: {}, 3617 3618 // Detach an event or set of events from an element 3619 remove: function( elem, types, handler, selector ) { 3620 3621 var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), 3622 t, tns, type, namespaces, origCount, 3623 j, events, special, handle, eventType, handleObj; 3624 3625 if ( !elemData || !(events = elemData.events) ) { 3626 return; 3627 } 3628 3629 // Once for each type.namespace in types; type may be omitted 3630 types = hoverHack( types || "" ).split(" "); 3631 for ( t = 0; t < types.length; t++ ) { 3632 tns = rtypenamespace.exec( types[t] ) || []; 3633 type = tns[1]; 3634 namespaces = tns[2]; 3635 3636 // Unbind all events (on this namespace, if provided) for the element 3637 if ( !type ) { 3638 namespaces = namespaces? "." + namespaces : ""; 3639 for ( j in events ) { 3640 jQuery.event.remove( elem, j + namespaces, handler, selector ); 3641 } 3642 return; 3643 } 3644 3645 special = jQuery.event.special[ type ] || {}; 3646 type = ( selector? special.delegateType : special.bindType ) || type; 3647 eventType = events[ type ] || []; 3648 origCount = eventType.length; 3649 namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; 3650 3651 // Only need to loop for special events or selective removal 3652 if ( handler || namespaces || selector || special.remove ) { 3653 for ( j = 0; j < eventType.length; j++ ) { 3654 handleObj = eventType[ j ]; 3655 3656 if ( !handler || handler.guid === handleObj.guid ) { 3657 if ( !namespaces || namespaces.test( handleObj.namespace ) ) { 3658 if ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) { 3659 eventType.splice( j--, 1 ); 3660 3661 if ( handleObj.selector ) { 3662 eventType.delegateCount--; 3663 } 3664 if ( special.remove ) { 3665 special.remove.call( elem, handleObj ); 3666 } 3667 } 3668 } 3669 } 3670 } 3671 } else { 3672 // Removing all events 3673 eventType.length = 0; 3674 } 3675 3676 // Remove generic event handler if we removed something and no more handlers exist 3677 // (avoids potential for endless recursion during removal of special event handlers) 3678 if ( eventType.length === 0 && origCount !== eventType.length ) { 3679 if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { 3680 jQuery.removeEvent( elem, type, elemData.handle ); 3681 } 3682 3683 delete events[ type ]; 3684 } 3685 } 3686 3687 // Remove the expando if it's no longer used 3688 if ( jQuery.isEmptyObject( events ) ) { 3689 handle = elemData.handle; 3690 if ( handle ) { 3691 handle.elem = null; 3692 } 3693 3694 // removeData also checks for emptiness and clears the expando if empty 3695 // so use it instead of delete 3696 jQuery.removeData( elem, [ "events", "handle" ], true ); 3697 } 3698 }, 3699 3700 // Events that are safe to short-circuit if no handlers are attached. 3701 // Native DOM events should not be added, they may have inline handlers. 3702 customEvent: { 3703 "getData": true, 3704 "setData": true, 3705 "changeData": true 3706 }, 3707 3708 trigger: function( event, data, elem, onlyHandlers ) { 3709 // Don't do events on text and comment nodes 3710 if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { 3711 return; 3712 } 3713 3714 // Event object or event type 3715 var type = event.type || event, 3716 namespaces = [], 3717 cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; 3718 3719 if ( type.indexOf( "!" ) >= 0 ) { 3720 // Exclusive events trigger only for the exact event (no namespaces) 3721 type = type.slice(0, -1); 3722 exclusive = true; 3723 } 3724 3725 if ( type.indexOf( "." ) >= 0 ) { 3726 // Namespaced trigger; create a regexp to match event type in handle() 3727 namespaces = type.split("."); 3728 type = namespaces.shift(); 3729 namespaces.sort(); 3730 } 3731 3732 if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { 3733 // No jQuery handlers for this event type, and it can't have inline handlers 3734 return; 3735 } 3736 3737 // Caller can pass in an Event, Object, or just an event type string 3738 event = typeof event === "object" ? 3739 // jQuery.Event object 3740 event[ jQuery.expando ] ? event : 3741 // Object literal 3742 new jQuery.Event( type, event ) : 3743 // Just the event type (string) 3744 new jQuery.Event( type ); 3745 3746 event.type = type; 3747 event.isTrigger = true; 3748 event.exclusive = exclusive; 3749 event.namespace = namespaces.join( "." ); 3750 event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; 3751 ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; 3752 3753 // triggerHandler() and global events don't bubble or run the default action 3754 if ( onlyHandlers || !elem ) { 3755 event.preventDefault(); 3756 } 3757 3758 // Handle a global trigger 3759 if ( !elem ) { 3760 3761 // TODO: Stop taunting the data cache; remove global events and always attach to document 3762 cache = jQuery.cache; 3763 for ( i in cache ) { 3764 if ( cache[ i ].events && cache[ i ].events[ type ] ) { 3765 jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); 3766 } 3767 } 3768 return; 3769 } 3770 3771 // Clean up the event in case it is being reused 3772 event.result = undefined; 3773 if ( !event.target ) { 3774 event.target = elem; 3775 } 3776 3777 // Clone any incoming data and prepend the event, creating the handler arg list 3778 data = data != null ? jQuery.makeArray( data ) : []; 3779 data.unshift( event ); 3780 3781 // Allow special events to draw outside the lines 3782 special = jQuery.event.special[ type ] || {}; 3783 if ( special.trigger && special.trigger.apply( elem, data ) === false ) { 3784 return; 3785 } 3786 3787 // Determine event propagation path in advance, per W3C events spec (#9951) 3788 // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) 3789 eventPath = [[ elem, special.bindType || type ]]; 3790 if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { 3791 3792 bubbleType = special.delegateType || type; 3793 old = null; 3794 for ( cur = elem.parentNode; cur; cur = cur.parentNode ) { 3795 eventPath.push([ cur, bubbleType ]); 3796 old = cur; 3797 } 3798 3799 // Only add window if we got to document (e.g., not plain obj or detached DOM) 3800 if ( old && old === elem.ownerDocument ) { 3801 eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); 3802 } 3803 } 3804 3805 // Fire handlers on the event path 3806 for ( i = 0; i < eventPath.length; i++ ) { 3807 3808 cur = eventPath[i][0]; 3809 event.type = eventPath[i][1]; 3810 3811 handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); 3812 if ( handle ) { 3813 handle.apply( cur, data ); 3814 } 3815 handle = ontype && cur[ ontype ]; 3816 if ( handle && jQuery.acceptData( cur ) ) { 3817 handle.apply( cur, data ); 3818 } 3819 3820 if ( event.isPropagationStopped() ) { 3821 break; 3822 } 3823 } 3824 event.type = type; 3825 3826 // If nobody prevented the default action, do it now 3827 if ( !event.isDefaultPrevented() ) { 3828 3829 if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && 3830 !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { 3831 3832 // Call a native DOM method on the target with the same name name as the event. 3833 // Can't use an .isFunction() check here because IE6/7 fails that test. 3834 // Don't do default actions on window, that's where global variables be (#6170) 3835 // IE<9 dies on focus/blur to hidden element (#1486) 3836 if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { 3837 3838 // Don't re-trigger an onFOO event when we call its FOO() method 3839 old = elem[ ontype ]; 3840 3841 if ( old ) { 3842 elem[ ontype ] = null; 3843 } 3844 3845 // Prevent re-triggering of the same event, since we already bubbled it above 3846 jQuery.event.triggered = type; 3847 elem[ type ](); 3848 jQuery.event.triggered = undefined; 3849 3850 if ( old ) { 3851 elem[ ontype ] = old; 3852 } 3853 } 3854 } 3855 } 3856 3857 return event.result; 3858 }, 3859 3860 dispatch: function( event ) { 3861 3862 // Make a writable jQuery.Event from the native event object 3863 event = jQuery.event.fix( event || window.event ); 3864 3865 var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), 3866 delegateCount = handlers.delegateCount, 3867 args = [].slice.call( arguments, 0 ), 3868 run_all = !event.exclusive && !event.namespace, 3869 specialHandle = ( jQuery.event.special[ event.type ] || {} ).handle, 3870 handlerQueue = [], 3871 i, j, cur, ret, selMatch, matched, matches, handleObj, sel, hit, related; 3872 3873 // Use the fix-ed jQuery.Event rather than the (read-only) native event 3874 args[0] = event; 3875 event.delegateTarget = this; 3876 3877 // Determine handlers that should run if there are delegated events 3878 // Avoid disabled elements in IE (#6911) and non-left-click bubbling in Firefox (#3861) 3879 if ( delegateCount && !event.target.disabled && !(event.button && event.type === "click") ) { 3880 3881 for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { 3882 selMatch = {}; 3883 matches = []; 3884 for ( i = 0; i < delegateCount; i++ ) { 3885 handleObj = handlers[ i ]; 3886 sel = handleObj.selector; 3887 hit = selMatch[ sel ]; 3888 3889 if ( handleObj.isPositional ) { 3890 // Since .is() does not work for positionals; see http://jsfiddle.net/eJ4yd/3/ 3891 hit = ( hit || (selMatch[ sel ] = jQuery( sel )) ).index( cur ) >= 0; 3892 } else if ( hit === undefined ) { 3893 hit = selMatch[ sel ] = ( handleObj.quick ? quickIs( cur, handleObj.quick ) : jQuery( cur ).is( sel ) ); 3894 } 3895 if ( hit ) { 3896 matches.push( handleObj ); 3897 } 3898 } 3899 if ( matches.length ) { 3900 handlerQueue.push({ elem: cur, matches: matches }); 3901 } 3902 } 3903 } 3904 3905 // Add the remaining (directly-bound) handlers 3906 if ( handlers.length > delegateCount ) { 3907 handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); 3908 } 3909 3910 // Run delegates first; they may want to stop propagation beneath us 3911 for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { 3912 matched = handlerQueue[ i ]; 3913 event.currentTarget = matched.elem; 3914 3915 for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { 3916 handleObj = matched.matches[ j ]; 3917 3918 // Triggered event must either 1) be non-exclusive and have no namespace, or 3919 // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). 3920 if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { 3921 3922 event.data = handleObj.data; 3923 event.handleObj = handleObj; 3924 3925 ret = ( specialHandle || handleObj.handler ).apply( matched.elem, args ); 3926 3927 if ( ret !== undefined ) { 3928 event.result = ret; 3929 if ( ret === false ) { 3930 event.preventDefault(); 3931 event.stopPropagation(); 3932 } 3933 } 3934 } 3935 } 3936 } 3937 3938 return event.result; 3939 }, 3940 3941 // Includes some event props shared by KeyEvent and MouseEvent 3942 // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** 3943 props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), 3944 3945 fixHooks: {}, 3946 3947 keyHooks: { 3948 props: "char charCode key keyCode".split(" "), 3949 filter: function( event, original ) { 3950 3951 // Add which for key events 3952 if ( event.which == null ) { 3953 event.which = original.charCode != null ? original.charCode : original.keyCode; 3954 } 3955 3956 return event; 3957 } 3958 }, 3959 3960 mouseHooks: { 3961 props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement wheelDelta".split(" "), 3962 filter: function( event, original ) { 3963 var eventDoc, doc, body, 3964 button = original.button, 3965 fromElement = original.fromElement; 3966 3967 // Calculate pageX/Y if missing and clientX/Y available 3968 if ( event.pageX == null && original.clientX != null ) { 3969 eventDoc = event.target.ownerDocument || document; 3970 doc = eventDoc.documentElement; 3971 body = eventDoc.body; 3972 3973 event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); 3974 event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); 3975 } 3976 3977 // Add relatedTarget, if necessary 3978 if ( !event.relatedTarget && fromElement ) { 3979 event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; 3980 } 3981 3982 // Add which for click: 1 === left; 2 === middle; 3 === right 3983 // Note: button is not normalized, so don't use it 3984 if ( !event.which && button !== undefined ) { 3985 event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); 3986 } 3987 3988 return event; 3989 } 3990 }, 3991 3992 fix: function( event ) { 3993 if ( event[ jQuery.expando ] ) { 3994 return event; 3995 } 3996 3997 // Create a writable copy of the event object and normalize some properties 3998 var i, prop, 3999 originalEvent = event, 4000 fixHook = jQuery.event.fixHooks[ event.type ] || {}, 4001 copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; 4002 4003 event = jQuery.Event( originalEvent ); 4004 4005 for ( i = copy.length; i; ) { 4006 prop = copy[ --i ]; 4007 event[ prop ] = originalEvent[ prop ]; 4008 } 4009 4010 // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) 4011 if ( !event.target ) { 4012 event.target = originalEvent.srcElement || document; 4013 } 4014 4015 // Target should not be a text node (#504, Safari) 4016 if ( event.target.nodeType === 3 ) { 4017 event.target = event.target.parentNode; 4018 } 4019 4020 // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) 4021 if ( event.metaKey === undefined ) { 4022 event.metaKey = event.ctrlKey; 4023 } 4024 4025 return fixHook.filter? fixHook.filter( event, originalEvent ) : event; 4026 }, 4027 4028 special: { 4029 ready: { 4030 // Make sure the ready event is setup 4031 setup: jQuery.bindReady 4032 }, 4033 4034 focus: { 4035 delegateType: "focusin", 4036 noBubble: true 4037 }, 4038 blur: { 4039 delegateType: "focusout", 4040 noBubble: true 4041 }, 4042 4043 beforeunload: { 4044 setup: function( data, namespaces, eventHandle ) { 4045 // We only want to do this special case on windows 4046 if ( jQuery.isWindow( this ) ) { 4047 this.onbeforeunload = eventHandle; 4048 } 4049 }, 4050 4051 teardown: function( namespaces, eventHandle ) { 4052 if ( this.onbeforeunload === eventHandle ) { 4053 this.onbeforeunload = null; 4054 } 4055 } 4056 } 4057 }, 4058 4059 simulate: function( type, elem, event, bubble ) { 4060 // Piggyback on a donor event to simulate a different one. 4061 // Fake originalEvent to avoid donor's stopPropagation, but if the 4062 // simulated event prevents default then we do the same on the donor. 4063 var e = jQuery.extend( 4064 new jQuery.Event(), 4065 event, 4066 { type: type, 4067 isSimulated: true, 4068 originalEvent: {} 4069 } 4070 ); 4071 if ( bubble ) { 4072 jQuery.event.trigger( e, null, elem ); 4073 } else { 4074 jQuery.event.dispatch.call( elem, e ); 4075 } 4076 if ( e.isDefaultPrevented() ) { 4077 event.preventDefault(); 4078 } 4079 } 4080}; 4081 4082// Some plugins are using, but it's undocumented/deprecated and will be removed. 4083// The 1.7 special event interface should provide all the hooks needed now. 4084jQuery.event.handle = jQuery.event.dispatch; 4085 4086jQuery.removeEvent = document.removeEventListener ? 4087 function( elem, type, handle ) { 4088 if ( elem.removeEventListener ) { 4089 elem.removeEventListener( type, handle, false ); 4090 } 4091 } : 4092 function( elem, type, handle ) { 4093 if ( elem.detachEvent ) { 4094 elem.detachEvent( "on" + type, handle ); 4095 } 4096 }; 4097 4098jQuery.Event = function( src, props ) { 4099 // Allow instantiation without the 'new' keyword 4100 if ( !(this instanceof jQuery.Event) ) { 4101 return new jQuery.Event( src, props ); 4102 } 4103 4104 // Event object 4105 if ( src && src.type ) { 4106 this.originalEvent = src; 4107 this.type = src.type; 4108 4109 // Events bubbling up the document may have been marked as prevented 4110 // by a handler lower down the tree; reflect the correct value. 4111 this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || 4112 src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; 4113 4114 // Event type 4115 } else { 4116 this.type = src; 4117 } 4118 4119 // Put explicitly provided properties onto the event object 4120 if ( props ) { 4121 jQuery.extend( this, props ); 4122 } 4123 4124 // Create a timestamp if incoming event doesn't have one 4125 this.timeStamp = src && src.timeStamp || jQuery.now(); 4126 4127 // Mark it as fixed 4128 this[ jQuery.expando ] = true; 4129}; 4130 4131function returnFalse() { 4132 return false; 4133} 4134function returnTrue() { 4135 return true; 4136} 4137 4138// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding 4139// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html 4140jQuery.Event.prototype = { 4141 preventDefault: function() { 4142 this.isDefaultPrevented = returnTrue; 4143 4144 var e = this.originalEvent; 4145 if ( !e ) { 4146 return; 4147 } 4148 4149 // if preventDefault exists run it on the original event 4150 if ( e.preventDefault ) { 4151 e.preventDefault(); 4152 4153 // otherwise set the returnValue property of the original event to false (IE) 4154 } else { 4155 e.returnValue = false; 4156 } 4157 }, 4158 stopPropagation: function() { 4159 this.isPropagationStopped = returnTrue; 4160 4161 var e = this.originalEvent; 4162 if ( !e ) { 4163 return; 4164 } 4165 // if stopPropagation exists run it on the original event 4166 if ( e.stopPropagation ) { 4167 e.stopPropagation(); 4168 } 4169 // otherwise set the cancelBubble property of the original event to true (IE) 4170 e.cancelBubble = true; 4171 }, 4172 stopImmediatePropagation: function() { 4173 this.isImmediatePropagationStopped = returnTrue; 4174 this.stopPropagation(); 4175 }, 4176 isDefaultPrevented: returnFalse, 4177 isPropagationStopped: returnFalse, 4178 isImmediatePropagationStopped: returnFalse 4179}; 4180 4181// Create mouseenter/leave events using mouseover/out and event-time checks 4182jQuery.each({ 4183 mouseenter: "mouseover", 4184 mouseleave: "mouseout" 4185}, function( orig, fix ) { 4186 jQuery.event.special[ orig ] = jQuery.event.special[ fix ] = { 4187 delegateType: fix, 4188 bindType: fix, 4189 4190 handle: function( event ) { 4191 var target = this, 4192 related = event.relatedTarget, 4193 handleObj = event.handleObj, 4194 selector = handleObj.selector, 4195 oldType, ret; 4196 4197 // For a real mouseover/out, always call the handler; for 4198 // mousenter/leave call the handler if related is outside the target. 4199 // NB: No relatedTarget if the mouse left/entered the browser window 4200 if ( !related || handleObj.origType === event.type || (related !== target && !jQuery.contains( target, related )) ) { 4201 oldType = event.type; 4202 event.type = handleObj.origType; 4203 ret = handleObj.handler.apply( this, arguments ); 4204 event.type = oldType; 4205 } 4206 return ret; 4207 } 4208 }; 4209}); 4210 4211// IE submit delegation 4212if ( !jQuery.support.submitBubbles ) { 4213 4214 jQuery.event.special.submit = { 4215 setup: function() { 4216 // Only need this for delegated form submit events 4217 if ( jQuery.nodeName( this, "form" ) ) { 4218 return false; 4219 } 4220 4221 // Lazy-add a submit handler when a descendant form may potentially be submitted 4222 jQuery.event.add( this, "click._submit keypress._submit", function( e ) { 4223 // Node name check avoids a VML-related crash in IE (#9807) 4224 var elem = e.target, 4225 form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; 4226 if ( form && !form._submit_attached ) { 4227 jQuery.event.add( form, "submit._submit", function( event ) { 4228 // Form was submitted, bubble the event up the tree 4229 if ( this.parentNode ) { 4230 jQuery.event.simulate( "submit", this.parentNode, event, true ); 4231 } 4232 }); 4233 form._submit_attached = true; 4234 } 4235 }); 4236 // return undefined since we don't need an event listener 4237 }, 4238 4239 teardown: function() { 4240 // Only need this for delegated form submit events 4241 if ( jQuery.nodeName( this, "form" ) ) { 4242 return false; 4243 } 4244 4245 // Remove delegated handlers; cleanData eventually reaps submit handlers attached above 4246 jQuery.event.remove( this, "._submit" ); 4247 } 4248 }; 4249} 4250 4251// IE change delegation and checkbox/radio fix 4252if ( !jQuery.support.changeBubbles ) { 4253 4254 jQuery.event.special.change = { 4255 4256 setup: function() { 4257 4258 if ( rformElems.test( this.nodeName ) ) { 4259 // IE doesn't fire change on a check/radio until blur; trigger it on click 4260 // after a propertychange. Eat the blur-change in special.change.handle. 4261 // This still fires onchange a second time for check/radio after blur. 4262 if ( this.type === "checkbox" || this.type === "radio" ) { 4263 jQuery.event.add( this, "propertychange._change", function( event ) { 4264 if ( event.originalEvent.propertyName === "checked" ) { 4265 this._just_changed = true; 4266 } 4267 }); 4268 jQuery.event.add( this, "click._change", function( event ) { 4269 if ( this._just_changed ) { 4270 this._just_changed = false; 4271 jQuery.event.simulate( "change", this, event, true ); 4272 } 4273 }); 4274 } 4275 return false; 4276 } 4277 // Delegated event; lazy-add a change handler on descendant inputs 4278 jQuery.event.add( this, "beforeactivate._change", function( e ) { 4279 var elem = e.target; 4280 4281 if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) { 4282 jQuery.event.add( elem, "change._change", function( event ) { 4283 if ( this.parentNode && !event.isSimulated ) { 4284 jQuery.event.simulate( "change", this.parentNode, event, true ); 4285 } 4286 }); 4287 elem._change_attached = true; 4288 } 4289 }); 4290 }, 4291 4292 handle: function( event ) { 4293 var elem = event.target; 4294 4295 // Swallow native change events from checkbox/radio, we already triggered them above 4296 if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { 4297 return event.handleObj.handler.apply( this, arguments ); 4298 } 4299 }, 4300 4301 teardown: function() { 4302 jQuery.event.remove( this, "._change" ); 4303 4304 return rformElems.test( this.nodeName ); 4305 } 4306 }; 4307} 4308 4309// Create "bubbling" focus and blur events 4310if ( !jQuery.support.focusinBubbles ) { 4311 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { 4312 4313 // Attach a single capturing handler while someone wants focusin/focusout 4314 var attaches = 0, 4315 handler = function( event ) { 4316 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); 4317 }; 4318 4319 jQuery.event.special[ fix ] = { 4320 setup: function() { 4321 if ( attaches++ === 0 ) { 4322 document.addEventListener( orig, handler, true ); 4323 } 4324 }, 4325 teardown: function() { 4326 if ( --attaches === 0 ) { 4327 document.removeEventListener( orig, handler, true ); 4328 } 4329 } 4330 }; 4331 }); 4332} 4333 4334jQuery.fn.extend({ 4335 4336 on: function( types, selector, data, fn, /*INTERNAL*/ one ) { 4337 var origFn, type; 4338 4339 // Types can be a map of types/handlers 4340 if ( typeof types === "object" ) { 4341 // ( types-Object, selector, data ) 4342 if ( typeof selector !== "string" ) { 4343 // ( types-Object, data ) 4344 data = selector; 4345 selector = undefined; 4346 } 4347 for ( type in types ) { 4348 this.on( type, selector, data, types[ type ], one ); 4349 } 4350 return this; 4351 } 4352 4353 if ( data == null && fn == null ) { 4354 // ( types, fn ) 4355 fn = selector; 4356 data = selector = undefined; 4357 } else if ( fn == null ) { 4358 if ( typeof selector === "string" ) { 4359 // ( types, selector, fn ) 4360 fn = data; 4361 data = undefined; 4362 } else { 4363 // ( types, data, fn ) 4364 fn = data; 4365 data = selector; 4366 selector = undefined; 4367 } 4368 } 4369 if ( fn === false ) { 4370 fn = returnFalse; 4371 } else if ( !fn ) { 4372 return this; 4373 } 4374 4375 if ( one === 1 ) { 4376 origFn = fn; 4377 fn = function( event ) { 4378 // Can use an empty set, since event contains the info 4379 jQuery().off( event ); 4380 return origFn.apply( this, arguments ); 4381 }; 4382 // Use same guid so caller can remove using origFn 4383 fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); 4384 } 4385 return this.each( function() { 4386 jQuery.event.add( this, types, fn, data, selector ); 4387 }); 4388 }, 4389 one: function( types, selector, data, fn ) { 4390 return this.on.call( this, types, selector, data, fn, 1 ); 4391 }, 4392 off: function( types, selector, fn ) { 4393 if ( types && types.preventDefault && types.handleObj ) { 4394 // ( event ) dispatched jQuery.Event 4395 var handleObj = types.handleObj; 4396 jQuery( types.delegateTarget ).off( 4397 handleObj.namespace? handleObj.type + "." + handleObj.namespace : handleObj.type, 4398 handleObj.selector, 4399 handleObj.handler 4400 ); 4401 return this; 4402 } 4403 if ( typeof types === "object" ) { 4404 // ( types-object [, selector] ) 4405 for ( var type in types ) { 4406 this.off( type, selector, types[ type ] ); 4407 } 4408 return this; 4409 } 4410 if ( selector === false || typeof selector === "function" ) { 4411 // ( types [, fn] ) 4412 fn = selector; 4413 selector = undefined; 4414 } 4415 if ( fn === false ) { 4416 fn = returnFalse; 4417 } 4418 return this.each(function() { 4419 jQuery.event.remove( this, types, fn, selector ); 4420 }); 4421 }, 4422 4423 bind: function( types, data, fn ) { 4424 return this.on( types, null, data, fn ); 4425 }, 4426 unbind: function( types, fn ) { 4427 return this.off( types, null, fn ); 4428 }, 4429 4430 live: function( types, data, fn ) { 4431 jQuery( this.context ).on( types, this.selector, data, fn ); 4432 return this; 4433 }, 4434 die: function( types, fn ) { 4435 jQuery( this.context ).off( types, this.selector || "**", fn ); 4436 return this; 4437 }, 4438 4439 delegate: function( selector, types, data, fn ) { 4440 return this.on( types, selector, data, fn ); 4441 }, 4442 undelegate: function( selector, types, fn ) { 4443 // ( namespace ) or ( selector, types [, fn] ) 4444 return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); 4445 }, 4446 4447 trigger: function( type, data ) { 4448 return this.each(function() { 4449 jQuery.event.trigger( type, data, this ); 4450 }); 4451 }, 4452 triggerHandler: function( type, data ) { 4453 if ( this[0] ) { 4454 return jQuery.event.trigger( type, data, this[0], true ); 4455 } 4456 }, 4457 4458 toggle: function( fn ) { 4459 // Save reference to arguments for access in closure 4460 var args = arguments, 4461 guid = fn.guid || jQuery.guid++, 4462 i = 0, 4463 toggler = function( event ) { 4464 // Figure out which function to execute 4465 var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; 4466 jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); 4467 4468 // Make sure that clicks stop 4469 event.preventDefault(); 4470 4471 // and execute the function 4472 return args[ lastToggle ].apply( this, arguments ) || false; 4473 }; 4474 4475 // link all the functions, so any of them can unbind this click handler 4476 toggler.guid = guid; 4477 while ( i < args.length ) { 4478 args[ i++ ].guid = guid; 4479 } 4480 4481 return this.click( toggler ); 4482 }, 4483 4484 hover: function( fnOver, fnOut ) { 4485 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); 4486 } 4487}); 4488 4489jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + 4490 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + 4491 "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { 4492 4493 // Handle event binding 4494 jQuery.fn[ name ] = function( data, fn ) { 4495 if ( fn == null ) { 4496 fn = data; 4497 data = null; 4498 } 4499 4500 return arguments.length > 0 ? 4501 this.bind( name, data, fn ) : 4502 this.trigger( name ); 4503 }; 4504 4505 if ( jQuery.attrFn ) { 4506 jQuery.attrFn[ name ] = true; 4507 } 4508 4509 if ( rkeyEvent.test( name ) ) { 4510 jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; 4511 } 4512 4513 if ( rmouseEvent.test( name ) ) { 4514 jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; 4515 } 4516}); 4517 4518 4519 4520/*! 4521 * Sizzle CSS Selector Engine 4522 * Copyright 2011, The Dojo Foundation 4523 * Released under the MIT, BSD, and GPL Licenses. 4524 * More information: http://sizzlejs.com/ 4525 */ 4526(function(){ 4527 4528var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, 4529 expando = "sizcache" + (Math.random() + '').replace('.', ''), 4530 done = 0, 4531 toString = Object.prototype.toString, 4532 hasDuplicate = false, 4533 baseHasDuplicate = true, 4534 rBackslash = /\\/g, 4535 rReturn = /\r\n/g, 4536 rNonWord = /\W/; 4537 4538// Here we check if the JavaScript engine is using some sort of 4539// optimization where it does not always call our comparision 4540// function. If that is the case, discard the hasDuplicate value. 4541// Thus far that includes Google Chrome. 4542[0, 0].sort(function() { 4543 baseHasDuplicate = false; 4544 return 0; 4545}); 4546 4547var Sizzle = function( selector, context, results, seed ) { 4548 results = results || []; 4549 context = context || document; 4550 4551 var origContext = context; 4552 4553 if ( context.nodeType !== 1 && context.nodeType !== 9 ) { 4554 return []; 4555 } 4556 4557 if ( !selector || typeof selector !== "string" ) { 4558 return results; 4559 } 4560 4561 var m, set, checkSet, extra, ret, cur, pop, i, 4562 prune = true, 4563 contextXML = Sizzle.isXML( context ), 4564 parts = [], 4565 soFar = selector; 4566 4567 // Reset the position of the chunker regexp (start from head) 4568 do { 4569 chunker.exec( "" ); 4570 m = chunker.exec( soFar ); 4571 4572 if ( m ) { 4573 soFar = m[3]; 4574 4575 parts.push( m[1] ); 4576 4577 if ( m[2] ) { 4578 extra = m[3]; 4579 break; 4580 } 4581 } 4582 } while ( m ); 4583 4584 if ( parts.length > 1 && origPOS.exec( selector ) ) { 4585 4586 if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { 4587 set = posProcess( parts[0] + parts[1], context, seed ); 4588 4589 } else { 4590 set = Expr.relative[ parts[0] ] ? 4591 [ context ] : 4592 Sizzle( parts.shift(), context ); 4593 4594 while ( parts.length ) { 4595 selector = parts.shift(); 4596 4597 if ( Expr.relative[ selector ] ) { 4598 selector += parts.shift(); 4599 } 4600 4601 set = posProcess( selector, set, seed ); 4602 } 4603 } 4604 4605 } else { 4606 // Take a shortcut and set the context if the root selector is an ID 4607 // (but not if it'll be faster if the inner selector is an ID) 4608 if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && 4609 Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { 4610 4611 ret = Sizzle.find( parts.shift(), context, contextXML ); 4612 context = ret.expr ? 4613 Sizzle.filter( ret.expr, ret.set )[0] : 4614 ret.set[0]; 4615 } 4616 4617 if ( context ) { 4618 ret = seed ? 4619 { expr: parts.pop(), set: makeArray(seed) } : 4620 Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); 4621 4622 set = ret.expr ? 4623 Sizzle.filter( ret.expr, ret.set ) : 4624 ret.set; 4625 4626 if ( parts.length > 0 ) { 4627 checkSet = makeArray( set ); 4628 4629 } else { 4630 prune = false; 4631 } 4632 4633 while ( parts.length ) { 4634 cur = parts.pop(); 4635 pop = cur; 4636 4637 if ( !Expr.relative[ cur ] ) { 4638 cur = ""; 4639 } else { 4640 pop = parts.pop(); 4641 } 4642 4643 if ( pop == null ) { 4644 pop = context; 4645 } 4646 4647 Expr.relative[ cur ]( checkSet, pop, contextXML ); 4648 } 4649 4650 } else { 4651 checkSet = parts = []; 4652 } 4653 } 4654 4655 if ( !checkSet ) { 4656 checkSet = set; 4657 } 4658 4659 if ( !checkSet ) { 4660 Sizzle.error( cur || selector ); 4661 } 4662 4663 if ( toString.call(checkSet) === "[object Array]" ) { 4664 if ( !prune ) { 4665 results.push.apply( results, checkSet ); 4666 4667 } else if ( context && context.nodeType === 1 ) { 4668 for ( i = 0; checkSet[i] != null; i++ ) { 4669 if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { 4670 results.push( set[i] ); 4671 } 4672 } 4673 4674 } else { 4675 for ( i = 0; checkSet[i] != null; i++ ) { 4676 if ( checkSet[i] && checkSet[i].nodeType === 1 ) { 4677 results.push( set[i] ); 4678 } 4679 } 4680 } 4681 4682 } else { 4683 makeArray( checkSet, results ); 4684 } 4685 4686 if ( extra ) { 4687 Sizzle( extra, origContext, results, seed ); 4688 Sizzle.uniqueSort( results ); 4689 } 4690 4691 return results; 4692}; 4693 4694Sizzle.uniqueSort = function( results ) { 4695 if ( sortOrder ) { 4696 hasDuplicate = baseHasDuplicate; 4697 results.sort( sortOrder ); 4698 4699 if ( hasDuplicate ) { 4700 for ( var i = 1; i < results.length; i++ ) { 4701 if ( results[i] === results[ i - 1 ] ) { 4702 results.splice( i--, 1 ); 4703 } 4704 } 4705 } 4706 } 4707 4708 return results; 4709}; 4710 4711Sizzle.matches = function( expr, set ) { 4712 return Sizzle( expr, null, null, set ); 4713}; 4714 4715Sizzle.matchesSelector = function( node, expr ) { 4716 return Sizzle( expr, null, null, [node] ).length > 0; 4717}; 4718 4719Sizzle.find = function( expr, context, isXML ) { 4720 var set, i, len, match, type, left; 4721 4722 if ( !expr ) { 4723 return []; 4724 } 4725 4726 for ( i = 0, len = Expr.order.length; i < len; i++ ) { 4727 type = Expr.order[i]; 4728 4729 if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { 4730 left = match[1]; 4731 match.splice( 1, 1 ); 4732 4733 if ( left.substr( left.length - 1 ) !== "\\" ) { 4734 match[1] = (match[1] || "").replace( rBackslash, "" ); 4735 set = Expr.find[ type ]( match, context, isXML ); 4736 4737 if ( set != null ) { 4738 expr = expr.replace( Expr.match[ type ], "" ); 4739 break; 4740 } 4741 } 4742 } 4743 } 4744 4745 if ( !set ) { 4746 set = typeof context.getElementsByTagName !== "undefined" ? 4747 context.getElementsByTagName( "*" ) : 4748 []; 4749 } 4750 4751 return { set: set, expr: expr }; 4752}; 4753 4754Sizzle.filter = function( expr, set, inplace, not ) { 4755 var match, anyFound, 4756 type, found, item, filter, left, 4757 i, pass, 4758 old = expr, 4759 result = [], 4760 curLoop = set, 4761 isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); 4762 4763 while ( expr && set.length ) { 4764 for ( type in Expr.filter ) { 4765 if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { 4766 filter = Expr.filter[ type ]; 4767 left = match[1]; 4768 4769 anyFound = false; 4770 4771 match.splice(1,1); 4772 4773 if ( left.substr( left.length - 1 ) === "\\" ) { 4774 continue; 4775 } 4776 4777 if ( curLoop === result ) { 4778 result = []; 4779 } 4780 4781 if ( Expr.preFilter[ type ] ) { 4782 match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); 4783 4784 if ( !match ) { 4785 anyFound = found = true; 4786 4787 } else if ( match === true ) { 4788 continue; 4789 } 4790 } 4791 4792 if ( match ) { 4793 for ( i = 0; (item = curLoop[i]) != null; i++ ) { 4794 if ( item ) { 4795 found = filter( item, match, i, curLoop ); 4796 pass = not ^ found; 4797 4798 if ( inplace && found != null ) { 4799 if ( pass ) { 4800 anyFound = true; 4801 4802 } else { 4803 curLoop[i] = false; 4804 } 4805 4806 } else if ( pass ) { 4807 result.push( item ); 4808 anyFound = true; 4809 } 4810 } 4811 } 4812 } 4813 4814 if ( found !== undefined ) { 4815 if ( !inplace ) { 4816 curLoop = result; 4817 } 4818 4819 expr = expr.replace( Expr.match[ type ], "" ); 4820 4821 if ( !anyFound ) { 4822 return []; 4823 } 4824 4825 break; 4826 } 4827 } 4828 } 4829 4830 // Improper expression 4831 if ( expr === old ) { 4832 if ( anyFound == null ) { 4833 Sizzle.error( expr ); 4834 4835 } else { 4836 break; 4837 } 4838 } 4839 4840 old = expr; 4841 } 4842 4843 return curLoop; 4844}; 4845 4846Sizzle.error = function( msg ) { 4847 throw "Syntax error, unrecognized expression: " + msg; 4848}; 4849 4850/** 4851 * Utility function for retreiving the text value of an array of DOM nodes 4852 * @param {Array|Element} elem 4853 */ 4854var getText = Sizzle.getText = function( elem ) { 4855 var i, node, 4856 nodeType = elem.nodeType, 4857 ret = ""; 4858 4859 if ( nodeType ) { 4860 if ( nodeType === 1 ) { 4861 // Use textContent || innerText for elements 4862 if ( typeof elem.textContent === 'string' ) { 4863 return elem.textContent; 4864 } else if ( typeof elem.innerText === 'string' ) { 4865 // Replace IE's carriage returns 4866 return elem.innerText.replace( rReturn, '' ); 4867 } else { 4868 // Traverse it's children 4869 for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { 4870 ret += getText( elem ); 4871 } 4872 } 4873 } else if ( nodeType === 3 || nodeType === 4 ) { 4874 return elem.nodeValue; 4875 } 4876 } else { 4877 4878 // If no nodeType, this is expected to be an array 4879 for ( i = 0; (node = elem[i]); i++ ) { 4880 // Do not traverse comment nodes 4881 if ( node.nodeType !== 8 ) { 4882 ret += getText( node ); 4883 } 4884 } 4885 } 4886 return ret; 4887}; 4888 4889var Expr = Sizzle.selectors = { 4890 order: [ "ID", "NAME", "TAG" ], 4891 4892 match: { 4893 ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, 4894 CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, 4895 NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, 4896 ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, 4897 TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, 4898 CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, 4899 POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, 4900 PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ 4901 }, 4902 4903 leftMatch: {}, 4904 4905 attrMap: { 4906 "class": "className", 4907 "for": "htmlFor" 4908 }, 4909 4910 attrHandle: { 4911 href: function( elem ) { 4912 return elem.getAttribute( "href" ); 4913 }, 4914 type: function( elem ) { 4915 return elem.getAttribute( "type" ); 4916 } 4917 }, 4918 4919 relative: { 4920 "+": function(checkSet, part){ 4921 var isPartStr = typeof part === "string", 4922 isTag = isPartStr && !rNonWord.test( part ), 4923 isPartStrNotTag = isPartStr && !isTag; 4924 4925 if ( isTag ) { 4926 part = part.toLowerCase(); 4927 } 4928 4929 for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { 4930 if ( (elem = checkSet[i]) ) { 4931 while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} 4932 4933 checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? 4934 elem || false : 4935 elem === part; 4936 } 4937 } 4938 4939 if ( isPartStrNotTag ) { 4940 Sizzle.filter( part, checkSet, true ); 4941 } 4942 }, 4943 4944 ">": function( checkSet, part ) { 4945 var elem, 4946 isPartStr = typeof part === "string", 4947 i = 0, 4948 l = checkSet.length; 4949 4950 if ( isPartStr && !rNonWord.test( part ) ) { 4951 part = part.toLowerCase(); 4952 4953 for ( ; i < l; i++ ) { 4954 elem = checkSet[i]; 4955 4956 if ( elem ) { 4957 var parent = elem.parentNode; 4958 checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; 4959 } 4960 } 4961 4962 } else { 4963 for ( ; i < l; i++ ) { 4964 elem = checkSet[i]; 4965 4966 if ( elem ) { 4967 checkSet[i] = isPartStr ? 4968 elem.parentNode : 4969 elem.parentNode === part; 4970 } 4971 } 4972 4973 if ( isPartStr ) { 4974 Sizzle.filter( part, checkSet, true ); 4975 } 4976 } 4977 }, 4978 4979 "": function(checkSet, part, isXML){ 4980 var nodeCheck, 4981 doneName = done++, 4982 checkFn = dirCheck; 4983 4984 if ( typeof part === "string" && !rNonWord.test( part ) ) { 4985 part = part.toLowerCase(); 4986 nodeCheck = part; 4987 checkFn = dirNodeCheck; 4988 } 4989 4990 checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); 4991 }, 4992 4993 "~": function( checkSet, part, isXML ) { 4994 var nodeCheck, 4995 doneName = done++, 4996 checkFn = dirCheck; 4997 4998 if ( typeof part === "string" && !rNonWord.test( part ) ) { 4999 part = part.toLowerCase(); 5000 nodeCheck = part; 5001 checkFn = dirNodeCheck; 5002 } 5003 5004 checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); 5005 } 5006 }, 5007 5008 find: { 5009 ID: function( match, context, isXML ) { 5010 if ( typeof context.getElementById !== "undefined" && !isXML ) { 5011 var m = context.getElementById(match[1]); 5012 // Check parentNode to catch when Blackberry 4.6 returns 5013 // nodes that are no longer in the document #6963 5014 return m && m.parentNode ? [m] : []; 5015 } 5016 }, 5017 5018 NAME: function( match, context ) { 5019 if ( typeof context.getElementsByName !== "undefined" ) { 5020 var ret = [], 5021 results = context.getElementsByName( match[1] ); 5022 5023 for ( var i = 0, l = results.length; i < l; i++ ) { 5024 if ( results[i].getAttribute("name") === match[1] ) { 5025 ret.push( results[i] ); 5026 } 5027 } 5028 5029 return ret.length === 0 ? null : ret; 5030 } 5031 }, 5032 5033 TAG: function( match, context ) { 5034 if ( typeof context.getElementsByTagName !== "undefined" ) { 5035 return context.getElementsByTagName( match[1] ); 5036 } 5037 } 5038 }, 5039 preFilter: { 5040 CLASS: function( match, curLoop, inplace, result, not, isXML ) { 5041 match = " " + match[1].replace( rBackslash, "" ) + " "; 5042 5043 if ( isXML ) { 5044 return match; 5045 } 5046 5047 for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { 5048 if ( elem ) { 5049 if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { 5050 if ( !inplace ) { 5051 result.push( elem ); 5052 } 5053 5054 } else if ( inplace ) { 5055 curLoop[i] = false; 5056 } 5057 } 5058 } 5059 5060 return false; 5061 }, 5062 5063 ID: function( match ) { 5064 return match[1].replace( rBackslash, "" ); 5065 }, 5066 5067 TAG: function( match, curLoop ) { 5068 return match[1].replace( rBackslash, "" ).toLowerCase(); 5069 }, 5070 5071 CHILD: function( match ) { 5072 if ( match[1] === "nth" ) { 5073 if ( !match[2] ) { 5074 Sizzle.error( match[0] ); 5075 } 5076 5077 match[2] = match[2].replace(/^\+|\s*/g, ''); 5078 5079 // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' 5080 var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( 5081 match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || 5082 !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); 5083 5084 // calculate the numbers (first)n+(last) including if they are negative 5085 match[2] = (test[1] + (test[2] || 1)) - 0; 5086 match[3] = test[3] - 0; 5087 } 5088 else if ( match[2] ) { 5089 Sizzle.error( match[0] ); 5090 } 5091 5092 // TODO: Move to normal caching system 5093 match[0] = done++; 5094 5095 return match; 5096 }, 5097 5098 ATTR: function( match, curLoop, inplace, result, not, isXML ) { 5099 var name = match[1] = match[1].replace( rBackslash, "" ); 5100 5101 if ( !isXML && Expr.attrMap[name] ) { 5102 match[1] = Expr.attrMap[name]; 5103 } 5104 5105 // Handle if an un-quoted value was used 5106 match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); 5107 5108 if ( match[2] === "~=" ) { 5109 match[4] = " " + match[4] + " "; 5110 } 5111 5112 return match; 5113 }, 5114 5115 PSEUDO: function( match, curLoop, inplace, result, not ) { 5116 if ( match[1] === "not" ) { 5117 // If we're dealing with a complex expression, or a simple one 5118 if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { 5119 match[3] = Sizzle(match[3], null, null, curLoop); 5120 5121 } else { 5122 var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); 5123 5124 if ( !inplace ) { 5125 result.push.apply( result, ret ); 5126 } 5127 5128 return false; 5129 } 5130 5131 } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { 5132 return true; 5133 } 5134 5135 return match; 5136 }, 5137 5138 POS: function( match ) { 5139 match.unshift( true ); 5140 5141 return match; 5142 } 5143 }, 5144 5145 filters: { 5146 enabled: function( elem ) { 5147 return elem.disabled === false && elem.type !== "hidden"; 5148 }, 5149 5150 disabled: function( elem ) { 5151 return elem.disabled === true; 5152 }, 5153 5154 checked: function( elem ) { 5155 return elem.checked === true; 5156 }, 5157 5158 selected: function( elem ) { 5159 // Accessing this property makes selected-by-default 5160 // options in Safari work properly 5161 if ( elem.parentNode ) { 5162 elem.parentNode.selectedIndex; 5163 } 5164 5165 return elem.selected === true; 5166 }, 5167 5168 parent: function( elem ) { 5169 return !!elem.firstChild; 5170 }, 5171 5172 empty: function( elem ) { 5173 return !elem.firstChild; 5174 }, 5175 5176 has: function( elem, i, match ) { 5177 return !!Sizzle( match[3], elem ).length; 5178 }, 5179 5180 header: function( elem ) { 5181 return (/h\d/i).test( elem.nodeName ); 5182 }, 5183 5184 text: function( elem ) { 5185 var attr = elem.getAttribute( "type" ), type = elem.type; 5186 // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) 5187 // use getAttribute instead to test this case 5188 return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); 5189 }, 5190 5191 radio: function( elem ) { 5192 return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; 5193 }, 5194 5195 checkbox: function( elem ) { 5196 return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; 5197 }, 5198 5199 file: function( elem ) { 5200 return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; 5201 }, 5202 5203 password: function( elem ) { 5204 return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; 5205 }, 5206 5207 submit: function( elem ) { 5208 var name = elem.nodeName.toLowerCase(); 5209 return (name === "input" || name === "button") && "submit" === elem.type; 5210 }, 5211 5212 image: function( elem ) { 5213 return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; 5214 }, 5215 5216 reset: function( elem ) { 5217 var name = elem.nodeName.toLowerCase(); 5218 return (name === "input" || name === "button") && "reset" === elem.type; 5219 }, 5220 5221 button: function( elem ) { 5222 var name = elem.nodeName.toLowerCase(); 5223 return name === "input" && "button" === elem.type || name === "button"; 5224 }, 5225 5226 input: function( elem ) { 5227 return (/input|select|textarea|button/i).test( elem.nodeName ); 5228 }, 5229 5230 focus: function( elem ) { 5231 return elem === elem.ownerDocument.activeElement; 5232 } 5233 }, 5234 setFilters: { 5235 first: function( elem, i ) { 5236 return i === 0; 5237 }, 5238 5239 last: function( elem, i, match, array ) { 5240 return i === array.length - 1; 5241 }, 5242 5243 even: function( elem, i ) { 5244 return i % 2 === 0; 5245 }, 5246 5247 odd: function( elem, i ) { 5248 return i % 2 === 1; 5249 }, 5250 5251 lt: function( elem, i, match ) { 5252 return i < match[3] - 0; 5253 }, 5254 5255 gt: function( elem, i, match ) { 5256 return i > match[3] - 0; 5257 }, 5258 5259 nth: function( elem, i, match ) { 5260 return match[3] - 0 === i; 5261 }, 5262 5263 eq: function( elem, i, match ) { 5264 return match[3] - 0 === i; 5265 } 5266 }, 5267 filter: { 5268 PSEUDO: function( elem, match, i, array ) { 5269 var name = match[1], 5270 filter = Expr.filters[ name ]; 5271 5272 if ( filter ) { 5273 return filter( elem, i, match, array ); 5274 5275 } else if ( name === "contains" ) { 5276 return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; 5277 5278 } else if ( name === "not" ) { 5279 var not = match[3]; 5280 5281 for ( var j = 0, l = not.length; j < l; j++ ) { 5282 if ( not[j] === elem ) { 5283 return false; 5284 } 5285 } 5286 5287 return true; 5288 5289 } else { 5290 Sizzle.error( name ); 5291 } 5292 }, 5293 5294 CHILD: function( elem, match ) { 5295 var first, last, 5296 doneName, parent, cache, 5297 count, diff, 5298 type = match[1], 5299 node = elem; 5300 5301 switch ( type ) { 5302 case "only": 5303 case "first": 5304 while ( (node = node.previousSibling) ) { 5305 if ( node.nodeType === 1 ) { 5306 return false; 5307 } 5308 } 5309 5310 if ( type === "first" ) { 5311 return true; 5312 } 5313 5314 node = elem; 5315 5316 case "last": 5317 while ( (node = node.nextSibling) ) { 5318 if ( node.nodeType === 1 ) { 5319 return false; 5320 } 5321 } 5322 5323 return true; 5324 5325 case "nth": 5326 first = match[2]; 5327 last = match[3]; 5328 5329 if ( first === 1 && last === 0 ) { 5330 return true; 5331 } 5332 5333 doneName = match[0]; 5334 parent = elem.parentNode; 5335 5336 if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { 5337 count = 0; 5338 5339 for ( node = parent.firstChild; node; node = node.nextSibling ) { 5340 if ( node.nodeType === 1 ) { 5341 node.nodeIndex = ++count; 5342 } 5343 } 5344 5345 parent[ expando ] = doneName; 5346 } 5347 5348 diff = elem.nodeIndex - last; 5349 5350 if ( first === 0 ) { 5351 return diff === 0; 5352 5353 } else { 5354 return ( diff % first === 0 && diff / first >= 0 ); 5355 } 5356 } 5357 }, 5358 5359 ID: function( elem, match ) { 5360 return elem.nodeType === 1 && elem.getAttribute("id") === match; 5361 }, 5362 5363 TAG: function( elem, match ) { 5364 return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; 5365 }, 5366 5367 CLASS: function( elem, match ) { 5368 return (" " + (elem.className || elem.getAttribute("class")) + " ") 5369 .indexOf( match ) > -1; 5370 }, 5371 5372 ATTR: function( elem, match ) { 5373 var name = match[1], 5374 result = Sizzle.attr ? 5375 Sizzle.attr( elem, name ) : 5376 Expr.attrHandle[ name ] ? 5377 Expr.attrHandle[ name ]( elem ) : 5378 elem[ name ] != null ? 5379 elem[ name ] : 5380 elem.getAttribute( name ), 5381 value = result + "", 5382 type = match[2], 5383 check = match[4]; 5384 5385 return result == null ? 5386 type === "!=" : 5387 !type && Sizzle.attr ? 5388 result != null : 5389 type === "=" ? 5390 value === check : 5391 type === "*=" ? 5392 value.indexOf(check) >= 0 : 5393 type === "~=" ? 5394 (" " + value + " ").indexOf(check) >= 0 : 5395 !check ? 5396 value && result !== false : 5397 type === "!=" ? 5398 value !== check : 5399 type === "^=" ? 5400 value.indexOf(check) === 0 : 5401 type === "$=" ? 5402 value.substr(value.length - check.length) === check : 5403 type === "|=" ? 5404 value === check || value.substr(0, check.length + 1) === check + "-" : 5405 false; 5406 }, 5407 5408 POS: function( elem, match, i, array ) { 5409 var name = match[2], 5410 filter = Expr.setFilters[ name ]; 5411 5412 if ( filter ) { 5413 return filter( elem, i, match, array ); 5414 } 5415 } 5416 } 5417}; 5418 5419var origPOS = Expr.match.POS, 5420 fescape = function(all, num){ 5421 return "\\" + (num - 0 + 1); 5422 }; 5423 5424for ( var type in Expr.match ) { 5425 Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); 5426 Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); 5427} 5428 5429var makeArray = function( array, results ) { 5430 array = Array.prototype.slice.call( array, 0 ); 5431 5432 if ( results ) { 5433 results.push.apply( results, array ); 5434 return results; 5435 } 5436 5437 return array; 5438}; 5439 5440// Perform a simple check to determine if the browser is capable of 5441// converting a NodeList to an array using builtin methods. 5442// Also verifies that the returned array holds DOM nodes 5443// (which is not the case in the Blackberry browser) 5444try { 5445 Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; 5446 5447// Provide a fallback method if it does not work 5448} catch( e ) { 5449 makeArray = function( array, results ) { 5450 var i = 0, 5451 ret = results || []; 5452 5453 if ( toString.call(array) === "[object Array]" ) { 5454 Array.prototype.push.apply( ret, array ); 5455 5456 } else { 5457 if ( typeof array.length === "number" ) { 5458 for ( var l = array.length; i < l; i++ ) { 5459 ret.push( array[i] ); 5460 } 5461 5462 } else { 5463 for ( ; array[i]; i++ ) { 5464 ret.push( array[i] ); 5465 } 5466 } 5467 } 5468 5469 return ret; 5470 }; 5471} 5472 5473var sortOrder, siblingCheck; 5474 5475if ( document.documentElement.compareDocumentPosition ) { 5476 sortOrder = function( a, b ) { 5477 if ( a === b ) { 5478 hasDuplicate = true; 5479 return 0; 5480 } 5481 5482 if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { 5483 return a.compareDocumentPosition ? -1 : 1; 5484 } 5485 5486 return a.compareDocumentPosition(b) & 4 ? -1 : 1; 5487 }; 5488 5489} else { 5490 sortOrder = function( a, b ) { 5491 // The nodes are identical, we can exit early 5492 if ( a === b ) { 5493 hasDuplicate = true; 5494 return 0; 5495 5496 // Fallback to using sourceIndex (in IE) if it's available on both nodes 5497 } else if ( a.sourceIndex && b.sourceIndex ) { 5498 return a.sourceIndex - b.sourceIndex; 5499 } 5500 5501 var al, bl, 5502 ap = [], 5503 bp = [], 5504 aup = a.parentNode, 5505 bup = b.parentNode, 5506 cur = aup; 5507 5508 // If the nodes are siblings (or identical) we can do a quick check 5509 if ( aup === bup ) { 5510 return siblingCheck( a, b ); 5511 5512 // If no parents were found then the nodes are disconnected 5513 } else if ( !aup ) { 5514 return -1; 5515 5516 } else if ( !bup ) { 5517 return 1; 5518 } 5519 5520 // Otherwise they're somewhere else in the tree so we need 5521 // to build up a full list of the parentNodes for comparison 5522 while ( cur ) { 5523 ap.unshift( cur ); 5524 cur = cur.parentNode; 5525 } 5526 5527 cur = bup; 5528 5529 while ( cur ) { 5530 bp.unshift( cur ); 5531 cur = cur.parentNode; 5532 } 5533 5534 al = ap.length; 5535 bl = bp.length; 5536 5537 // Start walking down the tree looking for a discrepancy 5538 for ( var i = 0; i < al && i < bl; i++ ) { 5539 if ( ap[i] !== bp[i] ) { 5540 return siblingCheck( ap[i], bp[i] ); 5541 } 5542 } 5543 5544 // We ended someplace up the tree so do a sibling check 5545 return i === al ? 5546 siblingCheck( a, bp[i], -1 ) : 5547 siblingCheck( ap[i], b, 1 ); 5548 }; 5549 5550 siblingCheck = function( a, b, ret ) { 5551 if ( a === b ) { 5552 return ret; 5553 } 5554 5555 var cur = a.nextSibling; 5556 5557 while ( cur ) { 5558 if ( cur === b ) { 5559 return -1; 5560 } 5561 5562 cur = cur.nextSibling; 5563 } 5564 5565 return 1; 5566 }; 5567} 5568 5569// Check to see if the browser returns elements by name when 5570// querying by getElementById (and provide a workaround) 5571(function(){ 5572 // We're going to inject a fake input element with a specified name 5573 var form = document.createElement("div"), 5574 id = "script" + (new Date()).getTime(), 5575 root = document.documentElement; 5576 5577 form.innerHTML = "<a name='" + id + "'/>"; 5578 5579 // Inject it into the root element, check its status, and remove it quickly 5580 root.insertBefore( form, root.firstChild ); 5581 5582 // The workaround has to do additional checks after a getElementById 5583 // Which slows things down for other browsers (hence the branching) 5584 if ( document.getElementById( id ) ) { 5585 Expr.find.ID = function( match, context, isXML ) { 5586 if ( typeof context.getElementById !== "undefined" && !isXML ) { 5587 var m = context.getElementById(match[1]); 5588 5589 return m ? 5590 m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? 5591 [m] : 5592 undefined : 5593 []; 5594 } 5595 }; 5596 5597 Expr.filter.ID = function( elem, match ) { 5598 var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); 5599 5600 return elem.nodeType === 1 && node && node.nodeValue === match; 5601 }; 5602 } 5603 5604 root.removeChild( form ); 5605 5606 // release memory in IE 5607 root = form = null; 5608})(); 5609 5610(function(){ 5611 // Check to see if the browser returns only elements 5612 // when doing getElementsByTagName("*") 5613 5614 // Create a fake element 5615 var div = document.createElement("div"); 5616 div.appendChild( document.createComment("") ); 5617 5618 // Make sure no comments are found 5619 if ( div.getElementsByTagName("*").length > 0 ) { 5620 Expr.find.TAG = function( match, context ) { 5621 var results = context.getElementsByTagName( match[1] ); 5622 5623 // Filter out possible comments 5624 if ( match[1] === "*" ) { 5625 var tmp = []; 5626 5627 for ( var i = 0; results[i]; i++ ) { 5628 if ( results[i].nodeType === 1 ) { 5629 tmp.push( results[i] ); 5630 } 5631 } 5632 5633 results = tmp; 5634 } 5635 5636 return results; 5637 }; 5638 } 5639 5640 // Check to see if an attribute returns normalized href attributes 5641 div.innerHTML = "<a href='#'></a>"; 5642 5643 if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && 5644 div.firstChild.getAttribute("href") !== "#" ) { 5645 5646 Expr.attrHandle.href = function( elem ) { 5647 return elem.getAttribute( "href", 2 ); 5648 }; 5649 } 5650 5651 // release memory in IE 5652 div = null; 5653})(); 5654 5655if ( document.querySelectorAll ) { 5656 (function(){ 5657 var oldSizzle = Sizzle, 5658 div = document.createElement("div"), 5659 id = "__sizzle__"; 5660 5661 div.innerHTML = "<p class='TEST'></p>"; 5662 5663 // Safari can't handle uppercase or unicode characters when 5664 // in quirks mode. 5665 if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { 5666 return; 5667 } 5668 5669 Sizzle = function( query, context, extra, seed ) { 5670 context = context || document; 5671 5672 // Only use querySelectorAll on non-XML documents 5673 // (ID selectors don't work in non-HTML documents) 5674 if ( !seed && !Sizzle.isXML(context) ) { 5675 // See if we find a selector to speed up 5676 var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); 5677 5678 if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { 5679 // Speed-up: Sizzle("TAG") 5680 if ( match[1] ) { 5681 return makeArray( context.getElementsByTagName( query ), extra ); 5682 5683 // Speed-up: Sizzle(".CLASS") 5684 } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { 5685 return makeArray( context.getElementsByClassName( match[2] ), extra ); 5686 } 5687 } 5688 5689 if ( context.nodeType === 9 ) { 5690 // Speed-up: Sizzle("body") 5691 // The body element only exists once, optimize finding it 5692 if ( query === "body" && context.body ) { 5693 return makeArray( [ context.body ], extra ); 5694 5695 // Speed-up: Sizzle("#ID") 5696 } else if ( match && match[3] ) { 5697 var elem = context.getElementById( match[3] ); 5698 5699 // Check parentNode to catch when Blackberry 4.6 returns 5700 // nodes that are no longer in the document #6963 5701 if ( elem && elem.parentNode ) { 5702 // Handle the case where IE and Opera return items 5703 // by name instead of ID 5704 if ( elem.id === match[3] ) { 5705 return makeArray( [ elem ], extra ); 5706 } 5707 5708 } else { 5709 return makeArray( [], extra ); 5710 } 5711 } 5712 5713 try { 5714 return makeArray( context.querySelectorAll(query), extra ); 5715 } catch(qsaError) {} 5716 5717 // qSA works strangely on Element-rooted queries 5718 // We can work around this by specifying an extra ID on the root 5719 // and working up from there (Thanks to Andrew Dupont for the technique) 5720 // IE 8 doesn't work on object elements 5721 } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { 5722 var oldContext = context, 5723 old = context.getAttribute( "id" ), 5724 nid = old || id, 5725 hasParent = context.parentNode, 5726 relativeHierarchySelector = /^\s*[+~]/.test( query ); 5727 5728 if ( !old ) { 5729 context.setAttribute( "id", nid ); 5730 } else { 5731 nid = nid.replace( /'/g, "\\$&" ); 5732 } 5733 if ( relativeHierarchySelector && hasParent ) { 5734 context = context.parentNode; 5735 } 5736 5737 try { 5738 if ( !relativeHierarchySelector || hasParent ) { 5739 return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); 5740 } 5741 5742 } catch(pseudoError) { 5743 } finally { 5744 if ( !old ) { 5745 oldContext.removeAttribute( "id" ); 5746 } 5747 } 5748 } 5749 } 5750 5751 return oldSizzle(query, context, extra, seed); 5752 }; 5753 5754 for ( var prop in oldSizzle ) { 5755 Sizzle[ prop ] = oldSizzle[ prop ]; 5756 } 5757 5758 // release memory in IE 5759 div = null; 5760 })(); 5761} 5762 5763(function(){ 5764 var html = document.documentElement, 5765 matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; 5766 5767 if ( matches ) { 5768 // Check to see if it's possible to do matchesSelector 5769 // on a disconnected node (IE 9 fails this) 5770 var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), 5771 pseudoWorks = false; 5772 5773 try { 5774 // This should fail with an exception 5775 // Gecko does not error, returns false instead 5776 matches.call( document.documentElement, "[test!='']:sizzle" ); 5777 5778 } catch( pseudoError ) { 5779 pseudoWorks = true; 5780 } 5781 5782 Sizzle.matchesSelector = function( node, expr ) { 5783 // Make sure that attribute selectors are quoted 5784 expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); 5785 5786 if ( !Sizzle.isXML( node ) ) { 5787 try { 5788 if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { 5789 var ret = matches.call( node, expr ); 5790 5791 // IE 9's matchesSelector returns false on disconnected nodes 5792 if ( ret || !disconnectedMatch || 5793 // As well, disconnected nodes are said to be in a document 5794 // fragment in IE 9, so check for that 5795 node.document && node.document.nodeType !== 11 ) { 5796 return ret; 5797 } 5798 } 5799 } catch(e) {} 5800 } 5801 5802 return Sizzle(expr, null, null, [node]).length > 0; 5803 }; 5804 } 5805})(); 5806 5807(function(){ 5808 var div = document.createElement("div"); 5809 5810 div.innerHTML = "<div class='test e'></div><div class='test'></div>"; 5811 5812 // Opera can't find a second classname (in 9.6) 5813 // Also, make sure that getElementsByClassName actually exists 5814 if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { 5815 return; 5816 } 5817 5818 // Safari caches class attributes, doesn't catch changes (in 3.2) 5819 div.lastChild.className = "e"; 5820 5821 if ( div.getElementsByClassName("e").length === 1 ) { 5822 return; 5823 } 5824 5825 Expr.order.splice(1, 0, "CLASS"); 5826 Expr.find.CLASS = function( match, context, isXML ) { 5827 if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { 5828 return context.getElementsByClassName(match[1]); 5829 } 5830 }; 5831 5832 // release memory in IE 5833 div = null; 5834})(); 5835 5836function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { 5837 for ( var i = 0, l = checkSet.length; i < l; i++ ) { 5838 var elem = checkSet[i]; 5839 5840 if ( elem ) { 5841 var match = false; 5842 5843 elem = elem[dir]; 5844 5845 while ( elem ) { 5846 if ( elem[ expando ] === doneName ) { 5847 match = checkSet[elem.sizset]; 5848 break; 5849 } 5850 5851 if ( elem.nodeType === 1 && !isXML ){ 5852 elem[ expando ] = doneName; 5853 elem.sizset = i; 5854 } 5855 5856 if ( elem.nodeName.toLowerCase() === cur ) { 5857 match = elem; 5858 break; 5859 } 5860 5861 elem = elem[dir]; 5862 } 5863 5864 checkSet[i] = match; 5865 } 5866 } 5867} 5868 5869function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { 5870 for ( var i = 0, l = checkSet.length; i < l; i++ ) { 5871 var elem = checkSet[i]; 5872 5873 if ( elem ) { 5874 var match = false; 5875 5876 elem = elem[dir]; 5877 5878 while ( elem ) { 5879 if ( elem[ expando ] === doneName ) { 5880 match = checkSet[elem.sizset]; 5881 break; 5882 } 5883 5884 if ( elem.nodeType === 1 ) { 5885 if ( !isXML ) { 5886 elem[ expando ] = doneName; 5887 elem.sizset = i; 5888 } 5889 5890 if ( typeof cur !== "string" ) { 5891 if ( elem === cur ) { 5892 match = true; 5893 break; 5894 } 5895 5896 } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { 5897 match = elem; 5898 break; 5899 } 5900 } 5901 5902 elem = elem[dir]; 5903 } 5904 5905 checkSet[i] = match; 5906 } 5907 } 5908} 5909 5910if ( document.documentElement.contains ) { 5911 Sizzle.contains = function( a, b ) { 5912 return a !== b && (a.contains ? a.contains(b) : true); 5913 }; 5914 5915} else if ( document.documentElement.compareDocumentPosition ) { 5916 Sizzle.contains = function( a, b ) { 5917 return !!(a.compareDocumentPosition(b) & 16); 5918 }; 5919 5920} else { 5921 Sizzle.contains = function() { 5922 return false; 5923 }; 5924} 5925 5926Sizzle.isXML = function( elem ) { 5927 // documentElement is verified for cases where it doesn't yet exist 5928 // (such as loading iframes in IE - #4833) 5929 var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; 5930 5931 return documentElement ? documentElement.nodeName !== "HTML" : false; 5932}; 5933 5934var posProcess = function( selector, context, seed ) { 5935 var match, 5936 tmpSet = [], 5937 later = "", 5938 root = context.nodeType ? [context] : context; 5939 5940 // Position selectors must be done after the filter 5941 // And so must :not(positional) so we move all PSEUDOs to the end 5942 while ( (match = Expr.match.PSEUDO.exec( selector )) ) { 5943 later += match[0]; 5944 selector = selector.replace( Expr.match.PSEUDO, "" ); 5945 } 5946 5947 selector = Expr.relative[selector] ? selector + "*" : selector; 5948 5949 for ( var i = 0, l = root.length; i < l; i++ ) { 5950 Sizzle( selector, root[i], tmpSet, seed ); 5951 } 5952 5953 return Sizzle.filter( later, tmpSet ); 5954}; 5955 5956// EXPOSE 5957// Override sizzle attribute retrieval 5958Sizzle.attr = jQuery.attr; 5959Sizzle.selectors.attrMap = {}; 5960jQuery.find = Sizzle; 5961jQuery.expr = Sizzle.selectors; 5962jQuery.expr[":"] = jQuery.expr.filters; 5963jQuery.unique = Sizzle.uniqueSort; 5964jQuery.text = Sizzle.getText; 5965jQuery.isXMLDoc = Sizzle.isXML; 5966jQuery.contains = Sizzle.contains; 5967 5968 5969})(); 5970 5971 5972var runtil = /Until$/, 5973 rparentsprev = /^(?:parents|prevUntil|prevAll)/, 5974 // Note: This RegExp should be improved, or likely pulled from Sizzle 5975 rmultiselector = /,/, 5976 isSimple = /^.[^:#\[\.,]*$/, 5977 slice = Array.prototype.slice, 5978 POS = jQuery.expr.match.POS, 5979 // methods guaranteed to produce a unique set when starting from a unique set 5980 guaranteedUnique = { 5981 children: true, 5982 contents: true, 5983 next: true, 5984 prev: true 5985 }; 5986 5987jQuery.fn.extend({ 5988 find: function( selector ) { 5989 var self = this, 5990 i, l; 5991 5992 if ( typeof selector !== "string" ) { 5993 return jQuery( selector ).filter(function() { 5994 for ( i = 0, l = self.length; i < l; i++ ) { 5995 if ( jQuery.contains( self[ i ], this ) ) { 5996 return true; 5997 } 5998 } 5999 }); 6000 } 6001 6002 var ret = this.pushStack( "", "find", selector ), 6003 length, n, r; 6004 6005 for ( i = 0, l = this.length; i < l; i++ ) { 6006 length = ret.length; 6007 jQuery.find( selector, this[i], ret ); 6008 6009 if ( i > 0 ) { 6010 // Make sure that the results are unique 6011 for ( n = length; n < ret.length; n++ ) { 6012 for ( r = 0; r < length; r++ ) { 6013 if ( ret[r] === ret[n] ) { 6014 ret.splice(n--, 1); 6015 break; 6016 } 6017 } 6018 } 6019 } 6020 } 6021 6022 return ret; 6023 }, 6024 6025 has: function( target ) { 6026 var targets = jQuery( target ); 6027 return this.filter(function() { 6028 for ( var i = 0, l = targets.length; i < l; i++ ) { 6029 if ( jQuery.contains( this, targets[i] ) ) { 6030 return true; 6031 } 6032 } 6033 }); 6034 }, 6035 6036 not: function( selector ) { 6037 return this.pushStack( winnow(this, selector, false), "not", selector); 6038 }, 6039 6040 filter: function( selector ) { 6041 return this.pushStack( winnow(this, selector, true), "filter", selector ); 6042 }, 6043 6044 is: function( selector ) { 6045 return !!selector && ( 6046 typeof selector === "string" ? 6047 // If this is a positional selector, check membership in the returned set 6048 // so $("p:first").is("p:last") won't return true for a doc with two "p". 6049 POS.test( selector ) ? 6050 jQuery( selector, this.context ).index( this[0] ) >= 0 : 6051 jQuery.filter( selector, this ).length > 0 : 6052 this.filter( selector ).length > 0 ); 6053 }, 6054 6055 closest: function( selectors, context ) { 6056 var ret = [], i, l, cur = this[0]; 6057 6058 // Array (deprecated as of jQuery 1.7) 6059 if ( jQuery.isArray( selectors ) ) { 6060 var level = 1; 6061 6062 while ( cur && cur.ownerDocument && cur !== context ) { 6063 for ( i = 0; i < selectors.length; i++ ) { 6064 6065 if ( jQuery( cur ).is( selectors[ i ] ) ) { 6066 ret.push({ selector: selectors[ i ], elem: cur, level: level }); 6067 } 6068 } 6069 6070 cur = cur.parentNode; 6071 level++; 6072 } 6073 6074 return ret; 6075 } 6076 6077 // String 6078 var pos = POS.test( selectors ) || typeof selectors !== "string" ? 6079 jQuery( selectors, context || this.context ) : 6080 0; 6081 6082 for ( i = 0, l = this.length; i < l; i++ ) { 6083 cur = this[i]; 6084 6085 while ( cur ) { 6086 if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { 6087 ret.push( cur ); 6088 break; 6089 6090 } else { 6091 cur = cur.parentNode; 6092 if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { 6093 break; 6094 } 6095 } 6096 } 6097 } 6098 6099 ret = ret.length > 1 ? jQuery.unique( ret ) : ret; 6100 6101 return this.pushStack( ret, "closest", selectors ); 6102 }, 6103 6104 // Determine the position of an element within 6105 // the matched set of elements 6106 index: function( elem ) { 6107 6108 // No argument, return index in parent 6109 if ( !elem ) { 6110 return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; 6111 } 6112 6113 // index in selector 6114 if ( typeof elem === "string" ) { 6115 return jQuery.inArray( this[0], jQuery( elem ) ); 6116 } 6117 6118 // Locate the position of the desired element 6119 return jQuery.inArray( 6120 // If it receives a jQuery object, the first element is used 6121 elem.jquery ? elem[0] : elem, this ); 6122 }, 6123 6124 add: function( selector, context ) { 6125 var set = typeof selector === "string" ? 6126 jQuery( selector, context ) : 6127 jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), 6128 all = jQuery.merge( this.get(), set ); 6129 6130 return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? 6131 all : 6132 jQuery.unique( all ) ); 6133 }, 6134 6135 andSelf: function() { 6136 return this.add( this.prevObject ); 6137 } 6138}); 6139 6140// A painfully simple check to see if an element is disconnected 6141// from a document (should be improved, where feasible). 6142function isDisconnected( node ) { 6143 return !node || !node.parentNode || node.parentNode.nodeType === 11; 6144} 6145 6146jQuery.each({ 6147 parent: function( elem ) { 6148 var parent = elem.parentNode; 6149 return parent && parent.nodeType !== 11 ? parent : null; 6150 }, 6151 parents: function( elem ) { 6152 return jQuery.dir( elem, "parentNode" ); 6153 }, 6154 parentsUntil: function( elem, i, until ) { 6155 return jQuery.dir( elem, "parentNode", until ); 6156 }, 6157 next: function( elem ) { 6158 return jQuery.nth( elem, 2, "nextSibling" ); 6159 }, 6160 prev: function( elem ) { 6161 return jQuery.nth( elem, 2, "previousSibling" ); 6162 }, 6163 nextAll: function( elem ) { 6164 return jQuery.dir( elem, "nextSibling" ); 6165 }, 6166 prevAll: function( elem ) { 6167 return jQuery.dir( elem, "previousSibling" ); 6168 }, 6169 nextUntil: function( elem, i, until ) { 6170 return jQuery.dir( elem, "nextSibling", until ); 6171 }, 6172 prevUntil: function( elem, i, until ) { 6173 return jQuery.dir( elem, "previousSibling", until ); 6174 }, 6175 siblings: function( elem ) { 6176 return jQuery.sibling( elem.parentNode.firstChild, elem ); 6177 }, 6178 children: function( elem ) { 6179 return jQuery.sibling( elem.firstChild ); 6180 }, 6181 contents: function( elem ) { 6182 return jQuery.nodeName( elem, "iframe" ) ? 6183 elem.contentDocument || elem.contentWindow.document : 6184 jQuery.makeArray( elem.childNodes ); 6185 } 6186}, function( name, fn ) { 6187 jQuery.fn[ name ] = function( until, selector ) { 6188 var ret = jQuery.map( this, fn, until ), 6189 // The variable 'args' was introduced in 6190 // https://github.com/jquery/jquery/commit/52a0238 6191 // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. 6192 // http://code.google.com/p/v8/issues/detail?id=1050 6193 args = slice.call(arguments); 6194 6195 if ( !runtil.test( name ) ) { 6196 selector = until; 6197 } 6198 6199 if ( selector && typeof selector === "string" ) { 6200 ret = jQuery.filter( selector, ret ); 6201 } 6202 6203 ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; 6204 6205 if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { 6206 ret = ret.reverse(); 6207 } 6208 6209 return this.pushStack( ret, name, args.join(",") ); 6210 }; 6211}); 6212 6213jQuery.extend({ 6214 filter: function( expr, elems, not ) { 6215 if ( not ) { 6216 expr = ":not(" + expr + ")"; 6217 } 6218 6219 return elems.length === 1 ? 6220 jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : 6221 jQuery.find.matches(expr, elems); 6222 }, 6223 6224 dir: function( elem, dir, until ) { 6225 var matched = [], 6226 cur = elem[ dir ]; 6227 6228 while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { 6229 if ( cur.nodeType === 1 ) { 6230 matched.push( cur ); 6231 } 6232 cur = cur[dir]; 6233 } 6234 return matched; 6235 }, 6236 6237 nth: function( cur, result, dir, elem ) { 6238 result = result || 1; 6239 var num = 0; 6240 6241 for ( ; cur; cur = cur[dir] ) { 6242 if ( cur.nodeType === 1 && ++num === result ) { 6243 break; 6244 } 6245 } 6246 6247 return cur; 6248 }, 6249 6250 sibling: function( n, elem ) { 6251 var r = []; 6252 6253 for ( ; n; n = n.nextSibling ) { 6254 if ( n.nodeType === 1 && n !== elem ) { 6255 r.push( n ); 6256 } 6257 } 6258 6259 return r; 6260 } 6261}); 6262 6263// Implement the identical functionality for filter and not 6264function winnow( elements, qualifier, keep ) { 6265 6266 // Can't pass null or undefined to indexOf in Firefox 4 6267 // Set to 0 to skip string check 6268 qualifier = qualifier || 0; 6269 6270 if ( jQuery.isFunction( qualifier ) ) { 6271 return jQuery.grep(elements, function( elem, i ) { 6272 var retVal = !!qualifier.call( elem, i, elem ); 6273 return retVal === keep; 6274 }); 6275 6276 } else if ( qualifier.nodeType ) { 6277 return jQuery.grep(elements, function( elem, i ) { 6278 return ( elem === qualifier ) === keep; 6279 }); 6280 6281 } else if ( typeof qualifier === "string" ) { 6282 var filtered = jQuery.grep(elements, function( elem ) { 6283 return elem.nodeType === 1; 6284 }); 6285 6286 if ( isSimple.test( qualifier ) ) { 6287 return jQuery.filter(qualifier, filtered, !keep); 6288 } else { 6289 qualifier = jQuery.filter( qualifier, filtered ); 6290 } 6291 } 6292 6293 return jQuery.grep(elements, function( elem, i ) { 6294 return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; 6295 }); 6296} 6297 6298 6299 6300 6301function createSafeFragment( document ) { 6302 var list = nodeNames.split( " " ), 6303 safeFrag = document.createDocumentFragment(); 6304 6305 if ( safeFrag.createElement ) { 6306 while ( list.length ) { 6307 safeFrag.createElement( 6308 list.pop() 6309 ); 6310 } 6311 } 6312 return safeFrag; 6313} 6314 6315var nodeNames = "abbr article aside audio canvas datalist details figcaption figure footer " + 6316 "header hgroup mark meter nav output progress section summary time video", 6317 rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, 6318 rleadingWhitespace = /^\s+/, 6319 rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, 6320 rtagName = /<([\w:]+)/, 6321 rtbody = /<tbody/i, 6322 rhtml = /<|&#?\w+;/, 6323 rnoInnerhtml = /<(?:script|style)/i, 6324 rnocache = /<(?:script|object|embed|option|style)/i, 6325 rnoshimcache = new RegExp("<(?:" + nodeNames.replace(" ", "|") + ")", "i"), 6326 // checked="checked" or checked 6327 rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, 6328 rscriptType = /\/(java|ecma)script/i, 6329 rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/, 6330 wrapMap = { 6331 option: [ 1, "<select multiple='multiple'>", "</select>" ], 6332 legend: [ 1, "<fieldset>", "</fieldset>" ], 6333 thead: [ 1, "<table>", "</table>" ], 6334 tr: [ 2, "<table><tbody>", "</tbody></table>" ], 6335 td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ], 6336 col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ], 6337 area: [ 1, "<map>", "</map>" ], 6338 _default: [ 0, "", "" ] 6339 }, 6340 safeFragment = createSafeFragment( document ); 6341 6342wrapMap.optgroup = wrapMap.option; 6343wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; 6344wrapMap.th = wrapMap.td; 6345 6346// IE can't serialize <link> and <script> tags normally 6347if ( !jQuery.support.htmlSerialize ) { 6348 wrapMap._default = [ 1, "div<div>", "</div>" ]; 6349} 6350 6351jQuery.fn.extend({ 6352 text: function( text ) { 6353 if ( jQuery.isFunction(text) ) { 6354 return this.each(function(i) { 6355 var self = jQuery( this ); 6356 6357 self.text( text.call(this, i, self.text()) ); 6358 }); 6359 } 6360 6361 if ( typeof text !== "object" && text !== undefined ) { 6362 return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) ); 6363 } 6364 6365 return jQuery.text( this ); 6366 }, 6367 6368 wrapAll: function( html ) { 6369 if ( jQuery.isFunction( html ) ) { 6370 return this.each(function(i) { 6371 jQuery(this).wrapAll( html.call(this, i) ); 6372 }); 6373 } 6374 6375 if ( this[0] ) { 6376 // The elements to wrap the target around 6377 var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); 6378 6379 if ( this[0].parentNode ) { 6380 wrap.insertBefore( this[0] ); 6381 } 6382 6383 wrap.map(function() { 6384 var elem = this; 6385 6386 while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { 6387 elem = elem.firstChild; 6388 } 6389 6390 return elem; 6391 }).append( this ); 6392 } 6393 6394 return this; 6395 }, 6396 6397 wrapInner: function( html ) { 6398 if ( jQuery.isFunction( html ) ) { 6399 return this.each(function(i) { 6400 jQuery(this).wrapInner( html.call(this, i) ); 6401 }); 6402 } 6403 6404 return this.each(function() { 6405 var self = jQuery( this ), 6406 contents = self.contents(); 6407 6408 if ( contents.length ) { 6409 contents.wrapAll( html ); 6410 6411 } else { 6412 self.append( html ); 6413 } 6414 }); 6415 }, 6416 6417 wrap: function( html ) { 6418 return this.each(function() { 6419 jQuery( this ).wrapAll( html ); 6420 }); 6421 }, 6422 6423 unwrap: function() { 6424 return this.parent().each(function() { 6425 if ( !jQuery.nodeName( this, "body" ) ) { 6426 jQuery( this ).replaceWith( this.childNodes ); 6427 } 6428 }).end(); 6429 }, 6430 6431 append: function() { 6432 return this.domManip(arguments, true, function( elem ) { 6433 if ( this.nodeType === 1 ) { 6434 this.appendChild( elem ); 6435 } 6436 }); 6437 }, 6438 6439 prepend: function() { 6440 return this.domManip(arguments, true, function( elem ) { 6441 if ( this.nodeType === 1 ) { 6442 this.insertBefore( elem, this.firstChild ); 6443 } 6444 }); 6445 }, 6446 6447 before: function() { 6448 if ( this[0] && this[0].parentNode ) { 6449 return this.domManip(arguments, false, function( elem ) { 6450 this.parentNode.insertBefore( elem, this ); 6451 }); 6452 } else if ( arguments.length ) { 6453 var set = jQuery(arguments[0]); 6454 set.push.apply( set, this.toArray() ); 6455 return this.pushStack( set, "before", arguments ); 6456 } 6457 }, 6458 6459 after: function() { 6460 if ( this[0] && this[0].parentNode ) { 6461 return this.domManip(arguments, false, function( elem ) { 6462 this.parentNode.insertBefore( elem, this.nextSibling ); 6463 }); 6464 } else if ( arguments.length ) { 6465 var set = this.pushStack( this, "after", arguments ); 6466 set.push.apply( set, jQuery(arguments[0]).toArray() ); 6467 return set; 6468 } 6469 }, 6470 6471 // keepData is for internal use only--do not document 6472 remove: function( selector, keepData ) { 6473 for ( var i = 0, elem; (elem = this[i]) != null; i++ ) { 6474 if ( !selector || jQuery.filter( selector, [ elem ] ).length ) { 6475 if ( !keepData && elem.nodeType === 1 ) { 6476 jQuery.cleanData( elem.getElementsByTagName("*") ); 6477 jQuery.cleanData( [ elem ] ); 6478 } 6479 6480 if ( elem.parentNode ) { 6481 elem.parentNode.removeChild( elem ); 6482 } 6483 } 6484 } 6485 6486 return this; 6487 }, 6488 6489 empty: function() { 6490 for ( var i = 0, elem; (elem = this[i]) != null; i++ ) { 6491 // Remove element nodes and prevent memory leaks 6492 if ( elem.nodeType === 1 ) { 6493 jQuery.cleanData( elem.getElementsByTagName("*") ); 6494 } 6495 6496 // Remove any remaining nodes 6497 while ( elem.firstChild ) { 6498 elem.removeChild( elem.firstChild ); 6499 } 6500 } 6501 6502 return this; 6503 }, 6504 6505 clone: function( dataAndEvents, deepDataAndEvents ) { 6506 dataAndEvents = dataAndEvents == null ? false : dataAndEvents; 6507 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; 6508 6509 return this.map( function () { 6510 return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); 6511 }); 6512 }, 6513 6514 html: function( value ) { 6515 if ( value === undefined ) { 6516 return this[0] && this[0].nodeType === 1 ? 6517 this[0].innerHTML.replace(rinlinejQuery, "") : 6518 null; 6519 6520 // See if we can take a shortcut and just use innerHTML 6521 } else if ( typeof value === "string" && !rnoInnerhtml.test( value ) && 6522 (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) && 6523 !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) { 6524 6525 value = value.replace(rxhtmlTag, "<$1></$2>"); 6526 6527 try { 6528 for ( var i = 0, l = this.length; i < l; i++ ) { 6529 // Remove element nodes and prevent memory leaks 6530 if ( this[i].nodeType === 1 ) { 6531 jQuery.cleanData( this[i].getElementsByTagName("*") ); 6532 this[i].innerHTML = value; 6533 } 6534 } 6535 6536 // If using innerHTML throws an exception, use the fallback method 6537 } catch(e) { 6538 this.empty().append( value ); 6539 } 6540 6541 } else if ( jQuery.isFunction( value ) ) { 6542 this.each(function(i){ 6543 var self = jQuery( this ); 6544 6545 self.html( value.call(this, i, self.html()) ); 6546 }); 6547 6548 } else { 6549 this.empty().append( value ); 6550 } 6551 6552 return this; 6553 }, 6554 6555 replaceWith: function( value ) { 6556 if ( this[0] && this[0].parentNode ) { 6557 // Make sure that the elements are removed from the DOM before they are inserted 6558 // this can help fix replacing a parent with child elements 6559 if ( jQuery.isFunction( value ) ) { 6560 return this.each(function(i) { 6561 var self = jQuery(this), old = self.html(); 6562 self.replaceWith( value.call( this, i, old ) ); 6563 }); 6564 } 6565 6566 if ( typeof value !== "string" ) { 6567 value = jQuery( value ).detach(); 6568 } 6569 6570 return this.each(function() { 6571 var next = this.nextSibling, 6572 parent = this.parentNode; 6573 6574 jQuery( this ).remove(); 6575 6576 if ( next ) { 6577 jQuery(next).before( value ); 6578 } else { 6579 jQuery(parent).append( value ); 6580 } 6581 }); 6582 } else { 6583 return this.length ? 6584 this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) : 6585 this; 6586 } 6587 }, 6588 6589 detach: function( selector ) { 6590 return this.remove( selector, true ); 6591 }, 6592 6593 domManip: function( args, table, callback ) { 6594 var results, first, fragment, parent, 6595 value = args[0], 6596 scripts = []; 6597 6598 // We can't cloneNode fragments that contain checked, in WebKit 6599 if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) { 6600 return this.each(function() { 6601 jQuery(this).domManip( args, table, callback, true ); 6602 }); 6603 } 6604 6605 if ( jQuery.isFunction(value) ) { 6606 return this.each(function(i) { 6607 var self = jQuery(this); 6608 args[0] = value.call(this, i, table ? self.html() : undefined); 6609 self.domManip( args, table, callback ); 6610 }); 6611 } 6612 6613 if ( this[0] ) { 6614 parent = value && value.parentNode; 6615 6616 // If we're in a fragment, just use that instead of building a new one 6617 if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) { 6618 results = { fragment: parent }; 6619 6620 } else { 6621 results = jQuery.buildFragment( args, this, scripts ); 6622 } 6623 6624 fragment = results.fragment; 6625 6626 if ( fragment.childNodes.length === 1 ) { 6627 first = fragment = fragment.firstChild; 6628 } else { 6629 first = fragment.firstChild; 6630 } 6631 6632 if ( first ) { 6633 table = table && jQuery.nodeName( first, "tr" ); 6634 6635 for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) { 6636 callback.call( 6637 table ? 6638 root(this[i], first) : 6639 this[i], 6640 // Make sure that we do not leak memory by inadvertently discarding 6641 // the original fragment (which might have attached data) instead of 6642 // using it; in addition, use the original fragment object for the last 6643 // item instead of first because it can end up being emptied incorrectly 6644 // in certain situations (Bug #8070). 6645 // Fragments from the fragment cache must always be cloned and never used 6646 // in place. 6647 results.cacheable || ( l > 1 && i < lastIndex ) ? 6648 jQuery.clone( fragment, true, true ) : 6649 fragment 6650 ); 6651 } 6652 } 6653 6654 if ( scripts.length ) { 6655 jQuery.each( scripts, evalScript ); 6656 } 6657 } 6658 6659 return this; 6660 } 6661}); 6662 6663function root( elem, cur ) { 6664 return jQuery.nodeName(elem, "table") ? 6665 (elem.getElementsByTagName("tbody")[0] || 6666 elem.appendChild(elem.ownerDocument.createElement("tbody"))) : 6667 elem; 6668} 6669 6670function cloneCopyEvent( src, dest ) { 6671 6672 if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { 6673 return; 6674 } 6675 6676 var type, i, l, 6677 oldData = jQuery._data( src ), 6678 curData = jQuery._data( dest, oldData ), 6679 events = oldData.events; 6680 6681 if ( events ) { 6682 delete curData.handle; 6683 curData.events = {}; 6684 6685 for ( type in events ) { 6686 for ( i = 0, l = events[ type ].length; i < l; i++ ) { 6687 jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data ); 6688 } 6689 } 6690 } 6691 6692 // make the cloned public data object a copy from the original 6693 if ( curData.data ) { 6694 curData.data = jQuery.extend( {}, curData.data ); 6695 } 6696} 6697 6698function cloneFixAttributes( src, dest ) { 6699 var nodeName; 6700 6701 // We do not need to do anything for non-Elements 6702 if ( dest.nodeType !== 1 ) { 6703 return; 6704 } 6705 6706 // clearAttributes removes the attributes, which we don't want, 6707 // but also removes the attachEvent events, which we *do* want 6708 if ( dest.clearAttributes ) { 6709 dest.clearAttributes(); 6710 } 6711 6712 // mergeAttributes, in contrast, only merges back on the 6713 // original attributes, not the events 6714 if ( dest.mergeAttributes ) { 6715 dest.mergeAttributes( src ); 6716 } 6717 6718 nodeName = dest.nodeName.toLowerCase(); 6719 6720 // IE6-8 fail to clone children inside object elements that use 6721 // the proprietary classid attribute value (rather than the type 6722 // attribute) to identify the type of content to display 6723 if ( nodeName === "object" ) { 6724 dest.outerHTML = src.outerHTML; 6725 6726 } else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) { 6727 // IE6-8 fails to persist the checked state of a cloned checkbox 6728 // or radio button. Worse, IE6-7 fail to give the cloned element 6729 // a checked appearance if the defaultChecked value isn't also set 6730 if ( src.checked ) { 6731 dest.defaultChecked = dest.checked = src.checked; 6732 } 6733 6734 // IE6-7 get confused and end up setting the value of a cloned 6735 // checkbox/radio button to an empty string instead of "on" 6736 if ( dest.value !== src.value ) { 6737 dest.value = src.value; 6738 } 6739 6740 // IE6-8 fails to return the selected option to the default selected 6741 // state when cloning options 6742 } else if ( nodeName === "option" ) { 6743 dest.selected = src.defaultSelected; 6744 6745 // IE6-8 fails to set the defaultValue to the correct value when 6746 // cloning other types of input fields 6747 } else if ( nodeName === "input" || nodeName === "textarea" ) { 6748 dest.defaultValue = src.defaultValue; 6749 } 6750 6751 // Event data gets referenced instead of copied if the expando 6752 // gets copied too 6753 dest.removeAttribute( jQuery.expando ); 6754} 6755 6756jQuery.buildFragment = function( args, nodes, scripts ) { 6757 var fragment, cacheable, cacheresults, doc, 6758 first = args[ 0 ]; 6759 6760 // nodes may contain either an explicit document object, 6761 // a jQuery collection or context object. 6762 // If nodes[0] contains a valid object to assign to doc 6763 if ( nodes && nodes[0] ) { 6764 doc = nodes[0].ownerDocument || nodes[0]; 6765 } 6766 6767 // Ensure that an attr object doesn't incorrectly stand in as a document object 6768 // Chrome and Firefox seem to allow this to occur and will throw exception 6769 // Fixes #8950 6770 if ( !doc.createDocumentFragment ) { 6771 doc = document; 6772 } 6773 6774 // Only cache "small" (1/2 KB) HTML strings that are associated with the main document 6775 // Cloning options loses the selected state, so don't cache them 6776 // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment 6777 // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache 6778 // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501 6779 if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document && 6780 first.charAt(0) === "<" && !rnocache.test( first ) && 6781 (jQuery.support.checkClone || !rchecked.test( first )) && 6782 (!jQuery.support.unknownElems && rnoshimcache.test( first )) ) { 6783 6784 cacheable = true; 6785 6786 cacheresults = jQuery.fragments[ first ]; 6787 if ( cacheresults && cacheresults !== 1 ) { 6788 fragment = cacheresults; 6789 } 6790 } 6791 6792 if ( !fragment ) { 6793 fragment = doc.createDocumentFragment(); 6794 jQuery.clean( args, doc, fragment, scripts ); 6795 } 6796 6797 if ( cacheable ) { 6798 jQuery.fragments[ first ] = cacheresults ? fragment : 1; 6799 } 6800 6801 return { fragment: fragment, cacheable: cacheable }; 6802}; 6803 6804jQuery.fragments = {}; 6805 6806jQuery.each({ 6807 appendTo: "append", 6808 prependTo: "prepend", 6809 insertBefore: "before", 6810 insertAfter: "after", 6811 replaceAll: "replaceWith" 6812}, function( name, original ) { 6813 jQuery.fn[ name ] = function( selector ) { 6814 var ret = [], 6815 insert = jQuery( selector ), 6816 parent = this.length === 1 && this[0].parentNode; 6817 6818 if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) { 6819 insert[ original ]( this[0] ); 6820 return this; 6821 6822 } else { 6823 for ( var i = 0, l = insert.length; i < l; i++ ) { 6824 var elems = ( i > 0 ? this.clone(true) : this ).get(); 6825 jQuery( insert[i] )[ original ]( elems ); 6826 ret = ret.concat( elems ); 6827 } 6828 6829 return this.pushStack( ret, name, insert.selector ); 6830 } 6831 }; 6832}); 6833 6834function getAll( elem ) { 6835 if ( typeof elem.getElementsByTagName !== "undefined" ) { 6836 return elem.getElementsByTagName( "*" ); 6837 6838 } else if ( typeof elem.querySelectorAll !== "undefined" ) { 6839 return elem.querySelectorAll( "*" ); 6840 6841 } else { 6842 return []; 6843 } 6844} 6845 6846// Used in clean, fixes the defaultChecked property 6847function fixDefaultChecked( elem ) { 6848 if ( elem.type === "checkbox" || elem.type === "radio" ) { 6849 elem.defaultChecked = elem.checked; 6850 } 6851} 6852// Finds all inputs and passes them to fixDefaultChecked 6853function findInputs( elem ) { 6854 var nodeName = ( elem.nodeName || "" ).toLowerCase(); 6855 if ( nodeName === "input" ) { 6856 fixDefaultChecked( elem ); 6857 // Skip scripts, get other children 6858 } else if ( nodeName !== "script" && typeof elem.getElementsByTagName !== "undefined" ) { 6859 jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); 6860 } 6861} 6862 6863jQuery.extend({ 6864 clone: function( elem, dataAndEvents, deepDataAndEvents ) { 6865 var clone = elem.cloneNode(true), 6866 srcElements, 6867 destElements, 6868 i; 6869 6870 if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && 6871 (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { 6872 // IE copies events bound via attachEvent when using cloneNode. 6873 // Calling detachEvent on the clone will also remove the events 6874 // from the original. In order to get around this, we use some 6875 // proprietary methods to clear the events. Thanks to MooTools 6876 // guys for this hotness. 6877 6878 cloneFixAttributes( elem, clone ); 6879 6880 // Using Sizzle here is crazy slow, so we use getElementsByTagName 6881 // instead 6882 srcElements = getAll( elem ); 6883 destElements = getAll( clone ); 6884 6885 // Weird iteration because IE will replace the length property 6886 // with an element if you are cloning the body and one of the 6887 // elements on the page has a name or id of "length" 6888 for ( i = 0; srcElements[i]; ++i ) { 6889 // Ensure that the destination node is not null; Fixes #9587 6890 if ( destElements[i] ) { 6891 cloneFixAttributes( srcElements[i], destElements[i] ); 6892 } 6893 } 6894 } 6895 6896 // Copy the events from the original to the clone 6897 if ( dataAndEvents ) { 6898 cloneCopyEvent( elem, clone ); 6899 6900 if ( deepDataAndEvents ) { 6901 srcElements = getAll( elem ); 6902 destElements = getAll( clone ); 6903 6904 for ( i = 0; srcElements[i]; ++i ) { 6905 cloneCopyEvent( srcElements[i], destElements[i] ); 6906 } 6907 } 6908 } 6909 6910 srcElements = destElements = null; 6911 6912 // Return the cloned set 6913 return clone; 6914 }, 6915 6916 clean: function( elems, context, fragment, scripts ) { 6917 var checkScriptType; 6918 6919 context = context || document; 6920 6921 // !context.createElement fails in IE with an error but returns typeof 'object' 6922 if ( typeof context.createElement === "undefined" ) { 6923 context = context.ownerDocument || context[0] && context[0].ownerDocument || document; 6924 } 6925 6926 var ret = [], j; 6927 6928 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { 6929 if ( typeof elem === "number" ) { 6930 elem += ""; 6931 } 6932 6933 if ( !elem ) { 6934 continue; 6935 } 6936 6937 // Convert html string into DOM nodes 6938 if ( typeof elem === "string" ) { 6939 if ( !rhtml.test( elem ) ) { 6940 elem = context.createTextNode( elem ); 6941 } else { 6942 // Fix "XHTML"-style tags in all browsers 6943 elem = elem.replace(rxhtmlTag, "<$1></$2>"); 6944 6945 // Trim whitespace, otherwise indexOf won't work as expected 6946 var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(), 6947 wrap = wrapMap[ tag ] || wrapMap._default, 6948 depth = wrap[0], 6949 div = context.createElement("div"); 6950 6951 // Append wrapper element to unknown element safe doc fragment 6952 if ( context === document ) { 6953 // Use the fragment we've already created for this document 6954 safeFragment.appendChild( div ); 6955 } else { 6956 // Use a fragment created with the owner document 6957 createSafeFragment( context ).appendChild( div ); 6958 } 6959 6960 // Go to html and back, then peel off extra wrappers 6961 div.innerHTML = wrap[1] + elem + wrap[2]; 6962 6963 // Move to the right depth 6964 while ( depth-- ) { 6965 div = div.lastChild; 6966 } 6967 6968 // Remove IE's autoinserted <tbody> from table fragments 6969 if ( !jQuery.support.tbody ) { 6970 6971 // String was a <table>, *may* have spurious <tbody> 6972 var hasBody = rtbody.test(elem), 6973 tbody = tag === "table" && !hasBody ? 6974 div.firstChild && div.firstChild.childNodes : 6975 6976 // String was a bare <thead> or <tfoot> 6977 wrap[1] === "<table>" && !hasBody ? 6978 div.childNodes : 6979 []; 6980 6981 for ( j = tbody.length - 1; j >= 0 ; --j ) { 6982 if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { 6983 tbody[ j ].parentNode.removeChild( tbody[ j ] ); 6984 } 6985 } 6986 } 6987 6988 // IE completely kills leading whitespace when innerHTML is used 6989 if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { 6990 div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); 6991 } 6992 6993 elem = div.childNodes; 6994 } 6995 } 6996 6997 // Resets defaultChecked for any radios and checkboxes 6998 // about to be appended to the DOM in IE 6/7 (#8060) 6999 var len; 7000 if ( !jQuery.support.appendChecked ) { 7001 if ( elem[0] && typeof (len = elem.length) === "number" ) { 7002 for ( j = 0; j < len; j++ ) { 7003 findInputs( elem[j] ); 7004 } 7005 } else { 7006 findInputs( elem ); 7007 } 7008 } 7009 7010 if ( elem.nodeType ) { 7011 ret.push( elem ); 7012 } else { 7013 ret = jQuery.merge( ret, elem ); 7014 } 7015 } 7016 7017 if ( fragment ) { 7018 checkScriptType = function( elem ) { 7019 return !elem.type || rscriptType.test( elem.type ); 7020 }; 7021 for ( i = 0; ret[i]; i++ ) { 7022 if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) { 7023 scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] ); 7024 7025 } else { 7026 if ( ret[i].nodeType === 1 ) { 7027 var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType ); 7028 7029 ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); 7030 } 7031 fragment.appendChild( ret[i] ); 7032 } 7033 } 7034 } 7035 7036 return ret; 7037 }, 7038 7039 cleanData: function( elems ) { 7040 var data, id, 7041 cache = jQuery.cache, 7042 special = jQuery.event.special, 7043 deleteExpando = jQuery.support.deleteExpando; 7044 7045 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { 7046 if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { 7047 continue; 7048 } 7049 7050 id = elem[ jQuery.expando ]; 7051 7052 if ( id ) { 7053 data = cache[ id ]; 7054 7055 if ( data && data.events ) { 7056 for ( var type in data.events ) { 7057 if ( special[ type ] ) { 7058 jQuery.event.remove( elem, type ); 7059 7060 // This is a shortcut to avoid jQuery.event.remove's overhead 7061 } else { 7062 jQuery.removeEvent( elem, type, data.handle ); 7063 } 7064 } 7065 7066 // Null the DOM reference to avoid IE6/7/8 leak (#7054) 7067 if ( data.handle ) { 7068 data.handle.elem = null; 7069 } 7070 } 7071 7072 if ( deleteExpando ) { 7073 delete elem[ jQuery.expando ]; 7074 7075 } else if ( elem.removeAttribute ) { 7076 elem.removeAttribute( jQuery.expando ); 7077 } 7078 7079 delete cache[ id ]; 7080 } 7081 } 7082 } 7083}); 7084 7085function evalScript( i, elem ) { 7086 if ( elem.src ) { 7087 jQuery.ajax({ 7088 url: elem.src, 7089 async: false, 7090 dataType: "script" 7091 }); 7092 } else { 7093 jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) ); 7094 } 7095 7096 if ( elem.parentNode ) { 7097 elem.parentNode.removeChild( elem ); 7098 } 7099} 7100 7101 7102 7103 7104var ralpha = /alpha\([^)]*\)/i, 7105 ropacity = /opacity=([^)]*)/, 7106 // fixed for IE9, see #8346 7107 rupper = /([A-Z]|^ms)/g, 7108 rnumpx = /^-?\d+(?:px)?$/i, 7109 rnum = /^-?\d/, 7110 rrelNum = /^([\-+])=([\-+.\de]+)/, 7111 7112 cssShow = { position: "absolute", visibility: "hidden", display: "block" }, 7113 cssWidth = [ "Left", "Right" ], 7114 cssHeight = [ "Top", "Bottom" ], 7115 curCSS, 7116 7117 getComputedStyle, 7118 currentStyle; 7119 7120jQuery.fn.css = function( name, value ) { 7121 // Setting 'undefined' is a no-op 7122 if ( arguments.length === 2 && value === undefined ) { 7123 return this; 7124 } 7125 7126 return jQuery.access( this, name, value, true, function( elem, name, value ) { 7127 return value !== undefined ? 7128 jQuery.style( elem, name, value ) : 7129 jQuery.css( elem, name ); 7130 }); 7131}; 7132 7133jQuery.extend({ 7134 // Add in style property hooks for overriding the default 7135 // behavior of getting and setting a style property 7136 cssHooks: { 7137 opacity: { 7138 get: function( elem, computed ) { 7139 if ( computed ) { 7140 // We should always get a number back from opacity 7141 var ret = curCSS( elem, "opacity", "opacity" ); 7142 return ret === "" ? "1" : ret; 7143 7144 } else { 7145 return elem.style.opacity; 7146 } 7147 } 7148 } 7149 }, 7150 7151 // Exclude the following css properties to add px 7152 cssNumber: { 7153 "fillOpacity": true, 7154 "fontWeight": true, 7155 "lineHeight": true, 7156 "opacity": true, 7157 "orphans": true, 7158 "widows": true, 7159 "zIndex": true, 7160 "zoom": true 7161 }, 7162 7163 // Add in properties whose names you wish to fix before 7164 // setting or getting the value 7165 cssProps: { 7166 // normalize float css property 7167 "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" 7168 }, 7169 7170 // Get and set the style property on a DOM Node 7171 style: function( elem, name, value, extra ) { 7172 // Don't set styles on text and comment nodes 7173 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { 7174 return; 7175 } 7176 7177 // Make sure that we're working with the right name 7178 var ret, type, origName = jQuery.camelCase( name ), 7179 style = elem.style, hooks = jQuery.cssHooks[ origName ]; 7180 7181 name = jQuery.cssProps[ origName ] || origName; 7182 7183 // Check if we're setting a value 7184 if ( value !== undefined ) { 7185 type = typeof value; 7186 7187 // convert relative number strings (+= or -=) to relative numbers. #7345 7188 if ( type === "string" && (ret = rrelNum.exec( value )) ) { 7189 value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) ); 7190 // Fixes bug #9237 7191 type = "number"; 7192 } 7193 7194 // Make sure that NaN and null values aren't set. See: #7116 7195 if ( value == null || type === "number" && isNaN( value ) ) { 7196 return; 7197 } 7198 7199 // If a number was passed in, add 'px' to the (except for certain CSS properties) 7200 if ( type === "number" && !jQuery.cssNumber[ origName ] ) { 7201 value += "px"; 7202 } 7203 7204 // If a hook was provided, use that value, otherwise just set the specified value 7205 if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) { 7206 // Wrapped to prevent IE from throwing errors when 'invalid' values are provided 7207 // Fixes bug #5509 7208 try { 7209 style[ name ] = value; 7210 } catch(e) {} 7211 } 7212 7213 } else { 7214 // If a hook was provided get the non-computed value from there 7215 if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { 7216 return ret; 7217 } 7218 7219 // Otherwise just get the value from the style object 7220 return style[ name ]; 7221 } 7222 }, 7223 7224 css: function( elem, name, extra ) { 7225 var ret, hooks; 7226 7227 // Make sure that we're working with the right name 7228 name = jQuery.camelCase( name ); 7229 hooks = jQuery.cssHooks[ name ]; 7230 name = jQuery.cssProps[ name ] || name; 7231 7232 // cssFloat needs a special treatment 7233 if ( name === "cssFloat" ) { 7234 name = "float"; 7235 } 7236 7237 // If a hook was provided get the computed value from there 7238 if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) { 7239 return ret; 7240 7241 // Otherwise, if a way to get the computed value exists, use that 7242 } else if ( curCSS ) { 7243 return curCSS( elem, name ); 7244 } 7245 }, 7246 7247 // A method for quickly swapping in/out CSS properties to get correct calculations 7248 swap: function( elem, options, callback ) { 7249 var old = {}; 7250 7251 // Remember the old values, and insert the new ones 7252 for ( var name in options ) { 7253 old[ name ] = elem.style[ name ]; 7254 elem.style[ name ] = options[ name ]; 7255 } 7256 7257 callback.call( elem ); 7258 7259 // Revert the old values 7260 for ( name in options ) { 7261 elem.style[ name ] = old[ name ]; 7262 } 7263 } 7264}); 7265 7266// DEPRECATED, Use jQuery.css() instead 7267jQuery.curCSS = jQuery.css; 7268 7269jQuery.each(["height", "width"], function( i, name ) { 7270 jQuery.cssHooks[ name ] = { 7271 get: function( elem, computed, extra ) { 7272 var val; 7273 7274 if ( computed ) { 7275 if ( elem.offsetWidth !== 0 ) { 7276 return getWH( elem, name, extra ); 7277 } else { 7278 jQuery.swap( elem, cssShow, function() { 7279 val = getWH( elem, name, extra ); 7280 }); 7281 } 7282 7283 return val; 7284 } 7285 }, 7286 7287 set: function( elem, value ) { 7288 if ( rnumpx.test( value ) ) { 7289 // ignore negative width and height values #1599 7290 value = parseFloat( value ); 7291 7292 if ( value >= 0 ) { 7293 return value + "px"; 7294 } 7295 7296 } else { 7297 return value; 7298 } 7299 } 7300 }; 7301}); 7302 7303if ( !jQuery.support.opacity ) { 7304 jQuery.cssHooks.opacity = { 7305 get: function( elem, computed ) { 7306 // IE uses filters for opacity 7307 return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? 7308 ( parseFloat( RegExp.$1 ) / 100 ) + "" : 7309 computed ? "1" : ""; 7310 }, 7311 7312 set: function( elem, value ) { 7313 var style = elem.style, 7314 currentStyle = elem.currentStyle, 7315 opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", 7316 filter = currentStyle && currentStyle.filter || style.filter || ""; 7317 7318 // IE has trouble with opacity if it does not have layout 7319 // Force it by setting the zoom level 7320 style.zoom = 1; 7321 7322 // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 7323 if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) { 7324 7325 // Setting style.filter to null, "" & " " still leave "filter:" in the cssText 7326 // if "filter:" is present at all, clearType is disabled, we want to avoid this 7327 // style.removeAttribute is IE Only, but so apparently is this code path... 7328 style.removeAttribute( "filter" ); 7329 7330 // if there there is no filter style applied in a css rule, we are done 7331 if ( currentStyle && !currentStyle.filter ) { 7332 return; 7333 } 7334 } 7335 7336 // otherwise, set new filter values 7337 style.filter = ralpha.test( filter ) ? 7338 filter.replace( ralpha, opacity ) : 7339 filter + " " + opacity; 7340 } 7341 }; 7342} 7343 7344jQuery(function() { 7345 // This hook cannot be added until DOM ready because the support test 7346 // for it is not run until after DOM ready 7347 if ( !jQuery.support.reliableMarginRight ) { 7348 jQuery.cssHooks.marginRight = { 7349 get: function( elem, computed ) { 7350 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right 7351 // Work around by temporarily setting element display to inline-block 7352 var ret; 7353 jQuery.swap( elem, { "display": "inline-block" }, function() { 7354 if ( computed ) { 7355 ret = curCSS( elem, "margin-right", "marginRight" ); 7356 } else { 7357 ret = elem.style.marginRight; 7358 } 7359 }); 7360 return ret; 7361 } 7362 }; 7363 } 7364}); 7365 7366if ( document.defaultView && document.defaultView.getComputedStyle ) { 7367 getComputedStyle = function( elem, name ) { 7368 var ret, defaultView, computedStyle; 7369 7370 name = name.replace( rupper, "-$1" ).toLowerCase(); 7371 7372 if ( !(defaultView = elem.ownerDocument.defaultView) ) { 7373 return undefined; 7374 } 7375 7376 if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) { 7377 ret = computedStyle.getPropertyValue( name ); 7378 if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) { 7379 ret = jQuery.style( elem, name ); 7380 } 7381 } 7382 7383 return ret; 7384 }; 7385} 7386 7387if ( document.documentElement.currentStyle ) { 7388 currentStyle = function( elem, name ) { 7389 var left, rsLeft, uncomputed, 7390 ret = elem.currentStyle && elem.currentStyle[ name ], 7391 style = elem.style; 7392 7393 // Avoid setting ret to empty string here 7394 // so we don't default to auto 7395 if ( ret === null && style && (uncomputed = style[ name ]) ) { 7396 ret = uncomputed; 7397 } 7398 7399 // From the awesome hack by Dean Edwards 7400 // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 7401 7402 // If we're not dealing with a regular pixel number 7403 // but a number that has a weird ending, we need to convert it to pixels 7404 if ( !rnumpx.test( ret ) && rnum.test( ret ) ) { 7405 7406 // Remember the original values 7407 left = style.left; 7408 rsLeft = elem.runtimeStyle && elem.runtimeStyle.left; 7409 7410 // Put in the new values to get a computed value out 7411 if ( rsLeft ) { 7412 elem.runtimeStyle.left = elem.currentStyle.left; 7413 } 7414 style.left = name === "fontSize" ? "1em" : ( ret || 0 ); 7415 ret = style.pixelLeft + "px"; 7416 7417 // Revert the changed values 7418 style.left = left; 7419 if ( rsLeft ) { 7420 elem.runtimeStyle.left = rsLeft; 7421 } 7422 } 7423 7424 return ret === "" ? "auto" : ret; 7425 }; 7426} 7427 7428curCSS = getComputedStyle || currentStyle; 7429 7430function getWH( elem, name, extra ) { 7431 7432 // Start with offset property 7433 var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, 7434 which = name === "width" ? cssWidth : cssHeight; 7435 7436 if ( val > 0 ) { 7437 if ( extra !== "border" ) { 7438 jQuery.each( which, function() { 7439 if ( !extra ) { 7440 val -= parseFloat( jQuery.css( elem, "padding" + this ) ) || 0; 7441 } 7442 if ( extra === "margin" ) { 7443 val += parseFloat( jQuery.css( elem, extra + this ) ) || 0; 7444 } else { 7445 val -= parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0; 7446 } 7447 }); 7448 } 7449 7450 return val + "px"; 7451 } 7452 7453 // Fall back to computed then uncomputed css if necessary 7454 val = curCSS( elem, name, name ); 7455 if ( val < 0 || val == null ) { 7456 val = elem.style[ name ] || 0; 7457 } 7458 // Normalize "", auto, and prepare for extra 7459 val = parseFloat( val ) || 0; 7460 7461 // Add padding, border, margin 7462 if ( extra ) { 7463 jQuery.each( which, function() { 7464 val += parseFloat( jQuery.css( elem, "padding" + this ) ) || 0; 7465 if ( extra !== "padding" ) { 7466 val += parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0; 7467 } 7468 if ( extra === "margin" ) { 7469 val += parseFloat( jQuery.css( elem, extra + this ) ) || 0; 7470 } 7471 }); 7472 } 7473 7474 return val + "px"; 7475} 7476 7477if ( jQuery.expr && jQuery.expr.filters ) { 7478 jQuery.expr.filters.hidden = function( elem ) { 7479 var width = elem.offsetWidth, 7480 height = elem.offsetHeight; 7481 7482 return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none"); 7483 }; 7484 7485 jQuery.expr.filters.visible = function( elem ) { 7486 return !jQuery.expr.filters.hidden( elem ); 7487 }; 7488} 7489 7490 7491 7492 7493var r20 = /%20/g, 7494 rbracket = /\[\]$/, 7495 rCRLF = /\r?\n/g, 7496 rhash = /#.*$/, 7497 rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL 7498 rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, 7499 // #7653, #8125, #8152: local protocol detection 7500 rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/, 7501 rnoContent = /^(?:GET|HEAD)$/, 7502 rprotocol = /^\/\//, 7503 rquery = /\?/, 7504 rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, 7505 rselectTextarea = /^(?:select|textarea)/i, 7506 rspacesAjax = /\s+/, 7507 rts = /([?&])_=[^&]*/, 7508 rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/, 7509 7510 // Keep a copy of the old load method 7511 _load = jQuery.fn.load, 7512 7513 /* Prefilters 7514 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) 7515 * 2) These are called: 7516 * - BEFORE asking for a transport 7517 * - AFTER param serialization (s.data is a string if s.processData is true) 7518 * 3) key is the dataType 7519 * 4) the catchall symbol "*" can be used 7520 * 5) execution will start with transport dataType and THEN continue down to "*" if needed 7521 */ 7522 prefilters = {}, 7523 7524 /* Transports bindings 7525 * 1) key is the dataType 7526 * 2) the catchall symbol "*" can be used 7527 * 3) selection will start with transport dataType and THEN go to "*" if needed 7528 */ 7529 transports = {}, 7530 7531 // Document location 7532 ajaxLocation, 7533 7534 // Document location segments 7535 ajaxLocParts, 7536 7537 // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression 7538 allTypes = ["*/"] + ["*"]; 7539 7540// #8138, IE may throw an exception when accessing 7541// a field from window.location if document.domain has been set 7542try { 7543 ajaxLocation = location.href; 7544} catch( e ) { 7545 // Use the href attribute of an A element 7546 // since IE will modify it given document.location 7547 ajaxLocation = document.createElement( "a" ); 7548 ajaxLocation.href = ""; 7549 ajaxLocation = ajaxLocation.href; 7550} 7551 7552// Segment location into parts 7553ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; 7554 7555// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport 7556function addToPrefiltersOrTransports( structure ) { 7557 7558 // dataTypeExpression is optional and defaults to "*" 7559 return function( dataTypeExpression, func ) { 7560 7561 if ( typeof dataTypeExpression !== "string" ) { 7562 func = dataTypeExpression; 7563 dataTypeExpression = "*"; 7564 } 7565 7566 if ( jQuery.isFunction( func ) ) { 7567 var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ), 7568 i = 0, 7569 length = dataTypes.length, 7570 dataType, 7571 list, 7572 placeBefore; 7573 7574 // For each dataType in the dataTypeExpression 7575 for ( ; i < length; i++ ) { 7576 dataType = dataTypes[ i ]; 7577 // We control if we're asked to add before 7578 // any existing element 7579 placeBefore = /^\+/.test( dataType ); 7580 if ( placeBefore ) { 7581 dataType = dataType.substr( 1 ) || "*"; 7582 } 7583 list = structure[ dataType ] = structure[ dataType ] || []; 7584 // then we add to the structure accordingly 7585 list[ placeBefore ? "unshift" : "push" ]( func ); 7586 } 7587 } 7588 }; 7589} 7590 7591// Base inspection function for prefilters and transports 7592function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR, 7593 dataType /* internal */, inspected /* internal */ ) { 7594 7595 dataType = dataType || options.dataTypes[ 0 ]; 7596 inspected = inspected || {}; 7597 7598 inspected[ dataType ] = true; 7599 7600 var list = structure[ dataType ], 7601 i = 0, 7602 length = list ? list.length : 0, 7603 executeOnly = ( structure === prefilters ), 7604 selection; 7605 7606 for ( ; i < length && ( executeOnly || !selection ); i++ ) { 7607 selection = list[ i ]( options, originalOptions, jqXHR ); 7608 // If we got redirected to another dataType 7609 // we try there if executing only and not done already 7610 if ( typeof selection === "string" ) { 7611 if ( !executeOnly || inspected[ selection ] ) { 7612 selection = undefined; 7613 } else { 7614 options.dataTypes.unshift( selection ); 7615 selection = inspectPrefiltersOrTransports( 7616 structure, options, originalOptions, jqXHR, selection, inspected ); 7617 } 7618 } 7619 } 7620 // If we're only executing or nothing was selected 7621 // we try the catchall dataType if not done already 7622 if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) { 7623 selection = inspectPrefiltersOrTransports( 7624 structure, options, originalOptions, jqXHR, "*", inspected ); 7625 } 7626 // unnecessary when only executing (prefilters) 7627 // but it'll be ignored by the caller in that case 7628 return selection; 7629} 7630 7631// A special extend for ajax options 7632// that takes "flat" options (not to be deep extended) 7633// Fixes #9887 7634function ajaxExtend( target, src ) { 7635 var key, deep, 7636 flatOptions = jQuery.ajaxSettings.flatOptions || {}; 7637 for ( key in src ) { 7638 if ( src[ key ] !== undefined ) { 7639 ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; 7640 } 7641 } 7642 if ( deep ) { 7643 jQuery.extend( true, target, deep ); 7644 } 7645} 7646 7647jQuery.fn.extend({ 7648 load: function( url, params, callback ) { 7649 if ( typeof url !== "string" && _load ) { 7650 return _load.apply( this, arguments ); 7651 7652 // Don't do a request if no elements are being requested 7653 } else if ( !this.length ) { 7654 return this; 7655 } 7656 7657 var off = url.indexOf( " " ); 7658 if ( off >= 0 ) { 7659 var selector = url.slice( off, url.length ); 7660 url = url.slice( 0, off ); 7661 } 7662 7663 // Default to a GET request 7664 var type = "GET"; 7665 7666 // If the second parameter was provided 7667 if ( params ) { 7668 // If it's a function 7669 if ( jQuery.isFunction( params ) ) { 7670 // We assume that it's the callback 7671 callback = params; 7672 params = undefined; 7673 7674 // Otherwise, build a param string 7675 } else if ( typeof params === "object" ) { 7676 params = jQuery.param( params, jQuery.ajaxSettings.traditional ); 7677 type = "POST"; 7678 } 7679 } 7680 7681 var self = this; 7682 7683 // Request the remote document 7684 jQuery.ajax({ 7685 url: url, 7686 type: type, 7687 dataType: "html", 7688 data: params, 7689 // Complete callback (responseText is used internally) 7690 complete: function( jqXHR, status, responseText ) { 7691 // Store the response as specified by the jqXHR object 7692 responseText = jqXHR.responseText; 7693 // If successful, inject the HTML into all the matched elements 7694 if ( jqXHR.isResolved() ) { 7695 // #4825: Get the actual response in case 7696 // a dataFilter is present in ajaxSettings 7697 jqXHR.done(function( r ) { 7698 responseText = r; 7699 }); 7700 // See if a selector was specified 7701 self.html( selector ? 7702 // Create a dummy div to hold the results 7703 jQuery("<div>") 7704 // inject the contents of the document in, removing the scripts 7705 // to avoid any 'Permission Denied' errors in IE 7706 .append(responseText.replace(rscript, "")) 7707 7708 // Locate the specified elements 7709 .find(selector) : 7710 7711 // If not, just inject the full result 7712 responseText ); 7713 } 7714 7715 if ( callback ) { 7716 self.each( callback, [ responseText, status, jqXHR ] ); 7717 } 7718 } 7719 }); 7720 7721 return this; 7722 }, 7723 7724 serialize: function() { 7725 return jQuery.param( this.serializeArray() ); 7726 }, 7727 7728 serializeArray: function() { 7729 return this.map(function(){ 7730 return this.elements ? jQuery.makeArray( this.elements ) : this; 7731 }) 7732 .filter(function(){ 7733 return this.name && !this.disabled && 7734 ( this.checked || rselectTextarea.test( this.nodeName ) || 7735 rinput.test( this.type ) ); 7736 }) 7737 .map(function( i, elem ){ 7738 var val = jQuery( this ).val(); 7739 7740 return val == null ? 7741 null : 7742 jQuery.isArray( val ) ? 7743 jQuery.map( val, function( val, i ){ 7744 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; 7745 }) : 7746 { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; 7747 }).get(); 7748 } 7749}); 7750 7751// Attach a bunch of functions for handling common AJAX events 7752jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ 7753 jQuery.fn[ o ] = function( f ){ 7754 return this.bind( o, f ); 7755 }; 7756}); 7757 7758jQuery.each( [ "get", "post" ], function( i, method ) { 7759 jQuery[ method ] = function( url, data, callback, type ) { 7760 // shift arguments if data argument was omitted 7761 if ( jQuery.isFunction( data ) ) { 7762 type = type || callback; 7763 callback = data; 7764 data = undefined; 7765 } 7766 7767 return jQuery.ajax({ 7768 type: method, 7769 url: url, 7770 data: data, 7771 success: callback, 7772 dataType: type 7773 }); 7774 }; 7775}); 7776 7777jQuery.extend({ 7778 7779 getScript: function( url, callback ) { 7780 return jQuery.get( url, undefined, callback, "script" ); 7781 }, 7782 7783 getJSON: function( url, data, callback ) { 7784 return jQuery.get( url, data, callback, "json" ); 7785 }, 7786 7787 // Creates a full fledged settings object into target 7788 // with both ajaxSettings and settings fields. 7789 // If target is omitted, writes into ajaxSettings. 7790 ajaxSetup: function( target, settings ) { 7791 if ( settings ) { 7792 // Building a settings object 7793 ajaxExtend( target, jQuery.ajaxSettings ); 7794 } else { 7795 // Extending ajaxSettings 7796 settings = target; 7797 target = jQuery.ajaxSettings; 7798 } 7799 ajaxExtend( target, settings ); 7800 return target; 7801 }, 7802 7803 ajaxSettings: { 7804 url: ajaxLocation, 7805 isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), 7806 global: true, 7807 type: "GET", 7808 contentType: "application/x-www-form-urlencoded", 7809 processData: true, 7810 async: true, 7811 /* 7812 timeout: 0, 7813 data: null, 7814 dataType: null, 7815 username: null, 7816 password: null, 7817 cache: null, 7818 traditional: false, 7819 headers: {}, 7820 */ 7821 7822 accepts: { 7823 xml: "application/xml, text/xml", 7824 html: "text/html", 7825 text: "text/plain", 7826 json: "application/json, text/javascript", 7827 "*": allTypes 7828 }, 7829 7830 contents: { 7831 xml: /xml/, 7832 html: /html/, 7833 json: /json/ 7834 }, 7835 7836 responseFields: { 7837 xml: "responseXML", 7838 text: "responseText" 7839 }, 7840 7841 // List of data converters 7842 // 1) key format is "source_type destination_type" (a single space in-between) 7843 // 2) the catchall symbol "*" can be used for source_type 7844 converters: { 7845 7846 // Convert anything to text 7847 "* text": window.String, 7848 7849 // Text to html (true = no transformation) 7850 "text html": true, 7851 7852 // Evaluate text as a json expression 7853 "text json": jQuery.parseJSON, 7854 7855 // Parse text as xml 7856 "text xml": jQuery.parseXML 7857 }, 7858 7859 // For options that shouldn't be deep extended: 7860 // you can add your own custom options here if 7861 // and when you create one that shouldn't be 7862 // deep extended (see ajaxExtend) 7863 flatOptions: { 7864 context: true, 7865 url: true 7866 } 7867 }, 7868 7869 ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), 7870 ajaxTransport: addToPrefiltersOrTransports( transports ), 7871 7872 // Main method 7873 ajax: function( url, options ) { 7874 7875 // If url is an object, simulate pre-1.5 signature 7876 if ( typeof url === "object" ) { 7877 options = url; 7878 url = undefined; 7879 } 7880 7881 // Force options to be an object 7882 options = options || {}; 7883 7884 var // Create the final options object 7885 s = jQuery.ajaxSetup( {}, options ), 7886 // Callbacks context 7887 callbackContext = s.context || s, 7888 // Context for global events 7889 // It's the callbackContext if one was provided in the options 7890 // and if it's a DOM node or a jQuery collection 7891 globalEventContext = callbackContext !== s && 7892 ( callbackContext.nodeType || callbackContext instanceof jQuery ) ? 7893 jQuery( callbackContext ) : jQuery.event, 7894 // Deferreds 7895 deferred = jQuery.Deferred(), 7896 completeDeferred = jQuery.Callbacks( "once memory" ), 7897 // Status-dependent callbacks 7898 statusCode = s.statusCode || {}, 7899 // ifModified key 7900 ifModifiedKey, 7901 // Headers (they are sent all at once) 7902 requestHeaders = {}, 7903 requestHeadersNames = {}, 7904 // Response headers 7905 responseHeadersString, 7906 responseHeaders, 7907 // transport 7908 transport, 7909 // timeout handle 7910 timeoutTimer, 7911 // Cross-domain detection vars 7912 parts, 7913 // The jqXHR state 7914 state = 0, 7915 // To know if global events are to be dispatched 7916 fireGlobals, 7917 // Loop variable 7918 i, 7919 // Fake xhr 7920 jqXHR = { 7921 7922 readyState: 0, 7923 7924 // Caches the header 7925 setRequestHeader: function( name, value ) { 7926 if ( !state ) { 7927 var lname = name.toLowerCase(); 7928 name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; 7929 requestHeaders[ name ] = value; 7930 } 7931 return this; 7932 }, 7933 7934 // Raw string 7935 getAllResponseHeaders: function() { 7936 return state === 2 ? responseHeadersString : null; 7937 }, 7938 7939 // Builds headers hashtable if needed 7940 getResponseHeader: function( key ) { 7941 var match; 7942 if ( state === 2 ) { 7943 if ( !responseHeaders ) { 7944 responseHeaders = {}; 7945 while( ( match = rheaders.exec( responseHeadersString ) ) ) { 7946 responseHeaders[ match[1].toLowerCase() ] = match[ 2 ]; 7947 } 7948 } 7949 match = responseHeaders[ key.toLowerCase() ]; 7950 } 7951 return match === undefined ? null : match; 7952 }, 7953 7954 // Overrides response content-type header 7955 overrideMimeType: function( type ) { 7956 if ( !state ) { 7957 s.mimeType = type; 7958 } 7959 return this; 7960 }, 7961 7962 // Cancel the request 7963 abort: function( statusText ) { 7964 statusText = statusText || "abort"; 7965 if ( transport ) { 7966 transport.abort( statusText ); 7967 } 7968 done( 0, statusText ); 7969 return this; 7970 } 7971 }; 7972 7973 // Callback for when everything is done 7974 // It is defined here because jslint complains if it is declared 7975 // at the end of the function (which would be more logical and readable) 7976 function done( status, nativeStatusText, responses, headers ) { 7977 7978 // Called once 7979 if ( state === 2 ) { 7980 return; 7981 } 7982 7983 // State is "done" now 7984 state = 2; 7985 7986 // Clear timeout if it exists 7987 if ( timeoutTimer ) { 7988 clearTimeout( timeoutTimer ); 7989 } 7990 7991 // Dereference transport for early garbage collection 7992 // (no matter how long the jqXHR object will be used) 7993 transport = undefined; 7994 7995 // Cache response headers 7996 responseHeadersString = headers || ""; 7997 7998 // Set readyState 7999 jqXHR.readyState = status > 0 ? 4 : 0; 8000 8001 var isSuccess, 8002 success, 8003 error, 8004 statusText = nativeStatusText, 8005 response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined, 8006 lastModified, 8007 etag; 8008 8009 // If successful, handle type chaining 8010 if ( status >= 200 && status < 300 || status === 304 ) { 8011 8012 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. 8013 if ( s.ifModified ) { 8014 8015 if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) { 8016 jQuery.lastModified[ ifModifiedKey ] = lastModified; 8017 } 8018 if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) { 8019 jQuery.etag[ ifModifiedKey ] = etag; 8020 } 8021 } 8022 8023 // If not modified 8024 if ( status === 304 ) { 8025 8026 statusText = "notmodified"; 8027 isSuccess = true; 8028 8029 // If we have data 8030 } else { 8031 8032 try { 8033 success = ajaxConvert( s, response ); 8034 statusText = "success"; 8035 isSuccess = true; 8036 } catch(e) { 8037 // We have a parsererror 8038 statusText = "parsererror"; 8039 error = e; 8040 } 8041 } 8042 } else { 8043 // We extract error from statusText 8044 // then normalize statusText and status for non-aborts 8045 error = statusText; 8046 if ( !statusText || status ) { 8047 statusText = "error"; 8048 if ( status < 0 ) { 8049 status = 0; 8050 } 8051 } 8052 } 8053 8054 // Set data for the fake xhr object 8055 jqXHR.status = status; 8056 jqXHR.statusText = "" + ( nativeStatusText || statusText ); 8057 8058 // Success/Error 8059 if ( isSuccess ) { 8060 deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); 8061 } else { 8062 deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); 8063 } 8064 8065 // Status-dependent callbacks 8066 jqXHR.statusCode( statusCode ); 8067 statusCode = undefined; 8068 8069 if ( fireGlobals ) { 8070 globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ), 8071 [ jqXHR, s, isSuccess ? success : error ] ); 8072 } 8073 8074 // Complete 8075 completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); 8076 8077 if ( fireGlobals ) { 8078 globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); 8079 // Handle the global AJAX counter 8080 if ( !( --jQuery.active ) ) { 8081 jQuery.event.trigger( "ajaxStop" ); 8082 } 8083 } 8084 } 8085 8086 // Attach deferreds 8087 deferred.promise( jqXHR ); 8088 jqXHR.success = jqXHR.done; 8089 jqXHR.error = jqXHR.fail; 8090 jqXHR.complete = completeDeferred.add; 8091 8092 // Status-dependent callbacks 8093 jqXHR.statusCode = function( map ) { 8094 if ( map ) { 8095 var tmp; 8096 if ( state < 2 ) { 8097 for ( tmp in map ) { 8098 statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ]; 8099 } 8100 } else { 8101 tmp = map[ jqXHR.status ]; 8102 jqXHR.then( tmp, tmp ); 8103 } 8104 } 8105 return this; 8106 }; 8107 8108 // Remove hash character (#7531: and string promotion) 8109 // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) 8110 // We also use the url parameter if available 8111 s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); 8112 8113 // Extract dataTypes list 8114 s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax ); 8115 8116 // Determine if a cross-domain request is in order 8117 if ( s.crossDomain == null ) { 8118 parts = rurl.exec( s.url.toLowerCase() ); 8119 s.crossDomain = !!( parts && 8120 ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] || 8121 ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) != 8122 ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) ) 8123 ); 8124 } 8125 8126 // Convert data if not already a string 8127 if ( s.data && s.processData && typeof s.data !== "string" ) { 8128 s.data = jQuery.param( s.data, s.traditional ); 8129 } 8130 8131 // Apply prefilters 8132 inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); 8133 8134 // If request was aborted inside a prefiler, stop there 8135 if ( state === 2 ) { 8136 return false; 8137 } 8138 8139 // We can fire global events as of now if asked to 8140 fireGlobals = s.global; 8141 8142 // Uppercase the type 8143 s.type = s.type.toUpperCase(); 8144 8145 // Determine if request has content 8146 s.hasContent = !rnoContent.test( s.type ); 8147 8148 // Watch for a new set of requests 8149 if ( fireGlobals && jQuery.active++ === 0 ) { 8150 jQuery.event.trigger( "ajaxStart" ); 8151 } 8152 8153 // More options handling for requests with no content 8154 if ( !s.hasContent ) { 8155 8156 // If data is available, append data to url 8157 if ( s.data ) { 8158 s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data; 8159 // #9682: remove data so that it's not used in an eventual retry 8160 delete s.data; 8161 } 8162 8163 // Get ifModifiedKey before adding the anti-cache parameter 8164 ifModifiedKey = s.url; 8165 8166 // Add anti-cache in url if needed 8167 if ( s.cache === false ) { 8168 8169 var ts = jQuery.now(), 8170 // try replacing _= if it is there 8171 ret = s.url.replace( rts, "$1_=" + ts ); 8172 8173 // if nothing was replaced, add timestamp to the end 8174 s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); 8175 } 8176 } 8177 8178 // Set the correct header, if data is being sent 8179 if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { 8180 jqXHR.setRequestHeader( "Content-Type", s.contentType ); 8181 } 8182 8183 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. 8184 if ( s.ifModified ) { 8185 ifModifiedKey = ifModifiedKey || s.url; 8186 if ( jQuery.lastModified[ ifModifiedKey ] ) { 8187 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] ); 8188 } 8189 if ( jQuery.etag[ ifModifiedKey ] ) { 8190 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] ); 8191 } 8192 } 8193 8194 // Set the Accepts header for the server, depending on the dataType 8195 jqXHR.setRequestHeader( 8196 "Accept", 8197 s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? 8198 s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : 8199 s.accepts[ "*" ] 8200 ); 8201 8202 // Check for headers option 8203 for ( i in s.headers ) { 8204 jqXHR.setRequestHeader( i, s.headers[ i ] ); 8205 } 8206 8207 // Allow custom headers/mimetypes and early abort 8208 if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { 8209 // Abort if not done already 8210 jqXHR.abort(); 8211 return false; 8212 8213 } 8214 8215 // Install callbacks on deferreds 8216 for ( i in { success: 1, error: 1, complete: 1 } ) { 8217 jqXHR[ i ]( s[ i ] ); 8218 } 8219 8220 // Get transport 8221 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); 8222 8223 // If no transport, we auto-abort 8224 if ( !transport ) { 8225 done( -1, "No Transport" ); 8226 } else { 8227 jqXHR.readyState = 1; 8228 // Send global event 8229 if ( fireGlobals ) { 8230 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); 8231 } 8232 // Timeout 8233 if ( s.async && s.timeout > 0 ) { 8234 timeoutTimer = setTimeout( function(){ 8235 jqXHR.abort( "timeout" ); 8236 }, s.timeout ); 8237 } 8238 8239 try { 8240 state = 1; 8241 transport.send( requestHeaders, done ); 8242 } catch (e) { 8243 // Propagate exception as error if not done 8244 if ( state < 2 ) { 8245 done( -1, e ); 8246 // Simply rethrow otherwise 8247 } else { 8248 jQuery.error( e ); 8249 } 8250 } 8251 } 8252 8253 return jqXHR; 8254 }, 8255 8256 // Serialize an array of form elements or a set of 8257 // key/values into a query string 8258 param: function( a, traditional ) { 8259 var s = [], 8260 add = function( key, value ) { 8261 // If value is a function, invoke it and return its value 8262 value = jQuery.isFunction( value ) ? value() : value; 8263 s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); 8264 }; 8265 8266 // Set traditional to true for jQuery <= 1.3.2 behavior. 8267 if ( traditional === undefined ) { 8268 traditional = jQuery.ajaxSettings.traditional; 8269 } 8270 8271 // If an array was passed in, assume that it is an array of form elements. 8272 if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { 8273 // Serialize the form elements 8274 jQuery.each( a, function() { 8275 add( this.name, this.value ); 8276 }); 8277 8278 } else { 8279 // If traditional, encode the "old" way (the way 1.3.2 or older 8280 // did it), otherwise encode params recursively. 8281 for ( var prefix in a ) { 8282 buildParams( prefix, a[ prefix ], traditional, add ); 8283 } 8284 } 8285 8286 // Return the resulting serialization 8287 return s.join( "&" ).replace( r20, "+" ); 8288 } 8289}); 8290 8291function buildParams( prefix, obj, traditional, add ) { 8292 if ( jQuery.isArray( obj ) ) { 8293 // Serialize array item. 8294 jQuery.each( obj, function( i, v ) { 8295 if ( traditional || rbracket.test( prefix ) ) { 8296 // Treat each array item as a scalar. 8297 add( prefix, v ); 8298 8299 } else { 8300 // If array item is non-scalar (array or object), encode its 8301 // numeric index to resolve deserialization ambiguity issues. 8302 // Note that rack (as of 1.0.0) can't currently deserialize 8303 // nested arrays properly, and attempting to do so may cause 8304 // a server error. Possible fixes are to modify rack's 8305 // deserialization algorithm or to provide an option or flag 8306 // to force array serialization to be shallow. 8307 buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add ); 8308 } 8309 }); 8310 8311 } else if ( !traditional && obj != null && typeof obj === "object" ) { 8312 // Serialize object item. 8313 for ( var name in obj ) { 8314 buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); 8315 } 8316 8317 } else { 8318 // Serialize scalar item. 8319 add( prefix, obj ); 8320 } 8321} 8322 8323// This is still on the jQuery object... for now 8324// Want to move this to jQuery.ajax some day 8325jQuery.extend({ 8326 8327 // Counter for holding the number of active queries 8328 active: 0, 8329 8330 // Last-Modified header cache for next request 8331 lastModified: {}, 8332 etag: {} 8333 8334}); 8335 8336/* Handles responses to an ajax request: 8337 * - sets all responseXXX fields accordingly 8338 * - finds the right dataType (mediates between content-type and expected dataType) 8339 * - returns the corresponding response 8340 */ 8341function ajaxHandleResponses( s, jqXHR, responses ) { 8342 8343 var contents = s.contents, 8344 dataTypes = s.dataTypes, 8345 responseFields = s.responseFields, 8346 ct, 8347 type, 8348 finalDataType, 8349 firstDataType; 8350 8351 // Fill responseXXX fields 8352 for ( type in responseFields ) { 8353 if ( type in responses ) { 8354 jqXHR[ responseFields[type] ] = responses[ type ]; 8355 } 8356 } 8357 8358 // Remove auto dataType and get content-type in the process 8359 while( dataTypes[ 0 ] === "*" ) { 8360 dataTypes.shift(); 8361 if ( ct === undefined ) { 8362 ct = s.mimeType || jqXHR.getResponseHeader( "content-type" ); 8363 } 8364 } 8365 8366 // Check if we're dealing with a known content-type 8367 if ( ct ) { 8368 for ( type in contents ) { 8369 if ( contents[ type ] && contents[ type ].test( ct ) ) { 8370 dataTypes.unshift( type ); 8371 break; 8372 } 8373 } 8374 } 8375 8376 // Check to see if we have a response for the expected dataType 8377 if ( dataTypes[ 0 ] in responses ) { 8378 finalDataType = dataTypes[ 0 ]; 8379 } else { 8380 // Try convertible dataTypes 8381 for ( type in responses ) { 8382 if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { 8383 finalDataType = type; 8384 break; 8385 } 8386 if ( !firstDataType ) { 8387 firstDataType = type; 8388 } 8389 } 8390 // Or just use first one 8391 finalDataType = finalDataType || firstDataType; 8392 } 8393 8394 // If we found a dataType 8395 // We add the dataType to the list if needed 8396 // and return the corresponding response 8397 if ( finalDataType ) { 8398 if ( finalDataType !== dataTypes[ 0 ] ) { 8399 dataTypes.unshift( finalDataType ); 8400 } 8401 return responses[ finalDataType ]; 8402 } 8403} 8404 8405// Chain conversions given the request and the original response 8406function ajaxConvert( s, response ) { 8407 8408 // Apply the dataFilter if provided 8409 if ( s.dataFilter ) { 8410 response = s.dataFilter( response, s.dataType ); 8411 } 8412 8413 var dataTypes = s.dataTypes, 8414 converters = {}, 8415 i, 8416 key, 8417 length = dataTypes.length, 8418 tmp, 8419 // Current and previous dataTypes 8420 current = dataTypes[ 0 ], 8421 prev, 8422 // Conversion expression 8423 conversion, 8424 // Conversion function 8425 conv, 8426 // Conversion functions (transitive conversion) 8427 conv1, 8428 conv2; 8429 8430 // For each dataType in the chain 8431 for ( i = 1; i < length; i++ ) { 8432 8433 // Create converters map 8434 // with lowercased keys 8435 if ( i === 1 ) { 8436 for ( key in s.converters ) { 8437 if ( typeof key === "string" ) { 8438 converters[ key.toLowerCase() ] = s.converters[ key ]; 8439 } 8440 } 8441 } 8442 8443 // Get the dataTypes 8444 prev = current; 8445 current = dataTypes[ i ]; 8446 8447 // If current is auto dataType, update it to prev 8448 if ( current === "*" ) { 8449 current = prev; 8450 // If no auto and dataTypes are actually different 8451 } else if ( prev !== "*" && prev !== current ) { 8452 8453 // Get the converter 8454 conversion = prev + " " + current; 8455 conv = converters[ conversion ] || converters[ "* " + current ]; 8456 8457 // If there is no direct converter, search transitively 8458 if ( !conv ) { 8459 conv2 = undefined; 8460 for ( conv1 in converters ) { 8461 tmp = conv1.split( " " ); 8462 if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) { 8463 conv2 = converters[ tmp[1] + " " + current ]; 8464 if ( conv2 ) { 8465 conv1 = converters[ conv1 ]; 8466 if ( conv1 === true ) { 8467 conv = conv2; 8468 } else if ( conv2 === true ) { 8469 conv = conv1; 8470 } 8471 break; 8472 } 8473 } 8474 } 8475 } 8476 // If we found no converter, dispatch an error 8477 if ( !( conv || conv2 ) ) { 8478 jQuery.error( "No conversion from " + conversion.replace(" "," to ") ); 8479 } 8480 // If found converter is not an equivalence 8481 if ( conv !== true ) { 8482 // Convert with 1 or 2 converters accordingly 8483 response = conv ? conv( response ) : conv2( conv1(response) ); 8484 } 8485 } 8486 } 8487 return response; 8488} 8489 8490 8491 8492 8493var jsc = jQuery.now(), 8494 jsre = /(\=)\?(&|$)|\?\?/i; 8495 8496// Default jsonp settings 8497jQuery.ajaxSetup({ 8498 jsonp: "callback", 8499 jsonpCallback: function() { 8500 return jQuery.expando + "_" + ( jsc++ ); 8501 } 8502}); 8503 8504// Detect, normalize options and install callbacks for jsonp requests 8505jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { 8506 8507 var inspectData = s.contentType === "application/x-www-form-urlencoded" && 8508 ( typeof s.data === "string" ); 8509 8510 if ( s.dataTypes[ 0 ] === "jsonp" || 8511 s.jsonp !== false && ( jsre.test( s.url ) || 8512 inspectData && jsre.test( s.data ) ) ) { 8513 8514 var responseContainer, 8515 jsonpCallback = s.jsonpCallback = 8516 jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback, 8517 previous = window[ jsonpCallback ], 8518 url = s.url, 8519 data = s.data, 8520 replace = "$1" + jsonpCallback + "$2"; 8521 8522 if ( s.jsonp !== false ) { 8523 url = url.replace( jsre, replace ); 8524 if ( s.url === url ) { 8525 if ( inspectData ) { 8526 data = data.replace( jsre, replace ); 8527 } 8528 if ( s.data === data ) { 8529 // Add callback manually 8530 url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback; 8531 } 8532 } 8533 } 8534 8535 s.url = url; 8536 s.data = data; 8537 8538 // Install callback 8539 window[ jsonpCallback ] = function( response ) { 8540 responseContainer = [ response ]; 8541 }; 8542 8543 // Clean-up function 8544 jqXHR.always(function() { 8545 // Set callback back to previous value 8546 window[ jsonpCallback ] = previous; 8547 // Call if it was a function and we have a response 8548 if ( responseContainer && jQuery.isFunction( previous ) ) { 8549 window[ jsonpCallback ]( responseContainer[ 0 ] ); 8550 } 8551 }); 8552 8553 // Use data converter to retrieve json after script execution 8554 s.converters["script json"] = function() { 8555 if ( !responseContainer ) { 8556 jQuery.error( jsonpCallback + " was not called" ); 8557 } 8558 return responseContainer[ 0 ]; 8559 }; 8560 8561 // force json dataType 8562 s.dataTypes[ 0 ] = "json"; 8563 8564 // Delegate to script 8565 return "script"; 8566 } 8567}); 8568 8569 8570 8571 8572// Install script dataType 8573jQuery.ajaxSetup({ 8574 accepts: { 8575 script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" 8576 }, 8577 contents: { 8578 script: /javascript|ecmascript/ 8579 }, 8580 converters: { 8581 "text script": function( text ) { 8582 jQuery.globalEval( text ); 8583 return text; 8584 } 8585 } 8586}); 8587 8588// Handle cache's special case and global 8589jQuery.ajaxPrefilter( "script", function( s ) { 8590 if ( s.cache === undefined ) { 8591 s.cache = false; 8592 } 8593 if ( s.crossDomain ) { 8594 s.type = "GET"; 8595 s.global = false; 8596 } 8597}); 8598 8599// Bind script tag hack transport 8600jQuery.ajaxTransport( "script", function(s) { 8601 8602 // This transport only deals with cross domain requests 8603 if ( s.crossDomain ) { 8604 8605 var script, 8606 head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement; 8607 8608 return { 8609 8610 send: function( _, callback ) { 8611 8612 script = document.createElement( "script" ); 8613 8614 script.async = "async"; 8615 8616 if ( s.scriptCharset ) { 8617 script.charset = s.scriptCharset; 8618 } 8619 8620 script.src = s.url; 8621 8622 // Attach handlers for all browsers 8623 script.onload = script.onreadystatechange = function( _, isAbort ) { 8624 8625 if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { 8626 8627 // Handle memory leak in IE 8628 script.onload = script.onreadystatechange = null; 8629 8630 // Remove the script 8631 if ( head && script.parentNode ) { 8632 head.removeChild( script ); 8633 } 8634 8635 // Dereference the script 8636 script = undefined; 8637 8638 // Callback if not abort 8639 if ( !isAbort ) { 8640 callback( 200, "success" ); 8641 } 8642 } 8643 }; 8644 // Use insertBefore instead of appendChild to circumvent an IE6 bug. 8645 // This arises when a base node is used (#2709 and #4378). 8646 head.insertBefore( script, head.firstChild ); 8647 }, 8648 8649 abort: function() { 8650 if ( script ) { 8651 script.onload( 0, 1 ); 8652 } 8653 } 8654 }; 8655 } 8656}); 8657 8658 8659 8660 8661var // #5280: Internet Explorer will keep connections alive if we don't abort on unload 8662 xhrOnUnloadAbort = window.ActiveXObject ? function() { 8663 // Abort all pending requests 8664 for ( var key in xhrCallbacks ) { 8665 xhrCallbacks[ key ]( 0, 1 ); 8666 } 8667 } : false, 8668 xhrId = 0, 8669 xhrCallbacks; 8670 8671// Functions to create xhrs 8672function createStandardXHR() { 8673 try { 8674 return new window.XMLHttpRequest(); 8675 } catch( e ) {} 8676} 8677 8678function createActiveXHR() { 8679 try { 8680 return new window.ActiveXObject( "Microsoft.XMLHTTP" ); 8681 } catch( e ) {} 8682} 8683 8684// Create the request object 8685// (This is still attached to ajaxSettings for backward compatibility) 8686jQuery.ajaxSettings.xhr = window.ActiveXObject ? 8687 /* Microsoft failed to properly 8688 * implement the XMLHttpRequest in IE7 (can't request local files), 8689 * so we use the ActiveXObject when it is available 8690 * Additionally XMLHttpRequest can be disabled in IE7/IE8 so 8691 * we need a fallback. 8692 */ 8693 function() { 8694 return !this.isLocal && createStandardXHR() || createActiveXHR(); 8695 } : 8696 // For all other browsers, use the standard XMLHttpRequest object 8697 createStandardXHR; 8698 8699// Determine support properties 8700(function( xhr ) { 8701 jQuery.extend( jQuery.support, { 8702 ajax: !!xhr, 8703 cors: !!xhr && ( "withCredentials" in xhr ) 8704 }); 8705})( jQuery.ajaxSettings.xhr() ); 8706 8707// Create transport if the browser can provide an xhr 8708if ( jQuery.support.ajax ) { 8709 8710 jQuery.ajaxTransport(function( s ) { 8711 // Cross domain only allowed if supported through XMLHttpRequest 8712 if ( !s.crossDomain || jQuery.support.cors ) { 8713 8714 var callback; 8715 8716 return { 8717 send: function( headers, complete ) { 8718 8719 // Get a new xhr 8720 var xhr = s.xhr(), 8721 handle, 8722 i; 8723 8724 // Open the socket 8725 // Passing null username, generates a login popup on Opera (#2865) 8726 if ( s.username ) { 8727 xhr.open( s.type, s.url, s.async, s.username, s.password ); 8728 } else { 8729 xhr.open( s.type, s.url, s.async ); 8730 } 8731 8732 // Apply custom fields if provided 8733 if ( s.xhrFields ) { 8734 for ( i in s.xhrFields ) { 8735 xhr[ i ] = s.xhrFields[ i ]; 8736 } 8737 } 8738 8739 // Override mime type if needed 8740 if ( s.mimeType && xhr.overrideMimeType ) { 8741 xhr.overrideMimeType( s.mimeType ); 8742 } 8743 8744 // X-Requested-With header 8745 // For cross-domain requests, seeing as conditions for a preflight are 8746 // akin to a jigsaw puzzle, we simply never set it to be sure. 8747 // (it can always be set on a per-request basis or even using ajaxSetup) 8748 // For same-domain requests, won't change header if already provided. 8749 if ( !s.crossDomain && !headers["X-Requested-With"] ) { 8750 headers[ "X-Requested-With" ] = "XMLHttpRequest"; 8751 } 8752 8753 // Need an extra try/catch for cross domain requests in Firefox 3 8754 try { 8755 for ( i in headers ) { 8756 xhr.setRequestHeader( i, headers[ i ] ); 8757 } 8758 } catch( _ ) {} 8759 8760 // Do send the request 8761 // This may raise an exception which is actually 8762 // handled in jQuery.ajax (so no try/catch here) 8763 xhr.send( ( s.hasContent && s.data ) || null ); 8764 8765 // Listener 8766 callback = function( _, isAbort ) { 8767 8768 var status, 8769 statusText, 8770 responseHeaders, 8771 responses, 8772 xml; 8773 8774 // Firefox throws exceptions when accessing properties 8775 // of an xhr when a network error occured 8776 // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE) 8777 try { 8778 8779 // Was never called and is aborted or complete 8780 if ( callback && ( isAbort || xhr.readyState === 4 ) ) { 8781 8782 // Only called once 8783 callback = undefined; 8784 8785 // Do not keep as active anymore 8786 if ( handle ) { 8787 xhr.onreadystatechange = jQuery.noop; 8788 if ( xhrOnUnloadAbort ) { 8789 delete xhrCallbacks[ handle ]; 8790 } 8791 } 8792 8793 // If it's an abort 8794 if ( isAbort ) { 8795 // Abort it manually if needed 8796 if ( xhr.readyState !== 4 ) { 8797 xhr.abort(); 8798 } 8799 } else { 8800 status = xhr.status; 8801 responseHeaders = xhr.getAllResponseHeaders(); 8802 responses = {}; 8803 xml = xhr.responseXML; 8804 8805 // Construct response list 8806 if ( xml && xml.documentElement /* #4958 */ ) { 8807 responses.xml = xml; 8808 } 8809 responses.text = xhr.responseText; 8810 8811 // Firefox throws an exception when accessing 8812 // statusText for faulty cross-domain requests 8813 try { 8814 statusText = xhr.statusText; 8815 } catch( e ) { 8816 // We normalize with Webkit giving an empty statusText 8817 statusText = ""; 8818 } 8819 8820 // Filter status for non standard behaviors 8821 8822 // If the request is local and we have data: assume a success 8823 // (success with no data won't get notified, that's the best we 8824 // can do given current implementations) 8825 if ( !status && s.isLocal && !s.crossDomain ) { 8826 status = responses.text ? 200 : 404; 8827 // IE - #1450: sometimes returns 1223 when it should be 204 8828 } else if ( status === 1223 ) { 8829 status = 204; 8830 } 8831 } 8832 } 8833 } catch( firefoxAccessException ) { 8834 if ( !isAbort ) { 8835 complete( -1, firefoxAccessException ); 8836 } 8837 } 8838 8839 // Call complete if needed 8840 if ( responses ) { 8841 complete( status, statusText, responses, responseHeaders ); 8842 } 8843 }; 8844 8845 // if we're in sync mode or it's in cache 8846 // and has been retrieved directly (IE6 & IE7) 8847 // we need to manually fire the callback 8848 if ( !s.async || xhr.readyState === 4 ) { 8849 callback(); 8850 } else { 8851 handle = ++xhrId; 8852 if ( xhrOnUnloadAbort ) { 8853 // Create the active xhrs callbacks list if needed 8854 // and attach the unload handler 8855 if ( !xhrCallbacks ) { 8856 xhrCallbacks = {}; 8857 jQuery( window ).unload( xhrOnUnloadAbort ); 8858 } 8859 // Add to list of active xhrs callbacks 8860 xhrCallbacks[ handle ] = callback; 8861 } 8862 xhr.onreadystatechange = callback; 8863 } 8864 }, 8865 8866 abort: function() { 8867 if ( callback ) { 8868 callback(0,1); 8869 } 8870 } 8871 }; 8872 } 8873 }); 8874} 8875 8876 8877 8878 8879var elemdisplay = {}, 8880 iframe, iframeDoc, 8881 rfxtypes = /^(?:toggle|show|hide)$/, 8882 rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i, 8883 timerId, 8884 fxAttrs = [ 8885 // height animations 8886 [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ], 8887 // width animations 8888 [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ], 8889 // opacity animations 8890 [ "opacity" ] 8891 ], 8892 fxNow; 8893 8894jQuery.fn.extend({ 8895 show: function( speed, easing, callback ) { 8896 var elem, display; 8897 8898 if ( speed || speed === 0 ) { 8899 return this.animate( genFx("show", 3), speed, easing, callback ); 8900 8901 } else { 8902 for ( var i = 0, j = this.length; i < j; i++ ) { 8903 elem = this[ i ]; 8904 8905 if ( elem.style ) { 8906 display = elem.style.display; 8907 8908 // Reset the inline display of this element to learn if it is 8909 // being hidden by cascaded rules or not 8910 if ( !jQuery._data(elem, "olddisplay") && display === "none" ) { 8911 display = elem.style.display = ""; 8912 } 8913 8914 // Set elements which have been overridden with display: none 8915 // in a stylesheet to whatever the default browser style is 8916 // for such an element 8917 if ( display === "" && jQuery.css(elem, "display") === "none" ) { 8918 jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) ); 8919 } 8920 } 8921 } 8922 8923 // Set the display of most of the elements in a second loop 8924 // to avoid the constant reflow 8925 for ( i = 0; i < j; i++ ) { 8926 elem = this[ i ]; 8927 8928 if ( elem.style ) { 8929 display = elem.style.display; 8930 8931 if ( display === "" || display === "none" ) { 8932 elem.style.display = jQuery._data( elem, "olddisplay" ) || ""; 8933 } 8934 } 8935 } 8936 8937 return this; 8938 } 8939 }, 8940 8941 hide: function( speed, easing, callback ) { 8942 if ( speed || speed === 0 ) { 8943 return this.animate( genFx("hide", 3), speed, easing, callback); 8944 8945 } else { 8946 var elem, display, 8947 i = 0, 8948 j = this.length; 8949 8950 for ( ; i < j; i++ ) { 8951 elem = this[i]; 8952 if ( elem.style ) { 8953 display = jQuery.css( elem, "display" ); 8954 8955 if ( display !== "none" && !jQuery._data( elem, "olddisplay" ) ) { 8956 jQuery._data( elem, "olddisplay", display ); 8957 } 8958 } 8959 } 8960 8961 // Set the display of the elements in a second loop 8962 // to avoid the constant reflow 8963 for ( i = 0; i < j; i++ ) { 8964 if ( this[i].style ) { 8965 this[i].style.display = "none"; 8966 } 8967 } 8968 8969 return this; 8970 } 8971 }, 8972 8973 // Save the old toggle function 8974 _toggle: jQuery.fn.toggle, 8975 8976 toggle: function( fn, fn2, callback ) { 8977 var bool = typeof fn === "boolean"; 8978 8979 if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) { 8980 this._toggle.apply( this, arguments ); 8981 8982 } else if ( fn == null || bool ) { 8983 this.each(function() { 8984 var state = bool ? fn : jQuery(this).is(":hidden"); 8985 jQuery(this)[ state ? "show" : "hide" ](); 8986 }); 8987 8988 } else { 8989 this.animate(genFx("toggle", 3), fn, fn2, callback); 8990 } 8991 8992 return this; 8993 }, 8994 8995 fadeTo: function( speed, to, easing, callback ) { 8996 return this.filter(":hidden").css("opacity", 0).show().end() 8997 .animate({opacity: to}, speed, easing, callback); 8998 }, 8999 9000 animate: function( prop, speed, easing, callback ) { 9001 var optall = jQuery.speed( speed, easing, callback ); 9002 9003 if ( jQuery.isEmptyObject( prop ) ) { 9004 return this.each( optall.complete, [ false ] ); 9005 } 9006 9007 // Do not change referenced properties as per-property easing will be lost 9008 prop = jQuery.extend( {}, prop ); 9009 9010 function doAnimation() { 9011 // XXX 'this' does not always have a nodeName when running the 9012 // test suite 9013 9014 if ( optall.queue === false ) { 9015 jQuery._mark( this ); 9016 } 9017 9018 var opt = jQuery.extend( {}, optall ), 9019 isElement = this.nodeType === 1, 9020 hidden = isElement && jQuery(this).is(":hidden"), 9021 name, val, p, e, 9022 parts, start, end, unit, 9023 method; 9024 9025 // will store per property easing and be used to determine when an animation is complete 9026 opt.animatedProperties = {}; 9027 9028 for ( p in prop ) { 9029 9030 // property name normalization 9031 name = jQuery.camelCase( p ); 9032 if ( p !== name ) { 9033 prop[ name ] = prop[ p ]; 9034 delete prop[ p ]; 9035 } 9036 9037 val = prop[ name ]; 9038 9039 // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default) 9040 if ( jQuery.isArray( val ) ) { 9041 opt.animatedProperties[ name ] = val[ 1 ]; 9042 val = prop[ name ] = val[ 0 ]; 9043 } else { 9044 opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing'; 9045 } 9046 9047 if ( val === "hide" && hidden || val === "show" && !hidden ) { 9048 return opt.complete.call( this ); 9049 } 9050 9051 if ( isElement && ( name === "height" || name === "width" ) ) { 9052 // Make sure that nothing sneaks out 9053 // Record all 3 overflow attributes because IE does not 9054 // change the overflow attribute when overflowX and 9055 // overflowY are set to the same value 9056 opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ]; 9057 9058 // Set display property to inline-block for height/width 9059 // animations on inline elements that are having width/height animated 9060 if ( jQuery.css( this, "display" ) === "inline" && 9061 jQuery.css( this, "float" ) === "none" ) { 9062 9063 // inline-level elements accept inline-block; 9064 // block-level elements need to be inline with layout 9065 if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === "inline" ) { 9066 this.style.display = "inline-block"; 9067 9068 } else { 9069 this.style.zoom = 1; 9070 } 9071 } 9072 } 9073 } 9074 9075 if ( opt.overflow != null ) { 9076 this.style.overflow = "hidden"; 9077 } 9078 9079 for ( p in prop ) { 9080 e = new jQuery.fx( this, opt, p ); 9081 val = prop[ p ]; 9082 9083 if ( rfxtypes.test( val ) ) { 9084 9085 // Tracks whether to show or hide based on private 9086 // data attached to the element 9087 method = jQuery._data( this, "toggle" + p ) || ( val === "toggle" ? hidden ? "show" : "hide" : 0 ); 9088 if ( method ) { 9089 jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" ); 9090 e[ method ](); 9091 } else { 9092 e[ val ](); 9093 } 9094 9095 } else { 9096 parts = rfxnum.exec( val ); 9097 start = e.cur(); 9098 9099 if ( parts ) { 9100 end = parseFloat( parts[2] ); 9101 unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" ); 9102 9103 // We need to compute starting value 9104 if ( unit !== "px" ) { 9105 jQuery.style( this, p, (end || 1) + unit); 9106 start = ( (end || 1) / e.cur() ) * start; 9107 jQuery.style( this, p, start + unit); 9108 } 9109 9110 // If a +=/-= token was provided, we're doing a relative animation 9111 if ( parts[1] ) { 9112 end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start; 9113 } 9114 9115 e.custom( start, end, unit ); 9116 9117 } else { 9118 e.custom( start, val, "" ); 9119 } 9120 } 9121 } 9122 9123 // For JS strict compliance 9124 return true; 9125 } 9126 9127 return optall.queue === false ? 9128 this.each( doAnimation ) : 9129 this.queue( optall.queue, doAnimation ); 9130 }, 9131 9132 stop: function( type, clearQueue, gotoEnd ) { 9133 if ( typeof type !== "string" ) { 9134 gotoEnd = clearQueue; 9135 clearQueue = type; 9136 type = undefined; 9137 } 9138 if ( clearQueue && type !== false ) { 9139 this.queue( type || "fx", [] ); 9140 } 9141 9142 return this.each(function() { 9143 var i, 9144 hadTimers = false, 9145 timers = jQuery.timers, 9146 data = jQuery._data( this ); 9147 9148 // clear marker counters if we know they won't be 9149 if ( !gotoEnd ) { 9150 jQuery._unmark( true, this ); 9151 } 9152 9153 function stopQueue( elem, data, i ) { 9154 var hooks = data[ i ]; 9155 jQuery.removeData( elem, i, true ); 9156 hooks.stop( gotoEnd ); 9157 } 9158 9159 if ( type == null ) { 9160 for ( i in data ) { 9161 if ( data[ i ].stop && i.indexOf(".run") === i.length - 4 ) { 9162 stopQueue( this, data, i ); 9163 } 9164 } 9165 } else if ( data[ i = type + ".run" ] && data[ i ].stop ){ 9166 stopQueue( this, data, i ); 9167 } 9168 9169 for ( i = timers.length; i--; ) { 9170 if ( timers[ i ].elem === this && (type == null || timers[ i ].queue === type) ) { 9171 if ( gotoEnd ) { 9172 9173 // force the next step to be the last 9174 timers[ i ]( true ); 9175 } else { 9176 timers[ i ].saveState(); 9177 } 9178 hadTimers = true; 9179 timers.splice( i, 1 ); 9180 } 9181 } 9182 9183 // start the next in the queue if the last step wasn't forced 9184 // timers currently will call their complete callbacks, which will dequeue 9185 // but only if they were gotoEnd 9186 if ( !( gotoEnd && hadTimers ) ) { 9187 jQuery.dequeue( this, type ); 9188 } 9189 }); 9190 } 9191 9192}); 9193 9194// Animations created synchronously will run synchronously 9195function createFxNow() { 9196 setTimeout( clearFxNow, 0 ); 9197 return ( fxNow = jQuery.now() ); 9198} 9199 9200function clearFxNow() { 9201 fxNow = undefined; 9202} 9203 9204// Generate parameters to create a standard animation 9205function genFx( type, num ) { 9206 var obj = {}; 9207 9208 jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() { 9209 obj[ this ] = type; 9210 }); 9211 9212 return obj; 9213} 9214 9215// Generate shortcuts for custom animations 9216jQuery.each({ 9217 slideDown: genFx( "show", 1 ), 9218 slideUp: genFx( "hide", 1 ), 9219 slideToggle: genFx( "toggle", 1 ), 9220 fadeIn: { opacity: "show" }, 9221 fadeOut: { opacity: "hide" }, 9222 fadeToggle: { opacity: "toggle" } 9223}, function( name, props ) { 9224 jQuery.fn[ name ] = function( speed, easing, callback ) { 9225 return this.animate( props, speed, easing, callback ); 9226 }; 9227}); 9228 9229jQuery.extend({ 9230 speed: function( speed, easing, fn ) { 9231 var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { 9232 complete: fn || !fn && easing || 9233 jQuery.isFunction( speed ) && speed, 9234 duration: speed, 9235 easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing 9236 }; 9237 9238 opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : 9239 opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; 9240 9241 // normalize opt.queue - true/undefined/null -> "fx" 9242 if ( opt.queue == null || opt.queue === true ) { 9243 opt.queue = "fx"; 9244 } 9245 9246 // Queueing 9247 opt.old = opt.complete; 9248 9249 opt.complete = function( noUnmark ) { 9250 if ( jQuery.isFunction( opt.old ) ) { 9251 opt.old.call( this ); 9252 } 9253 9254 if ( opt.queue ) { 9255 jQuery.dequeue( this, opt.queue ); 9256 } else if ( noUnmark !== false ) { 9257 jQuery._unmark( this ); 9258 } 9259 }; 9260 9261 return opt; 9262 }, 9263 9264 easing: { 9265 linear: function( p, n, firstNum, diff ) { 9266 return firstNum + diff * p; 9267 }, 9268 swing: function( p, n, firstNum, diff ) { 9269 return ( ( -Math.cos( p*Math.PI ) / 2 ) + 0.5 ) * diff + firstNum; 9270 } 9271 }, 9272 9273 timers: [], 9274 9275 fx: function( elem, options, prop ) { 9276 this.options = options; 9277 this.elem = elem; 9278 this.prop = prop; 9279 9280 options.orig = options.orig || {}; 9281 } 9282 9283}); 9284 9285jQuery.fx.prototype = { 9286 // Simple function for setting a style value 9287 update: function() { 9288 if ( this.options.step ) { 9289 this.options.step.call( this.elem, this.now, this ); 9290 } 9291 9292 ( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this ); 9293 }, 9294 9295 // Get the current size 9296 cur: function() { 9297 if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) { 9298 return this.elem[ this.prop ]; 9299 } 9300 9301 var parsed, 9302 r = jQuery.css( this.elem, this.prop ); 9303 // Empty strings, null, undefined and "auto" are converted to 0, 9304 // complex values such as "rotate(1rad)" are returned as is, 9305 // simple values such as "10px" are parsed to Float. 9306 return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed; 9307 }, 9308 9309 // Start an animation from one number to another 9310 custom: function( from, to, unit ) { 9311 var self = this, 9312 fx = jQuery.fx; 9313 9314 this.startTime = fxNow || createFxNow(); 9315 this.end = to; 9316 this.now = this.start = from; 9317 this.pos = this.state = 0; 9318 this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" ); 9319 9320 function t( gotoEnd ) { 9321 return self.step( gotoEnd ); 9322 } 9323 9324 t.queue = this.options.queue; 9325 t.elem = this.elem; 9326 t.saveState = function() { 9327 if ( self.options.hide && jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) { 9328 jQuery._data( self.elem, "fxshow" + self.prop, self.start ); 9329 } 9330 }; 9331 9332 if ( t() && jQuery.timers.push(t) && !timerId ) { 9333 timerId = setInterval( fx.tick, fx.interval ); 9334 } 9335 }, 9336 9337 // Simple 'show' function 9338 show: function() { 9339 var dataShow = jQuery._data( this.elem, "fxshow" + this.prop ); 9340 9341 // Remember where we started, so that we can go back to it later 9342 this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop ); 9343 this.options.show = true; 9344 9345 // Begin the animation 9346 // Make sure that we start at a small width/height to avoid any flash of content 9347 if ( dataShow !== undefined ) { 9348 // This show is picking up where a previous hide or show left off 9349 this.custom( this.cur(), dataShow ); 9350 } else { 9351 this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() ); 9352 } 9353 9354 // Start by showing the element 9355 jQuery( this.elem ).show(); 9356 }, 9357 9358 // Simple 'hide' function 9359 hide: function() { 9360 // Remember where we started, so that we can go back to it later 9361 this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop ); 9362 this.options.hide = true; 9363 9364 // Begin the animation 9365 this.custom( this.cur(), 0 ); 9366 }, 9367 9368 // Each step of an animation 9369 step: function( gotoEnd ) { 9370 var p, n, complete, 9371 t = fxNow || createFxNow(), 9372 done = true, 9373 elem = this.elem, 9374 options = this.options; 9375 9376 if ( gotoEnd || t >= options.duration + this.startTime ) { 9377 this.now = this.end; 9378 this.pos = this.state = 1; 9379 this.update(); 9380 9381 options.animatedProperties[ this.prop ] = true; 9382 9383 for ( p in options.animatedProperties ) { 9384 if ( options.animatedProperties[ p ] !== true ) { 9385 done = false; 9386 } 9387 } 9388 9389 if ( done ) { 9390 // Reset the overflow 9391 if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) { 9392 9393 jQuery.each( [ "", "X", "Y" ], function( index, value ) { 9394 elem.style[ "overflow" + value ] = options.overflow[ index ]; 9395 }); 9396 } 9397 9398 // Hide the element if the "hide" operation was done 9399 if ( options.hide ) { 9400 jQuery( elem ).hide(); 9401 } 9402 9403 // Reset the properties, if the item has been hidden or shown 9404 if ( options.hide || options.show ) { 9405 for ( p in options.animatedProperties ) { 9406 jQuery.style( elem, p, options.orig[ p ] ); 9407 jQuery.removeData( elem, "fxshow" + p, true ); 9408 // Toggle data is no longer needed 9409 jQuery.removeData( elem, "toggle" + p, true ); 9410 } 9411 } 9412 9413 // Execute the complete function 9414 // in the event that the complete function throws an exception 9415 // we must ensure it won't be called twice. #5684 9416 9417 complete = options.complete; 9418 if ( complete ) { 9419 9420 options.complete = false; 9421 complete.call( elem ); 9422 } 9423 } 9424 9425 return false; 9426 9427 } else { 9428 // classical easing cannot be used with an Infinity duration 9429 if ( options.duration == Infinity ) { 9430 this.now = t; 9431 } else { 9432 n = t - this.startTime; 9433 this.state = n / options.duration; 9434 9435 // Perform the easing function, defaults to swing 9436 this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration ); 9437 this.now = this.start + ( (this.end - this.start) * this.pos ); 9438 } 9439 // Perform the next step of the animation 9440 this.update(); 9441 } 9442 9443 return true; 9444 } 9445}; 9446 9447jQuery.extend( jQuery.fx, { 9448 tick: function() { 9449 var timer, 9450 timers = jQuery.timers, 9451 i = 0; 9452 9453 for ( ; i < timers.length; i++ ) { 9454 timer = timers[ i ]; 9455 // Checks the timer has not already been removed 9456 if ( !timer() && timers[ i ] === timer ) { 9457 timers.splice( i--, 1 ); 9458 } 9459 } 9460 9461 if ( !timers.length ) { 9462 jQuery.fx.stop(); 9463 } 9464 }, 9465 9466 interval: 13, 9467 9468 stop: function() { 9469 clearInterval( timerId ); 9470 timerId = null; 9471 }, 9472 9473 speeds: { 9474 slow: 600, 9475 fast: 200, 9476 // Default speed 9477 _default: 400 9478 }, 9479 9480 step: { 9481 opacity: function( fx ) { 9482 jQuery.style( fx.elem, "opacity", fx.now ); 9483 }, 9484 9485 _default: function( fx ) { 9486 if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) { 9487 fx.elem.style[ fx.prop ] = fx.now + fx.unit; 9488 } else { 9489 fx.elem[ fx.prop ] = fx.now; 9490 } 9491 } 9492 } 9493}); 9494 9495// Adds width/height step functions 9496// Do not set anything below 0 9497jQuery.each([ "width", "height" ], function( i, prop ) { 9498 jQuery.fx.step[ prop ] = function( fx ) { 9499 jQuery.style( fx.elem, prop, Math.max(0, fx.now) ); 9500 }; 9501}); 9502 9503if ( jQuery.expr && jQuery.expr.filters ) { 9504 jQuery.expr.filters.animated = function( elem ) { 9505 return jQuery.grep(jQuery.timers, function( fn ) { 9506 return elem === fn.elem; 9507 }).length; 9508 }; 9509} 9510 9511// Try to restore the default display value of an element 9512function defaultDisplay( nodeName ) { 9513 9514 if ( !elemdisplay[ nodeName ] ) { 9515 9516 var body = document.body, 9517 elem = jQuery( "<" + nodeName + ">" ).appendTo( body ), 9518 display = elem.css( "display" ); 9519 elem.remove(); 9520 9521 // If the simple way fails, 9522 // get element's real default display by attaching it to a temp iframe 9523 if ( display === "none" || display === "" ) { 9524 // No iframe to use yet, so create it 9525 if ( !iframe ) { 9526 iframe = document.createElement( "iframe" ); 9527 iframe.frameBorder = iframe.width = iframe.height = 0; 9528 } 9529 9530 body.appendChild( iframe ); 9531 9532 // Create a cacheable copy of the iframe document on first call. 9533 // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML 9534 // document to it; WebKit & Firefox won't allow reusing the iframe document. 9535 if ( !iframeDoc || !iframe.createElement ) { 9536 iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; 9537 iframeDoc.write( ( document.compatMode === "CSS1Compat" ? "<!doctype html>" : "" ) + "<html><body>" ); 9538 iframeDoc.close(); 9539 } 9540 9541 elem = iframeDoc.createElement( nodeName ); 9542 9543 iframeDoc.body.appendChild( elem ); 9544 9545 display = jQuery.css( elem, "display" ); 9546 body.removeChild( iframe ); 9547 } 9548 9549 // Store the correct default display 9550 elemdisplay[ nodeName ] = display; 9551 } 9552 9553 return elemdisplay[ nodeName ]; 9554} 9555 9556 9557 9558 9559var rtable = /^t(?:able|d|h)$/i, 9560 rroot = /^(?:body|html)$/i; 9561 9562if ( "getBoundingClientRect" in document.documentElement ) { 9563 jQuery.fn.offset = function( options ) { 9564 var elem = this[0], box; 9565 9566 if ( options ) { 9567 return this.each(function( i ) { 9568 jQuery.offset.setOffset( this, options, i ); 9569 }); 9570 } 9571 9572 if ( !elem || !elem.ownerDocument ) { 9573 return null; 9574 } 9575 9576 if ( elem === elem.ownerDocument.body ) { 9577 return jQuery.offset.bodyOffset( elem ); 9578 } 9579 9580 try { 9581 box = elem.getBoundingClientRect(); 9582 } catch(e) {} 9583 9584 var doc = elem.ownerDocument, 9585 docElem = doc.documentElement; 9586 9587 // Make sure we're not dealing with a disconnected DOM node 9588 if ( !box || !jQuery.contains( docElem, elem ) ) { 9589 return box ? { top: box.top, left: box.left } : { top: 0, left: 0 }; 9590 } 9591 9592 var body = doc.body, 9593 win = getWindow(doc), 9594 clientTop = docElem.clientTop || body.clientTop || 0, 9595 clientLeft = docElem.clientLeft || body.clientLeft || 0, 9596 scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop, 9597 scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft, 9598 top = box.top + scrollTop - clientTop, 9599 left = box.left + scrollLeft - clientLeft; 9600 9601 return { top: top, left: left }; 9602 }; 9603 9604} else { 9605 jQuery.fn.offset = function( options ) { 9606 var elem = this[0]; 9607 9608 if ( options ) { 9609 return this.each(function( i ) { 9610 jQuery.offset.setOffset( this, options, i ); 9611 }); 9612 } 9613 9614 if ( !elem || !elem.ownerDocument ) { 9615 return null; 9616 } 9617 9618 if ( elem === elem.ownerDocument.body ) { 9619 return jQuery.offset.bodyOffset( elem ); 9620 } 9621 9622 var computedStyle, 9623 offsetParent = elem.offsetParent, 9624 prevOffsetParent = elem, 9625 doc = elem.ownerDocument, 9626 docElem = doc.documentElement, 9627 body = doc.body, 9628 defaultView = doc.defaultView, 9629 prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle, 9630 top = elem.offsetTop, 9631 left = elem.offsetLeft; 9632 9633 while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) { 9634 if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) { 9635 break; 9636 } 9637 9638 computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle; 9639 top -= elem.scrollTop; 9640 left -= elem.scrollLeft; 9641 9642 if ( elem === offsetParent ) { 9643 top += elem.offsetTop; 9644 left += elem.offsetLeft; 9645 9646 if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) { 9647 top += parseFloat( computedStyle.borderTopWidth ) || 0; 9648 left += parseFloat( computedStyle.borderLeftWidth ) || 0; 9649 } 9650 9651 prevOffsetParent = offsetParent; 9652 offsetParent = elem.offsetParent; 9653 } 9654 9655 if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) { 9656 top += parseFloat( computedStyle.borderTopWidth ) || 0; 9657 left += parseFloat( computedStyle.borderLeftWidth ) || 0; 9658 } 9659 9660 prevComputedStyle = computedStyle; 9661 } 9662 9663 if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) { 9664 top += body.offsetTop; 9665 left += body.offsetLeft; 9666 } 9667 9668 if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) { 9669 top += Math.max( docElem.scrollTop, body.scrollTop ); 9670 left += Math.max( docElem.scrollLeft, body.scrollLeft ); 9671 } 9672 9673 return { top: top, left: left }; 9674 }; 9675} 9676 9677jQuery.offset = { 9678 9679 bodyOffset: function( body ) { 9680 var top = body.offsetTop, 9681 left = body.offsetLeft; 9682 9683 if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) { 9684 top += parseFloat( jQuery.css(body, "marginTop") ) || 0; 9685 left += parseFloat( jQuery.css(body, "marginLeft") ) || 0; 9686 } 9687 9688 return { top: top, left: left }; 9689 }, 9690 9691 setOffset: function( elem, options, i ) { 9692 var position = jQuery.css( elem, "position" ); 9693 9694 // set position first, in-case top/left are set even on static elem 9695 if ( position === "static" ) { 9696 elem.style.position = "relative"; 9697 } 9698 9699 var curElem = jQuery( elem ), 9700 curOffset = curElem.offset(), 9701 curCSSTop = jQuery.css( elem, "top" ), 9702 curCSSLeft = jQuery.css( elem, "left" ), 9703 calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, 9704 props = {}, curPosition = {}, curTop, curLeft; 9705 9706 // need to be able to calculate position if either top or left is auto and position is either absolute or fixed 9707 if ( calculatePosition ) { 9708 curPosition = curElem.position(); 9709 curTop = curPosition.top; 9710 curLeft = curPosition.left; 9711 } else { 9712 curTop = parseFloat( curCSSTop ) || 0; 9713 curLeft = parseFloat( curCSSLeft ) || 0; 9714 } 9715 9716 if ( jQuery.isFunction( options ) ) { 9717 options = options.call( elem, i, curOffset ); 9718 } 9719 9720 if ( options.top != null ) { 9721 props.top = ( options.top - curOffset.top ) + curTop; 9722 } 9723 if ( options.left != null ) { 9724 props.left = ( options.left - curOffset.left ) + curLeft; 9725 } 9726 9727 if ( "using" in options ) { 9728 options.using.call( elem, props ); 9729 } else { 9730 curElem.css( props ); 9731 } 9732 } 9733}; 9734 9735 9736jQuery.fn.extend({ 9737 9738 position: function() { 9739 if ( !this[0] ) { 9740 return null; 9741 } 9742 9743 var elem = this[0], 9744 9745 // Get *real* offsetParent 9746 offsetParent = this.offsetParent(), 9747 9748 // Get correct offsets 9749 offset = this.offset(), 9750 parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset(); 9751 9752 // Subtract element margins 9753 // note: when an element has margin: auto the offsetLeft and marginLeft 9754 // are the same in Safari causing offset.left to incorrectly be 0 9755 offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0; 9756 offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0; 9757 9758 // Add offsetParent borders 9759 parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0; 9760 parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0; 9761 9762 // Subtract the two offsets 9763 return { 9764 top: offset.top - parentOffset.top, 9765 left: offset.left - parentOffset.left 9766 }; 9767 }, 9768 9769 offsetParent: function() { 9770 return this.map(function() { 9771 var offsetParent = this.offsetParent || document.body; 9772 while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) { 9773 offsetParent = offsetParent.offsetParent; 9774 } 9775 return offsetParent; 9776 }); 9777 } 9778}); 9779 9780 9781// Create scrollLeft and scrollTop methods 9782jQuery.each( ["Left", "Top"], function( i, name ) { 9783 var method = "scroll" + name; 9784 9785 jQuery.fn[ method ] = function( val ) { 9786 var elem, win; 9787 9788 if ( val === undefined ) { 9789 elem = this[ 0 ]; 9790 9791 if ( !elem ) { 9792 return null; 9793 } 9794 9795 win = getWindow( elem ); 9796 9797 // Return the scroll offset 9798 return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] : 9799 jQuery.support.boxModel && win.document.documentElement[ method ] || 9800 win.document.body[ method ] : 9801 elem[ method ]; 9802 } 9803 9804 // Set the scroll offset 9805 return this.each(function() { 9806 win = getWindow( this ); 9807 9808 if ( win ) { 9809 win.scrollTo( 9810 !i ? val : jQuery( win ).scrollLeft(), 9811 i ? val : jQuery( win ).scrollTop() 9812 ); 9813 9814 } else { 9815 this[ method ] = val; 9816 } 9817 }); 9818 }; 9819}); 9820 9821function getWindow( elem ) { 9822 return jQuery.isWindow( elem ) ? 9823 elem : 9824 elem.nodeType === 9 ? 9825 elem.defaultView || elem.parentWindow : 9826 false; 9827} 9828 9829 9830 9831 9832// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods 9833jQuery.each([ "Height", "Width" ], function( i, name ) { 9834 9835 var type = name.toLowerCase(); 9836 9837 // innerHeight and innerWidth 9838 jQuery.fn[ "inner" + name ] = function() { 9839 var elem = this[0]; 9840 return elem ? 9841 elem.style ? 9842 parseFloat( jQuery.css( elem, type, "padding" ) ) : 9843 this[ type ]() : 9844 null; 9845 }; 9846 9847 // outerHeight and outerWidth 9848 jQuery.fn[ "outer" + name ] = function( margin ) { 9849 var elem = this[0]; 9850 return elem ? 9851 elem.style ? 9852 parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) : 9853 this[ type ]() : 9854 null; 9855 }; 9856 9857 jQuery.fn[ type ] = function( size ) { 9858 // Get window width or height 9859 var elem = this[0]; 9860 if ( !elem ) { 9861 return size == null ? null : this; 9862 } 9863 9864 if ( jQuery.isFunction( size ) ) { 9865 return this.each(function( i ) { 9866 var self = jQuery( this ); 9867 self[ type ]( size.call( this, i, self[ type ]() ) ); 9868 }); 9869 } 9870 9871 if ( jQuery.isWindow( elem ) ) { 9872 // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode 9873 // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat 9874 var docElemProp = elem.document.documentElement[ "client" + name ], 9875 body = elem.document.body; 9876 return elem.document.compatMode === "CSS1Compat" && docElemProp || 9877 body && body[ "client" + name ] || docElemProp; 9878 9879 // Get document width or height 9880 } else if ( elem.nodeType === 9 ) { 9881 // Either scroll[Width/Height] or offset[Width/Height], whichever is greater 9882 return Math.max( 9883 elem.documentElement["client" + name], 9884 elem.body["scroll" + name], elem.documentElement["scroll" + name], 9885 elem.body["offset" + name], elem.documentElement["offset" + name] 9886 ); 9887 9888 // Get or set width or height on the element 9889 } else if ( size === undefined ) { 9890 var orig = jQuery.css( elem, type ), 9891 ret = parseFloat( orig ); 9892 9893 return jQuery.isNumeric( ret ) ? ret : orig; 9894 9895 // Set the width or height on the element (default to pixels if value is unitless) 9896 } else { 9897 return this.css( type, typeof size === "string" ? size : size + "px" ); 9898 } 9899 }; 9900 9901}); 9902 9903 9904// Expose jQuery to the global object 9905window.jQuery = window.$ = jQuery; 9906})( window ); 9907</script><script type="text/javascript">/*! 9908 * jQuery UI 1.8.16 9909 * 9910 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 9911 * Dual licensed under the MIT or GPL Version 2 licenses. 9912 * http://jquery.org/license 9913 * 9914 * http://docs.jquery.com/UI 9915 */ 9916(function( $, undefined ) { 9917 9918// prevent duplicate loading 9919// this is only a problem because we proxy existing functions 9920// and we don't want to double proxy them 9921$.ui = $.ui || {}; 9922if ( $.ui.version ) { 9923 return; 9924} 9925 9926$.extend( $.ui, { 9927 version: "1.8.16", 9928 9929 keyCode: { 9930 ALT: 18, 9931 BACKSPACE: 8, 9932 CAPS_LOCK: 20, 9933 COMMA: 188, 9934 COMMAND: 91, 9935 COMMAND_LEFT: 91, // COMMAND 9936 COMMAND_RIGHT: 93, 9937 CONTROL: 17, 9938 DELETE: 46, 9939 DOWN: 40, 9940 END: 35, 9941 ENTER: 13, 9942 ESCAPE: 27, 9943 HOME: 36, 9944 INSERT: 45, 9945 LEFT: 37, 9946 MENU: 93, // COMMAND_RIGHT 9947 NUMPAD_ADD: 107, 9948 NUMPAD_DECIMAL: 110, 9949 NUMPAD_DIVIDE: 111, 9950 NUMPAD_ENTER: 108, 9951 NUMPAD_MULTIPLY: 106, 9952 NUMPAD_SUBTRACT: 109, 9953 PAGE_DOWN: 34, 9954 PAGE_UP: 33, 9955 PERIOD: 190, 9956 RIGHT: 39, 9957 SHIFT: 16, 9958 SPACE: 32, 9959 TAB: 9, 9960 UP: 38, 9961 WINDOWS: 91 // COMMAND 9962 } 9963}); 9964 9965// plugins 9966$.fn.extend({ 9967 propAttr: $.fn.prop || $.fn.attr, 9968 9969 _focus: $.fn.focus, 9970 focus: function( delay, fn ) { 9971 return typeof delay === "number" ? 9972 this.each(function() { 9973 var elem = this; 9974 setTimeout(function() { 9975 $( elem ).focus(); 9976 if ( fn ) { 9977 fn.call( elem ); 9978 } 9979 }, delay ); 9980 }) : 9981 this._focus.apply( this, arguments ); 9982 }, 9983 9984 scrollParent: function() { 9985 var scrollParent; 9986 if (($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) { 9987 scrollParent = this.parents().filter(function() { 9988 return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); 9989 }).eq(0); 9990 } else { 9991 scrollParent = this.parents().filter(function() { 9992 return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); 9993 }).eq(0); 9994 } 9995 9996 return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent; 9997 }, 9998 9999 zIndex: function( zIndex ) { 10000 if ( zIndex !== undefined ) { 10001 return this.css( "zIndex", zIndex ); 10002 } 10003 10004 if ( this.length ) { 10005 var elem = $( this[ 0 ] ), position, value; 10006 while ( elem.length && elem[ 0 ] !== document ) { 10007 // Ignore z-index if position is set to a value where z-index is ignored by the browser 10008 // This makes behavior of this function consistent across browsers 10009 // WebKit always returns auto if the element is positioned 10010 position = elem.css( "position" ); 10011 if ( position === "absolute" || position === "relative" || position === "fixed" ) { 10012 // IE returns 0 when zIndex is not specified 10013 // other browsers return a string 10014 // we ignore the case of nested elements with an explicit value of 0 10015 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> 10016 value = parseInt( elem.css( "zIndex" ), 10 ); 10017 if ( !isNaN( value ) && value !== 0 ) { 10018 return value; 10019 } 10020 } 10021 elem = elem.parent(); 10022 } 10023 } 10024 10025 return 0; 10026 }, 10027 10028 disableSelection: function() { 10029 return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + 10030 ".ui-disableSelection", function( event ) { 10031 event.preventDefault(); 10032 }); 10033 }, 10034 10035 enableSelection: function() { 10036 return this.unbind( ".ui-disableSelection" ); 10037 } 10038}); 10039 10040$.each( [ "Width", "Height" ], function( i, name ) { 10041 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], 10042 type = name.toLowerCase(), 10043 orig = { 10044 innerWidth: $.fn.innerWidth, 10045 innerHeight: $.fn.innerHeight, 10046 outerWidth: $.fn.outerWidth, 10047 outerHeight: $.fn.outerHeight 10048 }; 10049 10050 function reduce( elem, size, border, margin ) { 10051 $.each( side, function() { 10052 size -= parseFloat( $.curCSS( elem, "padding" + this, true) ) || 0; 10053 if ( border ) { 10054 size -= parseFloat( $.curCSS( elem, "border" + this + "Width", true) ) || 0; 10055 } 10056 if ( margin ) { 10057 size -= parseFloat( $.curCSS( elem, "margin" + this, true) ) || 0; 10058 } 10059 }); 10060 return size; 10061 } 10062 10063 $.fn[ "inner" + name ] = function( size ) { 10064 if ( size === undefined ) { 10065 return orig[ "inner" + name ].call( this ); 10066 } 10067 10068 return this.each(function() { 10069 $( this ).css( type, reduce( this, size ) + "px" ); 10070 }); 10071 }; 10072 10073 $.fn[ "outer" + name] = function( size, margin ) { 10074 if ( typeof size !== "number" ) { 10075 return orig[ "outer" + name ].call( this, size ); 10076 } 10077 10078 return this.each(function() { 10079 $( this).css( type, reduce( this, size, true, margin ) + "px" ); 10080 }); 10081 }; 10082}); 10083 10084// selectors 10085function focusable( element, isTabIndexNotNaN ) { 10086 var nodeName = element.nodeName.toLowerCase(); 10087 if ( "area" === nodeName ) { 10088 var map = element.parentNode, 10089 mapName = map.name, 10090 img; 10091 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { 10092 return false; 10093 } 10094 img = $( "img[usemap=#" + mapName + "]" )[0]; 10095 return !!img && visible( img ); 10096 } 10097 return ( /input|select|textarea|button|object/.test( nodeName ) 10098 ? !element.disabled 10099 : "a" == nodeName 10100 ? element.href || isTabIndexNotNaN 10101 : isTabIndexNotNaN) 10102 // the element and all of its ancestors must be visible 10103 && visible( element ); 10104} 10105 10106function visible( element ) { 10107 return !$( element ).parents().andSelf().filter(function() { 10108 return $.curCSS( this, "visibility" ) === "hidden" || 10109 $.expr.filters.hidden( this ); 10110 }).length; 10111} 10112 10113$.extend( $.expr[ ":" ], { 10114 data: function( elem, i, match ) { 10115 return !!$.data( elem, match[ 3 ] ); 10116 }, 10117 10118 focusable: function( element ) { 10119 return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); 10120 }, 10121 10122 tabbable: function( element ) { 10123 var tabIndex = $.attr( element, "tabindex" ), 10124 isTabIndexNaN = isNaN( tabIndex ); 10125 return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); 10126 } 10127}); 10128 10129// support 10130$(function() { 10131 var body = document.body, 10132 div = body.appendChild( div = document.createElement( "div" ) ); 10133 10134 $.extend( div.style, { 10135 minHeight: "100px", 10136 height: "auto", 10137 padding: 0, 10138 borderWidth: 0 10139 }); 10140 10141 $.support.minHeight = div.offsetHeight === 100; 10142 $.support.selectstart = "onselectstart" in div; 10143 10144 // set display to none to avoid a layout bug in IE 10145 // http://dev.jquery.com/ticket/4014 10146 body.removeChild( div ).style.display = "none"; 10147}); 10148 10149 10150 10151 10152 10153// deprecated 10154$.extend( $.ui, { 10155 // $.ui.plugin is deprecated. Use the proxy pattern instead. 10156 plugin: { 10157 add: function( module, option, set ) { 10158 var proto = $.ui[ module ].prototype; 10159 for ( var i in set ) { 10160 proto.plugins[ i ] = proto.plugins[ i ] || []; 10161 proto.plugins[ i ].push( [ option, set[ i ] ] ); 10162 } 10163 }, 10164 call: function( instance, name, args ) { 10165 var set = instance.plugins[ name ]; 10166 if ( !set || !instance.element[ 0 ].parentNode ) { 10167 return; 10168 } 10169 10170 for ( var i = 0; i < set.length; i++ ) { 10171 if ( instance.options[ set[ i ][ 0 ] ] ) { 10172 set[ i ][ 1 ].apply( instance.element, args ); 10173 } 10174 } 10175 } 10176 }, 10177 10178 // will be deprecated when we switch to jQuery 1.4 - use jQuery.contains() 10179 contains: function( a, b ) { 10180 return document.compareDocumentPosition ? 10181 a.compareDocumentPosition( b ) & 16 : 10182 a !== b && a.contains( b ); 10183 }, 10184 10185 // only used by resizable 10186 hasScroll: function( el, a ) { 10187 10188 //If overflow is hidden, the element might have extra content, but the user wants to hide it 10189 if ( $( el ).css( "overflow" ) === "hidden") { 10190 return false; 10191 } 10192 10193 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", 10194 has = false; 10195 10196 if ( el[ scroll ] > 0 ) { 10197 return true; 10198 } 10199 10200 // TODO: determine which cases actually cause this to happen 10201 // if the element doesn't have the scroll set, see if it's possible to 10202 // set the scroll 10203 el[ scroll ] = 1; 10204 has = ( el[ scroll ] > 0 ); 10205 el[ scroll ] = 0; 10206 return has; 10207 }, 10208 10209 // these are odd functions, fix the API or move into individual plugins 10210 isOverAxis: function( x, reference, size ) { 10211 //Determines when x coordinate is over "b" element axis 10212 return ( x > reference ) && ( x < ( reference + size ) ); 10213 }, 10214 isOver: function( y, x, top, left, height, width ) { 10215 //Determines when x, y coordinates is over "b" element 10216 return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width ); 10217 } 10218}); 10219 10220})( jQuery ); 10221/*! 10222 * jQuery UI Widget 1.8.16 10223 * 10224 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 10225 * Dual licensed under the MIT or GPL Version 2 licenses. 10226 * http://jquery.org/license 10227 * 10228 * http://docs.jquery.com/UI/Widget 10229 */ 10230(function( $, undefined ) { 10231 10232// jQuery 1.4+ 10233if ( $.cleanData ) { 10234 var _cleanData = $.cleanData; 10235 $.cleanData = function( elems ) { 10236 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { 10237 try { 10238 $( elem ).triggerHandler( "remove" ); 10239 // http://bugs.jquery.com/ticket/8235 10240 } catch( e ) {} 10241 } 10242 _cleanData( elems ); 10243 }; 10244} else { 10245 var _remove = $.fn.remove; 10246 $.fn.remove = function( selector, keepData ) { 10247 return this.each(function() { 10248 if ( !keepData ) { 10249 if ( !selector || $.filter( selector, [ this ] ).length ) { 10250 $( "*", this ).add( [ this ] ).each(function() { 10251 try { 10252 $( this ).triggerHandler( "remove" ); 10253 // http://bugs.jquery.com/ticket/8235 10254 } catch( e ) {} 10255 }); 10256 } 10257 } 10258 return _remove.call( $(this), selector, keepData ); 10259 }); 10260 }; 10261} 10262 10263$.widget = function( name, base, prototype ) { 10264 var namespace = name.split( "." )[ 0 ], 10265 fullName; 10266 name = name.split( "." )[ 1 ]; 10267 fullName = namespace + "-" + name; 10268 10269 if ( !prototype ) { 10270 prototype = base; 10271 base = $.Widget; 10272 } 10273 10274 // create selector for plugin 10275 $.expr[ ":" ][ fullName ] = function( elem ) { 10276 return !!$.data( elem, name ); 10277 }; 10278 10279 $[ namespace ] = $[ namespace ] || {}; 10280 $[ namespace ][ name ] = function( options, element ) { 10281 // allow instantiation without initializing for simple inheritance 10282 if ( arguments.length ) { 10283 this._createWidget( options, element ); 10284 } 10285 }; 10286 10287 var basePrototype = new base(); 10288 // we need to make the options hash a property directly on the new instance 10289 // otherwise we'll modify the options hash on the prototype that we're 10290 // inheriting from 10291// $.each( basePrototype, function( key, val ) { 10292// if ( $.isPlainObject(val) ) { 10293// basePrototype[ key ] = $.extend( {}, val ); 10294// } 10295// }); 10296 basePrototype.options = $.extend( true, {}, basePrototype.options ); 10297 $[ namespace ][ name ].prototype = $.extend( true, basePrototype, { 10298 namespace: namespace, 10299 widgetName: name, 10300 widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name, 10301 widgetBaseClass: fullName 10302 }, prototype ); 10303 10304 $.widget.bridge( name, $[ namespace ][ name ] ); 10305}; 10306 10307$.widget.bridge = function( name, object ) { 10308 $.fn[ name ] = function( options ) { 10309 var isMethodCall = typeof options === "string", 10310 args = Array.prototype.slice.call( arguments, 1 ), 10311 returnValue = this; 10312 10313 // allow multiple hashes to be passed on init 10314 options = !isMethodCall && args.length ? 10315 $.extend.apply( null, [ true, options ].concat(args) ) : 10316 options; 10317 10318 // prevent calls to internal methods 10319 if ( isMethodCall && options.charAt( 0 ) === "_" ) { 10320 return returnValue; 10321 } 10322 10323 if ( isMethodCall ) { 10324 this.each(function() { 10325 var instance = $.data( this, name ), 10326 methodValue = instance && $.isFunction( instance[options] ) ? 10327 instance[ options ].apply( instance, args ) : 10328 instance; 10329 // TODO: add this back in 1.9 and use $.error() (see #5972) 10330// if ( !instance ) { 10331// throw "cannot call methods on " + name + " prior to initialization; " + 10332// "attempted to call method '" + options + "'"; 10333// } 10334// if ( !$.isFunction( instance[options] ) ) { 10335// throw "no such method '" + options + "' for " + name + " widget instance"; 10336// } 10337// var methodValue = instance[ options ].apply( instance, args ); 10338 if ( methodValue !== instance && methodValue !== undefined ) { 10339 returnValue = methodValue; 10340 return false; 10341 } 10342 }); 10343 } else { 10344 this.each(function() { 10345 var instance = $.data( this, name ); 10346 if ( instance ) { 10347 instance.option( options || {} )._init(); 10348 } else { 10349 $.data( this, name, new object( options, this ) ); 10350 } 10351 }); 10352 } 10353 10354 return returnValue; 10355 }; 10356}; 10357 10358$.Widget = function( options, element ) { 10359 // allow instantiation without initializing for simple inheritance 10360 if ( arguments.length ) { 10361 this._createWidget( options, element ); 10362 } 10363}; 10364 10365$.Widget.prototype = { 10366 widgetName: "widget", 10367 widgetEventPrefix: "", 10368 options: { 10369 disabled: false 10370 }, 10371 _createWidget: function( options, element ) { 10372 // $.widget.bridge stores the plugin instance, but we do it anyway 10373 // so that it's stored even before the _create function runs 10374 $.data( element, this.widgetName, this ); 10375 this.element = $( element ); 10376 this.options = $.extend( true, {}, 10377 this.options, 10378 this._getCreateOptions(), 10379 options ); 10380 10381 var self = this; 10382 this.element.bind( "remove." + this.widgetName, function() { 10383 self.destroy(); 10384 }); 10385 10386 this._create(); 10387 this._trigger( "create" ); 10388 this._init(); 10389 }, 10390 _getCreateOptions: function() { 10391 return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ]; 10392 }, 10393 _create: function() {}, 10394 _init: function() {}, 10395 10396 destroy: function() { 10397 this.element 10398 .unbind( "." + this.widgetName ) 10399 .removeData( this.widgetName ); 10400 this.widget() 10401 .unbind( "." + this.widgetName ) 10402 .removeAttr( "aria-disabled" ) 10403 .removeClass( 10404 this.widgetBaseClass + "-disabled " + 10405 "ui-state-disabled" ); 10406 }, 10407 10408 widget: function() { 10409 return this.element; 10410 }, 10411 10412 option: function( key, value ) { 10413 var options = key; 10414 10415 if ( arguments.length === 0 ) { 10416 // don't return a reference to the internal hash 10417 return $.extend( {}, this.options ); 10418 } 10419 10420 if (typeof key === "string" ) { 10421 if ( value === undefined ) { 10422 return this.options[ key ]; 10423 } 10424 options = {}; 10425 options[ key ] = value; 10426 } 10427 10428 this._setOptions( options ); 10429 10430 return this; 10431 }, 10432 _setOptions: function( options ) { 10433 var self = this; 10434 $.each( options, function( key, value ) { 10435 self._setOption( key, value ); 10436 }); 10437 10438 return this; 10439 }, 10440 _setOption: function( key, value ) { 10441 this.options[ key ] = value; 10442 10443 if ( key === "disabled" ) { 10444 this.widget() 10445 [ value ? "addClass" : "removeClass"]( 10446 this.widgetBaseClass + "-disabled" + " " + 10447 "ui-state-disabled" ) 10448 .attr( "aria-disabled", value ); 10449 } 10450 10451 return this; 10452 }, 10453 10454 enable: function() { 10455 return this._setOption( "disabled", false ); 10456 }, 10457 disable: function() { 10458 return this._setOption( "disabled", true ); 10459 }, 10460 10461 _trigger: function( type, event, data ) { 10462 var callback = this.options[ type ]; 10463 10464 event = $.Event( event ); 10465 event.type = ( type === this.widgetEventPrefix ? 10466 type : 10467 this.widgetEventPrefix + type ).toLowerCase(); 10468 data = data || {}; 10469 10470 // copy original event properties over to the new event 10471 // this would happen if we could call $.event.fix instead of $.Event 10472 // but we don't have a way to force an event to be fixed multiple times 10473 if ( event.originalEvent ) { 10474 for ( var i = $.event.props.length, prop; i; ) { 10475 prop = $.event.props[ --i ]; 10476 event[ prop ] = event.originalEvent[ prop ]; 10477 } 10478 } 10479 10480 this.element.trigger( event, data ); 10481 10482 return !( $.isFunction(callback) && 10483 callback.call( this.element[0], event, data ) === false || 10484 event.isDefaultPrevented() ); 10485 } 10486}; 10487 10488})( jQuery ); 10489/*! 10490 * jQuery UI Mouse 1.8.16 10491 * 10492 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 10493 * Dual licensed under the MIT or GPL Version 2 licenses. 10494 * http://jquery.org/license 10495 * 10496 * http://docs.jquery.com/UI/Mouse 10497 * 10498 * Depends: 10499 * jquery.ui.widget.js 10500 */ 10501(function( $, undefined ) { 10502 10503var mouseHandled = false; 10504$( document ).mouseup( function( e ) { 10505 mouseHandled = false; 10506}); 10507 10508$.widget("ui.mouse", { 10509 options: { 10510 cancel: ':input,option', 10511 distance: 1, 10512 delay: 0 10513 }, 10514 _mouseInit: function() { 10515 var self = this; 10516 10517 this.element 10518 .bind('mousedown.'+this.widgetName, function(event) { 10519 return self._mouseDown(event); 10520 }) 10521 .bind('click.'+this.widgetName, function(event) { 10522 if (true === $.data(event.target, self.widgetName + '.preventClickEvent')) { 10523 $.removeData(event.target, self.widgetName + '.preventClickEvent'); 10524 event.stopImmediatePropagation(); 10525 return false; 10526 } 10527 }); 10528 10529 this.started = false; 10530 }, 10531 10532 // TODO: make sure destroying one instance of mouse doesn't mess with 10533 // other instances of mouse 10534 _mouseDestroy: function() { 10535 this.element.unbind('.'+this.widgetName); 10536 }, 10537 10538 _mouseDown: function(event) { 10539 // don't let more than one widget handle mouseStart 10540 if( mouseHandled ) { return }; 10541 10542 // we may have missed mouseup (out of window) 10543 (this._mouseStarted && this._mouseUp(event)); 10544 10545 this._mouseDownEvent = event; 10546 10547 var self = this, 10548 btnIsLeft = (event.which == 1), 10549 // event.target.nodeName works around a bug in IE 8 with 10550 // disabled inputs (#7620) 10551 elIsCancel = (typeof this.options.cancel == "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); 10552 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { 10553 return true; 10554 } 10555 10556 this.mouseDelayMet = !this.options.delay; 10557 if (!this.mouseDelayMet) { 10558 this._mouseDelayTimer = setTimeout(function() { 10559 self.mouseDelayMet = true; 10560 }, this.options.delay); 10561 } 10562 10563 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { 10564 this._mouseStarted = (this._mouseStart(event) !== false); 10565 if (!this._mouseStarted) { 10566 event.preventDefault(); 10567 return true; 10568 } 10569 } 10570 10571 // Click event may never have fired (Gecko & Opera) 10572 if (true === $.data(event.target, this.widgetName + '.preventClickEvent')) { 10573 $.removeData(event.target, this.widgetName + '.preventClickEvent'); 10574 } 10575 10576 // these delegates are required to keep context 10577 this._mouseMoveDelegate = function(event) { 10578 return self._mouseMove(event); 10579 }; 10580 this._mouseUpDelegate = function(event) { 10581 return self._mouseUp(event); 10582 }; 10583 $(document) 10584 .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate) 10585 .bind('mouseup.'+this.widgetName, this._mouseUpDelegate); 10586 10587 event.preventDefault(); 10588 10589 mouseHandled = true; 10590 return true; 10591 }, 10592 10593 _mouseMove: function(event) { 10594 // IE mouseup check - mouseup happened when mouse was out of window 10595 if ($.browser.msie && !(document.documentMode >= 9) && !event.button) { 10596 return this._mouseUp(event); 10597 } 10598 10599 if (this._mouseStarted) { 10600 this._mouseDrag(event); 10601 return event.preventDefault(); 10602 } 10603 10604 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { 10605 this._mouseStarted = 10606 (this._mouseStart(this._mouseDownEvent, event) !== false); 10607 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); 10608 } 10609 10610 return !this._mouseStarted; 10611 }, 10612 10613 _mouseUp: function(event) { 10614 $(document) 10615 .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate) 10616 .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate); 10617 10618 if (this._mouseStarted) { 10619 this._mouseStarted = false; 10620 10621 if (event.target == this._mouseDownEvent.target) { 10622 $.data(event.target, this.widgetName + '.preventClickEvent', true); 10623 } 10624 10625 this._mouseStop(event); 10626 } 10627 10628 return false; 10629 }, 10630 10631 _mouseDistanceMet: function(event) { 10632 return (Math.max( 10633 Math.abs(this._mouseDownEvent.pageX - event.pageX), 10634 Math.abs(this._mouseDownEvent.pageY - event.pageY) 10635 ) >= this.options.distance 10636 ); 10637 }, 10638 10639 _mouseDelayMet: function(event) { 10640 return this.mouseDelayMet; 10641 }, 10642 10643 // These are placeholder methods, to be overriden by extending plugin 10644 _mouseStart: function(event) {}, 10645 _mouseDrag: function(event) {}, 10646 _mouseStop: function(event) {}, 10647 _mouseCapture: function(event) { return true; } 10648}); 10649 10650})(jQuery); 10651/* 10652 * jQuery UI Draggable 1.8.16 10653 * 10654 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 10655 * Dual licensed under the MIT or GPL Version 2 licenses. 10656 * http://jquery.org/license 10657 * 10658 * http://docs.jquery.com/UI/Draggables 10659 * 10660 * Depends: 10661 * jquery.ui.core.js 10662 * jquery.ui.mouse.js 10663 * jquery.ui.widget.js 10664 */ 10665(function( $, undefined ) { 10666 10667$.widget("ui.draggable", $.ui.mouse, { 10668 widgetEventPrefix: "drag", 10669 options: { 10670 addClasses: true, 10671 appendTo: "parent", 10672 axis: false, 10673 connectToSortable: false, 10674 containment: false, 10675 cursor: "auto", 10676 cursorAt: false, 10677 grid: false, 10678 handle: false, 10679 helper: "original", 10680 iframeFix: false, 10681 opacity: false, 10682 refreshPositions: false, 10683 revert: false, 10684 revertDuration: 500, 10685 scope: "default", 10686 scroll: true, 10687 scrollSensitivity: 20, 10688 scrollSpeed: 20, 10689 snap: false, 10690 snapMode: "both", 10691 snapTolerance: 20, 10692 stack: false, 10693 zIndex: false 10694 }, 10695 _create: function() { 10696 10697 if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position"))) 10698 this.element[0].style.position = 'relative'; 10699 10700 (this.options.addClasses && this.element.addClass("ui-draggable")); 10701 (this.options.disabled && this.element.addClass("ui-draggable-disabled")); 10702 10703 this._mouseInit(); 10704 10705 }, 10706 10707 destroy: function() { 10708 if(!this.element.data('draggable')) return; 10709 this.element 10710 .removeData("draggable") 10711 .unbind(".draggable") 10712 .removeClass("ui-draggable" 10713 + " ui-draggable-dragging" 10714 + " ui-draggable-disabled"); 10715 this._mouseDestroy(); 10716 10717 return this; 10718 }, 10719 10720 _mouseCapture: function(event) { 10721 10722 var o = this.options; 10723 10724 // among others, prevent a drag on a resizable-handle 10725 if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle')) 10726 return false; 10727 10728 //Quit if we're not on a valid handle 10729 this.handle = this._getHandle(event); 10730 if (!this.handle) 10731 return false; 10732 10733 if ( o.iframeFix ) { 10734 $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { 10735 $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>') 10736 .css({ 10737 width: this.offsetWidth+"px", height: this.offsetHeight+"px", 10738 position: "absolute", opacity: "0.001", zIndex: 1000 10739 }) 10740 .css($(this).offset()) 10741 .appendTo("body"); 10742 }); 10743 } 10744 10745 return true; 10746 10747 }, 10748 10749 _mouseStart: function(event) { 10750 10751 var o = this.options; 10752 10753 //Create and append the visible helper 10754 this.helper = this._createHelper(event); 10755 10756 //Cache the helper size 10757 this._cacheHelperProportions(); 10758 10759 //If ddmanager is used for droppables, set the global draggable 10760 if($.ui.ddmanager) 10761 $.ui.ddmanager.current = this; 10762 10763 /* 10764 * - Position generation - 10765 * This block generates everything position related - it's the core of draggables. 10766 */ 10767 10768 //Cache the margins of the original element 10769 this._cacheMargins(); 10770 10771 //Store the helper's css position 10772 this.cssPosition = this.helper.css("position"); 10773 this.scrollParent = this.helper.scrollParent(); 10774 10775 //The element's absolute position on the page minus margins 10776 this.offset = this.positionAbs = this.element.offset(); 10777 this.offset = { 10778 top: this.offset.top - this.margins.top, 10779 left: this.offset.left - this.margins.left 10780 }; 10781 10782 $.extend(this.offset, { 10783 click: { //Where the click happened, relative to the element 10784 left: event.pageX - this.offset.left, 10785 top: event.pageY - this.offset.top 10786 }, 10787 parent: this._getParentOffset(), 10788 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper 10789 }); 10790 10791 //Generate the original position 10792 this.originalPosition = this.position = this._generatePosition(event); 10793 this.originalPageX = event.pageX; 10794 this.originalPageY = event.pageY; 10795 10796 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied 10797 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); 10798 10799 //Set a containment if given in the options 10800 if(o.containment) 10801 this._setContainment(); 10802 10803 //Trigger event + callbacks 10804 if(this._trigger("start", event) === false) { 10805 this._clear(); 10806 return false; 10807 } 10808 10809 //Recache the helper size 10810 this._cacheHelperProportions(); 10811 10812 //Prepare the droppable offsets 10813 if ($.ui.ddmanager && !o.dropBehaviour) 10814 $.ui.ddmanager.prepareOffsets(this, event); 10815 10816 this.helper.addClass("ui-draggable-dragging"); 10817 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position 10818 10819 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) 10820 if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event); 10821 10822 return true; 10823 }, 10824 10825 _mouseDrag: function(event, noPropagation) { 10826 10827 //Compute the helpers position 10828 this.position = this._generatePosition(event); 10829 this.positionAbs = this._convertPositionTo("absolute"); 10830 10831 //Call plugins and callbacks and use the resulting position if something is returned 10832 if (!noPropagation) { 10833 var ui = this._uiHash(); 10834 if(this._trigger('drag', event, ui) === false) { 10835 this._mouseUp({}); 10836 return false; 10837 } 10838 this.position = ui.position; 10839 } 10840 10841 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; 10842 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; 10843 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); 10844 10845 return false; 10846 }, 10847 10848 _mouseStop: function(event) { 10849 10850 //If we are using droppables, inform the manager about the drop 10851 var dropped = false; 10852 if ($.ui.ddmanager && !this.options.dropBehaviour) 10853 dropped = $.ui.ddmanager.drop(this, event); 10854 10855 //if a drop comes from outside (a sortable) 10856 if(this.dropped) { 10857 dropped = this.dropped; 10858 this.dropped = false; 10859 } 10860 10861 //if the original element is removed, don't bother to continue if helper is set to "original" 10862 if((!this.element[0] || !this.element[0].parentNode) && this.options.helper == "original") 10863 return false; 10864 10865 if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { 10866 var self = this; 10867 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { 10868 if(self._trigger("stop", event) !== false) { 10869 self._clear(); 10870 } 10871 }); 10872 } else { 10873 if(this._trigger("stop", event) !== false) { 10874 this._clear(); 10875 } 10876 } 10877 10878 return false; 10879 }, 10880 10881 _mouseUp: function(event) { 10882 if (this.options.iframeFix === true) { 10883 $("div.ui-draggable-iframeFix").each(function() { 10884 this.parentNode.removeChild(this); 10885 }); //Remove frame helpers 10886 } 10887 10888 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) 10889 if( $.ui.ddmanager ) $.ui.ddmanager.dragStop(this, event); 10890 10891 return $.ui.mouse.prototype._mouseUp.call(this, event); 10892 }, 10893 10894 cancel: function() { 10895 10896 if(this.helper.is(".ui-draggable-dragging")) { 10897 this._mouseUp({}); 10898 } else { 10899 this._clear(); 10900 } 10901 10902 return this; 10903 10904 }, 10905 10906 _getHandle: function(event) { 10907 10908 var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false; 10909 $(this.options.handle, this.element) 10910 .find("*") 10911 .andSelf() 10912 .each(function() { 10913 if(this == event.target) handle = true; 10914 }); 10915 10916 return handle; 10917 10918 }, 10919 10920 _createHelper: function(event) { 10921 10922 var o = this.options; 10923 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone().removeAttr('id') : this.element); 10924 10925 if(!helper.parents('body').length) 10926 helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)); 10927 10928 if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) 10929 helper.css("position", "absolute"); 10930 10931 return helper; 10932 10933 }, 10934 10935 _adjustOffsetFromHelper: function(obj) { 10936 if (typeof obj == 'string') { 10937 obj = obj.split(' '); 10938 } 10939 if ($.isArray(obj)) { 10940 obj = {left: +obj[0], top: +obj[1] || 0}; 10941 } 10942 if ('left' in obj) { 10943 this.offset.click.left = obj.left + this.margins.left; 10944 } 10945 if ('right' in obj) { 10946 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; 10947 } 10948 if ('top' in obj) { 10949 this.offset.click.top = obj.top + this.margins.top; 10950 } 10951 if ('bottom' in obj) { 10952 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; 10953 } 10954 }, 10955 10956 _getParentOffset: function() { 10957 10958 //Get the offsetParent and cache its position 10959 this.offsetParent = this.helper.offsetParent(); 10960 var po = this.offsetParent.offset(); 10961 10962 // This is a special case where we need to modify a offset calculated on start, since the following happened: 10963 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent 10964 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that 10965 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag 10966 if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) { 10967 po.left += this.scrollParent.scrollLeft(); 10968 po.top += this.scrollParent.scrollTop(); 10969 } 10970 10971 if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information 10972 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix 10973 po = { top: 0, left: 0 }; 10974 10975 return { 10976 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), 10977 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) 10978 }; 10979 10980 }, 10981 10982 _getRelativeOffset: function() { 10983 10984 if(this.cssPosition == "relative") { 10985 var p = this.element.position(); 10986 return { 10987 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), 10988 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() 10989 }; 10990 } else { 10991 return { top: 0, left: 0 }; 10992 } 10993 10994 }, 10995 10996 _cacheMargins: function() { 10997 this.margins = { 10998 left: (parseInt(this.element.css("marginLeft"),10) || 0), 10999 top: (parseInt(this.element.css("marginTop"),10) || 0), 11000 right: (parseInt(this.element.css("marginRight"),10) || 0), 11001 bottom: (parseInt(this.element.css("marginBottom"),10) || 0) 11002 }; 11003 }, 11004 11005 _cacheHelperProportions: function() { 11006 this.helperProportions = { 11007 width: this.helper.outerWidth(), 11008 height: this.helper.outerHeight() 11009 }; 11010 }, 11011 11012 _setContainment: function() { 11013 11014 var o = this.options; 11015 if(o.containment == 'parent') o.containment = this.helper[0].parentNode; 11016 if(o.containment == 'document' || o.containment == 'window') this.containment = [ 11017 o.containment == 'document' ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left, 11018 o.containment == 'document' ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top, 11019 (o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, 11020 (o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top 11021 ]; 11022 11023 if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) { 11024 var c = $(o.containment); 11025 var ce = c[0]; if(!ce) return; 11026 var co = c.offset(); 11027 var over = ($(ce).css("overflow") != 'hidden'); 11028 11029 this.containment = [ 11030 (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0), 11031 (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0), 11032 (over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right, 11033 (over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - this.margins.bottom 11034 ]; 11035 this.relative_container = c; 11036 11037 } else if(o.containment.constructor == Array) { 11038 this.containment = o.containment; 11039 } 11040 11041 }, 11042 11043 _convertPositionTo: function(d, pos) { 11044 11045 if(!pos) pos = this.position; 11046 var mod = d == "absolute" ? 1 : -1; 11047 var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); 11048 11049 return { 11050 top: ( 11051 pos.top // The absolute mouse position 11052 + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent 11053 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) 11054 - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) 11055 ), 11056 left: ( 11057 pos.left // The absolute mouse position 11058 + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent 11059 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) 11060 - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) 11061 ) 11062 }; 11063 11064 }, 11065 11066 _generatePosition: function(event) { 11067 11068 var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); 11069 var pageX = event.pageX; 11070 var pageY = event.pageY; 11071 11072 /* 11073 * - Position constraining - 11074 * Constrain the position to a mix of grid, containment. 11075 */ 11076 11077 if(this.originalPosition) { //If we are not dragging yet, we won't check for options 11078 var containment; 11079 if(this.containment) { 11080 if (this.relative_container){ 11081 var co = this.relative_container.offset(); 11082 containment = [ this.containment[0] + co.left, 11083 this.containment[1] + co.top, 11084 this.containment[2] + co.left, 11085 this.containment[3] + co.top ]; 11086 } 11087 else { 11088 containment = this.containment; 11089 } 11090 11091 if(event.pageX - this.offset.click.left < containment[0]) pageX = containment[0] + this.offset.click.left; 11092 if(event.pageY - this.offset.click.top < containment[1]) pageY = containment[1] + this.offset.click.top; 11093 if(event.pageX - this.offset.click.left > containment[2]) pageX = containment[2] + this.offset.click.left; 11094 if(event.pageY - this.offset.click.top > containment[3]) pageY = containment[3] + this.offset.click.top; 11095 } 11096 11097 if(o.grid) { 11098 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) 11099 var top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; 11100 pageY = containment ? (!(top - this.offset.click.top < containment[1] || top - this.offset.click.top > containment[3]) ? top : (!(top - this.offset.click.top < containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; 11101 11102 var left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; 11103 pageX = containment ? (!(left - this.offset.click.left < containment[0] || left - this.offset.click.left > containment[2]) ? left : (!(left - this.offset.click.left < containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; 11104 } 11105 11106 } 11107 11108 return { 11109 top: ( 11110 pageY // The absolute mouse position 11111 - this.offset.click.top // Click offset (relative to the element) 11112 - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent 11113 - this.offset.parent.top // The offsetParent's offset without borders (offset + border) 11114 + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) 11115 ), 11116 left: ( 11117 pageX // The absolute mouse position 11118 - this.offset.click.left // Click offset (relative to the element) 11119 - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent 11120 - this.offset.parent.left // The offsetParent's offset without borders (offset + border) 11121 + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) 11122 ) 11123 }; 11124 11125 }, 11126 11127 _clear: function() { 11128 this.helper.removeClass("ui-draggable-dragging"); 11129 if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove(); 11130 //if($.ui.ddmanager) $.ui.ddmanager.current = null; 11131 this.helper = null; 11132 this.cancelHelperRemoval = false; 11133 }, 11134 11135 // From now on bulk stuff - mainly helpers 11136 11137 _trigger: function(type, event, ui) { 11138 ui = ui || this._uiHash(); 11139 $.ui.plugin.call(this, type, [event, ui]); 11140 if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins 11141 return $.Widget.prototype._trigger.call(this, type, event, ui); 11142 }, 11143 11144 plugins: {}, 11145 11146 _uiHash: function(event) { 11147 return { 11148 helper: this.helper, 11149 position: this.position, 11150 originalPosition: this.originalPosition, 11151 offset: this.positionAbs 11152 }; 11153 } 11154 11155}); 11156 11157$.extend($.ui.draggable, { 11158 version: "1.8.16" 11159}); 11160 11161$.ui.plugin.add("draggable", "connectToSortable", { 11162 start: function(event, ui) { 11163 11164 var inst = $(this).data("draggable"), o = inst.options, 11165 uiSortable = $.extend({}, ui, { item: inst.element }); 11166 inst.sortables = []; 11167 $(o.connectToSortable).each(function() { 11168 var sortable = $.data(this, 'sortable'); 11169 if (sortable && !sortable.options.disabled) { 11170 inst.sortables.push({ 11171 instance: sortable, 11172 shouldRevert: sortable.options.revert 11173 }); 11174 sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page). 11175 sortable._trigger("activate", event, uiSortable); 11176 } 11177 }); 11178 11179 }, 11180 stop: function(event, ui) { 11181 11182 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper 11183 var inst = $(this).data("draggable"), 11184 uiSortable = $.extend({}, ui, { item: inst.element }); 11185 11186 $.each(inst.sortables, function() { 11187 if(this.instance.isOver) { 11188 11189 this.instance.isOver = 0; 11190 11191 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance 11192 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) 11193 11194 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid' 11195 if(this.shouldRevert) this.instance.options.revert = true; 11196 11197 //Trigger the stop of the sortable 11198 this.instance._mouseStop(event); 11199 11200 this.instance.options.helper = this.instance.options._helper; 11201 11202 //If the helper has been the original item, restore properties in the sortable 11203 if(inst.options.helper == 'original') 11204 this.instance.currentItem.css({ top: 'auto', left: 'auto' }); 11205 11206 } else { 11207 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance 11208 this.instance._trigger("deactivate", event, uiSortable); 11209 } 11210 11211 }); 11212 11213 }, 11214 drag: function(event, ui) { 11215 11216 var inst = $(this).data("draggable"), self = this; 11217 11218 var checkPos = function(o) { 11219 var dyClick = this.offset.click.top, dxClick = this.offset.click.left; 11220 var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left; 11221 var itemHeight = o.height, itemWidth = o.width; 11222 var itemTop = o.top, itemLeft = o.left; 11223 11224 return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth); 11225 }; 11226 11227 $.each(inst.sortables, function(i) { 11228 11229 //Copy over some variables to allow calling the sortable's native _intersectsWith 11230 this.instance.positionAbs = inst.positionAbs; 11231 this.instance.helperProportions = inst.helperProportions; 11232 this.instance.offset.click = inst.offset.click; 11233 11234 if(this.instance._intersectsWith(this.instance.containerCache)) { 11235 11236 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once 11237 if(!this.instance.isOver) { 11238 11239 this.instance.isOver = 1; 11240 //Now we fake the start of dragging for the sortable instance, 11241 //by cloning the list group item, appending it to the sortable and using it as inst.currentItem 11242 //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) 11243 this.instance.currentItem = $(self).clone().removeAttr('id').appendTo(this.instance.element).data("sortable-item", true); 11244 this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it 11245 this.instance.options.helper = function() { return ui.helper[0]; }; 11246 11247 event.target = this.instance.currentItem[0]; 11248 this.instance._mouseCapture(event, true); 11249 this.instance._mouseStart(event, true, true); 11250 11251 //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes 11252 this.instance.offset.click.top = inst.offset.click.top; 11253 this.instance.offset.click.left = inst.offset.click.left; 11254 this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; 11255 this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; 11256 11257 inst._trigger("toSortable", event); 11258 inst.dropped = this.instance.element; //draggable revert needs that 11259 //hack so receive/update callbacks work (mostly) 11260 inst.currentItem = inst.element; 11261 this.instance.fromOutside = inst; 11262 11263 } 11264 11265 //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable 11266 if(this.instance.currentItem) this.instance._mouseDrag(event); 11267 11268 } else { 11269 11270 //If it doesn't intersect with the sortable, and it intersected before, 11271 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval 11272 if(this.instance.isOver) { 11273 11274 this.instance.isOver = 0; 11275 this.instance.cancelHelperRemoval = true; 11276 11277 //Prevent reverting on this forced stop 11278 this.instance.options.revert = false; 11279 11280 // The out event needs to be triggered independently 11281 this.instance._trigger('out', event, this.instance._uiHash(this.instance)); 11282 11283 this.instance._mouseStop(event, true); 11284 this.instance.options.helper = this.instance.options._helper; 11285 11286 //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size 11287 this.instance.currentItem.remove(); 11288 if(this.instance.placeholder) this.instance.placeholder.remove(); 11289 11290 inst._trigger("fromSortable", event); 11291 inst.dropped = false; //draggable revert needs that 11292 } 11293 11294 }; 11295 11296 }); 11297 11298 } 11299}); 11300 11301$.ui.plugin.add("draggable", "cursor", { 11302 start: function(event, ui) { 11303 var t = $('body'), o = $(this).data('draggable').options; 11304 if (t.css("cursor")) o._cursor = t.css("cursor"); 11305 t.css("cursor", o.cursor); 11306 }, 11307 stop: function(event, ui) { 11308 var o = $(this).data('draggable').options; 11309 if (o._cursor) $('body').css("cursor", o._cursor); 11310 } 11311}); 11312 11313$.ui.plugin.add("draggable", "opacity", { 11314 start: function(event, ui) { 11315 var t = $(ui.helper), o = $(this).data('draggable').options; 11316 if(t.css("opacity")) o._opacity = t.css("opacity"); 11317 t.css('opacity', o.opacity); 11318 }, 11319 stop: function(event, ui) { 11320 var o = $(this).data('draggable').options; 11321 if(o._opacity) $(ui.helper).css('opacity', o._opacity); 11322 } 11323}); 11324 11325$.ui.plugin.add("draggable", "scroll", { 11326 start: function(event, ui) { 11327 var i = $(this).data("draggable"); 11328 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset(); 11329 }, 11330 drag: function(event, ui) { 11331 11332 var i = $(this).data("draggable"), o = i.options, scrolled = false; 11333 11334 if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') { 11335 11336 if(!o.axis || o.axis != 'x') { 11337 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) 11338 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; 11339 else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) 11340 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; 11341 } 11342 11343 if(!o.axis || o.axis != 'y') { 11344 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) 11345 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; 11346 else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) 11347 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; 11348 } 11349 11350 } else { 11351 11352 if(!o.axis || o.axis != 'x') { 11353 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) 11354 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); 11355 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) 11356 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); 11357 } 11358 11359 if(!o.axis || o.axis != 'y') { 11360 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) 11361 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); 11362 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) 11363 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); 11364 } 11365 11366 } 11367 11368 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) 11369 $.ui.ddmanager.prepareOffsets(i, event); 11370 11371 } 11372}); 11373 11374$.ui.plugin.add("draggable", "snap", { 11375 start: function(event, ui) { 11376 11377 var i = $(this).data("draggable"), o = i.options; 11378 i.snapElements = []; 11379 11380 $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() { 11381 var $t = $(this); var $o = $t.offset(); 11382 if(this != i.element[0]) i.snapElements.push({ 11383 item: this, 11384 width: $t.outerWidth(), height: $t.outerHeight(), 11385 top: $o.top, left: $o.left 11386 }); 11387 }); 11388 11389 }, 11390 drag: function(event, ui) { 11391 11392 var inst = $(this).data("draggable"), o = inst.options; 11393 var d = o.snapTolerance; 11394 11395 var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, 11396 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; 11397 11398 for (var i = inst.snapElements.length - 1; i >= 0; i--){ 11399 11400 var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width, 11401 t = inst.snapElements[i].top, b = t + inst.snapElements[i].height; 11402 11403 //Yes, I know, this is insane ;) 11404 if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { 11405 if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); 11406 inst.snapElements[i].snapping = false; 11407 continue; 11408 } 11409 11410 if(o.snapMode != 'inner') { 11411 var ts = Math.abs(t - y2) <= d; 11412 var bs = Math.abs(b - y1) <= d; 11413 var ls = Math.abs(l - x2) <= d; 11414 var rs = Math.abs(r - x1) <= d; 11415 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; 11416 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; 11417 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; 11418 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; 11419 } 11420 11421 var first = (ts || bs || ls || rs); 11422 11423 if(o.snapMode != 'outer') { 11424 var ts = Math.abs(t - y1) <= d; 11425 var bs = Math.abs(b - y2) <= d; 11426 var ls = Math.abs(l - x1) <= d; 11427 var rs = Math.abs(r - x2) <= d; 11428 if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; 11429 if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; 11430 if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; 11431 if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; 11432 } 11433 11434 if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) 11435 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); 11436 inst.snapElements[i].snapping = (ts || bs || ls || rs || first); 11437 11438 }; 11439 11440 } 11441}); 11442 11443$.ui.plugin.add("draggable", "stack", { 11444 start: function(event, ui) { 11445 11446 var o = $(this).data("draggable").options; 11447 11448 var group = $.makeArray($(o.stack)).sort(function(a,b) { 11449 return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); 11450 }); 11451 if (!group.length) { return; } 11452 11453 var min = parseInt(group[0].style.zIndex) || 0; 11454 $(group).each(function(i) { 11455 this.style.zIndex = min + i; 11456 }); 11457 11458 this[0].style.zIndex = min + group.length; 11459 11460 } 11461}); 11462 11463$.ui.plugin.add("draggable", "zIndex", { 11464 start: function(event, ui) { 11465 var t = $(ui.helper), o = $(this).data("draggable").options; 11466 if(t.css("zIndex")) o._zIndex = t.css("zIndex"); 11467 t.css('zIndex', o.zIndex); 11468 }, 11469 stop: function(event, ui) { 11470 var o = $(this).data("draggable").options; 11471 if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex); 11472 } 11473}); 11474 11475})(jQuery); 11476/* 11477 * jQuery UI Droppable 1.8.16 11478 * 11479 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 11480 * Dual licensed under the MIT or GPL Version 2 licenses. 11481 * http://jquery.org/license 11482 * 11483 * http://docs.jquery.com/UI/Droppables 11484 * 11485 * Depends: 11486 * jquery.ui.core.js 11487 * jquery.ui.widget.js 11488 * jquery.ui.mouse.js 11489 * jquery.ui.draggable.js 11490 */ 11491(function( $, undefined ) { 11492 11493$.widget("ui.droppable", { 11494 widgetEventPrefix: "drop", 11495 options: { 11496 accept: '*', 11497 activeClass: false, 11498 addClasses: true, 11499 greedy: false, 11500 hoverClass: false, 11501 scope: 'default', 11502 tolerance: 'intersect' 11503 }, 11504 _create: function() { 11505 11506 var o = this.options, accept = o.accept; 11507 this.isover = 0; this.isout = 1; 11508 11509 this.accept = $.isFunction(accept) ? accept : function(d) { 11510 return d.is(accept); 11511 }; 11512 11513 //Store the droppable's proportions 11514 this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight }; 11515 11516 // Add the reference and positions to the manager 11517 $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || []; 11518 $.ui.ddmanager.droppables[o.scope].push(this); 11519 11520 (o.addClasses && this.element.addClass("ui-droppable")); 11521 11522 }, 11523 11524 destroy: function() { 11525 var drop = $.ui.ddmanager.droppables[this.options.scope]; 11526 for ( var i = 0; i < drop.length; i++ ) 11527 if ( drop[i] == this ) 11528 drop.splice(i, 1); 11529 11530 this.element 11531 .removeClass("ui-droppable ui-droppable-disabled") 11532 .removeData("droppable") 11533 .unbind(".droppable"); 11534 11535 return this; 11536 }, 11537 11538 _setOption: function(key, value) { 11539 11540 if(key == 'accept') { 11541 this.accept = $.isFunction(value) ? value : function(d) { 11542 return d.is(value); 11543 }; 11544 } 11545 $.Widget.prototype._setOption.apply(this, arguments); 11546 }, 11547 11548 _activate: function(event) { 11549 var draggable = $.ui.ddmanager.current; 11550 if(this.options.activeClass) this.element.addClass(this.options.activeClass); 11551 (draggable && this._trigger('activate', event, this.ui(draggable))); 11552 }, 11553 11554 _deactivate: function(event) { 11555 var draggable = $.ui.ddmanager.current; 11556 if(this.options.activeClass) this.element.removeClass(this.options.activeClass); 11557 (draggable && this._trigger('deactivate', event, this.ui(draggable))); 11558 }, 11559 11560 _over: function(event) { 11561 11562 var draggable = $.ui.ddmanager.current; 11563 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element 11564 11565 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { 11566 if(this.options.hoverClass) this.element.addClass(this.options.hoverClass); 11567 this._trigger('over', event, this.ui(draggable)); 11568 } 11569 11570 }, 11571 11572 _out: function(event) { 11573 11574 var draggable = $.ui.ddmanager.current; 11575 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element 11576 11577 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { 11578 if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); 11579 this._trigger('out', event, this.ui(draggable)); 11580 } 11581 11582 }, 11583 11584 _drop: function(event,custom) { 11585 11586 var draggable = custom || $.ui.ddmanager.current; 11587 if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element 11588 11589 var childrenIntersection = false; 11590 this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() { 11591 var inst = $.data(this, 'droppable'); 11592 if( 11593 inst.options.greedy 11594 && !inst.options.disabled 11595 && inst.options.scope == draggable.options.scope 11596 && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) 11597 && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance) 11598 ) { childrenIntersection = true; return false; } 11599 }); 11600 if(childrenIntersection) return false; 11601 11602 if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { 11603 if(this.options.activeClass) this.element.removeClass(this.options.activeClass); 11604 if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass); 11605 this._trigger('drop', event, this.ui(draggable)); 11606 return this.element; 11607 } 11608 11609 return false; 11610 11611 }, 11612 11613 ui: function(c) { 11614 return { 11615 draggable: (c.currentItem || c.element), 11616 helper: c.helper, 11617 position: c.position, 11618 offset: c.positionAbs 11619 }; 11620 } 11621 11622}); 11623 11624$.extend($.ui.droppable, { 11625 version: "1.8.16" 11626}); 11627 11628$.ui.intersect = function(draggable, droppable, toleranceMode) { 11629 11630 if (!droppable.offset) return false; 11631 11632 var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, 11633 y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height; 11634 var l = droppable.offset.left, r = l + droppable.proportions.width, 11635 t = droppable.offset.top, b = t + droppable.proportions.height; 11636 11637 switch (toleranceMode) { 11638 case 'fit': 11639 return (l <= x1 && x2 <= r 11640 && t <= y1 && y2 <= b); 11641 break; 11642 case 'intersect': 11643 return (l < x1 + (draggable.helperProportions.width / 2) // Right Half 11644 && x2 - (draggable.helperProportions.width / 2) < r // Left Half 11645 && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half 11646 && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half 11647 break; 11648 case 'pointer': 11649 var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left), 11650 draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top), 11651 isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width); 11652 return isOver; 11653 break; 11654 case 'touch': 11655 return ( 11656 (y1 >= t && y1 <= b) || // Top edge touching 11657 (y2 >= t && y2 <= b) || // Bottom edge touching 11658 (y1 < t && y2 > b) // Surrounded vertically 11659 ) && ( 11660 (x1 >= l && x1 <= r) || // Left edge touching 11661 (x2 >= l && x2 <= r) || // Right edge touching 11662 (x1 < l && x2 > r) // Surrounded horizontally 11663 ); 11664 break; 11665 default: 11666 return false; 11667 break; 11668 } 11669 11670}; 11671 11672/* 11673 This manager tracks offsets of draggables and droppables 11674*/ 11675$.ui.ddmanager = { 11676 current: null, 11677 droppables: { 'default': [] }, 11678 prepareOffsets: function(t, event) { 11679 11680 var m = $.ui.ddmanager.droppables[t.options.scope] || []; 11681 var type = event ? event.type : null; // workaround for #2317 11682 var list = (t.currentItem || t.element).find(":data(droppable)").andSelf(); 11683 11684 droppablesLoop: for (var i = 0; i < m.length; i++) { 11685 11686 if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted 11687 for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item 11688 m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue 11689 11690 if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables 11691 11692 m[i].offset = m[i].element.offset(); 11693 m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; 11694 11695 } 11696 11697 }, 11698 drop: function(draggable, event) { 11699 11700 var dropped = false; 11701 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { 11702 11703 if(!this.options) return; 11704 if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) 11705 dropped = dropped || this._drop.call(this, event); 11706 11707 if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { 11708 this.isout = 1; this.isover = 0; 11709 this._deactivate.call(this, event); 11710 } 11711 11712 }); 11713 return dropped; 11714 11715 }, 11716 dragStart: function( draggable, event ) { 11717 //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) 11718 draggable.element.parents( ":not(body,html)" ).bind( "scroll.droppable", function() { 11719 if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event ); 11720 }); 11721 }, 11722 drag: function(draggable, event) { 11723 11724 //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. 11725 if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event); 11726 11727 //Run through all droppables and check their positions based on specific tolerance options 11728 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { 11729 11730 if(this.options.disabled || this.greedyChild || !this.visible) return; 11731 var intersects = $.ui.intersect(draggable, this, this.options.tolerance); 11732 11733 var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null); 11734 if(!c) return; 11735 11736 var parentInstance; 11737 if (this.options.greedy) { 11738 var parent = this.element.parents(':data(droppable):eq(0)'); 11739 if (parent.length) { 11740 parentInstance = $.data(parent[0], 'droppable'); 11741 parentInstance.greedyChild = (c == 'isover' ? 1 : 0); 11742 } 11743 } 11744 11745 // we just moved into a greedy child 11746 if (parentInstance && c == 'isover') { 11747 parentInstance['isover'] = 0; 11748 parentInstance['isout'] = 1; 11749 parentInstance._out.call(parentInstance, event); 11750 } 11751 11752 this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0; 11753 this[c == "isover" ? "_over" : "_out"].call(this, event); 11754 11755 // we just moved out of a greedy child 11756 if (parentInstance && c == 'isout') { 11757 parentInstance['isout'] = 0; 11758 parentInstance['isover'] = 1; 11759 parentInstance._over.call(parentInstance, event); 11760 } 11761 }); 11762 11763 }, 11764 dragStop: function( draggable, event ) { 11765 draggable.element.parents( ":not(body,html)" ).unbind( "scroll.droppable" ); 11766 //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) 11767 if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event ); 11768 } 11769}; 11770 11771})(jQuery); 11772/* 11773 * jQuery UI Resizable 1.8.16 11774 * 11775 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 11776 * Dual licensed under the MIT or GPL Version 2 licenses. 11777 * http://jquery.org/license 11778 * 11779 * http://docs.jquery.com/UI/Resizables 11780 * 11781 * Depends: 11782 * jquery.ui.core.js 11783 * jquery.ui.mouse.js 11784 * jquery.ui.widget.js 11785 */ 11786(function( $, undefined ) { 11787 11788$.widget("ui.resizable", $.ui.mouse, { 11789 widgetEventPrefix: "resize", 11790 options: { 11791 alsoResize: false, 11792 animate: false, 11793 animateDuration: "slow", 11794 animateEasing: "swing", 11795 aspectRatio: false, 11796 autoHide: false, 11797 containment: false, 11798 ghost: false, 11799 grid: false, 11800 handles: "e,s,se", 11801 helper: false, 11802 maxHeight: null, 11803 maxWidth: null, 11804 minHeight: 10, 11805 minWidth: 10, 11806 zIndex: 1000 11807 }, 11808 _create: function() { 11809 11810 var self = this, o = this.options; 11811 this.element.addClass("ui-resizable"); 11812 11813 $.extend(this, { 11814 _aspectRatio: !!(o.aspectRatio), 11815 aspectRatio: o.aspectRatio, 11816 originalElement: this.element, 11817 _proportionallyResizeElements: [], 11818 _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null 11819 }); 11820 11821 //Wrap the element if it cannot hold child nodes 11822 if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { 11823 11824 //Opera fix for relative positioning 11825 if (/relative/.test(this.element.css('position')) && $.browser.opera) 11826 this.element.css({ position: 'relative', top: 'auto', left: 'auto' }); 11827 11828 //Create a wrapper element and set the wrapper to the new current internal element 11829 this.element.wrap( 11830 $('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({ 11831 position: this.element.css('position'), 11832 width: this.element.outerWidth(), 11833 height: this.element.outerHeight(), 11834 top: this.element.css('top'), 11835 left: this.element.css('left') 11836 }) 11837 ); 11838 11839 //Overwrite the original this.element 11840 this.element = this.element.parent().data( 11841 "resizable", this.element.data('resizable') 11842 ); 11843 11844 this.elementIsWrapper = true; 11845 11846 //Move margins to the wrapper 11847 this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") }); 11848 this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); 11849 11850 //Prevent Safari textarea resize 11851 this.originalResizeStyle = this.originalElement.css('resize'); 11852 this.originalElement.css('resize', 'none'); 11853 11854 //Push the actual element to our proportionallyResize internal array 11855 this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' })); 11856 11857 // avoid IE jump (hard set the margin) 11858 this.originalElement.css({ margin: this.originalElement.css('margin') }); 11859 11860 // fix handlers offset 11861 this._proportionallyResize(); 11862 11863 } 11864 11865 this.handles = o.handles || (!$('.ui-resizable-handle', this.element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' }); 11866 if(this.handles.constructor == String) { 11867 11868 if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw'; 11869 var n = this.handles.split(","); this.handles = {}; 11870 11871 for(var i = 0; i < n.length; i++) { 11872 11873 var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle; 11874 var axis = $('<div class="ui-resizable-handle ' + hname + '"></div>'); 11875 11876 // increase zIndex of sw, se, ne, nw axis 11877 //TODO : this modifies original option 11878 if(/sw|se|ne|nw/.test(handle)) axis.css({ zIndex: ++o.zIndex }); 11879 11880 //TODO : What's going on here? 11881 if ('se' == handle) { 11882 axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se'); 11883 }; 11884 11885 //Insert into internal handles object and append to element 11886 this.handles[handle] = '.ui-resizable-'+handle; 11887 this.element.append(axis); 11888 } 11889 11890 } 11891 11892 this._renderAxis = function(target) { 11893 11894 target = target || this.element; 11895 11896 for(var i in this.handles) { 11897 11898 if(this.handles[i].constructor == String) 11899 this.handles[i] = $(this.handles[i], this.element).show(); 11900 11901 //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) 11902 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { 11903 11904 var axis = $(this.handles[i], this.element), padWrapper = 0; 11905 11906 //Checking the correct pad and border 11907 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); 11908 11909 //The padding type i have to apply... 11910 var padPos = [ 'padding', 11911 /ne|nw|n/.test(i) ? 'Top' : 11912 /se|sw|s/.test(i) ? 'Bottom' : 11913 /^e$/.test(i) ? 'Right' : 'Left' ].join(""); 11914 11915 target.css(padPos, padWrapper); 11916 11917 this._proportionallyResize(); 11918 11919 } 11920 11921 //TODO: What's that good for? There's not anything to be executed left 11922 if(!$(this.handles[i]).length) 11923 continue; 11924 11925 } 11926 }; 11927 11928 //TODO: make renderAxis a prototype function 11929 this._renderAxis(this.element); 11930 11931 this._handles = $('.ui-resizable-handle', this.element) 11932 .disableSelection(); 11933 11934 //Matching axis name 11935 this._handles.mouseover(function() { 11936 if (!self.resizing) { 11937 if (this.className) 11938 var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); 11939 //Axis, default = se 11940 self.axis = axis && axis[1] ? axis[1] : 'se'; 11941 } 11942 }); 11943 11944 //If we want to auto hide the elements 11945 if (o.autoHide) { 11946 this._handles.hide(); 11947 $(this.element) 11948 .addClass("ui-resizable-autohide") 11949 .hover(function() { 11950 if (o.disabled) return; 11951 $(this).removeClass("ui-resizable-autohide"); 11952 self._handles.show(); 11953 }, 11954 function(){ 11955 if (o.disabled) return; 11956 if (!self.resizing) { 11957 $(this).addClass("ui-resizable-autohide"); 11958 self._handles.hide(); 11959 } 11960 }); 11961 } 11962 11963 //Initialize the mouse interaction 11964 this._mouseInit(); 11965 11966 }, 11967 11968 destroy: function() { 11969 11970 this._mouseDestroy(); 11971 11972 var _destroy = function(exp) { 11973 $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") 11974 .removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove(); 11975 }; 11976 11977 //TODO: Unwrap at same DOM position 11978 if (this.elementIsWrapper) { 11979 _destroy(this.element); 11980 var wrapper = this.element; 11981 wrapper.after( 11982 this.originalElement.css({ 11983 position: wrapper.css('position'), 11984 width: wrapper.outerWidth(), 11985 height: wrapper.outerHeight(), 11986 top: wrapper.css('top'), 11987 left: wrapper.css('left') 11988 }) 11989 ).remove(); 11990 } 11991 11992 this.originalElement.css('resize', this.originalResizeStyle); 11993 _destroy(this.originalElement); 11994 11995 return this; 11996 }, 11997 11998 _mouseCapture: function(event) { 11999 var handle = false; 12000 for (var i in this.handles) { 12001 if ($(this.handles[i])[0] == event.target) { 12002 handle = true; 12003 } 12004 } 12005 12006 return !this.options.disabled && handle; 12007 }, 12008 12009 _mouseStart: function(event) { 12010 12011 var o = this.options, iniPos = this.element.position(), el = this.element; 12012 12013 this.resizing = true; 12014 this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() }; 12015 12016 // bugfix for http://dev.jquery.com/ticket/1749 12017 if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) { 12018 el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left }); 12019 } 12020 12021 //Opera fixing relative position 12022 if ($.browser.opera && (/relative/).test(el.css('position'))) 12023 el.css({ position: 'relative', top: 'auto', left: 'auto' }); 12024 12025 this._renderProxy(); 12026 12027 var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top')); 12028 12029 if (o.containment) { 12030 curleft += $(o.containment).scrollLeft() || 0; 12031 curtop += $(o.containment).scrollTop() || 0; 12032 } 12033 12034 //Store needed variables 12035 this.offset = this.helper.offset(); 12036 this.position = { left: curleft, top: curtop }; 12037 this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; 12038 this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; 12039 this.originalPosition = { left: curleft, top: curtop }; 12040 this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; 12041 this.originalMousePosition = { left: event.pageX, top: event.pageY }; 12042 12043 //Aspect Ratio 12044 this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); 12045 12046 var cursor = $('.ui-resizable-' + this.axis).css('cursor'); 12047 $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor); 12048 12049 el.addClass("ui-resizable-resizing"); 12050 this._propagate("start", event); 12051 return true; 12052 }, 12053 12054 _mouseDrag: function(event) { 12055 12056 //Increase performance, avoid regex 12057 var el = this.helper, o = this.options, props = {}, 12058 self = this, smp = this.originalMousePosition, a = this.axis; 12059 12060 var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0; 12061 var trigger = this._change[a]; 12062 if (!trigger) return false; 12063 12064 // Calculate the attrs that will be change 12065 var data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff; 12066 12067 // Put this in the mouseDrag handler since the user can start pressing shift while resizing 12068 this._updateVirtualBoundaries(event.shiftKey); 12069 if (this._aspectRatio || event.shiftKey) 12070 data = this._updateRatio(data, event); 12071 12072 data = this._respectSize(data, event); 12073 12074 // plugins callbacks need to be called first 12075 this._propagate("resize", event); 12076 12077 el.css({ 12078 top: this.position.top + "px", left: this.position.left + "px", 12079 width: this.size.width + "px", height: this.size.height + "px" 12080 }); 12081 12082 if (!this._helper && this._proportionallyResizeElements.length) 12083 this._proportionallyResize(); 12084 12085 this._updateCache(data); 12086 12087 // calling the user callback at the end 12088 this._trigger('resize', event, this.ui()); 12089 12090 return false; 12091 }, 12092 12093 _mouseStop: function(event) { 12094 12095 this.resizing = false; 12096 var o = this.options, self = this; 12097 12098 if(this._helper) { 12099 var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), 12100 soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, 12101 soffsetw = ista ? 0 : self.sizeDiff.width; 12102 12103 var s = { width: (self.helper.width() - soffsetw), height: (self.helper.height() - soffseth) }, 12104 left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, 12105 top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; 12106 12107 if (!o.animate) 12108 this.element.css($.extend(s, { top: top, left: left })); 12109 12110 self.helper.height(self.size.height); 12111 self.helper.width(self.size.width); 12112 12113 if (this._helper && !o.animate) this._proportionallyResize(); 12114 } 12115 12116 $('body').css('cursor', 'auto'); 12117 12118 this.element.removeClass("ui-resizable-resizing"); 12119 12120 this._propagate("stop", event); 12121 12122 if (this._helper) this.helper.remove(); 12123 return false; 12124 12125 }, 12126 12127 _updateVirtualBoundaries: function(forceAspectRatio) { 12128 var o = this.options, pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b; 12129 12130 b = { 12131 minWidth: isNumber(o.minWidth) ? o.minWidth : 0, 12132 maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity, 12133 minHeight: isNumber(o.minHeight) ? o.minHeight : 0, 12134 maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity 12135 }; 12136 12137 if(this._aspectRatio || forceAspectRatio) { 12138 // We want to create an enclosing box whose aspect ration is the requested one 12139 // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension 12140 pMinWidth = b.minHeight * this.aspectRatio; 12141 pMinHeight = b.minWidth / this.aspectRatio; 12142 pMaxWidth = b.maxHeight * this.aspectRatio; 12143 pMaxHeight = b.maxWidth / this.aspectRatio; 12144 12145 if(pMinWidth > b.minWidth) b.minWidth = pMinWidth; 12146 if(pMinHeight > b.minHeight) b.minHeight = pMinHeight; 12147 if(pMaxWidth < b.maxWidth) b.maxWidth = pMaxWidth; 12148 if(pMaxHeight < b.maxHeight) b.maxHeight = pMaxHeight; 12149 } 12150 this._vBoundaries = b; 12151 }, 12152 12153 _updateCache: function(data) { 12154 var o = this.options; 12155 this.offset = this.helper.offset(); 12156 if (isNumber(data.left)) this.position.left = data.left; 12157 if (isNumber(data.top)) this.position.top = data.top; 12158 if (isNumber(data.height)) this.size.height = data.height; 12159 if (isNumber(data.width)) this.size.width = data.width; 12160 }, 12161 12162 _updateRatio: function(data, event) { 12163 12164 var o = this.options, cpos = this.position, csize = this.size, a = this.axis; 12165 12166 if (isNumber(data.height)) data.width = (data.height * this.aspectRatio); 12167 else if (isNumber(data.width)) data.height = (data.width / this.aspectRatio); 12168 12169 if (a == 'sw') { 12170 data.left = cpos.left + (csize.width - data.width); 12171 data.top = null; 12172 } 12173 if (a == 'nw') { 12174 data.top = cpos.top + (csize.height - data.height); 12175 data.left = cpos.left + (csize.width - data.width); 12176 } 12177 12178 return data; 12179 }, 12180 12181 _respectSize: function(data, event) { 12182 12183 var el = this.helper, o = this._vBoundaries, pRatio = this._aspectRatio || event.shiftKey, a = this.axis, 12184 ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), 12185 isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height); 12186 12187 if (isminw) data.width = o.minWidth; 12188 if (isminh) data.height = o.minHeight; 12189 if (ismaxw) data.width = o.maxWidth; 12190 if (ismaxh) data.height = o.maxHeight; 12191 12192 var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height; 12193 var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); 12194 12195 if (isminw && cw) data.left = dw - o.minWidth; 12196 if (ismaxw && cw) data.left = dw - o.maxWidth; 12197 if (isminh && ch) data.top = dh - o.minHeight; 12198 if (ismaxh && ch) data.top = dh - o.maxHeight; 12199 12200 // fixing jump error on top/left - bug #2330 12201 var isNotwh = !data.width && !data.height; 12202 if (isNotwh && !data.left && data.top) data.top = null; 12203 else if (isNotwh && !data.top && data.left) data.left = null; 12204 12205 return data; 12206 }, 12207 12208 _proportionallyResize: function() { 12209 12210 var o = this.options; 12211 if (!this._proportionallyResizeElements.length) return; 12212 var element = this.helper || this.element; 12213 12214 for (var i=0; i < this._proportionallyResizeElements.length; i++) { 12215 12216 var prel = this._proportionallyResizeElements[i]; 12217 12218 if (!this.borderDif) { 12219 var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')], 12220 p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')]; 12221 12222 this.borderDif = $.map(b, function(v, i) { 12223 var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0; 12224 return border + padding; 12225 }); 12226 } 12227 12228 if ($.browser.msie && !(!($(element).is(':hidden') || $(element).parents(':hidden').length))) 12229 continue; 12230 12231 prel.css({ 12232 height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0, 12233 width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 12234 }); 12235 12236 }; 12237 12238 }, 12239 12240 _renderProxy: function() { 12241 12242 var el = this.element, o = this.options; 12243 this.elementOffset = el.offset(); 12244 12245 if(this._helper) { 12246 12247 this.helper = this.helper || $('<div style="overflow:hidden;"></div>'); 12248 12249 // fix ie6 offset TODO: This seems broken 12250 var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0), 12251 pxyoffset = ( ie6 ? 2 : -1 ); 12252 12253 this.helper.addClass(this._helper).css({ 12254 width: this.element.outerWidth() + pxyoffset, 12255 height: this.element.outerHeight() + pxyoffset, 12256 position: 'absolute', 12257 left: this.elementOffset.left - ie6offset +'px', 12258 top: this.elementOffset.top - ie6offset +'px', 12259 zIndex: ++o.zIndex //TODO: Don't modify option 12260 }); 12261 12262 this.helper 12263 .appendTo("body") 12264 .disableSelection(); 12265 12266 } else { 12267 this.helper = this.element; 12268 } 12269 12270 }, 12271 12272 _change: { 12273 e: function(event, dx, dy) { 12274 return { width: this.originalSize.width + dx }; 12275 }, 12276 w: function(event, dx, dy) { 12277 var o = this.options, cs = this.originalSize, sp = this.originalPosition; 12278 return { left: sp.left + dx, width: cs.width - dx }; 12279 }, 12280 n: function(event, dx, dy) { 12281 var o = this.options, cs = this.originalSize, sp = this.originalPosition; 12282 return { top: sp.top + dy, height: cs.height - dy }; 12283 }, 12284 s: function(event, dx, dy) { 12285 return { height: this.originalSize.height + dy }; 12286 }, 12287 se: function(event, dx, dy) { 12288 return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); 12289 }, 12290 sw: function(event, dx, dy) { 12291 return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); 12292 }, 12293 ne: function(event, dx, dy) { 12294 return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); 12295 }, 12296 nw: function(event, dx, dy) { 12297 return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); 12298 } 12299 }, 12300 12301 _propagate: function(n, event) { 12302 $.ui.plugin.call(this, n, [event, this.ui()]); 12303 (n != "resize" && this._trigger(n, event, this.ui())); 12304 }, 12305 12306 plugins: {}, 12307 12308 ui: function() { 12309 return { 12310 originalElement: this.originalElement, 12311 element: this.element, 12312 helper: this.helper, 12313 position: this.position, 12314 size: this.size, 12315 originalSize: this.originalSize, 12316 originalPosition: this.originalPosition 12317 }; 12318 } 12319 12320}); 12321 12322$.extend($.ui.resizable, { 12323 version: "1.8.16" 12324}); 12325 12326/* 12327 * Resizable Extensions 12328 */ 12329 12330$.ui.plugin.add("resizable", "alsoResize", { 12331 12332 start: function (event, ui) { 12333 var self = $(this).data("resizable"), o = self.options; 12334 12335 var _store = function (exp) { 12336 $(exp).each(function() { 12337 var el = $(this); 12338 el.data("resizable-alsoresize", { 12339 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), 12340 left: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10), 12341 position: el.css('position') // to reset Opera on stop() 12342 }); 12343 }); 12344 }; 12345 12346 if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) { 12347 if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } 12348 else { $.each(o.alsoResize, function (exp) { _store(exp); }); } 12349 }else{ 12350 _store(o.alsoResize); 12351 } 12352 }, 12353 12354 resize: function (event, ui) { 12355 var self = $(this).data("resizable"), o = self.options, os = self.originalSize, op = self.originalPosition; 12356 12357 var delta = { 12358 height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0, 12359 top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0 12360 }, 12361 12362 _alsoResize = function (exp, c) { 12363 $(exp).each(function() { 12364 var el = $(this), start = $(this).data("resizable-alsoresize"), style = {}, 12365 css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left']; 12366 12367 $.each(css, function (i, prop) { 12368 var sum = (start[prop]||0) + (delta[prop]||0); 12369 if (sum && sum >= 0) 12370 style[prop] = sum || null; 12371 }); 12372 12373 // Opera fixing relative position 12374 if ($.browser.opera && /relative/.test(el.css('position'))) { 12375 self._revertToRelativePosition = true; 12376 el.css({ position: 'absolute', top: 'auto', left: 'auto' }); 12377 } 12378 12379 el.css(style); 12380 }); 12381 }; 12382 12383 if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) { 12384 $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); }); 12385 }else{ 12386 _alsoResize(o.alsoResize); 12387 } 12388 }, 12389 12390 stop: function (event, ui) { 12391 var self = $(this).data("resizable"), o = self.options; 12392 12393 var _reset = function (exp) { 12394 $(exp).each(function() { 12395 var el = $(this); 12396 // reset position for Opera - no need to verify it was changed 12397 el.css({ position: el.data("resizable-alsoresize").position }); 12398 }); 12399 }; 12400 12401 if (self._revertToRelativePosition) { 12402 self._revertToRelativePosition = false; 12403 if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) { 12404 $.each(o.alsoResize, function (exp) { _reset(exp); }); 12405 }else{ 12406 _reset(o.alsoResize); 12407 } 12408 } 12409 12410 $(this).removeData("resizable-alsoresize"); 12411 } 12412}); 12413 12414$.ui.plugin.add("resizable", "animate", { 12415 12416 stop: function(event, ui) { 12417 var self = $(this).data("resizable"), o = self.options; 12418 12419 var pr = self._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), 12420 soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, 12421 soffsetw = ista ? 0 : self.sizeDiff.width; 12422 12423 var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) }, 12424 left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, 12425 top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; 12426 12427 self.element.animate( 12428 $.extend(style, top && left ? { top: top, left: left } : {}), { 12429 duration: o.animateDuration, 12430 easing: o.animateEasing, 12431 step: function() { 12432 12433 var data = { 12434 width: parseInt(self.element.css('width'), 10), 12435 height: parseInt(self.element.css('height'), 10), 12436 top: parseInt(self.element.css('top'), 10), 12437 left: parseInt(self.element.css('left'), 10) 12438 }; 12439 12440 if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height }); 12441 12442 // propagating resize, and updating values for each animation step 12443 self._updateCache(data); 12444 self._propagate("resize", event); 12445 12446 } 12447 } 12448 ); 12449 } 12450 12451}); 12452 12453$.ui.plugin.add("resizable", "containment", { 12454 12455 start: function(event, ui) { 12456 var self = $(this).data("resizable"), o = self.options, el = self.element; 12457 var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; 12458 if (!ce) return; 12459 12460 self.containerElement = $(ce); 12461 12462 if (/document/.test(oc) || oc == document) { 12463 self.containerOffset = { left: 0, top: 0 }; 12464 self.containerPosition = { left: 0, top: 0 }; 12465 12466 self.parentData = { 12467 element: $(document), left: 0, top: 0, 12468 width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight 12469 }; 12470 } 12471 12472 // i'm a node, so compute top, left, right, bottom 12473 else { 12474 var element = $(ce), p = []; 12475 $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); 12476 12477 self.containerOffset = element.offset(); 12478 self.containerPosition = element.position(); 12479 self.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; 12480 12481 var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width, 12482 width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); 12483 12484 self.parentData = { 12485 element: ce, left: co.left, top: co.top, width: width, height: height 12486 }; 12487 } 12488 }, 12489 12490 resize: function(event, ui) { 12491 var self = $(this).data("resizable"), o = self.options, 12492 ps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position, 12493 pRatio = self._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement; 12494 12495 if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co; 12496 12497 if (cp.left < (self._helper ? co.left : 0)) { 12498 self.size.width = self.size.width + (self._helper ? (self.position.left - co.left) : (self.position.left - cop.left)); 12499 if (pRatio) self.size.height = self.size.width / o.aspectRatio; 12500 self.position.left = o.helper ? co.left : 0; 12501 } 12502 12503 if (cp.top < (self._helper ? co.top : 0)) { 12504 self.size.height = self.size.height + (self._helper ? (self.position.top - co.top) : self.position.top); 12505 if (pRatio) self.size.width = self.size.height * o.aspectRatio; 12506 self.position.top = self._helper ? co.top : 0; 12507 } 12508 12509 self.offset.left = self.parentData.left+self.position.left; 12510 self.offset.top = self.parentData.top+self.position.top; 12511 12512 var woset = Math.abs( (self._helper ? self.offset.left - cop.left : (self.offset.left - cop.left)) + self.sizeDiff.width ), 12513 hoset = Math.abs( (self._helper ? self.offset.top - cop.top : (self.offset.top - co.top)) + self.sizeDiff.height ); 12514 12515 var isParent = self.containerElement.get(0) == self.element.parent().get(0), 12516 isOffsetRelative = /relative|absolute/.test(self.containerElement.css('position')); 12517 12518 if(isParent && isOffsetRelative) woset -= self.parentData.left; 12519 12520 if (woset + self.size.width >= self.parentData.width) { 12521 self.size.width = self.parentData.width - woset; 12522 if (pRatio) self.size.height = self.size.width / self.aspectRatio; 12523 } 12524 12525 if (hoset + self.size.height >= self.parentData.height) { 12526 self.size.height = self.parentData.height - hoset; 12527 if (pRatio) self.size.width = self.size.height * self.aspectRatio; 12528 } 12529 }, 12530 12531 stop: function(event, ui){ 12532 var self = $(this).data("resizable"), o = self.options, cp = self.position, 12533 co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement; 12534 12535 var helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() - self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height; 12536 12537 if (self._helper && !o.animate && (/relative/).test(ce.css('position'))) 12538 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); 12539 12540 if (self._helper && !o.animate && (/static/).test(ce.css('position'))) 12541 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); 12542 12543 } 12544}); 12545 12546$.ui.plugin.add("resizable", "ghost", { 12547 12548 start: function(event, ui) { 12549 12550 var self = $(this).data("resizable"), o = self.options, cs = self.size; 12551 12552 self.ghost = self.originalElement.clone(); 12553 self.ghost 12554 .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) 12555 .addClass('ui-resizable-ghost') 12556 .addClass(typeof o.ghost == 'string' ? o.ghost : ''); 12557 12558 self.ghost.appendTo(self.helper); 12559 12560 }, 12561 12562 resize: function(event, ui){ 12563 var self = $(this).data("resizable"), o = self.options; 12564 if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width }); 12565 }, 12566 12567 stop: function(event, ui){ 12568 var self = $(this).data("resizable"), o = self.options; 12569 if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0)); 12570 } 12571 12572}); 12573 12574$.ui.plugin.add("resizable", "grid", { 12575 12576 resize: function(event, ui) { 12577 var self = $(this).data("resizable"), o = self.options, cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || event.shiftKey; 12578 o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid; 12579 var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1); 12580 12581 if (/^(se|s|e)$/.test(a)) { 12582 self.size.width = os.width + ox; 12583 self.size.height = os.height + oy; 12584 } 12585 else if (/^(ne)$/.test(a)) { 12586 self.size.width = os.width + ox; 12587 self.size.height = os.height + oy; 12588 self.position.top = op.top - oy; 12589 } 12590 else if (/^(sw)$/.test(a)) { 12591 self.size.width = os.width + ox; 12592 self.size.height = os.height + oy; 12593 self.position.left = op.left - ox; 12594 } 12595 else { 12596 self.size.width = os.width + ox; 12597 self.size.height = os.height + oy; 12598 self.position.top = op.top - oy; 12599 self.position.left = op.left - ox; 12600 } 12601 } 12602 12603}); 12604 12605var num = function(v) { 12606 return parseInt(v, 10) || 0; 12607}; 12608 12609var isNumber = function(value) { 12610 return !isNaN(parseInt(value, 10)); 12611}; 12612 12613})(jQuery); 12614/* 12615 * jQuery UI Selectable 1.8.16 12616 * 12617 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 12618 * Dual licensed under the MIT or GPL Version 2 licenses. 12619 * http://jquery.org/license 12620 * 12621 * http://docs.jquery.com/UI/Selectables 12622 * 12623 * Depends: 12624 * jquery.ui.core.js 12625 * jquery.ui.mouse.js 12626 * jquery.ui.widget.js 12627 */ 12628(function( $, undefined ) { 12629 12630$.widget("ui.selectable", $.ui.mouse, { 12631 options: { 12632 appendTo: 'body', 12633 autoRefresh: true, 12634 distance: 0, 12635 filter: '*', 12636 tolerance: 'touch' 12637 }, 12638 _create: function() { 12639 var self = this; 12640 12641 this.element.addClass("ui-selectable"); 12642 12643 this.dragged = false; 12644 12645 // cache selectee children based on filter 12646 var selectees; 12647 this.refresh = function() { 12648 selectees = $(self.options.filter, self.element[0]); 12649 selectees.each(function() { 12650 var $this = $(this); 12651 var pos = $this.offset(); 12652 $.data(this, "selectable-item", { 12653 element: this, 12654 $element: $this, 12655 left: pos.left, 12656 top: pos.top, 12657 right: pos.left + $this.outerWidth(), 12658 bottom: pos.top + $this.outerHeight(), 12659 startselected: false, 12660 selected: $this.hasClass('ui-selected'), 12661 selecting: $this.hasClass('ui-selecting'), 12662 unselecting: $this.hasClass('ui-unselecting') 12663 }); 12664 }); 12665 }; 12666 this.refresh(); 12667 12668 this.selectees = selectees.addClass("ui-selectee"); 12669 12670 this._mouseInit(); 12671 12672 this.helper = $("<div class='ui-selectable-helper'></div>"); 12673 }, 12674 12675 destroy: function() { 12676 this.selectees 12677 .removeClass("ui-selectee") 12678 .removeData("selectable-item"); 12679 this.element 12680 .removeClass("ui-selectable ui-selectable-disabled") 12681 .removeData("selectable") 12682 .unbind(".selectable"); 12683 this._mouseDestroy(); 12684 12685 return this; 12686 }, 12687 12688 _mouseStart: function(event) { 12689 var self = this; 12690 12691 this.opos = [event.pageX, event.pageY]; 12692 12693 if (this.options.disabled) 12694 return; 12695 12696 var options = this.options; 12697 12698 this.selectees = $(options.filter, this.element[0]); 12699 12700 this._trigger("start", event); 12701 12702 $(options.appendTo).append(this.helper); 12703 // position helper (lasso) 12704 this.helper.css({ 12705 "left": event.clientX, 12706 "top": event.clientY, 12707 "width": 0, 12708 "height": 0 12709 }); 12710 12711 if (options.autoRefresh) { 12712 this.refresh(); 12713 } 12714 12715 this.selectees.filter('.ui-selected').each(function() { 12716 var selectee = $.data(this, "selectable-item"); 12717 selectee.startselected = true; 12718 if (!event.metaKey) { 12719 selectee.$element.removeClass('ui-selected'); 12720 selectee.selected = false; 12721 selectee.$element.addClass('ui-unselecting'); 12722 selectee.unselecting = true; 12723 // selectable UNSELECTING callback 12724 self._trigger("unselecting", event, { 12725 unselecting: selectee.element 12726 }); 12727 } 12728 }); 12729 12730 $(event.target).parents().andSelf().each(function() { 12731 var selectee = $.data(this, "selectable-item"); 12732 if (selectee) { 12733 var doSelect = !event.metaKey || !selectee.$element.hasClass('ui-selected'); 12734 selectee.$element 12735 .removeClass(doSelect ? "ui-unselecting" : "ui-selected") 12736 .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); 12737 selectee.unselecting = !doSelect; 12738 selectee.selecting = doSelect; 12739 selectee.selected = doSelect; 12740 // selectable (UN)SELECTING callback 12741 if (doSelect) { 12742 self._trigger("selecting", event, { 12743 selecting: selectee.element 12744 }); 12745 } else { 12746 self._trigger("unselecting", event, { 12747 unselecting: selectee.element 12748 }); 12749 } 12750 return false; 12751 } 12752 }); 12753 12754 }, 12755 12756 _mouseDrag: function(event) { 12757 var self = this; 12758 this.dragged = true; 12759 12760 if (this.options.disabled) 12761 return; 12762 12763 var options = this.options; 12764 12765 var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY; 12766 if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; } 12767 if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; } 12768 this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); 12769 12770 this.selectees.each(function() { 12771 var selectee = $.data(this, "selectable-item"); 12772 //prevent helper from being selected if appendTo: selectable 12773 if (!selectee || selectee.element == self.element[0]) 12774 return; 12775 var hit = false; 12776 if (options.tolerance == 'touch') { 12777 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); 12778 } else if (options.tolerance == 'fit') { 12779 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); 12780 } 12781 12782 if (hit) { 12783 // SELECT 12784 if (selectee.selected) { 12785 selectee.$element.removeClass('ui-selected'); 12786 selectee.selected = false; 12787 } 12788 if (selectee.unselecting) { 12789 selectee.$element.removeClass('ui-unselecting'); 12790 selectee.unselecting = false; 12791 } 12792 if (!selectee.selecting) { 12793 selectee.$element.addClass('ui-selecting'); 12794 selectee.selecting = true; 12795 // selectable SELECTING callback 12796 self._trigger("selecting", event, { 12797 selecting: selectee.element 12798 }); 12799 } 12800 } else { 12801 // UNSELECT 12802 if (selectee.selecting) { 12803 if (event.metaKey && selectee.startselected) { 12804 selectee.$element.removeClass('ui-selecting'); 12805 selectee.selecting = false; 12806 selectee.$element.addClass('ui-selected'); 12807 selectee.selected = true; 12808 } else { 12809 selectee.$element.removeClass('ui-selecting'); 12810 selectee.selecting = false; 12811 if (selectee.startselected) { 12812 selectee.$element.addClass('ui-unselecting'); 12813 selectee.unselecting = true; 12814 } 12815 // selectable UNSELECTING callback 12816 self._trigger("unselecting", event, { 12817 unselecting: selectee.element 12818 }); 12819 } 12820 } 12821 if (selectee.selected) { 12822 if (!event.metaKey && !selectee.startselected) { 12823 selectee.$element.removeClass('ui-selected'); 12824 selectee.selected = false; 12825 12826 selectee.$element.addClass('ui-unselecting'); 12827 selectee.unselecting = true; 12828 // selectable UNSELECTING callback 12829 self._trigger("unselecting", event, { 12830 unselecting: selectee.element 12831 }); 12832 } 12833 } 12834 } 12835 }); 12836 12837 return false; 12838 }, 12839 12840 _mouseStop: function(event) { 12841 var self = this; 12842 12843 this.dragged = false; 12844 12845 var options = this.options; 12846 12847 $('.ui-unselecting', this.element[0]).each(function() { 12848 var selectee = $.data(this, "selectable-item"); 12849 selectee.$element.removeClass('ui-unselecting'); 12850 selectee.unselecting = false; 12851 selectee.startselected = false; 12852 self._trigger("unselected", event, { 12853 unselected: selectee.element 12854 }); 12855 }); 12856 $('.ui-selecting', this.element[0]).each(function() { 12857 var selectee = $.data(this, "selectable-item"); 12858 selectee.$element.removeClass('ui-selecting').addClass('ui-selected'); 12859 selectee.selecting = false; 12860 selectee.selected = true; 12861 selectee.startselected = true; 12862 self._trigger("selected", event, { 12863 selected: selectee.element 12864 }); 12865 }); 12866 this._trigger("stop", event); 12867 12868 this.helper.remove(); 12869 12870 return false; 12871 } 12872 12873}); 12874 12875$.extend($.ui.selectable, { 12876 version: "1.8.16" 12877}); 12878 12879})(jQuery); 12880/* 12881 * jQuery UI Sortable 1.8.16 12882 * 12883 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 12884 * Dual licensed under the MIT or GPL Version 2 licenses. 12885 * http://jquery.org/license 12886 * 12887 * http://docs.jquery.com/UI/Sortables 12888 * 12889 * Depends: 12890 * jquery.ui.core.js 12891 * jquery.ui.mouse.js 12892 * jquery.ui.widget.js 12893 */ 12894(function( $, undefined ) { 12895 12896$.widget("ui.sortable", $.ui.mouse, { 12897 widgetEventPrefix: "sort", 12898 options: { 12899 appendTo: "parent", 12900 axis: false, 12901 connectWith: false, 12902 containment: false, 12903 cursor: 'auto', 12904 cursorAt: false, 12905 dropOnEmpty: true, 12906 forcePlaceholderSize: false, 12907 forceHelperSize: false, 12908 grid: false, 12909 handle: false, 12910 helper: "original", 12911 items: '> *', 12912 opacity: false, 12913 placeholder: false, 12914 revert: false, 12915 scroll: true, 12916 scrollSensitivity: 20, 12917 scrollSpeed: 20, 12918 scope: "default", 12919 tolerance: "intersect", 12920 zIndex: 1000 12921 }, 12922 _create: function() { 12923 12924 var o = this.options; 12925 this.containerCache = {}; 12926 this.element.addClass("ui-sortable"); 12927 12928 //Get the items 12929 this.refresh(); 12930 12931 //Let's determine if the items are being displayed horizontally 12932 this.floating = this.items.length ? o.axis === 'x' || (/left|right/).test(this.items[0].item.css('float')) || (/inline|table-cell/).test(this.items[0].item.css('display')) : false; 12933 12934 //Let's determine the parent's offset 12935 this.offset = this.element.offset(); 12936 12937 //Initialize mouse events for interaction 12938 this._mouseInit(); 12939 12940 }, 12941 12942 destroy: function() { 12943 this.element 12944 .removeClass("ui-sortable ui-sortable-disabled") 12945 .removeData("sortable") 12946 .unbind(".sortable"); 12947 this._mouseDestroy(); 12948 12949 for ( var i = this.items.length - 1; i >= 0; i-- ) 12950 this.items[i].item.removeData("sortable-item"); 12951 12952 return this; 12953 }, 12954 12955 _setOption: function(key, value){ 12956 if ( key === "disabled" ) { 12957 this.options[ key ] = value; 12958 12959 this.widget() 12960 [ value ? "addClass" : "removeClass"]( "ui-sortable-disabled" ); 12961 } else { 12962 // Don't call widget base _setOption for disable as it adds ui-state-disabled class 12963 $.Widget.prototype._setOption.apply(this, arguments); 12964 } 12965 }, 12966 12967 _mouseCapture: function(event, overrideHandle) { 12968 12969 if (this.reverting) { 12970 return false; 12971 } 12972 12973 if(this.options.disabled || this.options.type == 'static') return false; 12974 12975 //We have to refresh the items data once first 12976 this._refreshItems(event); 12977 12978 //Find out if the clicked node (or one of its parents) is a actual item in this.items 12979 var currentItem = null, self = this, nodes = $(event.target).parents().each(function() { 12980 if($.data(this, 'sortable-item') == self) { 12981 currentItem = $(this); 12982 return false; 12983 } 12984 }); 12985 if($.data(event.target, 'sortable-item') == self) currentItem = $(event.target); 12986 12987 if(!currentItem) return false; 12988 if(this.options.handle && !overrideHandle) { 12989 var validHandle = false; 12990 12991 $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; }); 12992 if(!validHandle) return false; 12993 } 12994 12995 this.currentItem = currentItem; 12996 this._removeCurrentsFromItems(); 12997 return true; 12998 12999 }, 13000 13001 _mouseStart: function(event, overrideHandle, noActivation) { 13002 13003 var o = this.options, self = this; 13004 this.currentContainer = this; 13005 13006 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture 13007 this.refreshPositions(); 13008 13009 //Create and append the visible helper 13010 this.helper = this._createHelper(event); 13011 13012 //Cache the helper size 13013 this._cacheHelperProportions(); 13014 13015 /* 13016 * - Position generation - 13017 * This block generates everything position related - it's the core of draggables. 13018 */ 13019 13020 //Cache the margins of the original element 13021 this._cacheMargins(); 13022 13023 //Get the next scrolling parent 13024 this.scrollParent = this.helper.scrollParent(); 13025 13026 //The element's absolute position on the page minus margins 13027 this.offset = this.currentItem.offset(); 13028 this.offset = { 13029 top: this.offset.top - this.margins.top, 13030 left: this.offset.left - this.margins.left 13031 }; 13032 13033 // Only after we got the offset, we can change the helper's position to absolute 13034 // TODO: Still need to figure out a way to make relative sorting possible 13035 this.helper.css("position", "absolute"); 13036 this.cssPosition = this.helper.css("position"); 13037 13038 $.extend(this.offset, { 13039 click: { //Where the click happened, relative to the element 13040 left: event.pageX - this.offset.left, 13041 top: event.pageY - this.offset.top 13042 }, 13043 parent: this._getParentOffset(), 13044 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper 13045 }); 13046 13047 //Generate the original position 13048 this.originalPosition = this._generatePosition(event); 13049 this.originalPageX = event.pageX; 13050 this.originalPageY = event.pageY; 13051 13052 //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied 13053 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); 13054 13055 //Cache the former DOM position 13056 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; 13057 13058 //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way 13059 if(this.helper[0] != this.currentItem[0]) { 13060 this.currentItem.hide(); 13061 } 13062 13063 //Create the placeholder 13064 this._createPlaceholder(); 13065 13066 //Set a containment if given in the options 13067 if(o.containment) 13068 this._setContainment(); 13069 13070 if(o.cursor) { // cursor option 13071 if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor"); 13072 $('body').css("cursor", o.cursor); 13073 } 13074 13075 if(o.opacity) { // opacity option 13076 if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity"); 13077 this.helper.css("opacity", o.opacity); 13078 } 13079 13080 if(o.zIndex) { // zIndex option 13081 if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex"); 13082 this.helper.css("zIndex", o.zIndex); 13083 } 13084 13085 //Prepare scrolling 13086 if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') 13087 this.overflowOffset = this.scrollParent.offset(); 13088 13089 //Call callbacks 13090 this._trigger("start", event, this._uiHash()); 13091 13092 //Recache the helper size 13093 if(!this._preserveHelperProportions) 13094 this._cacheHelperProportions(); 13095 13096 13097 //Post 'activate' events to possible containers 13098 if(!noActivation) { 13099 for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, self._uiHash(this)); } 13100 } 13101 13102 //Prepare possible droppables 13103 if($.ui.ddmanager) 13104 $.ui.ddmanager.current = this; 13105 13106 if ($.ui.ddmanager && !o.dropBehaviour) 13107 $.ui.ddmanager.prepareOffsets(this, event); 13108 13109 this.dragging = true; 13110 13111 this.helper.addClass("ui-sortable-helper"); 13112 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position 13113 return true; 13114 13115 }, 13116 13117 _mouseDrag: function(event) { 13118 13119 //Compute the helpers position 13120 this.position = this._generatePosition(event); 13121 this.positionAbs = this._convertPositionTo("absolute"); 13122 13123 if (!this.lastPositionAbs) { 13124 this.lastPositionAbs = this.positionAbs; 13125 } 13126 13127 //Do scrolling 13128 if(this.options.scroll) { 13129 var o = this.options, scrolled = false; 13130 if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') { 13131 13132 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) 13133 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; 13134 else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) 13135 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; 13136 13137 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) 13138 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; 13139 else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) 13140 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; 13141 13142 } else { 13143 13144 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) 13145 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); 13146 else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) 13147 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); 13148 13149 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) 13150 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); 13151 else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) 13152 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); 13153 13154 } 13155 13156 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) 13157 $.ui.ddmanager.prepareOffsets(this, event); 13158 } 13159 13160 //Regenerate the absolute position used for position checks 13161 this.positionAbs = this._convertPositionTo("absolute"); 13162 13163 //Set the helper position 13164 if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; 13165 if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; 13166 13167 //Rearrange 13168 for (var i = this.items.length - 1; i >= 0; i--) { 13169 13170 //Cache variables and intersection, continue if no intersection 13171 var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item); 13172 if (!intersection) continue; 13173 13174 if(itemElement != this.currentItem[0] //cannot intersect with itself 13175 && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before 13176 && !$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked 13177 && (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true) 13178 //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container 13179 ) { 13180 13181 this.direction = intersection == 1 ? "down" : "up"; 13182 13183 if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) { 13184 this._rearrange(event, item); 13185 } else { 13186 break; 13187 } 13188 13189 this._trigger("change", event, this._uiHash()); 13190 break; 13191 } 13192 } 13193 13194 //Post events to containers 13195 this._contactContainers(event); 13196 13197 //Interconnect with droppables 13198 if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); 13199 13200 //Call callbacks 13201 this._trigger('sort', event, this._uiHash()); 13202 13203 this.lastPositionAbs = this.positionAbs; 13204 return false; 13205 13206 }, 13207 13208 _mouseStop: function(event, noPropagation) { 13209 13210 if(!event) return; 13211 13212 //If we are using droppables, inform the manager about the drop 13213 if ($.ui.ddmanager && !this.options.dropBehaviour) 13214 $.ui.ddmanager.drop(this, event); 13215 13216 if(this.options.revert) { 13217 var self = this; 13218 var cur = self.placeholder.offset(); 13219 13220 self.reverting = true; 13221 13222 $(this.helper).animate({ 13223 left: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft), 13224 top: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop) 13225 }, parseInt(this.options.revert, 10) || 500, function() { 13226 self._clear(event); 13227 }); 13228 } else { 13229 this._clear(event, noPropagation); 13230 } 13231 13232 return false; 13233 13234 }, 13235 13236 cancel: function() { 13237 13238 var self = this; 13239 13240 if(this.dragging) { 13241 13242 this._mouseUp({ target: null }); 13243 13244 if(this.options.helper == "original") 13245 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); 13246 else 13247 this.currentItem.show(); 13248 13249 //Post deactivating events to containers 13250 for (var i = this.containers.length - 1; i >= 0; i--){ 13251 this.containers[i]._trigger("deactivate", null, self._uiHash(this)); 13252 if(this.containers[i].containerCache.over) { 13253 this.containers[i]._trigger("out", null, self._uiHash(this)); 13254 this.containers[i].containerCache.over = 0; 13255 } 13256 } 13257 13258 } 13259 13260 if (this.placeholder) { 13261 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! 13262 if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]); 13263 if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove(); 13264 13265 $.extend(this, { 13266 helper: null, 13267 dragging: false, 13268 reverting: false, 13269 _noFinalSort: null 13270 }); 13271 13272 if(this.domPosition.prev) { 13273 $(this.domPosition.prev).after(this.currentItem); 13274 } else { 13275 $(this.domPosition.parent).prepend(this.currentItem); 13276 } 13277 } 13278 13279 return this; 13280 13281 }, 13282 13283 serialize: function(o) { 13284 13285 var items = this._getItemsAsjQuery(o && o.connected); 13286 var str = []; o = o || {}; 13287 13288 $(items).each(function() { 13289 var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); 13290 if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2])); 13291 }); 13292 13293 if(!str.length && o.key) { 13294 str.push(o.key + '='); 13295 } 13296 13297 return str.join('&'); 13298 13299 }, 13300 13301 toArray: function(o) { 13302 13303 var items = this._getItemsAsjQuery(o && o.connected); 13304 var ret = []; o = o || {}; 13305 13306 items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); }); 13307 return ret; 13308 13309 }, 13310 13311 /* Be careful with the following core functions */ 13312 _intersectsWith: function(item) { 13313 13314 var x1 = this.positionAbs.left, 13315 x2 = x1 + this.helperProportions.width, 13316 y1 = this.positionAbs.top, 13317 y2 = y1 + this.helperProportions.height; 13318 13319 var l = item.left, 13320 r = l + item.width, 13321 t = item.top, 13322 b = t + item.height; 13323 13324 var dyClick = this.offset.click.top, 13325 dxClick = this.offset.click.left; 13326 13327 var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; 13328 13329 if( this.options.tolerance == "pointer" 13330 || this.options.forcePointerForContainers 13331 || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height']) 13332 ) { 13333 return isOverElement; 13334 } else { 13335 13336 return (l < x1 + (this.helperProportions.width / 2) // Right Half 13337 && x2 - (this.helperProportions.width / 2) < r // Left Half 13338 && t < y1 + (this.helperProportions.height / 2) // Bottom Half 13339 && y2 - (this.helperProportions.height / 2) < b ); // Top Half 13340 13341 } 13342 }, 13343 13344 _intersectsWithPointer: function(item) { 13345 13346 var isOverElementHeight = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), 13347 isOverElementWidth = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), 13348 isOverElement = isOverElementHeight && isOverElementWidth, 13349 verticalDirection = this._getDragVerticalDirection(), 13350 horizontalDirection = this._getDragHorizontalDirection(); 13351 13352 if (!isOverElement) 13353 return false; 13354 13355 return this.floating ? 13356 ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 ) 13357 : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) ); 13358 13359 }, 13360 13361 _intersectsWithSides: function(item) { 13362 13363 var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), 13364 isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), 13365 verticalDirection = this._getDragVerticalDirection(), 13366 horizontalDirection = this._getDragHorizontalDirection(); 13367 13368 if (this.floating && horizontalDirection) { 13369 return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf)); 13370 } else { 13371 return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf)); 13372 } 13373 13374 }, 13375 13376 _getDragVerticalDirection: function() { 13377 var delta = this.positionAbs.top - this.lastPositionAbs.top; 13378 return delta != 0 && (delta > 0 ? "down" : "up"); 13379 }, 13380 13381 _getDragHorizontalDirection: function() { 13382 var delta = this.positionAbs.left - this.lastPositionAbs.left; 13383 return delta != 0 && (delta > 0 ? "right" : "left"); 13384 }, 13385 13386 refresh: function(event) { 13387 this._refreshItems(event); 13388 this.refreshPositions(); 13389 return this; 13390 }, 13391 13392 _connectWith: function() { 13393 var options = this.options; 13394 return options.connectWith.constructor == String 13395 ? [options.connectWith] 13396 : options.connectWith; 13397 }, 13398 13399 _getItemsAsjQuery: function(connected) { 13400 13401 var self = this; 13402 var items = []; 13403 var queries = []; 13404 var connectWith = this._connectWith(); 13405 13406 if(connectWith && connected) { 13407 for (var i = connectWith.length - 1; i >= 0; i--){ 13408 var cur = $(connectWith[i]); 13409 for (var j = cur.length - 1; j >= 0; j--){ 13410 var inst = $.data(cur[j], 'sortable'); 13411 if(inst && inst != this && !inst.options.disabled) { 13412 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), inst]); 13413 } 13414 }; 13415 }; 13416 } 13417 13418 queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), this]); 13419 13420 for (var i = queries.length - 1; i >= 0; i--){ 13421 queries[i][0].each(function() { 13422 items.push(this); 13423 }); 13424 }; 13425 13426 return $(items); 13427 13428 }, 13429 13430 _removeCurrentsFromItems: function() { 13431 13432 var list = this.currentItem.find(":data(sortable-item)"); 13433 13434 for (var i=0; i < this.items.length; i++) { 13435 13436 for (var j=0; j < list.length; j++) { 13437 if(list[j] == this.items[i].item[0]) 13438 this.items.splice(i,1); 13439 }; 13440 13441 }; 13442 13443 }, 13444 13445 _refreshItems: function(event) { 13446 13447 this.items = []; 13448 this.containers = [this]; 13449 var items = this.items; 13450 var self = this; 13451 var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]]; 13452 var connectWith = this._connectWith(); 13453 13454 if(connectWith) { 13455 for (var i = connectWith.length - 1; i >= 0; i--){ 13456 var cur = $(connectWith[i]); 13457 for (var j = cur.length - 1; j >= 0; j--){ 13458 var inst = $.data(cur[j], 'sortable'); 13459 if(inst && inst != this && !inst.options.disabled) { 13460 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); 13461 this.containers.push(inst); 13462 } 13463 }; 13464 }; 13465 } 13466 13467 for (var i = queries.length - 1; i >= 0; i--) { 13468 var targetData = queries[i][1]; 13469 var _queries = queries[i][0]; 13470 13471 for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) { 13472 var item = $(_queries[j]); 13473 13474 item.data('sortable-item', targetData); // Data for target checking (mouse manager) 13475 13476 items.push({ 13477 item: item, 13478 instance: targetData, 13479 width: 0, height: 0, 13480 left: 0, top: 0 13481 }); 13482 }; 13483 }; 13484 13485 }, 13486 13487 refreshPositions: function(fast) { 13488 13489 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change 13490 if(this.offsetParent && this.helper) { 13491 this.offset.parent = this._getParentOffset(); 13492 } 13493 13494 for (var i = this.items.length - 1; i >= 0; i--){ 13495 var item = this.items[i]; 13496 13497 //We ignore calculating positions of all connected containers when we're not over them 13498 if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0]) 13499 continue; 13500 13501 var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; 13502 13503 if (!fast) { 13504 item.width = t.outerWidth(); 13505 item.height = t.outerHeight(); 13506 } 13507 13508 var p = t.offset(); 13509 item.left = p.left; 13510 item.top = p.top; 13511 }; 13512 13513 if(this.options.custom && this.options.custom.refreshContainers) { 13514 this.options.custom.refreshContainers.call(this); 13515 } else { 13516 for (var i = this.containers.length - 1; i >= 0; i--){ 13517 var p = this.containers[i].element.offset(); 13518 this.containers[i].containerCache.left = p.left; 13519 this.containers[i].containerCache.top = p.top; 13520 this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); 13521 this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); 13522 }; 13523 } 13524 13525 return this; 13526 }, 13527 13528 _createPlaceholder: function(that) { 13529 13530 var self = that || this, o = self.options; 13531 13532 if(!o.placeholder || o.placeholder.constructor == String) { 13533 var className = o.placeholder; 13534 o.placeholder = { 13535 element: function() { 13536 13537 var el = $(document.createElement(self.currentItem[0].nodeName)) 13538 .addClass(className || self.currentItem[0].className+" ui-sortable-placeholder") 13539 .removeClass("ui-sortable-helper")[0]; 13540 13541 if(!className) 13542 el.style.visibility = "hidden"; 13543 13544 return el; 13545 }, 13546 update: function(container, p) { 13547 13548 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that 13549 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified 13550 if(className && !o.forcePlaceholderSize) return; 13551 13552 //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item 13553 if(!p.height()) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); }; 13554 if(!p.width()) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); }; 13555 } 13556 }; 13557 } 13558 13559 //Create the placeholder 13560 self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem)); 13561 13562 //Append it after the actual current item 13563 self.currentItem.after(self.placeholder); 13564 13565 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) 13566 o.placeholder.update(self, self.placeholder); 13567 13568 }, 13569 13570 _contactContainers: function(event) { 13571 13572 // get innermost container that intersects with item 13573 var innermostContainer = null, innermostIndex = null; 13574 13575 13576 for (var i = this.containers.length - 1; i >= 0; i--){ 13577 13578 // never consider a container that's located within the item itself 13579 if($.ui.contains(this.currentItem[0], this.containers[i].element[0])) 13580 continue; 13581 13582 if(this._intersectsWith(this.containers[i].containerCache)) { 13583 13584 // if we've already found a container and it's more "inner" than this, then continue 13585 if(innermostContainer && $.ui.contains(this.containers[i].element[0], innermostContainer.element[0])) 13586 continue; 13587 13588 innermostContainer = this.containers[i]; 13589 innermostIndex = i; 13590 13591 } else { 13592 // container doesn't intersect. trigger "out" event if necessary 13593 if(this.containers[i].containerCache.over) { 13594 this.containers[i]._trigger("out", event, this._uiHash(this)); 13595 this.containers[i].containerCache.over = 0; 13596 } 13597 } 13598 13599 } 13600 13601 // if no intersecting containers found, return 13602 if(!innermostContainer) return; 13603 13604 // move the item into the container if it's not there already 13605 if(this.containers.length === 1) { 13606 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); 13607 this.containers[innermostIndex].containerCache.over = 1; 13608 } else if(this.currentContainer != this.containers[innermostIndex]) { 13609 13610 //When entering a new container, we will find the item with the least distance and append our item near it 13611 var dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[innermostIndex].floating ? 'left' : 'top']; 13612 for (var j = this.items.length - 1; j >= 0; j--) { 13613 if(!$.ui.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue; 13614 var cur = this.items[j][this.containers[innermostIndex].floating ? 'left' : 'top']; 13615 if(Math.abs(cur - base) < dist) { 13616 dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; 13617 } 13618 } 13619 13620 if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled 13621 return; 13622 13623 this.currentContainer = this.containers[innermostIndex]; 13624 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); 13625 this._trigger("change", event, this._uiHash()); 13626 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); 13627 13628 //Update the placeholder 13629 this.options.placeholder.update(this.currentContainer, this.placeholder); 13630 13631 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); 13632 this.containers[innermostIndex].containerCache.over = 1; 13633 } 13634 13635 13636 }, 13637 13638 _createHelper: function(event) { 13639 13640 var o = this.options; 13641 var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem); 13642 13643 if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already 13644 $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); 13645 13646 if(helper[0] == this.currentItem[0]) 13647 this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; 13648 13649 if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width()); 13650 if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height()); 13651 13652 return helper; 13653 13654 }, 13655 13656 _adjustOffsetFromHelper: function(obj) { 13657 if (typeof obj == 'string') { 13658 obj = obj.split(' '); 13659 } 13660 if ($.isArray(obj)) { 13661 obj = {left: +obj[0], top: +obj[1] || 0}; 13662 } 13663 if ('left' in obj) { 13664 this.offset.click.left = obj.left + this.margins.left; 13665 } 13666 if ('right' in obj) { 13667 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; 13668 } 13669 if ('top' in obj) { 13670 this.offset.click.top = obj.top + this.margins.top; 13671 } 13672 if ('bottom' in obj) { 13673 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; 13674 } 13675 }, 13676 13677 _getParentOffset: function() { 13678 13679 13680 //Get the offsetParent and cache its position 13681 this.offsetParent = this.helper.offsetParent(); 13682 var po = this.offsetParent.offset(); 13683 13684 // This is a special case where we need to modify a offset calculated on start, since the following happened: 13685 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent 13686 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that 13687 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag 13688 if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) { 13689 po.left += this.scrollParent.scrollLeft(); 13690 po.top += this.scrollParent.scrollTop(); 13691 } 13692 13693 if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information 13694 || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix 13695 po = { top: 0, left: 0 }; 13696 13697 return { 13698 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), 13699 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) 13700 }; 13701 13702 }, 13703 13704 _getRelativeOffset: function() { 13705 13706 if(this.cssPosition == "relative") { 13707 var p = this.currentItem.position(); 13708 return { 13709 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), 13710 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() 13711 }; 13712 } else { 13713 return { top: 0, left: 0 }; 13714 } 13715 13716 }, 13717 13718 _cacheMargins: function() { 13719 this.margins = { 13720 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), 13721 top: (parseInt(this.currentItem.css("marginTop"),10) || 0) 13722 }; 13723 }, 13724 13725 _cacheHelperProportions: function() { 13726 this.helperProportions = { 13727 width: this.helper.outerWidth(), 13728 height: this.helper.outerHeight() 13729 }; 13730 }, 13731 13732 _setContainment: function() { 13733 13734 var o = this.options; 13735 if(o.containment == 'parent') o.containment = this.helper[0].parentNode; 13736 if(o.containment == 'document' || o.containment == 'window') this.containment = [ 13737 0 - this.offset.relative.left - this.offset.parent.left, 13738 0 - this.offset.relative.top - this.offset.parent.top, 13739 $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, 13740 ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top 13741 ]; 13742 13743 if(!(/^(document|window|parent)$/).test(o.containment)) { 13744 var ce = $(o.containment)[0]; 13745 var co = $(o.containment).offset(); 13746 var over = ($(ce).css("overflow") != 'hidden'); 13747 13748 this.containment = [ 13749 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, 13750 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, 13751 co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, 13752 co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top 13753 ]; 13754 } 13755 13756 }, 13757 13758 _convertPositionTo: function(d, pos) { 13759 13760 if(!pos) pos = this.position; 13761 var mod = d == "absolute" ? 1 : -1; 13762 var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); 13763 13764 return { 13765 top: ( 13766 pos.top // The absolute mouse position 13767 + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent 13768 + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) 13769 - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) 13770 ), 13771 left: ( 13772 pos.left // The absolute mouse position 13773 + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent 13774 + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) 13775 - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) 13776 ) 13777 }; 13778 13779 }, 13780 13781 _generatePosition: function(event) { 13782 13783 var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); 13784 13785 // This is another very weird special case that only happens for relative elements: 13786 // 1. If the css position is relative 13787 // 2. and the scroll parent is the document or similar to the offset parent 13788 // we have to refresh the relative offset during the scroll so there are no jumps 13789 if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) { 13790 this.offset.relative = this._getRelativeOffset(); 13791 } 13792 13793 var pageX = event.pageX; 13794 var pageY = event.pageY; 13795 13796 /* 13797 * - Position constraining - 13798 * Constrain the position to a mix of grid, containment. 13799 */ 13800 13801 if(this.originalPosition) { //If we are not dragging yet, we won't check for options 13802 13803 if(this.containment) { 13804 if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left; 13805 if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top; 13806 if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left; 13807 if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top; 13808 } 13809 13810 if(o.grid) { 13811 var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; 13812 pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; 13813 13814 var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; 13815 pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; 13816 } 13817 13818 } 13819 13820 return { 13821 top: ( 13822 pageY // The absolute mouse position 13823 - this.offset.click.top // Click offset (relative to the element) 13824 - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent 13825 - this.offset.parent.top // The offsetParent's offset without borders (offset + border) 13826 + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) 13827 ), 13828 left: ( 13829 pageX // The absolute mouse position 13830 - this.offset.click.left // Click offset (relative to the element) 13831 - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent 13832 - this.offset.parent.left // The offsetParent's offset without borders (offset + border) 13833 + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) 13834 ) 13835 }; 13836 13837 }, 13838 13839 _rearrange: function(event, i, a, hardRefresh) { 13840 13841 a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling)); 13842 13843 //Various things done here to improve the performance: 13844 // 1. we create a setTimeout, that calls refreshPositions 13845 // 2. on the instance, we have a counter variable, that get's higher after every append 13846 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same 13847 // 4. this lets only the last addition to the timeout stack through 13848 this.counter = this.counter ? ++this.counter : 1; 13849 var self = this, counter = this.counter; 13850 13851 window.setTimeout(function() { 13852 if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove 13853 },0); 13854 13855 }, 13856 13857 _clear: function(event, noPropagation) { 13858 13859 this.reverting = false; 13860 // We delay all events that have to be triggered to after the point where the placeholder has been removed and 13861 // everything else normalized again 13862 var delayedTriggers = [], self = this; 13863 13864 // We first have to update the dom position of the actual currentItem 13865 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) 13866 if(!this._noFinalSort && this.currentItem.parent().length) this.placeholder.before(this.currentItem); 13867 this._noFinalSort = null; 13868 13869 if(this.helper[0] == this.currentItem[0]) { 13870 for(var i in this._storedCSS) { 13871 if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = ''; 13872 } 13873 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); 13874 } else { 13875 this.currentItem.show(); 13876 } 13877 13878 if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); 13879 if((this.fromOutside || this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) && !noPropagation) delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed 13880 if(!$.ui.contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element 13881 if(!noPropagation) delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); 13882 for (var i = this.containers.length - 1; i >= 0; i--){ 13883 if($.ui.contains(this.containers[i].element[0], this.currentItem[0]) && !noPropagation) { 13884 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.containers[i])); 13885 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.containers[i])); 13886 } 13887 }; 13888 }; 13889 13890 //Post events to containers 13891 for (var i = this.containers.length - 1; i >= 0; i--){ 13892 if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); 13893 if(this.containers[i].containerCache.over) { 13894 delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); 13895 this.containers[i].containerCache.over = 0; 13896 } 13897 } 13898 13899 //Do what was originally in plugins 13900 if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor 13901 if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset opacity 13902 if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index 13903 13904 this.dragging = false; 13905 if(this.cancelHelperRemoval) { 13906 if(!noPropagation) { 13907 this._trigger("beforeStop", event, this._uiHash()); 13908 for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events 13909 this._trigger("stop", event, this._uiHash()); 13910 } 13911 return false; 13912 } 13913 13914 if(!noPropagation) this._trigger("beforeStop", event, this._uiHash()); 13915 13916 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! 13917 this.placeholder[0].parentNode.removeChild(this.placeholder[0]); 13918 13919 if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null; 13920 13921 if(!noPropagation) { 13922 for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events 13923 this._trigger("stop", event, this._uiHash()); 13924 } 13925 13926 this.fromOutside = false; 13927 return true; 13928 13929 }, 13930 13931 _trigger: function() { 13932 if ($.Widget.prototype._trigger.apply(this, arguments) === false) { 13933 this.cancel(); 13934 } 13935 }, 13936 13937 _uiHash: function(inst) { 13938 var self = inst || this; 13939 return { 13940 helper: self.helper, 13941 placeholder: self.placeholder || $([]), 13942 position: self.position, 13943 originalPosition: self.originalPosition, 13944 offset: self.positionAbs, 13945 item: self.currentItem, 13946 sender: inst ? inst.element : null 13947 }; 13948 } 13949 13950}); 13951 13952$.extend($.ui.sortable, { 13953 version: "1.8.16" 13954}); 13955 13956})(jQuery); 13957/* 13958 * jQuery UI Effects 1.8.16 13959 * 13960 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 13961 * Dual licensed under the MIT or GPL Version 2 licenses. 13962 * http://jquery.org/license 13963 * 13964 * http://docs.jquery.com/UI/Effects/ 13965 */ 13966;jQuery.effects || (function($, undefined) { 13967 13968$.effects = {}; 13969 13970 13971 13972/******************************************************************************/ 13973/****************************** COLOR ANIMATIONS ******************************/ 13974/******************************************************************************/ 13975 13976// override the animation for color styles 13977$.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 13978 'borderRightColor', 'borderTopColor', 'borderColor', 'color', 'outlineColor'], 13979function(i, attr) { 13980 $.fx.step[attr] = function(fx) { 13981 if (!fx.colorInit) { 13982 fx.start = getColor(fx.elem, attr); 13983 fx.end = getRGB(fx.end); 13984 fx.colorInit = true; 13985 } 13986 13987 fx.elem.style[attr] = 'rgb(' + 13988 Math.max(Math.min(parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0], 10), 255), 0) + ',' + 13989 Math.max(Math.min(parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1], 10), 255), 0) + ',' + 13990 Math.max(Math.min(parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2], 10), 255), 0) + ')'; 13991 }; 13992}); 13993 13994// Color Conversion functions from highlightFade 13995// By Blair Mitchelmore 13996// http://jquery.offput.ca/highlightFade/ 13997 13998// Parse strings looking for color tuples [255,255,255] 13999function getRGB(color) { 14000 var result; 14001 14002 // Check if we're already dealing with an array of colors 14003 if ( color && color.constructor == Array && color.length == 3 ) 14004 return color; 14005 14006 // Look for rgb(num,num,num) 14007 if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)) 14008 return [parseInt(result[1],10), parseInt(result[2],10), parseInt(result[3],10)]; 14009 14010 // Look for rgb(num%,num%,num%) 14011 if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color)) 14012 return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55]; 14013 14014 // Look for #a0b1c2 14015 if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)) 14016 return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)]; 14017 14018 // Look for #fff 14019 if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)) 14020 return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)]; 14021 14022 // Look for rgba(0, 0, 0, 0) == transparent in Safari 3 14023 if (result = /rgba\(0, 0, 0, 0\)/.exec(color)) 14024 return colors['transparent']; 14025 14026 // Otherwise, we're most likely dealing with a named color 14027 return colors[$.trim(color).toLowerCase()]; 14028} 14029 14030function getColor(elem, attr) { 14031 var color; 14032 14033 do { 14034 color = $.curCSS(elem, attr); 14035 14036 // Keep going until we find an element that has color, or we hit the body 14037 if ( color != '' && color != 'transparent' || $.nodeName(elem, "body") ) 14038 break; 14039 14040 attr = "backgroundColor"; 14041 } while ( elem = elem.parentNode ); 14042 14043 return getRGB(color); 14044}; 14045 14046// Some named colors to work with 14047// From Interface by Stefan Petre 14048// http://interface.eyecon.ro/ 14049 14050var colors = { 14051 aqua:[0,255,255], 14052 azure:[240,255,255], 14053 beige:[245,245,220], 14054 black:[0,0,0], 14055 blue:[0,0,255], 14056 brown:[165,42,42], 14057 cyan:[0,255,255], 14058 darkblue:[0,0,139], 14059 darkcyan:[0,139,139], 14060 darkgrey:[169,169,169], 14061 darkgreen:[0,100,0], 14062 darkkhaki:[189,183,107], 14063 darkmagenta:[139,0,139], 14064 darkolivegreen:[85,107,47], 14065 darkorange:[255,140,0], 14066 darkorchid:[153,50,204], 14067 darkred:[139,0,0], 14068 darksalmon:[233,150,122], 14069 darkviolet:[148,0,211], 14070 fuchsia:[255,0,255], 14071 gold:[255,215,0], 14072 green:[0,128,0], 14073 indigo:[75,0,130], 14074 khaki:[240,230,140], 14075 lightblue:[173,216,230], 14076 lightcyan:[224,255,255], 14077 lightgreen:[144,238,144], 14078 lightgrey:[211,211,211], 14079 lightpink:[255,182,193], 14080 lightyellow:[255,255,224], 14081 lime:[0,255,0], 14082 magenta:[255,0,255], 14083 maroon:[128,0,0], 14084 navy:[0,0,128], 14085 olive:[128,128,0], 14086 orange:[255,165,0], 14087 pink:[255,192,203], 14088 purple:[128,0,128], 14089 violet:[128,0,128], 14090 red:[255,0,0], 14091 silver:[192,192,192], 14092 white:[255,255,255], 14093 yellow:[255,255,0], 14094 transparent: [255,255,255] 14095}; 14096 14097 14098 14099/******************************************************************************/ 14100/****************************** CLASS ANIMATIONS ******************************/ 14101/******************************************************************************/ 14102 14103var classAnimationActions = ['add', 'remove', 'toggle'], 14104 shorthandStyles = { 14105 border: 1, 14106 borderBottom: 1, 14107 borderColor: 1, 14108 borderLeft: 1, 14109 borderRight: 1, 14110 borderTop: 1, 14111 borderWidth: 1, 14112 margin: 1, 14113 padding: 1 14114 }; 14115 14116function getElementStyles() { 14117 var style = document.defaultView 14118 ? document.defaultView.getComputedStyle(this, null) 14119 : this.currentStyle, 14120 newStyle = {}, 14121 key, 14122 camelCase; 14123 14124 // webkit enumerates style porperties 14125 if (style && style.length && style[0] && style[style[0]]) { 14126 var len = style.length; 14127 while (len--) { 14128 key = style[len]; 14129 if (typeof style[key] == 'string') { 14130 camelCase = key.replace(/\-(\w)/g, function(all, letter){ 14131 return letter.toUpperCase(); 14132 }); 14133 newStyle[camelCase] = style[key]; 14134 } 14135 } 14136 } else { 14137 for (key in style) { 14138 if (typeof style[key] === 'string') { 14139 newStyle[key] = style[key]; 14140 } 14141 } 14142 } 14143 14144 return newStyle; 14145} 14146 14147function filterStyles(styles) { 14148 var name, value; 14149 for (name in styles) { 14150 value = styles[name]; 14151 if ( 14152 // ignore null and undefined values 14153 value == null || 14154 // ignore functions (when does this occur?) 14155 $.isFunction(value) || 14156 // shorthand styles that need to be expanded 14157 name in shorthandStyles || 14158 // ignore scrollbars (break in IE) 14159 (/scrollbar/).test(name) || 14160 14161 // only colors or values that can be converted to numbers 14162 (!(/color/i).test(name) && isNaN(parseFloat(value))) 14163 ) { 14164 delete styles[name]; 14165 } 14166 } 14167 14168 return styles; 14169} 14170 14171function styleDifference(oldStyle, newStyle) { 14172 var diff = { _: 0 }, // http://dev.jquery.com/ticket/5459 14173 name; 14174 14175 for (name in newStyle) { 14176 if (oldStyle[name] != newStyle[name]) { 14177 diff[name] = newStyle[name]; 14178 } 14179 } 14180 14181 return diff; 14182} 14183 14184$.effects.animateClass = function(value, duration, easing, callback) { 14185 if ($.isFunction(easing)) { 14186 callback = easing; 14187 easing = null; 14188 } 14189 14190 return this.queue(function() { 14191 var that = $(this), 14192 originalStyleAttr = that.attr('style') || ' ', 14193 originalStyle = filterStyles(getElementStyles.call(this)), 14194 newStyle, 14195 className = that.attr('class'); 14196 14197 $.each(classAnimationActions, function(i, action) { 14198 if (value[action]) { 14199 that[action + 'Class'](value[action]); 14200 } 14201 }); 14202 newStyle = filterStyles(getElementStyles.call(this)); 14203 that.attr('class', className); 14204 14205 that.animate(styleDifference(originalStyle, newStyle), { 14206 queue: false, 14207 duration: duration, 14208 easing: easing, 14209 complete: function() { 14210 $.each(classAnimationActions, function(i, action) { 14211 if (value[action]) { that[action + 'Class'](value[action]); } 14212 }); 14213 // work around bug in IE by clearing the cssText before setting it 14214 if (typeof that.attr('style') == 'object') { 14215 that.attr('style').cssText = ''; 14216 that.attr('style').cssText = originalStyleAttr; 14217 } else { 14218 that.attr('style', originalStyleAttr); 14219 } 14220 if (callback) { callback.apply(this, arguments); } 14221 $.dequeue( this ); 14222 } 14223 }); 14224 }); 14225}; 14226 14227$.fn.extend({ 14228 _addClass: $.fn.addClass, 14229 addClass: function(classNames, speed, easing, callback) { 14230 return speed ? $.effects.animateClass.apply(this, [{ add: classNames },speed,easing,callback]) : this._addClass(classNames); 14231 }, 14232 14233 _removeClass: $.fn.removeClass, 14234 removeClass: function(classNames,speed,easing,callback) { 14235 return speed ? $.effects.animateClass.apply(this, [{ remove: classNames },speed,easing,callback]) : this._removeClass(classNames); 14236 }, 14237 14238 _toggleClass: $.fn.toggleClass, 14239 toggleClass: function(classNames, force, speed, easing, callback) { 14240 if ( typeof force == "boolean" || force === undefined ) { 14241 if ( !speed ) { 14242 // without speed parameter; 14243 return this._toggleClass(classNames, force); 14244 } else { 14245 return $.effects.animateClass.apply(this, [(force?{add:classNames}:{remove:classNames}),speed,easing,callback]); 14246 } 14247 } else { 14248 // without switch parameter; 14249 return $.effects.animateClass.apply(this, [{ toggle: classNames },force,speed,easing]); 14250 } 14251 }, 14252 14253 switchClass: function(remove,add,speed,easing,callback) { 14254 return $.effects.animateClass.apply(this, [{ add: add, remove: remove },speed,easing,callback]); 14255 } 14256}); 14257 14258 14259 14260/******************************************************************************/ 14261/*********************************** EFFECTS **********************************/ 14262/******************************************************************************/ 14263 14264$.extend($.effects, { 14265 version: "1.8.16", 14266 14267 // Saves a set of properties in a data storage 14268 save: function(element, set) { 14269 for(var i=0; i < set.length; i++) { 14270 if(set[i] !== null) element.data("ec.storage."+set[i], element[0].style[set[i]]); 14271 } 14272 }, 14273 14274 // Restores a set of previously saved properties from a data storage 14275 restore: function(element, set) { 14276 for(var i=0; i < set.length; i++) { 14277 if(set[i] !== null) element.css(set[i], element.data("ec.storage."+set[i])); 14278 } 14279 }, 14280 14281 setMode: function(el, mode) { 14282 if (mode == 'toggle') mode = el.is(':hidden') ? 'show' : 'hide'; // Set for toggle 14283 return mode; 14284 }, 14285 14286 getBaseline: function(origin, original) { // Translates a [top,left] array into a baseline value 14287 // this should be a little more flexible in the future to handle a string & hash 14288 var y, x; 14289 switch (origin[0]) { 14290 case 'top': y = 0; break; 14291 case 'middle': y = 0.5; break; 14292 case 'bottom': y = 1; break; 14293 default: y = origin[0] / original.height; 14294 }; 14295 switch (origin[1]) { 14296 case 'left': x = 0; break; 14297 case 'center': x = 0.5; break; 14298 case 'right': x = 1; break; 14299 default: x = origin[1] / original.width; 14300 }; 14301 return {x: x, y: y}; 14302 }, 14303 14304 // Wraps the element around a wrapper that copies position properties 14305 createWrapper: function(element) { 14306 14307 // if the element is already wrapped, return it 14308 if (element.parent().is('.ui-effects-wrapper')) { 14309 return element.parent(); 14310 } 14311 14312 // wrap the element 14313 var props = { 14314 width: element.outerWidth(true), 14315 height: element.outerHeight(true), 14316 'float': element.css('float') 14317 }, 14318 wrapper = $('<div></div>') 14319 .addClass('ui-effects-wrapper') 14320 .css({ 14321 fontSize: '100%', 14322 background: 'transparent', 14323 border: 'none', 14324 margin: 0, 14325 padding: 0 14326 }), 14327 active = document.activeElement; 14328 14329 element.wrap(wrapper); 14330 14331 // Fixes #7595 - Elements lose focus when wrapped. 14332 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { 14333 $( active ).focus(); 14334 } 14335 14336 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually loose the reference to the wrapped element 14337 14338 // transfer positioning properties to the wrapper 14339 if (element.css('position') == 'static') { 14340 wrapper.css({ position: 'relative' }); 14341 element.css({ position: 'relative' }); 14342 } else { 14343 $.extend(props, { 14344 position: element.css('position'), 14345 zIndex: element.css('z-index') 14346 }); 14347 $.each(['top', 'left', 'bottom', 'right'], function(i, pos) { 14348 props[pos] = element.css(pos); 14349 if (isNaN(parseInt(props[pos], 10))) { 14350 props[pos] = 'auto'; 14351 } 14352 }); 14353 element.css({position: 'relative', top: 0, left: 0, right: 'auto', bottom: 'auto' }); 14354 } 14355 14356 return wrapper.css(props).show(); 14357 }, 14358 14359 removeWrapper: function(element) { 14360 var parent, 14361 active = document.activeElement; 14362 14363 if (element.parent().is('.ui-effects-wrapper')) { 14364 parent = element.parent().replaceWith(element); 14365 // Fixes #7595 - Elements lose focus when wrapped. 14366 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { 14367 $( active ).focus(); 14368 } 14369 return parent; 14370 } 14371 14372 return element; 14373 }, 14374 14375 setTransition: function(element, list, factor, value) { 14376 value = value || {}; 14377 $.each(list, function(i, x){ 14378 unit = element.cssUnit(x); 14379 if (unit[0] > 0) value[x] = unit[0] * factor + unit[1]; 14380 }); 14381 return value; 14382 } 14383}); 14384 14385 14386function _normalizeArguments(effect, options, speed, callback) { 14387 // shift params for method overloading 14388 if (typeof effect == 'object') { 14389 callback = options; 14390 speed = null; 14391 options = effect; 14392 effect = options.effect; 14393 } 14394 if ($.isFunction(options)) { 14395 callback = options; 14396 speed = null; 14397 options = {}; 14398 } 14399 if (typeof options == 'number' || $.fx.speeds[options]) { 14400 callback = speed; 14401 speed = options; 14402 options = {}; 14403 } 14404 if ($.isFunction(speed)) { 14405 callback = speed; 14406 speed = null; 14407 } 14408 14409 options = options || {}; 14410 14411 speed = speed || options.duration; 14412 speed = $.fx.off ? 0 : typeof speed == 'number' 14413 ? speed : speed in $.fx.speeds ? $.fx.speeds[speed] : $.fx.speeds._default; 14414 14415 callback = callback || options.complete; 14416 14417 return [effect, options, speed, callback]; 14418} 14419 14420function standardSpeed( speed ) { 14421 // valid standard speeds 14422 if ( !speed || typeof speed === "number" || $.fx.speeds[ speed ] ) { 14423 return true; 14424 } 14425 14426 // invalid strings - treat as "normal" speed 14427 if ( typeof speed === "string" && !$.effects[ speed ] ) { 14428 return true; 14429 } 14430 14431 return false; 14432} 14433 14434$.fn.extend({ 14435 effect: function(effect, options, speed, callback) { 14436 var args = _normalizeArguments.apply(this, arguments), 14437 // TODO: make effects take actual parameters instead of a hash 14438 args2 = { 14439 options: args[1], 14440 duration: args[2], 14441 callback: args[3] 14442 }, 14443 mode = args2.options.mode, 14444 effectMethod = $.effects[effect]; 14445 14446 if ( $.fx.off || !effectMethod ) { 14447 // delegate to the original method (e.g., .show()) if possible 14448 if ( mode ) { 14449 return this[ mode ]( args2.duration, args2.callback ); 14450 } else { 14451 return this.each(function() { 14452 if ( args2.callback ) { 14453 args2.callback.call( this ); 14454 } 14455 }); 14456 } 14457 } 14458 14459 return effectMethod.call(this, args2); 14460 }, 14461 14462 _show: $.fn.show, 14463 show: function(speed) { 14464 if ( standardSpeed( speed ) ) { 14465 return this._show.apply(this, arguments); 14466 } else { 14467 var args = _normalizeArguments.apply(this, arguments); 14468 args[1].mode = 'show'; 14469 return this.effect.apply(this, args); 14470 } 14471 }, 14472 14473 _hide: $.fn.hide, 14474 hide: function(speed) { 14475 if ( standardSpeed( speed ) ) { 14476 return this._hide.apply(this, arguments); 14477 } else { 14478 var args = _normalizeArguments.apply(this, arguments); 14479 args[1].mode = 'hide'; 14480 return this.effect.apply(this, args); 14481 } 14482 }, 14483 14484 // jQuery core overloads toggle and creates _toggle 14485 __toggle: $.fn.toggle, 14486 toggle: function(speed) { 14487 if ( standardSpeed( speed ) || typeof speed === "boolean" || $.isFunction( speed ) ) { 14488 return this.__toggle.apply(this, arguments); 14489 } else { 14490 var args = _normalizeArguments.apply(this, arguments); 14491 args[1].mode = 'toggle'; 14492 return this.effect.apply(this, args); 14493 } 14494 }, 14495 14496 // helper functions 14497 cssUnit: function(key) { 14498 var style = this.css(key), val = []; 14499 $.each( ['em','px','%','pt'], function(i, unit){ 14500 if(style.indexOf(unit) > 0) 14501 val = [parseFloat(style), unit]; 14502 }); 14503 return val; 14504 } 14505}); 14506 14507 14508 14509/******************************************************************************/ 14510/*********************************** EASING ***********************************/ 14511/******************************************************************************/ 14512 14513/* 14514 * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/ 14515 * 14516 * Uses the built in easing capabilities added In jQuery 1.1 14517 * to offer multiple easing options 14518 * 14519 * TERMS OF USE - jQuery Easing 14520 * 14521 * Open source under the BSD License. 14522 * 14523 * Copyright 2008 George McGinley Smith 14524 * All rights reserved. 14525 * 14526 * Redistribution and use in source and binary forms, with or without modification, 14527 * are permitted provided that the following conditions are met: 14528 * 14529 * Redistributions of source code must retain the above copyright notice, this list of 14530 * conditions and the following disclaimer. 14531 * Redistributions in binary form must reproduce the above copyright notice, this list 14532 * of conditions and the following disclaimer in the documentation and/or other materials 14533 * provided with the distribution. 14534 * 14535 * Neither the name of the author nor the names of contributors may be used to endorse 14536 * or promote products derived from this software without specific prior written permission. 14537 * 14538 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 14539 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 14540 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 14541 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 14542 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 14543 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 14544 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 14545 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 14546 * OF THE POSSIBILITY OF SUCH DAMAGE. 14547 * 14548*/ 14549 14550// t: current time, b: begInnIng value, c: change In value, d: duration 14551$.easing.jswing = $.easing.swing; 14552 14553$.extend($.easing, 14554{ 14555 def: 'easeOutQuad', 14556 swing: function (x, t, b, c, d) { 14557 //alert($.easing.default); 14558 return $.easing[$.easing.def](x, t, b, c, d); 14559 }, 14560 easeInQuad: function (x, t, b, c, d) { 14561 return c*(t/=d)*t + b; 14562 }, 14563 easeOutQuad: function (x, t, b, c, d) { 14564 return -c *(t/=d)*(t-2) + b; 14565 }, 14566 easeInOutQuad: function (x, t, b, c, d) { 14567 if ((t/=d/2) < 1) return c/2*t*t + b; 14568 return -c/2 * ((--t)*(t-2) - 1) + b; 14569 }, 14570 easeInCubic: function (x, t, b, c, d) { 14571 return c*(t/=d)*t*t + b; 14572 }, 14573 easeOutCubic: function (x, t, b, c, d) { 14574 return c*((t=t/d-1)*t*t + 1) + b; 14575 }, 14576 easeInOutCubic: function (x, t, b, c, d) { 14577 if ((t/=d/2) < 1) return c/2*t*t*t + b; 14578 return c/2*((t-=2)*t*t + 2) + b; 14579 }, 14580 easeInQuart: function (x, t, b, c, d) { 14581 return c*(t/=d)*t*t*t + b; 14582 }, 14583 easeOutQuart: function (x, t, b, c, d) { 14584 return -c * ((t=t/d-1)*t*t*t - 1) + b; 14585 }, 14586 easeInOutQuart: function (x, t, b, c, d) { 14587 if ((t/=d/2) < 1) return c/2*t*t*t*t + b; 14588 return -c/2 * ((t-=2)*t*t*t - 2) + b; 14589 }, 14590 easeInQuint: function (x, t, b, c, d) { 14591 return c*(t/=d)*t*t*t*t + b; 14592 }, 14593 easeOutQuint: function (x, t, b, c, d) { 14594 return c*((t=t/d-1)*t*t*t*t + 1) + b; 14595 }, 14596 easeInOutQuint: function (x, t, b, c, d) { 14597 if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; 14598 return c/2*((t-=2)*t*t*t*t + 2) + b; 14599 }, 14600 easeInSine: function (x, t, b, c, d) { 14601 return -c * Math.cos(t/d * (Math.PI/2)) + c + b; 14602 }, 14603 easeOutSine: function (x, t, b, c, d) { 14604 return c * Math.sin(t/d * (Math.PI/2)) + b; 14605 }, 14606 easeInOutSine: function (x, t, b, c, d) { 14607 return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; 14608 }, 14609 easeInExpo: function (x, t, b, c, d) { 14610 return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; 14611 }, 14612 easeOutExpo: function (x, t, b, c, d) { 14613 return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; 14614 }, 14615 easeInOutExpo: function (x, t, b, c, d) { 14616 if (t==0) return b; 14617 if (t==d) return b+c; 14618 if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; 14619 return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; 14620 }, 14621 easeInCirc: function (x, t, b, c, d) { 14622 return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; 14623 }, 14624 easeOutCirc: function (x, t, b, c, d) { 14625 return c * Math.sqrt(1 - (t=t/d-1)*t) + b; 14626 }, 14627 easeInOutCirc: function (x, t, b, c, d) { 14628 if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; 14629 return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; 14630 }, 14631 easeInElastic: function (x, t, b, c, d) { 14632 var s=1.70158;var p=0;var a=c; 14633 if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; 14634 if (a < Math.abs(c)) { a=c; var s=p/4; } 14635 else var s = p/(2*Math.PI) * Math.asin (c/a); 14636 return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; 14637 }, 14638 easeOutElastic: function (x, t, b, c, d) { 14639 var s=1.70158;var p=0;var a=c; 14640 if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; 14641 if (a < Math.abs(c)) { a=c; var s=p/4; } 14642 else var s = p/(2*Math.PI) * Math.asin (c/a); 14643 return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; 14644 }, 14645 easeInOutElastic: function (x, t, b, c, d) { 14646 var s=1.70158;var p=0;var a=c; 14647 if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); 14648 if (a < Math.abs(c)) { a=c; var s=p/4; } 14649 else var s = p/(2*Math.PI) * Math.asin (c/a); 14650 if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; 14651 return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; 14652 }, 14653 easeInBack: function (x, t, b, c, d, s) { 14654 if (s == undefined) s = 1.70158; 14655 return c*(t/=d)*t*((s+1)*t - s) + b; 14656 }, 14657 easeOutBack: function (x, t, b, c, d, s) { 14658 if (s == undefined) s = 1.70158; 14659 return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; 14660 }, 14661 easeInOutBack: function (x, t, b, c, d, s) { 14662 if (s == undefined) s = 1.70158; 14663 if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; 14664 return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; 14665 }, 14666 easeInBounce: function (x, t, b, c, d) { 14667 return c - $.easing.easeOutBounce (x, d-t, 0, c, d) + b; 14668 }, 14669 easeOutBounce: function (x, t, b, c, d) { 14670 if ((t/=d) < (1/2.75)) { 14671 return c*(7.5625*t*t) + b; 14672 } else if (t < (2/2.75)) { 14673 return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; 14674 } else if (t < (2.5/2.75)) { 14675 return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; 14676 } else { 14677 return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; 14678 } 14679 }, 14680 easeInOutBounce: function (x, t, b, c, d) { 14681 if (t < d/2) return $.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b; 14682 return $.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b; 14683 } 14684}); 14685 14686/* 14687 * 14688 * TERMS OF USE - EASING EQUATIONS 14689 * 14690 * Open source under the BSD License. 14691 * 14692 * Copyright 2001 Robert Penner 14693 * All rights reserved. 14694 * 14695 * Redistribution and use in source and binary forms, with or without modification, 14696 * are permitted provided that the following conditions are met: 14697 * 14698 * Redistributions of source code must retain the above copyright notice, this list of 14699 * conditions and the following disclaimer. 14700 * Redistributions in binary form must reproduce the above copyright notice, this list 14701 * of conditions and the following disclaimer in the documentation and/or other materials 14702 * provided with the distribution. 14703 * 14704 * Neither the name of the author nor the names of contributors may be used to endorse 14705 * or promote products derived from this software without specific prior written permission. 14706 * 14707 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 14708 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 14709 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 14710 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 14711 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 14712 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 14713 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 14714 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 14715 * OF THE POSSIBILITY OF SUCH DAMAGE. 14716 * 14717 */ 14718 14719})(jQuery); 14720/* 14721 * jQuery UI Effects Blind 1.8.16 14722 * 14723 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 14724 * Dual licensed under the MIT or GPL Version 2 licenses. 14725 * http://jquery.org/license 14726 * 14727 * http://docs.jquery.com/UI/Effects/Blind 14728 * 14729 * Depends: 14730 * jquery.effects.core.js 14731 */ 14732(function( $, undefined ) { 14733 14734$.effects.blind = function(o) { 14735 14736 return this.queue(function() { 14737 14738 // Create element 14739 var el = $(this), props = ['position','top','bottom','left','right']; 14740 14741 // Set options 14742 var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode 14743 var direction = o.options.direction || 'vertical'; // Default direction 14744 14745 // Adjust 14746 $.effects.save(el, props); el.show(); // Save & Show 14747 var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper 14748 var ref = (direction == 'vertical') ? 'height' : 'width'; 14749 var distance = (direction == 'vertical') ? wrapper.height() : wrapper.width(); 14750 if(mode == 'show') wrapper.css(ref, 0); // Shift 14751 14752 // Animation 14753 var animation = {}; 14754 animation[ref] = mode == 'show' ? distance : 0; 14755 14756 // Animate 14757 wrapper.animate(animation, o.duration, o.options.easing, function() { 14758 if(mode == 'hide') el.hide(); // Hide 14759 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore 14760 if(o.callback) o.callback.apply(el[0], arguments); // Callback 14761 el.dequeue(); 14762 }); 14763 14764 }); 14765 14766}; 14767 14768})(jQuery); 14769/* 14770 * jQuery UI Effects Bounce 1.8.16 14771 * 14772 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 14773 * Dual licensed under the MIT or GPL Version 2 licenses. 14774 * http://jquery.org/license 14775 * 14776 * http://docs.jquery.com/UI/Effects/Bounce 14777 * 14778 * Depends: 14779 * jquery.effects.core.js 14780 */ 14781(function( $, undefined ) { 14782 14783$.effects.bounce = function(o) { 14784 14785 return this.queue(function() { 14786 14787 // Create element 14788 var el = $(this), props = ['position','top','bottom','left','right']; 14789 14790 // Set options 14791 var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode 14792 var direction = o.options.direction || 'up'; // Default direction 14793 var distance = o.options.distance || 20; // Default distance 14794 var times = o.options.times || 5; // Default # of times 14795 var speed = o.duration || 250; // Default speed per bounce 14796 if (/show|hide/.test(mode)) props.push('opacity'); // Avoid touching opacity to prevent clearType and PNG issues in IE 14797 14798 // Adjust 14799 $.effects.save(el, props); el.show(); // Save & Show 14800 $.effects.createWrapper(el); // Create Wrapper 14801 var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; 14802 var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; 14803 var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 3 : el.outerWidth({margin:true}) / 3); 14804 if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift 14805 if (mode == 'hide') distance = distance / (times * 2); 14806 if (mode != 'hide') times--; 14807 14808 // Animate 14809 if (mode == 'show') { // Show Bounce 14810 var animation = {opacity: 1}; 14811 animation[ref] = (motion == 'pos' ? '+=' : '-=') + distance; 14812 el.animate(animation, speed / 2, o.options.easing); 14813 distance = distance / 2; 14814 times--; 14815 }; 14816 for (var i = 0; i < times; i++) { // Bounces 14817 var animation1 = {}, animation2 = {}; 14818 animation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance; 14819 animation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance; 14820 el.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing); 14821 distance = (mode == 'hide') ? distance * 2 : distance / 2; 14822 }; 14823 if (mode == 'hide') { // Last Bounce 14824 var animation = {opacity: 0}; 14825 animation[ref] = (motion == 'pos' ? '-=' : '+=') + distance; 14826 el.animate(animation, speed / 2, o.options.easing, function(){ 14827 el.hide(); // Hide 14828 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore 14829 if(o.callback) o.callback.apply(this, arguments); // Callback 14830 }); 14831 } else { 14832 var animation1 = {}, animation2 = {}; 14833 animation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance; 14834 animation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance; 14835 el.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing, function(){ 14836 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore 14837 if(o.callback) o.callback.apply(this, arguments); // Callback 14838 }); 14839 }; 14840 el.queue('fx', function() { el.dequeue(); }); 14841 el.dequeue(); 14842 }); 14843 14844}; 14845 14846})(jQuery); 14847/* 14848 * jQuery UI Effects Clip 1.8.16 14849 * 14850 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 14851 * Dual licensed under the MIT or GPL Version 2 licenses. 14852 * http://jquery.org/license 14853 * 14854 * http://docs.jquery.com/UI/Effects/Clip 14855 * 14856 * Depends: 14857 * jquery.effects.core.js 14858 */ 14859(function( $, undefined ) { 14860 14861$.effects.clip = function(o) { 14862 14863 return this.queue(function() { 14864 14865 // Create element 14866 var el = $(this), props = ['position','top','bottom','left','right','height','width']; 14867 14868 // Set options 14869 var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode 14870 var direction = o.options.direction || 'vertical'; // Default direction 14871 14872 // Adjust 14873 $.effects.save(el, props); el.show(); // Save & Show 14874 var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper 14875 var animate = el[0].tagName == 'IMG' ? wrapper : el; 14876 var ref = { 14877 size: (direction == 'vertical') ? 'height' : 'width', 14878 position: (direction == 'vertical') ? 'top' : 'left' 14879 }; 14880 var distance = (direction == 'vertical') ? animate.height() : animate.width(); 14881 if(mode == 'show') { animate.css(ref.size, 0); animate.css(ref.position, distance / 2); } // Shift 14882 14883 // Animation 14884 var animation = {}; 14885 animation[ref.size] = mode == 'show' ? distance : 0; 14886 animation[ref.position] = mode == 'show' ? 0 : distance / 2; 14887 14888 // Animate 14889 animate.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { 14890 if(mode == 'hide') el.hide(); // Hide 14891 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore 14892 if(o.callback) o.callback.apply(el[0], arguments); // Callback 14893 el.dequeue(); 14894 }}); 14895 14896 }); 14897 14898}; 14899 14900})(jQuery); 14901/* 14902 * jQuery UI Effects Drop 1.8.16 14903 * 14904 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 14905 * Dual licensed under the MIT or GPL Version 2 licenses. 14906 * http://jquery.org/license 14907 * 14908 * http://docs.jquery.com/UI/Effects/Drop 14909 * 14910 * Depends: 14911 * jquery.effects.core.js 14912 */ 14913(function( $, undefined ) { 14914 14915$.effects.drop = function(o) { 14916 14917 return this.queue(function() { 14918 14919 // Create element 14920 var el = $(this), props = ['position','top','bottom','left','right','opacity']; 14921 14922 // Set options 14923 var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode 14924 var direction = o.options.direction || 'left'; // Default Direction 14925 14926 // Adjust 14927 $.effects.save(el, props); el.show(); // Save & Show 14928 $.effects.createWrapper(el); // Create Wrapper 14929 var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; 14930 var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; 14931 var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 2 : el.outerWidth({margin:true}) / 2); 14932 if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift 14933 14934 // Animation 14935 var animation = {opacity: mode == 'show' ? 1 : 0}; 14936 animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance; 14937 14938 // Animate 14939 el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { 14940 if(mode == 'hide') el.hide(); // Hide 14941 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore 14942 if(o.callback) o.callback.apply(this, arguments); // Callback 14943 el.dequeue(); 14944 }}); 14945 14946 }); 14947 14948}; 14949 14950})(jQuery); 14951/* 14952 * jQuery UI Effects Explode 1.8.16 14953 * 14954 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 14955 * Dual licensed under the MIT or GPL Version 2 licenses. 14956 * http://jquery.org/license 14957 * 14958 * http://docs.jquery.com/UI/Effects/Explode 14959 * 14960 * Depends: 14961 * jquery.effects.core.js 14962 */ 14963(function( $, undefined ) { 14964 14965$.effects.explode = function(o) { 14966 14967 return this.queue(function() { 14968 14969 var rows = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3; 14970 var cells = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3; 14971 14972 o.options.mode = o.options.mode == 'toggle' ? ($(this).is(':visible') ? 'hide' : 'show') : o.options.mode; 14973 var el = $(this).show().css('visibility', 'hidden'); 14974 var offset = el.offset(); 14975 14976 //Substract the margins - not fixing the problem yet. 14977 offset.top -= parseInt(el.css("marginTop"),10) || 0; 14978 offset.left -= parseInt(el.css("marginLeft"),10) || 0; 14979 14980 var width = el.outerWidth(true); 14981 var height = el.outerHeight(true); 14982 14983 for(var i=0;i<rows;i++) { // = 14984 for(var j=0;j<cells;j++) { // || 14985 el 14986 .clone() 14987 .appendTo('body') 14988 .wrap('<div></div>') 14989 .css({ 14990 position: 'absolute', 14991 visibility: 'visible', 14992 left: -j*(width/cells), 14993 top: -i*(height/rows) 14994 }) 14995 .parent() 14996 .addClass('ui-effects-explode') 14997 .css({ 14998 position: 'absolute', 14999 overflow: 'hidden', 15000 width: width/cells, 15001 height: height/rows, 15002 left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? (j-Math.floor(cells/2))*(width/cells) : 0), 15003 top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? (i-Math.floor(rows/2))*(height/rows) : 0), 15004 opacity: o.options.mode == 'show' ? 0 : 1 15005 }).animate({ 15006 left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? 0 : (j-Math.floor(cells/2))*(width/cells)), 15007 top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? 0 : (i-Math.floor(rows/2))*(height/rows)), 15008 opacity: o.options.mode == 'show' ? 1 : 0 15009 }, o.duration || 500); 15010 } 15011 } 15012 15013 // Set a timeout, to call the callback approx. when the other animations have finished 15014 setTimeout(function() { 15015 15016 o.options.mode == 'show' ? el.css({ visibility: 'visible' }) : el.css({ visibility: 'visible' }).hide(); 15017 if(o.callback) o.callback.apply(el[0]); // Callback 15018 el.dequeue(); 15019 15020 $('div.ui-effects-explode').remove(); 15021 15022 }, o.duration || 500); 15023 15024 15025 }); 15026 15027}; 15028 15029})(jQuery); 15030/* 15031 * jQuery UI Effects Fade 1.8.16 15032 * 15033 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 15034 * Dual licensed under the MIT or GPL Version 2 licenses. 15035 * http://jquery.org/license 15036 * 15037 * http://docs.jquery.com/UI/Effects/Fade 15038 * 15039 * Depends: 15040 * jquery.effects.core.js 15041 */ 15042(function( $, undefined ) { 15043 15044$.effects.fade = function(o) { 15045 return this.queue(function() { 15046 var elem = $(this), 15047 mode = $.effects.setMode(elem, o.options.mode || 'hide'); 15048 15049 elem.animate({ opacity: mode }, { 15050 queue: false, 15051 duration: o.duration, 15052 easing: o.options.easing, 15053 complete: function() { 15054 (o.callback && o.callback.apply(this, arguments)); 15055 elem.dequeue(); 15056 } 15057 }); 15058 }); 15059}; 15060 15061})(jQuery); 15062/* 15063 * jQuery UI Effects Fold 1.8.16 15064 * 15065 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 15066 * Dual licensed under the MIT or GPL Version 2 licenses. 15067 * http://jquery.org/license 15068 * 15069 * http://docs.jquery.com/UI/Effects/Fold 15070 * 15071 * Depends: 15072 * jquery.effects.core.js 15073 */ 15074(function( $, undefined ) { 15075 15076$.effects.fold = function(o) { 15077 15078 return this.queue(function() { 15079 15080 // Create element 15081 var el = $(this), props = ['position','top','bottom','left','right']; 15082 15083 // Set options 15084 var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode 15085 var size = o.options.size || 15; // Default fold size 15086 var horizFirst = !(!o.options.horizFirst); // Ensure a boolean value 15087 var duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2; 15088 15089 // Adjust 15090 $.effects.save(el, props); el.show(); // Save & Show 15091 var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper 15092 var widthFirst = ((mode == 'show') != horizFirst); 15093 var ref = widthFirst ? ['width', 'height'] : ['height', 'width']; 15094 var distance = widthFirst ? [wrapper.width(), wrapper.height()] : [wrapper.height(), wrapper.width()]; 15095 var percent = /([0-9]+)%/.exec(size); 15096 if(percent) size = parseInt(percent[1],10) / 100 * distance[mode == 'hide' ? 0 : 1]; 15097 if(mode == 'show') wrapper.css(horizFirst ? {height: 0, width: size} : {height: size, width: 0}); // Shift 15098 15099 // Animation 15100 var animation1 = {}, animation2 = {}; 15101 animation1[ref[0]] = mode == 'show' ? distance[0] : size; 15102 animation2[ref[1]] = mode == 'show' ? distance[1] : 0; 15103 15104 // Animate 15105 wrapper.animate(animation1, duration, o.options.easing) 15106 .animate(animation2, duration, o.options.easing, function() { 15107 if(mode == 'hide') el.hide(); // Hide 15108 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore 15109 if(o.callback) o.callback.apply(el[0], arguments); // Callback 15110 el.dequeue(); 15111 }); 15112 15113 }); 15114 15115}; 15116 15117})(jQuery); 15118/* 15119 * jQuery UI Effects Highlight 1.8.16 15120 * 15121 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 15122 * Dual licensed under the MIT or GPL Version 2 licenses. 15123 * http://jquery.org/license 15124 * 15125 * http://docs.jquery.com/UI/Effects/Highlight 15126 * 15127 * Depends: 15128 * jquery.effects.core.js 15129 */ 15130(function( $, undefined ) { 15131 15132$.effects.highlight = function(o) { 15133 return this.queue(function() { 15134 var elem = $(this), 15135 props = ['backgroundImage', 'backgroundColor', 'opacity'], 15136 mode = $.effects.setMode(elem, o.options.mode || 'show'), 15137 animation = { 15138 backgroundColor: elem.css('backgroundColor') 15139 }; 15140 15141 if (mode == 'hide') { 15142 animation.opacity = 0; 15143 } 15144 15145 $.effects.save(elem, props); 15146 elem 15147 .show() 15148 .css({ 15149 backgroundImage: 'none', 15150 backgroundColor: o.options.color || '#ffff99' 15151 }) 15152 .animate(animation, { 15153 queue: false, 15154 duration: o.duration, 15155 easing: o.options.easing, 15156 complete: function() { 15157 (mode == 'hide' && elem.hide()); 15158 $.effects.restore(elem, props); 15159 (mode == 'show' && !$.support.opacity && this.style.removeAttribute('filter')); 15160 (o.callback && o.callback.apply(this, arguments)); 15161 elem.dequeue(); 15162 } 15163 }); 15164 }); 15165}; 15166 15167})(jQuery); 15168/* 15169 * jQuery UI Effects Pulsate 1.8.16 15170 * 15171 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 15172 * Dual licensed under the MIT or GPL Version 2 licenses. 15173 * http://jquery.org/license 15174 * 15175 * http://docs.jquery.com/UI/Effects/Pulsate 15176 * 15177 * Depends: 15178 * jquery.effects.core.js 15179 */ 15180(function( $, undefined ) { 15181 15182$.effects.pulsate = function(o) { 15183 return this.queue(function() { 15184 var elem = $(this), 15185 mode = $.effects.setMode(elem, o.options.mode || 'show'); 15186 times = ((o.options.times || 5) * 2) - 1; 15187 duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2, 15188 isVisible = elem.is(':visible'), 15189 animateTo = 0; 15190 15191 if (!isVisible) { 15192 elem.css('opacity', 0).show(); 15193 animateTo = 1; 15194 } 15195 15196 if ((mode == 'hide' && isVisible) || (mode == 'show' && !isVisible)) { 15197 times--; 15198 } 15199 15200 for (var i = 0; i < times; i++) { 15201 elem.animate({ opacity: animateTo }, duration, o.options.easing); 15202 animateTo = (animateTo + 1) % 2; 15203 } 15204 15205 elem.animate({ opacity: animateTo }, duration, o.options.easing, function() { 15206 if (animateTo == 0) { 15207 elem.hide(); 15208 } 15209 (o.callback && o.callback.apply(this, arguments)); 15210 }); 15211 15212 elem 15213 .queue('fx', function() { elem.dequeue(); }) 15214 .dequeue(); 15215 }); 15216}; 15217 15218})(jQuery); 15219/* 15220 * jQuery UI Effects Scale 1.8.16 15221 * 15222 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 15223 * Dual licensed under the MIT or GPL Version 2 licenses. 15224 * http://jquery.org/license 15225 * 15226 * http://docs.jquery.com/UI/Effects/Scale 15227 * 15228 * Depends: 15229 * jquery.effects.core.js 15230 */ 15231(function( $, undefined ) { 15232 15233$.effects.puff = function(o) { 15234 return this.queue(function() { 15235 var elem = $(this), 15236 mode = $.effects.setMode(elem, o.options.mode || 'hide'), 15237 percent = parseInt(o.options.percent, 10) || 150, 15238 factor = percent / 100, 15239 original = { height: elem.height(), width: elem.width() }; 15240 15241 $.extend(o.options, { 15242 fade: true, 15243 mode: mode, 15244 percent: mode == 'hide' ? percent : 100, 15245 from: mode == 'hide' 15246 ? original 15247 : { 15248 height: original.height * factor, 15249 width: original.width * factor 15250 } 15251 }); 15252 15253 elem.effect('scale', o.options, o.duration, o.callback); 15254 elem.dequeue(); 15255 }); 15256}; 15257 15258$.effects.scale = function(o) { 15259 15260 return this.queue(function() { 15261 15262 // Create element 15263 var el = $(this); 15264 15265 // Set options 15266 var options = $.extend(true, {}, o.options); 15267 var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode 15268 var percent = parseInt(o.options.percent,10) || (parseInt(o.options.percent,10) == 0 ? 0 : (mode == 'hide' ? 0 : 100)); // Set default scaling percent 15269 var direction = o.options.direction || 'both'; // Set default axis 15270 var origin = o.options.origin; // The origin of the scaling 15271 if (mode != 'effect') { // Set default origin and restore for show/hide 15272 options.origin = origin || ['middle','center']; 15273 options.restore = true; 15274 } 15275 var original = {height: el.height(), width: el.width()}; // Save original 15276 el.from = o.options.from || (mode == 'show' ? {height: 0, width: 0} : original); // Default from state 15277 15278 // Adjust 15279 var factor = { // Set scaling factor 15280 y: direction != 'horizontal' ? (percent / 100) : 1, 15281 x: direction != 'vertical' ? (percent / 100) : 1 15282 }; 15283 el.to = {height: original.height * factor.y, width: original.width * factor.x}; // Set to state 15284 15285 if (o.options.fade) { // Fade option to support puff 15286 if (mode == 'show') {el.from.opacity = 0; el.to.opacity = 1;}; 15287 if (mode == 'hide') {el.from.opacity = 1; el.to.opacity = 0;}; 15288 }; 15289 15290 // Animation 15291 options.from = el.from; options.to = el.to; options.mode = mode; 15292 15293 // Animate 15294 el.effect('size', options, o.duration, o.callback); 15295 el.dequeue(); 15296 }); 15297 15298}; 15299 15300$.effects.size = function(o) { 15301 15302 return this.queue(function() { 15303 15304 // Create element 15305 var el = $(this), props = ['position','top','bottom','left','right','width','height','overflow','opacity']; 15306 var props1 = ['position','top','bottom','left','right','overflow','opacity']; // Always restore 15307 var props2 = ['width','height','overflow']; // Copy for children 15308 var cProps = ['fontSize']; 15309 var vProps = ['borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom']; 15310 var hProps = ['borderLeftWidth', 'borderRightWidth', 'paddingLeft', 'paddingRight']; 15311 15312 // Set options 15313 var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode 15314 var restore = o.options.restore || false; // Default restore 15315 var scale = o.options.scale || 'both'; // Default scale mode 15316 var origin = o.options.origin; // The origin of the sizing 15317 var original = {height: el.height(), width: el.width()}; // Save original 15318 el.from = o.options.from || original; // Default from state 15319 el.to = o.options.to || original; // Default to state 15320 // Adjust 15321 if (origin) { // Calculate baseline shifts 15322 var baseline = $.effects.getBaseline(origin, original); 15323 el.from.top = (original.height - el.from.height) * baseline.y; 15324 el.from.left = (original.width - el.from.width) * baseline.x; 15325 el.to.top = (original.height - el.to.height) * baseline.y; 15326 el.to.left = (original.width - el.to.width) * baseline.x; 15327 }; 15328 var factor = { // Set scaling factor 15329 from: {y: el.from.height / original.height, x: el.from.width / original.width}, 15330 to: {y: el.to.height / original.height, x: el.to.width / original.width} 15331 }; 15332 if (scale == 'box' || scale == 'both') { // Scale the css box 15333 if (factor.from.y != factor.to.y) { // Vertical props scaling 15334 props = props.concat(vProps); 15335 el.from = $.effects.setTransition(el, vProps, factor.from.y, el.from); 15336 el.to = $.effects.setTransition(el, vProps, factor.to.y, el.to); 15337 }; 15338 if (factor.from.x != factor.to.x) { // Horizontal props scaling 15339 props = props.concat(hProps); 15340 el.from = $.effects.setTransition(el, hProps, factor.from.x, el.from); 15341 el.to = $.effects.setTransition(el, hProps, factor.to.x, el.to); 15342 }; 15343 }; 15344 if (scale == 'content' || scale == 'both') { // Scale the content 15345 if (factor.from.y != factor.to.y) { // Vertical props scaling 15346 props = props.concat(cProps); 15347 el.from = $.effects.setTransition(el, cProps, factor.from.y, el.from); 15348 el.to = $.effects.setTransition(el, cProps, factor.to.y, el.to); 15349 }; 15350 }; 15351 $.effects.save(el, restore ? props : props1); el.show(); // Save & Show 15352 $.effects.createWrapper(el); // Create Wrapper 15353 el.css('overflow','hidden').css(el.from); // Shift 15354 15355 // Animate 15356 if (scale == 'content' || scale == 'both') { // Scale the children 15357 vProps = vProps.concat(['marginTop','marginBottom']).concat(cProps); // Add margins/font-size 15358 hProps = hProps.concat(['marginLeft','marginRight']); // Add margins 15359 props2 = props.concat(vProps).concat(hProps); // Concat 15360 el.find("*[width]").each(function(){ 15361 child = $(this); 15362 if (restore) $.effects.save(child, props2); 15363 var c_original = {height: child.height(), width: child.width()}; // Save original 15364 child.from = {height: c_original.height * factor.from.y, width: c_original.width * factor.from.x}; 15365 child.to = {height: c_original.height * factor.to.y, width: c_original.width * factor.to.x}; 15366 if (factor.from.y != factor.to.y) { // Vertical props scaling 15367 child.from = $.effects.setTransition(child, vProps, factor.from.y, child.from); 15368 child.to = $.effects.setTransition(child, vProps, factor.to.y, child.to); 15369 }; 15370 if (factor.from.x != factor.to.x) { // Horizontal props scaling 15371 child.from = $.effects.setTransition(child, hProps, factor.from.x, child.from); 15372 child.to = $.effects.setTransition(child, hProps, factor.to.x, child.to); 15373 }; 15374 child.css(child.from); // Shift children 15375 child.animate(child.to, o.duration, o.options.easing, function(){ 15376 if (restore) $.effects.restore(child, props2); // Restore children 15377 }); // Animate children 15378 }); 15379 }; 15380 15381 // Animate 15382 el.animate(el.to, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { 15383 if (el.to.opacity === 0) { 15384 el.css('opacity', el.from.opacity); 15385 } 15386 if(mode == 'hide') el.hide(); // Hide 15387 $.effects.restore(el, restore ? props : props1); $.effects.removeWrapper(el); // Restore 15388 if(o.callback) o.callback.apply(this, arguments); // Callback 15389 el.dequeue(); 15390 }}); 15391 15392 }); 15393 15394}; 15395 15396})(jQuery); 15397/* 15398 * jQuery UI Effects Shake 1.8.16 15399 * 15400 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 15401 * Dual licensed under the MIT or GPL Version 2 licenses. 15402 * http://jquery.org/license 15403 * 15404 * http://docs.jquery.com/UI/Effects/Shake 15405 * 15406 * Depends: 15407 * jquery.effects.core.js 15408 */ 15409(function( $, undefined ) { 15410 15411$.effects.shake = function(o) { 15412 15413 return this.queue(function() { 15414 15415 // Create element 15416 var el = $(this), props = ['position','top','bottom','left','right']; 15417 15418 // Set options 15419 var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode 15420 var direction = o.options.direction || 'left'; // Default direction 15421 var distance = o.options.distance || 20; // Default distance 15422 var times = o.options.times || 3; // Default # of times 15423 var speed = o.duration || o.options.duration || 140; // Default speed per shake 15424 15425 // Adjust 15426 $.effects.save(el, props); el.show(); // Save & Show 15427 $.effects.createWrapper(el); // Create Wrapper 15428 var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; 15429 var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; 15430 15431 // Animation 15432 var animation = {}, animation1 = {}, animation2 = {}; 15433 animation[ref] = (motion == 'pos' ? '-=' : '+=') + distance; 15434 animation1[ref] = (motion == 'pos' ? '+=' : '-=') + distance * 2; 15435 animation2[ref] = (motion == 'pos' ? '-=' : '+=') + distance * 2; 15436 15437 // Animate 15438 el.animate(animation, speed, o.options.easing); 15439 for (var i = 1; i < times; i++) { // Shakes 15440 el.animate(animation1, speed, o.options.easing).animate(animation2, speed, o.options.easing); 15441 }; 15442 el.animate(animation1, speed, o.options.easing). 15443 animate(animation, speed / 2, o.options.easing, function(){ // Last shake 15444 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore 15445 if(o.callback) o.callback.apply(this, arguments); // Callback 15446 }); 15447 el.queue('fx', function() { el.dequeue(); }); 15448 el.dequeue(); 15449 }); 15450 15451}; 15452 15453})(jQuery); 15454/* 15455 * jQuery UI Effects Slide 1.8.16 15456 * 15457 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 15458 * Dual licensed under the MIT or GPL Version 2 licenses. 15459 * http://jquery.org/license 15460 * 15461 * http://docs.jquery.com/UI/Effects/Slide 15462 * 15463 * Depends: 15464 * jquery.effects.core.js 15465 */ 15466(function( $, undefined ) { 15467 15468$.effects.slide = function(o) { 15469 15470 return this.queue(function() { 15471 15472 // Create element 15473 var el = $(this), props = ['position','top','bottom','left','right']; 15474 15475 // Set options 15476 var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode 15477 var direction = o.options.direction || 'left'; // Default Direction 15478 15479 // Adjust 15480 $.effects.save(el, props); el.show(); // Save & Show 15481 $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper 15482 var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; 15483 var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; 15484 var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) : el.outerWidth({margin:true})); 15485 if (mode == 'show') el.css(ref, motion == 'pos' ? (isNaN(distance) ? "-" + distance : -distance) : distance); // Shift 15486 15487 // Animation 15488 var animation = {}; 15489 animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance; 15490 15491 // Animate 15492 el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { 15493 if(mode == 'hide') el.hide(); // Hide 15494 $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore 15495 if(o.callback) o.callback.apply(this, arguments); // Callback 15496 el.dequeue(); 15497 }}); 15498 15499 }); 15500 15501}; 15502 15503})(jQuery); 15504/* 15505 * jQuery UI Effects Transfer 1.8.16 15506 * 15507 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 15508 * Dual licensed under the MIT or GPL Version 2 licenses. 15509 * http://jquery.org/license 15510 * 15511 * http://docs.jquery.com/UI/Effects/Transfer 15512 * 15513 * Depends: 15514 * jquery.effects.core.js 15515 */ 15516(function( $, undefined ) { 15517 15518$.effects.transfer = function(o) { 15519 return this.queue(function() { 15520 var elem = $(this), 15521 target = $(o.options.to), 15522 endPosition = target.offset(), 15523 animation = { 15524 top: endPosition.top, 15525 left: endPosition.left, 15526 height: target.innerHeight(), 15527 width: target.innerWidth() 15528 }, 15529 startPosition = elem.offset(), 15530 transfer = $('<div class="ui-effects-transfer"></div>') 15531 .appendTo(document.body) 15532 .addClass(o.options.className) 15533 .css({ 15534 top: startPosition.top, 15535 left: startPosition.left, 15536 height: elem.innerHeight(), 15537 width: elem.innerWidth(), 15538 position: 'absolute' 15539 }) 15540 .animate(animation, o.duration, o.options.easing, function() { 15541 transfer.remove(); 15542 (o.callback && o.callback.apply(elem[0], arguments)); 15543 elem.dequeue(); 15544 }); 15545 }); 15546}; 15547 15548})(jQuery); 15549/* 15550 * jQuery UI Accordion 1.8.16 15551 * 15552 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 15553 * Dual licensed under the MIT or GPL Version 2 licenses. 15554 * http://jquery.org/license 15555 * 15556 * http://docs.jquery.com/UI/Accordion 15557 * 15558 * Depends: 15559 * jquery.ui.core.js 15560 * jquery.ui.widget.js 15561 */ 15562(function( $, undefined ) { 15563 15564$.widget( "ui.accordion", { 15565 options: { 15566 active: 0, 15567 animated: "slide", 15568 autoHeight: true, 15569 clearStyle: false, 15570 collapsible: false, 15571 event: "click", 15572 fillSpace: false, 15573 header: "> li > :first-child,> :not(li):even", 15574 icons: { 15575 header: "ui-icon-triangle-1-e", 15576 headerSelected: "ui-icon-triangle-1-s" 15577 }, 15578 navigation: false, 15579 navigationFilter: function() { 15580 return this.href.toLowerCase() === location.href.toLowerCase(); 15581 } 15582 }, 15583 15584 _create: function() { 15585 var self = this, 15586 options = self.options; 15587 15588 self.running = 0; 15589 15590 self.element 15591 .addClass( "ui-accordion ui-widget ui-helper-reset" ) 15592 // in lack of child-selectors in CSS 15593 // we need to mark top-LIs in a UL-accordion for some IE-fix 15594 .children( "li" ) 15595 .addClass( "ui-accordion-li-fix" ); 15596 15597 self.headers = self.element.find( options.header ) 15598 .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ) 15599 .bind( "mouseenter.accordion", function() { 15600 if ( options.disabled ) { 15601 return; 15602 } 15603 $( this ).addClass( "ui-state-hover" ); 15604 }) 15605 .bind( "mouseleave.accordion", function() { 15606 if ( options.disabled ) { 15607 return; 15608 } 15609 $( this ).removeClass( "ui-state-hover" ); 15610 }) 15611 .bind( "focus.accordion", function() { 15612 if ( options.disabled ) { 15613 return; 15614 } 15615 $( this ).addClass( "ui-state-focus" ); 15616 }) 15617 .bind( "blur.accordion", function() { 15618 if ( options.disabled ) { 15619 return; 15620 } 15621 $( this ).removeClass( "ui-state-focus" ); 15622 }); 15623 15624 self.headers.next() 15625 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ); 15626 15627 if ( options.navigation ) { 15628 var current = self.element.find( "a" ).filter( options.navigationFilter ).eq( 0 ); 15629 if ( current.length ) { 15630 var header = current.closest( ".ui-accordion-header" ); 15631 if ( header.length ) { 15632 // anchor within header 15633 self.active = header; 15634 } else { 15635 // anchor within content 15636 self.active = current.closest( ".ui-accordion-content" ).prev(); 15637 } 15638 } 15639 } 15640 15641 self.active = self._findActive( self.active || options.active ) 15642 .addClass( "ui-state-default ui-state-active" ) 15643 .toggleClass( "ui-corner-all" ) 15644 .toggleClass( "ui-corner-top" ); 15645 self.active.next().addClass( "ui-accordion-content-active" ); 15646 15647 self._createIcons(); 15648 self.resize(); 15649 15650 // ARIA 15651 self.element.attr( "role", "tablist" ); 15652 15653 self.headers 15654 .attr( "role", "tab" ) 15655 .bind( "keydown.accordion", function( event ) { 15656 return self._keydown( event ); 15657 }) 15658 .next() 15659 .attr( "role", "tabpanel" ); 15660 15661 self.headers 15662 .not( self.active || "" ) 15663 .attr({ 15664 "aria-expanded": "false", 15665 "aria-selected": "false", 15666 tabIndex: -1 15667 }) 15668 .next() 15669 .hide(); 15670 15671 // make sure at least one header is in the tab order 15672 if ( !self.active.length ) { 15673 self.headers.eq( 0 ).attr( "tabIndex", 0 ); 15674 } else { 15675 self.active 15676 .attr({ 15677 "aria-expanded": "true", 15678 "aria-selected": "true", 15679 tabIndex: 0 15680 }); 15681 } 15682 15683 // only need links in tab order for Safari 15684 if ( !$.browser.safari ) { 15685 self.headers.find( "a" ).attr( "tabIndex", -1 ); 15686 } 15687 15688 if ( options.event ) { 15689 self.headers.bind( options.event.split(" ").join(".accordion ") + ".accordion", function(event) { 15690 self._clickHandler.call( self, event, this ); 15691 event.preventDefault(); 15692 }); 15693 } 15694 }, 15695 15696 _createIcons: function() { 15697 var options = this.options; 15698 if ( options.icons ) { 15699 $( "<span></span>" ) 15700 .addClass( "ui-icon " + options.icons.header ) 15701 .prependTo( this.headers ); 15702 this.active.children( ".ui-icon" ) 15703 .toggleClass(options.icons.header) 15704 .toggleClass(options.icons.headerSelected); 15705 this.element.addClass( "ui-accordion-icons" ); 15706 } 15707 }, 15708 15709 _destroyIcons: function() { 15710 this.headers.children( ".ui-icon" ).remove(); 15711 this.element.removeClass( "ui-accordion-icons" ); 15712 }, 15713 15714 destroy: function() { 15715 var options = this.options; 15716 15717 this.element 15718 .removeClass( "ui-accordion ui-widget ui-helper-reset" ) 15719 .removeAttr( "role" ); 15720 15721 this.headers 15722 .unbind( ".accordion" ) 15723 .removeClass( "ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) 15724 .removeAttr( "role" ) 15725 .removeAttr( "aria-expanded" ) 15726 .removeAttr( "aria-selected" ) 15727 .removeAttr( "tabIndex" ); 15728 15729 this.headers.find( "a" ).removeAttr( "tabIndex" ); 15730 this._destroyIcons(); 15731 var contents = this.headers.next() 15732 .css( "display", "" ) 15733 .removeAttr( "role" ) 15734 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled" ); 15735 if ( options.autoHeight || options.fillHeight ) { 15736 contents.css( "height", "" ); 15737 } 15738 15739 return $.Widget.prototype.destroy.call( this ); 15740 }, 15741 15742 _setOption: function( key, value ) { 15743 $.Widget.prototype._setOption.apply( this, arguments ); 15744 15745 if ( key == "active" ) { 15746 this.activate( value ); 15747 } 15748 if ( key == "icons" ) { 15749 this._destroyIcons(); 15750 if ( value ) { 15751 this._createIcons(); 15752 } 15753 } 15754 // #5332 - opacity doesn't cascade to positioned elements in IE 15755 // so we need to add the disabled class to the headers and panels 15756 if ( key == "disabled" ) { 15757 this.headers.add(this.headers.next()) 15758 [ value ? "addClass" : "removeClass" ]( 15759 "ui-accordion-disabled ui-state-disabled" ); 15760 } 15761 }, 15762 15763 _keydown: function( event ) { 15764 if ( this.options.disabled || event.altKey || event.ctrlKey ) { 15765 return; 15766 } 15767 15768 var keyCode = $.ui.keyCode, 15769 length = this.headers.length, 15770 currentIndex = this.headers.index( event.target ), 15771 toFocus = false; 15772 15773 switch ( event.keyCode ) { 15774 case keyCode.RIGHT: 15775 case keyCode.DOWN: 15776 toFocus = this.headers[ ( currentIndex + 1 ) % length ]; 15777 break; 15778 case keyCode.LEFT: 15779 case keyCode.UP: 15780 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; 15781 break; 15782 case keyCode.SPACE: 15783 case keyCode.ENTER: 15784 this._clickHandler( { target: event.target }, event.target ); 15785 event.preventDefault(); 15786 } 15787 15788 if ( toFocus ) { 15789 $( event.target ).attr( "tabIndex", -1 ); 15790 $( toFocus ).attr( "tabIndex", 0 ); 15791 toFocus.focus(); 15792 return false; 15793 } 15794 15795 return true; 15796 }, 15797 15798 resize: function() { 15799 var options = this.options, 15800 maxHeight; 15801 15802 if ( options.fillSpace ) { 15803 if ( $.browser.msie ) { 15804 var defOverflow = this.element.parent().css( "overflow" ); 15805 this.element.parent().css( "overflow", "hidden"); 15806 } 15807 maxHeight = this.element.parent().height(); 15808 if ($.browser.msie) { 15809 this.element.parent().css( "overflow", defOverflow ); 15810 } 15811 15812 this.headers.each(function() { 15813 maxHeight -= $( this ).outerHeight( true ); 15814 }); 15815 15816 this.headers.next() 15817 .each(function() { 15818 $( this ).height( Math.max( 0, maxHeight - 15819 $( this ).innerHeight() + $( this ).height() ) ); 15820 }) 15821 .css( "overflow", "auto" ); 15822 } else if ( options.autoHeight ) { 15823 maxHeight = 0; 15824 this.headers.next() 15825 .each(function() { 15826 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); 15827 }) 15828 .height( maxHeight ); 15829 } 15830 15831 return this; 15832 }, 15833 15834 activate: function( index ) { 15835 // TODO this gets called on init, changing the option without an explicit call for that 15836 this.options.active = index; 15837 // call clickHandler with custom event 15838 var active = this._findActive( index )[ 0 ]; 15839 this._clickHandler( { target: active }, active ); 15840 15841 return this; 15842 }, 15843 15844 _findActive: function( selector ) { 15845 return selector 15846 ? typeof selector === "number" 15847 ? this.headers.filter( ":eq(" + selector + ")" ) 15848 : this.headers.not( this.headers.not( selector ) ) 15849 : selector === false 15850 ? $( [] ) 15851 : this.headers.filter( ":eq(0)" ); 15852 }, 15853 15854 // TODO isn't event.target enough? why the separate target argument? 15855 _clickHandler: function( event, target ) { 15856 var options = this.options; 15857 if ( options.disabled ) { 15858 return; 15859 } 15860 15861 // called only when using activate(false) to close all parts programmatically 15862 if ( !event.target ) { 15863 if ( !options.collapsible ) { 15864 return; 15865 } 15866 this.active 15867 .removeClass( "ui-state-active ui-corner-top" ) 15868 .addClass( "ui-state-default ui-corner-all" ) 15869 .children( ".ui-icon" ) 15870 .removeClass( options.icons.headerSelected ) 15871 .addClass( options.icons.header ); 15872 this.active.next().addClass( "ui-accordion-content-active" ); 15873 var toHide = this.active.next(), 15874 data = { 15875 options: options, 15876 newHeader: $( [] ), 15877 oldHeader: options.active, 15878 newContent: $( [] ), 15879 oldContent: toHide 15880 }, 15881 toShow = ( this.active = $( [] ) ); 15882 this._toggle( toShow, toHide, data ); 15883 return; 15884 } 15885 15886 // get the click target 15887 var clicked = $( event.currentTarget || target ), 15888 clickedIsActive = clicked[0] === this.active[0]; 15889 15890 // TODO the option is changed, is that correct? 15891 // TODO if it is correct, shouldn't that happen after determining that the click is valid? 15892 options.active = options.collapsible && clickedIsActive ? 15893 false : 15894 this.headers.index( clicked ); 15895 15896 // if animations are still active, or the active header is the target, ignore click 15897 if ( this.running || ( !options.collapsible && clickedIsActive ) ) { 15898 return; 15899 } 15900 15901 // find elements to show and hide 15902 var active = this.active, 15903 toShow = clicked.next(), 15904 toHide = this.active.next(), 15905 data = { 15906 options: options, 15907 newHeader: clickedIsActive && options.collapsible ? $([]) : clicked, 15908 oldHeader: this.active, 15909 newContent: clickedIsActive && options.collapsible ? $([]) : toShow, 15910 oldContent: toHide 15911 }, 15912 down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] ); 15913 15914 // when the call to ._toggle() comes after the class changes 15915 // it causes a very odd bug in IE 8 (see #6720) 15916 this.active = clickedIsActive ? $([]) : clicked; 15917 this._toggle( toShow, toHide, data, clickedIsActive, down ); 15918 15919 // switch classes 15920 active 15921 .removeClass( "ui-state-active ui-corner-top" ) 15922 .addClass( "ui-state-default ui-corner-all" ) 15923 .children( ".ui-icon" ) 15924 .removeClass( options.icons.headerSelected ) 15925 .addClass( options.icons.header ); 15926 if ( !clickedIsActive ) { 15927 clicked 15928 .removeClass( "ui-state-default ui-corner-all" ) 15929 .addClass( "ui-state-active ui-corner-top" ) 15930 .children( ".ui-icon" ) 15931 .removeClass( options.icons.header ) 15932 .addClass( options.icons.headerSelected ); 15933 clicked 15934 .next() 15935 .addClass( "ui-accordion-content-active" ); 15936 } 15937 15938 return; 15939 }, 15940 15941 _toggle: function( toShow, toHide, data, clickedIsActive, down ) { 15942 var self = this, 15943 options = self.options; 15944 15945 self.toShow = toShow; 15946 self.toHide = toHide; 15947 self.data = data; 15948 15949 var complete = function() { 15950 if ( !self ) { 15951 return; 15952 } 15953 return self._completed.apply( self, arguments ); 15954 }; 15955 15956 // trigger changestart event 15957 self._trigger( "changestart", null, self.data ); 15958 15959 // count elements to animate 15960 self.running = toHide.size() === 0 ? toShow.size() : toHide.size(); 15961 15962 if ( options.animated ) { 15963 var animOptions = {}; 15964 15965 if ( options.collapsible && clickedIsActive ) { 15966 animOptions = { 15967 toShow: $( [] ), 15968 toHide: toHide, 15969 complete: complete, 15970 down: down, 15971 autoHeight: options.autoHeight || options.fillSpace 15972 }; 15973 } else { 15974 animOptions = { 15975 toShow: toShow, 15976 toHide: toHide, 15977 complete: complete, 15978 down: down, 15979 autoHeight: options.autoHeight || options.fillSpace 15980 }; 15981 } 15982 15983 if ( !options.proxied ) { 15984 options.proxied = options.animated; 15985 } 15986 15987 if ( !options.proxiedDuration ) { 15988 options.proxiedDuration = options.duration; 15989 } 15990 15991 options.animated = $.isFunction( options.proxied ) ? 15992 options.proxied( animOptions ) : 15993 options.proxied; 15994 15995 options.duration = $.isFunction( options.proxiedDuration ) ? 15996 options.proxiedDuration( animOptions ) : 15997 options.proxiedDuration; 15998 15999 var animations = $.ui.accordion.animations, 16000 duration = options.duration, 16001 easing = options.animated; 16002 16003 if ( easing && !animations[ easing ] && !$.easing[ easing ] ) { 16004 easing = "slide"; 16005 } 16006 if ( !animations[ easing ] ) { 16007 animations[ easing ] = function( options ) { 16008 this.slide( options, { 16009 easing: easing, 16010 duration: duration || 700 16011 }); 16012 }; 16013 } 16014 16015 animations[ easing ]( animOptions ); 16016 } else { 16017 if ( options.collapsible && clickedIsActive ) { 16018 toShow.toggle(); 16019 } else { 16020 toHide.hide(); 16021 toShow.show(); 16022 } 16023 16024 complete( true ); 16025 } 16026 16027 // TODO assert that the blur and focus triggers are really necessary, remove otherwise 16028 toHide.prev() 16029 .attr({ 16030 "aria-expanded": "false", 16031 "aria-selected": "false", 16032 tabIndex: -1 16033 }) 16034 .blur(); 16035 toShow.prev() 16036 .attr({ 16037 "aria-expanded": "true", 16038 "aria-selected": "true", 16039 tabIndex: 0 16040 }) 16041 .focus(); 16042 }, 16043 16044 _completed: function( cancel ) { 16045 this.running = cancel ? 0 : --this.running; 16046 if ( this.running ) { 16047 return; 16048 } 16049 16050 if ( this.options.clearStyle ) { 16051 this.toShow.add( this.toHide ).css({ 16052 height: "", 16053 overflow: "" 16054 }); 16055 } 16056 16057 // other classes are removed before the animation; this one needs to stay until completed 16058 this.toHide.removeClass( "ui-accordion-content-active" ); 16059 // Work around for rendering bug in IE (#5421) 16060 if ( this.toHide.length ) { 16061 this.toHide.parent()[0].className = this.toHide.parent()[0].className; 16062 } 16063 16064 this._trigger( "change", null, this.data ); 16065 } 16066}); 16067 16068$.extend( $.ui.accordion, { 16069 version: "1.8.16", 16070 animations: { 16071 slide: function( options, additions ) { 16072 options = $.extend({ 16073 easing: "swing", 16074 duration: 300 16075 }, options, additions ); 16076 if ( !options.toHide.size() ) { 16077 options.toShow.animate({ 16078 height: "show", 16079 paddingTop: "show", 16080 paddingBottom: "show" 16081 }, options ); 16082 return; 16083 } 16084 if ( !options.toShow.size() ) { 16085 options.toHide.animate({ 16086 height: "hide", 16087 paddingTop: "hide", 16088 paddingBottom: "hide" 16089 }, options ); 16090 return; 16091 } 16092 var overflow = options.toShow.css( "overflow" ), 16093 percentDone = 0, 16094 showProps = {}, 16095 hideProps = {}, 16096 fxAttrs = [ "height", "paddingTop", "paddingBottom" ], 16097 originalWidth; 16098 // fix width before calculating height of hidden element 16099 var s = options.toShow; 16100 originalWidth = s[0].style.width; 16101 s.width( parseInt( s.parent().width(), 10 ) 16102 - parseInt( s.css( "paddingLeft" ), 10 ) 16103 - parseInt( s.css( "paddingRight" ), 10 ) 16104 - ( parseInt( s.css( "borderLeftWidth" ), 10 ) || 0 ) 16105 - ( parseInt( s.css( "borderRightWidth" ), 10) || 0 ) ); 16106 16107 $.each( fxAttrs, function( i, prop ) { 16108 hideProps[ prop ] = "hide"; 16109 16110 var parts = ( "" + $.css( options.toShow[0], prop ) ).match( /^([\d+-.]+)(.*)$/ ); 16111 showProps[ prop ] = { 16112 value: parts[ 1 ], 16113 unit: parts[ 2 ] || "px" 16114 }; 16115 }); 16116 options.toShow.css({ height: 0, overflow: "hidden" }).show(); 16117 options.toHide 16118 .filter( ":hidden" ) 16119 .each( options.complete ) 16120 .end() 16121 .filter( ":visible" ) 16122 .animate( hideProps, { 16123 step: function( now, settings ) { 16124 // only calculate the percent when animating height 16125 // IE gets very inconsistent results when animating elements 16126 // with small values, which is common for padding 16127 if ( settings.prop == "height" ) { 16128 percentDone = ( settings.end - settings.start === 0 ) ? 0 : 16129 ( settings.now - settings.start ) / ( settings.end - settings.start ); 16130 } 16131 16132 options.toShow[ 0 ].style[ settings.prop ] = 16133 ( percentDone * showProps[ settings.prop ].value ) 16134 + showProps[ settings.prop ].unit; 16135 }, 16136 duration: options.duration, 16137 easing: options.easing, 16138 complete: function() { 16139 if ( !options.autoHeight ) { 16140 options.toShow.css( "height", "" ); 16141 } 16142 options.toShow.css({ 16143 width: originalWidth, 16144 overflow: overflow 16145 }); 16146 options.complete(); 16147 } 16148 }); 16149 }, 16150 bounceslide: function( options ) { 16151 this.slide( options, { 16152 easing: options.down ? "easeOutBounce" : "swing", 16153 duration: options.down ? 1000 : 200 16154 }); 16155 } 16156 } 16157}); 16158 16159})( jQuery ); 16160/* 16161 * jQuery UI Autocomplete 1.8.16 16162 * 16163 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 16164 * Dual licensed under the MIT or GPL Version 2 licenses. 16165 * http://jquery.org/license 16166 * 16167 * http://docs.jquery.com/UI/Autocomplete 16168 * 16169 * Depends: 16170 * jquery.ui.core.js 16171 * jquery.ui.widget.js 16172 * jquery.ui.position.js 16173 */ 16174(function( $, undefined ) { 16175 16176// used to prevent race conditions with remote data sources 16177var requestIndex = 0; 16178 16179$.widget( "ui.autocomplete", { 16180 options: { 16181 appendTo: "body", 16182 autoFocus: false, 16183 delay: 300, 16184 minLength: 1, 16185 position: { 16186 my: "left top", 16187 at: "left bottom", 16188 collision: "none" 16189 }, 16190 source: null 16191 }, 16192 16193 pending: 0, 16194 16195 _create: function() { 16196 var self = this, 16197 doc = this.element[ 0 ].ownerDocument, 16198 suppressKeyPress; 16199 16200 this.element 16201 .addClass( "ui-autocomplete-input" ) 16202 .attr( "autocomplete", "off" ) 16203 // TODO verify these actually work as intended 16204 .attr({ 16205 role: "textbox", 16206 "aria-autocomplete": "list", 16207 "aria-haspopup": "true" 16208 }) 16209 .bind( "keydown.autocomplete", function( event ) { 16210 if ( self.options.disabled || self.element.propAttr( "readOnly" ) ) { 16211 return; 16212 } 16213 16214 suppressKeyPress = false; 16215 var keyCode = $.ui.keyCode; 16216 switch( event.keyCode ) { 16217 case keyCode.PAGE_UP: 16218 self._move( "previousPage", event ); 16219 break; 16220 case keyCode.PAGE_DOWN: 16221 self._move( "nextPage", event ); 16222 break; 16223 case keyCode.UP: 16224 self._move( "previous", event ); 16225 // prevent moving cursor to beginning of text field in some browsers 16226 event.preventDefault(); 16227 break; 16228 case keyCode.DOWN: 16229 self._move( "next", event ); 16230 // prevent moving cursor to end of text field in some browsers 16231 event.preventDefault(); 16232 break; 16233 case keyCode.ENTER: 16234 case keyCode.NUMPAD_ENTER: 16235 // when menu is open and has focus 16236 if ( self.menu.active ) { 16237 // #6055 - Opera still allows the keypress to occur 16238 // which causes forms to submit 16239 suppressKeyPress = true; 16240 event.preventDefault(); 16241 } 16242 //passthrough - ENTER and TAB both select the current element 16243 case keyCode.TAB: 16244 if ( !self.menu.active ) { 16245 return; 16246 } 16247 self.menu.select( event ); 16248 break; 16249 case keyCode.ESCAPE: 16250 self.element.val( self.term ); 16251 self.close( event ); 16252 break; 16253 default: 16254 // keypress is triggered before the input value is changed 16255 clearTimeout( self.searching ); 16256 self.searching = setTimeout(function() { 16257 // only search if the value has changed 16258 if ( self.term != self.element.val() ) { 16259 self.selectedItem = null; 16260 self.search( null, event ); 16261 } 16262 }, self.options.delay ); 16263 break; 16264 } 16265 }) 16266 .bind( "keypress.autocomplete", function( event ) { 16267 if ( suppressKeyPress ) { 16268 suppressKeyPress = false; 16269 event.preventDefault(); 16270 } 16271 }) 16272 .bind( "focus.autocomplete", function() { 16273 if ( self.options.disabled ) { 16274 return; 16275 } 16276 16277 self.selectedItem = null; 16278 self.previous = self.element.val(); 16279 }) 16280 .bind( "blur.autocomplete", function( event ) { 16281 if ( self.options.disabled ) { 16282 return; 16283 } 16284 16285 clearTimeout( self.searching ); 16286 // clicks on the menu (or a button to trigger a search) will cause a blur event 16287 self.closing = setTimeout(function() { 16288 self.close( event ); 16289 self._change( event ); 16290 }, 150 ); 16291 }); 16292 this._initSource(); 16293 this.response = function() { 16294 return self._response.apply( self, arguments ); 16295 }; 16296 this.menu = $( "<ul></ul>" ) 16297 .addClass( "ui-autocomplete" ) 16298 .appendTo( $( this.options.appendTo || "body", doc )[0] ) 16299 // prevent the close-on-blur in case of a "slow" click on the menu (long mousedown) 16300 .mousedown(function( event ) { 16301 // clicking on the scrollbar causes focus to shift to the body 16302 // but we can't detect a mouseup or a click immediately afterward 16303 // so we have to track the next mousedown and close the menu if 16304 // the user clicks somewhere outside of the autocomplete 16305 var menuElement = self.menu.element[ 0 ]; 16306 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) { 16307 setTimeout(function() { 16308 $( document ).one( 'mousedown', function( event ) { 16309 if ( event.target !== self.element[ 0 ] && 16310 event.target !== menuElement && 16311 !$.ui.contains( menuElement, event.target ) ) { 16312 self.close(); 16313 } 16314 }); 16315 }, 1 ); 16316 } 16317 16318 // use another timeout to make sure the blur-event-handler on the input was already triggered 16319 setTimeout(function() { 16320 clearTimeout( self.closing ); 16321 }, 13); 16322 }) 16323 .menu({ 16324 focus: function( event, ui ) { 16325 var item = ui.item.data( "item.autocomplete" ); 16326 if ( false !== self._trigger( "focus", event, { item: item } ) ) { 16327 // use value to match what will end up in the input, if it was a key event 16328 if ( /^key/.test(event.originalEvent.type) ) { 16329 self.element.val( item.value ); 16330 } 16331 } 16332 }, 16333 selected: function( event, ui ) { 16334 var item = ui.item.data( "item.autocomplete" ), 16335 previous = self.previous; 16336 16337 // only trigger when focus was lost (click on menu) 16338 if ( self.element[0] !== doc.activeElement ) { 16339 self.element.focus(); 16340 self.previous = previous; 16341 // #6109 - IE triggers two focus events and the second 16342 // is asynchronous, so we need to reset the previous 16343 // term synchronously and asynchronously :-( 16344 setTimeout(function() { 16345 self.previous = previous; 16346 self.selectedItem = item; 16347 }, 1); 16348 } 16349 16350 if ( false !== self._trigger( "select", event, { item: item } ) ) { 16351 self.element.val( item.value ); 16352 } 16353 // reset the term after the select event 16354 // this allows custom select handling to work properly 16355 self.term = self.element.val(); 16356 16357 self.close( event ); 16358 self.selectedItem = item; 16359 }, 16360 blur: function( event, ui ) { 16361 // don't set the value of the text field if it's already correct 16362 // this prevents moving the cursor unnecessarily 16363 if ( self.menu.element.is(":visible") && 16364 ( self.element.val() !== self.term ) ) { 16365 self.element.val( self.term ); 16366 } 16367 } 16368 }) 16369 .zIndex( this.element.zIndex() + 1 ) 16370 // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781 16371 .css({ top: 0, left: 0 }) 16372 .hide() 16373 .data( "menu" ); 16374 if ( $.fn.bgiframe ) { 16375 this.menu.element.bgiframe(); 16376 } 16377 }, 16378 16379 destroy: function() { 16380 this.element 16381 .removeClass( "ui-autocomplete-input" ) 16382 .removeAttr( "autocomplete" ) 16383 .removeAttr( "role" ) 16384 .removeAttr( "aria-autocomplete" ) 16385 .removeAttr( "aria-haspopup" ); 16386 this.menu.element.remove(); 16387 $.Widget.prototype.destroy.call( this ); 16388 }, 16389 16390 _setOption: function( key, value ) { 16391 $.Widget.prototype._setOption.apply( this, arguments ); 16392 if ( key === "source" ) { 16393 this._initSource(); 16394 } 16395 if ( key === "appendTo" ) { 16396 this.menu.element.appendTo( $( value || "body", this.element[0].ownerDocument )[0] ) 16397 } 16398 if ( key === "disabled" && value && this.xhr ) { 16399 this.xhr.abort(); 16400 } 16401 }, 16402 16403 _initSource: function() { 16404 var self = this, 16405 array, 16406 url; 16407 if ( $.isArray(this.options.source) ) { 16408 array = this.options.source; 16409 this.source = function( request, response ) { 16410 response( $.ui.autocomplete.filter(array, request.term) ); 16411 }; 16412 } else if ( typeof this.options.source === "string" ) { 16413 url = this.options.source; 16414 this.source = function( request, response ) { 16415 if ( self.xhr ) { 16416 self.xhr.abort(); 16417 } 16418 self.xhr = $.ajax({ 16419 url: url, 16420 data: request, 16421 dataType: "json", 16422 autocompleteRequest: ++requestIndex, 16423 success: function( data, status ) { 16424 if ( this.autocompleteRequest === requestIndex ) { 16425 response( data ); 16426 } 16427 }, 16428 error: function() { 16429 if ( this.autocompleteRequest === requestIndex ) { 16430 response( [] ); 16431 } 16432 } 16433 }); 16434 }; 16435 } else { 16436 this.source = this.options.source; 16437 } 16438 }, 16439 16440 search: function( value, event ) { 16441 value = value != null ? value : this.element.val(); 16442 16443 // always save the actual value, not the one passed as an argument 16444 this.term = this.element.val(); 16445 16446 if ( value.length < this.options.minLength ) { 16447 return this.close( event ); 16448 } 16449 16450 clearTimeout( this.closing ); 16451 if ( this._trigger( "search", event ) === false ) { 16452 return; 16453 } 16454 16455 return this._search( value ); 16456 }, 16457 16458 _search: function( value ) { 16459 this.pending++; 16460 this.element.addClass( "ui-autocomplete-loading" ); 16461 16462 this.source( { term: value }, this.response ); 16463 }, 16464 16465 _response: function( content ) { 16466 if ( !this.options.disabled && content && content.length ) { 16467 content = this._normalize( content ); 16468 this._suggest( content ); 16469 this._trigger( "open" ); 16470 } else { 16471 this.close(); 16472 } 16473 this.pending--; 16474 if ( !this.pending ) { 16475 this.element.removeClass( "ui-autocomplete-loading" ); 16476 } 16477 }, 16478 16479 close: function( event ) { 16480 clearTimeout( this.closing ); 16481 if ( this.menu.element.is(":visible") ) { 16482 this.menu.element.hide(); 16483 this.menu.deactivate(); 16484 this._trigger( "close", event ); 16485 } 16486 }, 16487 16488 _change: function( event ) { 16489 if ( this.previous !== this.element.val() ) { 16490 this._trigger( "change", event, { item: this.selectedItem } ); 16491 } 16492 }, 16493 16494 _normalize: function( items ) { 16495 // assume all items have the right format when the first item is complete 16496 if ( items.length && items[0].label && items[0].value ) { 16497 return items; 16498 } 16499 return $.map( items, function(item) { 16500 if ( typeof item === "string" ) { 16501 return { 16502 label: item, 16503 value: item 16504 }; 16505 } 16506 return $.extend({ 16507 label: item.label || item.value, 16508 value: item.value || item.label 16509 }, item ); 16510 }); 16511 }, 16512 16513 _suggest: function( items ) { 16514 var ul = this.menu.element 16515 .empty() 16516 .zIndex( this.element.zIndex() + 1 ); 16517 this._renderMenu( ul, items ); 16518 // TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate 16519 this.menu.deactivate(); 16520 this.menu.refresh(); 16521 16522 // size and position menu 16523 ul.show(); 16524 this._resizeMenu(); 16525 ul.position( $.extend({ 16526 of: this.element 16527 }, this.options.position )); 16528 16529 if ( this.options.autoFocus ) { 16530 this.menu.next( new $.Event("mouseover") ); 16531 } 16532 }, 16533 16534 _resizeMenu: function() { 16535 var ul = this.menu.element; 16536 ul.outerWidth( Math.max( 16537 ul.width( "" ).outerWidth(), 16538 this.element.outerWidth() 16539 ) ); 16540 }, 16541 16542 _renderMenu: function( ul, items ) { 16543 var self = this; 16544 $.each( items, function( index, item ) { 16545 self._renderItem( ul, item ); 16546 }); 16547 }, 16548 16549 _renderItem: function( ul, item) { 16550 return $( "<li></li>" ) 16551 .data( "item.autocomplete", item ) 16552 .append( $( "<a></a>" ).text( item.label ) ) 16553 .appendTo( ul ); 16554 }, 16555 16556 _move: function( direction, event ) { 16557 if ( !this.menu.element.is(":visible") ) { 16558 this.search( null, event ); 16559 return; 16560 } 16561 if ( this.menu.first() && /^previous/.test(direction) || 16562 this.menu.last() && /^next/.test(direction) ) { 16563 this.element.val( this.term ); 16564 this.menu.deactivate(); 16565 return; 16566 } 16567 this.menu[ direction ]( event ); 16568 }, 16569 16570 widget: function() { 16571 return this.menu.element; 16572 } 16573}); 16574 16575$.extend( $.ui.autocomplete, { 16576 escapeRegex: function( value ) { 16577 return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 16578 }, 16579 filter: function(array, term) { 16580 var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" ); 16581 return $.grep( array, function(value) { 16582 return matcher.test( value.label || value.value || value ); 16583 }); 16584 } 16585}); 16586 16587}( jQuery )); 16588 16589/* 16590 * jQuery UI Menu (not officially released) 16591 * 16592 * This widget isn't yet finished and the API is subject to change. We plan to finish 16593 * it for the next release. You're welcome to give it a try anyway and give us feedback, 16594 * as long as you're okay with migrating your code later on. We can help with that, too. 16595 * 16596 * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 16597 * Dual licensed under the MIT or GPL Version 2 licenses. 16598 * http://jquery.org/license 16599 * 16600 * http://docs.jquery.com/UI/Menu 16601 * 16602 * Depends: 16603 * jquery.ui.core.js 16604 * jquery.ui.widget.js 16605 */ 16606(function($) { 16607 16608$.widget("ui.menu", { 16609 _create: function() { 16610 var self = this; 16611 this.element 16612 .addClass("ui-menu ui-widget ui-widget-content ui-corner-all") 16613 .attr({ 16614 role: "listbox", 16615 "aria-activedescendant": "ui-active-menuitem" 16616 }) 16617 .click(function( event ) { 16618 if ( !$( event.target ).closest( ".ui-menu-item a" ).length ) { 16619 return; 16620 } 16621 // temporary 16622 event.preventDefault(); 16623 self.select( event ); 16624 }); 16625 this.refresh(); 16626 }, 16627 16628 refresh: function() { 16629 var self = this; 16630 16631 // don't refresh list items that are already adapted 16632 var items = this.element.children("li:not(.ui-menu-item):has(a)") 16633 .addClass("ui-menu-item") 16634 .attr("role", "menuitem"); 16635 16636 items.children("a") 16637 .addClass("ui-corner-all") 16638 .attr("tabindex", -1) 16639 // mouseenter doesn't work with event delegation 16640 .mouseenter(function( event ) { 16641 self.activate( event, $(this).parent() ); 16642 }) 16643 .mouseleave(function() { 16644 self.deactivate(); 16645 }); 16646 }, 16647 16648 activate: function( event, item ) { 16649 this.deactivate(); 16650 if (this.hasScroll()) { 16651 var offset = item.offset().top - this.element.offset().top, 16652 scroll = this.element.scrollTop(), 16653 elementHeight = this.element.height(); 16654 if (offset < 0) { 16655 this.element.scrollTop( scroll + offset); 16656 } else if (offset >= elementHeight) { 16657 this.element.scrollTop( scroll + offset - elementHeight + item.height()); 16658 } 16659 } 16660 this.active = item.eq(0) 16661 .children("a") 16662 .addClass("ui-state-hover") 16663 .attr("id", "ui-active-menuitem") 16664 .end(); 16665 this._trigger("focus", event, { item: item }); 16666 }, 16667 16668 deactivate: function() { 16669 if (!this.active) { return; } 16670 16671 this.active.children("a") 16672 .removeClass("ui-state-hover") 16673 .removeAttr("id"); 16674 this._trigger("blur"); 16675 this.active = null; 16676 }, 16677 16678 next: function(event) { 16679 this.move("next", ".ui-menu-item:first", event); 16680 }, 16681 16682 previous: function(event) { 16683 this.move("prev", ".ui-menu-item:last", event); 16684 }, 16685 16686 first: function() { 16687 return this.active && !this.active.prevAll(".ui-menu-item").length; 16688 }, 16689 16690 last: function() { 16691 return this.active && !this.active.nextAll(".ui-menu-item").length; 16692 }, 16693 16694 move: function(direction, edge, event) { 16695 if (!this.active) { 16696 this.activate(event, this.element.children(edge)); 16697 return; 16698 } 16699 var next = this.active[direction + "All"](".ui-menu-item").eq(0); 16700 if (next.length) { 16701 this.activate(event, next); 16702 } else { 16703 this.activate(event, this.element.children(edge)); 16704 } 16705 }, 16706 16707 // TODO merge with previousPage 16708 nextPage: function(event) { 16709 if (this.hasScroll()) { 16710 // TODO merge with no-scroll-else 16711 if (!this.active || this.last()) { 16712 this.activate(event, this.element.children(".ui-menu-item:first")); 16713 return; 16714 } 16715 var base = this.active.offset().top, 16716 height = this.element.height(), 16717 result = this.element.children(".ui-menu-item").filter(function() { 16718 var close = $(this).offset().top - base - height + $(this).height(); 16719 // TODO improve approximation 16720 return close < 10 && close > -10; 16721 }); 16722 16723 // TODO try to catch this earlier when scrollTop indicates the last page anyway 16724 if (!result.length) { 16725 result = this.element.children(".ui-menu-item:last"); 16726 } 16727 this.activate(event, result); 16728 } else { 16729 this.activate(event, this.element.children(".ui-menu-item") 16730 .filter(!this.active || this.last() ? ":first" : ":last")); 16731 } 16732 }, 16733 16734 // TODO merge with nextPage 16735 previousPage: function(event) { 16736 if (this.hasScroll()) { 16737 // TODO merge with no-scroll-else 16738 if (!this.active || this.first()) { 16739 this.activate(event, this.element.children(".ui-menu-item:last")); 16740 return; 16741 } 16742 16743 var base = this.active.offset().top, 16744 height = this.element.height(); 16745 result = this.element.children(".ui-menu-item").filter(function() { 16746 var close = $(this).offset().top - base + height - $(this).height(); 16747 // TODO improve approximation 16748 return close < 10 && close > -10; 16749 }); 16750 16751 // TODO try to catch this earlier when scrollTop indicates the last page anyway 16752 if (!result.length) { 16753 result = this.element.children(".ui-menu-item:first"); 16754 } 16755 this.activate(event, result); 16756 } else { 16757 this.activate(event, this.element.children(".ui-menu-item") 16758 .filter(!this.active || this.first() ? ":last" : ":first")); 16759 } 16760 }, 16761 16762 hasScroll: function() { 16763 return this.element.height() < this.element[ $.fn.prop ? "prop" : "attr" ]("scrollHeight"); 16764 }, 16765 16766 select: function( event ) { 16767 this._trigger("selected", event, { item: this.active }); 16768 } 16769}); 16770 16771}(jQuery)); 16772/* 16773 * jQuery UI Button 1.8.16 16774 * 16775 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 16776 * Dual licensed under the MIT or GPL Version 2 licenses. 16777 * http://jquery.org/license 16778 * 16779 * http://docs.jquery.com/UI/Button 16780 * 16781 * Depends: 16782 * jquery.ui.core.js 16783 * jquery.ui.widget.js 16784 */ 16785(function( $, undefined ) { 16786 16787var lastActive, startXPos, startYPos, clickDragged, 16788 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all", 16789 stateClasses = "ui-state-hover ui-state-active ", 16790 typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only", 16791 formResetHandler = function() { 16792 var buttons = $( this ).find( ":ui-button" ); 16793 setTimeout(function() { 16794 buttons.button( "refresh" ); 16795 }, 1 ); 16796 }, 16797 radioGroup = function( radio ) { 16798 var name = radio.name, 16799 form = radio.form, 16800 radios = $( [] ); 16801 if ( name ) { 16802 if ( form ) { 16803 radios = $( form ).find( "[name='" + name + "']" ); 16804 } else { 16805 radios = $( "[name='" + name + "']", radio.ownerDocument ) 16806 .filter(function() { 16807 return !this.form; 16808 }); 16809 } 16810 } 16811 return radios; 16812 }; 16813 16814$.widget( "ui.button", { 16815 options: { 16816 disabled: null, 16817 text: true, 16818 label: null, 16819 icons: { 16820 primary: null, 16821 secondary: null 16822 } 16823 }, 16824 _create: function() { 16825 this.element.closest( "form" ) 16826 .unbind( "reset.button" ) 16827 .bind( "reset.button", formResetHandler ); 16828 16829 if ( typeof this.options.disabled !== "boolean" ) { 16830 this.options.disabled = this.element.propAttr( "disabled" ); 16831 } 16832 16833 this._determineButtonType(); 16834 this.hasTitle = !!this.buttonElement.attr( "title" ); 16835 16836 var self = this, 16837 options = this.options, 16838 toggleButton = this.type === "checkbox" || this.type === "radio", 16839 hoverClass = "ui-state-hover" + ( !toggleButton ? " ui-state-active" : "" ), 16840 focusClass = "ui-state-focus"; 16841 16842 if ( options.label === null ) { 16843 options.label = this.buttonElement.html(); 16844 } 16845 16846 if ( this.element.is( ":disabled" ) ) { 16847 options.disabled = true; 16848 } 16849 16850 this.buttonElement 16851 .addClass( baseClasses ) 16852 .attr( "role", "button" ) 16853 .bind( "mouseenter.button", function() { 16854 if ( options.disabled ) { 16855 return; 16856 } 16857 $( this ).addClass( "ui-state-hover" ); 16858 if ( this === lastActive ) { 16859 $( this ).addClass( "ui-state-active" ); 16860 } 16861 }) 16862 .bind( "mouseleave.button", function() { 16863 if ( options.disabled ) { 16864 return; 16865 } 16866 $( this ).removeClass( hoverClass ); 16867 }) 16868 .bind( "click.button", function( event ) { 16869 if ( options.disabled ) { 16870 event.preventDefault(); 16871 event.stopImmediatePropagation(); 16872 } 16873 }); 16874 16875 this.element 16876 .bind( "focus.button", function() { 16877 // no need to check disabled, focus won't be triggered anyway 16878 self.buttonElement.addClass( focusClass ); 16879 }) 16880 .bind( "blur.button", function() { 16881 self.buttonElement.removeClass( focusClass ); 16882 }); 16883 16884 if ( toggleButton ) { 16885 this.element.bind( "change.button", function() { 16886 if ( clickDragged ) { 16887 return; 16888 } 16889 self.refresh(); 16890 }); 16891 // if mouse moves between mousedown and mouseup (drag) set clickDragged flag 16892 // prevents issue where button state changes but checkbox/radio checked state 16893 // does not in Firefox (see ticket #6970) 16894 this.buttonElement 16895 .bind( "mousedown.button", function( event ) { 16896 if ( options.disabled ) { 16897 return; 16898 } 16899 clickDragged = false; 16900 startXPos = event.pageX; 16901 startYPos = event.pageY; 16902 }) 16903 .bind( "mouseup.button", function( event ) { 16904 if ( options.disabled ) { 16905 return; 16906 } 16907 if ( startXPos !== event.pageX || startYPos !== event.pageY ) { 16908 clickDragged = true; 16909 } 16910 }); 16911 } 16912 16913 if ( this.type === "checkbox" ) { 16914 this.buttonElement.bind( "click.button", function() { 16915 if ( options.disabled || clickDragged ) { 16916 return false; 16917 } 16918 $( this ).toggleClass( "ui-state-active" ); 16919 self.buttonElement.attr( "aria-pressed", self.element[0].checked ); 16920 }); 16921 } else if ( this.type === "radio" ) { 16922 this.buttonElement.bind( "click.button", function() { 16923 if ( options.disabled || clickDragged ) { 16924 return false; 16925 } 16926 $( this ).addClass( "ui-state-active" ); 16927 self.buttonElement.attr( "aria-pressed", "true" ); 16928 16929 var radio = self.element[ 0 ]; 16930 radioGroup( radio ) 16931 .not( radio ) 16932 .map(function() { 16933 return $( this ).button( "widget" )[ 0 ]; 16934 }) 16935 .removeClass( "ui-state-active" ) 16936 .attr( "aria-pressed", "false" ); 16937 }); 16938 } else { 16939 this.buttonElement 16940 .bind( "mousedown.button", function() { 16941 if ( options.disabled ) { 16942 return false; 16943 } 16944 $( this ).addClass( "ui-state-active" ); 16945 lastActive = this; 16946 $( document ).one( "mouseup", function() { 16947 lastActive = null; 16948 }); 16949 }) 16950 .bind( "mouseup.button", function() { 16951 if ( options.disabled ) { 16952 return false; 16953 } 16954 $( this ).removeClass( "ui-state-active" ); 16955 }) 16956 .bind( "keydown.button", function(event) { 16957 if ( options.disabled ) { 16958 return false; 16959 } 16960 if ( event.keyCode == $.ui.keyCode.SPACE || event.keyCode == $.ui.keyCode.ENTER ) { 16961 $( this ).addClass( "ui-state-active" ); 16962 } 16963 }) 16964 .bind( "keyup.button", function() { 16965 $( this ).removeClass( "ui-state-active" ); 16966 }); 16967 16968 if ( this.buttonElement.is("a") ) { 16969 this.buttonElement.keyup(function(event) { 16970 if ( event.keyCode === $.ui.keyCode.SPACE ) { 16971 // TODO pass through original event correctly (just as 2nd argument doesn't work) 16972 $( this ).click(); 16973 } 16974 }); 16975 } 16976 } 16977 16978 // TODO: pull out $.Widget's handling for the disabled option into 16979 // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can 16980 // be overridden by individual plugins 16981 this._setOption( "disabled", options.disabled ); 16982 this._resetButton(); 16983 }, 16984 16985 _determineButtonType: function() { 16986 16987 if ( this.element.is(":checkbox") ) { 16988 this.type = "checkbox"; 16989 } else if ( this.element.is(":radio") ) { 16990 this.type = "radio"; 16991 } else if ( this.element.is("input") ) { 16992 this.type = "input"; 16993 } else { 16994 this.type = "button"; 16995 } 16996 16997 if ( this.type === "checkbox" || this.type === "radio" ) { 16998 // we don't search against the document in case the element 16999 // is disconnected from the DOM 17000 var ancestor = this.element.parents().filter(":last"), 17001 labelSelector = "label[for='" + this.element.attr("id") + "']"; 17002 this.buttonElement = ancestor.find( labelSelector ); 17003 if ( !this.buttonElement.length ) { 17004 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings(); 17005 this.buttonElement = ancestor.filter( labelSelector ); 17006 if ( !this.buttonElement.length ) { 17007 this.buttonElement = ancestor.find( labelSelector ); 17008 } 17009 } 17010 this.element.addClass( "ui-helper-hidden-accessible" ); 17011 17012 var checked = this.element.is( ":checked" ); 17013 if ( checked ) { 17014 this.buttonElement.addClass( "ui-state-active" ); 17015 } 17016 this.buttonElement.attr( "aria-pressed", checked ); 17017 } else { 17018 this.buttonElement = this.element; 17019 } 17020 }, 17021 17022 widget: function() { 17023 return this.buttonElement; 17024 }, 17025 17026 destroy: function() { 17027 this.element 17028 .removeClass( "ui-helper-hidden-accessible" ); 17029 this.buttonElement 17030 .removeClass( baseClasses + " " + stateClasses + " " + typeClasses ) 17031 .removeAttr( "role" ) 17032 .removeAttr( "aria-pressed" ) 17033 .html( this.buttonElement.find(".ui-button-text").html() ); 17034 17035 if ( !this.hasTitle ) { 17036 this.buttonElement.removeAttr( "title" ); 17037 } 17038 17039 $.Widget.prototype.destroy.call( this ); 17040 }, 17041 17042 _setOption: function( key, value ) { 17043 $.Widget.prototype._setOption.apply( this, arguments ); 17044 if ( key === "disabled" ) { 17045 if ( value ) { 17046 this.element.propAttr( "disabled", true ); 17047 } else { 17048 this.element.propAttr( "disabled", false ); 17049 } 17050 return; 17051 } 17052 this._resetButton(); 17053 }, 17054 17055 refresh: function() { 17056 var isDisabled = this.element.is( ":disabled" ); 17057 if ( isDisabled !== this.options.disabled ) { 17058 this._setOption( "disabled", isDisabled ); 17059 } 17060 if ( this.type === "radio" ) { 17061 radioGroup( this.element[0] ).each(function() { 17062 if ( $( this ).is( ":checked" ) ) { 17063 $( this ).button( "widget" ) 17064 .addClass( "ui-state-active" ) 17065 .attr( "aria-pressed", "true" ); 17066 } else { 17067 $( this ).button( "widget" ) 17068 .removeClass( "ui-state-active" ) 17069 .attr( "aria-pressed", "false" ); 17070 } 17071 }); 17072 } else if ( this.type === "checkbox" ) { 17073 if ( this.element.is( ":checked" ) ) { 17074 this.buttonElement 17075 .addClass( "ui-state-active" ) 17076 .attr( "aria-pressed", "true" ); 17077 } else { 17078 this.buttonElement 17079 .removeClass( "ui-state-active" ) 17080 .attr( "aria-pressed", "false" ); 17081 } 17082 } 17083 }, 17084 17085 _resetButton: function() { 17086 if ( this.type === "input" ) { 17087 if ( this.options.label ) { 17088 this.element.val( this.options.label ); 17089 } 17090 return; 17091 } 17092 var buttonElement = this.buttonElement.removeClass( typeClasses ), 17093 buttonText = $( "<span></span>" ) 17094 .addClass( "ui-button-text" ) 17095 .html( this.options.label ) 17096 .appendTo( buttonElement.empty() ) 17097 .text(), 17098 icons = this.options.icons, 17099 multipleIcons = icons.primary && icons.secondary, 17100 buttonClasses = []; 17101 17102 if ( icons.primary || icons.secondary ) { 17103 if ( this.options.text ) { 17104 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) ); 17105 } 17106 17107 if ( icons.primary ) { 17108 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" ); 17109 } 17110 17111 if ( icons.secondary ) { 17112 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" ); 17113 } 17114 17115 if ( !this.options.text ) { 17116 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" ); 17117 17118 if ( !this.hasTitle ) { 17119 buttonElement.attr( "title", buttonText ); 17120 } 17121 } 17122 } else { 17123 buttonClasses.push( "ui-button-text-only" ); 17124 } 17125 buttonElement.addClass( buttonClasses.join( " " ) ); 17126 } 17127}); 17128 17129$.widget( "ui.buttonset", { 17130 options: { 17131 items: ":button, :submit, :reset, :checkbox, :radio, a, :data(button)" 17132 }, 17133 17134 _create: function() { 17135 this.element.addClass( "ui-buttonset" ); 17136 }, 17137 17138 _init: function() { 17139 this.refresh(); 17140 }, 17141 17142 _setOption: function( key, value ) { 17143 if ( key === "disabled" ) { 17144 this.buttons.button( "option", key, value ); 17145 } 17146 17147 $.Widget.prototype._setOption.apply( this, arguments ); 17148 }, 17149 17150 refresh: function() { 17151 var ltr = this.element.css( "direction" ) === "ltr"; 17152 17153 this.buttons = this.element.find( this.options.items ) 17154 .filter( ":ui-button" ) 17155 .button( "refresh" ) 17156 .end() 17157 .not( ":ui-button" ) 17158 .button() 17159 .end() 17160 .map(function() { 17161 return $( this ).button( "widget" )[ 0 ]; 17162 }) 17163 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" ) 17164 .filter( ":first" ) 17165 .addClass( ltr ? "ui-corner-left" : "ui-corner-right" ) 17166 .end() 17167 .filter( ":last" ) 17168 .addClass( ltr ? "ui-corner-right" : "ui-corner-left" ) 17169 .end() 17170 .end(); 17171 }, 17172 17173 destroy: function() { 17174 this.element.removeClass( "ui-buttonset" ); 17175 this.buttons 17176 .map(function() { 17177 return $( this ).button( "widget" )[ 0 ]; 17178 }) 17179 .removeClass( "ui-corner-left ui-corner-right" ) 17180 .end() 17181 .button( "destroy" ); 17182 17183 $.Widget.prototype.destroy.call( this ); 17184 } 17185}); 17186 17187}( jQuery ) ); 17188/* 17189 * jQuery UI Datepicker 1.8.16 17190 * 17191 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 17192 * Dual licensed under the MIT or GPL Version 2 licenses. 17193 * http://jquery.org/license 17194 * 17195 * http://docs.jquery.com/UI/Datepicker 17196 * 17197 * Depends: 17198 * jquery.ui.core.js 17199 */ 17200(function( $, undefined ) { 17201 17202$.extend($.ui, { datepicker: { version: "1.8.16" } }); 17203 17204var PROP_NAME = 'datepicker'; 17205var dpuuid = new Date().getTime(); 17206var instActive; 17207 17208/* Date picker manager. 17209 Use the singleton instance of this class, $.datepicker, to interact with the date picker. 17210 Settings for (groups of) date pickers are maintained in an instance object, 17211 allowing multiple different settings on the same page. */ 17212 17213function Datepicker() { 17214 this.debug = false; // Change this to true to start debugging 17215 this._curInst = null; // The current instance in use 17216 this._keyEvent = false; // If the last event was a key event 17217 this._disabledInputs = []; // List of date picker inputs that have been disabled 17218 this._datepickerShowing = false; // True if the popup picker is showing , false if not 17219 this._inDialog = false; // True if showing within a "dialog", false if not 17220 this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division 17221 this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class 17222 this._appendClass = 'ui-datepicker-append'; // The name of the append marker class 17223 this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class 17224 this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class 17225 this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class 17226 this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class 17227 this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class 17228 this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class 17229 this.regional = []; // Available regional settings, indexed by language code 17230 this.regional[''] = { // Default regional settings 17231 closeText: 'Done', // Display text for close link 17232 prevText: 'Prev', // Display text for previous month link 17233 nextText: 'Next', // Display text for next month link 17234 currentText: 'Today', // Display text for current month link 17235 monthNames: ['January','February','March','April','May','June', 17236 'July','August','September','October','November','December'], // Names of months for drop-down and formatting 17237 monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting 17238 dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting 17239 dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting 17240 dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday 17241 weekHeader: 'Wk', // Column header for week of the year 17242 dateFormat: 'mm/dd/yy', // See format options on parseDate 17243 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... 17244 isRTL: false, // True if right-to-left language, false if left-to-right 17245 showMonthAfterYear: false, // True if the year select precedes month, false for month then year 17246 yearSuffix: '' // Additional text to append to the year in the month headers 17247 }; 17248 this._defaults = { // Global defaults for all the date picker instances 17249 showOn: 'focus', // 'focus' for popup on focus, 17250 // 'button' for trigger button, or 'both' for either 17251 showAnim: 'fadeIn', // Name of jQuery animation for popup 17252 showOptions: {}, // Options for enhanced animations 17253 defaultDate: null, // Used when field is blank: actual date, 17254 // +/-number for offset from today, null for today 17255 appendText: '', // Display text following the input box, e.g. showing the format 17256 buttonText: '...', // Text for trigger button 17257 buttonImage: '', // URL for trigger button image 17258 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button 17259 hideIfNoPrevNext: false, // True to hide next/previous month links 17260 // if not applicable, false to just disable them 17261 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links 17262 gotoCurrent: false, // True if today link goes back to current selection instead 17263 changeMonth: false, // True if month can be selected directly, false if only prev/next 17264 changeYear: false, // True if year can be selected directly, false if only prev/next 17265 yearRange: 'c-10:c+10', // Range of years to display in drop-down, 17266 // either relative to today's year (-nn:+nn), relative to currently displayed year 17267 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) 17268 showOtherMonths: false, // True to show dates in other months, false to leave blank 17269 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable 17270 showWeek: false, // True to show week of the year, false to not show it 17271 calculateWeek: this.iso8601Week, // How to calculate the week of the year, 17272 // takes a Date and returns the number of the week for it 17273 shortYearCutoff: '+10', // Short year values < this are in the current century, 17274 // > this are in the previous century, 17275 // string value starting with '+' for current year + value 17276 minDate: null, // The earliest selectable date, or null for no limit 17277 maxDate: null, // The latest selectable date, or null for no limit 17278 duration: 'fast', // Duration of display/closure 17279 beforeShowDay: null, // Function that takes a date and returns an array with 17280 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '', 17281 // [2] = cell title (optional), e.g. $.datepicker.noWeekends 17282 beforeShow: null, // Function that takes an input field and 17283 // returns a set of custom settings for the date picker 17284 onSelect: null, // Define a callback function when a date is selected 17285 onChangeMonthYear: null, // Define a callback function when the month or year is changed 17286 onClose: null, // Define a callback function when the datepicker is closed 17287 numberOfMonths: 1, // Number of months to show at a time 17288 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) 17289 stepMonths: 1, // Number of months to step back/forward 17290 stepBigMonths: 12, // Number of months to step back/forward for the big links 17291 altField: '', // Selector for an alternate field to store selected dates into 17292 altFormat: '', // The date format to use for the alternate field 17293 constrainInput: true, // The input is constrained by the current date format 17294 showButtonPanel: false, // True to show button panel, false to not show it 17295 autoSize: false, // True to size the input for the date format, false to leave as is 17296 disabled: false // The initial disabled state 17297 }; 17298 $.extend(this._defaults, this.regional['']); 17299 this.dpDiv = bindHover($('<div id="' + this._mainDivId + '" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')); 17300} 17301 17302$.extend(Datepicker.prototype, { 17303 /* Class name added to elements to indicate already configured with a date picker. */ 17304 markerClassName: 'hasDatepicker', 17305 17306 //Keep track of the maximum number of rows displayed (see #7043) 17307 maxRows: 4, 17308 17309 /* Debug logging (if enabled). */ 17310 log: function () { 17311 if (this.debug) 17312 console.log.apply('', arguments); 17313 }, 17314 17315 // TODO rename to "widget" when switching to widget factory 17316 _widgetDatepicker: function() { 17317 return this.dpDiv; 17318 }, 17319 17320 /* Override the default settings for all instances of the date picker. 17321 @param settings object - the new settings to use as defaults (anonymous object) 17322 @return the manager object */ 17323 setDefaults: function(settings) { 17324 extendRemove(this._defaults, settings || {}); 17325 return this; 17326 }, 17327 17328 /* Attach the date picker to a jQuery selection. 17329 @param target element - the target input field or division or span 17330 @param settings object - the new settings to use for this date picker instance (anonymous) */ 17331 _attachDatepicker: function(target, settings) { 17332 // check for settings on the control itself - in namespace 'date:' 17333 var inlineSettings = null; 17334 for (var attrName in this._defaults) { 17335 var attrValue = target.getAttribute('date:' + attrName); 17336 if (attrValue) { 17337 inlineSettings = inlineSettings || {}; 17338 try { 17339 inlineSettings[attrName] = eval(attrValue); 17340 } catch (err) { 17341 inlineSettings[attrName] = attrValue; 17342 } 17343 } 17344 } 17345 var nodeName = target.nodeName.toLowerCase(); 17346 var inline = (nodeName == 'div' || nodeName == 'span'); 17347 if (!target.id) { 17348 this.uuid += 1; 17349 target.id = 'dp' + this.uuid; 17350 } 17351 var inst = this._newInst($(target), inline); 17352 inst.settings = $.extend({}, settings || {}, inlineSettings || {}); 17353 if (nodeName == 'input') { 17354 this._connectDatepicker(target, inst); 17355 } else if (inline) { 17356 this._inlineDatepicker(target, inst); 17357 } 17358 }, 17359 17360 /* Create a new instance object. */ 17361 _newInst: function(target, inline) { 17362 var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars 17363 return {id: id, input: target, // associated target 17364 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection 17365 drawMonth: 0, drawYear: 0, // month being drawn 17366 inline: inline, // is datepicker inline or not 17367 dpDiv: (!inline ? this.dpDiv : // presentation div 17368 bindHover($('<div class="' + this._inlineClass + ' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')))}; 17369 }, 17370 17371 /* Attach the date picker to an input field. */ 17372 _connectDatepicker: function(target, inst) { 17373 var input = $(target); 17374 inst.append = $([]); 17375 inst.trigger = $([]); 17376 if (input.hasClass(this.markerClassName)) 17377 return; 17378 this._attachments(input, inst); 17379 input.addClass(this.markerClassName).keydown(this._doKeyDown). 17380 keypress(this._doKeyPress).keyup(this._doKeyUp). 17381 bind("setData.datepicker", function(event, key, value) { 17382 inst.settings[key] = value; 17383 }).bind("getData.datepicker", function(event, key) { 17384 return this._get(inst, key); 17385 }); 17386 this._autoSize(inst); 17387 $.data(target, PROP_NAME, inst); 17388 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) 17389 if( inst.settings.disabled ) { 17390 this._disableDatepicker( target ); 17391 } 17392 }, 17393 17394 /* Make attachments based on settings. */ 17395 _attachments: function(input, inst) { 17396 var appendText = this._get(inst, 'appendText'); 17397 var isRTL = this._get(inst, 'isRTL'); 17398 if (inst.append) 17399 inst.append.remove(); 17400 if (appendText) { 17401 inst.append = $('<span class="' + this._appendClass + '">' + appendText + '</span>'); 17402 input[isRTL ? 'before' : 'after'](inst.append); 17403 } 17404 input.unbind('focus', this._showDatepicker); 17405 if (inst.trigger) 17406 inst.trigger.remove(); 17407 var showOn = this._get(inst, 'showOn'); 17408 if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field 17409 input.focus(this._showDatepicker); 17410 if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked 17411 var buttonText = this._get(inst, 'buttonText'); 17412 var buttonImage = this._get(inst, 'buttonImage'); 17413 inst.trigger = $(this._get(inst, 'buttonImageOnly') ? 17414 $('<img/>').addClass(this._triggerClass). 17415 attr({ src: buttonImage, alt: buttonText, title: buttonText }) : 17416 $('<button type="button"></button>').addClass(this._triggerClass). 17417 html(buttonImage == '' ? buttonText : $('<img/>').attr( 17418 { src:buttonImage, alt:buttonText, title:buttonText }))); 17419 input[isRTL ? 'before' : 'after'](inst.trigger); 17420 inst.trigger.click(function() { 17421 if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0]) 17422 $.datepicker._hideDatepicker(); 17423 else 17424 $.datepicker._showDatepicker(input[0]); 17425 return false; 17426 }); 17427 } 17428 }, 17429 17430 /* Apply the maximum length for the date format. */ 17431 _autoSize: function(inst) { 17432 if (this._get(inst, 'autoSize') && !inst.inline) { 17433 var date = new Date(2009, 12 - 1, 20); // Ensure double digits 17434 var dateFormat = this._get(inst, 'dateFormat'); 17435 if (dateFormat.match(/[DM]/)) { 17436 var findMax = function(names) { 17437 var max = 0; 17438 var maxI = 0; 17439 for (var i = 0; i < names.length; i++) { 17440 if (names[i].length > max) { 17441 max = names[i].length; 17442 maxI = i; 17443 } 17444 } 17445 return maxI; 17446 }; 17447 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? 17448 'monthNames' : 'monthNamesShort')))); 17449 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? 17450 'dayNames' : 'dayNamesShort'))) + 20 - date.getDay()); 17451 } 17452 inst.input.attr('size', this._formatDate(inst, date).length); 17453 } 17454 }, 17455 17456 /* Attach an inline date picker to a div. */ 17457 _inlineDatepicker: function(target, inst) { 17458 var divSpan = $(target); 17459 if (divSpan.hasClass(this.markerClassName)) 17460 return; 17461 divSpan.addClass(this.markerClassName).append(inst.dpDiv). 17462 bind("setData.datepicker", function(event, key, value){ 17463 inst.settings[key] = value; 17464 }).bind("getData.datepicker", function(event, key){ 17465 return this._get(inst, key); 17466 }); 17467 $.data(target, PROP_NAME, inst); 17468 this._setDate(inst, this._getDefaultDate(inst), true); 17469 this._updateDatepicker(inst); 17470 this._updateAlternate(inst); 17471 //If disabled option is true, disable the datepicker before showing it (see ticket #5665) 17472 if( inst.settings.disabled ) { 17473 this._disableDatepicker( target ); 17474 } 17475 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements 17476 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height 17477 inst.dpDiv.css( "display", "block" ); 17478 }, 17479 17480 /* Pop-up the date picker in a "dialog" box. 17481 @param input element - ignored 17482 @param date string or Date - the initial date to display 17483 @param onSelect function - the function to call when a date is selected 17484 @param settings object - update the dialog date picker instance's settings (anonymous object) 17485 @param pos int[2] - coordinates for the dialog's position within the screen or 17486 event - with x/y coordinates or 17487 leave empty for default (screen centre) 17488 @return the manager object */ 17489 _dialogDatepicker: function(input, date, onSelect, settings, pos) { 17490 var inst = this._dialogInst; // internal instance 17491 if (!inst) { 17492 this.uuid += 1; 17493 var id = 'dp' + this.uuid; 17494 this._dialogInput = $('<input type="text" id="' + id + 17495 '" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>'); 17496 this._dialogInput.keydown(this._doKeyDown); 17497 $('body').append(this._dialogInput); 17498 inst = this._dialogInst = this._newInst(this._dialogInput, false); 17499 inst.settings = {}; 17500 $.data(this._dialogInput[0], PROP_NAME, inst); 17501 } 17502 extendRemove(inst.settings, settings || {}); 17503 date = (date && date.constructor == Date ? this._formatDate(inst, date) : date); 17504 this._dialogInput.val(date); 17505 17506 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); 17507 if (!this._pos) { 17508 var browserWidth = document.documentElement.clientWidth; 17509 var browserHeight = document.documentElement.clientHeight; 17510 var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; 17511 var scrollY = document.documentElement.scrollTop || document.body.scrollTop; 17512 this._pos = // should use actual width/height below 17513 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; 17514 } 17515 17516 // move input on screen for focus, but hidden behind dialog 17517 this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px'); 17518 inst.settings.onSelect = onSelect; 17519 this._inDialog = true; 17520 this.dpDiv.addClass(this._dialogClass); 17521 this._showDatepicker(this._dialogInput[0]); 17522 if ($.blockUI) 17523 $.blockUI(this.dpDiv); 17524 $.data(this._dialogInput[0], PROP_NAME, inst); 17525 return this; 17526 }, 17527 17528 /* Detach a datepicker from its control. 17529 @param target element - the target input field or division or span */ 17530 _destroyDatepicker: function(target) { 17531 var $target = $(target); 17532 var inst = $.data(target, PROP_NAME); 17533 if (!$target.hasClass(this.markerClassName)) { 17534 return; 17535 } 17536 var nodeName = target.nodeName.toLowerCase(); 17537 $.removeData(target, PROP_NAME); 17538 if (nodeName == 'input') { 17539 inst.append.remove(); 17540 inst.trigger.remove(); 17541 $target.removeClass(this.markerClassName). 17542 unbind('focus', this._showDatepicker). 17543 unbind('keydown', this._doKeyDown). 17544 unbind('keypress', this._doKeyPress). 17545 unbind('keyup', this._doKeyUp); 17546 } else if (nodeName == 'div' || nodeName == 'span') 17547 $target.removeClass(this.markerClassName).empty(); 17548 }, 17549 17550 /* Enable the date picker to a jQuery selection. 17551 @param target element - the target input field or division or span */ 17552 _enableDatepicker: function(target) { 17553 var $target = $(target); 17554 var inst = $.data(target, PROP_NAME); 17555 if (!$target.hasClass(this.markerClassName)) { 17556 return; 17557 } 17558 var nodeName = target.nodeName.toLowerCase(); 17559 if (nodeName == 'input') { 17560 target.disabled = false; 17561 inst.trigger.filter('button'). 17562 each(function() { this.disabled = false; }).end(). 17563 filter('img').css({opacity: '1.0', cursor: ''}); 17564 } 17565 else if (nodeName == 'div' || nodeName == 'span') { 17566 var inline = $target.children('.' + this._inlineClass); 17567 inline.children().removeClass('ui-state-disabled'); 17568 inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). 17569 removeAttr("disabled"); 17570 } 17571 this._disabledInputs = $.map(this._disabledInputs, 17572 function(value) { return (value == target ? null : value); }); // delete entry 17573 }, 17574 17575 /* Disable the date picker to a jQuery selection. 17576 @param target element - the target input field or division or span */ 17577 _disableDatepicker: function(target) { 17578 var $target = $(target); 17579 var inst = $.data(target, PROP_NAME); 17580 if (!$target.hasClass(this.markerClassName)) { 17581 return; 17582 } 17583 var nodeName = target.nodeName.toLowerCase(); 17584 if (nodeName == 'input') { 17585 target.disabled = true; 17586 inst.trigger.filter('button'). 17587 each(function() { this.disabled = true; }).end(). 17588 filter('img').css({opacity: '0.5', cursor: 'default'}); 17589 } 17590 else if (nodeName == 'div' || nodeName == 'span') { 17591 var inline = $target.children('.' + this._inlineClass); 17592 inline.children().addClass('ui-state-disabled'); 17593 inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). 17594 attr("disabled", "disabled"); 17595 } 17596 this._disabledInputs = $.map(this._disabledInputs, 17597 function(value) { return (value == target ? null : value); }); // delete entry 17598 this._disabledInputs[this._disabledInputs.length] = target; 17599 }, 17600 17601 /* Is the first field in a jQuery collection disabled as a datepicker? 17602 @param target element - the target input field or division or span 17603 @return boolean - true if disabled, false if enabled */ 17604 _isDisabledDatepicker: function(target) { 17605 if (!target) { 17606 return false; 17607 } 17608 for (var i = 0; i < this._disabledInputs.length; i++) { 17609 if (this._disabledInputs[i] == target) 17610 return true; 17611 } 17612 return false; 17613 }, 17614 17615 /* Retrieve the instance data for the target control. 17616 @param target element - the target input field or division or span 17617 @return object - the associated instance data 17618 @throws error if a jQuery problem getting data */ 17619 _getInst: function(target) { 17620 try { 17621 return $.data(target, PROP_NAME); 17622 } 17623 catch (err) { 17624 throw 'Missing instance data for this datepicker'; 17625 } 17626 }, 17627 17628 /* Update or retrieve the settings for a date picker attached to an input field or division. 17629 @param target element - the target input field or division or span 17630 @param name object - the new settings to update or 17631 string - the name of the setting to change or retrieve, 17632 when retrieving also 'all' for all instance settings or 17633 'defaults' for all global defaults 17634 @param value any - the new value for the setting 17635 (omit if above is an object or to retrieve a value) */ 17636 _optionDatepicker: function(target, name, value) { 17637 var inst = this._getInst(target); 17638 if (arguments.length == 2 && typeof name == 'string') { 17639 return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) : 17640 (inst ? (name == 'all' ? $.extend({}, inst.settings) : 17641 this._get(inst, name)) : null)); 17642 } 17643 var settings = name || {}; 17644 if (typeof name == 'string') { 17645 settings = {}; 17646 settings[name] = value; 17647 } 17648 if (inst) { 17649 if (this._curInst == inst) { 17650 this._hideDatepicker(); 17651 } 17652 var date = this._getDateDatepicker(target, true); 17653 var minDate = this._getMinMaxDate(inst, 'min'); 17654 var maxDate = this._getMinMaxDate(inst, 'max'); 17655 extendRemove(inst.settings, settings); 17656 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided 17657 if (minDate !== null && settings['dateFormat'] !== undefined && settings['minDate'] === undefined) 17658 inst.settings.minDate = this._formatDate(inst, minDate); 17659 if (maxDate !== null && settings['dateFormat'] !== undefined && settings['maxDate'] === undefined) 17660 inst.settings.maxDate = this._formatDate(inst, maxDate); 17661 this._attachments($(target), inst); 17662 this._autoSize(inst); 17663 this._setDate(inst, date); 17664 this._updateAlternate(inst); 17665 this._updateDatepicker(inst); 17666 } 17667 }, 17668 17669 // change method deprecated 17670 _changeDatepicker: function(target, name, value) { 17671 this._optionDatepicker(target, name, value); 17672 }, 17673 17674 /* Redraw the date picker attached to an input field or division. 17675 @param target element - the target input field or division or span */ 17676 _refreshDatepicker: function(target) { 17677 var inst = this._getInst(target); 17678 if (inst) { 17679 this._updateDatepicker(inst); 17680 } 17681 }, 17682 17683 /* Set the dates for a jQuery selection. 17684 @param target element - the target input field or division or span 17685 @param date Date - the new date */ 17686 _setDateDatepicker: function(target, date) { 17687 var inst = this._getInst(target); 17688 if (inst) { 17689 this._setDate(inst, date); 17690 this._updateDatepicker(inst); 17691 this._updateAlternate(inst); 17692 } 17693 }, 17694 17695 /* Get the date(s) for the first entry in a jQuery selection. 17696 @param target element - the target input field or division or span 17697 @param noDefault boolean - true if no default date is to be used 17698 @return Date - the current date */ 17699 _getDateDatepicker: function(target, noDefault) { 17700 var inst = this._getInst(target); 17701 if (inst && !inst.inline) 17702 this._setDateFromField(inst, noDefault); 17703 return (inst ? this._getDate(inst) : null); 17704 }, 17705 17706 /* Handle keystrokes. */ 17707 _doKeyDown: function(event) { 17708 var inst = $.datepicker._getInst(event.target); 17709 var handled = true; 17710 var isRTL = inst.dpDiv.is('.ui-datepicker-rtl'); 17711 inst._keyEvent = true; 17712 if ($.datepicker._datepickerShowing) 17713 switch (event.keyCode) { 17714 case 9: $.datepicker._hideDatepicker(); 17715 handled = false; 17716 break; // hide on tab out 17717 case 13: var sel = $('td.' + $.datepicker._dayOverClass + ':not(.' + 17718 $.datepicker._currentClass + ')', inst.dpDiv); 17719 if (sel[0]) 17720 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); 17721 var onSelect = $.datepicker._get(inst, 'onSelect'); 17722 if (onSelect) { 17723 var dateStr = $.datepicker._formatDate(inst); 17724 17725 // trigger custom callback 17726 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); 17727 } 17728 else 17729 $.datepicker._hideDatepicker(); 17730 return false; // don't submit the form 17731 break; // select the value on enter 17732 case 27: $.datepicker._hideDatepicker(); 17733 break; // hide on escape 17734 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? 17735 -$.datepicker._get(inst, 'stepBigMonths') : 17736 -$.datepicker._get(inst, 'stepMonths')), 'M'); 17737 break; // previous month/year on page up/+ ctrl 17738 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? 17739 +$.datepicker._get(inst, 'stepBigMonths') : 17740 +$.datepicker._get(inst, 'stepMonths')), 'M'); 17741 break; // next month/year on page down/+ ctrl 17742 case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target); 17743 handled = event.ctrlKey || event.metaKey; 17744 break; // clear on ctrl or command +end 17745 case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target); 17746 handled = event.ctrlKey || event.metaKey; 17747 break; // current on ctrl or command +home 17748 case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D'); 17749 handled = event.ctrlKey || event.metaKey; 17750 // -1 day on ctrl or command +left 17751 if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? 17752 -$.datepicker._get(inst, 'stepBigMonths') : 17753 -$.datepicker._get(inst, 'stepMonths')), 'M'); 17754 // next month/year on alt +left on Mac 17755 break; 17756 case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D'); 17757 handled = event.ctrlKey || event.metaKey; 17758 break; // -1 week on ctrl or command +up 17759 case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D'); 17760 handled = event.ctrlKey || event.metaKey; 17761 // +1 day on ctrl or command +right 17762 if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? 17763 +$.datepicker._get(inst, 'stepBigMonths') : 17764 +$.datepicker._get(inst, 'stepMonths')), 'M'); 17765 // next month/year on alt +right 17766 break; 17767 case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D'); 17768 handled = event.ctrlKey || event.metaKey; 17769 break; // +1 week on ctrl or command +down 17770 default: handled = false; 17771 } 17772 else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home 17773 $.datepicker._showDatepicker(this); 17774 else { 17775 handled = false; 17776 } 17777 if (handled) { 17778 event.preventDefault(); 17779 event.stopPropagation(); 17780 } 17781 }, 17782 17783 /* Filter entered characters - based on date format. */ 17784 _doKeyPress: function(event) { 17785 var inst = $.datepicker._getInst(event.target); 17786 if ($.datepicker._get(inst, 'constrainInput')) { 17787 var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')); 17788 var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode); 17789 return event.ctrlKey || event.metaKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1); 17790 } 17791 }, 17792 17793 /* Synchronise manual entry and field/alternate field. */ 17794 _doKeyUp: function(event) { 17795 var inst = $.datepicker._getInst(event.target); 17796 if (inst.input.val() != inst.lastVal) { 17797 try { 17798 var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), 17799 (inst.input ? inst.input.val() : null), 17800 $.datepicker._getFormatConfig(inst)); 17801 if (date) { // only if valid 17802 $.datepicker._setDateFromField(inst); 17803 $.datepicker._updateAlternate(inst); 17804 $.datepicker._updateDatepicker(inst); 17805 } 17806 } 17807 catch (event) { 17808 $.datepicker.log(event); 17809 } 17810 } 17811 return true; 17812 }, 17813 17814 /* Pop-up the date picker for a given input field. 17815 If false returned from beforeShow event handler do not show. 17816 @param input element - the input field attached to the date picker or 17817 event - if triggered by focus */ 17818 _showDatepicker: function(input) { 17819 input = input.target || input; 17820 if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger 17821 input = $('input', input.parentNode)[0]; 17822 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here 17823 return; 17824 var inst = $.datepicker._getInst(input); 17825 if ($.datepicker._curInst && $.datepicker._curInst != inst) { 17826 if ( $.datepicker._datepickerShowing ) { 17827 $.datepicker._triggerOnClose($.datepicker._curInst); 17828 } 17829 $.datepicker._curInst.dpDiv.stop(true, true); 17830 } 17831 var beforeShow = $.datepicker._get(inst, 'beforeShow'); 17832 var beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {}; 17833 if(beforeShowSettings === false){ 17834 //false 17835 return; 17836 } 17837 extendRemove(inst.settings, beforeShowSettings); 17838 inst.lastVal = null; 17839 $.datepicker._lastInput = input; 17840 $.datepicker._setDateFromField(inst); 17841 if ($.datepicker._inDialog) // hide cursor 17842 input.value = ''; 17843 if (!$.datepicker._pos) { // position below input 17844 $.datepicker._pos = $.datepicker._findPos(input); 17845 $.datepicker._pos[1] += input.offsetHeight; // add the height 17846 } 17847 var isFixed = false; 17848 $(input).parents().each(function() { 17849 isFixed |= $(this).css('position') == 'fixed'; 17850 return !isFixed; 17851 }); 17852 if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled 17853 $.datepicker._pos[0] -= document.documentElement.scrollLeft; 17854 $.datepicker._pos[1] -= document.documentElement.scrollTop; 17855 } 17856 var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; 17857 $.datepicker._pos = null; 17858 //to avoid flashes on Firefox 17859 inst.dpDiv.empty(); 17860 // determine sizing offscreen 17861 inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'}); 17862 $.datepicker._updateDatepicker(inst); 17863 // fix width for dynamic number of date pickers 17864 // and adjust position before showing 17865 offset = $.datepicker._checkOffset(inst, offset, isFixed); 17866 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? 17867 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none', 17868 left: offset.left + 'px', top: offset.top + 'px'}); 17869 if (!inst.inline) { 17870 var showAnim = $.datepicker._get(inst, 'showAnim'); 17871 var duration = $.datepicker._get(inst, 'duration'); 17872 var postProcess = function() { 17873 var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only 17874 if( !! cover.length ){ 17875 var borders = $.datepicker._getBorders(inst.dpDiv); 17876 cover.css({left: -borders[0], top: -borders[1], 17877 width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}); 17878 } 17879 }; 17880 inst.dpDiv.zIndex($(input).zIndex()+1); 17881 $.datepicker._datepickerShowing = true; 17882 if ($.effects && $.effects[showAnim]) 17883 inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); 17884 else 17885 inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess); 17886 if (!showAnim || !duration) 17887 postProcess(); 17888 if (inst.input.is(':visible') && !inst.input.is(':disabled')) 17889 inst.input.focus(); 17890 $.datepicker._curInst = inst; 17891 } 17892 }, 17893 17894 /* Generate the date picker content. */ 17895 _updateDatepicker: function(inst) { 17896 var self = this; 17897 self.maxRows = 4; //Reset the max number of rows being displayed (see #7043) 17898 var borders = $.datepicker._getBorders(inst.dpDiv); 17899 instActive = inst; // for delegate hover events 17900 inst.dpDiv.empty().append(this._generateHTML(inst)); 17901 var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only 17902 if( !!cover.length ){ //avoid call to outerXXXX() when not in IE6 17903 cover.css({left: -borders[0], top: -borders[1], width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}) 17904 } 17905 inst.dpDiv.find('.' + this._dayOverClass + ' a').mouseover(); 17906 var numMonths = this._getNumberOfMonths(inst); 17907 var cols = numMonths[1]; 17908 var width = 17; 17909 inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width(''); 17910 if (cols > 1) 17911 inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em'); 17912 inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') + 17913 'Class']('ui-datepicker-multi'); 17914 inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') + 17915 'Class']('ui-datepicker-rtl'); 17916 if (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input && 17917 // #6694 - don't focus the input if it's already focused 17918 // this breaks the change event in IE 17919 inst.input.is(':visible') && !inst.input.is(':disabled') && inst.input[0] != document.activeElement) 17920 inst.input.focus(); 17921 // deffered render of the years select (to avoid flashes on Firefox) 17922 if( inst.yearshtml ){ 17923 var origyearshtml = inst.yearshtml; 17924 setTimeout(function(){ 17925 //assure that inst.yearshtml didn't change. 17926 if( origyearshtml === inst.yearshtml && inst.yearshtml ){ 17927 inst.dpDiv.find('select.ui-datepicker-year:first').replaceWith(inst.yearshtml); 17928 } 17929 origyearshtml = inst.yearshtml = null; 17930 }, 0); 17931 } 17932 }, 17933 17934 /* Retrieve the size of left and top borders for an element. 17935 @param elem (jQuery object) the element of interest 17936 @return (number[2]) the left and top borders */ 17937 _getBorders: function(elem) { 17938 var convert = function(value) { 17939 return {thin: 1, medium: 2, thick: 3}[value] || value; 17940 }; 17941 return [parseFloat(convert(elem.css('border-left-width'))), 17942 parseFloat(convert(elem.css('border-top-width')))]; 17943 }, 17944 17945 /* Check positioning to remain on screen. */ 17946 _checkOffset: function(inst, offset, isFixed) { 17947 var dpWidth = inst.dpDiv.outerWidth(); 17948 var dpHeight = inst.dpDiv.outerHeight(); 17949 var inputWidth = inst.input ? inst.input.outerWidth() : 0; 17950 var inputHeight = inst.input ? inst.input.outerHeight() : 0; 17951 var viewWidth = document.documentElement.clientWidth + $(document).scrollLeft(); 17952 var viewHeight = document.documentElement.clientHeight + $(document).scrollTop(); 17953 17954 offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0); 17955 offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0; 17956 offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; 17957 17958 // now check if datepicker is showing outside window viewport - move to a better place if so. 17959 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? 17960 Math.abs(offset.left + dpWidth - viewWidth) : 0); 17961 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? 17962 Math.abs(dpHeight + inputHeight) : 0); 17963 17964 return offset; 17965 }, 17966 17967 /* Find an object's position on the screen. */ 17968 _findPos: function(obj) { 17969 var inst = this._getInst(obj); 17970 var isRTL = this._get(inst, 'isRTL'); 17971 while (obj && (obj.type == 'hidden' || obj.nodeType != 1 || $.expr.filters.hidden(obj))) { 17972 obj = obj[isRTL ? 'previousSibling' : 'nextSibling']; 17973 } 17974 var position = $(obj).offset(); 17975 return [position.left, position.top]; 17976 }, 17977 17978 /* Trigger custom callback of onClose. */ 17979 _triggerOnClose: function(inst) { 17980 var onClose = this._get(inst, 'onClose'); 17981 if (onClose) 17982 onClose.apply((inst.input ? inst.input[0] : null), 17983 [(inst.input ? inst.input.val() : ''), inst]); 17984 }, 17985 17986 /* Hide the date picker from view. 17987 @param input element - the input field attached to the date picker */ 17988 _hideDatepicker: function(input) { 17989 var inst = this._curInst; 17990 if (!inst || (input && inst != $.data(input, PROP_NAME))) 17991 return; 17992 if (this._datepickerShowing) { 17993 var showAnim = this._get(inst, 'showAnim'); 17994 var duration = this._get(inst, 'duration'); 17995 var postProcess = function() { 17996 $.datepicker._tidyDialog(inst); 17997 this._curInst = null; 17998 }; 17999 if ($.effects && $.effects[showAnim]) 18000 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); 18001 else 18002 inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' : 18003 (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess); 18004 if (!showAnim) 18005 postProcess(); 18006 $.datepicker._triggerOnClose(inst); 18007 this._datepickerShowing = false; 18008 this._lastInput = null; 18009 if (this._inDialog) { 18010 this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' }); 18011 if ($.blockUI) { 18012 $.unblockUI(); 18013 $('body').append(this.dpDiv); 18014 } 18015 } 18016 this._inDialog = false; 18017 } 18018 }, 18019 18020 /* Tidy up after a dialog display. */ 18021 _tidyDialog: function(inst) { 18022 inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar'); 18023 }, 18024 18025 /* Close date picker if clicked elsewhere. */ 18026 _checkExternalClick: function(event) { 18027 if (!$.datepicker._curInst) 18028 return; 18029 var $target = $(event.target); 18030 if ($target[0].id != $.datepicker._mainDivId && 18031 $target.parents('#' + $.datepicker._mainDivId).length == 0 && 18032 !$target.hasClass($.datepicker.markerClassName) && 18033 !$target.hasClass($.datepicker._triggerClass) && 18034 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI)) 18035 $.datepicker._hideDatepicker(); 18036 }, 18037 18038 /* Adjust one of the date sub-fields. */ 18039 _adjustDate: function(id, offset, period) { 18040 var target = $(id); 18041 var inst = this._getInst(target[0]); 18042 if (this._isDisabledDatepicker(target[0])) { 18043 return; 18044 } 18045 this._adjustInstDate(inst, offset + 18046 (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning 18047 period); 18048 this._updateDatepicker(inst); 18049 }, 18050 18051 /* Action for current link. */ 18052 _gotoToday: function(id) { 18053 var target = $(id); 18054 var inst = this._getInst(target[0]); 18055 if (this._get(inst, 'gotoCurrent') && inst.currentDay) { 18056 inst.selectedDay = inst.currentDay; 18057 inst.drawMonth = inst.selectedMonth = inst.currentMonth; 18058 inst.drawYear = inst.selectedYear = inst.currentYear; 18059 } 18060 else { 18061 var date = new Date(); 18062 inst.selectedDay = date.getDate(); 18063 inst.drawMonth = inst.selectedMonth = date.getMonth(); 18064 inst.drawYear = inst.selectedYear = date.getFullYear(); 18065 } 18066 this._notifyChange(inst); 18067 this._adjustDate(target); 18068 }, 18069 18070 /* Action for selecting a new month/year. */ 18071 _selectMonthYear: function(id, select, period) { 18072 var target = $(id); 18073 var inst = this._getInst(target[0]); 18074 inst['selected' + (period == 'M' ? 'Month' : 'Year')] = 18075 inst['draw' + (period == 'M' ? 'Month' : 'Year')] = 18076 parseInt(select.options[select.selectedIndex].value,10); 18077 this._notifyChange(inst); 18078 this._adjustDate(target); 18079 }, 18080 18081 /* Action for selecting a day. */ 18082 _selectDay: function(id, month, year, td) { 18083 var target = $(id); 18084 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { 18085 return; 18086 } 18087 var inst = this._getInst(target[0]); 18088 inst.selectedDay = inst.currentDay = $('a', td).html(); 18089 inst.selectedMonth = inst.currentMonth = month; 18090 inst.selectedYear = inst.currentYear = year; 18091 this._selectDate(id, this._formatDate(inst, 18092 inst.currentDay, inst.currentMonth, inst.currentYear)); 18093 }, 18094 18095 /* Erase the input field and hide the date picker. */ 18096 _clearDate: function(id) { 18097 var target = $(id); 18098 var inst = this._getInst(target[0]); 18099 this._selectDate(target, ''); 18100 }, 18101 18102 /* Update the input field with the selected date. */ 18103 _selectDate: function(id, dateStr) { 18104 var target = $(id); 18105 var inst = this._getInst(target[0]); 18106 dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); 18107 if (inst.input) 18108 inst.input.val(dateStr); 18109 this._updateAlternate(inst); 18110 var onSelect = this._get(inst, 'onSelect'); 18111 if (onSelect) 18112 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback 18113 else if (inst.input) 18114 inst.input.trigger('change'); // fire the change event 18115 if (inst.inline) 18116 this._updateDatepicker(inst); 18117 else { 18118 this._hideDatepicker(); 18119 this._lastInput = inst.input[0]; 18120 if (typeof(inst.input[0]) != 'object') 18121 inst.input.focus(); // restore focus 18122 this._lastInput = null; 18123 } 18124 }, 18125 18126 /* Update any alternate field to synchronise with the main field. */ 18127 _updateAlternate: function(inst) { 18128 var altField = this._get(inst, 'altField'); 18129 if (altField) { // update alternate field too 18130 var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat'); 18131 var date = this._getDate(inst); 18132 var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); 18133 $(altField).each(function() { $(this).val(dateStr); }); 18134 } 18135 }, 18136 18137 /* Set as beforeShowDay function to prevent selection of weekends. 18138 @param date Date - the date to customise 18139 @return [boolean, string] - is this date selectable?, what is its CSS class? */ 18140 noWeekends: function(date) { 18141 var day = date.getDay(); 18142 return [(day > 0 && day < 6), '']; 18143 }, 18144 18145 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. 18146 @param date Date - the date to get the week for 18147 @return number - the number of the week within the year that contains this date */ 18148 iso8601Week: function(date) { 18149 var checkDate = new Date(date.getTime()); 18150 // Find Thursday of this week starting on Monday 18151 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); 18152 var time = checkDate.getTime(); 18153 checkDate.setMonth(0); // Compare with Jan 1 18154 checkDate.setDate(1); 18155 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; 18156 }, 18157 18158 /* Parse a string value into a date object. 18159 See formatDate below for the possible formats. 18160 18161 @param format string - the expected format of the date 18162 @param value string - the date in the above format 18163 @param settings Object - attributes include: 18164 shortYearCutoff number - the cutoff year for determining the century (optional) 18165 dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 18166 dayNames string[7] - names of the days from Sunday (optional) 18167 monthNamesShort string[12] - abbreviated names of the months (optional) 18168 monthNames string[12] - names of the months (optional) 18169 @return Date - the extracted date value or null if value is blank */ 18170 parseDate: function (format, value, settings) { 18171 if (format == null || value == null) 18172 throw 'Invalid arguments'; 18173 value = (typeof value == 'object' ? value.toString() : value + ''); 18174 if (value == '') 18175 return null; 18176 var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff; 18177 shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : 18178 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); 18179 var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; 18180 var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; 18181 var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; 18182 var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; 18183 var year = -1; 18184 var month = -1; 18185 var day = -1; 18186 var doy = -1; 18187 var literal = false; 18188 // Check whether a format character is doubled 18189 var lookAhead = function(match) { 18190 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); 18191 if (matches) 18192 iFormat++; 18193 return matches; 18194 }; 18195 // Extract a number from the string value 18196 var getNumber = function(match) { 18197 var isDoubled = lookAhead(match); 18198 var size = (match == '@' ? 14 : (match == '!' ? 20 : 18199 (match == 'y' && isDoubled ? 4 : (match == 'o' ? 3 : 2)))); 18200 var digits = new RegExp('^\\d{1,' + size + '}'); 18201 var num = value.substring(iValue).match(digits); 18202 if (!num) 18203 throw 'Missing number at position ' + iValue; 18204 iValue += num[0].length; 18205 return parseInt(num[0], 10); 18206 }; 18207 // Extract a name from the string value and convert to an index 18208 var getName = function(match, shortNames, longNames) { 18209 var names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) { 18210 return [ [k, v] ]; 18211 }).sort(function (a, b) { 18212 return -(a[1].length - b[1].length); 18213 }); 18214 var index = -1; 18215 $.each(names, function (i, pair) { 18216 var name = pair[1]; 18217 if (value.substr(iValue, name.length).toLowerCase() == name.toLowerCase()) { 18218 index = pair[0]; 18219 iValue += name.length; 18220 return false; 18221 } 18222 }); 18223 if (index != -1) 18224 return index + 1; 18225 else 18226 throw 'Unknown name at position ' + iValue; 18227 }; 18228 // Confirm that a literal character matches the string value 18229 var checkLiteral = function() { 18230 if (value.charAt(iValue) != format.charAt(iFormat)) 18231 throw 'Unexpected literal at position ' + iValue; 18232 iValue++; 18233 }; 18234 var iValue = 0; 18235 for (var iFormat = 0; iFormat < format.length; iFormat++) { 18236 if (literal) 18237 if (format.charAt(iFormat) == "'" && !lookAhead("'")) 18238 literal = false; 18239 else 18240 checkLiteral(); 18241 else 18242 switch (format.charAt(iFormat)) { 18243 case 'd': 18244 day = getNumber('d'); 18245 break; 18246 case 'D': 18247 getName('D', dayNamesShort, dayNames); 18248 break; 18249 case 'o': 18250 doy = getNumber('o'); 18251 break; 18252 case 'm': 18253 month = getNumber('m'); 18254 break; 18255 case 'M': 18256 month = getName('M', monthNamesShort, monthNames); 18257 break; 18258 case 'y': 18259 year = getNumber('y'); 18260 break; 18261 case '@': 18262 var date = new Date(getNumber('@')); 18263 year = date.getFullYear(); 18264 month = date.getMonth() + 1; 18265 day = date.getDate(); 18266 break; 18267 case '!': 18268 var date = new Date((getNumber('!') - this._ticksTo1970) / 10000); 18269 year = date.getFullYear(); 18270 month = date.getMonth() + 1; 18271 day = date.getDate(); 18272 break; 18273 case "'": 18274 if (lookAhead("'")) 18275 checkLiteral(); 18276 else 18277 literal = true; 18278 break; 18279 default: 18280 checkLiteral(); 18281 } 18282 } 18283 if (iValue < value.length){ 18284 throw "Extra/unparsed characters found in date: " + value.substring(iValue); 18285 } 18286 if (year == -1) 18287 year = new Date().getFullYear(); 18288 else if (year < 100) 18289 year += new Date().getFullYear() - new Date().getFullYear() % 100 + 18290 (year <= shortYearCutoff ? 0 : -100); 18291 if (doy > -1) { 18292 month = 1; 18293 day = doy; 18294 do { 18295 var dim = this._getDaysInMonth(year, month - 1); 18296 if (day <= dim) 18297 break; 18298 month++; 18299 day -= dim; 18300 } while (true); 18301 } 18302 var date = this._daylightSavingAdjust(new Date(year, month - 1, day)); 18303 if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day) 18304 throw 'Invalid date'; // E.g. 31/02/00 18305 return date; 18306 }, 18307 18308 /* Standard date formats. */ 18309 ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601) 18310 COOKIE: 'D, dd M yy', 18311 ISO_8601: 'yy-mm-dd', 18312 RFC_822: 'D, d M y', 18313 RFC_850: 'DD, dd-M-y', 18314 RFC_1036: 'D, d M y', 18315 RFC_1123: 'D, d M yy', 18316 RFC_2822: 'D, d M yy', 18317 RSS: 'D, d M y', // RFC 822 18318 TICKS: '!', 18319 TIMESTAMP: '@', 18320 W3C: 'yy-mm-dd', // ISO 8601 18321 18322 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + 18323 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), 18324 18325 /* Format a date object into a string value. 18326 The format can be combinations of the following: 18327 d - day of month (no leading zero) 18328 dd - day of month (two digit) 18329 o - day of year (no leading zeros) 18330 oo - day of year (three digit) 18331 D - day name short 18332 DD - day name long 18333 m - month of year (no leading zero) 18334 mm - month of year (two digit) 18335 M - month name short 18336 MM - month name long 18337 y - year (two digit) 18338 yy - year (four digit) 18339 @ - Unix timestamp (ms since 01/01/1970) 18340 ! - Windows ticks (100ns since 01/01/0001) 18341 '...' - literal text 18342 '' - single quote 18343 18344 @param format string - the desired format of the date 18345 @param date Date - the date value to format 18346 @param settings Object - attributes include: 18347 dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 18348 dayNames string[7] - names of the days from Sunday (optional) 18349 monthNamesShort string[12] - abbreviated names of the months (optional) 18350 monthNames string[12] - names of the months (optional) 18351 @return string - the date in the above format */ 18352 formatDate: function (format, date, settings) { 18353 if (!date) 18354 return ''; 18355 var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; 18356 var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; 18357 var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; 18358 var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; 18359 // Check whether a format character is doubled 18360 var lookAhead = function(match) { 18361 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); 18362 if (matches) 18363 iFormat++; 18364 return matches; 18365 }; 18366 // Format a number, with leading zero if necessary 18367 var formatNumber = function(match, value, len) { 18368 var num = '' + value; 18369 if (lookAhead(match)) 18370 while (num.length < len) 18371 num = '0' + num; 18372 return num; 18373 }; 18374 // Format a name, short or long as requested 18375 var formatName = function(match, value, shortNames, longNames) { 18376 return (lookAhead(match) ? longNames[value] : shortNames[value]); 18377 }; 18378 var output = ''; 18379 var literal = false; 18380 if (date) 18381 for (var iFormat = 0; iFormat < format.length; iFormat++) { 18382 if (literal) 18383 if (format.charAt(iFormat) == "'" && !lookAhead("'")) 18384 literal = false; 18385 else 18386 output += format.charAt(iFormat); 18387 else 18388 switch (format.charAt(iFormat)) { 18389 case 'd': 18390 output += formatNumber('d', date.getDate(), 2); 18391 break; 18392 case 'D': 18393 output += formatName('D', date.getDay(), dayNamesShort, dayNames); 18394 break; 18395 case 'o': 18396 output += formatNumber('o', 18397 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3); 18398 break; 18399 case 'm': 18400 output += formatNumber('m', date.getMonth() + 1, 2); 18401 break; 18402 case 'M': 18403 output += formatName('M', date.getMonth(), monthNamesShort, monthNames); 18404 break; 18405 case 'y': 18406 output += (lookAhead('y') ? date.getFullYear() : 18407 (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100); 18408 break; 18409 case '@': 18410 output += date.getTime(); 18411 break; 18412 case '!': 18413 output += date.getTime() * 10000 + this._ticksTo1970; 18414 break; 18415 case "'": 18416 if (lookAhead("'")) 18417 output += "'"; 18418 else 18419 literal = true; 18420 break; 18421 default: 18422 output += format.charAt(iFormat); 18423 } 18424 } 18425 return output; 18426 }, 18427 18428 /* Extract all possible characters from the date format. */ 18429 _possibleChars: function (format) { 18430 var chars = ''; 18431 var literal = false; 18432 // Check whether a format character is doubled 18433 var lookAhead = function(match) { 18434 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); 18435 if (matches) 18436 iFormat++; 18437 return matches; 18438 }; 18439 for (var iFormat = 0; iFormat < format.length; iFormat++) 18440 if (literal) 18441 if (format.charAt(iFormat) == "'" && !lookAhead("'")) 18442 literal = false; 18443 else 18444 chars += format.charAt(iFormat); 18445 else 18446 switch (format.charAt(iFormat)) { 18447 case 'd': case 'm': case 'y': case '@': 18448 chars += '0123456789'; 18449 break; 18450 case 'D': case 'M': 18451 return null; // Accept anything 18452 case "'": 18453 if (lookAhead("'")) 18454 chars += "'"; 18455 else 18456 literal = true; 18457 break; 18458 default: 18459 chars += format.charAt(iFormat); 18460 } 18461 return chars; 18462 }, 18463 18464 /* Get a setting value, defaulting if necessary. */ 18465 _get: function(inst, name) { 18466 return inst.settings[name] !== undefined ? 18467 inst.settings[name] : this._defaults[name]; 18468 }, 18469 18470 /* Parse existing date and initialise date picker. */ 18471 _setDateFromField: function(inst, noDefault) { 18472 if (inst.input.val() == inst.lastVal) { 18473 return; 18474 } 18475 var dateFormat = this._get(inst, 'dateFormat'); 18476 var dates = inst.lastVal = inst.input ? inst.input.val() : null; 18477 var date, defaultDate; 18478 date = defaultDate = this._getDefaultDate(inst); 18479 var settings = this._getFormatConfig(inst); 18480 try { 18481 date = this.parseDate(dateFormat, dates, settings) || defaultDate; 18482 } catch (event) { 18483 this.log(event); 18484 dates = (noDefault ? '' : dates); 18485 } 18486 inst.selectedDay = date.getDate(); 18487 inst.drawMonth = inst.selectedMonth = date.getMonth(); 18488 inst.drawYear = inst.selectedYear = date.getFullYear(); 18489 inst.currentDay = (dates ? date.getDate() : 0); 18490 inst.currentMonth = (dates ? date.getMonth() : 0); 18491 inst.currentYear = (dates ? date.getFullYear() : 0); 18492 this._adjustInstDate(inst); 18493 }, 18494 18495 /* Retrieve the default date shown on opening. */ 18496 _getDefaultDate: function(inst) { 18497 return this._restrictMinMax(inst, 18498 this._determineDate(inst, this._get(inst, 'defaultDate'), new Date())); 18499 }, 18500 18501 /* A date may be specified as an exact value or a relative one. */ 18502 _determineDate: function(inst, date, defaultDate) { 18503 var offsetNumeric = function(offset) { 18504 var date = new Date(); 18505 date.setDate(date.getDate() + offset); 18506 return date; 18507 }; 18508 var offsetString = function(offset) { 18509 try { 18510 return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), 18511 offset, $.datepicker._getFormatConfig(inst)); 18512 } 18513 catch (e) { 18514 // Ignore 18515 } 18516 var date = (offset.toLowerCase().match(/^c/) ? 18517 $.datepicker._getDate(inst) : null) || new Date(); 18518 var year = date.getFullYear(); 18519 var month = date.getMonth(); 18520 var day = date.getDate(); 18521 var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g; 18522 var matches = pattern.exec(offset); 18523 while (matches) { 18524 switch (matches[2] || 'd') { 18525 case 'd' : case 'D' : 18526 day += parseInt(matches[1],10); break; 18527 case 'w' : case 'W' : 18528 day += parseInt(matches[1],10) * 7; break; 18529 case 'm' : case 'M' : 18530 month += parseInt(matches[1],10); 18531 day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); 18532 break; 18533 case 'y': case 'Y' : 18534 year += parseInt(matches[1],10); 18535 day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); 18536 break; 18537 } 18538 matches = pattern.exec(offset); 18539 } 18540 return new Date(year, month, day); 18541 }; 18542 var newDate = (date == null || date === '' ? defaultDate : (typeof date == 'string' ? offsetString(date) : 18543 (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime())))); 18544 newDate = (newDate && newDate.toString() == 'Invalid Date' ? defaultDate : newDate); 18545 if (newDate) { 18546 newDate.setHours(0); 18547 newDate.setMinutes(0); 18548 newDate.setSeconds(0); 18549 newDate.setMilliseconds(0); 18550 } 18551 return this._daylightSavingAdjust(newDate); 18552 }, 18553 18554 /* Handle switch to/from daylight saving. 18555 Hours may be non-zero on daylight saving cut-over: 18556 > 12 when midnight changeover, but then cannot generate 18557 midnight datetime, so jump to 1AM, otherwise reset. 18558 @param date (Date) the date to check 18559 @return (Date) the corrected date */ 18560 _daylightSavingAdjust: function(date) { 18561 if (!date) return null; 18562 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); 18563 return date; 18564 }, 18565 18566 /* Set the date(s) directly. */ 18567 _setDate: function(inst, date, noChange) { 18568 var clear = !date; 18569 var origMonth = inst.selectedMonth; 18570 var origYear = inst.selectedYear; 18571 var newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); 18572 inst.selectedDay = inst.currentDay = newDate.getDate(); 18573 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); 18574 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); 18575 if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange) 18576 this._notifyChange(inst); 18577 this._adjustInstDate(inst); 18578 if (inst.input) { 18579 inst.input.val(clear ? '' : this._formatDate(inst)); 18580 } 18581 }, 18582 18583 /* Retrieve the date(s) directly. */ 18584 _getDate: function(inst) { 18585 var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null : 18586 this._daylightSavingAdjust(new Date( 18587 inst.currentYear, inst.currentMonth, inst.currentDay))); 18588 return startDate; 18589 }, 18590 18591 /* Generate the HTML for the current state of the date picker. */ 18592 _generateHTML: function(inst) { 18593 var today = new Date(); 18594 today = this._daylightSavingAdjust( 18595 new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time 18596 var isRTL = this._get(inst, 'isRTL'); 18597 var showButtonPanel = this._get(inst, 'showButtonPanel'); 18598 var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext'); 18599 var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat'); 18600 var numMonths = this._getNumberOfMonths(inst); 18601 var showCurrentAtPos = this._get(inst, 'showCurrentAtPos'); 18602 var stepMonths = this._get(inst, 'stepMonths'); 18603 var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1); 18604 var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : 18605 new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); 18606 var minDate = this._getMinMaxDate(inst, 'min'); 18607 var maxDate = this._getMinMaxDate(inst, 'max'); 18608 var drawMonth = inst.drawMonth - showCurrentAtPos; 18609 var drawYear = inst.drawYear; 18610 if (drawMonth < 0) { 18611 drawMonth += 12; 18612 drawYear--; 18613 } 18614 if (maxDate) { 18615 var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), 18616 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); 18617 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); 18618 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { 18619 drawMonth--; 18620 if (drawMonth < 0) { 18621 drawMonth = 11; 18622 drawYear--; 18623 } 18624 } 18625 } 18626 inst.drawMonth = drawMonth; 18627 inst.drawYear = drawYear; 18628 var prevText = this._get(inst, 'prevText'); 18629 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, 18630 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), 18631 this._getFormatConfig(inst))); 18632 var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? 18633 '<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_' + dpuuid + 18634 '.datepicker._adjustDate(\'#' + inst.id + '\', -' + stepMonths + ', \'M\');"' + 18635 ' title="' + prevText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>' : 18636 (hideIfNoPrevNext ? '' : '<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+ prevText +'"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>')); 18637 var nextText = this._get(inst, 'nextText'); 18638 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, 18639 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), 18640 this._getFormatConfig(inst))); 18641 var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? 18642 '<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_' + dpuuid + 18643 '.datepicker._adjustDate(\'#' + inst.id + '\', +' + stepMonths + ', \'M\');"' + 18644 ' title="' + nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>' : 18645 (hideIfNoPrevNext ? '' : '<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+ nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>')); 18646 var currentText = this._get(inst, 'currentText'); 18647 var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today); 18648 currentText = (!navigationAsDateFormat ? currentText : 18649 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); 18650 var controls = (!inst.inline ? '<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_' + dpuuid + 18651 '.datepicker._hideDatepicker();">' + this._get(inst, 'closeText') + '</button>' : ''); 18652 var buttonPanel = (showButtonPanel) ? '<div class="ui-datepicker-buttonpane ui-widget-content">' + (isRTL ? controls : '') + 18653 (this._isInRange(inst, gotoDate) ? '<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_' + dpuuid + 18654 '.datepicker._gotoToday(\'#' + inst.id + '\');"' + 18655 '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : ''; 18656 var firstDay = parseInt(this._get(inst, 'firstDay'),10); 18657 firstDay = (isNaN(firstDay) ? 0 : firstDay); 18658 var showWeek = this._get(inst, 'showWeek'); 18659 var dayNames = this._get(inst, 'dayNames'); 18660 var dayNamesShort = this._get(inst, 'dayNamesShort'); 18661 var dayNamesMin = this._get(inst, 'dayNamesMin'); 18662 var monthNames = this._get(inst, 'monthNames'); 18663 var monthNamesShort = this._get(inst, 'monthNamesShort'); 18664 var beforeShowDay = this._get(inst, 'beforeShowDay'); 18665 var showOtherMonths = this._get(inst, 'showOtherMonths'); 18666 var selectOtherMonths = this._get(inst, 'selectOtherMonths'); 18667 var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week; 18668 var defaultDate = this._getDefaultDate(inst); 18669 var html = ''; 18670 for (var row = 0; row < numMonths[0]; row++) { 18671 var group = ''; 18672 this.maxRows = 4; 18673 for (var col = 0; col < numMonths[1]; col++) { 18674 var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); 18675 var cornerClass = ' ui-corner-all'; 18676 var calender = ''; 18677 if (isMultiMonth) { 18678 calender += '<div class="ui-datepicker-group'; 18679 if (numMonths[1] > 1) 18680 switch (col) { 18681 case 0: calender += ' ui-datepicker-group-first'; 18682 cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break; 18683 case numMonths[1]-1: calender += ' ui-datepicker-group-last'; 18684 cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break; 18685 default: calender += ' ui-datepicker-group-middle'; cornerClass = ''; break; 18686 } 18687 calender += '">'; 18688 } 18689 calender += '<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix' + cornerClass + '">' + 18690 (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') + 18691 (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') + 18692 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, 18693 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers 18694 '</div><table class="ui-datepicker-calendar"><thead>' + 18695 '<tr>'; 18696 var thead = (showWeek ? '<th class="ui-datepicker-week-col">' + this._get(inst, 'weekHeader') + '</th>' : ''); 18697 for (var dow = 0; dow < 7; dow++) { // days of the week 18698 var day = (dow + firstDay) % 7; 18699 thead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' + 18700 '<span title="' + dayNames[day] + '">' + dayNamesMin[day] + '</span></th>'; 18701 } 18702 calender += thead + '</tr></thead><tbody>'; 18703 var daysInMonth = this._getDaysInMonth(drawYear, drawMonth); 18704 if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth) 18705 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); 18706 var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; 18707 var curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate 18708 var numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043) 18709 this.maxRows = numRows; 18710 var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); 18711 for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows 18712 calender += '<tr>'; 18713 var tbody = (!showWeek ? '' : '<td class="ui-datepicker-week-col">' + 18714 this._get(inst, 'calculateWeek')(printDate) + '</td>'); 18715 for (var dow = 0; dow < 7; dow++) { // create date picker days 18716 var daySettings = (beforeShowDay ? 18717 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']); 18718 var otherMonth = (printDate.getMonth() != drawMonth); 18719 var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || 18720 (minDate && printDate < minDate) || (maxDate && printDate > maxDate); 18721 tbody += '<td class="' + 18722 ((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends 18723 (otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months 18724 ((printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth && inst._keyEvent) || // user pressed key 18725 (defaultDate.getTime() == printDate.getTime() && defaultDate.getTime() == selectedDate.getTime()) ? 18726 // or defaultDate is current printedDate and defaultDate is selectedDate 18727 ' ' + this._dayOverClass : '') + // highlight selected day 18728 (unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled': '') + // highlight unselectable days 18729 (otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates 18730 (printDate.getTime() == currentDate.getTime() ? ' ' + this._currentClass : '') + // highlight selected day 18731 (printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different) 18732 ((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title 18733 (unselectable ? '' : ' onclick="DP_jQuery_' + dpuuid + '.datepicker._selectDay(\'#' + 18734 inst.id + '\',' + printDate.getMonth() + ',' + printDate.getFullYear() + ', this);return false;"') + '>' + // actions 18735 (otherMonth && !showOtherMonths ? ' ' : // display for other months 18736 (unselectable ? '<span class="ui-state-default">' + printDate.getDate() + '</span>' : '<a class="ui-state-default' + 18737 (printDate.getTime() == today.getTime() ? ' ui-state-highlight' : '') + 18738 (printDate.getTime() == currentDate.getTime() ? ' ui-state-active' : '') + // highlight selected day 18739 (otherMonth ? ' ui-priority-secondary' : '') + // distinguish dates from other months 18740 '" href="#">' + printDate.getDate() + '</a>')) + '</td>'; // display selectable date 18741 printDate.setDate(printDate.getDate() + 1); 18742 printDate = this._daylightSavingAdjust(printDate); 18743 } 18744 calender += tbody + '</tr>'; 18745 } 18746 drawMonth++; 18747 if (drawMonth > 11) { 18748 drawMonth = 0; 18749 drawYear++; 18750 } 18751 calender += '</tbody></table>' + (isMultiMonth ? '</div>' + 18752 ((numMonths[0] > 0 && col == numMonths[1]-1) ? '<div class="ui-datepicker-row-break"></div>' : '') : ''); 18753 group += calender; 18754 } 18755 html += group; 18756 } 18757 html += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ? 18758 '<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>' : ''); 18759 inst._keyEvent = false; 18760 return html; 18761 }, 18762 18763 /* Generate the month and year header. */ 18764 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, 18765 secondary, monthNames, monthNamesShort) { 18766 var changeMonth = this._get(inst, 'changeMonth'); 18767 var changeYear = this._get(inst, 'changeYear'); 18768 var showMonthAfterYear = this._get(inst, 'showMonthAfterYear'); 18769 var html = '<div class="ui-datepicker-title">'; 18770 var monthHtml = ''; 18771 // month selection 18772 if (secondary || !changeMonth) 18773 monthHtml += '<span class="ui-datepicker-month">' + monthNames[drawMonth] + '</span>'; 18774 else { 18775 var inMinYear = (minDate && minDate.getFullYear() == drawYear); 18776 var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear); 18777 monthHtml += '<select class="ui-datepicker-month" ' + 18778 'onchange="DP_jQuery_' + dpuuid + '.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'M\');" ' + 18779 '>'; 18780 for (var month = 0; month < 12; month++) { 18781 if ((!inMinYear || month >= minDate.getMonth()) && 18782 (!inMaxYear || month <= maxDate.getMonth())) 18783 monthHtml += '<option value="' + month + '"' + 18784 (month == drawMonth ? ' selected="selected"' : '') + 18785 '>' + monthNamesShort[month] + '</option>'; 18786 } 18787 monthHtml += '</select>'; 18788 } 18789 if (!showMonthAfterYear) 18790 html += monthHtml + (secondary || !(changeMonth && changeYear) ? ' ' : ''); 18791 // year selection 18792 if ( !inst.yearshtml ) { 18793 inst.yearshtml = ''; 18794 if (secondary || !changeYear) 18795 html += '<span class="ui-datepicker-year">' + drawYear + '</span>'; 18796 else { 18797 // determine range of years to display 18798 var years = this._get(inst, 'yearRange').split(':'); 18799 var thisYear = new Date().getFullYear(); 18800 var determineYear = function(value) { 18801 var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) : 18802 (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) : 18803 parseInt(value, 10))); 18804 return (isNaN(year) ? thisYear : year); 18805 }; 18806 var year = determineYear(years[0]); 18807 var endYear = Math.max(year, determineYear(years[1] || '')); 18808 year = (minDate ? Math.max(year, minDate.getFullYear()) : year); 18809 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); 18810 inst.yearshtml += '<select class="ui-datepicker-year" ' + 18811 'onchange="DP_jQuery_' + dpuuid + '.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'Y\');" ' + 18812 '>'; 18813 for (; year <= endYear; year++) { 18814 inst.yearshtml += '<option value="' + year + '"' + 18815 (year == drawYear ? ' selected="selected"' : '') + 18816 '>' + year + '</option>'; 18817 } 18818 inst.yearshtml += '</select>'; 18819 18820 html += inst.yearshtml; 18821 inst.yearshtml = null; 18822 } 18823 } 18824 html += this._get(inst, 'yearSuffix'); 18825 if (showMonthAfterYear) 18826 html += (secondary || !(changeMonth && changeYear) ? ' ' : '') + monthHtml; 18827 html += '</div>'; // Close datepicker_header 18828 return html; 18829 }, 18830 18831 /* Adjust one of the date sub-fields. */ 18832 _adjustInstDate: function(inst, offset, period) { 18833 var year = inst.drawYear + (period == 'Y' ? offset : 0); 18834 var month = inst.drawMonth + (period == 'M' ? offset : 0); 18835 var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + 18836 (period == 'D' ? offset : 0); 18837 var date = this._restrictMinMax(inst, 18838 this._daylightSavingAdjust(new Date(year, month, day))); 18839 inst.selectedDay = date.getDate(); 18840 inst.drawMonth = inst.selectedMonth = date.getMonth(); 18841 inst.drawYear = inst.selectedYear = date.getFullYear(); 18842 if (period == 'M' || period == 'Y') 18843 this._notifyChange(inst); 18844 }, 18845 18846 /* Ensure a date is within any min/max bounds. */ 18847 _restrictMinMax: function(inst, date) { 18848 var minDate = this._getMinMaxDate(inst, 'min'); 18849 var maxDate = this._getMinMaxDate(inst, 'max'); 18850 var newDate = (minDate && date < minDate ? minDate : date); 18851 newDate = (maxDate && newDate > maxDate ? maxDate : newDate); 18852 return newDate; 18853 }, 18854 18855 /* Notify change of month/year. */ 18856 _notifyChange: function(inst) { 18857 var onChange = this._get(inst, 'onChangeMonthYear'); 18858 if (onChange) 18859 onChange.apply((inst.input ? inst.input[0] : null), 18860 [inst.selectedYear, inst.selectedMonth + 1, inst]); 18861 }, 18862 18863 /* Determine the number of months to show. */ 18864 _getNumberOfMonths: function(inst) { 18865 var numMonths = this._get(inst, 'numberOfMonths'); 18866 return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths)); 18867 }, 18868 18869 /* Determine the current maximum date - ensure no time components are set. */ 18870 _getMinMaxDate: function(inst, minMax) { 18871 return this._determineDate(inst, this._get(inst, minMax + 'Date'), null); 18872 }, 18873 18874 /* Find the number of days in a given month. */ 18875 _getDaysInMonth: function(year, month) { 18876 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate(); 18877 }, 18878 18879 /* Find the day of the week of the first of a month. */ 18880 _getFirstDayOfMonth: function(year, month) { 18881 return new Date(year, month, 1).getDay(); 18882 }, 18883 18884 /* Determines if we should allow a "next/prev" month display change. */ 18885 _canAdjustMonth: function(inst, offset, curYear, curMonth) { 18886 var numMonths = this._getNumberOfMonths(inst); 18887 var date = this._daylightSavingAdjust(new Date(curYear, 18888 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); 18889 if (offset < 0) 18890 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); 18891 return this._isInRange(inst, date); 18892 }, 18893 18894 /* Is the given date in the accepted range? */ 18895 _isInRange: function(inst, date) { 18896 var minDate = this._getMinMaxDate(inst, 'min'); 18897 var maxDate = this._getMinMaxDate(inst, 'max'); 18898 return ((!minDate || date.getTime() >= minDate.getTime()) && 18899 (!maxDate || date.getTime() <= maxDate.getTime())); 18900 }, 18901 18902 /* Provide the configuration settings for formatting/parsing. */ 18903 _getFormatConfig: function(inst) { 18904 var shortYearCutoff = this._get(inst, 'shortYearCutoff'); 18905 shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : 18906 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); 18907 return {shortYearCutoff: shortYearCutoff, 18908 dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'), 18909 monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')}; 18910 }, 18911 18912 /* Format the given date for display. */ 18913 _formatDate: function(inst, day, month, year) { 18914 if (!day) { 18915 inst.currentDay = inst.selectedDay; 18916 inst.currentMonth = inst.selectedMonth; 18917 inst.currentYear = inst.selectedYear; 18918 } 18919 var date = (day ? (typeof day == 'object' ? day : 18920 this._daylightSavingAdjust(new Date(year, month, day))) : 18921 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); 18922 return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst)); 18923 } 18924}); 18925 18926/* 18927 * Bind hover events for datepicker elements. 18928 * Done via delegate so the binding only occurs once in the lifetime of the parent div. 18929 * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. 18930 */ 18931function bindHover(dpDiv) { 18932 var selector = 'button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a'; 18933 return dpDiv.bind('mouseout', function(event) { 18934 var elem = $( event.target ).closest( selector ); 18935 if ( !elem.length ) { 18936 return; 18937 } 18938 elem.removeClass( "ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover" ); 18939 }) 18940 .bind('mouseover', function(event) { 18941 var elem = $( event.target ).closest( selector ); 18942 if ($.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0]) || 18943 !elem.length ) { 18944 return; 18945 } 18946 elem.parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover'); 18947 elem.addClass('ui-state-hover'); 18948 if (elem.hasClass('ui-datepicker-prev')) elem.addClass('ui-datepicker-prev-hover'); 18949 if (elem.hasClass('ui-datepicker-next')) elem.addClass('ui-datepicker-next-hover'); 18950 }); 18951} 18952 18953/* jQuery extend now ignores nulls! */ 18954function extendRemove(target, props) { 18955 $.extend(target, props); 18956 for (var name in props) 18957 if (props[name] == null || props[name] == undefined) 18958 target[name] = props[name]; 18959 return target; 18960}; 18961 18962/* Determine whether an object is an array. */ 18963function isArray(a) { 18964 return (a && (($.browser.safari && typeof a == 'object' && a.length) || 18965 (a.constructor && a.constructor.toString().match(/\Array\(\)/)))); 18966}; 18967 18968/* Invoke the datepicker functionality. 18969 @param options string - a command, optionally followed by additional parameters or 18970 Object - settings for attaching new datepicker functionality 18971 @return jQuery object */ 18972$.fn.datepicker = function(options){ 18973 18974 /* Verify an empty collection wasn't passed - Fixes #6976 */ 18975 if ( !this.length ) { 18976 return this; 18977 } 18978 18979 /* Initialise the date picker. */ 18980 if (!$.datepicker.initialized) { 18981 $(document).mousedown($.datepicker._checkExternalClick). 18982 find('body').append($.datepicker.dpDiv); 18983 $.datepicker.initialized = true; 18984 } 18985 18986 var otherArgs = Array.prototype.slice.call(arguments, 1); 18987 if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget')) 18988 return $.datepicker['_' + options + 'Datepicker']. 18989 apply($.datepicker, [this[0]].concat(otherArgs)); 18990 if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string') 18991 return $.datepicker['_' + options + 'Datepicker']. 18992 apply($.datepicker, [this[0]].concat(otherArgs)); 18993 return this.each(function() { 18994 typeof options == 'string' ? 18995 $.datepicker['_' + options + 'Datepicker']. 18996 apply($.datepicker, [this].concat(otherArgs)) : 18997 $.datepicker._attachDatepicker(this, options); 18998 }); 18999}; 19000 19001$.datepicker = new Datepicker(); // singleton instance 19002$.datepicker.initialized = false; 19003$.datepicker.uuid = new Date().getTime(); 19004$.datepicker.version = "1.8.16"; 19005 19006// Workaround for #4055 19007// Add another global to avoid noConflict issues with inline event handlers 19008window['DP_jQuery_' + dpuuid] = $; 19009 19010})(jQuery); 19011/* 19012 * jQuery UI Dialog 1.8.16 19013 * 19014 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 19015 * Dual licensed under the MIT or GPL Version 2 licenses. 19016 * http://jquery.org/license 19017 * 19018 * http://docs.jquery.com/UI/Dialog 19019 * 19020 * Depends: 19021 * jquery.ui.core.js 19022 * jquery.ui.widget.js 19023 * jquery.ui.button.js 19024 * jquery.ui.draggable.js 19025 * jquery.ui.mouse.js 19026 * jquery.ui.position.js 19027 * jquery.ui.resizable.js 19028 */ 19029(function( $, undefined ) { 19030 19031var uiDialogClasses = 19032 'ui-dialog ' + 19033 'ui-widget ' + 19034 'ui-widget-content ' + 19035 'ui-corner-all ', 19036 sizeRelatedOptions = { 19037 buttons: true, 19038 height: true, 19039 maxHeight: true, 19040 maxWidth: true, 19041 minHeight: true, 19042 minWidth: true, 19043 width: true 19044 }, 19045 resizableRelatedOptions = { 19046 maxHeight: true, 19047 maxWidth: true, 19048 minHeight: true, 19049 minWidth: true 19050 }, 19051 // support for jQuery 1.3.2 - handle common attrFn methods for dialog 19052 attrFn = $.attrFn || { 19053 val: true, 19054 css: true, 19055 html: true, 19056 text: true, 19057 data: true, 19058 width: true, 19059 height: true, 19060 offset: true, 19061 click: true 19062 }; 19063 19064$.widget("ui.dialog", { 19065 options: { 19066 autoOpen: true, 19067 buttons: {}, 19068 closeOnEscape: true, 19069 closeText: 'close', 19070 dialogClass: '', 19071 draggable: true, 19072 hide: null, 19073 height: 'auto', 19074 maxHeight: false, 19075 maxWidth: false, 19076 minHeight: 150, 19077 minWidth: 150, 19078 modal: false, 19079 position: { 19080 my: 'center', 19081 at: 'center', 19082 collision: 'fit', 19083 // ensure that the titlebar is never outside the document 19084 using: function(pos) { 19085 var topOffset = $(this).css(pos).offset().top; 19086 if (topOffset < 0) { 19087 $(this).css('top', pos.top - topOffset); 19088 } 19089 } 19090 }, 19091 resizable: true, 19092 show: null, 19093 stack: true, 19094 title: '', 19095 width: 300, 19096 zIndex: 1000 19097 }, 19098 19099 _create: function() { 19100 this.originalTitle = this.element.attr('title'); 19101 // #5742 - .attr() might return a DOMElement 19102 if ( typeof this.originalTitle !== "string" ) { 19103 this.originalTitle = ""; 19104 } 19105 19106 this.options.title = this.options.title || this.originalTitle; 19107 var self = this, 19108 options = self.options, 19109 19110 title = options.title || ' ', 19111 titleId = $.ui.dialog.getTitleId(self.element), 19112 19113 uiDialog = (self.uiDialog = $('<div></div>')) 19114 .appendTo(document.body) 19115 .hide() 19116 .addClass(uiDialogClasses + options.dialogClass) 19117 .css({ 19118 zIndex: options.zIndex 19119 }) 19120 // setting tabIndex makes the div focusable 19121 // setting outline to 0 prevents a border on focus in Mozilla 19122 .attr('tabIndex', -1).css('outline', 0).keydown(function(event) { 19123 if (options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && 19124 event.keyCode === $.ui.keyCode.ESCAPE) { 19125 19126 self.close(event); 19127 event.preventDefault(); 19128 } 19129 }) 19130 .attr({ 19131 role: 'dialog', 19132 'aria-labelledby': titleId 19133 }) 19134 .mousedown(function(event) { 19135 self.moveToTop(false, event); 19136 }), 19137 19138 uiDialogContent = self.element 19139 .show() 19140 .removeAttr('title') 19141 .addClass( 19142 'ui-dialog-content ' + 19143 'ui-widget-content') 19144 .appendTo(uiDialog), 19145 19146 uiDialogTitlebar = (self.uiDialogTitlebar = $('<div></div>')) 19147 .addClass( 19148 'ui-dialog-titlebar ' + 19149 'ui-widget-header ' + 19150 'ui-corner-all ' + 19151 'ui-helper-clearfix' 19152 ) 19153 .prependTo(uiDialog), 19154 19155 uiDialogTitlebarClose = $('<a href="#"></a>') 19156 .addClass( 19157 'ui-dialog-titlebar-close ' + 19158 'ui-corner-all' 19159 ) 19160 .attr('role', 'button') 19161 .hover( 19162 function() { 19163 uiDialogTitlebarClose.addClass('ui-state-hover'); 19164 }, 19165 function() { 19166 uiDialogTitlebarClose.removeClass('ui-state-hover'); 19167 } 19168 ) 19169 .focus(function() { 19170 uiDialogTitlebarClose.addClass('ui-state-focus'); 19171 }) 19172 .blur(function() { 19173 uiDialogTitlebarClose.removeClass('ui-state-focus'); 19174 }) 19175 .click(function(event) { 19176 self.close(event); 19177 return false; 19178 }) 19179 .appendTo(uiDialogTitlebar), 19180 19181 uiDialogTitlebarCloseText = (self.uiDialogTitlebarCloseText = $('<span></span>')) 19182 .addClass( 19183 'ui-icon ' + 19184 'ui-icon-closethick' 19185 ) 19186 .text(options.closeText) 19187 .appendTo(uiDialogTitlebarClose), 19188 19189 uiDialogTitle = $('<span></span>') 19190 .addClass('ui-dialog-title') 19191 .attr('id', titleId) 19192 .html(title) 19193 .prependTo(uiDialogTitlebar); 19194 19195 //handling of deprecated beforeclose (vs beforeClose) option 19196 //Ticket #4669 http://dev.jqueryui.com/ticket/4669 19197 //TODO: remove in 1.9pre 19198 if ($.isFunction(options.beforeclose) && !$.isFunction(options.beforeClose)) { 19199 options.beforeClose = options.beforeclose; 19200 } 19201 19202 uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection(); 19203 19204 if (options.draggable && $.fn.draggable) { 19205 self._makeDraggable(); 19206 } 19207 if (options.resizable && $.fn.resizable) { 19208 self._makeResizable(); 19209 } 19210 19211 self._createButtons(options.buttons); 19212 self._isOpen = false; 19213 19214 if ($.fn.bgiframe) { 19215 uiDialog.bgiframe(); 19216 } 19217 }, 19218 19219 _init: function() { 19220 if ( this.options.autoOpen ) { 19221 this.open(); 19222 } 19223 }, 19224 19225 destroy: function() { 19226 var self = this; 19227 19228 if (self.overlay) { 19229 self.overlay.destroy(); 19230 } 19231 self.uiDialog.hide(); 19232 self.element 19233 .unbind('.dialog') 19234 .removeData('dialog') 19235 .removeClass('ui-dialog-content ui-widget-content') 19236 .hide().appendTo('body'); 19237 self.uiDialog.remove(); 19238 19239 if (self.originalTitle) { 19240 self.element.attr('title', self.originalTitle); 19241 } 19242 19243 return self; 19244 }, 19245 19246 widget: function() { 19247 return this.uiDialog; 19248 }, 19249 19250 close: function(event) { 19251 var self = this, 19252 maxZ, thisZ; 19253 19254 if (false === self._trigger('beforeClose', event)) { 19255 return; 19256 } 19257 19258 if (self.overlay) { 19259 self.overlay.destroy(); 19260 } 19261 self.uiDialog.unbind('keypress.ui-dialog'); 19262 19263 self._isOpen = false; 19264 19265 if (self.options.hide) { 19266 self.uiDialog.hide(self.options.hide, function() { 19267 self._trigger('close', event); 19268 }); 19269 } else { 19270 self.uiDialog.hide(); 19271 self._trigger('close', event); 19272 } 19273 19274 $.ui.dialog.overlay.resize(); 19275 19276 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) 19277 if (self.options.modal) { 19278 maxZ = 0; 19279 $('.ui-dialog').each(function() { 19280 if (this !== self.uiDialog[0]) { 19281 thisZ = $(this).css('z-index'); 19282 if(!isNaN(thisZ)) { 19283 maxZ = Math.max(maxZ, thisZ); 19284 } 19285 } 19286 }); 19287 $.ui.dialog.maxZ = maxZ; 19288 } 19289 19290 return self; 19291 }, 19292 19293 isOpen: function() { 19294 return this._isOpen; 19295 }, 19296 19297 // the force parameter allows us to move modal dialogs to their correct 19298 // position on open 19299 moveToTop: function(force, event) { 19300 var self = this, 19301 options = self.options, 19302 saveScroll; 19303 19304 if ((options.modal && !force) || 19305 (!options.stack && !options.modal)) { 19306 return self._trigger('focus', event); 19307 } 19308 19309 if (options.zIndex > $.ui.dialog.maxZ) { 19310 $.ui.dialog.maxZ = options.zIndex; 19311 } 19312 if (self.overlay) { 19313 $.ui.dialog.maxZ += 1; 19314 self.overlay.$el.css('z-index', $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ); 19315 } 19316 19317 //Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed. 19318 // http://ui.jquery.com/bugs/ticket/3193 19319 saveScroll = { scrollTop: self.element.scrollTop(), scrollLeft: self.element.scrollLeft() }; 19320 $.ui.dialog.maxZ += 1; 19321 self.uiDialog.css('z-index', $.ui.dialog.maxZ); 19322 self.element.attr(saveScroll); 19323 self._trigger('focus', event); 19324 19325 return self; 19326 }, 19327 19328 open: function() { 19329 if (this._isOpen) { return; } 19330 19331 var self = this, 19332 options = self.options, 19333 uiDialog = self.uiDialog; 19334 19335 self.overlay = options.modal ? new $.ui.dialog.overlay(self) : null; 19336 self._size(); 19337 self._position(options.position); 19338 uiDialog.show(options.show); 19339 self.moveToTop(true); 19340 19341 // prevent tabbing out of modal dialogs 19342 if (options.modal) { 19343 uiDialog.bind('keypress.ui-dialog', function(event) { 19344 if (event.keyCode !== $.ui.keyCode.TAB) { 19345 return; 19346 } 19347 19348 var tabbables = $(':tabbable', this), 19349 first = tabbables.filter(':first'), 19350 last = tabbables.filter(':last'); 19351 19352 if (event.target === last[0] && !event.shiftKey) { 19353 first.focus(1); 19354 return false; 19355 } else if (event.target === first[0] && event.shiftKey) { 19356 last.focus(1); 19357 return false; 19358 } 19359 }); 19360 } 19361 19362 // set focus to the first tabbable element in the content area or the first button 19363 // if there are no tabbable elements, set focus on the dialog itself 19364 $(self.element.find(':tabbable').get().concat( 19365 uiDialog.find('.ui-dialog-buttonpane :tabbable').get().concat( 19366 uiDialog.get()))).eq(0).focus(); 19367 19368 self._isOpen = true; 19369 self._trigger('open'); 19370 19371 return self; 19372 }, 19373 19374 _createButtons: function(buttons) { 19375 var self = this, 19376 hasButtons = false, 19377 uiDialogButtonPane = $('<div></div>') 19378 .addClass( 19379 'ui-dialog-buttonpane ' + 19380 'ui-widget-content ' + 19381 'ui-helper-clearfix' 19382 ), 19383 uiButtonSet = $( "<div></div>" ) 19384 .addClass( "ui-dialog-buttonset" ) 19385 .appendTo( uiDialogButtonPane ); 19386 19387 // if we already have a button pane, remove it 19388 self.uiDialog.find('.ui-dialog-buttonpane').remove(); 19389 19390 if (typeof buttons === 'object' && buttons !== null) { 19391 $.each(buttons, function() { 19392 return !(hasButtons = true); 19393 }); 19394 } 19395 if (hasButtons) { 19396 $.each(buttons, function(name, props) { 19397 props = $.isFunction( props ) ? 19398 { click: props, text: name } : 19399 props; 19400 var button = $('<button type="button"></button>') 19401 .click(function() { 19402 props.click.apply(self.element[0], arguments); 19403 }) 19404 .appendTo(uiButtonSet); 19405 // can't use .attr( props, true ) with jQuery 1.3.2. 19406 $.each( props, function( key, value ) { 19407 if ( key === "click" ) { 19408 return; 19409 } 19410 if ( key in attrFn ) { 19411 button[ key ]( value ); 19412 } else { 19413 button.attr( key, value ); 19414 } 19415 }); 19416 if ($.fn.button) { 19417 button.button(); 19418 } 19419 }); 19420 uiDialogButtonPane.appendTo(self.uiDialog); 19421 } 19422 }, 19423 19424 _makeDraggable: function() { 19425 var self = this, 19426 options = self.options, 19427 doc = $(document), 19428 heightBeforeDrag; 19429 19430 function filteredUi(ui) { 19431 return { 19432 position: ui.position, 19433 offset: ui.offset 19434 }; 19435 } 19436 19437 self.uiDialog.draggable({ 19438 cancel: '.ui-dialog-content, .ui-dialog-titlebar-close', 19439 handle: '.ui-dialog-titlebar', 19440 containment: 'document', 19441 start: function(event, ui) { 19442 heightBeforeDrag = options.height === "auto" ? "auto" : $(this).height(); 19443 $(this).height($(this).height()).addClass("ui-dialog-dragging"); 19444 self._trigger('dragStart', event, filteredUi(ui)); 19445 }, 19446 drag: function(event, ui) { 19447 self._trigger('drag', event, filteredUi(ui)); 19448 }, 19449 stop: function(event, ui) { 19450 options.position = [ui.position.left - doc.scrollLeft(), 19451 ui.position.top - doc.scrollTop()]; 19452 $(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag); 19453 self._trigger('dragStop', event, filteredUi(ui)); 19454 $.ui.dialog.overlay.resize(); 19455 } 19456 }); 19457 }, 19458 19459 _makeResizable: function(handles) { 19460 handles = (handles === undefined ? this.options.resizable : handles); 19461 var self = this, 19462 options = self.options, 19463 // .ui-resizable has position: relative defined in the stylesheet 19464 // but dialogs have to use absolute or fixed positioning 19465 position = self.uiDialog.css('position'), 19466 resizeHandles = (typeof handles === 'string' ? 19467 handles : 19468 'n,e,s,w,se,sw,ne,nw' 19469 ); 19470 19471 function filteredUi(ui) { 19472 return { 19473 originalPosition: ui.originalPosition, 19474 originalSize: ui.originalSize, 19475 position: ui.position, 19476 size: ui.size 19477 }; 19478 } 19479 19480 self.uiDialog.resizable({ 19481 cancel: '.ui-dialog-content', 19482 containment: 'document', 19483 alsoResize: self.element, 19484 maxWidth: options.maxWidth, 19485 maxHeight: options.maxHeight, 19486 minWidth: options.minWidth, 19487 minHeight: self._minHeight(), 19488 handles: resizeHandles, 19489 start: function(event, ui) { 19490 $(this).addClass("ui-dialog-resizing"); 19491 self._trigger('resizeStart', event, filteredUi(ui)); 19492 }, 19493 resize: function(event, ui) { 19494 self._trigger('resize', event, filteredUi(ui)); 19495 }, 19496 stop: function(event, ui) { 19497 $(this).removeClass("ui-dialog-resizing"); 19498 options.height = $(this).height(); 19499 options.width = $(this).width(); 19500 self._trigger('resizeStop', event, filteredUi(ui)); 19501 $.ui.dialog.overlay.resize(); 19502 } 19503 }) 19504 .css('position', position) 19505 .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se'); 19506 }, 19507 19508 _minHeight: function() { 19509 var options = this.options; 19510 19511 if (options.height === 'auto') { 19512 return options.minHeight; 19513 } else { 19514 return Math.min(options.minHeight, options.height); 19515 } 19516 }, 19517 19518 _position: function(position) { 19519 var myAt = [], 19520 offset = [0, 0], 19521 isVisible; 19522 19523 if (position) { 19524 // deep extending converts arrays to objects in jQuery <= 1.3.2 :-( 19525 // if (typeof position == 'string' || $.isArray(position)) { 19526 // myAt = $.isArray(position) ? position : position.split(' '); 19527 19528 if (typeof position === 'string' || (typeof position === 'object' && '0' in position)) { 19529 myAt = position.split ? position.split(' ') : [position[0], position[1]]; 19530 if (myAt.length === 1) { 19531 myAt[1] = myAt[0]; 19532 } 19533 19534 $.each(['left', 'top'], function(i, offsetPosition) { 19535 if (+myAt[i] === myAt[i]) { 19536 offset[i] = myAt[i]; 19537 myAt[i] = offsetPosition; 19538 } 19539 }); 19540 19541 position = { 19542 my: myAt.join(" "), 19543 at: myAt.join(" "), 19544 offset: offset.join(" ") 19545 }; 19546 } 19547 19548 position = $.extend({}, $.ui.dialog.prototype.options.position, position); 19549 } else { 19550 position = $.ui.dialog.prototype.options.position; 19551 } 19552 19553 // need to show the dialog to get the actual offset in the position plugin 19554 isVisible = this.uiDialog.is(':visible'); 19555 if (!isVisible) { 19556 this.uiDialog.show(); 19557 } 19558 this.uiDialog 19559 // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781 19560 .css({ top: 0, left: 0 }) 19561 .position($.extend({ of: window }, position)); 19562 if (!isVisible) { 19563 this.uiDialog.hide(); 19564 } 19565 }, 19566 19567 _setOptions: function( options ) { 19568 var self = this, 19569 resizableOptions = {}, 19570 resize = false; 19571 19572 $.each( options, function( key, value ) { 19573 self._setOption( key, value ); 19574 19575 if ( key in sizeRelatedOptions ) { 19576 resize = true; 19577 } 19578 if ( key in resizableRelatedOptions ) { 19579 resizableOptions[ key ] = value; 19580 } 19581 }); 19582 19583 if ( resize ) { 19584 this._size(); 19585 } 19586 if ( this.uiDialog.is( ":data(resizable)" ) ) { 19587 this.uiDialog.resizable( "option", resizableOptions ); 19588 } 19589 }, 19590 19591 _setOption: function(key, value){ 19592 var self = this, 19593 uiDialog = self.uiDialog; 19594 19595 switch (key) { 19596 //handling of deprecated beforeclose (vs beforeClose) option 19597 //Ticket #4669 http://dev.jqueryui.com/ticket/4669 19598 //TODO: remove in 1.9pre 19599 case "beforeclose": 19600 key = "beforeClose"; 19601 break; 19602 case "buttons": 19603 self._createButtons(value); 19604 break; 19605 case "closeText": 19606 // ensure that we always pass a string 19607 self.uiDialogTitlebarCloseText.text("" + value); 19608 break; 19609 case "dialogClass": 19610 uiDialog 19611 .removeClass(self.options.dialogClass) 19612 .addClass(uiDialogClasses + value); 19613 break; 19614 case "disabled": 19615 if (value) { 19616 uiDialog.addClass('ui-dialog-disabled'); 19617 } else { 19618 uiDialog.removeClass('ui-dialog-disabled'); 19619 } 19620 break; 19621 case "draggable": 19622 var isDraggable = uiDialog.is( ":data(draggable)" ); 19623 if ( isDraggable && !value ) { 19624 uiDialog.draggable( "destroy" ); 19625 } 19626 19627 if ( !isDraggable && value ) { 19628 self._makeDraggable(); 19629 } 19630 break; 19631 case "position": 19632 self._position(value); 19633 break; 19634 case "resizable": 19635 // currently resizable, becoming non-resizable 19636 var isResizable = uiDialog.is( ":data(resizable)" ); 19637 if (isResizable && !value) { 19638 uiDialog.resizable('destroy'); 19639 } 19640 19641 // currently resizable, changing handles 19642 if (isResizable && typeof value === 'string') { 19643 uiDialog.resizable('option', 'handles', value); 19644 } 19645 19646 // currently non-resizable, becoming resizable 19647 if (!isResizable && value !== false) { 19648 self._makeResizable(value); 19649 } 19650 break; 19651 case "title": 19652 // convert whatever was passed in o a string, for html() to not throw up 19653 $(".ui-dialog-title", self.uiDialogTitlebar).html("" + (value || ' ')); 19654 break; 19655 } 19656 19657 $.Widget.prototype._setOption.apply(self, arguments); 19658 }, 19659 19660 _size: function() { 19661 /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content 19662 * divs will both have width and height set, so we need to reset them 19663 */ 19664 var options = this.options, 19665 nonContentHeight, 19666 minContentHeight, 19667 isVisible = this.uiDialog.is( ":visible" ); 19668 19669 // reset content sizing 19670 this.element.show().css({ 19671 width: 'auto', 19672 minHeight: 0, 19673 height: 0 19674 }); 19675 19676 if (options.minWidth > options.width) { 19677 options.width = options.minWidth; 19678 } 19679 19680 // reset wrapper sizing 19681 // determine the height of all the non-content elements 19682 nonContentHeight = this.uiDialog.css({ 19683 height: 'auto', 19684 width: options.width 19685 }) 19686 .height(); 19687 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); 19688 19689 if ( options.height === "auto" ) { 19690 // only needed for IE6 support 19691 if ( $.support.minHeight ) { 19692 this.element.css({ 19693 minHeight: minContentHeight, 19694 height: "auto" 19695 }); 19696 } else { 19697 this.uiDialog.show(); 19698 var autoHeight = this.element.css( "height", "auto" ).height(); 19699 if ( !isVisible ) { 19700 this.uiDialog.hide(); 19701 } 19702 this.element.height( Math.max( autoHeight, minContentHeight ) ); 19703 } 19704 } else { 19705 this.element.height( Math.max( options.height - nonContentHeight, 0 ) ); 19706 } 19707 19708 if (this.uiDialog.is(':data(resizable)')) { 19709 this.uiDialog.resizable('option', 'minHeight', this._minHeight()); 19710 } 19711 } 19712}); 19713 19714$.extend($.ui.dialog, { 19715 version: "1.8.16", 19716 19717 uuid: 0, 19718 maxZ: 0, 19719 19720 getTitleId: function($el) { 19721 var id = $el.attr('id'); 19722 if (!id) { 19723 this.uuid += 1; 19724 id = this.uuid; 19725 } 19726 return 'ui-dialog-title-' + id; 19727 }, 19728 19729 overlay: function(dialog) { 19730 this.$el = $.ui.dialog.overlay.create(dialog); 19731 } 19732}); 19733 19734$.extend($.ui.dialog.overlay, { 19735 instances: [], 19736 // reuse old instances due to IE memory leak with alpha transparency (see #5185) 19737 oldInstances: [], 19738 maxZ: 0, 19739 events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','), 19740 function(event) { return event + '.dialog-overlay'; }).join(' '), 19741 create: function(dialog) { 19742 if (this.instances.length === 0) { 19743 // prevent use of anchors and inputs 19744 // we use a setTimeout in case the overlay is created from an 19745 // event that we're going to be cancelling (see #2804) 19746 setTimeout(function() { 19747 // handle $(el).dialog().dialog('close') (see #4065) 19748 if ($.ui.dialog.overlay.instances.length) { 19749 $(document).bind($.ui.dialog.overlay.events, function(event) { 19750 // stop events if the z-index of the target is < the z-index of the overlay 19751 // we cannot return true when we don't want to cancel the event (#3523) 19752 if ($(event.target).zIndex() < $.ui.dialog.overlay.maxZ) { 19753 return false; 19754 } 19755 }); 19756 } 19757 }, 1); 19758 19759 // allow closing by pressing the escape key 19760 $(document).bind('keydown.dialog-overlay', function(event) { 19761 if (dialog.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && 19762 event.keyCode === $.ui.keyCode.ESCAPE) { 19763 19764 dialog.close(event); 19765 event.preventDefault(); 19766 } 19767 }); 19768 19769 // handle window resize 19770 $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize); 19771 } 19772 19773 var $el = (this.oldInstances.pop() || $('<div></div>').addClass('ui-widget-overlay')) 19774 .appendTo(document.body) 19775 .css({ 19776 width: this.width(), 19777 height: this.height() 19778 }); 19779 19780 if ($.fn.bgiframe) { 19781 $el.bgiframe(); 19782 } 19783 19784 this.instances.push($el); 19785 return $el; 19786 }, 19787 19788 destroy: function($el) { 19789 var indexOf = $.inArray($el, this.instances); 19790 if (indexOf != -1){ 19791 this.oldInstances.push(this.instances.splice(indexOf, 1)[0]); 19792 } 19793 19794 if (this.instances.length === 0) { 19795 $([document, window]).unbind('.dialog-overlay'); 19796 } 19797 19798 $el.remove(); 19799 19800 // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) 19801 var maxZ = 0; 19802 $.each(this.instances, function() { 19803 maxZ = Math.max(maxZ, this.css('z-index')); 19804 }); 19805 this.maxZ = maxZ; 19806 }, 19807 19808 height: function() { 19809 var scrollHeight, 19810 offsetHeight; 19811 // handle IE 6 19812 if ($.browser.msie && $.browser.version < 7) { 19813 scrollHeight = Math.max( 19814 document.documentElement.scrollHeight, 19815 document.body.scrollHeight 19816 ); 19817 offsetHeight = Math.max( 19818 document.documentElement.offsetHeight, 19819 document.body.offsetHeight 19820 ); 19821 19822 if (scrollHeight < offsetHeight) { 19823 return $(window).height() + 'px'; 19824 } else { 19825 return scrollHeight + 'px'; 19826 } 19827 // handle "good" browsers 19828 } else { 19829 return $(document).height() + 'px'; 19830 } 19831 }, 19832 19833 width: function() { 19834 var scrollWidth, 19835 offsetWidth; 19836 // handle IE 19837 if ( $.browser.msie ) { 19838 scrollWidth = Math.max( 19839 document.documentElement.scrollWidth, 19840 document.body.scrollWidth 19841 ); 19842 offsetWidth = Math.max( 19843 document.documentElement.offsetWidth, 19844 document.body.offsetWidth 19845 ); 19846 19847 if (scrollWidth < offsetWidth) { 19848 return $(window).width() + 'px'; 19849 } else { 19850 return scrollWidth + 'px'; 19851 } 19852 // handle "good" browsers 19853 } else { 19854 return $(document).width() + 'px'; 19855 } 19856 }, 19857 19858 resize: function() { 19859 /* If the dialog is draggable and the user drags it past the 19860 * right edge of the window, the document becomes wider so we 19861 * need to stretch the overlay. If the user then drags the 19862 * dialog back to the left, the document will become narrower, 19863 * so we need to shrink the overlay to the appropriate size. 19864 * This is handled by shrinking the overlay before setting it 19865 * to the full document size. 19866 */ 19867 var $overlays = $([]); 19868 $.each($.ui.dialog.overlay.instances, function() { 19869 $overlays = $overlays.add(this); 19870 }); 19871 19872 $overlays.css({ 19873 width: 0, 19874 height: 0 19875 }).css({ 19876 width: $.ui.dialog.overlay.width(), 19877 height: $.ui.dialog.overlay.height() 19878 }); 19879 } 19880}); 19881 19882$.extend($.ui.dialog.overlay.prototype, { 19883 destroy: function() { 19884 $.ui.dialog.overlay.destroy(this.$el); 19885 } 19886}); 19887 19888}(jQuery)); 19889/* 19890 * jQuery UI Position 1.8.16 19891 * 19892 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 19893 * Dual licensed under the MIT or GPL Version 2 licenses. 19894 * http://jquery.org/license 19895 * 19896 * http://docs.jquery.com/UI/Position 19897 */ 19898(function( $, undefined ) { 19899 19900$.ui = $.ui || {}; 19901 19902var horizontalPositions = /left|center|right/, 19903 verticalPositions = /top|center|bottom/, 19904 center = "center", 19905 _position = $.fn.position, 19906 _offset = $.fn.offset; 19907 19908$.fn.position = function( options ) { 19909 if ( !options || !options.of ) { 19910 return _position.apply( this, arguments ); 19911 } 19912 19913 // make a copy, we don't want to modify arguments 19914 options = $.extend( {}, options ); 19915 19916 var target = $( options.of ), 19917 targetElem = target[0], 19918 collision = ( options.collision || "flip" ).split( " " ), 19919 offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ], 19920 targetWidth, 19921 targetHeight, 19922 basePosition; 19923 19924 if ( targetElem.nodeType === 9 ) { 19925 targetWidth = target.width(); 19926 targetHeight = target.height(); 19927 basePosition = { top: 0, left: 0 }; 19928 // TODO: use $.isWindow() in 1.9 19929 } else if ( targetElem.setTimeout ) { 19930 targetWidth = target.width(); 19931 targetHeight = target.height(); 19932 basePosition = { top: target.scrollTop(), left: target.scrollLeft() }; 19933 } else if ( targetElem.preventDefault ) { 19934 // force left top to allow flipping 19935 options.at = "left top"; 19936 targetWidth = targetHeight = 0; 19937 basePosition = { top: options.of.pageY, left: options.of.pageX }; 19938 } else { 19939 targetWidth = target.outerWidth(); 19940 targetHeight = target.outerHeight(); 19941 basePosition = target.offset(); 19942 } 19943 19944 // force my and at to have valid horizontal and veritcal positions 19945 // if a value is missing or invalid, it will be converted to center 19946 $.each( [ "my", "at" ], function() { 19947 var pos = ( options[this] || "" ).split( " " ); 19948 if ( pos.length === 1) { 19949 pos = horizontalPositions.test( pos[0] ) ? 19950 pos.concat( [center] ) : 19951 verticalPositions.test( pos[0] ) ? 19952 [ center ].concat( pos ) : 19953 [ center, center ]; 19954 } 19955 pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : center; 19956 pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : center; 19957 options[ this ] = pos; 19958 }); 19959 19960 // normalize collision option 19961 if ( collision.length === 1 ) { 19962 collision[ 1 ] = collision[ 0 ]; 19963 } 19964 19965 // normalize offset option 19966 offset[ 0 ] = parseInt( offset[0], 10 ) || 0; 19967 if ( offset.length === 1 ) { 19968 offset[ 1 ] = offset[ 0 ]; 19969 } 19970 offset[ 1 ] = parseInt( offset[1], 10 ) || 0; 19971 19972 if ( options.at[0] === "right" ) { 19973 basePosition.left += targetWidth; 19974 } else if ( options.at[0] === center ) { 19975 basePosition.left += targetWidth / 2; 19976 } 19977 19978 if ( options.at[1] === "bottom" ) { 19979 basePosition.top += targetHeight; 19980 } else if ( options.at[1] === center ) { 19981 basePosition.top += targetHeight / 2; 19982 } 19983 19984 basePosition.left += offset[ 0 ]; 19985 basePosition.top += offset[ 1 ]; 19986 19987 return this.each(function() { 19988 var elem = $( this ), 19989 elemWidth = elem.outerWidth(), 19990 elemHeight = elem.outerHeight(), 19991 marginLeft = parseInt( $.curCSS( this, "marginLeft", true ) ) || 0, 19992 marginTop = parseInt( $.curCSS( this, "marginTop", true ) ) || 0, 19993 collisionWidth = elemWidth + marginLeft + 19994 ( parseInt( $.curCSS( this, "marginRight", true ) ) || 0 ), 19995 collisionHeight = elemHeight + marginTop + 19996 ( parseInt( $.curCSS( this, "marginBottom", true ) ) || 0 ), 19997 position = $.extend( {}, basePosition ), 19998 collisionPosition; 19999 20000 if ( options.my[0] === "right" ) { 20001 position.left -= elemWidth; 20002 } else if ( options.my[0] === center ) { 20003 position.left -= elemWidth / 2; 20004 } 20005 20006 if ( options.my[1] === "bottom" ) { 20007 position.top -= elemHeight; 20008 } else if ( options.my[1] === center ) { 20009 position.top -= elemHeight / 2; 20010 } 20011 20012 // prevent fractions (see #5280) 20013 position.left = Math.round( position.left ); 20014 position.top = Math.round( position.top ); 20015 20016 collisionPosition = { 20017 left: position.left - marginLeft, 20018 top: position.top - marginTop 20019 }; 20020 20021 $.each( [ "left", "top" ], function( i, dir ) { 20022 if ( $.ui.position[ collision[i] ] ) { 20023 $.ui.position[ collision[i] ][ dir ]( position, { 20024 targetWidth: targetWidth, 20025 targetHeight: targetHeight, 20026 elemWidth: elemWidth, 20027 elemHeight: elemHeight, 20028 collisionPosition: collisionPosition, 20029 collisionWidth: collisionWidth, 20030 collisionHeight: collisionHeight, 20031 offset: offset, 20032 my: options.my, 20033 at: options.at 20034 }); 20035 } 20036 }); 20037 20038 if ( $.fn.bgiframe ) { 20039 elem.bgiframe(); 20040 } 20041 elem.offset( $.extend( position, { using: options.using } ) ); 20042 }); 20043}; 20044 20045$.ui.position = { 20046 fit: { 20047 left: function( position, data ) { 20048 var win = $( window ), 20049 over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(); 20050 position.left = over > 0 ? position.left - over : Math.max( position.left - data.collisionPosition.left, position.left ); 20051 }, 20052 top: function( position, data ) { 20053 var win = $( window ), 20054 over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(); 20055 position.top = over > 0 ? position.top - over : Math.max( position.top - data.collisionPosition.top, position.top ); 20056 } 20057 }, 20058 20059 flip: { 20060 left: function( position, data ) { 20061 if ( data.at[0] === center ) { 20062 return; 20063 } 20064 var win = $( window ), 20065 over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(), 20066 myOffset = data.my[ 0 ] === "left" ? 20067 -data.elemWidth : 20068 data.my[ 0 ] === "right" ? 20069 data.elemWidth : 20070 0, 20071 atOffset = data.at[ 0 ] === "left" ? 20072 data.targetWidth : 20073 -data.targetWidth, 20074 offset = -2 * data.offset[ 0 ]; 20075 position.left += data.collisionPosition.left < 0 ? 20076 myOffset + atOffset + offset : 20077 over > 0 ? 20078 myOffset + atOffset + offset : 20079 0; 20080 }, 20081 top: function( position, data ) { 20082 if ( data.at[1] === center ) { 20083 return; 20084 } 20085 var win = $( window ), 20086 over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(), 20087 myOffset = data.my[ 1 ] === "top" ? 20088 -data.elemHeight : 20089 data.my[ 1 ] === "bottom" ? 20090 data.elemHeight : 20091 0, 20092 atOffset = data.at[ 1 ] === "top" ? 20093 data.targetHeight : 20094 -data.targetHeight, 20095 offset = -2 * data.offset[ 1 ]; 20096 position.top += data.collisionPosition.top < 0 ? 20097 myOffset + atOffset + offset : 20098 over > 0 ? 20099 myOffset + atOffset + offset : 20100 0; 20101 } 20102 } 20103}; 20104 20105// offset setter from jQuery 1.4 20106if ( !$.offset.setOffset ) { 20107 $.offset.setOffset = function( elem, options ) { 20108 // set position first, in-case top/left are set even on static elem 20109 if ( /static/.test( $.curCSS( elem, "position" ) ) ) { 20110 elem.style.position = "relative"; 20111 } 20112 var curElem = $( elem ), 20113 curOffset = curElem.offset(), 20114 curTop = parseInt( $.curCSS( elem, "top", true ), 10 ) || 0, 20115 curLeft = parseInt( $.curCSS( elem, "left", true ), 10) || 0, 20116 props = { 20117 top: (options.top - curOffset.top) + curTop, 20118 left: (options.left - curOffset.left) + curLeft 20119 }; 20120 20121 if ( 'using' in options ) { 20122 options.using.call( elem, props ); 20123 } else { 20124 curElem.css( props ); 20125 } 20126 }; 20127 20128 $.fn.offset = function( options ) { 20129 var elem = this[ 0 ]; 20130 if ( !elem || !elem.ownerDocument ) { return null; } 20131 if ( options ) { 20132 return this.each(function() { 20133 $.offset.setOffset( this, options ); 20134 }); 20135 } 20136 return _offset.call( this ); 20137 }; 20138} 20139 20140}( jQuery )); 20141/* 20142 * jQuery UI Progressbar 1.8.16 20143 * 20144 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 20145 * Dual licensed under the MIT or GPL Version 2 licenses. 20146 * http://jquery.org/license 20147 * 20148 * http://docs.jquery.com/UI/Progressbar 20149 * 20150 * Depends: 20151 * jquery.ui.core.js 20152 * jquery.ui.widget.js 20153 */ 20154(function( $, undefined ) { 20155 20156$.widget( "ui.progressbar", { 20157 options: { 20158 value: 0, 20159 max: 100 20160 }, 20161 20162 min: 0, 20163 20164 _create: function() { 20165 this.element 20166 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) 20167 .attr({ 20168 role: "progressbar", 20169 "aria-valuemin": this.min, 20170 "aria-valuemax": this.options.max, 20171 "aria-valuenow": this._value() 20172 }); 20173 20174 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" ) 20175 .appendTo( this.element ); 20176 20177 this.oldValue = this._value(); 20178 this._refreshValue(); 20179 }, 20180 20181 destroy: function() { 20182 this.element 20183 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) 20184 .removeAttr( "role" ) 20185 .removeAttr( "aria-valuemin" ) 20186 .removeAttr( "aria-valuemax" ) 20187 .removeAttr( "aria-valuenow" ); 20188 20189 this.valueDiv.remove(); 20190 20191 $.Widget.prototype.destroy.apply( this, arguments ); 20192 }, 20193 20194 value: function( newValue ) { 20195 if ( newValue === undefined ) { 20196 return this._value(); 20197 } 20198 20199 this._setOption( "value", newValue ); 20200 return this; 20201 }, 20202 20203 _setOption: function( key, value ) { 20204 if ( key === "value" ) { 20205 this.options.value = value; 20206 this._refreshValue(); 20207 if ( this._value() === this.options.max ) { 20208 this._trigger( "complete" ); 20209 } 20210 } 20211 20212 $.Widget.prototype._setOption.apply( this, arguments ); 20213 }, 20214 20215 _value: function() { 20216 var val = this.options.value; 20217 // normalize invalid value 20218 if ( typeof val !== "number" ) { 20219 val = 0; 20220 } 20221 return Math.min( this.options.max, Math.max( this.min, val ) ); 20222 }, 20223 20224 _percentage: function() { 20225 return 100 * this._value() / this.options.max; 20226 }, 20227 20228 _refreshValue: function() { 20229 var value = this.value(); 20230 var percentage = this._percentage(); 20231 20232 if ( this.oldValue !== value ) { 20233 this.oldValue = value; 20234 this._trigger( "change" ); 20235 } 20236 20237 this.valueDiv 20238 .toggle( value > this.min ) 20239 .toggleClass( "ui-corner-right", value === this.options.max ) 20240 .width( percentage.toFixed(0) + "%" ); 20241 this.element.attr( "aria-valuenow", value ); 20242 } 20243}); 20244 20245$.extend( $.ui.progressbar, { 20246 version: "1.8.16" 20247}); 20248 20249})( jQuery ); 20250/* 20251 * jQuery UI Slider 1.8.16 20252 * 20253 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 20254 * Dual licensed under the MIT or GPL Version 2 licenses. 20255 * http://jquery.org/license 20256 * 20257 * http://docs.jquery.com/UI/Slider 20258 * 20259 * Depends: 20260 * jquery.ui.core.js 20261 * jquery.ui.mouse.js 20262 * jquery.ui.widget.js 20263 */ 20264(function( $, undefined ) { 20265 20266// number of pages in a slider 20267// (how many times can you page up/down to go through the whole range) 20268var numPages = 5; 20269 20270$.widget( "ui.slider", $.ui.mouse, { 20271 20272 widgetEventPrefix: "slide", 20273 20274 options: { 20275 animate: false, 20276 distance: 0, 20277 max: 100, 20278 min: 0, 20279 orientation: "horizontal", 20280 range: false, 20281 step: 1, 20282 value: 0, 20283 values: null 20284 }, 20285 20286 _create: function() { 20287 var self = this, 20288 o = this.options, 20289 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ), 20290 handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>", 20291 handleCount = ( o.values && o.values.length ) || 1, 20292 handles = []; 20293 20294 this._keySliding = false; 20295 this._mouseSliding = false; 20296 this._animateOff = true; 20297 this._handleIndex = null; 20298 this._detectOrientation(); 20299 this._mouseInit(); 20300 20301 this.element 20302 .addClass( "ui-slider" + 20303 " ui-slider-" + this.orientation + 20304 " ui-widget" + 20305 " ui-widget-content" + 20306 " ui-corner-all" + 20307 ( o.disabled ? " ui-slider-disabled ui-disabled" : "" ) ); 20308 20309 this.range = $([]); 20310 20311 if ( o.range ) { 20312 if ( o.range === true ) { 20313 if ( !o.values ) { 20314 o.values = [ this._valueMin(), this._valueMin() ]; 20315 } 20316 if ( o.values.length && o.values.length !== 2 ) { 20317 o.values = [ o.values[0], o.values[0] ]; 20318 } 20319 } 20320 20321 this.range = $( "<div></div>" ) 20322 .appendTo( this.element ) 20323 .addClass( "ui-slider-range" + 20324 // note: this isn't the most fittingly semantic framework class for this element, 20325 // but worked best visually with a variety of themes 20326 " ui-widget-header" + 20327 ( ( o.range === "min" || o.range === "max" ) ? " ui-slider-range-" + o.range : "" ) ); 20328 } 20329 20330 for ( var i = existingHandles.length; i < handleCount; i += 1 ) { 20331 handles.push( handle ); 20332 } 20333 20334 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( self.element ) ); 20335 20336 this.handle = this.handles.eq( 0 ); 20337 20338 this.handles.add( this.range ).filter( "a" ) 20339 .click(function( event ) { 20340 event.preventDefault(); 20341 }) 20342 .hover(function() { 20343 if ( !o.disabled ) { 20344 $( this ).addClass( "ui-state-hover" ); 20345 } 20346 }, function() { 20347 $( this ).removeClass( "ui-state-hover" ); 20348 }) 20349 .focus(function() { 20350 if ( !o.disabled ) { 20351 $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" ); 20352 $( this ).addClass( "ui-state-focus" ); 20353 } else { 20354 $( this ).blur(); 20355 } 20356 }) 20357 .blur(function() { 20358 $( this ).removeClass( "ui-state-focus" ); 20359 }); 20360 20361 this.handles.each(function( i ) { 20362 $( this ).data( "index.ui-slider-handle", i ); 20363 }); 20364 20365 this.handles 20366 .keydown(function( event ) { 20367 var ret = true, 20368 index = $( this ).data( "index.ui-slider-handle" ), 20369 allowed, 20370 curVal, 20371 newVal, 20372 step; 20373 20374 if ( self.options.disabled ) { 20375 return; 20376 } 20377 20378 switch ( event.keyCode ) { 20379 case $.ui.keyCode.HOME: 20380 case $.ui.keyCode.END: 20381 case $.ui.keyCode.PAGE_UP: 20382 case $.ui.keyCode.PAGE_DOWN: 20383 case $.ui.keyCode.UP: 20384 case $.ui.keyCode.RIGHT: 20385 case $.ui.keyCode.DOWN: 20386 case $.ui.keyCode.LEFT: 20387 ret = false; 20388 if ( !self._keySliding ) { 20389 self._keySliding = true; 20390 $( this ).addClass( "ui-state-active" ); 20391 allowed = self._start( event, index ); 20392 if ( allowed === false ) { 20393 return; 20394 } 20395 } 20396 break; 20397 } 20398 20399 step = self.options.step; 20400 if ( self.options.values && self.options.values.length ) { 20401 curVal = newVal = self.values( index ); 20402 } else { 20403 curVal = newVal = self.value(); 20404 } 20405 20406 switch ( event.keyCode ) { 20407 case $.ui.keyCode.HOME: 20408 newVal = self._valueMin(); 20409 break; 20410 case $.ui.keyCode.END: 20411 newVal = self._valueMax(); 20412 break; 20413 case $.ui.keyCode.PAGE_UP: 20414 newVal = self._trimAlignValue( curVal + ( (self._valueMax() - self._valueMin()) / numPages ) ); 20415 break; 20416 case $.ui.keyCode.PAGE_DOWN: 20417 newVal = self._trimAlignValue( curVal - ( (self._valueMax() - self._valueMin()) / numPages ) ); 20418 break; 20419 case $.ui.keyCode.UP: 20420 case $.ui.keyCode.RIGHT: 20421 if ( curVal === self._valueMax() ) { 20422 return; 20423 } 20424 newVal = self._trimAlignValue( curVal + step ); 20425 break; 20426 case $.ui.keyCode.DOWN: 20427 case $.ui.keyCode.LEFT: 20428 if ( curVal === self._valueMin() ) { 20429 return; 20430 } 20431 newVal = self._trimAlignValue( curVal - step ); 20432 break; 20433 } 20434 20435 self._slide( event, index, newVal ); 20436 20437 return ret; 20438 20439 }) 20440 .keyup(function( event ) { 20441 var index = $( this ).data( "index.ui-slider-handle" ); 20442 20443 if ( self._keySliding ) { 20444 self._keySliding = false; 20445 self._stop( event, index ); 20446 self._change( event, index ); 20447 $( this ).removeClass( "ui-state-active" ); 20448 } 20449 20450 }); 20451 20452 this._refreshValue(); 20453 20454 this._animateOff = false; 20455 }, 20456 20457 destroy: function() { 20458 this.handles.remove(); 20459 this.range.remove(); 20460 20461 this.element 20462 .removeClass( "ui-slider" + 20463 " ui-slider-horizontal" + 20464 " ui-slider-vertical" + 20465 " ui-slider-disabled" + 20466 " ui-widget" + 20467 " ui-widget-content" + 20468 " ui-corner-all" ) 20469 .removeData( "slider" ) 20470 .unbind( ".slider" ); 20471 20472 this._mouseDestroy(); 20473 20474 return this; 20475 }, 20476 20477 _mouseCapture: function( event ) { 20478 var o = this.options, 20479 position, 20480 normValue, 20481 distance, 20482 closestHandle, 20483 self, 20484 index, 20485 allowed, 20486 offset, 20487 mouseOverHandle; 20488 20489 if ( o.disabled ) { 20490 return false; 20491 } 20492 20493 this.elementSize = { 20494 width: this.element.outerWidth(), 20495 height: this.element.outerHeight() 20496 }; 20497 this.elementOffset = this.element.offset(); 20498 20499 position = { x: event.pageX, y: event.pageY }; 20500 normValue = this._normValueFromMouse( position ); 20501 distance = this._valueMax() - this._valueMin() + 1; 20502 self = this; 20503 this.handles.each(function( i ) { 20504 var thisDistance = Math.abs( normValue - self.values(i) ); 20505 if ( distance > thisDistance ) { 20506 distance = thisDistance; 20507 closestHandle = $( this ); 20508 index = i; 20509 } 20510 }); 20511 20512 // workaround for bug #3736 (if both handles of a range are at 0, 20513 // the first is always used as the one with least distance, 20514 // and moving it is obviously prevented by preventing negative ranges) 20515 if( o.range === true && this.values(1) === o.min ) { 20516 index += 1; 20517 closestHandle = $( this.handles[index] ); 20518 } 20519 20520 allowed = this._start( event, index ); 20521 if ( allowed === false ) { 20522 return false; 20523 } 20524 this._mouseSliding = true; 20525 20526 self._handleIndex = index; 20527 20528 closestHandle 20529 .addClass( "ui-state-active" ) 20530 .focus(); 20531 20532 offset = closestHandle.offset(); 20533 mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" ); 20534 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { 20535 left: event.pageX - offset.left - ( closestHandle.width() / 2 ), 20536 top: event.pageY - offset.top - 20537 ( closestHandle.height() / 2 ) - 20538 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) - 20539 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) + 20540 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0) 20541 }; 20542 20543 if ( !this.handles.hasClass( "ui-state-hover" ) ) { 20544 this._slide( event, index, normValue ); 20545 } 20546 this._animateOff = true; 20547 return true; 20548 }, 20549 20550 _mouseStart: function( event ) { 20551 return true; 20552 }, 20553 20554 _mouseDrag: function( event ) { 20555 var position = { x: event.pageX, y: event.pageY }, 20556 normValue = this._normValueFromMouse( position ); 20557 20558 this._slide( event, this._handleIndex, normValue ); 20559 20560 return false; 20561 }, 20562 20563 _mouseStop: function( event ) { 20564 this.handles.removeClass( "ui-state-active" ); 20565 this._mouseSliding = false; 20566 20567 this._stop( event, this._handleIndex ); 20568 this._change( event, this._handleIndex ); 20569 20570 this._handleIndex = null; 20571 this._clickOffset = null; 20572 this._animateOff = false; 20573 20574 return false; 20575 }, 20576 20577 _detectOrientation: function() { 20578 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; 20579 }, 20580 20581 _normValueFromMouse: function( position ) { 20582 var pixelTotal, 20583 pixelMouse, 20584 percentMouse, 20585 valueTotal, 20586 valueMouse; 20587 20588 if ( this.orientation === "horizontal" ) { 20589 pixelTotal = this.elementSize.width; 20590 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 ); 20591 } else { 20592 pixelTotal = this.elementSize.height; 20593 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 ); 20594 } 20595 20596 percentMouse = ( pixelMouse / pixelTotal ); 20597 if ( percentMouse > 1 ) { 20598 percentMouse = 1; 20599 } 20600 if ( percentMouse < 0 ) { 20601 percentMouse = 0; 20602 } 20603 if ( this.orientation === "vertical" ) { 20604 percentMouse = 1 - percentMouse; 20605 } 20606 20607 valueTotal = this._valueMax() - this._valueMin(); 20608 valueMouse = this._valueMin() + percentMouse * valueTotal; 20609 20610 return this._trimAlignValue( valueMouse ); 20611 }, 20612 20613 _start: function( event, index ) { 20614 var uiHash = { 20615 handle: this.handles[ index ], 20616 value: this.value() 20617 }; 20618 if ( this.options.values && this.options.values.length ) { 20619 uiHash.value = this.values( index ); 20620 uiHash.values = this.values(); 20621 } 20622 return this._trigger( "start", event, uiHash ); 20623 }, 20624 20625 _slide: function( event, index, newVal ) { 20626 var otherVal, 20627 newValues, 20628 allowed; 20629 20630 if ( this.options.values && this.options.values.length ) { 20631 otherVal = this.values( index ? 0 : 1 ); 20632 20633 if ( ( this.options.values.length === 2 && this.options.range === true ) && 20634 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) ) 20635 ) { 20636 newVal = otherVal; 20637 } 20638 20639 if ( newVal !== this.values( index ) ) { 20640 newValues = this.values(); 20641 newValues[ index ] = newVal; 20642 // A slide can be canceled by returning false from the slide callback 20643 allowed = this._trigger( "slide", event, { 20644 handle: this.handles[ index ], 20645 value: newVal, 20646 values: newValues 20647 } ); 20648 otherVal = this.values( index ? 0 : 1 ); 20649 if ( allowed !== false ) { 20650 this.values( index, newVal, true ); 20651 } 20652 } 20653 } else { 20654 if ( newVal !== this.value() ) { 20655 // A slide can be canceled by returning false from the slide callback 20656 allowed = this._trigger( "slide", event, { 20657 handle: this.handles[ index ], 20658 value: newVal 20659 } ); 20660 if ( allowed !== false ) { 20661 this.value( newVal ); 20662 } 20663 } 20664 } 20665 }, 20666 20667 _stop: function( event, index ) { 20668 var uiHash = { 20669 handle: this.handles[ index ], 20670 value: this.value() 20671 }; 20672 if ( this.options.values && this.options.values.length ) { 20673 uiHash.value = this.values( index ); 20674 uiHash.values = this.values(); 20675 } 20676 20677 this._trigger( "stop", event, uiHash ); 20678 }, 20679 20680 _change: function( event, index ) { 20681 if ( !this._keySliding && !this._mouseSliding ) { 20682 var uiHash = { 20683 handle: this.handles[ index ], 20684 value: this.value() 20685 }; 20686 if ( this.options.values && this.options.values.length ) { 20687 uiHash.value = this.values( index ); 20688 uiHash.values = this.values(); 20689 } 20690 20691 this._trigger( "change", event, uiHash ); 20692 } 20693 }, 20694 20695 value: function( newValue ) { 20696 if ( arguments.length ) { 20697 this.options.value = this._trimAlignValue( newValue ); 20698 this._refreshValue(); 20699 this._change( null, 0 ); 20700 return; 20701 } 20702 20703 return this._value(); 20704 }, 20705 20706 values: function( index, newValue ) { 20707 var vals, 20708 newValues, 20709 i; 20710 20711 if ( arguments.length > 1 ) { 20712 this.options.values[ index ] = this._trimAlignValue( newValue ); 20713 this._refreshValue(); 20714 this._change( null, index ); 20715 return; 20716 } 20717 20718 if ( arguments.length ) { 20719 if ( $.isArray( arguments[ 0 ] ) ) { 20720 vals = this.options.values; 20721 newValues = arguments[ 0 ]; 20722 for ( i = 0; i < vals.length; i += 1 ) { 20723 vals[ i ] = this._trimAlignValue( newValues[ i ] ); 20724 this._change( null, i ); 20725 } 20726 this._refreshValue(); 20727 } else { 20728 if ( this.options.values && this.options.values.length ) { 20729 return this._values( index ); 20730 } else { 20731 return this.value(); 20732 } 20733 } 20734 } else { 20735 return this._values(); 20736 } 20737 }, 20738 20739 _setOption: function( key, value ) { 20740 var i, 20741 valsLength = 0; 20742 20743 if ( $.isArray( this.options.values ) ) { 20744 valsLength = this.options.values.length; 20745 } 20746 20747 $.Widget.prototype._setOption.apply( this, arguments ); 20748 20749 switch ( key ) { 20750 case "disabled": 20751 if ( value ) { 20752 this.handles.filter( ".ui-state-focus" ).blur(); 20753 this.handles.removeClass( "ui-state-hover" ); 20754 this.handles.propAttr( "disabled", true ); 20755 this.element.addClass( "ui-disabled" ); 20756 } else { 20757 this.handles.propAttr( "disabled", false ); 20758 this.element.removeClass( "ui-disabled" ); 20759 } 20760 break; 20761 case "orientation": 20762 this._detectOrientation(); 20763 this.element 20764 .removeClass( "ui-slider-horizontal ui-slider-vertical" ) 20765 .addClass( "ui-slider-" + this.orientation ); 20766 this._refreshValue(); 20767 break; 20768 case "value": 20769 this._animateOff = true; 20770 this._refreshValue(); 20771 this._change( null, 0 ); 20772 this._animateOff = false; 20773 break; 20774 case "values": 20775 this._animateOff = true; 20776 this._refreshValue(); 20777 for ( i = 0; i < valsLength; i += 1 ) { 20778 this._change( null, i ); 20779 } 20780 this._animateOff = false; 20781 break; 20782 } 20783 }, 20784 20785 //internal value getter 20786 // _value() returns value trimmed by min and max, aligned by step 20787 _value: function() { 20788 var val = this.options.value; 20789 val = this._trimAlignValue( val ); 20790 20791 return val; 20792 }, 20793 20794 //internal values getter 20795 // _values() returns array of values trimmed by min and max, aligned by step 20796 // _values( index ) returns single value trimmed by min and max, aligned by step 20797 _values: function( index ) { 20798 var val, 20799 vals, 20800 i; 20801 20802 if ( arguments.length ) { 20803 val = this.options.values[ index ]; 20804 val = this._trimAlignValue( val ); 20805 20806 return val; 20807 } else { 20808 // .slice() creates a copy of the array 20809 // this copy gets trimmed by min and max and then returned 20810 vals = this.options.values.slice(); 20811 for ( i = 0; i < vals.length; i+= 1) { 20812 vals[ i ] = this._trimAlignValue( vals[ i ] ); 20813 } 20814 20815 return vals; 20816 } 20817 }, 20818 20819 // returns the step-aligned value that val is closest to, between (inclusive) min and max 20820 _trimAlignValue: function( val ) { 20821 if ( val <= this._valueMin() ) { 20822 return this._valueMin(); 20823 } 20824 if ( val >= this._valueMax() ) { 20825 return this._valueMax(); 20826 } 20827 var step = ( this.options.step > 0 ) ? this.options.step : 1, 20828 valModStep = (val - this._valueMin()) % step, 20829 alignValue = val - valModStep; 20830 20831 if ( Math.abs(valModStep) * 2 >= step ) { 20832 alignValue += ( valModStep > 0 ) ? step : ( -step ); 20833 } 20834 20835 // Since JavaScript has problems with large floats, round 20836 // the final value to 5 digits after the decimal point (see #4124) 20837 return parseFloat( alignValue.toFixed(5) ); 20838 }, 20839 20840 _valueMin: function() { 20841 return this.options.min; 20842 }, 20843 20844 _valueMax: function() { 20845 return this.options.max; 20846 }, 20847 20848 _refreshValue: function() { 20849 var oRange = this.options.range, 20850 o = this.options, 20851 self = this, 20852 animate = ( !this._animateOff ) ? o.animate : false, 20853 valPercent, 20854 _set = {}, 20855 lastValPercent, 20856 value, 20857 valueMin, 20858 valueMax; 20859 20860 if ( this.options.values && this.options.values.length ) { 20861 this.handles.each(function( i, j ) { 20862 valPercent = ( self.values(i) - self._valueMin() ) / ( self._valueMax() - self._valueMin() ) * 100; 20863 _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; 20864 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); 20865 if ( self.options.range === true ) { 20866 if ( self.orientation === "horizontal" ) { 20867 if ( i === 0 ) { 20868 self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate ); 20869 } 20870 if ( i === 1 ) { 20871 self.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); 20872 } 20873 } else { 20874 if ( i === 0 ) { 20875 self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate ); 20876 } 20877 if ( i === 1 ) { 20878 self.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); 20879 } 20880 } 20881 } 20882 lastValPercent = valPercent; 20883 }); 20884 } else { 20885 value = this.value(); 20886 valueMin = this._valueMin(); 20887 valueMax = this._valueMax(); 20888 valPercent = ( valueMax !== valueMin ) ? 20889 ( value - valueMin ) / ( valueMax - valueMin ) * 100 : 20890 0; 20891 _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; 20892 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); 20893 20894 if ( oRange === "min" && this.orientation === "horizontal" ) { 20895 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate ); 20896 } 20897 if ( oRange === "max" && this.orientation === "horizontal" ) { 20898 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); 20899 } 20900 if ( oRange === "min" && this.orientation === "vertical" ) { 20901 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate ); 20902 } 20903 if ( oRange === "max" && this.orientation === "vertical" ) { 20904 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); 20905 } 20906 } 20907 } 20908 20909}); 20910 20911$.extend( $.ui.slider, { 20912 version: "1.8.16" 20913}); 20914 20915}(jQuery)); 20916/* 20917 * jQuery UI Tabs 1.8.16 20918 * 20919 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 20920 * Dual licensed under the MIT or GPL Version 2 licenses. 20921 * http://jquery.org/license 20922 * 20923 * http://docs.jquery.com/UI/Tabs 20924 * 20925 * Depends: 20926 * jquery.ui.core.js 20927 * jquery.ui.widget.js 20928 */ 20929(function( $, undefined ) { 20930 20931var tabId = 0, 20932 listId = 0; 20933 20934function getNextTabId() { 20935 return ++tabId; 20936} 20937 20938function getNextListId() { 20939 return ++listId; 20940} 20941 20942$.widget( "ui.tabs", { 20943 options: { 20944 add: null, 20945 ajaxOptions: null, 20946 cache: false, 20947 cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } 20948 collapsible: false, 20949 disable: null, 20950 disabled: [], 20951 enable: null, 20952 event: "click", 20953 fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } 20954 idPrefix: "ui-tabs-", 20955 load: null, 20956 panelTemplate: "<div></div>", 20957 remove: null, 20958 select: null, 20959 show: null, 20960 spinner: "<em>Loading…</em>", 20961 tabTemplate: "<li><a href='#{href}'><span>#{label}</span></a></li>" 20962 }, 20963 20964 _create: function() { 20965 this._tabify( true ); 20966 }, 20967 20968 _setOption: function( key, value ) { 20969 if ( key == "selected" ) { 20970 if (this.options.collapsible && value == this.options.selected ) { 20971 return; 20972 } 20973 this.select( value ); 20974 } else { 20975 this.options[ key ] = value; 20976 this._tabify(); 20977 } 20978 }, 20979 20980 _tabId: function( a ) { 20981 return a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF-]/g, "" ) || 20982 this.options.idPrefix + getNextTabId(); 20983 }, 20984 20985 _sanitizeSelector: function( hash ) { 20986 // we need this because an id may contain a ":" 20987 return hash.replace( /:/g, "\\:" ); 20988 }, 20989 20990 _cookie: function() { 20991 var cookie = this.cookie || 20992 ( this.cookie = this.options.cookie.name || "ui-tabs-" + getNextListId() ); 20993 return $.cookie.apply( null, [ cookie ].concat( $.makeArray( arguments ) ) ); 20994 }, 20995 20996 _ui: function( tab, panel ) { 20997 return { 20998 tab: tab, 20999 panel: panel, 21000 index: this.anchors.index( tab ) 21001 }; 21002 }, 21003 21004 _cleanup: function() { 21005 // restore all former loading tabs labels 21006 this.lis.filter( ".ui-state-processing" ) 21007 .removeClass( "ui-state-processing" ) 21008 .find( "span:data(label.tabs)" ) 21009 .each(function() { 21010 var el = $( this ); 21011 el.html( el.data( "label.tabs" ) ).removeData( "label.tabs" ); 21012 }); 21013 }, 21014 21015 _tabify: function( init ) { 21016 var self = this, 21017 o = this.options, 21018 fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash 21019 21020 this.list = this.element.find( "ol,ul" ).eq( 0 ); 21021 this.lis = $( " > li:has(a[href])", this.list ); 21022 this.anchors = this.lis.map(function() { 21023 return $( "a", this )[ 0 ]; 21024 }); 21025 this.panels = $( [] ); 21026 21027 this.anchors.each(function( i, a ) { 21028 var href = $( a ).attr( "href" ); 21029 // For dynamically created HTML that contains a hash as href IE < 8 expands 21030 // such href to the full page url with hash and then misinterprets tab as ajax. 21031 // Same consideration applies for an added tab with a fragment identifier 21032 // since a[href=#fragment-identifier] does unexpectedly not match. 21033 // Thus normalize href attribute... 21034 var hrefBase = href.split( "#" )[ 0 ], 21035 baseEl; 21036 if ( hrefBase && ( hrefBase === location.toString().split( "#" )[ 0 ] || 21037 ( baseEl = $( "base" )[ 0 ]) && hrefBase === baseEl.href ) ) { 21038 href = a.hash; 21039 a.href = href; 21040 } 21041 21042 // inline tab 21043 if ( fragmentId.test( href ) ) { 21044 self.panels = self.panels.add( self.element.find( self._sanitizeSelector( href ) ) ); 21045 // remote tab 21046 // prevent loading the page itself if href is just "#" 21047 } else if ( href && href !== "#" ) { 21048 // required for restore on destroy 21049 $.data( a, "href.tabs", href ); 21050 21051 // TODO until #3808 is fixed strip fragment identifier from url 21052 // (IE fails to load from such url) 21053 $.data( a, "load.tabs", href.replace( /#.*$/, "" ) ); 21054 21055 var id = self._tabId( a ); 21056 a.href = "#" + id; 21057 var $panel = self.element.find( "#" + id ); 21058 if ( !$panel.length ) { 21059 $panel = $( o.panelTemplate ) 21060 .attr( "id", id ) 21061 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) 21062 .insertAfter( self.panels[ i - 1 ] || self.list ); 21063 $panel.data( "destroy.tabs", true ); 21064 } 21065 self.panels = self.panels.add( $panel ); 21066 // invalid tab href 21067 } else { 21068 o.disabled.push( i ); 21069 } 21070 }); 21071 21072 // initialization from scratch 21073 if ( init ) { 21074 // attach necessary classes for styling 21075 this.element.addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ); 21076 this.list.addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ); 21077 this.lis.addClass( "ui-state-default ui-corner-top" ); 21078 this.panels.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ); 21079 21080 // Selected tab 21081 // use "selected" option or try to retrieve: 21082 // 1. from fragment identifier in url 21083 // 2. from cookie 21084 // 3. from selected class attribute on <li> 21085 if ( o.selected === undefined ) { 21086 if ( location.hash ) { 21087 this.anchors.each(function( i, a ) { 21088 if ( a.hash == location.hash ) { 21089 o.selected = i; 21090 return false; 21091 } 21092 }); 21093 } 21094 if ( typeof o.selected !== "number" && o.cookie ) { 21095 o.selected = parseInt( self._cookie(), 10 ); 21096 } 21097 if ( typeof o.selected !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) { 21098 o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); 21099 } 21100 o.selected = o.selected || ( this.lis.length ? 0 : -1 ); 21101 } else if ( o.selected === null ) { // usage of null is deprecated, TODO remove in next release 21102 o.selected = -1; 21103 } 21104 21105 // sanity check - default to first tab... 21106 o.selected = ( ( o.selected >= 0 && this.anchors[ o.selected ] ) || o.selected < 0 ) 21107 ? o.selected 21108 : 0; 21109 21110 // Take disabling tabs via class attribute from HTML 21111 // into account and update option properly. 21112 // A selected tab cannot become disabled. 21113 o.disabled = $.unique( o.disabled.concat( 21114 $.map( this.lis.filter( ".ui-state-disabled" ), function( n, i ) { 21115 return self.lis.index( n ); 21116 }) 21117 ) ).sort(); 21118 21119 if ( $.inArray( o.selected, o.disabled ) != -1 ) { 21120 o.disabled.splice( $.inArray( o.selected, o.disabled ), 1 ); 21121 } 21122 21123 // highlight selected tab 21124 this.panels.addClass( "ui-tabs-hide" ); 21125 this.lis.removeClass( "ui-tabs-selected ui-state-active" ); 21126 // check for length avoids error when initializing empty list 21127 if ( o.selected >= 0 && this.anchors.length ) { 21128 self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) ).removeClass( "ui-tabs-hide" ); 21129 this.lis.eq( o.selected ).addClass( "ui-tabs-selected ui-state-active" ); 21130 21131 // seems to be expected behavior that the show callback is fired 21132 self.element.queue( "tabs", function() { 21133 self._trigger( "show", null, 21134 self._ui( self.anchors[ o.selected ], self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) )[ 0 ] ) ); 21135 }); 21136 21137 this.load( o.selected ); 21138 } 21139 21140 // clean up to avoid memory leaks in certain versions of IE 6 21141 // TODO: namespace this event 21142 $( window ).bind( "unload", function() { 21143 self.lis.add( self.anchors ).unbind( ".tabs" ); 21144 self.lis = self.anchors = self.panels = null; 21145 }); 21146 // update selected after add/remove 21147 } else { 21148 o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); 21149 } 21150 21151 // update collapsible 21152 // TODO: use .toggleClass() 21153 this.element[ o.collapsible ? "addClass" : "removeClass" ]( "ui-tabs-collapsible" ); 21154 21155 // set or update cookie after init and add/remove respectively 21156 if ( o.cookie ) { 21157 this._cookie( o.selected, o.cookie ); 21158 } 21159 21160 // disable tabs 21161 for ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) { 21162 $( li )[ $.inArray( i, o.disabled ) != -1 && 21163 // TODO: use .toggleClass() 21164 !$( li ).hasClass( "ui-tabs-selected" ) ? "addClass" : "removeClass" ]( "ui-state-disabled" ); 21165 } 21166 21167 // reset cache if switching from cached to not cached 21168 if ( o.cache === false ) { 21169 this.anchors.removeData( "cache.tabs" ); 21170 } 21171 21172 // remove all handlers before, tabify may run on existing tabs after add or option change 21173 this.lis.add( this.anchors ).unbind( ".tabs" ); 21174 21175 if ( o.event !== "mouseover" ) { 21176 var addState = function( state, el ) { 21177 if ( el.is( ":not(.ui-state-disabled)" ) ) { 21178 el.addClass( "ui-state-" + state ); 21179 } 21180 }; 21181 var removeState = function( state, el ) { 21182 el.removeClass( "ui-state-" + state ); 21183 }; 21184 this.lis.bind( "mouseover.tabs" , function() { 21185 addState( "hover", $( this ) ); 21186 }); 21187 this.lis.bind( "mouseout.tabs", function() { 21188 removeState( "hover", $( this ) ); 21189 }); 21190 this.anchors.bind( "focus.tabs", function() { 21191 addState( "focus", $( this ).closest( "li" ) ); 21192 }); 21193 this.anchors.bind( "blur.tabs", function() { 21194 removeState( "focus", $( this ).closest( "li" ) ); 21195 }); 21196 } 21197 21198 // set up animations 21199 var hideFx, showFx; 21200 if ( o.fx ) { 21201 if ( $.isArray( o.fx ) ) { 21202 hideFx = o.fx[ 0 ]; 21203 showFx = o.fx[ 1 ]; 21204 } else { 21205 hideFx = showFx = o.fx; 21206 } 21207 } 21208 21209 // Reset certain styles left over from animation 21210 // and prevent IE's ClearType bug... 21211 function resetStyle( $el, fx ) { 21212 $el.css( "display", "" ); 21213 if ( !$.support.opacity && fx.opacity ) { 21214 $el[ 0 ].style.removeAttribute( "filter" ); 21215 } 21216 } 21217 21218 // Show a tab... 21219 var showTab = showFx 21220 ? function( clicked, $show ) { 21221 $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); 21222 $show.hide().removeClass( "ui-tabs-hide" ) // avoid flicker that way 21223 .animate( showFx, showFx.duration || "normal", function() { 21224 resetStyle( $show, showFx ); 21225 self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) ); 21226 }); 21227 } 21228 : function( clicked, $show ) { 21229 $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); 21230 $show.removeClass( "ui-tabs-hide" ); 21231 self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) ); 21232 }; 21233 21234 // Hide a tab, $show is optional... 21235 var hideTab = hideFx 21236 ? function( clicked, $hide ) { 21237 $hide.animate( hideFx, hideFx.duration || "normal", function() { 21238 self.lis.removeClass( "ui-tabs-selected ui-state-active" ); 21239 $hide.addClass( "ui-tabs-hide" ); 21240 resetStyle( $hide, hideFx ); 21241 self.element.dequeue( "tabs" ); 21242 }); 21243 } 21244 : function( clicked, $hide, $show ) { 21245 self.lis.removeClass( "ui-tabs-selected ui-state-active" ); 21246 $hide.addClass( "ui-tabs-hide" ); 21247 self.element.dequeue( "tabs" ); 21248 }; 21249 21250 // attach tab event handler, unbind to avoid duplicates from former tabifying... 21251 this.anchors.bind( o.event + ".tabs", function() { 21252 var el = this, 21253 $li = $(el).closest( "li" ), 21254 $hide = self.panels.filter( ":not(.ui-tabs-hide)" ), 21255 $show = self.element.find( self._sanitizeSelector( el.hash ) ); 21256 21257 // If tab is already selected and not collapsible or tab disabled or 21258 // or is already loading or click callback returns false stop here. 21259 // Check if click handler returns false last so that it is not executed 21260 // for a disabled or loading tab! 21261 if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible) || 21262 $li.hasClass( "ui-state-disabled" ) || 21263 $li.hasClass( "ui-state-processing" ) || 21264 self.panels.filter( ":animated" ).length || 21265 self._trigger( "select", null, self._ui( this, $show[ 0 ] ) ) === false ) { 21266 this.blur(); 21267 return false; 21268 } 21269 21270 o.selected = self.anchors.index( this ); 21271 21272 self.abort(); 21273 21274 // if tab may be closed 21275 if ( o.collapsible ) { 21276 if ( $li.hasClass( "ui-tabs-selected" ) ) { 21277 o.selected = -1; 21278 21279 if ( o.cookie ) { 21280 self._cookie( o.selected, o.cookie ); 21281 } 21282 21283 self.element.queue( "tabs", function() { 21284 hideTab( el, $hide ); 21285 }).dequeue( "tabs" ); 21286 21287 this.blur(); 21288 return false; 21289 } else if ( !$hide.length ) { 21290 if ( o.cookie ) { 21291 self._cookie( o.selected, o.cookie ); 21292 } 21293 21294 self.element.queue( "tabs", function() { 21295 showTab( el, $show ); 21296 }); 21297 21298 // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171 21299 self.load( self.anchors.index( this ) ); 21300 21301 this.blur(); 21302 return false; 21303 } 21304 } 21305 21306 if ( o.cookie ) { 21307 self._cookie( o.selected, o.cookie ); 21308 } 21309 21310 // show new tab 21311 if ( $show.length ) { 21312 if ( $hide.length ) { 21313 self.element.queue( "tabs", function() { 21314 hideTab( el, $hide ); 21315 }); 21316 } 21317 self.element.queue( "tabs", function() { 21318 showTab( el, $show ); 21319 }); 21320 21321 self.load( self.anchors.index( this ) ); 21322 } else { 21323 throw "jQuery UI Tabs: Mismatching fragment identifier."; 21324 } 21325 21326 // Prevent IE from keeping other link focussed when using the back button 21327 // and remove dotted border from clicked link. This is controlled via CSS 21328 // in modern browsers; blur() removes focus from address bar in Firefox 21329 // which can become a usability and annoying problem with tabs('rotate'). 21330 if ( $.browser.msie ) { 21331 this.blur(); 21332 } 21333 }); 21334 21335 // disable click in any case 21336 this.anchors.bind( "click.tabs", function(){ 21337 return false; 21338 }); 21339 }, 21340 21341 _getIndex: function( index ) { 21342 // meta-function to give users option to provide a href string instead of a numerical index. 21343 // also sanitizes numerical indexes to valid values. 21344 if ( typeof index == "string" ) { 21345 index = this.anchors.index( this.anchors.filter( "[href$=" + index + "]" ) ); 21346 } 21347 21348 return index; 21349 }, 21350 21351 destroy: function() { 21352 var o = this.options; 21353 21354 this.abort(); 21355 21356 this.element 21357 .unbind( ".tabs" ) 21358 .removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" ) 21359 .removeData( "tabs" ); 21360 21361 this.list.removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ); 21362 21363 this.anchors.each(function() { 21364 var href = $.data( this, "href.tabs" ); 21365 if ( href ) { 21366 this.href = href; 21367 } 21368 var $this = $( this ).unbind( ".tabs" ); 21369 $.each( [ "href", "load", "cache" ], function( i, prefix ) { 21370 $this.removeData( prefix + ".tabs" ); 21371 }); 21372 }); 21373 21374 this.lis.unbind( ".tabs" ).add( this.panels ).each(function() { 21375 if ( $.data( this, "destroy.tabs" ) ) { 21376 $( this ).remove(); 21377 } else { 21378 $( this ).removeClass([ 21379 "ui-state-default", 21380 "ui-corner-top", 21381 "ui-tabs-selected", 21382 "ui-state-active", 21383 "ui-state-hover", 21384 "ui-state-focus", 21385 "ui-state-disabled", 21386 "ui-tabs-panel", 21387 "ui-widget-content", 21388 "ui-corner-bottom", 21389 "ui-tabs-hide" 21390 ].join( " " ) ); 21391 } 21392 }); 21393 21394 if ( o.cookie ) { 21395 this._cookie( null, o.cookie ); 21396 } 21397 21398 return this; 21399 }, 21400 21401 add: function( url, label, index ) { 21402 if ( index === undefined ) { 21403 index = this.anchors.length; 21404 } 21405 21406 var self = this, 21407 o = this.options, 21408 $li = $( o.tabTemplate.replace( /#\{href\}/g, url ).replace( /#\{label\}/g, label ) ), 21409 id = !url.indexOf( "#" ) ? url.replace( "#", "" ) : this._tabId( $( "a", $li )[ 0 ] ); 21410 21411 $li.addClass( "ui-state-default ui-corner-top" ).data( "destroy.tabs", true ); 21412 21413 // try to find an existing element before creating a new one 21414 var $panel = self.element.find( "#" + id ); 21415 if ( !$panel.length ) { 21416 $panel = $( o.panelTemplate ) 21417 .attr( "id", id ) 21418 .data( "destroy.tabs", true ); 21419 } 21420 $panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide" ); 21421 21422 if ( index >= this.lis.length ) { 21423 $li.appendTo( this.list ); 21424 $panel.appendTo( this.list[ 0 ].parentNode ); 21425 } else { 21426 $li.insertBefore( this.lis[ index ] ); 21427 $panel.insertBefore( this.panels[ index ] ); 21428 } 21429 21430 o.disabled = $.map( o.disabled, function( n, i ) { 21431 return n >= index ? ++n : n; 21432 }); 21433 21434 this._tabify(); 21435 21436 if ( this.anchors.length == 1 ) { 21437 o.selected = 0; 21438 $li.addClass( "ui-tabs-selected ui-state-active" ); 21439 $panel.removeClass( "ui-tabs-hide" ); 21440 this.element.queue( "tabs", function() { 21441 self._trigger( "show", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) ); 21442 }); 21443 21444 this.load( 0 ); 21445 } 21446 21447 this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); 21448 return this; 21449 }, 21450 21451 remove: function( index ) { 21452 index = this._getIndex( index ); 21453 var o = this.options, 21454 $li = this.lis.eq( index ).remove(), 21455 $panel = this.panels.eq( index ).remove(); 21456 21457 // If selected tab was removed focus tab to the right or 21458 // in case the last tab was removed the tab to the left. 21459 if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) { 21460 this.select( index + ( index + 1 < this.anchors.length ? 1 : -1 ) ); 21461 } 21462 21463 o.disabled = $.map( 21464 $.grep( o.disabled, function(n, i) { 21465 return n != index; 21466 }), 21467 function( n, i ) { 21468 return n >= index ? --n : n; 21469 }); 21470 21471 this._tabify(); 21472 21473 this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) ); 21474 return this; 21475 }, 21476 21477 enable: function( index ) { 21478 index = this._getIndex( index ); 21479 var o = this.options; 21480 if ( $.inArray( index, o.disabled ) == -1 ) { 21481 return; 21482 } 21483 21484 this.lis.eq( index ).removeClass( "ui-state-disabled" ); 21485 o.disabled = $.grep( o.disabled, function( n, i ) { 21486 return n != index; 21487 }); 21488 21489 this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); 21490 return this; 21491 }, 21492 21493 disable: function( index ) { 21494 index = this._getIndex( index ); 21495 var self = this, o = this.options; 21496 // cannot disable already selected tab 21497 if ( index != o.selected ) { 21498 this.lis.eq( index ).addClass( "ui-state-disabled" ); 21499 21500 o.disabled.push( index ); 21501 o.disabled.sort(); 21502 21503 this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); 21504 } 21505 21506 return this; 21507 }, 21508 21509 select: function( index ) { 21510 index = this._getIndex( index ); 21511 if ( index == -1 ) { 21512 if ( this.options.collapsible && this.options.selected != -1 ) { 21513 index = this.options.selected; 21514 } else { 21515 return this; 21516 } 21517 } 21518 this.anchors.eq( index ).trigger( this.options.event + ".tabs" ); 21519 return this; 21520 }, 21521 21522 load: function( index ) { 21523 index = this._getIndex( index ); 21524 var self = this, 21525 o = this.options, 21526 a = this.anchors.eq( index )[ 0 ], 21527 url = $.data( a, "load.tabs" ); 21528 21529 this.abort(); 21530 21531 // not remote or from cache 21532 if ( !url || this.element.queue( "tabs" ).length !== 0 && $.data( a, "cache.tabs" ) ) { 21533 this.element.dequeue( "tabs" ); 21534 return; 21535 } 21536 21537 // load remote from here on 21538 this.lis.eq( index ).addClass( "ui-state-processing" ); 21539 21540 if ( o.spinner ) { 21541 var span = $( "span", a ); 21542 span.data( "label.tabs", span.html() ).html( o.spinner ); 21543 } 21544 21545 this.xhr = $.ajax( $.extend( {}, o.ajaxOptions, { 21546 url: url, 21547 success: function( r, s ) { 21548 self.element.find( self._sanitizeSelector( a.hash ) ).html( r ); 21549 21550 // take care of tab labels 21551 self._cleanup(); 21552 21553 if ( o.cache ) { 21554 $.data( a, "cache.tabs", true ); 21555 } 21556 21557 self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) ); 21558 try { 21559 o.ajaxOptions.success( r, s ); 21560 } 21561 catch ( e ) {} 21562 }, 21563 error: function( xhr, s, e ) { 21564 // take care of tab labels 21565 self._cleanup(); 21566 21567 self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) ); 21568 try { 21569 // Passing index avoid a race condition when this method is 21570 // called after the user has selected another tab. 21571 // Pass the anchor that initiated this request allows 21572 // loadError to manipulate the tab content panel via $(a.hash) 21573 o.ajaxOptions.error( xhr, s, index, a ); 21574 } 21575 catch ( e ) {} 21576 } 21577 } ) ); 21578 21579 // last, so that load event is fired before show... 21580 self.element.dequeue( "tabs" ); 21581 21582 return this; 21583 }, 21584 21585 abort: function() { 21586 // stop possibly running animations 21587 this.element.queue( [] ); 21588 this.panels.stop( false, true ); 21589 21590 // "tabs" queue must not contain more than two elements, 21591 // which are the callbacks for the latest clicked tab... 21592 this.element.queue( "tabs", this.element.queue( "tabs" ).splice( -2, 2 ) ); 21593 21594 // terminate pending requests from other tabs 21595 if ( this.xhr ) { 21596 this.xhr.abort(); 21597 delete this.xhr; 21598 } 21599 21600 // take care of tab labels 21601 this._cleanup(); 21602 return this; 21603 }, 21604 21605 url: function( index, url ) { 21606 this.anchors.eq( index ).removeData( "cache.tabs" ).data( "load.tabs", url ); 21607 return this; 21608 }, 21609 21610 length: function() { 21611 return this.anchors.length; 21612 } 21613}); 21614 21615$.extend( $.ui.tabs, { 21616 version: "1.8.16" 21617}); 21618 21619/* 21620 * Tabs Extensions 21621 */ 21622 21623/* 21624 * Rotate 21625 */ 21626$.extend( $.ui.tabs.prototype, { 21627 rotation: null, 21628 rotate: function( ms, continuing ) { 21629 var self = this, 21630 o = this.options; 21631 21632 var rotate = self._rotate || ( self._rotate = function( e ) { 21633 clearTimeout( self.rotation ); 21634 self.rotation = setTimeout(function() { 21635 var t = o.selected; 21636 self.select( ++t < self.anchors.length ? t : 0 ); 21637 }, ms ); 21638 21639 if ( e ) { 21640 e.stopPropagation(); 21641 } 21642 }); 21643 21644 var stop = self._unrotate || ( self._unrotate = !continuing 21645 ? function(e) { 21646 if (e.clientX) { // in case of a true click 21647 self.rotate(null); 21648 } 21649 } 21650 : function( e ) { 21651 t = o.selected; 21652 rotate(); 21653 }); 21654 21655 // start rotation 21656 if ( ms ) { 21657 this.element.bind( "tabsshow", rotate ); 21658 this.anchors.bind( o.event + ".tabs", stop ); 21659 rotate(); 21660 // stop rotation 21661 } else { 21662 clearTimeout( self.rotation ); 21663 this.element.unbind( "tabsshow", rotate ); 21664 this.anchors.unbind( o.event + ".tabs", stop ); 21665 delete this._rotate; 21666 delete this._unrotate; 21667 } 21668 21669 return this; 21670 } 21671}); 21672 21673})( jQuery ); 21674</script><script type="text/javascript">/* 21675 * $Id$ 21676 * 21677 * Copyright 2011, Juniper Network Inc, All rights reserved 21678 * See ../Copyright for more information. 21679 */ 21680 21681jQuery(function ($) { 21682 /* 21683 * dbgpr() is our old-and-trusted debug print function 21684 */ 21685 $.dbgpr = function () { 21686 /* The actual work is pretty trivial */ 21687 $('#debug-log').prepend(Array.prototype.slice 21688 .call(arguments).join(" ") + "\n"); 21689 } 21690}); 21691</script><script type="text/javascript">/* 21692 * $Id$ 21693 * 21694 * Copyright (c) 2006-2011, Juniper Networks, Inc. 21695 * All rights reserved. 21696 * This SOFTWARE is licensed under the LICENSE provided in the 21697 * ../Copyright file. By downloading, installing, copying, or otherwise 21698 * using the SOFTWARE, you agree to be bound by the terms of that 21699 * LICENSE. 21700 */ 21701 21702function popClick(event, objectId) { 21703 var sc = window["stickyClick"]; 21704 if (sc && sc[objectId]) { 21705 popDown(event, objectId); 21706 sc[objectId] = false; 21707 } else { 21708 popUp(event, objectId); 21709 if (!sc) { 21710 window["stickyClick"] = sc = []; 21711 } 21712 sc[objectId] = true; 21713 } 21714 return false; 21715} 21716 21717function popUp(event, objectId) { 21718 var sc = window["stickyClick"]; 21719 if (sc && sc[objectId]) { 21720 return; 21721 } 21722 21723 if (document.getElementById == null) 21724 return; 21725 var ie = document.all ? 1 : 0; /* Is this Internet Explorer? */ 21726 var dm = document.getElementById(objectId); 21727 if (dm == null) 21728 return; 21729 21730 var ds = dm.style; 21731 var widthPage = window.innerWidth ? window.innerWidth 21732 : document.body.clientWidth; 21733 21734 var elementWidth = dm.offsetWidth; 21735 var top; 21736 var left; 21737 21738 if (event.pageY) { 21739 top = event.pageY + 10; 21740 left = event.pageX + 10; 21741 } else if (event.clientY) { 21742 top = event.clientY + 10; 21743 left = event.clientX + 10; 21744 } else { 21745 return; 21746 } 21747 21748 if (left + elementWidth > widthPage) 21749 left = widthPage - elementWidth - 25; 21750 21751 if (ie) { 21752 ds.width = "1200px"; 21753 ds.display = "block"; 21754 var cw = dm.firstChild.clientWidth; 21755 if (cw > widthPage - left - 10) { 21756 cw = widthPage - left - 10; 21757 } 21758 ds.width = cw + "px"; 21759 } 21760 21761 ds.left = "10px"; 21762 ds.top = top + "px"; 21763 ds.width = widthPage / 2 + "px"; 21764 ds.display = "block"; 21765 21766 var tm = document.getElementById("table-" + objectId); 21767 if (tm == null) 21768 return; 21769 21770 elementWidth = tm.offsetWidth; 21771 if (left + elementWidth > widthPage) 21772 left = widthPage - elementWidth - 25; 21773 21774 ds.left = left + "px"; 21775} 21776 21777function popDown(event, objectId) { 21778 var sc = window["stickyClick"]; 21779 if (sc && sc[objectId]) { 21780 return; 21781 } 21782 21783 if (document.getElementById == null) 21784 return; 21785 var dm = document.getElementById(objectId); 21786 if (dm) { 21787 dm.style.display = "none"; 21788 } 21789} 21790</script><script type="text/javascript">/* 21791 * $Id$ 21792 * 21793 * Copyright (c) 2006-2011, Juniper Networks, Inc. 21794 * All rights reserved. 21795 * This SOFTWARE is licensed under the LICENSE provided in the 21796 * ../Copyright file. By downloading, installing, copying, or otherwise 21797 * using the SOFTWARE, you agree to be bound by the terms of that 21798 * LICENSE. 21799 */ 21800 21801jQuery(function ($) { 21802 var $body = $("body"); 21803 var $newp = $("<div id='top'><div id='top-left'/>" 21804 + "<div id='top-right'/></div"); 21805 var $left = $("div#top-left", $newp); 21806 var $right = $("div#top-right", $newp); 21807 21808 $right.append($("<div id='nav-bar'><button id='nav-prev'/>" 21809 + "<button id='nav-next'/></div>")); 21810 21811 $body.append($newp); 21812 $left.append($("div#toc")); 21813 21814 $("div.content, div.index, div.note", $body).each(function (i, elt) { 21815 $(elt).appendTo($right); 21816 }); 21817 21818 $("body > ul.toc").remove(); 21819 $("#rfc.toc").remove(); 21820 $("div.note").remove(); 21821 $("h1", $left).remove(); 21822 21823 /* $body.append($("<div id='debug-log'/>")); */ 21824 $left.append($("<div class='padding'/>")); 21825 21826 var active; 21827 var tocactive; 21828 21829 { 21830 var $active = $($right.children("div.content").get(0)); 21831 if (this.URL) { 21832 var last = this.URL.lastIndexOf("#"); 21833 if (last) { 21834 var $found = $(this.URL.substring(last)); 21835 if ($found.length > 0) 21836 $active = $found.parent(); 21837 if (!$active.hasClass("content")) 21838 $active = $active.parent(); 21839 } 21840 } 21841 setActive($active); 21842 } 21843 21844 function setActive ($elt, toggle) { 21845 if ($elt && $elt.length > 0 && $elt.hasClass("content")) { 21846 /* Mark a new element "active" */ 21847 if (active) 21848 active.removeClass("active"); 21849 active = $elt; 21850 active.addClass("active"); 21851 21852 /* Now we want to find the matching TOC entry and mark it */ 21853 if (tocactive) 21854 tocactive.removeClass("toc-active"); 21855 21856 var id = $elt.get(0).children[0].id 21857 $.dbgpr("sa:", id); 21858 if (id) { 21859 id = "#toc_" + id; 21860 tocactive = $("a", $(id).parent()); 21861 $.dbgpr("ta:", tocactive.length, id); 21862 if (tocactive.length) { 21863 tocactive = $(tocactive[0]); 21864 tocactive.addClass("toc-active"); 21865 21866 var $tt = tocactive.parents("li.tocline0"); 21867 $.dbgpr("tt:", $tt.length); 21868 if (toggle) 21869 $("ul.top-toc", $tt).toggleClass("top-toc-open"); 21870 else 21871 $("ul.top-toc", $tt).addClass("top-toc-open"); 21872 } 21873 } 21874 21875 var szr = $("div#top-right div.active").innerHeight(); 21876 var sz = $("p#title").innerHeight(); 21877 sz = window.innerHeight - sz; 21878 sz -= 66; 21879 if (sz < 200) 21880 sz = 300; 21881 if (sz < szr) 21882 sz = szr; 21883 $("div#toc > ul.toc").innerHeight(sz); 21884 21885 } 21886 } 21887 21888 function findParent ($elt, className) { 21889 while ($elt) { 21890 if ($elt.hasClass(className)) 21891 return $elt; 21892 $elt = $elt.parent(); 21893 } 21894 return null; 21895 } 21896 21897 $("a", $left).click(function (event) { 21898 event.preventDefault(); 21899 var $this = $(this); 21900 var id = this.href.split("#"); 21901 id = id[id.length - 1]; 21902 21903 var toggle = $(this).parent().hasClass("tocline0"); 21904 21905 var $target = $(document.getElementById(id)); 21906 $.dbgpr("id: ", id, " + ", $target, " + ", $target.length); 21907 21908 var $parent = findParent($target, "content"); 21909 $.dbgpr("pr: ", $parent); 21910 setActive($parent, toggle); 21911 $.dbgpr("done"); 21912 21913 $("html").animate({ scrollTop: 0 }, 500); 21914 }); 21915 21916 21917 $("a", $right).each(function (idx, elt) { 21918 /* Put the @title as the link value */ 21919 var $elt = $(elt); 21920 var href = $elt.attr("href"); 21921 var proto; 21922 21923 if (href) { 21924 var len = href.indexOf(":"); 21925 if (len > 0) { 21926 proto = href.substr(0, len); 21927 } 21928 } 21929 if (proto != "http" && proto != "https") { 21930 var t = $elt.attr("title"); 21931 if (t !== undefined && href !== undefined) 21932 $elt.text(t); 21933 $elt.click(function (event) { 21934 event.preventDefault(); 21935 var id = this.href.split("#"); 21936 id = id[id.length - 1]; 21937 21938 var $target = $(document.getElementById(id)); 21939 setActive($target.parents("div.content")); 21940 21941 $("html").animate({ scrollTop: 0 }, 500); 21942 }); 21943 } 21944 }); 21945 21946 $("button#nav-prev").button({ 21947 label: "<< Previous", 21948 }).click(function (event) { 21949 setActive(active.prev()); 21950 }); 21951 21952 $("button#nav-next").button({ 21953 label: "Next >>", 21954 }).click(function (event) { 21955 setActive(active.next()); 21956 }); 21957 21958 $("p", $right).each(function (idx, elt) { 21959 var $elt = $(elt); 21960 var val = $elt.get(0); 21961 if (val && val.textContent && val.textContent.startsWith("Section Contents")) { 21962 $elt.addClass("section-contents"); 21963 } 21964 }); 21965 21966 21967 function getMedia () { 21968 var mediaInspector = document.getElementById('media-inspector'); 21969 var zIndex; 21970 21971 if (mediaInspector === null) 21972 return -1; 21973 21974 if (mediaInspector.currentStyle) { 21975 zIndex = mediaInspector.currentStyle['zIndex']; 21976 } else if (window.getComputedStyle) { 21977 zIndex = window.getComputedStyle(mediaInspector, '') 21978 .getPropertyValue("z-index"); 21979 } 21980 return zIndex; 21981 } 21982}); 21983</script><link rel="Contents" href="#doc.toc"> 21984<link rel="Author" href="#doc.authors"> 21985<link rel="Chapter" title="1 Overview" href="#doc_section_1"> 21986<link rel="Chapter" title="2 Getting libxo" href="#doc_section_2"> 21987<link rel="Chapter" title="3 Formatting with libxo" href="#doc_section_3"> 21988<link rel="Chapter" title="4 Command-line Arguments" href="#doc_section_4"> 21989<link rel="Chapter" title="5 The libxo API" href="#doc_section_5"> 21990<link rel="Chapter" title='6 The "xo" Utility' href="#doc_section_6"> 21991<link rel="Chapter" title="7 xolint" href="#doc_section_7"> 21992<link rel="Chapter" title="8 xohtml" href="#doc_section_8"> 21993<link rel="Chapter" title="9 xopo" href="#doc_section_9"> 21994<link rel="Chapter" title="10 FAQs" href="#doc_section_10"> 21995<link rel="Chapter" title="11 Howtos: Focused Directions" href="#doc_section_11"> 21996<link rel="Chapter" title="12 Examples" href="#doc_section_12"> 21997<meta name="generator" content="http://greenbytes.de/tech/webdav/rfc2629.xslt, Revision 1.389, 2008-08-20 14:21:35, XSLT vendor: libxslt http://xmlsoft.org/XSLT/"> 21998<link rel="schema.DC" href="http://purl.org/dc/elements/1.1/"> 21999<meta name="DC.Creator" content="Shafer, P."> 22000</head> 22001<body style="font-size: 80%"> 22002<div id="media-inspector"></div> 22003<div id="header"><table summary="header information" class="header" border="0" cellpadding="1" cellspacing="1"> 22004<tr> 22005<td class="header left">The libxo Project</td> 22006<td class="header right">P. Shafer</td> 22007</tr> 22008<tr> 22009<td class="header left"></td> 22010<td class="header right">Juniper Networks</td> 22011</tr> 22012<tr> 22013<td class="header left"></td> 22014<td class="header right">May 21, 2018</td> 22015</tr> 22016</table></div> 22017<p id="title" class="title">libxo: The Easy Way to Generate text, XML, JSON, and HTML output<br><span class="filename">libxo-manual</span></p> 22018<div id="toc"> 22019<h1 class="np" id="doc.toc"><a href="#doc.toc">Table of Contents</a></h1> 22020<ul class="toc"> 22021<li class="tocline0"> 22022<div class="section-number" id="toc_doc_section_1">1���</div> 22023<a href="#overview">Overview</a> 22024</li> 22025<li class="tocline0"> 22026<div class="section-number" id="toc_doc_section_2">2���</div> 22027<a href="#getting-libxo">Getting libxo</a><ul class="toc top-toc"> 22028<li class="tocline1"> 22029<div class="section-number" id="toc_doc_section_2_1">2.1���</div> 22030<a href="#downloading-libxo-source-code">Downloading libxo Source Code</a> 22031</li> 22032<li class="tocline1"> 22033<div class="section-number" id="toc_doc_section_2_2">2.2���</div> 22034<a href="#building-libxo">Building libxo</a><ul class="toc"> 22035<li class="tocline1"> 22036<div class="section-number" id="toc_doc_section_2_2_1">2.2.1���</div> 22037<a href="#setting-up-the-build">Setting up the build</a> 22038</li> 22039<li class="tocline1"> 22040<div class="section-number" id="toc_doc_section_2_2_2">2.2.2���</div> 22041<a href="#running-the-configure-script">Running the "configure" Script</a><ul class="toc"> 22042<li class="tocline1"> 22043<div class="section-number" id="toc_doc_section_2_2_2_1">2.2.2.1���</div> 22044<a href="#running-the-make-command">Running the "make" command</a> 22045</li> 22046<li class="tocline1"> 22047<div class="section-number" id="toc_doc_section_2_2_2_2">2.2.2.2���</div> 22048<a href="#running-the-regression-tests">Running the Regression Tests</a> 22049</li> 22050</ul> 22051</li> 22052<li class="tocline1"> 22053<div class="section-number" id="toc_doc_section_2_2_3">2.2.3���</div> 22054<a href="#installing-libxo">Installing libxo</a> 22055</li> 22056</ul> 22057</li> 22058</ul> 22059</li> 22060<li class="tocline0"> 22061<div class="section-number" id="toc_doc_section_3">3���</div> 22062<a href="#formatting-with-libxo">Formatting with libxo</a><ul class="toc top-toc"> 22063<li class="tocline1"> 22064<div class="section-number" id="toc_doc_section_3_1">3.1���</div> 22065<a href="#encoding-styles">Encoding Styles</a><ul class="toc"> 22066<li class="tocline1"> 22067<div class="section-number" id="toc_doc_section_3_1_1">3.1.1���</div> 22068<a href="#text-output">Text Output</a> 22069</li> 22070<li class="tocline1"> 22071<div class="section-number" id="toc_doc_section_3_1_2">3.1.2���</div> 22072<a href="#xml-output">XML Output</a> 22073</li> 22074<li class="tocline1"> 22075<div class="section-number" id="toc_doc_section_3_1_3">3.1.3���</div> 22076<a href="#json-output">JSON Output</a> 22077</li> 22078<li class="tocline1"> 22079<div class="section-number" id="toc_doc_section_3_1_4">3.1.4���</div> 22080<a href="#html-output">HTML Output</a> 22081</li> 22082</ul> 22083</li> 22084<li class="tocline1"> 22085<div class="section-number" id="toc_doc_section_3_2">3.2���</div> 22086<a href="#format-strings">Format Strings</a><ul class="toc"> 22087<li class="tocline1"> 22088<div class="section-number" id="toc_doc_section_3_2_1">3.2.1���</div> 22089<a href="#field-roles">Field Roles</a><ul class="toc"> 22090<li class="tocline1"> 22091<div class="section-number" id="toc_doc_section_3_2_1_1">3.2.1.1���</div> 22092<a href="#color-role">The Color Role ({C:})</a> 22093</li> 22094<li class="tocline1"> 22095<div class="section-number" id="toc_doc_section_3_2_1_2">3.2.1.2���</div> 22096<a href="#the-decoration-role-d">The Decoration Role ({D:})</a> 22097</li> 22098<li class="tocline1"> 22099<div class="section-number" id="toc_doc_section_3_2_1_3">3.2.1.3���</div> 22100<a href="#gettext-role">The Gettext Role ({G:})</a> 22101</li> 22102<li class="tocline1"> 22103<div class="section-number" id="toc_doc_section_3_2_1_4">3.2.1.4���</div> 22104<a href="#the-label-role-l">The Label Role ({L:})</a> 22105</li> 22106<li class="tocline1"> 22107<div class="section-number" id="toc_doc_section_3_2_1_5">3.2.1.5���</div> 22108<a href="#the-note-role-n">The Note Role ({N:})</a> 22109</li> 22110<li class="tocline1"> 22111<div class="section-number" id="toc_doc_section_3_2_1_6">3.2.1.6���</div> 22112<a href="#padding-role">The Padding Role ({P:})</a> 22113</li> 22114<li class="tocline1"> 22115<div class="section-number" id="toc_doc_section_3_2_1_7">3.2.1.7���</div> 22116<a href="#the-title-role-t">The Title Role ({T:})</a> 22117</li> 22118<li class="tocline1"> 22119<div class="section-number" id="toc_doc_section_3_2_1_8">3.2.1.8���</div> 22120<a href="#the-units-role-u">The Units Role ({U:})</a> 22121</li> 22122<li class="tocline1"> 22123<div class="section-number" id="toc_doc_section_3_2_1_9">3.2.1.9���</div> 22124<a href="#the-value-role-v-and-">The Value Role ({V:} and {:})</a> 22125</li> 22126<li class="tocline1"> 22127<div class="section-number" id="toc_doc_section_3_2_1_10">3.2.1.10���</div> 22128<a href="#anchor-role">The Anchor Roles ({[:} and {]:})</a> 22129</li> 22130</ul> 22131</li> 22132<li class="tocline1"> 22133<div class="section-number" id="toc_doc_section_3_2_2">3.2.2���</div> 22134<a href="#field-modifiers">Field Modifiers</a><ul class="toc"> 22135<li class="tocline1"> 22136<div class="section-number" id="toc_doc_section_3_2_2_1">3.2.2.1���</div> 22137<a href="#the-argument-modifier-a">The Argument Modifier ({a:})</a> 22138</li> 22139<li class="tocline1"> 22140<div class="section-number" id="toc_doc_section_3_2_2_2">3.2.2.2���</div> 22141<a href="#the-colon-modifier-c">The Colon Modifier ({c:})</a> 22142</li> 22143<li class="tocline1"> 22144<div class="section-number" id="toc_doc_section_3_2_2_3">3.2.2.3���</div> 22145<a href="#the-display-modifier-d">The Display Modifier ({d:})</a> 22146</li> 22147<li class="tocline1"> 22148<div class="section-number" id="toc_doc_section_3_2_2_4">3.2.2.4���</div> 22149<a href="#e-modifier">The Encoding Modifier ({e:})</a> 22150</li> 22151<li class="tocline1"> 22152<div class="section-number" id="toc_doc_section_3_2_2_5">3.2.2.5���</div> 22153<a href="#gettext-modifier">The Gettext Modifier ({g:})</a> 22154</li> 22155<li class="tocline1"> 22156<div class="section-number" id="toc_doc_section_3_2_2_6">3.2.2.6���</div> 22157<a href="#the-humanize-modifier-h">The Humanize Modifier ({h:})</a> 22158</li> 22159<li class="tocline1"> 22160<div class="section-number" id="toc_doc_section_3_2_2_7">3.2.2.7���</div> 22161<a href="#the-key-modifier-k">The Key Modifier ({k:})</a> 22162</li> 22163<li class="tocline1"> 22164<div class="section-number" id="toc_doc_section_3_2_2_8">3.2.2.8���</div> 22165<a href="#the-leaf-list-modifier-l">The Leaf-List Modifier ({l:})</a> 22166</li> 22167<li class="tocline1"> 22168<div class="section-number" id="toc_doc_section_3_2_2_9">3.2.2.9���</div> 22169<a href="#the-no-quotes-modifier-n">The No-Quotes Modifier ({n:})</a> 22170</li> 22171<li class="tocline1"> 22172<div class="section-number" id="toc_doc_section_3_2_2_10">3.2.2.10���</div> 22173<a href="#plural-modifier">The Plural Modifier ({p:})</a> 22174</li> 22175<li class="tocline1"> 22176<div class="section-number" id="toc_doc_section_3_2_2_11">3.2.2.11���</div> 22177<a href="#the-quotes-modifier-q">The Quotes Modifier ({q:})</a> 22178</li> 22179<li class="tocline1"> 22180<div class="section-number" id="toc_doc_section_3_2_2_12">3.2.2.12���</div> 22181<a href="#the-trim-modifier-t">The Trim Modifier ({t:})</a> 22182</li> 22183<li class="tocline1"> 22184<div class="section-number" id="toc_doc_section_3_2_2_13">3.2.2.13���</div> 22185<a href="#the-white-space-modifier-w">The White Space Modifier ({w:})</a> 22186</li> 22187</ul> 22188</li> 22189<li class="tocline1"> 22190<div class="section-number" id="toc_doc_section_3_2_3">3.2.3���</div> 22191<a href="#field-formatting">Field Formatting</a> 22192</li> 22193<li class="tocline1"> 22194<div class="section-number" id="toc_doc_section_3_2_4">3.2.4���</div> 22195<a href="#utf-8-and-locale-strings">UTF-8 and Locale Strings</a> 22196</li> 22197<li class="tocline1"> 22198<div class="section-number" id="toc_doc_section_3_2_5">3.2.5���</div> 22199<a href="#characters-outside-of-field-definitions">Characters Outside of Field Definitions</a> 22200</li> 22201<li class="tocline1"> 22202<div class="section-number" id="toc_doc_section_3_2_6">3.2.6���</div> 22203<a href="#m-is-supported">"%m" Is Supported</a> 22204</li> 22205<li class="tocline1"> 22206<div class="section-number" id="toc_doc_section_3_2_7">3.2.7���</div> 22207<a href="#n-is-not-supported">"%n" Is Not Supported</a> 22208</li> 22209<li class="tocline1"> 22210<div class="section-number" id="toc_doc_section_3_2_8">3.2.8���</div> 22211<a href="#the-encoding-format-eformat">The Encoding Format (eformat)</a> 22212</li> 22213<li class="tocline1"> 22214<div class="section-number" id="toc_doc_section_3_2_9">3.2.9���</div> 22215<a href="#content-strings">Content Strings</a> 22216</li> 22217<li class="tocline1"> 22218<div class="section-number" id="toc_doc_section_3_2_10">3.2.10���</div> 22219<a href="#printf-like">Argument Validation</a> 22220</li> 22221<li class="tocline1"> 22222<div class="section-number" id="toc_doc_section_3_2_11">3.2.11���</div> 22223<a href="#retain">Retaining Parsed Format Information</a> 22224</li> 22225<li class="tocline1"> 22226<div class="section-number" id="toc_doc_section_3_2_12">3.2.12���</div> 22227<a href="#example">Example</a> 22228</li> 22229</ul> 22230</li> 22231<li class="tocline1"> 22232<div class="section-number" id="toc_doc_section_3_3">3.3���</div> 22233<a href="#representing-hierarchy">Representing Hierarchy</a><ul class="toc"> 22234<li class="tocline1"> 22235<div class="section-number" id="toc_doc_section_3_3_1">3.3.1���</div> 22236<a href="#containers">Containers</a> 22237</li> 22238<li class="tocline1"> 22239<div class="section-number" id="toc_doc_section_3_3_2">3.3.2���</div> 22240<a href="#lists-and-instances">Lists and Instances</a> 22241</li> 22242<li class="tocline1"> 22243<div class="section-number" id="toc_doc_section_3_3_3">3.3.3���</div> 22244<a href="#dtrt-mode">DTRT Mode</a> 22245</li> 22246<li class="tocline1"> 22247<div class="section-number" id="toc_doc_section_3_3_4">3.3.4���</div> 22248<a href="#markers">Markers</a> 22249</li> 22250</ul> 22251</li> 22252</ul> 22253</li> 22254<li class="tocline0"> 22255<div class="section-number" id="toc_doc_section_4">4���</div> 22256<a href="#options">Command-line Arguments</a><ul class="toc top-toc"> 22257<li class="tocline1"> 22258<div class="section-number" id="toc_doc_section_4_1">4.1���</div> 22259<a href="#option-keywords">Option keywords</a> 22260</li> 22261<li class="tocline1"> 22262<div class="section-number" id="toc_doc_section_4_2">4.2���</div> 22263<a href="#brief-options">Brief Options</a> 22264</li> 22265<li class="tocline1"> 22266<div class="section-number" id="toc_doc_section_4_3">4.3���</div> 22267<a href="#color-mapping">Color Mapping</a> 22268</li> 22269</ul> 22270</li> 22271<li class="tocline0"> 22272<div class="section-number" id="toc_doc_section_5">5���</div> 22273<a href="#the-libxo-api">The libxo API</a><ul class="toc top-toc"> 22274<li class="tocline1"> 22275<div class="section-number" id="toc_doc_section_5_1">5.1���</div> 22276<a href="#handles">Handles</a><ul class="toc"> 22277<li class="tocline1"> 22278<div class="section-number" id="toc_doc_section_5_1_1">5.1.1���</div> 22279<a href="#xo_create">xo_create</a> 22280</li> 22281<li class="tocline1"> 22282<div class="section-number" id="toc_doc_section_5_1_2">5.1.2���</div> 22283<a href="#xo_create_to_file">xo_create_to_file</a> 22284</li> 22285<li class="tocline1"> 22286<div class="section-number" id="toc_doc_section_5_1_3">5.1.3���</div> 22287<a href="#xo_set_writer">xo_set_writer</a> 22288</li> 22289<li class="tocline1"> 22290<div class="section-number" id="toc_doc_section_5_1_4">5.1.4���</div> 22291<a href="#xo_set_style">xo_set_style</a> 22292</li> 22293<li class="tocline1"> 22294<div class="section-number" id="toc_doc_section_5_1_5">5.1.5���</div> 22295<a href="#xo_get_style">xo_get_style</a><ul class="toc"> 22296<li class="tocline1"> 22297<div class="section-number" id="toc_doc_section_5_1_5_1">5.1.5.1���</div> 22298<a href="#styles">Output Styles (XO_STYLE_*)</a> 22299</li> 22300<li class="tocline1"> 22301<div class="section-number" id="toc_doc_section_5_1_5_2">5.1.5.2���</div> 22302<a href="#xo_set_style_name">xo_set_style_name</a> 22303</li> 22304</ul> 22305</li> 22306<li class="tocline1"> 22307<div class="section-number" id="toc_doc_section_5_1_6">5.1.6���</div> 22308<a href="#xo_set_flags">xo_set_flags</a><ul class="toc"> 22309<li class="tocline1"> 22310<div class="section-number" id="toc_doc_section_5_1_6_1">5.1.6.1���</div> 22311<a href="#flags">Flags (XOF_*)</a> 22312</li> 22313<li class="tocline1"> 22314<div class="section-number" id="toc_doc_section_5_1_6_2">5.1.6.2���</div> 22315<a href="#xo_clear_flags">xo_clear_flags</a> 22316</li> 22317<li class="tocline1"> 22318<div class="section-number" id="toc_doc_section_5_1_6_3">5.1.6.3���</div> 22319<a href="#xo_set_options">xo_set_options</a> 22320</li> 22321</ul> 22322</li> 22323<li class="tocline1"> 22324<div class="section-number" id="toc_doc_section_5_1_7">5.1.7���</div> 22325<a href="#xo_destroy">xo_destroy</a> 22326</li> 22327</ul> 22328</li> 22329<li class="tocline1"> 22330<div class="section-number" id="toc_doc_section_5_2">5.2���</div> 22331<a href="#emitting-content-xo_emit">Emitting Content (xo_emit)</a><ul class="toc"> 22332<li class="tocline1"> 22333<div class="section-number" id="toc_doc_section_5_2_1">5.2.1���</div> 22334<a href="#xo_emit_field">Single Field Emitting Functions (xo_emit_field)</a> 22335</li> 22336<li class="tocline1"> 22337<div class="section-number" id="toc_doc_section_5_2_2">5.2.2���</div> 22338<a href="#xo_attr">Attributes (xo_attr)</a> 22339</li> 22340<li class="tocline1"> 22341<div class="section-number" id="toc_doc_section_5_2_3">5.2.3���</div> 22342<a href="#flushing-output-xo_flush">Flushing Output (xo_flush)</a> 22343</li> 22344<li class="tocline1"> 22345<div class="section-number" id="toc_doc_section_5_2_4">5.2.4���</div> 22346<a href="#finishing-output-xo_finish">Finishing Output (xo_finish)</a> 22347</li> 22348</ul> 22349</li> 22350<li class="tocline1"> 22351<div class="section-number" id="toc_doc_section_5_3">5.3���</div> 22352<a href="#emitting-hierarchy">Emitting Hierarchy</a><ul class="toc"><li class="tocline1"> 22353<div class="section-number" id="toc_doc_section_5_3_1">5.3.1���</div> 22354<a href="#lists-and-instances-2">Lists and Instances</a> 22355</li></ul> 22356</li> 22357<li class="tocline1"> 22358<div class="section-number" id="toc_doc_section_5_4">5.4���</div> 22359<a href="#support-functions">Support Functions</a><ul class="toc"> 22360<li class="tocline1"> 22361<div class="section-number" id="toc_doc_section_5_4_1">5.4.1���</div> 22362<a href="#xo_parse_args">Parsing Command-line Arguments (xo_parse_args)</a> 22363</li> 22364<li class="tocline1"> 22365<div class="section-number" id="toc_doc_section_5_4_2">5.4.2���</div> 22366<a href="#xo_set_program">xo_set_program</a> 22367</li> 22368<li class="tocline1"> 22369<div class="section-number" id="toc_doc_section_5_4_3">5.4.3���</div> 22370<a href="#xo_set_version">xo_set_version</a> 22371</li> 22372<li class="tocline1"> 22373<div class="section-number" id="toc_doc_section_5_4_4">5.4.4���</div> 22374<a href="#info">Field Information (xo_info_t)</a> 22375</li> 22376<li class="tocline1"> 22377<div class="section-number" id="toc_doc_section_5_4_5">5.4.5���</div> 22378<a href="#memory-allocation">Memory Allocation</a> 22379</li> 22380<li class="tocline1"> 22381<div class="section-number" id="toc_doc_section_5_4_6">5.4.6���</div> 22382<a href="#LIBXO_OPTIONS">LIBXO_OPTIONS</a> 22383</li> 22384<li class="tocline1"> 22385<div class="section-number" id="toc_doc_section_5_4_7">5.4.7���</div> 22386<a href="#errors-warnings-and-messages">Errors, Warnings, and Messages</a> 22387</li> 22388<li class="tocline1"> 22389<div class="section-number" id="toc_doc_section_5_4_8">5.4.8���</div> 22390<a href="#xo_error">xo_error</a> 22391</li> 22392<li class="tocline1"> 22393<div class="section-number" id="toc_doc_section_5_4_9">5.4.9���</div> 22394<a href="#xo_no_setlocale">xo_no_setlocale</a> 22395</li> 22396</ul> 22397</li> 22398<li class="tocline1"> 22399<div class="section-number" id="toc_doc_section_5_5">5.5���</div> 22400<a href="#emitting-syslog-messages">Emitting syslog Messages</a><ul class="toc"> 22401<li class="tocline1"> 22402<div class="section-number" id="toc_doc_section_5_5_1">5.5.1���</div> 22403<a href="#priority">Priority, Facility, and Flags</a> 22404</li> 22405<li class="tocline1"> 22406<div class="section-number" id="toc_doc_section_5_5_2">5.5.2���</div> 22407<a href="#xo_syslog">xo_syslog</a> 22408</li> 22409<li class="tocline1"> 22410<div class="section-number" id="toc_doc_section_5_5_3">5.5.3���</div> 22411<a href="#support-functions-2">Support functions</a><ul class="toc"> 22412<li class="tocline1"> 22413<div class="section-number" id="toc_doc_section_5_5_3_1">5.5.3.1���</div> 22414<a href="#xo_vsyslog">xo_vsyslog</a> 22415</li> 22416<li class="tocline1"> 22417<div class="section-number" id="toc_doc_section_5_5_3_2">5.5.3.2���</div> 22418<a href="#xo_open_log">xo_open_log</a> 22419</li> 22420<li class="tocline1"> 22421<div class="section-number" id="toc_doc_section_5_5_3_3">5.5.3.3���</div> 22422<a href="#xo_close_log">xo_close_log</a> 22423</li> 22424<li class="tocline1"> 22425<div class="section-number" id="toc_doc_section_5_5_3_4">5.5.3.4���</div> 22426<a href="#xo_set_logmask">xo_set_logmask</a> 22427</li> 22428<li class="tocline1"> 22429<div class="section-number" id="toc_doc_section_5_5_3_5">5.5.3.5���</div> 22430<a href="#xo_set_syslog_enterprise_id">xo_set_syslog_enterprise_id</a> 22431</li> 22432</ul> 22433</li> 22434</ul> 22435</li> 22436<li class="tocline1"> 22437<div class="section-number" id="toc_doc_section_5_6">5.6���</div> 22438<a href="#creating-custom-encoders">Creating Custom Encoders</a><ul class="toc"> 22439<li class="tocline1"> 22440<div class="section-number" id="toc_doc_section_5_6_1">5.6.1���</div> 22441<a href="#loading-encoders">Loading Encoders</a> 22442</li> 22443<li class="tocline1"> 22444<div class="section-number" id="toc_doc_section_5_6_2">5.6.2���</div> 22445<a href="#encoder-initialization">Encoder Initialization</a> 22446</li> 22447<li class="tocline1"> 22448<div class="section-number" id="toc_doc_section_5_6_3">5.6.3���</div> 22449<a href="#operations">Operations</a> 22450</li> 22451</ul> 22452</li> 22453</ul> 22454</li> 22455<li class="tocline0"> 22456<div class="section-number" id="toc_doc_section_6">6���</div> 22457<a href="#the-xo-utility">The "xo" Utility</a><ul class="toc top-toc"> 22458<li class="tocline1"> 22459<div class="section-number" id="toc_doc_section_6_1">6.1���</div> 22460<a href="#command-line-options">Command Line Options</a> 22461</li> 22462<li class="tocline1"> 22463<div class="section-number" id="toc_doc_section_6_2">6.2���</div> 22464<a href="#example-2">Example</a> 22465</li> 22466</ul> 22467</li> 22468<li class="tocline0"> 22469<div class="section-number" id="toc_doc_section_7">7���</div> 22470<a href="#xolint">xolint</a> 22471</li> 22472<li class="tocline0"> 22473<div class="section-number" id="toc_doc_section_8">8���</div> 22474<a href="#xohtml">xohtml</a> 22475</li> 22476<li class="tocline0"> 22477<div class="section-number" id="toc_doc_section_9">9���</div> 22478<a href="#xopo">xopo</a> 22479</li> 22480<li class="tocline0"> 22481<div class="section-number" id="toc_doc_section_10">10���</div> 22482<a href="#faqs">FAQs</a><ul class="toc top-toc"> 22483<li class="tocline1"> 22484<div class="section-number" id="toc_doc_section_10_1">10.1���</div> 22485<a href="#general">General</a><ul class="toc"> 22486<li class="tocline1"> 22487<div class="section-number" id="toc_doc_section_10_1_1">10.1.1���</div> 22488<a href="#can-you-share-the-history-of-libxo">Can you share the history of libxo?</a> 22489</li> 22490<li class="tocline1"> 22491<div class="section-number" id="toc_doc_section_10_1_2">10.1.2���</div> 22492<a href="#did-the-complex-semantics-of-format-strings-evolve-over-time">Did the complex semantics of format strings evolve over time?</a> 22493</li> 22494<li class="tocline1"> 22495<div class="section-number" id="toc_doc_section_10_1_3">10.1.3���</div> 22496<a href="#good-field-names">What makes a good field name?</a> 22497</li> 22498</ul> 22499</li> 22500<li class="tocline1"> 22501<div class="section-number" id="toc_doc_section_10_2">10.2���</div> 22502<a href="#what-does-this-message-mean">What does this message mean?</a><ul class="toc"> 22503<li class="tocline1"> 22504<div class="section-number" id="toc_doc_section_10_2_1">10.2.1���</div> 22505<a href="#a-percent-sign-appearing-in-text-is-a-literal">'A percent sign appearing in text is a literal'</a> 22506</li> 22507<li class="tocline1"> 22508<div class="section-number" id="toc_doc_section_10_2_2">10.2.2���</div> 22509<a href="#unknown-long-name-for-rolemodifier">'Unknown long name for role/modifier'</a> 22510</li> 22511<li class="tocline1"> 22512<div class="section-number" id="toc_doc_section_10_2_3">10.2.3���</div> 22513<a href="#last-character-before-field-definition-is-a-field-type">'Last character before field definition is a field type'</a> 22514</li> 22515<li class="tocline1"> 22516<div class="section-number" id="toc_doc_section_10_2_4">10.2.4���</div> 22517<a href="#encoding-format-uses-different-number-of-arguments">'Encoding format uses different number of arguments'</a> 22518</li> 22519<li class="tocline1"> 22520<div class="section-number" id="toc_doc_section_10_2_5">10.2.5���</div> 22521<a href="#only-one-field-role-can-be-used">'Only one field role can be used'</a> 22522</li> 22523<li class="tocline1"> 22524<div class="section-number" id="toc_doc_section_10_2_6">10.2.6���</div> 22525<a href="#potential-missing-slash-after-c-d-n-l-or-t-with-format">'Potential missing slash after C, D, N, L, or T with format'</a> 22526</li> 22527<li class="tocline1"> 22528<div class="section-number" id="toc_doc_section_10_2_7">10.2.7���</div> 22529<a href="#an-encoding-format-cannot-be-given-roles-dnlt">'An encoding format cannot be given (roles: DNLT)'</a> 22530</li> 22531<li class="tocline1"> 22532<div class="section-number" id="toc_doc_section_10_2_8">10.2.8���</div> 22533<a href="#format-cannot-be-given-when-content-is-present-roles-cdln">'Format cannot be given when content is present (roles: CDLN)'</a> 22534</li> 22535<li class="tocline1"> 22536<div class="section-number" id="toc_doc_section_10_2_9">10.2.9���</div> 22537<a href="#field-has-color-without-fg--or-bg--role-c">'Field has color without fg- or bg- (role: C)'</a> 22538</li> 22539<li class="tocline1"> 22540<div class="section-number" id="toc_doc_section_10_2_10">10.2.10���</div> 22541<a href="#field-has-invalid-color-or-effect-role-c">'Field has invalid color or effect (role: C)'</a> 22542</li> 22543<li class="tocline1"> 22544<div class="section-number" id="toc_doc_section_10_2_11">10.2.11���</div> 22545<a href="#field-has-humanize-modifier-but-no-format-string">'Field has humanize modifier but no format string'</a> 22546</li> 22547<li class="tocline1"> 22548<div class="section-number" id="toc_doc_section_10_2_12">10.2.12���</div> 22549<a href="#field-has-hn--modifier-but-not-h-modifier">'Field has hn-* modifier but not 'h' modifier'</a> 22550</li> 22551<li class="tocline1"> 22552<div class="section-number" id="toc_doc_section_10_2_13">10.2.13���</div> 22553<a href="#value-field-must-have-a-name-as-content">'Value field must have a name (as content)")'</a> 22554</li> 22555<li class="tocline1"> 22556<div class="section-number" id="toc_doc_section_10_2_14">10.2.14���</div> 22557<a href="#use-hyphens-not-underscores-for-value-field-name">'Use hyphens, not underscores, for value field name'</a> 22558</li> 22559<li class="tocline1"> 22560<div class="section-number" id="toc_doc_section_10_2_15">10.2.15���</div> 22561<a href="#value-field-name-cannot-start-with-digit">'Value field name cannot start with digit'</a> 22562</li> 22563<li class="tocline1"> 22564<div class="section-number" id="toc_doc_section_10_2_16">10.2.16���</div> 22565<a href="#value-field-name-should-be-lower-case">'Value field name should be lower case'</a> 22566</li> 22567<li class="tocline1"> 22568<div class="section-number" id="toc_doc_section_10_2_17">10.2.17���</div> 22569<a href="#value-field-name-should-be-longer-than-two-characters">'Value field name should be longer than two characters'</a> 22570</li> 22571<li class="tocline1"> 22572<div class="section-number" id="toc_doc_section_10_2_18">10.2.18���</div> 22573<a href="#value-field-name-contains-invalid-character">'Value field name contains invalid character'</a> 22574</li> 22575<li class="tocline1"> 22576<div class="section-number" id="toc_doc_section_10_2_19">10.2.19���</div> 22577<a href="#decoration-field-contains-invalid-character">'decoration field contains invalid character'</a> 22578</li> 22579<li class="tocline1"> 22580<div class="section-number" id="toc_doc_section_10_2_20">10.2.20���</div> 22581<a href="#anchor-content-should-be-decimal-width">'Anchor content should be decimal width'</a> 22582</li> 22583<li class="tocline1"> 22584<div class="section-number" id="toc_doc_section_10_2_21">10.2.21���</div> 22585<a href="#anchor-format-should-be-d">'Anchor format should be "%d"'</a> 22586</li> 22587<li class="tocline1"> 22588<div class="section-number" id="toc_doc_section_10_2_22">10.2.22���</div> 22589<a href="#anchor-cannot-have-both-format-and-encoding-format">'Anchor cannot have both format and encoding format")'</a> 22590</li> 22591<li class="tocline1"> 22592<div class="section-number" id="toc_doc_section_10_2_23">10.2.23���</div> 22593<a href="#max-width-only-valid-for-strings">'Max width only valid for strings'</a> 22594</li> 22595</ul> 22596</li> 22597</ul> 22598</li> 22599<li class="tocline0"> 22600<div class="section-number" id="toc_doc_section_11">11���</div> 22601<a href="#howtos-focused-directions">Howtos: Focused Directions</a><ul class="toc top-toc"> 22602<li class="tocline1"> 22603<div class="section-number" id="toc_doc_section_11_1">11.1���</div> 22604<a href="#howto-report-bugs">Howto: Report bugs</a> 22605</li> 22606<li class="tocline1"> 22607<div class="section-number" id="toc_doc_section_11_2">11.2���</div> 22608<a href="#howto-install-libxo">Howto: Install libxo</a> 22609</li> 22610<li class="tocline1"> 22611<div class="section-number" id="toc_doc_section_11_3">11.3���</div> 22612<a href="#howto-convert-command-line-applications">Howto: Convert command line applications</a><ul class="toc"> 22613<li class="tocline1"> 22614<div class="section-number" id="toc_doc_section_11_3_1">11.3.1���</div> 22615<a href="#setting-up-the-context">Setting up the context</a> 22616</li> 22617<li class="tocline1"> 22618<div class="section-number" id="toc_doc_section_11_3_2">11.3.2���</div> 22619<a href="#converting-printf-calls">Converting printf Calls</a> 22620</li> 22621<li class="tocline1"> 22622<div class="section-number" id="toc_doc_section_11_3_3">11.3.3���</div> 22623<a href="#creating-hierarchy">Creating Hierarchy</a> 22624</li> 22625<li class="tocline1"> 22626<div class="section-number" id="toc_doc_section_11_3_4">11.3.4���</div> 22627<a href="#converting-error-functions">Converting Error Functions</a> 22628</li> 22629</ul> 22630</li> 22631<li class="tocline1"> 22632<div class="section-number" id="toc_doc_section_11_4">11.4���</div> 22633<a href="#howto-use-xo-in-shell-scripts">Howto: Use "xo" in Shell Scripts</a> 22634</li> 22635<li class="tocline1"> 22636<div class="section-number" id="toc_doc_section_11_5">11.5���</div> 22637<a href="#howto-i18n">Howto: Internationalization (i18n)</a><ul class="toc"><li class="tocline1"> 22638<div class="section-number" id="toc_doc_section_11_5_1">11.5.1���</div> 22639<a href="#i18n-and-xo_emit">i18n and xo_emit</a> 22640</li></ul> 22641</li> 22642</ul> 22643</li> 22644<li class="tocline0"> 22645<div class="section-number" id="toc_doc_section_12">12���</div> 22646<a href="#examples">Examples</a><ul class="toc top-toc"><li class="tocline1"> 22647<div class="section-number" id="toc_doc_section_12_1">12.1���</div> 22648<a href="#unit-test">Unit Test</a> 22649</li></ul> 22650</li> 22651<li class="tocline0"><a href="#doc.authors">Author's Address</a></li> 22652</ul> 22653</div> 22654<hr class="noprint"> 22655<div class="content"> 22656<h1 id="doc_section_1" class="np"> 22657<div class="self-section-number"> 22658<a href="#doc_section_1">1_</a>�</div> 22659<a id="overview" href="#overview">Overview</a> 22660</h1> 22661<p id="doc_section_1_p_1">libxo - A Library for Generating Text, XML, JSON, and HTML Output</p> 22662<p id="doc_section_1_p_2">You want to prepare for the future, but you need to live in the present. You'd love a flying car, but need to get to work today. You want to support features like XML, JSON, and HTML rendering to allow integration with NETCONF, REST, and web browsers, but you need to make text output for command line users.</p> 22663<p id="doc_section_1_p_3">And you don't want multiple code paths that can't help but get out of sync:</p> 22664<div id="doc_figure_u.1"></div> <pre> 22665 /* None of this "if (xml) {... } else {...}" logic */ 22666 if (xml) { 22667 /* some code to make xml*/ 22668 } else { 22669 /* other code to make text */ 22670 /* oops forgot to add something on both clauses! */ 22671 } 22672 22673 /* And ifdefs are right out. */ 22674 #ifdef MAKE_XML 22675 /* icky */ 22676 #else 22677 /* pooh */ 22678 #endif 22679 </pre> <p id="doc_section_1_p_5">But you'd really, really like all the fancy features that modern encoding formats can provide. libxo can help.</p> 22680<p id="doc_section_1_p_6">The libxo library allows an application to generate text, XML, JSON, and HTML output using a common set of function calls. The application decides at run time which output style should be produced. The application calls a function "xo_emit" to product output that is described in a format string. A "field descriptor" tells libxo what the field is and what it means. Each field descriptor is placed in braces with a printf-like format string (<a href="#format-strings" title="Format Strings">Section�3.2</a>):</p> 22681<div id="doc_figure_u.2"></div> <pre> 22682 xo_emit(" {:lines/%7ju} {:words/%7ju} " 22683 "{:characters/%7ju} {d:filename/%s}\n", 22684 linect, wordct, charct, file); 22685 </pre> <p id="doc_section_1_p_8">Each field can have a role, with the 'value' role being the default, and the role tells libxo how and when to render that field (see <a href="#field-roles" title="Field Roles">Section�3.2.1</a> for details). Modifiers change how the field is rendered in different output styles (see <a href="#field-modifiers" title="Field Modifiers">Section�3.2.2</a> for details. Output can then be generated in various style, using the "‑‑libxo" option:</p> 22686<div id="doc_figure_u.3"></div> <pre> 22687 % wc /etc/motd 22688 25 165 1140 /etc/motd 22689 % wc --libxo xml,pretty,warn /etc/motd 22690 <wc> 22691 <file> 22692 <lines>25</lines> 22693 <words>165</words> 22694 <characters>1140</characters> 22695 <filename>/etc/motd</filename> 22696 </file> 22697 </wc> 22698 % wc --libxo json,pretty,warn /etc/motd 22699 { 22700 "wc": { 22701 "file": [ 22702 { 22703 "lines": 25, 22704 "words": 165, 22705 "characters": 1140, 22706 "filename": "/etc/motd" 22707 } 22708 ] 22709 } 22710 } 22711 % wc --libxo html,pretty,warn /etc/motd 22712 <div class="line"> 22713 <div class="text"> </div> 22714 <div class="data" data-tag="lines"> 25</div> 22715 <div class="text"> </div> 22716 <div class="data" data-tag="words"> 165</div> 22717 <div class="text"> </div> 22718 <div class="data" data-tag="characters"> 1140</div> 22719 <div class="text"> </div> 22720 <div class="data" data-tag="filename">/etc/motd</div> 22721 </div> 22722 </pre> <p id="doc_section_1_p_10">Same code path, same format strings, same information, but it's rendered in distinct styles based on run-time flags.</p> 22723</div> 22724<hr class="noprint"> 22725<div class="content"> 22726<h1 id="doc_section_2" class="np"> 22727<div class="self-section-number"> 22728<a href="#doc_section_2">2_</a>�</div> 22729<a id="getting-libxo" href="#getting-libxo">Getting libxo</a> 22730</h1> 22731<p id="doc_section_2_p_1">libxo now ships as part of the FreeBSD Operating System (as of -11).</p> 22732<p id="doc_section_2_p_2">libxo lives on github as:</p> 22733<p id="doc_section_2_p_3"> <a href="https://github.com/Juniper/libxo">https://github.com/Juniper/libxo</a></p> 22734<p id="doc_section_2_p_4">The latest release of libxo is available at:</p> 22735<p id="doc_section_2_p_5"> <a href="https://github.com/Juniper/libxo/releases">https://github.com/Juniper/libxo/releases</a></p> 22736<p id="doc_section_2_p_6">We are following the branching scheme from <a href="http://nvie.com/posts/a-successful-git-branching-model/">http://nvie.com/posts/a-successful-git-branching-model/</a> which means we will do development under the "develop" branch, and release from the "master" branch. To clone a developer tree, run the following command:</p> 22737<div id="doc_figure_u.4"></div> <pre> 22738 git clone https://github.com/Juniper/libxo.git -b develop 22739 </pre> <p id="doc_section_2_p_8">We're using semantic release numbering, as defined in <a href="http://semver.org/spec/v2.0.0.html">http://semver.org/spec/v2.0.0.html</a>.</p> 22740<p id="doc_section_2_p_9">libxo is open source, distributed under the BSD license. It shipped as part of the FreeBSD operating system starting with release 11.0.</p> 22741<p id="doc_section_2_p_10">Issues, problems, and bugs should be directly to the issues page on our github site.</p> 22742<p id="doc_section_2_p_11">Section Contents: </p> 22743<ul> 22744<li><a href="#downloading-libxo-source-code" title="Downloading libxo Source Code">Section�2.1</a></li> 22745<li><a href="#building-libxo" title="Building libxo">Section�2.2</a></li> 22746</ul> 22747<div class="content"> 22748<h2 id="doc_section_2_1"> 22749<div class="self-section-number"> 22750<a href="#doc_section_2_1">2.1</a>�</div> 22751<a id="downloading-libxo-source-code" href="#downloading-libxo-source-code">Downloading libxo Source Code</a> 22752</h2> 22753<p id="doc_section_2_1_p_1">You can retrieve the source for libxo in two ways:</p> 22754<p id="doc_section_2_1_p_2">A) Use a "distfile" for a specific release. We use github to maintain our releases. Visit github release page (<a href="https://github.com/Juniper/libxo/releases">https://github.com/Juniper/libxo/releases</a>) to see the list of releases. To download the latest, look for the release with the green "Latest release" button and the green "libxo‑RELEASE.tar.gz" button under that section.</p> 22755<p id="doc_section_2_1_p_3">After downloading that release's distfile, untar it as follows:</p> 22756<div id="doc_figure_u.5"></div> <pre> 22757 tar -zxf libxo-RELEASE.tar.gz 22758 cd libxo-RELEASE 22759 </pre> <p id="doc_section_2_1_p_5">[Note: for Solaris users, your "tar" command lacks the "‑z" flag, so you'll need to substitute "gzip -dc "file" | tar xf -" instead of "tar -zxf "file"".]</p> 22760<p id="doc_section_2_1_p_6">B) Use the current build from github. This gives you the most recent source code, which might be less stable than a specific release. To build libxo from the git repo:</p> 22761<div id="doc_figure_u.6"></div> <pre> 22762 git clone https://github.com/Juniper/libxo.git 22763 cd libxo 22764 </pre> <p id="doc_section_2_1_p_8">_BE AWARE_: The github repository does _not_ contain the files generated by "autoreconf", with the notable exception of the "m4" directory. Since these files (depcomp, configure, missing, install-sh, etc) are generated files, we keep them out of the source code repository.</p> 22765<p id="doc_section_2_1_p_9">This means that if you download the a release distfile, these files will be ready and you'll just need to run "configure", but if you download the source code from svn, then you'll need to run "autoreconf" by hand. This step is done for you by the "setup.sh" script, described in the next section.</p> 22766</div> 22767<div class="content"> 22768<h2 id="doc_section_2_2"> 22769<div class="self-section-number"> 22770<a href="#doc_section_2_2">2.2</a>�</div> 22771<a id="building-libxo" href="#building-libxo">Building libxo</a> 22772</h2> 22773<p id="doc_section_2_2_p_1">To build libxo, you'll need to set up the build, run the "configure" script, run the "make" command, and run the regression tests.</p> 22774<p id="doc_section_2_2_p_2">The following is a summary of the commands needed. These commands are explained in detail in the rest of this section.</p> 22775<div id="doc_figure_u.7"></div> <pre> 22776 sh bin/setup.sh 22777 cd build 22778 ../configure 22779 make 22780 make test 22781 sudo make install 22782 </pre> <p id="doc_section_2_2_p_4">The following sections will walk through each of these steps with additional details and options, but the above directions should be all that's needed.</p> 22783<p id="doc_section_2_2_p_5">Section Contents: </p> 22784<ul> 22785<li><a href="#setting-up-the-build" title="Setting up the build">Section�2.2.1</a></li> 22786<li><a href="#running-the-configure-script" title='Running the "configure" Script'>Section�2.2.2</a></li> 22787<li><a href="#installing-libxo" title="Installing libxo">Section�2.2.3</a></li> 22788</ul> 22789<div class="content"> 22790<h3 id="doc_section_2_2_1"> 22791<div class="self-section-number"> 22792<a href="#doc_section_2_2_1">2.2.1</a>�</div> 22793<a id="setting-up-the-build" href="#setting-up-the-build">Setting up the build</a> 22794</h3> 22795<p id="doc_section_2_2_1_p_1">[If you downloaded a distfile, you can skip this step.]</p> 22796<p id="doc_section_2_2_1_p_2">Run the "setup.sh" script to set up the build. This script runs the "autoreconf" command to generate the "configure" script and other generated files.</p> 22797<div id="doc_figure_u.8"></div> <pre> 22798 sh bin/setup.sh 22799 </pre> <p id="doc_section_2_2_1_p_4">Note: We're are currently using autoreconf version 2.69.</p> 22800</div> 22801<div class="content"> 22802<h3 id="doc_section_2_2_2"> 22803<div class="self-section-number"> 22804<a href="#doc_section_2_2_2">2.2.2</a>�</div> 22805<a id="running-the-configure-script" href="#running-the-configure-script">Running the "configure" Script</a> 22806</h3> 22807<p id="doc_section_2_2_2_p_1">Configure (and autoconf in general) provides a means of building software in diverse environments. Our configure script supports a set of options that can be used to adjust to your operating environment. Use "configure --help" to view these options.</p> 22808<p id="doc_section_2_2_2_p_2">We use the "build" directory to keep object files and generated files away from the source tree.</p> 22809<p id="doc_section_2_2_2_p_3">To run the configure script, change into the "build" directory, and run the "configure" script. Add any required options to the "../configure" command line.</p> 22810<div id="doc_figure_u.9"></div> <pre> 22811 cd build 22812 ../configure 22813 </pre> <p id="doc_section_2_2_2_p_5">Expect to see the "configure" script generate the following error:</p> 22814<div id="doc_figure_u.10"></div> <pre> 22815 /usr/bin/rm: cannot remove `libtoolT': No such file or directory 22816 </pre> <p id="doc_section_2_2_2_p_7">This error is harmless and can be safely ignored.</p> 22817<p id="doc_section_2_2_2_p_8">By default, libxo installs architecture-independent files, including extension library files, in the /usr/local directories. To specify an installation prefix other than /usr/local for all installation files, include the --prefix=prefix option and specify an alternate location. To install just the extension library files in a different, user-defined location, include the --with-extensions-dir=dir option and specify the location where the extension libraries will live.</p> 22818<div id="doc_figure_u.11"></div> <pre> 22819 cd build 22820 ../configure [OPTION]... [VAR=VALUE]... 22821 </pre> <p id="doc_section_2_2_2_p_10">Section Contents: </p> 22822<ul> 22823<li><a href="#running-the-make-command" title='Running the "make" command'>Section�2.2.2.1</a></li> 22824<li><a href="#running-the-regression-tests" title="Running the Regression Tests">Section�2.2.2.2</a></li> 22825</ul> 22826<div class="content"> 22827<h4 id="doc_section_2_2_2_1"> 22828<div class="self-section-number"> 22829<a href="#doc_section_2_2_2_1">2.2.2.1</a>�</div> 22830<a id="running-the-make-command" href="#running-the-make-command">Running the "make" command</a> 22831</h4> 22832<p id="doc_section_2_2_2_1_p_1">Once the "configure" script is run, build the images using the "make" command:</p> 22833<div id="doc_figure_u.12"></div> <pre> 22834 make 22835 </pre> </div> 22836<div class="content"> 22837<h4 id="doc_section_2_2_2_2"> 22838<div class="self-section-number"> 22839<a href="#doc_section_2_2_2_2">2.2.2.2</a>�</div> 22840<a id="running-the-regression-tests" href="#running-the-regression-tests">Running the Regression Tests</a> 22841</h4> 22842<p id="doc_section_2_2_2_2_p_1">libxo includes a set of regression tests that can be run to ensure the software is working properly. These test are optional, but will help determine if there are any issues running libxo on your machine. To run the regression tests:</p> 22843<div id="doc_figure_u.13"></div> <pre> 22844 make test 22845 </pre> </div> 22846</div> 22847<div class="content"> 22848<h3 id="doc_section_2_2_3"> 22849<div class="self-section-number"> 22850<a href="#doc_section_2_2_3">2.2.3</a>�</div> 22851<a id="installing-libxo" href="#installing-libxo">Installing libxo</a> 22852</h3> 22853<p id="doc_section_2_2_3_p_1">Once the software is built, you'll need to install libxo using the "make install" command. If you are the root user, or the owner of the installation directory, simply issue the command:</p> 22854<div id="doc_figure_u.14"></div> <pre> 22855 make install 22856 </pre> <p id="doc_section_2_2_3_p_3">If you are not the "root" user and are using the "sudo" package, use:</p> 22857<div id="doc_figure_u.15"></div> <pre> 22858 sudo make install 22859 </pre> <p id="doc_section_2_2_3_p_5">Verify the installation by viewing the output of "xo --version":</p> 22860<div id="doc_figure_u.16"></div> <pre> 22861 % xo --version 22862 libxo version 0.3.5-git-develop 22863 xo version 0.3.5-git-develop 22864 </pre> </div> 22865</div> 22866</div> 22867<hr class="noprint"> 22868<div class="content"> 22869<h1 id="doc_section_3" class="np"> 22870<div class="self-section-number"> 22871<a href="#doc_section_3">3_</a>�</div> 22872<a id="formatting-with-libxo" href="#formatting-with-libxo">Formatting with libxo</a> 22873</h1> 22874<p id="doc_section_3_p_1">Most unix commands emit text output aimed at humans. It is designed to be parsed and understood by a user. Humans are gifted at extracting details and pattern matching in such output. Often programmers need to extract information from this human-oriented output. Programmers use tools like grep, awk, and regular expressions to ferret out the pieces of information they need. Such solutions are fragile and require maintenance when output contents change or evolve, along with testing and validation.</p> 22875<p id="doc_section_3_p_2">Modern tool developers favor encoding schemes like XML and JSON, which allow trivial parsing and extraction of data. Such formats are simple, well understood, hierarchical, easily parsed, and often integrate easier with common tools and environments. Changes to content can be done in ways that do not break existing users of the data, which can reduce maintenance costs and increase feature velocity.</p> 22876<p id="doc_section_3_p_3">In addition, modern reality means that more output ends up in web browsers than in terminals, making HTML output valuable.</p> 22877<p id="doc_section_3_p_4">libxo allows a single set of function calls in source code to generate traditional text output, as well as XML and JSON formatted data. HTML can also be generated; "<div>" elements surround the traditional text output, with attributes that detail how to render the data.</p> 22878<p id="doc_section_3_p_5">A single libxo function call in source code is all that's required:</p> 22879<div id="doc_figure_u.17"></div> <pre> 22880 xo_emit("Connecting to {:host}.{:domain}...\n", host, domain); 22881 22882 TEXT: 22883 Connecting to my-box.example.com... 22884 XML: 22885 <host>my-box</host> 22886 <domain>example.com</domain> 22887 JSON: 22888 "host": "my-box", 22889 "domain": "example.com" 22890 HTML: 22891 <div class="line"> 22892 <div class="text">Connecting to </div> 22893 <div class="data" data-tag="host" 22894 data-xpath="/top/host">my-box</div> 22895 <div class="text">.</div> 22896 <div class="data" data-tag="domain" 22897 data-xpath="/top/domain">example.com</div> 22898 <div class="text">...</div> 22899 </div> 22900 </pre> <p id="doc_section_3_p_7">Section Contents: </p> 22901<ul> 22902<li><a href="#encoding-styles" title="Encoding Styles">Section�3.1</a></li> 22903<li><a href="#format-strings" title="Format Strings">Section�3.2</a></li> 22904<li><a href="#representing-hierarchy" title="Representing Hierarchy">Section�3.3</a></li> 22905</ul> 22906<div class="content"> 22907<h2 id="doc_section_3_1"> 22908<div class="self-section-number"> 22909<a href="#doc_section_3_1">3.1</a>�</div> 22910<a id="encoding-styles" href="#encoding-styles">Encoding Styles</a> 22911</h2> 22912<p id="doc_section_3_1_p_1">There are four encoding styles supported by libxo:</p> 22913<p id="doc_section_3_1_p_2"> </p> 22914<ul> 22915<li>TEXT output can be display on a terminal session, allowing compatibility with traditional command line usage.</li> 22916<li>XML output is suitable for tools like XPath and protocols like NETCONF.</li> 22917<li>JSON output can be used for RESTful APIs and integration with languages like Javascript and Python.</li> 22918<li>HTML can be matched with a small CSS file to permit rendering in any HTML5 browser.</li> 22919</ul> 22920<p id="doc_section_3_1_p_3">In general, XML and JSON are suitable for encoding data, while TEXT is suited for terminal output and HTML is suited for display in a web browser (see <a href="#xohtml" title="xohtml">Section�8</a>).</p> 22921<p id="doc_section_3_1_p_4">Section Contents: </p> 22922<ul> 22923<li><a href="#text-output" title="Text Output">Section�3.1.1</a></li> 22924<li><a href="#xml-output" title="XML Output">Section�3.1.2</a></li> 22925<li><a href="#json-output" title="JSON Output">Section�3.1.3</a></li> 22926<li><a href="#html-output" title="HTML Output">Section�3.1.4</a></li> 22927</ul> 22928<div class="content"> 22929<h3 id="doc_section_3_1_1"> 22930<div class="self-section-number"> 22931<a href="#doc_section_3_1_1">3.1.1</a>�</div> 22932<a id="text-output" href="#text-output">Text Output</a> 22933</h3> 22934<p id="doc_section_3_1_1_p_1">Most traditional programs generate text output on standard output, with contents like:</p> 22935<div id="doc_figure_u.18"></div> <pre> 22936 36 ./src 22937 40 ./bin 22938 90 . 22939 </pre> <p id="doc_section_3_1_1_p_3">In this example (taken from du source code), the code to generate this data might look like:</p> 22940<div id="doc_figure_u.19"></div> <pre> 22941 printf("%d\t%s\n", num_blocks, path); 22942 </pre> <p id="doc_section_3_1_1_p_5">Simple, direct, obvious. But it's only making text output. Imagine using a single code path to make TEXT, XML, JSON or HTML, deciding at run time which to generate.</p> 22943<p id="doc_section_3_1_1_p_6">libxo expands on the idea of printf format strings to make a single format containing instructions for creating multiple output styles:</p> 22944<div id="doc_figure_u.20"></div> <pre> 22945 xo_emit("{:blocks/%d}\t{:path/%s}\n", num_blocks, path); 22946 </pre> <p id="doc_section_3_1_1_p_8">This line will generate the same text output as the earlier printf call, but also has enough information to generate XML, JSON, and HTML.</p> 22947<p id="doc_section_3_1_1_p_9">The following sections introduce the other formats.</p> 22948</div> 22949<div class="content"> 22950<h3 id="doc_section_3_1_2"> 22951<div class="self-section-number"> 22952<a href="#doc_section_3_1_2">3.1.2</a>�</div> 22953<a id="xml-output" href="#xml-output">XML Output</a> 22954</h3> 22955<p id="doc_section_3_1_2_p_1">XML output consists of a hierarchical set of elements, each encoded with a start tag and an end tag. The element should be named for data value that it is encoding:</p> 22956<div id="doc_figure_u.21"></div> <pre> 22957 <item> 22958 <blocks>36</blocks> 22959 <path>./src</path> 22960 </item> 22961 <item> 22962 <blocks>40</blocks> 22963 <path>./bin</path> 22964 </item> 22965 <item> 22966 <blocks>90</blocks> 22967 <path>.</path> 22968 </item> 22969 </pre> <p id="doc_section_3_1_2_p_3">XML is a W3C standard for encoding data. See w3c.org/TR/xml for additional information.</p> 22970</div> 22971<div class="content"> 22972<h3 id="doc_section_3_1_3"> 22973<div class="self-section-number"> 22974<a href="#doc_section_3_1_3">3.1.3</a>�</div> 22975<a id="json-output" href="#json-output">JSON Output</a> 22976</h3> 22977<p id="doc_section_3_1_3_p_1">JSON output consists of a hierarchical set of objects and lists, each encoded with a quoted name, a colon, and a value. If the value is a string, it must be quoted, but numbers are not quoted. Objects are encoded using braces; lists are encoded using square brackets. Data inside objects and lists is separated using commas:</p> 22978<div id="doc_figure_u.22"></div> <pre> 22979 items: [ 22980 { "blocks": 36, "path" : "./src" }, 22981 { "blocks": 40, "path" : "./bin" }, 22982 { "blocks": 90, "path" : "./" } 22983 ] 22984 </pre> </div> 22985<div class="content"> 22986<h3 id="doc_section_3_1_4"> 22987<div class="self-section-number"> 22988<a href="#doc_section_3_1_4">3.1.4</a>�</div> 22989<a id="html-output" href="#html-output">HTML Output</a> 22990</h3> 22991<p id="doc_section_3_1_4_p_1">HTML output is designed to allow the output to be rendered in a web browser with minimal effort. Each piece of output data is rendered inside a <div> element, with a class name related to the role of the data. By using a small set of class attribute values, a CSS stylesheet can render the HTML into rich text that mirrors the traditional text content.</p> 22992<p id="doc_section_3_1_4_p_2">Additional attributes can be enabled to provide more details about the data, including data type, description, and an XPath location.</p> 22993<div id="doc_figure_u.23"></div> <pre> 22994 <div class="line"> 22995 <div class="data" data-tag="blocks">36</div> 22996 <div class="padding"> </div> 22997 <div class="data" data-tag="path">./src</div> 22998 </div> 22999 <div class="line"> 23000 <div class="data" data-tag="blocks">40</div> 23001 <div class="padding"> </div> 23002 <div class="data" data-tag="path">./bin</div> 23003 </div> 23004 <div class="line"> 23005 <div class="data" data-tag="blocks">90</div> 23006 <div class="padding"> </div> 23007 <div class="data" data-tag="path">./</div> 23008 </div> 23009 </pre> </div> 23010</div> 23011<div class="content"> 23012<h2 id="doc_section_3_2"> 23013<div class="self-section-number"> 23014<a href="#doc_section_3_2">3.2</a>�</div> 23015<a id="format-strings" href="#format-strings">Format Strings</a> 23016</h2> 23017<p id="doc_section_3_2_p_1">libxo uses format strings to control the rendering of data into the various output styles. Each format string contains a set of zero or more field descriptions, which describe independent data fields. Each field description contains a set of modifiers, a content string, and zero, one, or two format descriptors. The modifiers tell libxo what the field is and how to treat it, while the format descriptors are formatting instructions using printf-style format strings, telling libxo how to format the field. The field description is placed inside a set of braces, with a colon (":") after the modifiers and a slash ("/") before each format descriptors. Text may be intermixed with field descriptions within the format string.</p> 23018<p id="doc_section_3_2_p_2">The field description is given as follows:</p> 23019<div id="doc_figure_u.24"></div> <pre> 23020 '{' [ role | modifier ]* [',' long-names ]* ':' [ content ] 23021 [ '/' field-format [ '/' encoding-format ]] '}' 23022 </pre> <p id="doc_section_3_2_p_4">The role describes the function of the field, while the modifiers enable optional behaviors. The contents, field-format, and encoding-format are used in varying ways, based on the role. These are described in the following sections.</p> 23023<p id="doc_section_3_2_p_5">In the following example, three field descriptors appear. The first is a padding field containing three spaces of padding, the second is a label ("In stock"), and the third is a value field ("in‑stock"). The in-stock field has a "%u" format that will parse the next argument passed to the xo_emit function as an unsigned integer.</p> 23024<div id="doc_figure_u.25"></div> <pre> 23025 xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n", 65); 23026 </pre> <p id="doc_section_3_2_p_7">This single line of code can generate text (" In stock: 65\n"), XML ("<in‑stock>65</in‑stock>"), JSON ('"in‑stock": 6'), or HTML (too lengthy to be listed here).</p> 23027<p id="doc_section_3_2_p_8">While roles and modifiers typically use single character for brevity, there are alternative names for each which allow more verbose formatting strings. These names must be preceded by a comma, and may follow any single-character values:</p> 23028<div id="doc_figure_u.26"></div> <pre> 23029 xo_emit("{L,white,colon:In stock}{,key:in-stock/%u}\n", 65); 23030 </pre> <p id="doc_section_3_2_p_10">Section Contents: </p> 23031<ul> 23032<li><a href="#field-roles" title="Field Roles">Section�3.2.1</a></li> 23033<li><a href="#field-modifiers" title="Field Modifiers">Section�3.2.2</a></li> 23034<li><a href="#field-formatting" title="Field Formatting">Section�3.2.3</a></li> 23035<li><a href="#utf-8-and-locale-strings" title="UTF-8 and Locale Strings">Section�3.2.4</a></li> 23036<li><a href="#characters-outside-of-field-definitions" title="Characters Outside of Field Definitions">Section�3.2.5</a></li> 23037<li><a href="#m-is-supported" title='"%m" Is Supported'>Section�3.2.6</a></li> 23038<li><a href="#n-is-not-supported" title='"%n" Is Not Supported'>Section�3.2.7</a></li> 23039<li><a href="#the-encoding-format-eformat" title="The Encoding Format (eformat)">Section�3.2.8</a></li> 23040<li><a href="#content-strings" title="Content Strings">Section�3.2.9</a></li> 23041<li><a href="#printf-like" title="Argument Validation">Section�3.2.10</a></li> 23042<li><a href="#retain" title="Retaining Parsed Format Information">Section�3.2.11</a></li> 23043<li><a href="#example" title="Example">Section�3.2.12</a></li> 23044</ul> 23045<div class="content"> 23046<h3 id="doc_section_3_2_1"> 23047<div class="self-section-number"> 23048<a href="#doc_section_3_2_1">3.2.1</a>�</div> 23049<a id="field-roles" href="#field-roles">Field Roles</a> 23050</h3> 23051<p id="doc_section_3_2_1_p_1">Field roles are optional, and indicate the role and formatting of the content. The roles are listed below; only one role is permitted:</p> 23052<div id="doc_table_u.1"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 23053<thead><tr> 23054<th class="left">R</th> 23055<th class="left">Name</th> 23056<th class="left">Description</th> 23057</tr></thead> 23058<tbody> 23059<tr> 23060<td>C</td> 23061<td>color</td> 23062<td>Field has color and effect controls</td> 23063</tr> 23064<tr> 23065<td>D</td> 23066<td>decoration</td> 23067<td>Field is non-text (e.g., colon, comma)</td> 23068</tr> 23069<tr> 23070<td>E</td> 23071<td>error</td> 23072<td>Field is an error message</td> 23073</tr> 23074<tr> 23075<td>G</td> 23076<td>gettext</td> 23077<td>Call gettext(3) on the format string</td> 23078</tr> 23079<tr> 23080<td>L</td> 23081<td>label</td> 23082<td>Field is text that prefixes a value</td> 23083</tr> 23084<tr> 23085<td>N</td> 23086<td>note</td> 23087<td>Field is text that follows a value</td> 23088</tr> 23089<tr> 23090<td>P</td> 23091<td>padding</td> 23092<td>Field is spaces needed for vertical alignment</td> 23093</tr> 23094<tr> 23095<td>T</td> 23096<td>title</td> 23097<td>Field is a title value for headings</td> 23098</tr> 23099<tr> 23100<td>U</td> 23101<td>units</td> 23102<td>Field is the units for the previous value field</td> 23103</tr> 23104<tr> 23105<td>V</td> 23106<td>value</td> 23107<td>Field is the name of field (the default)</td> 23108</tr> 23109<tr> 23110<td>W</td> 23111<td>warning</td> 23112<td>Field is a warning message</td> 23113</tr> 23114<tr> 23115<td>[</td> 23116<td>start-anchor</td> 23117<td>Begin a section of anchored variable-width text</td> 23118</tr> 23119<tr> 23120<td>]</td> 23121<td>stop-anchor</td> 23122<td>End a section of anchored variable-width text</td> 23123</tr> 23124</tbody> 23125</table></div> 23126<div id="doc_figure_u.27"></div> <pre> 23127 EXAMPLE: 23128 xo_emit("{L:Free}{D::}{P: }{:free/%u} {U:Blocks}\n", 23129 free_blocks); 23130 </pre> <p id="doc_section_3_2_1_p_3">When a role is not provided, the "value" role is used as the default.</p> 23131<p id="doc_section_3_2_1_p_4">Roles and modifiers can also use more verbose names, when preceded by a comma:</p> 23132<div id="doc_figure_u.28"></div> <pre> 23133 EXAMPLE: 23134 xo_emit("{,label:Free}{,decoration::}{,padding: }" 23135 "{,value:free/%u} {,units:Blocks}\n", 23136 free_blocks); 23137 </pre> <p id="doc_section_3_2_1_p_6">Section Contents: </p> 23138<ul> 23139<li><a href="#color-role" title="The Color Role ({C:})">Section�3.2.1.1</a></li> 23140<li><a href="#the-decoration-role-d" title="The Decoration Role ({D:})">Section�3.2.1.2</a></li> 23141<li><a href="#gettext-role" title="The Gettext Role ({G:})">Section�3.2.1.3</a></li> 23142<li><a href="#the-label-role-l" title="The Label Role ({L:})">Section�3.2.1.4</a></li> 23143<li><a href="#the-note-role-n" title="The Note Role ({N:})">Section�3.2.1.5</a></li> 23144<li><a href="#padding-role" title="The Padding Role ({P:})">Section�3.2.1.6</a></li> 23145<li><a href="#the-title-role-t" title="The Title Role ({T:})">Section�3.2.1.7</a></li> 23146<li><a href="#the-units-role-u" title="The Units Role ({U:})">Section�3.2.1.8</a></li> 23147<li><a href="#the-value-role-v-and-" title="The Value Role ({V:} and {:})">Section�3.2.1.9</a></li> 23148<li><a href="#anchor-role" title="The Anchor Roles ({[:} and {]:})">Section�3.2.1.10</a></li> 23149</ul> 23150<div class="content"> 23151<h4 id="doc_section_3_2_1_1"> 23152<div class="self-section-number"> 23153<a href="#doc_section_3_2_1_1">3.2.1.1</a>�</div> 23154<a id="color-role" href="#color-role">The Color Role ({C:})</a> 23155</h4> 23156<p id="doc_section_3_2_1_1_p_1">Colors and effects control how text values are displayed; they are used for display styles (TEXT and HTML).</p> 23157<div id="doc_figure_u.29"></div> <pre> 23158 xo_emit("{C:bold}{:value}{C:no-bold}\n", value); 23159 </pre> <p id="doc_section_3_2_1_1_p_3">Colors and effects remain in effect until modified by other "C"-role fields.</p> 23160<div id="doc_figure_u.30"></div> <pre> 23161 xo_emit("{C:bold}{C:inverse}both{C:no-bold}only inverse\n"); 23162 </pre> <p id="doc_section_3_2_1_1_p_5">If the content is empty, the "reset" action is performed.</p> 23163<div id="doc_figure_u.31"></div> <pre> 23164 xo_emit("{C:both,underline}{:value}{C:}\n", value); 23165 </pre> <p id="doc_section_3_2_1_1_p_7">The content should be a comma-separated list of zero or more colors or display effects.</p> 23166<div id="doc_figure_u.32"></div> <pre> 23167 xo_emit("{C:bold,inverse}Ugly{C:no-bold,no-inverse}\n"); 23168 </pre> <p id="doc_section_3_2_1_1_p_9">The color content can be either static, when placed directly within the field descriptor, or a printf-style format descriptor can be used, if preceded by a slash ("/"):</p> 23169<div id="doc_figure_u.33"></div> <pre> 23170 xo_emit("{C:/%s%s}{:value}{C:}", need_bold ? "bold" : "", 23171 need_underline ? "underline" : "", value); 23172 </pre> <p id="doc_section_3_2_1_1_p_11">Color names are prefixed with either "fg‑" or "bg‑" to change the foreground and background colors, respectively.</p> 23173<div id="doc_figure_u.34"></div> <pre> 23174 xo_emit("{C:/fg-%s,bg-%s}{Lwc:Cost}{:cost/%u}{C:reset}\n", 23175 fg_color, bg_color, cost); 23176 </pre> <p id="doc_section_3_2_1_1_p_13">The following table lists the supported effects:</p> 23177<div id="doc_table_u.2"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 23178<thead><tr> 23179<th class="left">Name</th> 23180<th class="left">Description</th> 23181</tr></thead> 23182<tbody> 23183<tr> 23184<td>bg-XXXXX</td> 23185<td>Change background color</td> 23186</tr> 23187<tr> 23188<td>bold</td> 23189<td>Start bold text effect</td> 23190</tr> 23191<tr> 23192<td>fg-XXXXX</td> 23193<td>Change foreground color</td> 23194</tr> 23195<tr> 23196<td>inverse</td> 23197<td>Start inverse (aka reverse) text effect</td> 23198</tr> 23199<tr> 23200<td>no-bold</td> 23201<td>Stop bold text effect</td> 23202</tr> 23203<tr> 23204<td>no-inverse</td> 23205<td>Stop inverse (aka reverse) text effect</td> 23206</tr> 23207<tr> 23208<td>no-underline</td> 23209<td>Stop underline text effect</td> 23210</tr> 23211<tr> 23212<td>normal</td> 23213<td>Reset effects (only)</td> 23214</tr> 23215<tr> 23216<td>reset</td> 23217<td>Reset colors and effects (restore defaults)</td> 23218</tr> 23219<tr> 23220<td>underline</td> 23221<td>Start underline text effect</td> 23222</tr> 23223</tbody> 23224</table></div> 23225<p id="doc_section_3_2_1_1_p_14">The following color names are supported:</p> 23226<div id="doc_table_u.3"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 23227<thead><tr> 23228<th class="left">Name</th> 23229<th class="left">Description</th> 23230</tr></thead> 23231<tbody> 23232<tr> 23233<td>black</td> 23234<td></td> 23235</tr> 23236<tr> 23237<td>blue</td> 23238<td></td> 23239</tr> 23240<tr> 23241<td>cyan</td> 23242<td></td> 23243</tr> 23244<tr> 23245<td>default</td> 23246<td>Default color for foreground or background</td> 23247</tr> 23248<tr> 23249<td>green</td> 23250<td></td> 23251</tr> 23252<tr> 23253<td>magenta</td> 23254<td></td> 23255</tr> 23256<tr> 23257<td>red</td> 23258<td></td> 23259</tr> 23260<tr> 23261<td>white</td> 23262<td></td> 23263</tr> 23264<tr> 23265<td>yellow</td> 23266<td></td> 23267</tr> 23268</tbody> 23269</table></div> 23270<p id="doc_section_3_2_1_1_p_15">When using colors, the developer should remember that users will change the foreground and background colors of terminal session according to their own tastes, so assuming that "blue" looks nice is never safe, and is a constant annoyance to your dear author. In addition, a significant percentage of users (1 in 12) will be color blind. Depending on color to convey critical information is not a good idea. Color should enhance output, but should not be used as the sole means of encoding information.</p> 23271</div> 23272<div class="content"> 23273<h4 id="doc_section_3_2_1_2"> 23274<div class="self-section-number"> 23275<a href="#doc_section_3_2_1_2">3.2.1.2</a>�</div> 23276<a id="the-decoration-role-d" href="#the-decoration-role-d">The Decoration Role ({D:})</a> 23277</h4> 23278<p id="doc_section_3_2_1_2_p_1">Decorations are typically punctuation marks such as colons, semi-colons, and commas used to decorate the text and make it simpler for human readers. By marking these distinctly, HTML usage scenarios can use CSS to direct their display parameters.</p> 23279<div id="doc_figure_u.35"></div> <pre> 23280 xo_emit("{D:((}{:name}{D:))}\n", name); 23281 </pre> </div> 23282<div class="content"> 23283<h4 id="doc_section_3_2_1_3"> 23284<div class="self-section-number"> 23285<a href="#doc_section_3_2_1_3">3.2.1.3</a>�</div> 23286<a id="gettext-role" href="#gettext-role">The Gettext Role ({G:})</a> 23287</h4> 23288<p id="doc_section_3_2_1_3_p_1">libxo supports internationalization (i18n) through its use of gettext(3). Use the "{G:}" role to request that the remaining part of the format string, following the "{G:}" field, be handled using gettext().</p> 23289<p id="doc_section_3_2_1_3_p_2">Since gettext() uses the string as the key into the message catalog, libxo uses a simplified version of the format string that removes unimportant field formatting and modifiers, stopping minor formatting changes from impacting the expensive translation process. A developer change such as changing "/%06d" to "/%08d" should not force hand inspection of all .po files.</p> 23290<p id="doc_section_3_2_1_3_p_3">The simplified version can be generated for a single message using the "xopo -s <text>" command, or an entire .pot can be translated using the "xopo -f <input> -o <output>" command.</p> 23291<div id="doc_figure_u.36"></div> <pre> 23292 xo_emit("{G:}Invalid token\n"); 23293 </pre> <p id="doc_section_3_2_1_3_p_5">The {G:} role allows a domain name to be set. gettext calls will continue to use that domain name until the current format string processing is complete, enabling a library function to emit strings using it's own catalog. The domain name can be either static as the content of the field, or a format can be used to get the domain name from the arguments.</p> 23294<div id="doc_figure_u.37"></div> <pre> 23295 xo_emit("{G:libc}Service unavailable in restricted mode\n"); 23296 </pre> <p id="doc_section_3_2_1_3_p_7">See <a href="#howto-i18n" title="Howto: Internationalization (i18n)">Section�11.5</a> for additional details.</p> 23297</div> 23298<div class="content"> 23299<h4 id="doc_section_3_2_1_4"> 23300<div class="self-section-number"> 23301<a href="#doc_section_3_2_1_4">3.2.1.4</a>�</div> 23302<a id="the-label-role-l" href="#the-label-role-l">The Label Role ({L:})</a> 23303</h4> 23304<p id="doc_section_3_2_1_4_p_1">Labels are text that appears before a value.</p> 23305<div id="doc_figure_u.38"></div> <pre> 23306 xo_emit("{Lwc:Cost}{:cost/%u}\n", cost); 23307 </pre> </div> 23308<div class="content"> 23309<h4 id="doc_section_3_2_1_5"> 23310<div class="self-section-number"> 23311<a href="#doc_section_3_2_1_5">3.2.1.5</a>�</div> 23312<a id="the-note-role-n" href="#the-note-role-n">The Note Role ({N:})</a> 23313</h4> 23314<p id="doc_section_3_2_1_5_p_1">Notes are text that appears after a value.</p> 23315<div id="doc_figure_u.39"></div> <pre> 23316 xo_emit("{:cost/%u} {N:per year}\n", cost); 23317 </pre> </div> 23318<div class="content"> 23319<h4 id="doc_section_3_2_1_6"> 23320<div class="self-section-number"> 23321<a href="#doc_section_3_2_1_6">3.2.1.6</a>�</div> 23322<a id="padding-role" href="#padding-role">The Padding Role ({P:})</a> 23323</h4> 23324<p id="doc_section_3_2_1_6_p_1">Padding represents whitespace used before and between fields.</p> 23325<p id="doc_section_3_2_1_6_p_2">The padding content can be either static, when placed directly within the field descriptor, or a printf-style format descriptor can be used, if preceded by a slash ("/"):</p> 23326<div id="doc_figure_u.40"></div> <pre> 23327 xo_emit("{P: }{Lwc:Cost}{:cost/%u}\n", cost); 23328 xo_emit("{P:/%30s}{Lwc:Cost}{:cost/%u}\n", "", cost); 23329 </pre> </div> 23330<div class="content"> 23331<h4 id="doc_section_3_2_1_7"> 23332<div class="self-section-number"> 23333<a href="#doc_section_3_2_1_7">3.2.1.7</a>�</div> 23334<a id="the-title-role-t" href="#the-title-role-t">The Title Role ({T:})</a> 23335</h4> 23336<p id="doc_section_3_2_1_7_p_1">Title are heading or column headers that are meant to be displayed to the user. The title can be either static, when placed directly within the field descriptor, or a printf-style format descriptor can be used, if preceded by a slash ("/"):</p> 23337<div id="doc_figure_u.41"></div> <pre> 23338 xo_emit("{T:Interface Statistics}\n"); 23339 xo_emit("{T:/%20.20s}{T:/%6.6s}\n", "Item Name", "Cost"); 23340 </pre> <p id="doc_section_3_2_1_7_p_3">Title fields have an extra convenience feature; if both content and format are specified, instead of looking to the argument list for a value, the content is used, allowing a mixture of format and content within the field descriptor:</p> 23341<div id="doc_figure_u.42"></div> <pre> 23342 xo_emit("{T:Name/%20s}{T:Count/%6s}\n"); 23343 </pre> <p id="doc_section_3_2_1_7_p_5">Since the incoming argument is a string, the format must be "%s" or something suitable.</p> 23344</div> 23345<div class="content"> 23346<h4 id="doc_section_3_2_1_8"> 23347<div class="self-section-number"> 23348<a href="#doc_section_3_2_1_8">3.2.1.8</a>�</div> 23349<a id="the-units-role-u" href="#the-units-role-u">The Units Role ({U:})</a> 23350</h4> 23351<p id="doc_section_3_2_1_8_p_1">Units are the dimension by which values are measured, such as degrees, miles, bytes, and decibels. The units field carries this information for the previous value field.</p> 23352<div id="doc_figure_u.43"></div> <pre> 23353 xo_emit("{Lwc:Distance}{:distance/%u}{Uw:miles}\n", miles); 23354 </pre> <p id="doc_section_3_2_1_8_p_3">Note that the sense of the 'w' modifier is reversed for units; a blank is added before the contents, rather than after it.</p> 23355<p id="doc_section_3_2_1_8_p_4">When the XOF_UNITS flag is set, units are rendered in XML as the "units" attribute:</p> 23356<div id="doc_figure_u.44"></div> <pre> 23357 <distance units="miles">50</distance> 23358 </pre> <p id="doc_section_3_2_1_8_p_6">Units can also be rendered in HTML as the "data‑units" attribute:</p> 23359<div id="doc_figure_u.45"></div> <pre> 23360 <div class="data" data-tag="distance" data-units="miles" 23361 data-xpath="/top/data/distance">50</div> 23362 </pre> </div> 23363<div class="content"> 23364<h4 id="doc_section_3_2_1_9"> 23365<div class="self-section-number"> 23366<a href="#doc_section_3_2_1_9">3.2.1.9</a>�</div> 23367<a id="the-value-role-v-and-" href="#the-value-role-v-and-">The Value Role ({V:} and {:})</a> 23368</h4> 23369<p id="doc_section_3_2_1_9_p_1">The value role is used to represent the a data value that is interesting for the non-display output styles (XML and JSON). Value is the default role; if no other role designation is given, the field is a value. The field name must appear within the field descriptor, followed by one or two format descriptors. The first format descriptor is used for display styles (TEXT and HTML), while the second one is used for encoding styles (XML and JSON). If no second format is given, the encoding format defaults to the first format, with any minimum width removed. If no first format is given, both format descriptors default to "%s".</p> 23370<div id="doc_figure_u.46"></div> <pre> 23371 xo_emit("{:length/%02u}x{:width/%02u}x{:height/%02u}\n", 23372 length, width, height); 23373 xo_emit("{:author} wrote \"{:poem}\" in {:year/%4d}\n, 23374 author, poem, year); 23375 </pre> </div> 23376<div class="content"> 23377<h4 id="doc_section_3_2_1_10"> 23378<div class="self-section-number"> 23379<a href="#doc_section_3_2_1_10">3.2.1.10</a>�</div> 23380<a id="anchor-role" href="#anchor-role">The Anchor Roles ({[:} and {]:})</a> 23381</h4> 23382<p id="doc_section_3_2_1_10_p_1">The anchor roles allow a set of strings by be padded as a group, but still be visible to xo_emit as distinct fields. Either the start or stop anchor can give a field width and it can be either directly in the descriptor or passed as an argument. Any fields between the start and stop anchor are padded to meet the minimum width given.</p> 23383<p id="doc_section_3_2_1_10_p_2">To give a width directly, encode it as the content of the anchor tag:</p> 23384<div id="doc_figure_u.47"></div> <pre> 23385 xo_emit("({[:10}{:min/%d}/{:max/%d}{]:})\n", min, max); 23386 </pre> <p id="doc_section_3_2_1_10_p_4">To pass a width as an argument, use "%d" as the format, which must appear after the "/". Note that only "%d" is supported for widths. Using any other value could ruin your day.</p> 23387<div id="doc_figure_u.48"></div> <pre> 23388 xo_emit("({[:/%d}{:min/%d}/{:max/%d}{]:})\n", width, min, max); 23389 </pre> <p id="doc_section_3_2_1_10_p_6">If the width is negative, padding will be added on the right, suitable for left justification. Otherwise the padding will be added to the left of the fields between the start and stop anchors, suitable for right justification. If the width is zero, nothing happens. If the number of columns of output between the start and stop anchors is less than the absolute value of the given width, nothing happens.</p> 23390<p id="doc_section_3_2_1_10_p_7">Widths over 8k are considered probable errors and not supported. If XOF_WARN is set, a warning will be generated.</p> 23391</div> 23392</div> 23393<div class="content"> 23394<h3 id="doc_section_3_2_2"> 23395<div class="self-section-number"> 23396<a href="#doc_section_3_2_2">3.2.2</a>�</div> 23397<a id="field-modifiers" href="#field-modifiers">Field Modifiers</a> 23398</h3> 23399<p id="doc_section_3_2_2_p_1">Field modifiers are flags which modify the way content emitted for particular output styles:</p> 23400<div id="doc_table_u.4"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 23401<thead><tr> 23402<th class="left">M</th> 23403<th class="left">Name</th> 23404<th class="left">Description</th> 23405</tr></thead> 23406<tbody> 23407<tr> 23408<td>a</td> 23409<td>argument</td> 23410<td>The content appears as a 'const char *' argument</td> 23411</tr> 23412<tr> 23413<td>c</td> 23414<td>colon</td> 23415<td>A colon (":") is appended after the label</td> 23416</tr> 23417<tr> 23418<td>d</td> 23419<td>display</td> 23420<td>Only emit field for display styles (text/HTML)</td> 23421</tr> 23422<tr> 23423<td>e</td> 23424<td>encoding</td> 23425<td>Only emit for encoding styles (XML/JSON)</td> 23426</tr> 23427<tr> 23428<td>g</td> 23429<td>gettext</td> 23430<td>Call gettext on field's render content</td> 23431</tr> 23432<tr> 23433<td>h</td> 23434<td>humanize (hn)</td> 23435<td>Format large numbers in human-readable style</td> 23436</tr> 23437<tr> 23438<td></td> 23439<td>hn-space</td> 23440<td>Humanize: Place space between numeric and unit</td> 23441</tr> 23442<tr> 23443<td></td> 23444<td>hn-decimal</td> 23445<td>Humanize: Add a decimal digit, if number < 10</td> 23446</tr> 23447<tr> 23448<td></td> 23449<td>hn-1000</td> 23450<td>Humanize: Use 1000 as divisor instead of 1024</td> 23451</tr> 23452<tr> 23453<td>k</td> 23454<td>key</td> 23455<td>Field is a key, suitable for XPath predicates</td> 23456</tr> 23457<tr> 23458<td>l</td> 23459<td>leaf-list</td> 23460<td>Field is a leaf-list</td> 23461</tr> 23462<tr> 23463<td>n</td> 23464<td>no-quotes</td> 23465<td>Do not quote the field when using JSON style</td> 23466</tr> 23467<tr> 23468<td>p</td> 23469<td>plural</td> 23470<td>Gettext: Use comma-separated plural form</td> 23471</tr> 23472<tr> 23473<td>q</td> 23474<td>quotes</td> 23475<td>Quote the field when using JSON style</td> 23476</tr> 23477<tr> 23478<td>t</td> 23479<td>trim</td> 23480<td>Trim leading and trailing whitespace</td> 23481</tr> 23482<tr> 23483<td>w</td> 23484<td>white</td> 23485<td>A blank (" ") is appended after the label</td> 23486</tr> 23487</tbody> 23488</table></div> 23489<p id="doc_section_3_2_2_p_2">Roles and modifiers can also use more verbose names, when preceded by a comma. For example, the modifier string "Lwc" (or "L,white,colon") means the field has a label role (text that describes the next field) and should be followed by a colon ('c') and a space ('w'). The modifier string "Vkq" (or ":key,quote") means the field has a value role (the default role), that it is a key for the current instance, and that the value should be quoted when encoded for JSON.</p> 23490<p id="doc_section_3_2_2_p_3">Section Contents: </p> 23491<ul> 23492<li><a href="#the-argument-modifier-a" title="The Argument Modifier ({a:})">Section�3.2.2.1</a></li> 23493<li><a href="#the-colon-modifier-c" title="The Colon Modifier ({c:})">Section�3.2.2.2</a></li> 23494<li><a href="#the-display-modifier-d" title="The Display Modifier ({d:})">Section�3.2.2.3</a></li> 23495<li><a href="#e-modifier" title="The Encoding Modifier ({e:})">Section�3.2.2.4</a></li> 23496<li><a href="#gettext-modifier" title="The Gettext Modifier ({g:})">Section�3.2.2.5</a></li> 23497<li><a href="#the-humanize-modifier-h" title="The Humanize Modifier ({h:})">Section�3.2.2.6</a></li> 23498<li><a href="#the-key-modifier-k" title="The Key Modifier ({k:})">Section�3.2.2.7</a></li> 23499<li><a href="#the-leaf-list-modifier-l" title="The Leaf-List Modifier ({l:})">Section�3.2.2.8</a></li> 23500<li><a href="#the-no-quotes-modifier-n" title="The No-Quotes Modifier ({n:})">Section�3.2.2.9</a></li> 23501<li><a href="#plural-modifier" title="The Plural Modifier ({p:})">Section�3.2.2.10</a></li> 23502<li><a href="#the-quotes-modifier-q" title="The Quotes Modifier ({q:})">Section�3.2.2.11</a></li> 23503<li><a href="#the-trim-modifier-t" title="The Trim Modifier ({t:})">Section�3.2.2.12</a></li> 23504<li><a href="#the-white-space-modifier-w" title="The White Space Modifier ({w:})">Section�3.2.2.13</a></li> 23505</ul> 23506<div class="content"> 23507<h4 id="doc_section_3_2_2_1"> 23508<div class="self-section-number"> 23509<a href="#doc_section_3_2_2_1">3.2.2.1</a>�</div> 23510<a id="the-argument-modifier-a" href="#the-argument-modifier-a">The Argument Modifier ({a:})</a> 23511</h4> 23512<p id="doc_section_3_2_2_1_p_1">The argument modifier indicates that the content of the field descriptor will be placed as a UTF-8 string (const char *) argument within the xo_emit parameters.</p> 23513<div id="doc_figure_u.49"></div> <pre> 23514 EXAMPLE: 23515 xo_emit("{La:} {a:}\n", "Label text", "label", "value"); 23516 TEXT: 23517 Label text value 23518 JSON: 23519 "label": "value" 23520 XML: 23521 <label>value</label> 23522 </pre> <p id="doc_section_3_2_2_1_p_3">The argument modifier allows field names for value fields to be passed on the stack, avoiding the need to build a field descriptor using snprintf. For many field roles, the argument modifier is not needed, since those roles have specific mechanisms for arguments, such as "{C:fg‑%s}".</p> 23523</div> 23524<div class="content"> 23525<h4 id="doc_section_3_2_2_2"> 23526<div class="self-section-number"> 23527<a href="#doc_section_3_2_2_2">3.2.2.2</a>�</div> 23528<a id="the-colon-modifier-c" href="#the-colon-modifier-c">The Colon Modifier ({c:})</a> 23529</h4> 23530<p id="doc_section_3_2_2_2_p_1">The colon modifier appends a single colon to the data value:</p> 23531<div id="doc_figure_u.50"></div> <pre> 23532 EXAMPLE: 23533 xo_emit("{Lc:Name}{:name}\n", "phil"); 23534 TEXT: 23535 Name:phil 23536 </pre> <p id="doc_section_3_2_2_2_p_3">The colon modifier is only used for the TEXT and HTML output styles. It is commonly combined with the space modifier ('{w:}'). It is purely a convenience feature.</p> 23537</div> 23538<div class="content"> 23539<h4 id="doc_section_3_2_2_3"> 23540<div class="self-section-number"> 23541<a href="#doc_section_3_2_2_3">3.2.2.3</a>�</div> 23542<a id="the-display-modifier-d" href="#the-display-modifier-d">The Display Modifier ({d:})</a> 23543</h4> 23544<p id="doc_section_3_2_2_3_p_1">The display modifier indicated the field should only be generated for the display output styles, TEXT and HTML.</p> 23545<div id="doc_figure_u.51"></div> <pre> 23546 EXAMPLE: 23547 xo_emit("{Lcw:Name}{d:name} {:id/%d}\n", "phil", 1); 23548 TEXT: 23549 Name: phil 1 23550 XML: 23551 <id>1</id> 23552 </pre> <p id="doc_section_3_2_2_3_p_3">The display modifier is the opposite of the encoding modifier, and they are often used to give to distinct views of the underlying data.</p> 23553</div> 23554<div class="content"> 23555<h4 id="doc_section_3_2_2_4"> 23556<div class="self-section-number"> 23557<a href="#doc_section_3_2_2_4">3.2.2.4</a>�</div> 23558<a id="e-modifier" href="#e-modifier">The Encoding Modifier ({e:})</a> 23559</h4> 23560<p id="doc_section_3_2_2_4_p_1">The display modifier indicated the field should only be generated for the display output styles, TEXT and HTML.</p> 23561<div id="doc_figure_u.52"></div> <pre> 23562 EXAMPLE: 23563 xo_emit("{Lcw:Name}{:name} {e:id/%d}\n", "phil", 1); 23564 TEXT: 23565 Name: phil 23566 XML: 23567 <name>phil</name><id>1</id> 23568 </pre> <p id="doc_section_3_2_2_4_p_3">The encoding modifier is the opposite of the display modifier, and they are often used to give to distinct views of the underlying data.</p> 23569</div> 23570<div class="content"> 23571<h4 id="doc_section_3_2_2_5"> 23572<div class="self-section-number"> 23573<a href="#doc_section_3_2_2_5">3.2.2.5</a>�</div> 23574<a id="gettext-modifier" href="#gettext-modifier">The Gettext Modifier ({g:})</a> 23575</h4> 23576<p id="doc_section_3_2_2_5_p_1">The gettext modifier is used to translate individual fields using the gettext domain (typically set using the "{G:}" role) and current language settings. Once libxo renders the field value, it is passed to gettext(3), where it is used as a key to find the native language translation.</p> 23577<p id="doc_section_3_2_2_5_p_2">In the following example, the strings "State" and "full" are passed to gettext() to find locale-based translated strings.</p> 23578<div id="doc_figure_u.53"></div> <pre> 23579 xo_emit("{Lgwc:State}{g:state}\n", "full"); 23580 </pre> <p id="doc_section_3_2_2_5_p_4">See <a href="#gettext-role" title="The Gettext Role ({G:})">Section�3.2.1.3</a>, <a href="#plural-modifier" title="The Plural Modifier ({p:})">Section�3.2.2.10</a>, and <a href="#howto-i18n" title="Howto: Internationalization (i18n)">Section�11.5</a> for additional details.</p> 23581</div> 23582<div class="content"> 23583<h4 id="doc_section_3_2_2_6"> 23584<div class="self-section-number"> 23585<a href="#doc_section_3_2_2_6">3.2.2.6</a>�</div> 23586<a id="the-humanize-modifier-h" href="#the-humanize-modifier-h">The Humanize Modifier ({h:})</a> 23587</h4> 23588<p id="doc_section_3_2_2_6_p_1">The humanize modifier is used to render large numbers as in a human-readable format. While numbers like "44470272" are completely readable to computers and savants, humans will generally find "44M" more meaningful.</p> 23589<p id="doc_section_3_2_2_6_p_2">"hn" can be used as an alias for "humanize".</p> 23590<p id="doc_section_3_2_2_6_p_3">The humanize modifier only affects display styles (TEXT and HMTL). The "no‑humanize" option (See <a href="#options" title="Command-line Arguments">Section�4</a>) will block the function of the humanize modifier.</p> 23591<p id="doc_section_3_2_2_6_p_4">There are a number of modifiers that affect details of humanization. These are only available in as full names, not single characters. The "hn‑space" modifier places a space between the number and any multiplier symbol, such as "M" or "K" (ex: "44 K"). The "hn‑decimal" modifier will add a decimal point and a single tenths digit when the number is less than 10 (ex: "4.4K"). The "hn‑1000" modifier will use 1000 as divisor instead of 1024, following the JEDEC-standard instead of the more natural binary powers-of-two tradition.</p> 23592<div id="doc_figure_u.54"></div> <pre> 23593 EXAMPLE: 23594 xo_emit("{h:input/%u}, {h,hn-space:output/%u}, " 23595 "{h,hn-decimal:errors/%u}, {h,hn-1000:capacity/%u}, " 23596 "{h,hn-decimal:remaining/%u}\n", 23597 input, output, errors, capacity, remaining); 23598 TEXT: 23599 21, 57 K, 96M, 44M, 1.2G 23600 </pre> <p id="doc_section_3_2_2_6_p_6">In the HTML style, the original numeric value is rendered in the "data‑number" attribute on the <div> element:</p> 23601<div id="doc_figure_u.55"></div> <pre> 23602 <div class="data" data-tag="errors" 23603 data-number="100663296">96M</div> 23604 </pre> </div> 23605<div class="content"> 23606<h4 id="doc_section_3_2_2_7"> 23607<div class="self-section-number"> 23608<a href="#doc_section_3_2_2_7">3.2.2.7</a>�</div> 23609<a id="the-key-modifier-k" href="#the-key-modifier-k">The Key Modifier ({k:})</a> 23610</h4> 23611<p id="doc_section_3_2_2_7_p_1">The key modifier is used to indicate that a particular field helps uniquely identify an instance of list data.</p> 23612<div id="doc_figure_u.56"></div> <pre> 23613 EXAMPLE: 23614 xo_open_list("user"); 23615 for (i = 0; i < num_users; i++) { 23616 xo_open_instance("user"); 23617 xo_emit("User {k:name} has {:count} tickets\n", 23618 user[i].u_name, user[i].u_tickets); 23619 xo_close_instance("user"); 23620 } 23621 xo_close_list("user"); 23622 </pre> <p id="doc_section_3_2_2_7_p_3">Currently the key modifier is only used when generating XPath value for the HTML output style when XOF_XPATH is set, but other uses are likely in the near future.</p> 23623</div> 23624<div class="content"> 23625<h4 id="doc_section_3_2_2_8"> 23626<div class="self-section-number"> 23627<a href="#doc_section_3_2_2_8">3.2.2.8</a>�</div> 23628<a id="the-leaf-list-modifier-l" href="#the-leaf-list-modifier-l">The Leaf-List Modifier ({l:})</a> 23629</h4> 23630<p id="doc_section_3_2_2_8_p_1">The leaf-list modifier is used to distinguish lists where each instance consists of only a single value. In XML, these are rendered as single elements, where JSON renders them as arrays.</p> 23631<div id="doc_figure_u.57"></div> <pre> 23632 EXAMPLE: 23633 for (i = 0; i < num_users; i++) { 23634 xo_emit("Member {l:user}\n", user[i].u_name); 23635 } 23636 XML: 23637 <user>phil</user> 23638 <user>pallavi</user> 23639 JSON: 23640 "user": [ "phil", "pallavi" ] 23641 </pre> <p id="doc_section_3_2_2_8_p_3">The name of the field must match the name of the leaf list.</p> 23642</div> 23643<div class="content"> 23644<h4 id="doc_section_3_2_2_9"> 23645<div class="self-section-number"> 23646<a href="#doc_section_3_2_2_9">3.2.2.9</a>�</div> 23647<a id="the-no-quotes-modifier-n" href="#the-no-quotes-modifier-n">The No-Quotes Modifier ({n:})</a> 23648</h4> 23649<p id="doc_section_3_2_2_9_p_1">The no-quotes modifier (and its twin, the 'quotes' modifier) affect the quoting of values in the JSON output style. JSON uses quotes for string value, but no quotes for numeric, boolean, and null data. xo_emit applies a simple heuristic to determine whether quotes are needed, but often this needs to be controlled by the caller.</p> 23650<div id="doc_figure_u.58"></div> <pre> 23651 EXAMPLE: 23652 const char *bool = is_true ? "true" : "false"; 23653 xo_emit("{n:fancy/%s}", bool); 23654 JSON: 23655 "fancy": true 23656 </pre> </div> 23657<div class="content"> 23658<h4 id="doc_section_3_2_2_10"> 23659<div class="self-section-number"> 23660<a href="#doc_section_3_2_2_10">3.2.2.10</a>�</div> 23661<a id="plural-modifier" href="#plural-modifier">The Plural Modifier ({p:})</a> 23662</h4> 23663<p id="doc_section_3_2_2_10_p_1">The plural modifier selects the appropriate plural form of an expression based on the most recent number emitted and the current language settings. The contents of the field should be the singular and plural English values, separated by a comma:</p> 23664<div id="doc_figure_u.59"></div> <pre> 23665 xo_emit("{:bytes} {Ngp:byte,bytes}\n", bytes); 23666 </pre> <p id="doc_section_3_2_2_10_p_3">The plural modifier is meant to work with the gettext modifier ({g:}) but can work independently. See <a href="#gettext-modifier" title="The Gettext Modifier ({g:})">Section�3.2.2.5</a>.</p> 23667<p id="doc_section_3_2_2_10_p_4">When used without the gettext modifier or when the message does not appear in the message catalog, the first token is chosen when the last numeric value is equal to 1; otherwise the second value is used, mimicking the simple pluralization rules of English.</p> 23668<p id="doc_section_3_2_2_10_p_5">When used with the gettext modifier, the ngettext(3) function is called to handle the heavy lifting, using the message catalog to convert the singular and plural forms into the native language.</p> 23669</div> 23670<div class="content"> 23671<h4 id="doc_section_3_2_2_11"> 23672<div class="self-section-number"> 23673<a href="#doc_section_3_2_2_11">3.2.2.11</a>�</div> 23674<a id="the-quotes-modifier-q" href="#the-quotes-modifier-q">The Quotes Modifier ({q:})</a> 23675</h4> 23676<p id="doc_section_3_2_2_11_p_1">The quotes modifier (and its twin, the 'no‑quotes' modifier) affect the quoting of values in the JSON output style. JSON uses quotes for string value, but no quotes for numeric, boolean, and null data. xo_emit applies a simple heuristic to determine whether quotes are needed, but often this needs to be controlled by the caller.</p> 23677<div id="doc_figure_u.60"></div> <pre> 23678 EXAMPLE: 23679 xo_emit("{q:time/%d}", 2014); 23680 JSON: 23681 "year": "2014" 23682 </pre> <p id="doc_section_3_2_2_11_p_3">The heuristic is based on the format; if the format uses any of the following conversion specifiers, then no quotes are used:</p> 23683<div id="doc_figure_u.61"></div> <pre> 23684 d i o u x X D O U e E f F g G a A c C p 23685 </pre> </div> 23686<div class="content"> 23687<h4 id="doc_section_3_2_2_12"> 23688<div class="self-section-number"> 23689<a href="#doc_section_3_2_2_12">3.2.2.12</a>�</div> 23690<a id="the-trim-modifier-t" href="#the-trim-modifier-t">The Trim Modifier ({t:})</a> 23691</h4> 23692<p id="doc_section_3_2_2_12_p_1">The trim modifier removes any leading or trailing whitespace from the value.</p> 23693<div id="doc_figure_u.62"></div> <pre> 23694 EXAMPLE: 23695 xo_emit("{t:description}", " some input "); 23696 JSON: 23697 "description": "some input" 23698 </pre> </div> 23699<div class="content"> 23700<h4 id="doc_section_3_2_2_13"> 23701<div class="self-section-number"> 23702<a href="#doc_section_3_2_2_13">3.2.2.13</a>�</div> 23703<a id="the-white-space-modifier-w" href="#the-white-space-modifier-w">The White Space Modifier ({w:})</a> 23704</h4> 23705<p id="doc_section_3_2_2_13_p_1">The white space modifier appends a single space to the data value:</p> 23706<div id="doc_figure_u.63"></div> <pre> 23707 EXAMPLE: 23708 xo_emit("{Lw:Name}{:name}\n", "phil"); 23709 TEXT: 23710 Name phil 23711 </pre> <p id="doc_section_3_2_2_13_p_3">The white space modifier is only used for the TEXT and HTML output styles. It is commonly combined with the colon modifier ('{c:}'). It is purely a convenience feature.</p> 23712<p id="doc_section_3_2_2_13_p_4">Note that the sense of the 'w' modifier is reversed for the units role ({Uw:}); a blank is added before the contents, rather than after it.</p> 23713</div> 23714</div> 23715<div class="content"> 23716<h3 id="doc_section_3_2_3"> 23717<div class="self-section-number"> 23718<a href="#doc_section_3_2_3">3.2.3</a>�</div> 23719<a id="field-formatting" href="#field-formatting">Field Formatting</a> 23720</h3> 23721<p id="doc_section_3_2_3_p_1">The field format is similar to the format string for printf(3). Its use varies based on the role of the field, but generally is used to format the field's contents.</p> 23722<p id="doc_section_3_2_3_p_2">If the format string is not provided for a value field, it defaults to "%s".</p> 23723<p id="doc_section_3_2_3_p_3">Note a field definition can contain zero or more printf-style 'directives', which are sequences that start with a '%' and end with one of following characters: "diouxXDOUeEfFgGaAcCsSp". Each directive is matched by one of more arguments to the xo_emit function.</p> 23724<p id="doc_section_3_2_3_p_4">The format string has the form:</p> 23725<div id="doc_figure_u.64"></div> <pre> 23726 '%' format-modifier * format-character 23727 </pre> <p id="doc_section_3_2_3_p_6">The format- modifier can be:</p> 23728<p id="doc_section_3_2_3_p_7"> </p> 23729<ul> 23730<li>a '#' character, indicating the output value should be prefixed with '0x', typically to indicate a base 16 (hex) value.</li> 23731<li>a minus sign ('‑'), indicating the output value should be padded on the right instead of the left.</li> 23732<li>a leading zero ('0') indicating the output value should be padded on the left with zeroes instead of spaces (' ').</li> 23733<li>one or more digits ('0' - '9') indicating the minimum width of the argument. If the width in columns of the output value is less than the minimum width, the value will be padded to reach the minimum.</li> 23734<li>a period followed by one or more digits indicating the maximum number of bytes which will be examined for a string argument, or the maximum width for a non-string argument. When handling ASCII strings this functions as the field width but for multi-byte characters, a single character may be composed of multiple bytes. xo_emit will never dereference memory beyond the given number of bytes.</li> 23735<li>a second period followed by one or more digits indicating the maximum width for a string argument. This modifier cannot be given for non-string arguments.</li> 23736<li>one or more 'h' characters, indicating shorter input data.</li> 23737<li>one or more 'l' characters, indicating longer input data.</li> 23738<li>a 'z' character, indicating a 'size_t' argument.</li> 23739<li>a 't' character, indicating a 'ptrdiff_t' argument.</li> 23740<li>a ' ' character, indicating a space should be emitted before positive numbers.</li> 23741<li>a '+' character, indicating sign should emitted before any number.</li> 23742</ul> 23743<p id="doc_section_3_2_3_p_8">Note that 'q', 'D', 'O', and 'U' are considered deprecated and will be removed eventually.</p> 23744<p id="doc_section_3_2_3_p_9">The format character is described in the following table:</p> 23745<div id="doc_table_u.5"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 23746<thead><tr> 23747<th class="left">Ltr</th> 23748<th class="left">Argument Type</th> 23749<th class="left">Format</th> 23750</tr></thead> 23751<tbody> 23752<tr> 23753<td>d</td> 23754<td>int</td> 23755<td>base 10 (decimal)</td> 23756</tr> 23757<tr> 23758<td>i</td> 23759<td>int</td> 23760<td>base 10 (decimal)</td> 23761</tr> 23762<tr> 23763<td>o</td> 23764<td>int</td> 23765<td>base 8 (octal)</td> 23766</tr> 23767<tr> 23768<td>u</td> 23769<td>unsigned</td> 23770<td>base 10 (decimal)</td> 23771</tr> 23772<tr> 23773<td>x</td> 23774<td>unsigned</td> 23775<td>base 16 (hex)</td> 23776</tr> 23777<tr> 23778<td>X</td> 23779<td>unsigned long</td> 23780<td>base 16 (hex)</td> 23781</tr> 23782<tr> 23783<td>D</td> 23784<td>long</td> 23785<td>base 10 (decimal)</td> 23786</tr> 23787<tr> 23788<td>O</td> 23789<td>unsigned long</td> 23790<td>base 8 (octal)</td> 23791</tr> 23792<tr> 23793<td>U</td> 23794<td>unsigned long</td> 23795<td>base 10 (decimal)</td> 23796</tr> 23797<tr> 23798<td>e</td> 23799<td>double</td> 23800<td>[-]d.ddde+-dd</td> 23801</tr> 23802<tr> 23803<td>E</td> 23804<td>double</td> 23805<td>[-]d.dddE+-dd</td> 23806</tr> 23807<tr> 23808<td>f</td> 23809<td>double</td> 23810<td>[-]ddd.ddd</td> 23811</tr> 23812<tr> 23813<td>F</td> 23814<td>double</td> 23815<td>[-]ddd.ddd</td> 23816</tr> 23817<tr> 23818<td>g</td> 23819<td>double</td> 23820<td>as 'e' or 'f'</td> 23821</tr> 23822<tr> 23823<td>G</td> 23824<td>double</td> 23825<td>as 'E' or 'F'</td> 23826</tr> 23827<tr> 23828<td>a</td> 23829<td>double</td> 23830<td>[-]0xh.hhhp[+-]d</td> 23831</tr> 23832<tr> 23833<td>A</td> 23834<td>double</td> 23835<td>[-]0Xh.hhhp[+-]d</td> 23836</tr> 23837<tr> 23838<td>c</td> 23839<td>unsigned char</td> 23840<td>a character</td> 23841</tr> 23842<tr> 23843<td>C</td> 23844<td>wint_t</td> 23845<td>a character</td> 23846</tr> 23847<tr> 23848<td>s</td> 23849<td>char *</td> 23850<td>a UTF-8 string</td> 23851</tr> 23852<tr> 23853<td>S</td> 23854<td>wchar_t *</td> 23855<td>a unicode/WCS string</td> 23856</tr> 23857<tr> 23858<td>p</td> 23859<td>void *</td> 23860<td>'%#lx'</td> 23861</tr> 23862</tbody> 23863</table></div> 23864<p id="doc_section_3_2_3_p_10">The 'h' and 'l' modifiers affect the size and treatment of the argument:</p> 23865<div id="doc_table_u.6"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 23866<thead><tr> 23867<th class="left">Mod</th> 23868<th class="left">d, i</th> 23869<th class="left">o, u, x, X</th> 23870</tr></thead> 23871<tbody> 23872<tr> 23873<td>hh</td> 23874<td>signed char</td> 23875<td>unsigned char</td> 23876</tr> 23877<tr> 23878<td>h</td> 23879<td>short</td> 23880<td>unsigned short</td> 23881</tr> 23882<tr> 23883<td>l</td> 23884<td>long</td> 23885<td>unsigned long</td> 23886</tr> 23887<tr> 23888<td>ll</td> 23889<td>long long</td> 23890<td>unsigned long long</td> 23891</tr> 23892<tr> 23893<td>j</td> 23894<td>intmax_t</td> 23895<td>uintmax_t</td> 23896</tr> 23897<tr> 23898<td>t</td> 23899<td>ptrdiff_t</td> 23900<td>ptrdiff_t</td> 23901</tr> 23902<tr> 23903<td>z</td> 23904<td>size_t</td> 23905<td>size_t</td> 23906</tr> 23907<tr> 23908<td>q</td> 23909<td>quad_t</td> 23910<td>u_quad_t</td> 23911</tr> 23912</tbody> 23913</table></div> 23914</div> 23915<div class="content"> 23916<h3 id="doc_section_3_2_4"> 23917<div class="self-section-number"> 23918<a href="#doc_section_3_2_4">3.2.4</a>�</div> 23919<a id="utf-8-and-locale-strings" href="#utf-8-and-locale-strings">UTF-8 and Locale Strings</a> 23920</h3> 23921<p id="doc_section_3_2_4_p_1">For strings, the 'h' and 'l' modifiers affect the interpretation of the bytes pointed to argument. The default '%s' string is a 'char *' pointer to a string encoded as UTF-8. Since UTF-8 is compatible with ASCII data, a normal 7-bit ASCII string can be used. '%ls' expects a 'wchar_t *' pointer to a wide-character string, encoded as a 32-bit Unicode values. '%hs' expects a 'char *' pointer to a multi-byte string encoded with the current locale, as given by the LC_CTYPE, LANG, or LC_ALL environment varibles. The first of this list of variables is used and if none of the variables are set, the locale defaults to "UTF‑8".</p> 23922<p id="doc_section_3_2_4_p_2">libxo will convert these arguments as needed to either UTF-8 (for XML, JSON, and HTML styles) or locale-based strings for display in text style.</p> 23923<div id="doc_figure_u.65"></div> <pre> 23924 xo_emit("All strings are utf-8 content {:tag/%ls}", 23925 L"except for wide strings"); 23926 </pre> <p id="doc_section_3_2_4_p_4">"%S" is equivalent to "%ls".</p> 23927<div id="doc_table_u.7"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 23928<thead><tr> 23929<th class="left">Format</th> 23930<th class="left">Argument Type</th> 23931<th class="left">Argument Contents</th> 23932</tr></thead> 23933<tbody> 23934<tr> 23935<td>%s</td> 23936<td>const char *</td> 23937<td>UTF-8 string</td> 23938</tr> 23939<tr> 23940<td>%S</td> 23941<td>const char *</td> 23942<td>UTF-8 string (alias for '%s')</td> 23943</tr> 23944<tr> 23945<td>%ls</td> 23946<td>const wchar_t *</td> 23947<td>Wide character UNICODE string</td> 23948</tr> 23949<tr> 23950<td>%hs</td> 23951<td>const char *</td> 23952<td>locale-based string</td> 23953</tr> 23954</tbody> 23955</table></div> 23956<p id="doc_section_3_2_4_p_5">For example, a function is passed a locale-base name, a hat size, and a time value. The hat size is formatted in a UTF-8 (ASCII) string, and the time value is formatted into a wchar_t string.</p> 23957<div id="doc_figure_u.66"></div> <pre> 23958 void print_order (const char *name, int size, 23959 struct tm *timep) { 23960 char buf[32]; 23961 const char *size_val = "unknown"; 23962 23963 if (size > 0) 23964 snprintf(buf, sizeof(buf), "%d", size); 23965 size_val = buf; 23966 } 23967 23968 wchar_t when[32]; 23969 wcsftime(when, sizeof(when), L"%d%b%y", timep); 23970 23971 xo_emit("The hat for {:name/%hs} is {:size/%s}.\n", 23972 name, size_val); 23973 xo_emit("It was ordered on {:order-time/%ls}.\n", 23974 when); 23975 } 23976 </pre> <p id="doc_section_3_2_4_p_7">It is important to note that xo_emit will perform the conversion required to make appropriate output. Text style output uses the current locale (as described above), while XML, JSON, and HTML use UTF-8.</p> 23977<p id="doc_section_3_2_4_p_8">UTF-8 and locale-encoded strings can use multiple bytes to encode one column of data. The traditional "precision'" (aka "max‑width") value for "%s" printf formatting becomes overloaded since it specifies both the number of bytes that can be safely referenced and the maximum number of columns to emit. xo_emit uses the precision as the former, and adds a third value for specifying the maximum number of columns.</p> 23978<p id="doc_section_3_2_4_p_9">In this example, the name field is printed with a minimum of 3 columns and a maximum of 6. Up to ten bytes of data at the location given by 'name' are in used in filling those columns.</p> 23979<div id="doc_figure_u.67"></div> <pre> 23980 xo_emit("{:name/%3.10.6s}", name); 23981 </pre> </div> 23982<div class="content"> 23983<h3 id="doc_section_3_2_5"> 23984<div class="self-section-number"> 23985<a href="#doc_section_3_2_5">3.2.5</a>�</div> 23986<a id="characters-outside-of-field-definitions" href="#characters-outside-of-field-definitions">Characters Outside of Field Definitions</a> 23987</h3> 23988<p id="doc_section_3_2_5_p_1">Characters in the format string that are not part of a field definition are copied to the output for the TEXT style, and are ignored for the JSON and XML styles. For HTML, these characters are placed in a <div> with class "text".</p> 23989<div id="doc_figure_u.68"></div> <pre> 23990 EXAMPLE: 23991 xo_emit("The hat is {:size/%s}.\n", size_val); 23992 TEXT: 23993 The hat is extra small. 23994 XML: 23995 <size>extra small</size> 23996 JSON: 23997 "size": "extra small" 23998 HTML: 23999 <div class="text">The hat is </div> 24000 <div class="data" data-tag="size">extra small</div> 24001 <div class="text">.</div> 24002 </pre> </div> 24003<div class="content"> 24004<h3 id="doc_section_3_2_6"> 24005<div class="self-section-number"> 24006<a href="#doc_section_3_2_6">3.2.6</a>�</div> 24007<a id="m-is-supported" href="#m-is-supported">"%m" Is Supported</a> 24008</h3> 24009<p id="doc_section_3_2_6_p_1">libxo supports the '%m' directive, which formats the error message associated with the current value of "errno". It is the equivalent of "%s" with the argument strerror(errno).</p> 24010<div id="doc_figure_u.69"></div> <pre> 24011 xo_emit("{:filename} cannot be opened: {:error/%m}", filename); 24012 xo_emit("{:filename} cannot be opened: {:error/%s}", 24013 filename, strerror(errno)); 24014 </pre> </div> 24015<div class="content"> 24016<h3 id="doc_section_3_2_7"> 24017<div class="self-section-number"> 24018<a href="#doc_section_3_2_7">3.2.7</a>�</div> 24019<a id="n-is-not-supported" href="#n-is-not-supported">"%n" Is Not Supported</a> 24020</h3> 24021<p id="doc_section_3_2_7_p_1">libxo does not support the '%n' directive. It's a bad idea and we just don't do it.</p> 24022</div> 24023<div class="content"> 24024<h3 id="doc_section_3_2_8"> 24025<div class="self-section-number"> 24026<a href="#doc_section_3_2_8">3.2.8</a>�</div> 24027<a id="the-encoding-format-eformat" href="#the-encoding-format-eformat">The Encoding Format (eformat)</a> 24028</h3> 24029<p id="doc_section_3_2_8_p_1">The "eformat" string is the format string used when encoding the field for JSON and XML. If not provided, it defaults to the primary format with any minimum width removed. If the primary is not given, both default to "%s".</p> 24030</div> 24031<div class="content"> 24032<h3 id="doc_section_3_2_9"> 24033<div class="self-section-number"> 24034<a href="#doc_section_3_2_9">3.2.9</a>�</div> 24035<a id="content-strings" href="#content-strings">Content Strings</a> 24036</h3> 24037<p id="doc_section_3_2_9_p_1">For padding and labels, the content string is considered the content, unless a format is given.</p> 24038</div> 24039<div class="content"> 24040<h3 id="doc_section_3_2_10"> 24041<div class="self-section-number"> 24042<a href="#doc_section_3_2_10">3.2.10</a>�</div> 24043<a id="printf-like" href="#printf-like">Argument Validation</a> 24044</h3> 24045<p id="doc_section_3_2_10_p_1">Many compilers and tool chains support validation of printf-like arguments. When the format string fails to match the argument list, a warning is generated. This is a valuable feature and while the formatting strings for libxo differ considerably from printf, many of these checks can still provide build-time protection against bugs.</p> 24046<p id="doc_section_3_2_10_p_2">libxo provide variants of functions that provide this ability, if the "‑‑enable‑printflike" option is passed to the "configure" script. These functions use the "_p" suffix, like "xo_emit_p()", xo_emit_hp()", etc.</p> 24047<p id="doc_section_3_2_10_p_3">The following are features of libxo formatting strings that are incompatible with printf-like testing:</p> 24048<p id="doc_section_3_2_10_p_4"> </p> 24049<ul> 24050<li>implicit formats, where "{:tag}" has an implicit "%s";</li> 24051<li>the "max" parameter for strings, where "{:tag/%4.10.6s}" means up to ten bytes of data can be inspected to fill a minimum of 4 columns and a maximum of 6;</li> 24052<li>percent signs in strings, where "{:filled}%" makes a single, trailing percent sign;</li> 24053<li>the "l" and "h" modifiers for strings, where "{:tag/%hs}" means locale-based string and "{:tag/%ls}" means a wide character string;</li> 24054<li>distinct encoding formats, where "{:tag/#%s/%s}" means the display styles (text and HTML) will use "#%s" where other styles use "%s";</li> 24055</ul> 24056<p id="doc_section_3_2_10_p_5">If none of these features are in use by your code, then using the "_p" variants might be wise.</p> 24057<div id="doc_table_u.8"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 24058<thead><tr> 24059<th class="left">Function</th> 24060<th class="left">printf-like Equivalent</th> 24061</tr></thead> 24062<tbody> 24063<tr> 24064<td>xo_emit_hv</td> 24065<td>xo_emit_hvp</td> 24066</tr> 24067<tr> 24068<td>xo_emit_h</td> 24069<td>xo_emit_hp</td> 24070</tr> 24071<tr> 24072<td>xo_emit</td> 24073<td>xo_emit_p</td> 24074</tr> 24075<tr> 24076<td>xo_emit_warn_hcv</td> 24077<td>xo_emit_warn_hcvp</td> 24078</tr> 24079<tr> 24080<td>xo_emit_warn_hc</td> 24081<td>xo_emit_warn_hcp</td> 24082</tr> 24083<tr> 24084<td>xo_emit_warn_c</td> 24085<td>xo_emit_warn_cp</td> 24086</tr> 24087<tr> 24088<td>xo_emit_warn</td> 24089<td>xo_emit_warn_p</td> 24090</tr> 24091<tr> 24092<td>xo_emit_warnx_</td> 24093<td>xo_emit_warnx_p</td> 24094</tr> 24095<tr> 24096<td>xo_emit_err</td> 24097<td>xo_emit_err_p</td> 24098</tr> 24099<tr> 24100<td>xo_emit_errx</td> 24101<td>xo_emit_errx_p</td> 24102</tr> 24103<tr> 24104<td>xo_emit_errc</td> 24105<td>xo_emit_errc_p</td> 24106</tr> 24107</tbody> 24108</table></div> 24109</div> 24110<div class="content"> 24111<h3 id="doc_section_3_2_11"> 24112<div class="self-section-number"> 24113<a href="#doc_section_3_2_11">3.2.11</a>�</div> 24114<a id="retain" href="#retain">Retaining Parsed Format Information</a> 24115</h3> 24116<p id="doc_section_3_2_11_p_1">libxo can retain the parsed internal information related to the given format string, allowing subsequent xo_emit calls, the retained information is used, avoiding repetitive parsing of the format string.</p> 24117<div id="doc_figure_u.70"></div> <pre> 24118 SYNTAX: 24119 int xo_emit_f(xo_emit_flags_t flags, const char fmt, ...); 24120 EXAMPLE: 24121 xo_emit_f(XOEF_RETAIN, "{:some/%02d}{:thing/%-6s}{:fancy}\n", 24122 some, thing, fancy); 24123 </pre> <p id="doc_section_3_2_11_p_3">To retain parsed format information, use the XOEF_RETAIN flag to the xo_emit_f() function. A complete set of xo_emit_f functions exist to match all the xo_emit function signatures (with handles, varadic argument, and printf-like flags):</p> 24124<div id="doc_table_u.9"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 24125<thead><tr> 24126<th class="left">Function</th> 24127<th class="left">Flags Equivalent</th> 24128</tr></thead> 24129<tbody> 24130<tr> 24131<td>xo_emit_hv</td> 24132<td>xo_emit_hvf</td> 24133</tr> 24134<tr> 24135<td>xo_emit_h</td> 24136<td>xo_emit_hf</td> 24137</tr> 24138<tr> 24139<td>xo_emit</td> 24140<td>xo_emit_f</td> 24141</tr> 24142<tr> 24143<td>xo_emit_hvp</td> 24144<td>xo_emit_hvfp</td> 24145</tr> 24146<tr> 24147<td>xo_emit_hp</td> 24148<td>xo_emit_hfp</td> 24149</tr> 24150<tr> 24151<td>xo_emit_p</td> 24152<td>xo_emit_fp</td> 24153</tr> 24154</tbody> 24155</table></div> 24156<p id="doc_section_3_2_11_p_4">The format string must be immutable across multiple calls to xo_emit_f(), since the library retains the string. Typically this is done by using static constant strings, such as string literals. If the string is not immutable, the XOEF_RETAIN flag must not be used.</p> 24157<p id="doc_section_3_2_11_p_5">The functions xo_retain_clear() and xo_retain_clear_all() release internal information on either a single format string or all format strings, respectively. Neither is required, but the library will retain this information until it is cleared or the process exits.</p> 24158<div id="doc_figure_u.71"></div> <pre> 24159 const char *fmt = "{:name} {:count/%d}\n"; 24160 for (i = 0; i < 1000; i++) { 24161 xo_open_instance("item"); 24162 xo_emit_f(XOEF_RETAIN, fmt, name[i], count[i]); 24163 } 24164 xo_retain_clear(fmt); 24165 </pre> <p id="doc_section_3_2_11_p_7">The retained information is kept as thread-specific data.</p> 24166</div> 24167<div class="content"> 24168<h3 id="doc_section_3_2_12"> 24169<div class="self-section-number"> 24170<a href="#doc_section_3_2_12">3.2.12</a>�</div> 24171<a id="example" href="#example">Example</a> 24172</h3> 24173<p id="doc_section_3_2_12_p_1">In this example, the value for the number of items in stock is emitted:</p> 24174<div id="doc_figure_u.72"></div> <pre> 24175 xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n", 24176 instock); 24177 </pre> <p id="doc_section_3_2_12_p_3">This call will generate the following output:</p> 24178<div id="doc_figure_u.73"></div> <pre> 24179 TEXT: 24180 In stock: 144 24181 XML: 24182 <in-stock>144</in-stock> 24183 JSON: 24184 "in-stock": 144, 24185 HTML: 24186 <div class="line"> 24187 <div class="padding"> </div> 24188 <div class="label">In stock</div> 24189 <div class="decoration">:</div> 24190 <div class="padding"> </div> 24191 <div class="data" data-tag="in-stock">144</div> 24192 </div> 24193 </pre> <p id="doc_section_3_2_12_p_5">Clearly HTML wins the verbosity award, and this output does not include XOF_XPATH or XOF_INFO data, which would expand the penultimate line to:</p> 24194<div id="doc_figure_u.74"></div> <pre> 24195 <div class="data" data-tag="in-stock" 24196 data-xpath="/top/data/item/in-stock" 24197 data-type="number" 24198 data-help="Number of items in stock">144</div> 24199 </pre> </div> 24200</div> 24201<div class="content"> 24202<h2 id="doc_section_3_3"> 24203<div class="self-section-number"> 24204<a href="#doc_section_3_3">3.3</a>�</div> 24205<a id="representing-hierarchy" href="#representing-hierarchy">Representing Hierarchy</a> 24206</h2> 24207<p id="doc_section_3_3_p_1">For XML and JSON, individual fields appear inside hierarchies which provide context and meaning to the fields. Unfortunately, these encoding have a basic disconnect between how lists is similar objects are represented.</p> 24208<p id="doc_section_3_3_p_2">XML encodes lists as set of sequential elements:</p> 24209<div id="doc_figure_u.75"></div> <pre> 24210 <user>phil</user> 24211 <user>pallavi</user> 24212 <user>sjg</user> 24213 </pre> <p id="doc_section_3_3_p_4">JSON encodes lists using a single name and square brackets:</p> 24214<div id="doc_figure_u.76"></div> <pre> 24215 "user": [ "phil", "pallavi", "sjg" ] 24216 </pre> <p id="doc_section_3_3_p_6">This means libxo needs three distinct indications of hierarchy: one for containers of hierarchy appear only once for any specific parent, one for lists, and one for each item in a list.</p> 24217<p id="doc_section_3_3_p_7">Section Contents: </p> 24218<ul> 24219<li><a href="#containers" title="Containers">Section�3.3.1</a></li> 24220<li><a href="#lists-and-instances" title="Lists and Instances">Section�3.3.2</a></li> 24221<li><a href="#dtrt-mode" title="DTRT Mode">Section�3.3.3</a></li> 24222<li><a href="#markers" title="Markers">Section�3.3.4</a></li> 24223</ul> 24224<div class="content"> 24225<h3 id="doc_section_3_3_1"> 24226<div class="self-section-number"> 24227<a href="#doc_section_3_3_1">3.3.1</a>�</div> 24228<a id="containers" href="#containers">Containers</a> 24229</h3> 24230<p id="doc_section_3_3_1_p_1">A "container" is an element of a hierarchy that appears only once under any specific parent. The container has no value, but serves to contain other nodes.</p> 24231<p id="doc_section_3_3_1_p_2">To open a container, call xo_open_container() or xo_open_container_h(). The former uses the default handle and the latter accepts a specific handle.</p> 24232<div id="doc_figure_u.77"></div> <pre> 24233 int xo_open_container_h (xo_handle_t *xop, const char *name); 24234 int xo_open_container (const char *name); 24235 </pre> <p id="doc_section_3_3_1_p_4">To close a level, use the xo_close_container() or xo_close_container_h() functions:</p> 24236<div id="doc_figure_u.78"></div> <pre> 24237 int xo_close_container_h (xo_handle_t *xop, const char *name); 24238 int xo_close_container (const char *name); 24239 </pre> <p id="doc_section_3_3_1_p_6">Each open call must have a matching close call. If the XOF_WARN flag is set and the name given does not match the name of the currently open container, a warning will be generated.</p> 24240<div id="doc_figure_u.79"></div> <pre> 24241 Example: 24242 24243 xo_open_container("top"); 24244 xo_open_container("system"); 24245 xo_emit("{:host-name/%s%s%s", hostname, 24246 domainname ? "." : "", domainname ?: ""); 24247 xo_close_container("system"); 24248 xo_close_container("top"); 24249 24250 Sample Output: 24251 Text: 24252 my-host.example.org 24253 XML: 24254 <top> 24255 <system> 24256 <host-name>my-host.example.org</host-name> 24257 </system> 24258 </top> 24259 JSON: 24260 "top" : { 24261 "system" : { 24262 "host-name": "my-host.example.org" 24263 } 24264 } 24265 HTML: 24266 <div class="data" 24267 data-tag="host-name">my-host.example.org</div> 24268 </pre> </div> 24269<div class="content"> 24270<h3 id="doc_section_3_3_2"> 24271<div class="self-section-number"> 24272<a href="#doc_section_3_3_2">3.3.2</a>�</div> 24273<a id="lists-and-instances" href="#lists-and-instances">Lists and Instances</a> 24274</h3> 24275<p id="doc_section_3_3_2_p_1">A list is set of one or more instances that appear under the same parent. The instances contain details about a specific object. One can think of instances as objects or records. A call is needed to open and close the list, while a distinct call is needed to open and close each instance of the list:</p> 24276<div id="doc_figure_u.80"></div> <pre> 24277 xo_open_list("item"); 24278 24279 for (ip = list; ip->i_title; ip++) { 24280 xo_open_instance("item"); 24281 xo_emit("{L:Item} '{:name/%s}':\n", ip->i_title); 24282 xo_close_instance("item"); 24283 } 24284 24285 xo_close_list("item"); 24286 </pre> <p id="doc_section_3_3_2_p_3">Getting the list and instance calls correct is critical to the proper generation of XML and JSON data.</p> 24287</div> 24288<div class="content"> 24289<h3 id="doc_section_3_3_3"> 24290<div class="self-section-number"> 24291<a href="#doc_section_3_3_3">3.3.3</a>�</div> 24292<a id="dtrt-mode" href="#dtrt-mode">DTRT Mode</a> 24293</h3> 24294<p id="doc_section_3_3_3_p_1">Some users may find tracking the names of open containers, lists, and instances inconvenient. libxo offers a "Do The Right Thing" mode, where libxo will track the names of open containers, lists, and instances so the close function can be called without a name. To enable DTRT mode, turn on the XOF_DTRT flag prior to making any other libxo output.</p> 24295<div id="doc_figure_u.81"></div> <pre> 24296 xo_set_flags(NULL, XOF_DTRT); 24297 </pre> <p id="doc_section_3_3_3_p_3">Each open and close function has a version with the suffix "_d", which will close the open container, list, or instance:</p> 24298<div id="doc_figure_u.82"></div> <pre> 24299 xo_open_container("top"); 24300 ... 24301 xo_close_container_d(); 24302 </pre> <p id="doc_section_3_3_3_p_5">This also works for lists and instances:</p> 24303<div id="doc_figure_u.83"></div> <pre> 24304 xo_open_list("item"); 24305 for (...) { 24306 xo_open_instance("item"); 24307 xo_emit(...); 24308 xo_close_instance_d(); 24309 } 24310 xo_close_list_d(); 24311 </pre> <p id="doc_section_3_3_3_p_7">Note that the XOF_WARN flag will also cause libxo to track open containers, lists, and instances. A warning is generated when the name given to the close function and the name recorded do not match.</p> 24312</div> 24313<div class="content"> 24314<h3 id="doc_section_3_3_4"> 24315<div class="self-section-number"> 24316<a href="#doc_section_3_3_4">3.3.4</a>�</div> 24317<a id="markers" href="#markers">Markers</a> 24318</h3> 24319<p id="doc_section_3_3_4_p_1">Markers are used to protect and restore the state of open constructs. While a marker is open, no other open constructs can be closed. When a marker is closed, all constructs open since the marker was opened will be closed.</p> 24320<p id="doc_section_3_3_4_p_2">Markers use names which are not user-visible, allowing the caller to choose appropriate internal names.</p> 24321<p id="doc_section_3_3_4_p_3">In this example, the code whiffles through a list of fish, calling a function to emit details about each fish. The marker "fish‑guts" is used to ensure that any constructs opened by the function are closed properly.</p> 24322<div id="doc_figure_u.84"></div> <pre> 24323 for (i = 0; fish[i]; i++) { 24324 xo_open_instance("fish"); 24325 xo_open_marker("fish-guts"); 24326 dump_fish_details(i); 24327 xo_close_marker("fish-guts"); 24328 } 24329 </pre> </div> 24330</div> 24331</div> 24332<hr class="noprint"> 24333<div class="content"> 24334<h1 id="doc_section_4" class="np"> 24335<div class="self-section-number"> 24336<a href="#doc_section_4">4_</a>�</div> 24337<a id="options" href="#options">Command-line Arguments</a> 24338</h1> 24339<p id="doc_section_4_p_1">libxo uses command line options to trigger rendering behavior. The following options are recognised:</p> 24340<p id="doc_section_4_p_2"> </p> 24341<ul> 24342<li>--libxo <options></li> 24343<li>--libxo=<options></li> 24344<li>--libxo:<brief‑options></li> 24345</ul> 24346<p id="doc_section_4_p_3">The following invocations are all identical in outcome:</p> 24347<div id="doc_figure_u.85"></div> <pre> 24348 my-app --libxo warn,pretty arg1 24349 my-app --libxo=warn,pretty arg1 24350 my-app --libxo:WP arg1 24351 </pre> <p id="doc_section_4_p_5">Programs using libxo are expecting to call the xo_parse_args function to parse these arguments. See <a href="#xo_parse_args" title="Parsing Command-line Arguments (xo_parse_args)">Section�5.4.1</a> for details.</p> 24352<p id="doc_section_4_p_6">Section Contents: </p> 24353<ul> 24354<li><a href="#option-keywords" title="Option keywords">Section�4.1</a></li> 24355<li><a href="#brief-options" title="Brief Options">Section�4.2</a></li> 24356<li><a href="#color-mapping" title="Color Mapping">Section�4.3</a></li> 24357</ul> 24358<div class="content"> 24359<h2 id="doc_section_4_1"> 24360<div class="self-section-number"> 24361<a href="#doc_section_4_1">4.1</a>�</div> 24362<a id="option-keywords" href="#option-keywords">Option keywords</a> 24363</h2> 24364<p id="doc_section_4_1_p_1">Options is a comma-separated list of tokens that correspond to output styles, flags, or features:</p> 24365<div id="doc_table_u.10"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 24366<thead><tr> 24367<th class="left">Token</th> 24368<th class="left">Action</th> 24369</tr></thead> 24370<tbody> 24371<tr> 24372<td>color</td> 24373<td>Enable colors/effects for display styles (TEXT, HTML)</td> 24374</tr> 24375<tr> 24376<td>colors=xxxx</td> 24377<td>Adjust color output values</td> 24378</tr> 24379<tr> 24380<td>dtrt</td> 24381<td>Enable "Do The Right Thing" mode</td> 24382</tr> 24383<tr> 24384<td>flush</td> 24385<td>Flush after every libxo function call</td> 24386</tr> 24387<tr> 24388<td>flush-line</td> 24389<td>Flush after every line (line-buffered)</td> 24390</tr> 24391<tr> 24392<td>html</td> 24393<td>Emit HTML output</td> 24394</tr> 24395<tr> 24396<td>indent=xx</td> 24397<td>Set the indentation level</td> 24398</tr> 24399<tr> 24400<td>info</td> 24401<td>Add info attributes (HTML)</td> 24402</tr> 24403<tr> 24404<td>json</td> 24405<td>Emit JSON output</td> 24406</tr> 24407<tr> 24408<td>keys</td> 24409<td>Emit the key attribute for keys (XML)</td> 24410</tr> 24411<tr> 24412<td>log-gettext</td> 24413<td>Log (via stderr) each gettext(3) string lookup</td> 24414</tr> 24415<tr> 24416<td>log-syslog</td> 24417<td>Log (via stderr) each syslog message (via xo_syslog)</td> 24418</tr> 24419<tr> 24420<td>no-humanize</td> 24421<td>Ignore the {h:} modifier (TEXT, HTML)</td> 24422</tr> 24423<tr> 24424<td>no-locale</td> 24425<td>Do not initialize the locale setting</td> 24426</tr> 24427<tr> 24428<td>no-retain</td> 24429<td>Prevent retaining formatting information</td> 24430</tr> 24431<tr> 24432<td>no-top</td> 24433<td>Do not emit a top set of braces (JSON)</td> 24434</tr> 24435<tr> 24436<td>not-first</td> 24437<td>Pretend the 1st output item was not 1st (JSON)</td> 24438</tr> 24439<tr> 24440<td>pretty</td> 24441<td>Emit pretty-printed output</td> 24442</tr> 24443<tr> 24444<td>retain</td> 24445<td>Force retaining formatting information</td> 24446</tr> 24447<tr> 24448<td>text</td> 24449<td>Emit TEXT output</td> 24450</tr> 24451<tr> 24452<td>underscores</td> 24453<td>Replace XML-friendly "-"s with JSON friendly "_"s</td> 24454</tr> 24455<tr> 24456<td>units</td> 24457<td>Add the 'units' (XML) or 'data-units (HTML) attribute</td> 24458</tr> 24459<tr> 24460<td>warn</td> 24461<td>Emit warnings when libxo detects bad calls</td> 24462</tr> 24463<tr> 24464<td>warn-xml</td> 24465<td>Emit warnings in XML</td> 24466</tr> 24467<tr> 24468<td>xml</td> 24469<td>Emit XML output</td> 24470</tr> 24471<tr> 24472<td>xpath</td> 24473<td>Add XPath expressions (HTML)</td> 24474</tr> 24475</tbody> 24476</table></div> 24477<p id="doc_section_4_1_p_2">Most of these option are simple and direct, but some require additional details:</p> 24478<p id="doc_section_4_1_p_3"> </p> 24479<ul> 24480<li>"colors" is described in <a href="#color-mapping" title="Color Mapping">Section�4.3</a>.</li> 24481<li>"flush‑line" performs line buffering, even when the output is not directed to a TTY device.</li> 24482<li>"info" generates additional data for HTML, encoded in attributes using names that state with "data‑".</li> 24483<li>"keys" adds a "key" attribute for XML output to indicate that a leaf is an identifier for the list member.</li> 24484<li>"no‑humanize"avoids "humanizing" numeric output (see humanize_number(3) for details).</li> 24485<li>"no‑locale" instructs libxo to avoid translating output to the current locale.</li> 24486<li>"no‑retain" disables the ability of libxo to internally retain "compiled" information about formatting strings.</li> 24487<li>"underscores" can be used with JSON output to change XML-friendly names with dashes into JSON-friendly name with underscores.</li> 24488<li>"warn" allows libxo to emit warnings on stderr when application code make incorrect calls.</li> 24489<li>"warn‑xml" causes those warnings to be placed in XML inside the output.</li> 24490</ul> 24491</div> 24492<div class="content"> 24493<h2 id="doc_section_4_2"> 24494<div class="self-section-number"> 24495<a href="#doc_section_4_2">4.2</a>�</div> 24496<a id="brief-options" href="#brief-options">Brief Options</a> 24497</h2> 24498<p id="doc_section_4_2_p_1">The brief options are simple single-letter aliases to the normal keywords, as detailed below:</p> 24499<div id="doc_table_u.11"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 24500<thead><tr> 24501<th class="left">Option</th> 24502<th class="left">Action</th> 24503</tr></thead> 24504<tbody> 24505<tr> 24506<td>c</td> 24507<td>Enable color/effects for TEXT/HTML</td> 24508</tr> 24509<tr> 24510<td>F</td> 24511<td>Force line-buffered flushing</td> 24512</tr> 24513<tr> 24514<td>H</td> 24515<td>Enable HTML output (XO_STYLE_HTML)</td> 24516</tr> 24517<tr> 24518<td>I</td> 24519<td>Enable info output (XOF_INFO)</td> 24520</tr> 24521<tr> 24522<td>i<num></td> 24523<td>Indent by <number></td> 24524</tr> 24525<tr> 24526<td>J</td> 24527<td>Enable JSON output (XO_STYLE_JSON)</td> 24528</tr> 24529<tr> 24530<td>k</td> 24531<td>Add keys to XPATH expressions in HTML</td> 24532</tr> 24533<tr> 24534<td>n</td> 24535<td>Disable humanization (TEXT, HTML)</td> 24536</tr> 24537<tr> 24538<td>P</td> 24539<td>Enable pretty-printed output (XOF_PRETTY)</td> 24540</tr> 24541<tr> 24542<td>T</td> 24543<td>Enable text output (XO_STYLE_TEXT)</td> 24544</tr> 24545<tr> 24546<td>U</td> 24547<td>Add units to HTML output</td> 24548</tr> 24549<tr> 24550<td>u</td> 24551<td>Change "-"s to "_"s in element names (JSON)</td> 24552</tr> 24553<tr> 24554<td>W</td> 24555<td>Enable warnings (XOF_WARN)</td> 24556</tr> 24557<tr> 24558<td>X</td> 24559<td>Enable XML output (XO_STYLE_XML)</td> 24560</tr> 24561<tr> 24562<td>x</td> 24563<td>Enable XPath data (XOF_XPATH)</td> 24564</tr> 24565</tbody> 24566</table></div> 24567</div> 24568<div class="content"> 24569<h2 id="doc_section_4_3"> 24570<div class="self-section-number"> 24571<a href="#doc_section_4_3">4.3</a>�</div> 24572<a id="color-mapping" href="#color-mapping">Color Mapping</a> 24573</h2> 24574<p id="doc_section_4_3_p_1">The "colors" option takes a value that is a set of mappings from the pre-defined set of colors to new foreground and background colors. The value is a series of "fg/bg" values, separated by a "+". Each pair of "fg/bg" values gives the colors to which a basic color is mapped when used as a foreground or background color. The order is the mappings is:</p> 24575<p id="doc_section_4_3_p_2"> </p> 24576<ul> 24577<li>black</li> 24578<li>red</li> 24579<li>green</li> 24580<li>yellow</li> 24581<li>blue</li> 24582<li>magenta</li> 24583<li>cyan</li> 24584<li>white</li> 24585</ul> 24586<p id="doc_section_4_3_p_3">Pairs may be skipped, leaving them mapped as normal, as are missing pairs or single colors.</p> 24587<p id="doc_section_4_3_p_4">For example consider the following xo_emit call:</p> 24588<div id="doc_figure_u.86"></div> <pre> 24589 xo_emit("{C:fg-red,bg-green}Merry XMas!!{C:}\n"); 24590 </pre> <p id="doc_section_4_3_p_6">To turn all colored output to red-on-blue, use eight pairs of "red/blue" mappings separated by "+"s:</p> 24591<div id="doc_figure_u.87"></div> <pre> 24592 --libxo colors=red/blue+red/blue+red/blue+red/blue+\ 24593 red/blue+red/blue+red/blue+red/blue 24594 </pre> <p id="doc_section_4_3_p_8">To turn the red-on-green text to magenta-on-cyan, give a "magenta" foreground value for red (the second mapping) and a "cyan" background to green (the third mapping):</p> 24595<div id="doc_figure_u.88"></div> <pre> 24596 --libxo colors=+magenta+/cyan 24597 </pre> <p id="doc_section_4_3_p_10">Consider the common situation where blue output looks unreadable on a terminal session with a black background. To turn both "blue" foreground and background output to "yellow", give only the fifth mapping, skipping the first four mappings with bare "+"s:</p> 24598<div id="doc_figure_u.89"></div> <pre> 24599 --libxo colors=++++yellow/yellow 24600 </pre> </div> 24601</div> 24602<hr class="noprint"> 24603<div class="content"> 24604<h1 id="doc_section_5" class="np"> 24605<div class="self-section-number"> 24606<a href="#doc_section_5">5_</a>�</div> 24607<a id="the-libxo-api" href="#the-libxo-api">The libxo API</a> 24608</h1> 24609<p id="doc_section_5_p_1">This section gives details about the functions in libxo, how to call them, and the actions they perform.</p> 24610<p id="doc_section_5_p_2">Section Contents: </p> 24611<ul> 24612<li><a href="#handles" title="Handles">Section�5.1</a></li> 24613<li><a href="#emitting-content-xo_emit" title="Emitting Content (xo_emit)">Section�5.2</a></li> 24614<li><a href="#emitting-hierarchy" title="Emitting Hierarchy">Section�5.3</a></li> 24615<li><a href="#support-functions" title="Support Functions">Section�5.4</a></li> 24616<li><a href="#emitting-syslog-messages" title="Emitting syslog Messages">Section�5.5</a></li> 24617<li><a href="#creating-custom-encoders" title="Creating Custom Encoders">Section�5.6</a></li> 24618</ul> 24619<div class="content"> 24620<h2 id="doc_section_5_1"> 24621<div class="self-section-number"> 24622<a href="#doc_section_5_1">5.1</a>�</div> 24623<a id="handles" href="#handles">Handles</a> 24624</h2> 24625<p id="doc_section_5_1_p_1">libxo uses "handles" to control its rendering functionality. The handle contains state and buffered data, as well as callback functions to process data.</p> 24626<p id="doc_section_5_1_p_2">Handles give an abstraction for libxo that encapsulates the state of a stream of output. Handles have the data type "xo_handle_t" and are opaque to the caller.</p> 24627<p id="doc_section_5_1_p_3">The library has a default handle that is automatically initialized. By default, this handle will send text style output (XO_STYLE_TEXT) to standard output. The xo_set_style and xo_set_flags functions can be used to change this behavior.</p> 24628<p id="doc_section_5_1_p_4">For the typical command that is generating output on standard output, there is no need to create an explicit handle, but they are available when needed, e.g., for daemons that generate multiple streams of output.</p> 24629<p id="doc_section_5_1_p_5">Many libxo functions take a handle as their first parameter; most that do not use the default handle. Any function taking a handle can be passed NULL to access the default handle. For the convenience of callers, the libxo library includes handle-less functions that implicitly use the default handle.</p> 24630<p id="doc_section_5_1_p_6">For example, the following are equivalent:</p> 24631<div id="doc_figure_u.90"></div> <pre> 24632 xo_emit("test"); 24633 xo_emit_h(NULL, "test"); 24634 </pre> <p id="doc_section_5_1_p_8">Handles are created using xo_create() and destroy using xo_destroy().</p> 24635<p id="doc_section_5_1_p_9">Section Contents: </p> 24636<ul> 24637<li><a href="#xo_create" title="xo_create">Section�5.1.1</a></li> 24638<li><a href="#xo_create_to_file" title="xo_create_to_file">Section�5.1.2</a></li> 24639<li><a href="#xo_set_writer" title="xo_set_writer">Section�5.1.3</a></li> 24640<li><a href="#xo_set_style" title="xo_set_style">Section�5.1.4</a></li> 24641<li><a href="#xo_get_style" title="xo_get_style">Section�5.1.5</a></li> 24642<li><a href="#xo_set_flags" title="xo_set_flags">Section�5.1.6</a></li> 24643<li><a href="#xo_destroy" title="xo_destroy">Section�5.1.7</a></li> 24644</ul> 24645<div class="content"> 24646<h3 id="doc_section_5_1_1"> 24647<div class="self-section-number"> 24648<a href="#doc_section_5_1_1">5.1.1</a>�</div> 24649<a id="xo_create" href="#xo_create">xo_create</a> 24650</h3> 24651<p id="doc_section_5_1_1_p_1">A handle can be allocated using the xo_create() function:</p> 24652<div id="doc_figure_u.91"></div> <pre> 24653 xo_handle_t *xo_create (unsigned style, unsigned flags); 24654 24655 Example: 24656 xo_handle_t *xop = xo_create(XO_STYLE_JSON, XOF_WARN); 24657 .... 24658 xo_emit_h(xop, "testing\n"); 24659 </pre> <p id="doc_section_5_1_1_p_3">See also <a href="#styles" title="Output Styles (XO_STYLE_*)">Section�5.1.5.1</a> and <a href="#flags" title="Flags (XOF_*)">Section�5.1.6.1</a>.</p> 24660</div> 24661<div class="content"> 24662<h3 id="doc_section_5_1_2"> 24663<div class="self-section-number"> 24664<a href="#doc_section_5_1_2">5.1.2</a>�</div> 24665<a id="xo_create_to_file" href="#xo_create_to_file">xo_create_to_file</a> 24666</h3> 24667<p id="doc_section_5_1_2_p_1">By default, libxo writes output to standard output. A convenience function is provided for situations when output should be written to a different file:</p> 24668<div id="doc_figure_u.92"></div> <pre> 24669 xo_handle_t *xo_create_to_file (FILE *fp, unsigned style, 24670 unsigned flags); 24671 </pre> <p id="doc_section_5_1_2_p_3">Use the XOF_CLOSE_FP flag to trigger a call to fclose() for the FILE pointer when the handle is destroyed.</p> 24672</div> 24673<div class="content"> 24674<h3 id="doc_section_5_1_3"> 24675<div class="self-section-number"> 24676<a href="#doc_section_5_1_3">5.1.3</a>�</div> 24677<a id="xo_set_writer" href="#xo_set_writer">xo_set_writer</a> 24678</h3> 24679<p id="doc_section_5_1_3_p_1">The xo_set_writer function allows custom 'write' functions which can tailor how libxo writes data. An opaque argument is recorded and passed back to the write function, allowing the function to acquire context information. The 'close' function can release this opaque data and any other resources as needed. The flush function can flush buffered data associated with the opaque object.</p> 24680<div id="doc_figure_u.93"></div> <pre> 24681 void xo_set_writer (xo_handle_t *xop, void *opaque, 24682 xo_write_func_t write_func, 24683 xo_close_func_t close_func); 24684 xo_flush_func_t flush_func); 24685 </pre> </div> 24686<div class="content"> 24687<h3 id="doc_section_5_1_4"> 24688<div class="self-section-number"> 24689<a href="#doc_section_5_1_4">5.1.4</a>�</div> 24690<a id="xo_set_style" href="#xo_set_style">xo_set_style</a> 24691</h3> 24692<p id="doc_section_5_1_4_p_1">To set the style, use the xo_set_style() function:</p> 24693<div id="doc_figure_u.94"></div> <pre> 24694 void xo_set_style(xo_handle_t *xop, unsigned style); 24695 </pre> <p id="doc_section_5_1_4_p_3">To use the default handle, pass a NULL handle:</p> 24696<div id="doc_figure_u.95"></div> <pre> 24697 xo_set_style(NULL, XO_STYLE_XML); 24698 </pre> </div> 24699<div class="content"> 24700<h3 id="doc_section_5_1_5"> 24701<div class="self-section-number"> 24702<a href="#doc_section_5_1_5">5.1.5</a>�</div> 24703<a id="xo_get_style" href="#xo_get_style">xo_get_style</a> 24704</h3> 24705<p id="doc_section_5_1_5_p_1">To find the current style, use the xo_get_style() function:</p> 24706<div id="doc_figure_u.96"></div> <pre> 24707 xo_style_t xo_get_style(xo_handle_t *xop); 24708 </pre> <p id="doc_section_5_1_5_p_3">To use the default handle, pass a NULL handle:</p> 24709<div id="doc_figure_u.97"></div> <pre> 24710 style = xo_get_style(NULL); 24711 </pre> <p id="doc_section_5_1_5_p_5">Section Contents: </p> 24712<ul> 24713<li><a href="#styles" title="Output Styles (XO_STYLE_*)">Section�5.1.5.1</a></li> 24714<li><a href="#xo_set_style_name" title="xo_set_style_name">Section�5.1.5.2</a></li> 24715</ul> 24716<div class="content"> 24717<h4 id="doc_section_5_1_5_1"> 24718<div class="self-section-number"> 24719<a href="#doc_section_5_1_5_1">5.1.5.1</a>�</div> 24720<a id="styles" href="#styles">Output Styles (XO_STYLE_*)</a> 24721</h4> 24722<p id="doc_section_5_1_5_1_p_1">The libxo functions accept a set of output styles:</p> 24723<div id="doc_table_u.12"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 24724<thead><tr> 24725<th class="left">Flag</th> 24726<th class="left">Description</th> 24727</tr></thead> 24728<tbody> 24729<tr> 24730<td>XO_STYLE_TEXT</td> 24731<td>Traditional text output</td> 24732</tr> 24733<tr> 24734<td>XO_STYLE_XML</td> 24735<td>XML encoded data</td> 24736</tr> 24737<tr> 24738<td>XO_STYLE_JSON</td> 24739<td>JSON encoded data</td> 24740</tr> 24741<tr> 24742<td>XO_STYLE_HTML</td> 24743<td>HTML encoded data</td> 24744</tr> 24745</tbody> 24746</table></div> 24747</div> 24748<div class="content"> 24749<h4 id="doc_section_5_1_5_2"> 24750<div class="self-section-number"> 24751<a href="#doc_section_5_1_5_2">5.1.5.2</a>�</div> 24752<a id="xo_set_style_name" href="#xo_set_style_name">xo_set_style_name</a> 24753</h4> 24754<p id="doc_section_5_1_5_2_p_1">The xo_set_style_name() can be used to set the style based on a name encoded as a string:</p> 24755<div id="doc_figure_u.98"></div> <pre> 24756 int xo_set_style_name (xo_handle_t *xop, const char *style); 24757 </pre> <p id="doc_section_5_1_5_2_p_3">The name can be any of the styles: "text", "xml", "json", or "html".</p> 24758<div id="doc_figure_u.99"></div> <pre> 24759 EXAMPLE: 24760 xo_set_style_name(NULL, "html"); 24761 </pre> </div> 24762</div> 24763<div class="content"> 24764<h3 id="doc_section_5_1_6"> 24765<div class="self-section-number"> 24766<a href="#doc_section_5_1_6">5.1.6</a>�</div> 24767<a id="xo_set_flags" href="#xo_set_flags">xo_set_flags</a> 24768</h3> 24769<p id="doc_section_5_1_6_p_1">To set the flags, use the xo_set_flags() function:</p> 24770<div id="doc_figure_u.100"></div> <pre> 24771 void xo_set_flags(xo_handle_t *xop, unsigned flags); 24772 </pre> <p id="doc_section_5_1_6_p_3">To use the default handle, pass a NULL handle:</p> 24773<div id="doc_figure_u.101"></div> <pre> 24774 xo_set_style(NULL, XO_STYLE_XML); 24775 </pre> <p id="doc_section_5_1_6_p_5">Section Contents: </p> 24776<ul> 24777<li><a href="#flags" title="Flags (XOF_*)">Section�5.1.6.1</a></li> 24778<li><a href="#xo_clear_flags" title="xo_clear_flags">Section�5.1.6.2</a></li> 24779<li><a href="#xo_set_options" title="xo_set_options">Section�5.1.6.3</a></li> 24780</ul> 24781<div class="content"> 24782<h4 id="doc_section_5_1_6_1"> 24783<div class="self-section-number"> 24784<a href="#doc_section_5_1_6_1">5.1.6.1</a>�</div> 24785<a id="flags" href="#flags">Flags (XOF_*)</a> 24786</h4> 24787<p id="doc_section_5_1_6_1_p_1">The set of valid flags include:</p> 24788<div id="doc_table_u.13"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 24789<thead><tr> 24790<th class="left">Flag</th> 24791<th class="left">Description</th> 24792</tr></thead> 24793<tbody> 24794<tr> 24795<td>XOF_CLOSE_FP</td> 24796<td>Close file pointer on xo_destroy()</td> 24797</tr> 24798<tr> 24799<td>XOF_COLOR</td> 24800<td>Enable color and effects in output</td> 24801</tr> 24802<tr> 24803<td>XOF_COLOR_ALLOWED</td> 24804<td>Allow color/effect for terminal output</td> 24805</tr> 24806<tr> 24807<td>XOF_DTRT</td> 24808<td>Enable "do the right thing" mode</td> 24809</tr> 24810<tr> 24811<td>XOF_INFO</td> 24812<td>Display info data attributes (HTML)</td> 24813</tr> 24814<tr> 24815<td>XOF_KEYS</td> 24816<td>Emit the key attribute (XML)</td> 24817</tr> 24818<tr> 24819<td>XOF_NO_ENV</td> 24820<td>Do not use the LIBXO_OPTIONS env var</td> 24821</tr> 24822<tr> 24823<td>XOF_NO_HUMANIZE</td> 24824<td>Display humanization (TEXT, HTML)</td> 24825</tr> 24826<tr> 24827<td>XOF_PRETTY</td> 24828<td>Make 'pretty printed' output</td> 24829</tr> 24830<tr> 24831<td>XOF_UNDERSCORES</td> 24832<td>Replaces hyphens with underscores</td> 24833</tr> 24834<tr> 24835<td>XOF_UNITS</td> 24836<td>Display units (XML, HMTL)</td> 24837</tr> 24838<tr> 24839<td>XOF_WARN</td> 24840<td>Generate warnings for broken calls</td> 24841</tr> 24842<tr> 24843<td>XOF_WARN_XML</td> 24844<td>Generate warnings in XML on stdout</td> 24845</tr> 24846<tr> 24847<td>XOF_XPATH</td> 24848<td>Emit XPath expressions (HTML)</td> 24849</tr> 24850<tr> 24851<td>XOF_COLUMNS</td> 24852<td>Force xo_emit to return columns used</td> 24853</tr> 24854<tr> 24855<td>XOF_FLUSH</td> 24856<td>Flush output after each xo_emit call</td> 24857</tr> 24858</tbody> 24859</table></div> 24860<p id="doc_section_5_1_6_1_p_2">The XOF_CLOSE_FP flag will trigger the call of the close_func (provided via xo_set_writer()) when the handle is destroyed.</p> 24861<p id="doc_section_5_1_6_1_p_3">The XOF_COLOR flag enables color and effects in output regardless of output device, while the XOF_COLOR_ALLOWED flag allows color and effects only if the output device is a terminal.</p> 24862<p id="doc_section_5_1_6_1_p_4">The XOF_PRETTY flag requests 'pretty printing', which will trigger the addition of indentation and newlines to enhance the readability of XML, JSON, and HTML output. Text output is not affected.</p> 24863<p id="doc_section_5_1_6_1_p_5">The XOF_WARN flag requests that warnings will trigger diagnostic output (on standard error) when the library notices errors during operations, or with arguments to functions. Without warnings enabled, such conditions are ignored.</p> 24864<p id="doc_section_5_1_6_1_p_6">Warnings allow developers to debug their interaction with libxo. The function "xo_failure" can used as a breakpoint for a debugger, regardless of whether warnings are enabled.</p> 24865<p id="doc_section_5_1_6_1_p_7">If the style is XO_STYLE_HTML, the following additional flags can be used:</p> 24866<div id="doc_table_u.14"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 24867<thead><tr> 24868<th class="left">Flag</th> 24869<th class="left">Description</th> 24870</tr></thead> 24871<tbody> 24872<tr> 24873<td>XOF_XPATH</td> 24874<td>Emit "data-xpath" attributes</td> 24875</tr> 24876<tr> 24877<td>XOF_INFO</td> 24878<td>Emit additional info fields</td> 24879</tr> 24880</tbody> 24881</table></div> 24882<p id="doc_section_5_1_6_1_p_8">The XOF_XPATH flag enables the emission of XPath expressions detailing the hierarchy of XML elements used to encode the data field, if the XPATH style of output were requested.</p> 24883<p id="doc_section_5_1_6_1_p_9">The XOF_INFO flag encodes additional informational fields for HTML output. See <a href="#info" title="Field Information (xo_info_t)">Section�5.4.4</a> for details.</p> 24884<p id="doc_section_5_1_6_1_p_10">If the style is XO_STYLE_XML, the following additional flags can be used:</p> 24885<div id="doc_table_u.15"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 24886<thead><tr> 24887<th class="left">Flag</th> 24888<th class="left">Description</th> 24889</tr></thead> 24890<tbody><tr> 24891<td>XOF_KEYS</td> 24892<td>Flag 'key' fields for xml</td> 24893</tr></tbody> 24894</table></div> 24895<p id="doc_section_5_1_6_1_p_11">The XOF_KEYS flag adds 'key' attribute to the XML encoding for field definitions that use the 'k' modifier. The key attribute has the value "key":</p> 24896<div id="doc_figure_u.102"></div> <pre> 24897 xo_emit("{k:name}", item); 24898 24899 XML: 24900 <name key="key">truck</name> 24901 </pre> </div> 24902<div class="content"> 24903<h4 id="doc_section_5_1_6_2"> 24904<div class="self-section-number"> 24905<a href="#doc_section_5_1_6_2">5.1.6.2</a>�</div> 24906<a id="xo_clear_flags" href="#xo_clear_flags">xo_clear_flags</a> 24907</h4> 24908<p id="doc_section_5_1_6_2_p_1">The xo_clear_flags() function turns off the given flags in a specific handle.</p> 24909<div id="doc_figure_u.103"></div> <pre> 24910 void xo_clear_flags (xo_handle_t *xop, xo_xof_flags_t flags); 24911 </pre> </div> 24912<div class="content"> 24913<h4 id="doc_section_5_1_6_3"> 24914<div class="self-section-number"> 24915<a href="#doc_section_5_1_6_3">5.1.6.3</a>�</div> 24916<a id="xo_set_options" href="#xo_set_options">xo_set_options</a> 24917</h4> 24918<p id="doc_section_5_1_6_3_p_1">The xo_set_options() function accepts a comma-separated list of styles and flags and enables them for a specific handle.</p> 24919<div id="doc_figure_u.104"></div> <pre> 24920 int xo_set_options (xo_handle_t *xop, const char *input); 24921 </pre> <p id="doc_section_5_1_6_3_p_3">The options are identical to those listed in <a href="#options" title="Command-line Arguments">Section�4</a>.</p> 24922</div> 24923</div> 24924<div class="content"> 24925<h3 id="doc_section_5_1_7"> 24926<div class="self-section-number"> 24927<a href="#doc_section_5_1_7">5.1.7</a>�</div> 24928<a id="xo_destroy" href="#xo_destroy">xo_destroy</a> 24929</h3> 24930<p id="doc_section_5_1_7_p_1">The xo_destroy function releases a handle and any resources it is using. Calling xo_destroy with a NULL handle will release any resources associated with the default handle.</p> 24931<div id="doc_figure_u.105"></div> <pre> 24932 void xo_destroy(xo_handle_t *xop); 24933 </pre> </div> 24934</div> 24935<div class="content"> 24936<h2 id="doc_section_5_2"> 24937<div class="self-section-number"> 24938<a href="#doc_section_5_2">5.2</a>�</div> 24939<a id="emitting-content-xo_emit" href="#emitting-content-xo_emit">Emitting Content (xo_emit)</a> 24940</h2> 24941<p id="doc_section_5_2_p_1">The following functions are used to emit output:</p> 24942<div id="doc_figure_u.106"></div> <pre> 24943 int xo_emit (const char *fmt, ...); 24944 int xo_emit_h (xo_handle_t *xop, const char *fmt, ...); 24945 int xo_emit_hv (xo_handle_t *xop, const char *fmt, va_list vap); 24946 </pre> <p id="doc_section_5_2_p_3">The "fmt" argument is a string containing field descriptors as specified in <a href="#format-strings" title="Format Strings">Section�3.2</a>. The use of a handle is optional and NULL can be passed to access the internal 'default' handle. See <a href="#handles" title="Handles">Section�5.1</a>.</p> 24947<p id="doc_section_5_2_p_4">The remaining arguments to xo_emit() and xo_emit_h() are a set of arguments corresponding to the fields in the format string. Care must be taken to ensure the argument types match the fields in the format string, since an inappropriate cast can ruin your day. The vap argument to xo_emit_hv() points to a variable argument list that can be used to retrieve arguments via va_arg().</p> 24948<p id="doc_section_5_2_p_5">Section Contents: </p> 24949<ul> 24950<li><a href="#xo_emit_field" title="Single Field Emitting Functions (xo_emit_field)">Section�5.2.1</a></li> 24951<li><a href="#xo_attr" title="Attributes (xo_attr)">Section�5.2.2</a></li> 24952<li><a href="#flushing-output-xo_flush" title="Flushing Output (xo_flush)">Section�5.2.3</a></li> 24953<li><a href="#finishing-output-xo_finish" title="Finishing Output (xo_finish)">Section�5.2.4</a></li> 24954</ul> 24955<div class="content"> 24956<h3 id="doc_section_5_2_1"> 24957<div class="self-section-number"> 24958<a href="#doc_section_5_2_1">5.2.1</a>�</div> 24959<a id="xo_emit_field" href="#xo_emit_field">Single Field Emitting Functions (xo_emit_field)</a> 24960</h3> 24961<p id="doc_section_5_2_1_p_1">The following functions can also make output, but only make a single field at a time:</p> 24962<div id="doc_figure_u.107"></div> <pre> 24963 int xo_emit_field_hv (xo_handle_t *xop, const char *rolmod, 24964 const char *contents, const char *fmt, 24965 const char *efmt, va_list vap); 24966 24967 int xo_emit_field_h (xo_handle_t *xop, const char *rolmod, 24968 const char *contents, const char *fmt, 24969 const char *efmt, ...); 24970 24971 int xo_emit_field (const char *rolmod, const char *contents, 24972 const char *fmt, const char *efmt, ...); 24973 </pre> <p id="doc_section_5_2_1_p_3">These functions are intended to avoid the scenario where one would otherwise need to compose a format descriptors using snprintf(). The individual parts of the format descriptor are passed in distinctly.</p> 24974<div id="doc_figure_u.108"></div> <pre> 24975 xo_emit("T", "Host name is ", NULL, NULL); 24976 xo_emit("V", "host-name", NULL, NULL, host-name); 24977 </pre> </div> 24978<div class="content"> 24979<h3 id="doc_section_5_2_2"> 24980<div class="self-section-number"> 24981<a href="#doc_section_5_2_2">5.2.2</a>�</div> 24982<a id="xo_attr" href="#xo_attr">Attributes (xo_attr)</a> 24983</h3> 24984<p id="doc_section_5_2_2_p_1">The xo_attr() function emits attributes for the XML output style.</p> 24985<div id="doc_figure_u.109"></div> <pre> 24986 int xo_attr (const char *name, const char *fmt, ...); 24987 int xo_attr_h (xo_handle_t *xop, const char *name, 24988 const char *fmt, ...); 24989 int xo_attr_hv (xo_handle_t *xop, const char *name, 24990 const char *fmt, va_list vap); 24991 </pre> <p id="doc_section_5_2_2_p_3">The name parameter give the name of the attribute to be encoded. The fmt parameter gives a printf-style format string used to format the value of the attribute using any remaining arguments, or the vap parameter passed to xo_attr_hv().</p> 24992<div id="doc_figure_u.110"></div> <pre> 24993 EXAMPLE: 24994 xo_attr("seconds", "%ld", (unsigned long) login_time); 24995 struct tm *tmp = localtime(login_time); 24996 strftime(buf, sizeof(buf), "%R", tmp); 24997 xo_emit("Logged in at {:login-time}\n", buf); 24998 XML: 24999 <login-time seconds="1408336270">00:14</login-time> 25000 </pre> <p id="doc_section_5_2_2_p_5">xo_attr is placed on the next container, instance, leaf, or leaf list that is emitted.</p> 25001<p id="doc_section_5_2_2_p_6">Since attributes are only emitted in XML, their use should be limited to meta-data and additional or redundant representations of data already emitted in other form.</p> 25002</div> 25003<div class="content"> 25004<h3 id="doc_section_5_2_3"> 25005<div class="self-section-number"> 25006<a href="#doc_section_5_2_3">5.2.3</a>�</div> 25007<a id="flushing-output-xo_flush" href="#flushing-output-xo_flush">Flushing Output (xo_flush)</a> 25008</h3> 25009<p id="doc_section_5_2_3_p_1">libxo buffers data, both for performance and consistency, but also to allow some advanced features to work properly. At various times, the caller may wish to flush any data buffered within the library. The xo_flush() call is used for this:</p> 25010<div id="doc_figure_u.111"></div> <pre> 25011 void xo_flush (void); 25012 void xo_flush_h (xo_handle_t *xop); 25013 </pre> <p id="doc_section_5_2_3_p_3">Calling xo_flush also triggers the flush function associated with the handle. For the default handle, this is equivalent to "fflush(stdio);".</p> 25014</div> 25015<div class="content"> 25016<h3 id="doc_section_5_2_4"> 25017<div class="self-section-number"> 25018<a href="#doc_section_5_2_4">5.2.4</a>�</div> 25019<a id="finishing-output-xo_finish" href="#finishing-output-xo_finish">Finishing Output (xo_finish)</a> 25020</h3> 25021<p id="doc_section_5_2_4_p_1">When the program is ready to exit or close a handle, a call to xo_finish() is required. This flushes any buffered data, closes open libxo constructs, and completes any pending operations.</p> 25022<div id="doc_figure_u.112"></div> <pre> 25023 int xo_finish (void); 25024 int xo_finish_h (xo_handle_t *xop); 25025 void xo_finish_atexit (void); 25026 </pre> <p id="doc_section_5_2_4_p_3">Calling this function is vital to the proper operation of libxo, especially for the non-TEXT output styles.</p> 25027<p id="doc_section_5_2_4_p_4">xo_finish_atexit is suitable for use with atexit(3).</p> 25028</div> 25029</div> 25030<div class="content"> 25031<h2 id="doc_section_5_3"> 25032<div class="self-section-number"> 25033<a href="#doc_section_5_3">5.3</a>�</div> 25034<a id="emitting-hierarchy" href="#emitting-hierarchy">Emitting Hierarchy</a> 25035</h2> 25036<p id="doc_section_5_3_p_1">libxo represents to types of hierarchy: containers and lists. A container appears once under a given parent where a list contains instances that can appear multiple times. A container is used to hold related fields and to give the data organization and scope.</p> 25037<p id="doc_section_5_3_p_2">To create a container, use the xo_open_container and xo_close_container functions:</p> 25038<div id="doc_figure_u.113"></div> <pre> 25039 int xo_open_container (const char *name); 25040 int xo_open_container_h (xo_handle_t *xop, const char *name); 25041 int xo_open_container_hd (xo_handle_t *xop, const char *name); 25042 int xo_open_container_d (const char *name); 25043 25044 int xo_close_container (const char *name); 25045 int xo_close_container_h (xo_handle_t *xop, const char *name); 25046 int xo_close_container_hd (xo_handle_t *xop); 25047 int xo_close_container_d (void); 25048 </pre> <p id="doc_section_5_3_p_4">The name parameter gives the name of the container, encoded in UTF-8. Since ASCII is a proper subset of UTF-8, traditional C strings can be used directly.</p> 25049<p id="doc_section_5_3_p_5">The close functions with the "_d" suffix are used in "Do The Right Thing" mode, where the name of the open containers, lists, and instances are maintained internally by libxo to allow the caller to avoid keeping track of the open container name.</p> 25050<p id="doc_section_5_3_p_6">Use the XOF_WARN flag to generate a warning if the name given on the close does not match the current open container.</p> 25051<p id="doc_section_5_3_p_7">For TEXT and HTML output, containers are not rendered into output text, though for HTML they are used when the XOF_XPATH flag is set.</p> 25052<div id="doc_figure_u.114"></div> <pre> 25053 EXAMPLE: 25054 xo_open_container("system"); 25055 xo_emit("The host name is {:host-name}\n", hn); 25056 xo_close_container("system"); 25057 XML: 25058 <system><host-name>foo</host-name></system> 25059 </pre> <p id="doc_section_5_3_p_9">Section Contents: </p> 25060<ul><li><a href="#lists-and-instances-2" title="Lists and Instances">Section�5.3.1</a></li></ul> 25061<div class="content"> 25062<h3 id="doc_section_5_3_1"> 25063<div class="self-section-number"> 25064<a href="#doc_section_5_3_1">5.3.1</a>�</div> 25065<a id="lists-and-instances-2" href="#lists-and-instances-2">Lists and Instances</a> 25066</h3> 25067<p id="doc_section_5_3_1_p_1">Lists are sequences of instances of homogeneous data objects. Two distinct levels of calls are needed to represent them in our output styles. Calls must be made to open and close a list, and for each instance of data in that list, calls must be make to open and close that instance.</p> 25068<p id="doc_section_5_3_1_p_2">The name given to all calls must be identical, and it is strongly suggested that the name be singular, not plural, as a matter of style and usage expectations.</p> 25069<div id="doc_figure_u.115"></div> <pre> 25070 EXAMPLE: 25071 xo_open_list("user"); 25072 for (i = 0; i < num_users; i++) { 25073 xo_open_instance("user"); 25074 xo_emit("{k:name}:{:uid/%u}:{:gid/%u}:{:home}\n", 25075 pw[i].pw_name, pw[i].pw_uid, 25076 pw[i].pw_gid, pw[i].pw_dir); 25077 xo_close_instance("user"); 25078 } 25079 xo_close_list("user"); 25080 TEXT: 25081 phil:1001:1001:/home/phil 25082 pallavi:1002:1002:/home/pallavi 25083 XML: 25084 <user> 25085 <name>phil</name> 25086 <uid>1001</uid> 25087 <gid>1001</gid> 25088 <home>/home/phil</home> 25089 </user> 25090 <user> 25091 <name>pallavi</name> 25092 <uid>1002</uid> 25093 <gid>1002</gid> 25094 <home>/home/pallavi</home> 25095 </user> 25096 JSON: 25097 user: [ 25098 { 25099 "name": "phil", 25100 "uid": 1001, 25101 "gid": 1001, 25102 "home": "/home/phil", 25103 }, 25104 { 25105 "name": "pallavi", 25106 "uid": 1002, 25107 "gid": 1002, 25108 "home": "/home/pallavi", 25109 } 25110 ] 25111 </pre> </div> 25112</div> 25113<div class="content"> 25114<h2 id="doc_section_5_4"> 25115<div class="self-section-number"> 25116<a href="#doc_section_5_4">5.4</a>�</div> 25117<a id="support-functions" href="#support-functions">Support Functions</a> 25118</h2> 25119<p id="doc_section_5_4_p_1">Section Contents: </p> 25120<ul> 25121<li><a href="#xo_parse_args" title="Parsing Command-line Arguments (xo_parse_args)">Section�5.4.1</a></li> 25122<li><a href="#xo_set_program" title="xo_set_program">Section�5.4.2</a></li> 25123<li><a href="#xo_set_version" title="xo_set_version">Section�5.4.3</a></li> 25124<li><a href="#info" title="Field Information (xo_info_t)">Section�5.4.4</a></li> 25125<li><a href="#memory-allocation" title="Memory Allocation">Section�5.4.5</a></li> 25126<li><a href="#LIBXO_OPTIONS" title="LIBXO_OPTIONS">Section�5.4.6</a></li> 25127<li><a href="#errors-warnings-and-messages" title="Errors, Warnings, and Messages">Section�5.4.7</a></li> 25128<li><a href="#xo_error" title="xo_error">Section�5.4.8</a></li> 25129<li><a href="#xo_no_setlocale" title="xo_no_setlocale">Section�5.4.9</a></li> 25130</ul> 25131<div class="content"> 25132<h3 id="doc_section_5_4_1"> 25133<div class="self-section-number"> 25134<a href="#doc_section_5_4_1">5.4.1</a>�</div> 25135<a id="xo_parse_args" href="#xo_parse_args">Parsing Command-line Arguments (xo_parse_args)</a> 25136</h3> 25137<p id="doc_section_5_4_1_p_1">The xo_parse_args() function is used to process a program's arguments. libxo-specific options are processed and removed from the argument list so the calling application does not need to process them. If successful, a new value for argc is returned. On failure, a message it emitted and -1 is returned.</p> 25138<div id="doc_figure_u.116"></div> <pre> 25139 argc = xo_parse_args(argc, argv); 25140 if (argc < 0) 25141 exit(EXIT_FAILURE); 25142 </pre> <p id="doc_section_5_4_1_p_3">Following the call to xo_parse_args, the application can process the remaining arguments in a normal manner. See <a href="#options" title="Command-line Arguments">Section�4</a> for a description of valid arguments.</p> 25143</div> 25144<div class="content"> 25145<h3 id="doc_section_5_4_2"> 25146<div class="self-section-number"> 25147<a href="#doc_section_5_4_2">5.4.2</a>�</div> 25148<a id="xo_set_program" href="#xo_set_program">xo_set_program</a> 25149</h3> 25150<p id="doc_section_5_4_2_p_1">The xo_set_program function sets name of the program as reported by functions like xo_failure, xo_warn, xo_err, etc. The program name is initialized by xo_parse_args, but subsequent calls to xo_set_program can override this value.</p> 25151<div id="doc_figure_u.117"></div> <pre> 25152 xo_set_program(argv[0]); 25153 </pre> <p id="doc_section_5_4_2_p_3">Note that the value is not copied, so the memory passed to xo_set_program (and xo_parse_args) must be maintained by the caller.</p> 25154</div> 25155<div class="content"> 25156<h3 id="doc_section_5_4_3"> 25157<div class="self-section-number"> 25158<a href="#doc_section_5_4_3">5.4.3</a>�</div> 25159<a id="xo_set_version" href="#xo_set_version">xo_set_version</a> 25160</h3> 25161<p id="doc_section_5_4_3_p_1">The xo_set_version function records a version number to be emitted as part of the data for encoding styles (XML and JSON). This version number is suitable for tracking changes in the content, allowing a user of the data to discern which version of the data model is in use.</p> 25162<div id="doc_figure_u.118"></div> <pre> 25163 void xo_set_version (const char *version); 25164 void xo_set_version_h (xo_handle_t *xop, const char *version); 25165 </pre> </div> 25166<div class="content"> 25167<h3 id="doc_section_5_4_4"> 25168<div class="self-section-number"> 25169<a href="#doc_section_5_4_4">5.4.4</a>�</div> 25170<a id="info" href="#info">Field Information (xo_info_t)</a> 25171</h3> 25172<p id="doc_section_5_4_4_p_1">HTML data can include additional information in attributes that begin with "data‑". To enable this, three things must occur:</p> 25173<p id="doc_section_5_4_4_p_2">First the application must build an array of xo_info_t structures, one per tag. The array must be sorted by name, since libxo uses a binary search to find the entry that matches names from format instructions.</p> 25174<p id="doc_section_5_4_4_p_3">Second, the application must inform libxo about this information using the xo_set_info() call:</p> 25175<div id="doc_figure_u.119"></div> <pre> 25176 typedef struct xo_info_s { 25177 const char *xi_name; /* Name of the element */ 25178 const char *xi_type; /* Type of field */ 25179 const char *xi_help; /* Description of field */ 25180 } xo_info_t; 25181 25182 void xo_set_info (xo_handle_t *xop, xo_info_t *infop, int count); 25183 </pre> <p id="doc_section_5_4_4_p_5">Like other libxo calls, passing NULL for the handle tells libxo to use the default handle.</p> 25184<p id="doc_section_5_4_4_p_6">If the count is -1, libxo will count the elements of infop, but there must be an empty element at the end. More typically, the number is known to the application:</p> 25185<div id="doc_figure_u.120"></div> <pre> 25186 xo_info_t info[] = { 25187 { "in-stock", "number", "Number of items in stock" }, 25188 { "name", "string", "Name of the item" }, 25189 { "on-order", "number", "Number of items on order" }, 25190 { "sku", "string", "Stock Keeping Unit" }, 25191 { "sold", "number", "Number of items sold" }, 25192 }; 25193 int info_count = (sizeof(info) / sizeof(info[0])); 25194 ... 25195 xo_set_info(NULL, info, info_count); 25196 </pre> <p id="doc_section_5_4_4_p_8">Third, the emission of info must be triggered with the XOF_INFO flag using either the xo_set_flags() function or the "‑‑libxo=info" command line argument.</p> 25197<p id="doc_section_5_4_4_p_9">The type and help values, if present, are emitted as the "data‑type" and "data‑help" attributes:</p> 25198<div id="doc_figure_u.121"></div> <pre> 25199 <div class="data" data-tag="sku" data-type="string" 25200 data-help="Stock Keeping Unit">GRO-000-533</div> 25201 </pre> </div> 25202<div class="content"> 25203<h3 id="doc_section_5_4_5"> 25204<div class="self-section-number"> 25205<a href="#doc_section_5_4_5">5.4.5</a>�</div> 25206<a id="memory-allocation" href="#memory-allocation">Memory Allocation</a> 25207</h3> 25208<p id="doc_section_5_4_5_p_1">The xo_set_allocator function allows libxo to be used in environments where the standard realloc() and free() functions are not available.</p> 25209<div id="doc_figure_u.122"></div> <pre> 25210 void xo_set_allocator (xo_realloc_func_t realloc_func, 25211 xo_free_func_t free_func); 25212 </pre> <p id="doc_section_5_4_5_p_3">realloc_func should expect the same arguments as realloc(3) and return a pointer to memory following the same convention. free_func will receive the same argument as free(3) and should release it, as appropriate for the environment.</p> 25213<p id="doc_section_5_4_5_p_4">By default, the standard realloc() and free() functions are used.</p> 25214</div> 25215<div class="content"> 25216<h3 id="doc_section_5_4_6"> 25217<div class="self-section-number"> 25218<a href="#doc_section_5_4_6">5.4.6</a>�</div> 25219<a id="LIBXO_OPTIONS" href="#LIBXO_OPTIONS">LIBXO_OPTIONS</a> 25220</h3> 25221<p id="doc_section_5_4_6_p_1">The environment variable "LIBXO_OPTIONS" can be set to a subset of libxo options, including:</p> 25222<p id="doc_section_5_4_6_p_2"> </p> 25223<ul> 25224<li>color</li> 25225<li>flush</li> 25226<li>flush-line</li> 25227<li>no-color</li> 25228<li>no-humanize</li> 25229<li>no-locale</li> 25230<li>no-retain</li> 25231<li>pretty</li> 25232<li>retain</li> 25233<li>underscores</li> 25234<li>warn</li> 25235</ul> 25236<p id="doc_section_5_4_6_p_3">For example, warnings can be enabled by:</p> 25237<div id="doc_figure_u.123"></div> <pre> 25238 % env LIBXO_OPTIONS=warn my-app 25239 </pre> <p id="doc_section_5_4_6_p_5">Since environment variables are inherited, child processes will have the same options, which may be undesirable, making the use of the "‑‑libxo" option is preferable in most situations.</p> 25240</div> 25241<div class="content"> 25242<h3 id="doc_section_5_4_7"> 25243<div class="self-section-number"> 25244<a href="#doc_section_5_4_7">5.4.7</a>�</div> 25245<a id="errors-warnings-and-messages" href="#errors-warnings-and-messages">Errors, Warnings, and Messages</a> 25246</h3> 25247<p id="doc_section_5_4_7_p_1">Many programs make use of the standard library functions err() and warn() to generate errors and warnings for the user. libxo wants to pass that information via the current output style, and provides compatible functions to allow this:</p> 25248<div id="doc_figure_u.124"></div> <pre> 25249 void xo_warn (const char *fmt, ...); 25250 void xo_warnx (const char *fmt, ...); 25251 void xo_warn_c (int code, const char *fmt, ...); 25252 void xo_warn_hc (xo_handle_t *xop, int code, 25253 const char *fmt, ...); 25254 void xo_err (int eval, const char *fmt, ...); 25255 void xo_errc (int eval, int code, const char *fmt, ...); 25256 void xo_errx (int eval, const char *fmt, ...); 25257 void xo_message (const char *fmt, ...); 25258 void xo_message_c (int code, const char *fmt, ...); 25259 void xo_message_hc (xo_handle_t *xop, int code, 25260 const char *fmt, ...); 25261 void xo_message_hcv (xo_handle_t *xop, int code, 25262 const char *fmt, va_list vap); 25263 </pre> <p id="doc_section_5_4_7_p_3">These functions display the program name, a colon, a formatted message based on the arguments, and then optionally a colon and an error message associated with either "errno" or the "code" parameter.</p> 25264<div id="doc_figure_u.125"></div> <pre> 25265 EXAMPLE: 25266 if (open(filename, O_RDONLY) < 0) 25267 xo_err(1, "cannot open file '%s'", filename); 25268 </pre> </div> 25269<div class="content"> 25270<h3 id="doc_section_5_4_8"> 25271<div class="self-section-number"> 25272<a href="#doc_section_5_4_8">5.4.8</a>�</div> 25273<a id="xo_error" href="#xo_error">xo_error</a> 25274</h3> 25275<p id="doc_section_5_4_8_p_1">The xo_error function can be used for generic errors that should be reported over the handle, rather than to stderr. The xo_error function behaves like xo_err for TEXT and HTML output styles, but puts the error into XML or JSON elements:</p> 25276<div id="doc_figure_u.126"></div> <pre> 25277 EXAMPLE:: 25278 xo_error("Does not %s", "compute"); 25279 XML:: 25280 <error><message>Does not compute</message></error> 25281 JSON:: 25282 "error": { "message": "Does not compute" } 25283 </pre> </div> 25284<div class="content"> 25285<h3 id="doc_section_5_4_9"> 25286<div class="self-section-number"> 25287<a href="#doc_section_5_4_9">5.4.9</a>�</div> 25288<a id="xo_no_setlocale" href="#xo_no_setlocale">xo_no_setlocale</a> 25289</h3> 25290<p id="doc_section_5_4_9_p_1">libxo automatically initializes the locale based on setting of the environment variables LC_CTYPE, LANG, and LC_ALL. The first of this list of variables is used and if none of the variables, the locale defaults to "UTF‑8". The caller may wish to avoid this behavior, and can do so by calling the xo_no_setlocale() function.</p> 25291<div id="doc_figure_u.127"></div> <pre> 25292 void xo_no_setlocale (void); 25293 </pre> </div> 25294</div> 25295<div class="content"> 25296<h2 id="doc_section_5_5"> 25297<div class="self-section-number"> 25298<a href="#doc_section_5_5">5.5</a>�</div> 25299<a id="emitting-syslog-messages" href="#emitting-syslog-messages">Emitting syslog Messages</a> 25300</h2> 25301<p id="doc_section_5_5_p_1">syslog is the system logging facility used throughout the unix world. Messages are sent from commands, applications, and daemons to a hierarchy of servers, where they are filtered, saved, and forwarded based on configuration behaviors.</p> 25302<p id="doc_section_5_5_p_2">syslog is an older protocol, originally documented only in source code. By the time RFC 3164 published, variation and mutation left the leading "<pri>" string as only common content. RFC 5424 defines a new version (version 1) of syslog and introduces structured data into the messages. Structured data is a set of name/value pairs transmitted distinctly alongside the traditional text message, allowing filtering on precise values instead of regular expressions.</p> 25303<p id="doc_section_5_5_p_3">These name/value pairs are scoped by a two-part identifier; an enterprise identifier names the party responsible for the message catalog and a name identifying that message. Enterprise IDs are defined by IANA, the Internet Assigned Numbers Authority:</p> 25304<p id="doc_section_5_5_p_4">https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers</p> 25305<p id="doc_section_5_5_p_5">Use the <a href="#xo_set_syslog_enterprise_id" title="xo_set_syslog_enterprise_id">Section�5.5.3.5</a>() function to set the Enterprise ID, as needed.</p> 25306<p id="doc_section_5_5_p_6">The message name should follow the conventions in <a href="#good-field-names" title="What makes a good field name?">Section�10.1.3</a>, as should the fields within the message.</p> 25307<div id="doc_figure_u.128"></div> <pre> 25308 /* Both of these calls are optional */ 25309 xo_set_syslog_enterprise_id(32473); 25310 xo_open_log("my-program", 0, LOG_DAEMON); 25311 25312 /* Generate a syslog message */ 25313 xo_syslog(LOG_ERR, "upload-failed", 25314 "error <%d> uploading file '{:filename}' " 25315 "as '{:target/%s:%s}'", 25316 code, filename, protocol, remote); 25317 25318 xo_syslog(LOG_INFO, "poofd-invalid-state", 25319 "state {:current/%u} is invalid {:connection/%u}", 25320 state, conn); 25321 </pre> <p id="doc_section_5_5_p_8">The developer should be aware that the message name may be used in the future to allow access to further information, including documentation. Care should be taken to choose quality, descriptive names.</p> 25322<p id="doc_section_5_5_p_9">Section Contents: </p> 25323<ul> 25324<li><a href="#priority" title="Priority, Facility, and Flags">Section�5.5.1</a></li> 25325<li><a href="#xo_syslog" title="xo_syslog">Section�5.5.2</a></li> 25326<li><a href="#support-functions-2" title="Support functions">Section�5.5.3</a></li> 25327</ul> 25328<div class="content"> 25329<h3 id="doc_section_5_5_1"> 25330<div class="self-section-number"> 25331<a href="#doc_section_5_5_1">5.5.1</a>�</div> 25332<a id="priority" href="#priority">Priority, Facility, and Flags</a> 25333</h3> 25334<p id="doc_section_5_5_1_p_1">The xo_syslog, xo_vsyslog, and xo_open_log functions accept a set of flags which provide the priority of the message, the source facility, and some additional features. These values are OR'd together to create a single integer argument:</p> 25335<div id="doc_figure_u.129"></div> <pre> 25336 xo_syslog(LOG_ERR | LOG_AUTH, "login-failed", 25337 "Login failed; user '{:user}' from host '{:address}'", 25338 user, addr); 25339 </pre> <p id="doc_section_5_5_1_p_3">These values are defined in <syslog.h>.</p> 25340<p id="doc_section_5_5_1_p_4">The priority value indicates the importance and potential impact of each message.</p> 25341<div id="doc_table_u.16"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 25342<thead><tr> 25343<th class="left">Priority</th> 25344<th class="left">Description</th> 25345</tr></thead> 25346<tbody> 25347<tr> 25348<td>LOG_EMERG</td> 25349<td>A panic condition, normally broadcast to all users</td> 25350</tr> 25351<tr> 25352<td>LOG_ALERT</td> 25353<td>A condition that should be corrected immediately</td> 25354</tr> 25355<tr> 25356<td>LOG_CRIT</td> 25357<td>Critical conditions</td> 25358</tr> 25359<tr> 25360<td>LOG_ERR</td> 25361<td>Generic errors</td> 25362</tr> 25363<tr> 25364<td>LOG_WARNING</td> 25365<td>Warning messages</td> 25366</tr> 25367<tr> 25368<td>LOG_NOTICE</td> 25369<td>Non-error conditions that might need special handling</td> 25370</tr> 25371<tr> 25372<td>LOG_INFO</td> 25373<td>Informational messages</td> 25374</tr> 25375<tr> 25376<td>LOG_DEBUG</td> 25377<td>Developer-oriented messages</td> 25378</tr> 25379</tbody> 25380</table></div> 25381<p id="doc_section_5_5_1_p_5">The facility value indicates the source of message, in fairly generic terms.</p> 25382<div id="doc_table_u.17"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 25383<thead><tr> 25384<th class="left">Facility</th> 25385<th class="left">Description</th> 25386</tr></thead> 25387<tbody> 25388<tr> 25389<td>LOG_AUTH</td> 25390<td>The authorization system (e.g. login(1))</td> 25391</tr> 25392<tr> 25393<td>LOG_AUTHPRIV</td> 25394<td>As LOG_AUTH, but logged to a privileged file</td> 25395</tr> 25396<tr> 25397<td>LOG_CRON</td> 25398<td>The cron daemon: cron(8)</td> 25399</tr> 25400<tr> 25401<td>LOG_DAEMON</td> 25402<td>System daemons, not otherwise explicitly listed</td> 25403</tr> 25404<tr> 25405<td>LOG_FTP</td> 25406<td>The file transfer protocol daemons</td> 25407</tr> 25408<tr> 25409<td>LOG_KERN</td> 25410<td>Messages generated by the kernel</td> 25411</tr> 25412<tr> 25413<td>LOG_LPR</td> 25414<td>The line printer spooling system</td> 25415</tr> 25416<tr> 25417<td>LOG_MAIL</td> 25418<td>The mail system</td> 25419</tr> 25420<tr> 25421<td>LOG_NEWS</td> 25422<td>The network news system</td> 25423</tr> 25424<tr> 25425<td>LOG_SECURITY</td> 25426<td>Security subsystems, such as ipfw(4)</td> 25427</tr> 25428<tr> 25429<td>LOG_SYSLOG</td> 25430<td>Messages generated internally by syslogd(8)</td> 25431</tr> 25432<tr> 25433<td>LOG_USER</td> 25434<td>Messages generated by user processes (default)</td> 25435</tr> 25436<tr> 25437<td>LOG_UUCP</td> 25438<td>The uucp system</td> 25439</tr> 25440<tr> 25441<td>LOG_LOCAL0..7</td> 25442<td>Reserved for local use</td> 25443</tr> 25444</tbody> 25445</table></div> 25446<p id="doc_section_5_5_1_p_6">In addition to the values listed above, xo_open_log accepts a set of addition flags requesting specific behaviors.</p> 25447<div id="doc_table_u.18"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 25448<thead><tr> 25449<th class="left">Flag</th> 25450<th class="left">Description</th> 25451</tr></thead> 25452<tbody> 25453<tr> 25454<td>LOG_CONS</td> 25455<td>If syslogd fails, attempt to write to /dev/console</td> 25456</tr> 25457<tr> 25458<td>LOG_NDELAY</td> 25459<td>Open the connection to syslogd(8) immediately</td> 25460</tr> 25461<tr> 25462<td>LOG_PERROR</td> 25463<td>Write the message also to standard error output</td> 25464</tr> 25465<tr> 25466<td>LOG_PID</td> 25467<td>Log the process id with each message</td> 25468</tr> 25469</tbody> 25470</table></div> 25471</div> 25472<div class="content"> 25473<h3 id="doc_section_5_5_2"> 25474<div class="self-section-number"> 25475<a href="#doc_section_5_5_2">5.5.2</a>�</div> 25476<a id="xo_syslog" href="#xo_syslog">xo_syslog</a> 25477</h3> 25478<p id="doc_section_5_5_2_p_1">Use the xo_syslog function to generate syslog messages by calling it with a log priority and facility, a message name, a format string, and a set of arguments. The priority/facility argument are discussed above, as is the message name.</p> 25479<p id="doc_section_5_5_2_p_2">The format string follows the same conventions as xo_emit's format string, with each field being rendered as an SD-PARAM pair.</p> 25480<div id="doc_figure_u.130"></div> <pre> 25481 xo_syslog(LOG_ERR, "poofd-missing-file", 25482 "'{:filename}' not found: {:error/%m}", filename); 25483 25484 ... [poofd-missing-file@32473 filename="/etc/poofd.conf" 25485 error="Permission denied"] '/etc/poofd.conf' not 25486 found: Permission denied 25487 </pre> </div> 25488<div class="content"> 25489<h3 id="doc_section_5_5_3"> 25490<div class="self-section-number"> 25491<a href="#doc_section_5_5_3">5.5.3</a>�</div> 25492<a id="support-functions-2" href="#support-functions-2">Support functions</a> 25493</h3> 25494<p id="doc_section_5_5_3_p_1">Section Contents: </p> 25495<ul> 25496<li><a href="#xo_vsyslog" title="xo_vsyslog">Section�5.5.3.1</a></li> 25497<li><a href="#xo_open_log" title="xo_open_log">Section�5.5.3.2</a></li> 25498<li><a href="#xo_close_log" title="xo_close_log">Section�5.5.3.3</a></li> 25499<li><a href="#xo_set_logmask" title="xo_set_logmask">Section�5.5.3.4</a></li> 25500<li><a href="#xo_set_syslog_enterprise_id" title="xo_set_syslog_enterprise_id">Section�5.5.3.5</a></li> 25501</ul> 25502<div class="content"> 25503<h4 id="doc_section_5_5_3_1"> 25504<div class="self-section-number"> 25505<a href="#doc_section_5_5_3_1">5.5.3.1</a>�</div> 25506<a id="xo_vsyslog" href="#xo_vsyslog">xo_vsyslog</a> 25507</h4> 25508<p id="doc_section_5_5_3_1_p_1">xo_vsyslog is identical in function to xo_syslog, but takes the set of arguments using a va_list.</p> 25509<div id="doc_figure_u.131"></div> <pre> 25510 void my_log (const char *name, const char *fmt, ...) 25511 { 25512 va_list vap; 25513 va_start(vap, fmt); 25514 xo_vsyslog(LOG_ERR, name, fmt, vap); 25515 va_end(vap); 25516 } 25517 </pre> </div> 25518<div class="content"> 25519<h4 id="doc_section_5_5_3_2"> 25520<div class="self-section-number"> 25521<a href="#doc_section_5_5_3_2">5.5.3.2</a>�</div> 25522<a id="xo_open_log" href="#xo_open_log">xo_open_log</a> 25523</h4> 25524<p id="doc_section_5_5_3_2_p_1">xo_open_log functions similar to openlog(3), allowing customization of the program name, the log facility number, and the additional option flags described in <a href="#priority" title="Priority, Facility, and Flags">Section�5.5.1</a>.</p> 25525<div id="doc_figure_u.132"></div> <pre> 25526 void 25527 xo_open_log (const char *ident, int logopt, int facility); 25528 </pre> </div> 25529<div class="content"> 25530<h4 id="doc_section_5_5_3_3"> 25531<div class="self-section-number"> 25532<a href="#doc_section_5_5_3_3">5.5.3.3</a>�</div> 25533<a id="xo_close_log" href="#xo_close_log">xo_close_log</a> 25534</h4> 25535<p id="doc_section_5_5_3_3_p_1">xo_close_log functions similar to closelog(3), closing the log file and releasing any associated resources.</p> 25536<div id="doc_figure_u.133"></div> <pre> 25537 void 25538 xo_close_log (void); 25539 </pre> </div> 25540<div class="content"> 25541<h4 id="doc_section_5_5_3_4"> 25542<div class="self-section-number"> 25543<a href="#doc_section_5_5_3_4">5.5.3.4</a>�</div> 25544<a id="xo_set_logmask" href="#xo_set_logmask">xo_set_logmask</a> 25545</h4> 25546<p id="doc_section_5_5_3_4_p_1">xo_set_logmask function similar to setlogmask(3), restricting the set of generated log event to those whose associated bit is set in maskpri. Use LOG_MASK(pri) to find the appropriate bit, or LOG_UPTO(toppri) to create a mask for all priorities up to and including toppri.</p> 25547<div id="doc_figure_u.134"></div> <pre> 25548 int 25549 xo_set_logmask (int maskpri); 25550 25551 Example: 25552 setlogmask(LOG_UPTO(LOG_WARN)); 25553 </pre> </div> 25554<div class="content"> 25555<h4 id="doc_section_5_5_3_5"> 25556<div class="self-section-number"> 25557<a href="#doc_section_5_5_3_5">5.5.3.5</a>�</div> 25558<a id="xo_set_syslog_enterprise_id" href="#xo_set_syslog_enterprise_id">xo_set_syslog_enterprise_id</a> 25559</h4> 25560<p id="doc_section_5_5_3_5_p_1">Use the xo_set_syslog_enterprise_id to supply a platform- or application-specific enterprise id. This value is used in any future syslog messages.</p> 25561<p id="doc_section_5_5_3_5_p_2">Ideally, the operating system should supply a default value via the "kern.syslog.enterprise_id" sysctl value. Lacking that, the application should provide a suitable value.</p> 25562<div id="doc_figure_u.135"></div> <pre> 25563 void 25564 xo_set_syslog_enterprise_id (unsigned short eid); 25565 </pre> <p id="doc_section_5_5_3_5_p_4">Enterprise IDs are administered by IANA, the Internet Assigned Number Authority. The complete list is EIDs on their web site:</p> 25566<p id="doc_section_5_5_3_5_p_5"> <a href="https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers">https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers</a></p> 25567<p id="doc_section_5_5_3_5_p_6">New EIDs can be requested from IANA using the following page:</p> 25568<p id="doc_section_5_5_3_5_p_7"> <a href="http://pen.iana.org/pen/PenApplication.page">http://pen.iana.org/pen/PenApplication.page</a></p> 25569<p id="doc_section_5_5_3_5_p_8">Each software development organization that defines a set of syslog messages should register their own EID and use that value in their software to ensure that messages can be uniquely identified by the combination of EID + message name.</p> 25570</div> 25571</div> 25572</div> 25573<div class="content"> 25574<h2 id="doc_section_5_6"> 25575<div class="self-section-number"> 25576<a href="#doc_section_5_6">5.6</a>�</div> 25577<a id="creating-custom-encoders" href="#creating-custom-encoders">Creating Custom Encoders</a> 25578</h2> 25579<p id="doc_section_5_6_p_1">The number of encoding schemes in current use is staggering, with new and distinct schemes appearing daily. While libxo provide XML, JSON, HMTL, and text natively, there are requirements for other encodings.</p> 25580<p id="doc_section_5_6_p_2">Rather than bake support for all possible encoders into libxo, the API allows them to be defined externally. libxo can then interfaces with these encoding modules using a simplistic API. libxo processes all functions calls, handles state transitions, performs all formatting, and then passes the results as operations to a customized encoding function, which implements specific encoding logic as required. This means your encoder doesn't need to detect errors with unbalanced open/close operations but can rely on libxo to pass correct data.</p> 25581<p id="doc_section_5_6_p_3">By making a simple API, libxo internals are not exposed, insulating the encoder and the library from future or internal changes.</p> 25582<p id="doc_section_5_6_p_4">The three elements of the API are:</p> 25583<p id="doc_section_5_6_p_5"> </p> 25584<ul> 25585<li>loading</li> 25586<li>initialization</li> 25587<li>operations</li> 25588</ul> 25589<p id="doc_section_5_6_p_6">The following sections provide details about these topics.</p> 25590<p id="doc_section_5_6_p_7">libxo source contain an encoder for Concise Binary Object Representation, aka CBOR (RFC 7049) which can be used as used as an example for the API.</p> 25591<p id="doc_section_5_6_p_8">Section Contents: </p> 25592<ul> 25593<li><a href="#loading-encoders" title="Loading Encoders">Section�5.6.1</a></li> 25594<li><a href="#encoder-initialization" title="Encoder Initialization">Section�5.6.2</a></li> 25595<li><a href="#operations" title="Operations">Section�5.6.3</a></li> 25596</ul> 25597<div class="content"> 25598<h3 id="doc_section_5_6_1"> 25599<div class="self-section-number"> 25600<a href="#doc_section_5_6_1">5.6.1</a>�</div> 25601<a id="loading-encoders" href="#loading-encoders">Loading Encoders</a> 25602</h3> 25603<p id="doc_section_5_6_1_p_1">Encoders can be registered statically or discovered dynamically. Applications can choose to call the xo_encoder_register() function to explicitly register encoders, but more typically they are built as shared libraries, placed in the libxo/extensions directory, and loaded based on name. libxo looks for a file with the name of the encoder and an extension of ".enc". This can be a file or a symlink to the shared library file that supports the encoder.</p> 25604<div id="doc_figure_u.136"></div> <pre> 25605 % ls -1 lib/libxo/extensions/*.enc 25606 lib/libxo/extensions/cbor.enc 25607 lib/libxo/extensions/test.enc 25608 </pre> </div> 25609<div class="content"> 25610<h3 id="doc_section_5_6_2"> 25611<div class="self-section-number"> 25612<a href="#doc_section_5_6_2">5.6.2</a>�</div> 25613<a id="encoder-initialization" href="#encoder-initialization">Encoder Initialization</a> 25614</h3> 25615<p id="doc_section_5_6_2_p_1">Each encoder must export a symbol used to access the library, which must have the following signature:</p> 25616<div id="doc_figure_u.137"></div> <pre> 25617 int xo_encoder_library_init (XO_ENCODER_INIT_ARGS); 25618 </pre> <p id="doc_section_5_6_2_p_3">XO_ENCODER_INIT_ARGS is a macro defined in xo_encoder.h that defines an argument called "arg", a pointer of the type xo_encoder_init_args_t. This structure contains two fields:</p> 25619<p id="doc_section_5_6_2_p_4"> </p> 25620<ul> 25621<li>xei_version is the version number of the API as implemented within libxo. This version is currently as 1 using XO_ENCODER_VERSION. This number can be checked to ensure compatibility. The working assumption is that all versions should be backward compatible, but each side may need to accurately know the version supported by the other side. xo_encoder_library_init can optionally check this value, and must then set it to the version number used by the encoder, allowing libxo to detect version differences and react accordingly. For example, if version 2 adds new operations, then libxo will know that an encoding library that set xei_version to 1 cannot be expected to handle those new operations.</li> 25622<li>xei_handler must be set to a pointer to a function of type xo_encoder_func_t, as defined in xo_encoder.h. This function takes a set of parameters: -- xop is a pointer to the opaque xo_handle_t structure -- op is an integer representing the current operation -- name is a string whose meaning differs by operation -- value is a string whose meaning differs by operation -- private is an opaque structure provided by the encoder</li> 25623</ul> 25624<p id="doc_section_5_6_2_p_5">Additional arguments may be added in the future, so handler functions should use the XO_ENCODER_HANDLER_ARGS macro. An appropriate "extern" declaration is provided to help catch errors.</p> 25625<p id="doc_section_5_6_2_p_6">Once the encoder initialization function has completed processing, it should return zero to indicate that no error has occurred. A non-zero return code will cause the handle initialization to fail.</p> 25626</div> 25627<div class="content"> 25628<h3 id="doc_section_5_6_3"> 25629<div class="self-section-number"> 25630<a href="#doc_section_5_6_3">5.6.3</a>�</div> 25631<a id="operations" href="#operations">Operations</a> 25632</h3> 25633<p id="doc_section_5_6_3_p_1">The encoder API defines a set of operations representing the processing model of libxo. Content is formatted within libxo, and callbacks are made to the encoder's handler function when data is ready to be processed.</p> 25634<div id="doc_table_u.19"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 25635<thead><tr> 25636<th class="left">Operation</th> 25637<th class="left">Meaning (Base function)</th> 25638</tr></thead> 25639<tbody> 25640<tr> 25641<td>XO_OP_CREATE</td> 25642<td>Called when the handle is created</td> 25643</tr> 25644<tr> 25645<td>XO_OP_OPEN_CONTAINER</td> 25646<td>Container opened (xo_open_container)</td> 25647</tr> 25648<tr> 25649<td>XO_OP_CLOSE_CONTAINER</td> 25650<td>Container closed (xo_close_container)</td> 25651</tr> 25652<tr> 25653<td>XO_OP_OPEN_LIST</td> 25654<td>List opened (xo_open_list)</td> 25655</tr> 25656<tr> 25657<td>XO_OP_CLOSE_LIST</td> 25658<td>List closed (xo_close_list)</td> 25659</tr> 25660<tr> 25661<td>XO_OP_OPEN_LEAF_LIST</td> 25662<td>Leaf list opened (xo_open_leaf_list)</td> 25663</tr> 25664<tr> 25665<td>XO_OP_CLOSE_LEAF_LIST</td> 25666<td>Leaf list closed (xo_close_leaf_list)</td> 25667</tr> 25668<tr> 25669<td>XO_OP_OPEN_INSTANCE</td> 25670<td>Instance opened (xo_open_instance)</td> 25671</tr> 25672<tr> 25673<td>XO_OP_CLOSE_INSTANCE</td> 25674<td>Instance closed (xo_close_instance)</td> 25675</tr> 25676<tr> 25677<td>XO_OP_STRING</td> 25678<td>Field with Quoted UTF-8 string</td> 25679</tr> 25680<tr> 25681<td>XO_OP_CONTENT</td> 25682<td>Field with content</td> 25683</tr> 25684<tr> 25685<td>XO_OP_FINISH</td> 25686<td>Finish any pending output</td> 25687</tr> 25688<tr> 25689<td>XO_OP_FLUSH</td> 25690<td>Flush any buffered output</td> 25691</tr> 25692<tr> 25693<td>XO_OP_DESTROY</td> 25694<td>Clean up resources</td> 25695</tr> 25696<tr> 25697<td>XO_OP_ATTRIBUTE</td> 25698<td>An attribute name/value pair</td> 25699</tr> 25700<tr> 25701<td>XO_OP_VERSION</td> 25702<td>A version string</td> 25703</tr> 25704</tbody> 25705</table></div> 25706<p id="doc_section_5_6_3_p_2">For all the open and close operations, the name parameter holds the name of the construct. For string, content, and attribute operations, the name parameter is the name of the field and the value parameter is the value. "string" are differentiated from "content" to allow differing treatment of true, false, null, and numbers from real strings, though content values are formatted as strings before the handler is called. For version operations, the value parameter contains the version.</p> 25707<p id="doc_section_5_6_3_p_3">All strings are encoded in UTF-8.</p> 25708</div> 25709</div> 25710</div> 25711<hr class="noprint"> 25712<div class="content"> 25713<h1 id="doc_section_6" class="np"> 25714<div class="self-section-number"> 25715<a href="#doc_section_6">6_</a>�</div> 25716<a id="the-xo-utility" href="#the-xo-utility">The "xo" Utility</a> 25717</h1> 25718<p id="doc_section_6_p_1">The "xo" utility allows command line access to the functionality of the libxo library. Using "xo", shell scripts can emit XML, JSON, and HTML using the same commands that emit text output.</p> 25719<p id="doc_section_6_p_2">The style of output can be selected using a specific option: "‑X" for XML, "‑J" for JSON, "‑H" for HTML, or "‑T" for TEXT, which is the default. The "--style <style>" option can also be used. The standard set of "‑‑libxo" options are available (see <a href="#options" title="Command-line Arguments">Section�4</a>), as well as the LIBXO_OPTIONS environment variable (see <a href="#LIBXO_OPTIONS" title="LIBXO_OPTIONS">Section�5.4.6</a>).</p> 25720<p id="doc_section_6_p_3">The "xo" utility accepts a format string suitable for xo_emit() and a set of zero or more arguments used to supply data for that string.</p> 25721<div id="doc_figure_u.138"></div> <pre> 25722 xo "The {k:name} weighs {:weight/%d} pounds.\n" fish 6 25723 25724 TEXT: 25725 The fish weighs 6 pounds. 25726 XML: 25727 <name>fish</name> 25728 <weight>6</weight> 25729 JSON: 25730 "name": "fish", 25731 "weight": 6 25732 HTML: 25733 <div class="line"> 25734 <div class="text">The </div> 25735 <div class="data" data-tag="name">fish</div> 25736 <div class="text"> weighs </div> 25737 <div class="data" data-tag="weight">6</div> 25738 <div class="text"> pounds.</div> 25739 </div> 25740 </pre> <p id="doc_section_6_p_5">The "--wrap <path>" option can be used to wrap emitted content in a specific hierarchy. The path is a set of hierarchical names separated by the '/' character.</p> 25741<div id="doc_figure_u.139"></div> <pre> 25742 xo --wrap top/a/b/c '{:tag}' value 25743 25744 XML: 25745 <top> 25746 <a> 25747 <b> 25748 <c> 25749 <tag>value</tag> 25750 </c> 25751 </b> 25752 </a> 25753 </top> 25754 JSON: 25755 "top": { 25756 "a": { 25757 "b": { 25758 "c": { 25759 "tag": "value" 25760 } 25761 } 25762 } 25763 } 25764 </pre> <p id="doc_section_6_p_7">The "--open <path>" and "--close <path>" can be used to emit hierarchical information without the matching close and open tag. This allows a shell script to emit open tags, data, and then close tags. The "‑‑depth" option may be used to set the depth for indentation. The "‑‑leading‑xpath" may be used to prepend data to the XPath values used for HTML output style.</p> 25765<div id="doc_figure_u.140"></div> <pre> 25766 #!/bin/sh 25767 xo --open top/data 25768 xo --depth 2 '{tag}' value 25769 xo --close top/data 25770 XML: 25771 <top> 25772 <data> 25773 <tag>value</tag> 25774 </data> 25775 </top> 25776 JSON: 25777 "top": { 25778 "data": { 25779 "tag": "value" 25780 } 25781 } 25782 </pre> <p id="doc_section_6_p_9">Section Contents: </p> 25783<ul> 25784<li><a href="#command-line-options" title="Command Line Options">Section�6.1</a></li> 25785<li><a href="#example-2" title="Example">Section�6.2</a></li> 25786</ul> 25787<div class="content"> 25788<h2 id="doc_section_6_1"> 25789<div class="self-section-number"> 25790<a href="#doc_section_6_1">6.1</a>�</div> 25791<a id="command-line-options" href="#command-line-options">Command Line Options</a> 25792</h2> 25793<p id="doc_section_6_1_p_1">Usage: xo [options] format [fields]</p> 25794<div id="doc_figure_u.141"></div> <pre> 25795 --close <path> Close tags for the given path 25796 --depth <num> Set the depth for pretty printing 25797 --help Display this help text 25798 --html OR -H Generate HTML output 25799 --json OR -J Generate JSON output 25800 --leading-xpath <path> Add a prefix to generated XPaths (HTML) 25801 --open <path> Open tags for the given path 25802 --pretty OR -p Make 'pretty' output (add indent, newlines) 25803 --style <style> Generate given style (xml, json, text, html) 25804 --text OR -T Generate text output (the default style) 25805 --version Display version information 25806 --warn OR -W Display warnings in text on stderr 25807 --warn-xml Display warnings in xml on stdout 25808 --wrap <path> Wrap output in a set of containers 25809 --xml OR -X Generate XML output 25810 --xpath Add XPath data to HTML output); 25811 </pre> </div> 25812<div class="content"> 25813<h2 id="doc_section_6_2"> 25814<div class="self-section-number"> 25815<a href="#doc_section_6_2">6.2</a>�</div> 25816<a id="example-2" href="#example-2">Example</a> 25817</h2> 25818<div id="doc_figure_u.142"></div> <pre> 25819 % xo 'The {:product} is {:status}\n' stereo "in route" 25820 The stereo is in route 25821 % ./xo/xo -p -X 'The {:product} is {:status}\n' stereo "in route" 25822 <product>stereo</product> 25823 <status>in route</status> 25824 </pre> </div> 25825</div> 25826<hr class="noprint"> 25827<div class="content"> 25828<h1 id="doc_section_7" class="np"> 25829<div class="self-section-number"> 25830<a href="#doc_section_7">7_</a>�</div> 25831<a id="xolint" href="#xolint">xolint</a> 25832</h1> 25833<p id="doc_section_7_p_1">xolint is a tool for reporting common mistakes in format strings in source code that invokes xo_emit(). It allows these errors to be diagnosed at build time, rather than waiting until runtime.</p> 25834<p id="doc_section_7_p_2">xolint takes the one or more C files as arguments, and reports and errors, warning, or informational messages as needed.</p> 25835<div id="doc_table_u.20"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 25836<thead><tr> 25837<th class="left">Option</th> 25838<th class="left">Meaning</th> 25839</tr></thead> 25840<tbody> 25841<tr> 25842<td>-c</td> 25843<td>Invoke 'cpp' against the input file</td> 25844</tr> 25845<tr> 25846<td>-C <flags></td> 25847<td>Flags that are passed to 'cpp</td> 25848</tr> 25849<tr> 25850<td>-d</td> 25851<td>Enable debug output</td> 25852</tr> 25853<tr> 25854<td>-D</td> 25855<td>Generate documentation for all xolint messages</td> 25856</tr> 25857<tr> 25858<td>-I</td> 25859<td>Generate info table code</td> 25860</tr> 25861<tr> 25862<td>-p</td> 25863<td>Print the offending lines after the message</td> 25864</tr> 25865<tr> 25866<td>-V</td> 25867<td>Print vocabulary of all field names</td> 25868</tr> 25869<tr> 25870<td>-X</td> 25871<td>Extract samples from xolint, suitable for testing</td> 25872</tr> 25873</tbody> 25874</table></div> 25875<p id="doc_section_7_p_3">The output message will contain the source filename and line number, the class of the message, the message, and, if -p is given, the line that contains the error:</p> 25876<div id="doc_figure_u.143"></div> <pre> 25877 % xolint.pl -t xolint.c 25878 xolint.c: 16: error: anchor format should be "%d" 25879 16 xo_emit("{[:/%s}"); 25880 </pre> <p id="doc_section_7_p_5">The "‑I" option will generate a table of xo_info_t structures ,</p> 25881<p id="doc_section_7_p_6">The "‑V" option does not report errors, but prints a complete list of all field names, sorted alphabetically. The output can help spot inconsistencies and spelling errors.</p> 25882</div> 25883<hr class="noprint"> 25884<div class="content"> 25885<h1 id="doc_section_8" class="np"> 25886<div class="self-section-number"> 25887<a href="#doc_section_8">8_</a>�</div> 25888<a id="xohtml" href="#xohtml">xohtml</a> 25889</h1> 25890<p id="doc_section_8_p_1">xohtml is a tool for turning the output of libxo-enabled commands into html files suitable for display in modern HTML web browsers. It can be used to test and debug HTML output, as well as to make the user ache to escape the world of 70s terminal devices.</p> 25891<p id="doc_section_8_p_2">xohtml is given a command, either on the command line or via the "‑c" option. If not command is given, standard input is used. The command's output is wrapped in HTML tags, with references to supporting CSS and Javascript files, and written to standard output or the file given in the "‑f" option. The "‑b" option can be used to provide an alternative base path for the support files.</p> 25892<div id="doc_table_u.21"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 25893<thead><tr> 25894<th class="left">Option</th> 25895<th class="left">Meaning</th> 25896</tr></thead> 25897<tbody> 25898<tr> 25899<td>-b <base></td> 25900<td>Base path for finding css/javascript files</td> 25901</tr> 25902<tr> 25903<td>-c <command></td> 25904<td>Command to execute</td> 25905</tr> 25906<tr> 25907<td>-f <file></td> 25908<td>Output file name</td> 25909</tr> 25910</tbody> 25911</table></div> 25912<p id="doc_section_8_p_3">The "‑c" option takes a full command with arguments, including any libxo options needed to generate html ("‑‑libxo=html"). This value must be quoted if it consists of multiple tokens.</p> 25913</div> 25914<hr class="noprint"> 25915<div class="content"> 25916<h1 id="doc_section_9" class="np"> 25917<div class="self-section-number"> 25918<a href="#doc_section_9">9_</a>�</div> 25919<a id="xopo" href="#xopo">xopo</a> 25920</h1> 25921<p id="doc_section_9_p_1">The "xopo" utility filters ".pot" files generated by the "xgettext" utility to remove formatting information suitable for use with the "{G:}" modifier. This means that when the developer changes the formatting portion of the field definitions, or the fields modifiers, the string passed to gettext(3) is unchanged, avoiding the expense of updating any existing translation files (".po" files).</p> 25922<p id="doc_section_9_p_2">The syntax for the xopo command is one of two forms; it can be used as a filter for processing a .po or .pot file, rewriting the "msgid" strings with a simplified message string. In this mode, the input is either standard input or a file given by the "‑f" option, and the output is either standard output or a file given by the "‑o" option.</p> 25923<p id="doc_section_9_p_3">In the second mode, a simple message given using the "‑s" option on the command, and the simplified version of that message is printed on stdout.</p> 25924<div id="doc_table_u.22"><table summary="" class="tt full" cellpadding="3" cellspacing="0"> 25925<thead><tr> 25926<th class="left">Option</th> 25927<th class="left">Meaning</th> 25928</tr></thead> 25929<tbody> 25930<tr> 25931<td>-o <file></td> 25932<td>Output file name</td> 25933</tr> 25934<tr> 25935<td>-f <file></td> 25936<td>Use the given .po file as input</td> 25937</tr> 25938<tr> 25939<td>-s <text></td> 25940<td>Simplify a format string</td> 25941</tr> 25942</tbody> 25943</table></div> 25944<div id="doc_figure_u.144"></div> <pre> 25945 EXAMPLE: 25946 % xopo -s "There are {:count/%u} {:event/%.6s} events\n" 25947 There are {:count} {:event} events\n 25948 25949 % xgettext --default-domain=foo --no-wrap \ 25950 --add-comments --keyword=xo_emit --keyword=xo_emit_h \ 25951 --keyword=xo_emit_warn -C -E -n --foreign-user \ 25952 -o foo.pot.raw foo.c 25953 % xopo -f foo.pot.raw -o foo.pot 25954 </pre> <p id="doc_section_9_p_5">Use of the "‑‑no‑wrap" option for xgettext is required to ensure that incoming msgid strings are not wrapped across multiple lines.</p> 25955</div> 25956<hr class="noprint"> 25957<div class="content"> 25958<h1 id="doc_section_10" class="np"> 25959<div class="self-section-number"> 25960<a href="#doc_section_10">10_</a>�</div> 25961<a id="faqs" href="#faqs">FAQs</a> 25962</h1> 25963<p id="doc_section_10_p_1">This section contains the set of questions that users typically ask, along with answers that might be helpful.</p> 25964<p id="doc_section_10_p_2">Section Contents: </p> 25965<ul> 25966<li><a href="#general" title="General">Section�10.1</a></li> 25967<li><a href="#what-does-this-message-mean" title="What does this message mean?">Section�10.2</a></li> 25968</ul> 25969<p id="doc_section_10_p_3">Section Contents: </p> 25970<ul> 25971<li><a href="#general" title="General">Section�10.1</a></li> 25972<li><a href="#what-does-this-message-mean" title="What does this message mean?">Section�10.2</a></li> 25973</ul> 25974<div class="content"> 25975<h2 id="doc_section_10_1"> 25976<div class="self-section-number"> 25977<a href="#doc_section_10_1">10.1</a>�</div> 25978<a id="general" href="#general">General</a> 25979</h2> 25980<p id="doc_section_10_1_p_1">Section Contents: </p> 25981<ul> 25982<li><a href="#can-you-share-the-history-of-libxo" title="Can you share the history of libxo?">Section�10.1.1</a></li> 25983<li><a href="#did-the-complex-semantics-of-format-strings-evolve-over-time" title="Did the complex semantics of format strings evolve over time?">Section�10.1.2</a></li> 25984<li><a href="#good-field-names" title="What makes a good field name?">Section�10.1.3</a></li> 25985</ul> 25986<div class="content"> 25987<h3 id="doc_section_10_1_1"> 25988<div class="self-section-number"> 25989<a href="#doc_section_10_1_1">10.1.1</a>�</div> 25990<a id="can-you-share-the-history-of-libxo" href="#can-you-share-the-history-of-libxo">Can you share the history of libxo?</a> 25991</h3> 25992<p id="doc_section_10_1_1_p_1">In 2001, we added an XML API to the JUNOS operating system, which is built on top of FreeBSD. Eventually this API became standardized as the NETCONF API (RFC 6241). As part of this effort, we modified many FreeBSD utilities to emit XML, typically via a "‑X" switch. The results were mixed. The cost of maintaining this code, updating it, and carrying it were non-trivial, and contributed to our expense (and the associated delay) with upgrading the version of FreeBSD on which each release of JUNOS is based.</p> 25993<p id="doc_section_10_1_1_p_2">A recent (2014) effort within JUNOS aims at removing our modifications to the underlying FreeBSD code as a means of reducing the expense and delay in tracking HEAD. JUNOS is structured to have system components generate XML that is rendered by the CLI (think: login shell) into human-readable text. This allows the API to use the same plumbing as the CLI, and ensures that all components emit XML, and that it is emitted with knowledge of the consumer of that XML, yielding an API that have no incremental cost or feature delay.</p> 25994<p id="doc_section_10_1_1_p_3">libxo is an effort to mix the best aspects of the JUNOS strategy into FreeBSD in a seemless way, allowing commands to make printf-like output calls with a single code path.</p> 25995</div> 25996<div class="content"> 25997<h3 id="doc_section_10_1_2"> 25998<div class="self-section-number"> 25999<a href="#doc_section_10_1_2">10.1.2</a>�</div> 26000<a id="did-the-complex-semantics-of-format-strings-evolve-over-time" href="#did-the-complex-semantics-of-format-strings-evolve-over-time">Did the complex semantics of format strings evolve over time?</a> 26001</h3> 26002<p id="doc_section_10_1_2_p_1">The history is both long and short: libxo's functionality is based on what JUNOS does in a data modeling language called ODL (output definition language). In JUNOS, all subcomponents generate XML, which is feed to the CLI, where data from the ODL files tell is how to render that XML into text. ODL might had a set of tags like:</p> 26003<div id="doc_figure_u.145"></div> <pre> 26004 tag docsis-state { 26005 help "State of the DOCSIS interface"; 26006 type string; 26007 } 26008 26009 tag docsis-mode { 26010 help "DOCSIS mode (2.0/3.0) of the DOCSIS interface"; 26011 type string; 26012 } 26013 26014 tag docsis-upstream-speed { 26015 help "Operational upstream speed of the interface"; 26016 type string; 26017 } 26018 26019 tag downstream-scanning { 26020 help "Result of scanning in downstream direction"; 26021 type string; 26022 } 26023 26024 tag ranging { 26025 help "Result of ranging action"; 26026 type string; 26027 } 26028 26029 tag signal-to-noise-ratio { 26030 help "Signal to noise ratio for all channels"; 26031 type string; 26032 } 26033 26034 tag power { 26035 help "Operational power of the signal on all channels"; 26036 type string; 26037 } 26038 26039 format docsis-status-format { 26040 picture " 26041 State : @, Mode: @, Upstream speed: @ 26042 Downstream scanning: @, Ranging: @ 26043 Signal to noise ratio: @ 26044 Power: @ 26045"; 26046 line { 26047 field docsis-state; 26048 field docsis-mode; 26049 field docsis-upstream-speed; 26050 field downstream-scanning; 26051 field ranging; 26052 field signal-to-noise-ratio; 26053 field power; 26054 } 26055 } 26056 </pre> <p id="doc_section_10_1_2_p_3">These tag definitions are compiled into field definitions that are triggered when matching XML elements are seen. ODL also supports other means of defining output.</p> 26057<p id="doc_section_10_1_2_p_4">The roles and modifiers describe these details.</p> 26058<p id="doc_section_10_1_2_p_5">In moving these ideas to bsd, two things had to happen: the formatting had to happen at the source since BSD won't have a JUNOS-like CLI to do the rendering, and we can't depend on external data models like ODL, which was seen as too hard a sell to the BSD community.</p> 26059<p id="doc_section_10_1_2_p_6">The results were that the xo_emit strings are used to encode the roles, modifiers, names, and formats. They are dense and a bit cryptic, but not so unlike printf format strings that developers will be lost.</p> 26060<p id="doc_section_10_1_2_p_7">libxo is a new implementation of these ideas and is distinct from the previous implementation in JUNOS.</p> 26061</div> 26062<div class="content"> 26063<h3 id="doc_section_10_1_3"> 26064<div class="self-section-number"> 26065<a href="#doc_section_10_1_3">10.1.3</a>�</div> 26066<a id="good-field-names" href="#good-field-names">What makes a good field name?</a> 26067</h3> 26068<p id="doc_section_10_1_3_p_1">To make useful, consistent field names, follow these guidelines:</p> 26069<p id="doc_section_10_1_3_p_2"> </p> 26070<dl> 26071<dt>Use lower case, even for TLAs</dt> 26072<dd>Lower case is more civilized. Even TLAs should be lower case to avoid scenarios where the differences between "XPath" and "Xpath" drive your users crazy. Using "xpath" is simpler and better.</dd> 26073<dt>Use hyphens, not underscores</dt> 26074<dd>Use of hyphens is traditional in XML, and the XOF_UNDERSCORES flag can be used to generate underscores in JSON, if desired. But the raw field name should use hyphens.</dd> 26075<dt>Use full words</dt> 26076<dd>Don't abbreviate especially when the abbreviation is not obvious or not widely used. Use "data‑size", not "dsz" or "dsize". Use "interface" instead of "ifname", "if‑name", "iface", "if", or "intf".</dd> 26077<dt>Use <verb>-<units></dt> 26078<dd>Using the form <verb>-<units> or <verb>-<classifier>-<units> helps in making consistent, useful names, avoiding the situation where one app uses "sent‑packet" and another "packets‑sent" and another "packets‑we‑have‑sent". The <units> can be dropped when it is obvious, as can obvious words in the classification. Use "receive‑after‑window‑packets" instead of "received‑packets‑of‑data‑after‑window".</dd> 26079<dt>Reuse existing field names</dt> 26080<dd>Nothing's worse than writing expressions like:</dd> 26081</dl> 26082<div id="doc_figure_u.146"></div> <pre> 26083 if ($src1/process[pid == $pid]/name == 26084 $src2/proc-table/proc-list 26085 /proc-entry[process-id == $pid]/proc-name) { 26086 ... 26087 } 26088 </pre> <p id="doc_section_10_1_3_p_4">Find someone else who is expressing similar data and follow their fields and hierarchy. Remember the quote is not "Consistency is the hobgoblin of little minds", but "A foolish consistency is the hobgoblin of little minds".</p> 26089<p id="doc_section_10_1_3_p_5"> </p> 26090<dl> 26091<dt>Use containment as scoping</dt> 26092<dd>In the previous example, all the names are prefixed with "proc‑", which is redundant given that they are nested under the process table.</dd> 26093<dt>Think about your users</dt> 26094<dd>Have empathy for your users, choosing clear and useful fields that contain clear and useful data. You may need to augment the display content with xo_attr() calls (<a href="#xo_attr" title="Attributes (xo_attr)">Section�5.2.2</a>) or "{e:}" fields (<a href="#e-modifier" title="The Encoding Modifier ({e:})">Section�3.2.2.4</a>) to make the data useful.</dd> 26095<dt>Don't use an arbitrary number postfix</dt> 26096<dd>What does "errors2" mean? No one will know. "errors‑after‑restart" would be a better choice. Think of your users, and think of the future. If you make "errors2", the next guy will happily make "errors3" and before you know it, someone will be asking what's the difference between errors37 and errors63.</dd> 26097<dt>Be consistent, uniform, unsurprising, and predictable</dt> 26098<dd>Think of your field vocabulary as an API. You want it useful, expressive, meaningful, direct, and obvious. You want the client application's programmer to move between without the need to understand a variety of opinions on how fields are named. They should see the system as a single cohesive whole, not a sack of cats.</dd> 26099</dl> 26100<p id="doc_section_10_1_3_p_6">Field names constitute the means by which client programmers interact with our system. By choosing wise names now, you are making their lives better.</p> 26101<p id="doc_section_10_1_3_p_7">After using "xolint" to find errors in your field descriptors, use "xolint -V" to spell check your field names and to detect different names for the same data. "dropped‑short" and "dropped‑too‑short" are both reasonable names, but using them both will lead users to ask the difference between the two fields. If there is no difference, use only one of the field names. If there is a difference, change the names to make that difference more obvious.</p> 26102</div> 26103</div> 26104<div class="content"> 26105<h2 id="doc_section_10_2"> 26106<div class="self-section-number"> 26107<a href="#doc_section_10_2">10.2</a>�</div> 26108<a id="what-does-this-message-mean" href="#what-does-this-message-mean">What does this message mean?</a> 26109</h2> 26110<p id="doc_section_10_2_p_1">Section Contents: </p> 26111<ul> 26112<li><a href="#a-percent-sign-appearing-in-text-is-a-literal" title="'A percent sign appearing in text is a literal'">Section�10.2.1</a></li> 26113<li><a href="#unknown-long-name-for-rolemodifier" title="'Unknown long name for role/modifier'">Section�10.2.2</a></li> 26114<li><a href="#last-character-before-field-definition-is-a-field-type" title="'Last character before field definition is a field type'">Section�10.2.3</a></li> 26115<li><a href="#encoding-format-uses-different-number-of-arguments" title="'Encoding format uses different number of arguments'">Section�10.2.4</a></li> 26116<li><a href="#only-one-field-role-can-be-used" title="'Only one field role can be used'">Section�10.2.5</a></li> 26117<li><a href="#potential-missing-slash-after-c-d-n-l-or-t-with-format" title="'Potential missing slash after C, D, N, L, or T with format'">Section�10.2.6</a></li> 26118<li><a href="#an-encoding-format-cannot-be-given-roles-dnlt" title="'An encoding format cannot be given (roles: DNLT)'">Section�10.2.7</a></li> 26119<li><a href="#format-cannot-be-given-when-content-is-present-roles-cdln" title="'Format cannot be given when content is present (roles: CDLN)'">Section�10.2.8</a></li> 26120<li><a href="#field-has-color-without-fg--or-bg--role-c" title="'Field has color without fg- or bg- (role: C)'">Section�10.2.9</a></li> 26121<li><a href="#field-has-invalid-color-or-effect-role-c" title="'Field has invalid color or effect (role: C)'">Section�10.2.10</a></li> 26122<li><a href="#field-has-humanize-modifier-but-no-format-string" title="'Field has humanize modifier but no format string'">Section�10.2.11</a></li> 26123<li><a href="#field-has-hn--modifier-but-not-h-modifier" title="'Field has hn-* modifier but not 'h' modifier'">Section�10.2.12</a></li> 26124<li><a href="#value-field-must-have-a-name-as-content" title="'Value field must have a name (as content)")'">Section�10.2.13</a></li> 26125<li><a href="#use-hyphens-not-underscores-for-value-field-name" title="'Use hyphens, not underscores, for value field name'">Section�10.2.14</a></li> 26126<li><a href="#value-field-name-cannot-start-with-digit" title="'Value field name cannot start with digit'">Section�10.2.15</a></li> 26127<li><a href="#value-field-name-should-be-lower-case" title="'Value field name should be lower case'">Section�10.2.16</a></li> 26128<li><a href="#value-field-name-should-be-longer-than-two-characters" title="'Value field name should be longer than two characters'">Section�10.2.17</a></li> 26129<li><a href="#value-field-name-contains-invalid-character" title="'Value field name contains invalid character'">Section�10.2.18</a></li> 26130<li><a href="#decoration-field-contains-invalid-character" title="'decoration field contains invalid character'">Section�10.2.19</a></li> 26131<li><a href="#anchor-content-should-be-decimal-width" title="'Anchor content should be decimal width'">Section�10.2.20</a></li> 26132<li><a href="#anchor-format-should-be-d" title="'Anchor format should be "%d"'">Section�10.2.21</a></li> 26133<li><a href="#anchor-cannot-have-both-format-and-encoding-format" title="'Anchor cannot have both format and encoding format")'">Section�10.2.22</a></li> 26134<li><a href="#max-width-only-valid-for-strings" title="'Max width only valid for strings'">Section�10.2.23</a></li> 26135</ul> 26136<div class="content"> 26137<h3 id="doc_section_10_2_1"> 26138<div class="self-section-number"> 26139<a href="#doc_section_10_2_1">10.2.1</a>�</div> 26140<a id="a-percent-sign-appearing-in-text-is-a-literal" href="#a-percent-sign-appearing-in-text-is-a-literal">'A percent sign appearing in text is a literal'</a> 26141</h3> 26142<p id="doc_section_10_2_1_p_1">The message "A percent sign appearing in text is a literal" can be caused by code like:</p> 26143<div id="doc_figure_u.147"></div> <pre> 26144 xo_emit("cost: %d", cost); 26145 </pre> <p id="doc_section_10_2_1_p_3">This code should be replaced with code like:</p> 26146<div id="doc_figure_u.148"></div> <pre> 26147 xo_emit("{L:cost}: {:cost/%d}", cost); 26148 </pre> <p id="doc_section_10_2_1_p_5">This can be a bit surprising and could be a field that was not properly converted to a libxo-style format string.</p> 26149</div> 26150<div class="content"> 26151<h3 id="doc_section_10_2_2"> 26152<div class="self-section-number"> 26153<a href="#doc_section_10_2_2">10.2.2</a>�</div> 26154<a id="unknown-long-name-for-rolemodifier" href="#unknown-long-name-for-rolemodifier">'Unknown long name for role/modifier'</a> 26155</h3> 26156<p id="doc_section_10_2_2_p_1">The message "Unknown long name for role/modifier" can be caused by code like:</p> 26157<div id="doc_figure_u.149"></div> <pre> 26158 xo_emit("{,humanization:value}", value); 26159 </pre> <p id="doc_section_10_2_2_p_3">This code should be replaced with code like:</p> 26160<div id="doc_figure_u.150"></div> <pre> 26161 xo_emit("{,humanize:value}", value); 26162 </pre> <p id="doc_section_10_2_2_p_5">The hn-* modifiers (hn-decimal, hn-space, hn-1000) are only valid for fields with the {h:} modifier.</p> 26163</div> 26164<div class="content"> 26165<h3 id="doc_section_10_2_3"> 26166<div class="self-section-number"> 26167<a href="#doc_section_10_2_3">10.2.3</a>�</div> 26168<a id="last-character-before-field-definition-is-a-field-type" href="#last-character-before-field-definition-is-a-field-type">'Last character before field definition is a field type'</a> 26169</h3> 26170<p id="doc_section_10_2_3_p_1">The message "Last character before field definition is a field type" can be caused by code like:</p> 26171<p id="doc_section_10_2_3_p_2">A common typo:</p> 26172<div id="doc_figure_u.151"></div> <pre> 26173 xo_emit("{T:Min} T{:Max}"); 26174 </pre> <p id="doc_section_10_2_3_p_4">This code should be replaced with code like:</p> 26175<div id="doc_figure_u.152"></div> <pre> 26176 xo_emit("{T:Min} {T:Max}"); 26177 </pre> <p id="doc_section_10_2_3_p_6">Twiddling the "{" and the field role is a common typo.</p> 26178</div> 26179<div class="content"> 26180<h3 id="doc_section_10_2_4"> 26181<div class="self-section-number"> 26182<a href="#doc_section_10_2_4">10.2.4</a>�</div> 26183<a id="encoding-format-uses-different-number-of-arguments" href="#encoding-format-uses-different-number-of-arguments">'Encoding format uses different number of arguments'</a> 26184</h3> 26185<p id="doc_section_10_2_4_p_1">The message "Encoding format uses different number of arguments" can be caused by code like:</p> 26186<div id="doc_figure_u.153"></div> <pre> 26187 xo_emit("{:name/%6.6s %%04d/%s}", name, number); 26188 </pre> <p id="doc_section_10_2_4_p_3">This code should be replaced with code like:</p> 26189<div id="doc_figure_u.154"></div> <pre> 26190 xo_emit("{:name/%6.6s %04d/%s-%d}", name, number); 26191 </pre> <p id="doc_section_10_2_4_p_5">Both format should consume the same number of arguments off the stack</p> 26192</div> 26193<div class="content"> 26194<h3 id="doc_section_10_2_5"> 26195<div class="self-section-number"> 26196<a href="#doc_section_10_2_5">10.2.5</a>�</div> 26197<a id="only-one-field-role-can-be-used" href="#only-one-field-role-can-be-used">'Only one field role can be used'</a> 26198</h3> 26199<p id="doc_section_10_2_5_p_1">The message "Only one field role can be used" can be caused by code like:</p> 26200<div id="doc_figure_u.155"></div> <pre> 26201 xo_emit("{LT:Max}"); 26202 </pre> <p id="doc_section_10_2_5_p_3">This code should be replaced with code like:</p> 26203<div id="doc_figure_u.156"></div> <pre> 26204 xo_emit("{T:Max}"); 26205 </pre> </div> 26206<div class="content"> 26207<h3 id="doc_section_10_2_6"> 26208<div class="self-section-number"> 26209<a href="#doc_section_10_2_6">10.2.6</a>�</div> 26210<a id="potential-missing-slash-after-c-d-n-l-or-t-with-format" href="#potential-missing-slash-after-c-d-n-l-or-t-with-format">'Potential missing slash after C, D, N, L, or T with format'</a> 26211</h3> 26212<p id="doc_section_10_2_6_p_1">The message "Potential missing slash after C, D, N, L, or T with format" can be caused by code like:</p> 26213<div id="doc_figure_u.157"></div> <pre> 26214 xo_emit("{T:%6.6s}\n", "Max"); 26215 </pre> <p id="doc_section_10_2_6_p_3">This code should be replaced with code like:</p> 26216<div id="doc_figure_u.158"></div> <pre> 26217 xo_emit("{T:/%6.6s}\n", "Max"); 26218 </pre> <p id="doc_section_10_2_6_p_5">The "%6.6s" will be a literal, not a field format. While it's possibly valid, it's likely a missing "/".</p> 26219</div> 26220<div class="content"> 26221<h3 id="doc_section_10_2_7"> 26222<div class="self-section-number"> 26223<a href="#doc_section_10_2_7">10.2.7</a>�</div> 26224<a id="an-encoding-format-cannot-be-given-roles-dnlt" href="#an-encoding-format-cannot-be-given-roles-dnlt">'An encoding format cannot be given (roles: DNLT)'</a> 26225</h3> 26226<p id="doc_section_10_2_7_p_1">The message "An encoding format cannot be given (roles: DNLT)" can be caused by code like:</p> 26227<div id="doc_figure_u.159"></div> <pre> 26228 xo_emit("{T:Max//%s}", "Max"); 26229 </pre> <p id="doc_section_10_2_7_p_3">Fields with the C, D, N, L, and T roles are not emitted in the 'encoding' style (JSON, XML), so an encoding format would make no sense.</p> 26230</div> 26231<div class="content"> 26232<h3 id="doc_section_10_2_8"> 26233<div class="self-section-number"> 26234<a href="#doc_section_10_2_8">10.2.8</a>�</div> 26235<a id="format-cannot-be-given-when-content-is-present-roles-cdln" href="#format-cannot-be-given-when-content-is-present-roles-cdln">'Format cannot be given when content is present (roles: CDLN)'</a> 26236</h3> 26237<p id="doc_section_10_2_8_p_1">The message "Format cannot be given when content is present (roles: CDLN)" can be caused by code like:</p> 26238<div id="doc_figure_u.160"></div> <pre> 26239 xo_emit("{N:Max/%6.6s}", "Max"); 26240 </pre> <p id="doc_section_10_2_8_p_3">Fields with the C, D, L, or N roles can't have both static literal content ("{L:Label}") and a format ("{L:/%s}"). This error will also occur when the content has a backslash in it, like "{N:Type of I/O}"; backslashes should be escaped, like "{N:Type of I\\/O}". Note the double backslash, one for handling 'C' strings, and one for libxo.</p> 26241</div> 26242<div class="content"> 26243<h3 id="doc_section_10_2_9"> 26244<div class="self-section-number"> 26245<a href="#doc_section_10_2_9">10.2.9</a>�</div> 26246<a id="field-has-color-without-fg--or-bg--role-c" href="#field-has-color-without-fg--or-bg--role-c">'Field has color without fg- or bg- (role: C)'</a> 26247</h3> 26248<p id="doc_section_10_2_9_p_1">The message "Field has color without fg- or bg- (role: C)" can be caused by code like:</p> 26249<div id="doc_figure_u.161"></div> <pre> 26250 xo_emit("{C:green}{:foo}{C:}", x); 26251 </pre> <p id="doc_section_10_2_9_p_3">This code should be replaced with code like:</p> 26252<div id="doc_figure_u.162"></div> <pre> 26253 xo_emit("{C:fg-green}{:foo}{C:}", x); 26254 </pre> <p id="doc_section_10_2_9_p_5">Colors must be prefixed by either "fg‑" or "bg‑".</p> 26255</div> 26256<div class="content"> 26257<h3 id="doc_section_10_2_10"> 26258<div class="self-section-number"> 26259<a href="#doc_section_10_2_10">10.2.10</a>�</div> 26260<a id="field-has-invalid-color-or-effect-role-c" href="#field-has-invalid-color-or-effect-role-c">'Field has invalid color or effect (role: C)'</a> 26261</h3> 26262<p id="doc_section_10_2_10_p_1">The message "Field has invalid color or effect (role: C)" can be caused by code like:</p> 26263<div id="doc_figure_u.163"></div> <pre> 26264 xo_emit("{C:fg-purple,bold}{:foo}{C:gween}", x); 26265 </pre> <p id="doc_section_10_2_10_p_3">This code should be replaced with code like:</p> 26266<div id="doc_figure_u.164"></div> <pre> 26267 xo_emit("{C:fg-red,bold}{:foo}{C:fg-green}", x); 26268 </pre> <p id="doc_section_10_2_10_p_5">The list of colors and effects are limited. The set of colors includes default, black, red, green, yellow, blue, magenta, cyan, and white, which must be prefixed by either "fg‑" or "bg‑". Effects are limited to bold, no-bold, underline, no-underline, inverse, no-inverse, normal, and reset. Values must be separated by commas.</p> 26269</div> 26270<div class="content"> 26271<h3 id="doc_section_10_2_11"> 26272<div class="self-section-number"> 26273<a href="#doc_section_10_2_11">10.2.11</a>�</div> 26274<a id="field-has-humanize-modifier-but-no-format-string" href="#field-has-humanize-modifier-but-no-format-string">'Field has humanize modifier but no format string'</a> 26275</h3> 26276<p id="doc_section_10_2_11_p_1">The message "Field has humanize modifier but no format string" can be caused by code like:</p> 26277<div id="doc_figure_u.165"></div> <pre> 26278 xo_emit("{h:value}", value); 26279 </pre> <p id="doc_section_10_2_11_p_3">This code should be replaced with code like:</p> 26280<div id="doc_figure_u.166"></div> <pre> 26281 xo_emit("{h:value/%d}", value); 26282 </pre> <p id="doc_section_10_2_11_p_5">Humanization is only value for numbers, which are not likely to use the default format ("%s").</p> 26283</div> 26284<div class="content"> 26285<h3 id="doc_section_10_2_12"> 26286<div class="self-section-number"> 26287<a href="#doc_section_10_2_12">10.2.12</a>�</div> 26288<a id="field-has-hn--modifier-but-not-h-modifier" href="#field-has-hn--modifier-but-not-h-modifier">'Field has hn-* modifier but not 'h' modifier'</a> 26289</h3> 26290<p id="doc_section_10_2_12_p_1">The message "Field has hn-* modifier but not 'h' modifier" can be caused by code like:</p> 26291<div id="doc_figure_u.167"></div> <pre> 26292 xo_emit("{,hn-1000:value}", value); 26293 </pre> <p id="doc_section_10_2_12_p_3">This code should be replaced with code like:</p> 26294<div id="doc_figure_u.168"></div> <pre> 26295 xo_emit("{h,hn-1000:value}", value); 26296 </pre> <p id="doc_section_10_2_12_p_5">The hn-* modifiers (hn-decimal, hn-space, hn-1000) are only valid for fields with the {h:} modifier.</p> 26297</div> 26298<div class="content"> 26299<h3 id="doc_section_10_2_13"> 26300<div class="self-section-number"> 26301<a href="#doc_section_10_2_13">10.2.13</a>�</div> 26302<a id="value-field-must-have-a-name-as-content" href="#value-field-must-have-a-name-as-content">'Value field must have a name (as content)")'</a> 26303</h3> 26304<p id="doc_section_10_2_13_p_1">The message "Value field must have a name (as content)")" can be caused by code like:</p> 26305<div id="doc_figure_u.169"></div> <pre> 26306 xo_emit("{:/%s}", "value"); 26307 </pre> <p id="doc_section_10_2_13_p_3">This code should be replaced with code like:</p> 26308<div id="doc_figure_u.170"></div> <pre> 26309 xo_emit("{:tag-name/%s}", "value"); 26310 </pre> <p id="doc_section_10_2_13_p_5">The field name is used for XML and JSON encodings. These tags names are static and must appear directly in the field descriptor.</p> 26311</div> 26312<div class="content"> 26313<h3 id="doc_section_10_2_14"> 26314<div class="self-section-number"> 26315<a href="#doc_section_10_2_14">10.2.14</a>�</div> 26316<a id="use-hyphens-not-underscores-for-value-field-name" href="#use-hyphens-not-underscores-for-value-field-name">'Use hyphens, not underscores, for value field name'</a> 26317</h3> 26318<p id="doc_section_10_2_14_p_1">The message "Use hyphens, not underscores, for value field name" can be caused by code like:</p> 26319<div id="doc_figure_u.171"></div> <pre> 26320 xo_emit("{:no_under_scores}", "bad"); 26321 </pre> <p id="doc_section_10_2_14_p_3">This code should be replaced with code like:</p> 26322<div id="doc_figure_u.172"></div> <pre> 26323 xo_emit("{:no-under-scores}", "bad"); 26324 </pre> <p id="doc_section_10_2_14_p_5">Use of hyphens is traditional in XML, and the XOF_UNDERSCORES flag can be used to generate underscores in JSON, if desired. But the raw field name should use hyphens.</p> 26325</div> 26326<div class="content"> 26327<h3 id="doc_section_10_2_15"> 26328<div class="self-section-number"> 26329<a href="#doc_section_10_2_15">10.2.15</a>�</div> 26330<a id="value-field-name-cannot-start-with-digit" href="#value-field-name-cannot-start-with-digit">'Value field name cannot start with digit'</a> 26331</h3> 26332<p id="doc_section_10_2_15_p_1">The message "Value field name cannot start with digit" can be caused by code like:</p> 26333<div id="doc_figure_u.173"></div> <pre> 26334 xo_emit("{:10-gig/}"); 26335 </pre> <p id="doc_section_10_2_15_p_3">This code should be replaced with code like:</p> 26336<div id="doc_figure_u.174"></div> <pre> 26337 xo_emit("{:ten-gig/}"); 26338 </pre> <p id="doc_section_10_2_15_p_5">XML element names cannot start with a digit.</p> 26339</div> 26340<div class="content"> 26341<h3 id="doc_section_10_2_16"> 26342<div class="self-section-number"> 26343<a href="#doc_section_10_2_16">10.2.16</a>�</div> 26344<a id="value-field-name-should-be-lower-case" href="#value-field-name-should-be-lower-case">'Value field name should be lower case'</a> 26345</h3> 26346<p id="doc_section_10_2_16_p_1">The message "Value field name should be lower case" can be caused by code like:</p> 26347<div id="doc_figure_u.175"></div> <pre> 26348 xo_emit("{:WHY-ARE-YOU-SHOUTING}", "NO REASON"); 26349 </pre> <p id="doc_section_10_2_16_p_3">This code should be replaced with code like:</p> 26350<div id="doc_figure_u.176"></div> <pre> 26351 xo_emit("{:why-are-you-shouting}", "no reason"); 26352 </pre> <p id="doc_section_10_2_16_p_5">Lower case is more civilized. Even TLAs should be lower case to avoid scenarios where the differences between "XPath" and "Xpath" drive your users crazy. Lower case rules the seas.</p> 26353</div> 26354<div class="content"> 26355<h3 id="doc_section_10_2_17"> 26356<div class="self-section-number"> 26357<a href="#doc_section_10_2_17">10.2.17</a>�</div> 26358<a id="value-field-name-should-be-longer-than-two-characters" href="#value-field-name-should-be-longer-than-two-characters">'Value field name should be longer than two characters'</a> 26359</h3> 26360<p id="doc_section_10_2_17_p_1">The message "Value field name should be longer than two characters" can be caused by code like:</p> 26361<div id="doc_figure_u.177"></div> <pre> 26362 xo_emit("{:x}", "mumble"); 26363 </pre> <p id="doc_section_10_2_17_p_3">This code should be replaced with code like:</p> 26364<div id="doc_figure_u.178"></div> <pre> 26365 xo_emit("{:something-meaningful}", "mumble"); 26366 </pre> <p id="doc_section_10_2_17_p_5">Field names should be descriptive, and it's hard to be descriptive in less than two characters. Consider your users and try to make something more useful. Note that this error often occurs when the field type is placed after the colon ("{:T/%20s}"), instead of before it ("{T:/20s}").</p> 26367</div> 26368<div class="content"> 26369<h3 id="doc_section_10_2_18"> 26370<div class="self-section-number"> 26371<a href="#doc_section_10_2_18">10.2.18</a>�</div> 26372<a id="value-field-name-contains-invalid-character" href="#value-field-name-contains-invalid-character">'Value field name contains invalid character'</a> 26373</h3> 26374<p id="doc_section_10_2_18_p_1">The message "Value field name contains invalid character" can be caused by code like:</p> 26375<div id="doc_figure_u.179"></div> <pre> 26376 xo_emit("{:cost-in-$$/%u}", 15); 26377 </pre> <p id="doc_section_10_2_18_p_3">This code should be replaced with code like:</p> 26378<div id="doc_figure_u.180"></div> <pre> 26379 xo_emit("{:cost-in-dollars/%u}", 15); 26380 </pre> <p id="doc_section_10_2_18_p_5">An invalid character is often a sign of a typo, like "{:]}" instead of "{]:}". Field names are restricted to lower-case characters, digits, and hyphens.</p> 26381</div> 26382<div class="content"> 26383<h3 id="doc_section_10_2_19"> 26384<div class="self-section-number"> 26385<a href="#doc_section_10_2_19">10.2.19</a>�</div> 26386<a id="decoration-field-contains-invalid-character" href="#decoration-field-contains-invalid-character">'decoration field contains invalid character'</a> 26387</h3> 26388<p id="doc_section_10_2_19_p_1">The message "decoration field contains invalid character" can be caused by code like:</p> 26389<div id="doc_figure_u.181"></div> <pre> 26390 xo_emit("{D:not good}"); 26391 </pre> <p id="doc_section_10_2_19_p_3">This code should be replaced with code like:</p> 26392<div id="doc_figure_u.182"></div> <pre> 26393 xo_emit("{D:((}{:good}{D:))}", "yes"); 26394 </pre> <p id="doc_section_10_2_19_p_5">This is minor, but fields should use proper roles. Decoration fields are meant to hold punctuation and other characters used to decorate the content, typically to make it more readable to human readers.</p> 26395</div> 26396<div class="content"> 26397<h3 id="doc_section_10_2_20"> 26398<div class="self-section-number"> 26399<a href="#doc_section_10_2_20">10.2.20</a>�</div> 26400<a id="anchor-content-should-be-decimal-width" href="#anchor-content-should-be-decimal-width">'Anchor content should be decimal width'</a> 26401</h3> 26402<p id="doc_section_10_2_20_p_1">The message "Anchor content should be decimal width" can be caused by code like:</p> 26403<div id="doc_figure_u.183"></div> <pre> 26404 xo_emit("{[:mumble}"); 26405 </pre> <p id="doc_section_10_2_20_p_3">This code should be replaced with code like:</p> 26406<div id="doc_figure_u.184"></div> <pre> 26407 xo_emit("{[:32}"); 26408 </pre> <p id="doc_section_10_2_20_p_5">Anchors need an integer value to specify the width of the set of anchored fields. The value can be positive (for left padding/right justification) or negative (for right padding/left justification) and can appear in either the start or stop anchor field descriptor.</p> 26409</div> 26410<div class="content"> 26411<h3 id="doc_section_10_2_21"> 26412<div class="self-section-number"> 26413<a href="#doc_section_10_2_21">10.2.21</a>�</div> 26414<a id="anchor-format-should-be-d" href="#anchor-format-should-be-d">'Anchor format should be "%d"'</a> 26415</h3> 26416<p id="doc_section_10_2_21_p_1">The message "Anchor format should be "%d"" can be caused by code like:</p> 26417<div id="doc_figure_u.185"></div> <pre> 26418 xo_emit("{[:/%s}"); 26419 </pre> <p id="doc_section_10_2_21_p_3">This code should be replaced with code like:</p> 26420<div id="doc_figure_u.186"></div> <pre> 26421 xo_emit("{[:/%d}"); 26422 </pre> <p id="doc_section_10_2_21_p_5">Anchors only grok integer values, and if the value is not static, if must be in an 'int' argument, represented by the "%d" format. Anything else is an error.</p> 26423</div> 26424<div class="content"> 26425<h3 id="doc_section_10_2_22"> 26426<div class="self-section-number"> 26427<a href="#doc_section_10_2_22">10.2.22</a>�</div> 26428<a id="anchor-cannot-have-both-format-and-encoding-format" href="#anchor-cannot-have-both-format-and-encoding-format">'Anchor cannot have both format and encoding format")'</a> 26429</h3> 26430<p id="doc_section_10_2_22_p_1">The message "Anchor cannot have both format and encoding format")" can be caused by code like:</p> 26431<div id="doc_figure_u.187"></div> <pre> 26432 xo_emit("{[:32/%d}"); 26433 </pre> <p id="doc_section_10_2_22_p_3">This code should be replaced with code like:</p> 26434<div id="doc_figure_u.188"></div> <pre> 26435 xo_emit("{[:32}"); 26436 </pre> <p id="doc_section_10_2_22_p_5">Anchors can have a static value or argument for the width, but cannot have both.</p> 26437</div> 26438<div class="content"> 26439<h3 id="doc_section_10_2_23"> 26440<div class="self-section-number"> 26441<a href="#doc_section_10_2_23">10.2.23</a>�</div> 26442<a id="max-width-only-valid-for-strings" href="#max-width-only-valid-for-strings">'Max width only valid for strings'</a> 26443</h3> 26444<p id="doc_section_10_2_23_p_1">The message "Max width only valid for strings" can be caused by code like:</p> 26445<div id="doc_figure_u.189"></div> <pre> 26446 xo_emit("{:tag/%2.4.6d}", 55); 26447 </pre> <p id="doc_section_10_2_23_p_3">This code should be replaced with code like:</p> 26448<div id="doc_figure_u.190"></div> <pre> 26449 xo_emit("{:tag/%2.6d}", 55); 26450 </pre> <p id="doc_section_10_2_23_p_5">libxo allows a true 'max width' in addition to the traditional printf-style 'max number of bytes to use for input'. But this is supported only for string values, since it makes no sense for non-strings. This error may occur from a typo, like "{:tag/%6..6d}" where only one period should be used.</p> 26451</div> 26452</div> 26453</div> 26454<hr class="noprint"> 26455<div class="content"> 26456<h1 id="doc_section_11" class="np"> 26457<div class="self-section-number"> 26458<a href="#doc_section_11">11_</a>�</div> 26459<a id="howtos-focused-directions" href="#howtos-focused-directions">Howtos: Focused Directions</a> 26460</h1> 26461<p id="doc_section_11_p_1">This section provides task-oriented instructions for selected tasks. If you have a task that needs instructions, please open a request as an enhancement issue on github.</p> 26462<p id="doc_section_11_p_2">Section Contents: </p> 26463<ul> 26464<li><a href="#howto-report-bugs" title="Howto: Report bugs">Section�11.1</a></li> 26465<li><a href="#howto-install-libxo" title="Howto: Install libxo">Section�11.2</a></li> 26466<li><a href="#howto-convert-command-line-applications" title="Howto: Convert command line applications">Section�11.3</a></li> 26467<li><a href="#howto-use-xo-in-shell-scripts" title='Howto: Use "xo" in Shell Scripts'>Section�11.4</a></li> 26468<li><a href="#howto-i18n" title="Howto: Internationalization (i18n)">Section�11.5</a></li> 26469</ul> 26470<div class="content"> 26471<h2 id="doc_section_11_1"> 26472<div class="self-section-number"> 26473<a href="#doc_section_11_1">11.1</a>�</div> 26474<a id="howto-report-bugs" href="#howto-report-bugs">Howto: Report bugs</a> 26475</h2> 26476<p id="doc_section_11_1_p_1">libxo uses github to track bugs or request enhancements. Please use the following URL:</p> 26477<p id="doc_section_11_1_p_2"> <a href="https://github.com/Juniper/libxo/issues">https://github.com/Juniper/libxo/issues</a></p> 26478</div> 26479<div class="content"> 26480<h2 id="doc_section_11_2"> 26481<div class="self-section-number"> 26482<a href="#doc_section_11_2">11.2</a>�</div> 26483<a id="howto-install-libxo" href="#howto-install-libxo">Howto: Install libxo</a> 26484</h2> 26485<p id="doc_section_11_2_p_1">libxo is open source, under a new BSD license. Source code is available on github, as are recent releases. To get the most current release, please visit:</p> 26486<p id="doc_section_11_2_p_2"> <a href="https://github.com/Juniper/libxo/releases">https://github.com/Juniper/libxo/releases</a></p> 26487<p id="doc_section_11_2_p_3">After downloading and untarring the source code, building involves the following steps:</p> 26488<div id="doc_figure_u.191"></div> <pre> 26489 sh bin/setup.sh 26490 cd build 26491 ../configure 26492 make 26493 make test 26494 sudo make install 26495 </pre> <p id="doc_section_11_2_p_5">libxo uses a distinct "build" directory to keep generated files separated from source files.</p> 26496<p id="doc_section_11_2_p_6">Use "../configure --help" to display available configuration options, which include the following:</p> 26497<div id="doc_figure_u.192"></div> <pre> 26498 --enable-warnings Turn on compiler warnings 26499 --enable-debug Turn on debugging 26500 --enable-text-only Turn on text-only rendering 26501 --enable-printflike Enable use of GCC __printflike attribute 26502 --disable-libxo-options Turn off support for LIBXO_OPTIONS 26503 --with-gettext=PFX Specify location of gettext installation 26504 --with-libslax-prefix=PFX Specify location of libslax config 26505 </pre> <p id="doc_section_11_2_p_8">Compiler warnings are a very good thing, but recent compiler version have added some very pedantic checks. While every attempt is made to keep libxo code warning-free, warnings are now optional. If you are doing development work on libxo, it is required that you use --enable-warnings to keep the code warning free, but most users need not use this option.</p> 26506<p id="doc_section_11_2_p_9">libxo provides the --enable-text-only option to reduce the footprint of the library for smaller installations. XML, JSON, and HTML rendering logic is removed.</p> 26507<p id="doc_section_11_2_p_10">The gettext library does not provide a simple means of learning its location, but libxo will look for it in /usr and /opt/local. If installed elsewhere, the installer will need to provide this information using the --with-gettext=/dir/path option.</p> 26508<p id="doc_section_11_2_p_11">libslax is not required by libxo; it contains the "oxtradoc" program used to format documentation.</p> 26509<p id="doc_section_11_2_p_12">For additional information, see <a href="#building-libxo" title="Building libxo">Section�2.2</a>.</p> 26510</div> 26511<div class="content"> 26512<h2 id="doc_section_11_3"> 26513<div class="self-section-number"> 26514<a href="#doc_section_11_3">11.3</a>�</div> 26515<a id="howto-convert-command-line-applications" href="#howto-convert-command-line-applications">Howto: Convert command line applications</a> 26516</h2> 26517<div id="doc_figure_u.193"></div> <pre> 26518 How do I convert an existing command line application? 26519 </pre> <p id="doc_section_11_3_p_2">There are three basic steps for converting command line application to use libxo.</p> 26520<p id="doc_section_11_3_p_3"> </p> 26521<ul> 26522<li>Setting up the context</li> 26523<li>Converting printf calls</li> 26524<li>Creating hierarchy</li> 26525<li>Converting error functions</li> 26526</ul> 26527<p id="doc_section_11_3_p_4">Section Contents: </p> 26528<ul> 26529<li><a href="#setting-up-the-context" title="Setting up the context">Section�11.3.1</a></li> 26530<li><a href="#converting-printf-calls" title="Converting printf Calls">Section�11.3.2</a></li> 26531<li><a href="#creating-hierarchy" title="Creating Hierarchy">Section�11.3.3</a></li> 26532<li><a href="#converting-error-functions" title="Converting Error Functions">Section�11.3.4</a></li> 26533</ul> 26534<div class="content"> 26535<h3 id="doc_section_11_3_1"> 26536<div class="self-section-number"> 26537<a href="#doc_section_11_3_1">11.3.1</a>�</div> 26538<a id="setting-up-the-context" href="#setting-up-the-context">Setting up the context</a> 26539</h3> 26540<p id="doc_section_11_3_1_p_1">To use libxo, you'll need to include the "xo.h" header file in your source code files:</p> 26541<div id="doc_figure_u.194"></div> <pre> 26542 #include <libxo/xo.h> 26543 </pre> <p id="doc_section_11_3_1_p_3">In your main() function, you'll need to call xo_parse_args to handling argument parsing (<a href="#xo_parse_args" title="Parsing Command-line Arguments (xo_parse_args)">Section�5.4.1</a>). This function removes libxo-specific arguments the program's argv and returns either the number of remaining arguments or -1 to indicate an error.</p> 26544<div id="doc_figure_u.195"></div> <pre> 26545 int main (int argc, char **argv) 26546 { 26547 argc = xo_parse_args(argc, argv); 26548 if (argc < 0) 26549 return argc; 26550 .... 26551 } 26552 </pre> <p id="doc_section_11_3_1_p_5">At the bottom of your main(), you'll need to call xo_finish() to complete output processing for the default handle (<a href="#handles" title="Handles">Section�5.1</a>). libxo provides the xo_finish_atexit function that is suitable for use with the atexit(3) function.</p> 26553<div id="doc_figure_u.196"></div> <pre> 26554 atexit(xo_finish_atexit); 26555 </pre> </div> 26556<div class="content"> 26557<h3 id="doc_section_11_3_2"> 26558<div class="self-section-number"> 26559<a href="#doc_section_11_3_2">11.3.2</a>�</div> 26560<a id="converting-printf-calls" href="#converting-printf-calls">Converting printf Calls</a> 26561</h3> 26562<p id="doc_section_11_3_2_p_1">The second task is inspecting code for printf(3) calls and replacing them with xo_emit() calls. The format strings are similar in task, but libxo format strings wrap output fields in braces. The following two calls produce identical text output:</p> 26563<div id="doc_figure_u.197"></div> <pre> 26564 printf("There are %d %s events\n", count, etype); 26565 xo_emit("There are {:count/%d} {:event} events\n", count, etype); 26566 </pre> <p id="doc_section_11_3_2_p_3">"count" and "event" are used as names for JSON and XML output. The "count" field uses the format "%d" and "event" uses the default "%s" format. Both are "value" roles, which is the default role.</p> 26567<p id="doc_section_11_3_2_p_4">Since text outside of output fields is passed verbatim, other roles are less important, but their proper use can help make output more useful. The "note" and "label" roles allow HTML output to recognize the relationship between text and the associated values, allowing appropriate "hover" and "onclick" behavior. Using the "units" role allows the presentation layer to perform conversions when needed. The "warning" and "error" roles allows use of color and font to draw attention to warnings. The "padding" role makes the use of vital whitespace more clear (<a href="#padding-role" title="The Padding Role ({P:})">Section�3.2.1.6</a>).</p> 26568<p id="doc_section_11_3_2_p_5">The "title" role indicates the headings of table and sections. This allows HTML output to use CSS to make this relationship more obvious.</p> 26569<div id="doc_figure_u.198"></div> <pre> 26570 printf("Statistics:\n"); 26571 xo_emit("{T:Statistics}:\n"); 26572 </pre> <p id="doc_section_11_3_2_p_7">The "color" roles controls foreground and background colors, as well as effects like bold and underline (see <a href="#color-role" title="The Color Role ({C:})">Section�3.2.1.1</a>).</p> 26573<div id="doc_figure_u.199"></div> <pre> 26574 xo_emit("{C:bold}required{C:}\n"); 26575 </pre> <p id="doc_section_11_3_2_p_9">Finally, the start- and stop-anchor roles allow justification and padding over multiple fields (see <a href="#anchor-role" title="The Anchor Roles ({[:} and {]:})">Section�3.2.1.10</a>).</p> 26576<div id="doc_figure_u.200"></div> <pre> 26577 snprintf(buf, sizeof(buf), "(%u/%u/%u)", min, ave, max); 26578 printf("%30s", buf); 26579 26580 xo_emit("{[:30}({:minimum/%u}/{:average/%u}/{:maximum/%u}{]:}", 26581 min, ave, max); 26582 </pre> </div> 26583<div class="content"> 26584<h3 id="doc_section_11_3_3"> 26585<div class="self-section-number"> 26586<a href="#doc_section_11_3_3">11.3.3</a>�</div> 26587<a id="creating-hierarchy" href="#creating-hierarchy">Creating Hierarchy</a> 26588</h3> 26589<p id="doc_section_11_3_3_p_1">Text output doesn't have any sort of hierarchy, but XML and JSON require this. Typically applications use indentation to represent these relationship:</p> 26590<div id="doc_figure_u.201"></div> <pre> 26591 printf("table %d\n", tnum); 26592 for (i = 0; i < tmax; i++) { 26593 printf(" %s %d\n", table[i].name, table[i].size); 26594 } 26595 26596 xo_emit("{T:/table %d}\n", tnum); 26597 xo_open_list("table"); 26598 for (i = 0; i < tmax; i++) { 26599 xo_open_instance("table"); 26600 xo_emit("{P: }{k:name} {:size/%d}\n", 26601 table[i].name, table[i].size); 26602 xo_close_instance("table"); 26603 } 26604 xo_close_list("table"); 26605 </pre> <p id="doc_section_11_3_3_p_3">The open and close list functions are used before and after the list, and the open and close instance functions are used before and after each instance with in the list.</p> 26606<p id="doc_section_11_3_3_p_4">Typically these developer looks for a "for" loop as an indication of where to put these calls.</p> 26607<p id="doc_section_11_3_3_p_5">In addition, the open and close container functions allow for organization levels of hierarchy.</p> 26608<div id="doc_figure_u.202"></div> <pre> 26609 printf("Paging information:\n"); 26610 printf(" Free: %lu\n", free); 26611 printf(" Active: %lu\n", active); 26612 printf(" Inactive: %lu\n", inactive); 26613 26614 xo_open_container("paging-information"); 26615 xo_emit("{P: }{L:Free: }{:free/%lu}\n", free); 26616 xo_emit("{P: }{L:Active: }{:active/%lu}\n", active); 26617 xo_emit("{P: }{L:Inactive: }{:inactive/%lu}\n", inactive); 26618 xo_close_container("paging-information"); 26619 </pre> </div> 26620<div class="content"> 26621<h3 id="doc_section_11_3_4"> 26622<div class="self-section-number"> 26623<a href="#doc_section_11_3_4">11.3.4</a>�</div> 26624<a id="converting-error-functions" href="#converting-error-functions">Converting Error Functions</a> 26625</h3> 26626<p id="doc_section_11_3_4_p_1">libxo provides variants of the standard error and warning functions, err(3) and warn(3). There are two variants, one for putting the errors on standard error, and the other writes the errors and warnings to the handle using the appropriate encoding style:</p> 26627<div id="doc_figure_u.203"></div> <pre> 26628 err(1, "cannot open output file: %s", file); 26629 26630 xo_err(1, "cannot open output file: %s", file); 26631 xo_emit_err(1, "cannot open output file: {:filename}", file); 26632 </pre> </div> 26633</div> 26634<div class="content"><h2 id="doc_section_11_4"> 26635<div class="self-section-number"> 26636<a href="#doc_section_11_4">11.4</a>�</div> 26637<a id="howto-use-xo-in-shell-scripts" href="#howto-use-xo-in-shell-scripts">Howto: Use "xo" in Shell Scripts</a> 26638</h2></div> 26639<div class="content"> 26640<h2 id="doc_section_11_5"> 26641<div class="self-section-number"> 26642<a href="#doc_section_11_5">11.5</a>�</div> 26643<a id="howto-i18n" href="#howto-i18n">Howto: Internationalization (i18n)</a> 26644</h2> 26645<div id="doc_figure_u.204"></div> <pre> 26646 How do I use libxo to support internationalization? 26647 </pre> <p id="doc_section_11_5_p_2">libxo allows format and field strings to be used a keys into message catalogs to enable translation into a user's native language by invoking the standard gettext(3) functions.</p> 26648<p id="doc_section_11_5_p_3">gettext setup is a bit complicated: text strings are extracted from source files into "portable object template" (.pot) files using the "xgettext" command. For each language, this template file is used as the source for a message catalog in the "portable object" (.po) format, which are translated by hand and compiled into "machine object" (.mo) files using the "msgfmt" command. The .mo files are then typically installed in the /usr/share/locale or /opt/local/share/locale directories. At run time, the user's language settings are used to select a .mo file which is searched for matching messages. Text strings in the source code are used as keys to look up the native language strings in the .mo file.</p> 26649<p id="doc_section_11_5_p_4">Since the xo_emit format string is used as the key into the message catalog, libxo removes unimportant field formatting and modifiers from the format string before use so that minor formatting changes will not impact the expensive translation process. We don't want a developer change such as changing "/%06d" to "/%08d" to force hand inspection of all .po files. The simplified version can be generated for a single message using the "xopo -s <text>" command, or an entire .pot can be translated using the "xopo -f <input> -o <output>" command.</p> 26650<div id="doc_figure_u.205"></div> <pre> 26651 EXAMPLE: 26652 % xopo -s "There are {:count/%u} {:event/%.6s} events\n" 26653 There are {:count} {:event} events\n 26654 26655 Recommended workflow: 26656 # Extract text messages 26657 xgettext --default-domain=foo --no-wrap \ 26658 --add-comments --keyword=xo_emit --keyword=xo_emit_h \ 26659 --keyword=xo_emit_warn -C -E -n --foreign-user \ 26660 -o foo.pot.raw foo.c 26661 26662 # Simplify format strings for libxo 26663 xopo -f foo.pot.raw -o foo.pot 26664 26665 # For a new language, just copy the file 26666 cp foo.pot po/LC/my_lang/foo.po 26667 26668 # For an existing language: 26669 msgmerge --no-wrap po/LC/my_lang/foo.po \ 26670 foo.pot -o po/LC/my_lang/foo.po.new 26671 26672 # Now the hard part: translate foo.po using tools 26673 # like poedit or emacs' po-mode 26674 26675 # Compile the finished file; Use of msgfmt's "-v" option is 26676 # strongly encouraged, so that "fuzzy" entries are reported. 26677 msgfmt -v -o po/my_lang/LC_MESSAGES/foo.mo po/my_lang/foo.po 26678 26679 # Install the .mo file 26680 sudo cp po/my_lang/LC_MESSAGES/foo.mo \ 26681 /opt/local/share/locale/my_lang/LC_MESSAGE/ 26682 </pre> <p id="doc_section_11_5_p_6">Once these steps are complete, you can use the "gettext" command to test the message catalog:</p> 26683<div id="doc_figure_u.206"></div> <pre> 26684 gettext -d foo -e "some text" 26685 </pre> <p id="doc_section_11_5_p_8">Section Contents: </p> 26686<ul><li><a href="#i18n-and-xo_emit" title="i18n and xo_emit">Section�11.5.1</a></li></ul> 26687<div class="content"> 26688<h3 id="doc_section_11_5_1"> 26689<div class="self-section-number"> 26690<a href="#doc_section_11_5_1">11.5.1</a>�</div> 26691<a id="i18n-and-xo_emit" href="#i18n-and-xo_emit">i18n and xo_emit</a> 26692</h3> 26693<p id="doc_section_11_5_1_p_1">There are three features used in libxo used to support i18n:</p> 26694<p id="doc_section_11_5_1_p_2"> </p> 26695<ul> 26696<li>The "{G:}" role looks for a translation of the format string.</li> 26697<li>The "{g:}" modifier looks for a translation of the field.</li> 26698<li>The "{p:}" modifier looks for a pluralized version of the field.</li> 26699</ul> 26700<p id="doc_section_11_5_1_p_3">Together these three flags allows a single function call to give native language support, as well as libxo's normal XML, JSON, and HTML support.</p> 26701<div id="doc_figure_u.207"></div> <pre> 26702 printf(gettext("Received %zu %s from {g:server} server\n"), 26703 counter, ngettext("byte", "bytes", counter), 26704 gettext("web")); 26705 26706 xo_emit("{G:}Received {:received/%zu} {Ngp:byte,bytes} " 26707 "from {g:server} server\n", counter, "web"); 26708 </pre> <p id="doc_section_11_5_1_p_5">libxo will see the "{G:}" role and will first simplify the format string, removing field formats and modifiers.</p> 26709<div id="doc_figure_u.208"></div> <pre> 26710 "Received {:received} {N:byte,bytes} from {:server} server\n" 26711 </pre> <p id="doc_section_11_5_1_p_7">libxo calls gettext(3) with that string to get a localized version. If your language were Pig Latin, the result might look like:</p> 26712<div id="doc_figure_u.209"></div> <pre> 26713 "Eceivedray {:received} {N:byte,bytes} omfray " 26714 "{:server} erversay\n" 26715 </pre> <p id="doc_section_11_5_1_p_9">Note the field names do not change and they should not be translated. The contents of the note ("byte,bytes") should also not be translated, since the "g" modifier will need the untranslated value as the key for the message catalog.</p> 26716<p id="doc_section_11_5_1_p_10">The field "{g:server}" requests the rendered value of the field be translated using gettext(3). In this example, "web" would be used.</p> 26717<p id="doc_section_11_5_1_p_11">The field "{Ngp:byte,bytes}" shows an example of plural form using the "p" modifier with the "g" modifier. The base singular and plural forms appear inside the field, separated by a comma. At run time, libxo uses the previous field's numeric value to decide which form to use by calling ngettext(3).</p> 26718<p id="doc_section_11_5_1_p_12">If a domain name is needed, it can be supplied as the content of the {G:} role. Domain names remain in use throughout the format string until cleared with another domain name.</p> 26719<div id="doc_figure_u.210"></div> <pre> 26720 printf(dgettext("dns", "Host %s not found: %d(%s)\n"), 26721 name, errno, dgettext("strerror", strerror(errno))); 26722 26723 xo_emit("{G:dns}Host {:hostname} not found: " 26724 "%d({G:strerror}{g:%m})\n", name, errno); 26725 </pre> </div> 26726</div> 26727</div> 26728<hr class="noprint"> 26729<div class="content"> 26730<h1 id="doc_section_12" class="np"> 26731<div class="self-section-number"> 26732<a href="#doc_section_12">12_</a>�</div> 26733<a id="examples" href="#examples">Examples</a> 26734</h1> 26735<p id="doc_section_12_p_1">Section Contents: </p> 26736<ul><li><a href="#unit-test" title="Unit Test">Section�12.1</a></li></ul> 26737<div class="content"> 26738<h2 id="doc_section_12_1"> 26739<div class="self-section-number"> 26740<a href="#doc_section_12_1">12.1</a>�</div> 26741<a id="unit-test" href="#unit-test">Unit Test</a> 26742</h2> 26743<p id="doc_section_12_1_p_1">Here is the unit test example:</p> 26744<div id="doc_figure_u.211"></div> <pre> 26745 int 26746 main (int argc, char **argv) 26747 { 26748 static char base_grocery[] = "GRO"; 26749 static char base_hardware[] = "HRD"; 26750 struct item { 26751 const char *i_title; 26752 int i_sold; 26753 int i_instock; 26754 int i_onorder; 26755 const char *i_sku_base; 26756 int i_sku_num; 26757 }; 26758 struct item list[] = { 26759 { "gum", 1412, 54, 10, base_grocery, 415 }, 26760 { "rope", 85, 4, 2, base_hardware, 212 }, 26761 { "ladder", 0, 2, 1, base_hardware, 517 }, 26762 { "bolt", 4123, 144, 42, base_hardware, 632 }, 26763 { "water", 17, 14, 2, base_grocery, 2331 }, 26764 { NULL, 0, 0, 0, NULL, 0 } 26765 }; 26766 struct item list2[] = { 26767 { "fish", 1321, 45, 1, base_grocery, 533 }, 26768 }; 26769 struct item *ip; 26770 xo_info_t info[] = { 26771 { "in-stock", "number", "Number of items in stock" }, 26772 { "name", "string", "Name of the item" }, 26773 { "on-order", "number", "Number of items on order" }, 26774 { "sku", "string", "Stock Keeping Unit" }, 26775 { "sold", "number", "Number of items sold" }, 26776 { NULL, NULL, NULL }, 26777 }; 26778 int info_count = (sizeof(info) / sizeof(info[0])) - 1; 26779 26780 argc = xo_parse_args(argc, argv); 26781 if (argc < 0) 26782 exit(EXIT_FAILURE); 26783 26784 xo_set_info(NULL, info, info_count); 26785 26786 xo_open_container_h(NULL, "top"); 26787 26788 xo_open_container("data"); 26789 xo_open_list("item"); 26790 26791 for (ip = list; ip->i_title; ip++) { 26792 xo_open_instance("item"); 26793 26794 xo_emit("{L:Item} '{k:name/%s}':\n", ip->i_title); 26795 xo_emit("{P: }{L:Total sold}: {n:sold/%u%s}\n", 26796 ip->i_sold, ip->i_sold ? ".0" : ""); 26797 xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n", 26798 ip->i_instock); 26799 xo_emit("{P: }{Lwc:On order}{:on-order/%u}\n", 26800 ip->i_onorder); 26801 xo_emit("{P: }{L:SKU}: {q:sku/%s-000-%u}\n", 26802 ip->i_sku_base, ip->i_sku_num); 26803 26804 xo_close_instance("item"); 26805 } 26806 26807 xo_close_list("item"); 26808 xo_close_container("data"); 26809 26810 xo_open_container("data"); 26811 xo_open_list("item"); 26812 26813 for (ip = list2; ip->i_title; ip++) { 26814 xo_open_instance("item"); 26815 26816 xo_emit("{L:Item} '{:name/%s}':\n", ip->i_title); 26817 xo_emit("{P: }{L:Total sold}: {n:sold/%u%s}\n", 26818 ip->i_sold, ip->i_sold ? ".0" : ""); 26819 xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n", 26820 ip->i_instock); 26821 xo_emit("{P: }{Lwc:On order}{:on-order/%u}\n", 26822 ip->i_onorder); 26823 xo_emit("{P: }{L:SKU}: {q:sku/%s-000-%u}\n", 26824 ip->i_sku_base, ip->i_sku_num); 26825 26826 xo_close_instance("item"); 26827 } 26828 26829 xo_close_list("item"); 26830 xo_close_container("data"); 26831 26832 xo_close_container_h(NULL, "top"); 26833 26834 return 0; 26835 } 26836 </pre> <p id="doc_section_12_1_p_3">Text output:</p> 26837<div id="doc_figure_u.212"></div> <pre> 26838 % ./testxo --libxo text 26839 Item 'gum': 26840 Total sold: 1412.0 26841 In stock: 54 26842 On order: 10 26843 SKU: GRO-000-415 26844 Item 'rope': 26845 Total sold: 85.0 26846 In stock: 4 26847 On order: 2 26848 SKU: HRD-000-212 26849 Item 'ladder': 26850 Total sold: 0 26851 In stock: 2 26852 On order: 1 26853 SKU: HRD-000-517 26854 Item 'bolt': 26855 Total sold: 4123.0 26856 In stock: 144 26857 On order: 42 26858 SKU: HRD-000-632 26859 Item 'water': 26860 Total sold: 17.0 26861 In stock: 14 26862 On order: 2 26863 SKU: GRO-000-2331 26864 Item 'fish': 26865 Total sold: 1321.0 26866 In stock: 45 26867 On order: 1 26868 SKU: GRO-000-533 26869 </pre> <p id="doc_section_12_1_p_5">JSON output:</p> 26870<div id="doc_figure_u.213"></div> <pre> 26871 % ./testxo --libxo json,pretty 26872 "top": { 26873 "data": { 26874 "item": [ 26875 { 26876 "name": "gum", 26877 "sold": 1412.0, 26878 "in-stock": 54, 26879 "on-order": 10, 26880 "sku": "GRO-000-415" 26881 }, 26882 { 26883 "name": "rope", 26884 "sold": 85.0, 26885 "in-stock": 4, 26886 "on-order": 2, 26887 "sku": "HRD-000-212" 26888 }, 26889 { 26890 "name": "ladder", 26891 "sold": 0, 26892 "in-stock": 2, 26893 "on-order": 1, 26894 "sku": "HRD-000-517" 26895 }, 26896 { 26897 "name": "bolt", 26898 "sold": 4123.0, 26899 "in-stock": 144, 26900 "on-order": 42, 26901 "sku": "HRD-000-632" 26902 }, 26903 { 26904 "name": "water", 26905 "sold": 17.0, 26906 "in-stock": 14, 26907 "on-order": 2, 26908 "sku": "GRO-000-2331" 26909 } 26910 ] 26911 }, 26912 "data": { 26913 "item": [ 26914 { 26915 "name": "fish", 26916 "sold": 1321.0, 26917 "in-stock": 45, 26918 "on-order": 1, 26919 "sku": "GRO-000-533" 26920 } 26921 ] 26922 } 26923 } 26924 </pre> <p id="doc_section_12_1_p_7">XML output:</p> 26925<div id="doc_figure_u.214"></div> <pre> 26926 % ./testxo --libxo pretty,xml 26927 <top> 26928 <data> 26929 <item> 26930 <name>gum</name> 26931 <sold>1412.0</sold> 26932 <in-stock>54</in-stock> 26933 <on-order>10</on-order> 26934 <sku>GRO-000-415</sku> 26935 </item> 26936 <item> 26937 <name>rope</name> 26938 <sold>85.0</sold> 26939 <in-stock>4</in-stock> 26940 <on-order>2</on-order> 26941 <sku>HRD-000-212</sku> 26942 </item> 26943 <item> 26944 <name>ladder</name> 26945 <sold>0</sold> 26946 <in-stock>2</in-stock> 26947 <on-order>1</on-order> 26948 <sku>HRD-000-517</sku> 26949 </item> 26950 <item> 26951 <name>bolt</name> 26952 <sold>4123.0</sold> 26953 <in-stock>144</in-stock> 26954 <on-order>42</on-order> 26955 <sku>HRD-000-632</sku> 26956 </item> 26957 <item> 26958 <name>water</name> 26959 <sold>17.0</sold> 26960 <in-stock>14</in-stock> 26961 <on-order>2</on-order> 26962 <sku>GRO-000-2331</sku> 26963 </item> 26964 </data> 26965 <data> 26966 <item> 26967 <name>fish</name> 26968 <sold>1321.0</sold> 26969 <in-stock>45</in-stock> 26970 <on-order>1</on-order> 26971 <sku>GRO-000-533</sku> 26972 </item> 26973 </data> 26974 </top> 26975 </pre> <p id="doc_section_12_1_p_9">HMTL output:</p> 26976<div id="doc_figure_u.215"></div> <pre> 26977 % ./testxo --libxo pretty,html 26978 <div class="line"> 26979 <div class="label">Item</div> 26980 <div class="text"> '</div> 26981 <div class="data" data-tag="name">gum</div> 26982 <div class="text">':</div> 26983 </div> 26984 <div class="line"> 26985 <div class="padding"> </div> 26986 <div class="label">Total sold</div> 26987 <div class="text">: </div> 26988 <div class="data" data-tag="sold">1412.0</div> 26989 </div> 26990 <div class="line"> 26991 <div class="padding"> </div> 26992 <div class="label">In stock</div> 26993 <div class="decoration">:</div> 26994 <div class="padding"> </div> 26995 <div class="data" data-tag="in-stock">54</div> 26996 </div> 26997 <div class="line"> 26998 <div class="padding"> </div> 26999 <div class="label">On order</div> 27000 <div class="decoration">:</div> 27001 <div class="padding"> </div> 27002 <div class="data" data-tag="on-order">10</div> 27003 </div> 27004 <div class="line"> 27005 <div class="padding"> </div> 27006 <div class="label">SKU</div> 27007 <div class="text">: </div> 27008 <div class="data" data-tag="sku">GRO-000-415</div> 27009 </div> 27010 <div class="line"> 27011 <div class="label">Item</div> 27012 <div class="text"> '</div> 27013 <div class="data" data-tag="name">rope</div> 27014 <div class="text">':</div> 27015 </div> 27016 <div class="line"> 27017 <div class="padding"> </div> 27018 <div class="label">Total sold</div> 27019 <div class="text">: </div> 27020 <div class="data" data-tag="sold">85.0</div> 27021 </div> 27022 <div class="line"> 27023 <div class="padding"> </div> 27024 <div class="label">In stock</div> 27025 <div class="decoration">:</div> 27026 <div class="padding"> </div> 27027 <div class="data" data-tag="in-stock">4</div> 27028 </div> 27029 <div class="line"> 27030 <div class="padding"> </div> 27031 <div class="label">On order</div> 27032 <div class="decoration">:</div> 27033 <div class="padding"> </div> 27034 <div class="data" data-tag="on-order">2</div> 27035 </div> 27036 <div class="line"> 27037 <div class="padding"> </div> 27038 <div class="label">SKU</div> 27039 <div class="text">: </div> 27040 <div class="data" data-tag="sku">HRD-000-212</div> 27041 </div> 27042 <div class="line"> 27043 <div class="label">Item</div> 27044 <div class="text"> '</div> 27045 <div class="data" data-tag="name">ladder</div> 27046 <div class="text">':</div> 27047 </div> 27048 <div class="line"> 27049 <div class="padding"> </div> 27050 <div class="label">Total sold</div> 27051 <div class="text">: </div> 27052 <div class="data" data-tag="sold">0</div> 27053 </div> 27054 <div class="line"> 27055 <div class="padding"> </div> 27056 <div class="label">In stock</div> 27057 <div class="decoration">:</div> 27058 <div class="padding"> </div> 27059 <div class="data" data-tag="in-stock">2</div> 27060 </div> 27061 <div class="line"> 27062 <div class="padding"> </div> 27063 <div class="label">On order</div> 27064 <div class="decoration">:</div> 27065 <div class="padding"> </div> 27066 <div class="data" data-tag="on-order">1</div> 27067 </div> 27068 <div class="line"> 27069 <div class="padding"> </div> 27070 <div class="label">SKU</div> 27071 <div class="text">: </div> 27072 <div class="data" data-tag="sku">HRD-000-517</div> 27073 </div> 27074 <div class="line"> 27075 <div class="label">Item</div> 27076 <div class="text"> '</div> 27077 <div class="data" data-tag="name">bolt</div> 27078 <div class="text">':</div> 27079 </div> 27080 <div class="line"> 27081 <div class="padding"> </div> 27082 <div class="label">Total sold</div> 27083 <div class="text">: </div> 27084 <div class="data" data-tag="sold">4123.0</div> 27085 </div> 27086 <div class="line"> 27087 <div class="padding"> </div> 27088 <div class="label">In stock</div> 27089 <div class="decoration">:</div> 27090 <div class="padding"> </div> 27091 <div class="data" data-tag="in-stock">144</div> 27092 </div> 27093 <div class="line"> 27094 <div class="padding"> </div> 27095 <div class="label">On order</div> 27096 <div class="decoration">:</div> 27097 <div class="padding"> </div> 27098 <div class="data" data-tag="on-order">42</div> 27099 </div> 27100 <div class="line"> 27101 <div class="padding"> </div> 27102 <div class="label">SKU</div> 27103 <div class="text">: </div> 27104 <div class="data" data-tag="sku">HRD-000-632</div> 27105 </div> 27106 <div class="line"> 27107 <div class="label">Item</div> 27108 <div class="text"> '</div> 27109 <div class="data" data-tag="name">water</div> 27110 <div class="text">':</div> 27111 </div> 27112 <div class="line"> 27113 <div class="padding"> </div> 27114 <div class="label">Total sold</div> 27115 <div class="text">: </div> 27116 <div class="data" data-tag="sold">17.0</div> 27117 </div> 27118 <div class="line"> 27119 <div class="padding"> </div> 27120 <div class="label">In stock</div> 27121 <div class="decoration">:</div> 27122 <div class="padding"> </div> 27123 <div class="data" data-tag="in-stock">14</div> 27124 </div> 27125 <div class="line"> 27126 <div class="padding"> </div> 27127 <div class="label">On order</div> 27128 <div class="decoration">:</div> 27129 <div class="padding"> </div> 27130 <div class="data" data-tag="on-order">2</div> 27131 </div> 27132 <div class="line"> 27133 <div class="padding"> </div> 27134 <div class="label">SKU</div> 27135 <div class="text">: </div> 27136 <div class="data" data-tag="sku">GRO-000-2331</div> 27137 </div> 27138 <div class="line"> 27139 <div class="label">Item</div> 27140 <div class="text"> '</div> 27141 <div class="data" data-tag="name">fish</div> 27142 <div class="text">':</div> 27143 </div> 27144 <div class="line"> 27145 <div class="padding"> </div> 27146 <div class="label">Total sold</div> 27147 <div class="text">: </div> 27148 <div class="data" data-tag="sold">1321.0</div> 27149 </div> 27150 <div class="line"> 27151 <div class="padding"> </div> 27152 <div class="label">In stock</div> 27153 <div class="decoration">:</div> 27154 <div class="padding"> </div> 27155 <div class="data" data-tag="in-stock">45</div> 27156 </div> 27157 <div class="line"> 27158 <div class="padding"> </div> 27159 <div class="label">On order</div> 27160 <div class="decoration">:</div> 27161 <div class="padding"> </div> 27162 <div class="data" data-tag="on-order">1</div> 27163 </div> 27164 <div class="line"> 27165 <div class="padding"> </div> 27166 <div class="label">SKU</div> 27167 <div class="text">: </div> 27168 <div class="data" data-tag="sku">GRO-000-533</div> 27169 </div> 27170 </pre> <p id="doc_section_12_1_p_11">HTML output with xpath and info flags:</p> 27171<div id="doc_figure_u.216"></div> <pre> 27172 % ./testxo --libxo pretty,html,xpath,info 27173 <div class="line"> 27174 <div class="label">Item</div> 27175 <div class="text"> '</div> 27176 <div class="data" data-tag="name" 27177 data-xpath="/top/data/item/name" data-type="string" 27178 data-help="Name of the item">gum</div> 27179 <div class="text">':</div> 27180 </div> 27181 <div class="line"> 27182 <div class="padding"> </div> 27183 <div class="label">Total sold</div> 27184 <div class="text">: </div> 27185 <div class="data" data-tag="sold" 27186 data-xpath="/top/data/item/sold" data-type="number" 27187 data-help="Number of items sold">1412.0</div> 27188 </div> 27189 <div class="line"> 27190 <div class="padding"> </div> 27191 <div class="label">In stock</div> 27192 <div class="decoration">:</div> 27193 <div class="padding"> </div> 27194 <div class="data" data-tag="in-stock" 27195 data-xpath="/top/data/item/in-stock" data-type="number" 27196 data-help="Number of items in stock">54</div> 27197 </div> 27198 <div class="line"> 27199 <div class="padding"> </div> 27200 <div class="label">On order</div> 27201 <div class="decoration">:</div> 27202 <div class="padding"> </div> 27203 <div class="data" data-tag="on-order" 27204 data-xpath="/top/data/item/on-order" data-type="number" 27205 data-help="Number of items on order">10</div> 27206 </div> 27207 <div class="line"> 27208 <div class="padding"> </div> 27209 <div class="label">SKU</div> 27210 <div class="text">: </div> 27211 <div class="data" data-tag="sku" 27212 data-xpath="/top/data/item/sku" data-type="string" 27213 data-help="Stock Keeping Unit">GRO-000-415</div> 27214 </div> 27215 <div class="line"> 27216 <div class="label">Item</div> 27217 <div class="text"> '</div> 27218 <div class="data" data-tag="name" 27219 data-xpath="/top/data/item/name" data-type="string" 27220 data-help="Name of the item">rope</div> 27221 <div class="text">':</div> 27222 </div> 27223 <div class="line"> 27224 <div class="padding"> </div> 27225 <div class="label">Total sold</div> 27226 <div class="text">: </div> 27227 <div class="data" data-tag="sold" 27228 data-xpath="/top/data/item/sold" data-type="number" 27229 data-help="Number of items sold">85.0</div> 27230 </div> 27231 <div class="line"> 27232 <div class="padding"> </div> 27233 <div class="label">In stock</div> 27234 <div class="decoration">:</div> 27235 <div class="padding"> </div> 27236 <div class="data" data-tag="in-stock" 27237 data-xpath="/top/data/item/in-stock" data-type="number" 27238 data-help="Number of items in stock">4</div> 27239 </div> 27240 <div class="line"> 27241 <div class="padding"> </div> 27242 <div class="label">On order</div> 27243 <div class="decoration">:</div> 27244 <div class="padding"> </div> 27245 <div class="data" data-tag="on-order" 27246 data-xpath="/top/data/item/on-order" data-type="number" 27247 data-help="Number of items on order">2</div> 27248 </div> 27249 <div class="line"> 27250 <div class="padding"> </div> 27251 <div class="label">SKU</div> 27252 <div class="text">: </div> 27253 <div class="data" data-tag="sku" 27254 data-xpath="/top/data/item/sku" data-type="string" 27255 data-help="Stock Keeping Unit">HRD-000-212</div> 27256 </div> 27257 <div class="line"> 27258 <div class="label">Item</div> 27259 <div class="text"> '</div> 27260 <div class="data" data-tag="name" 27261 data-xpath="/top/data/item/name" data-type="string" 27262 data-help="Name of the item">ladder</div> 27263 <div class="text">':</div> 27264 </div> 27265 <div class="line"> 27266 <div class="padding"> </div> 27267 <div class="label">Total sold</div> 27268 <div class="text">: </div> 27269 <div class="data" data-tag="sold" 27270 data-xpath="/top/data/item/sold" data-type="number" 27271 data-help="Number of items sold">0</div> 27272 </div> 27273 <div class="line"> 27274 <div class="padding"> </div> 27275 <div class="label">In stock</div> 27276 <div class="decoration">:</div> 27277 <div class="padding"> </div> 27278 <div class="data" data-tag="in-stock" 27279 data-xpath="/top/data/item/in-stock" data-type="number" 27280 data-help="Number of items in stock">2</div> 27281 </div> 27282 <div class="line"> 27283 <div class="padding"> </div> 27284 <div class="label">On order</div> 27285 <div class="decoration">:</div> 27286 <div class="padding"> </div> 27287 <div class="data" data-tag="on-order" 27288 data-xpath="/top/data/item/on-order" data-type="number" 27289 data-help="Number of items on order">1</div> 27290 </div> 27291 <div class="line"> 27292 <div class="padding"> </div> 27293 <div class="label">SKU</div> 27294 <div class="text">: </div> 27295 <div class="data" data-tag="sku" 27296 data-xpath="/top/data/item/sku" data-type="string" 27297 data-help="Stock Keeping Unit">HRD-000-517</div> 27298 </div> 27299 <div class="line"> 27300 <div class="label">Item</div> 27301 <div class="text"> '</div> 27302 <div class="data" data-tag="name" 27303 data-xpath="/top/data/item/name" data-type="string" 27304 data-help="Name of the item">bolt</div> 27305 <div class="text">':</div> 27306 </div> 27307 <div class="line"> 27308 <div class="padding"> </div> 27309 <div class="label">Total sold</div> 27310 <div class="text">: </div> 27311 <div class="data" data-tag="sold" 27312 data-xpath="/top/data/item/sold" data-type="number" 27313 data-help="Number of items sold">4123.0</div> 27314 </div> 27315 <div class="line"> 27316 <div class="padding"> </div> 27317 <div class="label">In stock</div> 27318 <div class="decoration">:</div> 27319 <div class="padding"> </div> 27320 <div class="data" data-tag="in-stock" 27321 data-xpath="/top/data/item/in-stock" data-type="number" 27322 data-help="Number of items in stock">144</div> 27323 </div> 27324 <div class="line"> 27325 <div class="padding"> </div> 27326 <div class="label">On order</div> 27327 <div class="decoration">:</div> 27328 <div class="padding"> </div> 27329 <div class="data" data-tag="on-order" 27330 data-xpath="/top/data/item/on-order" data-type="number" 27331 data-help="Number of items on order">42</div> 27332 </div> 27333 <div class="line"> 27334 <div class="padding"> </div> 27335 <div class="label">SKU</div> 27336 <div class="text">: </div> 27337 <div class="data" data-tag="sku" 27338 data-xpath="/top/data/item/sku" data-type="string" 27339 data-help="Stock Keeping Unit">HRD-000-632</div> 27340 </div> 27341 <div class="line"> 27342 <div class="label">Item</div> 27343 <div class="text"> '</div> 27344 <div class="data" data-tag="name" 27345 data-xpath="/top/data/item/name" data-type="string" 27346 data-help="Name of the item">water</div> 27347 <div class="text">':</div> 27348 </div> 27349 <div class="line"> 27350 <div class="padding"> </div> 27351 <div class="label">Total sold</div> 27352 <div class="text">: </div> 27353 <div class="data" data-tag="sold" 27354 data-xpath="/top/data/item/sold" data-type="number" 27355 data-help="Number of items sold">17.0</div> 27356 </div> 27357 <div class="line"> 27358 <div class="padding"> </div> 27359 <div class="label">In stock</div> 27360 <div class="decoration">:</div> 27361 <div class="padding"> </div> 27362 <div class="data" data-tag="in-stock" 27363 data-xpath="/top/data/item/in-stock" data-type="number" 27364 data-help="Number of items in stock">14</div> 27365 </div> 27366 <div class="line"> 27367 <div class="padding"> </div> 27368 <div class="label">On order</div> 27369 <div class="decoration">:</div> 27370 <div class="padding"> </div> 27371 <div class="data" data-tag="on-order" 27372 data-xpath="/top/data/item/on-order" data-type="number" 27373 data-help="Number of items on order">2</div> 27374 </div> 27375 <div class="line"> 27376 <div class="padding"> </div> 27377 <div class="label">SKU</div> 27378 <div class="text">: </div> 27379 <div class="data" data-tag="sku" 27380 data-xpath="/top/data/item/sku" data-type="string" 27381 data-help="Stock Keeping Unit">GRO-000-2331</div> 27382 </div> 27383 <div class="line"> 27384 <div class="label">Item</div> 27385 <div class="text"> '</div> 27386 <div class="data" data-tag="name" 27387 data-xpath="/top/data/item/name" data-type="string" 27388 data-help="Name of the item">fish</div> 27389 <div class="text">':</div> 27390 </div> 27391 <div class="line"> 27392 <div class="padding"> </div> 27393 <div class="label">Total sold</div> 27394 <div class="text">: </div> 27395 <div class="data" data-tag="sold" 27396 data-xpath="/top/data/item/sold" data-type="number" 27397 data-help="Number of items sold">1321.0</div> 27398 </div> 27399 <div class="line"> 27400 <div class="padding"> </div> 27401 <div class="label">In stock</div> 27402 <div class="decoration">:</div> 27403 <div class="padding"> </div> 27404 <div class="data" data-tag="in-stock" 27405 data-xpath="/top/data/item/in-stock" data-type="number" 27406 data-help="Number of items in stock">45</div> 27407 </div> 27408 <div class="line"> 27409 <div class="padding"> </div> 27410 <div class="label">On order</div> 27411 <div class="decoration">:</div> 27412 <div class="padding"> </div> 27413 <div class="data" data-tag="on-order" 27414 data-xpath="/top/data/item/on-order" data-type="number" 27415 data-help="Number of items on order">1</div> 27416 </div> 27417 <div class="line"> 27418 <div class="padding"> </div> 27419 <div class="label">SKU</div> 27420 <div class="text">: </div> 27421 <div class="data" data-tag="sku" 27422 data-xpath="/top/data/item/sku" data-type="string" 27423 data-help="Stock Keeping Unit">GRO-000-533</div> 27424 </div> 27425 </pre> </div> 27426</div> 27427<div class="content"></div> 27428<hr class="noprint"> 27429<div class="content"> 27430<h1 id="doc.authors" class="np"><a href="#doc.authors">Author's Address</a></h1> 27431<address class="vcard"> 27432<span class="vcardline"><span class="fn">Phil Shafer</span><span class="n hidden"><span class="family-name">Shafer</span><span class="given-name">Phil</span></span></span><span class="org vcardline">Juniper Networks</span><span class="vcardline">EMail: <a href="mailto:phil@juniper.net"><span class="email">phil@juniper.net</span></a></span> 27433</address> 27434</div> 27435</body> 27436</html> 27437