{"id":76,"date":"2026-03-17T05:47:49","date_gmt":"2026-03-17T05:47:49","guid":{"rendered":"https:\/\/tools.sanepo.com\/?post_type=tool&#038;p=76"},"modified":"2026-03-17T05:49:21","modified_gmt":"2026-03-17T05:49:21","slug":"online-html-cleaner","status":"publish","type":"tool","link":"https:\/\/tools.sanepo.com\/ar\/features\/online-html-cleaner\/","title":{"rendered":"Free Online HTML Cleaner &amp; Formatter \u2013 Strip MS Word Junk"},"content":{"rendered":"\n<style>\n    @import url('https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;500;600;700&display=swap');\n\n    \/* CSS Variables Default (Light Mode) *\/\n    #wpnt-html-cleaner {\n        --bg-primary: #ffffff;\n        --bg-secondary: #f8fafc;\n        --border-color: #e2e8f0;\n        --accent-color: #4361ee;\n        --accent-hover: #3a56d4;\n        --glass-bg: rgba(255, 255, 255, 0.85);\n        --text-color: #1e293b; \/* Variabel baru untuk mengunci warna teks *\/\n        --card-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);\n        --transition: all 0.3s ease;\n        \n        \/* Tool Specific Variables *\/\n        --wpnt-success: #10b981;\n        --wpnt-warning: #f59e0b;\n        --wpnt-danger: #ef4444;\n        --wpnt-radius-lg: 16px;\n        --wpnt-radius-md: 12px;\n        --wpnt-radius-sm: 8px;\n        \n        font-family: 'Inter', sans-serif;\n        color: var(--text-color);\n        width: 100%;\n        margin: 30px auto;\n        background: linear-gradient(135deg, var(--bg-primary) 0%, var(--bg-secondary) 100%);\n        border: 1px solid var(--border-color);\n        border-radius: var(--wpnt-radius-lg);\n        box-shadow: var(--card-shadow);\n        padding: 32px;\n        box-sizing: border-box;\n        line-height: 1.5;\n        backdrop-filter: blur(10px);\n        -webkit-backdrop-filter: blur(10px);\n    }\n\n    #wpnt-html-cleaner * {\n        box-sizing: border-box;\n        transition: background-color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;\n    }\n\n    \/* 1. OS Default Dark Mode (Hanya aktif jika tidak ada intervensi tema) *\/\n    @media (prefers-color-scheme: dark) {\n        #wpnt-html-cleaner {\n            --bg-primary: #0f172a;\n            --bg-secondary: #1e293b;\n            --border-color: #334155;\n            --glass-bg: rgba(15, 23, 42, 0.7);\n            --text-color: #f1f5f9;\n        }\n    }\n\n    \/* 2. Integrasi Manual Dark Mode Theme (Memaksa Dark Mode jika tema\/body\/html punya class .dark) *\/\n    html.dark #wpnt-html-cleaner,\n    body.dark #wpnt-html-cleaner,\n    [data-theme=\"dark\"] #wpnt-html-cleaner {\n        --bg-primary: #0f172a !important;\n        --bg-secondary: #1e293b !important;\n        --border-color: #334155 !important;\n        --glass-bg: rgba(15, 23, 42, 0.7) !important;\n        --text-color: #f1f5f9 !important;\n    }\n\n    \/* 3. Integrasi Manual Light Mode Theme (Memaksa Light Mode jika tema\/body\/html punya class .light) *\/\n    html.light #wpnt-html-cleaner,\n    body.light #wpnt-html-cleaner,\n    [data-theme=\"light\"] #wpnt-html-cleaner {\n        --bg-primary: #ffffff !important;\n        --bg-secondary: #f8fafc !important;\n        --border-color: #e2e8f0 !important;\n        --glass-bg: rgba(255, 255, 255, 0.85) !important;\n        --text-color: #1e293b !important;\n    }\n\n    \/* Header *\/\n    #wpnt-html-cleaner .wpnt-header {\n        text-align: center;\n        margin-bottom: 24px;\n    }\n\n    #wpnt-html-cleaner h3 {\n        margin: 0 0 8px 0;\n        font-size: 1.75rem;\n        font-weight: 700;\n        letter-spacing: -0.025em;\n        color: var(--text-color) !important; \/* Diberi important agar tidak ter-override CSS global tema Anda *\/\n    }\n\n    #wpnt-html-cleaner p {\n        margin: 0;\n        font-size: 0.95rem;\n        opacity: 0.8;\n        color: var(--text-color) !important;\n    }\n    \n    #wpnt-html-cleaner .wpnt-privacy-badge {\n        display: inline-block;\n        background: rgba(16, 185, 129, 0.1);\n        color: var(--wpnt-success);\n        border: 1px solid rgba(16, 185, 129, 0.2);\n        padding: 6px 12px;\n        border-radius: 20px;\n        font-size: 0.8rem;\n        font-weight: 600;\n        margin-top: 12px;\n    }\n\n    \/* Layout Grid *\/\n    #wpnt-html-cleaner .wpnt-grid {\n        display: grid;\n        grid-template-columns: 1fr 250px;\n        gap: 24px;\n        margin-bottom: 24px;\n    }\n\n    \/* Editors Area *\/\n    #wpnt-html-cleaner .wpnt-editors {\n        display: flex;\n        flex-direction: column;\n        gap: 20px;\n    }\n\n    #wpnt-html-cleaner .wpnt-editor-group {\n        display: flex;\n        flex-direction: column;\n        gap: 8px;\n    }\n\n    #wpnt-html-cleaner .wpnt-editor-header {\n        display: flex;\n        justify-content: space-between;\n        align-items: center;\n        font-weight: 600;\n        font-size: 0.9rem;\n    }\n\n    #wpnt-html-cleaner .wpnt-badge-count {\n        font-size: 0.75rem;\n        background: var(--bg-secondary);\n        border: 1px solid var(--border-color);\n        padding: 2px 8px;\n        border-radius: 12px;\n        color: var(--accent-color);\n    }\n\n    #wpnt-html-cleaner textarea {\n        width: 100%;\n        min-height: 200px;\n        padding: 16px;\n        border-radius: var(--wpnt-radius-md);\n        border: 1px solid var(--border-color);\n        background-color: var(--glass-bg);\n        font-family: 'Courier New', Courier, monospace;\n        font-size: 0.9rem;\n        color: inherit;\n        outline: none;\n        resize: vertical;\n        box-shadow: inset 0 2px 4px rgba(0,0,0,0.02);\n    }\n\n    #wpnt-html-cleaner textarea:focus {\n        border-color: var(--accent-color);\n        box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.15);\n    }\n\n    \/* Settings Sidebar *\/\n    #wpnt-html-cleaner .wpnt-settings-panel {\n        background: var(--glass-bg);\n        padding: 20px;\n        border-radius: var(--wpnt-radius-md);\n        border: 1px solid var(--border-color);\n        box-shadow: var(--card-shadow);\n        height: fit-content;\n    }\n\n    #wpnt-html-cleaner .wpnt-settings-title {\n        font-weight: 700;\n        font-size: 1rem;\n        margin-bottom: 16px;\n        padding-bottom: 12px;\n        border-bottom: 1px solid var(--border-color);\n        display: flex;\n        align-items: center;\n        gap: 8px;\n    }\n\n    #wpnt-html-cleaner .wpnt-checkbox-group {\n        display: flex;\n        flex-direction: column;\n        gap: 12px;\n        margin-bottom: 20px;\n    }\n\n    #wpnt-html-cleaner .wpnt-checkbox-label {\n        display: flex;\n        align-items: flex-start;\n        gap: 10px;\n        font-size: 0.85rem;\n        cursor: pointer;\n        user-select: none;\n    }\n\n    #wpnt-html-cleaner .wpnt-checkbox-label input[type=\"checkbox\"] {\n        appearance: none;\n        -webkit-appearance: none;\n        width: 18px;\n        height: 18px;\n        border: 2px solid var(--border-color);\n        border-radius: 4px;\n        background-color: var(--bg-primary);\n        cursor: pointer;\n        position: relative;\n        flex-shrink: 0;\n        margin-top: 2px;\n    }\n\n    #wpnt-html-cleaner .wpnt-checkbox-label input[type=\"checkbox\"]:checked {\n        background-color: var(--accent-color);\n        border-color: var(--accent-color);\n    }\n\n    #wpnt-html-cleaner .wpnt-checkbox-label input[type=\"checkbox\"]:checked::after {\n        content: '';\n        position: absolute;\n        left: 5px;\n        top: 1px;\n        width: 5px;\n        height: 10px;\n        border: solid white;\n        border-width: 0 2px 2px 0;\n        transform: rotate(45deg);\n    }\n\n    #wpnt-html-cleaner .wpnt-setting-desc {\n        display: block;\n        font-size: 0.75rem;\n        opacity: 0.6;\n        margin-top: 2px;\n    }\n\n    \/* Buttons *\/\n    #wpnt-html-cleaner .wpnt-btn {\n        background: var(--accent-color);\n        color: #ffffff;\n        border: none;\n        padding: 12px 20px;\n        border-radius: var(--wpnt-radius-sm);\n        cursor: pointer;\n        font-weight: 600;\n        font-size: 0.95rem;\n        display: inline-flex;\n        align-items: center;\n        justify-content: center;\n        gap: 8px;\n        width: 100%;\n        margin-bottom: 10px;\n    }\n\n    #wpnt-html-cleaner .wpnt-btn.secondary {\n        background: transparent;\n        color: var(--accent-color);\n        border: 1px solid var(--accent-color);\n    }\n\n    #wpnt-html-cleaner .wpnt-btn:hover {\n        transform: translateY(-2px);\n        box-shadow: 0 4px 12px rgba(67, 97, 238, 0.25);\n    }\n\n    #wpnt-html-cleaner .wpnt-btn.secondary:hover {\n        background: rgba(67, 97, 238, 0.05);\n        box-shadow: none;\n    }\n\n    #wpnt-html-cleaner .wpnt-btn svg {\n        width: 18px;\n        height: 18px;\n    }\n\n    \/* Results Stats *\/\n    #wpnt-html-cleaner .wpnt-stats-row {\n        display: flex;\n        justify-content: space-between;\n        background: var(--glass-bg);\n        border: 1px solid var(--border-color);\n        border-radius: var(--wpnt-radius-md);\n        padding: 16px 20px;\n        margin-top: 20px;\n    }\n\n    #wpnt-html-cleaner .wpnt-stat-item {\n        display: flex;\n        flex-direction: column;\n        align-items: center;\n        flex: 1;\n    }\n\n    #wpnt-html-cleaner .wpnt-stat-item:not(:last-child) {\n        border-right: 1px solid var(--border-color);\n    }\n\n    #wpnt-html-cleaner .wpnt-stat-value {\n        font-size: 1.25rem;\n        font-weight: 700;\n        color: var(--accent-color);\n    }\n\n    #wpnt-html-cleaner .wpnt-stat-label {\n        font-size: 0.75rem;\n        text-transform: uppercase;\n        letter-spacing: 0.05em;\n        opacity: 0.7;\n        margin-top: 4px;\n    }\n\n    \/* Toast Notification *\/\n    #wpnt-html-cleaner .wpnt-toast {\n        position: fixed;\n        bottom: 20px;\n        right: 20px;\n        background: var(--wpnt-success);\n        color: white;\n        padding: 12px 24px;\n        border-radius: var(--wpnt-radius-sm);\n        font-weight: 600;\n        font-size: 0.9rem;\n        box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);\n        transform: translateY(100px);\n        opacity: 0;\n        transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);\n        z-index: 9999;\n    }\n\n    #wpnt-html-cleaner .wpnt-toast.show {\n        transform: translateY(0);\n        opacity: 1;\n    }\n\n    \/* Responsiveness *\/\n    @media (max-width: 768px) {\n        #wpnt-html-cleaner {\n            padding: 20px 16px;\n        }\n        #wpnt-html-cleaner .wpnt-grid {\n            grid-template-columns: 1fr; \/* Stack layout on mobile *\/\n        }\n        #wpnt-html-cleaner .wpnt-stats-row {\n            flex-direction: column;\n            gap: 16px;\n        }\n        #wpnt-html-cleaner .wpnt-stat-item:not(:last-child) {\n            border-right: none;\n            border-bottom: 1px dashed var(--border-color);\n            padding-bottom: 16px;\n        }\n    }\n<\/style>\n\n<div id=\"wpnt-html-cleaner\">\n    <!-- Header Section -->\n    <div class=\"wpnt-header\">\n        <h3>Sanepo Tools &#8211; HTML Cleaner<\/h3>\n        <p>Instantly purify dirty HTML code from MS Word, Google Docs, or other websites.<\/p>\n        <div class=\"wpnt-privacy-badge\">\n            <svg style=\"width:14px;height:14px;vertical-align:middle;margin-right:4px;\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z\"><\/path><\/svg>\n            100% Client-Side (No Data Uploaded)\n        <\/div>\n    <\/div>\n\n    <!-- Main Grid Workspace -->\n    <div class=\"wpnt-grid\">\n        \n        <!-- Editors (Left\/Top) -->\n        <div class=\"wpnt-editors\">\n            <!-- Dirty Input -->\n            <div class=\"wpnt-editor-group\">\n                <div class=\"wpnt-editor-header\">\n                    <span>Dirty HTML Input<\/span>\n                    <span class=\"wpnt-badge-count\" id=\"wpnt-input-size\">0 Bytes<\/span>\n                <\/div>\n                <textarea id=\"wpnt-input-html\" placeholder=\"Paste your dirty HTML code here (e.g., from MS Word or another website)...\"><\/textarea>\n            <\/div>\n\n            <!-- Clean Output -->\n            <div class=\"wpnt-editor-group\">\n                <div class=\"wpnt-editor-header\">\n                    <span>Cleaned Result<\/span>\n                    <span class=\"wpnt-badge-count\" id=\"wpnt-output-size\">0 Bytes<\/span>\n                <\/div>\n                <textarea id=\"wpnt-output-html\" readonly placeholder=\"Your cleaned, SEO-friendly HTML will appear here...\"><\/textarea>\n            <\/div>\n        <\/div>\n\n        <!-- Settings & Actions (Right\/Bottom) -->\n        <div class=\"wpnt-settings-panel\">\n            <div class=\"wpnt-settings-title\">\n                <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\" style=\"width:20px;height:20px;\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z\"><\/path><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 12a3 3 0 11-6 0 3 3 0 016 0z\"><\/path><\/svg>\n                Cleaning Rules\n            <\/div>\n            \n            <div class=\"wpnt-checkbox-group\">\n                <label class=\"wpnt-checkbox-label\">\n                    <input type=\"checkbox\" id=\"opt-inline-styles\" checked>\n                    <div>\n                        Strip Inline Styles\n                        <span class=\"wpnt-setting-desc\">Removes style=&#8221;&#8230;&#8221; attributes<\/span>\n                    <\/div>\n                <\/label>\n                <label class=\"wpnt-checkbox-label\">\n                    <input type=\"checkbox\" id=\"opt-classes-ids\" checked>\n                    <div>\n                        Strip Classes &#038; IDs\n                        <span class=\"wpnt-setting-desc\">Removes class=&#8221;&#8230;&#8221; and id=&#8221;&#8230;&#8221;<\/span>\n                    <\/div>\n                <\/label>\n                <label class=\"wpnt-checkbox-label\">\n                    <input type=\"checkbox\" id=\"opt-comments\" checked>\n                    <div>\n                        Remove Comments\n                        <span class=\"wpnt-setting-desc\">Removes &lt;!&#8211; &#8230; &#8211;&gt; tags<\/span>\n                    <\/div>\n                <\/label>\n                <label class=\"wpnt-checkbox-label\">\n                    <input type=\"checkbox\" id=\"opt-empty-tags\" checked>\n                    <div>\n                        Remove Empty Tags\n                        <span class=\"wpnt-setting-desc\">Removes tags with no content like &lt;span&gt;&lt;\/span&gt;<\/span>\n                    <\/div>\n                <\/label>\n                <label class=\"wpnt-checkbox-label\">\n                    <input type=\"checkbox\" id=\"opt-ms-word\" checked>\n                    <div>\n                        Clear MS Word Junk\n                        <span class=\"wpnt-setting-desc\">Strips specific mso-tags and xml elements<\/span>\n                    <\/div>\n                <\/label>\n                <label class=\"wpnt-checkbox-label\">\n                    <input type=\"checkbox\" id=\"opt-beautify\" checked>\n                    <div>\n                        Auto-Format (Beautify)\n                        <span class=\"wpnt-setting-desc\">Properly indents the final HTML code<\/span>\n                    <\/div>\n                <\/label>\n            <\/div>\n\n            <button class=\"wpnt-btn\" id=\"wpnt-btn-clean\">\n                <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 002-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10\"><\/path><\/svg>\n                Clean HTML Now\n            <\/button>\n            \n            <button class=\"wpnt-btn secondary\" id=\"wpnt-btn-copy\" disabled>\n                <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3\"><\/path><\/svg>\n                Copy Result\n            <\/button>\n            \n            <button class=\"wpnt-btn secondary\" id=\"wpnt-btn-clear\" style=\"border-color: var(--border-color); color: var(--border-color);\">\n                Clear All\n            <\/button>\n        <\/div>\n    <\/div>\n\n    <!-- Statistics Row -->\n    <div class=\"wpnt-stats-row\">\n        <div class=\"wpnt-stat-item\">\n            <span class=\"wpnt-stat-value\" id=\"stat-elements-removed\">0<\/span>\n            <span class=\"wpnt-stat-label\">Junk Elements Removed<\/span>\n        <\/div>\n        <div class=\"wpnt-stat-item\">\n            <span class=\"wpnt-stat-value\" id=\"stat-attributes-removed\">0<\/span>\n            <span class=\"wpnt-stat-label\">Attributes Cleared<\/span>\n        <\/div>\n        <div class=\"wpnt-stat-item\">\n            <span class=\"wpnt-stat-value\" id=\"stat-space-saved\" style=\"color: var(--wpnt-success);\">0%<\/span>\n            <span class=\"wpnt-stat-label\">Size Reduction<\/span>\n        <\/div>\n    <\/div>\n\n    <!-- Toast Component -->\n    <div class=\"wpnt-toast\" id=\"wpnt-toast\">Action Successful!<\/div>\n\n<\/div>\n\n<script>\n    \/\/ Membungkus seluruh logika dalam IIFE (Immediately Invoked Function Expression) \n    \/\/ agar variabel dan fungsi kita tidak bentrok (clash) dengan script tema WordPress.\n    (function() {\n        \/\/ DOM Elements\n        const elInput = document.getElementById('wpnt-input-html');\n        const elOutput = document.getElementById('wpnt-output-html');\n        const btnClean = document.getElementById('wpnt-btn-clean');\n        const btnCopy = document.getElementById('wpnt-btn-copy');\n        const btnClear = document.getElementById('wpnt-btn-clear');\n        \n        \/\/ Options Elements\n        const optStyles = document.getElementById('opt-inline-styles');\n        const optClasses = document.getElementById('opt-classes-ids');\n        const optComments = document.getElementById('opt-comments');\n        const optEmptyTags = document.getElementById('opt-empty-tags');\n        const optMsWord = document.getElementById('opt-ms-word');\n        const optBeautify = document.getElementById('opt-beautify');\n\n        \/\/ Stats Elements\n        const statElRemoved = document.getElementById('stat-elements-removed');\n        const statAttrRemoved = document.getElementById('stat-attributes-removed');\n        const statSpaceSaved = document.getElementById('stat-space-saved');\n        const labelInputSize = document.getElementById('wpnt-input-size');\n        const labelOutputSize = document.getElementById('wpnt-output-size');\n\n        \/\/ Helper: Format Bytes agar mudah dibaca manusia\n        function formatBytes(bytes) {\n            if (bytes === 0) return '0 Bytes';\n            const k = 1024;\n            const sizes = ['Bytes', 'KB', 'MB'];\n            const i = Math.floor(Math.log(bytes) \/ Math.log(k));\n            return parseFloat((bytes \/ Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n        }\n\n        \/\/ Helper: Kalkulasi ukuran teks dalam bytes\n        function getByteSize(str) {\n            return new Blob([str]).size;\n        }\n\n        \/\/ Helper: Menampilkan notifikasi Toast\n        function showToast(message, isError = false) {\n            const toast = document.getElementById('wpnt-toast');\n            toast.textContent = message;\n            toast.style.background = isError ? 'var(--wpnt-danger)' : 'var(--wpnt-success)';\n            toast.classList.add('show');\n            setTimeout(() => { toast.classList.remove('show'); }, 3000);\n        }\n\n        \/\/ Helper: Fungsi Sederhana untuk Merapikan HTML (Beautifier \/ Indentation)\n        function beautifyHTML(html) {\n            let formatted = '';\n            let indent = '';\n            const indentChar = '  '; \/\/ 2 spaces for indentation\n            \n            \/\/ RegEx untuk memisahkan tag HTML menjadi array baris.\n            \/\/ Metode split dengan Capturing Group (<[^>]+>) jauh lebih aman dan didukung semua versi browser \n            \/\/ daripada menggunakan Regex Lookbehind (?<=...) yang sering memicu SyntaxError di Safari lama.\n            const tokens = html.replace(\/>\\s+<\/g, '><').split(\/(<[^>]+>)\/g).filter(function(t) { return t.trim() !== ''; });\n            \n            tokens.forEach(function(token) {\n                if (token.match(\/^<\\\/\\w\/)) {\n                    \/\/ Jika tag penutup (contoh: <\/div>), kurangi indentasi\n                    indent = indent.substring(indentChar.length);\n                    formatted += indent + token + '\\n';\n                } else if (token.match(\/^<\\w[^>]*[^\\\/]>.*$\/) ? !token.match(\/<\\\/\/) : false) {\n                    \/\/ Jika tag pembuka (contoh: <div>), tambah indentasi untuk baris berikutnya\n                    formatted += indent + token + '\\n';\n                    \/\/ Pengecualian untuk tag yang tidak butuh penutup (void elements)\n                    if (!token.match(\/<(img|hr|br|input|meta|link)\/i)) {\n                        indent += indentChar;\n                    }\n                } else if (token.match(\/^<!\/) || token.match(\/^<\\?\/)) {\n                    \/\/ Doctype atau komentar (jika masih tersisa)\n                    formatted += indent + token + '\\n';\n                } else {\n                    \/\/ Teks konten biasa\n                    formatted += indent + token.trim() + '\\n';\n                }\n            });\n            \n            return formatted.trim();\n        }\n\n        \/\/ --- CORE FUNCTION ENGINE ---\n        \/\/ Menjalankan pembersihan menggunakan fitur DOMParser milik Browser (Zero Server Load)\n        function processHTML() {\n            const rawHTML = elInput.value;\n            if (!rawHTML.trim()) {\n                showToast('Please enter some HTML code first!', true);\n                return;\n            }\n\n            const initialBytes = getByteSize(rawHTML);\n            labelInputSize.textContent = formatBytes(initialBytes);\n            \n            \/\/ Variabel statistik (Tracker)\n            let elRemovedCount = 0;\n            let attrRemovedCount = 0;\n\n            \/\/ 1. Pre-parsing: Hapus elemen Microsoft Word\/XML dengan RegEx secara aman\n            \/\/ karena DOMParser terkadang menormalisasi tag XML menjadi elemen aneh.\n            let preParsedHTML = rawHTML;\n            if (optMsWord.checked) {\n                \/\/ Menghapus tag XML Word (seperti <o:p>, <w:sdt>)\n                const xmlTagRegex = \/<\\\/?\\w+:[^>]*>\/gi;\n                const matches = preParsedHTML.match(xmlTagRegex);\n                if (matches) elRemovedCount += matches.length;\n                preParsedHTML = preParsedHTML.replace(xmlTagRegex, '');\n                \n                \/\/ Menghapus tag conditional mso:\n                \/\/ Menggunakan \\x3C (Hex) alih-alih simbol \"<\" langsung agar WordPress \n                \/\/ tidak merusak dan memutus block tag Script HTML kita.\n                const msoRegex = \/\\x3C!--\\[if[^>]*]>[\\s\\S]*?<!\\[endif\\]--\\x3E\/gi;\n                const msoMatches = preParsedHTML.match(msoRegex);\n                if (msoMatches) elRemovedCount += msoMatches.length;\n                preParsedHTML = preParsedHTML.replace(msoRegex, '');\n            }\n\n            \/\/ 2. Gunakan DOMParser untuk membuat Virtual DOM Sandboxing\n            const parser = new DOMParser();\n            const doc = parser.parseFromString(preParsedHTML, 'text\/html');\n            const body = doc.body; \/\/ Kita hanya butuh konten dalam body\n\n            \/\/ 3. Node Traversal: Menyisir dan membersihkan elemen DOM satu per satu\n            const walker = document.createTreeWalker(body, NodeFilter.SHOW_ALL, null, false);\n            const nodesToRemove = [];\n            const elementsToClean = [];\n\n            let currentNode;\n            while (currentNode = walker.nextNode()) {\n                \/\/ Proses Komentar HTML\n                if (currentNode.nodeType === Node.COMMENT_NODE) {\n                    if (optComments.checked) {\n                        nodesToRemove.push(currentNode);\n                    }\n                } \n                \/\/ Proses Elemen HTML biasa (<div>, <p>, <span>, dll)\n                else if (currentNode.nodeType === Node.ELEMENT_NODE) {\n                    elementsToClean.push(currentNode);\n                }\n            }\n\n            \/\/ Eksekusi penghapusan node (Komentar & Tag kosong)\n            nodesToRemove.forEach(function(node) {\n                node.parentNode.removeChild(node);\n                elRemovedCount++;\n            });\n\n            \/\/ Eksekusi pembersihan atribut dan tag kosong dari bawah ke atas\n            \/\/ (Reverse loop penting agar penghapusan elemen kosong tidak merusak iterasi indeks)\n            for (let i = elementsToClean.length - 1; i >= 0; i--) {\n                const el = elementsToClean[i];\n\n                \/\/ Hapus atribut style\n                if (optStyles.checked) {\n                    if (el.hasAttribute('style')) {\n                        el.removeAttribute('style');\n                        attrRemovedCount++;\n                    }\n                }\n\n                \/\/ Hapus atribut class dan id\n                if (optClasses.checked) {\n                    if (el.hasAttribute('class')) { el.removeAttribute('class'); attrRemovedCount++; }\n                    if (el.hasAttribute('id')) { el.removeAttribute('id'); attrRemovedCount++; }\n                }\n\n                \/\/ Hapus atribut kotor sisa dari Word (lang=\"...\" atau atribut namespace aneh)\n                if (optMsWord.checked) {\n                    const attrs = [...el.attributes];\n                    attrs.forEach(function(attr) {\n                        if (attr.name.includes(':') || attr.name === 'lang' || attr.name === 'data-uw-rm-sr') {\n                            el.removeAttribute(attr.name);\n                            attrRemovedCount++;\n                        }\n                    });\n                    \n                    \/\/ Unwrap (keluarkan teks dari) elemen span yang sudah tidak memiliki atribut\n                    \/\/ Sering terjadi dari Word: <span>Teks Biasa<\/span> -> Teks Biasa\n                    if (el.tagName.toLowerCase() === 'span' && el.attributes.length === 0) {\n                        while (el.firstChild) {\n                            el.parentNode.insertBefore(el.firstChild, el);\n                        }\n                        el.parentNode.removeChild(el);\n                        elRemovedCount++;\n                        continue; \/\/ Lewati pengecekan empty tag jika sudah di-unwrap\n                    }\n                }\n\n                \/\/ Hapus Empty Tags (Tag kosong seperti <p><\/p> atau <div><\/div>)\n                \/\/ Mengecualikan tag void seperti img, br, hr, input\n                if (optEmptyTags.checked) {\n                    const isVoidElement = ['IMG', 'BR', 'HR', 'INPUT', 'META', 'LINK'].includes(el.tagName);\n                    const isEmptyText = el.textContent.trim() === '';\n                    \/\/ Jika tag bukan void, tidak punya child element, dan teksnya kosong, maka hapus\n                    if (!isVoidElement) {\n                        if (el.children.length === 0) {\n                            if (isEmptyText) {\n                                el.parentNode.removeChild(el);\n                                elRemovedCount++;\n                            }\n                        }\n                    }\n                }\n            }\n\n            \/\/ 4. Proses Akhir: Ambil HTML bersih dari DOM\n            let finalHTML = body.innerHTML;\n\n            \/\/ 5. Beautify jika diaktifkan\n            if (optBeautify.checked) {\n                finalHTML = beautifyHTML(finalHTML);\n            } else {\n                \/\/ Minify secara sederhana jika beautify tidak dicentang\n                finalHTML = finalHTML.replace(\/>\\s+<\/g, '><').trim();\n            }\n\n            \/\/ 6. Tampilkan Hasil ke Layar\n            elOutput.value = finalHTML;\n            btnCopy.disabled = false; \/\/ Aktifkan tombol copy\n\n            \/\/ 7. Kalkulasi &#038; Update Statistik\n            const finalBytes = getByteSize(finalHTML);\n            labelOutputSize.textContent = formatBytes(finalBytes);\n            \n            statElRemoved.textContent = elRemovedCount;\n            statAttrRemoved.textContent = attrRemovedCount;\n            \n            let reductionPercent = 0;\n            if (initialBytes > 0) {\n                reductionPercent = Math.round(((initialBytes - finalBytes) \/ initialBytes) * 100);\n            }\n            \n            const spaceSavedEl = document.getElementById('stat-space-saved');\n            spaceSavedEl.textContent = reductionPercent + '%';\n            \n            \/\/ Ubah warna text size reduction jika kode justru bertambah ukurannya (karena beautify)\n            if (reductionPercent < 0) {\n                spaceSavedEl.style.color = 'var(--wpnt-warning)';\n            } else {\n                spaceSavedEl.style.color = 'var(--wpnt-success)';\n            }\n\n            showToast('HTML Successfully Cleaned!');\n        }\n\n        \/\/ --- EVENT LISTENERS ---\n        \n        \/\/ Klik tombol Clean\n        btnClean.addEventListener('click', processHTML);\n\n        \/\/ Fitur Copy ke Clipboard\n        btnCopy.addEventListener('click', function() {\n            if (!elOutput.value) return;\n            \n            elOutput.select();\n            \/\/ Fallback modern clipboard API atau executeCommand\n            let isCopied = false;\n            if (navigator.clipboard) {\n                if (window.isSecureContext) {\n                    navigator.clipboard.writeText(elOutput.value).then(function() {\n                        showToast('Cleaned HTML Copied to Clipboard!');\n                    });\n                    isCopied = true;\n                }\n            }\n            \n            if (!isCopied) {\n                document.execCommand('copy');\n                showToast('Cleaned HTML Copied to Clipboard!');\n            }\n        });\n\n        \/\/ Klik tombol Clear All\n        btnClear.addEventListener('click', function() {\n            elInput.value = '';\n            elOutput.value = '';\n            btnCopy.disabled = true;\n            \n            \/\/ Reset Stats\n            labelInputSize.textContent = '0 Bytes';\n            labelOutputSize.textContent = '0 Bytes';\n            statElRemoved.textContent = '0';\n            statAttrRemoved.textContent = '0';\n            document.getElementById('stat-space-saved').textContent = '0%';\n            document.getElementById('stat-space-saved').style.color = 'var(--wpnt-success)';\n        });\n\n        \/\/ Optional: Membersihkan secara otomatis saat ada proses Paste di input\n        elInput.addEventListener('paste', function() {\n            \/\/ Beri jeda kecil agar value textarea terisi terlebih dahulu\n            setTimeout(function() {\n                if (elInput.value.trim().length > 0) {\n                    processHTML();\n                }\n            }, 100);\n        });\n\n    })();\n<\/script>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sanepo Tools &#8211; HTML Cleaner Instantly purify dirty HTML code from MS Word, Google Docs, or other websites. 100% Client-Side (No Data Uploaded) Dirty HTML Input 0 Bytes Cleaned Result 0 Bytes Cleaning Rules Strip Inline Styles Removes style=&#8221;&#8230;&#8221; attributes Strip Classes &#038; IDs Removes class=&#8221;&#8230;&#8221; and id=&#8221;&#8230;&#8221; Remove Comments Removes &lt;!&#8211; &#8230; &#8211;&gt; tags [&hellip;]<\/p>\n","protected":false},"featured_media":0,"template":"","meta":[],"class_list":["post-76","tool","type-tool","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/tools.sanepo.com\/ar\/wp-json\/wp\/v2\/tool\/76","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tools.sanepo.com\/ar\/wp-json\/wp\/v2\/tool"}],"about":[{"href":"https:\/\/tools.sanepo.com\/ar\/wp-json\/wp\/v2\/types\/tool"}],"wp:attachment":[{"href":"https:\/\/tools.sanepo.com\/ar\/wp-json\/wp\/v2\/media?parent=76"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}