mirror of
https://github.com/fcwu/docker-ubuntu-vnc-desktop
synced 2026-08-05 16:12:41 +02:00
upgrade noVNC to 0.5.1
This commit is contained in:
+96
-98
@@ -4,112 +4,110 @@
|
||||
|
||||
// From: http://hg.mozilla.org/mozilla-central/raw-file/ec10630b1a54/js/src/devtools/jint/sunspider/string-base64.js
|
||||
|
||||
/*jslint white: false, bitwise: false, plusplus: false */
|
||||
/*jslint white: false */
|
||||
/*global console */
|
||||
|
||||
var Base64 = {
|
||||
/* Convert data (an array of integers) to a Base64 string. */
|
||||
toBase64Table : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''),
|
||||
base64Pad : '=',
|
||||
|
||||
/* Convert data (an array of integers) to a Base64 string. */
|
||||
toBase64Table : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''),
|
||||
base64Pad : '=',
|
||||
encode: function (data) {
|
||||
"use strict";
|
||||
var result = '';
|
||||
var toBase64Table = Base64.toBase64Table;
|
||||
var length = data.length;
|
||||
var lengthpad = (length % 3);
|
||||
// Convert every three bytes to 4 ascii characters.
|
||||
|
||||
encode: function (data) {
|
||||
"use strict";
|
||||
var result = '';
|
||||
var toBase64Table = Base64.toBase64Table;
|
||||
var length = data.length
|
||||
var lengthpad = (length%3);
|
||||
var i = 0, j = 0;
|
||||
// Convert every three bytes to 4 ascii characters.
|
||||
/* BEGIN LOOP */
|
||||
for (i = 0; i < (length - 2); i += 3) {
|
||||
result += toBase64Table[data[i] >> 2];
|
||||
result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)];
|
||||
result += toBase64Table[((data[i+1] & 0x0f) << 2) + (data[i+2] >> 6)];
|
||||
result += toBase64Table[data[i+2] & 0x3f];
|
||||
}
|
||||
/* END LOOP */
|
||||
|
||||
// Convert the remaining 1 or 2 bytes, pad out to 4 characters.
|
||||
if (lengthpad === 2) {
|
||||
j = length - lengthpad;
|
||||
result += toBase64Table[data[j] >> 2];
|
||||
result += toBase64Table[((data[j] & 0x03) << 4) + (data[j+1] >> 4)];
|
||||
result += toBase64Table[(data[j+1] & 0x0f) << 2];
|
||||
result += toBase64Table[64];
|
||||
} else if (lengthpad === 1) {
|
||||
j = length - lengthpad;
|
||||
result += toBase64Table[data[j] >> 2];
|
||||
result += toBase64Table[(data[j] & 0x03) << 4];
|
||||
result += toBase64Table[64];
|
||||
result += toBase64Table[64];
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/* Convert Base64 data to a string */
|
||||
toBinaryTable : [
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
|
||||
52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
|
||||
15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
|
||||
-1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
|
||||
41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
|
||||
],
|
||||
|
||||
decode: function (data, offset) {
|
||||
"use strict";
|
||||
offset = typeof(offset) !== 'undefined' ? offset : 0;
|
||||
var toBinaryTable = Base64.toBinaryTable;
|
||||
var base64Pad = Base64.base64Pad;
|
||||
var result, result_length, idx, i, c, padding;
|
||||
var leftbits = 0; // number of bits decoded, but yet to be appended
|
||||
var leftdata = 0; // bits decoded, but yet to be appended
|
||||
var data_length = data.indexOf('=') - offset;
|
||||
|
||||
if (data_length < 0) { data_length = data.length - offset; }
|
||||
|
||||
/* Every four characters is 3 resulting numbers */
|
||||
result_length = (data_length >> 2) * 3 + Math.floor((data_length%4)/1.5);
|
||||
result = new Array(result_length);
|
||||
|
||||
// Convert one by one.
|
||||
/* BEGIN LOOP */
|
||||
for (idx = 0, i = offset; i < data.length; i++) {
|
||||
c = toBinaryTable[data.charCodeAt(i) & 0x7f];
|
||||
padding = (data.charAt(i) === base64Pad);
|
||||
// Skip illegal characters and whitespace
|
||||
if (c === -1) {
|
||||
console.error("Illegal character code " + data.charCodeAt(i) + " at position " + i);
|
||||
continue;
|
||||
for (var i = 0; i < (length - 2); i += 3) {
|
||||
result += toBase64Table[data[i] >> 2];
|
||||
result += toBase64Table[((data[i] & 0x03) << 4) + (data[i + 1] >> 4)];
|
||||
result += toBase64Table[((data[i + 1] & 0x0f) << 2) + (data[i + 2] >> 6)];
|
||||
result += toBase64Table[data[i + 2] & 0x3f];
|
||||
}
|
||||
|
||||
// Collect data into leftdata, update bitcount
|
||||
leftdata = (leftdata << 6) | c;
|
||||
leftbits += 6;
|
||||
|
||||
// If we have 8 or more bits, append 8 bits to the result
|
||||
if (leftbits >= 8) {
|
||||
leftbits -= 8;
|
||||
// Append if not padding.
|
||||
if (!padding) {
|
||||
result[idx++] = (leftdata >> leftbits) & 0xff;
|
||||
// Convert the remaining 1 or 2 bytes, pad out to 4 characters.
|
||||
var j = 0;
|
||||
if (lengthpad === 2) {
|
||||
j = length - lengthpad;
|
||||
result += toBase64Table[data[j] >> 2];
|
||||
result += toBase64Table[((data[j] & 0x03) << 4) + (data[j + 1] >> 4)];
|
||||
result += toBase64Table[(data[j + 1] & 0x0f) << 2];
|
||||
result += toBase64Table[64];
|
||||
} else if (lengthpad === 1) {
|
||||
j = length - lengthpad;
|
||||
result += toBase64Table[data[j] >> 2];
|
||||
result += toBase64Table[(data[j] & 0x03) << 4];
|
||||
result += toBase64Table[64];
|
||||
result += toBase64Table[64];
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/* Convert Base64 data to a string */
|
||||
/* jshint -W013 */
|
||||
toBinaryTable : [
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
|
||||
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
|
||||
52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
|
||||
15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
|
||||
-1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
|
||||
41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
|
||||
],
|
||||
/* jshint +W013 */
|
||||
|
||||
decode: function (data, offset) {
|
||||
"use strict";
|
||||
offset = typeof(offset) !== 'undefined' ? offset : 0;
|
||||
var toBinaryTable = Base64.toBinaryTable;
|
||||
var base64Pad = Base64.base64Pad;
|
||||
var result, result_length;
|
||||
var leftbits = 0; // number of bits decoded, but yet to be appended
|
||||
var leftdata = 0; // bits decoded, but yet to be appended
|
||||
var data_length = data.indexOf('=') - offset;
|
||||
|
||||
if (data_length < 0) { data_length = data.length - offset; }
|
||||
|
||||
/* Every four characters is 3 resulting numbers */
|
||||
result_length = (data_length >> 2) * 3 + Math.floor((data_length % 4) / 1.5);
|
||||
result = new Array(result_length);
|
||||
|
||||
// Convert one by one.
|
||||
for (var idx = 0, i = offset; i < data.length; i++) {
|
||||
var c = toBinaryTable[data.charCodeAt(i) & 0x7f];
|
||||
var padding = (data.charAt(i) === base64Pad);
|
||||
// Skip illegal characters and whitespace
|
||||
if (c === -1) {
|
||||
console.error("Illegal character code " + data.charCodeAt(i) + " at position " + i);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Collect data into leftdata, update bitcount
|
||||
leftdata = (leftdata << 6) | c;
|
||||
leftbits += 6;
|
||||
|
||||
// If we have 8 or more bits, append 8 bits to the result
|
||||
if (leftbits >= 8) {
|
||||
leftbits -= 8;
|
||||
// Append if not padding.
|
||||
if (!padding) {
|
||||
result[idx++] = (leftdata >> leftbits) & 0xff;
|
||||
}
|
||||
leftdata &= (1 << leftbits) - 1;
|
||||
}
|
||||
leftdata &= (1 << leftbits) - 1;
|
||||
}
|
||||
|
||||
// If there are any bits left, the base64 string was corrupted
|
||||
if (leftbits) {
|
||||
err = new Error('Corrupted base64 string');
|
||||
err.name = 'Base64-Error';
|
||||
throw err;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/* END LOOP */
|
||||
|
||||
// If there are any bits left, the base64 string was corrupted
|
||||
if (leftbits) {
|
||||
throw {name: 'Base64-Error',
|
||||
message: 'Corrupted base64 string'};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}; /* End of Base64 namespace */
|
||||
|
||||
+176
-173
@@ -75,199 +75,202 @@
|
||||
* fine Java utilities: http://www.acme.com/java/
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
/*jslint white: false, bitwise: false, plusplus: false */
|
||||
/* jslint white: false */
|
||||
|
||||
function DES(passwd) {
|
||||
"use strict";
|
||||
|
||||
// Tables, permutations, S-boxes, etc.
|
||||
var PC2 = [13,16,10,23, 0, 4, 2,27,14, 5,20, 9,22,18,11, 3,
|
||||
25, 7,15, 6,26,19,12, 1,40,51,30,36,46,54,29,39,
|
||||
50,44,32,47,43,48,38,55,33,52,45,41,49,35,28,31 ],
|
||||
totrot = [ 1, 2, 4, 6, 8,10,12,14,15,17,19,21,23,25,27,28],
|
||||
z = 0x0, a,b,c,d,e,f, SP1,SP2,SP3,SP4,SP5,SP6,SP7,SP8,
|
||||
keys = [];
|
||||
// Tables, permutations, S-boxes, etc.
|
||||
// jshint -W013
|
||||
var PC2 = [13,16,10,23, 0, 4, 2,27,14, 5,20, 9,22,18,11, 3,
|
||||
25, 7,15, 6,26,19,12, 1,40,51,30,36,46,54,29,39,
|
||||
50,44,32,47,43,48,38,55,33,52,45,41,49,35,28,31 ],
|
||||
totrot = [ 1, 2, 4, 6, 8,10,12,14,15,17,19,21,23,25,27,28],
|
||||
z = 0x0, a,b,c,d,e,f, SP1,SP2,SP3,SP4,SP5,SP6,SP7,SP8,
|
||||
keys = [];
|
||||
|
||||
a=1<<16; b=1<<24; c=a|b; d=1<<2; e=1<<10; f=d|e;
|
||||
SP1 = [c|e,z|z,a|z,c|f,c|d,a|f,z|d,a|z,z|e,c|e,c|f,z|e,b|f,c|d,b|z,z|d,
|
||||
z|f,b|e,b|e,a|e,a|e,c|z,c|z,b|f,a|d,b|d,b|d,a|d,z|z,z|f,a|f,b|z,
|
||||
a|z,c|f,z|d,c|z,c|e,b|z,b|z,z|e,c|d,a|z,a|e,b|d,z|e,z|d,b|f,a|f,
|
||||
c|f,a|d,c|z,b|f,b|d,z|f,a|f,c|e,z|f,b|e,b|e,z|z,a|d,a|e,z|z,c|d];
|
||||
a=1<<20; b=1<<31; c=a|b; d=1<<5; e=1<<15; f=d|e;
|
||||
SP2 = [c|f,b|e,z|e,a|f,a|z,z|d,c|d,b|f,b|d,c|f,c|e,b|z,b|e,a|z,z|d,c|d,
|
||||
a|e,a|d,b|f,z|z,b|z,z|e,a|f,c|z,a|d,b|d,z|z,a|e,z|f,c|e,c|z,z|f,
|
||||
z|z,a|f,c|d,a|z,b|f,c|z,c|e,z|e,c|z,b|e,z|d,c|f,a|f,z|d,z|e,b|z,
|
||||
z|f,c|e,a|z,b|d,a|d,b|f,b|d,a|d,a|e,z|z,b|e,z|f,b|z,c|d,c|f,a|e];
|
||||
a=1<<17; b=1<<27; c=a|b; d=1<<3; e=1<<9; f=d|e;
|
||||
SP3 = [z|f,c|e,z|z,c|d,b|e,z|z,a|f,b|e,a|d,b|d,b|d,a|z,c|f,a|d,c|z,z|f,
|
||||
b|z,z|d,c|e,z|e,a|e,c|z,c|d,a|f,b|f,a|e,a|z,b|f,z|d,c|f,z|e,b|z,
|
||||
c|e,b|z,a|d,z|f,a|z,c|e,b|e,z|z,z|e,a|d,c|f,b|e,b|d,z|e,z|z,c|d,
|
||||
b|f,a|z,b|z,c|f,z|d,a|f,a|e,b|d,c|z,b|f,z|f,c|z,a|f,z|d,c|d,a|e];
|
||||
a=1<<13; b=1<<23; c=a|b; d=1<<0; e=1<<7; f=d|e;
|
||||
SP4 = [c|d,a|f,a|f,z|e,c|e,b|f,b|d,a|d,z|z,c|z,c|z,c|f,z|f,z|z,b|e,b|d,
|
||||
z|d,a|z,b|z,c|d,z|e,b|z,a|d,a|e,b|f,z|d,a|e,b|e,a|z,c|e,c|f,z|f,
|
||||
b|e,b|d,c|z,c|f,z|f,z|z,z|z,c|z,a|e,b|e,b|f,z|d,c|d,a|f,a|f,z|e,
|
||||
c|f,z|f,z|d,a|z,b|d,a|d,c|e,b|f,a|d,a|e,b|z,c|d,z|e,b|z,a|z,c|e];
|
||||
a=1<<25; b=1<<30; c=a|b; d=1<<8; e=1<<19; f=d|e;
|
||||
SP5 = [z|d,a|f,a|e,c|d,z|e,z|d,b|z,a|e,b|f,z|e,a|d,b|f,c|d,c|e,z|f,b|z,
|
||||
a|z,b|e,b|e,z|z,b|d,c|f,c|f,a|d,c|e,b|d,z|z,c|z,a|f,a|z,c|z,z|f,
|
||||
z|e,c|d,z|d,a|z,b|z,a|e,c|d,b|f,a|d,b|z,c|e,a|f,b|f,z|d,a|z,c|e,
|
||||
c|f,z|f,c|z,c|f,a|e,z|z,b|e,c|z,z|f,a|d,b|d,z|e,z|z,b|e,a|f,b|d];
|
||||
a=1<<22; b=1<<29; c=a|b; d=1<<4; e=1<<14; f=d|e;
|
||||
SP6 = [b|d,c|z,z|e,c|f,c|z,z|d,c|f,a|z,b|e,a|f,a|z,b|d,a|d,b|e,b|z,z|f,
|
||||
z|z,a|d,b|f,z|e,a|e,b|f,z|d,c|d,c|d,z|z,a|f,c|e,z|f,a|e,c|e,b|z,
|
||||
b|e,z|d,c|d,a|e,c|f,a|z,z|f,b|d,a|z,b|e,b|z,z|f,b|d,c|f,a|e,c|z,
|
||||
a|f,c|e,z|z,c|d,z|d,z|e,c|z,a|f,z|e,a|d,b|f,z|z,c|e,b|z,a|d,b|f];
|
||||
a=1<<21; b=1<<26; c=a|b; d=1<<1; e=1<<11; f=d|e;
|
||||
SP7 = [a|z,c|d,b|f,z|z,z|e,b|f,a|f,c|e,c|f,a|z,z|z,b|d,z|d,b|z,c|d,z|f,
|
||||
b|e,a|f,a|d,b|e,b|d,c|z,c|e,a|d,c|z,z|e,z|f,c|f,a|e,z|d,b|z,a|e,
|
||||
b|z,a|e,a|z,b|f,b|f,c|d,c|d,z|d,a|d,b|z,b|e,a|z,c|e,z|f,a|f,c|e,
|
||||
z|f,b|d,c|f,c|z,a|e,z|z,z|d,c|f,z|z,a|f,c|z,z|e,b|d,b|e,z|e,a|d];
|
||||
a=1<<18; b=1<<28; c=a|b; d=1<<6; e=1<<12; f=d|e;
|
||||
SP8 = [b|f,z|e,a|z,c|f,b|z,b|f,z|d,b|z,a|d,c|z,c|f,a|e,c|e,a|f,z|e,z|d,
|
||||
c|z,b|d,b|e,z|f,a|e,a|d,c|d,c|e,z|f,z|z,z|z,c|d,b|d,b|e,a|f,a|z,
|
||||
a|f,a|z,c|e,z|e,z|d,c|d,z|e,a|f,b|e,z|d,b|d,c|z,c|d,b|z,a|z,b|f,
|
||||
z|z,c|f,a|d,b|d,c|z,b|e,b|f,z|z,c|f,a|e,a|e,z|f,z|f,a|d,b|z,c|e];
|
||||
// jshint -W015
|
||||
a=1<<16; b=1<<24; c=a|b; d=1<<2; e=1<<10; f=d|e;
|
||||
SP1 = [c|e,z|z,a|z,c|f,c|d,a|f,z|d,a|z,z|e,c|e,c|f,z|e,b|f,c|d,b|z,z|d,
|
||||
z|f,b|e,b|e,a|e,a|e,c|z,c|z,b|f,a|d,b|d,b|d,a|d,z|z,z|f,a|f,b|z,
|
||||
a|z,c|f,z|d,c|z,c|e,b|z,b|z,z|e,c|d,a|z,a|e,b|d,z|e,z|d,b|f,a|f,
|
||||
c|f,a|d,c|z,b|f,b|d,z|f,a|f,c|e,z|f,b|e,b|e,z|z,a|d,a|e,z|z,c|d];
|
||||
a=1<<20; b=1<<31; c=a|b; d=1<<5; e=1<<15; f=d|e;
|
||||
SP2 = [c|f,b|e,z|e,a|f,a|z,z|d,c|d,b|f,b|d,c|f,c|e,b|z,b|e,a|z,z|d,c|d,
|
||||
a|e,a|d,b|f,z|z,b|z,z|e,a|f,c|z,a|d,b|d,z|z,a|e,z|f,c|e,c|z,z|f,
|
||||
z|z,a|f,c|d,a|z,b|f,c|z,c|e,z|e,c|z,b|e,z|d,c|f,a|f,z|d,z|e,b|z,
|
||||
z|f,c|e,a|z,b|d,a|d,b|f,b|d,a|d,a|e,z|z,b|e,z|f,b|z,c|d,c|f,a|e];
|
||||
a=1<<17; b=1<<27; c=a|b; d=1<<3; e=1<<9; f=d|e;
|
||||
SP3 = [z|f,c|e,z|z,c|d,b|e,z|z,a|f,b|e,a|d,b|d,b|d,a|z,c|f,a|d,c|z,z|f,
|
||||
b|z,z|d,c|e,z|e,a|e,c|z,c|d,a|f,b|f,a|e,a|z,b|f,z|d,c|f,z|e,b|z,
|
||||
c|e,b|z,a|d,z|f,a|z,c|e,b|e,z|z,z|e,a|d,c|f,b|e,b|d,z|e,z|z,c|d,
|
||||
b|f,a|z,b|z,c|f,z|d,a|f,a|e,b|d,c|z,b|f,z|f,c|z,a|f,z|d,c|d,a|e];
|
||||
a=1<<13; b=1<<23; c=a|b; d=1<<0; e=1<<7; f=d|e;
|
||||
SP4 = [c|d,a|f,a|f,z|e,c|e,b|f,b|d,a|d,z|z,c|z,c|z,c|f,z|f,z|z,b|e,b|d,
|
||||
z|d,a|z,b|z,c|d,z|e,b|z,a|d,a|e,b|f,z|d,a|e,b|e,a|z,c|e,c|f,z|f,
|
||||
b|e,b|d,c|z,c|f,z|f,z|z,z|z,c|z,a|e,b|e,b|f,z|d,c|d,a|f,a|f,z|e,
|
||||
c|f,z|f,z|d,a|z,b|d,a|d,c|e,b|f,a|d,a|e,b|z,c|d,z|e,b|z,a|z,c|e];
|
||||
a=1<<25; b=1<<30; c=a|b; d=1<<8; e=1<<19; f=d|e;
|
||||
SP5 = [z|d,a|f,a|e,c|d,z|e,z|d,b|z,a|e,b|f,z|e,a|d,b|f,c|d,c|e,z|f,b|z,
|
||||
a|z,b|e,b|e,z|z,b|d,c|f,c|f,a|d,c|e,b|d,z|z,c|z,a|f,a|z,c|z,z|f,
|
||||
z|e,c|d,z|d,a|z,b|z,a|e,c|d,b|f,a|d,b|z,c|e,a|f,b|f,z|d,a|z,c|e,
|
||||
c|f,z|f,c|z,c|f,a|e,z|z,b|e,c|z,z|f,a|d,b|d,z|e,z|z,b|e,a|f,b|d];
|
||||
a=1<<22; b=1<<29; c=a|b; d=1<<4; e=1<<14; f=d|e;
|
||||
SP6 = [b|d,c|z,z|e,c|f,c|z,z|d,c|f,a|z,b|e,a|f,a|z,b|d,a|d,b|e,b|z,z|f,
|
||||
z|z,a|d,b|f,z|e,a|e,b|f,z|d,c|d,c|d,z|z,a|f,c|e,z|f,a|e,c|e,b|z,
|
||||
b|e,z|d,c|d,a|e,c|f,a|z,z|f,b|d,a|z,b|e,b|z,z|f,b|d,c|f,a|e,c|z,
|
||||
a|f,c|e,z|z,c|d,z|d,z|e,c|z,a|f,z|e,a|d,b|f,z|z,c|e,b|z,a|d,b|f];
|
||||
a=1<<21; b=1<<26; c=a|b; d=1<<1; e=1<<11; f=d|e;
|
||||
SP7 = [a|z,c|d,b|f,z|z,z|e,b|f,a|f,c|e,c|f,a|z,z|z,b|d,z|d,b|z,c|d,z|f,
|
||||
b|e,a|f,a|d,b|e,b|d,c|z,c|e,a|d,c|z,z|e,z|f,c|f,a|e,z|d,b|z,a|e,
|
||||
b|z,a|e,a|z,b|f,b|f,c|d,c|d,z|d,a|d,b|z,b|e,a|z,c|e,z|f,a|f,c|e,
|
||||
z|f,b|d,c|f,c|z,a|e,z|z,z|d,c|f,z|z,a|f,c|z,z|e,b|d,b|e,z|e,a|d];
|
||||
a=1<<18; b=1<<28; c=a|b; d=1<<6; e=1<<12; f=d|e;
|
||||
SP8 = [b|f,z|e,a|z,c|f,b|z,b|f,z|d,b|z,a|d,c|z,c|f,a|e,c|e,a|f,z|e,z|d,
|
||||
c|z,b|d,b|e,z|f,a|e,a|d,c|d,c|e,z|f,z|z,z|z,c|d,b|d,b|e,a|f,a|z,
|
||||
a|f,a|z,c|e,z|e,z|d,c|d,z|e,a|f,b|e,z|d,b|d,c|z,c|d,b|z,a|z,b|f,
|
||||
z|z,c|f,a|d,b|d,c|z,b|e,b|f,z|z,c|f,a|e,a|e,z|f,z|f,a|d,b|z,c|e];
|
||||
// jshint +W013,+W015
|
||||
|
||||
// Set the key.
|
||||
function setKeys(keyBlock) {
|
||||
var i, j, l, m, n, o, pc1m = [], pcr = [], kn = [],
|
||||
raw0, raw1, rawi, KnLi;
|
||||
// Set the key.
|
||||
function setKeys(keyBlock) {
|
||||
var i, j, l, m, n, o, pc1m = [], pcr = [], kn = [],
|
||||
raw0, raw1, rawi, KnLi;
|
||||
|
||||
for (j = 0, l = 56; j < 56; ++j, l-=8) {
|
||||
l += l<-5 ? 65 : l<-3 ? 31 : l<-1 ? 63 : l===27 ? 35 : 0; // PC1
|
||||
m = l & 0x7;
|
||||
pc1m[j] = ((keyBlock[l >>> 3] & (1<<m)) !== 0) ? 1: 0;
|
||||
}
|
||||
for (j = 0, l = 56; j < 56; ++j, l -= 8) {
|
||||
l += l < -5 ? 65 : l < -3 ? 31 : l < -1 ? 63 : l === 27 ? 35 : 0; // PC1
|
||||
m = l & 0x7;
|
||||
pc1m[j] = ((keyBlock[l >>> 3] & (1<<m)) !== 0) ? 1: 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
m = i << 1;
|
||||
n = m + 1;
|
||||
kn[m] = kn[n] = 0;
|
||||
for (o=28; o<59; o+=28) {
|
||||
for (j = o-28; j < o; ++j) {
|
||||
l = j + totrot[i];
|
||||
if (l < o) {
|
||||
pcr[j] = pc1m[l];
|
||||
} else {
|
||||
pcr[j] = pc1m[l - 28];
|
||||
for (i = 0; i < 16; ++i) {
|
||||
m = i << 1;
|
||||
n = m + 1;
|
||||
kn[m] = kn[n] = 0;
|
||||
for (o = 28; o < 59; o += 28) {
|
||||
for (j = o - 28; j < o; ++j) {
|
||||
l = j + totrot[i];
|
||||
if (l < o) {
|
||||
pcr[j] = pc1m[l];
|
||||
} else {
|
||||
pcr[j] = pc1m[l - 28];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (j = 0; j < 24; ++j) {
|
||||
if (pcr[PC2[j]] !== 0) {
|
||||
kn[m] |= 1 << (23 - j);
|
||||
}
|
||||
if (pcr[PC2[j + 24]] !== 0) {
|
||||
kn[n] |= 1 << (23 - j);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (j = 0; j < 24; ++j) {
|
||||
if (pcr[PC2[j]] !== 0) {
|
||||
kn[m] |= 1<<(23-j);
|
||||
}
|
||||
if (pcr[PC2[j + 24]] !== 0) {
|
||||
kn[n] |= 1<<(23-j);
|
||||
}
|
||||
|
||||
// cookey
|
||||
for (i = 0, rawi = 0, KnLi = 0; i < 16; ++i) {
|
||||
raw0 = kn[rawi++];
|
||||
raw1 = kn[rawi++];
|
||||
keys[KnLi] = (raw0 & 0x00fc0000) << 6;
|
||||
keys[KnLi] |= (raw0 & 0x00000fc0) << 10;
|
||||
keys[KnLi] |= (raw1 & 0x00fc0000) >>> 10;
|
||||
keys[KnLi] |= (raw1 & 0x00000fc0) >>> 6;
|
||||
++KnLi;
|
||||
keys[KnLi] = (raw0 & 0x0003f000) << 12;
|
||||
keys[KnLi] |= (raw0 & 0x0000003f) << 16;
|
||||
keys[KnLi] |= (raw1 & 0x0003f000) >>> 4;
|
||||
keys[KnLi] |= (raw1 & 0x0000003f);
|
||||
++KnLi;
|
||||
}
|
||||
}
|
||||
|
||||
// cookey
|
||||
for (i = 0, rawi = 0, KnLi = 0; i < 16; ++i) {
|
||||
raw0 = kn[rawi++];
|
||||
raw1 = kn[rawi++];
|
||||
keys[KnLi] = (raw0 & 0x00fc0000) << 6;
|
||||
keys[KnLi] |= (raw0 & 0x00000fc0) << 10;
|
||||
keys[KnLi] |= (raw1 & 0x00fc0000) >>> 10;
|
||||
keys[KnLi] |= (raw1 & 0x00000fc0) >>> 6;
|
||||
++KnLi;
|
||||
keys[KnLi] = (raw0 & 0x0003f000) << 12;
|
||||
keys[KnLi] |= (raw0 & 0x0000003f) << 16;
|
||||
keys[KnLi] |= (raw1 & 0x0003f000) >>> 4;
|
||||
keys[KnLi] |= (raw1 & 0x0000003f);
|
||||
++KnLi;
|
||||
}
|
||||
}
|
||||
// Encrypt 8 bytes of text
|
||||
function enc8(text) {
|
||||
var i = 0, b = text.slice(), fval, keysi = 0,
|
||||
l, r, x; // left, right, accumulator
|
||||
|
||||
// Encrypt 8 bytes of text
|
||||
function enc8(text) {
|
||||
var i = 0, b = text.slice(), fval, keysi = 0,
|
||||
l, r, x; // left, right, accumulator
|
||||
// Squash 8 bytes to 2 ints
|
||||
l = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++];
|
||||
r = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++];
|
||||
|
||||
// Squash 8 bytes to 2 ints
|
||||
l = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++];
|
||||
r = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++];
|
||||
x = ((l >>> 4) ^ r) & 0x0f0f0f0f;
|
||||
r ^= x;
|
||||
l ^= (x << 4);
|
||||
x = ((l >>> 16) ^ r) & 0x0000ffff;
|
||||
r ^= x;
|
||||
l ^= (x << 16);
|
||||
x = ((r >>> 2) ^ l) & 0x33333333;
|
||||
l ^= x;
|
||||
r ^= (x << 2);
|
||||
x = ((r >>> 8) ^ l) & 0x00ff00ff;
|
||||
l ^= x;
|
||||
r ^= (x << 8);
|
||||
r = (r << 1) | ((r >>> 31) & 1);
|
||||
x = (l ^ r) & 0xaaaaaaaa;
|
||||
l ^= x;
|
||||
r ^= x;
|
||||
l = (l << 1) | ((l >>> 31) & 1);
|
||||
|
||||
x = ((l >>> 4) ^ r) & 0x0f0f0f0f;
|
||||
r ^= x;
|
||||
l ^= (x << 4);
|
||||
x = ((l >>> 16) ^ r) & 0x0000ffff;
|
||||
r ^= x;
|
||||
l ^= (x << 16);
|
||||
x = ((r >>> 2) ^ l) & 0x33333333;
|
||||
l ^= x;
|
||||
r ^= (x << 2);
|
||||
x = ((r >>> 8) ^ l) & 0x00ff00ff;
|
||||
l ^= x;
|
||||
r ^= (x << 8);
|
||||
r = (r << 1) | ((r >>> 31) & 1);
|
||||
x = (l ^ r) & 0xaaaaaaaa;
|
||||
l ^= x;
|
||||
r ^= x;
|
||||
l = (l << 1) | ((l >>> 31) & 1);
|
||||
for (i = 0; i < 8; ++i) {
|
||||
x = (r << 28) | (r >>> 4);
|
||||
x ^= keys[keysi++];
|
||||
fval = SP7[x & 0x3f];
|
||||
fval |= SP5[(x >>> 8) & 0x3f];
|
||||
fval |= SP3[(x >>> 16) & 0x3f];
|
||||
fval |= SP1[(x >>> 24) & 0x3f];
|
||||
x = r ^ keys[keysi++];
|
||||
fval |= SP8[x & 0x3f];
|
||||
fval |= SP6[(x >>> 8) & 0x3f];
|
||||
fval |= SP4[(x >>> 16) & 0x3f];
|
||||
fval |= SP2[(x >>> 24) & 0x3f];
|
||||
l ^= fval;
|
||||
x = (l << 28) | (l >>> 4);
|
||||
x ^= keys[keysi++];
|
||||
fval = SP7[x & 0x3f];
|
||||
fval |= SP5[(x >>> 8) & 0x3f];
|
||||
fval |= SP3[(x >>> 16) & 0x3f];
|
||||
fval |= SP1[(x >>> 24) & 0x3f];
|
||||
x = l ^ keys[keysi++];
|
||||
fval |= SP8[x & 0x0000003f];
|
||||
fval |= SP6[(x >>> 8) & 0x3f];
|
||||
fval |= SP4[(x >>> 16) & 0x3f];
|
||||
fval |= SP2[(x >>> 24) & 0x3f];
|
||||
r ^= fval;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
x = (r << 28) | (r >>> 4);
|
||||
x ^= keys[keysi++];
|
||||
fval = SP7[x & 0x3f];
|
||||
fval |= SP5[(x >>> 8) & 0x3f];
|
||||
fval |= SP3[(x >>> 16) & 0x3f];
|
||||
fval |= SP1[(x >>> 24) & 0x3f];
|
||||
x = r ^ keys[keysi++];
|
||||
fval |= SP8[x & 0x3f];
|
||||
fval |= SP6[(x >>> 8) & 0x3f];
|
||||
fval |= SP4[(x >>> 16) & 0x3f];
|
||||
fval |= SP2[(x >>> 24) & 0x3f];
|
||||
l ^= fval;
|
||||
x = (l << 28) | (l >>> 4);
|
||||
x ^= keys[keysi++];
|
||||
fval = SP7[x & 0x3f];
|
||||
fval |= SP5[(x >>> 8) & 0x3f];
|
||||
fval |= SP3[(x >>> 16) & 0x3f];
|
||||
fval |= SP1[(x >>> 24) & 0x3f];
|
||||
x = l ^ keys[keysi++];
|
||||
fval |= SP8[x & 0x0000003f];
|
||||
fval |= SP6[(x >>> 8) & 0x3f];
|
||||
fval |= SP4[(x >>> 16) & 0x3f];
|
||||
fval |= SP2[(x >>> 24) & 0x3f];
|
||||
r ^= fval;
|
||||
r = (r << 31) | (r >>> 1);
|
||||
x = (l ^ r) & 0xaaaaaaaa;
|
||||
l ^= x;
|
||||
r ^= x;
|
||||
l = (l << 31) | (l >>> 1);
|
||||
x = ((l >>> 8) ^ r) & 0x00ff00ff;
|
||||
r ^= x;
|
||||
l ^= (x << 8);
|
||||
x = ((l >>> 2) ^ r) & 0x33333333;
|
||||
r ^= x;
|
||||
l ^= (x << 2);
|
||||
x = ((r >>> 16) ^ l) & 0x0000ffff;
|
||||
l ^= x;
|
||||
r ^= (x << 16);
|
||||
x = ((r >>> 4) ^ l) & 0x0f0f0f0f;
|
||||
l ^= x;
|
||||
r ^= (x << 4);
|
||||
|
||||
// Spread ints to bytes
|
||||
x = [r, l];
|
||||
for (i = 0; i < 8; i++) {
|
||||
b[i] = (x[i>>>2] >>> (8 * (3 - (i % 4)))) % 256;
|
||||
if (b[i] < 0) { b[i] += 256; } // unsigned
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
r = (r << 31) | (r >>> 1);
|
||||
x = (l ^ r) & 0xaaaaaaaa;
|
||||
l ^= x;
|
||||
r ^= x;
|
||||
l = (l << 31) | (l >>> 1);
|
||||
x = ((l >>> 8) ^ r) & 0x00ff00ff;
|
||||
r ^= x;
|
||||
l ^= (x << 8);
|
||||
x = ((l >>> 2) ^ r) & 0x33333333;
|
||||
r ^= x;
|
||||
l ^= (x << 2);
|
||||
x = ((r >>> 16) ^ l) & 0x0000ffff;
|
||||
l ^= x;
|
||||
r ^= (x << 16);
|
||||
x = ((r >>> 4) ^ l) & 0x0f0f0f0f;
|
||||
l ^= x;
|
||||
r ^= (x << 4);
|
||||
|
||||
// Spread ints to bytes
|
||||
x = [r, l];
|
||||
for (i = 0; i < 8; i++) {
|
||||
b[i] = (x[i>>>2] >>> (8*(3 - (i%4)))) % 256;
|
||||
if (b[i] < 0) { b[i] += 256; } // unsigned
|
||||
// Encrypt 16 bytes of text using passwd as key
|
||||
function encrypt(t) {
|
||||
return enc8(t.slice(0, 8)).concat(enc8(t.slice(8, 16)));
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
// Encrypt 16 bytes of text using passwd as key
|
||||
function encrypt(t) {
|
||||
return enc8(t.slice(0,8)).concat(enc8(t.slice(8,16)));
|
||||
}
|
||||
|
||||
setKeys(passwd); // Setup keys
|
||||
return {'encrypt': encrypt}; // Public interface
|
||||
setKeys(passwd); // Setup keys
|
||||
return {'encrypt': encrypt}; // Public interface
|
||||
|
||||
} // function DES
|
||||
|
||||
+705
-729
File diff suppressed because it is too large
Load Diff
+350
-363
@@ -5,397 +5,384 @@
|
||||
* Licensed under MPL 2.0 or any later version (see LICENSE.txt)
|
||||
*/
|
||||
|
||||
/*jslint browser: true, white: false, bitwise: false */
|
||||
/*jslint browser: true, white: false */
|
||||
/*global window, Util */
|
||||
|
||||
var Keyboard, Mouse;
|
||||
|
||||
//
|
||||
// Keyboard event handler
|
||||
//
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function Keyboard(defaults) {
|
||||
"use strict";
|
||||
//
|
||||
// Keyboard event handler
|
||||
//
|
||||
|
||||
var that = {}, // Public API methods
|
||||
conf = {}, // Configuration attributes
|
||||
Keyboard = function (defaults) {
|
||||
this._keyDownList = []; // List of depressed keys
|
||||
// (even if they are happy)
|
||||
|
||||
keyDownList = []; // List of depressed keys
|
||||
// (even if they are happy)
|
||||
Util.set_defaults(this, defaults, {
|
||||
'target': document,
|
||||
'focused': true
|
||||
});
|
||||
|
||||
// Configuration attributes
|
||||
Util.conf_defaults(conf, that, defaults, [
|
||||
['target', 'wo', 'dom', document, 'DOM element that captures keyboard input'],
|
||||
['focused', 'rw', 'bool', true, 'Capture and send key events'],
|
||||
// create the keyboard handler
|
||||
this._handler = new KeyEventDecoder(kbdUtil.ModifierSync(),
|
||||
VerifyCharModifier( /* jshint newcap: false */
|
||||
TrackKeyState(
|
||||
EscapeModifiers(this._handleRfbEvent.bind(this))
|
||||
)
|
||||
)
|
||||
); /* jshint newcap: true */
|
||||
|
||||
['onKeyPress', 'rw', 'func', null, 'Handler for key press/release']
|
||||
]);
|
||||
// keep these here so we can refer to them later
|
||||
this._eventHandlers = {
|
||||
'keyup': this._handleKeyUp.bind(this),
|
||||
'keydown': this._handleKeyDown.bind(this),
|
||||
'keypress': this._handleKeyPress.bind(this),
|
||||
'blur': this._allKeysUp.bind(this)
|
||||
};
|
||||
};
|
||||
|
||||
Keyboard.prototype = {
|
||||
// private methods
|
||||
|
||||
//
|
||||
// Private functions
|
||||
//
|
||||
|
||||
/////// setup
|
||||
|
||||
function onRfbEvent(evt) {
|
||||
if (conf.onKeyPress) {
|
||||
Util.Debug("onKeyPress " + (evt.type == 'keydown' ? "down" : "up")
|
||||
+ ", keysym: " + evt.keysym.keysym + "(" + evt.keysym.keyname + ")");
|
||||
conf.onKeyPress(evt.keysym.keysym, evt.type == 'keydown');
|
||||
}
|
||||
}
|
||||
|
||||
// create the keyboard handler
|
||||
var k = KeyEventDecoder(kbdUtil.ModifierSync(),
|
||||
VerifyCharModifier(
|
||||
TrackKeyState(
|
||||
EscapeModifiers(onRfbEvent)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
function onKeyDown(e) {
|
||||
if (! conf.focused) {
|
||||
return true;
|
||||
}
|
||||
if (k.keydown(e)) {
|
||||
// Suppress bubbling/default actions
|
||||
Util.stopEvent(e);
|
||||
return false;
|
||||
} else {
|
||||
// Allow the event to bubble and become a keyPress event which
|
||||
// will have the character code translated
|
||||
return true;
|
||||
}
|
||||
}
|
||||
function onKeyPress(e) {
|
||||
if (! conf.focused) {
|
||||
return true;
|
||||
}
|
||||
if (k.keypress(e)) {
|
||||
// Suppress bubbling/default actions
|
||||
Util.stopEvent(e);
|
||||
return false;
|
||||
} else {
|
||||
// Allow the event to bubble and become a keyPress event which
|
||||
// will have the character code translated
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function onKeyUp(e) {
|
||||
if (! conf.focused) {
|
||||
return true;
|
||||
}
|
||||
if (k.keyup(e)) {
|
||||
// Suppress bubbling/default actions
|
||||
Util.stopEvent(e);
|
||||
return false;
|
||||
} else {
|
||||
// Allow the event to bubble and become a keyPress event which
|
||||
// will have the character code translated
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function onOther(e) {
|
||||
k.syncModifiers(e);
|
||||
}
|
||||
|
||||
function allKeysUp() {
|
||||
Util.Debug(">> Keyboard.allKeysUp");
|
||||
|
||||
k.releaseAll();
|
||||
Util.Debug("<< Keyboard.allKeysUp");
|
||||
}
|
||||
|
||||
//
|
||||
// Public API interface functions
|
||||
//
|
||||
|
||||
that.grab = function() {
|
||||
//Util.Debug(">> Keyboard.grab");
|
||||
var c = conf.target;
|
||||
|
||||
Util.addEvent(c, 'keydown', onKeyDown);
|
||||
Util.addEvent(c, 'keyup', onKeyUp);
|
||||
Util.addEvent(c, 'keypress', onKeyPress);
|
||||
|
||||
// Release (key up) if window loses focus
|
||||
Util.addEvent(window, 'blur', allKeysUp);
|
||||
|
||||
//Util.Debug("<< Keyboard.grab");
|
||||
};
|
||||
|
||||
that.ungrab = function() {
|
||||
//Util.Debug(">> Keyboard.ungrab");
|
||||
var c = conf.target;
|
||||
|
||||
Util.removeEvent(c, 'keydown', onKeyDown);
|
||||
Util.removeEvent(c, 'keyup', onKeyUp);
|
||||
Util.removeEvent(c, 'keypress', onKeyPress);
|
||||
Util.removeEvent(window, 'blur', allKeysUp);
|
||||
|
||||
// Release (key up) all keys that are in a down state
|
||||
allKeysUp();
|
||||
|
||||
//Util.Debug(">> Keyboard.ungrab");
|
||||
};
|
||||
|
||||
that.sync = function(e) {
|
||||
k.syncModifiers(e);
|
||||
}
|
||||
|
||||
return that; // Return the public API interface
|
||||
|
||||
} // End of Keyboard()
|
||||
|
||||
|
||||
//
|
||||
// Mouse event handler
|
||||
//
|
||||
|
||||
function Mouse(defaults) {
|
||||
"use strict";
|
||||
|
||||
var that = {}, // Public API methods
|
||||
conf = {}, // Configuration attributes
|
||||
mouseCaptured = false;
|
||||
|
||||
var doubleClickTimer = null,
|
||||
lastTouchPos = null;
|
||||
|
||||
// Configuration attributes
|
||||
Util.conf_defaults(conf, that, defaults, [
|
||||
['target', 'ro', 'dom', document, 'DOM element that captures mouse input'],
|
||||
['notify', 'ro', 'func', null, 'Function to call to notify whenever a mouse event is received'],
|
||||
['focused', 'rw', 'bool', true, 'Capture and send mouse clicks/movement'],
|
||||
['scale', 'rw', 'float', 1.0, 'Viewport scale factor 0.0 - 1.0'],
|
||||
|
||||
['onMouseButton', 'rw', 'func', null, 'Handler for mouse button click/release'],
|
||||
['onMouseMove', 'rw', 'func', null, 'Handler for mouse movement'],
|
||||
['touchButton', 'rw', 'int', 1, 'Button mask (1, 2, 4) for touch devices (0 means ignore clicks)']
|
||||
]);
|
||||
|
||||
function captureMouse() {
|
||||
// capturing the mouse ensures we get the mouseup event
|
||||
if (conf.target.setCapture) {
|
||||
conf.target.setCapture();
|
||||
}
|
||||
|
||||
// some browsers give us mouseup events regardless,
|
||||
// so if we never captured the mouse, we can disregard the event
|
||||
mouseCaptured = true;
|
||||
}
|
||||
|
||||
function releaseMouse() {
|
||||
if (conf.target.releaseCapture) {
|
||||
conf.target.releaseCapture();
|
||||
}
|
||||
mouseCaptured = false;
|
||||
}
|
||||
//
|
||||
// Private functions
|
||||
//
|
||||
|
||||
function resetDoubleClickTimer() {
|
||||
doubleClickTimer = null;
|
||||
}
|
||||
|
||||
function onMouseButton(e, down) {
|
||||
var evt, pos, bmask;
|
||||
if (! conf.focused) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (conf.notify) {
|
||||
conf.notify(e);
|
||||
}
|
||||
|
||||
evt = (e ? e : window.event);
|
||||
pos = Util.getEventPosition(e, conf.target, conf.scale);
|
||||
|
||||
if (e.touches || e.changedTouches) {
|
||||
// Touch device
|
||||
|
||||
// When two touches occur within 500 ms of each other and are
|
||||
// closer than 20 pixels together a double click is triggered.
|
||||
if (down == 1) {
|
||||
if (doubleClickTimer == null) {
|
||||
lastTouchPos = pos;
|
||||
} else {
|
||||
clearTimeout(doubleClickTimer);
|
||||
|
||||
// When the distance between the two touches is small enough
|
||||
// force the position of the latter touch to the position of
|
||||
// the first.
|
||||
|
||||
var xs = lastTouchPos.x - pos.x;
|
||||
var ys = lastTouchPos.y - pos.y;
|
||||
var d = Math.sqrt((xs * xs) + (ys * ys));
|
||||
|
||||
// The goal is to trigger on a certain physical width, the
|
||||
// devicePixelRatio brings us a bit closer but is not optimal.
|
||||
if (d < 20 * window.devicePixelRatio) {
|
||||
pos = lastTouchPos;
|
||||
}
|
||||
_handleRfbEvent: function (e) {
|
||||
if (this._onKeyPress) {
|
||||
Util.Debug("onKeyPress " + (e.type == 'keydown' ? "down" : "up") +
|
||||
", keysym: " + e.keysym.keysym + "(" + e.keysym.keyname + ")");
|
||||
this._onKeyPress(e.keysym.keysym, e.type == 'keydown');
|
||||
}
|
||||
doubleClickTimer = setTimeout(resetDoubleClickTimer, 500);
|
||||
},
|
||||
|
||||
_handleKeyDown: function (e) {
|
||||
if (!this._focused) { return true; }
|
||||
|
||||
if (this._handler.keydown(e)) {
|
||||
// Suppress bubbling/default actions
|
||||
Util.stopEvent(e);
|
||||
return false;
|
||||
} else {
|
||||
// Allow the event to bubble and become a keyPress event which
|
||||
// will have the character code translated
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
_handleKeyPress: function (e) {
|
||||
if (!this._focused) { return true; }
|
||||
|
||||
if (this._handler.keypress(e)) {
|
||||
// Suppress bubbling/default actions
|
||||
Util.stopEvent(e);
|
||||
return false;
|
||||
} else {
|
||||
// Allow the event to bubble and become a keyPress event which
|
||||
// will have the character code translated
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
_handleKeyUp: function (e) {
|
||||
if (!this._focused) { return true; }
|
||||
|
||||
if (this._handler.keyup(e)) {
|
||||
// Suppress bubbling/default actions
|
||||
Util.stopEvent(e);
|
||||
return false;
|
||||
} else {
|
||||
// Allow the event to bubble and become a keyPress event which
|
||||
// will have the character code translated
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
_allKeysUp: function () {
|
||||
Util.Debug(">> Keyboard.allKeysUp");
|
||||
this._handler.releaseAll();
|
||||
Util.Debug("<< Keyboard.allKeysUp");
|
||||
},
|
||||
|
||||
// Public methods
|
||||
|
||||
grab: function () {
|
||||
//Util.Debug(">> Keyboard.grab");
|
||||
var c = this._target;
|
||||
|
||||
Util.addEvent(c, 'keydown', this._eventHandlers.keydown);
|
||||
Util.addEvent(c, 'keyup', this._eventHandlers.keyup);
|
||||
Util.addEvent(c, 'keypress', this._eventHandlers.keypress);
|
||||
|
||||
// Release (key up) if window loses focus
|
||||
Util.addEvent(window, 'blur', this._eventHandlers.blur);
|
||||
|
||||
//Util.Debug("<< Keyboard.grab");
|
||||
},
|
||||
|
||||
ungrab: function () {
|
||||
//Util.Debug(">> Keyboard.ungrab");
|
||||
var c = this._target;
|
||||
|
||||
Util.removeEvent(c, 'keydown', this._eventHandlers.keydown);
|
||||
Util.removeEvent(c, 'keyup', this._eventHandlers.keyup);
|
||||
Util.removeEvent(c, 'keypress', this._eventHandlers.keypress);
|
||||
Util.removeEvent(window, 'blur', this._eventHandlers.blur);
|
||||
|
||||
// Release (key up) all keys that are in a down state
|
||||
this._allKeysUp();
|
||||
|
||||
//Util.Debug(">> Keyboard.ungrab");
|
||||
},
|
||||
|
||||
sync: function (e) {
|
||||
this._handler.syncModifiers(e);
|
||||
}
|
||||
bmask = conf.touchButton;
|
||||
// If bmask is set
|
||||
} else if (evt.which) {
|
||||
/* everything except IE */
|
||||
bmask = 1 << evt.button;
|
||||
} else {
|
||||
/* IE including 9 */
|
||||
bmask = (evt.button & 0x1) + // Left
|
||||
(evt.button & 0x2) * 2 + // Right
|
||||
(evt.button & 0x4) / 2; // Middle
|
||||
}
|
||||
//Util.Debug("mouse " + pos.x + "," + pos.y + " down: " + down +
|
||||
// " bmask: " + bmask + "(evt.button: " + evt.button + ")");
|
||||
if (conf.onMouseButton) {
|
||||
Util.Debug("onMouseButton " + (down ? "down" : "up") +
|
||||
", x: " + pos.x + ", y: " + pos.y + ", bmask: " + bmask);
|
||||
conf.onMouseButton(pos.x, pos.y, down, bmask);
|
||||
}
|
||||
Util.stopEvent(e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
function onMouseDown(e) {
|
||||
captureMouse();
|
||||
onMouseButton(e, 1);
|
||||
}
|
||||
Util.make_properties(Keyboard, [
|
||||
['target', 'wo', 'dom'], // DOM element that captures keyboard input
|
||||
['focused', 'rw', 'bool'], // Capture and send key events
|
||||
|
||||
function onMouseUp(e) {
|
||||
if (!mouseCaptured) {
|
||||
return;
|
||||
}
|
||||
['onKeyPress', 'rw', 'func'] // Handler for key press/release
|
||||
]);
|
||||
|
||||
onMouseButton(e, 0);
|
||||
releaseMouse();
|
||||
}
|
||||
//
|
||||
// Mouse event handler
|
||||
//
|
||||
|
||||
function onMouseWheel(e) {
|
||||
var evt, pos, bmask, wheelData;
|
||||
if (! conf.focused) {
|
||||
return true;
|
||||
}
|
||||
if (conf.notify) {
|
||||
conf.notify(e);
|
||||
}
|
||||
Mouse = function (defaults) {
|
||||
this._mouseCaptured = false;
|
||||
|
||||
evt = (e ? e : window.event);
|
||||
pos = Util.getEventPosition(e, conf.target, conf.scale);
|
||||
wheelData = evt.detail ? evt.detail * -1 : evt.wheelDelta / 40;
|
||||
if (wheelData > 0) {
|
||||
bmask = 1 << 3;
|
||||
} else {
|
||||
bmask = 1 << 4;
|
||||
}
|
||||
//Util.Debug('mouse scroll by ' + wheelData + ':' + pos.x + "," + pos.y);
|
||||
if (conf.onMouseButton) {
|
||||
conf.onMouseButton(pos.x, pos.y, 1, bmask);
|
||||
conf.onMouseButton(pos.x, pos.y, 0, bmask);
|
||||
}
|
||||
Util.stopEvent(e);
|
||||
return false;
|
||||
}
|
||||
this._doubleClickTimer = null;
|
||||
this._lastTouchPos = null;
|
||||
|
||||
function onMouseMove(e) {
|
||||
var evt, pos;
|
||||
if (! conf.focused) {
|
||||
return true;
|
||||
}
|
||||
if (conf.notify) {
|
||||
conf.notify(e);
|
||||
}
|
||||
// Configuration attributes
|
||||
Util.set_defaults(this, defaults, {
|
||||
'target': document,
|
||||
'focused': true,
|
||||
'scale': 1.0,
|
||||
'touchButton': 1
|
||||
});
|
||||
|
||||
evt = (e ? e : window.event);
|
||||
pos = Util.getEventPosition(e, conf.target, conf.scale);
|
||||
//Util.Debug('mouse ' + evt.which + '/' + evt.button + ' up:' + pos.x + "," + pos.y);
|
||||
if (conf.onMouseMove) {
|
||||
conf.onMouseMove(pos.x, pos.y);
|
||||
}
|
||||
Util.stopEvent(e);
|
||||
return false;
|
||||
}
|
||||
this._eventHandlers = {
|
||||
'mousedown': this._handleMouseDown.bind(this),
|
||||
'mouseup': this._handleMouseUp.bind(this),
|
||||
'mousemove': this._handleMouseMove.bind(this),
|
||||
'mousewheel': this._handleMouseWheel.bind(this),
|
||||
'mousedisable': this._handleMouseDisable.bind(this)
|
||||
};
|
||||
};
|
||||
|
||||
function onMouseDisable(e) {
|
||||
var evt, pos;
|
||||
if (! conf.focused) {
|
||||
return true;
|
||||
}
|
||||
evt = (e ? e : window.event);
|
||||
pos = Util.getEventPosition(e, conf.target, conf.scale);
|
||||
/* Stop propagation if inside canvas area */
|
||||
if ((pos.realx >= 0) && (pos.realy >= 0) &&
|
||||
(pos.realx < conf.target.offsetWidth) &&
|
||||
(pos.realy < conf.target.offsetHeight)) {
|
||||
//Util.Debug("mouse event disabled");
|
||||
Util.stopEvent(e);
|
||||
return false;
|
||||
}
|
||||
//Util.Debug("mouse event not disabled");
|
||||
return true;
|
||||
}
|
||||
Mouse.prototype = {
|
||||
// private methods
|
||||
_captureMouse: function () {
|
||||
// capturing the mouse ensures we get the mouseup event
|
||||
if (this._target.setCapture) {
|
||||
this._target.setCapture();
|
||||
}
|
||||
|
||||
//
|
||||
// Public API interface functions
|
||||
//
|
||||
// some browsers give us mouseup events regardless,
|
||||
// so if we never captured the mouse, we can disregard the event
|
||||
this._mouseCaptured = true;
|
||||
},
|
||||
|
||||
that.grab = function() {
|
||||
//Util.Debug(">> Mouse.grab");
|
||||
var c = conf.target;
|
||||
_releaseMouse: function () {
|
||||
if (this._target.releaseCapture) {
|
||||
this._target.releaseCapture();
|
||||
}
|
||||
this._mouseCaptured = false;
|
||||
},
|
||||
|
||||
if ('ontouchstart' in document.documentElement) {
|
||||
Util.addEvent(c, 'touchstart', onMouseDown);
|
||||
Util.addEvent(window, 'touchend', onMouseUp);
|
||||
Util.addEvent(c, 'touchend', onMouseUp);
|
||||
Util.addEvent(c, 'touchmove', onMouseMove);
|
||||
} else {
|
||||
Util.addEvent(c, 'mousedown', onMouseDown);
|
||||
Util.addEvent(window, 'mouseup', onMouseUp);
|
||||
Util.addEvent(c, 'mouseup', onMouseUp);
|
||||
Util.addEvent(c, 'mousemove', onMouseMove);
|
||||
Util.addEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel',
|
||||
onMouseWheel);
|
||||
}
|
||||
_resetDoubleClickTimer: function () {
|
||||
this._doubleClickTimer = null;
|
||||
},
|
||||
|
||||
/* Work around right and middle click browser behaviors */
|
||||
Util.addEvent(document, 'click', onMouseDisable);
|
||||
Util.addEvent(document.body, 'contextmenu', onMouseDisable);
|
||||
_handleMouseButton: function (e, down) {
|
||||
if (!this._focused) { return true; }
|
||||
|
||||
//Util.Debug("<< Mouse.grab");
|
||||
};
|
||||
if (this._notify) {
|
||||
this._notify(e);
|
||||
}
|
||||
|
||||
that.ungrab = function() {
|
||||
//Util.Debug(">> Mouse.ungrab");
|
||||
var c = conf.target;
|
||||
var evt = (e ? e : window.event);
|
||||
var pos = Util.getEventPosition(e, this._target, this._scale);
|
||||
|
||||
if ('ontouchstart' in document.documentElement) {
|
||||
Util.removeEvent(c, 'touchstart', onMouseDown);
|
||||
Util.removeEvent(window, 'touchend', onMouseUp);
|
||||
Util.removeEvent(c, 'touchend', onMouseUp);
|
||||
Util.removeEvent(c, 'touchmove', onMouseMove);
|
||||
} else {
|
||||
Util.removeEvent(c, 'mousedown', onMouseDown);
|
||||
Util.removeEvent(window, 'mouseup', onMouseUp);
|
||||
Util.removeEvent(c, 'mouseup', onMouseUp);
|
||||
Util.removeEvent(c, 'mousemove', onMouseMove);
|
||||
Util.removeEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel',
|
||||
onMouseWheel);
|
||||
}
|
||||
var bmask;
|
||||
if (e.touches || e.changedTouches) {
|
||||
// Touch device
|
||||
|
||||
/* Work around right and middle click browser behaviors */
|
||||
Util.removeEvent(document, 'click', onMouseDisable);
|
||||
Util.removeEvent(document.body, 'contextmenu', onMouseDisable);
|
||||
// When two touches occur within 500 ms of each other and are
|
||||
// closer than 20 pixels together a double click is triggered.
|
||||
if (down == 1) {
|
||||
if (this._doubleClickTimer === null) {
|
||||
this._lastTouchPos = pos;
|
||||
} else {
|
||||
clearTimeout(this._doubleClickTimer);
|
||||
|
||||
//Util.Debug(">> Mouse.ungrab");
|
||||
};
|
||||
// When the distance between the two touches is small enough
|
||||
// force the position of the latter touch to the position of
|
||||
// the first.
|
||||
|
||||
return that; // Return the public API interface
|
||||
var xs = this._lastTouchPos.x - pos.x;
|
||||
var ys = this._lastTouchPos.y - pos.y;
|
||||
var d = Math.sqrt((xs * xs) + (ys * ys));
|
||||
|
||||
} // End of Mouse()
|
||||
// The goal is to trigger on a certain physical width, the
|
||||
// devicePixelRatio brings us a bit closer but is not optimal.
|
||||
if (d < 20 * window.devicePixelRatio) {
|
||||
pos = this._lastTouchPos;
|
||||
}
|
||||
}
|
||||
this._doubleClickTimer = setTimeout(this._resetDoubleClickTimer.bind(this), 500);
|
||||
}
|
||||
bmask = this._touchButton;
|
||||
// If bmask is set
|
||||
} else if (evt.which) {
|
||||
/* everything except IE */
|
||||
bmask = 1 << evt.button;
|
||||
} else {
|
||||
/* IE including 9 */
|
||||
bmask = (evt.button & 0x1) + // Left
|
||||
(evt.button & 0x2) * 2 + // Right
|
||||
(evt.button & 0x4) / 2; // Middle
|
||||
}
|
||||
|
||||
if (this._onMouseButton) {
|
||||
Util.Debug("onMouseButton " + (down ? "down" : "up") +
|
||||
", x: " + pos.x + ", y: " + pos.y + ", bmask: " + bmask);
|
||||
this._onMouseButton(pos.x, pos.y, down, bmask);
|
||||
}
|
||||
Util.stopEvent(e);
|
||||
return false;
|
||||
},
|
||||
|
||||
_handleMouseDown: function (e) {
|
||||
this._captureMouse();
|
||||
this._handleMouseButton(e, 1);
|
||||
},
|
||||
|
||||
_handleMouseUp: function (e) {
|
||||
if (!this._mouseCaptured) { return; }
|
||||
|
||||
this._handleMouseButton(e, 0);
|
||||
this._releaseMouse();
|
||||
},
|
||||
|
||||
_handleMouseWheel: function (e) {
|
||||
if (!this._focused) { return true; }
|
||||
|
||||
if (this._notify) {
|
||||
this._notify(e);
|
||||
}
|
||||
|
||||
var evt = (e ? e : window.event);
|
||||
var pos = Util.getEventPosition(e, this._target, this._scale);
|
||||
var wheelData = evt.detail ? evt.detail * -1 : evt.wheelDelta / 40;
|
||||
var bmask;
|
||||
if (wheelData > 0) {
|
||||
bmask = 1 << 3;
|
||||
} else {
|
||||
bmask = 1 << 4;
|
||||
}
|
||||
|
||||
if (this._onMouseButton) {
|
||||
this._onMouseButton(pos.x, pos.y, 1, bmask);
|
||||
this._onMouseButton(pos.x, pos.y, 0, bmask);
|
||||
}
|
||||
Util.stopEvent(e);
|
||||
return false;
|
||||
},
|
||||
|
||||
_handleMouseMove: function (e) {
|
||||
if (! this._focused) { return true; }
|
||||
|
||||
if (this._notify) {
|
||||
this._notify(e);
|
||||
}
|
||||
|
||||
var evt = (e ? e : window.event);
|
||||
var pos = Util.getEventPosition(e, this._target, this._scale);
|
||||
if (this._onMouseMove) {
|
||||
this._onMouseMove(pos.x, pos.y);
|
||||
}
|
||||
Util.stopEvent(e);
|
||||
return false;
|
||||
},
|
||||
|
||||
_handleMouseDisable: function (e) {
|
||||
if (!this._focused) { return true; }
|
||||
|
||||
var evt = (e ? e : window.event);
|
||||
var pos = Util.getEventPosition(e, this._target, this._scale);
|
||||
|
||||
/* Stop propagation if inside canvas area */
|
||||
if ((pos.realx >= 0) && (pos.realy >= 0) &&
|
||||
(pos.realx < this._target.offsetWidth) &&
|
||||
(pos.realy < this._target.offsetHeight)) {
|
||||
//Util.Debug("mouse event disabled");
|
||||
Util.stopEvent(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
|
||||
// Public methods
|
||||
grab: function () {
|
||||
var c = this._target;
|
||||
|
||||
if ('ontouchstart' in document.documentElement) {
|
||||
Util.addEvent(c, 'touchstart', this._eventHandlers.mousedown);
|
||||
Util.addEvent(window, 'touchend', this._eventHandlers.mouseup);
|
||||
Util.addEvent(c, 'touchend', this._eventHandlers.mouseup);
|
||||
Util.addEvent(c, 'touchmove', this._eventHandlers.mousemove);
|
||||
} else {
|
||||
Util.addEvent(c, 'mousedown', this._eventHandlers.mousedown);
|
||||
Util.addEvent(window, 'mouseup', this._eventHandlers.mouseup);
|
||||
Util.addEvent(c, 'mouseup', this._eventHandlers.mouseup);
|
||||
Util.addEvent(c, 'mousemove', this._eventHandlers.mousemove);
|
||||
Util.addEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel',
|
||||
this._eventHandlers.mousewheel);
|
||||
}
|
||||
|
||||
/* Work around right and middle click browser behaviors */
|
||||
Util.addEvent(document, 'click', this._eventHandlers.mousedisable);
|
||||
Util.addEvent(document.body, 'contextmenu', this._eventHandlers.mousedisable);
|
||||
},
|
||||
|
||||
ungrab: function () {
|
||||
var c = this._target;
|
||||
|
||||
if ('ontouchstart' in document.documentElement) {
|
||||
Util.removeEvent(c, 'touchstart', this._eventHandlers.mousedown);
|
||||
Util.removeEvent(window, 'touchend', this._eventHandlers.mouseup);
|
||||
Util.removeEvent(c, 'touchend', this._eventHandlers.mouseup);
|
||||
Util.removeEvent(c, 'touchmove', this._eventHandlers.mousemove);
|
||||
} else {
|
||||
Util.removeEvent(c, 'mousedown', this._eventHandlers.mousedown);
|
||||
Util.removeEvent(window, 'mouseup', this._eventHandlers.mouseup);
|
||||
Util.removeEvent(c, 'mouseup', this._eventHandlers.mouseup);
|
||||
Util.removeEvent(c, 'mousemove', this._eventHandlers.mousemove);
|
||||
Util.removeEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel',
|
||||
this._eventHandlers.mousewheel);
|
||||
}
|
||||
|
||||
/* Work around right and middle click browser behaviors */
|
||||
Util.removeEvent(document, 'click', this._eventHandlers.mousedisable);
|
||||
Util.removeEvent(document.body, 'contextmenu', this._eventHandlers.mousedisable);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
Util.make_properties(Mouse, [
|
||||
['target', 'ro', 'dom'], // DOM element that captures mouse input
|
||||
['notify', 'ro', 'func'], // Function to call to notify whenever a mouse event is received
|
||||
['focused', 'rw', 'bool'], // Capture and send mouse clicks/movement
|
||||
['scale', 'rw', 'float'], // Viewport scale factor 0.0 - 1.0
|
||||
|
||||
['onMouseButton', 'rw', 'func'], // Handler for mouse button click/release
|
||||
['onMouseMove', 'rw', 'func'], // Handler for mouse movement
|
||||
['touchButton', 'rw', 'int'] // Button mask (1, 2, 4) for touch devices (0 means ignore clicks)
|
||||
]);
|
||||
})();
|
||||
|
||||
+99
-84
@@ -15,23 +15,23 @@ var kbdUtil = (function() {
|
||||
|
||||
var sub = substitutions[cp];
|
||||
return sub ? sub : cp;
|
||||
};
|
||||
}
|
||||
|
||||
function isMac() {
|
||||
return navigator && !!(/macintosh/i).exec(navigator.appVersion);
|
||||
return navigator && !!(/mac/i).exec(navigator.platform);
|
||||
}
|
||||
function isWindows() {
|
||||
return navigator && !!(/windows/i).exec(navigator.appVersion);
|
||||
return navigator && !!(/win/i).exec(navigator.platform);
|
||||
}
|
||||
function isLinux() {
|
||||
return navigator && !!(/linux/i).exec(navigator.appVersion);
|
||||
return navigator && !!(/linux/i).exec(navigator.platform);
|
||||
}
|
||||
|
||||
// Return true if a modifier which is not the specified char modifier (and is not shift) is down
|
||||
function hasShortcutModifier(charModifier, currentModifiers) {
|
||||
var mods = {};
|
||||
for (var key in currentModifiers) {
|
||||
if (parseInt(key) !== 0xffe1) {
|
||||
if (parseInt(key) !== XK_Shift_L) {
|
||||
mods[key] = currentModifiers[key];
|
||||
}
|
||||
}
|
||||
@@ -65,24 +65,18 @@ var kbdUtil = (function() {
|
||||
// Helper object tracking modifier key state
|
||||
// and generates fake key events to compensate if it gets out of sync
|
||||
function ModifierSync(charModifier) {
|
||||
var ctrl = 0xffe3;
|
||||
var alt = 0xffe9;
|
||||
var altGr = 0xfe03;
|
||||
var shift = 0xffe1;
|
||||
var meta = 0xffe7;
|
||||
|
||||
if (!charModifier) {
|
||||
if (isMac()) {
|
||||
// on Mac, Option (AKA Alt) is used as a char modifier
|
||||
charModifier = [alt];
|
||||
charModifier = [XK_Alt_L];
|
||||
}
|
||||
else if (isWindows()) {
|
||||
// on Windows, Ctrl+Alt is used as a char modifier
|
||||
charModifier = [alt, ctrl];
|
||||
charModifier = [XK_Alt_L, XK_Control_L];
|
||||
}
|
||||
else if (isLinux()) {
|
||||
// on Linux, AltGr is used as a char modifier
|
||||
charModifier = [altGr];
|
||||
// on Linux, ISO Level 3 Shift (AltGr) is used as a char modifier
|
||||
charModifier = [XK_ISO_Level3_Shift];
|
||||
}
|
||||
else {
|
||||
charModifier = [];
|
||||
@@ -90,11 +84,11 @@ var kbdUtil = (function() {
|
||||
}
|
||||
|
||||
var state = {};
|
||||
state[ctrl] = false;
|
||||
state[alt] = false;
|
||||
state[altGr] = false;
|
||||
state[shift] = false;
|
||||
state[meta] = false;
|
||||
state[XK_Control_L] = false;
|
||||
state[XK_Alt_L] = false;
|
||||
state[XK_ISO_Level3_Shift] = false;
|
||||
state[XK_Shift_L] = false;
|
||||
state[XK_Meta_L] = false;
|
||||
|
||||
function sync(evt, keysym) {
|
||||
var result = [];
|
||||
@@ -102,25 +96,30 @@ var kbdUtil = (function() {
|
||||
return {keysym: keysyms.lookup(keysym), type: state[keysym] ? 'keydown' : 'keyup'};
|
||||
}
|
||||
|
||||
if (evt.ctrlKey !== undefined && evt.ctrlKey !== state[ctrl] && keysym !== ctrl) {
|
||||
state[ctrl] = evt.ctrlKey;
|
||||
result.push(syncKey(ctrl));
|
||||
if (evt.ctrlKey !== undefined &&
|
||||
evt.ctrlKey !== state[XK_Control_L] && keysym !== XK_Control_L) {
|
||||
state[XK_Control_L] = evt.ctrlKey;
|
||||
result.push(syncKey(XK_Control_L));
|
||||
}
|
||||
if (evt.altKey !== undefined && evt.altKey !== state[alt] && keysym !== alt) {
|
||||
state[alt] = evt.altKey;
|
||||
result.push(syncKey(alt));
|
||||
if (evt.altKey !== undefined &&
|
||||
evt.altKey !== state[XK_Alt_L] && keysym !== XK_Alt_L) {
|
||||
state[XK_Alt_L] = evt.altKey;
|
||||
result.push(syncKey(XK_Alt_L));
|
||||
}
|
||||
if (evt.altGraphKey !== undefined && evt.altGraphKey !== state[altGr] && keysym !== altGr) {
|
||||
state[altGr] = evt.altGraphKey;
|
||||
result.push(syncKey(altGr));
|
||||
if (evt.altGraphKey !== undefined &&
|
||||
evt.altGraphKey !== state[XK_ISO_Level3_Shift] && keysym !== XK_ISO_Level3_Shift) {
|
||||
state[XK_ISO_Level3_Shift] = evt.altGraphKey;
|
||||
result.push(syncKey(XK_ISO_Level3_Shift));
|
||||
}
|
||||
if (evt.shiftKey !== undefined && evt.shiftKey !== state[shift] && keysym !== shift) {
|
||||
state[shift] = evt.shiftKey;
|
||||
result.push(syncKey(shift));
|
||||
if (evt.shiftKey !== undefined &&
|
||||
evt.shiftKey !== state[XK_Shift_L] && keysym !== XK_Shift_L) {
|
||||
state[XK_Shift_L] = evt.shiftKey;
|
||||
result.push(syncKey(XK_Shift_L));
|
||||
}
|
||||
if (evt.metaKey !== undefined && evt.metaKey !== state[meta] && keysym !== meta) {
|
||||
state[meta] = evt.metaKey;
|
||||
result.push(syncKey(meta));
|
||||
if (evt.metaKey !== undefined &&
|
||||
evt.metaKey !== state[XK_Meta_L] && keysym !== XK_Meta_L) {
|
||||
state[XK_Meta_L] = evt.metaKey;
|
||||
result.push(syncKey(XK_Meta_L));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -152,11 +151,14 @@ var kbdUtil = (function() {
|
||||
// Get a key ID from a keyboard event
|
||||
// May be a string or an integer depending on the available properties
|
||||
function getKey(evt){
|
||||
if (evt.key) {
|
||||
return evt.key;
|
||||
if ('keyCode' in evt && 'key' in evt) {
|
||||
return evt.key + ':' + evt.keyCode;
|
||||
}
|
||||
else if ('keyCode' in evt) {
|
||||
return evt.keyCode;
|
||||
}
|
||||
else {
|
||||
return evt.keyCode;
|
||||
return evt.key;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +172,10 @@ var kbdUtil = (function() {
|
||||
else if (evt.charCode) {
|
||||
codepoint = evt.charCode;
|
||||
}
|
||||
|
||||
else if (evt.keyCode && evt.type === 'keypress') {
|
||||
// IE10 stores the char code as keyCode, and has no other useful properties
|
||||
codepoint = evt.keyCode;
|
||||
}
|
||||
if (codepoint) {
|
||||
var res = keysyms.fromUnicode(substituteCodepoint(codepoint));
|
||||
if (res) {
|
||||
@@ -205,21 +210,21 @@ var kbdUtil = (function() {
|
||||
return shiftPressed ? keycode : keycode + 32; // A-Z
|
||||
}
|
||||
if (keycode >= 0x60 && keycode <= 0x69) {
|
||||
return 0xffb0 + (keycode - 0x60); // numpad 0-9
|
||||
return XK_KP_0 + (keycode - 0x60); // numpad 0-9
|
||||
}
|
||||
|
||||
switch(keycode) {
|
||||
case 0x20: return 0x20; // space
|
||||
case 0x6a: return 0xffaa; // multiply
|
||||
case 0x6b: return 0xffab; // add
|
||||
case 0x6c: return 0xffac; // separator
|
||||
case 0x6d: return 0xffad; // subtract
|
||||
case 0x6e: return 0xffae; // decimal
|
||||
case 0x6f: return 0xffaf; // divide
|
||||
case 0xbb: return 0x2b; // +
|
||||
case 0xbc: return 0x2c; // ,
|
||||
case 0xbd: return 0x2d; // -
|
||||
case 0xbe: return 0x2e; // .
|
||||
case 0x20: return XK_space;
|
||||
case 0x6a: return XK_KP_Multiply;
|
||||
case 0x6b: return XK_KP_Add;
|
||||
case 0x6c: return XK_KP_Separator;
|
||||
case 0x6d: return XK_KP_Subtract;
|
||||
case 0x6e: return XK_KP_Decimal;
|
||||
case 0x6f: return XK_KP_Divide;
|
||||
case 0xbb: return XK_plus;
|
||||
case 0xbc: return XK_comma;
|
||||
case 0xbd: return XK_minus;
|
||||
case 0xbe: return XK_period;
|
||||
}
|
||||
|
||||
return nonCharacterKey({keyCode: keycode});
|
||||
@@ -233,43 +238,44 @@ var kbdUtil = (function() {
|
||||
var keycode = evt.keyCode;
|
||||
|
||||
if (keycode >= 0x70 && keycode <= 0x87) {
|
||||
return 0xffbe + keycode - 0x70; // F1-F24
|
||||
return XK_F1 + keycode - 0x70; // F1-F24
|
||||
}
|
||||
switch (keycode) {
|
||||
|
||||
case 8 : return 0xFF08; // BACKSPACE
|
||||
case 13 : return 0xFF0D; // ENTER
|
||||
case 8 : return XK_BackSpace;
|
||||
case 13 : return XK_Return;
|
||||
|
||||
case 9 : return 0xFF09; // TAB
|
||||
case 9 : return XK_Tab;
|
||||
|
||||
case 27 : return 0xFF1B; // ESCAPE
|
||||
case 46 : return 0xFFFF; // DELETE
|
||||
case 27 : return XK_Escape;
|
||||
case 46 : return XK_Delete;
|
||||
|
||||
case 36 : return 0xFF50; // HOME
|
||||
case 35 : return 0xFF57; // END
|
||||
case 33 : return 0xFF55; // PAGE_UP
|
||||
case 34 : return 0xFF56; // PAGE_DOWN
|
||||
case 45 : return 0xFF63; // INSERT
|
||||
case 36 : return XK_Home;
|
||||
case 35 : return XK_End;
|
||||
case 33 : return XK_Page_Up;
|
||||
case 34 : return XK_Page_Down;
|
||||
case 45 : return XK_Insert;
|
||||
|
||||
case 37 : return 0xFF51; // LEFT
|
||||
case 38 : return 0xFF52; // UP
|
||||
case 39 : return 0xFF53; // RIGHT
|
||||
case 40 : return 0xFF54; // DOWN
|
||||
case 16 : return 0xFFE1; // SHIFT
|
||||
case 17 : return 0xFFE3; // CONTROL
|
||||
case 18 : return 0xFFE9; // Left ALT (Mac Option)
|
||||
case 37 : return XK_Left;
|
||||
case 38 : return XK_Up;
|
||||
case 39 : return XK_Right;
|
||||
case 40 : return XK_Down;
|
||||
|
||||
case 224 : return 0xFE07; // Meta
|
||||
case 225 : return 0xFE03; // AltGr
|
||||
case 91 : return 0xFFEC; // Super_L (Win Key)
|
||||
case 92 : return 0xFFED; // Super_R (Win Key)
|
||||
case 93 : return 0xFF67; // Menu (Win Menu), Mac Command
|
||||
case 16 : return XK_Shift_L;
|
||||
case 17 : return XK_Control_L;
|
||||
case 18 : return XK_Alt_L; // also: Option-key on Mac
|
||||
|
||||
case 224 : return XK_Meta_L;
|
||||
case 225 : return XK_ISO_Level3_Shift; // AltGr
|
||||
case 91 : return XK_Super_L; // also: Windows-key
|
||||
case 92 : return XK_Super_R; // also: Windows-key
|
||||
case 93 : return XK_Menu; // also: Windows-Menu, Command on Mac
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
return {
|
||||
hasShortcutModifier : hasShortcutModifier,
|
||||
hasCharModifier : hasCharModifier,
|
||||
hasCharModifier : hasCharModifier,
|
||||
ModifierSync : ModifierSync,
|
||||
getKey : getKey,
|
||||
getKeysym : getKeysym,
|
||||
@@ -381,17 +387,22 @@ function VerifyCharModifier(next) {
|
||||
if (timer) {
|
||||
return;
|
||||
}
|
||||
|
||||
var delayProcess = function () {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
process();
|
||||
};
|
||||
|
||||
while (queue.length !== 0) {
|
||||
var cur = queue[0];
|
||||
queue = queue.splice(1);
|
||||
switch (cur.type) {
|
||||
case 'stall':
|
||||
// insert a delay before processing available events.
|
||||
timer = setTimeout(function() {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
process();
|
||||
}, 5);
|
||||
/* jshint loopfunc: true */
|
||||
timer = setTimeout(delayProcess, 5);
|
||||
/* jshint loopfunc: false */
|
||||
return;
|
||||
case 'keydown':
|
||||
// is the next element a keypress? Then we should merge the two
|
||||
@@ -483,23 +494,25 @@ function TrackKeyState(next) {
|
||||
|
||||
var item = state.splice(idx, 1)[0];
|
||||
// for each keysym tracked by this key entry, clone the current event and override the keysym
|
||||
var clone = (function(){
|
||||
function Clone(){}
|
||||
return function (obj) { Clone.prototype=obj; return new Clone(); };
|
||||
}());
|
||||
for (var key in item.keysyms) {
|
||||
var clone = (function(){
|
||||
function Clone(){}
|
||||
return function (obj) { Clone.prototype=obj; return new Clone(); };
|
||||
}());
|
||||
var out = clone(evt);
|
||||
out.keysym = item.keysyms[key];
|
||||
next(out);
|
||||
}
|
||||
break;
|
||||
case 'releaseall':
|
||||
/* jshint shadow: true */
|
||||
for (var i = 0; i < state.length; ++i) {
|
||||
for (var key in state[i].keysyms) {
|
||||
var keysym = state[i].keysyms[key];
|
||||
next({keyId: 0, keysym: keysym, type: 'keyup'});
|
||||
}
|
||||
}
|
||||
/* jshint shadow: false */
|
||||
state = [];
|
||||
}
|
||||
};
|
||||
@@ -521,8 +534,10 @@ function EscapeModifiers(next) {
|
||||
// send the character event
|
||||
next(evt);
|
||||
// redo modifiers
|
||||
/* jshint shadow: true */
|
||||
for (var i = 0; i < evt.escape.length; ++i) {
|
||||
next({type: 'keydown', keyId: 0, keysym: keysyms.lookup(evt.escape[i])});
|
||||
}
|
||||
/* jshint shadow: false */
|
||||
};
|
||||
}
|
||||
|
||||
@@ -170,6 +170,8 @@ XK_Super_R = 0xffec, /* Right super */
|
||||
XK_Hyper_L = 0xffed, /* Left hyper */
|
||||
XK_Hyper_R = 0xffee, /* Right hyper */
|
||||
|
||||
XK_ISO_Level3_Shift = 0xfe03, /* AltGr */
|
||||
|
||||
/*
|
||||
* Latin 1
|
||||
* (ISO/IEC 8859-1 = Unicode U+0020..U+00FF)
|
||||
|
||||
+1809
-1909
File diff suppressed because it is too large
Load Diff
+955
-937
File diff suppressed because it is too large
Load Diff
+460
-187
@@ -6,9 +6,8 @@
|
||||
* See README.md for usage and integration instructions.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
/*jslint bitwise: false, white: false */
|
||||
/*global window, console, document, navigator, ActiveXObject */
|
||||
/* jshint white: false, nonstandard: true */
|
||||
/*global window, console, document, navigator, ActiveXObject, INCLUDE_URI */
|
||||
|
||||
// Globals defined here
|
||||
var Util = {};
|
||||
@@ -18,61 +17,163 @@ var Util = {};
|
||||
* Make arrays quack
|
||||
*/
|
||||
|
||||
Array.prototype.push8 = function (num) {
|
||||
this.push(num & 0xFF);
|
||||
var addFunc = function (cl, name, func) {
|
||||
if (!cl.prototype[name]) {
|
||||
Object.defineProperty(cl.prototype, name, { enumerable: false, value: func });
|
||||
}
|
||||
};
|
||||
|
||||
Array.prototype.push16 = function (num) {
|
||||
addFunc(Array, 'push8', function (num) {
|
||||
"use strict";
|
||||
this.push(num & 0xFF);
|
||||
});
|
||||
|
||||
addFunc(Array, 'push16', function (num) {
|
||||
"use strict";
|
||||
this.push((num >> 8) & 0xFF,
|
||||
(num ) & 0xFF );
|
||||
};
|
||||
Array.prototype.push32 = function (num) {
|
||||
num & 0xFF);
|
||||
});
|
||||
|
||||
addFunc(Array, 'push32', function (num) {
|
||||
"use strict";
|
||||
this.push((num >> 24) & 0xFF,
|
||||
(num >> 16) & 0xFF,
|
||||
(num >> 8) & 0xFF,
|
||||
(num ) & 0xFF );
|
||||
};
|
||||
num & 0xFF);
|
||||
});
|
||||
|
||||
// IE does not support map (even in IE9)
|
||||
//This prototype is provided by the Mozilla foundation and
|
||||
//is distributed under the MIT license.
|
||||
//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
|
||||
if (!Array.prototype.map)
|
||||
{
|
||||
Array.prototype.map = function(fun /*, thisp*/)
|
||||
{
|
||||
addFunc(Array, 'map', function (fun /*, thisp*/) {
|
||||
"use strict";
|
||||
var len = this.length;
|
||||
if (typeof fun != "function")
|
||||
throw new TypeError();
|
||||
if (typeof fun != "function") {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
||||
var res = new Array(len);
|
||||
var thisp = arguments[1];
|
||||
for (var i = 0; i < len; i++)
|
||||
{
|
||||
if (i in this)
|
||||
res[i] = fun.call(thisp, this[i], i, this);
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (i in this) {
|
||||
res[i] = fun.call(thisp, this[i], i, this);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
});
|
||||
|
||||
// IE <9 does not support indexOf
|
||||
//This prototype is provided by the Mozilla foundation and
|
||||
//is distributed under the MIT license.
|
||||
//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
|
||||
addFunc(Array, 'indexOf', function (elt /*, from*/) {
|
||||
"use strict";
|
||||
var len = this.length >>> 0;
|
||||
|
||||
var from = Number(arguments[1]) || 0;
|
||||
from = (from < 0) ? Math.ceil(from) : Math.floor(from);
|
||||
if (from < 0) {
|
||||
from += len;
|
||||
}
|
||||
|
||||
for (; from < len; from++) {
|
||||
if (from in this &&
|
||||
this[from] === elt) {
|
||||
return from;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
});
|
||||
|
||||
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
|
||||
if (!Object.keys) {
|
||||
Object.keys = (function () {
|
||||
'use strict';
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty,
|
||||
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
|
||||
dontEnums = [
|
||||
'toString',
|
||||
'toLocaleString',
|
||||
'valueOf',
|
||||
'hasOwnProperty',
|
||||
'isPrototypeOf',
|
||||
'propertyIsEnumerable',
|
||||
'constructor'
|
||||
],
|
||||
dontEnumsLength = dontEnums.length;
|
||||
|
||||
return function (obj) {
|
||||
if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
|
||||
throw new TypeError('Object.keys called on non-object');
|
||||
}
|
||||
|
||||
var result = [], prop, i;
|
||||
|
||||
for (prop in obj) {
|
||||
if (hasOwnProperty.call(obj, prop)) {
|
||||
result.push(prop);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDontEnumBug) {
|
||||
for (i = 0; i < dontEnumsLength; i++) {
|
||||
if (hasOwnProperty.call(obj, dontEnums[i])) {
|
||||
result.push(dontEnums[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
}
|
||||
|
||||
//
|
||||
// PhantomJS 1.x doesn't support bind,
|
||||
// so leave this in until PhantomJS 2.0 is released
|
||||
//This prototype is provided by the Mozilla foundation and
|
||||
//is distributed under the MIT license.
|
||||
//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
|
||||
addFunc(Function, 'bind', function (oThis) {
|
||||
if (typeof this !== "function") {
|
||||
// closest thing possible to the ECMAScript 5
|
||||
// internal IsCallable function
|
||||
throw new TypeError("Function.prototype.bind - " +
|
||||
"what is trying to be bound is not callable");
|
||||
}
|
||||
|
||||
var aArgs = Array.prototype.slice.call(arguments, 1),
|
||||
fToBind = this,
|
||||
fNOP = function () {},
|
||||
fBound = function () {
|
||||
return fToBind.apply(this instanceof fNOP && oThis ? this
|
||||
: oThis,
|
||||
aArgs.concat(Array.prototype.slice.call(arguments)));
|
||||
};
|
||||
|
||||
fNOP.prototype = this.prototype;
|
||||
fBound.prototype = new fNOP();
|
||||
|
||||
return fBound;
|
||||
});
|
||||
|
||||
//
|
||||
// requestAnimationFrame shim with setTimeout fallback
|
||||
//
|
||||
|
||||
window.requestAnimFrame = (function(){
|
||||
return window.requestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.oRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame ||
|
||||
function(callback){
|
||||
window.requestAnimFrame = (function () {
|
||||
"use strict";
|
||||
return window.requestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.oRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame ||
|
||||
function (callback) {
|
||||
window.setTimeout(callback, 1000 / 60);
|
||||
};
|
||||
})();
|
||||
|
||||
/*
|
||||
/*
|
||||
* ------------------------------------------------------
|
||||
* Namespaced in Util
|
||||
* ------------------------------------------------------
|
||||
@@ -84,6 +185,7 @@ window.requestAnimFrame = (function(){
|
||||
|
||||
Util._log_level = 'warn';
|
||||
Util.init_logging = function (level) {
|
||||
"use strict";
|
||||
if (typeof level === 'undefined') {
|
||||
level = Util._log_level;
|
||||
} else {
|
||||
@@ -94,26 +196,34 @@ Util.init_logging = function (level) {
|
||||
window.console = {
|
||||
'log' : window.opera.postError,
|
||||
'warn' : window.opera.postError,
|
||||
'error': window.opera.postError };
|
||||
'error': window.opera.postError
|
||||
};
|
||||
} else {
|
||||
window.console = {
|
||||
'log' : function(m) {},
|
||||
'warn' : function(m) {},
|
||||
'error': function(m) {}};
|
||||
'log' : function (m) {},
|
||||
'warn' : function (m) {},
|
||||
'error': function (m) {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Util.Debug = Util.Info = Util.Warn = Util.Error = function (msg) {};
|
||||
/* jshint -W086 */
|
||||
switch (level) {
|
||||
case 'debug': Util.Debug = function (msg) { console.log(msg); };
|
||||
case 'info': Util.Info = function (msg) { console.log(msg); };
|
||||
case 'warn': Util.Warn = function (msg) { console.warn(msg); };
|
||||
case 'error': Util.Error = function (msg) { console.error(msg); };
|
||||
case 'debug':
|
||||
Util.Debug = function (msg) { console.log(msg); };
|
||||
case 'info':
|
||||
Util.Info = function (msg) { console.log(msg); };
|
||||
case 'warn':
|
||||
Util.Warn = function (msg) { console.warn(msg); };
|
||||
case 'error':
|
||||
Util.Error = function (msg) { console.error(msg); };
|
||||
case 'none':
|
||||
break;
|
||||
default:
|
||||
throw("invalid logging type '" + level + "'");
|
||||
throw new Error("invalid logging type '" + level + "'");
|
||||
}
|
||||
/* jshint +W086 */
|
||||
};
|
||||
Util.get_logging = function () {
|
||||
return Util._log_level;
|
||||
@@ -121,87 +231,139 @@ Util.get_logging = function () {
|
||||
// Initialize logging level
|
||||
Util.init_logging();
|
||||
|
||||
Util.make_property = function (proto, name, mode, type) {
|
||||
"use strict";
|
||||
|
||||
// Set configuration default for Crockford style function namespaces
|
||||
Util.conf_default = function(cfg, api, defaults, v, mode, type, defval, desc) {
|
||||
var getter, setter;
|
||||
|
||||
// Default getter function
|
||||
getter = function (idx) {
|
||||
if ((type in {'arr':1, 'array':1}) &&
|
||||
(typeof idx !== 'undefined')) {
|
||||
return cfg[v][idx];
|
||||
} else {
|
||||
return cfg[v];
|
||||
}
|
||||
};
|
||||
|
||||
// Default setter function
|
||||
setter = function (val, idx) {
|
||||
if (type in {'boolean':1, 'bool':1}) {
|
||||
if ((!val) || (val in {'0':1, 'no':1, 'false':1})) {
|
||||
val = false;
|
||||
var getter;
|
||||
if (type === 'arr') {
|
||||
getter = function (idx) {
|
||||
if (typeof idx !== 'undefined') {
|
||||
return this['_' + name][idx];
|
||||
} else {
|
||||
val = true;
|
||||
return this['_' + name];
|
||||
}
|
||||
} else if (type in {'integer':1, 'int':1}) {
|
||||
val = parseInt(val, 10);
|
||||
} else if (type === 'str') {
|
||||
val = String(val);
|
||||
} else if (type === 'func') {
|
||||
if (!val) {
|
||||
val = function () {};
|
||||
}
|
||||
}
|
||||
if (typeof idx !== 'undefined') {
|
||||
cfg[v][idx] = val;
|
||||
} else {
|
||||
cfg[v] = val;
|
||||
}
|
||||
};
|
||||
|
||||
// Set the description
|
||||
api[v + '_description'] = desc;
|
||||
|
||||
// Set the getter function
|
||||
if (typeof api['get_' + v] === 'undefined') {
|
||||
api['get_' + v] = getter;
|
||||
}
|
||||
|
||||
// Set the setter function with extra sanity checks
|
||||
if (typeof api['set_' + v] === 'undefined') {
|
||||
api['set_' + v] = function (val, idx) {
|
||||
if (mode in {'RO':1, 'ro':1}) {
|
||||
throw(v + " is read-only");
|
||||
} else if ((mode in {'WO':1, 'wo':1}) &&
|
||||
(typeof cfg[v] !== 'undefined')) {
|
||||
throw(v + " can only be set once");
|
||||
}
|
||||
setter(val, idx);
|
||||
};
|
||||
} else {
|
||||
getter = function () {
|
||||
return this['_' + name];
|
||||
};
|
||||
}
|
||||
|
||||
// Set the default value
|
||||
if (typeof defaults[v] !== 'undefined') {
|
||||
defval = defaults[v];
|
||||
} else if ((type in {'arr':1, 'array':1}) &&
|
||||
(! (defval instanceof Array))) {
|
||||
defval = [];
|
||||
var make_setter = function (process_val) {
|
||||
if (process_val) {
|
||||
return function (val, idx) {
|
||||
if (typeof idx !== 'undefined') {
|
||||
this['_' + name][idx] = process_val(val);
|
||||
} else {
|
||||
this['_' + name] = process_val(val);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return function (val, idx) {
|
||||
if (typeof idx !== 'undefined') {
|
||||
this['_' + name][idx] = val;
|
||||
} else {
|
||||
this['_' + name] = val;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
var setter;
|
||||
if (type === 'bool') {
|
||||
setter = make_setter(function (val) {
|
||||
if (!val || (val in {'0': 1, 'no': 1, 'false': 1})) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
} else if (type === 'int') {
|
||||
setter = make_setter(function (val) { return parseInt(val, 10); });
|
||||
} else if (type === 'float') {
|
||||
setter = make_setter(parseFloat);
|
||||
} else if (type === 'str') {
|
||||
setter = make_setter(String);
|
||||
} else if (type === 'func') {
|
||||
setter = make_setter(function (val) {
|
||||
if (!val) {
|
||||
return function () {};
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
});
|
||||
} else if (type === 'arr' || type === 'dom' || type == 'raw') {
|
||||
setter = make_setter();
|
||||
} else {
|
||||
throw new Error('Unknown property type ' + type); // some sanity checking
|
||||
}
|
||||
// Coerce existing setting to the right type
|
||||
//Util.Debug("v: " + v + ", defval: " + defval + ", defaults[v]: " + defaults[v]);
|
||||
setter(defval);
|
||||
|
||||
// set the getter
|
||||
if (typeof proto['get_' + name] === 'undefined') {
|
||||
proto['get_' + name] = getter;
|
||||
}
|
||||
|
||||
// set the setter if needed
|
||||
if (typeof proto['set_' + name] === 'undefined') {
|
||||
if (mode === 'rw') {
|
||||
proto['set_' + name] = setter;
|
||||
} else if (mode === 'wo') {
|
||||
proto['set_' + name] = function (val, idx) {
|
||||
if (typeof this['_' + name] !== 'undefined') {
|
||||
throw new Error(name + " can only be set once");
|
||||
}
|
||||
setter.call(this, val, idx);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// make a special setter that we can use in set defaults
|
||||
proto['_raw_set_' + name] = function (val, idx) {
|
||||
setter.call(this, val, idx);
|
||||
//delete this['_init_set_' + name]; // remove it after use
|
||||
};
|
||||
};
|
||||
|
||||
// Set group of configuration defaults
|
||||
Util.conf_defaults = function(cfg, api, defaults, arr) {
|
||||
var i;
|
||||
for (i = 0; i < arr.length; i++) {
|
||||
Util.conf_default(cfg, api, defaults, arr[i][0], arr[i][1],
|
||||
arr[i][2], arr[i][3], arr[i][4]);
|
||||
Util.make_properties = function (constructor, arr) {
|
||||
"use strict";
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
Util.make_property(constructor.prototype, arr[i][0], arr[i][1], arr[i][2]);
|
||||
}
|
||||
};
|
||||
|
||||
Util.set_defaults = function (obj, conf, defaults) {
|
||||
var defaults_keys = Object.keys(defaults);
|
||||
var conf_keys = Object.keys(conf);
|
||||
var keys_obj = {};
|
||||
var i;
|
||||
for (i = 0; i < defaults_keys.length; i++) { keys_obj[defaults_keys[i]] = 1; }
|
||||
for (i = 0; i < conf_keys.length; i++) { keys_obj[conf_keys[i]] = 1; }
|
||||
var keys = Object.keys(keys_obj);
|
||||
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
var setter = obj['_raw_set_' + keys[i]];
|
||||
if (!setter) {
|
||||
Util.Warn('Invalid property ' + keys[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (keys[i] in conf) {
|
||||
setter.call(obj, conf[keys[i]]);
|
||||
} else {
|
||||
setter.call(obj, defaults[keys[i]]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Decode from UTF-8
|
||||
*/
|
||||
Util.decodeUTF8 = function (utf8string) {
|
||||
"use strict";
|
||||
return decodeURIComponent(escape(utf8string));
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Cross-browser routines
|
||||
@@ -214,42 +376,46 @@ Util.conf_defaults = function(cfg, api, defaults, arr) {
|
||||
// Handles the case where load_scripts is invoked from a script that
|
||||
// itself is loaded via load_scripts. Once all scripts are loaded the
|
||||
// window.onscriptsloaded handler is called (if set).
|
||||
Util.get_include_uri = function() {
|
||||
Util.get_include_uri = function () {
|
||||
return (typeof INCLUDE_URI !== "undefined") ? INCLUDE_URI : "include/";
|
||||
}
|
||||
};
|
||||
Util._loading_scripts = [];
|
||||
Util._pending_scripts = [];
|
||||
Util.load_scripts = function(files) {
|
||||
Util.load_scripts = function (files) {
|
||||
"use strict";
|
||||
var head = document.getElementsByTagName('head')[0], script,
|
||||
ls = Util._loading_scripts, ps = Util._pending_scripts;
|
||||
for (var f=0; f<files.length; f++) {
|
||||
|
||||
var loadFunc = function (e) {
|
||||
while (ls.length > 0 && (ls[0].readyState === 'loaded' ||
|
||||
ls[0].readyState === 'complete')) {
|
||||
// For IE, append the script to trigger execution
|
||||
var s = ls.shift();
|
||||
//console.log("loaded script: " + s.src);
|
||||
head.appendChild(s);
|
||||
}
|
||||
if (!this.readyState ||
|
||||
(Util.Engine.presto && this.readyState === 'loaded') ||
|
||||
this.readyState === 'complete') {
|
||||
if (ps.indexOf(this) >= 0) {
|
||||
this.onload = this.onreadystatechange = null;
|
||||
//console.log("completed script: " + this.src);
|
||||
ps.splice(ps.indexOf(this), 1);
|
||||
|
||||
// Call window.onscriptsload after last script loads
|
||||
if (ps.length === 0 && window.onscriptsload) {
|
||||
window.onscriptsload();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (var f = 0; f < files.length; f++) {
|
||||
script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.src = Util.get_include_uri() + files[f];
|
||||
//console.log("loading script: " + script.src);
|
||||
script.onload = script.onreadystatechange = function (e) {
|
||||
while (ls.length > 0 && (ls[0].readyState === 'loaded' ||
|
||||
ls[0].readyState === 'complete')) {
|
||||
// For IE, append the script to trigger execution
|
||||
var s = ls.shift();
|
||||
//console.log("loaded script: " + s.src);
|
||||
head.appendChild(s);
|
||||
}
|
||||
if (!this.readyState ||
|
||||
(Util.Engine.presto && this.readyState === 'loaded') ||
|
||||
this.readyState === 'complete') {
|
||||
if (ps.indexOf(this) >= 0) {
|
||||
this.onload = this.onreadystatechange = null;
|
||||
//console.log("completed script: " + this.src);
|
||||
ps.splice(ps.indexOf(this), 1);
|
||||
|
||||
// Call window.onscriptsload after last script loads
|
||||
if (ps.length === 0 && window.onscriptsload) {
|
||||
window.onscriptsload();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
script.onload = script.onreadystatechange = loadFunc;
|
||||
// In-order script execution tricks
|
||||
if (Util.Engine.trident) {
|
||||
// For IE wait until readyState is 'loaded' before
|
||||
@@ -264,23 +430,80 @@ Util.load_scripts = function(files) {
|
||||
}
|
||||
ps.push(script);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Get DOM element position on page
|
||||
Util.getPosition = function (obj) {
|
||||
var x = 0, y = 0;
|
||||
if (obj.offsetParent) {
|
||||
do {
|
||||
x += obj.offsetLeft;
|
||||
y += obj.offsetTop;
|
||||
obj = obj.offsetParent;
|
||||
} while (obj);
|
||||
// This solution is based based on http://www.greywyvern.com/?post=331
|
||||
// Thanks to Brian Huisman AKA GreyWyvern!
|
||||
Util.getPosition = (function () {
|
||||
"use strict";
|
||||
function getStyle(obj, styleProp) {
|
||||
var y;
|
||||
if (obj.currentStyle) {
|
||||
y = obj.currentStyle[styleProp];
|
||||
} else if (window.getComputedStyle)
|
||||
y = window.getComputedStyle(obj, null)[styleProp];
|
||||
return y;
|
||||
}
|
||||
return {'x': x, 'y': y};
|
||||
};
|
||||
|
||||
function scrollDist() {
|
||||
var myScrollTop = 0, myScrollLeft = 0;
|
||||
var html = document.getElementsByTagName('html')[0];
|
||||
|
||||
// get the scrollTop part
|
||||
if (html.scrollTop && document.documentElement.scrollTop) {
|
||||
myScrollTop = html.scrollTop;
|
||||
} else if (html.scrollTop || document.documentElement.scrollTop) {
|
||||
myScrollTop = html.scrollTop + document.documentElement.scrollTop;
|
||||
} else if (document.body.scrollTop) {
|
||||
myScrollTop = document.body.scrollTop;
|
||||
} else {
|
||||
myScrollTop = 0;
|
||||
}
|
||||
|
||||
// get the scrollLeft part
|
||||
if (html.scrollLeft && document.documentElement.scrollLeft) {
|
||||
myScrollLeft = html.scrollLeft;
|
||||
} else if (html.scrollLeft || document.documentElement.scrollLeft) {
|
||||
myScrollLeft = html.scrollLeft + document.documentElement.scrollLeft;
|
||||
} else if (document.body.scrollLeft) {
|
||||
myScrollLeft = document.body.scrollLeft;
|
||||
} else {
|
||||
myScrollLeft = 0;
|
||||
}
|
||||
|
||||
return [myScrollLeft, myScrollTop];
|
||||
}
|
||||
|
||||
return function (obj) {
|
||||
var curleft = 0, curtop = 0, scr = obj, fixed = false;
|
||||
while ((scr = scr.parentNode) && scr != document.body) {
|
||||
curleft -= scr.scrollLeft || 0;
|
||||
curtop -= scr.scrollTop || 0;
|
||||
if (getStyle(scr, "position") == "fixed") {
|
||||
fixed = true;
|
||||
}
|
||||
}
|
||||
if (fixed && !window.opera) {
|
||||
var scrDist = scrollDist();
|
||||
curleft += scrDist[0];
|
||||
curtop += scrDist[1];
|
||||
}
|
||||
|
||||
do {
|
||||
curleft += obj.offsetLeft;
|
||||
curtop += obj.offsetTop;
|
||||
} while ((obj = obj.offsetParent));
|
||||
|
||||
return {'x': curleft, 'y': curtop};
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
// Get mouse event position in DOM element
|
||||
Util.getEventPosition = function (e, obj, scale) {
|
||||
"use strict";
|
||||
var evt, docX, docY, pos;
|
||||
//if (!e) evt = window.event;
|
||||
evt = (e ? e : window.event);
|
||||
@@ -300,38 +523,41 @@ Util.getEventPosition = function (e, obj, scale) {
|
||||
}
|
||||
var realx = docX - pos.x;
|
||||
var realy = docY - pos.y;
|
||||
var x = Math.max(Math.min(realx, obj.width-1), 0);
|
||||
var y = Math.max(Math.min(realy, obj.height-1), 0);
|
||||
var x = Math.max(Math.min(realx, obj.width - 1), 0);
|
||||
var y = Math.max(Math.min(realy, obj.height - 1), 0);
|
||||
return {'x': x / scale, 'y': y / scale, 'realx': realx / scale, 'realy': realy / scale};
|
||||
};
|
||||
|
||||
|
||||
// Event registration. Based on: http://www.scottandrew.com/weblog/articles/cbs-events
|
||||
Util.addEvent = function (obj, evType, fn){
|
||||
if (obj.attachEvent){
|
||||
var r = obj.attachEvent("on"+evType, fn);
|
||||
Util.addEvent = function (obj, evType, fn) {
|
||||
"use strict";
|
||||
if (obj.attachEvent) {
|
||||
var r = obj.attachEvent("on" + evType, fn);
|
||||
return r;
|
||||
} else if (obj.addEventListener){
|
||||
obj.addEventListener(evType, fn, false);
|
||||
} else if (obj.addEventListener) {
|
||||
obj.addEventListener(evType, fn, false);
|
||||
return true;
|
||||
} else {
|
||||
throw("Handler could not be attached");
|
||||
throw new Error("Handler could not be attached");
|
||||
}
|
||||
};
|
||||
|
||||
Util.removeEvent = function(obj, evType, fn){
|
||||
if (obj.detachEvent){
|
||||
var r = obj.detachEvent("on"+evType, fn);
|
||||
Util.removeEvent = function (obj, evType, fn) {
|
||||
"use strict";
|
||||
if (obj.detachEvent) {
|
||||
var r = obj.detachEvent("on" + evType, fn);
|
||||
return r;
|
||||
} else if (obj.removeEventListener){
|
||||
} else if (obj.removeEventListener) {
|
||||
obj.removeEventListener(evType, fn, false);
|
||||
return true;
|
||||
} else {
|
||||
throw("Handler could not be removed");
|
||||
throw new Error("Handler could not be removed");
|
||||
}
|
||||
};
|
||||
|
||||
Util.stopEvent = function(e) {
|
||||
Util.stopEvent = function (e) {
|
||||
"use strict";
|
||||
if (e.stopPropagation) { e.stopPropagation(); }
|
||||
else { e.cancelBubble = true; }
|
||||
|
||||
@@ -343,41 +569,88 @@ Util.stopEvent = function(e) {
|
||||
// Set browser engine versions. Based on mootools.
|
||||
Util.Features = {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)};
|
||||
|
||||
Util.Engine = {
|
||||
// Version detection break in Opera 11.60 (errors on arguments.callee.caller reference)
|
||||
//'presto': (function() {
|
||||
// return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); }()),
|
||||
'presto': (function() { return (!window.opera) ? false : true; }()),
|
||||
(function () {
|
||||
"use strict";
|
||||
// 'presto': (function () { return (!window.opera) ? false : true; }()),
|
||||
var detectPresto = function () {
|
||||
return !!window.opera;
|
||||
};
|
||||
|
||||
'trident': (function() {
|
||||
return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); }()),
|
||||
'webkit': (function() {
|
||||
try { return (navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); } catch (e) { return false; } }()),
|
||||
//'webkit': (function() {
|
||||
// return ((typeof navigator.taintEnabled !== "unknown") && navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); }()),
|
||||
'gecko': (function() {
|
||||
return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18); }())
|
||||
};
|
||||
if (Util.Engine.webkit) {
|
||||
// Extract actual webkit version if available
|
||||
Util.Engine.webkit = (function(v) {
|
||||
var re = new RegExp('WebKit/([0-9\.]*) ');
|
||||
v = (navigator.userAgent.match(re) || ['', v])[1];
|
||||
return parseFloat(v, 10);
|
||||
})(Util.Engine.webkit);
|
||||
}
|
||||
// 'trident': (function () { return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4);
|
||||
var detectTrident = function () {
|
||||
if (!window.ActiveXObject) {
|
||||
return false;
|
||||
} else {
|
||||
if (window.XMLHttpRequest) {
|
||||
return (document.querySelectorAll) ? 6 : 5;
|
||||
} else {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Util.Flash = (function(){
|
||||
// 'webkit': (function () { try { return (navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); } catch (e) { return false; } }()),
|
||||
var detectInitialWebkit = function () {
|
||||
try {
|
||||
if (navigator.taintEnabled) {
|
||||
return false;
|
||||
} else {
|
||||
if (Util.Features.xpath) {
|
||||
return (Util.Features.query) ? 525 : 420;
|
||||
} else {
|
||||
return 419;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
var detectActualWebkit = function (initial_ver) {
|
||||
var re = /WebKit\/([0-9\.]*) /;
|
||||
var str_ver = (navigator.userAgent.match(re) || ['', initial_ver])[1];
|
||||
return parseFloat(str_ver, 10);
|
||||
};
|
||||
|
||||
// 'gecko': (function () { return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19ssName) ? 19 : 18 : 18); }())
|
||||
var detectGecko = function () {
|
||||
/* jshint -W041 */
|
||||
if (!document.getBoxObjectFor && window.mozInnerScreenX == null) {
|
||||
return false;
|
||||
} else {
|
||||
return (document.getElementsByClassName) ? 19 : 18;
|
||||
}
|
||||
/* jshint +W041 */
|
||||
};
|
||||
|
||||
Util.Engine = {
|
||||
// Version detection break in Opera 11.60 (errors on arguments.callee.caller reference)
|
||||
//'presto': (function() {
|
||||
// return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); }()),
|
||||
'presto': detectPresto(),
|
||||
'trident': detectTrident(),
|
||||
'webkit': detectInitialWebkit(),
|
||||
'gecko': detectGecko(),
|
||||
};
|
||||
|
||||
if (Util.Engine.webkit) {
|
||||
// Extract actual webkit version if available
|
||||
Util.Engine.webkit = detectActualWebkit(Util.Engine.webkit);
|
||||
}
|
||||
})();
|
||||
|
||||
Util.Flash = (function () {
|
||||
"use strict";
|
||||
var v, version;
|
||||
try {
|
||||
v = navigator.plugins['Shockwave Flash'].description;
|
||||
} catch(err1) {
|
||||
} catch (err1) {
|
||||
try {
|
||||
v = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
|
||||
} catch(err2) {
|
||||
} catch (err2) {
|
||||
v = '0 r0';
|
||||
}
|
||||
}
|
||||
version = v.match(/\d+/g);
|
||||
return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0};
|
||||
}());
|
||||
}());
|
||||
|
||||
+304
-342
@@ -14,7 +14,7 @@
|
||||
* read binary data off of the receive queue.
|
||||
*/
|
||||
|
||||
/*jslint browser: true, bitwise: false, plusplus: false */
|
||||
/*jslint browser: true, bitwise: true */
|
||||
/*global Util, Base64 */
|
||||
|
||||
|
||||
@@ -43,380 +43,342 @@ if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) {
|
||||
}
|
||||
Util.load_scripts(["web-socket-js/swfobject.js",
|
||||
"web-socket-js/web_socket.js"]);
|
||||
}());
|
||||
})();
|
||||
}
|
||||
|
||||
|
||||
function Websock() {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var api = {}, // Public API
|
||||
websocket = null, // WebSocket object
|
||||
mode = 'base64', // Current WebSocket mode: 'binary', 'base64'
|
||||
rQ = [], // Receive queue
|
||||
rQi = 0, // Receive queue index
|
||||
rQmax = 10000, // Max receive queue size before compacting
|
||||
sQ = [], // Send queue
|
||||
this._websocket = null; // WebSocket object
|
||||
this._rQ = []; // Receive queue
|
||||
this._rQi = 0; // Receive queue index
|
||||
this._rQmax = 10000; // Max receive queue size before compacting
|
||||
this._sQ = []; // Send queue
|
||||
|
||||
eventHandlers = {
|
||||
'message' : function() {},
|
||||
'open' : function() {},
|
||||
'close' : function() {},
|
||||
'error' : function() {}
|
||||
},
|
||||
this._mode = 'base64'; // Current WebSocket mode: 'binary', 'base64'
|
||||
this.maxBufferedAmount = 200;
|
||||
|
||||
test_mode = false;
|
||||
|
||||
|
||||
//
|
||||
// Queue public functions
|
||||
//
|
||||
|
||||
function get_sQ() {
|
||||
return sQ;
|
||||
this._eventHandlers = {
|
||||
'message': function () {},
|
||||
'open': function () {},
|
||||
'close': function () {},
|
||||
'error': function () {}
|
||||
};
|
||||
}
|
||||
|
||||
function get_rQ() {
|
||||
return rQ;
|
||||
}
|
||||
function get_rQi() {
|
||||
return rQi;
|
||||
}
|
||||
function set_rQi(val) {
|
||||
rQi = val;
|
||||
}
|
||||
(function () {
|
||||
"use strict";
|
||||
Websock.prototype = {
|
||||
// Getters and Setters
|
||||
get_sQ: function () {
|
||||
return this._sQ;
|
||||
},
|
||||
|
||||
function rQlen() {
|
||||
return rQ.length - rQi;
|
||||
}
|
||||
get_rQ: function () {
|
||||
return this._rQ;
|
||||
},
|
||||
|
||||
function rQpeek8() {
|
||||
return (rQ[rQi] );
|
||||
}
|
||||
function rQshift8() {
|
||||
return (rQ[rQi++] );
|
||||
}
|
||||
function rQunshift8(num) {
|
||||
if (rQi === 0) {
|
||||
rQ.unshift(num);
|
||||
} else {
|
||||
rQi -= 1;
|
||||
rQ[rQi] = num;
|
||||
}
|
||||
get_rQi: function () {
|
||||
return this._rQi;
|
||||
},
|
||||
|
||||
}
|
||||
function rQshift16() {
|
||||
return (rQ[rQi++] << 8) +
|
||||
(rQ[rQi++] );
|
||||
}
|
||||
function rQshift32() {
|
||||
return (rQ[rQi++] << 24) +
|
||||
(rQ[rQi++] << 16) +
|
||||
(rQ[rQi++] << 8) +
|
||||
(rQ[rQi++] );
|
||||
}
|
||||
function rQshiftStr(len) {
|
||||
if (typeof(len) === 'undefined') { len = rQlen(); }
|
||||
var arr = rQ.slice(rQi, rQi + len);
|
||||
rQi += len;
|
||||
return String.fromCharCode.apply(null, arr);
|
||||
}
|
||||
function rQshiftBytes(len) {
|
||||
if (typeof(len) === 'undefined') { len = rQlen(); }
|
||||
rQi += len;
|
||||
return rQ.slice(rQi-len, rQi);
|
||||
}
|
||||
set_rQi: function (val) {
|
||||
this._rQi = val;
|
||||
},
|
||||
|
||||
function rQslice(start, end) {
|
||||
if (end) {
|
||||
return rQ.slice(rQi + start, rQi + end);
|
||||
} else {
|
||||
return rQ.slice(rQi + start);
|
||||
}
|
||||
}
|
||||
// Receive Queue
|
||||
rQlen: function () {
|
||||
return this._rQ.length - this._rQi;
|
||||
},
|
||||
|
||||
// Check to see if we must wait for 'num' bytes (default to FBU.bytes)
|
||||
// to be available in the receive queue. Return true if we need to
|
||||
// wait (and possibly print a debug message), otherwise false.
|
||||
function rQwait(msg, num, goback) {
|
||||
var rQlen = rQ.length - rQi; // Skip rQlen() function call
|
||||
if (rQlen < num) {
|
||||
if (goback) {
|
||||
if (rQi < goback) {
|
||||
throw("rQwait cannot backup " + goback + " bytes");
|
||||
rQpeek8: function () {
|
||||
return this._rQ[this._rQi];
|
||||
},
|
||||
|
||||
rQshift8: function () {
|
||||
return this._rQ[this._rQi++];
|
||||
},
|
||||
|
||||
rQskip8: function () {
|
||||
this._rQi++;
|
||||
},
|
||||
|
||||
rQskipBytes: function (num) {
|
||||
this._rQi += num;
|
||||
},
|
||||
|
||||
rQunshift8: function (num) {
|
||||
if (this._rQi === 0) {
|
||||
this._rQ.unshift(num);
|
||||
} else {
|
||||
this._rQi--;
|
||||
this._rQ[this._rQi] = num;
|
||||
}
|
||||
rQi -= goback;
|
||||
}
|
||||
//Util.Debug(" waiting for " + (num-rQlen) +
|
||||
// " " + msg + " byte(s)");
|
||||
return true; // true means need more data
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
//
|
||||
// Private utility routines
|
||||
//
|
||||
rQshift16: function () {
|
||||
return (this._rQ[this._rQi++] << 8) +
|
||||
this._rQ[this._rQi++];
|
||||
},
|
||||
|
||||
function encode_message() {
|
||||
if (mode === 'binary') {
|
||||
// Put in a binary arraybuffer
|
||||
return (new Uint8Array(sQ)).buffer;
|
||||
} else {
|
||||
// base64 encode
|
||||
return Base64.encode(sQ);
|
||||
}
|
||||
}
|
||||
rQshift32: function () {
|
||||
return (this._rQ[this._rQi++] << 24) +
|
||||
(this._rQ[this._rQi++] << 16) +
|
||||
(this._rQ[this._rQi++] << 8) +
|
||||
this._rQ[this._rQi++];
|
||||
},
|
||||
|
||||
function decode_message(data) {
|
||||
//Util.Debug(">> decode_message: " + data);
|
||||
if (mode === 'binary') {
|
||||
// push arraybuffer values onto the end
|
||||
var u8 = new Uint8Array(data);
|
||||
for (var i = 0; i < u8.length; i++) {
|
||||
rQ.push(u8[i]);
|
||||
}
|
||||
} else {
|
||||
// base64 decode and concat to the end
|
||||
rQ = rQ.concat(Base64.decode(data, 0));
|
||||
}
|
||||
//Util.Debug(">> decode_message, rQ: " + rQ);
|
||||
}
|
||||
rQshiftStr: function (len) {
|
||||
if (typeof(len) === 'undefined') { len = this.rQlen(); }
|
||||
var arr = this._rQ.slice(this._rQi, this._rQi + len);
|
||||
this._rQi += len;
|
||||
return String.fromCharCode.apply(null, arr);
|
||||
},
|
||||
|
||||
rQshiftBytes: function (len) {
|
||||
if (typeof(len) === 'undefined') { len = this.rQlen(); }
|
||||
this._rQi += len;
|
||||
return this._rQ.slice(this._rQi - len, this._rQi);
|
||||
},
|
||||
|
||||
//
|
||||
// Public Send functions
|
||||
//
|
||||
|
||||
function flush() {
|
||||
if (websocket.bufferedAmount !== 0) {
|
||||
Util.Debug("bufferedAmount: " + websocket.bufferedAmount);
|
||||
}
|
||||
if (websocket.bufferedAmount < api.maxBufferedAmount) {
|
||||
//Util.Debug("arr: " + arr);
|
||||
//Util.Debug("sQ: " + sQ);
|
||||
if (sQ.length > 0) {
|
||||
websocket.send(encode_message(sQ));
|
||||
sQ = [];
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
Util.Info("Delaying send, bufferedAmount: " +
|
||||
websocket.bufferedAmount);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// overridable for testing
|
||||
function send(arr) {
|
||||
//Util.Debug(">> send_array: " + arr);
|
||||
sQ = sQ.concat(arr);
|
||||
return flush();
|
||||
}
|
||||
|
||||
function send_string(str) {
|
||||
//Util.Debug(">> send_string: " + str);
|
||||
api.send(str.split('').map(
|
||||
function (chr) { return chr.charCodeAt(0); } ) );
|
||||
}
|
||||
|
||||
//
|
||||
// Other public functions
|
||||
|
||||
function recv_message(e) {
|
||||
//Util.Debug(">> recv_message: " + e.data.length);
|
||||
|
||||
try {
|
||||
decode_message(e.data);
|
||||
if (rQlen() > 0) {
|
||||
eventHandlers.message();
|
||||
// Compact the receive queue
|
||||
if (rQ.length > rQmax) {
|
||||
//Util.Debug("Compacting receive queue");
|
||||
rQ = rQ.slice(rQi);
|
||||
rQi = 0;
|
||||
rQslice: function (start, end) {
|
||||
if (end) {
|
||||
return this._rQ.slice(this._rQi + start, this._rQi + end);
|
||||
} else {
|
||||
return this._rQ.slice(this._rQi + start);
|
||||
}
|
||||
} else {
|
||||
Util.Debug("Ignoring empty message");
|
||||
}
|
||||
} catch (exc) {
|
||||
if (typeof exc.stack !== 'undefined') {
|
||||
Util.Warn("recv_message, caught exception: " + exc.stack);
|
||||
} else if (typeof exc.description !== 'undefined') {
|
||||
Util.Warn("recv_message, caught exception: " + exc.description);
|
||||
} else {
|
||||
Util.Warn("recv_message, caught exception:" + exc);
|
||||
}
|
||||
if (typeof exc.name !== 'undefined') {
|
||||
eventHandlers.error(exc.name + ": " + exc.message);
|
||||
} else {
|
||||
eventHandlers.error(exc);
|
||||
}
|
||||
}
|
||||
//Util.Debug("<< recv_message");
|
||||
}
|
||||
},
|
||||
|
||||
// Check to see if we must wait for 'num' bytes (default to FBU.bytes)
|
||||
// to be available in the receive queue. Return true if we need to
|
||||
// wait (and possibly print a debug message), otherwise false.
|
||||
rQwait: function (msg, num, goback) {
|
||||
var rQlen = this._rQ.length - this._rQi; // Skip rQlen() function call
|
||||
if (rQlen < num) {
|
||||
if (goback) {
|
||||
if (this._rQi < goback) {
|
||||
throw new Error("rQwait cannot backup " + goback + " bytes");
|
||||
}
|
||||
this._rQi -= goback;
|
||||
}
|
||||
return true; // true means need more data
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
// Set event handlers
|
||||
function on(evt, handler) {
|
||||
eventHandlers[evt] = handler;
|
||||
}
|
||||
// Send Queue
|
||||
|
||||
function init(protocols) {
|
||||
rQ = [];
|
||||
rQi = 0;
|
||||
sQ = [];
|
||||
websocket = null;
|
||||
flush: function () {
|
||||
if (this._websocket.bufferedAmount !== 0) {
|
||||
Util.Debug("bufferedAmount: " + this._websocket.bufferedAmount);
|
||||
}
|
||||
|
||||
var bt = false,
|
||||
wsbt = false,
|
||||
try_binary = false;
|
||||
if (this._websocket.bufferedAmount < this.maxBufferedAmount) {
|
||||
if (this._sQ.length > 0) {
|
||||
this._websocket.send(this._encode_message());
|
||||
this._sQ = [];
|
||||
}
|
||||
|
||||
// Check for full typed array support
|
||||
if (('Uint8Array' in window) &&
|
||||
('set' in Uint8Array.prototype)) {
|
||||
bt = true;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
Util.Info("Delaying send, bufferedAmount: " +
|
||||
this._websocket.bufferedAmount);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
// Check for full binary type support in WebSockets
|
||||
// TODO: this sucks, the property should exist on the prototype
|
||||
// but it does not.
|
||||
try {
|
||||
if (bt && ('binaryType' in (new WebSocket("wss://localhost:17523")))) {
|
||||
Util.Info("Detected binaryType support in WebSockets");
|
||||
wsbt = true;
|
||||
}
|
||||
} catch (exc) {
|
||||
// Just ignore failed test localhost connections
|
||||
}
|
||||
send: function (arr) {
|
||||
this._sQ = this._sQ.concat(arr);
|
||||
return this.flush();
|
||||
},
|
||||
|
||||
// Default protocols if not specified
|
||||
if (typeof(protocols) === "undefined") {
|
||||
if (wsbt) {
|
||||
protocols = ['binary', 'base64'];
|
||||
} else {
|
||||
protocols = 'base64';
|
||||
}
|
||||
}
|
||||
send_string: function (str) {
|
||||
this.send(str.split('').map(function (chr) {
|
||||
return chr.charCodeAt(0);
|
||||
}));
|
||||
},
|
||||
|
||||
// If no binary support, make sure it was not requested
|
||||
if (!wsbt) {
|
||||
if (protocols === 'binary') {
|
||||
throw("WebSocket binary sub-protocol requested but not supported");
|
||||
}
|
||||
if (typeof(protocols) === "object") {
|
||||
var new_protocols = [];
|
||||
for (var i = 0; i < protocols.length; i++) {
|
||||
if (protocols[i] === 'binary') {
|
||||
Util.Error("Skipping unsupported WebSocket binary sub-protocol");
|
||||
// Event Handlers
|
||||
on: function (evt, handler) {
|
||||
this._eventHandlers[evt] = handler;
|
||||
},
|
||||
|
||||
init: function (protocols, ws_schema) {
|
||||
this._rQ = [];
|
||||
this._rQi = 0;
|
||||
this._sQ = [];
|
||||
this._websocket = null;
|
||||
|
||||
// Check for full typed array support
|
||||
var bt = false;
|
||||
if (('Uint8Array' in window) &&
|
||||
('set' in Uint8Array.prototype)) {
|
||||
bt = true;
|
||||
}
|
||||
|
||||
// Check for full binary type support in WebSockets
|
||||
// Inspired by:
|
||||
// https://github.com/Modernizr/Modernizr/issues/370
|
||||
// https://github.com/Modernizr/Modernizr/blob/master/feature-detects/websockets/binary.js
|
||||
var wsbt = false;
|
||||
try {
|
||||
if (bt && ('binaryType' in WebSocket.prototype ||
|
||||
!!(new WebSocket(ws_schema + '://.').binaryType))) {
|
||||
Util.Info("Detected binaryType support in WebSockets");
|
||||
wsbt = true;
|
||||
}
|
||||
} catch (exc) {
|
||||
// Just ignore failed test localhost connection
|
||||
}
|
||||
|
||||
// Default protocols if not specified
|
||||
if (typeof(protocols) === "undefined") {
|
||||
if (wsbt) {
|
||||
protocols = ['binary', 'base64'];
|
||||
} else {
|
||||
new_protocols.push(protocols[i]);
|
||||
protocols = 'base64';
|
||||
}
|
||||
}
|
||||
if (new_protocols.length > 0) {
|
||||
protocols = new_protocols;
|
||||
|
||||
if (!wsbt) {
|
||||
if (protocols === 'binary') {
|
||||
throw new Error('WebSocket binary sub-protocol requested but not supported');
|
||||
}
|
||||
|
||||
if (typeof(protocols) === 'object') {
|
||||
var new_protocols = [];
|
||||
|
||||
for (var i = 0; i < protocols.length; i++) {
|
||||
if (protocols[i] === 'binary') {
|
||||
Util.Error('Skipping unsupported WebSocket binary sub-protocol');
|
||||
} else {
|
||||
new_protocols.push(protocols[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (new_protocols.length > 0) {
|
||||
protocols = new_protocols;
|
||||
} else {
|
||||
throw new Error("Only WebSocket binary sub-protocol was requested and is not supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return protocols;
|
||||
},
|
||||
|
||||
open: function (uri, protocols) {
|
||||
var ws_schema = uri.match(/^([a-z]+):\/\//)[1];
|
||||
protocols = this.init(protocols, ws_schema);
|
||||
|
||||
this._websocket = new WebSocket(uri, protocols);
|
||||
|
||||
if (protocols.indexOf('binary') >= 0) {
|
||||
this._websocket.binaryType = 'arraybuffer';
|
||||
}
|
||||
|
||||
this._websocket.onmessage = this._recv_message.bind(this);
|
||||
this._websocket.onopen = (function () {
|
||||
Util.Debug('>> WebSock.onopen');
|
||||
if (this._websocket.protocol) {
|
||||
this._mode = this._websocket.protocol;
|
||||
Util.Info("Server choose sub-protocol: " + this._websocket.protocol);
|
||||
} else {
|
||||
this._mode = 'base64';
|
||||
Util.Error('Server select no sub-protocol!: ' + this._websocket.protocol);
|
||||
}
|
||||
this._eventHandlers.open();
|
||||
Util.Debug("<< WebSock.onopen");
|
||||
}).bind(this);
|
||||
this._websocket.onclose = (function (e) {
|
||||
Util.Debug(">> WebSock.onclose");
|
||||
this._eventHandlers.close(e);
|
||||
Util.Debug("<< WebSock.onclose");
|
||||
}).bind(this);
|
||||
this._websocket.onerror = (function (e) {
|
||||
Util.Debug(">> WebSock.onerror: " + e);
|
||||
this._eventHandlers.error(e);
|
||||
Util.Debug("<< WebSock.onerror: " + e);
|
||||
}).bind(this);
|
||||
},
|
||||
|
||||
close: function () {
|
||||
if (this._websocket) {
|
||||
if ((this._websocket.readyState === WebSocket.OPEN) ||
|
||||
(this._websocket.readyState === WebSocket.CONNECTING)) {
|
||||
Util.Info("Closing WebSocket connection");
|
||||
this._websocket.close();
|
||||
}
|
||||
|
||||
this._websocket.onmessage = function (e) { return; };
|
||||
}
|
||||
},
|
||||
|
||||
// private methods
|
||||
_encode_message: function () {
|
||||
if (this._mode === 'binary') {
|
||||
// Put in a binary arraybuffer
|
||||
return (new Uint8Array(this._sQ)).buffer;
|
||||
} else {
|
||||
throw("Only WebSocket binary sub-protocol was requested and not supported.");
|
||||
// base64 encode
|
||||
return Base64.encode(this._sQ);
|
||||
}
|
||||
},
|
||||
|
||||
_decode_message: function (data) {
|
||||
if (this._mode === 'binary') {
|
||||
// push arraybuffer values onto the end
|
||||
var u8 = new Uint8Array(data);
|
||||
for (var i = 0; i < u8.length; i++) {
|
||||
this._rQ.push(u8[i]);
|
||||
}
|
||||
} else {
|
||||
// base64 decode and concat to end
|
||||
this._rQ = this._rQ.concat(Base64.decode(data, 0));
|
||||
}
|
||||
},
|
||||
|
||||
_recv_message: function (e) {
|
||||
try {
|
||||
this._decode_message(e.data);
|
||||
if (this.rQlen() > 0) {
|
||||
this._eventHandlers.message();
|
||||
// Compact the receive queue
|
||||
if (this._rQ.length > this._rQmax) {
|
||||
this._rQ = this._rQ.slice(this._rQi);
|
||||
this._rQi = 0;
|
||||
}
|
||||
} else {
|
||||
Util.Debug("Ignoring empty message");
|
||||
}
|
||||
} catch (exc) {
|
||||
var exception_str = "";
|
||||
if (exc.name) {
|
||||
exception_str += "\n name: " + exc.name + "\n";
|
||||
exception_str += " message: " + exc.message + "\n";
|
||||
}
|
||||
|
||||
if (typeof exc.description !== 'undefined') {
|
||||
exception_str += " description: " + exc.description + "\n";
|
||||
}
|
||||
|
||||
if (typeof exc.stack !== 'undefined') {
|
||||
exception_str += exc.stack;
|
||||
}
|
||||
|
||||
if (exception_str.length > 0) {
|
||||
Util.Error("recv_message, caught exception: " + exception_str);
|
||||
} else {
|
||||
Util.Error("recv_message, caught exception: " + exc);
|
||||
}
|
||||
|
||||
if (typeof exc.name !== 'undefined') {
|
||||
this._eventHandlers.error(exc.name + ": " + exc.message);
|
||||
} else {
|
||||
this._eventHandlers.error(exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return protocols;
|
||||
}
|
||||
|
||||
function open(uri, protocols) {
|
||||
protocols = init(protocols);
|
||||
|
||||
if (test_mode) {
|
||||
websocket = {};
|
||||
} else {
|
||||
websocket = new WebSocket(uri, protocols);
|
||||
if (protocols.indexOf('binary') >= 0) {
|
||||
websocket.binaryType = 'arraybuffer';
|
||||
}
|
||||
}
|
||||
|
||||
websocket.onmessage = recv_message;
|
||||
websocket.onopen = function() {
|
||||
Util.Debug(">> WebSock.onopen");
|
||||
if (websocket.protocol) {
|
||||
mode = websocket.protocol;
|
||||
Util.Info("Server chose sub-protocol: " + websocket.protocol);
|
||||
} else {
|
||||
mode = 'base64';
|
||||
Util.Error("Server select no sub-protocol!: " + websocket.protocol);
|
||||
}
|
||||
eventHandlers.open();
|
||||
Util.Debug("<< WebSock.onopen");
|
||||
};
|
||||
websocket.onclose = function(e) {
|
||||
Util.Debug(">> WebSock.onclose");
|
||||
eventHandlers.close(e);
|
||||
Util.Debug("<< WebSock.onclose");
|
||||
};
|
||||
websocket.onerror = function(e) {
|
||||
Util.Debug(">> WebSock.onerror: " + e);
|
||||
eventHandlers.error(e);
|
||||
Util.Debug("<< WebSock.onerror");
|
||||
};
|
||||
}
|
||||
|
||||
function close() {
|
||||
if (websocket) {
|
||||
if ((websocket.readyState === WebSocket.OPEN) ||
|
||||
(websocket.readyState === WebSocket.CONNECTING)) {
|
||||
Util.Info("Closing WebSocket connection");
|
||||
websocket.close();
|
||||
}
|
||||
websocket.onmessage = function (e) { return; };
|
||||
}
|
||||
}
|
||||
|
||||
// Override internal functions for testing
|
||||
// Takes a send function, returns reference to recv function
|
||||
function testMode(override_send, data_mode) {
|
||||
test_mode = true;
|
||||
mode = data_mode;
|
||||
api.send = override_send;
|
||||
api.close = function () {};
|
||||
return recv_message;
|
||||
}
|
||||
|
||||
function constructor() {
|
||||
// Configuration settings
|
||||
api.maxBufferedAmount = 200;
|
||||
|
||||
// Direct access to send and receive queues
|
||||
api.get_sQ = get_sQ;
|
||||
api.get_rQ = get_rQ;
|
||||
api.get_rQi = get_rQi;
|
||||
api.set_rQi = set_rQi;
|
||||
|
||||
// Routines to read from the receive queue
|
||||
api.rQlen = rQlen;
|
||||
api.rQpeek8 = rQpeek8;
|
||||
api.rQshift8 = rQshift8;
|
||||
api.rQunshift8 = rQunshift8;
|
||||
api.rQshift16 = rQshift16;
|
||||
api.rQshift32 = rQshift32;
|
||||
api.rQshiftStr = rQshiftStr;
|
||||
api.rQshiftBytes = rQshiftBytes;
|
||||
api.rQslice = rQslice;
|
||||
api.rQwait = rQwait;
|
||||
|
||||
api.flush = flush;
|
||||
api.send = send;
|
||||
api.send_string = send_string;
|
||||
|
||||
api.on = on;
|
||||
api.init = init;
|
||||
api.open = open;
|
||||
api.close = close;
|
||||
api.testMode = testMode;
|
||||
|
||||
return api;
|
||||
}
|
||||
|
||||
return constructor();
|
||||
|
||||
}
|
||||
})();
|
||||
|
||||
+61
-43
@@ -7,8 +7,7 @@
|
||||
* See README.md for usage and integration instructions.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
/*jslint bitwise: false, white: false */
|
||||
/*jslint bitwise: false, white: false, browser: true, devel: true */
|
||||
/*global Util, window, document */
|
||||
|
||||
// Globals defined here
|
||||
@@ -31,45 +30,47 @@ if (!window.$D) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
* ------------------------------------------------------
|
||||
* Namespaced in WebUtil
|
||||
* ------------------------------------------------------
|
||||
*/
|
||||
|
||||
// init log level reading the logging HTTP param
|
||||
WebUtil.init_logging = function(level) {
|
||||
WebUtil.init_logging = function (level) {
|
||||
"use strict";
|
||||
if (typeof level !== "undefined") {
|
||||
Util._log_level = level;
|
||||
} else {
|
||||
Util._log_level = (document.location.href.match(
|
||||
/logging=([A-Za-z0-9\._\-]*)/) ||
|
||||
['', Util._log_level])[1];
|
||||
var param = document.location.href.match(/logging=([A-Za-z0-9\._\-]*)/);
|
||||
Util._log_level = (param || ['', Util._log_level])[1];
|
||||
}
|
||||
Util.init_logging();
|
||||
};
|
||||
|
||||
|
||||
WebUtil.dirObj = function (obj, depth, parent) {
|
||||
var i, msg = "", val = "";
|
||||
if (! depth) { depth=2; }
|
||||
if (! parent) { parent= ""; }
|
||||
"use strict";
|
||||
if (! depth) { depth = 2; }
|
||||
if (! parent) { parent = ""; }
|
||||
|
||||
// Print the properties of the passed-in object
|
||||
for (i in obj) {
|
||||
if ((depth > 1) && (typeof obj[i] === "object")) {
|
||||
// Print the properties of the passed-in object
|
||||
var msg = "";
|
||||
for (var i in obj) {
|
||||
if ((depth > 1) && (typeof obj[i] === "object")) {
|
||||
// Recurse attributes that are objects
|
||||
msg += WebUtil.dirObj(obj[i], depth-1, parent + "." + i);
|
||||
msg += WebUtil.dirObj(obj[i], depth - 1, parent + "." + i);
|
||||
} else {
|
||||
//val = new String(obj[i]).replace("\n", " ");
|
||||
var val = "";
|
||||
if (typeof(obj[i]) === "undefined") {
|
||||
val = "undefined";
|
||||
} else {
|
||||
val = obj[i].toString().replace("\n", " ");
|
||||
}
|
||||
if (val.length > 30) {
|
||||
val = val.substr(0,30) + "...";
|
||||
}
|
||||
val = val.substr(0, 30) + "...";
|
||||
}
|
||||
msg += parent + "." + i + ": " + val + "\n";
|
||||
}
|
||||
}
|
||||
@@ -77,8 +78,9 @@ WebUtil.dirObj = function (obj, depth, parent) {
|
||||
};
|
||||
|
||||
// Read a query string variable
|
||||
WebUtil.getQueryVar = function(name, defVal) {
|
||||
var re = new RegExp('[?][^#]*' + name + '=([^&#]*)'),
|
||||
WebUtil.getQueryVar = function (name, defVal) {
|
||||
"use strict";
|
||||
var re = new RegExp('.*[?&]' + name + '=([^&#]*)'),
|
||||
match = document.location.href.match(re);
|
||||
if (typeof defVal === 'undefined') { defVal = null; }
|
||||
if (match) {
|
||||
@@ -94,42 +96,50 @@ WebUtil.getQueryVar = function(name, defVal) {
|
||||
*/
|
||||
|
||||
// No days means only for this browser session
|
||||
WebUtil.createCookie = function(name,value,days) {
|
||||
var date, expires, secure;
|
||||
WebUtil.createCookie = function (name, value, days) {
|
||||
"use strict";
|
||||
var date, expires;
|
||||
if (days) {
|
||||
date = new Date();
|
||||
date.setTime(date.getTime()+(days*24*60*60*1000));
|
||||
expires = "; expires="+date.toGMTString();
|
||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||
expires = "; expires=" + date.toGMTString();
|
||||
} else {
|
||||
expires = "";
|
||||
}
|
||||
|
||||
var secure;
|
||||
if (document.location.protocol === "https:") {
|
||||
secure = "; secure";
|
||||
} else {
|
||||
secure = "";
|
||||
}
|
||||
document.cookie = name+"="+value+expires+"; path=/"+secure;
|
||||
document.cookie = name + "=" + value + expires + "; path=/" + secure;
|
||||
};
|
||||
|
||||
WebUtil.readCookie = function(name, defaultValue) {
|
||||
var i, c, nameEQ = name + "=", ca = document.cookie.split(';');
|
||||
for(i=0; i < ca.length; i += 1) {
|
||||
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); }
|
||||
WebUtil.readCookie = function (name, defaultValue) {
|
||||
"use strict";
|
||||
var nameEQ = name + "=",
|
||||
ca = document.cookie.split(';');
|
||||
|
||||
for (var i = 0; i < ca.length; i += 1) {
|
||||
var 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 (typeof defaultValue !== 'undefined') ? defaultValue : null;
|
||||
};
|
||||
|
||||
WebUtil.eraseCookie = function(name) {
|
||||
WebUtil.createCookie(name,"",-1);
|
||||
WebUtil.eraseCookie = function (name) {
|
||||
"use strict";
|
||||
WebUtil.createCookie(name, "", -1);
|
||||
};
|
||||
|
||||
/*
|
||||
* Setting handling.
|
||||
*/
|
||||
|
||||
WebUtil.initSettings = function(callback) {
|
||||
WebUtil.initSettings = function (callback /*, ...callbackArgs */) {
|
||||
"use strict";
|
||||
var callbackArgs = Array.prototype.slice.call(arguments, 1);
|
||||
if (window.chrome && window.chrome.storage) {
|
||||
window.chrome.storage.sync.get(function (cfg) {
|
||||
@@ -148,7 +158,8 @@ WebUtil.initSettings = function(callback) {
|
||||
};
|
||||
|
||||
// No days means only for this browser session
|
||||
WebUtil.writeSetting = function(name, value) {
|
||||
WebUtil.writeSetting = function (name, value) {
|
||||
"use strict";
|
||||
if (window.chrome && window.chrome.storage) {
|
||||
//console.log("writeSetting:", name, value);
|
||||
if (WebUtil.settings[name] !== value) {
|
||||
@@ -160,7 +171,8 @@ WebUtil.writeSetting = function(name, value) {
|
||||
}
|
||||
};
|
||||
|
||||
WebUtil.readSetting = function(name, defaultValue) {
|
||||
WebUtil.readSetting = function (name, defaultValue) {
|
||||
"use strict";
|
||||
var value;
|
||||
if (window.chrome && window.chrome.storage) {
|
||||
value = WebUtil.settings[name];
|
||||
@@ -177,7 +189,8 @@ WebUtil.readSetting = function(name, defaultValue) {
|
||||
}
|
||||
};
|
||||
|
||||
WebUtil.eraseSetting = function(name) {
|
||||
WebUtil.eraseSetting = function (name) {
|
||||
"use strict";
|
||||
if (window.chrome && window.chrome.storage) {
|
||||
window.chrome.storage.sync.remove(name);
|
||||
delete WebUtil.settings[name];
|
||||
@@ -189,9 +202,12 @@ WebUtil.eraseSetting = function(name) {
|
||||
/*
|
||||
* Alternate stylesheet selection
|
||||
*/
|
||||
WebUtil.getStylesheets = function() { var i, links, sheets = [];
|
||||
links = document.getElementsByTagName("link");
|
||||
for (i = 0; i < links.length; i += 1) {
|
||||
WebUtil.getStylesheets = function () {
|
||||
"use strict";
|
||||
var links = document.getElementsByTagName("link");
|
||||
var sheets = [];
|
||||
|
||||
for (var i = 0; i < links.length; i += 1) {
|
||||
if (links[i].title &&
|
||||
links[i].rel.toUpperCase().indexOf("STYLESHEET") > -1) {
|
||||
sheets.push(links[i]);
|
||||
@@ -202,14 +218,16 @@ WebUtil.getStylesheets = function() { var i, links, sheets = [];
|
||||
|
||||
// No sheet means try and use value from cookie, null sheet used to
|
||||
// clear all alternates.
|
||||
WebUtil.selectStylesheet = function(sheet) {
|
||||
var i, link, sheets = WebUtil.getStylesheets();
|
||||
WebUtil.selectStylesheet = function (sheet) {
|
||||
"use strict";
|
||||
if (typeof sheet === 'undefined') {
|
||||
sheet = 'default';
|
||||
}
|
||||
for (i=0; i < sheets.length; i += 1) {
|
||||
link = sheets[i];
|
||||
if (link.title === sheet) {
|
||||
|
||||
var sheets = WebUtil.getStylesheets();
|
||||
for (var i = 0; i < sheets.length; i += 1) {
|
||||
var link = sheets[i];
|
||||
if (link.title === sheet) {
|
||||
Util.Debug("Using stylesheet " + sheet);
|
||||
link.disabled = false;
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user