Skip to content
This repository has been archived by the owner on Feb 25, 2023. It is now read-only.

Commit

Permalink
AnkiUtil (#1439)
Browse files Browse the repository at this point in the history
* Add AnkiUtil

* Update AnkiConnect to use AnkiUtil

* Use AnkiUtil in AnkiNoteBuilder

* Replace containsAnyMarker with AnkiUtil.stringContainsAnyFieldMarker

* Add AnkiUtil.getFieldMarkers

* Add fieldsObjectContainsMarker to AnkiUtil

* Remove unused global

* Remove unused parameter: enabled

* Add cloneFieldMarkerPattern
  • Loading branch information
toasted-nutbread authored Feb 25, 2021
1 parent 0a76de1 commit ae92e0b
Show file tree
Hide file tree
Showing 18 changed files with 123 additions and 59 deletions.
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@
"ext/js/comm/clipboard-monitor.js",
"ext/js/comm/clipboard-reader.js",
"ext/js/comm/mecab.js",
"ext/js/data/anki-util.js",
"ext/js/data/database.js",
"ext/js/data/json-schema.js",
"ext/js/data/options-util.js",
Expand Down
1 change: 1 addition & 0 deletions ext/action-popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ <h3 id="extension-info">Yomichan</h3>

<script src="/js/comm/api.js"></script>
<script src="/js/comm/cross-frame-api.js"></script>
<script src="/js/data/anki-util.js"></script>
<script src="/js/data/permissions-util.js"></script>
<script src="/js/input/hotkey-help-controller.js"></script>
<script src="/js/input/hotkey-util.js"></script>
Expand Down
1 change: 1 addition & 0 deletions ext/background.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<script src="/js/comm/clipboard-monitor.js"></script>
<script src="/js/comm/clipboard-reader.js"></script>
<script src="/js/comm/mecab.js"></script>
<script src="/js/data/anki-util.js"></script>
<script src="/js/data/database.js"></script>
<script src="/js/data/json-schema.js"></script>
<script src="/js/data/options-util.js"></script>
Expand Down
1 change: 1 addition & 0 deletions ext/info.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ <h2 id="links">Links</h2>

<script src="/js/comm/api.js"></script>
<script src="/js/comm/cross-frame-api.js"></script>
<script src="/js/data/anki-util.js"></script>
<script src="/js/data/permissions-util.js"></script>
<script src="/js/dom/document-focus-controller.js"></script>
<script src="/js/dom/html-template-collection.js"></script>
Expand Down
11 changes: 5 additions & 6 deletions ext/js/comm/anki.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

/* global
* AnkiUtil
*/

class AnkiConnect {
constructor() {
this._enabled = false;
Expand Down Expand Up @@ -113,7 +117,7 @@ class AnkiConnect {
query = `"deck:${this._escapeQuery(note.deckName)}" `;
break;
case 'deck-root':
query = `"deck:${this._escapeQuery(this.getRootDeckName(note.deckName))}" `;
query = `"deck:${this._escapeQuery(AnkiUtil.getRootDeckName(note.deckName))}" `;
break;
}
query += this._fieldsToQuery(note.fields);
Expand All @@ -138,11 +142,6 @@ class AnkiConnect {
return await this.findCards(`nid:${noteId}`);
}

getRootDeckName(deckName) {
const index = deckName.indexOf('::');
return index >= 0 ? deckName.substring(0, index) : deckName;
}

// Private

async _checkVersion() {
Expand Down
30 changes: 5 additions & 25 deletions ext/js/data/anki-note-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@
*/

/* global
* AnkiUtil
* TemplateRendererProxy
*/

class AnkiNoteBuilder {
constructor(enabled) {
this._markerPattern = /\{([\w-]+)\}/g;
this._templateRenderer = enabled ? new TemplateRendererProxy() : null;
constructor() {
this._markerPattern = AnkiUtil.cloneFieldMarkerPattern(true);
this._templateRenderer = new TemplateRendererProxy();
}

async createNote({
Expand All @@ -46,7 +47,7 @@ class AnkiNoteBuilder {
let duplicateScopeCheckChildren = false;
if (duplicateScope === 'deck-root') {
duplicateScope = 'deck';
duplicateScopeDeckName = this.getRootDeckName(deckName);
duplicateScopeDeckName = AnkiUtil.getRootDeckName(deckName);
duplicateScopeCheckChildren = true;
}

Expand Down Expand Up @@ -89,27 +90,6 @@ class AnkiNoteBuilder {
};
}

containsMarker(fields, marker) {
marker = `{${marker}}`;
for (const [, fieldValue] of fields) {
if (fieldValue.includes(marker)) {
return true;
}
}
return false;
}

containsAnyMarker(field) {
const result = this._markerPattern.test(field);
this._markerPattern.lastIndex = 0;
return result;
}

getRootDeckName(deckName) {
const index = deckName.indexOf('::');
return index >= 0 ? deckName.substring(0, index) : deckName;
}

// Private

async _formatField(field, data, templates, errors=null) {
Expand Down
87 changes: 87 additions & 0 deletions ext/js/data/anki-util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright (C) 2021 Yomichan Authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

/**
* This class has some general utility functions for working with Anki data.
*/
class AnkiUtil {
/**
* Gets the root deck name of a full deck name. If the deck is a root deck,
* the same name is returned. Nested decks are separated using '::'.
* @param deckName A string of the deck name.
* @returns A string corresponding to the name of the root deck.
*/
static getRootDeckName(deckName) {
const index = deckName.indexOf('::');
return index >= 0 ? deckName.substring(0, index) : deckName;
}

/**
* Checks whether or not any marker is contained in a string.
* @param string A string to check.
* @return `true` if the text contains an Anki field marker, `false` otherwise.
*/
static stringContainsAnyFieldMarker(string) {
const result = this._markerPattern.test(string);
this._markerPattern.lastIndex = 0;
return result;
}

/**
* Gets a list of all markers that are contained in a string.
* @param string A string to check.
* @return An array of marker strings.
*/
static getFieldMarkers(string) {
const pattern = this._markerPattern;
const markers = [];
while (true) {
const match = pattern.exec(string);
if (match === null) { break; }
markers.push(match[1]);
}
return markers;
}

/**
* Checks whether an object of key-value pairs has a value which contains a specific marker.
* @param fieldsObject An object with key-value pairs, where the value corresponds to the field value.
* @param marker The marker string to check for, excluding brackets.
* @returns `true` if any of the fields contains the marker, `false` otherwise.
*/
static fieldsObjectContainsMarker(fieldsObject, marker) {
marker = `{${marker}}`;
for (const [, fieldValue] of fieldsObject) {
if (fieldValue.includes(marker)) {
return true;
}
}
return false;
}

/**
* Returns a regular expression which can be used to find markers in a string.
* @param global Whether or not the regular expression should have the global flag.
* @returns A new `RegExp` instance.
*/
static cloneFieldMarkerPattern(global) {
return new RegExp(this._markerPattern.source, global ? 'g' : '');
}
}

// eslint-disable-next-line no-underscore-dangle
AnkiUtil._markerPattern = /\{([\w-]+)\}/g;
21 changes: 6 additions & 15 deletions ext/js/data/permissions-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

/* global
* AnkiUtil
*/

class PermissionsUtil {
constructor() {
this._ankiFieldMarkersRequiringClipboardPermission = new Set([
'clipboard-image',
'clipboard-text'
]);
this._ankiMarkerPattern = /\{([\w-]+)\}/g;
}

hasPermissions(permissions) {
Expand Down Expand Up @@ -69,7 +72,7 @@ class PermissionsUtil {
}

getRequiredPermissionsForAnkiFieldValue(fieldValue) {
const markers = this._getAnkiFieldMarkers(fieldValue);
const markers = AnkiUtil.getFieldMarkers(fieldValue);
const markerPermissions = this._ankiFieldMarkersRequiringClipboardPermission;
for (const marker of markers) {
if (markerPermissions.has(marker)) {
Expand Down Expand Up @@ -99,7 +102,7 @@ class PermissionsUtil {
];
for (const fields of fieldsList) {
for (const fieldValue of Object.values(fields)) {
const markers = this._getAnkiFieldMarkers(fieldValue);
const markers = AnkiUtil.getFieldMarkers(fieldValue);
for (const marker of markers) {
if (fieldMarkersRequiringClipboardPermission.has(marker)) {
return false;
Expand All @@ -111,16 +114,4 @@ class PermissionsUtil {

return true;
}

// Private

_getAnkiFieldMarkers(fieldValue) {
const pattern = this._ankiMarkerPattern;
const markers = [];
let match;
while ((match = pattern.exec(fieldValue)) !== null) {
markers.push(match[1]);
}
return markers;
}
}
11 changes: 6 additions & 5 deletions ext/js/display/display.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

/* global
* AnkiNoteBuilder
* AnkiUtil
* DisplayAudio
* DisplayGenerator
* DisplayHistory
Expand Down Expand Up @@ -85,7 +86,7 @@ class Display extends EventDispatcher {
});
this._ankiFieldTemplates = null;
this._ankiFieldTemplatesDefault = null;
this._ankiNoteBuilder = new AnkiNoteBuilder(true);
this._ankiNoteBuilder = new AnkiNoteBuilder();
this._updateAdderButtonsPromise = Promise.resolve();
this._contentScrollElement = document.querySelector('#content-scroll');
this._contentScrollBodyElement = document.querySelector('#content-body');
Expand Down Expand Up @@ -1493,7 +1494,7 @@ class Display extends EventDispatcher {
const definitionDetails = this._getDefinitionDetailsForNote(definition);

let audioDetails = null;
if (definitionDetails.type !== 'kanji' && this._ankiNoteBuilder.containsMarker(fields, 'audio')) {
if (definitionDetails.type !== 'kanji' && AnkiUtil.fieldsObjectContainsMarker(fields, 'audio')) {
const primaryCardAudio = this._displayAudio.getPrimaryCardAudio(definitionDetails.expression, definitionDetails.reading);
let preferredAudioIndex = null;
let sources2 = sources;
Expand All @@ -1504,11 +1505,11 @@ class Display extends EventDispatcher {
audioDetails = {sources: sources2, preferredAudioIndex, customSourceUrl, customSourceType};
}

const screenshotDetails = (this._ankiNoteBuilder.containsMarker(fields, 'screenshot') ? {tabId: this._contentOriginTabId, frameId: this._contentOriginFrameId, format, quality} : null);
const screenshotDetails = (AnkiUtil.fieldsObjectContainsMarker(fields, 'screenshot') ? {tabId: this._contentOriginTabId, frameId: this._contentOriginFrameId, format, quality} : null);

const clipboardDetails = {
image: this._ankiNoteBuilder.containsMarker(fields, 'clipboard-image'),
text: this._ankiNoteBuilder.containsMarker(fields, 'clipboard-text')
image: AnkiUtil.fieldsObjectContainsMarker(fields, 'clipboard-image'),
text: AnkiUtil.fieldsObjectContainsMarker(fields, 'clipboard-text')
};

return await yomichan.api.injectAnkiNoteMedia(
Expand Down
9 changes: 2 additions & 7 deletions ext/js/pages/settings/anki-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

/* global
* AnkiConnect
* AnkiNoteBuilder
* AnkiUtil
* ObjectPropertyAccessor
* SelectorObserver
*/
Expand All @@ -26,7 +26,6 @@ class AnkiController {
constructor(settingsController) {
this._settingsController = settingsController;
this._ankiConnect = new AnkiConnect();
this._ankiNoteBuilder = new AnkiNoteBuilder(false);
this._selectorObserver = new SelectorObserver({
selector: '.anki-card',
ignoreSelector: null,
Expand Down Expand Up @@ -156,10 +155,6 @@ class AnkiController {
return this._settingsController.permissionsUtil.getRequiredPermissionsForAnkiFieldValue(fieldValue);
}

containsAnyMarker(field) {
return this._ankiNoteBuilder.containsAnyMarker(field);
}

// Private

async _onOptionsChanged({options: {anki}}) {
Expand Down Expand Up @@ -439,7 +434,7 @@ class AnkiCardController {

_validateField(node, index) {
let valid = (node.dataset.hasPermissions !== 'false');
if (valid && index === 0 && !this._ankiController.containsAnyMarker(node.value)) {
if (valid && index === 0 && !AnkiUtil.stringContainsAnyFieldMarker(node.value)) {
valid = false;
}
node.dataset.invalid = `${!valid}`;
Expand Down
2 changes: 1 addition & 1 deletion ext/js/pages/settings/anki-templates-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class AnkiTemplatesController {
this._renderFieldInput = null;
this._renderResult = null;
this._fieldTemplateResetModal = null;
this._ankiNoteBuilder = new AnkiNoteBuilder(true);
this._ankiNoteBuilder = new AnkiNoteBuilder();
}

async prepare() {
Expand Down
1 change: 1 addition & 0 deletions ext/permissions.html
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ <h2 id="permissions"></h2>

<script src="/js/comm/api.js"></script>
<script src="/js/comm/cross-frame-api.js"></script>
<script src="/js/data/anki-util.js"></script>
<script src="/js/data/permissions-util.js"></script>
<script src="/js/dom/document-focus-controller.js"></script>
<script src="/js/dom/html-template-collection.js"></script>
Expand Down
1 change: 1 addition & 0 deletions ext/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ <h3>Default Profile</h3>
<script src="/js/comm/cross-frame-api.js"></script>
<script src="/js/comm/frame-endpoint.js"></script>
<script src="/js/data/anki-note-builder.js"></script>
<script src="/js/data/anki-util.js"></script>
<script src="/js/display/display.js"></script>
<script src="/js/display/display-audio.js"></script>
<script src="/js/display/display-generator.js"></script>
Expand Down
1 change: 1 addition & 0 deletions ext/search.html
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ <h1>Yomichan Search</h1>
<script src="/js/comm/clipboard-monitor.js"></script>
<script src="/js/comm/cross-frame-api.js"></script>
<script src="/js/data/anki-note-builder.js"></script>
<script src="/js/data/anki-util.js"></script>
<script src="/js/display/display.js"></script>
<script src="/js/display/display-audio.js"></script>
<script src="/js/display/display-generator.js"></script>
Expand Down
1 change: 1 addition & 0 deletions ext/settings-old.html
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,7 @@ <h3>Support Development</h3>
<script src="/js/comm/api.js"></script>
<script src="/js/comm/cross-frame-api.js"></script>
<script src="/js/data/anki-note-builder.js"></script>
<script src="/js/data/anki-util.js"></script>
<script src="/js/data/database.js"></script>
<script src="/js/data/json-schema.js"></script>
<script src="/js/data/options-util.js"></script>
Expand Down
1 change: 1 addition & 0 deletions ext/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -3198,6 +3198,7 @@ <h2></h2>
<script src="/js/comm/api.js"></script>
<script src="/js/comm/cross-frame-api.js"></script>
<script src="/js/data/anki-note-builder.js"></script>
<script src="/js/data/anki-util.js"></script>
<script src="/js/data/database.js"></script>
<script src="/js/data/json-schema.js"></script>
<script src="/js/data/options-util.js"></script>
Expand Down
1 change: 1 addition & 0 deletions ext/sw.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ self.importScripts(
'/js/comm/clipboard-monitor.js',
'/js/comm/clipboard-reader.js',
'/js/comm/mecab.js',
'/js/data/anki-util.js',
'/js/data/database.js',
'/js/data/json-schema.js',
'/js/data/options-util.js',
Expand Down
Loading

0 comments on commit ae92e0b

Please sign in to comment.