EditJavascriptCode.vue 7.1 KB

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