Editor Field Descriptions (#1476)
* Add description input to fields dialog QLineEdit seems like the best option, as it saves space and motivates users to keep their descriptions concise. * Add setDescriptions to note initialization script Went for the extra function instead of including it in setFields to prevent potential add-on breakages. * Add tooltip next to field name if description is set * Refactor code according to suggestions Set default tooltip placement to right instead of bottom Use .get() for fld["description"] Fix tab order in fields dialog Swap out abbreviation "desc" for full length name to keep consistency * Update Protobuf and Rust for description Add description to notetypes.proto and schema11 Co-authored-by: RumovZ <RumovZ@users.noreply.github.com> * Fix tooltips not updating with description Remove redundant variable tooltipOptions Update previousTooltip within reactive function * Move LabelDescription out of LabelName Co-authored-by: Henrik Giesel <hgiesel@users.noreply.github.com> * Decrease icon size and fix alignment Co-Authored-By: Henrik Giesel <hengiesel@gmail.com> * the new key needs to be cleared from fields, not the notetype itself Co-authored-by: RumovZ <RumovZ@users.noreply.github.com> Co-authored-by: Henrik Giesel <hengiesel@gmail.com> Co-authored-by: Damien Elmes <gpg@ankiweb.net>
This commit is contained in:
parent
07f3f34bf5
commit
371f731e30
|
@ -3,6 +3,8 @@ fields-delete-field-from = Delete field from { $val }?
|
|||
fields-editing-font = Editing Font
|
||||
fields-field = Field:
|
||||
fields-field-name = Field name:
|
||||
fields-description = Description
|
||||
fields-description-placeholder = Tooltip to show next to the field's name in the editing screen
|
||||
fields-fields-for = Fields for { $val }
|
||||
fields-font = Font:
|
||||
fields-new-position-1 = New position (1...{ $val }):
|
||||
|
|
|
@ -68,6 +68,7 @@ message Notetype {
|
|||
bool rtl = 2;
|
||||
string font_name = 3;
|
||||
uint32 font_size = 4;
|
||||
string description = 5;
|
||||
|
||||
bytes other = 255;
|
||||
}
|
||||
|
|
|
@ -460,6 +460,10 @@ noteEditorPromise.then(noteEditor => noteEditor.toolbar.toolbar.appendGroup({{
|
|||
(fld, self.mw.col.media.escape_media_filenames(val))
|
||||
for fld, val in self.note.items()
|
||||
]
|
||||
|
||||
flds = self.note.note_type()["flds"]
|
||||
descriptions = [fld.get("description", "") for fld in flds]
|
||||
|
||||
self.widget.show()
|
||||
|
||||
note_fields_status = self.note.fields_check()
|
||||
|
@ -478,8 +482,9 @@ noteEditorPromise.then(noteEditor => noteEditor.toolbar.toolbar.appendGroup({{
|
|||
text_color = self.mw.pm.profile.get("lastTextColor", "#00f")
|
||||
highlight_color = self.mw.pm.profile.get("lastHighlightColor", "#00f")
|
||||
|
||||
js = "setFields({}); setFonts({}); focusField({}); setNoteId({}); setColorButtons({}); setTags({}); ".format(
|
||||
js = "setFields({}); setDescriptions({}); setFonts({}); focusField({}); setNoteId({}); setColorButtons({}); setTags({}); ".format(
|
||||
json.dumps(data),
|
||||
json.dumps(descriptions),
|
||||
json.dumps(self.fonts()),
|
||||
json.dumps(focusTo),
|
||||
json.dumps(self.note.id),
|
||||
|
|
|
@ -214,6 +214,7 @@ class FieldDialog(QDialog):
|
|||
f.fontSize.setValue(fld["size"])
|
||||
f.sortField.setChecked(self.model["sortf"] == fld["ord"])
|
||||
f.rtl.setChecked(fld["rtl"])
|
||||
f.fieldDescription.setText(fld.get("description", ""))
|
||||
|
||||
def saveField(self) -> None:
|
||||
# not initialized yet?
|
||||
|
@ -234,6 +235,10 @@ class FieldDialog(QDialog):
|
|||
if fld["rtl"] != rtl:
|
||||
fld["rtl"] = rtl
|
||||
self.change_tracker.mark_basic()
|
||||
desc = f.fieldDescription.text()
|
||||
if fld.get("description", "") != desc:
|
||||
fld["description"] = desc
|
||||
self.change_tracker.mark_basic()
|
||||
|
||||
def reject(self) -> None:
|
||||
if self.change_tracker.changed():
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>483</width>
|
||||
<height>352</height>
|
||||
<width>586</width>
|
||||
<height>376</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -84,17 +84,21 @@
|
|||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="_2">
|
||||
<item row="0" column="1">
|
||||
<widget class="QFontComboBox" name="fontFamily">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>25</height>
|
||||
</size>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_font">
|
||||
<property name="text">
|
||||
<string>fields_editing_font</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="rtl">
|
||||
<property name="text">
|
||||
<string>fields_reverse_text_direction_rtl</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QSpinBox" name="fontSize">
|
||||
<property name="minimum">
|
||||
<number>5</number>
|
||||
|
@ -104,31 +108,47 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_sort">
|
||||
<property name="text">
|
||||
<string>actions_options</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="2" column="1">
|
||||
<widget class="QRadioButton" name="sortField">
|
||||
<property name="text">
|
||||
<string>fields_sort_by_this_field_in_the</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="rtl">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_description">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>fields_reverse_text_direction_rtl</string>
|
||||
<string>fields_description</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>fields_editing_font</string>
|
||||
<item row="1" column="1">
|
||||
<widget class="QFontComboBox" name="fontFamily">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>25</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="fieldDescription">
|
||||
<property name="placeholderText">
|
||||
<string>fields_description_placeholder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -152,11 +172,11 @@
|
|||
<tabstop>fieldDelete</tabstop>
|
||||
<tabstop>fieldRename</tabstop>
|
||||
<tabstop>fieldPosition</tabstop>
|
||||
<tabstop>fieldDescription</tabstop>
|
||||
<tabstop>fontFamily</tabstop>
|
||||
<tabstop>fontSize</tabstop>
|
||||
<tabstop>sortField</tabstop>
|
||||
<tabstop>rtl</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="icons.qrc"/>
|
||||
|
|
|
@ -44,6 +44,7 @@ impl NoteField {
|
|||
rtl: false,
|
||||
font_name: "Arial".into(),
|
||||
font_size: 20,
|
||||
description: "".into(),
|
||||
other: vec![],
|
||||
},
|
||||
}
|
||||
|
|
|
@ -165,6 +165,13 @@ impl From<Notetype> for NotetypeSchema11 {
|
|||
}
|
||||
}
|
||||
|
||||
fn clear_other_field_duplicates(other: &mut HashMap<String, Value>) {
|
||||
// see `clear_other_duplicates()` in `deckconfig/schema11.rs`
|
||||
for key in &["description"] {
|
||||
other.remove(*key);
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CardRequirementSchema11> for CardRequirement {
|
||||
fn from(r: CardRequirementSchema11) -> Self {
|
||||
CardRequirement {
|
||||
|
@ -203,6 +210,13 @@ pub struct NoteFieldSchema11 {
|
|||
pub(crate) rtl: bool,
|
||||
pub(crate) font: String,
|
||||
pub(crate) size: u16,
|
||||
|
||||
// This was not in schema 11, but needs to be listed here so that the setting is not lost
|
||||
// on downgrade/upgrade.
|
||||
// NOTE: if adding new ones, make sure to update clear_other_field_duplicates()
|
||||
#[serde(default, deserialize_with = "default_on_invalid")]
|
||||
pub(crate) description: String,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub(crate) other: HashMap<String, Value>,
|
||||
}
|
||||
|
@ -216,6 +230,7 @@ impl Default for NoteFieldSchema11 {
|
|||
rtl: false,
|
||||
font: "Arial".to_string(),
|
||||
size: 20,
|
||||
description: String::new(),
|
||||
other: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -231,6 +246,7 @@ impl From<NoteFieldSchema11> for NoteField {
|
|||
rtl: f.rtl,
|
||||
font_name: f.font,
|
||||
font_size: f.size as u32,
|
||||
description: f.description,
|
||||
other: other_to_bytes(&f.other),
|
||||
},
|
||||
}
|
||||
|
@ -242,6 +258,8 @@ impl From<NoteFieldSchema11> for NoteField {
|
|||
impl From<NoteField> for NoteFieldSchema11 {
|
||||
fn from(p: NoteField) -> Self {
|
||||
let conf = p.config;
|
||||
let mut other = bytes_to_other(&conf.other);
|
||||
clear_other_field_duplicates(&mut other);
|
||||
NoteFieldSchema11 {
|
||||
name: p.name,
|
||||
ord: p.ord.map(|o| o as u16),
|
||||
|
@ -249,7 +267,8 @@ impl From<NoteField> for NoteFieldSchema11 {
|
|||
rtl: conf.rtl,
|
||||
font: conf.font_name,
|
||||
size: conf.font_size as u16,
|
||||
other: bytes_to_other(&conf.other),
|
||||
description: conf.description,
|
||||
other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
export let hideDelay = 0;
|
||||
|
||||
let tooltipObject: Tooltip;
|
||||
|
||||
function createTooltip(element: HTMLElement): void {
|
||||
element.title = tooltip;
|
||||
tooltipObject = new Tooltip(element, {
|
||||
|
@ -39,6 +38,15 @@
|
|||
}
|
||||
|
||||
onDestroy(() => tooltipObject?.dispose());
|
||||
|
||||
// hack to update field description tooltips
|
||||
let previousTooltip: string = tooltip;
|
||||
$: if (tooltip !== previousTooltip) {
|
||||
previousTooltip = tooltip;
|
||||
let element: HTMLElement = tooltipObject["_element"];
|
||||
tooltipObject.dispose();
|
||||
createTooltip(element);
|
||||
}
|
||||
</script>
|
||||
|
||||
<slot {createTooltip} {tooltipObject} />
|
||||
|
|
|
@ -9,6 +9,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
|
||||
export interface FieldData {
|
||||
name: string;
|
||||
description: string;
|
||||
fontFamily: string;
|
||||
fontSize: number;
|
||||
direction: "ltr" | "rtl";
|
||||
|
@ -29,6 +30,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
<script lang="ts">
|
||||
import EditingArea from "./EditingArea.svelte";
|
||||
import LabelContainer from "./LabelContainer.svelte";
|
||||
import LabelDescription from "./LabelDescription.svelte";
|
||||
import LabelName from "./LabelName.svelte";
|
||||
import FieldState from "./FieldState.svelte";
|
||||
|
||||
|
@ -74,7 +76,14 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
on:click={() => editingArea.focus?.()}
|
||||
>
|
||||
<LabelContainer>
|
||||
<LabelName>{field.name}</LabelName>
|
||||
<span>
|
||||
<LabelName>
|
||||
{field.name}
|
||||
</LabelName>
|
||||
{#if field.description}
|
||||
<LabelDescription description={field.description} />
|
||||
{/if}
|
||||
</span>
|
||||
<FieldState><slot name="field-state" /></FieldState>
|
||||
</LabelContainer>
|
||||
<EditingArea
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<!--
|
||||
Copyright: Ankitects Pty Ltd and contributors
|
||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { descriptionIcon } from "./icons";
|
||||
import WithTooltip from "../components/WithTooltip.svelte";
|
||||
import Badge from "../components/Badge.svelte";
|
||||
|
||||
export let description: string;
|
||||
</script>
|
||||
|
||||
<span>
|
||||
<WithTooltip
|
||||
tooltip={description}
|
||||
showDelay={250}
|
||||
offset={[0, 20]}
|
||||
placement="right"
|
||||
let:createTooltip
|
||||
>
|
||||
<Badge
|
||||
--icon-align="sub"
|
||||
iconSize={65}
|
||||
on:mount={(event) => createTooltip(event.detail.span)}
|
||||
>
|
||||
{@html descriptionIcon}
|
||||
</Badge>
|
||||
</WithTooltip>
|
||||
</span>
|
||||
|
||||
<style lang="scss">
|
||||
span {
|
||||
opacity: 0.4;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -2,7 +2,10 @@
|
|||
Copyright: Ankitects Pty Ltd and contributors
|
||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
-->
|
||||
<span class="label-name"><slot /></span>
|
||||
|
||||
<span class="label-name">
|
||||
<slot />
|
||||
</span>
|
||||
|
||||
<style lang="scss">
|
||||
.label-name {
|
||||
|
|
|
@ -115,6 +115,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
fieldNames = newFieldNames;
|
||||
}
|
||||
|
||||
let fieldDescriptions: string[] = [];
|
||||
export function setDescriptions(fs: string[]): void {
|
||||
fieldDescriptions = fs;
|
||||
}
|
||||
|
||||
let fonts: [string, number, boolean][] = [];
|
||||
let richTextsHidden: boolean[] = [];
|
||||
let plainTextsHidden: boolean[] = [];
|
||||
|
@ -173,6 +178,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
|
||||
$: fieldsData = fieldNames.map((name, index) => ({
|
||||
name,
|
||||
description: fieldDescriptions[index],
|
||||
fontFamily: quoteFontFamily(fonts[index][0]),
|
||||
fontSize: fonts[index][1],
|
||||
direction: fonts[index][2] ? "rtl" : "ltr",
|
||||
|
|
|
@ -32,6 +32,8 @@ export { default as micIcon } from "bootstrap-icons/icons/mic.svg";
|
|||
export { default as ellipseIcon } from "@mdi/svg/svg/contain.svg";
|
||||
export { default as functionIcon } from "@mdi/svg/svg/function-variant.svg";
|
||||
|
||||
export { default as descriptionIcon } from "bootstrap-icons/icons/info-circle.svg";
|
||||
|
||||
export { default as tagIcon } from "@mdi/svg/svg/tag.svg";
|
||||
export { default as addTagIcon } from "@mdi/svg/svg/tag-plus.svg";
|
||||
export { default as dotsIcon } from "@mdi/svg/svg/dots-vertical.svg";
|
||||
|
|
|
@ -85,6 +85,7 @@ async function setupNoteEditor(): Promise<NoteEditorAPI> {
|
|||
|
||||
Object.assign(globalThis, {
|
||||
setFields: noteEditor.setFields,
|
||||
setDescriptions: noteEditor.setDescriptions,
|
||||
setFonts: noteEditor.setFonts,
|
||||
focusField: noteEditor.focusField,
|
||||
setColorButtons: noteEditor.setColorButtons,
|
||||
|
|
Loading…
Reference in New Issue