1(globalThis.webpackChunkdiscours_io_frontend=globalThis.webpackChunkdiscours_io_frontend||[]).push([[18],{6929(t,e,n){"use strict";var i=n(84799),s=n(88484);angular.module("discours.components").component("editorHeader",{templateUrl:"/components/editorHeader/editorHeader.html",bindings:{docTitle:"<",slug:"<",collabStatus:"<",connectedUsers:"<",isOfflineMode:"<",isReconnecting:"<",collabPermissionDenied:"<",onRetryConnection:"&?",tiptapEditor:"<",isPreviewMode:"<",suggestionMode:"<",sidebarVisible:"<",pendingCount:"<",collabSyncPending:"<",contentStatus:"<",contentLink:"<?",isSaving:"<",isPublishing:"<",hasUnsavedChanges:"<",hasDraft:"<",canEdit:"<",isAuthor:"<",showCollabControls:"<",isSavingVersion:"<",isSaveSuccess:"<",isSaveError:"<",lastVersionSavedAt:"<",showInviteButton:"<",inviteCount:"<",onOpenInvite:"&?",onModeChange:"&",onToggleSidebar:"&",onSave:"&?",onSaveVersionDialog:"&?",onPublish:"&?",onValidateBeforePublish:"&?",onVersionsClick:"&?",nightMode:"<",onToggleNightMode:"&?",marginViewMode:"<",onToggleMarginView:"&?",quietMode:"<",onToggleQuietMode:"&?",onRunTypographer:"&?",onOpenSettings:"&?",isAdmin:"<",onCleanCode:"&?",wordCount:"<",charCount:"<",initialParaCount:"<?",initialLastModified:"<",isLoggedIn:"<",userAvatar:"<",userPath:"<"},controller:["$scope","$element","$window","$timeout","$location","$injector","ConfirmDialog","Notification","eventBus",function(t,e,a,o,l,r,c,d,g){function p(t){let e=0;return t.forEach(function(t){"paragraph"===t.type.name&&t.textContent.trim().length>0&&e++}),e}function u(){(_.profileMenuOpen||B)&&(R&&(clearTimeout(R),R=null),B&&(B(),B=null),_.profileMenuOpen=!1,U&&"function"==typeof U.focus&&!U.disabled&&document.contains(U)&&U.focus(),U=null,t.$$destroyed||t.$applyAsync())}function m(){try{var t=_.tiptapEditor;if(t&&"function"==typeof t.getHTML){var e=t.getHTML();e&&"<p></p>"!==e&&localStorage.setItem("ls.contentItem.body",JSON.stringify(e))}_.docTitle&&localStorage.setItem("ls.contentItem.title",JSON.stringify(_.docTitle))}catch(t){}}function v(){let t;try{t=_.onPublish()}catch(t){return}t&&"function"==typeof t.then?t.then(function(t){t&&_.navigateToPublished()}).catch(function(t){}):_.navigateToPublished()}function b(){const t=_.contentStatus;return"posted"===t||"published"===t||"featured"===t||"recalled"===t}function f(){_.tiptapEditor.commands.enableLanguageTool&&(_.ltEnabled=!1!==_.tiptapEditor.commands.enableLanguageTool())}function h(){t.$$destroyed||(_.typographerDone=!0,T&&o.cancel(T),T=o(function(){_.typographerDone=!1},4e3))}function w(t){return t?("0"+t.getDate()).slice(-2)+"."+("0"+(t.getMonth()+1)).slice(-2)+"."+String(t.getFullYear()).slice(-2)+" в "+("0"+t.getHours()).slice(-2)+":"+("0"+t.getMinutes()).slice(-2):null}function y(){if(!_.slug&&!_.contentStatus)return _.statusText="ЧеÑновик",_.statusClass="draft",_.publishButtonText="ÐпÑбликоваÑÑ",void(_.toolsPublishText="ÐпÑбликоваÑÑ");switch(_.contentStatus){case"draft":_.statusText="ЧеÑновик",_.statusClass="draft",_.publishButtonText="ÐпÑбликоваÑÑ",_.toolsPublishText="ÐпÑбликоваÑÑ";break;case"posted":case"recalled":_.statusText="ÐпÑбликовано",_.statusClass="posted",_.publishButtonText="СоÑ
ÑаниÑÑ",_.toolsPublishText="ÐбновиÑÑ Ð¿ÑбликаÑиÑ";break;case"published":case"featured":_.statusText="РжÑÑнале",_.statusClass="featured",_.publishButtonText="СоÑ
ÑаниÑÑ",_.toolsPublishText="ÐбновиÑÑ Ð¿ÑбликаÑиÑ";break;default:_.statusText=null,_.statusClass="",_.publishButtonText="ÐпÑбликоваÑÑ",_.toolsPublishText="ÐпÑбликоваÑÑ"}}const _=this;_.isMac="undefined"!=typeof navigator&&(/macOS/i.test(navigator.userAgentData&&navigator.userAgentData.platform||"")||/Mac|iPod|iPhone|iPad/.test(navigator.platform||"")),_.isScrolled=!1,_.modeSwitcherOpen=!1,_.currentMode="editing",_.showCollabStatus=!1,_.showPanelButton=!1,_.showSuggestionMode=!1,_._publishDialogOpen=!1,_.helpBtnHidden=!1,_.profileMenuOpen=!1,_.avatarLoadError=!1,_.toolsPanelOpen=!1,_.typographerDone=!1,_.cleanCodeDone=!1,_.statusDescription="",_.paraCount=null,_.lastModifiedAt=null,_.lastModifiedFormatted=null,_.ltChecking=!1;let k=null,C=null;_.ltEnabled=!1,_.showHelpDot=!1;try{_.showHelpDot=!localStorage.getItem("discours_shortcuts_help_seen")}catch(t){}let x=null,S=null,I=null,M=null,P=null,E=null,L=null,T=null,A=null,D=null,V=null,H=null;_.$onInit=function(){function e(){const t=_.tiptapEditor&&_.tiptapEditor.storage&&_.tiptapEditor.storage.languageTool;_.ltChecking=!(!t||!t.loading),_.ltRateLimited=!(!t||!t.rateLimitError)}_.updateCurrentMode(),_.updateCollabFeatures(),y(),_.statusDescription=_.getStatusDescription(),angular.element(a).on("scroll",_.handleScroll),_._onShortcutsHelpSeen=function(){t.$applyAsync(function(){_.showHelpDot=!1})},a.addEventListener("shortcutsHelpSeen",_._onShortcutsHelpSeen),t.$watch(function(){const t=_.tiptapEditor&&_.tiptapEditor.storage&&_.tiptapEditor.storage.languageTool;return t?(t.loading?1:0)+(t.rateLimitError?2:0):null}
1,e),_._onLtLoadingChange=function(){t.$applyAsync(e)},document.addEventListener("lt-loading-change",_._onLtLoadingChange),t.$watch(function(){return _.tiptapEditor&&_.tiptapEditor.isEditable},function(t,e){t!==e&&_.updateCurrentMode()})},_.$onChanges=function(e){if((e.isPreviewMode||e.suggestionMode||e.tiptapEditor)&&_.updateCurrentMode(),e.tiptapEditor){var n=e.tiptapEditor.previousValue,i=e.tiptapEditor.currentValue;k&&n&&n.off&&n.off("update",k),C&&(clearTimeout(C),C=null),i&&i.on&&function(e){if(e.state&&e.state.doc){var n=p(e.state.doc);(n>0||null==_.paraCount)&&(_.paraCount=n)}k=function(e){e&&e.transaction&&e.transaction.docChanged&&(C&&clearTimeout(C),C=setTimeout(function(){C=null;var e=_.tiptapEditor;if(e&&e.state&&e.state.doc){var n=p(e.state.doc);t.$applyAsync(function(){_.lastModifiedAt=new Date,_.lastModifiedFormatted=w(_.lastModifiedAt),_.paraCount=n})}},300))},e.on("update",k)}(i)}if(e.initialParaCount&&null!=e.initialParaCount.currentValue&&null==_.paraCount&&(_.paraCount=e.initialParaCount.currentValue),e.initialLastModified&&e.initialLastModified.currentValue&&!_.lastModifiedAt&&(_.lastModifiedAt=e.initialLastModified.currentValue,_.lastModifiedFormatted=w(_.lastModifiedAt)),(e.collabStatus||e.isOfflineMode||e.isReconnecting||e.collabPermissionDenied||e.showCollabControls)&&(_.statusDescription=_.getStatusDescription(),_._statusTitleCache=_.getStatusTitle()),e.lastVersionSavedAt){const t=e.lastVersionSavedAt.currentValue;_._savedTimeCache=t?new Date(t).toLocaleTimeString():""}e.showCollabControls&&_.updateCollabFeatures(),(e.contentStatus||e.slug)&&y()};var B=null,R=null,U=null;_.openProfileMenu=function(){if(_.profileMenuOpen)u();else{U=document.activeElement,_.profileMenuOpen=!0,B&&(B(),B=null);var e=function(){B&&B(),u()},n=function(t){"Escape"!==t.key&&27!==t.keyCode||(B&&B(),u())};B=function(){document.removeEventListener("click",e,!0),document.removeEventListener("keyup",n)},R=setTimeout(function(){R=null,!t.$$destroyed&&_.profileMenuOpen?(document.addEventListener("click",e,!0),document.addEventListener("keyup",n)):B&&(B(),B=null)},0)}},_.openLogin=function(){if(_.tiptapEditor&&m(),"function"==typeof a.loadAuthModals){var e;try{e=r.get("$ocLazyLoad")}catch(t){return void(a.location.href="/#login")}a.loadAuthModals().then(function(n){if(!t.$$destroyed)return e.inject((n&&n.default||n||{}).modules||["discours.components","discours.templates"])}).then(function(){t.$$destroyed||(t.$root.editorLoginDetail={title:"ÐойдиÑе, ÑÑÐ¾Ð±Ñ ÑоÑ
ÑаниÑÑ ÑеÑновик на бÑдÑÑее"},t.$root.editorLoginShown=!0,t.$applyAsync())}).catch(function(){t.$$destroyed||(m(),a.location.href="/#login")})}else a.location.href="/#login"},_.logOut=function(){var t=r.get("loginService"),e=r.get("$route");t.logout().catch(function(t){}).finally(function(){e.reload()})},_.$onDestroy=function(){R&&(clearTimeout(R),R=null),B&&(B(),B=null),angular.element(a).off("scroll",_.handleScroll),x&&o.cancel(x),S&&o.cancel(S),I&&(o.cancel(I),I=null),t.$root.editorLoginShown&&(t.$root.editorLoginShown=!1,t.$root.editorLoginDetail=null),D&&(clearTimeout(D),D=null),_.removeToolsPanelHandlers(),T&&o.cancel(T),A&&o.cancel(A),_._onShortcutsHelpSeen&&a.removeEventListener("shortcutsHelpSeen",_._onShortcutsHelpSeen),_._onLtLoadingChange&&document.removeEventListener("lt-loading-change",_._onLtLoadingChange),V&&(clearTimeout(V),V=null),C&&(clearTimeout(C),C=null),k&&_.tiptapEditor&&_.tiptapEditor.off&&(_.tiptapEditor.off("update",k),k=null),H=null},_.updateCollabFeatures=function(){const t=!0===_.showCollabControls||"true"===_.showCollabControls;_.showCollabStatus=t,_.showPanelButton=t,_.showSuggestionMode=t},_.updateCurrentMode=function(){_.currentMode=_.isPreviewMode||_.tiptapEditor&&!1===_.tiptapEditor.isEditable?"preview":_.suggestionMode?"suggesting":"editing"},_.toggleModeSwitcher=function(){_.modeSwitcherOpen=!_.modeSwitcherOpen},_.closeModeSwitcherDelayed=function(){x&&o.cancel(x),x=o(function(){_.modeSwitcherOpen=!1},150)},_.setMode=function(t){if(_.modeSwitcherOpen=!1,t===_.currentMode)return;const e=_.currentMode;_.currentMode=t,_.onModeChange&&!1===_.onModeChange({mode:t})&&(_.currentMode=e)},_.togglePreviewMode=function(){_.setMode("preview"===_.currentMode?"editing":"preview")}
1,_.openHelpModal=function(){_.closeToolsPanel(),g.emit(g.EVENTS.OPEN_FEEDBACK_MODAL,"bug")},_.openShortcutsHelp=function(){Promise.all([n.e(272),n.e(929),n.e(411),n.e(753),n.e(68),n.e(1)]).then(n.bind(n,38023)).then(function(e){e.openShortcutsHelp(),t.$applyAsync(function(){_.showHelpDot=!1})}).catch(function(t){})},_.openImportExport=function(){_.closeToolsPanel(),Promise.all([n.e(272),n.e(929),n.e(411),n.e(753),n.e(68),n.e(1)]).then(n.bind(n,11561)).then(function(t){let e=null,n=(0,i.q)();try{e=r.get("s3UploaderService")}catch(t){}try{n=r.get("THUMBOR_SERVER")||n}catch(t){}t.openImportExportDialog({editor:_.tiptapEditor,s3UploaderService:e,Notification:d,contentItem:{slug:_.slug||"draft",title:_.docTitle||""},THUMBOR_SERVER:n})}).catch(function(t){d.error("Ðе ÑдалоÑÑ Ð¾ÑкÑÑÑÑ Ð¸Ð¼Ð¿Ð¾ÑÑ/ÑкÑпоÑÑ")})},_.toggleSidebar=function(){_.onToggleSidebar&&_.onToggleSidebar()},_.hasCursorPosition=function(t){if(!_.tiptapEditor)return!1;if(_.tiptapEditor.getProvider){const e=_.tiptapEditor.getProvider();if(e&&e.awareness){const n=e.awareness.getStates().get(t.clientId);if(n&&n.cursor&&null!=n.cursor.anchor)return!0}}return!(!_.tiptapEditor._cursorCache||null==_.tiptapEditor._cursorCache.get(t.clientId))},_.scrollToUserCursor=function(t){if(!_.tiptapEditor||!_.tiptapEditor.getProvider)return;const e=_.tiptapEditor.getProvider();if(!e||!e.awareness)return;const n=e.awareness.getStates().get(t.clientId);let i=null;if(n&&n.cursor&&null!=n.cursor.anchor&&_.tiptapEditor.resolveRelativePosition&&(i=_.tiptapEditor.resolveRelativePosition(n.cursor.anchor)),null==i&&(i=_.tiptapEditor._cursorCache&&_.tiptapEditor._cursorCache.get(t.clientId)),null!=i)try{const t=_.tiptapEditor.state.doc.content.size,e=Math.min(Math.max(0,i),t);_.tiptapEditor.chain().focus().setTextSelection(e).run(),V&&clearTimeout(V),V=setTimeout(function(){V=null;try{if(!_.tiptapEditor||!_.tiptapEditor.view)return;const t=_.tiptapEditor.view.coordsAtPos(e);t&&a.scrollTo({top:Math.max(0,a.pageYOffset+t.top-a.innerHeight/2),behavior:"smooth"})}catch(t){}},100)}catch(t){}},_.save=function(){_.showSaveDialog()},_.showSaveDialog=function(){const t=b();c.open({title:(0,s.t)(t?"Ðбновление маÑеÑиала":"ÐÑбликаÑÐ¸Ñ Ð¼Ð°ÑеÑиала"),message:(0,s.t)(t?"ÐаÑеÑиал бÑÐ´ÐµÑ Ð¾Ð±Ð½Ð¾Ð²Ð»Ñн и доÑÑÑпен ÑиÑаÑелÑм.":"ÐаÑеÑиал ÑÑÐ°Ð½ÐµÑ Ð´Ð¾ÑÑÑпен ÑиÑаÑелÑм поÑле пÑбликаÑии."),confirmText:(0,s.t)(t?"ÐбновиÑÑ":"ÐпÑбликоваÑÑ"),cancelText:(0,s.t)("СоÑ
ÑаниÑÑ ÐºÐ°ÐºÂ ÑеÑновик")}).then(function(){_.publish()}).catch(function(t){"cancel"!==t?c.onDismissed("[editorHeader.showSaveDialog]")(t):_.saveDraftAndGoToDrafts()})},_.saveDraftInPlace=function(){if(!_.isLoggedIn)return void _.openLogin();if(!_.onSave)return;const t=_.onSave();t&&"function"==typeof t.catch&&t.catch(function(){})},_.saveDraftAndGoToDrafts=function(){if(!_.isLoggedIn)return void _.openLogin();const e=_.getAfterSaveRedirectPath();if(!_.onSave)return void l.path(e);const n=_.onSave();n&&"function"==typeof n.then?n.then(function(){l.path(e),t.$applyAsync()}).catch(function(){}):n&&l.path(e)},_.getLastVersionSavedTooltip=function(){return _._savedTimeCache||""},_.publish=function(){if(_.onPublish&&!_.isPublishing&&!_._publishDialogOpen){if(_.onValidateBeforePublish)try{const t=_.onValidateBeforePublish();if(!1===t)return;if(t&&"function"==typeof t.then)return}catch(t){return}b()?v():(_._publishDialogOpen=!0,c.open({title:(0,s.t)("ÐпÑбликоваÑÑ?"),message:(0,s.t)("ÐоÑле пÑбликаÑии маÑеÑиал ÑÑÐ°Ð½ÐµÑ Ð´Ð¾ÑÑÑпен ÑиÑаÑелÑм"),confirmText:(0,s.t)("ÐпÑбликоваÑÑ"),cancelText:(0,s.t)("ÐÑмена")}).then(function(){v()},function(){c.onDismissed("[editorHeader.publish]")()}).catch(function(t){}).finally(function(){_._publishDialogOpen=!1}))}},_.navigateToPublished=function(){const t=_.getPublicUrl()||"/";if("/"===t)return void l.path("/");document.body.classList.add("is-navigating-from-editor");const e=document.createElement("div");e.id="editor-transition-overlay";const n=document.body.classList.contains("dark")?"#1e1e1e":"#fff";e.style.cssText="position:fixed;top:0;left:0;right:0;bottom:0;background:"+n+";z-index:var(--z-header-overlay, 100000);pointer-events:none;",document.body.appendChild(e),I&&o.cancel(I),I=o(function(){var t=document.getElementById("editor-transition-overlay");t&&t.remove(),document.body.classList.remove("is-navigating-from-editor")},8e3),S=o(function(){o.cancel(I),I=null,a.scrollTo(0,0),l.path(t)},0)},_.getPublicUrl=function(){if(_.contentLink&&"/"===_.contentLink.charAt(0))return _.contentLink;const t=l.path().replace(/^\/edit/,"").replace(/\/preview$/,"");
1return t&&/^\/(articles|expo)\//.test(t)?t:null},_.getAfterSaveRedirectPath=function(){if(("published"===_.contentStatus||"featured"===_.contentStatus)&&!1===_.isAuthor){const t=_.getPublicUrl();return t&&"/"!==t?t:"/drafts"}return"/drafts"},_.openInviteModal=function(){_.onOpenInvite&&_.onOpenInvite()},_.toggleToolsPanel=function(t){t&&t.stopPropagation(),_.toolsPanelOpen?_.closeToolsPanel():_.openToolsPanel()},_.openToolsPanel=function(){_.removeToolsPanelHandlers(),_.toolsPanelOpen=!0,L=o(function(){M=function(e){if(!_.toolsPanelOpen)return;const n=e.target;n&&n.closest&&n.closest(".editor-header__tools-wrapper")||t.$applyAsync(function(){_.closeToolsPanel()})},P=function(e){"Escape"!==e.key&&27!==e.keyCode||t.$applyAsync(function(){_.closeToolsPanel()})},E=function(){document.hidden&&_.toolsPanelOpen&&t.$applyAsync(function(){_.closeToolsPanel()})},document.addEventListener("mousedown",M,!0),document.addEventListener("touchstart",M,{capture:!0,passive:!0}),document.addEventListener("keydown",P,!0),document.addEventListener("visibilitychange",E)},0)},_.closeToolsPanel=function(){_.toolsPanelOpen=!1,_.removeToolsPanelHandlers()},_.removeToolsPanelHandlers=function(){M&&(document.removeEventListener("mousedown",M,!0),document.removeEventListener("touchstart",M,{capture:!0,passive:!0}),M=null),P&&(document.removeEventListener("keydown",P,!0),P=null),E&&(document.removeEventListener("visibilitychange",E),E=null),L&&(o.cancel(L),L=null)},_.toggleNightMode=function(){_.onToggleNightMode&&_.onToggleNightMode(),_.closeToolsPanel()},_.toggleMarginViewFromTools=function(){_.onToggleMarginView&&_.onToggleMarginView(),_.closeToolsPanel()},_.toggleQuietModeFromTools=function(){_.onToggleQuietMode&&_.onToggleQuietMode(),_.closeToolsPanel()},_.toggleLanguageTool=function(){if(!_.tiptapEditor)return;if(_.ltEnabled)return void(_.tiptapEditor.commands.disableLanguageTool&&(_.tiptapEditor.commands.disableLanguageTool(),_.ltEnabled=!1));let t=!1;try{t=!!localStorage.getItem("lt-privacy-accepted")}catch(t){}t?f():c.open({title:(0,s.t)("ÐÑовеÑка гÑаммаÑики"),message:(0,s.t)("ÐÐ»Ñ Ð¿ÑовеÑки оÑÑогÑаÑии и гÑаммаÑики ÑекÑÑ ÑÑаÑÑи бÑÐ´ÐµÑ Ð¾ÑпÑавлен на ÑеÑÐ²ÐµÑ Ð¿ÑоекÑа LanguageTool. ÐапÑÑÑиÑÑ?"),confirmText:(0,s.t)("ÐклÑÑиÑÑ"),cancelText:(0,s.t)("ÐÑмена")}).then(function(){try{localStorage.setItem("lt-privacy-accepted","1")}catch(t){}f()}).catch(function(){c.onDismissed("[editorHeader.toggleLanguageTool]")()})},_.runTypographer=function(){if(_.onRunTypographer){const e=_.onRunTypographer();e&&"function"==typeof e.then?e.catch(function(t){}).finally(function(){t.$$destroyed||(h(),t.$applyAsync())}):h()}},_.cleanHtmlContent=function(){_.tiptapEditor&&_.tiptapEditor.commands.cleanHtmlContent&&(_.tiptapEditor.commands.cleanHtmlContent({preserveEmptyParagraphs:!0,stripUnderline:!0}),_.onCleanCode&&_.onCleanCode(),_.cleanCodeDone=!0,A&&o.cancel(A),A=o(function(){_.cleanCodeDone=!1},4e3))},_.openSearchReplace=function(){_.tiptapEditor&&_.tiptapEditor.commands.openSearchReplace&&_.tiptapEditor.commands.openSearchReplace(!0)},_.openSettings=function(){_.closeToolsPanel(),_.onOpenSettings&&_.onOpenSettings()},_.retryConnection=function(){_.onRetryConnection&&_.onRetryConnection()},_.getLastModifiedFormatted=function(){return _.lastModifiedFormatted},_.statusText="ЧеÑновик",_.statusClass="draft",_.publishButtonText="ÐпÑбликоваÑÑ",_.toolsPublishText="ÐпÑбликоваÑÑ",_.getStatusTitle=function(){if(_.collabPermissionDenied)return"ТолÑко ÑÑение";if(_.isOfflineMode)return"ÐвÑономнÑй Ñежим";switch(_.collabStatus){case"synced":return"СинÑ
ÑонизиÑовано";case"connected":return"ÐодклÑÑено";case"connecting":return"ÐодклÑÑение...";case"disconnected":return"Соединение поÑеÑÑно";default:return"ÐокалÑнÑй Ñежим"}},_.getStatusDescription=function(){if(_.collabPermissionDenied)return"У Ð²Ð°Ñ Ð½ÐµÑ Ð¿Ñав на ÑедакÑиÑование ÑÑого доÐ
1ºÑменÑа. ÐÑкÑÑÑо в Ñежиме пÑоÑмоÑÑа.";if(_.isOfflineMode)return"СовмеÑÑÐ½Ð°Ñ Ð¿Ñавка недоÑÑÑпна. ÐажмиÑе «ÐеÑеподклÑÑиÑÑÑÑ»; пÑавки пока не доÑли до ÑовмеÑÑной комнаÑÑ.";if(_.isReconnecting)return"ÐопÑÑка воÑÑÑановиÑÑ Ñоединение Ñ ÑеÑвеÑом...";switch(_.collabStatus){case"synced":return"ÐÑе Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÑинÑ
ÑонизиÑÐ¾Ð²Ð°Ð½Ñ Ñ ÑеÑвеÑом. ÐÑÑгие авÑоÑÑ Ð²Ð¸Ð´ÑÑ Ð²Ð°Ñи пÑавки в ÑеалÑном вÑемени.";case"connected":return"Соединение ÑÑÑановлено, идÑÑ ÑинÑ
ÑонизаÑÐ¸Ñ Ð´Ð¾ÐºÑменÑа...";case"connecting":return"УÑÑанавливаеÑÑÑ Ñоединение Ñ ÑеÑвеÑом ÑовмеÑÑного ÑедакÑиÑованиÑ...";case"disconnected":return"СвÑÐ·Ñ Ð¿Ð¾ÑеÑÑна. ÐовÑоÑÑем подклÑÑение; пÑавки пока не доÑли до ÑовмеÑÑной комнаÑÑ.";default:return"РабоÑа без ÑинÑ
ÑонизаÑии. ÐÐ·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÑоÑ
ÑанÑÑÑÑÑ ÑолÑко на ÑеÑвеÑ."}},_.handleScroll=function(){D||(D=setTimeout(function(){D=null;const e=a.scrollY>0;if(!(H&&H.isConnected||(H=document.querySelector(".discours-editor.tiptap-mode"),H)))return void(_.isScrolled!==e&&t.$applyAsync(function(){_.isScrolled=e}));let n=!1;if(H){const t=H.getBoundingClientRect();n=t.bottom<0||t.top>a.innerHeight}_.isScrolled===e&&_.helpBtnHidden===n||t.$applyAsync(function(){_.isScrolled=e,_.helpBtnHidden=n})},16))}}]})},12849(){!function t(e){try{var n=document.querySelector("[ng-app]")||document.body,i=angular.element(n).injector();if(!i)return e<5?void setTimeout(function(){t(e+1)},50*Math.pow(2,e)):void 0;var s=i.get("$templateCache");s.put("/components/editorHeader/editorHeader.html",'<style> .editor-header .custom-tooltip, .editor-header .mode-tooltip, .editor-header .help-btn-tooltip, .editor-header .save-btn-tooltip, .editor-header .invite-btn-tooltip, .editor-header .panel-btn-tooltip, .editor-header .tools-btn-tooltip { opacity: 0; visibility: hidden; position: absolute; pointer-events: none; } /* ÐÑиÑиÑеÑкий CSS: ÑкÑÑÑие панели инÑÑÑÑменÑов до загÑÑзки editor.css */ .editor-header__tools-panel { opacity: 0; visibility: hidden; position: absolute; pointer-events: none; } @media (max-width: 991px), (hover: none) { .editor-header .custom-tooltip, .editor-header .mode-tooltip, .editor-header .help-btn-tooltip, .editor-header .save-btn-tooltip, .editor-header .invite-btn-tooltip, .editor-header .panel-btn-tooltip, .editor-header .tools-btn-tooltip { display: none !important; } .editor-header__content-badge, .editor-header__title { display: none !important; } } </style> <div class="editor-header" ng-class="{\'editor-header--scrolled\': $ctrl.isScrolled, \'editor-header--loading\': $ctrl.collabSyncPending }" > <div class="editor-header__container"> <div class="editor-header__logo"> <a href="/" class="logo-link"> <img class="logo-img" src="/images/logo-mini.svg" alt="Discours" loading="eager" width="26" height="28" /> </a> </div> <div class="editor-header__title" ng-if="$ctrl.docTitle"> <span class="title-text">{{ $ctrl.docTitle }}</span> <span class="custom-tooltip custom-tooltip--title">{{ $ctrl.docTitle }}</span> </div> <span class="editor-header__content-badge editor-header__content-badge--{{ $ctrl.statusClass }}" ng-if="$ctrl.statusText" >{{ $ctrl.statusText | t }}</span > <span class="editor-header__save-status" ng-if="$ctrl.showCollabControls && $ctrl.slug"> <span ng-if="$ctrl.isSaving" class="save-status save-status--saving"> <i class="fas fa-circle-notch fa-spin"></i> {{ \'СоÑ
Ñанениеâ¦\' | t }} </span> <span ng-if="!$ctrl.isSaving && $ctrl.isSaveSuccess" class="save-status save-status--saved"> <i class="fas fa-check"></i> {{ \'СоÑ
Ñанено\' | t }} </span> <span ng-if="!$ctrl.isSaving && $ctrl.isSaveError" class="save-status save-status--error"> <i class="fas fa-exclamation-triangle"></i> {{ \'ÐÑибка ÑоÑ
ÑанениÑ\' | t }} <span class="custom-tooltip" aria-hidden="true">{{ \'ÐÑовеÑÑÑе Ñоединение\' | t }}</span> </span> </span> <div class="editor-header__spacer"></div> <div class="editor-header__users" ng-if="$ctrl.connectedUsers && $ctrl.connectedUsers.length > 0" > <div class="user-avatar" ng-repeat="user in $ctrl.connectedUsers | limitTo:5 track by user.clientId" ng-style="{ \'border-color\': user.color }" ng-class="{\'user-avatar--no-cursor\': !$ctrl.hasCursorPosition(user) }" ng-click="$ctrl.scrollToUserCursor(user)" > <img ng-if="user.avatar" ng-src="{{ user.avatar | imageUrl: 64:64 }}" alt="{{ user.name }}" /> <span ng-if="!user.avatar" class="avatar-initial" ng-style="{ \'background\': user.color }"> {{ (user.name || \'?\').charAt(0).toUpperCase() }}
1 </span> <span class="custom-tooltip" >{{ user.name }}{{ $ctrl.hasCursorPosition(user) ? \' â \' + (\'пеÑейÑи к кÑÑÑоÑÑ\' | t) : \'\' }}</span > </div> <div class="user-avatar user-avatar--more" ng-if="$ctrl.connectedUsers && $ctrl.connectedUsers.length > 5" > +{{ $ctrl.connectedUsers.length - 5 }} <span class="custom-tooltip">{{ $ctrl.connectedUsers.length - 5 }} {{ \'еÑÑ\' | t }}</span> </div> </div> <button type="button" class="editor-header__panel-btn" aria-label="{{ \'ÐÐ°Ð½ÐµÐ»Ñ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑиев и пÑавок\' | t }}" ng-attr-aria-pressed="{{ !!$ctrl.sidebarVisible }}" ng-if="$ctrl.showPanelButton" ng-class="{ active: $ctrl.sidebarVisible, \'moved-to-margin\': !$ctrl.marginViewMode }" ng-disabled="$ctrl.collabSyncPending" ng-click="$ctrl.toggleSidebar()" > <svg width="21" height="17" viewBox="0 0 21 17" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M3.88021 0C3.03125 0 2.32031 0.151042 1.74219 0.450522C1.16667 0.75 0.731771 1.1875 0.440104 1.76302C0.145833 2.34115 0 3.04688 0 3.88021V6.52604C0 7.35938 0.145833 8.06511 0.440104 8.64063C0.734375 9.21615 1.16667 9.65625 1.74219 9.95573C2.32031 10.2552 2.95573 10.4063 3.80469 10.4063V12.4635C3.80469 12.8229 3.89323 13.1068 4.06771 13.3177C4.24479 13.5286 4.49479 13.6328 4.81771 13.6328C5.04687 13.6328 5.2526 13.5729 5.4401 13.4531C5.625 13.3307 5.85937 13.1432 6.14323 12.888L8.91406 10.4063H11.1536C12 10.4063 12.7135 10.2552 13.2891 9.95573C13.8646 9.65625 14.2995 9.21615 14.5911 8.64063C14.8854 8.06511 15.0312 7.35938 15.0312 6.52604V3.88021C15.0312 3.04427 14.8854 2.34115 14.5911 1.76302C14.2995 1.1875 13.8646 0.75 13.2891 0.450522C12.7135 0.151042 12 0 11.1536 0H3.88021ZM3.88021 1.5H11.1536C11.987 1.5 12.5938 1.69792 12.974 2.09635C13.3542 2.49219 13.5417 3.08594 13.5417 3.88021V6.52604C13.5417 7.31771 13.3542 7.91667 12.974 8.31511C12.5938 8.71615 11.987 8.91667 11.1536 8.91667H8.83333C8.58594 8.91667 8.38281 8.94011 8.22656 8.99219C8.07292 9.04427 7.91146 9.16146 7.7474 9.33854L5.20052 11.9349V9.60938C5.20052 9.35417 5.14844 9.17448 5.04167 9.07031C4.9349 8.96615 4.75521 8.91667 4.50781 8.91667H3.88021C3.04427 8.91667 2.4375 8.71615 2.0599 8.31511C1.67969 7.91667 1.48958 7.31771 1.48958 6.52604V3.88021C1.48958 3.08594 1.67969 2.49219 2.0599 2.09635C2.4375 1.69792 3.04427 1.5 3.88021 1.5ZM16.1016 3C16.1406 3.28125 16.1589 3.57292 16.1589 3.88021V4.5H16.2708C17.1068 4.5 17.7161 4.69792 18.0938 5.09635C18.4714 5.48958 18.6641 6.08594 18.6641 6.88021V9.59375C18.6641 10.388 18.4714 10.9844 18.0938 11.3802C17.7161 11.7839 17.1068 11.9818 16.2708 11.9818H15.6458C15.3984 11.9818 15.2188 12.0339 15.112 12.138C15.0052 12.2396 14.9505 12.4193 14.9505 12.6745V15.0052L12.4062 12.4089C12.2396 12.2292 12.0781 12.112 11.9245 12.0599C11.7708 12.0078 11.5677 11.9818 11.3203 11.9818C8.80729 11.9818 8.96094 11.9844 8.92188 11.9766L7.47656 13.2682C7.78646 13.362 8.27344 13.474 9 13.474H11.2344L14.0104 15.9557C14.2917 16.2109 14.5286 16.3984 14.7109 16.5182C14.8984 16.638 15.1042 16.6979 15.3333 16.6979C15.6562 16.6979 15.9089 16.5938 16.0833 16.3828C16.2604 16.1745 16.3464 15.888 16.3464 15.5339V13.474C17.1979 13.474 17.8307 13.3255 18.4089 13.0234C18.987 12.724 19.4167 12.2839 19.7135 11.7083C20.0052 11.1328 20.1536 10.4297 20.1536 9.59375V6.88021C20.1536 6.04427 20.0052 5.34115 19.7135 4.76302C19.4167 4.1875 18.987 3.75 18.4089 3.45052C17.8307 3.15104 17.1224 3 16.2708 3H16.1016ZM3.89583 3.7526C3.60156 3.7526 3.3776 3.99219 3.3776 4.27865C3.3776 4.57031 3.60156 4.80729 3.89583 4.80729H11.3281C11.6224 4.80729 11.8464 4.56771 11.8464 4.27865C11.8464 3.98958 11.6224 3.7526 11.3281 3.7526H3.89583ZM3.89583 6.01563C3.53385 6.01563 3.3776 6.33073 3.3776 6.55208C3.3776 6.84115 3.60156 7.07031 3.89583 7.07031H8.81771C9.10677 7.07031 9.33594 6.84635 9.33594 6.55208C9.33594 6.33594 9.17969 6.01563 8.81771 6.01563H3.89583Z" fill="currentColor" /> </svg> <span class="panel-counter" ng-if="$ctrl.pendingCount > 0">{{ $ctrl.pendingCount }}</span> <span class="panel-btn-tooltip">{{ \'ÐÐ°Ð½ÐµÐ»Ñ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑиев и пÑавок\' | t }}</span> </button> <button type="button" class="editor-header__mode-toggle-btn" aria-label="{{ \'ÐеÑеклÑÑиÑÑ Ñежим пÑоÑмоÑÑа\' | t }}
1" ng-if="!$ctrl.showSuggestionMode" ng-click="$ctrl.togglePreviewMode()" > <span ng-if="$ctrl.currentMode !== \'preview\'">{{ \'ÐÑедпÑоÑмоÑÑ\' | t }}</span> <span ng-if="$ctrl.currentMode === \'preview\'">{{ \'РедакÑиÑоваÑÑ\' | t }}</span> </button> <button type="button" class="editor-header__mode-toggle-btn" aria-label="{{ \'ÐеÑеклÑÑиÑÑ Ñежим пÑоÑмоÑÑа\' | t }}" ng-if="$ctrl.showSuggestionMode && !$ctrl.canEdit" ng-click="$ctrl.togglePreviewMode()" > <span ng-if="$ctrl.currentMode !== \'preview\'">{{ \'ÐÑедпÑоÑмоÑÑ\' | t }}</span> <span ng-if="$ctrl.currentMode === \'preview\'">{{ \'ÐомменÑиÑование\' | t }}</span> </button> <div class="editor-header__mode-switcher" ng-class="{ open: $ctrl.modeSwitcherOpen }" ng-if="$ctrl.showSuggestionMode && $ctrl.canEdit" > <button type="button" class="mode-switcher-toggle" aria-label="{{ \'ÐÑбÑаÑÑ Ñежим ÑедакÑоÑа\' | t }}" aria-haspopup="true" aria-expanded="{{ $ctrl.modeSwitcherOpen }}" ng-click="$ctrl.toggleModeSwitcher()" ng-blur="$ctrl.closeModeSwitcherDelayed()" > <span class="mode-tooltip">{{ \'Режим ÑедакÑоÑа\' | t }}</span> <span class="mode-icon" ng-if="$ctrl.currentMode === \'preview\'"> <svg width="21" height="14" viewBox="0 0 21 14" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M10.125 0C4.6875 0 0 4.52865 0 6.75C0 8.97135 4.6875 13.5 10.125 13.5C15.5625 13.5 20.25 8.97135 20.25 6.75C20.25 4.52865 15.5625 0 10.125 0ZM10.125 1.5C14.9792 1.5 18.75 5.6875 18.75 6.75C18.75 7.8125 14.9792 12 10.125 12C5.27083 12 1.5 7.8125 1.5 6.75C1.5 5.6875 5.27083 1.5 10.125 1.5ZM10.125 2.625C7.84635 2.625 6 4.47135 6 6.75C6 9.02865 7.84635 10.875 10.125 10.875C12.4036 10.875 14.25 9.02865 14.25 6.75C14.25 4.47135 12.4036 2.625 10.125 2.625ZM10.125 5.25C10.9531 5.25 11.625 5.92188 11.625 6.75C11.625 7.57813 10.9531 8.25 10.125 8.25C9.29688 8.25 8.625 7.57813 8.625 6.75C8.625 5.92188 9.29688 5.25 10.125 5.25Z" fill="currentColor" /> </svg> </span> <span class="mode-icon" ng-if="$ctrl.currentMode === \'editing\'"> <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M17.9975 4.89363L13.1038 0L0 13.1064V18H4.89363L17.9975 4.89363ZM13.105 2.55674L15.4421 4.89383L14.4612 5.87591L12.1241 3.53882L13.105 2.55674ZM10.8453 4.81648L13.1824 7.15357L5.42174 14.9137L3.08485 12.5756L10.8453 4.81648ZM1.80725 16.1915V13.8544L4.14434 16.1915H1.80725Z" fill="currentColor" /> </svg> </span> <span class="mode-icon" ng-if="$ctrl.currentMode === \'suggesting\'"> <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" > <mask id="mask0_toggle" style="mask-type: alpha" maskUnits="userSpaceOnUse" x="0" y="14" width="4" height="4" > <rect y="14.8242" width="3.17647" height="3.17647" fill="#C4C4C4" /> </mask> <g mask="url(#mask0_toggle)"> <path d="M16.0941 1.05859H0.847027C0.379194 1.05859 0 1.43779 0 1.90562V17.9998L3.38824 14.6115H16.0942C16.562 14.6115 16.9412 14.2323 16.9412 13.7645V1.90565C16.9412 1.43782 16.562 1.05863 16.0942 1.05863L16.0941 1.05859ZM15.2471 12.9174H1.69412V2.75271H15.2471V12.9174Z" fill="currentColor" /> </g> <rect x="1" y="1" width="16" height="12.8235" stroke="currentColor" stroke-width="2" /> <rect x="4.23438" y="3.17578" width="9.52941" height="2.11765" fill="currentColor" /> <rect x="4.23438" y="9.5293" width="7.41176" height="2.11765" fill="currentColor" /> <rect x="4.23438" y="6.35352" width="5.29412" height="2.11765" fill="currentColor" /> </svg> </span> <span class="mode-label"> <span ng-if="$ctrl.currentMode === \'preview\'">{{ \'ÐÑедпÑоÑмоÑÑ\' | t }}</span> <span ng-if="$ctrl.currentMode === \'editing\'">{{ \'РедакÑиÑование\' | t }}</span> <span ng-if="$ctrl.currentMode === \'suggesting\'">{{ \'ÐомменÑиÑование\' | t }}</span> </span> <i class="fas fa-chevron-down mode-chevron"></i> </button> <div class="mode-switcher-dropdown" role="menu"> <div class="mode-dropdown-content"> <button type="button" class="mode-option" role="menuitem" ng-class="{ active: $ctrl.currentMode === \'preview\' }" ng-mousedown="$event.preventDefault(); $ctrl.setMode(\'preview\')" ng-click="$ctrl.setMode(\'preview\')" > <div class="mode-option-header"> <span class="mode-option-icon"> <svg width="21" height="14" viewBox="0 0 21 14" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M10.125 0C4.6875 0 0 4.52865 0 6.75C0 8.97135 4.6875 13.5 10.125 13.5C15.5625 13.5 20.25 8.97135 20.25 6.75C20.25 4.52865 15.5625 0 10.125 0ZM10.125 1.5C14.9792 1.5 18.75 5.687
15 18.75 6.75C18.75 7.8125 14.9792 12 10.125 12C5.27083 12 1.5 7.8125 1.5 6.75C1.5 5.6875 5.27083 1.5 10.125 1.5ZM10.125 2.625C7.84635 2.625 6 4.47135 6 6.75C6 9.02865 7.84635 10.875 10.125 10.875C12.4036 10.875 14.25 9.02865 14.25 6.75C14.25 4.47135 12.4036 2.625 10.125 2.625ZM10.125 5.25C10.9531 5.25 11.625 5.92188 11.625 6.75C11.625 7.57813 10.9531 8.25 10.125 8.25C9.29688 8.25 8.625 7.57813 8.625 6.75C8.625 5.92188 9.29688 5.25 10.125 5.25Z" fill="currentColor" /> </svg> </span> <span class="mode-option-title">{{ \'ÐÑедпÑоÑмоÑÑ\' | t }}</span> </div> <div class="mode-option-desc"> {{ \'ÐоÑмоÑÑиÑе как маÑеÑиал бÑÐ´ÐµÑ Ð²ÑглÑдеÑÑ Ð¿Ñи пÑбликаÑии\' | t }} </div> </button> <button type="button" class="mode-option" role="menuitem" ng-class="{ active: $ctrl.currentMode === \'editing\' }" ng-mousedown="$event.preventDefault(); $ctrl.setMode(\'editing\')" ng-click="$ctrl.setMode(\'editing\')" ng-if="$ctrl.canEdit" > <div class="mode-option-header"> <span class="mode-option-icon"> <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M17.9975 4.89363L13.1038 0L0 13.1064V18H4.89363L17.9975 4.89363ZM13.105 2.55674L15.4421 4.89383L14.4612 5.87591L12.1241 3.53882L13.105 2.55674ZM10.8453 4.81648L13.1824 7.15357L5.42174 14.9137L3.08485 12.5756L10.8453 4.81648ZM1.80725 16.1915V13.8544L4.14434 16.1915H1.80725Z" fill="currentColor" /> </svg> </span> <span class="mode-option-title">{{ \'РедакÑиÑование\' | t }}</span> </div> <div class="mode-option-desc">{{ \'ÐиÑиÑе и ÑедакÑиÑÑйÑе ÑекÑÑ Ð½Ð°Ð¿ÑÑмÑÑ\' | t }}</div> </button> <button type="button" class="mode-option" role="menuitem" ng-if="$ctrl.showSuggestionMode" ng-class="{ active: $ctrl.currentMode === \'suggesting\' }" ng-mousedown="$event.preventDefault(); $ctrl.setMode(\'suggesting\')" ng-click="$ctrl.setMode(\'suggesting\')" > <div class="mode-option-header"> <span class="mode-option-icon"> <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" > <mask id="mask0_dropdown" style="mask-type: alpha" maskUnits="userSpaceOnUse" x="0" y="14" width="4" height="4" > <rect y="14.8242" width="3.17647" height="3.17647" fill="#C4C4C4" /> </mask> <g mask="url(#mask0_dropdown)"> <path d="M16.0941 1.05859H0.847027C0.379194 1.05859 0 1.43779 0 1.90562V17.9998L3.38824 14.6115H16.0942C16.562 14.6115 16.9412 14.2323 16.9412 13.7645V1.90565C16.9412 1.43782 16.562 1.05863 16.0942 1.05863L16.0941 1.05859ZM15.2471 12.9174H1.69412V2.75271H15.2471V12.9174Z" fill="currentColor" /> </g> <rect x="1" y="1" width="16" height="12.8235" stroke="currentColor" stroke-width="2" /> <rect x="4.23438" y="3.17578" width="9.52941" height="2.11765" fill="currentColor" /> <rect x="4.23438" y="9.5293" width="7.41176" height="2.11765" fill="currentColor" /> <rect x="4.23438" y="6.35352" width="5.29412" height="2.11765" fill="currentColor" /> </svg> </span> <span class="mode-option-title">{{ \'ÐомменÑиÑование\' | t }}</span> </div> <div class="mode-option-desc"> {{ \'ÐÑедлагайÑе пÑавки и комменÑаÑии, ÑÑÐ¾Ð±Ñ ÑделаÑÑ ÑекÑÑ Ð»ÑÑÑе\' | t }} </div> </button> </div> </div> </div> <button type="button" class="editor-header__invite-btn" aria-label="{{ \'ÐÑиглаÑиÑÑ ÑоавÑоÑов\' | t }}" ng-if="$ctrl.showInviteButton && $ctrl.canEdit" ng-click="$ctrl.openInviteModal()" > <svg class="invite-btn-icon" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M8.667 7.333a2.667 2.667 0 100-5.333 2.667 2.667 0 000 5.333zM1.333 14c0-2.946 3.283-5.333 7.333-5.333.598 0 1.179.059 1.733.168M12 10.667v4M10 12.667h4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" /> </svg> <span class="invite-btn-text">{{ \'ÐÑиглаÑиÑÑ\' | t }}</span> <span class="invite-btn-tooltip">{{ \'ÐÑиглаÑиÑÑ ÑоавÑоÑов\' | t }}</span> </button> <button type="button" class="editor-header__save-btn" ng-if="$ctrl.canEdit && $ctrl.onSave" ng-click="$ctrl.save()" ng-disabled="$ctrl.isSavingVersion || $ctrl.isSaving || $ctrl.isPublishing || $ctrl.isSaveSuccess" ng-class="{\'save-btn--success\': $ctrl.isSaveSuccess }" aria-label="{{ \'СоÑ
ÑаниÑÑ\' | t }}" aria-busy="{{ $ctrl.isSavingVersion }}" >
1 <span ng-if="!$ctrl.isSavingVersion && !$ctrl.isSaveSuccess">{{ \'СоÑ
ÑаниÑÑ\' | t }}</span> <span ng-if="$ctrl.isSavingVersion"><i class="fas fa-sync-alt fa-spin"></i></span> <span ng-if="$ctrl.isSaveSuccess">{{ \'СоÑ
Ñанено\' | t }}</span> <span class="save-btn-tooltip" ng-if="!$ctrl.isSaveSuccess" >{{ \'СоÑ
ÑаниÑÑ\' | t }} ({{ $ctrl.isMac ? \'âS\' : \'Ctrl+S\' }})</span > <span class="save-btn-tooltip" ng-if="$ctrl.isSaveSuccess" >{{ \'СоÑ
Ñанено в\' | t }} {{ $ctrl.getLastVersionSavedTooltip() }}</span > </button> <button type="button" class="editor-header__save-btn" ng-if="$ctrl.canEdit && !$ctrl.onSave && $ctrl.slug" ng-click="$ctrl.publish()" ng-disabled="$ctrl.isPublishing" aria-label="{{ $ctrl.publishButtonText | t }}" > <span ng-if="!$ctrl.isPublishing">{{ $ctrl.publishButtonText | t }}</span> <span ng-if="$ctrl.isPublishing"><i class="fas fa-sync-alt fa-spin"></i></span> </button> <div class="editor-header__tools-wrapper" ng-class="{ open: $ctrl.toolsPanelOpen,\'status--synced\': $ctrl.collabStatus === \'synced\', \'status--connected\': $ctrl.collabStatus === \'connected\', \'status--connecting\': $ctrl.collabStatus === \'connecting\' || $ctrl.isReconnecting, \'status--disconnected\': $ctrl.collabStatus === \'disconnected\', \'status--offline\': $ctrl.isOfflineMode || $ctrl.collabStatus === \'offline\', \'status--local\': !$ctrl.collabStatus && !$ctrl.isOfflineMode }" > <button type="button" class="editor-header__tools-btn" aria-label="{{ \'ÐнÑÑÑÑменÑÑ Ð¸ наÑÑÑойки\' | t }}" aria-haspopup="true" aria-expanded="{{ !!$ctrl.toolsPanelOpen }}" ng-click="$ctrl.toggleToolsPanel($event)" > <svg width="18" height="4" viewBox="0 0 18 4" fill="none" xmlns="http://www.w3.org/2000/svg" > <circle cx="2" cy="2" r="2" fill="currentColor" /> <circle cx="9" cy="2" r="2" class="status-dot-mid" fill="currentColor" /> <circle cx="16" cy="2" r="2" fill="currentColor" /> </svg> <span class="tools-btn-tooltip">{{ \'ÐнÑÑÑÑменÑÑ\' | t }}</span> </button> <div class="editor-header__tools-panel" ng-class="{\'tools-panel--open\': $ctrl.toolsPanelOpen }" role="menu" aria-label="{{ \'ÐнÑÑÑÑменÑÑ ÑедакÑоÑа\' | t }}" > <div class="tools-panel__section"> <button type="button" class="tools-panel__item" role="menuitem" ng-if="$ctrl.canEdit" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.publish(); $ctrl.closeToolsPanel()" ng-disabled="$ctrl.isPublishing" > <span class="tools-panel__item-icon"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <circle cx="10" cy="10" r="7.5" stroke="currentColor" stroke-width="1.5" /> <path d="M10 2.5c-2.5 3-2.5 9.5 0 15" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" /> <path d="M10 2.5c2.5 3 2.5 9.5 0 15" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" /> <path d="M2.5 10h15M3.5 6.5h13M3.5 13.5h13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" /> </svg> </span> <span class="tools-panel__item-title">{{ $ctrl.toolsPublishText | t }}</span> </button> <button type="button" class="tools-panel__item" role="menuitem" ng-if="$ctrl.canEdit && $ctrl.onSave" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.saveDraftInPlace()" ng-disabled="$ctrl.isSaving || $ctrl.isSaveSuccess" > <span class="tools-panel__item-icon"> <i ng-if="$ctrl.isSaving" class="fas fa-sync-alt fa-spin"></i> <svg ng-if="!$ctrl.isSaving" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M3.5 4.5A1 1 0 014.5 3.5h8.172a1 1 0 01.707.293l2.828 2.828a1 1 0 01.293.707V15.5a1 1 0 01-1 1h-11a1 1 0 01-1-1v-11z" stroke="currentColor" stroke-width="1.5" /> <path d="M7 3.5V7h5.5V3.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> <rect x="5.5" y="11" width="9" height="5.5" rx="0.5" stroke="currentColor" stroke-width="1.5" /> </svg> </span> <span class="tools-panel__item-title">{{ \'СоÑ
ÑаниÑÑ ÑеÑновик\' | t }}</span> <span class="tools-panel__item-sub tools-panel__item-sub--success" ng-if="$ctrl.isSaveSuccess" >{{ \'СоÑ
Ñанено!\' | t }}</span > </button> <button type="button" class="tools-panel__item" role="menuitem" ng-if="$ctrl.showInviteButton" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.openInviteModal();
1 $ctrl.closeToolsPanel()" > <span class="tools-panel__item-icon"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M10.833 9.167a3.333 3.333 0 100-6.667 3.333 3.333 0 000 6.667zM1.667 17.5c0-3.682 4.104-6.667 9.166-6.667.748 0 1.474.074 2.167.21M15 13.333v5M12.5 15.833h5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> </span> <span class="tools-panel__item-title">{{ \'ÐÑиглаÑиÑÑ ÑоавÑоÑов\' | t }}</span> <span class="tools-panel__item-badge" ng-if="$ctrl.inviteCount > 0" >{{ $ctrl.inviteCount }}</span > </button> <div class="tools-panel__divider"></div> <button type="button" class="tools-panel__item" role="menuitem" ng-if="$ctrl.canEdit && $ctrl.isLoggedIn && $ctrl.onOpenSettings" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.openSettings()" > <span class="tools-panel__item-icon"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M10 12.5a2.5 2.5 0 100-5 2.5 2.5 0 000 5z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> <path d="M16.167 12.5a1.375 1.375 0 00.275 1.517l.05.05a1.667 1.667 0 11-2.359 2.358l-.05-.05a1.375 1.375 0 00-1.516-.275 1.375 1.375 0 00-.834 1.258v.142a1.667 1.667 0 11-3.333 0v-.075a1.375 1.375 0 00-.9-1.258 1.375 1.375 0 00-1.517.275l-.05.05a1.667 1.667 0 11-2.358-2.358l.05-.05a1.375 1.375 0 00.275-1.517 1.375 1.375 0 00-1.258-.833H2.5a1.667 1.667 0 110-3.334h.075a1.375 1.375 0 001.258-.9 1.375 1.375 0 00-.275-1.516l-.05-.05A1.667 1.667 0 115.867 3.78l.05.05a1.375 1.375 0 001.516.275h.067A1.375 1.375 0 008.333 2.85V2.5a1.667 1.667 0 113.334 0v.075a1.375 1.375 0 00.833 1.258 1.375 1.375 0 001.517-.275l.05-.05a1.667 1.667 0 112.358 2.359l-.05.05a1.375 1.375 0 00-.275 1.516v.067a1.375 1.375 0 001.258.833H17.5a1.667 1.667 0 110 3.334h-.075a1.375 1.375 0 00-1.258.833z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> </span> <span class="tools-panel__item-title">{{ \'ÐаÑÑÑойки пÑбликаÑии\' | t }}</span> </button> <button type="button" class="tools-panel__item" role="menuitem" ng-if="$ctrl.canEdit && $ctrl.tiptapEditor" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.openImportExport()" > <span class="tools-panel__item-icon"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M4 14.5V16a1.5 1.5 0 001.5 1.5h9A1.5 1.5 0 0016 16v-1.5M13.5 6L10 2.5 6.5 6M10 2.5v10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> </span> <span class="tools-panel__item-title">{{ \'ÐмпоÑÑ / ÐкÑпоÑÑ\' | t }}</span> </button> <div class="tools-panel__item-row" ng-if="$ctrl.slug && $ctrl.onVersionsClick"> <button type="button" class="tools-panel__item tools-panel__item--flex" role="menuitem" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.onVersionsClick(); $ctrl.closeToolsPanel()" > <span class="tools-panel__item-icon"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <circle cx="10" cy="10" r="7.5" stroke="currentColor" stroke-width="1.5" /> <path d="M10 7V10.5l2.5 1.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> </span> <span class="tools-panel__item-title">{{ \'ÐÑÑоÑÐ¸Ñ Ð²ÐµÑÑий\' | t }}</span> </button> <button type="button" class="tools-panel__save-version-btn" aria-label="{{ \'СоÑ
ÑаниÑÑ Ð²ÐµÑÑиÑ\' | t }}" ng-if="$ctrl.canEdit && $ctrl.onSaveVersionDialog" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.onSaveVersionDialog(); $ctrl.closeToolsPanel()" > <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M2 4a2 2 0 012-2h7.586a1 1 0 01.707.293l1.414 1.414A1 1 0 0114 4.414V13a1 1 0 01-1 1H3a1 1 0 01-1-1V4z" stroke="currentColor" stroke-width="1.2" /> <path d="M5 2v3h5V2M5 14v-4h6v4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" /> </svg> </button> </div> </div> <div class="tools-panel__divider"></div> <div class="tools-panel__section"> <button type="button" class="tools-panel__item" role="menuitem" ng-if="$ctrl.onRunTypographer && $ctrl.isAdmin" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.runTypographer()" > <span class="tools-panel__item-icon"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M4 15.5h12M6.5 12l3.5-8 3.5 8M8 9.5h4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> </span> <span class="tools-panel__item-title">{{ \'ÐвÑоÑипогÑаÑ\' | t }}</span> <span class="tools-panel__item-sub tools-panel__item-sub--success" ng-if="$ctrl.typographerDone" >{{ \'ÐоÑово!\' | t }}</span > </button> <button type="button" class="tools-panel__item" role="menuitem" ng-if="$ctrl.canEdit && $ctrl.tiptapEditor" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.toggleLanguageTool()" > <span class="tools-panel__item-icon"> <i ng-if="$ctrl.ltChecking" class="fas fa-sync-alt fa-spin" aria-hidden="true" ng-attr-aria-label="{{ \'ÐÑовеÑка...\' | t }}" ></i>
1 <svg ng-if="!$ctrl.ltChecking" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M3.333 5H10M3.333 8.333H10M3.333 11.667h5M13.333 10l-2.5 5 2.5-1.667 2.5 1.667-2.5-5z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> </span> <span class="tools-panel__item-title">{{ \'ÐÑовеÑка гÑаммаÑики\' | t }}</span> <span class="tools-panel__lt-rate-limit" ng-if="$ctrl.ltRateLimited" >â³<span class="custom-tooltip" aria-hidden="true" >{{ \'ÐÐ¸Ð¼Ð¸Ñ Ð·Ð°Ð¿ÑоÑов â повÑÐ¾Ñ ÑеÑез минÑÑÑ\' | t }}</span ></span > <div class="tools-panel__toggle" ng-class="{\'tools-panel__toggle--on\': $ctrl.ltEnabled }" > <div class="tools-panel__toggle-knob"></div> </div> </button> <button type="button" class="tools-panel__item tools-panel__item--margin-view" role="menuitem" ng-attr-aria-label="{{ \'ÐомменÑаÑии на полÑÑ
\' | t }}" ng-attr-aria-pressed="{{ $ctrl.marginViewMode ? \'true\' : \'false\' }}" ng-if="$ctrl.showCollabControls" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.toggleMarginViewFromTools()" > <span class="tools-panel__item-icon"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <rect x="2" y="3.5" width="10" height="13" rx="1" stroke="currentColor" stroke-width="1.5" /> <path d="M14.5 7h3M14.5 10h3M14.5 13h2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" /> <rect x="13" y="5.5" width="5" height="4" rx="1" stroke="currentColor" stroke-width="1.2" /> </svg> </span> <span class="tools-panel__item-title">{{ \'ÐомменÑаÑии на полÑÑ
\' | t }}</span> <div class="tools-panel__toggle" ng-class="{\'tools-panel__toggle--on\': $ctrl.marginViewMode }" > <div class="tools-panel__toggle-knob"></div> </div> </button> <button type="button" class="tools-panel__item" role="menuitem" ng-if="$ctrl.isAdmin" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.cleanHtmlContent()" > <span class="tools-panel__item-icon"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M7.5 4.167L3.333 10 7.5 15.833M12.5 4.167l4.167 5.833-4.167 5.833" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> </span> <span class="tools-panel__item-title">{{ \'ÐоÑиÑÑиÑÑ ÐºÐ¾Ð´\' | t }}</span> <span class="tools-panel__item-sub tools-panel__item-sub--success" ng-if="$ctrl.cleanCodeDone" >{{ \'ÐоÑово!\' | t }}</span > </button> <button type="button" class="tools-panel__item" role="menuitem" ng-if="$ctrl.tiptapEditor" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.openSearchReplace(); $ctrl.closeToolsPanel()" > <span class="tools-panel__item-icon"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M8.5 3a5.5 5.5 0 1 0 3.4 9.8l3.8 3.8M13.5 12.5l-2-2M6 8h5M6 11h3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> </span> <span class="tools-panel__item-title">{{ \'ÐайÑи и замениÑÑ\' | t }}</span> </button> <div class="tools-panel__divider"></div> <button type="button" class="tools-panel__item" role="menuitem" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.openShortcutsHelp(); $ctrl.closeToolsPanel()" > <span class="tools-panel__item-icon"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <rect x="1.667" y="4.167" width="16.667" height="11.667" rx="2" stroke="currentColor" stroke-width="1.5" /> <path d="M5 8.333h1.667M5 11.667h1.667M8.333 8.333h3.334M8.333 11.667H11.667M13.333 8.333H15M13.333 11.667H15" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" /> </svg> </span> <span class="tools-panel__item-title">{{ \'ÐоÑÑÑие клавиÑи\' | t }}</span> </button> <a class="tools-panel__item" href="/articles/theory/how-to-write-a-good-article" target="_blank" rel="noopener noreferrer" role="menuitem" ng-if="false" ng-click="$ctrl.closeToolsPanel
1()" > <span class="tools-panel__item-icon"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M10 2.5a7.5 7.5 0 100 15 7.5 7.5 0 000-15z" stroke="currentColor" stroke-width="1.5" /> <path d="M10 13.333v-5M10 6.667v-.834" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" /> </svg> </span> <span class="tools-panel__item-title">{{ \'Ðак напиÑаÑÑ Ñ
оÑоÑий ÑекÑÑ\' | t }}</span> </a> <button type="button" class="tools-panel__item" role="menuitem" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.openHelpModal()" > <span class="tools-panel__item-icon"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M10 2.5a7.5 7.5 0 100 15 7.5 7.5 0 000-15z" stroke="currentColor" stroke-width="1.5" /> <path d="M7.575 7.5a2.5 2.5 0 014.85.833c0 1.667-2.5 2.5-2.5 2.5M10 13.333h.008" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> </span> <span class="tools-panel__item-title">{{ \'ÐомоÑÑ\' | t }}</span> </button> </div> <div class="tools-panel__divider"></div> <div class="tools-panel__section"> <button type="button" class="tools-panel__item" role="menuitem" ng-attr-aria-pressed="{{ $ctrl.quietMode ? \'true\' : \'false\' }}" ng-if="$ctrl.showCollabControls" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.toggleQuietModeFromTools()" > <span class="tools-panel__item-icon"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M17.94 17.94A10.07 10.07 0 0112 20c-7 0-11-8-11-8a18.45 18.45 0 015.06-5.94M9.9 4.24A9.12 9.12 0 0112 4c7 0 11 8 11 8a18.5 18.5 0 01-2.16 3.19m-6.72-1.07a3 3 0 11-4.24-4.24" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> <line x1="1" y1="1" x2="23" y2="23" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" /> </svg> </span> <span class="tools-panel__item-title">{{ \'ТиÑ
ий Ñежим\' | t }}</span> <div class="tools-panel__toggle" ng-class="{\'tools-panel__toggle--on\': $ctrl.quietMode }" > <div class="tools-panel__toggle-knob"></div> </div> </button> <button type="button" class="tools-panel__item" role="menuitem" ng-attr-aria-pressed="{{ $ctrl.nightMode ? \'true\' : \'false\' }}" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.toggleNightMode()" > <span class="tools-panel__item-icon"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M17.5 10.833A7.5 7.5 0 019.167 2.5a7.5 7.5 0 000 15A7.5 7.5 0 0017.5 10.833z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> </span> <span class="tools-panel__item-title">{{ \'ÐоÑÐ½Ð°Ñ Ñема\' | t }}</span> <div class="tools-panel__toggle" ng-class="{\'tools-panel__toggle--on\': $ctrl.nightMode }" > <div class="tools-panel__toggle-knob"></div> </div> </button> </div> <div class="tools-panel__footer"> <div class="tools-panel__stats" ng-if="$ctrl.wordCount != null || $ctrl.charCount != null || $ctrl.paraCount != null" > <span>{{ $ctrl.wordCount | pluralize:\'Ñлово\':\'Ñлова\':\'Ñлов\' }}</span> <span class="tools-panel__stats-sep">·</span> <span>{{ $ctrl.charCount | pluralize:\'знак\':\'знака\':\'знаков\' }}</span> <span class="tools-panel__stats-sep">·</span> <span>{{ $ctrl.paraCount | pluralize:\'абзаÑ\':\'абзаÑа\':\'абзаÑев\' }}</span> </div> <div class="tools-panel__last-modified" ng-if="$ctrl.lastModifiedFormatted"> {{ \'ÐоÑледнее изменение:\' | t }} {{ $ctrl.lastModifiedFormatted }} </div> <div class="tools-panel__status-compact" ng-if="$ctrl.showCollabStatus" ng-class="{\'status--synced\': $ctrl.collabStatus === \'synced\', \'status--connected\': $ctrl.collabStatus === \'connected\', \'status--connecting\': $ctrl.collabStatus === \'connecting\' || $ctrl.isReconnecting, \'status--disconnected\': $ctrl.collabStatus === \'disconnected\', \'status--offline\': $ctrl.isOfflineMode || $ctrl.collabStatus === \'offline\' }" > <span class="tools-panel__status-dot-small"></span> <span class="tools-panel__status-compact-text">{{ $ctrl._statusTitleCache | t }}</span> <span class="tools-panel__status-hint" ng-if="$ctrl.statusDescription" ng-bind="$ctrl.statusDescription | t" ></span> <button type="button" class="tools-panel__status-compact-reconnect" ng-if="$ctrl.isOfflineMode || $ctrl.collabStatus === \'disconnected\'" ng-mousedown="$event.preventDefault()" ng-click="$ctrl.retryConnection()" ng-disabled="$ctrl.isReconnecting" >
1 <i ng-if="!$ctrl.isReconnecting" class="fas fa-redo"></i> <i ng-if="$ctrl.isReconnecting" class="fas fa-sync-alt fa-spin"></i> <span ng-if="!$ctrl.isReconnecting">{{ \'ÐеÑеподклÑÑиÑÑÑÑ\' | t }}</span> </button> </div> </div> </div> </div> <div class="editor-header__avatar" ng-if="!$ctrl.isLoggedIn"> <button type="button" class="avatar-btn" ng-click="$ctrl.openLogin()" aria-label="{{ \'ÐойÑи в аккаÑнÑ\' | t }}" > <span class="custom-tooltip">{{ \'ÐойÑи в аккаÑнÑ\' | t }}</span> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" > <path d="M8 8a3 3 0 100-6 3 3 0 000 6zM2 14c0-2.21 2.686-4 6-4s6 1.79 6 4" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" /> </svg> </button> </div> <div class="editor-header__avatar" ng-if="$ctrl.isLoggedIn"> <button type="button" class="avatar-btn avatar-btn--logged-in" ng-click="$ctrl.openProfileMenu()" aria-label="{{ \'ÐÑоÑÐ¸Ð»Ñ Ð¿Ð¾Ð»ÑзоваÑелÑ\' | t }}" aria-haspopup="true" aria-expanded="{{ !!$ctrl.profileMenuOpen }}" > <img ng-if="$ctrl.userAvatar && !$ctrl.avatarLoadError" ng-src="{{ $ctrl.userAvatar | imageUrl: 64:64 }}" alt="{{ \'ÐваÑаÑ\' | t }}" class="avatar-img" ng-img-error="$ctrl.avatarLoadError = true" /> <svg ng-if="!$ctrl.userAvatar || $ctrl.avatarLoadError" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" > <path d="M8 8a3 3 0 100-6 3 3 0 000 6zM2 14c0-2.21 2.686-4 6-4s6 1.79 6 4" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" /> </svg> </button> <div class="editor-header__profile-menu" ng-class="{ open: $ctrl.profileMenuOpen }" role="menu" aria-label="{{ \'ÐÐµÐ½Ñ Ð¿ÑоÑилÑ\' | t }}" > <a ng-href="/{{ $ctrl.userPath || \'\' }}" class="profile-menu__item" role="menuitem"> <svg viewBox="0 0 15 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" > <path d="M12.73 15.75H1.72C.53 15.75-.31 14.56.1 13.45 1.08 10.82 3.94 9.05 7.23 9.05c3.28 0 6.14 1.77 7.12 4.4.41 1.11-.43 2.3-1.62 2.3zM7.23 10.55c-2.62 0-4.97 1.41-5.72 3.42-.03.08.02.28.21.28h11.01c.21 0 .24-.2.21-.28-.75-2.01-3.1-3.42-5.71-3.42z" fill="currentColor" /> <path d="M7.23 7.88c-2.07 0-3.75-1.77-3.75-3.94C3.48 1.77 5.16 0 7.23 0c2.07 0 3.75 1.77 3.75 3.94 0 2.17-1.68 3.94-3.75 3.94zm0-6.38c-1.24 0-2.25 1.1-2.25 2.44s1.01 2.44 2.25 2.44 2.25-1.1 2.25-2.44S8.47 1.5 7.23 1.5z" fill="currentColor" /> </svg> {{ \'ÐÑоÑилÑ\' | t }} </a> <a ng-href="/drafts" class="profile-menu__item" role="menuitem"> <svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" > <path d="M13.44 0c-.61 0-1.22.23-1.69.7L1.32 11.13.03 14.96c-.17.51.35 1 .86.83l3.83-1.28L15.13 4.07c.93-.93.93-2.44 0-3.38C14.66.23 14.05 0 13.44 0zm-.06 1.56c.23 0 .45.09.63.26.34.35.34.91 0 1.25l-.52.52-1.25-1.25.52-.52c.17-.17.4-.26.62-.26zm-2.2 1.83l1.25 1.25-7.42 7.42-1.26-1.25 7.43-7.42zM2.69 11.88l1.25 1.26-1.51.72c-.13.06-.29.04-.39-.06-.11-.1-.14-.26-.08-.4l.73-1.52z" fill="currentColor" /> </svg> {{ \'ЧеÑновики\' | t }} </a> <a ng-href="/profile/{{ $ctrl.userPath || \'\' }}?subscriptions" class="profile-menu__item" role="menuitem" > <svg width="19" height="19" viewBox="0 0 17 15" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" > <path d="M4.88 0C3.84 0 3 .84 3 1.88V3.75H1.88C.84 3.75 0 4.59 0 5.63v7.12C0 13.99 1.01 15 2.25 15h12c1.24 0 2.25-1.01 2.25-2.25V1.88C16.5.84 15.66 0 14.63 0H4.88zm0 1.5h9.75c.2 0 .37.17.37.38v10.87c0 .41-.34.75-.75.75H4.37c.08-.23.13-.49.13-.75V1.88c0-.21.17-.38.38-.38zM6.38 3c-.41 0-.75.34-.75.75s.34.75.75.75h6.75c.41 0 .75-.34.75-.75S13.54 3 13.13 3H6.38zM1.88 5.25H3v7.5c0 .41-.34.75-.75.75s-.75-.34-.75-.75V5.63c0-.21.17-.38.38-.38zm4.5.38c-.41 0-.75.34-.75.75s.34.75.75.75h6.75c.41 0 .75-.34.75-.75s-.34-.75-.75-.75H6.38zm0 2.62c-.41 0-.75.34-.75.75v2.63c0 .41.34.75.75.75h2.25c.41 0 .75-.34.75-.75V9c0-.41-.34-.75-.75-.75H6.38zm4.87 0c-.41 0-.75.34-.75.75s.34.75.75.75h1.88c.41 0 .75-.34.75-.75s-.34-.75-.75-.75H11.25zm0 2.63c-.41 0-.75.34-.75.75s.34.75.75.75h1.88c.41 0 .75-.34.75-.75s-.34-.75-.75-.75H11.25z" fill="currentColor" /> </svg> {{ \'ÐодпиÑки\' | t }}
1 </a> <a ng-href="/notifications" class="profile-menu__item" role="menuitem"> <svg viewBox="0 0 21 17" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" > <path d="M3.88 0C3.03 0 2.32.15 1.74.45 1.17.75.73 1.19.44 1.76.15 2.34 0 3.05 0 3.88v2.65c0 .83.15 1.54.44 2.11.29.58.73 1.02 1.3 1.32.58.3 1.22.45 2.06.45v2.06c0 .36.09.64.26.85.18.21.43.32.75.32.23 0 .44-.06.62-.18.19-.12.42-.31.7-.56l2.78-2.48h2.24c.85 0 1.56-.15 2.14-.45.57-.3 1.01-.74 1.3-1.32.29-.57.44-1.28.44-2.11V3.88c0-.84-.15-1.54-.44-2.12-.29-.57-.73-1.01-1.3-1.31C12.71.15 12 0 11.15 0H3.88zm0 1.5h7.27c.83 0 1.44.2 1.82.6.38.4.57.99.57 1.78v2.65c0 .79-.2 1.39-.57 1.79-.38.4-.99.6-1.82.6H8.83c-.25 0-.45.02-.6.07-.16.06-.32.17-.48.35l-2.55 2.6V9.6c0-.26-.05-.43-.16-.54-.1-.1-.28-.16-.53-.16h-.63c-.84 0-1.44-.2-1.82-.6-.38-.4-.57-.99-.57-1.79V3.88c0-.79.19-1.39.57-1.78.38-.4.99-.6 1.82-.6zM16.1 3c.04.28.06.57.06.88V4.5h.11c.84 0 1.45.2 1.82.6.38.39.57.99.57 1.78v2.71c0 .8-.19 1.39-.57 1.79-.38.4-.99.6-1.82.6h-.63c-.25 0-.42.05-.53.16-.11.1-.16.29-.16.54v2.33l-2.54-2.6c-.17-.18-.33-.3-.48-.35-.16-.05-.36-.08-.6-.08-2.52 0-2.36 0-2.4-.01l-1.45 1.3c.31.09.8.2 1.53.2h2.23l2.78 2.48c.28.25.52.44.7.56.19.12.4.18.63.18.32 0 .57-.1.75-.31.18-.21.26-.5.26-.85v-2.06c.85 0 1.48-.15 2.06-.45.58-.3 1.01-.74 1.3-1.32.29-.57.44-1.28.44-2.11V6.88c0-.84-.15-1.54-.44-2.12-.3-.57-.73-1.01-1.3-1.31-.58-.3-1.29-.45-2.14-.45H16.1z" fill="currentColor" /> </svg> {{ \'ÐомменÑаÑии\' | t }} </a> <a ng-href="/profile/{{ $ctrl.userPath || \'\' }}" class="profile-menu__item" role="menuitem"> <svg viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" > <path d="M7.15 0c-.5 0-.93.36-1.02.86L5.91 2.13c-.11.04-.23.09-.34.14L4.52 1.52c-.46-.32-1.01-.2-1.32.1L1.64 3.2c-.36.35-.4.91-.11 1.32l.74 1.05c-.05.11-.1.22-.14.34L.86 6.13C.36 6.21 0 6.64 0 7.15v2.21c0 .5.36.93.86 1.01l1.26.22c.04.11.09.23.14.34l-.74 1.05c-.29.41-.24.97.1 1.32l1.56 1.56c.41.4.97.37 1.32.11l1.05-.74c.11.05.23.1.34.14l.22 1.27c.08.49.51.85 1.02.85h2.21c.5 0 .93-.36 1.02-.86l.22-1.27c.11-.04.23-.09.34-.14l1.05.74c.31.23.9.31 1.32-.11l1.56-1.56c.36-.36.4-.91.11-1.32l-.74-1.05c.05-.11.1-.23.14-.34l1.27-.22c.49-.08.86-.51.86-1.02V7.15c0-.5-.36-.93-.86-1.02l-1.27-.22c-.04-.11-.09-.23-.14-.34l.74-1.05c.29-.41.24-.97-.11-1.32l-1.56-1.56c-.4-.39-.95-.38-1.32-.11l-1.05.74c-.11-.05-.23-.1-.34-.14L10.37.86C10.29.36 9.86 0 9.35 0H7.15zm.43 1.5h1.34c.02 0 .04.02.05.04l.29 1.68c.66.24 1.28.49 1.84.76l1.39-.98c.02-.01.04-.01.06.01l.95.95c.02.02.02.04.01.06l-.98 1.39c.28.6.54 1.22.76 1.84l1.68.29c.02 0 .04.02.04.05v1.34c0 .02-.02.04-.04.05l-1.68.29c-.22.63-.47 1.24-.76 1.84l.98 1.39c.01.02.01.04-.01.06l-.95.95c-.02.02-.04.02-.06.01l-1.39-.98c-.61.29-1.23.54-1.84.76l-.29 1.68c0 .03-.02.04-.05.04H7.58c-.02 0-.04-.02-.05-.04l-.29-1.68c-.6-.21-1.21-.46-1.84-.76l-1.39.98c-.02.01-.04.01-.06-.01l-.95-.95c-.02-.02-.02-.04-.01-.06l.98-1.39c-.29-.63-.55-1.24-.76-1.84l-1.68-.29C1.52 8.96 1.5 8.94 1.5 8.92V7.58c0-.02.02-.04.04-.05l1.68-.29c.22-.61.47-1.22.76-1.84l-.98-1.39c-.01-.02-.01-.04.01-.06l.95-.95c.02-.02.04-.02.06-.01l1.39.98c.58-.28 1.2-.53 1.84-.76l.29-1.68c0-.02.02-.04.05-.04zM8.25 4.88c-1.86 0-3.38 1.51-3.38 3.37 0 1.86 1.52 3.38 3.38 3.38s3.38-1.52 3.38-3.38c0-1.86-1.52-3.37-3.38-3.37zm0 1.5c1.04 0 1.88.84 1.88 1.87 0 1.04-.84 1.88-1.88 1.88s-1.88-.84-1.88-1.88c0-1.03.84-1.87 1.88-1.87z" fill="currentColor" /> </svg> {{ \'ÐаÑÑÑойки\' | t }} </a> <div class="profile-menu__separator" role="separator"></div> <button type="button" ng-click="$ctrl.logOut()" class="profile-menu__item profile-menu__item--logout" role="menuitem" > <svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" > <path d="M12.93 0c-1.04 0-1.88.84-1.88 1.88s.84 1.87 1.88 1.87 1.87-.84 1.87-1.87S13.96 0 12.93 0zm-1.5 4.5c-.27 0-.53.06-.77.17L7.67 6.08c-.15.07-.26.18-.33.33L5.87 9.68c-.04.08-.07.16-.07.26 0 .31.25.56.56.56.23 0 .44-.14.52-.34v0l1.57-2.68.78-.28-.74 2.43.01 0c-.04.16-.08.33-.08.5 0 .71.41 1.33.99 1.65l0 0 2.92 2.13 1 3.56h0c.1.31.38.53.72.53.41 0 .75-.34.75-.75 0-.08-.02-.15-.04-.22h0l-.75-3.76c-.02-.12-.07-.24-.14-.35l-1.65-2.71 1-3.29-.02-.01c.06-.18.1-.36.1-.56 0-1.03-.84-1.88-1.88-1.88zm2.49 2.98l-.57 1.54.44.32c.04.03.07.05.12.07l2.73 1.04c.01.01.02.01.03.01l.02.01c.06.02.12.03.18.03.31 0 .56-.25.56-.56 0-.22-.13-.41-.32-.5l-2.44-1.28-.75-.68zM5.66 10.88c-.22-.02-.44.09-.55.29l-.93 1.76-1.33-.71c-.36-.19-.82-.06-1.01.31L.09 15.85c-.19.36-.05.82.32 1.01l.83.45c-.01-.26.05-.52.18-.75.26-.49.77-.8 1.33-.8.24 0 .48.06.7.18.11.06.22.13.31.22l.99-1.86 0 0 .23-.44.21-.39v0l.93-1.76c.15-.28.04-.61-.23-.76-.07-.04-.14-.05-.21-.06zm2.94 1.42l-.36 1.67-1.57 2.86-.03.06c-.06.11-.1.23-.1.36 0 .41.34.75.75.75.27 0 .51-.15.64-.37l2.54-3.96-1.87-1.37zm-5.8 4.21c-.29-.02-.58.13-.73.4-.2.37-.05.82.32 1.02.36.19.82.06 1.01-.31.19-.37.06-.82-.31-1.02-.09-.05-.18-.07-.29-.09z" fill="currentColor" /> </svg> {{ \'ÐÑйÑи\' | t }} </button> </div> </div> </div> <button type="button" class="editor-header__help-btn" ng-class="{\'help-btn--hidden\': $ctrl.helpBtnHidden }" aria-label="{{ \'ÐоÑÑÑие клавиÑи\' | t }}" ng-click="$ctrl.openShortcutsHelp()" > <span class="help-btn-text">?</span> <span class="help-btn-dot" ng-if="$ctrl.showHelpDot"></span> <span class="help-btn-tooltip">{{ \'ÐоÑÑÑие клавиÑи\' | t }}</span> </button> </div>'),s.put("/components/inviteCollaborators/inviteCollaborators.html",'<div ng-if="$ctrl.opened" class="invite-collab-backdrop active" ng-click="$ctrl.onBackdropClick()" ></div> <div ng-if="$ctrl.opened" class="invite-collab active" ng-class="{\'invite-collab--dropdown-open\': $ctrl.accessDropdownOpen || $ctrl.linkRoleDropdownOpen || $ctrl.inputRoleDropdownOpen || $ctrl.openRoleDropdownId }" role="dialog" aria-modal="true" aria-labelledby="invite-collab-title" ng-click="$ctrl.closeAllDropdowns()" > <button type="button" class="invite-collab__close" aria-label="{{ \'ÐакÑÑÑÑ\' | t }}" ng-click="$ctrl.close()" > <svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M15 5L5 15M5 5L15 15" stroke="#141414" stroke-width="2" stroke-linecap="round" /> </svg> </button> <h2 class="invite-collab__title" id="invite-collab-title">{{ \'ÐÑиглаÑиÑÑ ÑоавÑоÑов\' | t }}</h2> <div class="invite-collab__search-row"> <div class="invite-collab__input-wrap"> <input type="text" class="invite-collab__input" placeholder="{{ $ctrl.searchPlaceholder }}" aria-label="{{ \'ÐоиÑк полÑзоваÑелей по имени или email\' | t }}" ng-model="$ctrl.searchQuery" ng-change="$ctrl.onSearchInput()" ng-keydown="$ctrl.onSearchKeydown($event)" autocomplete="off" /> <div class="invite-collab__input-line"></div> <div class="invite-collab__role-selector" role="button" tabindex="0" aria-haspopup="true" ng-attr-aria-expanded="{{ $ctrl.inputRoleDropdownOpen ? \'true\' : \'false\' }}" ng-click="$ctrl.toggleInputRoleDropdown($event)" ng-keydown="$ctrl.onPseudoButtonKeydown($event, $ctrl.toggleInputRoleDropdown)" > <span class="invite-collab__role-label">
1{{ $ctrl.getRoleLabel($ctrl.selectedRole) }}</span> <svg aria-hidden="true" class="invite-collab__chevron" width="16" height="16" viewBox="0 0 16 16" fill="none" ng-class="{\'invite-collab__chevron--up\': $ctrl.inputRoleDropdownOpen }" > <path d="M4 6L8 10L12 6" stroke="#141414" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> <div class="invite-collab__role-dropdown" ng-if="$ctrl.inputRoleDropdownOpen" ng-click="$event.stopPropagation()" > <div class="invite-collab__role-option" ng-repeat="role in $ctrl.roles track by role.id" role="button" tabindex="0" ng-class="{\'invite-collab__role-option--active\': role.id === $ctrl.selectedRole }" ng-click="$ctrl.selectInputRole(role.id); $event.stopPropagation()" ng-keydown="$ctrl.onPseudoButtonKeydown($event, $ctrl.selectInputRole, role.id)" > <div class="invite-collab__role-option-title">{{ role.label }}</div> <div class="invite-collab__role-option-desc">{{ role.description }}</div> </div> </div> </div> </div> <button type="button" class="invite-collab__add-btn" ng-click="$ctrl.addByInput()" ng-disabled="!$ctrl.searchQuery.trim()" > {{ \'ÐобавиÑÑ\' | t }} </button> </div> <div class="invite-collab__search-dropdown" aria-live="polite" ng-if="$ctrl.searchResults.length > 0 || ($ctrl.isSearching && $ctrl.searchQuery.length >= 2)" > <div class="invite-collab__search-loading" ng-if="$ctrl.isSearching"> <i class="fas fa-sync-alt fa-spin"></i> {{ \'ÐоиÑк...\' | t }} </div> <div class="invite-collab__search-item" ng-repeat="user in $ctrl.searchResults track by user._id" role="button" tabindex="0" ng-class="{\'invite-collab__search-item--highlighted\': $index === $ctrl.highlightedIndex }" ng-click="$ctrl.selectUser(user)" ng-keydown="$ctrl.onPseudoButtonKeydown($event, $ctrl.selectUser, user)" > <div class="invite-collab__avatar invite-collab__avatar--sm"> <img ng-if="$ctrl.getAvatarUrl(user.thumborId)" ng-src="{{ $ctrl.getAvatarUrl(user.thumborId) }}" alt="" loading="lazy" width="24" height="24" /> <span ng-if="!$ctrl.getAvatarUrl(user.thumborId)" class="invite-collab__avatar-initials"> {{ $ctrl.getInitials(user.name) }} </span> </div> <div class="invite-collab__search-item-info"> <div class="invite-collab__search-item-name">{{ user.name }}</div> <div class="invite-collab__search-item-email" ng-if="user.email">{{ user.email }}</div> </div> </div> <div class="invite-collab__search-empty" ng-if="!$ctrl.isSearching && $ctrl.searchResults.length === 0 && $ctrl.searchQuery.length >= 2" > <span ng-if="!$ctrl.isEmailQuery()" >{{ \'ÐолÑзоваÑÐµÐ»Ñ Ð½Ðµ найден. ÐведиÑе email Ð´Ð»Ñ Ð¿ÑиглаÑениÑ.\' | t }}</span > <span ng-if="$ctrl.isEmailQuery()"> {{ \'ÐÑпÑавиÑÑ Ð¿ÑиглаÑение на\' | t }} <strong>{{ $ctrl.searchQuery }}</strong>? <button type="button" class="invite-collab__search-invite-btn" ng-click="$ctrl.addByInput()" > {{ \'ÐÑиглаÑиÑÑ\' | t }} </button> </span> </div> </div> <div class="invite-collab__list" ng-if="$ctrl.invites.length > 0"> <div class="invite-collab__invite-row" ng-repeat="invite in $ctrl.invites track by invite._id"> <div class="invite-collab__avatar"> <img ng-if="$ctrl.getAvatarUrl(invite.inviteeThumbor)" ng-src="{{ $ctrl.getAvatarUrl(invite.inviteeThumbor) }}" alt="" loading="lazy" width="32" height="32" /> <span ng-if="!$ctrl.getAvatarUrl(invite.inviteeThumbor)" class="invite-collab__avatar-initials" > {{ $ctrl.getInitials(invite.inviteeName) }} </span> </div> <div class="invite-collab__invite-info"> <div class="invite-collab__invite-name">{{ invite.inviteeName }}</div> <div class="invite-collab__invite-status invite-collab__invite-status--draft" ng-if="invite._pending" > {{ \'ÐÑÐ´ÐµÑ Ð¿ÑиглаÑен(а)\' | t }} </div> <div class="invite-collab__invite-status-row" ng-if="!invite._pending"> <div class="invite-collab__invite-status" ng-class="\'invite-collab__invite-status--\' + $ctrl.getStatusColor(invite.status, invite)" > {{ $ctrl.getStatusLabel(invite.status, invite) }} </div> <button type="button" class="invite-collab__resend-btn" ng-if="$ctrl.canResend(invite)" ng-click="$ctrl.resendInvite(invite); $event.stopPropagation()" ng-disabled="invite._resending" > <i class="fas" ng-class="invite._resending ?\'fa-sync-alt fa-spin\' : \'fa-redo-alt\'" aria-hidden="true" ></i> {{ (invite._resending ? \'ÐÑпÑавка...\' : \'ÐÑпÑавиÑÑ Ð¿Ð¾Ð²ÑоÑно\') | t }} </button> </div> </div> <div class="invite-collab__invite-role" ng-click="$event.stopPropagation()"> <button type="button" class="invite-collab__invite-role-btn" aria-haspopup="true" ng-attr-aria-expanded="{{ $ctrl.openRoleDropdownId === invite._id ? \'true\' : \'false\' }}" ng-click="$ctrl.toggleRoleDropdown(invite._id, $event)" > <span>{{ $ctrl.getRoleLabel(invite.role) }}</span> <svg aria-hidden="true" class="invite-collab__chevron" width="16" height="16" viewB
1ox="0 0 16 16" fill="none" ng-class="{\'invite-collab__chevron--up\': $ctrl.openRoleDropdownId === invite._id }" > <path d="M4 6L8 10L12 6" stroke="#141414" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> </button> <div class="invite-collab__role-dropdown invite-collab__role-dropdown--invite" ng-if="$ctrl.openRoleDropdownId === invite._id" > <div class="invite-collab__role-option" ng-repeat="role in $ctrl.roles track by role.id" role="button" tabindex="0" ng-class="{\'invite-collab__role-option--active\': role.id === invite.role }" ng-click="$ctrl.updateInviteRole(invite, role.id); $event.stopPropagation()" ng-keydown="$ctrl.onPseudoButtonKeydown($event, $ctrl.updateInviteRole, invite, role.id)" > <div class="invite-collab__role-option-title">{{ role.label }}</div> <div class="invite-collab__role-option-desc">{{ role.description }}</div> </div> <div class="invite-collab__role-option invite-collab__role-option--remove" ng-click="$ctrl.removeInvite(invite); $event.stopPropagation()" role="button" tabindex="0" ng-keydown="$ctrl.onPseudoButtonKeydown($event, $ctrl.removeInvite, invite)" > <div class="invite-collab__role-option-title invite-collab__role-option-title--remove"> {{ \'УдалиÑÑ\' | t }} </div> </div> </div> </div> </div> </div> <div class="invite-collab__empty" ng-if="$ctrl.loadError && !$ctrl.isLoading"> <p>{{ \'Ðе ÑдалоÑÑ Ð·Ð°Ð³ÑÑзиÑÑ Ð¿ÑиглаÑениÑ.\' | t }}</p> <p> <button type="button" class="invite-collab__search-invite-btn" ng-click="$ctrl.loadInvites()"> {{ \'ÐопÑобоваÑÑ Ñнова\' | t }} </button> </p> </div> <div class="invite-collab__empty" ng-if="!$ctrl.isLoading && !$ctrl.loadError && $ctrl.invites.length === 0" > <p>{{ \'Ðока Ð½ÐµÑ Ð¿ÑиглаÑÑннÑÑ
ÑоавÑоÑов.\' | t }}</p> <p>{{ \'ÐайдиÑе полÑзоваÑÐµÐ»Ñ Ð¿Ð¾ имени или пÑиглаÑиÑе по email.\' | t }}</p> </div> <div class="invite-collab__loading" ng-if="$ctrl.isLoading"> <i class="fas fa-sync-alt fa-spin"></i> </div> <div class="invite-collab__general-access" ng-if="!$ctrl.isLoading && !$ctrl.loadError"> <div class="invite-collab__general-access-row"> <div class="invite-collab__avatar invite-collab__avatar--icon"> <svg aria-hidden="true" ng-if="$ctrl.linkSharing.access === \'restricted\'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" > <rect x="3" y="9" width="14" height="9" rx="2" stroke="#141414" stroke-width="1.5" /> <path d="M6 9V6C6 3.79086 7.79086 2 10 2C12.2091 2 14 3.79086 14 6V9" stroke="#141414" stroke-width="1.5" stroke-linecap="round" /> </svg> <svg aria-hidden="true" ng-if="$ctrl.linkSharing.access === \'authenticated\'" width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" stroke="#141414" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> <circle cx="9" cy="7" r="4" stroke="#141414" stroke-width="1.5" /> <path d="M23 21v-2a4 4 0 0 0-3-3.87" stroke="#141414" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> <path d="M16 3.13a4 4 0 0 1 0 7.75" stroke="#141414" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> <span ng-if="$ctrl.linkSharing.access === \'anyone\'" class="invite-collab__avatar-icon-inner" ng-include="\'/partials/icons/globe.html\'" ></span> </div> <span class="invite-collab__general-access-title">{{ \'ÐбÑий доÑÑÑп\' | t }}</span> <div class="invite-collab__general-access-select" role="button" tabindex="0" aria-haspopup="true" ng-attr-aria-expanded="{{ $ctrl.accessDropdownOpen ? \'true\' : \'false\' }}" ng-click="$ctrl.toggleAccessDropdown($event)" ng-keydown="$ctrl.onPseudoButtonKeydown($event, $ctrl.toggleAccessDropdown)" > <span class="invite-collab__general-access-level" >{{ $ctrl.getAccessLabel($ctrl.linkSharing.access) }}</span > <svg aria-hidden="true" class="invite-collab__chevron" width="16" height="16" viewBox="0 0 16 16" fill="none" ng-class="{\'invite-collab__chevron--up\': $ctrl.accessDropdownOpen }" > <path d="M4 6L8 10L12 6" stroke="#141414" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> <div class="invite-collab__access-dropdown" ng-if="$ctrl.accessDropdownOpen" ng-click="$event.stopPropagation()" > <div class="invite-collab__role-option" ng-repeat="opt in $ctrl.accessOptions track by opt.id" role="button" tabindex="0" ng-class="{\'invite-collab__role-option--active\': opt.id === $ctrl.linkSharing.access }" ng-click="$ctrl.selectAccessLevel(opt.id); $event.stopPropagation()" ng-keydown="$ctrl.onPseudoButtonKeydown($event, $ctrl.selectAccessLevel, opt.id)" > <div class="invite-collab__role-option-title">{{ opt.label }}</div> <div class="invite-collab__role-option-desc">{{ opt.description }}</div> </div> </div> </div> <span class="invite-collab__general-access-spacer"></span> <div class="invite-collab__invite-role" ng-if="$ctrl.linkSharing.access !== \'restricted\'" ng-click="$event.stopPropagation()" > <button type="button" class="invite-collab__invite-role-btn" aria-haspopup="true" ng-attr-aria-expanded="{{ $ctrl.linkRoleDropdownOpen ? \'true\' : \'false\' }}" ng-click="$ctrl.toggleLinkRoleDropdown($event)" > <span>{{ $ctrl.getRoleLabel($ctrl.linkSharing.role) }}</span> <svg aria-hidden="true" class="invite-collab__chevron" width="16" height="16" viewB
1ox="0 0 16 16" fill="none" ng-class="{\'invite-collab__chevron--up\': $ctrl.linkRoleDropdownOpen }" > <path d="M4 6L8 10L12 6" stroke="#141414" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> </button> <div class="invite-collab__role-dropdown invite-collab__role-dropdown--invite" ng-if="$ctrl.linkRoleDropdownOpen" ng-click="$event.stopPropagation()" > <div class="invite-collab__role-option" ng-repeat="role in $ctrl.roles track by role.id" role="button" tabindex="0" ng-class="{\'invite-collab__role-option--active\': role.id === $ctrl.linkSharing.role }" ng-click="$ctrl.selectLinkRole(role.id); $event.stopPropagation()" ng-keydown="$ctrl.onPseudoButtonKeydown($event, $ctrl.selectLinkRole, role.id)" > <div class="invite-collab__role-option-title">{{ role.label }}</div> <div class="invite-collab__role-option-desc">{{ role.description }}</div> </div> </div> </div> </div> <button type="button" class="invite-collab__copy-link-btn" aria-label="{{ \'ÐопиÑоваÑÑ ÑÑÑÐ»ÐºÑ Ð´Ð»Ñ Ð¾Ð±Ñего доÑÑÑпа\' | t }}" ng-if="$ctrl.linkSharing.access !== \'restricted\'" ng-click="$ctrl.copyShareLink()" > <svg aria-hidden="true" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M6.5 9.5L9.5 6.5M7 11L5.5 12.5C4.39543 13.6046 2.60457 13.6046 1.5 12.5C0.395431 11.3954 0.395431 9.60457 1.5 8.5L3 7M9 5L10.5 3.5C11.6046 2.39543 13.3954 2.39543 14.5 3.5C15.6046 4.60457 15.6046 6.39543 14.5 7.5L13 9" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" /> </svg> <span>{{ ($ctrl.linkCopied ? \'СÑÑлка ÑкопиÑована!\' : \'ÐопиÑоваÑÑ ÑÑÑлкÑ\') | t }}</span> </button> </div> <button type="button" class="invite-collab__done-btn" ng-class="{\'invite-collab__done-btn--saved\': $ctrl.saved }" ng-click="$ctrl.done()" ng-disabled="$ctrl.isSaving" > <span ng-if="!$ctrl.isSaving && !$ctrl.saved">{{ \'ÐоÑово\' | t }}</span> <span ng-if="!$ctrl.isSaving && $ctrl.saved">{{ \'СоÑ
Ñанено\' | t }}</span> <span ng-if="$ctrl.isSaving" ><i class="fas fa-sync-alt fa-spin"></i> {{ \'СоÑ
Ñанение...\' | t }}</span > </button> </div>'),s.put("/pages/edit/author.html",'<update-meta title="{{ \'ÐаÑÑÑойки\' | t }}"></update-meta> <script type="text/ng-template" id="apple-icon-svg"> <svg viewBox="0 0 384 512" width="14" height="14" fill="currentColor"><path d="M318.7 268.7c-.2-36.7 16.4-64.4 50-84.8-18.8-26.9-47.2-41.7-84.7-44.6-35.5-2.8-74.3 20.7-88.5 20.7-15 0-49.4-19.7-76.4-19.7C63.3 141.2 4 184.8 4 273.5c0 26.2 4.8 53.3 14.4 81.2 12.8 36.7 59 126.7 107.2 125.2 25.2-.6 43-17.9 75.8-17.9 31.8 0 48.3 17.9 76.4 17.9 48.6-.7 90.4-82.5 102.6-119.3-65.2-30.7-61.7-90-61.7-91.9zm-56.6-164.2c27.3-32.4 24.8-61.9 24-72.5-24.1 1.4-52 16.4-67.9 34.9-17.5 19.8-27.8 44.3-25.6 71.9 26.1 2 49.9-11.4 69.5-34.3z"/></svg> <\/script> <div class="settings-page" ng-if="$ctrl.authorized"> <div class="ds-container"> <div class="tw:row-flex"> <aside class="tw:gutter-half tw:w-full tw:md:w-2/12 settings-sidebar"> <div class="settings-sidebar__title">{{ \'ÐаÑÑÑойки\' | t }}</div> <nav class="settings-sidebar__nav" role="tablist" aria-label="{{ \'ÐаÑÑÑойки\' | t }}"> <a class="settings-sidebar__link" href="" id="tab-about" role="tab" aria-selected="{{ $ctrl.activeTab === \'about\' }}" aria-controls="panel-about" tabindex="{{ $ctrl.activeTab === \'about\' ? \'0\' : \'-1\' }}" ng-class="{\'settings-sidebar__link--active\': $ctrl.activeTab === \'about\' }" ng-click="$ctrl.setTab(\'about\'); $event.preventDefault()" ng-keydown="$ctrl.onTabKeydown($event)" >{{ \'ÐÑоÑилÑ\' | t }}</a > <a class="settings-sidebar__link" href="" id="tab-subscriptions" role="tab" aria-selected="{{ $ctrl.activeTab === \'subscriptions\' }}" aria-controls="panel-subscriptions" tabindex="{{ $ctrl.activeTab === \'subscriptions\' ? \'0\' : \'-1\' }}" ng-class="{\'settings-sidebar__link--active\': $ctrl.activeTab === \'subscriptions\' }" ng-click="$ctrl.setTab(\'subscriptions\'); $event.preventDefault()" ng-keydown="$ctrl.onTabKeydown($event)" >{{ \'ÐодпиÑки\' | t }}</a > <a class="settings-sidebar__link" href="" id="tab-notifications" role="tab" aria-selected="{{ $ctrl.activeTab === \'notifications\' }}" aria-controls="panel-notifications" tabindex="{{ $ctrl.activeTab === \'notifications\' ? \'0\' : \'-1\' }}" ng-class="{\'settings-sidebar__link--active\': $ctrl.activeTab === \'notifications\' }" ng-click="$ctrl.setTab(\'notifications\'); $event.preventDefault()" ng-keydown="$ctrl.onTabKeydown($event)" >{{ \'УведомлениÑ\' | t }}</a > <a class="settings-sidebar__link" href="" id="tab-security" role="tab" aria-selected="{{ $ctrl.activeTab === \'security\' }}" aria-controls="panel-security" tabindex="{{ $ctrl.activeTab === \'security\' ? \'0\' : \'-1\' }}" ng-class="{\'settings-sidebar__link--active\': $ctrl.activeTab === \'security\' }" ng-click="$ctrl.setTab(\'security\'); $event.preventDefault()" ng-keydown="$ctrl.onTabKeydown($event)" >{{ \'ÐÑ
од и безопаÑноÑÑÑ\' | t }}</a > </nav> </aside> <main class="tw:gutter-half tw:w-full tw:md:w-10/12 settings-content">
1 <div class="settings-verify-banner" ng-if="!$ctrl.emailVerified"> <div class="settings-verify-banner__icon"> <i class="fas fa-envelope"></i> </div> <div class="settings-verify-banner__body"> <div class="settings-verify-banner__text"> {{ \'ÐодÑвеÑдиÑе email, ÑÑÐ¾Ð±Ñ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑиÑоваÑÑ Ð¸ оÑениваÑÑ Ð¼Ð°ÑеÑиалÑ\' | t }} </div> <div class="settings-verify-banner__actions"> <button type="button" class="settings-verify-banner__btn" ng-click="$ctrl.resendVerificationEmail()" ng-disabled="$ctrl.resendCooldown > 0 || $ctrl.resendLoading" > <i class="fas fa-sync-alt fa-spin" ng-show="$ctrl.resendLoading"></i> <span ng-if="$ctrl.resendCooldown <= 0 && !$ctrl.resendLoading" >{{ \'ÐÑпÑавиÑÑ Ð¿Ð¸ÑÑмо подÑвеÑждениÑ\' | t }}</span > <span ng-if="$ctrl.resendCooldown > 0" >{{ \'ÐовÑоÑиÑÑ ÑеÑез\' | t }} {{ $ctrl.resendCooldown }} {{ \'Ñек\' | t }}</span > </button> <span class="settings-verify-banner__sent" ng-if="$ctrl.resendSuccess"> <i class="fas fa-check"></i> {{ \'ÐиÑÑмо оÑпÑавлено\' | t }} </span> </div> </div> <button type="button" class="settings-verify-banner__dismiss" ng-click="$ctrl.dismissVerifyBanner()" aria-label="{{ \'СкÑÑÑÑ\' | t }}" > × </button> </div> <div ng-if="$ctrl.activeTab === \'about\'" id="panel-about" class="settings-tab-content" role="tabpanel" aria-labelledby="tab-about" > <div class="settings-content__header"> <h1 class="settings-content__title">{{ \'ÐаÑÑÑойки пÑоÑилÑ\' | t }}</h1> <p class="settings-content__subtitle"> {{ \'ÐдеÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ наÑÑÑоиÑÑ Ñвой пÑоÑÐ¸Ð»Ñ Ñак, как Ð²Ñ Ñ
оÑиÑе\' | t }} </p> </div> <form name="profileForm" ng-submit="$ctrl.saveProfile()"> <div class="settings-section"> <div class="settings-section__title">{{ \'ÐваÑаÑ\' | t }}</div> <div class="settings-avatar"> <div class="settings-avatar__circle" ngf-select="$ctrl.uploadAvatar($file)" ngf-accept="\'image/*\'" ng-disabled="$ctrl.avatarUploading" > <img ng-if="!$ctrl.avatarUploading && $ctrl.author.thumborId" class="settings-avatar__image" ng-src="{{ $ctrl.author.thumborId | imageUrl: 300:300 }}" /> <img ng-if="!$ctrl.avatarUploading && !$ctrl.author.thumborId && $ctrl.author.image" class="settings-avatar__image" ng-src="{{ $ctrl.author.image }}" /> <div ng-if="!$ctrl.avatarUploading && ($ctrl.author.thumborId || $ctrl.author.image)" class="settings-avatar__overlay" > <span class="settings-avatar__overlay-icon"><i class="fas fa-camera"></i></span> <span class="settings-avatar__overlay-text">{{ \'СмениÑÑ ÑоÑо\' | t }}</span> </div> <div ng-if="!$ctrl.avatarUploading && !$ctrl.author.thumborId && !$ctrl.author.image" class="settings-avatar__placeholder" > <span class="settings-avatar__placeholder-icon" ><i class="fas fa-camera"></i ></span> <span class="settings-avatar__placeholder-text" >{{ \'ÐажмиÑе, ÑÑÐ¾Ð±Ñ Ð·Ð°Ð³ÑÑзиÑÑ ÑÐ²Ð¾Ñ ÑоÑогÑаÑиÑ\' | t }}</span > </div> <span ng-if="$ctrl.avatarUploading" class="settings-avatar__spinner"> <i class="fas fa-sync-alt fa-spin"></i> </span> </div> </div> </div> <div class="settings-section"> <div class="settings-section__title">{{ \'ÐмÑ\' | t }}</div> <div class="settings-field"> <div class="settings-field__input-wrap"> <input class="settings-field__input" type="text" ng-model="$ctrl.displayName" ng-change="$ctrl.onNameChange()" placeholder="{{ \'Ðак Ð²Ð°Ñ Ð·Ð¾Ð²ÑÑ?\' | t }}" maxlength="100" required /> <span class="settings-field__counter" ng-class="{\'settings-field__counter--warning\': ($ctrl.displayName || \'\').length > 80, \'settings-field__counter--limit\': ($ctrl.displayName || \'\').length >= 100 }" >{{ 100 - ($ctrl.displayName || \'\').length }}</span > </div> <div class="settings-field__error" ng-if="$ctrl.nameError"> {{ $ctrl.nameError }} </div> <div class="settings-field__hint" ng-if="!$ctrl.nameError"> {{ \'ÐаÑе Ð¸Ð¼Ñ Ð¿Ð¾ÑвиÑÑÑ Ð½Ð° ÑÑÑаниÑе пÑоÑÐ¸Ð»Ñ Ð¸ как подпиÑÑ Ð² пÑбликаÑиÑÑ
, комменÑаÑиÑÑ
и оÑкликаÑ
\' | t }} </div> </div> </div> <div class="settings-section"> <div class="settings-section__title">{{ \'Ð Ñебе\' | t }}</div> <div class="settings-field"> <div class="settings-field__input-wrap settings-field__input-wrap--textarea"> <textarea id="settings-bio" class="settings-field__input settings-field__input--textarea settings-field__input--autogrow" ng-model="$ctrl.author.bio" maxlength="2000" aria-label="{{ \'Ð Ñебе\' | t }}" placeholder="{{ \'РаÑÑкажиÑе немного о Ñебе\' | t }}" ></textarea> <span class="settings-field__counter settings-field__counter--top" ng-if="($ctrl.author.bio || \'\').length > 1800" ng-class="{\'settings-field__counter--warning\': ($ctrl.author.bio || \'\').length > 1800, \'settings-field__counter--limit\': ($ctrl.author.bio || \'\').length >= 2000 }" >{{ 2000 - ($ctrl.author.bio || \'\').length }}</span > </div> </div> </div> <div class="settings-section"> <div class="settings-section__title">{{ \'ÐдÑÐµÑ Ð½Ð° ÐиÑкÑÑÑе\' | t }}</div> <div class="settings-field"> <div class="settings-address__input-wrap"> <span class="settings-address__prefix">https://discours.io/</span> <input class="settings-address__slug" type="text" ng-model="$ctrl.author.path" ng-change="$ctrl.onPathChange()" ng-blur="$ctrl.onPathBlur()" ng-model-options="{ debounce: { default: 300, blur: 0 } }" required /> </div> <div class="settings-field__error" ng-if="$ctrl.pathError"> {{ $ctrl.pathError }} </div>
1 <div class="settings-field__hint" ng-if="!$ctrl.pathError"> {{ \'Ðожно пиÑаÑÑ ÐºÐ¸ÑиллиÑей â адÑÐµÑ Ñам ÑÑÐ°Ð½ÐµÑ Ð»Ð°ÑинÑким (напÑимеÑ, «ÐÐ·Ð°Ñ Ðапенов» â «azat-kapenov»). СÑÑоÑнÑе лаÑинÑкие бÑквÑ, ÑиÑÑÑ, деÑÐ¸Ñ Ð¸ подÑÑÑкивание, Ð¾Ñ 3 Ñимволов.\' | t }} </div> </div> </div> <div class="settings-section"> <div class="settings-section__title">{{ \'СоÑиалÑнÑе ÑеÑи\' | t }}</div> <div class="settings-social"> <div class="settings-social__row"> <div class="settings-social__item"> <span class="settings-social__icon settings-social__icon--facebook">f</span> <input class="settings-social__input" ng-class="{\'settings-social__input--error\': $ctrl.socialErrors.facebook}" type="text" ng-model="$ctrl.author.facebook" ng-change="$ctrl.onSocialChange(\'facebook\')" ng-blur="$ctrl.onSocialBlur(\'facebook\')" aria-label="Facebook" placeholder="https://facebook.com/username" /> </div> <div class="settings-social__error" ng-if="$ctrl.socialErrors.facebook"> {{ $ctrl.socialErrors.facebook }} </div> </div> <div class="settings-social__row"> <div class="settings-social__item"> <span class="settings-social__icon settings-social__icon--telegram"> <i class="fab fa-telegram-plane"></i> </span> <input class="settings-social__input" ng-class="{\'settings-social__input--error\': $ctrl.socialErrors.telegram}" type="text" ng-model="$ctrl.author.telegram" ng-change="$ctrl.onSocialChange(\'telegram\')" ng-blur="$ctrl.onSocialBlur(\'telegram\')" aria-label="Telegram" placeholder="https://t.me/username" /> </div> <div class="settings-social__error" ng-if="$ctrl.socialErrors.telegram"> {{ $ctrl.socialErrors.telegram }} </div> </div> <div class="settings-social__row"> <div class="settings-social__item"> <span class="settings-social__icon settings-social__icon--vk">VK</span> <input class="settings-social__input" ng-class="{\'settings-social__input--error\': $ctrl.socialErrors.vkontakte}" type="text" ng-model="$ctrl.author.vkontakte" ng-change="$ctrl.onSocialChange(\'vkontakte\')" ng-blur="$ctrl.onSocialBlur(\'vkontakte\')" aria-label="VK" placeholder="https://vk.com/username" /> </div> <div class="settings-social__error" ng-if="$ctrl.socialErrors.vkontakte"> {{ $ctrl.socialErrors.vkontakte }} </div> </div> <div class="settings-social__row"> <div class="settings-social__item"> <span class="settings-social__icon settings-social__icon--twitter"> <i class="fab fa-twitter"></i> </span> <input class="settings-social__input" ng-class="{\'settings-social__input--error\': $ctrl.socialErrors.twitter}" type="text" ng-model="$ctrl.author.twitter" ng-change="$ctrl.onSocialChange(\'twitter\')" ng-blur="$ctrl.onSocialBlur(\'twitter\')" aria-label="Twitter" placeholder="https://twitter.com/username" /> </div> <div class="settings-social__error" ng-if="$ctrl.socialErrors.twitter"> {{ $ctrl.socialErrors.twitter }} </div> </div> <div class="settings-social__row"> <div class="settings-social__item"> <span class="settings-social__icon settings-social__icon--instagram"> <i class="fab fa-instagram"></i> </span> <input class="settings-social__input" ng-class="{\'settings-social__input--error\': $ctrl.socialErrors.instagram}" type="text" ng-model="$ctrl.author.instagram" ng-change="$ctrl.onSocialChange(\'instagram\')" ng-blur="$ctrl.onSocialBlur(\'instagram\')" aria-label="Instagram" placeholder="https://instagram.com/username" /> </div> <div class="settings-social__error" ng-if="$ctrl.socialErrors.instagram"> {{ $ctrl.socialErrors.instagram }} </div> </div> <div class="settings-social__row"> <div class="settings-social__item"> <span class="settings-social__icon settings-social__icon--linkedin">in</span> <input class="settings-social__input" ng-class="{\'settings-social__input--error\': $ctrl.socialErrors.linkedin}" type="text" ng-model="$ctrl.author.linkedin" ng-change="$ctrl.onSocialChange(\'linkedin\')" ng-blur="$ctrl.onSocialBlur(\'linkedin\')" aria-label="LinkedIn" placeholder="https://linkedin.com/in/username" /> </div> <div class="settings-social__error" ng-if="$ctrl.socialErrors.linkedin"> {{ $ctrl.socialErrors.linkedin }} </div> </div> <div class="settings-social__row"> <div class="settings-social__item"> <span class="settings-social__icon settings-social__icon--website"> <i class="fas fa-globe"></i> </span> <input class="settings-social__input" ng-class="{\'settings-social__input--error\': $ctrl.socialErrors.website}" type="text" ng-model="$ctrl.author.website" ng-change="$ctrl.onSocialChange(\'website\')" ng-blur="$ctrl.onSocialBlur(\'website\')" aria-label="{{ \'СайÑ\' | t }}" placeholder="https://website.com" /> </div> <div class="settings-social__error" ng-if="$ctrl.socialErrors.website"> {{ $ctrl.socialErrors.website }} </div> </div> </div> </div> </form> </div> <div ng-if="$ctrl.activeTab === \'security\'" id="panel-security" class="settings-tab-content" role="tabpanel" aria-labelledby="tab-security" > <div class="settings-content__header"> <h1 class="settings-content__title">{{ \'ÐаÑÑÑойки вÑ
ода\' | t }}</h1> <p class="settings-content__subtitle"> {{ \'УпÑавление доÑÑÑпом к ваÑÐµÐ¼Ñ Ð°ÐºÐºÐ°ÑнÑÑ\' | t }} </p> </div> <form name="securityForm" ng-submit="$ctrl.saveSecurity()"> <div class="settings-section"> <div class="settings-section__title">{{ \'ÐоÑÑа\' | t }}</div> <div class="settings-field"> <div class="settings-field__input-wrap"> <input class="settings-field__input" type="email" inputmode="email" autocomplete="email" ng-model="$ctrl.author.email" aria-label="{{ \'ÐлекÑÑÐ¾Ð½Ð½Ð°Ñ Ð¿Ð¾ÑÑа\' | t }}" /> </div> </div> </div> <div class="settings-section"> <div class="settings-section__title">{{ \'ÐаÑолÑ\' | t }}</div> <div class="settings-field settings-field--spaced"> <div class="settings-section__label">{{ \'ÐовÑй паÑолÑ\' | t }}</div> <div class="settings-field__input-wrap"> <input class="settings-field__input" type="password" ng-model="$ctrl.newPassword" minlength="8" autocomplete="new-password" placeholder="{{ \'ÐинимÑм 8 Ñимволов\' | t }}" aria-label="{{ \'ÐовÑй паÑолÑ\' | t }}" /> </div> </div> <div class="settings-field settings-field--confirm-password" ng-if="$ctrl.newPassword" > <div class="settings-section__label">{{ \'ÐодÑвеÑдиÑе новÑй паÑолÑ\' | t }}</div> <div class="settings-field__input-wrap"> <input class="settings-field__input" type="password" ng-model="$ctrl.confirmPassword" autocomplete="new-password" aria-label="{{ \'ÐодÑвеÑдиÑе новÑй паÑолÑ\' | t }}" /> </div> <div class="settings-field__error" ng-if="$ctrl.passwordError"> {{ $ctrl.passwordError }} </div> </div> </div> <div class="settings-section"> <div class="settings-section__title">{{ \'ÐÑ
од ÑеÑез ÑоÑÑеÑи\' | t }}</div> <div class="settings-oauth"> <div class="settings-oauth__item"> <span class="settings-oauth__label">Google</span> <span class="settings-oauth__connected" ng-if="$ctrl.oauthConnected.google"> <span class="settings-oauth__provider-icon settings-oauth__provider-icon--google" >G</span > <span>{{ \'ÐодклÑÑÑн\' | t }}</span> <button type="button" class="settings-oauth__disconnect" ng-click="$ctrl.disconnectOAuth(\'google\')" ng-disabled="$ctrl.oauthLoading.google" > × </button>
1 </span> <button type="button" class="settings-oauth__connect" ng-if="!$ctrl.oauthConnected.google" ng-click="$ctrl.connectOAuth(\'google\')" ng-disabled="$ctrl.oauthLoading.google" ng-class="{\'settings-oauth__connect--loading\': $ctrl.oauthLoading.google }" > <span class="settings-oauth__provider-icon" style="color: #fff">G</span> <span ng-if="!$ctrl.oauthLoading.google">{{ \'ÐÑивÑзаÑÑ\' | t }}</span> <span ng-if="$ctrl.oauthLoading.google">{{ \'ÐодклÑÑениеâ¦\' | t }}</span> </button> </div> <div class="settings-oauth__item"> <span class="settings-oauth__label">GitHub</span> <span class="settings-oauth__connected" ng-if="$ctrl.oauthConnected.github"> <span class="settings-oauth__provider-icon settings-oauth__provider-icon--github" > <i class="fab fa-github"></i> </span> <span>{{ \'ÐодклÑÑÑн\' | t }}</span> <button type="button" class="settings-oauth__disconnect" ng-click="$ctrl.disconnectOAuth(\'github\')" ng-disabled="$ctrl.oauthLoading.github" > × </button> </span> <button type="button" class="settings-oauth__connect" ng-if="!$ctrl.oauthConnected.github" ng-click="$ctrl.connectOAuth(\'github\')" ng-disabled="$ctrl.oauthLoading.github" ng-class="{\'settings-oauth__connect--loading\': $ctrl.oauthLoading.github }" > <span class="settings-oauth__provider-icon" style="color: #fff"> <i class="fab fa-github"></i> </span> <span ng-if="!$ctrl.oauthLoading.github">{{ \'ÐÑивÑзаÑÑ\' | t }}</span> <span ng-if="$ctrl.oauthLoading.github">{{ \'ÐодклÑÑениеâ¦\' | t }}</span> </button> </div> <div class="settings-oauth__item"> <span class="settings-oauth__label">Facebook</span> <span class="settings-oauth__connected" ng-if="$ctrl.oauthConnected.facebook"> <span class="settings-oauth__provider-icon settings-oauth__provider-icon--facebook" > <i class="fab fa-facebook-f"></i> </span> <span>{{ \'ÐодклÑÑÑн\' | t }}</span> <button type="button" class="settings-oauth__disconnect" ng-click="$ctrl.disconnectOAuth(\'facebook\')" ng-disabled="$ctrl.oauthLoading.facebook" > × </button> </span> <button type="button" class="settings-oauth__connect" ng-if="!$ctrl.oauthConnected.facebook" ng-click="$ctrl.connectOAuth(\'facebook\')" ng-disabled="$ctrl.oauthLoading.facebook" ng-class="{\'settings-oauth__connect--loading\': $ctrl.oauthLoading.facebook }" > <span class="settings-oauth__provider-icon" style="color: #fff"> <i class="fab fa-facebook-f"></i> </span> <span ng-if="!$ctrl.oauthLoading.facebook">{{ \'ÐÑивÑзаÑÑ\' | t }}</span> <span ng-if="$ctrl.oauthLoading.facebook">{{ \'ÐодклÑÑениеâ¦\' | t }}</span> </button> </div> <div class="settings-oauth__item"> <span class="settings-oauth__label">VK</span> <span class="settings-oauth__connected" ng-if="$ctrl.oauthConnected.vk"> <span class="settings-oauth__provider-icon settings-oauth__provider-icon--vk"> <i class="fab fa-vk"></i> </span> <span>{{ \'ÐодклÑÑÑн\' | t }}</span> <button type="button" class="settings-oauth__disconnect" ng-click="$ctrl.disconnectOAuth(\'vk\')" ng-disabled="$ctrl.oauthLoading.vk" > × </button> </span> <button type="button" class="settings-oauth__connect" ng-if="!$ctrl.oauthConnected.vk" ng-click="$ctrl.connectOAuth(\'vk\')" ng-disabled="$ctrl.oauthLoading.vk" ng-class="{\'settings-oauth__connect--loading\': $ctrl.oauthLoading.vk }" > <span class="settings-oauth__provider-icon" style="color: #fff"> <i class="fab fa-vk"></i> </span> <span ng-if="!$ctrl.oauthLoading.vk">{{ \'ÐÑивÑзаÑÑ\' | t }}</span> <span ng-if="$ctrl.oauthLoading.vk">{{ \'ÐодклÑÑениеâ¦\' | t }}</span> </button> </div> </div> </div> <div class="settings-section"> <div class="settings-section__title">{{ \'Telegram-боÑ\' | t }}</div> <div class="settings-telegram" ng-if="$ctrl.telegramLinked"> <div class="settings-telegram__status"> <span class="settings-telegram__icon" aria-hidden="true">â</span> <div class="settings-telegram__status-text"> <strong>{{ \'Telegram пÑивÑзан\' | t }}</strong> <span class="settings-telegram__username" ng-if="$ctrl.telegramUsername" >@{{ $ctrl.telegramUsername }}</span > </div> </div> <p class="settings-telegram__hint"> {{ \'РбоÑе доÑÑÑпнÑ\' | t }} <a ng-href="{{ $ctrl.telegramBotLink }}" target="_blank" rel="noopener" >@DiscoursPostBot</a >: <code>/myqueue</code> â {{ \'ÑÑаÑÑÑÑ Ð²Ð°ÑиÑ
маÑеÑиалов\' | t }}, <code>/queue</code> â {{ \'оÑеÑÐµÐ´Ñ ÑедакÑии (еÑли еÑÑÑ ÑолÑ)\' | t }}. {{ \'ЧÑÐ¾Ð±Ñ Ð¾ÑвÑзаÑÑ â оÑпÑавÑÑе\' | t }} <code>/unlink</code> {{ \'в боÑа\' | t }}. </p> </div>
1 <div class="settings-telegram" ng-if="!$ctrl.telegramLinked && $ctrl.telegramCode"> <p class="settings-telegram__hint"> {{ \'ÐÑкÑойÑе\' | t }} <a ng-href="{{ $ctrl.telegramBotLink }}" target="_blank" rel="noopener" >@DiscoursPostBot</a > {{ \'и оÑпÑавÑÑе ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ñ ÐºÐ¾Ð´Ð¾Ð¼\' | t }}: </p> <div class="settings-telegram__code-wrap"> <div class="settings-telegram__code" aria-label="{{ \'ÐдноÑазовÑй код пÑивÑзки\' | t }}" > <code>/link {{ $ctrl.telegramCode }}</code> </div> <button type="button" class="settings-telegram__copy" ng-click="$ctrl.copyTelegramCode()" ng-disabled="$ctrl.telegramCodeCopied" aria-label="{{ \'СкопиÑоваÑÑ ÐºÐ¾Ð´\' | t }}" > <span ng-if="!$ctrl.telegramCodeCopied">{{ \'ÐопиÑоваÑÑ\' | t }}</span> <span ng-if="$ctrl.telegramCodeCopied">â {{ \'СкопиÑовано\' | t }}</span> </button> </div> <div class="settings-telegram__meta"> <span class="settings-telegram__countdown" aria-live="polite" >â± {{ \'Ðод дейÑÑвÑеÑ\' | t }}: {{ $ctrl.telegramCountdownText() }}</span > <button type="button" class="settings-telegram__check" ng-click="$ctrl.checkTelegramLinkStatus()" > {{ \'Я ввÑл код\' | t }} </button> <button type="button" class="settings-telegram__cancel" ng-click="$ctrl.cancelTelegramLink()" > {{ \'ÐÑмена\' | t }} </button> </div> <p class="settings-telegram__hint settings-telegram__hint--small"> {{ \'Ðак ÑолÑко введÑÑе код в боÑе, ÑÑÑаниÑа Ñама обновиÑÑÑ\' | t }}. </p> </div> <div class="settings-telegram" ng-if="!$ctrl.telegramLinked && !$ctrl.telegramCode"> <p class="settings-telegram__hint"> {{ \'ÐÑивÑжиÑе Telegram-аккаÑнÑ, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð»ÑÑаÑÑ Ð² @DiscoursPostBot ÑÑаÑÑÑÑ ÑвоиÑ
маÑеÑиалов и ÑедакÑионнÑе ÑведомлениÑ\' | t }}. </p> <button type="button" class="settings-oauth__connect" ng-click="$ctrl.generateTelegramCode()" ng-disabled="$ctrl.telegramGenerating" ng-class="{\'settings-oauth__connect--loading\': $ctrl.telegramGenerating }" > <span class="settings-oauth__provider-icon" style="color: #fff" aria-hidden="true" >â</span > <span ng-if="!$ctrl.telegramGenerating">{{ \'ÐÑивÑзаÑÑ Telegram\' | t }}</span> <span ng-if="$ctrl.telegramGenerating">{{ \'ÐенеÑиÑÑем кодâ¦\' | t }}</span> </button> </div> </div> </form> </div> <div ng-if="$ctrl.activeTab === \'notifications\'" id="panel-notifications" class="settings-tab-content" role="tabpanel" aria-labelledby="tab-notifications" > <div class="settings-content__header"> <h1 class="settings-content__title">{{ \'УведомлениÑ\' | t }}</h1> <p class="settings-content__subtitle"> {{ \'ÐÑбеÑиÑе, какие ÑÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð²Ñ Ñ
оÑиÑе полÑÑаÑÑ\' | t }} </p> </div> <form class="settings-notif-form" ng-submit="$ctrl.saveNotifications()"> <table class="settings-notif-table"> <thead> <tr> <th>{{ \'Тип\' | t }}</th> <th>{{ \'Ðа ÑайÑе\' | t }}</th> <th>{{ \'Email\' | t }}</th> </tr> </thead> <tbody> <tr> <td>{{ \'ÐомменÑаÑии\' | t }}</td> <td> <input type="checkbox" ng-model="$ctrl.notifPrefs.comments_site" aria-label="{{ \'ÐомменÑаÑии на ÑайÑе\' | t }}" /> </td> <td> <input type="checkbox" ng-model="$ctrl.notifPrefs.comments_email" aria-label="{{ \'ÐомменÑаÑии по email\' | t }}" /> </td> </tr> <tr> <td>{{ \'РемаÑки\' | t }}</td> <td> <input type="checkbox" ng-model="$ctrl.notifPrefs.remarks_site" aria-label="{{ \'РемаÑки на ÑайÑе\' | t }}" /> </td> <td> <input type="checkbox" ng-model="$ctrl.notifPrefs.remarks_email" aria-label="{{ \'РемаÑки по email\' | t }}" /> </td> </tr> <tr> <td>{{ \'УпоминаниÑ\' | t }}</td> <td> <input type="checkbox" ng-model="$ctrl.notifPrefs.mentions_site" aria-label="{{ \'Ð£Ð¿Ð¾Ð¼Ð¸Ð½Ð°Ð½Ð¸Ñ Ð½Ð° ÑайÑе\' | t }}" /> </td> <td> <input type="checkbox" ng-model="$ctrl.notifPrefs.mentions_email" aria-label="{{ \'Ð£Ð¿Ð¾Ð¼Ð¸Ð½Ð°Ð½Ð¸Ñ Ð¿Ð¾ email\' | t }}" /> </td> </tr> <tr> <td>{{ \'ÐÑиглаÑениÑ\' | t }}</td> <td> <input type="checkbox" ng-model="$ctrl.notifPrefs.invites_site" aria-label="{{ \'ÐÑиглаÑÐµÐ½Ð¸Ñ Ð½Ð° ÑайÑе\' | t }}" /> </td> <td> <input type="checkbox" ng-model="$ctrl.notifPrefs.invites_email" aria-label="{{ \'ÐÑиглаÑÐµÐ½Ð¸Ñ Ð¿Ð¾ email\' | t }}" /> </td> </tr> <tr> <td>{{ \'ÐÑбликаÑии\' | t }}</td> <td> <input type="checkbox" ng-model="$ctrl.notifPrefs.published_site" aria-label="{{ \'ÐÑбликаÑии на ÑайÑе\' | t }}" /> </td> <td> <input type="checkbox" ng-model="$ctrl.notifPrefs.published_email" aria-label="{{ \'ÐÑбликаÑии по email\' | t }}" /> </td> </tr> <tr> <td>{{ \'ÐÑавки (пÑедложениÑ)\' | t }}</td> <td> <input type="checkbox" ng-model="$ctrl.notifPrefs.suggestions_site" aria-label="{{ \'ÐÑавки на ÑайÑе\' | t }}" /> </td> <td> <input type="checkbox" ng-model="$ctrl.notifPrefs.suggestions_email" aria-label="{{ \'ÐÑавки по email\' | t }}" /> </td> </tr> <tr> <td>{{ \'СообÑениÑ\' | t }}</td> <td> <input type="checkbox" ng-model="$ctrl.notifPrefs.messages_site" aria-label="{{ \'СообÑÐµÐ½Ð¸Ñ Ð½Ð° ÑайÑе\' | t }}" /> </td> <td> <input type="checkbox" ng-model="$ctrl.notifPrefs.messages_email" aria-label="{{ \'СообÑÐµÐ½Ð¸Ñ Ð¿Ð¾ email\' | t }}" /> </td> </tr> </tbody> </table> <div class="settings-notif-actions"> <button type="submit" class="ds-btn ds-btn-primary" ng-disabled="$ctrl.notifSaving || !$ctrl.hasNotifChanges()" > {{ $ctrl.notifSaving ? (\'СоÑ
Ñанение...\' | t) : (\'СоÑ
ÑаниÑÑ\' | t) }} </button> </div> </form> </div> <div ng-if="$ctrl.activeTab === \'subscriptions\'" id="panel-subscriptions" class="settings-tab-content" role="tabpanel" aria-labelledby="tab-subscriptions" > <div class="settings-content__header"> <h1 class="settings-content__title">{{ \'ÐодпиÑки\' | t }}</h1> <p class="settings-content__subtitle"> {{ \'ÐдеÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ ÑпÑавлÑÑÑ Ð²Ñеми Ñвоими подпиÑками Ð
1½Ð° ÑайÑе\' | t }} </p> </div> <div class="settings-sub-tabs"> <button type="button" class="settings-sub-tab" ng-class="{\'settings-sub-tab--active\': $ctrl.subTab === \'all\' }" ng-click="$ctrl.setSubTab(\'all\')" > {{ \'ÐÑе\' | t }} <span class="settings-sub-tab__count">{{ $ctrl.subscriptionCounts.all }}</span> </button> <button type="button" class="settings-sub-tab" ng-class="{\'settings-sub-tab--active\': $ctrl.subTab === \'users\' }" ng-click="$ctrl.setSubTab(\'users\')" > {{ \'ÐолÑзоваÑели\' | t }} <span class="settings-sub-tab__count">{{ $ctrl.subscriptionCounts.users }}</span> </button> <button type="button" class="settings-sub-tab" ng-class="{\'settings-sub-tab--active\': $ctrl.subTab === \'tags\' }" ng-click="$ctrl.setSubTab(\'tags\')" > {{ \'ТемÑ\' | t }} <span class="settings-sub-tab__count">{{ $ctrl.subscriptionCounts.tags }}</span> </button> </div> <div class="settings-search"> <div class="settings-search__wrap"> <input class="settings-search__input" type="text" ng-model="$ctrl.subscriptionSearch" ng-change="$ctrl.filterSubscriptions()" ng-model-options="{ debounce: 300 }" placeholder="{{ \'ÐоиÑк\' | t }}" /> <i class="fas fa-search settings-search__icon"></i> </div> </div> <div class="settings-subscription-list" ng-if="$ctrl.subscriptionsLoading"> <div class="settings-skeleton-item" ng-repeat="i in [1,2,3,4,5] track by $index"> <div class="settings-skeleton-item__avatar settings-skeleton-pulse"></div> <div class="settings-skeleton-item__info"> <div class="settings-skeleton-item__name settings-skeleton-pulse"></div> <div class="settings-skeleton-item__desc settings-skeleton-pulse"></div> </div> <div class="settings-skeleton-item__btn settings-skeleton-pulse"></div> </div> </div> <div class="settings-subscription-list" ng-if="!$ctrl.subscriptionsLoading"> <a class="settings-subscription-item" ng-repeat="item in $ctrl.filteredSubscriptions track by (item.type + \':\' + item.id)" ng-href="{{ $ctrl.getSubscriptionLink(item) }}" > <img ng-if="item.type === \'user\' && item.thumborId" class="settings-subscription-item__avatar" ng-src="{{ item.thumborId | imageUrl: 96:96 }}" /> <div ng-if="item.type === \'user\' && !item.thumborId" class="settings-subscription-item__avatar settings-subscription-item__avatar--placeholder" > <i class="fas fa-user"></i> </div> <div ng-if="item.type === \'tag\'" class="settings-subscription-item__topic-icon"> <span ng-include="\'/partials/icons/hashtag.html\'"></span> </div> <div class="settings-subscription-item__info"> <div class="settings-subscription-item__name" ng-class="{\'settings-subscription-item__name--topic\': item.type === \'tag\' }" > {{ item.name }} </div> <div class="settings-subscription-item__description" ng-if="item.description || item.itemsCount" > {{ item.description || (item.itemsCount | pluralize:\'пÑбликаÑиÑ\':\'пÑбликаÑии\':\'пÑбликаÑий\') }} </div> </div> <div class="settings-subscription-item__action" ng-if="!$ctrl.isCurrentUser(item)"> <button type="button" class="settings-subscription-item__btn" ng-class="{\'settings-subscription-item__btn--subscribed\': item.isSubscribed, \'settings-subscription-item__btn--subscribe\': !item.isSubscribed }" ng-disabled="item.loading" ng-click="$ctrl.toggleFollow(item, $event)" > <span ng-if="!item.loading" >{{ item.isSubscribed ? (\'ÐÑ Ð¿Ð¾Ð´Ð¿Ð¸ÑанÑ\' | t) : (\'ÐодпиÑаÑÑÑÑ\' | t) }}</span > <i ng-if="item.loading" class="fas fa-sync-alt fa-spin"></i> </button> </div> </a> <div class="settings-field__hint" style="text-align: center; padding: 12px 0" ng-if="$ctrl.hasMoreSubscriptions && $ctrl.filteredSubscriptions.length > 0" > {{ \'ÐÐ¾ÐºÐ°Ð·Ð°Ð½Ñ Ð¿ÐµÑвÑе\' | t }} {{ $ctrl.subscriptionCounts.all }} {{ \'подпиÑок. ÐолнÑй ÑпиÑок доÑÑÑпен на ваÑей ÑÑÑаниÑе пÑоÑилÑ.\' | t }} </div> <div class="settings-placeholder" ng-if="$ctrl.filteredSubscriptions.length === 0"> <div class="settings-placeholder__icon"> <i class="fas fa-users"></i> </div> <div class="settings-placeholder__title" ng-if="!$ctrl.subscriptionSearch"> {{ \'У Ð²Ð°Ñ Ð¿Ð¾ÐºÐ° Ð½ÐµÑ Ð¿Ð¾Ð´Ð¿Ð¸Ñок\' | t }} </div>
1 <div class="settings-placeholder__text" ng-if="!$ctrl.subscriptionSearch"> <a href="/authors" class="linklike">{{ \'ÐайÑи авÑоÑов\' | t }}</a> </div> <div class="settings-placeholder__title" ng-if="$ctrl.subscriptionSearch"> {{ \'ÐиÑего не найдено\' | t }} </div> <div class="settings-placeholder__text" ng-if="$ctrl.subscriptionSearch"> {{ \'ÐопÑобÑйÑе измениÑÑ Ð·Ð°Ð¿ÑоÑ\' | t }} </div> </div> </div> </div> </main> </div> </div> </div> <div class="settings-actions settings-actions--sticky" ng-if="$ctrl.authorized && $ctrl.hasUnsavedChanges" > <div class="ds-container"> <div class="tw:row-flex"> <div class="tw:gutter-half tw:w-full tw:md:w-10/12 tw:md:ml-offset-2"> <div class="settings-actions__inner"> <button type="button" class="settings-actions__cancel" ng-click="$ctrl.cancelChanges()"> {{ \'ÐÑмениÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ\' | t }} </button> <button type="button" class="settings-actions__save" ng-disabled="$ctrl.savingProfile || $ctrl.savingSecurity" ng-click="$ctrl.activeTab === \'security\' ? $ctrl.saveSecurity() : $ctrl.saveProfile()" > <span ng-hide="$ctrl.savingProfile || $ctrl.savingSecurity" >{{ \'СоÑ
ÑаниÑÑ Ð½Ð°ÑÑÑойки\' | t }}</span > <i ng-show="$ctrl.savingProfile || $ctrl.savingSecurity" class="fas fa-sync-alt fa-spin" ></i> </button> </div> </div> </div> </div> </div>'),s.put("/pages/edit/editContentItem/customTypeahead.html",'<a> <span ng-bind-html="match.label | typeaheadHighlight:query"></span> <span class="tag-counter" ng-bind="match.model.itemsCount"></span> </a>'),s.put("/pages/edit/editContentItem/editContentItem.html",'<link rel="stylesheet" href="/styles/editor-e839e09a.css" /> <auth-required-screen ng-if="$ctrl.requiresAuth" title="{{ \'ÐойдиÑе Ð´Ð»Ñ Ð´Ð¾ÑÑÑпа к&nbsp;маÑеÑиалÑ\' | t }}" description="{{ \'ÐÐ»Ñ ÑедакÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð¼Ð°ÑеÑиала<br>необÑ
одимо войÑи в&nbsp;Ñвой аккаÑнÑ\' | t }}" icon="fas fa-edit" button-text="{{ \'ÐойÑи\' | t }}" on-login-click="$ctrl.openLoginModal()" ></auth-required-screen> <div class="auth-required-screen" ng-cloak ng-if="!$ctrl.requiresAuth && $ctrl.accessDenied"> <update-meta title="{{ \'Ðе ÑдаеÑÑÑ Ð¾ÑкÑÑÑÑ ÑÑÑаниÑÑ\' | t }}"></update-meta> <update-meta name="robots" content="noindex, nofollow"></update-meta> <div class="ds-container"> <div class="tw:row-flex"> <div class="tw:gutter-half tw:w-full tw:md:w-6/12 tw:md:ml-offset-3 tw:text-center"> <div class="auth-required-content"> <i class="{{ $ctrl.accessDeniedIcon ||\'fas fa-lock\' }} auth-required-icon"></i> <h2>{{ ($ctrl.accessDeniedTitle || \'Ðе ÑдаеÑÑÑ Ð¾ÑкÑÑÑÑ ÑÑÑаниÑÑ\') | t }}</h2> <p class="auth-required-description" ng-if="$ctrl.accessDeniedMessage"> {{ $ctrl.accessDeniedMessage | t }} </p> <p class="auth-required-description" ng-if="!$ctrl.accessDeniedMessage"> {{ \'Ðозможно, ÑÑÑаниÑÑ Ð½Ðµ ÑÑÑеÑÑвÑеÑ\' | t }}<br />{{ \'или к ней Ð½ÐµÑ Ð´Ð¾ÑÑÑпа\' | t }} </p> <p class="auth-required-description" ng-if="$ctrl.accessDeniedEmailUnverified"> {{ \'ÐÑли пÑиглаÑение пÑиÑлали на поÑÑÑ, подÑвеÑдиÑе адÑÐµÑ â доÑÑÑп оÑкÑоеÑÑÑ ÑÑÐ°Ð·Ñ Ð¿Ð¾Ñле ÑÑого.\' | t }} </p> <div class="auth-required-actions"> <button type="button" ng-if="$ctrl.canRetryEditorLoad" ng-click="$ctrl.retryEditorLoad()" class="ds-btn ds-btn-primary" > {{ \'ÐовÑоÑиÑÑ\' | t }} </button> <a href="/" ng-class="$ctrl.canRetryEditorLoad ? \'auth-required-btn-secondary\' : \'ds-btn ds-btn-primary\'" >{{ \'Ðа главнÑÑ\' | t }}</a > <a ng-if="$ctrl.accessDeniedLink" ng-href="{{ $ctrl.accessDeniedLink }}" class="auth-required-btn-secondary" >{{ \'ÐÑкÑÑÑÑ Ð¼Ð°ÑеÑиал\' | t }}</a > <button ng-if="$ctrl.canRequestAccess" ng-click="$ctrl.showAccessRequestModal = true" class="auth-required-btn-secondary" > {{ \'ÐапÑоÑиÑÑ Ð´Ð¾ÑÑÑп\' | t }} </button> <button type="button" ng-if="$ctrl.accessDeniedEmailUnverified" ng-click="$ctrl.openEmailVerification()" class="auth-required-btn-secondary" > {{ \'ÐодÑвеÑдиÑÑ Ð¿Ð¾ÑÑÑ\' | t }} </button> </div> <p ng-if="$ctrl.accessRequestSent" class="tw:mt-4 tw:text-success"> {{ \'ÐапÑÐ¾Ñ Ð½Ð° доÑÑÑп оÑпÑавлен\' | t }} </p> </div> </div> </div> </div> <request-contribution ng-if="$ctrl.showAccessRequestModal" document-name="$ctrl.accessRequestDocName" opened="$ctrl.showAccessRequestModal" on-close
1="$ctrl.showAccessRequestModal = false" on-sent-change="$ctrl.onAccessRequestSent(sent)" ></request-contribution> </div> <div class="ds-container" ng-if="!$ctrl.requiresAuth && !$ctrl.accessDenied"> <ng-include src="\'/pages/other/error.html\'" ng-if="contentItem.error" ng-init="$root.statusCode = contentItem.error.value" ></ng-include> </div> <div class="ds-container post-form has-tiptap-editor" ng-class="{\'has-admin-tools\': $ctrl.isAdmin}" ng-if="!$ctrl.requiresAuth && !$ctrl.accessDenied && !contentItem.error && ($ctrl.types[contentItem.type] || $ctrl.isGalleryLoading)" ng-cloak > <update-meta title="{{ title }}" ng-if="title"></update-meta> <update-meta name="robots" content="noindex, nofollow"></update-meta> <update-meta ng-if="$ctrl.types[contentItem.type]" name="description" content="{{ $ctrl.types[contentItem.type].description }}" ></update-meta> <update-meta name="keywords" content="{{ \'Discours.io, ÑÑаÑÑ Ð°Ð²ÑоÑом, пеÑоÑниÑа\' | t }}" ></update-meta> <update-meta ng-if="$ctrl.types[contentItem.type]" property="og:title" content="{{ $ctrl.types[contentItem.type].og_title }}" ></update-meta> <update-meta ng-if="$ctrl.types[contentItem.type]" property="og:description" content="{{ $ctrl.types[contentItem.type].og_description }}" ></update-meta> <update-meta property="og:image" content="/images/joinfull.webp"></update-meta> <update-meta property="og:image:width" content="1800"></update-meta> <update-meta property="og:image:height" content="1083"></update-meta> <form class="discours-form" name="articleForm" novalidate ng-class="{\'editor-form-ready\': $ctrl.tiptapReady || $ctrl.tiptapExpoEditor || $ctrl.album || (!$ctrl.useTiptapEditor && !$ctrl.useTiptapExpoEditor) }" > <div class="editor-content-row tw:flex tw:flex-wrap tw:mt-20"> <div class="editor-main-col tw:sm:w-8/12 tw:md:ml-offset-2"> <div ng-if="$ctrl.isGalleryLoading" class="editor-skeleton"> <div class="skeleton-title"></div> <div class="skeleton-gallery-row"> <div class="skeleton-image"></div> <div class="skeleton-content"> <div class="skeleton-subtitle"></div> <div class="skeleton-text"></div> <div class="skeleton-text skeleton-text--85"></div> <div class="skeleton-text skeleton-text--70"></div> </div> </div> <div class="skeleton-gallery-row"> <div class="skeleton-image"></div> <div class="skeleton-content"> <div class="skeleton-subtitle"></div> <div class="skeleton-text"></div> <div class="skeleton-text skeleton-text--90"></div> </div> </div> </div> <ng-include ng-if="contentItem.type && !$ctrl.album" src="\'/pages/edit/editContentItem/types/\' + contentItem.type + \'.html\'" ></ng-include> <ng-include ng-if="contentItem.type && $ctrl.album && !$ctrl.isGalleryLoading" src="\'/pages/edit/editContentItem/types/\' + contentItem.type + \'Album.html\'" ></ng-include> </div> </div> <div class="category-selector-button-wrapper tw:flex tw:flex-wrap" ng-class="{ active: $ctrl.categorySelectorOpen }" ng-hide="$ctrl.isPreviewMode" > <div class="category-selector-col tw:sm:w-8/12 tw:md:ml-offset-2 tw:-mt-2.5"> <div class="form-flex-layout tw:flex tw:flex-wrap"> <div class="category-label-col tw:w-3/12 form-label-title"> <div class="tags-title" ng-if=" contentItem.type != \'Literature\' && contentItem.type != \'Music\' && contentItem.type != \'Video\' && contentItem.type != \'Image\' " > {{ \'ÑÑбÑика:\' | t }} </div> <div class="tags-title" ng-if=" contentItem.type == \'Literature\' || contentItem.type == \'Music\' || contentItem.type == \'Video\' || contentItem.type == \'Image\' " > {{ \'жанÑ:\' | t }} </div> </div> <div class="category-input-col tw:sm:w-8/12"> <button type="button" class="category-selector-button" ng-class="{\'category-selector-button--error\': formErrors.category}" ng-click="$ctrl.categorySelectorClick($event)" id="category-selector-button" aria-invalid="{{ !!formErrors.category }}" aria-describedby="form-error-category" > <span id="category-selector-text" class="placeholder" ng-if="!contentItem.selectedCategory" >{{ \'вÑбÑаÑÑ\' | t }} </span> <span ng-if="contentItem.selectedCategory" id="category-selector-text"> {{ contentItem.selectedCategory.title | t }} </span> </button> <ul class="sort-menu post-menu category-selector" ng-class="{ active: $ctrl.categorySelectorOpen }" > <li ng-repeat="category in $ctrl.categories track by category._id" ng-class="{ active: contentItem.selectedCategory == category }" > <a ng-click="contentItem.selectedCategory = category; formErrors.category = false; $ctrl.categorySelectorOpen = false;" >{{ category.title | t }}</a > </li> </ul> <span id="form-error-category" class="help-block" ng-show="formErrors.category" role="alert" >{{ \'ÐÑбеÑиÑе ÑÑбÑикÑ\' | t }}</span > </div> </div> </div> </div> <div class="tags-row-wrapper tw:flex tw:flex-wrap" ng-hide="$ctrl.isPreviewMode"> <div class="tags-row-col tw:sm:w-8/12 tw:md:ml-offset-2 tw:-mt-[5px]"> <div class="form-flex-layout tw:flex tw:flex-wrap"> <div class="tags-label-col tw:w-3/12 form-label-title"> <div class="tags-title">{{ \'ÑемÑ:\' | t }}</div> </div> <div class="tags-input-col tw:sm:w-8/12 tw:lg:w-10/12"> <ul class="tags edit"> <li ng-repeat="tag in contentItem.tags track by (tag._id || tag.title || $index)"> <a ng-click="$ctrl.removeTag(tag)">{{ tag.title }}<span class="times">Ã</span></a> </li> <li> <input type="text" placeholder="{{ \'добавиÑÑ ÑемÑ\' | t }}" class="tags-input tags-auto-width" ng-model="$ctrl.newTag" simple-typeahead="tag as tag.title for tag in $ctrl.tagsTypeahead($viewValue)" typeahead-loading="$ctrl.tagLoading" typeahead-on-select="$ctrl.inputSelect($item, $model, $label)" typeahead-template-url="/pages/edit/editContentItem/customTypeahead.html" aria-label="{{ \'ÐобавиÑÑ ÑемÑ\' | t }}" /><span class="tags-spinner" style=" display: inline-block; width: 1.25em; margin-left: 6px; vertical-align: middle; " ><i class="fas fa-sync-alt fa-spin" ng-show="$ctrl.tagLoading"></i ></span> </li> </ul> </div> </div> </div> </div> <div class="editor-content-row tw:flex tw:flex-wrap tw:mt-20 tw:mb-2.5" ng-if="!$
1ctrl.isLoggedIn && !$ctrl.isPreviewMode && !$ctrl.contentItemCreatorId" > <div class="editor-main-col tw:sm:w-8/12 tw:md:ml-offset-2"> <h1 class="category-title big" ng-if="!$ctrl.isLoggedIn">{{ \'Ð ÐССÐÐÐÐТРРСÐÐÐ\' | t }}</h1> <h1 class="category-title big" ng-if="$ctrl.isLoggedIn"> <u>{{ $ctrl.types[contentItem.type].title }}</u> </h1> </div> </div> <div class="tw:flex tw:flex-wrap tw:mt-section" ng-if="!$ctrl.isLoggedIn && !$ctrl.isPreviewMode && !$ctrl.contentItemCreatorId" > <div class="editor-main-col tw:sm:w-8/12 tw:md:ml-offset-2"> <div class="app-about"> <div class="app-about__row" ng-class="{\'has-error\': formErrors.applicationName}"> <input class="app-about__input" placeholder="{{ \'Ðак Ð²Ð°Ñ Ð·Ð¾Ð²ÑÑ?\' | t }}" aria-label="{{ \'ÐаÑе Ð¸Ð¼Ñ Ð¸ ÑамилиÑ\' | t }}" ng-model="contentItem.application.name" ng-model-options="{ updateOn: \'blur\', debounce: 1000 }" ng-keydown="formErrors.applicationName = false" ng-change="$ctrl.sendNotSentApplication()" clear-blank-on-blur aria-invalid="{{ !!formErrors.applicationName }}" aria-describedby="form-error-app-name" /> <div class="app-about__note"> <span id="form-error-app-name" class="app-about__error" ng-show="formErrors.applicationName" role="alert" >{{ \'УкажиÑе имÑ\' | t }}</span > </div> </div> <div class="app-about__row" ng-class="{\'has-error\': formErrors.applicationEmail}"> <input class="app-about__input" placeholder="{{ \'ÐаÑа поÑÑа\' | t }}" aria-label="{{ \'ÐлекÑÑÐ¾Ð½Ð½Ð°Ñ Ð¿Ð¾ÑÑа\' | t }}" ng-model="contentItem.application.email" type="email" inputmode="email" ng-model-options="{ debounce: 1000 }" ng-keydown="formErrors.applicationEmail = false" ng-change="$ctrl.sendNotSentApplication()" clear-blank-on-blur aria-invalid="{{ !!formErrors.applicationEmail }}" aria-describedby="app-hint-email form-error-app-email" /> <div class="app-about__note"> <span class="app-about__hint" id="app-hint-email" >{{ \'ÐÐ»Ñ Ð¾ÑвеÑа ÑедакÑии\' | t }}</span > <span id="form-error-app-email" class="app-about__error" ng-show="formErrors.applicationEmail" role="alert" >{{ \'УкажиÑе коÑÑекÑнÑй email\' | t }}</span > </div> </div> <div class="app-about__row app-about__row--bio"> <textarea class="app-about__input app-about__input--bio" rows="1" ng-model="contentItem.application.bio" placeholder="{{ \'Чем Ð²Ñ Ð·Ð°Ð½Ð¸Ð¼Ð°ÐµÑеÑÑ?\' | t }}" aria-label="{{ \'ÐиогÑаÑÐ¸Ñ Ð°Ð²ÑоÑа\' | t }}" msd-elastic="msd-elastic" ng-model-options="{ debounce: 1000 }" ng-change="$ctrl.sendNotSentApplication()" clear-blank-on-blur aria-describedby="app-hint-bio" ></textarea> <div class="app-about__note"> <span class="app-about__hint" id="app-hint-bio" >{{ \'РаÑÑкажиÑе немного о Ñебе, ÑÑÐ¾Ñ ÑекÑÑ Ð¿Ð¾ÑвиÑÑÑ Ð² ваÑем пÑоÑиле\' | t }}</span > </div> </div> </div> </div> </div> <div class="edit-actions tw:sm:w-8/12 tw:md:ml-offset-2" ng-hide="$ctrl.isPreviewMode"> <div class="edit-actions__row"> <div class="edit-actions__main"> <button ng-if="$ctrl.canEdit === true || !$ctrl.isLoggedIn" class="edit-action-btn edit-action-btn--primary ng-animate-disabled" type="button" ng-disabled="contentItemSending || $ctrl.disableSendButton" ng-click="$ctrl.sendForm($event)" > <span ng-class="{\'edit-button-text--hidden\': sendingAction === \'submit\'}" >{{ \'ÐпÑбликоваÑÑ\' | t }}</span ><i class="fas fa-sync-alt fa-spin edit-button-spinner ng-animate-disabled" ng-if="sendingAction === \'submit\'" ></i> </button> <button ng-if="$ctrl.canEdit === false" class="edit-action-btn edit-action-btn--primary ng-animate-disabled" type="button" ng-click="$ctrl.finishAndNavigateToArticle()" > {{ \'ÐоÑово\' | t }} </button> <button ng-if="$ctrl.canEdit === true && $ctrl.isLoggedIn && (!contentItem.slug || $ctrl.saveAndCreateVersion)" class="edit-action-btn edit-action-btn--secondary ng-animate-disabled" type="button" ng-disabled="contentItemSending || $ctrl.disableSendButton" ng-click="$ctrl.saveDraftBtnClick($event)" title="{{ \'СоÑ
ÑаниÑÑ ÑеÑновик\' | t }}" > <span ng-class="{\'edit-button-text--hidden\': sendingAction === \'draft\'}" >{{ \'СоÑ
ÑаниÑÑ ÑеÑновик\' | t }}</span ><i class="fas fa-sync-alt fa-spin edit-button-spinner ng-animate-disabled" ng-if="sendingAction === \'draft\'" ></i> </button>
1 <button class="edit-action-btn edit-action-btn--ghost" type="button" ng-click="$ctrl.openPreviewModeAndScrollTop()" > {{ \'ÐÑедпÑоÑмоÑÑ\' | t }} </button> </div> <button class="edit-action-btn edit-action-btn--danger" ng-click="$ctrl.deleteContentItem(contentItem.slug)" type="button" ng-if="contentItem._id && ($ctrl.isAdmin || $ctrl.canDeleteOwn())" > {{ \'УдалиÑÑ\' | t }} </button> </div> </div> <div class="version-history-panel" ng-if="$ctrl.versionsVisible" ng-class="{\'with-preview\': $ctrl.selectedVersion }" > <div class="version-history-header"> <h3>{{ \'ÐÑÑоÑÐ¸Ñ Ð²ÐµÑÑий\' | t }}</h3> <div class="version-header-actions" ng-if="!$ctrl.selectedVersion"> <button class="version-header-save-btn ng-animate-disabled" type="button" ng-click="$ctrl.openVersionNameDialog()" ng-disabled="$ctrl.savingVersion" title="{{ \'СоÑ
ÑаниÑÑ ÑекÑÑее ÑоÑÑоÑние как веÑÑиÑ\' | t }}" > <span ng-if="$ctrl.savingVersion"><i class="fa fa-spinner fa-spin"></i></span> <span ng-if="!$ctrl.savingVersion">{{ \'СоÑ
ÑаниÑÑ Ð²ÐµÑÑиÑ\' | t }}</span> </button> <button type="button" class="close-btn" ng-click="$ctrl.toggleVersions()" title="{{ \'ÐакÑÑÑÑ\' | t }}" > <i class="fa fa-times"></i> </button> </div> </div> <div class="version-stats" ng-if="$ctrl.versionStats && $ctrl.versionStats.total > 0"> <span title="{{ \'ÐвÑоÑоÑ
ÑанениÑ\' | t }}" ng-if="$ctrl.versionStats.counts.auto > 0"> <i class="fa fa-clock-o"></i> {{ $ctrl.versionStats.counts.auto }} </span> <span title="{{ \'ÐÑÑпнÑе изменениÑ\' | t }}" ng-if="$ctrl.versionStats.counts.milestone > 0"> <i class="fa fa-flag"></i> {{ $ctrl.versionStats.counts.milestone }} </span> <span title="{{ \'СоÑ
Ñанено вÑÑÑнÑÑ\' | t }}" ng-if="$ctrl.versionStats.counts.manual > 0"> <i class="fa fa-save"></i> {{ $ctrl.versionStats.counts.manual }} </span> <span title="{{ \'ÐÑи пÑбликаÑии\' | t }}" ng-if="$ctrl.versionStats.counts.publish > 0"> <i class="fa fa-check-circle"></i> {{ $ctrl.versionStats.counts.publish }} </span> </div> <div class="version-loading" ng-if="$ctrl.versionsLoading"> <i class="fa fa-spinner fa-spin"></i> {{ \'ÐагÑÑзка...\' | t }} </div> <div class="version-list" ng-if="!$ctrl.versionsLoading"> <div class="version-empty" ng-if="$ctrl.versions.length === 0"> <p>{{ \'ÐеÑÑии еÑÑ Ð½Ðµ ÑозданÑ\' | t }}</p> <p class="hint"> {{ \'ÐеÑÑии ÑоздаÑÑÑÑ Ð°Ð²ÑомаÑиÑеÑки каждÑе 20 минÑÑ, пÑи пÑбликаÑии и пÑи знаÑиÑелÑнÑÑ
изменениÑÑ
.\' | t }} </p> </div> <div class="version-item" ng-repeat="version in $ctrl.versions track by version._id" ng-class="{\'version-auto\': version.type === \'auto\', \'version-milestone\': version.type === \'milestone\', \'version-manual\': version.type === \'manual\', \'version-publish\': version.type === \'publish\', \'version-legacy\': version.type === \'legacy\', \'selected\': $ctrl.selectedVersion && $ctrl.selectedVersion._id === version._id }" ng-click="$ctrl.previewVersion(version)" > <div class="version-icon"> <i class="fa" ng-class="version.typeIcon"></i> </div> <div class="version-info"> <div class="version-header"> <span class="version-type">{{ version.name || version.typeLabel }}</span> <span class="version-number" ng-if="version.versionNumber" >v{{ version.versionNumber }}</span > </div> <div class="version-meta"> <span class="version-date">{{ version.formattedDate }}</span> <span class="version-author" ng-if="version.createdByName && version.createdByName !== \'СиÑÑема\'" > â {{ version.createdByName }} </span> </div> <div class="version-change" ng-if="version.changePercentFormatted"> <span class="change-label">{{ \'ÐзменениÑ:\' | t }}</span> {{ version.changePercentFormatted }} </div> </div> <div class="version-actions" ng-click="$event.stopPropagation()"> <button type="button" class="version-action-btn restore" ng-click="$ctrl.restoreVersion(version)" title="{{ \'ÐоÑÑÑановиÑÑ ÑÑÑ Ð²ÐµÑÑиÑ\' | t }}" > <i class="fa fa-undo"></i> </button> <button type="button" class="version-action-btn delete" ng-if="version.type === \'manual\'" ng-click="$ctrl.deleteVersion(version)" title="{{ \'УдалиÑÑ Ð²ÐµÑÑиÑ\' | t }}" >
1 <i class="fa fa-trash"></i> </button> </div> </div> </div> <div class="version-preview" ng-if="$ctrl.selectedVersion"> <div class="version-preview-header"> <h4> <span ng-if="$ctrl.selectedVersion.versionNumber" >{{ \'ÐеÑÑиÑ\' | t }} {{ $ctrl.selectedVersion.versionNumber }}</span > <span ng-if="!$ctrl.selectedVersion.versionNumber" >{{ $ctrl.selectedVersion.typeLabel }}</span > <span class="version-type-badge" ng-if="$ctrl.selectedVersion.versionNumber" >{{ $ctrl.selectedVersion.typeLabel }}</span > </h4> <button type="button" class="close-btn" ng-click="$ctrl.closeVersionPreview()" title="{{ \'ÐакÑÑÑÑ\' | t }}" > <i class="fa fa-times"></i> </button> </div> <div class="version-preview-meta"> <span>{{ $ctrl.selectedVersion.formattedDate }}</span> <span ng-if="$ctrl.selectedVersion.name"> â {{ $ctrl.selectedVersion.name }}</span> </div> <div class="version-preview-actions"> <button type="button" class="ds-btn btn-compare" ng-click="$ctrl.openDiffPopup()"> <i class="fa fa-columns"></i> {{ \'СÑавниÑÑ\' | t }} </button> <button type="button" class="ds-btn ds-btn-primary" ng-click="$ctrl.restoreVersion($ctrl.selectedVersion)" > <i class="fa fa-undo"></i> {{ \'ÐоÑÑÑановиÑÑ\' | t }} </button> </div> <div class="version-view-toggle" role="group" aria-label="{{ \'Ðид веÑÑии\' | t }}" ng-if="$ctrl.versionViews.hasMarks" > <button type="button" class="version-view-toggle__btn" ng-class="{ \'is-active\': $ctrl.versionView === \'clean\' }" aria-pressed="{{ $ctrl.versionView === \'clean\' }}" ng-click="$ctrl.setVersionView(\'clean\')" > {{ \'Ðез пÑавок\' | t }} </button> <button type="button" class="version-view-toggle__btn" ng-class="{ \'is-active\': $ctrl.versionView === \'marks\' }" aria-pressed="{{ $ctrl.versionView === \'marks\' }}" ng-click="$ctrl.setVersionView(\'marks\')" > {{ \'С пÑавками\' | t }} </button> </div> <div class="version-preview-content" ng-class="{ \'version-preview-content--marks\': $ctrl.isVersionMarksView() }" ng-bind-html="$ctrl.getVersionPreviewHtml() | trustedHtml" ></div> </div> </div> <div class="version-diff-popup-backdrop" ng-if="$ctrl.diffPopupVisible" ng-click="$ctrl.closeDiffPopup()" aria-hidden="true" ></div> <div class="version-diff-popup" ng-if="$ctrl.diffPopupVisible" role="dialog" aria-modal="true" aria-labelledby="version-diff-popup-title" tabindex="-1" > <div class="version-diff-popup-header"> <h3 id="version-diff-popup-title">{{ \'СÑавнение веÑÑий\' | t }}</h3> <button type="button" class="close-btn" ng-click="$ctrl.closeDiffPopup()" title="{{ \'ÐакÑÑÑÑ\' | t }}" aria-label="{{ \'ÐакÑÑÑÑ Ð¾ÐºÐ½Ð¾ ÑÑÐ°Ð²Ð½ÐµÐ½Ð¸Ñ Ð²ÐµÑÑий\' | t }}" > <i class="fa fa-times"></i> </button> </div> <div class="version-diff-loading" ng-if="$ctrl.diffLoading"> <i class="fa fa-spinner fa-spin"></i> {{ \'ÐÑÑиÑление ÑазлиÑий...\' | t }} </div> <div class="version-diff-popup-body" ng-if="!$ctrl.diffLoading && $ctrl.diffHtml"> <div class="version-diff-side"> <div class="version-diff-side-header"> <div class="version-dropdown version-dropdown--left"> <button type="button" class="version-dropdown__trigger" ng-click="$ctrl.toggleDiffDropdown(\'left\'); $event.stopPropagation()" ng-class="{\'version-dropdown__trigger--open\': $ctrl.diffDropdownOpen === \'left\' }" > <span class="version-dropdown__label" >{{ $ctrl.getDiffVersionLabel($ctrl.diffLeftVersionId) }}</span > <i class="fa fa-chevron-down version-dropdown__arrow"></i> </button> <div class="version-dropdown__menu" ng-if="$ctrl.diffDropdownOpen === \'left\'"> <div class="version-dropdown__item" ng-class="{\'version-dropdown__item--active\': $ctrl.diffLeftVersionId === \'__current__\' }" ng-click="$ctrl.selectDiffVersion(\'left\', \'__current__\')" > <i class="fa fa-file-alt version-dropdown__item-icon"></i> <span>{{ \'ТекÑÑий ÑекÑÑ\' | t }}</span> </div> <div class="version-dropdown__item" ng-repeat="v in $ctrl.versions track by v._id" ng-class="{\'version-dropdown__item--active\': $ctrl.diffLeftVersionId === v._id }" ng-click="$ctrl.selectDiffVersion(\'left\', v._id)" > <i class="fa version-dropdown__item-icon" ng-class="v.typeIcon"></i> <span>{{ v.name || v.formattedDate }}</span> <span class="version-dropdown__item-badge" ng-if="v.versionNumber" >v{{ v.versionNumber }}</span > </div> </div> </div> </div> <div class="version-diff-side-content" ng-bind-html="$ctrl.diffLeftHtml | trustedHtml" ></div> </div> <div class="version-diff-side version-diff-side--current"> <div class="version-diff-side-header"> <div class="version-dropdown version-dropdown--right"> <button type="button" class="version-dropdown__trigger" ng-click="$ctrl.toggleDiffDropdown(\'right\'); $event.stopPropagation()" ng-class="{\'version-dropdown__trigger--open\': $ctrl.diffDropdownOpen === \'right\' }" > <span class="version-dropdown__label" >{{ $ctrl.getDiffVersionLabel($ctrl.diffRightVersionId) }}</span > <i class="fa fa-chevron-down version-dropdown__arrow"></i> </button> <div class="version-dropdown__menu" ng-if="$ctrl.diffDropdownOpen === \'right\'"> <div class="version-dropdown__item" ng-class="{\'version-dropdown__item--active\': $ctrl.diffRightVersionId === \'__current__\' }" ng-click="$ctrl.selectDiffVersion(\'right\', \'__current__\')" > <i class="fa fa-file-alt version-dropdown__item-icon"></i> <span>{{ \'ТекÑÑий ÑекÑÑ\' | t }}</span> </div> <div class="version-dropdown__item" ng-repeat="v in $ctrl.versions track by v._id" ng-class="{\'version-dropdown__item--active\': $ctrl.diffRightVersionId === v._id }" ng-click="$ctrl.selectDiffVersion(\'right\', v._id)" > <i class="fa version-dropdown__item-icon" ng-class="v.typeIcon"></i> <span>{{ v.name || v.formattedDate }}</span> <span class="version-dropdown__item-badge" ng-if="v.versionNumber" >v{{ v.versionNumber }}</span > </div> </div> </div> <span class="version-diff-side-meta version-diff-legend-inline"> <ins>{{ \'добавлено\' | t }}</ins> <del>{{ \'Ñдалено\' | t }}</del> </span> </div> <div class="version-diff-scroll-wrapper"> <div class="version-diff-side-content version-diff-content" ng-bind-html="$ctrl.diffHtml | trustedHtml" ></div> <div class="version-diff-gutter"></div> </div> </div> </div>
1 <div class="version-diff-empty" ng-if="!$ctrl.diffLoading && !$ctrl.diffHtml"> <i class="fa fa-check-circle"></i> <p>{{ $ctrl.diffEmptyMessage || (\'ÐеÑÑии иденÑиÑнÑ\' | t) }}</p> <span class="hint" >{{ $ctrl.diffEmptyHint || (\'ÐÑбÑаннÑе веÑÑии не ÑодеÑÐ¶Ð°Ñ ÑазлиÑий\' | t) }}</span > </div> </div> <div class="tiptap-dialog-backdrop" ng-if="$ctrl.versionNameDialogVisible" ng-click="$ctrl.closeVersionNameDialog()" ></div> <div class="tiptap-dialog tiptap-version-dialog" ng-if="$ctrl.versionNameDialogVisible"> <div class="tiptap-dialog__header"> <div class="tiptap-dialog__title">{{ \'СоÑ
ÑаниÑÑ Ð²ÐµÑÑиÑ\' | t }}</div> <button type="button" class="tiptap-dialog__close" ng-click="$ctrl.closeVersionNameDialog()" aria-label="{{ \'ÐакÑÑÑÑ\' | t }}" > × </button> </div> <div class="tiptap-dialog__input-row"> <input type="text" class="tiptap-dialog__input" placeholder="{{ $ctrl.versionNamePlaceholder }}" ng-model="$ctrl.versionNameInput" ng-keydown="$event.keyCode === 13 && $ctrl.confirmSaveVersion(); $event.keyCode === 27 && $ctrl.closeVersionNameDialog()" autofocus /> </div> <div class="tiptap-dialog__hint"> {{ \'ÐÑÑавÑÑе пÑÑÑÑм Ð´Ð»Ñ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð¿Ð¾ ÑмолÑаниÑ\' | t }} </div> <div class="tiptap-dialog__buttons"> <button type="button" class="tiptap-dialog__btn tiptap-dialog__btn--secondary" ng-click="$ctrl.closeVersionNameDialog()" > {{ \'ÐÑмена\' | t }} </button> <button type="button" class="tiptap-dialog__btn tiptap-dialog__btn--primary ng-animate-disabled" ng-click="$ctrl.confirmSaveVersion()" ng-disabled="$ctrl.savingVersion" > <span ng-if="!$ctrl.savingVersion">{{ \'СоÑ
ÑаниÑÑ\' | t }}</span> <span ng-if="$ctrl.savingVersion"><i class="fa fa-spinner fa-spin"></i></span> </button> </div> </div> </form> </div>'),s.put("/pages/edit/editContentItem/partials/collab-capability-notice.html",'<p class="collab-capability-notice" ng-if="$ctrl.collabCommentStoreUnavailable" role="status"> {{ \'ÐомменÑаÑии и обÑÑÐ¶Ð´ÐµÐ½Ð¸Ñ Ð¿Ñавок в ÑÑом ÑообÑеÑÑве пока недоÑÑÑпнÑ\' | t }} </p>'),s.put("/pages/edit/editContentItem/partials/comment-filter.html",'<div class="sidebar-filter" ng-if="$ctrl.comments.length" ng-click="$event.stopPropagation()"> <button type="button" class="sidebar-filter-btn" ng-class="{ open: $ctrl.filterPopupOpen, filtered: $ctrl.isCommentFilterModified() }" ng-click="$ctrl.toggleFilterPopup($event)" aria-haspopup="true" aria-controls="comment-filter-popup" ng-attr-aria-expanded="{{ $ctrl.filterPopupOpen ? \'true\' : \'false\' }}" aria-label="{{ \'ФилÑÑÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑиев\' | t }}" title="{{ \'ФилÑÑÑÑ\' | t }}" > <i class="fas fa-filter" aria-hidden="true"></i> <span class="sidebar-filter-dot" ng-if="$ctrl.isCommentFilterModified()" aria-hidden="true" ></span> </button> <div id="comment-filter-popup" class="sidebar-filter-popup" ng-if="$ctrl.filterPopupOpen" role="group" aria-label="{{ \'ФилÑÑÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑиев\' | t }}" > <div class="filter-group-label" id="filter-status-label">{{ \'СÑаÑÑÑ\' | t }}</div> <div class="comment-filter" role="group" aria-labelledby="filter-status-label"> <button type="button" class="comment-filter__btn" ng-class="{ active: $ctrl.commentFilter === \'open\' }" ng-attr-aria-pressed="{{ $ctrl.commentFilter === \'open\' }}" ng-click="$ctrl.setCommentFilter(\'open\')" > {{ \'ÐÑкÑÑÑÑе\' | t }} </button> <button type="button" class="comment-filter__btn" ng-class="{ active: $ctrl.commentFilter === \'resolved\' }" ng-attr-aria-pressed="{{ $ctrl.commentFilter === \'resolved\' }}" ng-click="$ctrl.setCommentFilter(\'resolved\')" > {{ \'ÐакÑÑÑÑе\' | t }} </button> </div> <div class="filter-group-label" id="filter-source-label">{{ \'ÐÑÑоÑник\' | t }}</div> <div class="comment-filter comment-filter--type" role="group" aria-labelledby="filter-source-label" > <button type="button" class="comment-filter__btn" ng-class="{ active: $ctrl.remarkFilter === \'all\' }" ng-attr-aria-pressed="{{ $ctrl.remarkFilter === \'all\' }}" ng-click="$ctrl.setRemarkFilter(\'all\')" > {{ \'ÐÑе\' | t }} </button>
1 <button type="button" class="comment-filter__btn" ng-class="{ active: $ctrl.remarkFilter === \'readers\' }" ng-attr-aria-pressed="{{ $ctrl.remarkFilter === \'readers\' }}" ng-click="$ctrl.setRemarkFilter(\'readers\')" > {{ \'ÐÑ ÑиÑаÑелей\' | t }} </button> <button type="button" class="comment-filter__btn" ng-class="{ active: $ctrl.remarkFilter === \'editors\' }" ng-attr-aria-pressed="{{ $ctrl.remarkFilter === \'editors\' }}" ng-click="$ctrl.setRemarkFilter(\'editors\')" > {{ \'РедакÑоÑÑкие\' | t }} </button> </div> </div> </div>'),s.put("/pages/edit/editContentItem/partials/comment-list.html",'<div id="collab-recovery-list" class="collab-capability-notice collab-recovery-list" ng-if="$ctrl.commentRecoveryDrafts.length" > <p id="collab-recovery-status" role="status" aria-live="polite" aria-atomic="true" tabindex="-1"> {{ \'ÐеоÑпÑавленнÑй ÑекÑÑ ÑоÑ
ÑанÑн ниже. СкопиÑÑйÑе его пеÑед вÑÑ
одом Ñо ÑÑÑаниÑÑ\' | t }} </p> <div class="collab-recovery-draft" ng-repeat="draft in $ctrl.commentRecoveryDrafts track by draft.id" > <label for="collab-recovery-{{ ::$index }}">{{ draft.label | t }}</label> <textarea id="collab-recovery-{{ ::$index }}" readonly rows="3" ng-model="draft.text" ></textarea> </div> </div> <div class="sidebar-empty" ng-if="$ctrl.comments.length && !$ctrl.filteredComments.length"> <i class="fas fa-filter"></i> <p> {{ \'ÐеÑ\' | t }} {{ $ctrl.commentFilter === \'resolved\' ? (\'закÑÑÑÑÑ
\' | t) : (\'оÑкÑÑÑÑÑ
\' | t) }} {{ \'ÑемаÑок\' | t }}{{ $ctrl.remarkFilter === \'readers\' ? \' \' + (\'Ð¾Ñ ÑиÑаÑелей\' | t) : ($ctrl.remarkFilter === \'editors\' ? \' \' + (\'Ð¾Ñ ÑедакÑоÑов\' | t) : \'\') }} </p> </div> <div class="comment-list ng-animate-disabled" ng-if="$ctrl.filteredComments.length" data-collab-comments-region tabindex="-1" > <div class="comment-item" ng-repeat="comment in $ctrl.filteredComments | limitTo:$ctrl.commentsDisplayLimit track by comment.id" ng-class="{ resolved: comment.resolved, rejected: comment.rejected, orphaned: comment.orphaned, expanded: comment.isExpanded }" data-sidebar-comment-id="{{ ::comment.id }}" ng-click="$ctrl.toggleCommentExpand(comment)" role="group" ng-attr-aria-label="{{ ::(\'ÐомменÑаÑий оÑ\' | t) + \' \' + (comment.authorName || (\'ÐвÑоÑ\' | t)) }}" > <div class="comment-header"> <div class="comment-header-main"> <a class="comment-author" ng-href="/{{ ::comment.authorSlug }}" ng-if="::comment.authorSlug" target="_blank" rel="noopener noreferrer" ng-click="$event.stopPropagation()" > <img class="author-avatar" ng-if="::comment.authorAvatar" ng-src="{{ ::comment.authorAvatar }}" alt="" width="28" height="28" loading="lazy" decoding="async" ng-on-error="$event.target.style.display=\'none\'" /> <span class="author-avatar-placeholder" ng-if="::(!comment.authorAvatar && comment.authorId && comment.authorId !== \'anonymous\')" title="{{ ::comment.authorName || (\'ÐвÑоÑ\' | t) }}" >{{ ::(comment.authorName || (\'Ð\' | t)).charAt(0) }}</span > <span class="author-avatar-placeholder author-avatar-placeholder--anon" ng-if="::(!comment.authorAvatar && (!comment.authorId || comment.authorId === \'anonymous\'))" title="{{ \'Ðнонимно\' | t }}" ><i class="fas fa-user-secret" aria-hidden="true"></i ></span> <div class="sidebar-author-info"> <span class="author-name">{{ ::comment.authorName || (\'ÐвÑоÑ\' | t) }}</span> <span class="sidebar-date">{{ ::comment.createdAt | date:\'dd.MM HH:mm\' }}</span> </div> </a> <span class="comment-author" ng-if="::(!comment.authorSlug)"> <img class="author-avatar" ng-if="::comment.authorAvatar" ng-src="{{ ::comment.authorAvatar }}" alt="" width="28" height="28" loading="lazy" decoding="async" ng-on-error="$event.target.style.display=\'none\'" /> <span class="author-avatar-placeholder" ng-if="::(!comment.authorAvatar && comment.authorId && comment.authorId !== \'anonymous\')" title="{{ ::comment.authorName || (\'ÐвÑоÑ\' | t) }}" >{{ ::(comment.authorName || (\'Ð\' | t)).charAt(0) }}</span > <span class="author-avatar-placeholder author-avatar-placeholder--anon" ng-if="::(!comment.authorAvatar && (!comment.authorId || comment.authorId === \'anonymous\'))" title="{{ \'Ðнонимно\' | t }}" ><i class="fas fa-user-secret" aria-hidden="true"></i ></span> <div class="sidebar-author-info"> <span class="author-name" >{{ ::(!comment.authorId || comment.authorId === \'anonymous\') ? (\'Ðнонимно\' | t) : (comment.authorName || (\'ÐвÑоÑ\' | t)) }}</span > <span class="sidebar-date">{{ ::comment.createdAt | date:\'dd.MM HH:mm\' }}</span> </div> </span> <span class="remark-badge" ng-if="::comment.isRemark">{{ \'ÑемаÑка\' | t }}</span> </div> <div class="comment-actions" ng-class="{\'has-open-menu\': comment.menuOpen}" ng-click="$event.stopPropagation()" > <button type="button" class="ds-btn-link btn-icon card-disclosure" ng-click="$event.stopPropagation(); $ctrl.toggleCommentDisclosure(comment)" ng-attr-aria-expanded="{{ comment.isExpanded ? \'true\' : \'false\' }}" ng-attr-aria-controls="{{ comment.isExpanded ? (\'comment-discussion-\' + comment.id) : undefined }}" aria-label="{{ (comment.isExpanded ? \'СвеÑнÑÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑий\' : \'РазвеÑнÑÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑий\') | t }}" > <i class="fas fa-chevron-down" aria-hidden="true"></i> </button> <span class="ds-btn-link btn-icon orphaned-hint" ng-if="comment.orphaned" aria-label="{{ ::(comment.isRemark ? (\'РемаÑка ÑиÑаÑÐµÐ»Ñ â ÑÑÐ°Ð³Ð¼ÐµÐ½Ñ Ð½Ðµ пÑивÑзан к ÑекÑÑÑ\' | t) : (\'ÐомменÑаÑий не пÑивÑзан к ÑекÑÑÑ\' | t)) }}" > <i class="fas fa-unlink"></i> <span class="custom-tooltip" >{{ ::(comment.isRemark ? (\'Ðе пÑивÑзана к ÑекÑÑÑ\' | t) : (\'Ðе пÑивÑзан к ÑекÑÑÑ\' | t)) }}</span > </span> <button type="button" class="ds-btn-link btn-icon ds-btn-success" ng-click="$ctrl.resolve
1Comment(comment)" ng-if="!comment.resolved && !comment.rejected && $ctrl.canModerate()" ng-disabled="$ctrl.isCommentWriteBlocked(comment)" aria-label="{{ \'ÐÑинÑÑÑ\' | t }}" > <i class="fas fa-check"></i> <span class="custom-tooltip">{{ \'ÐÑинÑÑÑ\' | t }}</span> </button> <button type="button" class="ds-btn-link btn-icon" ng-click="$ctrl.unresolveComment(comment)" ng-if="comment.resolved && !comment.rejected && $ctrl.canModerate()" ng-disabled="$ctrl.isCommentWriteBlocked(comment)" aria-label="{{ \'ÐÑкÑÑÑÑ\' | t }}" > <i class="fas fa-undo"></i> <span class="custom-tooltip">{{ \'ÐÑкÑÑÑÑ\' | t }}</span> </button> <button type="button" class="ds-btn-link btn-icon ds-btn-warning" ng-click="$ctrl.rejectComment(comment)" ng-if="!comment.resolved && !comment.rejected && $ctrl.canModerate()" ng-disabled="$ctrl.isCommentWriteBlocked(comment)" data-collab-reject-id="{{ ::comment.id }}" data-collab-reject-surface="sidebar" aria-label="{{ \'ÐÑклониÑÑ\' | t }}" > <i class="fas fa-times"></i> <span class="custom-tooltip">{{ \'ÐÑклониÑÑ\' | t }}</span> </button> <div class="item-actions-menu" ng-if="$ctrl.canEditComment(comment) || $ctrl.canDeleteComment(comment)" > <button type="button" class="ds-btn-link btn-icon item-menu-trigger" ng-click="$ctrl.toggleItemMenu(comment, $event)" ng-disabled="$ctrl.isCommentWriteBlocked(comment)" aria-label="{{ \'ÐейÑÑÐ²Ð¸Ñ Ñ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑием\' | t }}" > <i class="fas fa-ellipsis-v"></i> </button> <div class="item-dropdown" ng-if="comment.menuOpen" ng-click="$event.stopPropagation()"> <button type="button" class="item-dropdown-btn" ng-if="$ctrl.canEditComment(comment) && !comment.resolved && !comment.rejected && !comment.isEditing" ng-click="$ctrl.startEditComment(comment); comment.menuOpen = false" ng-disabled="$ctrl.isCommentWriteBlocked(comment)" > {{ \'РедакÑиÑоваÑÑ\' | t }} </button> <button type="button" class="item-dropdown-btn item-dropdown-btn--danger" ng-if="$ctrl.canDeleteComment(comment)" ng-click="$ctrl.deleteComment(comment); comment.menuOpen = false" ng-disabled="$ctrl.isCommentWriteBlocked(comment)" > {{ \'УдалиÑÑ\' | t }} </button> </div> </div> </div> </div> <p class="collab-write-uncertain" ng-if="$ctrl.isCommentWriteUncertain(comment)" role="status"> <i class="fas fa-exclamation-triangle" aria-hidden="true"></i> {{ \'Ðе ÑдалоÑÑ Ð¿Ð¾Ð´ÑвеÑдиÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ðµ. ÐбновиÑе ÑÑÑаниÑÑ, пÑежде Ñем пÑодолжиÑÑ\' | t }} </p> <div class="comment-quoted" ng-if="::(comment.quotedText && comment.quotedText.trim())"> <i>«{{ ::comment.quotedText }}»</i> </div> <div class="comment-text" ng-if="!comment.isEditing" ng-bind-html="comment.text | inlineMarkdown | mentionLinksHtml" ></div> <div class="comment-edit-form" ng-if="comment.isEditing" ng-click="$event.stopPropagation()"> <textarea class="comment-edit-textarea" ng-model="comment.editText" mention-autocomplete rich-text-shortcuts rows="2" msd-elastic="msd-elastic" aria-label="{{ \'РедакÑиÑование комменÑаÑиÑ\' | t }}" ng-keydown="$ctrl.onCommentEditKeydown($event, comment)" ng-readonly="$ctrl.isCommentWriteBlocked(comment)" ></textarea> <div class="comment-edit-actions"> <button type="button" class="btn-edit-cancel" ng-click="$ctrl.cancelEditComment(comment)" ng-disabled="$ctrl.isCommentWritePending(comment)" > {{ \'ÐÑмениÑÑ\' | t }} </button> <button type="button" class="btn-edit-save" ng-click="$ctrl.saveEditComment(comment)" ng-disabled="!comment.editText || !comment.editText.trim() || $ctrl.isCommentWriteBlocked(comment)" > {{ \'СоÑ
ÑаниÑÑ\' | t }} </button> </div> </div> <div class="replies-count-hint" ng-if="!comment.isExpanded && comment.replies && comment.replies.length" > <i class="fas fa-reply" aria-hidden="true"></i> <span>{{ comment.replies.length | pluralize:\'оÑвеÑ\':\'оÑвеÑа\':\'оÑвеÑов\' }}</span> </div> <div id="comment-discussion-{{ ::comment.id }}" ng-if="comment.isExpanded" ng-click="$event.stopPropagation()" ng-keydown="($event.key === \'Enter\' || $event.key === \' \') && $event.stopPropagation()" > <ng-include src="\'/pages/edit/editContentItem/partials/comment-replies.html\'"></ng-include> </div> </div>
1 <button type="button" class="sidebar-show-more" ng-if="$ctrl.filteredComments.length > $ctrl.commentsDisplayLimit" ng-click="$ctrl.showMoreComments()" > {{ \'ÐоказаÑÑ ÐµÑÑ\' | t }} {{ $ctrl.filteredComments.length - $ctrl.commentsDisplayLimit }} </button> </div>'),s.put("/pages/edit/editContentItem/partials/comment-replies.html",'<div class="comment-replies" ng-if="comment.replies && comment.replies.length > 0" role="list" aria-label="{{ \'ÐÑвеÑÑ Ð½Ð° комменÑаÑий\' | t }}" > <div class="reply-item" ng-repeat="reply in comment.replies track by reply._id" role="listitem" data-reply-id="{{ ::reply._id }}" > <div class="reply-header"> <a class="reply-author" ng-href="/{{ ::reply.author.path }}" ng-if="::(reply.author && reply.author.path)" target="_blank" rel="noopener noreferrer" > <img class="author-avatar" ng-if="::reply.authorAvatar" ng-src="{{ ::reply.authorAvatar }}" alt="" ng-on-error="$event.target.style.display=\'none\'" /> <span class="author-avatar-placeholder" ng-if="::(!reply.authorAvatar)" title="{{ ::(reply.author && reply.author.name) || (\'ÐвÑоÑ\' | t) }}" >{{ ::((reply.author && reply.author.name) || (\'Ð\' | t)).charAt(0) }}</span > <div class="sidebar-author-info"> <span class="author-name" >{{ ::(reply.author && reply.author.name) || (\'ÐвÑоÑ\' | t) }}</span > <span class="sidebar-date">{{ ::reply.createdAt | date:\'dd.MM HH:mm\' }}</span> </div> </a> <span class="reply-author" ng-if="::(!reply.author || !reply.author.path)"> <img class="author-avatar" ng-if="::reply.authorAvatar" ng-src="{{ ::reply.authorAvatar }}" alt="" ng-on-error="$event.target.style.display=\'none\'" /> <span class="author-avatar-placeholder" ng-if="::(!reply.authorAvatar)" title="{{ ::(reply.author && reply.author.name) || (\'Ð\' | t) }}" >{{ ::((reply.author && reply.author.name) || (\'Ð\' | t)).charAt(0) }}</span > <div class="sidebar-author-info"> <span class="author-name" >{{ ::(reply.author && reply.author.name) || (\'ÐвÑоÑ\' | t) }}</span > <span class="sidebar-date">{{ ::reply.createdAt | date:\'dd.MM HH:mm\' }}</span> </div> </span> <div class="item-actions-menu" ng-if="$ctrl.canEditReply(reply) || $ctrl.canDeleteReply(reply)" ng-class="{\'has-open-menu\': reply.menuOpen}" ng-click="$event.stopPropagation()" > <button type="button" class="ds-btn-link btn-icon item-menu-trigger reply-menu-trigger" ng-click="$ctrl.toggleItemMenu(reply, $event)" ng-disabled="$ctrl.isCommentWriteBlocked(comment) || $ctrl.isReplyWriteBlocked(reply)" aria-label="{{ \'ÐейÑÑÐ²Ð¸Ñ Ñ Ð¾ÑвеÑом\' | t }}" > <i class="fas fa-ellipsis-v"></i> </button> <div class="item-dropdown" ng-if="reply.menuOpen" ng-click="$event.stopPropagation()"> <button type="button" class="item-dropdown-btn" ng-if="$ctrl.canEditReply(reply) && !reply.isEditing" ng-click="$ctrl.startEditReply(reply); reply.menuOpen = false" ng-disabled="$ctrl.isCommentWriteBlocked(comment) || $ctrl.isReplyWriteBlocked(reply)" > {{ \'РедакÑиÑоваÑÑ\' | t }} </button> <button type="button" class="item-dropdown-btn item-dropdown-btn--danger" ng-if="$ctrl.canDeleteReply(reply)" ng-click="$ctrl.deleteReply(comment, reply); reply.menuOpen = false" ng-disabled="$ctrl.isCommentWriteBlocked(comment) || $ctrl.isReplyWriteBlocked(reply)" > {{ \'УдалиÑÑ\' | t }} </button> </div> </div> </div> <p class="collab-write-uncertain" ng-if="$ctrl.isReplyWriteUncertain(reply)" role="status"> <i class="fas fa-exclamation-triangle" aria-hidden="true"></i> {{ \'Ðе ÑдалоÑÑ Ð¿Ð¾Ð´ÑвеÑдиÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ðµ. ÐбновиÑе ÑÑÑаниÑÑ, пÑежде Ñем пÑодолжиÑÑ\' | t }} </p> <div class="reply-text" ng-if="!reply.isEditing" ng-bind-html="reply.text | inlineMarkdown | mentionLinksHtml" ></div> <div class="reply-edit-form" ng-if="reply.isEditing"> <textarea class="reply-edit-textarea" ng-model="reply.editText" mention-autocomplete rich-text-shortcuts rows="1" msd-elastic="msd-elastic" aria-label="{{ \'РедакÑиÑование оÑвеÑа\' | t }}" ng-keydown="$ctrl.onReplyEditKeydown($event, comment, reply)" ng-readonly="$ctrl.isCommentWriteBlocked(comment) || $ctrl.isReplyWriteBlocked(reply)" ></textarea> <div class="reply-edit-actions"> <button type="button" class="btn-edit-cancel" ng-click="$ctrl.cancelEditReply(reply)" ng-disabled="$ctrl.isReplyWritePending(reply)" > {{ \'ÐÑмениÑÑ\' | t }} </button> <button type="button" class="btn-edit-save" ng-click="$ctrl.saveEditReply(comment, reply)" ng-disabled="!reply.editText || !reply.editText.trim() || $ctrl.isCommentWriteBlocked(comment) || $ctrl.isReplyWriteBlocked(reply)" > {{ \'СоÑ
ÑаниÑÑ\' | t }} </button> </div> </div> </div> </div> <div class="comment-add-reply" ng-if="!comment.resolved"> <div class="reply-input-wrapper">
1 <textarea ng-model="comment.newReplyText" placeholder="{{ \'ÐÑвеÑиÑÑ...\' | t }}" aria-label="{{ \'ТекÑÑ Ð¾ÑвеÑа на комменÑаÑий\' | t }}" mention-autocomplete rich-text-shortcuts rows="1" msd-elastic="msd-elastic" ng-keydown="$ctrl.onReplyKeydown($event, comment)" ng-readonly="$ctrl.isCommentWriteBlocked(comment)" ></textarea> <button type="button" class="reply-send-btn btn-icon" ng-click="$ctrl.addReply(comment)" ng-disabled="!comment.newReplyText || !comment.newReplyText.trim() || $ctrl.isCommentWriteBlocked(comment)" aria-label="{{ \'ÐÑпÑавиÑÑ Ð¾ÑвеÑ\' | t }}" > <i class="fas fa-paper-plane" aria-hidden="true"></i> <span class="custom-tooltip">{{ \'ÐÑпÑавиÑÑ\' | t }}</span> </button> </div> </div>'),s.put("/pages/edit/editContentItem/partials/cover-actions-mobile.html",'<div class="cover-actions-mobile"> <button type="button" class="cover-actions-toggle" aria-label="{{ \'ÐейÑÑÐ²Ð¸Ñ Ñ Ð¾Ð±Ð»Ð¾Ð¶ÐºÐ¾Ð¹\' | t }}" aria-haspopup="true" ng-attr-aria-expanded="{{$ctrl.coverMenuOpen}}" ng-click="$ctrl.toggleCoverMenu($event)" ng-disabled="$ctrl.cropUploading || $ctrl.imageUploading[\'root\']" > <i class="fas fa-ellipsis-v" aria-hidden="true"></i> </button> <div class="cover-actions-dropdown" role="menu" ng-show="$ctrl.coverMenuOpen" ng-click="$event.stopPropagation()" > <button type="button" role="menuitem" class="cover-action-item" ng-click="$ctrl.cropCoverImage(); $ctrl.coverMenuOpen = false" ng-disabled="$ctrl.cropUploading" aria-label="{{ \'ÐадÑиÑоваÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" > <i class="fas fa-crop-alt" aria-hidden="true"></i> <span>{{ \'ÐадÑиÑоваÑÑ\' | t }}</span> </button> <button type="button" role="menuitem" class="cover-action-item" ng-click="$ctrl.coverMenuOpen = false" ngf-select="$ctrl.uploadImage($file)" ngf-accept="\'image/*\'" ng-disabled="$ctrl.cropUploading || $ctrl.imageUploading[\'root\']" aria-label="{{ \'ÐамениÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" > <i class="fas fa-image" aria-hidden="true"></i> <span>{{ \'ÐамениÑÑ\' | t }}</span> </button> <button type="button" role="menuitem" class="cover-action-item cover-action-item--delete" ng-click="$ctrl.deleteCoverImage(); $ctrl.coverMenuOpen = false" ng-disabled="$ctrl.cropUploading" aria-label="{{ \'УдалиÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" > <i class="fas fa-times" aria-hidden="true"></i> <span>{{ \'УдалиÑÑ\' | t }}</span> </button> </div> </div>'),s.put("/pages/edit/editContentItem/partials/expo-preview.html",'<div class="expo-preview-wrapper tiptap-preview-mode" ng-if="$ctrl.isPreviewMode && $ctrl.previewPost" ng-init="editCtrl = $ctrl; post = $ctrl.previewPost" > <div class="button-container"> <button type="button" class="preview-close-button" ng-click="editCtrl.togglePreviewMode()"> <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M17.9975 4.89363L13.1038 0L0 13.1064V18H4.89363L17.9975 4.89363ZM13.105 2.55674L15.4421 4.89383L14.4612 5.87591L12.1241 3.53882L13.105 2.55674ZM10.8453 4.81648L13.1824 7.15357L5.42174 14.9137L3.08485 12.5756L10.8453 4.81648ZM1.80725 16.1915V13.8544L4.14434 16.1915H1.80725Z" fill="currentColor" /> </svg> {{ \'ÐÑодолжиÑÑ ÑедакÑиÑоваÑÑ\' | t }} </button> </div> <div ng-controller="ExpoPreviewCtrl as $ctrl"> <ng-include src="\'/pages/expo/expoMainPart.html\'"></ng-include> </div> <div class="button-container bottom-button" ng-if="editCtrl.showBottomEditButton"> <button type="button" class="preview-close-button bottom" ng-click="editCtrl.togglePreviewMode()" > <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M17.9975 4.89363L13.1038 0L0 13.1064V18H4.89363L17.9975 4.89363ZM13.105 2.55674L15.4421 4.89383L14.4612 5.87591L12.1241 3.53882L13.105 2.55674ZM10.8453 4.81648L13.1824 7.15357L5.42174 14.9137L3.08485 12.5756L10.8453 4.81648ZM1.80725 16.1915V13.8544L4.14434 16.1915H1.80725Z" fill="currentColor" /> </svg> {{ \'ÐÑодолжиÑÑ ÑедакÑиÑоваÑÑ\' | t }} </button> </div> </div>'),s.put("/pages/edit/editContentItem/partials/margin-view.html",'<div class="margin-items-column" ng-show="$ctrl.marginViewMode" aria-label="{{ \'РемаÑки и пÑавки на полÑÑ
\' | t }}
1" aria-live="polite" aria-atomic="false" data-collab-margin-region tabindex="-1" > <div class="margin-item-card" ng-repeat="comment in $ctrl.visibleMarginComments track by comment.id" ng-class="{ resolved: comment.resolved, remark: comment.isRemark, orphaned: comment.orphaned,\'margin-expanded\': comment.marginExpanded }" ng-attr-title="{{ comment.orphaned ? (comment.isRemark ? (\'РемаÑка болÑÑе не пÑивÑзана к ÑекÑÑÑ\'|t) : (\'ÐомменÑаÑий болÑÑе не пÑивÑзан к ÑекÑÑÑ\'|t)) : undefined }}" data-margin-comment-id="{{ ::comment.id }}" ng-click="$ctrl.toggleMarginCard(comment, $event)" role="group" ng-attr-aria-label="{{ ::(comment.isRemark ? (\'РемаÑка оÑ\'|t) : (\'ÐомменÑаÑий оÑ\'|t)) + \' \' + (comment.authorName || (\'ÐвÑоÑ\'|t)) }}" > <div class="margin-card-header"> <div class="margin-card-header-main"> <img class="margin-avatar" ng-if="::comment.authorAvatar" ng-src="{{ ::comment.authorAvatar }}" alt="" ng-on-error="$event.target.style.display=\'none\'" /> <span class="margin-avatar-placeholder" ng-if="::(!comment.authorAvatar && comment.authorId && comment.authorId !== \'anonymous\')" >{{ ::(comment.authorName || (\'Ð\' | t)).charAt(0) }}</span > <span class="margin-avatar-placeholder margin-avatar-placeholder--anon" ng-if="::(!comment.authorAvatar && (!comment.authorId || comment.authorId === \'anonymous\'))" title="{{ \'Ðнонимно\' | t }}" ><i class="fas fa-user-secret" aria-hidden="true"></i ></span> <div class="margin-author-info"> <a class="margin-author" ng-if="::comment.authorSlug" ng-href="/{{ ::comment.authorSlug }}" target="_blank" rel="noopener noreferrer" ng-click="$event.stopPropagation()" >{{ ::comment.authorName || (\'ÐвÑоÑ\' | t) }}</a > <span class="margin-author" ng-if="::(!comment.authorSlug)" >{{ ::(!comment.authorId || comment.authorId === \'anonymous\') ? (\'Ðнонимно\' | t) : (comment.authorName || (\'ÐвÑоÑ\' | t)) }}</span > <span class="margin-date">{{ ::comment.createdAt | date:\'dd.MM HH:mm\' }}</span> </div> </div> <div class="margin-card-header-actions" ng-class="{\'has-open-menu\': comment.menuOpen}" ng-click="$event.stopPropagation()" > <button type="button" class="ds-btn-link btn-icon card-disclosure" ng-click="$event.stopPropagation(); $ctrl.toggleMarginDisclosure(comment)" ng-attr-aria-expanded="{{ comment.marginExpanded ? \'true\' : \'false\' }}" ng-attr-aria-controls="{{ comment.marginExpanded ? (\'margin-comment-discussion-\' + comment.id) : undefined }}" aria-label="{{ (comment.marginExpanded ? \'СвеÑнÑÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑий\' : \'РазвеÑнÑÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑий\') | t }}" > <i class="fas fa-chevron-down" aria-hidden="true"></i> </button> <button type="button" class="ds-btn-link btn-icon ds-btn-success" ng-if="!comment.resolved && !comment.rejected && $ctrl.canModerate()" ng-click="$ctrl.resolve
1Comment(comment)" ng-disabled="$ctrl.isCommentWriteBlocked(comment)" aria-label="{{ \'ÐÑинÑÑÑ\' | t }}" > <i class="fas fa-check"></i><span class="custom-tooltip">{{ \'ÐÑинÑÑÑ\' | t }}</span> </button> <button type="button" class="ds-btn-link btn-icon ds-btn-warning" ng-if="!comment.resolved && !comment.rejected && $ctrl.canModerate()" ng-click="$ctrl.rejectComment(comment)" ng-disabled="$ctrl.isCommentWriteBlocked(comment)" data-collab-reject-id="{{ ::comment.id }}" data-collab-reject-surface="margin" aria-label="{{ \'ÐÑклониÑÑ\' | t }}" > <i class="fas fa-times"></i><span class="custom-tooltip">{{ \'ÐÑклониÑÑ\' | t }}</span> </button> <div class="item-actions-menu" ng-if="$ctrl.canEditComment(comment) || $ctrl.canDeleteComment(comment)" > <button type="button" class="ds-btn-link btn-icon item-menu-trigger" ng-click="$ctrl.toggleItemMenu(comment, $event)" ng-disabled="$ctrl.isCommentWriteBlocked(comment)" aria-label="{{ \'ÐейÑÑÐ²Ð¸Ñ Ñ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑием\' | t }}" > <i class="fas fa-ellipsis-v"></i> </button> <div class="item-dropdown" ng-if="comment.menuOpen" ng-click="$event.stopPropagation()"> <button type="button" class="item-dropdown-btn" ng-if="$ctrl.canEditComment(comment) && !comment.resolved && !comment.rejected && !comment.isEditing" ng-click="$ctrl.startEditComment(comment); comment.marginExpanded = true; comment.menuOpen = false" ng-disabled="$ctrl.isCommentWriteBlocked(comment)" > {{ \'РедакÑиÑоваÑÑ\' | t }} </button> <button type="button" class="item-dropdown-btn item-dropdown-btn--danger" ng-if="$ctrl.canDeleteComment(comment)" ng-click="$ctrl.deleteComment(comment); comment.menuOpen = false" ng-disabled="$ctrl.isCommentWriteBlocked(comment)" > {{ \'УдалиÑÑ\' | t }} </button> </div> </div> </div> </div> <div class="margin-card-text" ng-if="!comment.isEditing">{{ comment.text | mentionNames }}</div> <div class="margin-edit-form" ng-if="comment.isEditing" ng-click="$event.stopPropagation()"> <textarea class="margin-edit-textarea" ng-model="comment.editText" mention-autocomplete rich-text-shortcuts rows="2" msd-elastic="msd-elastic" aria-label="{{ \'РедакÑиÑование комменÑаÑиÑ\' | t }}" ng-keydown="$ctrl.onCommentEditKeydown($event, comment)" ng-readonly="$ctrl.isCommentWriteBlocked(comment)" ></textarea> <div class="margin-edit-actions"> <button type="button" class="btn-edit-cancel" ng-click="$ctrl.cancelEditComment(comment)" ng-disabled="$ctrl.isCommentWritePending(comment)" > {{ \'ÐÑмениÑÑ\' | t }} </button> <button type="button" class="btn-edit-save" ng-click="$ctrl.saveEditComment(comment)" ng-disabled="!comment.editText || !comment.editText.trim() || $ctrl.isCommentWriteBlocked(comment)" > {{ \'СоÑ
ÑаниÑÑ\' | t }} </button> </div> </div> <p class="collab-write-uncertain" ng-if="$ctrl.isCommentWriteUncertain(comment)" role="status"> <i class="fas fa-exclamation-triangle" aria-hidden="true"></i> {{ $ctrl.suggestionDiscussionNotice(suggestion) }} </p> <div class="margin-card-replies-count" ng-if="comment.replies && comment.replies.length && !comment.marginExpanded" > <i class="fas fa-reply" aria-hidden="true"></i> <span>{{ comment.replies.length | pluralize:\'оÑвеÑ\':\'оÑвеÑа\':\'оÑвеÑов\' }}</span> </div> <div id="margin-comment-discussion-{{ ::comment.id }}" class="margin-disclosure-content" ng-if="comment.marginExpanded" > <div class="margin-card-replies" ng-if="comment.replies && comment.replies.length" ng-click="$event.stopPropagation()" > <div class="margin-reply" ng-repeat="reply in comment.replies track by reply._id" data-reply-id="{{ ::reply._id }}" > <div class="margin-reply-header"> <span class="margin-reply-author" >{{ ::(reply.author && reply.author.name) || \'\' }}</span > <div class="item-actions-menu" ng-if="$ctrl.canEditReply(reply) || $ctrl.canDeleteReply(reply)" ng-class="{\'has-open-menu\': reply.menuOpen}" ng-click="$event.stopPropagation()" > <button type="button" class="ds-btn-link btn-icon item-menu-trigger margin-reply-menu-trigger" ng-click="$ctrl.toggleItemMenu(reply, $event)" ng-disabled="$ctrl.isCommentWriteBlocked(comment) || $ctrl.isReplyWriteBlocked(reply)" aria-label="{{ \'ÐейÑÑÐ²Ð¸Ñ Ñ Ð¾ÑвеÑом\' | t }}" > <i class="fas fa-ellipsis-v"></i> </button> <div class="item-dropdown" ng-if="reply.menuOpen" ng-click="$event.stopPropagation()"> <button type="button" class="item-dropdown-btn" ng-if="$ctrl.canEditReply(reply) && !reply.isEditing" ng-click="$ctrl.startEditReply(reply); reply.menuOpen = false" ng-disabled="$ctrl.isCommentWriteBlocked(comment) || $ctrl.isReplyWriteBlocked(reply)" > {{ \'РедакÑиÑоваÑÑ\' | t }} </button> <button type="button" class="item-dropdown-btn item-dropdown-btn--danger" ng-if="$ctrl.canDeleteReply(reply)" ng-click="$ctrl.deleteReply(comment, reply); reply.menuOpen = false" ng-disabled="$ctrl.isCommentWriteBlocked(comment) || $ctrl.isReplyWriteBlocked(reply)" > {{ \'УдалиÑÑ\' | t }} </button> </div> </div> </div> <span class="margin-reply-text" ng-if="!reply.isEditing" ng-bind-html="reply.text | inlineMarkdown | mentionLinksHtml" ></span> <div class="margin-reply-edit-form" ng-if="reply.isEditing"> <textarea class="margin-reply-edit-textarea" ng-model="reply.editText" mention-autocomplete rich-text-shortcuts rows="1" msd-elastic="msd-elastic" aria-label="{{ \'РедакÑиÑование оÑвеÑа\' | t }}" ng-keydown="$ctrl.onReplyEditKeydown($event, comment, reply)" ng-readonly="$ctrl.isCommentWriteBlocked(comment) || $ctrl.isReplyWriteBlocked(reply)" ></textarea> <div class="margin-reply-edit-actions"> <button type="button" class="btn-edit-cancel" ng-click="$ctrl.cancelEditReply(reply)" ng-disabled="$ctrl.isReplyWritePending(reply)" > {{ \'ÐÑмениÑÑ\' | t }} </button> <button type="button" class="btn-edit-save" ng-click="$ctrl.saveEditReply(comment, reply)" ng-disabled="!reply.editText || !reply.editText.trim() || $ctrl.isCommentWriteBlocked(comment) || $ctrl.isReplyWriteBlocked(reply)" > {{ \'СоÑ
ÑаниÑÑ\' | t }} </button> </div> </div> <p class="collab-write-uncertain" ng-if="$ctrl.isReplyWriteUncertain(reply)" role="status" > <i class="fas fa-exclamation-triangle" aria-hidden="true"></i> {{ \'Ðе ÑдалоÑÑ Ð¿Ð¾Ð´ÑвеÑдиÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ðµ. ÐбновиÑе ÑÑÑаниÑÑ, пÑежде Ñем пÑодолжиÑÑ\' | t }} </p> </div> </div> <div class="margin-reply-form" ng-if="$ctrl.userId" ng-click="$event.stopPropagation()" ng-keydown="($event.key === \'Enter\' || $event.key === \' \') && $event.stopPropagation()" >
1 <textarea class="margin-reply-input" ng-model="comment.newReplyText" placeholder="{{ \'ÐÑвеÑиÑÑ...\' | t }}" aria-label="{{ \'ТекÑÑ Ð¾ÑвеÑа на комменÑаÑий\' | t }}" mention-autocomplete rich-text-shortcuts rows="1" msd-elastic="msd-elastic" ng-keydown="$ctrl.onReplyKeydown($event, comment)" ng-readonly="$ctrl.isCommentWriteBlocked(comment)" ></textarea> <button type="button" class="ds-btn-link ds-btn-success margin-reply-submit" ng-mousedown="$event.preventDefault()" ng-click="$event.stopPropagation(); $ctrl.addReply(comment)" ng-disabled="!comment.newReplyText || !comment.newReplyText.trim() || $ctrl.isCommentWriteBlocked(comment)" > {{ \'ÐÑвеÑиÑÑ\' | t }} </button> </div> </div> </div> <div class="margin-item-card margin-item-card--suggestion" ng-repeat="suggestion in $ctrl.visibleMarginSuggestions track by suggestion.suggestionId" ng-class="[suggestion.type, {\'margin-expanded\': suggestion.marginExpanded }]" data-margin-suggestion-id="{{ ::suggestion.suggestionId }}" ng-click="$ctrl.toggleMarginCard(suggestion, $event)" role="group" ng-attr-aria-label="{{ ::(\'ÐÑавка оÑ\'|t) + \' \' + (suggestion.authorName || (\'ÐвÑоÑ\'|t)) }}" > <div class="margin-card-header"> <div class="margin-card-header-main"> <img class="margin-avatar" ng-if="::suggestion.authorAvatar" ng-src="{{ ::suggestion.authorAvatar }}" alt="" ng-on-error="$event.target.style.display=\'none\'" /> <span class="margin-avatar-placeholder" ng-if="::(!suggestion.authorAvatar && suggestion.authorId && suggestion.authorId !== \'anonymous\')" >{{ ::(suggestion.authorName || (\'Ð\' | t)).charAt(0) }}</span > <span class="margin-avatar-placeholder margin-avatar-placeholder--anon" ng-if="::(!suggestion.authorAvatar && (!suggestion.authorId || suggestion.authorId === \'anonymous\'))" title="{{ \'Ðнонимно\' | t }}" ><i class="fas fa-user-secret" aria-hidden="true"></i ></span> <div class="margin-author-info"> <a class="margin-author" ng-if="::suggestion.authorSlug" ng-href="/{{ ::suggestion.authorSlug }}" target="_blank" rel="noopener noreferrer" ng-click="$event.stopPropagation()" >{{ ::suggestion.authorName || (\'ÐвÑоÑ\' | t) }}</a > <span class="margin-author" ng-if="::(!suggestion.authorSlug)" >{{ ::suggestion.authorName || (\'ÐвÑоÑ\' | t) }}</span > <span class="margin-date"> {{ ::suggestion.createdAt | date:\'dd.MM HH:mm\' }} <span class="margin-type-badge" ng-if="::(suggestion.type === \'add\' || suggestion.type === \'node-add\')" >+</span > <span class="margin-type-badge margin-type-badge--delete" ng-if="::(suggestion.type === \'delete\' || suggestion.type === \'node-delete\')" >â</span > <span class="margin-type-badge margin-type-badge--replace" ng-if="::suggestion.type === \'replace\'" ><i class="fas fa-exchange-alt"></i ></span> <span class="margin-type-badge margin-type-badge--format" ng-if="::suggestion.type === \'format\'" ><i class="fas fa-paint-brush"></i ></span> <span class="margin-type-badge margin-type-badge--update" ng-if="::suggestion.type === \'node-update\'" ><i class="fas fa-pencil-alt"></i ></span> </span> </div> </div> <div class="margin-card-header-actions" ng-click="$event.stopPropagation()"> <button type="button" class="ds-btn-link btn-icon card-disclosure" ng-click="$event.stopPropagation(); $ctrl.toggleMarginDisclosure(suggestion)" ng-attr-aria-expanded="{{ suggestion.marginExpanded ? \'true\' : \'false\' }}" ng-attr-aria-controls="{{ suggestion.marginExpanded ? (\'margin-suggestion-discussion-\' + suggestion.suggestionId) : undefined }}" aria-label="{{ (suggestion.marginExpanded ? \'СвеÑнÑÑÑ Ð¿ÑавкÑ\' : \'РазвеÑнÑÑÑ Ð¿ÑавкÑ\') | t }}" > <i class="fas fa-chevron-down" aria-hidden="true"></i> </button> <button type="button" class="ds-btn-link btn-icon ds-btn-success" ng-if="$ctrl.canModerate()" ng-click="$ctrl.acceptSuggestion(suggestion)" ng-disabled="$ctrl.isSuggestionActionBlocked(suggestion)" aria-label="{{ \'ÐÑинÑÑÑ Ð¿ÑавкÑ\' | t }}" > <i class="fas fa-check"></i><span class="custom-tooltip">{{ \'ÐÑинÑÑÑ\' | t }}</span> </button> <button type="button" class="ds-btn-link btn-icon ds-btn-danger" ng-if="$ctrl.canModerate()" ng-click="$ctrl.rejectSuggestion(suggestion)" ng-disabled="$ctrl.isSuggestionActionBlocked(suggestion)" aria-label="{{ \'ÐÑклониÑÑ Ð¿ÑавкÑ\' | t }}" > <i class="fas fa-times"></i><span class="custom-tooltip">{{ \'ÐÑклониÑÑ\' | t }}</span> </button> </div> </div> <p class="collab-write-uncertain" ng-if="$ctrl.suggestionDiscussionNotice(suggestion) && !suggestion.marginExpanded" role="status" > <i class="fas fa-exclamation-triangle" aria-hidden="true"></i> {{ \'Ðе ÑдалоÑÑ Ð¿Ð¾Ð´ÑвеÑдиÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ðµ. ÐбновиÑе ÑÑÑаниÑÑ, пÑежде Ñем пÑодолжиÑÑ\' | t }} </p> <div class="margin-card-text"> <strong class="suggestion-action-label" ng-if="::(suggestion.type === \'add\' || suggestion.type === \'node-add\')" >{{ \'ÐобавиÑÑ:\' | t }}</strong > <strong class="suggestion-action-label" ng-if="::(suggestion.type === \'delete\' || suggestion.type === \'node-delete\')" >{{ \'УдалиÑÑ:\' | t }}</strong > <strong class="suggestion-action-label" ng-if="::suggestion.type === \'replace\'" >{{ \'ÐамениÑÑ:\' | t }}</strong > <strong class="suggestion-action-label" ng-if="::suggestion.type === \'format\'" >{{ \'ФоÑмаÑ:\' | t }}</strong > <strong class="suggestion-action-label" ng-if="::suggestion.type === \'node-update\'" >{{ \'ÐзмениÑÑ:\' | t }}</strong > <span ng-if="::suggestion.type === \'add\'" class="text-add">{{ suggestion.text }}</span> <span ng-if="::suggestion.type === \'delete\'" class="text-delete">{{ suggestion.text }}</span> <div ng-if="::suggestion.type === \'replace\'" class="suggestion-replace-block"> <span class="text-delete" >{{ suggestion.deleteText | limitTo:100 }}<span ng-if="suggestion.deleteText.length > 100" >â¦</span ></span > <span class="text-replace-arrow">â</span> <span class="text-add" >{{ suggestion.addText | limitTo:100 }}<span ng-if="suggestion.addText.length > 100" >â¦</span ></span > </div> <span ng-if="::suggestion.type === \'format\'" class="text-format" >{{ ::suggestion.formatDescription }}</span > <span ng-if="::(suggestion.type === \'node-add\' || suggestion.type === \'node-delete\' || suggestion.type === \'node-update\')" class="text-format" >{{ ::suggestion.nodeDescription }}</span > <div class="suggestion-update-changes" ng-if="suggestion.updateChanges.length"> <div class="suggestion-update-change" ng-repeat="change in suggestion.updateChanges track by change.key" > <span class="suggestion-update-label">{{ change.label }}</span> <span class="text-delete" ng-if="change.before" >{{ change.before | limitTo:100 }}<span ng-if="change.before.length > 100" >â¦</span ></span > <span class="text-delete suggestion-update-empty" ng-if="!change.before" >{{ \'пÑÑÑо\' | t }}</span > <span class="text-replace-arrow">â</span> <span class="text-add" ng-if="change.after" >{{ change.after | limitTo:100 }}<span ng-if="change.after.length > 100">â¦</span></span > <span class="text-add suggestion-update-empty" ng-if="!change.after" >{{ \'пÑÑÑо\' | t }}</span > </div> </div> </div> <div class="margin-card-replies-count" ng-if="$ctrl.suggestionThreads[suggestion.suggestionId] && $ctrl.suggestionThreads[suggestion.suggestionId].length && !suggestion.marginExpanded" > <i class="fas fa-reply" aria-hidden="true"></i> <span >{{ $ctrl.suggestionThreads[suggestion.suggestionId].length | pluralize:\'оÑвеÑ\':\'оÑвеÑа\':\'оÑвеÑов\' }}</span > </div> <div id="margin-suggestion-discussion-{{ ::suggestion.suggestionId }}" class="margin-disclosure-content" ng-if="suggestion.marginExpanded" > <p class="collab-write-uncertain" ng-if="$ctrl.suggestionDiscussionNotice(suggestion)" role="status" > <i class="fas fa-exclamation-triangle" aria-hidden="true"></i> {{ $ctrl.suggestionDiscussionNotice(suggestion) }} </p> <div class="margin-card-replies" ng-if="$ctrl.suggestionThreads[suggestion.suggestionId] && $ctrl.suggestionThreads[suggestion.suggestionId].length" ng-click="$event.stopPropagation()" > <div class="margin-reply" ng-repeat="reply in $ctrl.suggestionThreads[suggestion.suggestionId] track by reply._id" data-reply-id="{{ ::reply._id }}" > <div class="margin-reply-header"> <span class="margin-reply-author" >{{ ::(reply.author && reply.author.name) || \'\' }}</span > <div class="item-actions-menu" ng-if="$ctrl.canEditReply(reply) || $ctrl.canDeleteReply(reply)" ng-class="{\'has-open-menu\': reply.menuOpen}" ng-click="$event.stopPropagation()" > <button type="button" class="ds-btn-link btn-icon item-menu-trigger margin-reply-menu-trigger" ng-click="$ctrl.toggleItemMenu(reply, $event)" ng-disabled="$ctrl.isSuggestionReplyWriteBlocked(reply, suggestion)" aria-label="{{ \'ÐейÑÑÐ²Ð¸Ñ Ñ Ð¾ÑвеÑом\' | t }}" > <i class="fas fa-ellipsis-v"></i> </button> <div class="item-dropdown" ng-if="reply.menuOpen" ng-click="$event.stopPropagation()"> <button type="button" class="item-dropdown-btn" ng-if="$ctrl.canEditReply(reply) && !reply.isEditing" ng-click="$ctrl.startEditReply(reply, suggestion); reply.menuOpen = false" ng-disabled="$ctrl.isSuggestionReplyWriteBlocked(reply, suggestion)" > {{ \'РедакÑиÑоваÑÑ\' | t }} </button> <button type="button" class="item-dropdown-btn item-dropdown-btn--danger" ng-if="$ctrl.canDeleteReply(reply)" ng-click="$ctrl.deleteSuggestionReply(suggestion, reply
1); reply.menuOpen = false" ng-disabled="$ctrl.isSuggestionReplyWriteBlocked(reply, suggestion)" > {{ \'УдалиÑÑ\' | t }} </button> </div> </div> </div> <span class="margin-reply-text" ng-if="!reply.isEditing" ng-bind-html="reply.text | inlineMarkdown | mentionLinksHtml" ></span> <div class="margin-reply-edit-form" ng-if="reply.isEditing"> <textarea class="margin-reply-edit-textarea" ng-model="reply.editText" mention-autocomplete rich-text-shortcuts rows="1" msd-elastic="msd-elastic" aria-label="{{ \'РедакÑиÑование оÑвеÑа\' | t }}" ng-keydown="$ctrl.onSuggestionReplyEditKeydown($event, suggestion, reply)" ng-readonly="$ctrl.isSuggestionReplyWriteBlocked(reply, suggestion)" ></textarea> <div class="margin-reply-edit-actions"> <button type="button" class="btn-edit-cancel" ng-click="$ctrl.cancelEditReply(reply)" ng-disabled="$ctrl.isSuggestionReplyWritePending(reply)" > {{ \'ÐÑмениÑÑ\' | t }} </button> <button type="button" class="btn-edit-save" ng-click="$ctrl.saveEditSuggestionReply(suggestion, reply)" ng-disabled="!reply.editText || !reply.editText.trim() || $ctrl.isSuggestionReplyWriteBlocked(reply, suggestion)" > {{ \'СоÑ
ÑаниÑÑ\' | t }} </button> </div> </div> <p class="collab-write-uncertain" ng-if="$ctrl.isSuggestionReplyWriteUncertain(reply)" role="status" > <i class="fas fa-exclamation-triangle" aria-hidden="true"></i> {{ \'Ðе ÑдалоÑÑ Ð¿Ð¾Ð´ÑвеÑдиÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ðµ. ÐбновиÑе ÑÑÑаниÑÑ, пÑежде Ñем пÑодолжиÑÑ\' | t }} </p> </div> </div> <div class="margin-reply-form" ng-if="$ctrl.userId" ng-click="$event.stopPropagation()" ng-keydown="($event.key === \'Enter\' || $event.key === \' \') && $event.stopPropagation()" > <textarea class="margin-reply-input" ng-model="suggestion.newReplyText" placeholder="{{ \'ÐÑвеÑиÑÑ...\' | t }}" aria-label="{{ \'ТекÑÑ Ð¾ÑвеÑа на обÑÑждение пÑавки\' | t }}" mention-autocomplete rich-text-shortcuts rows="1" msd-elastic="msd-elastic" ng-keydown="$ctrl.onSuggestionReplyKeydown($event, suggestion)" ng-readonly="$ctrl.isSuggestionDiscussionBlocked(suggestion)" ></textarea> <button type="button" class="ds-btn-link ds-btn-success margin-reply-submit" ng-mousedown="$event.preventDefault()" ng-click="$event.stopPropagation(); $ctrl.addSuggestionReply(suggestion)" ng-disabled="!suggestion.newReplyText || !suggestion.newReplyText.trim() || $ctrl.isSuggestionDiscussionBlocked(suggestion)" > {{ \'ÐÑвеÑиÑÑ\' | t }} </button> </div> </div> </div> </div>'),s.put("/pages/edit/editContentItem/partials/sidebar-side-toggle.html",'<button type="button" class="sidebar-side-toggle" ng-if="contentItem.slug" ng-class="{ \'is-hidden\': $ctrl.sidebarVisible || $ctrl.marginViewMode }" ng-disabled="$ctrl.collabSyncPending" ng-click="$ctrl.toggleSidebar()" ng-attr-aria-pressed="{{ !!$ctrl.sidebarVisible }}" aria-label="{{ \'ÐÐ°Ð½ÐµÐ»Ñ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑиев и пÑавок\' | t }}" > <svg width="21" height="17" viewBox="0 0 21 17" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M3.88021 0C3.03125 0 2.32031 0.151042 1.74219 0.450522C1.16667 0.75 0.731771 1.1875 0.440104 1.76302C0.145833 2.34115 0 3.04688 0 3.88021V6.52604C0 7.35938 0.145833 8.06511 0.440104 8.64063C0.734375 9.21615 1.16667 9.65625 1.74219 9.95573C2.32031 10.2552 2.95573 10.4063 3.80469 10.4063V12.4635C3.80469 12.8229 3.89323 13.1068 4.06771 13.3177C4.24479 13.5286 4.49479 13.6328 4.81771 13.6328C5.04687 13.6328 5.2526 13.5729 5.4401 13.4531C5.625 13.3307 5.85937 13.1432 6.14323 12.888L8.91406 10.4063H11.1536C12 10.4063 12.7135 10.2552 13.2891 9.95573C13.8646 9.65625 14.2995 9.21615 14.5911 8.64063C14.8854 8.06511 15.0312 7.35938 15.0312 6.52604V3.88021C15.0312 3.04427 14.8854 2.34115 14.5911 1.76302C14.2995 1.1875 13.8646 0.75 13.2891 0.450522C12.7135 0.151042 12 0 11.1536 0H3.88021ZM3.88021 1.5H11.1536C11.987 1.5 12.5938 1.69792 12.974 2.09635C13.3542 2.49219 13.5417 3.08594 13.5417 3.88021V6.52604C13.5417 7.31771 13.3542 7.91667 12.974 8.31511C12.5938 8.71615 11.987 8.91667 11.1536 8.91667H8.83333C8.58594 8.91667 8.38281 8.94011 8.22656 8.99219C8.07292 9.04427 7.91146 9.16146 7.7474 9.33854L5.20052 11.9349V9.60938C5.20052 9.35417 5.14844 9.17448 5.04167 9.07031C4.9349 8.96615 4.75521 8.91667 4.50781 8.91667H3.88021C3.04427 8.91667 2.4375 8.71615 2.0599 8.31511C1.67969 7.91667 1.48958 7.31771 1.48958 6.52604V3.88021C1.48958 3.08594 1.67969 2.49219 2.0599 2.09635C2.4375 1.69792 3.04427 1.5 3.88021 1.5ZM16.1016 3C16.1406 3.28125 16.1589 3.57292 16.1589 3.88021V4.5H16.2708C17.1068 4.5 17.7161 4.69792 18.0938 5.09635C18.4714 5.48958 18.6641 6.08594 18.6641 6.8802
11V9.59375C18.6641 10.388 18.4714 10.9844 18.0938 11.3802C17.7161 11.7839 17.1068 11.9818 16.2708 11.9818H15.6458C15.3984 11.9818 15.2188 12.0339 15.112 12.138C15.0052 12.2396 14.9505 12.4193 14.9505 12.6745V15.0052L12.4062 12.4089C12.2396 12.2292 12.0781 12.112 11.9245 12.0599C11.7708 12.0078 11.5677 11.9818 11.3203 11.9818C8.80729 11.9818 8.96094 11.9844 8.92188 11.9766L7.47656 13.2682C7.78646 13.362 8.27344 13.474 9 13.474H11.2344L14.0104 15.9557C14.2917 16.2109 14.5286 16.3984 14.7109 16.5182C14.8984 16.638 15.1042 16.6979 15.3333 16.6979C15.6562 16.6979 15.9089 16.5938 16.0833 16.3828C16.2604 16.1745 16.3464 15.888 16.3464 15.5339V13.474C17.1979 13.474 17.8307 13.3255 18.4089 13.0234C18.987 12.724 19.4167 12.2839 19.7135 11.7083C20.0052 11.1328 20.1536 10.4297 20.1536 9.59375V6.88021C20.1536 6.04427 20.0052 5.34115 19.7135 4.76302C19.4167 4.1875 18.987 3.75 18.4089 3.45052C17.8307 3.15104 17.1224 3 16.2708 3H16.1016ZM3.89583 3.7526C3.60156 3.7526 3.3776 3.99219 3.3776 4.27865C3.3776 4.57031 3.60156 4.80729 3.89583 4.80729H11.3281C11.6224 4.80729 11.8464 4.56771 11.8464 4.27865C11.8464 3.98958 11.6224 3.7526 11.3281 3.7526H3.89583ZM3.89583 6.01563C3.53385 6.01563 3.3776 6.33073 3.3776 6.55208C3.3776 6.84115 3.60156 7.07031 3.89583 7.07031H8.81771C9.10677 7.07031 9.33594 6.84635 9.33594 6.55208C9.33594 6.33594 9.17969 6.01563 8.81771 6.01563H3.89583Z" fill="currentColor" /> </svg> <span class="sidebar-side-toggle__counter" ng-if="$ctrl.pendingChangesCount > 0" >{{ $ctrl.pendingChangesCount }}</span > <span class="custom-tooltip">{{ \'ÐÐ°Ð½ÐµÐ»Ñ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑиев и пÑавок\' | t }}</span> </button>'),s.put("/pages/edit/editContentItem/partials/suggestion-replies.html",'<p class="collab-write-uncertain" ng-if="$ctrl.suggestionDiscussionNotice(suggestion)" role="status" > <i class="fas fa-exclamation-triangle" aria-hidden="true"></i> {{ $ctrl.suggestionDiscussionNotice(suggestion) }} </p> <div class="comment-replies" ng-if="$ctrl.suggestionThreads[suggestion.suggestionId] && $ctrl.suggestionThreads[suggestion.suggestionId].length > 0" role="list" aria-label="{{ \'ÐÑвеÑÑ Ð½Ð° обÑÑждение пÑавки\' | t }}" > <div class="reply-item" ng-repeat="reply in $ctrl.suggestionThreads[suggestion.suggestionId] track by reply._id" role="listitem" data-reply-id="{{ ::reply._id }}" > <div class="reply-header"> <a class="reply-author" ng-href="/{{ ::reply.author.path }}" ng-if="::(reply.author && reply.author.path)" target="_blank" rel="noopener noreferrer" > <img class="author-avatar" ng-if="::reply.authorAvatar" ng-src="{{ ::reply.authorAvatar }}" alt="" ng-on-error="$event.target.style.display=\'none\'" /> <span class="author-avatar-placeholder" ng-if="::(!reply.authorAvatar)" title="{{ ::(reply.author && reply.author.name) || (\'ÐвÑоÑ\' | t) }}" >{{ ::((reply.author && reply.author.name) || (\'Ð\' | t)).charAt(0) }}</span > <div class="sidebar-author-info"> <span class="author-name" >{{ ::(reply.author && reply.author.name) || (\'ÐвÑоÑ\' | t) }}</span > <span class="sidebar-date">{{ ::reply.createdAt | date:\'dd.MM HH:mm\' }}</span> </div> </a> <span class="reply-author" ng-if="::(!reply.author || !reply.author.path)"> <img class="author-avatar" ng-if="::reply.authorAvatar" ng-src="{{ ::reply.authorAvatar }}" alt="" ng-on-error="$event.target.style.display=\'none\'" /> <span class="author-avatar-placeholder" ng-if="::(!reply.authorAvatar)" title="{{ ::(reply.author && reply.author.name) || (\'ÐвÑоÑ\' | t) }}" >{{ ::((reply.author && reply.author.name) || (\'Ð\' | t)).charAt(0) }}</span > <div class="sidebar-author-info"> <span class="author-name" >{{ ::(reply.author && reply.author.name) || (\'ÐвÑоÑ\' | t) }}</span > <span class="sidebar-date">{{ ::reply.createdAt | date:\'dd.MM HH:mm\' }}</span> </div> </span> <div class="item-actions-menu" ng-if="$ctrl.canEditReply(reply) || $ctrl.canDeleteReply(reply)" ng-class="{\'has-open-menu\': reply.menuOpen}" ng-click="$event.stopPropagation()" > <button type="button" class="ds-btn-link btn-icon item-menu-trigger reply-menu-trigger" ng-click="$ctrl.toggleItemMenu(reply, $event)" ng-disabled="$ctrl.isSuggestionReplyWriteBlocked(reply, suggestion)" aria-label="{{ \'ÐейÑÑÐ²Ð¸Ñ Ñ Ð¾ÑвеÑом\' | t }}" > <i class="fas fa-ellipsis-v"></i> </button> <div class="item-dropdown" ng-if="reply.menuOpen" ng-click="$event.stopPropagation()"> <button type="button" class="item-dropdown-btn" ng-if="$ctrl.canEditReply(reply) && !reply.isEditing" ng-click="$ctrl.startEditReply(reply, suggestion); reply.menuOpen = false" ng-disabled="$ctrl.isSuggestionReplyWriteBlocked(reply, suggestion)" > {{ \'РедакÑиÑоваÑÑ\' | t }} </button> <button type="button" class="item-dropdown-btn item-dropdown-btn--danger" ng-if="$ctrl.canDeleteReply(reply)" ng-click="$ctrl.deleteSuggestionReply(suggestion, reply
1); reply.menuOpen = false" ng-disabled="$ctrl.isSuggestionReplyWriteBlocked(reply, suggestion)" > {{ \'УдалиÑÑ\' | t }} </button> </div> </div> </div> <p class="collab-write-uncertain" ng-if="$ctrl.isSuggestionReplyWriteUncertain(reply)" role="status" > <i class="fas fa-exclamation-triangle" aria-hidden="true"></i> {{ \'Ðе ÑдалоÑÑ Ð¿Ð¾Ð´ÑвеÑдиÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ðµ. ÐбновиÑе ÑÑÑаниÑÑ, пÑежде Ñем пÑодолжиÑÑ\' | t }} </p> <div class="reply-text" ng-if="!reply.isEditing" ng-bind-html="reply.text | inlineMarkdown | mentionLinksHtml" ></div> <div class="reply-edit-form" ng-if="reply.isEditing"> <textarea class="reply-edit-textarea" ng-model="reply.editText" mention-autocomplete rich-text-shortcuts aria-label="{{ \'РедакÑиÑование оÑвеÑа на пÑавкÑ\' | t }}" rows="1" msd-elastic="msd-elastic" ng-keydown="$ctrl.onSuggestionReplyEditKeydown($event, suggestion, reply)" ng-readonly="$ctrl.isSuggestionReplyWriteBlocked(reply, suggestion)" ></textarea> <div class="reply-edit-actions"> <button type="button" class="btn-edit-cancel" ng-click="$ctrl.cancelEditReply(reply)" ng-disabled="$ctrl.isSuggestionReplyWritePending(reply)" > {{ \'ÐÑмениÑÑ\' | t }} </button> <button type="button" class="btn-edit-save" ng-click="$ctrl.saveEditSuggestionReply(suggestion, reply)" ng-disabled="!reply.editText || !reply.editText.trim() || $ctrl.isSuggestionReplyWriteBlocked(reply, suggestion)" > {{ \'СоÑ
ÑаниÑÑ\' | t }} </button> </div> </div> </div> </div> <div class="comment-add-reply"> <div class="reply-input-wrapper"> <textarea ng-model="suggestion.newReplyText" placeholder="{{ \'ÐÑвеÑиÑÑ...\' | t }}" aria-label="{{ \'ТекÑÑ Ð¾ÑвеÑа на обÑÑждение пÑавки\' | t }}" mention-autocomplete rich-text-shortcuts rows="1" msd-elastic="msd-elastic" ng-keydown="$ctrl.onSuggestionReplyKeydown($event, suggestion)" ng-readonly="$ctrl.isSuggestionDiscussionBlocked(suggestion)" ></textarea> <button type="button" class="reply-send-btn btn-icon" ng-click="$ctrl.addSuggestionReply(suggestion)" ng-disabled="!suggestion.newReplyText || !suggestion.newReplyText.trim() || $ctrl.isSuggestionDiscussionBlocked(suggestion)" aria-label="{{ \'ÐÑпÑавиÑÑ Ð¾ÑвеÑ\' | t }}" > <i class="fas fa-paper-plane" aria-hidden="true"></i> <span class="custom-tooltip">{{ \'ÐÑпÑавиÑÑ\' | t }}</span> </button> </div> </div>'),s.put("/pages/edit/editContentItem/partials/suggestion-type-label.html","<span class=\"suggestion-type-inline\" ng-if=\"suggestion.type === 'add'\">{{ 'Ðобавление' | t }}</span> <span class=\"suggestion-type-inline suggestion-type-inline--delete\" ng-if=\"suggestion.type === 'delete'\" >{{ 'Удаление' | t }}</span > <span class=\"suggestion-type-inline suggestion-type-inline--replace\" ng-if=\"suggestion.type === 'replace'\" >{{ 'Ðамена' | t }}</span > <span class=\"suggestion-type-inline suggestion-type-inline--format\" ng-if=\"suggestion.type === 'format'\" >{{ 'ФоÑмаÑ' | t }}</span > <span class=\"suggestion-type-inline\" ng-if=\"suggestion.type === 'node-add'\" >{{ 'ÐÑÑавка' | t }}</span > <span class=\"suggestion-type-inline suggestion-type-inline--delete\" ng-if=\"suggestion.type === 'node-delete'\" >{{ 'Удаление' | t }}</span > <span class=\"suggestion-type-inline suggestion-type-inline--update\" ng-if=\"suggestion.type === 'node-update'\" >{{ 'ÐÑавка' | t }}</span >"),s.put("/pages/edit/editContentItem/partials/tiptap-toolbar.html",'<div class="tiptap-editor-toolbar discours-toolbar" role="toolbar" aria-label="{{ \'ÐÐ°Ð½ÐµÐ»Ñ Ð¸Ð½ÑÑÑÑменÑов ÑедакÑоÑа\' | t }}" fixed-toolbar ng-mousedown="$event.preventDefault()" > <div class="tiptap-toolbar-buttons"> <div class="btn-group"> <button type="button" class="tiptap-btn" ng-class="{ active: $ctrl.isActive(\'bold\') }" ng-mousedown="$ctrl.execCommand(\'bold\', $event)" data-title="{{ \'жиÑнÑй\' | t }}" aria-label="{{ \'ÐиÑнÑй ÑекÑÑ\' | t }}" aria-pressed="{{$ctrl.isActive(\'bold\')}}" > <i class="df-editor-bold" aria-hidden="true"></i> </button> <button type="button" class="tiptap-btn" ng-class="{ active: $ctrl.isActive(\'italic\') }" ng-mousedown="$ctrl.execCommand(\'italic\', $event)" data-title="{{ \'кÑÑÑив\' | t }}" aria-label="{{ \'ÐÑÑÑив\' | t }}" aria-pressed="{{$ctrl.isActive(\'italic\')}}" > <i class="df-editor-italic" aria-hidden="true"></i> </button> <div class="btn-dropdown" ng-class="{ open: $ctrl.listDropdownOpen }" role="group" aria-label="{{ \'СпиÑки\' | t }}" > <button type="button" class="tiptap-btn btn-dropdown-toggle" ng-mousedown="$ctrl.toggleDropdown(\'listDropdownOpen\', $event)" data-title="{{ \'добавиÑÑ ÑпиÑок\' | t }}" aria-label="{{ \'ÐобавиÑÑ ÑпиÑок\' | t }}" aria-haspopup="true" aria-expanded="{{$ctrl.listDropdownOpen}}" > <i class="fas fa-list" aria-hidden="true"></i> </button> <div class="btn-dropdown-menu" ng-show="$ctrl.listDropdownOpen" role="menu"> <button type="button" class="tiptap-btn" ng-class="{ active: $ctrl.isActive(\'bulletList\') }" ng-mousedown="$ctrl.execCommand(\'bulletList\', $event); $ctrl.closeAllDropdowns()" data-title="{{ \'маÑкиÑованнÑй ÑпиÑок\' | t }}" aria-label="{{ \'ÐаÑкиÑованнÑй ÑпиÑок\' | t }}" role="menuitem" > <i class="fa fa-list-ul" aria-hidden="true"></i> </button> <button type="button" class="tiptap-btn" ng-class="{ active: $ctrl.isActive(\'orderedList\') }" ng-mousedown="$ctrl.execCommand(\'orderedList\', $event); $ctrl.closeAllDropdowns()" data-title="{{ \'нÑмеÑованнÑй ÑпиÑок\' | t }}" aria-label="{{ \'ÐÑмеÑованнÑй ÑпиÑок\' | t }}" role="menuitem" > <i class="fa fa-list-ol" aria-hidden="true"></i> </button> </div> </div> <div class="btn-dropdown" ng-class="{ open: $ctrl.formatDropdownOpen }" role="group" aria-label="{{ \'ФоÑмаÑиÑование ÑекÑÑа\' | t }}" > <button type="button" class="tiptap-btn btn-dropdown-toggle" ng-mousedown="$ctrl.toggleDropdown(\'formatDropdownOpen\', $event)" data-title="{{ \'ÑоÑмаÑиÑование ÑекÑÑа\' | t }}" aria-label="{{ \'ФоÑмаÑиÑование ÑекÑÑа\' | t }}" aria-haspopup="true" aria-expanded="{{$ctrl.formatDropdownOpen}}" > <i class="df-editor-text-tools" aria-hidden="true"></i> </button> <div class="btn-dropdown-menu" ng-show="$ctrl.formatDropdownOpen" role="menu"> <button type="button" class="tiptap-btn" ng-class="{ active: $ctrl.isActive(\'h2\') }" ng-mousedown="$ctrl.execCommand(\'h2\', $event); $ctrl.closeAllDropdowns()" data-title="{{ \'заголовок 1\' | t }}" aria-label="{{ \'Ðаголовок 1\' | t }}" role="menuitem" > <i class="df-editor-h1" aria-hidden="true"></i> </button> <button type="button" class="tiptap-btn" ng-class="{ active: $ctrl.isActive(\'h3\') }" ng-mousedown="$ctrl.execCommand(\'h3\', $event); $ctrl.closeAllDropdowns()" data-title="{{ \'заголовок 2\' | t }}" aria-label="{{ \'Ðаголовок 2\' | t }}" role="menuitem" > <i class="df-editor-h2" aria-hidden="true"></i> </button> <button type="button" class="tiptap-btn" ng-class="{ active: $ctrl.isActive(\'lead\') }" ng-mousedown="$ctrl.execCommand(\'lead\', $event); $ctrl.closeAllDropdowns()" data-title="{{ \'лид\' | t }}" aria-label="{{ \'Ðид\' | t }}" role="menuitem" > <i class="fa fa-paragraph" aria-hidden="true"></i> </button> <button type="button" class="tiptap-btn" ng-class="{ active: $ctrl.isActive(\'highlight\') }" ng-mousedown="$ctrl.execCommand(\'highlight\', $event); $ctrl.closeAllDropdowns()" data-title="{{ \'Ñ
айлайÑ\' | t }}" aria-label="{{ \'ХайлайÑ\' | t }}" role="menuitem" > <svg class="highlighter-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 544 512" width="16" height="16" fill="currentColor" aria-hidden="true" > <path d="M0 479.98L99.92 512l35.45-35.45-67.04-67.04L0 479.98zm124.61-240.01a36.592 36.592 0 0 0-10.79 38.1l13.05 42.83-50.93 50.94 96.23 96.23 50.86-50.86 42.74 13.08a36.46 36.46 0 0 0 38.09-10.79l94.12-114.14-159.2-159.2-114.17 93.81zm287.07-18.96L527.95 105.5c21.4-21.4 21.4-56.13 0-77.53l-43.91-43.91c-21.4-21.4-56.13-21.4-77.53 0L290.95 99.52l120.73 121.49z" /> </svg> </button> <button type="button" class="tiptap-btn" ng-class="{ active: $ctrl.isActive(\'blockquote\') }" ng-mousedown="$ctrl.execCommand(\'blockquote\', $event); $ctrl.closeAllDropdowns()" data-title="{{ \'ÑдаÑÐ½Ð°Ñ ÑиÑаÑа\' | t }}" aria-label="{{ \'УдаÑÐ½Ð°Ñ ÑиÑаÑа\' | t }}" role="menuitem" > <i class="df-editor-quote" aria-hidden="true"></i> </button> </div> </div> <div class="btn-dropdown" ng-class="{ open: $ctrl.wrapperDropdownOpen }" role="group" aria-label="{{ \'ÐодвÑÑÑÑки\' | t }}" > <button type="button" class="tiptap-btn btn-dropdown-toggle" ng-mousedown="$ctrl.toggleDropdown(\'wrapperDropdownOpen\', $event)" data-title="{{ \'подвÑÑÑÑки\' | t }}" aria-label="{{ \'ÐодвÑÑÑÑки\' | t }}" aria-haspopup="true" aria-expanded="{{$ctrl.wrapperDropdownOpen}}" > <span class="btn-icon-frame" aria-hidden="true"></span> </button> <div class="btn-dropdown-menu" ng-show="$ctrl.wrapperDropdownOpen" role="menu"> <button type="button" class="tiptap-btn" ng-class="{ active: $ctrl.isActive(\'taSelectionFrame\') }" ng-mousedown="$ctrl.execCommand(\'taSelectionFrame\', $event); $ctrl.closeAllDropdowns()" data-title="{{ \'Ñамка\' | t }}" aria-label="{{ \'Рамка\' | t }}" role="menuitem" > <span class="btn-icon-frame" aria-hidden="true"></span> </button> <button type="button" class="tiptap-btn" ng-class="{ active: $ctrl.isActive(\'taSub\') }" ng-mousedown="$ctrl.execCommand(\'taSub\', $event); $ctrl.closeAllDropdowns()" data-title="{{ \'подвÑÑÑÑка\' | t }}" aria-label="{{ \'ÐодвÑÑÑÑка\' | t }}" role="menuitem" > <span class="btn-icon-sub" aria-hidden="true"></span> </button> <button type="button" class="tiptap-btn" ng-class="{ active: $ctrl.isActive(\'taBorderSub\') }" ng-mousedown="$ctrl.execCommand(\'taBorderSub\', $event); $ctrl.closeAllDropdowns()" data-title="{{ \'подвÑÑÑÑка Ñ Ñамкой\' | t }}" aria-label="{{ \'ÐодвÑÑÑÑка Ñ Ñамкой\' | t }}" role="menuitem" > <span class="btn-icon-border-sub" aria-hidden="true"></span> </button> <button type="button" class="tiptap-btn" ng-class="{ active: $ctrl.isActive(\'taQuotation\') }" ng-mousedown="$ctrl.execCommand(\'taQuotation\', $event); $ctrl.closeAllDropdowns()" data-title="{{ \'ÑиÑаÑа из иÑÑоÑника\' | t }}" aria-label="{{ \'ЦиÑаÑа из иÑÑоÑника\' | t }}" role="menuitem" > <span class="btn-icon-quotation" aria-hidden="true"></span> </button> <button type="button" class="tiptap-btn" ng-class="{ active: $ctrl.isActive(\'taEpigraph\') }" ng-mousedown="$ctrl.execCommand(\'taEpigraph\', $event); $ctrl.closeAllDropdowns()" data-title="{{ \'ÑпигÑаÑ\' | t }}" aria-label="{{ \'ÐпигÑаÑ\' | t }}" role="menuitem" > <span class="btn-icon-epigraph" aria-hidden="true"></span> </button> </div> </div> <div class="btn-dropdown" ng-class="{ open: $ctrl.specialDropdownOpen }" role="group" aria-label="{{ \'СпеÑиалÑнÑе блоки\' | t }}" > <button type="button" class="tiptap-btn btn-dropdown-toggle" ng-mousedown="$ctrl.toggleDropdown(\'specialDropdownOpen\', $event)" data-title="{{ \'добавиÑÑ ÑпеÑблок\' | t }}" aria-label="{{ \'ÐобавиÑÑ ÑпеÑиалÑнÑй блок\' | t }}" aria-haspopup="true" aria-expanded="{{$ctrl.specialDropdownOpen}}" > <i class="fa fa-plus" aria-hidden="true"></i> </button> <div class="btn-dropdown-menu" ng-show="$ctrl.specialDropdownOpen" role="menu"> <button type="button" class="tiptap-btn" ng-mousedown="$ctrl.execCommand(\'insertToc\', $event); $ctrl.closeAllDropdowns()" data-title="{{ \'вÑÑавиÑÑ Ð¾Ð³Ð»Ð°Ð²Ð»ÐµÐ½Ð¸Ðµ\' | t }}" aria-label="{{ \'ÐÑÑавиÑÑ Ð¾Ð³Ð»Ð°Ð²Ð»ÐµÐ½Ð¸Ðµ\' | t }}" role="menuitem" > <i class="fa fa-list-alt" aria-hidden="true"></i> </button> <button type="button" class="tiptap-btn" ng-mousedown="$ctrl.execCommand(\'insertReadAlso\', $event); $ctrl.closeAllDropdowns()" data-title="{{ \'ÑиÑайÑе Ñакже\' | t }}" aria-label="{{ \'ЧиÑайÑе Ñакже\' | t }}" role="menuitem" > <i class="fa fa-newspaper" aria-hidden="true"></i> </button> <button type="button" class="tiptap-btn" ng-mousedown="$ctrl.execCommand(\'pdf\', $event); $ctrl.closeAllDropdowns()" data-title="{{ \'вÑÑавиÑÑ PDF\' | t }}" aria-label="{{ \'ÐÑÑавиÑÑ PDF докÑменÑ\' | t }}" role="menuitem" > <svg class="pdf-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" width="14" height="16" fill="currentColor" aria-hidden="true" > <path d="M64 0C28.7 0 0 28.7 0 64v384c0 35.3 28.7 64 64 64h256c35.3 0 64-28.7 64-64V160H256c-17.7 0-32-14.3-32-32V0H64zm192 0v128h128L256 0zM112 256c0-8.8 7.2-16 16-16h24c26.5 0 48 21.5 48 48s-21.5 48-48 48h-8v32c0 8.8-7.2 16-16 16s-16-7.2
1-16-16V256zm40 48h8c8.8 0 16-7.2 16-16s-7.2-16-16-16h-8v32zm64-48c0-8.8 7.2-16 16-16h16c26.5 0 48 21.5 48 48v64c0 26.5-21.5 48-48 48h-16c-8.8 0-16-7.2-16-16V256zm32 112h0c8.8 0 16-7.2 16-16v-64c0-8.8-7.2-16-16-16v96zm80-96h32c8.8 0 16-7.2 16-16s-7.2-16-16-16h-48c-8.8 0-16 7.2-16 16v128c0 8.8 7.2 16 16 16s16-7.2 16-16v-48h16c8.8 0 16-7.2 16-16s-7.2-16-16-16h-16v-32z" /> </svg> </button> <button type="button" class="tiptap-btn" ng-mousedown="$ctrl.execCommand(\'insertSpoiler\', $event); $ctrl.closeAllDropdowns()" data-title="{{ \'ÑпойлеÑ\' | t }}" aria-label="{{ \'Ð¡Ð¿Ð¾Ð¹Ð»ÐµÑ (подкаÑ)\' | t }}" role="menuitem" > <span class="btn-icon-spoiler" aria-hidden="true"></span> </button> </div> </div> </div> <div class="btn-group"> <button type="button" class="tiptap-btn" ng-class="{ active: $ctrl.isActive(\'link\') }" ng-mousedown="$ctrl.execCommand(\'link\', $event)" data-title="{{ \'вÑÑавиÑÑ ÑÑÑлкÑ\' | t }}" aria-label="{{ \'ÐÑÑавиÑÑ ÑÑÑлкÑ\' | t }}" > <i class="df-editor-link"></i> </button> <button type="button" class="tiptap-btn" ng-class="{ active: $ctrl.isActive(\'footnote\') }" ng-mousedown="$ctrl.execCommand(\'footnote\', $event)" data-title="{{ \'вÑÑавиÑÑ ÑноÑкÑ\' | t }}" aria-label="{{ \'ÐÑÑавиÑÑ ÑноÑкÑ\' | t }}" > <i class="df-editor-footnote"></i> </button> </div> <div class="btn-group"> <button type="button" class="tiptap-btn" ng-mousedown="$ctrl.execCommand(\'image\', $event)" data-title="{{ \'добавиÑÑ Ð¸Ð·Ð¾Ð±Ñажение\' | t }}" aria-label="{{ \'ÐобавиÑÑ Ð¸Ð·Ð¾Ð±Ñажение\' | t }}" > <i class="df-editor-image"></i> </button> <button type="button" class="tiptap-btn" ng-mousedown="$ctrl.execCommand(\'video\', $event)" data-title="{{ \'добавиÑÑ Ð²Ð¸Ð´ÐµÐ¾\' | t }}" aria-label="{{ \'ÐобавиÑÑ Ð²Ð¸Ð´ÐµÐ¾\' | t }}" > <i class="fab fa-youtube"></i> </button> <button type="button" class="tiptap-btn" ng-mousedown="$ctrl.execCommand(\'embed\', $event)" data-title="{{ \'вÑÑавиÑÑ Ð¼ÐµÐ´Ð¸Ð°\' | t }}" aria-label="{{ \'ÐÑÑавиÑÑ Ð¼ÐµÐ´Ð¸Ð°\' | t }}" > <i class="fa fa-code"></i> </button> <button type="button" class="tiptap-btn" ng-if="$ctrl.isAdmin" ng-class="{ active: $ctrl.htmlMode }" ng-mousedown="$ctrl.execCommand(\'toggleHtml\', $event)" data-title="{{ \'поÑмоÑÑеÑÑ html\' | t }}" aria-label="{{ \'ÐоÑмоÑÑеÑÑ HTML\' | t }}" > <i class="fas fa-wrench"></i> </button> </div> </div> </div>'),s.put("/pages/edit/editContentItem/types/Article.html",'<div class="title-input-row tw:flex tw:flex-wrap" ng-hide="$ctrl.isPreviewMode"> <div class="title-col tw:sm:w-8/12 tw:lg:w-9/12"> <div class="form-group tw:font-bold title" ng-class="{\'has-error\': formErrors.title}"> <textarea class="ds-input big-textarea placeholder-big" placeholder="{{ \'Ðаголовок\' | t }}" ng-model="contentItem.title" ng-change="formErrors.title = false" maxlength="120" textarea-limit-rows="textarea-limit-rows" rows="1" msd-elastic aria-label="{{ \'Ðаголовок ÑÑаÑÑи\' | t }}" aria-invalid="{{ !!formErrors.title }}" aria-describedby="form-error-title" ></textarea> <span id="form-error-title" class="help-block" ng-show="formErrors.title" role="alert" >{{ \'Ðаголовок обÑзаÑелен\' | t }}</span > </div> </div> <div class="cover-col tw:sm:w-4/12 tw:lg:w-3/12"> <div class="form-group"> <button class="big-button" type="button" ngf-select="$ctrl.uploadImage($file)" ngf-drop="$ctrl.uploadImage($file)" ngf-drag-over-class="\'drag-over\'" ngf-accept="\'image/*\'" ng-disabled="$ctrl.imageUploading[\'root\']" ng-hide="contentItem.thumborId" > <p class="fa fa-paperclip fa-4x"></p> <div>{{ \'ÐагÑÑзиÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}<br />(jpeg, png, gif)</div> <span class="fas fa-sync-alt fa-spin floating-text left" ng-show="$ctrl.imageUploading[\'root\']" ></span> </button> <div class="post-image-wrapper" ng-if="contentItem.thumborId"> <div class="cover-actions cover-actions--desktop"> <button type="button" class="cover-action-btn" ng-click="$ctrl.cropCoverImage()" ng-disabled="$ctrl.cropUploading" aria-label="{{ \'ÐадÑиÑоваÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'ÐадÑиÑоваÑÑ\' | t }}" > <i class="fas fa-crop-alt" aria-hidden="true"></i> </button> <button type="button" class="cover-action-btn" ngf-select="$ctrl.uploadImage($file)" ngf-accept="\'image/*\'" ng-disabled="$ctrl.cropUploading || $ctrl.imageUploading[\'root\']" aria-label="{{ \'ÐамениÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'ÐамениÑÑ\' | t }}" > <i class="fas fa-image" aria-hidden="true"></i> </button> <button type="button" class="cover-action-btn cover-action-btn--delete" ng-click="$ctrl.deleteCoverImage()" ng-disabled="$ctrl.cropUploading" aria-label="{{ \'УдалиÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'УдалиÑÑ\' | t }}" > <i class="fas fa-times" aria-hidden="true"></i> </button> </div> <ng-include src="\'/pages/edit/editContentItem/partials/cover-actions-mobile.html\'" ></ng-include> <span class="fas fa-sync-alt fa-spin crop-upload-spinner" ng-show="$ctrl.cropUploading" ></span> <img class="tw:block tw:max-w-full tw:h-auto thumbmail" ng-class="{\'is-uploading\': $ctrl.cropUploading }" ng-src="{{ contentItem.thumborId | imageUrl: 300 }}" ng-click="$ctrl.cropCoverImage()" alt="{{ contentItem.imageCaption || (\'Ðбложка:\' | t) + \' \' + (contentItem.title || (\'маÑеÑиал\' | t)) + \' \' + (\'â ÐиÑкÑÑÑ\' | t) }}" /> </div> <div class="image-caption-input"> <input type="text" name="imageCaption" placeholder="{{ \'ÐодпиÑÑ Ð¸Ð·Ð¾Ð±ÑажениÑ\' | t }}" class="material-style" ng-model="contentItem.imageCaption" /> <button type="button" class="caption-edit-icon" data-tooltip="{{ \'РедакÑиÑоваÑÑ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑ\' | t }}" ng-click="$ctrl.openImageCaptionEditor($event)" > <i class="fas fa-pencil-alt" aria-hidden="true"></i> </button> </div> </div> </div> </div> <editor-header ng-if="$ctrl.showEditorHeader" doc-title="contentItem.title" slug="contentItem.slug" content-status="contentItem.status" content-link="contentItem.link" collab-status="$ctrl.collabStatus" connected-users="$ctrl.connectedUsers" is-offline-mode="$ctrl.isOfflineMode" collab-permission-denied="$ctrl.collabPermissionDenied" is-reconnecting="$ctrl.isReconnecting" tiptap-editor="$ctrl.tiptapEditor" is-preview-mode="$ctrl.isPreviewMode" suggestion-mode="$ctrl.suggestionMode" sidebar-visible="$ctrl.sidebarVisible" pending-count="$ctrl.pendingChangesCount" collab-sync-pending="$ctrl.collabSyncPending" is-saving="$ctrl.isSaving" is-publishing="$ctrl.isPublishing" is-saving-version="$ctrl.savingVersion" is-save-success="$ctrl.saveSuccess" is-save-error="$ctrl.isSaveError" last-version-saved-at="$ctrl.lastVersionSavedAt" has-unsaved-changes="$ctrl.hasUnsavedChanges" has-draft="$ctrl.hasDraft" can-edit="$ctrl.canEdit === true" is-author="!$ctrl.contentItemCreatorId || $ctrl.userId === $ctrl.contentItemCreatorId" show-collab-control
1s="!!contentItem.slug" show-invite-button="$ctrl.canEdit === true && contentItem.slug" invite-count="$ctrl.inviteCount" on-open-invite="$ctrl.openInviteModal()" on-mode-change="$ctrl.onEditorModeChange(mode)" on-toggle-sidebar="$ctrl.toggleSidebar()" on-save="contentItem.slug ? $ctrl.saveAndCreateVersion() : $ctrl.saveDraft()" on-save-version-dialog="$ctrl.openVersionNameDialog()" on-publish="$ctrl.sendFormForPublish()" on-validate-before-publish="$ctrl.validateBeforePublish()" on-retry-connection="$ctrl.retryCollabConnection()" on-versions-click="$ctrl.toggleVersions()" night-mode="$ctrl.darkMode" on-toggle-night-mode="$ctrl.toggleDarkMode()" on-open-settings="$ctrl.openPublishSettings()" on-run-typographer="$ctrl.applyTypography()" word-count="$ctrl.wordCount" char-count="$ctrl.charCount" initial-para-count="$ctrl.paraCount" is-admin="$ctrl.isAdmin" on-clean-code="$ctrl.cleanHtmlContent()" initial-last-modified="$ctrl.initialLastModified" margin-view-mode="$ctrl.marginViewMode" on-toggle-margin-view="$ctrl.toggleMarginView()" quiet-mode="$ctrl.quietMode" on-toggle-quiet-mode="$ctrl.toggleQuietMode()" is-logged-in="$ctrl.isLoggedIn" user-avatar="$ctrl.userAvatarId" user-path="$ctrl.userPathSlug" ></editor-header> <invite-collaborators opened="$ctrl.inviteModalOpen" document-name="$ctrl.collabDocumentName" on-invites-changed="$ctrl.onInvitesChanged(invites)" ></invite-collaborators> <div class="post-preview tiptap-preview-mode" ng-if="$ctrl.isPreviewMode && $ctrl.previewPost"> <div class="button-container"> <button type="button" class="preview-close-button" ng-click="$ctrl.togglePreviewMode()"> <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M17.9975 4.89363L13.1038 0L0 13.1064V18H4.89363L17.9975 4.89363ZM13.105 2.55674L15.4421 4.89383L14.4612 5.87591L12.1241 3.53882L13.105 2.55674ZM10.8453 4.81648L13.1824 7.15357L5.42174 14.9137L3.08485 12.5756L10.8453 4.81648ZM1.80725 16.1915V13.8544L4.14434 16.1915H1.80725Z" fill="currentColor" /> </svg> {{ \'ÐÑодолжиÑÑ ÑедакÑиÑоваÑÑ\' | t }} </button> </div> <div class="open-post progress"> <div class="author-category" ng-class="{\'no-author\': !$ctrl.previewPost.author }"> <span class="category" ng-if="$ctrl.previewPost.category"> <a ng-href="{{ $ctrl.previewPost.categoryLink }}" rel="noopener noreferrer" target="_blank" >{{ $ctrl.previewPost.category }}</a > </span> <span class="author" ng-if="$ctrl.previewPost.author"> <a ng-href="{{ $ctrl.previewPost.authorLink }}" rel="noopener noreferrer" target="_blank" ng-if="$ctrl.previewPost.authorLink" >{{ $ctrl.previewPost.author }}</a > <span ng-if="!$ctrl.previewPost.authorLink">{{ $ctrl.previewPost.author }}</span> </span> </div> <h1 class="title">{{ $ctrl.previewPost.title }}</h1> <div class="open-post-title-image-wrapper" ng-if="$ctrl.previewPost.thumborId" ng-class="{\'is-image-loaded\': previewTitleImageLoaded}" > <img class="open-post-title-image fancybox-img" fancybox-img ng-if="$ctrl.previewPost.imageCaption" fetchpriority="high" loading="eager" decoding="async" sizes="(min-width: 768px) 66vw, 100vw" ng-src="{{ $ctrl.previewPost.thumborId | imageUrl: 750 }}" ng-srcset="{{ $ctrl.previewPost.thumborId | imageUrl: 320 }} 320w, {{ $ctrl.previewPost.thumborId | imageUrl: 480 }} 480w, {{ $ctrl.previewPost.thumborId | imageUrl: 640 }} 640w, {{ $ctrl.previewPost.thumborId | imageUrl: 960 }} 960w, {{ $ctrl.previewPost.thumborId | imageUrl: 1280 }} 1280w, {{ $ctrl.previewPost.thumborId | imageUrl: 1920 }} 1920w, {{ $ctrl.previewPost.thumborId | imageUrl: 2560 }} 2560w" alt="{{ ($ctrl.previewPost.imageCaption | stripHTML) + \'. \' + ($ctrl.previewPost.title | stripHTML) + \' \' + (\'â ÐиÑкÑÑÑ\' | t) }}" title="{{ ($ctrl.previewPost.imageCaption | stripHTML) + \'. \' + ($ctrl.previewPost.title | stripHTML) + \' \' + (\'â ÐиÑкÑÑÑ\' | t) }}" ng-image-onload="previewTitleImageLoaded = true" /> <img class="open-post-title-image fancybox-img" fancybox-img ng-if="!$ctrl.previewPost.imageCaption" fetchpriority="high" loading="eager" decoding="async" sizes="(min-width: 768px) 66vw, 100vw" ng-src="{{ $ctrl.previewPost.thumborId | imageUrl: 750 }}" ng-srcset="{{ $ctrl.previewPost.thumborId | imageUrl: 320 }} 320w, {{ $ctrl.previewPost.thumborId | imageUrl: 480 }} 480w, {{ $ctrl.previewPost.thumborId | imageUrl: 640 }} 640w, {{ $ctrl.previewPost.thumborId | imageUrl: 960 }} 960w, {{ $ctrl.previewPost.thumborId | imageUrl: 1280 }} 1280w, {{ $ctrl.previewPost.thumborId | imageUrl: 1920 }} 1920w, {{ $ctrl.previewPost.thumborId | imageUrl: 2560 }} 2560w" alt="{{ \'Ðбложка:\' | t }} {{ $ctrl.previewPost.title }} {{ \'â ÐиÑкÑÑÑ\' | t }}" title="{{ $ctrl.previewPost.title }} {{ \'â ÐиÑкÑÑÑ\' | t }}" ng-image-onload="previewTitleImageLoaded = true" /> </div> <p class="image-description" ng-if="$ctrl.previewPost.imageCaption" ng-bind-html="$ctrl.previewPost.imageCaption | trustedHtml" ></p> <div class="post-body" ng-bind-html="$ctrl.previewPost.body | trustedHtml" post-links="post-links" post-images="post-images" social-text="social-text" footnote-text="footnote-text" pdf-viewer-hydrate disclaimer="{{ $ctrl.previewPost.publishedAt }}" ></div> <div class="footer-post"> <hr class="tw:mt-2.5 tw:mb-5" /> <div class="post-meta-footer"> <div class="post-meta-footer__author"> <div class="author-title" ng-if="$ctrl.previewPost.author"> <a ng-href="{{ $ctrl.previewPost.authorLink }}" rel="noopener noreferrer" target="_blank" ng-if="$ctrl.previewPost.authorLink" >{{ $ctrl.previewPost.author }}</a >
1 <span ng-if="!$ctrl.previewPost.authorLink">{{ $ctrl.previewPost.author }}</span> </div> <div class="date-time"> <span class="time" ng-if="$ctrl.previewPost.publishedAt" >{{ $ctrl.previewPost.publishedAt | amDateFormat: \'D MMMM YYYY\' }}</span ><span class="time" ng-if="!$ctrl.previewPost.publishedAt && $ctrl.previewPost.postedAt" >{{ $ctrl.previewPost.postedAt | amDateFormat: \'D MMMM YYYY\' }}</span > </div> </div> </div> <ul class="tags tw:mt-2.5" ng-if="$ctrl.previewPost.tags.length"> <li ng-repeat="tag in $ctrl.previewPost.tags track by tag.slug"> <a ng-href="/tags/{{ tag.slug }}" rel="noopener noreferrer" target="_blank" >#{{ tag.title }}</a > </li> </ul> </div> </div> <div class="button-container bottom-button" ng-if="$ctrl.showBottomEditButton"> <button type="button" class="preview-close-button bottom" ng-click="$ctrl.togglePreviewMode()"> <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M17.9975 4.89363L13.1038 0L0 13.1064V18H4.89363L17.9975 4.89363ZM13.105 2.55674L15.4421 4.89383L14.4612 5.87591L12.1241 3.53882L13.105 2.55674ZM10.8453 4.81648L13.1824 7.15357L5.42174 14.9137L3.08485 12.5756L10.8453 4.81648ZM1.80725 16.1915V13.8544L4.14434 16.1915H1.80725Z" fill="currentColor" /> </svg> {{ \'ÐÑодолжиÑÑ ÑедакÑиÑоваÑÑ\' | t }} </button> </div> </div> <div class="form-group discours-editor big tiptap-mode" ng-show="!$ctrl.isPreviewMode" ng-class="{\'has-editor-header\': $ctrl.showEditorHeader, \'quiet-mode\': $ctrl.quietMode }" > <div class="tiptap-loading" ng-if="!$ctrl.tiptapReady || $ctrl.collabSyncPending"> <div class="loading-progress-bar"> <div class="loading-progress-fill"></div> </div> <div class="tiptap-loading-skeleton"> <div class="tiptap-loading-skeleton__line"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--90"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--75"></div> <div class="tiptap-loading-skeleton__gap"></div> <div class="tiptap-loading-skeleton__line"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--85"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--60"></div> <div class="tiptap-loading-skeleton__gap"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--90"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--75"></div> </div> </div> <div ng-if="$ctrl.commenterReadOnly && !$ctrl.loginForReviewAvailable && $ctrl.tiptapReady" class="backup-recovery-banner anonymous-suggestions-banner" > <div class="backup-message"> <i class="fas fa-comment"></i> <span>{{ \'Режим комменÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ â вÑделиÑе ÑекÑÑ, ÑÑÐ¾Ð±Ñ Ð¾ÑÑавиÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑий.\' | t }}</span> </div> </div> <div ng-if="$ctrl.loginForReviewAvailable && $ctrl.tiptapReady" class="backup-recovery-banner anonymous-suggestions-banner" > <div class="backup-message"> <i class="fas fa-key"></i> <span>{{ \'ÐойдиÑе, ÑÑÐ¾Ð±Ñ Ð¾ÑÑавлÑÑÑ Ð¿Ñавки в Ñежиме ÑеÑензиÑованиÑ.\' | t }}</span> </div> <div class="backup-actions"> <button type="button" class="btn-restore" ng-click="$ctrl.openLoginModal()"> {{ \'ÐойÑи\' | t }} </button> </div> </div> <div ng-if="$ctrl.hasLocalBackup && contentItem.slug && !$ctrl.collabSyncPending" class="backup-recovery-banner" ng-class="{\'is-collapsed\': $ctrl.backupBannerCollapsed}" > <button type="button" ng-if="$ctrl.backupBannerCollapsed" class="backup-collapsed-indicator" ng-click="$ctrl.expandBackupBanner()" aria-label="{{ \'ÐоказаÑÑ ÑезеÑвнÑÑ ÐºÐ¾Ð¿Ð¸Ñ\' | t }}" title="{{ \'ÐоказаÑÑ ÑезеÑвнÑÑ ÐºÐ¾Ð¿Ð¸Ñ\' | t }}" > <i class="fas fa-history"></i> <span>{{ \'ÐÑÑÑ ÑезеÑÐ²Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ\' | t }}</span> </button> <div ng-if="!$ctrl.backupBannerCollapsed" class="backup-message"> <i class="fas fa-history"></i> <span >{{ \'РезеÑÐ²Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ Ð¾Ñ\' | t }} {{ $ctrl.localBackupTime | date:\'dd.MM.yyyy HH:mm\' }}. <span ng-bind="\'ÐоÑÑÑановление Ð·Ð°Ð¼ÐµÐ½Ð¸Ñ Ð²ÐµÑÑ ÑекÑÑ, в Ñом ÑиÑле пÑавки ÑоавÑоÑов. ТекÑÑий ÑекÑÑ ÑнаÑала ÑоÑ
ÑаниÑÑÑ Ð²ÐµÑÑией.\' | t" ></span ></span> </div>
1 <div ng-if="!$ctrl.backupBannerCollapsed" class="backup-actions"> <button type="button" class="btn-restore" ng-click="$ctrl.restoreFromBackup()" ng-disabled="$ctrl.restoringBackup" > <i class="fas fa-undo"></i> {{ \'ÐоÑÑÑановиÑÑ\' | t }} </button> <button type="button" class="btn-discard" ng-click="$ctrl.discardBackup()"> <i class="fas fa-times" aria-hidden="true"></i> {{ \'СоÑ
ÑаниÑÑ ÐºÐ°Ðº веÑÑиÑ\' | t }} </button> </div> </div> <div ng-if="$ctrl.tiptapReady" class="tiptap-editor-container" ng-class="{\'is-syncing\': $ctrl.collabSyncPending}" > <div class="toc-nav-container" id="toc-nav-container-article"></div> <ng-include src="\'/pages/edit/editContentItem/partials/sidebar-side-toggle.html\'"></ng-include> <div class="tiptap-editor-wrapper"> <ng-include ng-if="!$ctrl.commenterReadOnly" src="\'/pages/edit/editContentItem/partials/tiptap-toolbar.html\'" ></ng-include> <div class="editor-with-margin-host" ng-class="{\'margin-view-active\': $ctrl.marginViewMode, \'sheet-open\': $ctrl.sidebarVisible }" > <tiptap-editor ng-model="contentItem.body" placeholder="{{ \'ÐеÑÑо Ð´Ð»Ñ Ð²Ð°Ñей иÑÑоÑииâ¦\' | t }}" user-id="$ctrl.userId" user-name="$ctrl.userName" user-slug="$ctrl.userSlug" user-avatar="$ctrl.userAvatar" editor-instance="$ctrl.tiptapEditor" content-item="contentItem" collab-server-url="{{ $ctrl.collabServerUrl }}" collab-document-name="$ctrl.collabDocumentName" collab-token="$ctrl.collabToken" collab-status="$ctrl.collabStatus" collab-permission-denied="$ctrl.collabPermissionDenied" is-offline-mode="$ctrl.isOfflineMode" is-reconnecting="$ctrl.isReconnecting" on-collab-synced="$ctrl.onCollabSynced()" on-collab-fallback="$ctrl.onCollabFallback(reason)" on-initial-content-ready="$ctrl.onInitialContentReady()" initial-content="$ctrl.initialContent" ></tiptap-editor> <ng-include src="\'/pages/edit/editContentItem/partials/margin-view.html\'"></ng-include> </div> <div class="tiptap-sidebar" ng-class="{ visible: $ctrl.sidebarVisible }"> <button type="button" class="sheet-drag-handle" aria-label="{{ \'ÐзмениÑÑ Ð²ÑÑоÑÑ Ð¿Ð°Ð½ÐµÐ»Ð¸\' | t }}" > <span class="sheet-drag-grip" aria-hidden="true"></span> </button> <div class="sidebar-header"> <div class="sidebar-tabs"> <button type="button" class="sidebar-tab" ng-class="{ active: $ctrl.sidebarTab === \'comments\' }" ng-click="$ctrl.sidebarTab = \'comments\'" data-collab-comments-tab > {{ \'ÐомменÑаÑии\' | t }} <span class="tab-count" ng-if="$ctrl.openCommentsCount" title="{{ \'ÐеÑеÑÑннÑе комменÑаÑии\' | t }}" >({{ $ctrl.openCommentsCount }})</span > </button> <button type="button" class="sidebar-tab" ng-class="{ active: $ctrl.sidebarTab === \'suggestions\' }" ng-click="$ctrl.sidebarTab = \'suggestions\'" > {{ \'ÐÑавки\' | t }} <span class="tab-count" ng-if="$ctrl.suggestions.length" >({{ $ctrl.suggestions.length }})</span > </button> </div> <div class="sidebar-header-actions"> <div ng-if="!$ctrl.commentsLoading && $ctrl.sidebarTab === \'comments\'" ng-include="\'/pages/edit/editContentItem/partials/comment-filter.html\'" ></div> <button type="button" class="sidebar-close" ng-click="$ctrl.toggleSidebar()" title="{{ \'ÐакÑÑÑÑ\' | t }}" > <i class="fas fa-times" aria-hidden="true"></i> </button> </div> </div> <ng-include class="sidebar-capability-notice" ng-if="$ctrl.collabCommentStoreUnavailable" src="\'/pages/edit/editContentItem/partials/collab-capability-notice.html\'" ></ng-include> <div class="sidebar-content" ng-if="$ctrl.sidebarTab === \'comments\'"> <div ng-if="$ctrl.commentsLoading" class="comments-skeleton" aria-busy="true" aria-label="{{ \'ÐагÑÑзка комменÑаÑиев\' | t }}" > <div class="comments-skeleton__item" ng-repeat="i in [1,2,3] track by $index"> <div class="comments-skeleton__author"></div> <div class="comments-skeleton__text"></div> <div class="comments-skeleton__meta"></div> </div> </div> <div class="sidebar-empty" ng-if="!$ctrl.commentsLoading && !$ctrl.comments.length && !$ctrl.collabCommentStoreUnavailable" > <i class="fas fa-comment"></i> <p>{{ \'ÐÐµÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑиев\' | t }}</p> <small>{{ \'ÐÑделиÑе ÑекÑÑ Ð¸ нажмиÑе ÐºÐ½Ð¾Ð¿ÐºÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑиÑ\' | t }}</small> </div>
1 <ng-include ng-if="!$ctrl.commentsLoading" src="\'/pages/edit/editContentItem/partials/comment-list.html\'" ></ng-include> </div> <div class="sidebar-content" ng-if="$ctrl.sidebarTab === \'suggestions\'"> <div class="sidebar-empty" ng-if="!$ctrl.suggestions.length"> <i class="fas fa-check-circle"></i> <p>{{ \'ÐÐµÑ Ð¾Ð¶Ð¸Ð´Ð°ÑÑиÑ
пÑавок\' | t }}</p> <small>{{ \'ÐклÑÑиÑе Ñежим пÑавок Ð´Ð»Ñ Ð¾ÑÑÐ»ÐµÐ¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹\' | t }}</small> </div> <div class="suggestion-list" ng-if="$ctrl.suggestions.length"> <div class="suggestion-actions-all" ng-if="$ctrl.suggestions.length > 1 && $ctrl.canModerate()" > <button type="button" class="ds-btn ds-btn-sm ds-btn-success" ng-click="$ctrl.acceptAllSuggestions()" ng-disabled="$ctrl.isSuggestionBulkActionBlocked()" > <i class="fas fa-check-double"></i> {{ \'ÐÑинÑÑÑ Ð²Ñе\' | t }} </button> <button type="button" class="ds-btn ds-btn-sm ds-btn-danger" ng-click="$ctrl.rejectAllSuggestions()" ng-disabled="$ctrl.isSuggestionBulkActionBlocked()" > <i class="fas fa-times" aria-hidden="true"></i> {{ \'ÐÑклониÑÑ Ð²Ñе\' | t }} </button> </div> <div class="suggestion-item" ng-repeat="suggestion in $ctrl.suggestions | limitTo:$ctrl.suggestionsDisplayLimit track by suggestion.suggestionId" ng-class="[suggestion.type, { expanded: suggestion.isExpanded }]" data-sidebar-suggestion-id="{{ suggestion.suggestionId }}" ng-click="$ctrl.toggleSuggestionExpand(suggestion)" role="group" ng-attr-aria-label="{{ ::(\'ÐÑавка оÑ\' | t) + \' \' + (suggestion.authorName || (\'ÐвÑоÑ\' | t)) }}" > <div class="suggestion-header"> <div class="suggestion-header-main"> <a class="suggestion-author" ng-href="/{{ suggestion.authorSlug }}" ng-if="suggestion.authorSlug" rel="noopener noreferrer" target="_blank" ng-click="$event.stopPropagation()" > <img class="author-avatar" ng-if="suggestion.authorAvatar" ng-src="{{ suggestion.authorAvatar }}" alt="" ng-on-error="$event.target.style.display=\'none\'" /> <span class="author-avatar-placeholder" ng-if="!suggestion.authorAvatar && suggestion.authorId" title="{{ suggestion.authorName || (\'ÐвÑоÑ\' | t) }}" >{{ (suggestion.authorName || (\'Ð\' | t)).charAt(0) }}</span > <div class="sidebar-author-info"> <span class="author-name">{{ suggestion.authorName || (\'ÐвÑоÑ\' | t) }}</span> <span class="sidebar-date" >{{ suggestion.createdAt | date:\'dd.MM HH:mm\' }}</span > </div> </a> <span class="suggestion-author" ng-if="!suggestion.authorSlug"> <img class="author-avatar" ng-if="suggestion.authorAvatar" ng-src="{{ suggestion.authorAvatar }}" alt="" ng-on-error="$event.target.style.display=\'none\'" /> <span class="author-avatar-placeholder" ng-if="!suggestion.authorAvatar && suggestion.authorId" title="{{ suggestion.authorName || (\'ÐвÑоÑ\' | t) }}" >{{ (suggestion.authorName || (\'Ð\' | t)).charAt(0) }}</span > <div class="sidebar-author-info"> <span class="author-name" >{{ !suggestion.authorId ? (\'Ðнонимно\' | t) : (suggestion.authorName || (\'ÐвÑоÑ\' | t)) }}</span > <span class="sidebar-date" >{{ suggestion.createdAt | date:\'dd.MM HH:mm\' }}</span > </div> </span> </div> <div class="suggestion-actions" ng-click="$event.stopPropagation()"> <button type="button" class="ds-btn-link btn-icon card-disclosure" ng-click="$ctrl.toggleSuggestionDisclosure(suggestion)" ng-attr-aria-expanded="{{ suggestion.isExpanded ? \'true\' : \'false\' }}" ng-attr-aria-controls="{{ suggestion.isExpanded ? (\'suggestion-discussion-\' + suggestion.suggestionId) : undefined }}" aria-label="{{ (suggestion.isExpanded ? \'СвеÑнÑÑÑ Ð¿ÑавкÑ\' : \'РазвеÑнÑÑÑ Ð¿ÑавкÑ\') | t }}" > <i class="fas fa-chevron-down" aria-hidden="true"></i> </button> <button type="button" class="ds-btn-link btn-icon ds-btn-success" ng-click="$ctrl.acceptSuggestion(suggestion)" ng-if="$ctrl.canModerate()" ng-disabled="$ctrl.isSuggestionActionBlocked(suggestion)" aria-label="{{ \'ÐÑинÑÑÑ Ð¿ÑавкÑ\' | t }}" > <i class="fas fa-check"></i> <span class="custom-tooltip">{{ \'ÐÑинÑÑÑ\' | t }}</span> </button> <button type="button" class="ds-btn-link btn-icon ds-btn-danger" ng-click="$ctrl.rejectSuggestion(suggestion)" ng-if="$ctrl.canModerate()" ng-disabled="$ctrl.isSuggestionActionBlocked(suggestion)" aria-label="{{ \'ÐÑклониÑÑ Ð¿ÑавкÑ\' | t }}" > <i class="fas fa-times" aria-hidden="true"></i> <span class="custom-tooltip">{{ \'ÐÑклониÑÑ\' | t }}</span> </button> </div> </div> <p class="collab-write-uncertain" ng-if="$ctrl.suggestionDiscussionNotice(suggestion) && !suggestion.isExpanded" role="status" > <i class="fas fa-exclamation-triangle" aria-hidden="true"></i> {{ $ctrl.suggestionDiscussionNotice(suggestion) }} </p> <div class="suggestion-text" ng-if="suggestion.type === \'node-add\' || suggestion.type === \'node-delete\' || suggestion.type === \'node-update\'" > <strong class="suggestion-action-label" ng-if="suggestion.type === \'node-add\'" >{{ \'ÐобавиÑÑ:\' | t }}</strong > <strong class="suggestion-action-label" ng-if="suggestion.type === \'node-delete\'" >{{ \'УдалиÑÑ:\' | t }}</strong > <strong class="suggestion-action-label" ng-if="suggestion.type === \'node-update\'" >{{ \'ÐзмениÑÑ:\' | t }}</strong > <span class="text-format">{{ suggestion.nodeDescription }}</span> <div class="suggestion-update-changes" ng-if="suggestion.updateChanges.length"> <div class="suggestion-update-change" ng-repeat="change in suggestion.updateChanges track by change.key" > <span class="suggestion-update-label">{{ change.label }}</span> <span class="text-delete" ng-if="change.before" >{{ change.before | limitTo:100 }}<span ng-if="change.before.length > 100" >â¦</span ></span > <span class="text-delete suggestion-update-empty" ng-if="!change.before" >{{ \'пÑÑÑо\' | t }}</span > <span class="text-replace-arrow">â</span> <span class="text-add" ng-if="change.after" >{{ change.after | limitTo:100 }}<span ng-if="change.after.length > 100" >â¦</span ></span > <span class="text-add suggestion-update-empty" ng-if="!change.after" >{{ \'пÑÑÑо\' | t }}</span > </div> </div> </div> <div class="suggestion-text" ng-if="suggestion.type === \'replace\'"> <strong class="suggestion-action-label">{{ \'ÐамениÑÑ:\' | t }}</strong> <div class="suggestion-replace-block"> <span class="text-delete" >{{ suggestion.deleteText | limitTo:100 }}<span ng-if="suggestion.deleteText.length > 100" >â¦</span ></span > <span class="text-replace-arrow">â</span> <span class="text-add" >{{ suggestion.addText | limitTo:100 }}<span ng-if="suggestion.addText.length > 100" >â¦</span ></span > </div> </div> <div class="suggestion-text" ng-if="suggestion.type === \'add\' || suggestion.type === \'delete\' || suggestion.type === \'format\'" > <strong class="suggestion-action-label" ng-if="suggestion.type === \'add\'" >{{ \'ÐобавиÑÑ:\' | t }}</strong > <strong class="suggestion-action-label" ng-if="suggestion.type === \'delete\'" >{{ \'УдалиÑÑ:\' | t }}</strong > <strong class="suggestion-action-label" ng-if="suggestion.type === \'format\'" >{{ \'ФоÑмаÑ:\' | t }}</strong > <span ng-if="suggestion.type === \'add\'" class="text-add" >{{ suggestion.text | limitTo:100 }}<span ng-if="suggestion.text.length > 100" >â¦</span ></span > <span ng-if="suggestion.type === \'delete\'" class="text-delete" >{{ suggestion.text | limitTo:100 }}<span ng-if="suggestion.text.length > 100" >â¦</span ></span > <span ng-if="suggestion.type === \'format\'" class="text-format" >{{ suggestion.formatDescription }}</span > </div> <div class="replies-count-hint" ng-if="!suggestion.isExpanded && $ctrl.suggestionThreads[suggestion.suggestionId] && $ctrl.suggestionThreads[suggestion.suggestionId].length" ng-click="$event.stopPropagation(); $ctrl.toggleSuggestionExpand(suggestion)" > <i class="fas fa-reply" aria-hidden="true"></i> <span >{{ $ctrl.suggestionThreads[suggestion.suggestionId].length | pluralize:\'оÑвеÑ\':\'оÑвеÑа\':\'оÑвеÑов\' }}</span > </div> <div id="suggestion-discussion-{{ ::suggestion.suggestionId }}" ng-if="suggestion.isExpanded" ng-click="$event.stopPropagation()" > <ng-include src="\'/pages/edit/editContentItem/partials/suggestion-replies.html\'" ></ng-include> </div> </div>
1 <button type="button" class="sidebar-show-more" ng-if="$ctrl.suggestions.length > $ctrl.suggestionsDisplayLimit" ng-click="$ctrl.showMoreSuggestions()" > {{ \'ÐоказаÑÑ ÐµÑÑ\' | t }} {{ $ctrl.suggestions.length - $ctrl.suggestionsDisplayLimit }} </button> </div> </div> </div> </div> <div class="tiptap-bottom-bar"> <div class="bottom-bar-left"></div> <div class="bottom-bar-right bottom-bar-save-status" aria-live="polite"> <span ng-show="$ctrl.isSaving" class="save-status save-status--saving"> <i class="fas fa-circle-notch fa-spin" aria-hidden="true"></i> {{ \'СоÑ
Ñанениеâ¦\' | t }} </span> <span ng-show="!$ctrl.isSaving && $ctrl.saveSuccess" class="save-status save-status--saved"> <i class="fas fa-check" aria-hidden="true"></i> {{ \'СоÑ
Ñанено\' | t }} </span> <span ng-show="!$ctrl.isSaving && !$ctrl.saveSuccess && $ctrl.hasUnsavedChanges" class="save-status save-status--unsaved" > {{ \'Ðе ÑоÑ
Ñанено\' | t }} </span> </div> </div> </div> </div>'),s.put("/pages/edit/editContentItem/types/Image.html",'<ng-include src="\'/pages/edit/editContentItem/partials/expo-preview.html\'" ng-if="$ctrl.isPreviewMode" ></ng-include> <editor-header ng-if="$ctrl.showEditorHeader" doc-title="contentItem.title" slug="contentItem.slug" content-status="contentItem.status" content-link="contentItem.link" tiptap-editor="$ctrl.tiptapExpoEditor" is-preview-mode="$ctrl.isPreviewMode" is-saving="$ctrl.isSaving" is-publishing="$ctrl.isPublishing" is-save-error="$ctrl.isSaveError" has-unsaved-changes="$ctrl.hasUnsavedChanges" has-draft="$ctrl.hasDraft" can-edit="$ctrl.canEdit === true" on-mode-change="$ctrl.onEditorModeChange(mode)" on-save="contentItem.slug ? $ctrl.saveAndCreateVersion() : $ctrl.saveDraft()" on-save-version-dialog="$ctrl.openVersionNameDialog()" on-versions-click="$ctrl.toggleVersions()" is-saving-version="$ctrl.savingVersion" is-save-success="$ctrl.saveSuccess" last-version-saved-at="$ctrl.lastVersionSavedAt" on-publish="$ctrl.sendFormForPublish()" is-admin="$ctrl.isAdmin" on-open-settings="$ctrl.openPublishSettings()" on-run-typographer="$ctrl.applyTypography()" on-clean-code="$ctrl.cleanHtmlContent()" word-count="$ctrl.wordCount" char-count="$ctrl.charCount" initial-para-count="$ctrl.paraCount" is-logged-in="$ctrl.isLoggedIn" user-avatar="$ctrl.userAvatarId" user-path="$ctrl.userPathSlug" night-mode="$ctrl.darkMode" on-toggle-night-mode="$ctrl.toggleDarkMode()" ></editor-header> <div class="title-input-row tw:flex tw:flex-wrap" ng-hide="$ctrl.isPreviewMode"> <div class="title-col tw:sm:w-8/12 tw:lg:w-9/12"> <div class="form-group tw:font-bold title" ng-class="{\'has-error\': formErrors.title}"> <textarea class="ds-input big-textarea placeholder-big" placeholder="{{ \'Ðаголовок\' | t }}" ng-model="contentItem.title" ng-change="formErrors.title = false" maxlength="120" textarea-limit-rows="textarea-limit-rows" aria-label="{{ \'Ðаголовок изобÑажениÑ\' | t }}" rows="1" msd-elastic aria-invalid="{{ !!formErrors.title }}" aria-describedby="form-error-title" ></textarea> <span id="form-error-title" class="help-block" ng-show="formErrors.title" role="alert" >{{ \'Ðаголовок обÑзаÑелен\' | t }}</span > </div> </div> <div class="cover-col tw:sm:w-4/12 tw:lg:w-3/12"> <div class="form-group"> <button class="big-button" type="button" ngf-select="$ctrl.uploadImage($file, 0)" ngf-drop="$ctrl.uploadImage($file, 0)" ngf-drag-over-class="\'drag-over\'" ngf-accept="\'image/*\'" ng-disabled="$ctrl.imageUploading[0]" ng-hide="contentItem.media[0].thumborId" > <p class="fa fa-paperclip fa-4x"></p> <div>{{ \'ÐагÑÑзиÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}<br />(jpeg, png, gif)</div> </button> <div class="post-image-wrapper" ng-if="contentItem.media[0].thumborId"> <button type="button" class="close" ng-click="contentItem.media[0].thumborId = null;" aria-label="{{ \'УдалиÑÑ Ð¸Ð·Ð¾Ð±Ñажение\' | t }}" > x </button> <img class="tw:block tw:max-w-full tw:h-auto thumbmail" ng-src="{{ contentItem.media[0].thumborId | imageUrl: 300 }}" alt="{{ contentItem.title || (\'ÐзобÑажение\' | t) }}" /> </div> </div> </div> </div> <div class="form-group discours-editor big tiptap-mode" ng-show="!$ctrl.isPreviewMode" ng-class="{\'has-editor-header\': $ctrl.showEditorHeader }" >
1 <div class="tiptap-loading" ng-if="!$ctrl.tiptapReady"> <div class="loading-progress-bar"> <div class="loading-progress-fill"></div> </div> <div class="tiptap-loading-skeleton"> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--60"></div> <div class="tiptap-loading-skeleton__gap"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--85"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--75"></div> </div> </div> <div ng-if="$ctrl.tiptapReady" class="tiptap-editor-container"> <div class="tiptap-editor-wrapper"> <ng-include ng-if="!$ctrl.commenterReadOnly" src="\'/pages/edit/editContentItem/partials/tiptap-toolbar.html\'" ></ng-include> <tiptap-editor ng-model="contentItem.media[0].body" placeholder="{{ \'ÐеÑÑо Ð´Ð»Ñ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑÐ¸Ñ â здеÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ ÑаÑÑказаÑÑ Ð¾ пÑоекÑе, конÑепÑии, иÑÑоÑии, ÑеÑ
нике, ÑоавÑоÑаÑ
\' | t }}" editable="true" editor-instance="$ctrl.tiptapExpoEditor" content-item="contentItem" initial-content="contentItem.media[0].body" ></tiptap-editor> </div> <div class="tiptap-bottom-bar"> <div class="bottom-bar-left"></div> <div class="bottom-bar-right" ng-show="$ctrl.expoAutosaveStatus" aria-live="polite"> <span class="expo-autosave-indicator expo-autosave-indicator--{{ $ctrl.expoAutosaveStatus }}" > <i ng-if="$ctrl.expoAutosaveStatus === \'saving\'" class="fas fa-circle-notch fa-spin" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'saved\'" class="fas fa-check" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'error\'" class="fas fa-exclamation-triangle" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'retrying\'" class="fas fa-sync fa-spin" aria-hidden="true" ></i> <span ng-if="$ctrl.expoAutosaveStatus === \'saving\'">{{ \'СоÑ
Ñанение...\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'saved\'">{{ \'СоÑ
Ñанено\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'error\'">{{ \'ÐÑибка ÑоÑ
ÑанениÑ\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'retrying\'">{{ \'ÐовÑоÑ...\' | t }}</span> </span> </div> </div> </div> </div>'),s.put("/pages/edit/editContentItem/types/ImageAlbum.html",'<ng-include src="\'/pages/edit/editContentItem/partials/expo-preview.html\'" ng-if="$ctrl.isPreviewMode" ></ng-include> <editor-header ng-if="$ctrl.showEditorHeader" doc-title="contentItem.title" slug="contentItem.slug" content-status="contentItem.status" content-link="contentItem.link" tiptap-editor="$ctrl.tiptapExpoEditor" is-preview-mode="$ctrl.isPreviewMode" is-saving="$ctrl.isSaving" is-publishing="$ctrl.isPublishing" is-save-error="$ctrl.isSaveError" has-unsaved-changes="$ctrl.hasUnsavedChanges" has-draft="$ctrl.hasDraft" can-edit="$ctrl.canEdit === true" on-mode-change="$ctrl.onEditorModeChange(mode)" on-save="contentItem.slug ? $ctrl.saveAndCreateVersion() : $ctrl.saveDraft()" on-save-version-dialog="$ctrl.openVersionNameDialog()" on-versions-click="$ctrl.toggleVersions()" is-saving-version="$ctrl.savingVersion" is-save-success="$ctrl.saveSuccess" last-version-saved-at="$ctrl.lastVersionSavedAt" on-publish="$ctrl.sendFormForPublish()" is-admin="$ctrl.isAdmin" on-open-settings="$ctrl.openPublishSettings()" on-run-typographer="$ctrl.applyTypography()" on-clean-code="$ctrl.cleanHtmlContent()" word-count="$ctrl.wordCount" char-count="$ctrl.charCount" initial-para-count="$ctrl.paraCount" is-logged-in="$ctrl.isLoggedIn" user-avatar="$ctrl.userAvatarId" user-path="$ctrl.userPathSlug" night-mode="$ctrl.darkMode" on-toggle-night-mode="$ctrl.toggleDarkMode()" ></editor-header> <div ng-hide="$ctrl.isPreviewMode"> <div> <div class="form-group tw:font-bold title" ng-class="{\'has-error\': formErrors.title}"> <textarea class="ds-input big-textarea placeholder-big" placeholder="{{ \'Ðазвание алÑбома\' | t }}" ng-model="contentItem.title" ng-change="formErrors.title = false" maxlength="120" textarea-limit-rows="textarea-limit-rows" rows="3" aria-label="{{ \'Ðазвание ÑоÑоалÑбома\' | t }}" aria-invalid="{{ !!formErrors.title }}" aria-describedby="form-error-title" ></textarea> <span id="form-error-title" class="help-block" ng-show="formErrors.title" role="alert" >{{ \'Ðаголовок обÑзаÑелен\' | t }}</span > </div> </div> </div> <div class="media-row tw:flex tw:flex-wrap tw:mt-section" ng-repeat="mediaItem in contentItem.media track by $index" ng-if="!$
1ctrl.isPreviewMode" > <div class="media-thumb-col tw:sm:w-4/12 tw:lg:w-3/12"> <div class="form-group tw:relative media-item-actions"> <button class="big-button" type="button" ngf-select="$ctrl.uploadImage($file, $index)" ngf-drop="$ctrl.uploadImage($file, $index)" ngf-drag-over-class="\'drag-over\'" ngf-accept="\'image/*\'" ng-disabled="$ctrl.imageUploading[$index]" ng-hide="mediaItem.thumborId" > <p class="fa fa-paperclip fa-4x"></p> <div>{{ \'ÐагÑÑзиÑÑ Ð¸Ð·Ð¾Ð±Ñажение\' | t }}<br />(jpeg, png, gif)</div> <span class="fas fa-sync-alt fa-spin floating-text left" ng-show="$ctrl.imageUploading[$index]" ></span> </button> <img class="tw:block tw:max-w-full tw:h-auto thumbmail" ng-src="{{ mediaItem.thumborId | imageUrl: 300 }}" ng-show="mediaItem.thumborId" alt="{{ (contentItem.title || (\'ÐзобÑажение\' | t)) + \', \' + ($index + 1) + \' / \' + contentItem.media.length }}" /> <button class="close" type="button" aria-label="{{ \'УдалиÑÑ Ð¸Ð·Ð¾Ð±Ñажение\' | t }}" ng-click="$ctrl.deleteMediaItem($index);" ng-if="contentItem.media.length > 1" ng-hide="mediaItem.thumborId" > <span aria-hidden="true"><i class="fas fa-times"></i></span> </button> <button class="close white-bg" type="button" aria-label="{{ \'УдалиÑÑ Ð¸Ð·Ð¾Ð±Ñажение\' | t }}" ng-click="mediaItem.thumborId = null;" ng-show="mediaItem.thumborId" > <span aria-hidden="true"><i class="fas fa-times"></i></span> </button> </div> <div class="tw:mt-section"></div> <div class="form-group"> <button class="ds-btn-border" type="button" ng-click="$ctrl.makeAlbumItemActive($index)" ng-class="{ active: mediaItem.main }" > <span ng-if="!mediaItem.main">{{ \'вÑбÑаÑÑ Ð² каÑеÑÑве обложки\' | t }}</span ><span ng-if="mediaItem.main">{{ \'вÑбÑано в каÑеÑÑве обложки\' | t }}</span> </button> </div> <div class="form-group" ng-if="$index === 0 && $ctrl.isAdmin && contentItem.media.length > 1"> <button class="ds-btn-border" type="button" ng-click="$ctrl.duplicateFirstMediaToAll()"> {{ \'ÐÑблиÑоваÑÑ Ð¾Ð¿Ð¸Ñание Ð´Ð»Ñ Ð²ÑеÑ
изобÑажений\' | t }} </button> </div> <div class="form-group media-reorder-buttons" ng-if="contentItem.media.length > 1"> <button class="ds-btn-border media-move-btn" type="button" ng-click="$ctrl.moveMediaItemUp($index)" ng-disabled="$index === 0" title="{{ \'ÐеÑемеÑÑиÑÑ Ð²Ð²ÐµÑÑ
\' | t }}" > <i class="fas fa-arrow-up"></i> </button> <button class="ds-btn-border media-move-btn" type="button" ng-click="$ctrl.moveMediaItemDown($index)" ng-disabled="$index === contentItem.media.length - 1" title="{{ \'ÐеÑемеÑÑиÑÑ Ð²Ð½Ð¸Ð·\' | t }}" > <i class="fas fa-arrow-down"></i> </button> </div> </div> <div class="media-content-col tw:sm:w-8/12 tw:lg:w-9/12"> <div class="form-group tw:font-bold"> <textarea class="ds-input big-textarea placeholder-big auto-grow-title" placeholder="{{ \'Ðазвание ÑабоÑÑ\' | t }}" ng-model="mediaItem.title" rows="1" maxlength="140" msd-elastic aria-label="{{ \'Ðазвание ÑабоÑÑ Ð² алÑбоме\' | t }}" ></textarea> </div> <div class="form-group discours-editor big tiptap-mode album-item-tiptap" ng-show="!$ctrl.isPreviewMode" ng-class="{\'has-editor-header\': $index === 0 && $ctrl.showEditorHeader }" > <tiptap-simple-editor ng-model="mediaItem.body" preset="album" placeholder="{{ \'ÐеÑÑо Ð´Ð»Ñ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑÐ¸Ñ â здеÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ ÑаÑÑказаÑÑ Ð¾ пÑоекÑе, конÑепÑии, ÑеÑ
нике и иÑÑоÑии ÑозданиÑ...\' | t }}" ></tiptap-simple-editor> <div class="tiptap-bottom-bar"> <div class="bottom-bar-left"></div> <div class="bottom-bar-right" ng-show="$ctrl.expoAutosaveStatus" aria-live="polite"> <span class="expo-autosave-indicator expo-autosave-indicator--{{ $ctrl.expoAutosaveStatus }}" > <i ng-if="$ctrl.expoAutosaveStatus === \'saving\'" class="fas fa-circle-notch fa-spin" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'saved\'" class="fas fa-check" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'error\'" class="fas fa-exclamation-triangle" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'retrying\'" class="fas fa-sync fa-spin" aria-hidden="true" ></i> <span ng-if="$ctrl.expoAutosaveStatus === \'saving\'">{{ \'СоÑ
Ñанение...\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'saved\'">{{ \'СоÑ
Ñанено\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'error\'">{{ \'ÐÑибка ÑоÑ
ÑанениÑ\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'retrying\'">{{ \'ÐовÑоÑ...\' | t }}</span> </span> </div> </div> </div> </div> </div>
1 <div class="tw:flex tw:flex-wrap tw:mb-section-lg" ng-if="!$ctrl.isPreviewMode"> <div class="tw:sm:w-4/12 tw:lg:w-3/12 discours-form"> <button class="ds-btn-border add-image-button" ng-click="contentItem.media.push({})" type="button" > <i class="fas fa-plus"></i>{{ \'добавиÑÑ Ð¸Ð·Ð¾Ð±Ñажение\' | t }} </button> </div> </div>'),s.put("/pages/edit/editContentItem/types/Literature.html",'<div class="title-input-row tw:flex tw:flex-wrap" ng-hide="$ctrl.isPreviewMode"> <div class="title-col tw:sm:w-8/12 tw:lg:w-9/12"> <div class="form-group tw:font-bold title" ng-class="{\'has-error\': formErrors.title}"> <textarea class="ds-input big-textarea placeholder-big" placeholder="{{ \'Ðаголовок\' | t }}" ng-model="contentItem.title" ng-change="formErrors.title = false" maxlength="120" textarea-limit-rows="textarea-limit-rows" aria-label="{{ \'Ðаголовок лиÑеÑаÑÑÑного маÑеÑиала\' | t }}" rows="1" msd-elastic aria-invalid="{{ !!formErrors.title }}" aria-describedby="form-error-title" ></textarea> <span id="form-error-title" class="help-block" ng-show="formErrors.title" role="alert" >{{ \'Ðаголовок обÑзаÑелен\' | t }}</span > </div> </div> <div class="cover-col tw:sm:w-4/12 tw:lg:w-3/12"> <div class="form-group"> <button class="big-button" type="button" ngf-select="$ctrl.uploadImage($file)" ngf-drop="$ctrl.uploadImage($file)" ngf-drag-over-class="\'drag-over\'" ngf-accept="\'image/*\'" ng-disabled="$ctrl.imageUploading[\'root\']" ng-hide="contentItem.thumborId" > <p class="fa fa-paperclip fa-4x"></p> <div>{{ \'ÐагÑÑзиÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}<br />(jpeg, png, gif)</div> <span class="fas fa-sync-alt fa-spin floating-text left" ng-show="$ctrl.imageUploading[\'root\']" ></span> </button> <div class="post-image-wrapper" ng-if="contentItem.thumborId"> <div class="cover-actions cover-actions--desktop"> <button type="button" class="cover-action-btn" ng-click="$ctrl.cropCoverImage()" ng-disabled="$ctrl.cropUploading" aria-label="{{ \'ÐадÑиÑоваÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'ÐадÑиÑоваÑÑ\' | t }}" > <i class="fas fa-crop-alt" aria-hidden="true"></i> </button> <button type="button" class="cover-action-btn" ngf-select="$ctrl.uploadImage($file)" ngf-accept="\'image/*\'" ng-disabled="$ctrl.cropUploading || $ctrl.imageUploading[\'root\']" aria-label="{{ \'ÐамениÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'ÐамениÑÑ\' | t }}" > <i class="fas fa-image" aria-hidden="true"></i> </button> <button type="button" class="cover-action-btn cover-action-btn--delete" ng-click="$ctrl.deleteCoverImage()" ng-disabled="$ctrl.cropUploading" aria-label="{{ \'УдалиÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'УдалиÑÑ\' | t }}" > <i class="fas fa-times" aria-hidden="true"></i> </button> </div> <ng-include src="\'/pages/edit/editContentItem/partials/cover-actions-mobile.html\'" ></ng-include> <span class="fas fa-sync-alt fa-spin crop-upload-spinner" ng-show="$ctrl.cropUploading" ></span> <img class="tw:block tw:max-w-full tw:h-auto thumbmail" ng-class="{\'is-uploading\': $ctrl.cropUploading }" ng-src="{{ contentItem.thumborId | imageUrl: 300 }}" ng-click="$ctrl.cropCoverImage()" alt="{{ contentItem.imageCaption || (\'Ðбложка:\' | t) + \' \' + (contentItem.title || (\'маÑеÑиал\' | t)) + \' \' + (\'â ÐиÑкÑÑÑ\' | t) }}" /> </div> <div class="image-caption-input"> <input type="text" name="imageCaption" placeholder="{{ \'ÐодпиÑÑ Ð¸Ð·Ð¾Ð±ÑажениÑ\' | t }}" class="material-style" ng-model="contentItem.imageCaption" /> <button type="button" class="caption-edit-icon" data-tooltip="{{ \'РедакÑиÑоваÑÑ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑ\' | t }}" ng-click="$ctrl.openImageCaptionEditor($event)" > <i class="fas fa-pencil-alt" aria-hidden="true"></i> </button> </div> </div> </div> </div> <editor-header ng-if="$ctrl.showEditorHeader" doc-title="contentItem.title" slug="contentItem.slug" content-status="contentItem.status" content-link="contentItem.link" collab-status="$ctrl.collabStatus" connected-users="$ctrl.connectedUsers" is-offline-mode="$ctrl.isOfflineMode" collab-permission-denied="$ctrl.collabPermissionDenied" is-reconnecting="$ctrl.isReconnecting" tiptap-editor="$ctrl.tiptapEditor" is-preview-mode="$ctrl.isPreviewMode" suggestion-mode="$ctrl.suggestionMode" sidebar-visible="$ctrl.sidebarVisible" pending-count="$ctrl.pendingChangesCount" collab-sync-pending="$ctrl.collabSyncPending" is-saving="$ctrl.isSaving" is-publishing="$ctrl.isPublishing" is-saving-version="$ctrl.savingVersion" is-save-success="$ctrl.saveSuccess" is-save-error="$ctrl.isSaveError" last-version-saved-at="$ctrl.lastVersionSavedAt" has-unsaved-changes="$ctrl.hasUnsavedChanges" has-draft="$ctrl.hasDraft" can-edit="$ctrl.canEdit === true" is-author="!$ctrl.contentItemCreatorId || $ctrl.userId === $ctrl.contentItemCreatorId" show-collab-control
1s="!!contentItem.slug" show-invite-button="$ctrl.canEdit === true && contentItem.slug" invite-count="$ctrl.inviteCount" on-open-invite="$ctrl.openInviteModal()" on-mode-change="$ctrl.onEditorModeChange(mode)" on-toggle-sidebar="$ctrl.toggleSidebar()" on-save="contentItem.slug ? $ctrl.saveAndCreateVersion() : $ctrl.saveDraft()" on-save-version-dialog="$ctrl.openVersionNameDialog()" on-publish="$ctrl.sendFormForPublish()" on-validate-before-publish="$ctrl.validateBeforePublish()" on-retry-connection="$ctrl.retryCollabConnection()" on-versions-click="$ctrl.toggleVersions()" night-mode="$ctrl.darkMode" on-toggle-night-mode="$ctrl.toggleDarkMode()" on-open-settings="$ctrl.openPublishSettings()" on-run-typographer="$ctrl.applyTypography()" word-count="$ctrl.wordCount" char-count="$ctrl.charCount" initial-para-count="$ctrl.paraCount" is-admin="$ctrl.isAdmin" on-clean-code="$ctrl.cleanHtmlContent()" initial-last-modified="$ctrl.initialLastModified" margin-view-mode="$ctrl.marginViewMode" on-toggle-margin-view="$ctrl.toggleMarginView()" quiet-mode="$ctrl.quietMode" on-toggle-quiet-mode="$ctrl.toggleQuietMode()" is-logged-in="$ctrl.isLoggedIn" user-avatar="$ctrl.userAvatarId" user-path="$ctrl.userPathSlug" ></editor-header> <invite-collaborators opened="$ctrl.inviteModalOpen" document-name="$ctrl.collabDocumentName" on-invites-changed="$ctrl.onInvitesChanged(invites)" ></invite-collaborators> <div class="post-preview tiptap-preview-mode lit-wrapper" ng-if="$ctrl.isPreviewMode && $ctrl.previewPost" post-images="post-images" footnote-text="footnote-text" social-text="social-text" > <div class="button-container"> <button type="button" class="preview-close-button" ng-click="$ctrl.togglePreviewMode()"> <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M17.9975 4.89363L13.1038 0L0 13.1064V18H4.89363L17.9975 4.89363ZM13.105 2.55674L15.4421 4.89383L14.4612 5.87591L12.1241 3.53882L13.105 2.55674ZM10.8453 4.81648L13.1824 7.15357L5.42174 14.9137L3.08485 12.5756L10.8453 4.81648ZM1.80725 16.1915V13.8544L4.14434 16.1915H1.80725Z" fill="currentColor" /> </svg> {{ \'ÐÑодолжиÑÑ ÑедакÑиÑоваÑÑ\' | t }} </button> </div> <div class="open-post progress expo-item"> <div class="author-category" ng-class="{\'no-author\': !$ctrl.previewPost.author }"> <span class="category" ng-if="$ctrl.previewPost.category"> <a ng-href="{{ $ctrl.previewPost.categoryLink }}" rel="noopener noreferrer" target="_blank" >{{ $ctrl.previewPost.category }}</a > </span> <span class="author" ng-if="$ctrl.previewPost.author"> <a ng-href="{{ $ctrl.previewPost.authorLink }}" rel="noopener noreferrer" target="_blank" ng-if="$ctrl.previewPost.authorLink" >{{ $ctrl.previewPost.author }}</a > <span ng-if="!$ctrl.previewPost.authorLink">{{ $ctrl.previewPost.author }}</span> </span> </div> <h1 class="title">{{ $ctrl.previewPost.title }}</h1> <div class="expo-item-title-image-wrapper" ng-if="$ctrl.previewPost.thumborId" ng-class="{\'is-image-loaded\': previewTitleImageLoaded}" > <img class="expo-item-title-image fancybox-img" fancybox-img ng-src="{{ $ctrl.previewPost.thumborId | imageUrl: 1000 }}" ng-srcset="{{ $ctrl.previewPost.thumborId | imageUrl: 720 }} 720w, {{ $ctrl.previewPost.thumborId | imageUrl: 900 }} 900w, {{ $ctrl.previewPost.thumborId | imageUrl: 1000 }} 1000w, {{ $ctrl.previewPost.thumborId | imageUrl: 1240 }} 1240w, {{ $ctrl.previewPost.thumborId | imageUrl: 1500 }} 1500w" fetchpriority="high" loading="eager" decoding="async" sizes="(min-width: 768px) 66vw, 100vw" alt="{{ $ctrl.previewPost.imageCaption ? ($ctrl.previewPost.imageCaption + \'. \' + $ctrl.previewPost.title + \' \' + (\'â ÐиÑкÑÑÑ\' | t)) : (\'Ðбложка:\' | t) + \' \' + $ctrl.previewPost.title + \' \' + (\'â ÐиÑкÑÑÑ\' | t) }}" title="{{ $ctrl.previewPost.imageCaption || ($ctrl.previewPost.title + \' \' + (\'â ÐиÑкÑÑÑ\' | t)) }}" ng-image-onload="previewTitleImageLoaded = true" /> </div> <p class="image-description" ng-if="$ctrl.previewPost.imageCaption" ng-bind-html="$ctrl.previewPost.imageCaption | trustedHtml" ></p> <div class="lit" ng-bind-html="$ctrl.previewPost.body | trustedHtml" post-links="post-links" post-images="post-images" book="book" pdf-viewer-hydrate disclaimer="{{ $ctrl.previewPost.publishedAt }}" ></div> <div class="footer-post"> <hr class="tw:mt-2.5 tw:mb-5" /> <div class="post-meta-footer"> <div class="post-meta-footer__author"> <div class="author-title" ng-if="$ctrl.previewPost.author"> <a ng-href="{{ $ctrl.previewPost.authorLink }}" rel="noopener noreferrer" target="_blank" ng-if="$ctrl.previewPost.authorLink" >{{ $ctrl.previewPost.author }}</a >
1 <span ng-if="!$ctrl.previewPost.authorLink">{{ $ctrl.previewPost.author }}</span> </div> <div class="date-time"> <span class="time" ng-if="$ctrl.previewPost.publishedAt" >{{ $ctrl.previewPost.publishedAt | amDateFormat: \'D MMMM YYYY\' }}</span ><span class="time" ng-if="!$ctrl.previewPost.publishedAt && $ctrl.previewPost.postedAt" >{{ $ctrl.previewPost.postedAt | amDateFormat: \'D MMMM YYYY\' }}</span > </div> </div> </div> <ul class="tags tw:mt-2.5" ng-if="$ctrl.previewPost.tags.length"> <li ng-repeat="tag in $ctrl.previewPost.tags track by tag.slug"> <a ng-href="/tags/{{ tag.slug }}" rel="noopener noreferrer" target="_blank" >#{{ tag.title }}</a > </li> </ul> </div> </div> <div class="button-container bottom-button" ng-if="$ctrl.showBottomEditButton"> <button type="button" class="preview-close-button bottom" ng-click="$ctrl.togglePreviewMode()"> <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M17.9975 4.89363L13.1038 0L0 13.1064V18H4.89363L17.9975 4.89363ZM13.105 2.55674L15.4421 4.89383L14.4612 5.87591L12.1241 3.53882L13.105 2.55674ZM10.8453 4.81648L13.1824 7.15357L5.42174 14.9137L3.08485 12.5756L10.8453 4.81648ZM1.80725 16.1915V13.8544L4.14434 16.1915H1.80725Z" fill="currentColor" /> </svg> {{ \'ÐÑодолжиÑÑ ÑедакÑиÑоваÑÑ\' | t }} </button> </div> </div> <div class="form-group discours-editor lit-editor big tiptap-mode" ng-show="!$ctrl.isPreviewMode" ng-class="{\'has-editor-header\': $ctrl.showEditorHeader, \'quiet-mode\': $ctrl.quietMode }" > <div class="tiptap-loading" ng-if="!$ctrl.tiptapReady || $ctrl.collabSyncPending"> <div class="loading-progress-bar"> <div class="loading-progress-fill"></div> </div> <div class="tiptap-loading-skeleton"> <div class="tiptap-loading-skeleton__line"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--90"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--75"></div> <div class="tiptap-loading-skeleton__gap"></div> <div class="tiptap-loading-skeleton__line"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--85"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--60"></div> </div> </div> <div ng-if="$ctrl.commenterReadOnly && !$ctrl.loginForReviewAvailable && $ctrl.tiptapReady" class="backup-recovery-banner anonymous-suggestions-banner" > <div class="backup-message"> <i class="fas fa-comment"></i> <span>{{ \'Режим комменÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ â вÑделиÑе ÑекÑÑ, ÑÑÐ¾Ð±Ñ Ð¾ÑÑавиÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑий.\' | t }}</span> </div> </div> <div ng-if="$ctrl.loginForReviewAvailable && $ctrl.tiptapReady" class="backup-recovery-banner anonymous-suggestions-banner" > <div class="backup-message"> <i class="fas fa-key"></i> <span>{{ \'ÐойдиÑе, ÑÑÐ¾Ð±Ñ Ð¾ÑÑавлÑÑÑ Ð¿Ñавки в Ñежиме ÑеÑензиÑованиÑ.\' | t }}</span> </div> <div class="backup-actions"> <button type="button" class="btn-restore" ng-click="$ctrl.openLoginModal()"> {{ \'ÐойÑи\' | t }} </button> </div> </div> <div ng-if="$ctrl.hasLocalBackup && contentItem.slug && !$ctrl.collabSyncPending" class="backup-recovery-banner" ng-class="{\'is-collapsed\': $ctrl.backupBannerCollapsed}" > <button type="button" ng-if="$ctrl.backupBannerCollapsed" class="backup-collapsed-indicator" ng-click="$ctrl.expandBackupBanner()" aria-label="{{ \'ÐоказаÑÑ ÑезеÑвнÑÑ ÐºÐ¾Ð¿Ð¸Ñ\' | t }}" title="{{ \'ÐоказаÑÑ ÑезеÑвнÑÑ ÐºÐ¾Ð¿Ð¸Ñ\' | t }}" > <i class="fas fa-history"></i> <span>{{ \'ÐÑÑÑ ÑезеÑÐ²Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ\' | t }}</span> </button> <div ng-if="!$ctrl.backupBannerCollapsed" class="backup-message"> <i class="fas fa-history"></i> <span >{{ \'РезеÑÐ²Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ Ð¾Ñ\' | t }} {{ $ctrl.localBackupTime | date:\'dd.MM.yyyy HH:mm\' }}. <span ng-bind="\'ÐоÑÑÑановление Ð·Ð°Ð¼ÐµÐ½Ð¸Ñ Ð²ÐµÑÑ ÑекÑÑ, в Ñом ÑиÑле пÑавки ÑоавÑоÑов. ТекÑÑий ÑекÑÑ ÑнаÑала ÑоÑ
ÑаниÑÑÑ Ð²ÐµÑÑией.\' | t" ></span ></span> </div>
1 <div ng-if="!$ctrl.backupBannerCollapsed" class="backup-actions"> <button type="button" class="btn-restore" ng-click="$ctrl.restoreFromBackup()" ng-disabled="$ctrl.restoringBackup" > <i class="fas fa-undo"></i> {{ \'ÐоÑÑÑановиÑÑ\' | t }} </button> <button type="button" class="btn-discard" ng-click="$ctrl.discardBackup()"> <i class="fas fa-times" aria-hidden="true"></i> {{ \'СоÑ
ÑаниÑÑ ÐºÐ°Ðº веÑÑиÑ\' | t }} </button> </div> </div> <div ng-if="$ctrl.tiptapReady" class="tiptap-editor-container" ng-class="{\'is-syncing\': $ctrl.collabSyncPending}" > <div class="toc-nav-container" id="toc-nav-container-literature"></div> <ng-include src="\'/pages/edit/editContentItem/partials/sidebar-side-toggle.html\'"></ng-include> <div class="tiptap-editor-wrapper"> <ng-include ng-if="!$ctrl.commenterReadOnly" src="\'/pages/edit/editContentItem/partials/tiptap-toolbar.html\'" ></ng-include> <div class="editor-with-margin-host" ng-class="{\'margin-view-active\': $ctrl.marginViewMode, \'sheet-open\': $ctrl.sidebarVisible }" > <tiptap-editor ng-model="contentItem.media[0].literatureBody" placeholder="{{ \'ТекÑÑ\' | t }}" user-id="$ctrl.userId" user-name="$ctrl.userName" user-slug="$ctrl.userSlug" user-avatar="$ctrl.userAvatar" editor-instance="$ctrl.tiptapEditor" content-item="contentItem" collab-server-url="{{ $ctrl.collabServerUrl }}" collab-document-name="$ctrl.collabDocumentName" collab-token="$ctrl.collabToken" collab-status="$ctrl.collabStatus" collab-permission-denied="$ctrl.collabPermissionDenied" is-offline-mode="$ctrl.isOfflineMode" is-reconnecting="$ctrl.isReconnecting" on-collab-synced="$ctrl.onCollabSynced()" on-collab-fallback="$ctrl.onCollabFallback(reason)" on-initial-content-ready="$ctrl.onInitialContentReady()" initial-content="$ctrl.initialContent" ></tiptap-editor> <ng-include src="\'/pages/edit/editContentItem/partials/margin-view.html\'"></ng-include> </div> <div class="tiptap-sidebar" ng-class="{ visible: $ctrl.sidebarVisible }"> <button type="button" class="sheet-drag-handle" aria-label="{{ \'ÐзмениÑÑ Ð²ÑÑоÑÑ Ð¿Ð°Ð½ÐµÐ»Ð¸\' | t }}" > <span class="sheet-drag-grip" aria-hidden="true"></span> </button> <div class="sidebar-header"> <div class="sidebar-tabs"> <button type="button" class="sidebar-tab" ng-class="{ active: $ctrl.sidebarTab === \'comments\' }" ng-click="$ctrl.sidebarTab = \'comments\'" data-collab-comments-tab > {{ \'ÐомменÑаÑии\' | t }} <span class="tab-count" ng-if="$ctrl.openCommentsCount" title="{{ \'ÐеÑеÑÑннÑе комменÑаÑии\' | t }}" >({{ $ctrl.openCommentsCount }})</span > </button> <button type="button" class="sidebar-tab" ng-class="{ active: $ctrl.sidebarTab === \'suggestions\' }" ng-click="$ctrl.sidebarTab = \'suggestions\'" > {{ \'ÐÑавки\' | t }} <span class="tab-count" ng-if="$ctrl.suggestions.length" >({{ $ctrl.suggestions.length }})</span > </button> </div> <div class="sidebar-header-actions"> <div ng-if="!$ctrl.commentsLoading && $ctrl.sidebarTab === \'comments\'" ng-include="\'/pages/edit/editContentItem/partials/comment-filter.html\'" ></div> <button type="button" class="sidebar-close" ng-click="$ctrl.toggleSidebar()" title="{{ \'ÐакÑÑÑÑ\' | t }}" > <i class="fas fa-times" aria-hidden="true"></i> </button> </div> </div> <ng-include class="sidebar-capability-notice" ng-if="$ctrl.collabCommentStoreUnavailable" src="\'/pages/edit/editContentItem/partials/collab-capability-notice.html\'" ></ng-include> <div class="sidebar-content" ng-if="$ctrl.sidebarTab === \'comments\'"> <div ng-if="$ctrl.commentsLoading" class="comments-skeleton" aria-busy="true" aria-label="{{ \'ÐагÑÑзка комменÑаÑиев\' | t }}" > <div class="comments-skeleton__item" ng-repeat="i in [1,2,3] track by $index"> <div class="comments-skeleton__author"></div> <div class="comments-skeleton__text"></div> <div class="comments-skeleton__meta"></div> </div> </div> <div class="sidebar-empty" ng-if="!$ctrl.commentsLoading && !$ctrl.comments.length && !$ctrl.collabCommentStoreUnavailable" > <i class="fas fa-comment"></i> <p>{{ \'ÐÐµÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑиев\' | t }}</p> <small>{{ \'ÐÑделиÑе ÑекÑÑ Ð¸ нажмиÑе ÐºÐ½Ð¾Ð¿ÐºÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑиÑ\' | t }}</small> </div>
1 <ng-include ng-if="!$ctrl.commentsLoading" src="\'/pages/edit/editContentItem/partials/comment-list.html\'" ></ng-include> </div> <div class="sidebar-content" ng-if="$ctrl.sidebarTab === \'suggestions\'"> <div class="sidebar-empty" ng-if="!$ctrl.suggestions.length"> <i class="fas fa-check-circle"></i> <p>{{ \'ÐÐµÑ Ð¾Ð¶Ð¸Ð´Ð°ÑÑиÑ
пÑавок\' | t }}</p> <small>{{ \'ÐклÑÑиÑе Ñежим пÑавок Ð´Ð»Ñ Ð¾ÑÑÐ»ÐµÐ¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹\' | t }}</small> </div> <div class="suggestion-list" ng-if="$ctrl.suggestions.length"> <div class="suggestion-actions-all" ng-if="$ctrl.suggestions.length > 1 && $ctrl.canModerate()" > <button type="button" class="ds-btn ds-btn-sm ds-btn-success" ng-click="$ctrl.acceptAllSuggestions()" ng-disabled="$ctrl.isSuggestionBulkActionBlocked()" > <i class="fas fa-check-double"></i> {{ \'ÐÑинÑÑÑ Ð²Ñе\' | t }} </button> <button type="button" class="ds-btn ds-btn-sm ds-btn-danger" ng-click="$ctrl.rejectAllSuggestions()" ng-disabled="$ctrl.isSuggestionBulkActionBlocked()" > <i class="fas fa-times" aria-hidden="true"></i> {{ \'ÐÑклониÑÑ Ð²Ñе\' | t }} </button> </div> <div class="suggestion-item" ng-repeat="suggestion in $ctrl.suggestions | limitTo:$ctrl.suggestionsDisplayLimit track by suggestion.suggestionId" ng-class="[suggestion.type, { expanded: suggestion.isExpanded }]" data-sidebar-suggestion-id="{{ suggestion.suggestionId }}" ng-click="$ctrl.toggleSuggestionExpand(suggestion)" role="group" ng-attr-aria-label="{{ ::(\'ÐÑавка оÑ\' | t) + \' \' + (suggestion.authorName || (\'ÐвÑоÑ\' | t)) }}" > <div class="suggestion-header"> <div class="suggestion-header-main"> <a class="suggestion-author" ng-href="/{{ suggestion.authorSlug }}" ng-if="suggestion.authorSlug" rel="noopener noreferrer" target="_blank" ng-click="$event.stopPropagation()" > <img class="author-avatar" ng-if="suggestion.authorAvatar" ng-src="{{ suggestion.authorAvatar }}" alt="" ng-on-error="$event.target.style.display=\'none\'" /> <span class="author-avatar-placeholder" ng-if="!suggestion.authorAvatar && suggestion.authorId" title="{{ suggestion.authorName || (\'ÐвÑоÑ\' | t) }}" >{{ (suggestion.authorName || (\'Ð\' | t)).charAt(0) }}</span > <div class="sidebar-author-info"> <span class="author-name">{{ suggestion.authorName || (\'ÐвÑоÑ\' | t) }}</span> <span class="sidebar-date" >{{ suggestion.createdAt | date:\'dd.MM HH:mm\' }}</span > </div> </a> <span class="suggestion-author" ng-if="!suggestion.authorSlug"> <img class="author-avatar" ng-if="suggestion.authorAvatar" ng-src="{{ suggestion.authorAvatar }}" alt="" ng-on-error="$event.target.style.display=\'none\'" /> <span class="author-avatar-placeholder" ng-if="!suggestion.authorAvatar && suggestion.authorId" title="{{ suggestion.authorName || (\'ÐвÑоÑ\' | t) }}" >{{ (suggestion.authorName || (\'Ð\' | t)).charAt(0) }}</span > <div class="sidebar-author-info"> <span class="author-name" >{{ !suggestion.authorId ? (\'Ðнонимно\' | t) : (suggestion.authorName || (\'ÐвÑоÑ\' | t)) }}</span > <span class="sidebar-date" >{{ suggestion.createdAt | date:\'dd.MM HH:mm\' }}</span > </div> </span> </div> <div class="suggestion-actions" ng-click="$event.stopPropagation()"> <button type="button" class="ds-btn-link btn-icon card-disclosure" ng-click="$ctrl.toggleSuggestionDisclosure(suggestion)" ng-attr-aria-expanded="{{ suggestion.isExpanded ? \'true\' : \'false\' }}" ng-attr-aria-controls="{{ suggestion.isExpanded ? (\'suggestion-discussion-\' + suggestion.suggestionId) : undefined }}" aria-label="{{ (suggestion.isExpanded ? \'СвеÑнÑÑÑ Ð¿ÑавкÑ\' : \'РазвеÑнÑÑÑ Ð¿ÑавкÑ\') | t }}" > <i class="fas fa-chevron-down" aria-hidden="true"></i> </button> <button type="button" class="ds-btn-link btn-icon ds-btn-success" ng-click="$ctrl.acceptSuggestion(suggestion)" ng-if="$ctrl.canModerate()" ng-disabled="$ctrl.isSuggestionActionBlocked(suggestion)" aria-label="{{ \'ÐÑинÑÑÑ Ð¿ÑавкÑ\' | t }}" > <i class="fas fa-check"></i> <span class="custom-tooltip">{{ \'ÐÑинÑÑÑ\' | t }}</span> </button> <button type="button" class="ds-btn-link btn-icon ds-btn-danger" ng-click="$ctrl.rejectSuggestion(suggestion)" ng-if="$ctrl.canModerate()" ng-disabled="$ctrl.isSuggestionActionBlocked(suggestion)" aria-label="{{ \'ÐÑклониÑÑ Ð¿ÑавкÑ\' | t }}" > <i class="fas fa-times" aria-hidden="true"></i> <span class="custom-tooltip">{{ \'ÐÑклониÑÑ\' | t }}</span> </button> </div> </div> <p class="collab-write-uncertain" ng-if="$ctrl.suggestionDiscussionNotice(suggestion) && !suggestion.isExpanded" role="status" > <i class="fas fa-exclamation-triangle" aria-hidden="true"></i> {{ $ctrl.suggestionDiscussionNotice(suggestion) }} </p> <div class="suggestion-text" ng-if="suggestion.type === \'node-add\' || suggestion.type === \'node-delete\' || suggestion.type === \'node-update\'" > <strong class="suggestion-action-label" ng-if="suggestion.type === \'node-add\'" >{{ \'ÐобавиÑÑ:\' | t }}</strong > <strong class="suggestion-action-label" ng-if="suggestion.type === \'node-delete\'" >{{ \'УдалиÑÑ:\' | t }}</strong > <strong class="suggestion-action-label" ng-if="suggestion.type === \'node-update\'" >{{ \'ÐзмениÑÑ:\' | t }}</strong > <span class="text-format">{{ suggestion.nodeDescription }}</span> <div class="suggestion-update-changes" ng-if="suggestion.updateChanges.length"> <div class="suggestion-update-change" ng-repeat="change in suggestion.updateChanges track by change.key" > <span class="suggestion-update-label">{{ change.label }}</span> <span class="text-delete" ng-if="change.before" >{{ change.before | limitTo:100 }}<span ng-if="change.before.length > 100" >â¦</span ></span > <span class="text-delete suggestion-update-empty" ng-if="!change.before" >{{ \'пÑÑÑо\' | t }}</span > <span class="text-replace-arrow">â</span> <span class="text-add" ng-if="change.after" >{{ change.after | limitTo:100 }}<span ng-if="change.after.length > 100" >â¦</span ></span > <span class="text-add suggestion-update-empty" ng-if="!change.after" >{{ \'пÑÑÑо\' | t }}</span > </div> </div> </div> <div class="suggestion-text" ng-if="suggestion.type === \'replace\'"> <strong class="suggestion-action-label">{{ \'ÐамениÑÑ:\' | t }}</strong> <div class="suggestion-replace-block"> <span class="text-delete" >{{ suggestion.deleteText | limitTo:100 }}<span ng-if="suggestion.deleteText.length > 100" >â¦</span ></span > <span class="text-replace-arrow">â</span> <span class="text-add" >{{ suggestion.addText | limitTo:100 }}<span ng-if="suggestion.addText.length > 100" >â¦</span ></span > </div> </div> <div class="suggestion-text" ng-if="suggestion.type === \'add\' || suggestion.type === \'delete\' || suggestion.type === \'format\'" > <strong class="suggestion-action-label" ng-if="suggestion.type === \'add\'" >{{ \'ÐобавиÑÑ:\' | t }}</strong > <strong class="suggestion-action-label" ng-if="suggestion.type === \'delete\'" >{{ \'УдалиÑÑ:\' | t }}</strong > <strong class="suggestion-action-label" ng-if="suggestion.type === \'format\'" >{{ \'ФоÑмаÑ:\' | t }}</strong > <span ng-if="suggestion.type === \'add\'" class="text-add" >{{ suggestion.text | limitTo:100 }}<span ng-if="suggestion.text.length > 100" >â¦</span ></span > <span ng-if="suggestion.type === \'delete\'" class="text-delete" >{{ suggestion.text | limitTo:100 }}<span ng-if="suggestion.text.length > 100" >â¦</span ></span > <span ng-if="suggestion.type === \'format\'" class="text-format" >{{ suggestion.formatDescription }}</span > </div> <div class="replies-count-hint" ng-if="!suggestion.isExpanded && $ctrl.suggestionThreads[suggestion.suggestionId] && $ctrl.suggestionThreads[suggestion.suggestionId].length" ng-click="$event.stopPropagation(); $ctrl.toggleSuggestionExpand(suggestion)" > <i class="fas fa-reply" aria-hidden="true"></i> <span >{{ $ctrl.suggestionThreads[suggestion.suggestionId].length | pluralize:\'оÑвеÑ\':\'оÑвеÑа\':\'оÑвеÑов\' }}</span > </div> <div id="suggestion-discussion-{{ ::suggestion.suggestionId }}" ng-if="suggestion.isExpanded" ng-click="$event.stopPropagation()" > <ng-include src="\'/pages/edit/editContentItem/partials/suggestion-replies.html\'" ></ng-include> </div> </div>
1 <button type="button" class="sidebar-show-more" ng-if="$ctrl.suggestions.length > $ctrl.suggestionsDisplayLimit" ng-click="$ctrl.showMoreSuggestions()" > {{ \'ÐоказаÑÑ ÐµÑÑ\' | t }} {{ $ctrl.suggestions.length - $ctrl.suggestionsDisplayLimit }} </button> </div> </div> </div> </div> <div class="tiptap-bottom-bar"> <div class="bottom-bar-left"></div> <div class="bottom-bar-right bottom-bar-save-status" aria-live="polite"> <span ng-show="$ctrl.isSaving" class="save-status save-status--saving"> <i class="fas fa-circle-notch fa-spin" aria-hidden="true"></i> {{ \'СоÑ
Ñанениеâ¦\' | t }} </span> <span ng-show="!$ctrl.isSaving && $ctrl.saveSuccess" class="save-status save-status--saved"> <i class="fas fa-check" aria-hidden="true"></i> {{ \'СоÑ
Ñанено\' | t }} </span> <span ng-show="!$ctrl.isSaving && !$ctrl.saveSuccess && $ctrl.hasUnsavedChanges" class="save-status save-status--unsaved" > {{ \'Ðе ÑоÑ
Ñанено\' | t }} </span> </div> </div> </div> </div>'),s.put("/pages/edit/editContentItem/types/Music.html",'<ng-include src="\'/pages/edit/editContentItem/partials/expo-preview.html\'" ng-if="$ctrl.isPreviewMode" ></ng-include> <editor-header ng-if="$ctrl.showEditorHeader" doc-title="contentItem.title" slug="contentItem.slug" content-status="contentItem.status" content-link="contentItem.link" tiptap-editor="$ctrl.tiptapExpoEditor" is-preview-mode="$ctrl.isPreviewMode" is-saving="$ctrl.isSaving" is-publishing="$ctrl.isPublishing" is-save-error="$ctrl.isSaveError" has-unsaved-changes="$ctrl.hasUnsavedChanges" has-draft="$ctrl.hasDraft" can-edit="$ctrl.canEdit === true" on-mode-change="$ctrl.onEditorModeChange(mode)" on-save="contentItem.slug ? $ctrl.saveAndCreateVersion() : $ctrl.saveDraft()" on-save-version-dialog="$ctrl.openVersionNameDialog()" on-versions-click="$ctrl.toggleVersions()" is-saving-version="$ctrl.savingVersion" is-save-success="$ctrl.saveSuccess" last-version-saved-at="$ctrl.lastVersionSavedAt" on-publish="$ctrl.sendFormForPublish()" is-admin="$ctrl.isAdmin" on-open-settings="$ctrl.openPublishSettings()" on-run-typographer="$ctrl.applyTypography()" on-clean-code="$ctrl.cleanHtmlContent()" word-count="$ctrl.wordCount" char-count="$ctrl.charCount" initial-para-count="$ctrl.paraCount" is-logged-in="$ctrl.isLoggedIn" user-avatar="$ctrl.userAvatarId" user-path="$ctrl.userPathSlug" night-mode="$ctrl.darkMode" on-toggle-night-mode="$ctrl.toggleDarkMode()" ></editor-header> <div class="title-input-row tw:flex tw:flex-wrap" ng-hide="$ctrl.isPreviewMode"> <div class="title-col tw:sm:w-8/12 tw:lg:w-9/12"> <div class="form-group tw:font-bold title" ng-class="{\'has-error\': formErrors.title}"> <textarea class="ds-input big-textarea placeholder-big" placeholder="{{ \'Ðазвание композиÑии\' | t }}" ng-model="contentItem.title" ng-change="formErrors.title = false" maxlength="120" textarea-limit-rows="textarea-limit-rows" aria-label="{{ \'Ðазвание композиÑии\' | t }}" rows="1" msd-elastic aria-invalid="{{ !!formErrors.title }}" aria-describedby="form-error-title" ></textarea> <span id="form-error-title" class="help-block" ng-show="formErrors.title" role="alert" >{{ \'Ðаголовок обÑзаÑелен\' | t }}</span > </div> <div class="form-group"> <input class="ds-input" ng-model="contentItem.media[0].performer" placeholder="{{ \'ÐÐ¼Ñ Ð¸ÑполниÑелÑ\' | t }}" /> </div> </div> <div class="cover-col tw:sm:w-4/12 tw:lg:w-3/12"> <div class="form-group"> <button class="big-button thin" type="button" ngf-select="$ctrl.uploadImage($file)" ngf-drop="$ctrl.uploadImage($file)" ngf-drag-over-class="\'drag-over\'" ngf-accept="\'image/*\'" ng-disabled="$ctrl.imageUploading[\'root\']" ng-hide="contentItem.thumborId" > <img src="/images/icons/attach.png" alt="{{ \'ÐагÑÑзиÑÑ\' | t }}" /><span >{{ \'ÐобавиÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}</span ><span class="fas fa-sync-alt fa-spin floating-text left" ng-show="$ctrl.imageUploading[\'root\']" ></span ><span class="floating-text">*jpeg, png, gif</span> </button> <div class="post-image-wrapper" ng-if="contentItem.thumborId"> <div class="cover-actions cover-actions--desktop"> <button type="button" class="cover-action-btn" ng-click="$ctrl.cropCoverImage()" ng-disabled="$ctrl.cropUploading" aria-label="{{ \'ÐадÑиÑоваÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'ÐадÑиÑоваÑÑ\' | t }}" > <i class="fas fa-crop-alt" aria-hidden="true"></i> </button> <button type="button" class="cover-action-btn" ngf-select="$ctrl.uploadImage($file)" ngf-accept="\'image/*\'" ng-disabled="$ctrl.cropUploading || $ctrl.imageUploading[\'root\']" aria-label="{{ \'ÐамениÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'ÐамениÑÑ\' | t }}" > <i class="fas fa-image" aria-hidden="true"></i> </button> <button type="button" class="cover-action-btn cover-action-btn--delete" ng-click="$ctrl.deleteCoverImage()" ng-disabled="$ctrl.cropUploading" aria-label="{{ \'УдалиÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'УдалиÑÑ\' | t }}" > <i class="fas fa-times" aria-hidden="true"></i> </button> </div> <ng-include src="\'/pages/edit/editContentItem/partials/cover-actions-mobile.html\'" ></ng-include> <span class="fas fa-sync-alt fa-spin crop-upload-spinner" ng-show="$ctrl.cropUploading" ></span> <img class="tw:block tw:max-w-full tw:h-auto thumbmail" ng-class="{\'is-uploading\': $ctrl.cropUploading }" ng-src="{{ contentItem.thumborId | imageUrl: 300 }}" ng-click="$ctrl.cropCoverImage()" alt="{{ (\'Ðбложка:\' | t) + \' \' + (contentItem.title || (\'композиÑиÑ\' | t)) + \' â ÐиÑкÑÑÑ\' }}" /> </div> </div> </div> <div class="music-upload-col tw:sm:w-4/12 tw:lg:w-3/12"> <div class="form-group">
1 <button class="big-button thin small" type="button" ngf-select="$ctrl.uploadMusic($file, 0)" ng-disabled="$ctrl.musicUploading[0]" ng-hide="contentItem.media[0].fileUrl" accept="audio/*" > <img src="/images/icons/attach.png" alt="{{ \'ÐагÑÑзиÑÑ\' | t }}" /><span >{{ \'ÐагÑÑзиÑÑ ÐºÐ¾Ð¼Ð¿Ð¾Ð·Ð¸ÑиÑ\' | t }}</span ><span class="fas fa-sync-alt fa-spin floating-text left" ng-show="$ctrl.musicUploading[0]" ></span ><span class="floating-text">*mp3, wav, m4a, ogg, flac</span> </button> <div ng-show="contentItem.media[0].fileName"> <p>{{ \'ÐÐ¼Ñ Ñайла:\' | t }}</p> <p> {{ contentItem.media[0].fileName }}<i class="fas fa-times tw:cursor-pointer" ng-click="contentItem.media[0].fileName = null; contentItem.media[0].fileUrl = null;" ></i> </p> </div> </div> </div> </div> <div class="form-group discours-editor big tiptap-mode" ng-show="!$ctrl.isPreviewMode" ng-class="{\'has-editor-header\': $ctrl.showEditorHeader }" > <div class="tiptap-loading" ng-if="!$ctrl.tiptapReady"> <div class="loading-progress-bar"> <div class="loading-progress-fill"></div> </div> <div class="tiptap-loading-skeleton"> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--60"></div> <div class="tiptap-loading-skeleton__gap"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--85"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--75"></div> </div> </div> <div ng-if="$ctrl.tiptapReady" class="tiptap-editor-container"> <div class="tiptap-editor-wrapper"> <ng-include ng-if="!$ctrl.commenterReadOnly" src="\'/pages/edit/editContentItem/partials/tiptap-toolbar.html\'" ></ng-include> <tiptap-editor ng-model="contentItem.body" placeholder="{{ \'ТекÑÑ\' | t }}" editable="true" editor-instance="$ctrl.tiptapExpoEditor" content-item="contentItem" initial-content="contentItem.body" ></tiptap-editor> </div> <div class="tiptap-bottom-bar"> <div class="bottom-bar-left"></div> <div class="bottom-bar-right" ng-show="$ctrl.expoAutosaveStatus" aria-live="polite"> <span class="expo-autosave-indicator expo-autosave-indicator--{{ $ctrl.expoAutosaveStatus }}" > <i ng-if="$ctrl.expoAutosaveStatus === \'saving\'" class="fas fa-circle-notch fa-spin" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'saved\'" class="fas fa-check" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'error\'" class="fas fa-exclamation-triangle" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'retrying\'" class="fas fa-sync fa-spin" aria-hidden="true" ></i> <span ng-if="$ctrl.expoAutosaveStatus === \'saving\'">{{ \'СоÑ
Ñанение...\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'saved\'">{{ \'СоÑ
Ñанено\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'error\'">{{ \'ÐÑибка ÑоÑ
ÑанениÑ\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'retrying\'">{{ \'ÐовÑоÑ...\' | t }}</span> </span> </div> </div> </div> </div>'),s.put("/pages/edit/editContentItem/types/MusicAlbum.html",'<ng-include src="\'/pages/edit/editContentItem/partials/expo-preview.html\'" ng-if="$ctrl.isPreviewMode" ></ng-include> <editor-header ng-if="$ctrl.showEditorHeader" doc-title="contentItem.title" slug="contentItem.slug" content-status="contentItem.status" content-link="contentItem.link" tiptap-editor="$ctrl.tiptapExpoEditor" is-preview-mode="$ctrl.isPreviewMode" is-saving="$ctrl.isSaving" is-publishing="$ctrl.isPublishing" is-save-error="$ctrl.isSaveError" has-unsaved-changes="$ctrl.hasUnsavedChanges" has-draft="$ctrl.hasDraft" can-edit="$ctrl.canEdit === true" on-mode-change="$ctrl.onEditorModeChange(mode)" on-save="contentItem.slug ? $ctrl.saveAndCreateVersion() : $ctrl.saveDraft()" on-save-version-dialog="$ctrl.openVersionNameDialog()" on-versions-click="$ctrl.toggleVersions()" is-saving-version="$ctrl.savingVersion" is-save-success="$ctrl.saveSuccess" last-version-saved-at="$ctrl.lastVersionSavedAt" on-publish="$ctrl.sendFormForPublish()" is-admin="$ctrl.isAdmin" on-open-settings="$ctrl.openPublishSettings()" on-run-typographer="$ctrl.applyTypography()" on-clean-code="$ctrl.cleanHtmlContent()" word-count="$ctrl.wordCount" char-count="$ctrl.charCount" initial-para-count="$ctrl.paraCount" is-logged-in="$ctrl.isLoggedIn" user-avatar="$ctrl.userAvatarId" user-path="$ctrl.userPathSlug" night-mode="$ctrl.darkMode" on-toggle-night-mode="$ctrl.toggleDarkMode()" ></editor-header> <div class="title-input-row tw:flex tw:flex-wrap" ng-hide="$ctrl.isPreviewMode"> <div class="title-col tw:sm:w-8/12 tw:lg:w-9/12"> <div class="form-group tw:font-bold title" ng-class="{\'has-error\': formErrors.title}"> <textarea class="ds-input big-textarea placeholder-big" placeholder="{{ \'Ðазвание алÑбома\' | t }}" ng-model="contentItem.title" ng-change="formErrors.title = false" maxlength="120" textarea-limit-rows="textarea-limit-rows" aria-label="{{ \'Ðазвание мÑзÑкалÑного алÑбома\' | t }}" rows="1" msd-elastic aria-invalid="{{ !!formErrors.title }}" aria-describedby="form-error-title" ></textarea> <span id="form-error-title" class="help-block" ng-show="formErrors.title" role="alert" >{{ \'Ðаголовок обÑзаÑелен\' | t }}</span > </div> </div> <div class="cover-col tw:sm:w-4/12 tw:lg:w-3/12"> <div class="form-group"> <button class="big-button" type="button" ngf-select="$ctrl.uploadImage($file)" ngf-drop="$ctrl.uploadImage($file)" ngf-drag-over-class="\'drag-over\'" ngf-accept="\'image/*\'" ng-disabled="$ctrl.imageUploading[\'root\']" ng-hide="contentItem.thumborId" > <p class="fa fa-paperclip fa-4x"></p> <div>{{ \'ÐагÑÑзиÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}<br />(jpeg, png, gif)</div> <span class="fas fa-sync-alt fa-spin floating-text left" ng-show="$ctrl.imageUploading[\'root\']" ></span> </button> <div class="post-image-wrapper" ng-if="contentItem.thumborId"> <div class="cover-actions cover-actions--desktop"> <button type="button" class="cover-action-btn" ng-click="$ctrl.cropCoverImage()" ng-disabled="$ctrl.cropUploading" aria-label="{{ \'ÐадÑиÑоваÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'ÐадÑиÑоваÑÑ\' | t }}" > <i class="fas fa-crop-alt" aria-hidden="true"></i> </button> <button type="button" class="cover-action-btn" ngf-select="$ctrl.uploadImage($file)" ngf-accept="\'image/*\'" ng-disabled="$ctrl.cropUploading || $ctrl.imageUploading[\'root\']" aria-label="{{ \'ÐамениÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'ÐамениÑÑ\' | t }}" > <i class="fas fa-image" aria-hidden="true"></i> </button> <button type="button" class="cover-action-btn cover-action-btn--delete" ng-click="$ctrl.deleteCoverImage()" ng-disabled="$ctrl.cropUploading" aria-label="{{ \'УдалиÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'УдалиÑÑ\' | t }}" > <i class="fas fa-times" aria-hidden="true"></i> </button> </div> <ng-include src="\'/pages/edit/editContentItem/partials/cover-actions-mobile.html\'" ></ng-include> <span class="fas fa-sync-alt fa-spin crop-upload-spinner" ng-show="$ctrl.cropUploading" ></span> <img class="tw:block tw:max-w-full tw:h-auto thumbmail" ng-class="{\'is-uploading\': $ctrl.cropUploading }" ng-src="{{ contentItem.thumborId | imageUrl: 300 }}" ng-click="$ctrl.cropCoverImage()" alt="{{ (\'Ðбложка:\' | t) + \' \' + (contentItem.title || (\'алÑбом\' | t)) + \' â ÐиÑкÑÑÑ\' }}" /> </div> </div> </div> </div> <div> <div class="form-group discours-editor big tiptap-mode" ng-show="!$ctrl.isPreviewMode" ng-class="{\'has-editor-header\': $ctrl.showEditorHeader }" >
1 <div class="tiptap-loading" ng-if="!$ctrl.tiptapReady"> <div class="loading-progress-bar"> <div class="loading-progress-fill"></div> </div> <div class="tiptap-loading-skeleton"> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--60"></div> <div class="tiptap-loading-skeleton__gap"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--85"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--75"></div> </div> </div> <div ng-if="$ctrl.tiptapReady" class="tiptap-editor-container"> <div class="tiptap-editor-wrapper"> <ng-include ng-if="!$ctrl.commenterReadOnly" src="\'/pages/edit/editContentItem/partials/tiptap-toolbar.html\'" ></ng-include> <tiptap-editor ng-model="contentItem.body" placeholder="{{ \'ТекÑÑ\' | t }}" editable="true" editor-instance="$ctrl.tiptapExpoEditor" content-item="contentItem" initial-content="contentItem.body" ></tiptap-editor> </div> <div class="tiptap-bottom-bar"> <div class="bottom-bar-left"></div> <div class="bottom-bar-right" ng-show="$ctrl.expoAutosaveStatus" aria-live="polite"> <span class="expo-autosave-indicator expo-autosave-indicator--{{ $ctrl.expoAutosaveStatus }}" > <i ng-if="$ctrl.expoAutosaveStatus === \'saving\'" class="fas fa-circle-notch fa-spin" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'saved\'" class="fas fa-check" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'error\'" class="fas fa-exclamation-triangle" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'retrying\'" class="fas fa-sync fa-spin" aria-hidden="true" ></i> <span ng-if="$ctrl.expoAutosaveStatus === \'saving\'">{{ \'СоÑ
Ñанение...\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'saved\'">{{ \'СоÑ
Ñанено\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'error\'">{{ \'ÐÑибка ÑоÑ
ÑанениÑ\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'retrying\'">{{ \'ÐовÑоÑ...\' | t }}</span> </span> </div> </div> </div> </div> <div class="media-row tw:flex tw:flex-wrap tw:mt-section" ng-repeat="mediaItem in contentItem.media track by $index" > <div class="media-thumb-col tw:sm:w-5/12 tw:lg:w-3/12"> <div class="form-group tw:relative media-item-actions"> <p> <b>{{ \'ТÑек\' | t }} {{ \'#\' }}{{ $index + 1 }}</b> </p>
1 <button class="big-button thin small" type="button" ngf-select="$ctrl.uploadMusic($file, $index)" ng-disabled="$ctrl.musicUploading[$index]" ng-hide="mediaItem.fileUrl" accept="audio/*" > <p class="fa fa-paperclip fa-2x"></p> <div>{{ \'ÐагÑÑзиÑÑ ÐºÐ¾Ð¼Ð¿Ð¾Ð·Ð¸ÑиÑ\' | t }}<br />(mp3, wav, m4a, ogg, flac)</div> <span class="fas fa-sync-alt fa-spin floating-text left" ng-show="$ctrl.musicUploading[$index]" ></span> </button> <div ng-show="mediaItem.fileUrl"> <p>{{ \'ÐÐ¼Ñ Ñайла:\' | t }}</p> <p> {{ mediaItem.fileName }}<i class="fas fa-times tw:cursor-pointer" ng-click="contentItem.media.splice($index, 1)" ></i> </p> </div> </div> </div> <div class="media-content-col tw:sm:w-7/12 tw:lg:w-9/12 tw:mt-10"> <div class="form-group"> <p> <input class="ds-input" placeholder="{{ \'Ðазвание запиÑи\' | t }}" ng-model="mediaItem.title" required="required" maxlength="120" /> </p> <input class="ds-input" ng-model="mediaItem.performer" placeholder="{{ \'ÐÑполниÑелÑ\' | t }}" /> </div> </div> </div> <div class="tw:flex tw:flex-wrap tw:mb-section-lg"> <div class="tw:sm:w-5/12 tw:lg:w-3/12 discours-form"> <button class="ds-btn-border add-image-button" ng-click="contentItem.media.push({})" type="button" > <i class="fas fa-plus"></i>{{ \'добавиÑÑ ÐºÐ¾Ð¼Ð¿Ð¾Ð·Ð¸ÑиÑ\' | t }} </button> </div> </div> </div>'),s.put("/pages/edit/editContentItem/types/Video.html",'<ng-include src="\'/pages/edit/editContentItem/partials/expo-preview.html\'" ng-if="$ctrl.isPreviewMode" ></ng-include> <editor-header ng-if="$ctrl.showEditorHeader" doc-title="contentItem.title" slug="contentItem.slug" content-status="contentItem.status" content-link="contentItem.link" tiptap-editor="$ctrl.tiptapExpoEditor" is-preview-mode="$ctrl.isPreviewMode" is-saving="$ctrl.isSaving" is-publishing="$ctrl.isPublishing" is-save-error="$ctrl.isSaveError" has-unsaved-changes="$ctrl.hasUnsavedChanges" has-draft="$ctrl.hasDraft" can-edit="$ctrl.canEdit === true" on-mode-change="$ctrl.onEditorModeChange(mode)" on-save="contentItem.slug ? $ctrl.saveAndCreateVersion() : $ctrl.saveDraft()" on-save-version-dialog="$ctrl.openVersionNameDialog()" on-versions-click="$ctrl.toggleVersions()" is-saving-version="$ctrl.savingVersion" is-save-success="$ctrl.saveSuccess" last-version-saved-at="$ctrl.lastVersionSavedAt" on-publish="$ctrl.sendFormForPublish()" is-admin="$ctrl.isAdmin" on-open-settings="$ctrl.openPublishSettings()" on-run-typographer="$ctrl.applyTypography()" on-clean-code="$ctrl.cleanHtmlContent()" word-count="$ctrl.wordCount" char-count="$ctrl.charCount" initial-para-count="$ctrl.paraCount" is-logged-in="$ctrl.isLoggedIn" user-avatar="$ctrl.userAvatarId" user-path="$ctrl.userPathSlug" night-mode="$ctrl.darkMode" on-toggle-night-mode="$ctrl.toggleDarkMode()" ></editor-header> <div class="title-input-row tw:flex tw:flex-wrap" ng-hide="$ctrl.isPreviewMode"> <div class="title-col tw:sm:w-8/12 tw:lg:w-9/12"> <div class="form-group tw:font-bold title" ng-class="{\'has-error\': formErrors.title}"> <textarea class="ds-input big-textarea placeholder-big" placeholder="{{ \'Ðаголовок\' | t }}" ng-model="contentItem.title" ng-change="formErrors.title = false" maxlength="120" textarea-limit-rows="textarea-limit-rows" aria-label="{{ \'Ðаголовок видео\' | t }}" rows="1" msd-elastic aria-invalid="{{ !!formErrors.title }}" aria-describedby="form-error-title" ></textarea> <span id="form-error-title" class="help-block" ng-show="formErrors.title" role="alert" >{{ \'Ðаголовок обÑзаÑелен\' | t }}</span > </div> </div> <div class="cover-col tw:sm:w-4/12 tw:lg:w-3/12 tw:mb-2.5"> <div class="form-group"> <button class="big-button" type="button" ngf-select="$ctrl.uploadImage($file)" ngf-drop="$ctrl.uploadImage($file)" ngf-drag-over-class="\'drag-over\'" ngf-accept="\'image/*\'" ng-disabled="$ctrl.imageUploading[\'root\']" ng-hide="contentItem.thumborId" > <p class="fa fa-paperclip fa-4x"></p> <div>{{ \'ÐагÑÑзиÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}<br />(jpeg, png, gif)</div> <span class="fas fa-sync-alt fa-spin floating-text left" ng-show="$ctrl.imageUploading[\'root\']" ></span> </button> <div class="post-image-wrapper" ng-if="contentItem.thumborId"> <div class="cover-actions cover-actions--desktop"> <button type="button" class="cover-action-btn" ng-click="$ctrl.cropCoverImage()" ng-disabled="$ctrl.cropUploading" aria-label="{{ \'ÐадÑиÑоваÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'ÐадÑиÑоваÑÑ\' | t }}" > <i class="fas fa-crop-alt" aria-hidden="true"></i> </button> <button type="button" class="cover-action-btn" ngf-select="$ctrl.uploadImage($file)" ngf-accept="\'image/*\'" ng-disabled="$ctrl.cropUploading || $ctrl.imageUploading[\'root\']" aria-label="{{ \'ÐамениÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'ÐамениÑÑ\' | t }}" > <i class="fas fa-image" aria-hidden="true"></i> </button> <button type="button" class="cover-action-btn cover-action-btn--delete" ng-click="$ctrl.deleteCoverImage()" ng-disabled="$ctrl.cropUploading" aria-label="{{ \'УдалиÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'УдалиÑÑ\' | t }}" > <i class="fas fa-times" aria-hidden="true"></i> </button> </div> <ng-include src="\'/pages/edit/editContentItem/partials/cover-actions-mobile.html\'" ></ng-include> <span class="fas fa-sync-alt fa-spin crop-upload-spinner" ng-show="$ctrl.cropUploading" ></span> <img class="tw:block tw:max-w-full tw:h-auto thumbmail" ng-class="{\'is-uploading\': $ctrl.cropUploading }" ng-src="{{ contentItem.thumborId | imageUrl: 300 }}" ng-click="$ctrl.cropCoverImage()" alt="{{ (\'Ðбложка:\' | t) + \' \' + (contentItem.title || (\'видео\' | t)) + \' \' + (\'â ÐиÑкÑÑÑ\' | t) }}" /> </div> </div> </div> </div> <div class="tw:flex tw:flex-wrap" ng-hide="$ctrl.isPreviewMode"> <div class="video-link-col tw:sm:w-5/12"> <div class="form-group video-link-form"> <label>{{ \'СÑÑлка на видео\' | t }}</label> <input class="ds-input video-link-input" placeholder="{{ \'УкажиÑе ÑÑÑлкÑ\' | t }}" ng-model="contentItem.media[0].videoUrl" /> </div> </div> <div class="tw:sm:w-2/12 tw:text-center tw:mt-section-xl" ng-hide="contentItem.media[0].videoUrl"> <p class="tw:font-bold">{{ \'ÐÐÐ\' | t }}</p> </div> <div class="video-upload-col tw:sm:w-5/12" ng-hide="contentItem.media[0].videoUrl"> <div class="form-group"> <button class="small-button thin" type="button" ng-class="{\'uploading-process\': $ctrl.videoUploading[0] }" ngf-select="$ctrl.uploadVideo($file, 0)" accept="video/*" required="required" ng-disabled="$ctrl.videoUploading[0]" > <span class="floating-text floating-top" ng-hide="$ctrl.videoUploading[0]" >{{ \'ÐагÑÑзиÑÑ Ð²Ð¸Ð´ÐµÐ¾\' | t }}</span ><span class="floating-text floating-top" ng-show="$ctrl.videoUploading[0]" >{{ \'ÐÐ´ÐµÑ Ð·Ð°Ð³ÑÑзка...\' | t }}</span ><span ng-hide="$ctrl.videoUploading[0]">{{ \'ÐÑбеÑиÑе Ñайл\' | t }}</span ><span class="fas fa-sync-alt fa-spin uploading-icon" ng-show="$ctrl.videoUploading[0]" ></span ><span class="floating-text floating-bottom">*MP4, AVI, MOV</span> </button> </div> </div> </div> <div class="form-group discours-editor big tiptap-mode" ng-show="!$ctrl.isPreviewMode" ng-class="{\'has-editor-header\': $ctrl.showEditorHeader }" >
1 <div class="tiptap-loading" ng-if="!$ctrl.tiptapReady"> <div class="loading-progress-bar"> <div class="loading-progress-fill"></div> </div> <div class="tiptap-loading-skeleton"> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--60"></div> <div class="tiptap-loading-skeleton__gap"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--85"></div> <div class="tiptap-loading-skeleton__line tiptap-loading-skeleton__line--75"></div> </div> </div> <div ng-if="$ctrl.tiptapReady" class="tiptap-editor-container"> <div class="tiptap-editor-wrapper"> <ng-include ng-if="!$ctrl.commenterReadOnly" src="\'/pages/edit/editContentItem/partials/tiptap-toolbar.html\'" ></ng-include> <tiptap-editor ng-model="contentItem.body" placeholder="{{ \'ТекÑÑ\' | t }}" editable="true" editor-instance="$ctrl.tiptapExpoEditor" content-item="contentItem" initial-content="contentItem.body" ></tiptap-editor> </div> <div class="tiptap-bottom-bar"> <div class="bottom-bar-left"></div> <div class="bottom-bar-right" ng-show="$ctrl.expoAutosaveStatus" aria-live="polite"> <span class="expo-autosave-indicator expo-autosave-indicator--{{ $ctrl.expoAutosaveStatus }}" > <i ng-if="$ctrl.expoAutosaveStatus === \'saving\'" class="fas fa-circle-notch fa-spin" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'saved\'" class="fas fa-check" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'error\'" class="fas fa-exclamation-triangle" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'retrying\'" class="fas fa-sync fa-spin" aria-hidden="true" ></i> <span ng-if="$ctrl.expoAutosaveStatus === \'saving\'">{{ \'СоÑ
Ñанение...\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'saved\'">{{ \'СоÑ
Ñанено\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'error\'">{{ \'ÐÑибка ÑоÑ
ÑанениÑ\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'retrying\'">{{ \'ÐовÑоÑ...\' | t }}</span> </span> </div> </div> </div> </div>'),s.put("/pages/edit/editContentItem/types/VideoAlbum.html",'<ng-include src="\'/pages/edit/editContentItem/partials/expo-preview.html\'" ng-if="$ctrl.isPreviewMode" ></ng-include> <editor-header ng-if="$ctrl.showEditorHeader" doc-title="contentItem.title" slug="contentItem.slug" content-status="contentItem.status" content-link="contentItem.link" tiptap-editor="$ctrl.tiptapExpoEditor" is-preview-mode="$ctrl.isPreviewMode" is-saving="$ctrl.isSaving" is-publishing="$ctrl.isPublishing" is-save-error="$ctrl.isSaveError" has-unsaved-changes="$ctrl.hasUnsavedChanges" has-draft="$ctrl.hasDraft" can-edit="$ctrl.canEdit === true" on-mode-change="$ctrl.onEditorModeChange(mode)" on-save="contentItem.slug ? $ctrl.saveAndCreateVersion() : $ctrl.saveDraft()" on-save-version-dialog="$ctrl.openVersionNameDialog()" on-versions-click="$ctrl.toggleVersions()" is-saving-version="$ctrl.savingVersion" is-save-success="$ctrl.saveSuccess" last-version-saved-at="$ctrl.lastVersionSavedAt" on-publish="$ctrl.sendFormForPublish()" is-admin="$ctrl.isAdmin" on-open-settings="$ctrl.openPublishSettings()" on-run-typographer="$ctrl.applyTypography()" on-clean-code="$ctrl.cleanHtmlContent()" word-count="$ctrl.wordCount" char-count="$ctrl.charCount" initial-para-count="$ctrl.paraCount" is-logged-in="$ctrl.isLoggedIn" user-avatar="$ctrl.userAvatarId" user-path="$ctrl.userPathSlug" night-mode="$ctrl.darkMode" on-toggle-night-mode="$ctrl.toggleDarkMode()" ></editor-header> <div class="title-input-row tw:flex tw:flex-wrap" ng-hide="$ctrl.isPreviewMode"> <div class="title-col tw:sm:w-8/12 tw:lg:w-9/12"> <div class="form-group tw:font-bold title" ng-class="{\'has-error\': formErrors.title}"> <textarea class="ds-input big-textarea placeholder-big" placeholder="{{ \'Ðазвание алÑбома\' | t }}" ng-model="contentItem.title" ng-change="formErrors.title = false" maxlength="120" textarea-limit-rows="textarea-limit-rows" rows="1" msd-elastic aria-label="{{ \'Ðазвание видеоалÑбома\' | t }}" aria-invalid="{{ !!formErrors.title }}" aria-describedby="form-error-title" ></textarea> <span id="form-error-title" class="help-block" ng-show="formErrors.title" role="alert" >{{ \'Ðаголовок обÑзаÑелен\' | t }}</span > </div> </div> <div class="cover-col tw:sm:w-4/12 tw:lg:w-3/12 tw:mb-2.5"> <div class="form-group"> <button class="big-button" type="button" ngf-select="$ctrl.uploadImage($file)" ngf-drop="$ctrl.uploadImage($file)" ngf-drag-over-class="\'drag-over\'" ngf-accept="\'image/*\'" ng-disabled="$ctrl.imageUploading[\'root\']" ng-hide="contentItem.thumborId" > <p class="fa fa-paperclip fa-4x"></p> <div>{{ \'ÐагÑÑзиÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}<br />(jpeg, png, gif)</div> <span class="fas fa-sync-alt fa-spin floating-text left" ng-show="$ctrl.imageUploading[\'root\']" ></span> </button> <div class="post-image-wrapper" ng-if="contentItem.thumborId"> <div class="cover-actions cover-actions--desktop"> <button type="button" class="cover-action-btn" ng-click="$ctrl.cropCoverImage()" ng-disabled="$ctrl.cropUploading" aria-label="{{ \'ÐадÑиÑоваÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'ÐадÑиÑоваÑÑ\' | t }}" > <i class="fas fa-crop-alt" aria-hidden="true"></i> </button> <button type="button" class="cover-action-btn" ngf-select="$ctrl.uploadImage($file)" ngf-accept="\'image/*\'" ng-disabled="$ctrl.cropUploading || $ctrl.imageUploading[\'root\']" aria-label="{{ \'ÐамениÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'ÐамениÑÑ\' | t }}" > <i class="fas fa-image" aria-hidden="true"></i> </button> <button type="button" class="cover-action-btn cover-action-btn--delete" ng-click="$ctrl.deleteCoverImage()" ng-disabled="$ctrl.cropUploading" aria-label="{{ \'УдалиÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÑ\' | t }}" data-tooltip="{{ \'УдалиÑÑ\' | t }}" > <i class="fas fa-times" aria-hidden="true"></i> </button> </div> <ng-include src="\'/pages/edit/editContentItem/partials/cover-actions-mobile.html\'" ></ng-include> <span class="fas fa-sync-alt fa-spin crop-upload-spinner" ng-show="$ctrl.cropUploading" ></span> <img class="tw:block tw:max-w-full tw:h-auto thumbmail" ng-class="{\'is-uploading\': $ctrl.cropUploading }" ng-src="{{ contentItem.thumborId | imageUrl: 300 }}" ng-click="$ctrl.cropCoverImage()" alt="{{ (\'Ðбложка:\' | t) + \' \' + (contentItem.title || (\'видеоалÑбом\' | t)) + \' â ÐиÑкÑÑÑ\' }}" /> </div> </div> </div> </div> <div class="media-row tw:flex tw:flex-wrap tw:mt-section" ng-repeat="mediaItem in contentItem.media track by $index" > <div class="media-thumb-col tw:sm:w-4/12"> <div class="form-group tw:relative media-item-actions">
1 <button class="big-button thin small" type="button" ngf-select="$ctrl.uploadVideo($file, $index)" accept="video/*" ng-disabled="$ctrl.videoUploading[$index]" ng-hide="mediaItem.videoUrl" > <img src="/images/icons/attach.png" alt="{{ \'ÐагÑÑзиÑÑ\' | t }}" /><span >{{ \'загÑÑзиÑÑ Ð²Ð¸Ð´ÐµÐ¾\' | t }}</span ><span class="fas fa-sync-alt fa-spin floating-text left" ng-show="$ctrl.videoUploading[$index]" ></span ><span class="floating-text">*MP4,AVI,MOV</span> </button> <p class="tw:font-bold tw:mt-2.5 tw:mb-2.5" ng-hide="mediaItem.videoUrl">{{ \'ÐÐÐ\' | t }}</p> <div class="form-group"> <input class="ds-input" placeholder="{{ \'ÑÑÑлка (Youtube, Vimeo)\' | t }}" ng-model="mediaItem.videoUrl" /> </div> </div> </div> <div class="media-content-col tw:sm:w-8/12"> <div class="form-group tw:font-bold" ng-class="{\'tw:mr-section\': $index != 0 }"> <textarea class="ds-input" placeholder="{{ \'название видео\' | t }}" ng-model="mediaItem.title" aria-label="{{ \'Ðазвание видео в алÑбоме\' | t }}" ></textarea> </div> <div class="form-group discours-editor xs small-margin tiptap-mode" ng-show="!$ctrl.isPreviewMode" ng-class="{\'has-editor-header\': $index === 0 && $ctrl.showEditorHeader }" > <tiptap-simple-editor ng-model="mediaItem.body" preset="simplified" placeholder="{{ \'ТекÑÑ\' | t }}" ></tiptap-simple-editor> </div> </div> </div> <div ng-if="!$ctrl.isPreviewMode"> <div> <div class="tiptap-bottom-bar"> <div class="bottom-bar-left"></div> <div class="bottom-bar-right" ng-show="$ctrl.expoAutosaveStatus" aria-live="polite"> <span class="expo-autosave-indicator expo-autosave-indicator--{{ $ctrl.expoAutosaveStatus }}" > <i ng-if="$ctrl.expoAutosaveStatus === \'saving\'" class="fas fa-circle-notch fa-spin" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'saved\'" class="fas fa-check" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'error\'" class="fas fa-exclamation-triangle" aria-hidden="true" ></i> <i ng-if="$ctrl.expoAutosaveStatus === \'retrying\'" class="fas fa-sync fa-spin" aria-hidden="true" ></i> <span ng-if="$ctrl.expoAutosaveStatus === \'saving\'">{{ \'СоÑ
Ñанение...\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'saved\'">{{ \'СоÑ
Ñанено\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'error\'">{{ \'ÐÑибка ÑоÑ
ÑанениÑ\' | t }}</span> <span ng-if="$ctrl.expoAutosaveStatus === \'retrying\'">{{ \'ÐовÑоÑ...\' | t }}</span> </span> </div> </div> </div> </div> <div class="tw:mb-section-lg"> <div class="discours-form"> <button class="ds-btn-border add-image-button" ng-click="contentItem.media.push({})" type="button" > <i class="fas fa-plus fa-3x"></i>{{ \'добавиÑÑ Ð²Ð¸Ð´ÐµÐ¾\' | t }} </button> </div> </div>'),s.put("/pages/editor-poc/editor-poc.html",'<link rel="stylesheet" href="/styles/editor-e839e09a.css" /> <style> .editor-poc-page { opacity: 0; transition: opacity 0.15s; } </style> <link rel="stylesheet" href="/styles/editor-poc-38826fe3.css" id="editor-poc-css" /> <script> (function () { var link = document.getElementById(\'editor-poc-css\'); var reveal = function () { var el = document.querySelector(\'.editor-poc-page\'); // Ðменно \'1\', а не \'\': ÑбÑÐ¾Ñ Ð¸Ð½Ð»Ð°Ð¹Ð½Ð¾Ð²Ð¾Ð³Ð¾ ÑÑÐ¸Ð»Ñ Ð²Ð¾Ð·Ð²ÑаÑÐ°ÐµÑ ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ð¿Ð¾Ð´ // пÑавило `.editor-poc-page { opacity: 0 }` из <style> вÑÑе â Ñой же // ÑпеÑиÑиÑноÑÑи и без конкÑÑенÑа, поÑÐ¾Ð¼Ñ ÑÑо editor-poc.css Ñвоего // `opacity` Ð´Ð»Ñ ÑÑого клаÑÑа не задаÑÑ. Со ÑбÑоÑом ÑÑÑаниÑа оÑÑавалаÑÑ // невидимой ÐСÐÐÐÐ (Ð·Ð°Ð¼ÐµÑ 22.08.2026 на deploy-preview: css 200, // link.sheet еÑÑÑ, reveal ÑÑабоÑал, inline style пÑÑÑ, // getComputedStyle().opacity === \'0\' пÑи 154 оÑÑендеÑеннÑÑ
ÑзлаÑ
). // РаÑÑÐµÑ â scripts/editor-poc-reveal.test.js. if (el) el.style.opacity = \'1\'; }; if (link) { link.addEventListener(\'load\', reveal); link.addEventListener(\'error\', reveal); // Fallback: еÑли CSS Ñже загÑÑжен из кÑÑа if (link.sheet) reveal(); } // Fallback: reveal page after 3s even if CSS fails to load (network error, 404, etc.) setTimeout(reveal, 3000); })(); <\/script> <div class="editor-poc-page" ng-class="{\'preview-mode\': previewMode, \'has-editor-header\': editorInstance }" > <editor-header ng-if="editorInstance" doc-title="documentTitle || \'ÐовÑй маÑеÑиал\'" collab-status="collabStatus" connected-users="[]" is-offline-mode="collabStatus === \'offline\'" is-reconnecting="collabStatus === \'connecting\'" tiptap-editor="editorInstance" suggestion-mode="suggestionMode" sidebar-visible="showCommentsSidebar" pending-count="comments.length + suggestions.all.length" is-saving="isSaving" is-publishing="isPublishing" has-unsaved-changes="hasUnsavedChanges" has-draft="hasDraft" can-edit="true" show-collab-control
1s="collabEnabled" show-invite-button="collabEnabled" on-open-invite="openInviteModal()" on-mode-change="onEditorModeChange(mode)" on-toggle-sidebar="toggleSidebar()" on-publish="publishDocument()" on-retry-connection="retryConnection()" ></editor-header> <invite-collaborators opened="inviteModalOpen" document-name="collabDocumentName" on-invites-changed="onInvitesChanged(invites)" ></invite-collaborators> <div class="editor-poc-header" ng-hide="editorInstance"> <h1>Tiptap Editor PoC</h1> <p class="editor-poc-subtitle"> Proof of Concept коллабоÑаÑивного ÑедакÑоÑа Ñ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑиÑми и пÑедложениÑми пÑавок </p> <div class="collab-status-panel" ng-class="collabStatus"> <div class="collab-info" ng-if="collabEnabled"> <span class="collab-indicator"></span> <span class="collab-status-text"> <span ng-if="collabStatus === \'connecting\'">ÐодклÑÑение к ÑеÑвеÑÑ...</span> <span ng-if="collabStatus === \'connected\'">ÐодклÑÑено</span> <span ng-if="collabStatus === \'synced\'">СинÑ
ÑонизиÑовано</span> <span ng-if="collabStatus === \'disconnected\'">ÐÑклÑÑено (пеÑеподклÑÑение...)</span> <span ng-if="collabStatus === \'offline\'">ÐвÑономнÑй Ñежим</span> <span ng-if="collabStatus === \'auth-failed\'">ÐÑибка авÑоÑизаÑии</span> </span> <span class="collab-server">{{ collabServerUrl }}</span> <span class="collab-doc">ÐокÑменÑ: {{ collabDocumentName }}</span> </div> <div class="collab-info collab-disabled" ng-if="!collabEnabled"> <span class="collab-indicator"></span> <span class="collab-status-text">ÐоллабоÑаÑÐ¸Ñ Ð¾ÑклÑÑена</span> <span class="collab-hint" ng-if="!currentUser._id || currentUser._id === \'anonymous\'"> (войдиÑе в аккаÑÐ½Ñ Ð´Ð»Ñ ÑовмеÑÑного ÑедакÑиÑованиÑ) </span> </div> <div class="save-status-info"> <span class="save-indicator" ng-class="{\'saving\': isSaving, \'unsaved\': hasUnsavedChanges && !isSaving, \'error\': saveError}" > <span ng-if="isSaving">СоÑ
Ñанение...</span> <span ng-if="!isSaving && saveError === \'conflict\'" >â ÐонÑÐ»Ð¸ÐºÑ Ð²ÐµÑÑий - обновиÑе ÑÑÑаниÑÑ</span > <span ng-if="!isSaving && saveError === \'error\'">â ÐÑибка ÑоÑ
ÑанениÑ</span> <span ng-if="!isSaving && !saveError && hasUnsavedChanges" >â ÐÑÑÑ Ð½ÐµÑоÑ
ÑанÑннÑе изменениÑ</span > <span ng-if="!isSaving && !saveError && !hasUnsavedChanges && lastSavedAt" >СоÑ
Ñанено {{ lastSavedAt | date:\'HH:mm:ss\' }}</span > </span> </div> </div> <div class="draft-recovery-banner" ng-if="hasRecoverableDraft"> <span class="draft-recovery-text"> ÐбнаÑÑжен неÑоÑ
ÑанÑннÑй ÑеÑновик Ð¾Ñ {{ draftBackup.timestamp | date:\'dd.MM.yyyy HH:mm\' }} </span> <button type="button" class="draft-recovery-btn restore" ng-click="restoreDraftBackup()"> ÐоÑÑÑановиÑÑ ÑеÑновик </button> <button type="button" class="draft-recovery-btn dismiss" ng-click="dismissDraftBackup()"> ÐÑклониÑÑ </button> </div> <div class="offline-banner" ng-if="isOffline"> <span class="offline-icon">â </span> <span class="offline-text" >ÐÐµÑ Ð¿Ð¾Ð´ÐºÐ»ÑÑÐµÐ½Ð¸Ñ Ðº ÑеÑи. РедакÑиÑование пÑодолжаеÑÑÑ Ð»Ð¾ÐºÐ°Ð»Ñно. ÐÐ·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð±ÑдÑÑ ÑинÑ
ÑонизиÑÐ¾Ð²Ð°Ð½Ñ Ð¿Ñи воÑÑÑановлении ÑвÑзи.</span > </div> </div> <div class="editor-poc-toolbar" ng-hide="previewMode"> <div class="toolbar-group"> <button type="button" class="toolbar-btn" ng-class="{ active: isActive(\'bold\') }" ng-click="execCommand(\'bold\')" title="ÐиÑнÑй (Ctrl+B)" > <strong>B</strong> </button> <button type="button" class="toolbar-btn" ng-class="{ active: isActive(\'italic\') }" ng-click="execCommand(\'italic\')" title="ÐÑÑÑив (Ctrl+I)" > <em>I</em> </button> <button type="button" class="toolbar-btn" ng-class="{ active: isActive(\'underline\') }" ng-click="execCommand(\'underline\')" title="ÐодÑÑÑкивание (Ctrl+U)" > <u>U</u> </button> <button type="button" class="toolbar-btn" ng-class="{ active: isActive(\'strike\') }" ng-click="execCommand(\'strike\')" title="ÐаÑÑÑкнÑÑÑй" > <s>S</s> </button> </div> <div class="toolbar-separator"></div> <div class="toolbar-group"> <button type="button" class="toolbar-btn" ng-class="{ active: isActive(\'h2\') }" ng-click="execCommand(\'h2\')" title="Ðаголовок H2" > H2 </button> <button type="button" class="toolbar-btn" ng-class="{ active: isActive(\'h3\') }" ng-click="execCommand(\'h3\')" title="Ðаголовок H3" > H3 </button> </div> <div class="toolbar-separator"></div> <div class="toolbar-group"> <button type="button" class="toolbar-btn" ng-class="{ active: isActive(\'bulletList\') }" ng-click="execCommand(\'bulletList\')" title="ÐаÑкиÑованнÑй ÑпиÑок" > <i class="fas fa-list-ul"></i> </button> <button type="button" class="toolbar-btn" ng-class="{ active: isActive(\'orderedList\') }" ng-click="execCommand(\'orderedList\')" title="ÐÑмеÑованнÑй ÑпиÑок" > <i class="fas fa-list-ol"></i> </button> </div> <div class="toolbar-separator"></div> <div class="toolbar-group"> <button type="button" class="toolbar-btn" ng-class="{ active: isActive(\'blockquote\') }" ng-click="execCommand(\'blockquote\')" title="ЦиÑаÑа" > <i class="fas fa-quote-left"></i> </button> <button type="button" class="toolbar-btn toolbar-btn-tasub" ng-class="{ active: isActive(\'taSub\') }" ng-click="execCommand(\'taSub\')" title="ÐодвÑÑÑÑка (ÑеÑÐ°Ñ Ð¿Ð»Ð°Ñка)" > SUB </button> </div> <div class="toolbar-separator"></div> <div class="toolbar-group"> <button type="button" class="toolbar-btn" ng-class="{ active: isActive(\'link\') }" ng-click="execCommand(\'link\')" title="ÐÑÑавиÑÑ ÑÑÑлкÑ" > <i class="fas fa-link"></i> </button> <button type="button" class="toolbar-btn" ng-click="execCommand(\'unlink\')" ng-disabled="!isActive(\'link\')" title="УбÑаÑÑ ÑÑÑлкÑ" > <i class="fas fa-unlink"></i> </button> </div> <div class="toolbar-separator"></div> <div class="toolbar-group"> <button type="button" class="toolbar-btn" ng-click="execCommand(\'undo\')" title="ÐÑмениÑÑ (Ctrl+Z)" > <i class="fas fa-undo"></i> </button> <button type="button" class="toolbar-btn" ng-click="execCommand(\'redo\')" title="ÐовÑоÑиÑÑ (Ctrl+Shift+Z)" > <i class="fas fa-redo"></i> </button> </div> <div class="toolbar-spacer"></div> <div class="toolbar-group toolbar-group-collab"> <button type="button" class="toolbar-btn toolbar-btn-comment" ng-click="addComment()" ng-disabled="!canAddComment()" title="ÐобавиÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑий к вÑÐ´ÐµÐ»ÐµÐ½Ð½Ð¾Ð¼Ñ ÑекÑÑÑ" > <i class="fas fa-comment"></i> ÐомменÑаÑий </button> <button type="button" class="toolbar-btn toolbar-btn-suggestion" ng-class="{ active: suggestionMode }" ng-click="toggleSuggestionMode()" title="Режим пÑедложений (track changes)" > <i class="fas fa-pencil-alt"></i> {{ suggestionMode ? \'ÐÑйÑи из Ñежима\' : \'ÐÑедложиÑÑ Ð¿Ñавки\' }} </button> <button type="button" class="toolbar-btn" ng-click="toggleSidebar()" title="ÐоказаÑÑ/ÑкÑÑÑÑ Ð¿Ð°Ð½ÐµÐ»Ñ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑиев" > <i class="fas fa-columns"></i> </button> </div> </div> <div class="post-preview" ng-if="previewMode && previewPost"> <div class="ds-container"> <div class="button-container"> <button type="button" class="preview-close-button" ng-click="togglePreviewMode()"> <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M17.9975 4.89363L13.1038 0L0 13.1064V18H4.89363L17.9975 4.89363ZM13.105 2.55674L15.4421 4.89383L14.4612 5.87591L12.1241 3.53882L13.105 2.55674ZM10.8453 4.81648L13.1824 7.
115357L5.42174 14.9137L3.08485 12.5756L10.8453 4.81648ZM1.80725 16.1915V13.8544L4.14434 16.1915H1.80725Z" fill="currentColor" /> </svg> ÐÑодолжиÑÑ ÑедакÑиÑоваÑÑ </button> </div> </div> <div class="ds-container"> <div class="open-post progress"> <div class="tw:row-flex"> <div class="ds-content-col"> <div class="post-main-spacer tw:mt-section tw:max-md:hidden"></div> <div class="author-category" ng-class="{\'no-author\': !previewPost.author }"> <span class="category" ng-if="previewPost.category"> <a ng-href="{{ previewPost.categoryLink }}" rel="noopener noreferrer" target="_blank" >{{ previewPost.category }}</a > </span> <span class="author" ng-if="previewPost.author"> <a ng-href="{{ previewPost.authorLink }}" rel="noopener noreferrer" target="_blank" ng-if="previewPost.authorLink" >{{ previewPost.author }}</a > <span ng-if="!previewPost.authorLink">{{ previewPost.author }}</span> </span> </div> <h1 class="title">{{ previewPost.title }}</h1> <div class="open-post-title-image-wrapper" ng-if="previewPost.thumborId"> <img class="open-post-title-image" ng-src="{{ previewPost.thumborId | imageUrl: 750 }}" alt="{{ previewPost.title }}" /> </div> <p class="image-description" ng-if="previewPost.imageCaption" ng-bind-html="previewPost.imageCaption | trustedHtml" ></p> </div> </div> <div class="tw:row-flex"> <div class="ds-content-col"> <div class="post-body" ng-bind-html="previewPost.body | trustedHtml" post-links="post-links" post-images="post-images" ></div> </div> </div> <div class="footer-post tw:row-flex"> <div class="ds-content-col"> <hr class="tw:mt-2.5 tw:mb-5" /> <div class="post-meta-footer"> <div class="post-meta-footer__author"> <div class="author-title" ng-if="previewPost.author"> <a ng-href="{{ previewPost.authorLink }}" rel="noopener noreferrer" target="_blank" ng-if="previewPost.authorLink" >{{ previewPost.author }}</a > <span ng-if="!previewPost.authorLink">{{ previewPost.author }}</span> </div> <div class="date-time"> <span class="time" >{{ previewPost.publishedAt | amDateFormat: \'D MMMM YYYY\' }}</span > </div> </div> </div> <div class="tw:mt-2.5" ng-if="previewPost.tags.length"> <div class="tags-container"> <ul class="tags"> <li ng-repeat="tag in previewPost.tags track by tag.slug"> <a ng-href="/tags/{{ tag.slug }}" rel="noopener noreferrer" target="_blank" >#{{ tag.title }}</a > </li> </ul> </div> </div> </div> </div> </div> </div> <div class="ds-container" ng-if="showBottomEditButton"> <div class="button-container"> <button type="button" class="preview-close-button bottom" ng-click="togglePreviewMode()"> <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M17.9975 4.89363L13.1038 0L0 13.1064V18H4.89363L17.9975 4.89363ZM13.105 2.55674L15.4421 4.89383L14.4612 5.87591L12.1241 3.53882L13.105 2.55674ZM10.8453 4.81648L13.1824 7.15357L5.42174 14.9137L3.08485 12.5756L10.8453 4.81648ZM1.80725 16.1915V13.8544L4.14434 16.1915H1.80725Z" fill="currentColor" /> </svg> ÐÑодолжиÑÑ ÑедакÑиÑоваÑÑ </button> </div> </div> </div> <div class="editor-poc-container" ng-class="{\'with-sidebar\': showCommentsSidebar }" ng-if="!previewMode" > <div class="toc-nav-container" id="toc-nav-container"></div> <div class="editor-poc-main"> <div class="editor-poc-editor" ng-class="{\'suggestion-mode\': suggestionMode }"> <tiptap-editor ng-model="content" placeholder="ÐаÑниÑе пиÑаÑÑ..." user-id="userId" user-name="currentUser.name" editor-instance="editorInstance" on-selection-change="onSelectionChange(selection)" collab-server-url="{{ collabServerUrl }}" collab-document-name="collabDocumentName" collab-token="collabToken" collab-status="collabStatus" on-collab-synced="onCollabSynced()" on-collab-disconnect="onCollabDisconnect()" on-collab-connect="onCollabConnect()" on-collab-fallback="onCollabFallback(reason)" initial-content="initialContent" ></tiptap-editor> </div> <div class="suggestion-mode-indicator" ng-if="suggestionMode"> <i class="fas fa-pencil-alt"></i> Режим пÑедложений акÑивен. ÐаÑи пÑавки бÑдÑÑ Ð¾ÑмеÑÐµÐ½Ñ Ð´Ð»Ñ Ð¿ÑовеÑки. </div> <div class="editor-poc-footer"> <div class="footer-spacer"></div> <button type="button" class="preview-toggle-btn" ng-click="togglePreviewMode()" title="ÐÑедпÑоÑмоÑÑ" > <svg width="21" height="14" viewBox="0 0 21 14" fill="none" xmlns="http://www.w3.org/2000/svg" > <path d="M10.125 0C4.6875 0 0 4.52865 0 6.75C0 8.97135 4.6875 13.5 10.125 13.5C15.5625 13.5 20.25 8.97135 20.25 6.75C20.25 4.52865 15.5625 0 10.125 0ZM10.125 1.5C14.9792 1.5 18.75 5.687
15 18.75 6.75C18.75 7.8125 14.9792 12 10.125 12C5.27083 12 1.5 7.8125 1.5 6.75C1.5 5.6875 5.27083 1.5 10.125 1.5ZM10.125 2.625C7.84635 2.625 6 4.47135 6 6.75C6 9.02865 7.84635 10.875 10.125 10.875C12.4036 10.875 14.25 9.02865 14.25 6.75C14.25 4.47135 12.4036 2.625 10.125 2.625ZM10.125 5.25C10.9531 5.25 11.625 5.92188 11.625 6.75C11.625 7.57813 10.9531 8.25 10.125 8.25C9.29688 8.25 8.625 7.57813 8.625 6.75C8.625 5.92188 9.29688 5.25 10.125 5.25Z" fill="currentColor" /> </svg> ÐÑедпÑоÑмоÑÑ </button> </div> </div> <div class="editor-poc-sidebar" ng-show="showCommentsSidebar"> <div class="sidebar-tabs"> <button type="button" class="sidebar-tab" ng-class="{ active: sidebarTab !==\'suggestions\' }" ng-click="sidebarTab = \'comments\'" > ÐомменÑаÑии ({{ comments.length }}) </button> <button type="button" class="sidebar-tab" ng-class="{ active: sidebarTab === \'suggestions\' }" ng-click="sidebarTab = \'suggestions\'" > ÐÑавки ({{ suggestions.all.length }}) </button> </div> <div class="collab-capability-notice" ng-if="collabCommentStoreUnavailable" role="status" aria-live="polite" > {{ collabCommentStoreMessage | t }} </div> <div class="collab-capability-notice collab-recovery-list" ng-if="collabCommentRecoveryDrafts.length" > <p role="status" aria-live="polite" aria-atomic="true"> {{ \'ÐеоÑпÑавленнÑй ÑекÑÑ ÑоÑ
ÑанÑн ниже. СкопиÑÑйÑе его пеÑед вÑÑ
одом Ñо ÑÑÑаниÑÑ\' | t }} </p> <div class="collab-recovery-draft" ng-repeat="draft in collabCommentRecoveryDrafts track by draft.id" > <label for="poc-collab-recovery-{{ ::$index }}">{{ draft.label | t }}</label> <textarea id="poc-collab-recovery-{{ ::$index }}" readonly rows="3" ng-model="draft.text" ></textarea> </div> </div> <div class="sidebar-content" ng-if="sidebarTab !== \'suggestions\'"> <div class="comments-list" ng-if="comments.length > 0"> <div class="comment-item" ng-repeat="comment in comments track by comment.id" ng-class="{ resolved: comment.resolved, editing: comment.editing, active: activeCommentId === comment.id }" ng-click="scrollToComment(comment)" > <div class="comment-header"> <span class="comment-author">{{ comment.author.name || \'ÐвÑоÑ\' }}</span> <span class="comment-date">{{ comment.createdAt | date:\'dd.MM.yyyy HH:mm\' }}</span> <span class="comment-resolved-badge" ng-if="comment.resolved">РеÑено</span> </div> <div class="comment-body" ng-if="!comment.editing">{{ comment.text }}</div> <div class="comment-edit" ng-if="comment.editing"> <textarea ng-model="comment.text" placeholder="ÐведиÑе комменÑаÑий..." rows="3" ng-readonly="collabCommentStoreUnavailable" ></textarea> <div class="comment-actions"> <button type="button" class="btn-save" ng-click="saveComment(comment)" ng-disabled="collabCommentStoreUnavailable" > ÐÑпÑавиÑÑ </button> <button type="button" class="btn-cancel" ng-click="cancelComment(comment)"> ÐÑмена </button> </div> </div> <div class="comment-footer" ng-if="!comment.editing"> <button type="button" class="ds-btn-link" ng-click="editComment(comment)" ng-disabled="collabCommentStoreUnavailable" > ÐзмениÑÑ </button> <button type="button" class="ds-btn-link" ng-click="resolveComment(comment)" ng-if="!comment.resolved" ng-disabled="collabCommentStoreUnavailable" > РеÑено </button> <button type="button" class="ds-btn-link" ng-click="unresolveComment(comment)" ng-if="comment.resolved" ng-disabled="collabCommentStoreUnavailable" > ÐÑкÑÑÑÑ Ñнова </button> <button type="button" class="ds-btn-link ds-btn-danger" ng-click="removeComment(comment)" ng-disabled="collabCommentStoreUnavailable" > УдалиÑÑ </button> </div> <div class="comment-replies" ng-if="comment.replies.length > 0"> <div class="reply-item" ng-repeat="reply in comment.replies track by (reply._id || $index)" > <span class="reply-author">{{ reply.author.name }}</span>: {{ reply.text }} </div> </div> <div class="comment-add-reply" ng-if="!comment.editing && !comment.resolved"> <input type="text" ng-model="comment.newReplyText" placeholder="ÐÑвеÑиÑÑ..." ng-keypress="$event.keyCode === 13 && addReply(comment, comment.
1newReplyText)" ng-readonly="collabCommentStoreUnavailable" /> </div> </div> </div> <div class="sidebar-empty" ng-if="comments.length === 0 && !collabCommentStoreUnavailable"> <i class="fas fa-comment"></i> <p>ÐÐµÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑиев</p> <p class="hint">ÐÑделиÑе ÑекÑÑ Ð¸ нажмиÑе "ÐомменÑаÑий"</p> </div> </div> <div class="sidebar-content" ng-if="sidebarTab === \'suggestions\'"> <div class="suggestions-actions" ng-if="suggestions.all.length > 0"> <button type="button" class="btn-accept-all" ng-click="acceptAllSuggestions()"> <i class="fas fa-check-double"></i> ÐÑинÑÑÑ Ð²Ñе </button> <button type="button" class="btn-reject-all" ng-click="rejectAllSuggestions()"> <i class="fas fa-times"></i> ÐÑклониÑÑ Ð²Ñе </button> </div> <div class="suggestions-list" ng-if="suggestions.all.length > 0"> <div class="suggestion-item" ng-repeat="suggestion in suggestions.all track by suggestion.suggestionId" ng-class="{\'suggestion-add\': suggestion.type === \'add\', \'suggestion-delete\': suggestion.type === \'delete\' }" > <div class="suggestion-header"> <span class="suggestion-type" ng-if="suggestion.type === \'add\'"> <i class="fas fa-plus"></i> Ðобавление </span> <span class="suggestion-type" ng-if="suggestion.type === \'delete\'"> <i class="fas fa-minus"></i> Удаление </span> </div> <div class="suggestion-text">"{{ suggestion.text | limitTo:100 }}"</div> <div class="suggestion-actions"> <button type="button" class="btn-accept" ng-click="acceptSuggestion(suggestion); $event.stopPropagation()" > <i class="fas fa-check"></i> ÐÑинÑÑÑ </button> <button type="button" class="btn-reject" ng-click="rejectSuggestion(suggestion); $event.stopPropagation()" > <i class="fas fa-times"></i> ÐÑклониÑÑ </button> </div> </div> </div> <div class="sidebar-empty" ng-if="suggestions.all.length === 0"> <i class="fas fa-pencil-alt"></i> <p>ÐÐµÑ Ð¿Ñедложений</p> <p class="hint">ÐклÑÑиÑе "Режим пÑедложений" и ÑедакÑиÑÑйÑе ÑекÑÑ</p> </div> </div> </div> </div> <div class="editor-poc-debug" ng-if="DISCOURS_ENV !== \'production\'"> <h4>ÐÑладка</h4> <div class="debug-actions"> <button type="button" ng-click="loadSampleContent()">ÐагÑÑзиÑÑ Ð¿ÑимеÑ</button> <button type="button" ng-click="clearContent()">ÐÑиÑÑиÑÑ</button> <button type="button" ng-click="getHTML()">ÐÑвеÑÑи HTML в конÑолÑ</button> </div> <div class="debug-info"> <p> <strong>ÐÑделение:</strong> {{ selection.hasSelection ? selection.selectedText : \'неÑ\' }} </p> <p><strong>Режим пÑедложений:</strong> {{ suggestionMode ? \'Ðа\' : \'ÐеÑ\' }}</p> <p><strong>ÐомменÑаÑиев:</strong> {{ comments.length }}</p> <p><strong>ÐÑедложений:</strong> {{ suggestions.all.length }}</p> </div> </div> </div>')}catch(t){}}(0)},53320(t,e,n){"use strict";var i=n(36817),s=n(74774),a=n(31455),o=n(88484);const l=(...t)=>window.TIPTAP_DEBUG&&void 0;angular.module("discours.directives").directive("tiptapEditor",["$timeout","$interval","apiClient","Notification",function(t,e,r,c){function d(t){if(!t)return!0;const e=t.replace(/<p>\s*<\/p>/g,"").replace(/<br\s*\/?>/gi,"").replace(/ /gi,"").replace(/\s+/g,"").trim();return""===e||"<p></p>"===e}function g(t,e={}){const n={type:"hocuspocus_error",event:t,timestamp:(new Date).toISOString(),...e};if(window.__sentry){var i="websocket_closed"===t&&(null==e.code||-1!==u.indexOf(e.code)||e.hadSynced),s=-1!==m.indexOf(t);i||s||window.__sentry.captureException(new Error("HocusPocus: "+t),{extra:n,level:"warning",fingerprint:["hocuspocus-error",String(t||"unknown")]})}try{const t="tiptap_collab_errors",e=JSON.parse(localStorage.getItem(t)||"[]");e.push(n),e.length>10&&e.shift(),localStorage.setItem(t,JSON.stringify(e))}catch(t){}}const p=8e3;var u=[1e3,1001,1005,1006,1012,1013],m=["sync_timeout","early_disconnect","reconnection_timeout"];return{restrict:"E",require:"?ngModel",scope:{placeholder:"@",editable:"=?",userId:"=?",userName:"=?",userSlug:"=?",userAvatar:"=?",userColor:"=?",onSelectionChange:"&?",onFocus:"&?",onBlur:"&?",editorInstance:"=?",contentItem:"=?",collabServerUrl:"@?",collabDocumentName:"=?",collabToken:"=?",onCollabSynced:"&?",onCollabDisconnect:"&?",onCollabConnect:"&?",collabStatus:"=?",collabPermissionDenied:"=?",initialContent:"=?",onCollabFallback:"&?",onInitialContentReady:"&?",isOfflineMode:"=?",isReconnecting:"=?",lastSyncTime:"=?",connectionLatency:"=?",unsyncedCh
1angesCount:"=?"},template:'<div class="tiptap-editor-inner"><div class="tiptap-editor-loading-bar" ng-if="isLoading && !isReconnecting"><div class="loading-progress-fill"></div></div><div class="tiptap-editor-error" ng-if="loadError"><div class="error-message">{{loadError}}</div><button type="button" ng-click="retryInit()">ÐовÑоÑиÑÑ Ð·Ð°Ð³ÑÑзкÑ</button></div><div class="tiptap-collab-reconnecting-banner" ng-if="isReconnecting"><span>ÐеÑеподклÑÑение к ÑеÑвеÑÑ...</span></div><div class="tiptap-prosemirror-container" ng-hide="loadError" ng-class="{\'is-loading\': isLoading}"></div></div>',_debugDomObserver:null,link:function(u,m,v,b){function f(t){if(!k)return;const e=k.isSuggestionMode&&k.isSuggestionMode();e&&k.setSuggestionMode&&k.setSuggestionMode(!1);try{k.commands.setContent(t,!1),k.clearUndoHistory?k.clearUndoHistory():k.commands.clearHistory&&k.commands.clearHistory()}finally{e&&k.setSuggestionMode&&k.setSuggestionMode(!0)}}function h(){u.onInitialContentReady&&!S&&t(function(){S||u.onInitialContentReady()})}function w(e){z.cancelPending(),V&&(t.cancel(V),V=null),H&&(t.cancel(H),H=null);let n=null;if(k&&!k.isDestroyed)try{n=k.getHTML(),n&&!d(n)&&(u.initialContent=n,A=!1,l(n.substring(0,100)))}catch(t){}if(u.isOfflineMode=!0,u.isReconnecting=!1,u.collabStatus="offline",l(),k&&u.initialContent){const t=k.getHTML(),e=d(t);if(l(t?.substring(0,100)),e){l(),C=!0;try{f(x?.cleanHtml?x.cleanHtml(u.initialContent):(0,i.NT)(u.initialContent))}catch(t){}C=!1}}k&&!k.isDestroyed&&k.setEditable(!0),u.onCollabFallback&&t(()=>{u.onCollabFallback({reason:e}),t(()=>{if(!S&&k&&!k.isDestroyed&&k.isEditable)try{k.commands.focus()}catch(t){}},50)})}function y(){Promise.all([n.e(272),n.e(929),n.e(411),n.e(753),n.e(68),n.e(1)]).then(n.bind(n,36090)).then(function(e){x=e,u.isLoading=!1,u.loadError=null;(u.collabServerUrl?void 0!==v.collabServerUrl:"")&&!u.collabDocumentName?(l(),L=u.$watchGroup(["collabDocumentName","initialContent"],function(e){if(S)return void(L&&(L(),L=null));const[n,i]=e;if(n&&u.collabToken){if(!i&&!u._waitedForContent){u._waitedForContent=!0,l();const e=t(()=>{S||I||(l(),L&&(L(),L=null),_())},1500);return void F.push(e)}l(),L&&(L(),L=null),_()}})):S||(l(),_()),u.$applyAsync()}).catch(function(t){u.isLoading=!1,u.loadError="Ðе ÑдалоÑÑ Ð·Ð°Ð³ÑÑзиÑÑ ÑедакÑоÑ, пÑовеÑÑÑе Ñоединение и попÑобÑйÑе Ñнова",c.error("ÐÑибка загÑÑзки ÑедакÑоÑа"),u.$applyAsync()})}async function _(){if(S||I)return void l();I=!0;const{createTiptapEditor:n,extractComments:a,extractSuggestions:v,generateId:y,cleanHtml:_,isContentLikelyDuplicated:L}=x;try{let x=null,I=u.collabServerUrl&&u.collabDocumentName&&u.collabToken;l(),I?(u.collabStatus="connecting",V=t(()=>{S||"connecting"===u.collabStatus&&w("connection_timeout")},p),F.push(V),x={serverUrl:u.collabServerUrl,documentName:u.collabDocumentName,token:u.collabToken,onSynced:()=>
1{S||(z.reset(),D=!1,V&&(t.cancel(V),V=null),H&&(t.cancel(H),H=null),t(()=>{if(S||!k)return;u.collabStatus="synced",u.isOfflineMode=!1,u.isReconnecting=!1,T=!0,u.lastSyncTime=Date.now(),u.unsyncedChangesCount=0;const e=()=>{if(A||S||!k)return;const t=d(k.getHTML());if(!u.initialContent&&t)try{var e=localStorage.getItem("ls.contentItem.body");if(e){var n=JSON.parse(e);n&&"<p></p>"!==n&&(u.initialContent=n,localStorage.removeItem("ls.contentItem.body"))}}catch(t){}const a=!!u.initialContent;if(!t&&a&&/<iframe\s/i.test(u.initialContent)&&function(t,e){if(!t||!e)return!1;try{const n=(new DOMParser).parseFromString(e,"text/html").querySelectorAll("iframe[src]");if(0===n.length)return!1;const i=new Map;if(n.forEach(t=>{const e=t.getAttribute("src")||"";if(!e)return;const n=t.getAttribute("height"),s=t.style&&t.style.height,a=t.style&&t.style.minHeight;let o=null;n&&parseInt(n,10)>100?o=parseInt(n,10)+"px":a?o=a:s&&(o=s);const l=t.closest(".social-embed-container"),r=l?l.dataset.aspectRatio||l.style.paddingBottom:null;(o||r)&&i.set(e,{minHeight:o,aspectRatio:r})}),0===i.size)return!1;const{tr:s}=t.state;let a=!1;return t.state.doc.descendants((t,e)=>{if("socialEmbed"!==t.type.name)return;const n=t.attrs.minHeight,o=n?parseInt(n,10):0;let l=!1;if(n?1e3!==o||"piktochart"!==t.attrs.provider&&"auto"!==t.attrs.aspectRatio||(l=!0):("custom"===t.attrs.provider||!t.attrs.aspectRatio||"auto"===t.attrs.aspectRatio)&&(l=!0),l){const n=i.get(t.attrs.src||"");n&&n.minHeight&&(s.setNodeMarkup(e,void 0,{...t.attrs,minHeight:n.minHeight,aspectRatio:n.aspectRatio||t.attrs.aspectRatio}),a=!0)}}),!!a&&(t.view.dispatch(s),l(),!0)}catch(t){return!1}}(k,u.initialContent),t&&a){const t=k.getYDoc&&k.getYDoc();if(t){const e=t.getMap("documentInit"),n=String(t.clientID);return e.has("initBy")||e.set("initBy",n),void(U=setTimeout(function(){if(U=null,A||S||!k)return;if(!d(k.getHTML()))return A=!0,u.initialContent=null,void h();const t=e.get("initBy");if(t!==n&&t){l(),A=!0;let t=0;R=setInterval(function(){if(t++,S||!k||t>50)if(clearInterval(R),R=null,k&&!S&&u.initialContent&&d(k.getHTML())){let t=!1;try{t=e&&!e.has("initBy")}catch(t){}if(t)return l(),void(N=setTimeout(function(){if(N=null,!S&&k){if(d(k.getHTML())&&u.initialContent){l(),C=!0;try{f(_?_(u.initialContent):(0,i.NT)(u.initialContent))}catch(t){A=!1}C=!1,u.initialContent=null}h()}},2e3));l(),C=!0;try{f(_?_(u.initialContent):(0,i.NT)(u.initialContent))}catch(t){A=!1}C=!1,u.initialContent=null,h()}else k&&!S&&h();else d(k.getHTML())||(clearInterval(R),R=null,u.initialContent=null,h())},200)}else{if(!u.initialContent)return l(),A=!0,void h();A=!0,l(),C=!0;try{f(_?_(u.initialContent):(0,i.NT)(u.initialContent))}catch(t){A=!1}C=!1;const t=u.initialContent;u.initialContent=null;try{e.delete("initBy")}catch(t){}h();const n=k.getHTML();O=setTimeout(function(){if(k&&!S){try{const e=k.getHTML();if(e!==n)return void l();if(L&&L(e)&&t){C=!0;try{f(_?_(t):(0,i.NT)(t))}catch(t){}C=!1}}catch(t){}O=null}},3e3)}},s.S))}A=!0,l(),C=!0;try{f(_?_(u.initialContent):(0,i.NT)(u.initialContent))}catch(t){A=!1}C=!1,u.initialContent=null,h()}else t||(A=!0)};if(k){const n=k.getYDoc&&k.getYDoc();n?(n._errorHandlerAttached||(n._errorHandlerAttached=!0,n.on("error",e=>{u.isOfflineMode||t(()=>{w("ydoc_error"),c.error("ÐÑибка ÑинÑ
ÑонизаÑии. РабоÑаем в авÑономном Ñежиме.")})})),n.once("afterAllTransactions",()=>{requestAnimationFrame(()=>{t(e,0)})}),n.transact(()=>{})):requestAnimationFrame(()=>{t(e,100)})}u.onCollabSynced&&!S&&u.onCollabSynced()}))},onDisconnect:()=>{S||t(()=>{if(S)return;const t="connecting"===u.collabStatus||"connected"===u.collabStatus;if(u.collabStatus="disconnected",!T&&t&&!D)return g("early_disconnect",{documentName:u.collabDocumentName,reason:"disconnected_before_sync",hadSynced:!1}),void w("early_disconnect");u.onCollabDisconnect&&u.onCollabDisconnect()})},onConnect:()=>{S||(V&&(t.cancel(V),V=null),H&&t.cancel(H),H=t(()=>{S||"connected"===u.collabStatus&&(g("sync_timeout",{documentName:u.collabDocumentName,reason:"sync_not_completed_in_time",hadSynced:!1}),w("sync_timeout"))},12e3),F.push(H),t(()=>{S||(u.collabStatus="connected",u.onCollabConnect&&u.onCollabConnect())}
1))},onStatus:e=>{S||t(()=>{S||(u.collabStatus=e.status)})},onAuthenticationFailed:e=>{if(S)return;const n=e&&e.reason||"",i="API_UNAVAILABLE"===n;if("permission-denied"===n||"PERMISSION_DENIED"===n||"INVALID_DOCUMENT_NAME"===n||"NOT_FOUND"===n)t(()=>{S||(u.collabPermissionDenied=!0,u.collabPermissionReason=n,w("permission_denied"))});else{if(i){D=!0,H&&(t.cancel(H),H=null);const n=z.failed();return void g("auth_failed_transient",{documentName:u.collabDocumentName,reason:e.reason,attempt:n,hadSynced:T})}D=!1,g("auth_failed",{documentName:u.collabDocumentName,reason:e&&e.reason||"authentication_failed",hadSynced:T}),t(()=>{w("auth_failed")})}},onClose:e=>{S||(g("websocket_closed",{documentName:u.collabDocumentName,code:e?.code,reason:e?.reason,hadSynced:T}),T||u.isOfflineMode||D||t(()=>{w("connection_closed")}))}}):l();var B=b&&b.$viewValue||u.initialContent||"";const q=B?_?_(B):(0,i.NT)(B):"";if(window.TIPTAP_DEBUG&&q&&(q.match(/<(ta-quotation|ta-sub|ta-border-sub|ta-epigraph|ta-selection-frame)[^>]*>/g),q.match(/<[^>]+class="[^"]*\b(ta-quotation|ta-sub|ta-border-sub|ta-epigraph|ta-selection-frame)\b[^"]*"[^>]*>/g),q.match(/<[^>]+class="[^"]*\b(lead|punchline)\b[^"]*"[^>]*>/g)),k=await n({element:M,content:q,editable:!1!==u.editable,placeholder:(0,o.t)(u.placeholder||"ÐаÑниÑе пиÑаÑÑ..."),userId:u.userId||"anonymous",userName:u.userName||(0,o.t)("ÐоÑÑÑ"),userSlug:u.userSlug||null,userAvatar:u.userAvatar||null,userColor:u.userColor,collaboration:x,getLanguageToolPrivacyState:function(){const t=u.contentItem;if(!t)return{allowed:!0,reason:"no-content-item"};const e=t.status||null;return{allowed:!0,reason:null,status:e,isSharedDraft:!0===t.isSharedDraft,isPublicStatus:"posted"===e||"published"===e||"featured"===e||"recalled"===e}},uploadService:r,notificationService:c,onUpdate:(e,n)=>{C||S||n&&n.getMeta("remarkMarksInternal")||("synced"!==u.collabStatus&&(u.unsyncedChangesCount=(u.unsyncedChangesCount||0)+1),P&&clearTimeout(P),P=setTimeout(()=>{P=null,!S&&b&&e&&!e.isDestroyed&&t(()=>{b&&b.$setViewValue(e.getHTML())})},300))},onSelectionUpdate:e=>{!S&&u.onSelectionChange&&(E&&clearTimeout(E),E=setTimeout(()=>{E=null,!S&&u.onSelectionChange&&t(()=>{try{u.onSelectionChange({selection:e})}catch(t){}})},100))},onFocus:()=>{m.addClass("tiptap-focused"),u.onFocus&&t(()=>{try{u.onFocus()}catch(t){}})},onBlur:()=>{m.removeClass("tiptap-focused"),u.onBlur&&t(()=>{try{u.onBlur()}catch(t){}})}}),S){if(k)try{k.destroy()}catch(t){}return}if(!k)return void t(()=>{u.editorInstance=null});t(()=>{S||(u.editorInstance=k)});const Z=function(){S||!k||k.isDestroyed||setTimeout(function(){if(!S&&k&&!k.isDestroyed&&!k.isFocused&&k.isEditable){l();try{k.commands.focus("end")}catch(t){}}},50)};if(M.addEventListener("click",Z),u._containerClickHandler=Z,"undefined"!=typeof window&&window.DISCOURS_DEBUG_DOM){const t=M.querySelector(".ProseMirror");if(t&&!u._debugDomObserver){let e=0,n=Date.now();const i=[];u._debugDomObserver=new MutationObserver(t=>{e+=t.length;const s=(Date.now()-n)/1e3;e%50==0&&(e/s).toFixed(2),i.length<100&&t.forEach(t=>{i.push({type:t.type,target:t.target.nodeName+(t.target.className?"."+t.target.className.split(" ")[0]:""),added:t.addedNodes.length,removed:t.removedNodes.length,attr:t.attributeName})}),u._debugDomLogTimer||(u._debugDomLogTimer=setInterval(()=>{if(S)return;const t=(Date.now()-n)/1e3,s=((e/t).toFixed(2),{});i.forEach(t=>{const e=t.target+(t.attr?`[${t.attr}]`:"");s[e]=(s[e]||0)+1}),Object.entries(s).sort((t,e)=>e[1]-t[1]).slice(0,5)},5e3))}),u._debugDomObserver.observe(t,{childList:!0,subtree:!0,attributes:!0,characterData:!0})}}if(window.TIPTAP_DEBUG&&t(()=>{k.getHTML().match(/<(ta-quotation|ta-sub|ta-border-sub|ta-epigraph|ta-selection-frame)[^>]*>/g)},500),u.extractComments=()=>a(k),u.extractSuggestions=()=>v(k),u.generateId=y,x&&(u._latencyInterval=e(()=>{if(!S&&"synced"===u.collabStatus&&u.lastSyncTime){const t=Date.now()-u.lastSyncTime;u.connectionLatency=t<5e3?Math.min(t,200):t<3e4?300:600}},1e4)),b&&!x){let t=!0;b.$render=function(){if(k&&void 0!==b.$viewValue&&k.getHTML()!==b.$viewValue){C=!0;const e=_?_(b.$viewValue||""):(0,i.NT)(b.$viewValue||"");k.commands.setContent(e,!1),t&&(k.clearUndoHistory?k.clearUndoHistory():k.commands.clearHistory&&k.commands.clearHistory(),t=!1),C=!1}}}u.$watch("editable",t=>{k&&k.setEditable(!1!==t)});
1const j=u.$watch("userId",t=>{k&&t&&(k.setUserId(t),j())});u._tiptapEventBridges=["tiptap:addComment","tiptap:toggleSuggestionMode","tiptap:toggleSidebar","tiptap:togglePreview","tiptap:setEditingMode","tiptap:toggleShortcutsHelp","tiptap:toggleToc","tiptap:openHtmlEditor","tiptap:toggleDarkMode","tiptap:toggleQuietMode"].map(e=>{const n=n=>{t(()=>{u.$emit(e,n.detail)})};return M.addEventListener(e,n),{eventName:e,handler:n}})}catch(t){u.loadError="ÐÑибка иниÑиализаÑии ÑедакÑоÑа: "+(t.message||"ÐеизвеÑÑÐ½Ð°Ñ Ð¾Ñибка"),I=!1,c.error("Ðе ÑдалоÑÑ Ð¸Ð½Ð¸ÑиализиÑоваÑÑ ÑедакÑоÑ")}}let k=null,C=!1,x=null,S=!1,I=!1;const M=m[0].querySelector(".tiptap-prosemirror-container");let P=null,E=null,L=null;u.isLoading=!0,u.loadError=null,u.isOfflineMode=!1,u.isReconnecting=!1,u.unsyncedChangesCount=0;let T=!1,A=!1,D=!1,V=null,H=null,B=null,R=null,U=null,O=null,N=null;const F=[],z=(0,a.Q)({schedule:(e,n)=>t(e,n),cancel:e=>t.cancel(e),limit:3,delay:2e3,retry:()=>{if(S||u.isOfflineMode)return;D=!1;const e=k&&k.getProvider&&k.getProvider();if(e&&"function"==typeof e.connect){u.collabStatus="connecting",V=t(()=>{V=null,S||u.isOfflineMode||"synced"===u.collabStatus||w("auth_retry_connection_timeout")},p),F.push(V);try{Promise.resolve(e.connect()).catch(()=>{S||u.isOfflineMode||"synced"===u.collabStatus||w("auth_retry_connect_error")})}catch(t){w("auth_retry_connect_error")}}else w("auth_retry_provider_missing")},exhausted:()=>{t(()=>{S||u.isOfflineMode||w("auth_failed_transient_limit")})}});u.retryInit=function(){u.loadError=null,u.isLoading=!0,u.isOfflineMode=!1,S=!1,I=!1,y()},u.retryCollabConnection=function(){if(!k||u.isReconnecting)return void l();B&&(t.cancel(B),B=null),l(),z.reset(),D=!1,u.isOfflineMode=!1,u.isReconnecting=!0,u.collabStatus="connecting";const e=k.getProvider&&k.getProvider();if(e&&"function"==typeof e.connect)return l(),V=t(()=>{!S&&k&&"connecting"===u.collabStatus&&(g("reconnection_timeout",{documentName:u.collabDocumentName,reason:"reconnection_failed",hadSynced:T}),u.isReconnecting=!1,w("reconnection_timeout"))},p),F.push(V),void e.connect();l();const n=k.getHTML();u.initialContent=n,A=!1,B=t(()=>{if(B=null,S)l();else try{k&&(k.destroy(),k=null),I=!1,u._waitedForContent=!0,_()}catch(t){u.isReconnecting=!1,w("reconnect_error"),c.error("ÐÑибка пеÑеподклÑÑениÑ. РабоÑаем в авÑономном Ñежиме")}},100),F.push(B)},y(),u.$on("$destroy",()=>{S=!0,z.destroy(),u._containerClickHandler&&M&&(M.removeEventListener("click",u._containerClickHandler),u._containerClickHandler=null),u._debugDomObserver&&(u._debugDomObserver.disconnect(),u._debugDomObserver=null),u._debugDomLogTimer&&(clearInterval(u._debugDomLogTimer),u._debugDomLogTimer=null),P&&(clearTimeout(P),P=null),E&&(clearTimeout(E),E=null),V&&(t.cancel(V),V=null),H&&(t.cancel(H),H=null),B&&(t.cancel(B),B=null),U&&(clearTimeout(U),U=null),R&&(clearInterval(R),R=null),O&&(clearTimeout(O),O=null),N&&(clearTimeout(N),N=null),u._latencyInterval&&(e.cancel(u._latencyInterval),u._latencyInterval=null),F.forEach(e=>{e&&t.cancel(e)}),F.length=0,L&&(L(),L=null),u._tiptapEventBridges&&(u._tiptapEventBridges.forEach(({eventName:t,handler:e})=>{M.removeEventListener(t,e)}),u._tiptapEventBridges=null),k&&(k.destroy(),k=null)})}}}])}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.