diff --git a/panel/context/auth.tsx b/panel/context/auth.tsx index 7b2cfd81..4156ddaf 100644 --- a/panel/context/auth.tsx +++ b/panel/context/auth.tsx @@ -76,12 +76,16 @@ export const AuthProvider: Component = (props) => { // Инициализация авторизации при монтировании onMount(async () => { console.log('[AuthProvider] Performing auth initialization...') + console.log('[AuthProvider] Checking localStorage token:', !!localStorage.getItem(AUTH_TOKEN_KEY)) + console.log('[AuthProvider] Checking cookie token:', !!getAuthTokenFromCookie()) + console.log('[AuthProvider] Checking CSRF token:', !!getCsrfTokenFromCookie()) // Небольшая задержка для завершения других инициализаций await new Promise((resolve) => setTimeout(resolve, 100)) // Проверяем текущее состояние авторизации const authStatus = checkAuthStatus() + console.log('[AuthProvider] Final auth status after check:', authStatus) setIsAuthenticated(authStatus) console.log('[AuthProvider] Auth initialization complete, ready for requests') diff --git a/panel/ui/HTMLEditor.tsx b/panel/ui/HTMLEditor.tsx index 83b2f9f4..1d17cdc9 100644 --- a/panel/ui/HTMLEditor.tsx +++ b/panel/ui/HTMLEditor.tsx @@ -191,8 +191,11 @@ const HTMLEditor = (props: HTMLEditorProps) => { const value = props.value || '' if (value.trim()) { + // Форматируем HTML перед экранированием + const formattedValue = formatHTML(value) + // Экранируем HTML для безопасности - const escapedValue = value + const escapedValue = formattedValue .replace(/&/g, '&') .replace(//g, '>') @@ -334,16 +337,47 @@ const HTMLEditor = (props: HTMLEditorProps) => { const formatHTML = (html: string): string => { try { - // Простое форматирование с отступами - const lines = html.split(/\n/) - const formattedLines = lines.map((line, index) => { - const trimmedLine = line.trim() - if (trimmedLine.startsWith('<') && !trimmedLine.startsWith(' 0 ? 1 : 0) + trimmedLine + if (!html.trim()) return html + + // Функция для форматирования HTML с правильными отступами + const formatHTMLString = (str: string): string => { + let formatted = '' + let indent = 0 + const indentStr = ' ' // 2 пробела для отступа + + // Разбиваем на токены (теги и текст) + const tokens = str.match(/<\/?[^>]*>|[^<]+/g) || [] + + for (let i = 0; i < tokens.length; i++) { + const token = tokens[i].trim() + if (!token) continue + + if (token.startsWith('')) { + // Открывающий тег + const isSelfClosing = token.endsWith('/>') || + /^<(area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)(\s|>)/i.test(token) + + formatted += indentStr.repeat(indent) + token + '\n' + + if (!isSelfClosing) { + indent++ + } + } else { + // Текстовое содержимое + if (token.length > 0) { + formatted += indentStr.repeat(indent) + token + '\n' + } + } } - return trimmedLine - }) - return formattedLines.join('\n') + + return formatted.trim() + } + + return formatHTMLString(html) } catch (error) { console.warn('HTML formatting error:', error) return html