Enhancement : Palette color creator

- Added import button on create palette dialog
- implemented import from images
- missing limitation on color count when importing !!
- should remove button when editing existing palette
This commit is contained in:
jdescottes 2014-09-07 14:31:28 +02:00
parent 8643f4402a
commit e457209c8f
12 changed files with 117 additions and 90 deletions

View File

@ -17,6 +17,10 @@
top: 50px; top: 50px;
} }
.create-palette-import-section {
display : inline-block;
}
.colors-container { .colors-container {
position: absolute; position: absolute;

View File

@ -38,8 +38,8 @@
this.piskelController = new pskl.controller.piskel.PublicPiskelController(this.corePiskelController); this.piskelController = new pskl.controller.piskel.PublicPiskelController(this.corePiskelController);
this.piskelController.init(); this.piskelController.init();
this.paletteImportService = new pskl.service.palette.PaletteImportService();
this.paletteService = new pskl.service.palette.PaletteService(); this.paletteService = new pskl.service.palette.PaletteService();
this.paletteService.init();
this.paletteController = new pskl.controller.PaletteController(); this.paletteController = new pskl.controller.PaletteController();
this.paletteController.init(); this.paletteController.init();

View File

@ -3,6 +3,7 @@
ns.CreatePaletteController = function (piskelController) { ns.CreatePaletteController = function (piskelController) {
this.paletteService = pskl.app.paletteService; this.paletteService = pskl.app.paletteService;
this.paletteImportService = pskl.app.paletteImportService;
this.selectedIndex = -1; this.selectedIndex = -1;
}; };
@ -11,32 +12,41 @@
ns.CreatePaletteController.prototype.init = function (paletteId) { ns.CreatePaletteController.prototype.init = function (paletteId) {
this.superclass.init.call(this); this.superclass.init.call(this);
if (paletteId) {
var palette = this.paletteService.getPaletteById(paletteId);
this.palette = pskl.model.Palette.fromObject(palette);
} else {
paletteId = pskl.utils.Uuid.generate();
this.palette = new pskl.model.Palette(paletteId, 'New palette', []);
}
this.colorsList = document.querySelector('.colors-list'); this.colorsList = document.querySelector('.colors-list');
this.colorPreviewEl = document.querySelector('.color-preview'); this.colorPreviewEl = document.querySelector('.color-preview');
this.hiddenFileInput = document.querySelector('.create-palette-import-input');
this.nameInput = document.querySelector('input[name="palette-name"]'); this.nameInput = document.querySelector('input[name="palette-name"]');
this.nameInput.value = pskl.utils.unescapeHtml(this.palette.name);
var submitButton = document.querySelector('.create-palette-submit'); var submitButton = document.querySelector('.create-palette-submit');
var cancelButton = document.querySelector('.create-palette-cancel'); var cancelButton = document.querySelector('.create-palette-cancel');
var importFileButton = document.querySelector('.create-palette-import-button');
this.colorsList.addEventListener('click', this.onColorContainerClick_.bind(this)); this.colorsList.addEventListener('click', this.onColorContainerClick_.bind(this));
this.nameInput.addEventListener('input', this.onNameInputChange_.bind(this)); this.nameInput.addEventListener('input', this.onNameInputChange_.bind(this));
this.hiddenFileInput.addEventListener('change', this.onFileInputChange_.bind(this));
submitButton.addEventListener('click', this.onSubmitButtonClick_.bind(this)); submitButton.addEventListener('click', this.onSubmitButtonClick_.bind(this));
cancelButton.addEventListener('click', this.closeDialog.bind(this)); cancelButton.addEventListener('click', this.closeDialog.bind(this));
importFileButton.addEventListener('click', this.onImportFileButtonClick_.bind(this));
var colorPickerContainer = document.querySelector('.color-picker-container'); var colorPickerContainer = document.querySelector('.color-picker-container');
this.hslRgbColorPicker = new pskl.controller.widgets.HslRgbColorPicker(colorPickerContainer, this.onColorUpdated_.bind(this)); this.hslRgbColorPicker = new pskl.controller.widgets.HslRgbColorPicker(colorPickerContainer, this.onColorUpdated_.bind(this));
this.hslRgbColorPicker.init(); this.hslRgbColorPicker.init();
var palette;
if (paletteId) {
var paletteObject = this.paletteService.getPaletteById(paletteId);
palette = pskl.model.Palette.fromObject(paletteObject);
} else {
palette = new pskl.model.Palette(pskl.utils.Uuid.generate(), 'New palette', []);
}
this.setPalette_(palette);
};
ns.CreatePaletteController.prototype.setPalette_ = function (palette) {
this.palette = palette;
this.nameInput.value = pskl.utils.unescapeHtml(this.palette.name);
this.refresh_(); this.refresh_();
}; };
@ -49,9 +59,10 @@
ns.CreatePaletteController.prototype.onColorUpdated_ = function (color) { ns.CreatePaletteController.prototype.onColorUpdated_ = function (color) {
var rgbColor = color.toRgbString(); var rgbColor = color.toRgbString();
this.colorPreviewEl.style.background = rgbColor; this.colorPreviewEl.style.background = rgbColor;
if (this.palette) {
this.palette.set(this.selectedIndex, rgbColor); this.palette.set(this.selectedIndex, rgbColor);
this.refreshColorElement_(this.selectedIndex); this.refreshColorElement_(this.selectedIndex);
}
}; };
/** /**
@ -100,6 +111,17 @@
this.closeDialog(); this.closeDialog();
}; };
ns.CreatePaletteController.prototype.onImportFileButtonClick_ = function () {
this.hiddenFileInput.click();
};
ns.CreatePaletteController.prototype.onFileInputChange_ = function (evt) {
var files = this.hiddenFileInput.files;
if (files.length == 1) {
this.paletteImportService.read(files[0], this.setPalette_.bind(this));
}
};
ns.CreatePaletteController.prototype.onNameInputChange_ = function (evt) { ns.CreatePaletteController.prototype.onNameInputChange_ = function (evt) {
this.palette.name = pskl.utils.escapeHtml(this.nameInput.value); this.palette.name = pskl.utils.escapeHtml(this.nameInput.value);
}; };

View File

@ -28,7 +28,7 @@
this.importImageForm = $('[name=import-image-form]'); this.importImageForm = $('[name=import-image-form]');
this.importImageForm.submit(this.onImportFormSubmit_.bind(this)); this.importImageForm.submit(this.onImportFormSubmit_.bind(this));
pskl.utils.FileUtils.readFile(this.file_, this.processImageSource_.bind(this)); pskl.utils.FileUtils.readImageFile(this.file_, this.onImageLoaded_.bind(this));
}; };
ns.ImportImageController.prototype.onImportFormSubmit_ = function (evt) { ns.ImportImageController.prototype.onImportFormSubmit_ = function (evt) {
@ -55,18 +55,9 @@
} }
}; };
/** ns.ImportImageController.prototype.onImageLoaded_ = function (image) {
* Create an image from the given source (url or data-url), and onload forward to onImageLoaded this.importedImage_ = image;
* TODO : should be a generic utility method, should take a callback
* @param {String} imageSource url or data-url, will be used as src for the image
*/
ns.ImportImageController.prototype.processImageSource_ = function (imageSource) {
this.importedImage_ = new Image();
this.importedImage_.onload = this.onImageLoaded_.bind(this);
this.importedImage_.src = imageSource;
};
ns.ImportImageController.prototype.onImageLoaded_ = function (evt) {
var w = this.importedImage_.width, var w = this.importedImage_.width,
h = this.importedImage_.height; h = this.importedImage_.height;

View File

@ -1,61 +0,0 @@
(function () {
var ns = $.namespace('pskl.service');
ns.PaletteService = function () {
this.palettes = [];
this.localStorageService = window.localStorage;
};
ns.PaletteService.prototype.init = function () {};
ns.PaletteService.prototype.getPalettes = function () {
var palettesString = this.localStorageService.getItem('piskel.palettes');
return JSON.parse(palettesString) || [];
};
ns.PaletteService.prototype.getPaletteById = function (paletteId) {
var palettes = this.getPalettes();
return this.findPaletteInArray_(paletteId, palettes);
};
ns.PaletteService.prototype.savePalette = function (palette) {
var palettes = this.getPalettes();
var existingPalette = this.findPaletteInArray_(palette.id, palettes);
if (existingPalette) {
var currentIndex = palettes.indexOf(existingPalette);
palettes.splice(currentIndex, 1, palette);
} else {
palettes.push(palette);
}
this.savePalettes_(palettes);
$.publish(Events.SHOW_NOTIFICATION, [{"content": "Palette " + palette.name + " successfully saved !"}]);
window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000);
};
ns.PaletteService.prototype.deletePaletteById = function (id) {
var palettes = this.getPalettes();
var filteredPalettes = palettes.filter(function (palette) {
return palette.id !== id;
});
this.savePalettes_(filteredPalettes);
};
ns.PaletteService.prototype.savePalettes_ = function (palettes) {
this.localStorageService.setItem('piskel.palettes', JSON.stringify(palettes));
$.publish(Events.PALETTE_LIST_UPDATED);
};
ns.PaletteService.prototype.findPaletteInArray_ = function (paletteId, palettes) {
var match = null;
palettes.forEach(function (palette) {
if (palette.id === paletteId) {
match = palette;
}
});
return match;
};
})();

View File

@ -0,0 +1,29 @@
(function () {
var ns = $.namespace('pskl.service.palette');
ns.PaletteImageReader = function (file, onSuccess, onError) {
this.file = file;
this.onSuccess = onSuccess;
this.onError = onError;
};
ns.PaletteImageReader.prototype.read = function () {
pskl.utils.FileUtils.readImageFile(this.file, this.onImageLoaded_.bind(this));
};
ns.PaletteImageReader.prototype.onImageLoaded_ = function (image) {
var frame = pskl.utils.FrameUtils.createFromImage(image);
var colorsMap = {};
frame.forEachPixel(function (color, x, y) {
colorsMap[color] = true;
});
delete colorsMap[Constants.TRANSPARENT_COLOR];
var colors = Object.keys(colorsMap);
var uuid = pskl.utils.Uuid.generate();
var palette = new pskl.model.Palette(uuid, this.file.name + ' palette', colors);
this.onSuccess(palette);
};
})();

View File

@ -0,0 +1,26 @@
(function () {
var ns = $.namespace('pskl.service.palette');
ns.PaletteImportService = function () {};
ns.PaletteImportService.prototype.read = function (file, onSuccess, onError) {
if (this.isImage_(file)){
var reader = new ns.PaletteImageReader(file, onSuccess, onError);
reader.read();
} else if (this.isSupportedFormat_(file)) {
this.importFile(file);
}
};
ns.PaletteImportService.prototype.importFile = function (file) {
};
ns.PaletteImportService.prototype.isImage_ = function (file) {
return file.type.indexOf('image') === 0;
};
ns.PaletteImportService.prototype.isSupportedFormat_ = function (file) {
return (/\.piskel$/).test(file.name);
};
})();

View File

@ -1,12 +1,11 @@
(function () { (function () {
var ns = $.namespace('pskl.service.palette'); var ns = $.namespace('pskl.service.palette');
ns.PaletteService = function () { ns.PaletteService = function () {
this.palettes = []; this.palettes = [];
this.localStorageService = window.localStorage; this.localStorageService = window.localStorage;
}; };
ns.PaletteService.prototype.init = function () {};
ns.PaletteService.prototype.getPalettes = function () { ns.PaletteService.prototype.getPalettes = function () {
var palettesString = this.localStorageService.getItem('piskel.palettes'); var palettesString = this.localStorageService.getItem('piskel.palettes');
return JSON.parse(palettesString) || []; return JSON.parse(palettesString) || [];

View File

@ -14,6 +14,14 @@
reader.readAsDataURL(file); reader.readAsDataURL(file);
}, },
readImageFile : function (file, callback) {
ns.FileUtils.readFile(file, function (content) {
var image = new Image();
image.onload = callback.bind(null, image);
image.src = content;
});
},
downloadAsFile : function (content, filename) { downloadAsFile : function (content, filename) {
var saveAs = window.saveAs || (navigator.msSaveBlob && navigator.msSaveBlob.bind(navigator)); var saveAs = window.saveAs || (navigator.msSaveBlob && navigator.msSaveBlob.bind(navigator));
if (saveAs) { if (saveAs) {

View File

@ -120,6 +120,8 @@
"js/service/BeforeUnloadService.js", "js/service/BeforeUnloadService.js",
"js/service/HistoryService.js", "js/service/HistoryService.js",
"js/service/palette/PaletteService.js", "js/service/palette/PaletteService.js",
"js/service/palette/PaletteImportService.js",
"js/service/palette/PaletteImageReader.js",
"js/service/SavedStatusService.js", "js/service/SavedStatusService.js",
"js/service/keyboard/ShortcutService.js", "js/service/keyboard/ShortcutService.js",
"js/service/keyboard/KeycodeTranslator.js", "js/service/keyboard/KeycodeTranslator.js",

View File

@ -5,7 +5,14 @@
</h3> </h3>
<div class="dialog-create-palette" style="font-size:1.3em"> <div class="dialog-create-palette" style="font-size:1.3em">
<div class="create-palette-section form-section"> <div class="create-palette-section form-section">
<span class="dialog-create-palette-name">Name :</span><input type="text" class="textfield" name="palette-name" placeholder="palette name ..."/> <span class="create-palette-name-label">Name</span>
<input type="text" class="textfield create-palette-name-input" name="palette-name" placeholder="palette name ..."/>
<div class="create-palette-import-section">
<button type="button" class="button button-primary create-palette-import-button">Import from file</button>
<input style="display:none"
class="create-palette-import-input"
type="file" value="file" accept="*"/>
</div>
</div> </div>
<div class="colors-container"> <div class="colors-container">
<ul class="colors-list"></ul> <ul class="colors-list"></ul>

View File

@ -37,7 +37,7 @@ describe("Palette Service", function() {
} }
}; };
paletteService = new pskl.service.PaletteService(); paletteService = new pskl.service.palette.PaletteService();
paletteService.localStorageService = localStorageService; paletteService.localStorageService = localStorageService;
}); });