Hi Anki community!
The issue I faced was that I had multiple fields for a single purpose. Creating the individual notes was kind of cumbersome and it was easy to lose overview on each individual note.
My project was to consolidate these multiple fields and append their values to the card using javascript. In addition to that, I wanted a code that could handle more pieces of information (entities) in a dynamic manner. The output should be presented in a way that adjusts dynamically and has a nice structured panel look to it.
Narrow view:
Broad view:
In my case I have 3 different fields for the example sentence + 1 field for audio:
1x sentence in target language
1x phonetic transcription of the sentence
1x translation of the sentence.
1x audio
The javascript allows me to have multiple example sentences. Before that I was restricted to only one example sentence.
I chose a single column structure for the input value that uses double colons “::” as a delimiter for the headline. If the input should have nested objects then slash “/” is used for this purpose.
You can define your key values in the first line, separating the keys using double colons “::” as delimiter:
ids::target::phonetic::native::audio
(As an object with nested value, it could look like this:
ids::sentence/target::sentence/phonetic::sentence/native::audio )
The header defines the structure of your input. In this case I have 5 rows per entity.:
(1) ids, (2) target, (3) phonetic, (4) native, (5) audio
Newline (’\n’, break) is used as delimiter within the entity.
Numbers followed by period (1., 2., 3., aso.) are used as delimiter between the separate entities.
The complete input value looks like this in my case:
'ids::target::phonetic::native::audio
-
example
FIRST Target SNTNC
FIRST Phonetic SNTNC
FIRST Native SNTNC
first audio file -
example
SECOND Target SNTNC
SECOND Phonetic SNTNC
SECOND Native SNTNC -
example
THIRD Target SNTNC
THIRD Phonetic SNTNC
THIRD Native SNTNC
third audio file’
The issues that haven’t been solved yet:
I have not manged yet to include the audio files dynamically as Anki responds with error messages as soon as I try to create a code like: ‘[sound:’ + list[i][Object.keys(list[0])[4]] + ‘]’
I also haven’t figured out how to hide empty ‘undefined’ audio values.
Initially, I planned to have the code detect dynamically if there are nested objects and act accordingly but I can’t figure out how to make it work.
Instead of showing the audio symbol on each panel, I would prefer to have a different background color of the panel indicating that this example sentence provides audio on click or on hover.
I’m still researching on the topic of dynamic identifiers in HTML and CSS to make it easier to adjust the individual panels.
The solution so far:
The field name in my case is: {{example}}
HTML code (on front or back as needed):
<div class="wrapper" id="EXAMPLE"></div>
CSS code
You have to provide the CSS code for the snippets of information on each panel.
The key names defined in the header are the class names in CSS.
<style>
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
grid-auto-rows: minmax(120px, auto);
justify-content: center;
grid-column-gap: 6px;
grid-row-gap: 6px;
padding: 2px 0;
background-color: floralwhite;
}
.panel {
background-color: snow;
border: 2px solid teal;
padding: 1rem;
}
.target {
color: green;
}
.phonetic {
color: Crimson;
}
.native {
color: SlateBlue;
}
</style>
Javascript code
I have very basic knowledge of javascript, so this is the best I could come up with:
<script src='_jquery.js'></script>
<script>
// convert an HTML fragment to plain text
var tempDiv = document.createElement('div');
tempDiv.innerHTML = '{{example}}';
document.documentElement.appendChild(tempDiv);
var singleColumnCSV = tempDiv.innerText;
document.documentElement.removeChild(tempDiv);
var pipeSeparatedValues = singleColumnCSV.replace(/\s\n|\n/g, "|");
var removePipesTwoOrMore = pipeSeparatedValues.replace(/(\|)\1+/g, "|");
var removeSuperSpace = removePipesTwoOrMore.replace(/(?<=\|)\s(?=\d\.|$)/g,"");
var createNewArray = removeSuperSpace.match(/(^[^|]+)|(\b\d+\.+(.+?)(?=\s*\|\b\d+\.|\s*$))/g );
//source:
//https://stackoverflow.com/questions/44178371/converting-csv-to-nested-json-in-javascript/44179597
// PSV = "Pipe Separated Values"
var PSV = createNewArray
var attrs = PSV.splice(0,1);
var result = PSV.map(function(row) {
var obj = {};
// use PIPE '|' as delimiter
var rowData = row.split('|');
// use 2 colons '::' as delimiter
attrs[0].split('::').forEach(function(val, idx) {
obj = constructObj(val, obj, rowData[idx]);
});
return obj;
})
function constructObj(str, parentObj, data) {
if(str.split('/').length === 1) {
parentObj[str] = data;
return parentObj;
}
var curKey = str.split('/')[0];
if(!parentObj[curKey])
parentObj[curKey] = {};
parentObj[curKey] = constructObj(str.split('/').slice(1).join('/'),
parentObj[curKey], data);
return parentObj;
}
var list = result
var html = '';
// Get id and print
for (var i = 0, l = list.length; i < l; i++) {
$('#EXAMPLE')
.append('<div class="panel">'
+'<div>'
+ list[i][Object.keys(list[0])[0]] + '</div>'
+'<div class="'+ [Object.keys(list[0])[1]] + '">'
+ list[i][Object.keys(list[0])[1]] + '</div>'
+'<div class="'+ [Object.keys(list[0])[2]] + '">'
+ list[i][Object.keys(list[0])[2]] + '</div>'
+'<div class="'+ [Object.keys(list[0])[3]] + '">'
+ list[i][Object.keys(list[0])[3]] + '</div>'
// audio file:
+'<div class="'+ [Object.keys(list[0])[4]] + '">'
+ list[i][Object.keys(list[0])[4]]
+ '</div>'
+'</div>');
}
</script>