index.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /**
  2. * 网页涂鸦精灵:可以针对任何网页进行任何涂鸦
  3. * @author zhaoxianlie
  4. */
  5. let editor = null;
  6. new Vue({
  7. el: '#pageContainer',
  8. data: {
  9. editing: false,
  10. editCM: {},
  11. unSavedCMID: 0,
  12. cachedModifiers: []
  13. },
  14. mounted: function () {
  15. this.editCM = this.getANewCM();
  16. // 编辑器初始化
  17. editor = CodeMirror.fromTextArea(this.$refs.mScript, {
  18. mode: "text/javascript",
  19. lineNumbers: true,
  20. matchBrackets: true,
  21. styleActiveLine: true,
  22. lineWrapping: true
  23. });
  24. // 退出的时候检测是否有未保存的数据
  25. window.onbeforeunload = function (e) {
  26. if (this.editing) {
  27. (e || window.event).returnValue = '当前还有未保存的数据,确定要离开么?';
  28. }
  29. };
  30. // 初始化获取数据
  31. chrome.runtime.sendMessage({
  32. type: MSG_TYPE.GET_PAGE_MODIFIER_CONFIG
  33. }, (cmList) => {
  34. this.cachedModifiers = cmList || [];
  35. });
  36. },
  37. methods: {
  38. getANewCM: function () {
  39. return {
  40. mName: '',
  41. mPattern: '',
  42. mFilter: '0',
  43. mScript: '',
  44. mRefresh: 0,
  45. mDisabled: null
  46. };
  47. },
  48. createModifier: function () {
  49. if (this.editing) {
  50. return alert('当前还有未保存的数据,无法继续创建!');
  51. }
  52. this.editing = true;
  53. this.editCM = this.getANewCM();
  54. this.editCM.id = 'mf_' + new Date() * 1;
  55. this.cachedModifiers.push(this.editCM);
  56. // 右侧面板,进行表单项编辑
  57. this.$refs.mForm.reset();
  58. $('.m-mask').slideUp();
  59. $('.m-form').removeClass('x-masked');
  60. },
  61. selectModifier: function (cm) {
  62. // 在编辑中,并且确定还要当前这个数据,就设定为选择无效
  63. if (this.editing) {
  64. if (confirm('当前还有未保存的数据,确定不要这个数据了吗?')) {
  65. this.editing = false;
  66. this.cachedModifiers.pop();
  67. } else {
  68. return false;
  69. }
  70. }
  71. // 如果当前数据还没保存,也点击无效
  72. if (this.editCM.id === cm.id) {
  73. return false;
  74. }
  75. // 把数据呈现到编辑面板
  76. this.editCM = cm;
  77. editor.setValue(cm.mScript);
  78. $('.m-mask').slideUp();
  79. $('.m-form').removeClass('x-masked');
  80. },
  81. saveModifier: function (isEditMode) {
  82. if (isEditMode) {
  83. // 必须填写一个名称
  84. if (!this.editCM.mName || !this.editCM.mName.trim()) {
  85. alert('网页精灵名称 不能为空,起一个自己看得懂的名字吧!');
  86. return false;
  87. }
  88. // 首先校验规则是否是一个合法正则表达式
  89. let matchs = this.editCM.mPattern.trim().match(/\/(.*)\/([igm]*)?$/);
  90. if (!matchs || !matchs.length) {
  91. alert('网页匹配规则 必须是一个正确的Javascript正则表达式!');
  92. return false;
  93. }
  94. this.editCM.mScript = editor.getValue();
  95. this.cachedModifiers.some(cm => {
  96. if (cm.id === this.editCM.id) {
  97. cm.mName = this.editCM.mName.trim();
  98. cm.mPattern = this.editCM.mPattern.trim();
  99. cm.mFilter = this.editCM.mFilter;
  100. cm.mRefresh = this.editCM.mRefresh;
  101. cm.mScript = editor.getValue();
  102. cm.mDisabled = !!cm.mDisabled;
  103. return true;
  104. }
  105. });
  106. }
  107. chrome.runtime.sendMessage({
  108. type: MSG_TYPE.SAVE_PAGE_MODIFIER_CONFIG,
  109. params: this.cachedModifiers
  110. }, () => {
  111. alert('数据操作成功!');
  112. this.editCM = this.getANewCM();
  113. editor.setValue('');
  114. this.editing = false;
  115. this.$refs.mForm.reset();
  116. $('.m-mask').slideDown();
  117. $('.m-form').addClass('x-masked');
  118. });
  119. },
  120. // 导入配置
  121. importModifier: function () {
  122. let that = this;
  123. let fileInput = document.getElementById('fileInput');
  124. if (!fileInput) {
  125. fileInput = document.createElement('input');
  126. fileInput.id = 'fileInput';
  127. fileInput.type = 'file';
  128. fileInput.accept = 'application/json';
  129. fileInput.style.cssText = 'position:relative;top:-1000px;left:-1000px;';
  130. fileInput.onchange = function (event) {
  131. let reader = new FileReader();
  132. reader.readAsText(fileInput.files[0], 'utf-8');
  133. reader.onload = (evt) => {
  134. let content = evt.target.result;
  135. try {
  136. // 过滤掉文件头部所有注释,然后转化成json
  137. let list = JSON.parse(content.replace(/^\/\*[^\*]*\*\//, ''));
  138. if (list && Array.isArray(list) && list.length) {
  139. let keys = 'id,mName,mPattern,mFilter,mRefresh,mScript,mDisabled'.split(',');
  140. let result = list.filter(item => {
  141. if (typeof item === 'object') {
  142. Object.keys(item).forEach(k => {
  143. !keys.includes(k) && delete(item[k]);
  144. });
  145. if (Object.keys(item).length) {
  146. return true;
  147. }
  148. }
  149. return false;
  150. });
  151. if (result.length) {
  152. let merge = null;
  153. // 配置合并,如果有重复的,则弹框确认
  154. result.forEach(r => {
  155. let found = that.cachedModifiers.some(cm => {
  156. if (r.id === cm.id || r.mName === cm.mName || r.mPattern === cm.mPattern) {
  157. if (merge === null) {
  158. merge = confirm('发现有相同名称或规则的精灵,是否选择覆盖?');
  159. }
  160. if (merge) {
  161. keys.forEach(k => {
  162. cm[k] = r[k];
  163. });
  164. } else {
  165. r.id += '_';
  166. }
  167. return merge;
  168. }
  169. });
  170. if (!found) {
  171. that.cachedModifiers.push(r);
  172. }
  173. });
  174. return that.saveModifier();
  175. }
  176. }
  177. throw new Error();
  178. } catch (e) {
  179. alert('当前选择的JSON配置文件格式不正确!');
  180. }
  181. };
  182. };
  183. document.body.appendChild(fileInput);
  184. }
  185. fileInput.click();
  186. },
  187. // 导出配置
  188. exportModifier: function () {
  189. chrome.runtime.sendMessage({
  190. type: MSG_TYPE.GET_PAGE_MODIFIER_CONFIG
  191. }, (cmList) => {
  192. if (cmList && cmList.length) {
  193. let timestamp = new Date() * 1;
  194. let exportPrefix = '/* Page modifier config, exported from FeHelper, timestamp:' + timestamp + ' */\n\n';
  195. let exportContent = JSON.stringify(cmList, null, 4);
  196. let blob = new Blob([exportPrefix + exportContent], {type: 'application/octet-stream'});
  197. // 请求权限
  198. chrome.permissions.request({
  199. permissions: ['downloads']
  200. }, (granted) => {
  201. if (granted) {
  202. chrome.downloads.download({
  203. url: URL.createObjectURL(blob),
  204. saveAs: true,
  205. conflictAction: 'overwrite',
  206. filename: 'FeHelper-PM-' + timestamp + '.json'
  207. }, () => {
  208. alert('数据导出成功!');
  209. });
  210. } else {
  211. alert('必须接受授权,才能正常导出!');
  212. }
  213. });
  214. } else {
  215. alert('没有已保存/可使用的精灵,不可导出!');
  216. }
  217. });
  218. },
  219. // 清空精灵
  220. removeModifier: function (theCM) {
  221. if (confirm('你确定要删除所有的精灵吗,此操作不可撤销!')) {
  222. if (theCM) {
  223. this.cachedModifiers = this.cachedModifiers.filter(cm => {
  224. return cm.id !== theCM.id;
  225. });
  226. } else {
  227. this.cachedModifiers = [];
  228. }
  229. this.saveModifier();
  230. }
  231. },
  232. // 停用精灵
  233. disableModifier: function (theCM) {
  234. if (theCM) {
  235. if (confirm('请再次确认是否需要' + (theCM.mDisabled ? '启用' : '停用') + '此精灵?')) {
  236. this.editCM.mDisabled = !theCM.mDisabled;
  237. this.saveModifier(true);
  238. }
  239. } else {
  240. if (confirm('停用精灵后,可单独编辑启用;是否继续此操作?')) {
  241. this.cachedModifiers.forEach(cm => {
  242. cm.mDisabled = true;
  243. });
  244. this.saveModifier();
  245. }
  246. }
  247. }
  248. }
  249. });