[{"data":1,"prerenderedAt":330},["ShallowReactive",2],{"docs:\u002Fdocs\u002Fguides\u002Fimages":3},{"id":4,"title":5,"body":6,"description":320,"extension":321,"meta":322,"navigation":325,"path":326,"seo":327,"stem":328,"__hash__":329},"docs\u002Fdocs\u002Fguides\u002Fimages.md","Изображения и загрузка",{"type":7,"value":8,"toc":315},"minimark",[9,14,66,70,74,81,291,294,298,308,311],[10,11,13],"h2",{"id":12},"вставьте-по-адресу","Вставьте по адресу",[15,16,21],"pre",{"className":17,"code":18,"language":19,"meta":20,"style":20},"language-ts shiki shiki-themes github-dark","editor.insertImage({ src: '\u002Fuploads\u002Fpicture.png', alt: 'Описание', width: 640, height: 480 });\n","ts","",[22,23,24],"code",{"__ignoreMap":20},[25,26,29,33,37,40,44,47,50,53,57,60,63],"span",{"class":27,"line":28},"line",1,[25,30,32],{"class":31},"s95oV","editor.",[25,34,36],{"class":35},"svObZ","insertImage",[25,38,39],{"class":31},"({ src: ",[25,41,43],{"class":42},"sU2Wk","'\u002Fuploads\u002Fpicture.png'",[25,45,46],{"class":31},", alt: ",[25,48,49],{"class":42},"'Описание'",[25,51,52],{"class":31},", width: ",[25,54,56],{"class":55},"sDLfK","640",[25,58,59],{"class":31},", height: ",[25,61,62],{"class":55},"480",[25,64,65],{"class":31}," });\n",[67,68,69],"p",{},"Изображения доступны в base\u002Fpro; insertImage возвращает boolean. Изображение inline, заменяет выделение одной операцией истории. src обязателен; alt\u002Ftitle — текст; размеры — целые 1–10000. Допустимы HTTP(S), относительные адреса и ограниченные raster data URL PNG\u002FJPEG\u002FGIF\u002FWebP. Blob\u002Ffile\u002Fjavascript и SVG data URL запрещены.",[10,71,73],{"id":72},"подключите-загрузку","Подключите загрузку",[67,75,76,77,80],{},"В превью конструктора файл можно выбрать в диалоге изображения. Он читается локально и встраивается в HTML как data URL; на сервер сайта файл не отправляется. Чтобы загрузка работала в вашем приложении и изображения хранились отдельно, задайте callback ",[22,78,79],{},"uploadImage",", возвращающий постоянный URL. Без callback диалог предлагает только адрес изображения.",[15,82,84],{"className":17,"code":83,"language":19,"meta":20,"style":20},"const editor = new ViText('#editor', {\n  preset: 'base',\n  uploadImage: async (file, { signal }) => {\n    const body = new FormData(); body.append('image', file);\n    const response = await fetch('\u002Fapi\u002Fimages', { method: 'POST', body, signal });\n    if (!response.ok) throw new Error('Загрузка не выполнена');\n    const result = await response.json();\n    return { src: result.url, alt: file.name };\n  }\n});\n",[22,85,86,113,125,159,189,219,249,270,279,285],{"__ignoreMap":20},[25,87,88,92,95,98,101,104,107,110],{"class":27,"line":28},[25,89,91],{"class":90},"snl16","const",[25,93,94],{"class":55}," editor",[25,96,97],{"class":90}," =",[25,99,100],{"class":90}," new",[25,102,103],{"class":35}," ViText",[25,105,106],{"class":31},"(",[25,108,109],{"class":42},"'#editor'",[25,111,112],{"class":31},", {\n",[25,114,116,119,122],{"class":27,"line":115},2,[25,117,118],{"class":31},"  preset: ",[25,120,121],{"class":42},"'base'",[25,123,124],{"class":31},",\n",[25,126,128,131,134,137,140,144,147,150,153,156],{"class":27,"line":127},3,[25,129,130],{"class":35},"  uploadImage",[25,132,133],{"class":31},": ",[25,135,136],{"class":90},"async",[25,138,139],{"class":31}," (",[25,141,143],{"class":142},"s9osk","file",[25,145,146],{"class":31},", { ",[25,148,149],{"class":142},"signal",[25,151,152],{"class":31}," }) ",[25,154,155],{"class":90},"=>",[25,157,158],{"class":31}," {\n",[25,160,162,165,168,170,172,175,178,181,183,186],{"class":27,"line":161},4,[25,163,164],{"class":90},"    const",[25,166,167],{"class":55}," body",[25,169,97],{"class":90},[25,171,100],{"class":90},[25,173,174],{"class":35}," FormData",[25,176,177],{"class":31},"(); body.",[25,179,180],{"class":35},"append",[25,182,106],{"class":31},[25,184,185],{"class":42},"'image'",[25,187,188],{"class":31},", file);\n",[25,190,192,194,197,199,202,205,207,210,213,216],{"class":27,"line":191},5,[25,193,164],{"class":90},[25,195,196],{"class":55}," response",[25,198,97],{"class":90},[25,200,201],{"class":90}," await",[25,203,204],{"class":35}," fetch",[25,206,106],{"class":31},[25,208,209],{"class":42},"'\u002Fapi\u002Fimages'",[25,211,212],{"class":31},", { method: ",[25,214,215],{"class":42},"'POST'",[25,217,218],{"class":31},", body, signal });\n",[25,220,222,225,227,230,233,236,238,241,243,246],{"class":27,"line":221},6,[25,223,224],{"class":90},"    if",[25,226,139],{"class":31},[25,228,229],{"class":90},"!",[25,231,232],{"class":31},"response.ok) ",[25,234,235],{"class":90},"throw",[25,237,100],{"class":90},[25,239,240],{"class":35}," Error",[25,242,106],{"class":31},[25,244,245],{"class":42},"'Загрузка не выполнена'",[25,247,248],{"class":31},");\n",[25,250,252,254,257,259,261,264,267],{"class":27,"line":251},7,[25,253,164],{"class":90},[25,255,256],{"class":55}," result",[25,258,97],{"class":90},[25,260,201],{"class":90},[25,262,263],{"class":31}," response.",[25,265,266],{"class":35},"json",[25,268,269],{"class":31},"();\n",[25,271,273,276],{"class":27,"line":272},8,[25,274,275],{"class":90},"    return",[25,277,278],{"class":31}," { src: result.url, alt: file.name };\n",[25,280,282],{"class":27,"line":281},9,[25,283,284],{"class":31},"  }\n",[25,286,288],{"class":27,"line":287},10,[25,289,290],{"class":31},"});\n",[67,292,293],{},"\u002Fapi\u002Fimages — маршрут вашего приложения, ViText его не создаёт. До callback проверены заявленный MIME, ненулевой размер и максимум 5 000 000 байт; сервер проверяет реальные байты\u002Fдоступ\u002Fлимиты.",[10,295,297],{"id":296},"отмена-и-устаревший-ответ","Отмена и устаревший ответ",[67,299,300,303,304],{},[22,301,302],{},"uploadImage(file, { signal?, alt? })"," возвращает Promise",[305,306,307],"boolean",{},". Signal\u002Fdestroy отменяют операцию, даже если callback игнорирует отмену. Изменение документа или CSS во время загрузки делает результат устаревшим; StaleDocumentError не вставляет изображение. Перемещение курсора допустимо: результат вставляется в сохранённый диапазон.",[67,309,310],{},"Приложение удаляет неиспользованный загруженный файл самостоятельно. Вставка файлов из drag\u002Fdrop или clipboard в callback пока не подключена. Внешний URL может обращаться к стороннему серверу; CSP и доверенные домены определяет приложение.",[312,313,314],"style",{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":20,"searchDepth":115,"depth":115,"links":316},[317,318,319],{"id":12,"depth":115,"text":13},{"id":72,"depth":115,"text":73},{"id":296,"depth":115,"text":297},"Безопасные адреса и callback загрузки на стороне приложения.","md",{"group":323,"order":324},"Работа с документом",24,true,"\u002Fdocs\u002Fguides\u002Fimages",{"title":5,"description":320},"docs\u002Fguides\u002Fimages","ELyWHBrgvRNSWM8bwKGNerDsCdP-XVqdcJi050I7fG0",1792670389277]