diff --git a/css/style.css b/css/style.css index cee6f6ab..4e4984b5 100644 --- a/css/style.css +++ b/css/style.css @@ -16,9 +16,9 @@ body { text-align: center; font-size: 0; position: absolute; - left: 104px; + left: 100px; /* Reserve room for tools on the left edge of the screen. */ top: 10px; - right: 0; + right: 50px; /* Reserve room for actions on the right edge of the screen. */ bottom: 10px; } @@ -51,15 +51,120 @@ body { position: fixed; top: 0; bottom: 0; - left: 0; - width: 140px; + z-index: 1000; } -.sticky-section .wrap { +.sticky-section .wrap, +.sticky-section .drawer { display: table-cell; vertical-align: middle; } +.left-sticky-section.sticky-section { + left: 0; + max-width: 100px; +} + +.left-sticky-section .tool-icon { + float: left; +} + +.right-sticky-section.sticky-section { + right: 0; + width: 50px; + + -webkit-transition: all 200ms ease-out; + -moz-transition: all 200ms ease-out; + -ms-transition: all 200ms ease-out; + transition: all 200ms ease-out; +} + +.right-sticky-section .tool-icon { + float: right; + margin-right: 0; +} + +.drawer { + +} + +.drawer-content { + overflow: hidden; + background-color: #444; + height: 550px; + max-height: 100%; + width: 280px; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} + +/** Righty sticky drawer expanded state. */ + +.right-sticky-section.expanded { + right: 280px; +} + +.right-sticky-section.expanded .tool-icon { + margin-right: 1px; +} + +.right-sticky-section .tool-icon.has-expanded-drawer { + position: relative; + background-color: #444; + margin-right: 0; + padding-right: 1px; +} + +.settings-section { + margin: 10px 20px; + font-size: 12px; + font-weight: bold; + color: #ccc; + text-shadow: 1px 1px #000; +} + +.settings-title { + margin-top: 20px; + margin-bottom: 10px; + text-transform: uppercase; + border-bottom: 1px #aaa solid; + padding-bottom: 5px; +} + +.settings-item {} + +.background-picker-wrapper { + overflow: hidden; + padding: 10px 5px 20px 5px; +} + +.background-picker { + cursor: pointer; + float: left; + height: 35px; + width: 35px; + background-color: transparent; + margin-right: 15px; + padding: 1px; + position: relative; +} + +.background-picker:after { + content: " "; + position: absolute; + top: -2px; + right: -2px; + bottom: -2px; + left: -2px; +} + +.background-picker:hover:after { + border: #eee 1px solid; +} + +.background-picker.selected:after { + border: gold 1px solid; +} /** * Canvases layout @@ -76,7 +181,6 @@ body { } .canvas-container .canvas-background { - background: url(../img/canvas_background/medium_canvas_background.png) repeat; position: absolute; top: 0; right: 0; @@ -84,18 +188,22 @@ body { left: 0; } +.light-picker-background, .light-canvas-background .canvas-background { background: url(../img/canvas_background/light_canvas_background.png) repeat; } +.medium-picker-background, .medium-canvas-background .canvas-background { background: url(../img/canvas_background/medium_canvas_background.png) repeat; } +.lowcont-medium-picker-background, .lowcont-medium-canvas-background .canvas-background { background: url(../img/canvas_background/lowcont_medium_canvas_background.png) repeat; } +.lowcont-dark-picker-background, .lowcont-dark-canvas-background .canvas-background { background: url(../img/canvas_background/lowcont_dark_canvas_background.png) repeat; } @@ -137,10 +245,6 @@ body { overflow: hidden; } -.application-actions { - margin-top: 35px; -} - /** * User messages */ diff --git a/css/tools.css b/css/tools.css index 69db6316..76165c7b 100644 --- a/css/tools.css +++ b/css/tools.css @@ -6,12 +6,11 @@ } .tool-icon { - float: left; cursor : pointer; width: 46px; height: 46px; margin: 1px; - background-color: rgba(200,200,200, .1); + background-color: #3a3a3a; background-repeat: no-repeat; background-position: 12px 12px; background-size: 24px 24px; @@ -198,6 +197,12 @@ background-size: 36px 36px; } +.tool-icon.gear-icon { + background-image: url(../img/gear.png); + background-position: 6px 7px; + background-size: 32px 32px; +} + .tool-icon.upload-cloud-icon { background-image: url(../img/cloud_export.png); background-position: 4px 0px; @@ -213,5 +218,6 @@ font-size: 11px; text-transform: uppercase; color: #fff; + text-align: center; } diff --git a/img/gear.png b/img/gear.png new file mode 100644 index 00000000..c09e06fa Binary files /dev/null and b/img/gear.png differ diff --git a/index.html b/index.html index 18aa0140..77de32b0 100644 --- a/index.html +++ b/index.html @@ -16,8 +16,7 @@ - - + +
+
+
+ +
+
+ GIF
-
- Canvas background: - +
+ PNG +
+
+
+
+
+
+ Canvas settings: +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+ +
+
@@ -81,16 +107,6 @@
-
- -
-
- GIF -
-
- PNG -
-
@@ -114,6 +130,7 @@ + @@ -136,6 +153,7 @@ + diff --git a/js/Constants.js b/js/Constants.js index 231dfb5b..c7abf94a 100644 --- a/js/Constants.js +++ b/js/Constants.js @@ -1,3 +1,4 @@ +// TODO(grosbouddha): put under pskl namespace. var Constants = { DEFAULT_SIZE : { height : 32, diff --git a/js/Events.js b/js/Events.js index ab065356..34283d0d 100644 --- a/js/Events.js +++ b/js/Events.js @@ -1,3 +1,4 @@ +// TODO(grosbouddha): put under pskl namespace. Events = { TOOL_SELECTED : "TOOL_SELECTED", @@ -30,7 +31,13 @@ Events = { */ REDRAW_PREVIEWFILM: "REDRAW_PREVIEWFILM", - GRID_DISPLAY_STATE_CHANGED: "GRID_DISPLAY_STATE_CHANGED", + /** + * Fired each time a user setting change. + * The payload will be: + * 1st argument: Name of the settings + * 2nd argument: New value + */ + USER_SETTINGS_CHANGED: "USER_SETTINGS_CHANGED", /** * The framesheet was reseted and is now probably drastically different. diff --git a/js/controller/DrawingController.js b/js/controller/DrawingController.js index c1284ff1..c6ee9844 100644 --- a/js/controller/DrawingController.js +++ b/js/controller/DrawingController.js @@ -19,7 +19,7 @@ // TODO(vincz): Store user prefs in a localstorage string ? var renderingOptions = { "dpi": this.calculateDPI_(), - "hasGrid" : true + "supportGridRendering" : true }; this.renderer = new pskl.rendering.FrameRenderer(this.container, renderingOptions, "drawing-canvas"); @@ -61,7 +61,7 @@ $(window).resize($.proxy(this.startDPIUpdateTimer_, this)); $.subscribe(Events.FRAME_SIZE_CHANGED, $.proxy(this.updateDPI_, this)); - $.subscribe(Events.GRID_DISPLAY_STATE_CHANGED, $.proxy(this.forceRendering_, this)); + $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); }; ns.DrawingController.prototype.initMouseBehavior = function() { @@ -83,6 +83,15 @@ this.dpiUpdateTimer = window.setTimeout($.proxy(this.updateDPI_, this), 200); }, + /** + * @private + */ + ns.DrawingController.prototype.onUserSettingsChange_ = function (evt, settingsName, settingsValue) { + if(settingsName == pskl.UserSettings.SHOW_GRID) { + this.forceRendering_(); + } + }, + /** * @private */ diff --git a/js/controller/PreviewFilmController.js b/js/controller/PreviewFilmController.js index 3f5a0ec3..a80f3db9 100644 --- a/js/controller/PreviewFilmController.js +++ b/js/controller/PreviewFilmController.js @@ -56,10 +56,10 @@ if (scrollBottom > treshold) { overflowBottom = true; } - var wrapper = $('#preview-list-wrapper'); - wrapper.toggleClass('top-overflow-visible', overflowTop); - wrapper.toggleClass('bottom-overflow-visible', overflowBottom); } + var wrapper = $('#preview-list-wrapper'); + wrapper.toggleClass('top-overflow-visible', overflowTop); + wrapper.toggleClass('bottom-overflow-visible', overflowBottom); }; ns.PreviewFilmController.prototype.createPreviews_ = function () { diff --git a/js/controller/SettingsController.js b/js/controller/SettingsController.js new file mode 100644 index 00000000..7c54903d --- /dev/null +++ b/js/controller/SettingsController.js @@ -0,0 +1,45 @@ +(function () { + var ns = $.namespace("pskl.controller"); + + ns.SettingsController = function () {}; + + /** + * @public + */ + ns.SettingsController.prototype.init = function() { + + // Highlight selected background picker: + var backgroundClass = pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND); + $('#background-picker-wrapper') + .find('.background-picker[data-background-class=' + backgroundClass + ']') + .addClass('selected'); + + // Initial state for grid display: + var show_grid = pskl.UserSettings.get(pskl.UserSettings.SHOW_GRID); + $('#show-grid').prop('checked', show_grid); + + // Expand drawer when clicking 'Settings' tab. + $('#settings').click(function(evt) { + $('.right-sticky-section').toggleClass('expanded'); + $('#settings').toggleClass('has-expanded-drawer'); + }); + + // Handle grid display changes: + $('#show-grid').change($.proxy(function(evt) { + var checked = $('#show-grid').prop('checked'); + pskl.UserSettings.set(pskl.UserSettings.SHOW_GRID, checked); + }, this)); + + // Handle canvas background changes: + $('#background-picker-wrapper').click(function(evt) { + var target = $(evt.target).closest('.background-picker'); + if (target.length) { + var backgroundClass = target.data('background-class'); + pskl.UserSettings.set(pskl.UserSettings.CANVAS_BACKGROUND, backgroundClass); + + $('.background-picker').removeClass('selected'); + target.addClass('selected'); + } + }); + }; +})(); \ No newline at end of file diff --git a/js/controller/ToolController.js b/js/controller/ToolController.js index 26b008c6..aa48685e 100644 --- a/js/controller/ToolController.js +++ b/js/controller/ToolController.js @@ -58,7 +58,7 @@ this.selectTool_(this.toolInstances[tool]); // Show tool as selected: - $('#menubar .tool-icon.selected').removeClass('selected'); + $('#tool-section .tool-icon.selected').removeClass('selected'); clickedTool.addClass('selected'); } } @@ -83,17 +83,6 @@ $('#tools-container').html(toolMarkup); }; - /** - * Get state for the checkbox that control the display of the grid - * on the drawing canvas. - * @private - */ - ns.ToolController.prototype.isShowGridChecked_ = function() { - var showGridCheckbox = $('#show-grid'); - var isChecked = showGridCheckbox.is(':checked'); - return isChecked; - }; - /** * @public */ @@ -105,13 +94,6 @@ // Set SimplePen as default selected tool: this.selectTool_(this.toolInstances.simplePen); // Activate listener on tool panel: - $("#menubar").click($.proxy(this.onToolIconClicked_, this)); - - // Show/hide the grid on drawing canvas: - $.publish(Events.GRID_DISPLAY_STATE_CHANGED, [this.isShowGridChecked_()]); - $('#show-grid').change($.proxy(function(evt) { - var checked = this.isShowGridChecked_(); - $.publish(Events.GRID_DISPLAY_STATE_CHANGED, [checked]); - }, this)); + $("#tool-section").click($.proxy(this.onToolIconClicked_, this)); }; })(); \ No newline at end of file diff --git a/js/piskel.js b/js/piskel.js index 04830f4f..725d15c9 100644 --- a/js/piskel.js +++ b/js/piskel.js @@ -24,6 +24,7 @@ $.namespace("pskl"); this.drawingController = new pskl.controller.DrawingController(frameSheet, $('#drawing-canvas-container')); this.animationController = new pskl.controller.AnimatedPreviewController(frameSheet, $('#preview-canvas-container')); this.previewsController = new pskl.controller.PreviewFilmController(frameSheet, $('#preview-list')); + this.settingsController = new pskl.controller.SettingsController(); // To catch the current active frame, the selection manager have to be initialized before // the 'frameSheet.setCurrentFrameIndex(0);' line below. @@ -39,6 +40,7 @@ $.namespace("pskl"); this.animationController.init(); this.previewsController.init(); + this.settingsController.init(); this.historyService = new pskl.service.HistoryService(frameSheet); this.historyService.init(); @@ -70,13 +72,6 @@ $.namespace("pskl"); $('body').tooltip({ selector: '[rel=tooltip]' }); - - $('#canvas-picker').change(function(evt) { - $('#canvas-picker option:selected').each(function() { - console.log($(this).val()); - $('html')[0].className = $(this).val(); - }); - }); }, render : function (delta) { @@ -130,7 +125,6 @@ $.namespace("pskl"); loadFramesheetFromService : function (frameId) { var xhr = new XMLHttpRequest(); - // TODO: Change frameId to framesheetId on the backend xhr.open('GET', Constants.PISKEL_SERVICE_URL + '/get?l=' + frameId, true); xhr.responseType = 'text'; @@ -152,7 +146,6 @@ $.namespace("pskl"); // TODO(julz): Create package ? storeSheet : function (event) { - // TODO Refactor using jquery ? var xhr = new XMLHttpRequest(); var formData = new FormData(); formData.append('framesheet_content', frameSheet.serialize()); @@ -213,6 +206,7 @@ $.namespace("pskl"); } }; + // TODO(grosbouddha): Remove this window.piskel global (eventually pskl.piskel or pskl.app instead) window.piskel = piskel; piskel.init(); diff --git a/js/rendering/FrameRenderer.js b/js/rendering/FrameRenderer.js index e4fec384..99d30131 100644 --- a/js/rendering/FrameRenderer.js +++ b/js/rendering/FrameRenderer.js @@ -1,143 +1,165 @@ (function () { - var ns = $.namespace("pskl.rendering"); + var ns = $.namespace("pskl.rendering"); - ns.FrameRenderer = function (container, renderingOptions, className) { - - this.defaultRenderingOptions = { - "hasGrid" : false - }; - renderingOptions = $.extend(true, {}, this.defaultRenderingOptions, renderingOptions); + ns.FrameRenderer = function (container, renderingOptions, className) { + this.defaultRenderingOptions = { + 'supportGridRendering' : false + }; + renderingOptions = $.extend(true, {}, this.defaultRenderingOptions, renderingOptions); - if(container === undefined) { - throw "Bad FrameRenderer initialization. undefined."; - } - - if(isNaN(renderingOptions.dpi)) { - throw "Bad FrameRenderer initialization. not well defined."; - } + if(container === undefined) { + throw 'Bad FrameRenderer initialization. undefined.'; + } + + if(isNaN(renderingOptions.dpi)) { + throw 'Bad FrameRenderer initialization. not well defined.'; + } - this.container = container; - this.dpi = renderingOptions.dpi; - this.className = className; - this.canvas = null; - this.hasGrid = renderingOptions.hasGrid; - this.gridStrokeWidth = 0; + this.container = container; + this.dpi = renderingOptions.dpi; + this.className = className; + this.canvas = null; + this.supportGridRendering = renderingOptions.supportGridRendering; - // Flag to know if the config was altered - this.canvasConfigDirty = true; + this.enableGrid(pskl.UserSettings.get(pskl.UserSettings.SHOW_GRID)); - if(this.hasGrid) { - $.subscribe(Events.GRID_DISPLAY_STATE_CHANGED, $.proxy(this.showGrid, this)); - } - }; + // Flag to know if the config was altered + this.canvasConfigDirty = true; + this.updateBackgroundClass_(pskl.UserSettings.get(pskl.UserSettings.CANVAS_BACKGROUND)); + $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); + }; - ns.FrameRenderer.prototype.init = function (frame) { - this.render(frame); - this.lastRenderedFrame = frame; - }; + ns.FrameRenderer.prototype.init = function (frame) { + this.render(frame); + this.lastRenderedFrame = frame; + }; - ns.FrameRenderer.prototype.updateDPI = function (newDPI) { - this.dpi = newDPI; - this.canvasConfigDirty = true; - }; + ns.FrameRenderer.prototype.updateDPI = function (newDPI) { + this.dpi = newDPI; + this.canvasConfigDirty = true; + }; - ns.FrameRenderer.prototype.showGrid = function (evt, show) { - - this.gridStrokeWidth = 0; - if(show) { - this.gridStrokeWidth = Constants.GRID_STROKE_WIDTH; - } - - this.canvasConfigDirty = true; - }; + /** + * @private + */ + ns.FrameRenderer.prototype.onUserSettingsChange_ = function (evt, settingName, settingValue) { + + if(settingName == pskl.UserSettings.SHOW_GRID) { + this.enableGrid(settingValue); + } + else if (settingName == pskl.UserSettings.CANVAS_BACKGROUND) { + this.updateBackgroundClass_(settingValue); + } + }; - ns.FrameRenderer.prototype.render = function (frame) { - this.clear(frame); - var context = this.getCanvas_(frame).getContext('2d'); - for(var col = 0, width = frame.getWidth(); col < width; col++) { - for(var row = 0, height = frame.getHeight(); row < height; row++) { - var color = frame.getPixel(col, row); - this.renderPixel_(color, col, row, context); - } - } - this.lastRenderedFrame = frame; - }; + /** + * @private + */ + ns.FrameRenderer.prototype.updateBackgroundClass_ = function (newClass) { + var currentClass = this.container.data('current-background-class'); + if (currentClass) { + this.container.removeClass(currentClass); + } + this.container.addClass(newClass); + this.container.data('current-background-class', newClass); + }; - ns.FrameRenderer.prototype.renderPixel_ = function (color, col, row, context) { - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(this.getFramePos_(col), this.getFramePos_(row), this.dpi, this.dpi); - } - }; + ns.FrameRenderer.prototype.enableGrid = function (flag) { + this.gridStrokeWidth = (flag && this.supportGridRendering) ? Constants.GRID_STROKE_WIDTH : 0; + this.canvasConfigDirty = true; + }; - ns.FrameRenderer.prototype.clear = function (frame) { - var canvas = this.getCanvas_(frame); - canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height); - }; + ns.FrameRenderer.prototype.render = function (frame) { + this.clear(frame); + var context = this.getCanvas_(frame).getContext('2d'); + for(var col = 0, width = frame.getWidth(); col < width; col++) { + for(var row = 0, height = frame.getHeight(); row < height; row++) { + var color = frame.getPixel(col, row); + this.renderPixel_(color, col, row, context); + } + } + this.lastRenderedFrame = frame; + }; - /** - * Transform a screen pixel-based coordinate (relative to the top-left corner of the rendered - * frame) into a sprite coordinate in column and row. - * @public - */ - ns.FrameRenderer.prototype.convertPixelCoordinatesIntoSpriteCoordinate = function(coords) { - var cellSize = this.dpi + this.gridStrokeWidth; - return { - "col" : (coords.x - coords.x % cellSize) / cellSize, - "row" : (coords.y - coords.y % cellSize) / cellSize - }; - }; + ns.FrameRenderer.prototype.renderPixel_ = function (color, col, row, context) { + if(color != Constants.TRANSPARENT_COLOR) { + context.fillStyle = color; + context.fillRect(this.getFramePos_(col), this.getFramePos_(row), this.dpi, this.dpi); + } + }; - /** - * @private - */ - ns.FrameRenderer.prototype.getFramePos_ = function(index) { - return index * this.dpi + ((index - 1) * this.gridStrokeWidth); - }; + ns.FrameRenderer.prototype.clear = function (frame) { + var canvas = this.getCanvas_(frame); + canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height); + }; - /** - * @private - */ - ns.FrameRenderer.prototype.drawGrid_ = function(canvas, width, height, col, row) { - var ctx = canvas.getContext("2d"); - ctx.lineWidth = Constants.GRID_STROKE_WIDTH; - ctx.strokeStyle = Constants.GRID_STROKE_COLOR; - for(var c=1; c < col; c++) { - ctx.moveTo(this.getFramePos_(c), 0); - ctx.lineTo(this.getFramePos_(c), height); - ctx.stroke(); - } - - for(var r=1; r < row; r++) { - ctx.moveTo(0, this.getFramePos_(r)); - ctx.lineTo(width, this.getFramePos_(r)); - ctx.stroke(); - } - }; + /** + * Transform a screen pixel-based coordinate (relative to the top-left corner of the rendered + * frame) into a sprite coordinate in column and row. + * @public + */ + ns.FrameRenderer.prototype.convertPixelCoordinatesIntoSpriteCoordinate = function(coords) { + var cellSize = this.dpi + this.gridStrokeWidth; + return { + "col" : (coords.x - coords.x % cellSize) / cellSize, + "row" : (coords.y - coords.y % cellSize) / cellSize + }; + }; - /** - * @private - */ - ns.FrameRenderer.prototype.getCanvas_ = function (frame) { - if(this.canvasConfigDirty) { - $(this.canvas).remove(); - - var col = frame.getWidth(), - row = frame.getHeight(); - - var pixelWidth = col * this.dpi + this.gridStrokeWidth * (col - 1); - var pixelHeight = row * this.dpi + this.gridStrokeWidth * (row - 1); - var canvas = pskl.CanvasUtils.createCanvas(pixelWidth, pixelHeight, ["canvas", this.className]); + /** + * @private + */ + ns.FrameRenderer.prototype.getFramePos_ = function(index) { + return index * this.dpi + ((index - 1) * this.gridStrokeWidth); + }; - this.container.append(canvas); + /** + * @private + */ + ns.FrameRenderer.prototype.drawGrid_ = function(canvas, width, height, col, row) { + var ctx = canvas.getContext("2d"); + ctx.lineWidth = Constants.GRID_STROKE_WIDTH; + ctx.strokeStyle = Constants.GRID_STROKE_COLOR; + for(var c=1; c < col; c++) { + ctx.moveTo(this.getFramePos_(c), 0); + ctx.lineTo(this.getFramePos_(c), height); + ctx.stroke(); + } + + for(var r=1; r < row; r++) { + ctx.moveTo(0, this.getFramePos_(r)); + ctx.lineTo(width, this.getFramePos_(r)); + ctx.stroke(); + } + }; - if(this.gridStrokeWidth > 0) { - this.drawGrid_(canvas, pixelWidth, pixelHeight, col, row); - } - - this.canvas = canvas; - this.canvasConfigDirty = false; - } - return this.canvas; - }; + /** + * @private + */ + ns.FrameRenderer.prototype.getCanvas_ = function (frame) { + if(this.canvasConfigDirty) { + $(this.canvas).remove(); + + var col = frame.getWidth(), + row = frame.getHeight(); + + var pixelWidth = col * this.dpi + this.gridStrokeWidth * (col - 1); + var pixelHeight = row * this.dpi + this.gridStrokeWidth * (row - 1); + var classes = ['canvas']; + if (this.className) { + classes.push(this.className); + } + var canvas = pskl.CanvasUtils.createCanvas(pixelWidth, pixelHeight, classes); + + this.container.append(canvas); + + if(this.gridStrokeWidth > 0) { + this.drawGrid_(canvas, pixelWidth, pixelHeight, col, row); + } + + this.canvas = canvas; + this.canvasConfigDirty = false; + } + return this.canvas; + }; })(); \ No newline at end of file diff --git a/js/utils/UserSettings.js b/js/utils/UserSettings.js new file mode 100644 index 00000000..89359bee --- /dev/null +++ b/js/utils/UserSettings.js @@ -0,0 +1,76 @@ +(function () { + var ns = $.namespace("pskl"); + + ns.UserSettings = { + + SHOW_GRID : 'SHOW_GRID', + CANVAS_BACKGROUND : 'CANVAS_BACKGROUND', + + KEY_TO_DEFAULT_VALUE_MAP_ : { + 'SHOW_GRID' : false, + 'CANVAS_BACKGROUND' : 'medium-canvas-background' + }, + + /** + * @private + */ + cache_ : {}, + + /** + * Static method to access a user defined settings value ot its default + * value if not defined yet. + */ + get : function (key) { + this.checkKeyValidity_(key); + if (!(key in this.cache_)) { + this.cache_[key] = + this.readFromLocalStorage_(key) || this.readFromDefaults_(key); + } + return this.cache_[key]; + }, + + set : function (key, value) { + this.checkKeyValidity_(key); + this.cache_[key] = value; + this.writeToLocalStorage_(key, value); + + $.publish(Events.USER_SETTINGS_CHANGED, [key, value]); + }, + + /** + * @private + */ + readFromLocalStorage_ : function(key) { + var value = window.localStorage[key]; + if (typeof value != "undefined") { + value = JSON.parse(value); + } + return value; + }, + + /** + * @private + */ + writeToLocalStorage_ : function(key, value) { + // TODO(grosbouddha): Catch storage exception here. + window.localStorage[key] = JSON.stringify(value); + }, + + /** + * @private + */ + readFromDefaults_ : function (key) { + return this.KEY_TO_DEFAULT_VALUE_MAP_[key]; + }, + + /** + * @private + */ + checkKeyValidity_ : function(key) { + if(!(key in this.KEY_TO_DEFAULT_VALUE_MAP_)) { + // TODO(grosbouddha): Define error catching strategy and throw exception from here. + console.log("UserSettings key <"+ key +"> not find in supported keys."); + } + } + }; +})(); \ No newline at end of file diff --git a/resources/icons.png b/resources/icons.png new file mode 100644 index 00000000..cbeb10d7 Binary files /dev/null and b/resources/icons.png differ