2013-09-22 16 views
17

私はhtmlとjavascriptで難しい状況に陥っています。 私のHTMLページでは、テキストを選択して色で強調表示できます。今度は、状態をデータベースに保存して、後でそのユーザーに表示する必要があります。もちろん、ユーザーが編集したHTML全体を保存することができます。しかし、私はちょうどいくつかのパラメータを保存し、元のhtmlと組み合わせて、前回の状態ユーザーのページを表示したいだけです。この機能を使用すると:選択テキストを保存し、後でhtmlとjavascriptに表示します

var index = innerHTML.indexOf(text); 

そのインデックスのテキストをハイライトすることができます。しかし、ページに同じテキストがたくさんある場合は、前にハイライト表示されたユーザーの単語を正確に強調したいと思います。

誰でも私にjavascriptでこれを達成する方法を教えていただけますか?

多くのご支援をいただきありがとうございます。

+1

は、なぜあなたは、アレイ内の強調表示された単語のインデックス、およびその長さを保存しませんか? –

+0

私は@mohammedessamに同意して、 'xyz'をハイライト表示するユーザーが 'xyz'を配列に追加し、 'xyz'の特定のインスタンスを示すインデックスを含むように配列を作成します(つまり、 'xyz'のインスタンスはインデックスが3になります。 – tamak

+0

'innerHTML.indexOf(text)'は何かを提供しますが、インデックスだけでなく、 'ReferenceError'の可能性もあります。 – KooiInc

答えて

0

アレイを使用して、ユーザーの選択を保存することができます!その後、配列全体をデータベースに保存します。ユーザーがサイトを再表示すると、関数は文字列と単語を配列と比較し、ハイライト表示します。

+2

はい。そして、それをどうやって行うのか、私は疑問だ。 –

+0

@DavidThomas問題は、彼が自分のアプリケーションのハイライト機能を管理する方法についてOPが何も言わなかったことです。 –

+0

mousedown()とjavascriptのmou​​seup()イベントは、選択の開始時にmousedown()を使用し、選択したmouseup()をエンディングして配列に保存します。 – UserOnE

0

.serialize()標準のURLエンコード表記でテキスト文字列を返すメソッドを使用できます。 <input>, <textarea>などの個々のフォーム要素を選択しました。$(form).serialize();を使用してDB内のシリアル化された戻り文字列をプッシュし、変更を強調表示するためにOld $(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(" > ") 
} 

テキストを選択する2つのオプションをユーザに与えたいとします。

  1. ページ内の単純なテキスト。
  2. 入力テキストまたはテキストエリア内のテキストを選択します。

最初のオプションでは、クリックハンドラまたは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 
    }; 
} 

2番目のオプションでは、selectイベントハンドラを使用できます。

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

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

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

入力テキストまたはテキストエリアでは、selectイベントハンドラを使用する方が適しています。
最初のオプションを使用して選択を取得する場合は、入力テキストとテキストエリアがShadow DOMを使用して構築されているため、正しいターゲットノードを取得できません。
したがって、getSelectionTextAndContainerElement関数から再実行されたターゲットノードを無視し、selectイベントのtargetプロパティを使用する方が良いです。

jsfiddleの例を作成しました。

+0

jsfiddleはうまく機能します。しかし、私は12を選択して23を選択しようとすると、選択肢を123に拡張できないことに気付きました。 – xeo

+0

数字の選択は実際にはテキスト選択ではなく、選択したテキストの折り返しと同じ色の選択範囲のスパンに注意してください。私はそれが問題ではなかったので、ソリューション全体を作成しようとはしていませんでしたが、要素から選択とパスを取得することが可能であるという例を提供しました。テキストの選択を完了するには、https://developer.mozilla.org/en-US/docs/Web/API/Selectionでここを読んでください。 – Sagi

0

テストの観点からは、ハイライトを調整しなくても元のhtmlを変更することができれば、切り離されたハイライトを保存する方法はありません。

私の解決方法は、色付きHTML全体をシリアル化することです。スクラブ機能を使ってすべてのカラーハイライトを削除し、ベースラインhtmlに戻ります。これにより、データベース内のhtmlに色のハイライトを含めることができ、編集は保存されて強調表示されます。

何かのように:

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

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

6

Rangeオブジェクトとdocument.execCommandかなり簡単に選択を操作することができます。あなたの場合の主な問題は、範囲オブジェクトをテキスト形式で保存することです。

基本的には何が必要範囲オブジェクトを作成するために必要な値でありstartContainerstartOffsetendContainerendOffsetを得ることです。 Offsetsは数字なのでかなり簡単です。コンテナはノードです。これは文字列として直接保存することはできませんので、それが主な問題です。あなたができることの1つは、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); 

これが完了すると、あなたは文字列として保存することができ、オブジェクトの範囲オブジェクトを変換することができます。このように:

これを使用して、ユーザーが作成した各選択を配列に保存できます。このように:

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に保存されたオブジェクトからの範囲を作成します逆の機能を使用することができます。

オブジェクトに変換して追加できる範囲オブジェクトに変換する文字列の範囲の配列を持つことができます。次に、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 >を追加して、レコードを取得したときにハイライトされたテキストが残ります。

<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内にスパンサラダが出るかもしれません... – 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

第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>

第2の例

<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>

実施例3:

<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>

関連する問題