Improve AnkiController to indicate when the model/deck is invalid (#1611)

This commit is contained in:
toasted-nutbread 2021-04-12 20:20:14 -04:00 committed by GitHub
parent 20d60a2ba7
commit bbf47865ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -340,15 +340,13 @@ class AnkiCardController {
this._cardMenu = node.dataset.ankiCardMenu;
this._eventListeners = new EventListenerCollection();
this._fieldEventListeners = new EventListenerCollection();
this._deck = null;
this._model = null;
this._fields = null;
this._modelChangingTo = null;
this._ankiCardDeckSelect = null;
this._ankiCardModelSelect = null;
this._ankiCardFieldsContainer = null;
this._cleaned = false;
this._fieldEntries = [];
this._deckController = new AnkiCardSelectController();
this._modelController = new AnkiCardSelectController();
}
async prepare() {
@ -359,19 +357,16 @@ class AnkiCardController {
const cardOptions = this._getCardOptions(ankiOptions, this._cardType);
if (cardOptions === null) { return; }
const {deck, model, fields} = cardOptions;
this._deck = deck;
this._model = model;
this._deckController.prepare(this._node.querySelector('.anki-card-deck'), deck);
this._modelController.prepare(this._node.querySelector('.anki-card-model'), model);
this._fields = fields;
this._ankiCardDeckSelect = this._node.querySelector('.anki-card-deck');
this._ankiCardModelSelect = this._node.querySelector('.anki-card-model');
this._ankiCardFieldsContainer = this._node.querySelector('.anki-card-fields');
this._setupSelects([], []);
this._setupFields();
this._eventListeners.addEventListener(this._ankiCardDeckSelect, 'change', this._onCardDeckChange.bind(this), false);
this._eventListeners.addEventListener(this._ankiCardModelSelect, 'change', this._onCardModelChange.bind(this), false);
this._eventListeners.addEventListener(this._deckController.select, 'change', this._onCardDeckChange.bind(this), false);
this._eventListeners.addEventListener(this._modelController.select, 'change', this._onCardModelChange.bind(this), false);
this._eventListeners.on(this._settingsController, 'permissionsChanged', this._onPermissionsChanged.bind(this));
await this.updateAnkiState();
@ -387,7 +382,8 @@ class AnkiCardController {
if (this._fields === null) { return; }
const {deckNames, modelNames} = await this._ankiController.getAnkiData();
if (this._cleaned) { return; }
this._setupSelects(deckNames, modelNames);
this._deckController.setOptionValues(deckNames);
this._modelController.setOptionValues(modelNames);
}
isStale() {
@ -456,31 +452,6 @@ class AnkiCardController {
}
}
_setupSelects(deckNames, modelNames) {
const deck = this._deck;
const model = this._model;
if (!deckNames.includes(deck)) { deckNames = [...deckNames, deck]; }
if (!modelNames.includes(model)) { modelNames = [...modelNames, model]; }
this._setSelectOptions(this._ankiCardDeckSelect, deckNames);
this._ankiCardDeckSelect.value = deck;
this._setSelectOptions(this._ankiCardModelSelect, modelNames);
this._ankiCardModelSelect.value = model;
}
_setSelectOptions(select, optionValues) {
const fragment = document.createDocumentFragment();
for (const optionValue of optionValues) {
const option = document.createElement('option');
option.value = optionValue;
option.textContent = optionValue;
fragment.appendChild(option);
}
select.textContent = '';
select.appendChild(fragment);
}
_setupFields() {
this._fieldEventListeners.removeAllEventListeners();
@ -551,7 +522,7 @@ class AnkiCardController {
let fieldNames;
try {
fieldNames = await this._ankiController.getModelFieldNames(this._model);
fieldNames = await this._ankiController.getModelFieldNames(this._modelController.value);
} catch (e) {
return;
}
@ -568,8 +539,8 @@ class AnkiCardController {
}
async _setDeck(value) {
if (this._deck === value) { return; }
this._deck = value;
if (this._deckController.value === value) { return; }
this._deckController.value = value;
await this._settingsController.modifyProfileSettings([{
action: 'set',
@ -579,12 +550,13 @@ class AnkiCardController {
}
async _setModel(value) {
const select = this._modelController.select;
if (this._modelChangingTo !== null) {
// Revert
this._ankiCardModelSelect.value = this._modelChangingTo;
select.value = this._modelChangingTo;
return;
}
if (this._model === value) { return; }
if (this._modelController.value === value) { return; }
let fieldNames;
let options;
@ -594,7 +566,7 @@ class AnkiCardController {
options = await this._ankiController.settingsController.getOptions();
} catch (e) {
// Revert
this._ankiCardModelSelect.value = this._model;
select.value = this._modelController.value;
return;
} finally {
this._modelChangingTo = null;
@ -623,7 +595,7 @@ class AnkiCardController {
}
];
this._model = value;
this._modelController.value = value;
this._fields = fields;
await this._settingsController.modifyProfileSettings(targets);
@ -724,3 +696,81 @@ class AnkiCardController {
return '';
}
}
class AnkiCardSelectController {
constructor() {
this._value = null;
this._select = null;
this._optionValues = null;
this._hasExtraOption = false;
this._selectNeedsUpdate = false;
}
get value() {
return this._value;
}
set value(value) {
this._value = value;
this._updateSelect();
}
get select() {
return this._select;
}
prepare(select, value) {
this._select = select;
this._value = value;
this._updateSelect();
}
setOptionValues(optionValues) {
this._optionValues = optionValues;
this._selectNeedsUpdate = true;
this._updateSelect();
}
// Private
_updateSelect() {
const value = this._value;
let optionValues = this._optionValues;
const hasOptionValues = Array.isArray(optionValues) && optionValues.length > 0;
if (!hasOptionValues) {
optionValues = [];
}
const hasExtraOption = !optionValues.includes(value);
if (hasExtraOption) {
optionValues = [...optionValues, value];
}
const select = this._select;
if (this._selectNeedsUpdate || hasExtraOption !== this._hasExtraOption) {
this._setSelectOptions(select, optionValues);
select.value = value;
this._hasExtraOption = hasExtraOption;
this._selectNeedsUpdate = false;
}
if (hasOptionValues) {
select.dataset.invalid = `${hasExtraOption}`;
} else {
delete select.dataset.invalid;
}
}
_setSelectOptions(select, optionValues) {
const fragment = document.createDocumentFragment();
for (const optionValue of optionValues) {
const option = document.createElement('option');
option.value = optionValue;
option.textContent = optionValue;
fragment.appendChild(option);
}
select.textContent = '';
select.appendChild(fragment);
}
}