<commit_before>const render_to_theme = 'theme_js';
const potential_theme_entries_div = 'theme0';

function render_theme() {
    display_grid(render_to_theme);

    let min_theme_len = 9; // TODO?: allow user to pick?
    let list_of_lists_of_potential_theme_entries = document.createElement('div');

    let buttonLabels = ['Clues', 'Entries'];
    let buttonActions = [function () { toggleByClass('clue') }, function () { toggleByClass('entry') }];
    add_buttons(list_of_lists_of_potential_theme_entries, buttonLabels, buttonActions);

    create_twisty(list_of_lists_of_potential_theme_entries, 'toggle-starred', 'starred');
    add_named_section(list_of_lists_of_potential_theme_entries, 'STARRED CLUES',
        display_starred_clues(window.puzdata));

    create_twisty(list_of_lists_of_potential_theme_entries, 'toggle-long', 'long');
    add_named_section(list_of_lists_of_potential_theme_entries, 'LONG ENTRIES',
        display_long_entries_and_common_substrings(window.puzdata, min_theme_len));

    document.getElementById(potential_theme_entries_div).appendChild(list_of_lists_of_potential_theme_entries);
}

// append a <div> containing n <button> elements defined by an n-sized array of labels
// and an n-sized array of onClick() functions that are invoked when clicking said buttons
function add_buttons(parent, labelsArr, onClickArr) {
    "use strict";
    let buttons = document.createElement('div');
    for (let i = 0; i < labelsArr.length; ++i) {
        let b = document.createElement('button');
        b.appendChild(document.createTextNode(labelsArr[i]));
        b.onclick = function () { onClickArr[i]() };
        buttons.appendChild(b);
    }
    parent.appendChild(buttons);
}

// prepend to a given parent a clickable '▸' character to toggle display
// assigns the id 'toggleName' to the
function create_twisty(parent, toggleName, toggledId) {
    "use strict";

    let showHide = document.createElement('input');
    showHide.type = 'checkbox';
    showHide.id = toggleName;
    showHide.style.display = 'none';
    showHide.onclick = function () { toggleById(toggledId) };

    let toggled = document.createTextNode('▾');
    let untoggled = document.createTextNode('▸');

    let toggleLabel = document.createElement('label');
    toggleLabel.id = 'shown';
    toggleLabel.htmlFor = toggleName;
    toggleLabel.style.float = 'left';
    toggleLabel.style.marginRight = '5px';
    toggleLabel.appendChild(toggled);
    toggleLabel.onclick = function () { swap_label(toggleLabel, toggled, untoggled) };

    parent.appendChild(showHide);
    parent.appendChild(toggleLabel);
}

function swap_label(item, toggled, untoggled) {
    "use strict";
    let textNode = item.childNodes[0];
    if (textNode == toggled) {
        item.replaceChild(untoggled, item.childNodes[0]);
    } else {
        item.replaceChild(toggled, item.childNodes[0]);
    }
}

function add_named_section(all_items, heading, addedElements, classToAdd, styleToApply) {
    let heading_item = document.createElement('div');
    if (!(typeof classToAdd === 'undefined') || !(classToAdd == null)) {
        heading_item.className = classToAdd;
    }
    if (!(typeof styleToApply === 'undefined') || !(styleToApply == null)) {
        heading_item.style = styleToApply;
    }
    heading_item.appendChild(document.createTextNode(heading));
    all_items.appendChild(heading_item);
    all_items.appendChild(addedElements);
}

function display_starred_clues(puzdata) {
    let retval = document.createElement('div');
    retval.className = 'items indent';
    retval.id = 'starred';

    var across_clues = puzdata.clues[0].clue;
    var down_clues = puzdata.clues[1].clue;
    var entry_map = puzdata.get_entry_mapping();
    let starred_across = getCluesPreOrPostfixedWith(across_clues, '*', entry_map, 'A');
    let starred_down = getCluesPreOrPostfixedWith(down_clues, '*', entry_map, 'D');

    let starred_clues = starred_across.clues.concat(starred_down.clues);

    if (starred_clues.length == 0) {
        let empty_item = document.createElement('div');
        let newChild = document.createTextNode('<none>');
        empty_item.appendChild(newChild);
        retval.appendChild(empty_item);
    } else {
        let items = document.createElement('div');
        items.className = 'indent';
        add_items(items, starred_across.entries, starred_across.clues);
        add_items(items, starred_down.entries, starred_down.clues);

        retval.appendChild(items);
    }
    return retval;
}

function add_items(elem, entries, clues) {
    "use strict";
    for (let i = 0; i < entries.length; ++i) {
        let clueDiv = document.createElement('div');
        let entryDiv = document.createElement('div');
        let clue = document.createElement('span');
        let entry = document.createElement('span');
        clueDiv.className = 'clue';
        entryDiv.className = 'entry';
        if (i % 2 === 0) {
            clueDiv.className += ' hilight';
            entryDiv.className += ' hilight';
        }
        clue.appendChild(document.createTextNode(clues[i]));
        entry.appendChild(document.createTextNode(entries[i]));
        clueDiv.appendChild(clue);
        entryDiv.appendChild(entry);
        elem.appendChild(clueDiv);
        elem.appendChild(entryDiv);
    }
}

function getCluesPreOrPostfixedWith(clues, token, entries, type) {
    let retClues = [];
    let retEntries = [];

    for (let i in clues) {
      var clue_num = clues[i].number;
      var clue_text = clues[i].text;
      var clue_entry = entries[clue_num];
      if (clue_text.startsWith(token) || clue_text.endsWith(token)) {
        retClues.push(clue_num + type + ' [' + clue_text + ']');
        retEntries.push(entries[clue_num]);<commit_msg>fix entries for STARRED CLUES in Theme tab<commit_after>const render_to_theme = 'theme_js';
const potential_theme_entries_div = 'theme0';

function render_theme() {
    display_grid(render_to_theme);

    let min_theme_len = 9; // TODO?: allow user to pick?
    let list_of_lists_of_potential_theme_entries = document.createElement('div');

    let buttonLabels = ['Clues', 'Entries'];
    let buttonActions = [function () { toggleByClass('clue') }, function () { toggleByClass('entry') }];
    add_buttons(list_of_lists_of_potential_theme_entries, buttonLabels, buttonActions);

    create_twisty(list_of_lists_of_potential_theme_entries, 'toggle-starred', 'starred');
    add_named_section(list_of_lists_of_potential_theme_entries, 'STARRED CLUES',
        display_starred_clues(window.puzdata));

    create_twisty(list_of_lists_of_potential_theme_entries, 'toggle-long', 'long');
    add_named_section(list_of_lists_of_potential_theme_entries, 'LONG ENTRIES',
        display_long_entries_and_common_substrings(window.puzdata, min_theme_len));

    document.getElementById(potential_theme_entries_div).appendChild(list_of_lists_of_potential_theme_entries);
}

// append a <div> containing n <button> elements defined by an n-sized array of labels
// and an n-sized array of onClick() functions that are invoked when clicking said buttons
function add_buttons(parent, labelsArr, onClickArr) {
    "use strict";
    let buttons = document.createElement('div');
    for (let i = 0; i < labelsArr.length; ++i) {
        let b = document.createElement('button');
        b.appendChild(document.createTextNode(labelsArr[i]));
        b.onclick = function () { onClickArr[i]() };
        buttons.appendChild(b);
    }
    parent.appendChild(buttons);
}

// prepend to a given parent a clickable '▸' character to toggle display
// assigns the id 'toggleName' to the
function create_twisty(parent, toggleName, toggledId) {
    "use strict";

    let showHide = document.createElement('input');
    showHide.type = 'checkbox';
    showHide.id = toggleName;
    showHide.style.display = 'none';
    showHide.onclick = function () { toggleById(toggledId) };

    let toggled = document.createTextNode('▾');
    let untoggled = document.createTextNode('▸');

    let toggleLabel = document.createElement('label');
    toggleLabel.id = 'shown';
    toggleLabel.htmlFor = toggleName;
    toggleLabel.style.float = 'left';
    toggleLabel.style.marginRight = '5px';
    toggleLabel.appendChild(toggled);
    toggleLabel.onclick = function () { swap_label(toggleLabel, toggled, untoggled) };

    parent.appendChild(showHide);
    parent.appendChild(toggleLabel);
}

function swap_label(item, toggled, untoggled) {
    "use strict";
    let textNode = item.childNodes[0];
    if (textNode == toggled) {
        item.replaceChild(untoggled, item.childNodes[0]);
    } else {
        item.replaceChild(toggled, item.childNodes[0]);
    }
}

function add_named_section(all_items, heading, addedElements, classToAdd, styleToApply) {
    let heading_item = document.createElement('div');
    if (!(typeof classToAdd === 'undefined') || !(classToAdd == null)) {
        heading_item.className = classToAdd;
    }
    if (!(typeof styleToApply === 'undefined') || !(styleToApply == null)) {
        heading_item.style = styleToApply;
    }
    heading_item.appendChild(document.createTextNode(heading));
    all_items.appendChild(heading_item);
    all_items.appendChild(addedElements);
}

function display_starred_clues(puzdata) {
    let retval = document.createElement('div');
    retval.className = 'items indent';
    retval.id = 'starred';

    var across_clues = puzdata.clues[0].clue;
    var down_clues = puzdata.clues[1].clue;
    var entry_map = puzdata.get_entry_mapping();
    let starred_across = getCluesPreOrPostfixedWith(across_clues, '*', entry_map, 'A');
    let starred_down = getCluesPreOrPostfixedWith(down_clues, '*', entry_map, 'D');

    let starred_clues = starred_across.clues.concat(starred_down.clues);

    if (starred_clues.length == 0) {
        let empty_item = document.createElement('div');
        let newChild = document.createTextNode('<none>');
        empty_item.appendChild(newChild);
        retval.appendChild(empty_item);
    } else {
        let items = document.createElement('div');
        items.className = 'indent';
        add_items(items, starred_across.entries, starred_across.clues);
        add_items(items, starred_down.entries, starred_down.clues);

        retval.appendChild(items);
    }
    return retval;
}

function add_items(elem, entries, clues) {
    "use strict";
    for (let i = 0; i < entries.length; ++i) {
        let clueDiv = document.createElement('div');
        let entryDiv = document.createElement('div');
        let clue = document.createElement('span');
        let entry = document.createElement('span');
        clueDiv.className = 'clue';
        entryDiv.className = 'entry';
        if (i % 2 === 0) {
            clueDiv.className += ' hilight';
            entryDiv.className += ' hilight';
        }
        clue.appendChild(document.createTextNode(clues[i]));
        entry.appendChild(document.createTextNode(entries[i]));
        clueDiv.appendChild(clue);
        entryDiv.appendChild(entry);
        elem.appendChild(clueDiv);
        elem.appendChild(entryDiv);
    }
}

function getCluesPreOrPostfixedWith(clues, token, entries, type) {
    let retClues = [];
    let retEntries = [];

    for (let i in clues) {
      var clue_num = clues[i].number;
      var clue_text = clues[i].text;
      var clue_entry = entries[Number(i)+1]; /* dictionary is 1-based */
      if (clue_text.startsWith(token) || clue_text.endsWith(token)) {
        retClues.push(clue_num + type + ' [' + clue_text + ']');
        retEntries.push(clue_entry);
{'fraction_non_alphanumeric': 0.12537829658452226, 'fraction_numerical': 0.002421098140942499, 'mean_word_length': 3.8393305439330545, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '166779', 'n_tokens_mistral': 3592, 'n_tokens_neox': 3522, 'n_words': 687}