Responsiv Web Design
LUCRARE DE LICENȚĂ
RESPONSIV WEB DESIGN
Aplicație practică: www.photogear.ro
Cuprins
1. Parte teoretică – Principii web design
1.1. Responsive Typography
Ce este responsive typography?
Ideea principală în responsive typography este să se folosească tehnici de ajustare a fontului unui site, ca mărime, astfel încât acesta să arate la fel pe orice rezoluție sau dispozitiv de pe care este accesat, iar experiența de citire să nu fie afectată din acest motiv.
Deși responsive design rezolvă mai multe probleme legate de reguli de formatare a paragrafelor (mărimea fontului, înălțimea sau lățimea coloanei), există anumite aspecte ce țin de optimizarea fontului ce ar trebui luate în considerare separat.
Avem nevoie de responsive typography?
Până nu demult, rezoluțiile ecranelor erau, într-o mai mare sau mai mică măsură, omogene, pe când acum, există o varietate de rezoluții, rapoarte și dispozitive de pe care putem naviga pe internet. În plus, avem modificări și în ceea ce privește densitatea pixelilor (retina display).
Chiar și fonturile care până acum funcționau perfect, dar care nu au fost gândite pentru aceste schimbări, nu reușesc să țină pasul cu ele și tind să nu mai fie folosite. De exemplu, principalul font cu serife, Georgia, funcționează bine pe web doar până la dimensiunea de 16 pixeli. Peste această dimensiune, fontul arată diferit, dar nu din cauză că nu este un font cu un design bun, ci, pur și simplu, nu a fost creat pentru dimensiuni mari sau pentru ecrane cu densitate crescută a pixelilor.
În aceste condiții, lucrurile au devenit mult mai complicate când vine vorba de alegerea tipului și dimensiunii fontului atunci când construim un site.
Alegerea fontului
Fiecare font are avantajele și dezavantajele sale, iar alegerea fontului destinat paragrafelor de text se restrânge, ca de obicei, la cele trei mari categorii: serif, sans serif sau slab serif. În general, acestea au aceleași performanțe, însă sub dimensiunea de 12 pixeli, fonturile cu serife nu arată suficient de bine. Cu toate astea, orice text sub dimensiunea de 12 pixeli este cu siguranță mult prea mic pentru a fi citit în condiții optime pe monitoarele actuale.
Probleme de afișare
Dacă vrem ca fontul ales să se potrivească în cât mai multe situații, trebuie să avem în vedere, în primul rând, 3 mari categorii de sisteme de operare, care vin “la pachet” cu propriile probleme de afișare.
De exemplu:
Pe Windows/Linux – sistemele de fonturi arată ok în majoritatea cazurilor.
Pe OS X – sistemele de fonturi arată bine pe ecranele cu rezoluții mici, se văd prea îngroșate pe ecrane cu rezoluție mare, însă pe Retina Display sunt afișate în regulă. De asemenea, corpul de literă mai subțire arată excelent pe ecranele cu rezoluție mare, dar este mult prea subțire pentru Retina Display.
iOS – sistemele de fonturi arată prea îngroșat în cazul ecranelor cu rezoluție mare (iPhone 1-3, iPad 1-2), însă arată bine pe Retina Display (iPad 3).
Așadar, pentru performanță optimă în afara ecranelor cu rezoluție mică și a sistemelor de operare Windows și Linux, avem nevoie de 3 ajustări ale fonturilor, ca mărime.
Mai subțiri (pentru ecrane cu rezoluție mare)
Segoe UI
Open Sans
Normale (pentru Retina landscape HTML mode)
Roboto
Myriad Pro
Mai îngroșate (pentru Retina portrait HTML mode)
Proxima Nova
Helvetica
În zona de mobile, fiecare sistem de operare folosește propriul lui font, dar se randează la fel de bine și pe PC:
iOS – Helvetica (regular, bold)
Windows Phone – Segoe UI
Android – Roboto
Câteva exemple de fonturi care arată bine pe toate mediile ar putea fi:
Gotham
Proxima
Open Sans
Myriad Pro
Concluzie
Prin implementarea de responsive layouts și responsive typography, experiența digitală a cititorului devine mai bună. Conținutul, fiind mai ușor de parcurs de către cititor datorită folosirii unui font bun, va crește și performanța site-ului din punctul de vedere al traficului (scade rata de abandon și crește timpul petrecut pe site). Este o situație de tip win-win, atât pentru proprietarul site-ului, cât și pentru cititor.[***1]
1.2. Culori în web design
2. Tehnologii web.
2.1. HTML
Istoric
Web Hypertext Application Technology Working Group (WHATWG) a început să lucreze la un nou standard în 2004, când Consorțiul World Wide Web era concentrat pe evoluțiile viitoare ale XHTML 2.0 și HTML 4.01 care nu au fost actualizate din anul 2000. În 2009 W3C a permis cartei XHTML 2.0 Working Group să expire, și a decis să nu o reînoiască. W3C și WHATWG lucrează în prezent împreună pentru dezvoltarea HTML5.
Chiar dacă HTML5 a fost bine cunoscut ani buni printre dezvoltatorii de web, el devine subiectul general de discuție în media în Aprilie 2010 după ce Steve Jobs, CEO la Apple Inc. atunci, a dat publicității o scrisoare cu titlul "Gânduri despre Flash" în care a concluzionat că Flash nu mai este necesar pentru a urmări filme și pentru a consuma orice tip de resursă web și asta datorită standardelor noi create și deschise în era mobilului, cum ar fi HTML5, care vor câștiga. Aceasta a strârnit o dezbatere în cercurile de web developeri unde unii sugerau că, atîta tip cât HTML5 va livra funcționalități solide, developerii vor trebui să ia în considerare varietatea suporturilor de browsere din diferite părți și standarde precum și alte diferențe funcționale între HTML5 și Flash.
W3C – procesul de standardizare
WHATWG a pornit lucrul la caietul de sarcini în iunie 2004 numit "Web Applications 1.0". Astfel în ianuarie 2011, caietul de specificații ca un Proiect de standarde era publicat la WHATWG și proiectul de lucru era publicat la W3C. Ian Hickson de la Google este editorul lui HTML5.
Caietul de sarcini a fost adoptat ca punct de pornire la dezvoltarea noului HTML de grupul de lucru de la W3C, Consorțiul World Wide Web, în 2007. Acest grup a publicat Primul Proiect Public de Lucru din caietul de sarcini în 22 ianuarie 2008. Caietul de sarcini este încă în lucru și se așteaptă să mai continue încă mulți ani deși părți din HTML5 sunt gata de a fi terminate și implementate în browsere înainte ca întregul caiet de sarcini să ajungă la final.
Conform orarului W3C, s-a estimat că HTML5 va ajunge o recomandare a W3C pe la sfârșitul anului 2010. Oricum, obiectivul de timp al Primului Proiect Public de Lucru a fost ratat cu 8 luni și Proiectul "Last Call and Candidate Recommendation" a fost așteptat să fie terminat în 2008, dar în ianuarie 2011 HTML5 era încă la stadiul de proiect de lucru în W3C. HTML5 a fost in Last Call la WHATWG din octombrie 2009.
Ian Hickson, editorul caietului de sarcini HTML5, se aștepta ca acesta să ajungă la stadiul de Candidate Recommendation în cursul anului 2012. Criteriul ca acest caiet de sarcini să ajungă Recomandare W3C este "două implementări 100% complete și interoperabile". Într-un interviu dat publicației TechRepublic, Hickson previzionează că acesta va mai dura până în 2022 sau chiar mai târziu. Oricum, multe părți din caietul de sarcini sunt stabile și pot fi implementate în produse.
În Decembrie 2009, WHATWG a trecut la un model neversionat de dezvoltare pentru caietul de sarcini HTML5. W3C încă mai continuă cu publicarea unei versiuni momentane de caiet de sarcini HTML5.
Pe 14 februarie 2011, W3C a extins documentul HTML Working Group cu etape clare pentru HTML5. De la acest workgroup se așteapta în mai 2011 să avanseze HTML5 la nivel de "Last Call", o invitație pentru comunitățile din interiorul și din exteriorul W3C de a confirma soliditatea specificațiilor tehnice. Grupul se va concentra apoi pe adunarea de experiență de implementare. W3C este, de asemenea, în plin proces de dezvoltare a unui întreg set de teste pentru a realiza interoperabilitatea largă pentru întregul caiet de sarcini până în 2014 inclusiv, ceea ce acum este un obiectiv pentru atingerea stadiului de Recomandare.
Markup
HTML5 introduce un număr de noi elemente și atribute care reflectă utilizarea tipică a unui site modern. Unele dintre ele sunt semantic înlocuite cu utilizări comune de blocuri generice (<div>) și de elemente inline (<span>), de exemplu <nav> – block de navigatie în site -, <footer> – în mod normal se referă la partea de jos a unei pagini web sau la ultima linie de cod HTML – sau<audio> și <video> în loc de <object>. Unele elemente depreciate din HTML 4.01 au fost șterse, inclusiv nevinovatul element de prezentare <font> și <center>, al căror efect este realizat cu CSS (Cascading Style Sheets). Se pune astfel accent pe importanța DOM scripting (e.g. JavaScript) în comportamentul web.
Sintaxa HTML5 nu mai este bazată pe SGML în ciuda asemănării cu marcajele acestuia. Oricum a fost dezvoltată pentru compatibilitatea cu parserele comune de HTML mai vechi. Aceasta vine cu o nouă linie introductivă, arată ca tipurile de declarare SGML, <!DOCTYPE html>, care declanșează modurile standard de redare. Din 5 ianuarie 2009, HTML5 include de asemenea Web Forms 2.0, anteriorul caiet de sarcini WHATWG.
Noile API
În completarea marcajelor prezentate mai sus, HTML5 aduce scriptingul API (application programming interfaces). Interfața existentă document object model (DOM) este extinsă de fapt cu caracteristici noi, documentate. Sunt noi API-uri, cum ar fi:
Elementul canvas pentru modul de desen 2D. A se vedea Canvas 2D API Specification 1.0 specification
Timed media playback – mod de redare media cronometrat
Offline storage database (offline web applications)
Editare de documente
Drag-and-drop
Mesagerie Cross-document
Managementul de istorie a browserului
MIME type și protocolul de manipulare a înregistrărilor
Microdata
Nu toate aceste tehnologii sunt incluse în caietul de sarcini HTML5 – W3C, chiar dacă ele sunt incluse în caietul de sarcini WHATWG HTML. Unele din tehnologiile care nu sunt prezente nici în caietul de sarcini W3C nici în cel WHATWG, sunt următoarele de mai jos. W3C publică specificații separate pentru acestea.
Geolocation
Web SQL Database, o bază de date SQL locală (nu mai este întreținută).
Baza de date API indexată, o rezervă de chei valorice ierarhice (odinioară WebSimpleDB).
Web Storage
File API, manipularea încărcării fișierelor.
Directories and System. Acest API este destinat să satisfacă utilizarea tehnologiei client-side-storage cazurile de utilizare care nu sunt deservite de o bază de date.
File Writer. Un API pentru scrierea de fișiere din aplicații web.
O neînțelegere des întâlnită este aceea că HTML5 nu ar livra animație în paginile web, ceea ce este total neadevărat. Fiecare dintre JavaScript sau CSS 3 sunt necesare pentru animarea de elemente HTML. Animația este de asemenea posibilă utilizând JavaScript și HTML4.
XHTML5
XHTML5 este serializarea XML a HTML5. Documentele XML trebuie servite cu un tip XML media de internet cum ar fi application/xhtml+xml și application/xml. HTML5 necesită utilizarea strictă a XML, sintaxă bine formatată. Alegerea între HTML5 și XHTML5 se rezumă la alegerea tipului de conținut MIME: tipul de media ales determină ce tip de document se va folosi. În XHTML5 doctype-ul html există și poate fi chiar și omis. HTML5 care a fost scris în conformitate cu ambele standarde HTML și XHTML va produce același tree DOM dacă va fi parsat de HTML și XHTML – proces numit "polyglot markup".
Tratarea erorilor
Un browser de HTML5 (text/html) va fi flexibil în tratarea sintaxelor incorecte. HTML5 este proiectat de asemenea pentru ca browserele vechi să poată ignora în siguranță noile construcții HTML5. În contrast cu HTML 4.01, caietul de sarcini HTML5 oferă reguli detaliate pentru lexing și parsare cu intenția ca browsere, diferite între ele, vor produce același rezultat și în cazul unei sintaxe incorecte. Deși HTML5 definește azi un comportament consistent pentru documentele "tag soup", documente de taguri, acestea nu sunt considerate ca fiind conforme cu standardul HTML5.
Diferențe față de HTML 4.01 și XHTML 1.x
Următoarea este o listă sumară de diferențe și câteva exemple specifice:
Noi reguli de parsare: orientate rientate către parsare rapidă și compatibilitate; nu se bazează pe SGML
Abilitatea de a utiliza inline SVG și MathML în text/html
Noi elemente: article, aside, audio, bdo, canvas, command, datalist, details,embed, figcaption, figure, footer, header, hgroup, keygen, mark, meter, nav,output, progress, rp, rt, ruby, section, source, summary, time, video, wbr
Noi tipuri de forme de control: dates and times, email, url, search, number, range,tel, color
Noi atribute: charset (on meta), async (on script)
Atribute globale (care pot fi aplicate oricărui element): id, tabindex, hidden, data-*(custom data attributes)
Elemente depreciate ce vor fi șterse cu totul: acronym, applet, basefont, big, center,dir, font, frame, frameset, isindex, noframes, strike [***3]
2.2. CSS3
CSS3 reprezintă un upgrade ce aduce câteva atribute noi și ajută la dezvoltarea noilor concepte in webdesign.
Unele dintre cele mai importante segmente (module) noi adăugate acestui standard pentru formatarea elementelor HTML aduc un plus considerabil in dezvoltarea activități webdesign.
Mai jos sunt prezente in listă cele mai importante modulele adăugate in CSS3:
Selectors
Box Model
Backgrounds and Borders
Image Values and Replaced Content
Text Effects
2D/3D Transformations
Animations
Multiple Column Layout
User Interface
Deși au apărut unele deficiente de compatibilitate intre browsere, majoritatea proprietăților CSS3 au fost implementate cu succes in variantele browserelor noi.
CSS3 – Borduri
Acum CSS3 oferă posibilitatea de a crea borduri cu colțurile rotunjite fară a folosi elemente grafice de fundal așa cum se folosea anterior acestui upgrade.
Proprietatea CSS3 border-radius definește prin valorile exprimate in pixeli cat de rotunjite vor fi colțurile unui element HTML sau unei imagini. Fiecare colț poate avea o alta valoare exprimată in pixeli diferită de un alt colț al aceluiași element. Prin urmare putem folosi pana la 4 valori diferite atribuite unui element HTML sau imagine.
Exemplu:
border-radius: 5px ;
– definește valoarea de 5px radius pentru toate cele 4 colțuri ale elementului.
border-radius: 5px 7px 12px 4px;
– aceste valori multiple definesc cat de mult vor fi rotunjite colțurile elementului HTML, iar pentru fiecare colt este specificata valorarea. Colțul stanga-sus are valoarea border-radius de 5px, colțul dreapta-sus are valoarea border-radius de 7px, colțul dreapta-jos al elementului HTML are valoarea de 12px iar colțul din stanga-jos are valoarea de 4px.
CSS3 – Borduri Rotunjite – Optimizat
Varianta ne-comprimată sau ne-optimizată:
border-radius-left: 5px;
border-radius-right: 7px;
border-radius-top: 12px;
border-radius-bottom: 4px;
Varianta mimificată, compresată/optimizată:
border-radius: 5px 7px 12px 4px;
Ambele variante sunt corecte și acceptate de clientul browser.
CSS3 – Borduri Rotunjite – Compatibilitate Browser
Pentru compatibilitatea cu diferite browsere se folosesc prefixe: -webkit- , -moz- , -o-
Compatibilitate: Internet Explorer (IE) – 0.9 , Chrome folosește prefixul -webkit- pentru 4,0 , Firefox folosește prefixul -moz- pentru versiunea 3.0, Safari folosește prefixul -webkit- pentru versiunea 3.1, Opera 10.5 prefix -o-
Exemplu CSS3 border-radius:
div {
border: 2px solid #333333;
padding: 10px 40px;
background: #dddddd;
width: 300px;
border-radius:25px;
}
Elementul HTML div este definit de urmatoarele proprietăți CSS: dimensiunea in lungime este redată de valoarea in pixeli a proprietății width, folosește o bordură de 2 pixeli, o bordură solidă de culoare gri-inchis definită de caloarea HEX #333333. Culoarea de fundal este gri deschis definită de HEX #dddddd. Bordura rotunjită este de 25 pixeli pentru toate cele 4 colțuri. [***4]
2.3. Media query în Responsive web design
Încă de pe vremea CSS 2.1, stilul nostru s-a bucurat într-o oarecare măsură de constientizarea device-ului prin diferite tipuri de media. Daca ati scris vreodată un print style sheet, atunci sunteti familiarizati cu conceptul:
În speranta că realizăm mai mult decât pagini perfect formatate pentru printare, specificatiile CSS ne furnizează o multime de medii acceptabile, fiecare adaptat pentru o anumită clasă de dispozitive web. Dar, majoritatea browserelor si dispozitivelor nu îmbrătisează cu adevărat toate specificatiile, lăsând multe tipuri de media imperfect implementate, sau chiar ignorate cu totul.
Din fericire, W3C a creat media query-urile ca parte a specificatiilor CSS3, îmbunătătind, conform promisiunii, tipurile de media. Un media query ne permite să realizăm nu doar clase pentru câteva dispozitive, dar si să inspectăm caracteristicile fizice ale dispozitivului pentru care realizăm munca. De exemplu, ca urmare a cresterii recente a Webkit-urilor mobile, media query-urile au devenit o tehnică foarte populară de a furniza style sheet-uri adaptate perfect pentru iPhone sau telefoane Android. Pentru a face acest lucru am putea include un query într-un atribut al style sheet-ului:
Querry-ul contine două componente:
Un tip media (ecran), si
Query-ul dintre paranteze, ce contine o caracteristică media (lătimea maximă a dispozitivului), este urmat de o valoare tintă (480px).
De fapt noi întrebăm dispozitivul dacă rezolutia sa orizontală (lătimea maximă a dispozitivului) este egală sau mai mică decât 480px. Dacă trece testul – adică dacă putem vedea pagina pe un ecran mic, cum ar fi cel de iPhone – atunci dispozitivul va încărca fisierul shetland.css. Altfel, link-ul este ignorat per ansamblu.
Designerii au experimentat cu layout-uri “resolution aware”, majoritatea lor bazându-se pe solutii JS, cum ar fi scriptul excelent al lui Cameron Adam. Dar specificatiile media query-urilor oferă o serie de caracteristici dincolo de rezolutiile ecranelor, extinzând cu mult domeniul de aplicare peste ceea ce putem noi testa cu query-urile noastre. Ba mai mult, puteti testa mai multe proprietăti si valorile lor, printr-un singur query, prin înlăntuirea acestora împreuna cu cuvântul cheie:
Mai mult, nu există nicio limită în a încorpora media query-uri în link-urile noastre. Le putem include în CSS-ul nostru, sau ca parte a regulii @media:
Sau ca parte a unei directive @import:
Dar, în fiecare caz, efectul este acelasi: dacă dispozitivul trece testul prezentat de către media query-ul nostru, atunci se aplică CSS-ul relevant. Media query-urile sunt pe scurt comentarii conditionale pentru ceilalti. Decât să vizăm o anumită versiune a unui browser, mai degrabă ne putem corecta chirurgical problemele în layout, astfel încât să se potrivească si pe o altă rezolutie decât cea ideală.
Adaptează, răspunde și depăseste
Să ne îndreptăm atentia către baza paginii noastre. În layout-ul lor default, CSS-ul relevant arată cam asa:
Am omis o serie de proprietăti tipografice ca să ne concentrăm pe layout: fiecare figură este redimensionată la o treime din coloana care o contine, cu marginea de pe dreapta redusă la zero, pentru cele două poze de la finalul fiecărui rând (li#f-mycroft, li#f-winter). si acest lucru merge destul de bine, până când viewport-ul se vede fie mai mic, fie mai lat decât design-ul nostru initial. Cu media query-uri putem aplica spotfix-uri specifice rezolutiei, adaptând design-ul nostru pentru a răspunde mai bine schimbărilor dimensiunilor ecranului.
Mai întâi de toate să linearizăm pagina noastră, odată ce viewport-ul scade mai mult de o anumită rezolutie, sa zicem 600px. Astfel, în partea de jos a style sheet-ului, să creăm un bloc @media, cam asa:
Dacă vedem pagina noastră actualizată la un browser modern pentru desktop si reducem dimensiunea ferestrei până la mai putin de 600px, media query-ul va dezactiva elementele majore ale designului, stivuind fiecare bloc unul deasupra celuilalt în cursul documentului. Astfel, design-ul nostru miniaturizat, se conturează frumos, dar imaginile nu se redimensionează atât de inteligent. Dacă introducem un alt media query, putem modifica aspectul lor în consecintă:
Figurile noastre îsi pot schimba responsiv aspectul, pentru a se potrivi mai bine display-urilor de mici dimensiuni.
Nu deranjează procentele inestetice. Pur si simplu recalculăm lătimile gridului fluid pentru a tine cont de aspectul nou liniarizat. Pe scurt, trecem de la un aspect pe trei coloane la unul pe două coloane când dispozitivul de vizualizare scade sub 400px, făcând imaginile mai proeminente.
Putem folosi aceeasi abordare si pentru ecrane late. Pentru rezolutii mai mari, putem folosi o metodă în asa fel încât să punem imaginile în acelasi rând:
Acum imaginile noastre arată frumos la ambele extremităti ale spectrului rezolutiilor, optimizându-si aspectul atât la schimbările lătimii ferestrei, cât si la schimbările rezolutiilor dispozitivelor.
Specificând o lătime minimă mai mare într-un nou media querry putem aranja imaginile noastre pe un singur rând.
Dar acesta este doar începutul. Lucrând cu media query-ul pe care l-am integrat în CSS-ul nostru, putem modifica mult mai mult decât plasarea câtorva imagini: putem introduce noi aspecte adaptate pentru fiecare gamă de rezolutii, cum ar fi să facem o navigare mai bună pe un ecran lat sau să le repozitionăm deasupra logo-ului pe ecranele mai mici.
Prin design-ul responsiv, putem nu doar să liniarizăm continutul pe dispozitive mai mici, dar să optimizăm si aspectul pentru diferite dimensiuni ale ecranului.
Însă un design responsiv nu se limitează doar la schimbările de aspect. Media query-urile ne permit să realizăm un reglaj fin incredibil de precis pe măsură ce paginile noastre se re-aranjează singure: putem creste zona tintă pe link-uri pentru ecranele mici, aplicând mai bine legea lui Fitt pentru ecranele tactile; putem afisa sau ascunde selectiv anumite elemente, astfel încât să îmbunătătim navigarea prin pagină; putem folosi chiar o formatare graduală, responsivă a textului nostru, optimizând experienta citirii pentru diferite ecrane.
Câteva date tehnice
Trebuie remarcat faptul că media query-urile se bucură de un larg suport în rândul browserelor moderne. Browserele pentru desktop, cum ar fi Safari 3+, Chrome sau Opera7+ toate analizează media query-urile, la fel cum fac si browserele mobile cum ar fi Opera Mini sau WebKitl-ul mobil. Bineînteles că versiunile mai vechi ale acestor browsere nu suportă media query. si, în timp ce Microsoft s-a angajat să ofere suport media query în IE9, Internet Explorer-ul curent nu oferă o implementare nativă.
Totusi, dacă sunteti interesati de implementarea suportului browserelor pentru media query există un JavaScript cu această tentă:
Un plugin jQuery din 2007 oferă într-un fel suport limitat pentru media query, implementând doar proprietătile de lătime maximă si minimă atunci când sunt atasate separat pentru fiecare element.
Mai recent, a fost lansat css3-mediaqueries.js, o librărie care permite “să facă IE5+, Firefox1+ si Safari 2 să interpreteze transparent, să testeze si să aplice CSS3 Media Queries”, atunci când este inclusă într-un bloc @media. Am găsit versiunea 1.0 foarte robustă, si am de gând să urmăresc personal dezvoltarea acesteia.
Dar dacă utilizarea JavaScript nu vă atrage, este de înteles. Însă acest lucru ne întăreste posibilitătile de a construi aspectul cu ajutorul unui grid flexibil, asigurându-ne că design-ul nostru se bucură într-o oarecare măsură de flexibilitatea media query chiar si în browserele sau dispozitivele ce nu stiu de asa ceva.
Calea de urmat
Gridurile fluide, imaginile flexibile si media querry-urile sunt cele trei ingrediente tehnice pentru un web design responsiv, dar necesită si un alt tip de gândire. Decât să închidem continutul nostru în experiente separate dispozitiv-specifice, mai bine putem folosi media query-uri pentru a ne îmbunătăti progresiv munca, pentru diferite contexte de vizualizare; acest lucru nu înseamnă că nu există o serie de unelte pentru site-uri separate, orientate către anumite dispozitive; de exemplu, dacă obiectivele utilizatorului pentru site-ul nostru mobil sunt mai limitate fată de echivalentul său desktop, atunci servirea de continut diferit pentru fiecare versiune poate fi cea mai bună abordare.
Dar acest mod de a gândi designul nu trebuie să fie văzut ca default. Acum, mai mult ca oricând, munca noastră de designeri este menită să fie privită de-a lungul unui sir de experiente. Web designul responsiv ne oferă o cale de urmat, permitându-ne în final să realizăm “designul pentru fluxul si refluxul lucrurilor”.
3. Aplicație practică: www.photogear.ro
3.1. Oportunitate și fiabilitate.
În cadrul proiectului de licență doresc să vă prezint modul în care am implementat principiile RWD în cadrul site-ului web www.photogear.ro. Site-ul a fost dezvoltat inițial în aprilie 2011 și are ca bază de funcționare platforma wordpress. Desigur, designul – atât ca interfață grafică, cât și funcționalitate – a avut în vedere tehnologia disponibilă la momentul respectiv. Mai exact, s-a pornit de la rezultatele statisticilor care afirmau că cele mai utilizate rezoluții vin din partea monitoarelor de desktop și laptopuri cu rezoluția de minim 1024×768 pixeli. Cu toate că pe atunci au fost prezente tabletele și smartphonurile, numărul lor relativ mic – comparativ cu cel al PC-urilor și laptopurilor – au determinat neglijarea lor, și am decis optimizarea site-ului pentru rezoluția celor din urmă.
În prezent, statisticile cu privire la evoluția numărului de tablete, smartphonuri și PC-uri arată o creștere impresionantă a primelor două, așa cum se poate vedea în figura nr.1.
Din tabelul de mai jos se poate vedea cum se estimează că în anul 2017 numărul de smartphonuri și tablete va ajunge la aprox. 87% față de 13% PC-uri și tablete. Ei bine, această creștere trebuie luată în serios și tratată ca atare.
Cum ce va schimba designul paginilor site-ului atunci când avem deaface cu rezoluții mai mici – sau chiar mai mari – ale monitoarelor? Cum vom implementa interacțiunea cu touchscreenul?
Cum vom programa site-ul astfel încât să identifice tipul de dispozitiv și să funcționeze corect indiferent de platformă?
Sunt întrebări importante care trebuiesc puse. Dar, în timp ce atenția ne este îndreptată spre design și dezvoltare, nu trebuie să neglijăm modul în care vom aranja (sau adapta, prezenta) conținutul informațional cât mai potrivit cu fiecare dispozitiv mobil. Din fericire, răspunsul la această întrebare ne va fi de folos, indiferent de sistemul de operare folosit de dispozitivele mobile, de rezoluția afișajului, sau alte caracteristici. Stabilirea modului în care va fi structurată prezentarea informațiilor ne va da posibilitatea să o prezentăm pe orice fel de dispozitiv.
Tot mai mult, informația este accesată prin intermediul dispozitivului mobil. Limita dintre sarcinile caracteristice unui desktop și cele potrivite unui dispozitiv mobil este greu de stabilit. Uneori prefer să-mi folosesc mobilul pentru simplul motiv că sunt prea comod să mă ridic din fotoliu și să merg până la computer. Alte ori în timp ce sunt la computer mă trezesc că prefer să răspund la un email pe telefon (după ce în prealabil m-a anunțat că am primit un mesaj).
Sau, anumite acțiuni ca de exemplu rezervarea unui bilet la CinemaCity este mai simplu de făcut pe mobil – nu mai vezi atâtea bannere sau informații care le consideri nefolositoare.
Telefonul mobil este folosit oriunde, fie ca suntem acasă în fotoliu, fie că ne aflăm la plimbare prin oraș sau suntem într-un CaffeBar. Tableta este folosită cu deosebită atenție în cadrul unei întâlniri de business, la fel de mult ca și acasă când vrem să răsfoim relaxați știrile mondene. La birou, bineînțeles folosim desktop-uri sau laptop-uri.
Chiar dacă am ști ce tip de dispozitiv folosește utilizatorul nu putem ști care este intenția lui, sau chiar dacă știm care este locația din care accesează informația, nu știm nimic despre obiectivele acestei persoane. Putem doar presupune dar certitudini nu putem avea. Ceea ce știm în mod sigur este că folosește un dispozitiv cu ecran mai mic…
Prin urmare atunci când prezentăm versiunea mobilă a unui site web, ar fi bine să nu ofensăm pe nimeni prin prezentarea unei versiuni „diluate” sau “superficiale”. Dacă dorim să realizăm un site care să fie folosit pe dispozitivele mobile atunci va trebui să facem posibilă accesarea întregii informații, indiferent de context (natura sau tipul dispozitivelor).
Deși pare greu de crezut, acesta este adevărul. Nu noi trebuie să decidem ce să „tăiem” din informații deoarece oamenii accesează uneori același site și cu mobilul și cu desktopul. Nici să-i subestimăm și să le oferim o informație incompletă utilizatorilor de dispozitive mobile. Ar fi o mare greșeală să trimitem un utilizator de dispozitiv mobil să meargă la un desktop pentru a putea citi informația dorită. Chiar dacă conținutul este puțin diferit, sau prezentat într-un mod diferit pe dispozitive mobile, până la urmă utilizatorul trebuie să aibe parte de o experiență plăcută. [1]
După cum se poate vedea în imaginile alăturate, aceeași pagină web arată diferit pe dispozitive mobile ca smartphone, tabletă sau dispozitive fixe de tip laptop sau desktop.
Da, și aceasta nu în mod întâmplător nici pentru simplul fapt că afișajele dispozitivelor au rezoluții diferite sau sunt orientate în poziția portrait sau landscape.
Pagina web arată astfel pentru că așa am intenționat în calitate de programator al site-ului. Am intenționat ca pe smartphone, să avem – atunci când este orientat în poziția portrait – o imagine care are lățimea egală cu cea a dispozitivului, un titlu lizibil, și alte trei pictograme. Așa cum se poate vedea, meniul este ascuns, doar butonul toggle (binecunoscut pe dispozitivele mobile) ne dă de înțeles că în spatele lui este meniul de navigare. Pe tabletă, care are un ecran de două ori mai mare decât un smartphone, orientat în poziția landscape avem două imagini mai mari, fiecare cu titlul ei, iar în continuare se pot vedea altele, la fel de mari. Aici meniul este prezent, alături de logo-ul companiei și are loc în pagină chiar și un toggle de căutare. Cât despre afișajul unui desktop, aici pagina web este afișată în versiunea implicită. Cum se întâmplă aceste lucruri, cum de pagina site-ului răspunde la tipul de dispozitiv pe care se încarcă, sunt întrebări care țin de web design responsiv, și este subiectul acestei lucrări.
3.2. Detectarea dispozitivelor
Una din etapele dificile in realizarea unui site web responsiv este menținerea integrității responsive după ce site-ul este lansat, adica live. În general, administratorul site-ului are aptitudini limitate în domeniul scrierii codului și aceasta s-ar putea sa-l împiedice să poată menține tema site-ului responsivă.
Pentru a detecta dispozitivele care se conectează la site, pe baza accesului la nivel de server, am folosit pluginul WP Mobile Detect. Acesta facilitează ascunderea/afișarea conținutului prin folosirea unor shortcode-uri.
Folosind acest plugin, nu mai trebuie să ne bazăm pe expresii de cod ca și display:none; sau alte tehnici prin care uneori să ascundem conținutul pe dispozitivele mobile. Mai mult chiar, putem înlocui conținutul dorit cu alternative. Atunci când o imagine de tip infografic aflată într-un articol de pe site este descărcată la rezoluția maximă pe telefonul unui utilizator, putem considera că descărcarea a fost inițializată de către un Non-user, adică fără consimțământul utilizatorului. Acesta din urmă probabil habar nu are că poate și-a ocupat toată lățimea de bandă.
Pluginul WP Mobile Detect ne dă posibilitatea să cuprindem acea imagine de tip infografic în cod de tip [notdevice][/notdevice] astfel încât la nivel de server putem decide dacă vrem să afișăm imaginea respectivă doar dacă utilizatorul NU folosește o tabletă sau un telefon mobil.
Pe de altă parte, am putea cuprinde aceeași imagine de tip infografic în cod de tip [device][/device] ca și o posibilitate pentru utilizator de a descărca imaginea cu acordul lui.
Pentru a instala acest plugin pe site, am urcat fișierele mobile-detect.php readme.txt și wp-mobile-detect.php pe server, unde am activat pluginul în cadrul secțiunii Plugins din meniul panoului de administrare, iar apoi am început să folosesc shortcode-ul în conținutul temei și a funcțiilor acesteia.
În continuare prezint căteva din shortcoduri-le care pot fi folosite pentru afișarea / ascunderea conținutului unei pagini web, în funcție de tipul dispozitivelor pe care este accesată pagina site-ului:
* [phone]Aici se pune conținutul care vrem să fie afișat pe Telefon dar NU pe Tabletă SAU desktop[/phone]
* [tablet] Aici se pune conținutul care vrem să fie afișat pe Tabletă dar NU pe Telefon SAU Desktop[/tablet]
* [device] Aici se pune conținutul care vrem să fie afișat pe Telefon SAU Tabletă dar NU pe Desktop[/device]
* [notphone] Aici se pune conținutul care vrem să fie afișat pe Tabletă SAU Desktop dar NU pe Telefon[/notphone]
* [nottab] Aici se pune conținutul care vrem să fie afișat pe Telefon SAU Desktop dar NU pe Tabletă[/nottab]
* [notdevice]Aici se pune conținutul care vrem să fie afișat pe Desktop dar NU pe Telefon SAU Tabletă[/notdevice]
* [ios] Aici se pune conținutul care vrem să fie afișat pe dispozitive iOS[/ios]
* [iPhone] Aici se pune conținutul care vrem să fie afișat pe iPhone[/iPhone]
* [iPad]Aici se pune conținutul care vrem să fie afișat pe iPad[/iPad]
* [android] Aici se pune conținutul care vrem să fie afișat pe dispozitive Android [/android]
* [windowsmobile] Aici se pune conținutul care vrem să fie afișat pe dispozitive Windows Mobile [/windowsmobile]
Cu acest plugin sunt disponibile următoarele funcții care pot fi apelate în cadrul temei:
* wpmd_is_notphone() – Returnează true dacă este pe desktop sau tabletă
* wpmd_is_nottab() – Returnează true dacă este pe desktop sau telefon
* wpmd_is_notdevice() – Returnează true dacă este pe desktop only
* wpmd_is_phone() – Returnează true dacă este NUMAI pe telefon
* wpmd_is_tablet() – Returnează true dacă este NUMAI pe Tabletă
* wpmd_is_device() – Returnează true dacă este pe telefon sau tabletă dar NU destkop
* wpmd_is_ios() – Returnează true dacă este pe un dispozitiv iOS
* wpmd_is_iphone() – Returnează true dacă este pe iPhone
* wpmd_is_ipad() – Returnează true dacă este pe iPad
* wpmd_is_android() – Returnează true dacă este pe Android
* wpmd_is_windows_mobile() – Returnează true dacă este pe Windows Mobile [2]
3.3. Adăugarea de câmpuri personalizate
Acum, după ce am rezolvat problema detectării dispozitivului, și avem pârghiile necesare ascunderii / afișării conținutului, am creat o alternativă – ce urmează a fi afișată pe dispozitive mobile – pentru Short Title (Titlul Scurt al articolelor de pe site) și pentru Short Excerpt (Citate Scurte). Aceste două câmpuri vor fi disponibile în panoul de administrare atunci când vrem să adăugăm un articol nou pe site. Nu vom folosi alternative pentru conținutul articolelor deoarece dorim ca acestea să fie afișate în întregime atunci când acest lucru este posibil, indiferent de dispozitivul care accesează pagina site-ului. Desigur, vom folosi WP-Mobile Detect pentru a ajusta prezentarea conținutului.
3.4.Adaptarea conținutului în funcție de dispozitiv.
Această „adaptare” este mai degrabă o afișare potrivită a conținutului în funcție de dispozitivul pe care dorim să încărcăm pagina web.
După ce am adăugat cele două câmpuri noi, am creat o funcție care face posibilă afișarea potrivită atunci când este încărcată pagina site-ului pe un telefon mobil. Cu alte cuvinte, am înlocuit conținutul original al titlului și a citatelor cu o versiune mai scurtă care se încadrează mai bine pe ecranul telefonului.
Am făcut acest lucru prin adăugarea următoarei funcții la documentul functions.php
Funcția adaptive_content este folosită atât de filtrul the_title cât și de filtrul the_excerpt și se execută ori de câte ori este apelată. Prin verificarea if ( !in_the_loop() se asigură filtrarea paginilor cu postări.
Funcția wpmd_is_phone() este folosită pentru a verifica dacă dispozitivul folosit este sau nu telefon. Dacă este telefon, atunci prin filtrele „the_title” și „the_excerpt” se folosesc numele câmpurilor create anterior, atunci când avem o apelare de tip get_field. Dacă câmpurile au fost completate, atunci este returnat conținutul lor, dacă nu, atunci este returnat conținutul original. [3]
3.5.Adăugarea meniului pt. dispozitive mobile
Un aspect foarte important în realizarea unui site care răspunde și se adaptează la dispozitivele pe care este încărcat, este asigurarea unui meniu de navigare special pentru dispozitivele mobile. Pentru aceasta, am avut în vedere realizarea unei coloane (sidebar) care să conțină meniul și care se ascunde în lateral (slide-out). Deasemenea am folosit un buton care în loc să arate meniul, va activa slide-out-ul într-un mod specific dispozitivelor mobile și care va fi poziționat astfel încât să fie ușor de atins cu degetul mare.
Pentru implementarea meniului lateral am folosit un un plugin facut pentru jQuery, numit Sidr.
Pluginul Sidr are capacitatea de a implementa meniul pe stânga sau pe dreapta ecranului. El este format din urnătoarele blocuri:
un DIV care conține codul HTML
un link care are setat href către id -ul DIV-ului meniului lateral; acesta comută afișarea sau ascunderea meniului
Un script Java pentru a lega funcționarea Sidr de link
Pluginul Sidr are capacitatea să administreze mai multe meniuri, atât pe stânga cât și pe dreapta. Când un meniu este afișat, atunci conținutul se deplasează în aceeași direcție. Prin urmare, dacă facem click pe un link pentru mâna dreaptă, meniul se va deplasa spre stânga, și vom putea face scroll pe conținutul principal în partea stângă. În urma instalării plugin-ului am realizat următorii pași:
Am creat o zonă de tip widget pentru coloana (sidebar) care se deplasează spre lateral (slide-out) în functions.php astfel:
După cum se poate vedea, am adăugat clasa mobile-widget la containerul widgetului pentru a putea specifica modul în care va arăta acest widget, separat de celelalte widget-uri din cadrul temei.
Pentru a putea folosi un buton pentru meniu – specific numai dispozitivelor mobile – care să asigure slide-out în locul afișării meniului de navigare clasic, trebuie să includem un meniu în nou creata sidebar. Pentru o flexibilitate și mai mare, vom adăuga la locația meniului existent o opțiune ”mobil”, fapt care ne permite să atribuim un meniu mobil diferit de meniul clasic. Pentru aceasta, am adăugat următorul cod la functions.php:
Acum, că avem zona widget și noul meniu pentru mobil, va trebui să ne asigurăm că, coloana (sidebar) funcționează corect. Pentru aceasta am creat o nouă funcție wp_is_mobile() care, atunci când este cazul, să afișeze sidebar-ul. Codul pentru această funcție a fost inclus în documentul sidebar.php și arată astfel:
Această coloană sidebar folosește funcția wp_is_mobile(), pentru a putea afișa o coloană sidebar diferită, specific construită pentru dispozitivele mobile. Totodată, această coloană (sidebar) poziționează id-ul #slideout și clasa sidr în recipientul exterior al coloanei. Rezultatul poate fi văzut în următoarele două figuri:
Odată ce componentele sidebar-ului sunt create, a trebuit doar activat. Pentru aceasta am creat un document numit slideout.js în care am adăugat următorul javascript:
Așa cum se poate vedea și în imaginile de mai sus, acest javascript afișează butonul de meniu pentru dispozitivele mobile (menu toggle icon). Prin atingerea lui, coloana laterală (sidebar) – inițial ascunsă – se va deplasa spre interiorul ecranului și va deveni vizibilă, sau la următoarea atingere se va deplasa spre exterior (se va ascunde).
În final, am creat o funcție prin care site-ul să știe de javascriptul Sidr, de javascriptul slide-out și de pagina .css. Aceasta am adăugat-o la documentul functions.php astfel:
Pentru a putea asigura folosirea javascriptului și a CSS -ului necesar, am folosit wp_enqueue_script.
După cum se poate vedea în codul de mai sus, există anumite dependențe, și anume Sidr depinde de jQuery, Slideout depinde de Sidr iar acțiunile sunt apelate doar atunci când dispozitivul mobil face apelul.
3.6. Optimizare Header pt. dispozitive mobile și desktop
În funcție de dispozitivul pe care se încarcă site-ul, este de dorit să avem un header implicit, de dimensiuni potrivite pentru sisteme desktop sau laptop și un header de dimensiuni reduse, care să nu ocupe mult din suprafața afișajului pentru dispozitive mobile. Pentru aceasta am folosit următorul cod în cadrul documentului header.php:
Pentru a obține un header pentru mobil care să aibe un aspect plăcut, va trebui să specificăm toate informațiile referitoare la dimensiuni, culori și forme în cadrul fișierului style.css după cum urmează:
O altă înbunătățire pe care am adus-o afișării paginii web este legată de aspectul headerului pe dispozitive care nu sunt mobile. Acesta, la momentul în care se încarcă pentru prima dată va fi mai mare (mai înalt) și se va subția în momentul în care utilizatorul va începe să navigheze în josul paginii (scroll). Atunci când se subțiază headerul, elementele care nu sunt neapărat necesare vor fi ascunse, iar cele care vor rămâne, vor fi reașezate printr-o animație plăcută ochiului.
Atunci când am actualizat slide-out sidebar din header.php, am efectuat și modificările aferente headerului, prin urmare va trebui să ne ocupăm de aspect prin specificări în style.css.
Întrucât dorim ca această adaptare a headerului să afecteze doar dispozitivele care nu sunt mobile, am plasat css și jQuery în documente separate de cele principale ca să fie folosite doar când e nevoie pe dispozitive non mobile.
Aceasta implică crearea unui Javascript în folderul js. Totodată, vom adăuga noul javascript prin o nouă funcție legată de acțiunile wp_enqueue_scripts care sunt folosite numai dacă wp_is_mobile() nu returnează true. Astfel nu descărcăm pe dispozitive mobile Javascripturi care nu sunt necesare, în special unul ca acesta care încontinuu efectuează ajustări, pe măsură ce pagina este derulată (scroll).
Pentru aceasta, am adăugat următorul cod în documentul functions.php:
Pentru a putea obține o afișare optimă pe display atunci când se încarcă pagina, am configurat în CSS afișarea topbar-ului în întregime, la dimensiunea maximă.
Strategia adoptată a fost să creez două rânduri asigurându-mă că #top-big este un element de tip block în timp ce restul sunt elemente de tip inline. Practic, acest aspect l-am specificat atunci când am rearanjat headerul pentru meniul slide-out, prin urmare singura preocupare rămasă a fost ce se întâmplă când este modificată dimensiunea ferestrei browserului.
Cu toate că am folosit o strategie de adaptabilitate (responsivitate) în abordarea navigării pe dispozitive mobile – prin coloana care se deplasează în lateral (slide-out sidebar) – trebuia să mă asigur că designul paginii răspunde la acțiunile utilizatorului, acțiuni de îngustare / lățire a ferestrei browserului. Acest lucru se poate face prin adăugarea de @media query. Astfel, am adăugat următorul cod la documentul style.css:
Pentru a rearanja headerul atunci când se dă scroll la pagină (se navighează pe pagina în jos) am folosit un javascript numit scrollTop() de la jQuery. Această funcție returnează poziția barei de navigare verticală pentru un container – care în cazul de față este body. Aceasta ne permite să comprimăm headerul ori de câte ori pagina este derulată față de partea de sus a paginii (page top). Cum? Verificăm dacă poziția scroll este mai mare decât zero. Atunci când valoarea scroll revine la zero atunci reașezăm totul la poziția inițială.
Deasemenea, acest script include două funcții prin care ne asigurăm că topbar nu se suprapune cu conținutul principal (main content) și cu bara de sus, atunci când suntem în panoul de administrare al site-ului. Aceste corecții sunt efectuate prin jQuery din moment ce #masthead și #wpadmin se pot modificaîn funcție de lățimea ecranului și de poziția de scroll. Pentru a calcula înălțimile lor, am folosit funcția jQuery, height() și iar valorile obținute, le-am folosit la parametrii top-margin din css. Astfel am creat documentul topbar.js din folderul /js care arată astfel:
3.7. Afișarea pe dispozitive mobile a articolelor evidențiate
Prin această opțiune am definit numărul și modul în care sunt afișate articolele care dorim să fie evidențiate. Pentru aceasta am adăugat în cadrul functions.php următorul cod:
Prin acest cod am adăugat trei setări noi, și anume num_posts_grid – numărul de articole care vor apărea în grid, num_posts_slider – numărul de postări care vor apărea în slider și layout_mobile – care stabilește ce fel de aspect va fi afișat pe dispozitivele mobile: grid sau slider.
Pentru a putea folosi efectul slider pe dispozitivele mobile în vederea afișării imaginilor reprezentative pentru fiecare articol, am folosit un script Java numit Flexslider. După ce am mutat documentul jquery.flexslider-min.js în temei site-ului, am adăugat la funcția functions.php. următorul cod:
Prin aceasta am înlocuit codul pentru slider și scriptul functions cu versiunea personalizată și astfel codul pentru Flexslider va fi încarcat doar atunci când se cere slider-ul; astfel evităm să risipim resursele dacă nu este cazul. Acest cod, deasemenea, șterge fișierele functions din tema părinte a site-ului, urmănd ca versiunea Flexslider să poată fi executată atunci când este nevoie.
Concluzii
Bibliografie
[***1] http://ctrl-d.ro/design/resurse-design/introducere-in-responsive-typography/
[***2] http://ro.wikipedia.org/wiki/Culoare
[***3] http://ro.wikipedia.org/wiki/HTML5
[***4] http://ro.wikipedia.org/wiki/Cascading_Style_Sheets
[***5] KAREN MCGRANE November 05, 2012 Content Strategy for Mobile link
[***6] Jesse Friedman – PHP Mobile Detect class – WordPress Plugin link
[7] Chris Knowles, Sept. 25, 2013 How To Make Content Adapt To A Responsive WordPress Theme
[8] http://premium.wpmudev.org/blog/how-to-make-twenty-fourteen-or-any-other-wp-theme-super/
[9]
<?php
/*
Plugin Name: WP Mobile Detect
Version: 1.2.0
Plugin URI: http://jes.se.com/wp-mobile-detect
Description: A WordPress plugin based on the PHP Mobile Detect class (Original author Victor Stanciu now maintained by Serban Ghita) incorporates functions and shortcodes to empower User Admins to have better control of when content is served
Author: Jesse Friedman
Author URI: http://jes.se.com
License: GPL v3
WP Mobile Detect
Copyright (C) 2012, Jesse Friedman – http://jes.se.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/********************************************//**
* PHP Mobile Detect class used to detect browser or device type
***********************************************/
require_once('mobile-detect.php');
$detect = new Mobile_Detect();
/********************************************//**
* Generates [notmobile][/notmobile] shortcode which shows content on desktops or tablets
***********************************************/
function wpmd_notphone( $tats, $content="" ) {
global $detect;
if( ! $detect->isMobile() || $detect->isTablet() ) return do_shortcode($content);
}
add_shortcode( 'notphone', 'wpmd_notphone' );
/********************************************//**
* Returns true when on desktops or tablets
***********************************************/
function wpmd_is_notphone() {
global $detect;
if( ! $detect->isMobile() || $detect->isTablet() ) return true;
}
/********************************************//**
* Generates [nottab][/nottab] shortcode which shows content on desktops or phones
***********************************************/
function wpmd_nottab( $tats, $content="" ) {
global $detect;
if( ! $detect->isTablet() ) return do_shortcode($content);
}
add_shortcode( 'nottab', 'wpmd_nottab' );
/********************************************//**
* Returns true when on desktops or phones
***********************************************/
function wpmd_is_nottab() {
global $detect;
if( ! $detect->isTablet() ) return true;
}
/********************************************//**
* Generates [notdevice][/notdevice] shortcode which shows content on desktops only
***********************************************/
function wpmd_notdevice( $tats, $content="" ) {
global $detect;
if( ! $detect->isMobile() && ! $detect->isTablet() ) return do_shortcode($content);
}
add_shortcode( 'notdevice', 'wpmd_notdevice' );
/********************************************//**
* Returns true when on desktops only
***********************************************/
function wpmd_is_notdevice() {
global $detect;
if( ! $detect->isMobile() && ! $detect->isTablet() ) return true;
}
/********************************************//**
* Generates [phone][/phone] shortcode which shows content on phones ONLY
***********************************************/
function wpmd_phone( $tats, $content="" ) {
global $detect;
if( $detect->isMobile() && ! $detect->isTablet() ) return do_shortcode($content);
}
add_shortcode( 'phone', 'wpmd_phone' );
/********************************************//**
* Returns true when on phones ONLY
***********************************************/
function wpmd_is_phone() {
global $detect;
if( $detect->isMobile() && ! $detect->isTablet() ) return true;
}
/********************************************//**
* Generates [tablet][/tablet] shortcode which shows content on Tablets ONLY
***********************************************/
function wpmd_tablet( $tats, $content="" ) {
global $detect;
if( $detect->isTablet() ) return do_shortcode($content);
}
add_shortcode( 'tablet', 'wpmd_tablet' );
/********************************************//**
* WARNING: This is deprecated. Conflicts with the [tab] shortcode changed to [tablet] Generates [tab][/tab] shortcode which shows content on Tablets ONLY
***********************************************/
function wpmd_tab( $tats, $content="" ) {
global $detect;
if( $detect->isTablet() ) return do_shortcode($content);
}
add_shortcode( 'tab', 'wpmd_tab' );
/********************************************//**
* Returns true when on Tablets ONLY
***********************************************/
function wpmd_is_tablet() {
global $detect;
if( $detect->isTablet() ) return true;
}
/********************************************//**
* Generates [device][/device] shortcode which shows content on phones or tablets but NOT destkop
***********************************************/
function wpmd_device( $tats, $content="" ) {
global $detect;
if( $detect->isMobile() || $detect->isTablet() ) return do_shortcode($content);
}
add_shortcode( 'device', 'wpmd_device' );
/********************************************//**
* Returns true when on phones or tablets but NOT destkop
***********************************************/
function wpmd_is_device() {
global $detect;
if( $detect->isMobile() || $detect->isTablet() ) return true;
}
/********************************************//**
* Generates [ios][/ios] shortcode which shows content on iOS devices only
***********************************************/
function wpmd_ios( $tats, $content="" ) {
global $detect;
if( $detect->isiOS() ) return do_shortcode($content);
}
add_shortcode( 'ios', 'wpmd_ios' );
/********************************************//**
* Returns true when on iOS
***********************************************/
function wpmd_is_ios() {
global $detect;
if( $detect->isiOS() ) return true;
}
/********************************************//**
* Generates [iPhone][/iPhone] shortcode which shows content on iPhone's only
***********************************************/
function wpmd_iphone( $tats, $content="" ) {
global $detect;
if( $detect->isiPhone() ) return do_shortcode($content);
}
add_shortcode( 'iPhone', 'wpmd_iphone' );
/********************************************//**
* Returns true when on iPhone
***********************************************/
function wpmd_is_iphone() {
global $detect;
if( $detect->isiPhone() ) return true;
}
/********************************************//**
* Generates [iPad][/iPad] shortcode which shows content on iPad's only
***********************************************/
function wpmd_ipad( $tats, $content="" ) {
global $detect;
if( $detect->isiPad() ) return do_shortcode($content);
}
add_shortcode( 'iPad', 'wpmd_ipad' );
/********************************************//**
* Returns true when on iPad
***********************************************/
function wpmd_is_ipad() {
global $detect;
if( $detect->isiPad() ) return true;
}
/********************************************//**
* Generates [android][/android] shortcode which shows content on Android devices only
***********************************************/
function wpmd_android( $tats, $content="" ) {
global $detect;
if( $detect->isAndroidOS() ) return do_shortcode($content);
}
add_shortcode( 'android', 'wpmd_android' );
/********************************************//**
* Returns true when on Android OS
***********************************************/
function wpmd_is_android() {
global $detect;
if( $detect->isAndroidOS() ) return true;
}
/********************************************//**
* Generates [windowsmobile][/windowsmobile] shortcode which shows content on Windows Mobile devices only
***********************************************/
function wpmd_windows_mobile( $tats, $content="" ) {
global $detect;
if( $detect->isWindowsMobileOS() ) return do_shortcode($content);
}
add_shortcode( 'windowsmobile', 'wpmd_windows_mobile' );
/********************************************//**
* Returns true when on Android OS
***********************************************/
function wpmd_is_windows_mobile() {
global $detect;
if( $detect->isWindowsMobileOS() ) return true;
}
=========================================================================
<?php
/**
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* @author Serban Ghita <[anonimizat]>
* Victor Stanciu <[anonimizat]> (until v.1.0)
* @license MIT License https://github.com/serbanghita/Mobile-Detect/blob/master/LICENSE.txt
* @link Official page: http://mobiledetect.net
* GitHub Repository: https://github.com/serbanghita/Mobile-Detect
* Google Code Old Page: http://code.google.com/p/php-mobile-detect/
* @version 2.5.8
*/
class Mobile_Detect {
protected $scriptVersion = '2.5.8';
// External info.
protected $userAgent = null;
protected $httpHeaders;
// Arrays holding all detection rules.
protected $mobileDetectionRules = null;
protected $mobileDetectionRulesExtended = null;
// Type of detection to use.
protected $detectionType = 'mobile'; // mobile, extended @todo: refactor this.
// List of mobile devices (phones)
protected $phoneDevices = array(
'iPhone' => '\biPhone.*Mobile|\biPod|\biTunes',
'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+',
'HTC' => 'HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6425|001HT|Inspire 4G|Android.*\bEVO\b',
'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile',
// @todo: Is 'Dell Streak' a tablet or a phone? 😉
'Dell' => 'Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b',
'Motorola' => 'Motorola|\bDroid\b.*Build|DROIDX|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT909|XT910|XT912|XT928',
'Samsung' => 'Samsung|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9300 |GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-P6810|GT-P7100|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N8010',
'Sony' => 'sony|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i',
'Asus' => 'Asus.*Galaxy',
'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ; @todo – complete the regex.
'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', // Just for fun 😉
// @ref: http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH)
// Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android.
'Pantech' => 'PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790',
// @ref: http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones.
'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250',
// Added simvalley mobile just for fun. They have some interesting devices.
// @ref: http://www.simvalley.fr/telephonie–gps-_22_telephonie-mobile_telephones_.html
'SimValley' => '\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\b',
// @Tapatalk is a mobile app; @ref: http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039
'GenericPhone' => 'Tapatalk|PDA;|PPC;|SAGEM|mmp|pocket|psp|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|wap|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser|LG-P500'
);
// List of tablet devices.
protected $tabletDevices = array(
'iPad' => 'iPad|iPad.*Mobile', // @todo: check for mobile friendly emails topic.
'NexusTablet' => '^.*Android.*Nexus(((?:(?!Mobile))|(?:(\s(7|10).+))).)*$',
'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1010|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P6810|GT-P7501',
// @reference: http://www.labnol.org/software/kindle-user-agent-string/20378/
'Kindle' => 'Kindle|Silk.*Accelerated',
// Only the Surface tablets with Windows RT are considered mobile.
// @ref: http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx
'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;',
'AsusTablet' => 'Transformer|TF101',
'BlackBerryTablet' => 'PlayBook|RIM Tablet',
'HTCtablet' => 'HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200',
'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617',
'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNTV250A|LogicPD Zoom2',
// @ref: http://www.acer.ro/ac/ro/RO/content/drivers
// @ref: http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer)
'AcerTablet' => 'Android.*\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71)\b',
// @ref: http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/
// @ref: http://us.toshiba.com/tablets/tablet-finder
// @ref: http://www.toshiba.co.jp/regza/tablet/
'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)',
// @ref: http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html
'LGTablet' => '\bL-06C|LG-V900|LG-V909',
'YarvikTablet' => 'Android.*(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468)',
'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB',
'ArnovaTablet' => 'AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT',
// @reference: http://wiki.archosfans.com/index.php?title=Main_Page
'ArchosTablet' => 'Android.*ARCHOS|101G9|80G9',
// @reference: http://en.wikipedia.org/wiki/NOVO7
'AinolTablet' => 'NOVO7|Novo7Aurora|Novo7Basic|NOVO7PALADIN',
// @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER
// @ref: Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser
// @ref: http://www.sony.jp/support/tablet/
'SonyTablet' => 'Sony Tablet|Sony Tablet S|SGPT12|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT211|SGPT213|EBRD1101|EBRD1102|EBRD1201',
// @ref: db + http://www.cube-tablet.com/buy-products.html
'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT',
// @ref: http://www.cobyusa.com/?p=pcat&pcat_id=3001
'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010',
// @ref: http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets)
// @ref: http://www.imp3.net/14/show.php?itemid=20454
'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)',
// @ref: http://www.rock-chips.com/index.php?do=prod&pid=2
'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A',
// @ref: http://www.telstra.com.au/home-phone/thub-2/
'TelstraTablet' => 'T-Hub2',
// @ref: http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/
'FlyTablet' => 'IQ310|Fly Vision',
// @ref: http://www.bqreaders.com/gb/tablets-prices-sale.html
'bqTablet' => 'bq.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant)',
// @ref: http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290
// @ref: http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets)
'HuaweiTablet' => 'MediaPad|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim',
// Nec or Medias Tab
'NecTablet' => '\bN-06D|\bN-08D',
// Pantech Tablets: http://www.pantechusa.com/phones/
'PantechTablet' => 'Pantech.*P4100',
// Broncho Tablets: http://www.broncho.cn/ (hard to find)
'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)',
// @ref: http://versusuk.com/support.html
'VersusTablet' => 'TOUCHPAD.*[78910]',
// @ref: http://www.zync.in/index.php/our-products/tablet-phablets
'ZyncTablet' => 'z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900',
// @ref: http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/
'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA',
// @ref: https://www.nabitablet.com/
'NabiTablet' => 'Android.*\bNabi',
// @note: Avoid detecting 'PLAYSTATION 3' as mobile.
'PlaystationTablet' => 'Playstation.*(Portable|Vita)',
'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|ViewPad7|MID7015|BNTV250A|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|hp-tablet',
);
// List of mobile Operating Systems.
protected $operatingSystems = array(
'AndroidOS' => 'Android',
'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os',
'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino',
'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b',
// @reference: http://en.wikipedia.org/wiki/Windows_Mobile
'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;',
// @reference: http://en.wikipedia.org/wiki/Windows_Phone
// http://wifeng.cn/?r=blog&a=view&id=106
// http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx
'WindowsPhoneOS' => 'Windows Phone OS|XBLWP7|ZuneWP7',
'iOS' => '\biPhone.*Mobile|\biPod|\biPad',
// http://en.wikipedia.org/wiki/MeeGo
// @todo: research MeeGo in UAs
'MeeGoOS' => 'MeeGo',
// http://en.wikipedia.org/wiki/Maemo
// @todo: research Maemo in UAs
'MaemoOS' => 'Maemo',
'JavaOS' => 'J2ME/|Java/|\bMIDP\b|\bCLDC\b',
'webOS' => 'webOS|hpwOS',
'badaOS' => '\bBada\b',
'BREWOS' => 'BREW',
);
// List of mobile User Agents.
protected $userAgents = array(
// @reference: https://developers.google.com/chrome/mobile/docs/user-agent
'Chrome' => '\bCrMo\b|CriOS|Android.*Chrome/[.0-9]* (Mobile)?',
'Dolfin' => '\bDolfin\b',
'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|OPR/[0-9.]+',
'Skyfire' => 'Skyfire',
'IE' => 'IEMobile|MSIEMobile',
'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile',
'Bolt' => 'bolt',
'TeaShark' => 'teashark',
'Blazer' => 'Blazer',
// @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3
'Safari' => 'Version.*Mobile.*Safari|Safari.*Mobile',
// @ref: http://en.wikipedia.org/wiki/Midori_(web_browser)
//'Midori' => 'midori',
'Tizen' => 'Tizen',
'UCBrowser' => 'UC.*Browser|UCWEB',
// @ref: https://github.com/serbanghita/Mobile-Detect/issues/7
'DiigoBrowser' => 'DiigoBrowser',
// http://www.puffinbrowser.com/index.php
'Puffin' => 'Puffin',
// @ref: http://mercury-browser.com/index.html
'Mercury' => '\bMercury\b',
// @reference: http://en.wikipedia.org/wiki/Minimo
// http://en.wikipedia.org/wiki/Vision_Mobile_Browser
'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision'
);
// Utilities.
protected $utilities = array(
// Experimental. When a mobile device wants to switch to 'Desktop Mode'.
// @ref: http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/
// @ref: https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011
'DesktopMode' => 'WPDesktop',
'TV' => 'SonyDTV115', // experimental
'WebKit' => '(webkit)[ /]([\w.]+)',
'Bot' => 'Googlebot|DoCoMo|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|facebookexternalhit',
'MobileBot' => 'Googlebot-Mobile|DoCoMo|YahooSeeker/M1A1-R2D2',
);
// Properties list.
// @reference: http://user-agent-string.info/list-of-ua#Mobile Browser
const VER = '([\w._]+)';
protected $properties = array(
// Build
'Mobile' => 'Mobile/[VER]',
'Build' => 'Build/[VER]',
'Version' => 'Version/[VER]',
'VendorID' => 'VendorID/[VER]',
// Devices
'iPad' => 'iPad.*CPU[a-z ]+[VER]',
'iPhone' => 'iPhone.*CPU[a-z ]+[VER]',
'iPod' => 'iPod.*CPU[a-z ]+[VER]',
//'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'),
'Kindle' => 'Kindle/[VER]',
// Browser
'Chrome' => 'Chrome/[VER]',
'CriOS' => 'CriOS/[VER]',
'Dolfin' => 'Dolfin/[VER]',
// @reference: https://developer.mozilla.org/en-US/docs/User_Agent_Strings_Reference
'Firefox' => 'Firefox/[VER]',
'Fennec' => 'Fennec/[VER]',
// @reference: http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx
'IEMobile' => array('IEMobile/[VER];', 'IEMobile [VER]'),
'MSIE' => 'MSIE [VER];',
// http://en.wikipedia.org/wiki/NetFront
'NetFront' => 'NetFront/[VER]',
'NokiaBrowser' => 'NokiaBrowser/[VER]',
'Opera' => 'Version/[VER]',
'Opera Mini' => 'Opera Mini/[VER]',
'Opera Mobi' => 'Version/[VER]',
'UC Browser' => 'UC Browser[VER]',
'Safari' => 'Version/[VER]',
'Skyfire' => 'Skyfire/[VER]',
'Tizen' => 'Tizen/[VER]',
'Webkit' => 'webkit[ /][VER]',
// Engine
'Gecko' => 'Gecko/[VER]',
'Trident' => 'Trident/[VER]',
'Presto' => 'Presto/[VER]',
// OS
'Android' => 'Android [VER]',
'BlackBerry' => array('BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]'),
'BREW' => 'BREW [VER]',
'Java' => 'Java/[VER]',
// @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx
// @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases
'Windows Phone OS' => 'Windows Phone OS [VER]',
'Windows Phone' => 'Windows Phone [VER]',
'Windows CE' => 'Windows CE/[VER]',
// http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd
'Windows NT' => 'Windows NT [VER]',
'Symbian' => array('SymbianOS/[VER]', 'Symbian/[VER]'),
'webOS' => array('webOS/[VER]', 'hpwOS/[VER];'),
);
function __construct(){
$this->setHttpHeaders();
$this->setUserAgent();
$this->setMobileDetectionRules();
$this->setMobileDetectionRulesExtended();
}
/**
* Get the current script version.
* This is useful for the demo.php file,
* so people can check on what version they are testing
* for mobile devices.
*/
public function getScriptVersion(){
return $this->scriptVersion;
}
public function setHttpHeaders($httpHeaders = null){
if(!empty($httpHeaders)){
$this->httpHeaders = $httpHeaders;
} else {
foreach($_SERVER as $key => $value){
if(substr($key,0,5)=='HTTP_'){
$this->httpHeaders[$key] = $value;
}
}
}
}
public function getHttpHeaders(){
return $this->httpHeaders;
}
public function setUserAgent($userAgent = null){
if(!empty($userAgent)){
$this->userAgent = $userAgent;
} else {
$this->userAgent = isset($this->httpHeaders['HTTP_USER_AGENT']) ? $this->httpHeaders['HTTP_USER_AGENT'] : null;
if(empty($this->userAgent)){
$this->userAgent = isset($this->httpHeaders['HTTP_X_DEVICE_USER_AGENT']) ? $this->httpHeaders['HTTP_X_DEVICE_USER_AGENT'] : null;
}
// Header can occur on devices using Opera Mini (can expose the real device type). Let's concatenate it (we need this extra info in the regexes).
if(!empty($this->httpHeaders['HTTP_X_OPERAMINI_PHONE_UA'])){
$this->userAgent .= ' '.$this->httpHeaders['HTTP_X_OPERAMINI_PHONE_UA'];
}
}
}
public function getUserAgent(){
return $this->userAgent;
}
function setDetectionType($type = null){
$this->detectionType = (!empty($type) ? $type : 'mobile');
}
public function getPhoneDevices(){
return $this->phoneDevices;
}
public function getTabletDevices(){
return $this->tabletDevices;
}
/**
* Method sets the mobile detection rules.
*
* This method is used for the magic methods $detect->is*()
*/
public function setMobileDetectionRules(){
// Merge all rules together.
$this->mobileDetectionRules = array_merge(
$this->phoneDevices,
$this->tabletDevices,
$this->operatingSystems,
$this->userAgents
);
}
/**
* Method sets the mobile detection rules + utilities.
* The reason this is separate is because utilities rules
* don't necessary imply mobile.
*
* This method is used inside the new $detect->is('stuff') method.
*
* @return bool
*/
public function setMobileDetectionRulesExtended(){
// Merge all rules together.
$this->mobileDetectionRulesExtended = array_merge(
$this->phoneDevices,
$this->tabletDevices,
$this->operatingSystems,
$this->userAgents,
$this->utilities
);
}
/**
* @return array
*/
public function getRules()
{
if($this->detectionType=='extended'){
return $this->mobileDetectionRulesExtended;
} else {
return $this->mobileDetectionRules;
}
}
/**
* Check the HTTP headers for signs of mobile.
* This is the fastest mobile check possible; it's used
* inside isMobile() method.
* @return boolean
*/
public function checkHttpHeadersForMobile(){
if(
isset($this->httpHeaders['HTTP_ACCEPT']) &&
(strpos($this->httpHeaders['HTTP_ACCEPT'], 'application/x-obml2d') !== false || // Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/
strpos($this->httpHeaders['HTTP_ACCEPT'], 'application/vnd.rim.html') !== false || // BlackBerry devices.
strpos($this->httpHeaders['HTTP_ACCEPT'], 'text/vnd.wap.wml') !== false ||
strpos($this->httpHeaders['HTTP_ACCEPT'], 'application/vnd.wap.xhtml+xml') !== false) ||
isset($this->httpHeaders['HTTP_X_WAP_PROFILE']) || // @todo: validate
isset($this->httpHeaders['HTTP_X_WAP_CLIENTID']) ||
isset($this->httpHeaders['HTTP_WAP_CONNECTION']) ||
isset($this->httpHeaders['HTTP_PROFILE']) ||
isset($this->httpHeaders['HTTP_X_OPERAMINI_PHONE_UA']) || // Reported by Nokia devices (eg. C3)
isset($this->httpHeaders['HTTP_X_NOKIA_IPADDRESS']) ||
isset($this->httpHeaders['HTTP_X_NOKIA_GATEWAY_ID']) ||
isset($this->httpHeaders['HTTP_X_ORANGE_ID']) ||
isset($this->httpHeaders['HTTP_X_VODAFONE_3GPDPCONTEXT']) ||
isset($this->httpHeaders['HTTP_X_HUAWEI_USERID']) ||
isset($this->httpHeaders['HTTP_UA_OS']) || // Reported by Windows Smartphones.
isset($this->httpHeaders['HTTP_X_MOBILE_GATEWAY']) || // Reported by Verizon, Vodafone proxy system.
isset($this->httpHeaders['HTTP_X_ATT_DEVICEID']) || // Seend this on HTC Sensation. @ref: SensationXE_Beats_Z715e
//HTTP_X_NETWORK_TYPE = WIFI
( isset($this->httpHeaders['HTTP_UA_CPU']) &&
$this->httpHeaders['HTTP_UA_CPU'] == 'ARM' // Seen this on a HTC.
)
){
return true;
}
return false;
}
/**
* Magic overloading method.
*
* @method boolean is[…]()
* @param string $name
* @param array $arguments
* @return mixed
*/
public function __call($name, $arguments)
{
$this->setDetectionType('mobile');
$key = substr($name, 2);
return $this->matchUAAgainstKey($key);
}
/**
* Find a detection rule that matches the current User-agent.
*
* @param null $userAgent deprecated
* @return boolean
*/
private function matchDetectionRulesAgainstUA($userAgent = null){
// Begin general search.
foreach($this->getRules() as $_regex){
if(empty($_regex)){ continue; }
if( $this->match($_regex, $userAgent) ){
//var_dump( $_regex );
return true;
}
}
return false;
}
/**
* Search for a certain key in the rules array.
* If the key is found the try to match the corresponding
* regex agains the User-agent.
*
* @param string $key
* @param null $userAgent deprecated
* @return mixed
*/
private function matchUAAgainstKey($key, $userAgent = null){
// Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc.
$key = strtolower($key);
$_rules = array_change_key_case($this->getRules());
if(array_key_exists($key, $_rules)){
if(empty($_rules[$key])){ return null; }
return $this->match($_rules[$key], $userAgent);
}
return false;
}
/**
* Check if the device is mobile.
* Returns true if any type of mobile device detected, including special ones
* @param null $userAgent deprecated
* @param null $httpHeaders deprecated
* @return bool
*/
public function isMobile($userAgent = null, $httpHeaders = null) {
if($httpHeaders){ $this->setHttpHeaders($httpHeaders); }
if($userAgent){ $this->setUserAgent($userAgent); }
$this->setDetectionType('mobile');
if ($this->checkHttpHeadersForMobile()) {
return true;
} else {
return $this->matchDetectionRulesAgainstUA();
}
}
/**
* Check if the device is a tablet.
* Return true if any type of tablet device is detected.
*
* @param null $userAgent deprecated
* @param null $httpHeaders deprecated
* @return bool
*/
public function isTablet($userAgent = null, $httpHeaders = null) {
$this->setDetectionType('mobile');
foreach($this->tabletDevices as $_regex){
if($this->match($_regex, $userAgent)){
return true;
}
}
return false;
}
/**
* This method checks for a certain property in the
* userAgent.
* @todo: The httpHeaders part is not yet used.
*
* @param $key
* @param string $userAgent deprecated
* @param string $httpHeaders deprecated
* @return bool|int|null
*/
public function is($key, $userAgent = null, $httpHeaders = null){
// Set the UA and HTTP headers only if needed (eg. batch mode).
if($httpHeaders) $this->setHttpHeaders($httpHeaders);
if($userAgent) $this->setUserAgent($userAgent);
$this->setDetectionType('extended');
return $this->matchUAAgainstKey($key);
}
public function getOperatingSystems(){
return $this->operatingSystems;
}
/**
* Some detection rules are relative (not standard),
* because of the diversity of devices, vendors and
* their conventions in representing the User-Agent or
* the HTTP headers.
*
* This method will be used to check custom regexes against
* the User-Agent string.
*
* @param $regex
* @param string $userAgent
* @return bool
*
* @todo: search in the HTTP headers too.
*/
function match($regex, $userAgent=null){
// Escape the special character which is the delimiter.
$regex = str_replace('/', '\/', $regex);
return (bool)preg_match('/'.$regex.'/is', (!empty($userAgent) ? $userAgent : $this->userAgent));
}
/**
* Get the properties array.
* @return array
*/
function getProperties(){
return $this->properties;
}
/**
* Prepare the version number.
*
* @param $ver
* @return int
*/
function prepareVersionNo($ver){
$ver = str_replace(array('_', ' ', '/'), array('.', '.', '.'), $ver);
$arrVer = explode('.', $ver, 2);
$arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions.
$ver = (float)implode('.', $arrVer);
return $ver;
}
/**
* Check the version of the given property in the User-Agent.
* Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31)
*
* @param string $propertyName
* @return mixed $version
*/
function version($propertyName){
$properties = $this->getProperties();
// If the property is found in the User-Agent then move to the next step.
if(stripos($this->userAgent, $propertyName)!==false){
// Prepare the pattern to be matched.
// Make sure we always deal with an array (string is converted).
$properties[$propertyName] = (array)$properties[$propertyName];
foreach($properties[$propertyName] as $propertyMatchString){
$propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString);
// Escape the special character which is the delimiter.
$propertyPattern = str_replace('/', '\/', $propertyPattern);
// Identify and extract the version.
preg_match('/'.$propertyPattern.'/is', $this->userAgent, $match);
if(!empty($match[1])){
$version = $this->prepareVersionNo($match[1]);
return $version;
}
}
return 0;
}
return false;
}
function mobileGrade(){
$isMobile = $this->isMobile();
if(
// Apple iOS 3.2-5.1 – Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1)
$this->version('iPad')>=4.3 ||
$this->version('iPhone')>=3.1 ||
$this->version('iPod')>=3.1 ||
// Android 2.1-2.3 – Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5)
// Android 3.1 (Honeycomb) – Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM
// Android 4.0 (ICS) – Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices
// Android 4.1 (Jelly Bean) – Tested on a Galaxy Nexus and Galaxy 7
( $this->version('Android')>2.1 && $this->is('Webkit') ) ||
// Windows Phone 7-7.5 – Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800
$this->version('Windows Phone OS')>=7.0 ||
// Blackberry 7 – Tested on BlackBerry® Torch 9810
// Blackberry 6.0 – Tested on the Torch 9800 and Style 9670
$this->version('BlackBerry')>=6.0 ||
// Blackberry Playbook (1.0-2.0) – Tested on PlayBook
$this->match('Playbook.*Tablet') ||
// Palm WebOS (1.4-2.0) – Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0)
( $this->version('webOS')>=1.4 && $this->match('Palm|Pre|Pixi') ) ||
// Palm WebOS 3.0 – Tested on HP TouchPad
$this->match('hp.*TouchPad') ||
// Firefox Mobile (12 Beta) – Tested on Android 2.3 device
( $this->is('Firefox') && $this->version('Firefox')>=12 ) ||
// Chrome for Android – Tested on Android 4.0, 4.1 device
( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android')>=4.0 ) ||
// Skyfire 4.1 – Tested on Android 2.3 device
( $this->is('Skyfire') && $this->version('Skyfire')>=4.1 && $this->is('AndroidOS') && $this->version('Android')>=2.3 ) ||
// Opera Mobile 11.5-12: Tested on Android 2.3
( $this->is('Opera') && $this->version('Opera Mobi')>11 && $this->is('AndroidOS') ) ||
// Meego 1.2 – Tested on Nokia 950 and N9
$this->is('MeeGoOS') ||
// Tizen (pre-release) – Tested on early hardware
$this->is('Tizen') ||
// Samsung Bada 2.0 – Tested on a Samsung Wave 3, Dolphin browser
// @todo: more tests here!
$this->is('Dolfin') && $this->version('Bada')>=2.0 ||
// UC Browser – Tested on Android 2.3 device
( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android')>=2.3 ) ||
// Kindle 3 and Fire – Tested on the built-in WebKit browser for each
( $this->match('Kindle Fire') ||
$this->is('Kindle') && $this->version('Kindle')>=3.0 ) ||
// Nook Color 1.4.1 – Tested on original Nook Color, not Nook Tablet
$this->is('AndroidOS') && $this->is('NookTablet') ||
// Chrome Desktop 11-21 – Tested on OS X 10.7 and Windows 7
$this->version('Chrome')>=11 && !$isMobile ||
// Safari Desktop 4-5 – Tested on OS X 10.7 and Windows 7
$this->version('Safari')>=5.0 && !$isMobile ||
// Firefox Desktop 4-13 – Tested on OS X 10.7 and Windows 7
$this->version('Firefox')>=4.0 && !$isMobile ||
// Internet Explorer 7-9 – Tested on Windows XP, Vista and 7
$this->version('MSIE')>=7.0 && !$isMobile ||
// Opera Desktop 10-12 – Tested on OS X 10.7 and Windows 7
// @reference: http://my.opera.com/community/openweb/idopera/
$this->version('Opera')>=10 && !$isMobile
){
return 'A';
}
if(
// Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770
$this->version('BlackBerry')>=5 && $this->version('BlackBerry')<6 ||
//Opera Mini (5.0-6.5) – Tested on iOS 3.2/4.3 and Android 2.3
( $this->version('Opera Mini')>=5.0 && $this->version('Opera Mini')<=6.5 &&
($this->version('Android')>=2.3 || $this->is('iOS')) ) ||
// Nokia Symbian^3 – Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1)
$this->match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') ||
// @todo: report this (tested on Nokia N71)
$this->version('Opera Mobi')>=11 && $this->is('SymbianOS')
){
return 'B';
}
if(
// Blackberry 4.x – Tested on the Curve 8330
$this->version('BlackBerry')<5.0 ||
// Windows Mobile – Tested on the HTC Leo (WinMo 5.2)
$this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile')<=5.2
){
return 'C';
}
// All older smartphone platforms and featurephones – Any device that doesn't support media queries will receive the basic, C grade experience
return 'C';
}
}
<?php
/**
* The Header for mobile theme
*
* Displays all of the <head> section and everything up till <div id="main">
*/
?><!DOCTYPE html>
<!–[if IE 7]>
<html class="ie ie7" <?php language_attributes(); ?>>
<![endif]–>
<!–[if IE 8]>
<html class="ie ie8" <?php language_attributes(); ?>>
<![endif]–>
<!–[if !(IE 7) | !(IE 8) ]><!–>
<html <?php language_attributes(); ?>>
<!–<![endif]–>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<meta name="viewport" content="width=device-width">
<title><?php wp_title( '|', true, 'right' ); ?></title>
<link rel="profile" href="http://gmpg.org/xfn/11">
<link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>">
<!–[if lt IE 9]>
<script src="<?php echo get_template_directory_uri(); ?>/js/html5.js"></script>
<![endif]–>
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<div id="page" class="hfeed site">
<?php if ( get_header_image() ) : ?>
<div id="site-header">
<a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home">
<img src="<?php header_image(); ?>" width="<?php echo get_custom_header()->width; ?>" height="<?php echo get_custom_header()->height; ?>" alt="">
</a>
</div>
<?php endif; ?>
<?php if ( wp_is_mobile() ) : ?>
<header id="masthead" class="site-header" role="banner">
<div class="header-main">
<h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
<?php
$description = get_bloginfo( 'description', 'display' );
if ( ! empty ( $description ) ) :
?>
<h2 class="topbar-description"><?php echo esc_html( $description ); ?></h2>
<?php endif; ?>
</div>
<a class="screen-reader-text skip-link" href="#content"><?php _e( 'Skip to content', 'twentyfourteen' ); ?></a>
<a id="menu-toggle" class="second" title="<?php _e( 'Click To Show Sidebar', 'AR_responsive' ); ?>" href="#slideout"><span class="genericon genericon-menu"></span></a>
</header><!– #masthead –>
<?php else: ?>
<header id="masthead" class="site-header" role="banner">
<div id="big-top">
<div class="header-main">
<h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
</div>
<?php
$description = get_bloginfo( 'description', 'display' );
if ( ! empty ( $description ) ) :
?>
<h2 class="topbar-description"><?php echo esc_html( $description ); ?></h2>
<?php endif; ?>
</div>
<nav id="primary-navigation" class="site-navigation primary-navigation" role="navigation">
<div class="search-toggle">
<a href="#search-container" class="screen-reader-text"><?php _e( 'Search', 'twentyfourteen' ); ?></a>
</div>
<div id="search-container" class="search-box-wrapper hide">
<div class="search-box">
<?php get_search_form(); ?>
</div>
</div>
<h1 class="menu-toggle"><?php _e( 'Primary Menu', 'twentyfourteen' ); ?></h1>
<a class="screen-reader-text skip-link" href="#content"><?php _e( 'Skip to content', 'twentyfourteen' ); ?></a>
<?php wp_nav_menu( array( 'theme_location' => 'primary', 'menu_class' => 'nav-menu', 'container_class' => 'topbar-menu', ) ); ?>
</nav>
</header><!– #masthead –>
<?php endif; ?>
<div id="main" class="site-main">
Bibliografie
[***1] http://ctrl-d.ro/design/resurse-design/introducere-in-responsive-typography/
[***2] http://ro.wikipedia.org/wiki/Culoare
[***3] http://ro.wikipedia.org/wiki/HTML5
[***4] http://ro.wikipedia.org/wiki/Cascading_Style_Sheets
[***5] KAREN MCGRANE November 05, 2012 Content Strategy for Mobile link
[***6] Jesse Friedman – PHP Mobile Detect class – WordPress Plugin link
[7] Chris Knowles, Sept. 25, 2013 How To Make Content Adapt To A Responsive WordPress Theme
[8] http://premium.wpmudev.org/blog/how-to-make-twenty-fourteen-or-any-other-wp-theme-super/
[9]
<?php
/*
Plugin Name: WP Mobile Detect
Version: 1.2.0
Plugin URI: http://jes.se.com/wp-mobile-detect
Description: A WordPress plugin based on the PHP Mobile Detect class (Original author Victor Stanciu now maintained by Serban Ghita) incorporates functions and shortcodes to empower User Admins to have better control of when content is served
Author: Jesse Friedman
Author URI: http://jes.se.com
License: GPL v3
WP Mobile Detect
Copyright (C) 2012, Jesse Friedman – http://jes.se.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/********************************************//**
* PHP Mobile Detect class used to detect browser or device type
***********************************************/
require_once('mobile-detect.php');
$detect = new Mobile_Detect();
/********************************************//**
* Generates [notmobile][/notmobile] shortcode which shows content on desktops or tablets
***********************************************/
function wpmd_notphone( $tats, $content="" ) {
global $detect;
if( ! $detect->isMobile() || $detect->isTablet() ) return do_shortcode($content);
}
add_shortcode( 'notphone', 'wpmd_notphone' );
/********************************************//**
* Returns true when on desktops or tablets
***********************************************/
function wpmd_is_notphone() {
global $detect;
if( ! $detect->isMobile() || $detect->isTablet() ) return true;
}
/********************************************//**
* Generates [nottab][/nottab] shortcode which shows content on desktops or phones
***********************************************/
function wpmd_nottab( $tats, $content="" ) {
global $detect;
if( ! $detect->isTablet() ) return do_shortcode($content);
}
add_shortcode( 'nottab', 'wpmd_nottab' );
/********************************************//**
* Returns true when on desktops or phones
***********************************************/
function wpmd_is_nottab() {
global $detect;
if( ! $detect->isTablet() ) return true;
}
/********************************************//**
* Generates [notdevice][/notdevice] shortcode which shows content on desktops only
***********************************************/
function wpmd_notdevice( $tats, $content="" ) {
global $detect;
if( ! $detect->isMobile() && ! $detect->isTablet() ) return do_shortcode($content);
}
add_shortcode( 'notdevice', 'wpmd_notdevice' );
/********************************************//**
* Returns true when on desktops only
***********************************************/
function wpmd_is_notdevice() {
global $detect;
if( ! $detect->isMobile() && ! $detect->isTablet() ) return true;
}
/********************************************//**
* Generates [phone][/phone] shortcode which shows content on phones ONLY
***********************************************/
function wpmd_phone( $tats, $content="" ) {
global $detect;
if( $detect->isMobile() && ! $detect->isTablet() ) return do_shortcode($content);
}
add_shortcode( 'phone', 'wpmd_phone' );
/********************************************//**
* Returns true when on phones ONLY
***********************************************/
function wpmd_is_phone() {
global $detect;
if( $detect->isMobile() && ! $detect->isTablet() ) return true;
}
/********************************************//**
* Generates [tablet][/tablet] shortcode which shows content on Tablets ONLY
***********************************************/
function wpmd_tablet( $tats, $content="" ) {
global $detect;
if( $detect->isTablet() ) return do_shortcode($content);
}
add_shortcode( 'tablet', 'wpmd_tablet' );
/********************************************//**
* WARNING: This is deprecated. Conflicts with the [tab] shortcode changed to [tablet] Generates [tab][/tab] shortcode which shows content on Tablets ONLY
***********************************************/
function wpmd_tab( $tats, $content="" ) {
global $detect;
if( $detect->isTablet() ) return do_shortcode($content);
}
add_shortcode( 'tab', 'wpmd_tab' );
/********************************************//**
* Returns true when on Tablets ONLY
***********************************************/
function wpmd_is_tablet() {
global $detect;
if( $detect->isTablet() ) return true;
}
/********************************************//**
* Generates [device][/device] shortcode which shows content on phones or tablets but NOT destkop
***********************************************/
function wpmd_device( $tats, $content="" ) {
global $detect;
if( $detect->isMobile() || $detect->isTablet() ) return do_shortcode($content);
}
add_shortcode( 'device', 'wpmd_device' );
/********************************************//**
* Returns true when on phones or tablets but NOT destkop
***********************************************/
function wpmd_is_device() {
global $detect;
if( $detect->isMobile() || $detect->isTablet() ) return true;
}
/********************************************//**
* Generates [ios][/ios] shortcode which shows content on iOS devices only
***********************************************/
function wpmd_ios( $tats, $content="" ) {
global $detect;
if( $detect->isiOS() ) return do_shortcode($content);
}
add_shortcode( 'ios', 'wpmd_ios' );
/********************************************//**
* Returns true when on iOS
***********************************************/
function wpmd_is_ios() {
global $detect;
if( $detect->isiOS() ) return true;
}
/********************************************//**
* Generates [iPhone][/iPhone] shortcode which shows content on iPhone's only
***********************************************/
function wpmd_iphone( $tats, $content="" ) {
global $detect;
if( $detect->isiPhone() ) return do_shortcode($content);
}
add_shortcode( 'iPhone', 'wpmd_iphone' );
/********************************************//**
* Returns true when on iPhone
***********************************************/
function wpmd_is_iphone() {
global $detect;
if( $detect->isiPhone() ) return true;
}
/********************************************//**
* Generates [iPad][/iPad] shortcode which shows content on iPad's only
***********************************************/
function wpmd_ipad( $tats, $content="" ) {
global $detect;
if( $detect->isiPad() ) return do_shortcode($content);
}
add_shortcode( 'iPad', 'wpmd_ipad' );
/********************************************//**
* Returns true when on iPad
***********************************************/
function wpmd_is_ipad() {
global $detect;
if( $detect->isiPad() ) return true;
}
/********************************************//**
* Generates [android][/android] shortcode which shows content on Android devices only
***********************************************/
function wpmd_android( $tats, $content="" ) {
global $detect;
if( $detect->isAndroidOS() ) return do_shortcode($content);
}
add_shortcode( 'android', 'wpmd_android' );
/********************************************//**
* Returns true when on Android OS
***********************************************/
function wpmd_is_android() {
global $detect;
if( $detect->isAndroidOS() ) return true;
}
/********************************************//**
* Generates [windowsmobile][/windowsmobile] shortcode which shows content on Windows Mobile devices only
***********************************************/
function wpmd_windows_mobile( $tats, $content="" ) {
global $detect;
if( $detect->isWindowsMobileOS() ) return do_shortcode($content);
}
add_shortcode( 'windowsmobile', 'wpmd_windows_mobile' );
/********************************************//**
* Returns true when on Android OS
***********************************************/
function wpmd_is_windows_mobile() {
global $detect;
if( $detect->isWindowsMobileOS() ) return true;
}
=========================================================================
<?php
/**
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* @author Serban Ghita <[anonimizat]>
* Victor Stanciu <[anonimizat]> (until v.1.0)
* @license MIT License https://github.com/serbanghita/Mobile-Detect/blob/master/LICENSE.txt
* @link Official page: http://mobiledetect.net
* GitHub Repository: https://github.com/serbanghita/Mobile-Detect
* Google Code Old Page: http://code.google.com/p/php-mobile-detect/
* @version 2.5.8
*/
class Mobile_Detect {
protected $scriptVersion = '2.5.8';
// External info.
protected $userAgent = null;
protected $httpHeaders;
// Arrays holding all detection rules.
protected $mobileDetectionRules = null;
protected $mobileDetectionRulesExtended = null;
// Type of detection to use.
protected $detectionType = 'mobile'; // mobile, extended @todo: refactor this.
// List of mobile devices (phones)
protected $phoneDevices = array(
'iPhone' => '\biPhone.*Mobile|\biPod|\biTunes',
'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+',
'HTC' => 'HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6425|001HT|Inspire 4G|Android.*\bEVO\b',
'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile',
// @todo: Is 'Dell Streak' a tablet or a phone? 😉
'Dell' => 'Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b',
'Motorola' => 'Motorola|\bDroid\b.*Build|DROIDX|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT909|XT910|XT912|XT928',
'Samsung' => 'Samsung|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9300 |GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-P6810|GT-P7100|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N8010',
'Sony' => 'sony|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i',
'Asus' => 'Asus.*Galaxy',
'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ; @todo – complete the regex.
'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', // Just for fun 😉
// @ref: http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH)
// Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android.
'Pantech' => 'PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790',
// @ref: http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones.
'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250',
// Added simvalley mobile just for fun. They have some interesting devices.
// @ref: http://www.simvalley.fr/telephonie–gps-_22_telephonie-mobile_telephones_.html
'SimValley' => '\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\b',
// @Tapatalk is a mobile app; @ref: http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039
'GenericPhone' => 'Tapatalk|PDA;|PPC;|SAGEM|mmp|pocket|psp|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|wap|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser|LG-P500'
);
// List of tablet devices.
protected $tabletDevices = array(
'iPad' => 'iPad|iPad.*Mobile', // @todo: check for mobile friendly emails topic.
'NexusTablet' => '^.*Android.*Nexus(((?:(?!Mobile))|(?:(\s(7|10).+))).)*$',
'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1010|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P6810|GT-P7501',
// @reference: http://www.labnol.org/software/kindle-user-agent-string/20378/
'Kindle' => 'Kindle|Silk.*Accelerated',
// Only the Surface tablets with Windows RT are considered mobile.
// @ref: http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx
'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;',
'AsusTablet' => 'Transformer|TF101',
'BlackBerryTablet' => 'PlayBook|RIM Tablet',
'HTCtablet' => 'HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200',
'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617',
'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNTV250A|LogicPD Zoom2',
// @ref: http://www.acer.ro/ac/ro/RO/content/drivers
// @ref: http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer)
'AcerTablet' => 'Android.*\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71)\b',
// @ref: http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/
// @ref: http://us.toshiba.com/tablets/tablet-finder
// @ref: http://www.toshiba.co.jp/regza/tablet/
'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)',
// @ref: http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html
'LGTablet' => '\bL-06C|LG-V900|LG-V909',
'YarvikTablet' => 'Android.*(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468)',
'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB',
'ArnovaTablet' => 'AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT',
// @reference: http://wiki.archosfans.com/index.php?title=Main_Page
'ArchosTablet' => 'Android.*ARCHOS|101G9|80G9',
// @reference: http://en.wikipedia.org/wiki/NOVO7
'AinolTablet' => 'NOVO7|Novo7Aurora|Novo7Basic|NOVO7PALADIN',
// @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER
// @ref: Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser
// @ref: http://www.sony.jp/support/tablet/
'SonyTablet' => 'Sony Tablet|Sony Tablet S|SGPT12|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT211|SGPT213|EBRD1101|EBRD1102|EBRD1201',
// @ref: db + http://www.cube-tablet.com/buy-products.html
'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT',
// @ref: http://www.cobyusa.com/?p=pcat&pcat_id=3001
'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010',
// @ref: http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets)
// @ref: http://www.imp3.net/14/show.php?itemid=20454
'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)',
// @ref: http://www.rock-chips.com/index.php?do=prod&pid=2
'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A',
// @ref: http://www.telstra.com.au/home-phone/thub-2/
'TelstraTablet' => 'T-Hub2',
// @ref: http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/
'FlyTablet' => 'IQ310|Fly Vision',
// @ref: http://www.bqreaders.com/gb/tablets-prices-sale.html
'bqTablet' => 'bq.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant)',
// @ref: http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290
// @ref: http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets)
'HuaweiTablet' => 'MediaPad|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim',
// Nec or Medias Tab
'NecTablet' => '\bN-06D|\bN-08D',
// Pantech Tablets: http://www.pantechusa.com/phones/
'PantechTablet' => 'Pantech.*P4100',
// Broncho Tablets: http://www.broncho.cn/ (hard to find)
'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)',
// @ref: http://versusuk.com/support.html
'VersusTablet' => 'TOUCHPAD.*[78910]',
// @ref: http://www.zync.in/index.php/our-products/tablet-phablets
'ZyncTablet' => 'z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900',
// @ref: http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/
'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA',
// @ref: https://www.nabitablet.com/
'NabiTablet' => 'Android.*\bNabi',
// @note: Avoid detecting 'PLAYSTATION 3' as mobile.
'PlaystationTablet' => 'Playstation.*(Portable|Vita)',
'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|ViewPad7|MID7015|BNTV250A|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|hp-tablet',
);
// List of mobile Operating Systems.
protected $operatingSystems = array(
'AndroidOS' => 'Android',
'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os',
'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino',
'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b',
// @reference: http://en.wikipedia.org/wiki/Windows_Mobile
'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;',
// @reference: http://en.wikipedia.org/wiki/Windows_Phone
// http://wifeng.cn/?r=blog&a=view&id=106
// http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx
'WindowsPhoneOS' => 'Windows Phone OS|XBLWP7|ZuneWP7',
'iOS' => '\biPhone.*Mobile|\biPod|\biPad',
// http://en.wikipedia.org/wiki/MeeGo
// @todo: research MeeGo in UAs
'MeeGoOS' => 'MeeGo',
// http://en.wikipedia.org/wiki/Maemo
// @todo: research Maemo in UAs
'MaemoOS' => 'Maemo',
'JavaOS' => 'J2ME/|Java/|\bMIDP\b|\bCLDC\b',
'webOS' => 'webOS|hpwOS',
'badaOS' => '\bBada\b',
'BREWOS' => 'BREW',
);
// List of mobile User Agents.
protected $userAgents = array(
// @reference: https://developers.google.com/chrome/mobile/docs/user-agent
'Chrome' => '\bCrMo\b|CriOS|Android.*Chrome/[.0-9]* (Mobile)?',
'Dolfin' => '\bDolfin\b',
'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|OPR/[0-9.]+',
'Skyfire' => 'Skyfire',
'IE' => 'IEMobile|MSIEMobile',
'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile',
'Bolt' => 'bolt',
'TeaShark' => 'teashark',
'Blazer' => 'Blazer',
// @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3
'Safari' => 'Version.*Mobile.*Safari|Safari.*Mobile',
// @ref: http://en.wikipedia.org/wiki/Midori_(web_browser)
//'Midori' => 'midori',
'Tizen' => 'Tizen',
'UCBrowser' => 'UC.*Browser|UCWEB',
// @ref: https://github.com/serbanghita/Mobile-Detect/issues/7
'DiigoBrowser' => 'DiigoBrowser',
// http://www.puffinbrowser.com/index.php
'Puffin' => 'Puffin',
// @ref: http://mercury-browser.com/index.html
'Mercury' => '\bMercury\b',
// @reference: http://en.wikipedia.org/wiki/Minimo
// http://en.wikipedia.org/wiki/Vision_Mobile_Browser
'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision'
);
// Utilities.
protected $utilities = array(
// Experimental. When a mobile device wants to switch to 'Desktop Mode'.
// @ref: http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/
// @ref: https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011
'DesktopMode' => 'WPDesktop',
'TV' => 'SonyDTV115', // experimental
'WebKit' => '(webkit)[ /]([\w.]+)',
'Bot' => 'Googlebot|DoCoMo|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|facebookexternalhit',
'MobileBot' => 'Googlebot-Mobile|DoCoMo|YahooSeeker/M1A1-R2D2',
);
// Properties list.
// @reference: http://user-agent-string.info/list-of-ua#Mobile Browser
const VER = '([\w._]+)';
protected $properties = array(
// Build
'Mobile' => 'Mobile/[VER]',
'Build' => 'Build/[VER]',
'Version' => 'Version/[VER]',
'VendorID' => 'VendorID/[VER]',
// Devices
'iPad' => 'iPad.*CPU[a-z ]+[VER]',
'iPhone' => 'iPhone.*CPU[a-z ]+[VER]',
'iPod' => 'iPod.*CPU[a-z ]+[VER]',
//'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'),
'Kindle' => 'Kindle/[VER]',
// Browser
'Chrome' => 'Chrome/[VER]',
'CriOS' => 'CriOS/[VER]',
'Dolfin' => 'Dolfin/[VER]',
// @reference: https://developer.mozilla.org/en-US/docs/User_Agent_Strings_Reference
'Firefox' => 'Firefox/[VER]',
'Fennec' => 'Fennec/[VER]',
// @reference: http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx
'IEMobile' => array('IEMobile/[VER];', 'IEMobile [VER]'),
'MSIE' => 'MSIE [VER];',
// http://en.wikipedia.org/wiki/NetFront
'NetFront' => 'NetFront/[VER]',
'NokiaBrowser' => 'NokiaBrowser/[VER]',
'Opera' => 'Version/[VER]',
'Opera Mini' => 'Opera Mini/[VER]',
'Opera Mobi' => 'Version/[VER]',
'UC Browser' => 'UC Browser[VER]',
'Safari' => 'Version/[VER]',
'Skyfire' => 'Skyfire/[VER]',
'Tizen' => 'Tizen/[VER]',
'Webkit' => 'webkit[ /][VER]',
// Engine
'Gecko' => 'Gecko/[VER]',
'Trident' => 'Trident/[VER]',
'Presto' => 'Presto/[VER]',
// OS
'Android' => 'Android [VER]',
'BlackBerry' => array('BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]'),
'BREW' => 'BREW [VER]',
'Java' => 'Java/[VER]',
// @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx
// @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases
'Windows Phone OS' => 'Windows Phone OS [VER]',
'Windows Phone' => 'Windows Phone [VER]',
'Windows CE' => 'Windows CE/[VER]',
// http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd
'Windows NT' => 'Windows NT [VER]',
'Symbian' => array('SymbianOS/[VER]', 'Symbian/[VER]'),
'webOS' => array('webOS/[VER]', 'hpwOS/[VER];'),
);
function __construct(){
$this->setHttpHeaders();
$this->setUserAgent();
$this->setMobileDetectionRules();
$this->setMobileDetectionRulesExtended();
}
/**
* Get the current script version.
* This is useful for the demo.php file,
* so people can check on what version they are testing
* for mobile devices.
*/
public function getScriptVersion(){
return $this->scriptVersion;
}
public function setHttpHeaders($httpHeaders = null){
if(!empty($httpHeaders)){
$this->httpHeaders = $httpHeaders;
} else {
foreach($_SERVER as $key => $value){
if(substr($key,0,5)=='HTTP_'){
$this->httpHeaders[$key] = $value;
}
}
}
}
public function getHttpHeaders(){
return $this->httpHeaders;
}
public function setUserAgent($userAgent = null){
if(!empty($userAgent)){
$this->userAgent = $userAgent;
} else {
$this->userAgent = isset($this->httpHeaders['HTTP_USER_AGENT']) ? $this->httpHeaders['HTTP_USER_AGENT'] : null;
if(empty($this->userAgent)){
$this->userAgent = isset($this->httpHeaders['HTTP_X_DEVICE_USER_AGENT']) ? $this->httpHeaders['HTTP_X_DEVICE_USER_AGENT'] : null;
}
// Header can occur on devices using Opera Mini (can expose the real device type). Let's concatenate it (we need this extra info in the regexes).
if(!empty($this->httpHeaders['HTTP_X_OPERAMINI_PHONE_UA'])){
$this->userAgent .= ' '.$this->httpHeaders['HTTP_X_OPERAMINI_PHONE_UA'];
}
}
}
public function getUserAgent(){
return $this->userAgent;
}
function setDetectionType($type = null){
$this->detectionType = (!empty($type) ? $type : 'mobile');
}
public function getPhoneDevices(){
return $this->phoneDevices;
}
public function getTabletDevices(){
return $this->tabletDevices;
}
/**
* Method sets the mobile detection rules.
*
* This method is used for the magic methods $detect->is*()
*/
public function setMobileDetectionRules(){
// Merge all rules together.
$this->mobileDetectionRules = array_merge(
$this->phoneDevices,
$this->tabletDevices,
$this->operatingSystems,
$this->userAgents
);
}
/**
* Method sets the mobile detection rules + utilities.
* The reason this is separate is because utilities rules
* don't necessary imply mobile.
*
* This method is used inside the new $detect->is('stuff') method.
*
* @return bool
*/
public function setMobileDetectionRulesExtended(){
// Merge all rules together.
$this->mobileDetectionRulesExtended = array_merge(
$this->phoneDevices,
$this->tabletDevices,
$this->operatingSystems,
$this->userAgents,
$this->utilities
);
}
/**
* @return array
*/
public function getRules()
{
if($this->detectionType=='extended'){
return $this->mobileDetectionRulesExtended;
} else {
return $this->mobileDetectionRules;
}
}
/**
* Check the HTTP headers for signs of mobile.
* This is the fastest mobile check possible; it's used
* inside isMobile() method.
* @return boolean
*/
public function checkHttpHeadersForMobile(){
if(
isset($this->httpHeaders['HTTP_ACCEPT']) &&
(strpos($this->httpHeaders['HTTP_ACCEPT'], 'application/x-obml2d') !== false || // Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/
strpos($this->httpHeaders['HTTP_ACCEPT'], 'application/vnd.rim.html') !== false || // BlackBerry devices.
strpos($this->httpHeaders['HTTP_ACCEPT'], 'text/vnd.wap.wml') !== false ||
strpos($this->httpHeaders['HTTP_ACCEPT'], 'application/vnd.wap.xhtml+xml') !== false) ||
isset($this->httpHeaders['HTTP_X_WAP_PROFILE']) || // @todo: validate
isset($this->httpHeaders['HTTP_X_WAP_CLIENTID']) ||
isset($this->httpHeaders['HTTP_WAP_CONNECTION']) ||
isset($this->httpHeaders['HTTP_PROFILE']) ||
isset($this->httpHeaders['HTTP_X_OPERAMINI_PHONE_UA']) || // Reported by Nokia devices (eg. C3)
isset($this->httpHeaders['HTTP_X_NOKIA_IPADDRESS']) ||
isset($this->httpHeaders['HTTP_X_NOKIA_GATEWAY_ID']) ||
isset($this->httpHeaders['HTTP_X_ORANGE_ID']) ||
isset($this->httpHeaders['HTTP_X_VODAFONE_3GPDPCONTEXT']) ||
isset($this->httpHeaders['HTTP_X_HUAWEI_USERID']) ||
isset($this->httpHeaders['HTTP_UA_OS']) || // Reported by Windows Smartphones.
isset($this->httpHeaders['HTTP_X_MOBILE_GATEWAY']) || // Reported by Verizon, Vodafone proxy system.
isset($this->httpHeaders['HTTP_X_ATT_DEVICEID']) || // Seend this on HTC Sensation. @ref: SensationXE_Beats_Z715e
//HTTP_X_NETWORK_TYPE = WIFI
( isset($this->httpHeaders['HTTP_UA_CPU']) &&
$this->httpHeaders['HTTP_UA_CPU'] == 'ARM' // Seen this on a HTC.
)
){
return true;
}
return false;
}
/**
* Magic overloading method.
*
* @method boolean is[…]()
* @param string $name
* @param array $arguments
* @return mixed
*/
public function __call($name, $arguments)
{
$this->setDetectionType('mobile');
$key = substr($name, 2);
return $this->matchUAAgainstKey($key);
}
/**
* Find a detection rule that matches the current User-agent.
*
* @param null $userAgent deprecated
* @return boolean
*/
private function matchDetectionRulesAgainstUA($userAgent = null){
// Begin general search.
foreach($this->getRules() as $_regex){
if(empty($_regex)){ continue; }
if( $this->match($_regex, $userAgent) ){
//var_dump( $_regex );
return true;
}
}
return false;
}
/**
* Search for a certain key in the rules array.
* If the key is found the try to match the corresponding
* regex agains the User-agent.
*
* @param string $key
* @param null $userAgent deprecated
* @return mixed
*/
private function matchUAAgainstKey($key, $userAgent = null){
// Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc.
$key = strtolower($key);
$_rules = array_change_key_case($this->getRules());
if(array_key_exists($key, $_rules)){
if(empty($_rules[$key])){ return null; }
return $this->match($_rules[$key], $userAgent);
}
return false;
}
/**
* Check if the device is mobile.
* Returns true if any type of mobile device detected, including special ones
* @param null $userAgent deprecated
* @param null $httpHeaders deprecated
* @return bool
*/
public function isMobile($userAgent = null, $httpHeaders = null) {
if($httpHeaders){ $this->setHttpHeaders($httpHeaders); }
if($userAgent){ $this->setUserAgent($userAgent); }
$this->setDetectionType('mobile');
if ($this->checkHttpHeadersForMobile()) {
return true;
} else {
return $this->matchDetectionRulesAgainstUA();
}
}
/**
* Check if the device is a tablet.
* Return true if any type of tablet device is detected.
*
* @param null $userAgent deprecated
* @param null $httpHeaders deprecated
* @return bool
*/
public function isTablet($userAgent = null, $httpHeaders = null) {
$this->setDetectionType('mobile');
foreach($this->tabletDevices as $_regex){
if($this->match($_regex, $userAgent)){
return true;
}
}
return false;
}
/**
* This method checks for a certain property in the
* userAgent.
* @todo: The httpHeaders part is not yet used.
*
* @param $key
* @param string $userAgent deprecated
* @param string $httpHeaders deprecated
* @return bool|int|null
*/
public function is($key, $userAgent = null, $httpHeaders = null){
// Set the UA and HTTP headers only if needed (eg. batch mode).
if($httpHeaders) $this->setHttpHeaders($httpHeaders);
if($userAgent) $this->setUserAgent($userAgent);
$this->setDetectionType('extended');
return $this->matchUAAgainstKey($key);
}
public function getOperatingSystems(){
return $this->operatingSystems;
}
/**
* Some detection rules are relative (not standard),
* because of the diversity of devices, vendors and
* their conventions in representing the User-Agent or
* the HTTP headers.
*
* This method will be used to check custom regexes against
* the User-Agent string.
*
* @param $regex
* @param string $userAgent
* @return bool
*
* @todo: search in the HTTP headers too.
*/
function match($regex, $userAgent=null){
// Escape the special character which is the delimiter.
$regex = str_replace('/', '\/', $regex);
return (bool)preg_match('/'.$regex.'/is', (!empty($userAgent) ? $userAgent : $this->userAgent));
}
/**
* Get the properties array.
* @return array
*/
function getProperties(){
return $this->properties;
}
/**
* Prepare the version number.
*
* @param $ver
* @return int
*/
function prepareVersionNo($ver){
$ver = str_replace(array('_', ' ', '/'), array('.', '.', '.'), $ver);
$arrVer = explode('.', $ver, 2);
$arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions.
$ver = (float)implode('.', $arrVer);
return $ver;
}
/**
* Check the version of the given property in the User-Agent.
* Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31)
*
* @param string $propertyName
* @return mixed $version
*/
function version($propertyName){
$properties = $this->getProperties();
// If the property is found in the User-Agent then move to the next step.
if(stripos($this->userAgent, $propertyName)!==false){
// Prepare the pattern to be matched.
// Make sure we always deal with an array (string is converted).
$properties[$propertyName] = (array)$properties[$propertyName];
foreach($properties[$propertyName] as $propertyMatchString){
$propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString);
// Escape the special character which is the delimiter.
$propertyPattern = str_replace('/', '\/', $propertyPattern);
// Identify and extract the version.
preg_match('/'.$propertyPattern.'/is', $this->userAgent, $match);
if(!empty($match[1])){
$version = $this->prepareVersionNo($match[1]);
return $version;
}
}
return 0;
}
return false;
}
function mobileGrade(){
$isMobile = $this->isMobile();
if(
// Apple iOS 3.2-5.1 – Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1)
$this->version('iPad')>=4.3 ||
$this->version('iPhone')>=3.1 ||
$this->version('iPod')>=3.1 ||
// Android 2.1-2.3 – Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5)
// Android 3.1 (Honeycomb) – Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM
// Android 4.0 (ICS) – Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices
// Android 4.1 (Jelly Bean) – Tested on a Galaxy Nexus and Galaxy 7
( $this->version('Android')>2.1 && $this->is('Webkit') ) ||
// Windows Phone 7-7.5 – Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800
$this->version('Windows Phone OS')>=7.0 ||
// Blackberry 7 – Tested on BlackBerry® Torch 9810
// Blackberry 6.0 – Tested on the Torch 9800 and Style 9670
$this->version('BlackBerry')>=6.0 ||
// Blackberry Playbook (1.0-2.0) – Tested on PlayBook
$this->match('Playbook.*Tablet') ||
// Palm WebOS (1.4-2.0) – Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0)
( $this->version('webOS')>=1.4 && $this->match('Palm|Pre|Pixi') ) ||
// Palm WebOS 3.0 – Tested on HP TouchPad
$this->match('hp.*TouchPad') ||
// Firefox Mobile (12 Beta) – Tested on Android 2.3 device
( $this->is('Firefox') && $this->version('Firefox')>=12 ) ||
// Chrome for Android – Tested on Android 4.0, 4.1 device
( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android')>=4.0 ) ||
// Skyfire 4.1 – Tested on Android 2.3 device
( $this->is('Skyfire') && $this->version('Skyfire')>=4.1 && $this->is('AndroidOS') && $this->version('Android')>=2.3 ) ||
// Opera Mobile 11.5-12: Tested on Android 2.3
( $this->is('Opera') && $this->version('Opera Mobi')>11 && $this->is('AndroidOS') ) ||
// Meego 1.2 – Tested on Nokia 950 and N9
$this->is('MeeGoOS') ||
// Tizen (pre-release) – Tested on early hardware
$this->is('Tizen') ||
// Samsung Bada 2.0 – Tested on a Samsung Wave 3, Dolphin browser
// @todo: more tests here!
$this->is('Dolfin') && $this->version('Bada')>=2.0 ||
// UC Browser – Tested on Android 2.3 device
( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android')>=2.3 ) ||
// Kindle 3 and Fire – Tested on the built-in WebKit browser for each
( $this->match('Kindle Fire') ||
$this->is('Kindle') && $this->version('Kindle')>=3.0 ) ||
// Nook Color 1.4.1 – Tested on original Nook Color, not Nook Tablet
$this->is('AndroidOS') && $this->is('NookTablet') ||
// Chrome Desktop 11-21 – Tested on OS X 10.7 and Windows 7
$this->version('Chrome')>=11 && !$isMobile ||
// Safari Desktop 4-5 – Tested on OS X 10.7 and Windows 7
$this->version('Safari')>=5.0 && !$isMobile ||
// Firefox Desktop 4-13 – Tested on OS X 10.7 and Windows 7
$this->version('Firefox')>=4.0 && !$isMobile ||
// Internet Explorer 7-9 – Tested on Windows XP, Vista and 7
$this->version('MSIE')>=7.0 && !$isMobile ||
// Opera Desktop 10-12 – Tested on OS X 10.7 and Windows 7
// @reference: http://my.opera.com/community/openweb/idopera/
$this->version('Opera')>=10 && !$isMobile
){
return 'A';
}
if(
// Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770
$this->version('BlackBerry')>=5 && $this->version('BlackBerry')<6 ||
//Opera Mini (5.0-6.5) – Tested on iOS 3.2/4.3 and Android 2.3
( $this->version('Opera Mini')>=5.0 && $this->version('Opera Mini')<=6.5 &&
($this->version('Android')>=2.3 || $this->is('iOS')) ) ||
// Nokia Symbian^3 – Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1)
$this->match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') ||
// @todo: report this (tested on Nokia N71)
$this->version('Opera Mobi')>=11 && $this->is('SymbianOS')
){
return 'B';
}
if(
// Blackberry 4.x – Tested on the Curve 8330
$this->version('BlackBerry')<5.0 ||
// Windows Mobile – Tested on the HTC Leo (WinMo 5.2)
$this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile')<=5.2
){
return 'C';
}
// All older smartphone platforms and featurephones – Any device that doesn't support media queries will receive the basic, C grade experience
return 'C';
}
}
<?php
/**
* The Header for mobile theme
*
* Displays all of the <head> section and everything up till <div id="main">
*/
?><!DOCTYPE html>
<!–[if IE 7]>
<html class="ie ie7" <?php language_attributes(); ?>>
<![endif]–>
<!–[if IE 8]>
<html class="ie ie8" <?php language_attributes(); ?>>
<![endif]–>
<!–[if !(IE 7) | !(IE 8) ]><!–>
<html <?php language_attributes(); ?>>
<!–<![endif]–>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<meta name="viewport" content="width=device-width">
<title><?php wp_title( '|', true, 'right' ); ?></title>
<link rel="profile" href="http://gmpg.org/xfn/11">
<link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>">
<!–[if lt IE 9]>
<script src="<?php echo get_template_directory_uri(); ?>/js/html5.js"></script>
<![endif]–>
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<div id="page" class="hfeed site">
<?php if ( get_header_image() ) : ?>
<div id="site-header">
<a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home">
<img src="<?php header_image(); ?>" width="<?php echo get_custom_header()->width; ?>" height="<?php echo get_custom_header()->height; ?>" alt="">
</a>
</div>
<?php endif; ?>
<?php if ( wp_is_mobile() ) : ?>
<header id="masthead" class="site-header" role="banner">
<div class="header-main">
<h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
<?php
$description = get_bloginfo( 'description', 'display' );
if ( ! empty ( $description ) ) :
?>
<h2 class="topbar-description"><?php echo esc_html( $description ); ?></h2>
<?php endif; ?>
</div>
<a class="screen-reader-text skip-link" href="#content"><?php _e( 'Skip to content', 'twentyfourteen' ); ?></a>
<a id="menu-toggle" class="second" title="<?php _e( 'Click To Show Sidebar', 'AR_responsive' ); ?>" href="#slideout"><span class="genericon genericon-menu"></span></a>
</header><!– #masthead –>
<?php else: ?>
<header id="masthead" class="site-header" role="banner">
<div id="big-top">
<div class="header-main">
<h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
</div>
<?php
$description = get_bloginfo( 'description', 'display' );
if ( ! empty ( $description ) ) :
?>
<h2 class="topbar-description"><?php echo esc_html( $description ); ?></h2>
<?php endif; ?>
</div>
<nav id="primary-navigation" class="site-navigation primary-navigation" role="navigation">
<div class="search-toggle">
<a href="#search-container" class="screen-reader-text"><?php _e( 'Search', 'twentyfourteen' ); ?></a>
</div>
<div id="search-container" class="search-box-wrapper hide">
<div class="search-box">
<?php get_search_form(); ?>
</div>
</div>
<h1 class="menu-toggle"><?php _e( 'Primary Menu', 'twentyfourteen' ); ?></h1>
<a class="screen-reader-text skip-link" href="#content"><?php _e( 'Skip to content', 'twentyfourteen' ); ?></a>
<?php wp_nav_menu( array( 'theme_location' => 'primary', 'menu_class' => 'nav-menu', 'container_class' => 'topbar-menu', ) ); ?>
</nav>
</header><!– #masthead –>
<?php endif; ?>
<div id="main" class="site-main">
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Responsiv Web Design (ID: 150373)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
