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
82
gaia/distros/spark/apps/customizer/components/esprima/ChangeLog
Executable file
82
gaia/distros/spark/apps/customizer/components/esprima/ChangeLog
Executable file
|
|
@ -0,0 +1,82 @@
|
|||
2015-02-06: Version 2.0.0
|
||||
|
||||
* Support ES6 arrow function (issue 517)
|
||||
* Support ES6 Unicode code point escape (issue 521)
|
||||
* Improve the speed and accuracy of comment attachment (issue 522)
|
||||
* Support ES6 default parameter (issue 519)
|
||||
* Support ES6 regular expression flags (issue 557)
|
||||
* Fix scanning of implicit octal literals (issue 565)
|
||||
* Fix the handling of automatic semicolon insertion (issue 574)
|
||||
* Support ES6 method definition (issue 620)
|
||||
* Support ES6 octal integer literal (issue 621)
|
||||
* Support ES6 binary integer literal (issue 622)
|
||||
* Support ES6 object literal property value shorthand (issue 624)
|
||||
|
||||
2015-01-18: Version 1.2.3
|
||||
|
||||
* Fix division by this (issue 616)
|
||||
|
||||
2014-05-18: Version 1.2.2
|
||||
|
||||
* Fix duplicated tokens when collecting comments (issue 537)
|
||||
|
||||
2014-05-04: Version 1.2.1
|
||||
|
||||
* Ensure that Program node may still have leading comments (issue 536)
|
||||
|
||||
2014-04-29: Version 1.2.0
|
||||
|
||||
* Fix semicolon handling for expression statement (issue 462, 533)
|
||||
* Disallow escaped characters in regular expression flags (issue 503)
|
||||
* Performance improvement for location tracking (issue 520)
|
||||
* Improve the speed of comment attachment (issue 522)
|
||||
|
||||
2014-03-26: Version 1.1.1
|
||||
|
||||
* Fix token handling of forward slash after an array literal (issue 512)
|
||||
|
||||
2014-03-23: Version 1.1.0
|
||||
|
||||
* Optionally attach comments to the owning syntax nodes (issue 197)
|
||||
* Simplify binary parsing with stack-based shift reduce (issue 352)
|
||||
* Always include the raw source of literals (issue 376)
|
||||
* Add optional input source information (issue 386)
|
||||
* Tokenizer API for pure lexical scanning (issue 398)
|
||||
* Improve the web site and its online demos (issue 337, 400, 404)
|
||||
* Performance improvement for location tracking (issue 417, 424)
|
||||
* Support HTML comment syntax (issue 451)
|
||||
* Drop support for legacy browsers (issue 474)
|
||||
|
||||
2013-08-27: Version 1.0.4
|
||||
|
||||
* Minimize the payload for packages (issue 362)
|
||||
* Fix missing cases on an empty switch statement (issue 436)
|
||||
* Support escaped ] in regexp literal character classes (issue 442)
|
||||
* Tolerate invalid left-hand side expression (issue 130)
|
||||
|
||||
2013-05-17: Version 1.0.3
|
||||
|
||||
* Variable declaration needs at least one declarator (issue 391)
|
||||
* Fix benchmark's variance unit conversion (issue 397)
|
||||
* IE < 9: \v should be treated as vertical tab (issue 405)
|
||||
* Unary expressions should always have prefix: true (issue 418)
|
||||
* Catch clause should only accept an identifier (issue 423)
|
||||
* Tolerate setters without parameter (issue 426)
|
||||
|
||||
2012-11-02: Version 1.0.2
|
||||
|
||||
Improvement:
|
||||
|
||||
* Fix esvalidate JUnit output upon a syntax error (issue 374)
|
||||
|
||||
2012-10-28: Version 1.0.1
|
||||
|
||||
Improvements:
|
||||
|
||||
* esvalidate understands shebang in a Unix shell script (issue 361)
|
||||
* esvalidate treats fatal parsing failure as an error (issue 361)
|
||||
* Reduce Node.js package via .npmignore (issue 362)
|
||||
|
||||
2012-10-22: Version 1.0.0
|
||||
|
||||
Initial release.
|
||||
19
gaia/distros/spark/apps/customizer/components/esprima/LICENSE.BSD
Executable file
19
gaia/distros/spark/apps/customizer/components/esprima/LICENSE.BSD
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
127
gaia/distros/spark/apps/customizer/components/esprima/bin/esparse.js
Executable file
127
gaia/distros/spark/apps/customizer/components/esprima/bin/esparse.js
Executable file
|
|
@ -0,0 +1,127 @@
|
|||
#!/usr/bin/env node
|
||||
/*
|
||||
Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*jslint sloppy:true node:true rhino:true */
|
||||
|
||||
var fs, esprima, fname, content, options, syntax;
|
||||
|
||||
if (typeof require === 'function') {
|
||||
fs = require('fs');
|
||||
esprima = require('esprima');
|
||||
} else if (typeof load === 'function') {
|
||||
try {
|
||||
load('esprima.js');
|
||||
} catch (e) {
|
||||
load('../esprima.js');
|
||||
}
|
||||
}
|
||||
|
||||
// Shims to Node.js objects when running under Rhino.
|
||||
if (typeof console === 'undefined' && typeof process === 'undefined') {
|
||||
console = { log: print };
|
||||
fs = { readFileSync: readFile };
|
||||
process = { argv: arguments, exit: quit };
|
||||
process.argv.unshift('esparse.js');
|
||||
process.argv.unshift('rhino');
|
||||
}
|
||||
|
||||
function showUsage() {
|
||||
console.log('Usage:');
|
||||
console.log(' esparse [options] file.js');
|
||||
console.log();
|
||||
console.log('Available options:');
|
||||
console.log();
|
||||
console.log(' --comment Gather all line and block comments in an array');
|
||||
console.log(' --loc Include line-column location info for each syntax node');
|
||||
console.log(' --range Include index-based range for each syntax node');
|
||||
console.log(' --raw Display the raw value of literals');
|
||||
console.log(' --tokens List all tokens in an array');
|
||||
console.log(' --tolerant Tolerate errors on a best-effort basis (experimental)');
|
||||
console.log(' -v, --version Shows program version');
|
||||
console.log();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (process.argv.length <= 2) {
|
||||
showUsage();
|
||||
}
|
||||
|
||||
options = {};
|
||||
|
||||
process.argv.splice(2).forEach(function (entry) {
|
||||
|
||||
if (entry === '-h' || entry === '--help') {
|
||||
showUsage();
|
||||
} else if (entry === '-v' || entry === '--version') {
|
||||
console.log('ECMAScript Parser (using Esprima version', esprima.version, ')');
|
||||
console.log();
|
||||
process.exit(0);
|
||||
} else if (entry === '--comment') {
|
||||
options.comment = true;
|
||||
} else if (entry === '--loc') {
|
||||
options.loc = true;
|
||||
} else if (entry === '--range') {
|
||||
options.range = true;
|
||||
} else if (entry === '--raw') {
|
||||
options.raw = true;
|
||||
} else if (entry === '--tokens') {
|
||||
options.tokens = true;
|
||||
} else if (entry === '--tolerant') {
|
||||
options.tolerant = true;
|
||||
} else if (entry.slice(0, 2) === '--') {
|
||||
console.log('Error: unknown option ' + entry + '.');
|
||||
process.exit(1);
|
||||
} else if (typeof fname === 'string') {
|
||||
console.log('Error: more than one input file.');
|
||||
process.exit(1);
|
||||
} else {
|
||||
fname = entry;
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof fname !== 'string') {
|
||||
console.log('Error: no input file.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Special handling for regular expression literal since we need to
|
||||
// convert it to a string literal, otherwise it will be decoded
|
||||
// as object "{}" and the regular expression would be lost.
|
||||
function adjustRegexLiteral(key, value) {
|
||||
if (key === 'value' && value instanceof RegExp) {
|
||||
value = value.toString();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
try {
|
||||
content = fs.readFileSync(fname, 'utf-8');
|
||||
syntax = esprima.parse(content, options);
|
||||
console.log(JSON.stringify(syntax, adjustRegexLiteral, 4));
|
||||
} catch (e) {
|
||||
console.log('Error: ' + e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
199
gaia/distros/spark/apps/customizer/components/esprima/bin/esvalidate.js
Executable file
199
gaia/distros/spark/apps/customizer/components/esprima/bin/esvalidate.js
Executable file
|
|
@ -0,0 +1,199 @@
|
|||
#!/usr/bin/env node
|
||||
/*
|
||||
Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*jslint sloppy:true plusplus:true node:true rhino:true */
|
||||
/*global phantom:true */
|
||||
|
||||
var fs, system, esprima, options, fnames, count;
|
||||
|
||||
if (typeof esprima === 'undefined') {
|
||||
// PhantomJS can only require() relative files
|
||||
if (typeof phantom === 'object') {
|
||||
fs = require('fs');
|
||||
system = require('system');
|
||||
esprima = require('./esprima');
|
||||
} else if (typeof require === 'function') {
|
||||
fs = require('fs');
|
||||
esprima = require('esprima');
|
||||
} else if (typeof load === 'function') {
|
||||
try {
|
||||
load('esprima.js');
|
||||
} catch (e) {
|
||||
load('../esprima.js');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shims to Node.js objects when running under PhantomJS 1.7+.
|
||||
if (typeof phantom === 'object') {
|
||||
fs.readFileSync = fs.read;
|
||||
process = {
|
||||
argv: [].slice.call(system.args),
|
||||
exit: phantom.exit
|
||||
};
|
||||
process.argv.unshift('phantomjs');
|
||||
}
|
||||
|
||||
// Shims to Node.js objects when running under Rhino.
|
||||
if (typeof console === 'undefined' && typeof process === 'undefined') {
|
||||
console = { log: print };
|
||||
fs = { readFileSync: readFile };
|
||||
process = { argv: arguments, exit: quit };
|
||||
process.argv.unshift('esvalidate.js');
|
||||
process.argv.unshift('rhino');
|
||||
}
|
||||
|
||||
function showUsage() {
|
||||
console.log('Usage:');
|
||||
console.log(' esvalidate [options] file.js');
|
||||
console.log();
|
||||
console.log('Available options:');
|
||||
console.log();
|
||||
console.log(' --format=type Set the report format, plain (default) or junit');
|
||||
console.log(' -v, --version Print program version');
|
||||
console.log();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (process.argv.length <= 2) {
|
||||
showUsage();
|
||||
}
|
||||
|
||||
options = {
|
||||
format: 'plain'
|
||||
};
|
||||
|
||||
fnames = [];
|
||||
|
||||
process.argv.splice(2).forEach(function (entry) {
|
||||
|
||||
if (entry === '-h' || entry === '--help') {
|
||||
showUsage();
|
||||
} else if (entry === '-v' || entry === '--version') {
|
||||
console.log('ECMAScript Validator (using Esprima version', esprima.version, ')');
|
||||
console.log();
|
||||
process.exit(0);
|
||||
} else if (entry.slice(0, 9) === '--format=') {
|
||||
options.format = entry.slice(9);
|
||||
if (options.format !== 'plain' && options.format !== 'junit') {
|
||||
console.log('Error: unknown report format ' + options.format + '.');
|
||||
process.exit(1);
|
||||
}
|
||||
} else if (entry.slice(0, 2) === '--') {
|
||||
console.log('Error: unknown option ' + entry + '.');
|
||||
process.exit(1);
|
||||
} else {
|
||||
fnames.push(entry);
|
||||
}
|
||||
});
|
||||
|
||||
if (fnames.length === 0) {
|
||||
console.log('Error: no input file.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (options.format === 'junit') {
|
||||
console.log('<?xml version="1.0" encoding="UTF-8"?>');
|
||||
console.log('<testsuites>');
|
||||
}
|
||||
|
||||
count = 0;
|
||||
fnames.forEach(function (fname) {
|
||||
var content, timestamp, syntax, name;
|
||||
try {
|
||||
content = fs.readFileSync(fname, 'utf-8');
|
||||
|
||||
if (content[0] === '#' && content[1] === '!') {
|
||||
content = '//' + content.substr(2, content.length);
|
||||
}
|
||||
|
||||
timestamp = Date.now();
|
||||
syntax = esprima.parse(content, { tolerant: true });
|
||||
|
||||
if (options.format === 'junit') {
|
||||
|
||||
name = fname;
|
||||
if (name.lastIndexOf('/') >= 0) {
|
||||
name = name.slice(name.lastIndexOf('/') + 1);
|
||||
}
|
||||
|
||||
console.log('<testsuite name="' + fname + '" errors="0" ' +
|
||||
' failures="' + syntax.errors.length + '" ' +
|
||||
' tests="' + syntax.errors.length + '" ' +
|
||||
' time="' + Math.round((Date.now() - timestamp) / 1000) +
|
||||
'">');
|
||||
|
||||
syntax.errors.forEach(function (error) {
|
||||
var msg = error.message;
|
||||
msg = msg.replace(/^Line\ [0-9]*\:\ /, '');
|
||||
console.log(' <testcase name="Line ' + error.lineNumber + ': ' + msg + '" ' +
|
||||
' time="0">');
|
||||
console.log(' <error type="SyntaxError" message="' + error.message + '">' +
|
||||
error.message + '(' + name + ':' + error.lineNumber + ')' +
|
||||
'</error>');
|
||||
console.log(' </testcase>');
|
||||
});
|
||||
|
||||
console.log('</testsuite>');
|
||||
|
||||
} else if (options.format === 'plain') {
|
||||
|
||||
syntax.errors.forEach(function (error) {
|
||||
var msg = error.message;
|
||||
msg = msg.replace(/^Line\ [0-9]*\:\ /, '');
|
||||
msg = fname + ':' + error.lineNumber + ': ' + msg;
|
||||
console.log(msg);
|
||||
++count;
|
||||
});
|
||||
|
||||
}
|
||||
} catch (e) {
|
||||
++count;
|
||||
if (options.format === 'junit') {
|
||||
console.log('<testsuite name="' + fname + '" errors="1" failures="0" tests="1" ' +
|
||||
' time="' + Math.round((Date.now() - timestamp) / 1000) + '">');
|
||||
console.log(' <testcase name="' + e.message + '" ' + ' time="0">');
|
||||
console.log(' <error type="ParseError" message="' + e.message + '">' +
|
||||
e.message + '(' + fname + ((e.lineNumber) ? ':' + e.lineNumber : '') +
|
||||
')</error>');
|
||||
console.log(' </testcase>');
|
||||
console.log('</testsuite>');
|
||||
} else {
|
||||
console.log('Error: ' + e.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (options.format === 'junit') {
|
||||
console.log('</testsuites>');
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (count === 0 && typeof phantom === 'object') {
|
||||
process.exit(0);
|
||||
}
|
||||
29
gaia/distros/spark/apps/customizer/components/esprima/bower.json
Executable file
29
gaia/distros/spark/apps/customizer/components/esprima/bower.json
Executable file
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "esprima",
|
||||
"version": "2.0.0",
|
||||
"main": "./esprima.js",
|
||||
"scripts": [
|
||||
"esprima.js"
|
||||
],
|
||||
"dependencies": {},
|
||||
"ignore": [
|
||||
"examples",
|
||||
"test",
|
||||
"tools"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/jquery/esprima.git"
|
||||
},
|
||||
"licenses": [{
|
||||
"type": "BSD",
|
||||
"url": "http://github.com/jquery/esprima/raw/master/LICENSE.BSD"
|
||||
}],
|
||||
"keywords": [
|
||||
"ast",
|
||||
"ecmascript",
|
||||
"javascript",
|
||||
"parser",
|
||||
"syntax"
|
||||
]
|
||||
}
|
||||
24
gaia/distros/spark/apps/customizer/components/esprima/component.json
Executable file
24
gaia/distros/spark/apps/customizer/components/esprima/component.json
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "esprima",
|
||||
"version": "2.0.0",
|
||||
"main": "./esprima.js",
|
||||
"scripts": [
|
||||
"esprima.js"
|
||||
],
|
||||
"dependencies": {},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/jquery/esprima.git"
|
||||
},
|
||||
"licenses": [{
|
||||
"type": "BSD",
|
||||
"url": "http://github.com/jquery/esprima/raw/master/LICENSE.BSD"
|
||||
}],
|
||||
"keywords": [
|
||||
"ast",
|
||||
"ecmascript",
|
||||
"javascript",
|
||||
"parser",
|
||||
"syntax"
|
||||
]
|
||||
}
|
||||
4156
gaia/distros/spark/apps/customizer/components/esprima/esprima.js
Executable file
4156
gaia/distros/spark/apps/customizer/components/esprima/esprima.js
Executable file
File diff suppressed because one or more lines are too long
79
gaia/distros/spark/apps/customizer/components/esprima/package.json
Executable file
79
gaia/distros/spark/apps/customizer/components/esprima/package.json
Executable file
|
|
@ -0,0 +1,79 @@
|
|||
{
|
||||
"name": "esprima",
|
||||
"description": "ECMAScript parsing infrastructure for multipurpose analysis",
|
||||
"homepage": "http://esprima.org",
|
||||
"main": "esprima.js",
|
||||
"bin": {
|
||||
"esparse": "./bin/esparse.js",
|
||||
"esvalidate": "./bin/esvalidate.js"
|
||||
},
|
||||
"version": "2.0.0",
|
||||
"files": [
|
||||
"bin",
|
||||
"test/run.js",
|
||||
"test/runner.js",
|
||||
"test/test.js",
|
||||
"test/compat.js",
|
||||
"test/reflect.js",
|
||||
"esprima.js"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
},
|
||||
"author": {
|
||||
"name": "Ariya Hidayat",
|
||||
"email": "ariya.hidayat@gmail.com"
|
||||
},
|
||||
"maintainers": [{
|
||||
"name": "Ariya Hidayat",
|
||||
"email": "ariya.hidayat@gmail.com",
|
||||
"web": "http://ariya.ofilabs.com"
|
||||
}],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jquery/esprima.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "http://issues.esprima.org"
|
||||
},
|
||||
"licenses": [{
|
||||
"type": "BSD",
|
||||
"url": "https://github.com/jquery/esprima/raw/master/LICENSE.BSD"
|
||||
}],
|
||||
"devDependencies": {
|
||||
"eslint": "~0.12.0",
|
||||
"jscs": "~1.10.0",
|
||||
"istanbul": "~0.2.6",
|
||||
"escomplex-js": "1.0.0",
|
||||
"complexity-report": "~1.1.1",
|
||||
"regenerate": "~0.6.2",
|
||||
"unicode-7.0.0": "~0.1.5",
|
||||
"json-diff": "~0.3.1",
|
||||
"optimist": "~0.6.0"
|
||||
},
|
||||
"keywords": [
|
||||
"ast",
|
||||
"ecmascript",
|
||||
"javascript",
|
||||
"parser",
|
||||
"syntax"
|
||||
],
|
||||
"scripts": {
|
||||
"generate-regex": "node tools/generate-identifier-regex.js",
|
||||
|
||||
"test": "node test/run.js && npm run lint && npm run coverage",
|
||||
|
||||
"lint": "npm run check-version && npm run eslint && npm run jscs && npm run complexity",
|
||||
"check-version": "node tools/check-version.js",
|
||||
"jscs": "jscs esprima.js test/*test.js",
|
||||
"eslint": "node node_modules/eslint/bin/eslint.js esprima.js",
|
||||
"complexity": "node tools/list-complexity.js && cr -s -l -w --maxcyc 16 esprima.js",
|
||||
|
||||
"coverage": "npm run analyze-coverage && npm run check-coverage",
|
||||
"analyze-coverage": "node node_modules/istanbul/lib/cli.js cover test/runner.js",
|
||||
"check-coverage": "node node_modules/istanbul/lib/cli.js check-coverage --statement 100 --branch 100 --function 100",
|
||||
|
||||
"benchmark": "node test/benchmarks.js",
|
||||
"benchmark-quick": "node test/benchmarks.js quick"
|
||||
}
|
||||
}
|
||||
18
gaia/distros/spark/apps/customizer/components/font-fit/bower.json
Executable file
18
gaia/distros/spark/apps/customizer/components/font-fit/bower.json
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "font-fit",
|
||||
"main": "font-fit.js",
|
||||
"version": "0.3.1",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"README.md",
|
||||
"index.html",
|
||||
"package.json"
|
||||
]
|
||||
}
|
||||
132
gaia/distros/spark/apps/customizer/components/font-fit/font-fit.js
Executable file
132
gaia/distros/spark/apps/customizer/components/font-fit/font-fit.js
Executable file
|
|
@ -0,0 +1,132 @@
|
|||
;(function(define){define(function(require,exports,module){
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Simple logger.
|
||||
*
|
||||
* @return {Function}
|
||||
*/
|
||||
var debug = 0 ? console.log.bind(console) : function(){};
|
||||
|
||||
/**
|
||||
* Global canvas cache.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var cache = {};
|
||||
|
||||
/**
|
||||
* Default min/max font-size.
|
||||
*
|
||||
* @type {Number}
|
||||
*/
|
||||
var MIN = 16;
|
||||
var MAX = 24;
|
||||
|
||||
/**
|
||||
* The number of pixels to subtract from
|
||||
* the given `config.space` to ensure
|
||||
* HTML text doesn't overflow container.
|
||||
*
|
||||
* Ideally we would use 1px, but in some
|
||||
* cases italicised text in canvas is ~2px
|
||||
* longer than the same text in HTML.
|
||||
*
|
||||
* http://bugzil.la/1126391
|
||||
*
|
||||
* @type {Number}
|
||||
*/
|
||||
var BUFFER = 3;
|
||||
|
||||
/**
|
||||
* Get the font-size that closest fits
|
||||
* the given space with the given font.
|
||||
*
|
||||
* Config:
|
||||
*
|
||||
* - {String} `text` The text string
|
||||
* - {String} `font` Font shorthand string
|
||||
* - {Number} `space` Width (px) to fit the text into
|
||||
* - {Number} `min` Min font-size (px) (optional)
|
||||
* - {Number} `max` Max font-size (px) (optional)
|
||||
*
|
||||
* @param {Object} config
|
||||
* @return {Object} {fontSize,overflowing,textWidth}
|
||||
*/
|
||||
module.exports = function(config) {
|
||||
debug('font fit', config);
|
||||
var space = config.space - BUFFER;
|
||||
var min = config.min || MIN;
|
||||
var max = config.max || MAX;
|
||||
var text = trim(config.text);
|
||||
var fontSize = max;
|
||||
var textWidth;
|
||||
var font;
|
||||
|
||||
do {
|
||||
font = config.font.replace(/\d+px/, fontSize + 'px');
|
||||
textWidth = getTextWidth(text, font);
|
||||
} while (textWidth > space && fontSize !== min && fontSize--);
|
||||
|
||||
return {
|
||||
textWidth: textWidth,
|
||||
fontSize: fontSize,
|
||||
overflowing: textWidth > space
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the width of the given text
|
||||
* with the given font style.
|
||||
*
|
||||
* @param {String} text
|
||||
* @param {String} font (CSS shorthand)
|
||||
* @return {Number} (px)
|
||||
*/
|
||||
function getTextWidth(text, font) {
|
||||
var ctx = getCanvasContext(font);
|
||||
var width = ctx.measureText(text).width;
|
||||
debug('got text width', width);
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a canvas context configured
|
||||
* to the given font style.
|
||||
*
|
||||
* @param {String} font
|
||||
* @return {CanvasRenderingContext2D}
|
||||
*/
|
||||
function getCanvasContext(font) {
|
||||
debug('get canvas context', font);
|
||||
|
||||
var cached = cache[font];
|
||||
if (cached) { return cached; }
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.setAttribute('moz-opaque', 'true');
|
||||
canvas.setAttribute('width', '1px');
|
||||
canvas.setAttribute('height', '1px');
|
||||
debug('created canvas', canvas);
|
||||
|
||||
var ctx = canvas.getContext('2d', { willReadFrequently: true });
|
||||
ctx.font = font;
|
||||
|
||||
return cache[font] = ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim leading, trailing
|
||||
* and excess whitespace.
|
||||
*
|
||||
* @param {String} text
|
||||
* @return {String}
|
||||
*/
|
||||
function trim(text) {
|
||||
return text.replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('font-fit',this));
|
||||
15
gaia/distros/spark/apps/customizer/components/fxos-mvc/bower.json
Executable file
15
gaia/distros/spark/apps/customizer/components/fxos-mvc/bower.json
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "fxos-mvc",
|
||||
"version": "0.0.7",
|
||||
"homepage": "https://github.com/fxos/mvc",
|
||||
"license": "MPL",
|
||||
"main": "mvc.js",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"example",
|
||||
"node_modules",
|
||||
"package.json",
|
||||
"README.md",
|
||||
"test"
|
||||
]
|
||||
}
|
||||
1660
gaia/distros/spark/apps/customizer/components/fxos-mvc/dist/mvc.js
vendored
Executable file
1660
gaia/distros/spark/apps/customizer/components/fxos-mvc/dist/mvc.js
vendored
Executable file
File diff suppressed because it is too large
Load diff
44
gaia/distros/spark/apps/customizer/components/fxos-mvc/gulpfile.js
Executable file
44
gaia/distros/spark/apps/customizer/components/fxos-mvc/gulpfile.js
Executable file
|
|
@ -0,0 +1,44 @@
|
|||
var gulp = require('gulp');
|
||||
var merge = require('gulp-merge');
|
||||
var concat = require('gulp-concat');
|
||||
var wrapper = require('gulp-wrapper');
|
||||
var to5 = require('gulp-6to5');
|
||||
|
||||
/**
|
||||
* converts javascript to es5.
|
||||
*/
|
||||
gulp.task('to5', function () {
|
||||
try {
|
||||
return merge(
|
||||
gulp
|
||||
.src([
|
||||
'./node_modules/observe-shim/lib/observe-shim.js',
|
||||
'./node_modules/observe-utils/lib/observe-utils.js'
|
||||
])
|
||||
.pipe(concat('shim.js')),
|
||||
gulp
|
||||
.src([
|
||||
'./node_modules/sanitizer/sanitizer.js'
|
||||
])
|
||||
.pipe(wrapper({
|
||||
header: '(function(){var define,exports;',
|
||||
footer: '})(window);'
|
||||
}))
|
||||
.pipe(concat('deps.js')),
|
||||
gulp
|
||||
.src('./mvc.js')
|
||||
.pipe(to5({
|
||||
modules: 'amd'
|
||||
}).on('error', function(e) {
|
||||
console.log('error running 6to5', e);
|
||||
})
|
||||
)
|
||||
)
|
||||
.pipe(concat('mvc.js'))
|
||||
.pipe(gulp.dest('./dist/'));
|
||||
} catch(e) {
|
||||
console.log('Got error in 6to5', e);
|
||||
}
|
||||
});
|
||||
|
||||
gulp.task('default', ['to5']);
|
||||
312
gaia/distros/spark/apps/customizer/components/fxos-mvc/mvc.js
Executable file
312
gaia/distros/spark/apps/customizer/components/fxos-mvc/mvc.js
Executable file
|
|
@ -0,0 +1,312 @@
|
|||
/**
|
||||
* Model
|
||||
*/
|
||||
export class Model {
|
||||
constructor(properties) {
|
||||
properties = properties || {};
|
||||
|
||||
for (var key in properties) {
|
||||
this[key] = properties[key];
|
||||
}
|
||||
|
||||
this.observableProperties = {};
|
||||
|
||||
Object.observe(this, (changes) => {
|
||||
changes.forEach((change) => {
|
||||
var handlers = this.observableProperties[change.name];
|
||||
if (handlers) {
|
||||
handlers.forEach((handler) => {
|
||||
handler(change);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
on(property, handler) {
|
||||
if (typeof handler !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.observableProperties[property]) {
|
||||
ObserveUtils.defineObservableProperties(this, property);
|
||||
this.observableProperties[property] = [];
|
||||
}
|
||||
|
||||
this.observableProperties[property].push(handler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* View
|
||||
*/
|
||||
var events = {};
|
||||
|
||||
export class View {
|
||||
constructor(options) {
|
||||
options = options || {};
|
||||
|
||||
for (var key in options) {
|
||||
this[key] = options[key];
|
||||
}
|
||||
|
||||
if (!this.el) {
|
||||
this.el = document.createElement('div');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an instance with the specified controller.
|
||||
*
|
||||
* @param {Controller} controller
|
||||
* @return {View}
|
||||
*/
|
||||
init(controller) {
|
||||
this.controller = controller;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the layout wrapper for the template.
|
||||
*
|
||||
* @param {Template} Inner template
|
||||
* @return {String} Rendered layout with template
|
||||
*/
|
||||
layout(template) {
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the default template.
|
||||
*/
|
||||
render(params) {
|
||||
var innerHTML = '';
|
||||
|
||||
if (params) {
|
||||
if (typeof params === 'object') {
|
||||
for (var index in params) {
|
||||
var param = params[index];
|
||||
innerHTML += this.template(param);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
var param = params[i];
|
||||
innerHTML += this.template(param);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
innerHTML = this.template();
|
||||
}
|
||||
|
||||
this.el.innerHTML = this.layout(innerHTML);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to provide a function that returns the template string.
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
template() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a single child element using the specified selector.
|
||||
*
|
||||
* @param {String} query
|
||||
* @return {Element | null}
|
||||
*/
|
||||
$(selector) {
|
||||
return this.el.querySelector(selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all child elements using the specified selector.
|
||||
*
|
||||
* @param {String} query
|
||||
* @return {NodeList}
|
||||
*/
|
||||
$$(selector) {
|
||||
return this.el.querySelectorAll(selector);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
on(type, selector, handler, scope) {
|
||||
var controller = this.controller;
|
||||
scope = scope || this.el;
|
||||
|
||||
if (!events[type]) {
|
||||
events[type] = [];
|
||||
window.addEventListener(type, delegateHandler, true);
|
||||
}
|
||||
|
||||
events[type].push({
|
||||
selector: selector,
|
||||
handler: handler,
|
||||
controller: controller,
|
||||
scope: scope
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
off(type, selector, handler) {
|
||||
if (!events[type]) {
|
||||
return;
|
||||
}
|
||||
|
||||
events[type] = events[type].filter((delegate) => {
|
||||
if (typeof handler === 'function') {
|
||||
return delegate.selector !== selector ||
|
||||
delegate.handler !== handler;
|
||||
}
|
||||
|
||||
return delegate.selector !== selector;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward an event based on the target's `[data-action]` attr to the controller.
|
||||
* e.g. "click" on a `<button data-action="cancel">` goes to controller.cancel()
|
||||
*/
|
||||
function handleAction(event, controller) {
|
||||
var action = event.target.dataset.action;
|
||||
if (controller && controller[action]) {
|
||||
controller[action](event);
|
||||
}
|
||||
}
|
||||
|
||||
function delegateHandler(event) {
|
||||
var target = event.target;
|
||||
|
||||
events[event.type].forEach((delegate) => {
|
||||
if (delegate.scope.contains(target) && target.matches(delegate.selector)) {
|
||||
if (delegate.handler) {
|
||||
delegate.handler.call(target, event);
|
||||
} else {
|
||||
handleAction(event, delegate.controller);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller
|
||||
*/
|
||||
export class Controller {
|
||||
constructor(options) {
|
||||
options = options || {};
|
||||
|
||||
for (var key in options) {
|
||||
this[key] = options[key];
|
||||
}
|
||||
|
||||
// Initialize the view (if applicable) when the
|
||||
// controller is instantiated.
|
||||
if (this.view && typeof this.view.init === 'function') {
|
||||
this.view.init(this);
|
||||
}
|
||||
}
|
||||
|
||||
teardown() {
|
||||
|
||||
}
|
||||
|
||||
main() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export class RoutingController extends Controller {
|
||||
constructor(controllers) {
|
||||
if (window.routingController) {
|
||||
console.error('Document can only contain one RoutingController');
|
||||
return;
|
||||
}
|
||||
|
||||
super();
|
||||
this._controllers = controllers;
|
||||
this.activeController = null;
|
||||
window.routingController = this;
|
||||
window.addEventListener('hashchange', this.route.bind(this));
|
||||
}
|
||||
|
||||
route() {
|
||||
var route = window.location.hash.slice(1);
|
||||
var controller = this._controllers[route];
|
||||
if (controller) {
|
||||
if (this.activeController) {
|
||||
this.activeController.teardown();
|
||||
}
|
||||
|
||||
this.activeController = controller;
|
||||
controller.main();
|
||||
}
|
||||
}
|
||||
|
||||
controller(id) {
|
||||
return this._controllers[id];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Service
|
||||
*/
|
||||
export class Service {
|
||||
constructor() {
|
||||
this._listeners = {};
|
||||
this._dispatchedEvents = {};
|
||||
}
|
||||
|
||||
addEventListener(name, callback, trigger) {
|
||||
if (!this._listeners[name]) {
|
||||
this._listeners[name] = [callback];
|
||||
} else {
|
||||
this._listeners[name].push(callback);
|
||||
}
|
||||
|
||||
if (trigger && this._dispatchedEvents[name] !== undefined) {
|
||||
setTimeout(() => {
|
||||
callback(this._dispatchedEvents[name]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeEventListener(name, callback) {
|
||||
if (!this._listeners[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var listenerIndex;
|
||||
this._listeners[name].find((listener, index) => {
|
||||
if (listener === callback) {
|
||||
listenerIndex = index;
|
||||
}
|
||||
|
||||
return listenerIndex !== undefined;
|
||||
});
|
||||
|
||||
if (listenerIndex !== undefined) {
|
||||
this._listeners[name].splice(listenerIndex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
_dispatchEvent(name, params) {
|
||||
if (!this._listeners[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._dispatchedEvents[name] = params || null;
|
||||
|
||||
this._listeners[name].forEach((listener) => {
|
||||
listener(params);
|
||||
});
|
||||
}
|
||||
}
|
||||
26
gaia/distros/spark/apps/customizer/components/gaia-button/bower.json
Executable file
26
gaia/distros/spark/apps/customizer/components/gaia-button/bower.json
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "gaia-button",
|
||||
"version": "0.0.3",
|
||||
"main": "gaia-button.js",
|
||||
"homepage": "https://github.com/gaia-components/gaia-button",
|
||||
"authors": [
|
||||
"cyee@mozilla.com"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
],
|
||||
"devDependencies": {
|
||||
"gaia-fonts": "gaia-components/gaia-fonts#~0.2.1",
|
||||
"gaia-icons": "gaia-components/gaia-icons#~0.7.1",
|
||||
"base": "gaia-components/base",
|
||||
"gaia-theme": "gaia-components/gaia-theme#~0.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"gaia-component": "gaia-components/gaia-component#~0.3.0"
|
||||
}
|
||||
}
|
||||
198
gaia/distros/spark/apps/customizer/components/gaia-button/gaia-button.js
Executable file
198
gaia/distros/spark/apps/customizer/components/gaia-button/gaia-button.js
Executable file
|
|
@ -0,0 +1,198 @@
|
|||
(function(define){define(function(require,exports,module){
|
||||
/*jshint esnext:true*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
module.exports = component.register('gaia-button', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
this.setAttribute('role', 'button');
|
||||
this.tabIndex = 0;
|
||||
},
|
||||
|
||||
attrs: {
|
||||
circular: {
|
||||
get: function() { return this.getAttribute('circular'); },
|
||||
set: function(value) {
|
||||
value = !!(value === '' || value);
|
||||
if (value) {
|
||||
this.setAttribute('circular', '');
|
||||
} else {
|
||||
this.removeAttribute('circular');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
disabled: {
|
||||
get: function() { return this.getAttribute('disabled'); },
|
||||
set: function(value) {
|
||||
value = !!(value === '' || value);
|
||||
if (value) {
|
||||
this.setAttribute('disabled', '');
|
||||
} else {
|
||||
this.removeAttribute('disabled');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
template: `
|
||||
<div class="inner">
|
||||
<div class="background"></div>
|
||||
<div class="content"><content></content></div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
height: 50px;
|
||||
min-width: 50%;
|
||||
border-radius: 50px;
|
||||
margin: var(--base-m, 18px) 0;
|
||||
outline: 0;
|
||||
font-style: italic;
|
||||
font-size: 17px;
|
||||
cursor: pointer;
|
||||
-moz-user-select: none;
|
||||
line-height: 1;
|
||||
|
||||
background:
|
||||
var(--button-background,
|
||||
var(--input-background,
|
||||
var(--background-plus,
|
||||
#fff)));
|
||||
|
||||
color:
|
||||
var(--button-color,
|
||||
var(--text-color,
|
||||
inherit));
|
||||
|
||||
box-shadow:
|
||||
var(--button-box-shadow,
|
||||
var(--box-shadow,
|
||||
none));
|
||||
|
||||
transition: color 0ms 300ms;
|
||||
}
|
||||
|
||||
@media(min-width:500px) {
|
||||
:host { min-width: 140px; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Pressed
|
||||
*/
|
||||
|
||||
:host(:active) {
|
||||
color: var(--button-color-active, #fff);
|
||||
box-shadow: var(--button-box-shadow-active, none);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* [circular]
|
||||
*/
|
||||
|
||||
:host([circular]) {
|
||||
width: 50px;
|
||||
min-width: 0;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
:host([disabled]) {
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/** Inner
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.inner {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/** Background
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.background {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
|
||||
transition: opacity 500ms 200ms;
|
||||
|
||||
background:
|
||||
var(--button-background-active,
|
||||
var(--highlight-color,
|
||||
#333));
|
||||
}
|
||||
|
||||
:active .background {
|
||||
transition: none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Content
|
||||
---------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* 1. In some cases events seems to be getting
|
||||
* swallowed by text-nodes. Ignoring pointer-
|
||||
* events means we can listen on parent nodes
|
||||
* instead.
|
||||
*/
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
height: 100%;
|
||||
padding: 0 18px;
|
||||
pointer-events: none; /* 1 */
|
||||
}
|
||||
|
||||
[circular] .content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
i:before {
|
||||
font-size: 26px;
|
||||
}
|
||||
|
||||
::content i {
|
||||
margin-left: -2px;
|
||||
margin-right: -2px;
|
||||
}
|
||||
|
||||
::content i + span,
|
||||
::content span + i {
|
||||
-moz-margin-start: 8px;
|
||||
}
|
||||
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})((function(n,w){return typeof define=='function'&&define.amd?
|
||||
define:typeof module=='object'?function(c){c(require,exports,module);}:function(c){
|
||||
var m={exports:{}},r=function(n){return w[n];};w[n]=c(r,m.exports,m)||m.exports;};})('gaia-button',this));
|
||||
66
gaia/distros/spark/apps/customizer/components/gaia-button/index.html
Executable file
66
gaia/distros/spark/apps/customizer/components/gaia-button/index.html
Executable file
|
|
@ -0,0 +1,66 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title><gaia-button></title>
|
||||
<meta name="description" content="gaia-text-input demo" />
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/base/base.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-theme/gaia-theme.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-icons/gaia-icons.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-fonts/style.css">
|
||||
<script src="bower_components/gaia-theme/lib/gaia-theme-selector.js"></script>
|
||||
<script src="bower_components/gaia-component/gaia-component.js"></script>
|
||||
<script src="gaia-button.js"></script>
|
||||
<style type="text/css">
|
||||
|
||||
body {
|
||||
padding-top: 48px;
|
||||
background-color: var(--background);
|
||||
}
|
||||
/*
|
||||
[data-icon=back-light] {
|
||||
margin-left: -9px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
|
||||
[data-icon=forward-light] {
|
||||
margin-left: 10px;
|
||||
margin-right: -9px;
|
||||
}*/
|
||||
|
||||
[flex] {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body role="application" class="l-align-center">
|
||||
<gaia-theme-selector></gaia-theme-selector>
|
||||
<h1 class="large l-align-center l-mb-mega"><gaia-button></h1>
|
||||
|
||||
<section>
|
||||
<gaia-button>Gaia button 1</gaia-button>
|
||||
<gaia-button disabled>Gaia button 1</gaia-button>
|
||||
</section>
|
||||
|
||||
<hr/>
|
||||
|
||||
<section>
|
||||
<gaia-button><i data-icon="back-light"></i><span>Back</span></gaia-button>
|
||||
<gaia-button><span>Forward</span><i data-icon="forward-light"></i></gaia-button>
|
||||
</section>
|
||||
|
||||
<hr/>
|
||||
|
||||
<section flex>
|
||||
<gaia-button circular><i data-icon="camera"></i></gaia-button>
|
||||
<gaia-button circular><i data-icon="bug"></i></gaia-button>
|
||||
<gaia-button circular><i data-icon="video"></i></gaia-button>
|
||||
<gaia-button circular><i data-icon="camera"></i></gaia-button>
|
||||
<gaia-button circular><i data-icon="reload"></i></gaia-button>
|
||||
<gaia-button circular><i data-icon="airplane"></i></gaia-button>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
18
gaia/distros/spark/apps/customizer/components/gaia-component/bower.json
Executable file
18
gaia/distros/spark/apps/customizer/components/gaia-component/bower.json
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "gaia-component",
|
||||
"version": "0.3.8",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "gaia-component.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"README.md",
|
||||
"package.json",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
]
|
||||
}
|
||||
420
gaia/distros/spark/apps/customizer/components/gaia-component/gaia-component.js
Executable file
420
gaia/distros/spark/apps/customizer/components/gaia-component/gaia-component.js
Executable file
|
|
@ -0,0 +1,420 @@
|
|||
/* globals define */
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
/**
|
||||
* Locals
|
||||
*/
|
||||
var textContent = Object.getOwnPropertyDescriptor(Node.prototype,
|
||||
'textContent');
|
||||
var innerHTML = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
|
||||
var removeAttribute = Element.prototype.removeAttribute;
|
||||
var setAttribute = Element.prototype.setAttribute;
|
||||
var noop = function() {};
|
||||
|
||||
/**
|
||||
* Register a new component.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Object} props
|
||||
* @return {constructor}
|
||||
* @public
|
||||
*/
|
||||
exports.register = function(name, props) {
|
||||
var baseProto = getBaseProto(props.extends);
|
||||
var template = props.template || baseProto.templateString;
|
||||
|
||||
// Components are extensible by default but can be declared
|
||||
// as non extensible as an optimization to avoid
|
||||
// storing the template strings
|
||||
var extensible = props.extensible = props.hasOwnProperty('extensible')?
|
||||
props.extensible : true;
|
||||
|
||||
// Clean up
|
||||
delete props.extends;
|
||||
|
||||
// Pull out CSS that needs to be in the light-dom
|
||||
if (template) {
|
||||
// Stores the string to be reprocessed when
|
||||
// a new component extends this one
|
||||
if (extensible && props.template) {
|
||||
props.templateString = props.template;
|
||||
}
|
||||
|
||||
var output = processCss(template, name);
|
||||
|
||||
props.template = document.createElement('template');
|
||||
props.template.innerHTML = output.template;
|
||||
props.lightCss = output.lightCss;
|
||||
|
||||
props.globalCss = props.globalCss || '';
|
||||
props.globalCss += output.globalCss;
|
||||
}
|
||||
|
||||
// Inject global CSS into the document,
|
||||
// and delete as no longer needed
|
||||
injectGlobalCss(props.globalCss);
|
||||
delete props.globalCss;
|
||||
|
||||
// Merge base getter/setter attributes with the user's,
|
||||
// then define the property descriptors on the prototype.
|
||||
var descriptors = mixin(props.attrs || {}, base.descriptors);
|
||||
|
||||
// Store the orginal descriptors somewhere
|
||||
// a little more private and delete the original
|
||||
props._attrs = props.attrs;
|
||||
delete props.attrs;
|
||||
|
||||
// Create the prototype, extended from base and
|
||||
// define the descriptors directly on the prototype
|
||||
var proto = createProto(baseProto, props);
|
||||
Object.defineProperties(proto, descriptors);
|
||||
|
||||
// Register the custom-element and return the constructor
|
||||
try {
|
||||
return document.registerElement(name, { prototype: proto });
|
||||
} catch (e) {
|
||||
if (e.name !== 'NotSupportedError') {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var base = {
|
||||
properties: {
|
||||
GaiaComponent: true,
|
||||
attributeChanged: noop,
|
||||
attached: noop,
|
||||
detached: noop,
|
||||
created: noop,
|
||||
|
||||
createdCallback: function() {
|
||||
if (this.rtl) { addDirObserver(); }
|
||||
injectLightCss(this);
|
||||
this.created();
|
||||
},
|
||||
|
||||
/**
|
||||
* It is very common to want to keep object
|
||||
* properties in-sync with attributes,
|
||||
* for example:
|
||||
*
|
||||
* el.value = 'foo';
|
||||
* el.setAttribute('value', 'foo');
|
||||
*
|
||||
* So we support an object on the prototype
|
||||
* named 'attrs' to provide a consistent
|
||||
* way for component authors to define
|
||||
* these properties. When an attribute
|
||||
* changes we keep the attr[name]
|
||||
* up-to-date.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String||null} from
|
||||
* @param {String||null} to
|
||||
*/
|
||||
attributeChangedCallback: function(name, from, to) {
|
||||
var prop = toCamelCase(name);
|
||||
if (this._attrs && this._attrs[prop]) { this[prop] = to; }
|
||||
this.attributeChanged(name, from, to);
|
||||
},
|
||||
|
||||
attachedCallback: function() { this.attached(); },
|
||||
detachedCallback: function() { this.detached(); },
|
||||
|
||||
/**
|
||||
* A convenient method for setting up
|
||||
* a shadow-root using the defined template.
|
||||
*
|
||||
* @return {ShadowRoot}
|
||||
*/
|
||||
setupShadowRoot: function() {
|
||||
if (!this.template) { return; }
|
||||
var node = document.importNode(this.template.content, true);
|
||||
this.createShadowRoot().appendChild(node);
|
||||
return this.shadowRoot;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets an attribute internally
|
||||
* and externally. This is so that
|
||||
* we can style internal shadow-dom
|
||||
* content.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String} value
|
||||
*/
|
||||
setAttr: function(name, value) {
|
||||
var internal = this.shadowRoot.firstElementChild;
|
||||
setAttribute.call(internal, name, value);
|
||||
setAttribute.call(this, name, value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes an attribute internally
|
||||
* and externally. This is so that
|
||||
* we can style internal shadow-dom
|
||||
* content.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String} value
|
||||
*/
|
||||
removeAttr: function(name) {
|
||||
var internal = this.shadowRoot.firstElementChild;
|
||||
removeAttribute.call(internal, name);
|
||||
removeAttribute.call(this, name);
|
||||
}
|
||||
},
|
||||
|
||||
descriptors: {
|
||||
textContent: {
|
||||
set: function(value) {
|
||||
textContent.set.call(this, value);
|
||||
if (this.lightStyle) { this.appendChild(this.lightStyle); }
|
||||
},
|
||||
|
||||
get: function() {
|
||||
return textContent.get();
|
||||
}
|
||||
},
|
||||
|
||||
innerHTML: {
|
||||
set: function(value) {
|
||||
innerHTML.set.call(this, value);
|
||||
if (this.lightStyle) { this.appendChild(this.lightStyle); }
|
||||
},
|
||||
|
||||
get: innerHTML.get
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The default base prototype to use
|
||||
* when `extends` is undefined.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var defaultPrototype = createProto(HTMLElement.prototype, base.properties);
|
||||
|
||||
/**
|
||||
* Returns a suitable prototype based
|
||||
* on the object passed.
|
||||
*
|
||||
* @private
|
||||
* @param {HTMLElementPrototype|undefined} proto
|
||||
* @return {HTMLElementPrototype}
|
||||
*/
|
||||
function getBaseProto(proto) {
|
||||
if (!proto) { return defaultPrototype; }
|
||||
proto = proto.prototype || proto;
|
||||
return !proto.GaiaComponent ?
|
||||
createProto(proto, base.properties) : proto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends the given proto and mixes
|
||||
* in the given properties.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} proto
|
||||
* @param {Object} props
|
||||
* @return {Object}
|
||||
*/
|
||||
function createProto(proto, props) {
|
||||
return mixin(Object.create(proto), props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects presence of shadow-dom
|
||||
* CSS selectors.
|
||||
*
|
||||
* @private
|
||||
* @return {Boolean}
|
||||
*/
|
||||
var hasShadowCSS = (function() {
|
||||
var div = document.createElement('div');
|
||||
try { div.querySelector(':host'); div.querySelector('::content'); return true; }
|
||||
catch (e) { return false; }
|
||||
})();
|
||||
|
||||
/**
|
||||
* Regexs used to extract shadow-css
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var regex = {
|
||||
shadowCss: /(?:\:host|\:\:content)[^{]*\{[^}]*\}/g,
|
||||
':host': /(?:\:host)/g,
|
||||
':host()': /\:host\((.+)\)(?: \:\:content)?/g,
|
||||
':host-context': /\:host-context\((.+)\)([^{,]+)?/g,
|
||||
'::content': /(?:\:\:content)/g
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts the :host and ::content rules
|
||||
* from the shadow-dom CSS and rewrites
|
||||
* them to work from the <style scoped>
|
||||
* injected at the root of the component.
|
||||
*
|
||||
* @private
|
||||
* @return {String}
|
||||
*/
|
||||
function processCss(template, name) {
|
||||
var globalCss = '';
|
||||
var lightCss = '';
|
||||
|
||||
if (!hasShadowCSS) {
|
||||
template = template.replace(regex.shadowCss, function(match) {
|
||||
var hostContext = regex[':host-context'].exec(match);
|
||||
|
||||
if (hostContext) {
|
||||
globalCss += match
|
||||
.replace(regex['::content'], '')
|
||||
.replace(regex[':host-context'], '$1 ' + name + '$2')
|
||||
.replace(/ +/g, ' '); // excess whitespace
|
||||
} else {
|
||||
lightCss += match
|
||||
.replace(regex[':host()'], name + '$1')
|
||||
.replace(regex[':host'], name)
|
||||
.replace(regex['::content'], name);
|
||||
}
|
||||
|
||||
return '';
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
template: template,
|
||||
lightCss: lightCss,
|
||||
globalCss: globalCss
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Some CSS rules, such as @keyframes
|
||||
* and @font-face don't work inside
|
||||
* scoped or shadow <style>. So we
|
||||
* have to put them into 'global'
|
||||
* <style> in the head of the
|
||||
* document.
|
||||
*
|
||||
* @private
|
||||
* @param {String} css
|
||||
*/
|
||||
function injectGlobalCss(css) {
|
||||
if (!css) {return;}
|
||||
var style = document.createElement('style');
|
||||
style.innerHTML = css.trim();
|
||||
headReady().then(function() {
|
||||
document.head.appendChild(style);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolves a promise once document.head is ready.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function headReady() {
|
||||
return new Promise(function(resolve) {
|
||||
if (document.head) { return resolve(); }
|
||||
window.addEventListener('load', function fn() {
|
||||
window.removeEventListener('load', fn);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The Gecko platform doesn't yet have
|
||||
* `::content` or `:host`, selectors,
|
||||
* without these we are unable to style
|
||||
* user-content in the light-dom from
|
||||
* within our shadow-dom style-sheet.
|
||||
*
|
||||
* To workaround this, we clone the <style>
|
||||
* node into the root of the component,
|
||||
* so our selectors are able to target
|
||||
* light-dom content.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function injectLightCss(el) {
|
||||
if (hasShadowCSS) { return; }
|
||||
el.lightStyle = document.createElement('style');
|
||||
el.lightStyle.setAttribute('scoped', '');
|
||||
el.lightStyle.innerHTML = el.lightCss;
|
||||
el.appendChild(el.lightStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hyphen separated
|
||||
* string to camel-case.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* toCamelCase('foo-bar'); //=> 'fooBar'
|
||||
*
|
||||
* @private
|
||||
* @param {Sring} string
|
||||
* @return {String}
|
||||
*/
|
||||
function toCamelCase(string) {
|
||||
return string.replace(/-(.)/g, function replacer(string, p1) {
|
||||
return p1.toUpperCase();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Observer (singleton)
|
||||
*
|
||||
* @type {MutationObserver|undefined}
|
||||
*/
|
||||
var dirObserver;
|
||||
|
||||
/**
|
||||
* Observes the document `dir` (direction)
|
||||
* attribute and dispatches a global event
|
||||
* when it changes.
|
||||
*
|
||||
* Components can listen to this event and
|
||||
* make internal changes if need be.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function addDirObserver() {
|
||||
if (dirObserver) { return; }
|
||||
|
||||
dirObserver = new MutationObserver(onChanged);
|
||||
dirObserver.observe(document.documentElement, {
|
||||
attributeFilter: ['dir'],
|
||||
attributes: true
|
||||
});
|
||||
|
||||
function onChanged(mutations) {
|
||||
document.dispatchEvent(new Event('dirchanged'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the values of all properties from
|
||||
* source object `target` to a target object `source`.
|
||||
* It will return the target object.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} target
|
||||
* @param {Object} source
|
||||
* @returns {Object}
|
||||
*/
|
||||
function mixin(target, source) {
|
||||
for (var key in source) {
|
||||
target[key] = source[key];
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-component',this));
|
||||
31
gaia/distros/spark/apps/customizer/components/gaia-dialog/bower.json
Executable file
31
gaia/distros/spark/apps/customizer/components/gaia-dialog/bower.json
Executable file
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "gaia-dialog",
|
||||
"version": "0.2.1",
|
||||
"homepage": "https://github.com/gaia-components/gaia-dialog",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "gaia-dialog.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"examples",
|
||||
"test",
|
||||
"tests",
|
||||
"README.md"
|
||||
],
|
||||
"devDependencies": {
|
||||
"base": "gaia-components/base",
|
||||
"pressed": "gaia-components/pressed",
|
||||
"gaia-fonts": "gaia-components/gaia-fonts",
|
||||
"gaia-theme": "gaia-components/gaia-theme",
|
||||
"gaia-button": "gaia-components/gaia-button"
|
||||
},
|
||||
"dependencies": {
|
||||
"gaia-text-input": "gaia-components/gaia-text-input",
|
||||
"gaia-icons": "gaia-components/gaia-icons#^0.8.0",
|
||||
"gaia-component": "gaia-components/gaia-component#^0.3.7"
|
||||
}
|
||||
}
|
||||
111
gaia/distros/spark/apps/customizer/components/gaia-dialog/gaia-dialog-action.js
Executable file
111
gaia/distros/spark/apps/customizer/components/gaia-dialog/gaia-dialog-action.js
Executable file
|
|
@ -0,0 +1,111 @@
|
|||
/* global define */
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var GaiaDialogProto = require('gaia-dialog').prototype;
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
module.exports = component.register('gaia-dialog-action', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
dialog: this.shadowRoot.querySelector('gaia-dialog'),
|
||||
submit: this.shadowRoot.querySelector('.submit'),
|
||||
cancel: this.shadowRoot.querySelector('.cancel')
|
||||
};
|
||||
},
|
||||
|
||||
open: function(e) {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.open(e));
|
||||
},
|
||||
|
||||
close: function() {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.close());
|
||||
},
|
||||
|
||||
template: `
|
||||
<gaia-dialog>
|
||||
<section>
|
||||
<content select="h1"></content>
|
||||
</section>
|
||||
<content select="button"></content>
|
||||
<button on-click="close" class="cancel">Cancel</button>
|
||||
</gaia-dialog>
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host[opened],
|
||||
:host.animating {
|
||||
display: block;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/** Button
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content section {
|
||||
padding: 33px 16px;
|
||||
}
|
||||
|
||||
::content button {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0rem 25px;
|
||||
font: inherit;
|
||||
background: var(--color-beta);
|
||||
color: var(--color-epsilon);
|
||||
transition: all 200ms;
|
||||
transition-delay: 300ms;
|
||||
}
|
||||
|
||||
::content button:after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 1px;
|
||||
left: 6px;
|
||||
right: 6px;
|
||||
top: 49px;
|
||||
background: #E7E7E7;
|
||||
}
|
||||
|
||||
::content button:last-child:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::content button:active {
|
||||
background-color: var(--highlight-color);
|
||||
color: #fff;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
::content button:active:after {
|
||||
background: var(--highlight-color);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-dialog-action',this));
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/* global define */
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var GaiaDialogProto = require('gaia-dialog').prototype;
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
module.exports = component.register('gaia-dialog-alert', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
this.els = {
|
||||
dialog: this.shadowRoot.querySelector('gaia-dialog')
|
||||
};
|
||||
},
|
||||
|
||||
open: function(e) {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.open(e));
|
||||
},
|
||||
|
||||
close: function() {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.close());
|
||||
},
|
||||
|
||||
template: `
|
||||
<gaia-dialog>
|
||||
<section>
|
||||
<p><content></content></p>
|
||||
</section>
|
||||
<div>
|
||||
<button class="submit primary" on-click="close">Ok</button>
|
||||
</div>
|
||||
</gaia-dialog>
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: none;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-dialog-alert',this));
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/* global define */
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var GaiaDialogProto = require('gaia-dialog').prototype;
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
module.exports = component.register('gaia-dialog-confirm', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
dialog: this.shadowRoot.querySelector('gaia-dialog'),
|
||||
submit: this.shadowRoot.querySelector('.submit'),
|
||||
cancel: this.shadowRoot.querySelector('.cancel')
|
||||
};
|
||||
|
||||
this.els.cancel.addEventListener('click', this.close.bind(this));
|
||||
this.els.submit.addEventListener('click', this.close.bind(this));
|
||||
},
|
||||
|
||||
open: function(e) {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.open(e));
|
||||
},
|
||||
|
||||
close: function() {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.close());
|
||||
},
|
||||
|
||||
template: `
|
||||
<gaia-dialog>
|
||||
<section>
|
||||
<p><content></content></p>
|
||||
</section>
|
||||
<fieldset>
|
||||
<button class="cancel">Cancel</button>
|
||||
<button class="submit danger">Confirm</button>
|
||||
</fieldset>
|
||||
</gaia-dialog>
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host[opened],
|
||||
:host.animating {
|
||||
display: block;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-dialog-confirm',this));
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/* global define */
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var GaiaDialogProto = require('gaia-dialog').prototype;
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
module.exports = component.register('gaia-dialog-menu', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
this.els = {
|
||||
dialog: this.shadowRoot.querySelector('gaia-dialog')
|
||||
};
|
||||
},
|
||||
|
||||
open: function(e) {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.open(e));
|
||||
},
|
||||
|
||||
close: function() {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.close());
|
||||
},
|
||||
|
||||
template: `
|
||||
<gaia-dialog>
|
||||
<div class="items"><content select="button"></content></div>
|
||||
</gaia-dialog>
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: none;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
::content > button {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
line-height: 51px;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0rem 16px;
|
||||
font: inherit;
|
||||
font-style: italic;
|
||||
text-align: start;
|
||||
background: var(--color-beta);
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
::content > button[data-icon]:before {
|
||||
width: 50px;
|
||||
font-size: 22px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/** Button Divider Line
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content > button:after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 1px;
|
||||
left: 6px;
|
||||
right: 6px;
|
||||
top: 49px;
|
||||
background: #E7E7E7;
|
||||
}
|
||||
|
||||
::content > button:last-of-type:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-dialog-menu',this));
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/* global define */
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var GaiaDialogProto = require('gaia-dialog').prototype;
|
||||
var component = require('gaia-component');
|
||||
|
||||
require('gaia-text-input');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
module.exports = component.register('gaia-dialog-prompt', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
dialog: this.shadowRoot.querySelector('gaia-dialog'),
|
||||
input: this.shadowRoot.querySelector('gaia-text-input'),
|
||||
submit: this.shadowRoot.querySelector('.submit'),
|
||||
cancel: this.shadowRoot.querySelector('.cancel')
|
||||
};
|
||||
|
||||
this.els.dialog.addEventListener('opened', () => {
|
||||
this.setAttribute('opened', '');
|
||||
});
|
||||
|
||||
this.els.dialog.addEventListener('closed', () => {
|
||||
this.removeAttribute('opened');
|
||||
});
|
||||
|
||||
this.els.input.placeholder = this.firstChild.textContent;
|
||||
this.els.cancel.addEventListener('click', this.close.bind(this));
|
||||
this.els.submit.addEventListener('click', this.close.bind(this));
|
||||
},
|
||||
|
||||
open: function(e) {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.open(e));
|
||||
},
|
||||
|
||||
close: function() {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.close());
|
||||
},
|
||||
|
||||
template: `
|
||||
<gaia-dialog>
|
||||
<div><gaia-text-input></gaia-text-input></div>
|
||||
<fieldset>
|
||||
<button class="cancel">Cancel</button>
|
||||
<button class="submit primary">Ok</button>
|
||||
</fieldset>
|
||||
</gaia-dialog>
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host[opened],
|
||||
:host.animating {
|
||||
display: block;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
gaia-text-input {
|
||||
margin: 16px !important;
|
||||
}
|
||||
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-dialog-prompt',this));
|
||||
230
gaia/distros/spark/apps/customizer/components/gaia-dialog/gaia-dialog-select.js
Executable file
230
gaia/distros/spark/apps/customizer/components/gaia-dialog/gaia-dialog-select.js
Executable file
|
|
@ -0,0 +1,230 @@
|
|||
/* global define */
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var GaiaDialogProto = require('gaia-dialog').prototype;
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
module.exports = component.register('gaia-dialog-select', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
dialog: this.shadowRoot.querySelector('gaia-dialog'),
|
||||
submit: this.shadowRoot.querySelector('.submit'),
|
||||
cancel: this.shadowRoot.querySelector('.cancel'),
|
||||
list: this.shadowRoot.querySelector('ul')
|
||||
};
|
||||
|
||||
this.multiple = this.hasAttribute('multiple');
|
||||
this.els.list.addEventListener('click', this.onListClick.bind(this));
|
||||
this.els.submit.addEventListener('click', this.close.bind(this));
|
||||
this.els.cancel.addEventListener('click', this.close.bind(this));
|
||||
},
|
||||
|
||||
open: function(e) {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.open(e));
|
||||
},
|
||||
|
||||
close: function() {
|
||||
return GaiaDialogProto.show.call(this)
|
||||
.then(() => this.els.dialog.close());
|
||||
},
|
||||
|
||||
onListClick: function(e) {
|
||||
var el = e.target.closest('li');
|
||||
var selected = el.getAttribute('aria-selected') === 'true';
|
||||
|
||||
if (this.multiple) { this.onChangeMultiple(el, selected); }
|
||||
else { this.onChange(el, selected); }
|
||||
},
|
||||
|
||||
onChange: function(el, selected) {
|
||||
this.clearSelected();
|
||||
if (!selected) { el.setAttribute('aria-selected', !selected); }
|
||||
this.fireChange();
|
||||
this.close();
|
||||
},
|
||||
|
||||
onChangeMultiple: function(el, selected) {
|
||||
el.setAttribute('aria-selected', !selected);
|
||||
this.fireChange();
|
||||
},
|
||||
|
||||
clearSelected: function() {
|
||||
[].forEach.call(this.selectedOptions, function(option) {
|
||||
option.removeAttribute('aria-selected');
|
||||
});
|
||||
},
|
||||
|
||||
fireChange: function() {
|
||||
var e = new CustomEvent('change', { detail: { value: this.valueString }});
|
||||
this.dispatchEvent(e);
|
||||
},
|
||||
|
||||
attrs: {
|
||||
multiple: {
|
||||
get: function() { return !!this._multiple; },
|
||||
set: function(value) {
|
||||
value = value === '' ? true : value;
|
||||
if (value === this._multiple) { return; }
|
||||
if (!value) {
|
||||
this._multiple = false;
|
||||
this.removeAttribute('multiple');
|
||||
} else {
|
||||
this._multiple = true;
|
||||
this.setAttribute('multiple', '');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
options: {
|
||||
get: function() { return this.querySelectorAll('li'); }
|
||||
},
|
||||
|
||||
selectedOptions: {
|
||||
get: function() {
|
||||
return this.querySelectorAll('li[aria-selected="true"]');
|
||||
}
|
||||
},
|
||||
|
||||
selected: {
|
||||
get: function() { return this.selectedOptions[0]; }
|
||||
},
|
||||
|
||||
value: {
|
||||
get: function() {
|
||||
var selected = this.selectedOptions[0];
|
||||
return selected && selected.getAttribute('value');
|
||||
}
|
||||
},
|
||||
|
||||
valueString: {
|
||||
get: function() {
|
||||
var selected = this.selected;
|
||||
return selected && selected.textContent;
|
||||
}
|
||||
},
|
||||
|
||||
length: {
|
||||
get: function() { return this.options.length; }
|
||||
}
|
||||
},
|
||||
|
||||
template: `
|
||||
<gaia-dialog>
|
||||
<content select="h1"></content>
|
||||
<ul><content select="li"></content></ul>
|
||||
<fieldset>
|
||||
<button class="cancel">Cancel</button>
|
||||
<button class="submit primary">Select</button>
|
||||
</fieldset>
|
||||
</gaia-dialog>
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: none;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/** Title (duplicate from gaia-dialog)
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content h1 {
|
||||
padding: 16px;
|
||||
font-size: 23px;
|
||||
line-height: 26px;
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
color: #858585;
|
||||
}
|
||||
|
||||
/** List
|
||||
---------------------------------------------------------*/
|
||||
|
||||
ul {
|
||||
display: block;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/** Options
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content li {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 16px;
|
||||
text-align: start;
|
||||
-moz-user-select: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::content li[aria-selected='true'] {
|
||||
color: #00CAF2;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
::content li:after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 1px;
|
||||
left: 16px;
|
||||
right: 16px;
|
||||
bottom: 1px;
|
||||
background: #E7E7E7;
|
||||
}
|
||||
|
||||
::content li:last-of-type:after {
|
||||
display: none
|
||||
}
|
||||
|
||||
/** Buttons
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::host:not([multiple]) .submit {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
::host:not([multiple]) .cancel {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
::host:not([multiple]) .cancel:after {
|
||||
display: none% !important;
|
||||
}
|
||||
|
||||
/** Tick Icon
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content li[aria-selected='true']:before {
|
||||
content: 'tick';
|
||||
position: absolute;
|
||||
top: 50%; right: 20px;
|
||||
display: block;
|
||||
margin-top: -12px;
|
||||
font-family: 'gaia-icons';
|
||||
font-style: normal;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-dialog-select',this));
|
||||
466
gaia/distros/spark/apps/customizer/components/gaia-dialog/gaia-dialog.js
Executable file
466
gaia/distros/spark/apps/customizer/components/gaia-dialog/gaia-dialog.js
Executable file
|
|
@ -0,0 +1,466 @@
|
|||
;(function(define){'use strict';define((require,exports,module) => {
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Simple logger (toggle 0)
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
var debug = 0 ? console.log.bind(console) : () => {};
|
||||
|
||||
/**
|
||||
* Use the dom-scheduler if it's around,
|
||||
* else fallback to fake shim.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var schedule = (window.scheduler && typeof window.scheduler.mutation === "function" ? window.scheduler : null) || {
|
||||
mutation: block => Promise.resolve(block()),
|
||||
transition(block, el, event, timeout) {
|
||||
block();
|
||||
return after(el, event, timeout || 500);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
module.exports = component.register('gaia-dialog', {
|
||||
created() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
inner: this.shadowRoot.querySelector('.dialog-inner'),
|
||||
background: this.shadowRoot.querySelector('.background'),
|
||||
window: this.shadowRoot.querySelector('.window')
|
||||
};
|
||||
|
||||
this.shadowRoot.addEventListener('click', e => this.onClick(e));
|
||||
},
|
||||
|
||||
onClick(e) {
|
||||
var el = e.target.closest('[on-click]');
|
||||
if (!el) { return; }
|
||||
debug('onClick');
|
||||
var method = el.getAttribute('on-click');
|
||||
if (typeof this[method] == 'function') { this[method](); }
|
||||
},
|
||||
|
||||
open(options) {
|
||||
if (this.isOpen) { return; }
|
||||
debug('open dialog');
|
||||
this.isOpen = true;
|
||||
|
||||
this.show()
|
||||
.then(() => this.animateBackgroundIn(options))
|
||||
.then(() => this.animateWindowIn());
|
||||
},
|
||||
|
||||
close(options) {
|
||||
if (!this.isOpen) { return; }
|
||||
debug('close dialog');
|
||||
this.isOpen = false;
|
||||
|
||||
this.animateWindowOut()
|
||||
.then(() => this.animateBackgroundOut())
|
||||
.then(() => this.hide());
|
||||
},
|
||||
|
||||
animateBackgroundIn(options) {
|
||||
if (options) { return this.animateBackgroundInFrom(options); }
|
||||
|
||||
var el = this.els.background;
|
||||
return schedule.transition(() => {
|
||||
debug('animate background in');
|
||||
el.classList.remove('animate-out');
|
||||
el.classList.add('animate-in');
|
||||
}, el, 'animationend');
|
||||
},
|
||||
|
||||
animateBackgroundOut() {
|
||||
var el = this.els.background;
|
||||
return schedule.transition(() => {
|
||||
debug('animate background out');
|
||||
el.classList.add('animate-out');
|
||||
el.classList.remove('animate-in');
|
||||
}, el, 'animationend')
|
||||
.then(() => el.style = '');
|
||||
},
|
||||
|
||||
animateBackgroundInFrom(pos) {
|
||||
var el = this.els.background;
|
||||
var scale = Math.sqrt(window.innerWidth * window.innerHeight) / 15;
|
||||
var duration = scale * 9;
|
||||
|
||||
return schedule.mutation(() => {
|
||||
el.classList.add('circular');
|
||||
el.classList.remove('animate-out');
|
||||
el.style.transform = `translate(${pos.clientX}px, ${pos.clientY}px)`;
|
||||
el.style.transitionDuration = duration + 'ms';
|
||||
el.offsetTop; // Hack, any ideas?
|
||||
})
|
||||
|
||||
.then(() => {
|
||||
return schedule.transition(() => {
|
||||
debug('animate background in from', pos);
|
||||
el.style.transform += ` scale(${scale})`;
|
||||
el.style.opacity = 1;
|
||||
}, el, 'transitionend', duration * 1.5);
|
||||
});
|
||||
},
|
||||
|
||||
show() {
|
||||
return schedule.mutation(() => {
|
||||
debug('show');
|
||||
this.style.display = 'block';
|
||||
});
|
||||
},
|
||||
|
||||
hide() {
|
||||
return schedule.mutation(() => {
|
||||
debug('hide');
|
||||
this.style.display = 'none';
|
||||
});
|
||||
},
|
||||
|
||||
animateWindowIn() {
|
||||
var el = this.els.window;
|
||||
return schedule.transition(() => {
|
||||
debug('animate window in');
|
||||
el.classList.add('animate-in');
|
||||
}, el, 'animationend');
|
||||
},
|
||||
|
||||
animateWindowOut() {
|
||||
var el = this.els.window;
|
||||
|
||||
return schedule.transition(() => {
|
||||
debug('animate window out');
|
||||
el.classList.remove('animate-out', 'animate-in');
|
||||
}, el, 'animationend');
|
||||
},
|
||||
|
||||
attrs: {
|
||||
opened: {
|
||||
get: function() { return !!this.isOpen; },
|
||||
set: function(value) {
|
||||
value = value === '' || value;
|
||||
if (!value) { this.close(); }
|
||||
else { this.open(); }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
template: `
|
||||
<div class="dialog-inner">
|
||||
<div class="background" on-click="close"></div>
|
||||
<div class="window"><content></content></div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
::content * {
|
||||
box-sizing: border-box;
|
||||
font-weight: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
::content p,
|
||||
::content h1,
|
||||
::content h2,
|
||||
::content h3,
|
||||
::content h4,
|
||||
::content button,
|
||||
::content fieldset {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
:host {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0px; left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 200;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/** Inner
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.dialog-inner {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/** Background
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.background {
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
background: rgba(199,199,199,0.85);
|
||||
}
|
||||
|
||||
/**
|
||||
* .circular
|
||||
*/
|
||||
|
||||
.background.circular {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: -20px;
|
||||
border-radius: 50%;
|
||||
will-change: transform, opacity;
|
||||
transition-property: opacity, transform;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
|
||||
/**
|
||||
* .animate-in
|
||||
*/
|
||||
|
||||
.background.animate-in {
|
||||
animation-name: gaia-dialog-fade-in;
|
||||
animation-duration: 260ms;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
/**
|
||||
* .animate-out
|
||||
*/
|
||||
|
||||
.background.animate-out {
|
||||
animation-name: gaia-dialog-fade-out;
|
||||
animation-duration: 260ms;
|
||||
animation-fill-mode: forwards;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/** Window
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.window {
|
||||
position: relative;
|
||||
width: 90%;
|
||||
max-width: 350px;
|
||||
margin: auto;
|
||||
box-shadow: 0 1px 0 0px rgba(0,0,0,0.15);
|
||||
background: var(--color-iota);
|
||||
transition: opacity 300ms;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.window.animate-in {
|
||||
animation-name: gaia-dialog-entrance;
|
||||
animation-duration: 300ms;
|
||||
animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.275);
|
||||
animation-fill-mode: forwards;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.window.animate-out {
|
||||
animation-name: gaia-dialog-fade-out;
|
||||
animation-duration: 150ms;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/** Title
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content h1 {
|
||||
padding: 16px;
|
||||
font-size: 23px;
|
||||
line-height: 26px;
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
color: #858585;
|
||||
}
|
||||
|
||||
::content strong {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
::content small {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
/** Section
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content section {
|
||||
padding: 33px 18px;
|
||||
color: #858585;
|
||||
}
|
||||
|
||||
::content section > *:not(:last-child) {
|
||||
margin-bottom: 13px;
|
||||
}
|
||||
|
||||
/** Paragraphs
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content p {
|
||||
text-align: -moz-start;
|
||||
}
|
||||
|
||||
/** Buttons
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content button {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0rem 16px;
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
background: var(--color-beta);
|
||||
color: var(--color-epsilon);
|
||||
transition: all 200ms;
|
||||
transition-delay: 300ms;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* .primary
|
||||
*/
|
||||
|
||||
::content button.primary {
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
/**
|
||||
* .danger
|
||||
*/
|
||||
|
||||
::content button.danger {
|
||||
color: var(--color-destructive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disabled buttons
|
||||
*/
|
||||
|
||||
::content button[disabled] {
|
||||
color: var(--color-zeta);
|
||||
}
|
||||
|
||||
/** Button Divider Line
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content button:after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 1px;
|
||||
left: 6px;
|
||||
right: 6px;
|
||||
top: 49px;
|
||||
background: #E7E7E7;
|
||||
}
|
||||
|
||||
::content button:last-of-type:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::content button:active {
|
||||
background-color: var(--highlight-color);
|
||||
color: #fff;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
::content button:active:after {
|
||||
background: var(--highlight-color);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
::content button[data-icon]:before {
|
||||
float: left;
|
||||
}
|
||||
|
||||
/** Fieldset (button group)
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content fieldset {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
::content fieldset button {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
::content fieldset button:after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
bottom: 6px;
|
||||
right: 0px;
|
||||
left: auto;
|
||||
width: 1px;
|
||||
height: calc(100% - 12px);
|
||||
background: #e7e7e7;
|
||||
transition: all 200ms;
|
||||
transition-delay: 200ms;
|
||||
}
|
||||
|
||||
</style>`,
|
||||
|
||||
globalCss: `
|
||||
@keyframes gaia-dialog-entrance {
|
||||
0% { transform: translateY(100px); }
|
||||
100% { transform: translateY(0px); }
|
||||
}
|
||||
|
||||
@keyframes gaia-dialog-fade-in {
|
||||
0% { opacity: 0 }
|
||||
100% { opacity: 1 }
|
||||
}
|
||||
|
||||
@keyframes gaia-dialog-fade-out {
|
||||
0% { opacity: 1 }
|
||||
100% { opacity: 0 }
|
||||
}`
|
||||
});
|
||||
|
||||
/**
|
||||
* Utils
|
||||
*/
|
||||
|
||||
function after(target, event, timeout) {
|
||||
return new Promise(resolve => {
|
||||
var timer = timeout && setTimeout(cb, timeout);
|
||||
target.addEventListener(event, cb);
|
||||
function cb() {
|
||||
target.removeEventListener(event, cb);
|
||||
clearTimeout(timer);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-dialog',this));
|
||||
124
gaia/distros/spark/apps/customizer/components/gaia-dialog/index.html
Executable file
124
gaia/distros/spark/apps/customizer/components/gaia-dialog/index.html
Executable file
|
|
@ -0,0 +1,124 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title><gaia-dialog></title>
|
||||
<meta name="description" content="gaia-dialog demo" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/base/base.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-theme/gaia-theme.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-fonts/style.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-icons/gaia-icons.css">
|
||||
<script src="bower_components/gaia-theme/lib/gaia-theme-selector.js"></script>
|
||||
<script src="bower_components/pressed/pressed.js"></script>
|
||||
<script src="bower_components/gaia-component/gaia-component.js"></script>
|
||||
<script src="bower_components/gaia-button/gaia-button.js"></script>
|
||||
<script src="bower_components/gaia-text-input/gaia-text-input.js"></script>
|
||||
<!-- <script src="bower_components/dom-scheduler/lib/dom-scheduler.js"></script> -->
|
||||
<script src="gaia-dialog.js"></script>
|
||||
<script src="gaia-dialog-alert.js"></script>
|
||||
<script src="gaia-dialog-confirm.js"></script>
|
||||
<script src="gaia-dialog-prompt.js"></script>
|
||||
<script src="gaia-dialog-action.js"></script>
|
||||
<script src="gaia-dialog-select.js"></script>
|
||||
<script src="gaia-dialog-menu.js"></script>
|
||||
<style>
|
||||
body {
|
||||
padding: 48px var(--base-m) 0 var(--base-m);
|
||||
background-color: var(--background);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="l-align-center">
|
||||
<gaia-theme-selector></gaia-theme-selector>
|
||||
|
||||
<div id="buttons">
|
||||
<div class="l-mb-small"><gaia-button data-for="gaia-dialog-alert">Alert</gaia-button></div>
|
||||
<div class="l-mb-small"><gaia-button data-for="gaia-dialog-confirm">Confirm</gaia-button></div>
|
||||
<div class="l-mb-small"><gaia-button data-for="gaia-dialog-prompt">Prompt</gaia-button></div>
|
||||
<div class="l-mb-small"><gaia-button data-for="gaia-dialog-action">Action</gaia-button></div>
|
||||
<div class="l-mb-small"><gaia-button data-for="gaia-dialog-select">Select</gaia-button></div>
|
||||
<div class="l-mb-small"><gaia-button data-for="gaia-dialog-select[multiple]">Select Multiple</gaia-button></div>
|
||||
<div class="l-mb-small"><gaia-button data-for="gaia-dialog-menu">Menu</gaia-button></div>
|
||||
<div class="l-mb-small"><gaia-button data-for="#custom-dialog-1">Custom</gaia-button></div>
|
||||
</div>
|
||||
|
||||
<div id="dialogs">
|
||||
<gaia-dialog-alert>No SIM card is present</gaia-dialog-alert>
|
||||
<gaia-dialog-confirm>Are you sure you want to delete this contact?</gaia-dialog-confirm>
|
||||
<gaia-dialog-prompt>Device name</gaia-dialog-prompt>
|
||||
|
||||
<gaia-dialog-action>
|
||||
<h1>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur eu mollis tortor.</h1>
|
||||
<button on-click="close">Action 1</button>
|
||||
<button on-click="close">Action 2</button>
|
||||
</gaia-dialog-action>
|
||||
|
||||
<gaia-dialog-select>
|
||||
<h1>Ring tone</h1>
|
||||
<li>Classic prism</li>
|
||||
<li>Wallphone</li>
|
||||
<li>Disco drive</li>
|
||||
<li>Touchmatic</li>
|
||||
<li>Classic courier</li>
|
||||
<li>Hacker</li>
|
||||
</gaia-dialog-select>
|
||||
|
||||
<gaia-dialog-select multiple>
|
||||
<h1>Ring tone</h1>
|
||||
<li>Classic prism</li>
|
||||
<li>Wallphone</li>
|
||||
<li>Disco drive</li>
|
||||
<li>Touchmatic</li>
|
||||
<li>Classic courier</li>
|
||||
<li>Hacker</li>
|
||||
</gaia-dialog-select>
|
||||
|
||||
<gaia-dialog-menu>
|
||||
<button on-click="close" data-icon="firefox">Open in new window</button>
|
||||
<button on-click="close" data-icon="firefox">Add to Home Screen</button>
|
||||
<button on-click="close" data-icon="firefox">Share link</button>
|
||||
<button on-click="close" data-icon="firefox">Settings</button>
|
||||
</gaia-dialog-menu>
|
||||
|
||||
<gaia-dialog id="custom-dialog-1">
|
||||
<section>
|
||||
<h1>Application Download</h1>
|
||||
<p>Do you want to download and install this application?</p>
|
||||
</section>
|
||||
<fieldset>
|
||||
<button on-click="close">Cancel</button>
|
||||
<button on-click="close">Action</button>
|
||||
</fieldset>
|
||||
</gaia-dialog>
|
||||
|
||||
<gaia-dialog>
|
||||
<h1>Main Heading</h1>
|
||||
<h2>Sub Heading</h2>
|
||||
<hr></hr>
|
||||
<p>Lorem ipsum dolor sit amet, consecutor adipisicing elit, sed do eiusod tempor incidenti ut la et dolore magna...</p>
|
||||
<button on-click="close">Action</button>
|
||||
<button on-click="close">Cancel</button>
|
||||
</gaia-dialog>
|
||||
|
||||
<gaia-dialog>
|
||||
<h1>Confirmation</h1>
|
||||
<p>Lorem ipsum dolor sit amet, consecutor adipisicing elit, sed do eiusod tempor incidenti ut la et dolore magna...</p>
|
||||
<hr>
|
||||
<p>Lorem ipsum dolor sit amet, consecutor adipisicing elit, sed do eiusod tempor incidenti ut la et dolore magna...</p>
|
||||
<button on-click="close">Action</button>
|
||||
<button on-click="close">Action</button>
|
||||
<button on-click="close">Cancel</button>
|
||||
</gaia-dialog>
|
||||
</div>
|
||||
<script>
|
||||
var buttons = document.querySelectorAll('gaia-button');
|
||||
[].forEach.call(buttons, function(button) {
|
||||
button.addEventListener('click', function(e) {
|
||||
var dialog = document.querySelector(button.dataset.for);
|
||||
dialog.open(e);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
27
gaia/distros/spark/apps/customizer/components/gaia-dialog/package.json
Executable file
27
gaia/distros/spark/apps/customizer/components/gaia-dialog/package.json
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "gaia-dialog",
|
||||
"version": "0.2.1",
|
||||
"homepage": "https://github.com/gaia-components/gaia-dialog",
|
||||
"license": "MIT",
|
||||
"main": "gaia-dialog.js",
|
||||
"devDependencies": {
|
||||
"babel": "^5.2.12",
|
||||
"bower": "^1.4.1",
|
||||
"browserify": "^10.1.0",
|
||||
"jshint": "^2.7.0"
|
||||
},
|
||||
"scripts": {
|
||||
"install": "bower install",
|
||||
"lint": "jshint gaia-dialog*.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/gaia-components/gaia-dialog.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/gaia-components/gaia-dialog/issues"
|
||||
},
|
||||
"browser": {
|
||||
"gaia-component": "./bower_components/gaia-component/gaia-component.js"
|
||||
}
|
||||
}
|
||||
22
gaia/distros/spark/apps/customizer/components/gaia-dom-tree/LICENSE
Executable file
22
gaia/distros/spark/apps/customizer/components/gaia-dom-tree/LICENSE
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015
|
||||
|
||||
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.
|
||||
|
||||
28
gaia/distros/spark/apps/customizer/components/gaia-dom-tree/bower.json
Executable file
28
gaia/distros/spark/apps/customizer/components/gaia-dom-tree/bower.json
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "gaia-dom-tree",
|
||||
"version": "0.2.3",
|
||||
"homepage": "https://github.com/gaia-components/gaia-dom-tree",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "gaia-dom-tree.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"!.jshintrc",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"index.html",
|
||||
"package.json",
|
||||
"README.md"
|
||||
],
|
||||
"dependencies": {
|
||||
"gaia-component": "gaia-components/gaia-component#~0.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"gaia-theme": "gaia-components/gaia-theme",
|
||||
"gaia-fonts": "gaia-components/gaia-fonts",
|
||||
"base": "gaia-components/base"
|
||||
}
|
||||
}
|
||||
315
gaia/distros/spark/apps/customizer/components/gaia-dom-tree/gaia-dom-tree.js
Executable file
315
gaia/distros/spark/apps/customizer/components/gaia-dom-tree/gaia-dom-tree.js
Executable file
|
|
@ -0,0 +1,315 @@
|
|||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Simple logger (toggle 0)
|
||||
*
|
||||
* @type {Function}
|
||||
*/
|
||||
var debug = 0 ? console.log.bind(console) : function() {};
|
||||
|
||||
const NODE_TYPES = {
|
||||
1: 'element',
|
||||
3: 'text'
|
||||
};
|
||||
|
||||
/**
|
||||
* Register the element.
|
||||
*
|
||||
* @return {Element} constructor
|
||||
*/
|
||||
module.exports = component.register('gaia-dom-tree', {
|
||||
|
||||
/**
|
||||
* Called when the element is first created.
|
||||
*
|
||||
* Here we create the shadow-root and
|
||||
* inject our template into it.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
created: function() {
|
||||
debug('created');
|
||||
this.setupShadowRoot();
|
||||
this.els = {
|
||||
inner: this.shadowRoot.querySelector('.inner'),
|
||||
tree: this.shadowRoot.querySelector('.tree')
|
||||
};
|
||||
|
||||
this.filter = this.getAttribute('filter');
|
||||
|
||||
this.selectedTreeNode = null;
|
||||
this.selectedNode = null;
|
||||
this.treeMap = new Map();
|
||||
this.els.inner.addEventListener('click', e => this.onInnerClick(e));
|
||||
this.els.inner.addEventListener('contextmenu', e => this.onInnerClick(e));
|
||||
},
|
||||
|
||||
attrs: {
|
||||
filter: {
|
||||
get: function() { return this._filter; },
|
||||
set: function(value) {
|
||||
if (value === this._filter) { return; }
|
||||
this._filter = value;
|
||||
this.setAttr('filter', value);
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setRoot: function(el) {
|
||||
debug('set root', el);
|
||||
this.root = el;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
this.els.tree.innerHTML = '';
|
||||
if (this.root) {
|
||||
var tree = this.createTree(this.root);
|
||||
this.els.tree.appendChild(tree);
|
||||
debug('rendered');
|
||||
}
|
||||
},
|
||||
|
||||
select: function(el) {
|
||||
debug('select', el);
|
||||
var treeNode = this.treeMap.get(el);
|
||||
if (!treeNode) return;
|
||||
this.selectNode(treeNode);
|
||||
this.expandNode(treeNode);
|
||||
},
|
||||
|
||||
onInnerClick: function(e) {
|
||||
debug('inner click', e);
|
||||
if (e.type === 'contextmenu') e.preventDefault();
|
||||
var nodeTitle = e.target.closest('h3');
|
||||
if (nodeTitle) this.onNodeTitleClick(nodeTitle, e);
|
||||
},
|
||||
|
||||
onNodeTitleClick: function(el, e) {
|
||||
var node = el.closest('li');
|
||||
if (e.type === 'click') this.toggleExpanded(node);
|
||||
this.selectNode(node, e);
|
||||
},
|
||||
|
||||
expandNode: function(node) {
|
||||
debug('expand node', node);
|
||||
node.classList.add('expanded');
|
||||
var parent = node.parentNode.closest('li');
|
||||
if (parent) this.expandNode(parent);
|
||||
},
|
||||
|
||||
contractNode: function(node) {
|
||||
node.classList.remove('expanded');
|
||||
},
|
||||
|
||||
toggleExpanded: function(node) {
|
||||
var expanded = node.classList.contains('expanded');
|
||||
if (expanded) this.contractNode(node);
|
||||
else this.expandNode(node);
|
||||
},
|
||||
|
||||
selectNode: function(treeNode, e) {
|
||||
var previous = this.selectedTreeNode;
|
||||
if (previous) previous.classList.remove('selected');
|
||||
treeNode.classList.add('selected');
|
||||
this.selectedTreeNode = treeNode;
|
||||
this.selectedNode = treeNode.sourceNode;
|
||||
this.dispatch((e && e.type === 'contextmenu') ? 'longpressed' : 'click');
|
||||
},
|
||||
|
||||
dispatch: function(name) {
|
||||
this.dispatchEvent(new Event(name));
|
||||
},
|
||||
|
||||
createTree: function(node) {
|
||||
var treeNode = document.createElement('li');
|
||||
var title = document.createElement('h3');
|
||||
var children = document.createElement('ul');
|
||||
var type = NODE_TYPES[node.nodeType];
|
||||
var stringified = stringify[type](node);
|
||||
|
||||
// Exclude <gaia-dom-tree> from being seen as
|
||||
// part of the DOM tree.
|
||||
var childNodes = [].filter.call(node.childNodes, (node) => {
|
||||
return node.nodeType === Node.TEXT_NODE || (
|
||||
node.nodeType === Node.ELEMENT_NODE &&
|
||||
node.nodeName !== 'GAIA-DOM-TREE' && (
|
||||
(this.filter && !node.matches(this.filter)) ||
|
||||
!this.filter
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
if (!stringified) return;
|
||||
|
||||
title.innerHTML = stringified;
|
||||
|
||||
treeNode.appendChild(title);
|
||||
treeNode.appendChild(children);
|
||||
treeNode.sourceNode = node;
|
||||
treeNode.classList.add(type);
|
||||
|
||||
// Flag when a node has children
|
||||
treeNode.classList.toggle('has-children', !!childNodes.length);
|
||||
|
||||
childNodes.map((node) => this.createTree(node))
|
||||
.filter(node => !!node)
|
||||
.forEach(children.appendChild, children);
|
||||
|
||||
this.treeMap.set(node, treeNode);
|
||||
return treeNode;
|
||||
},
|
||||
|
||||
template: `
|
||||
<style>
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.inner {
|
||||
color: var(--text-color);
|
||||
background: var(--background);
|
||||
font-family: Consolas,Monaco,"Andale Mono",monospace;
|
||||
line-height: 1;
|
||||
-moz-user-select: none;
|
||||
cursor: default;
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
ul.tree {
|
||||
padding: 0.5rem;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
ul.tree > li:first-child {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/** Node Title
|
||||
---------------------------------------------------------*/
|
||||
|
||||
h3 {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0.2em 0.2em;
|
||||
font: inherit;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/**
|
||||
* .selected
|
||||
*/
|
||||
|
||||
li.selected > h3 {
|
||||
background: var(--background-plus)
|
||||
}
|
||||
|
||||
li.text > h3 {
|
||||
font-style: italic;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
/** Node Icon
|
||||
---------------------------------------------------------*/
|
||||
|
||||
li > h3:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
width: 1.4em;
|
||||
font-size: 0.8em;
|
||||
opacity: 0.2
|
||||
}
|
||||
|
||||
li.element.has-children > h3:before {
|
||||
content: '▶';
|
||||
}
|
||||
|
||||
/**
|
||||
* .expanded
|
||||
*/
|
||||
|
||||
li.expanded > h3:before {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
/** Node Attributes
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.attr-value {
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
/** Children
|
||||
---------------------------------------------------------*/
|
||||
|
||||
li > ul {
|
||||
display: none;
|
||||
-moz-padding-start: 0.8em;
|
||||
}
|
||||
|
||||
/**
|
||||
* .expanded
|
||||
*/
|
||||
|
||||
li.expanded > ul {
|
||||
display: block;
|
||||
}
|
||||
|
||||
</style>
|
||||
<div class="inner">
|
||||
<ul class="tree"></div>
|
||||
</div>
|
||||
`
|
||||
});
|
||||
|
||||
var stringify = {
|
||||
element: function(el) {
|
||||
var tagName = el.tagName.toLowerCase();
|
||||
var attrs = stringifyAttrs(el.attributes);
|
||||
return `<${tagName}<span class="attrs">${attrs}</span>>`;
|
||||
},
|
||||
|
||||
text: function(textNode) {
|
||||
var value = textNode.nodeValue.trim();
|
||||
debug('stringify textNode', value);
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
function stringifyAttrs(attrs) {
|
||||
return [].map.call(attrs, attr => {
|
||||
return ` ${attr.name}="<span class="attr-value">${attr.value}</span>"`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function escape(html) {
|
||||
return html
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-dom-tree',this));
|
||||
30
gaia/distros/spark/apps/customizer/components/gaia-header/bower.json
Executable file
30
gaia/distros/spark/apps/customizer/components/gaia-header/bower.json
Executable file
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "gaia-header",
|
||||
"version": "0.8.4",
|
||||
"homepage": "https://github.com/gaia-components/gaia-header",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "gaia-header.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"!.jshintrc",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"index.html",
|
||||
"package.json",
|
||||
"README.md"
|
||||
],
|
||||
"dependencies": {
|
||||
"gaia-icons": "gaia-components/gaia-icons#~0.8.0",
|
||||
"gaia-component": "gaia-components/gaia-component#~0.3.0",
|
||||
"font-fit": "gaia-components/font-fit#~0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"gaia-theme": "gaia-components/gaia-theme",
|
||||
"gaia-fonts": "gaia-components/gaia-fonts",
|
||||
"base": "gaia-components/base"
|
||||
}
|
||||
}
|
||||
1422
gaia/distros/spark/apps/customizer/components/gaia-header/dist/gaia-header-es5.js
vendored
Executable file
1422
gaia/distros/spark/apps/customizer/components/gaia-header/dist/gaia-header-es5.js
vendored
Executable file
File diff suppressed because one or more lines are too long
1580
gaia/distros/spark/apps/customizer/components/gaia-header/dist/gaia-header.js
vendored
Executable file
1580
gaia/distros/spark/apps/customizer/components/gaia-header/dist/gaia-header.js
vendored
Executable file
File diff suppressed because it is too large
Load diff
1015
gaia/distros/spark/apps/customizer/components/gaia-header/gaia-header.js
Executable file
1015
gaia/distros/spark/apps/customizer/components/gaia-header/gaia-header.js
Executable file
File diff suppressed because it is too large
Load diff
118
gaia/distros/spark/apps/customizer/components/gaia-icons/bin/report.js
Executable file
118
gaia/distros/spark/apps/customizer/components/gaia-icons/bin/report.js
Executable file
|
|
@ -0,0 +1,118 @@
|
|||
'use strict';
|
||||
|
||||
// Create a report about unused icons in a project.
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var exec = require('child_process').exec;
|
||||
|
||||
var optimist = require('optimist');
|
||||
|
||||
var cli = optimist
|
||||
.usage('Create a report about unused icons in a project.' + '\n' +
|
||||
'Usage: $0 path/to/your/project/');
|
||||
var projectDir = cli.argv._[0];
|
||||
|
||||
// No folder passed? Show help message then.
|
||||
if (!projectDir) {
|
||||
cli.showHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Check if the directory exist.
|
||||
var stats = fs.lstatSync(projectDir);
|
||||
if (!stats.isDirectory()) {
|
||||
console.log('\x1b[31mPlease provide a valid folder.\x1b[0m\n');
|
||||
cli.showHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of all the icons in the font.
|
||||
* @returns {Array}
|
||||
*/
|
||||
function getIcons() {
|
||||
var icons = fs.readdirSync('./images/');
|
||||
|
||||
icons = icons.map(function(icon) {
|
||||
return path.basename(icon, '.svg');
|
||||
});
|
||||
|
||||
return icons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a grep pattern to extract used icons from files.
|
||||
* @param {string} grep
|
||||
* @param {Function} callback
|
||||
*/
|
||||
function getUsedIcons(grep, callback) {
|
||||
exec(grep, function(err, stdout, stderr) {
|
||||
var usedIcons = stdout
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map(function(icon) {
|
||||
// Take only the icon name.
|
||||
return icon.split(/["']/)[1];
|
||||
})
|
||||
.filter(function(icon) {
|
||||
// Remove non string items.
|
||||
return icon && icon.match(/^[a-z0-9-]+$/);
|
||||
});
|
||||
|
||||
callback(usedIcons);
|
||||
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of unused icons in a folder. The patterns of extraction are:
|
||||
* * data-icon="[^"]+"
|
||||
* * .dataset.icon ?= ?.+
|
||||
*/
|
||||
function getUnusedIcons() {
|
||||
var usedIcons = [];
|
||||
var length = 2;
|
||||
|
||||
var cb = function(icons) {
|
||||
usedIcons = usedIcons.concat(icons);
|
||||
length--;
|
||||
|
||||
if (length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var allIcons = getIcons();
|
||||
var unusedIcons = [];
|
||||
|
||||
allIcons.forEach(function(icon) {
|
||||
if (usedIcons.indexOf(icon) === -1) {
|
||||
unusedIcons.push(icon);
|
||||
}
|
||||
});
|
||||
|
||||
outputUnusedIcons(allIcons, unusedIcons);
|
||||
};
|
||||
|
||||
getUsedIcons('grep -rhoP \'data-icon="[^"]+"\' ' + projectDir, cb);
|
||||
getUsedIcons('grep -rhoP \'.dataset.icon ?= ?.+\' ' + projectDir, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the list of unused icons to the screen.
|
||||
* @param {Array.<string>} icons
|
||||
* @param {Array.<string>} unusedIcons
|
||||
*/
|
||||
function outputUnusedIcons(icons, unusedIcons) {
|
||||
console.log('\x1b[36mList of unused icons in %s (%d/%d):\x1b[0m',
|
||||
projectDir, unusedIcons.length, icons.length);
|
||||
|
||||
unusedIcons.forEach(function(icon) {
|
||||
console.log('* ' + icon);
|
||||
});
|
||||
}
|
||||
|
||||
getUnusedIcons();
|
||||
30
gaia/distros/spark/apps/customizer/components/gaia-icons/bower.json
Executable file
30
gaia/distros/spark/apps/customizer/components/gaia-icons/bower.json
Executable file
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "gaia-icons",
|
||||
"version": "0.8.0",
|
||||
"homepage": "https://github.com/wilsonpage/gaia-icons",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": [
|
||||
"gaia-icons.js",
|
||||
"gaia-icons.css",
|
||||
"fonts/gaia-icons.ttf",
|
||||
"gaia-icons-embedded.css"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"!.jshintrc",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"templates",
|
||||
"images",
|
||||
"test",
|
||||
"tests",
|
||||
"index.html",
|
||||
"create-svg-icon-set-file.py",
|
||||
"Gruntfile.js",
|
||||
"README.md",
|
||||
"package.json"
|
||||
]
|
||||
}
|
||||
BIN
gaia/distros/spark/apps/customizer/components/gaia-icons/fonts/gaia-icons.ttf
Executable file
BIN
gaia/distros/spark/apps/customizer/components/gaia-icons/fonts/gaia-icons.ttf
Executable file
Binary file not shown.
File diff suppressed because one or more lines are too long
25
gaia/distros/spark/apps/customizer/components/gaia-icons/gaia-icons.css
Executable file
25
gaia/distros/spark/apps/customizer/components/gaia-icons/gaia-icons.css
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: "gaia-icons";
|
||||
src: url("fonts/gaia-icons.ttf") format("truetype");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
|
||||
[data-icon]:before,
|
||||
.ligature-icons {
|
||||
font-family: "gaia-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;
|
||||
}
|
||||
38
gaia/distros/spark/apps/customizer/components/gaia-icons/gaia-icons.js
Executable file
38
gaia/distros/spark/apps/customizer/components/gaia-icons/gaia-icons.js
Executable file
|
|
@ -0,0 +1,38 @@
|
|||
(function(define){define(function(require,exports,module){
|
||||
/*jshint laxbreak:true*/
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
var base = window.GAIA_ICONS_BASE_URL
|
||||
|| window.COMPONENTS_BASE_URL
|
||||
|| 'bower_components/';
|
||||
|
||||
if (!document.documentElement) {
|
||||
window.addEventListener('load', load);
|
||||
} else {
|
||||
load();
|
||||
}
|
||||
|
||||
function load() {
|
||||
if (isLoaded()) { return; }
|
||||
|
||||
var link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.type = 'text/css';
|
||||
link.href = base + 'gaia-icons/gaia-icons.css';
|
||||
document.head.appendChild(link);
|
||||
exports.loaded = true;
|
||||
}
|
||||
|
||||
function isLoaded() {
|
||||
return exports.loaded ||
|
||||
document.querySelector('link[href*=gaia-icons]') ||
|
||||
document.documentElement.classList.contains('gaia-icons-loaded');
|
||||
}
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-icons',this));
|
||||
30
gaia/distros/spark/apps/customizer/components/gaia-list/bower.json
Executable file
30
gaia/distros/spark/apps/customizer/components/gaia-list/bower.json
Executable file
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "gaia-list",
|
||||
"version": "0.2.1",
|
||||
"homepage": "https://github.com/gaia-components/gaia-list",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "gaia-list.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests",
|
||||
"index.html",
|
||||
"package.json",
|
||||
"README.md"
|
||||
],
|
||||
"devDependencies": {
|
||||
"base": "gaia-components/base",
|
||||
"gaia-fonts": "gaia-components/gaia-fonts",
|
||||
"gaia-icons": "gaia-components/gaia-icons",
|
||||
"gaia-switch": "gaia-components/gaia-switch",
|
||||
"gaia-theme": "gaia-components/gaia-theme"
|
||||
},
|
||||
"dependencies": {
|
||||
"gaia-component": "gaia-components/gaia-component#^0.3.6"
|
||||
}
|
||||
}
|
||||
321
gaia/distros/spark/apps/customizer/components/gaia-list/gaia-list.js
Executable file
321
gaia/distros/spark/apps/customizer/components/gaia-list/gaia-list.js
Executable file
|
|
@ -0,0 +1,321 @@
|
|||
/* global define */
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Pointer event abstraction to make
|
||||
* it work for touch and mouse.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
/*jshint ignore:start */
|
||||
var pointer = [
|
||||
{ down: 'touchstart', up: 'touchend', move: 'touchmove' },
|
||||
{ down: 'mousedown', up: 'mouseup', move: 'mousemove' }
|
||||
]['ontouchstart' in window ? 0 : 1];
|
||||
/*jshint ignore:end */
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
module.exports = component.register('gaia-list', {
|
||||
extends: HTMLUListElement.prototype,
|
||||
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
this.els = { inner: this.shadowRoot.querySelector('.inner') };
|
||||
this.addEventListener('click', this.onPointerDown);
|
||||
this.makeAccessible();
|
||||
},
|
||||
|
||||
makeAccessible: function() {
|
||||
[].forEach.call(this.children, (el) => { el.tabIndex = 0; });
|
||||
},
|
||||
|
||||
itemShouldRipple: function(el) {
|
||||
if (scrolling) { return false; }
|
||||
else if (el.classList.contains('ripple')) { return true; }
|
||||
else if (el.classList.contains('no-ripple')) { return false; }
|
||||
else if (this.classList.contains('ripple')){ return true; }
|
||||
else if (this.classList.contains('no-ripple')){ return false; }
|
||||
else if (el.tagName === 'A') { return true; }
|
||||
else { return false; }
|
||||
},
|
||||
|
||||
onPointerDown: function(e) {
|
||||
var point = e.touches ? e.changedTouches[0] : e;
|
||||
var target = this.getChild(e.target);
|
||||
|
||||
if (!this.itemShouldRipple(target)) { return; }
|
||||
|
||||
var pos = {
|
||||
list: this.getBoundingClientRect(),
|
||||
item: target.getBoundingClientRect()
|
||||
};
|
||||
|
||||
var els = {
|
||||
container: document.createElement('div'),
|
||||
ripple: document.createElement('div')
|
||||
};
|
||||
|
||||
requestAnimationFrame(this.ripple.bind(this, point, pos, els));
|
||||
},
|
||||
|
||||
ripple: function(point, pos, els) {
|
||||
els.container.className = 'ripple-container';
|
||||
els.container.style.left = (pos.item.left - pos.list.left) + 'px';
|
||||
els.container.style.top = (pos.item.top - pos.list.top) + 'px';
|
||||
els.container.style.width = pos.item.width + 'px';
|
||||
els.container.style.height = pos.item.height + 'px';
|
||||
|
||||
var offset = {
|
||||
x: point.clientX - pos.item.left,
|
||||
y: point.clientY - pos.item.top
|
||||
};
|
||||
|
||||
els.ripple.className = 'ripple';
|
||||
els.ripple.style.left = offset.x + 'px';
|
||||
els.ripple.style.top = offset.y + 'px';
|
||||
els.ripple.style.visibility = 'hidden';
|
||||
|
||||
els.container.appendChild(els.ripple);
|
||||
this.els.inner.appendChild(els.container);
|
||||
|
||||
var end = 'transitionend';
|
||||
requestAnimationFrame(function() {
|
||||
els.ripple.style.visibility = '';
|
||||
els.ripple.style.transform = 'scale(' + pos.item.width + ')';
|
||||
els.ripple.style.transitionDuration = '500ms';
|
||||
|
||||
els.ripple.addEventListener(end, function fn() {
|
||||
els.ripple.removeEventListener(end, fn);
|
||||
els.ripple.style.transitionDuration = '1000ms';
|
||||
els.ripple.style.opacity = '0';
|
||||
|
||||
els.ripple.addEventListener(end, function fn() {
|
||||
els.ripple.removeEventListener(end, fn);
|
||||
els.container.remove();
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
getChild: function(el) {
|
||||
return el && (el.parentNode === this ? el : this.getChild(el.parentNode));
|
||||
},
|
||||
|
||||
template: `
|
||||
<div class="inner">
|
||||
<content></content>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
/** Reset
|
||||
---------------------------------------------------------*/
|
||||
|
||||
label { background: none; }
|
||||
|
||||
/** Host
|
||||
---------------------------------------------------------*/
|
||||
|
||||
:host {
|
||||
position: relative;
|
||||
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
/** Children
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content > *:not(style) {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: 60px;
|
||||
padding: 9px 16px;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
|
||||
font-size: 18px;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
background: transparent;
|
||||
align-items: center;
|
||||
list-style-type: none;
|
||||
|
||||
color:
|
||||
var(--text-color);
|
||||
}
|
||||
|
||||
::content > a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/** Titles
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content h1,
|
||||
::content h2,
|
||||
::content h3,
|
||||
::content h4 {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/** Layout Helpers
|
||||
---------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* [flexbox]
|
||||
*
|
||||
* A helper attribute to allow users to
|
||||
* quickly define content as a flexbox.
|
||||
*/
|
||||
|
||||
::content [flexbox] {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/**
|
||||
* [flex]
|
||||
*
|
||||
* A helper attribute to allow users to
|
||||
* quickly define area as flexible.
|
||||
*/
|
||||
|
||||
::content [flex] {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/** Border
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content > *:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 16px;
|
||||
right: 16px;
|
||||
height: 1px;
|
||||
|
||||
background:
|
||||
var(--border-color,
|
||||
var(--background-plus));
|
||||
}
|
||||
|
||||
/* Hack: Hide the line before the second element, since the first element is
|
||||
* the <style scoped> element */
|
||||
::content > :first-child:before,
|
||||
::content > style:first-child ~ :nth-child(2):before,
|
||||
::content > gaia-header:first-child ~ :nth-child(2):before,
|
||||
::content > gaia-sub-header:first-child ~ :nth-child(2):before,
|
||||
::content > h1:first-child ~ :nth-child(2):before,
|
||||
::content > h2:first-child ~ :nth-child(2):before,
|
||||
::content > .borderless:before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/** Descriptions
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content small,
|
||||
::content p {
|
||||
font-size: 0.7em;
|
||||
line-height: 1.35em;
|
||||
}
|
||||
|
||||
/** Icon
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content i {
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
::content i:before {
|
||||
display: block;
|
||||
}
|
||||
|
||||
::content > * > i:last-child {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the icons when the document is RTL mode
|
||||
*/
|
||||
|
||||
:host-context([dir=rtl]) ::content i:before {
|
||||
transform: scale(-1, 1);
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
/** Divided
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content .divided {
|
||||
-moz-border-start: solid 1px;
|
||||
-moz-padding-start: 14px;
|
||||
|
||||
border-color:
|
||||
var(--border-color,
|
||||
var(--background-plus));
|
||||
}
|
||||
|
||||
/** Ripple Container
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.ripple-container.ripple-container {
|
||||
box-sizing: content-box;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
padding-top: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/** Ripple
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.ripple-container > .ripple {
|
||||
background: var(--border-color);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
margin: -1px;
|
||||
border-radius: 50%;
|
||||
transition-property: transform, opacity;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
</style>
|
||||
`
|
||||
});
|
||||
|
||||
var scrolling = false;
|
||||
var scrollTimeout;
|
||||
|
||||
addEventListener('scroll', function() {
|
||||
scrolling = true;
|
||||
clearTimeout(scrollTimeout);
|
||||
scrollTimeout = setTimeout(function() {
|
||||
scrolling = false;
|
||||
}, 100);
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-list',this));
|
||||
28
gaia/distros/spark/apps/customizer/components/gaia-modal/bower.json
Executable file
28
gaia/distros/spark/apps/customizer/components/gaia-modal/bower.json
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "gaia-modal",
|
||||
"version": "0.1.0",
|
||||
"homepage": "https://github.com/gaia-components/gaia-modal",
|
||||
"authors": [
|
||||
"Justin D'Arcangelo <jdarcangelo@mozilla.com>"
|
||||
],
|
||||
"main": "gaia-modal.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"bower_components",
|
||||
"index.html",
|
||||
"node_modules",
|
||||
"package.json",
|
||||
"README.md",
|
||||
"test",
|
||||
"!.jshintrc"
|
||||
],
|
||||
"dependencies": {
|
||||
"gaia-component": "gaia-components/gaia-component#~0.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"base": "gaia-components/base",
|
||||
"gaia-fonts": "gaia-components/gaia-fonts",
|
||||
"gaia-theme": "gaia-components/gaia-theme"
|
||||
}
|
||||
}
|
||||
401
gaia/distros/spark/apps/customizer/components/gaia-modal/dist/gaia-modal.js
vendored
Executable file
401
gaia/distros/spark/apps/customizer/components/gaia-modal/dist/gaia-modal.js
vendored
Executable file
|
|
@ -0,0 +1,401 @@
|
|||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.GaiaModal=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||
;(function(define){define(function(require,exports,module){
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Locals
|
||||
*/
|
||||
|
||||
var textContent = Object.getOwnPropertyDescriptor(Node.prototype, 'textContent');
|
||||
var removeAttribute = HTMLElement.prototype.removeAttribute;
|
||||
var setAttribute = HTMLElement.prototype.setAttribute;
|
||||
var noop = function() {};
|
||||
|
||||
/**
|
||||
* Detects presence of shadow-dom
|
||||
* CSS selectors.
|
||||
*
|
||||
* @return {Boolean}
|
||||
*/
|
||||
var hasShadowCSS = (function() {
|
||||
var div = document.createElement('div');
|
||||
try { div.querySelector(':host'); div.querySelector('::content'); return true; }
|
||||
catch (e) { return false; }
|
||||
})();
|
||||
|
||||
/**
|
||||
* Register a new component.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Object} props
|
||||
* @return {constructor}
|
||||
* @public
|
||||
*/
|
||||
module.exports.register = function(name, props) {
|
||||
|
||||
// Decide on a base protoype, create a handy
|
||||
// reference to super (extended) class, then clean up.
|
||||
var parent = props.extends ? props.extends.prototype : base;
|
||||
props.super = parent;
|
||||
delete props.extends;
|
||||
|
||||
// Pull out CSS that needs to be in the light-dom
|
||||
if (props.template) {
|
||||
var output = processCss(props.template, name);
|
||||
|
||||
props.template = document.createElement('template');
|
||||
props.template.innerHTML = output.template;
|
||||
props.lightCss = output.lightCss;
|
||||
|
||||
props.globalCss = props.globalCss || '';
|
||||
props.globalCss += output.globalCss;
|
||||
}
|
||||
|
||||
// Inject global CSS into the document,
|
||||
// and delete as no longer needed
|
||||
injectGlobalCss(props.globalCss);
|
||||
delete props.globalCss;
|
||||
|
||||
// Merge base getter/setter attributes with the user's,
|
||||
// then define the property descriptors on the prototype.
|
||||
var descriptors = Object.assign(props.attrs || {}, baseAttrs);
|
||||
|
||||
// Store the orginal descriptors somewhere
|
||||
// a little more private and delete the original
|
||||
props._attrs = props.attrs;
|
||||
delete props.attrs;
|
||||
|
||||
// Create the prototype, extended from the parent
|
||||
var proto = Object.assign(Object.create(parent), props);
|
||||
|
||||
// Define the properties directly on the prototype
|
||||
Object.defineProperties(proto, descriptors);
|
||||
|
||||
// Register the custom-element and return the constructor
|
||||
return document.registerElement(name, { prototype: proto });
|
||||
};
|
||||
|
||||
var base = Object.assign(Object.create(HTMLElement.prototype), {
|
||||
attributeChanged: noop,
|
||||
attached: noop,
|
||||
detached: noop,
|
||||
created: noop,
|
||||
|
||||
createdCallback: function() {
|
||||
injectLightCss(this);
|
||||
this.created();
|
||||
},
|
||||
|
||||
/**
|
||||
* It is very common to want to keep object
|
||||
* properties in-sync with attributes,
|
||||
* for example:
|
||||
*
|
||||
* el.value = 'foo';
|
||||
* el.setAttribute('value', 'foo');
|
||||
*
|
||||
* So we support an object on the prototype
|
||||
* named 'attrs' to provide a consistent
|
||||
* way for component authors to define
|
||||
* these properties. When an attribute
|
||||
* changes we keep the attr[name]
|
||||
* up-to-date.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String||null} from
|
||||
* @param {String||null} to
|
||||
*/
|
||||
attributeChangedCallback: function(name, from, to) {
|
||||
var prop = toCamelCase(name);
|
||||
if (this._attrs && this._attrs[prop]) { this[prop] = to; }
|
||||
this.attributeChanged(name, from, to);
|
||||
},
|
||||
|
||||
attachedCallback: function() { this.attached(); },
|
||||
detachedCallback: function() { this.detached(); },
|
||||
|
||||
/**
|
||||
* A convenient method for setting up
|
||||
* a shadow-root using the defined template.
|
||||
*
|
||||
* @return {ShadowRoot}
|
||||
*/
|
||||
setupShadowRoot: function() {
|
||||
if (!this.template) { return; }
|
||||
var node = document.importNode(this.template.content, true);
|
||||
this.createShadowRoot().appendChild(node);
|
||||
return this.shadowRoot;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets an attribute internally
|
||||
* and externally. This is so that
|
||||
* we can style internal shadow-dom
|
||||
* content.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String} value
|
||||
*/
|
||||
setAttr: function(name, value) {
|
||||
var internal = this.shadowRoot.firstElementChild;
|
||||
setAttribute.call(internal, name, value);
|
||||
setAttribute.call(this, name, value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes an attribute internally
|
||||
* and externally. This is so that
|
||||
* we can style internal shadow-dom
|
||||
* content.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String} value
|
||||
*/
|
||||
removeAttr: function(name) {
|
||||
var internal = this.shadowRoot.firstElementChild;
|
||||
removeAttribute.call(internal, name);
|
||||
removeAttribute.call(this, name);
|
||||
}
|
||||
});
|
||||
|
||||
var baseAttrs = {
|
||||
textContent: {
|
||||
set: function(value) {
|
||||
var node = firstChildTextNode(this);
|
||||
if (node) { node.nodeValue = value; }
|
||||
},
|
||||
|
||||
get: function() {
|
||||
var node = firstChildTextNode(this);
|
||||
return node && node.nodeValue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the first child textNode.
|
||||
*
|
||||
* @param {Element} el
|
||||
* @return {TextNode}
|
||||
*/
|
||||
function firstChildTextNode(el) {
|
||||
for (var i = 0; i < el.childNodes.length; i++) {
|
||||
var node = el.childNodes[i];
|
||||
if (node && node.nodeType === 3) { return node; }
|
||||
}
|
||||
}
|
||||
|
||||
var regex = {
|
||||
shadowCss: /(?:\:host|\:\:content)[^{]*\{[^}]*\}/g,
|
||||
':host': /(?:\:host)/g,
|
||||
':host()': /\:host\((.+)\)/g,
|
||||
':host-context': /\:host-context\((.+)\)([^{,]+)?/g,
|
||||
'::content': /(?:\:\:content)/g
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts the :host and ::content rules
|
||||
* from the shadow-dom CSS and rewrites
|
||||
* them to work from the <style scoped>
|
||||
* injected at the root of the component.
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
function processCss(template, name) {
|
||||
var globalCss = '';
|
||||
var lightCss = '';
|
||||
|
||||
if (!hasShadowCSS) {
|
||||
template = template.replace(regex.shadowCss, function(match) {
|
||||
var hostContext = regex[':host-context'].exec(match);
|
||||
|
||||
if (hostContext) {
|
||||
globalCss += match
|
||||
.replace(regex['::content'], '')
|
||||
.replace(regex[':host-context'], '$1 ' + name + '$2')
|
||||
.replace(/ +/g, ' '); // excess whitespace
|
||||
} else {
|
||||
lightCss += match
|
||||
.replace(regex[':host()'], name + '$1')
|
||||
.replace(regex[':host'], name)
|
||||
.replace(regex['::content'], name);
|
||||
}
|
||||
|
||||
return '';
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
template: template,
|
||||
lightCss: lightCss,
|
||||
globalCss: globalCss
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Some CSS rules, such as @keyframes
|
||||
* and @font-face don't work inside
|
||||
* scoped or shadow <style>. So we
|
||||
* have to put them into 'global'
|
||||
* <style> in the head of the
|
||||
* document.
|
||||
*
|
||||
* @param {String} css
|
||||
*/
|
||||
function injectGlobalCss(css) {
|
||||
if (!css) return;
|
||||
var style = document.createElement('style');
|
||||
style.innerHTML = css.trim();
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The Gecko platform doesn't yet have
|
||||
* `::content` or `:host`, selectors,
|
||||
* without these we are unable to style
|
||||
* user-content in the light-dom from
|
||||
* within our shadow-dom style-sheet.
|
||||
*
|
||||
* To workaround this, we clone the <style>
|
||||
* node into the root of the component,
|
||||
* so our selectors are able to target
|
||||
* light-dom content.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function injectLightCss(el) {
|
||||
if (hasShadowCSS) { return; }
|
||||
el.lightStyle = document.createElement('style');
|
||||
el.lightStyle.setAttribute('scoped', '');
|
||||
el.lightStyle.innerHTML = el.lightCss;
|
||||
el.appendChild(el.lightStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hyphen separated
|
||||
* string to camel-case.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* toCamelCase('foo-bar'); //=> 'fooBar'
|
||||
*
|
||||
* @param {Sring} string
|
||||
* @return {String}
|
||||
*/
|
||||
function toCamelCase(string) {
|
||||
return string.replace(/-(.)/g, function replacer(string, p1) {
|
||||
return p1.toUpperCase();
|
||||
});
|
||||
}
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-component',this));
|
||||
|
||||
},{}],2:[function(require,module,exports){
|
||||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Register the element.
|
||||
*
|
||||
* @return {Element} constructor
|
||||
*/
|
||||
module.exports = component.register('gaia-modal', {
|
||||
|
||||
/**
|
||||
* Called when the element is first created.
|
||||
*
|
||||
* Here we create the shadow-root and
|
||||
* inject our template into it.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
// Properties
|
||||
this.active = this.getAttribute('active');
|
||||
},
|
||||
|
||||
/**
|
||||
* Known attribute property
|
||||
* descriptors.
|
||||
*
|
||||
* These setters get called when matching
|
||||
* attributes change on the element.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
attrs: {
|
||||
active: {
|
||||
get: function() { return this._active || false; },
|
||||
set: function(value) {
|
||||
value = !!(value || value === '');
|
||||
|
||||
if (value === this.active) { return; }
|
||||
this._active = value;
|
||||
|
||||
if (value) { this.setAttr('active', ''); }
|
||||
else { this.removeAttr('active'); }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
open: function() {
|
||||
this.active = true;
|
||||
},
|
||||
|
||||
close: function() {
|
||||
this.active = false;
|
||||
},
|
||||
|
||||
template: `<div class="inner">
|
||||
<content></content>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:host {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 9999;
|
||||
transition: all 0.2s;
|
||||
transform: translate(0, 100%);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
:host[active] {
|
||||
transform: translate(0, 0);
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.inner {
|
||||
background: var(--background, #fff);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-modal',this));
|
||||
|
||||
},{"gaia-component":1}]},{},[2])(2)
|
||||
});
|
||||
101
gaia/distros/spark/apps/customizer/components/gaia-modal/gaia-modal.js
Executable file
101
gaia/distros/spark/apps/customizer/components/gaia-modal/gaia-modal.js
Executable file
|
|
@ -0,0 +1,101 @@
|
|||
;(function(define){'use strict';define(function(require,exports,module){
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Register the element.
|
||||
*
|
||||
* @return {Element} constructor
|
||||
*/
|
||||
module.exports = component.register('gaia-modal', {
|
||||
|
||||
/**
|
||||
* Called when the element is first created.
|
||||
*
|
||||
* Here we create the shadow-root and
|
||||
* inject our template into it.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
// Properties
|
||||
this.active = this.getAttribute('active');
|
||||
},
|
||||
|
||||
/**
|
||||
* Known attribute property
|
||||
* descriptors.
|
||||
*
|
||||
* These setters get called when matching
|
||||
* attributes change on the element.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
attrs: {
|
||||
active: {
|
||||
get: function() { return this._active || false; },
|
||||
set: function(value) {
|
||||
value = !!(value || value === '');
|
||||
|
||||
if (value === this.active) { return; }
|
||||
this._active = value;
|
||||
|
||||
if (value) { this.setAttr('active', ''); }
|
||||
else { this.removeAttr('active'); }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
open: function() {
|
||||
this.active = true;
|
||||
},
|
||||
|
||||
close: function() {
|
||||
this.active = false;
|
||||
},
|
||||
|
||||
template: `<div class="inner">
|
||||
<content></content>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:host {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 9999;
|
||||
transition: all 0.2s;
|
||||
transform: translate(0, 100%);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
:host[active] {
|
||||
transform: translate(0, 0);
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.inner {
|
||||
background: var(--background, #fff);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-modal',this));
|
||||
24
gaia/distros/spark/apps/customizer/components/gaia-tabs/bower.json
Executable file
24
gaia/distros/spark/apps/customizer/components/gaia-tabs/bower.json
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "gaia-tabs",
|
||||
"version": "0.0.1",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "gaia-tabs.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"examples",
|
||||
"test",
|
||||
"tests",
|
||||
"README.md"
|
||||
],
|
||||
"dependencies": {
|
||||
"gaia-component": "gaia-components/gaia-component#~0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"base": "gaia-components/base"
|
||||
}
|
||||
}
|
||||
235
gaia/distros/spark/apps/customizer/components/gaia-tabs/gaia-tabs.js
Executable file
235
gaia/distros/spark/apps/customizer/components/gaia-tabs/gaia-tabs.js
Executable file
|
|
@ -0,0 +1,235 @@
|
|||
;(function(umd){umd(function(require,exports,module){
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
module.exports = component.register('gaia-tabs', {
|
||||
|
||||
/**
|
||||
* Runs on creation
|
||||
*
|
||||
* The initial value of the `select`
|
||||
* attribute is used to select a tab.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
marker: this.shadowRoot.querySelector('.marker')
|
||||
};
|
||||
|
||||
this.makeAccessible();
|
||||
this.addEventListener('click', this.onClick);
|
||||
this.select(this.getAttribute('selected'));
|
||||
this.setupMarker();
|
||||
},
|
||||
|
||||
getLength: function() {
|
||||
var style = this.querySelector('style') ? 1 : 0;
|
||||
return this.children.length - style;
|
||||
},
|
||||
|
||||
setupMarker: function() {
|
||||
this.els.marker.style.width = (1 / this.getLength() * 100) + '%';
|
||||
},
|
||||
|
||||
setMarkerPosition: function(index) {
|
||||
index = document.dir === 'rtl' ? this.getLength() - index - 1 : index;
|
||||
this.els.marker.style.transform = 'translateX(' + index * 100 + '%)';
|
||||
},
|
||||
|
||||
/**
|
||||
* Add necessary attributes to
|
||||
* improve accessibility.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
makeAccessible: function() {
|
||||
this.setAttribute('role', 'tablist');
|
||||
for (var el = this.firstElementChild; el; el = el.nextElementSibling) {
|
||||
el.setAttribute('role', 'tab');
|
||||
el.tabIndex = 0;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Walks up the DOM from the `event.target`
|
||||
* until it finds an immediate child of the
|
||||
* element, then selects the index
|
||||
* of that element.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @private
|
||||
*/
|
||||
onClick: function(e) {
|
||||
var el = e.target;
|
||||
var i;
|
||||
while (el) {
|
||||
i = [].indexOf.call(this.children, el);
|
||||
if (i > -1) { return this.select(i); }
|
||||
el = el.parentNode;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Select a tab by index.
|
||||
*
|
||||
* @param {Number} index
|
||||
* @public
|
||||
*/
|
||||
select: function(index) {
|
||||
if (index === null) { return; }
|
||||
|
||||
// Make sure it's a number
|
||||
index = Number(index);
|
||||
|
||||
var el = this.children[index];
|
||||
this.deselect(this.selected);
|
||||
this.setMarkerPosition(index);
|
||||
this.selectedChild = el;
|
||||
this.selected = index;
|
||||
|
||||
el.setAttribute('aria-selected', 'true');
|
||||
el.classList.add('selected');
|
||||
|
||||
var e = new CustomEvent('change');
|
||||
setTimeout(this.dispatchEvent.bind(this, e));
|
||||
},
|
||||
|
||||
/**
|
||||
* Deselect a tab by index.
|
||||
* @param {Number} index
|
||||
* @public
|
||||
*/
|
||||
deselect: function(index) {
|
||||
var el = this.children[index];
|
||||
if (!el) { return; }
|
||||
el.removeAttribute('aria-selected');
|
||||
el.classList.remove('selected');
|
||||
if (this.current == el) {
|
||||
this.selectedChild = null;
|
||||
this.selected = null;
|
||||
}
|
||||
},
|
||||
|
||||
template: `
|
||||
<div class="inner">
|
||||
<content></content>
|
||||
<div class="marker"></div>
|
||||
</div>
|
||||
<style>
|
||||
|
||||
/** Host
|
||||
---------------------------------------------------------*/
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
position: relative;
|
||||
border-top: 1px solid;
|
||||
overflow: hidden;
|
||||
|
||||
border-color:
|
||||
var(--border-color,
|
||||
var(--background-plus))
|
||||
}
|
||||
|
||||
/** Inner
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.inner {
|
||||
display: flex;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
/** Direct Children
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content > * {
|
||||
position: relative;
|
||||
|
||||
display: block;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
line-height: 45px;
|
||||
outline: 0;
|
||||
border: 0;
|
||||
flex: 1;
|
||||
|
||||
font-size: 17px;
|
||||
font-style: italic;
|
||||
font-weight: lighter;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
transition:
|
||||
color,
|
||||
opacity 0.2s;
|
||||
transition-delay: 200ms;
|
||||
}
|
||||
|
||||
/**
|
||||
* :active
|
||||
*/
|
||||
|
||||
::content > :active {
|
||||
transition: none;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
/**
|
||||
* .selected
|
||||
*/
|
||||
|
||||
::content > .selected {
|
||||
color: var(--highlight-color, #000);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* [disabled]
|
||||
*/
|
||||
|
||||
::content > [disabled] {
|
||||
transition: none;
|
||||
opacity: 0.3;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/** Style
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::content style {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/** Marker
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.marker {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
height: 3px;
|
||||
background: var(--highlight-color, #000);
|
||||
transition: transform 0.2s;
|
||||
transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.275);
|
||||
}
|
||||
|
||||
</style>
|
||||
`
|
||||
});
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-tabs',this));
|
||||
35
gaia/distros/spark/apps/customizer/components/gaia-tabs/index.html
Executable file
35
gaia/distros/spark/apps/customizer/components/gaia-tabs/index.html
Executable file
|
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title><gaia-tabs></title>
|
||||
<meta name="description" content="gaia-tabs example" />
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/base/base.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-theme/gaia-theme.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-fonts/style.css">
|
||||
<script src="bower_components/gaia-theme/lib/gaia-theme-selector.js"></script>
|
||||
<script src="bower_components/gaia-component/gaia-component.js"></script>
|
||||
<script src="gaia-tabs.js"></script>
|
||||
<style type="text/css">
|
||||
|
||||
body {
|
||||
padding: 16px;
|
||||
padding-top: 48px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<gaia-theme-selector></gaia-theme-selector>
|
||||
<h1 class="large l-align-center l-mb-mega"><gaia-tabs></h1>
|
||||
<section>
|
||||
<gaia-tabs selected="2">
|
||||
<a href="#" class="icon-dialer">Item 1</a>
|
||||
<a href="#" class="icon-contacts">Item 2</a>
|
||||
<a href="#" class="icon-call-log">Item 3</a>
|
||||
<a href="#" disabled="">Item 4</a>
|
||||
<a href="#">Item 5</a>
|
||||
</gaia-tabs>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
26
gaia/distros/spark/apps/customizer/components/gaia-tabs/package.json
Executable file
26
gaia/distros/spark/apps/customizer/components/gaia-tabs/package.json
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "gaia-tabs",
|
||||
"version": "0.1.0",
|
||||
"main": "gaia-tabs.js",
|
||||
"directories": {
|
||||
"example": "examples",
|
||||
"test": "test"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
"test": "gaia-test-lint && gaia-test-unit"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/gaia-components/gaia-tabs.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/gaia-components/gaia-tabs/issues"
|
||||
},
|
||||
"homepage": "https://github.com/gaia-components/gaia-tabs",
|
||||
"dependencies": {
|
||||
"gaia-test": "git://github.com/gaia-components/gaia-test"
|
||||
}
|
||||
}
|
||||
27
gaia/distros/spark/apps/customizer/components/gaia-text-input/bower.json
Executable file
27
gaia/distros/spark/apps/customizer/components/gaia-text-input/bower.json
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "gaia-text-input",
|
||||
"version": "0.1.2",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "gaia-text-input.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests",
|
||||
"README.md"
|
||||
],
|
||||
"dependencies": {
|
||||
"gaia-icons": "gaia-components/gaia-icons#~0.8.0",
|
||||
"gaia-component": "gaia-components/gaia-component#~0.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"gaia-fonts": "gaia-components/gaia-fonts#~0.2.1",
|
||||
"gaia-theme": "gaia-components/gaia-theme#~0.4.3",
|
||||
"base": "gaia-components/base",
|
||||
"gaia-icons": "gaia-components/gaia-icons#master"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
(function(define){define(function(require,exports,module){
|
||||
/*jshint esnext:true*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
module.exports = component.register('gaia-text-input-multiline', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
inner: this.shadowRoot.querySelector('.inner'),
|
||||
field: this.shadowRoot.querySelector('textarea')
|
||||
};
|
||||
|
||||
this.type = this.getAttribute('type');
|
||||
this.disabled = this.hasAttribute('disabled');
|
||||
this.placeholder = this.getAttribute('placeholder');
|
||||
this.required = this.getAttribute('required');
|
||||
this.value = this.getAttribute('value');
|
||||
},
|
||||
|
||||
clear: function(e) {
|
||||
this.value = '';
|
||||
},
|
||||
|
||||
attrs: {
|
||||
placeholder: {
|
||||
get: function() { return this.els.field.placeholder; },
|
||||
set: function(value) { this.els.field.placeholder = value || ''; }
|
||||
},
|
||||
|
||||
value: {
|
||||
get: function() { return this.els.field.value; },
|
||||
set: function(value) { this.els.field.value = value; }
|
||||
},
|
||||
|
||||
required: {
|
||||
get: function() { return this.els.field.required; },
|
||||
set: function(value) { this.els.field.required = value; }
|
||||
},
|
||||
|
||||
disabled: {
|
||||
get: function() { return this.els.field.disabled; },
|
||||
set: function(value) {
|
||||
value = !!(value === '' || value);
|
||||
this.els.field.disabled = value;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
template: `<div class="inner">
|
||||
<content select="label"></content>
|
||||
<div class="fields">
|
||||
<textarea></textarea>
|
||||
<div class="focus focus-1"></div>
|
||||
<div class="focus focus-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
|
||||
/** Reset
|
||||
---------------------------------------------------------*/
|
||||
|
||||
textarea {
|
||||
box-sizing: border-box;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/** Host
|
||||
---------------------------------------------------------*/
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
margin-top: var(--base-m, 18px);
|
||||
margin-bottom: var(--base-m, 18px);
|
||||
}
|
||||
|
||||
/** Inner
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.inner {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/** Label
|
||||
---------------------------------------------------------*/
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
margin: 0 0 4px 16px;
|
||||
}
|
||||
|
||||
/**
|
||||
* [disbled]
|
||||
*/
|
||||
|
||||
[disabled] label {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
/** Fields
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.fields {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
--gi-border-color:
|
||||
var(--input-border-color,
|
||||
var(--border-color,
|
||||
var(--background-plus,
|
||||
#e7e7e7)));
|
||||
|
||||
border-color:
|
||||
var(--gi-border-color);
|
||||
|
||||
border:
|
||||
var(--input-border,
|
||||
var(--border,
|
||||
1px solid var(--gi-border-color)));
|
||||
}
|
||||
|
||||
/** Textarea
|
||||
---------------------------------------------------------*/
|
||||
|
||||
textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 86px;
|
||||
padding: 10px 16px;
|
||||
font-size: inherit;
|
||||
border: none;
|
||||
margin: 0;
|
||||
font: inherit;
|
||||
resize: none;
|
||||
|
||||
/* dynamic */
|
||||
|
||||
color:
|
||||
var(--text-color, #000);
|
||||
|
||||
background:
|
||||
var(--text-input-background,
|
||||
var(--input-background,
|
||||
var(--background-minus,
|
||||
#fff)));
|
||||
}
|
||||
|
||||
/**
|
||||
* [disabled]
|
||||
*/
|
||||
|
||||
textarea[disabled] {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/** Placeholder Text
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::-moz-placeholder {
|
||||
font-style: italic;
|
||||
|
||||
color:
|
||||
var(--input-placeholder-color, #909ca7);
|
||||
}
|
||||
|
||||
/** Focus Bar
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.focus {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
transition: all 200ms;
|
||||
transform: scaleX(0);
|
||||
visibility: hidden;
|
||||
background: var(--highlight-color, #000);
|
||||
}
|
||||
|
||||
/**
|
||||
* input:focus
|
||||
*/
|
||||
|
||||
:focus ~ .focus {
|
||||
transform: scaleX(1);
|
||||
transition-delay: 200ms;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.focus-2 {
|
||||
top: 0;
|
||||
bottom: auto;
|
||||
}
|
||||
|
||||
</style>`
|
||||
});
|
||||
|
||||
});})((function(n,w){return typeof define=='function'&&define.amd?
|
||||
define:typeof module=='object'?function(c){c(require,exports,module);}:function(c){
|
||||
var m={exports:{}},r=function(n){return w[n];};w[n]=c(r,m.exports,m)||m.exports;};})('gaia-text-input-multiline',this));
|
||||
|
|
@ -0,0 +1,279 @@
|
|||
(function(define){define(function(require,exports,module){
|
||||
/*jshint esnext:true*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var component = require('gaia-component');
|
||||
|
||||
/**
|
||||
* Locals
|
||||
*/
|
||||
|
||||
var DEFAULT_LENGTH = 4;
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
module.exports = component.register('gaia-text-input-pin', {
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
inner: this.shadowRoot.querySelector('.inner'),
|
||||
fields: this.shadowRoot.querySelector('.fields'),
|
||||
input: this.shadowRoot.querySelector('input')
|
||||
};
|
||||
|
||||
this.disabled = this.hasAttribute('disabled');
|
||||
this.length = this.getAttribute('length') || DEFAULT_LENGTH;
|
||||
|
||||
this.addEventListener('keyup', () => this.updateCells());
|
||||
},
|
||||
|
||||
updateCells: function() {
|
||||
var l = this.els.input.value.length;
|
||||
this.els.cells.forEach((cell, i) => {
|
||||
cell.classList.toggle('populated', i < l);
|
||||
cell.classList.toggle('focused', i == l);
|
||||
});
|
||||
},
|
||||
|
||||
onBackspace: function(e) {
|
||||
var input = e.target;
|
||||
var empty = !input.value;
|
||||
var previous = input.previousElementSibling;
|
||||
|
||||
if (!empty && previous) {
|
||||
previous.clear();
|
||||
previous.focus();
|
||||
} else if (empty && previous) {
|
||||
previous.focus();
|
||||
}
|
||||
},
|
||||
|
||||
setupFields: function() {
|
||||
this.els.fields.innerHTML = '';
|
||||
this.els.cells = [];
|
||||
|
||||
for (var i = 0, l = this.length; i < l; i++) {
|
||||
var el = document.createElement('div');
|
||||
el.className = 'cell';
|
||||
this.els.fields.appendChild(el);
|
||||
this.els.cells.push(el);
|
||||
}
|
||||
},
|
||||
|
||||
attributeChangedCallback: function(attr, from, to) {
|
||||
if (attrs[attr]) { this[attr] = to; }
|
||||
},
|
||||
|
||||
clear: function(e) {
|
||||
this.value = '';
|
||||
},
|
||||
|
||||
/**
|
||||
* Attributes
|
||||
*/
|
||||
|
||||
attrs: {
|
||||
length: {
|
||||
get: function() { return this._length; },
|
||||
set: function(value) {
|
||||
value = Number(value);
|
||||
this._length = value;
|
||||
this.els.input.setAttribute('maxlength', this.length);
|
||||
this.setupFields();
|
||||
}
|
||||
},
|
||||
|
||||
value: {
|
||||
get: function() { return this.els.input.value; },
|
||||
set: function(value) { this.els.input.value = value; }
|
||||
},
|
||||
|
||||
disabled: {
|
||||
get: function() { return this.els.input.disabled; },
|
||||
set: function(value) {
|
||||
value = !!(value === '' || value);
|
||||
this.els.input.disabled = value;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
template: `
|
||||
<div class="inner">
|
||||
<content select="label"></content>
|
||||
<div class="container">
|
||||
<input />
|
||||
<div class="fields"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
/** Host
|
||||
---------------------------------------------------------*/
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
height: 40px;
|
||||
margin-top: var(--base-m, 18px);
|
||||
margin-bottom: var(--base-m, 18px);
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
/** Inner
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.inner {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/** Label
|
||||
---------------------------------------------------------*/
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
margin: 0 0 4px 16px;
|
||||
}
|
||||
|
||||
/** Container
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/** Input (hidden)
|
||||
---------------------------------------------------------*/
|
||||
|
||||
input {
|
||||
opacity: 0;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/** Fields
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.fields {
|
||||
display: flex;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
margin-left: -1rem;
|
||||
}
|
||||
|
||||
/**
|
||||
* [disbled]
|
||||
*/
|
||||
|
||||
[disabled] + .fields {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/** Cell
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.cell {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
margin-left: 1rem;
|
||||
flex: 1;
|
||||
|
||||
/* dynamic */
|
||||
|
||||
--gi-border-color:
|
||||
var(--input-border-color,
|
||||
var(--border-color,
|
||||
var(--background-plus,
|
||||
#e7e7e7)));
|
||||
|
||||
border-color:
|
||||
var(--gi-border-color);
|
||||
|
||||
border:
|
||||
var(--input-border,
|
||||
var(--border,
|
||||
1px solid var(--gi-border-color)));
|
||||
|
||||
background:
|
||||
var(--text-input-background,
|
||||
var(--input-background,
|
||||
var(--background-minus,
|
||||
#fff)));
|
||||
}
|
||||
|
||||
/**
|
||||
* [disbled]
|
||||
*/
|
||||
|
||||
[disabled] + .fields .cell {
|
||||
background: none;
|
||||
}
|
||||
|
||||
/** Dot
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.cell::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin: -7px;
|
||||
border-radius: 50%;
|
||||
opacity: 0;
|
||||
|
||||
/* dynamic */
|
||||
|
||||
background:
|
||||
var(--text-color);
|
||||
}
|
||||
|
||||
/**
|
||||
* .populated
|
||||
*/
|
||||
|
||||
.cell.populated::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.cell::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
visibility: hidden;
|
||||
background: var(--highlight-color, #000);
|
||||
}
|
||||
|
||||
/**
|
||||
* input:focus
|
||||
*/
|
||||
|
||||
input:focus + .fields .cell::before {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
</style>
|
||||
`
|
||||
});
|
||||
|
||||
});})((function(n,w){return typeof define=='function'&&define.amd?
|
||||
define:typeof module=='object'?function(c){c(require,exports,module);}:function(c){
|
||||
var m={exports:{}},r=function(n){return w[n];};w[n]=c(r,m.exports,m)||m.exports;};})('gaia-text-input-pin',this));
|
||||
317
gaia/distros/spark/apps/customizer/components/gaia-text-input/gaia-text-input.js
Executable file
317
gaia/distros/spark/apps/customizer/components/gaia-text-input/gaia-text-input.js
Executable file
|
|
@ -0,0 +1,317 @@
|
|||
(function(define){define(function(require,exports,module){
|
||||
/*jshint esnext:true*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var component = require('gaia-component');
|
||||
require('gaia-icons'); // Load gaia-icons
|
||||
|
||||
/**
|
||||
* Exports
|
||||
*/
|
||||
|
||||
module.exports = component.register('gaia-text-input', {
|
||||
extends: HTMLInputElement,
|
||||
|
||||
created: function() {
|
||||
this.setupShadowRoot();
|
||||
|
||||
this.els = {
|
||||
inner: this.shadowRoot.querySelector('.inner'),
|
||||
input: this.shadowRoot.querySelector('input'),
|
||||
clear: this.shadowRoot.querySelector('.clear')
|
||||
};
|
||||
|
||||
this.type = this.getAttribute('type');
|
||||
this.disabled = this.hasAttribute('disabled');
|
||||
this.clearable = this.hasAttribute('clearable');
|
||||
this.placeholder = this.getAttribute('placeholder');
|
||||
this.required = this.getAttribute('required');
|
||||
this.value = this.getAttribute('value');
|
||||
|
||||
// Don't take focus from the input field
|
||||
this.els.clear.addEventListener('mousedown', (e) => e.preventDefault());
|
||||
this.els.clear.addEventListener('click', e => this.clear(e));
|
||||
},
|
||||
|
||||
clear: function(e) {
|
||||
this.value = '';
|
||||
},
|
||||
|
||||
focus: function() {
|
||||
this.els.input.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Attributes
|
||||
*/
|
||||
|
||||
attrs: {
|
||||
type: {
|
||||
get: function() { return this.els.input.getAttribute('type'); },
|
||||
set: function(value) {
|
||||
if (!value) { return; }
|
||||
this.els.inner.setAttribute('type', value);
|
||||
this.els.input.setAttribute('type', value);
|
||||
}
|
||||
},
|
||||
|
||||
placeholder: {
|
||||
get: function() { return this.field.placeholder; },
|
||||
set: function(value) {
|
||||
if (!value && value !== '') { return; }
|
||||
this.els.input.placeholder = value;
|
||||
}
|
||||
},
|
||||
|
||||
clearable: {
|
||||
get: function() { return this._clearable; },
|
||||
set: function(value) {
|
||||
var clearable = !!(value === '' || value);
|
||||
if (clearable === this.clearable) { return; }
|
||||
|
||||
if (clearable) {
|
||||
this.els.inner.setAttribute('clearable', '');
|
||||
this.setAttribute('clearable', '');
|
||||
} else {
|
||||
this.els.inner.removeAttribute('clearable');
|
||||
this.removeAttribute('clearable');
|
||||
}
|
||||
|
||||
this._clearable = clearable;
|
||||
}
|
||||
},
|
||||
|
||||
value: {
|
||||
get: function() { return this.els.input.value; },
|
||||
set: function(value) { this.els.input.value = value; }
|
||||
},
|
||||
|
||||
required: {
|
||||
get: function() { return this.els.input.required; },
|
||||
set: function(value) { this.els.input.required = value; }
|
||||
},
|
||||
|
||||
maxlength: {
|
||||
get: function() { return this.els.input.getAttribute('maxlength'); },
|
||||
set: function(value) { this.els.input.setAttribute('maxlength', value); }
|
||||
},
|
||||
|
||||
disabled: {
|
||||
get: function() { return this.els.input.disabled; },
|
||||
set: function(value) {
|
||||
value = !!(value === '' || value);
|
||||
this.els.input.disabled = value;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
template: `
|
||||
<div class="inner">
|
||||
<content select="label"></content>
|
||||
<div class="fields">
|
||||
<input type="text"/>
|
||||
<button class="clear" tabindex="-1"></button>
|
||||
<div class="focus"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
height: 40px;
|
||||
margin-top: var(--base-m, 18px);
|
||||
margin-bottom: var(--base-m, 18px);
|
||||
}
|
||||
|
||||
/** Reset
|
||||
---------------------------------------------------------*/
|
||||
|
||||
input,
|
||||
button {
|
||||
box-sizing: border-box;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/** Inner
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.inner {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/** Label
|
||||
---------------------------------------------------------*/
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
margin: 0 0 4px 16px;
|
||||
}
|
||||
|
||||
/**
|
||||
* [disbled]
|
||||
*/
|
||||
|
||||
[disabled] label {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
/** Fields
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.fields {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
--gi-border-color:
|
||||
var(--input-border-color,
|
||||
var(--border-color,
|
||||
var(--background-plus,
|
||||
#e7e7e7)));
|
||||
|
||||
border-color:
|
||||
var(--gi-border-color);
|
||||
|
||||
border:
|
||||
var(--input-border,
|
||||
var(--border,
|
||||
1px solid var(--gi-border-color)));
|
||||
}
|
||||
|
||||
/**
|
||||
* [type='search']
|
||||
*/
|
||||
|
||||
[type='search'] .fields {
|
||||
border-radius: 30px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/** Input Field
|
||||
---------------------------------------------------------*/
|
||||
|
||||
input {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
padding: 0 16px;
|
||||
margin: 0;
|
||||
font: inherit;
|
||||
resize: none;
|
||||
|
||||
/* Dynamic */
|
||||
|
||||
color:
|
||||
var(--text-color, #000);
|
||||
|
||||
background:
|
||||
var(--text-input-background,
|
||||
var(--input-background,
|
||||
var(--background-minus,
|
||||
#fff)));
|
||||
}
|
||||
|
||||
/**
|
||||
* [disabled]
|
||||
*/
|
||||
|
||||
input[disabled] {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/** Placeholder Text
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::-moz-placeholder {
|
||||
font-style: italic;
|
||||
|
||||
color:
|
||||
var(--input-placeholder-color, #909ca7);
|
||||
}
|
||||
|
||||
/** Clear Button
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.clear {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 11px;
|
||||
right: 10px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-radius: 50%;
|
||||
opacity: 0;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
|
||||
background:
|
||||
var(--input-clear-background, #999);
|
||||
}
|
||||
|
||||
/**
|
||||
* [clearable]
|
||||
*/
|
||||
|
||||
[clearable] .clear {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* input:focus
|
||||
*/
|
||||
|
||||
input:focus ~ .clear {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/** Clear Icon
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.clear:before {
|
||||
font: normal 500 19px/16.5px 'gaia-icons';
|
||||
content: 'close';
|
||||
display: block;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
/** Focus Bar
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.focus {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
transition: all 200ms;
|
||||
transform: scaleX(0);
|
||||
visibility: hidden;
|
||||
background: var(--highlight-color, #000);
|
||||
}
|
||||
|
||||
/**
|
||||
* input:focus
|
||||
*/
|
||||
|
||||
:focus ~ .focus {
|
||||
transform: scaleX(1);
|
||||
transition-delay: 200ms;
|
||||
visibility: visible;
|
||||
}
|
||||
</style>
|
||||
`
|
||||
});
|
||||
|
||||
});})((function(n,w){return typeof define=='function'&&define.amd?
|
||||
define:typeof module=='object'?function(c){c(require,exports,module);}:function(c){
|
||||
var m={exports:{}},r=function(n){return w[n];};w[n]=c(r,m.exports,m)||m.exports;};})('gaia-text-input',this));
|
||||
50
gaia/distros/spark/apps/customizer/components/gaia-text-input/index.html
Executable file
50
gaia/distros/spark/apps/customizer/components/gaia-text-input/index.html
Executable file
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><gaia-text-input></title>
|
||||
<meta name="description" content="gaia-text-input demo">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/base/base.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-icons/gaia-icons.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-theme/gaia-theme.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-fonts/style.css">
|
||||
<script src="bower_components/gaia-theme/lib/gaia-theme-selector.js"></script>
|
||||
<script src="bower_components/gaia-component/gaia-component.js"></script>
|
||||
<script src="gaia-text-input.js"></script>
|
||||
<script src="gaia-text-input-multiline.js"></script>
|
||||
<script src="gaia-text-input-pin.js"></script>
|
||||
<style type="text/css">
|
||||
|
||||
body {
|
||||
padding: 48px 24px 24px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<gaia-theme-selector></gaia-theme-selector>
|
||||
|
||||
<button id="btn">Focus</button>
|
||||
|
||||
|
||||
<gaia-text-input id="field" placeholder="Default"></gaia-text-input>
|
||||
<gaia-text-input placeholder="Search" type="search"></gaia-text-input>
|
||||
<gaia-text-input placeholder="Email" type="email" clearable></gaia-text-input>
|
||||
<gaia-text-input-multiline placeholder="Multiline"></gaia-text-input-multiline>
|
||||
<gaia-text-input-pin length="4"></gaia-text-input-pin>
|
||||
|
||||
<gaia-text-input placeholder="Disabled" disabled></gaia-text-input>
|
||||
<gaia-text-input placeholder="Search" type="search" disabled></gaia-text-input>
|
||||
<gaia-text-input placeholder="Email" type="email" clearable disabled></gaia-text-input>
|
||||
<gaia-text-input-multiline placeholder="Multiline" disabled></gaia-text-input-multiline>
|
||||
<gaia-text-input-pin length="4" disabled></gaia-text-input-pin>
|
||||
|
||||
<!-- <gaia-text-input-password></gaia-text-input-password> -->
|
||||
|
||||
|
||||
<script>
|
||||
btn.onclick = e => field.focus();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
28
gaia/distros/spark/apps/customizer/components/gaia-text-input/package.json
Executable file
28
gaia/distros/spark/apps/customizer/components/gaia-text-input/package.json
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "gaia-text-input",
|
||||
"homepage": "https://github.com/gaia-components/gaia-text-input",
|
||||
"license": "ISC",
|
||||
"main": "gaia-text-input.js",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bower": "^1.3.5",
|
||||
"karma": "^0.12.16",
|
||||
"karma-firefox-launcher": "^0.1.3",
|
||||
"karma-mocha": "^0.1.3",
|
||||
"karma-sinon-chai": "^0.1.6",
|
||||
"mozilla-download": "0.4.4"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "./node_modules/karma/bin/karma start test/karma.conf.js --single-run",
|
||||
"test-dev": "./node_modules/karma/bin/karma start test/karma.conf.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/gaia-components/gaia-text-input.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/gaia-components/gaia-text-input/issues"
|
||||
}
|
||||
}
|
||||
26
gaia/distros/spark/apps/customizer/components/gaia-theme/bower.json
Executable file
26
gaia/distros/spark/apps/customizer/components/gaia-theme/bower.json
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "gaia-theme",
|
||||
"version": "0.5.0",
|
||||
"homepage": "https://github.com/gaia-components/gaia-theme",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"!.jshintrc",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests",
|
||||
"index.html",
|
||||
"README.md"
|
||||
],
|
||||
"devDependencies": {
|
||||
"gaia-icons": "gaia-components/gaia-icons",
|
||||
"gaia-header": "gaia-components/gaia-header",
|
||||
"gaia-button": "gaia-components/gaia-button",
|
||||
"gaia-switch": "gaia-components/gaia-switch",
|
||||
"gaia-checkbox": "gaia-components/gaia-checkbox"
|
||||
}
|
||||
}
|
||||
244
gaia/distros/spark/apps/customizer/components/gaia-theme/gaia-theme.css
Executable file
244
gaia/distros/spark/apps/customizer/components/gaia-theme/gaia-theme.css
Executable file
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
Gaia theme variables
|
||||
*/
|
||||
|
||||
|
||||
:root {
|
||||
|
||||
/** Grey Colors
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--color-alpha: #333333;
|
||||
--color-beta: #ffffff;
|
||||
--color-gamma: #4d4d4d;
|
||||
--color-delta: #5f5f5f;
|
||||
--color-epsilon: #858585;
|
||||
--color-zeta: #a6a6a6;
|
||||
--color-eta: #c7c7c7;
|
||||
--color-theta: #e7e7e7;
|
||||
--color-iota: #f4f4f4;
|
||||
|
||||
/** Brand Colors
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--color-darkblue: #00539f;
|
||||
--color-blue: #00caf2;
|
||||
--color-turquoise: #27c8c2;
|
||||
--color-darkorange: #e66000;
|
||||
--color-orange: #ff9500;
|
||||
--color-yellow: #ffcb00;
|
||||
--color-violet: #c40c84;
|
||||
|
||||
--color-warning: #fbbd3c;
|
||||
--color-destructive: #e2443a;
|
||||
--color-preffered: #00ba91;
|
||||
|
||||
/** Background
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--background: var(--color-beta);
|
||||
--background-plus: var(--color-theta);
|
||||
--background-minus: var(--color-zeta);
|
||||
|
||||
/** Borders
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--border-color: var(--color-theta);
|
||||
|
||||
/** Text Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--text-color: var(--color-gamma);
|
||||
--text-color-minus: var(--color-eta);
|
||||
|
||||
/** Button
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--button-background: var(--color-iota);
|
||||
|
||||
/** Links
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--link-color: var(--highlight-color);
|
||||
|
||||
/** Inputs
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--input-background: var(--color-beta);
|
||||
--input-color: var(--color-alpha);
|
||||
--input-clear-background: #909ca7;
|
||||
|
||||
/** Buttons
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--button-box-shadow:
|
||||
inset 0 -1px 0 #d8d8d8,
|
||||
inset 0 1px 0 #eeeeee;
|
||||
--button-box-shadow-active: var(--button-box-shadow);
|
||||
|
||||
/** Header
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--header-disabled-button-color: rgba(255,255,255,0.3);
|
||||
|
||||
/** Transitions
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--transition-duration: 0.2s;
|
||||
}
|
||||
|
||||
|
||||
.theme-productivity {
|
||||
|
||||
/** Brand Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--highlight-color: var(--color-orange);
|
||||
|
||||
/** Header
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--header-background: var(--highlight-color);
|
||||
--header-color: var(--color-beta);
|
||||
}
|
||||
|
||||
.theme-communications {
|
||||
|
||||
/** Brand Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--highlight-color: var(--color-turquoise);
|
||||
|
||||
/** Links
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--link-color: #177874;
|
||||
|
||||
/** Header
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--header-background: var(--highlight-color);
|
||||
--header-color: var(--color-beta);
|
||||
--header-icon-color: var(--color-beta);
|
||||
--header-button-color: var(--color-beta);
|
||||
}
|
||||
|
||||
.theme-settings {
|
||||
|
||||
/** Background
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--background: var(--color-iota);
|
||||
--background-plus: var(--color-beta);
|
||||
--background-minus: var(--color-epsilon);
|
||||
--background-minus-minus: var(--color-zeta);
|
||||
|
||||
/** Highlight
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--highlight-color: var(--color-blue);
|
||||
|
||||
/** Borders
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--border-color: var(--color-theta);
|
||||
|
||||
/** Text Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--text-color: var(--color-gamma);
|
||||
|
||||
/** Titles
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--title-color: var(--background-minus);
|
||||
|
||||
/** Buttons
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--button-background: var(--background-plus);
|
||||
|
||||
/** Switch
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--switch-background: var(--background-minus-minus);
|
||||
|
||||
/** Checkbox
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--checkbox-border-color: var(--background-minus-minus);
|
||||
|
||||
/** Header
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--header-color: var(--title-color);
|
||||
--header-background: var(--background);
|
||||
--header-button-color: var(--highlight-color);
|
||||
--header-disabled-button-color: var(--color-theta);
|
||||
--header-action-button-color: var(--title-color);
|
||||
}
|
||||
|
||||
.theme-media {
|
||||
|
||||
/** Highlight Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--highlight-color: var(--color-blue);
|
||||
|
||||
/** Background
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--background: var(--color-alpha);
|
||||
--background-plus: var(--color-gamma);
|
||||
--background-minus: #2B2B2B;
|
||||
--background-minus-minus: #1a1a1a;
|
||||
|
||||
/** Text Color
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--text-color: var(--color-beta);
|
||||
|
||||
/** Button
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--button-background: var(--background-plus);
|
||||
|
||||
/** Header
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--header-background: var(--background);
|
||||
--header-icon-color: var(--text-color);
|
||||
--header-button-color: var(--highlight-color);
|
||||
|
||||
/** Borders
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--border-color: var(--color-gamma);
|
||||
|
||||
/** Inputs
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--input-background: var(--background-plus);
|
||||
|
||||
/** Text Input
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--text-input-background: var(--background-minus);
|
||||
|
||||
/** Switch
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--switch-head-border-color: var(--background-minus-minus);
|
||||
--switch-background: var(--background-minus-minus);
|
||||
|
||||
/** Checkbox
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--checkbox-border-color: var(--background-minus-minus);
|
||||
|
||||
/** Buttons
|
||||
---------------------------------------------------------*/
|
||||
|
||||
--button-box-shadow: none;
|
||||
--button-box-shadow-active: none;
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
(function(define){'use strict';define(function(require,exports,module){
|
||||
/*jshint esnext:true*/
|
||||
|
||||
/**
|
||||
* Extend from the `HTMLElement` prototype
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var proto = Object.create(HTMLElement.prototype);
|
||||
|
||||
proto.createdCallback = function() {
|
||||
this.createShadowRoot().innerHTML = template;
|
||||
|
||||
this.els = {
|
||||
themes: this.shadowRoot.querySelector('.themes'),
|
||||
rtl: this.shadowRoot.querySelector('.toggle-rtl')
|
||||
};
|
||||
|
||||
this.els.rtl.addEventListener('click', this.onRtlClick.bind(this));
|
||||
this.els.themes.addEventListener('click', this.onThemeClick.bind(this));
|
||||
this.styleHack();
|
||||
this.set(localStorage.theme || 'settings');
|
||||
};
|
||||
|
||||
proto.styleHack = function() {
|
||||
var style = this.shadowRoot.querySelector('style');
|
||||
style.setAttribute('scoped', '');
|
||||
this.appendChild(style.cloneNode(true));
|
||||
};
|
||||
|
||||
proto.onThemeClick = function(e) {
|
||||
var theme = e.target.value;
|
||||
if (theme) { this.set(theme); }
|
||||
};
|
||||
|
||||
proto.onRtlClick = function() {
|
||||
document.dir = this.els.rtl.checked ? 'rtl' : 'ltr';
|
||||
};
|
||||
|
||||
proto.set = function(theme) {
|
||||
var radio = this.shadowRoot.querySelector('[value="' + theme + '"]');
|
||||
document.body.classList.remove('theme-' + this.theme);
|
||||
document.body.classList.add('theme-' + theme);
|
||||
radio.checked = true;
|
||||
this.theme = theme;
|
||||
localStorage.theme = theme;
|
||||
};
|
||||
|
||||
var template = `
|
||||
<style>
|
||||
|
||||
* { margin: 0; padding: 0; }
|
||||
|
||||
gaia-theme-selector {
|
||||
position: fixed;
|
||||
top: 0; left: 0;
|
||||
z-index: 101;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
background: rgba(255,255,255,0.8);
|
||||
color: #000;
|
||||
font-size: 9px;
|
||||
text-align: center;
|
||||
box-shadow: 0 1px 1px rgba(0,0,0,0.1);
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
form label {
|
||||
-moz-margin-start: 9px;
|
||||
}
|
||||
|
||||
form input {
|
||||
-moz-margin-end: 6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.rtl {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<form>
|
||||
<label class="rtl"><input type="checkbox" class="toggle-rtl" />RTL</label>
|
||||
<span class="themes">
|
||||
<label><input type="radio" name="theme" value="productivity"/>Prod</label>
|
||||
<label><input type="radio" name="theme" value="communications"/>Comms</label>
|
||||
<label><input type="radio" name="theme" value="media"/>Media</label>
|
||||
<label><input type="radio" name="theme" value="settings"/>Settings</label>
|
||||
</span>
|
||||
</form>`;
|
||||
|
||||
document.registerElement('gaia-theme-selector', { prototype: proto });
|
||||
|
||||
});})((function(n,w){'use strict';return typeof define=='function'&&define.amd?
|
||||
define:typeof module=='object'?function(c){c(require,exports,module);}:
|
||||
function(c){var m={exports:{}},r=function(n){return w[n];};
|
||||
w[n]=c(r,m.exports,m)||m.exports;};})('gaia-theme-selector',this));
|
||||
27
gaia/distros/spark/apps/customizer/components/gaia-toolbar/bower.json
Executable file
27
gaia/distros/spark/apps/customizer/components/gaia-toolbar/bower.json
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "gaia-toolbar",
|
||||
"version": "0.0.0",
|
||||
"authors": [
|
||||
"Wilson Page <wilsonpage@me.com>"
|
||||
],
|
||||
"main": "script.js",
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"examples",
|
||||
"test",
|
||||
"tests",
|
||||
"README.md"
|
||||
],
|
||||
"devDependencies": {
|
||||
"gaia-icons": "gaia-components/gaia-icons#~0.6.1",
|
||||
"gaia-theme": "gaia-components/gaia-theme#~0.5.0",
|
||||
"base": "gaia-components/base"
|
||||
},
|
||||
"dependencies": {
|
||||
"gaia-dialog": "gaia-components/gaia-dialog",
|
||||
"gaia-component": "gaia-components/gaia-component#~0.2.0"
|
||||
}
|
||||
}
|
||||
307
gaia/distros/spark/apps/customizer/components/gaia-toolbar/gaia-toolbar.js
Executable file
307
gaia/distros/spark/apps/customizer/components/gaia-toolbar/gaia-toolbar.js
Executable file
|
|
@ -0,0 +1,307 @@
|
|||
;(function(define){define(function(require,exports,module){
|
||||
/*jshint esnext:true*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
||||
var GaiaDialogMenu = require('gaia-dialog-menu');
|
||||
|
||||
/**
|
||||
* Locals
|
||||
*/
|
||||
|
||||
var forEach = [].forEach;
|
||||
var slice = [].slice;
|
||||
|
||||
/**
|
||||
* Extend from the `HTMLElement` prototype
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var proto = Object.create(HTMLElement.prototype);
|
||||
|
||||
proto.createdCallback = function() {
|
||||
this.createShadowRoot().innerHTML = template;
|
||||
|
||||
this.els = {
|
||||
inner: this.shadowRoot.querySelector('.inner'),
|
||||
moreButton: this.shadowRoot.querySelector('.more-button')
|
||||
};
|
||||
|
||||
this.els.moreButton.addEventListener('click', this.openOverflow.bind(this));
|
||||
|
||||
var self = this;
|
||||
this.reflow_raf = rafWrap(this.reflow, this);
|
||||
addEventListener('resize', this.reflow_raf);
|
||||
this.shadowStyleHack();
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
addEventListener('load', this.reflow.bind(this));
|
||||
return;
|
||||
}
|
||||
|
||||
this.style.visibility = 'hidden';
|
||||
self.reflow_raf();
|
||||
};
|
||||
|
||||
proto.attachedCallback = function() {
|
||||
this.style.visibility = 'hidden';
|
||||
this.reflow_raf();
|
||||
};
|
||||
|
||||
proto.reflow = function() {
|
||||
this.release();
|
||||
var overflow = this.getOverflowData();
|
||||
if (overflow.overflowed) { this.onOverflowed(overflow); }
|
||||
this.style.visibility = '';
|
||||
};
|
||||
|
||||
proto.getOverflowData = function() {
|
||||
var space = this.els.inner.clientWidth;
|
||||
var child = this.children[0];
|
||||
var overflowed = false;
|
||||
var willFit = 0;
|
||||
var total = 0;
|
||||
var overflow;
|
||||
var width;
|
||||
|
||||
while (child) {
|
||||
width = child.clientWidth;
|
||||
overflow = width + total - space;
|
||||
|
||||
if (overflow > 3) {
|
||||
overflowed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
willFit++;
|
||||
total += width;
|
||||
child = child.nextElementSibling;
|
||||
}
|
||||
|
||||
return {
|
||||
willFit: willFit,
|
||||
remaining: space - total,
|
||||
overflowed: overflowed
|
||||
};
|
||||
};
|
||||
|
||||
proto.onOverflowed = function(overflow) {
|
||||
var items = slice.call(this.children, 0, -1);
|
||||
var minMoreButtonWidth = 70;
|
||||
var extra = overflow.remaining < minMoreButtonWidth ? 1 : 0;
|
||||
var numToHide = items.length - overflow.willFit + extra;
|
||||
|
||||
this.hiddenChildren = slice.call(items, 0 - numToHide);
|
||||
this.hiddenChildren.forEach(function(el) { el.classList.add('overflowing'); });
|
||||
this.els.inner.classList.add('overflowed');
|
||||
};
|
||||
|
||||
proto.release = function() {
|
||||
if (!this.hiddenChildren) { return; }
|
||||
this.els.inner.classList.remove('overflowed');
|
||||
forEach.call(this.hiddenChildren, function(el) {
|
||||
el.classList.remove('overflowing');
|
||||
});
|
||||
};
|
||||
|
||||
proto.getTotalItemLength = function() {
|
||||
return [].reduce.call(this.children, function(total, el) {
|
||||
return total + el.clientWidth;
|
||||
}, 0);
|
||||
};
|
||||
|
||||
proto.shadowStyleHack = function() {
|
||||
var style = this.shadowRoot.querySelector('style').cloneNode(true);
|
||||
this.classList.add('-content', '-host');
|
||||
style.setAttribute('scoped', '');
|
||||
this.appendChild(style);
|
||||
};
|
||||
|
||||
proto.openOverflow = function(e) {
|
||||
this.dialog = new GaiaDialogMenu();
|
||||
|
||||
this.hiddenChildren.forEach(function(el) {
|
||||
this.dialog.appendChild(el);
|
||||
el.classList.remove('overflowing');
|
||||
}, this);
|
||||
|
||||
this.appendChild(this.dialog);
|
||||
this.dialog.addEventListener('click', this.dialog.close.bind(this.dialog));
|
||||
this.dialog.addEventListener('closed', this.onDialogClosed.bind(this));
|
||||
this.dialog.open(e);
|
||||
};
|
||||
|
||||
proto.onDialogClosed = function() {
|
||||
this.dialog.remove();
|
||||
this.dialog = null;
|
||||
|
||||
this.hiddenChildren.forEach(function(el) {
|
||||
el.classList.add('overflowing');
|
||||
this.insertBefore(el, this.lastChild);
|
||||
}, this);
|
||||
|
||||
};
|
||||
|
||||
var template = `
|
||||
<style>
|
||||
|
||||
/** Reset
|
||||
---------------------------------------------------------*/
|
||||
|
||||
::-moz-focus-inner { border: 0; }
|
||||
|
||||
/** Host
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.-host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/** Inner
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.inner {
|
||||
display: flex;
|
||||
height: 45px;
|
||||
overflow: hidden;
|
||||
|
||||
border-top: 1px solid;
|
||||
border-color:
|
||||
var(--border-color,
|
||||
var(--background-plus));
|
||||
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
/** Direct Children
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.-content > *,
|
||||
.more-button {
|
||||
box-sizing: border-box;
|
||||
flex: 1 0 0;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0 6px;
|
||||
border: 0;
|
||||
font-size: 17px;
|
||||
line-height: 45px;
|
||||
font-style: italic;
|
||||
font-weight: lighter;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
transition: color 200ms 300ms;
|
||||
|
||||
color:
|
||||
var(--text-color, inherit);
|
||||
}
|
||||
|
||||
/**
|
||||
* :active
|
||||
*/
|
||||
|
||||
.more-button :active,
|
||||
.-content > :active {
|
||||
transition: none;
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
/**
|
||||
* .overflowing
|
||||
*/
|
||||
|
||||
.-content > .overflowing {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* [disabled]
|
||||
*/
|
||||
|
||||
.-content > [disabled] {
|
||||
pointer-events: none;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.-content > [data-icon] {
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
/** Style
|
||||
---------------------------------------------------------*/
|
||||
|
||||
style {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/** More Button
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.more-button {
|
||||
display: none;
|
||||
flex: 0.7;
|
||||
}
|
||||
|
||||
/** More Button Icon
|
||||
---------------------------------------------------------*/
|
||||
|
||||
.more-button:before {
|
||||
font-family: 'gaia-icons';
|
||||
font-weight: 500;
|
||||
content: 'more';
|
||||
text-rendering: optimizeLegibility;
|
||||
font-style: normal;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
/**
|
||||
* .overflowed
|
||||
*/
|
||||
|
||||
.overflowed .more-button {
|
||||
display: block;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div class="inner">
|
||||
<content></content>
|
||||
<button class="more-button"></button>
|
||||
</div>`;
|
||||
|
||||
|
||||
function rafWrap(fn, ctx) {
|
||||
var raf = requestAnimationFrame;
|
||||
var frame;
|
||||
|
||||
return function() {
|
||||
if (frame) { return; }
|
||||
var args = arguments;
|
||||
|
||||
frame = raf(function() {
|
||||
raf(function() {
|
||||
frame = null;
|
||||
fn.apply(ctx, arguments);
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// Register and expose the constructor
|
||||
try {
|
||||
module.exports = document.registerElement('gaia-toolbar', { prototype: proto });
|
||||
module.exports.proto = proto;
|
||||
} catch (e) {
|
||||
if (e.name !== 'NotSupportedError') {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
});})(typeof define=='function'&&define.amd?define
|
||||
:(function(n,w){'use strict';return typeof module=='object'?function(c){
|
||||
c(require,exports,module);}:function(c){var m={exports:{}};c(function(n){
|
||||
return w[n];},m.exports,m);w[n]=m.exports;};})('gaia-toolbar',this));
|
||||
74
gaia/distros/spark/apps/customizer/components/gaia-toolbar/index.html
Executable file
74
gaia/distros/spark/apps/customizer/components/gaia-toolbar/index.html
Executable file
|
|
@ -0,0 +1,74 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title><gaia-toolbar></title>
|
||||
<meta name="description" content="gaia-toolbar example" />
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/base/base.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-theme/gaia-theme.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-icons/style.css">
|
||||
<link rel="stylesheet" type="text/css" href="bower_components/gaia-fonts/style.css">
|
||||
<script src="bower_components/gaia-theme/lib/gaia-theme-selector.js"></script>
|
||||
<script src="bower_components/gaia-component/gaia-component.js"></script>
|
||||
<script src="bower_components/gaia-dialog/gaia-dialog.js"></script>
|
||||
<script src="bower_components/gaia-icons/gaia-icons.js"></script>
|
||||
<script src="gaia-toolbar.js"></script>
|
||||
<style type="text/css">
|
||||
|
||||
body {
|
||||
padding: 16px;
|
||||
padding-top: 48px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body role="application">
|
||||
<gaia-theme-selector></gaia-theme-selector>
|
||||
<h1 class="large l-align-center l-mb-mega"><gaia-toolbar></h1>
|
||||
<button id="append">Add one</button>
|
||||
<section id="section">
|
||||
<gaia-toolbar class="l-mb-mega" selected="2">
|
||||
<button data-icon="recent-calls"></button>
|
||||
<button data-icon="user"></button>
|
||||
<button data-icon="dialpad"></button>
|
||||
<button data-icon="sync">sync</button>
|
||||
<button data-icon="camera">camera</button>
|
||||
</gaia-toolbar>
|
||||
|
||||
<gaia-toolbar class="l-mb-mega" selected="2">
|
||||
<button data-icon="recent-calls"></button>
|
||||
<button data-icon="user"></button>
|
||||
</gaia-toolbar>
|
||||
|
||||
<gaia-toolbar selected="2">
|
||||
<button>Phone</button>
|
||||
<button>Contact</button>
|
||||
<button>Dialer</button>
|
||||
<button>Refresh</button>
|
||||
<button>Add to homescreen</button>
|
||||
</gaia-toolbar>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
/*jshint esnext:true*/
|
||||
|
||||
append.onclick = add;
|
||||
|
||||
function add() {
|
||||
var div = document.createElement('div');
|
||||
|
||||
div.innerHTML = `
|
||||
<gaia-toolbar selected="2">
|
||||
<div>Phone</div>
|
||||
<div>Contact</div>
|
||||
<div>Dialer</div>
|
||||
<div>Refresh</div>
|
||||
<div>Add to homescreen</div>
|
||||
</gaia-toolbar>`;
|
||||
|
||||
section.appendChild(div.firstElementChild);
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
22
gaia/distros/spark/apps/customizer/components/gesture/bower.json
Executable file
22
gaia/distros/spark/apps/customizer/components/gesture/bower.json
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "gesture",
|
||||
"version": "0.0.3",
|
||||
"homepage": "https://github.com/fxos/gesture",
|
||||
"authors": [
|
||||
"FxOS Developers <dev-gaia@lists.mozilla.com>"
|
||||
],
|
||||
"main": "gesture.js",
|
||||
"license": "Apache",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"example",
|
||||
"node_modules",
|
||||
"test",
|
||||
"bower.json",
|
||||
"LICENSE",
|
||||
"package.json",
|
||||
"README.md"
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {}
|
||||
}
|
||||
305
gaia/distros/spark/apps/customizer/components/gesture/gesture.js
Executable file
305
gaia/distros/spark/apps/customizer/components/gesture/gesture.js
Executable file
|
|
@ -0,0 +1,305 @@
|
|||
/*jshint esnext:true*/
|
||||
;(function (g,n,f) {
|
||||
'use strict';
|
||||
if (typeof define === 'function' && define.amd){ define(f); }
|
||||
else { g[n]=f(); }
|
||||
}(this, 'Gesture', function() {
|
||||
|
||||
var Gesture = {
|
||||
DEBUG: false
|
||||
};
|
||||
|
||||
function debug(...args) {
|
||||
if (Gesture.DEBUG) {
|
||||
console.log('[Gesture]', ...args);
|
||||
}
|
||||
}
|
||||
|
||||
// Return a promise that will resolve when the specified gesture is
|
||||
// detected. Note that the gesture is detected only once. You must call
|
||||
// this function again if you want to detect it again. The returned
|
||||
// promise will have a cancel() method on it. When called, gesture
|
||||
// detection stops and the promise is rejected.
|
||||
function detect(gestureSpec) {
|
||||
|
||||
// These are the states of the gesture detector
|
||||
const NOT_STARTED = 0; // We have not detected the gesture start yet
|
||||
const STARTED = 1; // Gesture has begun but has not finished
|
||||
const FINISHED = 2; // Gesture finished or was cancelled
|
||||
|
||||
var state; // Current gesture detection state
|
||||
var startEvent; // The touchstart event that started the gesture
|
||||
|
||||
var promise; // The promise we return;
|
||||
var promiseResolver; // The resolve function for the promise
|
||||
var promiseRejector; // The reject function for the promise
|
||||
|
||||
/*
|
||||
* Functions init(), start(), fail(), succeed(), cancel() and cleanup()
|
||||
* below handle state transitions between NOT_STARTED, STARTED and
|
||||
* FINISHED and also register and unregister event handlers, and
|
||||
* resolve or reject the promise.
|
||||
*/
|
||||
|
||||
// Call this function once to start listening.
|
||||
function init() {
|
||||
debug('Initializing');
|
||||
// Set our initial state
|
||||
state = NOT_STARTED;
|
||||
|
||||
// Register a capturing event listener for touchstart events.
|
||||
// This is the only event handler that is registered when
|
||||
// we are in the NOT_STARTED state.
|
||||
window.addEventListener('touchstart', touchstart, true);
|
||||
}
|
||||
|
||||
// Called when we detect that the gesture has started because
|
||||
// the right number of fingers are in the starting zone.
|
||||
// It registers handlers for touchmove and touchend and sets
|
||||
// the state to STARTED.
|
||||
function start() {
|
||||
debug('Start of gesture detected');
|
||||
state = STARTED;
|
||||
window.addEventListener('touchmove', touchmove, true);
|
||||
window.addEventListener('touchend', touchend, true);
|
||||
}
|
||||
|
||||
// This is called when the gesture fails (an additional finger
|
||||
// is added, for example, or the time limit is exceeded). It
|
||||
// unregisters the touchmove and touchend handlers and resets
|
||||
// the state to NOT_STARTED where it continues listening for new
|
||||
// touches.
|
||||
function fail(why) {
|
||||
debug('Gesture did not complete:', why);
|
||||
state = NOT_STARTED;
|
||||
window.removeEventListener('touchmove', touchmove, true);
|
||||
window.removeEventListener('touchend', touchend, true);
|
||||
}
|
||||
|
||||
// This is called when the gesture is successfully detected.
|
||||
// It resolves the promise and cleans up any listeners.
|
||||
// The data argument contains information about the gesture that
|
||||
// is used to resolve the promise.
|
||||
function succeed(data) {
|
||||
debug('Gesture completed:', data);
|
||||
cleanup();
|
||||
promiseResolver(data);
|
||||
}
|
||||
|
||||
// This is called if the caller cancels gesture detection.
|
||||
// It rejects the promise and cleans up any listeners
|
||||
function cancel() {
|
||||
cleanup();
|
||||
promiseRejector('cancelled');
|
||||
}
|
||||
|
||||
// Unregister all currently registered event listeners
|
||||
function cleanup() {
|
||||
state = FINISHED;
|
||||
window.removeEventListener('touchstart', touchstart, true);
|
||||
window.removeEventListener('touchmove', touchmove, true);
|
||||
window.removeEventListener('touchend', touchend, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* The touchstart(), touchmove(), touchend() functions below handle
|
||||
* touch events and call the state transition functions above as
|
||||
* appopriate.
|
||||
*/
|
||||
|
||||
// This is called whenever the user touches the screen.
|
||||
// But it doesn't do anything unless this event looks like the
|
||||
// start of a gesture.
|
||||
function touchstart(e) {
|
||||
debug('touch start', e.touches.length);
|
||||
// If a gesture has already started and another finger
|
||||
// goes down, then this is not the gesture we thought it was,
|
||||
// so we cancel it and go back to the initial state
|
||||
if (state === STARTED) {
|
||||
fail('already started');
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, check if the current touches meet the gesture
|
||||
// start condition, and switch to STARTED if so
|
||||
if (isGestureStart(e)) {
|
||||
startEvent = e;
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
function touchmove(e) {
|
||||
debug(e.type, e.touches.length,
|
||||
e.changedTouches[0].clientX, e.changedTouches[0].clientY);
|
||||
var gestureData;
|
||||
try {
|
||||
gestureData = isGestureEnd(startEvent, e);
|
||||
}
|
||||
catch(ex) {
|
||||
// If isGestureEnd throws an exception, the gesture fails.
|
||||
fail(ex.message);
|
||||
return;
|
||||
}
|
||||
|
||||
// If isGestureEnd returns a truthy value, the gesture succeeds.
|
||||
if (gestureData) {
|
||||
succeed(gestureData);
|
||||
}
|
||||
|
||||
// Otherwise, we just keep listening for more move events
|
||||
}
|
||||
|
||||
// Handle touchend events in the same way that we handle touchmove events
|
||||
function touchend(e) {
|
||||
touchmove(e);
|
||||
}
|
||||
|
||||
// Return true if this event marks the start of the specified gesture
|
||||
function isGestureStart(event) {
|
||||
return Detectors[gestureSpec.type].isGestureStart(gestureSpec,
|
||||
event);
|
||||
}
|
||||
|
||||
function isGestureEnd(startEvent, endEvent) {
|
||||
return Detectors[gestureSpec.type].isGestureEnd(gestureSpec,
|
||||
startEvent,
|
||||
endEvent);
|
||||
}
|
||||
|
||||
// Make sure we know how to detect the specified gesture
|
||||
if (!Detectors[gestureSpec.type]) {
|
||||
return Promise.reject('Unsupported gesture: ' + gestureSpec.type);
|
||||
}
|
||||
|
||||
// If we do, then create the promise that we will return
|
||||
// and start detecting gestures when the promise is ready
|
||||
|
||||
promise = new Promise(function(resolve, reject) {
|
||||
// Store resolve and reject in the outer scope where we can use them
|
||||
promiseResolver = resolve;
|
||||
promiseRejector = reject;
|
||||
init();
|
||||
});
|
||||
|
||||
// Add a method to the returned promise that allows the client to
|
||||
// stop listening for the gesture
|
||||
promise.cancel = cancel;
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
|
||||
// A utility function to determine whether the Touch t is in the region r.
|
||||
// Regions are specified in units relative to the window size.
|
||||
// (0,0) is the top-left corner of the window and (1,1) is the bottom right.
|
||||
function touchInRegion(t, r) {
|
||||
var x = t.clientX / window.innerWidth;
|
||||
var y = t.clientY / window.innerHeight;
|
||||
return x >= r.x0 && x <= r.x1 && y >= r.y0 && y <= r.y1;
|
||||
}
|
||||
|
||||
var Detectors = {
|
||||
swipe: {
|
||||
isGestureStart: function isSwipeStart(spec, event) {
|
||||
var touches = event.touches;
|
||||
|
||||
// If the number of touches is not correct, this is not a gesture start
|
||||
if (touches.length !== spec.numFingers) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If any of the touches is in the wrong place,
|
||||
// this is not a gesture start
|
||||
if (spec.startRegion) {
|
||||
for(var i = 0; i < touches.length; i++) {
|
||||
var t = touches[i];
|
||||
if (!touchInRegion(t, spec.startRegion)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The gesture has started
|
||||
return true;
|
||||
},
|
||||
|
||||
//
|
||||
// This function tests whether the endEvent marks the end of the specified
|
||||
// gesture that started with the startEvent. There are three possible
|
||||
// outcomes:
|
||||
//
|
||||
// - if this is the end of the gesture, this function returns an object
|
||||
// that holds information about the gesture, and that object will be
|
||||
// used to resolve the promise.
|
||||
//
|
||||
// - if endEvent is not the end of the gesture, this function returns
|
||||
// false
|
||||
//
|
||||
// - if endEvent is indicates that the gesture has failed (for example
|
||||
// if the user's fingers are moving in the wrong direction) then this
|
||||
// function should throw an error which will cause the gesture detector
|
||||
// to reset to its NOT_STARTED state
|
||||
//
|
||||
isGestureEnd: function isSwipeEnd(spec, startEvent, endEvent) {
|
||||
var dt = endEvent.timeStamp - startEvent.timeStamp;
|
||||
var startTouches = startEvent.touches;
|
||||
var endTouches = endEvent.touches;
|
||||
|
||||
// The gesture fails if:
|
||||
// 1) it has taken too long
|
||||
// 2) a finger is lifted before success
|
||||
// 3) there are the wrong number of touches (that should not happen).
|
||||
if (spec.maxTime && dt > spec.maxTime) {
|
||||
throw new Error('timeout:' + dt);
|
||||
}
|
||||
if (endEvent.type === 'touchend') {
|
||||
throw new Error('touchend');
|
||||
}
|
||||
if (endTouches.length !== startTouches.length) {
|
||||
// This should not happen, but it does happen for unknown reasons
|
||||
// See bug 1139575. If we throw an error here it aborts the gesture
|
||||
// and makes it hard for the user to swipe on some devices.
|
||||
// So instead we just return false and act like it never happened
|
||||
// throw new Error('wrong number of touches');
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = {
|
||||
dt: dt,
|
||||
fingers: []
|
||||
};
|
||||
|
||||
for(var i = 0; i < startTouches.length; i++) {
|
||||
var st = startTouches[i];
|
||||
var et = endTouches.identifiedTouch(st.identifier);
|
||||
if (!et) { // this should not happen
|
||||
throw new Error('mismatch');
|
||||
}
|
||||
|
||||
// If the gesture spec specifies and endRegion and this touch is
|
||||
// not in it, then this is not the end of the gesture
|
||||
// (For some types of gestures it might be better to specify
|
||||
// a minimum and maximum required distance in each direction
|
||||
// instead of a end region.)
|
||||
if (spec.endRegion && !touchInRegion(et, spec.endRegion)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This touch passes the test, so record it in the data
|
||||
data.fingers.push({
|
||||
x0: st.clientX,
|
||||
y0: st.clientY,
|
||||
x1: et.clientX,
|
||||
y1: et.clientY
|
||||
});
|
||||
}
|
||||
|
||||
// If all the touches were okay, then we've found the end of the gesture
|
||||
return data;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Gesture.detect = detect;
|
||||
return Gesture;
|
||||
}));
|
||||
9
gaia/distros/spark/apps/customizer/components/js-beautify/LICENSE
Executable file
9
gaia/distros/spark/apps/customizer/components/js-beautify/LICENSE
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2013 Einar Lielmanis and contributors.
|
||||
|
||||
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.
|
||||
74
gaia/distros/spark/apps/customizer/components/js-beautify/Makefile
Executable file
74
gaia/distros/spark/apps/customizer/components/js-beautify/Makefile
Executable file
|
|
@ -0,0 +1,74 @@
|
|||
|
||||
define AVAILABLE_ACTIONS
|
||||
|
||||
build: do static checking and build of js
|
||||
buildp: do static checking and build of python
|
||||
buildj: do static checking and build of javascript
|
||||
test: test both implementations, js and python
|
||||
testp: test python implementation
|
||||
testj: test javascript implementation
|
||||
|
||||
endef
|
||||
export AVAILABLE_ACTIONS
|
||||
|
||||
|
||||
.SILENT:
|
||||
all: build test status
|
||||
|
||||
help:
|
||||
echo "$$AVAILABLE_ACTIONS"
|
||||
|
||||
build: buildj buildp
|
||||
|
||||
buildj:
|
||||
echo Building javascript... ;\
|
||||
npm install ;\
|
||||
|
||||
buildp:
|
||||
echo Building python... ;\
|
||||
pip install -e ./python
|
||||
|
||||
testp:
|
||||
echo Testing python implementation...
|
||||
node test/generate-tests.js || exit 1;\
|
||||
cd python ;\
|
||||
python --version ;\
|
||||
./jsbeautifier/tests/shell-smoke-test.sh
|
||||
|
||||
testj:
|
||||
echo Testing javascript implementation...
|
||||
node test/generate-tests.js || exit 1;\
|
||||
node --version; \
|
||||
npm test
|
||||
|
||||
|
||||
edit:
|
||||
vim \
|
||||
js/lib/beautify.js python/jsbeautifier/__init__.py \
|
||||
js/test/beautify-tests.js python/jsbeautifier/tests/testjsbeautifier.py
|
||||
|
||||
gedit:
|
||||
gvim \
|
||||
js/lib/beautify.js \
|
||||
js/test/beautify-tests.js \
|
||||
python/jsbeautifier/__init__.py \
|
||||
python/jsbeautifier/tests/testjsbeautifier.py &
|
||||
|
||||
tests: testj testp
|
||||
|
||||
test: testj testp
|
||||
|
||||
status:
|
||||
test/git-status-clear.sh || exit 1
|
||||
|
||||
|
||||
gh:
|
||||
git push origin master &&\
|
||||
cd gh-pages &&\
|
||||
git fetch &&\
|
||||
git checkout gh-pages &&\
|
||||
git reset --hard origin/gh-pages &&\
|
||||
git merge origin/master &&\
|
||||
git push origin gh-pages
|
||||
|
||||
.PHONY: testp testj all edit tests test
|
||||
11
gaia/distros/spark/apps/customizer/components/js-beautify/bower.json
Executable file
11
gaia/distros/spark/apps/customizer/components/js-beautify/bower.json
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "js-beautify",
|
||||
"main": [
|
||||
"./js/lib/beautify.js",
|
||||
"./js/lib/beautify-css.js",
|
||||
"./js/lib/beautify-html.js"
|
||||
],
|
||||
"ignore": [
|
||||
"**/.*"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
#!/bin/bash
|
||||
# based on https://gist.github.com/joelittlejohn/5937573
|
||||
#
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Usage: ./generate-changelog.sh user/repo"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IFS=$'\n'
|
||||
echo "# Changelog" > CHANGELOG.md
|
||||
|
||||
for m in $(curl -s "https://api.github.com/repos/$1/milestones?state=closed" | jq -c '.[] | [.title, .number, .description]' | sort -r); do
|
||||
mid=$(echo $m | sed 's/\[".*",\(.*\),".*"\]/\1/')
|
||||
title=$(echo $m | sed 's/\["\(.*\)",.*,".*"\]/\1/')
|
||||
|
||||
echo "Processing milestone: $title..."
|
||||
echo $m | sed 's/\["\(.*\)",.*\]/## \1/' >> CHANGELOG.md
|
||||
echo "" >> CHANGELOG.md
|
||||
echo '### Description' >> CHANGELOG.md
|
||||
echo $m | sed 's/\[".*",.*,"\(.*\)"\]/\1/' | sed -e 's/\\"/"/g' | sed -e 's/\\r\\n/\\n/g' | sed -e 's/\\n/\'$'\n/g' >> CHANGELOG.md
|
||||
echo "" >> CHANGELOG.md
|
||||
echo '### Closed Issues' >> CHANGELOG.md
|
||||
for i in $(curl -s "https://api.github.com/repos/$1/issues?milestone=$mid&state=closed" | jq -c '.[] | [.html_url, .number, .title]'); do
|
||||
echo $i | sed 's/\["\(.*\)",\(.*\),\"\(.*\)\"\]/* \3 ([#\2](\1))/' | sed 's/\\"/"/g' >> CHANGELOG.md
|
||||
done
|
||||
echo "" >> CHANGELOG.md
|
||||
echo "" >> CHANGELOG.md
|
||||
done
|
||||
544
gaia/distros/spark/apps/customizer/components/js-beautify/index.html
Executable file
544
gaia/distros/spark/apps/customizer/components/js-beautify/index.html
Executable file
|
|
@ -0,0 +1,544 @@
|
|||
<html>
|
||||
<!--
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2013 Einar Lielmanis and contributors.
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Online JavaScript beautifier</title>
|
||||
<link rel="icon" href="web/favicon.png" type="image/png">
|
||||
<link rel="stylesheet" href="web/third-party/codemirror/lib/codemirror.css">
|
||||
|
||||
<script src="web/third-party/codemirror/lib/codemirror.js"></script>
|
||||
<script src="web/third-party/codemirror/mode/javascript/javascript.js"></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
background: #eee;
|
||||
color: #333;
|
||||
}
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
a.self {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: #444;
|
||||
border-bottom: 1px solid #aaa
|
||||
}
|
||||
p, select, label, .blurb, a.turn-off-codemirror {
|
||||
font:13px/1.231 arial, sans-serif;
|
||||
*font-size:small;
|
||||
}
|
||||
a.turn-off-codemirror {
|
||||
margin-left: 25px;
|
||||
}
|
||||
button.submit {
|
||||
width: 100%;
|
||||
padding: 10px 0;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
}
|
||||
button.submit em {
|
||||
font-size: 11px;
|
||||
font-style: normal;
|
||||
color: #999;
|
||||
}
|
||||
label {
|
||||
cursor: pointer;
|
||||
}
|
||||
select {
|
||||
width: 220px;
|
||||
}
|
||||
table#options {
|
||||
float: right;
|
||||
}
|
||||
table#options td {
|
||||
vertical-align: top;
|
||||
padding-left: 10px;
|
||||
}
|
||||
#about {
|
||||
float: left;
|
||||
}
|
||||
#about p {
|
||||
margin: 0 6px 6px 0;
|
||||
}
|
||||
li {
|
||||
line-height: 150%;
|
||||
}
|
||||
li.writeme {
|
||||
padding-top: 8px;
|
||||
}
|
||||
#testresults {
|
||||
display: none;
|
||||
font-family: monaco, "lucida console", "courier new", monospace;
|
||||
}
|
||||
.CodeMirror {
|
||||
border: 1px solid #ccc;
|
||||
height: 450px;
|
||||
font-size: 90%;
|
||||
margin-bottom: 6px;
|
||||
background: white;
|
||||
}
|
||||
p {
|
||||
margin-left: 40px;
|
||||
margin-right: 40px;
|
||||
}
|
||||
a {
|
||||
white-space: nowrap;
|
||||
color: #36d;
|
||||
}
|
||||
.contributor-sep {
|
||||
border-top: 1px solid #ccc;
|
||||
padding-top: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="web/third-party/jquery/jquery.js"></script>
|
||||
<script src="web/third-party/jquery/jquery.cookie.js"></script>
|
||||
|
||||
<script src="js/lib/beautify.js"></script>
|
||||
<script src="js/lib/beautify-css.js"></script>
|
||||
<script src="js/lib/beautify-html.js"></script>
|
||||
<script src="js/test/sanitytest.js"></script>
|
||||
<script src="js/test/beautify-javascript-tests.js"></script>
|
||||
<script src="js/test/beautify-css-tests.js"></script>
|
||||
<script src="js/test/beautify-html-tests.js"></script>
|
||||
<script src="js/lib/unpackers/javascriptobfuscator_unpacker.js"></script>
|
||||
<script src="js/lib/unpackers/urlencode_unpacker.js"></script>
|
||||
<script src="js/lib/unpackers/p_a_c_k_e_r_unpacker.js"></script>
|
||||
<script src="js/lib/unpackers/myobfuscate_unpacker.js"></script>
|
||||
|
||||
<script>
|
||||
var the = {
|
||||
use_codemirror: (!window.location.href.match(/without-codemirror/)),
|
||||
beautify_in_progress: false,
|
||||
editor: null // codemirror editor
|
||||
};
|
||||
|
||||
function run_tests() {
|
||||
var st = new SanityTest();
|
||||
run_javascript_tests(st, Urlencoded, js_beautify, html_beautify, css_beautify);
|
||||
run_css_tests(st, Urlencoded, js_beautify, html_beautify, css_beautify);
|
||||
run_html_tests(st, Urlencoded, js_beautify, html_beautify, css_beautify);
|
||||
JavascriptObfuscator.run_tests(st);
|
||||
P_A_C_K_E_R.run_tests(st);
|
||||
Urlencoded.run_tests(st);
|
||||
MyObfuscate.run_tests(st);
|
||||
var results = st.results_raw()
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/ /g, ' ')
|
||||
.replace(/\r/g, '·')
|
||||
.replace(/\n/g, '<br>');
|
||||
$('#testresults').html(results).show();
|
||||
}
|
||||
|
||||
|
||||
function any(a, b) {
|
||||
return a || b;
|
||||
}
|
||||
|
||||
function read_settings_from_cookie() {
|
||||
$('#tabsize').val(any($.cookie('tabsize'), '4'));
|
||||
$('#brace-style').val(any($.cookie('brace-style'), 'collapse'));
|
||||
$('#detect-packers').prop('checked', $.cookie('detect-packers') !== 'off');
|
||||
$('#max-preserve-newlines').val(any($.cookie('max-preserve-newlines'), '5'));
|
||||
$('#keep-array-indentation').prop('checked', $.cookie('keep-array-indentation') === 'on');
|
||||
$('#break-chained-methods').prop('checked', $.cookie('break-chained-methods') === 'on');
|
||||
$('#indent-scripts').val(any($.cookie('indent-scripts'), 'normal'));
|
||||
$('#space-before-conditional').prop('checked', $.cookie('space-before-conditional') !== 'off');
|
||||
$('#wrap-line-length').val(any($.cookie('wrap-line-length'), '0'));
|
||||
$('#unescape-strings').prop('checked', $.cookie('unescape-strings') === 'on');
|
||||
$('#jslint-happy').prop('checked', $.cookie('jslint-happy') === 'on');
|
||||
$('#end-with-newline').prop('checked', $.cookie('end-with-newline') === 'on');
|
||||
$('#indent-inner-html').prop('checked', $.cookie('indent-inner-html') === 'on');
|
||||
$('#comma-first').prop('checked', $.cookie('comma-first') === 'on');
|
||||
$('#e4x').prop('checked', $.cookie('e4x') === 'on');
|
||||
}
|
||||
|
||||
function store_settings_to_cookie() {
|
||||
var opts = {
|
||||
expires: 360
|
||||
};
|
||||
$.cookie('tabsize', $('#tabsize').val(), opts);
|
||||
$.cookie('brace-style', $('#brace-style').val(), opts);
|
||||
$.cookie('detect-packers', $('#detect-packers').prop('checked') ? 'on' : 'off', opts);
|
||||
$.cookie('max-preserve-newlines', $('#max-preserve-newlines').val(), opts);
|
||||
$.cookie('keep-array-indentation', $('#keep-array-indentation').prop('checked') ? 'on' : 'off', opts);
|
||||
$.cookie('break-chained-methods', $('#break-chained-methods').prop('checked') ? 'on' : 'off', opts);
|
||||
$.cookie('space-before-conditional', $('#space-before-conditional').prop('checked') ? 'on' : 'off',
|
||||
opts);
|
||||
$.cookie('unescape-strings', $('#unescape-strings').prop('checked') ? 'on' : 'off', opts);
|
||||
$.cookie('jslint-happy', $('#jslint-happy').prop('checked') ? 'on' : 'off', opts);
|
||||
$.cookie('end-with-newline', $('#end-with-newline').prop('checked') ? 'on' : 'off', opts);
|
||||
$.cookie('wrap-line-length', $('#wrap-line-length').val(), opts);
|
||||
$.cookie('indent-scripts', $('#indent-scripts').val(), opts);
|
||||
$.cookie('indent-inner-html', $('#indent-inner-html').prop('checked') ? 'on' : 'off', opts);
|
||||
$.cookie('comma-first', $('#comma-first').prop('checked') ? 'on' : 'off', opts);
|
||||
$.cookie('e4x', $('#e4x').prop('checked') ? 'on' : 'off', opts);
|
||||
|
||||
}
|
||||
|
||||
function unpacker_filter(source) {
|
||||
var trailing_comments = '',
|
||||
comment = '',
|
||||
unpacked = '',
|
||||
found = false;
|
||||
|
||||
// cut trailing comments
|
||||
do {
|
||||
found = false;
|
||||
if (/^\s*\/\*/.test(source)) {
|
||||
found = true;
|
||||
comment = source.substr(0, source.indexOf('*/') + 2);
|
||||
source = source.substr(comment.length).replace(/^\s+/, '');
|
||||
trailing_comments += comment + "\n";
|
||||
} else if (/^\s*\/\//.test(source)) {
|
||||
found = true;
|
||||
comment = source.match(/^\s*\/\/.*/)[0];
|
||||
source = source.substr(comment.length).replace(/^\s+/, '');
|
||||
trailing_comments += comment + "\n";
|
||||
}
|
||||
} while (found);
|
||||
|
||||
var unpackers = [P_A_C_K_E_R, Urlencoded, /*JavascriptObfuscator,*/ MyObfuscate];
|
||||
for (var i = 0; i < unpackers.length; i++) {
|
||||
if (unpackers[i].detect(source)) {
|
||||
unpacked = unpackers[i].unpack(source);
|
||||
if (unpacked != source) {
|
||||
source = unpacker_filter(unpacked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return trailing_comments + source;
|
||||
}
|
||||
|
||||
|
||||
function beautify() {
|
||||
if (the.beautify_in_progress) return;
|
||||
|
||||
store_settings_to_cookie();
|
||||
|
||||
the.beautify_in_progress = true;
|
||||
|
||||
var source = the.editor ? the.editor.getValue() : $('#source').val(),
|
||||
output,
|
||||
opts = {};
|
||||
|
||||
opts.indent_size = $('#tabsize').val();
|
||||
opts.indent_char = opts.indent_size == 1 ? '\t' : ' ';
|
||||
opts.max_preserve_newlines = $('#max-preserve-newlines').val();
|
||||
opts.preserve_newlines = opts.max_preserve_newlines !== "-1";
|
||||
opts.keep_array_indentation = $('#keep-array-indentation').prop('checked');
|
||||
opts.break_chained_methods = $('#break-chained-methods').prop('checked');
|
||||
opts.indent_scripts = $('#indent-scripts').val();
|
||||
opts.brace_style = $('#brace-style').val();
|
||||
opts.space_before_conditional = $('#space-before-conditional').prop('checked');
|
||||
opts.unescape_strings = $('#unescape-strings').prop('checked');
|
||||
opts.jslint_happy = $('#jslint-happy').prop('checked');
|
||||
opts.end_with_newline = $('#end-with-newline').prop('checked');
|
||||
opts.wrap_line_length = $('#wrap-line-length').val();
|
||||
opts.indent_inner_html = $('#indent-inner-html').prop('checked');
|
||||
opts.comma_first = $('#comma-first').prop('checked');
|
||||
opts.e4x = $('#e4x').prop('checked');
|
||||
|
||||
if (looks_like_html(source)) {
|
||||
output = html_beautify(source, opts);
|
||||
} else {
|
||||
if ($('#detect-packers').prop('checked')) {
|
||||
source = unpacker_filter(source);
|
||||
}
|
||||
output = js_beautify(source, opts);
|
||||
}
|
||||
if (the.editor) {
|
||||
the.editor.setValue(output);
|
||||
} else {
|
||||
$('#source').val(output);
|
||||
}
|
||||
|
||||
the.beautify_in_progress = false;
|
||||
}
|
||||
|
||||
function looks_like_html(source) {
|
||||
// <foo> - looks like html
|
||||
// <!--\nalert('foo!');\n--> - doesn't look like html
|
||||
|
||||
var trimmed = source.replace(/^[ \t\n\r]+/, '');
|
||||
var comment_mark = '<' + '!-' + '-';
|
||||
return (trimmed && (trimmed.substring(0, 1) === '<' && trimmed.substring(0, 4) !== comment_mark));
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="about">
|
||||
<p>
|
||||
<a class="self" href="./">Beautify, unpack or deobfuscate JavaScript and HTML, make JSON/JSONP readable, etc.</a>
|
||||
</p>
|
||||
<p>
|
||||
All of the source code is completely free and open, available on <a href="https://github.com/beautify-web/js-beautify">GitHub</a> under MIT licence,
|
||||
<br>and we have a command-line version, python library and a <a href="https://npmjs.org/package/js-beautify">node package</a> as well.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
<table id="options">
|
||||
<tr>
|
||||
<td>
|
||||
<select name="tabsize" id="tabsize">
|
||||
<option value="1">Indent with a tab character</option>
|
||||
<option value="2">Indent with 2 spaces</option>
|
||||
<option value="3">Indent with 3 spaces</option>
|
||||
<option value="4">Indent with 4 spaces</option>
|
||||
<option value="8">Indent with 8 spaces</option>
|
||||
</select>
|
||||
<br>
|
||||
|
||||
<select name="max-preserve-newlines" id="max-preserve-newlines">
|
||||
<option value="-1">Remove all extra newlines</option>
|
||||
<option value="1">Allow 1 newline between tokens</option>
|
||||
<option value="2">Allow 2 newlines between tokens</option>
|
||||
<option value="5">Allow 5 newlines between tokens</option>
|
||||
<option value="10">Allow 10 newlines between tokens</option>
|
||||
<option value="0">Allow unlimited newlines between tokens</option>
|
||||
</select>
|
||||
<br>
|
||||
|
||||
<select name="wrap-line-length" id="wrap-line-length">
|
||||
<option value="0">Do not wrap lines</option>
|
||||
<option value="40">Wrap lines near 40 characters</option>
|
||||
<option value="70">Wrap lines near 70 characters</option>
|
||||
<option value="80">Wrap lines near 80 characters</option>
|
||||
<option value="110">Wrap lines near 110 characters</option>
|
||||
<option value="120">Wrap lines near 120 characters</option>
|
||||
<option value="160">Wrap lines near 160 characters</option>
|
||||
</select>
|
||||
<br>
|
||||
|
||||
<select id="brace-style">
|
||||
<option value="collapse">Braces with control statement</option>
|
||||
<option value="expand">Braces on own line</option>
|
||||
<option value="end-expand">End braces on own line</option>
|
||||
<option value="none">Attempt to keep braces where
|
||||
they are</option>
|
||||
</select>
|
||||
|
||||
<p style="margin:6px 0 0 0">HTML <style>, <script> formatting:</p>
|
||||
<select id="indent-scripts">
|
||||
<option value="keep">Keep indent level of the tag</option>
|
||||
<option value="normal">Add one indent level</option>
|
||||
<option value="separate">Separate indentation</option>
|
||||
</select>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<input class="checkbox" type="checkbox" id="end-with-newline">
|
||||
<label for="end-with-newline">End script and style with newline?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="e4x">
|
||||
<label for="e4x">Support e4x/jsx syntax</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="comma-first">
|
||||
<label for="comma-first">Use comma-first list style?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="detect-packers">
|
||||
<label for="detect-packers">Detect packers and obfuscators?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="keep-array-indentation">
|
||||
<label for="keep-array-indentation">Keep array indentation?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="break-chained-methods">
|
||||
<label for="break-chained-methods">Break lines on chained methods?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="space-before-conditional">
|
||||
<label for="space-before-conditional">Space before conditional: "if(x)" / "if (x)"</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="unescape-strings">
|
||||
<label for="unescape-strings">Unescape printable chars encoded as \xNN or \uNNNN?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="jslint-happy">
|
||||
<label for="jslint-happy">Use JSLint-happy formatting tweaks?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="indent-inner-html">
|
||||
<label for="indent-inner-html">Indent <head> and <body> sections?</label>
|
||||
<br><a href="?without-codemirror" class="turn-off-codemirror">Use a simple textarea for code input?</a>
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div style="line-height: 0">
|
||||
<button class="submit"><strong>Beautify JavaScript or HTML</strong> <em>(ctrl-enter)</em>
|
||||
</button>
|
||||
<textarea id="source" rows="30" cols="160"></textarea>
|
||||
<button class="submit"><strong>Beautify JavaScript or HTML</strong> <em>(ctrl-enter)</em>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="blurb">
|
||||
<div style="float:right;">
|
||||
<a style="display:block; float: left; padding-top: 3px" href="http://flattr.com/thing/94550/jsbeautifier-org" target="_blank">
|
||||
<img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p>Browser extensions and other uses:</p>
|
||||
<ul id="uses">
|
||||
|
||||
<li>A <a href="javascript:(function(){s=document.getElementsByTagName('SCRIPT');tx='';sr=[];for(i=0;i<s.length;i++){with(s.item(i)){t=text;if(t){tx+=t;}else{sr.push(src)};}};with(window.open()){document.write('<textarea id="t">'+(sr.join("\n"))+"\n\n-----\n\n"+tx+'</textarea><script src="http://jsbeautifier.org/beautify.js"></script><script>with(document.getElementById("t")){value=js_beautify(value);with(style){width="99%";height="99%";borderStyle="none";}};</script>');document.close();}})();"><strong>bookmarklet</strong></a> (drag
|
||||
it to your bookmarks) by Ichiro Hiroshi to see all scripts used on the page,</li>
|
||||
|
||||
<li style="margin-top: 8px"><strong>Chrome</strong>: <a href="https://github.com/rixth/jsbeautify-for-chrome">jsbeautify-for-chrome</a> by Tom Rix,</li>
|
||||
<li><strong>Chrome</strong>: <a href="https://chrome.google.com/webstore/detail/piekbefgpgdecckjcpffhnacjflfoddg">Pretty Beautiful JavaScript</a> by Will McSweeney,</li>
|
||||
<li><strong>Chrome</strong>: <a href="https://chrome.google.com/webstore/detail/cfmcghennfbpmhemnnfjhkdmnbidpanb">Quick source viewer</a> by Tomi Mickelsson
|
||||
(<a href="https://github.com/tomimick/chrome-ext-view-src">github</a>, <a href="http://tomicloud.com/2012/07/viewsrc-chrome-ext">blog</a>),</li>
|
||||
<li><strong>Chrome</strong>: <a href="https://chrome.google.com/webstore/detail/stackoverflow-code-beauti/pljeafjjkkbacckkollfejkciddacmeb">Stackoverflow Code Beautify</a> by Making Odd Edit Studios (<a href="https://github.com/MakingOddEdit/CodeBeautify">github</a>),</li>
|
||||
<li style="margin-top: 8px"><strong>Firefox</strong>: <a href="https://addons.mozilla.org/en-US/firefox/addon/javascript-deminifier/">Javascript deminifier</a> by Ben Murphy, to be
|
||||
used together with the firebug (<a href="https://github.com/benmmurphy/jsdeminifier_xpi/">github</a>),</li>
|
||||
<li style="margin-top: 8px"><strong>Safari</strong>: <a href="http://spadin.github.com/js-beautify-safari-extension">Safari extension</a> by Sandro Padin,</li>
|
||||
<li style="margin-top: 8px"><strong>Opera</strong>: <a href="https://addons.opera.com/addons/extensions/details/readable-javascript/">Readable JavaScript</a>
|
||||
(<a href="https://github.com/Dither/readable-javascript">github</a>) by Dither,</li>
|
||||
<li><strong>Opera</strong>: <a href="https://addons.opera.com/addons/extensions/details/source/">Source</a> extension by Deathamns,</li>
|
||||
<li style="margin-top: 8px"><strong>Sublime Text 2:</strong> <a href="https://github.com/jdc0589/JsFormat">JsFormat</a>, a javascript formatting plugin for this nice editor by Davis
|
||||
Clark,</li>
|
||||
<li style="margin-top: 8px"><strong>vim:</strong> <a href="https://github.com/michalliu/sourcebeautify.vim">sourcebeautify.vim</a>, a plugin by michalliu (requires node.js, V8, SpiderMonkey
|
||||
or cscript js engine),</li>
|
||||
<li><strong>vim:</strong> <a href="https://github.com/maksimr/vim-jsbeautify">vim-jsbeautify</a>, a plugin by Maksim Ryzhikov (node.js or V8 required),</li>
|
||||
|
||||
<li style="margin-top: 8px"><strong>Emacs:</strong> <a href="https://github.com/yasuyk/web-beautify">Web-beautify</a> formatting package by Yasuyuki Oka,</li>
|
||||
<li style="margin-top: 8px"><strong>C#:</strong> ghost6991 <a href="https://github.com/ghost6991/Jsbeautifier">ported the javascript formatter to C#</a>,
|
||||
<li style="margin-top: 8px"><strong>Go:</strong> ditashi has <a href="https://github.com/ditashi/jsbeautifier-go">ported the javascript formatter to golang</a>,
|
||||
<li style="margin-top: 12px"><a href="http://fiddler2.com/">Fiddler</a> proxy: <a href="http://fiddler2.com/Fiddler2/extensions.asp">JavaScript Formatter addon</a>,
|
||||
<li><a href="https://github.com/nagaozen/gedit-tunnings/">gEdit tips</a> by Fabio Nagao,</li>
|
||||
<li><a href="http://akelpad.sourceforge.net/forum/viewtopic.php?p=11246#11246">Akelpad extension</a> by Infocatcher,</li>
|
||||
<li>Beautifier in <a href="http://sethmason.com/2011/04/28/jsbeautify-in-emacs.html">Emacs</a> write-up by Seth Mason,</li>
|
||||
<li><a href="http://c9.io">Cloud9</a>, a lovely IDE running in a browser, working in the node/cloud, uses jsbeautifier (<a href="https://github.com/ajaxorg/cloud9">github</a>),</li>
|
||||
<li><a href="http://www.symetronapps.com/pages/apps/shrinker.html">Shrinker</a>, a non-free JavaScript packer for Mac. I haven't used it, so I have
|
||||
no idea if it's any good,</li>
|
||||
<li><a href="http://www.restconsole.com/">REST Console</a>, a request debugging tool for Chrome, beautifies JSON responses (<a href="https://github.com/codeinchaos/rest-console">github</a>),</li>
|
||||
<li><a href="http://mitmproxy.org/">mitmproxy</a>, a nifty SSL-capable HTTP proxy, provides pretty javascript responses (<a href="https://github.com/cortesi/mitmproxy">github</a>).</li>
|
||||
<li><a href="http://www.wakanda.org/">wakanda</a>, a neat IDE for web and mobile applications has a <a href="http://forum.wakanda.org/showthread.php?1483-3-new-extensions-JSLint-Beautifier-and-Snippet">Beautifier extension</a>
|
||||
(<a href="https://github.com/Wakanda/wakanda-extensions/tree/master/Beautifier">github</a>).</li>
|
||||
<li><a href="http://portswigger.net/burp/">Burp Suite</a> now has a <a href="https://github.com/irsdl/BurpSuiteJSBeautifier/">beautfier extension</a>,
|
||||
thanks to Soroush Dalili,</li>
|
||||
<li><a href="http://plugins.netbeans.org/plugin/43263/jsbeautify">Netbeans jsbeautify</a> plugin by Drew Hamlett
|
||||
(<a href="https://github.com/drewhjava/netbeans-jsbeautify">github</a>).</li>
|
||||
<li><a href="https://github.com/drewhjava/brackets-beautify">brackets-beautify-extension</a> for <a href="http://brackets.io">Adobe Brackets</a> by Drew
|
||||
Hamlett (<a href="https://github.com/drewhjava/brackets-beautify">github</a>),</li>
|
||||
<li><a href="http://codecaddy.net/">codecaddy.net</a>, a collection of webdev-related tools, assembled by Darik Hall,
|
||||
<li><a href="http://www.editey.com/">editey.com</a>, an interesting and free Google-Drive oriented editor uses this beautifier,
|
||||
<li><a href="https://github.com/vkadam/grunt-jsbeautifier">a beautifier plugin for Grunt</a> by Vishal Kadam,
|
||||
<li><a href="http://www.uvviewsoft.com/synwrite/">SynWrite</a> editor has a JsFormat plugin (<a href="https://sourceforge.net/projects/synwrite-addons/files/PyPlugins/Alexey.JsFormat/">rar</a>, <a href="http://synwrite.sourceforge.net/forums/viewtopic.php?f=19&t=865">readme</a>),
|
||||
<li><a href="http://liveditor.com/">LIVEditor</a>, a live-editing HTML/CSS/JS IDE (commercial, Windows-only) uses the library,
|
||||
<li><a href="https://github.com/Diogenesthecynic/FullScreenMario-JSON/">FullScreenMario</a>, a HTML5/javascript remake of Super Mario Bros game, uses the library in its level editor.
|
||||
<li class="writeme">Doing anything interesting? Write me to einar@jsbeautifier.org and I'll include your link.</li>
|
||||
</ul>
|
||||
|
||||
<p class="contributors contributor-sep">Written by Einar Lielmanis, <a href="mailto:einar@jsbeautifier.org">einar@jsbeautifier.org</a>, maintained and evolved by <a href="https://github.com/bitwiseman/">Liam Newman</a>.</p>
|
||||
<p class="contributors">We use the wonderful <a href="http://codemirror.net">CodeMirror</a> syntax highlighting editor, written by Marijn Haverbeke.
|
||||
</p>
|
||||
<p class="contributors">Made with a great help of Jason Diamond, Patrick Hof, Nochum Sossonko, Andreas Schneider,
|
||||
<br>Dave Vasilevsky,
|
||||
<a href="http://my.opera.com/Vital/blog/">Vital Batmanov</a>, Ron Baldwin, Gabriel Harrison,
|
||||
<a href="http://shullian.com">Chris J. Shull</a>,
|
||||
<a href="http://mathiasbynens.be/">Mathias Bynens</a>,
|
||||
<br>
|
||||
<a href="https://www.vittgam.net/">Vittorio Gambaletta</a>,
|
||||
<a href="https://github.com/esseks">Stefano Sanfilippo</a> and
|
||||
<a href="https://github.com/evocateur">Daniel Stockman</a>.
|
||||
</p>
|
||||
|
||||
<p style="text-align:right">
|
||||
<a href="#" style="color: #ccc; border-bottom: 1px dashed #ccc; text-decoration: none;" onclick="run_tests(); return false;">Run the tests</a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div id="testresults"></div>
|
||||
<script>
|
||||
$(function () {
|
||||
|
||||
read_settings_from_cookie();
|
||||
|
||||
var default_text =
|
||||
"// This is just a sample script. Paste your real code (javascript or HTML) here.\n\nif ('this_is'==/an_example/){of_beautifer();}else{var a=b?(c%d):e[f];}";
|
||||
var textArea = $('#source')[0];
|
||||
|
||||
if (the.use_codemirror && typeof CodeMirror !== 'undefined') {
|
||||
the.editor = CodeMirror.fromTextArea(textArea, {
|
||||
theme: 'default',
|
||||
lineNumbers: true
|
||||
});
|
||||
the.editor.focus();
|
||||
|
||||
the.editor.setValue(default_text);
|
||||
$('.CodeMirror').click(function () {
|
||||
if (the.editor.getValue() == default_text) {
|
||||
the.editor.setValue('');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$('#source').val(default_text).bind('click focus', function () {
|
||||
if ($(this).val() == default_text) {
|
||||
$(this).val('');
|
||||
}
|
||||
}).bind('blur', function () {
|
||||
if (!$(this).val()) {
|
||||
$(this).val(default_text);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
$(window).bind('keydown', function (e) {
|
||||
if (e.ctrlKey && e.keyCode == 13) {
|
||||
beautify();
|
||||
}
|
||||
})
|
||||
$('.submit').click(beautify);
|
||||
$('select').change(beautify);
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
var _gaq = [
|
||||
['_setAccount', 'UA-7409939-1'],
|
||||
['_trackPageview']
|
||||
];
|
||||
(function (d, t) {
|
||||
var g = d.createElement(t),
|
||||
s = d.getElementsByTagName(t)[0];
|
||||
g.src = '//www.google-analytics.com/ga.js';
|
||||
s.parentNode.insertBefore(g, s);
|
||||
}(document, 'script'));
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env node
|
||||
var cli = require('../lib/cli'); cli.interpret();
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env node
|
||||
var cli = require('../lib/cli'); cli.interpret();
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
var cli = require('../lib/cli');
|
||||
cli.interpret();
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"indent_size": 4,
|
||||
"indent_char": " ",
|
||||
"indent_level": 0,
|
||||
"indent_with_tabs": false,
|
||||
"preserve_newlines": true,
|
||||
"max_preserve_newlines": 10,
|
||||
"jslint_happy": false,
|
||||
"space_after_anon_function": false,
|
||||
"brace_style": "collapse",
|
||||
"keep_array_indentation": false,
|
||||
"keep_function_indentation": false,
|
||||
"space_before_conditional": true,
|
||||
"break_chained_methods": false,
|
||||
"eval_code": false,
|
||||
"unescape_strings": false,
|
||||
"wrap_line_length": 0
|
||||
}
|
||||
55
gaia/distros/spark/apps/customizer/components/js-beautify/js/index.js
Executable file
55
gaia/distros/spark/apps/customizer/components/js-beautify/js/index.js
Executable file
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
The following batches are equivalent:
|
||||
|
||||
var beautify_js = require('js-beautify');
|
||||
var beautify_js = require('js-beautify').js;
|
||||
var beautify_js = require('js-beautify').js_beautify;
|
||||
|
||||
var beautify_css = require('js-beautify').css;
|
||||
var beautify_css = require('js-beautify').css_beautify;
|
||||
|
||||
var beautify_html = require('js-beautify').html;
|
||||
var beautify_html = require('js-beautify').html_beautify;
|
||||
|
||||
All methods returned accept two arguments, the source string and an options object.
|
||||
**/
|
||||
|
||||
function get_beautify(js_beautify, css_beautify, html_beautify) {
|
||||
// the default is js
|
||||
var beautify = function (src, config) {
|
||||
return js_beautify.js_beautify(src, config);
|
||||
};
|
||||
|
||||
// short aliases
|
||||
beautify.js = js_beautify.js_beautify;
|
||||
beautify.css = css_beautify.css_beautify;
|
||||
beautify.html = html_beautify.html_beautify;
|
||||
|
||||
// legacy aliases
|
||||
beautify.js_beautify = js_beautify.js_beautify;
|
||||
beautify.css_beautify = css_beautify.css_beautify;
|
||||
beautify.html_beautify = html_beautify.html_beautify;
|
||||
|
||||
return beautify;
|
||||
}
|
||||
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// Add support for AMD ( https://github.com/amdjs/amdjs-api/wiki/AMD#defineamd-property- )
|
||||
define([
|
||||
"./lib/beautify",
|
||||
"./lib/beautify-css",
|
||||
"./lib/beautify-html"
|
||||
], function(js_beautify, css_beautify, html_beautify) {
|
||||
return get_beautify(js_beautify, css_beautify, html_beautify);
|
||||
});
|
||||
} else {
|
||||
(function(mod) {
|
||||
var js_beautify = require('./lib/beautify');
|
||||
var css_beautify = require('./lib/beautify-css');
|
||||
var html_beautify = require('./lib/beautify-html');
|
||||
|
||||
mod.exports = get_beautify(js_beautify, css_beautify, html_beautify);
|
||||
|
||||
})(module);
|
||||
}
|
||||
|
||||
491
gaia/distros/spark/apps/customizer/components/js-beautify/js/lib/beautify-css.js
Executable file
491
gaia/distros/spark/apps/customizer/components/js-beautify/js/lib/beautify-css.js
Executable file
|
|
@ -0,0 +1,491 @@
|
|||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2013 Einar Lielmanis and contributors.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
CSS Beautifier
|
||||
---------------
|
||||
|
||||
Written by Harutyun Amirjanyan, (amirjanyan@gmail.com)
|
||||
|
||||
Based on code initially developed by: Einar Lielmanis, <einar@jsbeautifier.org>
|
||||
http://jsbeautifier.org/
|
||||
|
||||
Usage:
|
||||
css_beautify(source_text);
|
||||
css_beautify(source_text, options);
|
||||
|
||||
The options are (default in brackets):
|
||||
indent_size (4) — indentation size,
|
||||
indent_char (space) — character to indent with,
|
||||
selector_separator_newline (true) - separate selectors with newline or
|
||||
not (e.g. "a,\nbr" or "a, br")
|
||||
end_with_newline (false) - end with a newline
|
||||
newline_between_rules (true) - add a new line after every css rule
|
||||
|
||||
e.g
|
||||
|
||||
css_beautify(css_source_text, {
|
||||
'indent_size': 1,
|
||||
'indent_char': '\t',
|
||||
'selector_separator': ' ',
|
||||
'end_with_newline': false,
|
||||
'newline_between_rules': true
|
||||
});
|
||||
*/
|
||||
|
||||
// http://www.w3.org/TR/CSS21/syndata.html#tokenization
|
||||
// http://www.w3.org/TR/css3-syntax/
|
||||
|
||||
(function() {
|
||||
function css_beautify(source_text, options) {
|
||||
options = options || {};
|
||||
source_text = source_text || '';
|
||||
// HACK: newline parsing inconsistent. This brute force normalizes the input.
|
||||
source_text = source_text.replace(/\r\n|[\r\u2028\u2029]/g, '\n')
|
||||
|
||||
var indentSize = options.indent_size || 4;
|
||||
var indentCharacter = options.indent_char || ' ';
|
||||
var selectorSeparatorNewline = (options.selector_separator_newline === undefined) ? true : options.selector_separator_newline;
|
||||
var end_with_newline = (options.end_with_newline === undefined) ? false : options.end_with_newline;
|
||||
var newline_between_rules = (options.newline_between_rules === undefined) ? true : options.newline_between_rules;
|
||||
var eol = options.eol ? options.eol : '\n';
|
||||
|
||||
// compatibility
|
||||
if (typeof indentSize === "string") {
|
||||
indentSize = parseInt(indentSize, 10);
|
||||
}
|
||||
|
||||
if(options.indent_with_tabs){
|
||||
indentCharacter = '\t';
|
||||
indentSize = 1;
|
||||
}
|
||||
|
||||
eol = eol.replace(/\\r/, '\r').replace(/\\n/, '\n')
|
||||
|
||||
|
||||
// tokenizer
|
||||
var whiteRe = /^\s+$/;
|
||||
var wordRe = /[\w$\-_]/;
|
||||
|
||||
var pos = -1,
|
||||
ch;
|
||||
var parenLevel = 0;
|
||||
|
||||
function next() {
|
||||
ch = source_text.charAt(++pos);
|
||||
return ch || '';
|
||||
}
|
||||
|
||||
function peek(skipWhitespace) {
|
||||
var result = '';
|
||||
var prev_pos = pos;
|
||||
if (skipWhitespace) {
|
||||
eatWhitespace();
|
||||
}
|
||||
result = source_text.charAt(pos + 1) || '';
|
||||
pos = prev_pos - 1;
|
||||
next();
|
||||
return result;
|
||||
}
|
||||
|
||||
function eatString(endChars) {
|
||||
var start = pos;
|
||||
while (next()) {
|
||||
if (ch === "\\") {
|
||||
next();
|
||||
} else if (endChars.indexOf(ch) !== -1) {
|
||||
break;
|
||||
} else if (ch === "\n") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return source_text.substring(start, pos + 1);
|
||||
}
|
||||
|
||||
function peekString(endChar) {
|
||||
var prev_pos = pos;
|
||||
var str = eatString(endChar);
|
||||
pos = prev_pos - 1;
|
||||
next();
|
||||
return str;
|
||||
}
|
||||
|
||||
function eatWhitespace() {
|
||||
var result = '';
|
||||
while (whiteRe.test(peek())) {
|
||||
next();
|
||||
result += ch;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function skipWhitespace() {
|
||||
var result = '';
|
||||
if (ch && whiteRe.test(ch)) {
|
||||
result = ch;
|
||||
}
|
||||
while (whiteRe.test(next())) {
|
||||
result += ch;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function eatComment(singleLine) {
|
||||
var start = pos;
|
||||
singleLine = peek() === "/";
|
||||
next();
|
||||
while (next()) {
|
||||
if (!singleLine && ch === "*" && peek() === "/") {
|
||||
next();
|
||||
break;
|
||||
} else if (singleLine && ch === "\n") {
|
||||
return source_text.substring(start, pos);
|
||||
}
|
||||
}
|
||||
|
||||
return source_text.substring(start, pos) + ch;
|
||||
}
|
||||
|
||||
|
||||
function lookBack(str) {
|
||||
return source_text.substring(pos - str.length, pos).toLowerCase() ===
|
||||
str;
|
||||
}
|
||||
|
||||
// Nested pseudo-class if we are insideRule
|
||||
// and the next special character found opens
|
||||
// a new block
|
||||
function foundNestedPseudoClass() {
|
||||
var openParen = 0;
|
||||
for (var i = pos + 1; i < source_text.length; i++) {
|
||||
var ch = source_text.charAt(i);
|
||||
if (ch === "{") {
|
||||
return true;
|
||||
} else if (ch === '(') {
|
||||
// pseudoclasses can contain ()
|
||||
openParen += 1;
|
||||
} else if (ch === ')') {
|
||||
if (openParen == 0) {
|
||||
return false;
|
||||
}
|
||||
openParen -= 1;
|
||||
} else if (ch === ";" || ch === "}") {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// printer
|
||||
var basebaseIndentString = source_text.match(/^[\t ]*/)[0];
|
||||
var singleIndent = new Array(indentSize + 1).join(indentCharacter);
|
||||
var indentLevel = 0;
|
||||
var nestedLevel = 0;
|
||||
|
||||
function indent() {
|
||||
indentLevel++;
|
||||
basebaseIndentString += singleIndent;
|
||||
}
|
||||
|
||||
function outdent() {
|
||||
indentLevel--;
|
||||
basebaseIndentString = basebaseIndentString.slice(0, -indentSize);
|
||||
}
|
||||
|
||||
var print = {};
|
||||
print["{"] = function(ch) {
|
||||
print.singleSpace();
|
||||
output.push(ch);
|
||||
print.newLine();
|
||||
};
|
||||
print["}"] = function(ch) {
|
||||
print.newLine();
|
||||
output.push(ch);
|
||||
print.newLine();
|
||||
};
|
||||
|
||||
print._lastCharWhitespace = function() {
|
||||
return whiteRe.test(output[output.length - 1]);
|
||||
};
|
||||
|
||||
print.newLine = function(keepWhitespace) {
|
||||
if (output.length) {
|
||||
if (!keepWhitespace && output[output.length - 1] !== '\n') {
|
||||
print.trim();
|
||||
}
|
||||
|
||||
output.push('\n');
|
||||
|
||||
if (basebaseIndentString) {
|
||||
output.push(basebaseIndentString);
|
||||
}
|
||||
}
|
||||
};
|
||||
print.singleSpace = function() {
|
||||
if (output.length && !print._lastCharWhitespace()) {
|
||||
output.push(' ');
|
||||
}
|
||||
};
|
||||
|
||||
print.preserveSingleSpace = function() {
|
||||
if (isAfterSpace) {
|
||||
print.singleSpace();
|
||||
}
|
||||
};
|
||||
|
||||
print.trim = function() {
|
||||
while (print._lastCharWhitespace()) {
|
||||
output.pop();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var output = [];
|
||||
/*_____________________--------------------_____________________*/
|
||||
|
||||
var insideRule = false;
|
||||
var insidePropertyValue = false;
|
||||
var enteringConditionalGroup = false;
|
||||
var top_ch = '';
|
||||
var last_top_ch = '';
|
||||
|
||||
while (true) {
|
||||
var whitespace = skipWhitespace();
|
||||
var isAfterSpace = whitespace !== '';
|
||||
var isAfterNewline = whitespace.indexOf('\n') !== -1;
|
||||
last_top_ch = top_ch;
|
||||
top_ch = ch;
|
||||
|
||||
if (!ch) {
|
||||
break;
|
||||
} else if (ch === '/' && peek() === '*') { /* css comment */
|
||||
var header = indentLevel === 0;
|
||||
|
||||
if (isAfterNewline || header) {
|
||||
print.newLine();
|
||||
}
|
||||
|
||||
output.push(eatComment());
|
||||
print.newLine();
|
||||
if (header) {
|
||||
print.newLine(true);
|
||||
}
|
||||
} else if (ch === '/' && peek() === '/') { // single line comment
|
||||
if (!isAfterNewline && last_top_ch !== '{' ) {
|
||||
print.trim();
|
||||
}
|
||||
print.singleSpace();
|
||||
output.push(eatComment());
|
||||
print.newLine();
|
||||
} else if (ch === '@') {
|
||||
print.preserveSingleSpace();
|
||||
output.push(ch);
|
||||
|
||||
// strip trailing space, if present, for hash property checks
|
||||
var variableOrRule = peekString(": ,;{}()[]/='\"");
|
||||
|
||||
if (variableOrRule.match(/[ :]$/)) {
|
||||
// we have a variable or pseudo-class, add it and insert one space before continuing
|
||||
next();
|
||||
variableOrRule = eatString(": ").replace(/\s$/, '');
|
||||
output.push(variableOrRule);
|
||||
print.singleSpace();
|
||||
}
|
||||
|
||||
variableOrRule = variableOrRule.replace(/\s$/, '')
|
||||
|
||||
// might be a nesting at-rule
|
||||
if (variableOrRule in css_beautify.NESTED_AT_RULE) {
|
||||
nestedLevel += 1;
|
||||
if (variableOrRule in css_beautify.CONDITIONAL_GROUP_RULE) {
|
||||
enteringConditionalGroup = true;
|
||||
}
|
||||
}
|
||||
} else if (ch === '#' && peek() === '{') {
|
||||
print.preserveSingleSpace();
|
||||
output.push(eatString('}'));
|
||||
} else if (ch === '{') {
|
||||
if (peek(true) === '}') {
|
||||
eatWhitespace();
|
||||
next();
|
||||
print.singleSpace();
|
||||
output.push("{}");
|
||||
print.newLine();
|
||||
if (newline_between_rules && indentLevel === 0) {
|
||||
print.newLine(true);
|
||||
}
|
||||
} else {
|
||||
indent();
|
||||
print["{"](ch);
|
||||
// when entering conditional groups, only rulesets are allowed
|
||||
if (enteringConditionalGroup) {
|
||||
enteringConditionalGroup = false;
|
||||
insideRule = (indentLevel > nestedLevel);
|
||||
} else {
|
||||
// otherwise, declarations are also allowed
|
||||
insideRule = (indentLevel >= nestedLevel);
|
||||
}
|
||||
}
|
||||
} else if (ch === '}') {
|
||||
outdent();
|
||||
print["}"](ch);
|
||||
insideRule = false;
|
||||
insidePropertyValue = false;
|
||||
if (nestedLevel) {
|
||||
nestedLevel--;
|
||||
}
|
||||
if (newline_between_rules && indentLevel === 0) {
|
||||
print.newLine(true);
|
||||
}
|
||||
} else if (ch === ":") {
|
||||
eatWhitespace();
|
||||
if ((insideRule || enteringConditionalGroup) &&
|
||||
!(lookBack("&") || foundNestedPseudoClass())) {
|
||||
// 'property: value' delimiter
|
||||
// which could be in a conditional group query
|
||||
insidePropertyValue = true;
|
||||
output.push(':');
|
||||
print.singleSpace();
|
||||
} else {
|
||||
// sass/less parent reference don't use a space
|
||||
// sass nested pseudo-class don't use a space
|
||||
if (peek() === ":") {
|
||||
// pseudo-element
|
||||
next();
|
||||
output.push("::");
|
||||
} else {
|
||||
// pseudo-class
|
||||
output.push(':');
|
||||
}
|
||||
}
|
||||
} else if (ch === '"' || ch === '\'') {
|
||||
print.preserveSingleSpace();
|
||||
output.push(eatString(ch));
|
||||
} else if (ch === ';') {
|
||||
insidePropertyValue = false;
|
||||
output.push(ch);
|
||||
print.newLine();
|
||||
} else if (ch === '(') { // may be a url
|
||||
if (lookBack("url")) {
|
||||
output.push(ch);
|
||||
eatWhitespace();
|
||||
if (next()) {
|
||||
if (ch !== ')' && ch !== '"' && ch !== '\'') {
|
||||
output.push(eatString(')'));
|
||||
} else {
|
||||
pos--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
parenLevel++;
|
||||
print.preserveSingleSpace();
|
||||
output.push(ch);
|
||||
eatWhitespace();
|
||||
}
|
||||
} else if (ch === ')') {
|
||||
output.push(ch);
|
||||
parenLevel--;
|
||||
} else if (ch === ',') {
|
||||
output.push(ch);
|
||||
eatWhitespace();
|
||||
if (selectorSeparatorNewline && !insidePropertyValue && parenLevel < 1) {
|
||||
print.newLine();
|
||||
} else {
|
||||
print.singleSpace();
|
||||
}
|
||||
} else if (ch === ']') {
|
||||
output.push(ch);
|
||||
} else if (ch === '[') {
|
||||
print.preserveSingleSpace();
|
||||
output.push(ch);
|
||||
} else if (ch === '=') { // no whitespace before or after
|
||||
eatWhitespace()
|
||||
ch = '=';
|
||||
output.push(ch);
|
||||
} else {
|
||||
print.preserveSingleSpace();
|
||||
output.push(ch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var sweetCode = '';
|
||||
if (basebaseIndentString) {
|
||||
sweetCode += basebaseIndentString;
|
||||
}
|
||||
|
||||
sweetCode += output.join('').replace(/[\r\n\t ]+$/, '');
|
||||
|
||||
// establish end_with_newline
|
||||
if (end_with_newline) {
|
||||
sweetCode += '\n';
|
||||
}
|
||||
|
||||
if (eol != '\n') {
|
||||
sweetCode = sweetCode.replace(/[\n]/g, eol);
|
||||
}
|
||||
|
||||
return sweetCode;
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
|
||||
css_beautify.NESTED_AT_RULE = {
|
||||
"@page": true,
|
||||
"@font-face": true,
|
||||
"@keyframes": true,
|
||||
// also in CONDITIONAL_GROUP_RULE below
|
||||
"@media": true,
|
||||
"@supports": true,
|
||||
"@document": true
|
||||
};
|
||||
css_beautify.CONDITIONAL_GROUP_RULE = {
|
||||
"@media": true,
|
||||
"@supports": true,
|
||||
"@document": true
|
||||
};
|
||||
|
||||
/*global define */
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// Add support for AMD ( https://github.com/amdjs/amdjs-api/wiki/AMD#defineamd-property- )
|
||||
define([], function() {
|
||||
return {
|
||||
css_beautify: css_beautify
|
||||
};
|
||||
});
|
||||
} else if (typeof exports !== "undefined") {
|
||||
// Add support for CommonJS. Just put this file somewhere on your require.paths
|
||||
// and you will be able to `var html_beautify = require("beautify").html_beautify`.
|
||||
exports.css_beautify = css_beautify;
|
||||
} else if (typeof window !== "undefined") {
|
||||
// If we're running a web page and don't have either of the above, add our one global
|
||||
window.css_beautify = css_beautify;
|
||||
} else if (typeof global !== "undefined") {
|
||||
// If we don't even have window, try global.
|
||||
global.css_beautify = css_beautify;
|
||||
}
|
||||
|
||||
}());
|
||||
|
|
@ -0,0 +1,952 @@
|
|||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2013 Einar Lielmanis and contributors.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Style HTML
|
||||
---------------
|
||||
|
||||
Written by Nochum Sossonko, (nsossonko@hotmail.com)
|
||||
|
||||
Based on code initially developed by: Einar Lielmanis, <einar@jsbeautifier.org>
|
||||
http://jsbeautifier.org/
|
||||
|
||||
Usage:
|
||||
style_html(html_source);
|
||||
|
||||
style_html(html_source, options);
|
||||
|
||||
The options are:
|
||||
indent_inner_html (default false) — indent <head> and <body> sections,
|
||||
indent_size (default 4) — indentation size,
|
||||
indent_char (default space) — character to indent with,
|
||||
wrap_line_length (default 250) - maximum amount of characters per line (0 = disable)
|
||||
brace_style (default "collapse") - "collapse" | "expand" | "end-expand" | "none"
|
||||
put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line, or attempt to keep them where they are.
|
||||
unformatted (defaults to inline tags) - list of tags, that shouldn't be reformatted
|
||||
indent_scripts (default normal) - "keep"|"separate"|"normal"
|
||||
preserve_newlines (default true) - whether existing line breaks before elements should be preserved
|
||||
Only works before elements, not inside tags or for text.
|
||||
max_preserve_newlines (default unlimited) - maximum number of line breaks to be preserved in one chunk
|
||||
indent_handlebars (default false) - format and indent {{#foo}} and {{/foo}}
|
||||
end_with_newline (false) - end with a newline
|
||||
extra_liners (default [head,body,/html]) -List of tags that should have an extra newline before them.
|
||||
|
||||
e.g.
|
||||
|
||||
style_html(html_source, {
|
||||
'indent_inner_html': false,
|
||||
'indent_size': 2,
|
||||
'indent_char': ' ',
|
||||
'wrap_line_length': 78,
|
||||
'brace_style': 'expand',
|
||||
'unformatted': ['a', 'sub', 'sup', 'b', 'i', 'u'],
|
||||
'preserve_newlines': true,
|
||||
'max_preserve_newlines': 5,
|
||||
'indent_handlebars': false,
|
||||
'extra_liners': ['/html']
|
||||
});
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
||||
function trim(s) {
|
||||
return s.replace(/^\s+|\s+$/g, '');
|
||||
}
|
||||
|
||||
function ltrim(s) {
|
||||
return s.replace(/^\s+/g, '');
|
||||
}
|
||||
|
||||
function rtrim(s) {
|
||||
return s.replace(/\s+$/g,'');
|
||||
}
|
||||
|
||||
function style_html(html_source, options, js_beautify, css_beautify) {
|
||||
//Wrapper function to invoke all the necessary constructors and deal with the output.
|
||||
|
||||
var multi_parser,
|
||||
indent_inner_html,
|
||||
indent_size,
|
||||
indent_character,
|
||||
wrap_line_length,
|
||||
brace_style,
|
||||
unformatted,
|
||||
preserve_newlines,
|
||||
max_preserve_newlines,
|
||||
indent_handlebars,
|
||||
wrap_attributes,
|
||||
wrap_attributes_indent_size,
|
||||
end_with_newline,
|
||||
extra_liners,
|
||||
eol;
|
||||
|
||||
options = options || {};
|
||||
|
||||
// backwards compatibility to 1.3.4
|
||||
if ((options.wrap_line_length === undefined || parseInt(options.wrap_line_length, 10) === 0) &&
|
||||
(options.max_char !== undefined && parseInt(options.max_char, 10) !== 0)) {
|
||||
options.wrap_line_length = options.max_char;
|
||||
}
|
||||
|
||||
indent_inner_html = (options.indent_inner_html === undefined) ? false : options.indent_inner_html;
|
||||
indent_size = (options.indent_size === undefined) ? 4 : parseInt(options.indent_size, 10);
|
||||
indent_character = (options.indent_char === undefined) ? ' ' : options.indent_char;
|
||||
brace_style = (options.brace_style === undefined) ? 'collapse' : options.brace_style;
|
||||
wrap_line_length = parseInt(options.wrap_line_length, 10) === 0 ? 32786 : parseInt(options.wrap_line_length || 250, 10);
|
||||
unformatted = options.unformatted || ['a', 'span', 'img', 'bdo', 'em', 'strong', 'dfn', 'code', 'samp', 'kbd',
|
||||
'var', 'cite', 'abbr', 'acronym', 'q', 'sub', 'sup', 'tt', 'i', 'b', 'big', 'small', 'u', 's', 'strike',
|
||||
'font', 'ins', 'del', 'pre', 'address', 'dt', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
|
||||
preserve_newlines = (options.preserve_newlines === undefined) ? true : options.preserve_newlines;
|
||||
max_preserve_newlines = preserve_newlines ?
|
||||
(isNaN(parseInt(options.max_preserve_newlines, 10)) ? 32786 : parseInt(options.max_preserve_newlines, 10))
|
||||
: 0;
|
||||
indent_handlebars = (options.indent_handlebars === undefined) ? false : options.indent_handlebars;
|
||||
wrap_attributes = (options.wrap_attributes === undefined) ? 'auto' : options.wrap_attributes;
|
||||
wrap_attributes_indent_size = (options.wrap_attributes_indent_size === undefined) ? indent_size : parseInt(options.wrap_attributes_indent_size, 10) || indent_size;
|
||||
end_with_newline = (options.end_with_newline === undefined) ? false : options.end_with_newline;
|
||||
extra_liners = (typeof options.extra_liners == 'object') && options.extra_liners ?
|
||||
options.extra_liners.concat() : (typeof options.extra_liners === 'string') ?
|
||||
options.extra_liners.split(',') : 'head,body,/html'.split(',');
|
||||
eol = options.eol ? options.eol : '\n';
|
||||
|
||||
if(options.indent_with_tabs){
|
||||
indent_character = '\t';
|
||||
indent_size = 1;
|
||||
}
|
||||
|
||||
eol = eol.replace(/\\r/, '\r').replace(/\\n/, '\n')
|
||||
|
||||
function Parser() {
|
||||
|
||||
this.pos = 0; //Parser position
|
||||
this.token = '';
|
||||
this.current_mode = 'CONTENT'; //reflects the current Parser mode: TAG/CONTENT
|
||||
this.tags = { //An object to hold tags, their position, and their parent-tags, initiated with default values
|
||||
parent: 'parent1',
|
||||
parentcount: 1,
|
||||
parent1: ''
|
||||
};
|
||||
this.tag_type = '';
|
||||
this.token_text = this.last_token = this.last_text = this.token_type = '';
|
||||
this.newlines = 0;
|
||||
this.indent_content = indent_inner_html;
|
||||
|
||||
this.Utils = { //Uilities made available to the various functions
|
||||
whitespace: "\n\r\t ".split(''),
|
||||
single_token: 'br,input,link,meta,source,!doctype,basefont,base,area,hr,wbr,param,img,isindex,embed'.split(','), //all the single tags for HTML
|
||||
extra_liners: extra_liners, //for tags that need a line of whitespace before them
|
||||
in_array: function(what, arr) {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (what === arr[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Return true if the given text is composed entirely of whitespace.
|
||||
this.is_whitespace = function(text) {
|
||||
for (var n = 0; n < text.length; text++) {
|
||||
if (!this.Utils.in_array(text.charAt(n), this.Utils.whitespace)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
this.traverse_whitespace = function() {
|
||||
var input_char = '';
|
||||
|
||||
input_char = this.input.charAt(this.pos);
|
||||
if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
|
||||
this.newlines = 0;
|
||||
while (this.Utils.in_array(input_char, this.Utils.whitespace)) {
|
||||
if (preserve_newlines && input_char === '\n' && this.newlines <= max_preserve_newlines) {
|
||||
this.newlines += 1;
|
||||
}
|
||||
|
||||
this.pos++;
|
||||
input_char = this.input.charAt(this.pos);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Append a space to the given content (string array) or, if we are
|
||||
// at the wrap_line_length, append a newline/indentation.
|
||||
this.space_or_wrap = function(content) {
|
||||
if (this.line_char_count >= this.wrap_line_length) { //insert a line when the wrap_line_length is reached
|
||||
this.print_newline(false, content);
|
||||
this.print_indentation(content);
|
||||
} else {
|
||||
this.line_char_count++;
|
||||
content.push(' ');
|
||||
}
|
||||
};
|
||||
|
||||
this.get_content = function() { //function to capture regular content between tags
|
||||
var input_char = '',
|
||||
content = [],
|
||||
space = false; //if a space is needed
|
||||
|
||||
while (this.input.charAt(this.pos) !== '<') {
|
||||
if (this.pos >= this.input.length) {
|
||||
return content.length ? content.join('') : ['', 'TK_EOF'];
|
||||
}
|
||||
|
||||
if (this.traverse_whitespace()) {
|
||||
this.space_or_wrap(content);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (indent_handlebars) {
|
||||
// Handlebars parsing is complicated.
|
||||
// {{#foo}} and {{/foo}} are formatted tags.
|
||||
// {{something}} should get treated as content, except:
|
||||
// {{else}} specifically behaves like {{#if}} and {{/if}}
|
||||
var peek3 = this.input.substr(this.pos, 3);
|
||||
if (peek3 === '{{#' || peek3 === '{{/') {
|
||||
// These are tags and not content.
|
||||
break;
|
||||
} else if (peek3 === '{{!') {
|
||||
return [this.get_tag(), 'TK_TAG_HANDLEBARS_COMMENT'];
|
||||
} else if (this.input.substr(this.pos, 2) === '{{') {
|
||||
if (this.get_tag(true) === '{{else}}') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input_char = this.input.charAt(this.pos);
|
||||
this.pos++;
|
||||
this.line_char_count++;
|
||||
content.push(input_char); //letter at-a-time (or string) inserted to an array
|
||||
}
|
||||
return content.length ? content.join('') : '';
|
||||
};
|
||||
|
||||
this.get_contents_to = function(name) { //get the full content of a script or style to pass to js_beautify
|
||||
if (this.pos === this.input.length) {
|
||||
return ['', 'TK_EOF'];
|
||||
}
|
||||
var input_char = '';
|
||||
var content = '';
|
||||
var reg_match = new RegExp('</' + name + '\\s*>', 'igm');
|
||||
reg_match.lastIndex = this.pos;
|
||||
var reg_array = reg_match.exec(this.input);
|
||||
var end_script = reg_array ? reg_array.index : this.input.length; //absolute end of script
|
||||
if (this.pos < end_script) { //get everything in between the script tags
|
||||
content = this.input.substring(this.pos, end_script);
|
||||
this.pos = end_script;
|
||||
}
|
||||
return content;
|
||||
};
|
||||
|
||||
this.record_tag = function(tag) { //function to record a tag and its parent in this.tags Object
|
||||
if (this.tags[tag + 'count']) { //check for the existence of this tag type
|
||||
this.tags[tag + 'count']++;
|
||||
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
|
||||
} else { //otherwise initialize this tag type
|
||||
this.tags[tag + 'count'] = 1;
|
||||
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
|
||||
}
|
||||
this.tags[tag + this.tags[tag + 'count'] + 'parent'] = this.tags.parent; //set the parent (i.e. in the case of a div this.tags.div1parent)
|
||||
this.tags.parent = tag + this.tags[tag + 'count']; //and make this the current parent (i.e. in the case of a div 'div1')
|
||||
};
|
||||
|
||||
this.retrieve_tag = function(tag) { //function to retrieve the opening tag to the corresponding closer
|
||||
if (this.tags[tag + 'count']) { //if the openener is not in the Object we ignore it
|
||||
var temp_parent = this.tags.parent; //check to see if it's a closable tag.
|
||||
while (temp_parent) { //till we reach '' (the initial value);
|
||||
if (tag + this.tags[tag + 'count'] === temp_parent) { //if this is it use it
|
||||
break;
|
||||
}
|
||||
temp_parent = this.tags[temp_parent + 'parent']; //otherwise keep on climbing up the DOM Tree
|
||||
}
|
||||
if (temp_parent) { //if we caught something
|
||||
this.indent_level = this.tags[tag + this.tags[tag + 'count']]; //set the indent_level accordingly
|
||||
this.tags.parent = this.tags[temp_parent + 'parent']; //and set the current parent
|
||||
}
|
||||
delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; //delete the closed tags parent reference...
|
||||
delete this.tags[tag + this.tags[tag + 'count']]; //...and the tag itself
|
||||
if (this.tags[tag + 'count'] === 1) {
|
||||
delete this.tags[tag + 'count'];
|
||||
} else {
|
||||
this.tags[tag + 'count']--;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.indent_to_tag = function(tag) {
|
||||
// Match the indentation level to the last use of this tag, but don't remove it.
|
||||
if (!this.tags[tag + 'count']) {
|
||||
return;
|
||||
}
|
||||
var temp_parent = this.tags.parent;
|
||||
while (temp_parent) {
|
||||
if (tag + this.tags[tag + 'count'] === temp_parent) {
|
||||
break;
|
||||
}
|
||||
temp_parent = this.tags[temp_parent + 'parent'];
|
||||
}
|
||||
if (temp_parent) {
|
||||
this.indent_level = this.tags[tag + this.tags[tag + 'count']];
|
||||
}
|
||||
};
|
||||
|
||||
this.get_tag = function(peek) { //function to get a full tag and parse its type
|
||||
var input_char = '',
|
||||
content = [],
|
||||
comment = '',
|
||||
space = false,
|
||||
first_attr = true,
|
||||
tag_start, tag_end,
|
||||
tag_start_char,
|
||||
orig_pos = this.pos,
|
||||
orig_line_char_count = this.line_char_count;
|
||||
|
||||
peek = peek !== undefined ? peek : false;
|
||||
|
||||
do {
|
||||
if (this.pos >= this.input.length) {
|
||||
if (peek) {
|
||||
this.pos = orig_pos;
|
||||
this.line_char_count = orig_line_char_count;
|
||||
}
|
||||
return content.length ? content.join('') : ['', 'TK_EOF'];
|
||||
}
|
||||
|
||||
input_char = this.input.charAt(this.pos);
|
||||
this.pos++;
|
||||
|
||||
if (this.Utils.in_array(input_char, this.Utils.whitespace)) { //don't want to insert unnecessary space
|
||||
space = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (input_char === "'" || input_char === '"') {
|
||||
input_char += this.get_unformatted(input_char);
|
||||
space = true;
|
||||
|
||||
}
|
||||
|
||||
if (input_char === '=') { //no space before =
|
||||
space = false;
|
||||
}
|
||||
|
||||
if (content.length && content[content.length - 1] !== '=' && input_char !== '>' && space) {
|
||||
//no space after = or before >
|
||||
this.space_or_wrap(content);
|
||||
space = false;
|
||||
if (!first_attr && wrap_attributes === 'force' && input_char !== '/') {
|
||||
this.print_newline(true, content);
|
||||
this.print_indentation(content);
|
||||
for (var count = 0; count < wrap_attributes_indent_size; count++) {
|
||||
content.push(indent_character);
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < content.length; i++) {
|
||||
if (content[i] === ' ') {
|
||||
first_attr = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (indent_handlebars && tag_start_char === '<') {
|
||||
// When inside an angle-bracket tag, put spaces around
|
||||
// handlebars not inside of strings.
|
||||
if ((input_char + this.input.charAt(this.pos)) === '{{') {
|
||||
input_char += this.get_unformatted('}}');
|
||||
if (content.length && content[content.length - 1] !== ' ' && content[content.length - 1] !== '<') {
|
||||
input_char = ' ' + input_char;
|
||||
}
|
||||
space = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (input_char === '<' && !tag_start_char) {
|
||||
tag_start = this.pos - 1;
|
||||
tag_start_char = '<';
|
||||
}
|
||||
|
||||
if (indent_handlebars && !tag_start_char) {
|
||||
if (content.length >= 2 && content[content.length - 1] === '{' && content[content.length - 2] === '{') {
|
||||
if (input_char === '#' || input_char === '/' || input_char === '!') {
|
||||
tag_start = this.pos - 3;
|
||||
} else {
|
||||
tag_start = this.pos - 2;
|
||||
}
|
||||
tag_start_char = '{';
|
||||
}
|
||||
}
|
||||
|
||||
this.line_char_count++;
|
||||
content.push(input_char); //inserts character at-a-time (or string)
|
||||
|
||||
if (content[1] && (content[1] === '!' || content[1] === '?' || content[1] === '%')) { //if we're in a comment, do something special
|
||||
// We treat all comments as literals, even more than preformatted tags
|
||||
// we just look for the appropriate close tag
|
||||
content = [this.get_comment(tag_start)];
|
||||
break;
|
||||
}
|
||||
|
||||
if (indent_handlebars && content[1] && content[1] === '{' && content[2] && content[2] === '!') { //if we're in a comment, do something special
|
||||
// We treat all comments as literals, even more than preformatted tags
|
||||
// we just look for the appropriate close tag
|
||||
content = [this.get_comment(tag_start)];
|
||||
break;
|
||||
}
|
||||
|
||||
if (indent_handlebars && tag_start_char === '{' && content.length > 2 && content[content.length - 2] === '}' && content[content.length - 1] === '}') {
|
||||
break;
|
||||
}
|
||||
} while (input_char !== '>');
|
||||
|
||||
var tag_complete = content.join('');
|
||||
var tag_index;
|
||||
var tag_offset;
|
||||
|
||||
if (tag_complete.indexOf(' ') !== -1) { //if there's whitespace, thats where the tag name ends
|
||||
tag_index = tag_complete.indexOf(' ');
|
||||
} else if (tag_complete.charAt(0) === '{') {
|
||||
tag_index = tag_complete.indexOf('}');
|
||||
} else { //otherwise go with the tag ending
|
||||
tag_index = tag_complete.indexOf('>');
|
||||
}
|
||||
if (tag_complete.charAt(0) === '<' || !indent_handlebars) {
|
||||
tag_offset = 1;
|
||||
} else {
|
||||
tag_offset = tag_complete.charAt(2) === '#' ? 3 : 2;
|
||||
}
|
||||
var tag_check = tag_complete.substring(tag_offset, tag_index).toLowerCase();
|
||||
if (tag_complete.charAt(tag_complete.length - 2) === '/' ||
|
||||
this.Utils.in_array(tag_check, this.Utils.single_token)) { //if this tag name is a single tag type (either in the list or has a closing /)
|
||||
if (!peek) {
|
||||
this.tag_type = 'SINGLE';
|
||||
}
|
||||
} else if (indent_handlebars && tag_complete.charAt(0) === '{' && tag_check === 'else') {
|
||||
if (!peek) {
|
||||
this.indent_to_tag('if');
|
||||
this.tag_type = 'HANDLEBARS_ELSE';
|
||||
this.indent_content = true;
|
||||
this.traverse_whitespace();
|
||||
}
|
||||
} else if (this.is_unformatted(tag_check, unformatted)) { // do not reformat the "unformatted" tags
|
||||
comment = this.get_unformatted('</' + tag_check + '>', tag_complete); //...delegate to get_unformatted function
|
||||
content.push(comment);
|
||||
tag_end = this.pos - 1;
|
||||
this.tag_type = 'SINGLE';
|
||||
} else if (tag_check === 'script' &&
|
||||
(tag_complete.search('type') === -1 ||
|
||||
(tag_complete.search('type') > -1 &&
|
||||
tag_complete.search(/\b(text|application)\/(x-)?(javascript|ecmascript|jscript|livescript)/) > -1))) {
|
||||
if (!peek) {
|
||||
this.record_tag(tag_check);
|
||||
this.tag_type = 'SCRIPT';
|
||||
}
|
||||
} else if (tag_check === 'style' &&
|
||||
(tag_complete.search('type') === -1 ||
|
||||
(tag_complete.search('type') > -1 && tag_complete.search('text/css') > -1))) {
|
||||
if (!peek) {
|
||||
this.record_tag(tag_check);
|
||||
this.tag_type = 'STYLE';
|
||||
}
|
||||
} else if (tag_check.charAt(0) === '!') { //peek for <! comment
|
||||
// for comments content is already correct.
|
||||
if (!peek) {
|
||||
this.tag_type = 'SINGLE';
|
||||
this.traverse_whitespace();
|
||||
}
|
||||
} else if (!peek) {
|
||||
if (tag_check.charAt(0) === '/') { //this tag is a double tag so check for tag-ending
|
||||
this.retrieve_tag(tag_check.substring(1)); //remove it and all ancestors
|
||||
this.tag_type = 'END';
|
||||
} else { //otherwise it's a start-tag
|
||||
this.record_tag(tag_check); //push it on the tag stack
|
||||
if (tag_check.toLowerCase() !== 'html') {
|
||||
this.indent_content = true;
|
||||
}
|
||||
this.tag_type = 'START';
|
||||
}
|
||||
|
||||
// Allow preserving of newlines after a start or end tag
|
||||
if (this.traverse_whitespace()) {
|
||||
this.space_or_wrap(content);
|
||||
}
|
||||
|
||||
if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { //check if this double needs an extra line
|
||||
this.print_newline(false, this.output);
|
||||
if (this.output.length && this.output[this.output.length - 2] !== '\n') {
|
||||
this.print_newline(true, this.output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (peek) {
|
||||
this.pos = orig_pos;
|
||||
this.line_char_count = orig_line_char_count;
|
||||
}
|
||||
|
||||
return content.join(''); //returns fully formatted tag
|
||||
};
|
||||
|
||||
this.get_comment = function(start_pos) { //function to return comment content in its entirety
|
||||
// this is will have very poor perf, but will work for now.
|
||||
var comment = '',
|
||||
delimiter = '>',
|
||||
matched = false;
|
||||
|
||||
this.pos = start_pos;
|
||||
input_char = this.input.charAt(this.pos);
|
||||
this.pos++;
|
||||
|
||||
while (this.pos <= this.input.length) {
|
||||
comment += input_char;
|
||||
|
||||
// only need to check for the delimiter if the last chars match
|
||||
if (comment.charAt(comment.length - 1) === delimiter.charAt(delimiter.length - 1) &&
|
||||
comment.indexOf(delimiter) !== -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// only need to search for custom delimiter for the first few characters
|
||||
if (!matched && comment.length < 10) {
|
||||
if (comment.indexOf('<![if') === 0) { //peek for <![if conditional comment
|
||||
delimiter = '<![endif]>';
|
||||
matched = true;
|
||||
} else if (comment.indexOf('<![cdata[') === 0) { //if it's a <[cdata[ comment...
|
||||
delimiter = ']]>';
|
||||
matched = true;
|
||||
} else if (comment.indexOf('<![') === 0) { // some other ![ comment? ...
|
||||
delimiter = ']>';
|
||||
matched = true;
|
||||
} else if (comment.indexOf('<!--') === 0) { // <!-- comment ...
|
||||
delimiter = '-->';
|
||||
matched = true;
|
||||
} else if (comment.indexOf('{{!') === 0) { // {{! handlebars comment
|
||||
delimiter = '}}';
|
||||
matched = true;
|
||||
} else if (comment.indexOf('<?') === 0) { // {{! handlebars comment
|
||||
delimiter = '?>';
|
||||
matched = true;
|
||||
} else if (comment.indexOf('<%') === 0) { // {{! handlebars comment
|
||||
delimiter = '%>';
|
||||
matched = true;
|
||||
}
|
||||
}
|
||||
|
||||
input_char = this.input.charAt(this.pos);
|
||||
this.pos++;
|
||||
}
|
||||
|
||||
return comment;
|
||||
};
|
||||
|
||||
this.get_unformatted = function(delimiter, orig_tag) { //function to return unformatted content in its entirety
|
||||
|
||||
if (orig_tag && orig_tag.toLowerCase().indexOf(delimiter) !== -1) {
|
||||
return '';
|
||||
}
|
||||
var input_char = '';
|
||||
var content = '';
|
||||
var min_index = 0;
|
||||
var space = true;
|
||||
do {
|
||||
|
||||
if (this.pos >= this.input.length) {
|
||||
return content;
|
||||
}
|
||||
|
||||
input_char = this.input.charAt(this.pos);
|
||||
this.pos++;
|
||||
|
||||
if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
|
||||
if (!space) {
|
||||
this.line_char_count--;
|
||||
continue;
|
||||
}
|
||||
if (input_char === '\n' || input_char === '\r') {
|
||||
content += '\n';
|
||||
/* Don't change tab indention for unformatted blocks. If using code for html editing, this will greatly affect <pre> tags if they are specified in the 'unformatted array'
|
||||
for (var i=0; i<this.indent_level; i++) {
|
||||
content += this.indent_string;
|
||||
}
|
||||
space = false; //...and make sure other indentation is erased
|
||||
*/
|
||||
this.line_char_count = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
content += input_char;
|
||||
this.line_char_count++;
|
||||
space = true;
|
||||
|
||||
if (indent_handlebars && input_char === '{' && content.length && content.charAt(content.length - 2) === '{') {
|
||||
// Handlebars expressions in strings should also be unformatted.
|
||||
content += this.get_unformatted('}}');
|
||||
// These expressions are opaque. Ignore delimiters found in them.
|
||||
min_index = content.length;
|
||||
}
|
||||
} while (content.toLowerCase().indexOf(delimiter, min_index) === -1);
|
||||
return content;
|
||||
};
|
||||
|
||||
this.get_token = function() { //initial handler for token-retrieval
|
||||
var token;
|
||||
|
||||
if (this.last_token === 'TK_TAG_SCRIPT' || this.last_token === 'TK_TAG_STYLE') { //check if we need to format javascript
|
||||
var type = this.last_token.substr(7);
|
||||
token = this.get_contents_to(type);
|
||||
if (typeof token !== 'string') {
|
||||
return token;
|
||||
}
|
||||
return [token, 'TK_' + type];
|
||||
}
|
||||
if (this.current_mode === 'CONTENT') {
|
||||
token = this.get_content();
|
||||
if (typeof token !== 'string') {
|
||||
return token;
|
||||
} else {
|
||||
return [token, 'TK_CONTENT'];
|
||||
}
|
||||
}
|
||||
|
||||
if (this.current_mode === 'TAG') {
|
||||
token = this.get_tag();
|
||||
if (typeof token !== 'string') {
|
||||
return token;
|
||||
} else {
|
||||
var tag_name_type = 'TK_TAG_' + this.tag_type;
|
||||
return [token, tag_name_type];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.get_full_indent = function(level) {
|
||||
level = this.indent_level + level || 0;
|
||||
if (level < 1) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return Array(level + 1).join(this.indent_string);
|
||||
};
|
||||
|
||||
this.is_unformatted = function(tag_check, unformatted) {
|
||||
//is this an HTML5 block-level link?
|
||||
if (!this.Utils.in_array(tag_check, unformatted)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tag_check.toLowerCase() !== 'a' || !this.Utils.in_array('a', unformatted)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//at this point we have an tag; is its first child something we want to remain
|
||||
//unformatted?
|
||||
var next_tag = this.get_tag(true /* peek. */ );
|
||||
|
||||
// test next_tag to see if it is just html tag (no external content)
|
||||
var tag = (next_tag || "").match(/^\s*<\s*\/?([a-z]*)\s*[^>]*>\s*$/);
|
||||
|
||||
// if next_tag comes back but is not an isolated tag, then
|
||||
// let's treat the 'a' tag as having content
|
||||
// and respect the unformatted option
|
||||
if (!tag || this.Utils.in_array(tag, unformatted)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
this.printer = function(js_source, indent_character, indent_size, wrap_line_length, brace_style) { //handles input/output and some other printing functions
|
||||
|
||||
this.input = js_source || ''; //gets the input for the Parser
|
||||
|
||||
// HACK: newline parsing inconsistent. This brute force normalizes the input.
|
||||
this.input = this.input.replace(/\r\n|[\r\u2028\u2029]/g, '\n')
|
||||
|
||||
this.output = [];
|
||||
this.indent_character = indent_character;
|
||||
this.indent_string = '';
|
||||
this.indent_size = indent_size;
|
||||
this.brace_style = brace_style;
|
||||
this.indent_level = 0;
|
||||
this.wrap_line_length = wrap_line_length;
|
||||
this.line_char_count = 0; //count to see if wrap_line_length was exceeded
|
||||
|
||||
for (var i = 0; i < this.indent_size; i++) {
|
||||
this.indent_string += this.indent_character;
|
||||
}
|
||||
|
||||
this.print_newline = function(force, arr) {
|
||||
this.line_char_count = 0;
|
||||
if (!arr || !arr.length) {
|
||||
return;
|
||||
}
|
||||
if (force || (arr[arr.length - 1] !== '\n')) { //we might want the extra line
|
||||
if ((arr[arr.length - 1] !== '\n')) {
|
||||
arr[arr.length - 1] = rtrim(arr[arr.length - 1]);
|
||||
}
|
||||
arr.push('\n');
|
||||
}
|
||||
};
|
||||
|
||||
this.print_indentation = function(arr) {
|
||||
for (var i = 0; i < this.indent_level; i++) {
|
||||
arr.push(this.indent_string);
|
||||
this.line_char_count += this.indent_string.length;
|
||||
}
|
||||
};
|
||||
|
||||
this.print_token = function(text) {
|
||||
// Avoid printing initial whitespace.
|
||||
if (this.is_whitespace(text) && !this.output.length) {
|
||||
return;
|
||||
}
|
||||
if (text || text !== '') {
|
||||
if (this.output.length && this.output[this.output.length - 1] === '\n') {
|
||||
this.print_indentation(this.output);
|
||||
text = ltrim(text);
|
||||
}
|
||||
}
|
||||
this.print_token_raw(text);
|
||||
};
|
||||
|
||||
this.print_token_raw = function(text) {
|
||||
// If we are going to print newlines, truncate trailing
|
||||
// whitespace, as the newlines will represent the space.
|
||||
if (this.newlines > 0) {
|
||||
text = rtrim(text);
|
||||
}
|
||||
|
||||
if (text && text !== '') {
|
||||
if (text.length > 1 && text.charAt(text.length - 1) === '\n') {
|
||||
// unformatted tags can grab newlines as their last character
|
||||
this.output.push(text.slice(0, -1));
|
||||
this.print_newline(false, this.output);
|
||||
} else {
|
||||
this.output.push(text);
|
||||
}
|
||||
}
|
||||
|
||||
for (var n = 0; n < this.newlines; n++) {
|
||||
this.print_newline(n > 0, this.output);
|
||||
}
|
||||
this.newlines = 0;
|
||||
};
|
||||
|
||||
this.indent = function() {
|
||||
this.indent_level++;
|
||||
};
|
||||
|
||||
this.unindent = function() {
|
||||
if (this.indent_level > 0) {
|
||||
this.indent_level--;
|
||||
}
|
||||
};
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/*_____________________--------------------_____________________*/
|
||||
|
||||
multi_parser = new Parser(); //wrapping functions Parser
|
||||
multi_parser.printer(html_source, indent_character, indent_size, wrap_line_length, brace_style); //initialize starting values
|
||||
|
||||
while (true) {
|
||||
var t = multi_parser.get_token();
|
||||
multi_parser.token_text = t[0];
|
||||
multi_parser.token_type = t[1];
|
||||
|
||||
if (multi_parser.token_type === 'TK_EOF') {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (multi_parser.token_type) {
|
||||
case 'TK_TAG_START':
|
||||
multi_parser.print_newline(false, multi_parser.output);
|
||||
multi_parser.print_token(multi_parser.token_text);
|
||||
if (multi_parser.indent_content) {
|
||||
multi_parser.indent();
|
||||
multi_parser.indent_content = false;
|
||||
}
|
||||
multi_parser.current_mode = 'CONTENT';
|
||||
break;
|
||||
case 'TK_TAG_STYLE':
|
||||
case 'TK_TAG_SCRIPT':
|
||||
multi_parser.print_newline(false, multi_parser.output);
|
||||
multi_parser.print_token(multi_parser.token_text);
|
||||
multi_parser.current_mode = 'CONTENT';
|
||||
break;
|
||||
case 'TK_TAG_END':
|
||||
//Print new line only if the tag has no content and has child
|
||||
if (multi_parser.last_token === 'TK_CONTENT' && multi_parser.last_text === '') {
|
||||
var tag_name = multi_parser.token_text.match(/\w+/)[0];
|
||||
var tag_extracted_from_last_output = null;
|
||||
if (multi_parser.output.length) {
|
||||
tag_extracted_from_last_output = multi_parser.output[multi_parser.output.length - 1].match(/(?:<|{{#)\s*(\w+)/);
|
||||
}
|
||||
if (tag_extracted_from_last_output === null ||
|
||||
(tag_extracted_from_last_output[1] !== tag_name && !multi_parser.Utils.in_array(tag_extracted_from_last_output[1], unformatted))) {
|
||||
multi_parser.print_newline(false, multi_parser.output);
|
||||
}
|
||||
}
|
||||
multi_parser.print_token(multi_parser.token_text);
|
||||
multi_parser.current_mode = 'CONTENT';
|
||||
break;
|
||||
case 'TK_TAG_SINGLE':
|
||||
// Don't add a newline before elements that should remain unformatted.
|
||||
var tag_check = multi_parser.token_text.match(/^\s*<([a-z-]+)/i);
|
||||
if (!tag_check || !multi_parser.Utils.in_array(tag_check[1], unformatted)) {
|
||||
multi_parser.print_newline(false, multi_parser.output);
|
||||
}
|
||||
multi_parser.print_token(multi_parser.token_text);
|
||||
multi_parser.current_mode = 'CONTENT';
|
||||
break;
|
||||
case 'TK_TAG_HANDLEBARS_ELSE':
|
||||
multi_parser.print_token(multi_parser.token_text);
|
||||
if (multi_parser.indent_content) {
|
||||
multi_parser.indent();
|
||||
multi_parser.indent_content = false;
|
||||
}
|
||||
multi_parser.current_mode = 'CONTENT';
|
||||
break;
|
||||
case 'TK_TAG_HANDLEBARS_COMMENT':
|
||||
multi_parser.print_token(multi_parser.token_text);
|
||||
multi_parser.current_mode = 'TAG';
|
||||
break;
|
||||
case 'TK_CONTENT':
|
||||
multi_parser.print_token(multi_parser.token_text);
|
||||
multi_parser.current_mode = 'TAG';
|
||||
break;
|
||||
case 'TK_STYLE':
|
||||
case 'TK_SCRIPT':
|
||||
if (multi_parser.token_text !== '') {
|
||||
multi_parser.print_newline(false, multi_parser.output);
|
||||
var text = multi_parser.token_text,
|
||||
_beautifier,
|
||||
script_indent_level = 1;
|
||||
if (multi_parser.token_type === 'TK_SCRIPT') {
|
||||
_beautifier = typeof js_beautify === 'function' && js_beautify;
|
||||
} else if (multi_parser.token_type === 'TK_STYLE') {
|
||||
_beautifier = typeof css_beautify === 'function' && css_beautify;
|
||||
}
|
||||
|
||||
if (options.indent_scripts === "keep") {
|
||||
script_indent_level = 0;
|
||||
} else if (options.indent_scripts === "separate") {
|
||||
script_indent_level = -multi_parser.indent_level;
|
||||
}
|
||||
|
||||
var indentation = multi_parser.get_full_indent(script_indent_level);
|
||||
if (_beautifier) {
|
||||
|
||||
// call the Beautifier if avaliable
|
||||
var Child_options = function() {
|
||||
this.eol = '\n';
|
||||
};
|
||||
Child_options.prototype = options;
|
||||
var child_options = new Child_options();
|
||||
text = _beautifier(text.replace(/^\s*/, indentation), child_options);
|
||||
} else {
|
||||
// simply indent the string otherwise
|
||||
var white = text.match(/^\s*/)[0];
|
||||
var _level = white.match(/[^\n\r]*$/)[0].split(multi_parser.indent_string).length - 1;
|
||||
var reindent = multi_parser.get_full_indent(script_indent_level - _level);
|
||||
text = text.replace(/^\s*/, indentation)
|
||||
.replace(/\r\n|\r|\n/g, '\n' + reindent)
|
||||
.replace(/\s+$/, '');
|
||||
}
|
||||
if (text) {
|
||||
multi_parser.print_token_raw(text);
|
||||
multi_parser.print_newline(true, multi_parser.output);
|
||||
}
|
||||
}
|
||||
multi_parser.current_mode = 'TAG';
|
||||
break;
|
||||
default:
|
||||
// We should not be getting here but we don't want to drop input on the floor
|
||||
// Just output the text and move on
|
||||
if (multi_parser.token_text !== '') {
|
||||
multi_parser.print_token(multi_parser.token_text);
|
||||
}
|
||||
break;
|
||||
}
|
||||
multi_parser.last_token = multi_parser.token_type;
|
||||
multi_parser.last_text = multi_parser.token_text;
|
||||
}
|
||||
var sweet_code = multi_parser.output.join('').replace(/[\r\n\t ]+$/, '');
|
||||
|
||||
// establish end_with_newline
|
||||
if (end_with_newline) {
|
||||
sweet_code += '\n';
|
||||
}
|
||||
|
||||
if (eol != '\n') {
|
||||
sweet_code = sweet_code.replace(/[\n]/g, eol);
|
||||
}
|
||||
|
||||
return sweet_code;
|
||||
}
|
||||
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// Add support for AMD ( https://github.com/amdjs/amdjs-api/wiki/AMD#defineamd-property- )
|
||||
define(["require", "./beautify", "./beautify-css"], function(requireamd) {
|
||||
var js_beautify = requireamd("./beautify");
|
||||
var css_beautify = requireamd("./beautify-css");
|
||||
|
||||
return {
|
||||
html_beautify: function(html_source, options) {
|
||||
return style_html(html_source, options, js_beautify.js_beautify, css_beautify.css_beautify);
|
||||
}
|
||||
};
|
||||
});
|
||||
} else if (typeof exports !== "undefined") {
|
||||
// Add support for CommonJS. Just put this file somewhere on your require.paths
|
||||
// and you will be able to `var html_beautify = require("beautify").html_beautify`.
|
||||
var js_beautify = require('./beautify.js');
|
||||
var css_beautify = require('./beautify-css.js');
|
||||
|
||||
exports.html_beautify = function(html_source, options) {
|
||||
return style_html(html_source, options, js_beautify.js_beautify, css_beautify.css_beautify);
|
||||
};
|
||||
} else if (typeof window !== "undefined") {
|
||||
// If we're running a web page and don't have either of the above, add our one global
|
||||
window.html_beautify = function(html_source, options) {
|
||||
return style_html(html_source, options, window.js_beautify, window.css_beautify);
|
||||
};
|
||||
} else if (typeof global !== "undefined") {
|
||||
// If we don't even have window, try global.
|
||||
global.html_beautify = function(html_source, options) {
|
||||
return style_html(html_source, options, global.js_beautify, global.css_beautify);
|
||||
};
|
||||
}
|
||||
|
||||
}());
|
||||
2087
gaia/distros/spark/apps/customizer/components/js-beautify/js/lib/beautify.js
Executable file
2087
gaia/distros/spark/apps/customizer/components/js-beautify/js/lib/beautify.js
Executable file
File diff suppressed because it is too large
Load diff
477
gaia/distros/spark/apps/customizer/components/js-beautify/js/lib/cli.js
Executable file
477
gaia/distros/spark/apps/customizer/components/js-beautify/js/lib/cli.js
Executable file
|
|
@ -0,0 +1,477 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2013 Einar Lielmanis and contributors.
|
||||
|
||||
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.
|
||||
|
||||
Js-Beautify Command-line for node.js
|
||||
-------------------------------------
|
||||
|
||||
Written by Daniel Stockman (daniel.stockman@gmail.com)
|
||||
|
||||
*/
|
||||
|
||||
var debug = process.env.DEBUG_JSBEAUTIFY || process.env.JSBEAUTIFY_DEBUG ? function() {
|
||||
console.error.apply(console, arguments);
|
||||
} : function() {};
|
||||
|
||||
var fs = require('fs'),
|
||||
cc = require('config-chain'),
|
||||
beautify = require('../index'),
|
||||
mkdirp = require('mkdirp'),
|
||||
nopt = require('nopt'),
|
||||
path = require('path'),
|
||||
knownOpts = {
|
||||
// Beautifier
|
||||
"indent_size": Number,
|
||||
"indent_char": String,
|
||||
"eol": String,
|
||||
"indent_level": Number,
|
||||
"indent_with_tabs": Boolean,
|
||||
"preserve_newlines": Boolean,
|
||||
"max_preserve_newlines": Number,
|
||||
"space_in_paren": Boolean,
|
||||
"space_in_empty_paren": Boolean,
|
||||
"jslint_happy": Boolean,
|
||||
"space_after_anon_function": Boolean,
|
||||
// TODO: expand-strict is obsolete, now identical to expand. Remove in future version
|
||||
"brace_style": ["collapse", "expand", "end-expand", "expand-strict", "none"],
|
||||
"break_chained_methods": Boolean,
|
||||
"keep_array_indentation": Boolean,
|
||||
"unescape_strings": Boolean,
|
||||
"wrap_line_length": Number,
|
||||
"wrap_attributes": ["auto", "force"],
|
||||
"wrap_attributes_indent_size": Number,
|
||||
"e4x": Boolean,
|
||||
"end_with_newline": Boolean,
|
||||
"comma_first": Boolean,
|
||||
// CSS-only
|
||||
"selector_separator_newline": Boolean,
|
||||
"newline_between_rules": Boolean,
|
||||
// HTML-only
|
||||
"max_char": Number, // obsolete since 1.3.5
|
||||
"unformatted": [String, Array],
|
||||
"indent_inner_html": [Boolean],
|
||||
"indent_scripts": ["keep", "separate", "normal"],
|
||||
"extra_liners": [String, Array],
|
||||
// CLI
|
||||
"version": Boolean,
|
||||
"help": Boolean,
|
||||
"files": [path, Array],
|
||||
"outfile": path,
|
||||
"replace": Boolean,
|
||||
"quiet": Boolean,
|
||||
"type": ["js", "css", "html"],
|
||||
"config": path
|
||||
},
|
||||
// dasherizeShorthands provides { "indent-size": ["--indent_size"] }
|
||||
// translation, allowing more convenient dashes in CLI arguments
|
||||
shortHands = dasherizeShorthands({
|
||||
// Beautifier
|
||||
"s": ["--indent_size"],
|
||||
"c": ["--indent_char"],
|
||||
"e": ["--eol"],
|
||||
"l": ["--indent_level"],
|
||||
"t": ["--indent_with_tabs"],
|
||||
"p": ["--preserve_newlines"],
|
||||
"m": ["--max_preserve_newlines"],
|
||||
"P": ["--space_in_paren"],
|
||||
"E": ["--space_in_empty_paren"],
|
||||
"j": ["--jslint_happy"],
|
||||
"a": ["--space_after_anon_function"],
|
||||
"b": ["--brace_style"],
|
||||
"B": ["--break_chained_methods"],
|
||||
"k": ["--keep_array_indentation"],
|
||||
"x": ["--unescape_strings"],
|
||||
"w": ["--wrap_line_length"],
|
||||
"X": ["--e4x"],
|
||||
"n": ["--end_with_newline"],
|
||||
"C": ["--comma_first"],
|
||||
// CSS-only
|
||||
"L": ["--selector_separator_newline"],
|
||||
"N": ["--newline_between_rules"],
|
||||
// HTML-only
|
||||
"A": ["--wrap_attributes"],
|
||||
"i": ["--wrap_attributes_indent_size"],
|
||||
"W": ["--max_char"], // obsolete since 1.3.5
|
||||
"U": ["--unformatted"],
|
||||
"I": ["--indent_inner_html"],
|
||||
"S": ["--indent_scripts"],
|
||||
"E": ["--extra_liners"],
|
||||
// non-dasherized hybrid shortcuts
|
||||
"good-stuff": [
|
||||
"--keep_array_indentation",
|
||||
"--keep_function_indentation",
|
||||
"--jslint_happy"
|
||||
],
|
||||
"js": ["--type", "js"],
|
||||
"css": ["--type", "css"],
|
||||
"html": ["--type", "html"],
|
||||
// CLI
|
||||
"v": ["--version"],
|
||||
"h": ["--help"],
|
||||
"f": ["--files"],
|
||||
"o": ["--outfile"],
|
||||
"r": ["--replace"],
|
||||
"q": ["--quiet"]
|
||||
// no shorthand for "config"
|
||||
});
|
||||
|
||||
function verifyExists(fullPath) {
|
||||
return fs.existsSync(fullPath) ? fullPath : null;
|
||||
}
|
||||
|
||||
function findRecursive(dir, fileName) {
|
||||
var fullPath = path.join(dir, fileName);
|
||||
var nextDir = path.dirname(dir);
|
||||
var result = verifyExists(fullPath);
|
||||
|
||||
if (!result && (nextDir !== dir)) {
|
||||
result = findRecursive(nextDir, fileName);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function getUserHome() {
|
||||
return process.env.HOME || process.env.USERPROFILE;
|
||||
}
|
||||
|
||||
// var cli = require('js-beautify/cli'); cli.interpret();
|
||||
var interpret = exports.interpret = function(argv, slice) {
|
||||
var parsed = nopt(knownOpts, shortHands, argv, slice);
|
||||
|
||||
if (parsed.version) {
|
||||
console.log(require('../../package.json').version);
|
||||
process.exit(0);
|
||||
} else if (parsed.help) {
|
||||
usage();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
var cfg = cc(
|
||||
parsed,
|
||||
cleanOptions(cc.env('jsbeautify_'), knownOpts),
|
||||
parsed.config,
|
||||
findRecursive(process.cwd(), '.jsbeautifyrc'),
|
||||
verifyExists(path.join(getUserHome() || "", ".jsbeautifyrc")),
|
||||
__dirname + '/../config/defaults.json'
|
||||
).snapshot;
|
||||
|
||||
try {
|
||||
// Verify arguments
|
||||
checkType(cfg);
|
||||
checkFiles(cfg);
|
||||
debug(cfg);
|
||||
|
||||
// Process files synchronously to avoid EMFILE error
|
||||
cfg.files.forEach(processInputSync, {
|
||||
cfg: cfg
|
||||
});
|
||||
} catch (ex) {
|
||||
debug(cfg);
|
||||
// usage(ex);
|
||||
console.error(ex);
|
||||
console.error('Run `' + getScriptName() + ' -h` for help.');
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
// interpret args immediately when called as executable
|
||||
if (require.main === module) {
|
||||
interpret();
|
||||
}
|
||||
|
||||
function usage(err) {
|
||||
var scriptName = getScriptName();
|
||||
var msg = [
|
||||
scriptName + '@' + require('../../package.json').version,
|
||||
'',
|
||||
'CLI Options:',
|
||||
' -f, --file Input file(s) (Pass \'-\' for stdin)',
|
||||
' -r, --replace Write output in-place, replacing input',
|
||||
' -o, --outfile Write output to file (default stdout)',
|
||||
' --config Path to config file',
|
||||
' --type [js|css|html] ["js"]',
|
||||
' -q, --quiet Suppress logging to stdout',
|
||||
' -h, --help Show this help',
|
||||
' -v, --version Show the version',
|
||||
'',
|
||||
'Beautifier Options:',
|
||||
' -s, --indent-size Indentation size [4]',
|
||||
' -c, --indent-char Indentation character [" "]',
|
||||
' -t, --indent-with-tabs Indent with tabs, overrides -s and -c',
|
||||
' -e, --eol Character(s) to use as line terminators. (default newline - "\\n")',
|
||||
' -n, --end-with-newline End output with newline'
|
||||
];
|
||||
|
||||
switch (scriptName.split('-').shift()) {
|
||||
case "js":
|
||||
msg.push(' -l, --indent-level Initial indentation level [0]');
|
||||
msg.push(' -p, --preserve-newlines Preserve line-breaks (--no-preserve-newlines disables)');
|
||||
msg.push(' -m, --max-preserve-newlines Number of line-breaks to be preserved in one chunk [10]');
|
||||
msg.push(' -P, --space-in-paren Add padding spaces within paren, ie. f( a, b )');
|
||||
msg.push(' -E, --space-in-empty-paren Add a single space inside empty paren, ie. f( )');
|
||||
msg.push(' -j, --jslint-happy Enable jslint-stricter mode');
|
||||
msg.push(' -a, --space-after-anon-function Add a space before an anonymous function\'s parens, ie. function ()');
|
||||
msg.push(' -b, --brace-style [collapse|expand|end-expand|none] ["collapse"]');
|
||||
msg.push(' -B, --break-chained-methods Break chained method calls across subsequent lines');
|
||||
msg.push(' -k, --keep-array-indentation Preserve array indentation');
|
||||
msg.push(' -x, --unescape-strings Decode printable characters encoded in xNN notation');
|
||||
msg.push(' -w, --wrap-line-length Wrap lines at next opportunity after N characters [0]');
|
||||
msg.push(' -X, --e4x Pass E4X xml literals through untouched');
|
||||
msg.push(' --good-stuff Warm the cockles of Crockford\'s heart');
|
||||
msg.push(' -C, --comma-first Put commas at the beginning of new line instead of end');
|
||||
break;
|
||||
case "html":
|
||||
msg.push(' -b, --brace-style [collapse|expand|end-expand] ["collapse"]');
|
||||
msg.push(' -I, --indent-inner-html Indent body and head sections. Default is false.');
|
||||
msg.push(' -S, --indent-scripts [keep|separate|normal] ["normal"]');
|
||||
msg.push(' -w, --wrap-line-length Wrap lines at next opportunity after N characters [0]');
|
||||
msg.push(' -A, --wrap-attributes Wrap html tag attributes to new lines [auto|force] ["auto"]');
|
||||
msg.push(' -i, --wrap-attributes-indent-size Indent wrapped tags to after N characters [indent-level]');
|
||||
msg.push(' -p, --preserve-newlines Preserve line-breaks (--no-preserve-newlines disables)');
|
||||
msg.push(' -m, --max-preserve-newlines Number of line-breaks to be preserved in one chunk [10]');
|
||||
msg.push(' -U, --unformatted List of tags (defaults to inline) that should not be reformatted');
|
||||
msg.push(' -E, --extra_liners List of tags (defaults to [head,body,/html] that should have an extra newline');
|
||||
break;
|
||||
case "css":
|
||||
msg.push(' -L, --selector-separator-newline Add a newline between multiple selectors.')
|
||||
msg.push(' -N, --newline-between-rules Add a newline between CSS rules.')
|
||||
}
|
||||
|
||||
if (err) {
|
||||
msg.push(err);
|
||||
msg.push('');
|
||||
console.error(msg.join('\n'));
|
||||
} else {
|
||||
console.log(msg.join('\n'));
|
||||
}
|
||||
}
|
||||
|
||||
// main iterator, {cfg} passed as thisArg of forEach call
|
||||
|
||||
function processInputSync(filepath) {
|
||||
var data = '',
|
||||
config = this.cfg,
|
||||
outfile = config.outfile,
|
||||
input;
|
||||
|
||||
// -o passed with no value overwrites
|
||||
if (outfile === true || config.replace) {
|
||||
outfile = filepath;
|
||||
}
|
||||
|
||||
if (filepath === '-') {
|
||||
input = process.stdin;
|
||||
input.resume();
|
||||
input.setEncoding('utf8');
|
||||
|
||||
input.on('data', function(chunk) {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
input.on('end', function() {
|
||||
makePretty(data, config, outfile, writePretty);
|
||||
});
|
||||
} else {
|
||||
var dir = path.dirname(outfile);
|
||||
mkdirp.sync(dir);
|
||||
data = fs.readFileSync(filepath, 'utf8');
|
||||
makePretty(data, config, outfile, writePretty);
|
||||
}
|
||||
}
|
||||
|
||||
function makePretty(code, config, outfile, callback) {
|
||||
try {
|
||||
var fileType = getOutputType(outfile, config.type);
|
||||
var pretty = beautify[fileType](code, config);
|
||||
|
||||
callback(null, pretty, outfile, config);
|
||||
} catch (ex) {
|
||||
callback(ex);
|
||||
}
|
||||
}
|
||||
|
||||
function writePretty(err, pretty, outfile, config) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (outfile) {
|
||||
if (isFileDifferent(outfile, pretty)) {
|
||||
try {
|
||||
fs.writeFileSync(outfile, pretty, 'utf8');
|
||||
logToStdout('beautified ' + path.relative(process.cwd(), outfile), config);
|
||||
} catch (ex) {
|
||||
onOutputError(ex);
|
||||
}
|
||||
} else {
|
||||
logToStdout('beautified ' + path.relative(process.cwd(), outfile) + ' - unchanged', config);
|
||||
}
|
||||
} else {
|
||||
process.stdout.write(pretty);
|
||||
}
|
||||
}
|
||||
|
||||
function isFileDifferent(filePath, expected) {
|
||||
try {
|
||||
return fs.readFileSync(filePath, 'utf8') !== expected;
|
||||
} catch (ex) {
|
||||
// failing to read is the same as different
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// workaround the fact that nopt.clean doesn't return the object passed in :P
|
||||
|
||||
function cleanOptions(data, types) {
|
||||
nopt.clean(data, types);
|
||||
return data;
|
||||
}
|
||||
|
||||
// error handler for output stream that swallows errors silently,
|
||||
// allowing the loop to continue over unwritable files.
|
||||
|
||||
function onOutputError(err) {
|
||||
if (err.code === 'EACCES') {
|
||||
console.error(err.path + " is not writable. Skipping!");
|
||||
} else {
|
||||
console.error(err);
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// turn "--foo_bar" into "foo-bar"
|
||||
|
||||
function dasherizeFlag(str) {
|
||||
return str.replace(/^\-+/, '').replace(/_/g, '-');
|
||||
}
|
||||
|
||||
// translate weird python underscored keys into dashed argv,
|
||||
// avoiding single character aliases.
|
||||
|
||||
function dasherizeShorthands(hash) {
|
||||
// operate in-place
|
||||
Object.keys(hash).forEach(function(key) {
|
||||
// each key value is an array
|
||||
var val = hash[key][0];
|
||||
// only dasherize one-character shorthands
|
||||
if (key.length === 1 && val.indexOf('_') > -1) {
|
||||
hash[dasherizeFlag(val)] = val;
|
||||
}
|
||||
});
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
function getOutputType(outfile, configType) {
|
||||
if (outfile && /\.(js|css|html)$/.test(outfile)) {
|
||||
return outfile.split('.').pop();
|
||||
}
|
||||
return configType;
|
||||
}
|
||||
|
||||
function getScriptName() {
|
||||
return path.basename(process.argv[1]);
|
||||
}
|
||||
|
||||
function checkType(parsed) {
|
||||
var scriptType = getScriptName().split('-').shift();
|
||||
debug("executable type:", scriptType);
|
||||
|
||||
var parsedType = parsed.type;
|
||||
debug("parsed type:", parsedType);
|
||||
|
||||
if (!parsedType) {
|
||||
debug("type defaulted:", scriptType);
|
||||
parsed.type = scriptType;
|
||||
}
|
||||
}
|
||||
|
||||
function checkFiles(parsed) {
|
||||
var argv = parsed.argv;
|
||||
|
||||
if (!parsed.files) {
|
||||
parsed.files = [];
|
||||
} else {
|
||||
if (argv.cooked.indexOf('-') > -1) {
|
||||
// strip stdin path eagerly added by nopt in '-f -' case
|
||||
parsed.files.some(removeDashedPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (argv.remain.length) {
|
||||
// assume any remaining args are files
|
||||
argv.remain.forEach(function(f) {
|
||||
parsed.files.push(path.resolve(f));
|
||||
});
|
||||
}
|
||||
|
||||
if ('string' === typeof parsed.outfile && !parsed.files.length) {
|
||||
// use outfile as input when no other files passed in args
|
||||
parsed.files.push(parsed.outfile);
|
||||
// operation is now an implicit overwrite
|
||||
parsed.replace = true;
|
||||
}
|
||||
|
||||
if (argv.original.indexOf('-') > -1) {
|
||||
// ensure '-' without '-f' still consumes stdin
|
||||
parsed.files.push('-');
|
||||
}
|
||||
|
||||
if (!parsed.files.length) {
|
||||
throw 'Must define at least one file.';
|
||||
}
|
||||
debug('files.length ' + parsed.files.length);
|
||||
|
||||
parsed.files.forEach(testFilePath);
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function removeDashedPath(filepath, i, arr) {
|
||||
var found = filepath.lastIndexOf('-') === (filepath.length - 1);
|
||||
if (found) {
|
||||
arr.splice(i, 1);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
function testFilePath(filepath) {
|
||||
try {
|
||||
if (filepath !== "-") {
|
||||
fs.statSync(filepath);
|
||||
}
|
||||
} catch (err) {
|
||||
throw 'Unable to open path "' + filepath + '"';
|
||||
}
|
||||
}
|
||||
|
||||
function logToStdout(str, config) {
|
||||
if (typeof config.quiet === "undefined" || !config.quiet) {
|
||||
console.log(str);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
//
|
||||
// simple unpacker/deobfuscator for scripts messed up with javascriptobfuscator.com
|
||||
// written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
//
|
||||
// usage:
|
||||
//
|
||||
// if (JavascriptObfuscator.detect(some_string)) {
|
||||
// var unpacked = JavascriptObfuscator.unpack(some_string);
|
||||
// }
|
||||
//
|
||||
//
|
||||
|
||||
var JavascriptObfuscator = {
|
||||
detect: function (str) {
|
||||
return /^var _0x[a-f0-9]+ ?\= ?\[/.test(str);
|
||||
},
|
||||
|
||||
unpack: function (str) {
|
||||
if (JavascriptObfuscator.detect(str)) {
|
||||
var matches = /var (_0x[a-f\d]+) ?\= ?\[(.*?)\];/.exec(str);
|
||||
if (matches) {
|
||||
var var_name = matches[1];
|
||||
var strings = JavascriptObfuscator._smart_split(matches[2]);
|
||||
str = str.substring(matches[0].length);
|
||||
for (var k in strings) {
|
||||
str = str.replace(new RegExp(var_name + '\\[' + k + '\\]', 'g'),
|
||||
JavascriptObfuscator._fix_quotes(JavascriptObfuscator._unescape(strings[k])));
|
||||
}
|
||||
}
|
||||
}
|
||||
return str;
|
||||
},
|
||||
|
||||
_fix_quotes: function(str) {
|
||||
var matches = /^"(.*)"$/.exec(str);
|
||||
if (matches) {
|
||||
str = matches[1];
|
||||
str = "'" + str.replace(/'/g, "\\'") + "'";
|
||||
}
|
||||
return str;
|
||||
},
|
||||
|
||||
_smart_split: function(str) {
|
||||
var strings = [];
|
||||
var pos = 0;
|
||||
while (pos < str.length) {
|
||||
if (str.charAt(pos) == '"') {
|
||||
// new word
|
||||
var word = '';
|
||||
pos += 1;
|
||||
while (pos < str.length) {
|
||||
if (str.charAt(pos) == '"') {
|
||||
break;
|
||||
}
|
||||
if (str.charAt(pos) == '\\') {
|
||||
word += '\\';
|
||||
pos++;
|
||||
}
|
||||
word += str.charAt(pos);
|
||||
pos++;
|
||||
}
|
||||
strings.push('"' + word + '"');
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
return strings;
|
||||
},
|
||||
|
||||
|
||||
_unescape: function (str) {
|
||||
// inefficient if used repeatedly or on small strings, but wonderful on single large chunk of text
|
||||
for (var i = 32; i < 128; i++) {
|
||||
str = str.replace(new RegExp('\\\\x' + i.toString(16), 'ig'), String.fromCharCode(i));
|
||||
}
|
||||
str = str.replace(/\\x09/g, "\t");
|
||||
return str;
|
||||
},
|
||||
|
||||
run_tests: function (sanity_test) {
|
||||
var t = sanity_test || new SanityTest();
|
||||
|
||||
t.test_function(JavascriptObfuscator._smart_split, "JavascriptObfuscator._smart_split");
|
||||
t.expect('', []);
|
||||
t.expect('"a", "b"', ['"a"', '"b"']);
|
||||
t.expect('"aaa","bbbb"', ['"aaa"', '"bbbb"']);
|
||||
t.expect('"a", "b\\\""', ['"a"', '"b\\\""']);
|
||||
t.test_function(JavascriptObfuscator._unescape, 'JavascriptObfuscator._unescape');
|
||||
t.expect('\\x40', '@');
|
||||
t.expect('\\x10', '\\x10');
|
||||
t.expect('\\x1', '\\x1');
|
||||
t.expect("\\x61\\x62\\x22\\x63\\x64", 'ab"cd');
|
||||
t.test_function(JavascriptObfuscator.detect, 'JavascriptObfuscator.detect');
|
||||
t.expect('', false);
|
||||
t.expect('abcd', false);
|
||||
t.expect('var _0xaaaa', false);
|
||||
t.expect('var _0xaaaa = ["a", "b"]', true);
|
||||
t.expect('var _0xaaaa=["a", "b"]', true);
|
||||
t.expect('var _0x1234=["a","b"]', true);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
//
|
||||
// simple unpacker/deobfuscator for scripts messed up with myobfuscate.com
|
||||
// You really don't want to obfuscate your scripts there: they're tracking
|
||||
// your unpackings, your script gets turned into something like this,
|
||||
// as of 2011-04-25:
|
||||
/*
|
||||
|
||||
var _escape = 'your_script_escaped';
|
||||
var _111 = document.createElement('script');
|
||||
_111.src = 'http://api.www.myobfuscate.com/?getsrc=ok' +
|
||||
'&ref=' + encodeURIComponent(document.referrer) +
|
||||
'&url=' + encodeURIComponent(document.URL);
|
||||
var 000 = document.getElementsByTagName('head')[0];
|
||||
000.appendChild(_111);
|
||||
document.write(unescape(_escape));
|
||||
|
||||
*/
|
||||
//
|
||||
// written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
//
|
||||
// usage:
|
||||
//
|
||||
// if (MyObfuscate.detect(some_string)) {
|
||||
// var unpacked = MyObfuscate.unpack(some_string);
|
||||
// }
|
||||
//
|
||||
//
|
||||
|
||||
var MyObfuscate = {
|
||||
detect: function (str) {
|
||||
if (/^var _?[0O1lI]{3}\=('|\[).*\)\)\);/.test(str)) {
|
||||
return true;
|
||||
}
|
||||
if (/^function _?[0O1lI]{3}\(_/.test(str) && /eval\(/.test(str)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
unpack: function (str) {
|
||||
if (MyObfuscate.detect(str)) {
|
||||
var __eval = eval;
|
||||
try {
|
||||
eval = function (unpacked) {
|
||||
if (MyObfuscate.starts_with(unpacked, 'var _escape')) {
|
||||
// fetch the urlencoded stuff from the script,
|
||||
var matches = /'([^']*)'/.exec(unpacked);
|
||||
var unescaped = unescape(matches[1]);
|
||||
if (MyObfuscate.starts_with(unescaped, '<script>')) {
|
||||
unescaped = unescaped.substr(8, unescaped.length - 8);
|
||||
}
|
||||
if (MyObfuscate.ends_with(unescaped, '</script>')) {
|
||||
unescaped = unescaped.substr(0, unescaped.length - 9);
|
||||
}
|
||||
unpacked = unescaped;
|
||||
}
|
||||
// throw to terminate the script
|
||||
unpacked = "// Unpacker warning: be careful when using myobfuscate.com for your projects:\n" +
|
||||
"// scripts obfuscated by the free online version may call back home.\n" +
|
||||
"\n//\n" + unpacked;
|
||||
throw unpacked;
|
||||
};
|
||||
__eval(str); // should throw
|
||||
} catch (e) {
|
||||
// well, it failed. we'll just return the original, instead of crashing on user.
|
||||
if (typeof e === "string") {
|
||||
str = e;
|
||||
}
|
||||
}
|
||||
eval = __eval;
|
||||
}
|
||||
return str;
|
||||
},
|
||||
|
||||
starts_with: function (str, what) {
|
||||
return str.substr(0, what.length) === what;
|
||||
},
|
||||
|
||||
ends_with: function (str, what) {
|
||||
return str.substr(str.length - what.length, what.length) === what;
|
||||
},
|
||||
|
||||
run_tests: function (sanity_test) {
|
||||
var t = sanity_test || new SanityTest();
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// Unpacker for Dean Edward's p.a.c.k.e.r, a part of javascript beautifier
|
||||
// written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
//
|
||||
// Coincidentally, it can defeat a couple of other eval-based compressors.
|
||||
//
|
||||
// usage:
|
||||
//
|
||||
// if (P_A_C_K_E_R.detect(some_string)) {
|
||||
// var unpacked = P_A_C_K_E_R.unpack(some_string);
|
||||
// }
|
||||
//
|
||||
//
|
||||
|
||||
var P_A_C_K_E_R = {
|
||||
detect: function (str) {
|
||||
return (P_A_C_K_E_R.get_chunks(str).length > 0);
|
||||
},
|
||||
|
||||
get_chunks: function(str) {
|
||||
var chunks = str.match(/eval\(\(?function\(.*?(,0,\{\}\)\)|split\('\|'\)\)\))($|\n)/g);
|
||||
return chunks ? chunks : [];
|
||||
},
|
||||
|
||||
unpack: function (str) {
|
||||
var chunks = P_A_C_K_E_R.get_chunks(str),
|
||||
chunk;
|
||||
for(var i = 0; i < chunks.length; i++) {
|
||||
chunk = chunks[i].replace(/\n$/, '');
|
||||
str = str.split(chunk).join( P_A_C_K_E_R.unpack_chunk(chunk) );
|
||||
}
|
||||
return str;
|
||||
},
|
||||
|
||||
unpack_chunk: function (str) {
|
||||
var unpacked_source = '';
|
||||
var __eval = eval;
|
||||
if (P_A_C_K_E_R.detect(str)) {
|
||||
try {
|
||||
eval = function (s) { unpacked_source += s; return unpacked_source; };
|
||||
__eval(str);
|
||||
if (typeof unpacked_source == 'string' && unpacked_source) {
|
||||
str = unpacked_source;
|
||||
}
|
||||
} catch (e) {
|
||||
// well, it failed. we'll just return the original, instead of crashing on user.
|
||||
}
|
||||
}
|
||||
eval = __eval;
|
||||
return str;
|
||||
},
|
||||
|
||||
run_tests: function (sanity_test) {
|
||||
var t = sanity_test || new SanityTest(),
|
||||
|
||||
pk1 = "eval(function(p,a,c,k,e,r){e=String;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('0 2=1',3,3,'var||a'.split('|'),0,{}))",
|
||||
unpk1 = 'var a=1',
|
||||
pk2 = "eval(function(p,a,c,k,e,r){e=String;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('0 2=1',3,3,'foo||b'.split('|'),0,{}))",
|
||||
unpk2 = 'foo b=1',
|
||||
pk_broken = "eval(function(p,a,c,k,e,r){BORKBORK;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('0 2=1',3,3,'var||a'.split('|'),0,{}))";
|
||||
pk3 = "eval(function(p,a,c,k,e,r){e=String;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('0 2=1{}))',3,3,'var||a'.split('|'),0,{}))",
|
||||
unpk3 = 'var a=1{}))',
|
||||
|
||||
t.test_function(P_A_C_K_E_R.detect, "P_A_C_K_E_R.detect");
|
||||
t.expect('', false);
|
||||
t.expect('var a = b', false);
|
||||
t.test_function(P_A_C_K_E_R.unpack, "P_A_C_K_E_R.unpack");
|
||||
t.expect(pk_broken, pk_broken);
|
||||
t.expect(pk1, unpk1);
|
||||
t.expect(pk2, unpk2);
|
||||
t.expect(pk3, unpk3);
|
||||
|
||||
var filler = '\nfiller\n';
|
||||
t.expect(filler + pk1 + "\n" + pk_broken + filler + pk2 + filler, filler + unpk1 + "\n" + pk_broken + filler + unpk2 + filler);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*global unescape */
|
||||
/*jshint curly: false, scripturl: true */
|
||||
//
|
||||
// trivial bookmarklet/escaped script detector for the javascript beautifier
|
||||
// written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
//
|
||||
// usage:
|
||||
//
|
||||
// if (Urlencoded.detect(some_string)) {
|
||||
// var unpacked = Urlencoded.unpack(some_string);
|
||||
// }
|
||||
//
|
||||
//
|
||||
|
||||
var isNode = (typeof module !== 'undefined' && module.exports);
|
||||
if (isNode) {
|
||||
var SanityTest = require(__dirname + '/../../test/sanitytest');
|
||||
}
|
||||
|
||||
var Urlencoded = {
|
||||
detect: function (str) {
|
||||
// the fact that script doesn't contain any space, but has %20 instead
|
||||
// should be sufficient check for now.
|
||||
if (str.indexOf(' ') == -1) {
|
||||
if (str.indexOf('%2') != -1) return true;
|
||||
if (str.replace(/[^%]+/g, '').length > 3) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
unpack: function (str) {
|
||||
if (Urlencoded.detect(str)) {
|
||||
if (str.indexOf('%2B') != -1 || str.indexOf('%2b') != -1) {
|
||||
// "+" escaped as "%2B"
|
||||
return unescape(str.replace(/\+/g, '%20'));
|
||||
} else {
|
||||
return unescape(str);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
},
|
||||
|
||||
|
||||
|
||||
run_tests: function (sanity_test) {
|
||||
var t = sanity_test || new SanityTest();
|
||||
t.test_function(Urlencoded.detect, "Urlencoded.detect");
|
||||
t.expect('', false);
|
||||
t.expect('var a = b', false);
|
||||
t.expect('var%20a+=+b', true);
|
||||
t.expect('var%20a=b', true);
|
||||
t.expect('var%20%21%22', true);
|
||||
t.expect('javascript:(function(){var%20whatever={init:function(){alert(%22a%22+%22b%22)}};whatever.init()})();', true);
|
||||
t.test_function(Urlencoded.unpack, 'Urlencoded.unpack');
|
||||
|
||||
t.expect('javascript:(function(){var%20whatever={init:function(){alert(%22a%22+%22b%22)}};whatever.init()})();',
|
||||
'javascript:(function(){var whatever={init:function(){alert("a"+"b")}};whatever.init()})();'
|
||||
);
|
||||
t.expect('', '');
|
||||
t.expect('abcd', 'abcd');
|
||||
t.expect('var a = b', 'var a = b');
|
||||
t.expect('var%20a=b', 'var a=b');
|
||||
t.expect('var%20a=b+1', 'var a=b+1');
|
||||
t.expect('var%20a=b%2b1', 'var a=b+1');
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
if (isNode) {
|
||||
module.exports = Urlencoded;
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*global js_beautify: true */
|
||||
/*jshint node:true */
|
||||
|
||||
var requirejs = require('requirejs'),
|
||||
SanityTest = require('./sanitytest'),
|
||||
Urlencoded = require('../lib/unpackers/urlencode_unpacker'),
|
||||
run_javascript_tests = require('./beautify-javascript-tests').run_javascript_tests,
|
||||
run_css_tests = require('./beautify-css-tests').run_css_tests,
|
||||
run_html_tests = require('./beautify-html-tests').run_html_tests;
|
||||
|
||||
requirejs.config({
|
||||
paths: {
|
||||
'beautify': "..",
|
||||
'beautify-lib': "../lib"
|
||||
}
|
||||
});
|
||||
|
||||
function amd_beautifier_index_tests(name, test_runner) {
|
||||
console.log('Testing ' + name + ' with node.js Require.js (index file)...');
|
||||
var results = new SanityTest();
|
||||
var beautify = requirejs('beautify/index');
|
||||
|
||||
test_runner(
|
||||
results,
|
||||
Urlencoded,
|
||||
beautify.js,
|
||||
beautify.html,
|
||||
beautify.css);
|
||||
|
||||
console.log(results.results_raw());
|
||||
return results;
|
||||
}
|
||||
|
||||
function amd_beautifier_tests(name, test_runner) {
|
||||
console.log('Testing ' + name + ' with node.js Require.js (separate file)...');
|
||||
var results = new SanityTest();
|
||||
var js_beautify = requirejs('beautify-lib/beautify'),
|
||||
css_beautify = requirejs('beautify-lib/beautify-css'),
|
||||
html_beautify = requirejs('beautify-lib/beautify-html');
|
||||
|
||||
test_runner(
|
||||
results,
|
||||
Urlencoded,
|
||||
js_beautify.js_beautify,
|
||||
html_beautify.html_beautify,
|
||||
css_beautify.css_beautify);
|
||||
|
||||
console.log(results.results_raw());
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (require.main === module) {
|
||||
process.exit(
|
||||
amd_beautifier_tests('js-beautifier', run_javascript_tests).get_exitcode() +
|
||||
amd_beautifier_index_tests('js-beautifier', run_javascript_tests).get_exitcode() +
|
||||
amd_beautifier_tests('cs-beautifier', run_css_tests).get_exitcode() +
|
||||
amd_beautifier_index_tests('css-beautifier', run_css_tests).get_exitcode() +
|
||||
amd_beautifier_tests('html-beautifier', run_html_tests).get_exitcode() +
|
||||
amd_beautifier_index_tests('html-beautifier', run_html_tests).get_exitcode()
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,335 @@
|
|||
/*global js_beautify: true */
|
||||
|
||||
function run_css_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_beautify)
|
||||
{
|
||||
|
||||
var opts = {
|
||||
indent_size: 4,
|
||||
indent_char: ' ',
|
||||
preserve_newlines: true,
|
||||
jslint_happy: false,
|
||||
keep_array_indentation: false,
|
||||
brace_style: 'collapse',
|
||||
space_before_conditional: true,
|
||||
break_chained_methods: false,
|
||||
selector_separator: '\n',
|
||||
end_with_newline: false,
|
||||
newline_between_rules: true
|
||||
};
|
||||
|
||||
function test_css_beautifier(input)
|
||||
{
|
||||
return css_beautify(input, opts);
|
||||
}
|
||||
|
||||
var sanitytest;
|
||||
|
||||
// test the input on beautifier with the current flag settings
|
||||
// does not check the indentation / surroundings as bt() does
|
||||
function test_fragment(input, expected)
|
||||
{
|
||||
expected = expected || expected === '' ? expected : input;
|
||||
sanitytest.expect(input, expected);
|
||||
// if the expected is different from input, run it again
|
||||
// expected output should be unchanged when run twice.
|
||||
if (expected !== input) {
|
||||
sanitytest.expect(expected, expected);
|
||||
}
|
||||
|
||||
// Everywhere we do newlines, they should be replaced with opts.eol
|
||||
opts.eol = '\r\\n';
|
||||
expected = expected.replace(/[\n]/g, '\r\n');
|
||||
sanitytest.expect(input, expected);
|
||||
input = input.replace(/[\n]/g, '\r\n');
|
||||
sanitytest.expect(input, expected);
|
||||
opts.eol = '\n';
|
||||
}
|
||||
|
||||
// test css
|
||||
function t(input, expectation)
|
||||
{
|
||||
var wrapped_input, wrapped_expectation;
|
||||
|
||||
expectation = expectation || expectation === '' ? expectation : input;
|
||||
sanitytest.test_function(test_css_beautifier, 'css_beautify');
|
||||
test_fragment(input, expectation);
|
||||
}
|
||||
|
||||
function unicode_char(value) {
|
||||
return String.fromCharCode(value)
|
||||
}
|
||||
|
||||
function beautifier_tests()
|
||||
{
|
||||
sanitytest = test_obj;
|
||||
|
||||
t(".tabs {}");
|
||||
|
||||
opts.indent_size = 1;
|
||||
opts.indent_char = '\t';
|
||||
opts.selector_separator_newline = true;
|
||||
opts.end_with_newline = false;
|
||||
opts.newline_between_rules = false;
|
||||
|
||||
// End With Newline - (eof = "\n")
|
||||
opts.end_with_newline = true;
|
||||
test_fragment('', '\n');
|
||||
test_fragment(' .tabs{}', ' .tabs {}\n');
|
||||
test_fragment(' \n\n.tabs{}\n\n\n\n', ' .tabs {}\n');
|
||||
test_fragment('\n');
|
||||
|
||||
// End With Newline - (eof = "")
|
||||
opts.end_with_newline = false;
|
||||
test_fragment('');
|
||||
test_fragment(' .tabs{}', ' .tabs {}');
|
||||
test_fragment(' \n\n.tabs{}\n\n\n\n', ' .tabs {}');
|
||||
test_fragment('\n', '');
|
||||
|
||||
// Empty braces
|
||||
t('.tabs{}', '.tabs {}');
|
||||
t('.tabs { }', '.tabs {}');
|
||||
t('.tabs { }', '.tabs {}');
|
||||
t('.tabs \n{\n \n }', '.tabs {}');
|
||||
|
||||
//
|
||||
t('#cboxOverlay {\n\tbackground: url(images/overlay.png) repeat 0 0;\n\topacity: 0.9;\n\tfilter: alpha(opacity = 90);\n}', '#cboxOverlay {\n\tbackground: url(images/overlay.png) repeat 0 0;\n\topacity: 0.9;\n\tfilter: alpha(opacity=90);\n}');
|
||||
|
||||
// Selector Separator - (separator = " ", separator1 = " ")
|
||||
opts.selector_separator_newline = false;
|
||||
opts.selector_separator = " ";
|
||||
t('#bla, #foo{color:green}', '#bla, #foo {\n\tcolor: green\n}');
|
||||
t('@media print {.tab{}}', '@media print {\n\t.tab {}\n}');
|
||||
t('@media print {.tab,.bat{}}', '@media print {\n\t.tab, .bat {}\n}');
|
||||
t('#bla, #foo{color:black}', '#bla, #foo {\n\tcolor: black\n}');
|
||||
t('a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}', 'a:first-child, a:first-child {\n\tcolor: red;\n\tdiv:first-child, div:hover {\n\t\tcolor: black;\n\t}\n}');
|
||||
|
||||
// Selector Separator - (separator = " ", separator1 = " ")
|
||||
opts.selector_separator_newline = false;
|
||||
opts.selector_separator = " ";
|
||||
t('#bla, #foo{color:green}', '#bla, #foo {\n\tcolor: green\n}');
|
||||
t('@media print {.tab{}}', '@media print {\n\t.tab {}\n}');
|
||||
t('@media print {.tab,.bat{}}', '@media print {\n\t.tab, .bat {}\n}');
|
||||
t('#bla, #foo{color:black}', '#bla, #foo {\n\tcolor: black\n}');
|
||||
t('a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}', 'a:first-child, a:first-child {\n\tcolor: red;\n\tdiv:first-child, div:hover {\n\t\tcolor: black;\n\t}\n}');
|
||||
|
||||
// Selector Separator - (separator = "\n", separator1 = "\n\t")
|
||||
opts.selector_separator_newline = true;
|
||||
opts.selector_separator = " ";
|
||||
t('#bla, #foo{color:green}', '#bla,\n#foo {\n\tcolor: green\n}');
|
||||
t('@media print {.tab{}}', '@media print {\n\t.tab {}\n}');
|
||||
t('@media print {.tab,.bat{}}', '@media print {\n\t.tab,\n\t.bat {}\n}');
|
||||
t('#bla, #foo{color:black}', '#bla,\n#foo {\n\tcolor: black\n}');
|
||||
t('a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}', 'a:first-child,\na:first-child {\n\tcolor: red;\n\tdiv:first-child,\n\tdiv:hover {\n\t\tcolor: black;\n\t}\n}');
|
||||
|
||||
// Selector Separator - (separator = "\n", separator1 = "\n\t")
|
||||
opts.selector_separator_newline = true;
|
||||
opts.selector_separator = " ";
|
||||
t('#bla, #foo{color:green}', '#bla,\n#foo {\n\tcolor: green\n}');
|
||||
t('@media print {.tab{}}', '@media print {\n\t.tab {}\n}');
|
||||
t('@media print {.tab,.bat{}}', '@media print {\n\t.tab,\n\t.bat {}\n}');
|
||||
t('#bla, #foo{color:black}', '#bla,\n#foo {\n\tcolor: black\n}');
|
||||
t('a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}', 'a:first-child,\na:first-child {\n\tcolor: red;\n\tdiv:first-child,\n\tdiv:hover {\n\t\tcolor: black;\n\t}\n}');
|
||||
|
||||
// Newline Between Rules - (separator = "\n")
|
||||
opts.newline_between_rules = true;
|
||||
t('.div {}\n.span {}', '.div {}\n\n.span {}');
|
||||
t('.div{}\n \n.span{}', '.div {}\n\n.span {}');
|
||||
t('.div {} \n \n.span { } \n', '.div {}\n\n.span {}');
|
||||
t('.div {\n \n} \n .span {\n } ', '.div {}\n\n.span {}');
|
||||
t('.selector1 {\n\tmargin: 0; /* This is a comment including an url http://domain.com/path/to/file.ext */\n}\n.div{height:15px;}', '.selector1 {\n\tmargin: 0;\n\t/* This is a comment including an url http://domain.com/path/to/file.ext */\n}\n\n.div {\n\theight: 15px;\n}');
|
||||
t('.tabs{width:10px;//end of line comment\nheight:10px;//another\n}\n.div{height:15px;}', '.tabs {\n\twidth: 10px; //end of line comment\n\theight: 10px; //another\n}\n\n.div {\n\theight: 15px;\n}');
|
||||
t('#foo {\n\tbackground-image: url(foo@2x.png);\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n.div{height:15px;}', '#foo {\n\tbackground-image: url(foo@2x.png);\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n\n.div {\n\theight: 15px;\n}');
|
||||
t('@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n.div{height:15px;}', '@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n\n.div {\n\theight: 15px;\n}');
|
||||
t('@font-face {\n\tfont-family: "Bitstream Vera Serif Bold";\n\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n}\n@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo.png);\n\t}\n\t@media screen and (min-device-pixel-ratio: 2) {\n\t\t@font-face {\n\t\t\tfont-family: "Helvetica Neue"\n\t\t}\n\t\t#foo:hover {\n\t\t\tbackground-image: url(foo@2x.png);\n\t\t}\n\t}\n}', '@font-face {\n\tfont-family: "Bitstream Vera Serif Bold";\n\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n}\n\n@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo.png);\n\t}\n\t@media screen and (min-device-pixel-ratio: 2) {\n\t\t@font-face {\n\t\t\tfont-family: "Helvetica Neue"\n\t\t}\n\t\t#foo:hover {\n\t\t\tbackground-image: url(foo@2x.png);\n\t\t}\n\t}\n}');
|
||||
t('a:first-child{color:red;div:first-child{color:black;}}\n.div{height:15px;}', 'a:first-child {\n\tcolor: red;\n\tdiv:first-child {\n\t\tcolor: black;\n\t}\n}\n\n.div {\n\theight: 15px;\n}');
|
||||
t('a:first-child{color:red;div:not(.peq){color:black;}}\n.div{height:15px;}', 'a:first-child {\n\tcolor: red;\n\tdiv:not(.peq) {\n\t\tcolor: black;\n\t}\n}\n\n.div {\n\theight: 15px;\n}');
|
||||
|
||||
// Newline Between Rules - (separator = "")
|
||||
opts.newline_between_rules = false;
|
||||
t('.div {}\n.span {}');
|
||||
t('.div{}\n \n.span{}', '.div {}\n.span {}');
|
||||
t('.div {} \n \n.span { } \n', '.div {}\n.span {}');
|
||||
t('.div {\n \n} \n .span {\n } ', '.div {}\n.span {}');
|
||||
t('.selector1 {\n\tmargin: 0; /* This is a comment including an url http://domain.com/path/to/file.ext */\n}\n.div{height:15px;}', '.selector1 {\n\tmargin: 0;\n\t/* This is a comment including an url http://domain.com/path/to/file.ext */\n}\n.div {\n\theight: 15px;\n}');
|
||||
t('.tabs{width:10px;//end of line comment\nheight:10px;//another\n}\n.div{height:15px;}', '.tabs {\n\twidth: 10px; //end of line comment\n\theight: 10px; //another\n}\n.div {\n\theight: 15px;\n}');
|
||||
t('#foo {\n\tbackground-image: url(foo@2x.png);\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n.div{height:15px;}', '#foo {\n\tbackground-image: url(foo@2x.png);\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n.div {\n\theight: 15px;\n}');
|
||||
t('@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n.div{height:15px;}', '@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n.div {\n\theight: 15px;\n}');
|
||||
t('@font-face {\n\tfont-family: "Bitstream Vera Serif Bold";\n\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n}\n@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo.png);\n\t}\n\t@media screen and (min-device-pixel-ratio: 2) {\n\t\t@font-face {\n\t\t\tfont-family: "Helvetica Neue"\n\t\t}\n\t\t#foo:hover {\n\t\t\tbackground-image: url(foo@2x.png);\n\t\t}\n\t}\n}');
|
||||
t('a:first-child{color:red;div:first-child{color:black;}}\n.div{height:15px;}', 'a:first-child {\n\tcolor: red;\n\tdiv:first-child {\n\t\tcolor: black;\n\t}\n}\n.div {\n\theight: 15px;\n}');
|
||||
t('a:first-child{color:red;div:not(.peq){color:black;}}\n.div{height:15px;}', 'a:first-child {\n\tcolor: red;\n\tdiv:not(.peq) {\n\t\tcolor: black;\n\t}\n}\n.div {\n\theight: 15px;\n}');
|
||||
|
||||
// Functions braces
|
||||
t('.tabs(){}', '.tabs() {}');
|
||||
t('.tabs (){}', '.tabs () {}');
|
||||
t('.tabs (pa, pa(1,2)), .cols { }', '.tabs (pa, pa(1, 2)),\n.cols {}');
|
||||
t('.tabs(pa, pa(1,2)), .cols { }', '.tabs(pa, pa(1, 2)),\n.cols {}');
|
||||
t('.tabs ( ) { }', '.tabs () {}');
|
||||
t('.tabs( ) { }', '.tabs() {}');
|
||||
t('.tabs (t, t2) \n{\n key: val(p1 ,p2); \n }', '.tabs (t, t2) {\n\tkey: val(p1, p2);\n}');
|
||||
t('.box-shadow(@shadow: 0 1px 3px rgba(0, 0, 0, .25)) {\n\t-webkit-box-shadow: @shadow;\n\t-moz-box-shadow: @shadow;\n\tbox-shadow: @shadow;\n}');
|
||||
|
||||
// Comments
|
||||
t('/* test */');
|
||||
t('.tabs{/* test */}', '.tabs {\n\t/* test */\n}');
|
||||
t('.tabs{/* test */}', '.tabs {\n\t/* test */\n}');
|
||||
t('/* header */.tabs {}', '/* header */\n\n.tabs {}');
|
||||
t('.tabs {\n/* non-header */\nwidth:10px;}', '.tabs {\n\t/* non-header */\n\twidth: 10px;\n}');
|
||||
t('/* header');
|
||||
t('// comment');
|
||||
t('.selector1 {\n\tmargin: 0; /* This is a comment including an url http://domain.com/path/to/file.ext */\n}', '.selector1 {\n\tmargin: 0;\n\t/* This is a comment including an url http://domain.com/path/to/file.ext */\n}');
|
||||
|
||||
// single line comment support (less/sass)
|
||||
t('.tabs{\n// comment\nwidth:10px;\n}', '.tabs {\n\t// comment\n\twidth: 10px;\n}');
|
||||
t('.tabs{// comment\nwidth:10px;\n}', '.tabs {\n\t// comment\n\twidth: 10px;\n}');
|
||||
t('//comment\n.tabs{width:10px;}', '//comment\n.tabs {\n\twidth: 10px;\n}');
|
||||
t('.tabs{//comment\n//2nd single line comment\nwidth:10px;}', '.tabs {\n\t//comment\n\t//2nd single line comment\n\twidth: 10px;\n}');
|
||||
t('.tabs{width:10px;//end of line comment\n}', '.tabs {\n\twidth: 10px; //end of line comment\n}');
|
||||
t('.tabs{width:10px;//end of line comment\nheight:10px;}', '.tabs {\n\twidth: 10px; //end of line comment\n\theight: 10px;\n}');
|
||||
t('.tabs{width:10px;//end of line comment\nheight:10px;//another\n}', '.tabs {\n\twidth: 10px; //end of line comment\n\theight: 10px; //another\n}');
|
||||
|
||||
// Psuedo-classes vs Variables
|
||||
t('@page :first {}');
|
||||
|
||||
// Assume the colon goes with the @name. If we're in LESS, this is required regardless of the at-string.
|
||||
t('@page:first {}', '@page: first {}');
|
||||
t('@page: first {}');
|
||||
|
||||
// SASS/SCSS
|
||||
|
||||
// Basic Interpolation
|
||||
t('p {\n\t$font-size: 12px;\n\t$line-height: 30px;\n\tfont: #{$font-size}/#{$line-height};\n}');
|
||||
t('p.#{$name} {}');
|
||||
t(
|
||||
'@mixin itemPropertiesCoverItem($items, $margin) {\n' +
|
||||
'\twidth: calc((100% - ((#{$items} - 1) * #{$margin}rem)) / #{$items});\n' +
|
||||
'\tmargin: 1.6rem #{$margin}rem 1.6rem 0;\n' +
|
||||
'}');
|
||||
|
||||
//
|
||||
|
||||
// test basic css beautifier
|
||||
t(".tabs {}");
|
||||
t(".tabs{color:red;}", ".tabs {\n\tcolor: red;\n}");
|
||||
t(".tabs{color:rgb(255, 255, 0)}", ".tabs {\n\tcolor: rgb(255, 255, 0)\n}");
|
||||
t(".tabs{background:url('back.jpg')}", ".tabs {\n\tbackground: url('back.jpg')\n}");
|
||||
t("#bla, #foo{color:red}", "#bla,\n#foo {\n\tcolor: red\n}");
|
||||
t("@media print {.tab{}}", "@media print {\n\t.tab {}\n}");
|
||||
t("@media print {.tab{background-image:url(foo@2x.png)}}", "@media print {\n\t.tab {\n\t\tbackground-image: url(foo@2x.png)\n\t}\n}");
|
||||
|
||||
t("a:before {\n" +
|
||||
"\tcontent: 'a{color:black;}\"\"\\'\\'\"\\n\\n\\na{color:black}\';\n" +
|
||||
"}");
|
||||
|
||||
//lead-in whitespace determines base-indent.
|
||||
// lead-in newlines are stripped.
|
||||
t("\n\na, img {padding: 0.2px}", "a,\nimg {\n\tpadding: 0.2px\n}");
|
||||
t(" a, img {padding: 0.2px}", " a,\n img {\n \tpadding: 0.2px\n }");
|
||||
t(" \t \na, img {padding: 0.2px}", " \t a,\n \t img {\n \t \tpadding: 0.2px\n \t }");
|
||||
t("\n\n a, img {padding: 0.2px}", "a,\nimg {\n\tpadding: 0.2px\n}");
|
||||
|
||||
// separate selectors
|
||||
t("#bla, #foo{color:red}", "#bla,\n#foo {\n\tcolor: red\n}");
|
||||
t("a, img {padding: 0.2px}", "a,\nimg {\n\tpadding: 0.2px\n}");
|
||||
|
||||
// block nesting
|
||||
t("#foo {\n\tbackground-image: url(foo@2x.png);\n\t@font-face {\n\t\tfont-family: 'Bitstream Vera Serif Bold';\n\t\tsrc: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');\n\t}\n}");
|
||||
t("@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n\t@font-face {\n\t\tfont-family: 'Bitstream Vera Serif Bold';\n\t\tsrc: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');\n\t}\n}");
|
||||
/*
|
||||
@font-face {
|
||||
font-family: 'Bitstream Vera Serif Bold';
|
||||
src: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');
|
||||
}
|
||||
@media screen {
|
||||
#foo:hover {
|
||||
background-image: url(foo.png);
|
||||
}
|
||||
@media screen and (min-device-pixel-ratio: 2) {
|
||||
@font-face {
|
||||
font-family: 'Helvetica Neue'
|
||||
}
|
||||
#foo:hover {
|
||||
background-image: url(foo@2x.png);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
t("@font-face {\n\tfont-family: 'Bitstream Vera Serif Bold';\n\tsrc: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');\n}\n@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo.png);\n\t}\n\t@media screen and (min-device-pixel-ratio: 2) {\n\t\t@font-face {\n\t\t\tfont-family: 'Helvetica Neue'\n\t\t}\n\t\t#foo:hover {\n\t\t\tbackground-image: url(foo@2x.png);\n\t\t}\n\t}\n}");
|
||||
|
||||
// less-css cases
|
||||
t('.well{@well-bg:@bg-color;@well-fg:@fg-color;}','.well {\n\t@well-bg: @bg-color;\n\t@well-fg: @fg-color;\n}');
|
||||
t('.well {&.active {\nbox-shadow: 0 1px 1px @border-color, 1px 0 1px @border-color;}}',
|
||||
'.well {\n' +
|
||||
'\t&.active {\n' +
|
||||
'\t\tbox-shadow: 0 1px 1px @border-color, 1px 0 1px @border-color;\n' +
|
||||
'\t}\n' +
|
||||
'}');
|
||||
t('a {\n' +
|
||||
'\tcolor: blue;\n' +
|
||||
'\t&:hover {\n' +
|
||||
'\t\tcolor: green;\n' +
|
||||
'\t}\n' +
|
||||
'\t& & &&&.active {\n' +
|
||||
'\t\tcolor: green;\n' +
|
||||
'\t}\n' +
|
||||
'}');
|
||||
|
||||
// Not sure if this is sensible
|
||||
// but I believe it is correct to not remove the space in "&: hover".
|
||||
t('a {\n' +
|
||||
'\t&: hover {\n' +
|
||||
'\t\tcolor: green;\n' +
|
||||
'\t}\n' +
|
||||
'}');
|
||||
|
||||
// import
|
||||
t('@import "test";');
|
||||
|
||||
// don't break nested pseudo-classes
|
||||
t("a:first-child{color:red;div:first-child{color:black;}}",
|
||||
"a:first-child {\n\tcolor: red;\n\tdiv:first-child {\n\t\tcolor: black;\n\t}\n}");
|
||||
|
||||
// handle SASS/LESS parent reference
|
||||
t("div{&:first-letter {text-transform: uppercase;}}",
|
||||
"div {\n\t&:first-letter {\n\t\ttext-transform: uppercase;\n\t}\n}");
|
||||
|
||||
//nested modifiers (&:hover etc)
|
||||
t(".tabs{&:hover{width:10px;}}", ".tabs {\n\t&:hover {\n\t\twidth: 10px;\n\t}\n}");
|
||||
t(".tabs{&.big{width:10px;}}", ".tabs {\n\t&.big {\n\t\twidth: 10px;\n\t}\n}");
|
||||
t(".tabs{&>big{width:10px;}}", ".tabs {\n\t&>big {\n\t\twidth: 10px;\n\t}\n}");
|
||||
t(".tabs{&+.big{width:10px;}}", ".tabs {\n\t&+.big {\n\t\twidth: 10px;\n\t}\n}");
|
||||
|
||||
//nested rules
|
||||
t(".tabs{.child{width:10px;}}", ".tabs {\n\t.child {\n\t\twidth: 10px;\n\t}\n}");
|
||||
|
||||
//variables
|
||||
t("@myvar:10px;.tabs{width:10px;}", "@myvar: 10px;\n.tabs {\n\twidth: 10px;\n}");
|
||||
t("@myvar:10px; .tabs{width:10px;}", "@myvar: 10px;\n.tabs {\n\twidth: 10px;\n}");
|
||||
|
||||
// test options
|
||||
opts.indent_size = 2;
|
||||
opts.indent_char = ' ';
|
||||
opts.selector_separator_newline = false;
|
||||
|
||||
// pseudo-classes and pseudo-elements
|
||||
t("#foo:hover {\n background-image: url(foo@2x.png)\n}");
|
||||
t("#foo *:hover {\n color: purple\n}");
|
||||
t("::selection {\n color: #ff0000;\n}");
|
||||
|
||||
// TODO: don't break nested pseduo-classes
|
||||
t("@media screen {.tab,.bat:hover {color:red}}", "@media screen {\n .tab, .bat:hover {\n color: red\n }\n}");
|
||||
|
||||
// particular edge case with braces and semicolons inside tags that allows custom text
|
||||
t("a:not(\"foobar\\\";{}omg\"){\ncontent: 'example\\';{} text';\ncontent: \"example\\\";{} text\";}",
|
||||
"a:not(\"foobar\\\";{}omg\") {\n content: 'example\\';{} text';\n content: \"example\\\";{} text\";\n}");
|
||||
|
||||
// may not eat the space before "["
|
||||
t('html.js [data-custom="123"] {\n opacity: 1.00;\n}');
|
||||
t('html.js *[data-custom="123"] {\n opacity: 1.00;\n}');
|
||||
}
|
||||
|
||||
beautifier_tests();
|
||||
}
|
||||
|
||||
if (typeof exports !== "undefined") {
|
||||
exports.run_css_tests = run_css_tests;
|
||||
}
|
||||
|
|
@ -0,0 +1,736 @@
|
|||
/*global js_beautify: true */
|
||||
|
||||
function run_html_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_beautify)
|
||||
{
|
||||
|
||||
var opts = {
|
||||
indent_size: 4,
|
||||
indent_char: ' ',
|
||||
preserve_newlines: true,
|
||||
jslint_happy: false,
|
||||
keep_array_indentation: false,
|
||||
brace_style: 'collapse',
|
||||
space_before_conditional: true,
|
||||
break_chained_methods: false,
|
||||
selector_separator: '\n',
|
||||
end_with_newline: false
|
||||
};
|
||||
|
||||
function test_html_beautifier(input)
|
||||
{
|
||||
return html_beautify(input, opts);
|
||||
}
|
||||
|
||||
var sanitytest;
|
||||
|
||||
// test the input on beautifier with the current flag settings
|
||||
// does not check the indentation / surroundings as bt() does
|
||||
function test_fragment(input, expected)
|
||||
{
|
||||
expected = expected || expected === '' ? expected : input;
|
||||
sanitytest.expect(input, expected);
|
||||
// if the expected is different from input, run it again
|
||||
// expected output should be unchanged when run twice.
|
||||
if (expected !== input) {
|
||||
sanitytest.expect(expected, expected);
|
||||
}
|
||||
|
||||
// Everywhere we do newlines, they should be replaced with opts.eol
|
||||
opts.eol = '\r\n';
|
||||
expected = expected.replace(/[\n]/g, '\r\n');
|
||||
sanitytest.expect(input, expected);
|
||||
input = input.replace(/[\n]/g, '\r\n');
|
||||
sanitytest.expect(input, expected);
|
||||
opts.eol = '\n';
|
||||
}
|
||||
|
||||
// test html
|
||||
function bth(input, expectation)
|
||||
{
|
||||
var wrapped_input, wrapped_expectation, field_input, field_expectation;
|
||||
|
||||
expectation = expectation || expectation === '' ? expectation : input;
|
||||
sanitytest.test_function(test_html_beautifier, 'html_beautify');
|
||||
test_fragment(input, expectation);
|
||||
|
||||
if (opts.indent_size === 4 && input) {
|
||||
wrapped_input = '<div>\n' + input.replace(/^(.+)$/mg, ' $1') + '\n <span>inline</span>\n</div>';
|
||||
wrapped_expectation = '<div>\n' + expectation.replace(/^(.+)$/mg, ' $1') + '\n <span>inline</span>\n</div>';
|
||||
test_fragment(wrapped_input, wrapped_expectation);
|
||||
}
|
||||
}
|
||||
|
||||
function unicode_char(value) {
|
||||
return String.fromCharCode(value)
|
||||
}
|
||||
|
||||
function beautifier_tests()
|
||||
{
|
||||
sanitytest = test_obj;
|
||||
|
||||
bth('');
|
||||
|
||||
opts.indent_size = 4;
|
||||
opts.indent_char = ' ';
|
||||
opts.indent_with_tabs = false;
|
||||
opts.preserve_newlines = true;
|
||||
opts.jslint_happy = false;
|
||||
opts.keep_array_indentation = false;
|
||||
opts.brace_style = 'collapse';
|
||||
opts.extra_liners = ['html', 'head', '/html'];
|
||||
|
||||
// End With Newline - (eof = "\n")
|
||||
opts.end_with_newline = true;
|
||||
test_fragment('', '\n');
|
||||
test_fragment('<div></div>', '<div></div>\n');
|
||||
test_fragment('\n');
|
||||
|
||||
// End With Newline - (eof = "")
|
||||
opts.end_with_newline = false;
|
||||
test_fragment('');
|
||||
test_fragment('<div></div>');
|
||||
test_fragment('\n', '');
|
||||
|
||||
|
||||
// Custom Extra Liners (empty) - ()
|
||||
opts.extra_liners = [];
|
||||
test_fragment('<html><head><meta></head><body><div><p>x</p></div></body></html>', '<html>\n<head>\n <meta>\n</head>\n<body>\n <div>\n <p>x</p>\n </div>\n</body>\n</html>');
|
||||
|
||||
|
||||
// Custom Extra Liners (default) - ()
|
||||
opts.extra_liners = null;
|
||||
test_fragment('<html><head></head><body></body></html>', '<html>\n\n<head></head>\n\n<body></body>\n\n</html>');
|
||||
|
||||
|
||||
// Custom Extra Liners (p, string) - ()
|
||||
opts.extra_liners = 'p,/p';
|
||||
test_fragment('<html><head><meta></head><body><div><p>x</p></div></body></html>', '<html>\n<head>\n <meta>\n</head>\n<body>\n <div>\n\n <p>x\n\n </p>\n </div>\n</body>\n</html>');
|
||||
|
||||
|
||||
// Custom Extra Liners (p) - ()
|
||||
opts.extra_liners = ['p', '/p'];
|
||||
test_fragment('<html><head><meta></head><body><div><p>x</p></div></body></html>', '<html>\n<head>\n <meta>\n</head>\n<body>\n <div>\n\n <p>x\n\n </p>\n </div>\n</body>\n</html>');
|
||||
|
||||
|
||||
// Attribute Wrap - (eof = "\n", indent_attr = " ", over80 = "\n")
|
||||
opts.wrap_attributes = 'force';
|
||||
test_fragment('<div attr0 attr1="123" data-attr2="hello t here">This is some text</div>', '<div attr0\n attr1="123"\n data-attr2="hello t here">This is some text</div>');
|
||||
test_fragment('<div lookatthissuperduperlongattributenamewhoahcrazy0="true" attr0 attr1="123" data-attr2="hello t here" heymanimreallylongtoowhocomesupwiththesenames="false">This is some text</div>', '<div lookatthissuperduperlongattributenamewhoahcrazy0="true"\n attr0\n attr1="123"\n data-attr2="hello t here"\n heymanimreallylongtoowhocomesupwiththesenames="false">This is some text</div>');
|
||||
test_fragment('<img attr0 attr1="123" data-attr2="hello t here"/>', '<img attr0\n attr1="123"\n data-attr2="hello t here" />');
|
||||
|
||||
// Attribute Wrap - (eof = "\n", indent_attr = " ", over80 = "\n")
|
||||
opts.wrap_attributes = 'force';
|
||||
opts.wrap_line_length = 80;
|
||||
test_fragment('<div attr0 attr1="123" data-attr2="hello t here">This is some text</div>', '<div attr0\n attr1="123"\n data-attr2="hello t here">This is some text</div>');
|
||||
test_fragment('<div lookatthissuperduperlongattributenamewhoahcrazy0="true" attr0 attr1="123" data-attr2="hello t here" heymanimreallylongtoowhocomesupwiththesenames="false">This is some text</div>', '<div lookatthissuperduperlongattributenamewhoahcrazy0="true"\n attr0\n attr1="123"\n data-attr2="hello t here"\n heymanimreallylongtoowhocomesupwiththesenames="false">This is some text</div>');
|
||||
test_fragment('<img attr0 attr1="123" data-attr2="hello t here"/>', '<img attr0\n attr1="123"\n data-attr2="hello t here" />');
|
||||
|
||||
// Attribute Wrap - (eof = "\n", indent_attr = " ", over80 = "\n")
|
||||
opts.wrap_attributes = 'force';
|
||||
opts.wrap_attributes_indent_size = 8;
|
||||
test_fragment('<div attr0 attr1="123" data-attr2="hello t here">This is some text</div>', '<div attr0\n attr1="123"\n data-attr2="hello t here">This is some text</div>');
|
||||
test_fragment('<div lookatthissuperduperlongattributenamewhoahcrazy0="true" attr0 attr1="123" data-attr2="hello t here" heymanimreallylongtoowhocomesupwiththesenames="false">This is some text</div>', '<div lookatthissuperduperlongattributenamewhoahcrazy0="true"\n attr0\n attr1="123"\n data-attr2="hello t here"\n heymanimreallylongtoowhocomesupwiththesenames="false">This is some text</div>');
|
||||
test_fragment('<img attr0 attr1="123" data-attr2="hello t here"/>', '<img attr0\n attr1="123"\n data-attr2="hello t here" />');
|
||||
|
||||
// Attribute Wrap - (eof = " ", indent_attr = "", over80 = "\n")
|
||||
opts.wrap_attributes = 'auto';
|
||||
opts.wrap_line_length = 80;
|
||||
test_fragment('<div attr0 attr1="123" data-attr2="hello t here">This is some text</div>');
|
||||
test_fragment('<div lookatthissuperduperlongattributenamewhoahcrazy0="true" attr0 attr1="123" data-attr2="hello t here" heymanimreallylongtoowhocomesupwiththesenames="false">This is some text</div>', '<div lookatthissuperduperlongattributenamewhoahcrazy0="true" attr0 attr1="123" data-attr2="hello t here"\nheymanimreallylongtoowhocomesupwiththesenames="false">This is some text</div>');
|
||||
test_fragment('<img attr0 attr1="123" data-attr2="hello t here"/>', '<img attr0 attr1="123" data-attr2="hello t here" />');
|
||||
|
||||
// Attribute Wrap - (eof = " ", indent_attr = "", over80 = " ")
|
||||
opts.wrap_attributes = 'auto';
|
||||
opts.wrap_line_length = 0;
|
||||
test_fragment('<div attr0 attr1="123" data-attr2="hello t here">This is some text</div>');
|
||||
test_fragment('<div lookatthissuperduperlongattributenamewhoahcrazy0="true" attr0 attr1="123" data-attr2="hello t here" heymanimreallylongtoowhocomesupwiththesenames="false">This is some text</div>');
|
||||
test_fragment('<img attr0 attr1="123" data-attr2="hello t here"/>', '<img attr0 attr1="123" data-attr2="hello t here" />');
|
||||
|
||||
|
||||
|
||||
// Handlebars Indenting Off
|
||||
opts.indent_handlebars = false;
|
||||
test_fragment(
|
||||
'{{#if 0}}\n <div>\n </div>\n{{/if}}',
|
||||
'{{#if 0}}\n<div>\n</div>\n{{/if}}');
|
||||
test_fragment(
|
||||
'<div>\n{{#each thing}}\n {{name}}\n{{/each}}\n</div>',
|
||||
'<div>\n {{#each thing}} {{name}} {{/each}}\n</div>');
|
||||
|
||||
|
||||
// Handlebars Indenting On - (content = "{{field}}")
|
||||
opts.indent_handlebars = true;
|
||||
test_fragment('{{page-title}}');
|
||||
test_fragment('{{#if 0}}{{/if}}');
|
||||
test_fragment('{{#if 0}}{{field}}{{/if}}');
|
||||
test_fragment('{{#if 0}}\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if words}}{{/if}}',
|
||||
'{{#if words}}{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if words}}{{field}}{{/if}}',
|
||||
'{{#if words}}{{field}}{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if words}}{{field}}{{/if}}',
|
||||
'{{#if words}}{{field}}{{/if}}');
|
||||
test_fragment('{{#if 1}}\n <div>\n </div>\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if 1}}\n<div>\n</div>\n{{/if}}',
|
||||
'{{#if 1}}\n <div>\n </div>\n{{/if}}');
|
||||
test_fragment('<div>\n {{#if 1}}\n {{/if}}\n</div>');
|
||||
test_fragment(
|
||||
'<div>\n{{#if 1}}\n{{/if}}\n</div>',
|
||||
'<div>\n {{#if 1}}\n {{/if}}\n</div>');
|
||||
test_fragment(
|
||||
'{{#if}}\n{{#each}}\n{{#if}}\n{{field}}\n{{/if}}\n{{#if}}\n{{field}}\n{{/if}}\n{{/each}}\n{{/if}}',
|
||||
'{{#if}}\n {{#each}}\n {{#if}}\n {{field}}\n {{/if}}\n {{#if}}\n {{field}}\n {{/if}}\n {{/each}}\n{{/if}}');
|
||||
test_fragment('{{#if 1}}\n <div>\n </div>\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if 1}}\n {{field}}\n {{else}}\n {{field}}\n{{/if}}',
|
||||
'{{#if 1}}\n {{field}}\n{{else}}\n {{field}}\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if 1}}\n {{else}}\n {{/if}}',
|
||||
'{{#if 1}}\n{{else}}\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if thing}}\n{{#if otherthing}}\n {{field}}\n {{else}}\n{{field}}\n {{/if}}\n {{else}}\n{{field}}\n{{/if}}',
|
||||
'{{#if thing}}\n {{#if otherthing}}\n {{field}}\n {{else}}\n {{field}}\n {{/if}}\n{{else}}\n {{field}}\n{{/if}}');
|
||||
test_fragment(
|
||||
'<div{{somestyle}}></div>',
|
||||
'<div {{somestyle}}></div>');
|
||||
test_fragment(
|
||||
'<div{{#if test}}class="foo"{{/if}}>{{field}}</div>',
|
||||
'<div {{#if test}} class="foo" {{/if}}>{{field}}</div>');
|
||||
test_fragment(
|
||||
'<div{{#if thing}}{{somestyle}}class="{{class}}"{{else}}class="{{class2}}"{{/if}}>{{field}}</div>',
|
||||
'<div {{#if thing}} {{somestyle}} class="{{class}}" {{else}} class="{{class2}}" {{/if}}>{{field}}</div>');
|
||||
test_fragment(
|
||||
'<span{{#if condition}}class="foo"{{/if}}>{{field}}</span>',
|
||||
'<span {{#if condition}} class="foo" {{/if}}>{{field}}</span>');
|
||||
test_fragment('<div unformatted="{{#if}}{{field}}{{/if}}">{{field}}</div>');
|
||||
test_fragment('<div unformatted="{{#if }} {{field}}{{/if}}">{{field}}</div>');
|
||||
test_fragment('<div class="{{#if thingIs "value"}}{{field}}{{/if}}"></div>');
|
||||
test_fragment('<div class="{{#if thingIs \'value\'}}{{field}}{{/if}}"></div>');
|
||||
test_fragment('<div class=\'{{#if thingIs "value"}}{{field}}{{/if}}\'></div>');
|
||||
test_fragment('<div class=\'{{#if thingIs \'value\'}}{{field}}{{/if}}\'></div>');
|
||||
|
||||
// Handlebars Indenting On - (content = "{{! comment}}")
|
||||
opts.indent_handlebars = true;
|
||||
test_fragment('{{page-title}}');
|
||||
test_fragment('{{#if 0}}{{/if}}');
|
||||
test_fragment('{{#if 0}}{{! comment}}{{/if}}');
|
||||
test_fragment('{{#if 0}}\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if words}}{{/if}}',
|
||||
'{{#if words}}{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if words}}{{! comment}}{{/if}}',
|
||||
'{{#if words}}{{! comment}}{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if words}}{{! comment}}{{/if}}',
|
||||
'{{#if words}}{{! comment}}{{/if}}');
|
||||
test_fragment('{{#if 1}}\n <div>\n </div>\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if 1}}\n<div>\n</div>\n{{/if}}',
|
||||
'{{#if 1}}\n <div>\n </div>\n{{/if}}');
|
||||
test_fragment('<div>\n {{#if 1}}\n {{/if}}\n</div>');
|
||||
test_fragment(
|
||||
'<div>\n{{#if 1}}\n{{/if}}\n</div>',
|
||||
'<div>\n {{#if 1}}\n {{/if}}\n</div>');
|
||||
test_fragment(
|
||||
'{{#if}}\n{{#each}}\n{{#if}}\n{{! comment}}\n{{/if}}\n{{#if}}\n{{! comment}}\n{{/if}}\n{{/each}}\n{{/if}}',
|
||||
'{{#if}}\n {{#each}}\n {{#if}}\n {{! comment}}\n {{/if}}\n {{#if}}\n {{! comment}}\n {{/if}}\n {{/each}}\n{{/if}}');
|
||||
test_fragment('{{#if 1}}\n <div>\n </div>\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if 1}}\n {{! comment}}\n {{else}}\n {{! comment}}\n{{/if}}',
|
||||
'{{#if 1}}\n {{! comment}}\n{{else}}\n {{! comment}}\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if 1}}\n {{else}}\n {{/if}}',
|
||||
'{{#if 1}}\n{{else}}\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if thing}}\n{{#if otherthing}}\n {{! comment}}\n {{else}}\n{{! comment}}\n {{/if}}\n {{else}}\n{{! comment}}\n{{/if}}',
|
||||
'{{#if thing}}\n {{#if otherthing}}\n {{! comment}}\n {{else}}\n {{! comment}}\n {{/if}}\n{{else}}\n {{! comment}}\n{{/if}}');
|
||||
test_fragment(
|
||||
'<div{{somestyle}}></div>',
|
||||
'<div {{somestyle}}></div>');
|
||||
test_fragment(
|
||||
'<div{{#if test}}class="foo"{{/if}}>{{! comment}}</div>',
|
||||
'<div {{#if test}} class="foo" {{/if}}>{{! comment}}</div>');
|
||||
test_fragment(
|
||||
'<div{{#if thing}}{{somestyle}}class="{{class}}"{{else}}class="{{class2}}"{{/if}}>{{! comment}}</div>',
|
||||
'<div {{#if thing}} {{somestyle}} class="{{class}}" {{else}} class="{{class2}}" {{/if}}>{{! comment}}</div>');
|
||||
test_fragment(
|
||||
'<span{{#if condition}}class="foo"{{/if}}>{{! comment}}</span>',
|
||||
'<span {{#if condition}} class="foo" {{/if}}>{{! comment}}</span>');
|
||||
test_fragment('<div unformatted="{{#if}}{{! comment}}{{/if}}">{{! comment}}</div>');
|
||||
test_fragment('<div unformatted="{{#if }} {{! comment}}{{/if}}">{{! comment}}</div>');
|
||||
test_fragment('<div class="{{#if thingIs "value"}}{{! comment}}{{/if}}"></div>');
|
||||
test_fragment('<div class="{{#if thingIs \'value\'}}{{! comment}}{{/if}}"></div>');
|
||||
test_fragment('<div class=\'{{#if thingIs "value"}}{{! comment}}{{/if}}\'></div>');
|
||||
test_fragment('<div class=\'{{#if thingIs \'value\'}}{{! comment}}{{/if}}\'></div>');
|
||||
|
||||
// Handlebars Indenting On - (content = "{pre{{field1}} {{field2}} {{field3}}post")
|
||||
opts.indent_handlebars = true;
|
||||
test_fragment('{{page-title}}');
|
||||
test_fragment('{{#if 0}}{{/if}}');
|
||||
test_fragment('{{#if 0}}{pre{{field1}} {{field2}} {{field3}}post{{/if}}');
|
||||
test_fragment('{{#if 0}}\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if words}}{{/if}}',
|
||||
'{{#if words}}{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if words}}{pre{{field1}} {{field2}} {{field3}}post{{/if}}',
|
||||
'{{#if words}}{pre{{field1}} {{field2}} {{field3}}post{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if words}}{pre{{field1}} {{field2}} {{field3}}post{{/if}}',
|
||||
'{{#if words}}{pre{{field1}} {{field2}} {{field3}}post{{/if}}');
|
||||
test_fragment('{{#if 1}}\n <div>\n </div>\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if 1}}\n<div>\n</div>\n{{/if}}',
|
||||
'{{#if 1}}\n <div>\n </div>\n{{/if}}');
|
||||
test_fragment('<div>\n {{#if 1}}\n {{/if}}\n</div>');
|
||||
test_fragment(
|
||||
'<div>\n{{#if 1}}\n{{/if}}\n</div>',
|
||||
'<div>\n {{#if 1}}\n {{/if}}\n</div>');
|
||||
test_fragment(
|
||||
'{{#if}}\n{{#each}}\n{{#if}}\n{pre{{field1}} {{field2}} {{field3}}post\n{{/if}}\n{{#if}}\n{pre{{field1}} {{field2}} {{field3}}post\n{{/if}}\n{{/each}}\n{{/if}}',
|
||||
'{{#if}}\n {{#each}}\n {{#if}}\n {pre{{field1}} {{field2}} {{field3}}post\n {{/if}}\n {{#if}}\n {pre{{field1}} {{field2}} {{field3}}post\n {{/if}}\n {{/each}}\n{{/if}}');
|
||||
test_fragment('{{#if 1}}\n <div>\n </div>\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if 1}}\n {pre{{field1}} {{field2}} {{field3}}post\n {{else}}\n {pre{{field1}} {{field2}} {{field3}}post\n{{/if}}',
|
||||
'{{#if 1}}\n {pre{{field1}} {{field2}} {{field3}}post\n{{else}}\n {pre{{field1}} {{field2}} {{field3}}post\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if 1}}\n {{else}}\n {{/if}}',
|
||||
'{{#if 1}}\n{{else}}\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if thing}}\n{{#if otherthing}}\n {pre{{field1}} {{field2}} {{field3}}post\n {{else}}\n{pre{{field1}} {{field2}} {{field3}}post\n {{/if}}\n {{else}}\n{pre{{field1}} {{field2}} {{field3}}post\n{{/if}}',
|
||||
'{{#if thing}}\n {{#if otherthing}}\n {pre{{field1}} {{field2}} {{field3}}post\n {{else}}\n {pre{{field1}} {{field2}} {{field3}}post\n {{/if}}\n{{else}}\n {pre{{field1}} {{field2}} {{field3}}post\n{{/if}}');
|
||||
test_fragment(
|
||||
'<div{{somestyle}}></div>',
|
||||
'<div {{somestyle}}></div>');
|
||||
test_fragment(
|
||||
'<div{{#if test}}class="foo"{{/if}}>{pre{{field1}} {{field2}} {{field3}}post</div>',
|
||||
'<div {{#if test}} class="foo" {{/if}}>{pre{{field1}} {{field2}} {{field3}}post</div>');
|
||||
test_fragment(
|
||||
'<div{{#if thing}}{{somestyle}}class="{{class}}"{{else}}class="{{class2}}"{{/if}}>{pre{{field1}} {{field2}} {{field3}}post</div>',
|
||||
'<div {{#if thing}} {{somestyle}} class="{{class}}" {{else}} class="{{class2}}" {{/if}}>{pre{{field1}} {{field2}} {{field3}}post</div>');
|
||||
test_fragment(
|
||||
'<span{{#if condition}}class="foo"{{/if}}>{pre{{field1}} {{field2}} {{field3}}post</span>',
|
||||
'<span {{#if condition}} class="foo" {{/if}}>{pre{{field1}} {{field2}} {{field3}}post</span>');
|
||||
test_fragment('<div unformatted="{{#if}}{pre{{field1}} {{field2}} {{field3}}post{{/if}}">{pre{{field1}} {{field2}} {{field3}}post</div>');
|
||||
test_fragment('<div unformatted="{{#if }} {pre{{field1}} {{field2}} {{field3}}post{{/if}}">{pre{{field1}} {{field2}} {{field3}}post</div>');
|
||||
test_fragment('<div class="{{#if thingIs "value"}}{pre{{field1}} {{field2}} {{field3}}post{{/if}}"></div>');
|
||||
test_fragment('<div class="{{#if thingIs \'value\'}}{pre{{field1}} {{field2}} {{field3}}post{{/if}}"></div>');
|
||||
test_fragment('<div class=\'{{#if thingIs "value"}}{pre{{field1}} {{field2}} {{field3}}post{{/if}}\'></div>');
|
||||
test_fragment('<div class=\'{{#if thingIs \'value\'}}{pre{{field1}} {{field2}} {{field3}}post{{/if}}\'></div>');
|
||||
|
||||
// Handlebars Indenting On - (content = "{{! \n mult-line\ncomment \n with spacing\n}}")
|
||||
opts.indent_handlebars = true;
|
||||
test_fragment('{{page-title}}');
|
||||
test_fragment('{{#if 0}}{{/if}}');
|
||||
test_fragment('{{#if 0}}{{! \n mult-line\ncomment \n with spacing\n}}{{/if}}');
|
||||
test_fragment('{{#if 0}}\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if words}}{{/if}}',
|
||||
'{{#if words}}{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if words}}{{! \n mult-line\ncomment \n with spacing\n}}{{/if}}',
|
||||
'{{#if words}}{{! \n mult-line\ncomment \n with spacing\n}}{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if words}}{{! \n mult-line\ncomment \n with spacing\n}}{{/if}}',
|
||||
'{{#if words}}{{! \n mult-line\ncomment \n with spacing\n}}{{/if}}');
|
||||
test_fragment('{{#if 1}}\n <div>\n </div>\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if 1}}\n<div>\n</div>\n{{/if}}',
|
||||
'{{#if 1}}\n <div>\n </div>\n{{/if}}');
|
||||
test_fragment('<div>\n {{#if 1}}\n {{/if}}\n</div>');
|
||||
test_fragment(
|
||||
'<div>\n{{#if 1}}\n{{/if}}\n</div>',
|
||||
'<div>\n {{#if 1}}\n {{/if}}\n</div>');
|
||||
test_fragment(
|
||||
'{{#if}}\n{{#each}}\n{{#if}}\n{{! \n mult-line\ncomment \n with spacing\n}}\n{{/if}}\n{{#if}}\n{{! \n mult-line\ncomment \n with spacing\n}}\n{{/if}}\n{{/each}}\n{{/if}}',
|
||||
'{{#if}}\n {{#each}}\n {{#if}}\n {{! \n mult-line\ncomment \n with spacing\n}}\n {{/if}}\n {{#if}}\n {{! \n mult-line\ncomment \n with spacing\n}}\n {{/if}}\n {{/each}}\n{{/if}}');
|
||||
test_fragment('{{#if 1}}\n <div>\n </div>\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if 1}}\n {{! \n mult-line\ncomment \n with spacing\n}}\n {{else}}\n {{! \n mult-line\ncomment \n with spacing\n}}\n{{/if}}',
|
||||
'{{#if 1}}\n {{! \n mult-line\ncomment \n with spacing\n}}\n{{else}}\n {{! \n mult-line\ncomment \n with spacing\n}}\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if 1}}\n {{else}}\n {{/if}}',
|
||||
'{{#if 1}}\n{{else}}\n{{/if}}');
|
||||
test_fragment(
|
||||
'{{#if thing}}\n{{#if otherthing}}\n {{! \n mult-line\ncomment \n with spacing\n}}\n {{else}}\n{{! \n mult-line\ncomment \n with spacing\n}}\n {{/if}}\n {{else}}\n{{! \n mult-line\ncomment \n with spacing\n}}\n{{/if}}',
|
||||
'{{#if thing}}\n {{#if otherthing}}\n {{! \n mult-line\ncomment \n with spacing\n}}\n {{else}}\n {{! \n mult-line\ncomment \n with spacing\n}}\n {{/if}}\n{{else}}\n {{! \n mult-line\ncomment \n with spacing\n}}\n{{/if}}');
|
||||
test_fragment(
|
||||
'<div{{somestyle}}></div>',
|
||||
'<div {{somestyle}}></div>');
|
||||
test_fragment(
|
||||
'<div{{#if test}}class="foo"{{/if}}>{{! \n mult-line\ncomment \n with spacing\n}}</div>',
|
||||
'<div {{#if test}} class="foo" {{/if}}>{{! \n mult-line\ncomment \n with spacing\n}}</div>');
|
||||
test_fragment(
|
||||
'<div{{#if thing}}{{somestyle}}class="{{class}}"{{else}}class="{{class2}}"{{/if}}>{{! \n mult-line\ncomment \n with spacing\n}}</div>',
|
||||
'<div {{#if thing}} {{somestyle}} class="{{class}}" {{else}} class="{{class2}}" {{/if}}>{{! \n mult-line\ncomment \n with spacing\n}}</div>');
|
||||
test_fragment(
|
||||
'<span{{#if condition}}class="foo"{{/if}}>{{! \n mult-line\ncomment \n with spacing\n}}</span>',
|
||||
'<span {{#if condition}} class="foo" {{/if}}>{{! \n mult-line\ncomment \n with spacing\n}}</span>');
|
||||
test_fragment('<div unformatted="{{#if}}{{! \n mult-line\ncomment \n with spacing\n}}{{/if}}">{{! \n mult-line\ncomment \n with spacing\n}}</div>');
|
||||
test_fragment('<div unformatted="{{#if }} {{! \n mult-line\ncomment \n with spacing\n}}{{/if}}">{{! \n mult-line\ncomment \n with spacing\n}}</div>');
|
||||
test_fragment('<div class="{{#if thingIs "value"}}{{! \n mult-line\ncomment \n with spacing\n}}{{/if}}"></div>');
|
||||
test_fragment('<div class="{{#if thingIs \'value\'}}{{! \n mult-line\ncomment \n with spacing\n}}{{/if}}"></div>');
|
||||
test_fragment('<div class=\'{{#if thingIs "value"}}{{! \n mult-line\ncomment \n with spacing\n}}{{/if}}\'></div>');
|
||||
test_fragment('<div class=\'{{#if thingIs \'value\'}}{{! \n mult-line\ncomment \n with spacing\n}}{{/if}}\'></div>');
|
||||
|
||||
|
||||
|
||||
// Unclosed html elements
|
||||
test_fragment('<source>\n<source>');
|
||||
test_fragment('<br>\n<br>');
|
||||
test_fragment('<input>\n<input>');
|
||||
test_fragment('<meta>\n<meta>');
|
||||
test_fragment('<link>\n<link>');
|
||||
|
||||
|
||||
|
||||
// Unformatted tags
|
||||
test_fragment('<ol>\n <li>b<pre>c</pre></li>\n</ol>');
|
||||
test_fragment('<ol>\n <li>b<code>c</code></li>\n</ol>');
|
||||
|
||||
|
||||
|
||||
// Php formatting
|
||||
test_fragment('<h1 class="content-page-header"><?=$view["name"]; ?></h1>');
|
||||
test_fragment(
|
||||
'<?php\n' +
|
||||
'for($i = 1; $i <= 100; $i++;) {\n' +
|
||||
' #count to 100!\n' +
|
||||
' echo($i . "</br>");\n' +
|
||||
'}\n' +
|
||||
'?>');
|
||||
|
||||
|
||||
|
||||
// underscore.js formatting
|
||||
test_fragment(
|
||||
'<div class="col-sm-9">\n' +
|
||||
' <textarea id="notes" class="form-control" rows="3">\n' +
|
||||
' <%= notes %>\n' +
|
||||
' </textarea>\n' +
|
||||
'</div>');
|
||||
|
||||
|
||||
|
||||
// Indent with tabs
|
||||
opts.indent_with_tabs = true;
|
||||
test_fragment(
|
||||
'<div>\n<div>\n</div>\n</div>',
|
||||
'<div>\n\t<div>\n\t</div>\n</div>');
|
||||
|
||||
|
||||
|
||||
// Indent without tabs
|
||||
opts.indent_with_tabs = false;
|
||||
test_fragment(
|
||||
'<div>\n<div>\n</div>\n</div>',
|
||||
'<div>\n <div>\n </div>\n</div>');
|
||||
|
||||
|
||||
|
||||
// New Test Suite
|
||||
|
||||
|
||||
opts.end_with_newline = true;
|
||||
test_fragment('', '\n');
|
||||
test_fragment('<div></div>\n');
|
||||
test_fragment('<div></div>\n\n\n', '<div></div>\n');
|
||||
test_fragment('<head>\n' +
|
||||
' <script>\n' +
|
||||
' mocha.setup("bdd");\n' +
|
||||
'\n' +
|
||||
' </script>\n' +
|
||||
'</head>\n');
|
||||
|
||||
|
||||
opts.end_with_newline = false;
|
||||
// error cases need love too
|
||||
bth('<img title="Bad food!" src="foo.jpg" alt="Evil" ">');
|
||||
bth("<!-- don't blow up if a comment is not complete"); // -->
|
||||
|
||||
test_fragment(
|
||||
'<head>\n' +
|
||||
' <script>\n' +
|
||||
' mocha.setup("bdd");\n' +
|
||||
' </script>\n' +
|
||||
'</head>');
|
||||
|
||||
test_fragment('<div></div>\n', '<div></div>');
|
||||
bth('<div></div>');
|
||||
bth('<div>content</div>');
|
||||
bth('<div><div></div></div>',
|
||||
'<div>\n' +
|
||||
' <div></div>\n' +
|
||||
'</div>');
|
||||
bth('<div><div>content</div></div>',
|
||||
'<div>\n' +
|
||||
' <div>content</div>\n' +
|
||||
'</div>');
|
||||
bth('<div>\n' +
|
||||
' <span>content</span>\n' +
|
||||
'</div>');
|
||||
bth('<div>\n' +
|
||||
'</div>');
|
||||
bth('<div>\n' +
|
||||
' content\n' +
|
||||
'</div>');
|
||||
bth('<div>\n' +
|
||||
' </div>',
|
||||
'<div>\n' +
|
||||
'</div>');
|
||||
bth(' <div>\n' +
|
||||
' </div>',
|
||||
'<div>\n' +
|
||||
'</div>');
|
||||
bth('<div>\n' +
|
||||
'</div>\n' +
|
||||
' <div>\n' +
|
||||
' </div>',
|
||||
'<div>\n' +
|
||||
'</div>\n' +
|
||||
'<div>\n' +
|
||||
'</div>');
|
||||
bth(' <div>\n' +
|
||||
'</div>',
|
||||
'<div>\n' +
|
||||
'</div>');
|
||||
bth('<div >content</div>',
|
||||
'<div>content</div>');
|
||||
bth('<div thinger="preserve space here" ></div >',
|
||||
'<div thinger="preserve space here"></div>');
|
||||
bth('content\n' +
|
||||
' <div>\n' +
|
||||
' </div>\n' +
|
||||
'content',
|
||||
'content\n' +
|
||||
'<div>\n' +
|
||||
'</div>\n' +
|
||||
'content');
|
||||
bth('<li>\n' +
|
||||
' <div>\n' +
|
||||
' </div>\n' +
|
||||
'</li>');
|
||||
bth('<li>\n' +
|
||||
'<div>\n' +
|
||||
'</div>\n' +
|
||||
'</li>',
|
||||
'<li>\n' +
|
||||
' <div>\n' +
|
||||
' </div>\n' +
|
||||
'</li>');
|
||||
bth('<li>\n' +
|
||||
' content\n' +
|
||||
'</li>\n' +
|
||||
'<li>\n' +
|
||||
' content\n' +
|
||||
'</li>');
|
||||
|
||||
bth('<img>content');
|
||||
bth('<img> content');
|
||||
bth('<img> content', '<img> content');
|
||||
|
||||
bth('<img><img>content');
|
||||
bth('<img> <img>content');
|
||||
bth('<img> <img>content', '<img> <img>content');
|
||||
|
||||
bth('<img><b>content</b>');
|
||||
bth('<img> <b>content</b>');
|
||||
bth('<img> <b>content</b>', '<img> <b>content</b>');
|
||||
|
||||
bth('<div>content<img>content</div>');
|
||||
bth('<div> content <img> content</div>');
|
||||
bth('<div> content <img> content </div>',
|
||||
'<div> content <img> content </div>');
|
||||
bth('Text <a href="#">Link</a> Text');
|
||||
|
||||
|
||||
// START tests for issue 453
|
||||
bth('<script type="text/unknown"><div></div></script>',
|
||||
'<script type="text/unknown">\n' +
|
||||
' <div></div>\n' +
|
||||
'</script>');
|
||||
bth('<script type="text/javascript"><div></div></script>',
|
||||
'<script type="text/javascript">\n' +
|
||||
' < div > < /div>\n' +
|
||||
'</script>');
|
||||
bth('<script><div></div></script>',
|
||||
'<script>\n' +
|
||||
' < div > < /div>\n' +
|
||||
'</script>');
|
||||
bth('<script type="text/javascript">var foo = "bar";</script>',
|
||||
'<script type="text/javascript">\n' +
|
||||
' var foo = "bar";\n' +
|
||||
'</script>');
|
||||
bth('<script type="application/javascript">var foo = "bar";</script>',
|
||||
'<script type="application/javascript">\n' +
|
||||
' var foo = "bar";\n' +
|
||||
'</script>');
|
||||
bth('<script type="application/javascript;version=1.8">var foo = "bar";</script>',
|
||||
'<script type="application/javascript;version=1.8">\n' +
|
||||
' var foo = "bar";\n' +
|
||||
'</script>');
|
||||
bth('<script type="application/x-javascript">var foo = "bar";</script>',
|
||||
'<script type="application/x-javascript">\n' +
|
||||
' var foo = "bar";\n' +
|
||||
'</script>');
|
||||
bth('<script type="application/ecmascript">var foo = "bar";</script>',
|
||||
'<script type="application/ecmascript">\n' +
|
||||
' var foo = "bar";\n' +
|
||||
'</script>');
|
||||
bth('<script type="text/javascript1.5">var foo = "bar";</script>',
|
||||
'<script type="text/javascript1.5">\n' +
|
||||
' var foo = "bar";\n' +
|
||||
'</script>');
|
||||
bth('<script>var foo = "bar";</script>',
|
||||
'<script>\n' +
|
||||
' var foo = "bar";\n' +
|
||||
'</script>');
|
||||
|
||||
bth('<style type="text/unknown"><tag></tag></style>',
|
||||
'<style type="text/unknown">\n' +
|
||||
' <tag></tag>\n' +
|
||||
'</style>');
|
||||
bth('<style type="text/css"><tag></tag></style>',
|
||||
'<style type="text/css">\n' +
|
||||
' <tag></tag>\n' +
|
||||
'</style>');
|
||||
bth('<style><tag></tag></style>',
|
||||
'<style>\n' +
|
||||
' <tag></tag>\n' +
|
||||
'</style>');
|
||||
bth('<style type="text/css">.selector {font-size:12px;}</style>',
|
||||
'<style type="text/css">\n' +
|
||||
' .selector {\n' +
|
||||
' font-size: 12px;\n' +
|
||||
' }\n'+
|
||||
'</style>');
|
||||
bth('<style>.selector {font-size:12px;}</style>',
|
||||
'<style>\n' +
|
||||
' .selector {\n' +
|
||||
' font-size: 12px;\n' +
|
||||
' }\n'+
|
||||
'</style>');
|
||||
// END tests for issue 453
|
||||
|
||||
var unformatted = opts.unformatted;
|
||||
opts.unformatted = ['script', 'style'];
|
||||
bth('<script id="javascriptTemplate" type="text/x-kendo-template">\n' +
|
||||
' <ul>\n' +
|
||||
' # for (var i = 0; i < data.length; i++) { #\n' +
|
||||
' <li>#= data[i] #</li>\n' +
|
||||
' # } #\n' +
|
||||
' </ul>\n' +
|
||||
'</script>');
|
||||
bth('<style>\n' +
|
||||
' body {background-color:lightgrey}\n' +
|
||||
' h1 {color:blue}\n' +
|
||||
'</style>');
|
||||
opts.unformatted = unformatted;
|
||||
|
||||
unformatted = opts.unformatted;
|
||||
opts.unformatted = ['custom-element'];
|
||||
test_fragment('<div>should <custom-element>not</custom-element>' +
|
||||
' insert newlines</div>',
|
||||
'<div>should <custom-element>not</custom-element>' +
|
||||
' insert newlines</div>');
|
||||
opts.unformatted = unformatted;
|
||||
|
||||
// Tests that don't pass, but probably should.
|
||||
// bth('<div><span>content</span></div>');
|
||||
|
||||
// Handlebars tests
|
||||
// Without the indent option on, handlebars are treated as content.
|
||||
|
||||
opts.wrap_line_length = 0;
|
||||
//...---------1---------2---------3---------4---------5---------6---------7
|
||||
//...1234567890123456789012345678901234567890123456789012345678901234567890
|
||||
bth('<div>Some text that should not wrap at all.</div>',
|
||||
/* expected */
|
||||
'<div>Some text that should not wrap at all.</div>');
|
||||
|
||||
// A value of 0 means no max line length, and should not wrap.
|
||||
//...---------1---------2---------3---------4---------5---------6---------7---------8---------9--------10--------11--------12--------13--------14--------15--------16--------17--------18--------19--------20--------21--------22--------23--------24--------25--------26--------27--------28--------29
|
||||
//...12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
bth('<div>Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all.</div>',
|
||||
/* expected */
|
||||
'<div>Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all.</div>');
|
||||
|
||||
opts.wrap_line_length = "0";
|
||||
//...---------1---------2---------3---------4---------5---------6---------7
|
||||
//...1234567890123456789012345678901234567890123456789012345678901234567890
|
||||
bth('<div>Some text that should not wrap at all.</div>',
|
||||
/* expected */
|
||||
'<div>Some text that should not wrap at all.</div>');
|
||||
|
||||
// A value of "0" means no max line length, and should not wrap
|
||||
//...---------1---------2---------3---------4---------5---------6---------7---------8---------9--------10--------11--------12--------13--------14--------15--------16--------17--------18--------19--------20--------21--------22--------23--------24--------25--------26--------27--------28--------29
|
||||
//...12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
bth('<div>Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all.</div>',
|
||||
/* expected */
|
||||
'<div>Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all. Some text that should not wrap at all.</div>');
|
||||
|
||||
//BUGBUG: This should wrap before 40 not after.
|
||||
opts.wrap_line_length = 40;
|
||||
//...---------1---------2---------3---------4---------5---------6---------7
|
||||
//...1234567890123456789012345678901234567890123456789012345678901234567890
|
||||
bth('<div>Some test text that should wrap_inside_this section here.</div>',
|
||||
/* expected */
|
||||
'<div>Some test text that should wrap_inside_this\n' +
|
||||
' section here.</div>');
|
||||
|
||||
opts.wrap_line_length = "40";
|
||||
//...---------1---------2---------3---------4---------5---------6---------7
|
||||
//...1234567890123456789012345678901234567890123456789012345678901234567890
|
||||
bth('<div>Some test text that should wrap_inside_this section here.</div>',
|
||||
/* expected */
|
||||
'<div>Some test text that should wrap_inside_this\n' +
|
||||
' section here.</div>');
|
||||
|
||||
opts.indent_size = 1;
|
||||
opts.indent_char = '\t';
|
||||
opts.preserve_newlines = false;
|
||||
bth('<div>\n\tfoo\n</div>', '<div> foo </div>');
|
||||
|
||||
opts.preserve_newlines = true;
|
||||
bth('<div>\n\tfoo\n</div>');
|
||||
|
||||
|
||||
|
||||
// test preserve_newlines and max_preserve_newlines
|
||||
opts.preserve_newlines = false;
|
||||
bth('<div>Should not</div>\n\n\n' +
|
||||
'<div>preserve newlines</div>',
|
||||
'<div>Should not</div>\n' +
|
||||
'<div>preserve newlines</div>');
|
||||
|
||||
opts.preserve_newlines = true;
|
||||
opts.max_preserve_newlines = 0;
|
||||
bth('<div>Should</div>\n\n\n' +
|
||||
'<div>preserve zero newlines</div>',
|
||||
'<div>Should</div>\n' +
|
||||
'<div>preserve zero newlines</div>');
|
||||
|
||||
opts.max_preserve_newlines = 1;
|
||||
bth('<div>Should</div>\n\n\n' +
|
||||
'<div>preserve one newline</div>',
|
||||
'<div>Should</div>\n\n' +
|
||||
'<div>preserve one newline</div>');
|
||||
|
||||
opts.max_preserve_newlines = null;
|
||||
bth('<div>Should</div>\n\n\n' +
|
||||
'<div>preserve one newline</div>',
|
||||
'<div>Should</div>\n\n\n' +
|
||||
'<div>preserve one newline</div>');
|
||||
}
|
||||
|
||||
beautifier_tests();
|
||||
}
|
||||
|
||||
if (typeof exports !== "undefined") {
|
||||
exports.run_html_tests = run_html_tests;
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,50 @@
|
|||
/*global js_beautify: true */
|
||||
/*jshint node:true */
|
||||
|
||||
var fs = require('fs'),
|
||||
SanityTest = require('./sanitytest'),
|
||||
Benchmark = require('benchmark'),
|
||||
Urlencoded = require('../lib/unpackers/urlencode_unpacker'),
|
||||
js_beautify = require('../index').js_beautify,
|
||||
css_beautify = require('../index').css_beautify,
|
||||
html_beautify = require('../index').html_beautify;
|
||||
|
||||
function node_beautifier_tests() {
|
||||
console.log('Testing performance...');
|
||||
var data = fs.readFileSync(__dirname + '/../../test/underscore.js', 'utf8');
|
||||
var data_min = fs.readFileSync(__dirname + '/../../test/underscore-min.js', 'utf8');
|
||||
var options = {
|
||||
wrap_line_length: 80
|
||||
};
|
||||
|
||||
//warm-up
|
||||
js_beautify(data, options);
|
||||
js_beautify(data_min, options);
|
||||
|
||||
var suite = new Benchmark.Suite;
|
||||
|
||||
suite.add("js-beautify (underscore)", function() {
|
||||
js_beautify(data, options);
|
||||
})
|
||||
.add("js-beautify (underscore-min)", function() {
|
||||
js_beautify(data_min, options);
|
||||
})
|
||||
// add listeners
|
||||
.on('cycle', function(event) {
|
||||
console.log(String(event.target));
|
||||
})
|
||||
.on('error', function(event) {
|
||||
return 1;
|
||||
})
|
||||
.on('complete', function(event) {
|
||||
})
|
||||
.run()
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (require.main === module) {
|
||||
process.exit(node_beautifier_tests());
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*global js_beautify: true */
|
||||
/*jshint node:true */
|
||||
|
||||
var SanityTest = require('./sanitytest'),
|
||||
Urlencoded = require('../lib/unpackers/urlencode_unpacker'),
|
||||
run_javascript_tests = require('./beautify-javascript-tests').run_javascript_tests,
|
||||
run_css_tests = require('./beautify-css-tests').run_css_tests,
|
||||
run_html_tests = require('./beautify-html-tests').run_html_tests;
|
||||
|
||||
function node_beautifier_legacy_tests(name, test_runner) {
|
||||
console.log('Testing ' + name + ' with node.js CommonJS (legacy names)...');
|
||||
var results = new SanityTest();
|
||||
var beautify = require('../index');
|
||||
|
||||
test_runner(
|
||||
results,
|
||||
Urlencoded,
|
||||
beautify.js_beautify,
|
||||
beautify.html_beautify,
|
||||
beautify.css_beautify);
|
||||
|
||||
console.log(results.results_raw());
|
||||
return results;
|
||||
}
|
||||
|
||||
function node_beautifier_tests(name, test_runner) {
|
||||
console.log('Testing ' + name + ' with node.js CommonJS (new names)...');
|
||||
var results = new SanityTest();
|
||||
var beautify = require('../index');
|
||||
|
||||
|
||||
test_runner(
|
||||
results,
|
||||
Urlencoded,
|
||||
beautify.js,
|
||||
beautify.html,
|
||||
beautify.css);
|
||||
|
||||
console.log(results.results_raw());
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
if (require.main === module) {
|
||||
process.exit(
|
||||
node_beautifier_tests('js-beautifier', run_javascript_tests).get_exitcode() +
|
||||
node_beautifier_legacy_tests('js-beautifier', run_javascript_tests).get_exitcode() +
|
||||
node_beautifier_tests('cs-beautifier', run_css_tests).get_exitcode() +
|
||||
node_beautifier_legacy_tests('css-beautifier', run_css_tests).get_exitcode() +
|
||||
node_beautifier_tests('html-beautifier', run_html_tests).get_exitcode() +
|
||||
node_beautifier_legacy_tests('html-beautifier', run_html_tests).get_exitcode()
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
|
||||
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.10/require.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
require(["../lib/beautify-html"],function(html_beautify){
|
||||
var input = document.getElementById("input").value;
|
||||
var output = html_beautify.html_beautify(input);
|
||||
document.getElementById("output").innerHTML = output;
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
#output{
|
||||
border: 1px solid black;
|
||||
height: 300px;
|
||||
width: 100%;
|
||||
}
|
||||
#input{
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>RequireJS test</h1>
|
||||
|
||||
<p>
|
||||
This example loads the html-beautifier by using a relative path in the require call to the beautify-html.js file.
|
||||
(also works works with absolute paths)
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
require(["../lib/beautify-html"],function(html_beautify){
|
||||
var input = document.getElementById("input").value;
|
||||
var output = html_beautify.html_beautify(input);
|
||||
document.getElementById("output").innerHTML = output;
|
||||
});
|
||||
</pre>
|
||||
|
||||
<h2>Input</h2>
|
||||
<textarea name="" id="input">
|
||||
<ul><li><a href="test"></a></li></ul>
|
||||
</textarea>
|
||||
|
||||
<h2>Output</h2>
|
||||
<textarea name="" id="output">
|
||||
|
||||
</textarea>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
function indentMe() {
|
||||
"no, me!";
|
||||
}
|
||||
17
gaia/distros/spark/apps/customizer/components/js-beautify/js/test/run-tests
Executable file
17
gaia/distros/spark/apps/customizer/components/js-beautify/js/test/run-tests
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/spidermonkey-1.7 -s
|
||||
|
||||
//#!/usr/bin/js
|
||||
|
||||
// a little helper for testing from command line
|
||||
// just run it, it will output the test results
|
||||
|
||||
load('js/lib/beautify.js');
|
||||
load('js/test/sanitytest.js')
|
||||
load('js/test/beautify-tests.js')
|
||||
load('js/lib/unpackers/urlencode_unpacker.js')
|
||||
|
||||
print(run_beautifier_tests(new SanityTest(), Urlencoded, js_beautify).results_raw())
|
||||
|
||||
|
||||
// for nodejs use this from the command line from the main directory:
|
||||
// node test/beautify-tests.js
|
||||
135
gaia/distros/spark/apps/customizer/components/js-beautify/js/test/sanitytest.js
Executable file
135
gaia/distros/spark/apps/customizer/components/js-beautify/js/test/sanitytest.js
Executable file
|
|
@ -0,0 +1,135 @@
|
|||
//
|
||||
// simple testing interface
|
||||
// written by Einar Lielmanis, einar@jsbeautifier.org
|
||||
//
|
||||
// usage:
|
||||
//
|
||||
// var t = new SanityTest(function (x) { return x; }, 'my function');
|
||||
// t.expect('input', 'output');
|
||||
// t.expect('a', 'a');
|
||||
// output_somewhere(t.results()); // good for <pre>, html safe-ish
|
||||
// alert(t.results_raw()); // html unescaped
|
||||
|
||||
|
||||
function SanityTest (func, name_of_test) {
|
||||
|
||||
var test_func = func || function (x) {
|
||||
return x;
|
||||
};
|
||||
|
||||
var test_name = name_of_test || '';
|
||||
|
||||
var n_failed = 0;
|
||||
var n_succeeded = 0;
|
||||
|
||||
var failures = [];
|
||||
|
||||
this.test_function = function(func, name) {
|
||||
test_func = func;
|
||||
test_name = name || '';
|
||||
};
|
||||
|
||||
this.get_exitcode = function() {
|
||||
return n_succeeded === 0 || n_failed !== 0 ? 1 : 0;
|
||||
};
|
||||
|
||||
this.expect = function(parameters, expected_value) {
|
||||
// multi-parameter calls not supported (I don't need them now).
|
||||
var result = test_func(parameters);
|
||||
// proper array checking is a pain. i'll maybe do it later, compare strings representations instead
|
||||
if ((result === expected_value) || (expected_value instanceof Array && result.join(', ') === expected_value.join(', '))) {
|
||||
n_succeeded += 1;
|
||||
} else {
|
||||
n_failed += 1;
|
||||
failures.push([test_name, parameters, expected_value, result]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.results_raw = function() {
|
||||
var results = '';
|
||||
if (n_failed === 0) {
|
||||
if (n_succeeded === 0) {
|
||||
results = 'No tests run.';
|
||||
} else {
|
||||
results = 'All ' + n_succeeded + ' tests passed.';
|
||||
}
|
||||
} else {
|
||||
for (var i = 0 ; i < failures.length; i++) {
|
||||
var f = failures[i];
|
||||
if (f[0]) {
|
||||
f[0] = f[0] + ' ';
|
||||
}
|
||||
results += '---- ' + f[0] + 'input -------\n' + this.prettyprint(f[1]) + '\n';
|
||||
results += '---- ' + f[0] + 'expected ----\n' + this.prettyprint(f[2]) + '\n';
|
||||
results += '---- ' + f[0] + 'output ------\n' + this.prettyprint(f[3]) + '\n\n';
|
||||
|
||||
}
|
||||
results += n_failed + ' tests failed.\n';
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
this.results = function() {
|
||||
return this.lazy_escape(this.results_raw());
|
||||
};
|
||||
|
||||
|
||||
this.prettyprint = function(something, quote_strings) {
|
||||
var type = typeof something;
|
||||
switch(type.toLowerCase()) {
|
||||
case 'string':
|
||||
if (quote_strings) {
|
||||
return "'" + something.replace("'", "\\'") + "'";
|
||||
} else {
|
||||
return something;
|
||||
}
|
||||
case 'number':
|
||||
return '' + something;
|
||||
case 'boolean':
|
||||
return something ? 'true' : 'false';
|
||||
case 'undefined':
|
||||
return 'undefined';
|
||||
case 'object':
|
||||
if (something instanceof Array) {
|
||||
var x = [];
|
||||
var expected_index = 0;
|
||||
for (var k in something) {
|
||||
if (k === expected_index) {
|
||||
x.push(this.prettyprint(something[k], true));
|
||||
expected_index += 1;
|
||||
} else {
|
||||
x.push('\n' + k + ': ' + this.prettyprint(something[k], true));
|
||||
}
|
||||
}
|
||||
return '[' + x.join(', ') + ']';
|
||||
} else {
|
||||
return 'object: ' + something;
|
||||
}
|
||||
default:
|
||||
return type + ': ' + something;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.lazy_escape = function (str) {
|
||||
return str.replace(/</g, '<').replace(/\>/g, '>').replace(/\n/g, '<br />');
|
||||
};
|
||||
|
||||
|
||||
this.log = function () {
|
||||
if (window.console) {
|
||||
if (console.firebug) {
|
||||
console.log.apply(console, Array.prototype.slice.call(arguments));
|
||||
} else {
|
||||
console.log.call(console, Array.prototype.slice.call(arguments));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = SanityTest;
|
||||
}
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
#!/bin/bash
|
||||
|
||||
REL_SCRIPT_DIR="`dirname \"$0\"`"
|
||||
SCRIPT_DIR="`( cd \"$REL_SCRIPT_DIR\" && pwd )`"
|
||||
|
||||
test_cli_common()
|
||||
{
|
||||
echo ----------------------------------------
|
||||
echo Testing common cli behavior...
|
||||
CLI_SCRIPT_NAME=${1:?missing_param}.js
|
||||
CLI_SCRIPT=$SCRIPT_DIR/../bin/$CLI_SCRIPT_NAME
|
||||
echo Script: $CLI_SCRIPT
|
||||
|
||||
# should find the minimal help output
|
||||
$CLI_SCRIPT 2>&1 | grep -q "Must define at least one file\." || {
|
||||
echo "[$CLI_SCRIPT_NAME] Output should be help message."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT 2> /dev/null && {
|
||||
echo "[$CLI_SCRIPT_NAME (with no parameters)] Return code should be error."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT -Z 2> /dev/null && {
|
||||
echo "[$CLI_SCRIPT_NAME -Z] Return code for invalid parameter should be error."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT -h > /dev/null || {
|
||||
echo "[$CLI_SCRIPT_NAME -h] Return code should be success."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT -v > /dev/null || {
|
||||
echo "[$CLI_SCRIPT_NAME -v] Return code should be success."
|
||||
exit 1
|
||||
}
|
||||
|
||||
MISSING_FILE="$SCRIPT_DIR/../../../js/bin/missing_file"
|
||||
MISSING_FILE_MESSAGE="Unable to open path"
|
||||
$CLI_SCRIPT $MISSING_FILE 2> /dev/null && {
|
||||
echo "[$CLI_SCRIPT_NAME $MISSING_FILE] Return code should be error."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT $MISSING_FILE 2>&1 | grep -q "$MISSING_FILE_MESSAGE" || {
|
||||
echo "[$CLI_SCRIPT_NAME $MISSING_FILE] Stderr should have useful message."
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ "`$CLI_SCRIPT $MISSING_FILE 2> /dev/null`" != "" ]; then
|
||||
echo "[$CLI_SCRIPT_NAME $MISSING_FILE] Stdout should have no text."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
test_cli_js_beautify()
|
||||
{
|
||||
echo ----------------------------------------
|
||||
echo Testing js-beautify cli behavior...
|
||||
CLI_SCRIPT=$SCRIPT_DIR/../bin/js-beautify.js
|
||||
|
||||
$CLI_SCRIPT $SCRIPT_DIR/../bin/js-beautify.js > /dev/null || {
|
||||
echo "js-beautify output for $SCRIPT_DIR/../bin/js-beautify.js was expected succeed."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT $SCRIPT_DIR/../bin/css-beautify.js > /dev/null || {
|
||||
echo "js-beautify output for $SCRIPT_DIR/../bin/css-beautify.js was expected succeed."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT $SCRIPT_DIR/../bin/js-beautify.js | diff $SCRIPT_DIR/../bin/js-beautify.js - || {
|
||||
echo "js-beautify output for $SCRIPT_DIR/../bin/js-beautify.js was expected to be unchanged."
|
||||
exit 1
|
||||
}
|
||||
|
||||
rm -rf /tmp/js-beautify-mkdir
|
||||
$CLI_SCRIPT -o /tmp/js-beautify-mkdir/js-beautify.js $SCRIPT_DIR/../bin/js-beautify.js && diff $SCRIPT_DIR/../bin/js-beautify.js /tmp/js-beautify-mkdir/js-beautify.js || {
|
||||
echo "js-beautify output for $SCRIPT_DIR/../bin/js-beautify.js should have been created in /tmp/js-beautify-mkdir/js-beautify.js."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ensure unchanged files are not overwritten
|
||||
cp -p /tmp/js-beautify-mkdir/js-beautify.js /tmp/js-beautify-mkdir/js-beautify-old.js
|
||||
touch -A -05 /tmp/js-beautify-mkdir/js-beautify.js
|
||||
touch -A -01 /tmp/js-beautify-mkdir/js-beautify-old.js
|
||||
$CLI_SCRIPT -r /tmp/js-beautify-mkdir/js-beautify.js && test /tmp/js-beautify-mkdir/js-beautify.js -nt /tmp/js-beautify-mkdir/js-beautify-old.js && {
|
||||
echo "js-beautify should not replace unchanged file /tmp/js-beautify-mkdir/js-beautify.js when using -r"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT -o /tmp/js-beautify-mkdir/js-beautify.js /tmp/js-beautify-mkdir/js-beautify.js && test /tmp/js-beautify-mkdir/js-beautify.js -nt /tmp/js-beautify-mkdir/js-beautify-old.js && {
|
||||
echo "js-beautify should not replace unchanged file /tmp/js-beautify-mkdir/js-beautify.js when using -o and same file name"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT -o /tmp/js-beautify-mkdir/js-beautify.js /tmp/js-beautify-mkdir/js-beautify-old.js && test /tmp/js-beautify-mkdir/js-beautify.js -nt /tmp/js-beautify-mkdir/js-beautify-old.js && {
|
||||
echo "js-beautify should not replace unchanged file /tmp/js-beautify-mkdir/js-beautify.js when using -o and different file name"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT $SCRIPT_DIR/../bin/css-beautify.js | diff -q $SCRIPT_DIR/../bin/css-beautify.js - && {
|
||||
echo "js-beautify output for $SCRIPT_DIR/../bin/css-beautify.js was expected to be different."
|
||||
exit 1
|
||||
}
|
||||
|
||||
export HOME=
|
||||
export USERPROFILE=
|
||||
$CLI_SCRIPT -o /tmp/js-beautify-mkdir/example1-default.js $SCRIPT_DIR/resources/example1.js
|
||||
|
||||
cd $SCRIPT_DIR/resources/indent11chars
|
||||
$CLI_SCRIPT /tmp/js-beautify-mkdir/example1-default.js | diff -q /tmp/js-beautify-mkdir/example1-default.js - && {
|
||||
echo "js-beautify output for /tmp/js-beautify-mkdir/example1-default.js was expected to be different based on CWD settings."
|
||||
exit 1
|
||||
}
|
||||
cd $SCRIPT_DIR/resources/indent11chars/subDir1/subDir2
|
||||
$CLI_SCRIPT /tmp/js-beautify-mkdir/example1-default.js | diff -q /tmp/js-beautify-mkdir/example1-default.js - && {
|
||||
echo "js-beautify output for /tmp/js-beautify-mkdir/example1-default.js was expected to be different based on CWD parent folder settings."
|
||||
exit 1
|
||||
}
|
||||
cd $SCRIPT_DIR
|
||||
|
||||
|
||||
export HOME=$SCRIPT_DIR/resources/indent11chars
|
||||
$CLI_SCRIPT /tmp/js-beautify-mkdir/example1-default.js | diff -q /tmp/js-beautify-mkdir/example1-default.js - && {
|
||||
echo "js-beautify output for /tmp/js-beautify-mkdir/example1-default.js was expected to be different based on HOME settings."
|
||||
exit 1
|
||||
}
|
||||
|
||||
export HOME=
|
||||
export USERPROFILE=$SCRIPT_DIR/resources/indent11chars
|
||||
$CLI_SCRIPT /tmp/js-beautify-mkdir/example1-default.js | diff -q /tmp/js-beautify-mkdir/example1-default.js - && {
|
||||
echo "js-beautify output for /tmp/js-beautify-mkdir/example1-default.js was expected to be different based on USERPROFILE settings."
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
test_smoke_js_beautify()
|
||||
{
|
||||
echo ----------------------------------------
|
||||
echo Testing js-beautify functionality...
|
||||
node $SCRIPT_DIR/node-beautify-tests.js || exit 1
|
||||
node $SCRIPT_DIR/amd-beautify-tests.js || exit 1
|
||||
}
|
||||
|
||||
|
||||
test_performance_js_beautify()
|
||||
{
|
||||
echo ----------------------------------------
|
||||
echo Testing js-beautify performance...
|
||||
node $SCRIPT_DIR/node-beautify-perf-tests.js || exit 1
|
||||
echo ----------------------------------------
|
||||
|
||||
}
|
||||
|
||||
test_cli_common css-beautify
|
||||
test_cli_common html-beautify
|
||||
test_cli_common js-beautify
|
||||
|
||||
test_cli_js_beautify
|
||||
test_smoke_js_beautify
|
||||
test_performance_js_beautify
|
||||
|
||||
echo ----------------------------------------
|
||||
echo $0 - PASSED.
|
||||
echo ----------------------------------------
|
||||
56
gaia/distros/spark/apps/customizer/components/js-beautify/package.json
Executable file
56
gaia/distros/spark/apps/customizer/components/js-beautify/package.json
Executable file
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"name": "js-beautify",
|
||||
"version": "1.5.10",
|
||||
"description": "jsbeautifier.org for node",
|
||||
"main": "js/index.js",
|
||||
"preferGlobal": true,
|
||||
"bin": {
|
||||
"css-beautify": "./js/bin/css-beautify.js",
|
||||
"html-beautify": "./js/bin/html-beautify.js",
|
||||
"js-beautify": "./js/bin/js-beautify.js"
|
||||
},
|
||||
"directories": {
|
||||
"lib": "js/lib",
|
||||
"test": "js/test"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "./js/test/shell-smoke-test.sh",
|
||||
"update-codemirror": "npm install codemirror && rm -rf ./web/third-party/codemirror/* && cp ./node_modules/codemirror/LICENSE ./web/third-party/codemirror/ && cp ./node_modules/codemirror/README.md ./web/third-party/codemirror/ && cp -r ./node_modules/codemirror/lib ./web/third-party/codemirror/ && mkdir -p ./web/third-party/codemirror/mode && cp -r ./node_modules/codemirror/mode/javascript ./web/third-party/codemirror/mode/ && git add -Av ./web/third-party/codemirror"
|
||||
},
|
||||
"bugs": "https://github.com/beautify-web/js-beautify/issues",
|
||||
"homepage": "http://jsbeautifier.org/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/beautify-web/js-beautify.git"
|
||||
},
|
||||
"keywords": [
|
||||
"beautify",
|
||||
"beautifier",
|
||||
"code-quality"
|
||||
],
|
||||
"author": "Einar Lielmanis <einar@jsbeautifier.org>",
|
||||
"contributors": [
|
||||
"Vital Batmanov <vital76@gmail.com>",
|
||||
"Chris J. Shull <chrisjshull@gmail.com>",
|
||||
"Gian Marco Gherardi <gianmarco.gherardi@gmail.com>",
|
||||
"Stan <stasson@orc.ru>",
|
||||
"Vittorio Gambaletta <VittGam@vittgam.net>",
|
||||
"Daniel Stockman <daniel.stockman@gmail.com>",
|
||||
"Harutyun Amirjanyan <amirjanyan@gmail.com>",
|
||||
"Nochum Sossonko <nsossonko@hotmail.com>",
|
||||
"Liam Newman <bitwiseman@gmail.com>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"config-chain": "~1.1.5",
|
||||
"mkdirp": "~0.5.0",
|
||||
"nopt": "~3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jshint": "~2.8.0",
|
||||
"node-static": "~0.7.1",
|
||||
"mustache": "~1.1.0",
|
||||
"requirejs": "2.1.x",
|
||||
"benchmark": "1.0.0"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
include js-beautify
|
||||
include js-beautify-test
|
||||
|
|
@ -0,0 +1,467 @@
|
|||
from __future__ import print_function
|
||||
import sys
|
||||
import re
|
||||
from cssbeautifier.__version__ import __version__
|
||||
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
|
||||
# Copyright (c) 2013 Einar Lielmanis and contributors.
|
||||
|
||||
# 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.
|
||||
|
||||
|
||||
class BeautifierOptions:
|
||||
def __init__(self):
|
||||
self.indent_size = 4
|
||||
self.indent_char = ' '
|
||||
self.indent_with_tabs = False
|
||||
self.selector_separator_newline = True
|
||||
self.end_with_newline = False
|
||||
self.newline_between_rules = True
|
||||
self.eol = '\n'
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return \
|
||||
"""indent_size = %d
|
||||
indent_char = [%s]
|
||||
indent_with_tabs = [%s]
|
||||
separate_selectors_newline = [%s]
|
||||
end_with_newline = [%s]
|
||||
newline_between_rules = [%s]
|
||||
""" % (self.indent_size, self.indent_char, self.indent_with_tabs,
|
||||
self.selector_separator_newline, self.end_with_newline, self.newline_between_rules)
|
||||
|
||||
|
||||
def default_options():
|
||||
return BeautifierOptions()
|
||||
|
||||
|
||||
def beautify(string, opts=default_options()):
|
||||
b = Beautifier(string, opts)
|
||||
return b.beautify()
|
||||
|
||||
|
||||
def beautify_file(file_name, opts=default_options()):
|
||||
if file_name == '-': # stdin
|
||||
stream = sys.stdin
|
||||
else:
|
||||
stream = open(file_name)
|
||||
content = ''.join(stream.readlines())
|
||||
b = Beautifier(content, opts)
|
||||
return b.beautify()
|
||||
|
||||
|
||||
def usage(stream=sys.stdout):
|
||||
|
||||
print("cssbeautifier.py@" + __version__ + """
|
||||
|
||||
CSS beautifier (http://jsbeautifier.org/)
|
||||
|
||||
""", file=stream)
|
||||
if stream == sys.stderr:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
WHITE_RE = re.compile("^\s+$")
|
||||
WORD_RE = re.compile("[\w$\-_]")
|
||||
|
||||
|
||||
class Printer:
|
||||
|
||||
def __init__(self, indent_char, indent_size, default_indent=""):
|
||||
self.indentSize = indent_size
|
||||
self.singleIndent = (indent_size) * indent_char
|
||||
self.indentLevel = 0
|
||||
self.nestedLevel = 0
|
||||
|
||||
self.baseIndentString = default_indent
|
||||
self.output = []
|
||||
|
||||
def __lastCharWhitespace(self):
|
||||
return len(self.output) > 0 and WHITE_RE.search(self.output[-1]) is not None
|
||||
|
||||
def indent(self):
|
||||
self.indentLevel += 1
|
||||
self.baseIndentString += self.singleIndent
|
||||
|
||||
def outdent(self):
|
||||
if self.indentLevel:
|
||||
self.indentLevel -= 1
|
||||
self.baseIndentString = self.baseIndentString[:-(len(self.singleIndent))]
|
||||
|
||||
def push(self, string):
|
||||
self.output.append(string)
|
||||
|
||||
def openBracket(self):
|
||||
self.singleSpace()
|
||||
self.output.append("{")
|
||||
self.newLine()
|
||||
|
||||
def closeBracket(self):
|
||||
self.newLine()
|
||||
self.output.append("}")
|
||||
self.newLine()
|
||||
|
||||
def semicolon(self):
|
||||
self.output.append(";")
|
||||
self.newLine()
|
||||
|
||||
def comment(self, comment):
|
||||
self.output.append(comment)
|
||||
|
||||
def newLine(self, keepWhitespace=False):
|
||||
if len(self.output) > 0 :
|
||||
if not keepWhitespace and self.output[-1] != '\n':
|
||||
self.trim()
|
||||
|
||||
self.output.append("\n")
|
||||
|
||||
if len(self.baseIndentString) > 0:
|
||||
self.output.append(self.baseIndentString)
|
||||
|
||||
def trim(self):
|
||||
while self.__lastCharWhitespace():
|
||||
self.output.pop()
|
||||
|
||||
def singleSpace(self):
|
||||
if len(self.output) > 0 and not self.__lastCharWhitespace():
|
||||
self.output.append(" ")
|
||||
|
||||
def preserveSingleSpace(self,isAfterSpace):
|
||||
if isAfterSpace:
|
||||
self.singleSpace()
|
||||
|
||||
def result(self):
|
||||
if self.baseIndentString:
|
||||
return self.baseIndentString + "".join(self.output);
|
||||
else:
|
||||
return "".join(self.output)
|
||||
|
||||
|
||||
class Beautifier:
|
||||
|
||||
def __init__(self, source_text, opts=default_options()):
|
||||
# This is not pretty, but given how we did the version import
|
||||
# it is the only way to do this without having setup.py fail on a missing six dependency.
|
||||
self.six = __import__("six")
|
||||
|
||||
if not source_text:
|
||||
source_text = ''
|
||||
|
||||
# HACK: newline parsing inconsistent. This brute force normalizes the input newlines.
|
||||
lineBreak = re.compile(self.six.u("\r\n|[\r\u2028\u2029]"))
|
||||
source_text = re.sub(lineBreak, '\n', source_text)
|
||||
|
||||
self.source_text = source_text
|
||||
self.opts = opts
|
||||
self.indentSize = opts.indent_size
|
||||
self.indentChar = opts.indent_char
|
||||
self.pos = -1
|
||||
self.ch = None
|
||||
|
||||
if self.opts.indent_with_tabs:
|
||||
self.indentChar = "\t"
|
||||
self.indentSize = 1
|
||||
|
||||
self.opts.eol = self.opts.eol.replace('\\r', '\r').replace('\\n', '\n')
|
||||
|
||||
# https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
|
||||
# also in CONDITIONAL_GROUP_RULE below
|
||||
self.NESTED_AT_RULE = [ \
|
||||
"@page", \
|
||||
"@font-face", \
|
||||
"@keyframes", \
|
||||
"@media", \
|
||||
"@supports", \
|
||||
"@document"]
|
||||
self.CONDITIONAL_GROUP_RULE = [ \
|
||||
"@media", \
|
||||
"@supports", \
|
||||
"@document"]
|
||||
|
||||
def next(self):
|
||||
self.pos = self.pos + 1
|
||||
if self.pos < len(self.source_text):
|
||||
self.ch = self.source_text[self.pos]
|
||||
else:
|
||||
self.ch = ''
|
||||
return self.ch
|
||||
|
||||
def peek(self,skipWhitespace=False):
|
||||
start = self.pos
|
||||
if skipWhitespace:
|
||||
self.eatWhitespace()
|
||||
result = ""
|
||||
if self.pos + 1 < len(self.source_text):
|
||||
result = self.source_text[self.pos + 1]
|
||||
if skipWhitespace:
|
||||
self.pos = start - 1
|
||||
self.next()
|
||||
|
||||
return result
|
||||
|
||||
def eatString(self, endChars):
|
||||
start = self.pos
|
||||
while self.next():
|
||||
if self.ch == "\\":
|
||||
self.next()
|
||||
elif self.ch in endChars:
|
||||
break
|
||||
elif self.ch == "\n":
|
||||
break
|
||||
return self.source_text[start:self.pos] + self.ch
|
||||
|
||||
def peekString(self, endChar):
|
||||
start = self.pos
|
||||
st = self.eatString(endChar)
|
||||
self.pos = start - 1
|
||||
self.next()
|
||||
return st
|
||||
|
||||
def eatWhitespace(self):
|
||||
result = ''
|
||||
while WHITE_RE.search(self.peek()) is not None:
|
||||
self.next()
|
||||
result += self.ch
|
||||
return result
|
||||
|
||||
def skipWhitespace(self):
|
||||
result = ''
|
||||
if self.ch and WHITE_RE.search(self.ch):
|
||||
result = self.ch
|
||||
|
||||
while WHITE_RE.search(self.next()) is not None:
|
||||
result += self.ch
|
||||
return result
|
||||
|
||||
def eatComment(self):
|
||||
start = self.pos
|
||||
singleLine = self.peek() == "/"
|
||||
self.next()
|
||||
while self.next():
|
||||
if not singleLine and self.ch == "*" and self.peek() == "/":
|
||||
self.next()
|
||||
break
|
||||
elif singleLine and self.ch == "\n":
|
||||
return self.source_text[start:self.pos]
|
||||
return self.source_text[start:self.pos] + self.ch
|
||||
|
||||
def lookBack(self, string):
|
||||
past = self.source_text[self.pos - len(string):self.pos]
|
||||
return past.lower() == string
|
||||
|
||||
# Nested pseudo-class if we are insideRule
|
||||
# and the next special character found opens
|
||||
# a new block
|
||||
def foundNestedPseudoClass(self):
|
||||
i = self.pos + 1
|
||||
openParen = 0
|
||||
while i < len(self.source_text):
|
||||
ch = self.source_text[i]
|
||||
if ch == "{":
|
||||
return True
|
||||
elif ch == "(":
|
||||
# pseudoclasses can contain ()
|
||||
openParen += 1
|
||||
elif ch == ")":
|
||||
if openParen == 0:
|
||||
return False
|
||||
openParen -= 1
|
||||
elif ch == ";" or ch == "}":
|
||||
return False
|
||||
i += 1;
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def beautify(self):
|
||||
m = re.search("^[\t ]*", self.source_text)
|
||||
baseIndentString = m.group(0)
|
||||
printer = Printer(self.indentChar, self.indentSize, baseIndentString)
|
||||
|
||||
insideRule = False
|
||||
insidePropertyValue = False
|
||||
enteringConditionalGroup = False
|
||||
top_ch = ''
|
||||
last_top_ch = ''
|
||||
parenLevel = 0
|
||||
|
||||
while True:
|
||||
whitespace = self.skipWhitespace()
|
||||
isAfterSpace = whitespace != ''
|
||||
isAfterNewline = '\n' in whitespace
|
||||
last_top_ch = top_ch
|
||||
top_ch = self.ch
|
||||
|
||||
if not self.ch:
|
||||
break
|
||||
elif self.ch == '/' and self.peek() == '*':
|
||||
header = printer.indentLevel == 0
|
||||
|
||||
if not isAfterNewline or header:
|
||||
printer.newLine()
|
||||
|
||||
|
||||
comment = self.eatComment()
|
||||
printer.comment(comment)
|
||||
printer.newLine()
|
||||
if header:
|
||||
printer.newLine(True)
|
||||
elif self.ch == '/' and self.peek() == '/':
|
||||
if not isAfterNewline and last_top_ch != '{':
|
||||
printer.trim()
|
||||
|
||||
printer.singleSpace()
|
||||
printer.comment(self.eatComment())
|
||||
printer.newLine()
|
||||
elif self.ch == '@':
|
||||
printer.preserveSingleSpace(isAfterSpace)
|
||||
printer.push(self.ch)
|
||||
|
||||
# strip trailing space, if present, for hash property check
|
||||
variableOrRule = self.peekString(": ,;{}()[]/='\"")
|
||||
|
||||
if variableOrRule[-1] in ": ":
|
||||
# wwe have a variable or pseudo-class, add it and insert one space before continuing
|
||||
self.next()
|
||||
variableOrRule = self.eatString(": ")
|
||||
if variableOrRule[-1].isspace():
|
||||
variableOrRule = variableOrRule[:-1]
|
||||
printer.push(variableOrRule)
|
||||
printer.singleSpace();
|
||||
|
||||
if variableOrRule[-1].isspace():
|
||||
variableOrRule = variableOrRule[:-1]
|
||||
|
||||
# might be a nesting at-rule
|
||||
if variableOrRule in self.NESTED_AT_RULE:
|
||||
printer.nestedLevel += 1
|
||||
if variableOrRule in self.CONDITIONAL_GROUP_RULE:
|
||||
enteringConditionalGroup = True
|
||||
elif self.ch == '#' and self.peek() == '{':
|
||||
printer.preserveSingleSpace(isAfterSpace)
|
||||
printer.push(self.eatString('}'));
|
||||
elif self.ch == '{':
|
||||
if self.peek(True) == '}':
|
||||
self.eatWhitespace()
|
||||
self.next()
|
||||
printer.singleSpace()
|
||||
printer.push("{}")
|
||||
printer.newLine()
|
||||
if self.opts.newline_between_rules and printer.indentLevel == 0:
|
||||
printer.newLine(True)
|
||||
else:
|
||||
printer.indent()
|
||||
printer.openBracket()
|
||||
# when entering conditional groups, only rulesets are allowed
|
||||
if enteringConditionalGroup:
|
||||
enteringConditionalGroup = False
|
||||
insideRule = printer.indentLevel > printer.nestedLevel
|
||||
else:
|
||||
# otherwise, declarations are also allowed
|
||||
insideRule = printer.indentLevel >= printer.nestedLevel
|
||||
elif self.ch == '}':
|
||||
printer.outdent()
|
||||
printer.closeBracket()
|
||||
insideRule = False
|
||||
insidePropertyValue = False
|
||||
if printer.nestedLevel:
|
||||
printer.nestedLevel -= 1
|
||||
if self.opts.newline_between_rules and printer.indentLevel == 0:
|
||||
printer.newLine(True)
|
||||
elif self.ch == ":":
|
||||
self.eatWhitespace()
|
||||
if (insideRule or enteringConditionalGroup) and \
|
||||
not (self.lookBack('&') or self.foundNestedPseudoClass()):
|
||||
# 'property: value' delimiter
|
||||
# which could be in a conditional group query
|
||||
insidePropertyValue = True
|
||||
printer.push(":")
|
||||
printer.singleSpace()
|
||||
else:
|
||||
# sass/less parent reference don't use a space
|
||||
# sass nested pseudo-class don't use a space
|
||||
if self.peek() == ":":
|
||||
# pseudo-element
|
||||
self.next()
|
||||
printer.push("::")
|
||||
else:
|
||||
# pseudo-element
|
||||
printer.push(":")
|
||||
elif self.ch == '"' or self.ch == '\'':
|
||||
printer.preserveSingleSpace(isAfterSpace)
|
||||
printer.push(self.eatString(self.ch))
|
||||
elif self.ch == ';':
|
||||
insidePropertyValue = False
|
||||
printer.semicolon()
|
||||
elif self.ch == '(':
|
||||
# may be a url
|
||||
if self.lookBack("url"):
|
||||
printer.push(self.ch)
|
||||
self.eatWhitespace()
|
||||
if self.next():
|
||||
if self.ch is not ')' and self.ch is not '"' \
|
||||
and self.ch is not '\'':
|
||||
printer.push(self.eatString(')'))
|
||||
else:
|
||||
self.pos = self.pos - 1
|
||||
else:
|
||||
parenLevel += 1
|
||||
printer.preserveSingleSpace(isAfterSpace)
|
||||
printer.push(self.ch)
|
||||
self.eatWhitespace()
|
||||
elif self.ch == ')':
|
||||
printer.push(self.ch)
|
||||
parenLevel -= 1
|
||||
elif self.ch == ',':
|
||||
printer.push(self.ch)
|
||||
self.eatWhitespace()
|
||||
if not insidePropertyValue and self.opts.selector_separator_newline and parenLevel < 1:
|
||||
printer.newLine()
|
||||
else:
|
||||
printer.singleSpace()
|
||||
elif self.ch == ']':
|
||||
printer.push(self.ch)
|
||||
elif self.ch == '[':
|
||||
printer.preserveSingleSpace(isAfterSpace)
|
||||
printer.push(self.ch)
|
||||
elif self.ch == '=':
|
||||
# no whitespace before or after
|
||||
self.eatWhitespace()
|
||||
self.ch = '='
|
||||
printer.push(self.ch)
|
||||
else:
|
||||
printer.preserveSingleSpace(isAfterSpace)
|
||||
printer.push(self.ch)
|
||||
|
||||
sweet_code = re.sub('[\r\n\t ]+$', '', printer.result())
|
||||
|
||||
# establish end_with_newline
|
||||
if self.opts.end_with_newline:
|
||||
sweet_code += '\n'
|
||||
|
||||
if not self.opts.eol == '\n':
|
||||
sweet_code = sweet_code.replace('\n', self.opts.eol)
|
||||
|
||||
return sweet_code
|
||||
|
|
@ -0,0 +1 @@
|
|||
__version__ = '1.0.0'
|
||||
|
|
@ -0,0 +1 @@
|
|||
# Empty file :)
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue