1 # sales_views.py 2 # ————————47PerfectCRM實現CRM客戶報名流程———————— 3 from django.db import IntegrityError # 主動捕捉錯誤信息 4 from django.shortcuts import render # 頁面返回 5 from crm import models # 數據庫 6 from bpm.bpm_auxiliary import bpm_forms # 自定製 forms 7 from django.contrib.auth.decorators import login_required # 登錄後頁面才能訪問 8 9 # ————————47PerfectCRM實現CRM客戶報名流程———————— 10 from django.core.mail import send_mail 11 # send_mail的參數分別是 郵件標題,郵件內容,發件箱(settings.py中設置過的那個),收件箱列表(能夠發送給多我的),失敗靜默(若發送失敗,報錯提示咱們) 12 import random 13 import datetime # 獲取時間#登錄過時 14 15 16 # 發送郵件的功能 #驗證碼#密碼 17 class stmp(): 18 def __init__(self): 19 self.emaillist = [] # 發送給誰 20 self.code = None # 驗證碼#密碼 21 22 def stmps(self, request, email, msg_mail): # 傳參數#頁面,session #郵箱,發送給誰 #內容 23 self.emaillist.append(email) # 將郵箱地址添加到調用Django發送郵件功能 24 # ——————生成驗證碼—————— 25 _letter_cases = "abcdefghjkmnpqrstuvwxy" # 小寫字母,去除可能干擾的i,l,o,z 26 _upper_cases = _letter_cases.upper() # 大寫字母 27 _numbers = ''.join(map(str, range(3, 10))) # 數字 28 chars = ''.join((_letter_cases, _upper_cases, _numbers)) # 變成一條字符串 29 list = random.sample(chars, 4) # 從一條字符串隨機選4個字符變成列表 30 self.code = ''.join(list) # 列表變字符串 31 # ——————生成驗證碼—————— 32 # ——————調用Django發送郵件—————— 33 title = 'PerfectCRM項目自動郵件:%s' % self.code # 郵件標題#防止同樣的內容被郵箱屏蔽 34 send_mail(title, # 郵件標題 35 msg_mail, # 驗證碼內容 36 'perfectcrm@sina.cn', # 發送的郵箱 #根據狀況從新配置 37 self.emaillist, # 接受的郵箱 38 fail_silently=False, # 靜默,拋出異常 39 ) 40 print('發送郵件成功!沒收到要換標題!檢查發送郵箱的配置!') 41 # ——————調用Django發送郵件—————— 42 43 44 # ————————47PerfectCRM實現CRM客戶報名流程———————— 45 # ————————47PerfectCRM實現CRM客戶報名流程———————— 46 # ————————50PerfectCRM實現CRM客戶報名流程學生合同URL隨機碼———————— 47 import random # 隨機 48 import string # 字母 數字 49 from django.core.cache import cache # 緩存 50 # ————————50PerfectCRM實現CRM客戶報名流程學生合同URL隨機碼———————— 51 52 # 報名填寫 銷售 53 @login_required # 登錄後頁面才能訪問 54 def enrollment(request, customer_id): 55 msgs = {} # 錯誤信息 56 customer_obj = models.Customer.objects.get(id=customer_id) # 取到客戶信息記錄 #返回到頁面#報名人 57 consultant_obj = models.UserProfile.objects.get(id=request.user.id) # 報名課程顧問 58 59 stmp_mail = {} # 郵件發送成功 60 stmpemail = stmp() # 實例化發送郵件的功能 61 email = request.POST.get('email') # 讓頁面POST提交的值,在頁面GET後仍然存在顯示 62 if request.method == "POST": 63 enroll_form = bpm_forms.EnrollmentForm(request.POST) # 獲取數據 64 if enroll_form.is_valid(): # 表單驗證 65 66 # ————————50PerfectCRM實現CRM客戶報名流程學生合同URL隨機碼———————— 67 # msg = "http://127.0.0.1:8000/bpm/customer/registration/{enroll_obj_id}/" 68 msg = "http://127.0.0.1:8000/bpm/customer/registration/{enroll_obj_id}/{random_str}/ " 69 random_str = ''.join(random.sample(string.ascii_lowercase + string.digits, 8)) # 生成8位隨機字符串 #URL使用 70 url_str = '''customer/registration/{enroll_obj_id}/{random_str}/''' # 報名連接 71 # ————————50PerfectCRM實現CRM客戶報名流程學生合同URL隨機碼———————— 72 73 try: 74 enroll_form.cleaned_data['customer'] = customer_obj # 添加學員對象 記錄 #報名人 75 enroll_form.cleaned_data['consultant'] = consultant_obj # 報名課程顧問 76 enroll_obj = models.Enrollment.objects.create(**enroll_form.cleaned_data) # 建立記錄 77 78 # ————————50PerfectCRM實現CRM客戶報名流程學生合同URL隨機碼———————— 79 # msgs['msg']=msg.format(enroll_obj_id=enroll_obj.id)#報名記錄對應的id,隨機字符串,報名連接 80 sort_url = enroll_obj.id # 獲取報名表對應的ID 81 cache.set(enroll_obj.id, random_str, 61000) # 加入過時時間 #URL使用 # cache緩存 82 msgs['msg'] = msg.format(enroll_obj_id=enroll_obj.id, random_str=random_str) # 報名記錄對應的id,隨機字符串,報名連接 83 url_str = url_str.format(enroll_obj_id=enroll_obj.id, random_str=random_str) # 報名連接 84 print(url_str) 85 # ————————50PerfectCRM實現CRM客戶報名流程學生合同URL隨機碼———————— 86 except IntegrityError as e: 87 # 取到這條記錄 88 enroll_obj = models.Enrollment.objects.get(customer_id=customer_obj.id, 89 enrolled_class_id=enroll_form.cleaned_data[ 90 'enrolled_class'].id) 91 enroll_form.add_error('__all__', '記錄已經存在,不能重複建立!') 92 93 # ————————50PerfectCRM實現CRM客戶報名流程學生合同URL隨機碼———————— 94 # msgs['msg']=msg.format(enroll_obj_id=enroll_obj.id)#報名記錄對應的id 95 cache.set(enroll_obj.id, random_str, 61000) # 加入過時時間 #URL使用 # cache緩存 96 msgs['msg'] = msg.format(enroll_obj_id=enroll_obj.id, random_str=random_str) # 報名記錄對應的id 97 url_str = url_str.format(enroll_obj_id=enroll_obj.id, random_str=random_str) # 報名連接 98 # ————————50PerfectCRM實現CRM客戶報名流程學生合同URL隨機碼———————— 99 100 if email: 101 # ————————50PerfectCRM實現CRM客戶報名流程學生合同URL隨機碼———————— 102 # msg_mail = "http://127.0.0.1:8000/bpm/customer/registration/%s" %enroll_obj.id 103 msg_mail = "http://127.0.0.1:8000/bpm/customer/registration/%s/%s" %(enroll_obj.id,random_str) 104 # ————————50PerfectCRM實現CRM客戶報名流程學生合同URL隨機碼———————— 105 stmpemail.stmps(request, email, msg_mail) # 發送郵件 106 stmp_mail['ok'] = "郵件已發送成功!" 107 108 else: 109 enroll_form = bpm_forms.EnrollmentForm() # modelform表單 110 return render(request, 'bpm_sales/enrollment.html', locals()) 111 # ————————47PerfectCRM實現CRM客戶報名流程———————— 112 113 114 # ————————48PerfectCRM實現CRM客戶報名流程學生合同———————— 115 #學員合同簽訂 116 117 # ————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片———————— 118 import os 119 from PerfectCRM import settings 120 import json 121 # ————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片———————— 122 123 # ————————50PerfectCRM實現CRM客戶報名流程學生合同URL隨機碼———————— 124 from django.shortcuts import HttpResponse #頁面返回 125 # def stu_registration(request,enroll_id): 126 def stu_registration(request,enroll_id,random_str): 127 # enroll_obj=models.Enrollment.objects.get(id=enroll_id)#獲取報名記錄 128 if cache.get(enroll_id) == random_str: # 判斷連接失效了沒有 129 enroll_obj = models.Enrollment.objects.get(id=enroll_id) # 報名記錄 130 # ————————50PerfectCRM實現CRM客戶報名流程學生合同URL隨機碼———————— 131 132 # ————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片———————— 133 enrolled_path='%s/%s/'%(settings.ENROLLED_DATA,enroll_id)#證件上傳路徑 134 img_file_len=0 #文件 135 if os.path.exists(enrolled_path):#判斷目錄是否存在 136 img_file_list=os.listdir(enrolled_path)#取目錄 下的文件 137 img_file_len=len(img_file_list) 138 # ————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片———————— 139 140 # ————————49PerfectCRM實現CRM客戶報名流程學生合同表單驗證———————— 141 # ————————50PerfectCRM實現CRM客戶報名流程學生合同URL隨機碼———————— 142 if request.method == "POST": 143 144 # ————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片———————— 145 ret=False 146 data=request.POST.get('data') 147 if data:#若是有刪除動做 148 del_img_path="%s/%s/%s"%(settings.ENROLLED_DATA,enroll_id,data)#路徑 149 print(del_img_path,'=-=-=-=-=-=') 150 os.remove(del_img_path) 151 ret=True 152 return HttpResponse(json.dumps(ret)) 153 if request.is_ajax():#ajax上傳圖片 #異步提交 154 print('ajax上傳圖片 #異步提交中。。。 ',request.FILES) 155 enroll_data_dir="%s/%s"%(settings.ENROLLED_DATA,enroll_id)#路徑 #重要信息不能放在靜態文件中 156 if not os.path.exists(enroll_data_dir):#若是不存目錄 157 os.makedirs(enroll_data_dir,exist_ok=True)#建立目錄 158 for k,file_obj in request.FILES.items(): #循環字典 #上傳的文件 159 with open("%s/%s"%(enroll_data_dir,file_obj.name),'wb') as f: #打開一個文件#路徑#獲取文件名 160 for chunk in file_obj.chunks():#循環寫入文件 # chunks塊 161 f.write(chunk) #保存文件 162 return HttpResponse('上傳完成!') 163 # ————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片———————— 164 165 customer_form = bpm_forms.CustomerForm(request.POST, instance=enroll_obj.customer) # 生成表單驗證 166 if customer_form.is_valid(): # 表單驗證經過 167 customer_form.save() # 保存 168 enroll_obj.contract_agreed = True # 贊成協議 169 enroll_obj.save() # 保存 170 status = 1 # 修改報名狀態 # 1 已經報名 171 return render(request, 'bpm_sales/stu_registration.html', locals()) 172 173 else: 174 if enroll_obj.contract_agreed == True: # 若是協議已經簽定 175 status = 1 # 修改報名狀態 # 1 已經報名 176 else: 177 status = 0 178 customer_form = bpm_forms.CustomerForm(instance=enroll_obj.customer) # 生成表單 179 # customer_form = bpm_forms.CustomerForm(instance=enroll_obj.customer) # 生成表單 180 # ————————49PerfectCRM實現CRM客戶報名流程學生合同表單驗證———————— 181 182 return render(request,'bpm_sales/stu_registration.html',locals()) 183 # ————————50PerfectCRM實現CRM客戶報名流程學生合同URL隨機碼———————— 184 # ————————48PerfectCRM實現CRM客戶報名流程學生合同———————— 185 # ————————50PerfectCRM實現CRM客戶報名流程學生合同URL隨機碼———————— 186 else: 187 return HttpResponse('連接失效,非法連接,請自重!') 188 # ————————50PerfectCRM實現CRM客戶報名流程學生合同URL隨機碼————————
1 {#stu_registration.html#} 2 {## ————————48PerfectCRM實現CRM客戶報名流程學生合同————————#} 3 {% extends 'bpm_master/bpm_sample.html' %} 4 {% load bpm_tags %} 5 {% block right-container-content %} {#自定義內容開始 右邊頁面內容#} 6 <div class="container col-lg-7 col-md-offset-2"> 7 <div class="panel panel-warning"> 8 <div class=" panel-heading"> 9 <h3 class="panel-title container">報名入學|信息填寫</h3> 10 </div> 11 <div class="panel-body "><!--返回提交函數--> 12 {## ————————49PerfectCRM實現CRM客戶報名流程學生合同表單驗證————————#} 13 {% if status != 1 %} 14 <span class="errors">{{ customer_form.errors }}</span><!--錯誤提示--> 15 {## ————————49PerfectCRM實現CRM客戶報名流程學生合同表單驗證————————#} 16 {## ————————49PerfectCRM實現CRM客戶報名流程學生合同表單驗證————————#} 17 {# <form method="post" class="form-horizontal" role="form">{% csrf_token %}#} 18 <form method="post" class="form-horizontal" role="form" 19 onsubmit="return RegisterFormCheck()">{% csrf_token %} 20 {## ————————49PerfectCRM實現CRM客戶報名流程學生合同表單驗證————————#} 21 {% for foo in customer_form %} 22 <div class="form-group"> 23 <label for="inputEmail3" class="col-sm-2 control-label">{{ foo.label }}</label> 24 <div class="col-sm-8"> 25 {{ foo }} 26 </div> 27 </div> 28 {% endfor %} 29 <hr> 30 {#返回06學員報名信息表的數據#} 31 <div class="form-group"> 32 <label for="inputEmail3" class="col-sm-2 control-label">所報班級</label> 33 <div class="col-sm-8"> 34 {{ enroll_obj.enrolled_class }} 35 </div> 36 </div> 37 <div class="form-group"> 38 <label for="inputEmail3" class="col-sm-2 control-label">課程費用</label> 39 <div class="col-sm-8"> 40 {{ enroll_obj.enrolled_class.course.price }} 41 </div> 42 </div> 43 <div class="form-group"> 44 <label for="inputEmail3" class="col-sm-2 control-label">開課日期</label> 45 <div class="col-sm-8"> 46 {{ enroll_obj.enrolled_class.start_date }} 47 </div> 48 </div> 49 <div class="form-group"> 50 <label for="inputEmail3" class="col-sm-2 control-label">合同</label> 51 <div class="col-sm-10"> 52 <div style="width: 550px"> 53 <pre style="height: 300px">{% render_enrolled_contract enroll_obj %} </pre> 54 </div> 55 56 </div> 57 </div> 58 <div class="form-group"> 59 <div class="col-sm-12"> 60 <input type="checkbox" value="{{ enroll_obj.contract_agreed }}" name="contract_agreed" 61 checked> 62 我已經認真閱讀完協議並接受全部條款 63 </div> 64 </div> 65 <div class="text-center"> 66 <input type="submit" class="btn btn-info" value="提交"> 67 </div> 68 </form> 69 70 {## ————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片————————#} 71 <div class="row"> 72 <div class="col-xs-6 col-md-3"> 73 {% for img_file in img_file_list %} 74 <div class="right"> 75 <a href="#" class="thumbnail" name="{{ img_file }}"> 76 <img src="/static/enrolled_data/{{ enroll_id }}/{{ img_file }}" alt="..."> 77 </a> 78 <a class="del_img">刪除</a> 79 <span class="img_f hide">{{ img_file }}</span> 80 </div> 81 {% endfor %} 82 </div> 83 </div> 84 <p>請上傳身份證反面照片</p> 85 <form action="{{ request.path }}" class="dropzone form-group" id="filerdropzone" method="post" 86 enctype="multipart/form-data">{% csrf_token %} 87 88 <input type="hidden" name="file_id" ng-model="file_id" id="file_id"/> 89 </form> 90 {## ————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片————————#} 91 92 {## ————————49PerfectCRM實現CRM客戶報名流程學生合同表單驗證————————#} 93 {% else %} 94 <h3>報名成功,同合進入審覈流程,感謝您的選擇!</h3> 95 {% endif %} 96 {## ————————49PerfectCRM實現CRM客戶報名流程學生合同表單驗證————————#} 97 </div> 98 <div class="panel-footer"> 99 <input type="button" class="btn btn-danger right" value="關閉" onclick="CloseWebPage()"> 100 </div> 101 </div> 102 </div> 103 {% endblock %} 104 105 {% block js %} 106 <script> 107 function CloseWebPage() { 108 if (confirm("您肯定要關閉本頁嗎?")) { 109 window.opener = null; 110 window.open('', '_self'); 111 window.close(); 112 } 113 else { 114 } 115 } 116 117 {## ————————49PerfectCRM實現CRM客戶報名流程學生合同表單驗證————————#} 118 119 function RegisterFormCheck() { 120 {## ————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片————————#} 121 if (myDropzone.files.length < 2) { 122 alert('請上傳身份證正反面!2張!)'); 123 return false; 124 } 125 {## ————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片————————#} 126 if ($('form :checkbox').prop("checked")) { 127 $("form").find("[disabled]").removeAttr("disabled");//移除不可修改 便於提交表單 #qq 128 return true; 129 } else { 130 alert('請認真閱讀而且贊成條款,才能夠報名'); 131 return false; 132 } 133 } 134 135 {## ————————49PerfectCRM實現CRM客戶報名流程學生合同表單驗證————————#} 136 137 {## ————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片————————#} 138 {##————————cookies刪除文件JS事件————————#} 139 $('.del_img').click(function () { 140 s = $(this); 141 texts = s.parent().children("span").text(); 142 $.ajax({ 143 url: "{{ request.path }}", 144 type: "post", 145 data: {"data": texts}, 146 headers: {'X-CSRFtoken': $.cookie('csrftoken')}, 147 success: function (arg) { 148 if (arg) { 149 alert('刪除成功!'); 150 s.parent('div').addClass('hide'); 151 } 152 } 153 }) 154 }); 155 {##————————cookies刪除文件JS事件————————#} 156 {##————————dropzone上傳文件插件————————#} 157 Dropzone.autoDiscover = false; 158 appElement = document.querySelector('div .inmodal'); 159 myDropzone = new Dropzone("#filerdropzone", { 160 url: '{{ request.path }}',//路徑爲 當前頁 161 paramName: "file", //默認爲file 162 method: "post", 163 maxFilesize: 1,//MB 兆# 1048576字節 164 addRemoveLinks: true, 165 maxFiles: 2, 166 acceptedFiles: ".jpg,.gif,.png,.jpeg", //上傳的類型 167 uploadMultiple: true, 168 parallelUploads: 1,//一次上傳的文件數量 169 dictDefaultMessage: '請將照片拖到這裏或點擊上傳', 170 dictMaxFilesExceeded: "您最多隻能上傳2個文件!", 171 dictResponseError: '文件上傳失敗!', 172 dictInvalidFileType: "文件類型只能是*.zip,*.7z。", 173 dictFallbackMessage: "瀏覽器不受支持", 174 dictFileTooBig: "文件過大上傳文件最大支持.", 175 dictRemoveLinks: "刪除", 176 dictCancelUpload: "取消", 177 init: function () { 178 this.on("addedfile", function (file) { 179 //上傳文件時觸發的事件 180 document.querySelector('div .dz-default').style.display = 'none'; 181 }); 182 this.on("success", function (file, data) { 183 //上傳成功觸發的事件 184 console.log('ok'); 185 // angular.element(appElement).scope().file_id = data.data.id; 186 }); 187 this.on("error", function (file, data) { 188 //上傳失敗觸發的事件 189 console.log('fail'); 190 var message = ''; 191 //lavarel框架有一個表單驗證, 192 //對於ajax請求,JSON 響應會發送一個 422 HTTP 狀態碼, 193 //對應file.accepted的值是false,在這裏捕捉表單驗證的錯誤提示 194 if (file.accepted) { 195 $.each(data, function (key, val) { 196 message = message + val[0] + ';'; 197 }); 198 //控制器層面的錯誤提示,file.accepted = true的時候; 199 alert(message); 200 } 201 }); 202 this.on("removedfile", function (file) { 203 //刪除文件時觸發的方法 204 205 document.querySelector('div .dz-default').style.display = 'block'; 206 }); 207 } 208 }); 209 {##————————dropzone上傳文件插件————————#} 210 {## ————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片————————#} 211 </script> 212 213 214 215 {% endblock %} 216 {## ————————48PerfectCRM實現CRM客戶報名流程學生合同————————#}
1 /*! 2 * jQuery Cookie Plugin v1.4.1 3 * https://github.com/carhartl/jquery-cookie 4 * 5 * Copyright 2013 Klaus Hartl 6 * Released under the MIT license 7 */ 8 (function (factory) { 9 if (typeof define === 'function' && define.amd) { 10 // AMD 11 define(['jquery'], factory); 12 } else if (typeof exports === 'object') { 13 // CommonJS 14 factory(require('jquery')); 15 } else { 16 // Browser globals 17 factory(jQuery); 18 } 19 }(function ($) { 20 21 var pluses = /\+/g; 22 23 function encode(s) { 24 return config.raw ? s : encodeURIComponent(s); 25 } 26 27 function decode(s) { 28 return config.raw ? s : decodeURIComponent(s); 29 } 30 31 function stringifyCookieValue(value) { 32 return encode(config.json ? JSON.stringify(value) : String(value)); 33 } 34 35 function parseCookieValue(s) { 36 if (s.indexOf('"') === 0) { 37 // This is a quoted cookie as according to RFC2068, unescape... 38 s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); 39 } 40 41 try { 42 // Replace server-side written pluses with spaces. 43 // If we can't decode the cookie, ignore it, it's unusable. 44 // If we can't parse the cookie, ignore it, it's unusable. 45 s = decodeURIComponent(s.replace(pluses, ' ')); 46 return config.json ? JSON.parse(s) : s; 47 } catch(e) {} 48 } 49 50 function read(s, converter) { 51 var value = config.raw ? s : parseCookieValue(s); 52 return $.isFunction(converter) ? converter(value) : value; 53 } 54 55 var config = $.cookie = function (key, value, options) { 56 57 // Write 58 59 if (value !== undefined && !$.isFunction(value)) { 60 options = $.extend({}, config.defaults, options); 61 62 if (typeof options.expires === 'number') { 63 var days = options.expires, t = options.expires = new Date(); 64 t.setTime(+t + days * 864e+5); 65 } 66 67 return (document.cookie = [ 68 encode(key), '=', stringifyCookieValue(value), 69 options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE 70 options.path ? '; path=' + options.path : '', 71 options.domain ? '; domain=' + options.domain : '', 72 options.secure ? '; secure' : '' 73 ].join('')); 74 } 75 76 // Read 77 78 var result = key ? undefined : {}; 79 80 // To prevent the for loop in the first place assign an empty array 81 // in case there are no cookies at all. Also prevents odd result when 82 // calling $.cookie(). 83 var cookies = document.cookie ? document.cookie.split('; ') : []; 84 85 for (var i = 0, l = cookies.length; i < l; i++) { 86 var parts = cookies[i].split('='); 87 var name = decode(parts.shift()); 88 var cookie = parts.join('='); 89 90 if (key && key === name) { 91 // If second argument (value) is a function it's a converter... 92 result = read(cookie, value); 93 break; 94 } 95 96 // Prevent storing a cookie that we couldn't decode. 97 if (!key && (cookie = read(cookie)) !== undefined) { 98 result[name] = cookie; 99 } 100 } 101 102 return result; 103 }; 104 105 config.defaults = {}; 106 107 $.removeCookie = function (key, options) { 108 if ($.cookie(key) === undefined) { 109 return false; 110 } 111 112 // Must not alter options, thus extending a fresh object... 113 $.cookie(key, '', $.extend({}, options, { expires: -1 })); 114 return !$.cookie(key); 115 }; 116 117 }));
1 @-webkit-keyframes passing-through { 2 0% { 3 opacity: 0; 4 -webkit-transform: translateY(40px); 5 -moz-transform: translateY(40px); 6 -ms-transform: translateY(40px); 7 -o-transform: translateY(40px); 8 transform: translateY(40px); } 9 30%, 70% { 10 opacity: 1; 11 -webkit-transform: translateY(0px); 12 -moz-transform: translateY(0px); 13 -ms-transform: translateY(0px); 14 -o-transform: translateY(0px); 15 transform: translateY(0px); } 16 100% { 17 opacity: 0; 18 -webkit-transform: translateY(-40px); 19 -moz-transform: translateY(-40px); 20 -ms-transform: translateY(-40px); 21 -o-transform: translateY(-40px); 22 transform: translateY(-40px); } } 23 @-moz-keyframes passing-through { 24 0% { 25 opacity: 0; 26 -webkit-transform: translateY(40px); 27 -moz-transform: translateY(40px); 28 -ms-transform: translateY(40px); 29 -o-transform: translateY(40px); 30 transform: translateY(40px); } 31 30%, 70% { 32 opacity: 1; 33 -webkit-transform: translateY(0px); 34 -moz-transform: translateY(0px); 35 -ms-transform: translateY(0px); 36 -o-transform: translateY(0px); 37 transform: translateY(0px); } 38 100% { 39 opacity: 0; 40 -webkit-transform: translateY(-40px); 41 -moz-transform: translateY(-40px); 42 -ms-transform: translateY(-40px); 43 -o-transform: translateY(-40px); 44 transform: translateY(-40px); } } 45 @keyframes passing-through { 46 0% { 47 opacity: 0; 48 -webkit-transform: translateY(40px); 49 -moz-transform: translateY(40px); 50 -ms-transform: translateY(40px); 51 -o-transform: translateY(40px); 52 transform: translateY(40px); } 53 30%, 70% { 54 opacity: 1; 55 -webkit-transform: translateY(0px); 56 -moz-transform: translateY(0px); 57 -ms-transform: translateY(0px); 58 -o-transform: translateY(0px); 59 transform: translateY(0px); } 60 100% { 61 opacity: 0; 62 -webkit-transform: translateY(-40px); 63 -moz-transform: translateY(-40px); 64 -ms-transform: translateY(-40px); 65 -o-transform: translateY(-40px); 66 transform: translateY(-40px); } } 67 @-webkit-keyframes slide-in { 68 0% { 69 opacity: 0; 70 -webkit-transform: translateY(40px); 71 -moz-transform: translateY(40px); 72 -ms-transform: translateY(40px); 73 -o-transform: translateY(40px); 74 transform: translateY(40px); } 75 30% { 76 opacity: 1; 77 -webkit-transform: translateY(0px); 78 -moz-transform: translateY(0px); 79 -ms-transform: translateY(0px); 80 -o-transform: translateY(0px); 81 transform: translateY(0px); } } 82 @-moz-keyframes slide-in { 83 0% { 84 opacity: 0; 85 -webkit-transform: translateY(40px); 86 -moz-transform: translateY(40px); 87 -ms-transform: translateY(40px); 88 -o-transform: translateY(40px); 89 transform: translateY(40px); } 90 30% { 91 opacity: 1; 92 -webkit-transform: translateY(0px); 93 -moz-transform: translateY(0px); 94 -ms-transform: translateY(0px); 95 -o-transform: translateY(0px); 96 transform: translateY(0px); } } 97 @keyframes slide-in { 98 0% { 99 opacity: 0; 100 -webkit-transform: translateY(40px); 101 -moz-transform: translateY(40px); 102 -ms-transform: translateY(40px); 103 -o-transform: translateY(40px); 104 transform: translateY(40px); } 105 30% { 106 opacity: 1; 107 -webkit-transform: translateY(0px); 108 -moz-transform: translateY(0px); 109 -ms-transform: translateY(0px); 110 -o-transform: translateY(0px); 111 transform: translateY(0px); } } 112 @-webkit-keyframes pulse { 113 0% { 114 -webkit-transform: scale(1); 115 -moz-transform: scale(1); 116 -ms-transform: scale(1); 117 -o-transform: scale(1); 118 transform: scale(1); } 119 10% { 120 -webkit-transform: scale(1.1); 121 -moz-transform: scale(1.1); 122 -ms-transform: scale(1.1); 123 -o-transform: scale(1.1); 124 transform: scale(1.1); } 125 20% { 126 -webkit-transform: scale(1); 127 -moz-transform: scale(1); 128 -ms-transform: scale(1); 129 -o-transform: scale(1); 130 transform: scale(1); } } 131 @-moz-keyframes pulse { 132 0% { 133 -webkit-transform: scale(1); 134 -moz-transform: scale(1); 135 -ms-transform: scale(1); 136 -o-transform: scale(1); 137 transform: scale(1); } 138 10% { 139 -webkit-transform: scale(1.1); 140 -moz-transform: scale(1.1); 141 -ms-transform: scale(1.1); 142 -o-transform: scale(1.1); 143 transform: scale(1.1); } 144 20% { 145 -webkit-transform: scale(1); 146 -moz-transform: scale(1); 147 -ms-transform: scale(1); 148 -o-transform: scale(1); 149 transform: scale(1); } } 150 @keyframes pulse { 151 0% { 152 -webkit-transform: scale(1); 153 -moz-transform: scale(1); 154 -ms-transform: scale(1); 155 -o-transform: scale(1); 156 transform: scale(1); } 157 10% { 158 -webkit-transform: scale(1.1); 159 -moz-transform: scale(1.1); 160 -ms-transform: scale(1.1); 161 -o-transform: scale(1.1); 162 transform: scale(1.1); } 163 20% { 164 -webkit-transform: scale(1); 165 -moz-transform: scale(1); 166 -ms-transform: scale(1); 167 -o-transform: scale(1); 168 transform: scale(1); } } 169 .dropzone, .dropzone * { 170 box-sizing: border-box; } 171 172 .dropzone { 173 min-height: 150px; 174 border: 2px solid rgba(0, 0, 0, 0.3); 175 background: white; 176 padding: 54px 54px; } 177 .dropzone.dz-clickable { 178 cursor: pointer; } 179 .dropzone.dz-clickable * { 180 cursor: default; } 181 .dropzone.dz-clickable .dz-message, .dropzone.dz-clickable .dz-message * { 182 cursor: pointer; } 183 .dropzone.dz-started .dz-message { 184 display: none; } 185 .dropzone.dz-drag-hover { 186 border-style: solid; } 187 .dropzone.dz-drag-hover .dz-message { 188 opacity: 0.5; } 189 .dropzone .dz-message { 190 text-align: center; 191 margin: 2em 0; } 192 .dropzone .dz-preview { 193 position: relative; 194 display: inline-block; 195 vertical-align: top; 196 margin: 16px; 197 min-height: 100px; } 198 .dropzone .dz-preview:hover { 199 z-index: 1000; } 200 .dropzone .dz-preview:hover .dz-details { 201 opacity: 1; } 202 .dropzone .dz-preview.dz-file-preview .dz-image { 203 border-radius: 20px; 204 background: #999; 205 background: linear-gradient(to bottom, #eee, #ddd); } 206 .dropzone .dz-preview.dz-file-preview .dz-details { 207 opacity: 1; } 208 .dropzone .dz-preview.dz-image-preview { 209 background: white; } 210 .dropzone .dz-preview.dz-image-preview .dz-details { 211 -webkit-transition: opacity 0.2s linear; 212 -moz-transition: opacity 0.2s linear; 213 -ms-transition: opacity 0.2s linear; 214 -o-transition: opacity 0.2s linear; 215 transition: opacity 0.2s linear; } 216 .dropzone .dz-preview .dz-remove { 217 font-size: 14px; 218 text-align: center; 219 display: block; 220 cursor: pointer; 221 border: none; } 222 .dropzone .dz-preview .dz-remove:hover { 223 text-decoration: underline; } 224 .dropzone .dz-preview:hover .dz-details { 225 opacity: 1; } 226 .dropzone .dz-preview .dz-details { 227 z-index: 20; 228 position: absolute; 229 top: 0; 230 left: 0; 231 opacity: 0; 232 font-size: 13px; 233 min-width: 100%; 234 max-width: 100%; 235 padding: 2em 1em; 236 text-align: center; 237 color: rgba(0, 0, 0, 0.9); 238 line-height: 150%; } 239 .dropzone .dz-preview .dz-details .dz-size { 240 margin-bottom: 1em; 241 font-size: 16px; } 242 .dropzone .dz-preview .dz-details .dz-filename { 243 white-space: nowrap; } 244 .dropzone .dz-preview .dz-details .dz-filename:hover span { 245 border: 1px solid rgba(200, 200, 200, 0.8); 246 background-color: rgba(255, 255, 255, 0.8); } 247 .dropzone .dz-preview .dz-details .dz-filename:not(:hover) { 248 overflow: hidden; 249 text-overflow: ellipsis; } 250 .dropzone .dz-preview .dz-details .dz-filename:not(:hover) span { 251 border: 1px solid transparent; } 252 .dropzone .dz-preview .dz-details .dz-filename span, .dropzone .dz-preview .dz-details .dz-size span { 253 background-color: rgba(255, 255, 255, 0.4); 254 padding: 0 0.4em; 255 border-radius: 3px; } 256 .dropzone .dz-preview:hover .dz-image img { 257 -webkit-transform: scale(1.05, 1.05); 258 -moz-transform: scale(1.05, 1.05); 259 -ms-transform: scale(1.05, 1.05); 260 -o-transform: scale(1.05, 1.05); 261 transform: scale(1.05, 1.05); 262 -webkit-filter: blur(8px); 263 filter: blur(8px); } 264 .dropzone .dz-preview .dz-image { 265 border-radius: 20px; 266 overflow: hidden; 267 width: 120px; 268 height: 120px; 269 position: relative; 270 display: block; 271 z-index: 10; } 272 .dropzone .dz-preview .dz-image img { 273 display: block; } 274 .dropzone .dz-preview.dz-success .dz-success-mark { 275 -webkit-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); 276 -moz-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); 277 -ms-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); 278 -o-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); 279 animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); } 280 .dropzone .dz-preview.dz-error .dz-error-mark { 281 opacity: 1; 282 -webkit-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); 283 -moz-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); 284 -ms-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); 285 -o-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); 286 animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); } 287 .dropzone .dz-preview .dz-success-mark, .dropzone .dz-preview .dz-error-mark { 288 pointer-events: none; 289 opacity: 0; 290 z-index: 500; 291 position: absolute; 292 display: block; 293 top: 50%; 294 left: 50%; 295 margin-left: -27px; 296 margin-top: -27px; } 297 .dropzone .dz-preview .dz-success-mark svg, .dropzone .dz-preview .dz-error-mark svg { 298 display: block; 299 width: 54px; 300 height: 54px; } 301 .dropzone .dz-preview.dz-processing .dz-progress { 302 opacity: 1; 303 -webkit-transition: all 0.2s linear; 304 -moz-transition: all 0.2s linear; 305 -ms-transition: all 0.2s linear; 306 -o-transition: all 0.2s linear; 307 transition: all 0.2s linear; } 308 .dropzone .dz-preview.dz-complete .dz-progress { 309 opacity: 0; 310 -webkit-transition: opacity 0.4s ease-in; 311 -moz-transition: opacity 0.4s ease-in; 312 -ms-transition: opacity 0.4s ease-in; 313 -o-transition: opacity 0.4s ease-in; 314 transition: opacity 0.4s ease-in; } 315 .dropzone .dz-preview:not(.dz-processing) .dz-progress { 316 -webkit-animation: pulse 6s ease infinite; 317 -moz-animation: pulse 6s ease infinite; 318 -ms-animation: pulse 6s ease infinite; 319 -o-animation: pulse 6s ease infinite; 320 animation: pulse 6s ease infinite; } 321 .dropzone .dz-preview .dz-progress { 322 opacity: 1; 323 z-index: 1000; 324 pointer-events: none; 325 position: absolute; 326 height: 16px; 327 left: 50%; 328 top: 50%; 329 margin-top: -8px; 330 width: 80px; 331 margin-left: -40px; 332 background: rgba(255, 255, 255, 0.9); 333 -webkit-transform: scale(1); 334 border-radius: 8px; 335 overflow: hidden; } 336 .dropzone .dz-preview .dz-progress .dz-upload { 337 background: #333; 338 background: linear-gradient(to bottom, #666, #444); 339 position: absolute; 340 top: 0; 341 left: 0; 342 bottom: 0; 343 width: 0; 344 -webkit-transition: width 300ms ease-in-out; 345 -moz-transition: width 300ms ease-in-out; 346 -ms-transition: width 300ms ease-in-out; 347 -o-transition: width 300ms ease-in-out; 348 transition: width 300ms ease-in-out; } 349 .dropzone .dz-preview.dz-error .dz-error-message { 350 display: block; } 351 .dropzone .dz-preview.dz-error:hover .dz-error-message { 352 opacity: 1; 353 pointer-events: auto; } 354 .dropzone .dz-preview .dz-error-message { 355 pointer-events: none; 356 z-index: 1000; 357 position: absolute; 358 display: block; 359 display: none; 360 opacity: 0; 361 -webkit-transition: opacity 0.3s ease; 362 -moz-transition: opacity 0.3s ease; 363 -ms-transition: opacity 0.3s ease; 364 -o-transition: opacity 0.3s ease; 365 transition: opacity 0.3s ease; 366 border-radius: 8px; 367 font-size: 13px; 368 top: 130px; 369 left: -10px; 370 width: 140px; 371 background: #be2626; 372 background: linear-gradient(to bottom, #be2626, #a92222); 373 padding: 0.5em 1.2em; 374 color: white; } 375 .dropzone .dz-preview .dz-error-message:after { 376 content: ''; 377 position: absolute; 378 top: -6px; 379 left: 64px; 380 width: 0; 381 height: 0; 382 border-left: 6px solid transparent; 383 border-right: 6px solid transparent; 384 border-bottom: 6px solid #be2626; }
1 /* 2 * 3 * More info at [www.dropzonejs.com](http://www.dropzonejs.com) 4 * 5 * Copyright (c) 2012, Matias Meno 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 * THE SOFTWARE. 24 * 25 * *特此授予許可,免費的,任何的人得到一份 26 *這個軟件和相關文檔的文件(「軟件」),交易 27 *在軟件沒有限制,包括但不限於權利 28 *使用、複製、修改、合併、出版、發行、有償和/或出售 29 *軟件的副本,並容許他們的軟件 30 *提供,應當具有下列條件: 31 * 32 *上述版權聲明和本許可聲明應當包含在 33 *全部副本或實質性部分的軟件。 34 * 35 *提供的軟件是「是」,沒有任何類型的保證,明示或 36 *暗示的保證,包括但不限於適銷性的保證, 37 *健身爲特定目的和無侵犯。在任何事件應當的 38 *做者或版權全部者承擔任何索賠、損害或其餘 39 *責任,不管是在一個動做的合同,侵權或不然,因, 40 *在鏈接或WI 41 42 */ 43 44 (function() { 45 var Dropzone, Emitter, ExifRestore, camelize, contentLoaded, detectVerticalSquash, drawImageIOSFix, noop, without, 46 slice = [].slice, 47 extend1 = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 48 hasProp = {}.hasOwnProperty; 49 50 noop = function() {}; 51 52 Emitter = (function() { 53 function Emitter() {} 54 55 Emitter.prototype.addEventListener = Emitter.prototype.on; 56 57 Emitter.prototype.on = function(event, fn) { 58 this._callbacks = this._callbacks || {}; 59 if (!this._callbacks[event]) { 60 this._callbacks[event] = []; 61 } 62 this._callbacks[event].push(fn); 63 return this; 64 }; 65 66 Emitter.prototype.emit = function() { 67 var args, callback, callbacks, event, j, len; 68 event = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; 69 this._callbacks = this._callbacks || {}; 70 callbacks = this._callbacks[event]; 71 if (callbacks) { 72 for (j = 0, len = callbacks.length; j < len; j++) { 73 callback = callbacks[j]; 74 callback.apply(this, args); 75 } 76 } 77 return this; 78 }; 79 80 Emitter.prototype.removeListener = Emitter.prototype.off; 81 82 Emitter.prototype.removeAllListeners = Emitter.prototype.off; 83 84 Emitter.prototype.removeEventListener = Emitter.prototype.off; 85 86 Emitter.prototype.off = function(event, fn) { 87 var callback, callbacks, i, j, len; 88 if (!this._callbacks || arguments.length === 0) { 89 this._callbacks = {}; 90 return this; 91 } 92 callbacks = this._callbacks[event]; 93 if (!callbacks) { 94 return this; 95 } 96 if (arguments.length === 1) { 97 delete this._callbacks[event]; 98 return this; 99 } 100 for (i = j = 0, len = callbacks.length; j < len; i = ++j) { 101 callback = callbacks[i]; 102 if (callback === fn) { 103 callbacks.splice(i, 1); 104 break; 105 } 106 } 107 return this; 108 }; 109 110 return Emitter; 111 112 })(); 113 114 Dropzone = (function(superClass) { 115 var extend, resolveOption; 116 117 extend1(Dropzone, superClass); 118 119 Dropzone.prototype.Emitter = Emitter; 120 121 122 /* 123 This is a list of all available events you can register on a dropzone object. 124 125 You can register an event handler like this: 126 127 dropzone.on("dragEnter", function() { }); 128 */ 129 130 Dropzone.prototype.events = ["drop", "dragstart", "dragend", "dragenter", "dragover", "dragleave", "addedfile", "addedfiles", "removedfile", "thumbnail", "error", "errormultiple", "processing", "processingmultiple", "uploadprogress", "totaluploadprogress", "sending", "sendingmultiple", "success", "successmultiple", "canceled", "canceledmultiple", "complete", "completemultiple", "reset", "maxfilesexceeded", "maxfilesreached", "queuecomplete"]; 131 132 Dropzone.prototype.defaultOptions = { 133 url: null, 134 method: "post", 135 withCredentials: false, 136 timeout: 30000, 137 parallelUploads: 2, 138 uploadMultiple: false, 139 maxFilesize: 256, 140 paramName: "file", 141 createImageThumbnails: true, 142 maxThumbnailFilesize: 10, 143 thumbnailWidth: 120, 144 thumbnailHeight: 120, 145 thumbnailMethod: 'crop', 146 resizeWidth: null, 147 resizeHeight: null, 148 resizeMimeType: null, 149 resizeQuality: 0.8, 150 resizeMethod: 'contain', 151 filesizeBase: 1000, 152 maxFiles: null, 153 params: {}, 154 headers: null, 155 clickable: true, 156 ignoreHiddenFiles: true, 157 acceptedFiles: null, 158 acceptedMimeTypes: null, 159 autoProcessQueue: true, 160 autoQueue: true, 161 addRemoveLinks: false, 162 previewsContainer: null, 163 hiddenInputContainer: "body", 164 capture: null, 165 renameFilename: null, 166 renameFile: null, 167 forceFallback: false, 168 dictDefaultMessage: "Drop files here to upload", 169 dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.", 170 dictFallbackText: "Please use the fallback form below to upload your files like in the olden days.", 171 dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.", 172 dictInvalidFileType: "You can't upload files of this type.", 173 dictResponseError: "Server responded with {{statusCode}} code.", 174 dictCancelUpload: "Cancel upload", 175 dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?", 176 dictRemoveFile: "Remove file", 177 dictRemoveFileConfirmation: null, 178 dictMaxFilesExceeded: "You can not upload any more files.", 179 dictFileSizeUnits: { 180 tb: "TB", 181 gb: "GB", 182 mb: "MB", 183 kb: "KB", 184 b: "b" 185 }, 186 init: function() { 187 return noop; 188 }, 189 accept: function(file, done) { 190 return done(); 191 }, 192 fallback: function() { 193 var child, j, len, messageElement, ref, span; 194 this.element.className = this.element.className + " dz-browser-not-supported"; 195 ref = this.element.getElementsByTagName("div"); 196 for (j = 0, len = ref.length; j < len; j++) { 197 child = ref[j]; 198 if (/(^| )dz-message($| )/.test(child.className)) { 199 messageElement = child; 200 child.className = "dz-message"; 201 continue; 202 } 203 } 204 if (!messageElement) { 205 messageElement = Dropzone.createElement("<div class=\"dz-message\"><span></span></div>"); 206 this.element.appendChild(messageElement); 207 } 208 span = messageElement.getElementsByTagName("span")[0]; 209 if (span) { 210 if (span.textContent != null) { 211 span.textContent = this.options.dictFallbackMessage; 212 } else if (span.innerText != null) { 213 span.innerText = this.options.dictFallbackMessage; 214 } 215 } 216 return this.element.appendChild(this.getFallbackForm()); 217 }, 218 resize: function(file, width, height, resizeMethod) { 219 var info, srcRatio, trgRatio; 220 info = { 221 srcX: 0, 222 srcY: 0, 223 srcWidth: file.width, 224 srcHeight: file.height 225 }; 226 srcRatio = file.width / file.height; 227 if ((width == null) && (height == null)) { 228 width = info.srcWidth; 229 height = info.srcHeight; 230 } else if (width == null) { 231 width = height * srcRatio; 232 } else if (height == null) { 233 height = width / srcRatio; 234 } 235 width = Math.min(width, info.srcWidth); 236 height = Math.min(height, info.srcHeight); 237 trgRatio = width / height; 238 if (info.srcWidth > width || info.srcHeight > height) { 239 if (resizeMethod === 'crop') { 240 if (srcRatio > trgRatio) { 241 info.srcHeight = file.height; 242 info.srcWidth = info.srcHeight * trgRatio; 243 } else { 244 info.srcWidth = file.width; 245 info.srcHeight = info.srcWidth / trgRatio; 246 } 247 } else if (resizeMethod === 'contain') { 248 if (srcRatio > trgRatio) { 249 height = width / srcRatio; 250 } else { 251 width = height * srcRatio; 252 } 253 } else { 254 throw new Error("Unknown resizeMethod '" + resizeMethod + "'"); 255 } 256 } 257 info.srcX = (file.width - info.srcWidth) / 2; 258 info.srcY = (file.height - info.srcHeight) / 2; 259 info.trgWidth = width; 260 info.trgHeight = height; 261 return info; 262 }, 263 transformFile: function(file, done) { 264 if ((this.options.resizeWidth || this.options.resizeHeight) && file.type.match(/image.*/)) { 265 return this.resizeImage(file, this.options.resizeWidth, this.options.resizeHeight, this.options.resizeMethod, done); 266 } else { 267 return done(file); 268 } 269 }, 270 previewTemplate: "<div class=\"dz-preview dz-file-preview\">\n <div class=\"dz-image\"><img data-dz-thumbnail /></div>\n <div class=\"dz-details\">\n <div class=\"dz-size\"><span data-dz-size></span></div>\n <div class=\"dz-filename\"><span data-dz-name></span></div>\n </div>\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress></span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n <div class=\"dz-success-mark\">\n <svg width=\"54px\" height=\"54px\" viewBox=\"0 0 54 54\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\">\n <title>Check</title>\n <defs></defs>\n <g id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\">\n <path d=\"M23.5,31.8431458 L17.5852419,25.9283877 C16.0248253,24.3679711 13.4910294,24.366835 11.9289322,25.9289322 C10.3700136,27.4878508 10.3665912,30.0234455 11.9283877,31.5852419 L20.4147581,40.0716123 C20.5133999,40.1702541 20.6159315,40.2626649 20.7218615,40.3488435 C22.2835669,41.8725651 24.794234,41.8626202 26.3461564,40.3106978 L43.3106978,23.3461564 C44.8771021,21.7797521 44.8758057,19.2483887 43.3137085,17.6862915 C41.7547899,16.1273729 39.2176035,16.1255422 37.6538436,17.6893022 L23.5,31.8431458 Z M27,53 C41.3594035,53 53,41.3594035 53,27 C53,12.6405965 41.3594035,1 27,1 C12.6405965,1 1,12.6405965 1,27 C1,41.3594035 12.6405965,53 27,53 Z\" id=\"Oval-2\" stroke-opacity=\"0.198794158\" stroke=\"#747474\" fill-opacity=\"0.816519475\" fill=\"#FFFFFF\" sketch:type=\"MSShapeGroup\"></path>\n </g>\n </svg>\n </div>\n <div class=\"dz-error-mark\">\n <svg width=\"54px\" height=\"54px\" viewBox=\"0 0 54 54\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\">\n <title>Error</title>\n <defs></defs>\n <g id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\">\n <g id=\"Check-+-Oval-2\" sketch:type=\"MSLayerGroup\" stroke=\"#747474\" stroke-opacity=\"0.198794158\" fill=\"#FFFFFF\" fill-opacity=\"0.816519475\">\n <path d=\"M32.6568542,29 L38.3106978,23.3461564 C39.8771021,21.7797521 39.8758057,19.2483887 38.3137085,17.6862915 C36.7547899,16.1273729 34.2176035,16.1255422 32.6538436,17.6893022 L27,23.3431458 L21.3461564,17.6893022 C19.7823965,16.1255422 17.2452101,16.1273729 15.6862915,17.6862915 C14.1241943,19.2483887 14.1228979,21.7797521 15.6893022,23.3461564 L21.3431458,29 L15.6893022,34.6538436 C14.1228979,36.2202479 14.1241943,38.7516113 15.6862915,40.3137085 C17.2452101,41.8726271 19.7823965,41.8744578 21.3461564,40.3106978 L27,34.6568542 L32.6538436,40.3106978 C34.2176035,41.8744578 36.7547899,41.8726271 38.3137085,40.3137085 C39.8758057,38.7516113 39.8771021,36.2202479 38.3106978,34.6538436 L32.6568542,29 Z M27,53 C41.3594035,53 53,41.3594035 53,27 C53,12.6405965 41.3594035,1 27,1 C12.6405965,1 1,12.6405965 1,27 C1,41.3594035 12.6405965,53 27,53 Z\" id=\"Oval-2\" sketch:type=\"MSShapeGroup\"></path>\n </g>\n </g>\n </svg>\n </div>\n</div>", 271 272 /* 273 Those functions register themselves to the events on init and handle all 274 the user interface specific stuff. Overwriting them won't break the upload 275 but can break the way it's displayed. 276 You can overwrite them if you don't like the default behavior. If you just 277 want to add an additional event handler, register it on the dropzone object 278 and don't overwrite those options. 279 */ 280 drop: function(e) { 281 return this.element.classList.remove("dz-drag-hover"); 282 }, 283 dragstart: noop, 284 dragend: function(e) { 285 return this.element.classList.remove("dz-drag-hover"); 286 }, 287 dragenter: function(e) { 288 return this.element.classList.add("dz-drag-hover"); 289 }, 290 dragover: function(e) { 291 return this.element.classList.add("dz-drag-hover"); 292 }, 293 dragleave: function(e) { 294 return this.element.classList.remove("dz-drag-hover"); 295 }, 296 paste: noop, 297 reset: function() { 298 return this.element.classList.remove("dz-started"); 299 }, 300 addedfile: function(file) { 301 var j, k, l, len, len1, len2, node, ref, ref1, ref2, removeFileEvent, removeLink, results; 302 if (this.element === this.previewsContainer) { 303 this.element.classList.add("dz-started"); 304 } 305 if (this.previewsContainer) { 306 file.previewElement = Dropzone.createElement(this.options.previewTemplate.trim()); 307 file.previewTemplate = file.previewElement; 308 this.previewsContainer.appendChild(file.previewElement); 309 ref = file.previewElement.querySelectorAll("[data-dz-name]"); 310 for (j = 0, len = ref.length; j < len; j++) { 311 node = ref[j]; 312 node.textContent = file.name; 313 } 314 ref1 = file.previewElement.querySelectorAll("[data-dz-size]"); 315 for (k = 0, len1 = ref1.length; k < len1; k++) { 316 node = ref1[k]; 317 node.innerHTML = this.filesize(file.size); 318 } 319 if (this.options.addRemoveLinks) { 320 file._removeLink = Dropzone.createElement("<a class=\"dz-remove\" href=\"javascript:undefined;\" data-dz-remove>" + this.options.dictRemoveFile + "</a>"); 321 file.previewElement.appendChild(file._removeLink); 322 } 323 removeFileEvent = (function(_this) { 324 return function(e) { 325 e.preventDefault(); 326 e.stopPropagation(); 327 if (file.status === Dropzone.UPLOADING) { 328 return Dropzone.confirm(_this.options.dictCancelUploadConfirmation, function() { 329 return _this.removeFile(file); 330 }); 331 } else { 332 if (_this.options.dictRemoveFileConfirmation) { 333 return Dropzone.confirm(_this.options.dictRemoveFileConfirmation, function() { 334 return _this.removeFile(file); 335 }); 336 } else { 337 return _this.removeFile(file); 338 } 339 } 340 }; 341 })(this); 342 ref2 = file.previewElement.querySelectorAll("[data-dz-remove]"); 343 results = []; 344 for (l = 0, len2 = ref2.length; l < len2; l++) { 345 removeLink = ref2[l]; 346 results.push(removeLink.addEventListener("click", removeFileEvent)); 347 } 348 return results; 349 } 350 }, 351 removedfile: function(file) { 352 var ref; 353 if (file.previewElement) { 354 if ((ref = file.previewElement) != null) { 355 ref.parentNode.removeChild(file.previewElement); 356 } 357 } 358 return this._updateMaxFilesReachedClass(); 359 }, 360 thumbnail: function(file, dataUrl) { 361 var j, len, ref, thumbnailElement; 362 if (file.previewElement) { 363 file.previewElement.classList.remove("dz-file-preview"); 364 ref = file.previewElement.querySelectorAll("[data-dz-thumbnail]"); 365 for (j = 0, len = ref.length; j < len; j++) { 366 thumbnailElement = ref[j]; 367 thumbnailElement.alt = file.name; 368 thumbnailElement.src = dataUrl; 369 } 370 return setTimeout(((function(_this) { 371 return function() { 372 return file.previewElement.classList.add("dz-image-preview"); 373 }; 374 })(this)), 1); 375 } 376 }, 377 error: function(file, message) { 378 var j, len, node, ref, results; 379 if (file.previewElement) { 380 file.previewElement.classList.add("dz-error"); 381 if (typeof message !== "String" && message.error) { 382 message = message.error; 383 } 384 ref = file.previewElement.querySelectorAll("[data-dz-errormessage]"); 385 results = []; 386 for (j = 0, len = ref.length; j < len; j++) { 387 node = ref[j]; 388 results.push(node.textContent = message); 389 } 390 return results; 391 } 392 }, 393 errormultiple: noop, 394 processing: function(file) { 395 if (file.previewElement) { 396 file.previewElement.classList.add("dz-processing"); 397 if (file._removeLink) { 398 return file._removeLink.textContent = this.options.dictCancelUpload; 399 } 400 } 401 }, 402 processingmultiple: noop, 403 uploadprogress: function(file, progress, bytesSent) { 404 var j, len, node, ref, results; 405 if (file.previewElement) { 406 ref = file.previewElement.querySelectorAll("[data-dz-uploadprogress]"); 407 results = []; 408 for (j = 0, len = ref.length; j < len; j++) { 409 node = ref[j]; 410 if (node.nodeName === 'PROGRESS') { 411 results.push(node.value = progress); 412 } else { 413 results.push(node.style.width = progress + "%"); 414 } 415 } 416 return results; 417 } 418 }, 419 totaluploadprogress: noop, 420 sending: noop, 421 sendingmultiple: noop, 422 success: function(file) { 423 if (file.previewElement) { 424 return file.previewElement.classList.add("dz-success"); 425 } 426 }, 427 successmultiple: noop, 428 canceled: function(file) { 429 return this.emit("error", file, "Upload canceled."); 430 }, 431 canceledmultiple: noop, 432 complete: function(file) { 433 if (file._removeLink) { 434 file._removeLink.textContent = this.options.dictRemoveFile; 435 } 436 if (file.previewElement) { 437 return file.previewElement.classList.add("dz-complete"); 438 } 439 }, 440 completemultiple: noop, 441 maxfilesexceeded: noop, 442 maxfilesreached: noop, 443 queuecomplete: noop, 444 addedfiles: noop 445 }; 446 447 extend = function() { 448 var j, key, len, object, objects, target, val; 449 target = arguments[0], objects = 2 <= arguments.length ? slice.call(arguments, 1) : []; 450 for (j = 0, len = objects.length; j < len; j++) { 451 object = objects[j]; 452 for (key in object) { 453 val = object[key]; 454 target[key] = val; 455 } 456 } 457 return target; 458 }; 459 460 function Dropzone(element1, options) { 461 var elementOptions, fallback, ref; 462 this.element = element1; 463 this.version = Dropzone.version; 464 this.defaultOptions.previewTemplate = this.defaultOptions.previewTemplate.replace(/\n*/g, ""); 465 this.clickableElements = []; 466 this.listeners = []; 467 this.files = []; 468 if (typeof this.element === "string") { 469 this.element = document.querySelector(this.element); 470 } 471 if (!(this.element && (this.element.nodeType != null))) { 472 throw new Error("Invalid dropzone element."); 473 } 474 if (this.element.dropzone) { 475 throw new Error("Dropzone already attached."); 476 } 477 Dropzone.instances.push(this); 478 this.element.dropzone = this; 479 elementOptions = (ref = Dropzone.optionsForElement(this.element)) != null ? ref : {}; 480 this.options = extend({}, this.defaultOptions, elementOptions, options != null ? options : {}); 481 if (this.options.forceFallback || !Dropzone.isBrowserSupported()) { 482 return this.options.fallback.call(this); 483 } 484 if (this.options.url == null) { 485 this.options.url = this.element.getAttribute("action"); 486 } 487 if (!this.options.url) { 488 throw new Error("No URL provided."); 489 } 490 if (this.options.acceptedFiles && this.options.acceptedMimeTypes) { 491 throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated."); 492 } 493 if (this.options.acceptedMimeTypes) { 494 this.options.acceptedFiles = this.options.acceptedMimeTypes; 495 delete this.options.acceptedMimeTypes; 496 } 497 if (this.options.renameFilename != null) { 498 this.options.renameFile = (function(_this) { 499 return function(file) { 500 return _this.options.renameFilename.call(_this, file.name, file); 501 }; 502 })(this); 503 } 504 this.options.method = this.options.method.toUpperCase(); 505 if ((fallback = this.getExistingFallback()) && fallback.parentNode) { 506 fallback.parentNode.removeChild(fallback); 507 } 508 if (this.options.previewsContainer !== false) { 509 if (this.options.previewsContainer) { 510 this.previewsContainer = Dropzone.getElement(this.options.previewsContainer, "previewsContainer"); 511 } else { 512 this.previewsContainer = this.element; 513 } 514 } 515 if (this.options.clickable) { 516 if (this.options.clickable === true) { 517 this.clickableElements = [this.element]; 518 } else { 519 this.clickableElements = Dropzone.getElements(this.options.clickable, "clickable"); 520 } 521 } 522 this.init(); 523 } 524 525 Dropzone.prototype.getAcceptedFiles = function() { 526 var file, j, len, ref, results; 527 ref = this.files; 528 results = []; 529 for (j = 0, len = ref.length; j < len; j++) { 530 file = ref[j]; 531 if (file.accepted) { 532 results.push(file); 533 } 534 } 535 return results; 536 }; 537 538 Dropzone.prototype.getRejectedFiles = function() { 539 var file, j, len, ref, results; 540 ref = this.files; 541 results = []; 542 for (j = 0, len = ref.length; j < len; j++) { 543 file = ref[j]; 544 if (!file.accepted) { 545 results.push(file); 546 } 547 } 548 return results; 549 }; 550 551 Dropzone.prototype.getFilesWithStatus = function(status) { 552 var file, j, len, ref, results; 553 ref = this.files; 554 results = []; 555 for (j = 0, len = ref.length; j < len; j++) { 556 file = ref[j]; 557 if (file.status === status) { 558 results.push(file); 559 } 560 } 561 return results; 562 }; 563 564 Dropzone.prototype.getQueuedFiles = function() { 565 return this.getFilesWithStatus(Dropzone.QUEUED); 566 }; 567 568 Dropzone.prototype.getUploadingFiles = function() { 569 return this.getFilesWithStatus(Dropzone.UPLOADING); 570 }; 571 572 Dropzone.prototype.getAddedFiles = function() { 573 return this.getFilesWithStatus(Dropzone.ADDED); 574 }; 575 576 Dropzone.prototype.getActiveFiles = function() { 577 var file, j, len, ref, results; 578 ref = this.files; 579 results = []; 580 for (j = 0, len = ref.length; j < len; j++) { 581 file = ref[j]; 582 if (file.status === Dropzone.UPLOADING || file.status === Dropzone.QUEUED) { 583 results.push(file); 584 } 585 } 586 return results; 587 }; 588 589 Dropzone.prototype.init = function() { 590 var eventName, j, len, noPropagation, ref, ref1, setupHiddenFileInput; 591 if (this.element.tagName === "form") { 592 this.element.setAttribute("enctype", "multipart/form-data"); 593 } 594 if (this.element.classList.contains("dropzone") && !this.element.querySelector(".dz-message")) { 595 this.element.appendChild(Dropzone.createElement("<div class=\"dz-default dz-message\"><span>" + this.options.dictDefaultMessage + "</span></div>")); 596 } 597 if (this.clickableElements.length) { 598 setupHiddenFileInput = (function(_this) { 599 return function() { 600 if (_this.hiddenFileInput) { 601 _this.hiddenFileInput.parentNode.removeChild(_this.hiddenFileInput); 602 } 603 _this.hiddenFileInput = document.createElement("input"); 604 _this.hiddenFileInput.setAttribute("type", "file"); 605 if ((_this.options.maxFiles == null) || _this.options.maxFiles > 1) { 606 _this.hiddenFileInput.setAttribute("multiple", "multiple"); 607 } 608 _this.hiddenFileInput.className = "dz-hidden-input"; 609 if (_this.options.acceptedFiles != null) { 610 _this.hiddenFileInput.setAttribute("accept", _this.options.acceptedFiles); 611 } 612 if (_this.options.capture != null) { 613 _this.hiddenFileInput.setAttribute("capture", _this.options.capture); 614 } 615 _this.hiddenFileInput.style.visibility = "hidden"; 616 _this.hiddenFileInput.style.position = "absolute"; 617 _this.hiddenFileInput.style.top = "0"; 618 _this.hiddenFileInput.style.left = "0"; 619 _this.hiddenFileInput.style.height = "0"; 620 _this.hiddenFileInput.style.width = "0"; 621 document.querySelector(_this.options.hiddenInputContainer).appendChild(_this.hiddenFileInput); 622 return _this.hiddenFileInput.addEventListener("change", function() { 623 var file, files, j, len; 624 files = _this.hiddenFileInput.files; 625 if (files.length) { 626 for (j = 0, len = files.length; j < len; j++) { 627 file = files[j]; 628 _this.addFile(file); 629 } 630 } 631 _this.emit("addedfiles", files); 632 return setupHiddenFileInput(); 633 }); 634 }; 635 })(this); 636 setupHiddenFileInput(); 637 } 638 this.URL = (ref = window.URL) != null ? ref : window.webkitURL; 639 ref1 = this.events; 640 for (j = 0, len = ref1.length; j < len; j++) { 641 eventName = ref1[j]; 642 this.on(eventName, this.options[eventName]); 643 } 644 this.on("uploadprogress", (function(_this) { 645 return function() { 646 return _this.updateTotalUploadProgress(); 647 }; 648 })(this)); 649 this.on("removedfile", (function(_this) { 650 return function() { 651 return _this.updateTotalUploadProgress(); 652 }; 653 })(this)); 654 this.on("canceled", (function(_this) { 655 return function(file) { 656 return _this.emit("complete", file); 657 }; 658 })(this)); 659 this.on("complete", (function(_this) { 660 return function(file) { 661 if (_this.getAddedFiles().length === 0 && _this.getUploadingFiles().length === 0 && _this.getQueuedFiles().length === 0) { 662 return setTimeout((function() { 663 return _this.emit("queuecomplete"); 664 }), 0); 665 } 666 }; 667 })(this)); 668 noPropagation = function(e) { 669 e.stopPropagation(); 670 if (e.preventDefault) { 671 return e.preventDefault(); 672 } else { 673 return e.returnValue = false; 674 } 675 }; 676 this.listeners = [ 677 { 678 element: this.element, 679 events: { 680 "dragstart": (function(_this) { 681 return function(e) { 682 return _this.emit("dragstart", e); 683 }; 684 })(this), 685 "dragenter": (function(_this) { 686 return function(e) { 687 noPropagation(e); 688 return _this.emit("dragenter", e); 689 }; 690 })(this), 691 "dragover": (function(_this) { 692 return function(e) { 693 var efct; 694 try { 695 efct = e.dataTransfer.effectAllowed; 696 } catch (undefined) {} 697 e.dataTransfer.dropEffect = 'move' === efct || 'linkMove' === efct ? 'move' : 'copy'; 698 noPropagation(e); 699 return _this.emit("dragover", e); 700 }; 701 })(this), 702 "dragleave": (function(_this) { 703 return function(e) { 704 return _this.emit("dragleave", e); 705 }; 706 })(this), 707 "drop": (function(_this) { 708 return function(e) { 709 noPropagation(e); 710 return _this.drop(e); 711 }; 712 })(this), 713 "dragend": (function(_this) { 714 return function(e) { 715 return _this.emit("dragend", e); 716 }; 717 })(this) 718 } 719 } 720 ]; 721 this.clickableElements.forEach((function(_this) { 722 return function(clickableElement) { 723 return _this.listeners.push({ 724 element: clickableElement, 725 events: { 726 "click": function(evt) { 727 if ((clickableElement !== _this.element) || (evt.target === _this.element || Dropzone.elementInside(evt.target, _this.element.querySelector(".dz-message")))) { 728 _this.hiddenFileInput.click(); 729 } 730 return true; 731 } 732 } 733 }); 734 }; 735 })(this)); 736 this.enable(); 737 return this.options.init.call(this); 738 }; 739 740 Dropzone.prototype.destroy = function() { 741 var ref; 742 this.disable(); 743 this.removeAllFiles(true); 744 if ((ref = this.hiddenFileInput) != null ? ref.parentNode : void 0) { 745 this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput); 746 this.hiddenFileInput = null; 747 } 748 delete this.element.dropzone; 749 return Dropzone.instances.splice(Dropzone.instances.indexOf(this), 1); 750 }; 751 752 Dropzone.prototype.updateTotalUploadProgress = function() { 753 var activeFiles, file, j, len, ref, totalBytes, totalBytesSent, totalUploadProgress; 754 totalBytesSent = 0; 755 totalBytes = 0; 756 activeFiles = this.getActiveFiles(); 757 if (activeFiles.length) { 758 ref = this.getActiveFiles(); 759 for (j = 0, len = ref.length; j < len; j++) { 760 file = ref[j]; 761 totalBytesSent += file.upload.bytesSent; 762 totalBytes += file.upload.total; 763 } 764 totalUploadProgress = 100 * totalBytesSent / totalBytes; 765 } else { 766 totalUploadProgress = 100; 767 } 768 return this.emit("totaluploadprogress", totalUploadProgress, totalBytes, totalBytesSent); 769 }; 770 771 Dropzone.prototype._getParamName = function(n) { 772 if (typeof this.options.paramName === "function") { 773 return this.options.paramName(n); 774 } else { 775 return "" + this.options.paramName + (this.options.uploadMultiple ? "[" + n + "]" : ""); 776 } 777 }; 778 779 Dropzone.prototype._renameFile = function(file) { 780 if (typeof this.options.renameFile !== "function") { 781 return file.name; 782 } 783 return this.options.renameFile(file); 784 }; 785 786 Dropzone.prototype.getFallbackForm = function() { 787 var existingFallback, fields, fieldsString, form; 788 if (existingFallback = this.getExistingFallback()) { 789 return existingFallback; 790 } 791 fieldsString = "<div class=\"dz-fallback\">"; 792 if (this.options.dictFallbackText) { 793 fieldsString += "<p>" + this.options.dictFallbackText + "</p>"; 794 } 795 fieldsString += "<input type=\"file\" name=\"" + (this._getParamName(0)) + "\" " + (this.options.uploadMultiple ? 'multiple="multiple"' : void 0) + " /><input type=\"submit\" value=\"Upload!\"></div>"; 796 fields = Dropzone.createElement(fieldsString); 797 if (this.element.tagName !== "FORM") { 798 form = Dropzone.createElement("<form action=\"" + this.options.url + "\" enctype=\"multipart/form-data\" method=\"" + this.options.method + "\"></form>"); 799 form.appendChild(fields); 800 } else { 801 this.element.setAttribute("enctype", "multipart/form-data"); 802 this.element.setAttribute("method", this.options.method); 803 } 804 return form != null ? form : fields; 805 }; 806 807 Dropzone.prototype.getExistingFallback = function() { 808 var fallback, getFallback, j, len, ref, tagName; 809 getFallback = function(elements) { 810 var el, j, len; 811 for (j = 0, len = elements.length; j < len; j++) { 812 el = elements[j]; 813 if (/(^| )fallback($| )/.test(el.className)) { 814 return el; 815 } 816 } 817 }; 818 ref = ["div", "form"]; 819 for (j = 0, len = ref.length; j < len; j++) { 820 tagName = ref[j]; 821 if (fallback = getFallback(this.element.getElementsByTagName(tagName))) { 822 return fallback; 823 } 824 } 825 }; 826 827 Dropzone.prototype.setupEventListeners = function() { 828 var elementListeners, event, j, len, listener, ref, results; 829 ref = this.listeners; 830 results = []; 831 for (j = 0, len = ref.length; j < len; j++) { 832 elementListeners = ref[j]; 833 results.push((function() { 834 var ref1, results1; 835 ref1 = elementListeners.events; 836 results1 = []; 837 for (event in ref1) { 838 listener = ref1[event]; 839 results1.push(elementListeners.element.addEventListener(event, listener, false)); 840 } 841 return results1; 842 })()); 843 } 844 return results; 845 }; 846 847 Dropzone.prototype.removeEventListeners = function() { 848 var elementListeners, event, j, len, listener, ref, results; 849 ref = this.listeners; 850 results = []; 851 for (j = 0, len = ref.length; j < len; j++) { 852 elementListeners = ref[j]; 853 results.push((function() { 854 var ref1, results1; 855 ref1 = elementListeners.events; 856 results1 = []; 857 for (event in ref1) { 858 listener = ref1[event]; 859 results1.push(elementListeners.element.removeEventListener(event, listener, false)); 860 } 861 return results1; 862 })()); 863 } 864 return results; 865 }; 866 867 Dropzone.prototype.disable = function() { 868 var file, j, len, ref, results; 869 this.clickableElements.forEach(function(element) { 870 return element.classList.remove("dz-clickable"); 871 }); 872 this.removeEventListeners(); 873 ref = this.files; 874 results = []; 875 for (j = 0, len = ref.length; j < len; j++) { 876 file = ref[j]; 877 results.push(this.cancelUpload(file)); 878 } 879 return results; 880 }; 881 882 Dropzone.prototype.enable = function() { 883 this.clickableElements.forEach(function(element) { 884 return element.classList.add("dz-clickable"); 885 }); 886 return this.setupEventListeners(); 887 }; 888 889 Dropzone.prototype.filesize = function(size) { 890 var cutoff, i, j, len, selectedSize, selectedUnit, unit, units; 891 selectedSize = 0; 892 selectedUnit = "b"; 893 if (size > 0) { 894 units = ['tb', 'gb', 'mb', 'kb', 'b']; 895 for (i = j = 0, len = units.length; j < len; i = ++j) { 896 unit = units[i]; 897 cutoff = Math.pow(this.options.filesizeBase, 4 - i) / 10; 898 if (size >= cutoff) { 899 selectedSize = size / Math.pow(this.options.filesizeBase, 4 - i); 900 selectedUnit = unit; 901 break; 902 } 903 } 904 selectedSize = Math.round(10 * selectedSize) / 10; 905 } 906 return "<strong>" + selectedSize + "</strong> " + this.options.dictFileSizeUnits[selectedUnit]; 907 }; 908 909 Dropzone.prototype._updateMaxFilesReachedClass = function() { 910 if ((this.options.maxFiles != null) && this.getAcceptedFiles().length >= this.options.maxFiles) { 911 if (this.getAcceptedFiles().length === this.options.maxFiles) { 912 this.emit('maxfilesreached', this.files); 913 } 914 return this.element.classList.add("dz-max-files-reached"); 915 } else { 916 return this.element.classList.remove("dz-max-files-reached"); 917 } 918 }; 919 920 Dropzone.prototype.drop = function(e) { 921 var files, items; 922 if (!e.dataTransfer) { 923 return; 924 } 925 this.emit("drop", e); 926 files = e.dataTransfer.files; 927 this.emit("addedfiles", files); 928 if (files.length) { 929 items = e.dataTransfer.items; 930 if (items && items.length && (items[0].webkitGetAsEntry != null)) { 931 this._addFilesFromItems(items); 932 } else { 933 this.handleFiles(files); 934 } 935 } 936 }; 937 938 Dropzone.prototype.paste = function(e) { 939 var items, ref; 940 if ((e != null ? (ref = e.clipboardData) != null ? ref.items : void 0 : void 0) == null) { 941 return; 942 } 943 this.emit("paste", e); 944 items = e.clipboardData.items; 945 if (items.length) { 946 return this._addFilesFromItems(items); 947 } 948 }; 949 950 Dropzone.prototype.handleFiles = function(files) { 951 var file, j, len, results; 952 results = []; 953 for (j = 0, len = files.length; j < len; j++) { 954 file = files[j]; 955 results.push(this.addFile(file)); 956 } 957 return results; 958 }; 959 960 Dropzone.prototype._addFilesFromItems = function(items) { 961 var entry, item, j, len, results; 962 results = []; 963 for (j = 0, len = items.length; j < len; j++) { 964 item = items[j]; 965 if ((item.webkitGetAsEntry != null) && (entry = item.webkitGetAsEntry())) { 966 if (entry.isFile) { 967 results.push(this.addFile(item.getAsFile())); 968 } else if (entry.isDirectory) { 969 results.push(this._addFilesFromDirectory(entry, entry.name)); 970 } else { 971 results.push(void 0); 972 } 973 } else if (item.getAsFile != null) { 974 if ((item.kind == null) || item.kind === "file") { 975 results.push(this.addFile(item.getAsFile())); 976 } else { 977 results.push(void 0); 978 } 979 } else { 980 results.push(void 0); 981 } 982 } 983 return results; 984 }; 985 986 Dropzone.prototype._addFilesFromDirectory = function(directory, path) { 987 var dirReader, errorHandler, readEntries; 988 dirReader = directory.createReader(); 989 errorHandler = function(error) { 990 return typeof console !== "undefined" && console !== null ? typeof console.log === "function" ? console.log(error) : void 0 : void 0; 991 }; 992 readEntries = (function(_this) { 993 return function() { 994 return dirReader.readEntries(function(entries) { 995 var entry, j, len; 996 if (entries.length > 0) { 997 for (j = 0, len = entries.length; j < len; j++) { 998 entry = entries[j]; 999 if (entry.isFile) { 1000 entry.file(function(file) { 1001 if (_this.options.ignoreHiddenFiles && file.name.substring(0, 1) === '.') { 1002 return; 1003 } 1004 file.fullPath = path + "/" + file.name; 1005 return _this.addFile(file); 1006 }); 1007 } else if (entry.isDirectory) { 1008 _this._addFilesFromDirectory(entry, path + "/" + entry.name); 1009 } 1010 } 1011 readEntries(); 1012 } 1013 return null; 1014 }, errorHandler); 1015 }; 1016 })(this); 1017 return readEntries(); 1018 }; 1019 1020 Dropzone.prototype.accept = function(file, done) { 1021 if (file.size > this.options.maxFilesize * 1024 * 1024) { 1022 return done(this.options.dictFileTooBig.replace("{{filesize}}", Math.round(file.size / 1024 / 10.24) / 100).replace("{{maxFilesize}}", this.options.maxFilesize)); 1023 } else if (!Dropzone.isValidFile(file, this.options.acceptedFiles)) { 1024 return done(this.options.dictInvalidFileType); 1025 } else if ((this.options.maxFiles != null) && this.getAcceptedFiles().length >= this.options.maxFiles) { 1026 done(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}", this.options.maxFiles)); 1027 return this.emit("maxfilesexceeded", file); 1028 } else { 1029 return this.options.accept.call(this, file, done); 1030 } 1031 }; 1032 1033 Dropzone.prototype.addFile = function(file) { 1034 file.upload = { 1035 progress: 0, 1036 total: file.size, 1037 bytesSent: 0, 1038 filename: this._renameFile(file) 1039 }; 1040 this.files.push(file); 1041 file.status = Dropzone.ADDED; 1042 this.emit("addedfile", file); 1043 this._enqueueThumbnail(file); 1044 return this.accept(file, (function(_this) { 1045 return function(error) { 1046 if (error) { 1047 file.accepted = false; 1048 _this._errorProcessing([file], error); 1049 } else { 1050 file.accepted = true; 1051 if (_this.options.autoQueue) { 1052 _this.enqueueFile(file); 1053 } 1054 } 1055 return _this._updateMaxFilesReachedClass(); 1056 }; 1057 })(this)); 1058 }; 1059 1060 Dropzone.prototype.enqueueFiles = function(files) { 1061 var file, j, len; 1062 for (j = 0, len = files.length; j < len; j++) { 1063 file = files[j]; 1064 this.enqueueFile(file); 1065 } 1066 return null; 1067 }; 1068 1069 Dropzone.prototype.enqueueFile = function(file) { 1070 if (file.status === Dropzone.ADDED && file.accepted === true) { 1071 file.status = Dropzone.QUEUED; 1072 if (this.options.autoProcessQueue) { 1073 return setTimeout(((function(_this) { 1074 return function() { 1075 return _this.processQueue(); 1076 }; 1077 })(this)), 0); 1078 } 1079 } else { 1080 throw new Error("This file can't be queued because it has already been processed or was rejected."); 1081 } 1082 }; 1083 1084 Dropzone.prototype._thumbnailQueue = []; 1085 1086 Dropzone.prototype._processingThumbnail = false; 1087 1088 Dropzone.prototype._enqueueThumbnail = function(file) { 1089 if (this.options.createImageThumbnails && file.type.match(/image.*/) && file.size <= this.options.maxThumbnailFilesize * 1024 * 1024) { 1090 this._thumbnailQueue.push(file); 1091 return setTimeout(((function(_this) { 1092 return function() { 1093 return _this._processThumbnailQueue(); 1094 }; 1095 })(this)), 0); 1096 } 1097 }; 1098 1099 Dropzone.prototype._processThumbnailQueue = function() { 1100 var file; 1101 if (this._processingThumbnail || this._thumbnailQueue.length === 0) { 1102 return; 1103 } 1104 this._processingThumbnail = true; 1105 file = this._thumbnailQueue.shift(); 1106 return this.createThumbnail(file, this.options.thumbnailWidth, this.options.thumbnailHeight, this.options.thumbnailMethod, true, (function(_this) { 1107 return function(dataUrl) { 1108 _this.emit("thumbnail", file, dataUrl); 1109 _this._processingThumbnail = false; 1110 return _this._processThumbnailQueue(); 1111 }; 1112 })(this)); 1113 }; 1114 1115 Dropzone.prototype.removeFile = function(file) { 1116 if (file.status === Dropzone.UPLOADING) { 1117 this.cancelUpload(file); 1118 } 1119 this.files = without(this.files, file); 1120 this.emit("removedfile", file); 1121 if (this.files.length === 0) { 1122 return this.emit("reset"); 1123 } 1124 }; 1125 1126 Dropzone.prototype.removeAllFiles = function(cancelIfNecessary) { 1127 var file, j, len, ref; 1128 if (cancelIfNecessary == null) { 1129 cancelIfNecessary = false; 1130 } 1131 ref = this.files.slice(); 1132 for (j = 0, len = ref.length; j < len; j++) { 1133 file = ref[j]; 1134 if (file.status !== Dropzone.UPLOADING || cancelIfNecessary) { 1135 this.removeFile(file); 1136 } 1137 } 1138 return null; 1139 }; 1140 1141 Dropzone.prototype.resizeImage = function(file, width, height, resizeMethod, callback) { 1142 return this.createThumbnail(file, width, height, resizeMethod, false, (function(_this) { 1143 return function(dataUrl, canvas) { 1144 var resizeMimeType, resizedDataURL; 1145 if (canvas === null) { 1146 return callback(file); 1147 } else { 1148 resizeMimeType = _this.options.resizeMimeType; 1149 if (resizeMimeType == null) { 1150 resizeMimeType = file.type; 1151 } 1152 resizedDataURL = canvas.toDataURL(resizeMimeType, _this.options.resizeQuality); 1153 if (resizeMimeType === 'image/jpeg' || resizeMimeType === 'image/jpg') { 1154 resizedDataURL = ExifRestore.restore(file.dataURL, resizedDataURL); 1155 } 1156 return callback(Dropzone.dataURItoBlob(resizedDataURL)); 1157 } 1158 }; 1159 })(this)); 1160 }; 1161 1162 Dropzone.prototype.createThumbnail = function(file, width, height, resizeMethod, fixOrientation, callback) { 1163 var fileReader; 1164 fileReader = new FileReader; 1165 fileReader.onload = (function(_this) { 1166 return function() { 1167 file.dataURL = fileReader.result; 1168 if (file.type === "image/svg+xml") { 1169 if (callback != null) { 1170 callback(fileReader.result); 1171 } 1172 return; 1173 } 1174 return _this.createThumbnailFromUrl(file, width, height, resizeMethod, fixOrientation, callback); 1175 }; 1176 })(this); 1177 return fileReader.readAsDataURL(file); 1178 }; 1179 1180 Dropzone.prototype.createThumbnailFromUrl = function(file, width, height, resizeMethod, fixOrientation, callback, crossOrigin) { 1181 var img; 1182 img = document.createElement("img"); 1183 if (crossOrigin) { 1184 img.crossOrigin = crossOrigin; 1185 } 1186 img.onload = (function(_this) { 1187 return function() { 1188 var loadExif; 1189 loadExif = function(callback) { 1190 return callback(1); 1191 }; 1192 if ((typeof EXIF !== "undefined" && EXIF !== null) && fixOrientation) { 1193 loadExif = function(callback) { 1194 return EXIF.getData(img, function() { 1195 return callback(EXIF.getTag(this, 'Orientation')); 1196 }); 1197 }; 1198 } 1199 return loadExif(function(orientation) { 1200 var canvas, ctx, ref, ref1, ref2, ref3, resizeInfo, thumbnail; 1201 file.width = img.width; 1202 file.height = img.height; 1203 resizeInfo = _this.options.resize.call(_this, file, width, height, resizeMethod); 1204 canvas = document.createElement("canvas"); 1205 ctx = canvas.getContext("2d"); 1206 canvas.width = resizeInfo.trgWidth; 1207 canvas.height = resizeInfo.trgHeight; 1208 if (orientation > 4) { 1209 canvas.width = resizeInfo.trgHeight; 1210 canvas.height = resizeInfo.trgWidth; 1211 } 1212 switch (orientation) { 1213 case 2: 1214 ctx.translate(canvas.width, 0); 1215 ctx.scale(-1, 1); 1216 break; 1217 case 3: 1218 ctx.translate(canvas.width, canvas.height); 1219 ctx.rotate(Math.PI); 1220 break; 1221 case 4: 1222 ctx.translate(0, canvas.height); 1223 ctx.scale(1, -1); 1224 break; 1225 case 5: 1226 ctx.rotate(0.5 * Math.PI); 1227 ctx.scale(1, -1); 1228 break; 1229 case 6: 1230 ctx.rotate(0.5 * Math.PI); 1231 ctx.translate(0, -canvas.height); 1232 break; 1233 case 7: 1234 ctx.rotate(0.5 * Math.PI); 1235 ctx.translate(canvas.width, -canvas.height); 1236 ctx.scale(-1, 1); 1237 break; 1238 case 8: 1239 ctx.rotate(-0.5 * Math.PI); 1240 ctx.translate(-canvas.width, 0); 1241 } 1242 drawImageIOSFix(ctx, img, (ref = resizeInfo.srcX) != null ? ref : 0, (ref1 = resizeInfo.srcY) != null ? ref1 : 0, resizeInfo.srcWidth, resizeInfo.srcHeight, (ref2 = resizeInfo.trgX) != null ? ref2 : 0, (ref3 = resizeInfo.trgY) != null ? ref3 : 0, resizeInfo.trgWidth, resizeInfo.trgHeight); 1243 thumbnail = canvas.toDataURL("image/png"); 1244 if (callback != null) { 1245 return callback(thumbnail, canvas); 1246 } 1247 }); 1248 }; 1249 })(this); 1250 if (callback != null) { 1251 img.onerror = callback; 1252 } 1253 return img.src = file.dataURL; 1254 }; 1255 1256 Dropzone.prototype.processQueue = function() { 1257 var i, parallelUploads, processingLength, queuedFiles; 1258 parallelUploads = this.options.parallelUploads; 1259 processingLength = this.getUploadingFiles().length; 1260 i = processingLength; 1261 if (processingLength >= parallelUploads) { 1262 return; 1263 } 1264 queuedFiles = this.getQueuedFiles(); 1265 if (!(queuedFiles.length > 0)) { 1266 return; 1267 } 1268 if (this.options.uploadMultiple) { 1269 return this.processFiles(queuedFiles.slice(0, parallelUploads - processingLength)); 1270 } else { 1271 while (i < parallelUploads) { 1272 if (!queuedFiles.length) { 1273 return; 1274 } 1275 this.processFile(queuedFiles.shift()); 1276 i++; 1277 } 1278 } 1279 }; 1280 1281 Dropzone.prototype.processFile = function(file) { 1282 return this.processFiles([file]); 1283 }; 1284 1285 Dropzone.prototype.processFiles = function(files) { 1286 var file, j, len; 1287 for (j = 0, len = files.length; j < len; j++) { 1288 file = files[j]; 1289 file.processing = true; 1290 file.status = Dropzone.UPLOADING; 1291 this.emit("processing", file); 1292 } 1293 if (this.options.uploadMultiple) { 1294 this.emit("processingmultiple", files); 1295 } 1296 return this.uploadFiles(files); 1297 }; 1298 1299 Dropzone.prototype._getFilesWithXhr = function(xhr) { 1300 var file, files; 1301 return files = (function() { 1302 var j, len, ref, results; 1303 ref = this.files; 1304 results = []; 1305 for (j = 0, len = ref.length; j < len; j++) { 1306 file = ref[j]; 1307 if (file.xhr === xhr) { 1308 results.push(file); 1309 } 1310 } 1311 return results; 1312 }).call(this); 1313 }; 1314 1315 Dropzone.prototype.cancelUpload = function(file) { 1316 var groupedFile, groupedFiles, j, k, len, len1, ref; 1317 if (file.status === Dropzone.UPLOADING) { 1318 groupedFiles = this._getFilesWithXhr(file.xhr); 1319 for (j = 0, len = groupedFiles.length; j < len; j++) { 1320 groupedFile = groupedFiles[j]; 1321 groupedFile.status = Dropzone.CANCELED; 1322 } 1323 file.xhr.abort(); 1324 for (k = 0, len1 = groupedFiles.length; k < len1; k++) { 1325 groupedFile = groupedFiles[k]; 1326 this.emit("canceled", groupedFile); 1327 } 1328 if (this.options.uploadMultiple) { 1329 this.emit("canceledmultiple", groupedFiles); 1330 } 1331 } else if ((ref = file.status) === Dropzone.ADDED || ref === Dropzone.QUEUED) { 1332 file.status = Dropzone.CANCELED; 1333 this.emit("canceled", file); 1334 if (this.options.uploadMultiple) { 1335 this.emit("canceledmultiple", [file]); 1336 } 1337 } 1338 if (this.options.autoProcessQueue) { 1339 return this.processQueue(); 1340 } 1341 }; 1342 1343 resolveOption = function() { 1344 var args, option; 1345 option = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; 1346 if (typeof option === 'function') { 1347 return option.apply(this, args); 1348 } 1349 return option; 1350 }; 1351 1352 Dropzone.prototype.uploadFile = function(file) { 1353 return this.uploadFiles([file]); 1354 }; 1355 1356 Dropzone.prototype.uploadFiles = function(files) { 1357 var doneCounter, doneFunction, file, formData, handleError, headerName, headerValue, headers, i, input, inputName, inputType, j, k, key, l, len, len1, len2, len3, m, method, o, option, progressObj, ref, ref1, ref2, ref3, ref4, ref5, response, results, updateProgress, url, value, xhr; 1358 xhr = new XMLHttpRequest(); 1359 for (j = 0, len = files.length; j < len; j++) { 1360 file = files[j]; 1361 file.xhr = xhr; 1362 } 1363 method = resolveOption(this.options.method, files); 1364 url = resolveOption(this.options.url, files); 1365 xhr.open(method, url, true); 1366 xhr.timeout = resolveOption(this.options.timeout, files); 1367 xhr.withCredentials = !!this.options.withCredentials; 1368 response = null; 1369 handleError = (function(_this) { 1370 return function() { 1371 var k, len1, results; 1372 results = []; 1373 for (k = 0, len1 = files.length; k < len1; k++) { 1374 file = files[k]; 1375 results.push(_this._errorProcessing(files, response || _this.options.dictResponseError.replace("{{statusCode}}", xhr.status), xhr)); 1376 } 1377 return results; 1378 }; 1379 })(this); 1380 updateProgress = (function(_this) { 1381 return function(e) { 1382 var allFilesFinished, k, l, len1, len2, len3, m, progress, results; 1383 if (e != null) { 1384 progress = 100 * e.loaded / e.total; 1385 for (k = 0, len1 = files.length; k < len1; k++) { 1386 file = files[k]; 1387 file.upload.progress = progress; 1388 file.upload.total = e.total; 1389 file.upload.bytesSent = e.loaded; 1390 } 1391 } else { 1392 allFilesFinished = true; 1393 progress = 100; 1394 for (l = 0, len2 = files.length; l < len2; l++) { 1395 file = files[l]; 1396 if (!(file.upload.progress === 100 && file.upload.bytesSent === file.upload.total)) { 1397 allFilesFinished = false; 1398 } 1399 file.upload.progress = progress; 1400 file.upload.bytesSent = file.upload.total; 1401 } 1402 if (allFilesFinished) { 1403 return; 1404 } 1405 } 1406 results = []; 1407 for (m = 0, len3 = files.length; m < len3; m++) { 1408 file = files[m]; 1409 results.push(_this.emit("uploadprogress", file, progress, file.upload.bytesSent)); 1410 } 1411 return results; 1412 }; 1413 })(this); 1414 xhr.onload = (function(_this) { 1415 return function(e) { 1416 var error1, ref; 1417 if (files[0].status === Dropzone.CANCELED) { 1418 return; 1419 } 1420 if (xhr.readyState !== 4) { 1421 return; 1422 } 1423 if (xhr.responseType !== 'arraybuffer' && xhr.responseType !== 'blob') { 1424 response = xhr.responseText; 1425 if (xhr.getResponseHeader("content-type") && ~xhr.getResponseHeader("content-type").indexOf("application/json")) { 1426 try { 1427 response = JSON.parse(response); 1428 } catch (error1) { 1429 e = error1; 1430 response = "Invalid JSON response from server."; 1431 } 1432 } 1433 } 1434 updateProgress(); 1435 if (!((200 <= (ref = xhr.status) && ref < 300))) { 1436 return handleError(); 1437 } else { 1438 return _this._finished(files, response, e); 1439 } 1440 }; 1441 })(this); 1442 xhr.onerror = (function(_this) { 1443 return function() { 1444 if (files[0].status === Dropzone.CANCELED) { 1445 return; 1446 } 1447 return handleError(); 1448 }; 1449 })(this); 1450 progressObj = (ref = xhr.upload) != null ? ref : xhr; 1451 progressObj.onprogress = updateProgress; 1452 headers = { 1453 "Accept": "application/json", 1454 "Cache-Control": "no-cache", 1455 "X-Requested-With": "XMLHttpRequest" 1456 }; 1457 if (this.options.headers) { 1458 extend(headers, this.options.headers); 1459 } 1460 for (headerName in headers) { 1461 headerValue = headers[headerName]; 1462 if (headerValue) { 1463 xhr.setRequestHeader(headerName, headerValue); 1464 } 1465 } 1466 formData = new FormData(); 1467 if (this.options.params) { 1468 ref1 = this.options.params; 1469 for (key in ref1) { 1470 value = ref1[key]; 1471 formData.append(key, value); 1472 } 1473 } 1474 for (k = 0, len1 = files.length; k < len1; k++) { 1475 file = files[k]; 1476 this.emit("sending", file, xhr, formData); 1477 } 1478 if (this.options.uploadMultiple) { 1479 this.emit("sendingmultiple", files, xhr, formData); 1480 } 1481 if (this.element.tagName === "FORM") { 1482 ref2 = this.element.querySelectorAll("input, textarea, select, button"); 1483 for (l = 0, len2 = ref2.length; l < len2; l++) { 1484 input = ref2[l]; 1485 inputName = input.getAttribute("name"); 1486 inputType = input.getAttribute("type"); 1487 if (input.tagName === "SELECT" && input.hasAttribute("multiple")) { 1488 ref3 = input.options; 1489 for (m = 0, len3 = ref3.length; m < len3; m++) { 1490 option = ref3[m]; 1491 if (option.selected) { 1492 formData.append(inputName, option.value); 1493 } 1494 } 1495 } else if (!inputType || ((ref4 = inputType.toLowerCase()) !== "checkbox" && ref4 !== "radio") || input.checked) { 1496 formData.append(inputName, input.value); 1497 } 1498 } 1499 } 1500 doneCounter = 0; 1501 results = []; 1502 for (i = o = 0, ref5 = files.length - 1; 0 <= ref5 ? o <= ref5 : o >= ref5; i = 0 <= ref5 ? ++o : --o) { 1503 doneFunction = (function(_this) { 1504 return function(file, paramName, fileName) { 1505 return function(transformedFile) { 1506 formData.append(paramName, transformedFile, fileName); 1507 if (++doneCounter === files.length) { 1508 return _this.submitRequest(xhr, formData, files); 1509 } 1510 }; 1511 }; 1512 })(this); 1513 results.push(this.options.transformFile.call(this, files[i], doneFunction(files[i], this._getParamName(i), files[i].upload.filename))); 1514 } 1515 return results; 1516 }; 1517 1518 Dropzone.prototype.submitRequest = function(xhr, formData, files) { 1519 return xhr.send(formData); 1520 }; 1521 1522 Dropzone.prototype._finished = function(files, responseText, e) { 1523 var file, j, len; 1524 for (j = 0, len = files.length; j < len; j++) { 1525 file = files[j]; 1526 file.status = Dropzone.SUCCESS; 1527 this.emit("success", file, responseText, e); 1528 this.emit("complete", file); 1529 } 1530 if (this.options.uploadMultiple) { 1531 this.emit("successmultiple", files, responseText, e); 1532 this.emit("completemultiple", files); 1533 } 1534 if (this.options.autoProcessQueue) { 1535 return this.processQueue(); 1536 } 1537 }; 1538 1539 Dropzone.prototype._errorProcessing = function(files, message, xhr) { 1540 var file, j, len; 1541 for (j = 0, len = files.length; j < len; j++) { 1542 file = files[j]; 1543 file.status = Dropzone.ERROR; 1544 this.emit("error", file, message, xhr); 1545 this.emit("complete", file); 1546 } 1547 if (this.options.uploadMultiple) { 1548 this.emit("errormultiple", files, message, xhr); 1549 this.emit("completemultiple", files); 1550 } 1551 if (this.options.autoProcessQueue) { 1552 return this.processQueue(); 1553 } 1554 }; 1555 1556 return Dropzone; 1557 1558 })(Emitter); 1559 1560 Dropzone.version = "5.1.1"; 1561 1562 Dropzone.options = {}; 1563 1564 Dropzone.optionsForElement = function(element) { 1565 if (element.getAttribute("id")) { 1566 return Dropzone.options[camelize(element.getAttribute("id"))]; 1567 } else { 1568 return void 0; 1569 } 1570 }; 1571 1572 Dropzone.instances = []; 1573 1574 Dropzone.forElement = function(element) { 1575 if (typeof element === "string") { 1576 element = document.querySelector(element); 1577 } 1578 if ((element != null ? element.dropzone : void 0) == null) { 1579 throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone."); 1580 } 1581 return element.dropzone; 1582 }; 1583 1584 Dropzone.autoDiscover = true; 1585 1586 Dropzone.discover = function() { 1587 var checkElements, dropzone, dropzones, j, len, results; 1588 if (document.querySelectorAll) { 1589 dropzones = document.querySelectorAll(".dropzone"); 1590 } else { 1591 dropzones = []; 1592 checkElements = function(elements) { 1593 var el, j, len, results; 1594 results = []; 1595 for (j = 0, len = elements.length; j < len; j++) { 1596 el = elements[j]; 1597 if (/(^| )dropzone($| )/.test(el.className)) { 1598 results.push(dropzones.push(el)); 1599 } else { 1600 results.push(void 0); 1601 } 1602 } 1603 return results; 1604 }; 1605 checkElements(document.getElementsByTagName("div")); 1606 checkElements(document.getElementsByTagName("form")); 1607 } 1608 results = []; 1609 for (j = 0, len = dropzones.length; j < len; j++) { 1610 dropzone = dropzones[j]; 1611 if (Dropzone.optionsForElement(dropzone) !== false) { 1612 results.push(new Dropzone(dropzone)); 1613 } else { 1614 results.push(void 0); 1615 } 1616 } 1617 return results; 1618 }; 1619 1620 Dropzone.blacklistedBrowsers = [/opera.*Macintosh.*version\/12/i]; 1621 1622 Dropzone.isBrowserSupported = function() { 1623 var capableBrowser, j, len, ref, regex; 1624 capableBrowser = true; 1625 if (window.File && window.FileReader && window.FileList && window.Blob && window.FormData && document.querySelector) { 1626 if (!("classList" in document.createElement("a"))) { 1627 capableBrowser = false; 1628 } else { 1629 ref = Dropzone.blacklistedBrowsers; 1630 for (j = 0, len = ref.length; j < len; j++) { 1631 regex = ref[j]; 1632 if (regex.test(navigator.userAgent)) { 1633 capableBrowser = false; 1634 continue; 1635 } 1636 } 1637 } 1638 } else { 1639 capableBrowser = false; 1640 } 1641 return capableBrowser; 1642 }; 1643 1644 Dropzone.dataURItoBlob = function(dataURI) { 1645 var ab, byteString, i, ia, j, mimeString, ref; 1646 byteString = atob(dataURI.split(',')[1]); 1647 mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; 1648 ab = new ArrayBuffer(byteString.length); 1649 ia = new Uint8Array(ab); 1650 for (i = j = 0, ref = byteString.length; 0 <= ref ? j <= ref : j >= ref; i = 0 <= ref ? ++j : --j) { 1651 ia[i] = byteString.charCodeAt(i); 1652 } 1653 return new Blob([ab], { 1654 type: mimeString 1655 }); 1656 }; 1657 1658 without = function(list, rejectedItem) { 1659 var item, j, len, results; 1660 results = []; 1661 for (j = 0, len = list.length; j < len; j++) { 1662 item = list[j]; 1663 if (item !== rejectedItem) { 1664 results.push(item); 1665 } 1666 } 1667 return results; 1668 }; 1669 1670 camelize = function(str) { 1671 return str.replace(/[\-_](\w)/g, function(match) { 1672 return match.charAt(1).toUpperCase(); 1673 }); 1674 }; 1675 1676 Dropzone.createElement = function(string) { 1677 var div; 1678 div = document.createElement("div"); 1679 div.innerHTML = string; 1680 return div.childNodes[0]; 1681 }; 1682 1683 Dropzone.elementInside = function(element, container) { 1684 if (element === container) { 1685 return true; 1686 } 1687 while (element = element.parentNode) { 1688 if (element === container) { 1689 return true; 1690 } 1691 } 1692 return false; 1693 }; 1694 1695 Dropzone.getElement = function(el, name) { 1696 var element; 1697 if (typeof el === "string") { 1698 element = document.querySelector(el); 1699 } else if (el.nodeType != null) { 1700 element = el; 1701 } 1702 if (element == null) { 1703 throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector or a plain HTML element."); 1704 } 1705 return element; 1706 }; 1707 1708 Dropzone.getElements = function(els, name) { 1709 var e, el, elements, error1, j, k, len, len1, ref; 1710 if (els instanceof Array) { 1711 elements = []; 1712 try { 1713 for (j = 0, len = els.length; j < len; j++) { 1714 el = els[j]; 1715 elements.push(this.getElement(el, name)); 1716 } 1717 } catch (error1) { 1718 e = error1; 1719 elements = null; 1720 } 1721 } else if (typeof els === "string") { 1722 elements = []; 1723 ref = document.querySelectorAll(els); 1724 for (k = 0, len1 = ref.length; k < len1; k++) { 1725 el = ref[k]; 1726 elements.push(el); 1727 } 1728 } else if (els.nodeType != null) { 1729 elements = [els]; 1730 } 1731 if (!((elements != null) && elements.length)) { 1732 throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector, a plain HTML element or a list of those."); 1733 } 1734 return elements; 1735 }; 1736 1737 Dropzone.confirm = function(question, accepted, rejected) { 1738 if (window.confirm(question)) { 1739 return accepted(); 1740 } else if (rejected != null) { 1741 return rejected(); 1742 } 1743 }; 1744 1745 Dropzone.isValidFile = function(file, acceptedFiles) { 1746 var baseMimeType, j, len, mimeType, validType; 1747 if (!acceptedFiles) { 1748 return true; 1749 } 1750 acceptedFiles = acceptedFiles.split(","); 1751 mimeType = file.type; 1752 baseMimeType = mimeType.replace(/\/.*$/, ""); 1753 for (j = 0, len = acceptedFiles.length; j < len; j++) { 1754 validType = acceptedFiles[j]; 1755 validType = validType.trim(); 1756 if (validType.charAt(0) === ".") { 1757 if (file.name.toLowerCase().indexOf(validType.toLowerCase(), file.name.length - validType.length) !== -1) { 1758 return true; 1759 } 1760 } else if (/\/\*$/.test(validType)) { 1761 if (baseMimeType === validType.replace(/\/.*$/, "")) { 1762 return true; 1763 } 1764 } else { 1765 if (mimeType === validType) { 1766 return true; 1767 } 1768 } 1769 } 1770 return false; 1771 }; 1772 1773 if (typeof jQuery !== "undefined" && jQuery !== null) { 1774 jQuery.fn.dropzone = function(options) { 1775 return this.each(function() { 1776 return new Dropzone(this, options); 1777 }); 1778 }; 1779 } 1780 1781 if (typeof module !== "undefined" && module !== null) { 1782 module.exports = Dropzone; 1783 } else { 1784 window.Dropzone = Dropzone; 1785 } 1786 1787 Dropzone.ADDED = "added"; 1788 1789 Dropzone.QUEUED = "queued"; 1790 1791 Dropzone.ACCEPTED = Dropzone.QUEUED; 1792 1793 Dropzone.UPLOADING = "uploading"; 1794 1795 Dropzone.PROCESSING = Dropzone.UPLOADING; 1796 1797 Dropzone.CANCELED = "canceled"; 1798 1799 Dropzone.ERROR = "error"; 1800 1801 Dropzone.SUCCESS = "success"; 1802 1803 1804 /* 1805 1806 Bugfix for iOS 6 and 7 1807 Source: http://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios 1808 based on the work of https://github.com/stomita/ios-imagefile-megapixel 1809 */ 1810 1811 detectVerticalSquash = function(img) { 1812 var alpha, canvas, ctx, data, ey, ih, iw, py, ratio, sy; 1813 iw = img.naturalWidth; 1814 ih = img.naturalHeight; 1815 canvas = document.createElement("canvas"); 1816 canvas.width = 1; 1817 canvas.height = ih; 1818 ctx = canvas.getContext("2d"); 1819 ctx.drawImage(img, 0, 0); 1820 data = ctx.getImageData(1, 0, 1, ih).data; 1821 sy = 0; 1822 ey = ih; 1823 py = ih; 1824 while (py > sy) { 1825 alpha = data[(py - 1) * 4 + 3]; 1826 if (alpha === 0) { 1827 ey = py; 1828 } else { 1829 sy = py; 1830 } 1831 py = (ey + sy) >> 1; 1832 } 1833 ratio = py / ih; 1834 if (ratio === 0) { 1835 return 1; 1836 } else { 1837 return ratio; 1838 } 1839 }; 1840 1841 drawImageIOSFix = function(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) { 1842 var vertSquashRatio; 1843 vertSquashRatio = detectVerticalSquash(img); 1844 return ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio); 1845 }; 1846 1847 ExifRestore = (function() { 1848 function ExifRestore() {} 1849 1850 ExifRestore.KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; 1851 1852 ExifRestore.encode64 = function(input) { 1853 var chr1, chr2, chr3, enc1, enc2, enc3, enc4, i, output; 1854 output = ''; 1855 chr1 = void 0; 1856 chr2 = void 0; 1857 chr3 = ''; 1858 enc1 = void 0; 1859 enc2 = void 0; 1860 enc3 = void 0; 1861 enc4 = ''; 1862 i = 0; 1863 while (true) { 1864 chr1 = input[i++]; 1865 chr2 = input[i++]; 1866 chr3 = input[i++]; 1867 enc1 = chr1 >> 2; 1868 enc2 = (chr1 & 3) << 4 | chr2 >> 4; 1869 enc3 = (chr2 & 15) << 2 | chr3 >> 6; 1870 enc4 = chr3 & 63; 1871 if (isNaN(chr2)) { 1872 enc3 = enc4 = 64; 1873 } else if (isNaN(chr3)) { 1874 enc4 = 64; 1875 } 1876 output = output + this.KEY_STR.charAt(enc1) + this.KEY_STR.charAt(enc2) + this.KEY_STR.charAt(enc3) + this.KEY_STR.charAt(enc4); 1877 chr1 = chr2 = chr3 = ''; 1878 enc1 = enc2 = enc3 = enc4 = ''; 1879 if (!(i < input.length)) { 1880 break; 1881 } 1882 } 1883 return output; 1884 }; 1885 1886 ExifRestore.restore = function(origFileBase64, resizedFileBase64) { 1887 var image, rawImage, segments; 1888 if (!origFileBase64.match('data:image/jpeg;base64,')) { 1889 return resizedFileBase64; 1890 } 1891 rawImage = this.decode64(origFileBase64.replace('data:image/jpeg;base64,', '')); 1892 segments = this.slice2Segments(rawImage); 1893 image = this.exifManipulation(resizedFileBase64, segments); 1894 return 'data:image/jpeg;base64,' + this.encode64(image); 1895 }; 1896 1897 ExifRestore.exifManipulation = function(resizedFileBase64, segments) { 1898 var aBuffer, exifArray, newImageArray; 1899 exifArray = this.getExifArray(segments); 1900 newImageArray = this.insertExif(resizedFileBase64, exifArray); 1901 aBuffer = new Uint8Array(newImageArray); 1902 return aBuffer; 1903 }; 1904 1905 ExifRestore.getExifArray = function(segments) { 1906 var seg, x; 1907 seg = void 0; 1908 x = 0; 1909 while (x < segments.length) { 1910 seg = segments[x]; 1911 if (seg[0] === 255 & seg[1] === 225) { 1912 return seg; 1913 } 1914 x++; 1915 } 1916 return []; 1917 }; 1918 1919 ExifRestore.insertExif = function(resizedFileBase64, exifArray) { 1920 var array, ato, buf, imageData, mae, separatePoint; 1921 imageData = resizedFileBase64.replace('data:image/jpeg;base64,', ''); 1922 buf = this.decode64(imageData); 1923 separatePoint = buf.indexOf(255, 3); 1924 mae = buf.slice(0, separatePoint); 1925 ato = buf.slice(separatePoint); 1926 array = mae; 1927 array = array.concat(exifArray); 1928 array = array.concat(ato); 1929 return array; 1930 }; 1931 1932 ExifRestore.slice2Segments = function(rawImageArray) { 1933 var endPoint, head, length, seg, segments; 1934 head = 0; 1935 segments = []; 1936 while (true) { 1937 if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 218) { 1938 break; 1939 } 1940 if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 216) { 1941 head += 2; 1942 } else { 1943 length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3]; 1944 endPoint = head + length + 2; 1945 seg = rawImageArray.slice(head, endPoint); 1946 segments.push(seg); 1947 head = endPoint; 1948 } 1949 if (head > rawImageArray.length) { 1950 break; 1951 } 1952 } 1953 return segments; 1954 }; 1955 1956 ExifRestore.decode64 = function(input) { 1957 var base64test, buf, chr1, chr2, chr3, enc1, enc2, enc3, enc4, i, output; 1958 output = ''; 1959 chr1 = void 0; 1960 chr2 = void 0; 1961 chr3 = ''; 1962 enc1 = void 0; 1963 enc2 = void 0; 1964 enc3 = void 0; 1965 enc4 = ''; 1966 i = 0; 1967 buf = []; 1968 base64test = /[^A-Za-z0-9\+\/\=]/g; 1969 if (base64test.exec(input)) { 1970 console.warning('There were invalid base64 characters in the input text.\n' + 'Valid base64 characters are A-Z, a-z, 0-9, \'+\', \'/\',and \'=\'\n' + 'Expect errors in decoding.'); 1971 } 1972 input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); 1973 while (true) { 1974 enc1 = this.KEY_STR.indexOf(input.charAt(i++)); 1975 enc2 = this.KEY_STR.indexOf(input.charAt(i++)); 1976 enc3 = this.KEY_STR.indexOf(input.charAt(i++)); 1977 enc4 = this.KEY_STR.indexOf(input.charAt(i++)); 1978 chr1 = enc1 << 2 | enc2 >> 4; 1979 chr2 = (enc2 & 15) << 4 | enc3 >> 2; 1980 chr3 = (enc3 & 3) << 6 | enc4; 1981 buf.push(chr1); 1982 if (enc3 !== 64) { 1983 buf.push(chr2); 1984 } 1985 if (enc4 !== 64) { 1986 buf.push(chr3); 1987 } 1988 chr1 = chr2 = chr3 = ''; 1989 enc1 = enc2 = enc3 = enc4 = ''; 1990 if (!(i < input.length)) { 1991 break; 1992 } 1993 } 1994 return buf; 1995 }; 1996 1997 return ExifRestore; 1998 1999 })(); 2000 2001 2002 /* 2003 * contentloaded.js 2004 * 2005 * Author: Diego Perini (diego.perini at gmail.com) 2006 * Summary: cross-browser wrapper for DOMContentLoaded 2007 * Updated: 20101020 2008 * License: MIT 2009 * Version: 1.2 2010 * 2011 * URL: 2012 * http://javascript.nwbox.com/ContentLoaded/ 2013 * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE 2014 */ 2015 2016 contentLoaded = function(win, fn) { 2017 var add, doc, done, init, poll, pre, rem, root, top; 2018 done = false; 2019 top = true; 2020 doc = win.document; 2021 root = doc.documentElement; 2022 add = (doc.addEventListener ? "addEventListener" : "attachEvent"); 2023 rem = (doc.addEventListener ? "removeEventListener" : "detachEvent"); 2024 pre = (doc.addEventListener ? "" : "on"); 2025 init = function(e) { 2026 if (e.type === "readystatechange" && doc.readyState !== "complete") { 2027 return; 2028 } 2029 (e.type === "load" ? win : doc)[rem](pre + e.type, init, false); 2030 if (!done && (done = true)) { 2031 return fn.call(win, e.type || e); 2032 } 2033 }; 2034 poll = function() { 2035 var e, error1; 2036 try { 2037 root.doScroll("left"); 2038 } catch (error1) { 2039 e = error1; 2040 setTimeout(poll, 50); 2041 return; 2042 } 2043 return init("poll"); 2044 }; 2045 if (doc.readyState !== "complete") { 2046 if (doc.createEventObject && root.doScroll) { 2047 try { 2048 top = !win.frameElement; 2049 } catch (undefined) {} 2050 if (top) { 2051 poll(); 2052 } 2053 } 2054 doc[add](pre + "DOMContentLoaded", init, false); 2055 doc[add](pre + "readystatechange", init, false); 2056 return win[add](pre + "load", init, false); 2057 } 2058 }; 2059 2060 Dropzone._autoDiscoverFunction = function() { 2061 if (Dropzone.autoDiscover) { 2062 return Dropzone.discover(); 2063 } 2064 }; 2065 2066 contentLoaded(window, Dropzone._autoDiscoverFunction); 2067 2068 }).call(this);
1 {#bpm_base.html#} 2 {## # ————————47PerfectCRM實現CRM客戶報名流程————————#} 3 {#模板文件 #} 4 <!DOCTYPE html> 5 <html lang="zh-CN"> 6 <head> 7 {# <meta> 元素可提供有關頁面的元信息(meta-information),好比針對搜索引擎和更新頻度的描述和關鍵詞。#} 8 {# <meta> 標籤位於文檔的頭部,不包含任何內容。<meta> 標籤的屬性定義了與文檔相關聯的名稱/值對。#} 9 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 10 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 11 <meta name="viewport" content="width=device-width, initial-scale=1"> 12 <meta name="description" content=""> 13 <meta name="author" content=""> 14 <link rel="icon" href="/static/bpm_img/bpm_logo.jpg">{# icon,指的是圖標 #} 15 <title>業務流程</title> {# 頁面頭部顯示#} 16 {# 使用link來調用外部的css文件#} 17 <link rel="stylesheet" href="/static/bpm_css/bootstrap.css" /> {#導航欄樣式#} 18 <link rel="stylesheet" href="/static/bpm_css/dashboard.css" /> {#指示板樣式#} 19 20 {##————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片————————#} 21 <link rel="stylesheet" href="/static/bpm_plugins/dropzone/dropzone.css" /> {#上傳文件的插件#} 22 {##————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片————————#} 23 24 </head> 25 <body> 26 {% block body %}{#自定義內容 body#}{% endblock %} 27 {# 將純JavaScript的語句另外保存在一個"*.js"的文件中,須要時再調用。#} 28 <script src="/static/bpm_js/jquery.js"></script> {# jQuery 是一個 JavaScript庫,極大地簡化了 JavaScript 編程。#} 29 <script src="/static/bpm_js/bootstrap.js"></script> {#指示板JS事件#} 30 31 {##————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片————————#} 32 <script src="/static/bpm_js/jquery.cookie.js"></script> {#刪除文件JS事件#} 33 <script src="/static/bpm_plugins/dropzone/dropzone.js"></script> {#上傳文件的插件#} 34 {##————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片————————#} 35 36 {% block js %}{#自定義內容 JS#}{% endblock %} 37 38 39 </body> 40 </html> 41 {## # ————————47PerfectCRM實現CRM客戶報名流程————————#}
1 # settings.py 2 3 """ 4 Django settings for PerfectCRM project. 5 6 Generated by 'django-admin startproject' using Django 2.0.3. 7 8 For more information on this file, see 9 https://docs.djangoproject.com/en/2.0/topics/settings/ 10 11 For the full list of settings and their values, see 12 https://docs.djangoproject.com/en/2.0/ref/settings/ 13 """ 14 15 import os 16 17 # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 18 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 19 20 21 # Quick-start development settings - unsuitable for production 22 # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ 23 24 # SECURITY WARNING: keep the secret key used in production secret! 25 SECRET_KEY = 'atkhzsd7emv4_okn@ynhji)p)qbpuvhq+a7@yx5=chaa0$l_br' 26 27 # SECURITY WARNING: don't run with debug turned on in production! 28 DEBUG = True 29 30 ALLOWED_HOSTS = [] 31 32 33 # Application definition 34 35 INSTALLED_APPS = [ 36 'django.contrib.admin', 37 'django.contrib.auth', 38 'django.contrib.contenttypes', 39 'django.contrib.sessions', 40 'django.contrib.messages', 41 'django.contrib.staticfiles', 42 43 # ————————04PerfectCRM實現King_admin註冊功能———————— 44 # 'crm.apps.CrmConfig', 45 'crm', 46 # ————————04PerfectCRM實現King_admin註冊功能———————— 47 48 # ————————02PerfectCRM建立ADMIN頁面———————— 49 'king_admin', 50 # ————————02PerfectCRM建立ADMIN頁面———————— 51 # ————————38PerfectCRM實現全局帳號登陸註銷———————— 52 'gbacc', 53 # ————————38PerfectCRM實現全局帳號登陸註銷———————— 54 55 # ————————48PerfectCRM實現CRM客戶報名流程學生合同———————— 56 'bpm', 57 # ————————48PerfectCRM實現CRM客戶報名流程學生合同———————— 58 ] 59 60 MIDDLEWARE = [ 61 'django.middleware.security.SecurityMiddleware', 62 'django.contrib.sessions.middleware.SessionMiddleware', 63 'django.middleware.common.CommonMiddleware', 64 'django.middleware.csrf.CsrfViewMiddleware', 65 'django.contrib.auth.middleware.AuthenticationMiddleware', 66 'django.contrib.messages.middleware.MessageMiddleware', 67 'django.middleware.clickjacking.XFrameOptionsMiddleware', 68 ] 69 70 ROOT_URLCONF = 'PerfectCRM.urls' 71 72 TEMPLATES = [ 73 { 74 'BACKEND': 'django.template.backends.django.DjangoTemplates', 75 # ————————02PerfectCRM建立ADMIN頁面———————— 76 'DIRS': [os.path.join(BASE_DIR, 'templates'), 77 os.path.join(BASE_DIR, 'king_admin/king_templates'), 78 79 # ————————03PerfectCRM建立基本數據———————— 80 os.path.join(BASE_DIR, 'DBadd/DBadd_templates'), 81 # ————————03PerfectCRM建立基本數據———————— 82 # ————————38PerfectCRM實現全局帳號登陸註銷———————— 83 os.path.join(BASE_DIR, 'gbacc/gbacc_templates'), 84 # ————————38PerfectCRM實現全局帳號登陸註銷———————— 85 86 # ————————47PerfectCRM實現CRM客戶報名流程———————— 87 os.path.join(BASE_DIR, 'bpm/bpm_templates'), ] 88 # ————————47PerfectCRM實現CRM客戶報名流程———————— 89 90 , 91 # ————————02PerfectCRM建立ADMIN頁面———————— 92 'APP_DIRS': True, 93 'OPTIONS': { 94 'context_processors': [ 95 'django.template.context_processors.debug', 96 'django.template.context_processors.request', 97 'django.contrib.auth.context_processors.auth', 98 'django.contrib.messages.context_processors.messages', 99 ], 100 }, 101 }, 102 ] 103 104 WSGI_APPLICATION = 'PerfectCRM.wsgi.application' 105 106 107 # Database 108 # https://docs.djangoproject.com/en/2.0/ref/settings/#databases 109 110 DATABASES = { 111 'default': { 112 'ENGINE': 'django.db.backends.sqlite3', 113 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 114 } 115 } 116 117 118 # Password validation 119 # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators 120 121 AUTH_PASSWORD_VALIDATORS = [ 122 { 123 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 124 }, 125 { 126 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 127 }, 128 { 129 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 130 }, 131 { 132 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 133 }, 134 ] 135 136 137 # Internationalization 138 # https://docs.djangoproject.com/en/2.0/topics/i18n/ 139 140 # ————————01PerfectCRM基本配置ADMIN———————— 141 #LANGUAGE_CODE = 'en-us' 142 143 #英文轉中文方法 144 LANGUAGE_CODE = 'zh-Hans' 145 # ————————01PerfectCRM基本配置ADMIN———————— 146 147 TIME_ZONE = 'UTC' 148 149 USE_I18N = True 150 151 USE_L10N = True 152 153 USE_TZ = True 154 155 156 # Static files (CSS, JavaScript, Images) 157 # https://docs.djangoproject.com/en/2.0/howto/static-files/ 158 159 STATIC_URL = '/static/' 160 161 # ————————01PerfectCRM基本配置ADMIN———————— 162 STATICFILES_DIRS = [os.path.join(BASE_DIR,'king_admin/static'), 163 # ————————01PerfectCRM基本配置ADMIN———————— 164 # ————————38PerfectCRM實現全局帳號登陸註銷———————— 165 os.path.join(BASE_DIR, 'gbacc/static'), 166 # ————————38PerfectCRM實現全局帳號登陸註銷———————— 167 168 # ————————47PerfectCRM實現CRM客戶報名流程———————— 169 os.path.join(BASE_DIR, 'bpm/static'),] 170 # ————————47PerfectCRM實現CRM客戶報名流程———————— 171 172 173 # ————————34PerfectCRM實現CRM自定義用戶———————— 174 AUTH_USER_MODEL = 'crm.UserProfile'#使用自定的admin 表單 175 # ————————34PerfectCRM實現CRM自定義用戶———————— 176 177 178 179 # ————————44PerfectCRM實現帳號快速註冊登錄———————— 180 # send e-mail 181 EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' #email後端 182 EMAIL_USE_TLS = False #是否使用TLS安全傳輸協議 183 EMAIL_USE_SSL = True #是否使用SSL加密,qq企業郵箱要求使用 184 EMAIL_HOST = 'smtp.sina.cn' #發送郵件的郵箱 的 SMTP服務器 #根據狀況從新配置 185 EMAIL_PORT = 465 #發件箱的SMTP服務器端口 #通常不須要修改465 186 EMAIL_HOST_USER = 'perfectcrm@sina.cn' #發送郵件的郵箱帳號 #根據狀況從新配置 #perfectcrm@sina.cn pydjango@sina.cn 187 EMAIL_HOST_PASSWORD = 'admin123456' #發送郵件的郵箱密碼 #根據狀況從新配置 188 189 # ————————44PerfectCRM實現帳號快速註冊登錄———————— 190 191 192 # ————————46PerfectCRM實現登錄後頁面才能訪問———————— 193 LOGIN_URL = '/gbacc/gbacc_login/'# login_url 配置 #默認 /accounts/login/ #注意: / (絕對路徑) 194 # ————————46PerfectCRM實現登錄後頁面才能訪問———————— 195 196 197 198 # ————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片———————— 199 ENROLLED_DATA='%s/bpm/static/enrolled_data'%BASE_DIR#證件上傳 # 上傳路徑 200 # ————————51PerfectCRM實現CRM客戶報名流程學生合同上傳照片————————