mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
Fix IO groups breaking upon editing (#2766)
* Fix IO groups breaking upon editing * Emit change signal after group/ungroup
This commit is contained in:
parent
9740393d72
commit
14940a617b
5 changed files with 35 additions and 14 deletions
|
@ -59,11 +59,15 @@ message GetImageOcclusionNoteResponse {
|
||||||
string value = 2;
|
string value = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ImageOcclusion {
|
message ImageOcclusionShape {
|
||||||
string shape = 1;
|
string shape = 1;
|
||||||
repeated ImageOcclusionProperty properties = 2;
|
repeated ImageOcclusionProperty properties = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ImageOcclusion {
|
||||||
|
repeated ImageOcclusionShape shapes = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message ImageOcclusionNote {
|
message ImageOcclusionNote {
|
||||||
bytes image_data = 1;
|
bytes image_data = 1;
|
||||||
repeated ImageOcclusion occlusions = 2;
|
repeated ImageOcclusion occlusions = 2;
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use anki_proto::image_occlusion::get_image_occlusion_note_response::ImageOcclusion;
|
use anki_proto::image_occlusion::get_image_occlusion_note_response::ImageOcclusion;
|
||||||
|
use anki_proto::image_occlusion::get_image_occlusion_note_response::ImageOcclusionShape;
|
||||||
use htmlescape::encode_attribute;
|
use htmlescape::encode_attribute;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use nom::branch::alt;
|
use nom::branch::alt;
|
||||||
|
@ -317,14 +319,20 @@ fn render_image_occlusion(text: &str, question_side: bool, active: bool, ordinal
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_image_occlusions(text: &str) -> Vec<ImageOcclusion> {
|
pub fn parse_image_occlusions(text: &str) -> Vec<ImageOcclusion> {
|
||||||
parse_text_with_clozes(text)
|
let mut occlusions: HashMap<u16, Vec<ImageOcclusionShape>> = HashMap::new();
|
||||||
.iter()
|
for node in parse_text_with_clozes(text) {
|
||||||
.filter_map(|node| match node {
|
if let TextOrCloze::Cloze(cloze) = node {
|
||||||
TextOrCloze::Cloze(cloze) if cloze.image_occlusion().is_some() => {
|
if cloze.image_occlusion().is_some() {
|
||||||
parse_image_cloze(cloze.image_occlusion().unwrap())
|
if let Some(shape) = parse_image_cloze(cloze.image_occlusion().unwrap()) {
|
||||||
|
occlusions.entry(cloze.ordinal).or_default().push(shape);
|
||||||
}
|
}
|
||||||
_ => None,
|
}
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
occlusions
|
||||||
|
.values()
|
||||||
|
.map(|v| ImageOcclusion { shapes: v.to_vec() })
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use anki_proto::image_occlusion::get_image_occlusion_note_response::ImageOcclusion;
|
|
||||||
use anki_proto::image_occlusion::get_image_occlusion_note_response::ImageOcclusionProperty;
|
use anki_proto::image_occlusion::get_image_occlusion_note_response::ImageOcclusionProperty;
|
||||||
|
use anki_proto::image_occlusion::get_image_occlusion_note_response::ImageOcclusionShape;
|
||||||
use htmlescape::encode_attribute;
|
use htmlescape::encode_attribute;
|
||||||
use nom::bytes::complete::escaped;
|
use nom::bytes::complete::escaped;
|
||||||
use nom::bytes::complete::is_not;
|
use nom::bytes::complete::is_not;
|
||||||
|
@ -18,7 +18,7 @@ fn unescape(text: &str) -> String {
|
||||||
text.replace("\\:", ":")
|
text.replace("\\:", ":")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_image_cloze(text: &str) -> Option<ImageOcclusion> {
|
pub fn parse_image_cloze(text: &str) -> Option<ImageOcclusionShape> {
|
||||||
if let Some((shape, _)) = text.split_once(':') {
|
if let Some((shape, _)) = text.split_once(':') {
|
||||||
let mut properties = vec![];
|
let mut properties = vec![];
|
||||||
let mut remaining = &text[shape.len()..];
|
let mut remaining = &text[shape.len()..];
|
||||||
|
@ -36,7 +36,7 @@ pub fn parse_image_cloze(text: &str) -> Option<ImageOcclusion> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return Some(ImageOcclusion {
|
return Some(ImageOcclusionShape {
|
||||||
shape: shape.to_string(),
|
shape: shape.to_string(),
|
||||||
properties,
|
properties,
|
||||||
});
|
});
|
||||||
|
|
|
@ -200,6 +200,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
{iconSize}
|
{iconSize}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
tool.action(canvas);
|
tool.action(canvas);
|
||||||
|
emitChangeSignal();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{@html tool.icon}
|
{@html tool.icon}
|
||||||
|
|
|
@ -18,9 +18,17 @@ export function extractShapesFromClozedField(
|
||||||
): ShapeOrShapes[] {
|
): ShapeOrShapes[] {
|
||||||
const output: ShapeOrShapes[] = [];
|
const output: ShapeOrShapes[] = [];
|
||||||
for (const occlusion of occlusions) {
|
for (const occlusion of occlusions) {
|
||||||
if (isValidType(occlusion.shape)) {
|
const group: Shape[] = [];
|
||||||
const props = Object.fromEntries(occlusion.properties.map(prop => [prop.name, prop.value]));
|
for (const shape of occlusion.shapes) {
|
||||||
output.push(buildShape(occlusion.shape, props));
|
if (isValidType(shape.shape)) {
|
||||||
|
const props = Object.fromEntries(shape.properties.map(prop => [prop.name, prop.value]));
|
||||||
|
group.push(buildShape(shape.shape, props));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (group.length > 1) {
|
||||||
|
output.push(group);
|
||||||
|
} else {
|
||||||
|
output.push(group[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue