• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

奋斗中...

曾经的程序员。ASP.NET/C#, JavaScript, PL/SQL, T-SQL; 工具: VS2003/2005, Oracle, SQLServer; 偶尔写点CSS, 批处理.
头脑中经常有新想法, 可惜没有去实现.
Never give up.
Never get into a fight with a pig. Both of you will get dirty. But the pig actually enjoys it.
  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

[JavaScript]模式窗口只读状态下复制控件文本

模式窗口只读状态下要进行复制很麻烦,无法选定文本也无法进行复制、编辑、右键浏览器菜单。本文提供一种解决这个问题的方法:使用JavaScript脚本,选定控件文本,再使用CTRL+C进行复制。

模式窗口只读状态下要进行复制很麻烦,无法选定文本也无法进行复制、编辑、右键浏览器菜单。本文提供一种解决这个问题的方法:使用JavaScript脚本,选定控件文本,再使用CTRL+C进行复制。


一、一些后面要用到的方法:

/* 
功能: 判断是否字符串类型 
参数: 无
调用方法: 对象.isString()
NOTE: (typeof(oSource) == 'string')不能正确识别new String()产生的字符串对象
*/
String.prototype.isString = String.prototype.isString || (
    function() { 
        return ('[object String]' == Object.prototype.toString.call(this)); 
    }
);

/*
功能: 获取控件文本。
*/
function GetControlText(oSource) {
    return (oSource.innerText
    || oSource.value
    || ""); //oSource.selectorText || 
}

/*
功能: 设置控件可复制
NOTE: 选定后就可以使用Ctrl+C组合键进行复制! 但不能使用浏览器右键菜单
*/
function SetCanCopy(oSource) {
    oSource.contentEditable = true;
    oSource.disabled = false;//可能不需要修改?
}

判断是否字符串的方法抄自百度开源js库;获取控件文本可能还有其他情况没考虑到;设置控件contentEditable = true;不是一定需要,不过设置了可以使得选定控件文本的操作更加准确(在文本选定方法fnSelectText中体现),具体来说,就是双击控件(控件外部不算),选定的文本就是点击的控件的文本,而如果不设置contentEditable为true,则很大概率会选定同页面出现相同文本的第一个地方。

二、保存控件原始属性

/* 现场保存与恢复 */

/* 
临时变量, 用于保存需要复制文本的控件的原始状态 
*/
var OriginStatus = OriginStatus || { };

/*
功能: 保存控件原始状态
*/
function SaveOriginStatus(oSource) {
    //oSource.disabled = 'disabled';//禁用后不能复制
    //oSource.readOnly = true;//无效, 还是可以复制
    OriginStatus.contentEditable = oSource.contentEditable;
    OriginStatus.disabled = oSource.disabled;
}

/*
功能: 还原控件原始状态
*/
function RecoverOriginStatus(oSource) {
    oSource.contentEditable = OriginStatus.contentEditable;
    oSource.disabled = OriginStatus.disabled;
}

三、鼠标左键按住不放进行控件文本选择

/* 鼠标左键按住不放进行控件文本选择 */
var isBound = false;

document.attachEvent("onmousedown", 
function() {
    isBound = true;
});

document.attachEvent("onmouseup", 
function() {
    isBound = false;
});

方法内注册事件用attachEvent,没有考虑到非IE的情况。

四、选中要复制的控件的文本

/*
功能: 选中要复制的控件的文本。
NOTE: 方法内部是选中控件所有文本, 而非部分.
*/
function fnSelectText(oSource, e) {
    if (!oSource) return;
    
    e = e || window.event;
    e.returnValue = false;
    
    //textarea采用自身选定功能. 注意textarea不能被disabled
    if(oSource.type == "textarea") return;

    //设置为可编辑, 是为了减少findText方法选中第一个的几率
    SaveOriginStatus(oSource);
    SetCanCopy(oSource);

    var sSourceText = GetControlText(oSource);
    var caretPos = sSourceText.length; //文本长度

    if (caretPos == 0) return;

    if (oSource.createTextRange) {
        var r = oSource.createTextRange();
        r.move('character', caretPos);
        r.select();
    } else if (oSource.setSelectionRang) {
        oSource.setSelectionRange(caretPos, caretPos);
        oSource.focus();
    } else {
        //TODO: BUG, 如果页面有多个相同文本, 则会选中第一个
        var r = document.selection.createRange();//或者document.body.createTextRange();
        r.findText(sSourceText);
        //动态添加的内容, 可能会导致异常: htmlfile: Could not complete the operation due to error 800a025e.
        r.select();
    }
    RecoverOriginStatus(oSource);
}

注意:方法内部是选中控件所有文本, 而非部分。另外还有个BUG未解决:如果页面有多个相同文本, 则会选中第一个。

五、页面事件注册

//双击控件选定文本事件
document.attachEvent("ondblclick", 
function(e) {
    //模式窗口下Label控件不属于document.activeElement
    if(window.event.srcElement) {
        fnSelectText(window.event.srcElement, window.event || e);
    }
});

//鼠标左键按住移动选中事件
document.attachEvent("onmouseover", 
function(e) {
    if(!!isBound) {
        if(window.event.srcElement) {
            fnSelectText(window.event.srcElement, window.event || e);
        }
    }
});

//鼠标右键事件
//document.attachEvent("onmousedown", function(e) {
//    e = e || window.event;
//    //点击鼠标右键
//    if(e.button == 2) {
//        var oSource = window.event.srcElement;
//        if(oSource.type == "textarea") return;
//        else {
//        //请同时按下Ctrl和C组合键进行复制或者长按鼠标左键将文本拖拉到富文本编辑器中!
//            alert("请同时按下Ctrl和C组合键进行复制!");
//            //window.event.cancelBubble = true; 
//            //e.returnValue = false;
//        }
//        //createCopyTextarea(oSource);
//        //window.event.srcElement.contentEditable = true;
//    }
//});
document.attachEvent("oncontextmenu", function(e) {
    var oSource = window.event.srcElement;
    if(oSource.type == "textarea") return;
    else {
        alert("请同时按下Ctrl和C组合键进行复制!");
    }
});

将事件注册到document,而不是某个控件,主要是考虑到页面如果有多个控件的话,逐个控件注册比较麻烦。这样处理也符合用户习惯,鼠标左键选定或者双击选定文本,然后按Ctrl+C组合键复制即可。

六、使用方法

假设脚本文件名为CopyDataOnModalWindow.js,文件存放路径为"http://www.cnblogs.com/Scripts/js/CopyDataOnModalWindow.js",那么可以如下调用:

<script type="text/javascript">
if(window.document.readyState == "interactive") {
    if (!window.opener) {
        //如果是在模式窗口下, 才引用脚本
        var s = document.createElement('script');
        s.src = "http://www.cnblogs.com/Scripts/js/CopyDataOnModalWindow.js";
        s.type = "text/javascript";
        window.document.getElementsByTagName("head")[0].appendChild(s);
    } else {
    }
}
</script>

注意:我不确定 !window.opener就一定是模式窗口,如果您有判断模式窗口更好的方法,请留言告知。

这段脚本放在页面最后即可。

〇、结束语及遗留问题

脚本如此处理,可以不用污染页面,只需要复制脚本调用方法即可。遗憾的是,没有解决JavaScript操作剪贴板出现异常的问题;也没处理好一些细节。

说明:

1.textarea控件如果不是disabled状态的话,即使是readOnly,是可以选定并且浏览器右键菜单可以弹出,所以处理时排除掉textarea;如果是disabled状态的话,双击、鼠标点击事件均不会被触发,暂时没有想到有什么其他办法可以解决。

2.select控件的文本也无法选定。但select控件disabled状态下事件可以被触发。

3.选定后,无法右键弹出浏览器原生菜单;如果是自定义菜单,暂时无法解决JavaScript操作剪贴板出现异常的问题;

4.细节问题

bug: 选择控件文本, 如果页面有多处相同文本, 将会选中第一个(当然也可以复制到文本)
bug: 选定控件文本, 鼠标左键在选定区域按下后不放, 将文本拖拉到其他地方再释放, 这个时候isBound 还是 true;或者某种情形下,点击右键,移动鼠标会使得鼠标移动过的控件逐个选定文本。这个无关大雅,不过没有深入处理。

----end----

posted on 2011-02-16 23:00  jes  阅读(1375)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3