Een WYSIWYG editor voor IE, FF én Opera

Pagina: 1
Acties:
  • 115 views sinds 30-01-2008
  • Reageer

  • Skit3000
  • Registratie: Mei 2005
  • Laatst online: 15:41
Hallo,

Al een poosje ben ik bezig met een What You See Is What You Get editor te maken met javascript die in alle browsers zou moeten werken (mits ze de HTML DOM ondersteunen). Je kan tekst typen, verwijderen met backspace en delete en je kunt enters geven. Er zitten nog aardig wat bugs in, je hebt bijvoorbeeld geen caret (knipperende cursor), als je op backspace of delete drukt bij het begin of einde van een HTML tag dan wist die de halve tag en de loops die gebruikt worden om te achterhalen waar de gebruiker heeft geklikt moeten stukken sneller kunnen (door middel van regexp).

Omdat ik zelf niet echt meer er mee bezig ben maar sommige mensen er misschien wat aan hebben, plaats ik hier wel de code en een voorbeeldje. Als je verbeteringen ofzo hebt, kwak het maar neer en met een beetje mazzel kunnen binnenkort mensen met Opera óók gewoon WYSIWYG gebruiken... :)

Voorbeeld: http://www.vanderhoorn.info/richtext.html

code:
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
<html>
    <head>
        <style>
            .vElement_input
            {
                border-left: 2px solid #828177;
                border-top: 2px solid #828177;
                border-right: 1px solid #E2E2E0;
                border-bottom: 1px solid #E2E2E0;
                font: 8pt Tahoma;
                cursor: text;
                padding: 2px 5px 2px 5px;
        }
        </style>
        <script type="text/javascript">
            
            function getOpenTags(input)
            {
                var tempArray = new Array();
                var i = 0;
                var tempTags = "";
                while (i < input.length)
                {
                    if (input.substr(i, 1) == "<")
                    {
                        while (input.substr(i, 1) != ">")
                        {
                            tempTags += input.substr(i, 1);
                            i++;
                        }
                        tempTags += input.substr(i, 1);
                    }
                    i++;
                }
                return tempTags;
            }
            
            function textclick(element, e)
            {
                // Remember where the user clicked
                var clickLeft = e.clientX - element.offsetLeft;
                var clickTop = e.clientY - element.offsetTop;
                
                // Create a temporary element which has the same size as the original div, to
                // be able to depend the row on which is clicked
                var tempDiv = document.createElement("DIV");
                tempDiv.className = "vElement_input";
                tempDiv.style.width = element.style.width;
                document.body.appendChild(tempDiv);
                
                var tempUntilLastRow = 0;
                var tempHeight = 0;
                
                var tempValue = element.innerHTML + "<p>&nbsp;</p>";
                var tempCounter = 0;
                
                // Determine the row on which is clicked with this loop. Please note that this loop
                // can be speed'n up by replacing tempCounter++; with tempCounter += 20; or something
                // like that, after which you create a second loop which will count backwards to get
                // the exact character number
                while (tempHeight < clickTop)
                {
                    tempDiv.innerHTML = tempValue.substr(0, tempCounter);
                    // Check if a new row has been created
                    if (tempHeight != tempDiv.offsetHeight)
                    {
                        // If there is a new row, remember after how many character it happened so
                        // we can determine with which character the row started
                        tempUntilLastRow = tempCounter;
                    }
                    tempHeight = tempDiv.offsetHeight;
                    tempCounter++;
                }
                // Remove the temporary DIV
                tempDiv.parentNode.removeChild(tempDiv);
                
                // New rows always start with a complete word, search the beginning of the word
                // and use it to put the remaining characters of the original text in tempValue
                tempCounter = tempCounter - 2;
                while (tempValue.substr(tempCounter, 1).match(/\w/) && (tempCounter > 0))
                {
                    tempCounter--;
                }
                tempCounter++;
                var tempTags = getOpenTags(tempValue.substr(0, tempCounter));
                tempValue = tempValue.substr(tempCounter);
                
                // Create a new DIV again, but this time, use the x-value of the mouseclick
                // as the width of it
                var tempDiv = document.createElement("DIV");
                tempDiv.className = "vElement_input";
                tempDiv.style.width = clickLeft + "px";
                tempDiv.innerHTML = "";
                document.body.appendChild(tempDiv);
                // Count the number of characters which will fit into the DIV until a new row
                // will be created
                tempChar = 1;
                var tempHeight = 0;
                var tempWidth = tempDiv.offsetWidth;
                while ((tempDiv.offsetHeight <= tempHeight || tempHeight == 0) && tempWidth == tempDiv.offsetWidth)
                {
                    tempDiv.innerHTML = tempTags + tempValue.substr(0, tempChar);
                    if (tempHeight == 0)
                    {
                        tempHeight = tempDiv.offsetHeight;
                    }
                    tempChar++;
                }
                tempChar--;
                
                // Remove the DIV
                tempDiv.parentNode.removeChild(tempDiv);
                
                // Return the position on which the user clicked
                return (tempCounter + tempChar);
            }
            
            function keypress(e)
            {
                // Use the onkeypress event to determine if SHIFT is hold or not
                var element = window["selectedelement"];
                if (!element)
                {
                    return;
                }
                var character = String.fromCharCode(e.keyCode || e.which);
                element.innerHTML = element.innerHTML.substr(0, element.caret) + character + element.innerHTML.substr(element.caret);
                element.caret++;
            }
            
            function keydown(e)
            {
                // Use onkeydown to detect all other (non visible) characters which are pressed
                var element = window["selectedelement"];
                if (!element)
                {
                    return;
                }
                var character = (e.keyCode || e.which);
                if (character == 8)
                {
                    // Backspace key
                    element.innerHTML = element.innerHTML.substr(0, element.caret - 1) + element.innerHTML.substr(element.caret);
                    element.caret--;
                }
                else if (character == 46)
                {
                    // Delete key
                    element.innerHTML = element.innerHTML.substr(0, element.caret) + element.innerHTML.substr(element.caret + 1);
                }
                else if (character == 10 || character == 13)
                {
                    // Enter key
                    element.innerHTML = element.innerHTML.substr(0, element.caret) + "<br>" + element.innerHTML.substr(element.caret);
                    element.caret = element.caret + 3;
                }
            }
            
        </script>
    </head>
    <body>
        <script type="text/javascript">
            // Add a DIV to the screen to test
            var myDiv = document.createElement("DIV");
            myDiv.className = "vElement_input";
            myDiv.style.width = "300px";
            myDiv.style.height = "200px";
            myDiv.innerHTML = "This is some text <h1>to test if the <u>function<\/u> is working<\/h1> like it should. In <b>most cases it does</b>, but when you enter text which has another size then the other text, it will stop functioning. <font color=\"red\">It also works with colored text.<\/font> It does? Yes, it does ;)";
            document.body.appendChild(myDiv);
            
            // Also create an editbox which will hold the focus, to prevent
            // that Opera or other browsers might see keyboard input as hotkeys
            // Make sure this editbox will be hidden for the user
            var tempInput = document.createElement("INPUT");
            tempInput.style.position = "absolute";
            tempInput.style.width = "0px";
            tempInput.style.height = "0px";
            tempInput.style.top = "-100px";
            document.body.appendChild(tempInput);
            
            myDiv.onmouseup = function (e)
            {
                // Check where the user clicked
                if (!e)
                {
                    var e = window.event;
                }
                this.caret = textclick(this, e);
                window["selectedelement"] = this;
                tempInput.focus();
            }
            
            document.onkeypress = function (e)
            {
                if (!e)
                {
                    var e = window.event;
                }
                keypress(e);
            }
            
            document.onkeydown = function (e)
            {
                if (!e)
                {
                    var e = window.event;
                }
                keydown(e);
            }
            
        </script>
    </body>
</html>

  • frickY
  • Registratie: Juli 2001
  • Laatst online: 23-02 17:28
Als ik me niet vergis zijn er tientallen open-source WYSIWYG-editors beschikbaar, welke ook in Opera werken. Om een voorbeeld te noemen; TinyMCE

  • Skit3000
  • Registratie: Mei 2005
  • Laatst online: 15:41
TinyMCE werkt niet met Opera, omdat Opera de designMode property (van Internet Explorer) en de contentEditable property (W3c) allebei niet werken. In plaats daarvan krijg je met veel richtext editors in Opera gewoon de HTML tekst te zien.

Opera 9 gaat trouwens volgens mij wél contentEditable ondersteunen, maar het kan nog even duren voor deze uitkomt én lang niet iedereen stapt gelijk over.

[ Voor 25% gewijzigd door Skit3000 op 15-03-2006 13:35 ]


Verwijderd

Ik ben ook al een poosje bezig met wysiwyg editors en ik kan je vertellen dat je al twee foute aannames hebt. 1.) Opera ondersteunt in versie 9 wel designMode. 2.) contentEditable is geen w3c property, maar gewoon bedacht door het Internet Explorer team.

Als laatste opmerking moet je goed beseffen dat er belangrijke verschillen zijn tussen designMode en contentEditable.

Verwijderd

/me schreeuwt FCKeditor

  • Victor
  • Registratie: November 2003
  • Niet online
Ik zit op dit moment ook met het probleem van de beruchte rich text editor. Ik heb een editor nodig die semantisch correcte XHTML uitspuugt, en dit blijkt een grotere opgave dan ik aanvankelijk gedacht had. Natuurlijk heb ik al gekeken naar bestaande editors, maar geen van allen voldoen. Ze bieden allemaal mooie foefjes, maar zijn daarom nodeloos groot en omslachtig in gebruik. Ik zoek een editor die enkel en alleen HTML elementen toe kan voegen, geen opmaak (styling dus) relateerde informatie.

Hiermee kom ik direct bij het volgende probleem: je kunt prima een editor schrijven op basis van de rich text controls in IE en FF die geen functionaliteit biedt om bijvoorbeeld een tekst kleurtje te veranderen, maar aangezien de editor een onderdeel is van de browser met functionaliteit die buiten de controle van de ontwikkelaar ligt, zijn ze per definitie niet te vertrouwen. Een goed voorbeeld hiervan is het kopieëren van tekst uit Microsoft Word naar zo'n rich text control. Hierbij wordt de befaamde Word "HTML" meegestuurd om de opmaak van de tekst te behouden. Niet bepaald wat je wilt, aangezien nu heel je pagina vol staat met inline styles en proprietary troep van Ome Bill. Nu valt dit wel weer af te vangen door de HTML te controleren op dit soort ongein, maar er moet toch een snellere manier zijn.

Ik twijfel op dit moment aan de haalbaarheid hiervan in JavaScript, en overweeg zelfs om een editor te schrijven in Flash/ActionScript, aangezien ik hierbij de volledige controle over m'n HTML kan behouden. Echt fraai is alleen anders...

  • HawVer
  • Registratie: Februari 2002
  • Laatst online: 14-02 19:36
Werkt die wel in opera?

http://hawvie.deviantart.com/


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Ik heb het even geprobeerd in Opera, maar backspace, del, pijltjes en andere toetsen gaan hier nogal...erm...fout ;)

Mijn advies: wacht op Opera 9 voordat je het wiel voor niks zit uit te vinden...

[ Voor 54% gewijzigd door RobIII op 16-03-2006 13:06 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


  • orf
  • Registratie: Augustus 2005
  • Nu online

orf

Ik twijfel op dit moment aan de haalbaarheid hiervan in JavaScript, en overweeg zelfs om een editor te schrijven in Flash/ActionScript, aangezien ik hierbij de volledige controle over m'n HTML kan behouden. Echt fraai is alleen anders...
Dat is precies wat ik heb gedaan: http://www.avviso.nl/texteditor/
Ik gebruik 2 kolommen in een databasetabel; één voor de Flash 'html', met font tags e.d. en één kolom met html/inline css opmaak. Een functie haalt de tekst door een aantal regexen en replaced daarmee de html. Plan is wel om gelijke inline css om te zetten naar classes, maar dat zal nog wat puzzelen worden.

Ik moet wel opmerken dat FCK functies ondersteund om Word 'html' om te zetten naar validerende HTML. De opmaak bevat naar mijn zin te veel divjes, maar het werkt wel crossbrowser en valideert.

  • Victor
  • Registratie: November 2003
  • Niet online
orf schreef op donderdag 16 maart 2006 @ 13:29:
Ik moet wel opmerken dat FCK functies ondersteund om Word 'html' om te zetten naar validerende HTML. De opmaak bevat naar mijn zin te veel divjes, maar het werkt wel crossbrowser en valideert.
Crossbrowser en validatie geloof ik wel, dat valt zelfs met de meest brakke HTML nog voor elkaar te krijgen. Het gaat mij om de kwaliteit van de HTML die er gegenereerd wordt. Deze moet semantisch correct zijn, en ieder gebruikt element moet te verantwoorden zijn. Geen DIV's, SPAN's of andere ellende terwijl het enige wat ik wil een paragraaf is.

Heb je die editor overigens zelf geschreven? Want ik moet zeggen dat het er wel netjes uitziet!

  • orf
  • Registratie: Augustus 2005
  • Nu online

orf

Die editor heb ik geschreven in SWiSH max (let the flames begin) :)
Als je in deze versie de broncode ziet, dan is het huilen; in de nieuwste versie laat ik de broncode daarom maar niet zien (dan kan de gebruiker ook niet handmatig broncode wijzigen).

De Flash player zet in de HTML de attributen altijd in dezelfde volgorde; daarom is het replacen van deze niet zo moeilijk en kun je er redelijk semantische HTML uitkrijgen. Zo gebruik ik bijvoorbeeld voor een <h1> een bepaalde font-grootte en bold in de editor. Bij het replacen wordt dat omgezet naar een <h1> tag. (het replacen doe ik trouwens met PHP)

Verwijderd

orf schreef op donderdag 16 maart 2006 @ 13:42:
Die editor heb ik geschreven in SWiSH max (let the flames begin) :)
Als je in deze versie de broncode ziet, dan is het huilen; in de nieuwste versie laat ik de broncode daarom maar niet zien (dan kan de gebruiker ook niet handmatig broncode wijzigen).

De Flash player zet in de HTML de attributen altijd in dezelfde volgorde; daarom is het replacen van deze niet zo moeilijk en kun je er redelijk semantische HTML uitkrijgen. Zo gebruik ik bijvoorbeeld voor een <h1> een bepaalde font-grootte en bold in de editor. Bij het replacen wordt dat omgezet naar een <h1> tag. (het replacen doe ik trouwens met PHP)
Broncode is geen kermis inderdaad, zou dat niet op te lossen zijn? Dan wordt het een waardevolle editor namelijk. Al die paragraven en font-tags lijken me flink overbodig.

  • orf
  • Registratie: Augustus 2005
  • Nu online

orf

Broncode is geen kermis inderdaad, zou dat niet op te lossen zijn? Dan wordt het een waardevolle editor namelijk. Al die paragraven en font-tags lijken me flink overbodig.
Die worden er allemaal door PHP uitgehaald. :)

  • Justice
  • Registratie: Maart 2001
  • Laatst online: 07-08-2025
Kijk hier eens:
http://www.themaninblue.com/experiment/widgEditor/

werkt goed in opera. Niet dat het verkeerd is om een eigen te bouwen, als leerervaring.

Human Bobby


  • orf
  • Registratie: Augustus 2005
  • Nu online

orf

Werkt die ook in Safari? Dat was mijn grootste reden om een Flash editor te bouwen.

  • Justice
  • Registratie: Maart 2001
  • Laatst online: 07-08-2025
Ho wacht ik teste hier met opera 9, even zoeken.

Volgens een post (http://www.themaninblue.c...perspective/2005/01/27/):
Peter Bex commented on 11 March 2006 @ 05:52

I got it to work under Safari (modulo some minor selection problems) by simply changing widgToolbar.prototype.addButton. Instead of hooking the widgToolBarAction to the onmouseclick action, hook it to the onmousedown action. That's it!

See also http://dartblogs.com/lambda/archives/002919.html

Too bad Safari is so broken...

Thanks for your great editor. It's wonderful in its simplicity and it's about the only elegantly coded WYSIWYG HTML-editor out there. Great work!

[ Voor 87% gewijzigd door Justice op 16-03-2006 15:00 ]

Human Bobby


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Justice schreef op donderdag 16 maart 2006 @ 14:46:
Kijk hier eens:
http://www.themaninblue.com/experiment/widgEditor/

werkt goed in opera. Niet dat het verkeerd is om een eigen te bouwen, als leerervaring.
Bij mij in Opera 8.52 gebeurt er anders weinig spannends hoor :?

/edit:
Justice schreef op donderdag 16 maart 2006 @ 14:54:
Ho wacht ik teste hier met opera 9, even zoeken
Aaaaaah :P

[ Voor 22% gewijzigd door RobIII op 16-03-2006 14:55 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


  • Justice
  • Registratie: Maart 2001
  • Laatst online: 07-08-2025
volgens mij ondersteunen verder geen 1 HTML editors in html opera 8 omdat die dus dat gebrek aan ondersteuning voor contentedible heeft.
(aan de hand van wat google werk bijvoorbeeld [google=widgeditor opera 8]

[ Voor 26% gewijzigd door Justice op 16-03-2006 15:04 ]

Human Bobby


  • eghie
  • Registratie: Februari 2002
  • Niet online

eghie

Spoken words!

Volgens mij ondersteund Opera 8 wel veel meer niet. Een collega van me gebruikt die nog wel eens en vind soms dat hij erg brak renderd.

Ik wil ooit nog een CMSje gaan bouwen en wil ik zelf ook zo'n HTML editor gaan bouwen, die ook alleen maar (X)HTML complaint code terug geeft. Ook een leuk leerproject.

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
eghie schreef op donderdag 16 maart 2006 @ 15:48:
Ik wil ooit nog een CMSje gaan bouwen en wil ik zelf ook zo'n HTML editor gaan bouwen, die ook alleen maar (X)HTML complaint code terug geeft. Ook een leuk leerproject.
offtopic:
Compliant ;)
Compliant = "voldoen aan de standaard"... iets in die richting.. vrij vertaald.
Complaint = klacht

TinyMCE kan heel mooi (X)HTML maken. Neemt niet weg dat het geen leuk leerproject is inderdaad ;)

[ Voor 12% gewijzigd door RobIII op 16-03-2006 15:51 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Verwijderd

orf schreef op donderdag 16 maart 2006 @ 14:27:
[...]


Die worden er allemaal door PHP uitgehaald. :)
Ik snap natuurlijk dat dat mogelijk is :) Maar het gaat toch om het idee om gewoon een goede editor te hebben die geen ranzige code spit. Daarbij denk ik dat op deze manier zo af en toe toch ranzige tags erdoorheen komen. Is het overigens mogelijk om in plaats van zo'n 'maak-link-venstertje' daar gewoon een HTML-pagina in te laden?

edit:

WidgEditor is al een jaar niet geupdate terwijl deze nog vol bugs zit, beetje jammer.

[ Voor 12% gewijzigd door Verwijderd op 16-03-2006 17:19 ]


  • orf
  • Registratie: Augustus 2005
  • Nu online

orf

Maar het gaat toch om het idee om gewoon een goede editor te hebben die geen ranzige code spit.
Zodra je in Flash een input field HTML text laat renderen zet Flash de <textformat> tags in; zodra je iets bold maakt zal Flash er opnieuw allerlei tags omheen zetten. In eerste instantie liet ik Flash zelf replaces doen in de code, maar PHP doet dat 100x sneller dan Flash. Nu kan ik gewoon op ieder moment de html-text uit de editor trekken met javascript als bijvoorbeeld een form gesubmit wordt. In mijn CMS voeg ik deze editor op dezelfde wijze toe als dat ik een simpele textarea toevoeg.
Is het overigens mogelijk om in plaats van zo'n 'maak-link-venstertje' daar gewoon een HTML-pagina in te laden?
Wat bedoel je precies?

Verwijderd

Flash malfunction dus :) Maar hier is het eigenlijk ook niet voor gemaakt natuurlijk.

Betreft die link, zou het makkelijk zijn als je daar wat meer mee kan dan alleen een URL intypen. Mijn vraag was dus of het mogelijk is om ipv zo'n dialog-window een HTML-pagina (server-side geparsed) te tonen als popup.

  • orf
  • Registratie: Augustus 2005
  • Nu online

orf

Mijn vraag was dus of het mogelijk is om ipv zo'n dialog-window een HTML-pagina (server-side geparsed) te tonen als popup.
Sorry, ik snap het nog steeds niet :?
Je kan wel een iframe over een Flash movie heenleggen en daar in tonen wat je wilt (al dan niet serverside geparsed), maar ik snap het idee niet zo; in elke editor moet je toch gewoon een url in een venstertje intypen om van een geselecteerd stukje tekst een link te maken?

Verwijderd

Het gaat er om dat je dan meer kunt, bijvoorbeeld een overzicht weergeven van alle andere pagina's van de website om zo met 2 keer klikken deze pagina's automatisch te kunnen koppelen.

  • Skit3000
  • Registratie: Mei 2005
  • Laatst online: 15:41
Ja, er zijn wel WYSIWYG editors voor Opera, maar die werken dus alleen maar met Opera 9. De reden dat ik met dit project ben begonnen, is juist omdat veel mensen die Opera gebruiken, versie 9 nog niet hebben. Daarnaast werkt dit script ook in alle andere browsers die wél de HTML DOM ondersteunen en níet contentEditable of designMode... :)
Pagina: 1