EditJavascriptCode.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. <template>
  2. <div class="mb-2 mt-4">
  3. <ui-textarea
  4. :model-value="data.description"
  5. autoresize
  6. :placeholder="t('common.description')"
  7. class="w-full mb-1"
  8. @change="updateData({ description: $event })"
  9. />
  10. <template v-if="!data.everyNewTab">
  11. <ui-input
  12. :model-value="data.timeout"
  13. :label="t('workflow.blocks.javascript-code.timeout.placeholder')"
  14. :title="t('workflow.blocks.javascript-code.timeout.title')"
  15. type="number"
  16. class="mb-2 w-full"
  17. @change="updateData({ timeout: +$event })"
  18. />
  19. <ui-select
  20. v-if="!isFirefox"
  21. :model-value="data.context"
  22. :label="t('workflow.blocks.javascript-code.context.name')"
  23. class="mb-2 w-full"
  24. @change="updateData({ context: $event })"
  25. >
  26. <option
  27. v-for="item in ['website', 'background']"
  28. :key="item"
  29. :value="item"
  30. >
  31. {{ t(`workflow.blocks.javascript-code.context.items.${item}`) }}
  32. </option>
  33. </ui-select>
  34. </template>
  35. <p class="text-sm ml-1 text-gray-600 dark:text-gray-200">
  36. {{ t('workflow.blocks.javascript-code.name') }}
  37. </p>
  38. <pre
  39. v-if="!state.showCodeModal"
  40. class="rounded-lg overflow-auto text-gray-200 p-4 max-h-80 bg-gray-900"
  41. @click="state.showCodeModal = true"
  42. v-text="data.code"
  43. />
  44. <template v-if="isFirefox || data.context !== 'background'">
  45. <ui-checkbox
  46. :model-value="data.everyNewTab"
  47. class="mt-2"
  48. @change="updateData({ everyNewTab: $event })"
  49. >
  50. {{ t('workflow.blocks.javascript-code.everyNewTab') }}
  51. </ui-checkbox>
  52. <ui-checkbox
  53. :model-value="data.runBeforeLoad"
  54. class="mt-2"
  55. @change="updateData({ runBeforeLoad: $event })"
  56. >
  57. Run before page loaded
  58. </ui-checkbox>
  59. </template>
  60. <ui-modal v-model="state.showCodeModal" content-class="max-w-4xl">
  61. <template #header>
  62. <ui-tabs v-model="state.activeTab" class="border-none">
  63. <ui-tab value="code">
  64. {{ t('workflow.blocks.javascript-code.modal.tabs.code') }}
  65. </ui-tab>
  66. <ui-tab value="preloadScript">
  67. {{ t('workflow.blocks.javascript-code.modal.tabs.preloadScript') }}
  68. </ui-tab>
  69. </ui-tabs>
  70. </template>
  71. <ui-tab-panels
  72. v-model="state.activeTab"
  73. class="overflow-auto"
  74. style="height: calc(100vh - 9rem)"
  75. >
  76. <ui-tab-panel value="code" class="h-full">
  77. <shared-codemirror
  78. v-model="state.code"
  79. :extensions="codemirrorExts"
  80. :style="{ height: data.everyNewTab ? '100%' : '87%' }"
  81. class="overflow-auto"
  82. />
  83. <template v-if="!data.everyNewTab">
  84. <p class="mt-1 text-sm flex justify-between">
  85. <span>{{
  86. t('workflow.blocks.javascript-code.availabeFuncs')
  87. }}</span>
  88. <span>
  89. <span
  90. class="underline cursor-pointer select-none"
  91. @click="modifyWhiteSpace"
  92. >wrap line</span
  93. >
  94. </span>
  95. </p>
  96. <p
  97. class="space-x-1 whitespace-nowrap overflow-x-auto overflow-y-hidden pb-1 scroll"
  98. >
  99. <a
  100. v-for="func in availableFuncs"
  101. :key="func.id"
  102. :href="`https://docs.automa.site/blocks/javascript-code.html#${func.id}`"
  103. target="_blank"
  104. rel="noopener"
  105. class="inline-block"
  106. >
  107. <code>
  108. {{ func.name }}
  109. </code>
  110. </a>
  111. </p>
  112. </template>
  113. </ui-tab-panel>
  114. <ui-tab-panel value="preloadScript">
  115. <div
  116. v-for="(script, index) in state.preloadScripts"
  117. :key="index"
  118. class="flex items-center mt-4"
  119. >
  120. <v-remixicon
  121. name="riDeleteBin7Line"
  122. class="mr-2 cursor-pointer"
  123. @click="state.preloadScripts.splice(index, 1)"
  124. />
  125. <ui-input
  126. v-model="state.preloadScripts[index].src"
  127. placeholder="http://example.com/script.js"
  128. class="flex-1 mr-4"
  129. />
  130. <ui-checkbox
  131. v-if="
  132. (!data.everyNewTab || data.context !== 'website') && !isFirefox
  133. "
  134. v-model="state.preloadScripts[index].removeAfterExec"
  135. >
  136. {{ t('workflow.blocks.javascript-code.removeAfterExec') }}
  137. </ui-checkbox>
  138. </div>
  139. <ui-button variant="accent" class="w-20 mt-4" @click="addScript">
  140. {{ t('common.add') }}
  141. </ui-button>
  142. </ui-tab-panel>
  143. </ui-tab-panels>
  144. </ui-modal>
  145. </div>
  146. </template>
  147. <script setup>
  148. import { watch, reactive, defineAsyncComponent } from 'vue';
  149. import { useI18n } from 'vue-i18n';
  150. import { autocompletion } from '@codemirror/autocomplete';
  151. import {
  152. automaFuncsSnippets,
  153. automaFuncsCompletion,
  154. completeFromGlobalScope,
  155. } from '@/utils/codeEditorAutocomplete';
  156. import { store } from '../../settings/jsBlockWrap';
  157. function modifyWhiteSpace() {
  158. if (store.whiteSpace === 'pre') {
  159. store.whiteSpace = 'pre-wrap';
  160. } else {
  161. store.whiteSpace = 'pre';
  162. }
  163. }
  164. const SharedCodemirror = defineAsyncComponent(() =>
  165. import('@/components/newtab/shared/SharedCodemirror.vue')
  166. );
  167. const props = defineProps({
  168. data: {
  169. type: Object,
  170. default: () => ({}),
  171. },
  172. });
  173. const emit = defineEmits(['update:data']);
  174. const { t } = useI18n();
  175. const isFirefox = BROWSER_TYPE === 'firefox';
  176. const availableFuncs = [
  177. { name: 'automaNextBlock(data, insert?)', id: 'automanextblock-data' },
  178. { name: 'automaRefData(keyword, path?)', id: 'automarefdata-keyword-path' },
  179. {
  180. name: 'automaSetVariable(name, value)',
  181. id: 'automasetvariable-name-value',
  182. },
  183. {
  184. name: 'automaFetch(type, resource)',
  185. id: 'automasetvariable-type-resource',
  186. },
  187. { name: 'automaResetTimeout()', id: 'automaresettimeout' },
  188. ];
  189. const autocompleteList = Object.values(automaFuncsSnippets).slice(0, 4);
  190. const state = reactive({
  191. activeTab: 'code',
  192. code: `${props.data.code}`,
  193. preloadScripts: [...Object.values(props.data.preloadScripts || [])],
  194. showCodeModal: false,
  195. });
  196. function updateData(value) {
  197. emit('update:data', { ...props.data, ...value });
  198. }
  199. function addScript() {
  200. state.preloadScripts.push({ src: '', removeAfterExec: true });
  201. }
  202. const codemirrorExts = [
  203. autocompletion({
  204. override: [
  205. automaFuncsCompletion(autocompleteList),
  206. completeFromGlobalScope,
  207. ],
  208. }),
  209. ];
  210. watch(
  211. () => state.code,
  212. (value) => {
  213. updateData({ code: value });
  214. }
  215. );
  216. watch(
  217. () => state.preloadScripts,
  218. (value) => {
  219. updateData({ preloadScripts: value });
  220. },
  221. { deep: true }
  222. );
  223. </script>
  224. <style scoped>
  225. code {
  226. @apply bg-gray-900 text-sm text-white p-1 rounded-md;
  227. }
  228. </style>