mobile-browsers-attack.appspot.com
@pamelafox
(use the space bar)
PhoneGap + Zepto + Bootstrap
function setupFixedFix() {
if (isFixedBroken()) {
$('.container-fluid').css({'position': 'static'});
$('.actionsbar, .navbar').css({'position': 'absolute'});
fixFixed();
$(window).bind('scroll', fixFixed);
$('.mobile-page').bind('touchend', fixFixed);
}
}
function isFixedBroken(){
// Feature detection didnt seem to work so we check the user agent instead
return (ED.util.isIOS() && navigator.userAgent.match(/[5-9]_[0-9]/) === null);
}
function fixFixed() {
if (isFixedBroken()) {
$('.actionsbar').css({'top': (window.pageYOffset) + 'px'});
$('.navbar').css({'top': (window.pageYOffset + window.innerHeight - 30) + 'px'});
}
}
ED.util.addTouchOrClickHandler($('.mobile-log-a'), openPageLink);
ED.util.addClickHandler($('.mobile-footer-a'), openPageLink);
ED.util.addClickHandler($('.mobile-stream-a'), openStreamLink);
function addTouchOrClickHandler(dom, callback, logThis) {
if (useTouchEvents()) {
dom.each(function() {
$(this).unbind('tap', callback);
$(this).bind('tap', callback);
$(this).bind('touchstart', function(e) {
e.preventDefault();
var item = e.currentTarget;
if (ISTOUCHING) return;
item.moved = false;
ISTOUCHING = true;
item.startX = e.touches[0].pageX;
item.startY = e.touches[0].pageY;
$(item).addClass('active');
});
$(this).bind('touchmove', function(e) {
var item = e.currentTarget;
if (Math.abs(e.touches[0].pageX - item.startX) > 10 ||
Math.abs(e.touches[0].pageY - item.startY) > 10) {
item.moved = true;
$(item).removeClass('active');
}
});
$(this).bind('touchend', function(e) {
var item = e.currentTarget;
ISTOUCHING = false;
if(!item.moved) {
$(item).trigger('tap');
}
setTimeout(function() {
$(item).removeClass('active');
}, 300);
delete item.moved;
});
});
} else {
dom.unbind('click', callback).bind('click', callback);
}
}
def click_button(self, selector):
if self.driver.name == 'iPhone':
self.driver.execute_script('$("%s").trigger("tap")' % (selector))
else:
try:
self.get_el(selector).click()
function show() {
ED.util.resetScroll();
ED.util.makeAutoResize($(DOM.notesInput));
ED.util.putCursorAtEnd($(DOM.notesInput));
}
function resetScroll(top) {
top = top || 0;
$(document).scrollTop(top);
window.setTimeout(function() {
$(document).scrollTop(top);
}, 10);
}
<input type="number" step="0.01">
function hideKeyboard() {
$('input, textarea').blur();
if (ED.util.isIOS()) {
document.activeElement.blur();
}
if (ED.util.isAndroid()) {
var field = $('<input type="text">');
$('#mobile-logs-page').append(field);
setTimeout(function() {
field.focus();
setTimeout(function() {
field.hide();
}, 50);
}, 50);
}
}
/**
* This is a hack to make text input focus work in Android/PG
* where calling el.focus() doesn't actually have the
* blinking cursor effect = scumbag.
* @param {Zepto} $el A zepto element.
*/
ws.focus = function($el) {
var el = $el.get(0);
el.focus();
el.setSelectionRange && el.setSelectionRange(0, 0);
};
Courtesy @elsigh
canvasContext.drawImage(img, x, y, width, height);
var dataUrl = canvas.toDataURL('image/png');
if (dataUrl.indexOf('data:image/png') == -1) {
onFail('Got back an invalid data URL');
} else {
onSuccess(dataUrl.replace('data:image/png;base64,', ''));
}
var cachedSupportsDataURL;
function supportsDataURL() {
if (cachedSupportsDataURL === undefined) {
var c = document.createElement('canvas');
var dataUrl = c.toDataURL('image/png');
cachedSupportsDataURL = (dataUrl.indexOf('data:image/png') === 0);
}
return cachedSupportsDataURL;
}
var MSG_LOG_OFFLINE = 'We can\'t connect to the network now, so your log may be out of date.';
runIfOnline(function() {
fetchNewData();
}, MSG_LOG_OFFLINE);
}
function runIfOnline(onlineFunc, message, offlineFunc) {
message = message || 'Sorry, we can\'t connect to the network right now.';
if (isOnline()) {
try {
onlineFunc();
} catch(e) {
logError(e);
}
} else {
alert(message);
if (offlineFunc) {
try {
offlineFunc();
} catch(ee) {
logError(ee);
}
}
}
}
function isOnline() {
// Presume online unless PhoneGap or HTML5 tell us otherwise.
if (navigator.network && navigator.network.connection.type == Connection.NONE && 0) {
ED.util.log('Found Connection.NONE');
return false;
}
if (navigator.onLine === false) {
ED.util.log('Found navigator.onLine is false');
return false;
}
return true;
}

var timedEvents = [];
function timeEvent(name) {
timedEvents.push({'name': name || 'unnamed', time: Date.now()});
}
function showTimedEvents() {
var timeText = '';
var timeHtml = '<table>';
for (var i = 0; i < timedEvents.length; i++) {
var timedEvent = timedEvents[i];
timeText += timedEvent.name + ': ' + timedEvent.time;
var diff = '';
if (i > 0) {
diff = (timedEvent.time - timedEvents[i-1].time);
timeText += ' (' + diff + 'ms elapsed)';
}
timeHtml += '<tr><td>' + timedEvent.name + '<td>' + timedEvent.time + '<td>' + diff;
timeText += '\n';
}
console.log(timeText);
document.body.innerHTML += timeHtml;
}
<html>
<head>
<script>
// Timer functions
</script>
<script>timeEvent('Before CSS');</script>
<link rel="stylesheet" href="css/all-phonegap-min.css?v=10201550"/>
<script>timeEvent('After CSS');</script>
</head>
<body>
<div>HTML here (more than this)</div>
<script>timeEvent('After HTML');</script>
<script src="js/libs/jquery-1.6.2.min.js"></script>
<script>timeEvent('After jQuery script tag');</script>
<script src="js/all-phonegap-min.js?v=10201550"></script>
<script>timeEvent('After other script tag');</script>
<script>
$(document).ready(function() {
timeEvent('After document ready');
myCustomMobileFunction();
timeEvent('After ready JS called');
showTimedEvents();
});
</script>
</body>
</html>
jQuery -> Zepto
Shaved: 22%
onload -> deviceready
Shaved: 67%
document.addEventListener("DOMContentLoaded", function() {
ED.mobile.setupMobile();
});
document.addEventListener('deviceready', function() {
ED.mobile.setupPhonegap();
}, false);
function setupMobile() {
// Sets up the page CSS
// Binds events to DOM
}
function setupPhonegap() {
// Shows splash page
// Fetches data
// Binds PhoneGap events
}
☞ Get to deviceready faster on Android
.android {
.modal {
@include box-shadow(none);
@include background-clip(border-box);
@include border-radius(0px);
border: 1px solid black;
}
}
$(window).on('scroll', $.throttle(500, loadVisibleImages));
☞ Delayed Image Loading on Long Pages
$textAreas.autoResizer({resizeOnChange: !isAndroid()});
window.setTimeout(function() {
ED.shared.setupStream();
ED.shared.setupStreamTimer();
}, 2000);
window.setTimeout(function() {
ED.shared.maybeFetchStream();
}, 100);
window.setTimeout(function() {
fetchNewData();
}, 1000);
☞ Zakas: Responsive Interfaces
☞ Issue 113088: Let Chrome be used by WebView