Skip to content

Instantly share code, notes, and snippets.

@vsemozhetbyt
Last active February 6, 2018 21:15
Show Gist options
  • Save vsemozhetbyt/f26932dfc20b43dee8540e8a669989e9 to your computer and use it in GitHub Desktop.
Save vsemozhetbyt/f26932dfc20b43dee8540e8a669989e9 to your computer and use it in GitHub Desktop.

Revisions

  1. vsemozhetbyt revised this gist Feb 6, 2018. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions news_bmk_instagram.js
    Original file line number Diff line number Diff line change
    @@ -40,13 +40,13 @@
    const opts = {
    'www.instagram.com': {
    additionalCSS: '[data-vmb-news-div] { display: block !important; }',
    idLinkSelector: 'div._mck9w._gvoze._f2mse a[href]',
    getPost: nd => nd.closest('div._mck9w._gvoze._f2mse'),
    idLinkSelector: 'div._mck9w._gvoze._tn0ps a[href]',
    getPost: nd => nd.closest('div._mck9w._gvoze._tn0ps'),
    getIdLink: nd => nd.querySelector('a[href]'),
    getBookmark: url => d.querySelector(`a[href='${url}']`),
    getPostgroupAncestor: nd => nd.closest('div._70iju'),
    getPrevPost: nd => xp(`./preceding::div[${xpClass('_mck9w _gvoze _f2mse')}][1]`, nd),
    getNextPost: nd => xp(`./following::div[${xpClass('_mck9w _gvoze _f2mse')}]`, nd),
    getPostgroupAncestor: nd => nd.closest('div._6d3hm._mnav9'),
    getPrevPost: nd => xp(`./preceding::div[${xpClass('_mck9w _gvoze _tn0ps')}][1]`, nd),
    getNextPost: nd => xp(`./following::div[${xpClass('_mck9w _gvoze _tn0ps')}]`, nd),
    scrollTop: -55,
    storage: IDB,
    siteFuncs: ['\u221e', '\u25b2', '\u25bc', '\u00a0\u222b\u00a0'],
  2. vsemozhetbyt created this gist Jan 28, 2018.
    233 changes: 233 additions & 0 deletions news_bmk_instagram.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,233 @@
    /* ************************************************************************** */
    // ==UserScript==
    // @name News Bookmark Instagram
    // @namespace vsemozhetbyt
    // @description News Reading from Bookmark in Instagram
    // @version 1
    // @include https://www.instagram.com/*
    // @noframes
    // @grant none
    // @nocompat Chrome
    // ==/UserScript==
    /* ************************************************************************** */

    'use strict';

    (() => {
    const d = document;
    const b = d.body;

    if (d.querySelector('[data-vmb-news-div]')) return;

    const funcs = [
    {
    name: '\u221e',
    func: bookmarkFind,
    }, {
    name: '\u25b2',
    func: navToPost,
    args: 'getPrevPost',
    }, {
    name: '\u25bc',
    func: navToPost,
    args: 'getNextPost',
    }, {
    name: '\u00a0\u222b\u00a0',
    func: bookmarkSave,
    },
    ];

    const opts = {
    'www.instagram.com': {
    additionalCSS: '[data-vmb-news-div] { display: block !important; }',
    idLinkSelector: 'div._mck9w._gvoze._f2mse a[href]',
    getPost: nd => nd.closest('div._mck9w._gvoze._f2mse'),
    getIdLink: nd => nd.querySelector('a[href]'),
    getBookmark: url => d.querySelector(`a[href='${url}']`),
    getPostgroupAncestor: nd => nd.closest('div._70iju'),
    getPrevPost: nd => xp(`./preceding::div[${xpClass('_mck9w _gvoze _f2mse')}][1]`, nd),
    getNextPost: nd => xp(`./following::div[${xpClass('_mck9w _gvoze _f2mse')}]`, nd),
    scrollTop: -55,
    storage: IDB,
    siteFuncs: ['\u221e', '\u25b2', '\u25bc', '\u00a0\u222b\u00a0'],
    autoload: [bookmarkFind],
    },
    };

    const opt = opts[location.hostname];
    if (!opt) {
    alert('Wrong site.');
    return;
    }

    const newsSt = b.appendChild(d.createElement('style'));
    newsSt.setAttribute('data-vmb-news-style', '');
    newsSt.textContent = `
    [data-vmb-news-div] { position: fixed; top: 0px; left: 50%; z-index: 10000; padding: 2px !important; background-color: gainsboro !important; outline: 1px solid black !important; }
    [data-vmb-news-div] * { margin: 0px 2px !important; }
    ${opt.additionalCSS || ''}
    `;

    if (opt.getBookmark || opt.getPrevPost) {
    const bmkNavSt = b.appendChild(d.createElement('style'));
    bmkNavSt.setAttribute('data-vmb-bookmark-nav-style', '');
    bmkNavSt.textContent = `
    body { counter-reset: vmb-bookmark-nav-counter; }
    ${opt.idLinkSelector}:before { content: counter(vmb-bookmark-nav-counter, decimal-leading-zero)'. '; counter-increment: vmb-bookmark-nav-counter; }
    [data-vmb-focus], [data-vmb-focus] ${opt.idLinkSelector} { outline: 1px solid lime !important; }
    [data-vmb-bookmark], [data-vmb-bookmark] *, [data-vmb-bookmark] ~ *, [data-vmb-bookmark] ~ * * { background-color: gainsboro !important; }
    ${opt.getPostgroupAncestor ? '[data-vmb-bookmark-postgroup-ancestor] ~ *, [data-vmb-bookmark-postgroup-ancestor] ~ * * { background-color: gainsboro !important; }' : ''}
    `;
    b.addEventListener('mouseup', setFocus);
    }

    const newsDiv = d.createElement('div');
    newsDiv.setAttribute('data-vmb-news-div', '');
    funcs.forEach(
    (func) => {
    if (opt.siteFuncs.includes(func.name)) {
    const btn = newsDiv.appendChild(d.createElement('button'));
    btn.type = 'button';
    btn.textContent = func.name;
    btn.addEventListener('click', () => { func.func(func.args); });
    }
    },
    );
    b.appendChild(newsDiv);
    if (opt.autoload) opt.autoload.forEach((func) => { func(); });

    function setFocus(evt) {
    const newFocus = opt.getPost(evt.target);
    if (newFocus) {
    const oldFocus = d.querySelector('[data-vmb-focus]');
    if (oldFocus) oldFocus.removeAttribute('data-vmb-focus');
    newFocus.setAttribute('data-vmb-focus', '');
    }
    }

    function bookmarkFind() {
    opt.storage(`vmb_bookmark_${location.href}`, null, (url) => {
    if (!url) {
    alert('Bookmark not found. Save a new one.');
    return;
    }

    const idLink = opt.getBookmark(url);
    let focus;
    if (idLink) focus = opt.getPost(idLink);

    if (focus) {
    const oldBookmark = d.querySelector('[data-vmb-bookmark]');
    if (oldBookmark) oldBookmark.removeAttribute('data-vmb-bookmark');

    focus.setAttribute('data-vmb-bookmark', '');

    if (opt.getPostgroupAncestor) {
    const oldBookmarkAncestor = d.querySelector('[data-vmb-bookmark-postgroup-ancestor]');
    if (oldBookmarkAncestor) {
    oldBookmarkAncestor.removeAttribute('data-vmb-bookmark-postgroup-ancestor');
    }

    opt.getPostgroupAncestor(focus).setAttribute('data-vmb-bookmark-postgroup-ancestor', '');
    }

    setFocus({ target: idLink });
    focus.scrollIntoView(true);
    scrollBy(0, opt.scrollTop);
    } else {
    scrollTo(0, b.scrollHeight);
    }
    });
    }

    function bookmarkSave() {
    const focus = d.querySelector('[data-vmb-focus]');
    if (focus) {
    const idLink = opt.getIdLink(focus);
    if (idLink) {
    const oldBookmark = d.querySelector('[data-vmb-bookmark]');
    if (oldBookmark) oldBookmark.removeAttribute('data-vmb-bookmark');

    focus.setAttribute('data-vmb-bookmark', '');

    if (opt.getPostgroupAncestor) {
    const oldBookmarkAncestor = d.querySelector('[data-vmb-bookmark-postgroup-ancestor]');
    if (oldBookmarkAncestor) oldBookmarkAncestor.removeAttribute('data-vmb-bookmark-postgroup-ancestor');

    opt.getPostgroupAncestor(focus).setAttribute('data-vmb-bookmark-postgroup-ancestor', '');
    }
    opt.storage(`vmb_bookmark_${location.href}`, idLink.getAttribute('href'));
    } else {
    alert('Sorry. Strange post. Select another one.');
    }
    } else {
    alert('Click on the post.');
    }
    }

    function navToPost(dirFunk) {
    const focus = d.querySelector('[data-vmb-focus]');
    if (focus) {
    const scrollPad = 50;

    const destPost = opt[dirFunk](focus);
    if (destPost) {
    setFocus({ target: destPost.querySelector('a[href]') });

    if (opt[dirFunk](destPost)) {
    destPost.scrollIntoView(true);
    scrollBy(0, opt.scrollTop);
    } else if (dirFunk === 'getPrevPost') {
    ;
    } else {
    scrollBy(0, scrollPad);
    }
    } else if (dirFunk === 'getPrevPost') {
    ;
    } else {
    scrollBy(0, scrollPad);
    }
    } else {
    const idLink = b.querySelector(opt.idLinkSelector);
    setFocus({ target: idLink });
    opt.getPost(idLink).scrollIntoView(true);
    scrollBy(0, opt.scrollTop);
    }
    }

    function IDB(key, value, func) {
    const openRequest = indexedDB.open('vmbIDBNews', 1);

    openRequest.onerror = (evtErr) => { console.error(evtErr.target.error); };

    openRequest.onupgradeneeded = (evt) => { evt.target.result.createObjectStore('news'); };

    openRequest.onsuccess = (evt) => {
    const db = evt.target.result;

    db.onerror = (evtErr) => { console.error(evtErr.target.error); db.close(); };

    if (value) {
    db.transaction('news', 'readwrite')
    .objectStore('news')
    .put(value, key)
    .onsuccess = () => { db.close(); };
    } else {
    db.transaction('news', 'readonly')
    .objectStore('news')
    .get(key)
    .onsuccess = (evtGet) => { func(evtGet.target.result); db.close(); };
    }
    };
    }

    function xp(expression, contextNode = b) {
    return d.evaluate(
    expression, contextNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null,
    ).singleNodeValue;
    }

    function xpClass(clsName) {
    return `contains(concat(" ", normalize-space(@class), " "), " ${clsName} ")`;
    }
    })();