| 3324 | | /** Returns a node after which we can insert other nodes, in the current |
| 3325 | | * selection. The selection is removed. It splits a text node, if needed. |
| 3326 | | */ |
| 3327 | | if ( !HTMLArea.is_ie ) |
| 3328 | | { |
| 3329 | | HTMLArea.prototype.insertNodeAtSelection = function(toBeInserted) |
| 3330 | | { |
| 3331 | | var sel = this._getSelection(); |
| 3332 | | var range = this._createRange(sel); |
| 3333 | | // remove the current selection |
| 3334 | | sel.removeAllRanges(); |
| 3335 | | range.deleteContents(); |
| 3336 | | var node = range.startContainer; |
| 3337 | | var pos = range.startOffset; |
| 3338 | | var selnode = toBeInserted; |
| 3339 | | switch ( node.nodeType ) |
| 3340 | | { |
| 3341 | | case 3: // Node.TEXT_NODE |
| 3342 | | // we have to split it at the caret position. |
| 3343 | | if ( toBeInserted.nodeType == 3 ) |
| 3344 | | { |
| 3345 | | // do optimized insertion |
| 3346 | | node.insertData(pos, toBeInserted.data); |
| 3347 | | range = this._createRange(); |
| 3348 | | range.setEnd(node, pos + toBeInserted.length); |
| 3349 | | range.setStart(node, pos + toBeInserted.length); |
| 3350 | | sel.addRange(range); |
| 3351 | | } |
| 3352 | | else |
| 3353 | | { |
| 3354 | | node = node.splitText(pos); |
| 3355 | | if ( toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */ ) |
| 3356 | | { |
| 3357 | | selnode = selnode.firstChild; |
| 3358 | | } |
| 3359 | | node.parentNode.insertBefore(toBeInserted, node); |
| 3360 | | this.selectNodeContents(selnode); |
| 3361 | | this.updateToolbar(); |
| 3362 | | } |
| 3363 | | break; |
| 3364 | | case 1: // Node.ELEMENT_NODE |
| 3365 | | if ( toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */ ) |
| 3366 | | { |
| 3367 | | selnode = selnode.firstChild; |
| 3368 | | } |
| 3369 | | node.insertBefore(toBeInserted, node.childNodes[pos]); |
| 3370 | | this.selectNodeContents(selnode); |
| 3371 | | this.updateToolbar(); |
| 3372 | | break; |
| 3373 | | } |
| 3374 | | }; |
| 3375 | | } |
| 3376 | | else |
| 3377 | | { |
| 3378 | | HTMLArea.prototype.insertNodeAtSelection = function(toBeInserted) |
| 3379 | | { |
| 3380 | | return null; // this function not yet used for IE <FIXME> |
| 3381 | | }; |
| 3382 | | } |
| 3383 | | |
| 3384 | | // Returns the deepest node that contains both endpoints of the selection. |
| 3385 | | if ( HTMLArea.is_ie ) |
| 3386 | | { |
| 3387 | | HTMLArea.prototype.getParentElement = function(sel) |
| 3388 | | { |
| 3389 | | if ( typeof sel == 'undefined' ) |
| 3390 | | { |
| 3391 | | sel = this._getSelection(); |
| 3392 | | } |
| 3393 | | var range = this._createRange(sel); |
| 3394 | | switch ( sel.type ) |
| 3395 | | { |
| 3396 | | case "Text": |
| 3397 | | // try to circumvent a bug in IE: |
| 3398 | | // the parent returned is not always the real parent element |
| 3399 | | var parent = range.parentElement(); |
| 3400 | | while ( true ) |
| 3401 | | { |
| 3402 | | var TestRange = range.duplicate(); |
| 3403 | | TestRange.moveToElementText(parent); |
| 3404 | | if ( TestRange.inRange(range) ) |
| 3405 | | { |
| 3406 | | break; |
| 3407 | | } |
| 3408 | | if ( ( parent.nodeType != 1 ) || ( parent.tagName.toLowerCase() == 'body' ) ) |
| 3409 | | { |
| 3410 | | break; |
| 3411 | | } |
| 3412 | | parent = parent.parentElement; |
| 3413 | | } |
| 3414 | | return parent; |
| 3415 | | case "None": |
| 3416 | | // It seems that even for selection of type "None", |
| 3417 | | // there _is_ a parent element and it's value is not |
| 3418 | | // only correct, but very important to us. MSIE is |
| 3419 | | // certainly the buggiest browser in the world and I |
| 3420 | | // wonder, God, how can Earth stand it? |
| 3421 | | return range.parentElement(); |
| 3422 | | case "Control": |
| 3423 | | return range.item(0); |
| 3424 | | default: |
| 3425 | | return this._doc.body; |
| 3426 | | } |
| 3427 | | }; |
| 3428 | | } |
| 3429 | | else |
| 3430 | | { |
| 3431 | | HTMLArea.prototype.getParentElement = function(sel) |
| 3432 | | { |
| 3433 | | if ( typeof sel == 'undefined' ) |
| 3434 | | { |
| 3435 | | sel = this._getSelection(); |
| 3436 | | } |
| 3437 | | var range = this._createRange(sel); |
| 3438 | | try |
| 3439 | | { |
| 3440 | | var p = range.commonAncestorContainer; |
| 3441 | | if ( !range.collapsed && range.startContainer == range.endContainer && |
| 3442 | | range.startOffset - range.endOffset <= 1 && range.startContainer.hasChildNodes() ) |
| 3443 | | { |
| 3444 | | p = range.startContainer.childNodes[range.startOffset]; |
| 3445 | | } |
| 3446 | | /* |
| 3447 | | alert(range.startContainer + ":" + range.startOffset + "\n" + |
| 3448 | | range.endContainer + ":" + range.endOffset); |
| 3449 | | */ |
| 3450 | | while ( p.nodeType == 3 ) |
| 3451 | | { |
| 3452 | | p = p.parentNode; |
| 3453 | | } |
| 3454 | | return p; |
| 3455 | | } |
| 3456 | | catch (ex) |
| 3457 | | { |
| 3458 | | return null; |
| 3459 | | } |
| 3460 | | }; |
| 3461 | | } |
| | 3356 | |
| | 3357 | // moved HTMLArea.prototype.insertNodeAtSelection() to browser specific file |
| | 3358 | // moved HTMLArea.prototype.getParentElement() to browser specific file |
| 3525 | | /** |
| 3526 | | * Returns the selected element, if any. That is, |
| 3527 | | * the element that you have last selected in the "path" |
| 3528 | | * at the bottom of the editor, or a "control" (eg image) |
| 3529 | | * |
| 3530 | | * @returns null | element |
| 3531 | | */ |
| 3532 | | if ( HTMLArea.is_ie ) |
| 3533 | | { |
| 3534 | | HTMLArea.prototype._activeElement = function(sel) |
| 3535 | | { |
| 3536 | | if ( ( sel === null ) || this._selectionEmpty(sel) ) |
| 3537 | | { |
| 3538 | | return null; |
| 3539 | | } |
| 3540 | | |
| 3541 | | if ( sel.type.toLowerCase() == "control" ) |
| 3542 | | { |
| 3543 | | return sel.createRange().item(0); |
| 3544 | | } |
| 3545 | | else |
| 3546 | | { |
| 3547 | | // If it's not a control, then we need to see if |
| 3548 | | // the selection is the _entire_ text of a parent node |
| 3549 | | // (this happens when a node is clicked in the tree) |
| 3550 | | var range = sel.createRange(); |
| 3551 | | var p_elm = this.getParentElement(sel); |
| 3552 | | if ( p_elm.innerHTML == range.htmlText ) |
| 3553 | | { |
| 3554 | | return p_elm; |
| 3555 | | } |
| 3556 | | /* |
| 3557 | | if ( p_elm ) |
| 3558 | | { |
| 3559 | | var p_rng = this._doc.body.createTextRange(); |
| 3560 | | p_rng.moveToElementText(p_elm); |
| 3561 | | if ( p_rng.isEqual(range) ) |
| 3562 | | { |
| 3563 | | return p_elm; |
| 3564 | | } |
| 3565 | | } |
| 3566 | | |
| 3567 | | if ( range.parentElement() ) |
| 3568 | | { |
| 3569 | | var prnt_range = this._doc.body.createTextRange(); |
| 3570 | | prnt_range.moveToElementText(range.parentElement()); |
| 3571 | | if ( prnt_range.isEqual(range) ) |
| 3572 | | { |
| 3573 | | return range.parentElement(); |
| 3574 | | } |
| 3575 | | } |
| 3576 | | */ |
| 3577 | | return null; |
| 3578 | | } |
| 3579 | | }; |
| 3580 | | } |
| 3581 | | else |
| 3582 | | { |
| 3583 | | HTMLArea.prototype._activeElement = function(sel) |
| 3584 | | { |
| 3585 | | if ( ( sel === null ) || this._selectionEmpty(sel) ) |
| 3586 | | { |
| 3587 | | return null; |
| 3588 | | } |
| 3589 | | |
| 3590 | | // For Mozilla we just see if the selection is not collapsed (something is selected) |
| 3591 | | // and that the anchor (start of selection) is an element. This might not be totally |
| 3592 | | // correct, we possibly should do a simlar check to IE? |
| 3593 | | if ( !sel.isCollapsed ) |
| 3594 | | { |
| 3595 | | if ( sel.anchorNode.childNodes.length > sel.anchorOffset && sel.anchorNode.childNodes[sel.anchorOffset].nodeType == 1 ) |
| 3596 | | { |
| 3597 | | return sel.anchorNode.childNodes[sel.anchorOffset]; |
| 3598 | | } |
| 3599 | | else if ( sel.anchorNode.nodeType == 1 ) |
| 3600 | | { |
| 3601 | | return sel.anchorNode; |
| 3602 | | } |
| 3603 | | else |
| 3604 | | { |
| 3605 | | return null; // return sel.anchorNode.parentNode; |
| 3606 | | } |
| 3607 | | } |
| 3608 | | return null; |
| 3609 | | }; |
| 3610 | | } |
| 3611 | | |
| 3612 | | if ( HTMLArea.is_ie ) |
| 3613 | | { |
| 3614 | | HTMLArea.prototype._selectionEmpty = function(sel) |
| 3615 | | { |
| 3616 | | if ( !sel ) |
| 3617 | | { |
| 3618 | | return true; |
| 3619 | | } |
| 3620 | | |
| 3621 | | return this._createRange(sel).htmlText === ''; |
| 3622 | | }; |
| 3623 | | } |
| 3624 | | else |
| 3625 | | { |
| 3626 | | HTMLArea.prototype._selectionEmpty = function(sel) |
| 3627 | | { |
| 3628 | | if ( !sel ) |
| 3629 | | { |
| 3630 | | return true; |
| 3631 | | } |
| 3632 | | |
| 3633 | | if ( typeof sel.isCollapsed != 'undefined' ) |
| 3634 | | { |
| 3635 | | return sel.isCollapsed; |
| 3636 | | } |
| 3637 | | |
| 3638 | | return true; |
| 3639 | | }; |
| 3640 | | } |
| | 3422 | // moved HTMLArea.prototype._activeElement() to browser specific file |
| | 3423 | // moved HTMLArea.prototype._selectionEmpty() to browser specific file |
| 3709 | | HTMLArea.prototype._formatBlock = function(block_format) |
| 3710 | | { |
| 3711 | | var ancestors = this.getAllAncestors(); |
| 3712 | | var apply_to, x = null; |
| 3713 | | // Block format can be a tag followed with class defs |
| 3714 | | // eg div.blue.left |
| 3715 | | var target_tag = null; |
| 3716 | | var target_classNames = [ ]; |
| 3717 | | |
| 3718 | | if ( block_format.indexOf('.') >= 0 ) |
| 3719 | | { |
| 3720 | | target_tag = block_format.substr(0, block_format.indexOf('.')).toLowerCase(); |
| 3721 | | target_classNames = block_format.substr(block_format.indexOf('.'), block_format.length - block_format.indexOf('.')).replace(/\./g, '').replace(/^\s*/, '').replace(/\s*$/, '').split(' '); |
| 3722 | | } |
| 3723 | | else |
| 3724 | | { |
| 3725 | | target_tag = block_format.toLowerCase(); |
| 3726 | | } |
| 3727 | | |
| 3728 | | var sel = this._getSelection(); |
| 3729 | | var rng = this._createRange(sel); |
| 3730 | | |
| 3731 | | if ( HTMLArea.is_gecko ) |
| 3732 | | { |
| 3733 | | if ( sel.isCollapsed ) |
| 3734 | | { |
| 3735 | | // With no selection we want to apply to the whole contents of the ancestor block |
| 3736 | | apply_to = this._getAncestorBlock(sel); |
| 3737 | | if ( apply_to === null ) |
| 3738 | | { |
| 3739 | | // If there wasn't an ancestor, make one. |
| 3740 | | apply_to = this._createImplicitBlock(sel, target_tag); |
| 3741 | | } |
| 3742 | | } |
| 3743 | | else |
| 3744 | | { |
| 3745 | | // With a selection it's more tricky |
| 3746 | | switch ( target_tag ) |
| 3747 | | { |
| 3748 | | |
| 3749 | | case 'h1': |
| 3750 | | case 'h2': |
| 3751 | | case 'h3': |
| 3752 | | case 'h4': |
| 3753 | | case 'h5': |
| 3754 | | case 'h6': |
| 3755 | | case 'h7': |
| 3756 | | apply_to = []; |
| 3757 | | var search_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']; |
| 3758 | | for ( var y = 0; y < search_tags.length; y++ ) |
| 3759 | | { |
| 3760 | | var headers = this._doc.getElementsByTagName(search_tags[y]); |
| 3761 | | for ( x = 0; x < headers.length; x++ ) |
| 3762 | | { |
| 3763 | | if ( sel.containsNode(headers[x]) ) |
| 3764 | | { |
| 3765 | | apply_to[apply_to.length] = headers[x]; |
| 3766 | | } |
| 3767 | | } |
| 3768 | | } |
| 3769 | | if ( apply_to.length > 0) |
| 3770 | | { |
| 3771 | | break; |
| 3772 | | } |
| 3773 | | // If there wern't any in the selection drop through |
| 3774 | | case 'div': |
| 3775 | | apply_to = this._doc.createElement(target_tag); |
| 3776 | | apply_to.appendChild(rng.extractContents()); |
| 3777 | | rng.insertNode(apply_to); |
| 3778 | | break; |
| 3779 | | |
| 3780 | | case 'p': |
| 3781 | | case 'center': |
| 3782 | | case 'pre': |
| 3783 | | case 'ins': |
| 3784 | | case 'del': |
| 3785 | | case 'blockquote': |
| 3786 | | case 'address': |
| 3787 | | apply_to = []; |
| 3788 | | var paras = this._doc.getElementsByTagName(target_tag); |
| 3789 | | for ( x = 0; x < paras.length; x++ ) |
| 3790 | | { |
| 3791 | | if ( sel.containsNode(paras[x]) ) |
| 3792 | | { |
| 3793 | | apply_to[apply_to.length] = paras[x]; |
| 3794 | | } |
| 3795 | | } |
| 3796 | | |
| 3797 | | if ( apply_to.length === 0 ) |
| 3798 | | { |
| 3799 | | sel.collapseToStart(); |
| 3800 | | return this._formatBlock(block_format); |
| 3801 | | } |
| 3802 | | break; |
| 3803 | | } |
| 3804 | | } |
| 3805 | | } |
| 3806 | | |
| 3807 | | }; |
| 3808 | | |
| 3809 | | // Selects the contents inside the given node |
| 3810 | | if ( HTMLArea.is_ie ) |
| 3811 | | { |
| 3812 | | HTMLArea.prototype.selectNodeContents = function(node, pos) |
| 3813 | | { |
| 3814 | | this.focusEditor(); |
| 3815 | | this.forceRedraw(); |
| 3816 | | var range; |
| 3817 | | var collapsed = typeof pos == "undefined" ? true : false; |
| 3818 | | // Tables and Images get selected as "objects" rather than the text contents |
| 3819 | | if ( collapsed && node.tagName && node.tagName.toLowerCase().match(/table|img|input|select|textarea/) ) |
| 3820 | | { |
| 3821 | | range = this._doc.body.createControlRange(); |
| 3822 | | range.add(node); |
| 3823 | | } |
| 3824 | | else |
| 3825 | | { |
| 3826 | | range = this._doc.body.createTextRange(); |
| 3827 | | range.moveToElementText(node); |
| 3828 | | //(collapsed) && range.collapse(pos); |
| 3829 | | } |
| 3830 | | range.select(); |
| 3831 | | }; |
| 3832 | | } |
| 3833 | | else |
| 3834 | | { |
| 3835 | | HTMLArea.prototype.selectNodeContents = function(node, pos) |
| 3836 | | { |
| 3837 | | this.focusEditor(); |
| 3838 | | this.forceRedraw(); |
| 3839 | | var range; |
| 3840 | | var collapsed = typeof pos == "undefined" ? true : false; |
| 3841 | | var sel = this._getSelection(); |
| 3842 | | range = this._doc.createRange(); |
| 3843 | | // Tables and Images get selected as "objects" rather than the text contents |
| 3844 | | if ( collapsed && node.tagName && node.tagName.toLowerCase().match(/table|img|input|textarea|select/) ) |
| 3845 | | { |
| 3846 | | range.selectNode(node); |
| 3847 | | } |
| 3848 | | else |
| 3849 | | { |
| 3850 | | range.selectNodeContents(node); |
| 3851 | | //(collapsed) && range.collapse(pos); |
| 3852 | | } |
| 3853 | | sel.removeAllRanges(); |
| 3854 | | sel.addRange(range); |
| 3855 | | }; |
| 3856 | | } |
| 3857 | | |
| 3858 | | /** Call this function to insert HTML code at the current position. It deletes |
| 3859 | | * the selection, if any. |
| 3860 | | */ |
| 3861 | | if ( HTMLArea.is_ie ) |
| 3862 | | { |
| 3863 | | HTMLArea.prototype.insertHTML = function(html) |
| 3864 | | { |
| 3865 | | var sel = this._getSelection(); |
| 3866 | | var range = this._createRange(sel); |
| 3867 | | this.focusEditor(); |
| 3868 | | range.pasteHTML(html); |
| 3869 | | }; |
| 3870 | | } |
| 3871 | | else |
| 3872 | | { |
| 3873 | | HTMLArea.prototype.insertHTML = function(html) |
| 3874 | | { |
| 3875 | | var sel = this._getSelection(); |
| 3876 | | var range = this._createRange(sel); |
| 3877 | | this.focusEditor(); |
| 3878 | | // construct a new document fragment with the given HTML |
| 3879 | | var fragment = this._doc.createDocumentFragment(); |
| 3880 | | var div = this._doc.createElement("div"); |
| 3881 | | div.innerHTML = html; |
| 3882 | | while ( div.firstChild ) |
| 3883 | | { |
| 3884 | | // the following call also removes the node from div |
| 3885 | | fragment.appendChild(div.firstChild); |
| 3886 | | } |
| 3887 | | // this also removes the selection |
| 3888 | | var node = this.insertNodeAtSelection(fragment); |
| 3889 | | }; |
| 3890 | | } |
| | 3492 | |
| | 3493 | // moved HTMLArea.prototype.selectNodeContents() to browser specific file |
| | 3494 | // moved HTMLArea.prototype.insertHTML() to browser specific file |
| 3942 | | HTMLArea.prototype._createLink = function(link) |
| 3943 | | { |
| 3944 | | var editor = this; |
| 3945 | | var outparam = null; |
| 3946 | | if ( typeof link == "undefined" ) |
| 3947 | | { |
| 3948 | | link = this.getParentElement(); |
| 3949 | | if ( link ) |
| 3950 | | { |
| 3951 | | while (link && !/^a$/i.test(link.tagName)) |
| 3952 | | { |
| 3953 | | link = link.parentNode; |
| 3954 | | } |
| 3955 | | } |
| 3956 | | } |
| 3957 | | if ( !link ) |
| 3958 | | { |
| 3959 | | var sel = editor._getSelection(); |
| 3960 | | var range = editor._createRange(sel); |
| 3961 | | var compare = 0; |
| 3962 | | if ( HTMLArea.is_ie ) |
| 3963 | | { |
| 3964 | | if ( sel.type == "Control" ) |
| 3965 | | { |
| 3966 | | compare = range.length; |
| 3967 | | } |
| 3968 | | else |
| 3969 | | { |
| 3970 | | compare = range.compareEndPoints("StartToEnd", range); |
| 3971 | | } |
| 3972 | | } |
| 3973 | | else |
| 3974 | | { |
| 3975 | | compare = range.compareBoundaryPoints(range.START_TO_END, range); |
| 3976 | | } |
| 3977 | | if ( compare === 0 ) |
| 3978 | | { |
| 3979 | | alert(HTMLArea._lc("You need to select some text before creating a link")); |
| 3980 | | return; |
| 3981 | | } |
| 3982 | | outparam = |
| 3983 | | { |
| 3984 | | f_href : '', |
| 3985 | | f_title : '', |
| 3986 | | f_target : '', |
| 3987 | | f_usetarget : editor.config.makeLinkShowsTarget |
| 3988 | | }; |
| 3989 | | } |
| 3990 | | else |
| 3991 | | { |
| 3992 | | outparam = |
| 3993 | | { |
| 3994 | | f_href : HTMLArea.is_ie ? editor.stripBaseURL(link.href) : link.getAttribute("href"), |
| 3995 | | f_title : link.title, |
| 3996 | | f_target : link.target, |
| 3997 | | f_usetarget : editor.config.makeLinkShowsTarget |
| 3998 | | }; |
| 3999 | | } |
| 4000 | | this._popupDialog( |
| 4001 | | editor.config.URIs.link, |
| 4002 | | function(param) |
| 4003 | | { |
| 4004 | | if ( !param ) |
| 4005 | | { |
| 4006 | | return false; |
| 4007 | | } |
| 4008 | | var a = link; |
| 4009 | | if ( !a ) |
| 4010 | | { |
| 4011 | | try |
| 4012 | | { |
| 4013 | | var tmp = HTMLArea.uniq('http://www.example.com/Link'); |
| 4014 | | editor._doc.execCommand('createlink', false, tmp); |
| 4015 | | |
| 4016 | | // Fix them up |
| 4017 | | var anchors = editor._doc.getElementsByTagName('a'); |
| 4018 | | for(var i = 0; i < anchors.length; i++) |
| 4019 | | { |
| 4020 | | var anchor = anchors[i]; |
| 4021 | | if(anchor.href == tmp) |
| 4022 | | { |
| 4023 | | // Found one. |
| 4024 | | if (!a) a = anchor; |
| 4025 | | anchor.href = param.f_href; |
| 4026 | | if (param.f_target) anchor.target = param.f_target; |
| 4027 | | if (param.f_title) anchor.title = param.f_title; |
| 4028 | | } |
| 4029 | | } |
| 4030 | | } catch(ex) {} |
| 4031 | | } |
| 4032 | | else |
| 4033 | | { |
| 4034 | | var href = param.f_href.trim(); |
| 4035 | | editor.selectNodeContents(a); |
| 4036 | | if ( href === '' ) |
| 4037 | | { |
| 4038 | | editor._doc.execCommand("unlink", false, null); |
| 4039 | | editor.updateToolbar(); |
| 4040 | | return false; |
| 4041 | | } |
| 4042 | | else |
| 4043 | | { |
| 4044 | | a.href = href; |
| 4045 | | } |
| 4046 | | } |
| 4047 | | if ( ! ( a && a.tagName.toLowerCase() == 'a' ) ) |
| 4048 | | { |
| 4049 | | return false; |
| 4050 | | } |
| 4051 | | a.target = param.f_target.trim(); |
| 4052 | | a.title = param.f_title.trim(); |
| 4053 | | editor.selectNodeContents(a); |
| 4054 | | editor.updateToolbar(); |
| 4055 | | }, |
| 4056 | | outparam); |
| 4057 | | }; |
| 4058 | | |
| 4059 | | // Called when the user clicks on "InsertImage" button. If an image is already |
| 4060 | | // there, it will just modify it's properties. |
| 4061 | | HTMLArea.prototype._insertImage = function(image) |
| 4062 | | { |
| 4063 | | var editor = this; // for nested functions |
| 4064 | | var outparam = null; |
| 4065 | | if ( typeof image == "undefined" ) |
| 4066 | | { |
| 4067 | | image = this.getParentElement(); |
| 4068 | | if ( image && image.tagName.toLowerCase() != 'img' ) |
| 4069 | | { |
| 4070 | | image = null; |
| 4071 | | } |
| 4072 | | } |
| 4073 | | if ( image ) |
| 4074 | | { |
| 4075 | | outparam = |
| 4076 | | { |
| 4077 | | f_base : editor.config.baseHref, |
| 4078 | | f_url : HTMLArea.is_ie ? editor.stripBaseURL(image.src) : image.getAttribute("src"), |
| 4079 | | f_alt : image.alt, |
| 4080 | | f_border : image.border, |
| 4081 | | f_align : image.align, |
| 4082 | | f_vert : image.vspace, |
| 4083 | | f_horiz : image.hspace |
| 4084 | | }; |
| 4085 | | } |
| 4086 | | this._popupDialog( |
| 4087 | | editor.config.URIs.insert_image, |
| 4088 | | function(param) |
| 4089 | | { |
| 4090 | | // user must have pressed Cancel |
| 4091 | | if ( !param ) |
| 4092 | | { |
| 4093 | | return false; |
| 4094 | | } |
| 4095 | | var img = image; |
| 4096 | | if ( !img ) |
| 4097 | | { |
| 4098 | | if ( HTMLArea.is_ie ) |
| 4099 | | { |
| 4100 | | var sel = editor._getSelection(); |
| 4101 | | var range = editor._createRange(sel); |
| 4102 | | editor._doc.execCommand("insertimage", false, param.f_url); |
| 4103 | | img = range.parentElement(); |
| 4104 | | // wonder if this works... |
| 4105 | | if ( img.tagName.toLowerCase() != "img" ) |
| 4106 | | { |
| 4107 | | img = img.previousSibling; |
| 4108 | | } |
| 4109 | | } |
| 4110 | | else |
| 4111 | | { |
| 4112 | | img = document.createElement('img'); |
| 4113 | | img.src = param.f_url; |
| 4114 | | editor.insertNodeAtSelection(img); |
| 4115 | | if ( !img.tagName ) |
| 4116 | | { |
| 4117 | | // if the cursor is at the beginning of the document |
| 4118 | | img = range.startContainer.firstChild; |
| 4119 | | } |
| 4120 | | } |
| 4121 | | } |
| 4122 | | else |
| 4123 | | { |
| 4124 | | img.src = param.f_url; |
| 4125 | | } |
| 4126 | | |
| 4127 | | for ( var field in param ) |
| 4128 | | { |
| 4129 | | var value = param[field]; |
| 4130 | | switch (field) |
| 4131 | | { |
| 4132 | | case "f_alt": |
| 4133 | | img.alt = value; |
| 4134 | | break; |
| 4135 | | case "f_border": |
| 4136 | | img.border = parseInt(value || "0", 10); |
| 4137 | | break; |
| 4138 | | case "f_align": |
| 4139 | | img.align = value; |
| 4140 | | break; |
| 4141 | | case "f_vert": |
| 4142 | | img.vspace = parseInt(value || "0", 10); |
| 4143 | | break; |
| 4144 | | case "f_horiz": |
| 4145 | | img.hspace = parseInt(value || "0", 10); |
| 4146 | | break; |
| 4147 | | } |
| 4148 | | } |
| 4149 | | }, |
| 4150 | | outparam); |
| 4151 | | }; |
| | 3517 | // moved HTMLArea.prototype._createLink() to popups/link.js |
| | 3518 | // moved HTMLArea.prototype._insertImage() to popups/insert_image.js |
| 4509 | | // IE's textRange and selection object is woefully inadequate, |
| 4510 | | // which means this fancy stuff is gecko only sorry :-| |
| 4511 | | // Die Bill, Die. (IE supports it somewhat nativly though) |
| 4512 | | if ( HTMLArea.is_gecko ) |
| 4513 | | { |
| 4514 | | var s = editor._getSelection(); |
| 4515 | | var autoWrap = function (textNode, tag) |
| 4516 | | { |
| 4517 | | var rightText = textNode.nextSibling; |
| 4518 | | if ( typeof tag == 'string') |
| 4519 | | { |
| 4520 | | tag = editor._doc.createElement(tag); |
| 4521 | | } |
| 4522 | | var a = textNode.parentNode.insertBefore(tag, rightText); |
| 4523 | | HTMLArea.removeFromParent(textNode); |
| 4524 | | a.appendChild(textNode); |
| 4525 | | rightText.data = ' ' + rightText.data; |
| 4526 | | |
| 4527 | | if ( HTMLArea.is_ie ) |
| 4528 | | { |
| 4529 | | var r = editor._createRange(s); |
| 4530 | | s.moveToElementText(rightText); |
| 4531 | | s.move('character', 1); |
| 4532 | | } |
| 4533 | | else |
| 4534 | | { |
| 4535 | | s.collapse(rightText, 1); |
| 4536 | | } |
| 4537 | | HTMLArea._stopEvent(ev); |
| 4538 | | |
| 4539 | | editor._unLink = function() |
| 4540 | | { |
| 4541 | | var t = a.firstChild; |
| 4542 | | a.removeChild(t); |
| 4543 | | a.parentNode.insertBefore(t, a); |
| 4544 | | HTMLArea.removeFromParent(a); |
| 4545 | | editor._unLink = null; |
| 4546 | | editor._unlinkOnUndo = false; |
| 4547 | | }; |
| 4548 | | editor._unlinkOnUndo = true; |
| 4549 | | |
| 4550 | | return a; |
| 4551 | | }; |
| 4552 | | |
| 4553 | | switch ( ev.which ) |
| 4554 | | { |
| 4555 | | // Space, see if the text just typed looks like a URL, or email address |
| 4556 | | // and link it appropriatly |
| 4557 | | case 32: |
| 4558 | | if ( this.config.convertUrlsToLinks && s.isCollapsed && s.anchorNode.nodeType == 3 && s.anchorNode.data.length > 3 && s.anchorNode.data.indexOf('.') >= 0 ) |
| 4559 | | { |
| 4560 | | var midStart = s.anchorNode.data.substring(0,s.anchorOffset).search(/\S{4,}$/); |
| 4561 | | if ( midStart == -1 ) |
| 4562 | | { |
| 4563 | | break; |
| 4564 | | } |
| 4565 | | |
| 4566 | | if ( this._getFirstAncestor(s, 'a') ) |
| 4567 | | { |
| 4568 | | break; // already in an anchor |
| 4569 | | } |
| 4570 | | |
| 4571 | | var matchData = s.anchorNode.data.substring(0,s.anchorOffset).replace(/^.*?(\S*)$/, '$1'); |
| 4572 | | |
| 4573 | | var mEmail = matchData.match(HTMLArea.RE_email); |
| 4574 | | if ( mEmail ) |
| 4575 | | { |
| 4576 | | var leftTextEmail = s.anchorNode; |
| 4577 | | var rightTextEmail = leftTextEmail.splitText(s.anchorOffset); |
| 4578 | | var midTextEmail = leftTextEmail.splitText(midStart); |
| 4579 | | |
| 4580 | | autoWrap(midTextEmail, 'a').href = 'mailto:' + mEmail[0]; |
| 4581 | | break; |
| 4582 | | } |
| 4583 | | |
| 4584 | | RE_date = /([0-9]+\.)+/; //could be date or ip or something else ... |
| 4585 | | RE_ip = /(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/; |
| 4586 | | var mUrl = matchData.match(HTMLArea.RE_url); |
| 4587 | | if ( mUrl ) |
| 4588 | | { |
| 4589 | | if (RE_date.test(matchData)) |
| 4590 | | { |
| 4591 | | if (!RE_ip.test(matchData)) |
| 4592 | | { |
| 4593 | | break; |
| 4594 | | } |
| 4595 | | } |
| 4596 | | var leftTextUrl = s.anchorNode; |
| 4597 | | var rightTextUrl = leftTextUrl.splitText(s.anchorOffset); |
| 4598 | | var midTextUrl = leftTextUrl.splitText(midStart); |
| 4599 | | autoWrap(midTextUrl, 'a').href = (mUrl[1] ? mUrl[1] : 'http://') + mUrl[2]; |
| 4600 | | break; |
| 4601 | | } |
| 4602 | | } |
| 4603 | | break; |
| 4604 | | |
| 4605 | | default: |
| 4606 | | if ( ev.keyCode == 27 || ( this._unlinkOnUndo && ev.ctrlKey && ev.which == 122 ) ) |
| 4607 | | { |
| 4608 | | if ( this._unLink ) |
| 4609 | | { |
| 4610 | | this._unLink(); |
| 4611 | | HTMLArea._stopEvent(ev); |
| 4612 | | } |
| 4613 | | break; |
| 4614 | | } |
| 4615 | | else if ( ev.which || ev.keyCode == 8 || ev.keyCode == 46 ) |
| 4616 | | { |
| 4617 | | this._unlinkOnUndo = false; |
| 4618 | | |
| 4619 | | if ( s.anchorNode && s.anchorNode.nodeType == 3 ) |
| 4620 | | { |
| 4621 | | // See if we might be changing a link |
| 4622 | | var a = this._getFirstAncestor(s, 'a'); |
| 4623 | | // @todo: we probably need here to inform the setTimeout below that we not changing a link and not start another setTimeout |
| 4624 | | if ( !a ) |
| 4625 | | { |
| 4626 | | break; // not an anchor |
| 4627 | | } |
| 4628 | | if ( !a._updateAnchTimeout ) |
| 4629 | | { |
| 4630 | | if ( s.anchorNode.data.match(HTMLArea.RE_email) && a.href.match('mailto:' + s.anchorNode.data.trim()) ) |
| 4631 | | { |
| 4632 | | var textNode = s.anchorNode; |
| 4633 | | var fnAnchor = function() |
| 4634 | | { |
| 4635 | | a.href = 'mailto:' + textNode.data.trim(); |
| 4636 | | // @fixme: why the hell do another timeout is started ? |
| 4637 | | // This lead to never ending timer if we dont remove this line |
| 4638 | | // But when removed, the email is not correctly updated |
| 4639 | | a._updateAnchTimeout = setTimeout(fnAnchor, 250); |
| 4640 | | }; |
| 4641 | | a._updateAnchTimeout = setTimeout(fnAnchor, 1000); |
| 4642 | | break; |
| 4643 | | } |
| 4644 | | |
| 4645 | | var m = s.anchorNode.data.match(HTMLArea.RE_url); |
| 4646 | | if ( m && a.href.match(s.anchorNode.data.trim()) ) |
| 4647 | | { |
| 4648 | | var txtNode = s.anchorNode; |
| 4649 | | var fnUrl = function() |
| 4650 | | { |
| 4651 | | // @fixme: Alert, sometimes m is undefined becase the url is not an url anymore (was www.url.com and become for example www.url) |
| 4652 | | m = txtNode.data.match(HTMLArea.RE_url); |
| 4653 | | a.href = (m[1] ? m[1] : 'http://') + m[2]; |
| 4654 | | // @fixme: why the hell do another timeout is started ? |
| 4655 | | // This lead to never ending timer if we dont remove this line |
| 4656 | | // But when removed, the url is not correctly updated |
| 4657 | | a._updateAnchTimeout = setTimeout(fnUrl, 250); |
| 4658 | | }; |
| 4659 | | a._updateAnchTimeout = setTimeout(fnUrl, 1000); |
| 4660 | | } |
| 4661 | | } |
| 4662 | | } |
| 4663 | | } |
| 4664 | | break; |
| 4665 | | } |
| 4666 | | } |
| 4667 | | |
| 4668 | | // other keys here |
| 4669 | | switch (ev.keyCode) |
| 4670 | | { |
| 4671 | | case 13: // KEY enter |
| 4672 | | if ( HTMLArea.is_gecko && !ev.shiftKey && this.config.mozParaHandler == 'dirty' ) |
| 4673 | | { |
| 4674 | | this.dom_checkInsertP(); |
| 4675 | | HTMLArea._stopEvent(ev); |
| 4676 | | } |
| 4677 | | break; |
| 4678 | | case 8: // KEY backspace |
| 4679 | | case 46: // KEY delete |
| 4680 | | if ( ( HTMLArea.is_gecko && !ev.shiftKey ) || HTMLArea.is_ie ) |
| 4681 | | { |
| 4682 | | if ( this.checkBackspace() ) |
| 4683 | | { |
| 4684 | | HTMLArea._stopEvent(ev); |
| 4685 | | } |
| 4686 | | } |
| 4687 | | break; |
| 4688 | | } |
| | 3876 | this.mozKey( ev, keyEvent ); |
| 4786 | | if ( HTMLArea.is_ie ) |
| 4787 | | { |
| 4788 | | // this function is for IE |
| 4789 | | HTMLArea.prototype.checkBackspace = function() |
| 4790 | | { |
| 4791 | | var sel = this._getSelection(); |
| 4792 | | if ( sel.type == 'Control' ) |
| 4793 | | { |
| 4794 | | var elm = this._activeElement(sel); |
| 4795 | | HTMLArea.removeFromParent(elm); |
| 4796 | | return true; |
| 4797 | | } |
| 4798 | | |
| 4799 | | // This bit of code preseves links when you backspace over the |
| 4800 | | // endpoint of the link in IE. Without it, if you have something like |
| 4801 | | // link_here | |
| 4802 | | // where | is the cursor, and backspace over the last e, then the link |
| 4803 | | // will de-link, which is a bit tedious |
| 4804 | | var range = this._createRange(sel); |
| 4805 | | var r2 = range.duplicate(); |
| 4806 | | r2.moveStart("character", -1); |
| 4807 | | var a = r2.parentElement(); |
| 4808 | | // @fixme: why using again a regex to test a single string ??? |
| 4809 | | if ( a != range.parentElement() && ( /^a$/i.test(a.tagName) ) ) |
| 4810 | | { |
| 4811 | | r2.collapse(true); |
| 4812 | | r2.moveEnd("character", 1); |
| 4813 | | r2.pasteHTML(''); |
| 4814 | | r2.select(); |
| 4815 | | return true; |
| 4816 | | } |
| 4817 | | }; |
| 4818 | | } |
| 4819 | | else |
| 4820 | | { |
| 4821 | | // this function is for DOM |
| 4822 | | HTMLArea.prototype.checkBackspace = function() |
| 4823 | | { |
| 4824 | | var self = this; |
| 4825 | | setTimeout( |
| 4826 | | function() |
| 4827 | | { |
| 4828 | | var sel = self._getSelection(); |
| 4829 | | var range = self._createRange(sel); |
| 4830 | | var SC = range.startContainer; |
| 4831 | | var SO = range.startOffset; |
| 4832 | | var EC = range.endContainer; |
| 4833 | | var EO = range.endOffset; |
| 4834 | | var newr = SC.nextSibling; |
| 4835 | | if ( SC.nodeType == 3 ) |
| 4836 | | { |
| 4837 | | SC = SC.parentNode; |
| 4838 | | } |
| 4839 | | if ( ! ( /\S/.test(SC.tagName) ) ) |
| 4840 | | { |
| 4841 | | var p = document.createElement("p"); |
| 4842 | | while ( SC.firstChild ) |
| 4843 | | { |
| 4844 | | p.appendChild(SC.firstChild); |
| 4845 | | } |
| 4846 | | SC.parentNode.insertBefore(p, SC); |
| 4847 | | HTMLArea.removeFromParent(SC); |
| 4848 | | var r = range.cloneRange(); |
| 4849 | | r.setStartBefore(newr); |
| 4850 | | r.setEndAfter(newr); |
| 4851 | | r.extractContents(); |
| 4852 | | sel.removeAllRanges(); |
| 4853 | | sel.addRange(r); |
| 4854 | | } |
| 4855 | | }, |
| 4856 | | 10); |
| 4857 | | }; |
| 4858 | | } |
| | 3975 | // moved HTMLArea.prototype.checkBackspace() to browser specific file |
| 5778 | | // Retrieves the HTML code from the given node. This is a replacement for |
| 5779 | | // getting innerHTML, using standard DOM calls. |
| 5780 | | // Wrapper catch a Mozilla-Exception with non well formed html source code |
| 5781 | | HTMLArea.getHTML = function(root, outputRoot, editor) |
| 5782 | | { |
| 5783 | | try |
| 5784 | | { |
| 5785 | | return HTMLArea.getHTMLWrapper(root,outputRoot,editor); |
| 5786 | | } |
| 5787 | | catch(ex) |
| 5788 | | { |
| 5789 | | alert(HTMLArea._lc('Your Document is not well formed. Check JavaScript console for details.')); |
| 5790 | | return editor._iframe.contentWindow.document.body.innerHTML; |
| 5791 | | } |
| 5792 | | }; |
| 5793 | | |
| 5794 | | HTMLArea.getHTMLWrapper = function(root, outputRoot, editor, indent) |
| 5795 | | { |
| 5796 | | var html = ""; |
| 5797 | | if ( !indent ) |
| 5798 | | { |
| 5799 | | indent = ''; |
| 5800 | | } |
| 5801 | | |
| 5802 | | switch ( root.nodeType ) |
| 5803 | | { |
| 5804 | | case 10:// Node.DOCUMENT_TYPE_NODE |
| 5805 | | case 6: // Node.ENTITY_NODE |
| 5806 | | case 12:// Node.NOTATION_NODE |
| 5807 | | // this all are for the document type, probably not necessary |
| 5808 | | break; |
| 5809 | | |
| 5810 | | case 2: // Node.ATTRIBUTE_NODE |
| 5811 | | // Never get here, this has to be handled in the ELEMENT case because |
| 5812 | | // of IE crapness requring that some attributes are grabbed directly from |
| 5813 | | // the attribute (nodeValue doesn't return correct values), see |
| 5814 | | //http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=3porgu4mc4ofcoa1uqkf7u8kvv064kjjb4%404ax.com |
| 5815 | | // for information |
| 5816 | | break; |
| 5817 | | |
| 5818 | | case 4: // Node.CDATA_SECTION_NODE |
| 5819 | | // Mozilla seems to convert CDATA into a comment when going into wysiwyg mode, |
| 5820 | | // don't know about IE |
| 5821 | | html += (HTMLArea.is_ie ? ('\n' + indent) : '') + '<![CDATA[' + root.data + ']]>' ; |
| 5822 | | break; |
| 5823 | | |
| 5824 | | case 5: // Node.ENTITY_REFERENCE_NODE |
| 5825 | | html += '&' + root.nodeValue + ';'; |
| 5826 | | break; |
| 5827 | | |
| 5828 | | case 7: // Node.PROCESSING_INSTRUCTION_NODE |
| 5829 | | // PI's don't seem to survive going into the wysiwyg mode, (at least in moz) |
| 5830 | | // so this is purely academic |
| 5831 | | html += (HTMLArea.is_ie ? ('\n' + indent) : '') + '<?' + root.target + ' ' + root.data + ' ?>'; |
| 5832 | | break; |
| 5833 | | |
| 5834 | | case 1: // Node.ELEMENT_NODE |
| 5835 | | case 11: // Node.DOCUMENT_FRAGMENT_NODE |
| 5836 | | case 9: // Node.DOCUMENT_NODE |
| 5837 | | var closed; |
| 5838 | | var i; |
| 5839 | | var root_tag = (root.nodeType == 1) ? root.tagName.toLowerCase() : ''; |
| 5840 | | if ( ( root_tag == "script" || root_tag == "noscript" ) && editor.config.stripScripts ) |
| 5841 | | { |
| 5842 | | break; |
| 5843 | | } |
| 5844 | | if ( outputRoot ) |
| 5845 | | { |
| 5846 | | outputRoot = !(editor.config.htmlRemoveTags && editor.config.htmlRemoveTags.test(root_tag)); |
| 5847 | | } |
| 5848 | | if ( HTMLArea.is_ie && root_tag == "head" ) |
| 5849 | | { |
| 5850 | | if ( outputRoot ) |
| 5851 | | { |
| 5852 | | html += (HTMLArea.is_ie ? ('\n' + indent) : '') + "<head>"; |
| 5853 | | } |
| 5854 | | // lowercasize |
| 5855 | | var save_multiline = RegExp.multiline; |
| 5856 | | RegExp.multiline = true; |
| 5857 | | var txt = root.innerHTML.replace(HTMLArea.RE_tagName, function(str, p1, p2) { return p1 + p2.toLowerCase(); }); |
| 5858 | | RegExp.multiline = save_multiline; |
| 5859 | | html += txt + '\n'; |
| 5860 | | if ( outputRoot ) |
| 5861 | | { |
| 5862 | | html += (HTMLArea.is_ie ? ('\n' + indent) : '') + "</head>"; |
| 5863 | | } |
| 5864 | | break; |
| 5865 | | } |
| 5866 | | else if ( outputRoot ) |
| 5867 | | { |
| 5868 | | closed = (!(root.hasChildNodes() || HTMLArea.needsClosingTag(root))); |
| 5869 | | html += (HTMLArea.is_ie && HTMLArea.isBlockElement(root) ? ('\n' + indent) : '') + "<" + root.tagName.toLowerCase(); |
| 5870 | | var attrs = root.attributes; |
| 5871 | | for ( i = 0; i < attrs.length; ++i ) |
| 5872 | | { |
| 5873 | | var a = attrs.item(i); |
| 5874 | | if ( !a.specified && !(root.tagName.toLowerCase().match(/input|option/) && a.nodeName == 'value') ) |
| 5875 | | { |
| 5876 | | continue; |
| 5877 | | } |
| 5878 | | var name = a.nodeName.toLowerCase(); |
| 5879 | | if ( /_moz_editor_bogus_node/.test(name) ) |
| 5880 | | { |
| 5881 | | html = ""; |
| 5882 | | break; |
| 5883 | | } |
| 5884 | | if ( /(_moz)|(contenteditable)|(_msh)/.test(name) ) |
| 5885 | | { |
| 5886 | | // avoid certain attributes |
| 5887 | | continue; |
| 5888 | | } |
| 5889 | | var value; |
| 5890 | | if ( name != "style" ) |
| 5891 | | { |
| 5892 | | // IE5.5 reports 25 when cellSpacing is |
| 5893 | | // 1; other values might be doomed too. |
| 5894 | | // For this reason we extract the |
| 5895 | | // values directly from the root node. |
| 5896 | | // I'm starting to HATE JavaScript |
| 5897 | | // development. Browser differences |
| 5898 | | // suck. |
| 5899 | | // |
| 5900 | | // Using Gecko the values of href and src are converted to absolute links |
| 5901 | | // unless we get them using nodeValue() |
| 5902 | | if ( typeof root[a.nodeName] != "undefined" && name != "href" && name != "src" && !(/^on/.test(name)) ) |
| 5903 | | { |
| 5904 | | value = root[a.nodeName]; |
| 5905 | | } |
| 5906 | | else |
| 5907 | | { |
| 5908 | | value = a.nodeValue; |
| 5909 | | // IE seems not willing to return the original values - it converts to absolute |
| 5910 | | // links using a.nodeValue, a.value, a.stringValue, root.getAttribute("href") |
| 5911 | | // So we have to strip the baseurl manually :-/ |
| 5912 | | if ( HTMLArea.is_ie && (name == "href" || name == "src") ) |
| 5913 | | { |
| 5914 | | value = editor.stripBaseURL(value); |
| 5915 | | } |
| 5916 | | |
| 5917 | | // High-ascii (8bit) characters in links seem to cause problems for some sites, |
| 5918 | | // while this seems to be consistent with RFC 3986 Section 2.4 |
| 5919 | | // because these are not "reserved" characters, it does seem to |
| 5920 | | // cause links to international resources not to work. See ticket:167 |
| 5921 | | |
| 5922 | | // IE always returns high-ascii characters un-encoded in links even if they |
| 5923 | | // were supplied as % codes (it unescapes them when we pul the value from the link). |
| 5924 | | |
| 5925 | | // Hmmm, very strange if we use encodeURI here, or encodeURIComponent in place |
| 5926 | | // of escape below, then the encoding is wrong. I mean, completely. |
| 5927 | | // Nothing like it should be at all. Using escape seems to work though. |
| 5928 | | // It's in both browsers too, so either I'm doing something wrong, or |
| 5929 | | // something else is going on? |
| 5930 | | |
| 5931 | | if ( editor.config.only7BitPrintablesInURLs && ( name == "href" || name == "src" ) ) |
| 5932 | | { |
| 5933 | | value = value.replace(/([^!-~]+)/g, function(match) { return escape(match); }); |
| 5934 | | } |
| 5935 | | } |
| 5936 | | } |
| 5937 | | else |
| 5938 | | { |
| 5939 | | // IE fails to put style in attributes list |
| 5940 | | // FIXME: cssText reported by IE is UPPERCASE |
| 5941 | | value = root.style.cssText; |
| 5942 | | } |
| 5943 | | if ( /^(_moz)?$/.test(value) ) |
| 5944 | | { |
| 5945 | | // Mozilla reports some special tags |
| 5946 | | // here; we don't need them. |
| 5947 | | continue; |
| 5948 | | } |
| 5949 | | html += " " + name + '="' + HTMLArea.htmlEncode(value) + '"'; |
| 5950 | | } |
| 5951 | | if ( html !== "" ) |
| 5952 | | { |
| 5953 | | if ( closed && root_tag=="p" ) |
| 5954 | | { |
| 5955 | | //never use <p /> as empty paragraphs won't be visible |
| 5956 | | html += "> </p>"; |
| 5957 | | } |
| 5958 | | else if ( closed ) |
| 5959 | | { |
| 5960 | | html += " />"; |
| 5961 | | } |
| 5962 | | else |
| 5963 | | { |
| 5964 | | html += ">"; |
| 5965 | | } |
| 5966 | | } |
| 5967 | | } |
| 5968 | | var containsBlock = false; |
| 5969 | | if ( root_tag == "script" || root_tag == "noscript" ) |
| 5970 | | { |
| 5971 | | if ( !editor.config.stripScripts ) |
| 5972 | | { |
| 5973 | | if (HTMLArea.is_ie) |
| 5974 | | { |
| 5975 | | var innerText = "\n" + root.innerHTML.replace(/^[\n\r]*/,'').replace(/\s+$/,'') + '\n' + indent; |
| 5976 | | } |
| 5977 | | else |
| 5978 | | { |
| 5979 | | var innerText = (root.hasChildNodes()) ? root.firstChild.nodeValue : ''; |
| 5980 | | } |
| 5981 | | html += innerText + '</'+root_tag+'>' + ((HTMLArea.is_ie) ? '\n' : ''); |
| 5982 | | } |
| 5983 | | } |
| 5984 | | else |
| 5985 | | { |
| 5986 | | for ( i = root.firstChild; i; i = i.nextSibling ) |
| 5987 | | { |
| 5988 | | if ( !containsBlock && i.nodeType == 1 && HTMLArea.isBlockElement(i) ) |
| 5989 | | { |
| 5990 | | containsBlock = true; |
| 5991 | | } |
| 5992 | | html += HTMLArea.getHTMLWrapper(i, true, editor, indent + ' '); |
| 5993 | | } |
| 5994 | | if ( outputRoot && !closed ) |
| 5995 | | { |
| 5996 | | html += (HTMLArea.is_ie && HTMLArea.isBlockElement(root) && containsBlock ? ('\n' + indent) : '') + "</" + root.tagName.toLowerCase() + ">"; |
| 5997 | | } |
| 5998 | | } |
| 5999 | | break; |
| 6000 | | |
| 6001 | | case 3: // Node.TEXT_NODE |
| 6002 | | html = /^script|style$/i.test(root.parentNode.tagName) ? root.data : HTMLArea.htmlEncode(root.data); |
| 6003 | | break; |
| 6004 | | |
| 6005 | | case 8: // Node.COMMENT_NODE |
| 6006 | | html = "<!--" + root.data + "-->"; |
| 6007 | | break; |
| 6008 | | } |
| 6009 | | return html; |
| 6010 | | }; |
| 6011 | | |
| 6012 | | /** @see getHTMLWrapper (search for "value = a.nodeValue;") */ |
| 6013 | | |
| | 4851 | // moved HTMLArea.getHTML() to getHTML.js |