17.07.2013 Views

JavaScript - jososoft - Jørgen Sørensen

JavaScript - jososoft - Jørgen Sørensen

JavaScript - jososoft - Jørgen Sørensen

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>JavaScript</strong><br />

Grundlæggende elementer<br />

<strong>Jørgen</strong> <strong>Sørensen</strong><br />

<strong>jososoft</strong> software development<br />

© 1998-2007 <strong>Jørgen</strong> <strong>Sørensen</strong>


<strong>JavaScript</strong> <strong>Jørgen</strong> <strong>Sørensen</strong> js@<strong>jososoft</strong>.dk<br />

Indholdsfortegnelse<br />

Introduktion …………………………………………………………………………………………………………………………<br />

Det første program ………………………………………………………………………………………………………………<br />

Variabler ………………………………………………………………………………….….………………………………………<br />

Operatorer ……………………………………………………………………………………………………………………………<br />

Objekthierarkiet i <strong>JavaScript</strong> ………………………………………………………………………………………………<br />

document objektet ………………………………………………………………………………………………………………<br />

window objektet …………………………………………………………………………………………………………………<br />

frames objektet ……………………………………………………………………………………………………………………<br />

location objektet …………………………………………………………………………………………………………………<br />

history objektet ……………………………………………………………………………………………………………………<br />

navigator objektet ………………………………………………………………………………………………………………<br />

Date objektet ………………………………………………………………………………………………………………………<br />

Math objektet ………………………………………………………………………………………………………………………<br />

String objektet ……………………………………………………………………………………………………………………<br />

Kontrolstrukturer …………………………………………………………………………………………………………………<br />

Funktioner ……………………………………………………………………………………………………………………………<br />

Hændelser ……………………………………………………………………………………………………………………………<br />

Validering af formularer ………………………………………………………………………………………………………<br />

Scriptfiler ……………………………………………………………………………………………………………………………..<br />

Side 2<br />

3<br />

3<br />

4<br />

4<br />

5<br />

5<br />

6<br />

7<br />

8<br />

8<br />

8<br />

9<br />

9<br />

9<br />

10<br />

12<br />

13<br />

14<br />

16


<strong>JavaScript</strong> <strong>Jørgen</strong> <strong>Sørensen</strong> js@<strong>jososoft</strong>.dk<br />

Introduktion<br />

<strong>JavaScript</strong> er et sprog, der kan give en hjemmeside mere funktionalitet og gøre den interaktiv,<br />

så den reagerer på læserens handlinger. <strong>JavaScript</strong> kan bl.a. bruges til validering af formularer<br />

før disse sendes til en server, hvilket er med til at nedsætte trafikken på internettet og samtidig<br />

vil en lokal validering være hurtigere.<br />

<strong>JavaScript</strong> afvikles lokalt i klientens browser og kræver ikke forbindelse til en server. Kombinationen<br />

af Html, CSS og <strong>JavaScript</strong> kaldes ofte "Dynamisk Html".<br />

<strong>JavaScript</strong> er udviklet af Netscape og hed oprindeligt LiveScript. <strong>JavaScript</strong> kan fortolkes af alle<br />

browsere i modsætning til VBScript og JScript, der begge er Microsoft opfindelser.<br />

<strong>JavaScript</strong> er et scriptsprog, der – i forhold til rigtige programmeringssprog – har en relativ<br />

simpel syntaks og kun få regler. Forskelle og ligheder er blandt andet:<br />

• <strong>JavaScript</strong> kode er fortolket kode, den kompileres ikke til f.eks. exe.filer eller dll.filer<br />

• <strong>JavaScript</strong> kode er ofte integreret i html-dokumenter<br />

• <strong>JavaScript</strong> variabler erklæres ikke og ej heller deres type<br />

• <strong>JavaScript</strong> er objektbaseret, bruger indbyggede objekter<br />

• <strong>JavaScript</strong>s objektreferencer kontrolleres under afvikling, dvs. en dynamisk binding<br />

NB: I kodeeksemplerne indeholder html-koden for overskuelighedens skyld ikke alle<br />

kravene i W3C-standarderne.<br />

Det første program<br />

Lad os straks skrive det første <strong>JavaScript</strong> program. Brug f.eks. Notesblok.<br />

<br />

<br />

Mit første <strong>JavaScript</strong><br />

<br />

<br />

<br />

document.write("Hello World");<br />

<br />

Det gik jo rigtig fint!<br />

<br />

<br />

Gem filen som "detførsteprogram.htm" og åbn filen i browseren.<br />

Du skulle nu gerne se dette billede:<br />

Side 3


<strong>JavaScript</strong> <strong>Jørgen</strong> <strong>Sørensen</strong> js@<strong>jososoft</strong>.dk<br />

Før vi går dybere i "Mit første <strong>JavaScript</strong>", skal vi lige have lidt basisviden om variabler og operatorer<br />

samt <strong>JavaScript</strong>s indbyggede objekter.<br />

Variabler<br />

Man definerer en variabel ved at tildele den en værdi, f.eks.<br />

sum = 15;<br />

tekst = "Hej med dig";<br />

Tekststrenge skal angives i dobbelte eller enkelte anførselstegn. Der bør sættes semikolon<br />

efter alle linier, der udfører noget; selv om nogle browsere er ligeglade!<br />

Variabelnavne skal begynde med et bogstav eller _. Efterfølgende kan også tallene anvendes.<br />

I visse tilfælde kan de specielle danske bogstaver give problemer i variabelnavne - undgå dem.<br />

Variabler, der benyttes i funktioner (se eksempler i afsnittet "Funktioner") kan skjules for andre<br />

funktioner med nøgleordet "var", f.eks.<br />

var tal = 315;<br />

var minTekst = "Velkommen";<br />

Operatorer<br />

Tildelende operatorer<br />

En tildelende operator giver en værdi til venstre operand baseret på værdien af højre operand.<br />

y = 5;<br />

Ovenstående betyder at y tildeles værdien 5.<br />

Aritmetiske operatorer<br />

<strong>JavaScript</strong> har de almindelige regningsarter ( + , - , * og / ). Der er også andre, f.eks.<br />

resultat = 7 % 3;<br />

Procenttegnet betyder modulus, hvilket er resten ved divisionen. I eksemplet går 3 op i 7 to<br />

gange og resten er 1. Dvs. variablen resultat bliver 1.<br />

Man forøger en variabel med 1 ved at bruge to plustegn, f.eks.<br />

a = ++b;<br />

a = b++;<br />

I første linie forøges b med 1 og resultatet tildeles a.<br />

I anden linie sættes a lig med b hvorefter b forøges med 1.<br />

Formindskelse sker på samme måde med -.<br />

Sammenlignende operatorer<br />

Et lille udvalg, som vist er umiddelbart forståelige:<br />

a > b;<br />

a >= c;<br />

a


<strong>JavaScript</strong> <strong>Jørgen</strong> <strong>Sørensen</strong> js@<strong>jososoft</strong>.dk<br />

og et par stykker, der kræver lidt forklaring:<br />

a == b;<br />

a != c;<br />

To lighedstegn (==) betyder en sammenligning, der kan være enten sand eller falsk. Sammenligningen<br />

er sand hvis værdien af a er lig med værdien af b.<br />

Det betyder ikke, at a bliver tildelt værdien af b.<br />

Udråbstegn og lighedstegn (!=) betyder en sammenligning, der kan være sand eller falsk. Der<br />

testes her på om værdierne af de to variable er forskellige. Hvis f.eks. a har værdien 3 og c<br />

har værdien 7 i eksemplet ovenfor er udsagnet sandt.<br />

Logiske operatorer<br />

Disse omfatter "And", "Or" og "Not". Disse anvendes oftest i kontrolstrukturer (se senere).<br />

And skrives &&; Or skrives || og Not skrives !. Se eksempler i afsnittet "Kontrolstrukturer".<br />

Objekthierarkiet i <strong>JavaScript</strong><br />

document-objektet har vi set, da vi skrev vort første script.<br />

document er en del af objekthierarkiet i <strong>JavaScript</strong>. Strukturen i objekthierarkiet er:<br />

window<br />

parent, frames, self, top<br />

location<br />

history<br />

document<br />

links<br />

anchors<br />

forms<br />

elements (text, textarea, button, checkbox, radio, submit, reset)<br />

window refererer til browservinduet<br />

parent, frames, self, top refererer til rammer<br />

location indeholder oplysninger om sidens protokol, adresse, kommunikationsport og vært<br />

history indeholder en liste over de tidligere besøgte sider<br />

document er selve siderne, som brugeren ser<br />

<strong>JavaScript</strong> har nogle objekter, der ligger uden for hierarkiet. Disse er:<br />

• navigator<br />

• Date<br />

• String<br />

• Math<br />

document objektet<br />

write() er en metode på objektet document. Vi brugte metoden i vort første script.<br />

document-objektet har også nogle egenskaber, f.eks. indstilling af baggrundsfarven.<br />

Ved at tilføje linien<br />

document.bgColor = "#666666";<br />

Side 5


<strong>JavaScript</strong> <strong>Jørgen</strong> <strong>Sørensen</strong> js@<strong>jososoft</strong>.dk<br />

i scriptet bliver siden vist som herunder.<br />

Vi bruger her egenskaben bgColor til at sætte baggrundsfarven til den hexidecimale værdi<br />

666666. De to første cifre er Rød = 66; de to næste cifre er Grøn = 66 og de to sidste cifre er<br />

Blå = 66. Den hexidecimale værdi 66 = 6 * 16 + 6 * 1 = 102.<br />

En farves værdi kan f.eks. findes i tegneprogrammet Paint, der findes i Programmer | Tilbehør<br />

i alle Windows versioner. Åbn Farver | Rediger farver | Definer farver. Sæt markøren i det store<br />

felt til højre og aflæs værdierne for Rød, Grøn og Blå og omregn til hexidecimale værdier.<br />

Prøv at ændre værdien 666666 til en anden værdi og se hvad der sker.<br />

Prøv at skrive bgcolor i stedet for bgColor. Hvad sker der?<br />

Prøv at glemme et anførselstegn. Hvad sker der?<br />

window objektet<br />

window-objektet har en række metoder og egenskaber.<br />

Metoderne open() og close() åbner og lukker browservinduer.<br />

Prøv i scriptet at tilføje linien<br />

nytVindue = window.open("http://www.google.com", "nyt");<br />

Egenskaberne sætter vinduets udseende. Prøv at erstatte linien ovenfor med:<br />

nytVindue = window.open("http://www.google.com", "nyt", "toolbar=no, location=no, status=no,<br />

width=400, height=400");<br />

Andre egenskaber er directories, menubar, scrollbars og resizable, der er "yes" eller "no".<br />

Prøv nogle af disse egenskaber og bemærk hvordan det nye browservindue ændrer udseende.<br />

alert<br />

alert() -metoden åbner en meddelelsesboks i browseren. Prøv at rette script-blokken til:<br />

<br />

alert("Klik OK for at fortsætte");<br />

document.write("Hello World");<br />

<br />

Prøv at bytte rækkefølgen på de to linier i scriptet til:<br />

document.write("Hello World");<br />

alert("Klik OK for at fortsætte");<br />

Side 6


<strong>JavaScript</strong> <strong>Jørgen</strong> <strong>Sørensen</strong> js@<strong>jososoft</strong>.dk<br />

confirm<br />

confirm() er lidt mere avanceret end alert. confirm() har en Ok-knap og en Annuller-knap.<br />

Det vil så være naturligt, at der sker noget forskelligt, afhængig af hvilken knap, der aktiveres.<br />

Prøv at rette de to script-linier til:<br />

if (confirm("Klik OK for at sende en hilsen"))<br />

document.write("Hello World");<br />

else<br />

document.write("Jeg sender ingen hilsen til dig");<br />

Så fik vi også lige klaret if…else konstruktionen. Mere om den senere!<br />

prompt<br />

prompt() beder brugeren om en indtastning. Prøv at rette script-linierne til:<br />

mitNavn = prompt("Skriv dit navn");<br />

document.write("Hello World from " + mitNavn);<br />

Bemærk, at tekststrenge sættes sammen (konkatineres) med "+".<br />

frames objektet<br />

Med et frame-objekt kan man styre indholdet i de enkelte vinduer i et frameset.<br />

Vi prøver en simpel konstruktion med tre rammer. Gem filen som "frameset.htm"<br />

<br />

<br />

Rammer og <strong>JavaScript</strong><br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

Skriv nu en ny fil og gem den som "heading.htm".<br />

<br />

<br />

Mine favoritlinks<br />

<br />

top.left.document.write("Her er en liste");<br />

top.right.document.write("Her er noget indhold");<br />

<br />

<br />

<br />

Åbn "frameset.htm" i browseren og du vil se følgende:<br />

Side 7


<strong>JavaScript</strong> <strong>Jørgen</strong> <strong>Sørensen</strong> js@<strong>jososoft</strong>.dk<br />

Filerne "liste.htm" og "indhold.htm" defineret i "frameset.htm" behøver du slet ikke oprette!<br />

Men pas på, at dit <strong>JavaScript</strong> er placeret i et dokument, der er synligt.<br />

location objektet<br />

location-objektet er <strong>JavaScript</strong>s måde at fortælle på, hvilket dokument, der skal åbnes.<br />

Prøv i filen "heading.htm" at ændre script-linierne til:<br />

top.left.location = "http://www.google.com";<br />

top.right.location = "http://www.jp.dk";<br />

history objektet<br />

history-objektet indeholder en liste over besøgte sider. Der kan springes som vist i eksemplet:<br />

<br />

<br />

History objektet<br />

<br />

<br />

<br />

history.go(-1);<br />

<br />

<br />

<br />

Anvendelse som ovenfor har ikke umiddelbart megen mening, da åbning af siden automatisk<br />

vil sende brugeren videre til den sidst åbnede. Hvis derimod scriptet kaldes f.eks. fra en knap<br />

(se afsnittet "Hændelser"), kan det have god mening.<br />

navigator objektet<br />

navigator-objektet kan give information om brugerens browser. Objektet har flere egenskaber,<br />

blandt andre disse som er vist i følgende kode:<br />

Side 8


<strong>JavaScript</strong> <strong>Jørgen</strong> <strong>Sørensen</strong> js@<strong>jososoft</strong>.dk<br />

<br />

<br />

Naviagtor objektet<br />

<br />

<br />

<br />

document.write("" + navigator.appCodeName); //browserens kodenavn<br />

document.write("" + navigator.appName); //browserens navn<br />

document.write("" + navigator.appVersion); //browserens version<br />

document.write("" + navigator.userAgent); //browserens headerinform.<br />

<br />

<br />

<br />

Bemærk, at kommentarer kan indsættes efter // - enten som vist eller på selvstændige linier.<br />

Større kommentarblokke på flere linier kan indsættes mellem /* og */.<br />

Date objektet<br />

Date-objektet har metoder til at hente dato, ugedage, timer, minutter, sekunder m.m. Se et<br />

eksempel på anvendelse af Date i afsnittet "Kontrolstrukturer".<br />

Math objektet<br />

Math-objektet indeholder en række matematiske konstanter (egenskaber).<br />

<br />

<br />

Math objektet<br />

<br />

<br />

<br />

document.write("Hvis cirklens radius er 5, så er dens areal = " + 5 * 5 * Math.PI);<br />

<br />

<br />

<br />

String objektet<br />

String-objektet er nok det mest benyttede; og ofte sker det uden man er klar over det. Ved<br />

en tildeling af en værdi til en variabel, f.eks.<br />

tekst = "Davs med dig";<br />

opretter man faktisk et String-objekt.<br />

String-objektet har kun én egenskab. Det er length, som returnerer strengens længde. Derimod<br />

er der en lang række metoder. Her vises et mindre udvalg:<br />

Metode Forklaring<br />

charAt(x) Returnerer tegnet på position x. Position går fra 0 og slutter på length-1<br />

fontcolor(rrggbb) Ændrer tekstfarven<br />

Side 9


<strong>JavaScript</strong> <strong>Jørgen</strong> <strong>Sørensen</strong> js@<strong>jososoft</strong>.dk<br />

fontsize(x) Ændrer tekststørrelse. Gyldige værdier er 1 – 7<br />

indexOf(x,y) Returnerer position af det først fundne x. Søgningen starter fra y<br />

lastIndexOf(x,y) Returnerer sidste position af x. Søgningen starter bagfra.<br />

substring(x,y) Udtrækker teksten fra position x til position y. (y er ikke strengens længde)<br />

toLowerCase() Alle bogstaver gøres små<br />

toUpperCase() Alle bogstaver gøre store<br />

Derudover er der en række tekstformateringsmetoder, som i html, f.eks. bold() og small().<br />

Kontrolstrukturer<br />

if…else<br />

Test af en betingelse og udførelse af kode, der afhænger af om betingelsen er sand eller falsk,<br />

foretages med if… eller med if…else kontrolstrukturen.<br />

Prøv at skrive følgende kode, og gem den som "hvaderklokken.htm".<br />

<br />

<br />

Hvad er klokken ?<br />

<br />

<br />

<br />

dato = new Date();<br />

time = dato.getHours();<br />

minut = dato.getMinutes();<br />

// vi skal have to cifre i variablen minut<br />

if (minut = 7 && time < 23)<br />

{<br />

document.bgColor = "Yellow";<br />

document.fgColor = "Red";<br />

document.write("Hvilken dejlig dag!");<br />

}<br />

else<br />

{<br />

document.bgColor = "Black";<br />

document.fgColor = "White";<br />

document.write("Nu er det nat!");<br />

}<br />

<br />

<br />

<br />

Prøv at stille tiden om på din pc.<br />

Bemærk, at:<br />

• En kodeblok på flere linier skal være i {}<br />

• Standardfarver kan angives med deres engelske navn<br />

Side 10


<strong>JavaScript</strong> <strong>Jørgen</strong> <strong>Sørensen</strong> js@<strong>jososoft</strong>.dk<br />

for<br />

for-kontrolstrukturen anvendes når en løkke skal gennemløbes et kendt antal gange. Syntaksen<br />

er:<br />

for (tællerens startværdi; slutbetingelse; tællerens optælling pr. gennemløb)<br />

{<br />

kommandoer<br />

}<br />

Prøv at indtaste følgende og gem det som "tekststørrelse.htm"<br />

<br />

<br />

Tekststørrelse<br />

<br />

<br />

<br />

tekst = "Tekst i mange størrelser";<br />

for (i = 1; i


<strong>JavaScript</strong> <strong>Jørgen</strong> <strong>Sørensen</strong> js@<strong>jososoft</strong>.dk<br />

break og continue<br />

break anvendes når en løkke skal afbrydes permanent.<br />

continue anvendes når kun det aktuelle gennemløb i løkken skal springes over.<br />

Prøv at indtaste følgende og gem det som "dividermednul.htm"<br />

<br />

<br />

Divider med nul<br />

<br />

<br />

<br />

for (i = -5; i


<strong>JavaScript</strong> <strong>Jørgen</strong> <strong>Sørensen</strong> js@<strong>jososoft</strong>.dk<br />

function udskriv(tekst)<br />

{<br />

document.write(tekst);<br />

}<br />

<br />

<br />

<br />

<br />

udskriv("Forskellige regnestykker");<br />

linieskift();<br />

udskriv("2 gange 4 er = " + gange(2,4));<br />

linieskift();<br />

udskriv("3 plus 5 er = " + plus(3,5));<br />

<br />

<br />

<br />

Bemærk:<br />

• Funktioner kaldes med "function" hvad enten funktionen returnerer noget eller ej.<br />

• Husk () efter funktionens navn – også selv om der ikke skal overføres parametre.<br />

• Parametre overføres uden typeangivelse.<br />

• Returværdier sendes tilbage med "return".<br />

Hændelser<br />

Funktioner er velegnede til at udføre bestemte opgaver. Hændelser er velegnede til at kalde en<br />

funktion når brugeren ønsker den udført, f.eks. ved klik på et hyperlink eller tryk på en knap.<br />

Lad os prøve! Skriv koden herunder og gem den som "hændelser.htm".<br />

<br />

<br />

Hændelser<br />

<br />

function linkklik()<br />

{<br />

alert("Du klikkede på et link");<br />

}<br />

function farvel()<br />

{<br />

alert("Du forlader nu denne side");<br />

}<br />

function velkommen()<br />

{<br />

alert("Velkommen på denne side");<br />

}<br />

<br />

<br />

<br />

Klik her<br />

<br />

<br />

Side 13


<strong>JavaScript</strong> <strong>Jørgen</strong> <strong>Sørensen</strong> js@<strong>jososoft</strong>.dk<br />

Skriv også følgende og gem den som "side2.htm".<br />

<br />

<br />

Side 2<br />

<br />

<br />

Side 2<br />

<br />

<br />

Prøv i filen "hændelser.htm" at ændre linien<br />

Klik her<br />

til<br />

Klik her<br />

Hvad sker der i statuslinien i bunden af browser-vinduet?<br />

Bemærk<br />

• anvendelsen af dobbelte og enkelte anførselstegn<br />

• at der kan kobles flere hændelser på det enkelte element.<br />

Andre hændelser:<br />

Hændelse Udføres når Anvendes ved<br />

onBlur Et formularfelt mister fokus Select, Text, Textarea<br />

onChange Indholdet i et formularfelt ændres Select, Text, Textarea<br />

onClick Et element klikkes med musen Button, Checkbox, Radio, A, Reset, Submit<br />

onFocus Et formularfelt får fokus Select, Text, Textarea<br />

onLoad Browser har indlæst dokumentet Body, Frameset<br />

onMouseOver Markøren er over elementet A<br />

onSelect En tekst i en formular markeres Text, Textarea<br />

onSubmit Submit-knappen trykkes Form<br />

onUnload Et andet dokument indlæses Body, Frameset<br />

Validering af formularer<br />

<strong>JavaScript</strong> kan anvendes til validering af formularer før disse sendes til serveren. Det kan være<br />

med til at reducere belastningen på nettet og at nedsætte svartiden.<br />

Forestil dig denne formular:<br />

Side 14


<strong>JavaScript</strong> <strong>Jørgen</strong> <strong>Sørensen</strong> js@<strong>jososoft</strong>.dk<br />

Vi vil nu kontrollere, at unge mennesker under 16 år ikke kan bestille mere end 1 kasse øl.<br />

Skriv koden nedenfor og gem den som "validering.htm"<br />

<br />

<br />

Bestilling<br />

<br />

function kontrol()<br />

{<br />

if (document.MinFormular.Kasser.value > 1 && document.MinFormular.Alder.value < 16)<br />

{<br />

alert("Hov, hov. Det er du ikke gammel nok til");<br />

return false;<br />

}<br />

return true;<br />

}<br />

<br />

<br />

<br />

Bestilling af øl<br />

Unge under 16 år kan højst bestille 1 kasse øl.<br />

<br />

<br />

Navn:<br />

Adresse:<br />

Alder:<br />

Antal kasser:<br />

<br />

<br />

<br />

<br />

<br />

<br />

Side 15


<strong>JavaScript</strong> <strong>Jørgen</strong> <strong>Sørensen</strong> js@<strong>jososoft</strong>.dk<br />

Valideringen udføres af funktionen kontrol(), der kaldes ved afsendelse af formularen.<br />

Scriptfiler<br />

Genbrug af <strong>JavaScript</strong>s kan laves ved at placere funktioner i særskilte script-filer.<br />

Hvis du vil have en fast top- og bundtekst (måske i en ramme) på dine hjemmesider kan det<br />

gøres sådan:<br />

<br />

<br />

<br />

Min hjemmeside<br />

<br />

<br />

toptekst();<br />

Indhold på siden. <br />

bundtekst();<br />

<br />

<br />

Gem filen som "bareenside.htm".<br />

Bemærk linien:<br />

<br />

i sektionen af siden. Denne linie skal indsættes på alle sider, hvor top- og/eller bundtekst<br />

funktionen ønskes anvendt.<br />

Du skal nu skrive en tekstfil og gemme den som "minefunktioner.js".<br />

function toptekst()<br />

{<br />

document.write("");<br />

document.write("Du er nu på min hjemmeside.");<br />

document.write("Jeg håber at du kan finde noget nyttigt");<br />

document.write("");<br />

}<br />

function bundtekst()<br />

{<br />

document.write("");<br />

document.write("Copyright 2003 Mig");<br />

document.write("");<br />

}<br />

Resultatet skulle gerne se sådan ud:<br />

Side 16


<strong>JavaScript</strong> <strong>Jørgen</strong> <strong>Sørensen</strong> js@<strong>jososoft</strong>.dk<br />

På denne måde kan man samle alle sine generelle scripts i én fil. Det letter i høj grad opdateringen<br />

af et større website.<br />

Side 17

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!