// // // // // global variables var timer; var artTypes = ['🎨','🧑','🏞️']; var imgTypeShown = 0; var log = ''; var editMostUsedMode = false; var windowWidth = 0; var gutterStartPosX, mouseStartPosX, gutterEndPercentX var style, stylesheet, imgHoverRule; var tagsConcatenated = new Set(); var editedArtists = new Set(); // // // // functions function startUp() { updateTagsConcatenated(); updateFooter(); loadEditedArtists(); insertArtists(); insertCheckboxesFromArtistsData(); insertCheckboxesFromCategories(); loadCheckboxesState(); showHideCategories(); loadOptionsState(); loadFavoritesState(); hideAllArtists(); unhideBasedOnPermissiveSetting(); updateArtistsCountPerTag('start'); rotatePromptsImages(); sortArtists(); sortTags(); loadMostUsedTags(); updateArtistsCountPerCategory(); showHideLowCountTags(); getStyleRuleForDrag(); } function updateTagsConcatenated() { // this set is used for tag editing mode for (var i=0, il=tagCategories.length; i editedA[0] === artist[0] && editedA[1] === artist[1]); if(artistFound) { // check if the edit now matches the original let match = true; for (let j=0, jl=artist.length; j { var last = artist[0]; var first = artist[1]; var tags1 = artist[2].replaceAll('|', ' ').toLowerCase(); // for classes var tags2 = artist[2].replaceAll('|', ', '); // for display // class names can't start with a number, but some tags do // in these cases we prepend the class with 'qqqq-' tags1 = tags1.replace(/(^|\s)(\d)/g, '$1qqqq-$2'); // artists can have a tag in the format of "added-YYYY-MM" // we want that to show up as a filter, but not on the artist card tags2 = tags2.replace(/, added-(\d|-)*/g,''); var itemDiv = document.createElement('div'); itemDiv.className = 'image-item ' + tags1; if(artist[3]) { itemDiv.dataset.deprecated = true; } var itemHeader = document.createElement('span'); var h3 = document.createElement('h3'); itemHeader.appendChild(h3); var firstN = document.createElement('span'); var lastN = document.createElement('span'); firstN.className = 'firstN'; lastN.className = 'lastN'; firstN.textContent = `${first}`; lastN.textContent = `${last}`; h3.appendChild(firstN); h3.appendChild(lastN); h3.title = 'copy to clipboard'; var h4 = document.createElement('h4'); h4.textContent = tags2; h4.title = 'copy to clipboard'; itemHeader.appendChild(h4); itemDiv.appendChild(itemHeader); var box = document.createElement('div'); var imgTools = document.createElement('div'); imgTools.className = 'imgTools'; var artPrev = document.createElement('div'); artPrev.className = 'art_prev'; var artPrevSpan = document.createElement('span'); artPrevSpan.textContent = '🧑'; artPrev.appendChild(artPrevSpan); imgTools.appendChild(artPrev); var artStar = document.createElement('div'); artStar.className = 'art_star'; var artStarSpan = document.createElement('span'); artStarSpan.textContent = '⭐️'; artStar.appendChild(artStarSpan); imgTools.appendChild(artStar); var artNext = document.createElement('div'); artNext.className = 'art_next'; var artNextSpan = document.createElement('span'); artNextSpan.textContent = '🏞️'; artNext.appendChild(artNextSpan); imgTools.appendChild(artNext); var artEdit = document.createElement('div'); artEdit.className = 'art_edit'; var artEditSpan = document.createElement('span'); artEditSpan.textContent = '✍️'; artEdit.appendChild(artEditSpan); imgTools.appendChild(artEdit); box.appendChild(imgTools); var imgBox = document.createElement('div'); imgBox.className = 'imgBox'; var imgArtwork = document.createElement('img'); var imgPortrait = document.createElement('img'); var imgLandscape = document.createElement('img'); imgArtwork.alt = `${first} ${last}` + ' - artwork'; imgPortrait.alt = `${first} ${last}` + ' - portrait'; imgLandscape.alt = `${first} ${last}` + ' - landscape'; imgArtwork.className = 'img_artwork'; imgPortrait.className = 'img_portrait hidden'; imgLandscape.className = 'img_landscape hidden'; let src = 'images/SDXL_1_0_thumbs/'; if(first == '') { src += last.replaceAll(' ', '_'); } else { src += first.replaceAll(' ', '_') + '_' + last.replaceAll(' ', '_'); } // files use accented characters and huggingface stores the files with this encoding src = encodeURI(src.normalize("NFD")); imgBox.appendChild(imgArtwork); imgBox.appendChild(imgPortrait); imgBox.appendChild(imgLandscape); box.appendChild(imgBox); itemDiv.appendChild(box); container.appendChild(itemDiv); if(artist[3]) { var deprecatedSpan = document.createElement('span'); deprecatedSpan.textContent = 'this artist is unknown to SDXL - more info in the help ⁉️' deprecatedSpan.className = 'deprecated'; imgBox.appendChild(deprecatedSpan); return Promise.allSettled([ new Promise((resolve, reject) => { imgArtwork.style.display = 'none'; imgArtwork.src = 'images/SDXL_1_0_thumbs/1x1.webp'; }), new Promise((resolve, reject) => { imgPortrait.style.display = 'none'; imgPortrait.src = 'images/SDXL_1_0_thumbs/1x1.webp'; }), new Promise((resolve, reject) => { imgLandscape.style.display = 'none'; imgLandscape.src = 'images/SDXL_1_0_thumbs/1x1.webp'; }) ]); } else { // if not flagged as deprecated return Promise.allSettled([ new Promise((resolve, reject) => { imgArtwork.onload = resolve; imgArtwork.onerror = () => { missingFiles += '
  • ' + first + '_' + last + '-artwork.webp
  • '; reject(); }; imgArtwork.src = src + '-artwork.webp'; }), new Promise((resolve, reject) => { imgPortrait.onload = resolve; imgPortrait.onerror = () => { missingFiles += '
  • ' + first + '_' + last + '-portrait.webp
  • '; reject(); }; imgPortrait.src = src + '-portrait.webp'; }), new Promise((resolve, reject) => { imgLandscape.onload = resolve; imgLandscape.onerror = () => { missingFiles += '
  • ' + first + '_' + last + '-landscape.webp
  • '; reject(); }; imgLandscape.src = src + '-landscape.webp'; }) ]); } }); let report = document.getElementById('missing_images_report'); Promise.allSettled(imagePromises).then(() => { if(missingFiles.indexOf('webp')>0) { report.innerHTML = missingFiles; } else { report.innerHTML = '
  • No thumbnails files are missing! Enlarged images are loaded on hover. If any are missing, they\'ll be listed here at that time.
  • ' } }); } function insertCheckboxesFromArtistsData() { var uniqueTags = new Set(); artistsData.forEach(function(artist) { var tags = artist[2].split('|'); tags.forEach(function(tag) { uniqueTags.add(tag.toLowerCase()); }); }); var uTags = Array.from(uniqueTags); var toggles = document.getElementById('toggles'); for(i=0,il=uTags.length;i 0) { // 👆 shouldn't need to sanitize database, but just in case var label = document.createElement('label'); var el = document.createElement('i'); el.className = 'most_used_indicator'; el.textContent = '+'; var input = document.createElement('input'); input.type = 'checkbox'; input.name = uTags[i]; input.value = uTags[i]; input.checked = true; var span1 = document.createElement('span'); span1.textContent = uTags[i]; var span2 = document.createElement('span'); span2.className = 'count'; label.appendChild(el); label.appendChild(input); label.appendChild(span1); label.appendChild(span2); toggles.appendChild(label); } } } function insertCheckboxesFromCategories() { var useCategories = document.querySelector('input[name="use_categories"]').checked; for(i=0,il=tagCategories.length;i 2) { imgTypeShown = 0; } } var links = document.getElementById('options_prompts').querySelectorAll('.link'); links.forEach(function(link) { link.classList.remove('selected'); }); if(imgTypeShown == 0) { document.getElementById('promptA').classList.add('selected'); doAlert('Showing artwork',0); } else if(imgTypeShown == 1) { document.getElementById('promptP').classList.add('selected'); doAlert('Showing portraits',0); } else if(imgTypeShown == 2) { document.getElementById('promptL').classList.add('selected'); doAlert('Showing landscapes',0); } } else { if(selected == 'promptA') { imgTypeShown = 0; doAlert('Showing artwork',0); } else if(selected == 'promptP') { imgTypeShown = 1; doAlert('Showing portraits',0); } else if(selected == 'promptL') { imgTypeShown = 2; doAlert('Showing landscapes',0); } var links = document.getElementById(selected).parentNode.querySelectorAll('.link'); links.forEach(function(link) { link.classList.remove('selected'); }); document.getElementById(selected).classList.add('selected'); } } function storeOptionsState() { let state = JSON.parse(localStorage.getItem('tagsChecked')) || {}; if(document.getElementById('promptA').classList.contains('selected')) { state['prompt'] = 'promptA'; } else if(document.getElementById('promptP').classList.contains('selected')) { state['prompt'] = 'promptP'; } else { state['prompt'] = 'promptL'; } if(document.getElementById('sortAR').classList.contains('selected')) { state['artistSort'] = 'sortAR'; } else { state['artistSort'] = 'sortAA'; } if(document.getElementById('sortTC').classList.contains('selected')) { state['tagSort'] = 'sortTC'; } else { state['tagSort'] = 'sortTA'; } localStorage.setItem('tagsChecked', JSON.stringify(state)); } function rotatePromptsImages() { // hide all images let images = document.querySelectorAll('.imgBox img'); images.forEach(function(image) { image.classList.add('hidden'); }); // unhide images matching highlighted option (imgTypeShown) if(imgTypeShown == 0) { images = document.querySelectorAll('.img_artwork'); } else if(imgTypeShown == 1) { images = document.querySelectorAll('.img_portrait'); } else if(imgTypeShown == 2) { images = document.querySelectorAll('.img_landscape'); } images.forEach(function(image) { image.classList.remove('hidden'); }); // switch prev and next button icons let artIndex = 0; artIndex = imgTypeShown-1; if(artIndex < 0) { artIndex = 2; } let prevButtons = document.querySelectorAll('.art_prev span'); prevButtons.forEach(function(span) { span.textContent = artTypes[artIndex]; }); artIndex = imgTypeShown+1; if(artIndex > 2) { artIndex = 0; } let nextButtons = document.querySelectorAll('.art_next span'); nextButtons.forEach(function(span) { span.textContent = artTypes[artIndex]; }); } function updateArtistsCountPerTag(whoCalled) { var permissiveCheckbox = document.querySelector('input[name="mode"]'); var deprecatedCheckbox = document.querySelector('input[name="deprecated"]'); var checkboxes = document.querySelectorAll('input[type="checkbox"]'); var divs = document.querySelectorAll('.image-item'); var hiddenDivs = document.querySelectorAll('.image-item.hidden'); var deprecatedDivs = document.querySelectorAll('.image-item[data-deprecated="true"]'); var count = 0; if(permissiveCheckbox.checked || whoCalled == 'start') { // on page load, we need to add all the counts first checkboxes.forEach(function(checkbox) { let isTop = checkbox.parentNode.classList.contains('top_control'); if(!isTop) { var theClass = checkbox.name.replace(/(^|\s)(\d)/g, '$1qqqq-$2'); var matchingDivs = document.querySelectorAll('.image-item.' + theClass); let filteredDivs = Array.from(matchingDivs).filter(mat => { return !Array.from(deprecatedDivs).some(dep => dep === mat); }); if(deprecatedCheckbox.checked) { count = filteredDivs.length; } else { count = matchingDivs.length; } checkbox.parentNode.classList.remove('no_matches'); checkbox.parentNode.querySelector('input').disabled = false; // editing tags can cause count to be null if(count) { checkbox.parentNode.querySelector('.count').textContent = ' - ' + count.toLocaleString(); } else { checkbox.parentNode.querySelector('.count').textContent = ' - ' + 'edited'; } } }); updateArtistsCountPerCategory(); } if(!permissiveCheckbox.checked) { checkboxes.forEach(function(checkbox) { let isTop = checkbox.parentNode.classList.contains('top_control'); if(!isTop) { count = 0; // class names can't start with a number, but some tags do // in these cases prepending with 'qqqq-' var theClass = checkbox.name.replace(/(^|\s)(\d)/g, '$1qqqq-$2'); // for strict mode, for each checkbox, only count artists with a classes matching all checked checkboxes var matchingDivs = document.querySelectorAll('.image-item.' + theClass + ':not(.hidden)'); let filteredDivs = Array.from(matchingDivs).filter(mat => { return !Array.from(deprecatedDivs).some(dep => dep === mat); }); if(deprecatedCheckbox.checked) { count = filteredDivs.length; } else { count = matchingDivs.length; } if(count == 0) { checkbox.parentNode.classList.add('no_matches'); checkbox.parentNode.querySelector('input').disabled = true; } else { checkbox.parentNode.classList.remove('no_matches'); checkbox.parentNode.querySelector('input').disabled = false; } checkbox.parentNode.querySelector('.count').textContent = ' - ' + count.toLocaleString(); } }); } updateCountOfAllArtistsShown(divs, hiddenDivs); } function updateArtistsCountPerCategory() { var imageItems = document.querySelectorAll('.image-item'); let counts = []; for(i=0,il=tagCategories.length; i { // class names can't start with a number, // so some classes were prepending with 'qqqq-' // which must be ignored return className.replace(/^qqqq-/, ''); }); for(i=0,il=tagCategories.length; i c.toLowerCase()).some(c => classes.includes(c))) { counts[i]++; } } }); for(i=0,il=tagCategories.length; i