getWebviewMarkup()

in src/cache-view.ts [258:540]


    getWebviewMarkup() {
        const key = '%TABLE_ROWS%';
        const searchButtonText = localize("search", "Search");
        const saveButtonText = localize("save", "Save");
        const keyColumnText = localize("key", "Key");
        const valueColumnText = localize("value", "Value");

        let html = `
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>${this.cmakeCacheEditorText}</title>
        <style>
          .select-default {
              width: 300px;
              height: 25px;
              font-size: 13px;
              font-family:sans-serif;
              color: var(--vscode-settings-dropdownForeground);
              background: var(--vscode-settings-dropdownBackground);
              border: 1px solid var(--vscode-settings-dropdownBorder);
          }

          input {
            height: 17px;
            padding: 6px;
            border: solid 1px;
            font-size: 13px;
            font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
            color: var(--vscode-settings-textInputForeground);
            background: var(--vscode-settings-textInputBackground);
            border: 1px solid var(--vscode-settings-textInputBorder);
          }

          .invalid-selection {
            background-color: #4e2621;
          }

          .vscode-light .input-disabled {
              background-color:rgba(255, 255, 255, 0.4);
              color: rgb(138, 138, 138);
              border: solid 1px rgb(201, 198, 198);
          }

          .vscode-dark .input-disabled {
              background-color: rgba(255, 255, 255, 0.1);
              color: rgb(167, 167, 167);
          }

          .vscode-high-contrast .input-disabled {
               background-color: transparent;
               color: #fff;
               border: solid 1px rgb(255, 255, 255);
          }

          .vscode-high-contrast code > div {
              background-color: #000
          }

          .vscode-high-contrast h1 {
              border-color: #000
          }

          .vscode-light {
              color: #1e1e1e
          }
          .vscode-dark {
              color: #ddd
          }
          .vscode-high-contrast {
              color: #fff
          }
          .vscode-light table,
          .vscode-high-contrast table {
            border: 1px solid var(--vscode-settings-textInputBorder);
            border-collapse: collapse;
          }
          .vscode-dark table {
            border: 1px solid rgb(255,255,255,0.3);
            border-collapse: collapse;
          }
          .container {
            padding-right: 15px;
            padding-left: 15px;
            width: 760px;
            margin: 30px auto;
          }
          tr {
            height: 25px;
          }
          .vscode-light th {
            background: rgba(0,0,0,.1);
          }
          .vscode-dark th {
            background: rgba(255,255,255,.1);
          }
          input#search {
            width: 98%;
            padding: 11px 0px 11px 11px;
            margin: 10px 0;
            color: var(--vscode-settings-textInputForeground);
            background: var(--vscode-settings-textInputBackground);
            border: 1px solid var(--vscode-settings-textInputBorder);
          }
          .invisible {
            display: none;
          }
          button#save {
            float: right;
            padding: 10px 25px;
            margin-top: 15px;
            background: var(--vscode-button-background);
            color: var(--vscode-button-foreground);
            text-transform: uppercase;
            font-weight: bold;
            border: solid 1px var(--vscode-contrastBorder);
            transition: 100ms ease-in-out;
          }
          button#save:hover {
            cursor: pointer;
            background-color: var(--vscode-button-hoverBackground);
          }
          button#save:focus,
          button#save input:focus,
          button#save select:focus {
            outline: 1px solid -webkit-focus-ring-color;
            outline-offset: 2px;
            border-color: var(--vscode-focusBorder);
            border: var(--vscode-focusBorder);
            contrastBorder: var(--vscode-focusBorder);
            contrastActiveBorder: var(--vscode-focusBorder);
          }
          button#save:active {
            outline: none;
          }

          checkbox:active,
          checkbox {
            color: var(--vscode-settings-checkboxForeground);
            background: var(--vscode-settings-checkboxForeground);
            border: var(--vscode-settings-checkboxBorder);
          }

          .vscode-light cmake-input-bool input:checked,
          .vscode-dark cmake-input-bool {
            color: var(--vscode-settings-checkboxForeground);
            background: var(--vscode-settings-checkboxForeground);
            border: var(--vscode-settings-checkboxBorder);
          }

          .cmake-input-bool input:checked,
          .cmake-input-bool:active,
          .cmake-input-bool {
            color: var(--vscode-settings-checkboxForeground);
            background: var(--vscode-settings-checkboxForeground);
            border: var(--vscode-settings-checkboxBorder);
          }
          a:focus,
          input:focus,
          select:focus,
          textarea:focus {
              outline: 1px solid -webkit-focus-ring-color;
              outline-offset: -1px;
              border-color: var(--vscode-focusBorder);
              contrastBorder: var(--vscode-focusBorder);
              contrastActiveBorder: var(--vscode-focusBorder);
          }
        </style>
        <script>
          const vscode = acquireVsCodeApi();
          function updateCheckboxState(checkbox) {
            checkbox.labels.forEach(label => label.textContent = checkbox.checked ? 'ON' : 'OFF');
          }
          function toggleKey(checkbox) {
            updateCheckboxState(checkbox);
            vscode.postMessage({key: checkbox.id, type: "Bool", value: checkbox.checked});
            document.getElementById('not-saved').classList.remove('invisible');
          }
          function validateInput(editbox) {
            const list = editbox.list;
            if (list) {
              let found = false;
              for (const opt of list.options) {
                if (opt.value === editbox.value) {
                  found = true;
                  break;
                }
              }
              editbox.classList.toggle('invalid-selection', !found);
            }
          }
          function edit(editbox) {
            validateInput(editbox);
            vscode.postMessage({key: editbox.id, type: "String", value: editbox.value});
            document.getElementById('not-saved').classList.remove('invisible');
          }
          function save() {
            document.getElementById('not-saved').classList.add('invisible');
            vscode.postMessage(false);
          }
          function search() {
            const filter = document.getElementById('search').value.toLowerCase();
            for (const tr of document.querySelectorAll('.content-tr')) {
              if (!tr.innerHTML.toLowerCase().includes(filter)) {
                tr.classList.add('invisible');
              } else {
                tr.classList.remove('invisible');
              }
            }
          }

          window.onload = function() {
            document.querySelectorAll('.cmake-input-bool').forEach(checkbox => {
              updateCheckboxState(checkbox);
              checkbox.onclick = () => toggleKey(checkbox);
            });
            document.querySelectorAll('.cmake-input-text').forEach(editbox => {
              validateInput(editbox)
              editbox.oninput = () => edit(editbox);
            });
          }
        </script>
    </head>
    <body>
      <div class="container">
        <button id="save" onclick="save()">${saveButtonText}</button>
        <h1>${this.cmakeCacheEditorText}<span class="invisible" id="not-saved">*</span></h1>
        <input class="search" type="text" id="search" oninput="search()" placeholder="${searchButtonText}" autofocus>
        <table style="width:100%">
          <tr style="height: 25px;">
            <th style="width: 30px"></th>
            <th style="width: 1px; white-space: nowrap;">${keyColumnText}</th>
            <th>${valueColumnText}</th>
          </tr>
          ${key}
        </table>
      </div>
    </body>
    </html>`;

        // compile a list of table rows that contain the key and value pairs
        const tableRows = this._options.map(option => {

            // HTML attributes may not contain literal double quotes or ambiguous ampersands
            const escapeAttribute = (text: string) => text.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
            // Escape HTML special characters that may not occur literally in any text
            const escapeHtml = (text: string) =>
                escapeAttribute(text)
                    .replace(/</g, "&lt;")
                    .replace(/>/g, "&gt;")
                    .replace(/'/g, "&#039;")
                    .replace(/ /g, "&nbsp;"); // we are usually dealing with single line entities - avoid unintential line breaks

            const id = escapeAttribute(option.key);
            let editControls = '';

            if (option.type === "Bool") {
                editControls = `<input class="cmake-input-bool" id="${id}" type="checkbox" ${util.isTruthy(option.value) ? 'checked' : ''}>
          <label id="LABEL_${id}" for="${id}"/>`;
            } else {
                const hasChoices = option.choices.length > 0;
                if (hasChoices) {
                    editControls = `<datalist id="CHOICES_${id}">
            ${option.choices.map(ch => `<option value="${escapeAttribute(ch)}">`).join()}
          </datalist>`;
                }
                editControls += `<input class="cmake-input-text" id="${id}" value="${escapeAttribute(option.value)}" style="width: 90%;"
          type="text" ${hasChoices ? `list="CHOICES_${id}"` : ''}>`;
            }

            return `<tr class="content-tr">
      <td></td>
      <td title="${escapeAttribute(option.helpString)}">${escapeHtml(option.key)}</td>
      <td>${editControls}</td>
    </tr>`;
        });

        html = html.replace(key, tableRows.join(""));

        return html;
    }