Django项目:CRM(客户关系管理系统)--61--51PerfectCRM实现CRM客户报名流程学生合同上传照片
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客户报名流程学生合同上传照片————————
您的资助是我最大的动力!
金额随意,欢迎来赏!
如果,您希望更容易地发现我的新博客,不妨点击一下绿色通道的
因为,我的写作热情也离不开您的肯定支持,感谢您的阅读,我是【颜言】!