Greasy Fork is available in English.
在#东商品列表和搜索结果页面增加【自营】【非自营】以及【满赠】【满减】等超过30个商品过滤选项,为【#东配送】【仅显示有货】以及【排序】选项增加记忆功能。
// ==UserScript== // @name #东自营过滤 // @version 0.5.3.4 // @icon https://www.jd.com/favicon.ico // @description 在#东商品列表和搜索结果页面增加【自营】【非自营】以及【满赠】【满减】等超过30个商品过滤选项,为【#东配送】【仅显示有货】以及【排序】选项增加记忆功能。 // @author You! // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_listValues // @grant GM_addStyle // @grant unsafeWindow // @include *://list.jd.com/list.html?* // @include *://coll.jd.com/list.html?* // @include *://list.jd.com/search?* // @include *://list.jd.com/Search?* // @include *://search.jd.com/search?* // @include *://search.jd.com/Search?* // @include *://www.jd.com/pinpai/* // _require https://code.jquery.com/jquery-3.5.0.min.js // @require https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js // _require https://code.jquery.com/color/jquery.color-2.1.2.min.js // @require https://cdn.bootcdn.net/ajax/libs/jquery-color/2.1.2/jquery.color.min.js // @run-at document-start // @namespace https://greasyfork.org/zh-CN/scripts/33729-#东自营过滤 // ==/UserScript== (function() { 'use strict'; //过滤器 var jdGoodsFilters = [ //自营,非自营 {name:'自营',nameN:'非自营',lv:0,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '#东自营,品质保障' ]} ]}, //PLUS会员价 {name:'PLUS会员',nameN:'非PLUS会员',lv:1,conditions:[ {type:'attr',tag:'span',attr:'title',vals:[ 'PLUS会员专享价' ]} ]}, //优惠券 {name:'优惠券',nameN:'无优惠券',lv:1,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '优惠券', '本商品可#用优惠券' ]} ]}, //满减 {name:'满减',nameN:'非满减',lv:1,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '该商品参加满减活动', '本商品参与满减促销', '满减' ]}, ]}, //满件 {name:'满件',nameN:'非满件',lv:1,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '本商品参与满件促销' ]} ]}, //满赠 {name:'满赠',nameN:'非满赠',lv:1,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '该商品参加满赠活动' ]} ]}, //赠品 {name:'赠品',nameN:'无赠品',lv:1,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '购买本商品送赠品' ]} ]}, //#东物流 {name:'#东物流',nameN:'非#东物流',lv:1,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '#东物流仓配,商家提供售后服务' ]} ]}, //厂商配送 {name:'厂商配送',nameN:'非厂商配送',lv:1,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '厂家或供应商发货和配送' ]} ]}, //到店自取 {name:'到店自取',nameN:'非到店自取',lv:1,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '该商品支持到店自取' ]} ]}, //免邮 {name:'免邮',nameN:'不免邮',lv:1,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '当前收货地址,该商品免邮费', '当前收货地址,本商品免邮费' ]} ]}, //运费险 {name:'运费险',nameN:'无运费险',lv:1,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '运费险', '退换货免运费' ]}, ]}, //#尊达 {name:'#尊达',nameN:'非#尊达',lv:1,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '专人配送,尊贵体验' ]} ]}, //预约抢购 {name:'预约抢购',nameN:'非预约抢购',conditions:[ {type:'multi',vals:[ {tag:'div',cls:'p-presell-time',textAny:['预约']}, ]}, ]}, //秒# {name:'秒#',nameN:'非秒#',lv:1,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '天天低价,正品保证' ]} ]}, //闪购 {name:'闪购',nameN:'非闪购',lv:1,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '品牌限时特卖' ]} ]}, //定期购 {name:'定期购',nameN:'非定期购',conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '定期免运费,省心又优惠' ]} ]}, //全球购 {name:'全球购',nameN:'非全球购',conditions:[ {type:'text',tag:'span',vals:[ '全球购' ]} ]}, //包税 {name:'包税',nameN:'不包税',conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '本商品已包税' ]} ]}, //新品 {name:'新品',nameN:'非新品',lv:1,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '该商品是当季新品' ]} ]}, //商场同款 {name:'商场同款',nameN:'非商场同款',lv:1,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '该商品是商场同款' ]} ]}, //#东精选 {name:'#东精选',nameN:'非#东精选',lv:1,conditions:[ {type:'attr',tag:'img',attr:'src',vals:[ '//img14.360buyimg.com/uba/jfs/t6919/268/501386350/1257/92e5fb39/5976fcf9Nd915775f.png' ]}, {type:'attr',tag:'img',attr:'data-tips',vals:[ '#东精选' ]} ]}, //品质优选 {name:'品质优选',nameN:'非品质优选',lv:1,conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '只为品质生活' ]} ]}, //#东超市 {name:'#东超市',nameN:'非#东超市',lv:1,conditions:[ {type:'text',tag:'span',vals:[ '#东超市' ]} ]}, //Sam's {name:'山姆会员',nameN:'非山姆会员',lv:1,conditions:[ {type:'shop',vals:[ '山姆会员商店官方旗舰店', '山姆会员商店全球购官方旗舰店' ]}, {type:'multi',vals:[ {tag:'span',cls:'price-sams-1'}, {tag:'em',textStart:'¥'} ]}, ]}, //有机 {name:'有机',nameN:'非有机',conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '有机' ]} ]}, //绿色 {name:'绿色',nameN:'非绿色',conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '绿色' ]} ]}, //无公害 {name:'无公害',nameN:'非无公害',conditions:[ {type:'text',tag:'i',vals:[ '无公害' ]} ]}, //三同 {name:'三同',nameN:'非三同',conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '三同' ]} ]}, //#东检测 {name:'#东检测',nameN:'非#东检测',conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '#东检测' ]} ]}, //双11保价 {name:'双11保价',nameN:'无双11保价',conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '商品当前价格已与11.11当天一致,买贵返还差额' ]} ]}, //老字号 {name:'老字号',nameN:'非老字号',conditions:[ {type:'text',tag:'i',vals:[ '老字号' ]} ]}, //地标产品 {name:'地标产品',nameN:'非地标产品',conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ '地标产品' ]} ]}, //ASC {name:'ASC',nameN:'非ASC',conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ 'ASC' ]} ]}, //BAP {name:'BAP',nameN:'非BAP',conditions:[ {type:'attr',tag:'i',attr:'data-tips',vals:[ 'BAP' ]} ]}, //海产品捕捞认证 {name:'海捕证',nameN:'无海捕证',conditions:[ {type:'text',tag:'i',vals:[ '海产品捕捞认证' ]} ]}, //商家客服 {name:'商家客服',nameN:'无商家客服',lv:1,conditions:[ {type:'attr',tag:'b',attr:'title',vals:[ '联系客服' ]}, {type:'attr',tag:'em',attr:'title',vals:[ '联系供应商进行咨询', '联系第三方卖家进行咨询', '供应商客服不在线,可留言' ]} ]}, //抢购中 {name:'抢购中',nameN:'非抢购中',conditions:[ {type:'multi',vals:[ {tag:'div',cls:'p-presell-time'}, {tag:'span',textAny:['抢购中']} ]} ]}, //有货 {name:'有货',nameN:'无货',conditions:[ {type:'multi',not:true,vals:[ {tag:'div',cls:'p-stock',textAny:['无货']} ]} ]}, //预订 {name:'预订',nameN:'非预订',conditions:[ {type:'multi',vals:[ {tag:'div',cls:'p-stock',textAny:['预订']} ]} ]}, //配送 {name:'支持配送',nameN:'不支持配送',conditions:[ {type:'multi',not:true,vals:[ {tag:'div',cls:'p-stock',textAny:['不支持配送']} ]} ]}, //二手有售 {name:'二手有售',nameN:'非二手有售',conditions:[ {type:'multi',vals:[ {tag:'a',cls:'spu-link',texts:['二手有售']} ]} ]}, //二手 {name:'二手',nameN:'非二手',conditions:[ {type:'multi',vals:[ {tag:'span',cls:'p-tag',texts:['拍拍']} ]} ]}, //2人拼 {name:'2人拼',nameN:'非2人拼',conditions:[ {type:'text',tag:'span',vals:[ '2人拼' ]} ]}, //放心购 {name:'放心购',nameN:'非放心购',conditions:[ {type:'text',tag:'i',vals:[ '放心购' ]} ]}, //#心东东 {name:'#心东东',nameN:'非#心东东',conditions:[ {type:'text',tag:'span',vals:[ '#心东东' ]} ]}, //广告 {name:'广告',nameN:'非广告',conditions:[ {type:'text',tag:'span',vals:[ '广告' ]} ]}, //本地仓 {name:'本地仓',nameN:'非本地仓',conditions:[ {type:'text',tag:'i',vals:[ '本地仓' ]} ]}, //商品名匹配 {name:'商品名匹配',nameN:'商品名不匹配',conditions:[ {type:'multi',vals:[ {tag:'div',cls:'p-name'}, {tag:'em'} ]}], _hlInfo:{ //私有数据 tag: 'b', cls: 'hl', getEmTag: function(elem) { return elem.emTag || (elem.emTag = elem.getElementsByClassName('p-name')[0].getElementsByTagName('em')[0]); } }, onPassed: function(elem) { //过滤器命中时执行:先取消高亮,再重新高亮 if (!unsafeWindow.x$.highlightGoodsPattern) return this.onMissed(elem); var hlInfo = this._hlInfo; var em = hlInfo.getEmTag(elem); var condVal = this.conditions[0].vals[1]; var match = condVal.textAny || condVal.textAll || condVal.textRex; if (!match) return this.onMissed(elem); var hlMatch = elem.highlighted; var html = em.innerHTML; var hlHtml = hlMatch === undefined ? highlightHtml(html, match, hlInfo) : //新加高亮 replaceHighlightHtml(html, match, hlMatch, hlInfo); //已经高亮过,尝试替换 if (hlHtml !== null) { elem.highlighted = match; em.innerHTML = hlHtml; } }, onMissed: function(elem) { //过滤器未命中时执行:取消高亮 if (!elem.highlighted) return; var hlInfo = this._hlInfo; var em = hlInfo.getEmTag(elem); var html = unhighlightHtml(em.innerHTML, hlInfo); if (html) em.innerHTML = html; delete elem.highlighted; }, init: function() { //过滤器初始化,只运行一次 var hlInfo = this._hlInfo; hlInfo.tag0 = []; for(var i=1; i<=9; ++i) hlInfo.tag0.push('<'+hlInfo.tag+' class="'+hlInfo.cls+i+'">'); hlInfo.tag1 = '</'+hlInfo.tag+'>'; } } ]; //过滤器处理程序 var goodsFilterMap = { attr: function(elem, cond) { var tags = elem.getElementsByTagName(cond.tag); for (var i=0; i<tags.length; ++i) { var attr = tags[i].getAttribute(cond.attr); if (attr !== null && includesAny(attr, cond.vals)) return true; } return false; }, text: function(elem, cond) { var tags = elem.getElementsByTagName(cond.tag); for (var i=0; i<tags.length; ++i) { var text = tags[i].innerText; if (text.length > 0 && (text = text.trim()).length > 0 && includesAny(text, cond.vals)) return true; } return false; }, multi: function(elem, cond) { return filterTag(elem, cond.vals, 0); function filterTag(elem, conds, ci) { var cond = conds[ci]; var tags = elem.getElementsByTagName(cond.tag); for (var i = 0; i < tags.length; ++i) { var tag = tags[i]; if (cond.cls && !hasClasses(tag, cond.cls)) continue; //if (cond.attr && !hitAttributes(tag, cond.attr)) continue; var text = tag.innerText.trim(); if (cond.texts && (text.length === 0 || !isAny(text, cond.texts))) continue; if (cond.textAny && (text.length === 0 || !includesAny(text, cond.textAny))) continue; if (cond.textAll && (text.length === 0 || !includesAll(text, cond.textAll))) continue; if (cond.textStart && (text.length === 0 || !text.startsWith(cond.textStart))) continue; // if (cond.textEnd && (text.length === 0 || !text.endsWith(cond.textEnd))) continue; // if (cond.textSub && (text.length === 0 || !text.includes(cond.textSub))) continue; if (cond.textRex && (text.length === 0 || (cond.textRex.lastIndex = 0) || !cond.textRex.test(text))) continue; return (++ci === conds.length) || filterTag(tag, conds, ci); } return false; function hasClasses(e,c) { if (!(c instanceof Array)) return e.classList.contains(c); for (var i=0; i<c.length; ++i) if (!e.classList.contains(c[i])) return false; return true; } // function hitAttributes(e,c) { // if (!(c instanceof Array)) return hitAttribute(e, c); // for (var i=0; i<c.length; ++i) if (!hitAttribute(e, c[i])) return false; // return true; // function hitAttribute(e,c) { // var a = e.getAttribute(c.attr); // return a !== null && includesAny(a, c.vals); // } // } } }, shop: function(elem, cond) { var tags = elem.getElementsByTagName('div'); for (var i=0; i<tags.length; ++i) { var tag = tags[i]; if (tag.classList.contains('p-shop')) { var tags2 = tag.getElementsByTagName('a'); for (var j=0; j<tags2.length; ++j) { var title = tags2[j].title; if (title.length > 0 && (title = title.trim()).length > 0 && cond.vals.includes(title)) return true; } } } return false; }//, // fn: function(elem, cond) { // for (var i=0; i<cond.vals.length; ++i) { // if (cond.vals[i](elem, cond)) return true; // } // return false; // } }; //防止页面重入 if (document.getElementById('goodsFilter'+jdGoodsFilters[0].name) !== null) return; //扫描页面的间隔频率时间 var timerFreq = 333; //当前页面路径 var currentPathname = location.pathname.toLowerCase(); if (currentPathname.startsWith('/pinpai/')) currentPathname = '/search'; //#东自带过滤器和排序选项 var jdFilters = { #东配送: {type:0, gm_name:'#东配送', val:'1'}, 货到付款: {type:0, gm_name:'货到付款', val:'1'}, 仅显示有货: {type:0, gm_name:'仅显示有货', name:'stock',val:'1',def:'0'}, 排序: {type:1, gm_name:'排序', vals:[ //综合没有值 'sort_dredisprice_desc', 'sort_dredisprice_asc', 'sort_totalsales15_desc', 'sort_commentcount_desc', 'sort_winsdate_desc' ]} }; //检查插件数据 CheckSettings(true); //通过重定向应用保存的#东自带过滤器和排序选项(v0.5.3.3 - jd更新【#东配送】【货到付款】等选项的参数后,某些情况商品页面会自动跳转到登录页,此版中暂时禁用。很久以后有时间了再修吧) //var newSearch = OnDocStart(); //if (newSearch !== undefined) location.search = newSearch; //else setTimeout(OnDocReady, 0); //载入【#东配送】【仅显示有货】和排序的设置,返回重定向的路径 function OnDocStart() { switch (currentPathname) { case '/search': jdFilters.#东配送.name = 'wtype'; jdFilters.货到付款.name = 'cod'; jdFilters.排序.name = 'psort'; break; case '/list.html': jdFilters.#东配送.name = 'delivery'; jdFilters.货到付款.name = 'delivery_daofu'; jdFilters.货到付款.val = '3'; jdFilters.排序.name = 'sort'; break; } var urlOpts = url2Obj(); if (readOpts(urlOpts)) { var newSearch = '?'; for (var opt in urlOpts) { if (newSearch.length > 1) newSearch += '&'; newSearch += opt; newSearch += '='; newSearch += urlOpts[opt]; } return newSearch.length > 1 ? newSearch : ''; } function url2Obj() { var ret = {}; var u = location.search.split(/[\?&]/); for (var i in u) { var opt = u[i]; if (opt.length > 0) { opt = opt.split('='); ret[opt[0]] = opt[1]; } } return ret; } function readOpts(opts) { var modified; for (var optKey in jdFilters) { var opt = jdFilters[optKey]; switch (opt.type) { case 0: modified |= readFilterOpt(opts, opt); break; case 1: modified |= readSortOpt(opts, opt); break; } } return modified; function readFilterOpt(opts, opt) { if (GM_getValue(opt.gm_name)) { //有保存的值 if (!opts.hasOwnProperty(opt.name) || opts[opt.name] !== opt.val) { opts[opt.name] = opt.val; return true; } } else { //没有保存的值 if (opt.def !== undefined) { //不允许url不带该参数 if (opts.hasOwnProperty(opt.name)) { if (opts[opt.name] !== opt.def) { opts[opt.name] = opt.def; return true; } } else { opts[opt.name] = opt.def; return true; } } else if (opts.hasOwnProperty(opt.name) && opts[opt.name] !== '0') { delete opts[opt.name]; return true; } } return false; } function readSortOpt(opts, opt) { var sortOpt = GM_getValue(opt.gm_name); switch (currentPathname) { case '/search': if (sortOpt !== undefined) ++sortOpt; break; case '/list.html': sortOpt = jdFilters.排序.vals[sortOpt]; break; } if (sortOpt !== undefined) { if (!opts.hasOwnProperty(opt.name) || urlOpts[opt.name] != sortOpt) { urlOpts[opt.name] = sortOpt; return true; } } else if (opts.hasOwnProperty(opt.name)) { delete opts[opt.name]; return true; } return false; } } } //载入页面后,为页面增加【自营】【非自营】等过滤器 function OnDocReady() { //防止页面重入 if (document.getElementById('goodsFilter'+jdGoodsFilters[0].name) !== null) return; runMain(); //页面入口点 function runMain() { if ($ && $.fn && $.fn.jquery) { enableAllFilters(); loadAllSettings(); initAllFilters(); uiInitAndLoadAllGoods(); } else setTimeout(runMain, timerFreq); function enableAllFilters() { for (var i=0; i<jdGoodsFilters.length; ++i) if (jdGoodsFilters[i].lv === undefined) jdGoodsFilters[i].lv = 1; } //加载设置 function loadAllSettings() { unsafeWindow.x$ = { //init:设置数据缓冲 infoLogText: '正在等待商品列表加载,请稍候……' }; unsafeWindow.y$ = {}; //init:设置控件引用缓冲 unsafeWindow.z$ = {}; //init:设置临时缓冲 loadAllFiltersStates(); //加载过滤器选中状态 loadFilterMode(); //加载过滤方式 loadMisc(); //加载其他设置 function loadAllFiltersStates() { for (var i=0; i<jdGoodsFilters.length; ++i) { var f = jdGoodsFilters[i]; //加载启用状态 f.level = GM_getValue('level'+f.name); if (f.level === undefined && f.lv !== undefined) f.level = f.lv; //加载选中状态 f.checked = undefined === GM_getValue(f.name); f.checkedN = undefined === GM_getValue(f.nameN); } //【商品名匹配使用正则】设置 var useRegex = GM_getValue('商品名匹配正则'); if (useRegex !== undefined) unsafeWindow.x$.useRegexChecked = true; //init:商品名匹配正则 //【商品名匹配高亮】设置 if (GM_getValue('商品名匹配不高亮') === undefined) unsafeWindow.x$.highlightGoodsPattern = true; //init:商品名匹配高亮 //【商品名匹配】过滤器 var cond = jdGoodsFilters[jdGoodsFilters.findIndex(function(j) {return j.name === '商品名匹配';})].conditions[0].vals[1]; var pattern = GM_getValue('商品名匹配规则'); if (pattern !== undefined) { unsafeWindow.x$.goodsPattern = pattern; if (useRegex) cond.textRex = ToRegex(pattern); else { var txtCond = ToTextCond(pattern); if (txtCond.allMatch) cond.textAll = txtCond.txts; else cond.textAny = txtCond.txts; } } unsafeWindow.x$.goodsPatternCondition = cond; //init:商品名匹配规则 } function loadFilterMode() { unsafeWindow.x$.filterModes = [ //init:设置过滤方式字典 'akari', 'haruhi', 'cirno', 'yuno', 'mizuki', 'burnIt', 'succubus', 'conan', 'hphphp' ]; unsafeWindow.x$.goodsFilterModeIndex = GM_getValue('过滤方式'); //init:过滤方式索引 if (unsafeWindow.x$.goodsFilterModeIndex === undefined) unsafeWindow.x$.goodsFilterModeIndex = 0; //init:过滤方式索引没有保存 else if (unsafeWindow.x$.goodsFilterModeIndex < 0 || unsafeWindow.x$.goodsFilterModeIndex >= unsafeWindow.x$.filterModes.length) unsafeWindow.x$.goodsFilterModeIndex = 0; //init:过滤方式索引超限 unsafeWindow.x$.goodsFilterModeClass = unsafeWindow.x$.filterModes[unsafeWindow.x$.goodsFilterModeIndex]; //init:过滤方式的className if (GM_getValue('后排') !== undefined) unsafeWindow.x$.filteredToLastChecked = true; //init:后排设置 } function loadMisc() { if (GM_getValue('老爷机不要动画') !== undefined) unsafeWindow.x$.noAnimateChecked = true; //init:关闭动画设置 } } //初始化过滤器 function initAllFilters() { for (var i=0; i<jdGoodsFilters.length; ++i) { var f = jdGoodsFilters[i]; if (f.init !== undefined) f.init(); } } } //向页面添加自营过滤选项 function uiInitAndLoadAllGoods() { var uiPos = $(document.querySelector('.f-feature ul')); if (uiPos.length > 0) { //改造#东自身过滤器和排序按钮 hookJdFilters(); //向页面添加过滤器 addFiltersParts(); //分页面情况处理后续是否加载商品 switch (currentPathname) { case '/search': if (document.querySelector('div.notice-filter-nor###lt') !== null) { //搜索没有结果 updateInfoLog(''); return; } } //UI 初始化成功,加载所有商品 loadAllGoods(); } else setTimeout(uiInitAndLoadAllGoods, timerFreq); function hookJdFilters() { switch (currentPathname) { case '/search': //【#东配送】【货到付款】【仅显示有货】【全球配送】【节日促销】按钮重载 searchlog uiPos.find('li a[onclick]').each(function() { var tagA = $(this); if (tagA.attr('onclick').length > 0) this.oldOnClick = this.onclick; tagA.removeAttr('onclick'); tagA.click(function() { if (this.oldOnClick !== undefined) { this.oldOnClick(); var waitAjaxLoadGoodsList = function() { if (unsafeWindow.SEARCH.loading) setTimeout(waitAjaxLoadGoodsList, timerFreq); else runMain(); }; setTimeout(waitAjaxLoadGoodsList, timerFreq); } }); }); //【综合】【销量】【评论】【新品】【价格】排序按钮重载 hookSearchSortHtml(); //翻页按钮重载 hookPager(); //重载搜索排序函数,保存排序选项 hookSearchSort(); //【#东配送】【货到付款】【仅显示有货】按钮 jdFilters.#东配送.aTag = uiPos.find('li a[data-field="wtype"]').first(); jdFilters.货到付款.aTag = uiPos.find('li a[data-field="cod"]').first(); jdFilters.仅显示有货.aTag = uiPos.find('li a[data-field="stock"]').first(); break; case '/list.html': //【综合】【销量】【价格】【评论】【上架】排序按钮重载,保存排序设置 $(document.querySelectorAll('#J_filter div.f-sort a:not([id])')).click(function() { var aTagSort = $(this); setTimeout(function() { var sortOpt = aTagSort.attr('href').match(/[&\?]sort=([^&]*)/i); if (sortOpt && 2 === sortOpt.length) { sortOpt = unescape(sortOpt[1]); for (var i=0; i<jdFilters.排序.vals.length; ++i) { if (sortOpt === jdFilters.排序.vals[i]) { GM_setValue(jdFilters.排序.gm_name, i); break; } } } else GM_deleteValue(jdFilters.排序.gm_name); }, 0); }); //【#东配送】【货到付款】【仅显示有货】按钮 switch (location.host) { case 'list.jd.com': jdFilters.#东配送.aTag = uiPos.find('li#delivery a').first(); jdFilters.货到付款.aTag = uiPos.find('li#delivery_daofu a').first(); jdFilters.仅显示有货.aTag = uiPos.find('li#stock a').first(); break; case 'coll.jd.com': jdFilters.#东配送.aTag = uiPos.find('li a:contains(#东配送)').first(); jdFilters.货到付款.aTag = uiPos.find('li a:contains(货到付款)').first(); jdFilters.仅显示有货.aTag = uiPos.find('li a:contains(仅显示有货)').first(); break; } break; } //【#东配送】按钮保存设置 jdFilters.#东配送.aTag.click(function() { setTimeout(function() { if (jdFilters.#东配送.aTag.hasClass('selected') ^ (currentPathname === '/search')) GM_deleteValue(jdFilters.#东配送.gm_name); else GM_setValue(jdFilters.#东配送.gm_name, true); }, 0); }); //【货到付款】按钮保存设置 jdFilters.货到付款.aTag.click(function() { setTimeout(function() { if (jdFilters.货到付款.aTag.hasClass('selected') ^ (currentPathname === '/search')) GM_deleteValue(jdFilters.货到付款.gm_name); else GM_setValue(jdFilters.货到付款.gm_name, true); }, 0); }); //【仅显示有货】按钮保存设置 jdFilters.仅显示有货.aTag.click(function() { setTimeout(function() { if (jdFilters.仅显示有货.aTag.hasClass('selected') ^ (currentPathname === '/search')) GM_deleteValue(jdFilters.仅显示有货.gm_name); else GM_setValue(jdFilters.仅显示有货.gm_name, true); }, 0); }); function hookSearchSortHtml() { if (unsafeWindow.SEARCH !== undefined && unsafeWindow.SEARCH.sort_html !== undefined) { if (unsafeWindow.SEARCH.oldFunc_sort_html === undefined) { unsafeWindow.SEARCH.oldFunc_sort_html = unsafeWindow.SEARCH.sort_html; unsafeWindow.SEARCH.sort_html = function(C) { //重载 SEARCH.sort_html 函数 unsafeWindow.SEARCH.oldFunc_sort_html(C); //在 loadAllGoods 处理 /search 页面的分支中会调用 SEARCH.scroll 来加载商品列表后半页, //这会导致 SEARCH.sort_html 被再次调用,如果在重载的函数中再次【直接】【自动】调用 loadAllGoods 会构成递归溢出, //因此必须将 loadAllGoods 的调用放在排序按钮的 onclick 事件响应里面,并删除原始的 onclick 属性内联调用 $(document.querySelectorAll('#J_filter div.f-sort a[onclick]')).each(function() { var tagA = $(this); if (tagA.attr('onclick').length > 0) this.oldOnClick = this.onclick; tagA.removeAttr('onclick'); tagA.click(function() { if (this.oldOnClick !== undefined) { this.oldOnClick(); var waitAjaxLoadGoodsList = function() { if (unsafeWindow.SEARCH.loading) setTimeout(waitAjaxLoadGoodsList, timerFreq); else loadAllGoods(); }; setTimeout(waitAjaxLoadGoodsList, timerFreq); } }); }); }; } } else setTimeout(hookSearchSortHtml, timerFreq); } function hookPager() { if (undefined !== unsafeWindow.SEARCH && undefined !== unsafeWindow.SEARCH.page) { if (unsafeWindow.SEARCH.oldFunc_page === undefined) { unsafeWindow.SEARCH.oldFunc_page = unsafeWindow.SEARCH.page; unsafeWindow.SEARCH.page = function(F, C) { //重载 SEARCH.page 函数 unsafeWindow.SEARCH.oldFunc_page(F, C); //loadAllGoods 不会与 SEARCH.page 发生嵌套循环调用,所以可以在重载函数内直接调用 loadAllGoods var waitAjaxLoadGoodsList = function() { if (unsafeWindow.SEARCH.loading) setTimeout(waitAjaxLoadGoodsList, timerFreq); else loadAllGoods(); }; setTimeout(waitAjaxLoadGoodsList, timerFreq); }; } } else setTimeout(hookPager, timerFreq); } function hookSearchSort() { if (unsafeWindow.SEARCH !== undefined && unsafeWindow.SEARCH.sort !== undefined) { if (unsafeWindow.SEARCH.oldFunc_sort === undefined) { unsafeWindow.SEARCH.oldFunc_sort = unsafeWindow.SEARCH.sort; unsafeWindow.SEARCH.sort = function(A) { //重载 SEARCH.sort 函数 unsafeWindow.SEARCH.oldFunc_sort(A); setTimeout(function() { if (!A) GM_deleteValue(jdFilters.排序.gm_name); else GM_setValue(jdFilters.排序.gm_name, A-1); }, 0); }; } } else setTimeout(hookSearchSort, timerFreq); } } function addFiltersParts() { //向页面添加样式表 if (document.getElementById('styleGoodsFilters') === null) GM_addStyle( //计数器占位符和计数器样式 'span.goodsCountPlaceholder{width:36px;display:inline-block;}'+ 'span.goodsCount{font-size:10px;color:#fff;background-color:#e23a3a;border-radius:3px;padding:0px 3px;}'+ //顶级过滤器样式 'div.f-feature>ul>li>a>span.goodsCount{margin-left:2px;}'+ //过滤器样式(必须带【.filter .f-feature ul li】前置,否则会被#东自身样式覆盖) '.filter .f-feature ul li a{padding-right:8px;}'+ '.filter .f-feature ul li a.filterN{color:#888;}'+ '.filter .f-feature ul li a.filterN:hover{color:#e23a3a;}'+ '.filter .f-feature ul li a.filterN.selected i{border-color:rgba(228,57,60,0.3);}'+ '.filter .f-feature ul li a.filterN.selected:hover i{border-color:#e4393c;}'+ '.filter .f-feature ul li a.zeroCountGoods{color:#ccc;}'+ '.filter .f-feature ul li a.zeroCountGoods.selected i{border-color:#ccc;}'+ '.filter .f-feature ul li a.zeroCountGoods span.goodsCount{background-color:#ccc;}'+ '.filter .f-feature ul li a.zeroCountGoods:hover{color:#e23a3a;}'+ '.filter .f-feature ul li a.zeroCountGoods.selected:hover i{border-color:#e4393c;}'+ //【下级过滤器】按钮 '.filter .f-feature ul li.showMoreFilters{padding-right:12px;}'+ '.filter .f-feature ul li.showMoreFilters a{padding:0 2px;color:#e23a3a;line-height:normal;border:1px solid #e23a3a;border-radius:3px;}'+ '.filter .f-feature ul li.showMoreFilters a.opened{color:white;background:#e23a3a;}'+ //过滤器数量蓝点 '.filter .f-feature ul li.showMoreFilters a #moreFiltersCount{color:white;background:dodgerblue;position:absolute;top:-4px;right:-10px;width:16px;height:16px;line-height:15px;border-radius:8px;font-size:8px;text-align:center;user-select:none;cursor:pointer;}'+ //过滤器面板 '#moreFiltersPanel{border:1px solid #E7E3E7;z-index:0;}'+ '#moreFiltersPanel *{white-space:nowrap;}'+ //过滤器表格和动作条分割线 '#moreFiltersPanel hr{margin:0 5px;border:0;border-top:1px solid #E7E3E7;}'+ //过滤器面板div布局 '#moreFiltersPanel div{display:flex;justify-content:center;align-items:center;}'+ //过滤器表格样式 'table.f-feature{margin:3px 0;border-collapse:collapse;}'+ 'table.f-feature td{padding:0 5px;text-align:center;}'+ //过滤器组分割线 'table.f-feature td:nth-child(3n+4){border-left:1px solid #E7E3E7;}'+ //左侧过滤器样式 'table.f-feature td:nth-child(3n+1){text-align:right;}'+ 'table.f-feature td:nth-child(3n+1) ul li a{padding:0;}'+ 'table.f-feature td:nth-child(3n+1) ul li a i{margin:0 0 0 4px;position:relative;top:3px;left:auto;right:0;}'+ //右侧过滤器样式 'table.f-feature td:nth-child(3n+3){text-align:left;}'+ 'table.f-feature td:nth-child(3n+3) ul li a{padding:0;}'+ 'table.f-feature td:nth-child(3n+3) ul li a i{margin:0 4px 0 0;position:relative;top:3px;left:0;right:auto;}'+ //右侧过滤器计数样式 'a.filterN span.goodsCount{background-color:rgba(226,58,58,0.3);}'+ 'a.filterN:hover span.goodsCount{background-color:#e23a3a;}'+ //自定义匹配 '#regFilter{margin:0 5px;}'+ '#regFilter .txt{margin:5px 0;padding:0 2px;width:50%;border:1px solid #E7E3E7;font-size:12px;color:#666;}'+ '.gl-item .p-name em b{font-weight:normal;}'+ '.gl-item .p-name em .hl1{background:hsla(0,100%,50%,0.5);}'+ '.gl-item .p-name em .hl2{background:hsla(200,100%,50%,0.5);}'+ '.gl-item .p-name em .hl3{background:hsla(40,100%,50%,0.5);}'+ '.gl-item .p-name em .hl4{background:hsla(240,100%,50%,0.5);}'+ '.gl-item .p-name em .hl5{background:hsla(80,100%,50%,0.5);}'+ '.gl-item .p-name em .hl6{background:hsla(280,100%,50%,0.5);}'+ '.gl-item .p-name em .hl7{background:hsla(120,100%,50%,0.5);}'+ '.gl-item .p-name em .hl8{background:hsla(320,100%,50%,0.5);}'+ '.gl-item .p-name em .hl9{background:hsla(160,100%,50%,0.5);}'+ //动作条按钮 '#moreFiltersPanel a.btn.btn-default{margin:5px;}'+ '#moreFiltersPanel a.btn.btn-default.btn-icon{padding:4px 5px;}'+ '#moreFiltersPanel a.btn-icon{margin:5px;height:25px;}'+ //动作条checkbox '#moreFiltersPanel .ckbox{margin:1px 0 0 6px;}'+ //动作条图标 '#actionBar i{display:inline-block;width:25px;height:25px;background:url(https://misc.360buyimg.com/user/passport/1.0.0/widget/login-form-2016-1124/i/qr-coagent.png) no-repeat;}'+ //动作条提示 '#actionBar i.info{margin:0 5px;background-position-x:-27px;}'+ '#actionBar #infoLog{color:blue;font-weight:bold;}'+ //动作条下拉选择框 '#actionBar select{padding:0 20px 0 3px;border:1px solid #E7E3E7;font-size:12px;color:#666;-webkit-appearance: none;background:url(//misc.360buyimg.com/product/list/1.0.7/css/i/search.ele.png) no-repeat 78px 5px;}'+ '#actionBar select:hover{background-position-y:-12px;}'+ //被过滤商品的样式 'li.gl-item:hover{filter:none;}'+ 'li.gl-item:hover .gl-i-wrap .p-img{filter:none;}'+ //样式0:淡化 'li.akari{background-color:#fff;filter:opacity(10%);}'+ 'li.akari:hover .gl-i-wrap div{filter:opacity(30%);}'+ '.goods-list-v1 .gl-item.akari:hover{border-color:#ccc;}'+ '.goods-list-v2 .gl-item.akari:hover .gl-i-wrap {border-color:#ccc;}'+ //样式1:隐藏 'li.haruhi{display:none;}'+ //样式2:边框 'li.cirno{background-color:#fff;}'+ 'li.cirno:hover .gl-i-wrap div{filter:opacity(30%);}'+ '.goods-list-v1 .gl-item.cirno{border-color:#000;}'+ '.goods-list-v1 .gl-item.cirno:hover{border-color:#48f;}'+ '.goods-list-v2 .gl-item.cirno .gl-i-wrap {border-color:#000;}'+ '.goods-list-v2 .gl-item.cirno:hover .gl-i-wrap {border-color:#48f;}'+ //样式3:黑白 'li.yuno{background-color:#fff;filter:grayscale(100%) brightness(60%);}'+ 'li.yuno:hover .gl-i-wrap div{filter:grayscale(100%);}'+ '.goods-list-v1 .gl-item.yuno:hover{border-color:#888;}'+ '.goods-list-v2 .gl-item.yuno:hover .gl-i-wrap {border-color:#888;}'+ //样式4:转色 'li.mizuki{background-color:#fff;filter:hue-rotate(180deg);}'+ 'li.mizuki:hover .gl-i-wrap div{filter:hue-rotate(180deg);}'+ '.goods-list-v1 .gl-item.mizuki:hover{border-color:#3af;}'+ '.goods-list-v2 .gl-item.mizuki:hover .gl-i-wrap {border-color:#3af;}'+ //样式5:异端通通烧死 'li.burnIt{background-color:#fff;filter:sepia(100%);}'+ 'li.burnIt:hover .gl-i-wrap div{filter:sepia(100%);}'+ '.goods-list-v1 .gl-item.burnIt:hover{border-color:#e85;}'+ '.goods-list-v2 .gl-item.burnIt:hover .gl-i-wrap {border-color:#e85;}'+ //样式6:模糊 'li.succubus{background-color:#fff;filter:blur(5px);}'+ 'li.succubus:hover .gl-i-wrap div{filter:blur(1.2px);}'+ '.goods-list-v1 .gl-item.succubus:hover{border-color:#f3c;}'+ '.goods-list-v2 .gl-item.succubus:hover .gl-i-wrap {border-color:#f3c;}'+ //样式7:反色 'li.conan{background-color:#fff;filter:invert(100%);}'+ 'li.conan:hover .gl-i-wrap div{filter:invert(100%);}'+ '.goods-list-v1 .gl-item.conan:hover{border-color:#000;}'+ '.goods-list-v2 .gl-item.conan:hover .gl-i-wrap {border-color:#000;}'+ //样式8:暗刻 'li.hphphp{background-color:#fff;filter:grayscale(10%) contrast(50) sepia(100%) saturate(100) hue-rotate(180deg) invert(100%) blur(1px);}'+ 'li.hphphp:hover .gl-i-wrap div{filter:grayscale(10%) contrast(50) sepia(100%) saturate(100) hue-rotate(180deg) invert(100%) blur(1px);}'+ '.goods-list-v1 .gl-item.hphphp:hover{border-color:#000;}'+ '.goods-list-v2 .gl-item.hphphp:hover .gl-i-wrap {border-color:#000;}'+ '' ).id = 'styleGoodsFilters'; //生成顶级过滤器HTML var uiPrependFilters = ''; for (var i=0; i<jdGoodsFilters.length; ++i) { var f = jdGoodsFilters[i]; if (f.level !== 0) continue; //剔除不是顶级的 var checkedClass = f.checked ? 'class="selected"' : ''; var checkedNClass = f.checkedN ? 'class="filterN selected"' : 'class="filterN"'; uiPrependFilters += '<li><a '+checkedClass+' href="javascript:;" id="goodsFilter'+f.name+'" filterId="'+i+'">'+ '<i></i>'+f.name+'<span class="goodsCount" id="goodsCount'+f.name+'">0</span>'+ '</a></li>'+ '<li><a '+checkedNClass+' href="javascript:;" id="goodsFilter'+f.nameN+'" filterId="'+i+'">'+ '<i></i>'+f.nameN+'<span class="goodsCount" id="goodsCount'+f.nameN+'">0</span>'+ '</a></li>'; } //生成【下级过滤器】按钮HTML uiPrependFilters += '<li class="showMoreFilters">'+ '<a id="showMoreFiltersPanel" href="javascript:;">'+ '下级过滤器'+ '<span id="moreFiltersCount" class="zeroFiltersCount" style="display:none;">0</span>'+ '</a>'+ '</li>'; //添加顶级过滤器和【下级过滤器】按钮 uiPos.first().prepend($(uiPrependFilters)); //保存控件引用 unsafeWindow.y$.aShowMoreFiltersPanel = $(document.getElementById('showMoreFiltersPanel')); unsafeWindow.y$.spanMoreFiltersCount = $(document.getElementById('moreFiltersCount')); //更新过滤器计数 var spanMoreFiltersCount = updateUsingMoreFiltersCount(); //添加顶级过滤器和【下级过滤器】按钮 //安装顶级过滤器响应函数 installFilterClickHandler(0); //安装【下级过滤器】按钮响应函数 unsafeWindow.y$.aShowMoreFiltersPanel.click(function() { setTimeout(toggleMoreFiltersPanel, 0); }); //根据保存的设置打开下级过滤器面板 if (GM_getValue('打开下级过滤器面板') !== undefined) toggleMoreFiltersPanel(true); //否则根据计数显示过滤器计数圆点 else if (!spanMoreFiltersCount.hasClass('zeroFiltersCount')) spanMoreFiltersCount.css('display', ''); //初始化不用动画 //安装过滤器响应函数 function installFilterClickHandler(level) { for (var i=0; i<jdGoodsFilters.length; ++i) { var f = jdGoodsFilters[i]; if (f.level !== level) continue; //剔除不是传入等级的 //绑定HTML元素 f.aFilter = document.getElementById('goodsFilter'+f.name); f.spanFilterCount = document.getElementById('goodsCount'+f.name); f.aFilterN = document.getElementById('goodsFilter'+f.nameN); f.spanFilterNCount = document.getElementById('goodsCount'+f.nameN); //初始化标记 f.created = true; //安装点击响应函数 f.aFilter.addEventListener('click', filterClickHandler); f.aFilterN.addEventListener('click', filterClickHandler); } //过滤器点击响应函数 function filterClickHandler() { if (undefined !== unsafeWindow.z$.currentFilterData) return; //防止重入 unsafeWindow.z$.currentFilterData = this || event.currentTarget || arguments[0].currentTarget; setTimeout(function() { var aFilter = unsafeWindow.z$.currentFilterData; var cl = aFilter.classList; cl.toggle('selected'); var checked = cl.contains('selected'); var filterN = cl.contains('filterN'); var f = jdGoodsFilters[aFilter.getAttribute('filterId')]; if (filterN) f.checkedN = checked; else f.checked = checked; if ((filterN ? f.goodsCountFilteredN+f.goodsCountN : f.goodsCountFiltered+f.goodsCount) !== 0) applyGoodsFilters(); //过滤器点击响应 //更新过滤器计数 if (f.level === 1) updateUsingMoreFiltersCount(); //过滤器点击响应 //保存设置 var valName = filterN ? f.nameN : f.name; if (checked) GM_deleteValue(valName); else GM_setValue(valName, true); delete unsafeWindow.z$.currentFilterData; }, 0); } } //打开/关闭下级过滤器面板 function toggleMoreFiltersPanel(isInitializing) { if (!isInitializing) saveStates(); var div = unsafeWindow.y$.divMoreFiltersPanel; if (div === undefined) { setupMoreFiltersPanel(); div = unsafeWindow.y$.divMoreFiltersPanel; } var span = unsafeWindow.y$.spanMoreFiltersCount; if (unsafeWindow.y$.aShowMoreFiltersPanel.toggleClass('opened').hasClass('opened')) { //保存下级过滤器面板打开状态 GM_setValue('打开下级过滤器面板', true); //显示下级过滤器面板 if (isInitializing || unsafeWindow.x$.noAnimateChecked) { //不允许动画 div.css('display', ''); if (!span.hasClass('zeroFiltersCount')) span.css('display', 'none'); } else { div.slideDown('fast'); if (!span.hasClass('zeroFiltersCount')) span.fadeOut(); } } else { //保存下级过滤器面板关闭状态 GM_deleteValue('打开下级过滤器面板'); //结束正在执行的提醒动画 $('#moreFiltersPanel td:has(a[filterId])').finish(); //querySelectorAll 不支持 :has //关闭下级过滤器面板 if (isInitializing || unsafeWindow.x$.noAnimateChecked) { //不允许动画 div.css('display', 'none'); if (!span.hasClass('zeroFiltersCount')) span.css('display', ''); } else { div.slideUp('fast'); if (!span.hasClass('zeroFiltersCount')) span.fadeIn(); } } //向页面添加下级过滤器面板 function setupMoreFiltersPanel() { var uiFilters = []; //生成过滤器HTML数组 for (var i=0; i<jdGoodsFilters.length; ++i) { var f = jdGoodsFilters[i]; if (f.level !== 1) continue; //剔除不是下级的 var checkedClass = f.checked ? 'class="selected"' : ''; var checkedNClass = f.checkedN ? 'class="filterN selected"' : 'class="filterN"'; uiFilters.push({ name: f.name, filter: '<li><a '+checkedClass+' href="javascript:;" id="goodsFilter'+f.name+'" filterId="'+i+'" title="【'+f.name+'】商品">'+ '<span class="goodsCountPlaceholder"><span class="goodsCount" id="goodsCount'+f.name+'">0</span></span><i></i>'+ '</a></li>', filterN: '<li><a '+checkedNClass+' href="javascript:;" id="goodsFilter'+f.nameN+'" filterId="'+i+'" title="【'+f.nameN+'】商品">'+ '<i></i><span class="goodsCountPlaceholder"><span class="goodsCount" id="goodsCount'+f.nameN+'">0</span></span>'+ '</a></li>' }); } //计算过滤器表格列数 var cols = 6; //生成过滤器表格内容HTML var filtersTableRows = ''; for (var j=0; j<uiFilters.length; j+=cols) { filtersTableRows += '<tr>'; for (var k=0; k<cols; ++k) { var l = j + k; if (l < uiFilters.length) { var m = uiFilters[l]; filtersTableRows += '<td><ul>'+m.filter+'</ul></td><td>'+m.name+'</td><td><ul>'+m.filterN+'</ul></td>'; } else filtersTableRows += '<td></td><td></td><td></td>'; } filtersTableRows += '</tr>'; } //向页面添加过滤器表格 document.getElementById('J_filter').insertAdjacentHTML('beforeend', '<div id="moreFiltersPanel" class="filter" style="display:none;">'+ '<table class="f-feature" style="float:none;">'+filtersTableRows+'</table>'+ '<hr>'+ '<div id="regFilter">'+ '<div style="flex-grow:1;">'+ '<a target="_blank" href="https://www.bilibili.com/video/av15760606" style="color:transparent;text-shadow:transparent 0 0 0!important;">国际通用手势教程</a>'+ '</div>'+ '<div style="flex-grow:1;">'+ '<label for="goodsPattern" title="过滤商品名【包含指定字串】或【匹配指定正则表达式】的商品">商品名匹配规则:</label><input id="goodsPattern" class="txt" type=text title="键入【回车】或点击【手动更新过滤结果】以应用商品名匹配规则"></input>'+ '<input class="ckbox" id="useRegex" type="checkbox"><label for="useRegex" title="'+ '普通模式:\n'+ '支持搜索多个值,以反引号【`】分隔值列表,\n'+ '值列表以反引号开头采用同时命中规则(AND),\n'+ '否则采用任一命中规则(OR)\n'+ '\n'+ '正则模式:【程序猿&攻城狮专用 ◕◡◕✧】\n'+ '支持 js 正则语法(正斜线分隔)\n'+ '非正则语法的情况下默认追加 igm 标志'+ '">正则</label>'+ '<input class="ckbox" id="highlightGoodsPattern" type="checkbox"><label for="highlightGoodsPattern">高亮</label>'+ '</div>'+ '<div style="flex-grow:1;">'+ '<a target="_blank" href="https://www.bilibili.com/video/av17978378" style="color:transparent;text-shadow:transparent 0 0 0!important;">脸控福利</a>'+ '</div>'+ '</div>'+ '<hr>'+ '<div id="actionBar">'+ '<a id="allFiltersReset" class="btn btn-default" href="javascript:;">重置全部过滤器</a>'+ '<a id="moreFiltersReset" class="btn btn-default" href="javascript:;">重置下级过滤器</a>'+ '<a id="highlightFilters" class="btn btn-default" href="javascript:;">提醒一下?</a>'+ '<a id="refreshCount" class="btn btn-default" href="javascript:;" title="'+ '一般情况下过滤结果都是正确的,但是不排除因为\n'+ '网络/缓存以及插件本身的 bug 等问题而可能导致\n'+ '过滤结果不准确或者出现各种莫名其妙的错误,\n'+ '此时可尝试手动更新过滤结果。'+ '">手动更新过滤结果</a>'+ '<div style="flex-grow:1;">'+ '<div style="display:none;">'+ '<i class="info"></i><label id="infoLog"></label>'+ '</div>'+ '</div>'+ '<select id="goodsFilterMode">'+ '<option value="0" selected>淡化</option>'+ '<option value="1">隐藏</option>'+ '<option value="2">边框</option>'+ '<option value="3">黑白</option>'+ '<option value="4">转色</option>'+ '<option value="5">异端通通烧死</option>'+ '<option value="6">模糊</option>'+ '<option value="7">反色</option>'+ '<option value="8">暗刻</option>'+ '</select>'+ '<div>'+ '<input id="filteredToLast" class="ckbox" type="checkbox"><label for="filteredToLast" title="o(* ̄3 ̄)o 过滤掉的商品扔到后面去">后排</label>'+ '<input id="noAnimate" class="ckbox" type="checkbox"><label for="noAnimate" title="囧rz">老爷机不要动画!</label>'+ '</div>'+ '<a id="showSettings" class="btn-icon" href="javascript:;" title="一个神秘的按钮……'+ '\n\n按钮背面刻着一串放荡不羁的狂草,'+ '\n经过漫漫五千年的悠久岁月,'+ '\n字迹已经被风化得几乎看不清楚:'+ '\n【欲点此钮,后果自负 ◕◡◕✧】"><i></i></a>'+ '</div>'+ '</div>' ); //保存控件引用 unsafeWindow.y$.divMoreFiltersPanel = $(document.getElementById('moreFiltersPanel')); unsafeWindow.y$.inputGoodsPattern = $(document.getElementById('goodsPattern')); unsafeWindow.y$.checkboxUseRegex = $(document.getElementById('useRegex')); unsafeWindow.y$.checkboxHighlightGoodsPattern = $(document.getElementById('highlightGoodsPattern')); unsafeWindow.y$.aAllFiltersReset = $(document.getElementById('allFiltersReset')); unsafeWindow.y$.aMoreFiltersReset = $(document.getElementById('moreFiltersReset')); unsafeWindow.y$.aHighlightFilters = $(document.getElementById('highlightFilters')); unsafeWindow.y$.aRefreshCount = $(document.getElementById('refreshCount')); unsafeWindow.y$.labelInfoLog = $(document.getElementById('infoLog')); unsafeWindow.y$.selectGoodsFilterMode = $(document.getElementById('goodsFilterMode')); unsafeWindow.y$.checkboxFilteredToLast = $(document.getElementById('filteredToLast')); unsafeWindow.y$.checkboxNoAnimate = $(document.getElementById('noAnimate')); unsafeWindow.y$.aShowSettings = $(document.getElementById('showSettings')); //安装下级过滤器响应函数 installFilterClickHandler(1); //显示下级过滤器面板之前更新计数 applyGoodsFilters(true); //更新下级过滤器面板计数 //正则模式 var inputGoodsPattern = unsafeWindow.y$.inputGoodsPattern; if (unsafeWindow.x$.goodsPattern) inputGoodsPattern.val(unsafeWindow.x$.goodsPattern); inputGoodsPattern.change(function() {setTimeout(updateGoodsPattern, 0);}); inputGoodsPattern.blur(function() {setTimeout(updateGoodsPattern, 0);}); inputGoodsPattern.keypress(function(e) { if (e.keyCode === 13) { updateInfoLog('计算中……'); unsafeWindow.y$.inputGoodsPattern.prop('disabled', true); setTimeout(function() { updateGoodsPattern(); applyGoodsFilters(); unsafeWindow.y$.inputGoodsPattern.prop('disabled', false); updateInfoLog(''); }, 0); } }); //设置checkbox【正则匹配】值和响应函数 if (unsafeWindow.x$.useRegexChecked) unsafeWindow.y$.checkboxUseRegex.prop('checked', true); unsafeWindow.y$.checkboxUseRegex.change(function() { setTimeout(function() { if (unsafeWindow.y$.checkboxUseRegex[0].checked) { unsafeWindow.x$.useRegexChecked = true; //操作更新 GM_setValue('商品名匹配正则', true); } else { delete unsafeWindow.x$.useRegexChecked; GM_deleteValue('商品名匹配正则'); } updateGoodsPattern(true); applyGoodsFilters(); }, 0); }); //设置checkbox【高亮匹配】值和响应函数 if (unsafeWindow.x$.highlightGoodsPattern) unsafeWindow.y$.checkboxHighlightGoodsPattern.prop('checked', true); unsafeWindow.y$.checkboxHighlightGoodsPattern.change(function() { setTimeout(function() { if (unsafeWindow.y$.checkboxHighlightGoodsPattern[0].checked) { unsafeWindow.x$.highlightGoodsPattern = true; //操作更新 GM_deleteValue('商品名匹配不高亮'); } else { delete unsafeWindow.x$.highlightGoodsPattern; GM_setValue('商品名匹配不高亮', true); } applyGoodsFilters(); }, 0); }); //【重置全部过滤器】按钮响应函数 unsafeWindow.y$.aAllFiltersReset.click(function() { resetGoodsFilters(true); }); //【重置下级过滤器】按钮响应函数 unsafeWindow.y$.aMoreFiltersReset.click(function() { resetGoodsFilters(false); }); //【提醒】按钮响应函数 unsafeWindow.y$.aHighlightFilters.click(function() { var filters = $('#moreFiltersPanel td:has(a[filterId])'); //querySelectorAll 不支持 :has var aside = filters.filter(':has(a.selected)'); var bside = filters.not(':has(a.selected)'); if (aside.length === 0 || bside.length === 0) return; filters.finish(); (aside.length < bside.length ? aside : bside) .animate({backgroundColor:'#0cf'}, 100) .animate({backgroundColor:'rgba(0,204,255,0)'}, 5000, function() { this.removeAttribute('style'); }); }); //【手动更新过滤结果】按钮响应函数 unsafeWindow.y$.aRefreshCount.click(function() { updateInfoLog('计算中……'); unsafeWindow.y$.aRefreshCount.prop('disabled', true); setTimeout(function() { saveStates(); var t = Date.now(); var updated = applyGoodsFilters(); //【手动更新过滤结果】按钮响应 t = Date.now() - t; var aTag = unsafeWindow.y$.aRefreshCount; var title0 = aTag.attr('title0'); if (title0 === undefined) { title0 = aTag.attr('title'); aTag.attr('title0', title0); } var log = '上次计算耗时 '+t/1000+' 秒,'+(updated>0?('更新了 '+updated+' 项数据'):'没有需要更新的数据'); aTag.attr('title', title0+'\n【'+log+'】'); aTag.prop('disabled', false); updateInfoLog(''); }, 30); }); //设置infoLog的信息 updateInfoLog(); //根据预设变量显示/隐藏infoLog //设置select值和响应函数 unsafeWindow.y$.selectGoodsFilterMode.val(unsafeWindow.x$.goodsFilterModeIndex).change(function() { unsafeWindow.z$.goodsFilterModeNew = parseInt(event.currentTarget.value); if (unsafeWindow.z$.goodsFilterModeNew === unsafeWindow.x$.goodsFilterModeIndex) { delete unsafeWindow.z$.goodsFilterModeNew; } else setTimeout(function() { if (unsafeWindow.z$.goodsFilterModeNew === undefined) return; //改变当前过滤商品的样式 var ca = unsafeWindow.x$.filterModes[unsafeWindow.z$.goodsFilterModeNew]; var cr = unsafeWindow.x$.goodsFilterModeClass; document.querySelectorAll('li.gl-item.'+unsafeWindow.x$.goodsFilterModeClass).forEach(function(e) { e.classList.add(ca); e.classList.remove(cr); }); //保存设置 if (unsafeWindow.z$.goodsFilterModeNew === 0) GM_deleteValue('过滤方式'); else GM_setValue('过滤方式', unsafeWindow.z$.goodsFilterModeNew); //更新值 unsafeWindow.x$.goodsFilterModeIndex = unsafeWindow.z$.goodsFilterModeNew; //操作更新 delete unsafeWindow.z$.goodsFilterModeNew; unsafeWindow.x$.goodsFilterModeClass = unsafeWindow.x$.filterModes[unsafeWindow.x$.goodsFilterModeIndex]; //操作更新 }, 0); }); //设置checkbox【后排】值和响应函数 if (unsafeWindow.x$.filteredToLastChecked) unsafeWindow.y$.checkboxFilteredToLast.prop('checked', true); unsafeWindow.y$.checkboxFilteredToLast.change(function() { setTimeout(function() { if (unsafeWindow.y$.checkboxFilteredToLast[0].checked) { unsafeWindow.x$.filteredToLastChecked = true; //操作更新 GM_setValue('后排', true); reorderGoodsByFilteredState(); } else { delete unsafeWindow.x$.filteredToLastChecked; GM_deleteValue('后排'); reorderGoodsByOriginalOrder(); } }, 0); }); //设置checkbox【关闭动画】值和响应函数 if (unsafeWindow.x$.noAnimateChecked) unsafeWindow.y$.checkboxNoAnimate.prop('checked', true); unsafeWindow.y$.checkboxNoAnimate.change(function() { setTimeout(function() { if (unsafeWindow.y$.checkboxNoAnimate[0].checked) { unsafeWindow.x$.noAnimateChecked = true; //操作更新 GM_setValue('老爷机不要动画', true); } else { delete unsafeWindow.x$.noAnimateChecked; GM_deleteValue('老爷机不要动画'); } }, 0); }); //神秘按钮 unsafeWindow.y$.aShowSettings.click(function() { setTimeout(CheckSettings, 0); }); //更新正则模式 function updateGoodsPattern(modeSwitched) { var v = unsafeWindow.y$.inputGoodsPattern[0].value; var cond = unsafeWindow.x$.goodsPatternCondition; var hasPattern = v.length > 0; if (hasPattern) { if (!modeSwitched && v === unsafeWindow.x$.goodsPattern) return false; if (unsafeWindow.x$.useRegexChecked) { var rex = ToRegex(v); if (rex !== null) { cond.textRex = ToRegex(v); delete cond.textAny; delete cond.textAll; } else hasPattern = false; } else { var txtCond = ToTextCond(v); if (txtCond.txts.length > 0) { if (txtCond.allMatch) { cond.textAll = txtCond.txts; delete cond.textAny; } else { cond.textAny = txtCond.txts; delete cond.textAll; } delete cond.textRex; } else hasPattern = false; } } if (hasPattern) { unsafeWindow.x$.goodsPattern = v; GM_setValue('商品名匹配规则', v); } else { delete unsafeWindow.x$.goodsPattern; delete cond.textAny; delete cond.textAll; delete cond.textRex; GM_deleteValue('商品名匹配规则'); } } //重置过滤器 function resetGoodsFilters(all) { setTimeout(function() { for (var i=0; i<jdGoodsFilters.length; ++i) { var f = jdGoodsFilters[i]; if (all ? f.level === undefined : f.level !== 1) continue; //重置全部,剔除未启用的;重置下级,剔除不是下级的 if (!f.checked) { f.checked = true; GM_deleteValue(f.name); } if (!f.checkedN) { f.checkedN = true; GM_deleteValue(f.nameN); } } //结束正在执行的提醒动画 $('#moreFiltersPanel td:has(a[filterId])').finish(); //querySelectorAll 不支持 :has //重置选中状态 var n = document.querySelectorAll((all?'':'table')+'.f-feature a[filterId]:not(.selected)'); for (var j=0; j<n.length; ++j) n[j].classList.add('selected'); applyGoodsFilters(); //重置过滤器 }, 0); } } } //保存设置 function saveStates(noPanelState, noFiltersStates, noMisc) { //保存过滤器面板打开状态 if (!noPanelState) { saveBoolIfDiff(unsafeWindow.y$.aShowMoreFiltersPanel.hasClass('opened'), '打开下级过滤器面板'); } //保存过滤器状态 if (!noFiltersStates) { for (var i=0; i<jdGoodsFilters.length; ++i) { var f = jdGoodsFilters[i]; var sname = 'level'+f.name; if (GM_getValue(sname) !== f.level) { if (f.level !== undefined) GM_setValue(sname, f.level); else GM_deleteValue(sname); } if (GM_getValue(f.name)) { if (f.checked) GM_deleteValue(f.name); } else if (!f.checked) GM_setValue(f.name, true); if (GM_getValue(f.nameN)) { if (f.checkedN) GM_deleteValue(f.nameN); } else if (!f.checkedN) GM_setValue(f.nameN, true); } } //保存其他设置 if (!noMisc) { //过滤方式 saveIntIfDiff(unsafeWindow.x$.goodsFilterModeIndex, '过滤方式', true); //过滤掉的商品扔到后面去 saveBoolIfDiff(unsafeWindow.x$.filteredToLastChecked, '后排'); //关闭动画 saveBoolIfDiff(unsafeWindow.x$.noAnimateChecked, '老爷机不要动画'); } function saveIntIfDiff(i, gm_name, undefMeansZero) { var val = GM_getValue(gm_name); if (undefMeansZero) { if (val === undefined) val = 0; if (val !== i) { if (val === 0) GM_deleteValue(gm_name); else GM_setValue(gm_name, i); } } else if (val !== i) GM_setValue(gm_name, i); } function saveBoolIfDiff(b, gm_name) { if (GM_getValue(gm_name)) { if (!b) GM_deleteValue(gm_name); } else if (b) GM_setValue(gm_name, true); } } } } //更新【下级过滤器】的提示和过滤器计数蓝点 function updateUsingMoreFiltersCount() { var moreFiltersTitle = ''; var moreFiltersCount = 0; for (var i=0; i<jdGoodsFilters.length; ++i) { var f = jdGoodsFilters[i]; if (f.level !== 1) continue; //剔除不是下级的 if (f.checked === f.checkedN) { if (f.checked) continue; moreFiltersTitle += '\n同时隐藏了【'+f.name+'】和【'+f.nameN+'】商品所以你啥也看不见了 囧rz'; moreFiltersCount += 2; } else { moreFiltersTitle += '\n隐藏【'+(f.checked ? f.nameN : f.name)+'】商品 '+ (f.checked ? (f.goodsCountFilteredN === f.goodsCountN ? (f.goodsCountN === 0 ? '' : parentheses(f.goodsCountN)) : parentheses(f.goodsCountFilteredN+'/'+f.goodsCountN)) : (f.goodsCountFiltered === f.goodsCount ? (f.goodsCount === 0 ? '' : parentheses(f.goodsCount)) : parentheses(f.goodsCountFiltered+'/'+f.goodsCount))); ++moreFiltersCount; } } var aShowMoreFiltersPanel = unsafeWindow.y$.aShowMoreFiltersPanel; var spanMoreFiltersCount = unsafeWindow.y$.spanMoreFiltersCount; if (moreFiltersCount > 0) { aShowMoreFiltersPanel.attr('title', '当前下级过滤器('+moreFiltersCount+'):'+moreFiltersTitle); spanMoreFiltersCount.text(moreFiltersCount); if (spanMoreFiltersCount.hasClass('zeroFiltersCount')) spanMoreFiltersCount.removeClass('zeroFiltersCount'); } else { aShowMoreFiltersPanel.attr('title', '当前下级过滤器:无'); spanMoreFiltersCount.text(0); if (!spanMoreFiltersCount.hasClass('zeroFiltersCount')) spanMoreFiltersCount.addClass('zeroFiltersCount'); } return spanMoreFiltersCount; } //更新【状态栏】 function updateInfoLog(log) { //将传入 log 和 unsafeWindow.x$.infoLogText 同步 if (undefined === log) { log = unsafeWindow.x$.infoLogText; } else { if (log.length) unsafeWindow.x$.infoLogText = log; else delete unsafeWindow.x$.infoLogText; } //根据 log 的值操作 labelInfoLog var labelInfoLog = unsafeWindow.y$.labelInfoLog; if (labelInfoLog) { if (undefined === log || !log.length) labelInfoLog.parent().css('display', 'none'); else labelInfoLog.text(log).parent().css('display', ''); } } //应用过滤器,计算商品数量 function applyGoodsFilters(setCountOnly) { var allGoods = document.querySelectorAll('li.gl-item'); //计算商品属性 calcGoodsProperties(); //逐个更新过滤器 var updatedCount = 0; for (var i=0; i<jdGoodsFilters.length; ++i) { var f = jdGoodsFilters[i]; if (f.level === undefined) continue; //剔除未启用的 //计算计数 var goodsCount = getGoodsCount(f); var goodsCountN = allGoods.length - goodsCount; var filteredCount = getGoodsCountFiltered(f); //更新左侧过滤器 var updated = updatedCount; if (f.goodsCount !== goodsCount) { f.goodsCount = goodsCount; ++updatedCount; } if (f.goodsCountFiltered !== filteredCount[0]) { f.goodsCountFiltered = filteredCount[0]; ++updatedCount; } if (updatedCount > updated) { if (f.aFilter) updateFilterCount(f); updated = updatedCount; } else if (f.created) updateFilterCount(f); //更新右侧过滤器 if (f.goodsCountN !== goodsCountN) { f.goodsCountN = goodsCountN; ++updatedCount; } if (f.goodsCountFilteredN !== filteredCount[1]) { f.goodsCountFilteredN = filteredCount[1]; ++updatedCount; } if (updatedCount > updated) { if (f.aFilterN) updateFilterNCount(f); } else if (f.created) updateFilterNCount(f); //删除初始化标志 if (f.created) delete f.created; } //更新【下级过滤器】的提示 updateUsingMoreFiltersCount(); //执行过滤器 if (!setCountOnly) applyFilters(); //返回更新的数据计数 return updatedCount; function calcGoodsProperties() { for (var i=0; i<allGoods.length; ++i) { var g = allGoods[i]; for (var j=0; j<jdGoodsFilters.length; ++j) { var f = jdGoodsFilters[j]; if (f.level === undefined) continue; //剔除未启用的 if (hitFilter(g, f)) g[f.name] = true; else delete g[f.name]; } } function hitFilter(elem, filter) { for (var i=0; i<filter.conditions.length; ++i) { var cond = filter.conditions[i]; if (goodsFilterMap[cond.type](elem, cond) ^ (cond.not !== undefined)) return true; } return false; } } function getGoodsCount(filter) { var count = 0; for (var i=0; i<allGoods.length; ++i) { if (allGoods[i][filter.name]) ++count; } return count; } function getGoodsCountFiltered(filter) { var filteredGoods = []; fg: for (var i=0; i<allGoods.length; ++i) { var g = allGoods[i]; for (var j=0; j<jdGoodsFilters.length; ++j) { var f = jdGoodsFilters[j]; if (f.level === undefined) continue; //剔除未启用的 if (filter === f) continue; //剔除正在计数的 if (f.checked === f.checkedN) { if (f.checked) continue; //忽略正反都显示的过滤器 return [0, 0]; //有正反都不显示的过滤器,直接返回 0 } if (g[f.name] ? f.checked : f.checkedN) continue; //测试通过 continue fg; } filteredGoods.push(g); } var count = 0; for (var k=0; k<filteredGoods.length; ++k) { if (filteredGoods[k][filter.name]) ++count; } return [count, filteredGoods.length - count]; } function updateFilterCount(filter) { filter.spanFilterCount.textContent = filter.goodsCountFiltered===filter.goodsCount ? filter.goodsCount : filter.goodsCountFiltered+'/'+filter.goodsCount; if (filter.goodsCountFiltered === 0) filter.aFilter.classList.add('zeroCountGoods'); else filter.aFilter.classList.remove('zeroCountGoods'); } function updateFilterNCount(filter) { filter.spanFilterNCount.textContent = filter.goodsCountFilteredN===filter.goodsCountN ? filter.goodsCountN : filter.goodsCountFilteredN+'/'+filter.goodsCountN; if (filter.goodsCountFilteredN === 0) filter.aFilterN.classList.add('zeroCountGoods'); else filter.aFilterN.classList.remove('zeroCountGoods'); } function applyFilters() { var inGoods = []; var outGoods = []; fg: for (var i=0; i<allGoods.length; ++i) { var g = allGoods[i]; for (var j=0; j<jdGoodsFilters.length; ++j) { var f = jdGoodsFilters[j]; if (f.level === undefined) continue; //剔除未启用的 if (g[f.name]) { if (f.onPassed) f.onPassed(g); } else { if (f.onMissed) f.onMissed(g); } if (f.checked === f.checkedN) { if (f.checked) continue; //忽略正反都显示的过滤器 var cf = unsafeWindow.x$.goodsFilterModeClass; for (var k=0; k<allGoods.length; ++k) allGoods[k].classList.add(cf); //正反都隐藏 return; } if (g[f.name] ? f.checked : f.checkedN) continue; //测试通过 //测试失败 outGoods.push(g); continue fg; } inGoods.push(g); } var c = unsafeWindow.x$.goodsFilterModeClass; if (inGoods.length > 0) for (var l=0; l<inGoods.length; ++l) inGoods[l].classList.remove(c); if (outGoods.length > 0) for (var m=0; m<outGoods.length; ++m) outGoods[m].classList.add(c); if (unsafeWindow.x$.filteredToLastChecked) reorderGoodsByFilteredState(allGoods); } } //重排商品 function reorderGoodsByFilteredState(allGoods) { if (undefined === allGoods) allGoods = document.querySelectorAll('li.gl-item'); groupGoods(allGoods, function(x,y) { var xx = x.classList.contains(unsafeWindow.x$.goodsFilterModeClass); var yy = y.classList.contains(unsafeWindow.x$.goodsFilterModeClass); return xx === yy ? x.sortOrder-y.sortOrder : (xx?1:-1); }); } function reorderGoodsByOriginalOrder(allGoods) { if (undefined === allGoods) allGoods = document.querySelectorAll('li.gl-item'); groupGoods(allGoods, function(x,y) { return x.sortOrder-y.sortOrder; }); } //将商品分组并记录原始顺序,然后对商品重新排序 function groupGoods(allGoods, sortBy) { if (allGoods && allGoods.length) { var grouped = []; //分组 for (var i=0; i<allGoods.length; ++i) { var goods = allGoods[i]; var parent = goods.parentElement; var current = undefined; for (var j=0; j<grouped.length; ++j) { if (grouped[j].parent === parent) { current = grouped[j]; break; } } if (!current) grouped.push(current = {parent: parent, goods:[]}); //记录原始顺序 if (undefined === goods.sortOrder) goods.sortOrder = current.goods.length; current.goods.push(goods); } //对每组商品单独排序 for (var k=0; k<grouped.length; ++k) { var group = grouped[k]; group.goods.sort(sortBy); $(group.parent).append(group.goods); } } } //加载所有商品 function loadAllGoods() { if (unsafeWindow.SEARCH !== undefined && unsafeWindow.SEARCH.scroll !== undefined) { unsafeWindow.SEARCH.scroll(); setTimeout(waitAllGoods, timerFreq); } else setTimeout(loadAllGoods, timerFreq); //等待所有商品加载完成 function waitAllGoods() { if (unsafeWindow.SEARCH.loading) setTimeout(waitAllGoods, timerFreq); else processGoodsList(); } //收尾处理 function processGoodsList() { if (document.querySelectorAll('li.gl-item').length) { var noR###ltNotice = document.querySelector('div.notice-filter-nor###lt'); if (noR###ltNotice) noR###ltNotice.remove(); } forceLoadLazyImgs(); applyGoodsFiltersOnLoaded(); //取消图片延迟加载 function forceLoadLazyImgs() { unsafeWindow.z$.forceLoadLazyImgsCount = 0; unsafeWindow.z$.forceLoadLazyImgsInterval = setInterval(function() { if (unsafeWindow.z$.forceLoadLazyImgsCount++ < 3) { var aName = 'data-lazy-img'; document.querySelectorAll('ul.gl-warp img[data-lazy-img]:not([src])').forEach(function(img) { img.setAttribute('src', img.getAttribute(aName)); img.removeAttribute(aName); }); return; } if (unsafeWindow.z$.forceLoadLazyImgsInterval) { clearInterval(unsafeWindow.z$.forceLoadLazyImgsInterval); delete unsafeWindow.z$.forceLoadLazyImgsInterval; } }, 2000); } //延时应用过滤器 function applyGoodsFiltersOnLoaded() { //每秒执行一次,前2次仅更新计数,15次后由 applyGoodsFiltersOnAjaxStop 接管,并计划一个10秒后的更新 unsafeWindow.z$.applyGoodsFiltersOnLoadedCount = 0; unsafeWindow.z$.applyGoodsFiltersOnLoadedCountInterval = setInterval(function() { if (unsafeWindow.z$.applyGoodsFiltersOnLoadedCount < 15) { applyGoodsFilters(unsafeWindow.z$.applyGoodsFiltersOnLoadedCount++ < 2); //延迟收尾 if (unsafeWindow.z$.applyGoodsFiltersOnLoadedCount === 3) updateInfoLog(''); return; } if (unsafeWindow.z$.applyGoodsFiltersOnLoadedCountInterval) { clearInterval(unsafeWindow.z$.applyGoodsFiltersOnLoadedCountInterval); delete unsafeWindow.z$.applyGoodsFiltersOnLoadedCountInterval; setTimeout(applyGoodsFilters, 1000 * 10); applyGoodsFiltersOnAjaxStop(); } }, 1000); } //ajaxStop收尾 function applyGoodsFiltersOnAjaxStop() { //开始计时 unsafeWindow.z$.goodsLoadedTime = Date.now(); //注册 ajaxStop 事件 unsafeWindow.$(document).ajaxStop(function() { var t = Date.now() - unsafeWindow.z$.goodsLoadedTime; if (t > 1000 * 15) return; //15秒之后不再响应该事件 //console.log('ajaxStop -> '+t+'ms'); //对挂起的操作重新计时(清除已有的并重新挂起一个新的延时操作) if (unsafeWindow.z$.applyGoodsFiltersTimeout !== undefined) { clearTimeout(unsafeWindow.z$.applyGoodsFiltersTimeout); delete unsafeWindow.z$.applyGoodsFiltersTimeout; } unsafeWindow.z$.applyGoodsFiltersTimeout = setTimeout(function() { delete unsafeWindow.z$.applyGoodsFiltersTimeout; applyGoodsFilters(); //ajaxStop 延时操作 }, 33); }); } } } } //检查保存数据的版本信息 function CheckSettings(versionCheck) { var version = 50102; //每个子版本号占2位 //GM_info.script.version //用GM_info会使每个小版本更新都强行重置所有保存的设置 if (versionCheck && GM_getValue('插件版本') >= version) return; var vals = GM_listValues(); for (var i=0; i<vals.length; ++i) GM_deleteValue(vals[i]); GM_setValue('插件版本', version); } //圆括号包围字串 function parentheses(str){return surround(str,'(',')');} function surround(str, prefix, suffix){return prefix+str+suffix;} //字串检测 function isAny(str, vals) { //str∈vals for (var i=0; i<vals.length; ++i) { if (str === vals[i]) return true; } return false; } function includesAny(str, vals) { //∃v∈vals,str⊇v for (var i=0; i<vals.length; ++i) { if (str.includes(vals[i])) return true; } return false; } function includesAll(str, vals) { //∀v∈vals,str⊇v for (var i=0; i<vals.length; ++i) { if (!str.includes(vals[i])) return false; } return true; } //字串转 RegExp function ToRegex(str) { if (str[0] === '/') { try { var r = eval(str); if (r instanceof RegExp) return new RegExp(r); //重新调用一次 RegExp 对字面量进行优化 } catch(e) {} } try { return new RegExp(str, 'gim'); } catch(e) {} return null; } //字串转匹配规则,去掉空白串 function ToTextCond(str) { var allMatch = str[0] === '`'; var vals = str.split('`'); var txts = []; for (var i=allMatch?1:0; i<vals.length; ++i) { var txt = vals[i]; if (txt.length > 0 && (txt = txt.trim()).length > 0) txts.push(txt); } return {allMatch:allMatch, txts:txts}; } //高亮 HTML (Regex) function highlightHtmlUsingRegex(html, rex, hlInfo) { var i=0; rex.lastIndex = 0; html = html.replace(rex, function(m) { return m.length > 0 ? hlInfo.tag0[i++%9]+m+hlInfo.tag1 : ''; }); return i>0 ? html : null; } //高亮 HTML (string[]) function highlightHtmlUsingTexts(html, txts, hlInfo) { if (txts.length === 0) return null; for (var i=0; i<txts.length; ++i) { var txt = txts[i]; if (html.includes(txt)) html = html.replace(txt, hlInfo.tag0[i%9]+txt+hlInfo.tag1); } return html; } //高亮 HTML function highlightHtml(html, match, hlInfo) { return match instanceof RegExp ? highlightHtmlUsingRegex(html, match, hlInfo) : highlightHtmlUsingTexts(html, match, hlInfo); } //替换高亮 HTML function replaceHighlightHtml(html, match, hlMatch, hlInfo) { if (match instanceof RegExp) { if (hlMatch instanceof RegExp) { //正则替换正则 if (match.source === hlMatch.source && match.flags === hlMatch.flags) return null; //相等的正则,跳过处理 } html = unhighlightHtml(html, hlInfo); html = highlightHtmlUsingRegex(html, match, hlInfo); } else { if (hlMatch instanceof RegExp) { html = unhighlightHtml(html, hlInfo); html = highlightHtmlUsingTexts(html, match, hlInfo); } else { //数组替换数组 var hit = false; for (var i=0; i<match.length; ++i) { var txt = match[i]; var ti = i%9; if (i < hlMatch.length) { var hlTxt = hlMatch[i]; if (txt === hlTxt) continue; //高亮的位置和内容相等,跳过处理 html = html.replace(hlInfo.tag0[ti]+hlTxt+hlInfo.tag1, hlTxt); //先取消高亮 } html = html.replace(txt, hlInfo.tag0[ti]+txt+hlInfo.tag1); //重新高亮 hit = true; } if (match.length < hlMatch.length) { for (var j=match.length; j<hlMatch.length; ++j) { var hl = hlMatch[j]; html = html.replace(hlInfo.tag0[j%9]+hl+hlInfo.tag1, hl); } hit = true; } return hit ? html : null; } } return html; } //取消高亮 HTML function unhighlightHtml(html, hlInfo) { for (var i=0; i<hlInfo.tag0.length; ++i) { html = html.replace(hlInfo.tag0[i], ''); } return html.replace(hlInfo.tag1, ''); } }());