Compare commits

...

3 Commits

Author SHA1 Message Date
Robbie Antenesse be61709d5d Only save dictionary and settings when changed 2019-07-09 17:17:33 -06:00
Robbie Antenesse 572b49a660 Make alphabetical order editable 2019-07-09 13:06:03 -06:00
Robbie Antenesse a6c290e31b Fix how custom sorting works!
Sort alphabetically first, then by custom if specified
2019-07-09 12:24:40 -06:00
5 changed files with 146 additions and 95 deletions

View File

@ -3,7 +3,7 @@ import { renderDictionaryDetails, renderPartsOfSpeech } from "./render/details";
import { renderAll, renderTheme } from "./render";
import { removeTags, cloneObject, getTimestampInSeconds, download, slugify } from "../helpers";
import { LOCAL_STORAGE_KEY, DEFAULT_DICTIONARY } from "../constants";
import { addMessage, getNextId, hasToken } from "./utilities";
import { addMessage, getNextId, hasToken, objectValuesAreDifferent } from "./utilities";
import { addWord, sortWords } from "./wordManagement";
import { migrateDictionary } from './migration';
@ -13,7 +13,7 @@ export function updateDictionary () {
}
export function openEditModal() {
const { name, specification, description, partsOfSpeech } = window.currentDictionary;
const { name, specification, description, partsOfSpeech, alphabeticalOrder } = window.currentDictionary;
const { consonants, vowels, blends } = window.currentDictionary.details.phonology;
const { phonotactics, orthography, grammar } = window.currentDictionary.details;
const { allowDuplicates, caseSensitive, sortByDefinition, theme, isPublic } = window.currentDictionary.settings;
@ -22,6 +22,7 @@ export function openEditModal() {
document.getElementById('editSpecification').value = specification;
document.getElementById('editDescription').value = description;
document.getElementById('editPartsOfSpeech').value = partsOfSpeech.join(',');
document.getElementById('editAlphabeticalOrder').value = alphabeticalOrder.join(' ');
document.getElementById('editConsonants').value = consonants.join(' ');
document.getElementById('editVowels').value = vowels.join(' ');
@ -48,46 +49,56 @@ export function openEditModal() {
}
export function saveEditModal() {
window.currentDictionary.name = removeTags(document.getElementById('editName').value.trim());
window.currentDictionary.specification = removeTags(document.getElementById('editSpecification').value.trim());
window.currentDictionary.description = removeTags(document.getElementById('editDescription').value.trim());
window.currentDictionary.partsOfSpeech = document.getElementById('editPartsOfSpeech').value.split(',').map(val => val.trim()).filter(val => val !== '');
const updatedDictionary = cloneObject(window.currentDictionary);
delete updatedDictionary.words;
updatedDictionary.name = removeTags(document.getElementById('editName').value.trim());
updatedDictionary.specification = removeTags(document.getElementById('editSpecification').value.trim());
updatedDictionary.description = removeTags(document.getElementById('editDescription').value.trim());
updatedDictionary.partsOfSpeech = document.getElementById('editPartsOfSpeech').value.split(',').map(val => val.trim()).filter(val => val !== '');
updatedDictionary.alphabeticalOrder = document.getElementById('editAlphabeticalOrder').value.split(' ').map(val => val.trim()).filter(val => val !== '');
window.currentDictionary.details.phonology.consonants = document.getElementById('editConsonants').value.split(' ').map(val => val.trim()).filter(val => val !== '');
window.currentDictionary.details.phonology.vowels = document.getElementById('editVowels').value.split(' ').map(val => val.trim()).filter(val => val !== '');
window.currentDictionary.details.phonology.blends = document.getElementById('editBlends').value.split(' ').map(val => val.trim()).filter(val => val !== '');
window.currentDictionary.details.phonotactics.onset = document.getElementById('editOnset').value.split(',').map(val => val.trim()).filter(val => val !== '');
window.currentDictionary.details.phonotactics.nucleus = document.getElementById('editNucleus').value.split(',').map(val => val.trim()).filter(val => val !== '');
window.currentDictionary.details.phonotactics.coda = document.getElementById('editCoda').value.split(',').map(val => val.trim()).filter(val => val !== '');
window.currentDictionary.details.phonotactics.notes = removeTags(document.getElementById('editPhonotacticsNotes').value.trim());
updatedDictionary.details.phonology.consonants = document.getElementById('editConsonants').value.split(' ').map(val => val.trim()).filter(val => val !== '');
updatedDictionary.details.phonology.vowels = document.getElementById('editVowels').value.split(' ').map(val => val.trim()).filter(val => val !== '');
updatedDictionary.details.phonology.blends = document.getElementById('editBlends').value.split(' ').map(val => val.trim()).filter(val => val !== '');
updatedDictionary.details.phonotactics.onset = document.getElementById('editOnset').value.split(',').map(val => val.trim()).filter(val => val !== '');
updatedDictionary.details.phonotactics.nucleus = document.getElementById('editNucleus').value.split(',').map(val => val.trim()).filter(val => val !== '');
updatedDictionary.details.phonotactics.coda = document.getElementById('editCoda').value.split(',').map(val => val.trim()).filter(val => val !== '');
updatedDictionary.details.phonotactics.notes = removeTags(document.getElementById('editPhonotacticsNotes').value.trim());
window.currentDictionary.details.orthography.translations = document.getElementById('editTranslations').value.split('\n').map(val => val.trim()).filter(val => val !== '');
window.currentDictionary.details.orthography.notes = removeTags(document.getElementById('editOrthography').value.trim());
window.currentDictionary.details.grammar.notes = removeTags(document.getElementById('editGrammar').value.trim());
updatedDictionary.details.orthography.translations = document.getElementById('editTranslations').value.split('\n').map(val => val.trim()).filter(val => val !== '');
updatedDictionary.details.orthography.notes = removeTags(document.getElementById('editOrthography').value.trim());
updatedDictionary.details.grammar.notes = removeTags(document.getElementById('editGrammar').value.trim());
window.currentDictionary.settings.allowDuplicates = !document.getElementById('editPreventDuplicates').checked;
window.currentDictionary.settings.caseSensitive = document.getElementById('editCaseSensitive').checked;
window.currentDictionary.settings.sortByDefinition = document.getElementById('editSortByDefinition').checked;
window.currentDictionary.settings.theme = document.getElementById('editTheme').value;
updatedDictionary.settings.allowDuplicates = !document.getElementById('editPreventDuplicates').checked;
updatedDictionary.settings.caseSensitive = document.getElementById('editCaseSensitive').checked;
updatedDictionary.settings.sortByDefinition = document.getElementById('editSortByDefinition').checked;
updatedDictionary.settings.theme = document.getElementById('editTheme').value;
if (hasToken()) {
window.currentDictionary.settings.isPublic = document.getElementById('editIsPublic').checked;
updatedDictionary.settings.isPublic = document.getElementById('editIsPublic').checked;
} else {
window.currentDictionary.settings.isPublic = false;
updatedDictionary.settings.isPublic = false;
}
addMessage('Saved ' + window.currentDictionary.specification + ' Successfully');
saveDictionary();
renderTheme();
renderDictionaryDetails();
renderPartsOfSpeech();
sortWords(true);
if (objectValuesAreDifferent(updatedDictionary, window.currentDictionary)) {
window.currentDictionary = Object.assign(window.currentDictionary, updatedDictionary);
if (hasToken()) {
import('./account/index.js').then(account => {
account.uploadDetailsDirect();
account.updateChangeDictionaryOption();
})
renderTheme();
renderDictionaryDetails();
renderPartsOfSpeech();
sortWords(true);
addMessage('Saved ' + window.currentDictionary.specification + ' Successfully');
saveDictionary();
if (hasToken()) {
import('./account/index.js').then(account => {
account.uploadDetailsDirect();
account.updateChangeDictionaryOption();
})
}
} else {
addMessage('No changes made to Dictionary Settings.');
}
}

View File

@ -2,7 +2,7 @@ import { SETTINGS_KEY, DEFAULT_SETTINGS } from "../constants";
import { cloneObject, removeTags } from "../helpers";
import { usePhondueDigraphs } from "./KeyboardFire/phondue/ipaField";
import { renderWords } from "./render/words";
import { addMessage, hasToken } from "./utilities";
import { addMessage, hasToken, objectValuesAreDifferent } from "./utilities";
import { enableHotKeys, disableHotKeys } from "./hotkeys";
export function loadSettings() {
@ -27,9 +27,10 @@ export function openSettingsModal() {
}
export function saveSettingsModal() {
window.settings.useIPAPronunciationField = document.getElementById('settingsUseIPA').checked;
window.settings.useHotkeys = document.getElementById('settingsUseHotkeys').checked;
window.settings.defaultTheme = document.getElementById('settingsDefaultTheme').value;
const updatedSettings = cloneObject(window.settings);
updatedSettings.useIPAPronunciationField = document.getElementById('settingsUseIPA').checked;
updatedSettings.useHotkeys = document.getElementById('settingsUseHotkeys').checked;
updatedSettings.defaultTheme = document.getElementById('settingsDefaultTheme').value;
if (hasToken()) {
import('./account/index.js').then(account => {
@ -40,19 +41,30 @@ export function saveSettingsModal() {
email = window.account.email;
emailField.value = email;
}
window.account.email = email;
window.account.publicName = removeTags(publicName.value).trim();
window.account.allowEmails = document.getElementById('accountSettingsAllowEmails').checked;
const updatedAccount = cloneObject(window.account);
updatedAccount.email = email;
updatedAccount.publicName = removeTags(publicName.value).trim();
updatedAccount.allowEmails = document.getElementById('accountSettingsAllowEmails').checked;
const newPassword = document.getElementById('accountSettingsNewPassword').value;
account.editAccount(Object.assign({ newPassword }, window.account));
if (objectValuesAreDifferent(updatedAccount, window.account)) {
window.account = Object.assign(window.account, updatedAccount);
account.editAccount(Object.assign({ newPassword }, window.account));
} else {
addMessage('No changes made to Account.');
}
});
}
saveSettings();
toggleHotkeysEnabled();
toggleIPAPronunciationFields();
if (objectValuesAreDifferent(updatedSettings, window.settings)) {
window.settings = Object.assign(window.settings, updatedSettings);
saveSettings();
toggleHotkeysEnabled();
toggleIPAPronunciationFields();
} else {
addMessage('No changes made to Settings.');
}
}
export function saveAndCloseSettingsModal() {

View File

@ -176,3 +176,19 @@ export function hideAllModals() {
export function hasToken() {
return window.isOffline !== true && getCookie('token') !== '';
}
export function objectValuesAreDifferent(newObject, oldObject) {
let valuesAreDifferent = false;
for (let property in newObject) {
if (!oldObject.hasOwnProperty(property) || JSON.stringify(newObject[property]) !== JSON.stringify(oldObject[property])) {
valuesAreDifferent = true;
}
if (typeof newObject[property] === 'object' && !Array.isArray(newObject[property])) {
valuesAreDifferent = objectValuesAreDifferent(newObject[property], oldObject[property]);
}
if (valuesAreDifferent) break;
}
return valuesAreDifferent;
}

View File

@ -35,57 +35,65 @@ export function sortWords(render) {
const { alphabeticalOrder } = window.currentDictionary;
const sortBy = sortByDefinition ? 'definition' : 'name';
const ordering = {}; // map for efficient lookup of sortIndex
for (let i = 0; i < alphabeticalOrder.length; i++) {
ordering[alphabeticalOrder[i]] = i;
}
window.currentDictionary.words.sort((wordA, wordB) => {
if (wordA[sortBy] === wordB[sortBy]) return 0;
const aLetters = wordA[sortBy].split('');
const bLetters = wordB[sortBy].split('');
for (let i = 0; i < aLetters.length; i++) {
const a = aLetters[i];
if (ordering.hasOwnProperty(a)) { // if a is in the alphabet...
if (typeof bLetters[i] !== 'undefined') { // and if wordB has a letter at the same position...
const b = bLetters[i];
if (ordering.hasOwnProperty(b)) { // and b is in the alphabet then compare the letters
const aIndex = ordering[a];
const bIndex = ordering[b];
if (aIndex === bIndex) { // If the letters are the same, then...
// If wordA is shorter than wordB and this is wordA's last letter, then sort a first;
if (aLetters.length < bLetters.length && i == aLetters.length - 1) return -1;
continue; // Otherwise if it is the same letter, check the next letter
}
return aIndex - bIndex; // If different and both in alphabet, compare alphabetical order
}
} else {
return 1; // If b is shorter than a after looping, then sort a after
}
} else if (ordering.hasOwnProperty(bLetters[i])) {
return 1; // If a is not in the alphabet but b is, sort a after
} else {
if (typeof bLetters[i] !== 'undefined') { // and if wordB has a letter at the same position...
const b = bLetters[i];
if (removeDiacritics(a).toLowerCase() === removeDiacritics(b).toLowerCase()) {
if (aLetters.length < bLetters.length && i == aLetters.length - 1) return -1;
continue;
}
return removeDiacritics(a).toLowerCase() > removeDiacritics(b).toLowerCase() ? 1 : -1;
} else {
return 1; // If b is shorter than a after looping, then sort a after
}
}
}
console.log('done looping, comparing normally:', wordA[sortBy], wordB[sortBy]);
// If after looping, the alphabet is still different, just compare the words alphabetically.
if (removeDiacritics(wordA[sortBy]).toLowerCase() === removeDiacritics(wordB[sortBy]).toLowerCase()) return 0;
return removeDiacritics(wordA[sortBy]).toLowerCase() > removeDiacritics(wordB[sortBy]).toLowerCase() ? 1 : -1;
// Sort normally first
return wordA[sortBy].localeCompare(wordB[sortBy], 'en', { sensitivity: 'base' }); // This is the smart way to do the below!
// if (removeDiacritics(wordA[sortBy]).toLowerCase() === removeDiacritics(wordB[sortBy]).toLowerCase()) return 0;
// return removeDiacritics(wordA[sortBy]).toLowerCase() > removeDiacritics(wordB[sortBy]).toLowerCase() ? 1 : -1;
});
if (alphabeticalOrder.length > 0) {
// If there's an alphabetical order specified, sort by that after! Any letters not in the alphabet will be unsorted, keeping them in ASCII order
const ordering = {}; // map for efficient lookup of sortIndex
for (let i = 0; i < alphabeticalOrder.length; i++) {
ordering[alphabeticalOrder[i]] = i + 1; // Add 1 to prevent 0 from resolving to false
}
window.currentDictionary.words.sort((wordA, wordB) => {
// console.log(alphabeticalOrder, ordering);
// console.log('comparing:', wordA[sortBy], wordB[sortBy]);
if (wordA[sortBy] === wordB[sortBy]) return 0;
const aLetters = wordA[sortBy].split('');
const bLetters = wordB[sortBy].split('');
for (let i = 0; i < aLetters.length; i++) {
const a = aLetters[i];
const b = bLetters[i];
// console.log('comparing letters', a, b);
if (!b) {
// console.log('no b, ', wordA[sortBy], 'is longer than', wordB[sortBy]);
return 1;
}
if (!ordering[a] && !ordering[b]) {
// console.log('a and b not in dictionary:', a, b, 'continuing to the next letter');
continue;
}
if (!ordering[a]) {
// console.log('a is not in dictionary:', a, 'moving back:', wordA[sortBy]);
return 1;
}
if (!ordering[b]) {
// console.log('b is not in dictionary:', b, 'moving forward:', wordA[sortBy]);
return -1;
}
if (ordering[a] === ordering[b]) {
// console.log('letters are the same order:', a, b);
if (aLetters.length < bLetters.length && i === aLetters.length - 1) {
// console.log(a, 'is shorter than', b);
return -1;
}
// console.log(a, 'is the same as', b, 'continuing to the next letter');
continue;
}
// console.log('comparing order:', a, b, 'result:', ordering[a] - ordering[b]);
return ordering[a] - ordering[b];
}
// console.log('all of the letters were dumb, no sort');
return 0;
});
}
saveDictionary(false);

View File

@ -255,8 +255,12 @@
<label>Parts of Speech <small>(Comma Separated List)</small><br>
<input id="editPartsOfSpeech" maxlength="2500" placeholder="Noun,Adjective,Verb">
</label>
<label>Alphabetical Order <small>(Comma Separated List. Include every letter!)</small><br>
<input id="editAlphabeticalOrder" disabled value="English Alphabet">
<label>Alphabetical Order <small>(Space Separated List)</small><br>
<input id="editAlphabeticalOrder" placeholder="a A b B c C d D ...">
<a class="label-help-button" onclick="alert('Include every letter and case! Any letters used in your words that are not specified will be sorted in the default order below your alphabetically custom-sorted words.\n\nLexiconga can only sort by single characters and will sort by the words AS ENTERED, not using orthographic translation.')">
Field Info
</a>&nbsp;
<small>Leave blank for default (case-insensitive ASCII/Unicode sorting)</small>
</label>
<h3>Phonology</h3>
<div class="split three">