This commit is contained in:
shim
2023-04-17 11:06:08 +09:00
parent d0b393aa97
commit 76264e09ad
4686 changed files with 552713 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
# 부트스트랩4 파일 업로드 테마
부트스트랩
## 주요기능
- 사진,파일 업로드
- 첨부물 메타정보 등록
- 첨부목록 숨김처리
- 대표이미지 지정
## 요구사항
- `widgets/_default/attach` 위젯 필요
- `/plugins/jquery-form/4.2.2/jquery.form.min.js` 플러그인 필요

View File

@@ -0,0 +1,5 @@
<?php
$d['theme']['hidden_photo'] = "0"; // 이미지 추가시 사진 숨김여부 기본값 (숨김=1/보임=0)
$d['theme']['allowedTypes'] = ""; // 업로드 가능한 파일 확장자. (명시하지 않으면 파일 확장자 필터링하지 않음.)
$d['theme']['multiple'] = "1"; // 멀티 업로드 (허용=1/비허용=0)
?>

View File

@@ -0,0 +1,242 @@
<?php include $g['dir_attach_theme'].'/modals.php'; // 모달 페이지 인클루드 ?>
<?php getImport('jquery-form','jquery.form.min','4.2.2','js'); ?>
<script>
var inputId='attach-file-input'; // 실제 작옹하는 input 엘리먼트 id 값을 옵션으로 지정을 해준다. (커스텀 버튼으로 click 이벤트 바인딩)
var attach_file_saveDir = '<?php echo $g['path_file'].$parent_module?>/';// 파일 업로드 폴더
var attach_module_theme = '<?php echo $attach_module_theme?>';// attach 모듈 테마
var uploadElement = $('#attach-files');
$(document).ready(function() {
var uploadObj = uploadElement.RbUploadFile({
<?php if ($d['theme']['allowedTypes']): ?>
allowedTypes:"<?php echo $d['theme']['allowedTypes'] ?>",// 업로드 가능한 파일 확장자. 여기에 명시하지 않으면 파일 확장자 필터링하지 않음.
<?php endif; ?>
fileName: "files", // <input type="file" name=""> 의 name 값 --> php 에서 파일처리할 때 사용됨.
multiple: <?php echo $d['theme']['multiple']?'true':'false' ?>, // 멀티업로드를 할 경우 true 로 해준다.
dragDrop:true,
uploadStr:"<i class='fa fa-folder-o fa-fw'></i> 파일찾기", // 파일첨부 버튼
maxFileCount: <?php echo $d['mediaset']['maxnum_file'] ?>, // 1회 첨부파일 갯수
maxFileSize: <?php echo $d['mediaset']['maxsize_file'] ?>, // 1회 첨부파일 용량
inputId:inputId, // 실제 작옹하는 input 엘리먼트 id 값을 옵션으로 지정을 해준다. (커스텀 버튼으로 click 이벤트 바인딩)
formData: {"saveDir":attach_file_saveDir,"theme":attach_module_theme}, // 추가 데이타 세팅
onSubmit:function(files){
console.log('모든 파일이 업로드가 시작되었습니다.')
uploadElement.isLoading({
text: "<i class='fa fa-spinner fa-spin'></i> 업로드중...",
position: 'overlay'
});
},
onSuccess:function(files,data,xhr,pd){
console.log('파일이 업로드 되었습니다.');
uploadElement.isLoading("hide");
// 포스트 글쓰기 페이지 저장버튼 출력
$('[data-role="postsubmit"]').removeClass('d-none');
$('[data-role="library"]').addClass('d-none');
},
afterUploadAll:function(obj) {
console.log('전체 업로드 완료')
uploadElement.isLoading("hide");
}
});
// main.js 기본값 세팅
var attach_settings={
module : 'mediaset',
theme : attach_module_theme,
handler_photo : '<?php echo $attach_handler_photo?>',
handler_file : '<?php echo $attach_handler_file?>',
handler_getModalList : '<?php echo $attach_handler_getModalList?>',
listModal : '#modal-attach'
}
uploadElement.RbAttachTheme(attach_settings);
});
$('[data-attach-act="insert"]').tooltip({
trigger: 'hover',
title : '본문삽입'
});
$('body').on('click','[data-attach-act="insert"]',function(){
$(this).attr('data-original-title', '본문삽입 되었습니다.')
$(this).tooltip('show');
$(this).attr('data-original-title', '본문삽입')
});
$('#modal-attach-file-meta').on('shown.bs.modal', function (event) {
var modal = $(this)
modal.find('[data-role="filename"]').focus()
})
$('#modal-attach-photo-tag').on('show.bs.modal', function (event) {
var modal = $(this)
var src = modal.find('[data-role="image-marker-area"] img').attr('src');
var point = {};
var parnet_uid = $('[name="uid"]').val();
modal.find('[data-role="test"]').text('');
//이미지가 로드 되었을때,
modal.find('[data-role="image-marker-area"] img').one('load',function() {
$.getJSON(rooturl+'/?r='+raccount+'&m=mediaset&a=get_attachTag&src='+src,{
format: "json"
},function(data){
var tag = data.tag;
if (tag) {
var point = JSON.parse(tag);
} else {
var point = {};
}
if (point) {
for(var i in point){ //포인터 출력
var goods_uid = point[i].g;
modal.find('[data-role="image-marker-area"]').append('<a href="#" data-toggle="tooltip" tabindex="0" class="fa fa-plus" id="' + i + '" style="left:' + point[i].x + '%;top:' + point[i].y + '%" data-goods='+point[i].g+'></a>');
$.getJSON(rooturl+'/?r='+raccount+'&m=shop&a=get_goodsData&uid='+goods_uid+'&featured_size=140x140', {
format: "json"
},
function(data) {
var uid = data.uid;
var name = data.name;
var price=data.price;
var featured_img=data.featured_img;
modal.find('a[data-goods="'+uid+'"]').attr('data-original-title',name).attr('data-name',name).attr('data-price',price).attr('data-price',price);
modal.find('[data-toggle="tooltip"]').tooltip();
});
}
}
modal.find('[data-role="image-marker-area"]').off().on('click', 'a', function(e) {
e.preventDefault();
var id = $(this).attr('id');
var goods_uid = $(this).attr('data-goods');
var name = $(this).attr('data-name');
var price = $(this).attr('data-price');
modal.find('[data-role="image-marker-area"] a').removeClass('active');
$(this).addClass('active');
modal.find('[name="goods"]').val(goods_uid)
modal.find('[data-role="comment"] textarea').val(name).attr('data-id', id);
modal.find('[data-role="comment"]').show();
modal.find('[data-role="test"]').text(JSON.stringify(point));
modal.find('[data-toggle="tooltip"]').tooltip('hide');
});
modal.find('[data-role="image-marker-area"] img').on('click', function(e) {
var position = getPosition(e, 1);
var x = position.x;
var y = position.y;
var id = randomId();
modal.find('[data-role="image-marker-area"] a').removeClass('active');
modal.find('[data-role="image-marker-area"]').append('<a href="#" tabindex="0" data-toggle="tooltip" title="" class="fa fa-plus active" id="' + id + '" style="left:' + x + '%;top:' + y + '%"></a>');
point[id] = {
'x': x,
'y': y,
'g': ''
};
// $(this).removeClass('edit');
modal.find('[data-role="comment"]').show();
modal.find('[name="goods"]').val('').focus();
modal.find('[data-role="comment"] textarea').val('').attr('data-id', id);
modal.find('[data-role="test"]').text(JSON.stringify(point));
});
// $('[data-role="image-marker-area"]').on('click', 'a', function(e) {
// e.preventDefault();
// $('[data-toggle="popover"]').popover('hide');
// $(this).popover('show');
// });
modal.find('#imagetag-cancel').off().on('click', function(e) {
modal.find('[data-role="comment"]').hide();
var i = modal.find('[data-role="comment"] textarea').data('id');
if (point[i].t == 'none')
$('#' + i).remove();
modal.find('[data-role="image-marker-area"] a').removeClass('active');
modal.find('[data-role="test"]').text(JSON.stringify(point));
});
modal.find('[data-attach-act="saveTag"]').on('click', function(e) {
$('[data-role="image-marker-area"] a').removeClass('active');
var uid = $(this).attr('data-id');
var i = modal.find('[data-role="comment"] textarea').data('id');
var goods_uid = modal.find('[name="goods"]').val();
point[i].g = goods_uid;
$('#' + i).attr('data-goods',goods_uid);
modal.find('[data-role="comment"]').hide();
modal.find('[data-role="image-marker-area"] a').removeClass('active');
modal.find('[data-role="tag"]').val(JSON.stringify(point));
modal.find('[data-role="test"]').text(JSON.stringify(point));
//DB저장하기
$.post(rooturl+'/?r='+raccount+'&m=mediaset&a=edit',{
uid : uid,
act : 'editTag',
tag : JSON.stringify(point)
},function(response,status){
if(status=='success'){
var result = $.parseJSON(response);
} else {
}
});
});
modal.find('#imagetag-delete').off().on('click', function(e) {
modal.find('[data-role="comment"]').hide();
var i = modal.find('[data-role="comment"] textarea').attr('data-id');
modal.find('#' + i).remove();
modal.find('[data-role="comment"] textarea').attr('data-id','');
delete point[i];
modal.find('[data-role="test"]').text(JSON.stringify(point));
});
});
});
//연결된 상품 불러기
$.post(rooturl+'/?r='+raccount+'&m=shop&a=get_postAttachGoods',{
markup_file: 'attach_goods_dropdown_item',
uid : parnet_uid,
featured_size : '70x52'
},function(response,status){
if(status=='success'){
var result = $.parseJSON(response);
var list=result.list;
$('[data-role="attach-goods"]').html(list);
} else {
alert(status);
}
});
})
$('#modal-attach-photo-tag').on('hidden.bs.modal', function (event) {
var modal = $(this)
modal.find('[data-role="image"] img').attr('src','');
modal.find('[data-role="image-marker-area"] a').remove()
})
</script>

View File

@@ -0,0 +1,123 @@
<?php
// 위젯 설정값 세팅
$parent_module=$d['attach']['parent_module']; // 첨부파일 사용하는 모듈
$parent_data=$d['attach']['parent_data']; // 해당 포스트 데이타 (수정시 필요)
$attach_module_theme=$d['attach']['theme']; // 첨부파일 테마
$attach_mode=$d['attach']['mod']; // list, main...
$attach_handler_file=$d['attach']['handler_file']; //파일첨부 실행 엘리먼트 button or 기타 엘리먼트 data-role="" 형태로 하는 것을 권고
$attach_handler_photo=$d['attach']['handler_photo']; // 사진첨부 실행 엘리먼트 button or 기타 엘리먼트 data-role="" 형태로 하는 것을 권고
$attach_handler_getModalList=$d['attach']['handler_getModalList']; // 첨부파일 리스트 호출 handler
$attach_object_type=$d['attach']['object_type']; // 첨부 대상에 따른 분류 : photo, file, link, video....
$editor_type=$d['attach']['editor_type']; // 에디터 타입 : html,markdown
require_once $g['dir_attach_theme'].'/main.func.php'; // 함수 인클루드
require_once $g['dir_attach_theme'].'/_var.php'; // 테마변수 인클루드
require_once $g['path_module'].'mediaset/var/var.php'; //모듈 공통변수 인클루드
?>
<script src="<?php echo $g['url_attach_theme']?>/js/fileuploader.js"></script>
<script src="<?php echo $g['url_attach_theme']?>/main.js"></script>
<!-- nestable : https://github.com/dbushell/Nestable -->
<?php getImport('nestable','jquery.nestable',false,'js') ?>
<style media="screen">
.ajax-upload-dragdrop {
margin-bottom: 20px;
padding: 30px;
border: 2px dashed #d1d1d1;
color: #999;
text-align: center;
vertical-align: middle;
}
.ajax-upload-dragdrop.state-hover {
box-shadow: 0 0 2px rgba(0,0,0,0.3), 0 0 4px rgba(26,170,85,0.4);
border: 1px solid #007bff;
}
.ajax-upload-dragdrop.state-hover::before {
display: inline-block;
font: normal normal normal 20px/1 FontAwesome;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
content: '\f093';
font-size: 2.5em;
text-align: center;
}
.ajax-upload-dragdrop.state-hover .ajax-file-upload,
.ajax-upload-dragdrop.state-hover span {
opacity: 0;
display: none
}
::-webkit-file-upload-button { cursor:pointer; }
/**
* Nestable
*/
[data-role="attach"] .dd { }
[data-role="attach"] .dd-list { display: block; position: relative; list-style: none; }
[data-role="attach"] .dd-list .dd-list { }
[data-role="attach"] .dd-collapsed .dd-list { display: none; }
[data-role="attach"] .dd-item,
[data-role="attach"] .dd-empty,
[data-role="attach"] .dd-placeholder { }
[data-role="attach"] .dd-handle {
position: absolute;
margin: 0;
left: 0;
top: 0;
bottom:0;
cursor: pointer;
width: 25px;
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
background-color: #eff3f6;
background-image: linear-gradient(-180deg, #fafbfc 0%, #eff3f6 90%);
background-repeat: repeat-x;
background-position: -1px -1px;
background-size: 110% 110%;
border-right: 1px solid rgba(27,31,35,0.1);
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
[data-role="attach"] .dd-handle:hover {
background-color: #e6ebf1;
background-image: linear-gradient(-180deg, #f0f3f6 0%, #e6ebf1 90%);
background-position: -.5em;
}
[data-role="attach"] .dd-handle:before {
display: block;
position: absolute;
left: 0;
top: 50%;
margin-top: -7px;
width: 100%;
text-align: center;
text-indent: 0;
color: #494949;
font-size: 14px;
font-weight: normal;
}
[data-role="attach"] .dd-placeholder,
[data-role="attach"] .dd-empty { margin: 5px 0; padding: 0; min-height: 30px; background: #f2fbff; border: 1px dashed #b6bcbf; box-sizing: border-box; -moz-box-sizing: border-box; }
[data-role="attach"] .dd-empty { border: 1px dashed #bbb; min-height: 100px; background-color: #e5e5e5;
background-image: -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
-webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
background-image: -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
-moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
background-size: 60px 60px;
background-position: 0 0, 30px 30px;
}
[data-role="attach"] .dd-dragel { position: absolute; pointer-events: none; z-index: 9999; }
[data-role="attach"] .dd-dragel > .dd-item .dd-handle { margin-top: 0; }
[data-role="attach"] .dd-dragel .dd-handle {
-webkit-box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1);
box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1);
}
</style>

View File

@@ -0,0 +1,902 @@
/*!
* jQuery Upload File Plugin
* version: 4.0.9
* @requires jQuery v1.5 or later & form plugin
* Copyright (c) 2013 Ravishanker Kusuma
* http://hayageek.com/
* https://github.com/hayageek/jquery-upload-file
*/
(function ($) {
var feature = {};
feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
feature.formdata = window.FormData !== undefined;
$.fn.RbUploadFile = function (options) {
// This is the easiest way to have default options.
var s = $.extend({
// These are the defaults.
url: rooturl+'/?r='+raccount+'&m=mediaset&a=upload', // attach 모듈 upload 액션 파일 지정
method: "POST",
enctype: "multipart/form-data",
returnType: null,
allowDuplicates: true,
duplicateStrict: false,
allowedTypes: "*",
//For list of acceptFiles
// http://stackoverflow.com/questions/11832930/html-input-file-accept-attribute-file-type-csv
acceptFiles: "*",
fileName: "file",
formData: false,
dynamicFormData:false,
maxFileSize: -1,
maxFileCount: -1,
multiple: true,
dragDrop: false, // 수정 dragDrop 사용하지 않음
autoSubmit: true,
showCancel: true,
showAbort: true,
showDone: false,
showDelete: false,
showError: true,
showStatusAfterSuccess: false, // 수정
showStatusAfterError: true,
showFileCounter: false, // 수정
fileCounterStyle: "). ",
showFileSize: true,
showProgress: true,
nestedForms: true,
showDownload: false,
onLoad: function (obj) {},
onSelect: function (files) {
return true;
},
onSubmit: function (files, xhr) {},
onSuccess: function (files, response, xhr, pd) {},
onError: function (files, status, message, pd) {},
onCancel: function (files, pd) {},
onAbort: function (files, pd) {},
downloadCallback: false,
deleteCallback: false,
afterUploadAll: false,
serialize:true,
sequential:false,
sequentialCount:2,
customProgressBar: false,
abortButtonClass: "btn btn-light btn-sm mt-2",
cancelButtonClass: "ajax-file-upload-cancel content-padded text-danger",
dragDropContainerClass: "ajax-upload-dragdrop",
dragDropHoverClass: "state-hover",
errorClass: "alert alert-danger",
uploadButtonClass: "ajax-file-upload",
dragDropStr: "<span class='align-middle'>또는 여기에 파일 놓기</span>",
uploadStr:"Upload",
uploadStr:"<i class='fa fa fa-upload fa-fw'></i> 파일첨부", // 첨부파일 버튼을 커스텀할 수 있도록 숨긴다.
abortStr: "취소",
cancelStr: "취소",
deletelStr: "삭제",
doneStr: "완료",
multiDragErrorStr: "드래그앤 드랍이 허용되지 않습니다.",
extErrorStr: "허용 된 확장가 아닙니다.: ",
duplicateErrorStr: "이미 존재하는 파일 입니다.",
sizeErrorStr: "허용 된 최대 크기를 초과합니다.: ",
uploadErrorStr: "업로드가 허용되지 않습니다.",
maxFileCountErrorStr: " 최대 허용 파일 수가 초과 되었습니다.:",
downloadStr: "Download",
customErrorKeyStr: "content-padded text-danger",
showQueueDiv: false,
// statusBarWidth: 400,
// dragdropWidth: 400,
showPreview: false,
previewHeight: "auto",
previewWidth: "100%",
extraHTML:false,
uploadQueueOrder:'top'
}, options);
this.fileCounter = 1;
this.selectedFiles = 0;
var formGroup = "ajax-file-upload-" + (new Date().getTime());
this.formGroup = formGroup;
this.errorLog = $("<div></div>"); //Writing errors
this.responses = [];
this.existingFileNames = [];
if(!feature.formdata) //check drag drop enabled.
{
s.dragDrop = false;
}
if(!feature.formdata) {
s.multiple = false;
}
$(this).html("");
var obj = this;
var uploadLabel = $('<div class="btn btn-link muted-link">' + s.uploadStr + '</div>');
$(uploadLabel).addClass(s.uploadButtonClass);
// wait form ajax Form plugin and initialize
(function checkAjaxFormLoaded() {
if($.fn.ajaxForm) {
if(s.dragDrop) {
var dragDrop = $('<div class="' + s.dragDropContainerClass + '" style="vertical-align:top;"></div>').width(s.dragdropWidth);
$(obj).append(dragDrop);
$(dragDrop).append(uploadLabel);
$(dragDrop).append($(s.dragDropStr));
setDragDropHandlers(obj, s, dragDrop);
} else {
$(obj).append(uploadLabel);
}
$(obj).append(obj.errorLog);
// 미리보기 div 출력 삭제 - 이 부분은 해당 페이지에서 커스텀으로 처리한다.
if(s.showQueueDiv)
obj.container =$("#"+s.showQueueDiv);
else
obj.container = $("<div class='ajax-file-upload-container'></div>").insertAfter($(obj));
s.onLoad.call(this, obj);
createCustomInputFile(obj, formGroup, s, uploadLabel);
} else window.setTimeout(checkAjaxFormLoaded, 10);
})();
this.startUpload = function () {
$("form").each(function(i,items)
{
if($(this).hasClass(obj.formGroup))
{
mainQ.push($(this));
}
});
if(mainQ.length >= 1 )
submitPendingUploads();
}
this.getFileCount = function () {
return obj.selectedFiles;
}
this.stopUpload = function () {
$("." + s.abortButtonClass).each(function (i, items) {
if($(this).hasClass(obj.formGroup)) $(this).click();
});
$("." + s.cancelButtonClass).each(function (i, items) {
if($(this).hasClass(obj.formGroup)) $(this).click();
});
}
this.cancelAll = function () {
$("." + s.cancelButtonClass).each(function (i, items) {
if($(this).hasClass(obj.formGroup)) $(this).click();
});
}
this.update = function (settings) {
//update new settings
s = $.extend(s, settings);
}
this.reset = function (removeStatusBars) {
obj.fileCounter = 1;
obj.selectedFiles = 0;
obj.errorLog.html("");
//remove all the status bars.
if(removeStatusBars != false)
{
obj.container.html("");
}
}
this.remove = function()
{
obj.container.html("");
$(obj).remove();
}
//This is for showing Old files to user.
this.createProgress = function (filename,filepath,filesize) {
var pd = new createProgressDiv(this, s);
pd.progressDiv.show();
pd.progressbar.width('100%');
var fileNameStr = "";
if(s.showFileCounter)
fileNameStr = obj.fileCounter + s.fileCounterStyle + filename;
else fileNameStr = filename;
if(s.showFileSize)
fileNameStr += " ("+getSizeStr(filesize)+")";
pd.filename.html(fileNameStr);
obj.fileCounter++;
obj.selectedFiles++;
if(s.showPreview)
{
pd.preview.attr('src',filepath);
pd.preview.show();
}
if(s.showDownload) {
pd.download.show();
pd.download.click(function () {
if(s.downloadCallback) s.downloadCallback.call(obj, [filename]);
});
}
if(s.showDelete)
{
pd.del.show();
pd.del.click(function () {
pd.statusbar.hide().remove();
var arr = [filename];
if(s.deleteCallback) s.deleteCallback.call(this, arr, pd);
obj.selectedFiles -= 1;
updateFileCounter(s, obj);
});
}
return pd;
}
this.getResponses = function () {
return this.responses;
}
var mainQ=[];
var progressQ=[]
var running = false;
function submitPendingUploads() {
if(running) return;
running = true;
(function checkPendingForms() {
//if not sequential upload all files
if(!s.sequential) s.sequentialCount=99999;
if(mainQ.length == 0 && progressQ.length == 0)
{
if(s.afterUploadAll) s.afterUploadAll(obj);
running= false;
}
else
{
if( progressQ.length < s.sequentialCount)
{
var frm = mainQ.shift();
if(frm != undefined)
{
progressQ.push(frm);
frm.submit();
}
}
window.setTimeout(checkPendingForms, 100);
}
})();
}
function setDragDropHandlers(obj, s, ddObj) {
ddObj.on('dragenter', function (e) {
e.stopPropagation();
e.preventDefault();
$(this).addClass(s.dragDropHoverClass);
});
ddObj.on('dragover', function (e) {
e.stopPropagation();
e.preventDefault();
var that = $(this);
if (that.hasClass(s.dragDropContainerClass) && !that.hasClass(s.dragDropHoverClass)) {
that.addClass(s.dragDropHoverClass);
}
});
ddObj.on('drop', function (e) {
e.preventDefault();
$(this).removeClass(s.dragDropHoverClass);
obj.errorLog.html("");
var files = e.originalEvent.dataTransfer.files;
if(!s.multiple && files.length > 1) {
if(s.showError) $("<div class='" + s.errorClass + "'>" + s.multiDragErrorStr + "</div>").appendTo(obj.errorLog);
return;
}
if(s.onSelect(files) == false) return;
serializeAndUploadFiles(s, obj, files);
});
ddObj.on('dragleave', function (e) {
$(this).removeClass(s.dragDropHoverClass);
});
$(document).on('dragenter', function (e) {
e.stopPropagation();
e.preventDefault();
});
$(document).on('dragover', function (e) {
e.stopPropagation();
e.preventDefault();
var that = $(this);
if (!that.hasClass(s.dragDropContainerClass)) {
that.removeClass(s.dragDropHoverClass);
}
});
$(document).on('drop', function (e) {
e.stopPropagation();
e.preventDefault();
$(this).removeClass(s.dragDropHoverClass);
});
}
function getSizeStr(size) {
var sizeStr = "";
var sizeKB = size / 1024;
if(parseInt(sizeKB) > 1024) {
var sizeMB = sizeKB / 1024;
sizeStr = sizeMB.toFixed(2) + " MB";
} else {
sizeStr = sizeKB.toFixed(2) + " KB";
}
return sizeStr;
}
function serializeData(extraData) {
var serialized = [];
if(jQuery.type(extraData) == "string") {
serialized = extraData.split('&');
} else {
serialized = $.param(extraData).split('&');
}
var len = serialized.length;
var result = [];
var i, part;
for(i = 0; i < len; i++) {
serialized[i] = serialized[i].replace(/\+/g, ' ');
part = serialized[i].split('=');
result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]);
}
return result;
}
function noserializeAndUploadFiles(s, obj, files) {
var ts = s;
var fd = new FormData();
var fileArray = [];
var fileName = s.fileName.replace("[]", "");
var fileListStr="";
for (var i = 0; i < files.length; i++) {
if (!isFileTypeAllowed(obj, s, files[i].name)) {
if (s.showError) $("<div><font color='red'><b>" + files[i].name + "</b> " + s.extErrorStr + s.allowedTypes + "</font></div>").appendTo(obj.errorLog);
continue;
}
if (s.maxFileSize != -1 && files[i].size > s.maxFileSize) {
if (s.showError) $("<div><font color='red'><b>" + files[i].name + "</b> " + s.sizeErrorStr + getSizeStr(s.maxFileSize) + "</font></div>").appendTo(obj.errorLog);
continue;
}
fd.append(fileName+"[]", files[i]);
fileArray.push(files[i].name);
fileListStr += obj.fileCounter + "). " + files[i].name+"<br>";
obj.fileCounter++;
}
if(fileArray.length ==0 ) return;
var extraData = s.formData;
if (extraData) {
var sData = serializeData(extraData);
for (var j = 0; j < sData.length; j++) {
if (sData[j]) {
fd.append(sData[j][0], sData[j][1]);
}
}
}
ts.fileData = fd;
var pd = new createProgressDiv(obj, s);
pd.filename.html(fileListStr);
var form = $("<form style='display:block; position:absolute;left: 150px;' class='" + obj.formGroup + "' method='" + s.method + "' action='" + s.url + "' enctype='" + s.enctype + "'></form>");
form.appendTo('body');
ajaxFormSubmit(form, ts, pd, fileArray, obj);
}
function serializeAndUploadFiles(s, obj, files) {
for(var i = 0; i < files.length; i++) {
if(!isFileTypeAllowed(obj, s, files[i].name)) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + files[i].name + "</b> " + s.extErrorStr + s.allowedTypes + "</div>").appendTo(obj.errorLog);
continue;
}
if(!s.allowDuplicates && isFileDuplicate(obj, files[i].name)) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + files[i].name + "</b> " + s.duplicateErrorStr + "</div>").appendTo(obj.errorLog);
continue;
}
if(s.maxFileSize != -1 && files[i].size > s.maxFileSize) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + files[i].name + "</b> " + s.sizeErrorStr + getSizeStr(s.maxFileSize) + "</div>").appendTo(
obj.errorLog);
continue;
}
if(s.maxFileCount != -1 && obj.selectedFiles >= s.maxFileCount) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + files[i].name + "</b> " + s.maxFileCountErrorStr + s.maxFileCount + "개까지 허용됨</div>").appendTo(
obj.errorLog);
continue;
}
obj.selectedFiles++;
obj.existingFileNames.push(files[i].name);
var ts = s;
var fd = new FormData();
var fileName = s.fileName.replace("[]", "");
fd.append(fileName, files[i]);
var extraData = s.formData;
if(extraData) {
var sData = serializeData(extraData);
for(var j = 0; j < sData.length; j++) {
if(sData[j]) {
fd.append(sData[j][0], sData[j][1]);
}
}
}
ts.fileData = fd;
var pd = new createProgressDiv(obj, s);
var fileNameStr = "";
if(s.showFileCounter) fileNameStr = obj.fileCounter + s.fileCounterStyle + files[i].name
else fileNameStr = files[i].name;
if(s.showFileSize)
fileNameStr += " ("+getSizeStr(files[i].size)+")";
pd.filename.html(fileNameStr);
var form = $("<form style='display:block; position:absolute;left: 150px;' class='" + obj.formGroup + "' method='" + s.method + "' action='" +
s.url + "' enctype='" + s.enctype + "'></form>");
form.appendTo('body');
var fileArray = [];
fileArray.push(files[i].name);
ajaxFormSubmit(form, ts, pd, fileArray, obj, files[i]);
obj.fileCounter++;
}
}
function isFileTypeAllowed(obj, s, fileName) {
var fileExtensions = s.allowedTypes.toLowerCase().split(/[\s,]+/g);
var ext = fileName.split('.').pop().toLowerCase();
if(s.allowedTypes != "*" && jQuery.inArray(ext, fileExtensions) < 0) {
return false;
}
return true;
}
function isFileDuplicate(obj, filename) {
var duplicate = false;
if (obj.existingFileNames.length) {
for (var x=0; x<obj.existingFileNames.length; x++) {
if (obj.existingFileNames[x] == filename
|| s.duplicateStrict && obj.existingFileNames[x].toLowerCase() == filename.toLowerCase()
) {
duplicate = true;
}
}
}
return duplicate;
}
function removeExistingFileName(obj, fileArr) {
if (obj.existingFileNames.length) {
for (var x=0; x<fileArr.length; x++) {
var pos = obj.existingFileNames.indexOf(fileArr[x]);
if (pos != -1) {
obj.existingFileNames.splice(pos, 1);
}
}
}
}
function getSrcToPreview(file, obj) {
if(file) {
obj.show();
var reader = new FileReader();
reader.onload = function (e) {
obj.attr('src', e.target.result);
};
reader.readAsDataURL(file);
}
}
function updateFileCounter(s, obj) {
if(s.showFileCounter) {
var count = $(obj.container).find(".ajax-file-upload-filename").length;
obj.fileCounter = count + 1;
$(obj.container).find(".ajax-file-upload-filename").each(function (i, items) {
var arr = $(this).html().split(s.fileCounterStyle);
var fileNum = parseInt(arr[0]) - 1; //decrement;
var name = count + s.fileCounterStyle + arr[1];
$(this).html(name);
count--;
});
}
}
// input 폼 세팅함수
function createCustomInputFile (obj, group, s, uploadLabel) {
//var fileUploadId = "ajax-upload-id-" + (new Date().getTime());
var fileUploadId=s.inputId; // 옵션에서 지정한 id 값으로 세팅한다.
var form = $("<form method='" + s.method + "' action='" + s.url + "' enctype='" + s.enctype + "'></form>");
var fileInputStr = "<input type='file' id='" + fileUploadId + "' name='" + s.fileName + "' accept='" + s.acceptFiles + "'/>";
if(s.multiple) {
if(s.fileName.indexOf("[]") != s.fileName.length - 2) // if it does not endwith
{
s.fileName += "[]";
}
fileInputStr = "<input type='file' id='" + fileUploadId + "' name='" + s.fileName + "' accept='" + s.acceptFiles + "' multiple/>";
}
var fileInput = $(fileInputStr).appendTo(form);
//fileInput.change(function () {
$(form).on('change','#'+fileUploadId,function(){
console.log(fileUploadId);
obj.errorLog.html("");
var fileExtensions = s.allowedTypes.toLowerCase().split(",");
var fileArray = [];
if(this.files) //support reading files
{
for(i = 0; i < this.files.length; i++) {
fileArray.push(this.files[i].name);
}
if(s.onSelect(this.files) == false) return;
} else {
var filenameStr = $(this).val();
var flist = [];
fileArray.push(filenameStr);
if(!isFileTypeAllowed(obj, s, filenameStr)) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + filenameStr + "</b> " + s.extErrorStr + s.allowedTypes + "</div>").appendTo(
obj.errorLog);
return;
}
//fallback for browser without FileAPI
flist.push({
name: filenameStr,
size: 'NA'
});
if(s.onSelect(flist) == false) return;
}
updateFileCounter(s, obj);
uploadLabel.unbind("click");
form.hide();
createCustomInputFile(obj, group, s, uploadLabel);
form.addClass(group);
if(s.serialize && feature.fileapi && feature.formdata) //use HTML5 support and split file submission
{
form.removeClass(group); //Stop Submitting when.
var files = this.files;
form.remove();
serializeAndUploadFiles(s, obj, files);
} else {
var fileList = "";
for(var i = 0; i < fileArray.length; i++) {
if(s.showFileCounter) fileList += obj.fileCounter + s.fileCounterStyle + fileArray[i] + "<br>";
else fileList += fileArray[i] + "<br>";;
obj.fileCounter++;
}
if(s.maxFileCount != -1 && (obj.selectedFiles + fileArray.length) > s.maxFileCount) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + fileList + "</b> " + s.maxFileCountErrorStr + s.maxFileCount + "</div>").appendTo(
obj.errorLog);
return;
}
obj.selectedFiles += fileArray.length;
var pd = new createProgressDiv(obj, s);
pd.filename.html(fileList);
ajaxFormSubmit(form, s, pd, fileArray, obj, null);
}
});
if(s.nestedForms) {
form.css({
'margin': 0,
'padding': 0
});
uploadLabel.css({
position: 'relative',
overflow: 'hidden',
cursor: 'pointer'
});
fileInput.css({
position: 'absolute',
'cursor': 'pointer',
'top': '0px',
'width': '100%',
'height': '100%',
'left': '0px',
'z-index': '100',
'opacity': '0.0',
'filter': 'alpha(opacity=0)',
'-ms-filter': "alpha(opacity=0)",
'-khtml-opacity': '0.0',
'-moz-opacity': '0.0'
});
form.appendTo(uploadLabel);
} else {
form.appendTo($('body'));
form.css({
margin: 0,
padding: 0,
display: 'block',
position: 'absolute',
left: '-250px'
});
if(navigator.appVersion.indexOf("MSIE ") != -1) //IE Browser
{
uploadLabel.attr('for', fileUploadId);
} else {
uploadLabel.click(function () {
fileInput.click();
});
}
}
}
function defaultProgressBar(obj,s)
{
this.statusbar = $("<section class='mb-3'></section>").width(s.statusBarWidth);
this.preview = $("<img class='ajax-file-upload-preview' />").width(s.previewWidth).height(s.previewHeight).appendTo(this.statusbar).hide();
this.filename = $("<div class='text-muted small my-2'></div>").appendTo(this.statusbar);
this.progressDiv = $("<div class='progress rounded-0' style='height: 15px;'>").appendTo(this.statusbar).hide();
this.progressbar = $("<div class='progress-bar progress-bar-striped progress-bar-animated'></div>").appendTo(this.progressDiv);
this.abort = $("<button>" + s.abortStr + "</button>").appendTo(this.statusbar).hide();
this.cancel = $("<div>" + s.cancelStr + "</div>").appendTo(this.statusbar).hide();
this.done = $("<div>" + s.doneStr + "</div>").appendTo(this.statusbar).hide();
this.download = $("<div>" + s.downloadStr + "</div>").appendTo(this.statusbar).hide();
this.del = $("<div>" + s.deletelStr + "</div>").appendTo(this.statusbar).hide();
// this.abort.addClass("ajax-file-upload-red");
this.done.addClass("ajax-file-upload-green");
this.download.addClass("ajax-file-upload-green");
this.cancel.addClass("ajax-file-upload-red");
this.del.addClass("ajax-file-upload-red");
return this;
}
function createProgressDiv(obj, s) {
var bar = null;
if(s.customProgressBar)
bar = new s.customProgressBar(obj,s);
else
bar = new defaultProgressBar(obj,s);
bar.abort.addClass(obj.formGroup);
bar.abort.addClass(s.abortButtonClass);
bar.cancel.addClass(obj.formGroup);
bar.cancel.addClass(s.cancelButtonClass);
if(s.extraHTML)
bar.extraHTML = $("<div class='extrahtml'>"+s.extraHTML()+"</div>").insertAfter(bar.filename);
if(s.uploadQueueOrder == 'bottom')
$(obj.container).append(bar.statusbar);
else
$(obj.container).prepend(bar.statusbar);
return bar;
}
function ajaxFormSubmit(form, s, pd, fileArray, obj, file) {
var currentXHR = null;
var options = {
cache: false,
contentType: false,
processData: false,
forceSync: false,
type: s.method,
data: s.formData,
formData: s.fileData,
dataType: s.returnType,
beforeSubmit: function (formData, $form, options) {
if(s.onSubmit.call(this, fileArray) != false) {
if(s.dynamicFormData)
{
var sData = serializeData(s.dynamicFormData());
if(sData) {
for(var j = 0; j < sData.length; j++) {
if(sData[j]) {
if(s.fileData != undefined) options.formData.append(sData[j][0], sData[j][1]);
else options.data[sData[j][0]] = sData[j][1];
}
}
}
}
if(s.extraHTML)
{
$(pd.extraHTML).find("input,select,textarea").each(function(i,items)
{
if(s.fileData != undefined) options.formData.append($(this).attr('name'),$(this).val());
else options.data[$(this).attr('name')] = $(this).val();
});
}
return true;
}
pd.statusbar.append("<div class='" + s.errorClass + "'>" + s.uploadErrorStr + "</div>");
pd.cancel.show()
form.remove();
pd.cancel.click(function () {
mainQ.splice(mainQ.indexOf(form), 1);
removeExistingFileName(obj, fileArray);
pd.statusbar.remove();
s.onCancel.call(obj, fileArray, pd);
obj.selectedFiles -= fileArray.length; //reduce selected File count
updateFileCounter(s, obj);
});
return false;
},
beforeSend: function (xhr, o) {
pd.progressDiv.show();
pd.cancel.hide();
pd.done.hide();
if(s.showAbort) {
pd.abort.show();
pd.abort.click(function () {
removeExistingFileName(obj, fileArray);
xhr.abort();
obj.selectedFiles -= fileArray.length; //reduce selected File count
s.onAbort.call(obj, fileArray, pd);
});
}
if(!feature.formdata) //For iframe based push
{
pd.progressbar.width('5%');
} else pd.progressbar.width('1%'); //Fix for small files
},
uploadProgress: function (event, position, total, percentComplete) {
//Fix for smaller file uploads in MAC
if(percentComplete > 98) percentComplete = 98;
var percentVal = percentComplete + '%';
if(percentComplete > 1) pd.progressbar.width(percentVal)
if(s.showProgress) {
pd.progressbar.html(percentVal);
pd.progressbar.css('text-align', 'center');
}
},
success: function (data, message, xhr) {
pd.cancel.remove();
progressQ.pop();
//For custom errors.
if(s.returnType == "json" && $.type(data) == "object" && data.hasOwnProperty(s.customErrorKeyStr)) {
pd.abort.hide();
var msg = data[s.customErrorKeyStr];
s.onError.call(this, fileArray, 200, msg, pd);
if(s.showStatusAfterError) {
pd.progressDiv.hide();
pd.statusbar.append("<span class='" + s.errorClass + "'>ERROR: " + msg + "</span>");
} else {
pd.statusbar.hide();
pd.statusbar.remove();
}
obj.selectedFiles -= fileArray.length; //reduce selected File count
form.remove();
return;
}
obj.responses.push(data);
pd.progressbar.width('100%')
if(s.showProgress) {
pd.progressbar.html('100%');
pd.progressbar.css('text-align', 'center');
}
pd.abort.hide();
s.onSuccess.call(this, fileArray, data, xhr, pd); // 해당 페이지에서 업로드 성공 후 추가 액션 가능
// 미리보기 출력
var result=$.parseJSON(data); // a.upload.php 에서 결과값을 preview & type 으로 구분하여 json 으로 보내준다.
var error=result.error; // 업로드 에러
var preview_default=result.preview_default; // 기본 리스트
var preview_modal=result.preview_modal; // 모달 리스트 (소스복사외 다른 메뉴는 노출하지 않는다.)
var attachType=result.type; // 해당 attachHandler 의 data-type 값 photo, file, map, link, people....
var previewBox_default=$('[data-role="attach-preview-'+attachType+'"]'); // type 에 따라서 미리보기 container 를 분리해서 지정한다.
var previewBox_modal=$('[data-role="modal-attach-preview-'+attachType+'"]'); // type 에 따라서 미리보기 container 를 분리해서 지정한다.
$(preview_default).prependTo(previewBox_default);// 업로드 성공후 미리보기 출력되는 부분 처리
$(preview_modal).prependTo(previewBox_modal);// 업로드 성공후 모달 미리보기 출력되는 부분 처리
if (error) $.notify({message: error},{type: "danger"});
if(s.showStatusAfterSuccess) {
if(s.showDone) {
pd.done.show();
pd.done.click(function () {
pd.statusbar.hide("slow");
pd.statusbar.remove();
});
} else {
pd.done.hide();
}
if(s.showDelete) {
pd.del.show();
pd.del.click(function () {
removeExistingFileName(obj, fileArray);
pd.statusbar.hide().remove();
if(s.deleteCallback) s.deleteCallback.call(this, data, pd);
obj.selectedFiles -= fileArray.length; //reduce selected File count
updateFileCounter(s, obj);
});
} else {
pd.del.hide();
}
} else {
pd.statusbar.hide("slow");
pd.statusbar.remove();
}
if(s.showDownload) {
pd.download.show();
pd.download.click(function () {
if(s.downloadCallback) s.downloadCallback(data);
});
}
form.remove();
},
error: function (xhr, status, errMsg) {
pd.cancel.remove();
progressQ.pop();
pd.abort.hide();
if(xhr.statusText == "abort") //we aborted it
{
pd.statusbar.hide("slow").remove();
updateFileCounter(s, obj);
} else {
s.onError.call(this, fileArray, status, errMsg, pd);
if(s.showStatusAfterError) {
pd.progressDiv.hide();
pd.statusbar.append("<span class='" + s.errorClass + "'>ERROR: " + errMsg + "</span>");
} else {
pd.statusbar.hide();
pd.statusbar.remove();
}
obj.selectedFiles -= fileArray.length; //reduce selected File count
}
form.remove();
}
};
if(s.showPreview && file != null) {
if(file.type.toLowerCase().split("/").shift() == "image") getSrcToPreview(file, pd.preview);
}
if(s.autoSubmit) {
form.ajaxForm(options);
mainQ.push(form);
submitPendingUploads();
} else {
if(s.showCancel) {
pd.cancel.show();
pd.cancel.click(function () {
mainQ.splice(mainQ.indexOf(form), 1);
removeExistingFileName(obj, fileArray);
form.remove();
pd.statusbar.remove();
s.onCancel.call(obj, fileArray, pd);
obj.selectedFiles -= fileArray.length; //reduce selected File count
updateFileCounter(s, obj);
});
}
form.ajaxForm(options);
}
}
return this;
}
}(jQuery));

View File

@@ -0,0 +1,290 @@
<?php
// 첨부파일 리스트 갯수 추출 함수
function getAttachNum($upload,$mod)
{
global $table;
$attach = getArrayString($upload);
$attach_file_num=0;// 첨부파일 수량
$hidden_file_num=0; // 숨김파일(다운로드 방지) 수량
foreach($attach['data'] as $val)
{
$U = getUidData($table['s_upload'],$val);
if($U['fileonly']==1) $attach_file_num++; // 전체 첨부파일 수량 증가
if($U['hidden']==1) $hidden_file_num++; // 숨김파일 수량 증가
}
$down_file_num=$attach_file_num-$hidden_file_num; // 다운로드 가능한 첨부파일
$result=array();
$result['modify']=$attach_file_num;
$result['view']=$down_file_num;
return $result[$mod];
}
// 첨부파일 리스트 추출 함수 (전체)
/*
$parent_data : 해당 포스트의 row 배열
$mod : upload or modal ==> 실제 업로드 모드 와 모달을 띄워서 본문에 삽입용도로 쓰거나
*/
function getAttachFileList($parent_data,$mod,$type,$editor)
{
global $table;
$upload=$parent_data['upload'];
$featured_img_uid=$parent_data['featured_img'];// 대표이미지 uid
$featured_video_uid=$parent_data['featured_video'];// 대표비디오 uid
$featured_audio_uid=$parent_data['featured_audio'];// 대표오디오 uid
if($type=='file') $sql='type=1';
else if($type=='photo') $sql='type=2';
else if($type=='audio') $sql='type=4';
else if($type=='video') $sql='type=5';
else if($type=='doc') $sql='type=6';
else if($type=='zip') $sql='type=7';
else if($type=='pdf') $sql='type=7';
else $sql='type=1';
$attach = getArrayString($upload);
$uid_q='(';
foreach($attach['data'] as $uid)
{
$uid_q.='uid='.$uid.' or ';
}
$uid_q=substr($uid_q,0,-4).')';
$sql=$sql.' and '.$uid_q;
$RCD=getDbArray($table['s_upload'],$sql,'*','gid','asc','',1);
$html='';
while($R=db_fetch_array($RCD)){
$U=getUidData($table['s_upload'],$R['uid']);
if($type=='file') $html.=getAttachFile($U,$mod,$featured_img_uid,$editor);
else if($type=='photo') $html.=getAttachFile($U,$mod,$featured_img_uid,$editor);
else if($type=='audio') $html.=getAttachAudio($U,$mod,$featured_audio_uid,$editor);
else if($type=='video') $html.=getAttachVideo($U,$mod,$featured_video_uid,$editor);
else if($type=='doc') $html.=getAttachFile($U,$mod,$featured_img_uid,$editor);
else if($type=='zip') $html.=getAttachFile($U,$mod,$featured_img_uid,$editor);
else if($type=='pdf') $html.=getAttachFile($U,$mod,$featured_img_uid,$editor);
else $html.=getAttachFile($U,$mod,$featured_img_uid,$editor);;
}
return $html;
}
// 첨부파일 리스트 추출 함수 (낱개)
function getAttachFile($R,$mod,$featured_img_uid,$editor)
{
global $g,$r;
$fileName=explode('.',$R['name']);
$file_name=$fileName[0]; // 파일명만 분리
if ($R['type']==2) {
$type='photo';
} elseif($R['type']==4) {
$type='audio';
} elseif($R['type']==5) {
$type='video';
} else {
$type='file';
}
if($type=='photo'){
$caption=$R['caption']?$R['caption']:$file_name;
$img_origin=$R['host'].'/'.$R['folder'].'/'.$R['tmpname'];
$thumb_list=getPreviewResize($R['src'],'s'); // 미리보기 사이즈 조정 (이미지 업로드시 썸네일을 만들 필요 없다.)
$thumb_modal=getPreviewResize($R['src'],'c'); // 정보수정 모달용 사이즈 조정 (이미지 업로드시 썸네일을 만들 필요 없다.)
$insert_text='!['.$caption.']('.$g['url_root'].$img_origin.')';
}else if($type=='file'){
$caption=$R['caption']?$R['caption']:$R['name'];
$src=$R['url'].$R['folder'].'/'.$R['name'];
$insert_text='['.$caption.']('.$g['url_root'].'/?r='.$r.'&m=mediaset&a=download&uid='.$R['uid'].')';
}
$html='';
$html.='
<li class="list-group-item d-flex justify-content-start dd-item" data-id="'.$R['uid'].'" style="background-color: transparent">';
if($R['type']==2){
$html.='
<div class="dd-handle fa fa-arrows" title="순서변경"></div>
<div class="media ml-3 mr-auto align-items-center text-truncate">
<a href="#" class="d-flex align-self-center mr-3 " data-attach-act="insert" data-type="'.$type.'" data-origin="'.($R['type']==2?$img_origin:$src).'" data-caption="'.$caption.'" data-editor="'.$editor.'"><img class="border" src="'.$thumb_list.'" alt="'.$caption.'" style="width: 50px"></a>
<div class="media-body">';
$html.='<span class="badge badge-warning'.($R['uid']==$featured_img_uid?'':' d-none').'" data-role="attachList-label-featured" data-id="'.$R['uid'].'">대표</span> ';
$html.='<span class="badge badge-secondary'.(!$R['hidden']?' d-none':'').'" data-role="attachList-label-hidden-'.$R['uid'].'">숨김</span>';
$html.='
<a href="#" data-role="attachList-list-name-'.$R['uid'].'" data-attach-act="insert" data-type="'.$type.'" data-origin="'.($R['type']==2?$img_origin:$src).'" data-caption="'.$caption.'" data-editor="'.$editor.'">'.$R['name'].'</a>
<small class="text-muted">'.getSizeFormat($R['size'],2).'</small>
</div>
</div>';
}else {
$html.='
<div class="dd-handle fa fa-arrows" title="순서변경"></div>
<div class="ml-3 mr-auto align-self-center">
<i class="fa fa-floppy-o fa-fw mr-1"></i>';
$html.='<span class="badge badge-secondary'.(!$R['hidden']?' d-none':'').'" data-role="attachList-label-hidden-'.$R['uid'].'">숨김</span>';
$html.='
<a href="#" class="list-group-item-text text-truncate" data-role="attachList-list-name-'.$R['uid'].'" data-attach-act="insert" data-type="'.$type.'" data-origin="'.($R['type']==2?$img_origin:$src).'" data-caption="'.$caption.'" data-editor="'.$editor.'">'.$R['name'].'</a>
<small class="text-muted">'.getSizeFormat($R['size'],2).'</small>
</div>';
}
if($mod=='upload') $html.='<input type="hidden" name="attachfiles[]" value="['.$R['uid'].']"/>';
$html.='<div class="align-self-center"><div class="btn-group btn-group-sm">';
$html.='
<button type="button" class="btn btn-light" data-attach-act="insert" data-type="'.$type.'" data-origin="'.($R['type']==2?$img_origin:$src).'" data-caption="'.$caption.'" data-id="'.$R['uid'].'" data-role="attachList-menu-insert-'.$R['uid'].'" data-editor="'.$editor.'">삽입</button>';
if($mod=='upload'){
$html.='
<button type="button" class="btn btn-light dropdown-toggle dropdown-toggle-split" data-toggle="dropdown">
</button>
<div class="dropdown-menu dropdown-menu-right">';
if($R['type']==2){
$html.='
<a class="dropdown-item" href="#" data-attach-act="featured-img" data-type="'.$type.'" data-id="'.$R['uid'].'">대표이미지 설정</a>
<a class="dropdown-item" href="#" data-toggle="modal" data-backdrop="false" data-target="#modal-attach-photo-tag" data-filename="'.$file_name.'" data-fileext="'.$R['ext'].'" data-caption="'.$caption.'" data-src="'.$img_origin.'" data-attach-act="edit" data-id="'.$R['uid'].'" data-type="'.$type.'" data-role="attachList-menu-edit-'.$R['uid'].'">상품태그</a>';
}
$html.='
<a class="dropdown-item" href="#" data-toggle="modal" data-backdrop="false" data-target="#modal-attach-'.($R['type']==2?'photo':'file').'-meta" data-filename="'.$file_name.'" data-fileext="'.$R['ext'].'" data-caption="'.$caption.'" data-src="'.$thumb_modal.'" data-origin="'.$img_origin.'" data-attach-act="edit" data-id="'.$R['uid'].'" data-type="'.$type.'" data-role="attachList-menu-edit-'.$R['uid'].'">정보수정</a>
<a class="dropdown-item" href="#" data-attach-act="showhide" data-role="attachList-menu-showhide-'.$R['uid'].'" data-id="'.$R['uid'].'" data-content="'.($R['hidden']?'show':'hide').'" >'.($R['hidden']?'보이기':'숨기기').'</a>
<a class="dropdown-item" href="#" data-attach-act="delete" data-id="'.$R['uid'].'" data-role="attachList-menu-delete-'.$R['uid'].'" data-featured="" data-type="'.$type.'">삭제</a>
</div>';
}
$html.='
</div></div>
</li>';
return $html;
}
// 오디오파일 리스트 추출 함수 (낱개)
function getAttachAudio($R,$mod,$featured_audio_uid)
{
global $g,$r;
$fileName=explode('.',$R['name']);
$file_name=$fileName[0]; // 파일명만 분리
$caption=$R['caption']?$R['caption']:$file_name;
$html='';
$html.='
<li class="list-group-item d-flex justify-content-between align-items-center dd-item animated fadeInDown" data-id="'.$R['uid'].'" style="background-color: transparent">
<div class="dd-handle fa fa-arrows" title="순서변경"></div>';
$html.='<div class="ml-3 mr-auto w-100"><span class="badge badge-secondary'.($R['uid']==$featured_audio_uid?'':' d-none').'" data-role="attachList-label-featured" data-id="'.$R['uid'].'">대표</span> ';
$html.='<span class="badge badge-secondary'.(!$R['hidden']?' d-none':'').'" data-role="attachList-label-hidden-'.$R['uid'].'">숨김</span>';
$html.='
<audio controls class="align-middle mr-4"><source src="'.$R['url'].$R['folder'].'/'.$R['tmpname'].'" type="audio/mpeg"></audio>';
$html.='<span data-role="attachList-list-name-'.$R['uid'].'" >'.$R['name'].'</span>';
$html.='
<span class="badge badge-secondary">'.getSizeFormat($R['size'],2).'</span></div>';
$html.='
<span class="align-self-center">
<div class="btn-group btn-group-sm">';
if($mod=='upload') $html.='<input type="hidden" name="attachfiles[]" value="['.$R['uid'].']"/>';
$html.='
<button type="button" class="btn btn-light" data-attach-act="delete" data-id="'.$R['uid'].'" data-role="attachList-menu-delete-'.$R['uid'].'" data-featured="" data-type="audio">삭제</button>';
if($mod=='upload'){
$html.='
<button type="button" class="btn btn-light dropdown-toggle dropdown-toggle-split" data-toggle="dropdown">
<span class="sr-only">Toggle Dropdown</span>
</button>
<div class="dropdown-menu dropdown-menu-right">';
$html.='
<a class="dropdown-item" href="#" data-attach-act="featured-audio" data-type="'.$type.'" data-id="'.$R['uid'].'">대표오디오 설정</a>';
$html.='
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#modal-attach-file-meta" data-filename="'.$file_name.'" data-fileext="'.$R['ext'].'" data-caption="'.$caption.'" data-src="'.$thumb_modal.'" data-origin="'.$img_origin.'" data-attach-act="edit" data-id="'.$R['uid'].'" data-type="audio" data-role="attachList-menu-edit-'.$R['uid'].'">정보수정</a>
<a class="dropdown-item" href="#" data-attach-act="showhide" data-role="attachList-menu-showhide-'.$R['uid'].'" data-id="'.$R['uid'].'" data-content="'.($R['hidden']?'show':'hide').'" >'.($R['hidden']?'보이기':'숨기기').'</a>
<a class="dropdown-item" href="#" data-attach-act="delete" data-id="'.$R['uid'].'" data-role="attachList-menu-delete-'.$R['uid'].'" data-featured="" data-type="audio">삭제</a>
</div>';
}
$html.='
</div>
</span>
</li>';
return $html;
}
// 비디오파일 리스트 추출 함수 (낱개)
function getAttachVideo($R,$mod,$featured_video_uid)
{
global $g,$r;
$fileName=explode('.',$R['name']);
$file_name=$fileName[0]; // 파일명만 분리
$caption=$R['caption']?$R['caption']:$file_name;
$html='';
$html.='
<li class="list-group-item d-flex justify-content-between align-items-center dd-item animated fadeInDown" data-id="'.$R['uid'].'" style="background-color: transparent">
<div class="dd-handle fa fa-arrows" title="순서변경"></div>
<div class="ml-3 mr-auto w-100">';
$html.='<span class="badge badge-secondary'.($R['uid']==$featured_video_uid?'':' d-none').'" data-role="attachList-label-featured" data-id="'.$R['uid'].'">대표</span> ';
$html.='<span class="badge badge-secondary'.(!$R['hidden']?' d-none':'').'" data-role="attachList-label-hidden-'.$R['uid'].'">숨김</span>';
$html.='
<video width="320" height="240" controls class="align-middle mr-3"><source src="'.$R['url'].$R['folder'].'/'.$R['tmpname'].'" type="video/'.$R['ext'].'"></video>';
$html.='<span data-role="attachList-list-name-'.$R['uid'].'" >'.$R['name'].'</span>';
$html.='
<span class="badge badge-secondary">'.getSizeFormat($R['size'],2).'</span></div>';
$html.='<div class="align-self-center">
<div class="btn-group btn-group-sm">';
if($mod=='upload') $html.='<input type="hidden" name="attachfiles[]" value="['.$R['uid'].']"/>';
$html.='
<button type="button" class="btn btn-light" data-attach-act="delete" data-id="'.$R['uid'].'" data-role="attachList-menu-delete-'.$R['uid'].'" data-featured="" data-type="video">삭제</button>';
if($mod=='upload'){
$html.='
<button type="button" class="btn btn-light btn-sm dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<div class="dropdown-menu dropdown-menu-right">';
$html.='
<a class="dropdown-item" href="#" data-attach-act="featured-video" data-type="'.$type.'" data-id="'.$R['uid'].'">대표 비디오 설정</a>';
$html.='
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#modal-attach-file-meta" data-filename="'.$file_name.'" data-fileext="'.$R['ext'].'" data-caption="'.$caption.'" data-src="'.$thumb_modal.'" data-origin="'.$img_origin.'" data-attach-act="edit" data-id="'.$R['uid'].'" data-type="video" data-role="attachList-menu-edit-'.$R['uid'].'">정보수정</a>
<a class="dropdown-item" href="#" data-attach-act="showhide" data-role="attachList-menu-showhide-'.$R['uid'].'" data-id="'.$R['uid'].'" data-content="'.($R['hidden']?'show':'hide').'" >'.($R['hidden']?'보이기':'숨기기').'</a>
<a class="dropdown-item" href="#" data-attach-act="delete" data-id="'.$R['uid'].'" data-role="attachList-menu-delete-'.$R['uid'].'" data-featured="" data-type="video ">삭제</a>
</div>';
}
$html.='
</div>
</div>
</li>';
return $html;
}
// 삽입 이미지 uid 얻기 함수
function getInsertImgUid($upload)
{
global $table;
$u_arr = getArrayString($upload);
$Insert_arr=array();
$i=0;
foreach ($u_arr['data'] as $val) {
$U=getUidData($table['s_upload'],$val);
if(!$U['fileonly']) $Insert_arr[$i]=$val;
$i++;
}
$upfiles='';
// 중괄로로 재조립
foreach ($Insert_arr as $uid) {
$upfiles.='['.$uid.']';
}
return $upfiles;
}
?>

View File

@@ -0,0 +1,232 @@
/**
* Copyright (c) 2015 redblock inc.
* Author kiere@kismq.com
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*
* Version: 1.0.0
*/
(function ($) {
$.fn.RbAttachTheme= function (settings) {
var defaults = {};
var opts = jQuery.extend(defaults, settings);
var module=opts.module; // 모듈명
var theme=opts.theme; // 테마 패스
var handler_photo=opts.handler_photo; // 사진첨부 실행 엘리먼트
var handler_file=opts.handler_file; // 파일첨부 실행 엘리먼트
var handler_getModalList=opts.handler_getModalList; // 첨부리스트 모달로 호출하는 엘리먼트
var listModal=opts.listModal;
var loaderbox='<div style="height:50%;margin-top:40%;" id="modal-loader-default"><div class="spinner-wrap"><div class="spinner"><div class="bounce1"></div><div class="bounce2"></div><div class="bounce3"></div></div></div></div>';
// 부모 모듈에서 파일첨부 액션 실행하는 버튼 or 기타 엘리먼트 클릭시 첨부파일 input click 이벤트 바인딩
$(handler_file).click(function(e){
e.preventDefault();
$('#'+inputId).click();
});
// 부모 모듈에서 사진첨부 액션 실행하는 버튼 or 기타 엘리먼트 클릭시 첨부파일 input click 이벤트 바인딩
$(handler_photo).click(function(e){
e.preventDefault();
$('#'+inputId).click();
});
// 부모 페이지 마크다운 에디터 toolbar 의 첨부파일 리스트 호출버튼 class 클릭시 첨부파일 리스트 모달 호출
$('body').on('click',handler_getModalList,function(){
if(handler_getModalList!='') $(listModal).modal('show');
});
// 업로드 리스트 showhide 값 reset 함수
var updateShowHide=function(uid,showhide){
if(showhide=='show'){
$('[data-role="attachList-menu-showhide-'+uid+'"]').attr('data-content','hide'); // data-content 값 수정
$('[data-role="attachList-menu-showhide-'+uid+'"]').text('숨기기'); // 메뉴명 변경
$('[data-role="attachList-label-hidden-'+uid+'"]').addClass('d-none'); // 숨김 라벨 숨기기
console.log($('[data-role="attachList-label-hidden-'+uid+'"]'));
}else{
$('[data-role="attachList-menu-showhide-'+uid+'"]').attr('data-content','show'); // data-content 값 수정
$('[data-role="attachList-menu-showhide-'+uid+'"]').text('보이기'); // 메뉴명 변경
$('[data-role="attachList-label-hidden-'+uid+'"]').removeClass('d-none'); // 숨김 라벨 노출
}
}
// 이벤트 바인딩 및 세팅
$('body').on('click','[data-attach-act]',function(e){
e.preventDefault();
var act=$(this).attr('data-attach-act');
var uid=$(this).attr('data-id');
var type=$(this).attr('data-type'); // file or photo
if(act=='edit'){
// data 값 세팅
var modal=$(this).data('target');
var filename=$(this).attr('data-filename'); // data-로 하면 변경된 값 적용 안됨
var fileext=$(this).data('fileext');
var caption=$(this).attr('data-caption'); // data- 로 하면 변경된 값 적용 안됨
var img_thumb=$(this).data('src');// 미리보기 이미지
var img_origin=$(this).data('origin');// 원본 이미지
// data 값 모달에 적용
$(modal).find('[data-role="filename"]').val(filename);
$(modal).find('[data-role="fileext"]').text(fileext);
$(modal).find('[data-role="filecaption"]').val(caption);
$(modal).find('[data-role="eventHandler"]').attr('data-id',uid); // save, cancel 엘리먼트 data-id="" 값에 uid 값 적용
$(modal).find('[data-role="eventHandler"]').attr('data-type',type); // save, cancel 엘리먼트 data-type="" 값에 type 값 적용
if(type=='photo'){
$(modal).find('[data-role="img-preview"]').attr('src',img_thumb); // 미리보기 이미지 src 적용
$(modal).find('[data-role="img-preview"]').attr('data-origin',img_origin); // 원본 이미지 src 적용
} else if(type=='video'){
$(modal).find('[data-role="img-preview"]').html('<i class="fa fa-file-video-o fa-4x"></i>'); // 타입별 아이콘 적용
} else if(type=='audio'){
$(modal).find('[data-role="img-preview"]').html('<i class="fa fa-file-audio-o fa-4x"></i>'); // 타입별 아이콘 적용
} else {
$(modal).find('[data-role="img-preview"]').html('<i class="fa fa-floppy-o fa-4x"></i>'); // 타입별 아이콘 적용
}
}
//액션 실행
if(act=='delete'){
// 삭제하는 리스트가 대표 이미지인 경우 write.php input 값에 적용
var is_featured=$(this).attr('data-featured');
if(is_featured=='1' && type=='photo'){
if(confirm('대표이미지를 삭제하시겠습니까? ')){
$('input[name="featured_img"]').val('');
}else{
return false;
}
}
$(this).closest('[data-id]').remove(); //항목 우선삭제
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=delete',{
uid : uid
},function(response){
var previewUl_default=$('[data-role="attach-preview-'+type+'"]'); // 파일 리스트 엘리먼트 class
var previewUl_modal=$('[data-role="modal-attach-preview-'+type+'"]'); // 파일 리스트 엘리먼트 class
var delEl_default=$(previewUl_default).find('[data-id="'+uid+'"]'); // 삭제 이벤트 진행된 엘리먼트
var delEl_modal=$(previewUl_modal).find('[data-id="'+uid+'"]'); // 삭제 이벤트 진행된 엘리먼트
delEl_default.remove();// 삭제 이벤트 진행시 해당 li 엘리먼트 remove
delEl_modal.remove();// 삭제 이벤트 진행시 해당 li 엘리먼트 remove
});
}else if(act=='showhide'){
var showhide=$(this).attr('data-content'); // data('content') 로 할 경우, ajax 로 변경된 값이 인식되지 않는다.
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=edit',{
act : act,
uid : uid,
showhide : showhide
},function(response){
var result=$.parseJSON(response);
if(!result.error){
updateShowHide(uid,showhide);
}
});
}else if(act=='save'){ // 정보수정 저장
var modal=$(this).data('target');
var filename=$(modal).find('[data-role="filename"]').val(); // 입력된 파일명
var filetype=$(modal).find('[data-role="eventHandler"]').attr('data-type'); // photo or file
var fileext=$(modal).find('[data-role="fileext"]').text(); // 입력된 파일 확장자명
var filecaption=$(modal).find('[data-role="filecaption"]').val(); // 입력된 캡션명
var filesrc=$(modal).find('[data-role="img-preview"]').attr('data-origin'); // 원본 이미지 소스
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=edit',{
act : act,
uid : uid,
filename : filename,
filetype : filetype,
fileext : fileext,
filecaption : filecaption,
filesrc : filesrc
},function(response){
var result=$.parseJSON(response);
if(!result.error){
var new_filename=result.filename;
var new_filecaption=result.filecaption;
var new_fileext=result.fileext;
var new_filetype=result.filetype;
var new_filesrc=result.filesrc;
// 리스트 값 수정
$('[data-role="attachList-menu-edit-'+uid+'"]').attr('data-filename',new_filename); // 파일명 수정
$('[data-role="attachList-menu-edit-'+uid+'"]').attr('data-caption',new_filecaption); // 'edit' 메뉴 캡션 업데이트
$('[data-role="attachList-menu-insert-'+uid+'"]').attr('data-caption',new_filecaption); // 'insert' 메뉴 캡션내용 수정
$('[data-role="attachList-list-name-'+uid+'"]').text(new_filename+'.'+new_fileext); // 리스트 name 수정
$('[data-role="attachList-list-name-'+uid+'"]').attr('data-caption',new_filecaption); // 리스트에도 캡션 업데이트
// 모달 닫기
$(modal).modal('hide');
$(modal).find('[data-role="filename"]').val(''); // 입력된 파일명 초기화
$(modal).find('[data-role="fileext"]').text(''); // 입력된 파일 확장자명 초기화
$(modal).find('[data-role="filecaption"]').val(''); // 입력된 캡션명 초기화
}
});
}else if(act=='featured-img'){ // 대표이미지 설정
// write.php 페이지 <input name="featured_img" value > 값에 적용
$('input[name="featured_img"]').val(uid);
// 대표 이미지 라벨 업데이트
$('[data-role="attachList-label-featured"]').each(function(){
$(this).addClass('d-none');
// 삭제 메뉴에 대표이미지 표시 지우기
$('[data-attach-act="delete"]').attr('data-featured','');
if($(this).data('id')==uid){
$(this).removeClass('d-none');
// 삭제 메뉴에 대표이미지 표시
$('[data-role="attachList-menu-delete-'+uid+'"]').attr('data-featured',1);
}
});
}else if(act=='insert'){
var agent = navigator.userAgent.toLowerCase();
var src=$(this).data('origin');
var type=$(this).attr('data-type');
var caption=$(this).attr('data-caption');
var dn_url = rooturl+'/'+raccount+'/download/'+uid;
if ((navigator.appName == 'Netscape' && navigator.userAgent.search('Trident') != -1) || (agent.indexOf("msie") != -1)) {
// 인터넷 익스플로러 브라우저 입니다.
var img_html = '<img src="'+src+'" alt="'+caption+'" class="img-fluid">';
var file_html = '<a href="'+dn_url+'">'+caption+'</a>';
if(type=='photo') {
InserHTMLtoEditor(type,img_html,src,caption)
} else {
InserHTMLtoEditor(type,file_html,dn_url,caption)
}
} else {
// 인터넷 익스플로러 브라우저가 아닙니다.
var img_html = '<figure class="image ck-widget" contenteditable="false">'+
'<img src="'+src+'">'+
'<figcaption class="ck-editor__editable ck-editor__nested-editable ck-placeholder ck-hidden" data-placeholder="이미지 설명을 입력하세요" contenteditable="true">'+caption+'</figcaption>'+
'</figure>';
var file_html = '<p><a href="'+dn_url+'">'+caption+'</a></p>';
if(type=='photo') {
InserHTMLtoEditor(editor,img_html)
} else {
InserHTMLtoEditor(editor,file_html)
}
}
var showhide= 'hide'; // 숨김처리
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=edit',{
act : act,
uid : uid,
showhide : showhide
},function(response){
var result=$.parseJSON(response);
if(!result.error){
updateShowHide(uid,showhide);
}
});
}
});
};
})(jQuery);

View File

@@ -0,0 +1,105 @@
<?php
include $g['dir_attach_theme'].'/header.php';
?>
<div id="attach-files" class="files position-relative"><!-- 파일폼 출력 --></div>
<div class="rb-attach mb-3 dd" id="nestable-photo">
<ol class="list-group rb-attach-photo rb-attach-featured mb-2 bg-faded dd-list" data-role="attach-preview-photo"><!-- 포토/이미지 리스트 -->
<?php if($parent_data['uid']):?>
<?php echo getAttachFileList($parent_data,'upload','photo',$editor_type)?>
<?php endif?>
</ol>
</div>
<div class="rb-attach mb-3 dd" id="nestable-file">
<ol class="list-group rb-attach-file bg-faded dd-list" data-role="attach-preview-file"> <!-- 일반파일 리스트 -->
<?php if($parent_data['uid']):?>
<?php echo getAttachFileList($parent_data,'upload','file',$editor_type)?>
<?php echo getAttachFileList($parent_data,'upload','doc',$editor_type)?>
<?php echo getAttachFileList($parent_data,'upload','zip',$editor_type)?>
<?php endif?>
</ol>
</div>
<div class="rb-attach mb-3 dd" id="nestable-video">
<ol class="list-group rb-attach-file bg-faded dd-list" data-role="attach-preview-video"> <!-- 비디오 파일 리스트 -->
<?php if($parent_data['uid']):?>
<?php echo getAttachFileList($parent_data,'upload','video',$editor_type)?>
<?php endif?>
</ol>
</div>
<div class="rb-attach mb-3 dd" id="nestable-audio">
<ol class="list-group rb-attach-file bg-faded dd-list" data-role="attach-preview-audio"> <!-- 오디오 파일 리스트 -->
<?php if($parent_data['uid']):?>
<?php echo getAttachFileList($parent_data,'upload','audio',$editor_type)?>
<?php endif?>
</ol>
</div>
<?php
include $g['dir_attach_theme'].'/footer.php';
?>
<script>
var link_settings={
module : 'mediaset',
theme : '<?php echo $g['dir_attach_theme']?>',
};
$('.rb-preview').on('click', function() {
$(this).removeClass('btn-primary').addClass('btn-light')
});
$(document).ready(function(){
// 첨부사진 순서변경
$('#nestable-photo').nestable({
group: 1,
maxDepth: 1
});
// 첨부파일 순서변경
$('#nestable-file').nestable({
group: 2,
maxDepth: 1
});
// 첨부 비디오 순서변경
$('#nestable-video').nestable({
group: 3,
maxDepth: 1
});
// 첨부 오디오 순서변경
$('#nestable-audio').nestable({
group: 4,
maxDepth: 1
});
// 첨부사진 순서변경
$('#nestable-link').nestable({
group: 5,
maxDepth: 1
});
// 순서변경 내역 저장
$('[data-role="attach"] .dd').on('change', function() {
var attachfiles=$('input[name="attachfiles[]"]').map(function(){return $(this).val()}).get();
var new_upfiles='';
if(attachfiles){
for(var i=0;i<attachfiles.length;i++) {
new_upfiles+=attachfiles[i];
}
}
$.post(rooturl+'/?r='+raccount+'&m=mediaset&a=modifygid',{
attachfiles : new_upfiles
});
});
});
</script>

View File

@@ -0,0 +1,151 @@
<!-- 첨부 사진 메타정보 수정 -->
<div class="modal rb-modal-attach-meta" id="modal-attach-photo-meta" tabindex="-1" role="dialog" aria-labelledby="">
<div class="modal-dialog modal-xl modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="">사진 정보수정</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body p-0">
<div class="container-fluid pl-0">
<div class="row">
<div class="col-8">
<img class="img-fluid" src="" alt="" data-role="img-preview" data-origin="">
</div><!-- /.col -->
<div class="col-4 pl-0 pt-3">
<div class="form-group">
<label for="file-caption" class="control-label">캡션:</label>
<textarea class="form-control" data-role="filecaption" rows="2"></textarea>
</div>
<div class="form-group">
<label for="file-name" class="control-label">파일명:</label>
<div class="input-group">
<input type="text" class="form-control" data-role="filename" name="filename">
<div class="input-group-append">
<span class="input-group-text" data-role="fileext">확장자</span>
</div>
</div>
</div>
<button type="button" class="btn btn-outline-secondary btn-block" data-attach-act="save" data-target="#modal-attach-photo-meta" data-role="eventHandler" data-id="">저장하기</button>
</div><!-- /.col -->
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 첨부 파일 메타정보 수정 -->
<div class="modal fade rb-modal-attach-meta" id="modal-attach-file-meta" tabindex="-1" role="dialog" aria-labelledby="">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id=""><i class="fa fa-floppy-o"></i> 첨부파일 정보수정</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-4">
<h1 class="text-xs-center" data-role="img-preview">
</h1>
</div>
<div class="col-md-8">
<div class="form-group">
<label for="file-name" class="control-label">파일명:</label>
<div class="input-group">
<input type="text" class="form-control" name="filename" data-role="filename">
<div class="input-group-append">
<span class="input-group-text" data-role="fileext">확장자</span>
</div>
</div>
</div>
<div class="form-group">
<label for="file-caption" class="control-label">캡션:</label>
<textarea class="form-control" data-role="filecaption" name="caption"></textarea>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal" data-attach-act="cancel" data-target="#modal-attach-file-meta" data-role="eventHandler" data-id="">취소하기</button>
<button type="button" class="btn btn-primary" data-attach-act="save" data-target="#modal-attach-file-meta" data-role="eventHandler" data-id="" data-type="">저장하기</button>
</div>
</div>
</div>
</div>
<!-- 첨부 사진 상품태그 -->
<div class="modal rb-modal-attach-meta" id="modal-attach-photo-tag" tabindex="-1" role="dialog" aria-labelledby="">
<!-- <input type="hidden" name="uid"> -->
<div class="modal-dialog modal-xl modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="">상품 태그</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body p-0">
<div class="container-fluid pl-0">
<div class="row">
<div class="col-8 text-center">
<div data-role="image-marker-area" class="d-inline-block">
<img class="img-fluid" src="" alt="" data-role="img-preview" data-origin="">
</div>
</div><!-- /.col -->
<div class="col-4 pl-0 pt-3">
<div data-role="comment" class="mb-3">
<div class="dropdown">
<button class="btn btn-white btn-sm btn-block p-2 d-flex justify-content-between align-items-center text-left" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" style="min-width: 8.3rem">
<div class="media d-none">
<img src="" class="mr-3" alt="">
<div class="media-body">
<h6 class="mt-1" data-role="name">[한만두] 달콤한 갈비만두</h6>
<span data-role="price"></span>
</div>
</div>
<div data-role="none">
연결할 상품을 선택하세요.
</div>
<i class="fa fa-caret-down mr-2" aria-hidden="true"></i>
</button>
<div class="dropdown-menu shadow py-0" data-role="attach-goods" style="min-width: 370px">
</div>
</div>
<input type="text" class="form-control mt-2" name="goods" value="">
<textarea class="form-control mt-3"></textarea>
<div class="d-flex justify-content-between mt-2">
<div class="">
<button type="button" id="imagetag-cancel" class="btn btn-white">취소</button>
<button type="button" id="imagetag-delete" class="btn btn-white">삭제</button>
</div>
<div class="">
<button type="button" data-attach-act="saveTag" data-target="#modal-attach-photo-tag" data-role="eventHandler" data-id="" class="btn btn-primary">
저장
</button>
</div>
</div>
</div>
<div data-role="test" class="f12"></div>
</div><!-- /.col -->
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1 @@
부트스트랩 심플 기본형

View File

@@ -0,0 +1,14 @@
# 부트스트랩4 파일 업로드 테마
부트스트랩
## 주요기능
- 사진,파일 업로드
- 첨부물 메타정보 등록
- 첨부목록 숨김처리
- 대표이미지 지정
## 요구사항
- `widgets/_default/attach` 위젯 필요
- `/plugins/jquery-form/4.2.2/jquery.form.min.js` 플러그인 필요

View File

@@ -0,0 +1,5 @@
<?php
$d['theme']['hidden_photo'] = "0"; // 이미지 추가시 사진 숨김여부 기본값 (숨김=1/보임=0)
$d['theme']['allowedTypes'] = ""; // 업로드 가능한 파일 확장자. (명시하지 않으면 파일 확장자 필터링하지 않음.)
$d['theme']['multiple'] = "1"; // 멀티 업로드 (허용=1/비허용=0)
?>

View File

@@ -0,0 +1,153 @@
<?php
// 모달 페이지 인클루드
include $g['dir_attach_theme'].'/modals.php';
getImport('moment','moment','2.22.2','js');
getImport('moment-duration-format','moment-duration-format','2.2.2','js');
?>
<script>
$(document).ready(function() {
$('[data-act="linkInsert"]').tooltip({
trigger: 'hover',
title : '본문삽입'
});
var check_url = $('#check_url');
check_url.find(".btn").click(function(){
var container = '#attach_link'
var fieldset = check_url
var textarea = check_url.find('textarea')
var url = textarea.val()
if (!url) {
textarea.focus()
return false
}
var link_url_parse = $('<a>', {href: url});
//네이버 블로그 URL의 실제 URL 변환
if ((link_url_parse.prop('hostname')=='blog.naver.com' || link_url_parse.prop('hostname')=='m.blog.naver.com' ) && link_url_parse.prop('pathname')) {
var nblog_path_arr = link_url_parse.prop('pathname').split("/");
var nblog_id = nblog_path_arr[1];
var nblog_pid = nblog_path_arr[2];
if (nblog_pid) {
var url = 'https://blog.naver.com/PostView.nhn?blogId='+nblog_id+'&logNo='+nblog_pid;
} else {
var url = 'https://blog.naver.com/PostList.nhn?blogId='+nblog_id;
}
}
fieldset.attr('disabled',true)
$.get('//embed.kimsq.com/oembed',{
url: url
}).done(function(response) {
var type = response.type;
var title = response.title;
var description = response.description;
var thumbnail_url = response.thumbnail_url;
var author = response.author;
var provider = response.provider_name;
var url = response.url;
var width = response.thumbnail_width;
var height = response.thumbnail_height;
var embed = response.html;
check_url.find('[data-role="title"]').text(title);
check_url.find('[data-role="description"]').text(description);
check_url.find('[data-role="thumbnail"]').attr('src',thumbnail_url);
check_url.find('[data-act="insert"]').attr('data-url',url).attr('data-title',title).attr('data-description',description).attr('data-thumbnail',thumbnail_url).attr('data-provider',provider);
// 포스트 글쓰기 페이지 저장버튼 출력
$('[data-role="postsubmit"]').removeClass('d-none');
$('[data-role="library"]').addClass('d-none');
if (type=='video') {
$.get('//embed.kimsq.com/iframely',{
url: url
}).done(function(response) {
var duration = response.meta.duration;
var _duration = moment.duration(duration, 's');
var formatted_duration = _duration.format("h:*m:ss");
$.post(rooturl+'/?r='+raccount+'&m=mediaset&a=saveLink',{
type : 9,
title : title,
theme : '_desktop/bs4-default-link',
description : description,
thumbnail_url : thumbnail_url,
author: author,
provider : provider,
url : url,
duration : duration?duration:'',
time : duration?formatted_duration:'',
width : width,
height : height,
embed : embed
},function(response){
var result=$.parseJSON(response);
if(!result.error){
$(container).find('[data-role="attach-preview-link"]').prepend(result.list);
$.notify("추가 되었습니다.");
$('[data-role="postsubmit"]').click(); // 포스트 저장
}
});
});
} else {
$.post(rooturl+'/?r='+raccount+'&m=mediaset&a=saveLink',{
type : 8,
title : title,
theme : '_desktop/bs4-default-link',
description : description,
thumbnail_url : thumbnail_url,
author: author,
provider : provider,
url : url,
width : width,
height : height,
embed : embed
},function(response){
var result=$.parseJSON(response);
if(!result.error){
$(container).find('[data-role="attach-preview-link"]').prepend(result.list);
$.notify("추가 되었습니다.");
}
});
}
}).fail(function() {
alert( "URL을 확인해주세요." );
}).always(function() {
textarea.val('')
fieldset.attr('disabled',false)
});
});
$(document).on('click','[data-act="linkInsert"]',function(){
var url = $(this).attr('data-url')
$(this).attr('data-original-title', '본문삽입 되었습니다.')
$(this).tooltip('show');
$(this).attr('data-original-title', '본문삽입')
var html = '<figure class="media"><oembed url="'+url+'"></oembed></figure>'
InserHTMLtoEditor(editor,html)
} );
})
</script>

View File

@@ -0,0 +1,95 @@
<?php
// 위젯 설정값 세팅
$parent_module=$d['attach']['parent_module']; // 첨부파일 사용하는 모듈
$parent_data=$d['attach']['parent_data']; // 해당 포스트 데이타 (수정시 필요)
$attach_module_theme=$d['attach']['theme']; // 첨부파일 테마
$attach_mode=$d['attach']['mod']; // list, main...
$attach_handler_file=$d['attach']['handler_file']; //파일첨부 실행 엘리먼트 button or 기타 엘리먼트 data-role="" 형태로 하는 것을 권고
$attach_handler_photo=$d['attach']['handler_photo']; // 사진첨부 실행 엘리먼트 button or 기타 엘리먼트 data-role="" 형태로 하는 것을 권고
$attach_handler_getModalList=$d['attach']['handler_getModalList']; // 첨부파일 리스트 호출 handler
$attach_object_type=$d['attach']['object_type']; // 첨부 대상에 따른 분류 : photo, file, link, video....
$editor_type=$d['attach']['editor_type']; // 에디터 타입 : html,markdown
require_once $g['dir_attach_theme'].'/main.func.php'; // 함수 인클루드
require_once $g['dir_attach_theme'].'/_var.php'; // 테마변수 인클루드
require_once $g['path_module'].'mediaset/var/var.php'; //모듈 공통변수 인클루드
?>
<script src="<?php echo $g['url_attach_theme']?>/js/fileuploader.js"></script>
<script src="<?php echo $g['url_attach_theme']?>/main.js"></script>
<!-- nestable : https://github.com/dbushell/Nestable -->
<?php getImport('nestable','jquery.nestable',false,'js') ?>
<style media="screen">
/**
* Nestable
*/
.dd { }
.dd-list { display: block; position: relative; list-style: none; }
.dd-list .dd-list { }
.dd-collapsed .dd-list { display: none; }
.dd-item,
.dd-empty,
.dd-placeholder { }
.dd-handle {
position: absolute;
margin: 0;
left: 0;
top: 0;
bottom:0;
cursor: pointer;
width: 25px;
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
background-color: #eff3f6;
background-image: linear-gradient(-180deg, #fafbfc 0%, #eff3f6 90%);
background-repeat: repeat-x;
background-position: -1px -1px;
background-size: 110% 110%;
border-right: 1px solid rgba(27,31,35,0.1);
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.dd-handle:hover {
background-color: #e6ebf1;
background-image: linear-gradient(-180deg, #f0f3f6 0%, #e6ebf1 90%);
background-position: -.5em;
}
.dd-handle:before {
display: block;
position: absolute;
left: 0;
top: 50%;
margin-top: -7px;
width: 100%;
text-align: center;
text-indent: 0;
color: #494949;
font-size: 14px;
font-weight: normal;
}
.dd-placeholder,
.dd-empty { margin: 5px 0; padding: 0; min-height: 30px; background: #f2fbff; border: 1px dashed #b6bcbf; box-sizing: border-box; -moz-box-sizing: border-box; }
.dd-empty { border: 1px dashed #bbb; min-height: 100px; background-color: #e5e5e5;
background-image: -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
-webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
background-image: -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
-moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
background-size: 60px 60px;
background-position: 0 0, 30px 30px;
}
.dd-dragel { position: absolute; pointer-events: none; z-index: 9999; }
.dd-dragel > .dd-item .dd-handle { margin-top: 0; }
.dd-dragel .dd-handle {
-webkit-box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1);
box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1);
}
</style>

View File

@@ -0,0 +1,89 @@
<?php
function getAttachPlatformList($parent_data,$mod,$type) {
global $table;
$upload=$parent_data['upload'];
$featured_img_uid=$parent_data['featured_img'];// 대표이미지 uid
$sql='fserver=3';
$attach = getArrayString($upload);
$uid_q='(';
foreach($attach['data'] as $uid)
{
$uid_q.='uid='.$uid.' or ';
}
$uid_q=substr($uid_q,0,-4).')';
$sql=$sql.' and '.$uid_q;
$RCD=getDbArray($table['s_upload'],$sql,'*','gid','asc','',1);
$html='';
while($R=db_fetch_array($RCD)){
$U=getUidData($table['s_upload'],$R['uid']);
$html.=getAttachPlatform($U,$mod,$featured_img_uid);
}
return $html;
}
// 추출 함수 (낱개)
function getAttachPlatform($R,$mod,$featured_img_uid) {
global $g,$r;
$md_title=str_replace('|','-',$R['title']);
$thumbnail_url_parse = parse_url($R['src']);
$thumbnail_url_arr = explode('//',$R['src']);
if ($R['provider']=='Google Maps') {
$thumbnail = $R['src'];
} else if (strpos($R['src'], '?') !== false) {
$thumbnail = '/_core/opensrc/timthumb/thumb.php?src='.$R['src'].'&w=50&h=50&s=1';
} else {
$thumbnail = '/thumb'.($thumbnail_url_parse['scheme']=='https'?'-ssl':'').'/50x50/u/'.$thumbnail_url_arr[1];
}
$insert_text='<video class=mejs-player img-responsive img-fluid style=max-width:100% preload=none><source src=https://www.youtube.com/embed/'.$R['src'].' type=video/youtube></video>';
$html='';
$html.='
<li class="list-group-item d-flex dd-item" data-id="'.$R['uid'].'" style="background-color: transparent">';
$html.='
<div class="dd-handle fa fa-arrows" title="순서변경"></div>
<div class="media ml-3 mr-auto align-items-center">
<a href="'.$R['linkurl'].'" target="_blank" class="d-flex align-self-center mr-3 position-relative"><img class="border" src="'.$thumbnail.'" alt="" style="width:50px;height:50px"><span class="position-absolute'.($R['duration']?'':' d-none').'" style="bottom:5px;right:5px;"><i class="fa fa-play-circle text-white" style="font-size:20px;text-shadow: 2px 2px 2px gray;" aria-hidden="true"></i></span></a>
<div class="media-body">';
$html.='<span class="badge badge-pill badge-warning '.($R['uid']==$featured_img_uid?'':'d-none').'" data-role="attachList-label-featured" data-id="'.$R['uid'].'">대표</span> ';
$html.='<span class="badge badge-pill badge-secondary '.(!$R['hidden']?'d-none':'').'" data-role="attachList-label-hidden-'.$R['uid'].'">숨김</span>';
$html.='
<a href="'.$R['linkurl'].'" target="_blank" class="title d-inline" data-role="attachList-list-name-'.$R['uid'].'" >'.($R['caption']?getStrCut($R['caption'],45,'..'):getStrCut($R['description'],45,'..')).'</a>
<div class="meta"><span class="badge badge-pill badge-light">'.$R['provider'].'</span> <span class="badge badge-pill badge-light" data-role="attachList-list-time-'.$R['uid'].'">'.$R['time'].'</span></div>';
$html.='
<span class="d-block mt-2">
<div class="btn-group btn-group-sm">';
$html.='<input type="hidden" name="attachfiles[]" value="['.$R['uid'].']"/>';
$html.='
<button type="button" class="btn btn-light" data-act="linkInsert" data-provider="'.$R['provider'].'" data-url="'.$R['linkurl'].'" data-title="'.$R['caption'].'" data-id="'.$R['uid'].'" data-role="attachList-menu-edit-'.$R['uid'].'" role="button">삽입</button>
<button type="button" class="btn btn-light" data-link-act="delete" data-id="'.$R['uid'].'" data-role="attachList-menu-delete-'.$R['uid'].'" data-featured="" data-type="'.($R['type']==8?'youtube':'file').'" role="button">삭제</button>';
$html.='
<div class="btn-group"><button type="button" class="btn btn-light dropdown-toggle" data-toggle="dropdown" role="button"></button>
<div class="dropdown-menu dropdown-menu-right" role="menu">
<button type="button" class="dropdown-item" data-link-act="featured-img" data-type="'.$type.'" data-id="'.$R['uid'].'">대표이미지 설정</button>
<button type="button" class="dropdown-item" data-link-act="showhide" data-role="attachList-menu-showhide-'.$R['uid'].'" data-id="'.$R['uid'].'" data-content="'.($R['hidden']?'show':'hide').'" >'.($R['hidden']?'보이기':'숨기기').'</button>
</div>
</div>
</div>
</span>';
$html.='
</div>
</div>';
$html.='
</li>';
return $html;
}
?>

View File

@@ -0,0 +1,158 @@
// 업로드 리스트 showhide 값 reset 함수
var updateShowHide=function(uid,showhide){
if(showhide=='show'){
$('[data-role="attachList-menu-showhide-'+uid+'"]').attr('data-content','hide'); // data-content 값 수정
$('[data-role="attachList-menu-showhide-'+uid+'"]').text('숨기기'); // 메뉴명 변경
$('[data-role="attachList-label-hidden-'+uid+'"]').addClass('d-none'); // 숨김 라벨 숨기기
console.log($('[data-role="attachList-label-hidden-'+uid+'"]'));
}else{
$('[data-role="attachList-menu-showhide-'+uid+'"]').attr('data-content','show'); // data-content 값 수정
$('[data-role="attachList-menu-showhide-'+uid+'"]').text('보이기'); // 메뉴명 변경
$('[data-role="attachList-label-hidden-'+uid+'"]').removeClass('d-none'); // 숨김 라벨 노출
}
}
$(document).on('click','[data-link-act]',function(e){
var act=$(this).attr('data-link-act');
var uid=$(this).attr('data-id');
var type=$(this).attr('data-type'); // file or photo
var module = 'mediaset';
showSaveButton(true) //포스트 저장버튼 활성화
if(act=='edit'){
// data 값 세팅
var modal=$(this).data('target');
var filename=$(this).attr('data-filename'); // data-로 하면 변경된 값 적용 안됨
var fileext=$(this).data('fileext');
var caption=$(this).attr('data-caption'); // data- 로 하면 변경된 값 적용 안됨
var img_thumb=$(this).data('src');// 미리보기 이미지
var img_origin=$(this).data('origin');// 원본 이미지
// data 값 모달에 적용
$(modal).find('[data-role="filename"]').val(filename);
$(modal).find('[data-role="fileext"]').text(fileext);
$(modal).find('[data-role="filecaption"]').val(caption);
$(modal).find('[data-role="eventHandler"]').attr('data-id',uid); // save, cancel 엘리먼트 data-id="" 값에 uid 값 적용
$(modal).find('[data-role="eventHandler"]').attr('data-type',type); // save, cancel 엘리먼트 data-type="" 값에 type 값 적용
if(type=='photo'){
$(modal).find('[data-role="img-preview"]').attr('src',img_thumb); // 미리보기 이미지 src 적용
$(modal).find('[data-role="img-preview"]').attr('data-origin',img_origin); // 원본 이미지 src 적용
} else if(type=='video'){
$(modal).find('[data-role="img-preview"]').html('<i class="fa fa-file-video-o fa-4x"></i>'); // 타입별 아이콘 적용
} else if(type=='audio'){
$(modal).find('[data-role="img-preview"]').html('<i class="fa fa-file-audio-o fa-4x"></i>'); // 타입별 아이콘 적용
} else {
$(modal).find('[data-role="img-preview"]').html('<i class="fa fa-floppy-o fa-4x"></i>'); // 타입별 아이콘 적용
}
}
//액션 실행
if(act=='delete'){
// 삭제하는 리스트가 대표 이미지인 경우 write.php input 값에 적용
var is_featured=$(this).attr('data-featured');
if(is_featured=='1' && type=='photo'){
if(confirm('대표이미지를 삭제하시겠습니까? ')){
$('input[name="featured_img"]').val('');
}else{
return false;
}
}
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=delete',{
uid : uid
},function(response){
var previewUl_default=$('[data-role="attach-preview-link"]'); // 파일 리스트 엘리먼트 class
var previewUl_modal=$('[data-role="modal-attach-preview-link"]'); // 파일 리스트 엘리먼트 class
var delEl_default=$(previewUl_default).find('[data-id="'+uid+'"]'); // 삭제 이벤트 진행된 엘리먼트
var delEl_modal=$(previewUl_modal).find('[data-id="'+uid+'"]'); // 삭제 이벤트 진행된 엘리먼트
delEl_default.remove();// 삭제 이벤트 진행시 해당 li 엘리먼트 remove
delEl_modal.remove();// 삭제 이벤트 진행시 해당 li 엘리먼트 remove
});
}else if(act=='showhide'){
var showhide=$(this).attr('data-content'); // data('content') 로 할 경우, ajax 로 변경된 값이 인식되지 않는다.
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=edit',{
act : act,
uid : uid,
showhide : showhide
},function(response){
var result=$.parseJSON(response);
if(!result.error){
updateShowHide(uid,showhide);
}
});
}else if(act=='save'){ // 정보수정 저장
var modal=$(this).data('target');
var filename=$(modal).find('[data-role="filename"]').val(); // 입력된 파일명
var filetype=$(modal).find('[data-role="eventHandler"]').attr('data-type'); // photo or file
var fileext=$(modal).find('[data-role="fileext"]').text(); // 입력된 파일 확장자명
var filecaption=$(modal).find('[data-role="filecaption"]').val(); // 입력된 캡션명
var filesrc=$(modal).find('[data-role="img-preview"]').attr('data-origin'); // 원본 이미지 소스
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=edit',{
act : act,
uid : uid,
filename : filename,
filetype : filetype,
fileext : fileext,
filecaption : filecaption,
filesrc : filesrc
},function(response){
var result=$.parseJSON(response);
if(!result.error){
var new_filename=result.filename;
var new_filecaption=result.filecaption;
var new_fileext=result.fileext;
var new_filetype=result.filetype;
var new_filesrc=result.filesrc;
// 리스트 값 수정
$('[data-role="attachList-menu-edit-'+uid+'"]').attr('data-filename',new_filename); // 파일명 수정
$('[data-role="attachList-menu-edit-'+uid+'"]').attr('data-caption',new_filecaption); // 'edit' 메뉴 캡션 업데이트
$('[data-role="attachList-menu-insert-'+uid+'"]').attr('data-caption',new_filecaption); // 'insert' 메뉴 캡션내용 수정
$('[data-role="attachList-list-name-'+uid+'"]').text(new_filename+'.'+new_fileext); // 리스트 name 수정
$('[data-role="attachList-list-name-'+uid+'"]').attr('data-caption',new_filecaption); // 리스트에도 캡션 업데이트
// 모달 닫기
$(modal).modal('hide');
$(modal).find('[data-role="filename"]').val(''); // 입력된 파일명 초기화
$(modal).find('[data-role="fileext"]').text(''); // 입력된 파일 확장자명 초기화
$(modal).find('[data-role="filecaption"]').val(''); // 입력된 캡션명 초기화
}
});
}else if(act=='featured-img'){ // 대표이미지 설정
// write.php 페이지 <input name="featured_img" value > 값에 적용
$('input[name="featured_img"]').val(uid);
// 대표 이미지 라벨 업데이트
$('[data-role="attachList-label-featured"]').each(function(){
$(this).addClass('d-none');
// 삭제 메뉴에 대표이미지 표시 지우기
$('[data-link-act="delete"]').attr('data-featured','');
if($(this).data('id')==uid){
$(this).removeClass('d-none');
// 삭제 메뉴에 대표이미지 표시
$('[data-role="attachList-menu-delete-'+uid+'"]').attr('data-featured',1);
}
});
}else if(act=='insert'){
var url=$(this).attr('data-url');
console.log(url)
InserHTMLtoEditor(editor,url)
var showhide= 'hide'; // 숨김처리
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=edit',{
act : act,
uid : uid,
showhide : showhide
},function(response){
var result=$.parseJSON(response);
if(!result.error){
updateShowHide(uid,showhide);
}
});
}
});

View File

@@ -0,0 +1,34 @@
<?php
include $g['dir_attach_theme'].'/header.php';
?>
<div id="attach_link">
<fieldset id="check_url" class="mb-3">
<div class="input-group" style="border: 2px dashed #d1d1d1;">
<textarea class="form-control bg-white border-0" rows="3" placeholder="URL을 입력해주세요."></textarea>
<div class="input-group-append">
<button class="btn btn-light border-right-0 border-top-0 border-bottom-0" type="button">
가져오기
</button>
</div>
</div>
<small class="form-text text-muted"></small>
</fieldset>
<div class="rb-attach mb-3 dd" id="nestable-link">
<ol class="list-group rb-attach-link rb-attach-featured bg-faded dd-list" data-role="attach-preview-link"> <!-- 일반파일 리스트 -->
<?php if($parent_data['uid']):?>
<?php echo getAttachPlatformList($parent_data,'upload','file')?>
<?php endif?>
</ol>
</div>
</div>
<?php
include $g['dir_attach_theme'].'/footer.php';
?>

View File

@@ -0,0 +1,149 @@
<!-- 첨부 사진 메타정보 수정 -->
<div class="modal fade rb-modal-attach-meta" id="modal-attach-photo-meta" tabindex="-1" role="dialog" aria-labelledby="">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id=""><i class="fa fa-camera-retro"></i> 사진 정보수정</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
<div class="row">
<!-- data-role="img-preview" src="_s 이미지" data-origin="원본 이미지" 넣는다. -->
<div class="col-md-4">
<p><img class="img-thumbnail" src="" alt="" data-role="img-preview" data-origin=""></p>
</div>
<div class="col-md-8">
<div class="form-group">
<label for="file-caption" class="control-label">캡션:</label>
<textarea class="form-control" data-role="filecaption" rows="5"></textarea>
</div>
<div class="form-group">
<label for="file-name" class="control-label">파일명:</label>
<div class="input-group">
<input type="text" class="form-control" data-role="filename" name="filename">
<div class="input-group-append">
<span class="input-group-text" data-role="fileext">확장자</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal" data-attach-act="cancel" data-target="#modal-attach-photo-meta" data-role="eventHandler" data-id="">취소하기</button>
<button type="button" class="btn btn-primary" data-attach-act="save" data-target="#modal-attach-photo-meta" data-role="eventHandler" data-id="">저장하기</button>
</div>
</div>
</div>
</div>
<!-- 첨부 파일 메타정보 수정 -->
<div class="modal fade rb-modal-attach-meta" id="modal-attach-file-meta" tabindex="-1" role="dialog" aria-labelledby="">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id=""><i class="fa fa-floppy-o"></i> 첨부파일 정보수정</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-4">
<h1 class="text-xs-center" data-role="img-preview">
</h1>
</div>
<div class="col-md-8">
<div class="form-group">
<label for="file-name" class="control-label">파일명:</label>
<div class="input-group">
<input type="text" class="form-control" name="filename" data-role="filename">
<div class="input-group-append">
<span class="input-group-text" data-role="fileext">확장자</span>
</div>
</div>
</div>
<div class="form-group">
<label for="file-caption" class="control-label">캡션:</label>
<textarea class="form-control" data-role="filecaption" name="caption"></textarea>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal" data-attach-act="cancel" data-target="#modal-attach-file-meta" data-role="eventHandler" data-id="">취소하기</button>
<button type="button" class="btn btn-primary" data-attach-act="save" data-target="#modal-attach-file-meta" data-role="eventHandler" data-id="" data-type="">저장하기</button>
</div>
</div>
</div>
</div>
<!-- 링크 추가 -->
<div class="modal fade" tabindex="-1" role="dialog" id="modal-attach-link">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">링크 추가</h4>
</div>
<div class="modal-body">
<p id="attach-link">
<!--링크 입력 필드 동적 생성 -->
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal">닫기</button>
<button type="button" class="btn btn-primary" data-plugin="clipboard" data-clipboard-text="" data-role="btn-copy-linkContent">링크내용 복사하기</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
<!-- 위치 추가 -->
<div class="modal fade" tabindex="-1" role="dialog" id="modal-attach-map">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">위치 추가</h4>
</div>
<div class="modal-body">
<p>지도 검색 UI </p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal">닫기</button>
<button type="button" class="btn btn-primary">적용하기</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
<!-- 비디오 추가 -->
<div class="modal fade" tabindex="-1" role="dialog" id="modal-attach-video">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">비디오 추가</h4>
</div>
<div class="modal-body">
<p>유튜브와 비메오 비디오만 링크를 추가하는 형태</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal">닫기</button>
<button type="button" class="btn btn-primary">적용하기</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->

View File

@@ -0,0 +1 @@
부트스트랩 심플 기본형

View File

@@ -0,0 +1,14 @@
# 부트스트랩4 파일 업로드 테마
부트스트랩
## 주요기능
- 이미지 전용 업로드
- 이미지 메타정보 등록
- 이미지 순서변경
- 이미지 숨김처리
- 대표 이미지 지정
## 요구사항
- `/plugins/jquery-form/4.2.2/jquery.form.min.js` 플러그인 필요

View File

@@ -0,0 +1,5 @@
<?php
$d['theme']['hidden_photo'] = "0"; // 이미지 추가시 사진 숨김여부 기본값 (숨김=1/보임=0)
$d['theme']['allowedTypes'] = "jpg,jpeg,png,gif"; // 업로드 가능한 파일 확장자. (명시하지 않으면 파일 확장자 필터링하지 않음.)
$d['theme']['multiple'] = "1"; // 멀티 업로드 (허용=1/비허용=0)
?>

View File

@@ -0,0 +1,45 @@
<?php
// 모달 페이지 인클루드
include $g['dir_attach_theme'].'/modals.php';
?>
<?php getImport('jquery-form','jquery.form.min','4.2.2','js'); ?>
<script>
var inputId='attach-file-input'; // 실제 작옹하는 input 엘리먼트 id 값을 옵션으로 지정을 해준다. (커스텀 버튼으로 click 이벤트 바인딩)
var attach_file_saveDir = '<?php echo $g['path_file'].$parent_module?>/';// 파일 업로드 폴더
var attach_module_theme = '<?php echo $attach_module_theme?>';// attach 모듈 테마
var editor_type = '<?php echo $editor_type ?>'; // 에디터 타입 : html, markdown
$(document).ready(function() {
// 파일업로드 옵션값 세팅
var upload_settings = {
<?php if ($d['theme']['allowedTypes']): ?>
allowedTypes:"<?php echo $d['theme']['allowedTypes'] ?>",// 업로드 가능한 파일 확장자. 여기에 명시하지 않으면 파일 확장자 필터링하지 않음.
<?php endif; ?>
fileName: "files", // <input type="file" name=""> 의 name 값 --> php 에서 파일처리할 때 사용됨.
multiple: <?php echo $d['theme']['multiple']?'true':'false' ?>, // 멀티업로드를 할 경우 true 로 해준다.
inputId:inputId, // 실제 작옹하는 input 엘리먼트 id 값을 옵션으로 지정을 해준다. (커스텀 버튼으로 click 이벤트 바인딩)
formData: {"saveDir":attach_file_saveDir,"theme":attach_module_theme,"editor":editor_type} // 추가 데이타 세팅
}
$("#attach-files").RbUploadFile(upload_settings); // 아작스 폼+input=file 엘리먼트 세팅
// main.js 기본값 세팅
var attach_settings={
module : 'mediaset',
theme : attach_module_theme,
handler_photo : '<?php echo $attach_handler_photo?>',
handler_file : '<?php echo $attach_handler_file?>',
handler_getModalList : '<?php echo $attach_handler_getModalList?>',
listModal : '#modal-attach'
}
$("#attach-files").RbAttachTheme(attach_settings);
});
// 모달 활성화시에 입력필드 포커스 처리
$('#modal-attach-photo-meta').on('shown.bs.modal', function (event) {
var modal = $(this)
modal.find('[data-role="filecaption"]').focus()
})
</script>

View File

@@ -0,0 +1,75 @@
<?php
// 위젯 설정값 세팅
$parent_module=$d['attach']['parent_module']; // 첨부파일 사용하는 모듈
$parent_data=$d['attach']['parent_data']; // 해당 포스트 데이타 (수정시 필요)
$attach_module_theme=$d['attach']['theme']; // 첨부파일 테마
$attach_mode=$d['attach']['mod']; // list, main...
$attach_handler_file=$d['attach']['handler_file']; //파일첨부 실행 엘리먼트 button or 기타 엘리먼트 data-role="" 형태로 하는 것을 권고
$attach_handler_photo=$d['attach']['handler_photo']; // 사진첨부 실행 엘리먼트 button or 기타 엘리먼트 data-role="" 형태로 하는 것을 권고
$attach_handler_getModalList=$d['attach']['handler_getModalList']; // 첨부파일 리스트 호출 handler
$attach_object_type=$d['attach']['object_type']; // 첨부 대상에 따른 분류 : photo, file, link, video....
$editor_type=$d['attach']['editor_type']; // 에디터 타입 : html,markdown
require_once $g['dir_attach_theme'].'/main.func.php'; // 함수 인클루드
require_once $g['dir_attach_theme'].'/_var.php'; // 테마변수 인클루드
?>
<script src="<?php echo $g['url_attach_theme']?>/js/fileuploader.js"></script>
<script src="<?php echo $g['url_attach_theme']?>/main.js"></script>
<?php getImport('jquery-ui','jquery-ui.min','1.12.1','js')?>
<style>
[data-plugin="ui-sortable"] {
list-style-type: none;
margin: 0;
padding: 0;
width: 450px;
}
[data-plugin="ui-sortable"] .item {
position: relative;
margin: 3px 3px 3px 0;
float: left;
text-align: center;
cursor: move;
background-color: #eee;
min-width: 120px;
min-height: 120px;
text-align: center;
}
[data-plugin="ui-sortable"] .item .item-label,
[data-plugin="ui-sortable"] .item .item-btn {
position: absolute;
}
[data-plugin="ui-sortable"] .item .item-label {
top: 10px;
left : 10px;
right:auto;
bottom: auto
}
[data-plugin="ui-sortable"] .item .item-btn {
top: 10px;
right : 10px;
left:auto;
bottom: auto
}
[data-plugin="ui-sortable"] .item .btn {
border-radius: 0
}
.item.upload {
float: left;
margin: 3px 3px 3px 0;
border: 1px dashed #ddd;
background-color: #f5f5f5;
min-width: 120px;
min-height: 120px;
text-align: center;
color: #ccc
}
.item.upload:hover {
background-color: #eee;
}
</style>

View File

@@ -0,0 +1,899 @@
/*!
* jQuery Upload File Plugin
* version: 4.0.9
* @requires jQuery v1.5 or later & form plugin
* Copyright (c) 2013 Ravishanker Kusuma
* http://hayageek.com/
* https://github.com/hayageek/jquery-upload-file
*/
(function ($) {
var feature = {};
feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
feature.formdata = window.FormData !== undefined;
$.fn.RbUploadFile = function (options) {
// This is the easiest way to have default options.
var s = $.extend({
// These are the defaults.
url: rooturl+'/?r='+raccount+'&m=mediaset&a=upload', // attach 모듈 upload 액션 파일 지정
method: "POST",
enctype: "multipart/form-data",
returnType: null,
allowDuplicates: true,
duplicateStrict: false,
allowedTypes: "*",
//For list of acceptFiles
// http://stackoverflow.com/questions/11832930/html-input-file-accept-attribute-file-type-csv
acceptFiles: "*",
fileName: "file",
formData: false,
dynamicFormData:false,
maxFileSize: -1,
maxFileCount: -1,
multiple: true,
dragDrop: false, // 수정 dragDrop 사용하지 않음
autoSubmit: true,
showCancel: true,
showAbort: true,
showDone: false,
showDelete: false,
showError: true,
showStatusAfterSuccess: false, // 수정
showStatusAfterError: true,
showFileCounter: false, // 수정
fileCounterStyle: "). ",
showFileSize: true,
showProgress: true,
nestedForms: true,
showDownload: false,
onLoad: function (obj) {},
onSelect: function (files) {
return true;
},
onSubmit: function (files, xhr) {},
onSuccess: function (files, response, xhr, pd) {},
onError: function (files, status, message, pd) {},
onCancel: function (files, pd) {},
onAbort: function (files, pd) {},
downloadCallback: false,
deleteCallback: false,
afterUploadAll: false,
serialize:true,
sequential:false,
sequentialCount:2,
customProgressBar: false,
abortButtonClass: "btn btn-light btn-sm mt-2",
cancelButtonClass: "ajax-file-upload-cancel",
dragDropContainerClass: "ajax-upload-dragdrop",
dragDropHoverClass: "state-hover",
errorClass: "content-padded text-danger",
uploadButtonClass: "ajax-file-upload",
dragDropStr: "<span><b>Drag &amp; Drop Files</b></span>",
//uploadStr:"Upload",
uploadStr:"", // 첨부파일 버튼을 커스텀할 수 있도록 숨긴다.
abortStr: "취소",
cancelStr: "취소",
deletelStr: "삭제",
doneStr: "완료",
multiDragErrorStr: "드래그앤 드랍이 허용되지 않습니다.",
extErrorStr: "허용 된 확장가 아닙니다.: ",
duplicateErrorStr: "이미 존재하는 파일 입니다.",
sizeErrorStr: "허용 된 최대 크기를 초과합니다.: ",
uploadErrorStr: "업로드가 허용되지 않습니다.",
maxFileCountErrorStr: " 최대 허용 파일 수가 초과 되었습니다.:",
downloadStr: "Download",
customErrorKeyStr: "content-padded text-danger",
showQueueDiv: false,
// statusBarWidth: 400,
dragdropWidth: 400,
showPreview: false,
previewHeight: "auto",
previewWidth: "100%",
extraHTML:false,
uploadQueueOrder:'top'
}, options);
this.fileCounter = 1;
this.selectedFiles = 0;
var formGroup = "ajax-file-upload-" + (new Date().getTime());
this.formGroup = formGroup;
this.errorLog = $("<div></div>"); //Writing errors
this.responses = [];
this.existingFileNames = [];
if(!feature.formdata) //check drag drop enabled.
{
s.dragDrop = false;
}
if(!feature.formdata) {
s.multiple = false;
}
$(this).html("");
var obj = this;
var uploadLabel = $('<div>' + s.uploadStr + '</div>');
$(uploadLabel).addClass(s.uploadButtonClass);
// wait form ajax Form plugin and initialize
(function checkAjaxFormLoaded() {
if($.fn.ajaxForm) {
if(s.dragDrop) {
var dragDrop = $('<div class="' + s.dragDropContainerClass + '" style="vertical-align:top;"></div>').width(s.dragdropWidth);
$(obj).append(dragDrop);
$(dragDrop).append(uploadLabel);
$(dragDrop).append($(s.dragDropStr));
setDragDropHandlers(obj, s, dragDrop);
} else {
$(obj).append(uploadLabel);
}
$(obj).append(obj.errorLog);
// 미리보기 div 출력 삭제 - 이 부분은 해당 페이지에서 커스텀으로 처리한다.
if(s.showQueueDiv)
obj.container =$("#"+s.showQueueDiv);
else
obj.container = $("<div class='ajax-file-upload-container'></div>").insertAfter($(obj));
s.onLoad.call(this, obj);
createCustomInputFile(obj, formGroup, s, uploadLabel);
} else window.setTimeout(checkAjaxFormLoaded, 10);
})();
this.startUpload = function () {
$("form").each(function(i,items)
{
if($(this).hasClass(obj.formGroup))
{
mainQ.push($(this));
}
});
if(mainQ.length >= 1 )
submitPendingUploads();
}
this.getFileCount = function () {
return obj.selectedFiles;
}
this.stopUpload = function () {
$("." + s.abortButtonClass).each(function (i, items) {
if($(this).hasClass(obj.formGroup)) $(this).click();
});
$("." + s.cancelButtonClass).each(function (i, items) {
if($(this).hasClass(obj.formGroup)) $(this).click();
});
}
this.cancelAll = function () {
$("." + s.cancelButtonClass).each(function (i, items) {
if($(this).hasClass(obj.formGroup)) $(this).click();
});
}
this.update = function (settings) {
//update new settings
s = $.extend(s, settings);
}
this.reset = function (removeStatusBars) {
obj.fileCounter = 1;
obj.selectedFiles = 0;
obj.errorLog.html("");
//remove all the status bars.
if(removeStatusBars != false)
{
obj.container.html("");
}
}
this.remove = function()
{
obj.container.html("");
$(obj).remove();
}
//This is for showing Old files to user.
this.createProgress = function (filename,filepath,filesize) {
var pd = new createProgressDiv(this, s);
pd.progressDiv.show();
pd.progressbar.width('100%');
var fileNameStr = "";
if(s.showFileCounter)
fileNameStr = obj.fileCounter + s.fileCounterStyle + filename;
else fileNameStr = filename;
if(s.showFileSize)
fileNameStr += " ("+getSizeStr(filesize)+")";
pd.filename.html(fileNameStr);
obj.fileCounter++;
obj.selectedFiles++;
if(s.showPreview)
{
pd.preview.attr('src',filepath);
pd.preview.show();
}
if(s.showDownload) {
pd.download.show();
pd.download.click(function () {
if(s.downloadCallback) s.downloadCallback.call(obj, [filename]);
});
}
if(s.showDelete)
{
pd.del.show();
pd.del.click(function () {
pd.statusbar.hide().remove();
var arr = [filename];
if(s.deleteCallback) s.deleteCallback.call(this, arr, pd);
obj.selectedFiles -= 1;
updateFileCounter(s, obj);
});
}
return pd;
}
this.getResponses = function () {
return this.responses;
}
var mainQ=[];
var progressQ=[]
var running = false;
function submitPendingUploads() {
if(running) return;
running = true;
(function checkPendingForms() {
//if not sequential upload all files
if(!s.sequential) s.sequentialCount=99999;
if(mainQ.length == 0 && progressQ.length == 0)
{
if(s.afterUploadAll) s.afterUploadAll(obj);
running= false;
}
else
{
if( progressQ.length < s.sequentialCount)
{
var frm = mainQ.shift();
if(frm != undefined)
{
progressQ.push(frm);
frm.submit();
}
}
window.setTimeout(checkPendingForms, 100);
}
})();
}
function setDragDropHandlers(obj, s, ddObj) {
ddObj.on('dragenter', function (e) {
e.stopPropagation();
e.preventDefault();
$(this).addClass(s.dragDropHoverClass);
});
ddObj.on('dragover', function (e) {
e.stopPropagation();
e.preventDefault();
var that = $(this);
if (that.hasClass(s.dragDropContainerClass) && !that.hasClass(s.dragDropHoverClass)) {
that.addClass(s.dragDropHoverClass);
}
});
ddObj.on('drop', function (e) {
e.preventDefault();
$(this).removeClass(s.dragDropHoverClass);
obj.errorLog.html("");
var files = e.originalEvent.dataTransfer.files;
if(!s.multiple && files.length > 1) {
if(s.showError) $("<div class='" + s.errorClass + "'>" + s.multiDragErrorStr + "</div>").appendTo(obj.errorLog);
return;
}
if(s.onSelect(files) == false) return;
serializeAndUploadFiles(s, obj, files);
});
ddObj.on('dragleave', function (e) {
$(this).removeClass(s.dragDropHoverClass);
});
$(document).on('dragenter', function (e) {
e.stopPropagation();
e.preventDefault();
});
$(document).on('dragover', function (e) {
e.stopPropagation();
e.preventDefault();
var that = $(this);
if (!that.hasClass(s.dragDropContainerClass)) {
that.removeClass(s.dragDropHoverClass);
}
});
$(document).on('drop', function (e) {
e.stopPropagation();
e.preventDefault();
$(this).removeClass(s.dragDropHoverClass);
});
}
function getSizeStr(size) {
var sizeStr = "";
var sizeKB = size / 1024;
if(parseInt(sizeKB) > 1024) {
var sizeMB = sizeKB / 1024;
sizeStr = sizeMB.toFixed(2) + " MB";
} else {
sizeStr = sizeKB.toFixed(2) + " KB";
}
return sizeStr;
}
function serializeData(extraData) {
var serialized = [];
if(jQuery.type(extraData) == "string") {
serialized = extraData.split('&');
} else {
serialized = $.param(extraData).split('&');
}
var len = serialized.length;
var result = [];
var i, part;
for(i = 0; i < len; i++) {
serialized[i] = serialized[i].replace(/\+/g, ' ');
part = serialized[i].split('=');
result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]);
}
return result;
}
function noserializeAndUploadFiles(s, obj, files) {
var ts = s;
var fd = new FormData();
var fileArray = [];
var fileName = s.fileName.replace("[]", "");
var fileListStr="";
for (var i = 0; i < files.length; i++) {
if (!isFileTypeAllowed(obj, s, files[i].name)) {
if (s.showError) $("<div><font color='red'><b>" + files[i].name + "</b> " + s.extErrorStr + s.allowedTypes + "</font></div>").appendTo(obj.errorLog);
continue;
}
if (s.maxFileSize != -1 && files[i].size > s.maxFileSize) {
if (s.showError) $("<div><font color='red'><b>" + files[i].name + "</b> " + s.sizeErrorStr + getSizeStr(s.maxFileSize) + "</font></div>").appendTo(obj.errorLog);
continue;
}
fd.append(fileName+"[]", files[i]);
fileArray.push(files[i].name);
fileListStr += obj.fileCounter + "). " + files[i].name+"<br>";
obj.fileCounter++;
}
if(fileArray.length ==0 ) return;
var extraData = s.formData;
if (extraData) {
var sData = serializeData(extraData);
for (var j = 0; j < sData.length; j++) {
if (sData[j]) {
fd.append(sData[j][0], sData[j][1]);
}
}
}
ts.fileData = fd;
var pd = new createProgressDiv(obj, s);
pd.filename.html(fileListStr);
var form = $("<form style='display:block; position:absolute;left: 150px;' class='" + obj.formGroup + "' method='" + s.method + "' action='" + s.url + "' enctype='" + s.enctype + "'></form>");
form.appendTo('body');
ajaxFormSubmit(form, ts, pd, fileArray, obj);
}
function serializeAndUploadFiles(s, obj, files) {
for(var i = 0; i < files.length; i++) {
if(!isFileTypeAllowed(obj, s, files[i].name)) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + files[i].name + "</b> " + s.extErrorStr + s.allowedTypes + "</div>").appendTo(obj.errorLog);
continue;
}
if(!s.allowDuplicates && isFileDuplicate(obj, files[i].name)) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + files[i].name + "</b> " + s.duplicateErrorStr + "</div>").appendTo(obj.errorLog);
continue;
}
if(s.maxFileSize != -1 && files[i].size > s.maxFileSize) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + files[i].name + "</b> " + s.sizeErrorStr + getSizeStr(s.maxFileSize) + "</div>").appendTo(
obj.errorLog);
continue;
}
if(s.maxFileCount != -1 && obj.selectedFiles >= s.maxFileCount) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + files[i].name + "</b> " + s.maxFileCountErrorStr + s.maxFileCount + "</div>").appendTo(
obj.errorLog);
continue;
}
obj.selectedFiles++;
obj.existingFileNames.push(files[i].name);
var ts = s;
var fd = new FormData();
var fileName = s.fileName.replace("[]", "");
fd.append(fileName, files[i]);
var extraData = s.formData;
if(extraData) {
var sData = serializeData(extraData);
for(var j = 0; j < sData.length; j++) {
if(sData[j]) {
fd.append(sData[j][0], sData[j][1]);
}
}
}
ts.fileData = fd;
var pd = new createProgressDiv(obj, s);
var fileNameStr = "";
if(s.showFileCounter) fileNameStr = obj.fileCounter + s.fileCounterStyle + files[i].name
else fileNameStr = files[i].name;
if(s.showFileSize)
fileNameStr += " ("+getSizeStr(files[i].size)+")";
pd.filename.html(fileNameStr);
var form = $("<form style='display:block; position:absolute;left: 150px;' class='" + obj.formGroup + "' method='" + s.method + "' action='" +
s.url + "' enctype='" + s.enctype + "'></form>");
form.appendTo('body');
var fileArray = [];
fileArray.push(files[i].name);
ajaxFormSubmit(form, ts, pd, fileArray, obj, files[i]);
obj.fileCounter++;
}
}
function isFileTypeAllowed(obj, s, fileName) {
var fileExtensions = s.allowedTypes.toLowerCase().split(/[\s,]+/g);
var ext = fileName.split('.').pop().toLowerCase();
if(s.allowedTypes != "*" && jQuery.inArray(ext, fileExtensions) < 0) {
return false;
}
return true;
}
function isFileDuplicate(obj, filename) {
var duplicate = false;
if (obj.existingFileNames.length) {
for (var x=0; x<obj.existingFileNames.length; x++) {
if (obj.existingFileNames[x] == filename
|| s.duplicateStrict && obj.existingFileNames[x].toLowerCase() == filename.toLowerCase()
) {
duplicate = true;
}
}
}
return duplicate;
}
function removeExistingFileName(obj, fileArr) {
if (obj.existingFileNames.length) {
for (var x=0; x<fileArr.length; x++) {
var pos = obj.existingFileNames.indexOf(fileArr[x]);
if (pos != -1) {
obj.existingFileNames.splice(pos, 1);
}
}
}
}
function getSrcToPreview(file, obj) {
if(file) {
obj.show();
var reader = new FileReader();
reader.onload = function (e) {
obj.attr('src', e.target.result);
};
reader.readAsDataURL(file);
}
}
function updateFileCounter(s, obj) {
if(s.showFileCounter) {
var count = $(obj.container).find(".ajax-file-upload-filename").length;
obj.fileCounter = count + 1;
$(obj.container).find(".ajax-file-upload-filename").each(function (i, items) {
var arr = $(this).html().split(s.fileCounterStyle);
var fileNum = parseInt(arr[0]) - 1; //decrement;
var name = count + s.fileCounterStyle + arr[1];
$(this).html(name);
count--;
});
}
}
// input 폼 세팅함수
function createCustomInputFile (obj, group, s, uploadLabel) {
//var fileUploadId = "ajax-upload-id-" + (new Date().getTime());
var fileUploadId=s.inputId; // 옵션에서 지정한 id 값으로 세팅한다.
var form = $("<form method='" + s.method + "' action='" + s.url + "' enctype='" + s.enctype + "'></form>");
var fileInputStr = "<input type='file' id='" + fileUploadId + "' name='" + s.fileName + "' accept='" + s.acceptFiles + "'/>";
if(s.multiple) {
if(s.fileName.indexOf("[]") != s.fileName.length - 2) // if it does not endwith
{
s.fileName += "[]";
}
fileInputStr = "<input type='file' id='" + fileUploadId + "' name='" + s.fileName + "' accept='" + s.acceptFiles + "' multiple/>";
}
var fileInput = $(fileInputStr).appendTo(form);
//fileInput.change(function () {
$(form).on('change','#'+fileUploadId,function(){
console.log(fileUploadId);
obj.errorLog.html("");
var fileExtensions = s.allowedTypes.toLowerCase().split(",");
var fileArray = [];
if(this.files) //support reading files
{
for(i = 0; i < this.files.length; i++) {
fileArray.push(this.files[i].name);
}
if(s.onSelect(this.files) == false) return;
} else {
var filenameStr = $(this).val();
var flist = [];
fileArray.push(filenameStr);
if(!isFileTypeAllowed(obj, s, filenameStr)) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + filenameStr + "</b> " + s.extErrorStr + s.allowedTypes + "</div>").appendTo(
obj.errorLog);
return;
}
//fallback for browser without FileAPI
flist.push({
name: filenameStr,
size: 'NA'
});
if(s.onSelect(flist) == false) return;
}
updateFileCounter(s, obj);
uploadLabel.unbind("click");
form.hide();
createCustomInputFile(obj, group, s, uploadLabel);
form.addClass(group);
if(s.serialize && feature.fileapi && feature.formdata) //use HTML5 support and split file submission
{
form.removeClass(group); //Stop Submitting when.
var files = this.files;
form.remove();
serializeAndUploadFiles(s, obj, files);
} else {
var fileList = "";
for(var i = 0; i < fileArray.length; i++) {
if(s.showFileCounter) fileList += obj.fileCounter + s.fileCounterStyle + fileArray[i] + "<br>";
else fileList += fileArray[i] + "<br>";;
obj.fileCounter++;
}
if(s.maxFileCount != -1 && (obj.selectedFiles + fileArray.length) > s.maxFileCount) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + fileList + "</b> " + s.maxFileCountErrorStr + s.maxFileCount + "</div>").appendTo(
obj.errorLog);
return;
}
obj.selectedFiles += fileArray.length;
var pd = new createProgressDiv(obj, s);
pd.filename.html(fileList);
ajaxFormSubmit(form, s, pd, fileArray, obj, null);
}
});
if(s.nestedForms) {
form.css({
'margin': 0,
'padding': 0
});
uploadLabel.css({
position: 'relative',
overflow: 'hidden',
cursor: 'default'
});
fileInput.css({
position: 'absolute',
'cursor': 'pointer',
'top': '0px',
'width': '100%',
'height': '100%',
'left': '0px',
'z-index': '100',
'opacity': '0.0',
'filter': 'alpha(opacity=0)',
'-ms-filter': "alpha(opacity=0)",
'-khtml-opacity': '0.0',
'-moz-opacity': '0.0'
});
form.appendTo(uploadLabel);
} else {
form.appendTo($('body'));
form.css({
margin: 0,
padding: 0,
display: 'block',
position: 'absolute',
left: '-250px'
});
if(navigator.appVersion.indexOf("MSIE ") != -1) //IE Browser
{
uploadLabel.attr('for', fileUploadId);
} else {
uploadLabel.click(function () {
fileInput.click();
});
}
}
}
function defaultProgressBar(obj,s)
{
this.statusbar = $("<section class='mb-3'></section>").width(s.statusBarWidth);
this.preview = $("<img class='ajax-file-upload-preview' />").width(s.previewWidth).height(s.previewHeight).appendTo(this.statusbar).hide();
this.filename = $("<div class='text-muted small my-2'></div>").appendTo(this.statusbar);
this.progressDiv = $("<div class='progress rounded-0' style='height: 20px;'>").appendTo(this.statusbar).hide();
this.progressbar = $("<div class='progress-bar progress-bar-striped progress-bar-animated'></div>").appendTo(this.progressDiv);
this.abort = $("<button>" + s.abortStr + "</button>").appendTo(this.statusbar).hide();
this.cancel = $("<div>" + s.cancelStr + "</div>").appendTo(this.statusbar).hide();
this.done = $("<div>" + s.doneStr + "</div>").appendTo(this.statusbar).hide();
this.download = $("<div>" + s.downloadStr + "</div>").appendTo(this.statusbar).hide();
this.del = $("<div>" + s.deletelStr + "</div>").appendTo(this.statusbar).hide();
// this.abort.addClass("ajax-file-upload-red");
this.done.addClass("ajax-file-upload-green");
this.download.addClass("ajax-file-upload-green");
this.cancel.addClass("ajax-file-upload-red");
this.del.addClass("ajax-file-upload-red");
return this;
}
function createProgressDiv(obj, s) {
var bar = null;
if(s.customProgressBar)
bar = new s.customProgressBar(obj,s);
else
bar = new defaultProgressBar(obj,s);
bar.abort.addClass(obj.formGroup);
bar.abort.addClass(s.abortButtonClass);
bar.cancel.addClass(obj.formGroup);
bar.cancel.addClass(s.cancelButtonClass);
if(s.extraHTML)
bar.extraHTML = $("<div class='extrahtml'>"+s.extraHTML()+"</div>").insertAfter(bar.filename);
if(s.uploadQueueOrder == 'bottom')
$(obj.container).append(bar.statusbar);
else
$(obj.container).prepend(bar.statusbar);
return bar;
}
function ajaxFormSubmit(form, s, pd, fileArray, obj, file) {
var currentXHR = null;
var options = {
cache: false,
contentType: false,
processData: false,
forceSync: false,
type: s.method,
data: s.formData,
formData: s.fileData,
dataType: s.returnType,
beforeSubmit: function (formData, $form, options) {
if(s.onSubmit.call(this, fileArray) != false) {
if(s.dynamicFormData)
{
var sData = serializeData(s.dynamicFormData());
if(sData) {
for(var j = 0; j < sData.length; j++) {
if(sData[j]) {
if(s.fileData != undefined) options.formData.append(sData[j][0], sData[j][1]);
else options.data[sData[j][0]] = sData[j][1];
}
}
}
}
if(s.extraHTML)
{
$(pd.extraHTML).find("input,select,textarea").each(function(i,items)
{
if(s.fileData != undefined) options.formData.append($(this).attr('name'),$(this).val());
else options.data[$(this).attr('name')] = $(this).val();
});
}
return true;
}
pd.statusbar.append("<div class='" + s.errorClass + "'>" + s.uploadErrorStr + "</div>");
pd.cancel.show()
form.remove();
pd.cancel.click(function () {
mainQ.splice(mainQ.indexOf(form), 1);
removeExistingFileName(obj, fileArray);
pd.statusbar.remove();
s.onCancel.call(obj, fileArray, pd);
obj.selectedFiles -= fileArray.length; //reduce selected File count
updateFileCounter(s, obj);
});
return false;
},
beforeSend: function (xhr, o) {
pd.progressDiv.show();
pd.cancel.hide();
pd.done.hide();
if(s.showAbort) {
pd.abort.show();
pd.abort.click(function () {
removeExistingFileName(obj, fileArray);
xhr.abort();
obj.selectedFiles -= fileArray.length; //reduce selected File count
s.onAbort.call(obj, fileArray, pd);
});
}
if(!feature.formdata) //For iframe based push
{
pd.progressbar.width('5%');
} else pd.progressbar.width('1%'); //Fix for small files
},
uploadProgress: function (event, position, total, percentComplete) {
//Fix for smaller file uploads in MAC
if(percentComplete > 98) percentComplete = 98;
var percentVal = percentComplete + '%';
if(percentComplete > 1) pd.progressbar.width(percentVal)
if(s.showProgress) {
pd.progressbar.html(percentVal);
pd.progressbar.css('text-align', 'center');
}
},
success: function (data, message, xhr) {
pd.cancel.remove();
progressQ.pop();
//For custom errors.
if(s.returnType == "json" && $.type(data) == "object" && data.hasOwnProperty(s.customErrorKeyStr)) {
pd.abort.hide();
var msg = data[s.customErrorKeyStr];
s.onError.call(this, fileArray, 200, msg, pd);
if(s.showStatusAfterError) {
pd.progressDiv.hide();
pd.statusbar.append("<span class='" + s.errorClass + "'>ERROR: " + msg + "</span>");
} else {
pd.statusbar.hide();
pd.statusbar.remove();
}
obj.selectedFiles -= fileArray.length; //reduce selected File count
form.remove();
return;
}
obj.responses.push(data);
pd.progressbar.width('100%')
if(s.showProgress) {
pd.progressbar.html('100%');
pd.progressbar.css('text-align', 'center');
}
pd.abort.hide();
s.onSuccess.call(this, fileArray, data, xhr, pd); // 해당 페이지에서 업로드 성공 후 추가 액션 가능
// 미리보기 출력
var result=$.parseJSON(data); // a.upload.php 에서 결과값을 preview & type 으로 구분하여 json 으로 보내준다.
var preview_default=result.preview_default; // 기본 리스트
var preview_modal=result.preview_modal; // 모달 리스트 (소스복사외 다른 메뉴는 노출하지 않는다.)
var attachType=result.type; // 해당 attachHandler 의 data-type 값 photo, file, map, link, people....
var previewBox_default=$('[data-role="attach-preview-'+attachType+'"]'); // type 에 따라서 미리보기 container 를 분리해서 지정한다.
var previewBox_modal=$('[data-role="modal-attach-preview-'+attachType+'"]'); // type 에 따라서 미리보기 container 를 분리해서 지정한다.
$(preview_default).appendTo(previewBox_default);// 업로드 성공후 미리보기 출력되는 부분 처리
$(preview_modal).appendTo(previewBox_modal);// 업로드 성공후 모달 미리보기 출력되는 부분 처리
if(s.showStatusAfterSuccess) {
if(s.showDone) {
pd.done.show();
pd.done.click(function () {
pd.statusbar.hide("slow");
pd.statusbar.remove();
});
} else {
pd.done.hide();
}
if(s.showDelete) {
pd.del.show();
pd.del.click(function () {
removeExistingFileName(obj, fileArray);
pd.statusbar.hide().remove();
if(s.deleteCallback) s.deleteCallback.call(this, data, pd);
obj.selectedFiles -= fileArray.length; //reduce selected File count
updateFileCounter(s, obj);
});
} else {
pd.del.hide();
}
} else {
pd.statusbar.hide("slow");
pd.statusbar.remove();
}
if(s.showDownload) {
pd.download.show();
pd.download.click(function () {
if(s.downloadCallback) s.downloadCallback(data);
});
}
form.remove();
},
error: function (xhr, status, errMsg) {
pd.cancel.remove();
progressQ.pop();
pd.abort.hide();
if(xhr.statusText == "abort") //we aborted it
{
pd.statusbar.hide("slow").remove();
updateFileCounter(s, obj);
} else {
s.onError.call(this, fileArray, status, errMsg, pd);
if(s.showStatusAfterError) {
pd.progressDiv.hide();
pd.statusbar.append("<span class='" + s.errorClass + "'>ERROR: " + errMsg + "</span>");
} else {
pd.statusbar.hide();
pd.statusbar.remove();
}
obj.selectedFiles -= fileArray.length; //reduce selected File count
}
form.remove();
}
};
if(s.showPreview && file != null) {
if(file.type.toLowerCase().split("/").shift() == "image") getSrcToPreview(file, pd.preview);
}
if(s.autoSubmit) {
form.ajaxForm(options);
mainQ.push(form);
submitPendingUploads();
} else {
if(s.showCancel) {
pd.cancel.show();
pd.cancel.click(function () {
mainQ.splice(mainQ.indexOf(form), 1);
removeExistingFileName(obj, fileArray);
form.remove();
pd.statusbar.remove();
s.onCancel.call(obj, fileArray, pd);
obj.selectedFiles -= fileArray.length; //reduce selected File count
updateFileCounter(s, obj);
});
}
form.ajaxForm(options);
}
}
return this;
}
}(jQuery));

View File

@@ -0,0 +1,181 @@
<?php
// 첨부파일 리스트 갯수 추출 함수
function getAttachNum($upload,$mod)
{
global $table;
$attach = getArrayString($upload);
$attach_file_num=0;// 첨부파일 수량
$hidden_file_num=0; // 숨김파일(다운로드 방지) 수량
foreach($attach['data'] as $val)
{
$U = getUidData($table['s_upload'],$val);
if($U['fileonly']==1) $attach_file_num++; // 전체 첨부파일 수량 증가
if($U['hidden']==1) $hidden_file_num++; // 숨김파일 수량 증가
}
$down_file_num=$attach_file_num-$hidden_file_num; // 다운로드 가능한 첨부파일
$result=array();
$result['modify']=$attach_file_num;
$result['view']=$down_file_num;
return $result[$mod];
}
// 첨부파일 리스트 추출 함수 (전체)
/*
$parent_data : 해당 포스트의 row 배열
$mod : upload or modal ==> 실제 업로드 모드 와 모달을 띄워서 본문에 삽입용도로 쓰거나
*/
function getAttachFileList($parent_data,$mod,$type,$editor)
{
global $table;
$upload=$parent_data['upload'];
$featured_img_uid=$parent_data['featured_img'];// 대표이미지 uid
$featured_video_uid=$parent_data['featured_video'];// 대표비디오 uid
$featured_audio_uid=$parent_data['featured_audio'];// 대표오디오 uid
if($type=='file') $sql='type=1';
else if($type=='photo') $sql='type=2';
else if($type=='audio') $sql='type=4';
else if($type=='video') $sql='type=5';
else if($type=='doc') $sql='type=6';
else if($type=='zip') $sql='type=7';
else if($type=='pdf') $sql='type=7';
else $sql='type=1';
$attach = getArrayString($upload);
$uid_q='(';
foreach($attach['data'] as $uid)
{
$uid_q.='uid='.$uid.' or ';
}
$uid_q=substr($uid_q,0,-4).')';
$sql=$sql.' and '.$uid_q;
$RCD=getDbArray($table['s_upload'],$sql,'*','gid','asc','',1);
$html='';
while($R=db_fetch_array($RCD)){
$U=getUidData($table['s_upload'],$R['uid']);
if($type=='file') $html.=getAttachFile($U,$mod,$featured_img_uid,$editor);
else if($type=='photo') $html.=getAttachFile($U,$mod,$featured_img_uid,$editor);
else if($type=='audio') $html.=getAttachAudio($U,$mod,$featured_audio_uid,$editor);
else if($type=='video') $html.=getAttachVideo($U,$mod,$featured_video_uid,$editor);
else if($type=='doc') $html.=getAttachFile($U,$mod,$featured_img_uid,$editor);
else if($type=='zip') $html.=getAttachFile($U,$mod,$featured_img_uid,$editor);
else if($type=='pdf') $html.=getAttachFile($U,$mod,$featured_img_uid,$editor);
else $html.=getAttachFile($U,$mod,$featured_img_uid,$editor);;
}
return $html;
}
// 첨부파일 리스트 추출 함수 (낱개)
function getAttachFile($R,$mod,$featured_img_uid,$editor)
{
global $g,$r;
$fileName=explode('.',$R['name']);
$file_name=$fileName[0]; // 파일명만 분리
if ($R['type']==2) {
$type='photo';
} elseif($R['type']==4) {
$type='audio';
} elseif($R['type']==5) {
$type='video';
} else {
$type='file';
}
if($type=='photo'){
$caption=$R['caption']?$R['caption']:$file_name;
$img_origin=$R['url'].$R['folder'].'/'.$R['tmpname'];
$thumb_list=getPreviewResize($R['src'],'q'); // 미리보기 사이즈 조정 (이미지 업로드시 썸네일을 만들 필요 없다.)
$thumb_modal=getPreviewResize($R['src'],'z'); // 정보수정 모달용 사이즈 조정 (이미지 업로드시 썸네일을 만들 필요 없다.)
$insert_text='!['.$caption.']('.$g['url_root'].$img_origin.')';
}else if($type=='file'){
$caption=$R['caption']?$R['caption']:$R['name'];
$src=$R['url'].$R['folder'].'/'.$R['name'];
$insert_text='['.$caption.']('.$g['url_root'].'/?r='.$r.'&m=mediaset&a=download&uid='.$R['uid'].')';
}
$html='';
$html.='
<li class="item" data-id="'.$R['uid'].'" style="background-color: transparent">';
if($R['type']==2){
$html.='
<div class="">
<img class="border" src="'.$thumb_list.'" alt="'.$caption.'" style="width: 120px">
<div class="item-label">';
$html.='<span class="badge badge-secondary'.($R['uid']==$featured_img_uid?'':' d-none').'" data-role="attachList-label-featured" data-id="'.$R['uid'].'">대표</span> ';
$html.='<span class="badge badge-secondary'.(!$R['hidden']?' d-none':'').'" data-role="attachList-label-hidden-'.$R['uid'].'">숨김</span>';
$html.='
<a class="d-none" href="#" data-role="attachList-list-name-'.$R['uid'].'" data-attach-act="insert" data-type="'.$type.'" data-origin="'.($R['type']==2?$img_origin:$src).'" data-caption="'.$caption.'" data-editor="'.$editor.'">'.$R['name'].'</a>
<small class="d-none text-muted">'.getSizeFormat($R['size'],2).'</small>
</div>
</div>';
}else {
$html.='
<div class="dd-handle fa fa-arrows" title="순서변경"></div>
<div class="ml-5 mr-auto">
<i class="fa fa-floppy-o fa-fw mr-1"></i>';
$html.='<span class="badge badge-secondary'.(!$R['hidden']?' d-none':'').'" data-role="attachList-label-hidden-'.$R['uid'].'">숨김</span>';
$html.='
<a href="#" class="list-group-item-text" data-role="attachList-list-name-'.$R['uid'].'" data-attach-act="insert" data-type="'.$type.'" data-origin="'.($R['type']==2?$img_origin:$src).'" data-caption="'.$caption.'" data-editor="'.$editor.'">'.$R['name'].'</a>
<small class="text-muted">'.getSizeFormat($R['size'],2).'</small>
</div>';
}
if($mod=='upload') $html.='<input type="hidden" name="attachfiles[]" value="['.$R['uid'].']"/>';
$html.='<div class="item-btn"><div class="btn-group btn-group-sm">';
$html.='
<button type="button" class="btn btn-light" data-attach-act="delete" data-id="'.$R['uid'].'" data-role="attachList-menu-delete-'.$R['uid'].'" data-featured="" data-type="'.$type.'"><i class="fa fa-times" aria-hidden="true"></i></button>';
if($mod=='upload'){
$html.='
<button type="button" class="btn btn-light dropdown-toggle dropdown-toggle-split" data-toggle="dropdown">
<span class="sr-only">Toggle Dropdown</span>
</button>
<div class="dropdown-menu dropdown-menu-right">';
if($R['type']==2){
$html.='
<a class="dropdown-item" href="#" data-attach-act="featured-img" data-type="'.$type.'" data-id="'.$R['uid'].'">대표이미지 설정</a>';
}
$html.='
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#modal-attach-'.($R['type']==2?'photo':'file').'-meta" data-filename="'.$file_name.'" data-fileext="'.$R['ext'].'" data-caption="'.$caption.'" data-src="'.$thumb_modal.'" data-origin="'.$img_origin.'" data-attach-act="edit" data-id="'.$R['uid'].'" data-type="'.$type.'" data-role="attachList-menu-edit-'.$R['uid'].'">정보수정</a>
<a class="dropdown-item" href="#" data-attach-act="showhide" data-role="attachList-menu-showhide-'.$R['uid'].'" data-id="'.$R['uid'].'" data-content="'.($R['hidden']?'show':'hide').'" >'.($R['hidden']?'보이기':'숨기기').'</a>
<a class="dropdown-item" href="#" data-attach-act="delete" data-id="'.$R['uid'].'" data-role="attachList-menu-delete-'.$R['uid'].'" data-featured="" data-type="'.$type.'">삭제</a>
</div>';
}
$html.='
</div></div>
</li>';
return $html;
}
// 본문삽입 이미지 uid 얻기 함수
function getInsertImgUid($upload)
{
global $table;
$u_arr = getArrayString($upload);
$Insert_arr=array();
$i=0;
foreach ($u_arr['data'] as $val) {
$U=getUidData($table['s_upload'],$val);
if(!$U['fileonly']) $Insert_arr[$i]=$val;
$i++;
}
$upfiles='';
// 중괄로로 재조립
foreach ($Insert_arr as $uid) {
$upfiles.='['.$uid.']';
}
return $upfiles;
}
?>

View File

@@ -0,0 +1,214 @@
/**
* Copyright (c) 2015 redblock inc.
* Author kiere@kismq.com
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*
* Version: 1.0.0
*/
(function ($) {
$.fn.RbAttachTheme= function (settings) {
var defaults = {};
var opts = jQuery.extend(defaults, settings);
var module=opts.module; // 모듈명
var theme=opts.theme; // 테마 패스
var handler_photo=opts.handler_photo; // 사진첨부 실행 엘리먼트
var handler_file=opts.handler_file; // 파일첨부 실행 엘리먼트
var handler_getModalList=opts.handler_getModalList; // 첨부리스트 모달로 호출하는 엘리먼트
var listModal=opts.listModal;
var loaderbox='<div style="height:50%;margin-top:40%;" id="modal-loader-default"><div class="spinner-wrap"><div class="spinner"><div class="bounce1"></div><div class="bounce2"></div><div class="bounce3"></div></div></div></div>';
// 부모 모듈에서 파일첨부 액션 실행하는 버튼 or 기타 엘리먼트 클릭시 첨부파일 input click 이벤트 바인딩
$(handler_file).click(function(e){
e.preventDefault();
$('#'+inputId).click();
});
// 부모 모듈에서 사진첨부 액션 실행하는 버튼 or 기타 엘리먼트 클릭시 첨부파일 input click 이벤트 바인딩
$(handler_photo).click(function(e){
e.preventDefault();
$('#'+inputId).click();
});
// 부모 페이지 마크다운 에디터 toolbar 의 첨부파일 리스트 호출버튼 class 클릭시 첨부파일 리스트 모달 호출
$('body').on('click',handler_getModalList,function(){
if(handler_getModalList!='') $(listModal).modal('show');
});
// 업로드 리스트 showhide 값 reset 함수
var updateShowHide=function(uid,showhide){
if(showhide=='show'){
$('[data-role="attachList-menu-showhide-'+uid+'"]').attr('data-content','hide'); // data-content 값 수정
$('[data-role="attachList-menu-showhide-'+uid+'"]').text('숨기기'); // 메뉴명 변경
$('[data-role="attachList-label-hidden-'+uid+'"]').addClass('d-none'); // 숨김 라벨 숨기기
console.log($('[data-role="attachList-label-hidden-'+uid+'"]'));
}else{
$('[data-role="attachList-menu-showhide-'+uid+'"]').attr('data-content','show'); // data-content 값 수정
$('[data-role="attachList-menu-showhide-'+uid+'"]').text('보이기'); // 메뉴명 변경
$('[data-role="attachList-label-hidden-'+uid+'"]').removeClass('d-none'); // 숨김 라벨 노출
}
}
// 이벤트 바인딩 및 세팅
$('body').on('click','[data-attach-act]',function(e){
e.preventDefault();
var act=$(this).data('attach-act');
var uid=$(this).attr('data-id');
var type=$(this).data('type'); // file or photo
if(act=='edit'){
// data 값 세팅
var modal=$(this).data('target');
var filename=$(this).attr('data-filename'); // data-로 하면 변경된 값 적용 안됨
var fileext=$(this).data('fileext');
var caption=$(this).attr('data-caption'); // data- 로 하면 변경된 값 적용 안됨
var img_thumb=$(this).data('src');// 미리보기 이미지
var img_origin=$(this).data('origin');// 원본 이미지
// data 값 모달에 적용
$(modal).find('[data-role="filename"]').val(filename);
$(modal).find('[data-role="fileext"]').text(fileext);
$(modal).find('[data-role="filecaption"]').val(caption);
$(modal).find('[data-role="eventHandler"]').attr('data-id',uid); // save, cancel 엘리먼트 data-id="" 값에 uid 값 적용
$(modal).find('[data-role="eventHandler"]').attr('data-type',type); // save, cancel 엘리먼트 data-type="" 값에 type 값 적용
if(type=='photo'){
$(modal).find('[data-role="img-preview"]').attr('src',img_thumb); // 미리보기 이미지 src 적용
$(modal).find('[data-role="img-preview"]').attr('data-origin',img_origin); // 원본 이미지 src 적용
} else if(type=='video'){
$(modal).find('[data-role="img-preview"]').html('<i class="fa fa-file-video-o fa-4x"></i>'); // 타입별 아이콘 적용
} else if(type=='audio'){
$(modal).find('[data-role="img-preview"]').html('<i class="fa fa-file-audio-o fa-4x"></i>'); // 타입별 아이콘 적용
} else {
$(modal).find('[data-role="img-preview"]').html('<i class="fa fa-floppy-o fa-4x"></i>'); // 타입별 아이콘 적용
}
}
//액션 실행
if(act=='delete'){
// 삭제하는 리스트가 대표 이미지인 경우 write.php input 값에 적용
var is_featured=$(this).attr('data-featured');
if(is_featured=='1' && type=='photo'){
if(confirm('대표이미지를 삭제하시겠습니까? ')){
$('input[name="featured_img"]').val('');
}else{
return false;
}
}
$(this).closest('[data-id]').remove(); //항목 우선삭제
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=delete',{
uid : uid
},function(response){
var previewUl_default=$('[data-role="attach-preview-'+type+'"]'); // 파일 리스트 엘리먼트 class
var previewUl_modal=$('[data-role="modal-attach-preview-'+type+'"]'); // 파일 리스트 엘리먼트 class
var delEl_default=$(previewUl_default).find('[data-id="'+uid+'"]'); // 삭제 이벤트 진행된 엘리먼트
var delEl_modal=$(previewUl_modal).find('[data-id="'+uid+'"]'); // 삭제 이벤트 진행된 엘리먼트
delEl_default.remove();// 삭제 이벤트 진행시 해당 li 엘리먼트 remove
delEl_modal.remove();// 삭제 이벤트 진행시 해당 li 엘리먼트 remove
});
}else if(act=='showhide'){
var showhide=$(this).attr('data-content'); // data('content') 로 할 경우, ajax 로 변경된 값이 인식되지 않는다.
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=edit',{
act : act,
uid : uid,
showhide : showhide
},function(response){
var result=$.parseJSON(response);
if(!result.error){
updateShowHide(uid,showhide);
}
});
}else if(act=='save'){ // 정보수정 저장
var modal=$(this).data('target');
var filename=$(modal).find('[data-role="filename"]').val(); // 입력된 파일명
var filetype=$(modal).find('[data-role="eventHandler"]').attr('data-type'); // photo or file
var fileext=$(modal).find('[data-role="fileext"]').text(); // 입력된 파일 확장자명
var filecaption=$(modal).find('[data-role="filecaption"]').val(); // 입력된 캡션명
var filesrc=$(modal).find('[data-role="img-preview"]').attr('data-origin'); // 원본 이미지 소스
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=edit',{
act : act,
uid : uid,
filename : filename,
filetype : filetype,
fileext : fileext,
filecaption : filecaption,
filesrc : filesrc
},function(response){
var result=$.parseJSON(response);
if(!result.error){
var new_filename=result.filename;
var new_filecaption=result.filecaption;
var new_fileext=result.fileext;
var new_filetype=result.filetype;
var new_filesrc=result.filesrc;
// 리스트 값 수정
$('[data-role="attachList-menu-edit-'+uid+'"]').attr('data-filename',new_filename); // 파일명 수정
$('[data-role="attachList-menu-edit-'+uid+'"]').attr('data-caption',new_filecaption); // 'edit' 메뉴 캡션 업데이트
$('[data-role="attachList-menu-insert-'+uid+'"]').attr('data-caption',new_filecaption); // 'insert' 메뉴 캡션내용 수정
$('[data-role="attachList-list-name-'+uid+'"]').text(new_filename+'.'+new_fileext); // 리스트 name 수정
$('[data-role="attachList-list-name-'+uid+'"]').attr('data-caption',new_filecaption); // 리스트에도 캡션 업데이트
// 모달 닫기
$(modal).modal('hide');
$(modal).find('[data-role="filename"]').val(''); // 입력된 파일명 초기화
$(modal).find('[data-role="fileext"]').text(''); // 입력된 파일 확장자명 초기화
$(modal).find('[data-role="filecaption"]').val(''); // 입력된 캡션명 초기화
}
});
}else if(act=='featured-img'){ // 대표이미지 설정
// write.php 페이지 <input name="featured_img" value > 값에 적용
$('input[name="featured_img"]').val(uid);
// 대표 이미지 라벨 업데이트
$('[data-role="attachList-label-featured"]').each(function(){
$(this).addClass('d-none');
// 삭제 메뉴에 대표이미지 표시 지우기
$('[data-attach-act="delete"]').attr('data-featured','');
if($(this).data('id')==uid){
$(this).removeClass('d-none');
// 삭제 메뉴에 대표이미지 표시
$('[data-role="attachList-menu-delete-'+uid+'"]').attr('data-featured',1);
}
});
}else if(act=='insert'){
var src=$(this).data('origin');
var editor=$(this).data('editor');
var caption=$(this).attr('data-caption');
var dn_url = rooturl+'/download/'+uid;
if (editor=='markdown') {
var img_html = '!['+caption+']('+src+')';
var file_html = '['+caption+']('+dn_url+')';
} else {
var img_html = '<img src="'+src+'" alt="'+caption+'" class="img-fluid">';
var file_html = '<a href="'+dn_url+'">'+caption+'</a>';
}
if(type=='photo') {
InserHTMLtoEditor(type,img_html,src,caption)
} else {
InserHTMLtoEditor(type,file_html,dn_url,caption)
}
var showhide= 'hide'; // 숨김처리
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=edit',{
act : act,
uid : uid,
showhide : showhide
},function(response){
var result=$.parseJSON(response);
if(!result.error){
updateShowHide(uid,showhide);
}
});
}
});
};
})(jQuery);

View File

@@ -0,0 +1,73 @@
<?php
include $g['dir_attach_theme'].'/header.php';
?>
<p class="text-muted">
사진 또는 이미지만 업로드 가능합니다.
</p>
<div class="rb-attach mb-3 clearfix">
<ul class="rb-attach-photo sortable mb-2 bg-faded" data-role="attach-preview-photo" data-plugin="ui-sortable"><!-- 포토/이미지 리스트 -->
<?php if($parent_data['uid']):?>
<?php echo getAttachFileList($parent_data,'upload','photo',$editor_type)?>
<?php endif?>
</ul>
<button type="button" class="item upload h1" role="button"
data-role="attach-handler-file"
data-type="file"
title="사진첨부"
data-loading-text="업로드 중...">
<i class="fa fa-plus fa-lg"></i>
</button>
</div>
<div id="attach-files" class="files"><!-- 파일폼 출력 --></div>
<?php include $g['dir_attach_theme'].'/footer.php';?>
<script>
var link_settings={
module : 'mediaset',
theme : '<?php echo $g['dir_attach_theme']?>',
};
$('.rb-preview').on('click', function() {
$(this).removeClass('btn-primary').addClass('btn-light')
});
$(document).ready(function(){
// 사진 첨부사진 순서변경
$('[data-plugin="ui-sortable"]').sortable({
update: function(event, ui) {
var attachfiles=$('input[name="attachfiles[]"]').map(function(){return $(this).val()}).get();
var new_upfiles='';
if(attachfiles){
for(var i=0;i<attachfiles.length;i++) {
new_upfiles+=attachfiles[i];
}
}
$.post(rooturl+'/?r='+raccount+'&m=mediaset&a=modifygid',{
attachfiles : new_upfiles
});
}
});
$('[data-plugin="ui-sortable"]').disableSelection();
// 순서변경 내역 저장
$('.dd').on('change', function() {
var attachfiles=$('input[name="attachfiles[]"]').map(function(){return $(this).val()}).get();
var new_upfiles='';
if(attachfiles){
for(var i=0;i<attachfiles.length;i++) {
new_upfiles+=attachfiles[i];
}
}
$.post(rooturl+'/?r='+raccount+'&m=mediaset&a=modifygid',{
attachfiles : new_upfiles
});
});
});
</script>

View File

@@ -0,0 +1,40 @@
<!-- 첨부 사진 메타정보 수정 -->
<div class="modal fade rb-modal-attach-meta" id="modal-attach-photo-meta" tabindex="-1" role="dialog" aria-labelledby="">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id=""><i class="fa fa-camera-retro"></i> 사진 정보수정</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
<div class="row">
<!-- data-role="img-preview" src="_s 이미지" data-origin="원본 이미지" 넣는다. -->
<div class="col-md-4">
<p><img class="img-thumbnail" src="" alt="" data-role="img-preview" data-origin=""></p>
</div>
<div class="col-md-8">
<div class="form-group">
<label for="file-caption" class="control-label">캡션:</label>
<textarea class="form-control" data-role="filecaption" rows="5"></textarea>
</div>
<div class="form-group">
<label for="file-name" class="control-label">파일명:</label>
<div class="input-group">
<input type="text" class="form-control" data-role="filename" name="filename">
<div class="input-group-append">
<span class="input-group-text" data-role="fileext">확장자</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal" data-attach-act="cancel" data-target="#modal-attach-photo-meta" data-role="eventHandler" data-id="">취소하기</button>
<button type="button" class="btn btn-primary" data-attach-act="save" data-target="#modal-attach-photo-meta" data-role="eventHandler" data-id="">저장하기</button>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1 @@
부트스트랩 포토갤러리형

View File

@@ -0,0 +1,14 @@
# 부트스트랩4 파일 업로드 테마
부트스트랩
## 주요기능
- 사진,파일 업로드
- 첨부물 메타정보 등록
- 첨부목록 숨김처리
- 대표이미지 지정
## 요구사항
- `widgets/_default/attach` 위젯 필요
- `/plugins/jquery-form/4.2.2/jquery.form.min.js` 플러그인 필요

View File

@@ -0,0 +1,5 @@
<?php
$d['theme']['hidden_photo'] = "0"; // 이미지 추가시 사진 숨김여부 기본값 (숨김=1/보임=0)
$d['theme']['allowedTypes'] = ""; // 업로드 가능한 파일 확장자. (명시하지 않으면 파일 확장자 필터링하지 않음.)
$d['theme']['multiple'] = "1"; // 멀티 업로드 (허용=1/비허용=0)
?>

View File

@@ -0,0 +1,90 @@
<?php include $g['dir_attach_theme'].'/modals.php'; // 모달 페이지 인클루드 ?>
<?php getImport('jquery-form','jquery.form.min','4.2.2','js'); ?>
<script>
var inputId='attach-file-input'; // 실제 작옹하는 input 엘리먼트 id 값을 옵션으로 지정을 해준다. (커스텀 버튼으로 click 이벤트 바인딩)
var attach_file_saveDir = '<?php echo $g['path_file'].$parent_module?>/';// 파일 업로드 폴더
var attach_module_theme = '<?php echo $attach_module_theme?>';// attach 모듈 테마
var uploadElement = $('#attach-files');
var wysiwyg = '<?php echo $wdgvar['wysiwyg'] ?>'
$(document).ready(function() {
var uploadObj = uploadElement.RbUploadFile({
<?php if ($d['theme']['allowedTypes']): ?>
allowedTypes:"<?php echo $d['theme']['allowedTypes'] ?>",// 업로드 가능한 파일 확장자. 여기에 명시하지 않으면 파일 확장자 필터링하지 않음.
<?php endif; ?>
fileName: "files", // <input type="file" name=""> 의 name 값 --> php 에서 파일처리할 때 사용됨.
multiple: <?php echo $d['theme']['multiple']?'true':'false' ?>, // 멀티업로드를 할 경우 true 로 해준다.
dragDrop:true,
uploadStr:"<i class='fa fa-folder-o fa-fw'></i> 파일찾기", // 파일첨부 버튼
maxFileCount: <?php echo $d['mediaset']['maxnum_file'] ?>, // 1회 첨부파일 갯수
maxFileSize: <?php echo $d['mediaset']['maxsize_file'] ?>, // 1회 첨부파일 용량
inputId:inputId, // 실제 작옹하는 input 엘리먼트 id 값을 옵션으로 지정을 해준다. (커스텀 버튼으로 click 이벤트 바인딩)
formData: {"saveDir":attach_file_saveDir,"theme":attach_module_theme,"wysiwyg":wysiwyg}, // 추가 데이타 세팅
onSubmit:function(files){
console.log('모든 파일이 업로드가 시작되었습니다.')
uploadElement.isLoading({
text: "<i class='fa fa-spinner fa-spin'></i> 업로드중...",
position: 'overlay'
});
},
onSuccess:function(files,data,xhr,pd){
console.log('파일이 업로드 되었습니다.')
uploadElement.isLoading("hide")
}
});
// main.js 기본값 세팅
var attach_settings={
module : 'mediaset',
theme : attach_module_theme,
handler_photo : '<?php echo $attach_handler_photo?>',
handler_file : '<?php echo $attach_handler_file?>',
handler_getModalList : '<?php echo $attach_handler_getModalList?>',
listModal : '#modal-attach'
}
uploadElement.RbAttachTheme(attach_settings);
});
/*
클립보드 기능 초기화 : clipboard.js 플러그인 참조
data-clipboard-text="" 값이 복사된다. data-feedback-msg="" 값이 메세지로 출력
*/
var clipboard = new ClipboardJS('[data-attach-act="clipboard"]');
$('[data-attach-act="insert"]').tooltip({
trigger: 'hover',
title : '본문삽입'
});
$('[data-attach-act="clipboard"]').tooltip({
trigger: 'hover',
title : '클립보드 복사'
});
$('body').on('click','[data-attach-act="insert"]',function(){
$(this).attr('data-original-title', '삽입완료')
$(this).tooltip('show');
$(this).attr('data-original-title', '본문삽입')
});
$('body').on('click','[data-attach-act="clipboard"]',function(){
$(this).attr('data-original-title', '복사완료')
$(this).tooltip('show');
$(this).attr('data-original-title', '클립보드 복사')
});
// 모달 활성화시에 입력필드 포커스 처리
$('#modal-attach-photo-meta').on('shown.bs.modal', function (event) {
var modal = $(this)
modal.find('[data-role="filecaption"]').focus()
})
$('#modal-attach-file-meta').on('shown.bs.modal', function (event) {
var modal = $(this)
modal.find('[data-role="filename"]').focus()
})
</script>

View File

@@ -0,0 +1,125 @@
<?php
// 위젯 설정값 세팅
$parent_module=$d['attach']['parent_module']; // 첨부파일 사용하는 모듈
$parent_data=$d['attach']['parent_data']; // 해당 포스트 데이타 (수정시 필요)
$attach_module_theme=$d['attach']['theme']; // 첨부파일 테마
$attach_mode=$d['attach']['mod']; // list, main...
$attach_handler_file=$d['attach']['handler_file']; //파일첨부 실행 엘리먼트 button or 기타 엘리먼트 data-role="" 형태로 하는 것을 권고
$attach_handler_photo=$d['attach']['handler_photo']; // 사진첨부 실행 엘리먼트 button or 기타 엘리먼트 data-role="" 형태로 하는 것을 권고
$attach_handler_getModalList=$d['attach']['handler_getModalList']; // 첨부파일 리스트 호출 handler
$attach_object_type=$d['attach']['object_type']; // 첨부 대상에 따른 분류 : photo, file, link, video....
$editor_type=$d['attach']['editor_type']; // 에디터 타입 : html,markdown
require_once $g['dir_attach_theme'].'/main.func.php'; // 함수 인클루드
require_once $g['dir_attach_theme'].'/_var.php'; // 테마변수 인클루드
require_once $g['path_module'].'mediaset/var/var.php'; //모듈 공통변수 인클루드
?>
<!-- 클립보드 : clipboard.js : https://github.com/zenorocha/clipboard.js-->
<?php getImport('clipboard','clipboard.min','2.0.4','js') ?>
<script src="<?php echo $g['url_attach_theme']?>/js/fileuploader.js"></script>
<script src="<?php echo $g['url_attach_theme']?>/main.js"></script>
<!-- nestable : https://github.com/dbushell/Nestable -->
<?php getImport('nestable','jquery.nestable',false,'js') ?>
<style media="screen">
.ajax-upload-dragdrop {
margin-bottom: 20px;
padding: 30px;
border: 2px dashed #d1d1d1;
color: #999;
text-align: center;
vertical-align: middle;
}
.ajax-upload-dragdrop.state-hover {
box-shadow: 0 0 2px rgba(0,0,0,0.3), 0 0 4px rgba(26,170,85,0.4);
border: 1px solid #007bff;
}
.ajax-upload-dragdrop.state-hover::before {
display: inline-block;
font: normal normal normal 20px/1 FontAwesome;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
content: '\f093';
font-size: 2.5em;
text-align: center;
}
.ajax-upload-dragdrop.state-hover .ajax-file-upload,
.ajax-upload-dragdrop.state-hover span {
opacity: 0;
display: none
}
::-webkit-file-upload-button { cursor:pointer; }
/**
* Nestable
*/
.dd { }
.dd-list { display: block; position: relative; list-style: none; }
.dd-list .dd-list { }
.dd-collapsed .dd-list { display: none; }
.dd-item,
.dd-empty,
.dd-placeholder { }
.dd-handle {
position: absolute;
margin: 0;
left: 0;
top: 0;
bottom:0;
cursor: pointer;
width: 25px;
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
background-color: #eff3f6;
background-image: linear-gradient(-180deg, #fafbfc 0%, #eff3f6 90%);
background-repeat: repeat-x;
background-position: -1px -1px;
background-size: 110% 110%;
border-right: 1px solid rgba(27,31,35,0.1);
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.dd-handle:hover {
background-color: #e6ebf1;
background-image: linear-gradient(-180deg, #f0f3f6 0%, #e6ebf1 90%);
background-position: -.5em;
}
.dd-handle:before {
display: block;
position: absolute;
left: 0;
top: 50%;
margin-top: -7px;
width: 100%;
text-align: center;
text-indent: 0;
color: #494949;
font-size: 14px;
font-weight: normal;
}
.dd-placeholder,
.dd-empty { margin: 5px 0; padding: 0; min-height: 30px; background: #f2fbff; border: 1px dashed #b6bcbf; box-sizing: border-box; -moz-box-sizing: border-box; }
.dd-empty { border: 1px dashed #bbb; min-height: 100px; background-color: #e5e5e5;
background-image: -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
-webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
background-image: -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
-moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
background-size: 60px 60px;
background-position: 0 0, 30px 30px;
}
.dd-dragel { position: absolute; pointer-events: none; z-index: 9999; }
.dd-dragel > .dd-item .dd-handle { margin-top: 0; }
.dd-dragel .dd-handle {
-webkit-box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1);
box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1);
}
</style>

View File

@@ -0,0 +1,902 @@
/*!
* jQuery Upload File Plugin
* version: 4.0.9
* @requires jQuery v1.5 or later & form plugin
* Copyright (c) 2013 Ravishanker Kusuma
* http://hayageek.com/
* https://github.com/hayageek/jquery-upload-file
*/
(function ($) {
var feature = {};
feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
feature.formdata = window.FormData !== undefined;
$.fn.RbUploadFile = function (options) {
// This is the easiest way to have default options.
var s = $.extend({
// These are the defaults.
url: rooturl+'/?r='+raccount+'&m=mediaset&a=upload', // attach 모듈 upload 액션 파일 지정
method: "POST",
enctype: "multipart/form-data",
returnType: null,
allowDuplicates: true,
duplicateStrict: false,
allowedTypes: "*",
//For list of acceptFiles
// http://stackoverflow.com/questions/11832930/html-input-file-accept-attribute-file-type-csv
acceptFiles: "*",
fileName: "file",
formData: false,
dynamicFormData:false,
maxFileSize: -1,
maxFileCount: -1,
multiple: true,
dragDrop: false, // 수정 dragDrop 사용하지 않음
autoSubmit: true,
showCancel: true,
showAbort: true,
showDone: false,
showDelete: false,
showError: true,
showStatusAfterSuccess: false, // 수정
showStatusAfterError: true,
showFileCounter: false, // 수정
fileCounterStyle: "). ",
showFileSize: true,
showProgress: true,
nestedForms: true,
showDownload: false,
onLoad: function (obj) {},
onSelect: function (files) {
return true;
},
onSubmit: function (files, xhr) {},
onSuccess: function (files, response, xhr, pd) {},
onError: function (files, status, message, pd) {},
onCancel: function (files, pd) {},
onAbort: function (files, pd) {},
downloadCallback: false,
deleteCallback: false,
afterUploadAll: false,
serialize:true,
sequential:false,
sequentialCount:2,
customProgressBar: false,
abortButtonClass: "ajax-file-upload-abort content-padded text-danger",
cancelButtonClass: "ajax-file-upload-cancel content-padded text-danger",
dragDropContainerClass: "ajax-upload-dragdrop",
dragDropHoverClass: "state-hover",
errorClass: "alert alert-danger",
uploadButtonClass: "ajax-file-upload",
dragDropStr: "<span class='align-middle'>또는 여기에 파일 놓기</span>",
uploadStr:"Upload",
uploadStr:"<i class='fa fa fa-upload fa-fw'></i> 파일첨부", // 첨부파일 버튼을 커스텀할 수 있도록 숨긴다.
abortStr: "실패",
cancelStr: "취소",
deletelStr: "삭제",
doneStr: "완료",
multiDragErrorStr: "드래그앤 드랍이 허용되지 않습니다.",
extErrorStr: "허용 된 확장가 아닙니다.: ",
duplicateErrorStr: "이미 존재하는 파일 입니다.",
sizeErrorStr: "허용 된 최대 크기를 초과합니다.: ",
uploadErrorStr: "업로드가 허용되지 않습니다.",
maxFileCountErrorStr: " 최대 허용 파일 수가 초과 되었습니다.:",
downloadStr: "Download",
customErrorKeyStr: "content-padded text-danger",
showQueueDiv: false,
statusBarWidth: 400,
// dragdropWidth: 400,
showPreview: false,
previewHeight: "auto",
previewWidth: "100%",
extraHTML:false,
uploadQueueOrder:'top'
}, options);
this.fileCounter = 1;
this.selectedFiles = 0;
var formGroup = "ajax-file-upload-" + (new Date().getTime());
this.formGroup = formGroup;
this.errorLog = $("<div></div>"); //Writing errors
this.responses = [];
this.existingFileNames = [];
if(!feature.formdata) //check drag drop enabled.
{
s.dragDrop = false;
}
if(!feature.formdata) {
s.multiple = false;
}
$(this).html("");
var obj = this;
var uploadLabel = $('<div class="btn btn-link muted-link">' + s.uploadStr + '</div>');
$(uploadLabel).addClass(s.uploadButtonClass);
// wait form ajax Form plugin and initialize
(function checkAjaxFormLoaded() {
if($.fn.ajaxForm) {
if(s.dragDrop) {
var dragDrop = $('<div class="' + s.dragDropContainerClass + '" style="vertical-align:top;"></div>').width(s.dragdropWidth);
$(obj).append(dragDrop);
$(dragDrop).append(uploadLabel);
$(dragDrop).append($(s.dragDropStr));
setDragDropHandlers(obj, s, dragDrop);
} else {
$(obj).append(uploadLabel);
}
$(obj).append(obj.errorLog);
// 미리보기 div 출력 삭제 - 이 부분은 해당 페이지에서 커스텀으로 처리한다.
// if(s.showQueueDiv)
// obj.container =$("#"+s.showQueueDiv);
// else
// obj.container = $("<div class='ajax-file-upload-container'></div>").insertAfter($(obj));
s.onLoad.call(this, obj);
createCustomInputFile(obj, formGroup, s, uploadLabel);
} else window.setTimeout(checkAjaxFormLoaded, 10);
})();
this.startUpload = function () {
$("form").each(function(i,items)
{
if($(this).hasClass(obj.formGroup))
{
mainQ.push($(this));
}
});
if(mainQ.length >= 1 )
submitPendingUploads();
}
this.getFileCount = function () {
return obj.selectedFiles;
}
this.stopUpload = function () {
$("." + s.abortButtonClass).each(function (i, items) {
if($(this).hasClass(obj.formGroup)) $(this).click();
});
$("." + s.cancelButtonClass).each(function (i, items) {
if($(this).hasClass(obj.formGroup)) $(this).click();
});
}
this.cancelAll = function () {
$("." + s.cancelButtonClass).each(function (i, items) {
if($(this).hasClass(obj.formGroup)) $(this).click();
});
}
this.update = function (settings) {
//update new settings
s = $.extend(s, settings);
}
this.reset = function (removeStatusBars) {
obj.fileCounter = 1;
obj.selectedFiles = 0;
obj.errorLog.html("");
//remove all the status bars.
if(removeStatusBars != false)
{
obj.container.html("");
}
}
this.remove = function()
{
obj.container.html("");
$(obj).remove();
}
//This is for showing Old files to user.
this.createProgress = function (filename,filepath,filesize) {
var pd = new createProgressDiv(this, s);
pd.progressDiv.show();
pd.progressbar.width('100%');
var fileNameStr = "";
if(s.showFileCounter)
fileNameStr = obj.fileCounter + s.fileCounterStyle + filename;
else fileNameStr = filename;
if(s.showFileSize)
fileNameStr += " ("+getSizeStr(filesize)+")";
pd.filename.html(fileNameStr);
obj.fileCounter++;
obj.selectedFiles++;
if(s.showPreview)
{
pd.preview.attr('src',filepath);
pd.preview.show();
}
if(s.showDownload) {
pd.download.show();
pd.download.click(function () {
if(s.downloadCallback) s.downloadCallback.call(obj, [filename]);
});
}
if(s.showDelete)
{
pd.del.show();
pd.del.click(function () {
pd.statusbar.hide().remove();
var arr = [filename];
if(s.deleteCallback) s.deleteCallback.call(this, arr, pd);
obj.selectedFiles -= 1;
updateFileCounter(s, obj);
});
}
return pd;
}
this.getResponses = function () {
return this.responses;
}
var mainQ=[];
var progressQ=[]
var running = false;
function submitPendingUploads() {
if(running) return;
running = true;
(function checkPendingForms() {
//if not sequential upload all files
if(!s.sequential) s.sequentialCount=99999;
if(mainQ.length == 0 && progressQ.length == 0)
{
if(s.afterUploadAll) s.afterUploadAll(obj);
running= false;
}
else
{
if( progressQ.length < s.sequentialCount)
{
var frm = mainQ.shift();
if(frm != undefined)
{
progressQ.push(frm);
frm.submit();
}
}
window.setTimeout(checkPendingForms, 100);
}
})();
}
function setDragDropHandlers(obj, s, ddObj) {
ddObj.on('dragenter', function (e) {
e.stopPropagation();
e.preventDefault();
$(this).addClass(s.dragDropHoverClass);
});
ddObj.on('dragover', function (e) {
e.stopPropagation();
e.preventDefault();
var that = $(this);
if (that.hasClass(s.dragDropContainerClass) && !that.hasClass(s.dragDropHoverClass)) {
that.addClass(s.dragDropHoverClass);
}
});
ddObj.on('drop', function (e) {
e.preventDefault();
$(this).removeClass(s.dragDropHoverClass);
obj.errorLog.html("");
var files = e.originalEvent.dataTransfer.files;
if(!s.multiple && files.length > 1) {
if(s.showError) $("<div class='" + s.errorClass + "'>" + s.multiDragErrorStr + "</div>").appendTo(obj.errorLog);
return;
}
if(s.onSelect(files) == false) return;
serializeAndUploadFiles(s, obj, files);
});
ddObj.on('dragleave', function (e) {
$(this).removeClass(s.dragDropHoverClass);
});
$(document).on('dragenter', function (e) {
e.stopPropagation();
e.preventDefault();
});
$(document).on('dragover', function (e) {
e.stopPropagation();
e.preventDefault();
var that = $(this);
if (!that.hasClass(s.dragDropContainerClass)) {
that.removeClass(s.dragDropHoverClass);
}
});
$(document).on('drop', function (e) {
e.stopPropagation();
e.preventDefault();
$(this).removeClass(s.dragDropHoverClass);
});
}
function getSizeStr(size) {
var sizeStr = "";
var sizeKB = size / 1024;
if(parseInt(sizeKB) > 1024) {
var sizeMB = sizeKB / 1024;
sizeStr = sizeMB.toFixed(2) + " MB";
} else {
sizeStr = sizeKB.toFixed(2) + " KB";
}
return sizeStr;
}
function serializeData(extraData) {
var serialized = [];
if(jQuery.type(extraData) == "string") {
serialized = extraData.split('&');
} else {
serialized = $.param(extraData).split('&');
}
var len = serialized.length;
var result = [];
var i, part;
for(i = 0; i < len; i++) {
serialized[i] = serialized[i].replace(/\+/g, ' ');
part = serialized[i].split('=');
result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]);
}
return result;
}
function noserializeAndUploadFiles(s, obj, files) {
var ts = s;
var fd = new FormData();
var fileArray = [];
var fileName = s.fileName.replace("[]", "");
var fileListStr="";
for (var i = 0; i < files.length; i++) {
if (!isFileTypeAllowed(obj, s, files[i].name)) {
if (s.showError) $("<div><font color='red'><b>" + files[i].name + "</b> " + s.extErrorStr + s.allowedTypes + "</font></div>").appendTo(obj.errorLog);
continue;
}
if (s.maxFileSize != -1 && files[i].size > s.maxFileSize) {
if (s.showError) $("<div><font color='red'><b>" + files[i].name + "</b> " + s.sizeErrorStr + getSizeStr(s.maxFileSize) + "</font></div>").appendTo(obj.errorLog);
continue;
}
fd.append(fileName+"[]", files[i]);
fileArray.push(files[i].name);
fileListStr += obj.fileCounter + "). " + files[i].name+"<br>";
obj.fileCounter++;
}
if(fileArray.length ==0 ) return;
var extraData = s.formData;
if (extraData) {
var sData = serializeData(extraData);
for (var j = 0; j < sData.length; j++) {
if (sData[j]) {
fd.append(sData[j][0], sData[j][1]);
}
}
}
ts.fileData = fd;
var pd = new createProgressDiv(obj, s);
pd.filename.html(fileListStr);
var form = $("<form style='display:block; position:absolute;left: 150px;' class='" + obj.formGroup + "' method='" + s.method + "' action='" + s.url + "' enctype='" + s.enctype + "'></form>");
form.appendTo('body');
ajaxFormSubmit(form, ts, pd, fileArray, obj);
}
function serializeAndUploadFiles(s, obj, files) {
for(var i = 0; i < files.length; i++) {
if(!isFileTypeAllowed(obj, s, files[i].name)) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + files[i].name + "</b> " + s.extErrorStr + s.allowedTypes + "</div>").appendTo(obj.errorLog);
continue;
}
if(!s.allowDuplicates && isFileDuplicate(obj, files[i].name)) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + files[i].name + "</b> " + s.duplicateErrorStr + "</div>").appendTo(obj.errorLog);
continue;
}
if(s.maxFileSize != -1 && files[i].size > s.maxFileSize) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + files[i].name + "</b> " + s.sizeErrorStr + getSizeStr(s.maxFileSize) + "</div>").appendTo(
obj.errorLog);
continue;
}
if(s.maxFileCount != -1 && obj.selectedFiles >= s.maxFileCount) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + files[i].name + "</b> " + s.maxFileCountErrorStr + s.maxFileCount + "개까지 허용됨</div>").appendTo(
obj.errorLog);
continue;
}
obj.selectedFiles++;
obj.existingFileNames.push(files[i].name);
var ts = s;
var fd = new FormData();
var fileName = s.fileName.replace("[]", "");
fd.append(fileName, files[i]);
var extraData = s.formData;
if(extraData) {
var sData = serializeData(extraData);
for(var j = 0; j < sData.length; j++) {
if(sData[j]) {
fd.append(sData[j][0], sData[j][1]);
}
}
}
ts.fileData = fd;
var pd = new createProgressDiv(obj, s);
var fileNameStr = "";
if(s.showFileCounter) fileNameStr = obj.fileCounter + s.fileCounterStyle + files[i].name
else fileNameStr = files[i].name;
if(s.showFileSize)
fileNameStr += " ("+getSizeStr(files[i].size)+")";
pd.filename.html(fileNameStr);
var form = $("<form style='display:block; position:absolute;left: 150px;' class='" + obj.formGroup + "' method='" + s.method + "' action='" +
s.url + "' enctype='" + s.enctype + "'></form>");
form.appendTo('body');
var fileArray = [];
fileArray.push(files[i].name);
ajaxFormSubmit(form, ts, pd, fileArray, obj, files[i]);
obj.fileCounter++;
}
}
function isFileTypeAllowed(obj, s, fileName) {
var fileExtensions = s.allowedTypes.toLowerCase().split(/[\s,]+/g);
var ext = fileName.split('.').pop().toLowerCase();
if(s.allowedTypes != "*" && jQuery.inArray(ext, fileExtensions) < 0) {
return false;
}
return true;
}
function isFileDuplicate(obj, filename) {
var duplicate = false;
if (obj.existingFileNames.length) {
for (var x=0; x<obj.existingFileNames.length; x++) {
if (obj.existingFileNames[x] == filename
|| s.duplicateStrict && obj.existingFileNames[x].toLowerCase() == filename.toLowerCase()
) {
duplicate = true;
}
}
}
return duplicate;
}
function removeExistingFileName(obj, fileArr) {
if (obj.existingFileNames.length) {
for (var x=0; x<fileArr.length; x++) {
var pos = obj.existingFileNames.indexOf(fileArr[x]);
if (pos != -1) {
obj.existingFileNames.splice(pos, 1);
}
}
}
}
function getSrcToPreview(file, obj) {
if(file) {
obj.show();
var reader = new FileReader();
reader.onload = function (e) {
obj.attr('src', e.target.result);
};
reader.readAsDataURL(file);
}
}
function updateFileCounter(s, obj) {
if(s.showFileCounter) {
var count = $(obj.container).find(".ajax-file-upload-filename").length;
obj.fileCounter = count + 1;
$(obj.container).find(".ajax-file-upload-filename").each(function (i, items) {
var arr = $(this).html().split(s.fileCounterStyle);
var fileNum = parseInt(arr[0]) - 1; //decrement;
var name = count + s.fileCounterStyle + arr[1];
$(this).html(name);
count--;
});
}
}
// input 폼 세팅함수
function createCustomInputFile (obj, group, s, uploadLabel) {
//var fileUploadId = "ajax-upload-id-" + (new Date().getTime());
var fileUploadId=s.inputId; // 옵션에서 지정한 id 값으로 세팅한다.
var form = $("<form method='" + s.method + "' action='" + s.url + "' enctype='" + s.enctype + "'></form>");
var fileInputStr = "<input type='file' id='" + fileUploadId + "' name='" + s.fileName + "' accept='" + s.acceptFiles + "'/>";
if(s.multiple) {
if(s.fileName.indexOf("[]") != s.fileName.length - 2) // if it does not endwith
{
s.fileName += "[]";
}
fileInputStr = "<input type='file' id='" + fileUploadId + "' name='" + s.fileName + "' accept='" + s.acceptFiles + "' multiple/>";
}
var fileInput = $(fileInputStr).appendTo(form);
//fileInput.change(function () {
$(form).on('change','#'+fileUploadId,function(){
console.log(fileUploadId);
obj.errorLog.html("");
var fileExtensions = s.allowedTypes.toLowerCase().split(",");
var fileArray = [];
if(this.files) //support reading files
{
for(i = 0; i < this.files.length; i++) {
fileArray.push(this.files[i].name);
}
if(s.onSelect(this.files) == false) return;
} else {
var filenameStr = $(this).val();
var flist = [];
fileArray.push(filenameStr);
if(!isFileTypeAllowed(obj, s, filenameStr)) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + filenameStr + "</b> " + s.extErrorStr + s.allowedTypes + "</div>").appendTo(
obj.errorLog);
return;
}
//fallback for browser without FileAPI
flist.push({
name: filenameStr,
size: 'NA'
});
if(s.onSelect(flist) == false) return;
}
updateFileCounter(s, obj);
uploadLabel.unbind("click");
form.hide();
createCustomInputFile(obj, group, s, uploadLabel);
form.addClass(group);
if(s.serialize && feature.fileapi && feature.formdata) //use HTML5 support and split file submission
{
form.removeClass(group); //Stop Submitting when.
var files = this.files;
form.remove();
serializeAndUploadFiles(s, obj, files);
} else {
var fileList = "";
for(var i = 0; i < fileArray.length; i++) {
if(s.showFileCounter) fileList += obj.fileCounter + s.fileCounterStyle + fileArray[i] + "<br>";
else fileList += fileArray[i] + "<br>";;
obj.fileCounter++;
}
if(s.maxFileCount != -1 && (obj.selectedFiles + fileArray.length) > s.maxFileCount) {
if(s.showError) $("<div class='" + s.errorClass + "'><b>" + fileList + "</b> " + s.maxFileCountErrorStr + s.maxFileCount + "</div>").appendTo(
obj.errorLog);
return;
}
obj.selectedFiles += fileArray.length;
var pd = new createProgressDiv(obj, s);
pd.filename.html(fileList);
ajaxFormSubmit(form, s, pd, fileArray, obj, null);
}
});
if(s.nestedForms) {
form.css({
'margin': 0,
'padding': 0
});
uploadLabel.css({
position: 'relative',
overflow: 'hidden',
cursor: 'pointer'
});
fileInput.css({
position: 'absolute',
'cursor': 'pointer',
'top': '0px',
'width': '100%',
'height': '100%',
'left': '0px',
'z-index': '100',
'opacity': '0.0',
'filter': 'alpha(opacity=0)',
'-ms-filter': "alpha(opacity=0)",
'-khtml-opacity': '0.0',
'-moz-opacity': '0.0'
});
form.appendTo(uploadLabel);
} else {
form.appendTo($('body'));
form.css({
margin: 0,
padding: 0,
display: 'block',
position: 'absolute',
left: '-250px'
});
if(navigator.appVersion.indexOf("MSIE ") != -1) //IE Browser
{
uploadLabel.attr('for', fileUploadId);
} else {
uploadLabel.click(function () {
fileInput.click();
});
}
}
}
function defaultProgressBar(obj,s)
{
this.statusbar = $("<div class='ajax-file-upload-statusbar'></div>").width(s.statusBarWidth);
this.preview = $("<img class='ajax-file-upload-preview' />").width(s.previewWidth).height(s.previewHeight).appendTo(this.statusbar).hide();
this.filename = $("<div class='ajax-file-upload-filename'></div>").appendTo(this.statusbar);
this.progressDiv = $("<div class='ajax-file-upload-progress'>").appendTo(this.statusbar).hide();
this.progressbar = $("<div class='ajax-file-upload-bar'></div>").appendTo(this.progressDiv);
this.abort = $("<div>" + s.abortStr + "</div>").appendTo(this.statusbar).hide();
this.cancel = $("<div>" + s.cancelStr + "</div>").appendTo(this.statusbar).hide();
this.done = $("<div>" + s.doneStr + "</div>").appendTo(this.statusbar).hide();
this.download = $("<div>" + s.downloadStr + "</div>").appendTo(this.statusbar).hide();
this.del = $("<div>" + s.deletelStr + "</div>").appendTo(this.statusbar).hide();
this.abort.addClass("ajax-file-upload-red");
this.done.addClass("ajax-file-upload-green");
this.download.addClass("ajax-file-upload-green");
this.cancel.addClass("ajax-file-upload-red");
this.del.addClass("ajax-file-upload-red");
return this;
}
function createProgressDiv(obj, s) {
var bar = null;
if(s.customProgressBar)
bar = new s.customProgressBar(obj,s);
else
bar = new defaultProgressBar(obj,s);
bar.abort.addClass(obj.formGroup);
bar.abort.addClass(s.abortButtonClass);
bar.cancel.addClass(obj.formGroup);
bar.cancel.addClass(s.cancelButtonClass);
if(s.extraHTML)
bar.extraHTML = $("<div class='extrahtml'>"+s.extraHTML()+"</div>").insertAfter(bar.filename);
if(s.uploadQueueOrder == 'bottom')
$(obj.container).append(bar.statusbar);
else
$(obj.container).prepend(bar.statusbar);
return bar;
}
function ajaxFormSubmit(form, s, pd, fileArray, obj, file) {
var currentXHR = null;
var options = {
cache: false,
contentType: false,
processData: false,
forceSync: false,
type: s.method,
data: s.formData,
formData: s.fileData,
dataType: s.returnType,
beforeSubmit: function (formData, $form, options) {
if(s.onSubmit.call(this, fileArray) != false) {
if(s.dynamicFormData)
{
var sData = serializeData(s.dynamicFormData());
if(sData) {
for(var j = 0; j < sData.length; j++) {
if(sData[j]) {
if(s.fileData != undefined) options.formData.append(sData[j][0], sData[j][1]);
else options.data[sData[j][0]] = sData[j][1];
}
}
}
}
if(s.extraHTML)
{
$(pd.extraHTML).find("input,select,textarea").each(function(i,items)
{
if(s.fileData != undefined) options.formData.append($(this).attr('name'),$(this).val());
else options.data[$(this).attr('name')] = $(this).val();
});
}
return true;
}
pd.statusbar.append("<div class='" + s.errorClass + "'>" + s.uploadErrorStr + "</div>");
pd.cancel.show()
form.remove();
pd.cancel.click(function () {
mainQ.splice(mainQ.indexOf(form), 1);
removeExistingFileName(obj, fileArray);
pd.statusbar.remove();
s.onCancel.call(obj, fileArray, pd);
obj.selectedFiles -= fileArray.length; //reduce selected File count
updateFileCounter(s, obj);
});
return false;
},
beforeSend: function (xhr, o) {
pd.progressDiv.show();
pd.cancel.hide();
pd.done.hide();
if(s.showAbort) {
pd.abort.show();
pd.abort.click(function () {
removeExistingFileName(obj, fileArray);
xhr.abort();
obj.selectedFiles -= fileArray.length; //reduce selected File count
s.onAbort.call(obj, fileArray, pd);
});
}
if(!feature.formdata) //For iframe based push
{
pd.progressbar.width('5%');
} else pd.progressbar.width('1%'); //Fix for small files
},
uploadProgress: function (event, position, total, percentComplete) {
//Fix for smaller file uploads in MAC
if(percentComplete > 98) percentComplete = 98;
var percentVal = percentComplete + '%';
if(percentComplete > 1) pd.progressbar.width(percentVal)
if(s.showProgress) {
pd.progressbar.html(percentVal);
pd.progressbar.css('text-align', 'center');
}
},
success: function (data, message, xhr) {
pd.cancel.remove();
progressQ.pop();
//For custom errors.
if(s.returnType == "json" && $.type(data) == "object" && data.hasOwnProperty(s.customErrorKeyStr)) {
pd.abort.hide();
var msg = data[s.customErrorKeyStr];
s.onError.call(this, fileArray, 200, msg, pd);
if(s.showStatusAfterError) {
pd.progressDiv.hide();
pd.statusbar.append("<span class='" + s.errorClass + "'>ERROR: " + msg + "</span>");
} else {
pd.statusbar.hide();
pd.statusbar.remove();
}
obj.selectedFiles -= fileArray.length; //reduce selected File count
form.remove();
return;
}
obj.responses.push(data);
pd.progressbar.width('100%')
if(s.showProgress) {
pd.progressbar.html('100%');
pd.progressbar.css('text-align', 'center');
}
pd.abort.hide();
s.onSuccess.call(this, fileArray, data, xhr, pd); // 해당 페이지에서 업로드 성공 후 추가 액션 가능
// 미리보기 출력
var result=$.parseJSON(data); // a.upload.php 에서 결과값을 preview & type 으로 구분하여 json 으로 보내준다.
var error=result.error; // 업로드 에러
var preview_default=result.preview_default; // 기본 리스트
var preview_modal=result.preview_modal; // 모달 리스트 (소스복사외 다른 메뉴는 노출하지 않는다.)
var attachType=result.type; // 해당 attachHandler 의 data-type 값 photo, file, map, link, people....
var previewBox_default=$('[data-role="attach-preview-'+attachType+'"]'); // type 에 따라서 미리보기 container 를 분리해서 지정한다.
var previewBox_modal=$('[data-role="modal-attach-preview-'+attachType+'"]'); // type 에 따라서 미리보기 container 를 분리해서 지정한다.
$(preview_default).prependTo(previewBox_default);// 업로드 성공후 미리보기 출력되는 부분 처리
$(preview_modal).prependTo(previewBox_modal);// 업로드 성공후 모달 미리보기 출력되는 부분 처리
if (error) $.notify({message: error},{type: "danger"});
if(s.showStatusAfterSuccess) {
if(s.showDone) {
pd.done.show();
pd.done.click(function () {
pd.statusbar.hide("slow");
pd.statusbar.remove();
});
} else {
pd.done.hide();
}
if(s.showDelete) {
pd.del.show();
pd.del.click(function () {
removeExistingFileName(obj, fileArray);
pd.statusbar.hide().remove();
if(s.deleteCallback) s.deleteCallback.call(this, data, pd);
obj.selectedFiles -= fileArray.length; //reduce selected File count
updateFileCounter(s, obj);
});
} else {
pd.del.hide();
}
} else {
pd.statusbar.hide("slow");
pd.statusbar.remove();
}
if(s.showDownload) {
pd.download.show();
pd.download.click(function () {
if(s.downloadCallback) s.downloadCallback(data);
});
}
form.remove();
},
error: function (xhr, status, errMsg) {
pd.cancel.remove();
progressQ.pop();
pd.abort.hide();
if(xhr.statusText == "abort") //we aborted it
{
pd.statusbar.hide("slow").remove();
updateFileCounter(s, obj);
} else {
s.onError.call(this, fileArray, status, errMsg, pd);
if(s.showStatusAfterError) {
pd.progressDiv.hide();
pd.statusbar.append("<span class='" + s.errorClass + "'>ERROR: " + errMsg + "</span>");
} else {
pd.statusbar.hide();
pd.statusbar.remove();
}
obj.selectedFiles -= fileArray.length; //reduce selected File count
}
form.remove();
}
};
if(s.showPreview && file != null) {
if(file.type.toLowerCase().split("/").shift() == "image") getSrcToPreview(file, pd.preview);
}
if(s.autoSubmit) {
form.ajaxForm(options);
mainQ.push(form);
submitPendingUploads();
} else {
if(s.showCancel) {
pd.cancel.show();
pd.cancel.click(function () {
mainQ.splice(mainQ.indexOf(form), 1);
removeExistingFileName(obj, fileArray);
form.remove();
pd.statusbar.remove();
s.onCancel.call(obj, fileArray, pd);
obj.selectedFiles -= fileArray.length; //reduce selected File count
updateFileCounter(s, obj);
});
}
form.ajaxForm(options);
}
}
return this;
}
}(jQuery));

View File

@@ -0,0 +1,288 @@
<?php
// 첨부파일 리스트 갯수 추출 함수
function getAttachNum($upload,$mod)
{
global $table;
$attach = getArrayString($upload);
$attach_file_num=0;// 첨부파일 수량
$hidden_file_num=0; // 숨김파일(다운로드 방지) 수량
foreach($attach['data'] as $val)
{
$U = getUidData($table['s_upload'],$val);
if($U['fileonly']==1) $attach_file_num++; // 전체 첨부파일 수량 증가
if($U['hidden']==1) $hidden_file_num++; // 숨김파일 수량 증가
}
$down_file_num=$attach_file_num-$hidden_file_num; // 다운로드 가능한 첨부파일
$result=array();
$result['modify']=$attach_file_num;
$result['view']=$down_file_num;
return $result[$mod];
}
// 첨부파일 리스트 추출 함수 (전체)
/*
$parent_data : 해당 포스트의 row 배열
$mod : upload or modal ==> 실제 업로드 모드 와 모달을 띄워서 본문에 삽입용도로 쓰거나
*/
function getAttachFileList($parent_data,$mod,$type,$wysiwyg)
{
global $table;
$upload=$parent_data['upload'];
$featured_img_uid=$parent_data['featured_img'];// 대표이미지 uid
$featured_video_uid=$parent_data['featured_video'];// 대표비디오 uid
$featured_audio_uid=$parent_data['featured_audio'];// 대표오디오 uid
if($type=='file') $sql='type=1';
else if($type=='photo') $sql='type=2';
else if($type=='audio') $sql='type=4';
else if($type=='video') $sql='type=5';
else if($type=='doc') $sql='type=6';
else if($type=='zip') $sql='type=7';
else if($type=='pdf') $sql='type=7';
else $sql='type=1';
$attach = getArrayString($upload);
$uid_q='(';
foreach($attach['data'] as $uid)
{
$uid_q.='uid='.$uid.' or ';
}
$uid_q=substr($uid_q,0,-4).')';
$sql=$sql.' and '.$uid_q;
$RCD=getDbArray($table['s_upload'],$sql,'*','gid','asc','',1);
$html='';
while($R=db_fetch_array($RCD)){
$U=getUidData($table['s_upload'],$R['uid']);
if($type=='file') $html.=getAttachFile($U,$mod,$featured_img_uid,$wysiwyg);
else if($type=='photo') $html.=getAttachFile($U,$mod,$featured_img_uid,$wysiwyg);
else if($type=='audio') $html.=getAttachAudio($U,$mod,$featured_audio_uid,$wysiwyg);
else if($type=='video') $html.=getAttachVideo($U,$mod,$featured_video_uid,$wysiwyg);
else if($type=='doc') $html.=getAttachFile($U,$mod,$featured_img_uid,$wysiwyg);
else if($type=='zip') $html.=getAttachFile($U,$mod,$featured_img_uid,$wysiwyg);
else if($type=='pdf') $html.=getAttachFile($U,$mod,$featured_img_uid,$wysiwyg);
else $html.=getAttachFile($U,$mod,$featured_img_uid,$wysiwyg);;
}
return $html;
}
// 첨부파일 리스트 추출 함수 (낱개)
function getAttachFile($R,$mod,$featured_img_uid,$wysiwyg)
{
global $g,$r;
$fileName=explode('.',$R['name']);
$file_name=$fileName[0]; // 파일명만 분리
if ($R['type']==2) {
$type='photo';
} elseif($R['type']==4) {
$type='audio';
} elseif($R['type']==5) {
$type='video';
} else {
$type='file';
}
if($type=='photo'){
$caption=$R['caption']?$R['caption']:$file_name;
$img_origin=$R['host'].'/'.$R['folder'].'/'.$R['tmpname'];
$thumb_list=getPreviewResize($R['src'],'s'); // 미리보기 사이즈 조정 (이미지 업로드시 썸네일을 만들 필요 없다.)
$thumb_modal=getPreviewResize($R['src'],'n'); // 정보수정 모달용 사이즈 조정 (이미지 업로드시 썸네일을 만들 필요 없다.)
$insert_text='<figure class="media"><img src="'.$R['src'].'"><figcaption>'.$caption.'</figcaption></figure>';
}else if($type=='file'){
$caption=$R['caption']?$R['caption']:$R['name'];
$src=$R['url'].$R['folder'].'/'.$R['name'];
$insert_text='['.$caption.']('.$g['url_root'].'/?r='.$r.'&m=mediaset&a=download&uid='.$R['uid'].')';
}
$html='';
$html.='
<li class="list-group-item dd-item" data-id="'.$R['uid'].'" style="background-color: transparent">
<div class="d-flex justify-content-between">';
if($R['type']==2){
$html.='
<div class="dd-handle fa fa-arrows" title="순서변경"></div>
<div class="media ml-3 mr-auto align-items-center text-truncate">
<a href="#" class="d-flex align-self-center mr-3 " data-attach-act="'.($wysiwyg?'insert':'').'" data-type="'.$type.'" data-origin="'.($R['type']==2?$img_origin:$src).'" data-caption="'.$caption.'" data-editor="'.$wysiwyg.'"><img class="border" src="'.$thumb_list.'" alt="'.$caption.'" style="width: 50px"></a>
<div class="media-body">';
$html.='<span class="badge badge-warning'.($R['uid']==$featured_img_uid?'':' d-none').'" data-role="attachList-label-featured" data-id="'.$R['uid'].'">대표</span> ';
$html.='<span class="badge badge-secondary'.(!$R['hidden']?' d-none':'').'" data-role="attachList-label-hidden-'.$R['uid'].'">숨김</span>';
$html.='
<a href="#" class="text-reset" data-role="attachList-list-name-'.$R['uid'].'" data-attach-act="insert" data-type="'.$type.'" data-origin="'.($R['type']==2?$img_origin:$src).'" data-caption="'.$caption.'" data-editor="'.$wysiwyg.'">'.$R['name'].'</a>
<small class="text-muted">'.getSizeFormat($R['size'],2).'</small>
</div>
</div>';
}else {
$html.='
<div class="dd-handle fa fa-arrows" title="순서변경"></div>
<div class="ml-3 mr-auto align-self-center">
<i class="fa fa-floppy-o fa-fw mr-1"></i>';
$html.='<span class="badge badge-secondary'.(!$R['hidden']?' d-none':'').'" data-role="attachList-label-hidden-'.$R['uid'].'">숨김</span>';
$html.='
<a href="#" class="list-group-item-text text-truncate text-reset" data-role="attachList-list-name-'.$R['uid'].'" data-attach-act="insert" data-type="'.$type.'" data-origin="'.($R['type']==2?$img_origin:$src).'" data-caption="'.$caption.'" data-editor="'.$wysiwyg.'">'.$R['name'].'</a>
<small class="text-muted">'.getSizeFormat($R['size'],2).'</small>
</div>';
}
if($mod=='upload') $html.='<input type="hidden" name="attachfiles[]" value="['.$R['uid'].']"/>';
$html.='<div style="margin-top:-5px;margin-right: -17px;"><div class="btn-group btn-group-sm">';
if($mod=='upload'){
$html.='
<button type="button" class="btn btn-link text-reset dropdown-toggle dropdown-toggle-split" data-toggle="dropdown">
<i class="fa fa-ellipsis-v" aria-hidden="true"></i>
</button>
<div class="dropdown-menu dropdown-menu-right">';
if($R['type']==2){
$html.='
<a class="dropdown-item" href="#" data-attach-act="featured-img" data-type="'.$type.'" data-id="'.$R['uid'].'">대표이미지 설정</a>';
}
$html.='
<a class="dropdown-item" href="#" data-toggle="modal" data-backdrop="false" data-target="#modal-attach-'.($R['type']==2?'photo':'file').'-meta" data-filename="'.$file_name.'" data-fileext="'.$R['ext'].'" data-caption="'.$caption.'" data-src="'.$thumb_modal.'" data-origin="'.$img_origin.'" data-attach-act="edit" data-id="'.$R['uid'].'" data-type="'.$type.'" data-role="attachList-menu-edit-'.$R['uid'].'">정보수정</a>
<a class="dropdown-item" href="#" data-attach-act="showhide" data-role="attachList-menu-showhide-'.$R['uid'].'" data-id="'.$R['uid'].'" data-content="'.($R['hidden']?'show':'hide').'" >'.($R['hidden']?'보이기':'숨기기').'</a>
<a class="dropdown-item" href="#" data-attach-act="delete" data-id="'.$R['uid'].'" data-role="attachList-menu-delete-'.$R['uid'].'" data-featured="" data-type="'.$type.'">삭제</a>
</div>';
}
$html.='</div></div></div>';
$html.='</li>';
return $html;
}
// 오디오파일 리스트 추출 함수 (낱개)
function getAttachAudio($R,$mod,$featured_audio_uid)
{
global $g,$r;
$fileName=explode('.',$R['name']);
$file_name=$fileName[0]; // 파일명만 분리
$caption=$R['caption']?$R['caption']:$file_name;
$html='';
$html.='
<li class="list-group-item d-flex justify-content-between align-items-center dd-item animated fadeInDown" data-id="'.$R['uid'].'" style="background-color: transparent">
<div class="dd-handle fa fa-arrows" title="순서변경"></div>';
$html.='<div class="ml-3 mr-auto w-100"><span class="badge badge-secondary'.($R['uid']==$featured_audio_uid?'':' d-none').'" data-role="attachList-label-featured" data-id="'.$R['uid'].'">대표</span> ';
$html.='<span class="badge badge-secondary'.(!$R['hidden']?' d-none':'').'" data-role="attachList-label-hidden-'.$R['uid'].'">숨김</span>';
$html.='
<audio controls class="align-middle mr-4"><source src="'.$R['url'].$R['folder'].'/'.$R['tmpname'].'" type="audio/mpeg"></audio>';
$html.='<span data-role="attachList-list-name-'.$R['uid'].'" >'.$R['name'].'</span>';
$html.='
<span class="badge badge-secondary">'.getSizeFormat($R['size'],2).'</span></div>';
$html.='
<span class="align-self-center">
<div class="btn-group btn-group-sm">';
if($mod=='upload') $html.='<input type="hidden" name="attachfiles[]" value="['.$R['uid'].']"/>';
$html.='
<button type="button" class="btn btn-light" data-attach-act="delete" data-id="'.$R['uid'].'" data-role="attachList-menu-delete-'.$R['uid'].'" data-featured="" data-type="audio">삭제</button>';
if($mod=='upload'){
$html.='
<button type="button" class="btn btn-light dropdown-toggle dropdown-toggle-split" data-toggle="dropdown">
<span class="sr-only">Toggle Dropdown</span>
</button>
<div class="dropdown-menu dropdown-menu-right">';
$html.='
<a class="dropdown-item" href="#" data-attach-act="featured-audio" data-type="'.$type.'" data-id="'.$R['uid'].'">대표오디오 설정</a>';
$html.='
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#modal-attach-file-meta" data-filename="'.$file_name.'" data-fileext="'.$R['ext'].'" data-caption="'.$caption.'" data-src="'.$thumb_modal.'" data-origin="'.$img_origin.'" data-attach-act="edit" data-id="'.$R['uid'].'" data-type="audio" data-role="attachList-menu-edit-'.$R['uid'].'">정보수정</a>
<a class="dropdown-item" href="#" data-attach-act="showhide" data-role="attachList-menu-showhide-'.$R['uid'].'" data-id="'.$R['uid'].'" data-content="'.($R['hidden']?'show':'hide').'" >'.($R['hidden']?'보이기':'숨기기').'</a>
<a class="dropdown-item" href="#" data-attach-act="delete" data-id="'.$R['uid'].'" data-role="attachList-menu-delete-'.$R['uid'].'" data-featured="" data-type="audio">삭제</a>
</div>';
}
$html.='
</div>
</span>
</li>';
return $html;
}
// 비디오파일 리스트 추출 함수 (낱개)
function getAttachVideo($R,$mod,$featured_video_uid)
{
global $g,$r;
$fileName=explode('.',$R['name']);
$file_name=$fileName[0]; // 파일명만 분리
$caption=$R['caption']?$R['caption']:$file_name;
$html='';
$html.='
<li class="list-group-item d-flex justify-content-between align-items-center dd-item animated fadeInDown" data-id="'.$R['uid'].'" style="background-color: transparent">
<div class="dd-handle fa fa-arrows" title="순서변경"></div>
<div class="ml-3 mr-auto w-100">';
$html.='<span class="badge badge-secondary'.($R['uid']==$featured_video_uid?'':' d-none').'" data-role="attachList-label-featured" data-id="'.$R['uid'].'">대표</span> ';
$html.='<span class="badge badge-secondary'.(!$R['hidden']?' d-none':'').'" data-role="attachList-label-hidden-'.$R['uid'].'">숨김</span>';
$html.='
<video width="320" height="240" controls class="align-middle mr-3"><source src="'.$R['url'].$R['folder'].'/'.$R['tmpname'].'" type="video/'.$R['ext'].'"></video>';
$html.='<span data-role="attachList-list-name-'.$R['uid'].'" >'.$R['name'].'</span>';
$html.='
<span class="badge badge-secondary">'.getSizeFormat($R['size'],2).'</span></div>';
$html.='<div class="align-self-center">
<div class="btn-group btn-group-sm">';
if($mod=='upload') $html.='<input type="hidden" name="attachfiles[]" value="['.$R['uid'].']"/>';
$html.='
<button type="button" class="btn btn-light" data-attach-act="delete" data-id="'.$R['uid'].'" data-role="attachList-menu-delete-'.$R['uid'].'" data-featured="" data-type="video">삭제</button>';
if($mod=='upload'){
$html.='
<button type="button" class="btn btn-light btn-sm dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<div class="dropdown-menu dropdown-menu-right">';
$html.='
<a class="dropdown-item" href="#" data-attach-act="featured-video" data-type="'.$type.'" data-id="'.$R['uid'].'">대표 비디오 설정</a>';
$html.='
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#modal-attach-file-meta" data-filename="'.$file_name.'" data-fileext="'.$R['ext'].'" data-caption="'.$caption.'" data-src="'.$thumb_modal.'" data-origin="'.$img_origin.'" data-attach-act="edit" data-id="'.$R['uid'].'" data-type="video" data-role="attachList-menu-edit-'.$R['uid'].'">정보수정</a>
<a class="dropdown-item" href="#" data-attach-act="showhide" data-role="attachList-menu-showhide-'.$R['uid'].'" data-id="'.$R['uid'].'" data-content="'.($R['hidden']?'show':'hide').'" >'.($R['hidden']?'보이기':'숨기기').'</a>
<a class="dropdown-item" href="#" data-attach-act="delete" data-id="'.$R['uid'].'" data-role="attachList-menu-delete-'.$R['uid'].'" data-featured="" data-type="video ">삭제</a>
</div>';
}
$html.='
</div>
</div>
</li>';
return $html;
}
// 삽입 이미지 uid 얻기 함수
function getInsertImgUid($upload)
{
global $table;
$u_arr = getArrayString($upload);
$Insert_arr=array();
$i=0;
foreach ($u_arr['data'] as $val) {
$U=getUidData($table['s_upload'],$val);
if(!$U['fileonly']) $Insert_arr[$i]=$val;
$i++;
}
$upfiles='';
// 중괄로로 재조립
foreach ($Insert_arr as $uid) {
$upfiles.='['.$uid.']';
}
return $upfiles;
}
?>

View File

@@ -0,0 +1,229 @@
/**
* Copyright (c) 2015 redblock inc.
* Author kiere@kismq.com
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*
* Version: 1.0.0
*/
(function ($) {
$.fn.RbAttachTheme= function (settings) {
var defaults = {};
var opts = jQuery.extend(defaults, settings);
var module=opts.module; // 모듈명
var theme=opts.theme; // 테마 패스
var handler_photo=opts.handler_photo; // 사진첨부 실행 엘리먼트
var handler_file=opts.handler_file; // 파일첨부 실행 엘리먼트
var handler_getModalList=opts.handler_getModalList; // 첨부리스트 모달로 호출하는 엘리먼트
var listModal=opts.listModal;
var loaderbox='<div style="height:50%;margin-top:40%;" id="modal-loader-default"><div class="spinner-wrap"><div class="spinner"><div class="bounce1"></div><div class="bounce2"></div><div class="bounce3"></div></div></div></div>';
// 부모 모듈에서 파일첨부 액션 실행하는 버튼 or 기타 엘리먼트 클릭시 첨부파일 input click 이벤트 바인딩
$(handler_file).click(function(e){
e.preventDefault();
$('#'+inputId).click();
});
// 부모 모듈에서 사진첨부 액션 실행하는 버튼 or 기타 엘리먼트 클릭시 첨부파일 input click 이벤트 바인딩
$(handler_photo).click(function(e){
e.preventDefault();
$('#'+inputId).click();
});
// 부모 페이지 마크다운 에디터 toolbar 의 첨부파일 리스트 호출버튼 class 클릭시 첨부파일 리스트 모달 호출
$('body').on('click',handler_getModalList,function(){
if(handler_getModalList!='') $(listModal).modal('show');
});
// 업로드 리스트 showhide 값 reset 함수
var updateShowHide=function(uid,showhide){
if(showhide=='show'){
$('[data-role="attachList-menu-showhide-'+uid+'"]').attr('data-content','hide'); // data-content 값 수정
$('[data-role="attachList-menu-showhide-'+uid+'"]').text('숨기기'); // 메뉴명 변경
$('[data-role="attachList-label-hidden-'+uid+'"]').addClass('d-none'); // 숨김 라벨 숨기기
console.log($('[data-role="attachList-label-hidden-'+uid+'"]'));
}else{
$('[data-role="attachList-menu-showhide-'+uid+'"]').attr('data-content','show'); // data-content 값 수정
$('[data-role="attachList-menu-showhide-'+uid+'"]').text('보이기'); // 메뉴명 변경
$('[data-role="attachList-label-hidden-'+uid+'"]').removeClass('d-none'); // 숨김 라벨 노출
}
}
// 이벤트 바인딩 및 세팅
$('body').on('click','[data-attach-act]',function(e){
e.preventDefault();
var act=$(this).data('attach-act');
var uid=$(this).attr('data-id');
var type=$(this).data('type'); // file or photo
if(act=='edit'){
// data 값 세팅
var modal=$(this).data('target');
var filename=$(this).attr('data-filename'); // data-로 하면 변경된 값 적용 안됨
var fileext=$(this).data('fileext');
var caption=$(this).attr('data-caption'); // data- 로 하면 변경된 값 적용 안됨
var img_thumb=$(this).data('src');// 미리보기 이미지
var img_origin=$(this).data('origin');// 원본 이미지
// data 값 모달에 적용
$(modal).find('[data-role="filename"]').val(filename);
$(modal).find('[data-role="fileext"]').text(fileext);
$(modal).find('[data-role="filecaption"]').val(caption);
$(modal).find('[data-role="eventHandler"]').attr('data-id',uid); // save, cancel 엘리먼트 data-id="" 값에 uid 값 적용
$(modal).find('[data-role="eventHandler"]').attr('data-type',type); // save, cancel 엘리먼트 data-type="" 값에 type 값 적용
if(type=='photo'){
$(modal).find('[data-role="img-preview"]').attr('src',img_thumb); // 미리보기 이미지 src 적용
$(modal).find('[data-role="img-preview"]').attr('data-origin',img_origin); // 원본 이미지 src 적용
} else if(type=='video'){
$(modal).find('[data-role="img-preview"]').html('<i class="fa fa-file-video-o fa-4x"></i>'); // 타입별 아이콘 적용
} else if(type=='audio'){
$(modal).find('[data-role="img-preview"]').html('<i class="fa fa-file-audio-o fa-4x"></i>'); // 타입별 아이콘 적용
} else {
$(modal).find('[data-role="img-preview"]').html('<i class="fa fa-floppy-o fa-4x"></i>'); // 타입별 아이콘 적용
}
}
//액션 실행
if(act=='delete'){
// 삭제하는 리스트가 대표 이미지인 경우 write.php input 값에 적용
var is_featured=$(this).attr('data-featured');
if(is_featured=='1' && type=='photo'){
if(confirm('대표이미지를 삭제하시겠습니까? ')){
$('input[name="featured_img"]').val('');
}else{
return false;
}
}
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=delete',{
uid : uid
},function(response){
var previewUl_default=$('[data-role="attach-preview-'+type+'"]'); // 파일 리스트 엘리먼트 class
var previewUl_modal=$('[data-role="modal-attach-preview-'+type+'"]'); // 파일 리스트 엘리먼트 class
var delEl_default=$(previewUl_default).find('[data-id="'+uid+'"]'); // 삭제 이벤트 진행된 엘리먼트
var delEl_modal=$(previewUl_modal).find('[data-id="'+uid+'"]'); // 삭제 이벤트 진행된 엘리먼트
delEl_default.remove();// 삭제 이벤트 진행시 해당 li 엘리먼트 remove
delEl_modal.remove();// 삭제 이벤트 진행시 해당 li 엘리먼트 remove
});
}else if(act=='showhide'){
var showhide=$(this).attr('data-content'); // data('content') 로 할 경우, ajax 로 변경된 값이 인식되지 않는다.
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=edit',{
act : act,
uid : uid,
showhide : showhide
},function(response){
var result=$.parseJSON(response);
if(!result.error){
updateShowHide(uid,showhide);
}
});
}else if(act=='save'){ // 정보수정 저장
var modal=$(this).data('target');
var filename=$(modal).find('[data-role="filename"]').val(); // 입력된 파일명
var filetype=$(modal).find('[data-role="eventHandler"]').attr('data-type'); // photo or file
var fileext=$(modal).find('[data-role="fileext"]').text(); // 입력된 파일 확장자명
var filecaption=$(modal).find('[data-role="filecaption"]').val(); // 입력된 캡션명
var filesrc=$(modal).find('[data-role="img-preview"]').attr('data-origin'); // 원본 이미지 소스
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=edit',{
act : act,
uid : uid,
filename : filename,
filetype : filetype,
fileext : fileext,
filecaption : filecaption,
filesrc : filesrc
},function(response){
var result=$.parseJSON(response);
if(!result.error){
var new_filename=result.filename;
var new_filecaption=result.filecaption;
var new_fileext=result.fileext;
var new_filetype=result.filetype;
var new_filesrc=result.filesrc;
// 리스트 값 수정
$('[data-role="attachList-menu-edit-'+uid+'"]').attr('data-filename',new_filename); // 파일명 수정
$('[data-role="attachList-menu-edit-'+uid+'"]').attr('data-caption',new_filecaption); // 'edit' 메뉴 캡션 업데이트
$('[data-role="attachList-menu-insert-'+uid+'"]').attr('data-caption',new_filecaption); // 'insert' 메뉴 캡션내용 수정
$('[data-role="attachList-list-name-'+uid+'"]').text(new_filename+'.'+new_fileext); // 리스트 name 수정
$('[data-role="attachList-list-name-'+uid+'"]').attr('data-caption',new_filecaption); // 리스트에도 캡션 업데이트
// 모달 닫기
$(modal).modal('hide');
$(modal).find('[data-role="filename"]').val(''); // 입력된 파일명 초기화
$(modal).find('[data-role="fileext"]').text(''); // 입력된 파일 확장자명 초기화
$(modal).find('[data-role="filecaption"]').val(''); // 입력된 캡션명 초기화
}
});
}else if(act=='featured-img'){ // 대표이미지 설정
// write.php 페이지 <input name="featured_img" value > 값에 적용
$('input[name="featured_img"]').val(uid);
// 대표 이미지 라벨 업데이트
$('[data-role="attachList-label-featured"]').each(function(){
$(this).addClass('d-none');
// 삭제 메뉴에 대표이미지 표시 지우기
$('[data-attach-act="delete"]').attr('data-featured','');
if($(this).data('id')==uid){
$(this).removeClass('d-none');
// 삭제 메뉴에 대표이미지 표시
$('[data-role="attachList-menu-delete-'+uid+'"]').attr('data-featured',1);
}
});
}else if(act=='insert'){
var agent = navigator.userAgent.toLowerCase();
var src=$(this).data('origin');
var type=$(this).attr('data-type');
var caption=$(this).attr('data-caption');
var dn_url = rooturl+'/'+raccount+'/download/'+uid;
if ((navigator.appName == 'Netscape' && navigator.userAgent.search('Trident') != -1) || (agent.indexOf("msie") != -1)) {
// 인터넷 익스플로러 브라우저 입니다.
var img_html = '<img src="'+src+'" alt="'+caption+'" class="img-fluid">';
var file_html = '<a href="'+dn_url+'">'+caption+'</a>';
if(type=='photo') {
InserHTMLtoEditor(type,img_html,src,caption)
} else {
InserHTMLtoEditor(type,file_html,dn_url,caption)
}
} else {
// 인터넷 익스플로러 브라우저가 아닙니다.
var img_html = '<figure class="image ck-widget" contenteditable="false">'+
'<img src="'+src+'">'+
'<figcaption class="ck-editor__editable ck-editor__nested-editable ck-placeholder ck-hidden" data-placeholder="이미지 설명을 입력하세요" contenteditable="true">'+caption+'</figcaption>'+
'</figure>';
var file_html = '<p><a href="'+dn_url+'">'+caption+'</a></p>';
if(type=='photo') {
InserHTMLtoEditor(img_html)
} else {
InserHTMLtoEditor(file_html)
}
}
var showhide= 'hide'; // 숨김처리
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=edit',{
act : act,
uid : uid,
showhide : showhide
},function(response){
var result=$.parseJSON(response);
if(!result.error){
updateShowHide(uid,showhide);
}
});
}
});
};
})(jQuery);

View File

@@ -0,0 +1,106 @@
<?php
include $g['dir_attach_theme'].'/header.php';
?>
<div id="attach-files" class="files position-relative"><!-- 파일폼 출력 -->
</div>
<div class="rb-attach mb-3 dd" id="nestable-photo">
<ol class="list-group rb-attach-photo mb-2 bg-faded dd-list" data-role="attach-preview-photo"><!-- 포토/이미지 리스트 -->
<?php if($parent_data['uid']):?>
<?php echo getAttachFileList($parent_data,'upload','photo',$wdgvar['wysiwyg'])?>
<?php endif?>
</ol>
</div>
<div class="rb-attach mb-3 dd" id="nestable-file">
<ol class="list-group rb-attach-file bg-faded dd-list" data-role="attach-preview-file"> <!-- 일반파일 리스트 -->
<?php if($parent_data['uid']):?>
<?php echo getAttachFileList($parent_data,'upload','file',$wdgvar['wysiwyg'])?>
<?php echo getAttachFileList($parent_data,'upload','doc',$wdgvar['wysiwyg'])?>
<?php echo getAttachFileList($parent_data,'upload','zip',$wdgvar['wysiwyg'])?>
<?php endif?>
</ol>
</div>
<div class="rb-attach mb-3 dd" id="nestable-video">
<ol class="list-group rb-attach-file bg-faded dd-list" data-role="attach-preview-video"> <!-- 비디오 파일 리스트 -->
<?php if($parent_data['uid']):?>
<?php echo getAttachFileList($parent_data,'upload','video',$wdgvar['wysiwyg'])?>
<?php endif?>
</ol>
</div>
<div class="rb-attach mb-3 dd" id="nestable-audio">
<ol class="list-group rb-attach-file bg-faded dd-list" data-role="attach-preview-audio"> <!-- 오디오 파일 리스트 -->
<?php if($parent_data['uid']):?>
<?php echo getAttachFileList($parent_data,'upload','audio',$wdgvar['wysiwyg'])?>
<?php endif?>
</ol>
</div>
<?php
include $g['dir_attach_theme'].'/footer.php';
?>
<script>
var link_settings={
module : 'mediaset',
theme : '<?php echo $g['dir_attach_theme']?>',
};
$('.rb-preview').on('click', function() {
$(this).removeClass('btn-primary').addClass('btn-light')
});
$(document).ready(function(){
// 첨부사진 순서변경
$('#nestable-photo').nestable({
group: 1,
maxDepth: 1
});
// 첨부파일 순서변경
$('#nestable-file').nestable({
group: 2,
maxDepth: 1
});
// 첨부 비디오 순서변경
$('#nestable-video').nestable({
group: 3,
maxDepth: 1
});
// 첨부 오디오 순서변경
$('#nestable-audio').nestable({
group: 4,
maxDepth: 1
});
// 첨부사진 순서변경
$('#nestable-link').nestable({
group: 5,
maxDepth: 1
});
// 순서변경 내역 저장
$('.dd').on('change', function() {
var attachfiles=$('input[name="attachfiles[]"]').map(function(){return $(this).val()}).get();
var new_upfiles='';
if(attachfiles){
for(var i=0;i<attachfiles.length;i++) {
new_upfiles+=attachfiles[i];
}
}
$.post(rooturl+'/?r='+raccount+'&m=mediaset&a=modifygid',{
attachfiles : new_upfiles
});
});
});
</script>

View File

@@ -0,0 +1,70 @@
<!-- 첨부 사진 메타정보 수정 -->
<div class="modal rb-modal-attach-meta" id="modal-attach-photo-meta" tabindex="-1" role="dialog" aria-labelledby="">
<div class="modal-dialog my-0" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id=""><i class="fa fa-camera-retro"></i> 사진 정보수정</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body" style="height: 64.2vh;">
<p><img class="img-fluid img-thumbnail" src="" alt="" data-role="img-preview" data-origin=""></p>
<div class="form-group">
<label for="file-caption" class="control-label">캡션:</label>
<textarea class="form-control" data-role="filecaption" rows="5"></textarea>
</div>
<div class="form-group">
<label for="file-name" class="control-label">파일명:</label>
<div class="input-group">
<input type="text" class="form-control" data-role="filename" name="filename">
<div class="input-group-append">
<span class="input-group-text" data-role="fileext">확장자</span>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary btn-block" data-attach-act="save" data-target="#modal-attach-photo-meta" data-role="eventHandler" data-id="">저장하기</button>
</div>
</div>
</div>
</div>
<!-- 첨부 파일 메타정보 수정 -->
<div class="modal fade rb-modal-attach-meta" id="modal-attach-file-meta" tabindex="-1" role="dialog" aria-labelledby="">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id=""><i class="fa fa-floppy-o"></i> 첨부파일 정보수정</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-4">
<h1 class="text-xs-center" data-role="img-preview">
</h1>
</div>
<div class="col-md-8">
<div class="form-group">
<label for="file-name" class="control-label">파일명:</label>
<div class="input-group">
<input type="text" class="form-control" name="filename" data-role="filename">
<div class="input-group-append">
<span class="input-group-text" data-role="fileext">확장자</span>
</div>
</div>
</div>
<div class="form-group">
<label for="file-caption" class="control-label">캡션:</label>
<textarea class="form-control" data-role="filecaption" name="caption"></textarea>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal" data-attach-act="cancel" data-target="#modal-attach-file-meta" data-role="eventHandler" data-id="">취소하기</button>
<button type="button" class="btn btn-primary" data-attach-act="save" data-target="#modal-attach-file-meta" data-role="eventHandler" data-id="" data-type="">저장하기</button>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1 @@
부트스트랩 심플 기본형

View File

@@ -0,0 +1,14 @@
# 부트스트랩4 파일 업로드 테마
부트스트랩
## 주요기능
- 사진,파일 업로드
- 첨부물 메타정보 등록
- 첨부목록 숨김처리
- 대표이미지 지정
## 요구사항
- `widgets/_default/attach` 위젯 필요
- `/plugins/jquery-form/4.2.2/jquery.form.min.js` 플러그인 필요

View File

@@ -0,0 +1,5 @@
<?php
$d['theme']['hidden_photo'] = "0"; // 이미지 추가시 사진 숨김여부 기본값 (숨김=1/보임=0)
$d['theme']['allowedTypes'] = ""; // 업로드 가능한 파일 확장자. (명시하지 않으면 파일 확장자 필터링하지 않음.)
$d['theme']['multiple'] = "1"; // 멀티 업로드 (허용=1/비허용=0)
?>

View File

@@ -0,0 +1,146 @@
<?php
// 모달 페이지 인클루드
include $g['dir_attach_theme'].'/modals.php';
getImport('moment','moment','2.22.2','js');
getImport('moment-duration-format','moment-duration-format','2.2.2','js');
?>
<script>
$(document).ready(function() {
var clipboard = new ClipboardJS('[data-link-act="clipboard"]');
$('[data-link-act="insert"]').tooltip({
trigger: 'hover',
title : '본문삽입'
});
$('[data-attach-act="clipboard"]').tooltip({
trigger: 'hover',
title : '클립보드 복사'
});
$('[data-link-act="clipboard"]').tooltip();
$('body').on('click','[data-link-act="insert"]',function(){
$(this).attr('data-original-title', '삽입 되었습니다.')
$(this).tooltip('show');
$(this).attr('data-original-title', '본문삽입')
});
$('body').on('click','[data-link-act="clipboard"]',function(){
$(this).attr('data-original-title', '복사 되었습니다.')
$(this).tooltip('show');
$(this).attr('data-original-title', '')
});
var check_url = $('#check_url');
var iframe_api_key = 'ad515293314b53d30d0e94';
check_url.find(".btn").click(function(){
var container = '#attach_link'
var fieldset = check_url
var textarea = check_url.find('textarea')
var url = textarea.val()
if (!url) {
textarea.focus()
return false
}
fieldset.attr('disabled',true)
$.get('//embed.kimsq.com/oembed',{
api_key : iframe_api_key,
url: url
}).done(function(response) {
var type = response.type;
var title = response.title;
var description = response.description;
var thumbnail_url = response.thumbnail_url;
var author = response.author;
var provider = response.provider_name;
var url = response.url;
var width = response.thumbnail_width;
var height = response.thumbnail_height;
var embed = response.html;
check_url.find('[data-role="title"]').text(title);
check_url.find('[data-role="description"]').text(description);
check_url.find('[data-role="thumbnail"]').attr('src',thumbnail_url);
check_url.find('[data-act="insert"]').attr('data-url',url).attr('data-title',title).attr('data-description',description).attr('data-thumbnail',thumbnail_url).attr('data-provider',provider);
if (type=='video') {
$.get('//embed.kimsq.com/iframely',{
api_key : iframe_api_key,
url: url
}).done(function(response) {
var duration = response.meta.duration;
var _duration = moment.duration(duration, 's');
var formatted_duration = _duration.format("h:*m:ss");
$.post(rooturl+'/?r='+raccount+'&m=mediaset&a=saveLink',{
type : 9,
title : title,
theme : '_desktop/bs4-system-link',
description : description,
thumbnail_url : thumbnail_url,
author: author,
provider : provider,
url : url,
duration : duration?duration:'',
time : duration?formatted_duration:'',
width : width,
height : height,
embed : embed,
wysiwyg : '<?php echo $wdgvar['wysiwyg'] ?>'
},function(response){
var result=$.parseJSON(response);
if(!result.error){
$(container).find('[data-role="attach-preview-link"]').prepend(result.list);
$.notify("추가 되었습니다.");
}
});
});
} else {
$.post(rooturl+'/?r='+raccount+'&m=mediaset&a=saveLink',{
type : 8,
title : title,
theme : '_desktop/bs4-system-link',
description : description,
thumbnail_url : thumbnail_url,
author: author,
provider : provider,
url : url,
width : width,
height : height,
embed : embed,
wysiwyg : '<?php echo $wdgvar['wysiwyg'] ?>'
},function(response){
var result=$.parseJSON(response);
if(!result.error){
$(container).find('[data-role="attach-preview-link"]').prepend(result.list);
$.notify("추가 되었습니다.");
}
});
}
}).fail(function() {
alert( "URL을 확인해주세요." );
}).always(function() {
textarea.val('')
fieldset.attr('disabled',false)
});
});
})
</script>

View File

@@ -0,0 +1,93 @@
<?php
// 위젯 설정값 세팅
$parent_module=$d['attach']['parent_module']; // 첨부파일 사용하는 모듈
$parent_data=$d['attach']['parent_data']; // 해당 포스트 데이타 (수정시 필요)
$attach_module_theme=$d['attach']['theme']; // 첨부파일 테마
$attach_mode=$d['attach']['mod']; // list, main...
$attach_handler_file=$d['attach']['handler_file']; //파일첨부 실행 엘리먼트 button or 기타 엘리먼트 data-role="" 형태로 하는 것을 권고
$attach_handler_photo=$d['attach']['handler_photo']; // 사진첨부 실행 엘리먼트 button or 기타 엘리먼트 data-role="" 형태로 하는 것을 권고
$attach_handler_getModalList=$d['attach']['handler_getModalList']; // 첨부파일 리스트 호출 handler
$attach_object_type=$d['attach']['object_type']; // 첨부 대상에 따른 분류 : photo, file, link, video....
$editor_type=$d['attach']['editor_type']; // 에디터 타입 : html,markdown
require_once $g['dir_attach_theme'].'/main.func.php'; // 함수 인클루드
require_once $g['dir_attach_theme'].'/_var.php'; // 테마변수 인클루드
require_once $g['path_module'].'mediaset/var/var.php'; //모듈 공통변수 인클루드
?>
<script src="<?php echo $g['url_attach_theme']?>/main.js"></script>
<!-- nestable : https://github.com/dbushell/Nestable -->
<?php getImport('nestable','jquery.nestable',false,'js') ?>
<style media="screen">
/**
* Nestable
*/
.dd { }
.dd-list { display: block; position: relative; list-style: none; }
.dd-list .dd-list { }
.dd-collapsed .dd-list { display: none; }
.dd-item,
.dd-empty,
.dd-placeholder { }
.dd-handle {
position: absolute;
margin: 0;
left: 0;
top: 0;
bottom:0;
cursor: pointer;
width: 25px;
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
background-color: #eff3f6;
background-image: linear-gradient(-180deg, #fafbfc 0%, #eff3f6 90%);
background-repeat: repeat-x;
background-position: -1px -1px;
background-size: 110% 110%;
border-right: 1px solid rgba(27,31,35,0.1);
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.dd-handle:hover {
background-color: #e6ebf1;
background-image: linear-gradient(-180deg, #f0f3f6 0%, #e6ebf1 90%);
background-position: -.5em;
}
.dd-handle:before {
display: block;
position: absolute;
left: 0;
top: 50%;
margin-top: -7px;
width: 100%;
text-align: center;
text-indent: 0;
color: #494949;
font-size: 14px;
font-weight: normal;
}
.dd-placeholder,
.dd-empty { margin: 5px 0; padding: 0; min-height: 30px; background: #f2fbff; border: 1px dashed #b6bcbf; box-sizing: border-box; -moz-box-sizing: border-box; }
.dd-empty { border: 1px dashed #bbb; min-height: 100px; background-color: #e5e5e5;
background-image: -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
-webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
background-image: -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
-moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
background-size: 60px 60px;
background-position: 0 0, 30px 30px;
}
.dd-dragel { position: absolute; pointer-events: none; z-index: 9999; }
.dd-dragel > .dd-item .dd-handle { margin-top: 0; }
.dd-dragel .dd-handle {
-webkit-box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1);
box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1);
}
</style>

View File

@@ -0,0 +1,79 @@
<?php
function getAttachPlatformList($parent_data,$mod,$wysiwyg) {
global $table;
$upload=$parent_data['upload'];
$featured_img_uid=$parent_data['featured_img'];// 대표이미지 uid
$sql='fserver=3';
$attach = getArrayString($upload);
$uid_q='(';
foreach($attach['data'] as $uid)
{
$uid_q.='uid='.$uid.' or ';
}
$uid_q=substr($uid_q,0,-4).')';
$sql=$sql.' and '.$uid_q;
$RCD=getDbArray($table['s_upload'],$sql,'*','gid','desc','',1);
$html='';
while($R=db_fetch_array($RCD)){
$U=getUidData($table['s_upload'],$R['uid']);
$html.=getAttachPlatform($U,$mod,$featured_img_uid,$wysiwyg);
}
return $html;
}
// 추출 함수 (낱개)
function getAttachPlatform($R,$mod,$featured_img_uid,$wysiwyg) {
global $g,$r;
$md_title=str_replace('|','-',$R['title']);
$thumbnail_url_parse = parse_url($R['src']);
$thumbnail_url_arr = explode('//',$R['src']);
if ($R['provider']=='Google Maps') $thumbnail = $R['src'];
else $thumbnail = '/thumb'.($thumbnail_url_parse['scheme']=='https'?'-ssl':'').'/50x50/u/'.$thumbnail_url_arr[1];
$insert_text='<figure class="media"><oembed url="'.$R['linkurl'].'"></oembed></figure>';
$html='';
$html.='
<li class="list-group-item dd-item" data-id="'.$R['uid'].'">
<div class="d-flex justify-content-between">';
$html.='
<div class="dd-handle fa fa-arrows" title="순서변경"></div>
<div class="media ml-3">
<a data-link-act="'.($wysiwyg?'insert':'').'" data-provider="'.$R['provider'].'" data-url="'.$R['linkurl'].'" data-id="'.$R['uid'].'" data-role="attachList-menu-edit-'.$R['uid'].'" href="" class="mr-3 position-relative"><img class="border" src="'.$thumbnail.'" alt="" style="width:50px;height:50px"><span class="position-absolute'.($R['duration']?'':' d-none').'" style="bottom:5px;right:5px;"><i class="fa fa-play-circle text-white" style="font-size:20px;text-shadow: 2px 2px 2px gray;" aria-hidden="true"></i></span></a>
<div class="media-body">';
$html.='<span class="badge badge-pill badge-warning '.($R['uid']==$featured_img_uid?'':'d-none').'" data-role="attachList-label-featured" data-id="'.$R['uid'].'">대표</span> ';
$html.='<span class="badge badge-pill badge-secondary '.(!$R['hidden']?'d-none':'').'" data-role="attachList-label-hidden-'.$R['uid'].'">숨김</span>';
$html.='
<a href="'.$R['linkurl'].'" target="_blank" class="title d-inline text-reset" data-role="attachList-list-name-'.$R['uid'].'" >'.($R['caption']?$R['caption']:$R['description']).'</a>
<div class="meta"><span class="badge badge-pill badge-light">'.$R['provider'].'</span> <span class="badge badge-pill badge-light" data-role="attachList-list-time-'.$R['uid'].'">'.$R['time'].'</span></div>';
$html.='
</div>
</div>';
$html.='
<div style="margin-top:-5px;margin-right: -21px;">';
$html.='<input type="hidden" name="attachfiles[]" value="['.$R['uid'].']"/>';
$html.='
<div class="btn-group"><button type="button" class="btn btn-link text-reset dropdown-toggle" data-toggle="dropdown" role="button"><i class="fa fa-ellipsis-v" aria-hidden="true"></i></button>
<div class="dropdown-menu dropdown-menu-right" role="menu">
<a class="dropdown-item" href="#" data-link-act="featured-img" data-id="'.$R['uid'].'">대표이미지 설정</a>
<a class="dropdown-item" href="#" data-link-act="showhide" data-role="attachList-menu-showhide-'.$R['uid'].'" data-id="'.$R['uid'].'" data-content="'.($R['hidden']?'show':'hide').'" >'.($R['hidden']?'보이기':'숨기기').'</a>
<a class="dropdown-item" href="#" data-link-act="delete" data-id="'.$R['uid'].'" data-role="attachList-menu-delete-'.$R['uid'].'">삭제</a>
</div>
</div></div>';
$html.='</div>';
if (!$wysiwyg) $html.='<div class="input-group ml-3 mt-2"><textarea class="form-control f13" id="clipboard-'.$R['uid'].'">'.$insert_text.'</textarea><div class="input-group-append"><button class="btn btn-light" data-attach-act="clipboard" data-clipboard-target="#clipboard-'.$R['uid'].'" type="button">복사</button></div></div>';
$html.='</li>';
return $html;
}
?>

View File

@@ -0,0 +1,161 @@
// 업로드 리스트 showhide 값 reset 함수
var updateShowHide=function(uid,showhide){
if(showhide=='show'){
$('[data-role="attachList-menu-showhide-'+uid+'"]').attr('data-content','hide'); // data-content 값 수정
$('[data-role="attachList-menu-showhide-'+uid+'"]').text('숨기기'); // 메뉴명 변경
$('[data-role="attachList-label-hidden-'+uid+'"]').addClass('d-none'); // 숨김 라벨 숨기기
console.log($('[data-role="attachList-label-hidden-'+uid+'"]'));
}else{
$('[data-role="attachList-menu-showhide-'+uid+'"]').attr('data-content','show'); // data-content 값 수정
$('[data-role="attachList-menu-showhide-'+uid+'"]').text('보이기'); // 메뉴명 변경
$('[data-role="attachList-label-hidden-'+uid+'"]').removeClass('d-none'); // 숨김 라벨 노출
}
}
$('body').on('click','[data-link-act]',function(e){
e.preventDefault();
var act=$(this).attr('data-link-act');
var uid=$(this).attr('data-id');
var type=$(this).data('type'); // file or photo
var module = 'mediaset';
if(act=='edit'){
// data 값 세팅
var modal=$(this).data('target');
var filename=$(this).attr('data-filename'); // data-로 하면 변경된 값 적용 안됨
var fileext=$(this).data('fileext');
var caption=$(this).attr('data-caption'); // data- 로 하면 변경된 값 적용 안됨
var img_thumb=$(this).data('src');// 미리보기 이미지
var img_origin=$(this).data('origin');// 원본 이미지
// data 값 모달에 적용
$(modal).find('[data-role="filename"]').val(filename);
$(modal).find('[data-role="fileext"]').text(fileext);
$(modal).find('[data-role="filecaption"]').val(caption);
$(modal).find('[data-role="eventHandler"]').attr('data-id',uid); // save, cancel 엘리먼트 data-id="" 값에 uid 값 적용
$(modal).find('[data-role="eventHandler"]').attr('data-type',type); // save, cancel 엘리먼트 data-type="" 값에 type 값 적용
if(type=='photo'){
$(modal).find('[data-role="img-preview"]').attr('src',img_thumb); // 미리보기 이미지 src 적용
$(modal).find('[data-role="img-preview"]').attr('data-origin',img_origin); // 원본 이미지 src 적용
} else if(type=='video'){
$(modal).find('[data-role="img-preview"]').html('<i class="fa fa-file-video-o fa-4x"></i>'); // 타입별 아이콘 적용
} else if(type=='audio'){
$(modal).find('[data-role="img-preview"]').html('<i class="fa fa-file-audio-o fa-4x"></i>'); // 타입별 아이콘 적용
} else {
$(modal).find('[data-role="img-preview"]').html('<i class="fa fa-floppy-o fa-4x"></i>'); // 타입별 아이콘 적용
}
}
//액션 실행
if(act=='delete'){
// 삭제하는 리스트가 대표 이미지인 경우 write.php input 값에 적용
var is_featured=$(this).attr('data-featured');
if(is_featured=='1' && type=='photo'){
if(confirm('대표이미지를 삭제하시겠습니까? ')){
$('input[name="featured_img"]').val('');
}else{
return false;
}
}
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=delete',{
uid : uid
},function(response){
var previewUl_default=$('[data-role="attach-preview-link"]'); // 파일 리스트 엘리먼트 class
var previewUl_modal=$('[data-role="modal-attach-preview-link"]'); // 파일 리스트 엘리먼트 class
var delEl_default=$(previewUl_default).find('[data-id="'+uid+'"]'); // 삭제 이벤트 진행된 엘리먼트
var delEl_modal=$(previewUl_modal).find('[data-id="'+uid+'"]'); // 삭제 이벤트 진행된 엘리먼트
delEl_default.remove();// 삭제 이벤트 진행시 해당 li 엘리먼트 remove
delEl_modal.remove();// 삭제 이벤트 진행시 해당 li 엘리먼트 remove
});
}else if(act=='showhide'){
var showhide=$(this).attr('data-content'); // data('content') 로 할 경우, ajax 로 변경된 값이 인식되지 않는다.
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=edit',{
act : act,
uid : uid,
showhide : showhide
},function(response){
var result=$.parseJSON(response);
if(!result.error){
updateShowHide(uid,showhide);
}
});
}else if(act=='save'){ // 정보수정 저장
var modal=$(this).data('target');
var filename=$(modal).find('[data-role="filename"]').val(); // 입력된 파일명
var filetype=$(modal).find('[data-role="eventHandler"]').attr('data-type'); // photo or file
var fileext=$(modal).find('[data-role="fileext"]').text(); // 입력된 파일 확장자명
var filecaption=$(modal).find('[data-role="filecaption"]').val(); // 입력된 캡션명
var filesrc=$(modal).find('[data-role="img-preview"]').attr('data-origin'); // 원본 이미지 소스
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=edit',{
act : act,
uid : uid,
filename : filename,
filetype : filetype,
fileext : fileext,
filecaption : filecaption,
filesrc : filesrc
},function(response){
var result=$.parseJSON(response);
if(!result.error){
var new_filename=result.filename;
var new_filecaption=result.filecaption;
var new_fileext=result.fileext;
var new_filetype=result.filetype;
var new_filesrc=result.filesrc;
// 리스트 값 수정
$('[data-role="attachList-menu-edit-'+uid+'"]').attr('data-filename',new_filename); // 파일명 수정
$('[data-role="attachList-menu-edit-'+uid+'"]').attr('data-caption',new_filecaption); // 'edit' 메뉴 캡션 업데이트
$('[data-role="attachList-menu-insert-'+uid+'"]').attr('data-caption',new_filecaption); // 'insert' 메뉴 캡션내용 수정
$('[data-role="attachList-list-name-'+uid+'"]').text(new_filename+'.'+new_fileext); // 리스트 name 수정
$('[data-role="attachList-list-name-'+uid+'"]').attr('data-caption',new_filecaption); // 리스트에도 캡션 업데이트
// 모달 닫기
$(modal).modal('hide');
$(modal).find('[data-role="filename"]').val(''); // 입력된 파일명 초기화
$(modal).find('[data-role="fileext"]').text(''); // 입력된 파일 확장자명 초기화
$(modal).find('[data-role="filecaption"]').val(''); // 입력된 캡션명 초기화
}
});
}else if(act=='featured-img'){ // 대표이미지 설정
// write.php 페이지 <input name="featured_img" value > 값에 적용
$('input[name="featured_img"]').val(uid);
// 대표 이미지 라벨 업데이트
$('[data-role="attachList-label-featured"]').each(function(){
$(this).addClass('d-none');
// 삭제 메뉴에 대표이미지 표시 지우기
$('[data-link-act="delete"]').attr('data-featured','');
if($(this).data('id')==uid){
$(this).removeClass('d-none');
// 삭제 메뉴에 대표이미지 표시
$('[data-role="attachList-menu-delete-'+uid+'"]').attr('data-featured',1);
}
});
}else if(act=='insert'){
var src=$(this).data('origin');
var type=$(this).attr('data-type');
var caption=$(this).attr('data-caption');
var dn_url = rooturl+'/'+raccount+'/download/'+uid;
var url = $(this).attr('data-url')
var html = '<figure class="media"><oembed url="'+url+'"></oembed></figure>'
InserHTMLtoEditor(html)
var showhide= 'hide'; // 숨김처리
$.post(rooturl+'/?r='+raccount+'&m='+module+'&a=edit',{
act : act,
uid : uid,
showhide : showhide
},function(response){
var result=$.parseJSON(response);
if(!result.error){
updateShowHide(uid,showhide);
}
});
}
});

View File

@@ -0,0 +1,34 @@
<?php
include $g['dir_attach_theme'].'/header.php';
?>
<div id="attach_link">
<fieldset id="check_url" class="mb-3">
<div class="input-group" style="border: 2px dashed #d1d1d1;">
<textarea class="form-control bg-white border-0" rows="3" placeholder="URL을 입력해주세요."></textarea>
<div class="input-group-append">
<button class="btn btn-light border-right-0 border-top-0 border-bottom-0" type="button">
가져오기
</button>
</div>
</div>
<small class="form-text text-muted"></small>
</fieldset>
<div class="rb-attach mb-3 dd" id="nestable-link">
<ol class="list-group rb-attach-file bg-faded dd-list" data-role="attach-preview-link"> <!-- 일반파일 리스트 -->
<?php if($parent_data['uid']):?>
<?php echo getAttachPlatformList($parent_data,'upload',$wdgvar['wysiwyg'])?>
<?php endif?>
</ol>
</div>
</div>
<?php
include $g['dir_attach_theme'].'/footer.php';
?>

View File

@@ -0,0 +1,149 @@
<!-- 첨부 사진 메타정보 수정 -->
<div class="modal fade rb-modal-attach-meta" id="modal-attach-photo-meta" tabindex="-1" role="dialog" aria-labelledby="">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id=""><i class="fa fa-camera-retro"></i> 사진 정보수정</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
<div class="row">
<!-- data-role="img-preview" src="_s 이미지" data-origin="원본 이미지" 넣는다. -->
<div class="col-md-4">
<p><img class="img-thumbnail" src="" alt="" data-role="img-preview" data-origin=""></p>
</div>
<div class="col-md-8">
<div class="form-group">
<label for="file-caption" class="control-label">캡션:</label>
<textarea class="form-control" data-role="filecaption" rows="5"></textarea>
</div>
<div class="form-group">
<label for="file-name" class="control-label">파일명:</label>
<div class="input-group">
<input type="text" class="form-control" data-role="filename" name="filename">
<div class="input-group-append">
<span class="input-group-text" data-role="fileext">확장자</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal" data-attach-act="cancel" data-target="#modal-attach-photo-meta" data-role="eventHandler" data-id="">취소하기</button>
<button type="button" class="btn btn-primary" data-attach-act="save" data-target="#modal-attach-photo-meta" data-role="eventHandler" data-id="">저장하기</button>
</div>
</div>
</div>
</div>
<!-- 첨부 파일 메타정보 수정 -->
<div class="modal fade rb-modal-attach-meta" id="modal-attach-file-meta" tabindex="-1" role="dialog" aria-labelledby="">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id=""><i class="fa fa-floppy-o"></i> 첨부파일 정보수정</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-4">
<h1 class="text-xs-center" data-role="img-preview">
</h1>
</div>
<div class="col-md-8">
<div class="form-group">
<label for="file-name" class="control-label">파일명:</label>
<div class="input-group">
<input type="text" class="form-control" name="filename" data-role="filename">
<div class="input-group-append">
<span class="input-group-text" data-role="fileext">확장자</span>
</div>
</div>
</div>
<div class="form-group">
<label for="file-caption" class="control-label">캡션:</label>
<textarea class="form-control" data-role="filecaption" name="caption"></textarea>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal" data-attach-act="cancel" data-target="#modal-attach-file-meta" data-role="eventHandler" data-id="">취소하기</button>
<button type="button" class="btn btn-primary" data-attach-act="save" data-target="#modal-attach-file-meta" data-role="eventHandler" data-id="" data-type="">저장하기</button>
</div>
</div>
</div>
</div>
<!-- 링크 추가 -->
<div class="modal fade" tabindex="-1" role="dialog" id="modal-attach-link">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">링크 추가</h4>
</div>
<div class="modal-body">
<p id="attach-link">
<!--링크 입력 필드 동적 생성 -->
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal">닫기</button>
<button type="button" class="btn btn-primary" data-plugin="clipboard" data-clipboard-text="" data-role="btn-copy-linkContent">링크내용 복사하기</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
<!-- 위치 추가 -->
<div class="modal fade" tabindex="-1" role="dialog" id="modal-attach-map">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">위치 추가</h4>
</div>
<div class="modal-body">
<p>지도 검색 UI </p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal">닫기</button>
<button type="button" class="btn btn-primary">적용하기</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
<!-- 비디오 추가 -->
<div class="modal fade" tabindex="-1" role="dialog" id="modal-attach-video">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">비디오 추가</h4>
</div>
<div class="modal-body">
<p>유튜브와 비메오 비디오만 링크를 추가하는 형태</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal">닫기</button>
<button type="button" class="btn btn-primary">적용하기</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->

View File

@@ -0,0 +1 @@
부트스트랩 심플 기본형