<commit_before>// ==UserScript==
// @name           Pixiv Download Helper
// @name:zh        Pixiv 下载助手
// @name:ja        ダウンロードヘルパー
// @description    Add download button or link for the Pixiv original picture in view page
// @description:zh 为 Pixiv 图片阅览页增加下载原图按钮或链接
// @description:ja Pixiv作品ダウンロードヘルパー
// @namespace      https://github.com/Sg4Dylan/PixivDownloadHelper
// @icon           https://www.pixiv.net/favicon.ico
// @downloadURL    https://github.com/Sg4Dylan/PixivDownloadHelper/raw/master/PixivDownloadHelper.user.js
// @updateURL      https://github.com/Sg4Dylan/PixivDownloadHelper/raw/master/PixivDownloadHelper.user.js
// @include        http://www.pixiv.net/*
// @include        https://www.pixiv.net/*
// @grant          GM_xmlhttpRequest
// @connect        i.pximg.net
// @connect        i1.pixiv.net
// @connect        i2.pixiv.net
// @connect        i3.pixiv.net
// @connect        i4.pixiv.net
// @connect        i5.pixiv.net
// @version        2017.4.30.0
// ==/UserScript==

//Turn thumbnail titles into direct links (single images) or mode=manga links.  Some kinds of thumbnails aren't covered, and an isolated few (like #17099702) don't work.
var directTitles = false;

//Append direct links below images on mode=manga pages
var directManga = true;

//Force pixiv's 'book view' style for manga sequences to something like the normal view.  Clicking a page won't scroll the window to the next page.
var breakBookView = false;

//Replace the medium thumbnail on mode=medium pages with the full size.  The image will be relinked to the full size regardless of this setting.
var fullSizeMedium = true;

//Disable lazy loading images.  These appear on mode=manga pages, rankings, and the "Recommended" section of the bookmarks page.
var dontSayLazy = true;

//Text for Button & link
var mangaModeLang = [["Right click \"Save As\" to download, file name: "], ["名前をつけて保存、ファイル名："], ["下载请使用右键“链接另存为”保存，文件名："]];
var normalModeLangZero = [["Direct download", "Right click \"Save As\" to download"], ["直接ダウンロード", "名前をつけて保存"], ["直接下载", "使用右键链接另存为"]];

//----------------------------------------------------------------//

var fullSizeWidth = "740px";

if( typeof(custom) != "undefined" )
    custom();

if( location.search.indexOf("mode=manga_big") > 0 || location.search.indexOf("mode=big") > 0 )
{
    //Make the 'big'/'manga_big' image link to itself instead of closing the window
    console.log("Mode=manga_big");
    var image = document.getElementsByTagName("img")[0];
    if( image )
    {
        var link = document.createElement("a");
        link.href = image.src;
        link.appendChild( document.createElement("img") ).src = image.src;
        document.body.innerHTML = "";
        document.body.appendChild( link );
    }
}
else if( location.search.indexOf("mode=manga") > 0 )
{
    console.log("Mode=manga");
    var container = document.getElementsByClassName("full-size-container");
    if( directManga && container.length )
    {
        //Check the mode=manga_big page for the first page, since the sample extension is always "jpg".
        var req = new XMLHttpRequest();
        req.open( "GET", location.href.replace(/page=\d+&?/,'').replace('mode=manga','mode=manga_big&page=0'), true );
        req.onload = function()
        {
            console.log("Pixiv Download Helper Patch ver 0.1 by SgDylan.");
            console.log("Parsing download link...");
            var firstImage = req.responseXML.querySelector("img[src*='_p0.']").src;
            for( var i = 0; i < container.length; i++ )
            {
                console.log("Getting link...");
                var sourcePictureLink = firstImage.replace( "_p0.", "_p"+i+"." );
                var extName = "." + sourcePictureLink.split(".").pop(-1);
                var FileName = "[" + document.getElementsByClassName("breadcrumbs")[0].children[1].children[0].innerHTML.split(">")[1];
                FileName += "][" + document.getElementsByClassName("breadcrumbs")[0].children[2].children[0].children[0].innerHTML + "][" + i + "]" + extName;
                console.log("File name: "+FileName);
                console.log("File Link: "+sourcePictureLink);
                console.log("Put download link");
                var link = document.createElement("a");
                link.textContent = multiLang(0, 0)+FileName;
                link.style.display = "block";
                link.href = sourcePictureLink;
                link.download = FileName;
                container[i].parentNode.appendChild( link );
            }
            console.log("All Ready !");
        };
        req.responseType = "document";
        req.send(null);
    }
    else if( breakBookView && document.head.innerHTML.indexOf("pixiv.context.images") > 0 )
    {
        //Book view (e.g. #54139174, #57045668)

        console.log("Mode=bookview");
        var mangaSection = document.createElement("section");
        mangaSection.className = "manga";

        var scripts = document.head.getElementsByTagName("script");
        var hits = 0;
        for( var i = 0; i < scripts.length; i++ )
        {
            var urls = scripts[i].innerHTML.match( /pixiv.context.images[^"]+"([^"]+)".*pixiv.context.originalImages[^"]+"([^"]+)"/ );
            if( urls )
            {
                var full = urls[2].replace( /\\\//g, "/");
                mangaSection.innerHTML += '
'+( directManga ? 'direct link' : '' )+'
';
                hits++;
            }
        }

        if( hits > 0 )
        {
            var sheet = document.createElement("link");
            sheet.setAttribute("rel","stylesheet");
            sheet.setAttribute("href","http://source.pixiv.net/www/css/member_illust_manga.css");
            document.head.appendChild( sheet );
            document.getElementsByTagName("html")[0].className = "verticaltext no-textcombine no-ie";
            document.body.innerHTML = "";
            document.body.appendChild( mangaSection );
        }
    }
}
else if( window == window.top )//not inside iframe
{
    if( directTitles )
    {
        //Link dem titles.
        linkThumbTitles([document]);
        new MutationObserver( function(mutationSet)
        {
            mutationSet.forEach( function(mutation){ linkThumbTitles( mutation.addedNodes ); } );
        }).observe( document.body, { childList:true, subtree:true } );
    }

    var worksDisplay = document.getElementsByClassName("works_display")[0];
    if( worksDisplay )
    {
        var mainImage, fullsizeSrc = 0, mainLink = worksDisplay.querySelector("a[href*='mode=']");
        if( mainLink )
            mainLink.removeAttribute('target');//Make link open in same window

        var oClass = document.getElementsByClassName("original-image");
        var downloadButton = document.getElementsByClassName("bookmark-container")[0];
        if( oClass.length == 1 )//47235071
        {
            var worksDiv = worksDisplay.getElementsByTagName("div")[0];
            worksDisplay.removeChild( worksDiv );//Need to remove instead of hide to prevent double source search links in other script
            var link = worksDisplay.insertBefore( document.createElement("a"), worksDisplay.firstChild );
            mainImage = link.appendChild( fullSizeMedium ? document.createElement("img") : worksDiv.getElementsByTagName("img")[0] );
            fullsizeSrc = link.href = oClass[0].getAttribute("data-src");
            //Add button to page
            if( fullSizeMedium )
            {
                console.log("Pixiv Download Helper Patch ver 0.1 by SgDylan.");
                console.log("Parsing download link...");
                var dButton0 = downloadButton.insertBefore( document.createElement("a"), downloadButton.firstChild );
                var dButton1 = downloadButton.insertBefore( document.createElement("a"), downloadButton.firstChild );
                console.log("Getting link...");
                var sourcePictureLink = oClass[0].getAttribute("data-src");
                var extName = "." + sourcePictureLink.split(".").pop(-1);
                var FileName = "[" + document.getElementsByClassName("user")[0].innerHTML;
                FileName += "][" + document.getElementsByClassName("title")[2].innerHTML + "]" + extName;
                console.log("File name: "+FileName);
                console.log("File Link: "+sourcePictureLink);
                console.log("Prepare right click button");
                dButton0.className = "_bookmark-toggle-button add-bookmark";
                dButton0.innerHTML = ""+multiLang(1, 1)+"";
                dButton0.download = FileName;
                dButton0.href = sourcePictureLink;
                console.log("Prepare right click button - Done !");
                console.log("Prepare direct click button");
                console.log("Preparing download file...");
                GM_xmlhttpRequest({
                    method: "GET",
                    url: sourcePictureLink,
                    responseType: "blob",
                    onload: function(response){
                        dButton1.className = "_bookmark-toggle-button add-bookmark";
                        dButton1.innerHTML = ""+multiLang(1, 0)+"";
                        dButton1.download = FileName;
                        dButton1.href = URL.createObjectURL(response.response);
                        console.log("Prepare direct click button - Done !");
                        console.log("All Ready !");
                    }
                });
            }
        }
        else if( mainLink && mainLink.href.indexOf("mode=big") > 0 && (mainImage = mainLink.getElementsByTagName("img")[0]) !== null )//17099702
        {
            //New thumbnails are always jpg, need to query mode=big page to get the right file extension.
            console.log("Mode=big");
            var req = new XMLHttpRequest();
            req.open( "GET", mainLink.href, true );
            req.onload = function()
            {
                mainLink.href = req.responseXML.getElementsByTagName("img")[0].src;
                if( fullSizeMedium )
                    mainImage.src = mainLink.href;
            }
            req.responseType = "document";
            req.send(null);
        }

        if( mainImage && fullSizeMedium )
        {
            if( fullsizeSrc )
                mainImage.src = fullsizeSrc;
            mainImage.setAttribute("style", "max-width: "+fullSizeWidth+"; height: auto; width: auto;");
            worksDisplay.style.width = fullSizeWidth;
        }
    }
}

if( dontSayLazy && unlazyImage() && window == window.top )
{
    //Initial page has lazy images; listen for more images added later
    new MutationObserver( function(mutationSet)
    {
        mutationSet.forEach( function(mutation)
        {
            for( var i = 0; i < mutation.addedNodes; i++ )
                unlazyImage( mutation.addedNodes[i] );
        } );
    }).observe( document.body, { childList:true, subtree:true } );
}

//----------------------------------------------------------------//

function multiLang(mode, position) {
    lang_mode = 0;
    localUsingLang = navigator.language;
    if(!localUsingLang) {
        localUsingLang = navigator.languages[0];
    }
    if(localUsingLang.indexOf("zh") !== -1) {
        lang_mode = 2;
    } else if(localUsingLang.indexOf("ja") !== -1) {
        lang_mode = 1;
    } else {
        lang_mode = 0;
    }
    switch(mode) {
        case 0:
            return mangaModeLang[lang_mode][position];
        case 1:
            return normalModeLangZero[lang_mode][position];
        default:
            break;
    }
}

function unlazyImage(target)
{
    var images = ( target || document ).querySelectorAll("img[data-src]");
    for( var i = 0; i < images.length; i++ )
        images[i].src = images[i].getAttribute("data-src");
    return images.length;
}

function pushTitleLink(list, link)
{
    var matcher;
    if( link && link.href && (matcher = link.href.match(/illust_id=(\d+)/)) && matcher[1] > 0 )
        list.push({ "id": matcher[1], "link": link });
}

function linkThumbTitles(targets)
{
    var titleList = [];

    for( var i = 0; i < targets.length; i++ )
    {
        //search.php, bookmark.php, member_illust.php, new_illust.php, member.php (uploads), mypage.php (new works)
        var foundTitle = targets[i].querySelectorAll("a[href*='mode=medium'][href*='illust_id='] > .title");
        for( var j = 0; j < foundTitle.length; j++ )
            pushTitleLink( titleList, foundTitle[j].parentNode );

        //ranking.php
        foundTitle = targets[i].querySelectorAll(".ranking-item a.title[href*='mode=medium'][href*='illust_id=']");
        for( var j = 0; j < foundTitle.length; j++ )
            pushTitleLink( titleList, foundTitle[j] );

        //member_illust.php (what image was responding to)
        foundTitle = targets[i].querySelector(".worksImageresponseInfo a.response-out-work[href*='mode=medium'][href*='illust_id=']");
        if( foundTitle )
            pushTitleLink( titleList, foundTitle );

        //response.php, member_illust.php (before/after thumbnails), ?member.php (bookmarks)?
        var image = targets[i].querySelectorAll("li a[href*='mode=medium'][href*='illust_id='] img");
        for( var j = 0; j < image.length; j++ )
        {
            var page, title;
            for( page = image[j].parentNode; page.tagName != "A"; page = page.parentNode );

            //The prev/next thumbnails on mode=medium pages have text before/after the image.  Text also follows the image on image responses listings.
            if( !(title = page.getElementsByClassName("title")[0]) && (title = page.lastChild).nodeName != '#text' && (title = page.firstChild).nodeName != '#text' )
                continue;//Can't find title element

            //Start title link at mode=medium and change later.
            var titleLink = document.createElement("a");
            titleLink.href = page.href;
            titleLink.style.color = "#333333";//Style used on some pages

            //Move the title out of the thumbnail link
            page.removeChild(title);
            titleLink.appendChild(title);
            page.parentNode.insertBefore( titleLink, page.nextSibling );

            pushTitleLink( titleList, titleLink );
        }
    }

    for( var i = 0; i < titleList.length; i++ )
        directLinkSingle( titleList[i] );
}

//Query an image's mode=medium page.
function directLinkSingle(title)
{
    var req = new XMLHttpRequest();
    req.open( "GET", "http://www.pixiv.net/member_illust.php?mode=medium&illust_id="+title.id, true );
    req.onload = function()
    {
        var select = req.responseXML.getElementsByClassName("original-image");
        if( select.length == 1 )
            title.link.href = select[0].getAttribute("data-src");
        else if( (select = req.responseXML.querySelector(".works_display a[href*='mode=manga']")) !== null )
        {
            title.link.href = select.href;
            var page = req.responseXML.querySelectorAll("ul.meta li")[1].textContent.match(/(\d+)P$/);
            if( page )
                ( title.link.firstChild.nodeName == '#text' ? title.link : title.link.firstChild ).title += " ("+page[1]+" pages)";
        }
    };
    req.responseType = "document";
    req.send(null);
}
<commit_msg>HTTPS fix for direct link titles<commit_after>// ==UserScript==
// @name           Pixiv Download Helper
// @name:zh        Pixiv 下载助手
// @name:ja        ダウンロードヘルパー
// @description    Add download button or link for the Pixiv original picture in view page
// @description:zh 为 Pixiv 图片阅览页增加下载原图按钮或链接
// @description:ja Pixiv作品ダウンロードヘルパー
// @namespace      https://github.com/Sg4Dylan/PixivDownloadHelper
// @icon           https://www.pixiv.net/favicon.ico
// @downloadURL    https://github.com/Sg4Dylan/PixivDownloadHelper/raw/master/PixivDownloadHelper.user.js
// @updateURL      https://github.com/Sg4Dylan/PixivDownloadHelper/raw/master/PixivDownloadHelper.user.js
// @include        http://www.pixiv.net/*
// @include        https://www.pixiv.net/*
// @grant          GM_xmlhttpRequest
// @connect        i.pximg.net
// @connect        i1.pixiv.net
// @connect        i2.pixiv.net
// @connect        i3.pixiv.net
// @connect        i4.pixiv.net
// @connect        i5.pixiv.net
// @version        2017.5.28.0
// ==/UserScript==

//Turn thumbnail titles into direct links (single images) or mode=manga links.  Some kinds of thumbnails aren't covered, and an isolated few (like #17099702) don't work.
var directTitles = false;

//Append direct links below images on mode=manga pages
var directManga = true;

//Force pixiv's 'book view' style for manga sequences to something like the normal view.  Clicking a page won't scroll the window to the next page.
var breakBookView = false;

//Replace the medium thumbnail on mode=medium pages with the full size.  The image will be relinked to the full size regardless of this setting.
var fullSizeMedium = true;

//Disable lazy loading images.  These appear on mode=manga pages, rankings, and the "Recommended" section of the bookmarks page.
var dontSayLazy = true;

//Text for Button & link
var mangaModeLang = [["Right click \"Save As\" to download, file name: "], ["名前をつけて保存、ファイル名："], ["下载请使用右键“链接另存为”保存，文件名："]];
var normalModeLangZero = [["Direct download", "Right click \"Save As\" to download"], ["直接ダウンロード", "名前をつけて保存"], ["直接下载", "使用右键链接另存为"]];

//----------------------------------------------------------------//

var fullSizeWidth = "740px";

if( typeof(custom) != "undefined" )
    custom();

if( location.search.indexOf("mode=manga_big") > 0 || location.search.indexOf("mode=big") > 0 )
{
    //Make the 'big'/'manga_big' image link to itself instead of closing the window
    console.log("Mode=manga_big");
    var image = document.getElementsByTagName("img")[0];
    if( image )
    {
        var link = document.createElement("a");
        link.href = image.src;
        link.appendChild( document.createElement("img") ).src = image.src;
        document.body.innerHTML = "";
        document.body.appendChild( link );
    }
}
else if( location.search.indexOf("mode=manga") > 0 )
{
    console.log("Mode=manga");
    var container = document.getElementsByClassName("full-size-container");
    if( directManga && container.length )
    {
        //Check the mode=manga_big page for the first page, since the sample extension is always "jpg".
        var req = new XMLHttpRequest();
        req.open( "GET", location.href.replace(/page=\d+&?/,'').replace('mode=manga','mode=manga_big&page=0'), true );
        req.onload = function()
        {
            console.log("Pixiv Download Helper Patch ver 0.1 by SgDylan.");
            console.log("Parsing download link...");
            var firstImage = req.responseXML.querySelector("img[src*='_p0.']").src;
            for( var i = 0; i < container.length; i++ )
            {
                console.log("Getting link...");
                var sourcePictureLink = firstImage.replace( "_p0.", "_p"+i+"." );
                var extName = "." + sourcePictureLink.split(".").pop(-1);
                var FileName = "[" + document.getElementsByClassName("breadcrumbs")[0].children[1].children[0].innerHTML.split(">")[1];
                FileName += "][" + document.getElementsByClassName("breadcrumbs")[0].children[2].children[0].children[0].innerHTML + "][" + i + "]" + extName;
                console.log("File name: "+FileName);
                console.log("File Link: "+sourcePictureLink);
                console.log("Put download link");
                var link = document.createElement("a");
                link.textContent = multiLang(0, 0)+FileName;
                link.style.display = "block";
                link.href = sourcePictureLink;
                link.download = FileName;
                container[i].parentNode.appendChild( link );
            }
            console.log("All Ready !");
        };
        req.responseType = "document";
        req.send(null);
    }
    else if( breakBookView && document.head.innerHTML.indexOf("pixiv.context.images") > 0 )
    {
        //Book view (e.g. #54139174, #57045668)

        console.log("Mode=bookview");
        var mangaSection = document.createElement("section");
        mangaSection.className = "manga";

        var scripts = document.head.getElementsByTagName("script");
        var hits = 0;
        for( var i = 0; i < scripts.length; i++ )
        {
            var urls = scripts[i].innerHTML.match( /pixiv.context.images[^"]+"([^"]+)".*pixiv.context.originalImages[^"]+"([^"]+)"/ );
            if( urls )
            {
                var full = urls[2].replace( /\\\//g, "/");
                mangaSection.innerHTML += '
'+( directManga ? 'direct link' : '' )+'
';
                hits++;
            }
        }

        if( hits > 0 )
        {
            var sheet = document.createElement("link");
            sheet.setAttribute("rel","stylesheet");
            sheet.setAttribute("href","http://source.pixiv.net/www/css/member_illust_manga.css");
            document.head.appendChild( sheet );
            document.getElementsByTagName("html")[0].className = "verticaltext no-textcombine no-ie";
            document.body.innerHTML = "";
            document.body.appendChild( mangaSection );
        }
    }
}
else if( window == window.top )//not inside iframe
{
    if( directTitles )
    {
        //Link dem titles.
        linkThumbTitles([document]);
        new MutationObserver( function(mutationSet)
        {
            mutationSet.forEach( function(mutation){ linkThumbTitles( mutation.addedNodes ); } );
        }).observe( document.body, { childList:true, subtree:true } );
    }

    var worksDisplay = document.getElementsByClassName("works_display")[0];
    if( worksDisplay )
    {
        var mainImage, fullsizeSrc = 0, mainLink = worksDisplay.querySelector("a[href*='mode=']");
        if( mainLink )
            mainLink.removeAttribute('target');//Make link open in same window

        var oClass = document.getElementsByClassName("original-image");
        var downloadButton = document.getElementsByClassName("bookmark-container")[0];
        if( oClass.length == 1 )//47235071
        {
            var worksDiv = worksDisplay.getElementsByTagName("div")[0];
            worksDisplay.removeChild( worksDiv );//Need to remove instead of hide to prevent double source search links in other script
            var link = worksDisplay.insertBefore( document.createElement("a"), worksDisplay.firstChild );
            mainImage = link.appendChild( fullSizeMedium ? document.createElement("img") : worksDiv.getElementsByTagName("img")[0] );
            fullsizeSrc = link.href = oClass[0].getAttribute("data-src");
            //Add button to page
            if( fullSizeMedium )
            {
                console.log("Pixiv Download Helper Patch ver 0.1 by SgDylan.");
                console.log("Parsing download link...");
                var dButton0 = downloadButton.insertBefore( document.createElement("a"), downloadButton.firstChild );
                var dButton1 = downloadButton.insertBefore( document.createElement("a"), downloadButton.firstChild );
                console.log("Getting link...");
                var sourcePictureLink = oClass[0].getAttribute("data-src");
                var extName = "." + sourcePictureLink.split(".").pop(-1);
                var FileName = "[" + document.getElementsByClassName("user")[0].innerHTML;
                FileName += "][" + document.getElementsByClassName("title")[2].innerHTML + "]" + extName;
                console.log("File name: "+FileName);
                console.log("File Link: "+sourcePictureLink);
                console.log("Prepare right click button");
                dButton0.className = "_bookmark-toggle-button add-bookmark";
                dButton0.innerHTML = ""+multiLang(1, 1)+"";
                dButton0.download = FileName;
                dButton0.href = sourcePictureLink;
                console.log("Prepare right click button - Done !");
                console.log("Prepare direct click button");
                console.log("Preparing download file...");
                GM_xmlhttpRequest({
                    method: "GET",
                    url: sourcePictureLink,
                    responseType: "blob",
                    onload: function(response){
                        dButton1.className = "_bookmark-toggle-button add-bookmark";
                        dButton1.innerHTML = ""+multiLang(1, 0)+"";
                        dButton1.download = FileName;
                        dButton1.href = URL.createObjectURL(response.response);
                        console.log("Prepare direct click button - Done !");
                        console.log("All Ready !");
                    }
                });
            }
        }
        else if( mainLink && mainLink.href.indexOf("mode=big") > 0 && (mainImage = mainLink.getElementsByTagName("img")[0]) !== null )//17099702
        {
            //New thumbnails are always jpg, need to query mode=big page to get the right file extension.
            console.log("Mode=big");
            var req = new XMLHttpRequest();
            req.open( "GET", mainLink.href, true );
            req.onload = function()
            {
                mainLink.href = req.responseXML.getElementsByTagName("img")[0].src;
                if( fullSizeMedium )
                    mainImage.src = mainLink.href;
            }
            req.responseType = "document";
            req.send(null);
        }

        if( mainImage && fullSizeMedium )
        {
            if( fullsizeSrc )
                mainImage.src = fullsizeSrc;
            mainImage.setAttribute("style", "max-width: "+fullSizeWidth+"; height: auto; width: auto;");
            worksDisplay.style.width = fullSizeWidth;
        }
    }
}

if( dontSayLazy && unlazyImage() && window == window.top )
{
    //Initial page has lazy images; listen for more images added later
    new MutationObserver( function(mutationSet)
    {
        mutationSet.forEach( function(mutation)
        {
            for( var i = 0; i < mutation.addedNodes; i++ )
                unlazyImage( mutation.addedNodes[i] );
        } );
    }).observe( document.body, { childList:true, subtree:true } );
}

//----------------------------------------------------------------//

function multiLang(mode, position) {
    lang_mode = 0;
    localUsingLang = navigator.language;
    if(!localUsingLang) {
        localUsingLang = navigator.languages[0];
    }
    if(localUsingLang.indexOf("zh") !== -1) {
        lang_mode = 2;
    } else if(localUsingLang.indexOf("ja") !== -1) {
        lang_mode = 1;
    } else {
        lang_mode = 0;
    }
    switch(mode) {
        case 0:
            return mangaModeLang[lang_mode][position];
        case 1:
            return normalModeLangZero[lang_mode][position];
        default:
            break;
    }
}

function unlazyImage(target)
{
    var images = ( target || document ).querySelectorAll("img[data-src]");
    for( var i = 0; i < images.length; i++ )
        images[i].src = images[i].getAttribute("data-src");
    return images.length;
}

function pushTitleLink(list, link)
{
    var matcher;
    if( link && link.href && (matcher = link.href.match(/illust_id=(\d+)/)) && matcher[1] > 0 )
        list.push({ "id": matcher[1], "link": link });
}

function linkThumbTitles(targets)
{
    var titleList = [];

    for( var i = 0; i < targets.length; i++ )
    {
        //search.php, bookmark.php, member_illust.php, new_illust.php, member.php (uploads), mypage.php (new works)
        var foundTitle = targets[i].querySelectorAll("a[href*='mode=medium'][href*='illust_id='] > .title");
        for( var j = 0; j < foundTitle.length; j++ )
            pushTitleLink( titleList, foundTitle[j].parentNode );

        //ranking.php
        foundTitle = targets[i].querySelectorAll(".ranking-item a.title[href*='mode=medium'][href*='illust_id=']");
        for( var j = 0; j < foundTitle.length; j++ )
            pushTitleLink( titleList, foundTitle[j] );

        //member_illust.php (what image was responding to)
        foundTitle = targets[i].querySelector(".worksImageresponseInfo a.response-out-work[href*='mode=medium'][href*='illust_id=']");
        if( foundTitle )
            pushTitleLink( titleList, foundTitle );

        //response.php, member_illust.php (before/after thumbnails), ?member.php (bookmarks)?
        var image = targets[i].querySelectorAll("li a[href*='mode=medium'][href*='illust_id='] img");
        for( var j = 0; j < image.length; j++ )
        {
            var page, title;
            for( page = image[j].parentNode; page.tagName != "A"; page = page.parentNode );

            //The prev/next thumbnails on mode=medium pages have text before/after the image.  Text also follows the image on image responses listings.
            if( !(title = page.getElementsByClassName("title")[0]) && (title = page.lastChild).nodeName != '#text' && (title = page.firstChild).nodeName != '#text' )
                continue;//Can't find title element

            //Start title link at mode=medium and change later.
            var titleLink = document.createElement("a");
            titleLink.href = page.href;
            titleLink.style.color = "#333333";//Style used on some pages

            //Move the title out of the thumbnail link
            page.removeChild(title);
            titleLink.appendChild(title);
            page.parentNode.insertBefore( titleLink, page.nextSibling );

            pushTitleLink( titleList, titleLink );
        }
    }

    for( var i = 0; i < titleList.length; i++ )
        directLinkSingle( titleList[i] );
}

//Query an image's mode=medium page.
function directLinkSingle(title)
{
    var req = new XMLHttpRequest();
    req.open( "GET", location.protocol+"//www.pixiv.net/member_illust.php?mode=medium&illust_id="+title.id, true );
    req.onload = function()
    {
        var select = req.responseXML.getElementsByClassName("original-image");
        if( select.length == 1 )
            title.link.href = select[0].getAttribute("data-src");
        else if( (select = req.responseXML.querySelector(".works_display a[href*='mode=manga']")) !== null )
        {
            title.link.href = select.href;
            var page = req.responseXML.querySelectorAll("ul.meta li")[1].textContent.match(/(\d+)P$/);
            if( page )
                ( title.link.firstChild.nodeName == '#text' ? title.link : title.link.firstChild ).title += " ("+page[1]+" pages)";
        }
    };
    req.responseType = "document";
    req.send(null);
}
<|endoftext|>


<commit_before>var COMMCAREHQ = {};

COMMCAREHQ.icons = {
    GRIP:   'icon-resize-vertical icon-blue fa fa-arrows-v',
    ADD:    'icon-plus icon-blue fa fa-plus',
    COPY:   'icon-copy icon-blue fa fa-copy',
    DELETE: 'icon-remove icon-blue fa fa-remove',
    PAPERCLIP: 'icon-paper-clip fa fa-paperclip'
};

var eventize = function (that) {
    'use strict';
    var events = {};
    that.on = function (tag, callback) {
        if (events[tag] === undefined) {
            events[tag] = [];
        }
        events[tag].push(callback);
        return that;
    };
    that.fire = function (tag, e) {
        var i;
        if (events[tag] !== undefined) {
            for (i = 0; i < events[tag].length; i += 1) {
                events[tag][i].apply(that, [e]);
            }
        }
        return that;
    };
    return that;
};

COMMCAREHQ.makeHqHelp = function (opts, wrap) {
    'use strict';
    wrap = wrap === undefined ? true : wrap;
    var el = $(
        '
' +
            '' +
                '
'
    );
    _.each(['content', 'title', 'html'], function(attr) {
        $('a', el).data(attr, opts[attr]);
    });
    if (wrap) {
        el.hqHelp();
    }
    return el;
};

COMMCAREHQ.transformHelpTemplate = function ($template, wrap) {
    'use strict';
    if ($template.data()) {
        var $help = COMMCAREHQ.makeHqHelp($template.data(), wrap);
        $help.insertAfter($template);
        $template.remove();
    }
};

COMMCAREHQ.initBlock = function ($elem) {
    'use strict';
    $('.submit_on_click', $elem).on("click", function (e) {
        e.preventDefault();
        if (!$(this).data('clicked')) {
            $(this).prev('form').submit();
            $(this).data('clicked', 'true').children('i').removeClass().addClass("icon-refresh icon-spin fa fa-refresh fa-spin");
        }
    });

    $('.submit').click(function (e) {
        var $form = $(this).closest('.form, form'),
            data = $form.my_serialize(),
            action = $form.attr('action') || $form.data('action');

        e.preventDefault();
        $.postGo(action, $.unparam(data));
    });
    $('.post-link').click(function (e) {
        e.preventDefault();
        $.postGo($(this).attr('href'), {});
    });

    $(".button", $elem).button().wrap('');
    $("input[type='submit']", $elem).button();
    $("input[type='text'], input[type='password'], textarea", $elem);
    $('.container', $elem).addClass('ui-widget ui-widget-content');
    $('.config', $elem).wrap('
').parent().addClass('container block ui-corner-all');
};

COMMCAREHQ.updateDOM = function (update) {
    'use strict';
    var key;
    for (key in update) {
        if (update.hasOwnProperty(key)) {
            $(key).text(update[key]).val(update[key]);
        }
    }
};

COMMCAREHQ.makeSaveButton = function(messageStrings, cssClass) {
    'use strict';
    var SaveButton = {
        /*
         options: {
         save: "Function to call when the user clicks Save",
         unsavedMessage: "Message to display when there are unsaved changes and the user leaves the page"
         }
         */
        init: function (options) {
            var button = {
                $save: $('
').text(SaveButton.message.SAVE).click(function () {
                    button.fire('save');
                }).addClass(cssClass),
                $retry: $('
').text(SaveButton.message.RETRY).click(function () {
                    button.fire('save');
                }).addClass(cssClass),
                $saving: $('
').text(SaveButton.message.SAVING).addClass('btn btn-default disabled'),
                $saved: $('
').text(SaveButton.message.SAVED).addClass('btn btn-default disabled'),
                ui: $('
').addClass('pull-right'),
                setStateWhenReady: function (state) {
                    if (this.state === 'saving') {
                        this.nextState = state;
                    } else {
                        this.setState(state);
                    }
                },
                setState: function (state) {
                    if (this.state === state) {
                        return;
                    }
                    this.state = state;
                    this.$save.detach();
                    this.$saving.detach();
                    this.$saved.detach();
                    this.$retry.detach();
                    if (state === 'save') {
                        this.ui.append(this.$save);
                    } else if (state === 'saving') {
                        this.ui.append(this.$saving);
                    } else if (state === 'saved') {
                        this.ui.append(this.$saved);
                    } else if (state === 'retry') {
                        this.ui.append(this.$retry);
                    }
                },
                ajax: function (options) {
                    var beforeSend = options.beforeSend || function () {},
                        success = options.success || function () {},
                        error = options.error || function () {},
                        that = this;
                    options.beforeSend = function (jqXHR, settings) {
                        that.setState('saving');
                        that.nextState = 'saved';
                        $.ajaxSettings.beforeSend(jqXHR, settings);
                        beforeSend.apply(this, arguments);
                    };
                    options.success = function (data) {
                        that.setState(that.nextState);
                        success.apply(this, arguments);
                    };
                    options.error = function (data) {
                        that.nextState = null;
                        that.setState('retry');
                        var customError = ((data.responseJSON && data.responseJSON.message) ? data.responseJSON.message : data.responseText);
                        alert_user(customError || SaveButton.message.ERROR_SAVING, 'danger');
                        error.apply(this, arguments);
                    };
                    var jqXHR = $.ajax(options);
                    if (!jqXHR) {
                        // request was aborted
                        that.setState('save');
                    }
                }
            };
            eventize(button);
            button.setState('saved');
            button.on('change', function () {
                this.setStateWhenReady('save');
            });
            if (options.save) {
                button.on('save', options.save);
            }
            $(window).bind('beforeunload', function () {
                var stillAttached = button.ui.parents()[button.ui.parents().length - 1].tagName.toLowerCase() == 'html';
                if (button.state !== 'saved' && stillAttached) {
                    return options.unsavedMessage || "";
                }
            });
            return button;
        },
        initForm: function ($form, options) {
            var url = $form.attr('action'),
                button = SaveButton.init({
                    unsavedMessage: options.unsavedMessage,
                    save: function () {
                        this.ajax({
                            url: url,
                            type: 'POST',
                            dataType: 'json',
                            data: $form.serialize(),
                            success: options.success
                        });
                    }
                }),
                fireChange = function () {
                    button.fire('change');
                };
            _.defer(function () {
                $form.find('*').change(fireChange);
                $form.find('input, textarea').bind('textchange', fireChange);
            });
            return button;
        },
        message: messageStrings
    };

    return SaveButton;
};

COMMCAREHQ.SaveButton = COMMCAREHQ.makeSaveButton({
    SAVE: django.gettext("Save"),
    SAVING: django.gettext("Saving..."),
    SAVED: django.gettext("Saved"),
    RETRY: django.gettext("Try Again"),
    ERROR_SAVING: django.gettext("There was an error saving")
}, 'btn btn-success');

COMMCAREHQ.DeleteButton = COMMCAREHQ.makeSaveButton({
    SAVE: django.gettext("Delete"),
    SAVING: django.gettext("Deleting..."),
    SAVED: django.gettext("Deleted"),
    RETRY: django.gettext("Try Again"),
    ERROR_SAVING: django.gettext("There was an error deleting")
}, 'btn btn-danger');

COMMCAREHQ.beforeUnload = [];

COMMCAREHQ.bindBeforeUnload = function (callback) {
    COMMCAREHQ.beforeUnload.push(callback);
};

COMMCAREHQ.beforeUnloadCallback = function () {
    for (var i = 0; i < COMMCAREHQ.beforeUnload.length; i++) {
        var message = COMMCAREHQ.beforeUnload[i]();
        if (message !== null && message !== undefined) {
            return message;
        }
    }
};

$(function () {
    'use strict';
    COMMCAREHQ.initBlock($("body"));
    $(window).bind('beforeunload', COMMCAREHQ.beforeUnloadCallback);
});

COMMCAREHQ.toggleEnabled = hqImport('hqwebapp/js/toggles.js').toggleEnabled;
COMMCAREHQ.previewEnabled = hqImport('hqwebapp/js/toggles.js').previewEnabled;
<commit_msg>catch full html pages being sent back<commit_after>var COMMCAREHQ = {};

COMMCAREHQ.icons = {
    GRIP:   'icon-resize-vertical icon-blue fa fa-arrows-v',
    ADD:    'icon-plus icon-blue fa fa-plus',
    COPY:   'icon-copy icon-blue fa fa-copy',
    DELETE: 'icon-remove icon-blue fa fa-remove',
    PAPERCLIP: 'icon-paper-clip fa fa-paperclip'
};

var eventize = function (that) {
    'use strict';
    var events = {};
    that.on = function (tag, callback) {
        if (events[tag] === undefined) {
            events[tag] = [];
        }
        events[tag].push(callback);
        return that;
    };
    that.fire = function (tag, e) {
        var i;
        if (events[tag] !== undefined) {
            for (i = 0; i < events[tag].length; i += 1) {
                events[tag][i].apply(that, [e]);
            }
        }
        return that;
    };
    return that;
};

COMMCAREHQ.makeHqHelp = function (opts, wrap) {
    'use strict';
    wrap = wrap === undefined ? true : wrap;
    var el = $(
        '
' +
            '' +
                '
'
    );
    _.each(['content', 'title', 'html'], function(attr) {
        $('a', el).data(attr, opts[attr]);
    });
    if (wrap) {
        el.hqHelp();
    }
    return el;
};

COMMCAREHQ.transformHelpTemplate = function ($template, wrap) {
    'use strict';
    if ($template.data()) {
        var $help = COMMCAREHQ.makeHqHelp($template.data(), wrap);
        $help.insertAfter($template);
        $template.remove();
    }
};

COMMCAREHQ.initBlock = function ($elem) {
    'use strict';
    $('.submit_on_click', $elem).on("click", function (e) {
        e.preventDefault();
        if (!$(this).data('clicked')) {
            $(this).prev('form').submit();
            $(this).data('clicked', 'true').children('i').removeClass().addClass("icon-refresh icon-spin fa fa-refresh fa-spin");
        }
    });

    $('.submit').click(function (e) {
        var $form = $(this).closest('.form, form'),
            data = $form.my_serialize(),
            action = $form.attr('action') || $form.data('action');

        e.preventDefault();
        $.postGo(action, $.unparam(data));
    });
    $('.post-link').click(function (e) {
        e.preventDefault();
        $.postGo($(this).attr('href'), {});
    });

    $(".button", $elem).button().wrap('');
    $("input[type='submit']", $elem).button();
    $("input[type='text'], input[type='password'], textarea", $elem);
    $('.container', $elem).addClass('ui-widget ui-widget-content');
    $('.config', $elem).wrap('
').parent().addClass('container block ui-corner-all');
};

COMMCAREHQ.updateDOM = function (update) {
    'use strict';
    var key;
    for (key in update) {
        if (update.hasOwnProperty(key)) {
            $(key).text(update[key]).val(update[key]);
        }
    }
};

COMMCAREHQ.makeSaveButton = function(messageStrings, cssClass) {
    'use strict';
    var SaveButton = {
        /*
         options: {
         save: "Function to call when the user clicks Save",
         unsavedMessage: "Message to display when there are unsaved changes and the user leaves the page"
         }
         */
        init: function (options) {
            var button = {
                $save: $('
').text(SaveButton.message.SAVE).click(function () {
                    button.fire('save');
                }).addClass(cssClass),
                $retry: $('
').text(SaveButton.message.RETRY).click(function () {
                    button.fire('save');
                }).addClass(cssClass),
                $saving: $('
').text(SaveButton.message.SAVING).addClass('btn btn-default disabled'),
                $saved: $('
').text(SaveButton.message.SAVED).addClass('btn btn-default disabled'),
                ui: $('
').addClass('pull-right'),
                setStateWhenReady: function (state) {
                    if (this.state === 'saving') {
                        this.nextState = state;
                    } else {
                        this.setState(state);
                    }
                },
                setState: function (state) {
                    if (this.state === state) {
                        return;
                    }
                    this.state = state;
                    this.$save.detach();
                    this.$saving.detach();
                    this.$saved.detach();
                    this.$retry.detach();
                    if (state === 'save') {
                        this.ui.append(this.$save);
                    } else if (state === 'saving') {
                        this.ui.append(this.$saving);
                    } else if (state === 'saved') {
                        this.ui.append(this.$saved);
                    } else if (state === 'retry') {
                        this.ui.append(this.$retry);
                    }
                },
                ajax: function (options) {
                    var beforeSend = options.beforeSend || function () {},
                        success = options.success || function () {},
                        error = options.error || function () {},
                        that = this;
                    options.beforeSend = function (jqXHR, settings) {
                        that.setState('saving');
                        that.nextState = 'saved';
                        $.ajaxSettings.beforeSend(jqXHR, settings);
                        beforeSend.apply(this, arguments);
                    };
                    options.success = function (data) {
                        that.setState(that.nextState);
                        success.apply(this, arguments);
                    };
                    options.error = function (data) {
                        that.nextState = null;
                        that.setState('retry');
                        var customError = ((data.responseJSON && data.responseJSON.message) ? data.responseJSON.message : data.responseText);
                        if (customError.indexOf('') > -1) {
                            // this is sending back a full html page, likely login, so no error message.
                            customError = null;
                        }
                        alert_user(customError || SaveButton.message.ERROR_SAVING, 'danger');
                        error.apply(this, arguments);
                    };
                    var jqXHR = $.ajax(options);
                    if (!jqXHR) {
                        // request was aborted
                        that.setState('save');
                    }
                }
            };
            eventize(button);
            button.setState('saved');
            button.on('change', function () {
                this.setStateWhenReady('save');
            });
            if (options.save) {
                button.on('save', options.save);
            }
            $(window).bind('beforeunload', function () {
                var stillAttached = button.ui.parents()[button.ui.parents().length - 1].tagName.toLowerCase() == 'html';
                if (button.state !== 'saved' && stillAttached) {
                    return options.unsavedMessage || "";
                }
            });
            return button;
        },
        initForm: function ($form, options) {
            var url = $form.attr('action'),
                button = SaveButton.init({
                    unsavedMessage: options.unsavedMessage,
                    save: function () {
                        this.ajax({
                            url: url,
                            type: 'POST',
                            dataType: 'json',
                            data: $form.serialize(),
                            success: options.success
                        });
                    }
                }),
                fireChange = function () {
                    button.fire('change');
                };
            _.defer(function () {
                $form.find('*').change(fireChange);
                $form.find('input, textarea').bind('textchange', fireChange);
            });
            return button;
        },
        message: messageStrings
    };

    return SaveButton;
};

COMMCAREHQ.SaveButton = COMMCAREHQ.makeSaveButton({
    SAVE: django.gettext("Save"),
    SAVING: django.gettext("Saving..."),
    SAVED: django.gettext("Saved"),
    RETRY: django.gettext("Try Again"),
    ERROR_SAVING: django.gettext("There was an error saving")
}, 'btn btn-success');

COMMCAREHQ.DeleteButton = COMMCAREHQ.makeSaveButton({
    SAVE: django.gettext("Delete"),
    SAVING: django.gettext("Deleting..."),
    SAVED: django.gettext("Deleted"),
    RETRY: django.gettext("Try Again"),
    ERROR_SAVING: django.gettext("There was an error deleting")
}, 'btn btn-danger');

COMMCAREHQ.beforeUnload = [];

COMMCAREHQ.bindBeforeUnload = function (callback) {
    COMMCAREHQ.beforeUnload.push(callback);
};

COMMCAREHQ.beforeUnloadCallback = function () {
    for (var i = 0; i < COMMCAREHQ.beforeUnload.length; i++) {
        var message = COMMCAREHQ.beforeUnload[i]();
        if (message !== null && message !== undefined) {
            return message;
        }
    }
};

$(function () {
    'use strict';
    COMMCAREHQ.initBlock($("body"));
    $(window).bind('beforeunload', COMMCAREHQ.beforeUnloadCallback);
});

COMMCAREHQ.toggleEnabled = hqImport('hqwebapp/js/toggles.js').toggleEnabled;
COMMCAREHQ.previewEnabled = hqImport('hqwebapp/js/toggles.js').previewEnabled;
<|endoftext|>


<commit_before>[
{"id":"layer_new","title":"Nueva capa"},
{"id":"layer_delete","title":"Suprimir capa"},
{"id":"layer_rename","title":"Renombrar capa"},
{"id":"layer_up","title":"Mover la capa hacia arriba"},
{"id":"layer_down","title":"Mover la capa hacia abajo"},
{"id":"tool_clear","title":"Nueva imagen"},
{"id":"tool_open","title":"Abrir imagen"},
{"id":"tool_save","title":"Guardar imagen"},
{"id":"tool_docprops","title":"Propiedades del documento"},
{"id":"tool_source","title":"Editar código fuente"},
{"id":"tool_undo","title":"Deshacer"},
{"id":"tool_redo","title":"Rehacer"},
{"id":"tool_clone","title":"Clonar elemento"},
{"id":"tool_delete","title":"Suprimir elemento"},
{"id":"tool_move_top","title":"Mover arriba"},
{"id":"tool_move_bottom","title":"Mover abajo"},
{"id":"group_opacity","title":"Cambiar la opacidad de elemento seleccionado"},
{"id":"angle","title":"Cambiar el ángulo de rotación"},
{"id":"tool_clone_multi","title":" Clonar elementos"},
{"id":"tool_delete_multi","title":"Suprimir los elementos seleccionados"},
{"id":"tool_alignleft","title":"Alinear lado izquierdo"},
{"id":"tool_aligncenter","title":"Centrar verticalmente"},
{"id":"tool_alignright","title":"Alinear lado derecho"},
{"id":"tool_aligntop","title":"Alinear parte superior"},
{"id":"tool_alignmiddle","title":"Centrar horizontalmente"},
{"id":"tool_alignbottom","title":"Alinear parte inferior"},
{"id":"align_relative_to","title":"Alinear con respecto a ..."},
{"id":"tool_group","title":"Agrupar elementos"},
{"id":"tool_ungroup","title":"Desagrupar elementos"},
{"id":"rect_width","title":"Cambiar el ancho rectángulo"},
{"id":"rect_height","title":"Cambiar la altura del rectágulo"},
{"id":"rect_rx","title":"Cambiar el radio de las esquinas del rectángulo"},
{"id":"image_width","title":"Cambiar el ancho de la imagen"},
{"id":"image_height","title":"Cambiar la altura de la imagen"},
{"id":"image_url","title":"Modificar URL"},
{"id":"circle_cx","title":"Cambiar la posición horizonral cx del círculo"},
{"id":"circle_cy","title":"Cambiar la posición vertical cy del círculo"},
{"id":"circle_r","title":"Cambiar el radio del círculo"},
{"id":"ellipse_cx","title":"Cambiar la posición horizontal cx de la elipse"},
{"id":"ellipse_cy","title":"Cambiar la posición vertical cy de la elipse"},
{"id":"ellipse_rx","title":"Cambiar el radio horizontal X de la elipse"},
{"id":"ellipse_ry","title":"Cambiar el radio vertical Y de la elipse"},
{"id":"line_x1","title":"Cambiar la posición horizontal X del comienzo de la línea"},
{"id":"line_y1","title":"Cambiar la posición vertical Y del comienzo de la línea"},
{"id":"line_x2","title":"Cambiar la posición horizontal X del final de la línea"},
{"id":"line_y2","title":"Cambiar la poición vertical Y del final de la línea"},
{"id":"tool_bold","title":"Texto en negrita"},
{"id":"tool_italic","title":"Texto en cursiva"},
{"id":"font_family","title":"Tipo de fuente"},
{"id":"font_size","title":"Tamaño de la fuente"},
{"id":"text","title":"Modificar el texto"},
{"id":"tool_select","title":"Herramienta de selección"},
{"id":"tool_fhpath","title":"Herramienta de lápiz"},
{"id":"tool_line","title":"Trazado de líneas"},
{"id":"tools_rect_show","title":"Cuadrado / Rectángulo"},
{"id":"tools_ellipse_show","title":"Círculo / Elipse"},
{"id":"tool_text","title":"Insertar texto"},
{"id":"tool_path","title":"Polígono"},
{"id":"tool_image","title":"Insertar imagen"},
{"id":"tool_zoom","title":"Zoom"},
{"id":"zoom","title":"Cambiar el nivel de zoom"},
{"id":"fill_color","title":"Cambiar el color de relleno"},
{"id":"stroke_color","title":"Cambiar el color del contorno"},
{"id":"stroke_width","title":"Cambiar el ancho del contorno"},
{"id":"stroke_style","title":"Cambiar el estilo del trazo del contorno"},
{"id":"palette","title":"Haga clic para cambiar el color de relleno. Pulse Mayús y haga clic para cambiar el color del contorno."},
{"id":"tool_square","title":"Cuadrado"},
{"id":"tool_rect","title":"Rectángulo"},
{"id":"tool_fhrect","title":"Rectángulo a mano alzada"},
{"id":"tool_circle","title":"Círculo"},
{"id":"tool_ellipse","title":"Elipse"},
{"id":"tool_fhellipse","title":"Elipse a mano alzada"},
{"id":"bkgnd_color","title":"Cambiar color de fondo / opacidad"},
{"id":"rwidthLabel","textContent":"Ancho:"},
{"id":"rheightLabel","textContent":"Alto:"},
{"id":"cornerRadiusLabel","textContent":"Radio de la esquina:"},
{"id":"iwidthLabel","textContent":"ancho:"},
{"id":"iheightLabel","textContent":"alto:"},
{"id":"svginfo_width","textContent":"Ancho:"},
{"id":"svginfo_height","textContent":"Alto:"},
{"id":"angleLabel","textContent":"ángulo:"},
{"id":"relativeToLabel","textContent":"en relación con:"},
{"id":"zoomLabel","textContent":"Zoom:"},
{"id":"layersLabel","textContent":"Capas:"},
{"id":"selectedPredefined","textContent":"Seleccionar predefinido:"},
{"id":"fitToContent","textContent":"Ajustar al contenido"},
{"id":"tool_source_save","textContent":"Aplicar cambios"},
{"id":"tool_docprops_save","textContent":"Aceptar"},
{"id":"tool_docprops_cancel","textContent":"Cancelar"},
{"id":"tool_source_cancel","textContent":"Cancelar"},
{"id":"fit_to_all","textContent":"Ajustar a todo el contenido"},
{"id":"fit_to_layer_content","textContent":"Ajustar al contenido de la capa"},
{"id":"fit_to_sel","textContent":"Ajustar a la selección"},
{"id":"fit_to_canvas","textContent":"Ajustar al lienzo"},
{"id":"selected_objects","textContent":"Objetos seleccionados"},
{"id":"largest_object","textContent":"El objeto más grande"},
{"id":"smallest_object","textContent":"El objeto más pequeño"},
{"id":"page","textContent":"Página"},
{"id":"fill_tool_bottom","textContent":"Relleno:"},
{"id":"stroke_tool_bottom","textContent":"Contorno:"},
{"id":"svninfo_dim","textContent":"Dimensiones del lienzo"},
{"id":"path_node_x","title":"Cambiar la posición horizontal X del nodo"},
{"id":"path_node_y","title":"Cambiar la posición vertical Y del nodo"},
{"id":"seg_type","title":"Cambiar el tipo de segmento"},
{"id":"straight_segments","textContent":"Recto"},
{"id":"curve_segments","textContent":"Curvo"},
{"id":"tool_node_clone","title":"Clonar nodo"},
{"id":"tool_node_delete","title":"Suprimir nodo"},
{"id":"selLayerLabel","textContent":"Desplazar elementos hacia:"},
{"id":"selLayerNames","title":"Mover los elementos seleccionados a otra capa"},
{"id":"sidepanel_handle","title":"Arrastrar hacia la izquierda/derecha para modificar el tamaño del panel lateral","textContent":"C a p a s"},
{"id":"tool_wireframe","title":"Modo wireframe"},
{"id":"svginfo_image_props","textContent":"Propiedades de Imagen"},
{"id":"svginfo_title","textContent":"Título"},
{"id":"svginfo_dim","textContent":"Tamaño del lienzo"},
{"id":"includedImages","textContent":"Imágenes integradas"},
{"id":"image_opt_embed","textContent":"Integrar imágenes en forma de datos (archivos locales)"},
{"id":"image_opt_ref","textContent":"Usar la referencia del archivo"},
{"id":"svginfo_editor_prefs","textContent":"Preferencias del Editor"},
{"id":"svginfo_lang","textContent":"Idioma"},
{"id":"svginfo_change_background","textContent":"Fondo del editor"},
{"id":"svginfo_bg_note","textContent":"Nota: El fondo no se guardará junto con la imagen."},
{"id":"svginfo_icons","textContent":"Tamaño de los iconos"},
{"id":"icon_small","textContent":"Pequeño"},
{"id":"icon_medium","textContent":"Mediano"},
{"id":"icon_large","textContent":"Grande"},
{"id":"icon_xlarge","textContent":"Muy grande"},
{"id":"selected_x","title":"Cambiar la posición horizontal X"},
{"id":"selected_y","title":"Cambiar la posición vertical Y"},
{"id":"tool_topath","title":"Convertir en ruta"},
{"id":"tool_reorient","title":"Reorientar la ruta"},
{"id":"tool_node_link","title":"Enlazar puntos de control"},
{"js_strings": {
	"invalidAttrValGiven":"Valor no válido",
	"noContentToFitTo":"No existe un contenido al que ajustarse.",
	'layer':"Capa",
	"dupeLayerName":"¡Ya existe una capa con este nombre!",
	"enterUniqueLayerName":"Introduzca otro nombre distinto para la capa.",
	"enterNewLayerName":"Introduzca el nuevo nombre de la capa.",
	"layerHasThatName":"El nombre introducido es el nombre actual de la capa.",
	"QmoveElemsToLayer":"¿Desplazar los elementos seleccionados a la capa '%s'?",
	"QwantToClear":"¿Desea suprimir el dibujo?\n¡El historial de acciones también se borrará!",
	"QerrorsRevertToSource":"Existen errores sintácticos en su código fuente SVG.\n¿Desea volver al código fuente SVG original?",
	"QignoreSourceChanges":"¿Desea ignorar los cambios realizados sobre el código fuente SVG?",
	"featNotSupported":"Función no compatible.",
	"enterNewImgURL":"Introduzca la nueva URL de la imagen.",
	"Aceptar":"Aceptar",
	"cancel":"Cancelar",
	"pathNodeTooltip":"Arrastre el nodo para desplazarlo. Haga doble clic sobre el nodo para cambiar el tipo de segmento.",
	"pathCtrlPtTooltip":"Arrastre el punto de control para ajustar las propiedades de la curva.",
	"key_up":"arriba",
	"key_down":"abajo",
	"key_backspace":"retroceso",
	"key_del":"suprimir"
	}
}
]<commit_msg>Update the Spanish language file by Alicia.<commit_after>[
{"id":"layer_new","title":"Nueva capa"},
{"id":"layer_delete","title":"Suprimir capa"},
{"id":"layer_rename","title":"Renombrar capa"},
{"id":"layer_up","title":"Mover la capa hacia arriba"},
{"id":"layer_down","title":"Mover la capa hacia abajo"},
{"id":"tool_clear","title":"Nueva imagen"},
{"id":"tool_open","title":"Abrir imagen"},
{"id":"tool_save","title":"Guardar imagen"},
{"id":"tool_docprops","title":"Propiedades del documento"},
{"id":"tool_source","title":"Editar código fuente"},
{"id":"tool_undo","title":"Deshacer"},
{"id":"tool_redo","title":"Rehacer"},
{"id":"tool_clone","title":"Clonar elemento"},
{"id":"tool_delete","title":"Suprimir elemento"},
{"id":"tool_move_top","title":"Mover arriba"},
{"id":"tool_move_bottom","title":"Mover abajo"},
{"id":"group_opacity","title":"Cambiar la opacidad de elemento seleccionado"},
{"id":"angle","title":"Cambiar el ángulo de rotación"},
{"id":"tool_clone_multi","title":" Clonar elementos"},
{"id":"tool_delete_multi","title":"Suprimir los elementos seleccionados"},
{"id":"tool_alignleft","title":"Alinear lado izquierdo"},
{"id":"tool_aligncenter","title":"Centrar verticalmente"},
{"id":"tool_alignright","title":"Alinear lado derecho"},
{"id":"tool_aligntop","title":"Alinear parte superior"},
{"id":"tool_alignmiddle","title":"Centrar horizontalmente"},
{"id":"tool_alignbottom","title":"Alinear parte inferior"},
{"id":"align_relative_to","title":"Alinear con respecto a ..."},
{"id":"tool_group","title":"Agrupar elementos"},
{"id":"tool_ungroup","title":"Desagrupar elementos"},
{"id":"rect_width","title":"Cambiar el ancho rectángulo"},
{"id":"rect_height","title":"Cambiar la altura del rectágulo"},
{"id":"rect_rx","title":"Cambiar el radio de las esquinas del rectángulo"},
{"id":"image_width","title":"Cambiar el ancho de la imagen"},
{"id":"image_height","title":"Cambiar la altura de la imagen"},
{"id":"image_url","title":"Modificar URL"},
{"id":"circle_cx","title":"Cambiar la posición horizonral cx del círculo"},
{"id":"circle_cy","title":"Cambiar la posición vertical cy del círculo"},
{"id":"circle_r","title":"Cambiar el radio del círculo"},
{"id":"ellipse_cx","title":"Cambiar la posición horizontal cx de la elipse"},
{"id":"ellipse_cy","title":"Cambiar la posición vertical cy de la elipse"},
{"id":"ellipse_rx","title":"Cambiar el radio horizontal X de la elipse"},
{"id":"ellipse_ry","title":"Cambiar el radio vertical Y de la elipse"},
{"id":"line_x1","title":"Cambiar la posición horizontal X del comienzo de la línea"},
{"id":"line_y1","title":"Cambiar la posición vertical Y del comienzo de la línea"},
{"id":"line_x2","title":"Cambiar la posición horizontal X del final de la línea"},
{"id":"line_y2","title":"Cambiar la poición vertical Y del final de la línea"},
{"id":"tool_bold","title":"Texto en negrita"},
{"id":"tool_italic","title":"Texto en cursiva"},
{"id":"font_family","title":"Tipo de fuente"},
{"id":"font_size","title":"Tamaño de la fuente"},
{"id":"text","title":"Modificar el texto"},
{"id":"tool_select","title":"Herramienta de selección"},
{"id":"tool_fhpath","title":"Herramienta de lápiz"},
{"id":"tool_line","title":"Trazado de líneas"},
{"id":"tools_rect_show","title":"Cuadrado / Rectángulo"},
{"id":"tools_ellipse_show","title":"Círculo / Elipse"},
{"id":"tool_text","title":"Insertar texto"},
{"id":"tool_path","title":"Herramienta de trazado"},
{"id":"tool_image","title":"Insertar imagen"},
{"id":"tool_zoom","title":"Zoom"},
{"id":"zoom","title":"Cambiar el nivel de zoom"},
{"id":"fill_color","title":"Cambiar el color de relleno"},
{"id":"stroke_color","title":"Cambiar el color del contorno"},
{"id":"stroke_width","title":"Cambiar el ancho del contorno"},
{"id":"stroke_style","title":"Cambiar el estilo del trazo del contorno"},
{"id":"palette","title":"Haga clic para cambiar el color de relleno. Pulse Mayús y haga clic para cambiar el color del contorno."},
{"id":"tool_square","title":"Cuadrado"},
{"id":"tool_rect","title":"Rectángulo"},
{"id":"tool_fhrect","title":"Rectángulo a mano alzada"},
{"id":"tool_circle","title":"Círculo"},
{"id":"tool_ellipse","title":"Elipse"},
{"id":"tool_fhellipse","title":"Elipse a mano alzada"},
{"id":"bkgnd_color","title":"Cambiar color de fondo / opacidad"},
{"id":"rwidthLabel","textContent":"Ancho:"},
{"id":"rheightLabel","textContent":"Alto:"},
{"id":"cornerRadiusLabel","textContent":"Radio de la esquina:"},
{"id":"iwidthLabel","textContent":"ancho:"},
{"id":"iheightLabel","textContent":"alto:"},
{"id":"svginfo_width","textContent":"Ancho:"},
{"id":"svginfo_height","textContent":"Alto:"},
{"id":"angleLabel","textContent":"ángulo:"},
{"id":"relativeToLabel","textContent":"en relación con:"},
{"id":"zoomLabel","textContent":"Zoom:"},
{"id":"layersLabel","textContent":"Capas:"},
{"id":"selectedPredefined","textContent":"Seleccionar predefinido:"},
{"id":"fitToContent","textContent":"Ajustar al contenido"},
{"id":"tool_source_save","textContent":"Aplicar cambios"},
{"id":"tool_docprops_save","textContent":"Aceptar"},
{"id":"tool_docprops_cancel","textContent":"Cancelar"},
{"id":"tool_source_cancel","textContent":"Cancelar"},
{"id":"fit_to_all","textContent":"Ajustar a todo el contenido"},
{"id":"fit_to_layer_content","textContent":"Ajustar al contenido de la capa"},
{"id":"fit_to_sel","textContent":"Ajustar a la selección"},
{"id":"fit_to_canvas","textContent":"Ajustar al lienzo"},
{"id":"selected_objects","textContent":"Objetos seleccionados"},
{"id":"largest_object","textContent":"El objeto más grande"},
{"id":"smallest_object","textContent":"El objeto más pequeño"},
{"id":"page","textContent":"Página"},
{"id":"fill_tool_bottom","textContent":"Relleno:"},
{"id":"stroke_tool_bottom","textContent":"Contorno:"},
{"id":"path_node_x","title":"Cambiar la posición horizontal X del nodo"},
{"id":"path_node_y","title":"Cambiar la posición vertical Y del nodo"},
{"id":"seg_type","title":"Cambiar el tipo de segmento"},
{"id":"straight_segments","textContent":"Recto"},
{"id":"curve_segments","textContent":"Curvo"},
{"id":"tool_node_clone","title":"Clonar nodo"},
{"id":"tool_node_delete","title":"Suprimir nodo"},
{"id":"selLayerLabel","textContent":"Desplazar elementos hacia:"},
{"id":"selLayerNames","title":"Mover los elementos seleccionados a otra capa"},
{"id":"sidepanel_handle","title":"Arrastrar hacia la izquierda/derecha para modificar el tamaño del panel lateral","textContent":"C a p a s"},
{"id":"tool_wireframe","title":"Modo wireframe"},
{"id":"svginfo_image_props","textContent":"Propiedades de Imagen"},
{"id":"svginfo_title","textContent":"Título"},
{"id":"svginfo_dim","textContent":"Tamaño del lienzo"},
{"id":"includedImages","textContent":"Imágenes integradas"},
{"id":"image_opt_embed","textContent":"Integrar imágenes en forma de datos (archivos locales)"},
{"id":"image_opt_ref","textContent":"Usar la referencia del archivo"},
{"id":"svginfo_editor_prefs","textContent":"Preferencias del Editor"},
{"id":"svginfo_lang","textContent":"Idioma"},
{"id":"svginfo_change_background","textContent":"Fondo del editor"},
{"id":"svginfo_bg_note","textContent":"Nota: El fondo no se guardará junto con la imagen."},
{"id":"svginfo_icons","textContent":"Tamaño de los iconos"},
{"id":"icon_small","textContent":"Pequeño"},
{"id":"icon_medium","textContent":"Mediano"},
{"id":"icon_large","textContent":"Grande"},
{"id":"icon_xlarge","textContent":"Muy grande"},
{"id":"selected_x","title":"Cambiar la posición horizontal X"},
{"id":"selected_y","title":"Cambiar la posición vertical Y"},
{"id":"tool_topath","title":"Convertir en ruta"},
{"id":"tool_reorient","title":"Reorientar la ruta"},
{"id":"tool_node_link","title":"Enlazar puntos de control"},
{"js_strings": {
	"invalidAttrValGiven":"Valor no válido",
	"noContentToFitTo":"No existe un contenido al que ajustarse.",
	'layer':"Capa",
	"dupeLayerName":"¡Ya existe una capa con este nombre!",
	"enterUniqueLayerName":"Introduzca otro nombre distinto para la capa.",
	"enterNewLayerName":"Introduzca el nuevo nombre de la capa.",
	"layerHasThatName":"El nombre introducido es el nombre actual de la capa.",
	"QmoveElemsToLayer":"¿Desplazar los elementos seleccionados a la capa '%s'?",
	"QwantToClear":"¿Desea suprimir el dibujo?\n¡El historial de acciones también se borrará!",
	"QerrorsRevertToSource":"Existen errores sintácticos en su código fuente SVG.\n¿Desea volver al código fuente SVG original?",
	"QignoreSourceChanges":"¿Desea ignorar los cambios realizados sobre el código fuente SVG?",
	"featNotSupported":"Función no compatible.",
	"enterNewImgURL":"Introduzca la nueva URL de la imagen.",
	"Aceptar":"Aceptar",
	"cancel":"Cancelar",
	"pathNodeTooltip":"Arrastre el nodo para desplazarlo. Haga doble clic sobre el nodo para cambiar el tipo de segmento.",
	"pathCtrlPtTooltip":"Arrastre el punto de control para ajustar las propiedades de la curva.",
	"key_up":"arriba",
	"key_down":"abajo",
	"key_backspace":"retroceso",
	"key_del":"suprimir"
	}
}
]<|endoftext|>


<commit_before>import antlr4 from 'antlr4';
import JavaScriptLexer from './JavaScriptLexer.js';

export default class JavaScriptLexerBase extends antlr4.Lexer {

    constructor(input) {
        super(input);
        this.scopeStrictModes = new Array();
        this.lastToken = null;
        this.useStrictDefault = false;
        this.useStrictCurrent = false;
        this.templateDepth = 0;
    }

    getStrictDefault() {
        return this.useStrictDefault;
    }

    setUseStrictDefault(value) {
        this.useStrictDefault = value;
        this.useStrictCurrent = value;
    }

    IsStrictMode() {
        return this.useStrictCurrent;
    }

    IsInTemplateString() {
        return this.templateDepth > 0;
    }

    getCurrentToken() {
        return nextToken.call(this);
    }

    nextToken() {
        var next = super.nextToken.call(this);

        if (next.channel === antlr4.Token.DEFAULT_CHANNEL) {
            this.lastToken = next;
        }
        return next;
    }

    ProcessOpenBrace() {
        this.useStrictCurrent =
            this.scopeStrictModes.length > 0 && this.scopeStrictModes[this.scopeStrictModes.length - 1]
                ? true
                : this.useStrictDefault;
        this.scopeStrictModes.push(this.useStrictCurrent);
    }

    ProcessCloseBrace() {
        this.useStrictCurrent =
            this.scopeStrictModes.length > 0
                ? this.scopeStrictModes.pop()
                : this.useStrictDefault;
    }

    ProcessStringLiteral() {
        if (this.lastToken === null ||
                this.lastToken.type === JavaScriptLexer.OpenBrace) {
            if (super.text === '"use strict"' || super.text === "'use strict'") {
                if (this.scopeStrictModes.length > 0) {
                    this.scopeStrictModes.pop();
                }
                this.useStrictCurrent = true;
                this.scopeStrictModes.push(this.useStrictCurrent);
            }
        }
    }

    IncreaseTemplateDepth() {
        this.templateDepth++;
    }

    DecreaseTemplateDepth() {
        this.templateDepth--;
    }

    IsRegexPossible() {
        if (this.lastToken === null) {
            return true;
        }

        switch (this.lastToken.type) {
            case JavaScriptLexer.Identifier:
            case JavaScriptLexer.NullLiteral:
            case JavaScriptLexer.BooleanLiteral:
            case JavaScriptLexer.This:
            case JavaScriptLexer.CloseBracket:
            case JavaScriptLexer.CloseParen:
            case JavaScriptLexer.OctalIntegerLiteral:
            case JavaScriptLexer.DecimalLiteral:
            case JavaScriptLexer.HexIntegerLiteral:
            case JavaScriptLexer.StringLiteral:
            case JavaScriptLexer.PlusPlus:
            case JavaScriptLexer.MinusMinus:
                return false;
            default:
                return true;
        }
    }

    IsStartOfFile() {
        return this.lastToken === null;
    }
}
<commit_msg>Stop invoking undefined methods<commit_after>import antlr4 from 'antlr4';
import JavaScriptLexer from './JavaScriptLexer.js';

export default class JavaScriptLexerBase extends antlr4.Lexer {

    constructor(input) {
        super(input);
        this.scopeStrictModes = new Array();
        this.lastToken = null;
        this.useStrictDefault = false;
        this.useStrictCurrent = false;
        this.templateDepth = 0;
    }

    getStrictDefault() {
        return this.useStrictDefault;
    }

    setUseStrictDefault(value) {
        this.useStrictDefault = value;
        this.useStrictCurrent = value;
    }

    IsStrictMode() {
        return this.useStrictCurrent;
    }

    IsInTemplateString() {
        return this.templateDepth > 0;
    }

    getCurrentToken() {
        return this.nextToken();
    }

    nextToken() {
        var next = super.nextToken();

        if (next.channel === antlr4.Token.DEFAULT_CHANNEL) {
            this.lastToken = next;
        }
        return next;
    }

    ProcessOpenBrace() {
        this.useStrictCurrent =
            this.scopeStrictModes.length > 0 && this.scopeStrictModes[this.scopeStrictModes.length - 1]
                ? true
                : this.useStrictDefault;
        this.scopeStrictModes.push(this.useStrictCurrent);
    }

    ProcessCloseBrace() {
        this.useStrictCurrent =
            this.scopeStrictModes.length > 0
                ? this.scopeStrictModes.pop()
                : this.useStrictDefault;
    }

    ProcessStringLiteral() {
        if (this.lastToken === null ||
                this.lastToken.type === JavaScriptLexer.OpenBrace) {
            if (super.text === '"use strict"' || super.text === "'use strict'") {
                if (this.scopeStrictModes.length > 0) {
                    this.scopeStrictModes.pop();
                }
                this.useStrictCurrent = true;
                this.scopeStrictModes.push(this.useStrictCurrent);
            }
        }
    }

    IncreaseTemplateDepth() {
        this.templateDepth++;
    }

    DecreaseTemplateDepth() {
        this.templateDepth--;
    }

    IsRegexPossible() {
        if (this.lastToken === null) {
            return true;
        }

        switch (this.lastToken.type) {
            case JavaScriptLexer.Identifier:
            case JavaScriptLexer.NullLiteral:
            case JavaScriptLexer.BooleanLiteral:
            case JavaScriptLexer.This:
            case JavaScriptLexer.CloseBracket:
            case JavaScriptLexer.CloseParen:
            case JavaScriptLexer.OctalIntegerLiteral:
            case JavaScriptLexer.DecimalLiteral:
            case JavaScriptLexer.HexIntegerLiteral:
            case JavaScriptLexer.StringLiteral:
            case JavaScriptLexer.PlusPlus:
            case JavaScriptLexer.MinusMinus:
                return false;
            default:
                return true;
        }
    }

    IsStartOfFile() {
        return this.lastToken === null;
    }
}
<|endoftext|>


<commit_before>var mongoose = require('mongoose');
var User = require('./userSchema');
var Session = require('./sessionSchema');
var Comment = require('./commentSchema');

// search for user
function findOneUser(req, res) {
  var id = req.query.id;
  User.findOne({ _id: id }, (err, user) => {
    if (err) {
      console.log('error in findUser', err)
    } else {
      console.log('user', user)
      res.json(user);
    }
  })
}

// create new session, add it to user permissions, add first comment to db (ADD COMMENT TO USER COMMENT ARRAY TOO)
function createSession(req, res) {
  var creator_id = req.body.user_id; // make sure this matches up to fetch method body params
  var title = req.body.title;
  var text = req.body.text;
  var timestamp = new Date();

  Session.create({creator_id: creator_id, timestamp: timestamp, title: title, modified: timestamp}, (err, session) => {
    if (err) {
      console.log('error in add session', err)
    } else {
      //saved!
      console.log('session saved', session);
      // add session to user permissions array
      // create comment using session id that was just created
      Comment.create({ creator_id: session.creator_id, parent_id: 'root', session_id: session._id, title: title, text: text, children: [], upvotes: [], downvotes: [], score: 0, timestamp: timestamp }, (err, comment) => {
        if (err) {
          console.log('error in create comment', err)
        } else {
          //saved!
          User.findOne({ _id: creator_id}, (err, user) => {
            if (err) {
              console.log('error in addSessionToUser', err)
            } else {
              user.created_sessions.push(session);
              user.comments.push(comment);
              user.accessible_sessions.push(session);
              user.save();
              console.log('session id saved in user array')
            }
          })
          console.log('comment saved', comment);
          // send comment to front end
          res.json(comment);
        }
      })
    }
  })
};

// fetch all comments for a given session
function findAllComments(req, res) {
  var session_id = req.query.id; // req.query = sessionId ( is it called req.query or req.params? )
  Comment.find({ session_id: session_id }, (err, comments) => {
    if (err) {
      console.log('err: ', err)
      res.sendStatus(400)
    } else {
      console.log('comments', comments)
      res.json(comments);
    }
  });
}

// add user permissions when they're invited to a session
function addUserPermission(req, res){
  var emails = req.body.emails;
  var sessionId = req.body.session_id;
  var newSession = {};
  Session.findOne({ _id: sessionId}, (err, session) => {
    if (err) {
      console.log('error finding session', err)
    } else {
      newSession = session;
    }
  })
  console.log('NEW SESSION', newSession)
  for (var email of emails) {
    User.findOne({ email: email }, (err, user) => {
      if (err) {
        console.log('error in accessible sessions route', err)
      } else {
        if (user) {
          if(!user.accessible_sessions.includes(newSession)) {
            user.accessible_sessions.push(newSession);
            user.new_sessions.push(newSession);
            user.save();
            console.log('session permissions saved')
          } else {
            console.log('user already has permission for this session')
          }
        }
      }
    })
  }
}

// update new sessions array
function newSession(req, res) {
  var id = req.body.id //userId based on state
  User.findOne({ _id: id }, (err, user) => {
    if (err) {
      console.log('error in changeNewSessionStatus', err);
    } else {
      user.new_sessions = [];
      user.save();
      console.log('new sessions array reset');
    }
  })
}

// create new comment
function addComment(req, res) {
  var userId = req.body.user_id;
  var parentId = req.body.parent_id;
  var sessionId = req.body.session_id;
  var title = req.body.title;
  var text = req.body.text;
  var timestamp = new Date();

  Session.findOne({_id: sessionId}, (err, session) => {
    if (err) {
      console.log('error in session modified', err)
    } else {
      session.modified = timestamp;
      console.log('session modified', session);
      session.save();
    }
  })

  Comment.create({ creator_id: userId, parent_id: parentId, session_id: sessionId, title: title, text: text, children: [], upvotes: [], downvotes: [], score: 0, timestamp: timestamp }, (err, comment) => {
      if (err) {
        console.log('error!', err)
      } else {
        //saved!
        console.log('comment saved in db');
        User.findOne({ _id: userId}, (err, user) => {
          if (err) {
            console.log('error in addSessionToUser', err)
          } else {
            user.comments.push(comment);
            user.save();
            console.log('comment id saved in user array')
          }
        })
        Comment.findOne({ _id: parentId}, (err, parentComment) => {
          if (err) {
            console.log('error in parent comment', err);
          }
          if (parentComment) {
            parentComment.children.push(comment);
            console.log('parentComment children', parentComment.children);
            parentComment.save();
            console.log('new comment id saved in children array');
          }
        })
        Comment.findOne({ _id: comment._id }, (err, comment) => {
          if (err) {
            console.log('err in comment find one');
            res.sendStatus(404);
          } else {
            res.json(comment);
          }
      })
    }
  })
};

//find a specific comment
function findComment(req, res) {
  var commentId = req.query.id;
  Comment.findOne({ _id: commentId }, (err, comment) => {
    if (err) {
      console.log('err in /comment get function')
    } else {
      console.log(comment);
      res.json(comment);
    }
  })
}

// edit a comment
function editComment(req, res) {
  var comment_id = req.body.comment_id;
  var title = req.body.title;
  var text = req.body.text;
  Comment.findOne({ _id: comment_id }, (err, comment) => {
    if (err) {
      console.log('error in edit', err);
    } else {
      comment.title = title;
      comment.text = text;
      comment.save();
      res.json(comment);
    }
  });
}

// upvote a comment
function upVote(req, res) {
  var comment_id = req.body.comment_id;
  var clickUser = req.body.user_id;    //clickUser = the user who clicked the upvote button
  Comment.findOne({ _id: comment_id }, (err, comment) => {
    if (err) {
      console.log('error in upvote', err);
      res.sendStatus(400);
    } else {
      if (!comment.upvotes.includes(clickUser)) {
        comment.upvotes.push(clickUser)
        comment.score += 1;
        if (comment.downvotes.includes(clickUser)) {
          var i = comment.downvotes.indexOf(clickUser)
          comment.downvotes.splice(i, 1)
          comment.score += 1
        }
      } else {
        var i = comment.upvotes.indexOf(clickUser);
        comment.upvotes.splice(i, 1);
        comment.score -= 1;
      }
      comment.save();
      console.log('upvote saved', comment)
      res.json(comment);
    }
  })
}

// downvote a comment
function downVote(req, res) {
  var comment_id = req.body.comment_id;
  var clickUser = req.body.user_id; //clickUser = the user who clicked the downvote button

  Comment.findOne({ _id: comment_id }, function(err, comment) {
    if (err) {
      console.log('error in downvote', err);
      res.sendStatus(400);
    } else {
      if (!comment.downvotes.includes(clickUser)) {
        comment.downvotes.push(clickUser)
        comment.score -= 1;
        if (comment.upvotes.includes(clickUser)) {
          var i = comment.upvotes.indexOf(clickUser)
          comment.upvotes.splice(i, 1)
          comment.score -= 1;
        }
      } else {
        var i = comment.downvotes.indexOf(clickUser);
        comment.downvotes.splice(i, 1);
        comment.score += 1;
      }
      comment.save();
      console.log('downvote saved')
      res.json(comment);
    }
  })
}

// insert user into db
function insertUser(profile) {
  User.create({google_id: profile.id, displayName: profile.displayName, created_sessions: [], accessible_sessions: [], comments: [], new_sessions: []}, (err, user) => {
    if (err) {
      console.log('error in insert user', err);
    } else {
      console.log('user saved');
    }
  })
}

// delete session

// function deleteSession(req, res){
//   var id = req.query.id;
//   console.log('id in delete session', id)
//   Session.findOne({ _id: id }, (err, session) => {
//     if (err) {
//       console.log('error in delete session', err)
//     } else {
//       session.remove();
//       // this also needs to delete the session from the user's accessible_sessions
//       // and remove all comments with that session id
//     }
//   })
//   res.sendStatus(200)
// }

exports.findOneUser = findOneUser;
exports.createSession = createSession;
exports.findAllComments = findAllComments;
exports.addUserPermission = addUserPermission;
exports.newSession = newSession;
exports.addComment = addComment;
exports.findComment = findComment;
exports.editComment = editComment;
exports.upVote = upVote;
exports.downVote = downVote;
exports.insertUser = insertUser;
// exports.deleteSession = deleteSession;
<commit_msg>Debug session permissions route<commit_after>var mongoose = require('mongoose');
var User = require('./userSchema');
var Session = require('./sessionSchema');
var Comment = require('./commentSchema');

// search for user
function findOneUser(req, res) {
  var id = req.query.id;
  User.findOne({ _id: id }, (err, user) => {
    if (err) {
      console.log('error in findUser', err)
    } else {
      console.log('user', user)
      res.json(user);
    }
  })
}

// create new session, add it to user permissions, add first comment to db (ADD COMMENT TO USER COMMENT ARRAY TOO)
function createSession(req, res) {
  var creator_id = req.body.user_id; // make sure this matches up to fetch method body params
  var title = req.body.title;
  var text = req.body.text;
  var timestamp = new Date();

  Session.create({creator_id: creator_id, timestamp: timestamp, title: title, modified: timestamp}, (err, session) => {
    if (err) {
      console.log('error in add session', err)
    } else {
      //saved!
      console.log('session saved', session);
      // add session to user permissions array
      // create comment using session id that was just created
      Comment.create({ creator_id: session.creator_id, parent_id: 'root', session_id: session._id, title: title, text: text, children: [], upvotes: [], downvotes: [], score: 0, timestamp: timestamp }, (err, comment) => {
        if (err) {
          console.log('error in create comment', err)
        } else {
          //saved!
          User.findOne({ _id: creator_id}, (err, user) => {
            if (err) {
              console.log('error in addSessionToUser', err)
            } else {
              user.created_sessions.push(session);
              user.comments.push(comment);
              user.accessible_sessions.push(session);
              user.save();
              console.log('session id saved in user array')
            }
          })
          console.log('comment saved', comment);
          // send comment to front end
          res.json(comment);
        }
      })
    }
  })
};

// fetch all comments for a given session
function findAllComments(req, res) {
  var session_id = req.query.id; // req.query = sessionId ( is it called req.query or req.params? )
  Comment.find({ session_id: session_id }, (err, comments) => {
    if (err) {
      console.log('err: ', err)
      res.sendStatus(400)
    } else {
      console.log('comments', comments)
      res.json(comments);
    }
  });
}

// add user permissions when they're invited to a session
function addUserPermission(req, res) {
  var emails = req.body.emails;
  var sessionId = req.body.session_id;
  Session.findOne({ _id: sessionId}, (err, session) => {
    if (err) {
      console.log('error finding session', err)
    } else {
      console.log('SESSION', session)
      for (var email of emails) {
        User.findOne({ email: email }, (err, user) => {
          if (err) {
            console.log('error in accessible sessions route', err)
          } else {
            if (user) {
              if(!user.accessible_sessions.includes(session)) {
                user.accessible_sessions.push(session);
                user.new_sessions.push(session);
                user.save();
                console.log('session permissions saved')
              } else {
                console.log('user already has permission for this session')
              }
            }
          }
        })
      }
    }
  })
}

// update new sessions array
function newSession(req, res) {
  var id = req.body.id //userId based on state
  User.findOne({ _id: id }, (err, user) => {
    if (err) {
      console.log('error in changeNewSessionStatus', err);
    } else {
      user.new_sessions = [];
      user.save();
      console.log('new sessions array reset');
    }
  })
}

// create new comment
function addComment(req, res) {
  var userId = req.body.user_id;
  var parentId = req.body.parent_id;
  var sessionId = req.body.session_id;
  var title = req.body.title;
  var text = req.body.text;
  var timestamp = new Date();

  Session.findOne({_id: sessionId}, (err, session) => {
    if (err) {
      console.log('error in session modified', err)
    } else {
      session.modified = timestamp;
      console.log('session modified', session);
      session.save();
    }
  })

  Comment.create({ creator_id: userId, parent_id: parentId, session_id: sessionId, title: title, text: text, children: [], upvotes: [], downvotes: [], score: 0, timestamp: timestamp }, (err, comment) => {
      if (err) {
        console.log('error!', err)
      } else {
        //saved!
        console.log('comment saved in db');
        User.findOne({ _id: userId}, (err, user) => {
          if (err) {
            console.log('error in addSessionToUser', err)
          } else {
            user.comments.push(comment);
            user.save();
            console.log('comment id saved in user array')
          }
        })
        Comment.findOne({ _id: parentId}, (err, parentComment) => {
          if (err) {
            console.log('error in parent comment', err);
          }
          if (parentComment) {
            parentComment.children.push(comment);
            console.log('parentComment children', parentComment.children);
            parentComment.save();
            console.log('new comment id saved in children array');
          }
        })
        Comment.findOne({ _id: comment._id }, (err, comment) => {
          if (err) {
            console.log('err in comment find one');
            res.sendStatus(404);
          } else {
            res.json(comment);
          }
      })
    }
  })
};

//find a specific comment
function findComment(req, res) {
  var commentId = req.query.id;
  Comment.findOne({ _id: commentId }, (err, comment) => {
    if (err) {
      console.log('err in /comment get function')
    } else {
      console.log(comment);
      res.json(comment);
    }
  })
}

// edit a comment
function editComment(req, res) {
  var comment_id = req.body.comment_id;
  var title = req.body.title;
  var text = req.body.text;
  Comment.findOne({ _id: comment_id }, (err, comment) => {
    if (err) {
      console.log('error in edit', err);
    } else {
      comment.title = title;
      comment.text = text;
      comment.save();
      res.json(comment);
    }
  });
}

// upvote a comment
function upVote(req, res) {
  var comment_id = req.body.comment_id;
  var clickUser = req.body.user_id;    //clickUser = the user who clicked the upvote button
  Comment.findOne({ _id: comment_id }, (err, comment) => {
    if (err) {
      console.log('error in upvote', err);
      res.sendStatus(400);
    } else {
      if (!comment.upvotes.includes(clickUser)) {
        comment.upvotes.push(clickUser)
        comment.score += 1;
        if (comment.downvotes.includes(clickUser)) {
          var i = comment.downvotes.indexOf(clickUser)
          comment.downvotes.splice(i, 1)
          comment.score += 1
        }
      } else {
        var i = comment.upvotes.indexOf(clickUser);
        comment.upvotes.splice(i, 1);
        comment.score -= 1;
      }
      comment.save();
      console.log('upvote saved', comment)
      res.json(comment);
    }
  })
}

// downvote a comment
function downVote(req, res) {
  var comment_id = req.body.comment_id;
  var clickUser = req.body.user_id; //clickUser = the user who clicked the downvote button

  Comment.findOne({ _id: comment_id }, function(err, comment) {
    if (err) {
      console.log('error in downvote', err);
      res.sendStatus(400);
    } else {
      if (!comment.downvotes.includes(clickUser)) {
        comment.downvotes.push(clickUser)
        comment.score -= 1;
        if (comment.upvotes.includes(clickUser)) {
          var i = comment.upvotes.indexOf(clickUser)
          comment.upvotes.splice(i, 1)
          comment.score -= 1;
        }
      } else {
        var i = comment.downvotes.indexOf(clickUser);
        comment.downvotes.splice(i, 1);
        comment.score += 1;
      }
      comment.save();
      console.log('downvote saved')
      res.json(comment);
    }
  })
}

// insert user into db
function insertUser(profile) {
  User.create({google_id: profile.id, displayName: profile.displayName, created_sessions: [], accessible_sessions: [], comments: [], new_sessions: []}, (err, user) => {
    if (err) {
      console.log('error in insert user', err);
    } else {
      console.log('user saved');
    }
  })
}

// delete session

// function deleteSession(req, res){
//   var id = req.query.id;
//   console.log('id in delete session', id)
//   Session.findOne({ _id: id }, (err, session) => {
//     if (err) {
//       console.log('error in delete session', err)
//     } else {
//       session.remove();
//       // this also needs to delete the session from the user's accessible_sessions
//       // and remove all comments with that session id
//     }
//   })
//   res.sendStatus(200)
// }

exports.findOneUser = findOneUser;
exports.createSession = createSession;
exports.findAllComments = findAllComments;
exports.addUserPermission = addUserPermission;
exports.newSession = newSession;
exports.addComment = addComment;
exports.findComment = findComment;
exports.editComment = editComment;
exports.upVote = upVote;
exports.downVote = downVote;
exports.insertUser = insertUser;
// exports.deleteSession = deleteSession;
<|endoftext|>