From 6d9bcdb9b50f69787593caff3f27eb04e15fe8aa Mon Sep 17 00:00:00 2001 From: Florrie Date: Fri, 6 Jul 2018 11:48:44 -0300 Subject: Paste --- playlist-utils.js | 2 +- ui.js | 76 ++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 56 insertions(+), 22 deletions(-) diff --git a/playlist-utils.js b/playlist-utils.js index 654d6ad..92e62b1 100644 --- a/playlist-utils.js +++ b/playlist-utils.js @@ -467,7 +467,7 @@ function isTrack(obj) { module.exports = { parentSymbol, - updatePlaylistFormat, updateTrackFormat, + updatePlaylistFormat, updateGroupFormat, updateTrackFormat, filterTracks, flattenGrouplike, partiallyFlattenGrouplike, collapseGrouplike, diff --git a/ui.js b/ui.js index 7ce5fdd..a18cd4d 100644 --- a/ui.js +++ b/ui.js @@ -1,7 +1,7 @@ const { getAllCrawlersForArg } = require('./crawlers') const { getDownloaderFor } = require('./downloaders') const { getPlayer } = require('./players') -const { parentSymbol, isGroup, isTrack, getItemPath, getItemPathString, flattenGrouplike } = require('./playlist-utils') +const { parentSymbol, isGroup, isTrack, getItemPath, getItemPathString, flattenGrouplike, updateGroupFormat } = require('./playlist-utils') const { shuffleArray } = require('./general-util') const processSmartPlaylist = require('./smart-playlist') const UndoManager = require('./undo-manager') @@ -34,7 +34,7 @@ class AppElement extends FocusElement { this.undoManager = new UndoManager() this.queueGrouplike = {name: 'Queue', isTheQueue: true, items: []} this.markGrouplike = {name: 'Marked', items: []} - this.editMode = false + this.editMode = true // Crude hack... this.recordStore.app = this @@ -117,31 +117,31 @@ class AppElement extends FocusElement { grouplikeListing.on('queue (shuffled)', item => this.shuffleQueueGrouplikeItem(item)) grouplikeListing.on('queue (play next)', item => this.queueGrouplikeItem(item, true, this.playingTrack)) + const updateListingsFor = item => { + for (const grouplikeListing of this.tabber.tabberElements) { + if (grouplikeListing.grouplike === item) { + grouplikeListing.loadGrouplike(item, false) + } + } + } + grouplikeListing.on('remove (x)', item => { if (this.editMode) { const parent = item[parentSymbol] const index = parent.items.indexOf(item) - const updateDisplay = () => { - for (const grouplikeListing of this.tabber.tabberElements) { - if (grouplikeListing.grouplike === parent) { - grouplikeListing.loadGrouplike(parent) - } else if (grouplikeListing.grouplike === item) { - grouplikeListing.loadGrouplike(item) - } - } - } - this.undoManager.pushAction({ activate: () => { parent.items.splice(index, 1) delete item[parentSymbol] - updateDisplay() + updateListingsFor(item) + updateListingsFor(parent) }, undo: () => { parent.items.splice(index, 0, item) item[parentSymbol] = parent - updateDisplay() + updateListingsFor(item) + updateListingsFor(parent) } }) } @@ -172,6 +172,34 @@ class AppElement extends FocusElement { } }) + const handlePaste = offset => item => { + if (this.editMode) { + if (this.markGrouplike.items.length) { + const parent = item[parentSymbol] + const index = parent.items.indexOf(item) + offset + this.undoManager.pushAction({ + activate: () => { + // TODO: More "proper" way of cloning a grouplike. (The purpose of updateGroupFormat + // here is to make the parentSymbols be properly set, as well as to create a set of + // totally new objects, so none of the pasted groups already appear somewhere else; + // or rather, not as the same objects.) + parent.items.splice(index, 0, ...updateGroupFormat(this.markGrouplike).items.map( + item => Object.assign({}, item, {[parentSymbol]: parent}) + )) + updateListingsFor(parent) + }, + undo: () => { + parent.items.splice(index, this.markGrouplike.items.length) + updateListingsFor(parent) + } + }) + } + } + } + + grouplikeListing.on('paste (below)', handlePaste(+1)) + grouplikeListing.on('paste (above)', handlePaste(0)) + const handleSelectFromPathElement = item => { this.form.selectInput(grouplikeListing) if (isGroup(item)) { @@ -674,9 +702,9 @@ class GrouplikeListingElement extends FocusElement { } } - loadGrouplike(grouplike) { + loadGrouplike(grouplike, resetIndex = true) { this.grouplike = grouplike - this.buildItems(true) + this.buildItems(resetIndex) } buildItems(resetIndex = false) { @@ -703,7 +731,7 @@ class GrouplikeListingElement extends FocusElement { if (this.grouplike.items.length) { for (const item of this.grouplike.items) { const itemElement = new GrouplikeItemElement(item, this.recordStore) - for (const evtName of ['download', 'remove (backspace)', 'remove (x)', 'mark', 'select (space)', 'select (enter)', 'queue', 'queue (shuffled)', 'queue (play next)']) { + for (const evtName of ['download', 'remove (backspace)', 'remove (x)', 'mark', 'paste (above)', 'paste (below)', 'select (space)', 'select (enter)', 'queue', 'queue (shuffled)', 'queue (play next)']) { itemElement.on(evtName, () => this.emit(evtName, item)) } form.addInput(itemElement) @@ -870,16 +898,22 @@ class GrouplikeItemElement extends Button { this.emit('queue (play next)') } } + } else if (telc.isSpace(keyBuf)) { + this.emit('select (space)') + } else if (telc.isEnter(keyBuf)) { + this.emit('select (enter)') } else if (telc.isBackspace(keyBuf)) { this.emit('remove (backspace)') } else if (telc.isCaselessLetter(keyBuf, 'x')) { this.emit('remove (x)') + + // Edit-mode things } else if (telc.isCaselessLetter(keyBuf, 'm')) { this.emit('mark') - } else if (telc.isSpace(keyBuf)) { - this.emit('select (space)') - } else if (telc.isEnter(keyBuf)) { - this.emit('select (enter)') + } else if (telc.isCharacter(keyBuf, 'p')) { + this.emit('paste (below)') + } else if (telc.isCharacter(keyBuf, 'P')) { + this.emit('paste (above)') } } } -- cgit 1.3.0-6-gf8a5