Compare commits

...

3 Commits

6 changed files with 86 additions and 19 deletions

View File

@ -1,6 +1,7 @@
import { addMessage } from "../utilities";
import { saveDictionary } from "../dictionaryManagement";
import { saveDictionary, clearDictionary } from "../dictionaryManagement";
import { request, saveToken } from "./helpers";
import { renderAll } from "../render";
/* Outline for syncing
login
@ -8,12 +9,12 @@ login
(DONE!) ? no id
-> upload dictionary
-> make new dictionary current
? mismatched id
(Canceled) ? mismatched id
-> sync local dictionary (see 'same id' below)
-> if no matching remote id, ignore (assume deleted)
-> clear local dictionary
-> insert downloaded dictionary
? same id
(DONE!) ? same id
-> compare detail last updated timestamp
? downloaded details are newer
-> replace local details
@ -37,15 +38,27 @@ export function syncDictionary() {
request({
action: 'get-current-dictionary',
}, remote => {
console.log(remote);
// console.log(remote);
if (remote.details.externalId !== window.currentDictionary.externalId) {
clearDictionary();
}
const detailsSynced = syncDetails(remote.details);
if (detailsSynced === false) {
addMessage('Could not sync');
} else {
detailsSynced.then(success => {
renderAll();
if (success) {
console.log('Do a word comparison!');
syncWords(remote.words, remote.deletedWords).then(success => {
if (success) {
renderAll();
} else {
console.error('word sync failed');
}
});
} else {
console.error('details sync failed');
}
});
}
@ -91,7 +104,17 @@ export function uploadWholeDictionary(asNew = false) {
}
export function syncDetails(remoteDetails = false) {
if (remoteDetails === false || remoteDetails.lastUpdated < window.currentDictionary.lastUpdated) {
let direction; // This is if/else if tree the only way I can think to correctly prioritize this when to upload vs download.
if (remoteDetails === false) {
direction = 'up';
} else if (!window.currentDictionary.hasOwnProperty('externalId')) { // If mismatched id, dictionary will be cleared, allowing it to be overwritten
direction = 'down';
} else if (remoteDetails.lastUpdated < window.currentDictionary.lastUpdated) {
direction = 'up';
} else if (remoteDetails.lastUpdated > window.currentDictionary.lastUpdated) {
direction = 'down';
}
if (direction === 'up') {
const details = Object.assign({}, window.currentDictionary);
delete details.words;
return request({
@ -105,12 +128,12 @@ export function syncDetails(remoteDetails = false) {
addMessage('Could not sync dictionary');
return false;
});
} else if (remoteDetails.lastUpdated > window.currentDictionary.lastUpdated) {
} else if (direction === 'down') {
window.currentDictionary = Object.assign(window.currentDictionary, remoteDetails);
saveDictionary();
}
addMessage('Dictionary details synchronized');
return Promise.resolve();
return Promise.resolve(true);
}
export function syncWords(remoteWords, deletedWords) {
@ -121,14 +144,44 @@ export function syncWords(remoteWords, deletedWords) {
}
return true;
});
const newLocalWords = words.filter(word => {
const localWordsToUpload = words.filter(word => {
// Find words that don't exist in remote words after clearing deleted words
const remote = remoteWords.find(remoteWord => remoteWord.id === word.wordId);
return typeof remote === 'undefined';
});
remoteWords.forEach(remoteWord => {
const localWord = words.find(word => word.wordId === remoteWord.wordId);
if (localWord) {
if (localWord.lastUpdated < remoteWord.lastUpdated) {
localWord = remoteWord;
} else if (localWord.lastUpdated > remoteWord.lastUpdated) {
// Add more-recently-updated words to upload
localWordsToUpload.push(localWord);
}
} else {
// If word not found, add it to words
words.push(remoteWord);
}
});
window.currentDictionary.words = words;
saveDictionary();
if (localWordsToUpload.length > 0) {
return request({
action: 'set-dictionary-words',
words,
}, successful => {
addMessage('Saved Words to Server');
return successful;
}, error => {
console.error(error);
addMessage('Could not sync words');
return false;
});
}
addMessage('Words synchronized');
return Promise.resolve(true);
}

View File

@ -96,7 +96,7 @@ export function renderStats() {
detailsPanel.innerHTML = numberOfWordsHTML + wordLengthHTML + letterDistributionHTML + totalLettersHTML;
}
export function renderPartsOfSpeech() {
export function renderPartsOfSpeech(onlyOptions = false) {
let optionsHTML = '<option value=""></option>',
searchHTML = '<label>Unclassified <input type="checkbox" checked id="searchPartOfSpeech__None"></label>';
window.currentDictionary.partsOfSpeech.forEach(partOfSpeech => {
@ -110,7 +110,9 @@ export function renderPartsOfSpeech() {
select.innerHTML = optionsHTML;
select.value = selectedValue;
});
document.getElementById('searchPartsOfSpeech').innerHTML = searchHTML;
if (!onlyOptions) {
document.getElementById('searchPartsOfSpeech').innerHTML = searchHTML;
}
setupSearchFilters();
}
@ -273,6 +275,7 @@ export function renderEditForm(wordId = false) {
document.getElementById(wordId.toString()).innerHTML = editForm;
setupWordEditFormButtons();
renderPartsOfSpeech(true);
}
}

View File

@ -107,6 +107,7 @@ export function updateWord(word, wordId) {
console.error('Could not find word to update');
} else {
word.lastUpdated = getTimestampInSeconds();
word.createdOn = window.currentDictionary.words[wordIndex].createdOn;
window.currentDictionary.words[wordIndex] = word;
addMessage('Word Updated Successfully');
sortWords(true);

View File

@ -197,7 +197,6 @@ WHERE dictionary=$dictionary";
if ($results) {
return array_map(function ($row) {
return array(
'id' => intval($row['word_id']),
'name' => $row['name'],
'pronunciation' => $row['pronunciation'],
'partOfSpeech' => $row['part_of_speech'],
@ -205,6 +204,7 @@ WHERE dictionary=$dictionary";
'details' => $row['details'],
'lastUpdated' => is_null($row['last_updated']) ? null : intval($row['last_updated']),
'createdOn' => intval($row['created_on']),
'wordId' => intval($row['word_id']),
);
}, $results);
}
@ -239,10 +239,10 @@ WHERE dictionary=$dictionary";
if ($most_recent_word_update < $last_updated) {
$most_recent_word_update = $last_updated;
}
$word_ids[] = $word['id'];
$word_ids[] = $word['wordId'];
$query .= "(?, ?, ?, ?, ?, ?, ?, ?, ?), ";
$params[] = $dictionary;
$params[] = $word['id'];
$params[] = $word['wordId'];
$params[] = $word['name'];
$params[] = $word['pronunciation'];
$params[] = $word['partOfSpeech'];
@ -257,7 +257,8 @@ pronunciation=VALUES(pronunciation),
part_of_speech=VALUES(part_of_speech),
definition=VALUES(definition),
details=VALUES(details),
last_updated=VALUES(last_updated)';
last_updated=VALUES(last_updated),
created_on=VALUES(created_on)';
$results = $this->db->execute($query, $params);

View File

@ -212,9 +212,12 @@ VALUES (?, ?, ?, ?, ?)';
$dictionary = $user_data->dictionary;
$user = $user_data->id;
$updated_words = $this->dictionary->setWords($user, $dictionary, $words);
if ($updated_words) {
if ($updated_words === true) {
return true;
}
return array(
'error' => $updated_words,
);
}
return false;
}

View File

@ -249,12 +249,18 @@ switch ($action) {
if ($token !== false && isset($request['words'])) {
$user = new User();
$update_words_success = $user->updateOrAddWordsToCurrentDictionary($token, $request['words']);
if ($update_words_success !== false) {
if ($update_words_success === true) {
return Response::json(array(
'data' => 'Updated successfully',
'data' => $update_words_success,
'error' => false,
), 200);
}
if (isset($update_words_success['error'])) {
return Response::json(array(
'data' => $update_words_success['error'],
'error' => true,
), 500);
}
return Response::json(array(
'data' => 'Could not set words: invalid token',
'error' => true,