diff --git a/SplunkAppForWazuh/appserver/controllers/manager.py b/SplunkAppForWazuh/appserver/controllers/manager.py index a08100c53..1dbfe84db 100644 --- a/SplunkAppForWazuh/appserver/controllers/manager.py +++ b/SplunkAppForWazuh/appserver/controllers/manager.py @@ -13,6 +13,7 @@ """ +from . import api import jsonbak import requestsbak import uuid @@ -74,6 +75,7 @@ def __init__(self): self.db = database() self.config = self.get_config_on_memory() self.timeout = int(self.config['timeout']) + self.wazuh_api = api.api() self.session = requestsbak.Session() self.session.trust_env = False except Exception as e: @@ -511,6 +513,54 @@ def check_daemons(self, url, auth, verify, check_cluster): self.logger.error("manager: Error checking daemons: %s" % (e)) raise e + @expose_page(must_login=False, methods=['POST']) + def upload_file(self, **kwargs): + # Only rules files are uploaded currently + self.logger.debug("manager: Uploading file(s)") + try: + # Get file name and file content + split_file = str(kwargs["file"]).split('\', \'') + file_name = split_file[1] + file_content = split_file[2] + file_content = file_content[:len(file_content)-2] + file_content2 = file_content + + # Get path + dest_path = kwargs["path"] + + + # Get current API data + opt_id = kwargs["apiId"] + current_api_json = self.db.get(opt_id) + current_api_json = jsonbak.loads(current_api_json) + opt_username = str(current_api_json["data"]["userapi"]) + opt_password = str(current_api_json["data"]["passapi"]) + opt_base_url = str(current_api_json["data"]["url"]) + opt_base_port = str(current_api_json["data"]["portapi"]) + opt_cluster = False + if "filterType" in current_api_json["data"] and current_api_json["data"]["filterType"] == 'cluster.name': + opt_cluster = True + + # API requests auth + auth = requestsbak.auth.HTTPBasicAuth(opt_username, opt_password) + verify = False + url = opt_base_url + ":" + opt_base_port + + + if dest_path and dest_path == 'etc/lists/': + file_content = file_content.replace('\\n',"\n") + result = self.session.post(url + '/manager/files?path='+ dest_path +file_name, data=file_content, headers= {"Content-type": "application/octet-stream"}, auth=auth, timeout=20, verify=verify) + else: + file_content = file_content.replace('\\n','') + result = self.session.post(url + '/manager/files?path='+ dest_path +file_name, data=file_content, headers= {"Content-type": "application/xml"}, auth=auth, timeout=20, verify=verify) + result = jsonbak.loads(result.text) + if 'error' in result and result['error'] != 0: + return jsonbak.dumps({"status": "400", "text": "Error adding file: %s. Cause: %s" % (file_name,result["message"])}) + return jsonbak.dumps({"status": "200", "text": "File %s was updated successfully. " % file_name}) + except Exception as e: + self.logger.error("manager: Error trying to upload a file(s): %s" % (e)) + + def get_config_on_memory(self): try: self.logger.debug("manager: Getting configuration on memory.") diff --git a/SplunkAppForWazuh/appserver/static/css/styles/common.css b/SplunkAppForWazuh/appserver/static/css/styles/common.css index 50b7e806b..b3f3ce5f7 100644 --- a/SplunkAppForWazuh/appserver/static/css/styles/common.css +++ b/SplunkAppForWazuh/appserver/static/css/styles/common.css @@ -87,6 +87,10 @@ border-color: #396e3e !important; } +.agreeBtn:hover { + background-color: #43884a !important; +} + .cancelBtn { color: #000000 !important; background-color: #d9d9d9 !important; @@ -2280,7 +2284,7 @@ md-tabs.md-default-theme md-ink-bar, md-tabs md-ink-bar { margin: 2px 15px 0px -500px; height: auto; } -} + .link-disabled { cursor: not-allowed; opacity: 0.5; @@ -2436,6 +2440,149 @@ wazuh-card-slider { width: 100% ; } +.euiButton .euiButton__content { + height: 100%; + width: 100%; + vertical-align: middle; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 0 12px; +} + +.euiButton:disabled .euiButton__content { + pointer-events: auto; + cursor: not-allowed; +} + +.table-striped>tbody>tr:nth-child(odd)>td, .table-striped>tbody>tr:nth-child(odd)>th { +background-color: white; +} + +.link-table { + margin-right:10px; + font-size: 16px; + padding-left: 10px; +} + +.link-table:hover { + text-decoration: underline +} + + +.euiTextArea:focus { + background-color: rgb(250,250,250); + border-bottom: 2px solid rgb(63, 126, 67); +} + +::-webkit-scrollbar { + width: 7px; + height: 7px; +} + +/* Track */ +::-webkit-scrollbar-track { + background: #f1f1f1; +} + +/* Handle */ +::-webkit-scrollbar-thumb { + background: #888; + border-radius: 10px; +} + +/* Handle on hover */ +::-webkit-scrollbar-thumb:hover { + background: #555; +} + + +.logtest-fullscreen { + position: fixed !important; + top: 0; + left: 0; + overflow: hidden; + height: 100% !important; + width: 100% !important; + max-width: 100% !important; + max-height: 100% !important; + z-index: 100; +} +.dz-filename { + padding-top: 18px !important; +} + +.dropzone .dz-preview .dz-progress { + margin-top: -18px !important; +} + +.dropzone.dz-clickable { + cursor: pointer; + background-color: #b4c5b573; + border: 1px solid rgba(0, 0, 0, 0.12); +} + + +.wz-popover-wrapper { + position: relative; + top: 55px; + right: -92%; + display: inline-block; + z-index: 100; +} +.wz-popover-content { + opacity: 0; + z-index:100; + visibility: hidden; + position: absolute; + left: -350px; + transform: translate(0, 10px); + background-color: #ffffff; + padding: 1rem 1.5rem 1.5rem 1.5rem; + box-shadow: 1px 2px 4px 1px rgba(0, 0, 0, 0.76); + width: 350px; +} +.wz-popover-content:before { + content: ""; + position: fixed; + width: 10px; + height: 10px; + background: white; + transform: rotate(45deg); + top: -6px; + z-index: 1 !important; + left: 326px; + border-top: 1px solid #80808085; + border-left: 1px solid #80808085; +} +.wz-popover-wrapper .wz-popover-content { + z-index: 10; + opacity: 1; + visibility: visible; + height:auto; + transform: translate(0, 10px); +} + + +.wz-popover-message { + text-align: center; +} + + +.wz-success-message { + color: rgb(32, 121, 32) !important +} + +.wz-error-message { + color: rgb(173, 16, 16) !important +} + .wz-min-height-40 { min-height: 40px !important; } \ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/css/styles/component.css b/SplunkAppForWazuh/appserver/static/css/styles/component.css index a2d460f86..6ba53fe26 100644 --- a/SplunkAppForWazuh/appserver/static/css/styles/component.css +++ b/SplunkAppForWazuh/appserver/static/css/styles/component.css @@ -299,6 +299,11 @@ md-chip { flex-grow: 1; } +.euiButtonIcon--primary>.euiIcon:hover { +padding-top:1px; +border-bottom: 1px solid; +} + .euiButtonIcon { font-family: "Inter UI", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-weight: 400; @@ -342,7 +347,7 @@ md-chip { } .euiButtonIcon--primary { - color: #006BB4; + color: rgba(34, 129, 55, 0.767); } /* DEV TOOLS */ diff --git a/SplunkAppForWazuh/appserver/static/css/styles/dropzone.css b/SplunkAppForWazuh/appserver/static/css/styles/dropzone.css new file mode 100644 index 000000000..3a143b289 --- /dev/null +++ b/SplunkAppForWazuh/appserver/static/css/styles/dropzone.css @@ -0,0 +1,2 @@ +@-webkit-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%, 70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@-moz-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%, 70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%, 70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@-webkit-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@-moz-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@-webkit-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}@-moz-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}@keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}.dropzone,.dropzone *{box-sizing:border-box}.dropzone{min-height:125px;border:2px solid rgba(0,0,0,0.3);background:white;padding:15px 15px}.dropzone.dz-clickable{cursor:pointer}.dropzone.dz-clickable *{cursor:default}.dropzone.dz-clickable .dz-message,.dropzone.dz-clickable .dz-message *{cursor:pointer}.dropzone.dz-started .dz-message{display:none}.dropzone.dz-drag-hover{border-style:solid}.dropzone.dz-drag-hover .dz-message{opacity:0.5}.dropzone .dz-message{text-align:center;margin:2em 0}.dropzone .dz-preview{position:relative;display:inline-block;vertical-align:top;margin:16px;min-height:100px}.dropzone .dz-preview:hover{z-index:1000}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview.dz-file-preview .dz-image{border-radius:20px;background:#999;background:linear-gradient(to bottom, #eee, #ddd)}.dropzone .dz-preview.dz-file-preview .dz-details{opacity:1}.dropzone .dz-preview.dz-image-preview{background:white}.dropzone .dz-preview.dz-image-preview .dz-details{-webkit-transition:opacity 0.2s linear;-moz-transition:opacity 0.2s linear;-ms-transition:opacity 0.2s linear;-o-transition:opacity 0.2s linear;transition:opacity 0.2s linear}.dropzone .dz-preview .dz-remove{font-size:14px;text-align:center;display:block;cursor:pointer;border:none}.dropzone .dz-preview .dz-remove:hover{text-decoration:underline}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview .dz-details{z-index:20;position:absolute;top:0;left:0;opacity:0;font-size:13px;min-width:100%;max-width:100%;padding:2em 1em;text-align:center;color:rgba(0,0,0,0.9);line-height:150%}.dropzone .dz-preview .dz-details .dz-size{margin-bottom:1em;font-size:16px}.dropzone .dz-preview .dz-details .dz-filename{white-space:nowrap}.dropzone .dz-preview .dz-details .dz-filename:hover span{border:1px solid rgba(170,170,170,0.8);background-color:rgba(240,240,240,1)}.dropzone .dz-preview .dz-details .dz-filename:not(:hover){overflow:hidden;text-overflow:ellipsis}.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span{border:1px solid transparent}.dropzone .dz-preview .dz-details .dz-filename span,.dropzone .dz-preview .dz-details .dz-size span{background-color:rgba(255,255,255,0.4);padding:0 0.4em;border-radius:3px}.dropzone .dz-preview:hover .dz-image img{-webkit-transform:scale(1.05, 1.05);-moz-transform:scale(1.05, 1.05);-ms-transform:scale(1.05, 1.05);-o-transform:scale(1.05, 1.05);transform:scale(1.05, 1.05);-webkit-filter:blur(8px);filter:blur(8px)}.dropzone .dz-preview .dz-image{border-radius:20px;overflow:hidden;width:120px;height:120px;position:relative;display:block;z-index:10}.dropzone .dz-preview .dz-image img{display:block}.dropzone .dz-preview.dz-success .dz-success-mark{-webkit-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-moz-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-ms-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-o-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview.dz-error .dz-error-mark{opacity:1;-webkit-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-moz-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-ms-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-o-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview .dz-success-mark,.dropzone .dz-preview .dz-error-mark{pointer-events:none;opacity:0;z-index:500;position:absolute;display:block;top:50%;left:50%;margin-left:-27px;margin-top:-27px}.dropzone .dz-preview .dz-success-mark svg,.dropzone .dz-preview .dz-error-mark svg{display:block;width:54px;height:54px}.dropzone .dz-preview.dz-processing .dz-progress{opacity:1;-webkit-transition:all 0.2s linear;-moz-transition:all 0.2s linear;-ms-transition:all 0.2s linear;-o-transition:all 0.2s linear;transition:all 0.2s linear}.dropzone .dz-preview.dz-complete .dz-progress{opacity:0;-webkit-transition:opacity 0.4s ease-in;-moz-transition:opacity 0.4s ease-in;-ms-transition:opacity 0.4s ease-in;-o-transition:opacity 0.4s ease-in;transition:opacity 0.4s ease-in}.dropzone .dz-preview:not(.dz-processing) .dz-progress{-webkit-animation:pulse 6s ease infinite;-moz-animation:pulse 6s ease infinite;-ms-animation:pulse 6s ease infinite;-o-animation:pulse 6s ease infinite;animation:pulse 6s ease infinite}.dropzone .dz-preview .dz-progress{opacity:1;z-index:1000;pointer-events:none;position:absolute;height:16px;left:50%;top:50%;margin-top:-8px;width:80px;margin-left:-40px;background:rgba(255,255,255,0.9);-webkit-transform:scale(1);border-radius:8px;overflow:hidden}.dropzone .dz-preview .dz-progress .dz-upload{background:#333;background:linear-gradient(to bottom, #666, #444);position:absolute;top:0;left:0;bottom:0;width:0;-webkit-transition:width 300ms ease-in-out;-moz-transition:width 300ms ease-in-out;-ms-transition:width 300ms ease-in-out;-o-transition:width 300ms ease-in-out;transition:width 300ms ease-in-out}.dropzone .dz-preview.dz-error .dz-error-message{display:block}.dropzone .dz-preview.dz-error:hover .dz-error-message{opacity:1;pointer-events:auto}.dropzone .dz-preview .dz-error-message{pointer-events:none;z-index:1000;position:absolute;display:block;display:none;opacity:0;-webkit-transition:opacity 0.3s ease;-moz-transition:opacity 0.3s ease;-ms-transition:opacity 0.3s ease;-o-transition:opacity 0.3s ease;transition:opacity 0.3s ease;border-radius:8px;font-size:13px;top:130px;left:-10px;width:140px;background:#be2626;background:linear-gradient(to bottom, #be2626, #a92222);padding:0.5em 1.2em;color:white}.dropzone .dz-preview .dz-error-message:after{content:'';position:absolute;top:-6px;left:64px;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #be2626} +.dropzone,.dropzone *{box-sizing:border-box}.dropzone{position:relative}.dropzone .dz-preview{position:relative;display:inline-block;width:120px;margin:0.5em}.dropzone .dz-preview .dz-progress{display:block;height:15px;border:1px solid #aaa}.dropzone .dz-preview .dz-progress .dz-upload{display:block;height:100%;width:0;background:green}.dropzone .dz-preview .dz-error-message{color:red;display:none}.dropzone .dz-preview.dz-error .dz-error-message,.dropzone .dz-preview.dz-error .dz-error-mark{display:block}.dropzone .dz-preview.dz-success .dz-success-mark{display:block}.dropzone .dz-preview .dz-error-mark,.dropzone .dz-preview .dz-success-mark{position:absolute;display:none;left:30px;top:30px;width:54px;height:58px;left:50%;margin-left:-27px} \ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/css/styles/layout.css b/SplunkAppForWazuh/appserver/static/css/styles/layout.css index 514bbf37f..e9cf96c97 100644 --- a/SplunkAppForWazuh/appserver/static/css/styles/layout.css +++ b/SplunkAppForWazuh/appserver/static/css/styles/layout.css @@ -28,6 +28,10 @@ margin: 8px 8px 8px 0px; } +.wz-margin-8 { + margin: 8px; +} + .wz-margin-right-15 { margin-right: 15px; } diff --git a/SplunkAppForWazuh/appserver/static/css/styles/loader.css b/SplunkAppForWazuh/appserver/static/css/styles/loader.css index 3785b2346..92ff05d1c 100644 --- a/SplunkAppForWazuh/appserver/static/css/styles/loader.css +++ b/SplunkAppForWazuh/appserver/static/css/styles/loader.css @@ -21,4 +21,5 @@ @import "wz_tooltips.css"; @import "xml-editor.css"; @import "wz-multiple-selector.css"; -@import "wz-add-filter-chip.css"; \ No newline at end of file +@import "wz-add-filter-chip.css"; +@import "dropzone.css"; \ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/config/routes/management-states.js b/SplunkAppForWazuh/appserver/static/js/config/routes/management-states.js index 70d758347..891411e16 100644 --- a/SplunkAppForWazuh/appserver/static/js/config/routes/management-states.js +++ b/SplunkAppForWazuh/appserver/static/js/config/routes/management-states.js @@ -18,7 +18,10 @@ define(['../module'], function(module) { .state('manager', { templateUrl: BASE_URL + - 'static/app/SplunkAppForWazuh/js/controllers/management/welcome/manager-welcome.html' + 'static/app/SplunkAppForWazuh/js/controllers/management/welcome/manager-welcome.html', + onEnter: () => { + window.sessionStorage.showLogtest = false + } }) // Manager - Monitoring .state('mg-monitoring', { diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/management/cdb/manager-cdb.html b/SplunkAppForWazuh/appserver/static/js/controllers/management/cdb/manager-cdb.html index 746a9f495..f29bcb2d1 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/management/cdb/manager-cdb.html +++ b/SplunkAppForWazuh/appserver/static/js/controllers/management/cdb/manager-cdb.html @@ -1,245 +1,280 @@
-
-
- Management - / Ruleset - / CDB Lists -
-
-
-
-
- - - - Rules - Decoders - - Lists - +
+ +
+
+
+ Management + / Ruleset + / CDB Lists +
+
+
+
+ + Rules + Decoders + + Lists + + +
+
- -
-
-
-
-
-
-
-
-
-
- - -
-
-
- - - Add new list - - - - - - File: {{getFilter('file')}} - - - - - File: {{getFilter('hipaa')}} - - - - - File: {{getFilter('NIST 800-53')}} - - - - - Path: {{getFilter('path')}} - - - - - Level: {{getFilter('level')}} - - - - - Group: {{getFilter('group')}} - - - - - PCI control: {{getFilter('pci')}} - - - - - GDPR: {{getFilter('gdpr')}} - - - - -
- - -
- -
-
-
+
+
+ +
+
+ +
+
+
+
+
+
+
+ +
+ + +
+ CDB Lists + + - -
- -
-
- -
- - - - -
- - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - -
KeyValueActions
- - - - - -
{{item[0]}} -
- -
-
- {{item[1]}} -
-
-
- - - - - Cancel - + + + Add new list - - - Apply - + + + Export formatted + + + Import files + + + + Refresh + +
+ +
+
- - - -
-
- This entry will be - removed -
-
- Cancel - Confirm -
+ +
-
- {{ totalItems }} items -
-
-
+ + +
+
+ + +
+ +
+
+ +
+ + + + +
+ + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
KeyValueActions
+ + + + + +
{{item[0]}} +
+ +
+
+ {{item[1]}} +
+
+
+ + + + + Cancel + + + + + Apply + + + + + + +
+
+ This entry will be + removed +
+
+ Cancel + Confirm +
+
+
+
+ {{ totalItems }} items + +
+
+
+
+
+
+ +
+
+
-
- +
\ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/management/decoders/manager-decoders.html b/SplunkAppForWazuh/appserver/static/js/controllers/management/decoders/manager-decoders.html index 6de2b1ab7..f8e5c85e3 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/management/decoders/manager-decoders.html +++ b/SplunkAppForWazuh/appserver/static/js/controllers/management/decoders/manager-decoders.html @@ -1,175 +1,222 @@
-
-
- Management - / Ruleset - / Decoders -
-
-
-
-
- - - - Rules - Decoders - Lists - - - - -
-
-
-
-
-
-
-
-
-
- -
- +
+ +
+
+
+ Management + / Ruleset + / Decoders +
+
+ +
+
+ + Rules + Decoders + Lists +
-
- +
+ +
+
+ +
+
+ +
+
+
+
-
- +
+
+ +
+ + +
+ Decoders + + + + + + + + Manage decoders files + + + + Export formatted + + + + Import files + + + + Refresh + + +
+ +
+
+ +
+ +
+
+ +
+
+ +
+ + +
+
+
+ + + + + File: {{ getFilter('file') }} + + + + + Path: {{ getFilter('path') }} + + + + +
+ + + + + + + + +
+
+
+ +
+
+ +
+
+ + + + +
+
+ + +
+
+ + + + +
+
+ + + + +
+
+ + +
+
+ + + +
+ + +
+
- - -
-
-
- - - - Add new decoders file - - Manage decoders files - - - - - - - - - - - File: {{ getFilter('file') }} - - - - - Path: {{ getFilter('path') }} - - - - -
- - - - - - - - -
- -
-
-
- - -
-
- - - - -
-
- - -
-
- -
-
- - - - -
-
- - -
-
- - -
- - + + +
-
\ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/manager-ruleset.html b/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/manager-ruleset.html index aa324e1c2..d402cc6cc 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/manager-ruleset.html +++ b/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/manager-ruleset.html @@ -1,206 +1,301 @@
-
-
- Management - / Ruleset - / Rules -
-
-
-
-
- - - - Rules - Decoders - - Lists - +
- -
-
-
-
-
-
-
-
-
+
- -
- -
-
- -
-
- +
+ Management + / Ruleset + / Rules +
+
+
+ +
+
+
+ + Rules + Decoders + + Lists + + +
+
+ +
+
+ +
+
+ +
+
+
- - -
-
-
- - - - - Add new rules file - - Manage rules files - - - - - - - - - File: {{getFilter('file')}} - - - - - Path: {{getFilter('path')}} - - - - - Level: {{getFilter('level')}} - - - - - Group: {{getFilter('group')}} - - - - - PCI control: {{getFilter('pci')}} - - - - - HIPAA: {{getFilter('hipaa')}} - - - - - NIST 800-53: {{getFilter('nist-800-53')}} - - - - - GDPR: {{getFilter('gdpr')}} - - - - -
- - - - - - - - -
- -
-
-
+
+
+ +
+ + +
+ Rules + + - -
-
- - - + -
-
- - -
-
+ + + Manage rules files + + + + Export formatted + + + + Import files + + + + Refresh + +
+
+
+ + + +
+ +
+
+ +
+
+ +
+
+
+ + + + File: {{getFilter('file')}} + + + + + Path: {{getFilter('path')}} + + + + + Level: {{getFilter('level')}} + + + + + Group: {{getFilter('group')}} + + + + + PCI control: {{getFilter('pci')}} + + + + + HIPAA: {{getFilter('hipaa')}} + + + + + NIST 800-53: {{getFilter('nist-800-53')}} + + + + + GDPR: {{getFilter('gdpr')}} + + + + +
+ + + + + + + + +
+
+
+ +
+
+ + +
+
+ + + + +
+
+ + +
+
+ + + +
+
+ + + + +
+
+ + +
+
+ + +
+ + +
+
+
- -
-
- - - +
+ +
-
- - -
-
- - -
- - -
-
\ No newline at end of file +
diff --git a/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/ruleset.js b/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/ruleset.js index 7c239452f..b812a9b31 100644 --- a/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/ruleset.js +++ b/SplunkAppForWazuh/appserver/static/js/controllers/management/rules/ruleset.js @@ -71,8 +71,11 @@ define(['../../module', 'FileSaver'], function(app) { } catch (err) { this.filter = [] } + this.scope.uploadingFiles = false this.scope.searchTerm = '' this.scope.viewingDetail = false + this.scope.showLogtest = window.sessionStorage.showLogtest === "true" + this.scope.fullScreen = false this.scope.isArray = angular.isArray // eslint-disable-line this.initialize() } @@ -89,6 +92,7 @@ define(['../../module', 'FileSaver'], function(app) { this.scope.search = term => this.search(term) this.scope.includesFilter = filterName => this.includesFilter(filterName) this.scope.getFilter = filterName => this.getFilter(filterName) + this.scope.switchLogtest = () => this.switchLogtest() this.scope.removeFilter = filterName => this.removeFilter(filterName) this.scope.colorRuleArg = ruleArg => this.colorRegex(ruleArg) this.scope.closeDetailView = clear => this.closeDetailView(clear) @@ -106,6 +110,8 @@ define(['../../module', 'FileSaver'], function(app) { this.scope.enableSave = () => this.enableSave() this.scope.switchFiles = () => this.switchFiles() + this.scope.switchUploadFiles = () => this.switchUploadFiles() + this.scope.closeEditingFile = () => this.closeEditingFile() this.scope.xmlIsValid = valid => this.xmlIsValid(valid) @@ -160,6 +166,17 @@ define(['../../module', 'FileSaver'], function(app) { this.removeAllFilters() } + + /** + * Open or closes the upload files view + */ + switchUploadFiles() { + this.scope.uploadingFiles = !this.scope.uploadingFiles + setTimeout(() => { + this.scope.$applyAsync() + }, 1) + } + /** * Exports the table in CSV format */ @@ -183,6 +200,7 @@ define(['../../module', 'FileSaver'], function(app) { return } + /** * Returns the color * @param {*} regex @@ -245,6 +263,7 @@ define(['../../module', 'FileSaver'], function(app) { this.scope.$applyAsync() } + /** * Searches a rule * @param {String} term @@ -380,6 +399,14 @@ define(['../../module', 'FileSaver'], function(app) { return filtered.length ? filtered[0].value : '' } + /** + * Open or closes Logtest + */ + switchLogtest() { + this.scope.showLogtest = !this.scope.showLogtest + window.sessionStorage.showLogtest = this.scope.showLogtest + } + /** * Removes a filter by name * @param {String} filterName diff --git a/SplunkAppForWazuh/appserver/static/js/directives/index.js b/SplunkAppForWazuh/appserver/static/js/directives/index.js index b877eac2f..5c376fabd 100644 --- a/SplunkAppForWazuh/appserver/static/js/directives/index.js +++ b/SplunkAppForWazuh/appserver/static/js/directives/index.js @@ -20,5 +20,7 @@ define([ './wz-head-toaster/wz-head-toaster', './wz-kbn-switch/wz-kbn-switch', './wz-alert-metrics/wz-alert-metrics', - './wz-card-slider/wz-card-slider' + './wz-card-slider/wz-card-slider', + './wz-logtest/wz-logtest', + './wz-upload-files/wz-upload-files', ], function() {}) diff --git a/SplunkAppForWazuh/appserver/static/js/directives/wz-logtest/wz-logtest.html b/SplunkAppForWazuh/appserver/static/js/directives/wz-logtest/wz-logtest.html new file mode 100644 index 000000000..015971460 --- /dev/null +++ b/SplunkAppForWazuh/appserver/static/js/directives/wz-logtest/wz-logtest.html @@ -0,0 +1,37 @@ +
+ +
+ Logtest +
+ +
+
+ + + + + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ +
\ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/directives/wz-logtest/wz-logtest.js b/SplunkAppForWazuh/appserver/static/js/directives/wz-logtest/wz-logtest.js new file mode 100644 index 000000000..86deed713 --- /dev/null +++ b/SplunkAppForWazuh/appserver/static/js/directives/wz-logtest/wz-logtest.js @@ -0,0 +1,78 @@ +/* + * Wazuh app - Wazuh Log test directive + * Copyright (C) 2015-2019 Wazuh, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Find more information about this on the LICENSE file. + */ +define(['../module'], function(directives) { + 'use strict' + directives.directive('wzLogtest', function(BASE_URL) { + return { + restrict: 'E', + scope: { + fullScreen: '=fullScreen', + closeLogtest: '&', + }, + replace: true, + controller($scope,$document,$notificationService) { + + $scope.switchFullScreen = () => { + $scope.fullScreen = !$scope.fullScreen + } + + /** Bind ESCAPE key to close the full screen box */ + $($document).keyup(function(e) { + if(e.which == 27) { + $scope.fullScreen = false; + $scope.$applyAsync() + } + }); + + /** Remove key up bind */ + $scope.$on('$destroy', () => { + $($document).unbind() + }) + + $scope.toClipboard = element => { + try { + const el = $document[0].getElementById(element) + const range = $document[0].createRange() + range.selectNodeContents(el) + const sel = window.getSelection() + sel.removeAllRanges() + sel.addRange(range) + $document[0].execCommand('copy') + $notificationService.showSimpleToast('Content has been copied') + } catch (error) { + $notificationService.showErrorToast( + 'Cannot copy the selected content' + ) + } + } + + + $scope.inputLog = "" + $scope.logResult = `**Phase 1: Completed pre-decoding. + full event: 'timestamp:2019-09-03T13:22:27.950+0000 rule:level:7 rule:description:python: Undocumented local_file protocol allows remote attackers to bypass protection mechanisms rule:id:23504 rule:firedtimes:33 rule:mail:false rule:groups:[vulnerability-detector] rule:gdpr:[IV_35.7.d] agent:id:000 agent:name:a205e5b2a1aa manager:{name:a205e5b2a1aa} id:1567516947.252273 cluster:name:wazuh cluster:node:master decoder:{name:json} data:{vulnerability:cve:CVE-2019-9948} data:{vulnerability:title:python: Undocumented local_file protocol allows remote attackers to bypass protection mechanisms} data:{vulnerability:severity:Medium} data:{vulnerability:published:2019-03-23T00:00:00+00:00} data:{vulnerability:state:Fixed} data:{vulnerability:cvss:{cvss3_score:7.400000}} data:{vulnerability:package:name:python} data:{vulnerability:package:version:2.7.5-80.el7_6} data:{vulnerability:package:condition:less than 2.7.5-86.el7} data:{vulnerability:advisories:RHSA-2019:2030,RHSA-2019:1700} data:{vulnerability:cwe_reference:CWE-749} data:{vulnerability:bugzilla_reference:https://bugzilla.redhat.com/show_bug.cgi?id=1695570} data:{vulnerability:reference:https://access.redhat.com/security/cve/CVE-2019-9948} location:vulnerability-detector' + timestamp: '(null)' + hostname: 'a205e5b2a1aa' + program_name: '(null)' + log: 'timestamp:2019-09-03T13:22:27.950+0000 rule:level:7 rule:description:python: Undocumented local_file protocol allows remote attackers to bypass protection mechanisms rule:id:23504 rule:firedtimes:33 rule:mail:false rule:groups:[vulnerability-detector] rule:gdpr:[IV_35.7.d] agent:id:000 agent:name:a205e5b2a1aa manager:{name:a205e5b2a1aa} id:1567516947.252273 cluster:name:wazuh cluster:node:master decoder:{name:json} data:{vulnerability:cve:CVE-2019-9948} data:{vulnerability:title:python: Undocumented local_file protocol allows remote attackers to bypass protection mechanisms} data:{vulnerability:severity:Medium} data:{vulnerability:published:2019-03-23T00:00:00+00:00} data:{vulnerability:state:Fixed} data:{vulnerability:cvss:{cvss3_score:7.400000}} data:{vulnerability:package:name:python} data:{vulnerability:package:version:2.7.5-80.el7_6} data:{vulnerability:package:condition:less than 2.7.5-86.el7} data:{vulnerability:advisories:RHSA-2019:2030,RHSA-2019:1700} data:{vulnerability:cwe_reference:CWE-749} data:{vulnerability:bugzilla_reference:https://bugzilla.redhat.com/show_bug.cgi?id=1695570} data:{vulnerability:reference:https://access.redhat.com/security/cve/CVE-2019-9948} location:vulnerability-detector' + **Phase 2: Completed decoding. + No decoder matched. + **Phase 3: Completed filtering (rules). + Rule id: '1002' + Level: '2' + Description: 'Unknown problem somewhere in the system.'` + }, + templateUrl: + BASE_URL + + '/static/app/SplunkAppForWazuh/js/directives/wz-logtest/wz-logtest.html' + } + }) +}) diff --git a/SplunkAppForWazuh/appserver/static/js/directives/wz-svg/wz-svg.html b/SplunkAppForWazuh/appserver/static/js/directives/wz-svg/wz-svg.html index d1eaeffa0..5663f0d18 100644 --- a/SplunkAppForWazuh/appserver/static/js/directives/wz-svg/wz-svg.html +++ b/SplunkAppForWazuh/appserver/static/js/directives/wz-svg/wz-svg.html @@ -12,19 +12,19 @@ - - - {{svgTooltip}} - - - - - - - - + + + + {{svgTooltip}} + + + + + + + @@ -400,4 +400,21 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + diff --git a/SplunkAppForWazuh/appserver/static/js/directives/wz-table/wz-table.html b/SplunkAppForWazuh/appserver/static/js/directives/wz-table/wz-table.html index ce679efdb..7823c9fd9 100644 --- a/SplunkAppForWazuh/appserver/static/js/directives/wz-table/wz-table.html +++ b/SplunkAppForWazuh/appserver/static/js/directives/wz-table/wz-table.html @@ -19,7 +19,7 @@ Show or hide columns - +
diff --git a/SplunkAppForWazuh/appserver/static/js/directives/wz-upload-files/wz-upload-files.html b/SplunkAppForWazuh/appserver/static/js/directives/wz-upload-files/wz-upload-files.html new file mode 100644 index 000000000..ed06a9bd4 --- /dev/null +++ b/SplunkAppForWazuh/appserver/static/js/directives/wz-upload-files/wz-upload-files.html @@ -0,0 +1,89 @@ +
+
+

{{uploadTitle}}

+
+
+
+ Select or drag and drop a file +
+
+
+
+
+ + + +
+ + +
+
+ +
+
+
+ + +
+
+ +
+
+
+ +
+
+ + + +
+
+ Check +
+
+ Error +
+ Remove file +
+ +
+ + +
+
+
+ +

+    + (

) + + +   +
+
+
+ +
+
+
+ + +    + +
+
\ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/directives/wz-upload-files/wz-upload-files.js b/SplunkAppForWazuh/appserver/static/js/directives/wz-upload-files/wz-upload-files.js new file mode 100644 index 000000000..de52eb4dc --- /dev/null +++ b/SplunkAppForWazuh/appserver/static/js/directives/wz-upload-files/wz-upload-files.js @@ -0,0 +1,110 @@ +/* + * Wazuh app - Wazuh upload files directive + * Copyright (C) 2015-2019 Wazuh, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Find more information about this on the LICENSE file. + */ + +define(['../module','Dropzone'], function(app,Dropzone) { + 'use strict' + app.directive('wzUploadFiles', function(BASE_URL) { + return { + restrict: 'E', + scope: { + uploadTitle: '@uploadTitle', + allowedExtensions: '=allowedExtensions', + refreshList: '&', + path: '@path' + }, + controller($scope,$currentDataService) { + $scope.noFilesAdded = true + var previewNode = document.querySelector("#template"); + previewNode.id = ""; + var previewTemplate = previewNode.parentNode.innerHTML; + setTimeout(() => { + previewNode.parentNode.innerHTML = "" + }, 250) + + const apiId = $currentDataService.getApi() + const currentApi = apiId['_key'] + + $scope.myDropzone = new Dropzone("#myDropzone",{ + url: `en-us/custom/SplunkAppForWazuh//manager/upload_file?apiId=${currentApi}&path=${$scope.path}`, + autoProcessQueue: false, + parallelUploads: 5, + maxFiles: 5, + previewTemplate: previewTemplate, + previewsContainer: "#previews", + acceptedFiles: $scope.allowedExtensions + }) + + + $scope.removeAllFiles = () => { + $scope.myDropzone.removeAllFiles(true) + $scope.noFilesAdded = true; + } + + $scope.uploadAllFiles = () => { + if($scope.myDropzone.files.length > 0){ + $scope.myDropzone.processQueue() + $scope.noFilesAdded = false + } + } + $scope.myDropzone.on("success", function (file, message) { + message = JSON.parse(message) + if (file.previewElement) { + file.previewElement.classList.add("dz-error"); + + for (var _iterator7 = file.previewElement.querySelectorAll("[data-dz-errormessage]"), _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { + var _ref6; + + if (_isArray7) { + if (_i7 >= _iterator7.length) break; + _ref6 = _iterator7[_i7++]; + } else { + _i7 = _iterator7.next(); + if (_i7.done) break; + _ref6 = _i7.value; + } + + var node = _ref6; + + if(message.status === "200"){ + node.classList.add("wz-success-message"); + }else{ + node.classList.add("wz-error-message"); + } + node.textContent = message.text || "Unknown error"; + } + } + }); + + $scope.myDropzone.on("error", function (file, jsonResponse) { + var errorMessage = "Could not upload document: "; + if (jsonResponse["ValidationMessage"] != null) { + errorMessage += jsonResponse["ValidationMessage"]; + } else { + errorMessage += "unknown error"; + } + }); + + $scope.myDropzone.on("removedfile", function (file) { + if($scope.myDropzone.files.length === 0){ + $scope.noFilesAdded = true + $scope.$applyAsync() + } + }); + + + }, + templateUrl: + BASE_URL + + '/static/app/SplunkAppForWazuh/js/directives/wz-upload-files/wz-upload-files.html' + } + }) +}) diff --git a/SplunkAppForWazuh/appserver/static/js/libs/dropzone/dropzone.js b/SplunkAppForWazuh/appserver/static/js/libs/dropzone/dropzone.js new file mode 100644 index 000000000..e959ec9e2 --- /dev/null +++ b/SplunkAppForWazuh/appserver/static/js/libs/dropzone/dropzone.js @@ -0,0 +1,3545 @@ +// Uses AMD or browser globals to create a jQuery plugin. +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else { + // Browser globals + factory(jQuery); + } + } (function (jQuery) { + var module = { exports: { } }; // Fake component + + "use strict"; + + var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + + function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + + function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + + /* + * + * More info at [www.dropzonejs.com](http://www.dropzonejs.com) + * + * Copyright (c) 2012, Matias Meno + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + + // The Emitter class provides the ability to call `.on()` on Dropzone to listen + // to events. + // It is strongly based on component's emitter class, and I removed the + // functionality because of the dependency hell with different frameworks. + var Emitter = function () { + function Emitter() { + _classCallCheck(this, Emitter); + } + + _createClass(Emitter, [{ + key: "on", + + // Add an event listener for given event + value: function on(event, fn) { + this._callbacks = this._callbacks || {}; + // Create namespace for this event + if (!this._callbacks[event]) { + this._callbacks[event] = []; + } + this._callbacks[event].push(fn); + return this; + } + }, { + key: "emit", + value: function emit(event) { + this._callbacks = this._callbacks || {}; + var callbacks = this._callbacks[event]; + + if (callbacks) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + for (var _iterator = callbacks, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref; + + if (_isArray) { + if (_i >= _iterator.length) break; + _ref = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref = _i.value; + } + + var callback = _ref; + + callback.apply(this, args); + } + } + + return this; + } + + // Remove event listener for given event. If fn is not provided, all event + // listeners for that event will be removed. If neither is provided, all + // event listeners will be removed. + + }, { + key: "off", + value: function off(event, fn) { + if (!this._callbacks || arguments.length === 0) { + this._callbacks = {}; + return this; + } + + // specific event + var callbacks = this._callbacks[event]; + if (!callbacks) { + return this; + } + + // remove all handlers + if (arguments.length === 1) { + delete this._callbacks[event]; + return this; + } + + // remove specific handler + for (var i = 0; i < callbacks.length; i++) { + var callback = callbacks[i]; + if (callback === fn) { + callbacks.splice(i, 1); + break; + } + } + + return this; + } + }]); + + return Emitter; + }(); + + var Dropzone = function (_Emitter) { + _inherits(Dropzone, _Emitter); + + _createClass(Dropzone, null, [{ + key: "initClass", + value: function initClass() { + + // Exposing the emitter class, mainly for tests + this.prototype.Emitter = Emitter; + + /* + This is a list of all available events you can register on a dropzone object. + You can register an event handler like this: + dropzone.on("dragEnter", function() { }); + */ + this.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"]; + + this.prototype.defaultOptions = { + /** + * Has to be specified on elements other than form (or when the form + * doesn't have an `action` attribute). You can also + * provide a function that will be called with `files` and + * must return the url (since `v3.12.0`) + */ + url: null, + + /** + * Can be changed to `"put"` if necessary. You can also provide a function + * that will be called with `files` and must return the method (since `v3.12.0`). + */ + method: "post", + + /** + * Will be set on the XHRequest. + */ + withCredentials: false, + + /** + * The timeout for the XHR requests in milliseconds (since `v4.4.0`). + */ + timeout: 30000, + + /** + * How many file uploads to process in parallel (See the + * Enqueuing file uploads* documentation section for more info) + */ + parallelUploads: 2, + + /** + * Whether to send multiple files in one request. If + * this it set to true, then the fallback file input element will + * have the `multiple` attribute as well. This option will + * also trigger additional events (like `processingmultiple`). See the events + * documentation section for more information. + */ + uploadMultiple: false, + + /** + * Whether you want files to be uploaded in chunks to your server. This can't be + * used in combination with `uploadMultiple`. + * + * See [chunksUploaded](#config-chunksUploaded) for the callback to finalise an upload. + */ + chunking: false, + + /** + * If `chunking` is enabled, this defines whether **every** file should be chunked, + * even if the file size is below chunkSize. This means, that the additional chunk + * form data will be submitted and the `chunksUploaded` callback will be invoked. + */ + forceChunking: false, + + /** + * If `chunking` is `true`, then this defines the chunk size in bytes. + */ + chunkSize: 2000000, + + /** + * If `true`, the individual chunks of a file are being uploaded simultaneously. + */ + parallelChunkUploads: false, + + /** + * Whether a chunk should be retried if it fails. + */ + retryChunks: false, + + /** + * If `retryChunks` is true, how many times should it be retried. + */ + retryChunksLimit: 3, + + /** + * If not `null` defines how many files this Dropzone handles. If it exceeds, + * the event `maxfilesexceeded` will be called. The dropzone element gets the + * class `dz-max-files-reached` accordingly so you can provide visual feedback. + */ + maxFilesize: 256, + + /** + * The name of the file param that gets transferred. + * **NOTE**: If you have the option `uploadMultiple` set to `true`, then + * Dropzone will append `[]` to the name. + */ + paramName: "file", + + /** + * Whether thumbnails for images should be generated + */ + createImageThumbnails: true, + + /** + * In MB. When the filename exceeds this limit, the thumbnail will not be generated. + */ + maxThumbnailFilesize: 10, + + /** + * If `null`, the ratio of the image will be used to calculate it. + */ + thumbnailWidth: 120, + + /** + * The same as `thumbnailWidth`. If both are null, images will not be resized. + */ + thumbnailHeight: 120, + + /** + * How the images should be scaled down in case both, `thumbnailWidth` and `thumbnailHeight` are provided. + * Can be either `contain` or `crop`. + */ + thumbnailMethod: 'crop', + + /** + * If set, images will be resized to these dimensions before being **uploaded**. + * If only one, `resizeWidth` **or** `resizeHeight` is provided, the original aspect + * ratio of the file will be preserved. + * + * The `options.transformFile` function uses these options, so if the `transformFile` function + * is overridden, these options don't do anything. + */ + resizeWidth: null, + + /** + * See `resizeWidth`. + */ + resizeHeight: null, + + /** + * The mime type of the resized image (before it gets uploaded to the server). + * If `null` the original mime type will be used. To force jpeg, for example, use `image/jpeg`. + * See `resizeWidth` for more information. + */ + resizeMimeType: null, + + /** + * The quality of the resized images. See `resizeWidth`. + */ + resizeQuality: 0.8, + + /** + * How the images should be scaled down in case both, `resizeWidth` and `resizeHeight` are provided. + * Can be either `contain` or `crop`. + */ + resizeMethod: 'contain', + + /** + * The base that is used to calculate the filesize. You can change this to + * 1024 if you would rather display kibibytes, mebibytes, etc... + * 1024 is technically incorrect, because `1024 bytes` are `1 kibibyte` not `1 kilobyte`. + * You can change this to `1024` if you don't care about validity. + */ + filesizeBase: 1000, + + /** + * Can be used to limit the maximum number of files that will be handled by this Dropzone + */ + maxFiles: null, + + /** + * An optional object to send additional headers to the server. Eg: + * `{ "My-Awesome-Header": "header value" }` + */ + headers: null, + + /** + * If `true`, the dropzone element itself will be clickable, if `false` + * nothing will be clickable. + * + * You can also pass an HTML element, a CSS selector (for multiple elements) + * or an array of those. In that case, all of those elements will trigger an + * upload when clicked. + */ + clickable: true, + + /** + * Whether hidden files in directories should be ignored. + */ + ignoreHiddenFiles: true, + + /** + * The default implementation of `accept` checks the file's mime type or + * extension against this list. This is a comma separated list of mime + * types or file extensions. + * + * Eg.: `image/*,application/pdf,.psd` + * + * If the Dropzone is `clickable` this option will also be used as + * [`accept`](https://developer.mozilla.org/en-US/docs/HTML/Element/input#attr-accept) + * parameter on the hidden file input as well. + */ + acceptedFiles: null, + + /** + * **Deprecated!** + * Use acceptedFiles instead. + */ + acceptedMimeTypes: null, + + /** + * If false, files will be added to the queue but the queue will not be + * processed automatically. + * This can be useful if you need some additional user input before sending + * files (or if you want want all files sent at once). + * If you're ready to send the file simply call `myDropzone.processQueue()`. + * + * See the [enqueuing file uploads](#enqueuing-file-uploads) documentation + * section for more information. + */ + autoProcessQueue: true, + + /** + * If false, files added to the dropzone will not be queued by default. + * You'll have to call `enqueueFile(file)` manually. + */ + autoQueue: true, + + /** + * If `true`, this will add a link to every file preview to remove or cancel (if + * already uploading) the file. The `dictCancelUpload`, `dictCancelUploadConfirmation` + * and `dictRemoveFile` options are used for the wording. + */ + addRemoveLinks: false, + + /** + * Defines where to display the file previews – if `null` the + * Dropzone element itself is used. Can be a plain `HTMLElement` or a CSS + * selector. The element should have the `dropzone-previews` class so + * the previews are displayed properly. + */ + previewsContainer: null, + + /** + * This is the element the hidden input field (which is used when clicking on the + * dropzone to trigger file selection) will be appended to. This might + * be important in case you use frameworks to switch the content of your page. + * + * Can be a selector string, or an element directly. + */ + hiddenInputContainer: "body", + + /** + * If null, no capture type will be specified + * If camera, mobile devices will skip the file selection and choose camera + * If microphone, mobile devices will skip the file selection and choose the microphone + * If camcorder, mobile devices will skip the file selection and choose the camera in video mode + * On apple devices multiple must be set to false. AcceptedFiles may need to + * be set to an appropriate mime type (e.g. "image/*", "audio/*", or "video/*"). + */ + capture: null, + + /** + * **Deprecated**. Use `renameFile` instead. + */ + renameFilename: null, + + /** + * A function that is invoked before the file is uploaded to the server and renames the file. + * This function gets the `File` as argument and can use the `file.name`. The actual name of the + * file that gets used during the upload can be accessed through `file.upload.filename`. + */ + renameFile: null, + + /** + * If `true` the fallback will be forced. This is very useful to test your server + * implementations first and make sure that everything works as + * expected without dropzone if you experience problems, and to test + * how your fallbacks will look. + */ + forceFallback: false, + + /** + * The text used before any files are dropped. + */ + dictDefaultMessage: "Drop files here to upload", + + /** + * The text that replaces the default message text it the browser is not supported. + */ + dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.", + + /** + * The text that will be added before the fallback form. + * If you provide a fallback element yourself, or if this option is `null` this will + * be ignored. + */ + dictFallbackText: "Please use the fallback form below to upload your files like in the olden days.", + + /** + * If the filesize is too big. + * `{{filesize}}` and `{{maxFilesize}}` will be replaced with the respective configuration values. + */ + dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.", + + /** + * If the file doesn't match the file type. + */ + dictInvalidFileType: "You can't upload files of this type.", + + /** + * If the server response was invalid. + * `{{statusCode}}` will be replaced with the servers status code. + */ + dictResponseError: "Server responded with {{statusCode}} code.", + + /** + * If `addRemoveLinks` is true, the text to be used for the cancel upload link. + */ + dictCancelUpload: "Cancel upload", + + /** + * The text that is displayed if an upload was manually canceled + */ + dictUploadCanceled: "Upload canceled.", + + /** + * If `addRemoveLinks` is true, the text to be used for confirmation when cancelling upload. + */ + dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?", + + /** + * If `addRemoveLinks` is true, the text to be used to remove a file. + */ + dictRemoveFile: "Remove file", + + /** + * If this is not null, then the user will be prompted before removing a file. + */ + dictRemoveFileConfirmation: null, + + /** + * Displayed if `maxFiles` is st and exceeded. + * The string `{{maxFiles}}` will be replaced by the configuration value. + */ + dictMaxFilesExceeded: "You can not upload any more files.", + + /** + * Allows you to translate the different units. Starting with `tb` for terabytes and going down to + * `b` for bytes. + */ + dictFileSizeUnits: { tb: "TB", gb: "GB", mb: "MB", kb: "KB", b: "b" }, + /** + * Called when dropzone initialized + * You can add event listeners here + */ + init: function init() {}, + + + /** + * Can be an **object** of additional parameters to transfer to the server, **or** a `Function` + * that gets invoked with the `files`, `xhr` and, if it's a chunked upload, `chunk` arguments. In case + * of a function, this needs to return a map. + * + * The default implementation does nothing for normal uploads, but adds relevant information for + * chunked uploads. + * + * This is the same as adding hidden input fields in the form element. + */ + params: function params(files, xhr, chunk) { + if (chunk) { + return { + dzuuid: chunk.file.upload.uuid, + dzchunkindex: chunk.index, + dztotalfilesize: chunk.file.size, + dzchunksize: this.options.chunkSize, + dztotalchunkcount: chunk.file.upload.totalChunkCount, + dzchunkbyteoffset: chunk.index * this.options.chunkSize + }; + } + }, + + + /** + * A function that gets a [file](https://developer.mozilla.org/en-US/docs/DOM/File) + * and a `done` function as parameters. + * + * If the done function is invoked without arguments, the file is "accepted" and will + * be processed. If you pass an error message, the file is rejected, and the error + * message will be displayed. + * This function will not be called if the file is too big or doesn't match the mime types. + */ + accept: function accept(file, done) { + return done(); + }, + + + /** + * The callback that will be invoked when all chunks have been uploaded for a file. + * It gets the file for which the chunks have been uploaded as the first parameter, + * and the `done` function as second. `done()` needs to be invoked when everything + * needed to finish the upload process is done. + */ + chunksUploaded: function chunksUploaded(file, done) { + done(); + }, + + /** + * Gets called when the browser is not supported. + * The default implementation shows the fallback input field and adds + * a text. + */ + fallback: function fallback() { + // This code should pass in IE7... :( + var messageElement = void 0; + this.element.className = this.element.className + " dz-browser-not-supported"; + + for (var _iterator2 = this.element.getElementsByTagName("div"), _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { + var _ref2; + + if (_isArray2) { + if (_i2 >= _iterator2.length) break; + _ref2 = _iterator2[_i2++]; + } else { + _i2 = _iterator2.next(); + if (_i2.done) break; + _ref2 = _i2.value; + } + + var child = _ref2; + + if (/(^| )dz-message($| )/.test(child.className)) { + messageElement = child; + child.className = "dz-message"; // Removes the 'dz-default' class + break; + } + } + if (!messageElement) { + messageElement = Dropzone.createElement("
"); + this.element.appendChild(messageElement); + } + + var span = messageElement.getElementsByTagName("span")[0]; + if (span) { + if (span.textContent != null) { + span.textContent = this.options.dictFallbackMessage; + } else if (span.innerText != null) { + span.innerText = this.options.dictFallbackMessage; + } + } + + return this.element.appendChild(this.getFallbackForm()); + }, + + + /** + * Gets called to calculate the thumbnail dimensions. + * + * It gets `file`, `width` and `height` (both may be `null`) as parameters and must return an object containing: + * + * - `srcWidth` & `srcHeight` (required) + * - `trgWidth` & `trgHeight` (required) + * - `srcX` & `srcY` (optional, default `0`) + * - `trgX` & `trgY` (optional, default `0`) + * + * Those values are going to be used by `ctx.drawImage()`. + */ + resize: function resize(file, width, height, resizeMethod) { + var info = { + srcX: 0, + srcY: 0, + srcWidth: file.width, + srcHeight: file.height + }; + + var srcRatio = file.width / file.height; + + // Automatically calculate dimensions if not specified + if (width == null && height == null) { + width = info.srcWidth; + height = info.srcHeight; + } else if (width == null) { + width = height * srcRatio; + } else if (height == null) { + height = width / srcRatio; + } + + // Make sure images aren't upscaled + width = Math.min(width, info.srcWidth); + height = Math.min(height, info.srcHeight); + + var trgRatio = width / height; + + if (info.srcWidth > width || info.srcHeight > height) { + // Image is bigger and needs rescaling + if (resizeMethod === 'crop') { + if (srcRatio > trgRatio) { + info.srcHeight = file.height; + info.srcWidth = info.srcHeight * trgRatio; + } else { + info.srcWidth = file.width; + info.srcHeight = info.srcWidth / trgRatio; + } + } else if (resizeMethod === 'contain') { + // Method 'contain' + if (srcRatio > trgRatio) { + height = width / srcRatio; + } else { + width = height * srcRatio; + } + } else { + throw new Error("Unknown resizeMethod '" + resizeMethod + "'"); + } + } + + info.srcX = (file.width - info.srcWidth) / 2; + info.srcY = (file.height - info.srcHeight) / 2; + + info.trgWidth = width; + info.trgHeight = height; + + return info; + }, + + + /** + * Can be used to transform the file (for example, resize an image if necessary). + * + * The default implementation uses `resizeWidth` and `resizeHeight` (if provided) and resizes + * images according to those dimensions. + * + * Gets the `file` as the first parameter, and a `done()` function as the second, that needs + * to be invoked with the file when the transformation is done. + */ + transformFile: function transformFile(file, done) { + if ((this.options.resizeWidth || this.options.resizeHeight) && file.type.match(/image.*/)) { + return this.resizeImage(file, this.options.resizeWidth, this.options.resizeHeight, this.options.resizeMethod, done); + } else { + return done(file); + } + }, + + + /** + * A string that contains the template used for each dropped + * file. Change it to fulfill your needs but make sure to properly + * provide all elements. + * + * If you want to use an actual HTML element instead of providing a String + * as a config option, you could create a div with the id `tpl`, + * put the template inside it and provide the element like this: + * + * document + * .querySelector('#tpl') + * .innerHTML + * + */ + previewTemplate: "
\n
\n
\n
\n
\n
\n
\n
\n
\n \n Check\n \n \n \n \n \n
\n
\n \n Error\n \n \n \n \n \n \n \n
\n
", + + // END OPTIONS + // (Required by the dropzone documentation parser) + + + /* + Those functions register themselves to the events on init and handle all + the user interface specific stuff. Overwriting them won't break the upload + but can break the way it's displayed. + You can overwrite them if you don't like the default behavior. If you just + want to add an additional event handler, register it on the dropzone object + and don't overwrite those options. + */ + + // Those are self explanatory and simply concern the DragnDrop. + drop: function drop(e) { + return this.element.classList.remove("dz-drag-hover"); + }, + dragstart: function dragstart(e) {}, + dragend: function dragend(e) { + return this.element.classList.remove("dz-drag-hover"); + }, + dragenter: function dragenter(e) { + return this.element.classList.add("dz-drag-hover"); + }, + dragover: function dragover(e) { + return this.element.classList.add("dz-drag-hover"); + }, + dragleave: function dragleave(e) { + return this.element.classList.remove("dz-drag-hover"); + }, + paste: function paste(e) {}, + + + // Called whenever there are no files left in the dropzone anymore, and the + // dropzone should be displayed as if in the initial state. + reset: function reset() { + return this.element.classList.remove("dz-started"); + }, + + + // Called when a file is added to the queue + // Receives `file` + addedfile: function addedfile(file) { + var _this2 = this; + + if (this.element === this.previewsContainer) { + this.element.classList.add("dz-started"); + } + + if (this.previewsContainer) { + file.previewElement = Dropzone.createElement(this.options.previewTemplate.trim()); + file.previewTemplate = file.previewElement; // Backwards compatibility + + this.previewsContainer.appendChild(file.previewElement); + for (var _iterator3 = file.previewElement.querySelectorAll("[data-dz-name]"), _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { + var _ref3; + + if (_isArray3) { + if (_i3 >= _iterator3.length) break; + _ref3 = _iterator3[_i3++]; + } else { + _i3 = _iterator3.next(); + if (_i3.done) break; + _ref3 = _i3.value; + } + + var node = _ref3; + + node.textContent = file.name; + } + for (var _iterator4 = file.previewElement.querySelectorAll("[data-dz-size]"), _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { + if (_isArray4) { + if (_i4 >= _iterator4.length) break; + node = _iterator4[_i4++]; + } else { + _i4 = _iterator4.next(); + if (_i4.done) break; + node = _i4.value; + } + + node.innerHTML = this.filesize(file.size); + } + + if (this.options.addRemoveLinks) { + file._removeLink = Dropzone.createElement("" + this.options.dictRemoveFile + ""); + file.previewElement.appendChild(file._removeLink); + } + + var removeFileEvent = function removeFileEvent(e) { + e.preventDefault(); + e.stopPropagation(); + if (file.status === Dropzone.UPLOADING) { + return Dropzone.confirm(_this2.options.dictCancelUploadConfirmation, function () { + return _this2.removeFile(file); + }); + } else { + if (_this2.options.dictRemoveFileConfirmation) { + return Dropzone.confirm(_this2.options.dictRemoveFileConfirmation, function () { + return _this2.removeFile(file); + }); + } else { + return _this2.removeFile(file); + } + } + }; + + for (var _iterator5 = file.previewElement.querySelectorAll("[data-dz-remove]"), _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { + var _ref4; + + if (_isArray5) { + if (_i5 >= _iterator5.length) break; + _ref4 = _iterator5[_i5++]; + } else { + _i5 = _iterator5.next(); + if (_i5.done) break; + _ref4 = _i5.value; + } + + var removeLink = _ref4; + + removeLink.addEventListener("click", removeFileEvent); + } + } + }, + + + // Called whenever a file is removed. + removedfile: function removedfile(file) { + if (file.previewElement != null && file.previewElement.parentNode != null) { + file.previewElement.parentNode.removeChild(file.previewElement); + } + return this._updateMaxFilesReachedClass(); + }, + + + // Called when a thumbnail has been generated + // Receives `file` and `dataUrl` + thumbnail: function thumbnail(file, dataUrl) { + if (file.previewElement) { + file.previewElement.classList.remove("dz-file-preview"); + for (var _iterator6 = file.previewElement.querySelectorAll("[data-dz-thumbnail]"), _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { + var _ref5; + + if (_isArray6) { + if (_i6 >= _iterator6.length) break; + _ref5 = _iterator6[_i6++]; + } else { + _i6 = _iterator6.next(); + if (_i6.done) break; + _ref5 = _i6.value; + } + + var thumbnailElement = _ref5; + + thumbnailElement.alt = file.name; + thumbnailElement.src = dataUrl; + } + + return setTimeout(function () { + return file.previewElement.classList.add("dz-image-preview"); + }, 1); + } + }, + + + // Called whenever an error occurs + // Receives `file` and `message` + error: function error(file, message) { + if (file.previewElement) { + file.previewElement.classList.add("dz-error"); + if (typeof message !== "String" && message.error) { + message = message.error; + } + for (var _iterator7 = file.previewElement.querySelectorAll("[data-dz-errormessage]"), _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { + var _ref6; + + if (_isArray7) { + if (_i7 >= _iterator7.length) break; + _ref6 = _iterator7[_i7++]; + } else { + _i7 = _iterator7.next(); + if (_i7.done) break; + _ref6 = _i7.value; + } + + var node = _ref6; + + node.textContent = message; + } + } + }, + errormultiple: function errormultiple() {}, + + + // Called when a file gets processed. Since there is a cue, not all added + // files are processed immediately. + // Receives `file` + processing: function processing(file) { + if (file.previewElement) { + file.previewElement.classList.add("dz-processing"); + if (file._removeLink) { + return file._removeLink.innerHTML = this.options.dictCancelUpload; + } + } + }, + processingmultiple: function processingmultiple() {}, + + + // Called whenever the upload progress gets updated. + // Receives `file`, `progress` (percentage 0-100) and `bytesSent`. + // To get the total number of bytes of the file, use `file.size` + uploadprogress: function uploadprogress(file, progress, bytesSent) { + if (file.previewElement) { + for (var _iterator8 = file.previewElement.querySelectorAll("[data-dz-uploadprogress]"), _isArray8 = Array.isArray(_iterator8), _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { + var _ref7; + + if (_isArray8) { + if (_i8 >= _iterator8.length) break; + _ref7 = _iterator8[_i8++]; + } else { + _i8 = _iterator8.next(); + if (_i8.done) break; + _ref7 = _i8.value; + } + + var node = _ref7; + + node.nodeName === 'PROGRESS' ? node.value = progress : node.style.width = progress + "%"; + } + } + }, + + + // Called whenever the total upload progress gets updated. + // Called with totalUploadProgress (0-100), totalBytes and totalBytesSent + totaluploadprogress: function totaluploadprogress() {}, + + + // Called just before the file is sent. Gets the `xhr` object as second + // parameter, so you can modify it (for example to add a CSRF token) and a + // `formData` object to add additional information. + sending: function sending() {}, + sendingmultiple: function sendingmultiple() {}, + + + // When the complete upload is finished and successful + // Receives `file` + success: function success(file) { + if (file.previewElement) { + return file.previewElement.classList.add("dz-success"); + } + }, + successmultiple: function successmultiple() {}, + + + // When the upload is canceled. + canceled: function canceled(file) { + return this.emit("error", file, this.options.dictUploadCanceled); + }, + canceledmultiple: function canceledmultiple() {}, + + + // When the upload is finished, either with success or an error. + // Receives `file` + complete: function complete(file) { + if (file._removeLink) { + file._removeLink.innerHTML = this.options.dictRemoveFile; + } + if (file.previewElement) { + return file.previewElement.classList.add("dz-complete"); + } + }, + completemultiple: function completemultiple() {}, + maxfilesexceeded: function maxfilesexceeded() {}, + maxfilesreached: function maxfilesreached() {}, + queuecomplete: function queuecomplete() {}, + addedfiles: function addedfiles() {} + }; + + this.prototype._thumbnailQueue = []; + this.prototype._processingThumbnail = false; + } + + // global utility + + }, { + key: "extend", + value: function extend(target) { + for (var _len2 = arguments.length, objects = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + objects[_key2 - 1] = arguments[_key2]; + } + + for (var _iterator9 = objects, _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { + var _ref8; + + if (_isArray9) { + if (_i9 >= _iterator9.length) break; + _ref8 = _iterator9[_i9++]; + } else { + _i9 = _iterator9.next(); + if (_i9.done) break; + _ref8 = _i9.value; + } + + var object = _ref8; + + for (var key in object) { + var val = object[key]; + target[key] = val; + } + } + return target; + } + }]); + + function Dropzone(el, options) { + _classCallCheck(this, Dropzone); + + var _this = _possibleConstructorReturn(this, (Dropzone.__proto__ || Object.getPrototypeOf(Dropzone)).call(this)); + + var fallback = void 0, + left = void 0; + _this.element = el; + // For backwards compatibility since the version was in the prototype previously + _this.version = Dropzone.version; + + _this.defaultOptions.previewTemplate = _this.defaultOptions.previewTemplate.replace(/\n*/g, ""); + + _this.clickableElements = []; + _this.listeners = []; + _this.files = []; // All files + + if (typeof _this.element === "string") { + _this.element = document.querySelector(_this.element); + } + + // Not checking if instance of HTMLElement or Element since IE9 is extremely weird. + if (!_this.element || _this.element.nodeType == null) { + throw new Error("Invalid dropzone element."); + } + + if (_this.element.dropzone) { + throw new Error("Dropzone already attached."); + } + + // Now add this dropzone to the instances. + Dropzone.instances.push(_this); + + // Put the dropzone inside the element itself. + _this.element.dropzone = _this; + + var elementOptions = (left = Dropzone.optionsForElement(_this.element)) != null ? left : {}; + + _this.options = Dropzone.extend({}, _this.defaultOptions, elementOptions, options != null ? options : {}); + + // If the browser failed, just call the fallback and leave + if (_this.options.forceFallback || !Dropzone.isBrowserSupported()) { + var _ret; + + return _ret = _this.options.fallback.call(_this), _possibleConstructorReturn(_this, _ret); + } + + // @options.url = @element.getAttribute "action" unless @options.url? + if (_this.options.url == null) { + _this.options.url = _this.element.getAttribute("action"); + } + + if (!_this.options.url) { + throw new Error("No URL provided."); + } + + if (_this.options.acceptedFiles && _this.options.acceptedMimeTypes) { + throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated."); + } + + if (_this.options.uploadMultiple && _this.options.chunking) { + throw new Error('You cannot set both: uploadMultiple and chunking.'); + } + + // Backwards compatibility + if (_this.options.acceptedMimeTypes) { + _this.options.acceptedFiles = _this.options.acceptedMimeTypes; + delete _this.options.acceptedMimeTypes; + } + + // Backwards compatibility + if (_this.options.renameFilename != null) { + _this.options.renameFile = function (file) { + return _this.options.renameFilename.call(_this, file.name, file); + }; + } + + _this.options.method = _this.options.method.toUpperCase(); + + if ((fallback = _this.getExistingFallback()) && fallback.parentNode) { + // Remove the fallback + fallback.parentNode.removeChild(fallback); + } + + // Display previews in the previewsContainer element or the Dropzone element unless explicitly set to false + if (_this.options.previewsContainer !== false) { + if (_this.options.previewsContainer) { + _this.previewsContainer = Dropzone.getElement(_this.options.previewsContainer, "previewsContainer"); + } else { + _this.previewsContainer = _this.element; + } + } + + if (_this.options.clickable) { + if (_this.options.clickable === true) { + _this.clickableElements = [_this.element]; + } else { + _this.clickableElements = Dropzone.getElements(_this.options.clickable, "clickable"); + } + } + + _this.init(); + return _this; + } + + // Returns all files that have been accepted + + + _createClass(Dropzone, [{ + key: "getAcceptedFiles", + value: function getAcceptedFiles() { + return this.files.filter(function (file) { + return file.accepted; + }).map(function (file) { + return file; + }); + } + + // Returns all files that have been rejected + // Not sure when that's going to be useful, but added for completeness. + + }, { + key: "getRejectedFiles", + value: function getRejectedFiles() { + return this.files.filter(function (file) { + return !file.accepted; + }).map(function (file) { + return file; + }); + } + }, { + key: "getFilesWithStatus", + value: function getFilesWithStatus(status) { + return this.files.filter(function (file) { + return file.status === status; + }).map(function (file) { + return file; + }); + } + + // Returns all files that are in the queue + + }, { + key: "getQueuedFiles", + value: function getQueuedFiles() { + return this.getFilesWithStatus(Dropzone.QUEUED); + } + }, { + key: "getUploadingFiles", + value: function getUploadingFiles() { + return this.getFilesWithStatus(Dropzone.UPLOADING); + } + }, { + key: "getAddedFiles", + value: function getAddedFiles() { + return this.getFilesWithStatus(Dropzone.ADDED); + } + + // Files that are either queued or uploading + + }, { + key: "getActiveFiles", + value: function getActiveFiles() { + return this.files.filter(function (file) { + return file.status === Dropzone.UPLOADING || file.status === Dropzone.QUEUED; + }).map(function (file) { + return file; + }); + } + + // The function that gets called when Dropzone is initialized. You + // can (and should) setup event listeners inside this function. + + }, { + key: "init", + value: function init() { + var _this3 = this; + + // In case it isn't set already + if (this.element.tagName === "form") { + this.element.setAttribute("enctype", "multipart/form-data"); + } + + if (this.element.classList.contains("dropzone") && !this.element.querySelector(".dz-message")) { + this.element.appendChild(Dropzone.createElement("
" + this.options.dictDefaultMessage + "
")); + } + + if (this.clickableElements.length) { + var setupHiddenFileInput = function setupHiddenFileInput() { + if (_this3.hiddenFileInput) { + _this3.hiddenFileInput.parentNode.removeChild(_this3.hiddenFileInput); + } + _this3.hiddenFileInput = document.createElement("input"); + _this3.hiddenFileInput.setAttribute("type", "file"); + if (_this3.options.maxFiles === null || _this3.options.maxFiles > 1) { + _this3.hiddenFileInput.setAttribute("multiple", "multiple"); + } + _this3.hiddenFileInput.className = "dz-hidden-input"; + + if (_this3.options.acceptedFiles !== null) { + _this3.hiddenFileInput.setAttribute("accept", _this3.options.acceptedFiles); + } + if (_this3.options.capture !== null) { + _this3.hiddenFileInput.setAttribute("capture", _this3.options.capture); + } + + // Not setting `display="none"` because some browsers don't accept clicks + // on elements that aren't displayed. + _this3.hiddenFileInput.style.visibility = "hidden"; + _this3.hiddenFileInput.style.position = "absolute"; + _this3.hiddenFileInput.style.top = "0"; + _this3.hiddenFileInput.style.left = "0"; + _this3.hiddenFileInput.style.height = "0"; + _this3.hiddenFileInput.style.width = "0"; + Dropzone.getElement(_this3.options.hiddenInputContainer, 'hiddenInputContainer').appendChild(_this3.hiddenFileInput); + return _this3.hiddenFileInput.addEventListener("change", function () { + var files = _this3.hiddenFileInput.files; + + if (files.length) { + for (var _iterator10 = files, _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) { + var _ref9; + + if (_isArray10) { + if (_i10 >= _iterator10.length) break; + _ref9 = _iterator10[_i10++]; + } else { + _i10 = _iterator10.next(); + if (_i10.done) break; + _ref9 = _i10.value; + } + + var file = _ref9; + + _this3.addFile(file); + } + } + _this3.emit("addedfiles", files); + return setupHiddenFileInput(); + }); + }; + setupHiddenFileInput(); + } + + this.URL = window.URL !== null ? window.URL : window.webkitURL; + + // Setup all event listeners on the Dropzone object itself. + // They're not in @setupEventListeners() because they shouldn't be removed + // again when the dropzone gets disabled. + for (var _iterator11 = this.events, _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) { + var _ref10; + + if (_isArray11) { + if (_i11 >= _iterator11.length) break; + _ref10 = _iterator11[_i11++]; + } else { + _i11 = _iterator11.next(); + if (_i11.done) break; + _ref10 = _i11.value; + } + + var eventName = _ref10; + + this.on(eventName, this.options[eventName]); + } + + this.on("uploadprogress", function () { + return _this3.updateTotalUploadProgress(); + }); + + this.on("removedfile", function () { + return _this3.updateTotalUploadProgress(); + }); + + this.on("canceled", function (file) { + return _this3.emit("complete", file); + }); + + // Emit a `queuecomplete` event if all files finished uploading. + this.on("complete", function (file) { + if (_this3.getAddedFiles().length === 0 && _this3.getUploadingFiles().length === 0 && _this3.getQueuedFiles().length === 0) { + // This needs to be deferred so that `queuecomplete` really triggers after `complete` + return setTimeout(function () { + return _this3.emit("queuecomplete"); + }, 0); + } + }); + + var noPropagation = function noPropagation(e) { + e.stopPropagation(); + if (e.preventDefault) { + return e.preventDefault(); + } else { + return e.returnValue = false; + } + }; + + // Create the listeners + this.listeners = [{ + element: this.element, + events: { + "dragstart": function dragstart(e) { + return _this3.emit("dragstart", e); + }, + "dragenter": function dragenter(e) { + noPropagation(e); + return _this3.emit("dragenter", e); + }, + "dragover": function dragover(e) { + // Makes it possible to drag files from chrome's download bar + // http://stackoverflow.com/questions/19526430/drag-and-drop-file-uploads-from-chrome-downloads-bar + // Try is required to prevent bug in Internet Explorer 11 (SCRIPT65535 exception) + var efct = void 0; + try { + efct = e.dataTransfer.effectAllowed; + } catch (error) {} + e.dataTransfer.dropEffect = 'move' === efct || 'linkMove' === efct ? 'move' : 'copy'; + + noPropagation(e); + return _this3.emit("dragover", e); + }, + "dragleave": function dragleave(e) { + return _this3.emit("dragleave", e); + }, + "drop": function drop(e) { + noPropagation(e); + return _this3.drop(e); + }, + "dragend": function dragend(e) { + return _this3.emit("dragend", e); + } + + // This is disabled right now, because the browsers don't implement it properly. + // "paste": (e) => + // noPropagation e + // @paste e + } }]; + + this.clickableElements.forEach(function (clickableElement) { + return _this3.listeners.push({ + element: clickableElement, + events: { + "click": function click(evt) { + // Only the actual dropzone or the message element should trigger file selection + if (clickableElement !== _this3.element || evt.target === _this3.element || Dropzone.elementInside(evt.target, _this3.element.querySelector(".dz-message"))) { + _this3.hiddenFileInput.click(); // Forward the click + } + return true; + } + } + }); + }); + + this.enable(); + + return this.options.init.call(this); + } + + // Not fully tested yet + + }, { + key: "destroy", + value: function destroy() { + this.disable(); + this.removeAllFiles(true); + if (this.hiddenFileInput != null ? this.hiddenFileInput.parentNode : undefined) { + this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput); + this.hiddenFileInput = null; + } + delete this.element.dropzone; + return Dropzone.instances.splice(Dropzone.instances.indexOf(this), 1); + } + }, { + key: "updateTotalUploadProgress", + value: function updateTotalUploadProgress() { + var totalUploadProgress = void 0; + var totalBytesSent = 0; + var totalBytes = 0; + + var activeFiles = this.getActiveFiles(); + + if (activeFiles.length) { + for (var _iterator12 = this.getActiveFiles(), _isArray12 = Array.isArray(_iterator12), _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) { + var _ref11; + + if (_isArray12) { + if (_i12 >= _iterator12.length) break; + _ref11 = _iterator12[_i12++]; + } else { + _i12 = _iterator12.next(); + if (_i12.done) break; + _ref11 = _i12.value; + } + + var file = _ref11; + + totalBytesSent += file.upload.bytesSent; + totalBytes += file.upload.total; + } + totalUploadProgress = 100 * totalBytesSent / totalBytes; + } else { + totalUploadProgress = 100; + } + + return this.emit("totaluploadprogress", totalUploadProgress, totalBytes, totalBytesSent); + } + + // @options.paramName can be a function taking one parameter rather than a string. + // A parameter name for a file is obtained simply by calling this with an index number. + + }, { + key: "_getParamName", + value: function _getParamName(n) { + if (typeof this.options.paramName === "function") { + return this.options.paramName(n); + } else { + return "" + this.options.paramName + (this.options.uploadMultiple ? "[" + n + "]" : ""); + } + } + + // If @options.renameFile is a function, + // the function will be used to rename the file.name before appending it to the formData + + }, { + key: "_renameFile", + value: function _renameFile(file) { + if (typeof this.options.renameFile !== "function") { + return file.name; + } + return this.options.renameFile(file); + } + + // Returns a form that can be used as fallback if the browser does not support DragnDrop + // + // If the dropzone is already a form, only the input field and button are returned. Otherwise a complete form element is provided. + // This code has to pass in IE7 :( + + }, { + key: "getFallbackForm", + value: function getFallbackForm() { + var existingFallback = void 0, + form = void 0; + if (existingFallback = this.getExistingFallback()) { + return existingFallback; + } + + var fieldsString = "
"; + if (this.options.dictFallbackText) { + fieldsString += "

" + this.options.dictFallbackText + "

"; + } + fieldsString += "
"; + + var fields = Dropzone.createElement(fieldsString); + if (this.element.tagName !== "FORM") { + form = Dropzone.createElement("
"); + form.appendChild(fields); + } else { + // Make sure that the enctype and method attributes are set properly + this.element.setAttribute("enctype", "multipart/form-data"); + this.element.setAttribute("method", this.options.method); + } + return form != null ? form : fields; + } + + // Returns the fallback elements if they exist already + // + // This code has to pass in IE7 :( + + }, { + key: "getExistingFallback", + value: function getExistingFallback() { + var getFallback = function getFallback(elements) { + for (var _iterator13 = elements, _isArray13 = Array.isArray(_iterator13), _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();;) { + var _ref12; + + if (_isArray13) { + if (_i13 >= _iterator13.length) break; + _ref12 = _iterator13[_i13++]; + } else { + _i13 = _iterator13.next(); + if (_i13.done) break; + _ref12 = _i13.value; + } + + var el = _ref12; + + if (/(^| )fallback($| )/.test(el.className)) { + return el; + } + } + }; + + var _arr = ["div", "form"]; + for (var _i14 = 0; _i14 < _arr.length; _i14++) { + var tagName = _arr[_i14]; + var fallback; + if (fallback = getFallback(this.element.getElementsByTagName(tagName))) { + return fallback; + } + } + } + + // Activates all listeners stored in @listeners + + }, { + key: "setupEventListeners", + value: function setupEventListeners() { + return this.listeners.map(function (elementListeners) { + return function () { + var result = []; + for (var event in elementListeners.events) { + var listener = elementListeners.events[event]; + result.push(elementListeners.element.addEventListener(event, listener, false)); + } + return result; + }(); + }); + } + + // Deactivates all listeners stored in @listeners + + }, { + key: "removeEventListeners", + value: function removeEventListeners() { + return this.listeners.map(function (elementListeners) { + return function () { + var result = []; + for (var event in elementListeners.events) { + var listener = elementListeners.events[event]; + result.push(elementListeners.element.removeEventListener(event, listener, false)); + } + return result; + }(); + }); + } + + // Removes all event listeners and cancels all files in the queue or being processed. + + }, { + key: "disable", + value: function disable() { + var _this4 = this; + + this.clickableElements.forEach(function (element) { + return element.classList.remove("dz-clickable"); + }); + this.removeEventListeners(); + this.disabled = true; + + return this.files.map(function (file) { + return _this4.cancelUpload(file); + }); + } + }, { + key: "enable", + value: function enable() { + delete this.disabled; + this.clickableElements.forEach(function (element) { + return element.classList.add("dz-clickable"); + }); + return this.setupEventListeners(); + } + + // Returns a nicely formatted filesize + + }, { + key: "filesize", + value: function filesize(size) { + var selectedSize = 0; + var selectedUnit = "b"; + + if (size > 0) { + var units = ['tb', 'gb', 'mb', 'kb', 'b']; + + for (var i = 0; i < units.length; i++) { + var unit = units[i]; + var cutoff = Math.pow(this.options.filesizeBase, 4 - i) / 10; + + if (size >= cutoff) { + selectedSize = size / Math.pow(this.options.filesizeBase, 4 - i); + selectedUnit = unit; + break; + } + } + + selectedSize = Math.round(10 * selectedSize) / 10; // Cutting of digits + } + + return "" + selectedSize + " " + this.options.dictFileSizeUnits[selectedUnit]; + } + + // Adds or removes the `dz-max-files-reached` class from the form. + + }, { + key: "_updateMaxFilesReachedClass", + value: function _updateMaxFilesReachedClass() { + if (this.options.maxFiles != null && this.getAcceptedFiles().length >= this.options.maxFiles) { + if (this.getAcceptedFiles().length === this.options.maxFiles) { + this.emit('maxfilesreached', this.files); + } + return this.element.classList.add("dz-max-files-reached"); + } else { + return this.element.classList.remove("dz-max-files-reached"); + } + } + }, { + key: "drop", + value: function drop(e) { + if (!e.dataTransfer) { + return; + } + this.emit("drop", e); + + // Convert the FileList to an Array + // This is necessary for IE11 + var files = []; + for (var i = 0; i < e.dataTransfer.files.length; i++) { + files[i] = e.dataTransfer.files[i]; + } + + this.emit("addedfiles", files); + + // Even if it's a folder, files.length will contain the folders. + if (files.length) { + var items = e.dataTransfer.items; + + if (items && items.length && items[0].webkitGetAsEntry != null) { + // The browser supports dropping of folders, so handle items instead of files + this._addFilesFromItems(items); + } else { + this.handleFiles(files); + } + } + } + }, { + key: "paste", + value: function paste(e) { + if (__guard__(e != null ? e.clipboardData : undefined, function (x) { + return x.items; + }) == null) { + return; + } + + this.emit("paste", e); + var items = e.clipboardData.items; + + + if (items.length) { + return this._addFilesFromItems(items); + } + } + }, { + key: "handleFiles", + value: function handleFiles(files) { + for (var _iterator14 = files, _isArray14 = Array.isArray(_iterator14), _i15 = 0, _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();;) { + var _ref13; + + if (_isArray14) { + if (_i15 >= _iterator14.length) break; + _ref13 = _iterator14[_i15++]; + } else { + _i15 = _iterator14.next(); + if (_i15.done) break; + _ref13 = _i15.value; + } + + var file = _ref13; + + this.addFile(file); + } + } + + // When a folder is dropped (or files are pasted), items must be handled + // instead of files. + + }, { + key: "_addFilesFromItems", + value: function _addFilesFromItems(items) { + var _this5 = this; + + return function () { + var result = []; + for (var _iterator15 = items, _isArray15 = Array.isArray(_iterator15), _i16 = 0, _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();;) { + var _ref14; + + if (_isArray15) { + if (_i16 >= _iterator15.length) break; + _ref14 = _iterator15[_i16++]; + } else { + _i16 = _iterator15.next(); + if (_i16.done) break; + _ref14 = _i16.value; + } + + var item = _ref14; + + var entry; + if (item.webkitGetAsEntry != null && (entry = item.webkitGetAsEntry())) { + if (entry.isFile) { + result.push(_this5.addFile(item.getAsFile())); + } else if (entry.isDirectory) { + // Append all files from that directory to files + result.push(_this5._addFilesFromDirectory(entry, entry.name)); + } else { + result.push(undefined); + } + } else if (item.getAsFile != null) { + if (item.kind == null || item.kind === "file") { + result.push(_this5.addFile(item.getAsFile())); + } else { + result.push(undefined); + } + } else { + result.push(undefined); + } + } + return result; + }(); + } + + // Goes through the directory, and adds each file it finds recursively + + }, { + key: "_addFilesFromDirectory", + value: function _addFilesFromDirectory(directory, path) { + var _this6 = this; + + var dirReader = directory.createReader(); + + var errorHandler = function errorHandler(error) { + return __guardMethod__(console, 'log', function (o) { + return o.log(error); + }); + }; + + var readEntries = function readEntries() { + return dirReader.readEntries(function (entries) { + if (entries.length > 0) { + for (var _iterator16 = entries, _isArray16 = Array.isArray(_iterator16), _i17 = 0, _iterator16 = _isArray16 ? _iterator16 : _iterator16[Symbol.iterator]();;) { + var _ref15; + + if (_isArray16) { + if (_i17 >= _iterator16.length) break; + _ref15 = _iterator16[_i17++]; + } else { + _i17 = _iterator16.next(); + if (_i17.done) break; + _ref15 = _i17.value; + } + + var entry = _ref15; + + if (entry.isFile) { + entry.file(function (file) { + if (_this6.options.ignoreHiddenFiles && file.name.substring(0, 1) === '.') { + return; + } + file.fullPath = path + "/" + file.name; + return _this6.addFile(file); + }); + } else if (entry.isDirectory) { + _this6._addFilesFromDirectory(entry, path + "/" + entry.name); + } + } + + // Recursively call readEntries() again, since browser only handle + // the first 100 entries. + // See: https://developer.mozilla.org/en-US/docs/Web/API/DirectoryReader#readEntries + readEntries(); + } + return null; + }, errorHandler); + }; + + return readEntries(); + } + + // If `done()` is called without argument the file is accepted + // If you call it with an error message, the file is rejected + // (This allows for asynchronous validation) + // + // This function checks the filesize, and if the file.type passes the + // `acceptedFiles` check. + + }, { + key: "accept", + value: function accept(file, done) { + if (this.options.maxFilesize && file.size > this.options.maxFilesize * 1024 * 1024) { + return done(this.options.dictFileTooBig.replace("{{filesize}}", Math.round(file.size / 1024 / 10.24) / 100).replace("{{maxFilesize}}", this.options.maxFilesize)); + } else if (!Dropzone.isValidFile(file, this.options.acceptedFiles)) { + return done(this.options.dictInvalidFileType); + } else if (this.options.maxFiles != null && this.getAcceptedFiles().length >= this.options.maxFiles) { + done(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}", this.options.maxFiles)); + return this.emit("maxfilesexceeded", file); + } else { + return this.options.accept.call(this, file, done); + } + } + }, { + key: "addFile", + value: function addFile(file) { + var _this7 = this; + + file.upload = { + uuid: Dropzone.uuidv4(), + progress: 0, + // Setting the total upload size to file.size for the beginning + // It's actual different than the size to be transmitted. + total: file.size, + bytesSent: 0, + filename: this._renameFile(file), + chunked: this.options.chunking && (this.options.forceChunking || file.size > this.options.chunkSize), + totalChunkCount: Math.ceil(file.size / this.options.chunkSize) + }; + this.files.push(file); + + file.status = Dropzone.ADDED; + + this.emit("addedfile", file); + + this._enqueueThumbnail(file); + + return this.accept(file, function (error) { + if (error) { + file.accepted = false; + _this7._errorProcessing([file], error); // Will set the file.status + } else { + file.accepted = true; + if (_this7.options.autoQueue) { + _this7.enqueueFile(file); + } // Will set .accepted = true + } + return _this7._updateMaxFilesReachedClass(); + }); + } + + // Wrapper for enqueueFile + + }, { + key: "enqueueFiles", + value: function enqueueFiles(files) { + for (var _iterator17 = files, _isArray17 = Array.isArray(_iterator17), _i18 = 0, _iterator17 = _isArray17 ? _iterator17 : _iterator17[Symbol.iterator]();;) { + var _ref16; + + if (_isArray17) { + if (_i18 >= _iterator17.length) break; + _ref16 = _iterator17[_i18++]; + } else { + _i18 = _iterator17.next(); + if (_i18.done) break; + _ref16 = _i18.value; + } + + var file = _ref16; + + this.enqueueFile(file); + } + return null; + } + }, { + key: "enqueueFile", + value: function enqueueFile(file) { + var _this8 = this; + + if (file.status === Dropzone.ADDED && file.accepted === true) { + file.status = Dropzone.QUEUED; + if (this.options.autoProcessQueue) { + return setTimeout(function () { + return _this8.processQueue(); + }, 0); // Deferring the call + } + } else { + throw new Error("This file can't be queued because it has already been processed or was rejected."); + } + } + }, { + key: "_enqueueThumbnail", + value: function _enqueueThumbnail(file) { + var _this9 = this; + + if (this.options.createImageThumbnails && file.type.match(/image.*/) && file.size <= this.options.maxThumbnailFilesize * 1024 * 1024) { + this._thumbnailQueue.push(file); + return setTimeout(function () { + return _this9._processThumbnailQueue(); + }, 0); // Deferring the call + } + } + }, { + key: "_processThumbnailQueue", + value: function _processThumbnailQueue() { + var _this10 = this; + + if (this._processingThumbnail || this._thumbnailQueue.length === 0) { + return; + } + + this._processingThumbnail = true; + var file = this._thumbnailQueue.shift(); + return this.createThumbnail(file, this.options.thumbnailWidth, this.options.thumbnailHeight, this.options.thumbnailMethod, true, function (dataUrl) { + _this10.emit("thumbnail", file, dataUrl); + _this10._processingThumbnail = false; + return _this10._processThumbnailQueue(); + }); + } + + // Can be called by the user to remove a file + + }, { + key: "removeFile", + value: function removeFile(file) { + if (file.status === Dropzone.UPLOADING) { + this.cancelUpload(file); + } + this.files = without(this.files, file); + + this.emit("removedfile", file); + if (this.files.length === 0) { + return this.emit("reset"); + } + } + + // Removes all files that aren't currently processed from the list + + }, { + key: "removeAllFiles", + value: function removeAllFiles(cancelIfNecessary) { + // Create a copy of files since removeFile() changes the @files array. + if (cancelIfNecessary == null) { + cancelIfNecessary = false; + } + for (var _iterator18 = this.files.slice(), _isArray18 = Array.isArray(_iterator18), _i19 = 0, _iterator18 = _isArray18 ? _iterator18 : _iterator18[Symbol.iterator]();;) { + var _ref17; + + if (_isArray18) { + if (_i19 >= _iterator18.length) break; + _ref17 = _iterator18[_i19++]; + } else { + _i19 = _iterator18.next(); + if (_i19.done) break; + _ref17 = _i19.value; + } + + var file = _ref17; + + if (file.status !== Dropzone.UPLOADING || cancelIfNecessary) { + this.removeFile(file); + } + } + return null; + } + + // Resizes an image before it gets sent to the server. This function is the default behavior of + // `options.transformFile` if `resizeWidth` or `resizeHeight` are set. The callback is invoked with + // the resized blob. + + }, { + key: "resizeImage", + value: function resizeImage(file, width, height, resizeMethod, callback) { + var _this11 = this; + + return this.createThumbnail(file, width, height, resizeMethod, true, function (dataUrl, canvas) { + if (canvas == null) { + // The image has not been resized + return callback(file); + } else { + var resizeMimeType = _this11.options.resizeMimeType; + + if (resizeMimeType == null) { + resizeMimeType = file.type; + } + var resizedDataURL = canvas.toDataURL(resizeMimeType, _this11.options.resizeQuality); + if (resizeMimeType === 'image/jpeg' || resizeMimeType === 'image/jpg') { + // Now add the original EXIF information + resizedDataURL = ExifRestore.restore(file.dataURL, resizedDataURL); + } + return callback(Dropzone.dataURItoBlob(resizedDataURL)); + } + }); + } + }, { + key: "createThumbnail", + value: function createThumbnail(file, width, height, resizeMethod, fixOrientation, callback) { + var _this12 = this; + + var fileReader = new FileReader(); + + fileReader.onload = function () { + + file.dataURL = fileReader.result; + + // Don't bother creating a thumbnail for SVG images since they're vector + if (file.type === "image/svg+xml") { + if (callback != null) { + callback(fileReader.result); + } + return; + } + + return _this12.createThumbnailFromUrl(file, width, height, resizeMethod, fixOrientation, callback); + }; + + return fileReader.readAsDataURL(file); + } + }, { + key: "createThumbnailFromUrl", + value: function createThumbnailFromUrl(file, width, height, resizeMethod, fixOrientation, callback, crossOrigin) { + var _this13 = this; + + // Not using `new Image` here because of a bug in latest Chrome versions. + // See https://github.com/enyo/dropzone/pull/226 + var img = document.createElement("img"); + + if (crossOrigin) { + img.crossOrigin = crossOrigin; + } + + img.onload = function () { + var loadExif = function loadExif(callback) { + return callback(1); + }; + if (typeof EXIF !== 'undefined' && EXIF !== null && fixOrientation) { + loadExif = function loadExif(callback) { + return EXIF.getData(img, function () { + return callback(EXIF.getTag(this, 'Orientation')); + }); + }; + } + + return loadExif(function (orientation) { + file.width = img.width; + file.height = img.height; + + var resizeInfo = _this13.options.resize.call(_this13, file, width, height, resizeMethod); + + var canvas = document.createElement("canvas"); + var ctx = canvas.getContext("2d"); + + canvas.width = resizeInfo.trgWidth; + canvas.height = resizeInfo.trgHeight; + + if (orientation > 4) { + canvas.width = resizeInfo.trgHeight; + canvas.height = resizeInfo.trgWidth; + } + + switch (orientation) { + case 2: + // horizontal flip + ctx.translate(canvas.width, 0); + ctx.scale(-1, 1); + break; + case 3: + // 180° rotate left + ctx.translate(canvas.width, canvas.height); + ctx.rotate(Math.PI); + break; + case 4: + // vertical flip + ctx.translate(0, canvas.height); + ctx.scale(1, -1); + break; + case 5: + // vertical flip + 90 rotate right + ctx.rotate(0.5 * Math.PI); + ctx.scale(1, -1); + break; + case 6: + // 90° rotate right + ctx.rotate(0.5 * Math.PI); + ctx.translate(0, -canvas.width); + break; + case 7: + // horizontal flip + 90 rotate right + ctx.rotate(0.5 * Math.PI); + ctx.translate(canvas.height, -canvas.width); + ctx.scale(-1, 1); + break; + case 8: + // 90° rotate left + ctx.rotate(-0.5 * Math.PI); + ctx.translate(-canvas.height, 0); + break; + } + + // This is a bugfix for iOS' scaling bug. + drawImageIOSFix(ctx, img, resizeInfo.srcX != null ? resizeInfo.srcX : 0, resizeInfo.srcY != null ? resizeInfo.srcY : 0, resizeInfo.srcWidth, resizeInfo.srcHeight, resizeInfo.trgX != null ? resizeInfo.trgX : 0, resizeInfo.trgY != null ? resizeInfo.trgY : 0, resizeInfo.trgWidth, resizeInfo.trgHeight); + + var thumbnail = canvas.toDataURL("image/png"); + + if (callback != null) { + return callback(thumbnail, canvas); + } + }); + }; + + if (callback != null) { + img.onerror = callback; + } + + return img.src = file.dataURL; + } + + // Goes through the queue and processes files if there aren't too many already. + + }, { + key: "processQueue", + value: function processQueue() { + var parallelUploads = this.options.parallelUploads; + + var processingLength = this.getUploadingFiles().length; + var i = processingLength; + + // There are already at least as many files uploading than should be + if (processingLength >= parallelUploads) { + return; + } + + var queuedFiles = this.getQueuedFiles(); + + if (!(queuedFiles.length > 0)) { + return; + } + + if (this.options.uploadMultiple) { + // The files should be uploaded in one request + return this.processFiles(queuedFiles.slice(0, parallelUploads - processingLength)); + } else { + while (i < parallelUploads) { + if (!queuedFiles.length) { + return; + } // Nothing left to process + this.processFile(queuedFiles.shift()); + i++; + } + } + } + + // Wrapper for `processFiles` + + }, { + key: "processFile", + value: function processFile(file) { + return this.processFiles([file]); + } + + // Loads the file, then calls finishedLoading() + + }, { + key: "processFiles", + value: function processFiles(files) { + for (var _iterator19 = files, _isArray19 = Array.isArray(_iterator19), _i20 = 0, _iterator19 = _isArray19 ? _iterator19 : _iterator19[Symbol.iterator]();;) { + var _ref18; + + if (_isArray19) { + if (_i20 >= _iterator19.length) break; + _ref18 = _iterator19[_i20++]; + } else { + _i20 = _iterator19.next(); + if (_i20.done) break; + _ref18 = _i20.value; + } + + var file = _ref18; + + file.processing = true; // Backwards compatibility + file.status = Dropzone.UPLOADING; + + this.emit("processing", file); + } + + if (this.options.uploadMultiple) { + this.emit("processingmultiple", files); + } + + return this.uploadFiles(files); + } + }, { + key: "_getFilesWithXhr", + value: function _getFilesWithXhr(xhr) { + var files = void 0; + return files = this.files.filter(function (file) { + return file.xhr === xhr; + }).map(function (file) { + return file; + }); + } + + // Cancels the file upload and sets the status to CANCELED + // **if** the file is actually being uploaded. + // If it's still in the queue, the file is being removed from it and the status + // set to CANCELED. + + }, { + key: "cancelUpload", + value: function cancelUpload(file) { + if (file.status === Dropzone.UPLOADING) { + var groupedFiles = this._getFilesWithXhr(file.xhr); + for (var _iterator20 = groupedFiles, _isArray20 = Array.isArray(_iterator20), _i21 = 0, _iterator20 = _isArray20 ? _iterator20 : _iterator20[Symbol.iterator]();;) { + var _ref19; + + if (_isArray20) { + if (_i21 >= _iterator20.length) break; + _ref19 = _iterator20[_i21++]; + } else { + _i21 = _iterator20.next(); + if (_i21.done) break; + _ref19 = _i21.value; + } + + var groupedFile = _ref19; + + groupedFile.status = Dropzone.CANCELED; + } + if (typeof file.xhr !== 'undefined') { + file.xhr.abort(); + } + for (var _iterator21 = groupedFiles, _isArray21 = Array.isArray(_iterator21), _i22 = 0, _iterator21 = _isArray21 ? _iterator21 : _iterator21[Symbol.iterator]();;) { + var _ref20; + + if (_isArray21) { + if (_i22 >= _iterator21.length) break; + _ref20 = _iterator21[_i22++]; + } else { + _i22 = _iterator21.next(); + if (_i22.done) break; + _ref20 = _i22.value; + } + + var _groupedFile = _ref20; + + this.emit("canceled", _groupedFile); + } + if (this.options.uploadMultiple) { + this.emit("canceledmultiple", groupedFiles); + } + } else if (file.status === Dropzone.ADDED || file.status === Dropzone.QUEUED) { + file.status = Dropzone.CANCELED; + this.emit("canceled", file); + if (this.options.uploadMultiple) { + this.emit("canceledmultiple", [file]); + } + } + + if (this.options.autoProcessQueue) { + return this.processQueue(); + } + } + }, { + key: "resolveOption", + value: function resolveOption(option) { + if (typeof option === 'function') { + for (var _len3 = arguments.length, args = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { + args[_key3 - 1] = arguments[_key3]; + } + + return option.apply(this, args); + } + return option; + } + }, { + key: "uploadFile", + value: function uploadFile(file) { + return this.uploadFiles([file]); + } + }, { + key: "uploadFiles", + value: function uploadFiles(files) { + var _this14 = this; + + this._transformFiles(files, function (transformedFiles) { + if (files[0].upload.chunked) { + // This file should be sent in chunks! + + // If the chunking option is set, we **know** that there can only be **one** file, since + // uploadMultiple is not allowed with this option. + var file = files[0]; + var transformedFile = transformedFiles[0]; + var startedChunkCount = 0; + + file.upload.chunks = []; + + var handleNextChunk = function handleNextChunk() { + var chunkIndex = 0; + + // Find the next item in file.upload.chunks that is not defined yet. + while (file.upload.chunks[chunkIndex] !== undefined) { + chunkIndex++; + } + + // This means, that all chunks have already been started. + if (chunkIndex >= file.upload.totalChunkCount) return; + + startedChunkCount++; + + var start = chunkIndex * _this14.options.chunkSize; + var end = Math.min(start + _this14.options.chunkSize, file.size); + + var dataBlock = { + name: _this14._getParamName(0), + data: transformedFile.webkitSlice ? transformedFile.webkitSlice(start, end) : transformedFile.slice(start, end), + filename: file.upload.filename, + chunkIndex: chunkIndex + }; + + file.upload.chunks[chunkIndex] = { + file: file, + index: chunkIndex, + dataBlock: dataBlock, // In case we want to retry. + status: Dropzone.UPLOADING, + progress: 0, + retries: 0 // The number of times this block has been retried. + }; + + _this14._uploadData(files, [dataBlock]); + }; + + file.upload.finishedChunkUpload = function (chunk) { + var allFinished = true; + chunk.status = Dropzone.SUCCESS; + + // Clear the data from the chunk + chunk.dataBlock = null; + // Leaving this reference to xhr intact here will cause memory leaks in some browsers + chunk.xhr = null; + + for (var i = 0; i < file.upload.totalChunkCount; i++) { + if (file.upload.chunks[i] === undefined) { + return handleNextChunk(); + } + if (file.upload.chunks[i].status !== Dropzone.SUCCESS) { + allFinished = false; + } + } + + if (allFinished) { + _this14.options.chunksUploaded(file, function () { + _this14._finished(files, '', null); + }); + } + }; + + if (_this14.options.parallelChunkUploads) { + for (var i = 0; i < file.upload.totalChunkCount; i++) { + handleNextChunk(); + } + } else { + handleNextChunk(); + } + } else { + var dataBlocks = []; + for (var _i23 = 0; _i23 < files.length; _i23++) { + dataBlocks[_i23] = { + name: _this14._getParamName(_i23), + data: transformedFiles[_i23], + filename: files[_i23].upload.filename + }; + } + _this14._uploadData(files, dataBlocks); + } + }); + } + + /// Returns the right chunk for given file and xhr + + }, { + key: "_getChunk", + value: function _getChunk(file, xhr) { + for (var i = 0; i < file.upload.totalChunkCount; i++) { + if (file.upload.chunks[i] !== undefined && file.upload.chunks[i].xhr === xhr) { + return file.upload.chunks[i]; + } + } + } + + // This function actually uploads the file(s) to the server. + // If dataBlocks contains the actual data to upload (meaning, that this could either be transformed + // files, or individual chunks for chunked upload). + + }, { + key: "_uploadData", + value: function _uploadData(files, dataBlocks) { + var _this15 = this; + + var xhr = new XMLHttpRequest(); + + // Put the xhr object in the file objects to be able to reference it later. + for (var _iterator22 = files, _isArray22 = Array.isArray(_iterator22), _i24 = 0, _iterator22 = _isArray22 ? _iterator22 : _iterator22[Symbol.iterator]();;) { + var _ref21; + + if (_isArray22) { + if (_i24 >= _iterator22.length) break; + _ref21 = _iterator22[_i24++]; + } else { + _i24 = _iterator22.next(); + if (_i24.done) break; + _ref21 = _i24.value; + } + + var file = _ref21; + + file.xhr = xhr; + } + if (files[0].upload.chunked) { + // Put the xhr object in the right chunk object, so it can be associated later, and found with _getChunk + files[0].upload.chunks[dataBlocks[0].chunkIndex].xhr = xhr; + } + + var method = this.resolveOption(this.options.method, files); + var url = this.resolveOption(this.options.url, files); + xhr.open(method, url, true); + + // Setting the timeout after open because of IE11 issue: https://gitlab.com/meno/dropzone/issues/8 + xhr.timeout = this.resolveOption(this.options.timeout, files); + + // Has to be after `.open()`. See https://github.com/enyo/dropzone/issues/179 + xhr.withCredentials = !!this.options.withCredentials; + + xhr.onload = function (e) { + _this15._finishedUploading(files, xhr, e); + }; + + xhr.onerror = function () { + _this15._handleUploadError(files, xhr); + }; + + // Some browsers do not have the .upload property + var progressObj = xhr.upload != null ? xhr.upload : xhr; + progressObj.onprogress = function (e) { + return _this15._updateFilesUploadProgress(files, xhr, e); + }; + + var headers = { + "Accept": "application/json", + "Cache-Control": "no-cache", + "X-Requested-With": "XMLHttpRequest" + }; + + if (this.options.headers) { + Dropzone.extend(headers, this.options.headers); + } + + for (var headerName in headers) { + var headerValue = headers[headerName]; + if (headerValue) { + xhr.setRequestHeader(headerName, headerValue); + } + } + + var formData = new FormData(); + + // Adding all @options parameters + if (this.options.params) { + var additionalParams = this.options.params; + if (typeof additionalParams === 'function') { + additionalParams = additionalParams.call(this, files, xhr, files[0].upload.chunked ? this._getChunk(files[0], xhr) : null); + } + + for (var key in additionalParams) { + var value = additionalParams[key]; + formData.append(key, value); + } + } + + // Let the user add additional data if necessary + for (var _iterator23 = files, _isArray23 = Array.isArray(_iterator23), _i25 = 0, _iterator23 = _isArray23 ? _iterator23 : _iterator23[Symbol.iterator]();;) { + var _ref22; + + if (_isArray23) { + if (_i25 >= _iterator23.length) break; + _ref22 = _iterator23[_i25++]; + } else { + _i25 = _iterator23.next(); + if (_i25.done) break; + _ref22 = _i25.value; + } + + var _file = _ref22; + + this.emit("sending", _file, xhr, formData); + } + if (this.options.uploadMultiple) { + this.emit("sendingmultiple", files, xhr, formData); + } + + this._addFormElementData(formData); + + // Finally add the files + // Has to be last because some servers (eg: S3) expect the file to be the last parameter + for (var i = 0; i < dataBlocks.length; i++) { + var dataBlock = dataBlocks[i]; + formData.append(dataBlock.name, dataBlock.data, dataBlock.filename); + } + + this.submitRequest(xhr, formData, files); + } + + // Transforms all files with this.options.transformFile and invokes done with the transformed files when done. + + }, { + key: "_transformFiles", + value: function _transformFiles(files, done) { + var _this16 = this; + + var transformedFiles = []; + // Clumsy way of handling asynchronous calls, until I get to add a proper Future library. + var doneCounter = 0; + + var _loop = function _loop(i) { + _this16.options.transformFile.call(_this16, files[i], function (transformedFile) { + transformedFiles[i] = transformedFile; + if (++doneCounter === files.length) { + done(transformedFiles); + } + }); + }; + + for (var i = 0; i < files.length; i++) { + _loop(i); + } + } + + // Takes care of adding other input elements of the form to the AJAX request + + }, { + key: "_addFormElementData", + value: function _addFormElementData(formData) { + // Take care of other input elements + if (this.element.tagName === "FORM") { + for (var _iterator24 = this.element.querySelectorAll("input, textarea, select, button"), _isArray24 = Array.isArray(_iterator24), _i26 = 0, _iterator24 = _isArray24 ? _iterator24 : _iterator24[Symbol.iterator]();;) { + var _ref23; + + if (_isArray24) { + if (_i26 >= _iterator24.length) break; + _ref23 = _iterator24[_i26++]; + } else { + _i26 = _iterator24.next(); + if (_i26.done) break; + _ref23 = _i26.value; + } + + var input = _ref23; + + var inputName = input.getAttribute("name"); + var inputType = input.getAttribute("type"); + if (inputType) inputType = inputType.toLowerCase(); + + // If the input doesn't have a name, we can't use it. + if (typeof inputName === 'undefined' || inputName === null) continue; + + if (input.tagName === "SELECT" && input.hasAttribute("multiple")) { + // Possibly multiple values + for (var _iterator25 = input.options, _isArray25 = Array.isArray(_iterator25), _i27 = 0, _iterator25 = _isArray25 ? _iterator25 : _iterator25[Symbol.iterator]();;) { + var _ref24; + + if (_isArray25) { + if (_i27 >= _iterator25.length) break; + _ref24 = _iterator25[_i27++]; + } else { + _i27 = _iterator25.next(); + if (_i27.done) break; + _ref24 = _i27.value; + } + + var option = _ref24; + + if (option.selected) { + formData.append(inputName, option.value); + } + } + } else if (!inputType || inputType !== "checkbox" && inputType !== "radio" || input.checked) { + formData.append(inputName, input.value); + } + } + } + } + + // Invoked when there is new progress information about given files. + // If e is not provided, it is assumed that the upload is finished. + + }, { + key: "_updateFilesUploadProgress", + value: function _updateFilesUploadProgress(files, xhr, e) { + var progress = void 0; + if (typeof e !== 'undefined') { + progress = 100 * e.loaded / e.total; + + if (files[0].upload.chunked) { + var file = files[0]; + // Since this is a chunked upload, we need to update the appropriate chunk progress. + var chunk = this._getChunk(file, xhr); + chunk.progress = progress; + chunk.total = e.total; + chunk.bytesSent = e.loaded; + var fileProgress = 0, + fileTotal = void 0, + fileBytesSent = void 0; + file.upload.progress = 0; + file.upload.total = 0; + file.upload.bytesSent = 0; + for (var i = 0; i < file.upload.totalChunkCount; i++) { + if (file.upload.chunks[i] !== undefined && file.upload.chunks[i].progress !== undefined) { + file.upload.progress += file.upload.chunks[i].progress; + file.upload.total += file.upload.chunks[i].total; + file.upload.bytesSent += file.upload.chunks[i].bytesSent; + } + } + file.upload.progress = file.upload.progress / file.upload.totalChunkCount; + } else { + for (var _iterator26 = files, _isArray26 = Array.isArray(_iterator26), _i28 = 0, _iterator26 = _isArray26 ? _iterator26 : _iterator26[Symbol.iterator]();;) { + var _ref25; + + if (_isArray26) { + if (_i28 >= _iterator26.length) break; + _ref25 = _iterator26[_i28++]; + } else { + _i28 = _iterator26.next(); + if (_i28.done) break; + _ref25 = _i28.value; + } + + var _file2 = _ref25; + + _file2.upload.progress = progress; + _file2.upload.total = e.total; + _file2.upload.bytesSent = e.loaded; + } + } + for (var _iterator27 = files, _isArray27 = Array.isArray(_iterator27), _i29 = 0, _iterator27 = _isArray27 ? _iterator27 : _iterator27[Symbol.iterator]();;) { + var _ref26; + + if (_isArray27) { + if (_i29 >= _iterator27.length) break; + _ref26 = _iterator27[_i29++]; + } else { + _i29 = _iterator27.next(); + if (_i29.done) break; + _ref26 = _i29.value; + } + + var _file3 = _ref26; + + this.emit("uploadprogress", _file3, _file3.upload.progress, _file3.upload.bytesSent); + } + } else { + // Called when the file finished uploading + + var allFilesFinished = true; + + progress = 100; + + for (var _iterator28 = files, _isArray28 = Array.isArray(_iterator28), _i30 = 0, _iterator28 = _isArray28 ? _iterator28 : _iterator28[Symbol.iterator]();;) { + var _ref27; + + if (_isArray28) { + if (_i30 >= _iterator28.length) break; + _ref27 = _iterator28[_i30++]; + } else { + _i30 = _iterator28.next(); + if (_i30.done) break; + _ref27 = _i30.value; + } + + var _file4 = _ref27; + + if (_file4.upload.progress !== 100 || _file4.upload.bytesSent !== _file4.upload.total) { + allFilesFinished = false; + } + _file4.upload.progress = progress; + _file4.upload.bytesSent = _file4.upload.total; + } + + // Nothing to do, all files already at 100% + if (allFilesFinished) { + return; + } + + for (var _iterator29 = files, _isArray29 = Array.isArray(_iterator29), _i31 = 0, _iterator29 = _isArray29 ? _iterator29 : _iterator29[Symbol.iterator]();;) { + var _ref28; + + if (_isArray29) { + if (_i31 >= _iterator29.length) break; + _ref28 = _iterator29[_i31++]; + } else { + _i31 = _iterator29.next(); + if (_i31.done) break; + _ref28 = _i31.value; + } + + var _file5 = _ref28; + + this.emit("uploadprogress", _file5, progress, _file5.upload.bytesSent); + } + } + } + }, { + key: "_finishedUploading", + value: function _finishedUploading(files, xhr, e) { + var response = void 0; + + if (files[0].status === Dropzone.CANCELED) { + return; + } + + if (xhr.readyState !== 4) { + return; + } + + if (xhr.responseType !== 'arraybuffer' && xhr.responseType !== 'blob') { + response = xhr.responseText; + + if (xhr.getResponseHeader("content-type") && ~xhr.getResponseHeader("content-type").indexOf("application/json")) { + try { + response = JSON.parse(response); + } catch (error) { + e = error; + response = "Invalid JSON response from server."; + } + } + } + + this._updateFilesUploadProgress(files); + + if (!(200 <= xhr.status && xhr.status < 300)) { + this._handleUploadError(files, xhr, response); + } else { + if (files[0].upload.chunked) { + files[0].upload.finishedChunkUpload(this._getChunk(files[0], xhr)); + } else { + this._finished(files, response, e); + } + } + } + }, { + key: "_handleUploadError", + value: function _handleUploadError(files, xhr, response) { + if (files[0].status === Dropzone.CANCELED) { + return; + } + + if (files[0].upload.chunked && this.options.retryChunks) { + var chunk = this._getChunk(files[0], xhr); + if (chunk.retries++ < this.options.retryChunksLimit) { + this._uploadData(files, [chunk.dataBlock]); + return; + } else { + console.warn('Retried this chunk too often. Giving up.'); + } + } + + for (var _iterator30 = files, _isArray30 = Array.isArray(_iterator30), _i32 = 0, _iterator30 = _isArray30 ? _iterator30 : _iterator30[Symbol.iterator]();;) { + var _ref29; + + if (_isArray30) { + if (_i32 >= _iterator30.length) break; + _ref29 = _iterator30[_i32++]; + } else { + _i32 = _iterator30.next(); + if (_i32.done) break; + _ref29 = _i32.value; + } + + var file = _ref29; + + this._errorProcessing(files, response || this.options.dictResponseError.replace("{{statusCode}}", xhr.status), xhr); + } + } + }, { + key: "submitRequest", + value: function submitRequest(xhr, formData, files) { + xhr.send(formData); + } + + // Called internally when processing is finished. + // Individual callbacks have to be called in the appropriate sections. + + }, { + key: "_finished", + value: function _finished(files, responseText, e) { + for (var _iterator31 = files, _isArray31 = Array.isArray(_iterator31), _i33 = 0, _iterator31 = _isArray31 ? _iterator31 : _iterator31[Symbol.iterator]();;) { + var _ref30; + + if (_isArray31) { + if (_i33 >= _iterator31.length) break; + _ref30 = _iterator31[_i33++]; + } else { + _i33 = _iterator31.next(); + if (_i33.done) break; + _ref30 = _i33.value; + } + + var file = _ref30; + + file.status = Dropzone.SUCCESS; + this.emit("success", file, responseText, e); + this.emit("complete", file); + } + if (this.options.uploadMultiple) { + this.emit("successmultiple", files, responseText, e); + this.emit("completemultiple", files); + } + + if (this.options.autoProcessQueue) { + return this.processQueue(); + } + } + + // Called internally when processing is finished. + // Individual callbacks have to be called in the appropriate sections. + + }, { + key: "_errorProcessing", + value: function _errorProcessing(files, message, xhr) { + for (var _iterator32 = files, _isArray32 = Array.isArray(_iterator32), _i34 = 0, _iterator32 = _isArray32 ? _iterator32 : _iterator32[Symbol.iterator]();;) { + var _ref31; + + if (_isArray32) { + if (_i34 >= _iterator32.length) break; + _ref31 = _iterator32[_i34++]; + } else { + _i34 = _iterator32.next(); + if (_i34.done) break; + _ref31 = _i34.value; + } + + var file = _ref31; + + file.status = Dropzone.ERROR; + this.emit("error", file, message, xhr); + this.emit("complete", file); + } + if (this.options.uploadMultiple) { + this.emit("errormultiple", files, message, xhr); + this.emit("completemultiple", files); + } + + if (this.options.autoProcessQueue) { + return this.processQueue(); + } + } + }], [{ + key: "uuidv4", + value: function uuidv4() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + var r = Math.random() * 16 | 0, + v = c === 'x' ? r : r & 0x3 | 0x8; + return v.toString(16); + }); + } + }]); + + return Dropzone; + }(Emitter); + + Dropzone.initClass(); + + Dropzone.version = "5.5.0"; + + // This is a map of options for your different dropzones. Add configurations + // to this object for your different dropzone elemens. + // + // Example: + // + // Dropzone.options.myDropzoneElementId = { maxFilesize: 1 }; + // + // To disable autoDiscover for a specific element, you can set `false` as an option: + // + // Dropzone.options.myDisabledElementId = false; + // + // And in html: + // + //
+ Dropzone.options = {}; + + // Returns the options for an element or undefined if none available. + Dropzone.optionsForElement = function (element) { + // Get the `Dropzone.options.elementId` for this element if it exists + if (element.getAttribute("id")) { + return Dropzone.options[camelize(element.getAttribute("id"))]; + } else { + return undefined; + } + }; + + // Holds a list of all dropzone instances + Dropzone.instances = []; + + // Returns the dropzone for given element if any + Dropzone.forElement = function (element) { + if (typeof element === "string") { + element = document.querySelector(element); + } + if ((element != null ? element.dropzone : undefined) == null) { + 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."); + } + return element.dropzone; + }; + + // Set to false if you don't want Dropzone to automatically find and attach to .dropzone elements. + Dropzone.autoDiscover = true; + + // Looks for all .dropzone elements and creates a dropzone for them + Dropzone.discover = function () { + var dropzones = void 0; + if (document.querySelectorAll) { + dropzones = document.querySelectorAll(".dropzone"); + } else { + dropzones = []; + // IE :( + var checkElements = function checkElements(elements) { + return function () { + var result = []; + for (var _iterator33 = elements, _isArray33 = Array.isArray(_iterator33), _i35 = 0, _iterator33 = _isArray33 ? _iterator33 : _iterator33[Symbol.iterator]();;) { + var _ref32; + + if (_isArray33) { + if (_i35 >= _iterator33.length) break; + _ref32 = _iterator33[_i35++]; + } else { + _i35 = _iterator33.next(); + if (_i35.done) break; + _ref32 = _i35.value; + } + + var el = _ref32; + + if (/(^| )dropzone($| )/.test(el.className)) { + result.push(dropzones.push(el)); + } else { + result.push(undefined); + } + } + return result; + }(); + }; + checkElements(document.getElementsByTagName("div")); + checkElements(document.getElementsByTagName("form")); + } + + return function () { + var result = []; + for (var _iterator34 = dropzones, _isArray34 = Array.isArray(_iterator34), _i36 = 0, _iterator34 = _isArray34 ? _iterator34 : _iterator34[Symbol.iterator]();;) { + var _ref33; + + if (_isArray34) { + if (_i36 >= _iterator34.length) break; + _ref33 = _iterator34[_i36++]; + } else { + _i36 = _iterator34.next(); + if (_i36.done) break; + _ref33 = _i36.value; + } + + var dropzone = _ref33; + + // Create a dropzone unless auto discover has been disabled for specific element + if (Dropzone.optionsForElement(dropzone) !== false) { + result.push(new Dropzone(dropzone)); + } else { + result.push(undefined); + } + } + return result; + }(); + }; + + // Since the whole Drag'n'Drop API is pretty new, some browsers implement it, + // but not correctly. + // So I created a blacklist of userAgents. Yes, yes. Browser sniffing, I know. + // But what to do when browsers *theoretically* support an API, but crash + // when using it. + // + // This is a list of regular expressions tested against navigator.userAgent + // + // ** It should only be used on browser that *do* support the API, but + // incorrectly ** + // + Dropzone.blacklistedBrowsers = [ + // The mac os and windows phone version of opera 12 seems to have a problem with the File drag'n'drop API. + /opera.*(Macintosh|Windows Phone).*version\/12/i]; + + // Checks if the browser is supported + Dropzone.isBrowserSupported = function () { + var capableBrowser = true; + + if (window.File && window.FileReader && window.FileList && window.Blob && window.FormData && document.querySelector) { + if (!("classList" in document.createElement("a"))) { + capableBrowser = false; + } else { + // The browser supports the API, but may be blacklisted. + for (var _iterator35 = Dropzone.blacklistedBrowsers, _isArray35 = Array.isArray(_iterator35), _i37 = 0, _iterator35 = _isArray35 ? _iterator35 : _iterator35[Symbol.iterator]();;) { + var _ref34; + + if (_isArray35) { + if (_i37 >= _iterator35.length) break; + _ref34 = _iterator35[_i37++]; + } else { + _i37 = _iterator35.next(); + if (_i37.done) break; + _ref34 = _i37.value; + } + + var regex = _ref34; + + if (regex.test(navigator.userAgent)) { + capableBrowser = false; + continue; + } + } + } + } else { + capableBrowser = false; + } + + return capableBrowser; + }; + + Dropzone.dataURItoBlob = function (dataURI) { + // convert base64 to raw binary data held in a string + // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this + var byteString = atob(dataURI.split(',')[1]); + + // separate out the mime component + var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; + + // write the bytes of the string to an ArrayBuffer + var ab = new ArrayBuffer(byteString.length); + var ia = new Uint8Array(ab); + for (var i = 0, end = byteString.length, asc = 0 <= end; asc ? i <= end : i >= end; asc ? i++ : i--) { + ia[i] = byteString.charCodeAt(i); + } + + // write the ArrayBuffer to a blob + return new Blob([ab], { type: mimeString }); + }; + + // Returns an array without the rejected item + var without = function without(list, rejectedItem) { + return list.filter(function (item) { + return item !== rejectedItem; + }).map(function (item) { + return item; + }); + }; + + // abc-def_ghi -> abcDefGhi + var camelize = function camelize(str) { + return str.replace(/[\-_](\w)/g, function (match) { + return match.charAt(1).toUpperCase(); + }); + }; + + // Creates an element from string + Dropzone.createElement = function (string) { + var div = document.createElement("div"); + div.innerHTML = string; + return div.childNodes[0]; + }; + + // Tests if given element is inside (or simply is) the container + Dropzone.elementInside = function (element, container) { + if (element === container) { + return true; + } // Coffeescript doesn't support do/while loops + while (element = element.parentNode) { + if (element === container) { + return true; + } + } + return false; + }; + + Dropzone.getElement = function (el, name) { + var element = void 0; + if (typeof el === "string") { + element = document.querySelector(el); + } else if (el.nodeType != null) { + element = el; + } + if (element == null) { + throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector or a plain HTML element."); + } + return element; + }; + + Dropzone.getElements = function (els, name) { + var el = void 0, + elements = void 0; + if (els instanceof Array) { + elements = []; + try { + for (var _iterator36 = els, _isArray36 = Array.isArray(_iterator36), _i38 = 0, _iterator36 = _isArray36 ? _iterator36 : _iterator36[Symbol.iterator]();;) { + if (_isArray36) { + if (_i38 >= _iterator36.length) break; + el = _iterator36[_i38++]; + } else { + _i38 = _iterator36.next(); + if (_i38.done) break; + el = _i38.value; + } + + elements.push(this.getElement(el, name)); + } + } catch (e) { + elements = null; + } + } else if (typeof els === "string") { + elements = []; + for (var _iterator37 = document.querySelectorAll(els), _isArray37 = Array.isArray(_iterator37), _i39 = 0, _iterator37 = _isArray37 ? _iterator37 : _iterator37[Symbol.iterator]();;) { + if (_isArray37) { + if (_i39 >= _iterator37.length) break; + el = _iterator37[_i39++]; + } else { + _i39 = _iterator37.next(); + if (_i39.done) break; + el = _i39.value; + } + + elements.push(el); + } + } else if (els.nodeType != null) { + elements = [els]; + } + + if (elements == null || !elements.length) { + throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector, a plain HTML element or a list of those."); + } + + return elements; + }; + + // Asks the user the question and calls accepted or rejected accordingly + // + // The default implementation just uses `window.confirm` and then calls the + // appropriate callback. + Dropzone.confirm = function (question, accepted, rejected) { + if (window.confirm(question)) { + return accepted(); + } else if (rejected != null) { + return rejected(); + } + }; + + // Validates the mime type like this: + // + // https://developer.mozilla.org/en-US/docs/HTML/Element/input#attr-accept + Dropzone.isValidFile = function (file, acceptedFiles) { + if (!acceptedFiles) { + return true; + } // If there are no accepted mime types, it's OK + acceptedFiles = acceptedFiles.split(","); + + var mimeType = file.type; + var baseMimeType = mimeType.replace(/\/.*$/, ""); + + for (var _iterator38 = acceptedFiles, _isArray38 = Array.isArray(_iterator38), _i40 = 0, _iterator38 = _isArray38 ? _iterator38 : _iterator38[Symbol.iterator]();;) { + var _ref35; + + if (_isArray38) { + if (_i40 >= _iterator38.length) break; + _ref35 = _iterator38[_i40++]; + } else { + _i40 = _iterator38.next(); + if (_i40.done) break; + _ref35 = _i40.value; + } + + var validType = _ref35; + + validType = validType.trim(); + if (validType.charAt(0) === ".") { + if (file.name.toLowerCase().indexOf(validType.toLowerCase(), file.name.length - validType.length) !== -1) { + return true; + } + } else if (/\/\*$/.test(validType)) { + // This is something like a image/* mime type + if (baseMimeType === validType.replace(/\/.*$/, "")) { + return true; + } + } else { + if (mimeType === validType) { + return true; + } + } + } + + return false; + }; + + // Augment jQuery + if (typeof jQuery !== 'undefined' && jQuery !== null) { + jQuery.fn.dropzone = function (options) { + return this.each(function () { + return new Dropzone(this, options); + }); + }; + } + + if (typeof module !== 'undefined' && module !== null) { + module.exports = Dropzone; + } else { + window.Dropzone = Dropzone; + } + + // Dropzone file status codes + Dropzone.ADDED = "added"; + + Dropzone.QUEUED = "queued"; + // For backwards compatibility. Now, if a file is accepted, it's either queued + // or uploading. + Dropzone.ACCEPTED = Dropzone.QUEUED; + + Dropzone.UPLOADING = "uploading"; + Dropzone.PROCESSING = Dropzone.UPLOADING; // alias + + Dropzone.CANCELED = "canceled"; + Dropzone.ERROR = "error"; + Dropzone.SUCCESS = "success"; + + /* + + Bugfix for iOS 6 and 7 + Source: http://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios + based on the work of https://github.com/stomita/ios-imagefile-megapixel + + */ + + // Detecting vertical squash in loaded image. + // Fixes a bug which squash image vertically while drawing into canvas for some images. + // This is a bug in iOS6 devices. This function from https://github.com/stomita/ios-imagefile-megapixel + var detectVerticalSquash = function detectVerticalSquash(img) { + var iw = img.naturalWidth; + var ih = img.naturalHeight; + var canvas = document.createElement("canvas"); + canvas.width = 1; + canvas.height = ih; + var ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0); + + var _ctx$getImageData = ctx.getImageData(1, 0, 1, ih), + data = _ctx$getImageData.data; + + // search image edge pixel position in case it is squashed vertically. + + + var sy = 0; + var ey = ih; + var py = ih; + while (py > sy) { + var alpha = data[(py - 1) * 4 + 3]; + + if (alpha === 0) { + ey = py; + } else { + sy = py; + } + + py = ey + sy >> 1; + } + var ratio = py / ih; + + if (ratio === 0) { + return 1; + } else { + return ratio; + } + }; + + // A replacement for context.drawImage + // (args are for source and destination). + var drawImageIOSFix = function drawImageIOSFix(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) { + var vertSquashRatio = detectVerticalSquash(img); + return ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio); + }; + + // Based on MinifyJpeg + // Source: http://www.perry.cz/files/ExifRestorer.js + // http://elicon.blog57.fc2.com/blog-entry-206.html + + var ExifRestore = function () { + function ExifRestore() { + _classCallCheck(this, ExifRestore); + } + + _createClass(ExifRestore, null, [{ + key: "initClass", + value: function initClass() { + this.KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + } + }, { + key: "encode64", + value: function encode64(input) { + var output = ''; + var chr1 = undefined; + var chr2 = undefined; + var chr3 = ''; + var enc1 = undefined; + var enc2 = undefined; + var enc3 = undefined; + var enc4 = ''; + var i = 0; + while (true) { + chr1 = input[i++]; + chr2 = input[i++]; + chr3 = input[i++]; + enc1 = chr1 >> 2; + enc2 = (chr1 & 3) << 4 | chr2 >> 4; + enc3 = (chr2 & 15) << 2 | chr3 >> 6; + enc4 = chr3 & 63; + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + output = output + this.KEY_STR.charAt(enc1) + this.KEY_STR.charAt(enc2) + this.KEY_STR.charAt(enc3) + this.KEY_STR.charAt(enc4); + chr1 = chr2 = chr3 = ''; + enc1 = enc2 = enc3 = enc4 = ''; + if (!(i < input.length)) { + break; + } + } + return output; + } + }, { + key: "restore", + value: function restore(origFileBase64, resizedFileBase64) { + if (!origFileBase64.match('data:image/jpeg;base64,')) { + return resizedFileBase64; + } + var rawImage = this.decode64(origFileBase64.replace('data:image/jpeg;base64,', '')); + var segments = this.slice2Segments(rawImage); + var image = this.exifManipulation(resizedFileBase64, segments); + return "data:image/jpeg;base64," + this.encode64(image); + } + }, { + key: "exifManipulation", + value: function exifManipulation(resizedFileBase64, segments) { + var exifArray = this.getExifArray(segments); + var newImageArray = this.insertExif(resizedFileBase64, exifArray); + var aBuffer = new Uint8Array(newImageArray); + return aBuffer; + } + }, { + key: "getExifArray", + value: function getExifArray(segments) { + var seg = undefined; + var x = 0; + while (x < segments.length) { + seg = segments[x]; + if (seg[0] === 255 & seg[1] === 225) { + return seg; + } + x++; + } + return []; + } + }, { + key: "insertExif", + value: function insertExif(resizedFileBase64, exifArray) { + var imageData = resizedFileBase64.replace('data:image/jpeg;base64,', ''); + var buf = this.decode64(imageData); + var separatePoint = buf.indexOf(255, 3); + var mae = buf.slice(0, separatePoint); + var ato = buf.slice(separatePoint); + var array = mae; + array = array.concat(exifArray); + array = array.concat(ato); + return array; + } + }, { + key: "slice2Segments", + value: function slice2Segments(rawImageArray) { + var head = 0; + var segments = []; + while (true) { + var length; + if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 218) { + break; + } + if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 216) { + head += 2; + } else { + length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3]; + var endPoint = head + length + 2; + var seg = rawImageArray.slice(head, endPoint); + segments.push(seg); + head = endPoint; + } + if (head > rawImageArray.length) { + break; + } + } + return segments; + } + }, { + key: "decode64", + value: function decode64(input) { + var output = ''; + var chr1 = undefined; + var chr2 = undefined; + var chr3 = ''; + var enc1 = undefined; + var enc2 = undefined; + var enc3 = undefined; + var enc4 = ''; + var i = 0; + var buf = []; + // remove all characters that are not A-Z, a-z, 0-9, +, /, or = + var base64test = /[^A-Za-z0-9\+\/\=]/g; + if (base64test.exec(input)) { + console.warn('There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, \'+\', \'/\',and \'=\'\nExpect errors in decoding.'); + } + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); + while (true) { + enc1 = this.KEY_STR.indexOf(input.charAt(i++)); + enc2 = this.KEY_STR.indexOf(input.charAt(i++)); + enc3 = this.KEY_STR.indexOf(input.charAt(i++)); + enc4 = this.KEY_STR.indexOf(input.charAt(i++)); + chr1 = enc1 << 2 | enc2 >> 4; + chr2 = (enc2 & 15) << 4 | enc3 >> 2; + chr3 = (enc3 & 3) << 6 | enc4; + buf.push(chr1); + if (enc3 !== 64) { + buf.push(chr2); + } + if (enc4 !== 64) { + buf.push(chr3); + } + chr1 = chr2 = chr3 = ''; + enc1 = enc2 = enc3 = enc4 = ''; + if (!(i < input.length)) { + break; + } + } + return buf; + } + }]); + + return ExifRestore; + }(); + + ExifRestore.initClass(); + + /* + * contentloaded.js + * + * Author: Diego Perini (diego.perini at gmail.com) + * Summary: cross-browser wrapper for DOMContentLoaded + * Updated: 20101020 + * License: MIT + * Version: 1.2 + * + * URL: + * http://javascript.nwbox.com/ContentLoaded/ + * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE + */ + + // @win window reference + // @fn function reference + var contentLoaded = function contentLoaded(win, fn) { + var done = false; + var top = true; + var doc = win.document; + var root = doc.documentElement; + var add = doc.addEventListener ? "addEventListener" : "attachEvent"; + var rem = doc.addEventListener ? "removeEventListener" : "detachEvent"; + var pre = doc.addEventListener ? "" : "on"; + var init = function init(e) { + if (e.type === "readystatechange" && doc.readyState !== "complete") { + return; + } + (e.type === "load" ? win : doc)[rem](pre + e.type, init, false); + if (!done && (done = true)) { + return fn.call(win, e.type || e); + } + }; + + var poll = function poll() { + try { + root.doScroll("left"); + } catch (e) { + setTimeout(poll, 50); + return; + } + return init("poll"); + }; + + if (doc.readyState !== "complete") { + if (doc.createEventObject && root.doScroll) { + try { + top = !win.frameElement; + } catch (error) {} + if (top) { + poll(); + } + } + doc[add](pre + "DOMContentLoaded", init, false); + doc[add](pre + "readystatechange", init, false); + return win[add](pre + "load", init, false); + } + }; + + // As a single function to be able to write tests. + Dropzone._autoDiscoverFunction = function () { + if (Dropzone.autoDiscover) { + return Dropzone.discover(); + } + }; + contentLoaded(window, Dropzone._autoDiscoverFunction); + + function __guard__(value, transform) { + return typeof value !== 'undefined' && value !== null ? transform(value) : undefined; + } + function __guardMethod__(obj, methodName, transform) { + if (typeof obj !== 'undefined' && obj !== null && typeof obj[methodName] === 'function') { + return transform(obj, methodName); + } else { + return undefined; + } + } + + return module.exports; + })); \ No newline at end of file diff --git a/SplunkAppForWazuh/appserver/static/js/main.js b/SplunkAppForWazuh/appserver/static/js/main.js index 87c8d4372..5b32c1e44 100644 --- a/SplunkAppForWazuh/appserver/static/js/main.js +++ b/SplunkAppForWazuh/appserver/static/js/main.js @@ -20,6 +20,9 @@ require.config({ // JSON2XML js2xmlparser: 'js/libs/json2xml/jsontoxml', + + // Dropzonejs + Dropzone: 'js/libs/dropzone/dropzone', // File saver FileSaver: 'js/libs/file-saver/file-saver',