102 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			102 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| (function () {
 | |
|     chrome.runtime.onMessage.addListener(
 | |
|         function (request, sender, sendResponse) {
 | |
|             if (!request.action) return;
 | |
|             // console.log("Recieved request:",request);
 | |
|             doAction(request, sender).then(r => sendResponse && sendResponse(r));
 | |
|             // return true to indicate you wish to send a response asynchronously
 | |
|             return true;
 | |
|         }
 | |
|     );
 | |
| 
 | |
|     async function doAction(request, sender) {
 | |
|         switch (request.action) {
 | |
|             case ACTION_EXTRACT:
 | |
|                 let data = extract(request.itemsSelector, request.fieldSelectors);
 | |
|                 return data;
 | |
|             case ACTION_GOTO_URL:
 | |
|                 window.location.replace(request.url);
 | |
|                 return request.url;
 | |
|             case ACTION_REPORT_IN:
 | |
|                 return request.action;
 | |
|             case ACTION_QUERY_URL:
 | |
|                 return window.location.href;
 | |
|             case ACTION_SCROLL_BOTTOM:
 | |
|                 return executeUntil(
 | |
|                     () => window.scrollTo(0, document.body.clientHeight),
 | |
|                     () => document.body.clientHeight - window.scrollY - window.innerHeight < 20,
 | |
|                     "Scroll to page bottom...",
 | |
|                     1000,
 | |
|                     10
 | |
|                 )
 | |
|             default:
 | |
|                 break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     function extract(itemsSelector, fieldSelectors) {
 | |
|         // since some elements may be loaded asynchronously.
 | |
|         // if one field is never found, we should return undefined,
 | |
|         // so that senders can detect to retry until elements loaded.
 | |
|         // If user writes wrong selectors, the task retries infinitely.
 | |
|         let fieldFound = {};
 | |
|         let items = Array.from(document.querySelectorAll(itemsSelector));
 | |
|         // items may not loaded yet, tell the sender to retry.
 | |
|         if (!items.length) return MSG_ELEMENT_NOT_FOUND;
 | |
|         let results = items.map(
 | |
|             item => {
 | |
|                 return fieldSelectors.map(
 | |
|                     selector => {
 | |
|                         let [cls, attr] = selector.split('@').slice(0, 2);
 | |
|                         let fieldVals = Array.from(item.querySelectorAll(cls));
 | |
|                         if (!fieldVals.length) {
 | |
|                             return;
 | |
|                         }
 | |
|                         fieldFound[selector] = true;
 | |
|                         return fieldVals.map(find => attr ? find[attr] : find.textContent.trim()).join('\n')
 | |
|                     }
 | |
|                 )
 | |
|             }
 | |
|         );
 | |
|         // if it exists a field, which is not found in any row, the sender should retry.
 | |
|         let shouldWait = fieldSelectors.reduce((p, c) => p || !fieldFound[c], false);
 | |
|         return shouldWait ? MSG_ELEMENT_NOT_FOUND : results
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Repeatedly execute an function until the the detector returns true.
 | |
|      * @param {object} fn the function to execute
 | |
|      * @param {object} detector the detector.
 | |
|      * @param {string} log messages logged to console.
 | |
|      * @param {number} interval interval for detecting
 | |
|      * @param {number} limit max execute times of a function
 | |
|      * @return {Promise} a promise of the response.
 | |
|      */
 | |
|     function executeUntil(fn, detector, log, interval, limit) {
 | |
|         interval = interval || 500;
 | |
|         let count = 0;
 | |
|         return new Promise((resolve, reject) => {
 | |
| 
 | |
|             loop();
 | |
| 
 | |
|             async function loop() {
 | |
|                 fn();
 | |
|                 limit++;
 | |
|                 if (limit && count >= limit) {
 | |
|                     reject(false);
 | |
|                 }
 | |
|                 setTimeout(() => {
 | |
|                     let flag = !detector || detector();
 | |
|                     if (log) console.log(log, flag ? '(OK)' : '(failed)');
 | |
|                     if (flag) {
 | |
|                         resolve(true);
 | |
|                     } else {
 | |
|                         loop();
 | |
|                     }
 | |
|                 }, interval);
 | |
|             }
 | |
|         });
 | |
|     }
 | |
| 
 | |
| })();
 |