Merge pull request #385 from toasted-nutbread/pitch-accents
Pitch accents
This commit is contained in:
commit
f439d12718
@ -87,6 +87,8 @@
|
|||||||
"stringReverse": "readonly",
|
"stringReverse": "readonly",
|
||||||
"promiseTimeout": "readonly",
|
"promiseTimeout": "readonly",
|
||||||
"parseUrl": "readonly",
|
"parseUrl": "readonly",
|
||||||
|
"areSetsEqual": "readonly",
|
||||||
|
"getSetIntersection": "readonly",
|
||||||
"EventDispatcher": "readonly",
|
"EventDispatcher": "readonly",
|
||||||
"EventListenerCollection": "readonly",
|
"EventListenerCollection": "readonly",
|
||||||
"EXTENSION_IS_BROWSER_EDGE": "readonly"
|
"EXTENSION_IS_BROWSER_EDGE": "readonly"
|
||||||
|
@ -13,13 +13,71 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["freq"],
|
"enum": ["freq", "pitch"],
|
||||||
"description": "Type of data. \"freq\" corresponds to frequency information."
|
"description": "Type of data. \"freq\" corresponds to frequency information; \"pitch\" corresponds to pitch information."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": ["string", "number"],
|
|
||||||
"description": "Data for the term/expression."
|
"description": "Data for the term/expression."
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
|
{},
|
||||||
|
{"enum": ["freq"]},
|
||||||
|
{
|
||||||
|
"type": ["string", "number"],
|
||||||
|
"description": "Frequency information for the term or expression."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
|
{},
|
||||||
|
{"enum": ["pitch"]},
|
||||||
|
{
|
||||||
|
"type": ["object"],
|
||||||
|
"description": "Pitch accent information for the term or expression.",
|
||||||
|
"required": [
|
||||||
|
"reading",
|
||||||
|
"pitches"
|
||||||
|
],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"reading": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Reading for the term or expression."
|
||||||
|
},
|
||||||
|
"pitches": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "List of different pitch accent information for the term and reading combination.",
|
||||||
|
"additionalItems": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"position"
|
||||||
|
],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"position": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Mora position of the pitch accent downstep. A value of 0 indicates that the word does not have a downstep (heiban).",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "List of tags for this pitch accent.",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Tag for this pitch accent. This typically corresponds to a certain type of part of speech."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -105,7 +105,10 @@
|
|||||||
"customPopupCss",
|
"customPopupCss",
|
||||||
"customPopupOuterCss",
|
"customPopupOuterCss",
|
||||||
"enableWanakana",
|
"enableWanakana",
|
||||||
"enableClipboardMonitor"
|
"enableClipboardMonitor",
|
||||||
|
"showPitchAccentDownstepNotation",
|
||||||
|
"showPitchAccentPositionNotation",
|
||||||
|
"showPitchAccentGraph"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"enable": {
|
"enable": {
|
||||||
@ -227,6 +230,18 @@
|
|||||||
"enableClipboardMonitor": {
|
"enableClipboardMonitor": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"showPitchAccentDownstepNotation": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"showPitchAccentPositionNotation": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"showPitchAccentGraph": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -137,30 +137,6 @@ function dictTermsGroup(definitions, dictionaries) {
|
|||||||
return dictTermsSort(results);
|
return dictTermsSort(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
function dictAreSetsEqual(set1, set2) {
|
|
||||||
if (set1.size !== set2.size) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const value of set1) {
|
|
||||||
if (!set2.has(value)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function dictGetSetIntersection(set1, set2) {
|
|
||||||
const result = [];
|
|
||||||
for (const value of set1) {
|
|
||||||
if (set2.has(value)) {
|
|
||||||
result.push(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function dictTermsMergeBySequence(definitions, mainDictionary) {
|
function dictTermsMergeBySequence(definitions, mainDictionary) {
|
||||||
const sequencedDefinitions = new Map();
|
const sequencedDefinitions = new Map();
|
||||||
const nonSequencedDefinitions = [];
|
const nonSequencedDefinitions = [];
|
||||||
@ -281,11 +257,11 @@ function dictTermsMergeByGloss(result, definitions, appendTo=null, mergedIndices
|
|||||||
const only = [];
|
const only = [];
|
||||||
const expressionSet = definition.expression;
|
const expressionSet = definition.expression;
|
||||||
const readingSet = definition.reading;
|
const readingSet = definition.reading;
|
||||||
if (!dictAreSetsEqual(expressionSet, resultExpressionSet)) {
|
if (!areSetsEqual(expressionSet, resultExpressionSet)) {
|
||||||
only.push(...dictGetSetIntersection(expressionSet, resultExpressionSet));
|
only.push(...getSetIntersection(expressionSet, resultExpressionSet));
|
||||||
}
|
}
|
||||||
if (!dictAreSetsEqual(readingSet, resultReadingSet)) {
|
if (!areSetsEqual(readingSet, resultReadingSet)) {
|
||||||
only.push(...dictGetSetIntersection(readingSet, resultReadingSet));
|
only.push(...getSetIntersection(readingSet, resultReadingSet));
|
||||||
}
|
}
|
||||||
definition.only = only;
|
definition.only = only;
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,10 @@ function profileOptionsCreateDefaults() {
|
|||||||
customPopupCss: '',
|
customPopupCss: '',
|
||||||
customPopupOuterCss: '',
|
customPopupOuterCss: '',
|
||||||
enableWanakana: true,
|
enableWanakana: true,
|
||||||
enableClipboardMonitor: false
|
enableClipboardMonitor: false,
|
||||||
|
showPitchAccentDownstepNotation: true,
|
||||||
|
showPitchAccentPositionNotation: true,
|
||||||
|
showPitchAccentGraph: false
|
||||||
},
|
},
|
||||||
|
|
||||||
audio: {
|
audio: {
|
||||||
|
@ -84,6 +84,9 @@ async function formRead(options) {
|
|||||||
options.general.popupScalingFactor = parseFloat($('#popup-scaling-factor').val());
|
options.general.popupScalingFactor = parseFloat($('#popup-scaling-factor').val());
|
||||||
options.general.popupScaleRelativeToPageZoom = $('#popup-scale-relative-to-page-zoom').prop('checked');
|
options.general.popupScaleRelativeToPageZoom = $('#popup-scale-relative-to-page-zoom').prop('checked');
|
||||||
options.general.popupScaleRelativeToVisualViewport = $('#popup-scale-relative-to-visual-viewport').prop('checked');
|
options.general.popupScaleRelativeToVisualViewport = $('#popup-scale-relative-to-visual-viewport').prop('checked');
|
||||||
|
options.general.showPitchAccentDownstepNotation = $('#show-pitch-accent-downstep-notation').prop('checked');
|
||||||
|
options.general.showPitchAccentPositionNotation = $('#show-pitch-accent-position-notation').prop('checked');
|
||||||
|
options.general.showPitchAccentGraph = $('#show-pitch-accent-graph').prop('checked');
|
||||||
options.general.popupTheme = $('#popup-theme').val();
|
options.general.popupTheme = $('#popup-theme').val();
|
||||||
options.general.popupOuterTheme = $('#popup-outer-theme').val();
|
options.general.popupOuterTheme = $('#popup-outer-theme').val();
|
||||||
options.general.customPopupCss = $('#custom-popup-css').val();
|
options.general.customPopupCss = $('#custom-popup-css').val();
|
||||||
@ -161,6 +164,9 @@ async function formWrite(options) {
|
|||||||
$('#popup-scaling-factor').val(options.general.popupScalingFactor);
|
$('#popup-scaling-factor').val(options.general.popupScalingFactor);
|
||||||
$('#popup-scale-relative-to-page-zoom').prop('checked', options.general.popupScaleRelativeToPageZoom);
|
$('#popup-scale-relative-to-page-zoom').prop('checked', options.general.popupScaleRelativeToPageZoom);
|
||||||
$('#popup-scale-relative-to-visual-viewport').prop('checked', options.general.popupScaleRelativeToVisualViewport);
|
$('#popup-scale-relative-to-visual-viewport').prop('checked', options.general.popupScaleRelativeToVisualViewport);
|
||||||
|
$('#show-pitch-accent-downstep-notation').prop('checked', options.general.showPitchAccentDownstepNotation);
|
||||||
|
$('#show-pitch-accent-position-notation').prop('checked', options.general.showPitchAccentPositionNotation);
|
||||||
|
$('#show-pitch-accent-graph').prop('checked', options.general.showPitchAccentGraph);
|
||||||
$('#popup-theme').val(options.general.popupTheme);
|
$('#popup-theme').val(options.general.popupTheme);
|
||||||
$('#popup-outer-theme').val(options.general.popupOuterTheme);
|
$('#popup-outer-theme').val(options.general.popupOuterTheme);
|
||||||
$('#custom-popup-css').val(options.general.customPopupCss);
|
$('#custom-popup-css').val(options.general.customPopupCss);
|
||||||
|
@ -490,6 +490,7 @@ class Translator {
|
|||||||
|
|
||||||
// New data
|
// New data
|
||||||
term.frequencies = [];
|
term.frequencies = [];
|
||||||
|
term.pitches = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const metas = await this.database.findTermMetaBulk(expressionsUnique, dictionaries);
|
const metas = await this.database.findTermMetaBulk(expressionsUnique, dictionaries);
|
||||||
@ -500,6 +501,13 @@ class Translator {
|
|||||||
term.frequencies.push({expression, frequency: data, dictionary});
|
term.frequencies.push({expression, frequency: data, dictionary});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'pitch':
|
||||||
|
for (const term of termsUnique[index]) {
|
||||||
|
const pitchData = await this.getPitchData(expression, data, dictionary, term);
|
||||||
|
if (pitchData === null) { continue; }
|
||||||
|
term.pitches.push(pitchData);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -583,6 +591,20 @@ class Translator {
|
|||||||
return tagMetaList;
|
return tagMetaList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getPitchData(expression, data, dictionary, term) {
|
||||||
|
const reading = data.reading;
|
||||||
|
const termReading = term.reading || expression;
|
||||||
|
if (reading !== termReading) { return null; }
|
||||||
|
|
||||||
|
const pitches = [];
|
||||||
|
for (let {position, tags} of data.pitches) {
|
||||||
|
tags = Array.isArray(tags) ? await this.getTagMetaList(tags, dictionary) : [];
|
||||||
|
pitches.push({position, tags});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {reading, pitches, dictionary};
|
||||||
|
}
|
||||||
|
|
||||||
static createExpression(expression, reading, termTags=null, termFrequency=null) {
|
static createExpression(expression, reading, termTags=null, termFrequency=null) {
|
||||||
const furiganaSegments = jp.distributeFurigana(expression, reading);
|
const furiganaSegments = jp.distributeFurigana(expression, reading);
|
||||||
return {
|
return {
|
||||||
|
@ -162,6 +162,18 @@
|
|||||||
<label><input type="checkbox" id="popup-scale-relative-to-visual-viewport"> Change popup size relative to page viewport</label>
|
<label><input type="checkbox" id="popup-scale-relative-to-visual-viewport"> Change popup size relative to page viewport</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="checkbox options-advanced">
|
||||||
|
<label><input type="checkbox" id="show-pitch-accent-downstep-notation"> Show downstep notation for pitch accents</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="checkbox options-position">
|
||||||
|
<label><input type="checkbox" id="show-pitch-accent-position-notation"> Show position notation for pitch accents</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="checkbox options-advanced">
|
||||||
|
<label><input type="checkbox" id="show-pitch-accent-graph"> Show graph for pitch accents</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="checkbox options-advanced">
|
<div class="checkbox options-advanced">
|
||||||
<label><input type="checkbox" id="show-debug-info"> Show debug information</label>
|
<label><input type="checkbox" id="show-debug-info"> Show debug information</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
body { background-color: #1e1e1e; color: #d4d4d4; }
|
body { background-color: #1e1e1e; color: #d4d4d4; }
|
||||||
|
|
||||||
|
h2 { border-bottom-color: #2f2f2f; }
|
||||||
|
|
||||||
.navigation-header {
|
.navigation-header {
|
||||||
background-color: #1e1e1e;
|
background-color: #1e1e1e;
|
||||||
border-bottom-color: #2f2f2f;
|
border-bottom-color: #2f2f2f;
|
||||||
@ -39,6 +41,7 @@ body { background-color: #1e1e1e; color: #d4d4d4; }
|
|||||||
.tag[data-category=frequency] { background-color: #489148; }
|
.tag[data-category=frequency] { background-color: #489148; }
|
||||||
.tag[data-category=partOfSpeech] { background-color: #565656; }
|
.tag[data-category=partOfSpeech] { background-color: #565656; }
|
||||||
.tag[data-category=search] { background-color: #69696e; }
|
.tag[data-category=search] { background-color: #69696e; }
|
||||||
|
.tag[data-category=pitch-accent-dictionary] { background-color: #6640be; }
|
||||||
|
|
||||||
.term-reasons { color: #888888; }
|
.term-reasons { color: #888888; }
|
||||||
|
|
||||||
@ -57,12 +60,15 @@ body { background-color: #1e1e1e; color: #d4d4d4; }
|
|||||||
color: #666666;
|
color: #666666;
|
||||||
}
|
}
|
||||||
|
|
||||||
.term-definition-container,
|
.term-definition-list,
|
||||||
.kanji-glossary-container {
|
.term-pitch-accent-group-list,
|
||||||
|
.term-pitch-accent-disambiguation-list,
|
||||||
|
.kanji-glossary-list {
|
||||||
color: #888888;
|
color: #888888;
|
||||||
}
|
}
|
||||||
|
|
||||||
.term-glossary,
|
.term-glossary,
|
||||||
|
.term-pitch-accent,
|
||||||
.kanji-glossary {
|
.kanji-glossary {
|
||||||
color: #d4d4d4;
|
color: #d4d4d4;
|
||||||
}
|
}
|
||||||
@ -72,3 +78,20 @@ body { background-color: #1e1e1e; color: #d4d4d4; }
|
|||||||
background-color: #d4d4d4;
|
background-color: #d4d4d4;
|
||||||
color: #1e1e1e;
|
color: #1e1e1e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-container { border-bottom-color: #2f2f2f; }
|
||||||
|
|
||||||
|
.term-pitch-accent-character:before { border-color: #ffffff; }
|
||||||
|
|
||||||
|
.term-pitch-accent-graph-line,
|
||||||
|
.term-pitch-accent-graph-line-tail,
|
||||||
|
#term-pitch-accent-graph-dot,
|
||||||
|
#term-pitch-accent-graph-dot-downstep,
|
||||||
|
#term-pitch-accent-graph-triangle {
|
||||||
|
stroke: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#term-pitch-accent-graph-dot,
|
||||||
|
#term-pitch-accent-graph-dot-downstep>circle:last-of-type {
|
||||||
|
fill: #ffffff;
|
||||||
|
}
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
body { background-color: #ffffff; color: #333333; }
|
body { background-color: #ffffff; color: #333333; }
|
||||||
|
|
||||||
|
h2 { border-bottom-color: #eeeeee; }
|
||||||
|
|
||||||
.navigation-header {
|
.navigation-header {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border-bottom-color: #eeeeee;
|
border-bottom-color: #eeeeee;
|
||||||
@ -39,6 +41,7 @@ body { background-color: #ffffff; color: #333333; }
|
|||||||
.tag[data-category=frequency] { background-color: #5cb85c; }
|
.tag[data-category=frequency] { background-color: #5cb85c; }
|
||||||
.tag[data-category=partOfSpeech] { background-color: #565656; }
|
.tag[data-category=partOfSpeech] { background-color: #565656; }
|
||||||
.tag[data-category=search] { background-color: #8a8a91; }
|
.tag[data-category=search] { background-color: #8a8a91; }
|
||||||
|
.tag[data-category=pitch-accent-dictionary] { background-color: #6640be; }
|
||||||
|
|
||||||
.term-reasons { color: #777777; }
|
.term-reasons { color: #777777; }
|
||||||
|
|
||||||
@ -57,12 +60,15 @@ body { background-color: #ffffff; color: #333333; }
|
|||||||
color: #999999;
|
color: #999999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.term-definition-container,
|
.term-definition-list,
|
||||||
.kanji-glossary-container {
|
.term-pitch-accent-group-list,
|
||||||
|
.term-pitch-accent-disambiguation-list,
|
||||||
|
.kanji-glossary-list {
|
||||||
color: #777777;
|
color: #777777;
|
||||||
}
|
}
|
||||||
|
|
||||||
.term-glossary,
|
.term-glossary,
|
||||||
|
.term-pitch-accent,
|
||||||
.kanji-glossary {
|
.kanji-glossary {
|
||||||
color: #000000;
|
color: #000000;
|
||||||
}
|
}
|
||||||
@ -72,3 +78,20 @@ body { background-color: #ffffff; color: #333333; }
|
|||||||
background-color: #333333;
|
background-color: #333333;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-container { border-bottom-color: #eeeeee; }
|
||||||
|
|
||||||
|
.term-pitch-accent-character:before { border-color: #000000; }
|
||||||
|
|
||||||
|
.term-pitch-accent-graph-line,
|
||||||
|
.term-pitch-accent-graph-line-tail,
|
||||||
|
#term-pitch-accent-graph-dot,
|
||||||
|
#term-pitch-accent-graph-dot-downstep,
|
||||||
|
#term-pitch-accent-graph-triangle {
|
||||||
|
stroke: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#term-pitch-accent-graph-dot,
|
||||||
|
#term-pitch-accent-graph-dot-downstep>circle:last-of-type {
|
||||||
|
fill: #000000;
|
||||||
|
}
|
||||||
|
@ -65,6 +65,14 @@ ol, ul {
|
|||||||
height: 2.28571428em; /* 14px => 32px */
|
height: 2.28571428em; /* 14px => 32px */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.25em;
|
||||||
|
font-weight: normal;
|
||||||
|
margin: 0.25em 0 0;
|
||||||
|
border-bottom-width: 0.05714285714285714em; /* 14px * 1.25em => 1px */
|
||||||
|
border-bottom-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Navigation
|
* Navigation
|
||||||
*/
|
*/
|
||||||
@ -302,6 +310,7 @@ button.action-button {
|
|||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.term-expression-list[data-multi=true] .term-expression:hover .term-expression-details {
|
.term-expression-list[data-multi=true] .term-expression:hover .term-expression-details {
|
||||||
@ -422,6 +431,187 @@ button.action-button {
|
|||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.term-entry-body[data-section-count="0"] .term-entry-body-section-header,
|
||||||
|
.term-entry-body[data-section-count="1"] .term-entry-body-section-header {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pitch accent styles
|
||||||
|
*/
|
||||||
|
|
||||||
|
.entry[data-pitch-accent-count='0'] .term-pitch-accent-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-container {
|
||||||
|
border-bottom-width: 0.05714285714285714em; /* 14px * 1.25em => 1px */
|
||||||
|
border-bottom-style: solid;
|
||||||
|
padding-bottom: 0.25em;
|
||||||
|
margin-bottom: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-group-list {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-group-list:not([data-count="0"]):not([data-count="1"]) {
|
||||||
|
padding-left: 1.4em;
|
||||||
|
list-style-type: decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-list {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-list:not([data-count="0"]):not([data-count="1"]) {
|
||||||
|
padding-left: 1.4em;
|
||||||
|
list-style-type: circle;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent {
|
||||||
|
display: inline;
|
||||||
|
line-height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-list:not([data-count="0"]):not([data-count="1"])>.term-pitch-accent {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-group-tag-list {
|
||||||
|
margin-right: 0.375em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-disambiguation-list {
|
||||||
|
padding-right: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-disambiguation-list:before {
|
||||||
|
content: "(";
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-disambiguation-list:after {
|
||||||
|
content: " only)";
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-disambiguation+.term-pitch-accent-disambiguation:before {
|
||||||
|
content: ", ";
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-disambiguation-list[data-count="0"],
|
||||||
|
:root[data-show-pitch-accent-downstep-notation=true] .term-pitch-accent-disambiguation-list[data-expression-count="0"],
|
||||||
|
:root[data-show-pitch-accent-downstep-notation=true] .term-pitch-accent-disambiguation[data-type=reading] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-tag-list:not([data-count="0"]) {
|
||||||
|
margin-right: 0.375em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-special-tags>.pitches {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-character {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.term-pitch-accent-character[data-pitch='high']:before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
user-select: none;
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 0.1em;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 0;
|
||||||
|
border-top-width: 0.1em;
|
||||||
|
border-top-style: solid;
|
||||||
|
}
|
||||||
|
.term-pitch-accent-character[data-pitch='high'][data-pitch-next='low']:before {
|
||||||
|
right: -0.1em;
|
||||||
|
height: 0.4em;
|
||||||
|
border-right-width: 0.1em;
|
||||||
|
border-right-style: solid;
|
||||||
|
}
|
||||||
|
.term-pitch-accent-character[data-pitch='high'][data-pitch-next='low'] {
|
||||||
|
padding-right: 0.1em;
|
||||||
|
margin-right: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-position:before {
|
||||||
|
content: " [";
|
||||||
|
}
|
||||||
|
.term-pitch-accent-position:after {
|
||||||
|
content: "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
.term-pitch-accent-details {
|
||||||
|
display: inline-block;
|
||||||
|
height: 0;
|
||||||
|
padding: 0 0.25em;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
:root[data-show-pitch-accent-downstep-notation=false] .term-pitch-accent-characters {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-show-pitch-accent-position-notation=false] .term-pitch-accent-position {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[data-show-pitch-accent-graph=false] .term-pitch-accent-details {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pitch accent graph styles
|
||||||
|
*/
|
||||||
|
|
||||||
|
.term-pitch-accent-graph {
|
||||||
|
display: block;
|
||||||
|
height: 1.5em;
|
||||||
|
transform: translateY(-0.875em);
|
||||||
|
}
|
||||||
|
.term-pitch-accent-graph-line,
|
||||||
|
.term-pitch-accent-graph-line-tail {
|
||||||
|
fill: none;
|
||||||
|
stroke: #000000;
|
||||||
|
stroke-width: 5;
|
||||||
|
}
|
||||||
|
.term-pitch-accent-graph-line-tail {
|
||||||
|
stroke-dasharray: 5 5;
|
||||||
|
}
|
||||||
|
#term-pitch-accent-graph-dot {
|
||||||
|
fill: #000000;
|
||||||
|
stroke: #000000;
|
||||||
|
stroke-width: 5;
|
||||||
|
}
|
||||||
|
#term-pitch-accent-graph-dot-downstep {
|
||||||
|
fill: none;
|
||||||
|
stroke: #000000;
|
||||||
|
stroke-width: 5;
|
||||||
|
}
|
||||||
|
#term-pitch-accent-graph-dot-downstep>circle:last-of-type {
|
||||||
|
fill: #000000;
|
||||||
|
}
|
||||||
|
#term-pitch-accent-graph-triangle {
|
||||||
|
fill: none;
|
||||||
|
stroke: #000000;
|
||||||
|
stroke-width: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Kanji
|
* Kanji
|
||||||
|
@ -17,7 +17,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="term-special-tags"><div class="frequencies tag-list"></div></div>
|
<div class="term-special-tags"><div class="frequencies tag-list"></div></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="term-definition-container"><ol class="term-definition-list"></ol></div>
|
<div class="term-entry-body">
|
||||||
|
<div class="term-entry-body-section term-pitch-accent-container"><ol class="term-entry-body-section-content term-pitch-accent-group-list"></ol></div>
|
||||||
|
<div class="term-entry-body-section term-definition-container"><ol class="term-entry-body-section-content term-definition-list"></ol></div>
|
||||||
|
</div>
|
||||||
<pre class="debug-info"></pre>
|
<pre class="debug-info"></pre>
|
||||||
</div></template>
|
</div></template>
|
||||||
<template id="term-expression-template"><div class="term-expression"><span class="term-expression-text source-text"></span><div class="term-expression-details">
|
<template id="term-expression-template"><div class="term-expression"><span class="term-expression-text source-text"></span><div class="term-expression-details">
|
||||||
@ -34,6 +37,18 @@
|
|||||||
<template id="term-glossary-item-template"><li class="term-glossary-item"><span class="term-glossary-separator"> </span><span class="term-glossary"></span></li></template>
|
<template id="term-glossary-item-template"><li class="term-glossary-item"><span class="term-glossary-separator"> </span><span class="term-glossary"></span></li></template>
|
||||||
<template id="term-reason-template"><span class="term-reason"></span><span class="term-reason-separator"> </span></template>
|
<template id="term-reason-template"><span class="term-reason"></span><span class="term-reason-separator"> </span></template>
|
||||||
|
|
||||||
|
<template id="term-pitch-accent-static-template"><svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
||||||
|
<defs>
|
||||||
|
<g id="term-pitch-accent-graph-dot"><circle cx="0" cy="0" r="15" /></g>
|
||||||
|
<g id="term-pitch-accent-graph-dot-downstep"><circle cx="0" cy="0" r="15" /><circle cx="0" cy="0" r="5" /></g>
|
||||||
|
<g id="term-pitch-accent-graph-triangle"><path d="M0 13 L15 -13 L-15 -13 Z" /></g>
|
||||||
|
</defs>
|
||||||
|
</svg></template>
|
||||||
|
<template id="term-pitch-accent-group-template"><li class="term-pitch-accent-group"><span class="term-pitch-accent-group-tag-list tag-list"></span><ul class="term-pitch-accent-list"></ul></li></template>
|
||||||
|
<template id="term-pitch-accent-disambiguation-template"><span class="term-pitch-accent-disambiguation"></span></template>
|
||||||
|
<template id="term-pitch-accent-template"><li class="term-pitch-accent"><span class="term-pitch-accent-tag-list tag-list"></span><span class="term-pitch-accent-disambiguation-list"></span><span class="term-pitch-accent-characters"></span><span class="term-pitch-accent-position"></span><span class="term-pitch-accent-details"><svg class="term-pitch-accent-graph" xmlns="http://www.w3.org/2000/svg"><path class="term-pitch-accent-graph-line" /><path class="term-pitch-accent-graph-line-tail" /></svg></span></li></template>
|
||||||
|
<template id="term-pitch-accent-character-template"><span class="term-pitch-accent-character"><span class="term-pitch-accent-character-inner"></span></span></template>
|
||||||
|
|
||||||
<template id="kanji-entry-template"><div class="entry" data-type="kanji">
|
<template id="kanji-entry-template"><div class="entry" data-type="kanji">
|
||||||
<div class="entry-header1">
|
<div class="entry-header1">
|
||||||
<div class="entry-header2">
|
<div class="entry-header2">
|
||||||
|
@ -132,6 +132,30 @@ function parseUrl(url) {
|
|||||||
return {baseUrl, queryParams};
|
return {baseUrl, queryParams};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function areSetsEqual(set1, set2) {
|
||||||
|
if (set1.size !== set2.size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const value of set1) {
|
||||||
|
if (!set2.has(value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSetIntersection(set1, set2) {
|
||||||
|
const result = [];
|
||||||
|
for (const value of set1) {
|
||||||
|
if (set2.has(value)) {
|
||||||
|
result.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Async utilities
|
* Async utilities
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
class DisplayGenerator {
|
class DisplayGenerator {
|
||||||
constructor() {
|
constructor() {
|
||||||
this._templateHandler = null;
|
this._templateHandler = null;
|
||||||
|
this._termPitchAccentStaticTemplateIsSetup = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async prepare() {
|
async prepare() {
|
||||||
@ -37,17 +38,33 @@ class DisplayGenerator {
|
|||||||
|
|
||||||
const expressionsContainer = node.querySelector('.term-expression-list');
|
const expressionsContainer = node.querySelector('.term-expression-list');
|
||||||
const reasonsContainer = node.querySelector('.term-reasons');
|
const reasonsContainer = node.querySelector('.term-reasons');
|
||||||
|
const pitchesContainer = node.querySelector('.term-pitch-accent-group-list');
|
||||||
const frequenciesContainer = node.querySelector('.frequencies');
|
const frequenciesContainer = node.querySelector('.frequencies');
|
||||||
const definitionsContainer = node.querySelector('.term-definition-list');
|
const definitionsContainer = node.querySelector('.term-definition-list');
|
||||||
const debugInfoContainer = node.querySelector('.debug-info');
|
const debugInfoContainer = node.querySelector('.debug-info');
|
||||||
|
const bodyContainer = node.querySelector('.term-entry-body');
|
||||||
|
|
||||||
|
const pitches = DisplayGenerator._getPitchInfos(details);
|
||||||
|
const pitchCount = pitches.reduce((i, v) => i + v[1].length, 0);
|
||||||
|
|
||||||
const expressionMulti = Array.isArray(details.expressions);
|
const expressionMulti = Array.isArray(details.expressions);
|
||||||
const definitionMulti = Array.isArray(details.definitions);
|
const definitionMulti = Array.isArray(details.definitions);
|
||||||
|
const expressionCount = expressionMulti ? details.expressions.length : 1;
|
||||||
|
const definitionCount = definitionMulti ? details.definitions.length : 1;
|
||||||
|
const uniqueExpressionCount = Array.isArray(details.expression) ? new Set(details.expression).size : 1;
|
||||||
|
|
||||||
node.dataset.expressionMulti = `${expressionMulti}`;
|
node.dataset.expressionMulti = `${expressionMulti}`;
|
||||||
node.dataset.definitionMulti = `${definitionMulti}`;
|
node.dataset.definitionMulti = `${definitionMulti}`;
|
||||||
node.dataset.expressionCount = `${expressionMulti ? details.expressions.length : 1}`;
|
node.dataset.expressionCount = `${expressionCount}`;
|
||||||
node.dataset.definitionCount = `${definitionMulti ? details.definitions.length : 1}`;
|
node.dataset.definitionCount = `${definitionCount}`;
|
||||||
|
node.dataset.uniqueExpressionCount = `${uniqueExpressionCount}`;
|
||||||
|
node.dataset.pitchAccentDictionaryCount = `${pitches.length}`;
|
||||||
|
node.dataset.pitchAccentCount = `${pitchCount}`;
|
||||||
|
|
||||||
|
bodyContainer.dataset.sectionCount = `${
|
||||||
|
(definitionCount > 0 ? 1 : 0) +
|
||||||
|
(pitches.length > 0 ? 1 : 0)
|
||||||
|
}`;
|
||||||
|
|
||||||
const termTags = details.termTags;
|
const termTags = details.termTags;
|
||||||
let expressions = details.expressions;
|
let expressions = details.expressions;
|
||||||
@ -56,6 +73,7 @@ class DisplayGenerator {
|
|||||||
DisplayGenerator._appendMultiple(expressionsContainer, this.createTermExpression.bind(this), expressions, [[details, termTags]]);
|
DisplayGenerator._appendMultiple(expressionsContainer, this.createTermExpression.bind(this), expressions, [[details, termTags]]);
|
||||||
DisplayGenerator._appendMultiple(reasonsContainer, this.createTermReason.bind(this), details.reasons);
|
DisplayGenerator._appendMultiple(reasonsContainer, this.createTermReason.bind(this), details.reasons);
|
||||||
DisplayGenerator._appendMultiple(frequenciesContainer, this.createFrequencyTag.bind(this), details.frequencies);
|
DisplayGenerator._appendMultiple(frequenciesContainer, this.createFrequencyTag.bind(this), details.frequencies);
|
||||||
|
DisplayGenerator._appendMultiple(pitchesContainer, this.createPitches.bind(this), pitches);
|
||||||
DisplayGenerator._appendMultiple(definitionsContainer, this.createTermDefinitionItem.bind(this), details.definitions, [details]);
|
DisplayGenerator._appendMultiple(definitionsContainer, this.createTermDefinitionItem.bind(this), details.definitions, [details]);
|
||||||
|
|
||||||
if (debugInfoContainer !== null) {
|
if (debugInfoContainer !== null) {
|
||||||
@ -262,6 +280,133 @@ class DisplayGenerator {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createPitches(details) {
|
||||||
|
if (!this._termPitchAccentStaticTemplateIsSetup) {
|
||||||
|
this._termPitchAccentStaticTemplateIsSetup = true;
|
||||||
|
const t = this._templateHandler.instantiate('term-pitch-accent-static');
|
||||||
|
document.head.appendChild(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [dictionary, dictionaryPitches] = details;
|
||||||
|
|
||||||
|
const node = this._templateHandler.instantiate('term-pitch-accent-group');
|
||||||
|
node.dataset.dictionary = dictionary;
|
||||||
|
node.dataset.pitchesMulti = 'true';
|
||||||
|
node.dataset.pitchesCount = `${dictionaryPitches.length}`;
|
||||||
|
|
||||||
|
const tag = this.createTag({notes: '', name: dictionary, category: 'pitch-accent-dictionary'});
|
||||||
|
node.querySelector('.term-pitch-accent-group-tag-list').appendChild(tag);
|
||||||
|
|
||||||
|
const n = node.querySelector('.term-pitch-accent-list');
|
||||||
|
DisplayGenerator._appendMultiple(n, this.createPitch.bind(this), dictionaryPitches);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
createPitch(details) {
|
||||||
|
const {reading, position, tags, exclusiveExpressions, exclusiveReadings} = details;
|
||||||
|
const morae = jp.getKanaMorae(reading);
|
||||||
|
|
||||||
|
const node = this._templateHandler.instantiate('term-pitch-accent');
|
||||||
|
|
||||||
|
node.dataset.pitchAccentPosition = `${position}`;
|
||||||
|
node.dataset.tagCount = `${tags.length}`;
|
||||||
|
|
||||||
|
let n = node.querySelector('.term-pitch-accent-position');
|
||||||
|
n.textContent = `${position}`;
|
||||||
|
|
||||||
|
n = node.querySelector('.term-pitch-accent-tag-list');
|
||||||
|
DisplayGenerator._appendMultiple(n, this.createTag.bind(this), tags);
|
||||||
|
|
||||||
|
n = node.querySelector('.term-pitch-accent-disambiguation-list');
|
||||||
|
this.createPitchAccentDisambiguations(n, exclusiveExpressions, exclusiveReadings);
|
||||||
|
|
||||||
|
n = node.querySelector('.term-pitch-accent-characters');
|
||||||
|
for (let i = 0, ii = morae.length; i < ii; ++i) {
|
||||||
|
const mora = morae[i];
|
||||||
|
const highPitch = jp.isMoraPitchHigh(i, position);
|
||||||
|
const highPitchNext = jp.isMoraPitchHigh(i + 1, position);
|
||||||
|
|
||||||
|
const n1 = this._templateHandler.instantiate('term-pitch-accent-character');
|
||||||
|
const n2 = n1.querySelector('.term-pitch-accent-character-inner');
|
||||||
|
|
||||||
|
n1.dataset.position = `${i}`;
|
||||||
|
n1.dataset.pitch = highPitch ? 'high' : 'low';
|
||||||
|
n1.dataset.pitchNext = highPitchNext ? 'high' : 'low';
|
||||||
|
n2.textContent = mora;
|
||||||
|
|
||||||
|
n.appendChild(n1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (morae.length > 0) {
|
||||||
|
this.populatePitchGraph(node.querySelector('.term-pitch-accent-graph'), position, morae);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
createPitchAccentDisambiguations(container, exclusiveExpressions, exclusiveReadings) {
|
||||||
|
const templateName = 'term-pitch-accent-disambiguation';
|
||||||
|
for (const exclusiveExpression of exclusiveExpressions) {
|
||||||
|
const node = this._templateHandler.instantiate(templateName);
|
||||||
|
node.dataset.type = 'expression';
|
||||||
|
node.textContent = exclusiveExpression;
|
||||||
|
container.appendChild(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const exclusiveReading of exclusiveReadings) {
|
||||||
|
const node = this._templateHandler.instantiate(templateName);
|
||||||
|
node.dataset.type = 'reading';
|
||||||
|
node.textContent = exclusiveReading;
|
||||||
|
container.appendChild(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
container.dataset.multi = 'true';
|
||||||
|
container.dataset.count = `${exclusiveExpressions.length + exclusiveReadings.length}`;
|
||||||
|
container.dataset.expressionCount = `${exclusiveExpressions.length}`;
|
||||||
|
container.dataset.readingCount = `${exclusiveReadings.length}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
populatePitchGraph(svg, position, morae) {
|
||||||
|
const svgns = svg.getAttribute('xmlns');
|
||||||
|
const ii = morae.length;
|
||||||
|
svg.setAttribute('viewBox', `0 0 ${50 * (ii + 1)} 100`);
|
||||||
|
|
||||||
|
const pathPoints = [];
|
||||||
|
for (let i = 0; i < ii; ++i) {
|
||||||
|
const highPitch = jp.isMoraPitchHigh(i, position);
|
||||||
|
const highPitchNext = jp.isMoraPitchHigh(i + 1, position);
|
||||||
|
const graphic = (highPitch && !highPitchNext ? '#term-pitch-accent-graph-dot-downstep' : '#term-pitch-accent-graph-dot');
|
||||||
|
const x = `${i * 50 + 25}`;
|
||||||
|
const y = highPitch ? '25' : '75';
|
||||||
|
const use = document.createElementNS(svgns, 'use');
|
||||||
|
use.setAttribute('href', graphic);
|
||||||
|
use.setAttribute('x', x);
|
||||||
|
use.setAttribute('y', y);
|
||||||
|
svg.appendChild(use);
|
||||||
|
pathPoints.push(`${x} ${y}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = svg.querySelector('.term-pitch-accent-graph-line');
|
||||||
|
path.setAttribute('d', `M${pathPoints.join(' L')}`);
|
||||||
|
|
||||||
|
pathPoints.splice(0, ii - 1);
|
||||||
|
{
|
||||||
|
const highPitch = jp.isMoraPitchHigh(ii, position);
|
||||||
|
const x = `${ii * 50 + 25}`;
|
||||||
|
const y = highPitch ? '25' : '75';
|
||||||
|
const use = document.createElementNS(svgns, 'use');
|
||||||
|
use.setAttribute('href', '#term-pitch-accent-graph-triangle');
|
||||||
|
use.setAttribute('x', x);
|
||||||
|
use.setAttribute('y', y);
|
||||||
|
svg.appendChild(use);
|
||||||
|
pathPoints.push(`${x} ${y}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
path = svg.querySelector('.term-pitch-accent-graph-line-tail');
|
||||||
|
path.setAttribute('d', `M${pathPoints.join(' L')}`);
|
||||||
|
}
|
||||||
|
|
||||||
createFrequencyTag(details) {
|
createFrequencyTag(details) {
|
||||||
const node = this._templateHandler.instantiate('tag-frequency');
|
const node = this._templateHandler.instantiate('tag-frequency');
|
||||||
|
|
||||||
@ -301,22 +446,28 @@ class DisplayGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static _appendMultiple(container, createItem, detailsArray, fallback=[]) {
|
static _appendMultiple(container, createItem, detailsIterable, fallback=[]) {
|
||||||
if (container === null) { return 0; }
|
if (container === null) { return 0; }
|
||||||
|
|
||||||
const isArray = Array.isArray(detailsArray);
|
const multi = (
|
||||||
if (!isArray) { detailsArray = fallback; }
|
detailsIterable !== null &&
|
||||||
|
typeof detailsIterable === 'object' &&
|
||||||
|
typeof detailsIterable[Symbol.iterator] !== 'undefined'
|
||||||
|
);
|
||||||
|
if (!multi) { detailsIterable = fallback; }
|
||||||
|
|
||||||
container.dataset.multi = `${isArray}`;
|
let count = 0;
|
||||||
container.dataset.count = `${detailsArray.length}`;
|
for (const details of detailsIterable) {
|
||||||
|
|
||||||
for (const details of detailsArray) {
|
|
||||||
const item = createItem(details);
|
const item = createItem(details);
|
||||||
if (item === null) { continue; }
|
if (item === null) { continue; }
|
||||||
container.appendChild(item);
|
container.appendChild(item);
|
||||||
|
++count;
|
||||||
}
|
}
|
||||||
|
|
||||||
return detailsArray.length;
|
container.dataset.multi = `${multi}`;
|
||||||
|
container.dataset.count = `${count}`;
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static _appendFurigana(container, segments, addText) {
|
static _appendFurigana(container, segments, addText) {
|
||||||
@ -342,4 +493,79 @@ class DisplayGenerator {
|
|||||||
container.appendChild(document.createTextNode(parts[i]));
|
container.appendChild(document.createTextNode(parts[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static _getPitchInfos(definition) {
|
||||||
|
const results = new Map();
|
||||||
|
|
||||||
|
const allExpressions = new Set();
|
||||||
|
const allReadings = new Set();
|
||||||
|
const expressions = definition.expressions;
|
||||||
|
const sources = Array.isArray(expressions) ? expressions : [definition];
|
||||||
|
for (const {pitches: expressionPitches, expression} of sources) {
|
||||||
|
allExpressions.add(expression);
|
||||||
|
for (const {reading, pitches, dictionary} of expressionPitches) {
|
||||||
|
allReadings.add(reading);
|
||||||
|
let dictionaryResults = results.get(dictionary);
|
||||||
|
if (typeof dictionaryResults === 'undefined') {
|
||||||
|
dictionaryResults = [];
|
||||||
|
results.set(dictionary, dictionaryResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const {position, tags} of pitches) {
|
||||||
|
let pitchInfo = DisplayGenerator._findExistingPitchInfo(reading, position, tags, dictionaryResults);
|
||||||
|
if (pitchInfo === null) {
|
||||||
|
pitchInfo = {expressions: new Set(), reading, position, tags};
|
||||||
|
dictionaryResults.push(pitchInfo);
|
||||||
|
}
|
||||||
|
pitchInfo.expressions.add(expression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const dictionaryResults of results.values()) {
|
||||||
|
for (const result of dictionaryResults) {
|
||||||
|
const exclusiveExpressions = [];
|
||||||
|
const exclusiveReadings = [];
|
||||||
|
const resultExpressions = result.expressions;
|
||||||
|
if (!areSetsEqual(resultExpressions, allExpressions)) {
|
||||||
|
exclusiveExpressions.push(...getSetIntersection(resultExpressions, allExpressions));
|
||||||
|
}
|
||||||
|
if (allReadings.size > 1) {
|
||||||
|
exclusiveReadings.push(result.reading);
|
||||||
|
}
|
||||||
|
result.exclusiveExpressions = exclusiveExpressions;
|
||||||
|
result.exclusiveReadings = exclusiveReadings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...results.entries()];
|
||||||
|
}
|
||||||
|
|
||||||
|
static _findExistingPitchInfo(reading, position, tags, pitchInfoList) {
|
||||||
|
for (const pitchInfo of pitchInfoList) {
|
||||||
|
if (
|
||||||
|
pitchInfo.reading === reading &&
|
||||||
|
pitchInfo.position === position &&
|
||||||
|
DisplayGenerator._areTagListsEqual(pitchInfo.tags, tags)
|
||||||
|
) {
|
||||||
|
return pitchInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static _areTagListsEqual(tagList1, tagList2) {
|
||||||
|
const ii = tagList1.length;
|
||||||
|
if (tagList2.length !== ii) { return false; }
|
||||||
|
|
||||||
|
for (let i = 0; i < ii; ++i) {
|
||||||
|
const tag1 = tagList1[i];
|
||||||
|
const tag2 = tagList2[i];
|
||||||
|
if (tag1.name !== tag2.name || tag1.dictionary !== tag2.dictionary) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -385,6 +385,9 @@ class Display {
|
|||||||
data.audioEnabled = `${options.audio.enabled}`;
|
data.audioEnabled = `${options.audio.enabled}`;
|
||||||
data.compactGlossaries = `${options.general.compactGlossaries}`;
|
data.compactGlossaries = `${options.general.compactGlossaries}`;
|
||||||
data.enableSearchTags = `${options.scanning.enableSearchTags}`;
|
data.enableSearchTags = `${options.scanning.enableSearchTags}`;
|
||||||
|
data.showPitchAccentDownstepNotation = `${options.general.showPitchAccentDownstepNotation}`;
|
||||||
|
data.showPitchAccentPositionNotation = `${options.general.showPitchAccentPositionNotation}`;
|
||||||
|
data.showPitchAccentGraph = `${options.general.showPitchAccentGraph}`;
|
||||||
data.debug = `${options.general.debugInfo}`;
|
data.debug = `${options.general.debugInfo}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +64,8 @@ const jp = (() => {
|
|||||||
[0xffe0, 0xffee] // Currency markers
|
[0xffe0, 0xffee] // Currency markers
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const SMALL_KANA_SET = new Set(Array.from('ぁぃぅぇぉゃゅょゎァィゥェォャュョヮ'));
|
||||||
|
|
||||||
|
|
||||||
// Character code testing functions
|
// Character code testing functions
|
||||||
|
|
||||||
@ -112,6 +114,26 @@ const jp = (() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Mora functions
|
||||||
|
|
||||||
|
function isMoraPitchHigh(moraIndex, pitchAccentPosition) {
|
||||||
|
return pitchAccentPosition === 0 ? (moraIndex > 0) : (moraIndex < pitchAccentPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getKanaMorae(text) {
|
||||||
|
const morae = [];
|
||||||
|
let i;
|
||||||
|
for (const c of text) {
|
||||||
|
if (SMALL_KANA_SET.has(c) && (i = morae.length) > 0) {
|
||||||
|
morae[i - 1] += c;
|
||||||
|
} else {
|
||||||
|
morae.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return morae;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Exports
|
// Exports
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -119,6 +141,8 @@ const jp = (() => {
|
|||||||
isCodePointKana,
|
isCodePointKana,
|
||||||
isCodePointJapanese,
|
isCodePointJapanese,
|
||||||
isStringEntirelyKana,
|
isStringEntirelyKana,
|
||||||
isStringPartiallyJapanese
|
isStringPartiallyJapanese,
|
||||||
|
isMoraPitchHigh,
|
||||||
|
getKanaMorae
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
4
test/data/dictionaries/valid-dictionary1/tag_bank_3.json
Normal file
4
test/data/dictionaries/valid-dictionary1/tag_bank_3.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[
|
||||||
|
["ptag1", "pcategory1", 0, "ptag1 notes", 0],
|
||||||
|
["ptag2", "pcategory2", 0, "ptag2 notes", 0]
|
||||||
|
]
|
@ -1,5 +1,39 @@
|
|||||||
[
|
[
|
||||||
["打", "freq", 1],
|
["打", "freq", 1],
|
||||||
["打つ", "freq", 2],
|
["打つ", "freq", 2],
|
||||||
["打ち込む", "freq", 3]
|
["打ち込む", "freq", 3],
|
||||||
|
[
|
||||||
|
"打ち込む",
|
||||||
|
"pitch",
|
||||||
|
{
|
||||||
|
"reading": "うちこむ",
|
||||||
|
"pitches": [
|
||||||
|
{"position": 0},
|
||||||
|
{"position": 3}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"打ち込む",
|
||||||
|
"pitch",
|
||||||
|
{
|
||||||
|
"reading": "ぶちこむ",
|
||||||
|
"pitches": [
|
||||||
|
{"position": 0},
|
||||||
|
{"position": 3}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"お手前",
|
||||||
|
"pitch",
|
||||||
|
{
|
||||||
|
"reading": "おてまえ",
|
||||||
|
"pitches": [
|
||||||
|
{"position": 2, "tags": ["ptag1"]},
|
||||||
|
{"position": 2, "tags": ["ptag2"]},
|
||||||
|
{"position": 0, "tags": ["ptag2"]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
]
|
]
|
@ -231,8 +231,8 @@ async function testDatabase1() {
|
|||||||
true
|
true
|
||||||
);
|
);
|
||||||
vm.assert.deepStrictEqual(counts, {
|
vm.assert.deepStrictEqual(counts, {
|
||||||
counts: [{kanji: 2, kanjiMeta: 2, terms: 32, termMeta: 3, tagMeta: 12}],
|
counts: [{kanji: 2, kanjiMeta: 2, terms: 32, termMeta: 6, tagMeta: 14}],
|
||||||
total: {kanji: 2, kanjiMeta: 2, terms: 32, termMeta: 3, tagMeta: 12}
|
total: {kanji: 2, kanjiMeta: 2, terms: 32, termMeta: 6, tagMeta: 14}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Test find* functions
|
// Test find* functions
|
||||||
@ -648,9 +648,10 @@ async function testFindTermMetaBulk1(database, titles) {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
expectedResults: {
|
expectedResults: {
|
||||||
total: 1,
|
total: 3,
|
||||||
modes: [
|
modes: [
|
||||||
['freq', 1]
|
['freq', 1],
|
||||||
|
['pitch', 2]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -392,6 +392,59 @@ function testDistributeFuriganaInflected() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testIsMoraPitchHigh() {
|
||||||
|
const data = [
|
||||||
|
[[0, 0], false],
|
||||||
|
[[1, 0], true],
|
||||||
|
[[2, 0], true],
|
||||||
|
[[3, 0], true],
|
||||||
|
|
||||||
|
[[0, 1], true],
|
||||||
|
[[1, 1], false],
|
||||||
|
[[2, 1], false],
|
||||||
|
[[3, 1], false],
|
||||||
|
|
||||||
|
[[0, 2], true],
|
||||||
|
[[1, 2], true],
|
||||||
|
[[2, 2], false],
|
||||||
|
[[3, 2], false],
|
||||||
|
|
||||||
|
[[0, 3], true],
|
||||||
|
[[1, 3], true],
|
||||||
|
[[2, 3], true],
|
||||||
|
[[3, 3], false],
|
||||||
|
|
||||||
|
[[0, 4], true],
|
||||||
|
[[1, 4], true],
|
||||||
|
[[2, 4], true],
|
||||||
|
[[3, 4], true]
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const [[moraIndex, pitchAccentPosition], expected] of data) {
|
||||||
|
const actual = jp.isMoraPitchHigh(moraIndex, pitchAccentPosition);
|
||||||
|
assert.strictEqual(actual, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function testGetKanaMorae() {
|
||||||
|
const data = [
|
||||||
|
['かこ', ['か', 'こ']],
|
||||||
|
['かっこ', ['か', 'っ', 'こ']],
|
||||||
|
['カコ', ['カ', 'コ']],
|
||||||
|
['カッコ', ['カ', 'ッ', 'コ']],
|
||||||
|
['コート', ['コ', 'ー', 'ト']],
|
||||||
|
['ちゃんと', ['ちゃ', 'ん', 'と']],
|
||||||
|
['とうきょう', ['と', 'う', 'きょ', 'う']],
|
||||||
|
['ぎゅう', ['ぎゅ', 'う']],
|
||||||
|
['ディスコ', ['ディ', 'ス', 'コ']]
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const [text, expected] of data) {
|
||||||
|
const actual = jp.getKanaMorae(text);
|
||||||
|
vm.assert.deepStrictEqual(actual, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
testIsCodePointKanji();
|
testIsCodePointKanji();
|
||||||
@ -408,6 +461,8 @@ function main() {
|
|||||||
testConvertAlphabeticToKana();
|
testConvertAlphabeticToKana();
|
||||||
testDistributeFurigana();
|
testDistributeFurigana();
|
||||||
testDistributeFuriganaInflected();
|
testDistributeFuriganaInflected();
|
||||||
|
testIsMoraPitchHigh();
|
||||||
|
testGetKanaMorae();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user