Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
22
gaia/tv_apps/remote-control/bower.json
Executable file
22
gaia/tv_apps/remote-control/bower.json
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "remote-control",
|
||||
"version": "0.0.0",
|
||||
"homepage": "https://github.com/mozilla-b2g/gaia/tree/master/tv_apps/remote-control",
|
||||
"description": "TV Remote Control App",
|
||||
"main": "index.html",
|
||||
"license": "MPL",
|
||||
"private": true,
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
],
|
||||
"dependencies": {
|
||||
"evt": "gaia-components/evt#~0.4.0",
|
||||
"smart-button": "gaia-components/smart-button#~0.0.2",
|
||||
"smart-icons": "smart-components/smart-icons#~0.0.2",
|
||||
"qrcodejs": "davidshimjs/qrcodejs"
|
||||
}
|
||||
}
|
||||
28
gaia/tv_apps/remote-control/bower_components/evt/.bower.json
vendored
Executable file
28
gaia/tv_apps/remote-control/bower_components/evt/.bower.json
vendored
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "evt",
|
||||
"main": "index.js",
|
||||
"version": "0.4.0",
|
||||
"homepage": "https://github.com/wilsonpage/evt",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"package.json",
|
||||
"test",
|
||||
"tests",
|
||||
"README.md"
|
||||
],
|
||||
"_release": "0.4.0",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "v0.4.0",
|
||||
"commit": "3593dd6b4dd19f683d00fd0eaf2581c11a128da6"
|
||||
},
|
||||
"_source": "git://github.com/gaia-components/evt.git",
|
||||
"_target": "~0.4.0",
|
||||
"_originalSource": "gaia-components/evt"
|
||||
}
|
||||
19
gaia/tv_apps/remote-control/bower_components/evt/bower.json
vendored
Executable file
19
gaia/tv_apps/remote-control/bower_components/evt/bower.json
vendored
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "evt",
|
||||
"main": "index.js",
|
||||
"version": "0.4.0",
|
||||
"homepage": "https://github.com/wilsonpage/evt",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"package.json",
|
||||
"test",
|
||||
"tests",
|
||||
"README.md"
|
||||
]
|
||||
}
|
||||
154
gaia/tv_apps/remote-control/bower_components/evt/index.js
vendored
Executable file
154
gaia/tv_apps/remote-control/bower_components/evt/index.js
vendored
Executable file
|
|
@ -0,0 +1,154 @@
|
|||
|
||||
/**
|
||||
* Evt
|
||||
*
|
||||
* A super lightweight
|
||||
* event emitter library.
|
||||
*
|
||||
* @version 0.3.3
|
||||
* @author Wilson Page <wilson.page@me.com>
|
||||
*/
|
||||
|
||||
;(function() {
|
||||
|
||||
/**
|
||||
* Locals
|
||||
*/
|
||||
|
||||
var proto = Events.prototype;
|
||||
var slice = [].slice;
|
||||
|
||||
/**
|
||||
* Creates a new event emitter
|
||||
* instance, or if passed an
|
||||
* object, mixes the event logic
|
||||
* into it.
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @return {Object}
|
||||
*/
|
||||
function Events(obj) {
|
||||
if (!(this instanceof Events)) return new Events(obj);
|
||||
if (obj) return mixin(obj, proto);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a callback
|
||||
* with an event name.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Function} cb
|
||||
* @return {Event}
|
||||
*/
|
||||
proto.on = function(name, cb) {
|
||||
this._cbs = this._cbs || {};
|
||||
(this._cbs[name] || (this._cbs[name] = [])).push(cb);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach a callback that once
|
||||
* called, detaches itself.
|
||||
*
|
||||
* TODO: Implement `.off()` to work
|
||||
* with `once()` callbacks.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Function} cb
|
||||
* @public
|
||||
*/
|
||||
proto.once = function(name, cb) {
|
||||
this.on(name, one);
|
||||
function one() {
|
||||
cb.apply(this, arguments);
|
||||
this.off(name, one);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes a single callback,
|
||||
* or all callbacks associated
|
||||
* with the passed event name.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Function} cb
|
||||
* @return {Event}
|
||||
*/
|
||||
proto.off = function(name, cb) {
|
||||
this._cbs = this._cbs || {};
|
||||
|
||||
if (!name) { this._cbs = {}; return; }
|
||||
if (!cb) { return delete this._cbs[name]; }
|
||||
|
||||
var cbs = this._cbs[name] || [];
|
||||
var i;
|
||||
|
||||
while (cbs && ~(i = cbs.indexOf(cb))) { cbs.splice(i, 1); }
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fires an event, triggering
|
||||
* all callbacks registered on this
|
||||
* event name.
|
||||
*
|
||||
* @param {String} name
|
||||
* @return {Event}
|
||||
*/
|
||||
proto.fire = proto.emit = function(options) {
|
||||
var cbs = this._cbs = this._cbs || {};
|
||||
var name = options.name || options;
|
||||
var batch = (cbs[name] || []).concat(cbs['*'] || []);
|
||||
var ctx = options.ctx || this;
|
||||
|
||||
if (batch.length) {
|
||||
this._fireArgs = arguments;
|
||||
var args = slice.call(arguments, 1);
|
||||
while (batch.length) {
|
||||
batch.shift().apply(ctx, args);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
proto.firer = function(name) {
|
||||
var self = this;
|
||||
return function() {
|
||||
var args = slice.call(arguments);
|
||||
args.unshift(name);
|
||||
self.fire.apply(self, args);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Util
|
||||
*/
|
||||
|
||||
/**
|
||||
* Mixes in the properties
|
||||
* of the second object into
|
||||
* the first.
|
||||
*
|
||||
* @param {Object} a
|
||||
* @param {Object} b
|
||||
* @return {Object}
|
||||
*/
|
||||
function mixin(a, b) {
|
||||
for (var key in b) a[key] = b[key];
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose 'Event' (UMD)
|
||||
*/
|
||||
|
||||
if (typeof exports === 'object') {
|
||||
module.exports = Events;
|
||||
} else if (typeof define === 'function' && define.amd) {
|
||||
define(function(){ return Events; });
|
||||
} else {
|
||||
window.evt = Events;
|
||||
}
|
||||
|
||||
})();
|
||||
27
gaia/tv_apps/remote-control/bower_components/qrcodejs/.bower.json
vendored
Executable file
27
gaia/tv_apps/remote-control/bower_components/qrcodejs/.bower.json
vendored
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "qrcode.js",
|
||||
"homepage": "https://github.com/davidshimjs/qrcodejs",
|
||||
"authors": [
|
||||
"Sangmin Shim",
|
||||
"Sangmin Shim <ssm0123@gmail.com> (http://jaguarjs.com)"
|
||||
],
|
||||
"description": "Cross-browser QRCode generator for javascript",
|
||||
"main": "qrcode.js",
|
||||
"ignore": [
|
||||
"bower_components",
|
||||
"node_modules",
|
||||
"index.html",
|
||||
"index.svg",
|
||||
"jquery.min.js",
|
||||
"qrcode.min.js"
|
||||
],
|
||||
"_release": "540308a766",
|
||||
"_resolution": {
|
||||
"type": "branch",
|
||||
"branch": "master",
|
||||
"commit": "540308a766f09f40c2f7aa5a39a3e76892da3259"
|
||||
},
|
||||
"_source": "git://github.com/davidshimjs/qrcodejs.git",
|
||||
"_target": "*",
|
||||
"_originalSource": "davidshimjs/qrcodejs"
|
||||
}
|
||||
4
gaia/tv_apps/remote-control/bower_components/qrcodejs/.gitignore
vendored
Executable file
4
gaia/tv_apps/remote-control/bower_components/qrcodejs/.gitignore
vendored
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
.DS_Store
|
||||
|
||||
.idea
|
||||
.project
|
||||
14
gaia/tv_apps/remote-control/bower_components/qrcodejs/LICENSE
vendored
Executable file
14
gaia/tv_apps/remote-control/bower_components/qrcodejs/LICENSE
vendored
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
The MIT License (MIT)
|
||||
---------------------
|
||||
Copyright (c) 2012 davidshimjs
|
||||
|
||||
Permission is hereby granted, free of charge,
|
||||
to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
18
gaia/tv_apps/remote-control/bower_components/qrcodejs/bower.json
vendored
Executable file
18
gaia/tv_apps/remote-control/bower_components/qrcodejs/bower.json
vendored
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "qrcode.js",
|
||||
"version": "0.0.1",
|
||||
"homepage": "https://github.com/davidshimjs/qrcodejs",
|
||||
"authors": [
|
||||
"Sangmin Shim", "Sangmin Shim <ssm0123@gmail.com> (http://jaguarjs.com)"
|
||||
],
|
||||
"description": "Cross-browser QRCode generator for javascript",
|
||||
"main": "qrcode.js",
|
||||
"ignore": [
|
||||
"bower_components",
|
||||
"node_modules",
|
||||
"index.html",
|
||||
"index.svg",
|
||||
"jquery.min.js",
|
||||
"qrcode.min.js"
|
||||
]
|
||||
}
|
||||
614
gaia/tv_apps/remote-control/bower_components/qrcodejs/qrcode.js
vendored
Executable file
614
gaia/tv_apps/remote-control/bower_components/qrcodejs/qrcode.js
vendored
Executable file
|
|
@ -0,0 +1,614 @@
|
|||
/**
|
||||
* @fileoverview
|
||||
* - Using the 'QRCode for Javascript library'
|
||||
* - Fixed dataset of 'QRCode for Javascript library' for support full-spec.
|
||||
* - this library has no dependencies.
|
||||
*
|
||||
* @author davidshimjs
|
||||
* @see <a href="http://www.d-project.com/" target="_blank">http://www.d-project.com/</a>
|
||||
* @see <a href="http://jeromeetienne.github.com/jquery-qrcode/" target="_blank">http://jeromeetienne.github.com/jquery-qrcode/</a>
|
||||
*/
|
||||
var QRCode;
|
||||
|
||||
(function () {
|
||||
//---------------------------------------------------------------------
|
||||
// QRCode for JavaScript
|
||||
//
|
||||
// Copyright (c) 2009 Kazuhiko Arase
|
||||
//
|
||||
// URL: http://www.d-project.com/
|
||||
//
|
||||
// Licensed under the MIT license:
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
// The word "QR Code" is registered trademark of
|
||||
// DENSO WAVE INCORPORATED
|
||||
// http://www.denso-wave.com/qrcode/faqpatent-e.html
|
||||
//
|
||||
//---------------------------------------------------------------------
|
||||
function QR8bitByte(data) {
|
||||
this.mode = QRMode.MODE_8BIT_BYTE;
|
||||
this.data = data;
|
||||
this.parsedData = [];
|
||||
|
||||
// Added to support UTF-8 Characters
|
||||
for (var i = 0, l = this.data.length; i < l; i++) {
|
||||
var byteArray = [];
|
||||
var code = this.data.charCodeAt(i);
|
||||
|
||||
if (code > 0x10000) {
|
||||
byteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18);
|
||||
byteArray[1] = 0x80 | ((code & 0x3F000) >>> 12);
|
||||
byteArray[2] = 0x80 | ((code & 0xFC0) >>> 6);
|
||||
byteArray[3] = 0x80 | (code & 0x3F);
|
||||
} else if (code > 0x800) {
|
||||
byteArray[0] = 0xE0 | ((code & 0xF000) >>> 12);
|
||||
byteArray[1] = 0x80 | ((code & 0xFC0) >>> 6);
|
||||
byteArray[2] = 0x80 | (code & 0x3F);
|
||||
} else if (code > 0x80) {
|
||||
byteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6);
|
||||
byteArray[1] = 0x80 | (code & 0x3F);
|
||||
} else {
|
||||
byteArray[0] = code;
|
||||
}
|
||||
|
||||
this.parsedData.push(byteArray);
|
||||
}
|
||||
|
||||
this.parsedData = Array.prototype.concat.apply([], this.parsedData);
|
||||
|
||||
if (this.parsedData.length != this.data.length) {
|
||||
this.parsedData.unshift(191);
|
||||
this.parsedData.unshift(187);
|
||||
this.parsedData.unshift(239);
|
||||
}
|
||||
}
|
||||
|
||||
QR8bitByte.prototype = {
|
||||
getLength: function (buffer) {
|
||||
return this.parsedData.length;
|
||||
},
|
||||
write: function (buffer) {
|
||||
for (var i = 0, l = this.parsedData.length; i < l; i++) {
|
||||
buffer.put(this.parsedData[i], 8);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function QRCodeModel(typeNumber, errorCorrectLevel) {
|
||||
this.typeNumber = typeNumber;
|
||||
this.errorCorrectLevel = errorCorrectLevel;
|
||||
this.modules = null;
|
||||
this.moduleCount = 0;
|
||||
this.dataCache = null;
|
||||
this.dataList = [];
|
||||
}
|
||||
|
||||
QRCodeModel.prototype={addData:function(data){var newData=new QR8bitByte(data);this.dataList.push(newData);this.dataCache=null;},isDark:function(row,col){if(row<0||this.moduleCount<=row||col<0||this.moduleCount<=col){throw new Error(row+","+col);}
|
||||
return this.modules[row][col];},getModuleCount:function(){return this.moduleCount;},make:function(){this.makeImpl(false,this.getBestMaskPattern());},makeImpl:function(test,maskPattern){this.moduleCount=this.typeNumber*4+17;this.modules=new Array(this.moduleCount);for(var row=0;row<this.moduleCount;row++){this.modules[row]=new Array(this.moduleCount);for(var col=0;col<this.moduleCount;col++){this.modules[row][col]=null;}}
|
||||
this.setupPositionProbePattern(0,0);this.setupPositionProbePattern(this.moduleCount-7,0);this.setupPositionProbePattern(0,this.moduleCount-7);this.setupPositionAdjustPattern();this.setupTimingPattern();this.setupTypeInfo(test,maskPattern);if(this.typeNumber>=7){this.setupTypeNumber(test);}
|
||||
if(this.dataCache==null){this.dataCache=QRCodeModel.createData(this.typeNumber,this.errorCorrectLevel,this.dataList);}
|
||||
this.mapData(this.dataCache,maskPattern);},setupPositionProbePattern:function(row,col){for(var r=-1;r<=7;r++){if(row+r<=-1||this.moduleCount<=row+r)continue;for(var c=-1;c<=7;c++){if(col+c<=-1||this.moduleCount<=col+c)continue;if((0<=r&&r<=6&&(c==0||c==6))||(0<=c&&c<=6&&(r==0||r==6))||(2<=r&&r<=4&&2<=c&&c<=4)){this.modules[row+r][col+c]=true;}else{this.modules[row+r][col+c]=false;}}}},getBestMaskPattern:function(){var minLostPoint=0;var pattern=0;for(var i=0;i<8;i++){this.makeImpl(true,i);var lostPoint=QRUtil.getLostPoint(this);if(i==0||minLostPoint>lostPoint){minLostPoint=lostPoint;pattern=i;}}
|
||||
return pattern;},createMovieClip:function(target_mc,instance_name,depth){var qr_mc=target_mc.createEmptyMovieClip(instance_name,depth);var cs=1;this.make();for(var row=0;row<this.modules.length;row++){var y=row*cs;for(var col=0;col<this.modules[row].length;col++){var x=col*cs;var dark=this.modules[row][col];if(dark){qr_mc.beginFill(0,100);qr_mc.moveTo(x,y);qr_mc.lineTo(x+cs,y);qr_mc.lineTo(x+cs,y+cs);qr_mc.lineTo(x,y+cs);qr_mc.endFill();}}}
|
||||
return qr_mc;},setupTimingPattern:function(){for(var r=8;r<this.moduleCount-8;r++){if(this.modules[r][6]!=null){continue;}
|
||||
this.modules[r][6]=(r%2==0);}
|
||||
for(var c=8;c<this.moduleCount-8;c++){if(this.modules[6][c]!=null){continue;}
|
||||
this.modules[6][c]=(c%2==0);}},setupPositionAdjustPattern:function(){var pos=QRUtil.getPatternPosition(this.typeNumber);for(var i=0;i<pos.length;i++){for(var j=0;j<pos.length;j++){var row=pos[i];var col=pos[j];if(this.modules[row][col]!=null){continue;}
|
||||
for(var r=-2;r<=2;r++){for(var c=-2;c<=2;c++){if(r==-2||r==2||c==-2||c==2||(r==0&&c==0)){this.modules[row+r][col+c]=true;}else{this.modules[row+r][col+c]=false;}}}}}},setupTypeNumber:function(test){var bits=QRUtil.getBCHTypeNumber(this.typeNumber);for(var i=0;i<18;i++){var mod=(!test&&((bits>>i)&1)==1);this.modules[Math.floor(i/3)][i%3+this.moduleCount-8-3]=mod;}
|
||||
for(var i=0;i<18;i++){var mod=(!test&&((bits>>i)&1)==1);this.modules[i%3+this.moduleCount-8-3][Math.floor(i/3)]=mod;}},setupTypeInfo:function(test,maskPattern){var data=(this.errorCorrectLevel<<3)|maskPattern;var bits=QRUtil.getBCHTypeInfo(data);for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<6){this.modules[i][8]=mod;}else if(i<8){this.modules[i+1][8]=mod;}else{this.modules[this.moduleCount-15+i][8]=mod;}}
|
||||
for(var i=0;i<15;i++){var mod=(!test&&((bits>>i)&1)==1);if(i<8){this.modules[8][this.moduleCount-i-1]=mod;}else if(i<9){this.modules[8][15-i-1+1]=mod;}else{this.modules[8][15-i-1]=mod;}}
|
||||
this.modules[this.moduleCount-8][8]=(!test);},mapData:function(data,maskPattern){var inc=-1;var row=this.moduleCount-1;var bitIndex=7;var byteIndex=0;for(var col=this.moduleCount-1;col>0;col-=2){if(col==6)col--;while(true){for(var c=0;c<2;c++){if(this.modules[row][col-c]==null){var dark=false;if(byteIndex<data.length){dark=(((data[byteIndex]>>>bitIndex)&1)==1);}
|
||||
var mask=QRUtil.getMask(maskPattern,row,col-c);if(mask){dark=!dark;}
|
||||
this.modules[row][col-c]=dark;bitIndex--;if(bitIndex==-1){byteIndex++;bitIndex=7;}}}
|
||||
row+=inc;if(row<0||this.moduleCount<=row){row-=inc;inc=-inc;break;}}}}};QRCodeModel.PAD0=0xEC;QRCodeModel.PAD1=0x11;QRCodeModel.createData=function(typeNumber,errorCorrectLevel,dataList){var rsBlocks=QRRSBlock.getRSBlocks(typeNumber,errorCorrectLevel);var buffer=new QRBitBuffer();for(var i=0;i<dataList.length;i++){var data=dataList[i];buffer.put(data.mode,4);buffer.put(data.getLength(),QRUtil.getLengthInBits(data.mode,typeNumber));data.write(buffer);}
|
||||
var totalDataCount=0;for(var i=0;i<rsBlocks.length;i++){totalDataCount+=rsBlocks[i].dataCount;}
|
||||
if(buffer.getLengthInBits()>totalDataCount*8){throw new Error("code length overflow. ("
|
||||
+buffer.getLengthInBits()
|
||||
+">"
|
||||
+totalDataCount*8
|
||||
+")");}
|
||||
if(buffer.getLengthInBits()+4<=totalDataCount*8){buffer.put(0,4);}
|
||||
while(buffer.getLengthInBits()%8!=0){buffer.putBit(false);}
|
||||
while(true){if(buffer.getLengthInBits()>=totalDataCount*8){break;}
|
||||
buffer.put(QRCodeModel.PAD0,8);if(buffer.getLengthInBits()>=totalDataCount*8){break;}
|
||||
buffer.put(QRCodeModel.PAD1,8);}
|
||||
return QRCodeModel.createBytes(buffer,rsBlocks);};QRCodeModel.createBytes=function(buffer,rsBlocks){var offset=0;var maxDcCount=0;var maxEcCount=0;var dcdata=new Array(rsBlocks.length);var ecdata=new Array(rsBlocks.length);for(var r=0;r<rsBlocks.length;r++){var dcCount=rsBlocks[r].dataCount;var ecCount=rsBlocks[r].totalCount-dcCount;maxDcCount=Math.max(maxDcCount,dcCount);maxEcCount=Math.max(maxEcCount,ecCount);dcdata[r]=new Array(dcCount);for(var i=0;i<dcdata[r].length;i++){dcdata[r][i]=0xff&buffer.buffer[i+offset];}
|
||||
offset+=dcCount;var rsPoly=QRUtil.getErrorCorrectPolynomial(ecCount);var rawPoly=new QRPolynomial(dcdata[r],rsPoly.getLength()-1);var modPoly=rawPoly.mod(rsPoly);ecdata[r]=new Array(rsPoly.getLength()-1);for(var i=0;i<ecdata[r].length;i++){var modIndex=i+modPoly.getLength()-ecdata[r].length;ecdata[r][i]=(modIndex>=0)?modPoly.get(modIndex):0;}}
|
||||
var totalCodeCount=0;for(var i=0;i<rsBlocks.length;i++){totalCodeCount+=rsBlocks[i].totalCount;}
|
||||
var data=new Array(totalCodeCount);var index=0;for(var i=0;i<maxDcCount;i++){for(var r=0;r<rsBlocks.length;r++){if(i<dcdata[r].length){data[index++]=dcdata[r][i];}}}
|
||||
for(var i=0;i<maxEcCount;i++){for(var r=0;r<rsBlocks.length;r++){if(i<ecdata[r].length){data[index++]=ecdata[r][i];}}}
|
||||
return data;};var QRMode={MODE_NUMBER:1<<0,MODE_ALPHA_NUM:1<<1,MODE_8BIT_BYTE:1<<2,MODE_KANJI:1<<3};var QRErrorCorrectLevel={L:1,M:0,Q:3,H:2};var QRMaskPattern={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7};var QRUtil={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:(1<<10)|(1<<8)|(1<<5)|(1<<4)|(1<<2)|(1<<1)|(1<<0),G18:(1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)|(1<<5)|(1<<2)|(1<<0),G15_MASK:(1<<14)|(1<<12)|(1<<10)|(1<<4)|(1<<1),getBCHTypeInfo:function(data){var d=data<<10;while(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G15)>=0){d^=(QRUtil.G15<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G15)));}
|
||||
return((data<<10)|d)^QRUtil.G15_MASK;},getBCHTypeNumber:function(data){var d=data<<12;while(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)>=0){d^=(QRUtil.G18<<(QRUtil.getBCHDigit(d)-QRUtil.getBCHDigit(QRUtil.G18)));}
|
||||
return(data<<12)|d;},getBCHDigit:function(data){var digit=0;while(data!=0){digit++;data>>>=1;}
|
||||
return digit;},getPatternPosition:function(typeNumber){return QRUtil.PATTERN_POSITION_TABLE[typeNumber-1];},getMask:function(maskPattern,i,j){switch(maskPattern){case QRMaskPattern.PATTERN000:return(i+j)%2==0;case QRMaskPattern.PATTERN001:return i%2==0;case QRMaskPattern.PATTERN010:return j%3==0;case QRMaskPattern.PATTERN011:return(i+j)%3==0;case QRMaskPattern.PATTERN100:return(Math.floor(i/2)+Math.floor(j/3))%2==0;case QRMaskPattern.PATTERN101:return(i*j)%2+(i*j)%3==0;case QRMaskPattern.PATTERN110:return((i*j)%2+(i*j)%3)%2==0;case QRMaskPattern.PATTERN111:return((i*j)%3+(i+j)%2)%2==0;default:throw new Error("bad maskPattern:"+maskPattern);}},getErrorCorrectPolynomial:function(errorCorrectLength){var a=new QRPolynomial([1],0);for(var i=0;i<errorCorrectLength;i++){a=a.multiply(new QRPolynomial([1,QRMath.gexp(i)],0));}
|
||||
return a;},getLengthInBits:function(mode,type){if(1<=type&&type<10){switch(mode){case QRMode.MODE_NUMBER:return 10;case QRMode.MODE_ALPHA_NUM:return 9;case QRMode.MODE_8BIT_BYTE:return 8;case QRMode.MODE_KANJI:return 8;default:throw new Error("mode:"+mode);}}else if(type<27){switch(mode){case QRMode.MODE_NUMBER:return 12;case QRMode.MODE_ALPHA_NUM:return 11;case QRMode.MODE_8BIT_BYTE:return 16;case QRMode.MODE_KANJI:return 10;default:throw new Error("mode:"+mode);}}else if(type<41){switch(mode){case QRMode.MODE_NUMBER:return 14;case QRMode.MODE_ALPHA_NUM:return 13;case QRMode.MODE_8BIT_BYTE:return 16;case QRMode.MODE_KANJI:return 12;default:throw new Error("mode:"+mode);}}else{throw new Error("type:"+type);}},getLostPoint:function(qrCode){var moduleCount=qrCode.getModuleCount();var lostPoint=0;for(var row=0;row<moduleCount;row++){for(var col=0;col<moduleCount;col++){var sameCount=0;var dark=qrCode.isDark(row,col);for(var r=-1;r<=1;r++){if(row+r<0||moduleCount<=row+r){continue;}
|
||||
for(var c=-1;c<=1;c++){if(col+c<0||moduleCount<=col+c){continue;}
|
||||
if(r==0&&c==0){continue;}
|
||||
if(dark==qrCode.isDark(row+r,col+c)){sameCount++;}}}
|
||||
if(sameCount>5){lostPoint+=(3+sameCount-5);}}}
|
||||
for(var row=0;row<moduleCount-1;row++){for(var col=0;col<moduleCount-1;col++){var count=0;if(qrCode.isDark(row,col))count++;if(qrCode.isDark(row+1,col))count++;if(qrCode.isDark(row,col+1))count++;if(qrCode.isDark(row+1,col+1))count++;if(count==0||count==4){lostPoint+=3;}}}
|
||||
for(var row=0;row<moduleCount;row++){for(var col=0;col<moduleCount-6;col++){if(qrCode.isDark(row,col)&&!qrCode.isDark(row,col+1)&&qrCode.isDark(row,col+2)&&qrCode.isDark(row,col+3)&&qrCode.isDark(row,col+4)&&!qrCode.isDark(row,col+5)&&qrCode.isDark(row,col+6)){lostPoint+=40;}}}
|
||||
for(var col=0;col<moduleCount;col++){for(var row=0;row<moduleCount-6;row++){if(qrCode.isDark(row,col)&&!qrCode.isDark(row+1,col)&&qrCode.isDark(row+2,col)&&qrCode.isDark(row+3,col)&&qrCode.isDark(row+4,col)&&!qrCode.isDark(row+5,col)&&qrCode.isDark(row+6,col)){lostPoint+=40;}}}
|
||||
var darkCount=0;for(var col=0;col<moduleCount;col++){for(var row=0;row<moduleCount;row++){if(qrCode.isDark(row,col)){darkCount++;}}}
|
||||
var ratio=Math.abs(100*darkCount/moduleCount/moduleCount-50)/5;lostPoint+=ratio*10;return lostPoint;}};var QRMath={glog:function(n){if(n<1){throw new Error("glog("+n+")");}
|
||||
return QRMath.LOG_TABLE[n];},gexp:function(n){while(n<0){n+=255;}
|
||||
while(n>=256){n-=255;}
|
||||
return QRMath.EXP_TABLE[n];},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)};for(var i=0;i<8;i++){QRMath.EXP_TABLE[i]=1<<i;}
|
||||
for(var i=8;i<256;i++){QRMath.EXP_TABLE[i]=QRMath.EXP_TABLE[i-4]^QRMath.EXP_TABLE[i-5]^QRMath.EXP_TABLE[i-6]^QRMath.EXP_TABLE[i-8];}
|
||||
for(var i=0;i<255;i++){QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]]=i;}
|
||||
function QRPolynomial(num,shift){if(num.length==undefined){throw new Error(num.length+"/"+shift);}
|
||||
var offset=0;while(offset<num.length&&num[offset]==0){offset++;}
|
||||
this.num=new Array(num.length-offset+shift);for(var i=0;i<num.length-offset;i++){this.num[i]=num[i+offset];}}
|
||||
QRPolynomial.prototype={get:function(index){return this.num[index];},getLength:function(){return this.num.length;},multiply:function(e){var num=new Array(this.getLength()+e.getLength()-1);for(var i=0;i<this.getLength();i++){for(var j=0;j<e.getLength();j++){num[i+j]^=QRMath.gexp(QRMath.glog(this.get(i))+QRMath.glog(e.get(j)));}}
|
||||
return new QRPolynomial(num,0);},mod:function(e){if(this.getLength()-e.getLength()<0){return this;}
|
||||
var ratio=QRMath.glog(this.get(0))-QRMath.glog(e.get(0));var num=new Array(this.getLength());for(var i=0;i<this.getLength();i++){num[i]=this.get(i);}
|
||||
for(var i=0;i<e.getLength();i++){num[i]^=QRMath.gexp(QRMath.glog(e.get(i))+ratio);}
|
||||
return new QRPolynomial(num,0).mod(e);}};function QRRSBlock(totalCount,dataCount){this.totalCount=totalCount;this.dataCount=dataCount;}
|
||||
QRRSBlock.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]];QRRSBlock.getRSBlocks=function(typeNumber,errorCorrectLevel){var rsBlock=QRRSBlock.getRsBlockTable(typeNumber,errorCorrectLevel);if(rsBlock==undefined){throw new Error("bad rs block @ typeNumber:"+typeNumber+"/errorCorrectLevel:"+errorCorrectLevel);}
|
||||
var length=rsBlock.length/3;var list=[];for(var i=0;i<length;i++){var count=rsBlock[i*3+0];var totalCount=rsBlock[i*3+1];var dataCount=rsBlock[i*3+2];for(var j=0;j<count;j++){list.push(new QRRSBlock(totalCount,dataCount));}}
|
||||
return list;};QRRSBlock.getRsBlockTable=function(typeNumber,errorCorrectLevel){switch(errorCorrectLevel){case QRErrorCorrectLevel.L:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+0];case QRErrorCorrectLevel.M:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+1];case QRErrorCorrectLevel.Q:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+2];case QRErrorCorrectLevel.H:return QRRSBlock.RS_BLOCK_TABLE[(typeNumber-1)*4+3];default:return undefined;}};function QRBitBuffer(){this.buffer=[];this.length=0;}
|
||||
QRBitBuffer.prototype={get:function(index){var bufIndex=Math.floor(index/8);return((this.buffer[bufIndex]>>>(7-index%8))&1)==1;},put:function(num,length){for(var i=0;i<length;i++){this.putBit(((num>>>(length-i-1))&1)==1);}},getLengthInBits:function(){return this.length;},putBit:function(bit){var bufIndex=Math.floor(this.length/8);if(this.buffer.length<=bufIndex){this.buffer.push(0);}
|
||||
if(bit){this.buffer[bufIndex]|=(0x80>>>(this.length%8));}
|
||||
this.length++;}};var QRCodeLimitLength=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]];
|
||||
|
||||
function _isSupportCanvas() {
|
||||
return typeof CanvasRenderingContext2D != "undefined";
|
||||
}
|
||||
|
||||
// android 2.x doesn't support Data-URI spec
|
||||
function _getAndroid() {
|
||||
var android = false;
|
||||
var sAgent = navigator.userAgent;
|
||||
|
||||
if (/android/i.test(sAgent)) { // android
|
||||
android = true;
|
||||
var aMat = sAgent.toString().match(/android ([0-9]\.[0-9])/i);
|
||||
|
||||
if (aMat && aMat[1]) {
|
||||
android = parseFloat(aMat[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return android;
|
||||
}
|
||||
|
||||
var svgDrawer = (function() {
|
||||
|
||||
var Drawing = function (el, htOption) {
|
||||
this._el = el;
|
||||
this._htOption = htOption;
|
||||
};
|
||||
|
||||
Drawing.prototype.draw = function (oQRCode) {
|
||||
var _htOption = this._htOption;
|
||||
var _el = this._el;
|
||||
var nCount = oQRCode.getModuleCount();
|
||||
var nWidth = Math.floor(_htOption.width / nCount);
|
||||
var nHeight = Math.floor(_htOption.height / nCount);
|
||||
|
||||
this.clear();
|
||||
|
||||
function makeSVG(tag, attrs) {
|
||||
var el = document.createElementNS('http://www.w3.org/2000/svg', tag);
|
||||
for (var k in attrs)
|
||||
if (attrs.hasOwnProperty(k)) el.setAttribute(k, attrs[k]);
|
||||
return el;
|
||||
}
|
||||
|
||||
var svg = makeSVG("svg" , {'viewBox': '0 0 ' + String(nCount) + " " + String(nCount), 'width': '100%', 'height': '100%', 'fill': _htOption.colorLight});
|
||||
svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink");
|
||||
_el.appendChild(svg);
|
||||
|
||||
svg.appendChild(makeSVG("rect", {"fill": _htOption.colorLight, "width": "100%", "height": "100%"}));
|
||||
svg.appendChild(makeSVG("rect", {"fill": _htOption.colorDark, "width": "1", "height": "1", "id": "template"}));
|
||||
|
||||
for (var row = 0; row < nCount; row++) {
|
||||
for (var col = 0; col < nCount; col++) {
|
||||
if (oQRCode.isDark(row, col)) {
|
||||
var child = makeSVG("use", {"x": String(col), "y": String(row)});
|
||||
child.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#template")
|
||||
svg.appendChild(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Drawing.prototype.clear = function () {
|
||||
while (this._el.hasChildNodes())
|
||||
this._el.removeChild(this._el.lastChild);
|
||||
};
|
||||
return Drawing;
|
||||
})();
|
||||
|
||||
var useSVG = document.documentElement.tagName.toLowerCase() === "svg";
|
||||
|
||||
// Drawing in DOM by using Table tag
|
||||
var Drawing = useSVG ? svgDrawer : !_isSupportCanvas() ? (function () {
|
||||
var Drawing = function (el, htOption) {
|
||||
this._el = el;
|
||||
this._htOption = htOption;
|
||||
};
|
||||
|
||||
/**
|
||||
* Draw the QRCode
|
||||
*
|
||||
* @param {QRCode} oQRCode
|
||||
*/
|
||||
Drawing.prototype.draw = function (oQRCode) {
|
||||
var _htOption = this._htOption;
|
||||
var _el = this._el;
|
||||
var nCount = oQRCode.getModuleCount();
|
||||
var nWidth = Math.floor(_htOption.width / nCount);
|
||||
var nHeight = Math.floor(_htOption.height / nCount);
|
||||
var aHTML = ['<table style="border:0;border-collapse:collapse;">'];
|
||||
|
||||
for (var row = 0; row < nCount; row++) {
|
||||
aHTML.push('<tr>');
|
||||
|
||||
for (var col = 0; col < nCount; col++) {
|
||||
aHTML.push('<td style="border:0;border-collapse:collapse;padding:0;margin:0;width:' + nWidth + 'px;height:' + nHeight + 'px;background-color:' + (oQRCode.isDark(row, col) ? _htOption.colorDark : _htOption.colorLight) + ';"></td>');
|
||||
}
|
||||
|
||||
aHTML.push('</tr>');
|
||||
}
|
||||
|
||||
aHTML.push('</table>');
|
||||
_el.innerHTML = aHTML.join('');
|
||||
|
||||
// Fix the margin values as real size.
|
||||
var elTable = _el.childNodes[0];
|
||||
var nLeftMarginTable = (_htOption.width - elTable.offsetWidth) / 2;
|
||||
var nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2;
|
||||
|
||||
if (nLeftMarginTable > 0 && nTopMarginTable > 0) {
|
||||
elTable.style.margin = nTopMarginTable + "px " + nLeftMarginTable + "px";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear the QRCode
|
||||
*/
|
||||
Drawing.prototype.clear = function () {
|
||||
this._el.innerHTML = '';
|
||||
};
|
||||
|
||||
return Drawing;
|
||||
})() : (function () { // Drawing in Canvas
|
||||
function _onMakeImage() {
|
||||
this._elImage.src = this._elCanvas.toDataURL("image/png");
|
||||
this._elImage.style.display = "block";
|
||||
this._elCanvas.style.display = "none";
|
||||
}
|
||||
|
||||
// Android 2.1 bug workaround
|
||||
// http://code.google.com/p/android/issues/detail?id=5141
|
||||
if (this._android && this._android <= 2.1) {
|
||||
var factor = 1 / window.devicePixelRatio;
|
||||
var drawImage = CanvasRenderingContext2D.prototype.drawImage;
|
||||
CanvasRenderingContext2D.prototype.drawImage = function (image, sx, sy, sw, sh, dx, dy, dw, dh) {
|
||||
if (("nodeName" in image) && /img/i.test(image.nodeName)) {
|
||||
for (var i = arguments.length - 1; i >= 1; i--) {
|
||||
arguments[i] = arguments[i] * factor;
|
||||
}
|
||||
} else if (typeof dw == "undefined") {
|
||||
arguments[1] *= factor;
|
||||
arguments[2] *= factor;
|
||||
arguments[3] *= factor;
|
||||
arguments[4] *= factor;
|
||||
}
|
||||
|
||||
drawImage.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the user's browser supports Data URI or not
|
||||
*
|
||||
* @private
|
||||
* @param {Function} fSuccess Occurs if it supports Data URI
|
||||
* @param {Function} fFail Occurs if it doesn't support Data URI
|
||||
*/
|
||||
function _safeSetDataURI(fSuccess, fFail) {
|
||||
var self = this;
|
||||
self._fFail = fFail;
|
||||
self._fSuccess = fSuccess;
|
||||
|
||||
// Check it just once
|
||||
if (self._bSupportDataURI === null) {
|
||||
var el = document.createElement("img");
|
||||
var fOnError = function() {
|
||||
self._bSupportDataURI = false;
|
||||
|
||||
if (self._fFail) {
|
||||
self._fFail.call(self);
|
||||
}
|
||||
};
|
||||
var fOnSuccess = function() {
|
||||
self._bSupportDataURI = true;
|
||||
|
||||
if (self._fSuccess) {
|
||||
self._fSuccess.call(self);
|
||||
}
|
||||
};
|
||||
|
||||
el.onabort = fOnError;
|
||||
el.onerror = fOnError;
|
||||
el.onload = fOnSuccess;
|
||||
el.src = "data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="; // the Image contains 1px data.
|
||||
return;
|
||||
} else if (self._bSupportDataURI === true && self._fSuccess) {
|
||||
self._fSuccess.call(self);
|
||||
} else if (self._bSupportDataURI === false && self._fFail) {
|
||||
self._fFail.call(self);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Drawing QRCode by using canvas
|
||||
*
|
||||
* @constructor
|
||||
* @param {HTMLElement} el
|
||||
* @param {Object} htOption QRCode Options
|
||||
*/
|
||||
var Drawing = function (el, htOption) {
|
||||
this._bIsPainted = false;
|
||||
this._android = _getAndroid();
|
||||
|
||||
this._htOption = htOption;
|
||||
this._elCanvas = document.createElement("canvas");
|
||||
this._elCanvas.width = htOption.width;
|
||||
this._elCanvas.height = htOption.height;
|
||||
el.appendChild(this._elCanvas);
|
||||
this._el = el;
|
||||
this._oContext = this._elCanvas.getContext("2d");
|
||||
this._bIsPainted = false;
|
||||
this._elImage = document.createElement("img");
|
||||
this._elImage.alt = "Scan me!";
|
||||
this._elImage.style.display = "none";
|
||||
this._el.appendChild(this._elImage);
|
||||
this._bSupportDataURI = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Draw the QRCode
|
||||
*
|
||||
* @param {QRCode} oQRCode
|
||||
*/
|
||||
Drawing.prototype.draw = function (oQRCode) {
|
||||
var _elImage = this._elImage;
|
||||
var _oContext = this._oContext;
|
||||
var _htOption = this._htOption;
|
||||
|
||||
var nCount = oQRCode.getModuleCount();
|
||||
var nWidth = _htOption.width / nCount;
|
||||
var nHeight = _htOption.height / nCount;
|
||||
var nRoundedWidth = Math.round(nWidth);
|
||||
var nRoundedHeight = Math.round(nHeight);
|
||||
|
||||
_elImage.style.display = "none";
|
||||
this.clear();
|
||||
|
||||
for (var row = 0; row < nCount; row++) {
|
||||
for (var col = 0; col < nCount; col++) {
|
||||
var bIsDark = oQRCode.isDark(row, col);
|
||||
var nLeft = col * nWidth;
|
||||
var nTop = row * nHeight;
|
||||
_oContext.strokeStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight;
|
||||
_oContext.lineWidth = 1;
|
||||
_oContext.fillStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight;
|
||||
_oContext.fillRect(nLeft, nTop, nWidth, nHeight);
|
||||
|
||||
// 안티 앨리어싱 방지 처리
|
||||
_oContext.strokeRect(
|
||||
Math.floor(nLeft) + 0.5,
|
||||
Math.floor(nTop) + 0.5,
|
||||
nRoundedWidth,
|
||||
nRoundedHeight
|
||||
);
|
||||
|
||||
_oContext.strokeRect(
|
||||
Math.ceil(nLeft) - 0.5,
|
||||
Math.ceil(nTop) - 0.5,
|
||||
nRoundedWidth,
|
||||
nRoundedHeight
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this._bIsPainted = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Make the image from Canvas if the browser supports Data URI.
|
||||
*/
|
||||
Drawing.prototype.makeImage = function () {
|
||||
if (this._bIsPainted) {
|
||||
_safeSetDataURI.call(this, _onMakeImage);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return whether the QRCode is painted or not
|
||||
*
|
||||
* @return {Boolean}
|
||||
*/
|
||||
Drawing.prototype.isPainted = function () {
|
||||
return this._bIsPainted;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear the QRCode
|
||||
*/
|
||||
Drawing.prototype.clear = function () {
|
||||
this._oContext.clearRect(0, 0, this._elCanvas.width, this._elCanvas.height);
|
||||
this._bIsPainted = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Number} nNumber
|
||||
*/
|
||||
Drawing.prototype.round = function (nNumber) {
|
||||
if (!nNumber) {
|
||||
return nNumber;
|
||||
}
|
||||
|
||||
return Math.floor(nNumber * 1000) / 1000;
|
||||
};
|
||||
|
||||
return Drawing;
|
||||
})();
|
||||
|
||||
/**
|
||||
* Get the type by string length
|
||||
*
|
||||
* @private
|
||||
* @param {String} sText
|
||||
* @param {Number} nCorrectLevel
|
||||
* @return {Number} type
|
||||
*/
|
||||
function _getTypeNumber(sText, nCorrectLevel) {
|
||||
var nType = 1;
|
||||
var length = _getUTF8Length(sText);
|
||||
|
||||
for (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) {
|
||||
var nLimit = 0;
|
||||
|
||||
switch (nCorrectLevel) {
|
||||
case QRErrorCorrectLevel.L :
|
||||
nLimit = QRCodeLimitLength[i][0];
|
||||
break;
|
||||
case QRErrorCorrectLevel.M :
|
||||
nLimit = QRCodeLimitLength[i][1];
|
||||
break;
|
||||
case QRErrorCorrectLevel.Q :
|
||||
nLimit = QRCodeLimitLength[i][2];
|
||||
break;
|
||||
case QRErrorCorrectLevel.H :
|
||||
nLimit = QRCodeLimitLength[i][3];
|
||||
break;
|
||||
}
|
||||
|
||||
if (length <= nLimit) {
|
||||
break;
|
||||
} else {
|
||||
nType++;
|
||||
}
|
||||
}
|
||||
|
||||
if (nType > QRCodeLimitLength.length) {
|
||||
throw new Error("Too long data");
|
||||
}
|
||||
|
||||
return nType;
|
||||
}
|
||||
|
||||
function _getUTF8Length(sText) {
|
||||
var replacedText = encodeURI(sText).toString().replace(/\%[0-9a-fA-F]{2}/g, 'a');
|
||||
return replacedText.length + (replacedText.length != sText ? 3 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @class QRCode
|
||||
* @constructor
|
||||
* @example
|
||||
* new QRCode(document.getElementById("test"), "http://jindo.dev.naver.com/collie");
|
||||
*
|
||||
* @example
|
||||
* var oQRCode = new QRCode("test", {
|
||||
* text : "http://naver.com",
|
||||
* width : 128,
|
||||
* height : 128
|
||||
* });
|
||||
*
|
||||
* oQRCode.clear(); // Clear the QRCode.
|
||||
* oQRCode.makeCode("http://map.naver.com"); // Re-create the QRCode.
|
||||
*
|
||||
* @param {HTMLElement|String} el target element or 'id' attribute of element.
|
||||
* @param {Object|String} vOption
|
||||
* @param {String} vOption.text QRCode link data
|
||||
* @param {Number} [vOption.width=256]
|
||||
* @param {Number} [vOption.height=256]
|
||||
* @param {String} [vOption.colorDark="#000000"]
|
||||
* @param {String} [vOption.colorLight="#ffffff"]
|
||||
* @param {QRCode.CorrectLevel} [vOption.correctLevel=QRCode.CorrectLevel.H] [L|M|Q|H]
|
||||
*/
|
||||
QRCode = function (el, vOption) {
|
||||
this._htOption = {
|
||||
width : 256,
|
||||
height : 256,
|
||||
typeNumber : 4,
|
||||
colorDark : "#000000",
|
||||
colorLight : "#ffffff",
|
||||
correctLevel : QRErrorCorrectLevel.H
|
||||
};
|
||||
|
||||
if (typeof vOption === 'string') {
|
||||
vOption = {
|
||||
text : vOption
|
||||
};
|
||||
}
|
||||
|
||||
// Overwrites options
|
||||
if (vOption) {
|
||||
for (var i in vOption) {
|
||||
this._htOption[i] = vOption[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof el == "string") {
|
||||
el = document.getElementById(el);
|
||||
}
|
||||
|
||||
if (this._htOption.useSVG) {
|
||||
Drawing = svgDrawer;
|
||||
}
|
||||
|
||||
this._android = _getAndroid();
|
||||
this._el = el;
|
||||
this._oQRCode = null;
|
||||
this._oDrawing = new Drawing(this._el, this._htOption);
|
||||
|
||||
if (this._htOption.text) {
|
||||
this.makeCode(this._htOption.text);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Make the QRCode
|
||||
*
|
||||
* @param {String} sText link data
|
||||
*/
|
||||
QRCode.prototype.makeCode = function (sText) {
|
||||
this._oQRCode = new QRCodeModel(_getTypeNumber(sText, this._htOption.correctLevel), this._htOption.correctLevel);
|
||||
this._oQRCode.addData(sText);
|
||||
this._oQRCode.make();
|
||||
this._el.title = sText;
|
||||
this._oDrawing.draw(this._oQRCode);
|
||||
this.makeImage();
|
||||
};
|
||||
|
||||
/**
|
||||
* Make the Image from Canvas element
|
||||
* - It occurs automatically
|
||||
* - Android below 3 doesn't support Data-URI spec.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
QRCode.prototype.makeImage = function () {
|
||||
if (typeof this._oDrawing.makeImage == "function" && (!this._android || this._android >= 3)) {
|
||||
this._oDrawing.makeImage();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear the QRCode
|
||||
*/
|
||||
QRCode.prototype.clear = function () {
|
||||
this._oDrawing.clear();
|
||||
};
|
||||
|
||||
/**
|
||||
* @name QRCode.CorrectLevel
|
||||
*/
|
||||
QRCode.CorrectLevel = QRErrorCorrectLevel;
|
||||
})();
|
||||
26
gaia/tv_apps/remote-control/bower_components/smart-button/.bower.json
vendored
Executable file
26
gaia/tv_apps/remote-control/bower_components/smart-button/.bower.json
vendored
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "smart-button",
|
||||
"version": "0.0.2",
|
||||
"homepage": "https://github.com/gaia-components/smart-button",
|
||||
"main": "script.js",
|
||||
"license": "MPL",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests",
|
||||
"examples",
|
||||
"LICENSE",
|
||||
"README.md"
|
||||
],
|
||||
"_release": "0.0.2",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "v0.0.2",
|
||||
"commit": "04fdae935e2f2ba99d1c4f3e156d17f12eb2d142"
|
||||
},
|
||||
"_source": "git://github.com/gaia-components/smart-button.git",
|
||||
"_target": "~0.0.2",
|
||||
"_originalSource": "gaia-components/smart-button"
|
||||
}
|
||||
17
gaia/tv_apps/remote-control/bower_components/smart-button/bower.json
vendored
Executable file
17
gaia/tv_apps/remote-control/bower_components/smart-button/bower.json
vendored
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "smart-button",
|
||||
"version": "0.0.2",
|
||||
"homepage": "https://github.com/gaia-components/smart-button",
|
||||
"main": "script.js",
|
||||
"license": "MPL",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests",
|
||||
"examples",
|
||||
"LICENSE",
|
||||
"README.md"
|
||||
]
|
||||
}
|
||||
62
gaia/tv_apps/remote-control/bower_components/smart-button/script.js
vendored
Executable file
62
gaia/tv_apps/remote-control/bower_components/smart-button/script.js
vendored
Executable file
|
|
@ -0,0 +1,62 @@
|
|||
'use strict';
|
||||
/* global KeyEvent */
|
||||
|
||||
window.SmartButton = (function(win) {
|
||||
// Extend from the HTMLButtonElement prototype
|
||||
var proto = Object.create(HTMLButtonElement.prototype);
|
||||
|
||||
proto.createdCallback = function() {
|
||||
this.addEventListener('mousedown', this);
|
||||
this.addEventListener('mouseup', this);
|
||||
this.addEventListener('touchstart', this);
|
||||
this.addEventListener('touchend', this);
|
||||
this.addEventListener('keydown', this);
|
||||
this.addEventListener('keyup', this);
|
||||
this.addEventListener('focus', this);
|
||||
this.addEventListener('blur', this);
|
||||
this.addEventListener('transitionend', this);
|
||||
this.tabIndex = 0;
|
||||
};
|
||||
|
||||
proto.handleEvent = function(evt) {
|
||||
switch(evt.type) {
|
||||
case 'mousedown':
|
||||
case 'touchstart':
|
||||
this.classList.add('pressed');
|
||||
break;
|
||||
case 'keydown':
|
||||
if (evt.keyCode === KeyEvent.DOM_VK_RETURN) {
|
||||
this.classList.add('pressed');
|
||||
}
|
||||
break;
|
||||
case 'mouseup':
|
||||
case 'touchend':
|
||||
this.classList.remove('pressed');
|
||||
this.classList.add('released');
|
||||
break;
|
||||
case 'keyup':
|
||||
if (evt.keyCode === KeyEvent.DOM_VK_RETURN) {
|
||||
this.classList.remove('pressed');
|
||||
this.classList.add('released');
|
||||
this.click();
|
||||
}
|
||||
break;
|
||||
case 'transitionend':
|
||||
if (this.classList.contains('released')) {
|
||||
this.classList.remove('released');
|
||||
}
|
||||
break;
|
||||
case 'focus':
|
||||
this.classList.add('focused');
|
||||
break;
|
||||
case 'blur':
|
||||
this.classList.remove('pressed');
|
||||
this.classList.remove('released');
|
||||
this.classList.remove('focused');
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// Register and return the constructor
|
||||
return document.registerElement('smart-button', { prototype: proto });
|
||||
})(window);
|
||||
497
gaia/tv_apps/remote-control/bower_components/smart-button/style.css
vendored
Executable file
497
gaia/tv_apps/remote-control/bower_components/smart-button/style.css
vendored
Executable file
|
|
@ -0,0 +1,497 @@
|
|||
/**
|
||||
* Button state:
|
||||
* 1. normal
|
||||
* In this state, we don't add any class.
|
||||
* 2. focused (class name: focused)
|
||||
* The focused state may be triggered by keyboard or touch/mouse.
|
||||
* 3. pressed (class name: pressed)
|
||||
* This state is triggered by user pressed confirm button, mousedown,
|
||||
* and touchdown.
|
||||
* 4. released (class name: released)
|
||||
* This state is only for changing duration of transition. We enter this
|
||||
* state when user release the button. After transitionend, we goes back
|
||||
* to focused state.
|
||||
**/
|
||||
smart-button {
|
||||
font-family: "Fira Sans";
|
||||
display: inline-block;
|
||||
width: 8rem;
|
||||
height: 8rem;
|
||||
/* we need to set border to none to remove the button border */
|
||||
border: none;
|
||||
/* the radius is still make button as round even if we don't have border */
|
||||
border-radius: 50%;
|
||||
/* 50% is not a real circle because of rounding, we have to use a value larger
|
||||
than 50% */
|
||||
-moz-outline-radius: 60%;
|
||||
outline: transparent 0 solid;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 5.4rem auto;
|
||||
background-position: center center;
|
||||
font-style: italic;
|
||||
|
||||
transition-property: all;
|
||||
transition-timing-function: cubic-bezier(0.25, 0, 0, 1.0);
|
||||
transition-duration: 0.42s;
|
||||
}
|
||||
|
||||
smart-button.focused {
|
||||
outline: 0;
|
||||
background-color: #ffffff;
|
||||
transform: scale(1.2);
|
||||
transition-duration: 0.42s;
|
||||
}
|
||||
|
||||
smart-button.released {
|
||||
transition-duration: 0.16s;
|
||||
}
|
||||
|
||||
smart-button.toggled {
|
||||
background-color: #00caf2;
|
||||
}
|
||||
|
||||
smart-button.pressed {
|
||||
background-color: #00caf2;
|
||||
transform: scale(0.8);
|
||||
transition-duration: 0.06s;
|
||||
}
|
||||
|
||||
smart-button.disabled {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
smart-button[data-icon]:before {
|
||||
width: 5.4rem;
|
||||
left: 1.3rem;
|
||||
font-size: 5.4rem;
|
||||
line-height: 8rem;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
white-space: normal;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
smart-button[data-icon].focused:before {
|
||||
color: #2d2d2d;
|
||||
}
|
||||
|
||||
smart-button[data-icon].toggled:before {
|
||||
color: #00caf2;
|
||||
}
|
||||
|
||||
smart-button[data-icon].pressed:before {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
smart-button[data-icon].disabled:before {
|
||||
color: #ffffff;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple Text Button
|
||||
**/
|
||||
smart-button[type="simple-text"] {
|
||||
color: #dddddd;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
|
||||
width: auto;
|
||||
height: 8rem;
|
||||
|
||||
line-height: 8rem;
|
||||
font-size: 2.4rem;
|
||||
-moz-user-select: none;
|
||||
padding-left: 2.6rem;
|
||||
padding-right: 2.6rem;
|
||||
}
|
||||
|
||||
smart-button[type="simple-text"].focused {
|
||||
color: #ffffff;
|
||||
background: none;
|
||||
}
|
||||
|
||||
smart-button[type="simple-text"].toggled {
|
||||
color: #00caf2;
|
||||
}
|
||||
|
||||
smart-button[type="simple-text"].pressed {
|
||||
color: #00caf2;
|
||||
background: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* End of Simple Text Button
|
||||
**/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* underlined text button
|
||||
*/
|
||||
smart-button[type="underlined-text"] {
|
||||
position: relative;
|
||||
color: white;
|
||||
font-size: 2.4rem;
|
||||
padding-left: 3.8rem;
|
||||
padding-right: 3.8rem;
|
||||
border-radius: 4rem;
|
||||
width: auto;
|
||||
line-height: 8rem;
|
||||
margin-right: 1.4rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
smart-button[type="underlined-text"]:after {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
content: ' ';
|
||||
border-bottom: 0.6rem #61acd7 solid;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
smart-button[type="underlined-text"].focused {
|
||||
transform: scale(1.2);
|
||||
color: #2d2d2d;
|
||||
}
|
||||
|
||||
smart-button[type="underlined-text"].pressed {
|
||||
transform: scale(1);
|
||||
color: white;
|
||||
background-color: #00caf2;
|
||||
}
|
||||
|
||||
/**
|
||||
* End of underlined text button
|
||||
*/
|
||||
|
||||
/**
|
||||
* App Icons
|
||||
**/
|
||||
smart-button[type="app-button"] {
|
||||
/* To use 33.4rem instead of to use 33.6rem is to work around the anti-alias
|
||||
pixel. So, the circle is filled by the background almost totally. */
|
||||
width: 33.4rem;
|
||||
height: 33.4rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
smart-button[type="app-button"].focused {
|
||||
transform: scale(1.4);
|
||||
/* To use outline will not change the size of button and make the whole button
|
||||
thrilling. */
|
||||
outline: 0.8rem solid #ffffff;
|
||||
}
|
||||
|
||||
smart-button[type="app-button"].pressed {
|
||||
/* While scaling, we may have a gap between outline and icon which may be
|
||||
anti-alias pixel. So, we use scale(1.22) to prevent such kind of case */
|
||||
transform: scale(1.22);
|
||||
/* To use outline will not change the size of button and make the whole button
|
||||
thrilling. */
|
||||
outline: 1.0rem solid #ffffff;
|
||||
}
|
||||
|
||||
smart-button[type="app-button"].fullsized {
|
||||
background-size: 33.6rem auto;
|
||||
}
|
||||
|
||||
smart-button[type="app-button"].fitted {
|
||||
background-size: 22rem auto;
|
||||
}
|
||||
|
||||
/** we use :after as label */
|
||||
smart-button[type="app-button"]:after {
|
||||
content: attr(label);
|
||||
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: auto;
|
||||
right: auto;
|
||||
|
||||
width: 33.6rem;
|
||||
height: 8rem;
|
||||
|
||||
padding-top: 1rem;
|
||||
|
||||
line-height: 3rem;
|
||||
text-align: center;
|
||||
|
||||
font-size: 2.8rem;
|
||||
font-style: italic;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* text backgorund color
|
||||
**/
|
||||
smart-button[type="app-button"][app-type="deck"]:after {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
smart-button[type="app-button"][app-type="tv"]:after {
|
||||
background-color: #d90c83;
|
||||
}
|
||||
|
||||
smart-button[type="app-button"][app-type="app"]:after {
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
smart-button[type="app-button"][app-type="device"]:after {
|
||||
background-color: #4a82ea;
|
||||
}
|
||||
|
||||
smart-button[type="app-button"][app-type="folder"] {
|
||||
background-color: #595959;
|
||||
}
|
||||
|
||||
smart-button[type="app-button"]:before {
|
||||
left: 0;
|
||||
line-height: 30rem;
|
||||
font-size: 16rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
smart-button[type="app-button"][app-type="folder"]:before {
|
||||
color: #CCCCCC;
|
||||
}
|
||||
|
||||
/**
|
||||
* End of App Icons
|
||||
**/
|
||||
|
||||
/**
|
||||
* text and icon button
|
||||
*/
|
||||
smart-button[type="text-and-icon"] {
|
||||
position: relative;
|
||||
color: white;
|
||||
font-size: 2.4rem;
|
||||
padding-left: 4.6rem;
|
||||
padding-right: 4.6rem;
|
||||
border-radius: 4rem;
|
||||
width: auto;
|
||||
line-height: 8rem;
|
||||
margin-right: 1.4rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
smart-button[type="text-and-icon"][data-icon] {
|
||||
padding-left: 9.6rem;
|
||||
}
|
||||
|
||||
smart-button[type="text-and-icon"][data-icon]:before {
|
||||
left: 3.8rem;
|
||||
}
|
||||
|
||||
smart-button[type="text-and-icon"].focused {
|
||||
transform: scale(1.2);
|
||||
color: #2d2d2d;
|
||||
}
|
||||
|
||||
smart-button[type="text-and-icon"].pressed {
|
||||
transform: scale(1);
|
||||
color: white;
|
||||
background-color: #00caf2;
|
||||
}
|
||||
|
||||
/**
|
||||
* End of text and icon button
|
||||
*/
|
||||
|
||||
/**
|
||||
* banner button
|
||||
**/
|
||||
smart-button[type="banner-button"] {
|
||||
position: relative;
|
||||
|
||||
color: #ffffff;
|
||||
font-size: 2rem;
|
||||
|
||||
width: 36rem;
|
||||
height: 20rem;
|
||||
overflow: hidden;
|
||||
|
||||
border-radius: 0;
|
||||
border: 0 solid #ffffff;
|
||||
|
||||
background-color: #5f5f5f;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 120%;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
transition-property: all;
|
||||
transition-timing-function: cubic-bezier(0.25, 0, 0.5, 1.0);
|
||||
transition-duration: 0.1s;
|
||||
}
|
||||
|
||||
smart-button[type="banner-button"][label]:before {
|
||||
content: attr(label);
|
||||
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
height: 5rem;
|
||||
|
||||
line-height: 5rem;
|
||||
text-align: center;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
smart-button[type="banner-button"]:after {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
transition-property: all;
|
||||
transition-timing-function: cubic-bezier(0.25, 0, 0, 1.0);
|
||||
transition-duration: 0.06s;
|
||||
background-color: rgba(255, 255, 255, 0);
|
||||
}
|
||||
|
||||
smart-button[type="banner-button"].focused {
|
||||
transform: none;
|
||||
border-width: 1.2rem;
|
||||
background-size: 100%;
|
||||
transition-duration: 0.24s;
|
||||
}
|
||||
|
||||
smart-button[type="banner-button"].pressed {
|
||||
transform: scale(0.945, 0.9);
|
||||
}
|
||||
|
||||
smart-button[type="banner-button"].pressed:after {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/**
|
||||
* banner button
|
||||
**/
|
||||
|
||||
/**
|
||||
* circle text button
|
||||
*/
|
||||
smart-button[type="circle-text"] {
|
||||
width: 21rem;
|
||||
height: 21rem;
|
||||
color: white;
|
||||
background-color: #5f6368;
|
||||
line-height: 21rem;
|
||||
padding: 2.5rem 2rem 1.5rem 2rem;
|
||||
text-align: center;
|
||||
font-size: 3.2rem;
|
||||
font-weight: bolder;
|
||||
overflow: hidden;
|
||||
transition-property: transform, color, background-color;
|
||||
}
|
||||
|
||||
smart-button[type="circle-text"].focused {
|
||||
transform: scale(1.2);
|
||||
color: #2d2d2d;
|
||||
background-color: white;
|
||||
transition-property: transform, color, background-color;
|
||||
}
|
||||
|
||||
smart-button[type="circle-text"].pressed {
|
||||
transform: scale(1);
|
||||
color: white;
|
||||
background-color: #00caf2;
|
||||
transition-property: transform, color, background-color;
|
||||
}
|
||||
|
||||
smart-button[type="circle-text"].primary {
|
||||
background-color: #00caf2;
|
||||
transition-property: transform, color, background-color;
|
||||
}
|
||||
|
||||
smart-button[type="circle-text"].primary.focused {
|
||||
color: #ffffff;
|
||||
background-color: #00caf2;
|
||||
transition-property: transform, color, background-color;
|
||||
}
|
||||
|
||||
smart-button[type="circle-text"].primary.pressed {
|
||||
background-color: #0097b5;
|
||||
transition-property: transform, color, background-color;
|
||||
}
|
||||
|
||||
smart-button[type="circle-text"].danger {
|
||||
background-color: #e63d2f;
|
||||
transition-property: transform, color, background-color;
|
||||
}
|
||||
|
||||
smart-button[type="circle-text"].danger.focused {
|
||||
color: #ffffff;
|
||||
background-color: #e63d2f;
|
||||
transition-property: transform, color, background-color;
|
||||
}
|
||||
|
||||
smart-button[type="circle-text"].danger.pressed {
|
||||
background-color: #ac2e23;
|
||||
transition-property: transform, color, background-color;
|
||||
}
|
||||
|
||||
/**
|
||||
* End of circle text button
|
||||
*/
|
||||
|
||||
/**
|
||||
* rounded-corner text button
|
||||
*/
|
||||
smart-button[type="rounded-corner-text"] {
|
||||
-moz-user-select: none;
|
||||
width: auto;
|
||||
height: 8rem;
|
||||
border-radius: 4rem;
|
||||
background-color: #5f6368;
|
||||
padding: 0 3.8rem;
|
||||
line-height: 8rem;
|
||||
color: white;
|
||||
text-align: center;
|
||||
font-size: 2.4rem;
|
||||
overflow: hidden;
|
||||
transition-property: transform, color, background-color;
|
||||
}
|
||||
|
||||
smart-button[type="rounded-corner-text"].focused,
|
||||
smart-button[type="rounded-corner-text"]:hover {
|
||||
transform: scale(1.2);
|
||||
color: #2d2d2d;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
smart-button[type="rounded-corner-text"].pressed {
|
||||
transform: scale(1);
|
||||
/*color: white;*/
|
||||
background-color: #00caf2;
|
||||
}
|
||||
|
||||
smart-button[type="rounded-corner-text"].primary {
|
||||
background-color: #00caf2;
|
||||
}
|
||||
|
||||
smart-button[type="rounded-corner-text"].primary:hover,
|
||||
smart-button[type="rounded-corner-text"].primary.focused {
|
||||
color: #ffffff;
|
||||
background-color: #00caf2;
|
||||
}
|
||||
|
||||
smart-button[type="rounded-corner-text"].primary.pressed {
|
||||
background-color: #0097b5;
|
||||
}
|
||||
|
||||
/**
|
||||
* End of rounded-corner text button
|
||||
*/
|
||||
30
gaia/tv_apps/remote-control/bower_components/smart-icons/.bower.json
vendored
Executable file
30
gaia/tv_apps/remote-control/bower_components/smart-icons/.bower.json
vendored
Executable file
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "smart-icons",
|
||||
"version": "0.0.3",
|
||||
"homepage": "https://github.com/smart-components/smart-icons",
|
||||
"description": "Icon font for smart-screen",
|
||||
"license": "MPL",
|
||||
"private": true,
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"templates",
|
||||
"images",
|
||||
"test",
|
||||
"tests",
|
||||
"index.html",
|
||||
"Gruntfile.js",
|
||||
"README.md",
|
||||
"package.json"
|
||||
],
|
||||
"_release": "0.0.3",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "v0.0.3",
|
||||
"commit": "0c335ac23f484069b4fafa7b7e5afd9f3c08d66e"
|
||||
},
|
||||
"_source": "git://github.com/smart-components/smart-icons.git",
|
||||
"_target": "~0.0.2",
|
||||
"_originalSource": "smart-components/smart-icons"
|
||||
}
|
||||
21
gaia/tv_apps/remote-control/bower_components/smart-icons/bower.json
vendored
Executable file
21
gaia/tv_apps/remote-control/bower_components/smart-icons/bower.json
vendored
Executable file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "smart-icons",
|
||||
"version": "0.0.3",
|
||||
"homepage": "https://github.com/smart-components/smart-icons",
|
||||
"description": "Icon font for smart-screen",
|
||||
"license": "MPL",
|
||||
"private": true,
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"templates",
|
||||
"images",
|
||||
"test",
|
||||
"tests",
|
||||
"index.html",
|
||||
"Gruntfile.js",
|
||||
"README.md",
|
||||
"package.json"
|
||||
]
|
||||
}
|
||||
BIN
gaia/tv_apps/remote-control/bower_components/smart-icons/fonts/smart-icons.ttf
vendored
Executable file
BIN
gaia/tv_apps/remote-control/bower_components/smart-icons/fonts/smart-icons.ttf
vendored
Executable file
Binary file not shown.
25
gaia/tv_apps/remote-control/bower_components/smart-icons/smart-icons-embedded.css
vendored
Executable file
25
gaia/tv_apps/remote-control/bower_components/smart-icons/smart-icons-embedded.css
vendored
Executable file
File diff suppressed because one or more lines are too long
25
gaia/tv_apps/remote-control/bower_components/smart-icons/smart-icons.css
vendored
Executable file
25
gaia/tv_apps/remote-control/bower_components/smart-icons/smart-icons.css
vendored
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
/* Generated by grunt-webfont */
|
||||
/* Based on https://github.com/endtwist/fontcustom/blob/master/lib/fontcustom/templates/fontcustom.css */
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: "smart-icons";
|
||||
src: url("fonts/smart-icons.ttf") format("truetype");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
|
||||
[data-icon]:before,
|
||||
.ligature-icons {
|
||||
font-family: "smart-icons";
|
||||
content: attr(data-icon);
|
||||
display: inline-block;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
text-decoration: inherit;
|
||||
text-transform: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-size: 30px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
89
gaia/tv_apps/remote-control/index.html
Executable file
89
gaia/tv_apps/remote-control/index.html
Executable file
|
|
@ -0,0 +1,89 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<title>Remote Control</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/smart-icons/smart-icons.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/smart-button/style.css">
|
||||
<link rel="stylesheet" type="text/css" href="style/main.css">
|
||||
|
||||
<script defer src="bower_components/smart-button/script.js"></script>
|
||||
<script defer src="bower_components/qrcodejs/qrcode.js"></script>
|
||||
<script defer src="bower_components/evt/index.js"></script>
|
||||
<script defer src="shared/js/settings_listener.js"></script>
|
||||
<script defer src="shared/js/l10n.js"></script>
|
||||
<script defer src="shared/js/smart-screen/key_navigation_adapter.js"></script>
|
||||
<script defer src="shared/js/smart-screen/spatial_navigator.js"></script>
|
||||
<script defer src="js/settings.js"></script>
|
||||
<script defer src="js/section.js"></script>
|
||||
<script defer src="js/settings_section.js"></script>
|
||||
<script defer src="js/app.js"></script>
|
||||
<script defer src="js/bootstrap.js"></script>
|
||||
|
||||
<!-- L10n properties -->
|
||||
<meta name="defaultLanguage" content="en-US">
|
||||
<meta name="availableLanguages" content="en-US">
|
||||
<link rel="localization" href="locales/remote-control.{locale}.properties">
|
||||
</head>
|
||||
<body>
|
||||
<section id="main-section">
|
||||
<h1 data-l10n-id="title"></h1>
|
||||
<div id="settings-icon">
|
||||
<smart-button data-icon="settings" id="settings-button" class="focusable"></smart-button>
|
||||
</div>
|
||||
<div id="main-area">
|
||||
<div id="instruction">
|
||||
<p data-l10n-id="instruction1"></p>
|
||||
<p data-l10n-id="instruction2"></p>
|
||||
<p data-l10n-id="instruction3"></p>
|
||||
</div>
|
||||
<div id="ip"></div>
|
||||
<div id="qrcode" class="focusable">
|
||||
<div id="qrcode-image"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="disabled-message" class="error-message">
|
||||
<div data-l10n-id="disabled-message"></div>
|
||||
<smart-button id="go-to-settings-button" type="rounded-corner-text" class="lower-right-button focusable" data-l10n-id="go-to-settings"></smart-button>
|
||||
</div>
|
||||
<div id="off-line-message" class="error-message">
|
||||
<div data-l10n-id="off-line-message"></div>
|
||||
<smart-button id="exit-button" type="rounded-corner-text" class="lower-right-button focusable" data-l10n-id="exit"></smart-button>
|
||||
</div>
|
||||
</section>
|
||||
<section id="big-qrcode">
|
||||
<div id="big-qrcode-container">
|
||||
<div id="big-qrcode-image"></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="settings-section">
|
||||
<h1 data-l10n-id="settings-title"></h1>
|
||||
<div id="option-list">
|
||||
<div class="option-item">
|
||||
<div id="option-pair-off" class="option-radio focusable"></div>
|
||||
<div class="option-content">
|
||||
<div class="label" data-l10n-id="option-pair-off-label"></div>
|
||||
<div class="description" data-l10n-id="option-pair-off-description"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="option-item">
|
||||
<div id="option-pair-on" class="option-radio focusable"></div>
|
||||
<div class="option-content">
|
||||
<div class="label" data-l10n-id="option-pair-on-label"></div>
|
||||
<div class="description" data-l10n-id="option-pair-on-description"></div>
|
||||
<smart-button id="clear-authorized-devices" type="rounded-corner-text" class="focusable" data-l10n-id="clear-authorized-devices"></smart-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="option-item">
|
||||
<div id="option-disabled" class="option-radio focusable"></div>
|
||||
<div class="option-content">
|
||||
<div class="label" data-l10n-id="option-disabled"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<smart-button id="save-button" type="rounded-corner-text" class="focusable" data-l10n-id="save"></smart-button>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
99
gaia/tv_apps/remote-control/js/app.js
Executable file
99
gaia/tv_apps/remote-control/js/app.js
Executable file
|
|
@ -0,0 +1,99 @@
|
|||
/* global Section, SettingsSection, Settings, QRCode */
|
||||
'use strict';
|
||||
|
||||
(function(exports) {
|
||||
function App(id) {
|
||||
Section.call(this, id);
|
||||
|
||||
this.addChild('big-qrcode', new Section('big-qrcode'));
|
||||
this.addChild('settings-section', new SettingsSection('settings-section'));
|
||||
|
||||
Settings.on('changed', this._onSettingsChanged.bind(this));
|
||||
}
|
||||
|
||||
App.prototype = Object.create(Section.prototype);
|
||||
|
||||
// Section's Interface
|
||||
App.prototype._readyToShow = function(previousId) {
|
||||
this.updateStatus();
|
||||
|
||||
var enabled = Settings['remote-control.enabled'];
|
||||
var hasConnection = !!Settings['remote-control.server-ip'];
|
||||
|
||||
// If the previousId is omitted, it means that this section is shown for the
|
||||
// first time by bootstrap.
|
||||
if (!previousId && enabled && !hasConnection) {
|
||||
this.focus('exit-button');
|
||||
}
|
||||
};
|
||||
|
||||
// Section's Interface
|
||||
App.prototype._handleClick = function() {
|
||||
var elem = this.getFocusedElement();
|
||||
switch(elem.id) {
|
||||
case 'qrcode':
|
||||
this.showChildSection('big-qrcode');
|
||||
break;
|
||||
case 'settings-button':
|
||||
case 'go-to-settings-button':
|
||||
this.showChildSection('settings-section');
|
||||
break;
|
||||
case 'exit-button':
|
||||
window.close();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
App.prototype._onSettingsChanged = function(name, value) {
|
||||
if (name == 'remote-control.server-ip') {
|
||||
this.updateIP(value);
|
||||
}
|
||||
this.updateStatus();
|
||||
};
|
||||
|
||||
App.prototype.updateIP = function(ip) {
|
||||
document.getElementById('ip').textContent = 'http://' + ip;
|
||||
this.updateQRCode('qrcode-image', ip, 260, 260);
|
||||
this.updateQRCode('big-qrcode-image', ip, 540, 540);
|
||||
};
|
||||
|
||||
App.prototype.updateQRCode = function(elemId, ip, width, height) {
|
||||
// Remove the previous one if it exists.
|
||||
var div = document.getElementById(elemId);
|
||||
while (div.firstChild) {
|
||||
div.removeChild(div.firstChild);
|
||||
}
|
||||
|
||||
/* jshint nonew: false */
|
||||
new QRCode(elemId, {
|
||||
text: 'http://' + ip + '/',
|
||||
width: width,
|
||||
height: height,
|
||||
colorDark : '#000000',
|
||||
colorLight : '#ffffff',
|
||||
correctLevel : QRCode.CorrectLevel.L
|
||||
});
|
||||
};
|
||||
|
||||
App.prototype.updateStatus = function() {
|
||||
var setVisible = function(elemId, visible) {
|
||||
var elem = document.getElementById(elemId);
|
||||
elem.classList[visible ? 'add' : 'remove']('visible');
|
||||
};
|
||||
|
||||
var enabled = Settings['remote-control.enabled'];
|
||||
var hasConnection = !!Settings['remote-control.server-ip'];
|
||||
setVisible('main-area', enabled && hasConnection);
|
||||
setVisible('off-line-message', enabled && !hasConnection);
|
||||
setVisible('disabled-message', !enabled);
|
||||
setVisible('settings-icon', enabled);
|
||||
|
||||
if (enabled && hasConnection) {
|
||||
this.focus('qrcode');
|
||||
} else {
|
||||
this.focus();
|
||||
}
|
||||
};
|
||||
|
||||
exports.App = App;
|
||||
}(window));
|
||||
17
gaia/tv_apps/remote-control/js/bootstrap.js
vendored
Executable file
17
gaia/tv_apps/remote-control/js/bootstrap.js
vendored
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
/* global App, Settings, KeyNavigationAdapter */
|
||||
'use strict';
|
||||
|
||||
window.addEventListener('load', function onLoad() {
|
||||
window.removeEventListener('load', onLoad);
|
||||
|
||||
var app = new App('main-section');
|
||||
|
||||
var keyNav = new KeyNavigationAdapter();
|
||||
keyNav.init();
|
||||
keyNav.on('move', app.handleMove.bind(app));
|
||||
keyNav.on('enter', app.handleClick.bind(app));
|
||||
keyNav.on('back', app.handleBack.bind(app));
|
||||
|
||||
Settings.start();
|
||||
Settings.once('ready', app.show.bind(app));
|
||||
});
|
||||
183
gaia/tv_apps/remote-control/js/section.js
Executable file
183
gaia/tv_apps/remote-control/js/section.js
Executable file
|
|
@ -0,0 +1,183 @@
|
|||
/* global SpatialNavigator */
|
||||
'use strict';
|
||||
|
||||
(function(exports) {
|
||||
function Section(id) {
|
||||
this.id = id;
|
||||
this._dom = document.getElementById(this.id);
|
||||
|
||||
var focusables = this._dom.querySelectorAll('.focusable');
|
||||
Array.from(focusables).forEach(function(elem) {
|
||||
elem.setAttribute('tabindex', -1);
|
||||
});
|
||||
|
||||
this._spatialNav = new SpatialNavigator(
|
||||
focusables,
|
||||
{
|
||||
ignoreHiddenElement: true,
|
||||
rememberSource: true
|
||||
}
|
||||
);
|
||||
this._spatialNav.on('focus', (elem) => {
|
||||
elem.focus();
|
||||
});
|
||||
|
||||
this._childSections = {};
|
||||
this._activeChildSectionId = '';
|
||||
this._defaultFocusElement = undefined;
|
||||
this._focusableElementCount = focusables.length;
|
||||
}
|
||||
|
||||
Section.prototype = {
|
||||
uninit: function() {
|
||||
if (this._uninit) {
|
||||
this._uninit();
|
||||
}
|
||||
|
||||
this._defaultFocusElement = undefined;
|
||||
this._activeChildSectionId = '';
|
||||
this._childSections = {};
|
||||
this._parentSection = undefined;
|
||||
this._spatialNav = undefined;
|
||||
this._dom = undefined;
|
||||
},
|
||||
|
||||
addChild: function(id, section) {
|
||||
this._childSections[id] = section;
|
||||
section._parentSection = this;
|
||||
},
|
||||
|
||||
removeChild: function(id) {
|
||||
this._childSections[id]._parentSection = undefined;
|
||||
delete this._childSections[id];
|
||||
},
|
||||
|
||||
focus: function(elem) {
|
||||
if (typeof elem === 'string') {
|
||||
elem = document.getElementById(elem);
|
||||
}
|
||||
return this._spatialNav.focus(elem);
|
||||
},
|
||||
|
||||
unfocus: function() {
|
||||
return this._spatialNav.unfocus();
|
||||
},
|
||||
|
||||
handleMove: function(direction) {
|
||||
var activeChildSection = this.getActiveChildSection();
|
||||
if (activeChildSection) {
|
||||
activeChildSection.handleMove(direction);
|
||||
} else {
|
||||
if (this._handleMove) {
|
||||
var nextElement = this._handleMove(direction);
|
||||
if (nextElement) {
|
||||
if (this._spatialNav.focus(nextElement)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!this._spatialNav.move(direction)) {
|
||||
// If failed to move, re-focus the current one.
|
||||
this._spatialNav.focus();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleClick: function() {
|
||||
var activeChildSection = this.getActiveChildSection();
|
||||
if (activeChildSection) {
|
||||
activeChildSection.handleClick();
|
||||
} else if (this._handleClick) {
|
||||
this._handleClick();
|
||||
} else if (!this._focusableElementCount) {
|
||||
// If there is no focusable element in this section, just close it.
|
||||
this.backToParent();
|
||||
}
|
||||
},
|
||||
|
||||
handleBack: function() {
|
||||
var activeChildSection = this.getActiveChildSection();
|
||||
if (activeChildSection) {
|
||||
if (!activeChildSection.handleBack()) {
|
||||
// Hide the child section if it doesn't handle BACK key.
|
||||
this.hideChildSection();
|
||||
return true;
|
||||
}
|
||||
} else if (this._handleBack) {
|
||||
return this._handleBack();
|
||||
}
|
||||
// Returning false can let BACK key to be bubbled to its parent.
|
||||
return false;
|
||||
},
|
||||
|
||||
getFocusedElement: function() {
|
||||
return this._spatialNav.getFocusedElement();
|
||||
},
|
||||
|
||||
getActiveChildSection: function() {
|
||||
if (!this._activeChildSectionId) {
|
||||
return undefined;
|
||||
}
|
||||
return this._childSections[this._activeChildSectionId];
|
||||
},
|
||||
|
||||
backToParent: function() {
|
||||
if (this._parentSection) {
|
||||
this._parentSection.hideChildSection();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
show: function(previousId) {
|
||||
document.activeElement.blur();
|
||||
|
||||
if (this._readyToShow) {
|
||||
this._readyToShow(previousId);
|
||||
}
|
||||
|
||||
this._dom.classList.add('visible');
|
||||
this._dom.removeAttribute('aria-hidden');
|
||||
|
||||
this._spatialNav.focus(this._defaultFocusElement);
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
this._dom.classList.remove('visible');
|
||||
this._dom.setAttribute('aria-hidden', true);
|
||||
return this;
|
||||
},
|
||||
|
||||
showChildSection: function(id) {
|
||||
var child = this._childSections[id];
|
||||
if (child) {
|
||||
this.hide();
|
||||
this._childSections[id].show();
|
||||
this._activeChildSectionId = id;
|
||||
}
|
||||
},
|
||||
|
||||
hideChildSection: function() {
|
||||
var activeChildSection = this.getActiveChildSection();
|
||||
if (activeChildSection) {
|
||||
var previousId = this._activeChildSectionId;
|
||||
this._activeChildSectionId = '';
|
||||
activeChildSection.hide();
|
||||
this.show(previousId);
|
||||
}
|
||||
},
|
||||
|
||||
setDefaultFocusElement: function(elem) {
|
||||
if (typeof elem === 'string') {
|
||||
elem = document.getElementById(elem);
|
||||
}
|
||||
if (elem) {
|
||||
this._defaultFocusElement = elem;
|
||||
} else {
|
||||
this._defaultFocusElement = undefined;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.Section = Section;
|
||||
}(window));
|
||||
80
gaia/tv_apps/remote-control/js/settings.js
Executable file
80
gaia/tv_apps/remote-control/js/settings.js
Executable file
|
|
@ -0,0 +1,80 @@
|
|||
/* global SettingsListener, evt */
|
||||
'use strict';
|
||||
|
||||
(function(exports) {
|
||||
var WATCH_SETTINGS = {
|
||||
'remote-control.enabled': false,
|
||||
'remote-control.pairing-required': false,
|
||||
'remote-control.authorized-devices': null,
|
||||
'remote-control.server-ip': ''
|
||||
};
|
||||
|
||||
var Settings = evt({
|
||||
_ready: false,
|
||||
_observer: [],
|
||||
|
||||
start: function() {
|
||||
for(var name in WATCH_SETTINGS) {
|
||||
this._observer[name] = this._settingHandler.bind(this, name);
|
||||
SettingsListener.observe(name, WATCH_SETTINGS[name],
|
||||
this._observer[name]);
|
||||
}
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
for(var name in WATCH_SETTINGS) {
|
||||
SettingsListener.unobserve(name, this._observer[name]);
|
||||
this[name] = undefined;
|
||||
}
|
||||
this._observer = [];
|
||||
this._ready = false;
|
||||
},
|
||||
|
||||
save: function(settings) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var validSettings = {};
|
||||
var name;
|
||||
|
||||
for (name in settings) {
|
||||
if (name in WATCH_SETTINGS) {
|
||||
validSettings[name] = settings[name];
|
||||
}
|
||||
}
|
||||
if (!Object.keys(validSettings).length) {
|
||||
reject();
|
||||
}
|
||||
|
||||
var req = SettingsListener.getSettingsLock().set(validSettings);
|
||||
req.onsuccess = () => {
|
||||
for (name in validSettings) {
|
||||
this._settingHandler(name, validSettings[name]);
|
||||
}
|
||||
resolve();
|
||||
};
|
||||
req.onerror = () => {
|
||||
reject();
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
_settingHandler: function(name, value) {
|
||||
if (this[name] !== value) {
|
||||
this[name] = value;
|
||||
this.fire('changed', name, value);
|
||||
}
|
||||
|
||||
// Check whether all settings are retrieved.
|
||||
if (!this._ready) {
|
||||
var hasValue = (name) => {
|
||||
return this[name] !== undefined;
|
||||
};
|
||||
if (Object.keys(WATCH_SETTINGS).every(hasValue)) {
|
||||
this._ready = true;
|
||||
this.fire('ready');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
exports.Settings = Settings;
|
||||
}(window));
|
||||
148
gaia/tv_apps/remote-control/js/settings_section.js
Executable file
148
gaia/tv_apps/remote-control/js/settings_section.js
Executable file
|
|
@ -0,0 +1,148 @@
|
|||
/* global Section, Settings */
|
||||
'use strict';
|
||||
|
||||
(function(exports) {
|
||||
function SettingsSection(id) {
|
||||
Section.call(this, id);
|
||||
Settings.on('changed', this._onSettingsChanged.bind(this));
|
||||
}
|
||||
|
||||
SettingsSection.prototype = Object.create(Section.prototype);
|
||||
|
||||
// Section's Interface
|
||||
SettingsSection.prototype._readyToShow = function() {
|
||||
if (Settings['remote-control.enabled']) {
|
||||
if (Settings['remote-control.pairing-required']) {
|
||||
this._checkedOption = 'option-pair-on';
|
||||
} else {
|
||||
this._checkedOption = 'option-pair-off';
|
||||
}
|
||||
} else {
|
||||
this._checkedOption = 'option-disabled';
|
||||
}
|
||||
|
||||
this.checkRadio(this._checkedOption);
|
||||
this.setDefaultFocusElement(this._checkedOption);
|
||||
|
||||
this.updateClearAuthorizedDevicesButton();
|
||||
};
|
||||
|
||||
// Section's Interface
|
||||
SettingsSection.prototype._handleMove = function(direction) {
|
||||
var elem = this.getFocusedElement();
|
||||
if ((elem.id == 'option-pair-on' && direction == 'down') ||
|
||||
(elem.id == 'option-disabled' && direction == 'up')) {
|
||||
return document.getElementById('clear-authorized-devices');
|
||||
}
|
||||
};
|
||||
|
||||
// Section's Interface
|
||||
SettingsSection.prototype._handleClick = function() {
|
||||
if (this._pendingSave) {
|
||||
return;
|
||||
}
|
||||
|
||||
var elem = this.getFocusedElement();
|
||||
switch(elem.id) {
|
||||
case 'option-pair-off':
|
||||
case 'option-pair-on':
|
||||
case 'option-disabled':
|
||||
this.checkRadio(elem.id);
|
||||
break;
|
||||
case 'clear-authorized-devices':
|
||||
navigator.mozL10n.formatValue('clear-authorized-devices-message')
|
||||
.then((string) => {
|
||||
if (confirm(string)) {
|
||||
this.clearAuthorizedDevices();
|
||||
}
|
||||
});
|
||||
break;
|
||||
case 'save-button':
|
||||
this.saveSettings();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
SettingsSection.prototype._onSettingsChanged = function(name, value) {
|
||||
if (name == 'remote-control.authorized-devices') {
|
||||
this.updateClearAuthorizedDevicesButton();
|
||||
}
|
||||
};
|
||||
|
||||
SettingsSection.prototype.checkRadio = function(id) {
|
||||
var radios = document.querySelectorAll('.option-radio');
|
||||
Array.from(radios).forEach(function(radio) {
|
||||
if (radio.id == id) {
|
||||
radio.classList.add('checked');
|
||||
} else {
|
||||
radio.classList.remove('checked');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
SettingsSection.prototype.updateClearAuthorizedDevicesButton = function() {
|
||||
var authorizedDevices = Settings['remote-control.authorized-devices'];
|
||||
var authorizedDevicesCount = 0;
|
||||
if (authorizedDevices) {
|
||||
authorizedDevicesCount = Object.keys(authorizedDevices).length;
|
||||
}
|
||||
|
||||
var button = document.getElementById('clear-authorized-devices');
|
||||
if (authorizedDevicesCount) {
|
||||
button.classList.remove('disabled');
|
||||
button.removeAttribute('aria-hidden');
|
||||
} else {
|
||||
button.classList.add('disabled');
|
||||
button.setAttribute('aria-hidden', true);
|
||||
}
|
||||
};
|
||||
|
||||
SettingsSection.prototype.clearAuthorizedDevices = function() {
|
||||
Settings.save({
|
||||
'remote-control.authorized-devices': {}
|
||||
}).then(() => {
|
||||
this.updateClearAuthorizedDevicesButton();
|
||||
this.focus('save-button');
|
||||
});
|
||||
};
|
||||
|
||||
SettingsSection.prototype.saveSettings = function() {
|
||||
var checkedOption = document.querySelector('.option-radio.checked').id;
|
||||
var callback = () => {
|
||||
this._pendingSave = undefined;
|
||||
this._checkedOption = undefined;
|
||||
this.backToParent();
|
||||
};
|
||||
|
||||
this._pendingSave = true;
|
||||
|
||||
if (checkedOption == this._checkedOption) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
// Also clear authorized devices when user changes the mode.
|
||||
var settings = {
|
||||
'remote-control.authorized-devices': {}
|
||||
};
|
||||
|
||||
switch(checkedOption) {
|
||||
case 'option-pair-on':
|
||||
settings['remote-control.enabled'] = true;
|
||||
settings['remote-control.pairing-required'] = true;
|
||||
break;
|
||||
case 'option-pair-off':
|
||||
settings['remote-control.enabled'] = true;
|
||||
settings['remote-control.pairing-required'] = false;
|
||||
break;
|
||||
case 'option-disabled':
|
||||
settings['remote-control.enabled'] = false;
|
||||
settings['remote-control.pairing-required'] = false;
|
||||
break;
|
||||
}
|
||||
|
||||
Settings.save(settings).then(callback).catch(callback);
|
||||
};
|
||||
|
||||
exports.SettingsSection = SettingsSection;
|
||||
}(window));
|
||||
17
gaia/tv_apps/remote-control/locales/remote-control.en-US.properties
Executable file
17
gaia/tv_apps/remote-control/locales/remote-control.en-US.properties
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
title=TV Remote Control
|
||||
instruction1=How it works?
|
||||
instruction2=You can remote control your TV using any device with a browser without downloading an app. Launch the browser on your other device and connect to the link below (or scan the barcode).
|
||||
instruction3=Please note that the TV and the controlling device need to be on the same Wi-Fi network.
|
||||
settings-title=Settings
|
||||
option-pair-off-label=Pairing code - OFF
|
||||
option-pair-off-description=Never ask to enter pairing code
|
||||
option-pair-on-label=Pairing code - ON
|
||||
option-pair-on-description=Pairing code will be asked on the first connection from a new device.
|
||||
clear-authorized-devices=clear paired devices
|
||||
clear-authorized-devices-message=Do you want to clear all paired devices?
|
||||
option-disabled=Disable remote control
|
||||
save=Save
|
||||
disabled-message=Remote control is disabled, please go to Settings to enable this feature.
|
||||
off-line-message=Your TV is offline. Please connect to the Internet and try again.
|
||||
exit=Exit
|
||||
go-to-settings=Go to Settings
|
||||
25
gaia/tv_apps/remote-control/manifest.webapp
Executable file
25
gaia/tv_apps/remote-control/manifest.webapp
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"name": "Remote Control",
|
||||
"description": "Remote Control",
|
||||
"launch_path": "/index.html",
|
||||
"type": "certified",
|
||||
"developer": {
|
||||
"name": "The Gaia Team",
|
||||
"url": "https://github.com/mozilla-b2g/gaia"
|
||||
},
|
||||
"locales": {
|
||||
"en-US": {
|
||||
"name": "Remote Control",
|
||||
"description": "Remote Control"
|
||||
}
|
||||
},
|
||||
"default_locale": "en-US",
|
||||
"icons": {
|
||||
"128": "/style/icons/remote_control.png"
|
||||
},
|
||||
"orientation": "landscape",
|
||||
"permissions": {
|
||||
"settings": { "access": "readwrite" },
|
||||
"moz-extremely-unstable-and-will-change-webcomponents": {}
|
||||
}
|
||||
}
|
||||
BIN
gaia/tv_apps/remote-control/style/icons/remote_control.png
Executable file
BIN
gaia/tv_apps/remote-control/style/icons/remote_control.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 7.3 KiB |
226
gaia/tv_apps/remote-control/style/main.css
Executable file
226
gaia/tv_apps/remote-control/style/main.css
Executable file
|
|
@ -0,0 +1,226 @@
|
|||
html {
|
||||
font-size: 10px;
|
||||
/* We have Fira Sans as default font in real device. But it isn't default in
|
||||
* browser. That's the main reason this line is here.*/
|
||||
font-family: "Fira Sans";
|
||||
}
|
||||
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
section {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 6rem 35.5rem 0 36rem;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
font-size: 4.6rem;
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #4d4d4d;
|
||||
}
|
||||
|
||||
#settings-section {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#settings-section.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#settings-icon {
|
||||
position: absolute;
|
||||
right: 6rem;
|
||||
top: 4rem;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#settings-icon.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#main-area {
|
||||
position: relative;
|
||||
display: none;
|
||||
margin: 16.5rem 0 0 4.5rem;
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
color: #4d4d4d;
|
||||
}
|
||||
|
||||
#main-area.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#qrcode {
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
right: 0;
|
||||
top: 0;
|
||||
transition-property: all;
|
||||
transition-timing-function: cubic-bezier(0.25, 0, 0, 1.0);
|
||||
transition-duration: 0.42s;
|
||||
}
|
||||
|
||||
#qrcode:focus {
|
||||
outline: 1rem solid #00cbf4;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
#qrcode-image {
|
||||
margin: 3rem;
|
||||
width: 26rem;
|
||||
height: 26rem;
|
||||
}
|
||||
|
||||
#instruction {
|
||||
width: 78rem;
|
||||
}
|
||||
|
||||
#instruction p {
|
||||
font-size: 2.8rem;
|
||||
margin: 0 0 1.5rem 0;
|
||||
}
|
||||
|
||||
#ip {
|
||||
margin-top: 4.5rem;
|
||||
font-size: 6rem;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
margin: 16rem 0 0 4.5rem;
|
||||
width: 78rem;
|
||||
font-size: 2.8rem;
|
||||
line-height: 5.6rem;
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.error-message.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
smart-button[type="rounded-corner-text"].lower-right-button {
|
||||
position: absolute;
|
||||
right: 40.5rem;
|
||||
bottom: 41rem;
|
||||
width: 23.7rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#big-qrcode {
|
||||
padding: 0;
|
||||
background-color: rgba(0, 0, 0, 0.9);
|
||||
display: flex;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.1s ease-in;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#big-qrcode.visible {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
#big-qrcode-container {
|
||||
background-color: white;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#big-qrcode-image {
|
||||
margin: 3rem;
|
||||
width: 54rem;
|
||||
height: 54rem;
|
||||
}
|
||||
|
||||
#option-list {
|
||||
color: #4d4d4d;
|
||||
margin: 12rem 0 0 4.5rem;
|
||||
}
|
||||
|
||||
.option-item {
|
||||
margin-bottom: 7rem;
|
||||
}
|
||||
|
||||
.option-radio, .option-content {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.option-radio {
|
||||
width: 6rem;
|
||||
height: 6rem;
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
border: 0.4rem solid #5f6368;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
outline: none;
|
||||
transition-property: all;
|
||||
transition-timing-function: cubic-bezier(0.25, 0, 0, 1.0);
|
||||
transition-duration: 0.42s;
|
||||
}
|
||||
|
||||
.option-radio.checked:after {
|
||||
font-family: "smart-icons";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-size: 7rem;
|
||||
line-height: 5.5rem;
|
||||
margin-left: -0.8rem;
|
||||
text-rendering: optimizelegibility;
|
||||
content: "check";
|
||||
color: #00caf2;
|
||||
}
|
||||
|
||||
.option-radio:focus {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
.option-content {
|
||||
margin: 0.8rem 0 0 2.5rem;
|
||||
}
|
||||
|
||||
.option-content .label {
|
||||
font-size: 3.8rem;
|
||||
}
|
||||
|
||||
.option-content .description {
|
||||
margin-top: 2.5rem;
|
||||
font-size: 2.8rem;
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
#clear-authorized-devices {
|
||||
margin-top: 2.5rem;
|
||||
width: 34rem;
|
||||
}
|
||||
|
||||
#clear-authorized-devices.disabled {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
#save-button {
|
||||
position: absolute;
|
||||
right: 40.5rem;
|
||||
bottom: 14rem;
|
||||
width: 23.7rem;
|
||||
text-align: center;
|
||||
}
|
||||
Loading…
Reference in a new issue