2013-09-22 48 views
17

我对html和javascript有困难。 我的html页面允许用户选择文本并用颜色突出显示它。现在我想将状态保存到数据库中,以便稍后为该用户显示。当然,我可以在用户编辑后保存整个html。但我只想保存一些参数,并结合原始html来显示状态用户上次看到的页面。我们可以使用此功能:保存选择文本,稍后在html和javascript中显示它

var index = innerHTML.indexOf(text); 

突出显示该索引处的文本。但是如果页面中有许多相同的文本,我想要突出显示用户之前突出显示的字词。

任何人都可以指导我如何用javascript做到这一点?

我非常感谢您的帮助。

+1

你为什么不救突出显示的单词的数组索引,并且它们的长度? –

+0

我同意@mohammedessam,创建一个数组,以便突出'xyz'的用户将数组添加'xyz',并且还会包含一个索引来指示'xyz'的具体实例是什么(即如果它是第3个'xyz'的实例,那么索引将是3. – tamak

+0

我怀疑'innerHTML.indexOf(text)'会传递任何东西,更不用说索引了。'ReferenceError'更可能。 – KooiInc

回答

0

您可以使用Array来保存用户的选择!之后你将整个数组保存到数据库中!并且当用户再次查看站点时,函数会比较数组中的字母和单词并将其突出显示。

+2

是的。而且*如何做到这一点*,我怀疑是问题所在。 –

+0

@DavidThomas问题在于OP没有提到他管理应用程序突出显示功能的方式,只有他知道如何实现它! –

+0

选择开始时使用mousedown()以及最终选择mouseup()并将选定文本保存在数组中时,javascript中的mousedown()和mouseup()事件! – UserOnE

0

可以使用.serialize()方法,该方法以标准URL编码表示法返回文本字符串。它已经选择了单个表单元素,例如<input>, <textarea>等。因此,在数据库中使用$(form).serialize();推送序列化的返回字符串,并用于突出显示更改,使用新的$(form).serialize();返回值检查旧的$(form).serialize();返回值。

2

您需要捕获节点的路径以了解其位置。
这可以通过几种方式完成。
最简单的方法是遍历直到主体并创建一个选择器。

function getPathFromElement(element) { 
    var stack = []; 

    while (element.parentNode != document.documentElement) { 
     var sibCount = 0; 
     var sibIndex = 0; 
     var childNodes = element.parentNode.childNodes; 
     var childLength = childNodes.length; 

     for (var i = 0; i < childLength; i++) { 
      var sib = childNodes[i]; 

      if (sib.nodeName == element.nodeName) { 
       if (sib === element) { 
        sibIndex = sibCount; 
       } 

       sibCount++; 
      } 
     } 

     if (element.hasAttribute("id") && element.id !== "") { 
      stack.unshift(`${element.nodeName.toLowerCase()}#${element.id}`); 
     } 
     else if (sibCount > 1) { 
      stack.unshift(`${element.nodeName.toLowerCase()}:eq(${sibIndex})`); 
     } 
     else { 
      stack.unshift(element.nodeName.toLowerCase()); 
     } 

     element = element.parentNode; 
    } 

    return stack.join(" > ") 
} 

让我们假设您想给您的用户两个选择文本的选项。

  1. 简单的文字在页面中。
  2. 在输入文本或textarea中选择文本。

对于第一个选项,您可以使用带有点击处理程序或mouseup事件的按钮。
为简单起见,我将使用按钮。

function sendDataToServer(data) { 
} 

document.querySelector("#button").addEventListener("click", function (e) { 
    var { target, text } = getSelectionTextAndContainerElement(); 

    var path = getPathFromElement(target); 

    sendDataToServer({ 
     path: path, 
     text: text 
    }); 
}); 

getSelectionTextAndContainerElement function basicaly选择文本和元素。

function getSelectionTextAndContainerElement() { 
    var text; 
    var containerElement = null; 

    if (typeof window.getSelection !== "undefined") { 
     var selection = window.getSelection(); 

     if (selection.rangeCount) { 
      var node = selection.getRangeAt(0).commonAncestorContainer; 
      containerElement = node.nodeType == 1 ? node : node.parentNode; 
      text = selection.toString(); 
     } 
    } 
    else if (typeof document.selection !== "undefined" && document.selection.type !== "Control") { 
     var textRange = document.selection.createRange(); 

     containerElement = textRange.parentElement(); 
     text = textRange.text; 
    } 

    return { 
     text: text, 
     target: containerElement 
    }; 
} 

对于第二个选项,您可以使用select事件处理程序。

document.addEventListener("select", onSelect, false); 

function onSelect(e) { 
    var { text } = getSelectionTextAndContainerElement(); 
    var path = getPathFromElement(e.target); 

    sendDataToServer({ 
     path: path, 
     text: text 
    });  
} 

对于输入文本或文本域它能够更好地使用select事件处理程序。
如果您将使用第一个选项来获取选择,您将无法获得正确的目标节点,因为输入文本和textarea使用Shadow DOM构建。
因此,最好忽略从getSelectionTextAndContainerElement函数重新构造的目标节点,并使用select事件的目标属性。

我为jsfiddle创建了一个示例。

+0

您的jsfiddle工作得很好。但我注意到,如果我选择12,然后尝试选择23它无法将选择扩展到123.对此的任何想法? – xeo

+0

请注意,数字选择不是文本选择,而是使用与选区颜色相同的跨度对选定文本进行包装。我并没有试图创建整个解决方案,因为这不是问题,而是要举例说明可以从元素中获取选择和路径。为了完成文本选择,你可以在这里阅读:https://developer.mozilla.org/en-US/docs/Web/API/Selection。 – Sagi

0

从测试的角度来看,如果可以在不调整亮点的情况下更改原始html,则无法存储分离的亮点。

我的解决方案是序列化整个彩色html。然后创建一个清理函数来删除所有颜色高亮并返回基准html。这允许db中的html包含颜色突出显示,并且仍然可以在高亮显示保留的情况下进行编辑。

类似:

function unhighlight() { 
    $('.highlighted').each(function(index, el) { 
    $(el).replaceWith($(el).html()); 
    }); 
} 

的jsfiddle:https://jsfiddle.net/tobtedsc/5/

6

Range对象和document.execCommand可以操作的选择很容易地。你的情况的主要问题是以文本格式保存范围对象。

基本上你需要的是获得startContainer,startOffset,endContainerendOffset,它们是创建Range对象所需的值。 Offsets是数字,所以它非常简单。容器是节点,你不能直接保存为字符串,所以这是主要问题。你可以做的一件事是添加键到你的DOM并保存密钥。但是,由于范围容器是文本节点,因此您需要保存文本节点的索引。这样的事情应该让来标记键的DOM,使用递归函数:

function addKey(element) { 
    if (element.children.length > 0) { 
    Array.prototype.forEach.call(element.children, function(each, i) { 
     each.dataset.key = key++; 
     addKey(each) 
    }); 
    } 
}; 

addKey(document.body); 

一旦做到这一点,你可以范围对象转换为一个对象,你可以保存为一个字符串。像这样:

function rangeToObj(range) { 
    return { 
    startKey: range.startContainer.parentNode.dataset.key, 
    startTextIndex: Array.prototype.indexOf.call(range.startContainer.parentNode.childNodes, range.startContainer), 
    endKey: range.endContainer.parentNode.dataset.key, 
    endTextIndex: Array.prototype.indexOf.call(range.endContainer.parentNode.childNodes, range.endContainer), 
    startOffset: range.startOffset, 
    endOffset: range.endOffset 
    } 
} 

使用此功能,您可以将用户创建的每个选择保存到数组中。像这样:

document.getElementById('textToSelect').addEventListener('mouseup', function(e) { 
    if (confirm('highlight?')) { 
    var range = document.getSelection().getRangeAt(0); 
    selectArray.push(rangeToObj(range)); 
    document.execCommand('hiliteColor', false, 'yellow') 
    } 
}); 

要保存高亮区,请将每个对象保存为JSON。为了测试这个,你可以从你的范围对象数组中获取JSON字符串。像这样的(这是在顶部使用get Seletion按钮):

document.getElementById('getSelectionString').addEventListener('click', function() { 
    alert('Copy string to save selections: ' + JSON.stringify(selectArray)); 
}); 

然后装入空的HTML时,您可以使用,这将创建一个从你的JSON保存的对象范围内的逆转。像这样:

function objToRange(rangeStr) { 
    range = document.createRange(); 
    range.setStart(document.querySelector('[data-key="' + rangeStr.startKey + '"]').childNodes[rangeStr.startTextIndex], rangeStr.startOffset); 
    range.setEnd(document.querySelector('[data-key="' + rangeStr.endKey + '"]').childNodes[rangeStr.endTextIndex], rangeStr.endOffset); 
    return range; 
} 

因此,您可以将字符串中的范围数组转换为对象,然后将其转换为可添加的Range对象。然后使用execCommand,设置一些格式。

document.getElementById('setSelection').addEventListener('click', function() { 
    var selStr = prompt('Paste string'); 
    var selArr = JSON.parse(selStr); 
    var sel = getSelection(); 
    selArr.forEach(function(each) { 
    sel.removeAllRanges(); 
    sel.addRange(objToRange(each)); 
    document.execCommand('hiliteColor', false, 'yellow') 
    }) 
}); 

参见:https://jsfiddle.net/sek4tr2f/3/

注意,有些情况下,这将无法正常工作的情况下,主要是这样的(这是在顶部使用组选择按钮,刷新小提琴之后做到这一点)有问题的情况是用户在已经突出显示的内容中选择了内容。这些情况可以处理,但您需要更多条件。

1

我的想法是在选定文本的开始和结尾添加<span >,之后保存文档整个html保存到数据库中,因此当他检索记录时,高亮显示的文本将保留。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<p>this is a paragraph creted to demonstrate highlighting selected text</p> 
 
<script> 
 
$(document).ready(function(){ 
 

 
$("p").on("mouseup",function() { 
 
    oldtxt = chosenText(); 
 
    
 
     var newtxt = '<span style="color:red;">' + oldtxt +'</span>'; 
 
$(this).html($(this).html().replace(oldtxt,newtxt)); 
 
    
 
}); 
 

 
//Grab selected text 
 
function chosenText(){ 
 
    if(window.getSelection){ 
 
     return window.getSelection().toString(); 
 
    } 
 
    else if(document.getSelection){ 
 
     return document.getSelection(); 
 
    } 
 
    else if(document.selection){ 
 
     return document.selection.createRange().text; 
 
    } 
 
} 
 
}); 
 
</script>

这将是舒服的jQuery因为你使用插件的文本高亮添加元素

+0

,因为我们不知道op的上下文 - 如果有多个用户在同一页面上这样做,那么可能会导致在您的html中的span色拉...... – errand

+0

@errand是的,但是,您可以保存在数据库中以供不同的用户使用。为每个用户显示正确的页面 –

1

,使用得到强调的话jQuery的:

var words = $('.highlight').map(function() { return $(this).text(); }); 

然后把它们放在一个阵列中

var saved = [ ]; 
for (var word in words) { 
    if (-1 === saved.indexOf(word)) { 
     saved.push(word); 
    } 
} 

最后,您可以将它们保存在数据库中。一个坏的(但快)的方式来做到这一点是保存列表作为逗号分隔,著名SQL antipattern

var wordList = saved.join(','); 

当你获得这个价值,你把它分解成单词,每个单词调用亮点插件。

如果任何文本包含逗号,这将不起作用。在这种情况下,您最好单独保存每个单词,这最终可以节省几个其他麻烦,而不是找出在用户文本中不太可能弹出的分隔字符。

1

第一示例:

<textarea id="quote" cols="50" rows="5"> 
 
The above properties are especially useful in getting any user selected text from a form field where the indices of the selection isn't already known. The following demo echoes what the user has selected from a TEXTAREA using these properties: 
 
</textarea> 
 
    
 
<div id="output"></div> 
 
    
 
<script> 
 
    
 
var quotearea = document.getElementById('quote') 
 
var output = document.getElementById('output') 
 
quotearea.addEventListener('mouseup', function(){ 
 
    if (this.selectionStart != this.selectionEnd){ // check the user has selected some text inside field 
 
     var selectedtext = this.value.substring(this.selectionStart, this.selectionEnd) 
 
     output.innerHTML = selectedtext 
 
    } 
 
}, false) 
 
    
 
</script>

第二示例

<head> 
 
    <script type="text/javascript"> 
 
     function GetSelectedText() { 
 
      var selText = ""; 
 
      if (window.getSelection) { // all browsers, except IE before version 9 
 
       if (document.activeElement && 
 
         (document.activeElement.tagName.toLowerCase() == "textarea" || 
 
         document.activeElement.tagName.toLowerCase() == "input")) 
 
       { 
 
        var text = document.activeElement.value; 
 
        selText = text.substring (document.activeElement.selectionStart, 
 
               document.activeElement.selectionEnd); 
 
       } 
 
       else { 
 
        var selRange = window.getSelection(); 
 
        selText = selRange.toString(); 
 
       } 
 
      } 
 
      else { 
 
       if (document.selection.createRange) {  // Internet Explorer 
 
        var range = document.selection.createRange(); 
 
        selText = range.text; 
 
       } 
 
      } 
 
      if (selText !== "") { 
 
       alert (selText); 
 
      } 
 
     } 
 
    </script> 
 
</head> 
 
<body onmouseup="GetSelectedText()"> 
 
    Some text for selection. 
 
    <br /><br /> 
 
    <textarea>Some text in a textarea element.</textarea> 
 
    <input type="text" value="Some text in an input field." size="40"/> 
 
    <br /><br /> 
 
    Select some content on this page! 
 
</body>

第三个例子:

<head> 
 
    <script type="text/javascript"> 
 
     function GetSelection() { 
 
      var selection = ""; 
 

 
      var textarea = document.getElementById("myArea"); 
 
      if ('selectionStart' in textarea) { 
 
        // check whether some text is selected in the textarea 
 
       if (textarea.selectionStart != textarea.selectionEnd) { 
 
        selection = textarea.value.substring (textarea.selectionStart, textarea.selectionEnd); 
 
       } 
 
      } 
 
      else { // Internet Explorer before version 9 
 
        // create a range from the current selection 
 
       var textRange = document.selection.createRange(); 
 
        // check whether the selection is within the textarea 
 
       var rangeParent = textRange.parentElement(); 
 
       if (rangeParent === textarea) { 
 
        selection = textRange.text; 
 

 
       } 
 
      } 
 

 
      if (selection == "") { 
 
       alert ("No text is selected."); 
 
      } 
 
      else { 
 
       alert ("The current selection is: " + selection); 
 
      } 
 
     } 
 
    </script> 
 
</head> 
 
<body> 
 
    <textarea id="myArea" spellcheck="false">Select some text within this field.</textarea> 
 
    <button onclick="GetSelection()">Get the current selection</button> 
 
</body>

相关问题