omii-ui
Version:
使用OMII开发的WebComponents库,样式采用bootstrap。可以作为标准的esmodule使用
327 lines (313 loc) • 9.35 kB
JSX
const { h, classNames, extractClass } = omii;
import uiBase from "../uiBase";
import css from "./index.scss";
import { getCSSStyleSheets } from "../css";
//min.js
let min = true;
let root = new URL(`./tinymce/`, import.meta.url).href;
let jsFile = `./tinymce.js`;
export default class extends uiBase {
static css = [() => getCSSStyleSheets("reboot", "scrollbar"), css];
static propTypes = {
value: String,
placeholder: String,
required: Boolean,
inline: Boolean,
readonly: Boolean,
};
static defaultProps = {
//编辑器引擎
value: "",
isEmpty(value) {
if (typeof value != "string") {
return true;
}
return value == "";
},
relativeUrls: null,
width: null,
height: null,
minWidth: null,
minHeight: null,
maxWidth: null,
maxHeight: null,
resize: true,
placeholder: "...",
readonly: false,
required: false,
language: "zh-Hans",
directionality: null,
plugins:
"preview importcss searchreplace autolink autosave save directionality code visualblocks visualchars fullscreen image link media template codesample table charmap pagebreak nonbreaking anchor insertdatetime advlist lists wordcount help charmap quickbars emoticons",
toolbar:
"undo redo searchreplace | bold italic underline strikethrough subscript superscript | fontfamily fontsize blocks styles lineheight | alignleft aligncenter alignright alignjustify | outdent indent | numlist bullist | forecolor backcolor removeformat | pagebreak hr insertdatetime | selectall cut copy paste pastetext |charmap emoticons | quickimage quicktable |insertfile image media table template link unlink anchor codesample | ltr rtl | visualblocks wordcount code fullscreen preview print",
toolbarSticky: true,
toolbarMode: "wrap",
menu: null,
menubar: false,
inline: false,
contentCss: null,
contentStyle: null,
blockFormats:
"Div=div;Paragraph=p;Heading 1=h1;Heading 2=h2;Heading 3=h3;Heading 4=h4;Heading 5=h5;Heading 6=h6;Preformatted=pre",
fontFamilyFormats:
"宋体=宋体;仿宋=仿宋;楷体=楷体;微软雅黑=微软雅黑;黑体=黑体;隶书=隶书;Andale Mono=andale mono,times; Arial=arial,helvetica,sans-serif; Arial Black=arial black,avant garde; Book Antiqua=book antiqua,palatino; Comic Sans MS=comic sans ms,sans-serif; Courier New=courier new,courier; Georgia=georgia,palatino; Helvetica=helvetica; Impact=impact,chicago; Symbol=symbol; Tahoma=tahoma,arial,helvetica,sans-serif; Terminal=terminal,monaco; Times New Roman=times new roman,times; Trebuchet MS=trebuchet ms,geneva; Verdana=verdana,geneva; Webdings=webdings; Wingdings=wingdings,zapf dingbats",
fontSizeFormats: null,
lineHeightFormats: null,
indentation: null,
indentUseMargin: false,
styleFormatsMerge: true,
styleFormats: null,
colorCols: 5,
colorMap: null,
imagesUploadUrl: null,
imagesUploadHandler: null,
imagesUploadBasePath: null,
imagesUploadCredentials: false,
imagesReuseFilename: false,
imagesFileTypes: null,
imageList: null,
imageAdvtab: true,
imageUploadtab: false,
imageDimensions: true,
imageTitle: true,
imagePrependUrl: null,
imageBatch: false,
automaticUploads: true,
filePickerTypes: null,
filePickerCallback: null,
templates: null,
importcssAppend: true,
importcssGroups: [
{ title: "Table styles", filter: /^(td|tr)\./ }, // td.class and tr.class
{ title: "Block styles", filter: /^(div|p)\./ }, // div.class and p.class
{ title: "Other styles" }, // The rest
],
};
static get min() {
return min;
}
static set min(value) {
min = value;
}
static get root() {
return root;
}
static set root(value) {
root = value;
}
static get jsFile() {
return jsFile;
}
static set jsFile(value) {
jsFile = value;
}
static async use() {
return await import(new URL(this.jsFile, this.root).href);
}
get value() {
return this.$props.value;
}
set value(value) {
this.$props.value = value;
if (this.editor && this.#ready) {
try {
this.editor.setContent(value);
} catch (exc) {
console.log("editor not init");
}
}
//这里不能fire change,这样容易引起循环调用
//监控change的控件可能会继续调用update
//this.fire("change", { value });
}
#editor;
get editor() {
return this.#editor;
}
#css;
css() {
return this.#css;
}
get validity() {
const { required, isEmpty } = this.$props;
const result = {
valid: true,
};
if (required && isEmpty(this.value)) {
result.valid = false;
result.valueMissing = true;
}
return result;
}
//已经检查过有效性
#checked = false;
/**
* 验证
* @returns {boolean}
*/
checkValidity() {
this.#checked = true;
const valid = this.validity.valid;
if (!valid) {
this.classList.add("is-invalid");
} else {
this.classList.remove("is-invalid");
}
return valid;
}
/**
* 获取编辑器Id
*/
get editorId() {
return `editor${this.elementId}`;
}
#ready = false;
async installed() {
// console.log("tiny installed");
//允许验证
this.dataset.validate = true;
await this.constructor.use();
const $editor = this.$(`#${this.editorId}`);
const {
menu,
menubar,
toolbar,
plugins,
language,
toolbarMode,
baseUrl,
inline,
readonly,
contentStyle,
contentCss,
fontFamilyFormats,
blockFormats,
fontSizeFormats,
lineHeightFormats,
indentUseMargin,
indentation,
styleFormats,
styleFormatsMerge,
colorCols,
colorMap,
imagesUploadUrl,
imagesUploadHandler,
imagesUploadBasePath,
imagesUploadCredentials,
imagesReuseFilename,
imagesFileTypes,
imageList,
imageBatch,
imageAdvtab,
imageUploadtab,
imageDimensions,
imageTitle,
imagePrependUrl,
relativeUrls,
automaticUploads,
filePickerTypes,
filePickerCallback,
templates,
importcssGroups,
importcssAppend,
width,
height,
minWidth,
minHeight,
maxWidth,
maxHeight,
resize,
placeholder,
setup,
...options
} = this.$props;
tinymce.init({
target: $editor,
promotion: false,
base_url: baseUrl ?? this.constructor.root,
menu,
menubar,
toolbar,
toolbar_mode: toolbarMode,
plugins,
language,
inline,
readonly,
extended_valid_elements: "oi-icon[name|color|size]",
custom_elements: "oi-icon",
content_css: contentCss,
content_style: contentStyle,
font_family_formats: fontFamilyFormats,
block_formats: blockFormats,
font_size_formats: fontSizeFormats,
line_height_formats: lineHeightFormats,
indent_use_margin: indentUseMargin,
indentation,
style_formats: styleFormats,
style_formats_merge: styleFormatsMerge,
color_cols: colorCols,
color_map: colorMap,
images_upload_url: imagesUploadUrl,
images_upload_handler: imagesUploadHandler,
images_upload_base_path: imagesUploadBasePath,
images_upload_credentials: imagesUploadCredentials,
images_reuse_filename: imagesReuseFilename,
images_file_types: imagesFileTypes,
image_list: imageList,
image_advtab: imageAdvtab,
image_uploadtab: imageUploadtab,
image_dimensions: imageDimensions,
image_title: imageTitle,
image_prepend_url: imagePrependUrl,
automatic_uploads: automaticUploads,
file_picker_types: filePickerTypes,
file_picker_callback: filePickerCallback,
importcss_groups: importcssGroups,
templates,
importcss_append: importcssAppend,
width,
height,
min_width: minWidth,
min_height: minHeight,
max_width: maxWidth,
max_height: maxHeight,
relative_urls: relativeUrls,
resize,
placeholder,
...options,
setup: (editor) => {
this.#editor = editor;
this.fire("setup", { editor });
editor.on("init", (e) => {
this.#ready = true;
this.fire("ready");
});
editor.on("blur", (e) => {
console.log("editor blur");
});
editor.on("change", (e) => {
this.$props.value = editor.getContent();
this.fire("change", { value: this.value });
});
},
});
}
render() {
const { inline } = this.$props;
return inline ? (
<div>
<div class="editor" id={this.editorId}>
{this.value}
</div>
</div>
) : (
<textarea
class="editor"
id={this.editorId}
value={this.value}
placeholder={this.placeholder}
></textarea>
);
}
}