diff --git a/src/js/controller/FramesListController.js b/src/js/controller/FramesListController.js index 35799118..bbd808bf 100644 --- a/src/js/controller/FramesListController.js +++ b/src/js/controller/FramesListController.js @@ -1,8 +1,6 @@ (function () { var ns = $.namespace('pskl.controller'); - var RENDER_MINIMUM_DELAY = 500; - var ACTION = { SELECT : 'select', CLONE : 'clone', @@ -13,19 +11,21 @@ ns.FramesListController = function (piskelController, container) { this.piskelController = piskelController; this.container = container; + this.domInitialized = false; this.refreshZoom_(); - this.lastRenderTime = 0; this.redrawFlag = true; this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); this.cachedFrameProcessor.setFrameProcessor(this.frameToPreviewCanvas_.bind(this)); this.cachedFrameProcessor.setOutputCloner(this.clonePreviewCanvas_.bind(this)); + + this.initDragndropBehavior_(); }; ns.FramesListController.prototype.init = function() { $.subscribe(Events.TOOL_RELEASED, this.flagForRedraw_.bind(this)); - $.subscribe(Events.PISKEL_RESET, this.flagForRedraw_.bind(this)); + $.subscribe(Events.PISKEL_RESET, this.flagForRedraw_.bind(this, true)); $.subscribe(Events.USER_SETTINGS_CHANGED, this.flagForRedraw_.bind(this)); $.subscribe(Events.PISKEL_RESET, this.refreshZoom_.bind(this)); @@ -35,8 +35,12 @@ this.updateScrollerOverflows(); }; - ns.FramesListController.prototype.flagForRedraw_ = function () { + ns.FramesListController.prototype.flagForRedraw_ = function (reinitializeDom) { this.redrawFlag = true; + + if (reinitializeDom) { + this.domInitialized = false; + } }; ns.FramesListController.prototype.refreshZoom_ = function () { @@ -44,10 +48,15 @@ }; ns.FramesListController.prototype.render = function () { - if (this.redrawFlag && (Date.now() - this.lastRenderTime > RENDER_MINIMUM_DELAY)) { - this.createPreviews_(); + if (this.redrawFlag) { + if (!this.domInitialized) { + this.tiles = []; + this.addFrameTile = null; + this.createPreviews_(); + } + + this.updatePreviews_(); this.redrawFlag = false; - this.lastRenderTime = Date.now(); } }; @@ -84,16 +93,56 @@ if (action === ACTION.CLONE) { this.piskelController.duplicateFrameAt(index); + var clonedTile = this.createPreviewTile_(index + 1); + this.container.get(0).insertBefore(clonedTile, this.tiles[index].nextSibling); + this.tiles.splice(index, 0, clonedTile); this.updateScrollerOverflows(); } else if (action === ACTION.DELETE) { this.piskelController.removeFrameAt(index); + this.container.get(0).removeChild(this.tiles[index]); + this.tiles.splice(index, 1); this.updateScrollerOverflows(); } else if (action === ACTION.SELECT) { this.piskelController.setCurrentFrameIndex(index); } else if (action === ACTION.NEW_FRAME) { this.piskelController.addFrame(); + var newtile = this.createPreviewTile_(this.tiles.length); + this.tiles.push(newtile); + this.container.get(0).insertBefore(newtile, this.addFrameTile); this.updateScrollerOverflows(); } + + this.flagForRedraw_(); + }; + + ns.FramesListController.prototype.updatePreviews_ = function () { + for (var i = 0, length = this.tiles.length; i < length; i++) { + // Remove selected class + this.tiles[i].classList.remove('selected'); + + // Update tile numbers + this.tiles[i].setAttribute('data-tile-number', i); + this.tiles[i].querySelector('.tile-count').innerHTML = (i + 1); + + // Check if any tile is updated + if (this.tiles[i].getAttribute('data-tile-hash') !== this.piskelController.getCurrentLayer().getFrameAt(i).getHash()) { + if (this.tiles[i].querySelector('canvas')) { + this.tiles[i].querySelector('.canvas-container').replaceChild(this.getCanvasForFrame(this.piskelController.getCurrentLayer().getFrameAt(i)), this.tiles[i].querySelector('canvas')); + } else { + this.tiles[i].querySelector('.canvas-container').appendChild(this.getCanvasForFrame(this.piskelController.getCurrentLayer().getFrameAt(i))); + } + } + } + + // Hide/Show buttons if needed + var buttons = this.container.get(0).querySelectorAll('.delete-frame-action, .dnd-action'); + var display = (this.piskelController.getFrameCount() > 1) ? 'block' : 'none'; + for (var i = 0, length = buttons.length; i < length; i++) { + buttons[i].style.display = display; + } + + // Add selected class + this.tiles[this.piskelController.getCurrentFrameIndex()].classList.add('selected'); }; ns.FramesListController.prototype.createPreviews_ = function () { @@ -104,7 +153,9 @@ var frameCount = this.piskelController.getFrameCount(); for (var i = 0 ; i < frameCount ; i++) { - this.container.append(this.createPreviewTile_(i)); + var tile = this.createPreviewTile_(i); + this.container.append(tile); + this.tiles[i] = tile; } // Append 'new empty frame' button var newFrameButton = document.createElement('div'); @@ -114,12 +165,10 @@ newFrameButton.innerHTML = '
' + '
Add new frame
'; this.container.append(newFrameButton); - - var needDragndropBehavior = (frameCount > 1); - if (needDragndropBehavior) { - this.initDragndropBehavior_(); - } + this.addFrameTile = newFrameButton; + this.updateScrollerOverflows(); + this.domInitialized = true; }; /** @@ -146,6 +195,10 @@ this.piskelController.moveFrame(originFrameId, targetInsertionId); this.piskelController.setCurrentFrameIndex(targetInsertionId); + + var tile = this.tiles.splice(originFrameId, 1)[0]; + this.tiles.splice(targetInsertionId, 0, tile); + this.flagForRedraw_(); }; /** @@ -157,6 +210,7 @@ var previewTileRoot = document.createElement('li'); previewTileRoot.setAttribute('data-tile-number', tileNumber); + previewTileRoot.setAttribute('data-tile-hash', currentFrame.getHash()); previewTileRoot.setAttribute('data-tile-action', ACTION.SELECT); previewTileRoot.classList.add('preview-tile'); if (this.piskelController.getCurrentFrame() == currentFrame) { @@ -175,10 +229,14 @@ canvasContainer.style.marginLeft = verticalMargin + 'px'; canvasContainer.style.marginRight = verticalMargin + 'px'; + // Add canvas background and canvas var canvasBackground = document.createElement('div'); canvasBackground.className = 'canvas-background'; canvasContainer.appendChild(canvasBackground); + canvasContainer.appendChild(this.getCanvasForFrame(currentFrame)); + previewTileRoot.appendChild(canvasContainer); + // Add clone button var cloneFrameButton = document.createElement('button'); cloneFrameButton.setAttribute('rel', 'tooltip'); cloneFrameButton.setAttribute('data-placement', 'right'); @@ -188,25 +246,22 @@ cloneFrameButton.className = 'tile-overlay duplicate-frame-action icon-frame-duplicate-white'; previewTileRoot.appendChild(cloneFrameButton); - canvasContainer.appendChild(this.getCanvasForFrame(currentFrame)); - previewTileRoot.appendChild(canvasContainer); + // Add delete button + var deleteButton = document.createElement('button'); + deleteButton.setAttribute('rel', 'tooltip'); + deleteButton.setAttribute('data-placement', 'right'); + deleteButton.setAttribute('title', 'Delete this frame'); + deleteButton.setAttribute('data-tile-number', tileNumber); + deleteButton.setAttribute('data-tile-action', ACTION.DELETE); + deleteButton.className = 'tile-overlay delete-frame-action icon-frame-recyclebin-white'; + previewTileRoot.appendChild(deleteButton); - if (tileNumber > 0 || this.piskelController.getFrameCount() > 1) { - // Add 'remove frame' button. - var deleteButton = document.createElement('button'); - deleteButton.setAttribute('rel', 'tooltip'); - deleteButton.setAttribute('data-placement', 'right'); - deleteButton.setAttribute('title', 'Delete this frame'); - deleteButton.setAttribute('data-tile-number', tileNumber); - deleteButton.setAttribute('data-tile-action', ACTION.DELETE); - deleteButton.className = 'tile-overlay delete-frame-action icon-frame-recyclebin-white'; - previewTileRoot.appendChild(deleteButton); + // Add 'dragndrop handle'. + var dndHandle = document.createElement('div'); + dndHandle.className = 'tile-overlay dnd-action icon-frame-dragndrop-white' ; + previewTileRoot.appendChild(dndHandle); - // Add 'dragndrop handle'. - var dndHandle = document.createElement('div'); - dndHandle.className = 'tile-overlay dnd-action icon-frame-dragndrop-white' ; - previewTileRoot.appendChild(dndHandle); - } + // Add tile count var tileCount = document.createElement('div'); tileCount.className = 'tile-overlay tile-count'; tileCount.innerHTML = tileNumber + 1;