Add import/export functions
This commit is contained in:
parent
3f17a19c50
commit
335b3dbb3e
15
index.html
15
index.html
|
@ -289,21 +289,24 @@
|
||||||
<div class="split two">
|
<div class="split two">
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
<a class="button">Import JSON</a><br>
|
<label class="button">Import JSON <input type="file" id="importDictionaryFile" accept="application/json, .dict"><br>
|
||||||
<small>Import a previously-exported <code>JSON</code> file.</small>
|
<small>Import a previously-exported <code>JSON</code> file.</small>
|
||||||
|
</label>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a class="button">Import Words</a><br>
|
<label class="button">Import Words <input type="file" id="importWordsCSV" accept="text/csv, .csv"><br>
|
||||||
<small>Import a CSV file of words. (Download an <a>example file with the correct formatting</a>.)</small>
|
<small>Import a CSV file of words.</small>
|
||||||
|
</label>
|
||||||
|
<a class="small button" download="Lexiconga_import-template.csv" href="data:text/csv;charset=utf-8,%22word%22,%22pronunciation%22,%22part of speech%22,%22definition%22,%22explanation%22%0A">Download an example file with the correct formatting</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
<a class="button">Export JSON</a><br>
|
<a class="button" id="exportDictionaryButton">Export JSON</a><br>
|
||||||
<small>Export your work as a <code>JSON</code> file to re-import later.</small>
|
<small>Export your work as a <code>JSON</code> file to re-import later.</small>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a class="button">Export Words</a><br>
|
<a class="button" id="exportWordsButton">Export Words</a><br>
|
||||||
<small>Export a CSV file of your words.</small>
|
<small>Export a CSV file of your words.</small>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"marked": "^0.6.2",
|
"marked": "^0.6.2",
|
||||||
"normalize.css": "^8.0.1"
|
"normalize.css": "^8.0.1",
|
||||||
|
"papaparse": "^4.6.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,24 @@ export function cloneObject(object) {
|
||||||
return JSON.parse(JSON.stringify(object));
|
return JSON.parse(JSON.stringify(object));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function download(data, filename, type) {
|
||||||
|
var file = new Blob([data], { type });
|
||||||
|
if (window.navigator.msSaveOrOpenBlob) // IE10+
|
||||||
|
window.navigator.msSaveOrOpenBlob(file, filename);
|
||||||
|
else { // Others
|
||||||
|
var a = document.createElement("a"),
|
||||||
|
url = URL.createObjectURL(file);
|
||||||
|
a.href = url;
|
||||||
|
a.download = filename;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
setTimeout(function () {
|
||||||
|
document.body.removeChild(a);
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function getIndicesOf(searchStr, findIn, caseSensitive) {
|
export function getIndicesOf(searchStr, findIn, caseSensitive) {
|
||||||
// https://stackoverflow.com/a/3410557
|
// https://stackoverflow.com/a/3410557
|
||||||
const searchStrLen = searchStr.length;
|
const searchStrLen = searchStr.length;
|
||||||
|
@ -52,5 +70,5 @@ export function removeTags(html) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function slugify(string) {
|
export function slugify(string) {
|
||||||
return removeDiacritics(string).replace(/[!a-zA-Z0-9-_]/g, '-');
|
return removeDiacritics(string).replace(/[^a-zA-Z0-9-_]/g, '-');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { renderDictionaryDetails, renderPartsOfSpeech } from "./render";
|
import { renderDictionaryDetails, renderPartsOfSpeech, renderAll } from "./render";
|
||||||
import { removeTags, cloneObject, getTimestampInSeconds } from "../helpers";
|
import { removeTags, cloneObject, getTimestampInSeconds, download, slugify } from "../helpers";
|
||||||
import { LOCAL_STORAGE_KEY, DEFAULT_DICTIONARY, MIGRATE_VERSION } from "../constants";
|
import { LOCAL_STORAGE_KEY, DEFAULT_DICTIONARY, MIGRATE_VERSION } from "../constants";
|
||||||
import { addMessage } from "./utilities";
|
import { addMessage, getNextId } from "./utilities";
|
||||||
|
import { addWord } from "./wordManagement";
|
||||||
|
|
||||||
export function updateDictionary () {
|
export function updateDictionary () {
|
||||||
|
|
||||||
|
@ -93,6 +94,118 @@ export function clearDictionary() {
|
||||||
window.currentDictionary = cloneObject(DEFAULT_DICTIONARY);
|
window.currentDictionary = cloneObject(DEFAULT_DICTIONARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function importDictionary() {
|
||||||
|
const importDictionaryField = document.getElementById('importDictionaryFile');
|
||||||
|
|
||||||
|
if (importDictionaryField.files.length === 1) {
|
||||||
|
if (confirm('Importing a dicitonary file will overwrite and replace your current dictionary!\nDo you want to continue?')) {
|
||||||
|
addMessage('Importing Dictionary...');
|
||||||
|
const fileReader = new FileReader();
|
||||||
|
fileReader.onload = function (fileLoadedEvent) {
|
||||||
|
const textFromFileLoaded = fileLoadedEvent.target.result;
|
||||||
|
const importedDictionary = JSON.parse(textFromFileLoaded);
|
||||||
|
if (importedDictionary && importedDictionary.hasOwnProperty('words')) {
|
||||||
|
window.currentDictionary = importedDictionary;
|
||||||
|
saveDictionary();
|
||||||
|
renderAll();
|
||||||
|
importDictionaryField.value = '';
|
||||||
|
document.getElementById('editModal').style.display = 'none';
|
||||||
|
addMessage('Dictionary Imported Successfully');
|
||||||
|
} else {
|
||||||
|
addMessage('Dictionary could not be imported', 10000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fileReader.readAsText(importDictionaryField.files[0], "UTF-8");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function importWords() {
|
||||||
|
const importWordsField = document.getElementById('importWordsCSV');
|
||||||
|
|
||||||
|
if (importWordsField.files.length === 1) {
|
||||||
|
if (confirm('Importing a CSV file with words will add all of the words in the file to your dictionary regardless of duplication!\nDo you want to continue?')) {
|
||||||
|
addMessage('Importing words...');
|
||||||
|
import('papaparse').then(papa => {
|
||||||
|
let wordsImported = 0;
|
||||||
|
papa.parse(importWordsField.files[0], {
|
||||||
|
header: true,
|
||||||
|
encoding: "utf-8",
|
||||||
|
step: results => {
|
||||||
|
if (results.errors.length > 0) {
|
||||||
|
results.errors.forEach(err => {
|
||||||
|
addMessage('Error Importing Word: ' + err);
|
||||||
|
console.error('Error Importing Word: ', err)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const row = results.data[0];
|
||||||
|
addWord({
|
||||||
|
name: removeTags(row.word).trim(),
|
||||||
|
pronunciation: removeTags(row.pronunciation).trim(),
|
||||||
|
partOfSpeech: removeTags(row['part of speech']).trim(),
|
||||||
|
definition: removeTags(row.definition).trim(),
|
||||||
|
details: removeTags(row.explanation).trim(),
|
||||||
|
wordId: getNextId(),
|
||||||
|
}, false, false);
|
||||||
|
wordsImported++;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
complete: () => {
|
||||||
|
saveDictionary();
|
||||||
|
renderAll();
|
||||||
|
importWordsField.value = '';
|
||||||
|
document.getElementById('editModal').style.display = 'none';
|
||||||
|
addMessage(`Done Importing ${wordsImported} Words`);
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
addMessage('Error Importing Words: ' + err);
|
||||||
|
console.error('Error Importing Words: ', err);
|
||||||
|
},
|
||||||
|
skipEmptyLines: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function exportDictionary() {
|
||||||
|
addMessage('Exporting JSON...');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
const file = JSON.stringify(window.currentDictionary),
|
||||||
|
{ name, specification } = window.currentDictionary;
|
||||||
|
|
||||||
|
const fileName = slugify(name + '_' + specification) + '.json';
|
||||||
|
|
||||||
|
download(file, fileName, 'application/json;charset=utf-8');
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function exportWords() {
|
||||||
|
addMessage('Exporting Words...');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
import('papaparse').then(papa => {
|
||||||
|
const { name, specification } = window.currentDictionary;
|
||||||
|
|
||||||
|
const fileName = slugify(name + '_' + specification) + '_words.csv';
|
||||||
|
|
||||||
|
const words = window.currentDictionary.words.map(word => {
|
||||||
|
return {
|
||||||
|
word: word.name,
|
||||||
|
pronunciation: word.pronunciation,
|
||||||
|
'part of speech': word.partOfSpeech,
|
||||||
|
definition: word.definition,
|
||||||
|
explanation: word.details,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const csv = papa.unparse(words, { quotes: true });
|
||||||
|
download(csv, fileName, 'text/csv;charset=utf-8');
|
||||||
|
});
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
export function migrateDictionary() {
|
export function migrateDictionary() {
|
||||||
let migrated = false;
|
let migrated = false;
|
||||||
if (!window.currentDictionary.hasOwnProperty('version')) {
|
if (!window.currentDictionary.hasOwnProperty('version')) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {showSection, hideDetailsPanel} from './displayToggles';
|
import {showSection, hideDetailsPanel} from './displayToggles';
|
||||||
import { renderWords, renderEditForm, renderMaximizedTextbox, renderInfoModal, renderIPATable } from './render';
|
import { renderWords, renderEditForm, renderMaximizedTextbox, renderInfoModal, renderIPATable } from './render';
|
||||||
import { confirmEditWord, cancelEditWord, confirmDeleteWord, submitWordForm } from './wordManagement';
|
import { confirmEditWord, cancelEditWord, confirmDeleteWord, submitWordForm } from './wordManagement';
|
||||||
import { openEditModal, saveEditModal, saveAndCloseEditModal } from './dictionaryManagement';
|
import { openEditModal, saveEditModal, saveAndCloseEditModal, exportDictionary, exportWords, importDictionary, importWords } from './dictionaryManagement';
|
||||||
import { goToNextPage, goToPreviousPage, goToPage } from './pagination';
|
import { goToNextPage, goToPreviousPage, goToPage } from './pagination';
|
||||||
import { insertAtCursor, getInputSelection, setSelectionRange } from './StackOverflow/inputCursorManagement';
|
import { insertAtCursor, getInputSelection, setSelectionRange } from './StackOverflow/inputCursorManagement';
|
||||||
import { usePhondueDigraphs } from './KeyboardFire/phondue/ipaField';
|
import { usePhondueDigraphs } from './KeyboardFire/phondue/ipaField';
|
||||||
|
@ -82,6 +82,10 @@ function setupEditFormInteractions() {
|
||||||
function setupEditFormButtons() {
|
function setupEditFormButtons() {
|
||||||
document.getElementById('editSave').addEventListener('click', () => saveEditModal());
|
document.getElementById('editSave').addEventListener('click', () => saveEditModal());
|
||||||
document.getElementById('editSaveAndClose').addEventListener('click', () => saveAndCloseEditModal());
|
document.getElementById('editSaveAndClose').addEventListener('click', () => saveAndCloseEditModal());
|
||||||
|
document.getElementById('importDictionaryFile').addEventListener('change', importDictionary);
|
||||||
|
document.getElementById('importWordsCSV').addEventListener('change', importWords);
|
||||||
|
document.getElementById('exportDictionaryButton').addEventListener('click', exportDictionary);
|
||||||
|
document.getElementById('exportWordsButton').addEventListener('click', exportWords);
|
||||||
|
|
||||||
setupMaximizeButtons();
|
setupMaximizeButtons();
|
||||||
}
|
}
|
||||||
|
@ -196,8 +200,8 @@ export function setupSettingsModal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setupWordEditFormButtons() {
|
export function setupWordEditFormButtons() {
|
||||||
const saveChangesButtons = document.getElementsByClassName('edit-save-changes');
|
const saveChangesButtons = document.getElementsByClassName('edit-save-changes'),
|
||||||
const cancelChangesButtons = document.getElementsByClassName('edit-cancel');
|
cancelChangesButtons = document.getElementsByClassName('edit-cancel');
|
||||||
Array.from(saveChangesButtons).forEach(button => {
|
Array.from(saveChangesButtons).forEach(button => {
|
||||||
button.removeEventListener('click', confirmEditWord);
|
button.removeEventListener('click', confirmEditWord);
|
||||||
button.addEventListener('click', confirmEditWord);
|
button.addEventListener('click', confirmEditWord);
|
||||||
|
|
|
@ -3524,6 +3524,11 @@ pako@~1.0.5:
|
||||||
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732"
|
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732"
|
||||||
integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==
|
integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==
|
||||||
|
|
||||||
|
papaparse@^4.6.3:
|
||||||
|
version "4.6.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-4.6.3.tgz#742e5eaaa97fa6c7e1358d2934d8f18f44aee781"
|
||||||
|
integrity sha512-LRq7BrHC2kHPBYSD50aKuw/B/dGcg29omyJbKWY3KsYUZU69RKwaBHu13jGmCYBtOc4odsLCrFyk6imfyNubJQ==
|
||||||
|
|
||||||
parcel-bundler@^1.12.3:
|
parcel-bundler@^1.12.3:
|
||||||
version "1.12.3"
|
version "1.12.3"
|
||||||
resolved "https://registry.yarnpkg.com/parcel-bundler/-/parcel-bundler-1.12.3.tgz#2bbf70bfa2d06097f071653285040bd125684d09"
|
resolved "https://registry.yarnpkg.com/parcel-bundler/-/parcel-bundler-1.12.3.tgz#2bbf70bfa2d06097f071653285040bd125684d09"
|
||||||
|
|
Loading…
Reference in New Issue