// ==UserScript== // @name DTextStyler // @namespace https://github.com/BrokenEagle/JavaScripts // @version 5.6 // @description Danbooru DText UI addon. // @source https://danbooru.donmai.us/users/23799 // @author BrokenEagle // @match *://*.donmai.us/* // @exclude /^https?://\w+\.donmai\.us/.*\.(xml|json|atom)(\?|$)/ // @grant none // @run-at document-end // @downloadURL https://raw.githubusercontent.com/BrokenEagle/JavaScripts/master/DTextStyler.user.js // @updateURL https://raw.githubusercontent.com/BrokenEagle/JavaScripts/master/DTextStyler.user.js // @require https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.2/papaparse.min.js // @require https://raw.githubusercontent.com/BrokenEagle/JavaScripts/20220515/lib/module.js // @require https://raw.githubusercontent.com/BrokenEagle/JavaScripts/20220515/lib/debug.js // @require https://raw.githubusercontent.com/BrokenEagle/JavaScripts/20220515/lib/utility.js // @require https://raw.githubusercontent.com/BrokenEagle/JavaScripts/20220515/lib/validate.js // @require https://raw.githubusercontent.com/BrokenEagle/JavaScripts/20220515/lib/storage.js // @require https://raw.githubusercontent.com/BrokenEagle/JavaScripts/20220515/lib/network.js // @require https://raw.githubusercontent.com/BrokenEagle/JavaScripts/20220515/lib/load.js // @require https://raw.githubusercontent.com/BrokenEagle/JavaScripts/20240223-menu/lib/menu.js // ==/UserScript== /* global JSPLib $ Danbooru Papa */ /****Global variables****/ // Library constants ////NONE //Exterior script variables const DANBOORU_TOPIC_ID = '14229'; const GITHUB_WIKI_PAGE = 'https://github.com/BrokenEagle/JavaScripts/wiki/DtextStyler'; //Variables for load.js const PROGRAM_LOAD_REQUIRED_VARIABLES = ['window.jQuery', 'window.Danbooru', 'Danbooru.Upload']; const PROGRAM_LOAD_OPTIONAL_SELECTORS = ['.dtext-previewable textarea', '#add-commentary-dialog', '.upload_artist_commentary_container', '#c-users #a-edit']; //Program name constants const PROGRAM_SHORTCUT = 'ds'; const PROGRAM_CLICK = 'click.ds'; const PROGRAM_KEYUP = 'keyup.ds'; const PROGRAM_NAME = 'DTextStyler'; //Main program variable const DS = {}; const DEFAULT_VALUES = { mode: 'edit', }; //Available setting values const ALL_TYPES = ['comment', 'forum', 'wiki', 'pool', 'dmail']; const ALL_MARKUP = ['bold', 'italic', 'underline', 'strikethrough', 'translation', 'spoiler', 'code', 'nodtext', 'quote', 'expand', 'textile_link', 'wiki_link', 'named_link', 'search_link', 'full_table', 'headless_table']; const ALL_ACTIONS = ['undo', 'redo']; //Main settings const SETTINGS_CONFIG = { post_commentary_enabled: { reset: true, validate: JSPLib.validate.isBoolean, hint: "Show dtext controls on the post commentary dialog." }, upload_commentary_enabled: { reset: true, validate: JSPLib.validate.isBoolean, hint: "Show dtext controls above the upload commentary inputs." }, dtext_types_handled: { allitems: ALL_TYPES, reset: ALL_TYPES, validate: (data) => JSPLib.menu.validateCheckboxRadio(data, 'checkbox', ALL_TYPES), hint: "Show dtext controls above the preview area for the available types.", }, available_dtext_markup: { allitems: ALL_MARKUP, reset: ALL_MARKUP, validate: (data) => (JSPLib.menu.validateCheckboxRadio(data, 'checkbox', ALL_MARKUP) && (data.length > 0)), hint: "Select the list of available DText tags to be shown. Must have at least one.", }, available_dtext_actions: { allitems: ALL_ACTIONS, reset: ALL_ACTIONS, validate: (data) => JSPLib.menu.validateCheckboxRadio(data, 'checkbox', ALL_ACTIONS), hint: "Select the list of available DText actions to be shown.", }, } const MENU_CONFIG = { topic_id: DANBOORU_TOPIC_ID, wiki_page: GITHUB_WIKI_PAGE, settings: [{ name: 'general', },{ name: 'main', },{ name: 'commentary', },{ name: 'controls', }], controls: [], }; //CSS constants const PROGRAM_CSS = ` /** General **/ /**** Preview ****/ .ds-preview-display { max-height: 300px; overflow-y: auto; } .ds-preview-display .ds-section { border: 1px solid #EEE; padding: 5px; } .ds-preview-display .ds-section-header { font-size: var(--text-lg); font-weight: bold; text-decoration: underline; margin: 0.5rem 0; } /**** Markup buttons ****/ .ds-markup-headers > div, .ds-markup-headers > div > div, .ds-buttons > div, .ds-buttons > div > div { display: inline-block; } .ds-markup-headers > div > div { text-align: center; font-weight: bold; } .dtext-button { width: 40px; height: 40px; position: relative; } .dtext-button > * { position: absolute; } .ds-translate-content { font-size: 16px; font-weight: bold; white-space: nowrap; }`; const POST_CSS = ` /** Posts page **/ form#fetch-commentary input#commentary_source { max-width: 75%; } form#edit-commentary input#artist_commentary_original_title, form#edit-commentary input#artist_commentary_translated_title { max-width: 100%; } button.ds-dialog-button[name=Cancel] { color: white; background: red; } button.ds-dialog-button[name=Submit] { color: white; background: green; }`; const UPLOAD_CSS = ` /** Uploads page **/ #ds-commentary-container { width: 65rem; background: #F8F8F8; border: 2px solid #EEE; box-shadow: 0 0 0 2px #DEF; padding: 10px; margin: 10px 0; } #ds-commentary-container .ds-markup-controls { border-bottom: 1px solid #DDD; padding-bottom: 5px; margin-bottom: 10px; } #edit-dialog #ds-commentary-container { display: none; /* Hide commentary when the tag box is detached */ } #ds-commentary-buttons { border-top: 2px solid #DDD; padding-top: 5px; } .ds-commentary-button { display: inline-block; } #ds-remove-button { color: white; background: red; }`; const MENU_CSS = ` .jsplib-selectors.ds-selectors[data-setting="dtext_types_handled"] label { width: 120px; } .jsplib-selectors.ds-selectors[data-setting="available_dtext_markup"] label { width: 150px; }`; //HTML constants const BOLD_CONTENT = ''; const ITALIC_CONTENT = ''; const UNDERLINE_CONTENT = ''; const STRIKETHROUGH_CONTENT = ''; const TRANSLATION_CONTENT = '
Aあ
'; const QUOTE_CONTENT = ''; const EXPAND_CONTENT = ''; const SPOILER_CONTENT = ''; const CODE_CONTENT = ''; const NODTEXT_CONTENT = ' '; const TEXTILELINK_CONTENT = ''; const NAMEDLINK_CONTENT = ''; const WIKILINK_CONTENT = ''; const SEARCHLINK_CONTENT = ''; const FULL_TABLE_CONTENT = ''; const HEADLESS_TABLE_CONTENT = ''; const UNDO_CONTENT = ''; const REDO_CONTENT = ''; const MARKUP_CONTROLS = `
%s
%s
`; const PREVIEW_SECTION = `
%s
`; const PREVIEW_BUTTONS = `
`; //Config constants const MARKUP_BUTTON_CONFIG = { bold: { stripped: false, inline: true, block: false, prefix: '[b]', suffix: '[/b]', top: '12px', left: '15px', content: BOLD_CONTENT, }, italic: { stripped: false, inline: true, block: false, prefix: '[i]', suffix: '[/i]', top: '12px', left: '16px', content: ITALIC_CONTENT, }, underline: { stripped: false, inline: true, block: false, prefix: '[u]', suffix: '[/u]', top: '12px', left: '11px', content: UNDERLINE_CONTENT, }, strikethrough: { stripped: false, inline: true, block: false, prefix: '[s]', suffix: '[/s]', top: '12px', left: '11px', content: STRIKETHROUGH_CONTENT, }, translation: { stripped: true, inline: true, block: true, prefix: '[tn]', suffix: '[/tn]', top: '10px', left: '6px', content: TRANSLATION_CONTENT, }, spoiler: { stripped: true, inline: true, block: true, prefix: '[spoiler]', suffix: '[/spoiler]', top: '12px', left: '10px', content: SPOILER_CONTENT, }, code: { stripped: false, inline: true, block: true, prefix: '[code]', suffix: '[/code]', top: '12px', left: '14px', content: CODE_CONTENT, }, nodtext: { stripped: false, inline: true, block: true, prefix: '[nodtext]', suffix: '[/nodtext]', top: '4px', left: '5px', content: NODTEXT_CONTENT, }, quote: { stripped: true, inline: false, block: true, prefix: '[quote]', suffix: '[/quote]', top: '12px', left: '14px', content: QUOTE_CONTENT, }, expand: { stripped: true, inline: false, block: true, prefix: '[expand]', suffix: '[/expand]', top: '12px', left: '10px', content: EXPAND_CONTENT, }, textile_link: { stripped: false, inline: true, block: false, prefix: '"', suffix: '":[url]', select_func: (text_area, _cursor_start, cursor_end)=>{ text_area.setSelectionRange(cursor_end - 4, cursor_end - 1); }, top: '12px', left: '12px', content: TEXTILELINK_CONTENT, }, wiki_link: { stripped: false, inline: true, block: false, prefix: '[[', suffix: ']]', top: '13px', left: '11px', content: WIKILINK_CONTENT, }, named_link: { stripped: false, inline: true, block: false, prefix: '[[', suffix: '|wiki_name]]', select_func: (text_area, _cursor_start, cursor_end)=>{ text_area.setSelectionRange(cursor_end - 11, cursor_end - 2); }, top: '11px', left: '12px', content: NAMEDLINK_CONTENT, }, search_link: { stripped: false, inline: true, block: false, prefix: '{{', suffix: '}}', top: '13px', left: '10px', content: SEARCHLINK_CONTENT, }, full_table: { markup: (text_area)=>{TableMarkup(text_area, true);}, top: '12px', left: '10px', content: FULL_TABLE_CONTENT, }, headless_table: { markup: (text_area)=>{TableMarkup(text_area, false);}, top: '10px', left: '10px', content: HEADLESS_TABLE_CONTENT, }, }; const ACTION_BUTTON_CONFIG = { undo: { action: (text_area)=>{UndoAction(text_area);}, top: '9px', left: '9px', content: UNDO_CONTENT, }, redo: { action: (text_area)=>{RedoAction(text_area);}, top: '9px', left: '9px', content: REDO_CONTENT, }, }; const MARKUP_SECTION_CONFIG = { font: { color: 'beige', buttons: ['bold', 'italic', 'underline', 'strikethrough'], }, special: { color: 'lightgreen', buttons: ['translation', 'spoiler', 'code', 'nodtext'], }, blocks: { color: 'orange', buttons: ['quote', 'expand'], }, links: { color: 'lightblue', buttons: ['textile_link', 'wiki_link', 'named_link', 'search_link'], }, tables: { color: 'pink', buttons: ['full_table', 'headless_table'], }, }; const ACTION_SECTION_CONFIG = { actions: { color: 'lightgrey', buttons: ['undo', 'redo'], }, }; const DIALOG_CONFIG = { Preview: function() { DS.$dialog_buttons.filter('[name=Preview]').hide(); DS.$dialog_buttons.filter('[name=Edit]').show(); DtextPreview(); }, Edit: function() { DS.$dialog_buttons.filter('[name=Preview]').show(); DS.$dialog_buttons.filter('[name=Edit]').hide(); DtextEdit(); }, }; //Other const DTEXT_SELECTORS = { comment: ['comment_body'], forum: ['forum_topic_original_post_body', 'forum_post_body'], wiki: ['wiki_page_body'], pool: ['pool_description'], dmail: ['dmail_body'], }; /****Functions****/ //Library functions ////NONE //Auxiliary functions function GetTextArea($obj) { let $text_areas = $obj.closest('.ds-container').find('textarea, input'); if ($text_areas.length <= 1) { var text_area = $text_areas.get(0); } else { text_area = (['TEXTAREA', 'INPUT'].includes(document.activeElement.tagName) && [...document.activeElement.classList].includes('ds-commentary-input') ? document.activeElement : null); } if (!text_area) { JSPLib.notice.error("No text input selected."); } else { DS.$close_notice.click(); } return text_area; } function MarkupSelectionText(text_area, config) { if ([...text_area.classList].includes('string') && config.stripped) { JSPLib.notice.notice("Block elements not available for inline DText."); return false; } SaveMarkup(text_area); let {prefix, suffix, block, inline, select_func} = config; let start_text = text_area.value.slice(0, text_area.selectionStart); let selection_text = text_area.value.slice(text_area.selectionStart, text_area.selectionEnd); let end_text = text_area.value.slice(text_area.selectionEnd); if ((block && !inline) || ((block && inline) && (selection_text.search('\n') >= 0))) { let starting_CRs = start_text.replace(/ /g, "").match(/\n*$/)[0].length; let ending_CRs = end_text.replace(/ /g, "").match(/^\n*/)[0].length; start_text = start_text + '\n'.repeat(Math.max(2 - starting_CRs)); end_text = '\n'.repeat(Math.max(2 - ending_CRs)) + end_text; var markup_text = prefix + '\n\n' + selection_text.trim() + '\n\n' + suffix; } else { markup_text = prefix + selection_text + suffix; } let cursor_start = start_text.length; let cursor_end = cursor_start + markup_text.length; let final_text = start_text + markup_text + end_text; final_text = final_text.replace(/^\s+/, ""); text_area.value = final_text; text_area.focus(); if (select_func) { select_func(text_area, cursor_start, cursor_end); } else { text_area.setSelectionRange(cursor_start, cursor_end); } return true; } function TableMarkup(text_area, has_header) { if ([...text_area.classList].includes('string')) { JSPLib.notice.notice("Block elements not available for inline DText."); return false; } SaveMarkup(text_area); let final_text = text_area.value.slice(0, text_area.selectionStart); let selection_text = text_area.value.slice(text_area.selectionStart, text_area.selectionEnd); final_text += CSVtoDtextTable(selection_text, has_header); final_text = final_text.replace(/^\s+/, ""); let cursor = final_text.length; final_text += text_area.value.slice(text_area.selectionEnd); text_area.value = final_text; text_area.focus(); text_area.setSelectionRange(cursor, cursor); return true; } function SaveMarkup(text_area) { let $text_area = $(text_area); let undo_actions = $text_area.data('undo_actions') || []; let undo_index = $text_area.data('undo_index') || 0; undo_actions = undo_actions.slice(0, undo_index); undo_actions.push(text_area.value); $text_area.data('undo_actions', undo_actions); $text_area.data('undo_index', undo_actions.length); $text_area.data('undo_saved', true); JSPLib.debug.debuglog('SaveMarkup', {undo_actions, undo_index}); } function UndoAction(text_area) { let $text_area = $(text_area); let {undo_actions = [], undo_index = 0, undo_saved} = $text_area.data(); if (undo_saved) { undo_actions.push(text_area.value); $text_area.data('undo_actions', undo_actions); } let undo_html = undo_actions.slice(undo_index - 1, undo_index)[0]; if (undo_html) { text_area.value = undo_html; } else { JSPLib.notice.notice("Beginning of actions buffer reached."); } let new_index = Math.max(0, undo_index - 1); $text_area.data('undo_index', new_index); $text_area.data('undo_saved', false); JSPLib.debug.debuglog('UndoAction', {undo_actions, undo_index, new_index}); return Boolean(undo_html); } function RedoAction(text_area) { let $text_area = $(text_area); let {undo_actions = [], undo_index = 0} = $text_area.data(); let undo_html = undo_actions.slice(undo_index + 1, undo_index + 2)[0]; if (undo_html) { text_area.value = undo_html; } else { JSPLib.notice.notice("End of actions buffer reached."); } let new_index = Math.min(undo_actions.length - 1, undo_index + 1); $text_area.data('undo_index', new_index); $text_area.data('undo_saved', false); JSPLib.debug.debuglog('RedoAction', {undo_actions, undo_index, new_index}); return Boolean(undo_html); } function ClearActions(event) { let $text_area = $(event.currentTarget); $text_area.data('undo_actions', []); $text_area.data('undo_index', 0); $text_area.data('undo_saved', false); JSPLib.debug.debuglog('Cleared actions.'); } function DisplayUploadCommentary(open) { if (open) { DS.$commentary_buttons.show(); DS.$markup_controls.show(); DS.$remove_button.show(); DS.$preview_button.show(); DS.$edit_button.hide(); } else { DS.$commentary_buttons.hide(); DS.$markup_controls.hide(); DS.$preview_display.hide(); } } //Render functions function RenderMarkupButton(type, name, config) { let title = JSPLib.utility.displayCase(name); return ``; } function RenderSectionControls(type, section_config, button_config, available_controls) { let header_html = ""; let button_html = ""; for (let section in section_config) { let html = ""; let button_length = 0; for (let i = 0; i < section_config[section].buttons.length; i++) { let button = section_config[section].buttons[i]; if (!available_controls.includes(button)) continue; html += RenderMarkupButton(type, button, button_config[button]); button_length++; } if (button_length === 0) continue; button_html += `
${html}
`; let width = (button_length * 40); let color = section_config[section].color; let name = (button_length > 1 ? JSPLib.utility.displayCase(section) : " "); header_html += `
${name}
`; } return [header_html, button_html]; } function RenderMarkupControls() { if (DS.user_settings.available_dtext_markup.length === 0 && DS.user_settings.available_dtext_actions.length === 0) return; let header_html = ""; let button_html = ""; if (DS.user_settings.available_dtext_markup.length) { let [markup_header, markup_buttons] = RenderSectionControls('markup', MARKUP_SECTION_CONFIG, MARKUP_BUTTON_CONFIG, DS.user_settings.available_dtext_markup); header_html += `
${markup_header}
`; button_html += `
${markup_buttons}
`; } if (DS.user_settings.available_dtext_actions.length > 0) { let [action_header, action_buttons] = RenderSectionControls('action', ACTION_SECTION_CONFIG, ACTION_BUTTON_CONFIG, DS.user_settings.available_dtext_actions); header_html += `
${action_header}
`; button_html += `
${action_buttons}
`; } let width = ((DS.user_settings.available_dtext_markup.length + DS.user_settings.available_dtext_actions.length) * 40) + 20; return JSPLib.utility.sprintf(MARKUP_CONTROLS, String(width), header_html, button_html); } function RenderPreviewSection(name, has_header=false) { let section_header = (has_header ? `
${JSPLib.utility.displayCase(name)}
` : ""); return JSPLib.utility.sprintf(PREVIEW_SECTION, name, section_header); } //Dtext functions function CSVtoDtextTable(csvtext, has_header) { let tabletext = ""; let sectiontext = ""; let csvdata = Papa.parse(csvtext); JSPLib.debug.debuglog('CSVtoDtextTable', {csvdata, has_header}); csvdata.data.forEach((row, i)=>{ let rowtext = ""; row.forEach((col)=>{ if (i === 0 && has_header) { rowtext += AddTableHeader(col); } else { rowtext += AddTableData(col); } }); sectiontext += AddTableRow(rowtext); if (i === 0 && has_header) { tabletext += AddTableHead(sectiontext); sectiontext = ""; } }); tabletext += AddTableBody(sectiontext); return AddTable(tabletext); } function AddTable(input) { return '[table]\n' + input + '[/table]\n'; } function AddTableHead(input) { return '[thead]\n' + input + '[/thead]\n'; } function AddTableBody(input) { return '[tbody]\n' + input + '[/tbody]\n'; } function AddTableRow(input) { return '[tr]\n' + input + '[/tr]\n'; } function AddTableHeader(input) { return '[th]' + input + '[/th]\n'; } function AddTableData(input) { return '[td]' + input + '[/td]\n'; } //Event handlers function DtextMarkup(event) { let $button = $(event.currentTarget); let text_area = GetTextArea($button); if (!text_area) return; let name = $button.attr('name'); let markup_func = (MARKUP_BUTTON_CONFIG[name].markup ? MARKUP_BUTTON_CONFIG[name].markup : MarkupSelectionText); if (markup_func(text_area, MARKUP_BUTTON_CONFIG[name])) { DS.$close_notice.click(); } } function DtextAction(event) { let $button = $(event.currentTarget); let text_area = GetTextArea($button); if (!text_area) return; let name = $button.attr('name'); let action_func = ACTION_BUTTON_CONFIG[name].action; if (action_func(text_area, ACTION_BUTTON_CONFIG[name])) { DS.$close_notice.click(); } } function OpenDialog() { if (!DS.$add_commentary_dialog.data('initialized')) { (DS.$dialog_buttons = DS.$add_commentary_dialog.closest('.ui-dialog').find('.ui-dialog-buttonset button')) .each((_i, button)=>{ $(button).addClass('ds-dialog-button').attr('name', button.innerText); }); DS.$add_commentary_dialog.data('initialized', true); } DS.$dialog_buttons.filter('[name=Preview]').show(); DS.$dialog_buttons.filter('[name=Edit]').hide(); DS.$edit_commentary = $('.ds-edit-commentary'); DS.$preview_display = $('.ds-preview-display'); DtextEdit(); } function ClearPreview(event) { setTimeout(()=>{ if (event.currentTarget.value === 'Preview') { $(event.currentTarget).closest('form').find('.dtext-preview').html(""); } }, 500); } function DtextPreview() { DS.$edit_commentary.hide(); let promise_array = []; let preview_array = []; (DS.$commentary_input ||= $('.ds-commentary-input')).each((_i, input)=>{ let {section, part} = $(input).data(); let preview = {section, part}; let inline = preview.inline = [...input.classList].includes('string'); let body = preview.body = input.value; let promise = (body.trim(/\s+/).length > 0 ? JSPLib.network.post('/dtext_preview', {data: {body, inline}}) : Promise.resolve(null)); promise_array.push(promise); preview_array.push(preview); }); Promise.all(promise_array).then((data)=>{ data.forEach((body, i)=>{ preview_array[i].body = body; }); ['original', 'artist', 'translated'].forEach((section)=>{ let $display = DS.$preview_display.filter(`[data-section=${section}]`); if ($display.length === 0) return; let is_shown = false; let $section = $display.find('.ds-section').html(""); ['title', 'description', 'desc'].forEach((part)=>{ let preview = preview_array.find((item) => (item.section === section && item.part === part)); if (!preview?.body) return; if (part === 'title') { $section.append(`

${preview.body}

`); } else if (part === 'description' || part === 'desc') { $section.append(`
${preview.body}
`); } is_shown = true; }); let action = (is_shown ? 'show' : 'hide'); $display[action](); }); JSPLib.debug.debuglog('DtextPreview', preview_array); }); DS.mode = 'preview'; } function DtextEdit() { DS.$preview_display.hide(); DS.$edit_commentary.show(); DS.mode = 'edit'; } function ToggleCommentary() { if (DS.commentary_open) { DS.$toggle_artist_commentary.text('show »'); DS.$artist_commentary.slideUp(); DS.$upload_commentary_translation_container.slideUp(); DisplayUploadCommentary(false); } else { DS.$toggle_artist_commentary.text('« hide'); DS.$artist_commentary.slideDown(); DS.$upload_commentary_translation_container.slideDown(); DisplayUploadCommentary(true); } DS.commentary_open = !DS.commentary_open; DS.mode = 'edit'; } function ToggleTranslation() { DS.$translation_edit_commentary ||= DS.$upload_commentary_translation_container.find('.ds-edit-commentary'); DS.$translation_preview_display ||= DS.$upload_commentary_translation_container.find('.ds-preview-display'); if (DS.translation_open) { DS.$toggle_commentary_translation.text('show »'); DS.$translation_edit_commentary.slideUp(); DS.$translation_preview_display.slideUp(); } else { DS.$toggle_commentary_translation.text('« hide'); if (DS.mode === 'preview') { DS.$translation_preview_display.slideDown(); } else if (DS.mode === 'edit') { DS.$translation_edit_commentary.slideDown(); } } DS.translation_open = !DS.translation_open; } //Initialize function InitializeButtons($button_container) { let all_configs = Object.assign({}, MARKUP_BUTTON_CONFIG, ACTION_BUTTON_CONFIG); for (let key in all_configs) { let {top, left} = all_configs[key]; $button_container.find(`button[name=${key}] > *:first-of-type`) .css({top, left}); } } function InitializeDtextPreviews() { let containers = JSPLib.utility.multiConcat(...DS.user_settings.dtext_types_handled.map((type) => DTEXT_SELECTORS[type])); let final_selector = JSPLib.utility.joinList(containers, '.', ' .dtext-previewable textarea', ', '); $(final_selector).each((_i, textarea)=>{ let $textarea = $(textarea); let $container = $textarea.closest('.input.dtext'); $container.addClass('ds-container'); $container.find('.dtext-previewable').before(RenderMarkupControls()); InitializeButtons($container.find('.ds-buttons')); $textarea.on(PROGRAM_KEYUP, ClearActions); }); $('.dtext-preview-button').on(PROGRAM_CLICK, ClearPreview); } function InitializeCommentaryDialog() { DS.$add_commentary_dialog = $('#add-commentary-dialog'); if (DS.$add_commentary_dialog.length === 0) return; DS.$add_commentary_dialog.addClass('ds-container'); DS.$add_commentary_dialog.find('#fetch-commentary') .after(RenderMarkupControls()); InitializeButtons(DS.$add_commentary_dialog.find('.ds-buttons')); $('#edit-commentary') .addClass('ds-edit-commentary') .after(RenderPreviewSection('original', true) + RenderPreviewSection('translated', true)); DS.$add_commentary_dialog.data('initialized', false); ['original', 'translated'].forEach((section)=>{ ['title', 'description'].forEach((part)=>{ $(`#artist_commentary_${section}_${part}`).data({section, part}).addClass('ds-commentary-input'); }); }); //Wait for the dialog to be initialized before performing the final step JSPLib.utility.recheckTimer({ check: () => JSPLib.utility.hasDOMDataKey('#add-commentary-dialog', 'uiDialog'), exec: ()=>{ let buttons = DS.$add_commentary_dialog.dialog('option', 'buttons'); buttons = Object.assign(DIALOG_CONFIG, buttons); let dialog_width = Math.max((DS.user_settings.available_dtext_markup.length + DS.user_settings.available_dtext_actions.length) * 40 + 50, DS.$add_commentary_dialog.dialog('option', 'width')); DS.$add_commentary_dialog.dialog('option', 'buttons', buttons); DS.$add_commentary_dialog.dialog('option', 'width', dialog_width); DS.$add_commentary_dialog.on('dialogopen.ds', OpenDialog); }, }, 500, JSPLib.utility.one_second * 15); DS.$add_commentary_dialog.find('.ds-commentary-input').on(PROGRAM_KEYUP, ClearActions); } function InitializeUploadCommentary() { //Move existing sections and add controls DS.$upload_artist_commentary_container = $('.upload_artist_commentary_container').detach(); if (DS.$upload_artist_commentary_container.length === 0) return; DS.$upload_artist_commentary_container .addClass('ds-container') .prepend(RenderMarkupControls()); InitializeButtons(DS.$upload_artist_commentary_container.find('.ds-buttons')); (DS.$artist_commentary = DS.$upload_artist_commentary_container.find('.artist-commentary')) .addClass('ds-edit-commentary') .after(RenderPreviewSection('artist')); DS.$upload_commentary_translation_container = $('.upload_commentary_translation_container').detach(); (DS.$commentary_translation = DS.$upload_commentary_translation_container.find('.commentary-translation')) .addClass('ds-edit-commentary') .after(RenderPreviewSection('translated')); ['artist', 'translated'].forEach((section)=>{ let $container = (section === 'artist' ? DS.$upload_artist_commentary_container : DS.$upload_commentary_translation_container); ['title', 'desc'].forEach((part)=>{ $container.find(`#post_${section}_commentary_${part}`).data({section, part}).addClass('ds-commentary-input'); }); }); (DS.$overall_container = $('
')) .append(DS.$upload_artist_commentary_container) .append(DS.$upload_commentary_translation_container). append(PREVIEW_BUTTONS); $('#tags-container').before(DS.$overall_container); //Initialize commentary handlers (DS.$preview_button = $('#ds-preview-button')).on(PROGRAM_CLICK, ()=>{ DtextPreview(); DS.$preview_button.hide(); DS.$edit_button.show(); }); (DS.$edit_button = $('#ds-edit-button')).on(PROGRAM_CLICK, ()=>{ DtextEdit(); DS.$preview_button.show(); DS.$edit_button.hide(); }); (DS.$remove_button = $('#ds-remove-button')).on(PROGRAM_CLICK, ()=>{ DS.$overall_container.remove(); }); //Wait until Danbooru binds the click, otherwise 2 click handlers will be bound JSPLib.utility.recheckTimer({ check: () => JSPLib.utility.isNamespaceBound('#toggle-artist-commentary', 'click', 'danbooru'), exec: ()=>{ DS.commentary_open = DS.$artist_commentary.is(':visible'); Danbooru.Upload.toggle_commentary = ToggleCommentary; if (DS.commentary_open) { DisplayUploadCommentary(true); } (DS.$toggle_artist_commentary = $('#toggle-artist-commentary')).off('click.danbooru').on(PROGRAM_CLICK, function(event) { Danbooru.Upload.toggle_commentary(); event.preventDefault(); }); DS.translation_open = DS.$commentary_translation.is(':visible'); Danbooru.Upload.toggle_translation = ToggleTranslation; (DS.$toggle_commentary_translation = $('#toggle-commentary-translation')).off('click.danbooru').on(PROGRAM_CLICK, function(event) { Danbooru.Upload.toggle_translation(); event.preventDefault(); }); }, }, 500, JSPLib.utility.one_second * 15); DS.$edit_commentary = $('.ds-edit-commentary'); DS.$preview_display = $('.ds-preview-display'); DS.$commentary_buttons = $('#ds-commentary-buttons'); DS.$markup_controls = $('.ds-markup-controls'); DS.$overall_container.find('.ds-commentary-input').on(PROGRAM_KEYUP, ClearActions); } // Settings functions function InitializeProgramValues() { Object.assign(DS, { $close_notice: $('#close-notice-link'), }); return true; } function RenderSettingsMenu() { $('#dtext-styler').append(JSPLib.menu.renderMenuFramework(MENU_CONFIG)); $("#ds-general-settings").append(JSPLib.menu.renderDomainSelectors()); $("#ds-main-settings").append(JSPLib.menu.renderInputSelectors('dtext_types_handled', 'checkbox')); $('#ds-commentary-settings').append(JSPLib.menu.renderCheckbox('post_commentary_enabled')); $('#ds-commentary-settings').append(JSPLib.menu.renderCheckbox('upload_commentary_enabled')); $("#ds-controls-settings").append(JSPLib.menu.renderInputSelectors('available_dtext_markup', 'checkbox')); $("#ds-controls-settings").append(JSPLib.menu.renderInputSelectors('available_dtext_actions', 'checkbox')); JSPLib.menu.engageUI(true); JSPLib.menu.saveUserSettingsClick(); JSPLib.menu.resetUserSettingsClick(); } //Main program function Main() { JSPLib.debug.debuglog("Initialize start:", JSPLib.utility.getProgramTime()); const preload = { run_on_settings: false, default_data: DEFAULT_VALUES, initialize_func: InitializeProgramValues, menu_css: MENU_CSS, }; if (!JSPLib.menu.preloadScript(DS, RenderSettingsMenu, preload)) return; if (DS.user_settings.dtext_types_handled.length) { InitializeDtextPreviews(); } if (DS.user_settings.post_commentary_enabled && DS.controller === 'posts' && DS.action === 'show') { InitializeCommentaryDialog(); JSPLib.utility.setCSSStyle(POST_CSS, 'post'); } else if (DS.user_settings.upload_commentary_enabled && ((DS.controller === 'uploads' && DS.action === 'show') || (DS.controller === 'upload-media-assets' && DS.action === 'show'))) { InitializeUploadCommentary(); JSPLib.utility.setCSSStyle(UPLOAD_CSS, 'upload'); } $('.dtext-markup').on(PROGRAM_CLICK, DtextMarkup); $('.dtext-action').on(PROGRAM_CLICK, DtextAction); JSPLib.utility.blockActiveElementSwitch('.dtext-markup, .dtext-action'); JSPLib.utility.setCSSStyle(PROGRAM_CSS, 'program'); } /****Initialization****/ //Variables for debug.js JSPLib.debug.debug_console = false; JSPLib.debug.level = JSPLib.debug.INFO; JSPLib.debug.program_shortcut = PROGRAM_SHORTCUT; //Variables for menu.js JSPLib.menu.program_shortcut = PROGRAM_SHORTCUT; JSPLib.menu.program_name = PROGRAM_NAME; JSPLib.menu.program_data = DS; JSPLib.menu.settings_config = SETTINGS_CONFIG; //Export JSPLib JSPLib.load.exportData(PROGRAM_NAME, DS); /****Execution start****/ JSPLib.load.programInitialize(Main, {program_name: PROGRAM_NAME, required_variables: PROGRAM_LOAD_REQUIRED_VARIABLES, optional_selectors: PROGRAM_LOAD_OPTIONAL_SELECTORS});