Set up Grunt tasks to build web and Node versions of CyberChef using webpack

This commit is contained in:
n1474335 2017-03-21 22:41:44 +00:00
parent 99f306dc18
commit 885fbe13ac
56 changed files with 299 additions and 29138 deletions

1
.babelrc Normal file
View file

@ -0,0 +1 @@
{ "presets": [ "es2015" ] }

1
.gitignore vendored
View file

@ -2,6 +2,7 @@ node_modules
npm-debug.log
build/dev
build/test
build/node
docs/*
!docs/*.conf.json
!docs/*.ico

View file

@ -1,4 +1,4 @@
/* eslint-env node */
var webpack = require("webpack");
module.exports = function(grunt) {
grunt.file.defaultEncoding = "utf8";
@ -7,16 +7,20 @@ module.exports = function(grunt) {
// Tasks
grunt.registerTask("dev",
"A persistent task which creates a development build whenever source files are modified.",
["clean:dev", "concat:css", "concat:js", "copy:htmlDev", "copy:staticDev", "chmod:build", "watch"]);
["clean:dev", "concat:css", "webpack:web", "copy:htmlDev", "copy:staticDev", "chmod:build", "watch"]);
grunt.registerTask("node",
"Compiles CyberChef into a single NodeJS module.",
["clean:node", "webpack:node", "chmod:build"]);
grunt.registerTask("test",
"A task which runs all the tests in test/tests.",
["clean:test", "concat:jsTest", "copy:htmlTest", "chmod:build", "execute:test"]);
["clean:test", "webpack:tests", "chmod:build", "execute:test"]);
grunt.registerTask("prod",
"Creates a production-ready build. Use the --msg flag to add a compile message.",
["eslint", "exec:stats", "clean", "jsdoc", "concat", "copy:htmlDev", "copy:htmlProd", "copy:htmlInline",
"copy:staticDev", "copy:staticProd", "cssmin", "uglify:prod", "inline", "htmlmin", "chmod", "test"]);
["eslint", "test", "exec:stats", "clean", "jsdoc", "webpack:web", "concat", "copy:htmlDev", "copy:htmlProd", "copy:htmlInline",
"copy:staticDev", "copy:staticProd", "cssmin", "uglify:prod", "inline", "htmlmin", "docs", "chmod"]);
grunt.registerTask("docs",
"Compiles documentation in the /docs directory.",
@ -43,6 +47,7 @@ module.exports = function(grunt) {
grunt.loadNpmTasks("grunt-eslint");
grunt.loadNpmTasks("grunt-jsdoc");
grunt.loadNpmTasks("grunt-contrib-clean");
grunt.loadNpmTasks("grunt-webpack");
grunt.loadNpmTasks("grunt-contrib-concat");
grunt.loadNpmTasks("grunt-contrib-copy");
grunt.loadNpmTasks("grunt-contrib-uglify");
@ -55,125 +60,6 @@ module.exports = function(grunt) {
grunt.loadNpmTasks("grunt-contrib-watch");
// JS includes
var jsIncludes = [
// Third party framework libraries
"src/js/lib/jquery-2.1.1.js",
"src/js/lib/bootstrap-3.3.6.js",
"src/js/lib/split.js",
"src/js/lib/bootstrap-switch.js",
"src/js/lib/yahoo.js",
"src/js/lib/snowfall.jquery.js",
// Third party operation libraries
"src/js/lib/cryptojs/core.js",
"src/js/lib/cryptojs/x64-core.js",
"src/js/lib/cryptojs/enc-base64.js",
"src/js/lib/cryptojs/enc-utf16.js",
"src/js/lib/cryptojs/md5.js",
"src/js/lib/cryptojs/evpkdf.js",
"src/js/lib/cryptojs/cipher-core.js",
"src/js/lib/cryptojs/mode-cfb.js",
"src/js/lib/cryptojs/mode-ctr-gladman.js",
"src/js/lib/cryptojs/mode-ctr.js",
"src/js/lib/cryptojs/mode-ecb.js",
"src/js/lib/cryptojs/mode-ofb.js",
"src/js/lib/cryptojs/format-hex.js",
"src/js/lib/cryptojs/lib-typedarrays.js",
"src/js/lib/cryptojs/pad-ansix923.js",
"src/js/lib/cryptojs/pad-iso10126.js",
"src/js/lib/cryptojs/pad-iso97971.js",
"src/js/lib/cryptojs/pad-nopadding.js",
"src/js/lib/cryptojs/pad-zeropadding.js",
"src/js/lib/cryptojs/aes.js",
"src/js/lib/cryptojs/hmac.js",
"src/js/lib/cryptojs/rabbit-legacy.js",
"src/js/lib/cryptojs/rabbit.js",
"src/js/lib/cryptojs/ripemd160.js",
"src/js/lib/cryptojs/sha1.js",
"src/js/lib/cryptojs/sha256.js",
"src/js/lib/cryptojs/sha224.js",
"src/js/lib/cryptojs/sha512.js",
"src/js/lib/cryptojs/sha384.js",
"src/js/lib/cryptojs/sha3.js",
"src/js/lib/cryptojs/tripledes.js",
"src/js/lib/cryptojs/rc4.js",
"src/js/lib/cryptojs/pbkdf2.js",
"src/js/lib/cryptoapi/crypto-api.js",
"src/js/lib/cryptoapi/hasher.md2.js",
"src/js/lib/cryptoapi/hasher.md4.js",
"src/js/lib/cryptoapi/hasher.sha0.js",
"src/js/lib/jsbn/jsbn.js",
"src/js/lib/jsbn/jsbn2.js",
"src/js/lib/jsbn/base64.js",
"src/js/lib/jsbn/ec.js",
"src/js/lib/jsbn/prng4.js",
"src/js/lib/jsbn/rng.js",
"src/js/lib/jsbn/rsa.js",
"src/js/lib/jsbn/sec.js",
"src/js/lib/jsrasign/asn1-1.0.js",
"src/js/lib/jsrasign/asn1hex-1.1.js",
"src/js/lib/jsrasign/asn1x509-1.0.js",
"src/js/lib/jsrasign/base64x-1.1.js",
"src/js/lib/jsrasign/crypto-1.1.js",
"src/js/lib/jsrasign/dsa-modified-1.0.js",
"src/js/lib/jsrasign/ecdsa-modified-1.0.js",
"src/js/lib/jsrasign/ecparam-1.0.js",
"src/js/lib/jsrasign/keyutil-1.0.js",
"src/js/lib/jsrasign/x509-1.1.js",
"src/js/lib/blowfish.dojo.js",
"src/js/lib/rawdeflate.js",
"src/js/lib/rawinflate.js",
"src/js/lib/zip.js",
"src/js/lib/unzip.js",
"src/js/lib/zlib_and_gzip.js",
"src/js/lib/bzip2.js",
"src/js/lib/punycode.js",
"src/js/lib/uas_parser.js",
"src/js/lib/esprima.js",
"src/js/lib/escodegen.browser.js",
"src/js/lib/esmangle.min.js",
"src/js/lib/diff.js",
"src/js/lib/moment.js",
"src/js/lib/moment-timezone.js",
"src/js/lib/prettify.js",
"src/js/lib/vkbeautify.js",
"src/js/lib/Sortable.js",
"src/js/lib/bootstrap-colorpicker.js",
"src/js/lib/es6-promise.auto.js",
"src/js/lib/xpath.js",
// Custom libraries
"src/js/lib/canvascomponents.js",
// Utility functions
"src/js/core/Utils.js",
// Operation objects
"src/js/operations/*.js",
// Core framework objects
"src/js/core/*.js",
"src/js/config/Categories.js",
"src/js/config/OperationConfig.js",
// HTML view objects
"src/js/views/html/*.js",
"!src/js/views/html/main.js",
];
var jsAppFiles = jsIncludes.concat([
// Start the main app!
"src/js/views/html/main.js",
]);
var jsTestFiles = jsIncludes.concat([
"test/TestRegister.js",
"test/tests/**/*.js",
"test/TestRunner.js",
]);
var banner = '/**\n\
* CyberChef - The Cyber Swiss Army Knife\n\
*\n\
@ -235,8 +121,70 @@ module.exports = function(grunt) {
dev: ["build/dev/*"],
prod: ["build/prod/*"],
test: ["build/test/*"],
node: ["build/node/*"],
docs: ["docs/*", "!docs/*.conf.json", "!docs/*.ico"],
},
webpack: {
options: {
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
moment: "moment-timezone"
}),
],
resolve: {
alias: {
jquery: "jquery/src/jquery"
}
},
module: {
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader?compact=false"
}]
}
},
web: {
target: "web",
entry: "./src/js/views/html/main.js",
output: {
filename: "scripts.js",
path: "build/dev"
},
},
tests: {
target: "node",
entry: "./test/TestRunner.js",
output: {
filename: "index.js",
path: "build/test"
},
module: {
loaders: [{
test: /prettify\.min\.js$/,
use: "imports-loader?window=>global"
}]
}
},
node: {
target: "node",
entry: "./src/js/views/node/index.js",
output: {
filename: "CyberChef.js",
path: "build/node",
library: "CyberChef",
libraryTarget: "commonjs2"
},
module: {
loaders: [{
test: /prettify\.min\.js$/,
use: "imports-loader?window=>global"
}]
}
}
},
concat: {
options: {
process: templateOptions
@ -256,20 +204,6 @@ module.exports = function(grunt) {
"src/css/themes/classic.css"
],
dest: "build/dev/styles.css"
},
js: {
options: {
banner: '"use strict";\n'
},
src: jsAppFiles,
dest: "build/dev/scripts.js"
},
jsTest: {
options: {
banner: '"use strict";\n'
},
src: jsTestFiles,
dest: "build/test/tests.js"
}
},
copy: {
@ -491,7 +425,7 @@ module.exports = function(grunt) {
}
},
execute: {
test: "test/NodeRunner.js"
test: "build/test/index.js"
},
watch: {
css: {

View file

@ -25,11 +25,12 @@
"type": "git",
"url": "https://github.com/gchq/CyberChef/"
},
"scripts": {
"build": "webpack"
},
"devDependencies": {
"grunt": "~1.0.1",
"babel-core": "^6.24.0",
"babel-loader": "^6.4.0",
"babel-preset-es2015": "^6.24.0",
"exports-loader": "^0.6.4",
"grunt": ">=0.4.5",
"grunt-chmod": "~1.1.1",
"grunt-contrib-clean": "~1.0.0",
"grunt-contrib-concat": "~1.0.0",
@ -43,11 +44,18 @@
"grunt-execute": "^0.2.2",
"grunt-inline-alt": "~0.3.10",
"grunt-jsdoc": "^2.1.0",
"grunt-webpack": "^2.0.1",
"import-loader": "^1.0.1",
"imports-loader": "^0.7.1",
"ink-docstrap": "^1.1.4",
"phantomjs-prebuilt": "^2.1.14",
"webpack": "^2.2.1"
},
"dependencies": {
"babel-polyfill": "^6.23.0",
"bootstrap": "^3.3.7",
"bootstrap-colorpicker": "^2.5.1",
"bootstrap-switch": "^3.3.4",
"crypto-api": "^0.6.2",
"crypto-js": "^3.1.9-1",
"diff": "^3.2.0",
@ -61,7 +69,11 @@
"moment": "^2.17.1",
"moment-timezone": "^0.5.11",
"sladex-blowfish": "^0.8.1",
"sortablejs": "^1.5.1",
"split.js": "^1.2.0",
"vkbeautify": "^0.99.1",
"xmldom": "^0.1.27",
"xpath": "0.0.24",
"zlibjs": "^0.2.0"
}
}

View file

@ -7,7 +7,6 @@
},
"env": {
"browser": true,
"jquery": true,
"es6": true,
"commonjs": true,
"node": true
@ -88,6 +87,10 @@
"space-in-parens": "error"
},
"globals": {
"$": false,
"jQuery": false,
"moment": false,
/* core/* */
"Chef": false,
"Dish": false,

View file

@ -24,7 +24,7 @@ var Chef = module.exports = function() {
* @param {Object} options - The options object storing various user choices
* @param {boolean} options.attempHighlight - Whether or not to attempt highlighting
* @param {number} progress - The position in the recipe to start from
* @param {number} [step] - The number of operations to execute
* @param {number} [step] - Whether to only execute one operation in the recipe
*
* @returns {Object} response
* @returns {string} response.result - The output of the recipe

View file

@ -1,3 +1,7 @@
var Recipe = require("./Recipe.js"),
Dish = require("./Dish.js");
/**
* Flow Control operations.
*

View file

@ -1,5 +1,5 @@
var OperationConfig = require("../config/OperationConfig.js"),
Operation = require("./Operation.js");
var Operation = require("./Operation.js");
// OperationConfig required at the bottom of this file to prevent circular dependency errors
/**
@ -216,3 +216,8 @@ Recipe.prototype.fromString = function(recipeStr) {
var recipeConfig = JSON.parse(recipeStr);
this._parseConfig(recipeConfig);
};
// Required here to prevent circular dependency where Recipe returns an empty object
// See http://stackoverflow.com/a/30390378
var OperationConfig = require("../config/OperationConfig.js");

View file

@ -1,6 +1,4 @@
var CryptoJS = require("crypto-js"),
moment = require("moment"),
$ = require("jquery");
var CryptoJS = require("crypto-js");
/**
@ -1172,36 +1170,6 @@ var Utils = module.exports = {
};
/**
* A jQuery function to select a range of text.
*
* @param {number} start
* @param {number} end
*
* @example
* // Highlights the 4th, 5th and 6th characters in the element #input-text.
* $("#input-text").selectRange(3,5);
*
* // Places the cursor at the beginning of the element #input-text.
* $("#input-text").selectRange(0);
*/
// $.fn.selectRange = function(start, end) {
// if (!end) end = start;
// return this.each(function() {
// if (this.setSelectionRange) {
// this.focus();
// this.setSelectionRange(start, end);
// } else if (this.createTextRange) {
// var range = this.createTextRange();
// range.collapse(true);
// range.moveEnd("character", end);
// range.moveStart("character", start);
// range.select();
// }
// });
// };
/**
* Removes all duplicates from an array.
*

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,583 +0,0 @@
/** @license
========================================================================
bootstrap-switch - v3.1.0
http://www.bootstrap-switch.org
Copyright 2012-2013 Mattia Larentis
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
(function() {
var __slice = [].slice;
(function($, window) {
"use strict";
var BootstrapSwitch;
BootstrapSwitch = (function() {
function BootstrapSwitch(element, options) {
if (options == null) {
options = {};
}
this.$element = $(element);
this.options = $.extend({}, $.fn.bootstrapSwitch.defaults, {
state: this.$element.is(":checked"),
size: this.$element.data("size"),
animate: this.$element.data("animate"),
disabled: this.$element.is(":disabled"),
readonly: this.$element.is("[readonly]"),
indeterminate: this.$element.data("indeterminate"),
inverse: this.$element.data("inverse"),
radioAllOff: this.$element.data("radio-all-off"),
onColor: this.$element.data("on-color"),
offColor: this.$element.data("off-color"),
onText: this.$element.data("on-text"),
offText: this.$element.data("off-text"),
labelText: this.$element.data("label-text"),
baseClass: this.$element.data("base-class"),
wrapperClass: this.$element.data("wrapper-class")
}, options);
this.$wrapper = $("<div>", {
"class": (function(_this) {
return function() {
var classes;
classes = ["" + _this.options.baseClass].concat(_this._getClasses(_this.options.wrapperClass));
classes.push(_this.options.state ? "" + _this.options.baseClass + "-on" : "" + _this.options.baseClass + "-off");
if (_this.options.size != null) {
classes.push("" + _this.options.baseClass + "-" + _this.options.size);
}
if (_this.options.animate) {
classes.push("" + _this.options.baseClass + "-animate");
}
if (_this.options.disabled) {
classes.push("" + _this.options.baseClass + "-disabled");
}
if (_this.options.readonly) {
classes.push("" + _this.options.baseClass + "-readonly");
}
if (_this.options.indeterminate) {
classes.push("" + _this.options.baseClass + "-indeterminate");
}
if (_this.options.inverse) {
classes.push("" + _this.options.baseClass + "-inverse");
}
if (_this.$element.attr("id")) {
classes.push("" + _this.options.baseClass + "-id-" + (_this.$element.attr("id")));
}
return classes.join(" ");
};
})(this)()
});
this.$container = $("<div>", {
"class": "" + this.options.baseClass + "-container"
});
this.$on = $("<span>", {
html: this.options.onText,
"class": "" + this.options.baseClass + "-handle-on " + this.options.baseClass + "-" + this.options.onColor
});
this.$off = $("<span>", {
html: this.options.offText,
"class": "" + this.options.baseClass + "-handle-off " + this.options.baseClass + "-" + this.options.offColor
});
this.$label = $("<label>", {
html: this.options.labelText,
"class": "" + this.options.baseClass + "-label"
});
if (this.options.indeterminate) {
this.$element.prop("indeterminate", true);
}
this.$element.on("init.bootstrapSwitch", (function(_this) {
return function() {
return _this.options.onInit.apply(element, arguments);
};
})(this));
this.$element.on("switchChange.bootstrapSwitch", (function(_this) {
return function() {
return _this.options.onSwitchChange.apply(element, arguments);
};
})(this));
this.$container = this.$element.wrap(this.$container).parent();
this.$wrapper = this.$container.wrap(this.$wrapper).parent();
this.$element.before(this.options.inverse ? this.$off : this.$on).before(this.$label).before(this.options.inverse ? this.$on : this.$off).trigger("init.bootstrapSwitch");
this._elementHandlers();
this._handleHandlers();
this._labelHandlers();
this._formHandler();
}
BootstrapSwitch.prototype._constructor = BootstrapSwitch;
BootstrapSwitch.prototype.state = function(value, skip) {
if (typeof value === "undefined") {
return this.options.state;
}
if (this.options.disabled || this.options.readonly) {
return this.$element;
}
if (this.options.state && !this.options.radioAllOff && this.$element.is(':radio')) {
return this.$element;
}
if (this.options.indeterminate) {
this.indeterminate(false);
value = true;
} else {
value = !!value;
}
this.$element.prop("checked", value).trigger("change.bootstrapSwitch", skip);
return this.$element;
};
BootstrapSwitch.prototype.toggleState = function(skip) {
if (this.options.disabled || this.options.readonly) {
return this.$element;
}
if (this.options.indeterminate) {
this.indeterminate(false);
return this.state(true);
} else {
return this.$element.prop("checked", !this.options.state).trigger("change.bootstrapSwitch", skip);
}
};
BootstrapSwitch.prototype.size = function(value) {
if (typeof value === "undefined") {
return this.options.size;
}
if (this.options.size != null) {
this.$wrapper.removeClass("" + this.options.baseClass + "-" + this.options.size);
}
if (value) {
this.$wrapper.addClass("" + this.options.baseClass + "-" + value);
}
this.options.size = value;
return this.$element;
};
BootstrapSwitch.prototype.animate = function(value) {
if (typeof value === "undefined") {
return this.options.animate;
}
value = !!value;
this.$wrapper[value ? "addClass" : "removeClass"]("" + this.options.baseClass + "-animate");
this.options.animate = value;
return this.$element;
};
BootstrapSwitch.prototype.toggleAnimate = function() {
this.$wrapper.toggleClass("" + this.options.baseClass + "-animate");
this.options.animate = !this.options.animate;
return this.$element;
};
BootstrapSwitch.prototype.disabled = function(value) {
if (typeof value === "undefined") {
return this.options.disabled;
}
value = !!value;
this.$wrapper[value ? "addClass" : "removeClass"]("" + this.options.baseClass + "-disabled");
this.$element.prop("disabled", value);
this.options.disabled = value;
return this.$element;
};
BootstrapSwitch.prototype.toggleDisabled = function() {
this.$element.prop("disabled", !this.options.disabled);
this.$wrapper.toggleClass("" + this.options.baseClass + "-disabled");
this.options.disabled = !this.options.disabled;
return this.$element;
};
BootstrapSwitch.prototype.readonly = function(value) {
if (typeof value === "undefined") {
return this.options.readonly;
}
value = !!value;
this.$wrapper[value ? "addClass" : "removeClass"]("" + this.options.baseClass + "-readonly");
this.$element.prop("readonly", value);
this.options.readonly = value;
return this.$element;
};
BootstrapSwitch.prototype.toggleReadonly = function() {
this.$element.prop("readonly", !this.options.readonly);
this.$wrapper.toggleClass("" + this.options.baseClass + "-readonly");
this.options.readonly = !this.options.readonly;
return this.$element;
};
BootstrapSwitch.prototype.indeterminate = function(value) {
if (typeof value === "undefined") {
return this.options.indeterminate;
}
value = !!value;
this.$wrapper[value ? "addClass" : "removeClass"]("" + this.options.baseClass + "-indeterminate");
this.$element.prop("indeterminate", value);
this.options.indeterminate = value;
return this.$element;
};
BootstrapSwitch.prototype.toggleIndeterminate = function() {
this.$element.prop("indeterminate", !this.options.indeterminate);
this.$wrapper.toggleClass("" + this.options.baseClass + "-indeterminate");
this.options.indeterminate = !this.options.indeterminate;
return this.$element;
};
BootstrapSwitch.prototype.inverse = function(value) {
var $off, $on;
if (typeof value === "undefined") {
return this.options.inverse;
}
value = !!value;
this.$wrapper[value ? "addClass" : "removeClass"]("" + this.options.baseClass + "-inverse");
$on = this.$on.clone(true);
$off = this.$off.clone(true);
this.$on.replaceWith($off);
this.$off.replaceWith($on);
this.$on = $off;
this.$off = $on;
this.options.inverse = value;
return this.$element;
};
BootstrapSwitch.prototype.toggleInverse = function() {
var $off, $on;
this.$wrapper.toggleClass("" + this.options.baseClass + "-inverse");
$on = this.$on.clone(true);
$off = this.$off.clone(true);
this.$on.replaceWith($off);
this.$off.replaceWith($on);
this.$on = $off;
this.$off = $on;
this.options.inverse = !this.options.inverse;
return this.$element;
};
BootstrapSwitch.prototype.onColor = function(value) {
var color;
color = this.options.onColor;
if (typeof value === "undefined") {
return color;
}
if (color != null) {
this.$on.removeClass("" + this.options.baseClass + "-" + color);
}
this.$on.addClass("" + this.options.baseClass + "-" + value);
this.options.onColor = value;
return this.$element;
};
BootstrapSwitch.prototype.offColor = function(value) {
var color;
color = this.options.offColor;
if (typeof value === "undefined") {
return color;
}
if (color != null) {
this.$off.removeClass("" + this.options.baseClass + "-" + color);
}
this.$off.addClass("" + this.options.baseClass + "-" + value);
this.options.offColor = value;
return this.$element;
};
BootstrapSwitch.prototype.onText = function(value) {
if (typeof value === "undefined") {
return this.options.onText;
}
this.$on.html(value);
this.options.onText = value;
return this.$element;
};
BootstrapSwitch.prototype.offText = function(value) {
if (typeof value === "undefined") {
return this.options.offText;
}
this.$off.html(value);
this.options.offText = value;
return this.$element;
};
BootstrapSwitch.prototype.labelText = function(value) {
if (typeof value === "undefined") {
return this.options.labelText;
}
this.$label.html(value);
this.options.labelText = value;
return this.$element;
};
BootstrapSwitch.prototype.baseClass = function(value) {
return this.options.baseClass;
};
BootstrapSwitch.prototype.wrapperClass = function(value) {
if (typeof value === "undefined") {
return this.options.wrapperClass;
}
if (!value) {
value = $.fn.bootstrapSwitch.defaults.wrapperClass;
}
this.$wrapper.removeClass(this._getClasses(this.options.wrapperClass).join(" "));
this.$wrapper.addClass(this._getClasses(value).join(" "));
this.options.wrapperClass = value;
return this.$element;
};
BootstrapSwitch.prototype.radioAllOff = function(value) {
if (typeof value === "undefined") {
return this.options.radioAllOff;
}
this.options.radioAllOff = value;
return this.$element;
};
BootstrapSwitch.prototype.onInit = function(value) {
if (typeof value === "undefined") {
return this.options.onInit;
}
if (!value) {
value = $.fn.bootstrapSwitch.defaults.onInit;
}
this.options.onInit = value;
return this.$element;
};
BootstrapSwitch.prototype.onSwitchChange = function(value) {
if (typeof value === "undefined") {
return this.options.onSwitchChange;
}
if (!value) {
value = $.fn.bootstrapSwitch.defaults.onSwitchChange;
}
this.options.onSwitchChange = value;
return this.$element;
};
BootstrapSwitch.prototype.destroy = function() {
var $form;
$form = this.$element.closest("form");
if ($form.length) {
$form.off("reset.bootstrapSwitch").removeData("bootstrap-switch");
}
this.$container.children().not(this.$element).remove();
this.$element.unwrap().unwrap().off(".bootstrapSwitch").removeData("bootstrap-switch");
return this.$element;
};
BootstrapSwitch.prototype._elementHandlers = function() {
return this.$element.on({
"change.bootstrapSwitch": (function(_this) {
return function(e, skip) {
var checked;
e.preventDefault();
e.stopImmediatePropagation();
checked = _this.$element.is(":checked");
if (checked === _this.options.state) {
return;
}
_this.options.state = checked;
_this.$wrapper.removeClass(checked ? "" + _this.options.baseClass + "-off" : "" + _this.options.baseClass + "-on").addClass(checked ? "" + _this.options.baseClass + "-on" : "" + _this.options.baseClass + "-off");
if (!skip) {
if (_this.$element.is(":radio")) {
$("[name='" + (_this.$element.attr('name')) + "']").not(_this.$element).prop("checked", false).trigger("change.bootstrapSwitch", true);
}
return _this.$element.trigger("switchChange.bootstrapSwitch", [checked]);
}
};
})(this),
"focus.bootstrapSwitch": (function(_this) {
return function(e) {
e.preventDefault();
return _this.$wrapper.addClass("" + _this.options.baseClass + "-focused");
};
})(this),
"blur.bootstrapSwitch": (function(_this) {
return function(e) {
e.preventDefault();
return _this.$wrapper.removeClass("" + _this.options.baseClass + "-focused");
};
})(this),
"keydown.bootstrapSwitch": (function(_this) {
return function(e) {
if (!e.which || _this.options.disabled || _this.options.readonly) {
return;
}
switch (e.which) {
case 37:
e.preventDefault();
e.stopImmediatePropagation();
return _this.state(false);
case 39:
e.preventDefault();
e.stopImmediatePropagation();
return _this.state(true);
}
};
})(this)
});
};
BootstrapSwitch.prototype._handleHandlers = function() {
this.$on.on("click.bootstrapSwitch", (function(_this) {
return function(e) {
_this.state(false);
return _this.$element.trigger("focus.bootstrapSwitch");
};
})(this));
return this.$off.on("click.bootstrapSwitch", (function(_this) {
return function(e) {
_this.state(true);
return _this.$element.trigger("focus.bootstrapSwitch");
};
})(this));
};
BootstrapSwitch.prototype._labelHandlers = function() {
return this.$label.on({
"mousemove.bootstrapSwitch touchmove.bootstrapSwitch": (function(_this) {
return function(e) {
var left, pageX, percent, right;
if (!_this.isLabelDragging) {
return;
}
e.preventDefault();
_this.isLabelDragged = true;
pageX = e.pageX || e.originalEvent.touches[0].pageX;
percent = ((pageX - _this.$wrapper.offset().left) / _this.$wrapper.width()) * 100;
left = 25;
right = 75;
if (_this.options.animate) {
_this.$wrapper.removeClass("" + _this.options.baseClass + "-animate");
}
if (percent < left) {
percent = left;
} else if (percent > right) {
percent = right;
}
_this.$container.css("margin-left", "" + (percent - right) + "%");
return _this.$element.trigger("focus.bootstrapSwitch");
};
})(this),
"mousedown.bootstrapSwitch touchstart.bootstrapSwitch": (function(_this) {
return function(e) {
if (_this.isLabelDragging || _this.options.disabled || _this.options.readonly) {
return;
}
e.preventDefault();
_this.isLabelDragging = true;
return _this.$element.trigger("focus.bootstrapSwitch");
};
})(this),
"mouseup.bootstrapSwitch touchend.bootstrapSwitch": (function(_this) {
return function(e) {
var state;
if (!_this.isLabelDragging) {
return;
}
e.preventDefault();
if (_this.isLabelDragged) {
state = parseInt(_this.$container.css("margin-left"), 10) > -(_this.$container.width() / 6);
_this.isLabelDragged = false;
_this.state(_this.options.inverse ? !state : state);
if (_this.options.animate) {
_this.$wrapper.addClass("" + _this.options.baseClass + "-animate");
}
_this.$container.css("margin-left", "");
} else {
_this.state(!_this.options.state);
}
return _this.isLabelDragging = false;
};
})(this),
"mouseleave.bootstrapSwitch": (function(_this) {
return function(e) {
return _this.$label.trigger("mouseup.bootstrapSwitch");
};
})(this)
});
};
BootstrapSwitch.prototype._formHandler = function() {
var $form;
$form = this.$element.closest("form");
if ($form.data("bootstrap-switch")) {
return;
}
return $form.on("reset.bootstrapSwitch", function() {
return window.setTimeout(function() {
return $form.find("input").filter(function() {
return $(this).data("bootstrap-switch");
}).each(function() {
return $(this).bootstrapSwitch("state", this.checked);
});
}, 1);
}).data("bootstrap-switch", true);
};
BootstrapSwitch.prototype._getClasses = function(classes) {
var c, cls, _i, _len;
if (!$.isArray(classes)) {
return ["" + this.options.baseClass + "-" + classes];
}
cls = [];
for (_i = 0, _len = classes.length; _i < _len; _i++) {
c = classes[_i];
cls.push("" + this.options.baseClass + "-" + c);
}
return cls;
};
return BootstrapSwitch;
})();
$.fn.bootstrapSwitch = function() {
var args, option, ret;
option = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
ret = this;
this.each(function() {
var $this, data;
$this = $(this);
data = $this.data("bootstrap-switch");
if (!data) {
$this.data("bootstrap-switch", data = new BootstrapSwitch(this, option));
}
if (typeof option === "string") {
return ret = data[option].apply(data, args);
}
});
return ret;
};
$.fn.bootstrapSwitch.Constructor = BootstrapSwitch;
return $.fn.bootstrapSwitch.defaults = {
state: true,
size: null,
animate: true,
disabled: false,
readonly: false,
indeterminate: false,
inverse: false,
radioAllOff: false,
onColor: "primary",
offColor: "default",
onText: "ON",
offText: "OFF",
labelText: "&nbsp;",
baseClass: "bootstrap-switch",
wrapperClass: "wrapper",
onInit: function() {},
onSwitchChange: function() {}
};
})(window.jQuery, window);
}).call(this);

View file

@ -28,7 +28,7 @@
*/
"use strict";
var bzip2 = module.exports = {};
var bzip2 = {};
bzip2.array = function(bytes){
var bit = 0, byte = 0;

View file

@ -10,7 +10,7 @@
* @constant
* @namespace
*/
var CanvasComponents = {
var CanvasComponents = module.exports = {
drawLine: function(ctx, startX, startY, endX, endY) {
ctx.beginPath();

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,585 +0,0 @@
/** @license
========================================================================
Split.js v1.1.1
Copyright (c) 2015 Nathan Cahill
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.
*/
// The programming goals of Split.js are to deliver readable, understandable and
// maintainable code, while at the same time manually optimizing for tiny minified file size,
// browser compatibility without additional requirements, graceful fallback (IE8 is supported)
// and very few assumptions about the user's page layout.
//
// Make sure all browsers handle this JS library correctly with ES5.
// More information here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode
'use strict';
// A wrapper function that does a couple things:
//
// 1. Doesn't pollute the global namespace. This is important for a library.
// 2. Allows us to mount the library in different module systems, as well as
// directly in the browser.
(function() {
// Save the global `this` for use later. In this case, since the library only
// runs in the browser, it will refer to `window`. Also, figure out if we're in IE8
// or not. IE8 will still render correctly, but will be static instead of draggable.
//
// Save a couple long function names that are used frequently.
// This optimization saves around 400 bytes.
var global = this
, isIE8 = global.attachEvent && !global[addEventListener]
, document = global.document
, addEventListener = 'addEventListener'
, removeEventListener = 'removeEventListener'
, getBoundingClientRect = 'getBoundingClientRect'
// This library only needs two helper functions:
//
// The first determines which prefixes of CSS calc we need.
// We only need to do this once on startup, when this anonymous function is called.
//
// Tests -webkit, -moz and -o prefixes. Modified from StackOverflow:
// http://stackoverflow.com/questions/16625140/js-feature-detection-to-detect-the-usage-of-webkit-calc-over-calc/16625167#16625167
, calc = (function () {
var el
, prefixes = ["", "-webkit-", "-moz-", "-o-"]
for (var i = 0; i < prefixes.length; i++) {
el = document.createElement('div')
el.style.cssText = "width:" + prefixes[i] + "calc(9px)"
if (el.style.length) {
return prefixes[i] + "calc"
}
}
})()
// The second helper function allows elements and string selectors to be used
// interchangeably. In either case an element is returned. This allows us to
// do `Split(elem1, elem2)` as well as `Split('#id1', '#id2')`.
, elementOrSelector = function (el) {
if (typeof el === 'string' || el instanceof String) {
return document.querySelector(el)
} else {
return el
}
}
// The main function to initialize a split. Split.js thinks about each pair
// of elements as an independant pair. Dragging the gutter between two elements
// only changes the dimensions of elements in that pair. This is key to understanding
// how the following functions operate, since each function is bound to a pair.
//
// A pair object is shaped like this:
//
// {
// a: DOM element,
// b: DOM element,
// aMin: Number,
// bMin: Number,
// dragging: Boolean,
// parent: DOM element,
// isFirst: Boolean,
// isLast: Boolean,
// direction: 'horizontal' | 'vertical'
// }
//
// The basic sequence:
//
// 1. Set defaults to something sane. `options` doesn't have to be passed at all.
// 2. Initialize a bunch of strings based on the direction we're splitting.
// A lot of the behavior in the rest of the library is paramatized down to
// rely on CSS strings and classes.
// 3. Define the dragging helper functions, and a few helpers to go with them.
// 4. Define a few more functions that "balance" the entire split instance.
// Split.js tries it's best to cope with min sizes that don't add up.
// 5. Loop through the elements while pairing them off. Every pair gets an
// `pair` object, a gutter, and special isFirst/isLast properties.
// 6. Actually size the pair elements, insert gutters and attach event listeners.
// 7. Balance all of the pairs to accomodate min sizes as best as possible.
, Split = function (ids, options) {
var dimension
, i
, clientDimension
, clientAxis
, position
, gutterClass
, paddingA
, paddingB
, pairs = []
// 1. Set defaults to something sane. `options` doesn't have to be passed at all,
// so create an options object if none exists. Pixel values 10, 100 and 30 are
// arbitrary but feel natural.
options = typeof options !== 'undefined' ? options : {}
if (typeof options.gutterSize === 'undefined') options.gutterSize = 10
if (typeof options.minSize === 'undefined') options.minSize = 100
if (typeof options.snapOffset === 'undefined') options.snapOffset = 30
if (typeof options.direction === 'undefined') options.direction = 'horizontal'
// 2. Initialize a bunch of strings based on the direction we're splitting.
// A lot of the behavior in the rest of the library is paramatized down to
// rely on CSS strings and classes.
if (options.direction == 'horizontal') {
dimension = 'width'
clientDimension = 'clientWidth'
clientAxis = 'clientX'
position = 'left'
gutterClass = 'gutter gutter-horizontal'
paddingA = 'paddingLeft'
paddingB = 'paddingRight'
if (!options.cursor) options.cursor = 'ew-resize'
} else if (options.direction == 'vertical') {
dimension = 'height'
clientDimension = 'clientHeight'
clientAxis = 'clientY'
position = 'top'
gutterClass = 'gutter gutter-vertical'
paddingA = 'paddingTop'
paddingB = 'paddingBottom'
if (!options.cursor) options.cursor = 'ns-resize'
}
// 3. Define the dragging helper functions, and a few helpers to go with them.
// Each helper is bound to a pair object that contains it's metadata. This
// also makes it easy to store references to listeners that that will be
// added and removed.
//
// Even though there are no other functions contained in them, aliasing
// this to self saves 50 bytes or so since it's used so frequently.
//
// The pair object saves metadata like dragging state, position and
// event listener references.
//
// startDragging calls `calculateSizes` to store the inital size in the pair object.
// It also adds event listeners for mouse/touch events,
// and prevents selection while dragging so avoid the selecting text.
var startDragging = function (e) {
// Alias frequently used variables to save space. 200 bytes.
var self = this
, a = self.a
, b = self.b
// Call the onDragStart callback.
if (!self.dragging && options.onDragStart) {
options.onDragStart()
}
// Don't actually drag the element. We emulate that in the drag function.
e.preventDefault()
// Set the dragging property of the pair object.
self.dragging = true
// Create two event listeners bound to the same pair object and store
// them in the pair object.
self.move = drag.bind(self)
self.stop = stopDragging.bind(self)
// All the binding. `window` gets the stop events in case we drag out of the elements.
global[addEventListener]('mouseup', self.stop)
global[addEventListener]('touchend', self.stop)
global[addEventListener]('touchcancel', self.stop)
self.parent[addEventListener]('mousemove', self.move)
self.parent[addEventListener]('touchmove', self.move)
// Disable selection. Disable!
a[addEventListener]('selectstart', noop)
a[addEventListener]('dragstart', noop)
b[addEventListener]('selectstart', noop)
b[addEventListener]('dragstart', noop)
a.style.userSelect = 'none'
a.style.webkitUserSelect = 'none'
a.style.MozUserSelect = 'none'
a.style.pointerEvents = 'none'
b.style.userSelect = 'none'
b.style.webkitUserSelect = 'none'
b.style.MozUserSelect = 'none'
b.style.pointerEvents = 'none'
// Set the cursor, both on the gutter and the parent element.
// Doing only a, b and gutter causes flickering.
self.gutter.style.cursor = options.cursor
self.parent.style.cursor = options.cursor
// Cache the initial sizes of the pair.
calculateSizes.call(self)
}
// stopDragging is very similar to startDragging in reverse.
, stopDragging = function () {
var self = this
, a = self.a
, b = self.b
if (self.dragging && options.onDragEnd) {
options.onDragEnd()
}
self.dragging = false
// Remove the stored event listeners. This is why we store them.
global[removeEventListener]('mouseup', self.stop)
global[removeEventListener]('touchend', self.stop)
global[removeEventListener]('touchcancel', self.stop)
self.parent[removeEventListener]('mousemove', self.move)
self.parent[removeEventListener]('touchmove', self.move)
// Delete them once they are removed. I think this makes a difference
// in memory usage with a lot of splits on one page. But I don't know for sure.
delete self.stop
delete self.move
a[removeEventListener]('selectstart', noop)
a[removeEventListener]('dragstart', noop)
b[removeEventListener]('selectstart', noop)
b[removeEventListener]('dragstart', noop)
a.style.userSelect = ''
a.style.webkitUserSelect = ''
a.style.MozUserSelect = ''
a.style.pointerEvents = ''
b.style.userSelect = ''
b.style.webkitUserSelect = ''
b.style.MozUserSelect = ''
b.style.pointerEvents = ''
self.gutter.style.cursor = ''
self.parent.style.cursor = ''
}
// drag, where all the magic happens. The logic is really quite simple:
//
// 1. Ignore if the pair is not dragging.
// 2. Get the offset of the event.
// 3. Snap offset to min if within snappable range (within min + snapOffset).
// 4. Actually adjust each element in the pair to offset.
//
// ---------------------------------------------------------------------
// | | <- this.aMin || this.bMin -> | |
// | | | <- this.snapOffset || this.snapOffset -> | | |
// | | | || | | |
// | | | || | | |
// ---------------------------------------------------------------------
// | <- this.start this.size -> |
, drag = function (e) {
var offset
if (!this.dragging) return
// Get the offset of the event from the first side of the
// pair `this.start`. Supports touch events, but not multitouch, so only the first
// finger `touches[0]` is counted.
if ('touches' in e) {
offset = e.touches[0][clientAxis] - this.start
} else {
offset = e[clientAxis] - this.start
}
// If within snapOffset of min or max, set offset to min or max.
// snapOffset buffers aMin and bMin, so logic is opposite for both.
// Include the appropriate gutter sizes to prevent overflows.
if (offset <= this.aMin + options.snapOffset + this.aGutterSize) {
offset = this.aMin + this.aGutterSize
} else if (offset >= this.size - (this.bMin + options.snapOffset + this.bGutterSize)) {
offset = this.size - (this.bMin + this.bGutterSize)
}
// Actually adjust the size.
adjust.call(this, offset)
// Call the drag callback continously. Don't do anything too intensive
// in this callback.
if (options.onDrag) {
options.onDrag()
}
}
// Cache some important sizes when drag starts, so we don't have to do that
// continously:
//
// `size`: The total size of the pair. First element + second element + first gutter + second gutter.
// `percentage`: The percentage between 0-100 that the pair occupies in the parent.
// `start`: The leading side of the first element.
//
// ------------------------------------------------ - - - - - - - - - - -
// | aGutterSize -> ||| | |
// | ||| | |
// | ||| | |
// | ||| <- bGutterSize | |
// ------------------------------------------------ - - - - - - - - - - -
// | <- start size -> | parentSize -> |
, calculateSizes = function () {
// Figure out the parent size minus padding.
var computedStyle = global.getComputedStyle(this.parent)
, parentSize = this.parent[clientDimension] - parseFloat(computedStyle[paddingA]) - parseFloat(computedStyle[paddingB])
this.size = this.a[getBoundingClientRect]()[dimension] + this.b[getBoundingClientRect]()[dimension] + this.aGutterSize + this.bGutterSize
this.percentage = Math.min(this.size / parentSize * 100, 100)
this.start = this.a[getBoundingClientRect]()[position]
}
// Actually adjust the size of elements `a` and `b` to `offset` while dragging.
// calc is used to allow calc(percentage + gutterpx) on the whole split instance,
// which allows the viewport to be resized without additional logic.
// Element a's size is the same as offset. b's size is total size - a size.
// Both sizes are calculated from the initial parent percentage, then the gutter size is subtracted.
, adjust = function (offset) {
this.a.style[dimension] = calc + '(' + (offset / this.size * this.percentage) + '% - ' + this.aGutterSize + 'px)'
this.b.style[dimension] = calc + '(' + (this.percentage - (offset / this.size * this.percentage)) + '% - ' + this.bGutterSize + 'px)'
}
// 4. Define a few more functions that "balance" the entire split instance.
// Split.js tries it's best to cope with min sizes that don't add up.
// At some point this should go away since it breaks out of the calc(% - px) model.
// Maybe it's a user error if you pass uncomputable minSizes.
, fitMin = function () {
var self = this
, a = self.a
, b = self.b
if (a[getBoundingClientRect]()[dimension] < self.aMin) {
a.style[dimension] = (self.aMin - self.aGutterSize) + 'px'
b.style[dimension] = (self.size - self.aMin - self.aGutterSize) + 'px'
} else if (b[getBoundingClientRect]()[dimension] < self.bMin) {
a.style[dimension] = (self.size - self.bMin - self.bGutterSize) + 'px'
b.style[dimension] = (self.bMin - self.bGutterSize) + 'px'
}
}
, fitMinReverse = function () {
var self = this
, a = self.a
, b = self.b
if (b[getBoundingClientRect]()[dimension] < self.bMin) {
a.style[dimension] = (self.size - self.bMin - self.bGutterSize) + 'px'
b.style[dimension] = (self.bMin - self.bGutterSize) + 'px'
} else if (a[getBoundingClientRect]()[dimension] < self.aMin) {
a.style[dimension] = (self.aMin - self.aGutterSize) + 'px'
b.style[dimension] = (self.size - self.aMin - self.aGutterSize) + 'px'
}
}
, balancePairs = function (pairs) {
for (var i = 0; i < pairs.length; i++) {
calculateSizes.call(pairs[i])
fitMin.call(pairs[i])
}
for (i = pairs.length - 1; i >= 0; i--) {
calculateSizes.call(pairs[i])
fitMinReverse.call(pairs[i])
}
}
, setElementSize = function (el, size, gutterSize) {
// Split.js allows setting sizes via numbers (ideally), or if you must,
// by string, like '300px'. This is less than ideal, because it breaks
// the fluid layout that `calc(% - px)` provides. You're on your own if you do that,
// make sure you calculate the gutter size by hand.
if (typeof size !== 'string' && !(size instanceof String)) {
if (!isIE8) {
size = calc + '(' + size + '% - ' + gutterSize + 'px)'
} else {
size = options.sizes[i] + '%'
}
}
el.style[dimension] = size
}
// No-op function to prevent default. Used to prevent selection.
, noop = function () { return false }
// All DOM elements in the split should have a common parent. We can grab
// the first elements parent and hope users read the docs because the
// behavior will be whacky otherwise.
, parent = elementOrSelector(ids[0]).parentNode
// Set default options.sizes to equal percentages of the parent element.
if (!options.sizes) {
var percent = 100 / ids.length
options.sizes = []
for (i = 0; i < ids.length; i++) {
options.sizes.push(percent)
}
}
// Standardize minSize to an array if it isn't already. This allows minSize
// to be passed as a number.
if (!Array.isArray(options.minSize)) {
var minSizes = []
for (i = 0; i < ids.length; i++) {
minSizes.push(options.minSize)
}
options.minSize = minSizes
}
// 5. Loop through the elements while pairing them off. Every pair gets a
// `pair` object, a gutter, and isFirst/isLast properties.
//
// Basic logic:
//
// - Starting with the second element `i > 0`, create `pair` objects with
// `a = ids[i - 1]` and `b = ids[i]`
// - Set gutter sizes based on the _pair_ being first/last. The first and last
// pair have gutterSize / 2, since they only have one half gutter, and not two.
// - Create gutter elements and add event listeners.
// - Set the size of the elements, minus the gutter sizes.
//
// -----------------------------------------------------------------------
// | i=0 | i=1 | i=2 | i=3 |
// | | isFirst | | isLast |
// | pair 0 pair 1 pair 2 |
// | | | | |
// -----------------------------------------------------------------------
for (i = 0; i < ids.length; i++) {
var el = elementOrSelector(ids[i])
, isFirstPair = (i == 1)
, isLastPair = (i == ids.length - 1)
, size = options.sizes[i]
, gutterSize = options.gutterSize
, pair
if (i > 0) {
// Create the pair object with it's metadata.
pair = {
a: elementOrSelector(ids[i - 1]),
b: el,
aMin: options.minSize[i - 1],
bMin: options.minSize[i],
dragging: false,
parent: parent,
isFirst: isFirstPair,
isLast: isLastPair,
direction: options.direction
}
// For first and last pairs, first and last gutter width is half.
pair.aGutterSize = options.gutterSize
pair.bGutterSize = options.gutterSize
if (isFirstPair) {
pair.aGutterSize = options.gutterSize / 2
}
if (isLastPair) {
pair.bGutterSize = options.gutterSize / 2
}
}
// Determine the size of the current element. IE8 is supported by
// staticly assigning sizes without draggable gutters. Assigns a string
// to `size`.
//
// IE9 and above
if (!isIE8) {
// Create gutter elements for each pair.
if (i > 0) {
var gutter = document.createElement('div')
gutter.className = gutterClass
gutter.style[dimension] = options.gutterSize + 'px'
gutter[addEventListener]('mousedown', startDragging.bind(pair))
gutter[addEventListener]('touchstart', startDragging.bind(pair))
parent.insertBefore(gutter, el)
pair.gutter = gutter
}
// Half-size gutters for first and last elements.
if (i === 0 || i == ids.length - 1) {
gutterSize = options.gutterSize / 2
}
}
// Set the element size to our determined size.
setElementSize(el, size, gutterSize)
// After the first iteration, and we have a pair object, append it to the
// list of pairs.
if (i > 0) {
pairs.push(pair)
}
}
// Balance the pairs to try to accomodate min sizes.
balancePairs(pairs)
return {
setSizes: function (sizes) {
for (var i = 0; i < sizes.length; i++) {
if (i > 0) {
var pair = pairs[i - 1]
setElementSize(pair.a, sizes[i - 1], pair.aGutterSize)
setElementSize(pair.b, sizes[i], pair.bGutterSize)
}
}
},
collapse: function (i) {
var pair
if (i === pairs.length) {
pair = pairs[i - 1]
calculateSizes.call(pair)
adjust.call(pair, pair.size - pair.bGutterSize)
} else {
pair = pairs[i]
calculateSizes.call(pair)
adjust.call(pair, pair.aGutterSize)
}
},
destroy: function () {
for (var i = 0; i < pairs.length; i++) {
pairs[i].parent.removeChild(pairs[i].gutter)
pairs[i].a.style[dimension] = ''
pairs[i].b.style[dimension] = ''
}
}
}
}
// Play nicely with module systems, and the browser too if you include it raw.
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = Split
}
exports.Split = Split
} else {
global.Split = Split
}
// Call our wrapper function with the current global. In this case, `window`.
}).call(window);

View file

@ -26,7 +26,9 @@
*/
"use strict";
var UAS_parser = module.exports = {
var Utils = require("../core/Utils.js");
var UAS_parser = {
parse: function (userAgent) {
var result = {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -89,11 +89,11 @@ var ByteRepr = module.exports = {
else if (ordinal < 4294967296) padding = 8;
else padding = 2;
if (padding > 2) app.options.attemptHighlight = false;
if (padding > 2 && app) app.options.attemptHighlight = false;
output += Utils.hex(ordinal, padding) + delim;
} else {
app.options.attemptHighlight = false;
if (app) app.options.attemptHighlight = false;
output += ordinal.toString(base) + delim;
}
}
@ -119,7 +119,7 @@ var ByteRepr = module.exports = {
throw "Error: Base argument must be between 2 and 36";
}
if (base !== 16) {
if (base !== 16 && app) {
app.options.attemptHighlight = false;
}

View file

@ -1,7 +1,8 @@
/* globals xpath */
var Utils = require("../core/Utils.js"),
VKbeautify = require("vkbeautify");
//Prettify = require("google-code-prettify");
VKbeautify = require("vkbeautify"),
dom = require("xmldom").DOMParser,
xpath = require("xpath"),
prettyPrintOne = require("exports-loader?prettyPrintOne!google-code-prettify/bin/prettify.min.js");
/**
@ -36,7 +37,7 @@ var Code = module.exports = {
runSyntaxHighlight: function(input, args) {
var language = args[0],
lineNums = args[1];
return "<code class='prettyprint'>" + Prettify.prettyPrintOne(Utils.escapeHtml(input), language, lineNums) + "</code>";
return "<code class='prettyprint'>" + prettyPrintOne(Utils.escapeHtml(input), language, lineNums) + "</code>";
},
@ -336,36 +337,25 @@ var Code = module.exports = {
var query = args[0],
delimiter = args[1];
var xml;
var doc;
try {
xml = $.parseXML(input);
doc = new dom().parseFromString(input);
} catch (err) {
return "Invalid input XML.";
}
var result;
var nodes;
try {
result = xpath.evaluate(xml, query);
nodes = xpath.select(query, doc);
} catch (err) {
return "Invalid XPath. Details:\n" + err.message;
}
var serializer = new XMLSerializer();
var nodeToString = function(node) {
switch (node.nodeType) {
case Node.ELEMENT_NODE: return serializer.serializeToString(node);
case Node.ATTRIBUTE_NODE: return node.value;
case Node.COMMENT_NODE: return node.data;
case Node.DOCUMENT_NODE: return serializer.serializeToString(node);
default: throw new Error("Unknown Node Type: " + node.nodeType);
}
return node.toString();
};
return Object.keys(result).map(function(key) {
return result[key];
}).slice(0, -1) // all values except last (length)
.map(nodeToString)
.join(delimiter);
return nodes.map(nodeToString).join(delimiter);
},

View file

@ -3,7 +3,7 @@ var rawdeflate = require("zlibjs/bin/rawdeflate.min"),
zlibAndGzip = require("zlibjs/bin/zlib_and_gzip.min"),
zip = require("zlibjs/bin/zip.min"),
unzip = require("zlibjs/bin/unzip.min"),
bzip2 = require("../lib/bzip2.js");
bzip2 = require("exports-loader?bzip2!../lib/bzip2.js");
var Zlib = {
RawDeflate: rawdeflate.Zlib.RawDeflate,

View file

@ -1,6 +1,3 @@
var moment = require("moment-timezone");
/**
* Date and time operations.
*

View file

@ -1,4 +1,4 @@
var UAParser = require("../lib/uas_parser.js");
var UAParser = require("exports-loader?UAS_parser!../lib/uas_parser.js");
/**

View file

@ -92,7 +92,7 @@ var Hexdump = module.exports = {
var w = (width - 13) / 4;
// w should be the specified width of the hexdump and therefore a round number
if (Math.floor(w) !== w || input.indexOf("\r") !== -1 || output.indexOf(13) !== -1) {
app.options.attemptHighlight = false;
if (app) app.options.attemptHighlight = false;
}
return output;
},

View file

@ -1,4 +1,5 @@
/* globals moment */
var Utils = require("../../core/Utils.js");
/**
* Waiter to handle events related to the CyberChef controls (i.e. Bake, Step, Save, Load etc.)
@ -11,7 +12,7 @@
* @param {HTMLApp} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
var ControlsWaiter = function(app, manager) {
var ControlsWaiter = module.exports = function(app, manager) {
this.app = app;
this.manager = manager;
};
@ -78,7 +79,9 @@ ControlsWaiter.prototype.setAutoBake = function(value) {
*/
ControlsWaiter.prototype.bakeClick = function() {
this.app.bake();
$("#output-text").selectRange(0);
var outputText = document.getElementById("output-text");
outputText.focus();
outputText.setSelectionRange(0, 0);
};
@ -87,7 +90,9 @@ ControlsWaiter.prototype.bakeClick = function() {
*/
ControlsWaiter.prototype.stepClick = function() {
this.app.bake(true);
$("#output-text").selectRange(0);
var outputText = document.getElementById("output-text");
outputText.focus();
outputText.setSelectionRange(0, 0);
};

View file

@ -1,4 +1,10 @@
/* globals Split */
var Utils = require("../../core/Utils.js"),
Chef = require("../../core/Chef.js"),
Manager = require("./Manager.js"),
HTMLCategory = require("./HTMLCategory.js"),
HTMLOperation = require("./HTMLOperation.js"),
Split = require("split.js");
/**
* HTML view for CyberChef responsible for building the web page and dealing with all user
@ -14,7 +20,7 @@
* @param {String[]} defaultFavourites - A list of default favourite operations.
* @param {Object} options - Default setting for app options.
*/
var HTMLApp = function(categories, operations, defaultFavourites, defaultOptions) {
var HTMLApp = module.exports = function(categories, operations, defaultFavourites, defaultOptions) {
this.categories = categories;
this.operations = operations;
this.dfavourites = defaultFavourites;

View file

@ -9,7 +9,7 @@
* @param {string} name - The name of the category.
* @param {boolean} selected - Whether this category is pre-selected or not.
*/
var HTMLCategory = function(name, selected) {
var HTMLCategory = module.exports = function(name, selected) {
this.name = name;
this.selected = selected;
this.opList = [];

View file

@ -10,7 +10,7 @@
* @param {HTMLApp} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
var HTMLIngredient = function(config, app, manager) {
var HTMLIngredient = module.exports = function(config, app, manager) {
this.app = app;
this.manager = manager;

View file

@ -1,3 +1,6 @@
var HTMLIngredient = require("./HTMLIngredient.js");
/**
* Object to handle the creation of operations.
*
@ -11,7 +14,7 @@
* @param {HTMLApp} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
var HTMLOperation = function(name, config, app, manager) {
var HTMLOperation = module.exports = function(name, config, app, manager) {
this.app = app;
this.manager = manager;

View file

@ -1,3 +1,6 @@
var Utils = require("../../core/Utils.js");
/**
* Waiter to handle events related to highlighting in CyberChef.
*
@ -8,7 +11,7 @@
* @constructor
* @param {HTMLApp} app - The main view object for CyberChef.
*/
var HighlighterWaiter = function(app) {
var HighlighterWaiter = module.exports = function(app) {
this.app = app;
this.mouseButtonDown = false;

View file

@ -1,3 +1,6 @@
var Utils = require("../../core/Utils.js");
/**
* Waiter to handle events related to the input.
*
@ -9,7 +12,7 @@
* @param {HTMLApp} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
var InputWaiter = function(app, manager) {
var InputWaiter = module.exports = function(app, manager) {
this.app = app;
this.manager = manager;

View file

@ -1,3 +1,14 @@
var WindowWaiter = require("./WindowWaiter.js"),
ControlsWaiter = require("./ControlsWaiter.js"),
RecipeWaiter = require("./RecipeWaiter.js"),
OperationsWaiter = require("./OperationsWaiter.js"),
InputWaiter = require("./InputWaiter.js"),
OutputWaiter = require("./OutputWaiter.js"),
OptionsWaiter = require("./OptionsWaiter.js"),
HighlighterWaiter = require("./HighlighterWaiter.js"),
SeasonalWaiter = require("./SeasonalWaiter.js");
/**
* This object controls the Waiters responsible for handling events from all areas of the app.
*
@ -8,7 +19,7 @@
* @constructor
* @param {HTMLApp} app - The main view object for CyberChef.
*/
var Manager = function(app) {
var Manager = module.exports = function(app) {
this.app = app;
// Define custom events

View file

@ -1,4 +1,6 @@
/* globals Sortable */
var HTMLOperation = require("./HTMLOperation.js"),
Sortable = require("sortablejs");
/**
* Waiter to handle events related to the operations.
@ -11,7 +13,7 @@
* @param {HTMLApp} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
var OperationsWaiter = function(app, manager) {
var OperationsWaiter = module.exports = function(app, manager) {
this.app = app;
this.manager = manager;

View file

@ -8,7 +8,7 @@
* @constructor
* @param {HTMLApp} app - The main view object for CyberChef.
*/
var OptionsWaiter = function(app) {
var OptionsWaiter = module.exports = function(app) {
this.app = app;
};

View file

@ -1,3 +1,6 @@
var Utils = require("../../core/Utils.js");
/**
* Waiter to handle events related to the output.
*
@ -9,7 +12,7 @@
* @param {HTMLApp} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
var OutputWaiter = function(app, manager) {
var OutputWaiter = module.exports = function(app, manager) {
this.app = app;
this.manager = manager;
};

View file

@ -1,4 +1,6 @@
/* globals Sortable */
var HTMLOperation = require("./HTMLOperation.js"),
Sortable = require("sortablejs");
/**
* Waiter to handle events related to the recipe.
@ -11,7 +13,7 @@
* @param {HTMLApp} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
var RecipeWaiter = function(app, manager) {
var RecipeWaiter = module.exports = function(app, manager) {
this.app = app;
this.manager = manager;
this.removeIntent = false;
@ -31,7 +33,8 @@ RecipeWaiter.prototype.initialiseOperationDragNDrop = function() {
sort: true,
animation: 0,
delay: 0,
filter: ".arg-input,.arg", // Relies on commenting out a line in Sortable.js which calls evt.preventDefault()
filter: ".arg-input,.arg",
preventOnFilter: false,
setData: function(dataTransfer, dragEl) {
dataTransfer.setData("Text", dragEl.querySelector(".arg-title").textContent);
},

View file

@ -9,7 +9,7 @@
* @param {HTMLApp} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
var SeasonalWaiter = function(app, manager) {
var SeasonalWaiter = module.exports = function(app, manager) {
this.app = app;
this.manager = manager;
};

View file

@ -8,7 +8,7 @@
* @constructor
* @param {HTMLApp} app - The main view object for CyberChef.
*/
var WindowWaiter = function(app) {
var WindowWaiter = module.exports = function(app) {
this.app = app;
};

View file

@ -1,11 +1,18 @@
/* globals moment */
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*/
require("bootstrap");
require("bootstrap-colorpicker");
require("bootstrap-switch");
var CanvasComponents = require("../../lib/canvascomponents.js");
var HTMLApp = require("./HTMLApp.js"),
Categories = require("../../config/Categories.js"),
OperationConfig = require("../../config/OperationConfig.js");
/**
* Main function used to build the CyberChef web app.
*/

View file

@ -1,31 +1,18 @@
var Chef = require("../../core/Chef.js");
/**
* Node view for CyberChef.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
var chef = new Chef();
var Chef = require("../../core/Chef.js");
console.log(chef.bake("test", [{"op":"To Hex", "args":["Space"]}], {}, 0, false));
module.exports = {
console.log(chef.bake("425a6839314159265359b218ed630000031380400104002a438c00200021a9ea601a10003202185d5ed68ca6442f1e177245385090b218ed63",
[
{
"op" : "From Hex",
"args" : ["Space"]
},
{
"op" : "Bzip2 Decompress",
"args" : []
}
],
{}, 0, false
));
bake: function(input, recipeConfig) {
this.chef = new Chef();
return this.chef.bake(input, recipeConfig, {}, 0, false);
}
console.log(chef.bake("192.168.0.0/30",
[{"op":"Parse IP range", "args":[true, true, false]}],
{}, 0, false
));
};

View file

@ -1,24 +0,0 @@
/* eslint-env node */
/**
* NodeRunner.js
*
* The purpose of this file is to execute via PhantomJS the file
* PhantomRunner.js, because PhantomJS is managed by node.
*
* @author tlwr [toby@toby.codes]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
var path = require("path"),
phantomjs = require("phantomjs-prebuilt"),
phantomEntryPoint = path.join(__dirname, "PhantomRunner.js"),
program = phantomjs.exec(phantomEntryPoint);
program.stdout.pipe(process.stdout);
program.stderr.pipe(process.stderr);
program.on("exit", function(status) {
process.exit(status);
});

View file

@ -1,99 +0,0 @@
/* eslint-env node */
/* globals phantom */
/**
* PhantomRunner.js
*
* This file navigates to build/test/index.html and logs the test results.
*
* @author tlwr [toby@toby.codes]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
var page = require("webpage").create(),
allTestsPassing = true,
testStatusCounts = {
total: 0,
};
/**
* Helper function to convert a status to an icon.
*
* @param {string} status
* @returns {string}
*/
function statusToIcon(status) {
var icons = {
erroring: "🔥",
failing: "❌",
passing: "✔️️",
};
return icons[status] || "?";
}
/**
* Callback function to handle test results.
*/
page.onCallback = function(messageType) {
if (messageType === "testResult") {
var testResult = arguments[1];
allTestsPassing = allTestsPassing && testResult.status === "passing";
var newCount = (testStatusCounts[testResult.status] || 0) + 1;
testStatusCounts[testResult.status] = newCount;
testStatusCounts.total += 1;
console.log([
statusToIcon(testResult.status),
testResult.test.name
].join(" "));
if (testResult.output) {
console.log(
testResult.output
.trim()
.replace(/^/, "\t")
.replace(/\n/g, "\n\t")
);
}
} else if (messageType === "exit") {
console.log("\n");
for (var testStatus in testStatusCounts) {
var count = testStatusCounts[testStatus];
if (count > 0) {
console.log(testStatus.toUpperCase(), count);
}
}
if (!allTestsPassing) {
console.log("\nNot all tests are passing");
}
phantom.exit(allTestsPassing ? 0 : 1);
}
};
/**
* Open the test webpage in PhantomJS.
*/
page.open("build/test/index.html", function(status) {
if (status !== "success") {
console.log("STATUS: ", status);
phantom.exit(1);
}
});
/**
* Fail if the process takes longer than 10 seconds.
*/
setTimeout(function() {
console.log("Tests took longer than 10 seconds to run, returning.");
phantom.exit(1);
}, 10 * 1000);

View file

@ -8,6 +8,7 @@
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
var Chef = require("../src/js/core/Chef.js");
(function() {
/**
@ -85,5 +86,6 @@
// Singleton TestRegister, keeping things simple and obvious.
window.TestRegister = new TestRegister();
global.TestRegister = global.TestRegister || new TestRegister();
module.exports = global.TestRegister;
})();

View file

@ -1,38 +1,92 @@
/**
* TestRunner.js
*
* This is for actually running the tests in the test register.
* For running the tests in the test register.
*
* @author tlwr [toby@toby.codes]
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
var TestRegister = require("./TestRegister.js"),
allTestsPassing = true,
testStatusCounts = {
total: 0,
};
document.addEventListener("DOMContentLoaded", function() {
TestRegister.runTests()
/**
* Requires and returns all modules that match.
*
* @param {Object} requireContext
* @returns {Object[]}
*/
function requireAll(requireContext) {
return requireContext.keys().map(requireContext);
}
// Import all tests
requireAll(require.context("./tests", true, /.+\.js$/));
/**
* Helper function to convert a status to an icon.
*
* @param {string} status
* @returns {string}
*/
function statusToIcon(status) {
var icons = {
erroring: "🔥",
failing: "❌",
passing: "✔️️",
};
return icons[status] || "?";
}
/**
* Displays a given test result in the console.
*
* @param {Object} testResult
*/
function handleTestResult(testResult) {
allTestsPassing = allTestsPassing && testResult.status === "passing";
var newCount = (testStatusCounts[testResult.status] || 0) + 1;
testStatusCounts[testResult.status] = newCount;
testStatusCounts.total += 1;
console.log([
statusToIcon(testResult.status),
testResult.test.name
].join(" "));
if (testResult.output) {
console.log(
testResult.output
.trim()
.replace(/^/, "\t")
.replace(/\n/g, "\n\t")
);
}
}
TestRegister.runTests()
.then(function(results) {
results.forEach(function(testResult) {
results.forEach(handleTestResult);
if (typeof window.callPhantom === "function") {
// If we're running this in PhantomJS
window.callPhantom(
"testResult",
testResult
);
} else {
// If we're just viewing this in a normal browser
var output = [
"----------",
testResult.test.name,
testResult.status,
testResult.output,
].join("<br>");
document.querySelector("main").innerHTML += output;
console.log("\n");
for (var testStatus in testStatusCounts) {
var count = testStatusCounts[testStatus];
if (count > 0) {
console.log(testStatus.toUpperCase(), count);
}
});
if (typeof window.callPhantom === "function") {
window.callPhantom("exit");
}
if (!allTestsPassing) {
console.log("\nNot all tests are passing");
}
process.exit(allTestsPassing ? 0 : 1);
});
});

View file

@ -1,33 +0,0 @@
<!--
CyberChef test suite
@author tlwr [toby@toby.codes]
@copyright Crown Copyright 2017
@license Apache-2.0
Copyright 2017 Crown Copyright
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CyberChef test suite</title>
</head>
<body>
<main style="white-space: pre"></main>
<script type="application/javascript" src="tests.js"></script>
</body>
</html>

View file

@ -6,6 +6,8 @@
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
var TestRegister = require("../../TestRegister.js");
TestRegister.addTests([
{
name: "To Base58 (Bitcoin): nothing",

View file

@ -5,6 +5,8 @@
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
var TestRegister = require("../../TestRegister.js");
TestRegister.addTests([
{
name: "Bzip2 decompress",

View file

@ -6,6 +6,8 @@
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
var TestRegister = require("../../TestRegister.js");
TestRegister.addTests([
{
name: "Fork: nothing",

View file

@ -6,6 +6,8 @@
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
var TestRegister = require("../../TestRegister.js");
TestRegister.addTests([
{
name: "To Morse Code: 'SOS'",

View file

@ -5,6 +5,8 @@
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
var TestRegister = require("../../TestRegister.js");
TestRegister.addTests([
{
name: "Regex, non-HTML op",

View file

@ -1,11 +0,0 @@
/* eslint-env node */
var path = require("path");
module.exports = {
entry: "./src/js/views/html/index.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "build/dev")
}
};