mirror of
https://github.com/coderaiser/cloudcmd.git
synced 2026-01-23 10:45:47 +00:00
feature(dom) rm addClass, removeClass
This commit is contained in:
parent
87e77c2654
commit
b53691f91a
24 changed files with 1119 additions and 78 deletions
|
|
@ -28,6 +28,7 @@
|
|||
"format-io": "~0.9.6",
|
||||
"rendy": "~1.1.0",
|
||||
"github": "~0.10.6",
|
||||
"vk-openapi": "~0.0.1"
|
||||
"vk-openapi": "~0.0.1",
|
||||
"html5-polyfills": "*"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,7 +161,10 @@ var Util, DOM, CloudFunc, join;
|
|||
},
|
||||
|
||||
funcBefore = function(callback) {
|
||||
var src = CloudCmd.LIBDIRCLIENT + 'polyfill.js';
|
||||
var src = prefix + '/join:' + [
|
||||
CloudCmd.LIBDIRCLIENT + 'polyfill.js',
|
||||
'/modules/html5-polyfills/classList.js'
|
||||
].join(':');
|
||||
|
||||
DOM.loadJquery(function() {
|
||||
DOM.load.js(src, callback);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
var files = DOM.getActiveFiles();
|
||||
|
||||
files.forEach(function(element) {
|
||||
DOM.addClass(element, CLASS);
|
||||
element.classList.add(CLASS);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +48,7 @@
|
|||
var files = DOM.getByClassAll(CLASS);
|
||||
|
||||
[].forEach.call(files, function(element) {
|
||||
DOM.removeClass(element, CLASS);
|
||||
element.classList.remove(CLASS);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -151,43 +151,6 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
|
|||
|
||||
DOMTreeProto = function() {
|
||||
var DOM = this;
|
||||
/**
|
||||
* add class to element
|
||||
*
|
||||
* @param element
|
||||
* @param pClass
|
||||
*/
|
||||
this.addClass = function(element, pClass) {
|
||||
var ret = element && pClass;
|
||||
|
||||
if (ret)
|
||||
element.classList.add(pClass);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* remove class pClass from element element
|
||||
* @param element
|
||||
* @param pClass
|
||||
*/
|
||||
this.removeClass = function(element, pClass) {
|
||||
var ret = element && pClass;
|
||||
|
||||
if (ret)
|
||||
element.classList.remove(pClass);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this.toggleClass = function(element, pClass) {
|
||||
var ret = element && pClass;
|
||||
|
||||
if (ret)
|
||||
element.classList.toggle(pClass);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* check class of element
|
||||
|
|
@ -284,11 +247,13 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
|
|||
* @param element
|
||||
*/
|
||||
this.hide = function(element) {
|
||||
return DOM.addClass(element, 'hidden');
|
||||
element.classList.add('hidden');
|
||||
return DOM;
|
||||
};
|
||||
|
||||
this.show = function(element) {
|
||||
return DOM.removeClass(element, 'hidden');
|
||||
element.classList.remove('hidden');
|
||||
return DOM;
|
||||
};
|
||||
},
|
||||
|
||||
|
|
@ -313,7 +278,7 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
|
|||
var ret = DOM.isCurrentFile(currentFile);
|
||||
|
||||
if (ret)
|
||||
DOM.removeClass(currentFile, CURRENT_FILE);
|
||||
currentFile.classList.remove(CURRENT_FILE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -931,7 +896,7 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
|
|||
unsetCurrentFile(currentFileWas);
|
||||
}
|
||||
|
||||
this.addClass(currentFile, CURRENT_FILE);
|
||||
currentFile.classList.add(CURRENT_FILE);
|
||||
|
||||
path = DOM.getCurrentDirPath();
|
||||
|
||||
|
|
@ -1003,10 +968,11 @@ var CloudCmd, Util, DOM, CloudFunc, Dialog;
|
|||
* @param currentFile
|
||||
*/
|
||||
this.toggleSelectedFile = function(currentFile) {
|
||||
var current = currentFile || this.getCurrentFile(),
|
||||
ret = this.toggleClass(current, SELECTED_FILE);
|
||||
var current = currentFile || this.getCurrentFile();
|
||||
|
||||
current.classList.toggle(SELECTED_FILE);
|
||||
|
||||
return ret;
|
||||
return Cmd;
|
||||
};
|
||||
|
||||
this.toggleAllSelectedFiles = function() {
|
||||
|
|
|
|||
|
|
@ -155,34 +155,6 @@ var Util, DOM, jQuery;
|
|||
element.scrollIntoView(alignWithTop);
|
||||
}
|
||||
};
|
||||
|
||||
if (!document.body.classList) {
|
||||
DOM.isContainClass = function(el, className) {
|
||||
var ret = $(el).hasClass(className);
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
DOM.addClass = function(pElement, pClass) {
|
||||
var lRet,
|
||||
lClassName = pElement && pElement.className,
|
||||
lSpaceChar = lClassName ? ' ' : '';
|
||||
|
||||
lRet = !DOM.isContainClass(pElement, pClass);
|
||||
|
||||
if (lRet)
|
||||
pElement.className += lSpaceChar + pClass;
|
||||
|
||||
return lRet;
|
||||
};
|
||||
|
||||
DOM.removeClass = function(pElement, pClass) {
|
||||
var lClassName = pElement.className;
|
||||
|
||||
if (lClassName.length > pClass.length)
|
||||
pElement.className = lClassName.replace(pClass, '');
|
||||
};
|
||||
}
|
||||
|
||||
if (!window.JSON) {
|
||||
Util.json.parse = $.parseJSON;
|
||||
|
|
|
|||
|
|
@ -317,11 +317,11 @@ var CloudCmd, Util, DOM, CloudFunc, $;
|
|||
}
|
||||
|
||||
function hideOverlay() {
|
||||
DOM.removeClass(Overlay, 'view-overlay');
|
||||
Overlay.classList.remove('view-overlay');
|
||||
}
|
||||
|
||||
function showOverlay() {
|
||||
DOM.addClass(Overlay, 'view-overlay');
|
||||
Overlay.classList.add('view-overlay');
|
||||
}
|
||||
|
||||
function listener(event) {
|
||||
|
|
|
|||
31
modules/html5-polyfills/.bower.json
Normal file
31
modules/html5-polyfills/.bower.json
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
{ sdfljsdlfjsdf lsdjflsdjflsdj ------- sdfjsdlfjdsljf
|
||||
"name": "html5-polyfills", sldjflsdjf lsdfjlsdjf
|
||||
"description": "Collection of polyfills by Remy Sharp",
|
||||
"homepage": "https://github.com/remy/polyfills",
|
||||
"keywords": [
|
||||
"polyfill",
|
||||
"client",
|
||||
"browser"
|
||||
],
|
||||
"author": {
|
||||
"name": "Remy Sharp",
|
||||
"email": "remy@leftlogic.com"
|
||||
},
|
||||
"readme": "This is my own collection of code snippets that support different native features of browsers using JavaScript (and if required, Flash in some cases).",
|
||||
"readmeFilename": "README.md",
|
||||
"_id": "html5-polyfills@0.0.20130621",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/remy/polyfills.git"
|
||||
},
|
||||
"_release": "768ce355de",
|
||||
"_resolution": {
|
||||
"type": "branch",
|
||||
"branch": "master",
|
||||
"commit": "768ce355de8f31d8d0a99aa3aba3708daa54e873"
|
||||
},
|
||||
"_source": "git://github.com/remy/polyfills.git",
|
||||
"_target": "*",
|
||||
"_originalSource": "html5-polyfills",
|
||||
"_direct": true
|
||||
}
|
||||
186
modules/html5-polyfills/EventSource.js
Normal file
186
modules/html5-polyfills/EventSource.js
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
;(function (global) {
|
||||
|
||||
if ("EventSource" in global) return;
|
||||
|
||||
var reTrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g;
|
||||
|
||||
var EventSource = function (url) {
|
||||
var eventsource = this,
|
||||
interval = 500, // polling interval
|
||||
lastEventId = null,
|
||||
cache = '';
|
||||
|
||||
if (!url || typeof url != 'string') {
|
||||
throw new SyntaxError('Not enough arguments');
|
||||
}
|
||||
|
||||
this.URL = url;
|
||||
this.readyState = this.CONNECTING;
|
||||
this._pollTimer = null;
|
||||
this._xhr = null;
|
||||
|
||||
function pollAgain(interval) {
|
||||
eventsource._pollTimer = setTimeout(function () {
|
||||
poll.call(eventsource);
|
||||
}, interval);
|
||||
}
|
||||
|
||||
function poll() {
|
||||
try { // force hiding of the error message... insane?
|
||||
if (eventsource.readyState == eventsource.CLOSED) return;
|
||||
|
||||
// NOTE: IE7 and upwards support
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', eventsource.URL, true);
|
||||
xhr.setRequestHeader('Accept', 'text/event-stream');
|
||||
xhr.setRequestHeader('Cache-Control', 'no-cache');
|
||||
// we must make use of this on the server side if we're working with Android - because they don't trigger
|
||||
// readychange until the server connection is closed
|
||||
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
||||
|
||||
if (lastEventId != null) xhr.setRequestHeader('Last-Event-ID', lastEventId);
|
||||
cache = '';
|
||||
|
||||
xhr.timeout = 50000;
|
||||
xhr.onreadystatechange = function () {
|
||||
if (this.readyState == 3 || (this.readyState == 4 && this.status == 200)) {
|
||||
// on success
|
||||
if (eventsource.readyState == eventsource.CONNECTING) {
|
||||
eventsource.readyState = eventsource.OPEN;
|
||||
eventsource.dispatchEvent('open', { type: 'open' });
|
||||
}
|
||||
|
||||
var responseText = '';
|
||||
try {
|
||||
responseText = this.responseText || '';
|
||||
} catch (e) {}
|
||||
|
||||
// process this.responseText
|
||||
var parts = responseText.substr(cache.length).split("\n"),
|
||||
eventType = 'message',
|
||||
data = [],
|
||||
i = 0,
|
||||
line = '';
|
||||
|
||||
cache = responseText;
|
||||
|
||||
// TODO handle 'event' (for buffer name), retry
|
||||
for (; i < parts.length; i++) {
|
||||
line = parts[i].replace(reTrim, '');
|
||||
if (line.indexOf('event') == 0) {
|
||||
eventType = line.replace(/event:?\s*/, '');
|
||||
} else if (line.indexOf('retry') == 0) {
|
||||
retry = parseInt(line.replace(/retry:?\s*/, ''));
|
||||
if(!isNaN(retry)) { interval = retry; }
|
||||
} else if (line.indexOf('data') == 0) {
|
||||
data.push(line.replace(/data:?\s*/, ''));
|
||||
} else if (line.indexOf('id:') == 0) {
|
||||
lastEventId = line.replace(/id:?\s*/, '');
|
||||
} else if (line.indexOf('id') == 0) { // this resets the id
|
||||
lastEventId = null;
|
||||
} else if (line == '') {
|
||||
if (data.length) {
|
||||
var event = new MessageEvent(data.join('\n'), eventsource.url, lastEventId);
|
||||
eventsource.dispatchEvent(eventType, event);
|
||||
data = [];
|
||||
eventType = 'message';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.readyState == 4) pollAgain(interval);
|
||||
// don't need to poll again, because we're long-loading
|
||||
} else if (eventsource.readyState !== eventsource.CLOSED) {
|
||||
if (this.readyState == 4) { // and some other status
|
||||
// dispatch error
|
||||
eventsource.readyState = eventsource.CONNECTING;
|
||||
eventsource.dispatchEvent('error', { type: 'error' });
|
||||
pollAgain(interval);
|
||||
} else if (this.readyState == 0) { // likely aborted
|
||||
pollAgain(interval);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
|
||||
setTimeout(function () {
|
||||
if (true || xhr.readyState == 3) xhr.abort();
|
||||
}, xhr.timeout);
|
||||
|
||||
eventsource._xhr = xhr;
|
||||
|
||||
} catch (e) { // in an attempt to silence the errors
|
||||
eventsource.dispatchEvent('error', { type: 'error', data: e.message }); // ???
|
||||
}
|
||||
};
|
||||
|
||||
poll(); // init now
|
||||
};
|
||||
|
||||
EventSource.prototype = {
|
||||
close: function () {
|
||||
// closes the connection - disabling the polling
|
||||
this.readyState = this.CLOSED;
|
||||
clearInterval(this._pollTimer);
|
||||
this._xhr.abort();
|
||||
},
|
||||
CONNECTING: 0,
|
||||
OPEN: 1,
|
||||
CLOSED: 2,
|
||||
dispatchEvent: function (type, event) {
|
||||
var handlers = this['_' + type + 'Handlers'];
|
||||
if (handlers) {
|
||||
for (var i = 0; i < handlers.length; i++) {
|
||||
handlers[i].call(this, event);
|
||||
}
|
||||
}
|
||||
|
||||
if (this['on' + type]) {
|
||||
this['on' + type].call(this, event);
|
||||
}
|
||||
},
|
||||
addEventListener: function (type, handler) {
|
||||
if (!this['_' + type + 'Handlers']) {
|
||||
this['_' + type + 'Handlers'] = [];
|
||||
}
|
||||
|
||||
this['_' + type + 'Handlers'].push(handler);
|
||||
},
|
||||
removeEventListener: function (type, handler) {
|
||||
var handlers = this['_' + type + 'Handlers'];
|
||||
if (!handlers) {
|
||||
return;
|
||||
}
|
||||
for (var i = handlers.length - 1; i >= 0; --i) {
|
||||
if (handlers[i] === handler) {
|
||||
handlers.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
onerror: null,
|
||||
onmessage: null,
|
||||
onopen: null,
|
||||
readyState: 0,
|
||||
URL: ''
|
||||
};
|
||||
|
||||
var MessageEvent = function (data, origin, lastEventId) {
|
||||
this.data = data;
|
||||
this.origin = origin;
|
||||
this.lastEventId = lastEventId || '';
|
||||
};
|
||||
|
||||
MessageEvent.prototype = {
|
||||
data: null,
|
||||
type: 'message',
|
||||
lastEventId: '',
|
||||
origin: ''
|
||||
};
|
||||
|
||||
if ('module' in global) module.exports = EventSource;
|
||||
global.EventSource = EventSource;
|
||||
|
||||
})(this);
|
||||
21
modules/html5-polyfills/MIT-LICENCE.txt
Normal file
21
modules/html5-polyfills/MIT-LICENCE.txt
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
Copyright (c) 2010 Remy Sharp, http://remysharp.com
|
||||
|
||||
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.
|
||||
|
||||
32
modules/html5-polyfills/README.md
Normal file
32
modules/html5-polyfills/README.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# Polyfills
|
||||
|
||||
> A way of getting the browser to behave and support the latest specifications.
|
||||
|
||||
This is my own collection of code snippets that support different native features of browsers using JavaScript (and if required, Flash in some cases).
|
||||
|
||||
## Component Installation
|
||||
|
||||
You can install polyfills using component:
|
||||
|
||||
```
|
||||
component install remy/polyfills
|
||||
```
|
||||
|
||||
If you'd like to include all polyfills (except device motion), you can just:
|
||||
|
||||
```
|
||||
require( 'polyfills' );
|
||||
```
|
||||
|
||||
If you'd only like a specific polyfill, you can require indivual ones like this:
|
||||
|
||||
```
|
||||
require( 'polyfills/classList' );
|
||||
|
||||
// now we can use classList in lots of browsers!
|
||||
element.classList.add( 'foo' );
|
||||
```
|
||||
|
||||
# License
|
||||
|
||||
License: http://rem.mit-license.org
|
||||
96
modules/html5-polyfills/Storage.js
Normal file
96
modules/html5-polyfills/Storage.js
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
if (typeof window.localStorage == 'undefined' || typeof window.sessionStorage == 'undefined') (function () {
|
||||
|
||||
var Storage = function (type) {
|
||||
function createCookie(name, value, days) {
|
||||
var date, expires;
|
||||
|
||||
if (days) {
|
||||
date = new Date();
|
||||
date.setTime(date.getTime()+(days*24*60*60*1000));
|
||||
expires = "; expires="+date.toGMTString();
|
||||
} else {
|
||||
expires = "";
|
||||
}
|
||||
document.cookie = name+"="+value+expires+"; path=/";
|
||||
}
|
||||
|
||||
function readCookie(name) {
|
||||
var nameEQ = name + "=",
|
||||
ca = document.cookie.split(';'),
|
||||
i, c;
|
||||
|
||||
for (i=0; i < ca.length; i++) {
|
||||
c = ca[i];
|
||||
while (c.charAt(0)==' ') {
|
||||
c = c.substring(1,c.length);
|
||||
}
|
||||
|
||||
if (c.indexOf(nameEQ) == 0) {
|
||||
return c.substring(nameEQ.length,c.length);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function setData(data) {
|
||||
data = JSON.stringify(data);
|
||||
if (type == 'session') {
|
||||
window.name = data;
|
||||
} else {
|
||||
createCookie('localStorage', data, 365);
|
||||
}
|
||||
}
|
||||
|
||||
function clearData() {
|
||||
if (type == 'session') {
|
||||
window.name = '';
|
||||
} else {
|
||||
createCookie('localStorage', '', 365);
|
||||
}
|
||||
}
|
||||
|
||||
function getData() {
|
||||
var data = type == 'session' ? window.name : readCookie('localStorage');
|
||||
return data ? JSON.parse(data) : {};
|
||||
}
|
||||
|
||||
|
||||
// initialise if there's already data
|
||||
var data = getData();
|
||||
|
||||
return {
|
||||
length: 0,
|
||||
clear: function () {
|
||||
data = {};
|
||||
this.length = 0;
|
||||
clearData();
|
||||
},
|
||||
getItem: function (key) {
|
||||
return data[key] === undefined ? null : data[key];
|
||||
},
|
||||
key: function (i) {
|
||||
// not perfect, but works
|
||||
var ctr = 0;
|
||||
for (var k in data) {
|
||||
if (ctr == i) return k;
|
||||
else ctr++;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
removeItem: function (key) {
|
||||
delete data[key];
|
||||
this.length--;
|
||||
setData(data);
|
||||
},
|
||||
setItem: function (key, value) {
|
||||
data[key] = value+''; // forces the value to a string
|
||||
this.length++;
|
||||
setData(data);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
if (typeof window.localStorage == 'undefined') window.localStorage = new Storage('local');
|
||||
if (typeof window.sessionStorage == 'undefined') window.sessionStorage = new Storage('session');
|
||||
|
||||
})();
|
||||
22
modules/html5-polyfills/bower.json
Normal file
22
modules/html5-polyfills/bower.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "html5-polyfills",
|
||||
"description": "Collection of polyfills by Remy Sharp",
|
||||
"homepage": "https://github.com/remy/polyfills",
|
||||
"keywords": [
|
||||
"polyfill",
|
||||
"client",
|
||||
"browser"
|
||||
],
|
||||
"author": {
|
||||
"name": "Remy Sharp",
|
||||
"email": "remy@leftlogic.com"
|
||||
},
|
||||
"version": "0.0.20130621",
|
||||
"readme": "This is my own collection of code snippets that support different native features of browsers using JavaScript (and if required, Flash in some cases).",
|
||||
"readmeFilename": "README.md",
|
||||
"_id": "html5-polyfills@0.0.20130621",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/remy/polyfills.git"
|
||||
}
|
||||
}
|
||||
70
modules/html5-polyfills/classList.js
Normal file
70
modules/html5-polyfills/classList.js
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
(function () {
|
||||
|
||||
if (typeof window.Element === "undefined" || "classList" in document.documentElement) return;
|
||||
|
||||
var prototype = Array.prototype,
|
||||
push = prototype.push,
|
||||
splice = prototype.splice,
|
||||
join = prototype.join;
|
||||
|
||||
function DOMTokenList(el) {
|
||||
this.el = el;
|
||||
// The className needs to be trimmed and split on whitespace
|
||||
// to retrieve a list of classes.
|
||||
var classes = el.className.replace(/^\s+|\s+$/g,'').split(/\s+/);
|
||||
for (var i = 0; i < classes.length; i++) {
|
||||
push.call(this, classes[i]);
|
||||
}
|
||||
};
|
||||
|
||||
DOMTokenList.prototype = {
|
||||
add: function(token) {
|
||||
if(this.contains(token)) return;
|
||||
push.call(this, token);
|
||||
this.el.className = this.toString();
|
||||
},
|
||||
contains: function(token) {
|
||||
return this.el.className.indexOf(token) != -1;
|
||||
},
|
||||
item: function(index) {
|
||||
return this[index] || null;
|
||||
},
|
||||
remove: function(token) {
|
||||
if (!this.contains(token)) return;
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
if (this[i] == token) break;
|
||||
}
|
||||
splice.call(this, i, 1);
|
||||
this.el.className = this.toString();
|
||||
},
|
||||
toString: function() {
|
||||
return join.call(this, ' ');
|
||||
},
|
||||
toggle: function(token) {
|
||||
if (!this.contains(token)) {
|
||||
this.add(token);
|
||||
} else {
|
||||
this.remove(token);
|
||||
}
|
||||
|
||||
return this.contains(token);
|
||||
}
|
||||
};
|
||||
|
||||
window.DOMTokenList = DOMTokenList;
|
||||
|
||||
function defineElementGetter (obj, prop, getter) {
|
||||
if (Object.defineProperty) {
|
||||
Object.defineProperty(obj, prop,{
|
||||
get : getter
|
||||
});
|
||||
} else {
|
||||
obj.__defineGetter__(prop, getter);
|
||||
}
|
||||
}
|
||||
|
||||
defineElementGetter(Element.prototype, 'classList', function () {
|
||||
return new DOMTokenList(this);
|
||||
});
|
||||
|
||||
})();
|
||||
16
modules/html5-polyfills/component.json
Normal file
16
modules/html5-polyfills/component.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "polyfills",
|
||||
"scripts": [
|
||||
"classList.js",
|
||||
"dataset.js",
|
||||
"device-motion-polyfill.js",
|
||||
"EventSource.js",
|
||||
"index.js",
|
||||
"input-target.js",
|
||||
"offline-events.js",
|
||||
"range.js",
|
||||
"sessionStorage.js",
|
||||
"Storage.js"
|
||||
],
|
||||
"main": "index.js"
|
||||
}
|
||||
57
modules/html5-polyfills/dataset.js
Normal file
57
modules/html5-polyfills/dataset.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
(function () {
|
||||
var forEach = [].forEach,
|
||||
regex = /^data-(.+)/,
|
||||
dashChar = /\-([a-z])/ig,
|
||||
el = document.createElement('div'),
|
||||
mutationSupported = false,
|
||||
match
|
||||
;
|
||||
|
||||
function detectMutation() {
|
||||
mutationSupported = true;
|
||||
this.removeEventListener('DOMAttrModified', detectMutation, false);
|
||||
}
|
||||
|
||||
function toCamelCase(s) {
|
||||
return s.replace(dashChar, function (m,l) { return l.toUpperCase(); });
|
||||
}
|
||||
|
||||
function updateDataset() {
|
||||
var dataset = {};
|
||||
forEach.call(this.attributes, function(attr) {
|
||||
if (match = attr.name.match(regex))
|
||||
dataset[toCamelCase(match[1])] = attr.value;
|
||||
});
|
||||
return dataset;
|
||||
}
|
||||
|
||||
// only add support if the browser doesn't support data-* natively
|
||||
if (el.dataset != undefined) return;
|
||||
|
||||
el.addEventListener('DOMAttrModified', detectMutation, false);
|
||||
el.setAttribute('foo', 'bar');
|
||||
|
||||
function defineElementGetter (obj, prop, getter) {
|
||||
if (Object.defineProperty) {
|
||||
Object.defineProperty(obj, prop,{
|
||||
get : getter
|
||||
});
|
||||
} else {
|
||||
obj.__defineGetter__(prop, getter);
|
||||
}
|
||||
}
|
||||
|
||||
defineElementGetter(Element.prototype, 'dataset', mutationSupported
|
||||
? function () {
|
||||
if (!this._datasetCache) {
|
||||
this._datasetCache = updateDataset.call(this);
|
||||
}
|
||||
return this._datasetCache;
|
||||
}
|
||||
: updateDataset
|
||||
);
|
||||
|
||||
document.addEventListener('DOMAttrModified', function (event) {
|
||||
delete event.target._datasetCache;
|
||||
}, false);
|
||||
})();
|
||||
253
modules/html5-polyfills/device-motion-polyfill.js
Normal file
253
modules/html5-polyfills/device-motion-polyfill.js
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
/**
|
||||
* DeviceMotion and DeviceOrientation polyfill
|
||||
* by Remy Sharp / leftlogic.com
|
||||
* MIT http://rem.mit-license.org
|
||||
*
|
||||
* Usage: used for testing motion events, include
|
||||
* script in head of test document and allow popup
|
||||
* to open to control device orientation.
|
||||
*/
|
||||
(!document.DeviceOrientationEvent || !document.DeviceMotionEvent) && (function () {
|
||||
|
||||
// thankfully we don't have to do anything, because the event only fires on the window object
|
||||
var polyfill = {
|
||||
motion: !document.DeviceMotionEvent,
|
||||
orientation: !document.DeviceOrientationEvent
|
||||
};
|
||||
|
||||
if (polyfill.orientation) window.DeviceOrientationEvent = function () {};
|
||||
|
||||
if (polyfill.motion) window.DeviceMotionEvent = function () {};
|
||||
|
||||
// images - yes I do like to be self contained don't I?! :)
|
||||
var imageSrc = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFsAAACpCAYAAABEbEGLAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIE1hY2ludG9zaCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxODkwMDQ2NTNDNEYxMUUxQTYyOTk2M0QwMjU4OThGOCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxODkwMDQ2NjNDNEYxMUUxQTYyOTk2M0QwMjU4OThGOCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjE4OTAwNDYzM0M0RjExRTFBNjI5OTYzRDAyNTg5OEY4IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjE4OTAwNDY0M0M0RjExRTFBNjI5OTYzRDAyNTg5OEY4Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+jKamsAAAAtNJREFUeNrs2t1t01AYgGG3dACPkA3qEcIlV5QJSCdAnaAwAWKCsgFs0HQChwmaS+6SThCOKwuigtP4J+ln9LzSRyWaRMmTE8fHcJLt3yRNkeY8U9VDmkWa+ZAPOktTptmYf84qzU29GDtXQG49111XM7xuUy3QfF/oa2DHAbeijwReABp8vjVh+zI8zFw4fBxv7q3qF1jdp1s7Qx2ut9UfZ0Gh+26BJ313dANXRDuvXg38xuf1NjrKoeTxMBKlq/rCzlCt01zWP0N0GujjtjzQ4y4iYS+DPJd8ZI/bCTtKHw7wmLNIJwBngbCn9QZgOcDZSF4/XqgzrUjY26ds0//xZPs0E2zYgg1bsGHDFuwRt2sHOcfTqSJruPi1C/s1t07dZg2XGxxGHLNhCzZswYYNW7BhCzZs2IINW7BhCzZs2IINW7BhwxZs2IINW7BhwxZs2IING7ZgwxZs2IING7ZgwxZs2LAFG7Zgw4Yt2LAFG7Zgw4Yt2LAFGzZswYYt2LAFGzZswYYt2LBhCzZswYYt2LBhCzZswYYNW7BhCzZs2IINW7BhCzZs2IINW7BhwxZs2IIdvbMdv7vG06lJF+yP3BxGYAs2bGcj8VukmadZb/1dkWaaJh/Li6hO8TaB57YGbSofwWvYjAH7psWiqd6QVWTsyMfsr2kuW9x+3vL2viDrlmmuOtzve/0mwW7RlydfhG36BLv9Cu3zqVjCbgf2kve3qRl5OezjtY6KPXnh+x/sMPIj4POa9oSOhr3YfnLRdlv3PV7YTfSdcBnwCX7uAF0E3apfbD/JWdAnOWsJvRrLp7TM4l6Meu4S6kXgi1C/V/XJk5VRRj1tqq953GV/X89+X/+MuhN+1/TLqIeTMU759BP5quEUZZqp7+WCN2l+7nNjK3zAFb3vt3sJr9X0/l9kM+g7Z1WfMT27az1puQ2uVvu5Q/JjD9mff/Hfq18CDADFyFpnRW9JPwAAAABJRU5ErkJggg==';
|
||||
|
||||
var imageBackSrc = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFsAAACpCAIAAADLDtbcAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIE1hY2ludG9zaCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo3OTFCRTMwQTNDNjMxMUUxQTYyOTk2M0QwMjU4OThGOCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo3OTFCRTMwQjNDNjMxMUUxQTYyOTk2M0QwMjU4OThGOCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjE4OTAwNDZCM0M0RjExRTFBNjI5OTYzRDAyNTg5OEY4IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjE4OTAwNDZDM0M0RjExRTFBNjI5OTYzRDAyNTg5OEY4Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+zWf2VgAABt9JREFUeNrsnU1P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';
|
||||
|
||||
var id = (+new Date).toString(32),
|
||||
body = document.documentElement, // yep - cheatin' Yud'up! :)
|
||||
height = 320;
|
||||
|
||||
// if the url hash doesn't contain tiltremote (our key) then fireup the popup, else we are the popup
|
||||
if (window.location.hash.indexOf('tiltremote') === -1) {
|
||||
initServer();
|
||||
} else {
|
||||
initRemote();
|
||||
}
|
||||
|
||||
function initServer() {
|
||||
// old way didn't work. Shame, but I like the new way too :)
|
||||
// var remote = window.open('data:text/html,<script src="' + src + '?tiltremote"></script>', 'Tilt', 'width=300,height=' + height);
|
||||
|
||||
var remote = window.open(window.location.toString() + '#tiltremote', 'Tilt', 'width=300,height=' + height);
|
||||
if (!remote) {
|
||||
alert('The remote control for the orientation event uses a popup')
|
||||
}
|
||||
|
||||
// TODO add remote-tilt.com support
|
||||
}
|
||||
|
||||
function initRemote() {
|
||||
var TO_RADIANS = Math.PI / 180;
|
||||
orientation = {
|
||||
alpha: 180,
|
||||
beta: 0,
|
||||
gamma: 0
|
||||
},
|
||||
accelerationIncludingGravity = { x: 0, y: 0, z: -9.81 },
|
||||
guid = (+new Date).toString(32);
|
||||
|
||||
function update(fromInput) {
|
||||
var preview = document.getElementById('preview');
|
||||
preview.style.webkitTransform = 'rotateY('+ gamma.value + 'deg) rotate3d(1,0,0, '+ (beta.value*-1) + 'deg)';
|
||||
preview.parentNode.style.webkitTransform = 'rotate(' + (180-orientation.alpha) + 'deg)';
|
||||
|
||||
if (!fromInput) {
|
||||
for (var key in orientation) {
|
||||
var el = document.getElementById(key);
|
||||
oninput.call(window, { target: el });
|
||||
}
|
||||
}
|
||||
|
||||
fireEvent();
|
||||
}
|
||||
|
||||
function fireDeviceOrienationEvent() {
|
||||
var event = document.createEvent('HTMLEvents');
|
||||
event.initEvent('deviceorientation', true, true);
|
||||
event.eventName = 'deviceorientation';
|
||||
event.alpha = orientation.alpha;
|
||||
event.beta = orientation.beta;
|
||||
event.gamma = orientation.gamma;
|
||||
|
||||
window.opener.dispatchEvent(event);
|
||||
}
|
||||
|
||||
function fireDeviceMotionEvent() {
|
||||
var event = document.createEvent('HTMLEvents');
|
||||
event.initEvent('devicemotion', true, true);
|
||||
event.eventName = 'devicemotion';
|
||||
|
||||
event.accelerationIncludingGravity = {};
|
||||
event.accelerationIncludingGravity.x = accelerationIncludingGravity.x;
|
||||
event.accelerationIncludingGravity.y = accelerationIncludingGravity.y;
|
||||
event.accelerationIncludingGravity.z = accelerationIncludingGravity.z;
|
||||
|
||||
window.opener.dispatchEvent(event);
|
||||
}
|
||||
|
||||
function fireEvent() {
|
||||
if (polyfill.orientation) fireDeviceOrienationEvent();
|
||||
if (polyfill.motion) fireDeviceMotionEvent();
|
||||
}
|
||||
|
||||
// hides the old body - but doesn't prevent the JavaScript from running.
|
||||
// just a clean up thing - lame, but tidier
|
||||
setTimeout(function () {
|
||||
var bodies = document.getElementsByTagName('body'),
|
||||
body = bodies[1];
|
||||
if (bodies.length == 2) {
|
||||
if (body.id == guid) body = bodies[0];
|
||||
}
|
||||
document.documentElement.removeChild(body);
|
||||
});
|
||||
|
||||
body.innerHTML = ['<head><title>Motion Emulator</title>',
|
||||
'<style>',
|
||||
'html { height: ' + height + 'px; }',
|
||||
'body { margin: 10px; font-family: sans-serif; overflow: hidden; }',
|
||||
'#pov { height: 170px; position: relative; -webkit-perspective: 500; perspective: 500; cursor: move; }',
|
||||
'#controls { position: relative; z-index: 1; }',
|
||||
'#preview { display: block; margin: 20px auto; max-width: 100%; width: 100px; height: 170px; }',
|
||||
'#preview div { width: 100%; height: 170px; position: absolute; top: 0; left: 0; -webkit-backface-visibility: hidden; }',
|
||||
'#front { background: url(' + imageSrc + ') no-repeat center; }',
|
||||
'#back { background: url(' + imageBackSrc + ') no-repeat center; -webkit-transform: rotateY(180deg); }',
|
||||
'label { display: block; clear: both; }',
|
||||
'label input[type=range] { display:inline-block; float: right; }',
|
||||
'#buttons { margin-top: 2px; }',
|
||||
'#south { position: absolute; bottom: 0; width: 100%; left: 0; text-align: center; color: #aaa; }',
|
||||
'</style>',
|
||||
'</head>',
|
||||
'<body id="' + guid + '">',
|
||||
'<div id=controls>',
|
||||
'<label for=gamma>Left - Right <input min=-180 max=180 id=gamma value=0 type=range step=0.001> <output id=og>0</output></label>',
|
||||
'<label for=beta>Back - Front <input min=-180 max=180 id=beta value=0 type=range step=0.001> <output id=ob>0</output></label>',
|
||||
'<label for=alpha>Rotate <input min=0 max=360 id=alpha value=180 type=range step=0.001> <output id=oa>180</output></label>',
|
||||
'<label for=wobble>Emulate slight shake<input type=checkbox id=wobble></label>',
|
||||
'<div id=buttons><button id=flat>Flat on it\'s back</button> ',
|
||||
'</div>',
|
||||
'</div>', // end of controls
|
||||
'<div id=pov>',
|
||||
'<div id=preview>',
|
||||
'<div id=front></div>',
|
||||
'<div id=back></div>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<span id=south>south</span>',
|
||||
'</body>'
|
||||
].join('');
|
||||
|
||||
function oninput(event) {
|
||||
var target = event.target;
|
||||
if (target.nodeName == 'INPUT') {
|
||||
|
||||
var value = target.value * 1;
|
||||
|
||||
if (target.id == 'beta') {
|
||||
// parseFloat + toFixed avoids the massive 0.00000000 and infinitely small numbers
|
||||
accelerationIncludingGravity.z = parseFloat( (Math.sin( (TO_RADIANS * (value - 90))) * 9.81).toFixed(10) );
|
||||
accelerationIncludingGravity.y = parseFloat((Math.sin( (TO_RADIANS * (value - 180))) * 9.81).toFixed(10));
|
||||
value = parseFloat((Math.sin(value * TO_RADIANS) * 90).toFixed(10));
|
||||
} else if (target.id == 'gamma') {
|
||||
accelerationIncludingGravity.x = parseFloat( (Math.sin( (TO_RADIANS * (value - 180))) * -9.81).toFixed(10) );
|
||||
}
|
||||
|
||||
document.getElementById('o' + target.id.substring(0, 1)).value = parseFloat(value.toFixed(2));
|
||||
|
||||
orientation[target.id] = value;
|
||||
|
||||
if (this !== window) update(true); // i.e. if not called manually
|
||||
}
|
||||
}
|
||||
|
||||
body.addEventListener('input', oninput, false);
|
||||
|
||||
var down = false,
|
||||
last = { x: null, y: null },
|
||||
pov = document.getElementById('pov'),
|
||||
alpha = document.getElementById('alpha'),
|
||||
beta = document.getElementById('beta'),
|
||||
gamma = document.getElementById('gamma');
|
||||
|
||||
pov.addEventListener('mousedown', function (event) {
|
||||
down = true;
|
||||
last.x = event.pageX;
|
||||
last.y = event.pageY;
|
||||
event.preventDefault();
|
||||
}, false);
|
||||
|
||||
body.addEventListener('mousemove', function (event) {
|
||||
if (down) {
|
||||
var dx = (last.x - event.pageX)// * 0.1,
|
||||
dy = (last.y - event.pageY); // * 0.1;
|
||||
last.x = event.pageX;
|
||||
last.y = event.pageY;
|
||||
gamma.value -= dx;
|
||||
beta.value -= dy;
|
||||
update();
|
||||
}
|
||||
}, false);
|
||||
|
||||
body.addEventListener('mouseup', function (event) {
|
||||
down = false;
|
||||
}, false);
|
||||
|
||||
body.addEventListener('click', function (event) {
|
||||
var target = event.target;
|
||||
if (target.nodeName == 'BUTTON') {
|
||||
if (target.id == 'flat') {
|
||||
alpha.value = 180;
|
||||
beta.value = 0;
|
||||
gamma.value = 0;
|
||||
|
||||
}
|
||||
update();
|
||||
} else if (target.id == 'wobble') {
|
||||
if (target.checked) startShake();
|
||||
else stopShake();
|
||||
}
|
||||
}, false);
|
||||
|
||||
function startShake() {
|
||||
shake = setInterval(function () {
|
||||
alpha.value = parseFloat(alpha.value) + (Math.random() * (Math.random() < 0.5 ? 1 : -1) * 0.05);
|
||||
beta.value = parseFloat(beta.value) + (Math.random() * (Math.random() < 0.5 ? 1 : -1) * 0.05);
|
||||
gamma.value = parseFloat(gamma.value) + (Math.random() * (Math.random() < 0.5 ? 1 : -1) * 0.05);
|
||||
update();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function stopShake() {
|
||||
clearInterval(shake);
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
8
modules/html5-polyfills/index.js
Normal file
8
modules/html5-polyfills/index.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
require( "./classList.js" );
|
||||
require( "./dataset.js" );
|
||||
require( "./EventSource.js" );
|
||||
require( "./input-target.js" );
|
||||
require( "./offline-events.js" );
|
||||
require( "./range.js" );
|
||||
require( "./sessionStorage.js" );
|
||||
require( "./Storage.js" );
|
||||
42
modules/html5-polyfills/input-target.js
Normal file
42
modules/html5-polyfills/input-target.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
(function () {
|
||||
|
||||
// setup for detection
|
||||
var form = document.createElement('form'),
|
||||
input = document.createElement('input'),
|
||||
body = document.body,
|
||||
id = 'f' + +new Date,
|
||||
inputTargetSupported = false;
|
||||
|
||||
// insert into DOM, work out if it's supported
|
||||
form.setAttribute('id', id);
|
||||
input.setAttribute('form', id);
|
||||
body.appendChild(form);
|
||||
body.appendChild(input);
|
||||
|
||||
inputTargetSupported = input.form !== null;
|
||||
body.removeChild(form);
|
||||
body.removeChild(input);
|
||||
|
||||
// if not, hook click handlers to all existing submit elements
|
||||
function click(event) {
|
||||
event = event || window.event;
|
||||
|
||||
// http://www.quirksmode.org/js/events_properties.html#target
|
||||
var target = event.target || event.srcElement;
|
||||
if (target.nodeType === 3) target = target.parentNode;
|
||||
|
||||
if (target.nodeName === 'INPUT' && target.type === 'submit' && target.form === null) {
|
||||
form = document.getElementById(target.getAttribute('form'));
|
||||
var clone = target.cloneNode(true);
|
||||
clone.style.display = 'none';
|
||||
form.appendChild(clone);
|
||||
clone.click(); // doing this because form.submit won't fire handles the way I want
|
||||
form.removeChild(clone);
|
||||
}
|
||||
}
|
||||
|
||||
if (!inputTargetSupported) {
|
||||
body.addEventListener ? body.addEventListener('click', click, false) : body.attachEvent('onclick', click);
|
||||
}
|
||||
|
||||
})();
|
||||
47
modules/html5-polyfills/offline-events.js
Normal file
47
modules/html5-polyfills/offline-events.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// Working demo: http://jsbin.com/ozusa6/2/
|
||||
(function () {
|
||||
|
||||
function triggerEvent(type) {
|
||||
var event = document.createEvent('HTMLEvents');
|
||||
event.initEvent(type, true, true);
|
||||
event.eventName = type;
|
||||
(document.body || window).dispatchEvent(event);
|
||||
}
|
||||
|
||||
function testConnection() {
|
||||
// make sync-ajax request
|
||||
var xhr = new XMLHttpRequest();
|
||||
// phone home
|
||||
xhr.open('HEAD', '/', false); // async=false
|
||||
try {
|
||||
xhr.send();
|
||||
onLine = true;
|
||||
} catch (e) {
|
||||
// throws NETWORK_ERR when disconnected
|
||||
onLine = false;
|
||||
}
|
||||
|
||||
return onLine;
|
||||
}
|
||||
|
||||
var onLine = true,
|
||||
lastOnLineStatus = true;
|
||||
|
||||
// note: this doesn't allow us to define a getter in Safari
|
||||
navigator.__defineGetter__("onLine", testConnection);
|
||||
testConnection();
|
||||
|
||||
if (onLine === false) {
|
||||
lastOnLineStatus = false;
|
||||
// trigger offline event
|
||||
triggerEvent('offline');
|
||||
}
|
||||
|
||||
setInterval(function () {
|
||||
testConnection();
|
||||
if (onLine !== lastOnLineStatus) {
|
||||
triggerEvent(onLine ? 'online' : 'offline');
|
||||
lastOnLineStatus = onLine;
|
||||
}
|
||||
}, 5000); // 5 seconds, made up - can't find docs to suggest interval time
|
||||
})();
|
||||
94
modules/html5-polyfills/range.js
Normal file
94
modules/html5-polyfills/range.js
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* This was from a proposal that James Edwards / Brothercake had during
|
||||
* 2011 Highland Fling - to use select elements as a starting point for
|
||||
* the range element - so it's a pretty darn good fit, I put this together
|
||||
* during his Q&A. In the end I needed to lift the detection code from
|
||||
* Modernizr - which credit really goes to @miketaylr.
|
||||
* My code starts from "if (bool) {"
|
||||
*
|
||||
* This code is looking for <select type="range"> and will progressively
|
||||
* enhance to a input[type=range] copying much of the attributes across.
|
||||
*/
|
||||
!function () {
|
||||
var rangeTest = document.createElement('input'),
|
||||
smile = ':)';
|
||||
rangeTest.setAttribute('type', 'range');
|
||||
|
||||
var bool = rangeTest.type !== 'text';
|
||||
if (bool) {
|
||||
rangeTest.style.cssText = 'position:absolute;visibility:hidden;';
|
||||
rangeTest.value = smile;
|
||||
if (rangeTest.style.WebkitAppearance !== undefined ) {
|
||||
|
||||
document.body.appendChild(rangeTest);
|
||||
defaultView = document.defaultView;
|
||||
|
||||
// Safari 2-4 allows the smiley as a value, despite making a slider
|
||||
bool = defaultView.getComputedStyle &&
|
||||
defaultView.getComputedStyle(rangeTest, null).WebkitAppearance !== 'textfield' &&
|
||||
// Mobile android web browser has false positive, so must
|
||||
// check the height to see if the widget is actually there.
|
||||
(rangeTest.offsetHeight !== 0);
|
||||
|
||||
document.body.removeChild(rangeTest);
|
||||
}
|
||||
} else {
|
||||
bool = rangeTest.value == smile;
|
||||
}
|
||||
|
||||
// if the input[range] is natively supported, then upgrade the <select type="range">
|
||||
// into a range element.
|
||||
if (bool) {
|
||||
function firstChild(el, nodeName) {
|
||||
nodeName = nodeName.toUpperCase();
|
||||
if (el.firstChild.nodeName === nodeName) {
|
||||
return el.firstChild;
|
||||
} else {
|
||||
return el.firstChild.nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
function lastChild(el, nodeName) {
|
||||
nodeName = nodeName.toUpperCase();
|
||||
if (el.lastChild.nodeName === nodeName) {
|
||||
return el.lastChild;
|
||||
} else {
|
||||
return el.lastChild.previousSibling;
|
||||
}
|
||||
}
|
||||
|
||||
var selects = document.getElementsByTagName('select'),
|
||||
i = 0;
|
||||
|
||||
for (; i < selects.length; i++) {
|
||||
if (selects[i].getAttribute('data-type') == 'range') (function (select) {
|
||||
var range = document.createElement('input'),
|
||||
parent = select.parentNode;
|
||||
|
||||
range.setAttribute('type', 'range');
|
||||
// works with the select element removed from the DOM
|
||||
select = parent.replaceChild(range, select);
|
||||
range.autofocus = select.autofocus;
|
||||
range.disabled = select.disabled;
|
||||
range.autocomplete = select.autocomplete; // eh? how would this even work?
|
||||
range.className = select.className;
|
||||
range.id = select.id;
|
||||
range.style = select.style;
|
||||
range.tabindex = select.tabindex;
|
||||
range.title = select.title;
|
||||
range.min = firstChild(select, 'option').value;
|
||||
range.max = lastChild(select, 'option').value;
|
||||
range.value = select.value;
|
||||
range.name = select.name;
|
||||
// Add step support
|
||||
if ( select.getAttribute('data-type-range-step') ) {
|
||||
range.step = select.getAttribute('data-type-range-step');
|
||||
}
|
||||
// yeah, this is filth, but it's because getElementsByTagName is
|
||||
// a live DOM collection, so when we removed the select element
|
||||
// the selects object reduced in length. Freaky, eh?
|
||||
i--;
|
||||
})(selects[i]);
|
||||
}
|
||||
}
|
||||
}();
|
||||
23
modules/html5-polyfills/sessionStorage.js
Normal file
23
modules/html5-polyfills/sessionStorage.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
if (!sessionStorage && JSON) {
|
||||
sessionStorage = (function () {
|
||||
var data = window.name ? JSON.parse(window.name) : {};
|
||||
|
||||
return {
|
||||
clear: function () {
|
||||
data = {};
|
||||
window.name = '';
|
||||
},
|
||||
getItem: function (key) {
|
||||
return data[key] === undefined ? null : data[key];
|
||||
},
|
||||
removeItem: function (key) {
|
||||
delete data[key];
|
||||
window.name = JSON.stringify(data);
|
||||
},
|
||||
setItem: function (key, value) {
|
||||
data[key] = value;
|
||||
window.name = JSON.stringify(data);
|
||||
}
|
||||
};
|
||||
})();
|
||||
}
|
||||
22
modules/html5-polyfills/tests/eventsource.html
Normal file
22
modules/html5-polyfills/tests/eventsource.html
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset=utf-8 />
|
||||
<title>event source test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="../EventSource.js"></script>
|
||||
<script>
|
||||
var es = new EventSource('/sse/');
|
||||
es.onmessage = function (event) {
|
||||
console.log('msg: ' + event.data);
|
||||
};
|
||||
|
||||
es.onopen = function () {
|
||||
console.log('connected');
|
||||
}
|
||||
|
||||
console.log(es);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
35
modules/html5-polyfills/tests/offline-events.html
Normal file
35
modules/html5-polyfills/tests/offline-events.html
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Online and offline event tests</title>
|
||||
<style>
|
||||
* { font-family: sans-serif; }
|
||||
body { width: 600px; margin: 40px auto; }
|
||||
#status { padding: 10px; text-align: center; }
|
||||
#status.online { background: #0c0; }
|
||||
#status.offline { background: #c00; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p><strong>Directions:</strong> disconnect the internet connection from your machine and watch the status switch from online to offline (and back again if you want to see the online event fire).</p>
|
||||
<p>Note that this polyfill <em>phones home</em> so it will also fire the offline event if the server this script is hosted on, goes down (feature or bug? who knows!).</p>
|
||||
<p class="online" id="status">ONLINE</p>
|
||||
<script src="../offline-events.js"></script>
|
||||
<script>
|
||||
(function () {
|
||||
var status = document.getElementById('status');
|
||||
status.className = navigator.onLine ? 'online' : 'offline';
|
||||
window.addEventListener('online', function () {
|
||||
status.className = 'online';
|
||||
status.innerHTML = 'ONLINE';
|
||||
}, false);
|
||||
|
||||
window.addEventListener('offline', function () {
|
||||
status.className = 'offline';
|
||||
status.innerHTML = 'OFFLINE';
|
||||
}, false);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
44
modules/html5-polyfills/tests/range.html
Normal file
44
modules/html5-polyfills/tests/range.html
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>range polyfill...</title>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<select class="foo" id="first" title="1-5 please" data-type="range">
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option selected value="5">5</option>
|
||||
</select>
|
||||
</div>
|
||||
<br>
|
||||
<select>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
</select>
|
||||
<br>
|
||||
<select autofocus data-type="range">
|
||||
<option value="1">3</option>
|
||||
<option selected value="4">4</option>
|
||||
<option value="50">5</option>
|
||||
</select>
|
||||
<br>
|
||||
<p>Last two examples are as the previous, but add <code>data-type-range-step="5"</code>:</p>
|
||||
<select data-type="range" data-type-range-step="5">
|
||||
<option value="1">3</option>
|
||||
<option selected value="4">4</option>
|
||||
<option value="50">5</option>
|
||||
</select>
|
||||
<br>
|
||||
<p>This one has the last value set to 51, instead of 50:</p>
|
||||
<select data-type="range" data-type-range-step="5">
|
||||
<option value="1">3</option>
|
||||
<option selected value="4">4</option>
|
||||
<option value="51">5</option>
|
||||
</select>
|
||||
<script src="../range.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue