2013-09-22 49 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>

相關問題