Files
dreamgirl/js/bestpic.js
dsyoon 5ac19523c1 이미지 삭제 기능을 추가하고 NCue 로고를 제거한다.
썸네일에서 서버의 실제 이미지 파일을 안전하게 삭제하고 갤러리 상태를 동기화한다.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 09:07:10 +09:00

266 lines
9.5 KiB
JavaScript

var refreshIntervalId = null;
// Prefer same-origin relative paths so HTTPS doesn't break due to mixed-content / upgrade rules.
var imgurl = "img/";
function buildThumbLi(filename) {
var imgfile = imgurl + encodeURIComponent(filename);
return (
"<li data-filename='" + filename.replace(/'/g, "&#39;") + "'>" +
" <button type='button' class='thumb-delete' title='삭제' aria-label='삭제'>&times;</button>" +
" <a class='thumb' name='leaf' href='" + imgfile + "' title='" + filename.replace(/'/g, "&#39;") + "'>" +
" <img src='" + imgfile + "' alt='" + filename.replace(/'/g, "&#39;") + "' width='75' height='75'/>" +
" </a>" +
" <div class='caption'></div>" +
"</li>"
);
}
function removeFromImageList(filename) {
if (!window.DREAMGIRL_IMAGES || !window.DREAMGIRL_IMAGES.length) return;
var idx = window.DREAMGIRL_IMAGES.indexOf(filename);
if (idx >= 0) window.DREAMGIRL_IMAGES.splice(idx, 1);
}
function deleteImageFile(filename, onSuccess, onError) {
var fd = new FormData();
fd.append('filename', filename);
fetch('api/delete_image.php', {
method: 'POST',
body: fd,
credentials: 'same-origin'
})
.then(function (r) { return r.json(); })
.then(function (data) {
if (!data || !data.ok) {
throw new Error((data && data.error) ? data.error : '삭제 실패');
}
if (typeof onSuccess === 'function') onSuccess(data);
})
.catch(function (err) {
if (typeof onError === 'function') {
onError(err);
} else {
alert('에러: ' + (err && err.message ? err.message : '삭제 실패'));
}
});
}
function bindThumbDeleteHandler() {
$('#thumbs').off('click.thumbDelete', '.thumb-delete');
$('#thumbs').on('click.thumbDelete', '.thumb-delete', function (e) {
e.preventDefault();
e.stopPropagation();
var $li = $(this).closest('li');
var filename = $li.attr('data-filename');
if (!filename) return;
if (!window.confirm('이 이미지를 삭제하시겠습니까?\n' + filename)) return;
var $btn = $(this);
$btn.prop('disabled', true);
deleteImageFile(filename, function () {
removeFromImageList(filename);
if (window.dreamgirlGallery) {
var gallery = window.dreamgirlGallery;
var index = $li.index();
var wasCurrent = gallery.currentImage && gallery.currentImage.index === index;
if (typeof gallery.removeImageByIndex === 'function') {
gallery.removeImageByIndex(index);
} else {
$li.remove();
}
if (wasCurrent && gallery.data && gallery.data.length) {
var nextIndex = Math.min(index, gallery.data.length - 1);
if (typeof gallery.gotoIndex === 'function') {
gallery.gotoIndex(nextIndex);
}
}
} else {
$li.remove();
}
}, function (err) {
$btn.prop('disabled', false);
alert('에러: ' + (err && err.message ? err.message : '삭제 실패'));
});
});
}
function getApiUrl() {
// Use scheme-relative URL so it matches http/https of the current page.
// NOTE: if the API does not support https, consider proxying it via Apache and pointing to a same-origin endpoint.
return "//api.martn.ncue.net/dreamgirl.ncue";
}
function getRandomIndex(n) {
var arr = new Array();
var temp;
var rnum;
for(var i=0; i<n; i++) {
arr.push(i);
}
for(var i=0; i<arr.length; i++) {
rnum = Math.floor(Math.random()*n);
temp = arr[i];
arr[i] = arr[rnum];
arr[rnum] = temp;
}
return arr;
}
function onLoad() {
function initGallery() {
// We only want these styles applied when javascript is enabled
// Layout is now handled by CSS (flex). Keep JS from forcing a fixed width.
$('div.navigation').css({'width' : '', 'float' : ''});
$('div.content').css('display', 'block');
// Initially set opacity on thumbs and add additional styling for hover effect on thumbs
var onMouseOutOpacity = 0.67;
$('#thumbs ul.thumbs li').opacityrollover({
mouseOutOpacity: onMouseOutOpacity,
mouseOverOpacity: 1.0,
fadeSpeed: 'fast',
exemptionSelector: '.selected'
});
// Initialize Advanced Galleriffic Gallery (store instance for uploader)
window.dreamgirlGallery = $('#thumbs').galleriffic({
delay: 2500,
numThumbs: 15,
preloadAhead: 10,
enableTopPager: true,
enableBottomPager: true,
maxPagesToShow: 7,
imageContainerSel: '#slideshow',
controlsContainerSel: '#controls',
captionContainerSel: '#caption',
loadingContainerSel: '#loading',
renderSSControls: true,
renderNavControls: true,
playLinkText: 'Play Slideshow',
pauseLinkText: 'Pause Slideshow',
prevLinkText: '&lsaquo; Previous Photo',
nextLinkText: 'Next Photo &rsaquo;',
nextPageLinkText: 'Next &rsaquo;',
prevPageLinkText: '&lsaquo; Prev',
enableHistory: false,
autoStart: true,
syncTransitions: true,
defaultTransitionDuration: 900,
onSlideChange: function(prevIndex, nextIndex) {
// 'this' refers to the gallery, which is an extension of $('#thumbs')
this.find('ul.thumbs').children()
.eq(prevIndex).fadeTo('fast', onMouseOutOpacity).end()
.eq(nextIndex).fadeTo('fast', 1.0);
},
onPageTransitionOut: function(callback) {
this.fadeTo('fast', 0.0, callback);
},
onPageTransitionIn: function() {
this.fadeTo('fast', 1.0);
}
});
}
function buildThumbsFromList(fileNames) {
var text = "<ul class='thumbs noscript'>";
var rid = getRandomIndex(fileNames.length);
for (var i=0; i<rid.length; i++) {
var fname = fileNames[rid[i]];
text += buildThumbLi(fname);
}
text += "</ul>";
$("#thumbs-list").html(text);
initGallery();
bindThumbDeleteHandler();
}
function tryLoadFromLocalListApi() {
return $.ajax({
url: 'api/list_images.php',
type: 'GET',
dataType: 'json',
cache: false,
timeout: 8000
});
}
function fallbackToLocalManifest() {
if (window.DREAMGIRL_IMAGES && window.DREAMGIRL_IMAGES.length) {
buildThumbsFromList(window.DREAMGIRL_IMAGES);
return true;
}
// Minimal fallback if manifest is missing for some reason
buildThumbsFromList(['0.jpg','1.jpg','2.jpg','3.jpg','20.jpg','24.jpg','25.jpg','26.jpg','28.jpg','36.jpg','66.jpg']);
return true;
}
// Prefer same-origin dynamic list (so newly uploaded images appear on refresh).
tryLoadFromLocalListApi()
.done(function(resp) {
if (resp && resp.ok && resp.images && resp.images.length) {
buildThumbsFromList(resp.images);
} else {
fallbackToLocalManifest();
}
})
.fail(function() {
// If local list API is unavailable, try remote JSONP API, then fall back to static manifest.
$.ajax({
url : getApiUrl(),
type: 'GET',
data : "id=user",
dataType : "jsonp",
jsonp : "callback",
cache : false,
timeout: 15000,
success: function(data) {
try {
var filelist = data && data.filelist ? data.filelist : null;
if (!filelist || !filelist.length) return fallbackToLocalManifest();
var names = [];
for (var i=0; i<filelist.length; i++) {
if (filelist[i] && filelist[i]["img"]) names.push(filelist[i]["img"]);
}
if (!names.length) return fallbackToLocalManifest();
buildThumbsFromList(names);
} catch (e) {
fallbackToLocalManifest();
}
},
error: function () {
fallbackToLocalManifest();
}
});
});
return true;
}
function toggle() {
if (!document.getElementById('betoven').muted) {
document.getElementById('betoven').muted = true;
clearInterval(refreshIntervalId);
$("#toggle").html("start");
} else {
document.getElementById('betoven').muted = false;
/*
refreshIntervalId = setInterval(function() {
var index = Math.floor(Math.random()*278) + 1;
$("#thumbs").html("<img src='"+pictures[index]+"' width='100%' onerror=\"this.src='"+imgurl+"z7jP92.jpg'\"/>");
}, 3000);
*/
$("#toggle").html("stop");
}
}