Singing With Sinatra The Recall App

Welkom bij nummer 2 van Singing with Sinatra. In deel één hebben we Routes besproken, hoe te werken met URI-parameters, werken met formulieren en hoe Sinatra routes onderscheidt op basis van de HTTP-methode waartoe ze zijn gevraagd. Vandaag gaan we onze kennis van Sinatra uitbreiden door een kleine database-gestuurde app te bouwen, "Recall", voor het maken van aantekeningen / het maken van een takenlijst.

We gaan een SQLite-database gebruiken om de notities op te slaan en we gebruiken de DataMapper RubyGem om met de database te communiceren. Voer het volgende in een shell uit om de relevante edelstenen te installeren:

gem installeer sqlite3 datamapper dm-sqlite-adapter

Afhankelijk van hoe u RubyGems heeft ingesteld op uw systeem, moet u mogelijk een voorvoegsel gebruiken gem installeren met sudo.


De warming-up

Laten we meteen naar binnen springen door een nieuwe map voor het project te maken en het toepassingsbestand te maken, recall.rb. Begin ermee door de relevante edelstenen te vereisen:

vereisen 'rubygems' vereisen 'sinatra' vereisen 'datamapper'

Notitie: Als je Ruby 1.9 draait (wat je zou moeten zijn), kun je de "require 'rubygems'" laten vallen als Ruby automatisch toch RubyGems laadt.

En stel de database in met de volgende:

DataMapper :: setup (: standaard, "sqlite3: // # Dir.pwd /recall.db") class Opmerking omvat DataMapper :: Resource-eigenschap: id, Seriële eigenschap: inhoud, Tekst,: vereist => echte eigenschap: voltooid, Boolean,: required => true,: default => false property: created_at, DateTime-eigenschap: updated_at, DateTime end DataMapper.finalize.auto_upgrade!

Op de eerste regel zetten we een nieuwe SQLite3-database op in de huidige map met de naam recall.db. Daaronder stellen we eigenlijk een 'Notes'-tabel in de database in.

Terwijl we de klasse 'Note' aanroepen, maakt DataMapper de tabel als 'Notes'. Dit komt overeen met een conventie die Ruby on Rails en andere frameworks en ORM-modules volgen.

In de klas stellen we het databaseschema op. De tabel 'Notes' heeft 5 velden. Een ID kaart veld dat een integer primaire sleutel is en automatisch wordt verhoogd (dit is wat 'Serieel' betekent). EEN inhoud veld met tekst, een boolean compleet veld en twee datetime velden, gemaakt bij en updated_at.

De allerlaatste regel geeft DataMapper opdracht om de database automatisch bij te werken zodat deze de tabellen en velden bevat die we hebben ingesteld, en dit opnieuw te doen als we wijzigingen in het schema aanbrengen.


De startpagina

Laten we nu onze startpagina maken:

Aan de bovenkant is een formulier om een ​​nieuwe notitie toe te voegen, en daaronder staan ​​alle notities in de database. Voeg om aan de slag te gaan het volgende toe aan het toepassingsbestand, recall.rb:

get '/' do @notes = Note.all: .order =>: id.desc @title = 'All Notes' erb: home einde

Belangrijke notitie: Verwijder de punt ('.') in :.bestellen. (WordPress interfereert met het codevoorbeeld.)

Op de tweede regel ziet u hoe we alle notities uit de database ophalen. Als u ActiveRecord (de ORM gebruikt in Rails) eerder hebt gebruikt, zal de syntaxis van DataMapper heel vertrouwd aanvoelen. De bankbiljetten zijn toegewezen aan de @notes instantievariabele. Het is belangrijk om instantievariabelen te gebruiken (dat zijn variabelen die beginnen met een @) zodat ze toegankelijk zijn vanuit het weergavebestand.

We hebben de @titel instantievariabele, en laad de views / home.erb bekijk het bestand via de ERB-parser.

Maak het views / home.erb bekijk het bestand en begin met het volgende:

<% # display notes %>

We hebben een eenvoudig formulier dat naar de startpagina POSTS ('/'), en daaronder is enige ERB-code die voorlopig als tijdelijke aanduiding dient.


lay-outs

De HTML-standaarden die u kent, hebben mogelijk een kleine hersenbloeding gehad nadat we hebben gezien dat ons thuisview-bestand geen doctype of andere HTML-tags bevat. Welnu, daar is een reden voor. Maak een layout.erb bestand in uw keer bekeken/ map met de volgende:

    <%= @title + ' | Recall' %>      

Terugroepen

omdat je het te druk hebt om te onthouden

<%= yield %>

Een app voor Nettuts+.

De twee interessante delen hier zijn lijn 5 en 18. Op regel 5 zie je het eerste gebruik van de <%=? %> ERB-tags. <%= is anders dan het gewone <% omdat het drukt wat er in zit. Dus hier laten we zien wat er in de @titel instantievariabele gevolgd door | Terugroepen voor de pagina's </code> label.</p> <p>Op lijn 18 is <code><%= yield %></code>. Sinatra zal dit weergeven <code>layout.erb</code> bestand op alle routes. En de daadwerkelijke inhoud voor die route wordt ingevoegd waar de <code>opbrengst</code> is. <code>opbrengst</code> is een term die in essentie betekent "stop hier, voeg alles in wat wacht, ga dan verder".</p> <p>Start de server op met <code>shotgun recall.rb</code> in de shell en bekijk de startpagina in de browser. U zou de inhoud van het lay-outbestand en het formulier van het werkelijke moeten zien <code>home.erb</code> uitzicht.</p> <img src="//accentsconagua.com/img/images_26_3/singing-with-sinatra-the-recall-app_2.png"> <hr> <h2>CSS</h2> <p>In het lay-outbestand hebben we twee CSS-bestanden opgenomen. Sinatra kan statische bestanden laden (bijv. Uw CSS, JS, afbeeldingen enz.) Vanuit een map met de naam <code>openbaar/</code> in de hoofdmap. Dus maak die map aan, en daarbinnen twee bestanden: <code>reset.css</code> en <code>style.css</code>. De reset bevat de HTML5 Boilerplate CSS-reset:</p> <pre>/ * HTML5? Boilerplate style.css bevat een reset, lettertype-normalisatie en enkele basisstijlen. het krediet blijft achter waar het krediet verschuldigd is. er is veel inspiratie gehaald uit deze projecten: yui.yahooapis.com/2.8.1/build/base/base.css camendesign.com/design/ praegnanz.de/weblog/htmlcssjs-kickstart * / / * html5doctor.com Reset stylesheet ( Eric Meyer's Reset Reloaded + HTML5 baseline) v1.6.1 2010-09-17 | Auteurs: Eric Meyer & Richard Clark html5doctor.com/html-5-reset-stylesheet/ * / html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre , abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dd, ol, ul, li , veldset, vorm, label, legenda, tabel, bijschrift, tbody, tfoot, thead, tr, th, td, artikel, opzij, canvas, details, figcaption, figuur, footer, header, hgroup, menu, nav, sectie, samenvatting , tijd, markering, audio, video margin: 0; padding: 0; border: 0; font-size: 100%; lettertype: inherit; vertical-align: basislijn; article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section display: block; blockquote, q quotes: none; blockquote: before, blockquote: after, q: before, q: after content: "; content: none; ins background-colour: # ff9; color: # 000; text-decoration: none; mark background -color: # ff9; color: # 000; font-style: italic; font-weight: bold; del text-decoration: line-through; abbr [title], dfn [title] border-bottom: 1px gestippeld; cursor: help; tabel border-collapse: collapse; border-spacing: 0; hr display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; opvulling: 0; invoer, selecteer vertical-align: middle; / * END RESET CSS * / / * lettertype normalisatie geïnspireerd door de fonts van de YUI Library fonts.css: developer.yahoo.com/yui/ * / body font : 13px / 1.231 schreefloos; * lettergrootte: klein; / * hack behouden om de specificiteit te behouden * / select, invoer, tekstveld, knop font: 99% sans-serif; / * normaliseer monospace sizing * en. wikipedia.org/wiki/MediaWiki_talk:Common.css/Archive_11#Teletype_style_fix_for_Chrome * / pre, code, kbd, samp font-family: monospace, sans-serif; / * * minimale b ase styles * / body, select, input, textarea / * # 444 ziet er beter uit dan zwart: twitter.com/H_FJ/statuses/11800719859 * / color: # 444; / * stel hier je basislettertype in, om gelijkmatig toe te passen * / / * font-family: Georgia, serif; * / / * headers (h1, h2, etc) hebben geen standaard lettertypegrootte of -marge. definieer die zelf. * / h1, h2, h3, h4, h5, h6 font-weight: bold; / * dwing altijd een schuifbalk in niet-IE: * / html overflow-y: scroll; / * toegankelijke focusbehandeling: people.opera.com/patrickl/experiments/keyboard/test * / a: hover, a: active outline: none; a, a: active, a: visited color: # 607890; a: hover color: # 036; ul, ol margin-left: 2em; ol list-style-type: decimal; / * marges verwijderen voor navigatielijsten * / nav ul, nav li margin: 0; list-style: none; lijst-stijl-afbeelding: geen; klein font-size: 85%; sterk, th font-weight: bold; td vertical-align: top; / * sub, sup instellen zonder de regelhoogte te beïnvloeden: gist.github.com/413930 * / sub, sup font-size: 75%; regelhoogte: 0; positie: relatief; sup top: -0.5em; sub bottom: -0.25em; pre / * www.pathf.com/blogs/2008/05/formatting-quoted-code-in-blog-posts-css21-white-space-pre-wrap/ * / white-space: pre; white-space: pre-wrap; white-space: pre-line; word-wrap: breekwoord; opvulling: 15px; textarea overflow: auto; / * www.sitepoint.com/blogs/2010/08/20/ie-remove-textarea-scrollbars/ * / .ie6 legend, .ie7 legend margin-left: -7px; / * thnx ivannikolic! * / / * vink selectievakjes, radio's, tekstinvoeringen met hun label uit door: Thierry Koblentz tjkdesign.com/ez-css/css/base.css * / input [type = "radio"] vertical-align: text-bottom; invoer [type = "checkbox"] vertical-align: bottom; .ie7 invoer [type = "checkbox"] vertical-align: baseline; .ie6 invoer vertical-align: text-bottom; / * handcursor op klikbare invoerelementen * / label, invoer [type = "knop"], invoer [type = "submit"], invoer [type = "afbeelding"], knop cursor: pointer; / * Webkit-browsers voegen een marge van 2 px toe buiten het chroom van formulierelementen * / knop, invoer, selectie, tekstgebied margin: 0; / * kleuren voor formuliergeldigheid * / invoer: geldig, tekstveld: geldig invoer: invalid, textarea: ongeldig border-radius: 1px; -moz-box-shadow: 0px 0px 5px rood; -webkit-box-shadow: 0px 0px 5px rood; vakschaduw: 0px 0px 5px rood; .no-boxshadow input: invalid, .no-boxshadow textarea: invalid background-color: # f0dddd; / * Deze selectieverklaringen moeten gescheiden zijn. Geen tekstschaduw: twitter.com/miketaylr/status/12228805301 Ook: hot pink. * / :: - moz-selection background: # FF5E99; color: # fff; text-shadow: none; :: selection background: # FF5E99; color: # fff; text-shadow: none; / * j.mp/webkit-tap-highlight-color * / a: link -webkit-tap-highlight-color: # FF5E99; / * maak knoppen leuk in IE: www.viget.com/inspire/styling-the-button-element-in-internet-explorer/ * / button width: auto; overloop: zichtbaar; / * bicubic resizing voor niet-native IMG: code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image- resizing / * / .ie7 img -ms-interpolatie-modus: bicubisch; </pre> <p>En <code>style.css</code> bevat enkele basisstyling om de app er mooi uit te laten zien:</p> <pre>body margin: 35px auto; breedte: 640 px; header text-align: center; marge: 0 0 20px; header h1 display: inline; lettertypegrootte: 32px; header h1 a: link, header h1 a: visited color: # 444; tekstdecoratie: geen; header h2 font-size: 16px; lettertype-stijl: cursief; kleur: # 999; #main margin: 0 0 20px; #add margin: 0 0 20px; #add textarea height: 30px; breedte: 510 px; opvulling: 10px; border: 1px solid #ddd; #add input height: 50px; breedte: 100 px; marge: -50px 0 0; border: 1px solid #ddd; achtergrond: wit; #edit textarea height: 30px; breedte: 480 px; opvulling: 10px; border: 1px solid #ddd; #edit input [type = submit] height: 50px; breedte: 100 px; marge: -50px 0 0; border: 1px solid #ddd; achtergrond: wit; #bewerkte invoer [type = aanvinken] hoogte: 50px; breedte: 20px; artikel border: 1px solid #eee; border-top: geen; opvulling: 15px 10px; article: first-of-type border: 1px solid #eee; artikel: nth-child (even) background: #fafafa; article.complete background: # fedae3; artikeloverspanning font-size: 0.8em; p margin: 0 0 5px; .meta font-size: 0.8em; lettertype-stijl: cursief; kleur: # 888; .links font-size: 1.8em; regelhoogte: 0.8em; zweven: rechts; marge: -10 px 0 0; . linkt een display: block; tekstdecoratie: geen; </pre> <p>Ververs de pagina in uw browser en alles zou meer gestyled moeten zijn. Maak je niet te veel zorgen om deze CSS; het maakt de dingen er gewoon een beetje mooier uitzien!</p> <img src="//accentsconagua.com/img/images_26_3/singing-with-sinatra-the-recall-app_3.png"> <hr> <h2>Een notitie aan de database toevoegen</h2> <p>Op dit moment krijg je een routefout als je het formulier op de startpagina probeert in te dienen. Laten we nu de POST-route voor de startpagina maken:</p> <pre>post '/' do n = Note.new n.content = params [: inhoud] n.created_at = Time.now n.updated_at = Time.now n.save redirect '/' end</pre> <p>Dus wanneer er een aanvraag wordt gedaan op de startpagina, maken we een nieuw Note-object in <code>n</code> (dankzij de DataMapper ORM, <code>Note.new</code> staat voor een nieuwe rij in de <code>aantekeningen</code> tabel in de database). De <code>inhoud</code> veld is ingesteld op de verzonden gegevens uit het tekstgebied en de <code>gemaakt bij</code> en <code>updated_at</code> datetime-velden worden ingesteld op het huidige tijdstempel.</p> <p>De nieuwe notitie wordt vervolgens opgeslagen en de gebruiker wordt teruggeleid naar de startpagina waar de nieuwe notitie wordt weergegeven.</p> <hr> <h2>De notities weergeven</h2> <p>Daarom hebben we een nieuwe notitie toegevoegd, maar we kunnen deze nog niet op de startpagina zien, omdat we de code er niet voor hebben geschreven. Binnen in de <code>views / home.erb</code> bekijk het bestand, vervang de <code><%# display notes %></code> regel met:</p> <pre><% @notes.each do |note| %> <article <%= 'class="complete"' if note.complete %>> <p> <%= note.content %> <span>"> [Bewerken]</span> </p> <p> / Complete ">? </p> <p>gemaakt: <%= note.created_at %></p> </article> <% end %></pre> <p>Op de eerste regel beginnen we een lus door elk van de <code>@notes</code> (anders hadden we kunnen schrijven <code>voor opmerking in @notes</code>, maar een blok gebruiken, zoals we hier zijn, is een betere oefening). Op regel 2 geven we de <code><article></code> een klasse van <code>compleet</code> als de huidige notitie is ingesteld op <code>compleet</code>. De rest zou vrij rechttoe rechtaan moeten zijn.</p> <hr> <h2>Een notitie bewerken</h2> <p>We kunnen dus notities toevoegen en bekijken. Nu hebben we alleen de mogelijkheid nodig om ze te bewerken en te verwijderen.</p> <p>Je hebt het misschien gemerkt in onze <code>home.erb</code> bekijken we een <code>[Bewerk]</code> link voor elke notitie naar wat in essentie is <code>/:ID kaart</code>, dus laten we die route nu maken:</p> <pre>get '/: id' do @note = Note.get params [: id] @title = "Bewerk opmerking ## params [: id]" erb: edit end</pre> <p>We halen de gevraagde notitie uit de database op met behulp van de verstrekte ID, stel a in <code>@titel</code> variabele, en laad de <code>views / edit.erb</code> bekijk het bestand via de ERB-parser.</p> <p>Voer het volgende in voor de <code>views / edit.erb</code> uitzicht:</p> <pre><% if @note %> <form action="/<%= @note.id %>"methode =" post "> <input type="hidden" name="_method" value="put"> <textarea name="content"><%= @note.content %></textarea> <input type="checkbox" name="complete" <%= "checked" if @note.complete %>> <input type="submit"> </form> <p>/ Delete "> Verwijderen</p> <% else %> <p>Opmerking niet gevonden.</p> <% end %></pre> <p>Dit is een vrij eenvoudige weergave. Een formulier dat naar de huidige pagina verwijst, een tekstgebied met de inhoud van de notitie en een selectievakje dat wordt gecontroleerd als de notitie is ingesteld op <code>compleet</code>.</p> <p>Maar kijk naar de derde regel. Mysterieus. Om dit uit te leggen, moeten we een beetje afwijken.</p> <h3>RESTful Services</h3> <p>Je hebt gehoord van de twee termen GET en POST.</p> <ul> <li> <strong>KRIJGEN: </strong>De meest voorkomende. Het is over het algemeen voor het aanvragen van een pagina en kan als bladwijzer worden gebruikt.</li> <li> <strong>POST: </strong> Wordt gebruikt voor het verzenden van gegevens en kan niet als bladwijzer worden gebruikt.</li> </ul> <p>Maar GET en POST zijn niet de enige "HTTP-werkwoorden" - er zijn er nog twee die u moet weten: PUT en DELETE.</p> <p>Technisch gezien zou POST alleen moeten worden gebruikt voor het maken van iets, zoals het maken van een nieuwe notitie in uw geweldige nieuwe web-app, bijvoorbeeld.</p> <p>PUT is het werkwoord om iets aan te passen. En VERWIJDEREN, je raadt het al, is om iets te verwijderen.</p> <p>Het hebben van deze vier werkwoorden is een geweldige manier om een ​​app te scheiden. Het is logisch. Helaas ondersteunen webbrowsers eigenlijk geen PUT- of DELETE-verzoeken, en daarom heeft u waarschijnlijk nog nooit van hen gehoord.</p> <p>Dus als we hier weer op het goede spoor komen, als we onze app logisch willen opsplitsen (wat Sinatra aanmoedigt), moeten we deze PUT- en DELETE-verzoeken vervalsen. Je zult onze formulieren zien <code>actie</code> ingesteld op <code>post</code>. Het verborgen <code>_methode</code> invoerveld waarin we hebben ingesteld <code>leggen</code> op de derde regel laat Sinatra dit PUT-verzoek vervalsen, terwijl het daadwerkelijk een POST gebruikt. Rails, naast andere frameworks, doen dingen op dezelfde manier.</p> <hr> <h2>Laten we zetten</h2> <p>Nu hebben we ons PUT-verzoek gefingeerd, we kunnen er een route voor maken:</p> <pre>zet '/: id' do n = Note.get params [: id] n.content = params [: content] n.complete = params [: compleet]? 1: 0 n.updated_at = Time.now n.save redirect '/' end</pre> <p>Het is allemaal vrij eenvoudig. We krijgen de relevante notitie met behulp van de ID in de URI, stellen de velden in op de nieuwe waarden, opslaan en omleiden naar huis. Merk op hoe we op de vierde regel een ternaire operator gebruiken om in te stellen <code>n.complete</code> naar <code>1</code> als <code>params [: invullen]</code> bestaat, of <code>0</code> anders. Dit komt omdat de waarde van een selectievakje alleen wordt verzonden met een formulier als het is aangevinkt, dus we controleren alleen of het bestaat.</p> <hr> <h2>Een notitie verwijderen</h2> <p>In onze <code>edit.erb</code> weergave, hebben we een link 'Verwijderen' toegevoegd aan wat in wezen het pad is <code>/: Id / delete</code>. Voeg dit toe aan uw sollicitatiebestand:</p> <pre>get '/: id / delete' do @note = Note.get params [: id] @title = "Bevestig de verwijdering van noot ## params [: id]" erb: delete end</pre> <p>Op deze pagina krijgen we een bevestiging van de gebruiker dat deze notitie daadwerkelijk wilt verwijderen. Maak het weergavebestand aan <code>views / delete.erb</code> met het volgende:</p> <pre><% if @note %> <p>Weet je zeker dat je de volgende opmerking wilt verwijderen: <em>"<%= @note.content %>"</em>?</p> <form action="/<%= @note.id %>"methode =" post "> <input type="hidden" name="_method" value="delete"> <input type="submit" value="Yes, Delete It!"> "> Annuleren </form> <% else %> <p>Opmerking niet gevonden.</p> <% end %></pre> <p>Merk op dat, net zoals we een PUT-verzoek hebben vervalst door een verborgen instelling in te stellen <code>_methode</code> invoerveld, doen we nu een VERWIJDEREN verzoek.</p> <hr> <h2>De DELETE-route</h2> <p>Ik weet zeker dat je dit nu onder de knie krijgt. De verwijderingsroute is:</p> <pre>delete '/: id' do n = Note.get params [: id] n.destroy redirect '/' end</pre> <p>Probeer het! U zou nu opmerkingen moeten kunnen bekijken, toevoegen, bewerken en verwijderen. Er is nog één ding? </p> <hr> <h2>Een notitie markeren als "voltooid"</h2> <p>Op dit moment als je een notitie wilt instellen als <code>compleet</code> je moet naar de weergave Bewerken gaan en het vakje op die pagina aanvinken. Laten we dat proces wat eenvoudiger maken.</p> <p>Toen we de hoofdpagina hebben opgezet, hebben we er een toegevoegd <code>/: Id / voltooid</code> link op elke notitie. Laten we die route nu maken, waarbij een notitie gewoon als compleet wordt geplaatst (of onvolledig als deze al was ingesteld om te voltooien):</p> <pre>get '/: id / complete' do n = Note.get params [: id] n.complete = n.complete? 0: 1 # flip it n.updated_at = Time.now n.save redirect '/' end</pre> <hr> <h2>Conclusie</h2> <p>Jij en Sinatra trekken een knetterend duet! Je hebt heel snel een eenvoudige webapp geschreven die alle CRUD-bewerkingen uitvoert die je van een app zou verwachten. Het is geschreven in super-sexy-schone Ruby-code en is gescheiden in zijn logische delen.</p> <p>In het laatste deel van Singing with Sinatra, de Encore, verbeteren we de afhandeling van fouten, beveiligen we de app van XSS en creëren we een RSS-feed voor de notities.</p> <p><strong>Notitie:</strong> Je kunt bladeren door de uiteindelijke projectbestanden voor deze tutorial via GitHub.</p> <div class="rek-block"> <center> <ins class="adsbygoogle" style="display:inline-block;width:580px;height:400px" data-ad-client="ca-pub-3810161443300697" data-ad-slot="9434875811"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </center> </div> <div class="h-alltags"> <a href="articles/code">Code</a> </div> </div> </div> </div> </div> <div class="next_posts clearfix"> <div class="n_post"> <div class="next_posts-h1 left_nh1"><a href="/articles/code/singing-with-sinatra.html">Zingen met Sinatra</a></div> <div class="next_posts-img" style="background-image: url('//accentsconagua.com/img/images_26_3/singing-with-sinatra.jpg');"></div> </div> <div class="n_post"> <div class="next_posts-h1 right_nh1"><a href="/articles/code/singing-with-sinatra-the-encore.html">Zingen met Sinatra - The Encore</a></div> <div class="next_posts-img" style="background-image: url('//accentsconagua.com/img/images_26_3/singing-with-sinatra-the-encore.jpg');"></div> </div> </div> <footer> <div class="container"> <div class="footer-langs"> <ul class="site-langs-list"> <li><a href="https://www.accentsconagua.com"><i class="flag flag-DE"></i>Deutsch</a></li> <li><a href="https://fr.accentsconagua.com"><i class="flag flag-FR"></i>Français</a></li> <li><a href="https://nl.accentsconagua.com"><i class="flag flag-NL"></i>Nederlands</a></li> <li><a href="https://no.accentsconagua.com"><i class="flag flag-NO"></i>Norsk</a></li> <li><a href="https://sv.accentsconagua.com"><i class="flag flag-SE"></i>Svenska</a></li> <li><a href="https://it.accentsconagua.com"><i class="flag flag-IT"></i>Italiano</a></li> <li><a href="https://es.accentsconagua.com"><i class="flag flag-ES"></i>Español</a></li> <li><a href="https://ro.accentsconagua.com"><i class="flag flag-RO"></i>Românesc</a></li> </ul> </div> <div class="h-block"><a href="/">nl.accentsconagua.com</a><div class="h-block-a"></div></div> <div class="footer-text"> Interessante informatie en nuttige tips over programmeren. Website ontwikkeling, webdesign en webontwikkeling. Photoshop-zelfstudies. Creatie van computerspellen en mobiele applicaties. Word een volledig professionele programmeur. </div> </div> </footer> <div class="search"> <img class="searchico" src="//accentsconagua.com/img/search.svg" alt=""> </div> <div class="modal"> <div class="modal-content"> <span class="close-button">×</span> <input class="searchmain" type="text" id="search-input" placeholder="Zoeken..."> <ul class="searchli" id="results-container"></ul> </div> </div> <link rel="stylesheet" href="css/flags.css"> <link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.1.0/cookieconsent.min.css" /> <script src="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/3.1.0/cookieconsent.min.js"></script> <script> window.addEventListener("load", function(){ window.cookieconsent.initialise({ "palette": { "popup": { "background": "#edeff5", "text": "#838391" }, "button": { "background": "#4b81e8" } }, "theme": "classic", "position": "bottom-right" })}); </script> <script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <script src="js/scripts.min.js"></script> <script src="js/common.js"></script> <link rel="stylesheet" href="css/fontawesome-all.min.css"> <script> var modal = document.querySelector(".modal"); var trigger = document.querySelector(".search"); var closeButton = document.querySelector(".close-button"); function toggleModal() { modal.classList.toggle("show-modal"); } function windowOnClick(event) { if (event.target === modal) { toggleModal(); } } trigger.addEventListener("click", toggleModal); closeButton.addEventListener("click", toggleModal); window.addEventListener("click", windowOnClick); </script> <script src="https://unpkg.com/simple-jekyll-search@1.5.0/dest/simple-jekyll-search.min.js"></script> <script> SimpleJekyllSearch({ searchInput: document.getElementById('search-input'), resultsContainer: document.getElementById('results-container'), json: '/search.json', searchResultTemplate: '<li><a href="{url}">{title}</a></li>' }) </script> <script src="jquery.unveil2.min.js"></script> <script> $('img').unveil(); </script> </body> </html>