WYSIWYG i JS - Del 2, Visning af aktive formatering

Tags:    javascript
Skrevet af Bruger #4575 @ 05.10.2005

Oversigt


1. Indledning
2. Aktive formatering
3. Menu-klasse
...3.1. Indikation af formatering
4. Aktive skrift-type?
5. Afslutning


1. Indledning


Denne artikkel er 2. del af 3, omkring WYSIWYG tekst redigering i JS. Hvis du lige har læst første artikel i rækken, vil det evt. være en god ide lige at sætte dig lidt ind i hvordan de forskellige kommandoer virker osv., så du har et bedre overblik over formattering af teksten. Det gør det også lettere at forstå hvad det er, der sker i denne artikel, så det hele ikke bare bliver Copy-Paste

2. Aktive formatering


For at vise den aktive formatering er der 2 nye funktioner, som vi kommer til at beskæftige os med: document.queryCommandState og document.queryCommandValue.

Det første vi skal gøre for at kunne gøre os nogle forhåbninger om at vise den aktive formatering er, at opfange 2 af editorens events: OnKeyDown og OnClick, så formateringen opdaters, når brugeren ændrer cursorens position.
Det lyder i sig selv meget simpelt, men er faktisk lidt sværere end som så, hvis ikke man ved hvordan det skal gøres.:

Fold kodeboks ind/udKode 


Som i kan se, skal eventet ikke tilføjes direkte til iframen, men til iframens content-document, som vi tilgår via this.richEdit.document (Kan i huske, at vi satte this.richEdit til iframens content-window i sidste artikel? :))
Desuden skal der benyttes to forskellige funktioner til at tilføje eventet attachEvent virker i IE og addEventListener virker i FF.

Nu skal vi så have lavet selve indikations funktionen, hvilket vi gør (som tidligere nævnt) ved at benytte document.queryCommandState funktionen.
Det første vi gør er, at oprette et array, som indeholder de former for formatering, som editoren kan tilføje (Undtagen f.eks. skrift-type, -størrelse, tekst-farve og andre ting, som kan få angivet bestemte værdier og ikke bare til/fra).
I vores tilfælde fra sidste gang skal vi altså kun have fat i Bold, Italic og Underline:

Fold kodeboks ind/udKode 


Som du kan se, så er det pt. en ret ubrugelig måde vi viser den aktive formatering på, da det som regel vil genere mere end det vil gavne, at få en pop-up, med den aktive formatering hver gang man skriver et bogstav.

Vi mangler nu bare at tilføje indikationen af aktive formatering til applyStyle funktionen, som vi lavede sidst:

Fold kodeboks ind/udKode 


Lad os derfor gå videre, og se på en ny måde at bygge menuen op på.

3. Menu-klasse


For at få en smartere måde at vise den aktive formatering på, vil vi være nødsagede til at opbygge en ny menu - Personligt foretrækker jeg en menu, som består af billeder, og jeg vil derfor tage udgangspunkt i en sådan i dette eksempel. Jeg vil dog lade det være op til jer selv at udforme billederne til menuen, eller i kan benytte standard-ikonerne, som i kan downloade her fra udvikleren.dk (http://www.udvikleren.dk/redirect.php?id=7&mode=download).
For at min form for indikation skal virke, er det vigtigt at i bruger dem som .gif-billeder med gennemsigtig baggrund!

Men lad os da komme i gang - Først skal vi finde ud af hvordan vi vil angive hvilke knapper der skal være i menuen, og hvordan den skal integeres på siden - Jeg har valgt at oprette en <div id="EditorMenu"></div>, umiddelbart over editoren's div-tag, og benytte mig af et array til at definere knapperne:

Fold kodeboks ind/udKode 


Puh ha, det var en længere omgang, men jeg håber at i kan følge tanke gangen i det! :)
Nu skal vi så bare have afgjort hvordan man opretter klassen, hvilket er meget simpelt:

Fold kodeboks ind/udKode 


3.1. Indikation af formatering


For nu at indikere formateringen på knapperne skal vi nu tilbage til indicateStyle funktionen - Nu skal den ikke længere lave en pop-up, men ændre aStandard, aOver og aDown variablerne på knapperne, så den aktive formatering bliver vist:

Fold kodeboks ind/udKode 


Som i kan se, er også dette relativt simpelt at gøre, og menuen burde nu virke fuldt ud - med indikation af aktiv formatering :)
Hvis i vil tilføje flere formateringer, er det bare at tilføje dem i arrays'ne.

4. Aktive skrift-type?


Ganske kort - Hvis du vil finde den aktive skrift-type, -størrelse, -farve osv., hvor værdierne kan være andet en til/fra, skal du bruge document.queryCommandValue til at få fat i værdierne, men det vil jeg ikke komme nærmere ind på her - Det må du selv fifle med :)

5. Afslutning


Det var alt for denne gang..
Editoren er ikke længere så simpel, og du kan nu give den et langt flottere design end før, da du har mulighed for selv at designe knapperne..

Min editor ser indtil videre sådan ud:



Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (12)

User
Bruger #714 @ 07.10.05 11:37
Rigtig god artikel serie du har gang i der, men kunne man få dig til at linke til et sted hvor man kan se editoren i funktion? Har selv lige prøvet at rode med det, men da jeg er en klovn til JS kan jeg sku ikke helt få det til at virke, så hvis du ville linke til et virkende eksempel kunne det være alle tiders.
User
Bruger #4575 @ 07.10.05 21:02
Jeg skal overveje det til mit næste eksempel, men jeg vil ikke vise kilden til min egen editor frem - Er ved at udvikle et CMS ;)
User
Bruger #8337 @ 22.10.05 19:31
Jeg kan nu ikke få det til at virke.. har prøvet at cp det ind direkte, men den viser ingen menu... jeg har ændret stien til billederne!
User
Bruger #5092 @ 24.10.05 20:23
jeg kan heller ikke få det til at virke ?
den brokker sig over sParent er undefined.

kunne du ikke prøve at vise os et fuld eksempel som virker :)

ellers god atikel !...
User
Bruger #714 @ 26.10.05 20:31
Har samme problem som de andre efter flere timers kløen i hovedet, er dog nået frem til at de steder hvor den brokker sig over sParent skal der står sEditor. Men derudover får jeg ingen menu op (mangler der ikke noget til rent faktisk at udskrive billederne?) og i indicateStyle brokker den sig over at aButtons ikke eksisterer. Derudover er selve oprettelse af menu objektet placeret på en forkert side af en if blok.
User
Bruger #714 @ 26.10.05 21:26
Nå, efter lidt mere roderi og en del ændringer har jeg fået det til at virke nu, så jeg deler lige koden (den er lang!)

javascript delen:

function RichEdit(sEditor) {
// For at editoren skal virke, er det nødvendigt at document.designMode
// og document.getElementById er tilgængelige
this.oMenu = fMenu;
if(document.designMode && document.getElementById) this.bEditable = true;
else this.bEditable = false;


// Hvis vi alligevel ikke kan redigere dokumentet, kan resten af koden
// være ligegyldig.
if(!this.bEditable) {
alert('Din browser understøtter ikke WYSIWYG-editoren!');
return false;
}

// Opret en variabel til at håndtere iframet, via ID'et angivet i sEditor
this.richEdit = document.getElementById(sEditor).contentWindow;

// Tjek browser-typen
if(navigator.userAgent.toLowerCase().indexOf("msie") != -1) {
// Skift designMode til on (i IE)
this.richEdit.document.designMode = "on";
} else {
// I FF bruger vi en lidt anderledes fremgangsmåde
document.getElementById(sEditor);
}
if(document.attachEvent) {
this.richEdit.document.attachEvent('onclick', function(){richEdit.indicateStyle(sEditor);});
this.richEdit.document.attachEvent('onkeydown', function(){richEdit.indicateStyle(sEditor);});
} else if(document.addEventListener) {
this.richEdit.document.addEventListener('click', function(){richEdit.indicateStyle(sEditor);}, false);
this.richEdit.document.addEventListener('keydown', function(){richEdit.indicateStyle(sEditor);}, false);

}
}

RichEdit.prototype.applyStyle = function(sCommand, sOption) {
// Vi sikrer os, at editoren er i fokus, når vi tilføjer layoutet,
// da browseren ellers kan blive forvirret over hvor den skal tilføje
// layoutet.
this.richEdit.focus();

// Tilføj det ønskede layout
this.richEdit.document.execCommand(sCommand, false, sOption);

// Og slut af med igen at fokusere editoren, så brugeren kan
// skrive uforstyrret videre.

RichEdit.prototype.indicateStyle('Editor');
}
RichEdit.prototype.indicateStyle = function(sEditor) {
// Lav en variabel, som kan håndtere editoren
var oEditor = document.getElementById(sEditor).contentWindow.document;

// Lav et array, som indeholder de former for formatering, som editoren understøtter
// Denne gang laver vi det to-dimensionelt. Det første felt angiver hvilken
// Formateringstype vi snakker om (Bold, Italic, Underline osv.), og den
// Næste angiver hvilket nummer i rækken af knapper, den pågældende
// knap er (starter med 0!).
var aStyles = [["Bold", 0], ["Italic", 1], ["Underline", 2]];

// Løb arrayet igennem, og find ud af hvilke af formateringerne der er hhv. til/fra.
var sRes = "";
for(var i = 0; i < aStyles.length; i++) {
var oSrc = fMenu.aButtons[aStyles[1]];
if(oEditor.queryCommandState(aStyles[ i][0])) {
// Den pågældende formatering er slået til
/*fMenu.aButtons[aStyles[ i][1]].aStandard = fMenu.oActive;
fMenu.aButtons[aStyles[ i][1]].aOver = fMenu.oDown;
fMenu.aButtons[aStyles[ i][1]].aDown = fMenu.oDown;
*/
for(s in oSrc.aDown){
oSrc.style = oSrc.aDown;
}
} else
// Den pågældende formatering er ikke slået til
/*fMenu.aButtons[aStyles[ i][1]].aStandard = fMenu.oStandard;
fMenu.aButtons[aStyles[ i][1]].aOver = fMenu.oOver;
fMenu.aButtons[aStyles[ i][1]].aDown = fMenu.oDown;
*/
for(s in oSrc.aStandard){
oSrc.style = oSrc.aStandard;
}
}
}

function initialize() {
fMenu = new Menu("EditorMenu", 'Editor', [["bold.gif", "Bold"], ["italic.gif", "Italic"], ["underline.gif", "Underline"]])
// Husk at angive ID'et på den iframe, som skal indeholde editoren her
richEdit = new RichEdit('Editor');
}
function Menu(sParent, sEditor, aButtons) {
// Lav en variabel til at håndtere det div-tag, som knapperne skal "puttes ind i"
var oParent = document.getElementById(sParent);

// Opret et array, som senere kan bruges til at håndtere knapperne med
this.aButtons = new Array();

// De styles, som knapperne skal have ved de forskellige stadier
this.aStandard = {"background":"none"}
this.aOver = {"backgroundColor":"#0000FF"}
this.aDown = {"backgroundColor":"#00FF00"}
this.aActive = {"backgroundColor":"#FF0000"}

// Lav en knap for hvert felt i aButtons arrayet
for(var i = 0; i < aButtons.length; i++) {
// Lav knappen
var oBtn = document.createElement('img');
oBtn.src = aButtons[i ][0];

// Gem den handling, som knappen skal udføre
oBtn.sAction = aButtons[i ][1];

// Tilføj styles, som knappen benytter ved de forskellige stadier
// - Hvis denne aktiveres, så bliver aActive sat som aStandard og
// aDown sat som aOver & aDown.
oBtn.aStandard = this.aStandard;
oBtn.aOver = this.aOver;
oBtn.aDown = this.aDown;

// Indiker det aktive stadie (aStandard)
oBtn.sActive = "aStandard";

// Line-back til denne klasse, så vi kan kontakte den igen,
// når knappen aktiveres, og kan hente de nye styles
oBtn.oOwner = this;


// Tilføj events
if(document.attachEvent) {
oBtn.attachEvent('onmouseover', Menu.prototype.mouseOver);
oBtn.attachEvent('onmouseout', Menu.prototype.mouseOut);
oBtn.attachEvent('onmousedown', Menu.prototype.mouseDown);
oBtn.attachEvent('onmouseup', Menu.prototype.mouseUp);
oBtn.attachEvent('onclick', function(){Menu.prototype.click(sEditor);});
} else if(document.addEventListener) {
oBtn.addEventListener('onmouseover', Menu.prototype.mouseOver);
oBtn.addEventListener('onmouseout', Menu.prototype.mouseOut);
oBtn.addEventListener('onmousedown', Menu.prototype.mouseDown);
oBtn.addEventListener('onmouseup', Menu.prototype.mouseUp);
oBtn.addEventListener('onclick', function(e){Menu.prototype.click(e, sEditor);});
} else {
alert("øv");
}

// Tilføj en variabel til at håndtere knappen med i this.aButtons
this.aButtons.push(oBtn);
oParent.appendChild(oBtn);
}
}

Menu.prototype.mouseOver = function(e) {
// Sørg for at e (event) er defineret
if(!e) var e = window.event;

// Lav en variabel, som kan håndtere den knap, som udløste eventet
if(e.srcElement) var oSrc = e.srcElement;
else if(e.target) var oSrc = e.target;

// Opdater layoutet af knappen
for(var s in oSrc.aOver) oSrc.style = oSrc.aOver;
//alert("herre øv");
}

Menu.prototype.mouseOut = function(e) {
// Sørg for at e (event) er defineret
if(!e) var e = window.event;

// Lav en variabel, som kan håndtere den knap, som udløste eventet
if(e.srcElement) var oSrc = e.srcElement;
else if(e.target) var oSrc = e.target;

// Opdater layoutet af knappen
for(var s in oSrc.aStandard) oSrc.style = oSrc.aStandard;
}

Menu.prototype.mouseDown = function(e) {
// Sørg for at e (event) er defineret
if(!e) var e = window.event;

// Lav en variabel, som kan håndtere den knap, som udløste eventet
if(e.srcElement) var oSrc = e.srcElement;
else if(e.target) var oSrc = e.target;

// Opdater layoutet af knappen
for(var s in oSrc.aDown) oSrc.style = oSrc.aDown;
}

Menu.prototype.mouseUp = function(e) {
// Sørg for at e (event) er defineret
if(!e) var e = window.event;

// Lav en variabel, som kan håndtere den knap, som udløste eventet
if(e.srcElement) var oSrc = e.srcElement;
else if(e.target) var oSrc = e.target;
// Opdater layoutet af knappen
for(var s in oSrc.aOver) oSrc.style = oSrc.aOver;
richEdit.applyStyle(oSrc.sAction, '');
document.getElementById("Editor").contentWindow.focus();
}

Menu.prototype.click = function(e) {
/* // Sørg for at e (event) er defineret
if(!e) var e = window.event;

// Lav en variabel, som kan håndtere den knap, som udløste eventet
if(e.srcElement) var oSrc = e.srcElement;
else if(e.target) var oSrc = e.target;


// Kald funktionen til at opdatere layoutet af teksten
richEdit.applyStyle(oSrc.sAction, '');*/
}

HTML delen:

<body onload="initialize();">
<div id="EditorMenu"></div>
<iframe id="Editor"></iframe>


Sådan, koden er sikkert møg grim og en masse andre ting, men den virker :D (i hvert fald i IE, skal lige se hvad firefox siger til den)
User
Bruger #714 @ 26.10.05 22:20
Nå undskyld for lange poster, men vil jo gerne dele koden, her er en opdateret kode der også virker i firefox, igen i skal ikke hakke ned på mig hvis noget kunne gøres nemmere, jeg er ikke god til javascript, men foretog bare nogle ændringer på baggrund af hvad der virkede og hvad jeg kunne google mig fremtil, men en opdateret js del følger:

function RichEdit(sEditor) {
// For at editoren skal virke, er det nødvendigt at document.designMode
// og document.getElementById er tilgængelige
this.oMenu = fMenu;
if(document.designMode && document.getElementById) this.bEditable = true;
else this.bEditable = false;


// Hvis vi alligevel ikke kan redigere dokumentet, kan resten af koden
// være ligegyldig.
if(!this.bEditable) {
alert('Din browser understøtter ikke WYSIWYG-editoren!');
return false;
}
// Opret en variabel til at håndtere iframet, via ID'et angivet i sEditor
this.richEdit = document.getElementById(sEditor).contentWindow;

// Tjek browser-typen
if(document.all) {
// Skift designMode til on (i IE)
this.richEdit.document.designMode = "on";
} else{
// I FF bruger vi en lidt anderledes fremgangsmåde
document.getElementById(sEditor).contentDocument.designMode="on";
}
if(document.all) {
this.richEdit.document.attachEvent('onclick', function(){richEdit.indicateStyle(sEditor);});
this.richEdit.document.attachEvent('onkeydown', function(){richEdit.indicateStyle(sEditor);});
} else if(document.addEventListener) {
this.richEdit.document.addEventListener('click', function(){richEdit.indicateStyle(sEditor);}, false);
this.richEdit.document.addEventListener('keydown', function(){richEdit.indicateStyle(sEditor);}, false);

}
}

RichEdit.prototype.applyStyle = function(sCommand, sOption) {
// Vi sikrer os, at editoren er i fokus, når vi tilføjer layoutet,
// da browseren ellers kan blive forvirret over hvor den skal tilføje
// layoutet.
this.richEdit.focus();

// Tilføj det ønskede layout
this.richEdit.document.execCommand(sCommand, false, sOption);

// Og slut af med igen at fokusere editoren, så brugeren kan
// skrive uforstyrret videre.

RichEdit.prototype.indicateStyle('Editor');
}
RichEdit.prototype.indicateStyle = function(sEditor) {
// Lav en variabel, som kan håndtere editoren
var oEditor = document.getElementById(sEditor).contentWindow.document;

// Lav et array, som indeholder de former for formatering, som editoren understøtter
// Denne gang laver vi det to-dimensionelt. Det første felt angiver hvilken
// Formateringstype vi snakker om (Bold, Italic, Underline osv.), og den
// Næste angiver hvilket nummer i rækken af knapper, den pågældende
// knap er (starter med 0!).
var aStyles = [["Bold", 0], ["Italic", 1], ["Underline", 2]];

// Løb arrayet igennem, og find ud af hvilke af formateringerne der er hhv. til/fra.
var sRes = "";
for(var i = 0; i < aStyles.length; i++) {
var oSrc = fMenu.aButtons[aStyles[1]];
if(oEditor.queryCommandState(aStyles[ i][0])) {
// Den pågældende formatering er slået til
//fMenu.aButtons[aStyles[ i][1]].aStandard = fMenu.oActive;
//fMenu.aButtons[aStyles[ i][1]].aOver = fMenu.oDown;
//fMenu.aButtons[aStyles[ i][1]].aDown = fMenu.oDown;


for(s in oSrc.aDown){
oSrc.style = oSrc.aDown;
}
} else
// Den pågældende formatering er ikke slået til
//fMenu.aButtons[aStyles[ i][1]].aStandard = fMenu.oStandard;
//fMenu.aButtons[aStyles[ i][1]].aOver = fMenu.oOver;
//fMenu.aButtons[aStyles[ i][1]].aDown = fMenu.oDown;

for(s in oSrc.aStandard){
oSrc.style = oSrc.aStandard;
}
}
}

function initialize() {
fMenu = new Menu("EditorMenu", 'Editor', [["bold.gif", "Bold"], ["italic.gif", "Italic"], ["underline.gif", "Underline"]])
// Husk at angive ID'et på den iframe, som skal indeholde editoren her
richEdit = new RichEdit('Editor');


}

function Menu(sParent, sEditor, aButtons) {

// Lav en variabel til at håndtere det div-tag, som knapperne skal "puttes ind i"
var oParent = document.getElementById(sParent);

// Opret et array, som senere kan bruges til at håndtere knapperne med
this.aButtons = new Array();

// De styles, som knapperne skal have ved de forskellige stadier
this.aStandard = {"background":"none"}
this.aOver = {"backgroundColor":"#0000FF"}
this.aDown = {"backgroundColor":"#00FF00"}
this.aActive = {"backgroundColor":"#FF0000"}
// Lav en knap for hvert felt i aButtons arrayet
for(var i = 0; i < aButtons.length; i++) {
// Lav knappen
var oBtn = document.createElement('img');
oBtn.src = aButtons[i ][0];

// Gem den handling, som knappen skal udføre
oBtn.sAction = aButtons[i ][1];

// Tilføj styles, som knappen benytter ved de forskellige stadier
// - Hvis denne aktiveres, så bliver aActive sat som aStandard og
// aDown sat som aOver & aDown.
oBtn.aStandard = this.aStandard;
oBtn.aOver = this.aOver;
oBtn.aDown = this.aDown;

// Indiker det aktive stadie (aStandard)
oBtn.sActive = "aStandard";

// Line-back til denne klasse, så vi kan kontakte den igen,
// når knappen aktiveres, og kan hente de nye styles
oBtn.oOwner = this;


// Tilføj events
if(document.attachEvent) {
oBtn.attachEvent('onmouseover', Menu.prototype.mouseOver);
oBtn.attachEvent('onmouseout', Menu.prototype.mouseOut);
oBtn.attachEvent('onmousedown', Menu.prototype.mouseDown);
oBtn.attachEvent('onmouseup', Menu.prototype.mouseUp);
oBtn.attachEvent('onclick', function(){Menu.prototype.click(sEditor);});
} else if(document.addEventListener) {
oBtn.addEventListener('mouseover', Menu.prototype.mouseOver, false);
oBtn.addEventListener('mouseout', Menu.prototype.mouseOut, true);
oBtn.addEventListener('mousedown', Menu.prototype.mouseDown, true);
oBtn.addEventListener('mouseup', Menu.prototype.mouseUp, true);
oBtn.addEventListener('click', function(e){Menu.prototype.click(e, sEditor);}, true);
}
// Tilføj en variabel til at håndtere knappen med i this.aButtons
this.aButtons.push(oBtn);
oParent.appendChild(oBtn);
}

}

Menu.prototype.mouseOver = function(e) {
// Sørg for at e (event) er defineret
if(!e) var e = window.event;

// Lav en variabel, som kan håndtere den knap, som udløste eventet
if(e.srcElement) var oSrc = e.srcElement;
else if(e.target) var oSrc = e.target;
else alert("øv");
// Opdater layoutet af knappen
for(var s in oSrc.aOver) oSrc.style = oSrc.aOver;
//alert("herre øv");
}

Menu.prototype.mouseOut = function(e) {
// Sørg for at e (event) er defineret
if(!e) var e = window.event;

// Lav en variabel, som kan håndtere den knap, som udløste eventet
if(e.srcElement) var oSrc = e.srcElement;
else if(e.target) var oSrc = e.target;

// Opdater layoutet af knappen
for(var s in oSrc.aStandard) oSrc.style = oSrc.aStandard;
}

Menu.prototype.mouseDown = function(e) {
// Sørg for at e (event) er defineret
if(!e) var e = window.event;

// Lav en variabel, som kan håndtere den knap, som udløste eventet
if(e.srcElement) var oSrc = e.srcElement;
else if(e.target) var oSrc = e.target;

// Opdater layoutet af knappen
for(var s in oSrc.aDown) oSrc.style = oSrc.aDown;
}

Menu.prototype.mouseUp = function(e) {
// Sørg for at e (event) er defineret
if(!e) var e = window.event;

// Lav en variabel, som kan håndtere den knap, som udløste eventet
if(e.srcElement) var oSrc = e.srcElement;
else if(e.target) var oSrc = e.target;
// Opdater layoutet af knappen
for(var s in oSrc.aOver) oSrc.style = oSrc.aOver;
richEdit.applyStyle(oSrc.sAction, '');
document.getElementById("Editor").contentWindow.focus();
}

Menu.prototype.click = function(e) {
// Sørg for at e (event) er defineret
//if(!e) var e = window.event;

// Lav en variabel, som kan håndtere den knap, som udløste eventet
//if(e.srcElement) var oSrc = e.srcElement;
//else if(e.target) var oSrc = e.target;


// Kald funktionen til at opdatere layoutet af teksten
//richEdit.applyStyle(oSrc.sAction, '');
}


Enjoy :D
User
Bruger #5092 @ 28.10.05 10:07
Jeg synes den er fed, fordi jeg for et godt indblik i hvordan tingende hænger sammen, og så kan man fin justere den til ens behov med ekstra features :)
User
Bruger #4575 @ 12.11.05 11:55
Jeg kan se at der er stemning for et fuldt eksempel - Men... Det vil kræve at jeg laver en editor fra bunden, hvilket i sig selv vil tage noget tid - tid som jeg desværre ikke har til rådighed lige for tiden...
Men jeg skal se hvad jeg kan gøre.. så kan jeg lige smide et link til den i ressourcer...
User
Bruger #9674 @ 07.12.06 10:38
Endnu en god artikkel, har ikke lige tjekket op på koden, men ser rimelig fornuftigt ud.

Ville godt lige se hvorda du fikser så man kan se den originale kode. Kan se du har et tab i dit billede til sidst som viser "source", men det kan være det kommer i næste artikkel? Har jeg ikke lige tjekket...


God artikkel som giver et god indblik i tingene.
User
Bruger #11047 @ 25.12.06 16:22
:roll:
Fold kodeboks ind/udKode 
User
Bruger #13203 @ 16.04.09 09:57
Kunne man få et link til billederne der virkede?
Du skal være logget ind for at skrive en kommentar.
t