天道酬勤,学无止境

Position cursor at start/end of Word document

We are manipulating our Word 2007 documents from .Net using Word Interop. Mostly doing stuff with fields as in:

For Each f In d.Fields
    f.Select()
    //do stuff with fields here            
Next

This leaves the last field in the document selected.

So, for the sake of neatness we would like to position the cursor at the end of the document (or even the start would be OK).

Googling for the answer doesn't throw up much ... the nearest I can get seems to be suggesting we need to involve ourselves with ranges or bookmarks. There's a GoTo method for the Document object but none of the WdGoToItem options it offers are useful.

Isn't there a simple way to just send the cursor to the end (or start) of document?

Edit

Part of my problem was I didn't like leaving the last field selected. Have now realised that I can do

f.Unlink

to remove the mergefield and just leave the field text there as plain text. Which is neater, whether or not we also reposition the cursor

评论

@Alexander Kojevnikov: Thanks for your help because you put me on the right track. However I found I had to apply the .GoTo to the Word Selection object, not the Document. As in:

    Dim what As Object = Word.WdGoToItem.wdGoToLine
    Dim which As Object = Word.WdGoToDirection.wdGoToLast

    //below line had no effect
    //d.GoTo(what, which, Nothing, Nothing)

    w.Selection.GoTo(what, which, Nothing, Nothing)

This is how it looks in C#:

object missing = Missing.Value;
object what = Word.WdGoToItem.wdGoToLine;
object which = Word.WdGoToDirection.wdGoToLast;
doc.GoTo(ref what, ref which, ref missing, ref missing);

I guess it will be even easier in VB.Net as it supports optional parameters.

I'm not sure I'm using the same environment as you, but to go to the start or end of the document here's what works for me:

Private Sub moveCursorToStartOfDocument()
    w.Selection.HomeKey(WdUnits.wdStory, Nothing)
End Sub

Private Sub moveCursorToEndOfDocument()
    w.Selection.EndKey(WdUnits.wdStory, Nothing)
End Sub

I use unit Word_TLB in Delphi with Appliction object- Word.Application

as following:

aWordDoc.Application.Selection.EndKey(wdStory,wdMove);

generally end of word document is:

Selection.EndKey( WdUnits.wdStory, WdMovementType.wdMove)

When I use

Selection.GoTo(Word.WdGoToItem.wdGoToLine, Word.WdGoToDirection.wdGoToLast, Nothing, Nothing);
Selection.InsertFile('documnet.docx');

new content was insert before last line.

The easiest way to figure out an outline for the actual code is to record a macro in Word for that specific action. Then you can modify the generated code to suit different syntax(s) of VB, VB.NET, C# etc.

The code snippet below demonstrates the usage for a VB.NET application:

Imports wordNmSpace = Microsoft.Office.Interop.Word
' Create an object for the application instance
objWord = CreateObject("Word.Application")

' Create a reference of the selection object within Word
objSelection = objWord.Selection

' Now comes the part where you move selection position to the end of document
objSelection.endof(wordNmSpace.WdUnits.wdStory, wordNmSpace.WdMovementType.wdMove)

Hope this helps.

To change cursor position at the end of the current document in a C# Word Add-In VSTO :

this.Application.ActiveDocument.Range(
this.Application.ActiveDocument.Content.End-1,
this.Application.ActiveDocument.Content.End-1).Select();

See How to: Programmatically Define and Select Ranges in Documents

Try this :

int lNumberOfPages = 
  _WordDoc.ComputeStatistics(Word.WdStatistic.wdStatisticPages, false);

WordApp.Selection.GoTo(Word.WdGoToItem.wdGoToPage,WordApp.WdGoToDirection.wdGoToLast, lNumberOfPages);

You can use the predefined bookmark:

EndOfDoc oDoc.Bookmarks.Item("\endofdoc").Range

Other predefined bookmarks:

ActiveDocument.Bookmarks("\Para").Copy "currpara"

https://msdn.microsoft.com/en-us/VBA/Word-VBA/articles/predefined-bookmarks

for net office:

mydoc.Range(GlobalClass.mydoc.Content.End-1 , mydoc.Content.End - 1).Select();

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 工具之_vim
    编辑器vim语法:vim [option]... file...1)打开文件,让光标处于第#行;+默认行尾vim +2 /etc/passwd #打开文件,光标处于第2行2)让光标处于第一个被PATTERN匹配到的行的行首+ /PATTERN3)二进制打开文件-b file4)比较多个文件-d file1 file2 ...5)只读方式打开文件-m file6)直接进入ex模式vim -e file 或ex filevim:一个模式的编辑器 -------------命令模式下跳转-------------字符跳转h[←] j[↓] k[↑] l[→]#command 跳转由#指定的个数的字符单词跳转w 下一个单词的词首e 当前或下一个单词词尾 [end]b 当前或前一个单词的词首 [before]#command 由#指定一次跳转的单词数当前页跳转H 页首 M 页中 L 页底zt 光标所在行移到屏幕顶端zz 光标所在行移到屏幕中间zb 光标所在行移到屏幕底端行首行尾跳转^ 行首第一个非空白字符0 行首 $ 行尾行间移动#G 跳转至第#行尾;同ex模式下的":#"G 最后一行1G/gg 第一行句间移动(句子是以"."隔开的)) 下一句( 上一句段落间移动(有空行就算段落)} 下一段{ 上一段翻屏ctrl+f 向尾部翻一屏ctrl+b 向首部翻一屏ctrl+d 向尾部翻半屏ctrl
  • Javascript Contenteditable-将Cursor / Caret设置为索引(Javascript Contenteditable - set Cursor / Caret to index)
    问题 我该如何修改它(如何在contenteditable元素(div)中设置插入符(光标)的位置?),使其接受数字索引和元素,并将光标位置设置为该索引? 例如:如果我有以下段落: <p contenteditable="true">This is a paragraph.</p> 我打电话给: setCaret($(this).get(0), 3) 光标将移动到索引3,如下所示: Thi|s is a paragraph. 我有这个,但是没有运气: function setCaret(contentEditableElement, index) { var range,selection; if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+ { range = document.createRange();//Create a range (a range is a like the selection but invisible) range.setStart(contentEditableElement,index); range.collapse(true); selection = window.getSelection();//get the selection object (allows
  • 如何在contenteditable元素(div)中设置插入符(光标)的位置?(How to set caret(cursor) position in contenteditable element (div)?)
    问题 我以这个简单的HTML为例: <div id="editable" contenteditable="true"> text text text<br> text text text<br> text text text<br> </div> <button id="button">focus</button> 我想要简单的事情-单击按钮时,我想将插入符号(光标)放入可编辑div中的特定位置。 通过网络搜索,我将这个JS附加到了按钮点击上,但是它不起作用(FF,Chrome): var range = document.createRange(); var myDiv = document.getElementById("editable"); range.setStart(myDiv, 5); range.setEnd(myDiv, 5); 是否可以像这样手动设置插入符号的位置? 回答1 在大多数浏览器中,您需要Range和Selection对象。 您可以将每个选择边界指定为一个节点,并在该节点内指定一个偏移量。 例如,要将插入符号设置为文本第二行的第五个字符,请执行以下操作: function setCaret() { var el = document.getElementById("editable") var range = document.createRange
  • 如何在当前光标位置的文本区域中插入文本?(How to insert text into the textarea at the current cursor position?)
    问题 我想创建一个简单的函数,将文本添加到用户光标位置的文本区域中。 它必须是一个干净的功能。 只是基础。 我能找出其余的。 回答1 使用输入元素的selectionStart / selectionEnd属性(也适用于<textarea> ) function insertAtCursor(myField, myValue) { //IE support if (document.selection) { myField.focus(); sel = document.selection.createRange(); sel.text = myValue; } //MOZILLA and others else if (myField.selectionStart || myField.selectionStart == '0') { var startPos = myField.selectionStart; var endPos = myField.selectionEnd; myField.value = myField.value.substring(0, startPos) + myValue + myField.value.substring(endPos, myField.value.length); } else { myField.value +=
  • 获取文本输入字段中的光标位置(以字符为单位)(Get cursor position (in characters) within a text Input field)
    问题 如何从输入字段中获得插入符的位置? 我已经通过Google找到了一些零散的信息,但没有任何防弹证据。 基本上像jQuery插件之类的东西是理想的,所以我可以简单地做 $("#myinput").caretPosition() 回答1 更容易的更新: 在此答案中使用field.selectionStart示例。 感谢@commonSenseCode指出了这一点。 旧答案: 找到了这个解决方案。 不是基于jquery的,但是将其集成到jquery中没有问题: /* ** Returns the caret (cursor) position of the specified text field (oField). ** Return value range is 0-oField.value.length. */ function doGetCaretPosition (oField) { // Initialize var iCaretPos = 0; // IE Support if (document.selection) { // Set focus on the element oField.focus(); // To get cursor position, get empty selection range var oSel = document
  • 在vi中快速缩进多行(Indent multiple lines quickly in vi)
    问题 它应该是微不足道的,甚至可能在帮助中,但是我不知道如何导航。 如何在vi中快速缩进多行? 回答1 使用>命令。 到缩进五线,5>>。 要标记一行并缩进,可使用V j j >缩进三行(仅Vim)。 要缩进大括号块,请将光标放在大括号之一上,然后使用> %或在block use > i B中的任何位置。 如果要在周围复制文本块,并且需要在新位置对齐块的缩进,请使用] p而不是p 。 这会将粘贴的块与周围的文本对齐。 另外,shiftwidth设置使您可以控制缩进多少空格。 回答2 该答案总结了该问题的其他答案和评论,并基于Vim文档和Vim Wiki添加了更多信息。 为简洁起见,此答案不能区分Vi和Vim特定的命令。 在下面的命令中,“重新缩进”表示“根据缩进设置缩进行”。 shiftwidth是控制缩进的主要变量。 通用命令 >> Indent line by shiftwidth spaces << De-indent line by shiftwidth spaces 5>> Indent 5 lines 5== Re-indent 5 lines >% Increase indent of a braced or bracketed block (place cursor on brace first) =% Reindent a braced or bracketed
  • 在Textarea中光标位置处显示DIV [重复](Display DIV at Cursor Position in Textarea [duplicate])
    问题 这个问题已经在这里有了答案: 如何在文本框中获取插入符号的(x,y)像素坐标? (3个答案) 7年前关闭。 对于我的一个项目,我很乐意为特定的textarea提供自动完成功能。 类似于智能感知/全残式的工作原理。 但是为此,我必须找出绝对光标位置,以便知道DIV应该出现的位置。 事实证明:(几乎希望如此)这是不可能实现的。 有谁有一些巧妙的想法如何解决这个问题? 回答1 我的Hacky实验版本2 此新版本适用于可以根据需要进行调整的任何字体以及任何textarea大小。 在注意到某些人仍在尝试使此方法起作用之后,我决定尝试一种新方法。 这次我的结果更好-至少在Linux上的Google chrome上。 我不再有Windows PC可用,因此我只能在Ubuntu上的chrome / firefox上进行测试。 我的结果在Chrome上可以始终保持100%的效果,而在Firefox上可以达到70-80%左右,但是我不认为很难找到不一致之处。 此新版本依赖于Canvas对象。 在我的示例中,我实际上展示了非常画布-就像您可以在实际中看到它一样,但是可以使用隐藏的画布对象很容易地完成它。 当然,这肯定是一种hack,对于那些我认为相当混乱的代码,我会提前表示歉意。 至少在Google chrome中,无论我设置为哪种字体或textarea的大小,它都能始终如一地工作。 我使用了萨姆
  • 将光标设置到CKEditor中的特定位置(Set cursor to specific position in CKEditor)
    问题 有没有一种方法可以将光标位置设置为CKEditor中的已知索引? 我想这样做是因为当我在编辑器中更改html时,它会将光标重置为插入元素的开头,这是一个问题,因为我随用户输入而即时更改内容。 如果我知道我想将光标设置回已知的字符位置,例如在编辑器中为100,这可能吗? (我问了一个相关的问题,但我想我用示例代码使问题复杂化了。) 回答1 设置选择的基本方法是创建一个范围,设置其位置并选择它。 注意:如果您不知道Range API(或者至少不了解Range背后的想法),则将无法使用选择。 这是一个很好的介绍-DOM Range规范(是的,这是一个规范,但是很好)。 CKEditor的Range API非常相似,但稍大一些。 例如: // Having this HTML in editor: // <p id="someId1">foo <em id="someId2">bar</em>.</p> var range = editor.createRange(); range.setStart( editor.document.getById( 'someId1' ), 0 ); // <p>^foo range.setEnd( editor.document.getById( 'someId2' ).getFirst(), 1 ); // <em>b^ar</em>
  • jQuery在文本区域中设置光标位置(jQuery Set Cursor Position in Text Area)
    问题 如何使用jQuery在文本字段中设置光标位置? 我有一个带有内容的文本字段,并且我希望用户将光标放在该字段上时将光标定位在某个偏移量处。 该代码应该看起来像这样: $('#input').focus(function() { $(this).setCursorPosition(4); }); 该setCursorPosition函数的实现是什么样的? 如果您的文本字段的内容为abcdefg,则此调用将导致光标的定位如下:abcd ** | ** efg。 Java具有类似的功能setCaretPosition。 javascript是否存在类似的方法? 更新:我修改了CMS的代码以与jQuery配合使用,如下所示: new function($) { $.fn.setCursorPosition = function(pos) { if (this.setSelectionRange) { this.setSelectionRange(pos, pos); } else if (this.createTextRange) { var range = this.createTextRange(); range.collapse(true); if(pos < 0) { pos = $(this).val().length + pos; } range.moveEnd(
  • 获取contentEditable插入符号索引位置(Get contentEditable caret index position)
    问题 我在如何设置contentEditable元素中的光标或插入符号索引位置方面找到了很多很好的,跨浏览器的答案,但是却没有关于如何获取或找到其索引的答案... 我想做的是知道keyup上该div内插入符号的索引。 因此,当用户键入文本时,我随时可以知道它在contentEditable元素内的光标索引。 编辑:我正在寻找div内容(文本)内的索引,而不是光标坐标。 <div id="contentBox" contentEditable="true"></div> $('#contentbox').keyup(function() { // ... ? }); 回答1 以下代码假定: 在可编辑的<div>始终只有一个文本节点,而没有其他节点可编辑的div没有将CSS white-space属性设置为pre 如果您需要更通用的方法来处理带有嵌套元素的内容,请尝试以下答案: https://stackoverflow.com/a/4812022/96100 代码: function getCaretPosition(editableDiv) { var caretPos = 0, sel, range; if (window.getSelection) { sel = window.getSelection(); if (sel.rangeCount) { range = sel
  • 如何从加载项轮询Google文档(How to poll a Google Doc from an add-on)
    问题 文档和工作表加载项的有据记录的限制是,Apps Script无法告知用户在加载项之外的操作。 这个诱人的提示是: 可以从侧边栏的客户端代码中查询文件内容中的更改,尽管您总是会稍有延迟。 该技术还可以提醒您的脚本用户的所选单元格(在工作表中)和光标或选择项(在文档中)的变化。 遗憾的是,任何演示代码都未显示此内容。 我该怎么做? 回答1 轮询是通过插件的用户界面中的html代码完成的,并使用google.script.run调用服务器端的Apps Script函数。 使用jQuery可以简化这一过程,我们甚至可以从简单轮询示例jQuery的答案开始。 function doPoll(){ $.post('ajax/test.html', function(data) { alert(data); // process results here setTimeout(doPoll,5000); }); } 如果我们将ajax调用替换为GAS等效项,则该基本思想适用于Google Apps脚本。 这是您将在html文件中使用的poll函数的框架: /** * On document load, assign click handlers to button(s), add * elements that should start hidden (avoids "flashing")
  • 获取文本区域中插入符号的偏移位置(以像素为单位)(Get the offset position of the caret in a textarea in pixels [duplicate])
    问题 这个问题已经在这里有了答案: 如何在文本框中获取插入符号的(x,y)像素坐标? (3个答案) 7年前关闭。 在我的项目中,我试图获取插入符号在textarea中的偏移位置(以像素为单位)。 能做到吗? 在这里问之前,我已经遍历了许多链接,尤其是Tim Down的链接,但是我找不到能在IE8 +,Chrome和Firefox中使用的解决方案。 蒂姆·唐(Tim Down)似乎正在为此工作。 我发现的其他一些链接有很多问题,例如找不到插入符位置的顶部偏移。 我试图获取插入符的偏移位置,因为我想展现内部的自动完成建议框textarea通过定位它的基础上插入符的偏移位置。 PS:我无法使用contenteditable div因为我编写了很多与textarea相关的代码。 回答1 这是一种使用rangyinputs,rangy和jQuery的方法。 它基本上将整个文本从文textarea复制到相同大小的div中。 我设置了一些CSS,以确保在每个浏览器中, textarea和div以完全相同的方式包装其内容。 单击textarea ,我读出插入符位于哪个字符索引,然后在div内的相同索引处插入一个插入符span 。 通过这样做,如果用户单击行的开头,插入符号span跳回到上一行,因此我最终遇到了问题。 为了解决这一问题,我检查了前一个字符是否为space (这将允许换行)
  • 有没有一种方法可以始终将Google Maps Marker固定到其地图中心?(Is there a way to Fix a Google Maps Marker to the Center of its Map always?)
    问题 更确切地说,我要尝试完成的工作是,当我拖动Google Map时,有一个Google Maps Marker始终保持固定在地图中心。 我认为这将改善用户体验,这就是我现在的做法: var map, marker, options; options = { center: new google.maps.LatLng(latitude, longitude), zoom: 15, mapTypeId: google.maps.MapTypeId.ROADMAP, mapTypeControl: false, overviewMapControl: false, zoomControl: true, draggable: true }; map = new google.maps.Map(mapContainer, options); marker = new google.maps.Marker({ position: new google.maps.LatLng(latitude, longitude), map: map, animation: google.maps.Animation.DROP }); //This line is what makes the Marker stick to the center of the map marker.bindTo(
  • How to fix ''UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d in position 29815: character maps to <undefined>''?
    At the moment, I am trying to get a Python 3 program to do some manipulations with a text file filled with information, through the Spyder IDE/GUI. However, when trying to read the file I get the following error: File "<ipython-input-13-d81e1333b8cd>", line 77, in <module> parser(f) File "<ipython-input-13-d81e1333b8cd>", line 18, in parser data = infile.read() File "C:\ProgramData\Anaconda3\lib\encodings\cp1252.py", line 23, in decode return codecs.charmap_decode(input,self.errors,decoding_table)[0] UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d in position 29815: character maps
  • 如何在AngularJS的输入字段中自动大写第一个字符?(How to autocapitalize the first character in an input field in AngularJS?)
    问题 如何在AngularJS表单元素内的输入字段中自动大写第一个字符? 我已经看到了jQuery解决方案,但相信在AngularJS中必须使用指令来完成此操作。 回答1 是的,您需要定义一个指令并定义自己的解析器函数: myApp.directive('capitalizeFirst', function($parse) { return { require: 'ngModel', link: function(scope, element, attrs, modelCtrl) { var capitalize = function(inputValue) { if (inputValue === undefined) { inputValue = ''; } var capitalized = inputValue.charAt(0).toUpperCase() + inputValue.substring(1); if(capitalized !== inputValue) { modelCtrl.$setViewValue(capitalized); modelCtrl.$render(); } return capitalized; } modelCtrl.$parsers.push(capitalize); capitalize($parse(attrs.ngModel
  • 修剪字符串中的特定字符(Trim specific character from a string)
    问题 与此C#方法等效的JavaScript是什么: var x = "|f|oo||"; var y = x.Trim('|'); // "f|oo" C#仅在字符串的开头和结尾处修剪所选字符! 回答1 一行就足够了: var x = '|f|oo||'; var y = x.replace(/^\|+|\|+$/g, ''); document.write(x + '<br />' + y); ^\|+ beginning of the string, pipe, one or more times | or \|+$ pipe, one or more times, end of the string 通用解决方案: function trim (s, c) { if (c === "]") c = "\\]"; if (c === "^") c = "\\^"; if (c === "\\") c = "\\\\"; return s.replace(new RegExp( "^[" + c + "]+|[" + c + "]+$", "g" ), ""); } chars = ".|]\\^"; for (c of chars) { s = c + "foo" + c + c + "oo" + c + c + c; console.log(s, "->", trim(s
  • 将光标设置为文本框焦点的长度为14(Set cursor at a length of 14 onfocus of a textbox)
    问题 Hai Guys,我想将光标设置在文本框上长度为14的位置,该位置将没有值。.我知道最初的光标将是0,但我希望它是14 回答1 IE在设置光标位置时使用的方法与Firefox,Opera和Chrome不同。 最好创建一个辅助函数,它将为您完成。 我将其用于自己的需求。 function setCursor(node,pos){ node = (typeof node == "string" || node instanceof String) ? document.getElementById(node) : node; if(!node){ return false; }else if(node.createTextRange){ var textRange = node.createTextRange(); textRange.collapse(true); textRange.moveEnd(pos); textRange.moveStart(pos); textRange.select(); return true; }else if(node.setSelectionRange){ node.setSelectionRange(pos,pos); return true; } return false; } 最后一件事是从onfocus处理程序中调用它。 祝你好运
  • 颠倒字符串中单词的顺序(Reverse the ordering of words in a string)
    问题 我有这个string s1 = "My name is XYZ" ,我想颠倒单词的顺序,以便s1 = "ZYX is name My" 。 我可以使用其他数组来做到这一点。 我想了很辛苦,但是有可能做到这一点(不使用其他数据结构)并且时间复杂度为O(n)吗? 回答1 颠倒整个字符串,然后颠倒每个单词的字母。 第一次通过后,字符串将是 s1 = "Z Y X si eman yM" 在第二遍之后 s1 = "Z Y X is name My" 回答2 反转字符串,然后在第二遍,反转每个单词... 在c#中,完全就位,而没有其他数组: static char[] ReverseAllWords(char[] in_text) { int lindex = 0; int rindex = in_text.Length - 1; if (rindex > 1) { //reverse complete phrase in_text = ReverseString(in_text, 0, rindex); //reverse each word in resultant reversed phrase for (rindex = 0; rindex <= in_text.Length; rindex++) { if (rindex == in_text.Length || in
  • Swing JTextArea上的文本鼠标悬停弹出窗口?(Text-mouseover popups over a Swing JTextArea?)
    问题 是否有任何东西可以让您在Swing JTextArea中的单个单词或字母上显示一个小的文本弹出窗口(如工具提示)? (或具有类似功能的JTextArea替代品。) 我需要的行为就像一个工具提示,换句话说,只有在鼠标悬停在单词上一两秒钟之后,才会显示弹出文本,并且一旦鼠标移开它就会自动消失。 当然,这里最棘手的部分是我希望它在文本中的字符/单词级别,而不是组件级别……有什么建议吗? 回答1 您可以根据需要重写getToolTipText(Mouse Event event)。 附录:JTextComponent是JTextArea的父级,它通过两种方法提供位置信息:modelToView()和viewToModel()。 后者应让您将鼠标位置转换为文档偏移量。 回答2 可能是 import java.awt.*; import java.awt.event.*; import java.awt.font.*; import java.awt.geom.*; import javax.swing.*; import java.util.*; import javax.swing.event.*; public class SimplePaintSurface implements Runnable, ActionListener { private static final
  • 获取选定的文本位置并在其旁边放置一个元素(Get selected text position and place an element next to it)
    问题 tl; dr 想法是允许用户标记任何文本,并在所选内容旁边看到菜单弹出窗口,并可以执行适用于所选文本的操作。 我需要在用户选择的文本旁边放置一个绝对定位的按钮。 我正在将mouseup事件绑定到文档,并获取选定的文本,但是我目前对如何知道实际选择项的位置没有任何想法,而无需将其包装在某些元素中,因为文本的选择范围很广几个元素,如果我将它包装起来,它将使结构混乱。 回答1 您可以将标记范围放置在选择的末尾,使用jQuery获取其坐标,将按钮放置在这些坐标处并删除标记范围。 以下内容将帮助您入门: var markSelection = (function() { var markerTextChar = "\ufeff"; var markerTextCharEntity = ""; var markerEl, markerId = "sel_" + new Date().getTime() + "_" + Math.random().toString().substr(2); var selectionEl; return function(win) { win = win || window; var doc = win.document; var sel, range; // Branch for IE <= 8 if (doc.selection && doc