[JavaScript]模式窗口只读状态下复制控件文本
模式窗口只读状态下要进行复制很麻烦,无法选定文本也无法进行复制、编辑、右键浏览器菜单。本文提供一种解决这个问题的方法:使用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----