Toon posts:

[JS] Tags om selectie of cursor in textarea detecteren

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik ben bezig met een eigen UBB editor. Als iemand aan het typen is, zorgt CTRL-B voor een [b]-tag en nogmaals CTRL-B voor een [/b] tag. Als je eerst een selectie maakt en dan CTRL-B drukt, wordt de selectie ingesloten door [b] en [/b], net als hier op GoT.

Wat ik nu probeer is, om de B-knop uit de toolbar te laten oplichten als de cursor op een woord staat dat omgeven is door B-tags:
code:
1
2
3
4
5
6
7
8
9
+---+ +---+ +---+
| B*| | U | | I |
+---+ +---+ +---+
+-----------------------------------------------+
| Dit is [b]ve|t[/b] en dit is                  |
| [b][u]vet en cursief[/u][/b]                  |
|                                               |
|                                               |
+-----------------------------------------------+

Er is hier al eerder een topic over geweest, maar daar kwam weinig respons op. Het idee werd geopperd om naar de source van widgEditor te kijken, omdat deze WYSIWYG de relevante toolbar buttons doet oplichten als de cursor op een woord staat. De relevante delen van deze code zijn (voor IE):
JavaScript:
1
2
3
4
5
6
7
8
9
theSelection = theWidgEditor.theIframe.contentWindow.document.selection;
theRange = theSelection.createRange();
theParentNode = theRange.parentElement();

switch (theParentNode.nodeName.toLowerCase()) {
  case "a":
    theWidgEditor.theToolbar.setState("Link", "on");
    break;
} 

Ik snap het principe hiervan, maar omdat ik hier te maken heb met een textarea met UBB codes (ipv een iframe met HTML codes), gaat dit verhaal niet op. Ik kan weliswaar op dezelfde wijze een selectie in de textarea detecteren, maar omdat UBB codes niet aan de DOM hangen, hebben zijn er geen parentNodes aan te geven. En ook al zou ik HTML tags ipv UBB tags in de textarea typen, dan nog gaat het parentNode verhaal imho niet op, omdat deze tags niet in de DOM terug te vinden zijn omdat ze slechts tekst zijn in een textarea (die opzich wel in de DOM terug te vinden is).

Ik heb wel de volgende functie gevonden, die de <b> en </b> tags om een selectie weghaalt, als de selectie uit de textarea als door bold-tags omvat is en er wederom op de bold knop gedrukt wordt:
JavaScript:
1
2
3
4
5
6
7
8
function selection_replace(type, text) {
  switch (type) {
    case 'bold':
      var re = new RegExp('^<b[^>]*>(.*?)</b>$');
      text = (!re.test(text)) ? '<b>'+ text +'</b>' : text.replace(re, '$1');
      break;
  }
}


Wellicht dat hier een deel van de oplossing zit, maar als dat zo is vraag ik bij deze hulp om dit te implementeren voor als er meerdere tags om een selectie staan, zoals bold en underline tags. Kan iemand mij uitleggen hoe ik de UBB (of HTML, wat dat betreft) tags om een selectie in een tekstarea kan detecteren, gelijk aan hoe widgEditor parentNodes detecteert?

  • beetle71
  • Registratie: Februari 2003
  • Laatst online: 24-11 16:50
Volgens mij is je conclusie goed, aangezien je tekst niet in een tree-model hangt kun je niet op zoek naar parent(s) en de tagnames daarvan.
Wat je zou kunnen doen is steeds in het deel van de tekst links van je cursor (caret) van achter naar voren op zoek te gaan naar een [iets] 'tag' en op basis daarvan je button aan/uit te zetten.
Dit is vermoed ik wel redelijk belastend voor de snelheid waarmee je buttonbar/textarea werkt, dus is het handig dit op een timer te zetten, bijv 0,5 seconden na een toetsaanslag, en zolang er toetsaanslagen blijven binnen deze timer 'm steeds weer te resetten. Volgens mij loopt er daarover nog ergens hier op GOT een topic.

Verwijderd

Topicstarter
beetle71 schreef op woensdag 28 februari 2007 @ 09:15:
Wat je zou kunnen doen is steeds in het deel van de tekst links van je cursor (caret) van achter naar voren op zoek te gaan naar een [iets] 'tag' en op basis daarvan je button aan/uit te zetten.
Voor de regex cracks onder ons: is er geen generieke regex oplossing hiervoor? Het gaat immers om een van tevoren bekend aantal tags: [b], [i], [u], [s], [sub], [sup], [url], [ul], [li], en [ol]

[ Voor 43% gewijzigd door Verwijderd op 28-02-2007 13:24 ]


  • beetle71
  • Registratie: Februari 2003
  • Laatst online: 24-11 16:50
Een generieke regex denk ik niet. Je moet ALLE items tussen [] vinden (ook de betreffende sluittags)
[code:javascript]
var re = new RegExp ('\[(.*)\]');
leftpart.match(re);
[/code]
Regex is uit het blote,slapperige hoofd dus waarschijnlijk fout ;-)

Vervolgens de array van voor naar achter doorlopen (ipv. achterstevoren zoals ik eerst zei).
en dan een array(stack) opbouwen per 'geopend' element bijv. [b] en dit element er weer afhalen als je een sluit element tegenkomt [/b]. Uiteindelijk hou je dan op je stack alleen nog de openers over die 'geactiveerde' buttons moeten hebben.
De push en pop voor de stack kan tricky worden als er ongebalanceerde tags voorkomen..
[b]dit is [i] heel erg [/b] tricky [/i]. Waarschijnlijk dan handiger om per tag een true/false steeds aan en uit te zetten bij het doorlopen van de array.

of zoiets 8)

Hee! Got gaat ook de mist in.. [b][pplain] [b]dit is [i] heel erg [/b] tricky [/i]. [/pplain] [/b] (pplain even express)
Geeft:
[b][plain] dit is heel erg [/b] tricky . [/plain]

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 13:26

crisp

Devver

Pixelated

beetle71: jouw voorbeeld gaat hier technisch goed hoor; het ligt er immers helemaal aan wat voor tag-matching algoritme je gebruikt (adoption agency algorithm, incest algorithm, secret affair algorithm, Heisenberg algorithm of gewoon lekker straight-forward :P )

Overigens is client-side tokenising en tree-building op zich niet zo heel zwaar vermits je daar een beetje redelijke implementatie voor gebruikt en het niet om al te grote teksten gaat. Het schrijven van een dergelijke implementatie is echter geheel andere koek. Ik heb wel wat experimenteel werk daarvoor liggen maar dat is nog lang niet productie-waardig... (daar los ik precies dit probleem ook in op - de positie van de caret binnen de tree bepalen).

Fact is dat je met reguliere expressies het probleem van nesting niet of nauwelijks kan ondervangen.
Als je wilt weten hoe bijvoorbeeld in HTML tokenising en tree-building wordt gedaan dan is de WA 1.0 WD wel een mooi uitgewerkt voorbeeld :)

[ Voor 17% gewijzigd door crisp op 01-03-2007 00:39 ]

Intentionally left blank


Verwijderd

Topicstarter
@crisp, beetle71: Ik heb nu dit:
HTML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<style type="text/css">.on { border:1px red; }</style>

<form action="#">
   <input type="button" value="b" name="b">
   <input type="button" value="u" name="u">
   <input type="button" value="i" name="i">
   <textarea onkeyup="foo(this)" onclick="foo(this)"></textarea>
</form>

<script type="text/javascript">
function foo(textarea) {
   var tags = ["b", "u", "i"];
   for(i = 0; i < tags.length; i++) {
     a = textarea.value.substr(
       0, getCaretPos(textarea)).split('[\/'+ tags[i] +']'
     );
     textarea.form.elements[tags[i]].className = (
       a[a.length - 1].indexOf('['+ tags[i] +']')!= -1
     ) ? 'on' : '';
   }
}
   
function getCaretPos(el) {
  var range, i = -1;
  if (typeof el.selectionStart == 'number') {
    i = el.selectionStart;
  }
  else if (document.selection && el.createTextRange) {
    range = document.selection.createRange();
    range.collapse(true);
    range.moveStart('character', -el.value.length);
    i = range.text.length;
  }
  return i;
}
</script>

Wat opzich wel werkt, alleen wordt de class ook op "on" gezet als je op een [b], [i] of [u] tag zelf staat, of als er alleen een openingstag staat. Enig idee hoe dit op te lossen? Vooral voor het eerste probleem zie ik zo snel geen oplossing...iemand?

  • beetle71
  • Registratie: Februari 2003
  • Laatst online: 24-11 16:50
Verwijderd schreef op donderdag 01 maart 2007 @ 02:12:
Wat opzich wel werkt, alleen wordt de class ook op "on" gezet als je op een [b], [i] of [u] tag zelf staat, of als er alleen een openingstag staat. Enig idee hoe dit op te lossen? Vooral voor het eerste probleem zie ik zo snel geen oplossing...iemand?
Heej, strange. De uitkomst van je CaretPosition levert iets geks op, check per keer maar eens wat er in je 'leftpart' staat. Dat klopt niet :?

Kijk ook eens hier http://www.bazon.net/mishoo/articles.epl?art_id=1292


@crisp; Naja, 'technisch' goed.... Het lijkt me toch dat tags binnen twee plain tags nooit geparsed mogen worden....

[ Voor 6% gewijzigd door beetle71 op 01-03-2007 09:55 ]


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 13:26

crisp

Devver

Pixelated

beetle71 schreef op donderdag 01 maart 2007 @ 09:53:
[...]
@crisp; Naja, 'technisch' goed.... Het lijkt me toch dat tags binnen twee plain tags nooit geparsed mogen worden....
Ah, wacht - je bedoelt met de echte [plain]-tag. Ja, React gaat daar inderdaad de mist in met de tag-matching. Mijn eigen parser doet het gelukkig wel goed :P

Intentionally left blank


  • killercow
  • Registratie: Maart 2000
  • Laatst online: 28-11 15:56

killercow

eth0

crisp schreef op donderdag 01 maart 2007 @ 00:32:
(adoption agency algorithm, incest algorithm, secret affair algorithm, Heisenberg algorithm of gewoon lekker straight-forward :P )

Fact is dat je met reguliere expressies het probleem van nesting niet of nauwelijks kan ondervangen.
Als je wilt weten hoe bijvoorbeeld in HTML tokenising en tree-building wordt gedaan dan is de WA 1.0 WD wel een mooi uitgewerkt voorbeeld :)
Kijk, dat is nog eens mooi leesvoer, ik vroeg me al af welke van de keuzes bij verkeerde nesting mijn tokenizer het beste kon gebruiken, maar nu hebben de oplossing iig namen. thanks

openkat.nl al gezien?


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 13:26

crisp

Devver

Pixelated

killercow schreef op donderdag 01 maart 2007 @ 11:58:
[...]


Kijk, dat is nog eens mooi leesvoer, ik vroeg me al af welke van de keuzes bij verkeerde nesting mijn tokenizer het beste kon gebruiken, maar nu hebben de oplossing iig namen. thanks
Dergelijke algorithmes zijn handig als je tagmatching en treebuilding in 1 pass wilt doen. error-correctie of in-tree manipulaties zijn daarbij echter wel noodzakelijk (je weet immers vantevoren niet of een tag wel of niet correct afgesloten wordt). Ik doe zelf meestal tagmatching en treebuilding los van elkaar wat aanzienlijk minder complex is (en sneller wanneer je veel ongebalanceerde tags hebt).

Intentionally left blank


  • killercow
  • Registratie: Maart 2000
  • Laatst online: 28-11 15:56

killercow

eth0

crisp schreef op donderdag 01 maart 2007 @ 12:16:
[...]

Dergelijke algorithmes zijn handig als je tagmatching en treebuilding in 1 pass wilt doen. error-correctie of in-tree manipulaties zijn daarbij echter wel noodzakelijk (je weet immers vantevoren niet of een tag wel of niet correct afgesloten wordt). Ik doe zelf meestal tagmatching en treebuilding los van elkaar wat aanzienlijk minder complex is (en sneller wanneer je veel ongebalanceerde tags hebt).
Erg interessant inderdaad,
Ik doe mathinc en building in een pass, en ik pas zelf een aantal regels toe maar deze heb ik zo uit het hoofd in elkaar gezet (zonder dus een set van regels what to do if), dat is het enige waarvan ik nog niet besloten had of het stable genoeg was, maar dat is nu dus oplosbaar. :)

openkat.nl al gezien?


Verwijderd

Topicstarter
Een hoop informatie, en ik ga er zeker gebruik van maken! Vooral de link van beetle71 (http://www.bazon.net/mishoo/articles.epl?art_id=1292) is handig.

Nu heb ik nog een laatste vraag betreffende selectie in een textarea, waarvan ik niet goed weet hoe ik er een begin mee moet maken. Als volgt:

code:
1
2
3
4
5
+-----------------------------------------------+
| Dit is [b]vet[/b] en dit is                   |
| [b][u]vetcursief[/u][/b]                      |
|                                               |
+-----------------------------------------------+

Als ik dubbelklik op "vet", wordt "vet" geselecteerd. Ik zoek naar een manier om ook tags die er om vet heen staan (in dit geval [b] en [/b]) mee te selecteren. Als ik op "vet en cursief" klik, moeten [b], [u], [/b] en [/u] ook meegeselecteerd worden.

Graag ideeen over hoe dit te bewerkstelligen :)

Verwijderd

Topicstarter
* kick :) *

  • beetle71
  • Registratie: Februari 2003
  • Laatst online: 24-11 16:50
Dat kun je doen door je text dan in drie delen te knippen, de tekst voor de selection start, de selectie en het stuk erachter. Eindigt het het eerste deel op [iets] en begint het derde deel met [/iets], dan kun je je selectionstart en selectionend aanpassen. MAAR! Ik denk dat dit niet helemaal handig is, de gebruiker zou dat natuurlijk ook nog wel eens een keertje NIET kunnen willen.

Daarnaast heb je ook nog eens een probleem als er meer dan 1 woord (of spaties) tussen de tags staan...
Pagina: 1