\n\n\n","import mod from \"-!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-4[0].rules[0].use[0]!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./other_version_notes.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-4[0].rules[0].use[0]!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./other_version_notes.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./other_version_notes.vue?vue&type=template&id=1521a894&\"\nimport script from \"./other_version_notes.vue?vue&type=script&lang=js&\"\nexport * from \"./other_version_notes.vue?vue&type=script&lang=js&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('a',{staticClass:\"ml-2\",attrs:{\"href\":\"#\"},on:{\"click\":function($event){$event.preventDefault();_vm.show = !_vm.show}}},[_vm._v(_vm._s(_vm.caret)+\" \"+_vm._s(_vm.notes.length)+\" notes from other versions\")]),_vm._v(\" \"),(_vm.show)?_c('Notes',{attrs:{\"hide-complete-option\":\"true\",\"hide-create\":\"true\",\"show-version\":\"true\",\"notes\":_vm.notes,\"owns-mix\":_vm.ownsMix,\"mid-id\":_vm.mixId}}):_vm._e()],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","import Vue from 'vue'\nimport Notes from './notes.vue'\nimport OtherVersionNotes from './other_version_notes.vue'\n\n$(document).ready(() => {\n $(\".mix-notes\").each( (_, div) => {\n new Vue({\n el: div,\n render: h => h(Notes, { props: $(div).data() } )\n })\n });\n\n $(\".mix-notes-other-versions\").each( (_, div) => {\n new Vue({\n el: div,\n render: h => h(OtherVersionNotes, { props: $(div).data() } )\n })\n })\n})\n\n","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('div',{staticClass:\"form-group\"},[_c('file-drag-target',{staticClass:\"drag-target\",attrs:{\"drag-class\":\"drag-target-active\"},on:{\"change\":function($event){return _vm.updateFiles($event)}}},[_c('div',{staticClass:\"custom-file\"},[_c('input',{staticClass:\"custom-file-input\",attrs:{\"type\":\"file\",\"name\":\"mix_files\",\"id\":\"mix_files\",\"multiple\":\"\"},on:{\"input\":function($event){return _vm.updateFiles($event)}}}),_vm._v(\" \"),_c('label',{staticClass:\"custom-file-label\",attrs:{\"for\":\"mix_files\"}},[(_vm.files.length == 0)?_c('div',[_vm._v(\"Drag files here or choose mixes...\")]):(_vm.files.length == 1)?_c('div',[_c('pre',[_vm._v(_vm._s(_vm.files[0].name))])]):_c('div',[_vm._v(_vm._s(_vm.files.length)+\" files...\")])])])]),_vm._v(\" \"),_c('div',[_vm._v(\"\\n or...\\n \")]),_vm._v(\" \"),_c('div',{attrs:{\"id\":\"dropbox-chooser\"}}),_vm._v(\" \"),_vm._m(0)],1),_vm._v(\" \"),_vm._l((_vm.files),function(file,index){return _c('div',[_c('pre',[_vm._v(_vm._s(file.name))]),_vm._v(\" \"),(file.uploading)?_c('progress',{staticStyle:{\"width\":\"100%\"},attrs:{\"max\":\"100\"},domProps:{\"value\":file.progress}}):_vm._e(),_vm._v(\" \"),(Object.keys(file.errors).length > 0)?_c('div',{staticClass:\"alert alert-danger\"},[_c('ul',[_vm._v(\"\\n There were problems with your upload:\\n \"),_vm._l((file.errors),function(value,key){return _vm._l((value),function(err){return _c('li',[_c('b',[_vm._v(_vm._s(key))]),_vm._v(\": \"),_c('i',[_vm._v(_vm._s(err))])])})})],2)]):_vm._e(),_vm._v(\" \"),(file.uploaded)?_c('div',{staticClass:\"alert alert-success\"},[_vm._v(\"\\n Uploaded Successfully!\\n \")]):_c('div',[_c('div',{staticClass:\"form-group row\"},[_c('label',{staticClass:\"col-sm-3 col-form-label\",attrs:{\"for\":_vm.nameOf(index, 'artist_name')}},[_vm._v(\"Artist:\")]),_vm._v(\" \"),_c('div',{staticClass:\"col-sm-9\",attrs:{\"autocomplete-wrapper\":\"\"}},[_c('autocomplete',{ref:\"autocomplete\",refInFor:true,attrs:{\"search\":_vm.searchArtists},on:{\"input\":function($event){return _vm.updateArtist($event.target.value, index)},\"submit\":function($event){return _vm.updateArtist($event, index)}}}),_vm._v(\" \"),_c('input',{attrs:{\"type\":\"hidden\",\"name\":_vm.nameOf(index, 'artist_name')},domProps:{\"value\":file.artist}}),_vm._v(\" \"),_c('a',{attrs:{\"href\":\"#\"},on:{\"click\":function($event){$event.preventDefault();$event.stopPropagation();return _vm.artistAutocompleteClick(index)}}},[_c('i',{staticClass:\"autocomplete-caret fa fa-caret-down\"})])],1)]),_vm._v(\" \"),_c('div',{staticClass:\"form-group row\"},[_c('label',{staticClass:\"col-sm-3 col-form-label\",attrs:{\"for\":_vm.nameOf(index, 'song_name')}},[_vm._v(\"Song:\")]),_vm._v(\" \"),_c('div',{staticClass:\"col-sm-9 autocomplete-wrapper\"},[_c('autocomplete',{ref:\"autocompleteTitle\",refInFor:true,attrs:{\"search\":_vm.searchSongs(file)},on:{\"input\":function($event){return _vm.updateTitle($event.target.value, file)},\"submit\":function($event){return _vm.updateTitle($event, file)}}}),_vm._v(\" \"),_c('input',{attrs:{\"type\":\"hidden\",\"id\":_vm.nameOf(index, 'song_name')},domProps:{\"value\":file.title}}),_vm._v(\" \"),_c('a',{attrs:{\"href\":\"#\"},on:{\"click\":function($event){$event.preventDefault();$event.stopPropagation();return _vm.titleAutocompleteClick(index)}}},[_c('i',{staticClass:\"autocomplete-caret fa fa-caret-down\"})])],1)]),_vm._v(\" \"),_c('div',{staticClass:\"form-group row\"},[_c('label',{staticClass:\"col-sm-3 col-form-label\",attrs:{\"for\":\"nameOf(index, 'description')\"}},[_vm._v(\"Description:\")]),_vm._v(\" \"),_c('div',{staticClass:\"col-sm-9\"},[_c('textarea',{directives:[{name:\"model\",rawName:\"v-model\",value:(file.description),expression:\"file.description\"}],staticClass:\"form-control\",attrs:{\"placeholder\":\"What's new in this version of the mix?\"},domProps:{\"value\":(file.description)},on:{\"input\":function($event){if($event.target.composing){ return; }_vm.$set(file, \"description\", $event.target.value)}}})])]),_vm._v(\" \"),(file.artist && file.title)?_c('div',{staticClass:\"form-group row\"},[_c('label',{staticClass:\"col-sm-3 col-form-label\"},[_vm._v(\"Version:\")]),_vm._v(\" \"),_c('div',{staticClass:\"col-sm-9\"},[_c('label',{staticClass:\"col-form-label\"},[_vm._v(\"\\n \"+_vm._s(file.version)+\"\\n \")])])]):_vm._e()])])}),_vm._v(\" \"),_c('div',{staticClass:\"form-row\"},[_c('button',{staticClass:\"btn btn-primary\",attrs:{\"disabled\":_vm.uploading},on:{\"click\":function($event){return _vm.startUpload(0)}}},[_vm._v(_vm._s(_vm.uploadButtonTitle))])])],2)}\nvar staticRenderFns = [function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('small',{staticClass:\"form-text\"},[_vm._v(\"For the moment, we only accept MP3s.\")])])}]\n\nexport { render, staticRenderFns }","\n
\n \n
\n\n\n\n","import mod from \"-!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-4[0].rules[0].use[0]!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./file_drag_target.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-4[0].rules[0].use[0]!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./file_drag_target.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./file_drag_target.vue?vue&type=template&id=bea749b6&\"\nimport script from \"./file_drag_target.vue?vue&type=script&lang=js&\"\nexport * from \"./file_drag_target.vue?vue&type=script&lang=js&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{class:_vm.activeClass},[_vm._t(\"default\")],2)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\n
\n
\n \n
\n \n \n
\n \n
\n or...\n
\n
\n
\n
\n For the moment, we only accept MP3s.\n
\n
\n\n\n
\n
{{ file.name }}
\n \n
0\" class=\"alert alert-danger\">\n
\n There were problems with your upload:\n \n
{{ key }}: {{ err }}
\n \n
\n
\n
\n Uploaded Successfully!\n
\n
\n
\n \n
\n \n \n \n
\n
\n
\n \n
\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n
\n \n
\n \n
\n
\n
\n
\n
\n \n
\n
\n\n\n","import mod from \"-!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-4[0].rules[0].use[0]!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./upload.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-4[0].rules[0].use[0]!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./upload.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./upload.vue?vue&type=template&id=4c963bcc&\"\nimport script from \"./upload.vue?vue&type=script&lang=js&\"\nexport * from \"./upload.vue?vue&type=script&lang=js&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","import Vue from 'vue'\nimport Upload from './upload.vue'\n\n$(document).ready(() => {\n $(\"#upload-form\").each( (_, div) => {\n new Vue({\n el: div,\n render: h => h(Upload, { props: { autocompleteData: $(div).data(\"autocomplete-data\") } })\n })\n });\n})\n\n\n","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('b-modal',{attrs:{\"id\":\"share-modal\",\"height\":\"auto\",\"hide-header\":true,\"hide-footer\":true,\"size\":\"lg\",\"body-class\":\"share-modal\",\"no-close-on-backdrop\":_vm.shareChoice}},[_c('div',{staticClass:\"share-modal-title\"},[(_vm.shareChoiceData)?_c('span',[_vm._v(\"\\n What shall we share?\\n \")]):_c('span',[_vm._v(\"\\n Sharing \"+_vm._s(_vm.shareObjectTypeData)+\": \\\"\"+_vm._s(_vm.shareTitleData)+\"\\\"\\n \")]),_vm._v(\" \"),_c('img',{staticClass:\"d-none d-sm-inline-block\",attrs:{\"src\":\"/images/trumpet-white.svg\",\"id\":\"share-trumpet\"}}),_vm._v(\" \"),_c('button',{staticClass:\"close share-modal-close\",attrs:{\"type\":\"button\",\"aria-label\":\"Close\"},on:{\"click\":function($event){return _vm.closeModal()}}},[_c('span',{attrs:{\"aria-hidden\":\"true\"}},[_vm._v(\"×\")])])]),_vm._v(\" \"),(_vm.shareChoiceData)?_c('div',{staticClass:\"p-2\"},[_c('share-choice',{on:{\"choice\":_vm.onShareChoice}})],1):_c('div',{staticClass:\"p-2\"},[_c('b-tabs',{attrs:{\"content-class\":\"mt-3\"},on:{\"input\":_vm.tabChanged}},[_c('b-tab',{attrs:{\"title\":\"Copy Link\",\"active\":\"\"}},[_c('div',{staticClass:\"container-fluid\"},[_c('div',{staticClass:\"row\"},[_c('div',{staticClass:\"col\"},[_vm._v(\"\\n Copy and paste this link to share via text, whatsapp, facebook..\\n \")])]),_vm._v(\" \"),_c('div',{staticClass:\"row py-4\"},[_c('div',{staticClass:\"col-12 col-sm-8\",staticStyle:{\"align-self\":\"center\"}},[_c('input',{ref:\"shareURL\",staticStyle:{\"width\":\"100%\"},attrs:{\"type\":\"text\",\"readonly\":\"\"},domProps:{\"value\":_vm.shareURL},on:{\"click\":function($event){return _vm.shareURLClick($event)}}})]),_vm._v(\" \"),_c('div',{staticClass:\"col-auto mt-2 mt-sm-0\"},[_c('button',{staticClass:\"btn btn-primary sharelink-copy\",attrs:{\"type\":\"button\",\"aria-label\":\"Copy\"},on:{\"click\":function($event){return _vm.copyURLClick()}}},[_vm._v(\"Copy\")])])])])]),_vm._v(\" \"),_c('b-tab',{attrs:{\"title\":\"Email\"}},[_c('div',{staticClass:\"container-fluid\"},[_c('div',{staticClass:\"form-group row\"},[_c('label',{staticClass:\"col-12 col-sm-4 col-form-label\",attrs:{\"for\":\"email\"}},[_vm._v(\"Email addresses:\")]),_vm._v(\" \"),_c('div',{staticClass:\"col-12 col-sm-7\"},[_c('vue-tags-input',{attrs:{\"add-on-key\":[',', ' ', 13],\"placeholder\":\"Add email\",\"tags\":_vm.emails,\"autocomplete-items\":_vm.autocompleteEmails},on:{\"tags-changed\":function (newTags) { return _vm.emails = newTags; }},model:{value:(_vm.email),callback:function ($$v) {_vm.email=$$v},expression:\"email\"}}),_vm._v(\" \"),_c('ErrorList',{attrs:{\"field\":\"email\",\"errors\":_vm.errors['email']}})],1)]),_vm._v(\" \"),_c('div',{staticClass:\"row\"},[_c('label',{staticClass:\"col-12 col-sm-4 col-form-label\",attrs:{\"for\":\"message\"}},[_vm._v(\"Message:\")]),_vm._v(\" \"),_c('div',{staticClass:\"col-12 col-sm-7\"},[_c('textarea',{directives:[{name:\"model\",rawName:\"v-model\",value:(_vm.message),expression:\"message\"}],staticClass:\"form-control\",attrs:{\"rows\":\"5\"},domProps:{\"value\":(_vm.message)},on:{\"input\":function($event){if($event.target.composing){ return; }_vm.message=$event.target.value}}})])]),_vm._v(\" \"),_c('div',{staticClass:\"form-group row py-2\"},[_c('div',{staticClass:\"offset-sm-4 col-auto\"},[_c('button',{staticClass:\"btn btn-primary\",attrs:{\"type\":\"button\",\"disabled\":_vm.state != 'pending'},on:{\"click\":function($event){return _vm.share()}}},[(_vm.state == 'sharing')?_c('span',[_c('span',{staticClass:\"spinner-border spinner-border-sm\",attrs:{\"role\":\"status\",\"aria-hidden\":\"true\"}}),_vm._v(\"\\n Share\\n \")]):(_vm.state == 'sent')?_c('span',[_c('img',{staticStyle:{\"height\":\"1em\",\"width\":\"1em\",\"margin-right\":\"5px\"},attrs:{\"src\":\"/images/thumbs_up.svg\"}}),_vm._v(\"sent!\\n \")]):_c('span',[_vm._v(\"\\n Share\\n \")])])])])])])],1)],1)])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\n
\n
\n
{{ field }}: {{ err }}
\n
\n
\n\n\n","import mod from \"-!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-4[0].rules[0].use[0]!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./error_list.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-4[0].rules[0].use[0]!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./error_list.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./error_list.vue?vue&type=template&id=2ebaca22&\"\nimport script from \"./error_list.vue?vue&type=script&lang=js&\"\nexport * from \"./error_list.vue?vue&type=script&lang=js&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:\"invalid-feedback\"},[_c('ul',_vm._l((_vm.errors),function(err){return _c('li',{staticClass:\"text-danger\"},[_vm._v(_vm._s(_vm.field)+\": \"+_vm._s(err))])}),0)])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\n
\n
\n \n \n \n {{ option.label }}\n \n \n \n
\n
\n Sharing an artist will allow people to hear any mixes uploaded by this artist in the future.\n
\n
\n\n\n\n","import mod from \"-!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-4[0].rules[0].use[0]!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./share_choice.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-4[0].rules[0].use[0]!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./share_choice.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./share_choice.vue?vue&type=template&id=3b466828&\"\nimport script from \"./share_choice.vue?vue&type=script&lang=js&\"\nexport * from \"./share_choice.vue?vue&type=script&lang=js&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","import mod from \"-!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-4[0].rules[0].use[0]!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./share_modal.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-4[0].rules[0].use[0]!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./share_modal.vue?vue&type=script&lang=js&\"","\n \n
\n \n What shall we share?\n \n \n Sharing {{ shareObjectTypeData }}: \"{{ shareTitleData }}\"\n \n \n \n
\n
\n \n
\n
\n \n \n
\n
\n
\n Copy and paste this link to share via text, whatsapp, facebook..\n
\n
\n
\n
\n \n
\n
\n \n
\n
\n
\n \n \n
\n
\n \n
\n emails = newTags\"\n />\n \n
\n
\n
\n \n
\n \n
\n
\n
\n
\n \n
\n
\n
\n \n \n
\n \n\n\n\n\n\n","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:\"p-3\"},[_c('div',{staticClass:\"d-flex\"},[_c('vue-select',{staticClass:\"flex-grow-1 mr-2\",attrs:{\"options\":_vm.choices,\"placeholder\":\"Choose an item to share...\"},scopedSlots:_vm._u([{key:\"option\",fn:function(option){return [_c('span',{staticClass:\"fa\",class:option.icon}),_vm._v(\"\\n \"+_vm._s(option.label)+\"\\n \")]}}]),model:{value:(_vm.choice),callback:function ($$v) {_vm.choice=$$v},expression:\"choice\"}}),_vm._v(\" \"),_c('button',{staticClass:\"btn btn-primary btn-sm\",attrs:{\"disabled\":!_vm.choice},on:{\"click\":function($event){$event.preventDefault();return _vm.$emit('choice', _vm.choice)}}},[_vm._v(\"Next\")])],1),_vm._v(\" \"),(_vm.choice && _vm.choice.objectType == 'artist')?_c('div',{staticClass:\"mt-3 text-dark\"},[_vm._v(\"\\n Sharing an artist will allow people to hear any mixes uploaded by this artist in the future.\\n \")]):_vm._e()])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","import { render, staticRenderFns } from \"./share_modal.vue?vue&type=template&id=4976349f&\"\nimport script from \"./share_modal.vue?vue&type=script&lang=js&\"\nexport * from \"./share_modal.vue?vue&type=script&lang=js&\"\nimport style0 from \"./share_modal.vue?vue&type=style&index=0&lang=css&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","import Vue from 'vue'\n\nimport ShareModal from './share_modal.vue'\nlet ShareModalVue = Vue.extend(ShareModal)\n\n$(document).ready(() => {\n if ( document.getElementById(\"share-modal\") ) {\n window.shareModal = new ShareModalVue()\n window.shareModal.$mount('#share-modal')\n }\n})\n\n","\n \n
\n Add track to playlist\n \n \n
\n
\n
\n
\n \n
\n
\n \n
\n
\n
\n
\n \n
\n
\n \n
\n
\n
\n
\n \n
\n
\n \n
\n
\n
\n
\n \n
\n
\n
\n
\n {{ message }}\n
\n
\n
\n \n\n\n\n\n","import mod from \"-!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-4[0].rules[0].use[0]!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./add_to_playlist_modal.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-4[0].rules[0].use[0]!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./add_to_playlist_modal.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./add_to_playlist_modal.vue?vue&type=template&id=ff761b60&\"\nimport script from \"./add_to_playlist_modal.vue?vue&type=script&lang=js&\"\nexport * from \"./add_to_playlist_modal.vue?vue&type=script&lang=js&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('b-modal',{attrs:{\"id\":\"add-to-playlist-modal\",\"height\":\"auto\",\"hide-header\":true,\"hide-footer\":true,\"size\":\"lg\",\"body-class\":\"add-to-playlist-modal\"}},[_c('div',{staticClass:\"share-modal-title\"},[_vm._v(\"\\n Add track to playlist\\n \"),_c('img',{staticClass:\"d-none d-sm-inline-block\",attrs:{\"src\":\"/images/trumpet-white.svg\",\"id\":\"share-trumpet\"}}),_vm._v(\" \"),_c('button',{staticClass:\"close share-modal-close\",attrs:{\"type\":\"button\",\"aria-label\":\"Close\"},on:{\"click\":function($event){return _vm.closeModal()}}},[_c('span',{attrs:{\"aria-hidden\":\"true\"}},[_vm._v(\"×\")])])]),_vm._v(\" \"),_c('div',{staticClass:\"container-fluid pt-4 playlist-add-container\"},[_c('div',{staticClass:\"form-group row\"},[_c('div',{staticClass:\"col-sm-4\"},[_c('label',{staticClass:\"col-form-label\",attrs:{\"for\":\"what\"}},[_vm._v(\"What to add:\")])]),_vm._v(\" \"),_c('div',{staticClass:\"col-sm-8\"},[_c('select',{directives:[{name:\"model\",rawName:\"v-model\",value:(_vm.what),expression:\"what\"}],staticClass:\"form-control\",on:{\"change\":function($event){var $$selectedVal = Array.prototype.filter.call($event.target.options,function(o){return o.selected}).map(function(o){var val = \"_value\" in o ? o._value : o.value;return val}); _vm.what=$event.target.multiple ? $$selectedVal : $$selectedVal[0]}}},[_c('option',{attrs:{\"value\":\"latest\"}},[_vm._v(\"Latest version of \\\"\"+_vm._s(_vm.songName)+\"\\\"\")]),_vm._v(\" \"),_c('option',{domProps:{\"value\":_vm.mixId}},[_vm._v(\"Version #\"+_vm._s(_vm.mixVersion)+\" of \\\"\"+_vm._s(_vm.songName)+\"\\\"\")])])])]),_vm._v(\" \"),_c('div',{staticClass:\"form-group row\"},[_c('div',{staticClass:\"col-sm-4\"},[_c('label',{staticClass:\"col-form-label\",attrs:{\"for\":\"playlist\"}},[_vm._v(\"Playlist:\")])]),_vm._v(\" \"),_c('div',{staticClass:\"col-sm-8\"},[_c('select',{directives:[{name:\"model\",rawName:\"v-model\",value:(_vm.playlist),expression:\"playlist\"}],staticClass:\"form-control\",on:{\"change\":function($event){var $$selectedVal = Array.prototype.filter.call($event.target.options,function(o){return o.selected}).map(function(o){var val = \"_value\" in o ? o._value : o.value;return val}); _vm.playlist=$event.target.multiple ? $$selectedVal : $$selectedVal[0]}}},[_vm._l((_vm.playlists),function(p){return _c('option',{key:p.id,domProps:{\"value\":p.id}},[_vm._v(_vm._s(p.name))])}),_vm._v(\" \"),_c('option',{attrs:{\"value\":\"_new\"}},[_vm._v(\"\")])],2)])]),_vm._v(\" \"),(_vm.playlist == '_new')?_c('div',{staticClass:\"form-group row\"},[_c('div',{staticClass:\"col-sm-4\"},[_c('label',{staticClass:\"col-form-label\",attrs:{\"for\":\"playlist_name\"}},[_vm._v(\"Playlist Name:\")])]),_vm._v(\" \"),_c('div',{staticClass:\"col-sm-8\"},[_c('input',{directives:[{name:\"model\",rawName:\"v-model\",value:(_vm.playlistName),expression:\"playlistName\"}],staticClass:\"form-control\",attrs:{\"type\":\"text\",\"id\":\"playlist_name\",\"placeholder\":\"playlist name...\"},domProps:{\"value\":(_vm.playlistName)},on:{\"input\":function($event){if($event.target.composing){ return; }_vm.playlistName=$event.target.value}}})])]):_vm._e(),_vm._v(\" \"),_c('div',{staticClass:\"form-group row\"},[_c('div',{staticClass:\"col\"},[_c('button',{staticClass:\"btn btn-primary\",attrs:{\"type\":\"button\",\"disabled\":(_vm.playlist == '_new' && !_vm.playlistName) || _vm.saving,\"aria-label\":\"Add Track\"},on:{\"click\":_vm.save}},[(_vm.saving)?_c('span',[_vm._v(\"...\")]):(_vm.playlist == '_new')?_c('span',[_vm._v(\"\\n Create Playlist\\n \")]):_c('span',[_vm._v(\"\\n Add Track to Playlist\\n \")])])])]),_vm._v(\" \"),_c('div',{staticClass:\"row\"},[_c('div',{staticClass:\"col pb-3\"},[_vm._v(\"\\n \"+_vm._s(_vm.message)+\"\\n \")])])])])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","import Vue from 'vue'\n\nimport AddToPlaylistModal from './add_to_playlist_modal.vue'\nconst AddToPlaylistVue = Vue.extend(AddToPlaylistModal)\n\n$(document).ready(() => {\n const globalData = $(\"#add-to-playlist-modal\").data() \n if ( document.getElementById(\"add-to-playlist-modal\") ) {\n window.addToPlaylistModal = new AddToPlaylistVue()\n window.addToPlaylistModal.$mount('#add-to-playlist-modal')\n }\n\n $(\".add-to-playlist-link\").click((e) => {\n e.preventDefault()\n let modal = window.addToPlaylistModal\n let data = $(e.target).closest('a').data();\n modal._props = { ...data, ...globalData }\n modal.showModal(data['what'])\n });\n})\n\n","\n \n \n \n \n\n\n\n","import mod from \"-!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-4[0].rules[0].use[0]!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./artist_autocomplete.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../../node_modules/babel-loader/lib/index.js??clonedRuleSet-4[0].rules[0].use[0]!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./artist_autocomplete.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./artist_autocomplete.vue?vue&type=template&id=0863dc40&\"\nimport script from \"./artist_autocomplete.vue?vue&type=script&lang=js&\"\nexport * from \"./artist_autocomplete.vue?vue&type=script&lang=js&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('span',[_c('autocomplete',{ref:\"autocomplete\",attrs:{\"search\":_vm.searchArtists,\"defaultValue\":_vm.artist},on:{\"input\":function($event){return _vm.update($event.target.value)},\"submit\":_vm.update}}),_vm._v(\" \"),_c('input',{attrs:{\"type\":\"hidden\",\"name\":_vm.elName},domProps:{\"value\":_vm.myArtist}})],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","import Vue from 'vue'\nimport ArtistAutocomplete from './artist_autocomplete.vue'\n\nconst classes = { ArtistAutocomplete }\n\n$(document).ready(() => {\n $(\".vue\").each( (_, el) => {\n const data = $(el).data()\n const vueClass = classes[data.vueClass]\n\n new Vue({\n el: el,\n render: h => h(vueClass, { props: data } )\n })\n });\n})\n\n","import Vue from 'vue'\n\nimport { TabsPlugin, ModalPlugin, DropdownPlugin, PopoverPlugin } from 'bootstrap-vue'\nVue.use(TabsPlugin)\nVue.use(ModalPlugin)\nVue.use(DropdownPlugin)\nVue.use(PopoverPlugin)\n\nimport vSelect from 'vue-select'\nVue.component('v-select', vSelect)\n\nimport VueTagsInput from '@johmun/vue-tags-input'\nVue.use(VueTagsInput)\n\nimport \"mixmastermiles/note\";\nimport \"mixmastermiles/upload\";\nimport \"mixmastermiles/share_modal\";\nimport \"mixmastermiles/add_to_playlist_modal\";\nimport \"mixmastermiles/ios_install\";\nimport \"mixmastermiles/vue\";\n\nimport setupSharing from \"mix_player/sharing.js\";\n\nimport SVGInject from '@iconfu/svg-inject'\nimport { post_csrf } from '../utils/csrf'\n\nwindow.SVGInject = SVGInject\n\n\n$( document ).ready(() => {\n const selectArtist = $(\"#select-artist\");\n selectArtist.change( (ev) => {\n let uri = \"\";\n\n if ( selectArtist.val() != \"all\" ) {\n uri = \"/artists/\" + selectArtist.val();\n }\n\n let path = window.location.pathname\n if ( path.match(/latest/)) {\n uri = uri + \"/latest\"\n }\n\n window.location.pathname = uri;\n });\n\n let artistShareLink = $(\".artist-share-link\")[0];\n if ( artistShareLink ) {\n let artistID = $(artistShareLink).data(\"artist-id\")\n let artistName = $(artistShareLink).data(\"artist-name\")\n setupSharing($(\".artist-share-link\"), '/share/artist/' + artistID + '.json', artistName, \"artist\");\n }\n \n let playlistShareLink = $(\".playlist-share-link\")[0];\n if ( playlistShareLink ) {\n let playlistID = $(playlistShareLink).data(\"playlist-id\")\n let playlistName = $(playlistShareLink).data(\"playlist-name\")\n setupSharing($(\".playlist-share-link\"), '/share/playlist/' + playlistID + '.json', playlistName, \"playlist\");\n }\n\n\n $(\".footer-share-link\").click(e => {\n let modal = window.shareModal\n modal.shareChoice = true\n modal.showModal()\n e.preventDefault()\n })\n\n if ( window.innerWidth < 500 ) {\n $(\".remove-on-mobile\").each((i, el) => { $(el).removeClass(\"carousel-item\") ; $(el).css(\"display\", \"none\") })\n }\n\n $(\"#nav-toggle\").click(() => { \n $(\".sidebar\").toggleClass('d-none');\n })\n\n $(\"#sidebar-more-artist\").click(() => { \n $(\"#sidebar-more-artist\").hide();\n $(\".artist-hidden-more\").toggleClass('artist-hidden-more');\n })\n\n $('.toast').toast('show');\n\n\n if ( /\\/playlists\\/\\d+/.test(window.location.pathname) ) {\n $(\".mix-list\").sortable({\n handle: \".drag-handle\",\n stop: (event) => { \n const newItemList = $(\".mix-list\").children().toArray().map(d => $(d).data().playlistItemId)\n post_csrf(window.location.pathname + \"/reorder\", { playlist_item_ids: newItemList })\n }\n })\n }\n\n})\n\n","let iosCopyToClipboard = function(el) {\n var oldContentEditable = el.contentEditable,\n oldReadOnly = el.readOnly,\n range = document.createRange();\n\n el.contentEditable = true;\n el.readOnly = false;\n range.selectNodeContents(el);\n\n var s = window.getSelection();\n s.removeAllRanges();\n s.addRange(range);\n\n el.setSelectionRange(0, 999999); // A big number, to cover anything that could be inside the element.\n\n el.contentEditable = oldContentEditable;\n el.readOnly = oldReadOnly;\n\n document.execCommand('copy');\n}\n\n$(document).ready(() => {\n $(\".ios-install-link\").click((ev) => {\n ev.preventDefault()\n\n $(\"#ios_copy_el\").each((i, el) => {\n iosCopyToClipboard(el)\n })\n\n document.cookie = \"appInstalled=true\"\n window.location = \"https://apps.apple.com/us/app/mix-master-miles/id1516224866\"\n })\n\n $(\"#ios-close-install\").click((ev) => {\n ev.preventDefault()\n document.cookie = \"appInstalled=true\"\n $(\".ios-install-banner\").hide()\n })\n})\n","// This file is automatically compiled by Webpack, along with any other files\n// present in this directory. You're encouraged to place your actual application logic in\n// a relevant structure within app/javascript and only use these pack files to reference\n// that code so it'll be compiled.\n\nrequire(\"@rails/ujs\").start()\nrequire(\"channels\")\n\nimport 'bootstrap/js/src/util.js';\nimport 'bootstrap/js/src/dropdown.js';\nimport 'bootstrap/js/src/carousel.js';\nimport 'bootstrap/js/src/toast.js';\nimport 'webpack-jquery-ui/sortable'\n\nimport bsCustomFileInput from 'bs-custom-file-input'\n\n\n$( document ).ready(() => bsCustomFileInput.init())\n\nrequire(\"waveforms\")\nrequire(\"mixmastermiles\")\n\nimport LocalTime from \"local-time\"\nLocalTime.start()\n\n// Uncomment to copy all static images under ../images to the output folder and reference\n// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)\n// or the `imagePath` JavaScript helper below.\n//\n// const images = require.context('../images', true)\n// const imagePath = (name) => images(name, true)\n","export default function fetch_csrf(url, options) {\n const token = document.querySelector('meta[name=csrf-token]').content;\n if ( !options )\n options = {};\n if ( !options.headers )\n options.headers = {};\n\n options.headers['X-CSRF-Token'] = token;\n return fetch(url, options);\n}\n\nexport function post_csrf(url, data, options) { \n const postOptions = { \n method: \"post\",\n body: JSON.stringify(data),\n headers: { 'Content-type': 'application/json' },\n ...(options || {})\n }\n return fetch_csrf(url, postOptions)\n}\n","export default function(time) {\n let minutes = Math.floor(time / 60)\n let seconds = Math.floor(time - (minutes * 60))\n return minutes.toFixed() + \":\" + seconds.toFixed().padStart(2, '0')\n}\n","/**\n * (Single) Region plugin class\n *\n * Must be turned into an observer before instantiating. This is done in\n * `RegionsPlugin` (main plugin class).\n *\n * @extends {Observer}\n */\nclass Region {\n constructor(params, ws) {\n this.handlers = {};\n this.wavesurfer = ws;\n this.wrapper = ws.drawer.wrapper;\n this.util = ws.util;\n this.style = this.util.style;\n\n this.id = params.id == null ? ws.util.getId() : params.id;\n this.start = Number(params.start) || 0;\n this.end =\n params.end == null\n ? // small marker-like region\n this.start +\n (4 / this.wrapper.scrollWidth) * this.wavesurfer.getDuration()\n : Number(params.end);\n this.resize =\n params.resize === undefined ? true : Boolean(params.resize);\n this.drag = params.drag === undefined ? true : Boolean(params.drag);\n // reflect resize and drag state of region for region-updated listener\n this.isResizing = false;\n this.isDragging = false;\n this.loop = Boolean(params.loop);\n this.color = params.color || 'rgba(0, 0, 0, 0.1)';\n this.data = params.data || {};\n this.attributes = params.attributes || {};\n\n this.maxLength = params.maxLength;\n this.minLength = params.minLength;\n this._onRedraw = () => this.updateRender();\n\n this.scroll = params.scroll !== false && ws.params.scrollParent;\n this.scrollSpeed = params.scrollSpeed || 1;\n this.scrollThreshold = params.scrollThreshold || 10;\n\n this.bindInOut();\n this.render();\n this.wavesurfer.on('zoom', this._onRedraw);\n this.wavesurfer.on('redraw', this._onRedraw);\n this.wavesurfer.fireEvent('region-created', this);\n }\n\n /* Update region params. */\n update(params) {\n if (null != params.start) {\n this.start = Number(params.start);\n }\n if (null != params.end) {\n this.end = Number(params.end);\n }\n if (null != params.loop) {\n this.loop = Boolean(params.loop);\n }\n if (null != params.color) {\n this.color = params.color;\n }\n if (null != params.data) {\n this.data = params.data;\n }\n if (null != params.resize) {\n this.resize = Boolean(params.resize);\n }\n if (null != params.drag) {\n this.drag = Boolean(params.drag);\n }\n if (null != params.maxLength) {\n this.maxLength = Number(params.maxLength);\n }\n if (null != params.minLength) {\n this.minLength = Number(params.minLength);\n }\n if (null != params.attributes) {\n this.attributes = params.attributes;\n }\n\n this.updateRender();\n this.fireEvent('update');\n this.wavesurfer.fireEvent('region-updated', this);\n }\n\n /* Remove a single region. */\n remove() {\n if (this.element) {\n this.wrapper.removeChild(this.element);\n this.element = null;\n this.fireEvent('remove');\n this.wavesurfer.un('zoom', this._onRedraw);\n this.wavesurfer.un('redraw', this._onRedraw);\n this.wavesurfer.fireEvent('region-removed', this);\n }\n }\n\n /* Play the audio region. */\n play(start) {\n const s = start || this.start;\n this.wavesurfer.play(s, this.end);\n this.fireEvent('play');\n this.wavesurfer.fireEvent('region-play', this);\n }\n\n /* Play the region in loop. */\n playLoop(start) {\n this.play(start);\n this.once('out', () => this.playLoop());\n }\n\n /* Render a region as a DOM element. */\n render() {\n const regionEl = document.createElement('region');\n regionEl.className = 'wavesurfer-region';\n regionEl.title = this.formatTime(this.start, this.end);\n regionEl.setAttribute('data-id', this.id);\n\n for (const attrname in this.attributes) {\n regionEl.setAttribute(\n 'data-region-' + attrname,\n this.attributes[attrname]\n );\n }\n\n this.style(regionEl, {\n position: 'absolute',\n zIndex: 2,\n height: '100%',\n top: '0px'\n });\n\n /* Resize handles */\n if (this.resize) {\n const handleLeft = regionEl.appendChild(\n document.createElement('handle')\n );\n const handleRight = regionEl.appendChild(\n document.createElement('handle')\n );\n handleLeft.className = 'wavesurfer-handle wavesurfer-handle-start';\n handleRight.className = 'wavesurfer-handle wavesurfer-handle-end';\n const css = {\n cursor: 'col-resize',\n position: 'absolute',\n top: '0px',\n width: '5px',\n maxWidth: '5px',\n height: '100%'\n };\n this.style(handleLeft, css);\n this.style(handleLeft, {\n left: '0px'\n });\n this.style(handleRight, css);\n this.style(handleRight, {\n right: '0px'\n });\n }\n\n\n\n this.element = this.wrapper.appendChild(regionEl);\n this.updateRender();\n this.bindEvents(regionEl);\n }\n\n formatTime(start, end) {\n return (start == end ? [start] : [start, end])\n .map(time =>\n [\n Math.floor((time % 3600) / 60), // minutes\n ('00' + Math.floor(time % 60)).slice(-2) // seconds\n ].join(':')\n )\n .join('-');\n }\n\n getWidth() {\n return this.wavesurfer.drawer.width / this.wavesurfer.params.pixelRatio;\n }\n\n /* Update element's position, width, color. */\n updateRender() {\n // duration varies during loading process, so don't overwrite important data\n const dur = this.wavesurfer.getDuration();\n const width = this.getWidth();\n\n var startLimited = this.start;\n var endLimited = this.end;\n if (startLimited < 0) {\n startLimited = 0;\n endLimited = endLimited - startLimited;\n }\n if (endLimited > dur) {\n endLimited = dur;\n startLimited = dur - (endLimited - startLimited);\n }\n\n if (this.minLength != null) {\n endLimited = Math.max(startLimited + this.minLength, endLimited);\n }\n\n if (this.maxLength != null) {\n endLimited = Math.min(startLimited + this.maxLength, endLimited);\n }\n\n if (this.element != null) {\n // Calculate the left and width values of the region such that\n // no gaps appear between regions.\n const left = Math.round((startLimited / dur) * width);\n const regionWidth = Math.round((endLimited / dur) * width) - left;\n\n this.style(this.element, {\n left: left + 'px',\n width: regionWidth + 'px',\n backgroundColor: this.color,\n cursor: this.drag ? 'move' : 'default'\n });\n\n for (const attrname in this.attributes) {\n this.element.setAttribute(\n 'data-region-' + attrname,\n this.attributes[attrname]\n );\n }\n\n this.element.title = this.formatTime(this.start, this.end);\n }\n }\n\n /* Bind audio events. */\n bindInOut() {\n this.firedIn = false;\n this.firedOut = false;\n\n const onProcess = time => {\n let start = Math.round(this.start * 10) / 10;\n let end = Math.round(this.end * 10) / 10;\n time = Math.round(time * 10) / 10;\n\n if (\n !this.firedOut &&\n this.firedIn &&\n (start > time || end <= time)\n ) {\n this.firedOut = true;\n this.firedIn = false;\n this.fireEvent('out');\n this.wavesurfer.fireEvent('region-out', this);\n }\n if (!this.firedIn && start <= time && end > time) {\n this.firedIn = true;\n this.firedOut = false;\n this.fireEvent('in');\n this.wavesurfer.fireEvent('region-in', this);\n }\n };\n\n this.wavesurfer.backend.on('audioprocess', onProcess);\n\n this.on('remove', () => {\n this.wavesurfer.backend.un('audioprocess', onProcess);\n });\n\n /* Loop playback. */\n this.on('out', () => {\n if (this.loop) {\n this.wavesurfer.play(this.start);\n }\n });\n }\n\n /* Bind DOM events. */\n bindEvents() {\n this.element.addEventListener('mouseenter', e => {\n this.fireEvent('mouseenter', e);\n this.wavesurfer.fireEvent('region-mouseenter', this, e);\n });\n\n this.element.addEventListener('mouseleave', e => {\n this.fireEvent('mouseleave', e);\n this.wavesurfer.fireEvent('region-mouseleave', this, e);\n });\n\n this.element.addEventListener('click', e => {\n e.preventDefault();\n this.fireEvent('click', e);\n this.wavesurfer.fireEvent('region-click', this, e);\n });\n\n this.element.addEventListener('dblclick', e => {\n e.stopPropagation();\n e.preventDefault();\n this.fireEvent('dblclick', e);\n this.wavesurfer.fireEvent('region-dblclick', this, e);\n });\n\n /* Drag or resize on mousemove. */\n (this.drag || this.resize) &&\n (() => {\n const container = this.wavesurfer.drawer.container;\n const scrollSpeed = this.scrollSpeed;\n const scrollThreshold = this.scrollThreshold;\n let startTime;\n let touchId;\n let drag;\n let maxScroll;\n let resize;\n let updated = false;\n let scrollDirection;\n let wrapperRect;\n\n // Scroll when the user is dragging within the threshold\n const edgeScroll = e => {\n const duration = this.wavesurfer.getDuration();\n if (!scrollDirection || (!drag && !resize)) {\n return;\n }\n\n // Update scroll position\n let scrollLeft =\n this.wrapper.scrollLeft + scrollSpeed * scrollDirection;\n this.wrapper.scrollLeft = scrollLeft = Math.min(\n maxScroll,\n Math.max(0, scrollLeft)\n );\n\n // Get the currently selected time according to the mouse position\n const time = this.wavesurfer.regions.util.getRegionSnapToGridValue(\n this.wavesurfer.drawer.handleEvent(e) * duration\n );\n const delta = time - startTime;\n startTime = time;\n\n // Continue dragging or resizing\n drag ? this.onDrag(delta) : this.onResize(delta, resize);\n\n // Repeat\n window.requestAnimationFrame(() => {\n edgeScroll(e);\n });\n };\n\n const onDown = e => {\n const duration = this.wavesurfer.getDuration();\n if (e.touches && e.touches.length > 1) {\n return;\n }\n touchId = e.targetTouches\n ? e.targetTouches[0].identifier\n : null;\n\n // stop the event propagation, if this region is resizable or draggable\n // and the event is therefore handled here.\n if (this.drag || this.resize) {\n e.stopPropagation();\n }\n\n // Store the selected startTime we begun dragging or resizing\n startTime = this.wavesurfer.regions.util.getRegionSnapToGridValue(\n this.wavesurfer.drawer.handleEvent(e, true) * duration\n );\n\n // Store for scroll calculations\n maxScroll =\n this.wrapper.scrollWidth - this.wrapper.clientWidth;\n wrapperRect = this.wrapper.getBoundingClientRect();\n\n this.isResizing = false;\n this.isDragging = false;\n if (e.target.tagName.toLowerCase() === 'handle') {\n this.isResizing = true;\n if (\n e.target.classList.contains(\n 'wavesurfer-handle-start'\n )\n ) {\n resize = 'start';\n } else {\n resize = 'end';\n }\n } else {\n this.isDragging = true;\n drag = true;\n resize = false;\n }\n };\n const onUp = e => {\n if (e.touches && e.touches.length > 1) {\n return;\n }\n\n if (drag || resize) {\n this.isDragging = false;\n this.isResizing = false;\n drag = false;\n scrollDirection = null;\n resize = false;\n }\n\n if (updated) {\n updated = false;\n this.util.preventClick();\n this.fireEvent('update-end', e);\n this.wavesurfer.fireEvent('region-update-end', this, e);\n }\n };\n const onMove = e => {\n const duration = this.wavesurfer.getDuration();\n\n if (e.touches && e.touches.length > 1) {\n return;\n }\n if (\n e.targetTouches &&\n e.targetTouches[0].identifier != touchId\n ) {\n return;\n }\n\n if (drag || resize) {\n const oldTime = startTime;\n const time = this.wavesurfer.regions.util.getRegionSnapToGridValue(\n this.wavesurfer.drawer.handleEvent(e) * duration\n );\n\n const delta = time - startTime;\n startTime = time;\n\n // Drag\n if (this.drag && drag) {\n updated = updated || !!delta;\n this.onDrag(delta);\n }\n\n // Resize\n if (this.resize && resize) {\n updated = updated || !!delta;\n this.onResize(delta, resize);\n }\n\n if (\n this.scroll &&\n container.clientWidth < this.wrapper.scrollWidth\n ) {\n if (drag) {\n // The threshold is not between the mouse and the container edge\n // but is between the region and the container edge\n const regionRect = this.element.getBoundingClientRect();\n let x = regionRect.left - wrapperRect.left;\n\n // Check direction\n if (time < oldTime && x >= 0) {\n scrollDirection = -1;\n } else if (\n time > oldTime &&\n x + regionRect.width <= wrapperRect.right\n ) {\n scrollDirection = 1;\n }\n\n // Check that we are still beyond the threshold\n if (\n (scrollDirection === -1 &&\n x > scrollThreshold) ||\n (scrollDirection === 1 &&\n x + regionRect.width <\n wrapperRect.right - scrollThreshold)\n ) {\n scrollDirection = null;\n }\n } else {\n // Mouse based threshold\n let x = e.clientX - wrapperRect.left;\n\n // Check direction\n if (x <= scrollThreshold) {\n scrollDirection = -1;\n } else if (\n x >=\n wrapperRect.right - scrollThreshold\n ) {\n scrollDirection = 1;\n } else {\n scrollDirection = null;\n }\n }\n\n scrollDirection && edgeScroll(e);\n }\n }\n };\n\n this.element.addEventListener('mousedown', onDown);\n this.element.addEventListener('touchstart', onDown);\n\n this.wrapper.addEventListener('mousemove', onMove);\n this.wrapper.addEventListener('touchmove', onMove);\n\n document.body.addEventListener('mouseup', onUp);\n document.body.addEventListener('touchend', onUp);\n\n this.on('remove', () => {\n document.body.removeEventListener('mouseup', onUp);\n document.body.removeEventListener('touchend', onUp);\n this.wrapper.removeEventListener('mousemove', onMove);\n this.wrapper.removeEventListener('touchmove', onMove);\n });\n\n this.wavesurfer.on('destroy', () => {\n document.body.removeEventListener('mouseup', onUp);\n document.body.removeEventListener('touchend', onUp);\n });\n })();\n }\n\n onDrag(delta) {\n const maxEnd = this.wavesurfer.getDuration();\n if (this.end + delta > maxEnd || this.start + delta < 0) {\n return;\n }\n\n this.update({\n start: this.start + delta,\n end: this.end + delta\n });\n }\n\n onResize(delta, direction) {\n if (direction === 'start') {\n this.update({\n start: Math.min(this.start + delta, this.end),\n end: Math.max(this.start + delta, this.end)\n });\n } else {\n this.update({\n start: Math.min(this.end + delta, this.start),\n end: Math.max(this.end + delta, this.start)\n });\n }\n }\n}\n\n/**\n * @typedef {Object} RegionsPluginParams\n * @property {?boolean} dragSelection Enable creating regions by dragging with\n * the mouse\n * @property {?RegionParams[]} regions Regions that should be added upon\n * initialisation\n * @property {number} slop=2 The sensitivity of the mouse dragging\n * @property {?number} snapToGridInterval Snap the regions to a grid of the specified multiples in seconds\n * @property {?number} snapToGridOffset Shift the snap-to-grid by the specified seconds. May also be negative.\n * @property {?boolean} deferInit Set to true to manually call\n * `initPlugin('regions')`\n */\n\n/**\n * @typedef {Object} RegionParams\n * @desc The parameters used to describe a region.\n * @example wavesurfer.addRegion(regionParams);\n * @property {string} id=→random The id of the region\n * @property {number} start=0 The start position of the region (in seconds).\n * @property {number} end=0 The end position of the region (in seconds).\n * @property {?boolean} loop Whether to loop the region when played back.\n * @property {boolean} drag=true Allow/disallow dragging the region.\n * @property {boolean} resize=true Allow/disallow resizing the region.\n * @property {string} [color='rgba(0, 0, 0, 0.1)'] HTML color code.\n */\n\n/**\n * Regions are visual overlays on waveform that can be used to play and loop\n * portions of audio. Regions can be dragged and resized.\n *\n * Visual customization is possible via CSS (using the selectors\n * `.wavesurfer-region` and `.wavesurfer-handle`).\n *\n * @implements {PluginClass}\n * @extends {Observer}\n *\n * @example\n * // es6\n * import RegionsPlugin from 'wavesurfer.regions.js';\n *\n * // commonjs\n * var RegionsPlugin = require('wavesurfer.regions.js');\n *\n * // if you are using