UPDATE: Add clear formatting

Fixes #267
This commit is contained in:
Nicolás Hatcher
2025-02-03 23:31:04 +01:00
committed by Nicolás Hatcher Andrés
parent 42d557d485
commit 8a54f45d75
8 changed files with 171 additions and 0 deletions

View File

@@ -436,3 +436,47 @@ fn false_removes_value() {
let style = model.get_cell_style(0, 1, 1).unwrap(); let style = model.get_cell_style(0, 1, 1).unwrap();
assert!(!style.font.b); assert!(!style.font.b);
} }
#[test]
fn cell_clear_formatting() {
let mut model = UserModel::new_empty("model", "en", "UTC").unwrap();
let range = Area {
sheet: 0,
row: 1,
column: 1,
width: 1,
height: 1,
};
// bold
model.update_range_style(&range, "font.b", "true").unwrap();
model
.update_range_style(&range, "alignment.horizontal", "centerContinuous")
.unwrap();
let style = model.get_cell_style(0, 1, 1).unwrap();
assert!(style.font.b);
assert_eq!(
style.alignment.unwrap().horizontal,
HorizontalAlignment::CenterContinuous
);
model.range_clear_all(&range).unwrap();
let style = model.get_cell_style(0, 1, 1).unwrap();
assert!(!style.font.b);
assert_eq!(style.alignment, None);
model.undo().unwrap();
let style = model.get_cell_style(0, 1, 1).unwrap();
assert!(style.font.b);
assert_eq!(
style.alignment.unwrap().horizontal,
HorizontalAlignment::CenterContinuous
);
model.redo().unwrap();
let style = model.get_cell_style(0, 1, 1).unwrap();
assert!(!style.font.b);
assert_eq!(style.alignment, None);
}

View File

@@ -566,6 +566,34 @@ impl UserModel {
Ok(()) Ok(())
} }
/// Removes cells styles and formatting, but keeps the content
///
/// See also:
/// * [UserModel::range_clear_all]
/// * [UserModel::range_clear_contents]
pub fn range_clear_formatting(&mut self, range: &Area) -> Result<(), String> {
let sheet = range.sheet;
let mut diff_list = Vec::new();
for row in range.row..range.row + range.height {
for column in range.column..range.column + range.width {
let old_style = self.model.get_style_for_cell(sheet, row, column)?;
// We can always assume that style with style_index 0 exists and it is the default
self.model
.workbook
.worksheet_mut(sheet)?
.set_cell_style(row, column, 0)?;
diff_list.push(Diff::CellClearFormatting {
sheet,
row,
column,
old_style: Box::new(old_style),
});
}
}
self.push_diff_list(diff_list);
Ok(())
}
/// Inserts a row /// Inserts a row
/// ///
/// See also: /// See also:
@@ -2006,6 +2034,15 @@ impl UserModel {
old_value, old_value,
new_value: _, new_value: _,
} => self.model.set_sheet_state(*index, old_value.clone())?, } => self.model.set_sheet_state(*index, old_value.clone())?,
Diff::CellClearFormatting {
sheet,
row,
column,
old_style,
} => {
self.model
.set_cell_style(*sheet, *row, *column, old_style)?;
}
} }
} }
if needs_evaluation { if needs_evaluation {
@@ -2160,6 +2197,17 @@ impl UserModel {
old_value: _, old_value: _,
new_value, new_value,
} => self.model.set_sheet_state(*index, new_value.clone())?, } => self.model.set_sheet_state(*index, new_value.clone())?,
Diff::CellClearFormatting {
sheet,
row,
column,
old_style: _,
} => {
self.model
.workbook
.worksheet_mut(*sheet)?
.set_cell_style(*row, *column, 0)?;
}
} }
} }

View File

@@ -39,6 +39,12 @@ pub(crate) enum Diff {
old_value: Box<Option<Cell>>, old_value: Box<Option<Cell>>,
old_style: Box<Style>, old_style: Box<Style>,
}, },
CellClearFormatting {
sheet: u32,
row: i32,
column: i32,
old_style: Box<Style>,
},
SetCellStyle { SetCellStyle {
sheet: u32, sheet: u32,
row: i32, row: i32,

View File

@@ -161,6 +161,28 @@ impl UserModel {
self.model.range_clear_contents(&range).map_err(to_js_error) self.model.range_clear_contents(&range).map_err(to_js_error)
} }
#[napi(js_name = "rangeClearFormatting")]
pub fn range_clear_formatting(
&mut self,
sheet: u32,
start_row: i32,
start_column: i32,
end_row: i32,
end_column: i32,
) -> Result<()> {
let range = Area {
sheet,
row: start_row,
column: start_column,
width: end_column - start_column + 1,
height: end_row - start_row + 1,
};
self
.model
.range_clear_formatting(&range)
.map_err(to_js_error)
}
#[napi(js_name = "insertRow")] #[napi(js_name = "insertRow")]
pub fn insert_row(&mut self, sheet: u32, row: i32) -> Result<()> { pub fn insert_row(&mut self, sheet: u32, row: i32) -> Result<()> {
self.model.insert_row(sheet, row).map_err(to_js_error) self.model.insert_row(sheet, row).map_err(to_js_error)

View File

@@ -174,6 +174,27 @@ impl Model {
self.model.range_clear_contents(&range).map_err(to_js_error) self.model.range_clear_contents(&range).map_err(to_js_error)
} }
#[wasm_bindgen(js_name = "rangeClearFormatting")]
pub fn range_clear_formatting(
&mut self,
sheet: u32,
start_row: i32,
start_column: i32,
end_row: i32,
end_column: i32,
) -> Result<(), JsError> {
let range = Area {
sheet,
row: start_row,
column: start_column,
width: end_column - start_column + 1,
height: end_row - start_row + 1,
};
self.model
.range_clear_formatting(&range)
.map_err(to_js_error)
}
#[wasm_bindgen(js_name = "insertRow")] #[wasm_bindgen(js_name = "insertRow")]
pub fn insert_row(&mut self, sheet: u32, row: i32) -> Result<(), JsError> { pub fn insert_row(&mut self, sheet: u32, row: i32) -> Result<(), JsError> {
self.model.insert_row(sheet, row).map_err(to_js_error) self.model.insert_row(sheet, row).map_err(to_js_error)

View File

@@ -23,6 +23,7 @@ import {
PaintRoller, PaintRoller,
Percent, Percent,
Redo2, Redo2,
RemoveFormatting,
Strikethrough, Strikethrough,
Tags, Tags,
Type, Type,
@@ -65,6 +66,7 @@ type ToolbarProperties = {
onFillColorPicked: (hex: string) => void; onFillColorPicked: (hex: string) => void;
onNumberFormatPicked: (numberFmt: string) => void; onNumberFormatPicked: (numberFmt: string) => void;
onBorderChanged: (border: BorderOptions) => void; onBorderChanged: (border: BorderOptions) => void;
onClearFormatting: () => void;
fillColor: string; fillColor: string;
fontColor: string; fontColor: string;
bold: boolean; bold: boolean;
@@ -360,6 +362,19 @@ function Toolbar(properties: ToolbarProperties) {
<Tags /> <Tags />
</StyledButton> </StyledButton>
<Divider />
<StyledButton
type="button"
$pressed={false}
disabled={!canEdit}
onClick={() => {
properties.onClearFormatting();
}}
title={t("toolbar.clear_formatting")}
>
<RemoveFormatting />
</StyledButton>
<ColorPicker <ColorPicker
color={properties.fontColor} color={properties.fontColor}
onChange={(color): void => { onChange={(color): void => {

View File

@@ -527,6 +527,20 @@ const Workbook = (props: { model: Model; workbookState: WorkbookState }) => {
onTextColorPicked={onTextColorPicked} onTextColorPicked={onTextColorPicked}
onFillColorPicked={onFillColorPicked} onFillColorPicked={onFillColorPicked}
onNumberFormatPicked={onNumberFormatPicked} onNumberFormatPicked={onNumberFormatPicked}
onClearFormatting={() => {
const {
sheet,
range: [rowStart, columnStart, rowEnd, columnEnd],
} = model.getSelectedView();
model.rangeClearFormatting(
sheet,
rowStart,
columnStart,
rowEnd,
columnEnd,
);
setRedrawId((id) => id + 1);
}}
onBorderChanged={(border: BorderOptions): void => { onBorderChanged={(border: BorderOptions): void => {
const { const {
sheet, sheet,

View File

@@ -3,6 +3,7 @@
"redo": "Redo", "redo": "Redo",
"undo": "Undo", "undo": "Undo",
"copy_styles": "Copy styles", "copy_styles": "Copy styles",
"clear_formatting": "Clear formatting",
"euro": "Format as Euro", "euro": "Format as Euro",
"percentage": "Format as Percentage", "percentage": "Format as Percentage",
"bold": "Bold", "bold": "Bold",