Merge pull request #214 from juliandescottes/feature-add-tests

Feature add tests
This commit is contained in:
Julian Descottes 2014-08-26 23:57:45 +02:00
commit 913ef272cf
49 changed files with 1164 additions and 182 deletions

View file

@ -1,6 +1,6 @@
language: node_js language: node_js
node_js: node_js:
- 0.8 - 0.10
before_install: before_install:
- npm update -g npm - npm update -g npm
- npm install -g grunt-cli - npm install -g grunt-cli

View file

@ -10,27 +10,48 @@
* If you run this task locally, it may require some env set up first. * If you run this task locally, it may require some env set up first.
*/ */
var SOURCE_FOLDER = "src";
module.exports = function(grunt) { module.exports = function(grunt) {
var dateFormat = require('dateformat'); var dateFormat = require('dateformat');
var now = new Date(); var now = new Date();
var version = '-' + dateFormat(now, "yyyy-mm-dd-hh-MM"); var version = '-' + dateFormat(now, "yyyy-mm-dd-hh-MM");
var mapToSrcFolder = function (path) {return [SOURCE_FOLDER, path].join('/');}; var mapToSrcFolder = function (path) {
return "src/" + path;
};
var piskelScripts = require('./src/piskel-script-list.js').scripts.map(mapToSrcFolder); var piskelScripts = require('./src/piskel-script-list.js').scripts.map(mapToSrcFolder).filter(function (path) {
return path.indexOf('devtools') === -1;
});
var piskelStyles = require('./src/piskel-style-list.js').styles.map(mapToSrcFolder); var piskelStyles = require('./src/piskel-style-list.js').styles.map(mapToSrcFolder);
var getGhostConfig = function (delay) { var mapToCasperFolder = function (path) {
return "test/casperjs/" + path;
};
var casperEnvironments = {
'local' : {
suite : './test/casperjs/LocalTestSuite.js',
delay : 50
},
'travis' : {
suite : './test/casperjs/TravisTestSuite.js',
delay : 5000
}
};
var getCasperConfig = function (env) {
var conf = casperEnvironments[env];
var tests = require(conf.suite).tests.map(mapToCasperFolder);
return { return {
filesSrc : ['test/integration/casperjs/*_test.js'], filesSrc : tests,
options : { options : {
args : { args : {
baseUrl : 'http://localhost:' + '<%= connect.test.options.port %>/src/', baseUrl : 'http://localhost:' + '<%= express.test.options.port %>/',
mode : '?debug', mode : '?debug',
delay : delay delay : conf.delay
}, },
async : false,
direct : false, direct : false,
logLevel : 'info', logLevel : 'info',
printCommand : false, printCommand : false,
@ -39,6 +60,23 @@ module.exports = function(grunt) {
}; };
}; };
var getExpressConfig = function (source, port, host) {
var bases;
if (typeof source === 'string') {
bases = [source];
} else if (Array.isArray(source)) {
bases = source;
}
return {
options: {
port: port,
hostname : host || 'localhost',
bases: bases
}
};
};
grunt.initConfig({ grunt.initConfig({
clean: { clean: {
before: ['dest'], before: ['dest'],
@ -62,29 +100,10 @@ module.exports = function(grunt) {
'!src/js/lib/**/*.js' // Exclude lib folder (note the leading !) '!src/js/lib/**/*.js' // Exclude lib folder (note the leading !)
] ]
}, },
connect : {
test : {
options : {
base : '.',
port : 4321
}
}
},
express: { express: {
regular: { test: getExpressConfig(['src', 'test'], 9991),
options: { regular: getExpressConfig('dest', 9001),
port: 9001, debug: getExpressConfig(['src', 'test'], 9901)
hostname : 'localhost',
bases: ['dest']
}
},
debug: {
options: {
port: 9901,
hostname : 'localhost',
bases: ['src']
}
}
}, },
open : { open : {
regular : { regular : {
@ -105,8 +124,8 @@ module.exports = function(grunt) {
} }
}, },
ghost : { ghost : {
'default' : getGhostConfig(5000), 'travis' : getCasperConfig('travis'),
local : getGhostConfig(50) 'local' : getCasperConfig('local')
}, },
concat : { concat : {
js : { js : {
@ -236,6 +255,11 @@ module.exports = function(grunt) {
dest: 'build/closure/closure_compiled_binary.js' dest: 'build/closure/closure_compiled_binary.js'
} }
}, },
karma: {
unit: {
configFile: 'karma.conf.js'
}
},
nodewebkit: { nodewebkit: {
options: { options: {
build_dir: './dest/desktop/', // destination folder of releases. build_dir: './dest/desktop/', // destination folder of releases.
@ -262,7 +286,6 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-closure-tools'); grunt.loadNpmTasks('grunt-closure-tools');
grunt.loadNpmTasks('grunt-contrib-clean'); grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-uglify');
@ -271,6 +294,7 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-replace'); grunt.loadNpmTasks('grunt-replace');
grunt.loadNpmTasks('grunt-ghost'); grunt.loadNpmTasks('grunt-ghost');
grunt.loadNpmTasks('grunt-open'); grunt.loadNpmTasks('grunt-open');
grunt.loadNpmTasks('grunt-karma');
grunt.loadNpmTasks('grunt-leading-indent'); grunt.loadNpmTasks('grunt-leading-indent');
grunt.loadNpmTasks('grunt-node-webkit-builder'); grunt.loadNpmTasks('grunt-node-webkit-builder');
grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-contrib-copy');
@ -278,11 +302,17 @@ module.exports = function(grunt) {
// Validate // Validate
grunt.registerTask('lint', ['leadingIndent:jsFiles', 'leadingIndent:cssFiles', 'jshint']); grunt.registerTask('lint', ['leadingIndent:jsFiles', 'leadingIndent:cssFiles', 'jshint']);
// Validate & Test // karma/unit-tests task
grunt.registerTask('test', ['lint', 'compile', 'connect:test', 'ghost:default']); grunt.registerTask('unit-test', ['karma']);
// Validate & Test
grunt.registerTask('test-travis', ['lint', 'compile', 'unit-test', 'express:test', 'ghost:travis']);
// Validate & Test (faster version) will NOT work on travis !! // Validate & Test (faster version) will NOT work on travis !!
grunt.registerTask('precommit', ['lint', 'compile', 'connect:test', 'ghost:local']); grunt.registerTask('test-local', ['lint', 'compile', 'unit-test', 'express:test', 'ghost:local']);
grunt.registerTask('test', ['test-travis']);
grunt.registerTask('precommit', ['test-local']);
// Compile JS code (eg verify JSDoc annotation and types, no actual minified code generated). // Compile JS code (eg verify JSDoc annotation and types, no actual minified code generated).
grunt.registerTask('compile', ['closureCompiler:compile', 'clean:after']); grunt.registerTask('compile', ['closureCompiler:compile', 'clean:after']);

67
karma.conf.js Normal file
View file

@ -0,0 +1,67 @@
// Karma configuration
// Generated on Tue Jul 22 2014 23:49:26 GMT+0200 (Romance Daylight Time)
module.exports = function(config) {
var mapToSrcFolder = function (path) {return ['src', path].join('/');};
var piskelScripts = require('./src/piskel-script-list.js').scripts.map(mapToSrcFolder);
piskelScripts.push('test/js/**/*.js');
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: piskelScripts,
// list of files to exclude
exclude: [],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['PhantomJS'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: true
});
};

View file

@ -12,34 +12,14 @@ SETLOCAL
set APP_BIN="%PISKEL_HOME%\dest\desktop\cache\win\0.9.2" set APP_BIN="%PISKEL_HOME%\dest\desktop\cache\win\0.9.2"
set MISC_FOLDER=%PISKEL_HOME%\misc set MISC_FOLDER=%PISKEL_HOME%\misc
set RELEASES_FOLDER=%PISKEL_HOME%\dest\desktop\releases set RELEASES_FOLDER=%PISKEL_HOME%\dest\desktop\releases
set DEST_FOLDER=%RELEASES_FOLDER%\win set DEST_FOLDER=%RELEASES_FOLDER%\piskel\win\piskel
ECHO "Building Piskel executable for Windows ..."
ECHO "Creating release directory ..."
MKDIR "%DEST_FOLDER%"
ECHO "DONE"
ECHO "Packaging executable ..."
COPY /b "%APP_BIN%\nw.exe"+"%RELEASES_FOLDER%\piskel\piskel.nw" "%DEST_FOLDER%\piskel-raw.exe"
ECHO "DONE"
ECHO "COPYing dependencies ..."
COPY "%APP_BIN%\*.dll" "%DEST_FOLDER%\"
COPY "%APP_BIN%\nw.pak" "%DEST_FOLDER%\"
ECHO "DONE"
ECHO "Updating Piskel icon -- Using Resource Hacker" ECHO "Updating Piskel icon -- Using Resource Hacker"
%RESOURCE_HACKER_PATH%\ResHacker -addoverwrite "%DEST_FOLDER%\piskel-raw.exe", "%DEST_FOLDER%\piskel-exploded.exe", "%MISC_FOLDER%\desktop\logo.ico", ICONGROUP, IDR_MAINFRAME, 1033 %RESOURCE_HACKER_PATH%\ResHacker -addoverwrite "%DEST_FOLDER%\piskel.exe", "%DEST_FOLDER%\piskel-logo.exe", "%MISC_FOLDER%\desktop\logo.ico", ICONGROUP, IDR_MAINFRAME, 1033
DEL "%DEST_FOLDER%\piskel-raw.exe" DEL "%DEST_FOLDER%\piskel.exe"
ECHO "DONE" ECHO "DONE"
ECHO "Boxing application to single file -- Using Enigma Virtual Box"
%VBOX_PATH%\enigmavbconsole "%MISC_FOLDER%\desktop\package-piskel.evb"
DEL "%DEST_FOLDER%\*.dll"
DEL "%DEST_FOLDER%\nw.pak"
DEL "%DEST_FOLDER%\piskel-exploded.exe"
ECHO "DONE"
PAUSE PAUSE
explorer "%DEST_FOLDER%\" explorer "%DEST_FOLDER%\"

View file

@ -3,7 +3,7 @@
"name": "piskel", "name": "piskel",
"main": "./dest/index.html", "main": "./dest/index.html",
"description": "Web based 2d animations editor", "description": "Web based 2d animations editor",
"version": "0.1.0", "version": "0.2.0",
"homepage": "http://github.com/juliandescottes/piskel", "homepage": "http://github.com/juliandescottes/piskel",
"repository": { "repository": {
"type": "git", "type": "git",
@ -14,23 +14,27 @@
"start": "nodewebkit" "start": "nodewebkit"
}, },
"devDependencies": { "devDependencies": {
"grunt": "~0.4.1", "dateformat": "1.0.8-1.2.3",
"grunt": "~0.4.5",
"grunt-closure-tools": "~0.9.7",
"grunt-contrib-clean": "0.5.0", "grunt-contrib-clean": "0.5.0",
"grunt-contrib-connect": "0.3.0", "grunt-contrib-concat": "0.5.0",
"grunt-contrib-concat": "0.1.2",
"grunt-contrib-copy": "0.5.0", "grunt-contrib-copy": "0.5.0",
"grunt-contrib-jshint": "0.5.4", "grunt-contrib-jshint": "0.10.0",
"grunt-contrib-uglify": "0.2.2", "grunt-contrib-uglify": "0.5.0",
"grunt-contrib-watch": "0.6.1", "grunt-contrib-watch": "0.6.1",
"grunt-express": "1.0", "grunt-express": "1.4.1",
"grunt-replace": "0.7.8", "grunt-ghost": "1.1.0",
"grunt-ghost": "1.0.12",
"grunt-open": "0.2.3",
"grunt-leading-indent": "0.1.0", "grunt-leading-indent": "0.1.0",
"grunt-closure-tools": "~0.8.3", "grunt-node-webkit-builder": "0.1.21",
"grunt-node-webkit-builder": "0.1.19", "grunt-open": "0.2.3",
"nodewebkit": "0.8.4", "grunt-replace": "0.7.8",
"dateformat" : "1.0.8-1.2.3" "grunt-karma": "~0.8.2",
"karma": "0.12.17",
"karma-chrome-launcher": "^0.1.4",
"karma-phantomjs-launcher": "^0.1.4",
"karma-jasmine": "^0.1.5",
"nodewebkit": "~0.10.1"
}, },
"window": { "window": {
"title": "Piskel", "title": "Piskel",

View file

@ -69,5 +69,8 @@ var Constants = {
MOUSEMOVE_THROTTLING : 10, MOUSEMOVE_THROTTLING : 10,
ABSTRACT_FUNCTION : function () {throw 'abstract method should be implemented';}, ABSTRACT_FUNCTION : function () {throw 'abstract method should be implemented';},
EMPTY_FUNCTION : function () {} EMPTY_FUNCTION : function () {},
// TESTS
DRAWING_TEST_FOLDER : 'drawing'
}; };

View file

@ -2,6 +2,8 @@
var Events = { var Events = {
TOOL_SELECTED : "TOOL_SELECTED", TOOL_SELECTED : "TOOL_SELECTED",
SELECT_TOOL : "SELECT_TOOL",
TOOL_RELEASED : "TOOL_RELEASED", TOOL_RELEASED : "TOOL_RELEASED",
SELECT_PRIMARY_COLOR: "SELECT_PRIMARY_COLOR", SELECT_PRIMARY_COLOR: "SELECT_PRIMARY_COLOR",
SELECT_SECONDARY_COLOR: "SELECT_SECONDARY_COLOR", SELECT_SECONDARY_COLOR: "SELECT_SECONDARY_COLOR",
@ -47,5 +49,12 @@ var Events = {
ZOOM_CHANGED : "ZOOM_CHANGED", ZOOM_CHANGED : "ZOOM_CHANGED",
CURRENT_COLORS_UPDATED : "CURRENT_COLORS_UPDATED" CURRENT_COLORS_UPDATED : "CURRENT_COLORS_UPDATED",
MOUSE_EVENT : "MOUSE_EVENT",
// Tests
TEST_RECORD_END : "TEST_RECORD_END",
TEST_CASE_END : "TEST_CASE_END",
TEST_SUITE_END : "TEST_SUITE_END"
}; };

View file

@ -29,8 +29,8 @@
var layer = new pskl.model.Layer("Layer 1"); var layer = new pskl.model.Layer("Layer 1");
var frame = new pskl.model.Frame(size.width, size.height); var frame = new pskl.model.Frame(size.width, size.height);
layer.addFrame(frame);
layer.addFrame(frame);
piskel.addLayer(layer); piskel.addLayer(layer);
this.corePiskelController = new pskl.controller.piskel.PiskelController(piskel); this.corePiskelController = new pskl.controller.piskel.PiskelController(piskel);
@ -115,7 +115,6 @@
} }
this.storageService.init(); this.storageService.init();
var drawingLoop = new pskl.rendering.DrawingLoop(); var drawingLoop = new pskl.rendering.DrawingLoop();
drawingLoop.addCallback(this.render, this); drawingLoop.addCallback(this.render, this);
drawingLoop.start(); drawingLoop.start();
@ -126,6 +125,10 @@
if (piskelData && piskelData.piskel) { if (piskelData && piskelData.piskel) {
this.loadPiskel_(piskelData.piskel, piskelData.descriptor, piskelData.fps); this.loadPiskel_(piskelData.piskel, piskelData.descriptor, piskelData.fps);
} }
if (pskl.devtools) {
pskl.devtools.init();
}
}, },
loadPiskel_ : function (serializedPiskel, descriptor, fps) { loadPiskel_ : function (serializedPiskel, descriptor, fps) {

View file

@ -134,8 +134,9 @@
* @private * @private
*/ */
ns.DrawingController.prototype.onMousedown_ = function (event) { ns.DrawingController.prototype.onMousedown_ = function (event) {
$.publish(Events.MOUSE_EVENT, [event, this]);
var frame = this.piskelController.getCurrentFrame(); var frame = this.piskelController.getCurrentFrame();
var coords = this.renderer.getCoordinates(event.clientX, event.clientY); var coords = this.getSpriteCoordinates(event.clientX, event.clientY);
if (event.button === Constants.MIDDLE_BUTTON) { if (event.button === Constants.MIDDLE_BUTTON) {
if (frame.containsPixel(coords.x, coords.y)) { if (frame.containsPixel(coords.x, coords.y)) {
@ -204,10 +205,11 @@
}; };
ns.DrawingController.prototype.moveTool_ = function (x, y, event) { ns.DrawingController.prototype.moveTool_ = function (x, y, event) {
var coords = this.renderer.getCoordinates(x, y); var coords = this.getSpriteCoordinates(x, y);
var currentFrame = this.piskelController.getCurrentFrame(); var currentFrame = this.piskelController.getCurrentFrame();
if (this.isClicked) { if (this.isClicked) {
$.publish(Events.MOUSE_EVENT, [event, this]);
// Warning : do not call setCurrentButton here // Warning : do not call setCurrentButton here
// mousemove do not have the correct mouse button information on all browsers // mousemove do not have the correct mouse button information on all browsers
this.currentToolBehavior.moveToolAt( this.currentToolBehavior.moveToolAt(
@ -248,6 +250,7 @@
*/ */
ns.DrawingController.prototype.onMouseup_ = function (event) { ns.DrawingController.prototype.onMouseup_ = function (event) {
if(this.isClicked) { if(this.isClicked) {
$.publish(Events.MOUSE_EVENT, [event, this]);
// A mouse button was clicked on the drawing canvas before this mouseup event, // A mouse button was clicked on the drawing canvas before this mouseup event,
// the user was probably drawing on the canvas. // the user was probably drawing on the canvas.
// Note: The mousemove movement (and the mouseup) may end up outside // Note: The mousemove movement (and the mouseup) may end up outside
@ -256,7 +259,7 @@
this.isClicked = false; this.isClicked = false;
this.setCurrentButton(event); this.setCurrentButton(event);
var coords = this.renderer.getCoordinates(event.clientX, event.clientY); var coords = this.getSpriteCoordinates(event.clientX, event.clientY);
this.currentToolBehavior.releaseToolAt( this.currentToolBehavior.releaseToolAt(
coords.x, coords.x,
coords.y, coords.y,
@ -280,6 +283,10 @@
return this.renderer.getCoordinates(screenX, screenY); return this.renderer.getCoordinates(screenX, screenY);
}; };
ns.DrawingController.prototype.getScreenCoordinates = function(spriteX, spriteY) {
return this.renderer.reverseCoordinates(spriteX, spriteY);
};
ns.DrawingController.prototype.setCurrentButton = function (event) { ns.DrawingController.prototype.setCurrentButton = function (event) {
this.currentMouseButton_ = event.button; this.currentMouseButton_ = event.button;
}; };

View file

@ -38,6 +38,8 @@
this.selectTool_(this.tools[0]); this.selectTool_(this.tools[0]);
// Activate listener on tool panel: // Activate listener on tool panel:
$("#tool-section").mousedown($.proxy(this.onToolIconClicked_, this)); $("#tool-section").mousedown($.proxy(this.onToolIconClicked_, this));
$.subscribe(Events.SELECT_TOOL, this.onSelectToolEvent_.bind(this));
}; };
/** /**
@ -54,6 +56,13 @@
stage.data("selected-tool-class", tool.instance.toolId); stage.data("selected-tool-class", tool.instance.toolId);
}; };
ns.ToolController.prototype.onSelectToolEvent_ = function(event, toolId) {
var tool = this.getToolById_(toolId);
if (tool) {
this.selectTool_(tool);
}
};
/** /**
* @private * @private
*/ */

View file

@ -47,17 +47,6 @@
this.duplicateFrameAt(this.getCurrentFrameIndex()); this.duplicateFrameAt(this.getCurrentFrameIndex());
}; };
ns.PublicPiskelController.prototype.raiseSaveStateEvent_ = function (fn, args) {
$.publish(Events.PISKEL_SAVE_STATE, {
type : pskl.service.HistoryService.REPLAY_NO_SNAPSHOT,
scope : this,
replay : {
fn : fn,
args : args
}
});
};
ns.PublicPiskelController.prototype.replay = function (frame, replayData) { ns.PublicPiskelController.prototype.replay = function (frame, replayData) {
replayData.fn.apply(this.piskelController, replayData.args); replayData.fn.apply(this.piskelController, replayData.args);
}; };
@ -141,4 +130,15 @@
return this.piskelController.piskel; return this.piskelController.piskel;
}; };
ns.PublicPiskelController.prototype.raiseSaveStateEvent_ = function (fn, args) {
$.publish(Events.PISKEL_SAVE_STATE, {
type : pskl.service.HistoryService.REPLAY_NO_SNAPSHOT,
scope : this,
replay : {
fn : fn,
args : args
}
});
};
})(); })();

View file

@ -39,7 +39,10 @@
}; };
ns.ImportController.prototype.onOpenPiskelChange_ = function (evt) { ns.ImportController.prototype.onOpenPiskelChange_ = function (evt) {
this.openPiskelFile_(); var files = this.hiddenOpenPiskelInput.get(0).files;
if (files.length == 1) {
this.openPiskelFile_(files[0]);
}
}; };
ns.ImportController.prototype.onOpenPiskelClick_ = function (evt) { ns.ImportController.prototype.onOpenPiskelClick_ = function (evt) {
@ -51,19 +54,14 @@
this.closeDrawer_(); this.closeDrawer_();
}; };
ns.ImportController.prototype.openPiskelFile_ = function () { ns.ImportController.prototype.openPiskelFile_ = function (file) {
var files = this.hiddenOpenPiskelInput.get(0).files; if (this.isPiskel_(file)){
if (files.length == 1) { pskl.utils.PiskelFileUtils.loadFromFile(file, function (piskel, descriptor, fps) {
piskel.setDescriptor(descriptor);
var file = files[0]; pskl.app.piskelController.setPiskel(piskel);
if (this.isPiskel_(file)){ pskl.app.animationController.setFPS(fps);
pskl.utils.PiskelFileUtils.loadFromFile(file, function (piskel, descriptor, fps) { });
piskel.setDescriptor(descriptor); this.closeDrawer_();
pskl.app.piskelController.setPiskel(piskel);
pskl.app.animationController.setFPS(fps);
});
this.closeDrawer_();
}
} }
}; };

View file

@ -30,7 +30,8 @@
for (var i = 0; i < this.piskelController.getFrameCount(); i++) { for (var i = 0; i < this.piskelController.getFrameCount(); i++) {
var frame = this.piskelController.getFrameAt(i); var frame = this.piskelController.getFrameAt(i);
var canvas = this.getFrameAsCanvas_(frame); var canvas = this.getFrameAsCanvas_(frame);
var filename = "sprite_" + (i+1) + ".png"; var basename = document.getElementById("zip-file-name").value || "sprite_";
var filename = basename + (i+1) + ".png";
zip.file(filename, pskl.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true}); zip.file(filename, pskl.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true});
} }
@ -85,4 +86,4 @@
} }
return url; return url;
}; };
})(); })();

View file

@ -0,0 +1,147 @@
(function () {
var ns = $.namespace('pskl.devtools');
ns.DrawingTestPlayer = function (testRecord, step) {
this.initialState = testRecord.initialState;
this.events = testRecord.events;
this.referencePng = testRecord.png;
this.step = step || ns.DrawingTestPlayer.DEFAULT_STEP;
this.callbacks = [];
this.shim = null;
};
ns.DrawingTestPlayer.DEFAULT_STEP = 50;
ns.DrawingTestPlayer.prototype.start = function () {
this.setupInitialState_();
this.createMouseShim_();
this.regenerateReferencePng().then(function () {
this.playEvent_(0);
}.bind(this));
};
ns.DrawingTestPlayer.prototype.setupInitialState_ = function () {
var size = this.initialState.size;
var piskel = this.createPiskel_(size.width, size.height);
pskl.app.piskelController.setPiskel(piskel);
$.publish(Events.SELECT_PRIMARY_COLOR, [this.initialState.primaryColor]);
$.publish(Events.SELECT_SECONDARY_COLOR, [this.initialState.secondaryColor]);
$.publish(Events.SELECT_TOOL, [this.initialState.selectedTool]);
};
ns.DrawingTestPlayer.prototype.createPiskel_ = function (width, height) {
var descriptor = new pskl.model.piskel.Descriptor('TestPiskel', '');
var piskel = new pskl.model.Piskel(width, height, descriptor);
var layer = new pskl.model.Layer("Layer 1");
var frame = new pskl.model.Frame(width, height);
layer.addFrame(frame);
piskel.addLayer(layer);
return piskel;
};
ns.DrawingTestPlayer.prototype.regenerateReferencePng = function () {
var image = new Image();
var then = function () {};
image.onload = function () {
this.referencePng = pskl.CanvasUtils.createFromImage(image).toDataURL();
then();
}.bind(this);
image.src = this.referencePng;
return {
then : function (cb) {
then = cb;
}
};
};
ns.DrawingTestPlayer.prototype.createMouseShim_ = function () {
this.shim = document.createElement('DIV');
this.shim.style.cssText = 'position:fixed;top:0;left:0;right:0;left:0;bottom:0;z-index:15000';
this.shim.addEventListener('mousemove', function (e) {
e.stopPropagation();
e.preventDefault();
}, true);
document.body.appendChild(this.shim);
};
ns.DrawingTestPlayer.prototype.removeMouseShim_ = function () {
this.shim.parentNode.removeChild(this.shim);
this.shim = null;
};
ns.DrawingTestPlayer.prototype.playEvent_ = function (index) {
this.timer = window.setTimeout(function () {
var recordEvent = this.events[index];
if (recordEvent.type === 'mouse-event') {
this.playMouseEvent_(recordEvent);
} else if (recordEvent.type === 'color-event') {
this.playColorEvent_(recordEvent);
} else if (recordEvent.type === 'tool-event') {
this.playToolEvent_(recordEvent);
} else if (recordEvent.type === 'instrumented-event') {
this.playInstrumentedEvent_(recordEvent);
}
if (this.events[index+1]) {
this.playEvent_(index+1);
} else {
this.onTestEnd_();
}
}.bind(this), this.step);
};
ns.DrawingTestPlayer.prototype.playMouseEvent_ = function (recordEvent) {
var event = recordEvent.event;
var screenCoordinates = pskl.app.drawingController.getScreenCoordinates(recordEvent.coords.x, recordEvent.coords.y);
event.clientX = screenCoordinates.x;
event.clientY = screenCoordinates.y;
if (event.type == 'mousedown') {
pskl.app.drawingController.onMousedown_(event);
} else if (event.type == 'mouseup') {
pskl.app.drawingController.onMouseup_(event);
} else if (event.type == 'mousemove') {
pskl.app.drawingController.onMousemove_(event);
}
};
ns.DrawingTestPlayer.prototype.playColorEvent_ = function (recordEvent) {
if (recordEvent.isPrimary) {
$.publish(Events.SELECT_PRIMARY_COLOR, [recordEvent.color]);
} else {
$.publish(Events.SELECT_SECONDARY_COLOR, [recordEvent.color]);
}
};
ns.DrawingTestPlayer.prototype.playToolEvent_ = function (recordEvent) {
$.publish(Events.SELECT_TOOL, [recordEvent.toolId]);
};
ns.DrawingTestPlayer.prototype.playInstrumentedEvent_ = function (recordEvent) {
pskl.app.piskelController[recordEvent.methodName].apply(pskl.app.piskelController, recordEvent.args);
};
ns.DrawingTestPlayer.prototype.onTestEnd_ = function () {
this.removeMouseShim_();
var renderer = new pskl.rendering.PiskelRenderer(pskl.app.piskelController);
var png = renderer.renderAsCanvas().toDataURL();
var success = png === this.referencePng;
$.publish(Events.TEST_RECORD_END, [success, png, this.referencePng]);
this.callbacks.forEach(function (callback) {
callback(success, png, this.referencePng);
});
};
ns.DrawingTestPlayer.prototype.addEndTestCallback = function (callback) {
this.callbacks.push(callback);
};
})();

View file

@ -0,0 +1,115 @@
(function () {
var ns = $.namespace('pskl.devtools');
ns.DrawingTestRecorder = function (piskelController) {
this.piskelController = piskelController;
this.isRecording = false;
this.reset();
};
ns.DrawingTestRecorder.prototype.init = function () {
$.subscribe(Events.MOUSE_EVENT, this.onMouseEvent_.bind(this));
$.subscribe(Events.TOOL_SELECTED, this.onToolEvent_.bind(this));
$.subscribe(Events.PRIMARY_COLOR_SELECTED, this.onColorEvent_.bind(this, true));
$.subscribe(Events.SECONDARY_COLOR_SELECTED, this.onColorEvent_.bind(this, false));
for (var key in this.piskelController) {
if (typeof this.piskelController[key] == 'function') {
var methodTriggersReset = this.piskelController[key].toString().indexOf('Events.PISKEL_RESET') != -1;
if (methodTriggersReset) {
this.piskelController[key] = this.instrumentMethod_(this.piskelController, key);
}
}
}
};
ns.DrawingTestRecorder.prototype.instrumentMethod_ = function (object, methodName) {
var method = object[methodName];
var testRecorder = this;
return function () {
testRecorder.onInstrumentedMethod_(object, methodName, arguments);
return method.apply(this, arguments);
};
};
ns.DrawingTestRecorder.prototype.reset = function () {
this.initialState = {};
this.events = [];
};
ns.DrawingTestRecorder.prototype.startRecord = function () {
this.isRecording = true;
this.initialState = {
size : {
width : this.piskelController.getWidth(),
height : this.piskelController.getHeight()
},
primaryColor : pskl.app.paletteController.getPrimaryColor(),
secondaryColor : pskl.app.paletteController.getSecondaryColor(),
selectedTool : pskl.app.toolController.currentSelectedTool.instance.toolId
};
};
ns.DrawingTestRecorder.prototype.stopRecord = function () {
this.isRecording = false;
var renderer = new pskl.rendering.PiskelRenderer(this.piskelController);
var png = renderer.renderAsCanvas().toDataURL();
var testRecord = JSON.stringify({
events : this.events,
initialState : this.initialState,
png : png
});
this.reset();
return testRecord;
};
ns.DrawingTestRecorder.prototype.onMouseEvent_ = function (evt, mouseEvent, originator) {
if (this.isRecording) {
this.recordMouseEvent_(mouseEvent);
}
};
ns.DrawingTestRecorder.prototype.onColorEvent_ = function (isPrimary, evt, color) {
if (this.isRecording) {
var recordEvent = {};
recordEvent.type = 'color-event';
recordEvent.color = color;
recordEvent.isPrimary = isPrimary;
this.events.push(recordEvent);
}
};
ns.DrawingTestRecorder.prototype.onToolEvent_ = function (evt, tool) {
if (this.isRecording) {
var recordEvent = {};
recordEvent.type = 'tool-event';
recordEvent.toolId = tool.toolId;
this.events.push(recordEvent);
}
};
ns.DrawingTestRecorder.prototype.onInstrumentedMethod_ = function (callee, methodName, args) {
if (this.isRecording) {
var recordEvent = {};
recordEvent.type = 'instrumented-event';
recordEvent.methodName = methodName;
recordEvent.args = Array.prototype.slice.call(args, 0);
this.events.push(recordEvent);
}
};
ns.DrawingTestRecorder.prototype.recordMouseEvent_ = function (mouseEvent) {
var coords = pskl.app.drawingController.getSpriteCoordinates(mouseEvent.clientX, mouseEvent.clientY);
var recordEvent = new ns.MouseEvent(mouseEvent, coords);
var lastEvent = this.events[this.events.length-1];
if (!recordEvent.equals(lastEvent)) {
this.events.push(recordEvent);
}
};
})();

View file

@ -0,0 +1,25 @@
(function () {
var ns = $.namespace('pskl.devtools');
ns.DrawingTestRunner = function (testName) {
this.testName = testName;
$.subscribe(Events.TEST_RECORD_END, this.onTestRecordEnd_.bind(this));
};
ns.DrawingTestRunner.prototype.start = function () {
pskl.utils.Xhr.get(this.testName, function (response) {
var res = response.responseText;
var recordPlayer = new ns.DrawingTestPlayer(JSON.parse(res));
recordPlayer.start();
}.bind(this));
};
ns.DrawingTestRunner.prototype.onTestRecordEnd_ = function (evt, success, png) {
var testResult = document.createElement('div');
testResult.id = 'drawing-test-result';
testResult.setAttribute('data-test-name', this.testName);
testResult.innerHTML = success ? 'OK' : ('KO:'+png);
document.body.appendChild(testResult);
};
})();

View file

@ -0,0 +1,77 @@
(function () {
var ns = $.namespace('pskl.devtools');
ns.DrawingTestSuiteController = function (suitePath) {
if (suitePath.indexOf('/') === -1) {
suitePath = [Constants.DRAWING_TEST_FOLDER, suitePath].join('/');
}
this.suitePath = suitePath;
this.testSuiteRunner = null;
};
ns.DrawingTestSuiteController.prototype.init = function () {
$.subscribe(Events.TEST_CASE_END, this.onTestCaseEnd_.bind(this));
$.subscribe(Events.TEST_SUITE_END, this.onTestSuiteEnd_.bind(this));
};
ns.DrawingTestSuiteController.prototype.start = function () {
this.reset();
this.startTime_ = Date.now();
pskl.utils.Xhr.get(this.suitePath, this.onTestSuiteLoaded_.bind(this));
var testSuiteStatus = document.createElement('li');
testSuiteStatus.innerHTML = pskl.utils.Template.replace(
'<b>Test Suite [{{path}}]</b>',
{path : this.shortenPath_(this.suitePath)}
);
this.testListElt.appendChild(testSuiteStatus);
};
ns.DrawingTestSuiteController.prototype.reset = function () {
this.domElt = document.createElement('div');
this.domElt.style.cssText = 'position:absolute;z-index:10000;margin:5px;padding:10px;background:lightgrey';
this.testListElt = document.createElement('ul');
this.domElt.appendChild(this.testListElt);
document.body.appendChild(this.domElt);
};
ns.DrawingTestSuiteController.prototype.onTestSuiteLoaded_ = function (response) {
var testPaths = JSON.parse(response.responseText).tests;
testPaths = testPaths.map(function (path) {
return [Constants.DRAWING_TEST_FOLDER, 'tests', path].join('/');
}.bind(this));
this.testSuiteRunner = new ns.DrawingTestSuiteRunner(testPaths);
this.testSuiteRunner.start();
};
ns.DrawingTestSuiteController.prototype.onTestCaseEnd_ = function (evt, testPath, status) {
var testCaseStatus = document.createElement('li');
testCaseStatus.innerHTML = pskl.utils.Template.replace(
'[{{path}}] finished : <b style="color:{{color}}">{{status}}</b>',
{path : this.shortenPath_(testPath), status : status ? 'OK' : 'KO', color : status ? 'green' : 'red'}
);
this.testListElt.appendChild(testCaseStatus);
};
ns.DrawingTestSuiteController.prototype.onTestSuiteEnd_ = function (evt, status) {
console.log('on test suite end');
var elapsed = Date.now() - this.startTime_;
elapsed = (elapsed/1000).toFixed(4);
var testSuiteStatus = document.createElement('li');
testSuiteStatus.innerHTML = pskl.utils.Template.replace(
'<b>Test finished : {{status}}</b> ({{elapsed}} seconds)',
{status : status, elapsed : elapsed}
);
this.testListElt.appendChild(testSuiteStatus);
};
ns.DrawingTestSuiteController.prototype.shortenPath_ = function (path) {
// keep only the part after the last '/'
return path.replace(/^.*\/([^\/]+.json$)/, '$1');
};
})();

View file

@ -0,0 +1,63 @@
(function () {
var ns = $.namespace('pskl.devtools');
ns.DrawingTestSuiteRunner = function (testPaths) {
if (Array.isArray(testPaths)) {
this.testStatus = {};
this.testPaths = testPaths;
this.status = ns.DrawingTestSuiteRunner.STATUS.NOT_STARTED;
this.currentIndex = -1;
} else {
throw new Error('testPaths should be an array of string (test paths)');
}
};
ns.DrawingTestSuiteRunner.STATUS = {
ERROR : 'ERROR',
FAILED : 'FAILED',
SUCCESS : 'SUCCESS',
ONGOING : 'ONGOING',
NOT_STARTED : 'NOT_STARTED'
};
ns.DrawingTestSuiteRunner.prototype.start = function () {
this.status = ns.DrawingTestSuiteRunner.STATUS.ONGOING;
this.runTest(0);
};
ns.DrawingTestSuiteRunner.prototype.runTest = function (testIndex) {
this.currentIndex = testIndex;
var path = this.testPaths[testIndex];
if (path) {
pskl.utils.Xhr.get(path, this.onTestLoaded_.bind(this));
} else {
this.onTestSuiteEnd_();
}
};
ns.DrawingTestSuiteRunner.prototype.onTestLoaded_ = function (response) {
var testRecord = JSON.parse(response.responseText);
var testPlayer = new ns.DrawingTestPlayer(testRecord, 50);
testPlayer.addEndTestCallback(this.onTestEnd_.bind(this));
testPlayer.start();
};
ns.DrawingTestSuiteRunner.prototype.onTestEnd_ = function (success, png, referencePng) {
var path = this.testPaths[this.currentIndex];
this.testStatus[path] = success;
$.publish(Events.TEST_CASE_END, [path, success]);
this.runTest(this.currentIndex + 1);
};
ns.DrawingTestSuiteRunner.prototype.onTestSuiteEnd_ = function () {
var success = this.testPaths.every(function (path) {
return this.testStatus[path];
}.bind(this));
this.status = success ? ns.DrawingTestSuiteRunner.STATUS.SUCCESS : ns.DrawingTestSuiteRunner.STATUS.ERROR;
$.publish(Events.TEST_SUITE_END, [this.status]);
};
})();

View file

@ -0,0 +1,26 @@
(function () {
var ns = $.namespace('pskl.devtools');
ns.MouseEvent = function (event, coords) {
this.event = {
type : event.type,
button : event.button,
shiftKey : event.shiftKey,
altKey : event.altKey,
ctrlKey : event.ctrlKey
};
this.coords = coords;
this.type = 'mouse-event';
};
ns.MouseEvent.prototype.equals = function (otherEvent) {
if (otherEvent && otherEvent instanceof ns.MouseEvent) {
var sameEvent = JSON.stringify(otherEvent.event) == JSON.stringify(this.event);
var sameCoords = JSON.stringify(otherEvent.coords) == JSON.stringify(this.coords);
return sameEvent && sameCoords;
} else {
return false;
}
};
})();

View file

@ -0,0 +1,76 @@
(function () {
var ns = $.namespace('pskl.devtools');
ns.TestRecordController = function (testRecorder) {
this.testRecorder = testRecorder;
$.subscribe(Events.TEST_RECORD_END, this.onTestRecordEnd_.bind(this));
};
ns.TestRecordController.prototype.init = function () {
var fileInput = document.createElement('input');
fileInput.setAttribute('type', 'file');
fileInput.addEventListener('change', this.onFileInputChange_.bind(this));
fileInput.style.display = 'none';
var container = document.createElement('div');
container.style.cssText = 'position:absolute;z-index:10000;margin:5px;padding:10px;background:lightgrey';
document.body.appendChild(container);
var loadInput = document.createElement('button');
loadInput.innerHTML = 'Load Test ...';
loadInput.addEventListener('click', this.onLoadInputClick_.bind(this));
var startInput = document.createElement('button');
startInput.innerHTML = 'Start record';
startInput.addEventListener('click', this.onStartInputClick_.bind(this));
var stopInput = document.createElement('button');
stopInput.innerHTML = 'Stop record';
stopInput.addEventListener('click', this.onStopInputClick_.bind(this));
stopInput.setAttribute('disabled','disabled');
this.container = container;
this.fileInput = this.container.appendChild(fileInput);
this.loadInput = this.container.appendChild(loadInput);
this.startInput = this.container.appendChild(startInput);
this.stopInput = this.container.appendChild(stopInput);
};
ns.TestRecordController.prototype.onLoadInputClick_ = function () {
this.fileInput.click();
};
ns.TestRecordController.prototype.onFileInputChange_ = function () {
var files = this.fileInput.files;
if (files.length == 1) {
var file =files[0];
pskl.utils.FileUtils.readFile(file, function (content) {
var testRecord = JSON.parse(window.atob(content.replace(/data\:.*?\;base64\,/,'')));
var testPlayer = new ns.DrawingTestPlayer(testRecord);
testPlayer.start();
}.bind(this));
}
};
ns.TestRecordController.prototype.onStartInputClick_ = function () {
this.testRecorder.startRecord();
this.startInput.setAttribute('disabled','disabled');
this.stopInput.removeAttribute('disabled');
};
ns.TestRecordController.prototype.onStopInputClick_ = function () {
var testRecord = this.testRecorder.stopRecord();
pskl.utils.BlobUtils.stringToBlob(testRecord, function(blob) {
pskl.utils.FileUtils.downloadAsFile(blob, 'record_piskel.json');
}.bind(this), "application/json");
this.startInput.removeAttribute('disabled');
this.stopInput.setAttribute('disabled','disabled');
};
ns.TestRecordController.prototype.onTestRecordEnd_ = function (evt, success) {
window.alert('Test finished : ', success);
};
})();

34
src/js/devtools/init.js Normal file
View file

@ -0,0 +1,34 @@
(function () {
var ns = $.namespace('pskl.devtools');
ns.init = function () {
var href = document.location.href.toLowerCase();
// test tools
var testModeOn = href.indexOf('test=true') !== -1;
if (testModeOn) {
this.testRecorder = new pskl.devtools.DrawingTestRecorder(pskl.app.piskelController);
this.testRecorder.init();
this.testRecordController = new pskl.devtools.TestRecordController(this.testRecorder);
this.testRecordController.init();
}
// test tools
var runTestModeOn = href.indexOf('test-run=') !== -1;
if (runTestModeOn) {
var testPath = href.split('test-run=')[1];
this.testRunner = new pskl.devtools.DrawingTestRunner(testPath);
this.testRunner.start();
}
// test tools
var runSuiteModeOn = href.indexOf('test-suite=') !== -1;
if (runSuiteModeOn) {
var suitePath = href.split('test-suite=')[1];
this.testSuiteController = new pskl.devtools.DrawingTestSuiteController(suitePath);
this.testSuiteController.init();
this.testSuiteController.start();
}
};
})();

View file

@ -196,6 +196,28 @@
}; };
}; };
ns.FrameRenderer.prototype.reverseCoordinates = function(x, y) {
var cellSize = this.zoom;
x = x * cellSize;
y = y * cellSize;
x = x - this.offset.x * cellSize;
y = y - this.offset.y * cellSize;
x = x + this.margin.x;
y = y + this.margin.y;
var containerOffset = this.container.offset();
x = x + containerOffset.left;
y = y + containerOffset.top;
return {
x : x + (cellSize/2),
y : y + (cellSize/2)
};
};
/** /**
* @private * @private
*/ */

View file

@ -8,42 +8,33 @@
ns.AppEngineStorageService.prototype.init = function () {}; ns.AppEngineStorageService.prototype.init = function () {};
ns.AppEngineStorageService.prototype.store = function (callbacks) { ns.AppEngineStorageService.prototype.store = function (callbacks) {
var formData = this.prepareFormData_();
var xhr = new XMLHttpRequest();
xhr.open('POST', Constants.APPENGINE.URL.SAVE, true);
xhr.onload = function(e) {
if (this.status == 200) {
callbacks.success();
callbacks.after();
} else {
this.onerror(e);
}
};
xhr.onerror = function(e) {
callbacks.error(this.status);
callbacks.after();
};
xhr.send(formData);
};
ns.AppEngineStorageService.prototype.prepareFormData_ = function () {
var piskel = this.piskelController.getPiskel(); var piskel = this.piskelController.getPiskel();
var descriptor = piskel.getDescriptor(); var descriptor = piskel.getDescriptor();
var formData = new FormData(); var data = {
formData.append('framesheet', this.piskelController.serialize()); framesheet : this.piskelController.serialize(),
formData.append('fps', this.piskelController.getFPS()); fps : this.piskelController.getFPS(),
formData.append('name', descriptor.name); name : descriptor.name,
formData.append('description', descriptor.description); description : descriptor.description,
if (descriptor.isPublic) { frames : this.piskelController.getFrameCount(),
formData.append('public', true); first_frame_as_png : pskl.app.getFirstFrameAsPng(),
} framesheet_as_png : pskl.app.getFramesheetAsPng()
formData.append('frames', this.piskelController.getFrameCount()); };
formData.append('first_frame_as_png', pskl.app.getFirstFrameAsPng());
formData.append('framesheet_as_png', pskl.app.getFramesheetAsPng());
return formData; if (descriptor.isPublic) {
data['public'] = true;
}
var success = function () {
callbacks.success();
callbacks.after();
};
var error = function (response) {
callbacks.error(response.status);
callbacks.after();
};
pskl.utils.Xhr.post(Constants.APPENGINE.URL.SAVE, data, success, error);
}; };
})(); })();

View file

@ -1,14 +1,13 @@
(function () { (function () {
var ns = $.namespace('pskl.service'); var ns = $.namespace('pskl.service');
var SNAPSHOT_PERIOD = 50; ns.HistoryService = function (piskelController, shortcutService, deserializer) {
var LOAD_STATE_INTERVAL = 50; this.piskelController = piskelController || pskl.app.piskelController;
this.shortcutService = shortcutService || pskl.app.shortcutService;
this.deserializer = deserializer || pskl.utils.serialization.Deserializer;
ns.HistoryService = function (piskelController) {
this.piskelController = piskelController;
this.stateQueue = []; this.stateQueue = [];
this.currentIndex = -1; this.currentIndex = -1;
this.saveState__b = this.onSaveStateEvent.bind(this);
this.lastLoadState = -1; this.lastLoadState = -1;
@ -17,6 +16,8 @@
ns.HistoryService.SNAPSHOT = 'SNAPSHOT'; ns.HistoryService.SNAPSHOT = 'SNAPSHOT';
ns.HistoryService.REPLAY = 'REPLAY'; ns.HistoryService.REPLAY = 'REPLAY';
ns.HistoryService.SNAPSHOT_PERIOD = 50;
ns.HistoryService.LOAD_STATE_INTERVAL = 50;
/** /**
* This event alters the state (frames, layers) of the piskel. The event is triggered before the execution of associated command. * This event alters the state (frames, layers) of the piskel. The event is triggered before the execution of associated command.
* Don't store snapshots for such events. * Don't store snapshots for such events.
@ -24,10 +25,10 @@
ns.HistoryService.REPLAY_NO_SNAPSHOT = 'REPLAY_NO_SNAPSHOT'; ns.HistoryService.REPLAY_NO_SNAPSHOT = 'REPLAY_NO_SNAPSHOT';
ns.HistoryService.prototype.init = function () { ns.HistoryService.prototype.init = function () {
$.subscribe(Events.PISKEL_SAVE_STATE, this.saveState__b); $.subscribe(Events.PISKEL_SAVE_STATE, this.onSaveStateEvent.bind(this));
pskl.app.shortcutService.addShortcut('ctrl+Z', this.undo.bind(this)); this.shortcutService.addShortcut('ctrl+Z', this.undo.bind(this));
pskl.app.shortcutService.addShortcut('ctrl+Y', this.redo.bind(this)); this.shortcutService.addShortcut('ctrl+Y', this.redo.bind(this));
this.saveState({ this.saveState({
type : ns.HistoryService.SNAPSHOT type : ns.HistoryService.SNAPSHOT
@ -50,7 +51,7 @@
var isSnapshot = stateInfo.type === ns.HistoryService.SNAPSHOT; var isSnapshot = stateInfo.type === ns.HistoryService.SNAPSHOT;
var isNoSnapshot = stateInfo.type === ns.HistoryService.REPLAY_NO_SNAPSHOT; var isNoSnapshot = stateInfo.type === ns.HistoryService.REPLAY_NO_SNAPSHOT;
var isAtAutoSnapshotInterval = this.currentIndex % SNAPSHOT_PERIOD === 0 || this.saveNextAsSnapshot; var isAtAutoSnapshotInterval = this.currentIndex % ns.HistoryService.SNAPSHOT_PERIOD === 0 || this.saveNextAsSnapshot;
if (isNoSnapshot && isAtAutoSnapshotInterval) { if (isNoSnapshot && isAtAutoSnapshotInterval) {
this.saveNextAsSnapshot = true; this.saveNextAsSnapshot = true;
} else if (isSnapshot || isAtAutoSnapshotInterval) { } else if (isSnapshot || isAtAutoSnapshotInterval) {
@ -58,10 +59,6 @@
this.saveNextAsSnapshot = false; this.saveNextAsSnapshot = false;
} }
if (isSnapshot) {
}
this.stateQueue.push(state); this.stateQueue.push(state);
}; };
@ -74,7 +71,7 @@
}; };
ns.HistoryService.prototype.isLoadStateAllowed_ = function (index) { ns.HistoryService.prototype.isLoadStateAllowed_ = function (index) {
var timeOk = (Date.now() - this.lastLoadState) > LOAD_STATE_INTERVAL; var timeOk = (Date.now() - this.lastLoadState) > ns.HistoryService.LOAD_STATE_INTERVAL;
var indexInRange = index >= 0 && index < this.stateQueue.length; var indexInRange = index >= 0 && index < this.stateQueue.length;
return timeOk && indexInRange; return timeOk && indexInRange;
}; };
@ -97,7 +94,7 @@
} }
var serializedPiskel = this.getSnapshotFromState_(snapshotIndex); var serializedPiskel = this.getSnapshotFromState_(snapshotIndex);
var onPiskelLoadedCb = this.onPiskelLoaded_.bind(this, index, snapshotIndex); var onPiskelLoadedCb = this.onPiskelLoaded_.bind(this, index, snapshotIndex);
pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, onPiskelLoadedCb); this.deserializer.deserialize(serializedPiskel, onPiskelLoadedCb);
} }
} catch (e) { } catch (e) {
window.console.error("[CRITICAL ERROR] : Unable to load a history state."); window.console.error("[CRITICAL ERROR] : Unable to load a history state.");
@ -138,6 +135,7 @@
this.replayState(state); this.replayState(state);
} }
// Should only do this when going backwards
var lastState = this.stateQueue[index+1]; var lastState = this.stateQueue[index+1];
if (lastState) { if (lastState) {
this.setupState(lastState); this.setupState(lastState);

View file

@ -6,23 +6,18 @@
/** /**
* Upload a base64 image data to distant service. If successful, will call provided callback with the image URL as first argument; * Upload a base64 image data to distant service. If successful, will call provided callback with the image URL as first argument;
* @param {String} imageData base64 image data (such as the return value of canvas.toDataUrl()) * @param {String} imageData base64 image data (such as the return value of canvas.toDataUrl())
* @param {Function} cbSuccess success callback. 1st argument will be the uploaded image URL * @param {Function} success success callback. 1st argument will be the uploaded image URL
* @param {Function} cbError error callback * @param {Function} error error callback
*/ */
ns.ImageUploadService.prototype.upload = function (imageData, cbSuccess, cbError) { ns.ImageUploadService.prototype.upload = function (imageData, success, error) {
var xhr = new XMLHttpRequest(); var data = {
var formData = new FormData(); data : imageData
formData.append('data', imageData);
xhr.open('POST', Constants.IMAGE_SERVICE_UPLOAD_URL, true);
xhr.onload = function (e) {
if (this.status == 200) {
var imageUrl = Constants.IMAGE_SERVICE_GET_URL + this.responseText;
cbSuccess(imageUrl);
} else {
cbError();
}
}; };
xhr.send(formData); var wrappedSuccess = function (response) {
success(Constants.IMAGE_SERVICE_GET_URL + response.responseText);
};
pskl.utils.Xhr.post(Constants.IMAGE_SERVICE_UPLOAD_URL, data, wrappedSuccess, error);
}; };
})(); })();

View file

@ -26,6 +26,13 @@
return canvas; return canvas;
}, },
createFromImage : function (image) {
var canvas = pskl.CanvasUtils.createCanvas(image.width, image.height);
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
return canvas;
},
/** /**
* By default, all scaling operations on a Canvas 2D Context are performed using antialiasing. * By default, all scaling operations on a Canvas 2D Context are performed using antialiasing.
* Resizing a 32x32 image to 320x320 will lead to a blurry output. * Resizing a 32x32 image to 320x320 will lead to a blurry output.

46
src/js/utils/Xhr.js Normal file
View file

@ -0,0 +1,46 @@
(function () {
var ns = $.namespace('pskl.utils');
ns.Xhr = {
get : function (url, success, error) {
var xhr = ns.Xhr.xhr_(url, 'GET', success, error);
xhr.send();
},
post : function (url, data, success, error) {
var xhr = ns.Xhr.xhr_(url, 'POST', success, error);
var formData = new FormData();
if (typeof data == 'object') {
for (var key in data) {
if (data.hasOwnProperty(key)) {
formData.append(key, data[key]);
}
}
}
xhr.send(formData);
},
xhr_ : function (url, method, success, error) {
success = success || function (){};
error = error || function (){};
var xhr = new XMLHttpRequest();
xhr.open(method, url, true);
xhr.onload = function(e) {
if (this.status == 200) {
success(this);
} else {
this.onerror(this, e);
}
};
xhr.onerror = function(e) {
error(e);
};
return xhr;
}
};
})();

View file

@ -14,13 +14,26 @@ jQuery.namespace = function() {
/** /**
* Need a polyfill for PhantomJS * Need a polyfill for PhantomJS
*/ */
if (typeof Function.prototype.bind !== "function") { if (!Function.prototype.bind) {
Function.prototype.bind = function(scope) { Function.prototype.bind = function (oThis) {
"use strict"; if (typeof this !== "function") {
var _function = this; // closest thing possible to the ECMAScript 5
return function() { // internal IsCallable function
return _function.apply(scope, arguments); throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}; }
var bindArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
var args = bindArgs.concat(Array.prototype.slice.call(arguments));
return fToBind.apply(this instanceof fNOP && oThis ? this : oThis, args);
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
}; };
} }

View file

@ -25,6 +25,7 @@
"js/utils/PiskelFileUtils.js", "js/utils/PiskelFileUtils.js",
"js/utils/Template.js", "js/utils/Template.js",
"js/utils/UserSettings.js", "js/utils/UserSettings.js",
"js/utils/Xhr.js",
"js/utils/serialization/Serializer.js", "js/utils/serialization/Serializer.js",
"js/utils/serialization/Deserializer.js", "js/utils/serialization/Deserializer.js",
"js/utils/serialization/backward/Deserializer_v0.js", "js/utils/serialization/backward/Deserializer_v0.js",
@ -137,6 +138,17 @@
"js/drawingtools/selectiontools/ShapeSelect.js", "js/drawingtools/selectiontools/ShapeSelect.js",
"js/drawingtools/ColorPicker.js", "js/drawingtools/ColorPicker.js",
"js/drawingtools/ColorSwap.js", "js/drawingtools/ColorSwap.js",
// Devtools
"js/devtools/DrawingTestPlayer.js",
"js/devtools/DrawingTestRecorder.js",
"js/devtools/DrawingTestRunner.js",
"js/devtools/DrawingTestSuiteController.js",
"js/devtools/DrawingTestSuiteRunner.js",
"js/devtools/MouseEvent.js",
"js/devtools/TestRecordController.js",
"js/devtools/init.js",
// Application controller and initialization // Application controller and initialization
"js/app.js", "js/app.js",
// Bonus features !! // Bonus features !!

View file

@ -7,11 +7,16 @@
<span class="settings-description">PNG with all frames side by side.</span> <span class="settings-description">PNG with all frames side by side.</span>
<button type="button" class="button button-primary png-download-button">Download PNG</button> <button type="button" class="button button-primary png-download-button">Download PNG</button>
</div> </div>
<div class="settings-title">
Export as ZIP
</div>
<div class="settings-item"> <div class="settings-item">
<span class="settings-description">ZIP with one PNG file per frame.</span> <span class="settings-description">ZIP with one PNG file per frame. Name will use the prefix above and append the frame index, ex: sprite_1.png</span>
<div> <div class="settings-item">
<button type="button" class="button button-primary zip-generate-button"/>Download ZIP</button> <label for="zip-file-name">File prefix:</label>
<input id="zip-file-name" type="text" class="textfield" placeholder="sprite_">
</div> </div>
<button type="button" class="button button-primary zip-generate-button"/>Download ZIP</button>
</div> </div>
<div class="settings-title"> <div class="settings-title">
Export to Animated GIF Export to Animated GIF
@ -37,4 +42,4 @@
<span class="gif-export-progress-status"></span> <span class="gif-export-progress-status"></span>
<div class="gif-export-progress-bar"></div> <div class="gif-export-progress-bar"></div>
</div> </div>
</div> </div>

View file

@ -0,0 +1,42 @@
(function () {
var tests = require('./test/drawing/DrawingTests.casper.js').tests;
var baseUrl = casper.cli.get('baseUrl')+"?debug";
var resultSelector = '#drawing-test-result';
casper.start();
var runTest = function (index) {
var test = 'drawing/tests/' + tests[index];
casper.open(baseUrl + "&test-run=" + test);
casper.then(function () {
this.echo('Running test : ' + test);
this.wait(casper.cli.get('delay'));
});
casper.then(function () {
this.echo('Waiting for test result : ' + resultSelector);
this.waitForSelector(resultSelector, function () {
// then
var result = this.getHTML(resultSelector);
this.echo('Test finished : ' + result);
this.test.assertEquals(result, 'OK');
}, function () {
// onTimeout
this.test.fail('Test timed out');
}, 60*1000);
})
.run(function () {
if (tests[index+1]) {
runTest(index+1);
} else {
this.test.done();
}
});
};
runTest(0);
})();

View file

@ -0,0 +1,4 @@
(typeof exports != "undefined" ? exports : pskl_exports).tests = [
'SmokeTest.js',
'DrawingTest.js'
];

View file

@ -7,7 +7,7 @@ casper
this.echo(casper.cli.get('baseUrl')+"?debug"); this.echo(casper.cli.get('baseUrl')+"?debug");
// If there was a JS error after the page load, casper won't perform asserts // If there was a JS error after the page load, casper won't perform asserts
this.test.assertExists('html', 'Casper JS cannot assert DOM elements. A JS error has probably occured.'); this.test.assertExists('html', 'Casper JS cannot assert DOM elements. A JS error has probably occured.');
this.test.assertExists('#drawing-canvas-container canvas', 'Check if drawing canvas element is created'); this.test.assertExists('#drawing-canvas-container canvas', 'Check if drawing canvas element is created');
}) })
.run(function () { .run(function () {

View file

@ -0,0 +1,4 @@
(typeof exports != "undefined" ? exports : pskl_exports).tests = [
// did not manage to successfully run drawing tests on travis yet ...
'SmokeTest.js'
];

View file

@ -0,0 +1,13 @@
{"tests" : [
"pen.drawing.json",
"bucket.drawing.json",
"color.picker.json",
"frames.fun.json",
"layers.fun.json",
"lighten.darken.json",
"move.json",
"pen.secondary.color.json",
"squares.circles.json",
"stroke.json",
"verticalpen.drawing.json"
]}

View file

@ -0,0 +1,11 @@
(typeof exports != "undefined" ? exports : pskl_exports).tests = [
"pen.drawing.json",
"color.picker.json",
"frames.fun.json",
"layers.fun.json",
"move.json",
"pen.secondary.color.json",
"squares.circles.json",
"stroke.json",
"verticalpen.drawing.json"
];

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,48 @@
{"events":[{"type":"tool-event","toolId":"tool-pen"},
{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":0},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":0},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":0},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":0},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":0},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":0},"type":"mouse-event"},
{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":0},"type":"mouse-event"},
{"type":"color-event","color":"rgb(11, 182, 0)","isPrimary":true},
{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":1},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":1},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":1},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":1},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":1},"type":"mouse-event"},
{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":1},"type":"mouse-event"},
{"type":"color-event","color":"rgb(49, 84, 47)","isPrimary":true},
{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":2},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":2},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":2},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":2},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":2},"type":"mouse-event"},
{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":2},"type":"mouse-event"},
{"type":"tool-event","toolId":"tool-colorpicker"},
{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":0},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":0},"type":"mouse-event"},
{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":0},"type":"mouse-event"},
{"type":"tool-event","toolId":"tool-pen"},
{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":3},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":3},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":3},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":3},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":3},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":3},"type":"mouse-event"},
{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":3},"type":"mouse-event"},
{"type":"tool-event","toolId":"tool-colorpicker"},
{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"},
{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"},
{"type":"tool-event","toolId":"tool-pen"},
{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":4},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":4},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":4},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":4},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":4},"type":"mouse-event"},
{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":4},"type":"mouse-event"},
{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":4},"type":"mouse-event"}],"initialState":{"size":{"width":5,"height":5},"primaryColor":"rgb(182, 177, 0)","secondaryColor":"#80ff00","selectedTool":"tool-move"},"png":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQIW2PctpHhPwMaYOTehkXQMEQfUyXR2gFosQoFS9oVSgAAAABJRU5ErkJggg=="}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
{"events":[{"type":"tool-event","toolId":"tool-pen"},{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":0},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":0},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":0},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":0},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":0},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":0},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":0},"type":"mouse-event"},{"type":"color-event","color":"#158d00","isPrimary":true},{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":3},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":4},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":4},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":4},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":4},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":4},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":3},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"},{"type":"color-event","color":"#6bb25e","isPrimary":true},{"type":"tool-event","toolId":"tool-paint-bucket"},{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"type":"instrumented-event","methodName":"addFrameAt","args":[1]},{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"type":"instrumented-event","methodName":"duplicateFrameAt","args":[0]},{"type":"instrumented-event","methodName":"moveFrame","args":[1,2]},{"type":"instrumented-event","methodName":"setCurrentFrameIndex","args":[2]}],"initialState":{"size":{"width":5,"height":5},"primaryColor":"#8d007c","secondaryColor":"rgba(0, 0, 0, 0)","selectedTool":"tool-move"},"png":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAFCAYAAACaTbYsAAAAPklEQVQYV2PsZaj5z4AG7m16hC7EoOQnhyHGKNrLgKE5TDUOQ+Gq24uwa0ZWDFKESzO6OrDNFGlGdw+xzgYAdtkjkmnNRVEAAAAASUVORK5CYII="}

View file

@ -0,0 +1 @@
{"events":[{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"type":"instrumented-event","methodName":"createLayer","args":[]},{"type":"color-event","color":"#0ea92e","isPrimary":true},{"type":"tool-event","toolId":"tool-rectangle"},{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":3},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":3},"type":"mouse-event"},{"type":"instrumented-event","methodName":"createLayer","args":[]},{"type":"color-event","color":"#170ea9","isPrimary":true},{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":3},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":3},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":3},"type":"mouse-event"},{"type":"instrumented-event","methodName":"moveLayerDown","args":[]},{"type":"tool-event","toolId":"tool-move"},{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":0},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":0},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"}],"initialState":{"size":{"width":5,"height":5},"primaryColor":"#a9220e","secondaryColor":"rgba(0, 0, 0, 0)","selectedTool":"tool-paint-bucket"},"png":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAM0lEQVQIW2NcqcT3nwENMIIEU9sV4MKzKx8wwAU5U6sZvs9uZQDRGCrhgiC9eW9mw40AAEumFR2KMzAWAAAAAElFTkSuQmCC"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
{"events":[{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":0},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":0},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":0},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":0},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":0},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":0},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":0},"type":"mouse-event"},{"type":"color-event","color":"#b00000","isPrimary":true},{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":1},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":1},"type":"mouse-event"},{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":2},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":2},"type":"mouse-event"},{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":3},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":3},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":3},"type":"mouse-event"},{"type":"color-event","color":"#03b000","isPrimary":true},{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":4},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":4},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":4},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":4},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":4},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":4},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":4},"type":"mouse-event"}],"initialState":{"size":{"width":5,"height":5},"primaryColor":"#000000","secondaryColor":"rgba(0, 0, 0, 0)","selectedTool":"tool-pen"},"png":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAALUlEQVQIW2NkYGD4D8QogBFdYANQEVwQxAEpCGBgYAQLggRAHJguRuYNmGYCAJ6NCGbAWR+yAAAAAElFTkSuQmCC"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,86 @@
var callFactory = function (method) {
return {
times : function (times) {
var results = [];
for (var i = 0 ; i < times ; i++) {
results.push(method());
}
return results;
},
once : function () {
return method();
}
};
};
describe("History Service suite", function() {
var SERIALIZED_PISKEL = 'serialized-piskel';
var historyService = null;
var getLastState = function () {
return historyService.stateQueue[historyService.currentIndex];
};
var createMockHistoryService = function () {
var mockPiskelController = {
serialize : function () {
return SERIALIZED_PISKEL;
}
};
var mockShortcutService = {
addShortcut : function () {}
};
return new pskl.service.HistoryService(mockPiskelController, mockShortcutService);
};
it("starts at -1", function() {
historyService = createMockHistoryService();
expect(historyService.currentIndex).toBe(-1);
});
it("is at 0 after init", function() {
historyService = createMockHistoryService();
historyService.init();
expect(historyService.currentIndex).toBe(0);
});
var sendSaveEvents = function (type) {
return callFactory (function () {
$.publish(Events.PISKEL_SAVE_STATE, {
type : type,
scope : {},
replay : {}
});
});
};
it("stores a piskel snapshot after 5 SAVE", function () {
// BEFORE
var SNAPSHOT_PERIOD_BACKUP = pskl.service.HistoryService.SNAPSHOT_PERIOD;
pskl.service.HistoryService.SNAPSHOT_PERIOD = 5;
historyService = createMockHistoryService();
historyService.init();
sendSaveEvents(pskl.service.HistoryService.REPLAY).times(5);
expect(historyService.currentIndex).toBe(5);
expect(getLastState().piskel).toBe(SERIALIZED_PISKEL);
sendSaveEvents(pskl.service.HistoryService.REPLAY).times(4);
sendSaveEvents(pskl.service.HistoryService.REPLAY_NO_SNAPSHOT).once();
expect(getLastState().piskel).toBeUndefined();
sendSaveEvents(pskl.service.HistoryService.REPLAY_NO_SNAPSHOT).once();
expect(getLastState().piskel).toBeUndefined();
sendSaveEvents(pskl.service.HistoryService.REPLAY).once();
expect(getLastState().piskel).toBe(SERIALIZED_PISKEL);
// AFTER
pskl.service.HistoryService.SNAPSHOT_PERIOD = SNAPSHOT_PERIOD_BACKUP;
})
});