whiteboard-app
Version:
Whiteboard - a slide-based activity presentation system
288 lines (258 loc) • 8.91 kB
JavaScript
const pathlib = require('path');
const fs = require('fs');
const schemaconf = require('schemaconf');
const { autogenerateDeckFromDir } = require('./fsimport.js');
const { getStore } = require('./prefs.js');
const packageJson = require('../../package.json');
const WB_FORMAT = '1';
const MAX_RECENT = 10;
function updateRecentList(filepath) {
const store = getStore();
let recent = store.get('recent');
const index = recent.indexOf(filepath);
if (index !== -1) {
recent.splice(index, 1);
}
recent.unshift({ path: filepath });
recent = recent.slice(0, MAX_RECENT);
store.set('recent', recent);
}
function saveToFile(filepath, data, callback) {
const string = schemaconf.format.stringify(data);
fs.writeFile(filepath, string, (err) => {
if (err) {
console.error('cannot write to path: ', filepath);
throw err;
}
updateRecentList(filepath);
callback();
});
}
module.exports = {
WB_FORMAT,
getRecentListData() {
// TODO: clean this up, move it to Start, make it fault tolerant, and
// async, and have it do it on ready
const store = getStore();
const list = store.get('recent');
return list.map(({ path }) => {
// otherwise read data from file
try {
const contents = fs.readFileSync(path, 'utf-8');
const data = schemaconf.format.parse(contents);
return { path, data };
} catch (e) {
return { path };
}
});
},
getRecentList() {
const store = getStore();
const list = store.get('recent');
// Process all entries removing the .whiteboard extension
return list.map(({ path }) => ({
path,
name: pathlib.basename(path).slice(0, -11),
}));
},
openHtml(manager, defaultPath, callback) {
const { dialog } = manager.electron;
dialog.showOpenDialog({
defaultPath,
properties: ['openFile'],
filters: [
{ name: 'HTML', extensions: ['html', 'htm'] },
{ name: 'All Files', extensions: ['*'] },
],
}, (paths) => {
if (!paths) {
return; // canceled
}
callback(paths[0]);
});
},
openImage(manager, callback) {
const { dialog } = manager.electron;
dialog.showOpenDialog({
// defaultPath,
properties: ['openFile'],
filters: [
{ name: 'Image', extensions: ['png', 'jpg', 'jpeg', 'gif', 'webp'] },
{ name: 'All Files', extensions: ['*'] },
],
}, (paths) => {
if (!paths) {
return; // canceled
}
callback(paths[0]);
});
},
openVideo(manager, callback) {
const { dialog } = manager.electron;
dialog.showOpenDialog({
// defaultPath,
properties: ['openFile'],
filters: [
{ name: 'Video', extensions: ['mp4', 'webm', 'ogg', 'avi', 'mkv', 'm4v'] },
{ name: 'All Files', extensions: ['*'] },
],
}, (paths) => {
if (!paths) {
return; // canceled
}
callback(paths[0]);
});
},
loadDeck(manager, defaultPath, callback) {
const { dialog } = manager.electron;
dialog.showOpenDialog({
defaultPath,
properties: ['openFile'],
filters: [
{ name: 'Whiteboard', extensions: ['whiteboard'] },
],
}, (paths) => {
if (!paths) {
return; // canceled
}
if (defaultPath === paths[0]) {
return; // don't do anything if we are re-opening same file
}
updateRecentList(paths[0]);
// Otherwise, create a new window opening this thing
manager.createWindow(paths[0], callback);
});
},
importDirectory(manager, defaultPath, callback) {
const { dialog } = manager.electron;
dialog.showOpenDialog({
defaultPath,
properties: ['openDirectory'],
}, (paths) => {
if (!paths) {
return; // canceled
}
// Otherwise, create a new window opening this thing
const slides = autogenerateDeckFromDir(paths[0]);
if (slides && slides.length > 0) {
const filepath = pathlib.resolve(paths[0], 'deck.whiteboard');
const data = { slide: slides };
saveToFile(filepath, data, () => {
// console.log('SAVED TO ', filepath);
manager.createWindow(filepath, callback);
updateRecentList(filepath);
});
}
});
},
newDeck(manager, defaultPath, callback) {
const { dialog } = manager.electron;
dialog.showSaveDialog({
defaultPath,
filters: [
{ name: 'Whiteboard', extensions: ['whiteboard'] },
],
}, (filepath) => {
if (!filepath) {
return; // canceled
}
// Otherwise, create a new window opening this thing
const data = {
format: [
{ version: WB_FORMAT },
],
slide: [
{ title: 'New Whiteboard Deck' },
],
};
saveToFile(filepath, data, () => {
// console.log('SAVED TO ', filepath);
manager.createWindow(filepath, callback);
updateRecentList(filepath);
});
});
},
setupShowConfirmQuit(deck) {
const { dialog } = deck.manager.electron;
const { browserWindow } = deck.windowInfo;
browserWindow.on('close', function onClose(ev) {
// Deck is readonly, don't prompt
if (deck.readonly) {
return;
}
// No unsaved changes, don't prompt
if (deck.isSavedToDisk()) {
return;
}
// TODO: Uncomment and test this refs #56
// if (deck.isAutasaveOn()) {
// deck.save();
// return;
// }
// Show prompt about unsaved changes
const choice = dialog.showMessageBox(this, {
type: 'question',
buttons: ['Quit', 'Save & Quit', 'Cancel'],
title: 'Unsaved Changes',
message: 'You have unsaved changes. ' +
'Are you sure you want to quit?',
});
if (choice === 0) {
// Quit was selected
return;
}
ev.preventDefault();
if (choice === 1) {
// Trigger save, followed by force window close (destroy)
deck.save(() => {
setTimeout(() => {
browserWindow.destroy();
}, 100);
});
}
});
},
showAboutWindow(manager, windowInfo) {
// TODO integrate full one into elmoed, this one is glitchy as hell
const { dialog } = manager.electron;
const title = 'About Whiteboard';
const message = `
Whiteboard v${packageJson.version}
`.replace(/\s+/g, ' ').trim();
const detail = `
Whiteboard is free software, licensed under
the ${packageJson.license} license.
Built with Electron v${packageJson.devDependencies.electron}.
`.replace(/\s+/g, ' ').trim();
const { browserWindow } = windowInfo;
setTimeout(() => {
dialog.showMessageBox(browserWindow, {
title,
detail,
message,
type: 'info',
buttons: ['Ok'],
});
}, 10);
},
showErrorMessage(editor, message) {
const { manager, windowInfo } = editor;
const { dialog } = manager.electron;
const title = 'Whiteboard Error';
const detail = `
If this problem persists, check for a newer version, or check
http://whiteboard.michaelb.org/ and report a bug if one has not
already been reported.
`.replace(/\s+/g, ' ').trim();
const { browserWindow } = windowInfo;
setTimeout(() => {
dialog.showMessageBox(browserWindow, {
title,
detail,
message,
type: 'info',
buttons: ['Ok'],
});
}, 10);
},
};