274 lines
13 KiB
PHP
274 lines
13 KiB
PHP
<div class="pb-6 h-full">
|
|
<input type="file" id="picker" name="file" class="hidden" accept="image/*" multiple>
|
|
|
|
<div class="mb-4 p-4 bg-white rounded-md">
|
|
<h1 class="tracking-wider text-2xl text-gray-700 mb-2" style="text-shadow: -4px 4px 0 rgb(0 0 0 / 10%);">Image Upload</h1>
|
|
<p class="text-gray-500 text-sm">最大可上传 1.00 MB 的图片,单次同时可选择 3 张。本站已托管 3267 张图片。</p>
|
|
<div class="mt-3 rounded-md border-2 border-dotted border-stone-300 w-full h-full" id="picker-dnd" onclick="$('#picker').click()">
|
|
<div id="upload-container" class="relative group flex flex-col justify-center items-center p-2 w-full h-full min-h-[150px] sm:min-h-[340px] space-y-4 text-gray-500 cursor-pointer">
|
|
<i id="clear" class="fas fa-times absolute top-1 right-1 w-8 h-8 flex justify-center items-center cursor-pointer text-xl text-center hidden group-hover:block text-gray-400 hover:text-gray-500"></i>
|
|
<p id="upload-all" title="点我上传全部"><i class="fas fa-cloud-upload-alt text-6xl hover:text-indigo-400"></i></p>
|
|
<p class="text-md text-center">拖拽文件到这里,支持多文件同时上传<br/>点击上面的图标上传全部已选择文件</p>
|
|
</div>
|
|
<div id="upload-preview" class="flex m-2 hidden"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="links-container" class="hidden mb-4 p-4 bg-white rounded-md relative group">
|
|
<div class="absolute top-2 right-2 flex">
|
|
<span id="copy-all" class="px-2 py-1 rounded-md text-xs text-gray-800 bg-gray-100 cursor-pointer hidden group-hover:block">复制全部</span>
|
|
<span id="clear-all" class="ml-1 px-2 py-1 rounded-md text-xs text-gray-800 bg-gray-100 cursor-pointer hidden group-hover:block">清除</span>
|
|
</div>
|
|
<div id="link-tabs" class="flex flex-nowrap overflow-scroll scrollbar-none text-sm">
|
|
<a href="javascript:void(0)" data-tab-name="url" class="hover:bg-gray-100 flex justify-center items-center px-8 py-2 border-b-2 border-indigo-500 active">URL</a>
|
|
<a href="javascript:void(0)" data-tab-name="html" class="hover:bg-gray-100 flex justify-center items-center px-8 py-2 border-b-2 border-transparent">HTML</a>
|
|
<a href="javascript:void(0)" data-tab-name="bbcode" class="hover:bg-gray-100 flex justify-center items-center px-8 py-2 border-b-2 border-transparent">BBCode</a>
|
|
<a href="javascript:void(0)" data-tab-name="markdown" class="hover:bg-gray-100 flex justify-center items-center px-8 py-2 border-b-2 border-transparent">Markdown</a>
|
|
<a href="javascript:void(0)" data-tab-name="markdown_with_link" class="hover:bg-gray-100 flex justify-center items-center px-8 py-2 border-b-2 border-transparent whitespace-nowrap">Markdown with link</a>
|
|
</div>
|
|
<div id="links" class="mt-2">
|
|
<div data-tab="url" class="space-y-2"></div>
|
|
<div data-tab="html" class="hidden space-y-2"></div>
|
|
<div data-tab="bbcode" class="hidden space-y-2"></div>
|
|
<div data-tab="markdown" class="hidden space-y-2"></div>
|
|
<div data-tab="markdown_with_link" class="hidden space-y-2"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="text/html" id="image-preview-tpl">
|
|
<div data-id="__id__" class="w-full flex items-center p-2 mb-2 rounded-md relative bg-gray-50 overflow-hidden">
|
|
<div class="absolute inset-0">
|
|
<div class="w-[0%] h-full bg-gray-200 opacity-70 upload-progress"></div>
|
|
</div>
|
|
<div class="relative flex w-full">
|
|
<div class="w-10 h-10 bg-gray-200 rounded-lg cursor-pointer overflow-hidden">
|
|
<img class="w-full h-full" src="__src__">
|
|
</div>
|
|
<div class="flex justify-end flex-col ml-2 w-[80%] opacity-70">
|
|
<p class="text-sm truncate">__name__</p>
|
|
<p class="text-xs truncate">
|
|
<span>__info__</span>, <span class="upload-info">等待上传</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div class="absolute right-2 flex space-x-2">
|
|
<a href="javascript:void(0)" data-operate="remove" class="flex justify-center items-center block shadow-sm w-10 h-10 rounded-full text-gray-600 bg-gray-100 hover:bg-gray-200 aspect-w-1 aspect-h-1"><i class="fas fa-times"></i></a>
|
|
<a href="javascript:void(0)" data-operate="upload" class="flex justify-center items-center block shadow-sm w-10 h-10 rounded-full text-gray-600 bg-gray-100 hover:bg-gray-200 aspect-w-1 aspect-h-1"><i class="fas fa-upload"></i></a>
|
|
</div>
|
|
</div>
|
|
</script>
|
|
@push('scripts')
|
|
<script src="{{ asset('js/blueimp-file-upload/jquery.ui.widget.js') }}"></script>
|
|
<script src="{{ asset('js/blueimp-file-upload/jquery.iframe-transport.js') }}"></script>
|
|
<script src="{{ asset('js/blueimp-file-upload/jquery.fileupload.js') }}"></script>
|
|
<script src="{{ asset('js/blueimp-load-image/load-image.all.min.js') }}"></script>
|
|
<script src="{{ asset('js/clipboard/clipboard.min.js') }}"></script>
|
|
@endpush
|
|
@push('scripts')
|
|
<script>
|
|
(new ClipboardJS('#copy-all', {
|
|
text: function(trigger) {
|
|
let text = '';
|
|
$('[data-tab="' + $('#link-tabs a.active').data('tab-name') + '"] p').each(function (i) {
|
|
if (i !== 0) {
|
|
text += '\r\n';
|
|
}
|
|
text += $(this).text();
|
|
});
|
|
return text;
|
|
}
|
|
})).on('success', function(e) {
|
|
if (! $(e.trigger).attr('disabled')) {
|
|
let text = $(e.trigger).text();
|
|
$(e.trigger).attr('disabled', true).text('复制成功');
|
|
setTimeout(function () {
|
|
$(e.trigger).attr('disabled', false).text(text);
|
|
}, 1000);
|
|
}
|
|
}).on('error', function(e) {
|
|
toastr.warning('复制失败')
|
|
});
|
|
</script>
|
|
<script>
|
|
const UPLOAD_WAITING = 0; // 等待上传
|
|
const UPLOAD_SUCCESS = 1; // 上传成功
|
|
const UPLOAD_ERROR = 2; // 上传失败
|
|
let $previews = $('#upload-preview');
|
|
let $links = $('#links-container');
|
|
let $picker = $('#picker');
|
|
let queue = []; // 文件队列
|
|
/**
|
|
* 设置状态
|
|
* @param data
|
|
* @param status
|
|
* @param message
|
|
*/
|
|
const setStatus = (data, status, message) => {
|
|
queue[data.guid].status = data.status = status;
|
|
let $info = data.$preview.find('.upload-info');
|
|
$info.removeClass('text-green-500 text-red-500')
|
|
let msg = '';
|
|
switch (status) {
|
|
case UPLOAD_WAITING:
|
|
msg = '等待上传';
|
|
break;
|
|
case UPLOAD_SUCCESS:
|
|
msg = '上传成功';
|
|
$info.addClass('text-green-800');
|
|
break;
|
|
case UPLOAD_ERROR:
|
|
msg = '上传失败';
|
|
$info.addClass('text-red-500')
|
|
break;
|
|
}
|
|
$info.text(message ? message : msg);
|
|
}
|
|
$picker.fileupload({
|
|
url: '{{ route('upload') }}',
|
|
autoUpload: false,
|
|
dataType: 'json',
|
|
headers: {
|
|
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
|
},
|
|
limitMultiFileUploads: 1,
|
|
limitConcurrentUploads: 3,
|
|
pasteZone: $(document),
|
|
dropZone: $('#picker-dnd'),
|
|
formData: (form) => {
|
|
|
|
},
|
|
add: (e, data) => {
|
|
let file = data.files[0];
|
|
let ext = file.name.substr(file.name.lastIndexOf('.') + 1);
|
|
let allowSuffixes = ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp', 'psd', 'svg', 'tiff', 'ico'];
|
|
if (allowSuffixes.indexOf(ext.toLowerCase()) === -1) {
|
|
toastr.warning(`不支持的文件格式 ${file.name}`);
|
|
return false;
|
|
}
|
|
if (file.size > 5242880) {
|
|
toastr.warning(`文件 ${file.name} 超出大小限制(最大5MB)`);
|
|
return false;
|
|
}
|
|
let guid = utils.guid();
|
|
data.guid = guid;
|
|
loadImage(file, function (img) {
|
|
if (img.type === 'error') {
|
|
toastr.error(`文件 ${file.name} 缩略图生成失败`);
|
|
console.error('Error loading image file')
|
|
}
|
|
let html = $('#image-preview-tpl')
|
|
.html()
|
|
.replace(/__id__/g, guid)
|
|
.replace(/__src__/g, img.toDataURL())
|
|
.replace(/__name__/g, file.name)
|
|
.replace(/__info__/g, utils.formatSize(file.size));
|
|
data.$preview = $previews.append(html).show().find(`[data-id="${guid}"]`);
|
|
queue[guid] = data;
|
|
setStatus(data, UPLOAD_WAITING);
|
|
}, {
|
|
maxWidth: 200,
|
|
maxHeight: 200,
|
|
meta: true,
|
|
orientation: true,
|
|
canvas: true
|
|
},
|
|
)
|
|
},
|
|
send: (e, data) => {
|
|
data.$preview.find('[data-operate="upload"]').hide();
|
|
},
|
|
progress: (e, data) => {
|
|
let progress = parseInt(data.loaded / data.total * 100, 10);
|
|
let $uploadInfo = data.$preview.find('.upload-info');
|
|
let $uploadProgress = data.$preview.find('.upload-progress');
|
|
let rate = progress + '%';
|
|
$uploadInfo.text('上传中...' + rate);
|
|
$uploadProgress.css('width', rate);
|
|
},
|
|
done: (e, data) => {
|
|
let response = data.result;
|
|
if (response.status) {
|
|
setStatus(data, UPLOAD_SUCCESS)
|
|
data.$preview.attr('uploaded', true);
|
|
// 追加链接
|
|
let links = response.data.links;
|
|
for (let key in links) {
|
|
$('#links [data-tab="' + key + '"]').append('<p class="whitespace-nowrap select-all mt-1 bg-gray-50 hover:bg-gray-200 text-gray-600 rounded px-2 py-1 cursor-pointer overflow-scroll scrollbar-none">' + links[key].toString() + '</p>')
|
|
}
|
|
$links.show();
|
|
} else {
|
|
setStatus(data, UPLOAD_ERROR, "上传失败, " + response.message);
|
|
// 重新显示上传按钮
|
|
data.$preview.find('[data-operate="upload"]').show();
|
|
}
|
|
},
|
|
fail: (e, data) => {
|
|
if (data.errorThrown !== 'abort') {
|
|
// 重新显示上传按钮
|
|
data.$preview.find('[data-operate="upload"]').show();
|
|
if (data.jqXHR.status === 419) {
|
|
return setStatus(data, UPLOAD_ERROR, '令牌错误,请刷新网页重试');
|
|
}
|
|
return setStatus(data, UPLOAD_ERROR, '服务端异常,请稍后重试');
|
|
}
|
|
},
|
|
// 等同于jq的complete
|
|
always: (e, data) => {
|
|
|
|
}
|
|
});
|
|
|
|
$(document).on('drop dragover', (e) => e.preventDefault());
|
|
$previews.click((e) => e.stopPropagation());
|
|
|
|
$('#upload-all').click((e) => {
|
|
// 队列中没有文件,选择则继续冒泡,选择文件
|
|
if (Object.values(queue).filter((item) => item.status !== UPLOAD_SUCCESS).length) {
|
|
e.stopPropagation();
|
|
for (const key in queue) {
|
|
if (queue[key].status !== UPLOAD_SUCCESS) {
|
|
queue[key].submit();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
$previews.on('click', '[data-operate]', function (e) {
|
|
e.stopPropagation();
|
|
let $preview = $(this).closest('[data-id]');
|
|
let method = $(this).data('operate');
|
|
let id = $preview.data('id');
|
|
if (method === 'remove') {
|
|
queue[id].abort();
|
|
delete queue[id];
|
|
$preview.remove();
|
|
}
|
|
if (method === 'upload' && queue[id].status !== UPLOAD_SUCCESS) {
|
|
queue[id].submit();
|
|
}
|
|
});
|
|
|
|
$('#clear').click(function (e) {
|
|
e.stopPropagation();
|
|
queue = [];
|
|
$previews.html('');
|
|
});
|
|
|
|
$('[data-tab-name]').click(function () {
|
|
$(this).removeClass('active border-transparent')
|
|
.addClass('active border-indigo-500')
|
|
.siblings()
|
|
.removeClass('active border-indigo-500')
|
|
.addClass('border-transparent');
|
|
$('[data-tab]').hide();
|
|
$('[data-tab="' + $(this).data('tab-name') + '"]').show()
|
|
});
|
|
|
|
$('#clear-all').click(function () {
|
|
$('[data-tab]').html('')
|
|
$links.hide();
|
|
});
|
|
</script>
|
|
@endpush
|