Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,11 +4,11 @@
|
||||
* @author Original WarlockD (https://github.com/warlockd)
|
||||
* @author Changes stylemistake
|
||||
* @author Changes ThePotato97
|
||||
* @author Changes Ghommie
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { classes } from 'common/react';
|
||||
import { Fragment } from 'inferno';
|
||||
import { Component } from 'inferno';
|
||||
import marked from 'marked';
|
||||
import { useBackend } from '../backend';
|
||||
@@ -16,8 +16,27 @@ import { Box, Flex, Tabs, TextArea } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
import { clamp } from 'common/math';
|
||||
import { sanitizeText } from '../sanitize';
|
||||
import katex from 'katex';
|
||||
|
||||
const MAX_PAPER_LENGTH = 5000; // Question, should we send this with ui_data?
|
||||
|
||||
// Find where people put in equations inside two $ symbols
|
||||
// and convert them to proper LaTeX
|
||||
const equationRegex = (text) => {
|
||||
const find_equation_formatting = /\$.*\$/igm;
|
||||
const find_regex = find_equation_formatting.exec(text);
|
||||
if (find_regex) {
|
||||
for (let i = 0; i < find_regex.length; i++) {
|
||||
const removeDollarSigns = find_regex[i].replace(/\$/g, '');
|
||||
const convertToLatex = katex.renderToString(removeDollarSigns, {
|
||||
throwOnError: false,
|
||||
});
|
||||
text = text.replace(find_regex[i], convertToLatex);
|
||||
}
|
||||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
// Hacky, yes, works?...yes
|
||||
const textWidth = (text, font, fontsize) => {
|
||||
// default font height is 12 in tgui
|
||||
@@ -31,7 +50,7 @@ const textWidth = (text, font, fontsize) => {
|
||||
|
||||
const setFontinText = (text, font, color, bold=false) => {
|
||||
return "<span style=\""
|
||||
+ "color:'" + color + "';"
|
||||
+ "color:" + color + ";"
|
||||
+ "font-family:'" + font + "';"
|
||||
+ ((bold)
|
||||
? "font-weight: bold;"
|
||||
@@ -55,7 +74,7 @@ const createInputField = (length, width, font,
|
||||
+ "type=\"text\" "
|
||||
+ "style=\""
|
||||
+ "font:'" + fontsize + "x " + font + "';"
|
||||
+ "color:'" + color + "';"
|
||||
+ "color:" + color + ";"
|
||||
+ "min-width:" + width + ";"
|
||||
+ "max-width:" + width + ";"
|
||||
+ "\" "
|
||||
@@ -236,7 +255,6 @@ const PaperSheetView = (props, context) => {
|
||||
height="100%" >
|
||||
<Box
|
||||
className="Paper__Page"
|
||||
color="black"
|
||||
fillPositionedParent
|
||||
width="100%"
|
||||
height="100%"
|
||||
@@ -345,7 +363,7 @@ class PaperSheetStamper extends Component {
|
||||
rotate: this.state.rotate,
|
||||
};
|
||||
return (
|
||||
<Fragment>
|
||||
<>
|
||||
<PaperSheetView
|
||||
readOnly
|
||||
value={value}
|
||||
@@ -353,11 +371,58 @@ class PaperSheetStamper extends Component {
|
||||
<Stamp
|
||||
active_stamp
|
||||
opacity={0.5} image={current_pos} />
|
||||
</Fragment>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// This creates the html from marked text as well as the form fields
|
||||
const createPreview = (
|
||||
value,
|
||||
text,
|
||||
do_fields = false,
|
||||
field_counter,
|
||||
color,
|
||||
font,
|
||||
user_name,
|
||||
is_crayon = false,
|
||||
) => {
|
||||
const out = { text: text };
|
||||
// check if we are adding to paper, if not
|
||||
// we still have to check if someone entered something
|
||||
// into the fields
|
||||
value = value.trim();
|
||||
if (value.length > 0) {
|
||||
// First lets make sure it ends in a new line
|
||||
value += value[value.length] === "\n" ? " \n" : "\n \n";
|
||||
// Second, we sanitize the text of html
|
||||
const sanitized_text = sanitizeText(value);
|
||||
const signed_text = signDocument(sanitized_text, color, user_name);
|
||||
// Third we replace the [__] with fields as markedjs fucks them up
|
||||
const fielded_text = createFields(
|
||||
signed_text, font, 12, color, field_counter);
|
||||
// Fourth, parse the text using markup
|
||||
const formatted_text = run_marked_default(fielded_text.text);
|
||||
const replacedEquations = equationRegex(formatted_text);
|
||||
// Fifth, we wrap the created text in the pin color, and font.
|
||||
// crayon is bold (<b> tags), maybe make fountain pin italic?
|
||||
const fonted_text = setFontinText(
|
||||
replacedEquations, font, color, is_crayon);
|
||||
out.text += fonted_text;
|
||||
out.field_counter = fielded_text.counter;
|
||||
}
|
||||
if (do_fields) {
|
||||
// finally we check all the form fields to see
|
||||
// if any data was entered by the user and
|
||||
// if it was return the data and modify the text
|
||||
const final_processing = checkAllFields(
|
||||
out.text, font, color, user_name, is_crayon);
|
||||
out.text = final_processing.text;
|
||||
out.form_fields = final_processing.fields;
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
// ugh. So have to turn this into a full
|
||||
// component too if I want to keep updates
|
||||
// low and keep the weird flashing down
|
||||
@@ -367,58 +432,24 @@ class PaperSheetEdit extends Component {
|
||||
this.state = {
|
||||
previewSelected: "Preview",
|
||||
old_text: props.value || "",
|
||||
counter: props.counter || 0,
|
||||
textarea_text: "",
|
||||
combined_text: props.value || "",
|
||||
};
|
||||
}
|
||||
|
||||
// This is the main rendering part, this creates the html from marked text
|
||||
// as well as the form fields
|
||||
createPreview(value, do_fields = false) {
|
||||
createPreviewFromData(value, do_fields = false) {
|
||||
const { data } = useBackend(this.context);
|
||||
const {
|
||||
text,
|
||||
pen_color,
|
||||
pen_font,
|
||||
is_crayon,
|
||||
field_counter,
|
||||
edit_usr,
|
||||
} = data;
|
||||
const out = { text: text };
|
||||
// check if we are adding to paper, if not
|
||||
// we still have to check if someone entered something
|
||||
// into the fields
|
||||
value = value.trim();
|
||||
if (value.length > 0) {
|
||||
// First lets make sure it ends in a new line
|
||||
value += value[value.length] === "\n" ? " \n" : "\n \n";
|
||||
// Second, we sanitize the text of html
|
||||
const sanitized_text = sanitizeText(value);
|
||||
const signed_text = signDocument(sanitized_text, pen_color, edit_usr);
|
||||
// Third we replace the [__] with fields as markedjs fucks them up
|
||||
const fielded_text = createFields(
|
||||
signed_text, pen_font, 12, pen_color, field_counter);
|
||||
// Fourth, parse the text using markup
|
||||
const formatted_text = run_marked_default(fielded_text.text);
|
||||
// Fifth, we wrap the created text in the pin color, and font.
|
||||
// crayon is bold (<b> tags), maybe make fountain pin italic?
|
||||
const fonted_text = setFontinText(
|
||||
formatted_text, pen_font, pen_color, is_crayon);
|
||||
out.text += fonted_text;
|
||||
out.field_counter = fielded_text.counter;
|
||||
}
|
||||
if (do_fields) {
|
||||
// finally we check all the form fields to see
|
||||
// if any data was entered by the user and
|
||||
// if it was return the data and modify the text
|
||||
const final_processing = checkAllFields(
|
||||
out.text, pen_font, pen_color, edit_usr, is_crayon);
|
||||
out.text = final_processing.text;
|
||||
out.form_fields = final_processing.fields;
|
||||
}
|
||||
return out;
|
||||
return createPreview(value,
|
||||
this.state.old_text,
|
||||
do_fields,
|
||||
this.state.counter,
|
||||
data.pen_color,
|
||||
data.pen_font,
|
||||
data.edit_usr,
|
||||
data.is_crayon,
|
||||
);
|
||||
}
|
||||
|
||||
onInputHandler(e, value) {
|
||||
if (value !== this.state.textarea_text) {
|
||||
const combined_length = this.state.old_text.length
|
||||
@@ -439,19 +470,21 @@ class PaperSheetEdit extends Component {
|
||||
}
|
||||
this.setState(() => ({
|
||||
textarea_text: value,
|
||||
combined_text: this.createPreview(value),
|
||||
combined_text: this.createPreviewFromData(value),
|
||||
}));
|
||||
}
|
||||
}
|
||||
// the final update send to byond, final upkeep
|
||||
finalUpdate(new_text) {
|
||||
const { act } = useBackend(this.context);
|
||||
const final_processing = this.createPreview(new_text, true);
|
||||
const final_processing = this.createPreviewFromData(new_text, true);
|
||||
act('save', final_processing);
|
||||
this.setState(() => { return {
|
||||
textarea_text: "",
|
||||
previewSelected: "save",
|
||||
combined_text: final_processing.text,
|
||||
old_text: final_processing.text,
|
||||
counter: final_processing.field_counter,
|
||||
}; });
|
||||
// byond should switch us to readonly mode from here
|
||||
}
|
||||
@@ -490,7 +523,7 @@ class PaperSheetEdit extends Component {
|
||||
const new_state = {
|
||||
previewSelected: "Preview",
|
||||
textarea_text: this.state.textarea_text,
|
||||
combined_text: this.createPreview(
|
||||
combined_text: this.createPreviewFromData(
|
||||
this.state.textarea_text).text,
|
||||
};
|
||||
return new_state;
|
||||
@@ -516,7 +549,7 @@ class PaperSheetEdit extends Component {
|
||||
const new_state = {
|
||||
previewSelected: "confirm",
|
||||
textarea_text: this.state.textarea_text,
|
||||
combined_text: this.createPreview(
|
||||
combined_text: this.createPreviewFromData(
|
||||
this.state.textarea_text).text,
|
||||
};
|
||||
return new_state;
|
||||
@@ -567,7 +600,33 @@ export const PaperSheet = (props, context) => {
|
||||
sizeX,
|
||||
sizeY,
|
||||
name,
|
||||
add_text,
|
||||
add_font,
|
||||
add_color,
|
||||
add_sign,
|
||||
field_counter,
|
||||
} = data;
|
||||
// some features can add text to a paper sheet outside of this ui
|
||||
// we need to parse, sanitize and add any of it to the text value.
|
||||
const values = { text: text, field_counter: field_counter };
|
||||
if (add_text) {
|
||||
for (let index = 0; index < add_text.length; index++) {
|
||||
const used_color = add_color[index];
|
||||
const used_font = add_font[index];
|
||||
const used_sign = add_sign[index];
|
||||
const processing = createPreview(
|
||||
add_text[index],
|
||||
values.text,
|
||||
false,
|
||||
values.field_counter,
|
||||
used_color,
|
||||
used_font,
|
||||
used_sign
|
||||
);
|
||||
values.text = processing.text;
|
||||
values.field_counter = processing.field_counter;
|
||||
}
|
||||
}
|
||||
const stamp_list = !stamps
|
||||
? []
|
||||
: stamps;
|
||||
@@ -576,14 +635,15 @@ export const PaperSheet = (props, context) => {
|
||||
case 0:
|
||||
return (
|
||||
<PaperSheetView
|
||||
value={text}
|
||||
value={values.text}
|
||||
stamps={stamp_list}
|
||||
readOnly />
|
||||
);
|
||||
case 1:
|
||||
return (
|
||||
<PaperSheetEdit
|
||||
value={text}
|
||||
value={values.text}
|
||||
counter={values.field_counter}
|
||||
textColor={pen_color}
|
||||
fontFamily={pen_font}
|
||||
stamps={stamp_list}
|
||||
@@ -592,7 +652,7 @@ export const PaperSheet = (props, context) => {
|
||||
case 2:
|
||||
return (
|
||||
<PaperSheetStamper
|
||||
value={text}
|
||||
value={values.text}
|
||||
stamps={stamp_list}
|
||||
stamp_class={stamp_class} />
|
||||
);
|
||||
@@ -605,8 +665,7 @@ export const PaperSheet = (props, context) => {
|
||||
title={name}
|
||||
theme="paper"
|
||||
width={sizeX || 400}
|
||||
height={sizeY || 500}
|
||||
resizable>
|
||||
height={sizeY || 500}>
|
||||
<Window.Content
|
||||
backgroundColor={paper_color}
|
||||
scrollable>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"dompurify": "^2.2.7",
|
||||
"inferno": "^7.4.8",
|
||||
"inferno-vnode-flags": "^7.4.8",
|
||||
"katex": "^0.15.1",
|
||||
"marked": "^2.0.3",
|
||||
"tgui-dev-server": "workspace:*",
|
||||
"tgui-polyfill": "workspace:*"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,28 @@
|
||||
.katex {
|
||||
font-size: 1.5em !important
|
||||
}
|
||||
|
||||
eq {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
eqn {
|
||||
display: block
|
||||
}
|
||||
|
||||
section.eqno {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-content: space-between;
|
||||
align-items: center
|
||||
}
|
||||
|
||||
section.eqno>eqn {
|
||||
width: 100%;
|
||||
margin-left: 3em
|
||||
}
|
||||
|
||||
section.eqno>span {
|
||||
width: 3em;
|
||||
text-align: right
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
@include meta.load-css('./atomic/debug-layout.scss');
|
||||
@include meta.load-css('./atomic/outline.scss');
|
||||
@include meta.load-css('./atomic/text.scss');
|
||||
@include meta.load-css('./atomic/TexMath.scss');
|
||||
@include meta.load-css('./atomic/KaTeX.scss');
|
||||
|
||||
// Components
|
||||
@include meta.load-css('./components/BlockQuote.scss');
|
||||
|
||||
@@ -3036,6 +3036,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"commander@npm:^8.0.0":
|
||||
version: 8.3.0
|
||||
resolution: "commander@npm:8.3.0"
|
||||
checksum: 0b818d97ca9c8ad461ff05f873082af0c1895e49984a2abf1090e4a85c3537c3c0f9921e38314a9de7e71941f00f710c204d3560e3a7bc0b1023eef92d6bbfc0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"common@workspace:*, common@workspace:packages/common":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "common@workspace:packages/common"
|
||||
@@ -5826,6 +5833,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"katex@npm:^0.15.1":
|
||||
version: 0.15.1
|
||||
resolution: "katex@npm:0.15.1"
|
||||
dependencies:
|
||||
commander: ^8.0.0
|
||||
bin:
|
||||
katex: cli.js
|
||||
checksum: d1db044d8b2f37c70adb4c331dfe55b453f2fc4a0cc72e050e76ff372a7f74201a3ac96998bda3f63cafac3622b2e2e89aecc4b2ed960c5fdd2dda2d8bfe5757
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"kind-of@npm:^3.0.2, kind-of@npm:^3.0.3, kind-of@npm:^3.2.0":
|
||||
version: 3.2.2
|
||||
resolution: "kind-of@npm:3.2.2"
|
||||
@@ -8369,6 +8387,7 @@ resolve@^2.0.0-next.3:
|
||||
dompurify: ^2.2.7
|
||||
inferno: ^7.4.8
|
||||
inferno-vnode-flags: ^7.4.8
|
||||
katex: ^0.15.1
|
||||
marked: ^2.0.3
|
||||
tgui-dev-server: "workspace:*"
|
||||
tgui-polyfill: "workspace:*"
|
||||
|
||||
Reference in New Issue
Block a user