2019-08-24 03:06:57 +00:00
< template >
2019-09-02 11:02:29 +00:00
< div class = "page" >
2019-09-09 05:57:00 +00:00
< pw-section class = "yellow" label = "Import" ref = "import" >
2019-09-09 10:20:28 +00:00
< ul >
< li >
2019-09-17 08:13:12 +00:00
< button class = "icon" id = "show-modal" @ click = "showModal = true" >
Import cURL
< / button >
2019-09-09 10:20:28 +00:00
< / li >
< / ul >
2019-09-13 05:02:49 +00:00
< pw-modal v-if = "showModal" @close="showModal = false" >
2019-09-06 10:41:18 +00:00
< div slot = "header" >
2019-09-09 10:20:28 +00:00
< ul >
< li >
2019-09-12 05:49:16 +00:00
< div class = "flex-wrap" >
< h3 class = "title" > Import cURL < / h3 >
< div >
2019-09-13 05:02:49 +00:00
< button class = "icon" @click ="toggleModal" >
2019-09-17 08:13:12 +00:00
< svg xmlns = "http://www.w3.org/2000/svg" width = "16" height = "16" viewBox = "0 0 24 24" >
< path d = "M23.954 21.03l-9.184-9.095 9.092-9.174-2.832-2.807-9.09 9.179-9.176-9.088-2.81 2.81 9.186 9.105-9.095 9.184 2.81 2.81 9.112-9.192 9.18 9.1z" / >
2019-09-13 05:02:49 +00:00
< / svg >
< / button >
2019-09-12 05:49:16 +00:00
< / div >
< / div >
2019-09-09 10:20:28 +00:00
< / li >
< / ul >
2019-09-06 10:41:18 +00:00
< / div >
< div slot = "body" >
2019-09-09 10:20:28 +00:00
< ul >
< li >
2019-09-16 12:57:07 +00:00
< textarea id = "import-text" autofocus rows = "8" placeholder = "Enter cURL" > < / textarea >
2019-09-09 10:20:28 +00:00
< / li >
< / ul >
2019-09-06 10:41:18 +00:00
< / div >
< div slot = "footer" >
2019-09-09 10:20:28 +00:00
< ul >
< li >
2019-09-17 08:13:12 +00:00
< button class = "icon" @click ="handleImport" >
Import
< / button >
2019-09-09 10:20:28 +00:00
< / li >
< / ul >
2019-09-06 10:41:18 +00:00
< / div >
2019-09-13 05:02:49 +00:00
< / pw-modal >
2019-09-07 13:40:22 +00:00
< / pw-section >
< pw-section class = "blue" label = "Request" ref = "request" >
2019-09-02 11:02:29 +00:00
< ul >
< li >
< label for = "method" > Method < / label >
< select id = "method" v-model = "method" >
< option > GET < / option >
< option > HEAD < / option >
< option > POST < / option >
< option > PUT < / option >
< option > DELETE < / option >
< option > OPTIONS < / option >
< option > PATCH < / option >
< / select >
< / li >
< li >
< label for = "url" > URL < / label >
2019-09-16 12:57:07 +00:00
< input : class = "{ error: !isValidURL }" @ keyup.enter = " isValidURL ? sendRequest ( ) : null " id = "url" name = "url" type = "url" v-model = "url" >
2019-09-02 11:02:29 +00:00
< / li >
< li >
< label for = "path" > Path < / label >
2019-09-16 22:54:11 +00:00
< input @ keyup.enter = " isValidURL ? sendRequest ( ) : null " id = "path" name = "path" v-model = "path" @input="pathInputHandler" >
2019-09-02 11:02:29 +00:00
< / li >
2019-09-12 11:09:59 +00:00
< div class = "show-on-small-screen" >
< li >
< label class = "hide-on-small-screen" for = "copyRequest" > & nbsp ; < / label >
< button class = "icon" @click ="copyRequest" id = "copyRequest" ref = "copyRequest" :disabled = "!isValidURL" >
2019-09-17 08:13:12 +00:00
< svg xmlns = "http://www.w3.org/2000/svg" width = "18" height = "18" viewBox = "0 0 24 24" >
< path d = "M19.647 15.247c-1.278 0-2.429.551-3.225 1.429l-7.788-3.846c.062-.343.079-.64.067-.942l8.058-4.231c.769.682 1.78 1.097 2.889 1.097 2.404-.001 4.352-1.949 4.352-4.353s-1.948-4.353-4.353-4.353-4.353 1.949-4.353 4.353c0 .18.012.356.033.53l-7.828 4.111c-.793-.829-1.908-1.347-3.146-1.347-2.405 0-4.353 1.949-4.353 4.353s1.948 4.353 4.353 4.353c1.013 0 1.943-.347 2.684-.927l8.26 4.078-.001.047c0 2.404 1.948 4.353 4.353 4.353s4.351-1.949 4.351-4.353-1.948-4.352-4.353-4.352z" / >
2019-09-12 11:09:59 +00:00
< / svg >
2019-09-17 08:13:12 +00:00
< span > Permalink < / span >
2019-09-12 11:09:59 +00:00
< / button >
< / li >
< li >
< label class = "hide-on-small-screen" for = "code" > & nbsp ; < / label >
2019-09-16 12:57:07 +00:00
< button class = "icon" id = "code" v -on : click = "isHidden = !isHidden" :disabled = "!isValidURL" >
2019-09-12 11:09:59 +00:00
< svg xmlns = "http://www.w3.org/2000/svg" width = "24" height = "24" viewBox = "0 0 24 24" v-if = "isHidden" >
2019-09-17 08:13:12 +00:00
< path d = "M15 12c0 1.654-1.346 3-3 3s-3-1.346-3-3 1.346-3 3-3 3 1.346 3 3zm9-.449s-4.252 8.449-11.985 8.449c-7.18 0-12.015-8.449-12.015-8.449s4.446-7.551 12.015-7.551c7.694 0 11.985 7.551 11.985 7.551zm-7 .449c0-2.757-2.243-5-5-5s-5 2.243-5 5 2.243 5 5 5 5-2.243 5-5z" / >
2019-09-12 11:09:59 +00:00
< / svg >
< svg xmlns = "http://www.w3.org/2000/svg" width = "24" height = "24" viewBox = "0 0 24 24" v-if = "!isHidden" >
2019-09-17 08:13:12 +00:00
< path d = "M11.885 14.988l3.104-3.098.011.11c0 1.654-1.346 3-3 3l-.115-.012zm8.048-8.032l-3.274 3.268c.212.554.341 1.149.341 1.776 0 2.757-2.243 5-5 5-.631 0-1.229-.13-1.785-.344l-2.377 2.372c1.276.588 2.671.972 4.177.972 7.733 0 11.985-8.449 11.985-8.449s-1.415-2.478-4.067-4.595zm1.431-3.536l-18.619 18.58-1.382-1.422 3.455-3.447c-3.022-2.45-4.818-5.58-4.818-5.58s4.446-7.551 12.015-7.551c1.825 0 3.456.426 4.886 1.075l3.081-3.075 1.382 1.42zm-13.751 10.922l1.519-1.515c-.077-.264-.132-.538-.132-.827 0-1.654 1.346-3 3-3 .291 0 .567.055.833.134l1.518-1.515c-.704-.382-1.496-.619-2.351-.619-2.757 0-5 2.243-5 5 0 .852.235 1.641.613 2.342z" / >
2019-09-12 11:09:59 +00:00
< / svg >
< span > { { isHidden ? 'Show Code' : 'Hide Code' } } < / span >
< / button >
< / li >
< / div >
2019-09-02 11:02:29 +00:00
< li >
2019-09-16 12:57:07 +00:00
< label class = "hide-on-small-screen" for = "send" > & nbsp ; < / label >
< button :disabled = "!isValidURL" @click ="sendRequest" class = "show" id = "send" ref = "sendButton" >
2019-09-02 12:05:59 +00:00
Send < span id = "hidden-message" > Again < / span >
2019-09-12 09:01:17 +00:00
< span >
2019-09-17 08:13:12 +00:00
< svg xmlns = "http://www.w3.org/2000/svg" width = "18" height = "18" viewBox = "0 0 24 24" >
< path d = "M24 0l-6 22-8.129-7.239 7.802-8.234-10.458 7.227-7.215-1.754 24-12zm-15 16.668v7.332l3.258-4.431-3.258-2.901z" / >
2019-09-12 09:01:17 +00:00
< / svg >
< / span >
2019-09-02 12:05:59 +00:00
< / button >
2019-09-02 11:02:29 +00:00
< / li >
< / ul >
2019-09-20 13:04:42 +00:00
< div class = "blue" label = "Request Body" v-if = "method === 'POST' || method === 'PUT' || method === 'PATCH'" >
2019-09-02 11:02:29 +00:00
< ul >
< li >
2019-09-21 03:05:46 +00:00
< label for = "contentType" > Content Type < / label >
2019-09-02 11:02:29 +00:00
< autocomplete :source = "validContentTypes" :spellcheck = "false" v-model = "contentType" > Content Type
< / autocomplete >
< span >
< pw-toggle :on = "rawInput" @ change = "rawInput = !rawInput" >
2019-09-13 16:52:11 +00:00
Raw Input { { rawInput ? "Enabled" : "Disabled" } }
2019-09-02 11:02:29 +00:00
< / pw-toggle >
2019-08-25 21:10:17 +00:00
< / span >
2019-09-02 11:02:29 +00:00
< / li >
< / ul >
< div v-if = "!rawInput" >
2019-09-18 08:55:17 +00:00
< ul >
< li >
< label for = "reqParamList" > Parameter List < / label >
< textarea id = "reqParamList" readonly v -textarea -auto -height = " rawRequestBody " v-model = "rawRequestBody" placeholder="(add at least one parameter)" rows="1" > < / textarea >
< / li >
< / ul >
2019-09-13 16:52:11 +00:00
< ul v-for ="(param, index) in bodyParams" :key ="index" >
2019-09-02 11:02:29 +00:00
< li >
2019-09-17 09:55:32 +00:00
< input : placeholder = "'key '+(index+1)" :name = "'bparam'+index" v-model = "param.key" @keyup.prevent="setRouteQueryState" autofocus >
2019-09-02 11:02:29 +00:00
< / li >
< li >
2019-09-17 09:55:32 +00:00
< input : placeholder = "'value '+(index+1)" :id = "'bvalue'+index" :name = "'bvalue'+index" v-model = "param.value" @keyup.prevent="setRouteQueryState" >
2019-09-02 11:02:29 +00:00
< / li >
2019-09-12 11:09:59 +00:00
< div >
< li >
2019-09-16 12:57:07 +00:00
< button class = "icon" @click ="removeRequestBodyParam(index)" id = "delParam" >
2019-09-17 08:13:12 +00:00
< svg xmlns = "http://www.w3.org/2000/svg" width = "18" height = "18" viewBox = "0 0 24 24" >
< path d = "M5.633 22.031c1.135 1.313 3.735 1.969 6.334 1.969 2.601 0 5.199-.656 6.335-1.969.081-.404 3.698-18.468 3.698-18.882 0-2.473-7.338-3.149-10-3.149-4.992 0-10 1.242-10 3.144 0 .406 3.556 18.488 3.633 18.887zm6.418-16.884c-4.211 0-7.625-.746-7.625-1.667s3.414-1.667 7.625-1.667 7.624.746 7.624 1.667-3.413 1.667-7.624 1.667z" / >
2019-09-12 11:09:59 +00:00
< / svg >
< / button >
< / li >
< / div >
2019-09-13 16:52:11 +00:00
< / ul >
2019-09-02 11:02:29 +00:00
< ul >
< li >
2019-09-17 08:13:12 +00:00
< button class = "icon" @click ="addRequestBodyParam" name = "addrequest" >
< svg xmlns = "http://www.w3.org/2000/svg" width = "18" height = "18" viewBox = "0 0 24 24" >
2019-09-21 20:31:07 +00:00
< path d = "M24 10h-10v-10h-4v10h-10v4h10v10h4v-10h10z" / >
2019-09-17 08:13:12 +00:00
< / svg >
< span > Add New < / span >
< / button >
2019-09-02 11:02:29 +00:00
< / li >
< / ul >
< / div >
< div v-else >
2019-09-13 16:52:11 +00:00
< ul >
< li >
< label for = "rawBody" > Raw Request Body < / label >
2019-09-16 12:57:07 +00:00
< textarea id = "rawBody" @keydown ="formatRawParams" rows = "8" v-model = "rawParams" v-textarea-auto-height="rawParams" > < / textarea >
2019-09-13 16:52:11 +00:00
< / li >
< / ul >
2019-09-02 11:02:29 +00:00
< / div >
2019-09-20 13:04:42 +00:00
< / div >
< / pw-section >
< pw-section class = "blue" label = "Code" ref = "requestCode" v-if = "!isHidden" >
< ul >
< li >
< label for = "requestType" > Request Type < / label >
< select id = "requestType" v-model = "requestType" >
< option > JavaScript XHR < / option >
< option > Fetch < / option >
< option > cURL < / option >
< / select >
< / li >
< / ul >
< ul >
< li >
< div class = "flex-wrap" >
< label for = "generatedCode" > Generated Code < / label >
< div >
< button class = "icon" @click ="copyRequestCode" id = "copyRequestCode" ref = "copyRequestCode" >
< svg xmlns = "http://www.w3.org/2000/svg" width = "18" height = "18" viewBox = "0 0 24 24" >
< path d = "M19.647 15.247c-1.278 0-2.429.551-3.225 1.429l-7.788-3.846c.062-.343.079-.64.067-.942l8.058-4.231c.769.682 1.78 1.097 2.889 1.097 2.404-.001 4.352-1.949 4.352-4.353s-1.948-4.353-4.353-4.353-4.353 1.949-4.353 4.353c0 .18.012.356.033.53l-7.828 4.111c-.793-.829-1.908-1.347-3.146-1.347-2.405 0-4.353 1.949-4.353 4.353s1.948 4.353 4.353 4.353c1.013 0 1.943-.347 2.684-.927l8.26 4.078-.001.047c0 2.404 1.948 4.353 4.353 4.353s4.351-1.949 4.351-4.353-1.948-4.352-4.353-4.352z" / >
< / svg >
< span > Copy < / span >
< / button >
< / div >
< / div >
< textarea id = "generatedCode" ref = "generatedCode" name = "generatedCode" rows = "8" v-model = "requestCode" > < / textarea >
< / li >
< / ul >
2019-09-02 11:02:29 +00:00
< / pw-section >
< pw-section class = "purple" id = "response" label = "Response" ref = "response" >
< ul >
< li >
< label for = "status" > status < / label >
2019-09-16 12:57:07 +00:00
< input : class = "statusCategory ? statusCategory.className : ''" : value = "response.status || '(waiting to send request)'" ref = "status" id = "status" name = "status" readonly type = "text" >
2019-09-02 11:02:29 +00:00
< / li >
< / ul >
2019-09-09 07:12:31 +00:00
< ul v-for ="(value, key) in response.headers" :key ="key" >
2019-09-02 11:02:29 +00:00
< li >
< label for = "value" > { { key } } < / label >
2019-09-16 12:57:07 +00:00
< input id = "value" :value = "value" name = "value" readonly >
2019-09-02 11:02:29 +00:00
< / li >
< / ul >
< ul v-if = "response.body" >
< li >
< div class = "flex-wrap" >
< label for = "body" > response < / label >
2019-09-02 12:05:59 +00:00
< div >
2019-09-16 12:57:07 +00:00
< button class = "icon" @click ="copyResponse" ref = "copyResponse" v-if = "response.body" >
2019-09-17 08:13:12 +00:00
< svg xmlns = "http://www.w3.org/2000/svg" width = "18" height = "18" viewBox = "0 0 24 24" >
< path d = "M19.647 15.247c-1.278 0-2.429.551-3.225 1.429l-7.788-3.846c.062-.343.079-.64.067-.942l8.058-4.231c.769.682 1.78 1.097 2.889 1.097 2.404-.001 4.352-1.949 4.352-4.353s-1.948-4.353-4.353-4.353-4.353 1.949-4.353 4.353c0 .18.012.356.033.53l-7.828 4.111c-.793-.829-1.908-1.347-3.146-1.347-2.405 0-4.353 1.949-4.353 4.353s1.948 4.353 4.353 4.353c1.013 0 1.943-.347 2.684-.927l8.26 4.078-.001.047c0 2.404 1.948 4.353 4.353 4.353s4.351-1.949 4.351-4.353-1.948-4.352-4.353-4.352z" / >
2019-09-03 04:54:08 +00:00
< / svg >
2019-09-02 02:28:03 +00:00
< span > Copy < / span >
< / button >
2019-09-02 12:05:59 +00:00
< / div >
2019-09-02 11:02:29 +00:00
< / div >
< div id = "response-details-wrapper" >
2019-09-16 12:57:07 +00:00
< pre > < code ref = "responseBody" id = "body" rows = "16" placeholder = "(waiting to send request)" > { { response . body } } < / code > < / pre >
2019-09-02 11:02:29 +00:00
< iframe : class = "{hidden: !previewEnabled}" class = "covers-response" ref = "previewFrame" src = "about:blank" > < / iframe >
< / div >
< div class = "align-right" v-if = "response.body && responseType === 'text/html'" >
2019-09-04 05:05:11 +00:00
< button class = "icon" @click.prevent ="togglePreview" >
< svg xmlns = "http://www.w3.org/2000/svg" width = "24" height = "24" viewBox = "0 0 24 24" v-if = "!previewEnabled" >
< path d = "M12.015 7c4.751 0 8.063 3.012 9.504 4.636-1.401 1.837-4.713 5.364-9.504 5.364-4.42 0-7.93-3.536-9.478-5.407 1.493-1.647 4.817-4.593 9.478-4.593zm0-2c-7.569 0-12.015 6.551-12.015 6.551s4.835 7.449 12.015 7.449c7.733 0 11.985-7.449 11.985-7.449s-4.291-6.551-11.985-6.551zm-.015 5c1.103 0 2 .897 2 2s-.897 2-2 2-2-.897-2-2 .897-2 2-2zm0-2c-2.209 0-4 1.792-4 4 0 2.209 1.791 4 4 4s4-1.791 4-4c0-2.208-1.791-4-4-4z" / >
< / svg >
< svg xmlns = "http://www.w3.org/2000/svg" width = "24" height = "24" viewBox = "0 0 24 24" v-if = "previewEnabled" >
< path d = "M19.604 2.562l-3.346 3.137c-1.27-.428-2.686-.699-4.243-.699-7.569 0-12.015 6.551-12.015 6.551s1.928 2.951 5.146 5.138l-2.911 2.909 1.414 1.414 17.37-17.035-1.415-1.415zm-6.016 5.779c-3.288-1.453-6.681 1.908-5.265 5.206l-1.726 1.707c-1.814-1.16-3.225-2.65-4.06-3.66 1.493-1.648 4.817-4.594 9.478-4.594.927 0 1.796.119 2.61.315l-1.037 1.026zm-2.883 7.431l5.09-4.993c1.017 3.111-2.003 6.067-5.09 4.993zm13.295-4.221s-4.252 7.449-11.985 7.449c-1.379 0-2.662-.291-3.851-.737l1.614-1.583c.715.193 1.458.32 2.237.32 4.791 0 8.104-3.527 9.504-5.364-.729-.822-1.956-1.99-3.587-2.952l1.489-1.46c2.982 1.9 4.579 4.327 4.579 4.327z" / >
< / svg >
< span > { { previewEnabled ? 'Hide Preview' : 'Preview HTML' } } < / span >
< / button >
2019-09-02 11:02:29 +00:00
< / div >
< / li >
< / ul >
< / pw-section >
2019-09-16 08:20:28 +00:00
< section >
< input id = "tab-one" type = "radio" name = "grp" checked = "checked" >
< label for = "tab-one" > Authentication < / label >
< div class = "tab" >
2019-09-17 08:13:12 +00:00
< pw-section class = "cyan" label = "Authentication" >
2019-09-16 08:20:28 +00:00
< ul >
< li >
< label for = "auth" > Authentication Type < / label >
2019-09-16 12:57:07 +00:00
< select id = "auth" v-model = "auth" >
2019-09-16 08:20:28 +00:00
< option > None < / option >
< option > Basic < / option >
< option > Bearer Token < / option >
< / select >
< / li >
< / ul >
< ul v-if = "auth === 'Basic'" >
< li >
2019-09-17 08:13:12 +00:00
< input placeholder = "User" name = "http_basic_user" v-model = "httpUser" >
2019-09-16 08:20:28 +00:00
< / li >
< li >
2019-09-17 08:13:12 +00:00
< input placeholder = "Password" name = "http_basic_passwd" :type = "passwordFieldType" v-model = "httpPassword" >
2019-09-16 08:20:28 +00:00
< / li >
< div >
< li >
2019-09-16 12:57:07 +00:00
< button class = "icon" id = "switchVisibility" ref = "switchVisibility" @click ="switchVisibility" >
2019-09-16 08:20:28 +00:00
< svg xmlns = "http://www.w3.org/2000/svg" width = "24" height = "24" viewBox = "0 0 24 24" v-if = "passwordFieldType === 'text'" >
2019-09-17 08:13:12 +00:00
< path d = "M15 12c0 1.654-1.346 3-3 3s-3-1.346-3-3 1.346-3 3-3 3 1.346 3 3zm9-.449s-4.252 8.449-11.985 8.449c-7.18 0-12.015-8.449-12.015-8.449s4.446-7.551 12.015-7.551c7.694 0 11.985 7.551 11.985 7.551zm-7 .449c0-2.757-2.243-5-5-5s-5 2.243-5 5 2.243 5 5 5 5-2.243 5-5z" / >
2019-09-16 08:20:28 +00:00
< / svg >
< svg xmlns = "http://www.w3.org/2000/svg" width = "24" height = "24" viewBox = "0 0 24 24" v-if = "passwordFieldType !== 'text'" >
2019-09-17 08:13:12 +00:00
< path d = "M11.885 14.988l3.104-3.098.011.11c0 1.654-1.346 3-3 3l-.115-.012zm8.048-8.032l-3.274 3.268c.212.554.341 1.149.341 1.776 0 2.757-2.243 5-5 5-.631 0-1.229-.13-1.785-.344l-2.377 2.372c1.276.588 2.671.972 4.177.972 7.733 0 11.985-8.449 11.985-8.449s-1.415-2.478-4.067-4.595zm1.431-3.536l-18.619 18.58-1.382-1.422 3.455-3.447c-3.022-2.45-4.818-5.58-4.818-5.58s4.446-7.551 12.015-7.551c1.825 0 3.456.426 4.886 1.075l3.081-3.075 1.382 1.42zm-13.751 10.922l1.519-1.515c-.077-.264-.132-.538-.132-.827 0-1.654 1.346-3 3-3 .291 0 .567.055.833.134l1.518-1.515c-.704-.382-1.496-.619-2.351-.619-2.757 0-5 2.243-5 5 0 .852.235 1.641.613 2.342z" / >
2019-09-16 08:20:28 +00:00
< / svg >
< / button >
< / li >
< / div >
< / ul >
< ul v-if = "auth === 'Bearer Token'" >
< li >
2019-09-17 08:13:12 +00:00
< input placeholder = "Token" name = "bearer_token" v-model = "bearerToken" >
2019-09-16 08:20:28 +00:00
< / li >
< / ul >
< / pw-section >
< / div >
< input id = "tab-two" type = "radio" name = "grp" >
< label for = "tab-two" > Headers < / label >
< div class = "tab" >
< pw-section class = "orange" label = "Headers" >
2019-09-17 08:13:12 +00:00
< ul >
< li >
< label for = "headerList" > Header List < / label >
< textarea id = "headerList" readonly v -textarea -auto -height = " headerString " v-model = "headerString" placeholder="(add at least one header)" rows="1" > < / textarea >
< / li >
< / ul >
2019-09-16 08:20:28 +00:00
< ul v-for ="(header, index) in headers" :key ="index" >
< li >
2019-09-17 09:55:32 +00:00
< input : placeholder = "'header '+(index+1)" :name = "'header'+index" v-model = "header.key" @keyup.prevent="setRouteQueryState" autofocus >
2019-09-16 08:20:28 +00:00
< / li >
< li >
2019-09-17 09:55:32 +00:00
< input : placeholder = "'value '+(index+1)" :name = "'value'+index" v-model = "header.value" @keyup.prevent="setRouteQueryState" >
2019-09-16 08:20:28 +00:00
< / li >
< div >
< li >
2019-09-16 12:57:07 +00:00
< button class = "icon" @click ="removeRequestHeader(index)" id = "header" >
2019-09-17 08:13:12 +00:00
< svg xmlns = "http://www.w3.org/2000/svg" width = "18" height = "18" viewBox = "0 0 24 24" >
< path d = "M5.633 22.031c1.135 1.313 3.735 1.969 6.334 1.969 2.601 0 5.199-.656 6.335-1.969.081-.404 3.698-18.468 3.698-18.882 0-2.473-7.338-3.149-10-3.149-4.992 0-10 1.242-10 3.144 0 .406 3.556 18.488 3.633 18.887zm6.418-16.884c-4.211 0-7.625-.746-7.625-1.667s3.414-1.667 7.625-1.667 7.624.746 7.624 1.667-3.413 1.667-7.624 1.667z" / >
2019-09-16 08:20:28 +00:00
< / svg >
< / button >
< / li >
< / div >
< / ul >
< ul >
< li >
2019-09-17 08:13:12 +00:00
< button class = "icon" @click ="addRequestHeader" >
< svg xmlns = "http://www.w3.org/2000/svg" width = "18" height = "18" viewBox = "0 0 24 24" >
2019-09-21 20:31:07 +00:00
< path d = "M24 10h-10v-10h-4v10h-10v4h10v10h4v-10h10z" / >
2019-09-17 08:13:12 +00:00
< / svg >
< span > Add New < / span >
< / button >
2019-09-16 08:20:28 +00:00
< / li >
< / ul >
< / pw-section >
< / div >
< input id = "tab-three" type = "radio" name = "grp" >
< label for = "tab-three" > Parameters < / label >
< div class = "tab" >
< pw-section class = "pink" label = "Parameters" >
2019-09-17 08:13:12 +00:00
< ul >
< li >
< label for = "paramList" > Parameter List < / label >
< textarea id = "paramList" readonly v -textarea -auto -height = " queryString " v-model = "queryString" placeholder="(add at least one parameter)" rows="1" > < / textarea >
< / li >
< / ul >
2019-09-16 08:20:28 +00:00
< ul v-for ="(param, index) in params" :key ="index" >
< li >
2019-09-17 09:55:32 +00:00
< input : placeholder = "'parameter '+(index+1)" :name = "'param'+index" v-model = "param.key" autofocus >
2019-09-16 08:20:28 +00:00
< / li >
< li >
2019-09-17 09:55:32 +00:00
< input : placeholder = "'value '+(index+1)" :name = "'value'+index" v-model = "param.value" >
2019-09-16 08:20:28 +00:00
< / li >
< div >
< li >
2019-09-16 12:57:07 +00:00
< button class = "icon" @click ="removeRequestParam(index)" id = "param" >
2019-09-17 08:13:12 +00:00
< svg xmlns = "http://www.w3.org/2000/svg" width = "18" height = "18" viewBox = "0 0 24 24" >
< path d = "M5.633 22.031c1.135 1.313 3.735 1.969 6.334 1.969 2.601 0 5.199-.656 6.335-1.969.081-.404 3.698-18.468 3.698-18.882 0-2.473-7.338-3.149-10-3.149-4.992 0-10 1.242-10 3.144 0 .406 3.556 18.488 3.633 18.887zm6.418-16.884c-4.211 0-7.625-.746-7.625-1.667s3.414-1.667 7.625-1.667 7.624.746 7.624 1.667-3.413 1.667-7.624 1.667z" / >
2019-09-16 08:20:28 +00:00
< / svg >
< / button >
< / li >
< / div >
< / ul >
< ul >
< li >
2019-09-17 08:13:12 +00:00
< button class = "icon" @click ="addRequestParam" >
< svg xmlns = "http://www.w3.org/2000/svg" width = "18" height = "18" viewBox = "0 0 24 24" >
2019-09-21 20:31:07 +00:00
< path d = "M24 10h-10v-10h-4v10h-10v4h10v10h4v-10h10z" / >
2019-09-17 08:13:12 +00:00
< / svg >
< span > Add New < / span >
< / button >
2019-09-16 08:20:28 +00:00
< / li >
< / ul >
< / pw-section >
< / div >
< / section >
2019-09-13 05:02:49 +00:00
< history @useHistory ="handleUseHistory" ref = "historyComponent" > < / history >
2019-09-02 11:02:29 +00:00
< / div >
2019-08-24 03:06:57 +00:00
< / template >
< script >
2019-09-02 11:02:29 +00:00
import autocomplete from '../components/autocomplete' ;
import history from "../components/history" ;
import section from "../components/section" ;
import textareaAutoHeight from "../directives/textareaAutoHeight" ;
import toggle from "../components/toggle" ;
2019-09-13 05:02:49 +00:00
import modal from "../components/modal" ;
2019-09-06 10:41:18 +00:00
import parseCurlCommand from '../assets/js/curlparser.js' ;
2019-09-11 10:59:33 +00:00
import hljs from 'highlight.js' ;
2019-09-12 05:49:16 +00:00
import 'highlight.js/styles/dracula.css' ;
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
const statusCategories = [ {
name : 'informational' ,
statusCodeRegex : new RegExp ( /[1][0-9]+/ ) ,
className : 'info-response'
2019-08-31 16:59:32 +00:00
} ,
2019-09-02 11:02:29 +00:00
{
name : 'successful' ,
statusCodeRegex : new RegExp ( /[2][0-9]+/ ) ,
className : 'success-response'
} ,
{
name : 'redirection' ,
statusCodeRegex : new RegExp ( /[3][0-9]+/ ) ,
className : 'redir-response'
} ,
{
name : 'client error' ,
statusCodeRegex : new RegExp ( /[4][0-9]+/ ) ,
className : 'cl-error-response'
} ,
{
name : 'server error' ,
statusCodeRegex : new RegExp ( /[5][0-9]+/ ) ,
className : 'sv-error-response'
} ,
{
// this object is a catch-all for when no other objects match and should always be last
name : 'unknown' ,
statusCodeRegex : new RegExp ( /.*/ ) ,
className : 'missing-data-response'
}
] ;
const parseHeaders = xhr => {
const headers = xhr . getAllResponseHeaders ( ) . trim ( ) . split ( /[\r\n]+/ ) ;
const headerMap = { } ;
headers . forEach ( line => {
const parts = line . split ( ': ' ) ;
const header = parts . shift ( ) . toLowerCase ( ) ;
const value = parts . join ( ': ' ) ;
headerMap [ header ] = value
} ) ;
return headerMap
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
} ;
2019-09-13 05:02:49 +00:00
export const findStatusGroup = responseStatus => statusCategories . find ( status => status . statusCodeRegex . test (
responseStatus ) ) ;
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
export default {
directives : {
textareaAutoHeight
} ,
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
components : {
'pw-section' : section ,
'pw-toggle' : toggle ,
2019-09-13 05:02:49 +00:00
'pw-modal' : modal ,
2019-09-02 11:02:29 +00:00
history ,
2019-09-06 10:41:18 +00:00
autocomplete ,
2019-09-02 11:02:29 +00:00
} ,
data ( ) {
return {
2019-09-06 10:41:18 +00:00
showModal : false ,
2019-09-17 08:13:12 +00:00
copyButton : '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M19.647 15.247c-1.278 0-2.429.551-3.225 1.429l-7.788-3.846c.062-.343.079-.64.067-.942l8.058-4.231c.769.682 1.78 1.097 2.889 1.097 2.404-.001 4.352-1.949 4.352-4.353s-1.948-4.353-4.353-4.353-4.353 1.949-4.353 4.353c0 .18.012.356.033.53l-7.828 4.111c-.793-.829-1.908-1.347-3.146-1.347-2.405 0-4.353 1.949-4.353 4.353s1.948 4.353 4.353 4.353c1.013 0 1.943-.347 2.684-.927l8.26 4.078-.001.047c0 2.404 1.948 4.353 4.353 4.353s4.351-1.949 4.351-4.353-1.948-4.352-4.353-4.352z"/></svg>' ,
copiedButton : '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24"><path d="M20.285 2l-11.285 11.567-5.286-5.011-3.714 3.716 9 8.728 15-15.285z"/></svg>' ,
2019-09-02 11:02:29 +00:00
method : 'GET' ,
url : 'https://reqres.in' ,
auth : 'None' ,
path : '/api/users' ,
httpUser : '' ,
httpPassword : '' ,
2019-09-13 05:02:49 +00:00
passwordFieldType : 'password' ,
2019-09-02 11:02:29 +00:00
bearerToken : '' ,
headers : [ ] ,
params : [ ] ,
bodyParams : [ ] ,
rawParams : '' ,
rawInput : false ,
contentType : 'application/json' ,
2019-09-03 04:25:50 +00:00
requestType : 'JavaScript XHR' ,
isHidden : true ,
2019-09-02 11:02:29 +00:00
response : {
status : '' ,
headers : '' ,
body : ''
} ,
previewEnabled : false ,
2019-09-16 22:54:11 +00:00
paramsWatchEnabled : true ,
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
/ * *
* These are content types that can be automatically
* serialized by postwoman .
* /
knownContentTypes : [
'application/json' ,
'application/x-www-form-urlencoded'
] ,
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
/ * *
* These are a list of Content Types known to Postwoman .
* /
validContentTypes : [
'application/json' ,
'application/hal+json' ,
'application/xml' ,
'application/x-www-form-urlencoded' ,
'text/html' ,
'text/plain'
]
}
} ,
watch : {
contentType ( val ) {
this . rawInput = ! this . knownContentTypes . includes ( val ) ;
2019-09-05 18:28:29 +00:00
} ,
2019-09-13 05:02:49 +00:00
rawInput ( status ) {
2019-09-05 18:28:29 +00:00
if ( status && this . rawParams === '' ) this . rawParams = '{}'
else this . setRouteQueryState ( )
2019-09-11 10:59:33 +00:00
} ,
2019-09-12 03:34:50 +00:00
'response.body' : function ( val ) {
2019-09-13 05:02:49 +00:00
var responseText = document . querySelector ( "div#response-details-wrapper pre code" ) != null ? document
. querySelector ( "div#response-details-wrapper pre code" ) : null ;
2019-09-12 03:34:50 +00:00
if ( responseText ) {
2019-09-13 05:02:49 +00:00
if ( document . querySelector ( '.hljs' ) !== null && responseText . innerHTML . indexOf ( '<span class="hljs' ) !== -
1 ) {
2019-09-12 03:34:50 +00:00
responseText . removeAttribute ( "class" ) ;
responseText . innerHTML = null ;
responseText . innerText = this . response . body ;
2019-09-13 05:02:49 +00:00
} else if ( responseText && this . response . body != "(waiting to send request)" && this . response . body !=
"Loading..." && this . response . body != "See JavaScript console (F12) for details." ) {
responseText . innerText = this . responseType == 'application/json' ? JSON . stringify ( this . response . body ,
null , 2 ) : this . response . body ;
2019-09-11 10:59:33 +00:00
hljs . highlightBlock ( document . querySelector ( "div#response-details-wrapper pre code" ) ) ;
2019-09-12 03:34:50 +00:00
} else {
responseText . innerText = this . response . body
2019-09-11 10:59:33 +00:00
}
2019-09-12 03:34:50 +00:00
}
2019-09-16 22:54:11 +00:00
} ,
params : {
handler : function ( newValue ) {
if ( ! this . paramsWatchEnabled ) {
this . paramsWatchEnabled = true ;
return ;
}
let path = this . path ;
let queryString = newValue
. filter ( ( {
key
} ) => ! ! key )
. map ( ( {
key ,
value
} ) => ` ${ key } = ${ value } ` ) . join ( '&' )
queryString = queryString === '' ? '' : ` ? ${ queryString } `
2019-09-18 09:40:44 +00:00
if ( path . includes ( '?' ) ) {
2019-09-16 22:54:11 +00:00
path = path . slice ( 0 , path . indexOf ( '?' ) ) + queryString ;
} else {
path = path + queryString
}
this . path = path ;
} ,
deep : true
2019-09-02 11:02:29 +00:00
}
} ,
computed : {
statusCategory ( ) {
return findStatusGroup ( this . response . status ) ;
} ,
isValidURL ( ) {
const protocol = '^(https?:\\/\\/)?' ;
2019-09-13 05:02:49 +00:00
const validIP = new RegExp ( protocol +
"(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" ) ;
const validHostname = new RegExp ( protocol +
"(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$"
) ;
2019-09-02 11:02:29 +00:00
return validIP . test ( this . url ) || validHostname . test ( this . url ) ;
} ,
hasRequestBody ( ) {
return [ 'POST' , 'PUT' , 'PATCH' ] . includes ( this . method ) ;
} ,
2019-09-16 22:54:11 +00:00
pathName ( ) {
2019-09-17 21:40:12 +00:00
return this . path . match ( /^([^?]*)\??/ ) [ 1 ]
2019-09-16 22:54:11 +00:00
} ,
2019-09-02 11:02:29 +00:00
rawRequestBody ( ) {
const {
bodyParams
} = this
if ( this . contentType === 'application/json' ) {
try {
const obj = JSON . parse ( ` { ${ bodyParams . filter ( ( { key } ) => !!key).map(({key, value}) => `
2019-09-02 10:27:24 +00:00
"${key}" : "${value}"
` ).join()}} ` )
2019-09-02 11:02:29 +00:00
return JSON . stringify ( obj )
} catch ( ex ) {
return 'invalid'
}
} else {
return bodyParams
. filter ( ( {
key
} ) => ! ! key )
. map ( ( {
key ,
value
} ) => ` ${ key } = ${ encodeURIComponent ( value ) } ` ) . join ( '&' )
}
} ,
headerString ( ) {
const result = this . headers
. filter ( ( {
key
} ) => ! ! key )
. map ( ( {
key ,
value
} ) => ` ${ key } : ${ value } ` ) . join ( ',\n' )
return result == '' ? '' : ` ${ result } `
} ,
queryString ( ) {
const result = this . params
. filter ( ( {
key
} ) => ! ! key )
. map ( ( {
key ,
value
} ) => ` ${ key } = ${ encodeURIComponent ( value ) } ` ) . join ( '&' )
return result === '' ? '' : ` ? ${ result } `
} ,
responseType ( ) {
return ( this . response . headers [ 'content-type' ] || '' ) . split ( ';' ) [ 0 ] . toLowerCase ( ) ;
2019-09-03 04:25:50 +00:00
} ,
requestCode ( ) {
if ( this . requestType == 'JavaScript XHR' ) {
var requestString = [ ]
requestString . push ( 'const xhr = new XMLHttpRequest()' ) ;
const user = this . auth === 'Basic' ? this . httpUser : null
const pswd = this . auth === 'Basic' ? this . httpPassword : null
2019-09-13 05:02:49 +00:00
requestString . push ( 'xhr.open(' + this . method + ', ' + this . url + this . path + this . queryString + ', true, ' +
user + ', ' + pswd + ')' ) ;
2019-09-03 04:25:50 +00:00
if ( this . auth === 'Bearer Token' ) {
requestString . push ( "xhr.setRequestHeader('Authorization', 'Bearer ' + " + this . bearerToken + ")" ) ;
}
if ( this . headers ) {
2019-09-13 05:02:49 +00:00
this . headers . forEach ( function ( element ) {
2019-09-03 04:25:50 +00:00
requestString . push ( 'xhr.setRequestHeader(' + element . key + ', ' + element . value + ')' ) ;
} )
}
if ( this . method === 'POST' || this . method === 'PUT' ) {
const requestBody = this . rawInput ? this . rawParams : this . rawRequestBody ;
requestString . push ( "xhr.setRequestHeader('Content-Length', " + requestBody . length + ")" )
requestString . push ( "xhr.setRequestHeader('Content-Type', `" + this . contentType + "; charset=utf-8`)" )
requestString . push ( "xhr.send(" + requestBody + ")" )
} else {
requestString . push ( 'xhr.send()' )
}
return requestString . join ( '\n' ) ;
} else if ( this . requestType == 'Fetch' ) {
var requestString = [ ] ;
var headers = [ ] ;
requestString . push ( 'fetch(' + this . url + this . path + this . queryString + ', {\n' )
requestString . push ( ' method: "' + this . method + '",\n' )
if ( this . auth === 'Basic' ) {
var basic = this . httpUser + ':' + this . httpPassword ;
headers . push ( ' "Authorization": "Basic ' + window . btoa ( unescape ( encodeURIComponent ( basic ) ) ) + ',\n' )
} else if ( this . auth === 'Bearer Token' ) {
headers . push ( ' "Authorization": "Bearer Token ' + this . bearerToken + ',\n' )
}
if ( this . method === 'POST' || this . method === 'PUT' ) {
const requestBody = this . rawInput ? this . rawParams : this . rawRequestBody ;
requestString . push ( ' body: ' + requestBody + ',\n' )
headers . push ( ' "Content-Length": ' + requestBody . length + ',\n' )
headers . push ( ' "Content-Type": "' + this . contentType + '; charset=utf-8",\n' )
}
if ( this . headers ) {
2019-09-13 05:02:49 +00:00
this . headers . forEach ( function ( element ) {
2019-09-03 04:25:50 +00:00
headers . push ( ' "' + element . key + '": "' + element . value + '",\n' ) ;
} )
}
headers = headers . join ( '' ) . slice ( 0 , - 3 ) ;
2019-09-04 04:14:16 +00:00
requestString . push ( ' headers: {\n' + headers + '\n },\n' )
2019-09-03 04:25:50 +00:00
requestString . push ( ' credentials: "same-origin"\n' )
requestString . push ( ')}).then(function(response) {\n' )
requestString . push ( ' response.status\n' )
requestString . push ( ' response.statusText\n' )
requestString . push ( ' response.headers\n' )
requestString . push ( ' response.url\n\n' )
requestString . push ( ' return response.text()\n' )
requestString . push ( ')}, function(error) {\n' )
requestString . push ( ' error.message\n' )
requestString . push ( ')}' )
return requestString . join ( '' ) ;
} else if ( this . requestType == 'cURL' ) {
var requestString = [ ] ;
requestString . push ( 'curl -X ' + this . method + ' \\\n' )
requestString . push ( " '" + this . url + this . path + this . queryString + "' \\\n" )
if ( this . auth === 'Basic' ) {
var basic = this . httpUser + ':' + this . httpPassword ;
2019-09-13 05:02:49 +00:00
requestString . push ( " -H 'Authorization: Basic " + window . btoa ( unescape ( encodeURIComponent ( basic ) ) ) +
"' \\\n" )
2019-09-03 04:25:50 +00:00
} else if ( this . auth === 'Bearer Token' ) {
requestString . push ( " -H 'Authorization: Bearer Token " + this . bearerToken + "' \\\n" )
}
if ( this . headers ) {
2019-09-13 05:02:49 +00:00
this . headers . forEach ( function ( element ) {
2019-09-03 04:25:50 +00:00
requestString . push ( " -H '" + element . key + ": " + element . value + "' \\\n" ) ;
} )
}
if ( this . method === 'POST' || this . method === 'PUT' ) {
const requestBody = this . rawInput ? this . rawParams : this . rawRequestBody ;
requestString . push ( " -H 'Content-Length: " + requestBody . length + "' \\\n" )
requestString . push ( " -H 'Content-Type: " + this . contentType + "; charset=utf-8' \\\n" )
requestString . push ( " -d '" + requestBody + "' \\\n" )
}
2019-09-16 09:00:37 +00:00
return requestString . join ( '' ) . slice ( 0 , - 3 ) ;
2019-09-03 04:25:50 +00:00
}
2019-09-02 11:02:29 +00:00
}
} ,
methods : {
handleUseHistory ( {
method ,
url ,
path
} ) {
this . method = method ;
this . url = url ;
this . path = path ;
this . $refs . request . $el . scrollIntoView ( {
behavior : 'smooth'
} ) ;
} ,
async sendRequest ( ) {
if ( ! this . isValidURL ) {
alert ( 'Please check the formatting of the URL.' ) ;
return ;
}
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
// Start showing the loading bar as soon as possible.
// The nuxt axios module will hide it when the request is made.
this . $nuxt . $loading . start ( ) ;
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
if ( this . $refs . response . $el . classList . contains ( 'hidden' ) ) {
this . $refs . response . $el . classList . toggle ( 'hidden' )
}
this . $refs . response . $el . scrollIntoView ( {
behavior : 'smooth'
} ) ;
this . previewEnabled = false ;
this . response . status = 'Fetching...' ;
this . response . body = 'Loading...' ;
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
const auth = this . auth === 'Basic' ? {
username : this . httpUser ,
password : this . httpPassword
} : null ;
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
let headers = { } ;
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
// If the request has a request body, we want to ensure Content-Length and
// Content-Type are sent.
let requestBody ;
if ( this . hasRequestBody ) {
requestBody = this . rawInput ? this . rawParams : this . rawRequestBody ;
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
Object . assign ( headers , {
//'Content-Length': requestBody.length,
'Content-Type' : ` ${ this . contentType } ; charset=utf-8 `
} ) ;
}
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
// If the request uses a token for auth, we want to make sure it's sent here.
if ( this . auth === 'Bearer Token' ) headers [ 'Authorization' ] = ` Bearer ${ this . bearerToken } ` ;
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
headers = Object . assign (
// Clone the app headers object first, we don't want to
// mutate it with the request headers added by default.
Object . assign ( { } , this . headers ) ,
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
// We make our temporary headers object the source so
// that you can override the added headers if you
// specify them.
headers
) ;
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
try {
const payload = await this . $axios ( {
method : this . method ,
2019-09-16 22:54:11 +00:00
url : this . url + this . pathName + this . queryString ,
2019-09-02 11:02:29 +00:00
auth ,
headers ,
data : requestBody ? requestBody . toString ( ) : null
} ) ;
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
( ( ) => {
const status = this . response . status = payload . status ;
const headers = this . response . headers = payload . headers ;
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
// We don't need to bother parsing JSON, axios already handles it for us!
const body = this . response . body = payload . data ;
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
const date = new Date ( ) . toLocaleDateString ( ) ;
const time = new Date ( ) . toLocaleTimeString ( ) ;
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
// Addition of an entry to the history component.
const entry = {
status ,
date ,
time ,
method : this . method ,
url : this . url ,
path : this . path
} ;
this . $refs . historyComponent . addEntry ( entry ) ;
} ) ( ) ;
} catch ( error ) {
if ( error . response ) {
this . response . headers = error . response . headers ;
this . response . status = error . response . status ;
this . response . body = error . response . data ;
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
// Addition of an entry to the history component.
const entry = {
status : this . response . status ,
date : new Date ( ) . toLocaleDateString ( ) ,
time : new Date ( ) . toLocaleTimeString ( ) ,
method : this . method ,
url : this . url ,
path : this . path
} ;
this . $refs . historyComponent . addEntry ( entry ) ;
return ;
}
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
this . response . status = error . message ;
this . response . body = "See JavaScript console (F12) for details." ;
}
} ,
2019-09-17 21:40:12 +00:00
getQueryStringFromPath ( ) {
let path = this . path ,
hashIndex = path . indexOf ( '#' ) ,
start = path . indexOf ( '?' ) ,
end = hashIndex !== - 1 ? hashIndex : path . length ,
queryString = '' ;
2019-09-16 22:54:11 +00:00
if ( start !== - 1 ) {
2019-09-17 21:40:12 +00:00
let sliced = path . slice ( start , end ) ;
queryString = sliced . length > 1 ? sliced : '' ;
2019-09-16 22:54:11 +00:00
}
2019-09-17 21:40:12 +00:00
return queryString ;
} ,
queryStringToArray ( queryString ) {
return queryString . replace ( /^\?/ , '' ) . split ( '&' ) . filter ( pair => ! ! pair ) . map ( pair => {
let splited = pair . replace ( /#/g , '' ) . split ( '=' ) ;
return {
key : splited . shift ( ) ,
value : splited . join ( '=' )
2019-09-16 22:54:11 +00:00
}
2019-09-17 21:40:12 +00:00
} )
} ,
pathInputHandler ( ) {
let queryString = this . getQueryStringFromPath ( ) ,
params = this . queryStringToArray ( queryString ) ;
2019-09-02 10:27:24 +00:00
2019-09-16 22:54:11 +00:00
this . paramsWatchEnabled = false ;
this . params = params ;
} ,
2019-09-02 11:02:29 +00:00
addRequestHeader ( ) {
this . headers . push ( {
key : '' ,
value : ''
} ) ;
return false
} ,
removeRequestHeader ( index ) {
this . headers . splice ( index , 1 )
} ,
addRequestParam ( ) {
this . params . push ( {
key : '' ,
value : ''
} )
return false
} ,
removeRequestParam ( index ) {
this . params . splice ( index , 1 )
} ,
addRequestBodyParam ( ) {
this . bodyParams . push ( {
key : '' ,
value : ''
} )
return false
} ,
removeRequestBodyParam ( index ) {
this . bodyParams . splice ( index , 1 )
} ,
formatRawParams ( event ) {
if ( ( event . which !== 13 && event . which !== 9 ) ) {
return ;
}
const textBody = event . target . value ;
const textBeforeCursor = textBody . substring ( 0 , event . target . selectionStart ) ;
const textAfterCursor = textBody . substring ( event . target . selectionEnd ) ;
if ( event . which === 13 ) {
event . preventDefault ( ) ;
const oldSelectionStart = event . target . selectionStart ;
const lastLine = textBeforeCursor . split ( '\n' ) . slice ( - 1 ) [ 0 ] ;
const rightPadding = lastLine . match ( /([\s\t]*).*/ ) [ 1 ] || "" ;
event . target . value = textBeforeCursor + '\n' + rightPadding + textAfterCursor ;
2019-09-13 05:02:49 +00:00
setTimeout ( ( ) => event . target . selectionStart = event . target . selectionEnd = oldSelectionStart + rightPadding
. length + 1 , 1 ) ;
2019-09-02 11:02:29 +00:00
} else if ( event . which === 9 ) {
event . preventDefault ( ) ;
const oldSelectionStart = event . target . selectionStart ;
event . target . value = textBeforeCursor + '\xa0\xa0' + textAfterCursor ;
event . target . selectionStart = event . target . selectionEnd = oldSelectionStart + 2 ;
return false ;
}
} ,
2019-09-02 12:05:59 +00:00
copyRequest ( ) {
2019-09-05 10:46:52 +00:00
if ( navigator . share ) {
2019-09-05 11:12:08 +00:00
let time = new Date ( ) . toLocaleTimeString ( ) ;
2019-09-05 11:30:30 +00:00
let date = new Date ( ) . toLocaleDateString ( ) ;
2019-09-05 10:46:52 +00:00
navigator . share ( {
2019-09-13 05:02:49 +00:00
text : ` Postwoman • API request builder at ${ time } on ${ date } ` ,
url : window . location . href
} ) . then ( ( ) => {
// console.log('Thanks for sharing!');
} )
. catch ( console . error ) ;
2019-09-05 10:46:52 +00:00
} else {
this . $refs . copyRequest . innerHTML = this . copiedButton + '<span>Copied</span>' ;
var dummy = document . createElement ( 'input' ) ;
document . body . appendChild ( dummy ) ;
dummy . value = window . location . href ;
dummy . select ( ) ;
document . execCommand ( 'copy' ) ;
document . body . removeChild ( dummy ) ;
2019-09-17 08:13:12 +00:00
setTimeout ( ( ) => this . $refs . copyRequest . innerHTML = this . copyButton + '<span>Permalink</span>' , 1500 )
2019-09-05 10:46:52 +00:00
}
2019-09-02 12:05:59 +00:00
} ,
2019-09-04 01:45:19 +00:00
copyRequestCode ( ) {
this . $refs . copyRequestCode . innerHTML = this . copiedButton + '<span>Copied</span>' ;
this . $refs . generatedCode . select ( ) ;
document . execCommand ( "copy" ) ;
setTimeout ( ( ) => this . $refs . copyRequestCode . innerHTML = this . copyButton + '<span>Copy</span>' , 1500 )
2019-09-02 12:05:59 +00:00
} ,
2019-09-02 11:02:29 +00:00
copyResponse ( ) {
2019-09-03 04:54:08 +00:00
this . $refs . copyResponse . innerHTML = this . copiedButton + '<span>Copied</span>' ;
2019-09-11 10:59:33 +00:00
// Creates a textarea element
var aux = document . createElement ( "textarea" ) ;
var copy = this . responseType == 'application/json' ? JSON . stringify ( this . response . body ) : this . response . body ;
// Adds response body to the new textarea
aux . innerText = copy ;
// Append the textarea to the body
document . body . appendChild ( aux ) ;
// Highlight the content
aux . select ( ) ;
document . execCommand ( 'copy' ) ;
// Remove the input from the body
document . body . removeChild ( aux ) ;
2019-09-03 04:54:08 +00:00
setTimeout ( ( ) => this . $refs . copyResponse . innerHTML = this . copyButton + '<span>Copy</span>' , 1500 )
2019-09-02 11:02:29 +00:00
} ,
togglePreview ( ) {
this . previewEnabled = ! this . previewEnabled ;
if ( this . previewEnabled ) {
// If you want to add 'preview' support for other response types,
// just add them here.
if ( this . responseType === "text/html" ) {
// If the preview already has that URL loaded, let's not bother re-loading it all.
if ( this . $refs . previewFrame . getAttribute ( 'data-previewing-url' ) === this . url )
return ;
// Use DOMParser to parse document HTML.
const previewDocument = new DOMParser ( ) . parseFromString ( this . response . body , this . responseType ) ;
// Inject <base href="..."> tag to head, to fix relative CSS/HTML paths.
previewDocument . head . innerHTML = ` <base href=" ${ this . url } "> ` + previewDocument . head . innerHTML ;
// Finally, set the iframe source to the resulting HTML.
this . $refs . previewFrame . srcdoc = previewDocument . documentElement . outerHTML ;
this . $refs . previewFrame . setAttribute ( 'data-previewing-url' , this . url ) ;
}
}
} ,
setRouteQueryState ( ) {
const flat = key => this [ key ] !== '' ? ` ${ key } = ${ this [ key ] } & ` : ''
const deep = key => {
const haveItems = [ ... this [ key ] ] . length
if ( haveItems && this [ key ] [ 'value' ] !== '' ) {
return ` ${ key } = ${ JSON . stringify ( this [ key ] ) } & `
} else return ''
}
2019-09-13 05:02:49 +00:00
let flats = [ 'method' , 'url' , 'path' , 'auth' , 'httpUser' , 'httpPassword' , 'bearerToken' , 'contentType' ] . map (
item => flat ( item ) )
2019-09-02 15:44:53 +00:00
let deeps = [ 'headers' , 'params' ] . map ( item => deep ( item ) )
2019-09-03 04:54:08 +00:00
let bodyParams = this . rawInput ? [ flat ( 'rawParams' ) ] : [ deep ( 'bodyParams' ) ] ;
2019-09-02 15:44:53 +00:00
this . $router . replace ( '/?' + flats . concat ( deeps , bodyParams ) . join ( '' ) . slice ( 0 , - 1 ) )
2019-09-02 11:02:29 +00:00
} ,
setRouteQueries ( queries ) {
2019-09-13 05:02:49 +00:00
if ( typeof ( queries ) !== 'object' ) throw new Error ( 'Route query parameters must be a Object' )
2019-09-02 11:02:29 +00:00
for ( const key in queries ) {
if ( key === 'headers' || key === 'params' || key === 'bodyParams' ) this [ key ] = JSON . parse ( queries [ key ] )
2019-09-02 15:44:53 +00:00
if ( key === 'rawParams' ) {
this . rawInput = true
this . rawParams = queries [ 'rawParams' ]
2019-09-13 05:02:49 +00:00
} else if ( typeof ( this [ key ] ) === 'string' ) this [ key ] = queries [ key ]
2019-09-02 11:02:29 +00:00
}
} ,
observeRequestButton ( ) {
const requestElement = this . $refs . request . $el ;
const sendButtonElement = this . $refs . sendButton ;
const observer = new IntersectionObserver ( ( entries , observer ) => {
entries . forEach ( entry => {
sendButtonElement . classList . toggle ( 'show' ) ;
} ) ;
} , {
threshold : 1
} ) ;
2019-09-02 10:27:24 +00:00
2019-09-02 11:02:29 +00:00
observer . observe ( requestElement ) ;
2019-09-06 10:41:18 +00:00
} ,
2019-09-13 05:02:49 +00:00
handleImport ( ) {
2019-09-06 10:41:18 +00:00
let textarea = document . getElementById ( "import-text" )
let text = textarea . value ;
try {
let parsedCurl = parseCurlCommand ( text ) ;
2019-09-12 09:01:17 +00:00
this . url = parsedCurl . url . replace ( /"/g , "" ) . replace ( /'/g , "" ) ;
2019-09-06 10:41:18 +00:00
this . url = this . url [ this . url . length - 1 ] == '/' ? this . url . slice ( 0 , - 1 ) : this . url ;
this . path = "" ;
this . headers = [ ] ;
for ( const key of Object . keys ( parsedCurl . headers ) ) {
2019-09-13 05:02:49 +00:00
this . headers . push ( {
key : key ,
value : parsedCurl . headers [ key ]
} )
2019-09-06 10:41:18 +00:00
}
this . method = parsedCurl . method . toUpperCase ( ) ;
2019-09-13 06:12:20 +00:00
if ( parsedCurl [ "data" ] ) {
this . rawInput = true ;
this . rawParams = parsedCurl [ "data" ] ;
}
this . showModal = false ;
2019-09-06 10:41:18 +00:00
} catch ( error ) {
this . showModal = false ;
}
2019-09-12 05:49:16 +00:00
} ,
toggleModal ( ) {
this . showModal = ! this . showModal ;
2019-09-13 05:02:49 +00:00
} ,
switchVisibility ( ) {
this . passwordFieldType = this . passwordFieldType === 'password' ? 'text' : 'password'
2019-09-02 11:02:29 +00:00
}
} ,
mounted ( ) {
this . observeRequestButton ( ) ;
} ,
created ( ) {
if ( Object . keys ( this . $route . query ) . length ) this . setRouteQueries ( this . $route . query ) ;
this . $watch ( vm => [
vm . method ,
vm . url ,
vm . auth ,
vm . path ,
vm . httpUser ,
vm . httpPassword ,
vm . bearerToken ,
vm . headers ,
vm . params ,
vm . bodyParams ,
2019-09-02 15:44:53 +00:00
vm . contentType ,
vm . rawParams
2019-09-02 11:02:29 +00:00
] , val => {
this . setRouteQueryState ( )
} )
2019-08-27 11:52:24 +00:00
}
2019-09-02 11:02:29 +00:00
}
2019-08-24 03:06:57 +00:00
< / script >