您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Rozszerzona czarna lista.
// ==UserScript== // @name CzarnaLista+ Wykop // @namespace https://wykop.pl/ // @version 0.1 // @description Rozszerzona czarna lista. // @author rpbyo, ashmedai // @match *://*.wykop.pl/* // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @require https://unpkg.com/react@16/umd/react.production.min.js // @require https://unpkg.com/react-dom@16/umd/react-dom.production.min.js // ==/UserScript== (function newf() { const wblp = { filter: { updateWykopSettings() { wykop.height.document = Math.round(document.body.getBoundingClientRect().height); wykop.bindLazy(); }, addHideButton(li) { const { type } = li.querySelector('div').dataset; const btn = '<a href="#" class="affect hide wblp-hideelement">Ukryj ponownie</a>'; switch (type) { case 'link': { const row = li.querySelector('.article > .lcontrast > .row.elements'); if (!row.querySelector('.wblp-hideelement')) { row.insertAdjacentHTML('beforeend', btn); } } break; default: { const row = li.querySelector('.wblock .row.elements'); if (row) { if (!row.querySelector('.wblp-hideelement')) { row.insertAdjacentHTML('beforeend', btn); } } else { const text = li.querySelector('.wblock .text'); if (!text.parentElement.querySelector('.wblp-hideelement')) { text.insertAdjacentHTML('afterend', `<div>${btn}</div>`); } } } break; } }, toggleFilteredElement({ target }) { const closestLi = target.closest('li'); if (closestLi) { closestLi.classList.toggle('wblp-hide'); this.addHideButton(closestLi); } this.updateWykopSettings(); }, hideElement(element, elementType, reason, { blockingType }) { const reasonsList = { colorFilter: 'kolor', domainFilter: 'domena', genderFilter: 'płeć', hasTagFilter: 'zawiera tag', tagFilter: 'tag', timeFilter: 'czas', userFilter: 'użytkownik', withoutTagFilter: 'brak tagów', wordFilter: 'słowo', }; const messagesList = { comment: `Komentarz został ukryty (${reasonsList[reason]})`, commentsub: `Komentarz został ukryty (${reasonsList[reason]})`, entry: `Wpis został ukryty (${reasonsList[reason]})`, entrycomment: `Komentarz został ukryty (${reasonsList[reason]})`, link: `Znalezisko zostało ukryte (${reasonsList[reason]})`, }; const msg = `<div class="show-message_container"><a href="#" class="show-element_button">${ messagesList[elementType] } - Kliknij, aby zobaczyć</a></div>`; switch (blockingType[elementType]) { case 0: { const li = element.closest('li'); if (elementType === 'link') { li.insertAdjacentHTML('beforeend', msg); } else { element.querySelector('.text').insertAdjacentHTML('afterend', msg); } this.addHideButton(li); } break; case 1: { const li = element.closest('li'); li.classList.add('wblp-hide'); if (elementType === 'link') { li.insertAdjacentHTML('beforeend', msg); } else { element.querySelector('.text').insertAdjacentHTML('afterend', msg); } } break; case 2: if (elementType === 'link') { element.closest('.link').remove(); } else { element.parentElement.remove(); } break; default: break; } this.updateWykopSettings(); }, getElementsToFilter({ elementToBlock }) { const selectorsList = { link: '#itemsStream > .link.iC > div[data-type="link"] > .lcontrast.m-reset-margin', comment: '#itemsStream > .iC > div[data-type="comment"]', commentsub: '#itemsStream > .iC > .sub > li > div[data-type="comment"]', entry: '#itemsStream > .entry.iC > div[data-type="entry"]', entrycomment: '#itemsStream > .entry.iC > .sub > li > div[data-type="entrycomment"]', }; let elements = []; Object.entries(elementToBlock).forEach((property) => { const [key, value] = property; if (value) { elements = [...elements, ...document.querySelectorAll(selectorsList[key])]; } }); return elements; }, getTypeOfElement(element) { if (element.classList.contains('m-reset-margin')) { return element.parentElement.dataset.type; } const { type } = element.dataset; if (type === 'comment' && element.closest('.sub')) { return 'commentsub'; } return type; }, filterModules: { genderFilter(element, elementType, { genderList }) { if (elementType !== 'link' && genderList.length) { const elementGenderString = element.querySelector('.avatar.lazy').classList.value; let elementGender = elementGenderString.match(/male|female/); switch (true) { case !elementGender: elementGender = 'none'; break; default: [elementGender] = elementGender; break; } return genderList.includes(elementGender); } return false; }, colorFilter(element, elementType, { colorList }) { if (colorList.length) { let userColorString; switch (elementType) { case 'link': { const em = element.querySelector('.fix-tagline > a > em'); userColorString = em.parentElement.classList.value; } break; default: { const nickElement = element.querySelector('.author > .showProfileSummary'); userColorString = nickElement ? nickElement.classList.value : element.querySelector('.author > b').classList.value; } break; } const userColor = userColorString.match(/color-\d+/)[0]; return colorList.includes(userColor); } return false; }, userFilter(element, elementType, { userList }) { if (userList.length) { let userName; switch (elementType) { case 'link': { const em = element.querySelector('.fix-tagline > a > em'); const parentText = em.parentElement.innerText; userName = parentText.substr(1).toLowerCase(); } break; default: { const nickElement = element.querySelector('.author > .showProfileSummary > b'); userName = nickElement ? nickElement.innerText.toLowerCase() : element.querySelector('.author > b').innerText.toLowerCase(); } break; } return userList.includes(userName); } return false; }, timeFilter(element, elementType, { timeList }) { if (elementType === 'entry' && timeList.length) { const timeElement = element.querySelector('.author time'); const timeAttr = timeElement.getAttribute('datetime'); const date = new Date(timeAttr); // eslint-disable-next-line const time = date.getHours() * 60 + date.getMinutes(); for (let i = 0; i < timeList.length; i += 1) { const timeArr = timeList[i].split('-').map(e => e.split(':')); // eslint-disable-next-line const [a, b] = timeArr.map(e => +e[0] * 60 + +e[1]); if (a <= b) { return time >= a && time <= b; } return (time >= a && time <= 1439) || (time <= b && time >= 0); } } return false; }, tagFilter(element, elementType, { tagList }) { if (tagList.length) { const { action, sort } = wykop.params; const tagArr = []; switch (elementType) { case 'link': { const tags = [...element.querySelectorAll('.fix-tagline > a.tag.affect.create')]; tags.forEach(a => a.classList.contains('unhide') || tagArr.push(a.innerText.substr(1).toLowerCase())); } break; default: { const tags = [...element.querySelectorAll('.text > p .showTagSummary')]; tags.forEach(a => tagArr.push(a.innerText.toLowerCase())); } break; } for (let i = 0; i < tagArr.length; i += 1) { if (action === 'tag' && tagArr[i] !== sort) { if (tagList.includes(tagArr[i])) return true; } } } return false; }, withoutTagFilter(element, elementType) { if (elementType === 'index' || elementType === 'entry') { if (elementType === 'link') { return !element.querySelector('.fix-tagline > .tag.affect.create'); } return !element.querySelector('.text > p .showTagSummary'); } return false; }, hasTagFilter(element, elementType) { if (elementType === 'link' || elementType === 'entry') { if (elementType === 'link') { return element.querySelector('.fix-tagline > .tag.affect.create'); } return element.querySelector('.text > p .showTagSummary'); } return false; }, domainFilter(element, elementType, { domainList }) { if (elementType === 'link' && domainList.length) { const domainElement = element.querySelector('.fix-tagline > .tag.create > a[rel="nofollow"]'); if (domainElement) { const domain = domainElement.innerText; return domainList.includes(domain); } } return false; }, wordFilter(element, elementType, { wordList }) { if (wordList.length) { const clearText = (textToEdit) => { let text = textToEdit.toLowerCase(); text = text.replace(/#[a-z0-9]+/g, ''); text = text.replace(/\s+/g, ' '); text = text.replace(/^\s|,|\s$/g, ''); text = text.replace(/ą/g, 'a'); text = text.replace(/ć/g, 'c'); text = text.replace(/ę/g, 'e'); text = text.replace(/ń/g, 'n'); text = text.replace(/ó/g, 'o'); text = text.replace(/ś/g, 's'); text = text.replace(/ź|ż/g, 'z'); return text; }; let textToCompare; switch (elementType) { case 'link': { const title = element.querySelector('h2').innerText; const description = element.querySelector('.description > .text > a').innerText; const text = `${title} ${description}`; textToCompare = clearText(text); } break; default: { const text = element.querySelector('.text > p').innerText; textToCompare = clearText(text); } break; } for (let i = 0; i < wordList.length; i += 1) { if (textToCompare.includes(wordList[i].toLowerCase())) { return true; } } } return false; }, }, startFilter({ filterType }, elements) { for (let e = 0; e < elements.length; e += 1) { const element = elements[e]; const elementType = this.getTypeOfElement(element); for ( let m = 0, n = Object.entries(filterType); m < Object.keys(filterType).length; m += 1 ) { if (n[m][1]) { if (this.filterModules[n[m][0]](element, elementType, this.data.filtersList)) { this.hideElement(element, elementType, n[m][0], this.data.pageOptions); break; } } } } }, runMutator(element, type, { elementToBlock }) { const observer = new MutationObserver((muts) => { const newElems = [...muts[0].addedNodes]; let elements = []; newElems.forEach((e) => { if (e.classList.contains('link') && elementToBlock.link) { elements.push(e.querySelector('div[data-type="link"] > .lcontrast.m-reset-margin')); } else if (e.classList.contains('entry')) { let sub = []; if (elementToBlock.entrycomment) { sub = [...sub, ...e.querySelectorAll('.sub > li > div')]; } if (elementToBlock.entry) { elements.push(e.querySelector('div')); } elements = [...elements, ...sub]; } else if (elementToBlock.entrycomment) { elements.push(e.querySelector('div')); } }); if (type === 'click') { observer.disconnect(); } this.startFilter(this.data.pageOptions, elements); }); observer.observe(element, { childList: true }); }, filterEv(event) { const { target } = event; if ( target.matches('a.affect.ajax') && target.parentElement.matches('p.more') && target.closest('.sub') ) { this.runMutator(target.closest('.sub'), 'click', this.data.pageOptions); } else if ( target.matches('a.show-element_button') || target.matches('a.wblp-hideelement') ) { event.preventDefault(); this.toggleFilteredElement(event); } }, addCss() { const css = '<style type="text/css">' + '.wblp-hide.link > .show-message_container,.wblp-hide > .wblock.lcontrast.dC{opacity:0.3;}' + '.wblp-hide.link > .show-message_container:hover,.wblp-hide > .wblock.lcontrast.dC:hover{opacity:1;}' + '.wblp-hide > .article,.wblp-hide > .wblock.lcontrast.dC + .sub,.wblp-hide > .wblock.lcontrast.dC > survey,.wblp-hide > .wblock.lcontrast.dC > div > :not(.author):not(.show-message_container),.show-message_container{display:none!important;}' + '.wblp-hide .show-message_container{display:block!important;text-align:center;}' + '.wblp-hide .show-element_button{zoom:1;cursor:pointer;text-align:center;line-height:2.8rem;display:block;color:#cacecf!important;font-weight:bold;}' + '.wblp-hideelement{margin-left:15px;}</style>'; document.head.insertAdjacentHTML('beforeend', css); }, addEvents({ action, method }) { switch (action) { case 'stream': case 'entries': case 'tag': if (method !== 'hot') { this.runMutator( document.querySelector(`${action === 'entries' ? '.sub' : '#itemsStream'}`), 'auto', this.data.pageOptions, ); } break; default: break; } document.addEventListener('click', event => this.filterEv(event), true); }, async getValue(id) { // eslint-disable-next-line const data = await GM_getValue(`wblp${id}`); return data ? JSON.parse(data) : data; }, mergeFilters(pf, gf, { isOn, filter, mainGlobalFilter, globalFilter, }) { let set; if (isOn !== false) { if (mainGlobalFilter !== false && globalFilter !== false && filter && pf && gf) { set = gf; Object.entries(set).forEach((property) => { const arr = [...property[1], ...pf[property[0]]]; set[property[0]] = [...new Set(arr)]; }); } else if (mainGlobalFilter !== false && globalFilter !== false && gf) { set = gf; } else if (filter && pf) { set = pf; } } return set; }, mergeOptions(po, go) { const pageoptions = po || {}; const globaloptions = go || {}; let set = {}; if (globaloptions.mainGlobalOptions && pageoptions.globalOptions !== false) { set = globaloptions; set.isOn = pageoptions.isOn; set.filter = pageoptions.filter; set.globalFilter = pageoptions.globalFilter; } else if (pageoptions.isOn) { set = pageoptions; } return set; }, splitData(obj) { const { filterList, ...optionsList } = obj; return [filterList, optionsList]; }, splitAndMerge([info, pageoptions, globaloptions]) { let po; let pf; let go; let gf; if (pageoptions) [pf, po] = this.splitData(pageoptions); if (globaloptions) [gf, go] = this.splitData(globaloptions); const options = this.mergeOptions(po, go); const filters = this.mergeFilters(pf, gf, options); const arr = [info, options, filters]; return arr; }, async getAndEditOptions({ action, sort }) { return Promise.all([ this.getValue('info'), this.getValue(`settings${action}${sort}`), this.getValue('settingsglobaloptions'), ]).then(data => this.splitAndMerge(data)); }, async loadSettings() { const [info, pageOptions, filtersList] = await this.getAndEditOptions(wykop.params); this.data = { info, pageOptions, filtersList }; }, isFilterOn() { return this.data.info ? this.data.info.isOn : undefined; }, initialize() { (async () => { this.loadSettings().then(() => { if ( this.isFilterOn() && this.data.filtersList && this.data.pageOptions.isOn !== false && Object.keys(this.data.pageOptions).length ) { this.addCss(); this.addEvents(wykop.params); this.startFilter( this.data.pageOptions, this.getElementsToFilter(this.data.pageOptions), ); } }); })(); }, }, option: { navElementsList: { global: { innerText: 'Opcje globalne', pageId: 'globaloptions', pageTitle: 'Opcje globalne', }, index: { innerText: 'Strona główna', sub: [ { innerText: 'najnowsze', pageId: 'index1', pageTitle: 'Strona główna - najnowsze' }, { innerText: 'aktywne', pageId: 'index2', pageTitle: 'Strona główna - aktywne' }, ], }, upcoming: { innerText: 'Wykopalisko', sub: [ { innerText: 'aktywne', pageId: 'upcoming1', pageTitle: 'Wykopalisko - aktywne' }, { innerText: 'najnowsze', pageId: 'upcoming2', pageTitle: 'Wykopalisko - najnowsze' }, { innerText: 'komentowane', pageId: 'upcoming3', pageTitle: 'Wykopalisko - komentowane', }, { innerText: 'wykopywane', pageId: 'upcoming4', pageTitle: 'Wykopalisko - wykopywane', }, ], }, link: { innerText: 'Znaleziska', pageId: 'link', pageTitle: 'Znaleziska' }, stream: { innerText: 'Mikroblog', sub: [ { innerText: 'najnowsze', pageId: 'streamindex', pageTitle: 'Mikroblog - najnowsze' }, { innerText: 'aktywne', pageId: 'streamactive', pageTitle: 'Mikroblog - aktywne' }, { innerText: 'gorące', pageId: 'streamhot', pageTitle: 'Mikroblog - gorące' }, ], }, entries: { innerText: 'Wpisy', pageId: 'entries', pageTitle: 'Wpisy' }, }, getObjectPattern(isGlobalOptions) { const pat = { blockingType: { comment: 1, commentsub: 1, entry: 1, entrycomment: 1, link: 1, }, elementToBlock: { comment: true, commentsub: true, entry: true, entrycomment: true, link: true, }, filterType: { colorFilter: false, domainFilter: false, genderFilter: false, hasTagFilter: false, tagFilter: false, timeFilter: false, userFilter: false, withoutTagFilter: false, wordFilter: false, }, filterList: { colorList: [], userList: [], tagList: [], domainList: [], timeList: [], wordList: [], genderList: [], }, }; if (isGlobalOptions) { pat.mainGlobalFilter = true; pat.mainGlobalOptions = true; } else { pat.isOn = true; pat.filter = true; pat.globalFilter = true; pat.globalOptions = true; } return pat; }, main() { const rce = React.createElement; const rc = React.Component; const toggleSub = (e) => { e.preventDefault(); e.target.classList.toggle('wblp-showsub'); }; const removeItemFromArray = (item, array) => { const arrayCopy = [...array]; const index = arrayCopy.indexOf(item); if (index < 0) return false; arrayCopy.splice(index, 1); return arrayCopy; }; const setValue = (id, data) => GM_setValue(`wblp${id}`, JSON.stringify(data)); const deleteValue = id => GM_deleteValue(`wblp${id}`); const getValue = async (id, isGO) => { try { const response = await GM_getValue(`wblp${id}`); const rej = id === 'info' ? null : this.getObjectPattern(isGO); const json = (await response) ? JSON.parse(response) : rej; return json; } catch (error) { throw new Error(`Wykop blacklist+ ${error}`); } }; const FieldsetList = props => rce( 'fieldset', null, rce('h4', null, props.h4Text), rce( 'div', { className: 'space' }, rce( 'div', { className: 'wblp-gridaction' }, rce('input', { placeholder: props.placeholder, className: 'wblp-input', type: 'text', onChange: props.onChange, value: props.value, }), rce( 'a', { href: '#', className: 'button', onClick: props.addItems, }, 'dodaj', ), ), rce( 'div', { className: 'wblp-gridfilterlist' }, props.list.map(item => rce( 'a', { key: item.id, href: '#', title: 'Kliknij, aby usunąć', onClick: e => props.itemRemove(e, item, props.filterListName), }, item, )), ), ), ); const Fieldset = props => rce( 'fieldset', null, rce('h4', null, props.h4Text), rce( 'div', { className: props.className || 'space' }, props.rows.map((item) => { const { inlineText, checked, title, select, handleChange, selectChange, } = item; return rce( 'div', { key: item.id, className: 'row' }, rce('input', { type: 'checkbox', title: title || '', checked, onChange: handleChange, }), rce( 'label', { className: `inline ${props.select ? 'wblp-inline' : ''}` }, inlineText, ), !!props.select && rce( 'select', { className: 'wblp-select', value: select, onChange: selectChange }, rce('option', { value: 0 }, 'Nic'), rce('option', { value: 1 }, 'Zwijaj'), rce('option', { value: 2 }, 'Usuwaj'), ), ); }), ), ); const PageFilterList = (props) => { const { pageId, checkboxToggleArr, filterList, addToFilterList, handleChange, inputsValues, itemRemove, } = props; const { colorList, domainList, userList, wordList, tagList, timeList, genderList, } = filterList; const { users, tags, domains, words, times, } = inputsValues; return rce( 'div', null, rce( 'h4', { className: 'wblp-h4' }, `Lista filtrów ${pageId === 'globaloptions' ? 'globalnych' : 'lokalnych'}`, ), rce(Fieldset, { h4Text: 'kolor', className: 'space wblp-grid', rows: [ { checked: colorList.includes('color-0'), inlineText: 'zielonki', handleChange: e => checkboxToggleArr(e, 'color-0', 'colorList'), }, { checked: colorList.includes('color-1'), inlineText: 'pomarańczowi', handleChange: e => checkboxToggleArr(e, 'color-1', 'colorList'), }, { checked: colorList.includes('color-2'), inlineText: 'bordo', handleChange: e => checkboxToggleArr(e, 'color-2', 'colorList'), }, { checked: colorList.includes('color-5'), inlineText: 'administracja', handleChange: e => checkboxToggleArr(e, 'color-5', 'colorList'), }, { checked: colorList.includes('color-1001'), inlineText: 'zbanowani', handleChange: e => checkboxToggleArr(e, 'color-1001', 'colorList'), }, { checked: colorList.includes('color-1002'), inlineText: 'konta usunięte', handleChange: e => checkboxToggleArr(e, 'color-1002', 'colorList'), }, { checked: colorList.includes('color-2001'), inlineText: 'oficjalne', handleChange: e => checkboxToggleArr(e, 'color-2001', 'colorList'), }, ], }), rce(Fieldset, { h4Text: 'Płeć', className: 'space wblp-grid', rows: [ { checked: genderList.includes('male'), inlineText: 'mężczyzna', handleChange: e => checkboxToggleArr(e, 'male', 'genderList'), }, { checked: genderList.includes('female'), inlineText: 'kobieta', handleChange: e => checkboxToggleArr(e, 'female', 'genderList'), }, { checked: genderList.includes('none'), inlineText: 'brak', handleChange: e => checkboxToggleArr(e, 'none', 'genderList'), }, ], }), rce(FieldsetList, { h4Text: 'nazwa użytkownika', placeholder: 'np. m__b, moderacja, wykop', list: userList, onChange: e => handleChange(e, 'users'), addItems: e => addToFilterList(e, 'users', 'userList'), itemRemove, filterListName: 'userList', value: users, }), rce(FieldsetList, { h4Text: 'tag', placeholder: 'np. gownowpis, patostreamy, nsfw, pilkanozna', list: tagList, onChange: e => handleChange(e, 'tags'), addItems: e => addToFilterList(e, 'tags', 'tagList'), itemRemove, filterListName: 'tagList', value: tags, }), rce(FieldsetList, { h4Text: 'domena', placeholder: 'np. wykop.pl, google.pl', list: domainList, onChange: e => handleChange(e, 'domains'), addItems: e => addToFilterList(e, 'domains', 'domainList'), itemRemove, filterListName: 'domainList', value: domains, }), rce(FieldsetList, { h4Text: 'słowo', placeholder: 'np. daj plusa, kazdy kto zaplusuje, ile plusow to', list: wordList, onChange: e => handleChange(e, 'words'), addItems: e => addToFilterList(e, 'words', 'wordList'), itemRemove, filterListName: 'wordList', value: words, }), rce(FieldsetList, { h4Text: 'czas', placeholder: 'np. 01:00-06:00, 23:00-02:00', list: timeList, onChange: e => handleChange(e, 'times'), addItems: e => addToFilterList(e, 'times', 'timeList'), itemRemove, filterListName: 'timeList', value: times, }), ); }; const PageSettings = (props) => { const { pageTitle, settings, checkboxToggle, selectChange, } = props; const isGO = typeof settings.isOn === 'boolean'; return rce( 'div', null, rce( 'h4', { className: 'wblp-h4' }, `Ustawienia ${isGO ? `dla ${pageTitle}` : 'globalne'}`, ), rce(Fieldset, { h4Text: 'Opcje podstawowe', rows: !isGO ? [ { checked: settings.mainGlobalOptions, inlineText: 'ustawienia globalne', title: 'Ustawienia globalne nadpisują ustawienia lokalne', handleChange: e => checkboxToggle(e, ['mainGlobalOptions']), }, { checked: settings.mainGlobalFilter, inlineText: 'filtr globalny', title: 'Filtr globalny łączy się z filtrem lokalnym', handleChange: e => checkboxToggle(e, ['mainGlobalFilter']), }, ] : [ { checked: settings.isOn, inlineText: 'filtrowanie na tej stronie', handleChange: e => checkboxToggle(e, ['isOn']), }, { checked: settings.filter, inlineText: 'filtr lokalny', handleChange: e => checkboxToggle(e, ['filter']), }, { checked: settings.globalOptions, inlineText: 'ustawienia globalne na tej stronie', title: 'Ustawienia globalne nadpisują ustawienia lokalne', handleChange: e => checkboxToggle(e, ['globalOptions']), }, { checked: settings.globalFilter, inlineText: 'filtr globalny na tej stronie', title: 'Filtr globalny łączy się z filtrem lokalnym', handleChange: e => checkboxToggle(e, ['globalFilter']), }, ], }), rce(Fieldset, { h4Text: 'Elementy oraz rodzaj filtrowania', select: true, rows: [ { checked: settings.elementToBlock.entry, inlineText: 'wpisy', select: settings.blockingType.entry, handleChange: e => checkboxToggle(e, ['elementToBlock', 'entry']), selectChange: e => selectChange(e, 'entry'), }, { checked: settings.elementToBlock.entrycomment, inlineText: 'komentarze do wpisów', select: settings.blockingType.entrycomment, handleChange: e => checkboxToggle(e, ['elementToBlock', 'entrycomment']), selectChange: e => selectChange(e, 'entrycomment'), }, { checked: settings.elementToBlock.link, inlineText: 'znaleziska', select: settings.blockingType.link, handleChange: e => checkboxToggle(e, ['elementToBlock', 'link']), selectChange: e => selectChange(e, 'link'), }, { checked: settings.elementToBlock.comment, inlineText: 'komentarze', select: settings.blockingType.comment, handleChange: e => checkboxToggle(e, ['elementToBlock', 'comment']), selectChange: e => selectChange(e, 'comment'), }, { checked: settings.elementToBlock.commentsub, inlineText: 'odpowiedzi', select: settings.blockingType.commentsub, handleChange: e => checkboxToggle(e, ['elementToBlock', 'commentsub']), selectChange: e => selectChange(e, 'commentsub'), }, ], }), rce(Fieldset, { h4Text: 'Filtruj przez', className: 'space wblp-col', rows: [ { checked: settings.filterType.colorFilter, inlineText: 'kolor użytkownika', handleChange: e => checkboxToggle(e, ['filterType', 'colorFilter']), }, { checked: settings.filterType.domainFilter, inlineText: 'domena', handleChange: e => checkboxToggle(e, ['filterType', 'domainFilter']), }, { checked: settings.filterType.genderFilter, inlineText: 'płeć', handleChange: e => checkboxToggle(e, ['filterType', 'genderFilter']), }, { checked: settings.filterType.hasTagFilter, inlineText: 'zawiera jakikolwiek tag', handleChange: e => checkboxToggle(e, ['filterType', 'hasTagFilter']), }, { checked: settings.filterType.tagFilter, inlineText: 'tagi', handleChange: e => checkboxToggle(e, ['filterType', 'tagFilter']), }, { checked: settings.filterType.timeFilter, inlineText: 'czas', handleChange: e => checkboxToggle(e, ['filterType', 'timeFilter']), }, { checked: settings.filterType.userFilter, inlineText: 'nazwa użytkownika', handleChange: e => checkboxToggle(e, ['filterType', 'userFilter']), }, { checked: settings.filterType.withoutTagFilter, inlineText: 'brak tagów', handleChange: e => checkboxToggle(e, ['filterType', 'withoutTagFilter']), }, { checked: settings.filterType.wordFilter, inlineText: 'słowo', handleChange: e => checkboxToggle(e, ['filterType', 'wordFilter']), }, ], }), ); }; class PageOptions extends rc { constructor(props) { super(props); this.state = { pageDetails: {}, pageData: {}, showPageOptions: false, inputsValues: { domains: '', tags: '', users: '', times: '', words: '', }, }; this.itemRemove = this.itemRemove.bind(this); this.selectChange = this.selectChange.bind(this); this.handleChange = this.handleChange.bind(this); this.checkboxToggle = this.checkboxToggle.bind(this); this.addToFilterList = this.addToFilterList.bind(this); this.checkboxToggleArr = this.checkboxToggleArr.bind(this); } sV() { setValue(`settings${this.state.pageDetails.pageId}`, this.state.pageData); } itemRemove(e, item, prop) { e.preventDefault(); const newFilterElems = removeItemFromArray(item, this.state.pageData.filterList[prop]); if (!newFilterElems) return; this.setState( prevState => ({ pageData: { ...prevState.pageData, filterList: { ...prevState.pageData.filterList, [prop]: newFilterElems, }, }, }), () => this.sV(), ); } selectChange(e, prop) { const { value } = e.target; this.setState( prevState => ({ pageData: { ...prevState.pageData, blockingType: { ...prevState.pageData.blockingType, [prop]: +value, }, }, }), () => this.sV(), ); } handleChange(e, prop) { const { value } = e.target; this.setState(prevState => ({ inputsValues: { ...prevState.inputsValues, [prop]: value }, })); } addToFilterList(e, prop, listName) { e.preventDefault(); const splitted = this.state.inputsValues[prop].split(','); const edd = splitted.map(i => i.trim().toLowerCase()); let filtered = []; switch (listName) { case 'userList': filtered = edd.filter(i => /^[0-9a-z\-_]{4,35}$/.test(i)); break; case 'tagList': filtered = edd.filter(i => /^[0-9a-z]{2,50}$/.test(i)); break; case 'domainList': filtered = edd.filter(i => /^((http|https):\/\/)?([a-zA-Z0-9_][-_a-zA-Z0-9]{0,62}\.)+([a-zA-Z0-9]{1,10})$/.test(i)); break; case 'timeList': filtered = edd.filter(i => /^\d\d:\d\d-\d\d:\d\d$/.test(i)); break; default: filtered = edd.filter(i => /\S+.+/.test(i)); break; } const merged = [...this.state.pageData.filterList[listName], ...filtered]; const newFilterElems = [...new Set(merged)]; this.setState( prevState => ({ pageData: { ...prevState.pageData, filterList: { ...prevState.pageData.filterList, [listName]: newFilterElems, }, }, inputsValues: { ...prevState.inputsValues, [prop]: '', }, }), () => this.sV(), ); } checkboxToggleArr(e, value, listName) { let updatedList = [...this.state.pageData.filterList[listName]]; if (e.target.checked) updatedList = [...new Set([...updatedList, value])]; else updatedList = updatedList.filter(item => item !== value); this.setState( prevState => ({ pageData: { ...prevState.pageData, filterList: { ...prevState.pageData.filterList, [listName]: updatedList, }, }, }), () => this.sV(), ); } checkboxToggle(e, path) { const { checked } = e.target; const [a, b] = path; if (b) { this.setState( prevState => ({ pageData: { ...prevState.pageData, [a]: { ...prevState.pageData[a], [b]: checked }, }, }), () => this.sV(), ); } else { this.setState( prevState => ({ pageData: { ...prevState.pageData, [a]: checked, }, }), () => this.sV(), ); } } updatePageData() { const { pageId } = this.state.pageDetails; getValue(`settings${pageId}`, pageId === 'globaloptions').then((resp) => { this.setState({ pageData: resp, showPageOptions: true }); }); } componentWillReceiveProps(nextProps) { if (nextProps.pageDetails.pageId !== this.props.pageDetails.pageId) { this.setState({ pageDetails: nextProps.pageDetails }, () => this.updatePageData()); } } componentDidMount() { this.setState( (prevState, props) => ({ pageDetails: props.pageDetails }), () => this.updatePageData(), ); } render() { const { inputsValues, showPageOptions, pageData, pageDetails, } = this.state; const { filterList, ...settings } = pageData; const { pageTitle, pageId } = pageDetails; return rce( 'div', { className: 'rbl-block wblp-pageoptionscontainer space' }, showPageOptions && rce(PageSettings, { settings, pageTitle, checkboxToggle: this.checkboxToggle, selectChange: this.selectChange, }), showPageOptions && rce(PageFilterList, { filterList, pageId, inputsValues, handleChange: this.handleChange, checkboxToggleArr: this.checkboxToggleArr, addToFilterList: this.addToFilterList, itemRemove: this.itemRemove, }), ); } } const ScriptOptions = props => rce( 'div', { className: 'rbl-block wblp-scriptoptionscontainer space' }, rce('h4', { className: 'wblp-h4' }, 'Ustawienia skryptu'), rce(Fieldset, { h4Text: 'Opcje podstawowe', className: 'wblp-space', rows: [ { checked: props.isOn, inlineText: 'włącz/wyłącz blacklist+', handleChange: props.handleChange, }, ], }), ); const Options = props => rce( 'div', { className: 'wblp-optionscontainer' }, rce(ScriptOptions, { isOn: props.isOn, handleChange: props.handleChange }), props.showPageOptions && rce(PageOptions, { pageDetails: props.pageDetails }), ); const NavButton = props => rce( 'div', null, rce( 'a', { href: '#', className: 'wblp-navelement', onClick: e => props.updateCurrentPage(e, props.elData.pageId, props.elData.pageTitle), }, props.elData.innerText, ), ); const Sub = props => rce( 'div', { className: 'dnone' }, props.sub.map(item => rce( 'a', { key: item.id, href: '#', className: 'wblp-navelement', onClick: e => props.updateCurrentPage(e, item.pageId, item.pageTitle), }, item.innerText, )), ); const NavDropdown = props => rce( 'div', null, rce( 'a', { href: '#', className: 'wblp-navelement', onClick: e => toggleSub(e), }, props.elData.innerText, ), rce(Sub, { sub: props.elData.sub, updateCurrentPage: props.updateCurrentPage, }), ); const TagList = props => rce( 'div', null, props.filteredTags.map(item => rce( 'div', { className: 'wblp-navtag' }, rce( 'a', { key: item.id, className: 'wblp-navelement', href: '#', title: `#${item}`, onClick: e => props.updateCurrentPage(e, `tag${item}`, `#${item}`), }, item, ), rce('i', { className: 'fa fa-times', onClick: e => props.removeTag(e, item) }), )), ); const NewTagContainer = props => rce( 'div', null, rce( 'div', { className: 'wblp-navinputcontainer' }, rce('input', { className: 'wblp-input', placeholder: '# dodaj nowy filtr', type: 'text', value: props.newTag, onChange: e => props.handleChange(e), }), rce( 'a', { href: '#', className: 'button', onClick: e => props.addNewTag(e), }, '+', ), ), ); const DefaultPagesList = (props) => { const eL = this.navElementsList; const { updateCurrentPage } = props; return rce( 'div', null, rce(NavButton, { elData: eL.global, updateCurrentPage }), rce(NavDropdown, { elData: eL.index, updateCurrentPage }), rce(NavDropdown, { elData: eL.upcoming, updateCurrentPage }), rce(NavButton, { elData: eL.link, updateCurrentPage }), rce(NavDropdown, { elData: eL.stream, updateCurrentPage }), rce(NavButton, { elData: eL.entries, updateCurrentPage }), ); }; const Nav = props => rce( 'div', { className: 'rbl-block wblp-nav' }, rce(DefaultPagesList, { updateCurrentPage: props.updateCurrentPage }), rce(NewTagContainer, { addNewTag: props.addNewTag, handleChange: props.handleChange, newTag: props.newTag, }), rce(TagList, { filteredTags: props.filteredTags, updateCurrentPage: props.updateCurrentPage, removeTag: props.removeTag, }), ); class Main extends rc { constructor(props) { super(props); this.state = { info: { isOn: false, filteredTags: [], }, newTag: '', pageDetails: { pageId: '', pageTitle: '', }, showPageOptions: false, }; this.addNewTag = this.addNewTag.bind(this); this.handleChange = this.handleChange.bind(this); this.removeTag = this.removeTag.bind(this); this.updateCurrentPage = this.updateCurrentPage.bind(this); } addNewTag(e) { e.preventDefault(); const fT = this.state.info.filteredTags; const nT = this.state.newTag.toLowerCase(); if (!/^[a-z\d]{2,50}$/g.test(nT) || fT.includes(nT)) return; this.setState( prevState => ({ info: { ...prevState.info, filteredTags: [...prevState.info.filteredTags, nT] }, newTag: '', }), () => setValue('info', this.state.info), ); } handleChange(e) { const { target } = e; const isCheckbox = target.type === 'checkbox'; const value = isCheckbox ? target.checked : target.value; if (isCheckbox) { this.setState( prevState => ({ info: { ...prevState.info, isOn: value }, }), () => setValue('info', this.state.info), ); } else { this.setState({ newTag: value }); } } removeTag(e, tagToRemove) { e.preventDefault(); const updatedFilteredTags = removeItemFromArray( tagToRemove, this.state.info.filteredTags, ); if ( !confirm(`Czy chcecz usunąć tag ${tagToRemove} (oraz jego opcje) z listy filtrów?`) || !updatedFilteredTags ) { return; } this.setState( prevState => ({ info: { ...prevState.info, filteredTags: updatedFilteredTags }, }), () => { setValue('info', this.state.info); deleteValue(`settingstag${tagToRemove}`); }, ); if (this.state.pageDetails.pageId === `tag${tagToRemove}`) { this.setState({ pageDetails: { pageId: '', pageTitle: '', }, showPageOptions: false, }); } } updateCurrentPage(e, pageId, pageTitle) { e.preventDefault(); if (this.state.pageDetails.pageId === pageId) return; this.setState({ pageDetails: { pageId, pageTitle }, showPageOptions: true }); } componentDidMount() { getValue('info', false).then((resp) => { if (!resp) return; this.setState({ info: resp }); }); } render() { const { pageDetails, info, newTag, showPageOptions, } = this.state; return rce( 'div', { className: 'wblp-maincontainer' }, rce(Nav, { newTag, filteredTags: info.filteredTags, handleChange: this.handleChange, removeTag: this.removeTag, updateCurrentPage: this.updateCurrentPage, addNewTag: this.addNewTag, }), rce(Options, { isOn: info.isOn, pageDetails, showPageOptions, handleChange: this.handleChange, }), ); } } ReactDOM.render( rce(Main, null), document.querySelector('#site .grid-main.m-reset-margin > div:not(.nav):not(.tdivider)'), ); }, addCss() { const style = '<style type="text/css">' + `.wblp-maincontainer { display: grid; grid-template-columns: 20% auto; }` + `.wblp-nav { margin-bottom: 0; }` + `.wblp-navelement { display: block; cursor: pointer; font-weight: 700; font-size: 1.5rem; padding: 10px 13px; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; }` + `.wblp-navelement + div a { font-size: 1.2rem !important; padding: 8px 13px 8px 15px !important; }` + `.wblp-navelement.wblp-showsub + div { display: block !important; }` + `.wblp-navinputcontainer { display: grid; grid-gap: 3px; grid-template-columns: 1fr auto; padding: 0px 3px; margin: 5px 0px; }` + `.wblp-input { margin: -1px 0; padding: 0 5px !important; }` + `.wblp-navtag { display: grid; grid-template-columns: 1fr 17px; }` + `.wblp-navtag > a::before { content: '#'; }` + `.wblp-navtag > .fa { font-size: 1.7rem; margin-top: 9px; opacity: 0; cursor: pointer; }` + `.wblp-navtag:hover > .fa { opacity: 1; }` + `.wblp-scriptoptionscontainer { border-bottom: 1px solid #222222; }` + `.wblp-pageoptionscontainer { border-top: 1px solid #222222; border-bottom: 1px solid #222222; }` + `.wblp-savebuttoncontainer { border-top: 1px solid #222222; text-align: right; }` + `.wblp-space { padding: 10px 10px 0px 10px; }` + `.wblp-maincontainer h4, .wblp-optionscontainer > div { margin-bottom: 0; }` + `.wblp-maincontainer .row { margin: 2px 0px; }` + `.wblp-h4 { font-size: 1.5rem; border: none; }` + `.wblp-inline { vertical-align: text-bottom !important; display: inline-block; min-width: 175px; }` + `.wblp-select { background: #2c2c2c; border-radius: 2px; color: #dedede; border: 1px solid #444; }` + `.wblp-col { display: grid; grid-template-columns: 1fr 1fr; }` + `.wblp-grid { display: grid; grid-template-columns: repeat(auto-fit, 25%); }` + `.wblp-gridaction { display: grid; grid-template-columns: 1fr 100px; grid-gap: 5px; }` + `.wblp-gridfilterlist { padding: 3px; text-align: justify; }` + `.wblp-gridfilterlist > *::after { content: ', '; }` + `.wblp-gridfilterlist > *:last-child::after { content: ''; }` + '</style>'; document.head.insertAdjacentHTML('beforeend', style); }, initialize() { wykop.params.method = 'blacklistplus'; this.addCss(); document.querySelector('#site .grid-main.m-reset-margin .tdivider').remove(); document .querySelector('#site .grid-main.m-reset-margin > div:not(.nav):not(.tdivider)') .classList.remove('rbl-block'); this.main(); }, }, addButtonToMenu() { const lastMenuElement = document.querySelector('#nav li.logged-user.ddC ul > li:last-child'); if (lastMenuElement) { const blackListMenuButton = '<li><a href="https://www.wykop.pl/ustawienia/blacklistplus/"><i class="fa fa-file"></i><span> blacklist +</span></a></li>'; lastMenuElement.insertAdjacentHTML('beforebegin', blackListMenuButton); } }, addButtonToNavbar(className) { const settingsNavbar = document.querySelector('.nav.bspace.rbl-block > ul > li:last-child'); const blackListOptionButton = `<li class="${className}"><a href="https://www.wykop.pl/ustawienia/blacklistplus/"><span>CzarnaLista+</span></a></li>`; if (className) { document .querySelector('.nav.bspace.rbl-block > ul > li:first-child') .classList.remove('active'); } settingsNavbar.insertAdjacentHTML('afterend', blackListOptionButton); }, isAllowedPage({ action, method, settings }) { let page; switch (action) { case 'settings': { const currPage = window.location.pathname.match(/\/ustawienia\/blacklistplus/); page = currPage ? 'blacklist' : 'button'; } break; case 'index': page = method === 'index' && settings.view === 'list' ? 'filter' : 'none'; break; case 'upcoming': case 'link': case 'tag': case 'entries': page = method === 'index' ? 'filter' : 'none'; break; case 'stream': { const currPage = ['index', 'active', 'hot'].includes(method); page = currPage ? 'filter' : 'none'; } break; default: page = 'none'; break; } return page; }, checkSort({ action, method, settings, tag, }) { let sort; switch (action) { case 'index': sort = settings.hp_sort; break; case 'upcoming': sort = settings.wykopalisko_sort; break; case 'tag': sort = tag; break; default: sort = method; break; } return sort; }, checkTag({ action, ajaxAutoRefresh }) { if (action === 'tag') { return ajaxAutoRefresh.url .match(/recent\/tag\/[0-9a-zA-Z]*\//)[0] .substr(11) .replace('/', ''); } return ''; }, initialize() { if (wykop.params.logged) { wykop.params.tag = this.checkTag(wykop.params); wykop.params.sort = this.checkSort(wykop.params); switch (this.isAllowedPage(wykop.params)) { case 'filter': this.filter.initialize(); break; case 'blacklist': this.option.initialize(); this.addButtonToNavbar('active'); break; case 'button': this.addButtonToNavbar(''); break; default: break; } this.addButtonToMenu(); } }, }; wblp.initialize(); }());