- localStorage
- sessionStorage
- selectors API
- custom data attrs/dataSet API
- CSS Generated Content
- application cache
- Transforms
- Transitions
- animation
- Audio
Also, JSON.stringify, touch events, classList
Estelle Weyl | @estellevw | Github | Press → to advance, 2 for comments, 4 to read/write notes.
http://estelle.github.io/html5jsapis/
http://estelle.github.io/html5jsapis/
Also, JSON.stringify, touch events, classList
Click on the #4 to show some notes
They're stored with local storage
addNotes: function(){ var ta = document.querySelector('.current .notes'), key; ta.classList.toggle('temphidden'); key = firstPartOfKey() + window.location.hash; ta.value = window.localStorage.getItem(key) || ''; ta.addEventListener('keyup', function(){ window.localStorage.setItem(key,ta.value); }); }
localStorage.setItem('keyname', 'data value') localStorage.getItem('keyname') localStorage.keyname localStorage.removeItem('keyname'); localStorage.clear(); localStorage.key(position) localStorage.length
sessionStorage.setItem('keyname', 'data value') sessionStorage.getItem('keyname') sessionStorage.keyname sessionStorage.removeItem('keyname'); sessionStorage.clear(); sessionStorage.key(position) sessionStorage.length
IE 8+
The 'Pause' and 'New' button event handler
eventHandlers: function(){ if('ontouchstart' in window || 'createTouch' in document || (window.DocumentTouch && document instanceof DocumentTouch)) { qbdoo.btn_pause.addEventListener('touchend', qbdoo.pauseGameOrNewGame); } else { qbdoo.btn_pause.addEventListener('click', qbdoo.pauseGameOrNewGame); } },
pauseGameOrNewGame: function(){ if (qbdoo.game.classList.contains('over')) { qbdoo.startNewGame(); } else { qbdoo.pauseGame(); } },
pauseGame: function(newgame) { var currentState = {}, i, cardinfo = []; // if game is paused if(qbdoo.game.classList.contains('paused')){ qbdoo.playGame(); return false; } // else qbdoo.pauseOrPlayBoard('pause'); currentState = qbdoo.storeValues(); for (i = 0; i < qbdoo.cardCount; i++) { cardinfo.push(qbdoo.cards[i].dataset); } // add level to value set currentState.currentLevel = qbdoo.currentLevel; currentState.cardPositions = JSON.stringify(cardinfo); // add to local storage localStorage.setItem('pausedgame', JSON.stringify(currentState)); //clear the board qbdoo.clearAll(); },
JSON.stringify
converts an object to JSON notation representing it.
IE8+, and all other browsers
IE8+, and all other browsers
<script src="jquery.js"></script> <script type="text/javascript"> $('li:first').addClass('first'); </script>
jquery.min.js
from: ajax.googleapis.com/ajax/libs/jquery/1.7.2
96.2KB + HTTP request + 4J + DNS lookup
vanilla js
document.querySelector('li').classList.add('first');
or simply
li:first-of-type { /* .first declarations */ }
var chil = $('#bar .foo');
Natively
var el = document.querySelector('#bar'); var chil = el.querySelectorAll('.foo'); **
or
chil = d.querySelectorAll('#bar .foo');
*Supported since IE8
**Returns a static nodelist
IE10+, Android 3+, and all other browsers
$('#foo').addClass('bar'); $('#foo').removeClass('bar'); $('#foo').toggle('bar'); $('#foo').hasClass('bar');
document.querySelector('#foo').classList.add('bar'); document.querySelector('#foo').classList.remove('bar'); document.querySelector('#foo').classList.toggle('bar');
fooCL = document.querySelector('#foo').classList; fooCL.add('bar'); fooCL.remove('bar'); fooCL.toggle('bar'); fooCL.contains('bar'); // true or false
* Late to the game: Android 3,IE 10
jQuery
$('.foo').addClass('bar');
Native
var foos = document.querySelectorAll('.foo'); for(var i = 0; i < foos.length; i++){ foos[i].classList.add('bar'); }
<div id="board" class="level1"> <div data-value="2" data-position="1"> <div class="face"></div> <div class="back"></div> </div> <div data-value="4" data-position="2"> <div class="face"></div> <div class="back"></div> </div> <div data-value="7" data-position="3"> <div class="face"></div> <div class="back"></div> </div> <div data-value="3" data-position="4"> <div class="face"></div> <div class="back"></div> </div> <div data-value="1" data-position="5"> <div class="face"></div> <div class="back"></div> </div> <div data-value="6" data-position="6"> <div class="face"></div> <div class="back"></div> </div> <div data-value="6" data-position="7"> <div class="face"></div> <div class="back"></div> </div> <div data-value="7" data-position="8"> <div class="face"></div> <div class="back"></div> </div> <div data-value="8" data-position="9"> <div class="face"></div> <div class="back"></div> </div> <div data-value="2" data-position="10"> <div class="face"></div> <div class="back"></div> </div> <div data-value="1" data-position="11"> <div class="face"></div> <div class="back"></div> </div> <div data-value="4" data-position="12"> <div class="face"></div> <div class="back"></div> </div> <div data-value="5" data-position="13"> <div class="face"></div> <div class="back"></div> </div> <div data-value="3" data-position="14"> <div class="face"></div> <div class="back"></div> </div> <div data-value="8" data-position="15"> <div class="face"></div> <div class="back"></div> </div> <div data-value="5" data-position="16"> <div class="face"></div> <div class="back"></div> </div> <div data-value="0" data-position="17"> <div class="face"></div> <div class="back"></div> </div> <div data-value="0" data-position="18"> <div class="face"></div> <div class="back"></div> </div> <div data-value="0" data-position="19"> <div class="face"></div> <div class="back"></div> </div> <div data-value="0" data-position="20"> <div class="face"></div> <div class="back"></div> </div> <div data-value="0" data-position="21"> <div class="face"></div> <div class="back"></div> </div> <div data-value="0" data-position="22"> <div class="face"></div> <div class="back"></div> </div> <div data-value="0" data-position="23"> <div class="face"></div> <div class="back"></div> </div> <div data-value="0" data-position="24"> <div class="face"></div> <div class="back"></div> </div> </div>
Add attributes to elements in the form of data-name and access these through the DOM using dataset[name] on the element in question.
<p data-foo-bar="test">
That's an author defined attribute
</p>
dataset property returns a DOMStringMap object of element's data- attributes
el.dataset['fooBar']
dataset is a convenience feature for handling the data-* attributes, which are exposed as camel-cased properties.
e.dataset.fooBar = 'test' e.dataset.value = '5' e.dataset.position = '6'
sets the data-foo-bar or data-value attribute on e.
d.body.dataset.fooBar = 'frog'; alert("A) " + d.body.getAttribute('data-foo-bar')); alert("B) " + d.body.dataset['fooBar']); alert("C) " + d.body.dataset.fooBar);
pauseGame: function(newgame) { var currentState = {}, i, cardinfo = []; // if game is paused if(qbdoo.game.classList.contains('paused')){ qbdoo.playGame(); return false; } // else qbdoo.pauseOrPlayBoard('pause'); currentState = qbdoo.storeValues(); for (i = 0; i < qbdoo.cardCount; i++) { cardinfo.push(qbdoo.cards[i].dataset); } // add level to value set currentState.currentLevel = qbdoo.currentLevel; currentState.cardPositions = JSON.stringify(cardinfo); // add to local storage localStorage.setItem('pausedgame', JSON.stringify(currentState)); //clear the board qbdoo.clearAll(); },
clearAll: function() { for (var i = 0; i < qbdoo.cardCount; i++) { qbdoo.cards[i].dataset.value = 0; } },
getValue: function(mycard) { return mycard.dataset['value']; },
setupGame: function(savedCards) {
var cardsValues, cards, dbsize;
// if starting from pause
if(savedCards) {
cardsValues = JSON.parse(savedCards);
for(i = 0; i < qbdoo.cardCount; i++){
for (key in cardsValues[i]) {
qbdoo.cards[i].dataset[key] = cardsValues[i][key];
}
}
} else { // not from pause
if (qbdoo.iterations &&
(qbdoo.iterations%qbdoo.iterationsPerLevel == 0)){
qbdoo.levelUp();
}
// populate all the active blocks with data valuess
for (var i = 1; i <= qbdoo.cardCount; i++) {
var num = "";
while (!num) {
num = qbdoo.randomize();
}
// set the data-value for each card
qbdoo.board.querySelector("div[data-position='" + i + "']").setAttribute("data-value", num);
}
// add to iterations so that iterationsPerLevel will eventually cause a level increase.
qbdoo.iterations++;
}
if(qbdoo.storageType !== "local"){
if(!qbdoo.db){
if (window.openDatabase) {
dbSize = 5 * 1024 * 1024;
qbdoo.db = openDatabase("highscoresDB", "1.0", "scores", 200000);
}
}
qbdoo.loadHighScoresSQL();
qbdoo.loadHighScoresSQL();
} else {
qbdoo.loadHighScoresLocal();
}
qbdoo.renderHighScores();
qbdoo.cardarray = [];
qbdoo.cardarray2 = [];
qbdoo.timerPause = true;
qbdoo.pauseOrPlayBoard('pause');
qbdoo.cardClicks();
qbdoo.eventHandlers();
qbdoo.setTimer(savedCards);
qbdoo.changeTheme();
qbdoo.congratulations('off');
qbdoo.writeLevel();
},
Define your own DOM manipulable data attributes
<div data-value="0" data-position="24"> <div class="face"></div> <div class="back"></div> </div>
All browsers support "data-*", but full support of 'dataset started with IE10, FF6, Safari 5.1, Chrome 7, Opera 11.1. Supported in iOS and Android. Polly fill
Part of CSS 2.1. Supported since IE8
for the number theme, change <body> class to "n"
.n div[data-value="1"] .face:after { content: '1';} .n div[data-value="2"] .face:after { content: '2';} .n div[data-value="3"] .face:after { content: '3';} .n div[data-value="4"] .face:after { content: '4';} .n div[data-value="5"] .face:after { content: '5';} .n div[data-value="6"] .face:after { content: '6';} .n div[data-value="7"] .face:after { content: '7';} .n div[data-value="8"] .face:after { content: '8';} .n div[data-value="9"] .face:after { content: '9';} .n div[data-value="10"] .face:after { content:'10';} .n div[data-value="11"] .face:after { content:'11';} .n div[data-value="12"] .face:after { content:'12';}
for the font shape theme, change <body> class to "s"
.s div[data-value="1"] .face:after { content:'★';} .s div[data-value="2"] .face:after { content:'⚫';} .s div[data-value="3"] .face:after { content:'⬣';} .s div[data-value="4"] .face:after { content:'◼';} .s div[data-value="5"] .face:after { content:'⬆';} .s div[data-value="6"] .face:after { content:'►';} .s div[data-value="7"] .face:after { content:'♦';} .s div[data-value="8"] .face:after { content:'♥';} .s div[data-value="9"] .face:after { content:'♣';} .s div[data-value="10"] .face:after { content:'♠';} .s div[data-value="11"] .face:after { content:'☻'} .s div[data-value="12"] .face:after { content:'⬇';}
What you need to know:
:before
and :after
content: '';
is the minimum requiredtop:0; bottom:0; left:0; right:0;
attr(x)
<!doctype HTML> <html manifest="cubeedoo.appcache"> <meta charset="utf-8"/> <title>....
CACHE MANIFEST #version01 #files that explicitly cached CACHE: index.html css/styles.css scripts/application.js #Resources requiring connectivity NETWORK: signin.php dosomething.cgi FALLBACK: / 404.html
Add to .htaccess file
AddType text/cache-manifest .appcache
if(window.applicationCache){ var appCache = window.applicationCache; appCache.update(); if (appCache.status == appCache.UPDATEREADY ){ appCache.swapCache(); } }
transform: translate(-80px, 200px);
transform: rotate(15deg);
transform: scale(1.5, 2);
transform: skewX(-8deg);
transform: translate(-80px, 200px) rotate(-15deg) scale(2, 1.5) skewX(8deg);
Specifies the x and y position of the origin, relative to the transform object.
Enables the transition of properties from one state to the next over a defined length of time
All browsers, prefixed. No prefix FF16 & IE10. Not in OperaMini or Win✆
var qbdoo = { ... match: 'assets/match.mp3', noMatch: 'assets/notmatch.mp3', mute: false, ...
var qbdoo = { ... match: document.getElementById('match'), noMatch: document.getElementById('noMatch'), mute: false, ...
playSound: function(matched){ //if sound is off for game, skip if(qbdoo.mute) { return false; } if(!qbdoo.audio){ qbdoo.audio = document.createElement('audio') } if(matched){ qbdoo.audio.src = qbdoo.match; } else { qbdoo.audio.src = qbdoo.noMatch; } qbdoo.audio.play(); }
playSound: function(matched){ if(qbdoo.mute) { return false; } if(matched){ qbdoo.match.play(); } else { qbdoo.noMatch.play(); } }
<audio id=match preload src=match.mp3></audio> <audio id=noMatch preload src=fail.mp3></audio> <audio id=gameover preload src=gameover.mp3></audio>
controls
shows controlsloop
loops the audioautoplay
don't do this!preload = none | auto | metadata
audio.play()
audio.pause()
audio.volume += 0.1
or -