Zach Wise
13 years ago
4 changed files with 0 additions and 1329 deletions
@ -1,463 +0,0 @@ |
|||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
|
||||||
/* AES implementation in JavaScript (c) Chris Veness 2005-2011 */ |
|
||||||
/* - see http://csrc.nist.gov/publications/PubsFIPS.html#197 */ |
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
|
||||||
|
|
||||||
var Aes = {}; // Aes namespace
|
|
||||||
|
|
||||||
/** |
|
||||||
* AES Cipher function: encrypt 'input' state with Rijndael algorithm |
|
||||||
* applies Nr rounds (10/12/14) using key schedule w for 'add round key' stage |
|
||||||
* |
|
||||||
* @param {Number[]} input 16-byte (128-bit) input state array |
|
||||||
* @param {Number[][]} w Key schedule as 2D byte-array (Nr+1 x Nb bytes) |
|
||||||
* @returns {Number[]} Encrypted output state array |
|
||||||
*/ |
|
||||||
Aes.cipher = function(input, w) { // main Cipher function [§5.1]
|
|
||||||
var Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
|
|
||||||
var Nr = w.length/Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys
|
|
||||||
|
|
||||||
var state = [[],[],[],[]]; // initialise 4xNb byte-array 'state' with input [§3.4]
|
|
||||||
for (var i=0; i<4*Nb; i++) state[i%4][Math.floor(i/4)] = input[i]; |
|
||||||
|
|
||||||
state = Aes.addRoundKey(state, w, 0, Nb); |
|
||||||
|
|
||||||
for (var round=1; round<Nr; round++) { |
|
||||||
state = Aes.subBytes(state, Nb); |
|
||||||
state = Aes.shiftRows(state, Nb); |
|
||||||
state = Aes.mixColumns(state, Nb); |
|
||||||
state = Aes.addRoundKey(state, w, round, Nb); |
|
||||||
} |
|
||||||
|
|
||||||
state = Aes.subBytes(state, Nb); |
|
||||||
state = Aes.shiftRows(state, Nb); |
|
||||||
state = Aes.addRoundKey(state, w, Nr, Nb); |
|
||||||
|
|
||||||
var output = new Array(4*Nb); // convert state to 1-d array before returning [§3.4]
|
|
||||||
for (var i=0; i<4*Nb; i++) output[i] = state[i%4][Math.floor(i/4)]; |
|
||||||
return output; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Perform Key Expansion to generate a Key Schedule |
|
||||||
* |
|
||||||
* @param {Number[]} key Key as 16/24/32-byte array |
|
||||||
* @returns {Number[][]} Expanded key schedule as 2D byte-array (Nr+1 x Nb bytes) |
|
||||||
*/ |
|
||||||
Aes.keyExpansion = function(key) { // generate Key Schedule (byte-array Nr+1 x Nb) from Key [§5.2]
|
|
||||||
var Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
|
|
||||||
var Nk = key.length/4 // key length (in words): 4/6/8 for 128/192/256-bit keys
|
|
||||||
var Nr = Nk + 6; // no of rounds: 10/12/14 for 128/192/256-bit keys
|
|
||||||
|
|
||||||
var w = new Array(Nb*(Nr+1)); |
|
||||||
var temp = new Array(4); |
|
||||||
|
|
||||||
for (var i=0; i<Nk; i++) { |
|
||||||
var r = [key[4*i], key[4*i+1], key[4*i+2], key[4*i+3]]; |
|
||||||
w[i] = r; |
|
||||||
} |
|
||||||
|
|
||||||
for (var i=Nk; i<(Nb*(Nr+1)); i++) { |
|
||||||
w[i] = new Array(4); |
|
||||||
for (var t=0; t<4; t++) temp[t] = w[i-1][t]; |
|
||||||
if (i % Nk == 0) { |
|
||||||
temp = Aes.subWord(Aes.rotWord(temp)); |
|
||||||
for (var t=0; t<4; t++) temp[t] ^= Aes.rCon[i/Nk][t]; |
|
||||||
} else if (Nk > 6 && i%Nk == 4) { |
|
||||||
temp = Aes.subWord(temp); |
|
||||||
} |
|
||||||
for (var t=0; t<4; t++) w[i][t] = w[i-Nk][t] ^ temp[t]; |
|
||||||
} |
|
||||||
|
|
||||||
return w; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
* ---- remaining routines are private, not called externally ---- |
|
||||||
*/ |
|
||||||
|
|
||||||
Aes.subBytes = function(s, Nb) { // apply SBox to state S [§5.1.1]
|
|
||||||
for (var r=0; r<4; r++) { |
|
||||||
for (var c=0; c<Nb; c++) s[r][c] = Aes.sBox[s[r][c]]; |
|
||||||
} |
|
||||||
return s; |
|
||||||
} |
|
||||||
|
|
||||||
Aes.shiftRows = function(s, Nb) { // shift row r of state S left by r bytes [§5.1.2]
|
|
||||||
var t = new Array(4); |
|
||||||
for (var r=1; r<4; r++) { |
|
||||||
for (var c=0; c<4; c++) t[c] = s[r][(c+r)%Nb]; // shift into temp copy
|
|
||||||
for (var c=0; c<4; c++) s[r][c] = t[c]; // and copy back
|
|
||||||
} // note that this will work for Nb=4,5,6, but not 7,8 (always 4 for AES):
|
|
||||||
return s; // see asmaes.sourceforge.net/rijndael/rijndaelImplementation.pdf
|
|
||||||
} |
|
||||||
|
|
||||||
Aes.mixColumns = function(s, Nb) { // combine bytes of each col of state S [§5.1.3]
|
|
||||||
for (var c=0; c<4; c++) { |
|
||||||
var a = new Array(4); // 'a' is a copy of the current column from 's'
|
|
||||||
var b = new Array(4); // 'b' is a•{02} in GF(2^8)
|
|
||||||
for (var i=0; i<4; i++) { |
|
||||||
a[i] = s[i][c]; |
|
||||||
b[i] = s[i][c]&0x80 ? s[i][c]<<1 ^ 0x011b : s[i][c]<<1; |
|
||||||
|
|
||||||
} |
|
||||||
// a[n] ^ b[n] is a•{03} in GF(2^8)
|
|
||||||
s[0][c] = b[0] ^ a[1] ^ b[1] ^ a[2] ^ a[3]; // 2*a0 + 3*a1 + a2 + a3
|
|
||||||
s[1][c] = a[0] ^ b[1] ^ a[2] ^ b[2] ^ a[3]; // a0 * 2*a1 + 3*a2 + a3
|
|
||||||
s[2][c] = a[0] ^ a[1] ^ b[2] ^ a[3] ^ b[3]; // a0 + a1 + 2*a2 + 3*a3
|
|
||||||
s[3][c] = a[0] ^ b[0] ^ a[1] ^ a[2] ^ b[3]; // 3*a0 + a1 + a2 + 2*a3
|
|
||||||
} |
|
||||||
return s; |
|
||||||
} |
|
||||||
|
|
||||||
Aes.addRoundKey = function(state, w, rnd, Nb) { // xor Round Key into state S [§5.1.4]
|
|
||||||
for (var r=0; r<4; r++) { |
|
||||||
for (var c=0; c<Nb; c++) state[r][c] ^= w[rnd*4+c][r]; |
|
||||||
} |
|
||||||
return state; |
|
||||||
} |
|
||||||
|
|
||||||
Aes.subWord = function(w) { // apply SBox to 4-byte word w
|
|
||||||
for (var i=0; i<4; i++) w[i] = Aes.sBox[w[i]]; |
|
||||||
return w; |
|
||||||
} |
|
||||||
|
|
||||||
Aes.rotWord = function(w) { // rotate 4-byte word w left by one byte
|
|
||||||
var tmp = w[0]; |
|
||||||
for (var i=0; i<3; i++) w[i] = w[i+1]; |
|
||||||
w[3] = tmp; |
|
||||||
return w; |
|
||||||
} |
|
||||||
|
|
||||||
// sBox is pre-computed multiplicative inverse in GF(2^8) used in subBytes and keyExpansion [§5.1.1]
|
|
||||||
Aes.sBox = [0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, |
|
||||||
0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, |
|
||||||
0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, |
|
||||||
0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, |
|
||||||
0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, |
|
||||||
0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, |
|
||||||
0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, |
|
||||||
0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, |
|
||||||
0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, |
|
||||||
0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, |
|
||||||
0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, |
|
||||||
0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, |
|
||||||
0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, |
|
||||||
0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, |
|
||||||
0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, |
|
||||||
0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16]; |
|
||||||
|
|
||||||
// rCon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [§5.2]
|
|
||||||
Aes.rCon = [ [0x00, 0x00, 0x00, 0x00], |
|
||||||
[0x01, 0x00, 0x00, 0x00], |
|
||||||
[0x02, 0x00, 0x00, 0x00], |
|
||||||
[0x04, 0x00, 0x00, 0x00], |
|
||||||
[0x08, 0x00, 0x00, 0x00], |
|
||||||
[0x10, 0x00, 0x00, 0x00], |
|
||||||
[0x20, 0x00, 0x00, 0x00], |
|
||||||
[0x40, 0x00, 0x00, 0x00], |
|
||||||
[0x80, 0x00, 0x00, 0x00], |
|
||||||
[0x1b, 0x00, 0x00, 0x00], |
|
||||||
[0x36, 0x00, 0x00, 0x00] ];
|
|
||||||
|
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
|
||||||
/* AES Counter-mode implementation in JavaScript (c) Chris Veness 2005-2011 */ |
|
||||||
/* - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf */ |
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
|
||||||
|
|
||||||
Aes.Ctr = {}; // Aes.Ctr namespace: a subclass or extension of Aes
|
|
||||||
|
|
||||||
/** |
|
||||||
* Encrypt a text using AES encryption in Counter mode of operation |
|
||||||
* |
|
||||||
* Unicode multi-byte character safe |
|
||||||
* |
|
||||||
* @param {String} plaintext Source text to be encrypted |
|
||||||
* @param {String} password The password to use to generate a key |
|
||||||
* @param {Number} nBits Number of bits to be used in the key (128, 192, or 256) |
|
||||||
* @returns {string} Encrypted text |
|
||||||
*/ |
|
||||||
Aes.Ctr.encrypt = function(plaintext, password, nBits) { |
|
||||||
var blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
|
|
||||||
if (!(nBits==128 || nBits==192 || nBits==256)) return ''; // standard allows 128/192/256 bit keys
|
|
||||||
plaintext = Utf8.encode(plaintext); |
|
||||||
password = Utf8.encode(password); |
|
||||||
//var t = new Date(); // timer
|
|
||||||
|
|
||||||
// use AES itself to encrypt password to get cipher key (using plain password as source for key
|
|
||||||
// expansion) - gives us well encrypted key (though hashed key might be preferred for prod'n use)
|
|
||||||
var nBytes = nBits/8; // no bytes in key (16/24/32)
|
|
||||||
var pwBytes = new Array(nBytes); |
|
||||||
for (var i=0; i<nBytes; i++) { // use 1st 16/24/32 chars of password for key
|
|
||||||
pwBytes[i] = isNaN(password.charCodeAt(i)) ? 0 : password.charCodeAt(i); |
|
||||||
} |
|
||||||
var key = Aes.cipher(pwBytes, Aes.keyExpansion(pwBytes)); // gives us 16-byte key
|
|
||||||
key = key.concat(key.slice(0, nBytes-16)); // expand key to 16/24/32 bytes long
|
|
||||||
|
|
||||||
// initialise 1st 8 bytes of counter block with nonce (NIST SP800-38A §B.2): [0-1] = millisec,
|
|
||||||
// [2-3] = random, [4-7] = seconds, together giving full sub-millisec uniqueness up to Feb 2106
|
|
||||||
var counterBlock = new Array(blockSize); |
|
||||||
|
|
||||||
var nonce = (new Date()).getTime(); // timestamp: milliseconds since 1-Jan-1970
|
|
||||||
var nonceMs = nonce%1000; |
|
||||||
var nonceSec = Math.floor(nonce/1000); |
|
||||||
var nonceRnd = Math.floor(Math.random()*0xffff); |
|
||||||
|
|
||||||
for (var i=0; i<2; i++) counterBlock[i] = (nonceMs >>> i*8) & 0xff; |
|
||||||
for (var i=0; i<2; i++) counterBlock[i+2] = (nonceRnd >>> i*8) & 0xff; |
|
||||||
for (var i=0; i<4; i++) counterBlock[i+4] = (nonceSec >>> i*8) & 0xff; |
|
||||||
|
|
||||||
// and convert it to a string to go on the front of the ciphertext
|
|
||||||
var ctrTxt = ''; |
|
||||||
for (var i=0; i<8; i++) ctrTxt += String.fromCharCode(counterBlock[i]); |
|
||||||
|
|
||||||
// generate key schedule - an expansion of the key into distinct Key Rounds for each round
|
|
||||||
var keySchedule = Aes.keyExpansion(key); |
|
||||||
|
|
||||||
var blockCount = Math.ceil(plaintext.length/blockSize); |
|
||||||
var ciphertxt = new Array(blockCount); // ciphertext as array of strings
|
|
||||||
|
|
||||||
for (var b=0; b<blockCount; b++) { |
|
||||||
// set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
|
|
||||||
// done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB)
|
|
||||||
for (var c=0; c<4; c++) counterBlock[15-c] = (b >>> c*8) & 0xff; |
|
||||||
for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8) |
|
||||||
|
|
||||||
var cipherCntr = Aes.cipher(counterBlock, keySchedule); // -- encrypt counter block --
|
|
||||||
|
|
||||||
// block size is reduced on final block
|
|
||||||
var blockLength = b<blockCount-1 ? blockSize : (plaintext.length-1)%blockSize+1; |
|
||||||
var cipherChar = new Array(blockLength); |
|
||||||
|
|
||||||
for (var i=0; i<blockLength; i++) { // -- xor plaintext with ciphered counter char-by-char --
|
|
||||||
cipherChar[i] = cipherCntr[i] ^ plaintext.charCodeAt(b*blockSize+i); |
|
||||||
cipherChar[i] = String.fromCharCode(cipherChar[i]); |
|
||||||
} |
|
||||||
ciphertxt[b] = cipherChar.join('');
|
|
||||||
} |
|
||||||
|
|
||||||
// Array.join is more efficient than repeated string concatenation in IE
|
|
||||||
var ciphertext = ctrTxt + ciphertxt.join(''); |
|
||||||
ciphertext = Base64.encode(ciphertext); // encode in base64
|
|
||||||
|
|
||||||
//alert((new Date()) - t);
|
|
||||||
return ciphertext; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Decrypt a text encrypted by AES in counter mode of operation |
|
||||||
* |
|
||||||
* @param {String} ciphertext Source text to be encrypted |
|
||||||
* @param {String} password The password to use to generate a key |
|
||||||
* @param {Number} nBits Number of bits to be used in the key (128, 192, or 256) |
|
||||||
* @returns {String} Decrypted text |
|
||||||
*/ |
|
||||||
Aes.Ctr.decrypt = function(ciphertext, password, nBits) { |
|
||||||
var blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
|
|
||||||
if (!(nBits==128 || nBits==192 || nBits==256)) return ''; // standard allows 128/192/256 bit keys
|
|
||||||
ciphertext = Base64.decode(ciphertext); |
|
||||||
password = Utf8.encode(password); |
|
||||||
//var t = new Date(); // timer
|
|
||||||
|
|
||||||
// use AES to encrypt password (mirroring encrypt routine)
|
|
||||||
var nBytes = nBits/8; // no bytes in key
|
|
||||||
var pwBytes = new Array(nBytes); |
|
||||||
for (var i=0; i<nBytes; i++) { |
|
||||||
pwBytes[i] = isNaN(password.charCodeAt(i)) ? 0 : password.charCodeAt(i); |
|
||||||
} |
|
||||||
var key = Aes.cipher(pwBytes, Aes.keyExpansion(pwBytes)); |
|
||||||
key = key.concat(key.slice(0, nBytes-16)); // expand key to 16/24/32 bytes long
|
|
||||||
|
|
||||||
// recover nonce from 1st 8 bytes of ciphertext
|
|
||||||
var counterBlock = new Array(8); |
|
||||||
ctrTxt = ciphertext.slice(0, 8); |
|
||||||
for (var i=0; i<8; i++) counterBlock[i] = ctrTxt.charCodeAt(i); |
|
||||||
|
|
||||||
// generate key schedule
|
|
||||||
var keySchedule = Aes.keyExpansion(key); |
|
||||||
|
|
||||||
// separate ciphertext into blocks (skipping past initial 8 bytes)
|
|
||||||
var nBlocks = Math.ceil((ciphertext.length-8) / blockSize); |
|
||||||
var ct = new Array(nBlocks); |
|
||||||
for (var b=0; b<nBlocks; b++) ct[b] = ciphertext.slice(8+b*blockSize, 8+b*blockSize+blockSize); |
|
||||||
ciphertext = ct; // ciphertext is now array of block-length strings
|
|
||||||
|
|
||||||
// plaintext will get generated block-by-block into array of block-length strings
|
|
||||||
var plaintxt = new Array(ciphertext.length); |
|
||||||
|
|
||||||
for (var b=0; b<nBlocks; b++) { |
|
||||||
// set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
|
|
||||||
for (var c=0; c<4; c++) counterBlock[15-c] = ((b) >>> c*8) & 0xff; |
|
||||||
for (var c=0; c<4; c++) counterBlock[15-c-4] = (((b+1)/0x100000000-1) >>> c*8) & 0xff; |
|
||||||
|
|
||||||
var cipherCntr = Aes.cipher(counterBlock, keySchedule); // encrypt counter block
|
|
||||||
|
|
||||||
var plaintxtByte = new Array(ciphertext[b].length); |
|
||||||
for (var i=0; i<ciphertext[b].length; i++) { |
|
||||||
// -- xor plaintxt with ciphered counter byte-by-byte --
|
|
||||||
plaintxtByte[i] = cipherCntr[i] ^ ciphertext[b].charCodeAt(i); |
|
||||||
plaintxtByte[i] = String.fromCharCode(plaintxtByte[i]); |
|
||||||
} |
|
||||||
plaintxt[b] = plaintxtByte.join(''); |
|
||||||
} |
|
||||||
|
|
||||||
// join array of blocks into single plaintext string
|
|
||||||
var plaintext = plaintxt.join(''); |
|
||||||
plaintext = Utf8.decode(plaintext); // decode from UTF8 back to Unicode multi-byte chars
|
|
||||||
|
|
||||||
//alert((new Date()) - t);
|
|
||||||
return plaintext; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
|
||||||
/* Base64 class: Base 64 encoding / decoding (c) Chris Veness 2002-2011 */ |
|
||||||
/* note: depends on Utf8 class */ |
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
|
||||||
|
|
||||||
var Base64 = {}; // Base64 namespace
|
|
||||||
|
|
||||||
Base64.code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; |
|
||||||
|
|
||||||
/** |
|
||||||
* Encode string into Base64, as defined by RFC 4648 [http://tools.ietf.org/html/rfc4648]
|
|
||||||
* (instance method extending String object). As per RFC 4648, no newlines are added. |
|
||||||
* |
|
||||||
* @param {String} str The string to be encoded as base-64 |
|
||||||
* @param {Boolean} [utf8encode=false] Flag to indicate whether str is Unicode string to be encoded
|
|
||||||
* to UTF8 before conversion to base64; otherwise string is assumed to be 8-bit characters |
|
||||||
* @returns {String} Base64-encoded string |
|
||||||
*/ |
|
||||||
Base64.encode = function(str, utf8encode) { // http://tools.ietf.org/html/rfc4648
|
|
||||||
utf8encode = (typeof utf8encode == 'undefined') ? false : utf8encode; |
|
||||||
var o1, o2, o3, bits, h1, h2, h3, h4, e=[], pad = '', c, plain, coded; |
|
||||||
var b64 = Base64.code; |
|
||||||
|
|
||||||
plain = utf8encode ? str.encodeUTF8() : str; |
|
||||||
|
|
||||||
c = plain.length % 3; // pad string to length of multiple of 3
|
|
||||||
if (c > 0) { while (c++ < 3) { pad += '='; plain += '\0'; } } |
|
||||||
// note: doing padding here saves us doing special-case packing for trailing 1 or 2 chars
|
|
||||||
|
|
||||||
for (c=0; c<plain.length; c+=3) { // pack three octets into four hexets
|
|
||||||
o1 = plain.charCodeAt(c); |
|
||||||
o2 = plain.charCodeAt(c+1); |
|
||||||
o3 = plain.charCodeAt(c+2); |
|
||||||
|
|
||||||
bits = o1<<16 | o2<<8 | o3; |
|
||||||
|
|
||||||
h1 = bits>>18 & 0x3f; |
|
||||||
h2 = bits>>12 & 0x3f; |
|
||||||
h3 = bits>>6 & 0x3f; |
|
||||||
h4 = bits & 0x3f; |
|
||||||
|
|
||||||
// use hextets to index into code string
|
|
||||||
e[c/3] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); |
|
||||||
} |
|
||||||
coded = e.join(''); // join() is far faster than repeated string concatenation in IE
|
|
||||||
|
|
||||||
// replace 'A's from padded nulls with '='s
|
|
||||||
coded = coded.slice(0, coded.length-pad.length) + pad; |
|
||||||
|
|
||||||
return coded; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Decode string from Base64, as defined by RFC 4648 [http://tools.ietf.org/html/rfc4648]
|
|
||||||
* (instance method extending String object). As per RFC 4648, newlines are not catered for. |
|
||||||
* |
|
||||||
* @param {String} str The string to be decoded from base-64 |
|
||||||
* @param {Boolean} [utf8decode=false] Flag to indicate whether str is Unicode string to be decoded
|
|
||||||
* from UTF8 after conversion from base64 |
|
||||||
* @returns {String} decoded string |
|
||||||
*/ |
|
||||||
Base64.decode = function(str, utf8decode) { |
|
||||||
utf8decode = (typeof utf8decode == 'undefined') ? false : utf8decode; |
|
||||||
var o1, o2, o3, h1, h2, h3, h4, bits, d=[], plain, coded; |
|
||||||
var b64 = Base64.code; |
|
||||||
|
|
||||||
coded = utf8decode ? str.decodeUTF8() : str; |
|
||||||
|
|
||||||
|
|
||||||
for (var c=0; c<coded.length; c+=4) { // unpack four hexets into three octets
|
|
||||||
h1 = b64.indexOf(coded.charAt(c)); |
|
||||||
h2 = b64.indexOf(coded.charAt(c+1)); |
|
||||||
h3 = b64.indexOf(coded.charAt(c+2)); |
|
||||||
h4 = b64.indexOf(coded.charAt(c+3)); |
|
||||||
|
|
||||||
bits = h1<<18 | h2<<12 | h3<<6 | h4; |
|
||||||
|
|
||||||
o1 = bits>>>16 & 0xff; |
|
||||||
o2 = bits>>>8 & 0xff; |
|
||||||
o3 = bits & 0xff; |
|
||||||
|
|
||||||
d[c/4] = String.fromCharCode(o1, o2, o3); |
|
||||||
// check for padding
|
|
||||||
if (h4 == 0x40) d[c/4] = String.fromCharCode(o1, o2); |
|
||||||
if (h3 == 0x40) d[c/4] = String.fromCharCode(o1); |
|
||||||
} |
|
||||||
plain = d.join(''); // join() is far faster than repeated string concatenation in IE
|
|
||||||
|
|
||||||
return utf8decode ? plain.decodeUTF8() : plain;
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
|
||||||
/* Utf8 class: encode / decode between multi-byte Unicode characters and UTF-8 multiple */ |
|
||||||
/* single-byte character encoding (c) Chris Veness 2002-2011 */ |
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
|
||||||
|
|
||||||
var Utf8 = {}; // Utf8 namespace
|
|
||||||
|
|
||||||
/** |
|
||||||
* Encode multi-byte Unicode string into utf-8 multiple single-byte characters
|
|
||||||
* (BMP / basic multilingual plane only) |
|
||||||
* |
|
||||||
* Chars in range U+0080 - U+07FF are encoded in 2 chars, U+0800 - U+FFFF in 3 chars |
|
||||||
* |
|
||||||
* @param {String} strUni Unicode string to be encoded as UTF-8 |
|
||||||
* @returns {String} encoded string |
|
||||||
*/ |
|
||||||
Utf8.encode = function(strUni) { |
|
||||||
// use regular expressions & String.replace callback function for better efficiency
|
|
||||||
// than procedural approaches
|
|
||||||
var strUtf = strUni.replace( |
|
||||||
/[\u0080-\u07ff]/g, // U+0080 - U+07FF => 2 bytes 110yyyyy, 10zzzzzz
|
|
||||||
function(c) {
|
|
||||||
var cc = c.charCodeAt(0); |
|
||||||
return String.fromCharCode(0xc0 | cc>>6, 0x80 | cc&0x3f); } |
|
||||||
); |
|
||||||
strUtf = strUtf.replace( |
|
||||||
/[\u0800-\uffff]/g, // U+0800 - U+FFFF => 3 bytes 1110xxxx, 10yyyyyy, 10zzzzzz
|
|
||||||
function(c) {
|
|
||||||
var cc = c.charCodeAt(0);
|
|
||||||
return String.fromCharCode(0xe0 | cc>>12, 0x80 | cc>>6&0x3F, 0x80 | cc&0x3f); } |
|
||||||
); |
|
||||||
return strUtf; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Decode utf-8 encoded string back into multi-byte Unicode characters |
|
||||||
* |
|
||||||
* @param {String} strUtf UTF-8 string to be decoded back to Unicode |
|
||||||
* @returns {String} decoded string |
|
||||||
*/ |
|
||||||
Utf8.decode = function(strUtf) { |
|
||||||
// note: decode 3-byte chars first as decoded 2-byte strings could appear to be 3-byte char!
|
|
||||||
var strUni = strUtf.replace( |
|
||||||
/[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, // 3-byte chars
|
|
||||||
function(c) { // (note parentheses for precence)
|
|
||||||
var cc = ((c.charCodeAt(0)&0x0f)<<12) | ((c.charCodeAt(1)&0x3f)<<6) | ( c.charCodeAt(2)&0x3f);
|
|
||||||
return String.fromCharCode(cc); } |
|
||||||
); |
|
||||||
strUni = strUni.replace( |
|
||||||
/[\u00c0-\u00df][\u0080-\u00bf]/g, // 2-byte chars
|
|
||||||
function(c) { // (note parentheses for precence)
|
|
||||||
var cc = (c.charCodeAt(0)&0x1f)<<6 | c.charCodeAt(1)&0x3f; |
|
||||||
return String.fromCharCode(cc); } |
|
||||||
); |
|
||||||
return strUni; |
|
||||||
} |
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
|
@ -1,270 +0,0 @@ |
|||||||
/* =========================================================== |
|
||||||
* bootstrap-tooltip.js v2.0.1 |
|
||||||
* http://twitter.github.com/bootstrap/javascript.html#tooltips
|
|
||||||
* Inspired by the original jQuery.tipsy by Jason Frame |
|
||||||
* =========================================================== |
|
||||||
* Copyright 2012 Twitter, Inc. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
* ========================================================== */ |
|
||||||
|
|
||||||
!function( $ ) { |
|
||||||
|
|
||||||
"use strict" |
|
||||||
|
|
||||||
/* TOOLTIP PUBLIC CLASS DEFINITION |
|
||||||
* =============================== */ |
|
||||||
|
|
||||||
var Tooltip = function ( element, options ) { |
|
||||||
this.init('tooltip', element, options) |
|
||||||
} |
|
||||||
|
|
||||||
Tooltip.prototype = { |
|
||||||
|
|
||||||
constructor: Tooltip |
|
||||||
|
|
||||||
, init: function ( type, element, options ) { |
|
||||||
var eventIn |
|
||||||
, eventOut |
|
||||||
|
|
||||||
this.type = type |
|
||||||
this.$element = $(element) |
|
||||||
this.options = this.getOptions(options) |
|
||||||
this.enabled = true |
|
||||||
|
|
||||||
if (this.options.trigger != 'manual') { |
|
||||||
eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus' |
|
||||||
eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur' |
|
||||||
this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this)) |
|
||||||
this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this)) |
|
||||||
} |
|
||||||
|
|
||||||
this.options.selector ? |
|
||||||
(this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : |
|
||||||
this.fixTitle() |
|
||||||
} |
|
||||||
|
|
||||||
, getOptions: function ( options ) { |
|
||||||
options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data()) |
|
||||||
|
|
||||||
if (options.delay && typeof options.delay == 'number') { |
|
||||||
options.delay = { |
|
||||||
show: options.delay |
|
||||||
, hide: options.delay |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return options |
|
||||||
} |
|
||||||
|
|
||||||
, enter: function ( e ) { |
|
||||||
var self = $(e.currentTarget)[this.type](this._options).data(this.type) |
|
||||||
|
|
||||||
if (!self.options.delay || !self.options.delay.show) { |
|
||||||
self.show() |
|
||||||
} else { |
|
||||||
self.hoverState = 'in' |
|
||||||
setTimeout(function() { |
|
||||||
if (self.hoverState == 'in') { |
|
||||||
self.show() |
|
||||||
} |
|
||||||
}, self.options.delay.show) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
, leave: function ( e ) { |
|
||||||
var self = $(e.currentTarget)[this.type](this._options).data(this.type) |
|
||||||
|
|
||||||
if (!self.options.delay || !self.options.delay.hide) { |
|
||||||
self.hide() |
|
||||||
} else { |
|
||||||
self.hoverState = 'out' |
|
||||||
setTimeout(function() { |
|
||||||
if (self.hoverState == 'out') { |
|
||||||
self.hide() |
|
||||||
} |
|
||||||
}, self.options.delay.hide) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
, show: function () { |
|
||||||
var $tip |
|
||||||
, inside |
|
||||||
, pos |
|
||||||
, actualWidth |
|
||||||
, actualHeight |
|
||||||
, placement |
|
||||||
, tp |
|
||||||
|
|
||||||
if (this.hasContent() && this.enabled) { |
|
||||||
$tip = this.tip() |
|
||||||
this.setContent() |
|
||||||
|
|
||||||
if (this.options.animation) { |
|
||||||
$tip.addClass('fade') |
|
||||||
} |
|
||||||
|
|
||||||
placement = typeof this.options.placement == 'function' ? |
|
||||||
this.options.placement.call(this, $tip[0], this.$element[0]) : |
|
||||||
this.options.placement |
|
||||||
|
|
||||||
inside = /in/.test(placement) |
|
||||||
|
|
||||||
$tip |
|
||||||
.remove() |
|
||||||
.css({ top: 0, left: 0, display: 'block' }) |
|
||||||
.appendTo(inside ? this.$element : document.body) |
|
||||||
|
|
||||||
pos = this.getPosition(inside) |
|
||||||
|
|
||||||
actualWidth = $tip[0].offsetWidth |
|
||||||
actualHeight = $tip[0].offsetHeight |
|
||||||
|
|
||||||
switch (inside ? placement.split(' ')[1] : placement) { |
|
||||||
case 'bottom': |
|
||||||
tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2} |
|
||||||
break |
|
||||||
case 'top': |
|
||||||
tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2} |
|
||||||
break |
|
||||||
case 'left': |
|
||||||
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth} |
|
||||||
break |
|
||||||
case 'right': |
|
||||||
tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width} |
|
||||||
break |
|
||||||
} |
|
||||||
|
|
||||||
$tip |
|
||||||
.css(tp) |
|
||||||
.addClass(placement) |
|
||||||
.addClass('in') |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
, setContent: function () { |
|
||||||
var $tip = this.tip() |
|
||||||
$tip.find('.tooltip-inner').html(this.getTitle()) |
|
||||||
$tip.removeClass('fade in top bottom left right') |
|
||||||
} |
|
||||||
|
|
||||||
, hide: function () { |
|
||||||
var that = this |
|
||||||
, $tip = this.tip() |
|
||||||
|
|
||||||
$tip.removeClass('in') |
|
||||||
|
|
||||||
function removeWithAnimation() { |
|
||||||
var timeout = setTimeout(function () { |
|
||||||
$tip.off($.support.transition.end).remove() |
|
||||||
}, 500) |
|
||||||
|
|
||||||
$tip.one($.support.transition.end, function () { |
|
||||||
clearTimeout(timeout) |
|
||||||
$tip.remove() |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
$.support.transition && this.$tip.hasClass('fade') ? |
|
||||||
removeWithAnimation() : |
|
||||||
$tip.remove() |
|
||||||
} |
|
||||||
|
|
||||||
, fixTitle: function () { |
|
||||||
var $e = this.$element |
|
||||||
if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { |
|
||||||
$e.attr('data-original-title', $e.attr('title') || '').removeAttr('title') |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
, hasContent: function () { |
|
||||||
return this.getTitle() |
|
||||||
} |
|
||||||
|
|
||||||
, getPosition: function (inside) { |
|
||||||
return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), { |
|
||||||
width: this.$element[0].offsetWidth |
|
||||||
, height: this.$element[0].offsetHeight |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
, getTitle: function () { |
|
||||||
var title |
|
||||||
, $e = this.$element |
|
||||||
, o = this.options |
|
||||||
|
|
||||||
title = $e.attr('data-original-title') |
|
||||||
|| (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) |
|
||||||
|
|
||||||
title = title.toString().replace(/(^\s*|\s*$)/, "") |
|
||||||
|
|
||||||
return title |
|
||||||
} |
|
||||||
|
|
||||||
, tip: function () { |
|
||||||
return this.$tip = this.$tip || $(this.options.template) |
|
||||||
} |
|
||||||
|
|
||||||
, validate: function () { |
|
||||||
if (!this.$element[0].parentNode) { |
|
||||||
this.hide() |
|
||||||
this.$element = null |
|
||||||
this.options = null |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
, enable: function () { |
|
||||||
this.enabled = true |
|
||||||
} |
|
||||||
|
|
||||||
, disable: function () { |
|
||||||
this.enabled = false |
|
||||||
} |
|
||||||
|
|
||||||
, toggleEnabled: function () { |
|
||||||
this.enabled = !this.enabled |
|
||||||
} |
|
||||||
|
|
||||||
, toggle: function () { |
|
||||||
this[this.tip().hasClass('in') ? 'hide' : 'show']() |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/* TOOLTIP PLUGIN DEFINITION |
|
||||||
* ========================= */ |
|
||||||
|
|
||||||
$.fn.tooltip = function ( option ) { |
|
||||||
return this.each(function () { |
|
||||||
var $this = $(this) |
|
||||||
, data = $this.data('tooltip') |
|
||||||
, options = typeof option == 'object' && option |
|
||||||
if (!data) $this.data('tooltip', (data = new Tooltip(this, options))) |
|
||||||
if (typeof option == 'string') data[option]() |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
$.fn.tooltip.Constructor = Tooltip |
|
||||||
|
|
||||||
$.fn.tooltip.defaults = { |
|
||||||
animation: true |
|
||||||
, delay: 0 |
|
||||||
, selector: false |
|
||||||
, placement: 'top' |
|
||||||
, trigger: 'hover' |
|
||||||
, title: '' |
|
||||||
, template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>' |
|
||||||
} |
|
||||||
|
|
||||||
}( window.jQuery ); |
|
@ -1,205 +0,0 @@ |
|||||||
/* |
|
||||||
* jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
|
|
||||||
* |
|
||||||
* Uses the built in easing capabilities added In jQuery 1.1 |
|
||||||
* to offer multiple easing options |
|
||||||
* |
|
||||||
* TERMS OF USE - jQuery Easing |
|
||||||
*
|
|
||||||
* Open source under the BSD License.
|
|
||||||
*
|
|
||||||
* Copyright © 2008 George McGinley Smith |
|
||||||
* All rights reserved. |
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met: |
|
||||||
*
|
|
||||||
* Redistributions of source code must retain the above copyright notice, this list of
|
|
||||||
* conditions and the following disclaimer. |
|
||||||
* Redistributions in binary form must reproduce the above copyright notice, this list
|
|
||||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
|
||||||
* provided with the distribution. |
|
||||||
*
|
|
||||||
* Neither the name of the author nor the names of contributors may be used to endorse
|
|
||||||
* or promote products derived from this software without specific prior written permission. |
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
||||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
|
||||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
||||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
* |
|
||||||
*/ |
|
||||||
|
|
||||||
// t: current time, b: begInnIng value, c: change In value, d: duration
|
|
||||||
jQuery.easing['jswing'] = jQuery.easing['swing']; |
|
||||||
|
|
||||||
jQuery.extend( jQuery.easing, |
|
||||||
{ |
|
||||||
def: 'easeOutQuad', |
|
||||||
swing: function (x, t, b, c, d) { |
|
||||||
//alert(jQuery.easing.default);
|
|
||||||
return jQuery.easing[jQuery.easing.def](x, t, b, c, d); |
|
||||||
}, |
|
||||||
easeInQuad: function (x, t, b, c, d) { |
|
||||||
return c*(t/=d)*t + b; |
|
||||||
}, |
|
||||||
easeOutQuad: function (x, t, b, c, d) { |
|
||||||
return -c *(t/=d)*(t-2) + b; |
|
||||||
}, |
|
||||||
easeInOutQuad: function (x, t, b, c, d) { |
|
||||||
if ((t/=d/2) < 1) return c/2*t*t + b; |
|
||||||
return -c/2 * ((--t)*(t-2) - 1) + b; |
|
||||||
}, |
|
||||||
easeInCubic: function (x, t, b, c, d) { |
|
||||||
return c*(t/=d)*t*t + b; |
|
||||||
}, |
|
||||||
easeOutCubic: function (x, t, b, c, d) { |
|
||||||
return c*((t=t/d-1)*t*t + 1) + b; |
|
||||||
}, |
|
||||||
easeInOutCubic: function (x, t, b, c, d) { |
|
||||||
if ((t/=d/2) < 1) return c/2*t*t*t + b; |
|
||||||
return c/2*((t-=2)*t*t + 2) + b; |
|
||||||
}, |
|
||||||
easeInQuart: function (x, t, b, c, d) { |
|
||||||
return c*(t/=d)*t*t*t + b; |
|
||||||
}, |
|
||||||
easeOutQuart: function (x, t, b, c, d) { |
|
||||||
return -c * ((t=t/d-1)*t*t*t - 1) + b; |
|
||||||
}, |
|
||||||
easeInOutQuart: function (x, t, b, c, d) { |
|
||||||
if ((t/=d/2) < 1) return c/2*t*t*t*t + b; |
|
||||||
return -c/2 * ((t-=2)*t*t*t - 2) + b; |
|
||||||
}, |
|
||||||
easeInQuint: function (x, t, b, c, d) { |
|
||||||
return c*(t/=d)*t*t*t*t + b; |
|
||||||
}, |
|
||||||
easeOutQuint: function (x, t, b, c, d) { |
|
||||||
return c*((t=t/d-1)*t*t*t*t + 1) + b; |
|
||||||
}, |
|
||||||
easeInOutQuint: function (x, t, b, c, d) { |
|
||||||
if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; |
|
||||||
return c/2*((t-=2)*t*t*t*t + 2) + b; |
|
||||||
}, |
|
||||||
easeInSine: function (x, t, b, c, d) { |
|
||||||
return -c * Math.cos(t/d * (Math.PI/2)) + c + b; |
|
||||||
}, |
|
||||||
easeOutSine: function (x, t, b, c, d) { |
|
||||||
return c * Math.sin(t/d * (Math.PI/2)) + b; |
|
||||||
}, |
|
||||||
easeInOutSine: function (x, t, b, c, d) { |
|
||||||
return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; |
|
||||||
}, |
|
||||||
easeInExpo: function (x, t, b, c, d) { |
|
||||||
return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b; |
|
||||||
}, |
|
||||||
easeOutExpo: function (x, t, b, c, d) { |
|
||||||
return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b; |
|
||||||
}, |
|
||||||
easeInOutExpo: function (x, t, b, c, d) { |
|
||||||
if (t==0) return b; |
|
||||||
if (t==d) return b+c; |
|
||||||
if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b; |
|
||||||
return c/2 * (-Math.pow(2, -10 * --t) + 2) + b; |
|
||||||
}, |
|
||||||
easeInCirc: function (x, t, b, c, d) { |
|
||||||
return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b; |
|
||||||
}, |
|
||||||
easeOutCirc: function (x, t, b, c, d) { |
|
||||||
return c * Math.sqrt(1 - (t=t/d-1)*t) + b; |
|
||||||
}, |
|
||||||
easeInOutCirc: function (x, t, b, c, d) { |
|
||||||
if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b; |
|
||||||
return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b; |
|
||||||
}, |
|
||||||
easeInElastic: function (x, t, b, c, d) { |
|
||||||
var s=1.70158;var p=0;var a=c; |
|
||||||
if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; |
|
||||||
if (a < Math.abs(c)) { a=c; var s=p/4; } |
|
||||||
else var s = p/(2*Math.PI) * Math.asin (c/a); |
|
||||||
return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; |
|
||||||
}, |
|
||||||
easeOutElastic: function (x, t, b, c, d) { |
|
||||||
var s=1.70158;var p=0;var a=c; |
|
||||||
if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; |
|
||||||
if (a < Math.abs(c)) { a=c; var s=p/4; } |
|
||||||
else var s = p/(2*Math.PI) * Math.asin (c/a); |
|
||||||
return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b; |
|
||||||
}, |
|
||||||
easeInOutElastic: function (x, t, b, c, d) { |
|
||||||
var s=1.70158;var p=0;var a=c; |
|
||||||
if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); |
|
||||||
if (a < Math.abs(c)) { a=c; var s=p/4; } |
|
||||||
else var s = p/(2*Math.PI) * Math.asin (c/a); |
|
||||||
if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b; |
|
||||||
return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b; |
|
||||||
}, |
|
||||||
easeInBack: function (x, t, b, c, d, s) { |
|
||||||
if (s == undefined) s = 1.70158; |
|
||||||
return c*(t/=d)*t*((s+1)*t - s) + b; |
|
||||||
}, |
|
||||||
easeOutBack: function (x, t, b, c, d, s) { |
|
||||||
if (s == undefined) s = 1.70158; |
|
||||||
return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; |
|
||||||
}, |
|
||||||
easeInOutBack: function (x, t, b, c, d, s) { |
|
||||||
if (s == undefined) s = 1.70158;
|
|
||||||
if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; |
|
||||||
return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; |
|
||||||
}, |
|
||||||
easeInBounce: function (x, t, b, c, d) { |
|
||||||
return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b; |
|
||||||
}, |
|
||||||
easeOutBounce: function (x, t, b, c, d) { |
|
||||||
if ((t/=d) < (1/2.75)) { |
|
||||||
return c*(7.5625*t*t) + b; |
|
||||||
} else if (t < (2/2.75)) { |
|
||||||
return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; |
|
||||||
} else if (t < (2.5/2.75)) { |
|
||||||
return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; |
|
||||||
} else { |
|
||||||
return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; |
|
||||||
} |
|
||||||
}, |
|
||||||
easeInOutBounce: function (x, t, b, c, d) { |
|
||||||
if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b; |
|
||||||
return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b; |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
/* |
|
||||||
* |
|
||||||
* TERMS OF USE - EASING EQUATIONS |
|
||||||
*
|
|
||||||
* Open source under the BSD License.
|
|
||||||
*
|
|
||||||
* Copyright © 2001 Robert Penner |
|
||||||
* All rights reserved. |
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met: |
|
||||||
*
|
|
||||||
* Redistributions of source code must retain the above copyright notice, this list of
|
|
||||||
* conditions and the following disclaimer. |
|
||||||
* Redistributions in binary form must reproduce the above copyright notice, this list
|
|
||||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
|
||||||
* provided with the distribution. |
|
||||||
*
|
|
||||||
* Neither the name of the author nor the names of contributors may be used to endorse
|
|
||||||
* or promote products derived from this software without specific prior written permission. |
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
|
||||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
|
||||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
||||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
* |
|
||||||
*/ |
|
@ -1,391 +0,0 @@ |
|||||||
/*jslint browser: true, eqeqeq: true, bitwise: true, newcap: true, immed: true, regexp: false */ |
|
||||||
|
|
||||||
/** |
|
||||||
LazyLoad makes it easy and painless to lazily load one or more external |
|
||||||
JavaScript or CSS files on demand either during or after the rendering of a web |
|
||||||
page. |
|
||||||
|
|
||||||
Supported browsers include Firefox 2+, IE6+, Safari 3+ (including Mobile |
|
||||||
Safari), Google Chrome, and Opera 9+. Other browsers may or may not work and |
|
||||||
are not officially supported. |
|
||||||
|
|
||||||
Visit https://github.com/rgrove/lazyload/ for more info.
|
|
||||||
|
|
||||||
Copyright (c) 2011 Ryan Grove <ryan@wonko.com> |
|
||||||
All rights reserved. |
|
||||||
|
|
||||||
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. |
|
||||||
|
|
||||||
@module lazyload |
|
||||||
@class LazyLoad |
|
||||||
@static |
|
||||||
@version 2.0.3 (git) |
|
||||||
*/ |
|
||||||
|
|
||||||
LazyLoad = (function (doc) { |
|
||||||
// -- Private Variables ------------------------------------------------------
|
|
||||||
|
|
||||||
// User agent and feature test information.
|
|
||||||
var env, |
|
||||||
|
|
||||||
// Reference to the <head> element (populated lazily).
|
|
||||||
head, |
|
||||||
|
|
||||||
// Requests currently in progress, if any.
|
|
||||||
pending = {}, |
|
||||||
|
|
||||||
// Number of times we've polled to check whether a pending stylesheet has
|
|
||||||
// finished loading. If this gets too high, we're probably stalled.
|
|
||||||
pollCount = 0, |
|
||||||
|
|
||||||
// Queued requests.
|
|
||||||
queue = {css: [], js: []}, |
|
||||||
|
|
||||||
// Reference to the browser's list of stylesheets.
|
|
||||||
styleSheets = doc.styleSheets; |
|
||||||
|
|
||||||
// -- Private Methods --------------------------------------------------------
|
|
||||||
|
|
||||||
/** |
|
||||||
Creates and returns an HTML element with the specified name and attributes. |
|
||||||
|
|
||||||
@method createNode |
|
||||||
@param {String} name element name |
|
||||||
@param {Object} attrs name/value mapping of element attributes |
|
||||||
@return {HTMLElement} |
|
||||||
@private |
|
||||||
*/ |
|
||||||
function createNode(name, attrs) { |
|
||||||
var node = doc.createElement(name), attr; |
|
||||||
|
|
||||||
for (attr in attrs) { |
|
||||||
if (attrs.hasOwnProperty(attr)) { |
|
||||||
node.setAttribute(attr, attrs[attr]); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return node; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
Called when the current pending resource of the specified type has finished |
|
||||||
loading. Executes the associated callback (if any) and loads the next |
|
||||||
resource in the queue. |
|
||||||
|
|
||||||
@method finish |
|
||||||
@param {String} type resource type ('css' or 'js') |
|
||||||
@private |
|
||||||
*/ |
|
||||||
function finish(type) { |
|
||||||
var p = pending[type], |
|
||||||
callback, |
|
||||||
urls; |
|
||||||
|
|
||||||
if (p) { |
|
||||||
callback = p.callback; |
|
||||||
urls = p.urls; |
|
||||||
|
|
||||||
urls.shift(); |
|
||||||
pollCount = 0; |
|
||||||
|
|
||||||
// If this is the last of the pending URLs, execute the callback and
|
|
||||||
// start the next request in the queue (if any).
|
|
||||||
if (!urls.length) { |
|
||||||
callback && callback.call(p.context, p.obj); |
|
||||||
pending[type] = null; |
|
||||||
queue[type].length && load(type); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
Populates the <code>env</code> variable with user agent and feature test |
|
||||||
information. |
|
||||||
|
|
||||||
@method getEnv |
|
||||||
@private |
|
||||||
*/ |
|
||||||
function getEnv() { |
|
||||||
var ua = navigator.userAgent; |
|
||||||
|
|
||||||
env = { |
|
||||||
// True if this browser supports disabling async mode on dynamically
|
|
||||||
// created script nodes. See
|
|
||||||
// http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
|
|
||||||
async: doc.createElement('script').async === true |
|
||||||
}; |
|
||||||
|
|
||||||
(env.webkit = /AppleWebKit\//.test(ua)) |
|
||||||
|| (env.ie = /MSIE/.test(ua)) |
|
||||||
|| (env.opera = /Opera/.test(ua)) |
|
||||||
|| (env.gecko = /Gecko\//.test(ua)) |
|
||||||
|| (env.unknown = true); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
Loads the specified resources, or the next resource of the specified type |
|
||||||
in the queue if no resources are specified. If a resource of the specified |
|
||||||
type is already being loaded, the new request will be queued until the |
|
||||||
first request has been finished. |
|
||||||
|
|
||||||
When an array of resource URLs is specified, those URLs will be loaded in |
|
||||||
parallel if it is possible to do so while preserving execution order. All |
|
||||||
browsers support parallel loading of CSS, but only Firefox and Opera |
|
||||||
support parallel loading of scripts. In other browsers, scripts will be |
|
||||||
queued and loaded one at a time to ensure correct execution order. |
|
||||||
|
|
||||||
@method load |
|
||||||
@param {String} type resource type ('css' or 'js') |
|
||||||
@param {String|Array} urls (optional) URL or array of URLs to load |
|
||||||
@param {Function} callback (optional) callback function to execute when the |
|
||||||
resource is loaded |
|
||||||
@param {Object} obj (optional) object to pass to the callback function |
|
||||||
@param {Object} context (optional) if provided, the callback function will |
|
||||||
be executed in this object's context |
|
||||||
@private |
|
||||||
*/ |
|
||||||
function load(type, urls, callback, obj, context) { |
|
||||||
var _finish = function () { finish(type); }, |
|
||||||
isCSS = type === 'css', |
|
||||||
nodes = [], |
|
||||||
i, len, node, p, pendingUrls, url; |
|
||||||
|
|
||||||
env || getEnv(); |
|
||||||
|
|
||||||
if (urls) { |
|
||||||
// If urls is a string, wrap it in an array. Otherwise assume it's an
|
|
||||||
// array and create a copy of it so modifications won't be made to the
|
|
||||||
// original.
|
|
||||||
urls = typeof urls === 'string' ? [urls] : urls.concat(); |
|
||||||
|
|
||||||
// Create a request object for each URL. If multiple URLs are specified,
|
|
||||||
// the callback will only be executed after all URLs have been loaded.
|
|
||||||
//
|
|
||||||
// Sadly, Firefox and Opera are the only browsers capable of loading
|
|
||||||
// scripts in parallel while preserving execution order. In all other
|
|
||||||
// browsers, scripts must be loaded sequentially.
|
|
||||||
//
|
|
||||||
// All browsers respect CSS specificity based on the order of the link
|
|
||||||
// elements in the DOM, regardless of the order in which the stylesheets
|
|
||||||
// are actually downloaded.
|
|
||||||
if (isCSS || env.async || env.gecko || env.opera) { |
|
||||||
// Load in parallel.
|
|
||||||
queue[type].push({ |
|
||||||
urls : urls, |
|
||||||
callback: callback, |
|
||||||
obj : obj, |
|
||||||
context : context |
|
||||||
}); |
|
||||||
} else { |
|
||||||
// Load sequentially.
|
|
||||||
for (i = 0, len = urls.length; i < len; ++i) { |
|
||||||
queue[type].push({ |
|
||||||
urls : [urls[i]], |
|
||||||
callback: i === len - 1 ? callback : null, // callback is only added to the last URL
|
|
||||||
obj : obj, |
|
||||||
context : context |
|
||||||
}); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// If a previous load request of this type is currently in progress, we'll
|
|
||||||
// wait our turn. Otherwise, grab the next item in the queue.
|
|
||||||
if (pending[type] || !(p = pending[type] = queue[type].shift())) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
head || (head = doc.head || doc.getElementsByTagName('head')[0]); |
|
||||||
pendingUrls = p.urls; |
|
||||||
|
|
||||||
for (i = 0, len = pendingUrls.length; i < len; ++i) { |
|
||||||
url = pendingUrls[i]; |
|
||||||
|
|
||||||
if (isCSS) { |
|
||||||
node = env.gecko ? createNode('style') : createNode('link', { |
|
||||||
href: url, |
|
||||||
rel : 'stylesheet' |
|
||||||
}); |
|
||||||
} else { |
|
||||||
node = createNode('script', {src: url}); |
|
||||||
node.async = false; |
|
||||||
} |
|
||||||
|
|
||||||
node.className = 'lazyload'; |
|
||||||
node.setAttribute('charset', 'utf-8'); |
|
||||||
|
|
||||||
if (env.ie && !isCSS) { |
|
||||||
node.onreadystatechange = function () { |
|
||||||
if (/loaded|complete/.test(node.readyState)) { |
|
||||||
node.onreadystatechange = null; |
|
||||||
_finish(); |
|
||||||
} |
|
||||||
}; |
|
||||||
} else if (isCSS && (env.gecko || env.webkit)) { |
|
||||||
// Gecko and WebKit don't support the onload event on link nodes.
|
|
||||||
if (env.webkit) { |
|
||||||
// In WebKit, we can poll for changes to document.styleSheets to
|
|
||||||
// figure out when stylesheets have loaded.
|
|
||||||
p.urls[i] = node.href; // resolve relative URLs (or polling won't work)
|
|
||||||
pollWebKit(); |
|
||||||
} else { |
|
||||||
// In Gecko, we can import the requested URL into a <style> node and
|
|
||||||
// poll for the existence of node.sheet.cssRules. Props to Zach
|
|
||||||
// Leatherman for calling my attention to this technique.
|
|
||||||
node.innerHTML = '@import "' + url + '";'; |
|
||||||
pollGecko(node); |
|
||||||
} |
|
||||||
} else { |
|
||||||
node.onload = node.onerror = _finish; |
|
||||||
} |
|
||||||
|
|
||||||
nodes.push(node); |
|
||||||
} |
|
||||||
|
|
||||||
for (i = 0, len = nodes.length; i < len; ++i) { |
|
||||||
head.appendChild(nodes[i]); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
Begins polling to determine when the specified stylesheet has finished loading |
|
||||||
in Gecko. Polling stops when all pending stylesheets have loaded or after 10 |
|
||||||
seconds (to prevent stalls). |
|
||||||
|
|
||||||
Thanks to Zach Leatherman for calling my attention to the @import-based |
|
||||||
cross-domain technique used here, and to Oleg Slobodskoi for an earlier |
|
||||||
same-domain implementation. See Zach's blog for more details: |
|
||||||
http://www.zachleat.com/web/2010/07/29/load-css-dynamically/
|
|
||||||
|
|
||||||
@method pollGecko |
|
||||||
@param {HTMLElement} node Style node to poll. |
|
||||||
@private |
|
||||||
*/ |
|
||||||
function pollGecko(node) { |
|
||||||
var hasRules; |
|
||||||
|
|
||||||
try { |
|
||||||
// We don't really need to store this value or ever refer to it again, but
|
|
||||||
// if we don't store it, Closure Compiler assumes the code is useless and
|
|
||||||
// removes it.
|
|
||||||
hasRules = !!node.sheet.cssRules; |
|
||||||
} catch (ex) { |
|
||||||
// An exception means the stylesheet is still loading.
|
|
||||||
pollCount += 1; |
|
||||||
|
|
||||||
if (pollCount < 200) { |
|
||||||
setTimeout(function () { pollGecko(node); }, 50); |
|
||||||
} else { |
|
||||||
// We've been polling for 10 seconds and nothing's happened. Stop
|
|
||||||
// polling and finish the pending requests to avoid blocking further
|
|
||||||
// requests.
|
|
||||||
hasRules && finish('css'); |
|
||||||
} |
|
||||||
|
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
// If we get here, the stylesheet has loaded.
|
|
||||||
finish('css'); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
Begins polling to determine when pending stylesheets have finished loading |
|
||||||
in WebKit. Polling stops when all pending stylesheets have loaded or after 10 |
|
||||||
seconds (to prevent stalls). |
|
||||||
|
|
||||||
@method pollWebKit |
|
||||||
@private |
|
||||||
*/ |
|
||||||
function pollWebKit() { |
|
||||||
var css = pending.css, i; |
|
||||||
|
|
||||||
if (css) { |
|
||||||
i = styleSheets.length; |
|
||||||
|
|
||||||
// Look for a stylesheet matching the pending URL.
|
|
||||||
while (--i >= 0) { |
|
||||||
if (styleSheets[i].href === css.urls[0]) { |
|
||||||
finish('css'); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
pollCount += 1; |
|
||||||
|
|
||||||
if (css) { |
|
||||||
if (pollCount < 200) { |
|
||||||
setTimeout(pollWebKit, 50); |
|
||||||
} else { |
|
||||||
// We've been polling for 10 seconds and nothing's happened, which may
|
|
||||||
// indicate that the stylesheet has been removed from the document
|
|
||||||
// before it had a chance to load. Stop polling and finish the pending
|
|
||||||
// request to prevent blocking further requests.
|
|
||||||
finish('css'); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return { |
|
||||||
|
|
||||||
/** |
|
||||||
Requests the specified CSS URL or URLs and executes the specified |
|
||||||
callback (if any) when they have finished loading. If an array of URLs is |
|
||||||
specified, the stylesheets will be loaded in parallel and the callback |
|
||||||
will be executed after all stylesheets have finished loading. |
|
||||||
|
|
||||||
@method css |
|
||||||
@param {String|Array} urls CSS URL or array of CSS URLs to load |
|
||||||
@param {Function} callback (optional) callback function to execute when |
|
||||||
the specified stylesheets are loaded |
|
||||||
@param {Object} obj (optional) object to pass to the callback function |
|
||||||
@param {Object} context (optional) if provided, the callback function |
|
||||||
will be executed in this object's context |
|
||||||
@static |
|
||||||
*/ |
|
||||||
css: function (urls, callback, obj, context) { |
|
||||||
load('css', urls, callback, obj, context); |
|
||||||
}, |
|
||||||
|
|
||||||
/** |
|
||||||
Requests the specified JavaScript URL or URLs and executes the specified |
|
||||||
callback (if any) when they have finished loading. If an array of URLs is |
|
||||||
specified and the browser supports it, the scripts will be loaded in |
|
||||||
parallel and the callback will be executed after all scripts have |
|
||||||
finished loading. |
|
||||||
|
|
||||||
Currently, only Firefox and Opera support parallel loading of scripts while |
|
||||||
preserving execution order. In other browsers, scripts will be |
|
||||||
queued and loaded one at a time to ensure correct execution order. |
|
||||||
|
|
||||||
@method js |
|
||||||
@param {String|Array} urls JS URL or array of JS URLs to load |
|
||||||
@param {Function} callback (optional) callback function to execute when |
|
||||||
the specified scripts are loaded |
|
||||||
@param {Object} obj (optional) object to pass to the callback function |
|
||||||
@param {Object} context (optional) if provided, the callback function |
|
||||||
will be executed in this object's context |
|
||||||
@static |
|
||||||
*/ |
|
||||||
js: function (urls, callback, obj, context) { |
|
||||||
load('js', urls, callback, obj, context); |
|
||||||
} |
|
||||||
|
|
||||||
}; |
|
||||||
})(this.document); |
|
Loading…
Reference in new issue