2013-09-22 10 views
17

में दिखाएं मुझे HTML और जावास्क्रिप्ट के साथ एक कठिन स्थिति है। मेरा एचटीएमएल पेज उपयोगकर्ता को टेक्स्ट का चयन करने और रंगों के साथ हाइलाइट करने की अनुमति देता है। अब मैं उस उपयोगकर्ता के लिए इसे बाद में दिखाने के लिए राज्य को डेटाबेस में सहेजना चाहता हूं। बेशक, उपयोगकर्ता इसे संपादित करने के बाद मैं पूरे एचटीएमएल को बचा सकता हूं। लेकिन मैं केवल कुछ पैरामीटर को सहेजना चाहता हूं, मूल उपयोगकर्ता के साथ गठबंधन करने के लिए मूल उपयोगकर्ता के साथ गठबंधन करें। हम इस फ़ंक्शन का उपयोग कर सकते हैं:चयन टेक्स्ट सहेजें और बाद में इसे HTML और जावास्क्रिप्ट

var index = innerHTML.indexOf(text); 

उस अनुक्रमणिका पर टेक्स्ट को हाइलाइट करने के लिए। लेकिन यदि पृष्ठ में कई समान ग्रंथ हैं, तो मैं पहले शब्द को हाइलाइट करना चाहता हूं।

कोई भी मुझे जावास्क्रिप्ट के साथ इसे पूरा करने का निर्देश दे सकता है?

मैं आपकी मदद की बहुत सराहना करता हूं।

+1

आप एक सरणी में हाइलाइट किए गए शब्द का सूचकांक, और उनके लंबाई क्यों नहीं बचा सकता हूं? –

+0

मैं @ मोहम्मदसेम से सहमत हूं, एक सरणी बनाएं ताकि उपयोगकर्ता 'xyz' को हाइलाइट करने वाला एक सरणी में 'xyz' जोड़ देगा और यह भी इंगित करेगा कि 'xyz' का कौन सा विशिष्ट उदाहरण था (यानी यदि यह तीसरा था तब 'xyz' का उदाहरण तब सूचकांक होगा 3. – tamak

+0

मुझे संदेह है कि 'innerHTML.indexOf (टेक्स्ट)' कुछ भी वितरित करेगा, अकेले एक इंडेक्स दें। 'संदर्भ त्रुटि' अधिक संभावना है। – KooiInc

उत्तर

0

आप उपयोगकर्ता का चयन सहेजने के लिए ऐरे का उपयोग कर सकते हैं !! उसके बाद आप पूरे सरणी को अपने डेटाबेस में सहेजते हैं! और जब उपयोगकर्ता साइट को दोबारा देखता है, तो फ़ंक्शन सरणी से अक्षर और शब्द की तुलना करता है और इसे हाइलाइट करता है ..

+2

हां में। और * यह कैसे करें *, मुझे संदेह है, सवाल है। –

+0

@ डेविड थॉमस समस्या यह है कि ओपी ने अपने आवेदन की हाइलाइटिंग कार्यक्षमता का प्रबंधन करने के तरीके के बारे में कुछ भी नहीं कहा, इस तरह केवल उसे जानता है कि इसे कैसे कार्यान्वित किया जाए! –

+0

mousedown() और mouseup() घटनाओं जावास्क्रिप्ट में जब चयन प्रारंभ 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. इनपुट टेक्स्ट या टेक्स्टरेरा के अंदर टेक्स्ट का चयन करना।

पहले विकल्प के लिए आप क्लिक हैंडलर या माउसअप ईवेंट वाले बटन का उपयोग कर सकते हैं।
मैं सादगी के लिए एक बटन का उपयोग करूंगा।

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 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 ईवेंट हैंडलर का उपयोग करने के लिए


यदि आप चयन प्राप्त करने के पहले विकल्प का उपयोग करेंगे तो आपको सही लक्ष्य नोड नहीं मिलेगा क्योंकि इनपुट टेक्स्ट और टेक्स्टरेरा Shadow DOM का उपयोग करके बनाया गया है।
तो getSelectionTextAndContainerElement फ़ंक्शन से पुनः प्राप्त लक्ष्य नोड को अनदेखा करना और select ईवेंट की लक्षित संपत्ति का उपयोग करना बेहतर है।

मैंने आपके लिए jsfiddle में एक उदाहरण बनाया है।

+0

आपका jsfiddle बहुत अच्छी तरह से काम करता है। लेकिन मैंने नोटिस किया कि यदि मैं 12 का चयन करता हूं तो 23 का चयन करने का प्रयास करें, यह चयन 123 तक बढ़ाने में विफल रहता है। उस पर कोई विचार? – xeo

+0

कृपया ध्यान दें कि संख्या चयन वास्तव में एक टेक्स्ट चयन नहीं है, लेकिन चयनित पाठ की एक रैपिंग जिसमें एक समान रंग है। मैं पूरा समाधान बनाने की कोशिश नहीं कर रहा था क्योंकि यह सवाल नहीं था, लेकिन एक उदाहरण देने के लिए कि चयन और तत्व से पथ प्राप्त करना संभव है। टेक्स्ट चयन को पूरा करने के लिए आप यहां इसके बारे में पढ़ सकते हैं: https://developer.mozilla.org/en-US/docs/Web/API/ चयन। – Sagi

0

एक परीक्षण परिप्रेक्ष्य से, अलग-अलग हाइलाइट्स को स्टोर करने के लिए कोई तरीका नहीं है यदि मूल HTML को भी हाइलाइट समायोजित किए बिना बदलना संभव हो।

मेरा समाधान पूरे रंगीन एचटीएमएल को क्रमबद्ध करना होगा। फिर सभी रंग हाइलाइट्स को हटाने और बेसलाइन एचटीएमएल पर वापस जाने के लिए एक स्क्रब फ़ंक्शन बनाएं। यह डीबी में एचटीएमएल को रंग हाइलाइट्स को शामिल करने की अनुमति देता है और संपादन अभी भी संरक्षित हाइलाइटिंग के साथ हो सकता है।

कुछ तरह:

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

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

6

Range वस्तुओं और document.execCommand बहुत आसानी से चयन में हेरफेर करने के लिए अनुमति देते हैं। आपके मामले में मुख्य समस्या श्रेणी वस्तु में रेंज ऑब्जेक्ट को सहेज रही है।

मूल रूप से आपको क्या चाहिए पाने के लिए है startContainer, startOffset, endContainer और endOffset, जो मूल्यों रेंज वस्तुओं बनाने के लिए आवश्यक हैं। Offsets संख्या है इसलिए यह बहुत सरल है। कंटेनर नोड्स हैं, जिन्हें आप स्ट्रिंग के रूप में सीधे सहेज नहीं सकते हैं, इसलिए यह मुख्य समस्या है। एक चीज जो आप कर सकते हैं वह आपके डोम में कुंजी जोड़ती है और कुंजी को सेव करती है। लेकिन फिर, जब श्रेणी कंटेनर टेक्स्ट नोड्स हैं, तो आपको टेक्स्ट नोड की अनुक्रमणिका को सहेजने की आवश्यकता होगी। यह हो जाने पर, आप एक वस्तु है कि आप एक स्ट्रिंग के रूप में सहेज सकते हैं करने के लिए सीमा वस्तुओं में बदल सकते हैं

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 स्ट्रिंग प्राप्त कर सकते हैं। इस तरह (यह शीर्ष पर प्राप्त seletion बटन का उपयोग किया जाता है):

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

फिर जब खाली एचटीएमएल लोड हो रहा है, तो आप एक रिवर्स समारोह है कि वस्तुओं आप 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; 
} 

तो तुम तार कि आप वस्तुओं में बदलने में पर्वतमाला की एक सरणी हो सकता था, और फिर वस्तुओं है कि आप जोड़ सकते हैं श्रृंखला के लिए कनवर्ट करें। फिर 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

क्योंकि हम ओप के संदर्भ को नहीं जानते हैं - यदि एक ही पृष्ठ पर कई उपयोगकर्ता ऐसा कर रहे हैं, तो इसके परिणामस्वरूप आपके एचटीएमएल में स्पैन सलाद हो सकता है ... – 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>

संबंधित मुद्दे