q-koa 7.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/core/app.js +1813 -0
  2. package/core/config.js +124 -0
  3. package/core/file/plugins/administrator/config.js +17 -0
  4. package/core/file/plugins/administrator/controller.js +264 -0
  5. package/core/file/plugins/administrator/model.js +53 -0
  6. package/core/file/plugins/administrator/validate.js +41 -0
  7. package/core/file/plugins/alipay/controller.js +68 -0
  8. package/core/file/plugins/alipay/validate.js +9 -0
  9. package/core/file/plugins/cache/service.js +16 -0
  10. package/core/file/plugins/cloudfunction/config.js +4 -0
  11. package/core/file/plugins/cloudfunction/model.js +15 -0
  12. package/core/file/plugins/common/controller.js +398 -0
  13. package/core/file/plugins/common/validate.js +47 -0
  14. package/core/file/plugins/douyin/config.js +3 -0
  15. package/core/file/plugins/douyin/controller.js +521 -0
  16. package/core/file/plugins/douyin/validate.js +40 -0
  17. package/core/file/plugins/douyin_user/config.js +15 -0
  18. package/core/file/plugins/douyin_user/model.js +72 -0
  19. package/core/file/plugins/good_sku/controller.js +80 -0
  20. package/core/file/plugins/h5_user/config.js +19 -0
  21. package/core/file/plugins/h5_user/model.js +71 -0
  22. package/core/file/plugins/lang/config.js +4 -0
  23. package/core/file/plugins/lang/model.js +15 -0
  24. package/core/file/plugins/language/config.js +5 -0
  25. package/core/file/plugins/language/model.js +54 -0
  26. package/core/file/plugins/log/config.js +25 -0
  27. package/core/file/plugins/log/controller.js +31 -0
  28. package/core/file/plugins/log/model.js +51 -0
  29. package/core/file/plugins/model/config.js +12 -0
  30. package/core/file/plugins/model/controller.js +69 -0
  31. package/core/file/plugins/model/model.js +169 -0
  32. package/core/file/plugins/model/service.js +218 -0
  33. package/core/file/plugins/model/validate.js +42 -0
  34. package/core/file/plugins/model_attributes/config.js +12 -0
  35. package/core/file/plugins/model_attributes/model.js +114 -0
  36. package/core/file/plugins/mp_user/config.js +19 -0
  37. package/core/file/plugins/mp_user/model.js +59 -0
  38. package/core/file/plugins/permission/config.js +15 -0
  39. package/core/file/plugins/permission/model.js +91 -0
  40. package/core/file/plugins/role/config.js +27 -0
  41. package/core/file/plugins/role/controller.js +26 -0
  42. package/core/file/plugins/role/model.js +58 -0
  43. package/core/file/plugins/role_permission/config.js +12 -0
  44. package/core/file/plugins/role_permission/controller.js +27 -0
  45. package/core/file/plugins/role_permission/model.js +24 -0
  46. package/core/file/plugins/routes/config.js +17 -0
  47. package/core/file/plugins/routes/controller.js +153 -0
  48. package/core/file/plugins/routes/model.js +70 -0
  49. package/core/file/plugins/routes/service.js +22 -0
  50. package/core/file/plugins/setting/afterExecute.js +14 -0
  51. package/core/file/plugins/setting/config.js +14 -0
  52. package/core/file/plugins/setting/controller.js +50 -0
  53. package/core/file/plugins/setting/model.js +118 -0
  54. package/core/file/plugins/setting/validate.js +42 -0
  55. package/core/file/plugins/system/controller.js +501 -0
  56. package/core/file/plugins/system/service.js +148 -0
  57. package/core/file/plugins/system/validate.js +40 -0
  58. package/core/file/plugins/todolist/config.js +31 -0
  59. package/core/file/plugins/todolist/model.js +69 -0
  60. package/core/file/plugins/toutiao/controller.js +201 -0
  61. package/core/file/plugins/toutiao_user/config.js +15 -0
  62. package/core/file/plugins/toutiao_user/model.js +66 -0
  63. package/core/file/plugins/user/afterExecute.js +38 -0
  64. package/core/file/plugins/user/config.js +9 -0
  65. package/core/file/plugins/user/controller.js +329 -0
  66. package/core/file/plugins/user/model.js +96 -0
  67. package/core/file/plugins/user/test.js +71 -0
  68. package/core/file/plugins/user/validate.js +44 -0
  69. package/core/file/plugins/video/config.js +3 -0
  70. package/core/file/plugins/video/controller.js +15 -0
  71. package/core/file/plugins/video/validate.js +12 -0
  72. package/core/file/plugins/weixin/config.js +3 -0
  73. package/core/file/plugins/weixin/controller.js +994 -0
  74. package/core/file/plugins/weixin/service.js +105 -0
  75. package/core/file/plugins/weixin/validate.js +111 -0
  76. package/core/file/services/aliSms.js +45 -0
  77. package/core/file/services/alipay.js +123 -0
  78. package/core/file/services/amap.js +95 -0
  79. package/core/file/services/card.js +24 -0
  80. package/core/file/services/config.js +38 -0
  81. package/core/file/services/douyin.js +151 -0
  82. package/core/file/services/email.js +45 -0
  83. package/core/file/services/express.js +37 -0
  84. package/core/file/services/geo.js +71 -0
  85. package/core/file/services/qqVideo.js +64 -0
  86. package/core/file/services/toutiao.js +102 -0
  87. package/core/file/services/weixin.js +79 -0
  88. package/core/file/services/weixinArticle.js +53 -0
  89. package/core/file/services/weixinCrypt.js +34 -0
  90. package/core/file/services/weixinMP.js +435 -0
  91. package/core/file/services/weixinPay.js +35 -0
  92. package/core/file/services/xml.js +33 -0
  93. package/core/file/task/shop/index.js +589 -0
  94. package/core/file/task/shop/static/562e45760a44632de6fa7219bab78cce.png +0 -0
  95. package/core/file/task/shop/static/d7aeaeb6bfd68f71a00a83c0f5548363.png +0 -0
  96. package/core/file/utils/index.js +61 -0
  97. package/core/middlewares.js +120 -0
  98. package/core/restc/.npminstall.done +1 -0
  99. package/core/restc/LICENSE +21 -0
  100. package/core/restc/README.md +48 -0
  101. package/core/restc/faas/index.html +1112 -0
  102. package/core/restc/faas/index.txt +31 -0
  103. package/core/restc/faas/install_production.sh +6 -0
  104. package/core/restc/index.d.ts +7 -0
  105. package/core/restc/index.js +9 -0
  106. package/core/restc/lib/express.js +7 -0
  107. package/core/restc/lib/hapi.js +17 -0
  108. package/core/restc/lib/hapiLegacy.js +15 -0
  109. package/core/restc/lib/index.js +46 -0
  110. package/core/restc/lib/koa.js +9 -0
  111. package/core/restc/lib/koa2.js +9 -0
  112. package/core/restc/lib/utils/gateway.js +51 -0
  113. package/core/restc/package.json +41 -0
  114. package/core/validator.js +15 -0
  115. package/index.js +1 -0
  116. package/package.json +65 -0
@@ -0,0 +1,1112 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>restc</title>
6
+ <link rel="stylesheet" href="https://shadow.elemecdn.com/gh/highlightjs/cdn-release@9.8.0/build/styles/default.min.css">
7
+ <link rel="stylesheet" href="https://shadow.elemecdn.com/gh/codemirror/CodeMirror@5.19.0/lib/codemirror.css"></script>
8
+ <link rel="stylesheet" href="https://shadow.elemecdn.com/gh/codemirror/CodeMirror@5.19.0/theme/material.css"></script>
9
+ <script>
10
+ if (!window.fetch) document.write('<script src="https://shadow.elemecdn.com/gh/github/fetch@v1.0.0/fetch.min.js"><\/script>');
11
+ </script>
12
+ <script src="https://shadow.elemecdn.com/npm/jinkela@1.2.18/umd.min.js"></script>
13
+ <script src="https://shadow.elemecdn.com/gh/highlightjs/cdn-release@9.8.0/build/highlight.min.js"></script>
14
+ <script src="https://shadow.elemecdn.com/gh/codemirror/CodeMirror@5.19.0/lib/codemirror.min.js"></script>
15
+ <script src="https://shadow.elemecdn.com/gh/codemirror/CodeMirror@5.19.0/mode/javascript/javascript.min.js"></script>
16
+ <script src="https://shadow.elemecdn.com/gh/codemirror/CodeMirror@5.19.0/addon/display/autorefresh.min.js"></script>
17
+ <script src="https://shadow.elemecdn.com/npm/json-format-safely@1.2.2/index.js"></script>
18
+ <script src="https://shadow.elemecdn.com/npm/content-disposition-attachment@0.1.1/build@module=ContentDispositionAttachment&amp;format=umd!toes5!uglifyjs!index.js"></script>
19
+ <script extract>
20
+ class Configuration {
21
+ static get watchList() {
22
+ let value = {};
23
+ Object.defineProperty(this, 'watchList', { value, configurable: true });
24
+ return value;
25
+ }
26
+ static set(key, value) {
27
+ let oldValue = this.get(key);
28
+ localStorage.setItem(key, JSON.stringify(value));
29
+ if (this.watchList.hasOwnProperty(key)) {
30
+ this.watchList[key].forEach(watcher => watcher.call(this, value, oldValue));
31
+ }
32
+ }
33
+ static get(key, defaultValue = null) {
34
+ try {
35
+ let value = JSON.parse(localStorage.getItem(key));
36
+ if (value === null) value = defaultValue;
37
+ return value;
38
+ } catch (error) {
39
+ return defaultValue;
40
+ }
41
+ }
42
+ static watch(key, callback, callImmediately = true) {
43
+ (this.watchList.hasOwnProperty(key) ? this.watchList[key] : this.watchList[key] = []).push(callback);
44
+ if (callImmediately) this.set(key, this.get(key));
45
+ }
46
+ static unwatch(key, callback) {
47
+ if (this.watchList.hasOwnProperty(key)) {
48
+ this.watchList[key] = this.watchList[key].filter(watcher => watcher !== callback);
49
+ }
50
+ }
51
+ }
52
+ class StrToJson{
53
+ static encode(str){
54
+ let json = eval('(' + str + ')');
55
+ return JSON.stringify(json).replace('{','{\n').replace('}','\n}')
56
+ }
57
+ }
58
+
59
+ class QueryString {
60
+ static encode(s) {
61
+ return encodeURIComponent(s).replace(/%20/g, '+');
62
+ }
63
+ static decode(s) {
64
+ return decodeURIComponent(s.replace(/\+/g, '%20'));
65
+ }
66
+ static parse(queryString, preserveOrder = false) {
67
+ let result = queryString.split('&')
68
+ .filter(entry => entry.length)
69
+ .map(entry => entry.split('='))
70
+ .map(([ key, value = '' ]) => ({ key: this.decode(key), value: this.decode(value) }));
71
+ if (preserveOrder) return result;
72
+ return result.reduce((result, { key, value }) => Object.assign(result, { [key]: value }), {});
73
+ }
74
+ static stringify(parameters) {
75
+ if (!Array.isArray(parameters)) {
76
+ parameters = Object.keys(parameters).map(key => ({ key, value: parameters[key] }));
77
+ }
78
+ return parameters
79
+ .map(({ key, value }) => [ this.encode(key), this.encode(value) ].join('='))
80
+ .join('&');
81
+ }
82
+ }
83
+
84
+ const isBodyEnabled = method => ![ 'HEAD', 'GET' ].includes(method);
85
+
86
+ const loader = ({ element }, $promise) => {
87
+ element.classList.add('loading');
88
+ let restore = () => { element.classList.remove('loading'); };
89
+ return $promise.then(data => {
90
+ restore();
91
+ return data;
92
+ }, e => {
93
+ restore();
94
+ throw e;
95
+ });
96
+ }
97
+
98
+ class Logo extends Jinkela {
99
+ get template() {
100
+ return `
101
+ <a href="https://github.com/ElemeFE/restc" target="_blank"></a>
102
+ `;
103
+ }
104
+ get styleSheet() {
105
+ return `
106
+ :scope {
107
+ margin: 0 -8px;
108
+ padding: 8px;
109
+ width: 67px;
110
+ height: 25px;
111
+ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIYAAAAyCAYAAACZIqPyAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpjNDUyZmZhYi1mYzc2LTQ3NzktYWIxNi0yMWIwYzAwNmQ3MzkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6REU5NDNBN0VBMDIxMTFFNkJFRjI4RDAyMkVFQTk1MEIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6REU5NDNBN0RBMDIxMTFFNkJFRjI4RDAyMkVFQTk1MEIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpjNDUyZmZhYi1mYzc2LTQ3NzktYWIxNi0yMWIwYzAwNmQ3MzkiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6YzQ1MmZmYWItZmM3Ni00Nzc5LWFiMTYtMjFiMGMwMDZkNzM5Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+3gUV5gAABPZJREFUeNrsXItxozAQlT1pQCmBlIBLwCWQEkgJUAIuwZRglwAlHCVYJYQSOJiTLoqy+gbEx3ozO54xIMTu29WuJDj0fY8ApIPkg8TAsQMK2BrqQRLhv26QYpAKuuBFQopb0OXugQe50t+LePAIXJAHnT0VckoOJTGwZPgI2HfkSHTEgEhR0LziEPKLzeLM2e8MHI9MhhIxQbkEvTqH6CuVNaEZ5K47SUeMNtjXmgxj4j6WeuUg2Ur7qbXrS7DlZHhAIXmrOAZ7BgRiBARiBARiBGyQGFeaofOScsdjLotnopt5xUL2z8sDydd4VEhpFdED8knbzIHksubOkyWemaSfOkT0ng/g+huSzFhOhnERjZOk/45aOG4r1/4nSnos62HcLNvrFe1gTf+iQf70dhjPj+n1de+Gh4PeZMgd7JLr2liiXI2pyCZ+iMR7bpaRIKXXjTN9naTN2qHEjCR9nArQSuhT5BgqUiDAiJgqK574XqXjvEMjIdoUKB1I0eyFGLqFOjKRAfnIkQBenzq2d5/RYaD8alyrekXf16sK2o8WzTQ7vcaqhAjKyhTnvXPKeld4cgaQRYZKMAIzREHb5z2UX5wiFu29GfRxvNcJ/VurEp/rQp/3vNdytaJK4o1LFMpCglHugicXknMTIGrJhrEP4P8LldeZhhEMPGthEA06X8TAHklRUCMQwbidgWdXEg+tJMoShy/sW9EaJEA0rNaUfEaeFGWynB8rDKhKuFqFV+qeK1qoIog95TGm9/9BjMygdJwCrUtnDYlBFEY3IXyN/C+XRw76mSqP40v7H8SQ1fQNWg6qcO8SyToLj7x6nk+IPTmkquS+8c97pAp4AEqoFiZGpCBMr5DMgBjEgBwJ1c0Nzb/PAnsmBjSUxxwXwKqkpUnhB9oXOiD5NTFAir7WYHwRw0cSzErexrRcjam34J0Rg0jmQUy9s0Tr2785RVRObOYx0p0pgUi8cIyOJ4sqIEP7ee+mpCItV8eJojdAOSlawWIOgLGfB0t50wwxbBbRpBqYY7m7M8yvphy6csBJGBf+RwxZWE0W9nKbpHSKTP1Ec6tOo9RsZmLMPYxD77Ge+XzjCFQiPplroyxffWLT9I3jHMsUTjC3Q0a68vWo6eCSCahqBjPxQEpVYmqjF+zwrL5fEyW65LND60Gr6E/q4f6dImpgi6EvcSCG76qwM61K1pRoyqoD3Tg/KvemqTBKR28nlhEjF5LXKxDKdcmhV2yVGAh9vRcaAwYfCVFrKquEKp+9TpgA5VxqQYxOUxr23L1ig+iUG5J/nsiywGZg23ZdN9yq7oV/2WZssMFWhU/g+kSxqTkRzs3o/yPSOTYDb+G9El35aFKaQVHlN1VLKyl3bYYXDFx/l+RT/GsKPY2U6Zz51haIQZB8p7cp4onKwZEQheJY84s+MScgDsTHz0gMpvQTsl/tZXMSFeCdtga4GxDU1LCyrQOd5XO2EzgNiC19BoFFDrbIl0qSOLacrNohxvZwsrYiyfDSUkI0yGy6nFAissQxAvqmW/Jns5BsCCwlz9iiGbdFHITPObI9CLxnnVHA3pALhCtERwovNQdsOscICMQICMQI2Cwxwsdg94n4t8RYfDEnYHKwUt+KGFCtLn5pJmB74KfUa+C40X6M8NHX50NjMpSET0Q/F6DPLIDEGKdr30Pk2D3YJx/ARcG/AgwApoTnnabyZYoAAAAASUVORK5CYII=');
112
+ background-position: 50% 50%;
113
+ background-repeat: no-repeat;
114
+ background-size: 67px 25px;
115
+ }
116
+ `;
117
+ }
118
+ }
119
+
120
+ class SideBarToggleButton extends Jinkela {
121
+ get template() {
122
+ return `
123
+ <a href="javascript:" on-click="{click}">Toggle SideBar</a>
124
+ `;
125
+ }
126
+ init() {
127
+ Configuration.watch('settings.sidebar.collapse', value => {
128
+ if (value) {
129
+ this.element.classList.remove('active');
130
+ } else {
131
+ this.element.classList.add('active');
132
+ }
133
+ });
134
+ }
135
+ click() {
136
+ Configuration.set('settings.sidebar.collapse', !Configuration.get('settings.sidebar.collapse'));
137
+ }
138
+ get styleSheet() {
139
+ return `
140
+ :scope {
141
+ margin-left: auto;
142
+ padding: 4px;
143
+ width: 24px;
144
+ height: 24px;
145
+ background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pjxzdmcgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiPjxwYXRoIGQ9Ik0yMzIuMzY5MjMxIDI4Mi44MTMwNDZoNTU5LjI2MTUzOGEzMS41MDc2OTIgMzEuNTA3NjkyIDAgMCAwIDAtNjMuMDE1Mzg0aC01NTkuMjYxNTM4YTMxLjUwNzY5MiAzMS41MDc2OTIgMCAwIDAgMCA2My4wMTUzODR6TTc5MS42MzA3NjkgNDgwLjQ5MjMwOGgtNTU5LjI2MTUzOGEzMS41MDc2OTIgMzEuNTA3NjkyIDAgMCAwIDAgNjMuMDE1Mzg0aDU1OS4yNjE1MzhhMzEuNTA3NjkyIDMxLjUwNzY5MiAwIDAgMCAwLTYzLjAxNTM4NHpNNzkxLjYzMDc2OSA3NDEuMTg2OTU0aC01NTkuMjYxNTM4YTMxLjUwNzY5MiAzMS41MDc2OTIgMCAwIDAgMCA2My4wMTUzODRoNTU5LjI2MTUzOGEzMS41MDc2OTIgMzEuNTA3NjkyIDAgMCAwIDAtNjMuMDE1Mzg0eiIgZmlsbD0iI2ZmZiI+PC9wYXRoPjwvc3ZnPg==');
146
+ background-position: 50% 50%;
147
+ background-repeat: no-repeat;
148
+ border-radius: 4px;
149
+ text-indent: 10000px;
150
+ overflow: hidden;
151
+ &:hover {
152
+ background-color: #3f4555;
153
+ }
154
+ &:active, &.active {
155
+ background-color: #2d2f3b;
156
+ }
157
+ }
158
+ `;
159
+ }
160
+ }
161
+
162
+ class Header extends Jinkela {
163
+ get template() {
164
+ return `
165
+ <div>
166
+ <jkl-logo></jkl-logo>
167
+ <jkl-side-bar-toggle-button></jkl-side-bar-toggle-button>
168
+ </div>
169
+ `;
170
+ }
171
+ get styleSheet() {
172
+ return `
173
+ :scope {
174
+ display: flex;
175
+ align-items: center;
176
+ padding: 10px 40px;
177
+ background: #4c5264;
178
+ }
179
+ `;
180
+ }
181
+ }
182
+
183
+ class HighlightBlock extends Jinkela {
184
+ get template() {
185
+ return `<pre><code class="http" ref="body"></code></pre>`;
186
+ }
187
+ update(code, ...elements) {
188
+ this.body.textContent = code;
189
+ hljs.highlightBlock(this.body);
190
+ for (let element of elements) {
191
+ if (element instanceof Jinkela) element.to(this.body);
192
+ }
193
+ }
194
+ get styleSheet() {
195
+ return `
196
+ :scope {
197
+ font-size: 12px;
198
+ line-height: 1.5;
199
+ & > code {
200
+ margin: 0 8px;
201
+ padding: 20px 32px;
202
+ background: transparent;
203
+ overflow: visible;
204
+ }
205
+ }
206
+ `;
207
+ }
208
+ }
209
+
210
+ class RequestView extends Jinkela {
211
+ constructor(...args) {
212
+ super(...args);
213
+ }
214
+ init() {
215
+ this.block = new HighlightBlock().to(this);
216
+ }
217
+ update({ method, path, queryString, body, headers }) {
218
+ let uri = path;
219
+ if (queryString) uri += '?' + queryString;
220
+ headers = Object.keys(headers)
221
+ .map(key => ({ key, value: headers[key] }))
222
+ .map(({ key, value }) => ({ key, values: Array.isArray(value) ? value : [ value ] }))
223
+ .reduce((result, { key, values }) => [ ...result, ...values.map(value => ({ key, value })) ], []);
224
+ let request = [
225
+ [ method, uri, 'HTTP/1.1' ].join(' '),
226
+ ...headers.map(({ key, value }) => [ key, value ].join(': '))
227
+ ].join('\n');
228
+ if (isBodyEnabled(method) && body) request = [ request, body ].join('\n\n');
229
+ this.block.update(request);
230
+ }
231
+ }
232
+
233
+ class ResponseViewDownloadLink extends Jinkela {
234
+ beforeParse(params) {
235
+ if (!params.filename) {
236
+ params.filename = '';
237
+ }
238
+ }
239
+ get template() {
240
+ return `
241
+ <a download="{filename}" href="{url}">
242
+ <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M1022.955 522.57c0 100.193-81.516 181.699-181.719 181.699H655.6c-11.298 0-20.467-9.169-20.467-20.466 0-11.308 9.17-20.466 20.467-20.466h185.637c77.628 0 140.787-63.148 140.787-140.766 0-77.424-62.841-140.449-140.203-140.766-.42.03-.819.05-1.218.061-5.945.143-11.686-2.292-15.687-6.703a20.455 20.455 0 0 1-5.168-16.25c1.33-10.806 1.944-19.76 1.944-28.192 0-60.764-23.658-117.885-66.617-160.833-42.969-42.968-100.09-66.617-160.843-66.617-47.369 0-92.742 14.45-131.208 41.782-37.617 26.739-65.953 63.7-81.926 106.884a20.5 20.5 0 0 1-14.828 12.894 20.492 20.492 0 0 1-18.86-5.547c-19.289-19.33-44.943-29.972-72.245-29.972-56.323 0-102.146 45.813-102.146 102.126 0 .317.04.982.092 1.627.061.92.122 1.831.153 2.763a20.466 20.466 0 0 1-15.002 20.455c-32.356 8.934-61.541 28.55-82.181 55.218-21.305 27.517-32.572 60.508-32.572 95.413 0 86.244 70.188 156.423 156.443 156.423h169.981c11.298 0 20.466 9.158 20.466 20.466 0 11.297-9.168 20.466-20.466 20.466H199.951c-108.829 0-197.375-88.536-197.375-197.355 0-44.053 14.224-85.712 41.126-120.474 22.81-29.46 53.898-52.086 88.71-64.816 5.066-74.323 67.15-133.245 142.752-133.245 28.386 0 55.504 8.218 78.651 23.526 19.658-39.868 48.843-74.169 85.498-100.212 45.434-32.296 99.004-49.354 154.918-49.354 71.693 0 139.088 27.916 189.782 78.6 50.695 50.695 78.61 118.09 78.61 189.782 0 3.705-.102 7.47-.296 11.37 90.307 10.478 160.628 87.42 160.628 180.48z"/><path d="M629.259 820.711L527.235 922.724c-3.99 4.002-9.23 5.997-14.47 5.997s-10.478-1.995-14.47-5.997L396.273 820.711c-7.992-7.992-7.992-20.947 0-28.94s20.947-8.001 28.94 0l67.087 67.079v-358.7c0-11.297 9.159-20.466 20.466-20.466 11.308 0 20.467 9.169 20.467 20.466v358.7l67.088-67.078c7.992-8.002 20.947-7.992 28.939 0s7.992 20.947 0 28.939z"/></svg>
243
+ Download <span>{filename}</span>
244
+ </a>
245
+ `;
246
+ }
247
+ get styleSheet() {
248
+ return `
249
+ :scope {
250
+ --r: 76;
251
+ --g: 82;
252
+ --b: 100;
253
+ --a: .9;
254
+ background: rgba(var(--r), var(--g), var(--b), var(--a));
255
+ border-radius: 4px;
256
+ color: #fff;
257
+ display: inline-block;
258
+ fill: #fff;
259
+ font-family: sans-serif;
260
+ padding: 10px 15px;
261
+ text-decoration: none;
262
+ transition: background .2s ease;
263
+ white-space: nowrap;
264
+ > svg {
265
+ display: inline;
266
+ vertical-align: middle;
267
+ }
268
+ &:hover {
269
+ --a: .8;
270
+ }
271
+ &:active {
272
+ --a: 1;
273
+ }
274
+ }
275
+ `;
276
+ }
277
+ }
278
+
279
+ class ResponseView extends Jinkela {
280
+ constructor(...args) {
281
+ super(...args);
282
+ }
283
+ init() {
284
+ this.block = new HighlightBlock().to(this);
285
+ }
286
+ update($response) {
287
+ return Promise.resolve($response).then(response => {
288
+ let status = [ 'HTTP/1.1', response.status, response.statusText ].join(' ');
289
+ let headers = [ ...response.headers.entries() ].map(this.stringifyHeader).join('\n');
290
+ let contentType = response.headers.get('Content-Type');
291
+ let json = /json/.test(contentType);
292
+ let javascript = /javascript/.test(contentType);
293
+ let binary = !(/text/.test(contentType) || json || javascript);
294
+ let contentDisposition = response.headers.get('Content-Disposition') || '';
295
+ try {
296
+ contentDisposition = ContentDispositionAttachment.parse(contentDisposition);
297
+ } catch (error) {
298
+ contentDisposition = { attachment: false };
299
+ }
300
+ let { attachment, filename } = contentDisposition;
301
+ let $body;
302
+ if (binary || attachment) {
303
+ $body = response.blob().then(URL.createObjectURL).then(url => {
304
+ return { elements: [ new ResponseViewDownloadLink({ url, filename }) ] };
305
+ });
306
+ } else {
307
+ $body = response.text().then(result => {
308
+ let body = result;
309
+ if (json) {
310
+ try {
311
+ body = jsonFormatSafely(body);
312
+ } catch (e) { /* ignore */ }
313
+ }
314
+ return { body };
315
+ });
316
+ }
317
+ $body.then(({ body, elements = [] }) => {
318
+ this.block.update([ status, headers, '', body ].join('\n'), ...elements);
319
+ })
320
+ }).catch(({ message }) => {
321
+ this.block.update(message);
322
+ });
323
+ }
324
+ stringifyHeader([ key, value ]) {
325
+ key = key.replace(/(?:^|-)./g, $0 => $0.toUpperCase());
326
+ return [ key, value ].join(': ');
327
+ }
328
+ get styleSheet() {
329
+ return `
330
+ :scope {
331
+ height: 100%;
332
+ overflow: auto;
333
+ &.loading {
334
+ position: relative;
335
+ &:after {
336
+ position: absolute;
337
+ left: 3px;
338
+ right: 3px;
339
+ top: 3px;
340
+ bottom: 3px;
341
+ content: '';
342
+ background: rgba(255, 255, 255, 0.8) url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPScyNHB4JyBoZWlnaHQ9JzI0cHgnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj48Y2lyY2xlIGN4PSI1MCIgY3k9IjUwIiByPSI0MCIgc3Ryb2tlPSIjN2NjZmFmIiBmaWxsPSJub25lIiBzdHJva2Utd2lkdGg9IjEwIiBzdHJva2UtbGluZWNhcD0icm91bmQiPjxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9InN0cm9rZS1kYXNob2Zmc2V0IiBkdXI9IjJzIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgZnJvbT0iMCIgdG89IjUwMiI+PC9hbmltYXRlPjxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9InN0cm9rZS1kYXNoYXJyYXkiIGR1cj0iMnMiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB2YWx1ZXM9IjE1MC42IDEwMC40OzEgMjUwOzE1MC42IDEwMC40Ij48L2FuaW1hdGU+PC9jaXJjbGU+PC9zdmc+') 50% 50% no-repeat;
343
+ backdrop-filter: blur(3px);
344
+ -webkit-backdrop-filter: blur(3px);
345
+ cursor: progress;
346
+ }
347
+ }
348
+ }
349
+ `;
350
+ }
351
+ }
352
+
353
+ class ResultView extends Jinkela {
354
+ get padding() { return 40; }
355
+ get btnWidth() { return 120; }
356
+ get template() {
357
+ return `
358
+ <dl>
359
+ <dt on-click="{click}">
360
+ <span ref="underline"></span>
361
+ <a href="JavaScript:" data-binding="ResponseView" data-nth="0">Response</a>
362
+ <a href="JavaScript:" data-binding="RequestView" data-nth="1">Request</a>
363
+ </dt>
364
+ <dd>
365
+ <meta ref="list" />
366
+ </dd>
367
+ </dl>
368
+ `;
369
+ }
370
+ click({ target }) {
371
+ let binding = target.dataset.binding;
372
+ if (!binding) return;
373
+ this.underline.style.left = this.padding + target.dataset.nth * this.btnWidth + 'px';
374
+ this.list.forEach(item => {
375
+ item.element.style.display = item.constructor.name === binding ? 'block' : 'none';
376
+ });
377
+ }
378
+ get requestView() {
379
+ let value = new RequestView();
380
+ Object.defineProperty(this, 'requestView', { value, configurable: true });
381
+ return value;
382
+ }
383
+ get responseView() {
384
+ let value = new ResponseView();
385
+ Object.defineProperty(this, 'responseView', { value, configurable: true });
386
+ return value;
387
+ }
388
+ init() {
389
+ this.list = [ this.requestView, this.responseView ];
390
+ this.element.querySelector('a').click();
391
+ }
392
+ set waiting(value) {
393
+ if (value) {
394
+ this.element.classList.add('waiting');
395
+ } else {
396
+ this.element.classList.remove('waiting');
397
+ }
398
+ }
399
+ get waiting() { return this.element.classList.has('waiting'); }
400
+ update(request, $response) {
401
+ this.waiting = false;
402
+ this.requestView.update(request);
403
+ return loader(this, this.responseView.update($response));
404
+ }
405
+ get styleSheet() {
406
+ return `
407
+ :scope {
408
+ position: relative;
409
+ height: 100%;
410
+ box-sizing: border-box;
411
+ margin: 0;
412
+ display: flex;
413
+ flex-direction: column;
414
+ > dt {
415
+ position: relative;
416
+ border-bottom: 1px solid #e4e4ec;
417
+ padding: 0 ${this.padding}px;
418
+ margin: 0;
419
+ font-size: 0;
420
+ > a {
421
+ position: relative;
422
+ z-index: 1;
423
+ text-decoration: none;
424
+ display: inline-block;
425
+ box-sizing: border-box;
426
+ padding: .5em 1em;
427
+ font-size: 16px;
428
+ width: ${this.btnWidth}px;
429
+ text-align: center;
430
+ font-weight: 600;
431
+ color: #5d6576;
432
+ &:hover { opacity: .8; }
433
+ }
434
+ > span {
435
+ transition: left 200ms ease, right 200ms ease;
436
+ position: absolute;
437
+ top: 0;
438
+ bottom: -1px;
439
+ font-size: 16px;
440
+ width: ${this.btnWidth}px;
441
+ border-bottom: 2px solid #2d2f3b;
442
+ background: #f1f1f6;
443
+ }
444
+ }
445
+ > dd {
446
+ flex: 1;
447
+ overflow: auto;
448
+ margin: 0;
449
+ }
450
+ &.loading:after {
451
+ position: absolute;
452
+ left: 0;
453
+ right: 0;
454
+ top: 0;
455
+ bottom: 0;
456
+ content: '';
457
+ background: rgba(248, 248, 250, 0.8) url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHdpZHRoPScyNHB4JyBoZWlnaHQ9JzI0cHgnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj48Y2lyY2xlIGN4PSI1MCIgY3k9IjUwIiByPSI0MCIgc3Ryb2tlPSIjN2NjZmFmIiBmaWxsPSJub25lIiBzdHJva2Utd2lkdGg9IjEwIiBzdHJva2UtbGluZWNhcD0icm91bmQiPjxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9InN0cm9rZS1kYXNob2Zmc2V0IiBkdXI9IjJzIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgZnJvbT0iMCIgdG89IjUwMiI+PC9hbmltYXRlPjxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9InN0cm9rZS1kYXNoYXJyYXkiIGR1cj0iMnMiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB2YWx1ZXM9IjE1MC42IDEwMC40OzEgMjUwOzE1MC42IDEwMC40Ij48L2FuaW1hdGU+PC9jaXJjbGU+PC9zdmc+') 50% 50% no-repeat;
458
+ cursor: progress;
459
+ z-index: 1000;
460
+ }
461
+ &.waiting:after {
462
+ position: absolute;
463
+ left: 0;
464
+ top: 0;
465
+ right: 0;
466
+ bottom: 0;
467
+ display: flex;
468
+ align-items: center;
469
+ justify-content: center;
470
+ content: 'Click “Send” to send the request';
471
+ font-weight: 500;
472
+ font-size: 1.2em;
473
+ background: rgba(248, 248, 250, 0.8);
474
+ z-index: 1000;
475
+ }
476
+ }
477
+ `;
478
+ }
479
+ }
480
+
481
+ class SideBarInput extends Jinkela {
482
+ get template() {
483
+ return `
484
+ <div>
485
+ <input ref="input" placeholder="{placeholder}" />
486
+ </div>
487
+ `;
488
+ }
489
+ get placeholder() { return ''; }
490
+ set value(value) { this.input.value = value; }
491
+ get value() { return this.input.value; }
492
+ select() {
493
+ this.input.select();
494
+ }
495
+ get styleSheet() {
496
+ return `
497
+ :scope {
498
+ padding: 0 1em;
499
+ display: flex;
500
+ box-sizing: border-box;
501
+ color: #dbdfeb;
502
+ background: #3f4555;
503
+ line-height: 40px;
504
+ border: 0 none;
505
+ border-radius: 8px;
506
+ > input {
507
+ margin: 0;
508
+ padding: 0;
509
+ flex: 1;
510
+ border: 0 none;
511
+ color: inherit;
512
+ background: transparent;
513
+ font: inherit;
514
+ vertical-align: middle;
515
+ outline: none;
516
+ &::-webkit-input-placeholder {
517
+ color: #5d6577;
518
+ }
519
+ }
520
+ }
521
+ `;
522
+ }
523
+ }
524
+
525
+ class SideBarMethodSelect extends Jinkela {
526
+ get template() {
527
+ return `
528
+ <select>
529
+ <option>POST</option>
530
+ <option>GET</option>
531
+ </select>
532
+ `;
533
+ }
534
+ set value(value) {
535
+ this.element.value = value;
536
+ }
537
+ get value() {
538
+ return this.element.value;
539
+ }
540
+ get styleSheet() {
541
+ return `
542
+ :scope {
543
+ padding: 0 1.5em 0 1em;
544
+ color: #dbdfeb;
545
+ background: #3f4555;
546
+ font: inherit;
547
+ width: 100px;
548
+ height: 40px;
549
+ border: 0 none;
550
+ border-radius: 8px;
551
+ outline: none;
552
+ -webkit-appearance: none;
553
+ -moz-appearance: none;
554
+ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAqdJREFUeNpi/P//P8NAAiaGAQajDhh1wKgDGEDlADqGAnYgNoLS5AI2IDaEmYHVLhwOYFVT1/HOLqzdoaKm5Q3ik2E5q5KyumdWQc02dU1dPxAfm11Yo0BJRcPOLzCqUUBASC8gKKZRQUnViURHsIL0BIXGNwoKChv4BUTVAx1jT3QaiIhOy+fh45diZ+dgANEhEclNcgrKDkQ6glVGVsEOqKcBqFcGZAY3L59kREx6PtEOYOdgb2RlY/vKzsHBwAHEfHz8smGRKY1S0nLWQGkWPJazgNSER6c1AfXIg/SCzACa9R1oZhM2DYzYKiNGRkaGrokLLViYWZYxMDJw/P71i+Hnzx8MHz68v7ts4bSaF8+fHAEq+4umjVlMXNIyJiGnTUBQSAXkc6DFwETG8OPP3z8xZfnxx7DZhTMbAjWcYGRijGdiYvrJxsbOADJQQEBQOTIuo1FYWNQCZCGy5cIiYubR8dlNyJYD9f4GmpEIspyscqAwK+ow0AfJQEN+gwxkY2dnACYqtdjk3CaQhVD9TEJCIqYxidlNgkLCGiA1MMtBeoFmHMRnB84oQAYTpi13B0bFrH///rH++vWT4dfPnwxv3766PHdGbw0oeyenF7cICYvqgeIbFFpAy/8ALU8vyIrcjl7mkOUAqCN8gCEx/e/fv8wwR7x7++oC0FF/RUQljEE+B1nOzMz89/+//9lAyzdhK/TIdgDUEYFAR0wCOQKUMH///gVJ+qysyJYXAS1fjavUpcgBUEeEAx3R9+/vP8a//yAZgZmJmYGJmek/0PISoOXL8RX7FDsA7IjpK2KBajpAShFm/68uyIxYQKjeoUptCLRoMdCwemBiAyU4kNENhCynKBfgiY4MUAwAg30qsTUvUQ4YbRGNOmDUAaMOoCcACDAAFHYu4lUVtcQAAAAASUVORK5CYII=');
555
+ background-position: 90% 50%;
556
+ background-repeat: no-repeat;
557
+ background-size: 16px;
558
+ cursor: pointer;
559
+ &:hover {
560
+ color: #fff;
561
+ }
562
+ }
563
+ `;
564
+ }
565
+ }
566
+
567
+ class SideBarQueryStringInput extends SideBarInput {
568
+ get styleSheet() {
569
+ return `
570
+ :scope {
571
+ flex: 1;
572
+ &:before {
573
+ margin-right: .2em;
574
+ content: '?';
575
+ color: #5d6577;
576
+ }
577
+ }
578
+ `;
579
+ }
580
+ }
581
+
582
+ class SideBarSendButton extends Jinkela {
583
+ get template() { return '<button>Send</button>'; }
584
+ get styleSheet() {
585
+ return `
586
+ :scope {
587
+ padding: 0 1em;
588
+ height: 40px;
589
+ color: #dbdfeb;
590
+ background: transparent;
591
+ font: inherit;
592
+ border: 2px solid #959cad;
593
+ border-radius: 4px;
594
+ outline: none;
595
+ cursor: pointer;
596
+ transition: .15s background;
597
+ &:hover {
598
+ color: #fff;
599
+ border-color: #fff;
600
+ }
601
+ }
602
+ `;
603
+ }
604
+ }
605
+
606
+ class SideBarMethod extends Jinkela {
607
+ get template() {
608
+ return `
609
+ <div>
610
+ <jkl-side-bar-method-select ref="methodSelect" on-change="{methodChange}"></jkl-side-bar-method-select>
611
+ <jkl-side-bar-query-string-input
612
+ ref="queryStringInput"
613
+ on-input="{queryStringChange}"
614
+ placeholder="query string"></jkl-side-bar-query-string-input>
615
+ <jkl-side-bar-send-button></jkl-side-bar-send-button>
616
+ </div>
617
+ `;
618
+ }
619
+ set method(value) { this.methodSelect.value = value; }
620
+ get method() { return this.methodSelect.value; }
621
+ set queryString(value) { this.queryStringInput.value = value; }
622
+ get queryString() { return this.queryStringInput.value; }
623
+ methodChange() {
624
+ this.element.dispatchEvent(new CustomEvent('methodchange', { bubbles: true, detail: this.method }));
625
+ }
626
+ queryStringChange() {
627
+ this.element.dispatchEvent(new CustomEvent('querystringchange', { bubbles: true, detail: this.queryString }));
628
+ }
629
+ get styleSheet() {
630
+ return `
631
+ :scope {
632
+ margin: -.25em;
633
+ display: flex;
634
+ & > * {
635
+ margin: .25em;
636
+ }
637
+ }
638
+ `;
639
+ }
640
+ }
641
+
642
+ class SideBarKeyValuePairCheckBox extends Jinkela {
643
+ get template() {
644
+ return `
645
+ <input type="checkbox" />
646
+ `;
647
+ }
648
+ set checked(value) {
649
+ this.element.checked = value;
650
+ }
651
+ get checked() {
652
+ return this.element.checked;
653
+ }
654
+ get styleSheet() {
655
+ return `
656
+ :scope {
657
+ margin: 0 8px 0 10px;
658
+ width: 18px;
659
+ height: 18px;
660
+ -webkit-appearance: none;
661
+ -moz-appearance: none;
662
+ background: #2d2f3b;
663
+ border-radius: 4px;
664
+ cursor: pointer;
665
+ outline: none;
666
+ &:hover {
667
+ background: #262c39;
668
+ }
669
+ &:checked {
670
+ background-position: center center;
671
+ background-repeat: no-repeat;
672
+ background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOCIgaGVpZ2h0PSI2IiB2aWV3Qm94PSIwIDAgOCA2IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGQ9Ik0xIDIuOTRsMi4wMyAyLjAzTDcgMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIi8+PC9zdmc+');
673
+ }
674
+ }
675
+ `;
676
+ }
677
+ }
678
+
679
+ class SideBarKeyValuePairInput extends SideBarInput {
680
+ get styleSheet() {
681
+ return `
682
+ :scope {
683
+ padding: 4px 6px 4px 0;
684
+ flex: 1;
685
+ border-radius: 0;
686
+ font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
687
+ line-height: 32px;
688
+ }
689
+ `;
690
+ }
691
+ }
692
+
693
+ class SideBarKeyValuePair extends Jinkela {
694
+ get template() {
695
+ return `
696
+ <div>
697
+ <jkl-side-bar-key-value-pair-check-box
698
+ ref="enabledCheckBox"
699
+ on-click="{emitChange}">
700
+ </jkl-side-bar-key-value-pair-check-box>
701
+ <jkl-side-bar-key-value-pair-input
702
+ placeholder="key"
703
+ ref="keyInput"
704
+ on-input="{emitChange}">
705
+ </jkl-side-bar-key-value-pair-input>
706
+ <jkl-side-bar-key-value-pair-input
707
+ placeholder="value"
708
+ ref="valueInput"
709
+ on-input="{emitChange}">
710
+ </jkl-side-bar-key-value-pair-input>
711
+ </div>
712
+ `;
713
+ }
714
+ set enabled(value) { this.enabledCheckBox.checked = value; }
715
+ get enabled() { return this.enabledCheckBox.checked; }
716
+ set key(value) { this.keyInput.value = value; }
717
+ get key() { return this.keyInput.value; }
718
+ set value(value) { this.valueInput.value = value; }
719
+ get value() { return this.valueInput.value; }
720
+ select() {
721
+ this.keyInput.select();
722
+ }
723
+ emitChange() {
724
+ this.element.dispatchEvent(new CustomEvent('pairchange', { bubbles: true }));
725
+ }
726
+ get styleSheet() {
727
+ return `
728
+ :scope {
729
+ margin-bottom: 1px;
730
+ display: flex;
731
+ align-items: center;
732
+ background: #3f4555;
733
+ font-size: 12px;
734
+ }
735
+ `;
736
+ }
737
+ }
738
+
739
+ class SideBarKeyValueAdd extends Jinkela {
740
+ get template() {
741
+ return `
742
+ <div>
743
+ <span ref="children"></span>
744
+ </div>
745
+ `;
746
+ }
747
+ get styleSheet() {
748
+ return `
749
+ :scope {
750
+ padding: 0 11px 0 35px;
751
+ display: flex;
752
+ align-items: center;
753
+ height: 40px;
754
+ color: #5d6577;
755
+ background: #3f4555 url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiI+PHBhdGggZD0iTTUgMTJWN0gwVjVoNVYwaDJ2NWg1djJIN3Y1eiIgZmlsbD0iIzVkNjU3NyIvPjwvc3ZnPg==') 12px 50% no-repeat;
756
+ font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
757
+ font-size: 12px;
758
+ cursor: pointer;
759
+ &:hover {
760
+ color: #fff;
761
+ }
762
+ }
763
+ `;
764
+ }
765
+ }
766
+
767
+ class SideBarKeyValueCollection extends Jinkela {
768
+ get template() {
769
+ return `
770
+ <div>
771
+ <div ref="list"></div>
772
+ <div>
773
+ <jkl-side-bar-key-value-add on-click="{add}">{text}</jkl-side-bar-key-value-add>
774
+ </div>
775
+ </div>
776
+ `;
777
+ }
778
+ get text() { return 'add'; }
779
+ fromJSON(json) {
780
+ while (this.list.firstChild) this.list.firstChild.remove();
781
+ this.$collection = SideBarKeyValuePair
782
+ .from(json.map(({ enabled = true, key, value }) => ({ enabled, key, value })))
783
+ .to(this.list);
784
+ }
785
+ toJSON() {
786
+ return (this.$collection || [])
787
+ .map(({ enabled, key, value }) => ({ enabled, key, value }));
788
+ }
789
+ set collection(value) { this.fromJSON(value); }
790
+ get collection() {
791
+ return this.toJSON()
792
+ .filter(({ enabled }) => enabled)
793
+ .map(({ key, value }) => ({ key, value }));
794
+ }
795
+ add() {
796
+ let item = new SideBarKeyValuePair({ enabled: true, key: 'new item' }).to(this.list);
797
+ item.select();
798
+ (this.$collection || (this.$collection = [])).push(item);
799
+ this.element.dispatchEvent(new CustomEvent('collectionchange', { bubbles: true }));
800
+ }
801
+ get styleSheet() {
802
+ return `
803
+ :scope {
804
+ > * {
805
+ border-radius: 4px;
806
+ overflow: hidden;
807
+ }
808
+ }
809
+ `;
810
+ }
811
+ }
812
+
813
+ class SideBarBodyEditor extends Jinkela {
814
+ get template() {
815
+ return `
816
+ <div>
817
+ <h3>Body</h3>
818
+ </div>
819
+ `;
820
+ }
821
+ init() {
822
+ this.cm = CodeMirror(this.element, {
823
+ mode: 'application/json',
824
+ theme: 'material'
825
+ });
826
+ this.cm.setValue('{\n\n}')
827
+ // console.log(this.cm)
828
+ }
829
+ didMount() {
830
+ this.refresh();
831
+ }
832
+ set value(value) { this.cm.setValue(value);}
833
+ get value() { return this.cm.getValue(); }
834
+ refresh() {
835
+ setTimeout(() => this.cm.refresh(), 0);
836
+ }
837
+ get styleSheet() {
838
+ return `
839
+ :scope {
840
+ .CodeMirror {
841
+ padding: 1em;
842
+ height: 10em;
843
+ border-radius: 8px;
844
+ background: #3f4555;
845
+ font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
846
+ line-height: 1.5;
847
+ }
848
+ }
849
+ `;
850
+ }
851
+ }
852
+
853
+ class SideBarHeaderCollection extends SideBarKeyValueCollection {
854
+ get value() {
855
+ return this.collection
856
+ .reduce((result, { key, value }) => {
857
+ (result[key] || (result[key] = [])).push(value);
858
+ return result;
859
+ }, {});
860
+ }
861
+ }
862
+ class SideBar extends Jinkela {
863
+ get template() {
864
+ return `
865
+ <form on-submit="{submit}">
866
+ <jkl-side-bar-method
867
+ ref="methodComponent"
868
+ on-methodchange="{methodChange}"
869
+ on-querystringchange="{syncQueryParameters}">
870
+ </jkl-side-bar-method>
871
+ <h3>Query Parameters</h3>
872
+ <jkl-side-bar-key-value-collection
873
+ ref="queryParameterCollection"
874
+ text="add query parameter"
875
+ on-collectionchange="{syncQueryString}"
876
+ on-pairchange="{syncQueryString}">
877
+ </jkl-side-bar-key-value-collection>
878
+ <jkl-side-bar-body-editor ref="bodyEditor"></jkl-side-bar-body-editor>
879
+ <h3>Headers</h3>
880
+ <jkl-side-bar-header-collection
881
+ ref="headerCollection"
882
+ text="add header">
883
+ </form>
884
+ `;
885
+ }
886
+ set method(value) {
887
+ this.methodComponent.method = value;
888
+ this.methodChange();
889
+ }
890
+ get method() { return this.methodComponent.method; }
891
+ set queryString(value) {
892
+ this.methodComponent.queryString = value;
893
+ this.syncQueryParameters();
894
+ }
895
+ get queryString() { return this.methodComponent.queryString; }
896
+ set queryParameters(value) {
897
+ this.queryParameterCollection.collection = value;
898
+ this.syncQueryString();
899
+ }
900
+ get queryParameters() { return this.queryParameterCollection.collection; }
901
+ set body(value) { return this.bodyEditor.value = value; }
902
+ get body() {return this.bodyEditor.value; }
903
+ set headers(value) { this.headerCollection.collection = value; }
904
+ get headers() { return this.headerCollection.value; }
905
+ fromJSON(json) {
906
+ let { method, queryParameters, body, headers } = json;
907
+ if (method) this.method = method.toUpperCase();
908
+ if (queryParameters) {
909
+ this.queryParameters = queryParameters;
910
+ } else {
911
+ this.queryString = location.search.slice(1);
912
+ }
913
+ if (body) this.body = body;
914
+ if (headers) this.headerCollection.fromJSON(headers);
915
+ }
916
+ toJSON() {
917
+ let { method, body } = this;
918
+ let queryParameters = this.queryParameterCollection.toJSON();
919
+ let headers = this.headerCollection.toJSON();
920
+ return { method, queryParameters, body, headers };
921
+ }
922
+ set isBodyVisible(value) {
923
+ if (value) {
924
+ this.bodyEditor.element.style.display = 'block';
925
+ this.bodyEditor.refresh();
926
+ } else {
927
+ this.bodyEditor.element.style.display = 'none';
928
+ }
929
+ }
930
+ get isBodyVisible() { return this.bodyEditor.element.style.display !== 'none'; }
931
+ init() {
932
+ let { method, queryParameters, body, headers = [] } = QueryString.parse(location.hash.replace(/^#!?/, ''));
933
+ try { headers = JSON.parse(headers); } catch (error) { /* ignore */ }
934
+ try { queryParameters = JSON.parse(queryParameters); } catch (error) { /* ignore */ }
935
+ this.fromJSON({ method, queryParameters, body, headers });
936
+ this.methodChange();
937
+ }
938
+ submit(event) {
939
+ event.preventDefault();
940
+ let { method, queryParameters, body, headers } = this.toJSON();
941
+ if (queryParameters) queryParameters = JSON.stringify(queryParameters);
942
+ if (headers) headers = JSON.stringify(headers);
943
+ let hash = QueryString.stringify({ method, queryParameters, body, headers });
944
+ if (hash) hash = '#!' + hash;
945
+ if (location.hash !== hash) {
946
+ location.hash = hash;
947
+ } else {
948
+ dispatchEvent(new Event('hashchange'));
949
+ }
950
+ }
951
+ methodChange() {
952
+ this.isBodyVisible = isBodyEnabled(this.method);
953
+ }
954
+ syncQueryParameters() {
955
+ let { queryString } = this;
956
+ let queryParameters = QueryString.parse(queryString, true);
957
+ this.queryParameterCollection.collection = queryParameters;
958
+ }
959
+ syncQueryString() {
960
+ let { collection } = this.queryParameterCollection;
961
+ let queryString = QueryString.stringify(collection);
962
+ this.methodComponent.queryString = queryString;
963
+ }
964
+ get styleSheet() {
965
+ return `
966
+ :scope {
967
+ padding: 40px;
968
+ box-sizing: border-box;
969
+ color: #fff;
970
+ background: #2d2f3b;
971
+ transition: transform 1s;
972
+ height: 100%;
973
+ box-sizing: border-box;
974
+ overflow: auto;
975
+ h3 {
976
+ margin-left: -40px;
977
+ margin-right: -40px;
978
+ padding: 20px 40px;
979
+ border-bottom: 1px solid #373b48;
980
+ font-size: 17px;
981
+ font-weight: 600;
982
+ }
983
+ }
984
+ `;
985
+ }
986
+ }
987
+
988
+ class Main extends Jinkela {
989
+ get template() {
990
+ return `
991
+ <div>
992
+ <section>
993
+ <jkl-result-view ref="resultView"></jkl-result-view>
994
+ </section>
995
+ <aside>
996
+ <jkl-side-bar ref="sideBar"></jkl-side-bar>
997
+ </aside>
998
+ </div>
999
+ `;
1000
+ }
1001
+ init() {
1002
+ if (this.sideBar.method === 'POST' || this.sendByUser) {
1003
+ this.sendRequest();
1004
+ } else {
1005
+ this.resultView.waiting = true;
1006
+ }
1007
+ Configuration.watch('settings.sidebar.collapse', value => {
1008
+ console.log('---?') ;
1009
+ if (value) {
1010
+ this.element.classList.add('sidebar-collapse');
1011
+ } else {
1012
+ this.element.classList.remove('sidebar-collapse');
1013
+ }
1014
+ });
1015
+ }
1016
+ sendRequest() {
1017
+ let path = location.pathname;
1018
+ let { method, queryString, body, headers } = this.sideBar;
1019
+ body = StrToJson.encode(body)
1020
+ let defaultHeaders = {
1021
+ Accept: 'application/json, */*',
1022
+ 'Content-Type': 'application/json'
1023
+ };
1024
+ headers = Object.assign({}, defaultHeaders, headers);
1025
+ let uri = `//${location.host}${path}`;
1026
+ if (queryString) uri += '?' + queryString;
1027
+ let options = { method, headers, credentials: 'include' };
1028
+ if (this.sideBar.isBodyVisible) options.body = body;
1029
+ let $response = fetch(uri, options);
1030
+ this.resultView.update({ method, path, queryString, body, headers }, $response);
1031
+ // sync title
1032
+ document.title = [ method, uri ].join(' ');
1033
+ }
1034
+ get styleSheet() {
1035
+ return `
1036
+ :scope {
1037
+ position: relative;
1038
+ flex: 1;
1039
+ width: 100%;
1040
+ min-height: 0;
1041
+ > section, > aside {
1042
+ position: absolute;
1043
+ top: 0;
1044
+ bottom: 0;
1045
+ }
1046
+ > section {
1047
+ left: 0;
1048
+ width: 57%;
1049
+ transition: width .01s .7s;
1050
+ }
1051
+ > aside {
1052
+ left: 57%;
1053
+ right: 0;
1054
+ transition: transform .7s;
1055
+ }
1056
+ &.sidebar-collapse {
1057
+ > section {
1058
+ width: 100%;
1059
+ transition: none;
1060
+ }
1061
+ > aside {
1062
+ transform: translateX(100%);
1063
+ }
1064
+ }
1065
+ }
1066
+ `;
1067
+ }
1068
+ }
1069
+
1070
+ class Frame extends Jinkela {
1071
+ init() {
1072
+ let { sendByUser } = this;
1073
+ new Header().to(this);
1074
+ new Main({ sendByUser }).to(this);
1075
+ }
1076
+ get styleSheet() {
1077
+ return `
1078
+ html {
1079
+ height: 100%;
1080
+ overflow: hidden;
1081
+ }
1082
+ body {
1083
+ margin: 0;
1084
+ height: 100%;
1085
+ background: #fff;
1086
+ color: #4c555a;
1087
+ font-family:
1088
+ "Alright Sans LP", "Avenir Next", "Helvetica Neue", Helvetica, Arial, "PingFang SC",
1089
+ "Source Han Sans SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi MicroHei", sans-serif;
1090
+ font-size: 14px;
1091
+ -webkit-font-smoothing: antialiased;
1092
+ line-height: 26px;
1093
+ }
1094
+ pre, code {
1095
+ font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
1096
+ }
1097
+ :scope {
1098
+ display: flex;
1099
+ flex-direction: column;
1100
+ width: 100%;
1101
+ height: 100%;
1102
+ }
1103
+ `;
1104
+ }
1105
+ }
1106
+
1107
+ let frame = new Frame();
1108
+ addEventListener('hashchange', () => frame = new Frame({ sendByUser: true }).renderWith(frame));
1109
+ addEventListener('DOMContentLoaded', () => frame.to(document.body));
1110
+ </script>
1111
+ </head>
1112
+ </html>