Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[JS] Focussen op een node in iframe (designmode)

Pagina: 1
Acties:

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
Ik ben bezig aan een wysiwyg editor. Het idee is dat de gebruiker altijd netjes in een paragraph oid zit, dus maak ik meteen een paragraafje aan bij het starten van de editor. Nou wil ik graag op dat paragraafje focussen (de caret erin zetten), maar dat krijg ik niet voor elkaar.

Probeersel-code:
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function placeCaretInNode(node) {
    if (window.getSelection) {
        //Gecko
        var sel = document.getElementById("editorframe").contentWindow.getSelection();
        sel.removeAllRanges();
        var range = document.createRange();
        range.selectNode(node);
        sel.addRange(range);
    }
    else {
        //IE
        node.focus();
        //document.getElementById("editorframe").contentWindow.focus();
        //var range = document.selection.createRange();
        //range.setStart(node,0);
        //range.setEnd(node,1);
    }
}

Het stukje voor firefox creëert weliswaar de goede selectie (de tekst in de paragraaf wordt geselecteerd) maar er wordt niet op gefocussed (als ik begin te typen overschrijf ik de selectie niet).

Het gecommente stukje bij IE zou volgens mij moeten werken, maar IE beweert dat de variabele range die twee functies niet ondersteunt. node.focus() doet niets, terwijl node.parentNode.focus() wel netjes de focus in de Body van de editor parkeert.

Jemand eine Ahnung?

NB: gaarne geen tips in de trant van 'ik gebruik editor x', ik wil gewoon kunnen focussen op een node.

TabCinema : NiftySplit


  • Juup
  • Registratie: Februari 2000
  • Niet online
Het is belangrijk dat je deze dingen probeert lang nadat de iframe is geladen en designmode is aangezet, zeg maar 1 seconde later pas ofzo.
Lukt het dan wel?

Een wappie is iemand die gevallen is voor de (jarenlange) Russische desinformatiecampagnes.
Wantrouwen en confirmation bias doen de rest.


  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
Nee :(

Ik had al rekening gehouden met zoiets door op onload events e.d. te wachten, en een timeout helpt helaas niet.

TabCinema : NiftySplit


Verwijderd

Wat bij mij werkt is dit:

code:
1
2
var range = obj.createTextRange();
range.select();


Waarbij obj het object is waar in de tekst staat (bij mij een textarea)

edit
^^ is voor Gecko btw, in IE doe ik gewoon een obj.focus()

[ Voor 19% gewijzigd door Verwijderd op 15-02-2008 11:09 ]


  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
Helaas, createTextRange bestaat niet voor een designmode iframe.

TabCinema : NiftySplit


Verwijderd

Bozozo schreef op vrijdag 15 februari 2008 @ 16:17:
Helaas, createTextRange bestaat niet voor een designmode iframe.
Maar je hebt het wel geprobeerd met range.select() of gaat dat in dit geval ook niet op?

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
Nee dat kan ook niet.

Hier een helemaal gestripte testcase: testcase

Bij PlaceCaretInNode is het te doen.


JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    function placeCaretInNode(node) {
      if (window.getSelection) {
        //Gecko
        var range = document.createRange();
        range.selectNode(node);
        var selected = document.getElementById("editorframe").contentWindow.getSelection();
        selected.addRange(range);
        selected.collapse(node, node.childNodes.length);
        document.getElementById("editorframe").contentWindow.focus(); 
      }
      else {
        //IE
        var range = document.getElementById("editorframe").contentWindow.document.selection.createRange();
        range.moveToElementText(node);
        range.collapse(false);
        range.move('character',-1);
        range.select();
        node.focus();
      }
    }


edit: bovenstaand stukje gedestilleerd uit de broncode van WYM editor. Ik krijg het helaas nog niet goed werkend voor IE, maar voor FF werkt het prima.

IE accepteert node niet als argument voor moveToElementText??

[ Voor 108% gewijzigd door Bozozo op 15-02-2008 20:59 ]

TabCinema : NiftySplit


  • f.v.b
  • Registratie: Januari 2008
  • Laatst online: 17-11 09:06
Je was er volgens mij bijna...

...document.selection.createRange() -> ...document.body.createTextRange()

Probeer dit eens in IE:

JavaScript:
1
2
3
4
5
6
7
8
        //IE
                //doe nog iets slims
        var range = document.getElementById("editorframe").contentWindow.document.body.createTextRange();
        range.moveToElementText(node);
        range.collapse(false);
        range.select();
        // document.getElementById("editorframe").contentWindow.focus(); 
        // node.focus();

[ Voor 9% gewijzigd door f.v.b op 16-02-2008 09:31 ]

Don't erase all files?
       [Yes]   [No]


  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
Held! Dank u zeer :)

Edit: hier de uiteindelijke code. De code van WYMeditor voor mozilla heb ik nog lichtjes aangepast, omdat hij de cursor na de huidige paragraaf parkeerde ipv erin.
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    function placeCaretInNode(node) {
      if (window.getSelection) {
        //Gecko
        var range = document.createRange();
        range.selectNode(node.lastChild);
        var selected = document.getElementById("editorframe").contentWindow.getSelection();
        selected.addRange(range);
        selected.collapse(node.lastChild, node.lastChild.length);
        document.getElementById("editorframe").contentWindow.focus();
      }
      else {
        //IE
        var range = document.getElementById("editorframe").contentWindow.document.body.createTextRange();
        range.moveToElementText(node);
        range.collapse(false);
        range.select();
      }
    }

[ Voor 97% gewijzigd door Bozozo op 16-02-2008 12:06 ]

TabCinema : NiftySplit


  • f.v.b
  • Registratie: Januari 2008
  • Laatst online: 17-11 09:06
Graag gedaan. :)

Het meeste werk had je zelf al gedaan. Na 10 minuten spitten in de TinyMCE code was het een kwestie van knippen en plakken.

Don't erase all files?
       [Yes]   [No]


  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
De werkende editor (beginnetje dan) staat nu hier: Editor

Ik wil hem graag werkend krijgen in IE, FF en Safari. Stomtoevallig (ik heb geen rekening gehouden met Safari) werkt hij vrij aardig in de laatstgenoemde browser. De placeCaretInNode functie helaas niet. Dat vind ik vreemd, want voor zover ik weet hebben Safari en FF ongeveer dezelfde engine.

Twee vragen:
- Ziet iemand een oplossing voor het focussen in Safari?
- Bestaat er een goede Safari JS reference, á la developer.mozilla.org?

TabCinema : NiftySplit


  • torp
  • Registratie: Januari 2001
  • Laatst online: 14-11 13:07
- Bestaat er een goede Safarie JS reference, á la developer.mozilla.org?
Volgens mij niet. Ik verkeer weleens op http://www.webkit.org (webkit is de engine van safari) en daar wordt soms ook verwezen naar developer.mozilla.org...

Heel interessant wat je aan het bouwen bent, ik had het hele verschijnsel designmode nog niet echt in de gaten. Maar hoe stuur je het gewijzigde bestand nou naar de server?

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
Je kunt gewoon de innerHTML eruit halen, en daarna bijvoorbeeld een hidden form submitten of met AJAX posten.

TabCinema : NiftySplit


  • torp
  • Registratie: Januari 2001
  • Laatst online: 14-11 13:07
Ah, I see. En dit moet persé in een iframe gebeuren? Ik zal me er eens in verdiepen.

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
Een nieuw probleem. Ik raak in IE de focus kwijt als ik een menu gebruik. Zie nieuwste versie. Door de muisklik events te verhinderen met preventDefault blijft de focus behouden in FF, maar in IE werkt die truc niet. Hoe kan ik dit oplossen zonder buttons te moeten gebruiken in mijn menu?

edit: een handige workaround leek mij het opslaan van de selectie, om die op een willekeurig moment te kunnen herstellen. Dit krijg ik echter niet voor elkaar. Het probleem lijkt nogal op het oorspronkelijke probleem, maar ik krijg het niet opgelost.

De code die niks doet maar mij logisch lijkt:
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
    function saveSelection() {
      if (document.selection) {
        selbuf = document.getElementById('editorframe').contentWindow.document.selection.createRange();
      }
    }
    
    function restoreSelection() {
      if (document.selection) {
        selbuf.select();
        document.getElementById('editorframe').contentWindow.focus();
      }    
    }


edit: Ik heb het probleem gevonden, maar ik zie geen oplossing. RestoreSelection wordt gecalled in de functie die wordt uitgevoerd na een mousedown op een submenuitem:
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    //voor alle submenu items geldt:
    addEvent(subitems[a],"mousedown",menucmd);

    ...

    function menucmd(e) {
      if (!e) e = window.event;
      e.cancelBubble = true;
      if (e.stopPropagation) e.stopPropagation();
      if (e.preventDefault) e.preventDefault();
      hidemenus(e);
      restoreSelection();
      errrror;
    }

Het regeltje errrrror zorgt voor een error (doh), waardoor alle javascript execution stopt. Op dat moment is de selectie netjes tevoorschijn gekomen en in focus.

Het probleem is dat, zonder errrrror, de mousedown functie daarna wordt voltooid en de selectie weer deselecteerd. De default action voorkomen (met e.returnvalue) heeft geen effect.

Ik moet dus eigenlijk wachten met het herstellen van de focus totdat de muisklik helemaal is afgerond. Een timeout instellen helpt helaas niet. Weet iemand hoe het wel kan?

[ Voor 97% gewijzigd door Bozozo op 17-02-2008 00:21 ]

TabCinema : NiftySplit


  • f.v.b
  • Registratie: Januari 2008
  • Laatst online: 17-11 09:06
Zelf gebruikte ik deze code (IE only) om ervoor te zorgen dat de selectie niet verdwijnt. document verwijst in onderstaande code niet naar de iframe, maar naar de pagina waarin de iframe staat:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    // Disable selection of links and images. This way
    // TEXTAREA's and IFRAME's stay the active element
    // after clicking on an image or link.
    // The same applies to the images used in the GUI bar

    var alllinks = document.getElementsByTagName('a');
    
    for (var i = 0; i < alllinks.length; i++)
    {
        alllinks[i].unselectable = "on";
    }
    
    var allimages = document.getElementsByTagName('img');
    
    for (var i = 0; i < allimages.length; i++)
    {
        allimages[i].unselectable = "on";
    }


Uiteindelijk zul je toch de selectie bij elke muisklik moeten opslaan. Dat was de enige methode die ik stabiel kreeg. Zodra je de selectie nodig hebt (maak bold/italic/hyperlink/etc.), moet je de selectie eerst herstellen.

Don't erase all files?
       [Yes]   [No]


  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
Ik ben nu aan het proberen om mijn editor ook werkend te krijgen in Safari en Opera. Safari is niet zo'n probleem, maar Opera wel. Het eerste grote probleem waar ik tegenaan loop is dat window.focus() niet goed werkt.

Testpagina nog steeds hier.

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    //move the caret to the specified node
    function placeCaretInNode(node,atstart) {
      if (browser==="IE") {
        var range = document.getElementById("editorframe").contentWindow.document.body.createTextRange();
        range.moveToElementText(node);
        range.collapse(atstart);
        range.select();
      }
      else {
        var range = document.getElementById("editorframe").contentWindow.document.createRange();
        range.selectNodeContents(node);
        var selected = document.getElementById("editorframe").contentWindow.getSelection();
        selected.addRange(range);
        if (atstart) selected.collapse(node.lastChild,0);
        else selected.collapse(node.lastChild,node.lastChild.length);
        document.getElementById("editorframe").contentWindow.focus();
        //note: focussing doens't work in Opera
      }
    }


Dit stukje code doet het in IE, Safari en Firefox. In Opera kan ik wel een selectie maken (te zien als je het collapse regeltje comment) maar focussen weigert hij gewoon.

Ik ben niet gewend om voor Opera te ontwikkelen. Weet iemand een oplossing voor mijn probleem?

NB: verder werkt de editor sowieso voor geen meter in Opera, maar het gaat me nu om deze specifieke fout.

edit: de functie wordt gecalled bij het openen van de pagina. Als hij werkt moet je de caret achter 'hoi' zien knipperen.

[ Voor 3% gewijzigd door Bozozo op 21-02-2008 10:16 ]

TabCinema : NiftySplit

Pagina: 1