| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 /* 2 * draggable unit tests 3 */ 4 (function($) { 5 // 6 // Draggable Test Helper Functions 7 // 8 9 var defaults = { 10 appendTo: "parent", 11 axis: false, 12 cancel: ":input", 13 connectToSortable: false, 14 containment: false, 15 cursor: "default", 16 cursorAt: null, 17 delay: 0, 18 disabled: false, 19 distance: 1, 20 grid: false, 21 handle: false, 22 helper: "original", 23 iframeFix: false, 24 opacity: 1.0, 25 refreshPositions: false, 26 revert: false, 27 revertDuration: 500, 28 scroll: true, 29 scrollSensitivity: 20, 30 scrollSpeed: 20, 31 scope: "default", 32 snap: false, 33 snapMode: "both", 34 snapTolerance: 20, 35 stack: false, 36 zIndex: null 37 }; 38 39 var el, offsetBefore, offsetAfter, dragged; 40 41 var drag = function(handle, dx, dy) { 42 var element = el.data("draggable").element; 43 offsetBefore = el.offset(); 44 $(handle).simulate("drag", { 45 dx: dx || 0, 46 dy: dy || 0 47 }); 48 dragged = { dx: dx, dy: dy }; 49 offsetAfter = el.offset(); 50 } 51 52 var moved = function (dx, dy, msg) { 53 msg = msg ? msg + "." : ""; 54 var actual = { left: offsetAfter.left, top: offsetAfter.top }; 55 var expected = { left: offsetBefore.left + dx, top: offsetBefore.top + dy }; 56 same(actual, expected, 'dragged[' + dragged.dx + ', ' + dragged.dy + '] ' + msg); 57 } 58 59 function shouldmove(why) { 60 drag(el, 50, 50); 61 moved(50, 50, why); 62 } 63 64 function shouldnotmove(why) { 65 drag(el, 50, 50); 66 moved(0, 0, why); 67 } 68 69 var border = function(el, side) { return parseInt(el.css('border-' + side + '-width')); } 70 71 var margin = function(el, side) { return parseInt(el.css('margin-' + side)); } 72 73 // Draggable Tests 74 module("draggable"); 75 76 test("init", function() { 77 expect(6); 78 79 $("<div></div>").appendTo('body').draggable().remove(); 80 ok(true, '.draggable() called on element'); 81 82 $([]).draggable(); 83 ok(true, '.draggable() called on empty collection'); 84 85 $("<div></div>").draggable(); 86 ok(true, '.draggable() called on disconnected DOMElement'); 87 88 $("<div></div>").draggable().draggable("foo"); 89 ok(true, 'arbitrary method called after init'); 90 91 $("<div></div>").draggable().data("foo.draggable"); 92 ok(true, 'arbitrary option getter after init'); 93 94 $("<div></div>").draggable().data("foo.draggable", "bar"); 95 ok(true, 'arbitrary option setter after init'); 96 }); 97 98 test("destroy", function() { 99 expect(6); 100 101 $("<div></div>").appendTo('body').draggable().draggable("destroy").remove(); 102 ok(true, '.draggable("destroy") called on element'); 103 104 $([]).draggable().draggable("destroy"); 105 ok(true, '.draggable("destroy") called on empty collection'); 106 107 $("<div></div>").draggable().draggable("destroy"); 108 ok(true, '.draggable("destroy") called on disconnected DOMElement'); 109 110 $("<div></div>").draggable().draggable("destroy").draggable("foo"); 111 ok(true, 'arbitrary method called after destroy'); 112 113 $("<div></div>").draggable().draggable("destroy").data("foo.draggable"); 114 ok(true, 'arbitrary option getter after destroy'); 115 116 $("<div></div>").draggable().draggable("destroy").data("foo.draggable", "bar"); 117 ok(true, 'arbitrary option setter after destroy'); 118 }); 119 120 test("enable", function() { 121 expect(6); 122 el = $("#draggable2").draggable({ disabled: true }); 123 shouldnotmove('.draggable({ disabled: true })'); 124 el.draggable("enable"); 125 shouldmove('.draggable("enable")'); 126 equals(el.data("disabled.draggable"), false, "disabled.draggable getter"); 127 128 el.draggable("destroy"); 129 el.draggable({ disabled: true }); 130 shouldnotmove('.draggable({ disabled: true })'); 131 el.data("disabled.draggable", false); 132 equals(el.data("disabled.draggable"), false, "disabled.draggable setter"); 133 shouldmove('.data("disabled.draggable", false)'); 134 }); 135 136 test("disable", function() { 137 expect(6); 138 el = $("#draggable2").draggable({ disabled: false }); 139 shouldmove('.draggable({ disabled: false })'); 140 el.draggable("disable"); 141 shouldnotmove('.draggable("disable")'); 142 equals(el.data("disabled.draggable"), true, "disabled.draggable getter"); 143 144 el.draggable("destroy"); 145 146 el.draggable({ disabled: false }); 147 shouldmove('.draggable({ disabled: false })'); 148 el.data("disabled.draggable", true); 149 equals(el.data("disabled.draggable"), true, "disabled.draggable setter"); 150 shouldnotmove('.data("disabled.draggable", true)'); 151 }); 152 153 test("element types", function() { 154 var typeNames = ('p,h1,h2,h3,h4,h5,h6,blockquote,ol,ul,dl,div,form' 155 + ',table,fieldset,address,ins,del,em,strong,q,cite,dfn,abbr' 156 + ',acronym,code,samp,kbd,var,img,object,hr' 157 + ',input,button,label,select,iframe').split(','); 158 159 $.each(typeNames, function(i) { 160 var typeName = typeNames[i]; 161 el = $(document.createElement(typeName)).appendTo('body'); 162 (typeName == 'table' && el.append("<tr><td>content</td></tr>")); 163 el.draggable({ cancel: '' }); 164 drag(el, 50, 50); 165 moved(50, 50, "<" + typeName + ">"); 166 el.draggable("destroy"); 167 el.remove(); 168 }); 169 }); 170 171 test("defaults", function() { 172 el = $('<div></div>').draggable(); 173 $.each(defaults, function(key, val) { 174 var actual = el.data(key + ".draggable"), expected = val; 175 same(actual, expected, key); 176 }); 177 el.remove(); 178 }); 179 180 test("No options, relative", function() { 181 el = $("#draggable1").draggable(); 182 drag(el, 50, 50); 183 moved(50, 50); 184 }); 185 186 test("No options, absolute", function() { 187 el = $("#draggable2").draggable(); 188 drag(el, 50, 50); 189 moved(50, 50); 190 }); 191 192 module("draggable: Options"); 193 194 test("{ axis: false }, default", function() { 195 el = $("#draggable2").draggable({ axis: false }); 196 drag(el, 50, 50); 197 moved(50, 50); 198 }); 199 200 test("{ axis: 'x' }", function() { 201 el = $("#draggable2").draggable({ axis: "x" }); 202 drag(el, 50, 50); 203 moved(50, 0); 204 }); 205 206 test("{ axis: 'y' }", function() { 207 el = $("#draggable2").draggable({ axis: "y" }); 208 drag(el, 50, 50); 209 moved(0, 50); 210 }); 211 212 test("{ axis: ? }, unexpected", function() { 213 var unexpected = { 214 "true": true, 215 "{}": {}, 216 "[]": [], 217 "null": null, 218 "undefined": undefined, 219 "function() {}": function() {} 220 }; 221 $.each(unexpected, function(key, val) { 222 el = $("#draggable2").draggable({ axis: val }); 223 drag(el, 50, 50); 224 moved(50, 50, "axis: " + key); 225 el.draggable("destroy"); 226 }) 227 }); 228 229 test("{ cancel: 'span' }", function() { 230 el = $("#draggable2").draggable(); 231 drag("#draggable2 span", 50, 50); 232 moved(50, 50); 233 234 el.draggable("destroy"); 235 236 el = $("#draggable2").draggable({ cancel: 'span' }); 237 drag("#draggable2 span", 50, 50); 238 moved(0, 0); 239 }); 240 241 test("{ cancel: ? }, unexpected", function() { 242 var unexpected = { 243 "true": true, 244 "false": false, 245 "{}": {}, 246 "[]": [], 247 "null": null, 248 "undefined": undefined, 249 "function() {return '';}": function() {return '';}, 250 "function() {return true;}": function() {return true;}, 251 "function() {return false;}": function() {return false;} 252 }; 253 $.each(unexpected, function(key, val) { 254 el = $("#draggable2").draggable({ cancel: val }); 255 drag(el, 50, 50); 256 var expected = [50, 50]; 257 moved(expected[0], expected[1], "cancel: " + key); 258 el.draggable("destroy"); 259 }) 260 }); 261 262 test("{ containment: 'parent' }, relative", function() { 263 el = $("#draggable1").draggable({ containment: 'parent' }); 264 var p = el.parent(), po = p.offset(); 265 drag(el, -100, -100); 266 var expected = { 267 left: po.left + border(p, 'left') + margin(el, 'left'), 268 top: po.top + border(p, 'top') + margin(el, 'top') 269 } 270 same(offsetAfter, expected, 'compare offset to parent'); 271 }); 272 273 test("{ containment: 'parent' }, absolute", function() { 274 el = $("#draggable2").draggable({ containment: 'parent' }); 275 var p = el.parent(), po = p.offset(); 276 drag(el, -100, -100); 277 var expected = { 278 left: po.left + border(p, 'left') + margin(el, 'left'), 279 top: po.top + border(p, 'top') + margin(el, 'top') 280 } 281 same(offsetAfter, expected, 'compare offset to parent'); 282 }); 283 284 test("{ cursor: 'move' }", function() { 285 286 function getCursor() { return $("body").css("cursor"); } 287 288 expect(2); 289 290 var expected = "move", actual, before, after; 291 292 el = $("#draggable2").draggable({ 293 cursor: expected, 294 start: function(event, ui) { 295 actual = getCursor(); 296 } 297 }); 298 299 before = getCursor(); 300 drag("#draggable2", -1, -1); 301 after = getCursor(); 302 303 equals(actual, expected, "start callback: cursor '" + expected + "'"); 304 equals(after, before, "after drag: cursor restored"); 305 306 }); 307 308 test("{ cursorAt: { left: -5, top: -5 } }", function() { 309 310 expect(4); 311 312 var dx = -3, dy = -3; 313 var ox = 5, oy = 5; 314 var cax = -5, cay = -5; 315 316 var actual = null; 317 $("#draggable2").draggable({ 318 cursorAt: { left: cax, top: cay }, 319 drag: function(event, ui) { 320 actual = ui.absolutePosition; 321 } 322 }); 323 var el = $("#draggable2").data("draggable").element; 324 325 var before = el.offset(); 326 var pos = { clientX: before.left + ox, clientY: before.top + oy }; 327 $("#draggable2").simulate("mousedown", pos); 328 pos = { clientX: pos.clientX + dx, clientY: pos.clientY + dy }; 329 $(document).simulate("mousemove", pos); 330 $(document).simulate("mousemove", pos); 331 $("#draggable2").simulate("mouseup", pos); 332 var expected = { 333 left: before.left + ox - cax + dx, 334 top: before.top + oy - cay + dy 335 }; 336 337 equals(actual.left, expected.left, "Absolute: -1px left"); 338 equals(actual.top, expected.top, "Absolute: -1px top"); 339 340 var actual = null; 341 $("#draggable1").draggable({ 342 cursorAt: { left: cax, top: cay }, 343 drag: function(event, ui) { 344 actual = ui.absolutePosition; 345 } 346 }); 347 var el = $("#draggable2").data("draggable").element; 348 349 var before = el.offset(); 350 var pos = { clientX: before.left + ox, clientY: before.top + oy }; 351 $("#draggable2").simulate("mousedown", pos); 352 pos = { clientX: pos.clientX + dx, clientY: pos.clientY + dy }; 353 $(document).simulate("mousemove", pos); 354 $(document).simulate("mousemove", pos); 355 $("#draggable2").simulate("mouseup", pos); 356 var expected = { 357 left: before.left + ox - cax + dx, 358 top: before.top + oy - cay + dy 359 }; 360 361 equals(actual.left, expected.left, "Relative: -1px left"); 362 equals(actual.top, expected.top, "Relative: -1px top"); 363 364 }); 365 366 test("{ distance: 10 }", function() { 367 368 el = $("#draggable2").draggable({ distance: 10 }); 369 drag(el, -9, -9); 370 moved(0, 0, 'distance not met'); 371 372 drag(el, -10, -10); 373 moved(-10, -10, 'distance met'); 374 375 drag(el, 9, 9); 376 moved(0, 0, 'distance not met'); 377 378 }); 379 380 test("{ grid: [50, 50] }, relative", function() { 381 el = $("#draggable1").draggable({ grid: [50, 50] }); 382 drag(el, 24, 24); 383 moved(0, 0); 384 drag(el, 26, 25); 385 moved(50, 50); 386 }); 387 388 test("{ grid: [50, 50] }, absolute", function() { 389 el = $("#draggable2").draggable({ grid: [50, 50] }); 390 drag(el, 24, 24); 391 moved(0, 0); 392 drag(el, 26, 25); 393 moved(50, 50); 394 }); 395 396 test("{ handle: 'span' }", function() { 397 el = $("#draggable2").draggable({ handle: 'span' }); 398 399 drag("#draggable2 span", 50, 50); 400 moved(50, 50, "drag span"); 401 402 drag("#draggable2", 50, 50); 403 moved(0, 0, "drag element"); 404 }); 405 406 test("{ helper: 'clone' }, relative", function() { 407 el = $("#draggable1").draggable({ helper: "clone" }); 408 drag(el, 50, 50); 409 moved(0, 0); 410 }); 411 412 test("{ helper: 'clone' }, absolute", function() { 413 el = $("#draggable2").draggable({ helper: "clone" }); 414 drag(el, 50, 50); 415 moved(0, 0); 416 }); 417 418 test("{ opacity: 0.5 }", function() { 419 420 expect(1); 421 422 var opacity = null; 423 el = $("#draggable2").draggable({ 424 opacity: 0.5, 425 start: function(event, ui) { 426 opacity = $(this).css("opacity"); 427 } 428 }); 429 430 drag("#draggable2", -1, -1); 431 432 equals(opacity, 0.5, "start callback: opacity is"); 433 434 }); 435 436 test("{ zIndex: 10 }", function() { 437 438 expect(1); 439 440 var expected = 10, actual; 441 442 var zIndex = null; 443 el = $("#draggable2").draggable({ 444 zIndex: expected, 445 start: function(event, ui) { 446 actual = $(this).css("zIndex"); 447 } 448 }); 449 450 drag("#draggable2", -1, -1); 451 452 equals(actual, expected, "start callback: zIndex is"); 453 454 }); 455 456 module("draggable: Callbacks"); 457 458 test("callbacks occurance count", function() { 459 460 expect(3); 461 462 var start = 0, stop = 0, dragc = 0; 463 el = $("#draggable2").draggable({ 464 start: function() { start++; }, 465 drag: function() { dragc++; }, 466 stop: function() { stop++; } 467 }); 468 469 drag(el, 10, 10); 470 471 equals(start, 1, "start callback should happen exactly once"); 472 equals(dragc, 3, "drag callback should happen exactly once per mousemove"); 473 equals(stop, 1, "stop callback should happen exactly once"); 474 475 }); 476 477 module("draggable: Scroll offsets"); 478 479 480 function testScroll(position) { 481 $("#main").css('position', position); 482 drag(el, 50, 50); 483 moved(50, 50, position+' parent'); 484 485 } 486 487 function setScroll(what) { 488 if(what) { 489 $(document).scrollTop(100); $(document).scrollLeft(100); 490 } else { 491 $("#main")[0].scrollTop = 100; $("#main")[0].scrollLeft = 100; 492 } 493 } 494 495 function restoreScroll(what) { 496 if(what) { 497 $(document).scrollTop(0); $(document).scrollLeft(0); 498 } else { 499 $("#main")[0].scrollTop = 0; $("#main")[0].scrollLeft = 0; 500 } 501 } 502 503 test("{ helper: 'original' }, relative, with scroll offset on parent", function() { 504 505 el = $("#draggable1").draggable({ helper: "original" }); 506 507 setScroll(); 508 testScroll('relative'); 509 510 setScroll(); 511 testScroll('static'); 512 513 setScroll(); 514 testScroll('absolute'); 515 516 restoreScroll(); 517 518 }); 519 520 test("{ helper: 'original' }, relative, with scroll offset on root", function() { 521 522 el = $("#draggable1").draggable({ helper: "original" }); 523 524 setScroll('root'); 525 testScroll('relative'); 526 527 setScroll('root'); 528 testScroll('static'); 529 530 setScroll('root'); 531 testScroll('absolute'); 532 533 restoreScroll('root'); 534 535 }); 536 537 test("{ helper: 'original' }, relative, with scroll offset on root and parent", function() { 538 539 el = $("#draggable1").draggable({ helper: "original" }); 540 541 setScroll(); 542 setScroll('root'); 543 testScroll('relative'); 544 545 setScroll(); 546 setScroll('root'); 547 testScroll('static'); 548 549 setScroll(); 550 setScroll('root'); 551 testScroll('absolute'); 552 553 restoreScroll(); 554 restoreScroll('root'); 555 556 }); 557 558 test("{ helper: 'original' }, absolute, with scroll offset on parent", function() { 559 560 el = $("#draggable1").css({ position: 'absolute', top: 0, left: 0 }).draggable({ helper: "original" }); 561 562 setScroll(); 563 testScroll('relative'); 564 565 setScroll(); 566 testScroll('static'); 567 568 setScroll(); 569 testScroll('absolute'); 570 571 restoreScroll(); 572 573 }); 574 575 test("{ helper: 'original' }, absolute, with scroll offset on root", function() { 576 577 el = $("#draggable1").css({ position: 'absolute', top: 0, left: 0 }).draggable({ helper: "original" }); 578 579 setScroll('root'); 580 testScroll('relative'); 581 582 setScroll('root'); 583 testScroll('static'); 584 585 setScroll('root'); 586 testScroll('absolute'); 587 588 restoreScroll('root'); 589 590 }); 591 592 test("{ helper: 'original' }, absolute, with scroll offset on root and parent", function() { 593 594 el = $("#draggable1").css({ position: 'absolute', top: 0, left: 0 }).draggable({ helper: "original" }); 595 596 setScroll(); 597 setScroll('root'); 598 testScroll('relative'); 599 600 setScroll(); 601 setScroll('root'); 602 testScroll('static'); 603 604 setScroll(); 605 setScroll('root'); 606 testScroll('absolute'); 607 608 restoreScroll(); 609 restoreScroll('root'); 610 611 }); 612 613 //Fixed not for IE < 7 614 if(!($.browser.msie && $.browser.version < 7)) { 615 616 test("{ helper: 'original' }, fixed, with scroll offset on parent", function() { 617 618 el = $("#draggable1").css({ position: 'fixed', top: 0, left: 0 }).draggable({ helper: "original" }); 619 620 setScroll(); 621 testScroll('relative'); 622 623 setScroll(); 624 testScroll('static'); 625 626 setScroll(); 627 testScroll('absolute'); 628 629 restoreScroll(); 630 631 }); 632 633 test("{ helper: 'original' }, fixed, with scroll offset on root", function() { 634 635 el = $("#draggable1").css({ position: 'fixed', top: 0, left: 0 }).draggable({ helper: "original" }); 636 637 setScroll('root'); 638 testScroll('relative'); 639 640 setScroll('root'); 641 testScroll('static'); 642 643 setScroll('root'); 644 testScroll('absolute'); 645 646 restoreScroll('root'); 647 648 }); 649 650 test("{ helper: 'original' }, fixed, with scroll offset on root and parent", function() { 651 652 el = $("#draggable1").css({ position: 'fixed', top: 0, left: 0 }).draggable({ helper: "original" }); 653 654 setScroll(); 655 setScroll('root'); 656 testScroll('relative'); 657 658 setScroll(); 659 setScroll('root'); 660 testScroll('static'); 661 662 setScroll(); 663 setScroll('root'); 664 testScroll('absolute'); 665 666 restoreScroll(); 667 restoreScroll('root'); 668 669 }); 670 671 } 672 673 674 675 test("{ helper: 'clone' }, absolute", function() { 676 677 var helperOffset = null; 678 var origOffset = $("#draggable1").offset(); 679 680 el = $("#draggable1").draggable({ helper: "clone", drag: function(event, ui) { 681 helperOffset = ui.helper.offset(); 682 } }); 683 684 drag(el, 1, 1); 685 same({ top: helperOffset.top-1, left: helperOffset.left-1 }, origOffset, 'dragged[' + dragged.dx + ', ' + dragged.dy + '] '); 686 687 }); 688 689 test("{ helper: 'clone' }, absolute with scroll offset on parent", function() { 690 691 setScroll(); 692 var helperOffset = null; 693 var origOffset = null; 694 695 el = $("#draggable1").draggable({ helper: "clone", drag: function(event, ui) { 696 helperOffset = ui.helper.offset(); 697 } }); 698 699 $("#main").css('position', 'relative'); 700 origOffset = $("#draggable1").offset(); 701 drag(el, 1, 1); 702 same({ top: helperOffset.top-1, left: helperOffset.left-1 }, origOffset, 'dragged[' + dragged.dx + ', ' + dragged.dy + '] '); 703 704 $("#main").css('position', 'static'); 705 origOffset = $("#draggable1").offset(); 706 drag(el, 1, 1); 707 same({ top: helperOffset.top-1, left: helperOffset.left-1 }, origOffset, 'dragged[' + dragged.dx + ', ' + dragged.dy + '] '); 708 709 $("#main").css('position', 'absolute'); 710 origOffset = $("#draggable1").offset(); 711 drag(el, 1, 1); 712 same({ top: helperOffset.top-1, left: helperOffset.left-1 }, origOffset, 'dragged[' + dragged.dx + ', ' + dragged.dy + '] '); 713 714 restoreScroll(); 715 716 }); 717 718 test("{ helper: 'clone' }, absolute with scroll offset on root", function() { 719 720 setScroll('root'); 721 var helperOffset = null; 722 var origOffset = null; 723 724 el = $("#draggable1").draggable({ helper: "clone", drag: function(event, ui) { 725 helperOffset = ui.helper.offset(); 726 } }); 727 728 $("#main").css('position', 'relative'); 729 origOffset = $("#draggable1").offset(); 730 drag(el, 1, 1); 731 same({ top: helperOffset.top-1, left: helperOffset.left-1 }, origOffset, 'dragged[' + dragged.dx + ', ' + dragged.dy + '] '); 732 733 $("#main").css('position', 'static'); 734 origOffset = $("#draggable1").offset(); 735 drag(el, 1, 1); 736 same({ top: helperOffset.top-1, left: helperOffset.left-1 }, origOffset, 'dragged[' + dragged.dx + ', ' + dragged.dy + '] '); 737 738 $("#main").css('position', 'absolute'); 739 origOffset = $("#draggable1").offset(); 740 drag(el, 1, 1); 741 same({ top: helperOffset.top-1, left: helperOffset.left-1 }, origOffset, 'dragged[' + dragged.dx + ', ' + dragged.dy + '] '); 742 743 restoreScroll('root'); 744 745 }); 746 747 test("{ helper: 'clone' }, absolute with scroll offset on root and parent", function() { 748 749 setScroll('root'); 750 setScroll(); 751 var helperOffset = null; 752 var origOffset = null; 753 754 el = $("#draggable1").draggable({ helper: "clone", drag: function(event, ui) { 755 helperOffset = ui.helper.offset(); 756 } }); 757 758 $("#main").css('position', 'relative'); 759 origOffset = $("#draggable1").offset() 760 drag(el, 1, 1); 761 same({ top: helperOffset.top-1, left: helperOffset.left-1 }, origOffset, 'dragged[' + dragged.dx + ', ' + dragged.dy + '] '); 762 763 $("#main").css('position', 'static'); 764 origOffset = $("#draggable1").offset() 765 drag(el, 1, 1); 766 same({ top: helperOffset.top-1, left: helperOffset.left-1 }, origOffset, 'dragged[' + dragged.dx + ', ' + dragged.dy + '] '); 767 768 $("#main").css('position', 'absolute'); 769 origOffset = $("#draggable1").offset() 770 drag(el, 1, 1); 771 same({ top: helperOffset.top-1, left: helperOffset.left-1 }, origOffset, 'dragged[' + dragged.dx + ', ' + dragged.dy + '] '); 772 773 restoreScroll('root'); 774 restoreScroll(); 775 776 }); 777 778 module("draggable: behaviour"); 779 780 test("Events should not be executed on the element if drag is initiated", function() { 781 //TODO: Implement missing test 782 }); 783 784 785 module("draggable: Tickets"); 786 787 })(jQuery);
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |