2016-10-01 14 views
5

Powiedzmy mam następujący prostą stronę z dwóch przypadkach CodeMirror:Jak mogę przeszukiwać wiele instancji codemirror?

const body = document.querySelector('body') 

const title = document.createElement('h1') 
title.textContent = 'This is a document with multiple CodeMirrors' 
body.appendChild(title); 

const area1 = document.createElement('textarea') 
body.appendChild(area1) 
const editor1 = CodeMirror.fromTextArea(area1, { 
    lineNumbers: true, 
}) 

const segway = document.createElement('h2') 
segway.textContent = 'Moving on to another editor' 
body.appendChild(segway) 


const area2 = document.createElement('textarea') 
body.appendChild(area2) 
const editor2 = CodeMirror.fromTextArea(area2, { 
    lineNumbers: true, 
}) 

i że podaję

  • codemirror/addon/search/search
  • codemirror/addon/search/searchcursor
  • codemirror/addon/dialog/dialog

Każdy CodeMirror instancja ma teraz swoją własną funkcję wyszukiwania, gdy koncentruje się na edytorze (wyzwalanym przez ctrl/cmd-f). Jak mogę zaimplementować funkcję wyszukiwania/zamiany, która działa w wielu instancjach CodeMirror?

Istnieje co najmniej jeden sposób wykonania find w każdym edytorze: editor.execCommand. Nie widzę sposobu, aby do tego przejść lub zapytać o to, jakie wyniki są dostępne.

CodePen with example code and imports

GitHub issue for project wanting to use this, nteract.

W CodeMirror issue Marijn stwierdza: "Musisz to sami zakodować", co jest słuszne - nie jestem pewien, jak się do tego zabrać.

Odpowiedz

2

znaleźć i zastąpić polecenia są związane z dialogowych dodatkami i nie wydaje się być sposób, aby uzyskać do nich dostęp za pośrednictwem instancji, a przynajmniej nie z kwerendy, która nie przepuszcza się przez dialog.

Można jednak odzyskać większość zawartości pliku search.js i dodać ją jako rozszerzenie, do którego można przekazać zapytanie. Ale musisz skonfigurować globalne okno dialogowe lub sposób na uzyskanie zapytania, które nie jest zależne od instancji, i uruchomić je dla każdej instancji. Coś takiego powinno działać, to tylko do poszukiwań, ale zastępując powinien być łatwy, a także:

CodeMirror.defineExtension('search', function(query) { 

    // This is all taken from search.js, pretty much as is for the first part. 
    function SearchState() { 
    this.posFrom = this.posTo = this.lastQuery = this.query = null; 
    this.overlay = null; 
    } 

    function getSearchState(cm) { 
    return cm.state.search || (cm.state.search = new SearchState()); 
    } 

    function searchOverlay(query, caseInsensitive) { 
    if (typeof query == "string") 
     query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g"); 
    else if (!query.global) 
     query = new RegExp(query.source, query.ignoreCase ? "gi" : "g"); 

    return { 
     token: function(stream) { 
     query.lastIndex = stream.pos; 
     var match = query.exec(stream.string); 
     if (match && match.index == stream.pos) { 
      stream.pos += match[0].length || 1; 
      return "searching"; 
     } else if (match) { 
      stream.pos = match.index; 
     } else { 
      stream.skipToEnd(); 
     } 
     } 
    }; 
    } 

    function queryCaseInsensitive(query) { 
    return typeof query == "string" && query == query.toLowerCase(); 
    } 

    function parseString(string) { 
    return string.replace(/\\(.)/g, function(_, ch) { 
     if (ch == "n") return "\n" 
     if (ch == "r") return "\r" 
     return ch 
    }) 
    } 

    function parseQuery(query) { 
    var isRE = query.match(/^\/(.*)\/([a-z]*)$/); 
    if (isRE) { 
     try { 
     query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); 
     } catch (e) {} // Not a regular expression after all, do a string search 
    } else { 
     query = parseString(query) 
    } 
    if (typeof query == "string" ? query == "" : query.test("")) 
     query = /x^/; 
    return query; 
    } 

    // From here it's still from search.js, but a bit tweaked so it applies 
    // as an extension, these are basically clearSearch and startSearch. 
    var state = getSearchState(this); 
    state.lastQuery = state.query; 
    state.query = state.queryText = null; 
    this.removeOverlay(state.overlay); 
    if (state.annotate) { 
    state.annotate.clear(); 
    state.annotate = null; 
    } 

    state.queryText = query; 
    state.query = parseQuery(query); 
    this.removeOverlay(state.overlay, queryCaseInsensitive(state.query)); 
    state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query)); 

    this.addOverlay(state.overlay); 
    if (this.showMatchesOnScrollbar) { 
    if (state.annotate) { 
     state.annotate.clear(); 
     state.annotate = null; 
    } 
    state.annotate = this.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query)); 
    } 
}); 

// this is to have an external input, but you could have your own way of 
// providing your query. Important thing is that you can run search on 
// an instance with a query. 
const body = document.querySelector('body') 
const searchAll = document.createElement('input'); 
body.appendChild(searchAll); 
searchAll.placeholder = 'Search All'; 
searchAll.addEventListener('input', function(e) { 
    var query = e.target.value; 
    var codeMirrorInstances = document.getElementsByClassName('CodeMirror'); 
    for (var i = 0; i < codeMirrorInstances.length; i++) { 
    var curInst = codeMirrorInstances[i].CodeMirror; 
    curInst.search(query); 
    } 
}); 

const title = document.createElement('h1') 
title.textContent = 'This is a document with multiple CodeMirrors' 
body.appendChild(title); 

const area1 = document.createElement('textarea') 
body.appendChild(area1) 
const editor1 = CodeMirror.fromTextArea(area1, { 
    lineNumbers: true, 
}) 

const segway = document.createElement('h2') 
segway.textContent = 'Moving on to another editor' 
body.appendChild(segway) 

const area2 = document.createElement('textarea') 
body.appendChild(area2) 
const editor2 = CodeMirror.fromTextArea(area2, { 
    lineNumbers: true, 
}); 

http://codepen.io/anon/pen/yavrRk?editors=0010

EDIT:

Inne polecenia, takie jak FindNext będzie działać normalnie po zapytanie jest stosowane, ale oczywiście będzie to również zależne od instancji. Jeśli musisz wdrożyć findNext we wszystkich instancjach, staje się bardziej skomplikowany, musisz zarządzać różnymi rzeczami, takimi jak aktualna, skupiona instancja, i zastąpić niektóre zachowania, takie jak findNext zapętlanie i podobne rzeczy. Można to zrobić, ale w zależności od wymaganego poziomu precyzji może być bardzo skomplikowany. Coś jak to działa, to nie jest bardzo elegancki, ale pokazuje, w jaki sposób można to zrobić:

CodeMirror.defineExtension('findNext', function(query) { 
    function SearchState() { 
    this.posFrom = this.posTo = this.lastQuery = this.query = null; 
    this.overlay = null; 
    } 

    function getSearchState(cm) { 
    return cm.state.search || (cm.state.search = new SearchState()); 
    } 

    // You tweak findNext a bit so it doesn't loop and so that it returns 
    // false when at the last occurence. You could make findPrevious as well 
    var state = getSearchState(this); 
    var cursor = this.getSearchCursor(state.query, state.posTo, state.query.toLowerCase()); 
    if (!cursor.find(false)) { 
    state.posTo = CodeMirror.Pos(0, 0); 
    this.setSelection(CodeMirror.Pos(0, 0)); 
    return false; 

    } else { 
    this.setSelection(cursor.from(), cursor.to()); 
    this.scrollIntoView({ 
     from: cursor.from(), 
     to: cursor.to() 
    }, 20); 
    state.posFrom = cursor.from(); 
    state.posTo = cursor.to(); 
    return true; 
    } 
}); 

// You make a find next button that will handle all instances 
const findNextBtn = document.createElement('button'); 
body.appendChild(findNextBtn); 
findNextBtn.textContent = 'Find next'; 
findNextBtn.addEventListener('click', function(e) { 
    // Here you need to keep track of where you want to start the search 
    // and iterating through all instances. 
    var curFocusIndex = -1; 
    var codeMirrorInstances = Array.prototype.slice.call(document.getElementsByClassName('CodeMirror')); 
    var focusedIndex = codeMirrorInstances.indexOf(lastFocused.getWrapperElement()); 

    // with the new return in findNext you can control when you go to 
    // next instance 
    var findInCurCm = lastFocused.findNext(); 
    while (!findInCurCm && curFocusIndex !== focusedIndex) { 
     curFocusIndex = codeMirrorInstances.indexOf(lastFocused.getWrapperElement()) + 1; 
     curFocusIndex = curFocusIndex === codeMirrorInstances.length ? 0 : curFocusIndex; 
     codeMirrorInstances[curFocusIndex].CodeMirror.focus(); 
     lastFocused = codeMirrorInstances[curFocusIndex].CodeMirror;  
     var findInCurCm = lastFocused.findNext();  
    } 
    }); 

http://codepen.io/anon/pen/ORvJpK?editors=0010

+0

Great! Jak przeskoczyć między wynikami wyszukiwania? –

+0

@KyleKelley Zobacz edycję, gdy tylko będziesz potrzebować zarządzać interakcjami między instancjami, aby zbudować sposób efektywnego zarządzania nimi. Metody instancji są łatwe do wdrożenia, ale zarządzanie interakcją między instancjami kopii lustrzanej kodu będzie bardziej złożone. –

+0

To świetnie, dziękuję bardzo. Kiedy zaczniemy zajmować się tym w naszym projekcie open source, dam ci znać, jak to działa! –

Powiązane problemy