Commit a9e204b6 by yakoff94

update version && fix image

parent 061a935f
......@@ -6,9 +6,16 @@ import 'react-ag-qeditor/dist/index.css'
const App = () => {
return <div style={{padding:40}}>
<QEditor
value={'<h1>Общая информация о компании 1С:БИЗНЕС РЕШЕНИЯ</h1><p><img src="https://cdn.atmaguru.online/2/brs/b/7/b7NtdzpNVws1TbKxzIaZeIUjqT9Bz6NAnloaLJ0tDJMraK4T92XdJOPW3Aci69ko.jpg"></p><p></p><p><strong>Наша профессия – Родину автоматизировать!</strong></p><p>Компания находится в городе Оренбург - областном центре Оренбургской области. Мы работаем на всей территории Российской Федерации и являемся официальным партнёром фирмы «1С».</p><p>Наша компания занимает первое место в рейтинге партнеров фирмы «1С» в городе Оренбурге и Оренбургской области.</p><p>Специалистами нашей компании накоплен значительный опыт в области создания и сопровождения комплексных автоматизированных информационных систем для управления финансово-хозяйственной деятельностью предприятий.</p><p><br></p><p><br></p><h1>О фирме 1С</h1><p></p><p>Фирма «1С» основана в 1991 г. и специализируется на разработке, дистрибьюции, издании и поддержке компьютерных программ делового и домашнего назначения.</p><p>«1С» работает с пользователями через разветвленную партнерскую сеть, которая включает более 10 000 постоянных партнеров в 600 городах 25 стран.</p><p><br></p><p>С подробной информацией вы можете ознакомиться на официальном сайте компании <a href="https://b-rs.ru" target="_blank" class="fr-green fr-strong">https://b-rs.ru</a></p><p><img src="https://cdn.atmaguru.online/1/brs/j/Y/jYHWg5cGVhaI0sfSzPPzf4NzAQJIFBft9eNiZYVvaxoTeW5PohLl9XFNMMQD5BlD.png"></p><p></p><p><strong>Дата создания компании – 11.08.2005.</strong></p><p><strong>Маркетинговое наименование компании - 1С:БИЗНЕС РЕШЕНИЯ. </strong>Маркетинговое наименование мы используем при общении, чтобы представляться и рассказывать о компании. Это наименование на слуху, его знают клиенты, кандидаты. Так мы называем нашу компанию на рынке.<br>Компания имеет два юридических лица - ООО «БИЗНЕС РЕШЕНИЯ» и ООО «ТОРГОВЫЙ ДОМ «БИЗНЕС РЕШЕНИЯ». Официальные юридические наименования используются для документов и официального документооборота.</p><p><audio src="https://cdn.atmaguru.online/1/atmacompany/A/n/An7eXbBSUmf6wZUOH5fxmjwt23g1L0gMp5jNZDfUSOaQwX50OFiTAwsMbqvLP4nf.mp3" controls="true"><source src="https://cdn.atmaguru.online/1/atmacompany/A/n/An7eXbBSUmf6wZUOH5fxmjwt23g1L0gMp5jNZDfUSOaQwX50OFiTAwsMbqvLP4nf.mp3"></audio><br></p><p>Номер телефона (3532) 43-05-17<br>Телефон отдела качества (3532) 60-95-17<br>Юридически и фактический адрес – 460000, г. Оренбург, пер. Матросский, д.2<br><br><br></p><p><br></p><h2>Компания 1С:БИЗНЕС РЕШЕНИЯ оказывает следующие виды профессиональных услуг</h2><p><br></p><p><strong>СОПРОВОЖДЕНИЕ ПРОГРАММ 1С КОММЕРЧЕСКИХ ОРГАНИЗАЦИЙ</strong></p><p>Комплексная услуга по обслуживанию программ 1С. Работая с нами, Вы будете уверены в стабильной работе Ваших программ 1С, своевременно получите квалифицированную помощь наших специалистов.</p><p></p><p><strong>СОПРОВОЖДЕНИЕ ПРОГРАММ 1С БЮДЖЕТНЫХ ОРГАНИЗАЦИЙ</strong></p><p>Услуги по обслуживанию и консультациям программ 1С для бюджетных организаций</p><p></p><p><strong>ПРОЕКТНОЕ ВНЕДРЕНИЕ</strong></p><p>Внедряем автоматизированные системы на базе «1С:Предприятие 8».</p><p>Наша проектная команда выполнит запуск типового или отраслевого решения 1С.</p><p></p><p><strong>ОБУЧЕНИЕ РАБОТЕ В ПРОГРАММАХ 1С</strong></p><p>Центр Сертифицированного Обучения компании «1С:БИЗНЕС РЕШЕНИЯ» является ведущим учебным центром в городе Оренбурге, осуществляющим обучение пользователей работе в программах 1С:Предприятие по стандартам фирмы «1С».</p><p></p><p><strong>АВТОМАТИЗАЦИЯ ТОРГОВЛИ</strong></p><p>Автоматизация торговых предприятий – одно из основных направлений деятельности компании «1С:БИЗНЕС РЕШЕНИЯ». Невозможно представить себе современный магазин, в котором бы не применялось торговое оборудование и специализированное программное обеспечение</p><p></p><p><strong>ТЕХНИЧЕСКОЕ ОБСЛУЖИВАНИЕ</strong></p><p>Комплексное обслуживание компьютерной и офисной техники</p><p><br></p><p style="text-align: center"><strong>Статусы компании</strong></p><p><br></p><ol><li><p>Официальный партнер фирмы "1С"</p></li><li><p>Центр Сопровождения 1С</p></li><li><p>Кандидат в 1С:Центр ERP</p></li><li><p>Ключевой партнер "1С-Рарус" по внедрению CRM-технологий на платформе "1С:Предприятие 8"</p></li><li><p>Центр компетенции по документообороту</p></li><li><p>Центр реальной автоматизации</p></li><li><p>Центр компетенции 1С по 54-ФЗ</p></li><li><p>Центр Сертифицированного Обучения фирмы "1С"</p></li><li><p>Авторизованный Учебный Центр фирмы "1С"</p></li><li><p>Авторизованный Центр Сертификации фирмы "1С"</p></li><li><p>Центр компетенции 1С по бюджетному учету</p></li><li><p>Готов к маркировке</p></li><li><p>Мастер ККТ</p></li><li><p>Ключевой партнер "1С-Рарус" по "Альфа-Авто"</p></li></ol>'}
value={`<p>There are two images below. One with alt text, and one without.</p>
<!-- <img-->
<!-- src="https://cdn.atmaguru.online/2/brs/b/7/b7NtdzpNVws1TbKxzIaZeIUjqT9Bz6NAnloaLJ0tDJMraK4T92XdJOPW3Aci69ko.jpg"-->
<!-- alt="Sandy hills with a foggy background"-->
<!-- />-->
<p></p>
<p></p>
<img src="https://cdn.atmaguru.online/2/atmacompany/L/u/Luzfq2rOeEruKLfLGNDDCWJcjh0y2zYimU7semFd3ZgW7uxA14DGwPf9jP5pH0yQ.png" /><p></p><p></p>`}
onChange={(value)=>{
// console.log(value);
console.log(value);
}}
uploadOptions={{
url: 'https://cdn.atmaguru.online/upload/?sid=atmacompany&md5=0cETbV4BquHkqAdG9cK9MA&expires=1742192970',
......
{
"name": "react-ag-qeditor",
"version": "1.0.29",
"version": "1.0.30",
"description": "WYSIWYG html editor",
"author": "atma",
"license": "MIT",
......
.image {
width: fit-content;
position: relative;
}
.image .alt-text-indicator {
font-size: 0.8em;
position: absolute;
bottom: 10px;
left: 10px;
max-width: calc(100% - 20px);
padding: 0 0.5em;
border: 1px solid #242424;
background-color: rgba(255, 255, 255, 0.8);
display: inline-flex;
align-items: center;
overflow: hidden;
gap: 0.25em;
}
.image .alt-text-indicator .symbol {
flex: 0 0 auto;
font-size: 1.4em;
font-weight: bold;
}
.image .alt-text-indicator .symbol-positive {
color: #19961b;
}
.image .alt-text-indicator .symbol-negative {
color: #961f1f;
}
.image .alt-text-indicator .text {
flex: 1 1 auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.image .alt-text-indicator .edit {
flex: 0 0 auto;
border: 0;
padding: 0;
background: transparent;
appearance: none;
text-decoration: underline;
}
.node-image {
display: inline-block;
}
.edit {
cursor: pointer;
}
......@@ -14,7 +14,7 @@ import TableRow from '@tiptap/extension-table-row'
import TableHeader from '@tiptap/extension-table-header'
import Focus from '@tiptap/extension-focus'
// import Link from '@tiptap/extension-link'
import Image from '@tiptap/extension-image'
// import Image from '@tiptap/extension-image'
import TextAlign from '@tiptap/extension-text-align'
import { Color } from '@tiptap/extension-color'
import Highlight from '@tiptap/extension-highlight'
......@@ -33,14 +33,28 @@ import { useReactMediaRecorder } from 'react-media-recorder'
import axios from 'axios'
import ReactStopwatch from 'react-stopwatch'
import Audio from './extensions/Audio'
import CustomImage from './extensions/Image'
// import ImageResize from 'tiptap-imagresize';
import IframeModal from './modals/IframeModal'
import IframeCustomModal from './modals/IframeCustomModal'
import { isMobile } from 'react-device-detect'
import Resizable from './extensions/Resizing'
import Resizing from "./extensions/Resizing";
import { ExportPdf } from './extensions/ExportPdf'
// const CustomImage = Image.extend({
// options: {inline: true},
// // addNodeView() {
// // return ({ editor, node }) => {
// // const image = document.createElement('img');
// // image.src = node.attrs.src;
// // image.width = node.attrs.width;
// // return {
// // dom: image,
// // }
// // }
// // },
// })
const initialBubbleItems = [
'bold',
'italic',
......@@ -300,7 +314,7 @@ const QEditor = ({
title: 'По центру',
onClick: () => {
editor.commands.setTextAlign('center');
editor.commands.paragraph({ textAlign: 'left' })
//так надо, даже не вникай, фикс бага в хроме при выравнивании картинки
setTimeout(()=>{
editor.commands.setTextAlign('center');
......@@ -415,20 +429,8 @@ const QEditor = ({
extensions: [
StarterKit,
Underline,
Image.configure({
inline: true
}),
Resizable.configure({
types: ["image"], // resizable type
handlerStyle: { // handler point style
width: "8px",
height: "8px",
background: "#07c160",
},
layerStyle: { // layer mask style
border: "2px solid #07c160",
},
}),
CustomImage,
// Link.configure({
// autolink: true,
// linkOnPaste: true,
......@@ -469,7 +471,7 @@ const QEditor = ({
}),
Audio,
Superscript,
Subscript
Subscript,
],
content: value,
onUpdate: ({editor}) => onChange(editor.getHTML()),
......@@ -1146,7 +1148,8 @@ const QEditor = ({
}
if (editor.isActive('image') === true) {
items = ['alignLeft', 'alignCenter', 'alignRight']
items = []
// items = ['alignLeft', 'alignCenter', 'alignRight']
}
setFocusFromTo([o.from, o.to].join(':'))
......
import { Extension } from "@tiptap/core";
import React from 'react'
import Image from '@tiptap/extension-image'
import { NodeViewWrapper, ReactNodeViewRenderer } from '@tiptap/react';
// loads with editor
import '../Image.css'
import { mergeAttributes } from "@tiptap/core";
export default Extension.create({
name: "Resizable",
export default Image.extend({
options: {inline: true},
addAttributes() {
return {
alt: {
parseHTML: element => element.getAttribute('alt'),
},
src: {
parseHTML: element => element.getAttribute('src'),
},
width: {
parseHTML: element => element.getAttribute('width'),
}
}
},
addNodeView () {
return ReactNodeViewRenderer(ImageNode)
},
renderHTML({HTMLAttributes }) {
// console.log(node.updateAttributes());
return ['img', mergeAttributes(HTMLAttributes)]
},
addOptions () {
return {
types: ["image", "video"],
types: ["image"],
handlerStyle: {
width: "8px",
height: "8px",
......@@ -17,92 +41,150 @@ export default Extension.create({
},
};
},
addStorage () {
return {
resizeElement: null,
};
},
onCreate (data) {
onCreate ({editor}) {
let editor = data.editor,
node = data.node;
const element = editor.options.element;
element.style.position = "relative";
// resizeLayer
// console.log('onCreate', editor);
// console.log('onCreate', data);
const resizeLayer = document.createElement("div");
resizeLayer.className = "resize-layer";
resizeLayer.id = "resize-layer";
resizeLayer.style.display = "none";
resizeLayer.style.position = "absolute";
Object.entries(this.options.layerStyle).forEach(([key, value]) => {
resizeLayer.style[key] = value;
});
resizeLayer.addEventListener("mousedown", (e) => {
const resizeElement = this.storage.resizeElement;
const handlers = ["top-left", "top-right", "bottom-left", "bottom-right"];
const fragment = document.createDocumentFragment();
for (let name of handlers) {
const item = document.createElement("div");
item.className = `handler ${name}`;
item.style.position = "absolute";
Object.entries(this.options.handlerStyle).forEach(([key, value]) => {
item.style[key] = value;
});
const dir = name.split("-");
item.style[dir[0]] = parseInt(item.style.width) / -2 + "px";
item.style[dir[1]] = parseInt(item.style.height) / -2 + "px";
if (name === "bottom-left") item.style.cursor = "sw-resize";
if (name === "bottom-right") item.style.cursor = "se-resize";
fragment.appendChild(item);
}
resizeLayer.appendChild(fragment);
editor.resizeLayer = resizeLayer;
element.appendChild(resizeLayer);
},
onUpdate({editor, transaction}) {
// console.log('update');
selectionUpdate({editor, transaction}, this.options, this.storage)
},
onSelectionUpdate ({editor, transaction}) {
selectionUpdate({editor, transaction}, this.options, this.storage)
},
})
function ImageNode (props) {
// let width = typeof props.editor.resizeLayer !== 'undefined' ? props.editor.resizeLayer.style.width : props.node.attrs.width;
const {src, alt, width} = props.node.attrs
const { updateAttributes } = props
let className = 'image'
if (props.selected) {
className += ' ProseMirror-selectednode'
}
const onEditAlt = (e) => {
e.preventDefault();
const newAlt = prompt('Введите Alt:', alt || '')
updateAttributes({ alt: newAlt })
}
let resizeLayer = document.getElementById('resize-layer');
if (resizeLayer) {
const handler = (e) => {
const element = props.editor.options.element;
const resizeElement = props.extension.storage.resizeElement;
if ( ! resizeElement) return;
if (/bottom/.test(e.target.className)) {
let startX = e.screenX;
const dir = e.target.classList.contains("bottom-left") ? -1 : 1;
let last_width = 0
const mousemoveHandle = (e) => {
e.preventDefault();
const width = resizeElement.clientWidth;
const distanceX = e.screenX - startX;
const total = width + dir * distanceX;
// resizeElement
resizeElement.style.width = total + "px";
const clientWidth = resizeElement.clientWidth;
const clientHeight = resizeElement.clientHeight;
resizeElement.style.width = clientWidth + "px"; // max width
// resizeLayer
last_width = clientWidth;
const pos = getRelativePosition(resizeElement, element);
// console.log(pos);
resizeLayer.style.top = pos.top + "px";
resizeLayer.style.left = pos.left + "px";
resizeLayer.style.width = clientWidth + "px";
resizeLayer.style.height = clientHeight + "px";
startX = e.screenX;
};
document.addEventListener("mousemove", mousemoveHandle);
document.addEventListener("mouseup", () => {
document.addEventListener("mouseup", (e) => {
updateAttributes({ width: last_width});
document.removeEventListener("mousemove", mousemoveHandle)
});
}
});
}
// resizeLayer.removeEventListener('mousedown', handler);
const handlers = ["top-left", "top-right", "bottom-left", "bottom-right"];
const fragment = document.createDocumentFragment();
for (let name of handlers) {
const item = document.createElement("div");
item.className = `handler ${name}`;
item.style.position = "absolute";
Object.entries(this.options.handlerStyle).forEach(([key, value]) => {
item.style[key] = value;
});
const dir = name.split("-");
item.style[dir[0]] = parseInt(item.style.width) / -2 + "px";
item.style[dir[1]] = parseInt(item.style.height) / -2 + "px";
if (name === "bottom-left") item.style.cursor = "sw-resize";
if (name === "bottom-right") item.style.cursor = "se-resize";
fragment.appendChild(item);
if (resizeLayer.getAttribute('listener') !== 'true') {
resizeLayer.setAttribute('listener', true);
resizeLayer.addEventListener("mousedown", handler);
}
}
resizeLayer.appendChild(fragment);
editor.resizeLayer = resizeLayer;
element.appendChild(resizeLayer);
},
onUpdate({editor, transaction}) {
selectionUpdate({editor, transaction}, this.options, this.storage)
},
return (
<NodeViewWrapper className={className} data-drag-handle>
<img src={src} width={width} alt={alt}/>
<span className="alt-text-indicator" style={{zIndex: '999'}}>
{alt ?
<span className="symbol symbol-positive"></span> :
<span className="symbol symbol-negative">!</span>
}
{alt ?
<span className="text">Alt: "{alt}".</span> :
<span className="text">Alt текст не найден.</span>
}
<button className="edit" type="button" onClick={onEditAlt}>
Изменить
</button>
</span>
</NodeViewWrapper>
)
}
onSelectionUpdate ({editor, transaction}) {
selectionUpdate({editor, transaction}, this.options, this.storage)
},
});
function selectionUpdate({editor, transaction}, options, storage)
{
const element = editor.options.element;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment