comparison media/js/tiny_mce/tiny_mce_src.js @ 247:6ed2932901fa

Update tinymce to 3.3.9
author Brian Neal <bgneal@gmail.com>
date Sat, 18 Sep 2010 19:54:11 +0000
parents 237710206167
children
comparison
equal deleted inserted replaced
246:e4dc0b649fcb 247:6ed2932901fa
3 undefined; 3 undefined;
4 4
5 var tinymce = { 5 var tinymce = {
6 majorVersion : '3', 6 majorVersion : '3',
7 7
8 minorVersion : '3.6', 8 minorVersion : '3.9',
9 9
10 releaseDate : '2010-05-20', 10 releaseDate : '2010-09-08',
11 11
12 _init : function() { 12 _init : function() {
13 var t = this, d = document, na = navigator, ua = na.userAgent, i, nl, n, base, p, v; 13 var t = this, d = document, na = navigator, ua = na.userAgent, i, nl, n, base, p, v;
14 14
15 t.isOpera = win.opera && opera.buildNumber; 15 t.isOpera = win.opera && opera.buildNumber;
50 base = v ? v.match(/.*\//)[0] : ''; // Get only directory 50 base = v ? v.match(/.*\//)[0] : ''; // Get only directory
51 } 51 }
52 } 52 }
53 53
54 function getBase(n) { 54 function getBase(n) {
55 if (n.src && /tiny_mce(|_gzip|_jquery|_prototype)(_dev|_src)?.js/.test(n.src)) { 55 if (n.src && /tiny_mce(|_gzip|_jquery|_prototype|_full)(_dev|_src)?.js/.test(n.src)) {
56 if (/_(src|dev)\.js/g.test(n.src)) 56 if (/_(src|dev)\.js/g.test(n.src))
57 t.suffix = '_src'; 57 t.suffix = '_src';
58 58
59 if ((p = n.src.indexOf('?')) != -1) 59 if ((p = n.src.indexOf('?')) != -1)
60 t.query = n.src.substring(p + 1); 60 t.query = n.src.substring(p + 1);
1576 if (isIE && !t.stdMode) { 1576 if (isIE && !t.stdMode) {
1577 n = n.getBoundingClientRect(); 1577 n = n.getBoundingClientRect();
1578 e = t.boxModel ? d.documentElement : d.body; 1578 e = t.boxModel ? d.documentElement : d.body;
1579 x = t.getStyle(t.select('html')[0], 'borderWidth'); // Remove border 1579 x = t.getStyle(t.select('html')[0], 'borderWidth'); // Remove border
1580 x = (x == 'medium' || t.boxModel && !t.isIE6) && 2 || x; 1580 x = (x == 'medium' || t.boxModel && !t.isIE6) && 2 || x;
1581 n.top += t.win.self != t.win.top ? 2 : 0; // IE adds some strange extra cord if used in a frameset
1582 1581
1583 return {x : n.left + e.scrollLeft - x, y : n.top + e.scrollTop - x}; 1582 return {x : n.left + e.scrollLeft - x, y : n.top + e.scrollTop - x};
1584 } 1583 }
1585 1584
1586 r = n; 1585 r = n;
3287 checkRng.collapse(start); 3286 checkRng.collapse(start);
3288 3287
3289 // Create marker and insert it at the end of the endpoints parent 3288 // Create marker and insert it at the end of the endpoints parent
3290 marker = dom.create('a'); 3289 marker = dom.create('a');
3291 parent = checkRng.parentElement(); 3290 parent = checkRng.parentElement();
3291
3292 // If parent doesn't have any children then set the container to that parent and the index to 0
3293 if (!parent.hasChildNodes()) {
3294 domRange[start ? 'setStart' : 'setEnd'](parent, 0);
3295 return;
3296 }
3297
3292 parent.appendChild(marker); 3298 parent.appendChild(marker);
3293 checkRng.moveToElementText(marker); 3299 checkRng.moveToElementText(marker);
3294 position = ieRange.compareEndPoints(start ? 'StartToStart' : 'EndToEnd', checkRng); 3300 position = ieRange.compareEndPoints(start ? 'StartToStart' : 'EndToEnd', checkRng);
3295 if (position > 0) { 3301 if (position > 0) {
3296 // The position is after the end of the parent element. 3302 // The position is after the end of the parent element.
3363 3369
3364 return domRange; 3370 return domRange;
3365 }; 3371 };
3366 3372
3367 this.addRange = function(rng) { 3373 this.addRange = function(rng) {
3368 var ieRng, ieRng2, doc = selection.dom.doc, body = doc.body, startPos, endPos, sc, so, ec, eo, marker, lastIndex, skipStart, skipEnd; 3374 var ieRng, ctrlRng, startContainer, startOffset, endContainer, endOffset, doc = selection.dom.doc, body = doc.body;
3369 3375
3376 function setEndPoint(start) {
3377 var container, offset, marker, tmpRng, nodes;
3378
3379 marker = dom.create('a');
3380 container = start ? startContainer : endContainer;
3381 offset = start ? startOffset : endOffset;
3382 tmpRng = ieRng.duplicate();
3383
3384 if (container == doc) {
3385 container = body;
3386 offset = 0;
3387 }
3388
3389 if (container.nodeType == 3) {
3390 container.parentNode.insertBefore(marker, container);
3391 tmpRng.moveToElementText(marker);
3392 tmpRng.moveStart('character', offset);
3393 dom.remove(marker);
3394 ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng);
3395 } else {
3396 nodes = container.childNodes;
3397
3398 if (nodes.length) {
3399 if (offset >= nodes.length) {
3400 dom.insertAfter(marker, nodes[nodes.length - 1]);
3401 } else {
3402 container.insertBefore(marker, nodes[offset]);
3403 }
3404
3405 tmpRng.moveToElementText(marker);
3406 } else {
3407 // Empty node selection for example <div>|</div>
3408 marker = doc.createTextNode(invisibleChar);
3409 container.appendChild(marker);
3410 tmpRng.moveToElementText(marker.parentNode);
3411 tmpRng.collapse(TRUE);
3412 }
3413
3414 ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng);
3415 dom.remove(marker);
3416 }
3417 }
3418
3419 // Destroy cached range
3370 this.destroy(); 3420 this.destroy();
3371 3421
3372 // Setup some shorter versions 3422 // Setup some shorter versions
3373 sc = rng.startContainer; 3423 startContainer = rng.startContainer;
3374 so = rng.startOffset; 3424 startOffset = rng.startOffset;
3375 ec = rng.endContainer; 3425 endContainer = rng.endContainer;
3376 eo = rng.endOffset; 3426 endOffset = rng.endOffset;
3377 ieRng = body.createTextRange(); 3427 ieRng = body.createTextRange();
3378 3428
3379 // If document selection move caret to first node in document 3429 // If single element selection then try making a control selection out of it
3380 if (sc == doc || ec == doc) { 3430 if (startContainer == endContainer && startContainer.nodeType == 1 && startOffset == endOffset - 1) {
3381 ieRng = body.createTextRange(); 3431 if (startOffset == endOffset - 1) {
3382 ieRng.collapse(); 3432 try {
3383 ieRng.select(); 3433 ctrlRng = body.createControlRange();
3384 return; 3434 ctrlRng.addElement(startContainer.childNodes[startOffset]);
3385 } 3435 ctrlRng.select();
3386 3436 ctrlRng.scrollIntoView();
3387 // If child index resolve it 3437 return;
3388 if (sc.nodeType == 1 && sc.hasChildNodes()) { 3438 } catch (ex) {
3389 lastIndex = sc.childNodes.length - 1; 3439 // Ignore
3390
3391 // Index is higher that the child count then we need to jump over the start container
3392 if (so > lastIndex) {
3393 skipStart = 1;
3394 sc = sc.childNodes[lastIndex];
3395 } else
3396 sc = sc.childNodes[so];
3397
3398 // Child was text node then move offset to start of it
3399 if (sc.nodeType == 3)
3400 so = 0;
3401 }
3402
3403 // If child index resolve it
3404 if (ec.nodeType == 1 && ec.hasChildNodes()) {
3405 lastIndex = ec.childNodes.length - 1;
3406
3407 if (eo == 0) {
3408 skipEnd = 1;
3409 ec = ec.childNodes[0];
3410 } else {
3411 ec = ec.childNodes[Math.min(lastIndex, eo - 1)];
3412
3413 // Child was text node then move offset to end of text node
3414 if (ec.nodeType == 3)
3415 eo = ec.nodeValue.length;
3416 }
3417 }
3418
3419 // Single element selection
3420 if (sc == ec && sc.nodeType == 1) {
3421 // Make control selection for some elements
3422 if (/^(IMG|TABLE)$/.test(sc.nodeName) && so != eo) {
3423 ieRng = body.createControlRange();
3424 ieRng.addElement(sc);
3425 } else {
3426 ieRng = body.createTextRange();
3427
3428 // Padd empty elements with invisible character
3429 if (!sc.hasChildNodes() && sc.canHaveHTML)
3430 sc.innerHTML = invisibleChar;
3431
3432 // Select element contents
3433 ieRng.moveToElementText(sc);
3434
3435 // If it's only containing a padding remove it so the caret remains
3436 if (sc.innerHTML == invisibleChar) {
3437 ieRng.collapse(TRUE);
3438 sc.removeChild(sc.firstChild);
3439 } 3440 }
3440 } 3441 }
3441 3442 }
3442 if (so == eo) 3443
3443 ieRng.collapse(eo <= rng.endContainer.childNodes.length - 1); 3444 // Set start/end point of selection
3444 3445 setEndPoint(true);
3445 ieRng.select(); 3446 setEndPoint();
3446 ieRng.scrollIntoView(); 3447
3447 return; 3448 // Select the new range and scroll it into view
3448 }
3449
3450 // Create range and marker
3451 ieRng = body.createTextRange();
3452 marker = doc.createElement('span');
3453 marker.innerHTML = ' ';
3454
3455 // Set start of range to startContainer/startOffset
3456 if (sc.nodeType == 3) {
3457 // Insert marker after/before startContainer
3458 if (skipStart)
3459 dom.insertAfter(marker, sc);
3460 else
3461 sc.parentNode.insertBefore(marker, sc);
3462
3463 // Select marker the caret to offset position
3464 ieRng.moveToElementText(marker);
3465 marker.parentNode.removeChild(marker);
3466 ieRng.move('character', so);
3467 } else {
3468 ieRng.moveToElementText(sc);
3469
3470 if (skipStart)
3471 ieRng.collapse(FALSE);
3472 }
3473
3474 // If same text container then we can do a more simple move
3475 if (sc == ec && sc.nodeType == 3) {
3476 try {
3477 ieRng.moveEnd('character', eo - so);
3478 ieRng.select();
3479 ieRng.scrollIntoView();
3480 } catch (ex) {
3481 // Some times a Runtime error of the 800a025e type gets thrown
3482 // especially when the caret is placed before a table.
3483 // This is a somewhat strange location for the caret.
3484 // TODO: Find a better solution for this would possible require a rewrite of the setRng method
3485 }
3486
3487 return;
3488 }
3489
3490 // Set end of range to endContainer/endOffset
3491 ieRng2 = body.createTextRange();
3492 if (ec.nodeType == 3) {
3493 // Insert marker after/before startContainer
3494 ec.parentNode.insertBefore(marker, ec);
3495
3496 // Move selection to end marker and move caret to end offset
3497 ieRng2.moveToElementText(marker);
3498 marker.parentNode.removeChild(marker);
3499 ieRng2.move('character', eo);
3500 ieRng.setEndPoint('EndToStart', ieRng2);
3501 } else {
3502 ieRng2.moveToElementText(ec);
3503 ieRng2.collapse(!!skipEnd);
3504 ieRng.setEndPoint('EndToEnd', ieRng2);
3505 }
3506
3507 ieRng.select(); 3449 ieRng.select();
3508 ieRng.scrollIntoView(); 3450 ieRng.scrollIntoView();
3509 }; 3451 };
3510 3452
3511 this.getRangeAt = function() { 3453 this.getRangeAt = function() {
3621 * Released under the MIT, BSD, and GPL Licenses. 3563 * Released under the MIT, BSD, and GPL Licenses.
3622 * More information: http://sizzlejs.com/ 3564 * More information: http://sizzlejs.com/
3623 */ 3565 */
3624 (function(){ 3566 (function(){
3625 3567
3626 var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g, 3568 var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
3627 done = 0, 3569 done = 0,
3628 toString = Object.prototype.toString, 3570 toString = Object.prototype.toString,
3629 hasDuplicate = false; 3571 hasDuplicate = false,
3572 baseHasDuplicate = true;
3573
3574 // Here we check if the JavaScript engine is using some sort of
3575 // optimization where it does not always call our comparision
3576 // function. If that is the case, discard the hasDuplicate value.
3577 // Thus far that includes Google Chrome.
3578 [0, 0].sort(function(){
3579 baseHasDuplicate = false;
3580 return 0;
3581 });
3630 3582
3631 var Sizzle = function(selector, context, results, seed) { 3583 var Sizzle = function(selector, context, results, seed) {
3632 results = results || []; 3584 results = results || [];
3633 var origContext = context = context || document; 3585 context = context || document;
3586
3587 var origContext = context;
3634 3588
3635 if ( context.nodeType !== 1 && context.nodeType !== 9 ) { 3589 if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
3636 return []; 3590 return [];
3637 } 3591 }
3638 3592
3639 if ( !selector || typeof selector !== "string" ) { 3593 if ( !selector || typeof selector !== "string" ) {
3640 return results; 3594 return results;
3641 } 3595 }
3642 3596
3643 var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context); 3597 var parts = [], m, set, checkSet, extra, prune = true, contextXML = Sizzle.isXML(context),
3598 soFar = selector, ret, cur, pop, i;
3644 3599
3645 // Reset the position of the chunker regexp (start from head) 3600 // Reset the position of the chunker regexp (start from head)
3646 chunker.lastIndex = 0; 3601 do {
3647 3602 chunker.exec("");
3648 while ( (m = chunker.exec(selector)) !== null ) { 3603 m = chunker.exec(soFar);
3649 parts.push( m[1] ); 3604
3605 if ( m ) {
3606 soFar = m[3];
3650 3607
3651 if ( m[2] ) { 3608 parts.push( m[1] );
3652 extra = RegExp.rightContext; 3609
3653 break; 3610 if ( m[2] ) {
3611 extra = m[3];
3612 break;
3613 }
3654 } 3614 }
3655 } 3615 } while ( m );
3656 3616
3657 if ( parts.length > 1 && origPOS.exec( selector ) ) { 3617 if ( parts.length > 1 && origPOS.exec( selector ) ) {
3658 if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { 3618 if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
3659 set = posProcess( parts[0] + parts[1], context ); 3619 set = posProcess( parts[0] + parts[1], context );
3660 } else { 3620 } else {
3663 Sizzle( parts.shift(), context ); 3623 Sizzle( parts.shift(), context );
3664 3624
3665 while ( parts.length ) { 3625 while ( parts.length ) {
3666 selector = parts.shift(); 3626 selector = parts.shift();
3667 3627
3668 if ( Expr.relative[ selector ] ) 3628 if ( Expr.relative[ selector ] ) {
3669 selector += parts.shift(); 3629 selector += parts.shift();
3670 3630 }
3631
3671 set = posProcess( selector, set ); 3632 set = posProcess( selector, set );
3672 } 3633 }
3673 } 3634 }
3674 } else { 3635 } else {
3675 // Take a shortcut and set the context if the root selector is an ID 3636 // Take a shortcut and set the context if the root selector is an ID
3676 // (but not if it'll be faster if the inner selector is an ID) 3637 // (but not if it'll be faster if the inner selector is an ID)
3677 if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && 3638 if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
3678 Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { 3639 Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
3679 var ret = Sizzle.find( parts.shift(), context, contextXML ); 3640 ret = Sizzle.find( parts.shift(), context, contextXML );
3680 context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; 3641 context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
3681 } 3642 }
3682 3643
3683 if ( context ) { 3644 if ( context ) {
3684 var ret = seed ? 3645 ret = seed ?
3685 { expr: parts.pop(), set: makeArray(seed) } : 3646 { expr: parts.pop(), set: makeArray(seed) } :
3686 Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); 3647 Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
3687 set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; 3648 set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
3688 3649
3689 if ( parts.length > 0 ) { 3650 if ( parts.length > 0 ) {
3691 } else { 3652 } else {
3692 prune = false; 3653 prune = false;
3693 } 3654 }
3694 3655
3695 while ( parts.length ) { 3656 while ( parts.length ) {
3696 var cur = parts.pop(), pop = cur; 3657 cur = parts.pop();
3658 pop = cur;
3697 3659
3698 if ( !Expr.relative[ cur ] ) { 3660 if ( !Expr.relative[ cur ] ) {
3699 cur = ""; 3661 cur = "";
3700 } else { 3662 } else {
3701 pop = parts.pop(); 3663 pop = parts.pop();
3715 if ( !checkSet ) { 3677 if ( !checkSet ) {
3716 checkSet = set; 3678 checkSet = set;
3717 } 3679 }
3718 3680
3719 if ( !checkSet ) { 3681 if ( !checkSet ) {
3720 throw "Syntax error, unrecognized expression: " + (cur || selector); 3682 Sizzle.error( cur || selector );
3721 } 3683 }
3722 3684
3723 if ( toString.call(checkSet) === "[object Array]" ) { 3685 if ( toString.call(checkSet) === "[object Array]" ) {
3724 if ( !prune ) { 3686 if ( !prune ) {
3725 results.push.apply( results, checkSet ); 3687 results.push.apply( results, checkSet );
3726 } else if ( context && context.nodeType === 1 ) { 3688 } else if ( context && context.nodeType === 1 ) {
3727 for ( var i = 0; checkSet[i] != null; i++ ) { 3689 for ( i = 0; checkSet[i] != null; i++ ) {
3728 if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { 3690 if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
3729 results.push( set[i] ); 3691 results.push( set[i] );
3730 } 3692 }
3731 } 3693 }
3732 } else { 3694 } else {
3733 for ( var i = 0; checkSet[i] != null; i++ ) { 3695 for ( i = 0; checkSet[i] != null; i++ ) {
3734 if ( checkSet[i] && checkSet[i].nodeType === 1 ) { 3696 if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
3735 results.push( set[i] ); 3697 results.push( set[i] );
3736 } 3698 }
3737 } 3699 }
3738 } 3700 }
3748 return results; 3710 return results;
3749 }; 3711 };
3750 3712
3751 Sizzle.uniqueSort = function(results){ 3713 Sizzle.uniqueSort = function(results){
3752 if ( sortOrder ) { 3714 if ( sortOrder ) {
3753 hasDuplicate = false; 3715 hasDuplicate = baseHasDuplicate;
3754 results.sort(sortOrder); 3716 results.sort(sortOrder);
3755 3717
3756 if ( hasDuplicate ) { 3718 if ( hasDuplicate ) {
3757 for ( var i = 1; i < results.length; i++ ) { 3719 for ( var i = 1; i < results.length; i++ ) {
3758 if ( results[i] === results[i-1] ) { 3720 if ( results[i] === results[i-1] ) {
3759 results.splice(i--, 1); 3721 results.splice(i--, 1);
3760 } 3722 }
3761 } 3723 }
3762 } 3724 }
3763 } 3725 }
3726
3727 return results;
3764 }; 3728 };
3765 3729
3766 Sizzle.matches = function(expr, set){ 3730 Sizzle.matches = function(expr, set){
3767 return Sizzle(expr, null, null, set); 3731 return Sizzle(expr, null, null, set);
3768 }; 3732 };
3769 3733
3770 Sizzle.find = function(expr, context, isXML){ 3734 Sizzle.find = function(expr, context, isXML){
3771 var set, match; 3735 var set;
3772 3736
3773 if ( !expr ) { 3737 if ( !expr ) {
3774 return []; 3738 return [];
3775 } 3739 }
3776 3740
3777 for ( var i = 0, l = Expr.order.length; i < l; i++ ) { 3741 for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
3778 var type = Expr.order[i], match; 3742 var type = Expr.order[i], match;
3779 3743
3780 if ( (match = Expr.match[ type ].exec( expr )) ) { 3744 if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
3781 var left = RegExp.leftContext; 3745 var left = match[1];
3746 match.splice(1,1);
3782 3747
3783 if ( left.substr( left.length - 1 ) !== "\\" ) { 3748 if ( left.substr( left.length - 1 ) !== "\\" ) {
3784 match[1] = (match[1] || "").replace(/\\/g, ""); 3749 match[1] = (match[1] || "").replace(/\\/g, "");
3785 set = Expr.find[ type ]( match, context, isXML ); 3750 set = Expr.find[ type ]( match, context, isXML );
3786 if ( set != null ) { 3751 if ( set != null ) {
3798 return {set: set, expr: expr}; 3763 return {set: set, expr: expr};
3799 }; 3764 };
3800 3765
3801 Sizzle.filter = function(expr, set, inplace, not){ 3766 Sizzle.filter = function(expr, set, inplace, not){
3802 var old = expr, result = [], curLoop = set, match, anyFound, 3767 var old = expr, result = [], curLoop = set, match, anyFound,
3803 isXMLFilter = set && set[0] && isXML(set[0]); 3768 isXMLFilter = set && set[0] && Sizzle.isXML(set[0]);
3804 3769
3805 while ( expr && set.length ) { 3770 while ( expr && set.length ) {
3806 for ( var type in Expr.filter ) { 3771 for ( var type in Expr.filter ) {
3807 if ( (match = Expr.match[ type ].exec( expr )) != null ) { 3772 if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
3808 var filter = Expr.filter[ type ], found, item; 3773 var filter = Expr.filter[ type ], found, item, left = match[1];
3809 anyFound = false; 3774 anyFound = false;
3810 3775
3811 if ( curLoop == result ) { 3776 match.splice(1,1);
3777
3778 if ( left.substr( left.length - 1 ) === "\\" ) {
3779 continue;
3780 }
3781
3782 if ( curLoop === result ) {
3812 result = []; 3783 result = [];
3813 } 3784 }
3814 3785
3815 if ( Expr.preFilter[ type ] ) { 3786 if ( Expr.preFilter[ type ] ) {
3816 match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); 3787 match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
3857 } 3828 }
3858 } 3829 }
3859 } 3830 }
3860 3831
3861 // Improper expression 3832 // Improper expression
3862 if ( expr == old ) { 3833 if ( expr === old ) {
3863 if ( anyFound == null ) { 3834 if ( anyFound == null ) {
3864 throw "Syntax error, unrecognized expression: " + expr; 3835 Sizzle.error( expr );
3865 } else { 3836 } else {
3866 break; 3837 break;
3867 } 3838 }
3868 } 3839 }
3869 3840
3870 old = expr; 3841 old = expr;
3871 } 3842 }
3872 3843
3873 return curLoop; 3844 return curLoop;
3845 };
3846
3847 Sizzle.error = function( msg ) {
3848 throw "Syntax error, unrecognized expression: " + msg;
3874 }; 3849 };
3875 3850
3876 var Expr = Sizzle.selectors = { 3851 var Expr = Sizzle.selectors = {
3877 order: [ "ID", "NAME", "TAG" ], 3852 order: [ "ID", "NAME", "TAG" ],
3878 match: { 3853 match: {
3879 ID: /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/, 3854 ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
3880 CLASS: /\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/, 3855 CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
3881 NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/, 3856 NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
3882 ATTR: /\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, 3857 ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
3883 TAG: /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/, 3858 TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
3884 CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, 3859 CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,
3885 POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, 3860 POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
3886 PSEUDO: /:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ 3861 PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
3887 }, 3862 },
3863 leftMatch: {},
3888 attrMap: { 3864 attrMap: {
3889 "class": "className", 3865 "class": "className",
3890 "for": "htmlFor" 3866 "for": "htmlFor"
3891 }, 3867 },
3892 attrHandle: { 3868 attrHandle: {
3893 href: function(elem){ 3869 href: function(elem){
3894 return elem.getAttribute("href"); 3870 return elem.getAttribute("href");
3895 } 3871 }
3896 }, 3872 },
3897 relative: { 3873 relative: {
3898 "+": function(checkSet, part, isXML){ 3874 "+": function(checkSet, part){
3899 var isPartStr = typeof part === "string", 3875 var isPartStr = typeof part === "string",
3900 isTag = isPartStr && !/\W/.test(part), 3876 isTag = isPartStr && !/\W/.test(part),
3901 isPartStrNotTag = isPartStr && !isTag; 3877 isPartStrNotTag = isPartStr && !isTag;
3902 3878
3903 if ( isTag && !isXML ) { 3879 if ( isTag ) {
3904 part = part.toUpperCase(); 3880 part = part.toLowerCase();
3905 } 3881 }
3906 3882
3907 for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { 3883 for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
3908 if ( (elem = checkSet[i]) ) { 3884 if ( (elem = checkSet[i]) ) {
3909 while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} 3885 while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
3910 3886
3911 checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? 3887 checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
3912 elem || false : 3888 elem || false :
3913 elem === part; 3889 elem === part;
3914 } 3890 }
3915 } 3891 }
3916 3892
3917 if ( isPartStrNotTag ) { 3893 if ( isPartStrNotTag ) {
3918 Sizzle.filter( part, checkSet, true ); 3894 Sizzle.filter( part, checkSet, true );
3919 } 3895 }
3920 }, 3896 },
3921 ">": function(checkSet, part, isXML){ 3897 ">": function(checkSet, part){
3922 var isPartStr = typeof part === "string"; 3898 var isPartStr = typeof part === "string",
3899 elem, i = 0, l = checkSet.length;
3923 3900
3924 if ( isPartStr && !/\W/.test(part) ) { 3901 if ( isPartStr && !/\W/.test(part) ) {
3925 part = isXML ? part : part.toUpperCase(); 3902 part = part.toLowerCase();
3926 3903
3927 for ( var i = 0, l = checkSet.length; i < l; i++ ) { 3904 for ( ; i < l; i++ ) {
3928 var elem = checkSet[i]; 3905 elem = checkSet[i];
3929 if ( elem ) { 3906 if ( elem ) {
3930 var parent = elem.parentNode; 3907 var parent = elem.parentNode;
3931 checkSet[i] = parent.nodeName === part ? parent : false; 3908 checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
3932 } 3909 }
3933 } 3910 }
3934 } else { 3911 } else {
3935 for ( var i = 0, l = checkSet.length; i < l; i++ ) { 3912 for ( ; i < l; i++ ) {
3936 var elem = checkSet[i]; 3913 elem = checkSet[i];
3937 if ( elem ) { 3914 if ( elem ) {
3938 checkSet[i] = isPartStr ? 3915 checkSet[i] = isPartStr ?
3939 elem.parentNode : 3916 elem.parentNode :
3940 elem.parentNode === part; 3917 elem.parentNode === part;
3941 } 3918 }
3945 Sizzle.filter( part, checkSet, true ); 3922 Sizzle.filter( part, checkSet, true );
3946 } 3923 }
3947 } 3924 }
3948 }, 3925 },
3949 "": function(checkSet, part, isXML){ 3926 "": function(checkSet, part, isXML){
3950 var doneName = done++, checkFn = dirCheck; 3927 var doneName = done++, checkFn = dirCheck, nodeCheck;
3951 3928
3952 if ( !part.match(/\W/) ) { 3929 if ( typeof part === "string" && !/\W/.test(part) ) {
3953 var nodeCheck = part = isXML ? part : part.toUpperCase(); 3930 part = part.toLowerCase();
3931 nodeCheck = part;
3954 checkFn = dirNodeCheck; 3932 checkFn = dirNodeCheck;
3955 } 3933 }
3956 3934
3957 checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); 3935 checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
3958 }, 3936 },
3959 "~": function(checkSet, part, isXML){ 3937 "~": function(checkSet, part, isXML){
3960 var doneName = done++, checkFn = dirCheck; 3938 var doneName = done++, checkFn = dirCheck, nodeCheck;
3961 3939
3962 if ( typeof part === "string" && !part.match(/\W/) ) { 3940 if ( typeof part === "string" && !/\W/.test(part) ) {
3963 var nodeCheck = part = isXML ? part : part.toUpperCase(); 3941 part = part.toLowerCase();
3942 nodeCheck = part;
3964 checkFn = dirNodeCheck; 3943 checkFn = dirNodeCheck;
3965 } 3944 }
3966 3945
3967 checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); 3946 checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
3968 } 3947 }
3972 if ( typeof context.getElementById !== "undefined" && !isXML ) { 3951 if ( typeof context.getElementById !== "undefined" && !isXML ) {
3973 var m = context.getElementById(match[1]); 3952 var m = context.getElementById(match[1]);
3974 return m ? [m] : []; 3953 return m ? [m] : [];
3975 } 3954 }
3976 }, 3955 },
3977 NAME: function(match, context, isXML){ 3956 NAME: function(match, context){
3978 if ( typeof context.getElementsByName !== "undefined" ) { 3957 if ( typeof context.getElementsByName !== "undefined" ) {
3979 var ret = [], results = context.getElementsByName(match[1]); 3958 var ret = [], results = context.getElementsByName(match[1]);
3980 3959
3981 for ( var i = 0, l = results.length; i < l; i++ ) { 3960 for ( var i = 0, l = results.length; i < l; i++ ) {
3982 if ( results[i].getAttribute("name") === match[1] ) { 3961 if ( results[i].getAttribute("name") === match[1] ) {
3999 return match; 3978 return match;
4000 } 3979 }
4001 3980
4002 for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { 3981 for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
4003 if ( elem ) { 3982 if ( elem ) {
4004 if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { 3983 if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) {
4005 if ( !inplace ) 3984 if ( !inplace ) {
4006 result.push( elem ); 3985 result.push( elem );
3986 }
4007 } else if ( inplace ) { 3987 } else if ( inplace ) {
4008 curLoop[i] = false; 3988 curLoop[i] = false;
4009 } 3989 }
4010 } 3990 }
4011 } 3991 }
4014 }, 3994 },
4015 ID: function(match){ 3995 ID: function(match){
4016 return match[1].replace(/\\/g, ""); 3996 return match[1].replace(/\\/g, "");
4017 }, 3997 },
4018 TAG: function(match, curLoop){ 3998 TAG: function(match, curLoop){
4019 for ( var i = 0; curLoop[i] === false; i++ ){} 3999 return match[1].toLowerCase();
4020 return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
4021 }, 4000 },
4022 CHILD: function(match){ 4001 CHILD: function(match){
4023 if ( match[1] == "nth" ) { 4002 if ( match[1] === "nth" ) {
4024 // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' 4003 // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
4025 var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( 4004 var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
4026 match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || 4005 match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
4027 !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); 4006 !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
4028 4007
4029 // calculate the numbers (first)n+(last) including if they are negative 4008 // calculate the numbers (first)n+(last) including if they are negative
4030 match[2] = (test[1] + (test[2] || 1)) - 0; 4009 match[2] = (test[1] + (test[2] || 1)) - 0;
4031 match[3] = test[3] - 0; 4010 match[3] = test[3] - 0;
4050 return match; 4029 return match;
4051 }, 4030 },
4052 PSEUDO: function(match, curLoop, inplace, result, not){ 4031 PSEUDO: function(match, curLoop, inplace, result, not){
4053 if ( match[1] === "not" ) { 4032 if ( match[1] === "not" ) {
4054 // If we're dealing with a complex expression, or a simple one 4033 // If we're dealing with a complex expression, or a simple one
4055 if ( match[3].match(chunker).length > 1 || /^\w/.test(match[3]) ) { 4034 if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
4056 match[3] = Sizzle(match[3], null, null, curLoop); 4035 match[3] = Sizzle(match[3], null, null, curLoop);
4057 } else { 4036 } else {
4058 var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); 4037 var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
4059 if ( !inplace ) { 4038 if ( !inplace ) {
4060 result.push.apply( result, ret ); 4039 result.push.apply( result, ret );
4096 }, 4075 },
4097 has: function(elem, i, match){ 4076 has: function(elem, i, match){
4098 return !!Sizzle( match[3], elem ).length; 4077 return !!Sizzle( match[3], elem ).length;
4099 }, 4078 },
4100 header: function(elem){ 4079 header: function(elem){
4101 return /h\d/i.test( elem.nodeName ); 4080 return (/h\d/i).test( elem.nodeName );
4102 }, 4081 },
4103 text: function(elem){ 4082 text: function(elem){
4104 return "text" === elem.type; 4083 return "text" === elem.type;
4105 }, 4084 },
4106 radio: function(elem){ 4085 radio: function(elem){
4123 }, 4102 },
4124 reset: function(elem){ 4103 reset: function(elem){
4125 return "reset" === elem.type; 4104 return "reset" === elem.type;
4126 }, 4105 },
4127 button: function(elem){ 4106 button: function(elem){
4128 return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; 4107 return "button" === elem.type || elem.nodeName.toLowerCase() === "button";
4129 }, 4108 },
4130 input: function(elem){ 4109 input: function(elem){
4131 return /input|select|textarea|button/i.test(elem.nodeName); 4110 return (/input|select|textarea|button/i).test(elem.nodeName);
4132 } 4111 }
4133 }, 4112 },
4134 setFilters: { 4113 setFilters: {
4135 first: function(elem, i){ 4114 first: function(elem, i){
4136 return i === 0; 4115 return i === 0;
4149 }, 4128 },
4150 gt: function(elem, i, match){ 4129 gt: function(elem, i, match){
4151 return i > match[3] - 0; 4130 return i > match[3] - 0;
4152 }, 4131 },
4153 nth: function(elem, i, match){ 4132 nth: function(elem, i, match){
4154 return match[3] - 0 == i; 4133 return match[3] - 0 === i;
4155 }, 4134 },
4156 eq: function(elem, i, match){ 4135 eq: function(elem, i, match){
4157 return match[3] - 0 == i; 4136 return match[3] - 0 === i;
4158 } 4137 }
4159 }, 4138 },
4160 filter: { 4139 filter: {
4161 PSEUDO: function(elem, match, i, array){ 4140 PSEUDO: function(elem, match, i, array){
4162 var name = match[1], filter = Expr.filters[ name ]; 4141 var name = match[1], filter = Expr.filters[ name ];
4163 4142
4164 if ( filter ) { 4143 if ( filter ) {
4165 return filter( elem, i, match, array ); 4144 return filter( elem, i, match, array );
4166 } else if ( name === "contains" ) { 4145 } else if ( name === "contains" ) {
4167 return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; 4146 return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0;
4168 } else if ( name === "not" ) { 4147 } else if ( name === "not" ) {
4169 var not = match[3]; 4148 var not = match[3];
4170 4149
4171 for ( var i = 0, l = not.length; i < l; i++ ) { 4150 for ( var j = 0, l = not.length; j < l; j++ ) {
4172 if ( not[i] === elem ) { 4151 if ( not[j] === elem ) {
4173 return false; 4152 return false;
4174 } 4153 }
4175 } 4154 }
4176 4155
4177 return true; 4156 return true;
4157 } else {
4158 Sizzle.error( "Syntax error, unrecognized expression: " + name );
4178 } 4159 }
4179 }, 4160 },
4180 CHILD: function(elem, match){ 4161 CHILD: function(elem, match){
4181 var type = match[1], node = elem; 4162 var type = match[1], node = elem;
4182 switch (type) { 4163 switch (type) {
4183 case 'only': 4164 case 'only':
4184 case 'first': 4165 case 'first':
4185 while (node = node.previousSibling) { 4166 while ( (node = node.previousSibling) ) {
4186 if ( node.nodeType === 1 ) return false; 4167 if ( node.nodeType === 1 ) {
4168 return false;
4169 }
4187 } 4170 }
4188 if ( type == 'first') return true; 4171 if ( type === "first" ) {
4172 return true;
4173 }
4189 node = elem; 4174 node = elem;
4190 case 'last': 4175 case 'last':
4191 while (node = node.nextSibling) { 4176 while ( (node = node.nextSibling) ) {
4192 if ( node.nodeType === 1 ) return false; 4177 if ( node.nodeType === 1 ) {
4178 return false;
4179 }
4193 } 4180 }
4194 return true; 4181 return true;
4195 case 'nth': 4182 case 'nth':
4196 var first = match[2], last = match[3]; 4183 var first = match[2], last = match[3];
4197 4184
4198 if ( first == 1 && last == 0 ) { 4185 if ( first === 1 && last === 0 ) {
4199 return true; 4186 return true;
4200 } 4187 }
4201 4188
4202 var doneName = match[0], 4189 var doneName = match[0],
4203 parent = elem.parentNode; 4190 parent = elem.parentNode;
4211 } 4198 }
4212 parent.sizcache = doneName; 4199 parent.sizcache = doneName;
4213 } 4200 }
4214 4201
4215 var diff = elem.nodeIndex - last; 4202 var diff = elem.nodeIndex - last;
4216 if ( first == 0 ) { 4203 if ( first === 0 ) {
4217 return diff == 0; 4204 return diff === 0;
4218 } else { 4205 } else {
4219 return ( diff % first == 0 && diff / first >= 0 ); 4206 return ( diff % first === 0 && diff / first >= 0 );
4220 } 4207 }
4221 } 4208 }
4222 }, 4209 },
4223 ID: function(elem, match){ 4210 ID: function(elem, match){
4224 return elem.nodeType === 1 && elem.getAttribute("id") === match; 4211 return elem.nodeType === 1 && elem.getAttribute("id") === match;
4225 }, 4212 },
4226 TAG: function(elem, match){ 4213 TAG: function(elem, match){
4227 return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; 4214 return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
4228 }, 4215 },
4229 CLASS: function(elem, match){ 4216 CLASS: function(elem, match){
4230 return (" " + (elem.className || elem.getAttribute("class")) + " ") 4217 return (" " + (elem.className || elem.getAttribute("class")) + " ")
4231 .indexOf( match ) > -1; 4218 .indexOf( match ) > -1;
4232 }, 4219 },
4250 type === "~=" ? 4237 type === "~=" ?
4251 (" " + value + " ").indexOf(check) >= 0 : 4238 (" " + value + " ").indexOf(check) >= 0 :
4252 !check ? 4239 !check ?
4253 value && result !== false : 4240 value && result !== false :
4254 type === "!=" ? 4241 type === "!=" ?
4255 value != check : 4242 value !== check :
4256 type === "^=" ? 4243 type === "^=" ?
4257 value.indexOf(check) === 0 : 4244 value.indexOf(check) === 0 :
4258 type === "$=" ? 4245 type === "$=" ?
4259 value.substr(value.length - check.length) === check : 4246 value.substr(value.length - check.length) === check :
4260 type === "|=" ? 4247 type === "|=" ?
4269 } 4256 }
4270 } 4257 }
4271 } 4258 }
4272 }; 4259 };
4273 4260
4274 var origPOS = Expr.match.POS; 4261 var origPOS = Expr.match.POS,
4262 fescape = function(all, num){
4263 return "\\" + (num - 0 + 1);
4264 };
4275 4265
4276 for ( var type in Expr.match ) { 4266 for ( var type in Expr.match ) {
4277 Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); 4267 Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
4268 Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
4278 } 4269 }
4279 4270
4280 var makeArray = function(array, results) { 4271 var makeArray = function(array, results) {
4281 array = Array.prototype.slice.call( array ); 4272 array = Array.prototype.slice.call( array, 0 );
4282 4273
4283 if ( results ) { 4274 if ( results ) {
4284 results.push.apply( results, array ); 4275 results.push.apply( results, array );
4285 return results; 4276 return results;
4286 } 4277 }
4288 return array; 4279 return array;
4289 }; 4280 };
4290 4281
4291 // Perform a simple check to determine if the browser is capable of 4282 // Perform a simple check to determine if the browser is capable of
4292 // converting a NodeList to an array using builtin methods. 4283 // converting a NodeList to an array using builtin methods.
4284 // Also verifies that the returned array holds DOM nodes
4285 // (which is not the case in the Blackberry browser)
4293 try { 4286 try {
4294 Array.prototype.slice.call( document.documentElement.childNodes ); 4287 Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
4295 4288
4296 // Provide a fallback method if it does not work 4289 // Provide a fallback method if it does not work
4297 } catch(e){ 4290 } catch(e){
4298 makeArray = function(array, results) { 4291 makeArray = function(array, results) {
4299 var ret = results || []; 4292 var ret = results || [], i = 0;
4300 4293
4301 if ( toString.call(array) === "[object Array]" ) { 4294 if ( toString.call(array) === "[object Array]" ) {
4302 Array.prototype.push.apply( ret, array ); 4295 Array.prototype.push.apply( ret, array );
4303 } else { 4296 } else {
4304 if ( typeof array.length === "number" ) { 4297 if ( typeof array.length === "number" ) {
4305 for ( var i = 0, l = array.length; i < l; i++ ) { 4298 for ( var l = array.length; i < l; i++ ) {
4306 ret.push( array[i] ); 4299 ret.push( array[i] );
4307 } 4300 }
4308 } else { 4301 } else {
4309 for ( var i = 0; array[i]; i++ ) { 4302 for ( ; array[i]; i++ ) {
4310 ret.push( array[i] ); 4303 ret.push( array[i] );
4311 } 4304 }
4312 } 4305 }
4313 } 4306 }
4314 4307
4318 4311
4319 var sortOrder; 4312 var sortOrder;
4320 4313
4321 if ( document.documentElement.compareDocumentPosition ) { 4314 if ( document.documentElement.compareDocumentPosition ) {
4322 sortOrder = function( a, b ) { 4315 sortOrder = function( a, b ) {
4316 if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
4317 if ( a == b ) {
4318 hasDuplicate = true;
4319 }
4320 return a.compareDocumentPosition ? -1 : 1;
4321 }
4322
4323 var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; 4323 var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
4324 if ( ret === 0 ) { 4324 if ( ret === 0 ) {
4325 hasDuplicate = true; 4325 hasDuplicate = true;
4326 } 4326 }
4327 return ret; 4327 return ret;
4328 }; 4328 };
4329 } else if ( "sourceIndex" in document.documentElement ) { 4329 } else if ( "sourceIndex" in document.documentElement ) {
4330 sortOrder = function( a, b ) { 4330 sortOrder = function( a, b ) {
4331 if ( !a.sourceIndex || !b.sourceIndex ) {
4332 if ( a == b ) {
4333 hasDuplicate = true;
4334 }
4335 return a.sourceIndex ? -1 : 1;
4336 }
4337
4331 var ret = a.sourceIndex - b.sourceIndex; 4338 var ret = a.sourceIndex - b.sourceIndex;
4332 if ( ret === 0 ) { 4339 if ( ret === 0 ) {
4333 hasDuplicate = true; 4340 hasDuplicate = true;
4334 } 4341 }
4335 return ret; 4342 return ret;
4336 }; 4343 };
4337 } else if ( document.createRange ) { 4344 } else if ( document.createRange ) {
4338 sortOrder = function( a, b ) { 4345 sortOrder = function( a, b ) {
4346 if ( !a.ownerDocument || !b.ownerDocument ) {
4347 if ( a == b ) {
4348 hasDuplicate = true;
4349 }
4350 return a.ownerDocument ? -1 : 1;
4351 }
4352
4339 var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); 4353 var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
4340 aRange.setStart(a, 0); 4354 aRange.setStart(a, 0);
4341 aRange.setEnd(a, 0); 4355 aRange.setEnd(a, 0);
4342 bRange.setStart(b, 0); 4356 bRange.setStart(b, 0);
4343 bRange.setEnd(b, 0); 4357 bRange.setEnd(b, 0);
4347 } 4361 }
4348 return ret; 4362 return ret;
4349 }; 4363 };
4350 } 4364 }
4351 4365
4366 // Utility function for retreiving the text value of an array of DOM nodes
4367 Sizzle.getText = function( elems ) {
4368 var ret = "", elem;
4369
4370 for ( var i = 0; elems[i]; i++ ) {
4371 elem = elems[i];
4372
4373 // Get the text from text nodes and CDATA nodes
4374 if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
4375 ret += elem.nodeValue;
4376
4377 // Traverse everything else, except comment nodes
4378 } else if ( elem.nodeType !== 8 ) {
4379 ret += Sizzle.getText( elem.childNodes );
4380 }
4381 }
4382
4383 return ret;
4384 };
4385
4352 // Check to see if the browser returns elements by name when 4386 // Check to see if the browser returns elements by name when
4353 // querying by getElementById (and provide a workaround) 4387 // querying by getElementById (and provide a workaround)
4354 (function(){ 4388 (function(){
4355 // We're going to inject a fake input element with a specified name 4389 // We're going to inject a fake input element with a specified name
4356 var form = document.createElement("div"), 4390 var form = document.createElement("div"),
4357 id = "script" + (new Date).getTime(); 4391 id = "script" + (new Date()).getTime();
4358 form.innerHTML = "<a name='" + id + "'/>"; 4392 form.innerHTML = "<a name='" + id + "'/>";
4359 4393
4360 // Inject it into the root element, check its status, and remove it quickly 4394 // Inject it into the root element, check its status, and remove it quickly
4361 var root = document.documentElement; 4395 var root = document.documentElement;
4362 root.insertBefore( form, root.firstChild ); 4396 root.insertBefore( form, root.firstChild );
4363 4397
4364 // The workaround has to do additional checks after a getElementById 4398 // The workaround has to do additional checks after a getElementById
4365 // Which slows things down for other browsers (hence the branching) 4399 // Which slows things down for other browsers (hence the branching)
4366 if ( !!document.getElementById( id ) ) { 4400 if ( document.getElementById( id ) ) {
4367 Expr.find.ID = function(match, context, isXML){ 4401 Expr.find.ID = function(match, context, isXML){
4368 if ( typeof context.getElementById !== "undefined" && !isXML ) { 4402 if ( typeof context.getElementById !== "undefined" && !isXML ) {
4369 var m = context.getElementById(match[1]); 4403 var m = context.getElementById(match[1]);
4370 return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; 4404 return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
4371 } 4405 }
4376 return elem.nodeType === 1 && node && node.nodeValue === match; 4410 return elem.nodeType === 1 && node && node.nodeValue === match;
4377 }; 4411 };
4378 } 4412 }
4379 4413
4380 root.removeChild( form ); 4414 root.removeChild( form );
4415 root = form = null; // release memory in IE
4381 })(); 4416 })();
4382 4417
4383 (function(){ 4418 (function(){
4384 // Check to see if the browser returns only elements 4419 // Check to see if the browser returns only elements
4385 // when doing getElementsByTagName("*") 4420 // when doing getElementsByTagName("*")
4416 div.firstChild.getAttribute("href") !== "#" ) { 4451 div.firstChild.getAttribute("href") !== "#" ) {
4417 Expr.attrHandle.href = function(elem){ 4452 Expr.attrHandle.href = function(elem){
4418 return elem.getAttribute("href", 2); 4453 return elem.getAttribute("href", 2);
4419 }; 4454 };
4420 } 4455 }
4456
4457 div = null; // release memory in IE
4421 })(); 4458 })();
4422 4459
4423 if ( document.querySelectorAll ) (function(){ 4460 if ( document.querySelectorAll ) {
4424 var oldSizzle = Sizzle, div = document.createElement("div"); 4461 (function(){
4425 div.innerHTML = "<p class='TEST'></p>"; 4462 var oldSizzle = Sizzle, div = document.createElement("div");
4426 4463 div.innerHTML = "<p class='TEST'></p>";
4427 // Safari can't handle uppercase or unicode characters when 4464
4428 // in quirks mode. 4465 // Safari can't handle uppercase or unicode characters when
4429 if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { 4466 // in quirks mode.
4467 if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
4468 return;
4469 }
4470
4471 Sizzle = function(query, context, extra, seed){
4472 context = context || document;
4473
4474 // Only use querySelectorAll on non-XML documents
4475 // (ID selectors don't work in non-HTML documents)
4476 if ( !seed && context.nodeType === 9 && !Sizzle.isXML(context) ) {
4477 try {
4478 return makeArray( context.querySelectorAll(query), extra );
4479 } catch(e){}
4480 }
4481
4482 return oldSizzle(query, context, extra, seed);
4483 };
4484
4485 for ( var prop in oldSizzle ) {
4486 Sizzle[ prop ] = oldSizzle[ prop ];
4487 }
4488
4489 div = null; // release memory in IE
4490 })();
4491 }
4492
4493 (function(){
4494 var div = document.createElement("div");
4495
4496 div.innerHTML = "<div class='test e'></div><div class='test'></div>";
4497
4498 // Opera can't find a second classname (in 9.6)
4499 // Also, make sure that getElementsByClassName actually exists
4500 if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
4501 return;
4502 }
4503
4504 // Safari caches class attributes, doesn't catch changes (in 3.2)
4505 div.lastChild.className = "e";
4506
4507 if ( div.getElementsByClassName("e").length === 1 ) {
4430 return; 4508 return;
4431 } 4509 }
4432 4510
4433 Sizzle = function(query, context, extra, seed){
4434 context = context || document;
4435
4436 // Only use querySelectorAll on non-XML documents
4437 // (ID selectors don't work in non-HTML documents)
4438 if ( !seed && context.nodeType === 9 && !isXML(context) ) {
4439 try {
4440 return makeArray( context.querySelectorAll(query), extra );
4441 } catch(e){}
4442 }
4443
4444 return oldSizzle(query, context, extra, seed);
4445 };
4446
4447 for ( var prop in oldSizzle ) {
4448 Sizzle[ prop ] = oldSizzle[ prop ];
4449 }
4450 })();
4451
4452 if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
4453 var div = document.createElement("div");
4454 div.innerHTML = "<div class='test e'></div><div class='test'></div>";
4455
4456 // Opera can't find a second classname (in 9.6)
4457 if ( div.getElementsByClassName("e").length === 0 )
4458 return;
4459
4460 // Safari caches class attributes, doesn't catch changes (in 3.2)
4461 div.lastChild.className = "e";
4462
4463 if ( div.getElementsByClassName("e").length === 1 )
4464 return;
4465
4466 Expr.order.splice(1, 0, "CLASS"); 4511 Expr.order.splice(1, 0, "CLASS");
4467 Expr.find.CLASS = function(match, context, isXML) { 4512 Expr.find.CLASS = function(match, context, isXML) {
4468 if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { 4513 if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
4469 return context.getElementsByClassName(match[1]); 4514 return context.getElementsByClassName(match[1]);
4470 } 4515 }
4471 }; 4516 };
4517
4518 div = null; // release memory in IE
4472 })(); 4519 })();
4473 4520
4474 function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { 4521 function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
4475 var sibDir = dir == "previousSibling" && !isXML;
4476 for ( var i = 0, l = checkSet.length; i < l; i++ ) { 4522 for ( var i = 0, l = checkSet.length; i < l; i++ ) {
4477 var elem = checkSet[i]; 4523 var elem = checkSet[i];
4478 if ( elem ) { 4524 if ( elem ) {
4479 if ( sibDir && elem.nodeType === 1 ){
4480 elem.sizcache = doneName;
4481 elem.sizset = i;
4482 }
4483 elem = elem[dir]; 4525 elem = elem[dir];
4484 var match = false; 4526 var match = false;
4485 4527
4486 while ( elem ) { 4528 while ( elem ) {
4487 if ( elem.sizcache === doneName ) { 4529 if ( elem.sizcache === doneName ) {
4492 if ( elem.nodeType === 1 && !isXML ){ 4534 if ( elem.nodeType === 1 && !isXML ){
4493 elem.sizcache = doneName; 4535 elem.sizcache = doneName;
4494 elem.sizset = i; 4536 elem.sizset = i;
4495 } 4537 }
4496 4538
4497 if ( elem.nodeName === cur ) { 4539 if ( elem.nodeName.toLowerCase() === cur ) {
4498 match = elem; 4540 match = elem;
4499 break; 4541 break;
4500 } 4542 }
4501 4543
4502 elem = elem[dir]; 4544 elem = elem[dir];
4506 } 4548 }
4507 } 4549 }
4508 } 4550 }
4509 4551
4510 function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { 4552 function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
4511 var sibDir = dir == "previousSibling" && !isXML;
4512 for ( var i = 0, l = checkSet.length; i < l; i++ ) { 4553 for ( var i = 0, l = checkSet.length; i < l; i++ ) {
4513 var elem = checkSet[i]; 4554 var elem = checkSet[i];
4514 if ( elem ) { 4555 if ( elem ) {
4515 if ( sibDir && elem.nodeType === 1 ) {
4516 elem.sizcache = doneName;
4517 elem.sizset = i;
4518 }
4519 elem = elem[dir]; 4556 elem = elem[dir];
4520 var match = false; 4557 var match = false;
4521 4558
4522 while ( elem ) { 4559 while ( elem ) {
4523 if ( elem.sizcache === doneName ) { 4560 if ( elem.sizcache === doneName ) {
4548 checkSet[i] = match; 4585 checkSet[i] = match;
4549 } 4586 }
4550 } 4587 }
4551 } 4588 }
4552 4589
4553 var contains = document.compareDocumentPosition ? function(a, b){ 4590 Sizzle.contains = document.compareDocumentPosition ? function(a, b){
4554 return a.compareDocumentPosition(b) & 16; 4591 return !!(a.compareDocumentPosition(b) & 16);
4555 } : function(a, b){ 4592 } : function(a, b){
4556 return a !== b && (a.contains ? a.contains(b) : true); 4593 return a !== b && (a.contains ? a.contains(b) : true);
4557 }; 4594 };
4558 4595
4559 var isXML = function(elem){ 4596 Sizzle.isXML = function(elem){
4560 return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || 4597 // documentElement is verified for cases where it doesn't yet exist
4561 !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; 4598 // (such as loading iframes in IE - #4833)
4599 var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
4600 return documentElement ? documentElement.nodeName !== "HTML" : false;
4562 }; 4601 };
4563 4602
4564 var posProcess = function(selector, context){ 4603 var posProcess = function(selector, context){
4565 var tmpSet = [], later = "", match, 4604 var tmpSet = [], later = "", match,
4566 root = context.nodeType ? [context] : context; 4605 root = context.nodeType ? [context] : context;
5104 // Dispatch set content event 5143 // Dispatch set content event
5105 t.onSetContent.dispatch(t, s); 5144 t.onSetContent.dispatch(t, s);
5106 }, 5145 },
5107 5146
5108 getStart : function() { 5147 getStart : function() {
5109 var t = this, r = t.getRng(), e; 5148 var rng = this.getRng(), startElement, parentElement, checkRng, node;
5110 5149
5111 if (r.duplicate || r.item) { 5150 if (rng.duplicate || rng.item) {
5112 if (r.item) 5151 // Control selection, return first item
5113 return r.item(0); 5152 if (rng.item)
5114 5153 return rng.item(0);
5115 r = r.duplicate(); 5154
5116 r.collapse(1); 5155 // Get start element
5117 e = r.parentElement(); 5156 checkRng = rng.duplicate();
5118 5157 checkRng.collapse(1);
5119 if (e && e.nodeName == 'BODY') 5158 startElement = checkRng.parentElement();
5120 return e.firstChild || e; 5159
5121 5160 // Check if range parent is inside the start element, then return the inner parent element
5122 return e; 5161 // This will fix issues when a single element is selected, IE would otherwise return the wrong start element
5162 parentElement = node = rng.parentElement();
5163 while (node = node.parentNode) {
5164 if (node == startElement) {
5165 startElement = parentElement;
5166 break;
5167 }
5168 }
5169
5170 // If start element is body element try to move to the first child if it exists
5171 if (startElement && startElement.nodeName == 'BODY')
5172 return startElement.firstChild || startElement;
5173
5174 return startElement;
5123 } else { 5175 } else {
5124 e = r.startContainer; 5176 startElement = rng.startContainer;
5125 5177
5126 if (e.nodeType == 1 && e.hasChildNodes()) 5178 if (startElement.nodeType == 1 && startElement.hasChildNodes())
5127 e = e.childNodes[Math.min(e.childNodes.length - 1, r.startOffset)]; 5179 startElement = startElement.childNodes[Math.min(startElement.childNodes.length - 1, rng.startOffset)];
5128 5180
5129 if (e && e.nodeType == 3) 5181 if (startElement && startElement.nodeType == 3)
5130 return e.parentNode; 5182 return startElement.parentNode;
5131 5183
5132 return e; 5184 return startElement;
5133 } 5185 }
5134 }, 5186 },
5135 5187
5136 getEnd : function() { 5188 getEnd : function() {
5137 var t = this, r = t.getRng(), e, eo; 5189 var t = this, r = t.getRng(), e, eo;
5285 if (bookmark.start) { 5337 if (bookmark.start) {
5286 rng = dom.createRng(); 5338 rng = dom.createRng();
5287 root = dom.getRoot(); 5339 root = dom.getRoot();
5288 5340
5289 function setEndPoint(start) { 5341 function setEndPoint(start) {
5290 var point = bookmark[start ? 'start' : 'end'], i, node, offset; 5342 var point = bookmark[start ? 'start' : 'end'], i, node, offset, children;
5291 5343
5292 if (point) { 5344 if (point) {
5293 // Find container node 5345 // Find container node
5294 for (node = root, i = point.length - 1; i >= 1; i--) 5346 for (node = root, i = point.length - 1; i >= 1; i--) {
5295 node = node.childNodes[point[i]]; 5347 children = node.childNodes;
5348
5349 if (children.length)
5350 node = children[point[i]];
5351 }
5296 5352
5297 // Set offset within container node 5353 // Set offset within container node
5298 if (start) 5354 if (start)
5299 rng.setStart(node, point[0]); 5355 rng.setStart(node, point[0]);
5300 else 5356 else
5315 5371
5316 if (suffix == 'start') { 5372 if (suffix == 'start') {
5317 if (!keep) { 5373 if (!keep) {
5318 idx = dom.nodeIndex(marker); 5374 idx = dom.nodeIndex(marker);
5319 } else { 5375 } else {
5320 node = marker; 5376 node = marker.firstChild;
5321 idx = 1; 5377 idx = 1;
5322 } 5378 }
5323 5379
5324 startContainer = endContainer = node; 5380 startContainer = endContainer = node;
5325 startOffset = endOffset = idx; 5381 startOffset = endOffset = idx;
5326 } else { 5382 } else {
5327 if (!keep) { 5383 if (!keep) {
5328 idx = dom.nodeIndex(marker); 5384 idx = dom.nodeIndex(marker);
5329 } else { 5385 } else {
5330 node = marker; 5386 node = marker.firstChild;
5331 idx = 1; 5387 idx = 1;
5332 } 5388 }
5333 5389
5334 endContainer = node; 5390 endContainer = node;
5335 endOffset = idx; 5391 endOffset = idx;
5366 } 5422 }
5367 } 5423 }
5368 } 5424 }
5369 }; 5425 };
5370 5426
5427 function addBogus(node) {
5428 // Adds a bogus BR element for empty block elements
5429 // on non IE browsers just to have a place to put the caret
5430 if (!isIE && dom.isBlock(node) && !node.innerHTML)
5431 node.innerHTML = '<br _mce_bogus="1" />';
5432
5433 return node;
5434 };
5435
5371 // Restore start/end points 5436 // Restore start/end points
5372 restoreEndPoint('start'); 5437 restoreEndPoint('start');
5373 restoreEndPoint('end'); 5438 restoreEndPoint('end');
5374 5439
5375 rng = dom.createRng(); 5440 if (startContainer) {
5376 rng.setStart(startContainer, startOffset); 5441 rng = dom.createRng();
5377 rng.setEnd(endContainer, endOffset); 5442 rng.setStart(addBogus(startContainer), startOffset);
5378 t.setRng(rng); 5443 rng.setEnd(addBogus(endContainer), endOffset);
5444 t.setRng(rng);
5445 }
5379 } else if (bookmark.name) { 5446 } else if (bookmark.name) {
5380 t.select(dom.select(bookmark.name)[bookmark.index]); 5447 t.select(dom.select(bookmark.name)[bookmark.index]);
5381 } else if (bookmark.rng) 5448 } else if (bookmark.rng)
5382 t.setRng(bookmark.rng); 5449 t.setRng(bookmark.rng);
5383 } 5450 }
6339 6406
6340 o.content = h; 6407 o.content = h;
6341 }, 6408 },
6342 6409
6343 _serializeNode : function(n, inner) { 6410 _serializeNode : function(n, inner) {
6344 var t = this, s = t.settings, w = t.writer, hc, el, cn, i, l, a, at, no, v, nn, ru, ar, iv, closed, keep, type; 6411 var t = this, s = t.settings, w = t.writer, hc, el, cn, i, l, a, at, no, v, nn, ru, ar, iv, closed, keep, type, scopeName;
6345 6412
6346 if (!s.node_filter || s.node_filter(n)) { 6413 if (!s.node_filter || s.node_filter(n)) {
6347 switch (n.nodeType) { 6414 switch (n.nodeType) {
6348 case 1: // Element 6415 case 1: // Element
6349 if (n.hasAttribute ? n.hasAttribute('_mce_bogus') : n.getAttribute('_mce_bogus')) 6416 if (n.hasAttribute ? n.hasAttribute('_mce_bogus') : n.getAttribute('_mce_bogus'))
6363 keep = 1; 6430 keep = 1;
6364 } 6431 }
6365 6432
6366 // Add correct prefix on IE 6433 // Add correct prefix on IE
6367 if (isIE) { 6434 if (isIE) {
6368 if (n.scopeName !== 'HTML' && n.scopeName !== 'html') 6435 scopeName = n.scopeName;
6369 nn = n.scopeName + ':' + nn; 6436 if (scopeName && scopeName !== 'HTML' && scopeName !== 'html')
6437 nn = scopeName + ':' + nn;
6370 } 6438 }
6371 6439
6372 // Remove mce prefix on IE needed for the abbr element 6440 // Remove mce prefix on IE needed for the abbr element
6373 if (nn.indexOf('mce:') === 0) 6441 if (nn.indexOf('mce:') === 0)
6374 nn = nn.substring(4); 6442 nn = nn.substring(4);
8087 8155
8088 postRender : function() { 8156 postRender : function() {
8089 var t = this, cp = t.classPrefix; 8157 var t = this, cp = t.classPrefix;
8090 8158
8091 Event.add(t.id, 'click', t.showMenu, t); 8159 Event.add(t.id, 'click', t.showMenu, t);
8092 Event.add(t.id + '_text', 'focus', function(e) { 8160 Event.add(t.id + '_text', 'focus', function() {
8093 if (!t._focused) { 8161 if (!t._focused) {
8094 t.keyDownHandler = Event.add(t.id + '_text', 'keydown', function(e) { 8162 t.keyDownHandler = Event.add(t.id + '_text', 'keydown', function(e) {
8095 var idx = -1, v, kc = e.keyCode; 8163 var idx = -1, v, kc = e.keyCode;
8096 8164
8097 // Find current index 8165 // Find current index
8665 8733
8666 (function(tinymce) { 8734 (function(tinymce) {
8667 var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each; 8735 var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each;
8668 8736
8669 tinymce.create('tinymce.AddOnManager', { 8737 tinymce.create('tinymce.AddOnManager', {
8670 items : [], 8738 AddOnManager : function() {
8671 urls : {}, 8739 var self = this;
8672 lookup : {}, 8740
8673 8741 self.items = [];
8674 onAdd : new Dispatcher(this), 8742 self.urls = {};
8743 self.lookup = {};
8744 self.onAdd = new Dispatcher(self);
8745 },
8675 8746
8676 get : function(n) { 8747 get : function(n) {
8677 return this.lookup[n]; 8748 return this.lookup[n];
8678 }, 8749 },
8679 8750
8700 8771
8701 if (u.indexOf('/') != 0 && u.indexOf('://') == -1) 8772 if (u.indexOf('/') != 0 && u.indexOf('://') == -1)
8702 u = tinymce.baseURL + '/' + u; 8773 u = tinymce.baseURL + '/' + u;
8703 8774
8704 t.urls[n] = u.substring(0, u.lastIndexOf('/')); 8775 t.urls[n] = u.substring(0, u.lastIndexOf('/'));
8705 tinymce.ScriptLoader.add(u, cb, s); 8776
8777 if (!t.lookup[n])
8778 tinymce.ScriptLoader.add(u, cb, s);
8706 } 8779 }
8707 }); 8780 });
8708 8781
8709 // Create plugin and theme managers 8782 // Create plugin and theme managers
8710 tinymce.PluginManager = new tinymce.AddOnManager(); 8783 tinymce.PluginManager = new tinymce.AddOnManager();
10634 }); 10707 });
10635 } 10708 }
10636 10709
10637 // Add node change handlers 10710 // Add node change handlers
10638 t.onMouseUp.add(t.nodeChanged); 10711 t.onMouseUp.add(t.nodeChanged);
10639 t.onClick.add(t.nodeChanged); 10712 //t.onClick.add(t.nodeChanged);
10640 t.onKeyUp.add(function(ed, e) { 10713 t.onKeyUp.add(function(ed, e) {
10641 var c = e.keyCode; 10714 var c = e.keyCode;
10642 10715
10643 if ((c >= 33 && c <= 36) || (c >= 37 && c <= 40) || c == 13 || c == 45 || c == 46 || c == 8 || (tinymce.isMac && (c == 91 || c == 93)) || e.ctrlKey) 10716 if ((c >= 33 && c <= 36) || (c >= 37 && c <= 40) || c == 13 || c == 45 || c == 46 || c == 8 || (tinymce.isMac && (c == 91 || c == 93)) || e.ctrlKey)
10644 t.nodeChanged(); 10717 t.nodeChanged();
10808 if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45 || e.ctrlKey) 10881 if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45 || e.ctrlKey)
10809 addUndo(); 10882 addUndo();
10810 }); 10883 });
10811 10884
10812 t.onKeyDown.add(function(ed, e) { 10885 t.onKeyDown.add(function(ed, e) {
10886 var rng, parent, bookmark;
10887
10888 // IE has a really odd bug where the DOM might include an node that doesn't have
10889 // a proper structure. If you try to access nodeValue it would throw an illegal value exception.
10890 // This seems to only happen when you delete contents and it seems to be avoidable if you refresh the element
10891 // after you delete contents from it. See: #3008923
10892 if (isIE && e.keyCode == 46) {
10893 rng = t.selection.getRng();
10894
10895 if (rng.parentElement) {
10896 parent = rng.parentElement();
10897
10898 // Select next word when ctrl key is used in combo with delete
10899 if (e.ctrlKey) {
10900 rng.moveEnd('word', 1);
10901 rng.select();
10902 }
10903
10904 // Delete contents
10905 t.selection.getSel().clear();
10906
10907 // Check if we are within the same parent
10908 if (rng.parentElement() == parent) {
10909 bookmark = t.selection.getBookmark();
10910
10911 try {
10912 // Update the HTML and hopefully it will remove the artifacts
10913 parent.innerHTML = parent.innerHTML;
10914 } catch (ex) {
10915 // And since it's IE it can sometimes produce an unknown runtime error
10916 }
10917
10918 // Restore the caret position
10919 t.selection.moveToBookmark(bookmark);
10920 }
10921
10922 // Block the default delete behavior since it might be broken
10923 e.preventDefault();
10924 return;
10925 }
10926 }
10927
10813 // Is caracter positon keys 10928 // Is caracter positon keys
10814 if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45) { 10929 if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45) {
10815 if (t.undoManager.typing) 10930 if (t.undoManager.typing)
10816 addUndo(); 10931 addUndo();
10817 10932
11095 mceBlockQuote : function(command) { 11210 mceBlockQuote : function(command) {
11096 toggleFormat('blockquote'); 11211 toggleFormat('blockquote');
11097 }, 11212 },
11098 11213
11099 FormatBlock : function(command, ui, value) { 11214 FormatBlock : function(command, ui, value) {
11100 return toggleFormat(value); 11215 return toggleFormat(value || 'p');
11101 }, 11216 },
11102 11217
11103 mceCleanup : function() { 11218 mceCleanup : function() {
11104 storeSelection(); 11219 var bookmark = selection.getBookmark();
11220
11105 editor.setContent(editor.getContent({cleanup : TRUE}), {cleanup : TRUE}); 11221 editor.setContent(editor.getContent({cleanup : TRUE}), {cleanup : TRUE});
11106 restoreSelection(); 11222
11223 selection.moveToBookmark(bookmark);
11107 }, 11224 },
11108 11225
11109 mceRemoveNode : function(command, ui, value) { 11226 mceRemoveNode : function(command, ui, value) {
11110 var node = value || selection.getNode(); 11227 var node = value || selection.getNode();
11111 11228
11136 selection.setContent(value); 11253 selection.setContent(value);
11137 }, 11254 },
11138 11255
11139 mceInsertRawHTML : function(command, ui, value) { 11256 mceInsertRawHTML : function(command, ui, value) {
11140 selection.setContent('tiny_mce_marker'); 11257 selection.setContent('tiny_mce_marker');
11141 editor.setContent(editor.getContent().replace(/tiny_mce_marker/g, value)); 11258 editor.setContent(editor.getContent().replace(/tiny_mce_marker/g, function() { return value }));
11142 }, 11259 },
11143 11260
11144 mceSetContent : function(command, ui, value) { 11261 mceSetContent : function(command, ui, value) {
11145 editor.setContent(value); 11262 editor.setContent(value);
11146 }, 11263 },
11218 editor.dom.remove(link, TRUE); 11335 editor.dom.remove(link, TRUE);
11219 } 11336 }
11220 }, 11337 },
11221 11338
11222 selectAll : function() { 11339 selectAll : function() {
11223 var root = dom.getRoot(); 11340 var root = dom.getRoot(), rng = dom.createRng();
11224 var rng = dom.createRng(); 11341
11225 rng.setStart(root, 0); 11342 rng.setStart(root, 0);
11226 rng.setEnd(root, root.childNodes.length); 11343 rng.setEnd(root, root.childNodes.length);
11344
11227 editor.selection.setRng(rng); 11345 editor.selection.setRng(rng);
11228 } 11346 }
11229 }); 11347 });
11230 11348
11231 // Add queryCommandState overrides 11349 // Add queryCommandState overrides
11414 each = tinymce.each, 11532 each = tinymce.each,
11415 extend = tinymce.extend, 11533 extend = tinymce.extend,
11416 TRUE = true, 11534 TRUE = true,
11417 FALSE = false; 11535 FALSE = false;
11418 11536
11537 function cloneFormats(node) {
11538 var clone, temp, inner;
11539
11540 do {
11541 if (/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(node.nodeName)) {
11542 if (clone) {
11543 temp = node.cloneNode(false);
11544 temp.appendChild(clone);
11545 clone = temp;
11546 } else {
11547 clone = inner = node.cloneNode(false);
11548 }
11549
11550 clone.removeAttribute('id');
11551 }
11552 } while (node = node.parentNode);
11553
11554 if (clone)
11555 return {wrapper : clone, inner : inner};
11556 };
11557
11419 // Checks if the selection/caret is at the end of the specified block element 11558 // Checks if the selection/caret is at the end of the specified block element
11420 function isAtEnd(rng, par) { 11559 function isAtEnd(rng, par) {
11421 var rng2 = par.ownerDocument.createRange(); 11560 var rng2 = par.ownerDocument.createRange();
11422 11561
11423 rng2.setStart(rng.endContainer, rng.endOffset); 11562 rng2.setStart(rng.endContainer, rng.endOffset);
11522 } 11661 }
11523 }); 11662 });
11524 } 11663 }
11525 } 11664 }
11526 11665
11527 if (!isIE && s.force_p_newlines) { 11666 if (s.force_p_newlines) {
11528 ed.onKeyPress.add(function(ed, e) { 11667 if (!isIE) {
11529 if (e.keyCode == 13 && !e.shiftKey && !t.insertPara(e)) 11668 ed.onKeyPress.add(function(ed, e) {
11530 Event.cancel(e); 11669 if (e.keyCode == 13 && !e.shiftKey && !t.insertPara(e))
11531 }); 11670 Event.cancel(e);
11671 });
11672 } else {
11673 // Ungly hack to for IE to preserve the formatting when you press
11674 // enter at the end of a block element with formatted contents
11675 // This logic overrides the browsers default logic with
11676 // custom logic that enables us to control the output
11677 tinymce.addUnload(function() {
11678 t._previousFormats = 0; // Fix IE leak
11679 });
11680
11681 ed.onKeyPress.add(function(ed, e) {
11682 t._previousFormats = 0;
11683
11684 // Clone the current formats, this will later be applied to the new block contents
11685 if (e.keyCode == 13 && !e.shiftKey && ed.selection.isCollapsed() && s.keep_styles)
11686 t._previousFormats = cloneFormats(ed.selection.getStart());
11687 });
11688
11689 ed.onKeyUp.add(function(ed, e) {
11690 // Let IE break the element and the wrap the new caret location in the previous formats
11691 if (e.keyCode == 13 && !e.shiftKey) {
11692 var parent = ed.selection.getStart(), fmt = t._previousFormats;
11693
11694 // Parent is an empty block
11695 if (!parent.hasChildNodes() && fmt) {
11696 parent = dom.getParent(parent, dom.isBlock);
11697
11698 if (parent && parent.nodeName != 'LI') {
11699 parent.innerHTML = '';
11700
11701 if (t._previousFormats) {
11702 parent.appendChild(fmt.wrapper);
11703 fmt.inner.innerHTML = '\uFEFF';
11704 } else
11705 parent.innerHTML = '\uFEFF';
11706
11707 selection.select(parent, 1);
11708 ed.getDoc().execCommand('Delete', false, null);
11709 t._previousFormats = 0;
11710 }
11711 }
11712 }
11713 });
11714 }
11532 11715
11533 if (isGecko) { 11716 if (isGecko) {
11534 ed.onKeyDown.add(function(ed, e) { 11717 ed.onKeyDown.add(function(ed, e) {
11535 if ((e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey) 11718 if ((e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey)
11536 t.backspaceDelete(e, e.keyCode == 8); 11719 t.backspaceDelete(e, e.keyCode == 8);
12028 12211
12029 return FALSE; 12212 return FALSE;
12030 }, 12213 },
12031 12214
12032 backspaceDelete : function(e, bs) { 12215 backspaceDelete : function(e, bs) {
12033 var t = this, ed = t.editor, b = ed.getBody(), dom = ed.dom, n, se = ed.selection, r = se.getRng(), sc = r.startContainer, n, w, tn; 12216 var t = this, ed = t.editor, b = ed.getBody(), dom = ed.dom, n, se = ed.selection, r = se.getRng(), sc = r.startContainer, n, w, tn, walker;
12217
12218 // Delete when caret is behind a element doesn't work correctly on Gecko see #3011651
12219 if (!bs && r.collapsed && sc.nodeType == 1 && r.startOffset == sc.childNodes.length) {
12220 walker = new tinymce.dom.TreeWalker(sc.lastChild, sc);
12221
12222 // Walk the dom backwards until we find a text node
12223 for (n = sc.lastChild; n; n = walker.prev()) {
12224 if (n.nodeType == 3) {
12225 r.setStart(n, n.nodeValue.length);
12226 r.collapse(true);
12227 se.setRng(r);
12228 return;
12229 }
12230 }
12231 }
12034 12232
12035 // The caret sometimes gets stuck in Gecko if you delete empty paragraphs 12233 // The caret sometimes gets stuck in Gecko if you delete empty paragraphs
12036 // This workaround removes the element by hand and moves the caret to the previous element 12234 // This workaround removes the element by hand and moves the caret to the previous element
12037 if (sc && ed.dom.isBlock(sc) && !/^(TD|TH)$/.test(sc.nodeName) && bs) { 12235 if (sc && ed.dom.isBlock(sc) && !/^(TD|TH)$/.test(sc.nodeName) && bs) {
12038 if (sc.childNodes.length == 0 || (sc.childNodes.length == 1 && sc.firstChild.nodeName == 'BR')) { 12236 if (sc.childNodes.length == 0 || (sc.childNodes.length == 1 && sc.firstChild.nodeName == 'BR')) {
12059 12257
12060 return Event.cancel(e); 12258 return Event.cancel(e);
12061 } 12259 }
12062 } 12260 }
12063 } 12261 }
12064
12065 // Gecko generates BR elements here and there, we don't like those so lets remove them
12066 function handler(e) {
12067 var pr;
12068
12069 e = e.target;
12070
12071 // A new BR was created in a block element, remove it
12072 if (e && e.parentNode && e.nodeName == 'BR' && (n = t.getParentBlock(e))) {
12073 pr = e.previousSibling;
12074
12075 Event.remove(b, 'DOMNodeInserted', handler);
12076
12077 // Is there whitespace at the end of the node before then we might need the pesky BR
12078 // to place the caret at a correct location see bug: #2013943
12079 if (pr && pr.nodeType == 3 && /\s+$/.test(pr.nodeValue))
12080 return;
12081
12082 // Only remove BR elements that got inserted in the middle of the text
12083 if (e.previousSibling || e.nextSibling)
12084 ed.dom.remove(e);
12085 }
12086 };
12087
12088 // Listen for new nodes
12089 Event._add(b, 'DOMNodeInserted', handler);
12090
12091 // Remove listener
12092 window.setTimeout(function() {
12093 Event._remove(b, 'DOMNodeInserted', handler);
12094 }, 1);
12095 } 12262 }
12096 }); 12263 });
12097 })(tinymce); 12264 })(tinymce);
12098 12265
12099 (function(tinymce) { 12266 (function(tinymce) {
12706 walker, node; 12873 walker, node;
12707 12874
12708 // Move startContainer/startOffset in to a suitable node 12875 // Move startContainer/startOffset in to a suitable node
12709 if (container.nodeType == 1 || container.nodeValue === "") { 12876 if (container.nodeType == 1 || container.nodeValue === "") {
12710 container = container.nodeType == 1 ? container.childNodes[offset] : container; 12877 container = container.nodeType == 1 ? container.childNodes[offset] : container;
12711 walker = new TreeWalker(container, container.parentNode); 12878
12712 for (node = walker.current(); node; node = walker.next()) { 12879 // Might fail if the offset is behind the last element in it's container
12713 if (node.nodeType == 3 && !isBlock(node.parentNode) && !isWhiteSpaceNode(node)) { 12880 if (container) {
12714 rng.setStart(node, 0); 12881 walker = new TreeWalker(container, container.parentNode);
12715 break; 12882 for (node = walker.current(); node; node = walker.next()) {
12883 if (node.nodeType == 3 && !isWhiteSpaceNode(node)) {
12884 rng.setStart(node, 0);
12885 break;
12886 }
12716 } 12887 }
12717 } 12888 }
12718 } 12889 }
12719 12890
12720 return rng; 12891 return rng;
12916 rng = dom.createRng(); 13087 rng = dom.createRng();
12917 13088
12918 rng.setStartBefore(node); 13089 rng.setStartBefore(node);
12919 rng.setEndAfter(node); 13090 rng.setEndAfter(node);
12920 13091
12921 applyRngStyle(rng); 13092 applyRngStyle(expandRng(rng, formatList));
12922 } else { 13093 } else {
12923 if (!selection.isCollapsed() || !format.inline) { 13094 if (!selection.isCollapsed() || !format.inline) {
12924 // Apply formatting to selection 13095 // Apply formatting to selection
12925 bookmark = selection.getBookmark(); 13096 bookmark = selection.getBookmark();
12926 applyRngStyle(expandRng(selection.getRng(TRUE), formatList)); 13097 applyRngStyle(expandRng(selection.getRng(TRUE), formatList));
12934 } 13105 }
12935 }; 13106 };
12936 13107
12937 function remove(name, vars, node) { 13108 function remove(name, vars, node) {
12938 var formatList = get(name), format = formatList[0], bookmark, i, rng; 13109 var formatList = get(name), format = formatList[0], bookmark, i, rng;
13110
13111 function moveStart(rng) {
13112 var container = rng.startContainer,
13113 offset = rng.startOffset,
13114 walker, node, nodes, tmpNode;
13115
13116 // Convert text node into index if possible
13117 if (container.nodeType == 3 && offset >= container.nodeValue.length - 1) {
13118 container = container.parentNode;
13119 offset = nodeIndex(container) + 1;
13120 }
13121
13122 // Move startContainer/startOffset in to a suitable node
13123 if (container.nodeType == 1) {
13124 nodes = container.childNodes;
13125 container = nodes[Math.min(offset, nodes.length - 1)];
13126 walker = new TreeWalker(container);
13127
13128 // If offset is at end of the parent node walk to the next one
13129 if (offset > nodes.length - 1)
13130 walker.next();
13131
13132 for (node = walker.current(); node; node = walker.next()) {
13133 if (node.nodeType == 3 && !isWhiteSpaceNode(node)) {
13134 // IE has a "neat" feature where it moves the start node into the closest element
13135 // we can avoid this by inserting an element before it and then remove it after we set the selection
13136 tmpNode = dom.create('a', null, INVISIBLE_CHAR);
13137 node.parentNode.insertBefore(tmpNode, node);
13138
13139 // Set selection and remove tmpNode
13140 rng.setStart(node, 0);
13141 selection.setRng(rng);
13142 dom.remove(tmpNode);
13143
13144 return;
13145 }
13146 }
13147 }
13148 };
12939 13149
12940 // Merges the styles for each node 13150 // Merges the styles for each node
12941 function process(node) { 13151 function process(node) {
12942 var children, i, l; 13152 var children, i, l;
12943 13153
13088 13298
13089 if (!selection.isCollapsed() || !format.inline) { 13299 if (!selection.isCollapsed() || !format.inline) {
13090 bookmark = selection.getBookmark(); 13300 bookmark = selection.getBookmark();
13091 removeRngStyle(selection.getRng(TRUE)); 13301 removeRngStyle(selection.getRng(TRUE));
13092 selection.moveToBookmark(bookmark); 13302 selection.moveToBookmark(bookmark);
13303
13304 // Check if start element still has formatting then we are at: "<b>text|</b>text" and need to move the start into the next text node
13305 if (match(name, vars, selection.getStart())) {
13306 moveStart(selection.getRng(true));
13307 }
13308
13093 ed.nodeChanged(); 13309 ed.nodeChanged();
13094 } else 13310 } else
13095 performCaretAction('remove', name, vars); 13311 performCaretAction('remove', name, vars);
13096 }; 13312 };
13097 13313
13342 13558
13343 return value; 13559 return value;
13344 }; 13560 };
13345 13561
13346 function isWhiteSpaceNode(node) { 13562 function isWhiteSpaceNode(node) {
13347 return node && node.nodeType === 3 && /^\s*$/.test(node.nodeValue); 13563 return node && node.nodeType === 3 && /^([\s\r\n]+|)$/.test(node.nodeValue);
13348 }; 13564 };
13349 13565
13350 function wrap(node, name, attrs) { 13566 function wrap(node, name, attrs) {
13351 var wrapper = dom.create(name, attrs); 13567 var wrapper = dom.create(name, attrs);
13352 13568
13880 14096
13881 // Look for marker 14097 // Look for marker
13882 if (isCaretNode(node)) { 14098 if (isCaretNode(node)) {
13883 textNode = node.firstChild; 14099 textNode = node.firstChild;
13884 14100
13885 perform(node); 14101 if (textNode) {
13886 14102 perform(node);
13887 rng = dom.createRng(); 14103
13888 rng.setStart(textNode, textNode.nodeValue.length); 14104 rng = dom.createRng();
13889 rng.setEnd(textNode, textNode.nodeValue.length); 14105 rng.setStart(textNode, textNode.nodeValue.length);
13890 selection.setRng(rng); 14106 rng.setEnd(textNode, textNode.nodeValue.length);
13891 ed.nodeChanged(); 14107 selection.setRng(rng);
14108 ed.nodeChanged();
14109 } else
14110 dom.remove(node);
13892 } 14111 }
13893 }); 14112 });
13894 14113
13895 // Always unbind and clear pending styles on keyup 14114 // Always unbind and clear pending styles on keyup
13896 if (e.type == 'keyup' || e.type == 'mouseup') 14115 if (e.type == 'keyup' || e.type == 'mouseup')
13909 14128
13910 if (settings.inline_styles) { 14129 if (settings.inline_styles) {
13911 fontSizes = tinymce.explode(settings.font_size_style_values); 14130 fontSizes = tinymce.explode(settings.font_size_style_values);
13912 14131
13913 function replaceWithSpan(node, styles) { 14132 function replaceWithSpan(node, styles) {
13914 dom.replace(dom.create('span', { 14133 tinymce.each(styles, function(value, name) {
13915 style : styles 14134 if (value)
13916 }), node, 1); 14135 dom.setStyle(node, name, value);
14136 });
14137
14138 dom.rename(node, 'span');
13917 }; 14139 };
13918 14140
13919 filters = { 14141 filters = {
13920 font : function(dom, node) { 14142 font : function(dom, node) {
13921 replaceWithSpan(node, { 14143 replaceWithSpan(node, {