diff --git a/README.md b/README.md
index 585e9ff..4785900 100644
--- a/README.md
+++ b/README.md
@@ -2630,6 +2630,134 @@ corresponding to when the API was available for use.
```
+#### `modelTemplateRename`
+
+* Renames a template in an existing model.
+
+
+ Sample request:
+
+ ```json
+ {
+ "action": "modelTemplateRename",
+ "version": 6,
+ "params": {
+ "modelName": "Basic",
+ "oldTemplateName": "Card 1",
+ "newTemplateName": "Card 1 renamed"
+ }
+ }
+ ```
+
+
+
+ Sample result:
+
+ ```json
+ {
+ "result": null,
+ "error": null
+ }
+ ```
+
+
+#### `modelTemplateReposition`
+
+* Repositions a template in an existing model.
+
+ The value of `index` starts at 0. For example, an index of `0` puts the template in the first position, and an index of `2` puts the template in the third position.
+
+
+ Sample request:
+
+ ```json
+ {
+ "action": "modelTemplateRemove",
+ "version": 6,
+ "params": {
+ "modelName": "Basic",
+ "templateName": "Card 1",
+ "index": 1
+ }
+ }
+ ```
+
+
+
+ Sample result:
+
+ ```json
+ {
+ "result": null,
+ "error": null
+ }
+ ```
+
+
+#### `modelTemplateAdd`
+
+* Adds a template to an existing model by name. If you want to update an existing template, use `updateModelTemplates`.
+
+
+ Sample request:
+
+ ```json
+ {
+ "action": "modelTemplateAdd",
+ "version": 6,
+ "params": {
+ "modelName": "Basic",
+ "template": {
+ "Name": "Card 3",
+ "Front": "Front html {{Field1}}",
+ "Back": "Back html {{Field2}}"
+ }
+ }
+ }
+ ```
+
+
+
+ Sample result:
+
+ ```json
+ {
+ "result": null,
+ "error": null
+ }
+ ```
+
+
+#### `modelTemplateRemove`
+
+* Removes a template from an existing model.
+
+
+ Sample request:
+
+ ```json
+ {
+ "action": "modelTemplateRemove",
+ "version": 6,
+ "params": {
+ "modelName": "Basic",
+ "templateName": "Card 1"
+ }
+ }
+ ```
+
+
+
+ Sample result:
+
+ ```json
+ {
+ "result": null,
+ "error": null
+ }
+ ```
+
+
#### `modelFieldRename`
* Rename the field name of a given model.
diff --git a/plugin/__init__.py b/plugin/__init__.py
index eaefc32..a30fca0 100644
--- a/plugin/__init__.py
+++ b/plugin/__init__.py
@@ -196,15 +196,20 @@ class AnkiConnect:
return model
- def getField(self, modelName, fieldName):
- model = self.getModel(modelName)
-
+ def getField(self, model, fieldName):
fieldMap = self.collection().models.fieldMap(model)
if fieldName not in fieldMap:
- raise Exception('field was not found in {}: {}'.format(modelName, fieldName))
+ raise Exception('field was not found in {}: {}'.format(model['name'], fieldName))
return fieldMap[fieldName][1]
+ def getTemplate(self, model, templateName):
+ for ankiTemplate in model['tmpls']:
+ if ankiTemplate['name'] == templateName:
+ return ankiTemplate
+ raise Exception('template was not found in {}: {}'.format(model['name'], templateName))
+
+
def startEditing(self):
self.window().requireReset()
@@ -1268,11 +1273,65 @@ class AnkiConnect:
return updatedModels
+ @util.api()
+ def modelTemplateRename(self, modelName, oldTemplateName, newTemplateName):
+ mm = self.collection().models
+ model = self.getModel(modelName)
+ ankiTemplate = self.getTemplate(model, oldTemplateName)
+
+ ankiTemplate['name'] = newTemplateName
+ self.save_model(mm, model)
+
+
+ @util.api()
+ def modelTemplateReposition(self, modelName, templateName, index):
+ mm = self.collection().models
+ model = self.getModel(modelName)
+ ankiTemplate = self.getTemplate(model, templateName)
+
+ mm.reposition_template(model, ankiTemplate, index)
+ self.save_model(mm, model)
+
+
+ @util.api()
+ def modelTemplateAdd(self, modelName, template):
+ # "Name", "Front", "Back" borrows from `createModel`
+ mm = self.collection().models
+ model = self.getModel(modelName)
+ name = template['Name']
+ qfmt = template['Front']
+ afmt = template['Back']
+
+ # updates the template if it already exists
+ for ankiTemplate in model['tmpls']:
+ if ankiTemplate['name'] == name:
+ ankiTemplate['qfmt'] = qfmt
+ ankiTemplate['afmt'] = afmt
+ return
+
+ ankiTemplate = mm.new_template(name)
+ ankiTemplate['qfmt'] = qfmt
+ ankiTemplate['afmt'] = afmt
+ mm.add_template(model, ankiTemplate)
+
+ self.save_model(mm, model)
+
+
+ @util.api()
+ def modelTemplateRemove(self, modelName, templateName):
+ mm = self.collection().models
+ model = self.getModel(modelName)
+ ankiTemplate = self.getTemplate(model, templateName)
+
+ mm.remove_template(model, ankiTemplate)
+ self.save_model(mm, model)
+
+
@util.api()
def modelFieldRename(self, modelName, oldFieldName, newFieldName):
mm = self.collection().models
model = self.getModel(modelName)
- field = self.getField(modelName, oldFieldName)
+ field = self.getField(model, oldFieldName)
mm.renameField(model, field, newFieldName)
@@ -1283,7 +1342,7 @@ class AnkiConnect:
def modelFieldReposition(self, modelName, fieldName, index):
mm = self.collection().models
model = self.getModel(modelName)
- field = self.getField(modelName, fieldName)
+ field = self.getField(model, fieldName)
mm.repositionField(model, field, index)
@@ -1314,7 +1373,7 @@ class AnkiConnect:
def modelFieldRemove(self, modelName, fieldName):
mm = self.collection().models
model = self.getModel(modelName)
- field = self.getField(modelName, fieldName)
+ field = self.getField(model, fieldName)
mm.removeField(model, field)
@@ -1325,7 +1384,7 @@ class AnkiConnect:
def modelFieldSetFont(self, modelName, fieldName, font):
mm = self.collection().models
model = self.getModel(modelName)
- field = self.getField(modelName, fieldName)
+ field = self.getField(model, fieldName)
if not isinstance(font, str):
raise Exception('font should be a string: {}'.format(font))
@@ -1339,7 +1398,7 @@ class AnkiConnect:
def modelFieldSetFontSize(self, modelName, fieldName, fontSize):
mm = self.collection().models
model = self.getModel(modelName)
- field = self.getField(modelName, fieldName)
+ field = self.getField(model, fieldName)
if not isinstance(fontSize, int):
raise Exception('fontSize should be an integer: {}'.format(fontSize))
@@ -1353,7 +1412,7 @@ class AnkiConnect:
def modelFieldSetDescription(self, modelName, fieldName, description):
mm = self.collection().models
model = self.getModel(modelName)
- field = self.getField(modelName, fieldName)
+ field = self.getField(model, fieldName)
if not isinstance(description, str):
raise Exception('description should be a string: {}'.format(description))
diff --git a/tests/test_models.py b/tests/test_models.py
index bf8aa97..1cda36a 100755
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -132,6 +132,58 @@ def test_findAndReplaceInModels(setup):
}
+class TestModelTemplates:
+ def test_modelTemplateRename(self, setup):
+ ac.modelTemplateRename(
+ modelName="test_model",
+ oldTemplateName="Card 1",
+ newTemplateName="Card 1 Renamed",
+ )
+
+ result = ac.modelTemplates(modelName="test_model")
+ assert result == {
+ "Card 1 Renamed": {"Front": "{{field1}}", "Back": "{{field2}}"},
+ "Card 2": {"Front": "{{field2}}", "Back": "{{field1}}"}
+ }
+
+ def test_modelTemplateReposition(self, setup):
+ # There currently isn't a way to test for order, so this is just a
+ # smoke test for now
+ ac.modelTemplateReposition(
+ modelName="test_model",
+ templateName="Card 1",
+ index=1,
+ )
+
+ def test_modelTemplateAdd(self, setup):
+ ac.modelTemplateAdd(
+ modelName="test_model",
+ template={
+ "Name": "Card 3",
+ "Front": "{{field1}} Card 3",
+ "Back": "{{field2}}",
+ }
+ )
+
+ result = ac.modelTemplates(modelName="test_model")
+ assert result == {
+ "Card 1": {"Front": "{{field1}}", "Back": "{{field2}}"},
+ "Card 2": {"Front": "{{field2}}", "Back": "{{field1}}"},
+ "Card 3": {"Front": "{{field1}} Card 3", "Back": "{{field2}}"},
+ }
+
+ def test_modelTemplateRemove(self, setup):
+ ac.modelTemplateRemove(
+ modelName="test_model",
+ templateName="Card 2"
+ )
+
+ result = ac.modelTemplates(modelName="test_model")
+ assert result == {
+ "Card 1": {"Front": "{{field1}}", "Back": "{{field2}}"},
+ }
+
+
class TestModelFieldNames:
def test_modelFieldRename(self, setup):
ac.modelFieldRename(