Rilevare che la parola è stato cliccato all’interno di un testo

Sto costruendo un JS script che ad un certo punto è in grado, su una determinata pagina, permettono all’utente di fare clic su qualsiasi parola e di archiviare questa parola in una variabile.

Ho una soluzione che è abbastanza brutto e coinvolge classe-analisi utilizzando jQuery:
Io prima di analizzare tutto il codice html, dividere tutto in ogni spazio " ", e reinserisci tutto avvolto in un <span class="word">word</span>, e poi aggiungo un evento con jQ per rilevare clic su una classe, e l’utilizzo di $(this).innerHTML ho cliccato parola.

Questo è lento e brutto in tanti modi e speravo che qualcuno conosce un altro modo per raggiungere questo obiettivo.

PS: potrei prendere in considerazione l’esecuzione come un estensione per il browser, quindi se non sembra possibile con un semplice JS, e se conoscete un browser API che permetterebbe di che, si sentono liberi di parlare !

Un possibile owrkaround per l’utente per evidenziare la parola, invece di fare clic su di esso, ma mi piacerebbe molto essere in grado di ottenere la stessa cosa con un solo clic !

  • C’è un particolare browser che ti stai rivolgendo?
  • La maggior parte di loro, ma sarei felice di poter iniziare con il browser che offre la più conveniente strumenti per farlo
InformationsquelleAutor Cystack | 2011-09-27

 

11 Replies
  1. 51

    Ecco una soluzione che funziona senza l’aggiunta di tonnellate di campate per il documento (che funziona anche su Webkit e Mozilla e IE9+):

    http://jsfiddle.net/Vap7C/15/

    <p class="clickable">some words</p>
    
    $(".clickable").click(function(e) {
        s = window.getSelection();
        var range = s.getRangeAt(0);
        var node = s.anchorNode;
        while (range.toString().indexOf(' ') != 0) {
            range.setStart(node, (range.startOffset - 1));
        }
        range.setStart(node, range.startOffset + 1);
        do {
            range.setEnd(node, range.endOffset + 1);
    
        } while (range.toString().indexOf(' ') == -1 && range.toString().trim() != '' && range.endOffset < node.length);
        var str = range.toString().trim();
        alert(str);
    });​

    in IE8, non ha problemi a causa di getSelection. Questo link ( C’è un cross-browser soluzione per getSelection()? ) può aiutare con questi problemi. Non ho mai messo in Opera.

    Ho usato http://jsfiddle.net/Vap7C/1/ da una domanda simile come un punto di partenza. Il Selezione.modificare funzione:

    s.modify('extend','forward','word');
    s.modify('extend','backward','word');

    Purtroppo non sempre ottenere l’intera parola. Come soluzione alternativa, ho avuto la Gamma per la selezione e l’aggiunta di due cicli di trovare la parola confini. Il primo continua ad aggiungere nuovi personaggi per la parola fino a quando non raggiunge uno spazio. il secondo ciclo va alla fine della parola fino a quando non raggiunge uno spazio.

    Questo sarà anche prendere la punteggiatura alla fine della parola, quindi assicuratevi di tagliare che fuori, se necessario.

    • In realtà ho dovuto leggere il DOM documentazione su Mozilla capire questo fuori.
    • un utente anonimo ha suggerito questa modifica: Una soluzione migliore che si ottiene sempre la parola giusta, è più semplice, e funziona in IE 4+: jsfiddle.net/Vap7C/80
    • Abbastanza dolce… ho modificato per attivare solo quando ctrl è anche premuto. Non sembra voler essere il testo di <a> elementi però. Come mai?
    • Io non lavoro per la prima parola. Almeno in Cromo/Linux
    • Nella prima sezione di codice di cui sopra, range.setStart(node, (range.startOffset - 1)); si blocca quando si esegue la prima parola di un “nodo”, perché tenta di impostare range a un valore negativo. Ho provato ad aggiungere la logica per impedire che, ma poi la successiva range.setStart(node, range.startOffset + 1); restituisce tutte, ma la prima lettera della prima parola. Inoltre, quando le parole sono separate da un carattere di nuova riga, l’ultima parola della riga precedente viene restituito oltre al cliccata parola. Quindi, questo necessita di qualche lavoro.
    • Vedere il mio follow-up al di sotto della gamma.* set di codice.

  2. 13

    Per quanto ne so, l’aggiunta di un span per ogni parola è l’unico modo per fare questo.

    Si potrebbe considerare l’utilizzo di Lettering.js, che gestisce la scissione per voi. Anche se questo non ha un impatto sulle prestazioni, a meno che il tuo “divisione di codice” è inefficiente.

    Poi, invece di associazione .click() per ogni span, sarebbe più efficiente associare un singolo .click() al contenitore del spans, e controllare evento.obiettivo per vedere che span è stato cliccato.

    • Ho appena trovato questo navigando COSÌ: jsfiddle.net/niklasvh/rD2uE non è così preciso come la ‘span’ hack, che è un problema, ma sembra funzionare… devo benchmark (e cercare di capire cosa effettivamente il codice fa)
  3. 5

    L’unico cross-browser (IE < 8) di modo che conosco è il confezionamento in span elementi. E ‘ brutto ma neanche lento.

    Questo esempio è retta da jQuery .css() funzione di documentazione, ma con un enorme blocco di testo pre-processo:

    http://jsfiddle.net/kMvYy/

    Ecco un altro modo per farlo (dato qui: jquery catturare la parola valore ) sullo stesso blocco di testo che non richiede il confezionamento in span.
    http://jsfiddle.net/Vap7C/1

    • scusate, avevo dimenticato di premi salva
    • ok allora avevo già visto questa tecnica, che sembra essere supervisionato da molti, pur essendo efficiente e molto portatile, purtroppo non è preciso (un clic sulla prima lettera di una parola, di solito restituisce la parola precedente).
  4. 5

    Qui ci sono miglioramenti per il accettato risposta:

    $(".clickable").click(function (e) {
        var selection = window.getSelection();
        if (!selection || selection.rangeCount < 1) return true;
        var range = selection.getRangeAt(0);
        var node = selection.anchorNode;
        var word_regexp = /^\w*$/;
    
        //Extend the range backward until it matches word beginning
        while ((range.startOffset > 0) && range.toString().match(word_regexp)) {
          range.setStart(node, (range.startOffset - 1));
        }
        //Restore the valid word match after overshooting
        if (!range.toString().match(word_regexp)) {
          range.setStart(node, range.startOffset + 1);
        }
    
        //Extend the range forward until it matches word ending
        while ((range.endOffset < node.length) && range.toString().match(word_regexp)) {
          range.setEnd(node, range.endOffset + 1);
        }
        //Restore the valid word match after overshooting
        if (!range.toString().match(word_regexp)) {
          range.setEnd(node, range.endOffset - 1);
        }
    
        var word = range.toString();
    });​
  5. 3

    -EDIT-
    Che dire di questo? utilizza getSelection() legato a mouseup

    <script type="text/javascript" src="jquery-1.6.3.min.js"></script>
    <script>
    $(document).ready(function(){
        words = [];
        $("#myId").bind("mouseup",function(){
            word = window.getSelection().toString();
            if(word != ''){
                if( confirm("Add *"+word+"* to array?") ){words.push(word);}
            }
        });
        //just to see what we've got
        $('button').click(function(){alert(words);});
    });
    </script>
    
    <div id='myId'>
        Some random text in here with many words huh
    </div>
    <button>See content</button>

    Non riesco a pensare a un modo accanto a dividere, questo è quello che mi piacerebbe fare, un piccolo plug-in che si divide in spans e quando si fa clic aggiungerà il suo contenuto in un array per un ulteriore uso:

    <script type="text/javascript" src="jquery-1.6.3.min.js"></script>
    <script>
    //plugin, take it to another file
    (function( $ ){
    $.fn.splitWords = function(ary) {
        this.html('<span>'+this.html().split(' ').join('</span> <span>')+'</span>');
        this.children('span').click(function(){
            $(this).css("background-color","#C0DEED");
            ary.push($(this).html());
        });
    };
    })( jQuery );
    //plugin, take it to another file
    
    $(document).ready(function(){
        var clicked_words = [];
        $('#myId').splitWords(clicked_words);
        //just to see what we've stored
        $('button').click(function(){alert(clicked_words);});
    });
    </script>
    
    <div id='myId'>
        Some random text in here with many words huh
    </div>
    <button>See content</button>
    • è interessante notare che questo è (spaventosamente) vicino a la versione che ho al momento :p la mia preoccupazione principale è che questo codice potrebbe essere lenti molto lunghe pagine (lavori accademici, che è il mio target principale), quindi ero in cerca di qualcosa di più clicca-driven, ma potrei andare con che
    • Mi chiedo se facendo il split lato server con php sarebbe meglio, sotto le circostanze, sarebbe un’opzione valida?
    • no, si suppone di spina 3 siti di terze parti, in modo che solo client-code è possibile: -) vorrei provare la tua MODIFICA, guarda bene a me
    • purtroppo non funziona, l’utente deve selezionare il testo per farlo funzionare. esso può essere migliorata con l’ .modificare l’attributo di se. Vi posto il codice
    • jsfiddle.net/zLGre con questo fix minori ho aggirare l’inesattezza. Dovrebbe fare 😀
  6. 2

    Qui è un metodo completamente diverso. Io non sono sicuro circa la praticità, ma si può dare alcune idee differenti.
    Qui è che cosa sto pensando che se si dispone di un tag contenitore con posizione relativa con solo il testo in esso. Poi si potrebbe mettere un arco intorno ad ogni parola il suo record di offset Altezza, Larghezza, a Sinistra, e la parte Superiore, quindi rimuovere l’estensione. Salvare quelli in un array e poi quando c’è un clic del mouse nell’area di fare una ricerca per scoprire che cosa la parola fu più vicina, e il click. Questo, ovviamente, sarà per la cpu all’inizio. Quindi, questo avrebbe funzionato meglio in una situazione in cui la persona sarà il trascorrere del tempo leggendo attentamente l’articolo. Il vantaggio è che non è necessario preoccuparsi probabilmente 100s di elementi extra, ma che beneficio può essere marginali.

    Nota penso che si possa rimuovere il contenitore elemento del DOM per accelerare il processo e ancora ottenere l’offset distanze, ma io non sono positivi.

    • può essere completamente distrutta da una finestra ridimensionata, perché le campate sono passati, quando l’utente fa clic però :/
    • Sì, ho fatto pensare che. Se l’utente ridimensiona la finestra o modifiche dimensione del carattere poi si dovrà ricalcolare l’intera cosa. Di nuovo, questo metodo sarebbe molto stretta utilizzo caso. Ero solo buttando là fuori.
  7. 2

    E prendere un altro su @stevendaniel risposta:

    JS:

    $('.clickable').click(function(){
       var sel=window.getSelection();
       var str=sel.anchorNode.nodeValue,len=str.length, a=b=sel.anchorOffset;
       while(str[a]!=' '&&a--){}; if (str[a]==' ') a++; //start of word
       while(str[b]!=' '&&b++<len){};                   //end of word+1
       console.log(str.substring(a,b));
    });

    HTML:

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
    <p class="clickable">The objective can also be achieved by simply analysing the
    string you get from <code>sel=window.getSelection()</code>. Two simple searches for
    the next blank before and after the word, pointed to by the current position
    (<code>sel.anchorOffset</code>) and the work is done:</p>
    
    <p>This second paragraph is <em>not</em> clickable. I tested this on Chrome and Internet explorer (IE11)</p>

  8. 1

    Questo è un follow-up sul mio commento a stevendaniels’ la risposta (sopra):

    Nella prima sezione di codice di cui sopra, gamma.setStart(nodo,
    (gamma.startOffset – 1)); si blocca quando si esegue la prima parola di un
    “nodo”, perché tenta di gamma per un valore negativo. Ho provato
    aggiunta di logica per evitare che, ma poi la successiva
    la gamma.setStart(nodo, gamma.startOffset + 1); restituisce tutte, ma la prima
    lettera della prima parola. Inoltre, quando le parole sono separate da un carattere di newline,
    l’ultima parola della riga precedente viene restituito in aggiunta al
    cliccata parola. Quindi, questo necessita di qualche lavoro.

    Ecco il mio codice per rendere l’intervallo di espansione codice in quella risposta affidabile:

    while (range.startOffset !== 0) {                   //start of node
        range.setStart(node, range.startOffset - 1)     //back up 1 char
        if (range.toString().search(/\s/) === 0) {      //space character
            range.setStart(node, range.startOffset + 1);//move forward 1 char
            break;
        }
    }
    
    while (range.endOffset < node.length) {         //end of node
        range.setEnd(node, range.endOffset + 1)     //forward 1 char
        if (range.toString().search(/\s/) !== -1) { //space character
            range.setEnd(node, range.endOffset - 1);//back 1 char
            break;
        }
    }
    • PERFETTO! Vi ringrazio tanto.
  9. 0

    Quello che sembra un poco più semplice soluzione.

    document.addEventListener('selectionchange', () => {
      const selection = window.getSelection();
      const matchingRE = new RegExp(`^.{0,${selection.focusOffset}}\\s+(\\w+)`);
      const clickedWord = (matchingRE.exec(selectiaon.focusNode.textContent) || ['']).pop();
    });

    Sto testando

  10. 0

    Soluzione scelta a volte non funziona russo di testi (mostra di errore). Vorrei suggerire la seguente soluzione per il russo e l’inglese testi:

    function returnClickedWord(){
        let selection = window.getSelection(),
            text = selection.anchorNode.data,
            index = selection.anchorOffset,
            symbol = "a";
        while(/[a-zA-z0-9а-яА-Я]/.test(symbol)&&symbol!==undefined){
            symbol = text[index--];
        }
        index += 2;
        let word = "";
        symbol = "a";
        while(/[a-zA-z0-9а-яА-Я]/.test(symbol) && index<text.length){
            symbol = text[index++];
        word += symbol;
        }
        alert(word);
    }
    document.addEventListener("click", returnClickedWord);

Lascia un commento