<commit_before>
var AliasList = function(){}
AliasList.prototype = {
    aliasesArr : [],
    numAddedLast: 0,
    add: function(aliases) {
        var oldLen = this.aliasesArr.length
        this.aliasesArr = _.union(aliases, this.aliasesArr)
        this.numAddedLast = this.aliasesArr.length - oldLen
        this.onChange()
        return this.numAddedLast
    },
    count: function() {
        return this.aliasesArr.length
    },
    forApi: function() {
        return this.aliasesArr
    },
    clear: function() {
        this.aliasesArr = []
        this.onChange()
        return true
    },
    onChange: function() {
        $("p#artcounter span").html(this.count())
    }
}

var AliasListInputs = function() {}
AliasListInputs.prototype = {
    aliases: new AliasList(),
    init: function() {
        var that = this

        this.textareaPlaceholders()
        this.initHelpModals()

        // import orcid, github, and slideshare from usernames
        $(".control-group.username input")
            .each(function(){
                $(this).blur(function(){
                    if (!$(this).val()) return false
                    var importer = new UsernameImporter(that.aliases, this)
                    importer.pull()
            })
        })

        // import from bibtex
        $("input#input_bibtex").change(function(){
            var importer = new BibtexImporter(that.aliases, this)
            importer.pull()
        })

        // set up the submit button
        $("#go-button").click(function(){
            var action = "update"

            // fetch ids from the textareas first
            $("textarea.ids").not(".default").each(function(){
                var importer = new TextareaImporter(that.aliases, this)
                importer.pull()
            })
            var button = new SubmitButton(that.aliases, this)

            if ($(this).hasClass(("update"))) {
                console.log("update!")
                return button.update(coll)
            }
            else if ($(this).hasClass(("create"))) {
                console.log("create!")
                return button.make()
            }

        })

        // clear the aliases when input modals are dismissed
        $("#import-products-modal").on("hide", function(){
            that.resetList.call(that)
        })

    },
    textareaPlaceholders: function() {
        // placeholder replacement
        $("textarea").each(function(){
            var this$ = $(this)
            var placeholderText = this$.attr("data-placeholder")
            this$.val(placeholderText).addClass("default")
            this$.blur(function(){
                if (!this$.val()) {
                    this$.val(placeholderText).addClass("default")
                    return false
                }
            })
            this$.focus(function(){
                if (this$.val() == placeholderText){
                    this$.val("").removeClass("default")
                }
            })
        })
    },
    initHelpModals: function(){

        $("#google-scholar-help-link").click(function(){
            $("#google-scholar-help").modal("show")
            return false
        })
        $("#orcid-help-link").click(function(){
            $("#orcid-help").modal("show")
            return false
        })
        $("#bibtex-fail-help a").click(function(){
            $(".modal").modal("hide")
            if ($(this).hasClass("uservoice")) {
                UserVoice.showPopupWidget()
            }
        })
    },
    resetList: function() {
        console.log("REEEEEEEEEEE SEEEETTTT!")
        this.aliases.clear()
        $(".import-products .control-group").each(function(){
            changeControlGroupState(this, "ready")
        })
        $(".import-products input").val("")
        $(".import-products textarea").val("")
        this.textareaPlaceholders()
    }
}

var SubmitButton = function(aliases, elem){
    this.aliases = aliases
    this.elem$ = $(elem)
}
SubmitButton.prototype = {
    make: function() {
        if (!this.start()) return false
        var requestObj = {
            alias_tiids: this.aliases.forApi(),
            email: $("div.inline-register input.email").val(),
            password: $("div.inline-register input.password").val(),
            given_name: $("div.inline-register input.given").val(),
            surname: $("div.inline-register input.surname").val()
        }

        $.ajax({
           url: webapp_root+'/user',
           type: "POST",
           dataType: "json",
           contentType: "application/json; charset=utf-8",
           data:  JSON.stringify(requestObj),
           success: function(data){
               console.log("finished creating the user!")
               location.href = "/" + data.url_slug
           }
        })
        return false
    },
    update: function(coll){
        if (!this.start()) return false
        this.addItemsToCollection(coll, this.aliases.forApi())
        return false
    },
    start:function(){
        if (!this.aliases.forApi().length) {
            alert("You haven't added any products.")
            return false
        }
        else if ($("div.inline-register .email").hasClass("failure")) {
            alert("please enter an email that's not already in use.")
            return false
        }
        else {
            changeControlGroupState(this.elem$, "working")
            console.log(this.elem$)
            return true
        }
    },
    failure: function() {
    },
    addItemsToCollection: function(coll, aliases) {
        var callbacks = {
            onSuccess: function(){location.reload()}
        }
        coll.addItems(aliases, callbacks)

    }
}

// Import aliases from external services that want a username
var UsernameImporter = function(aliases, elem) {
    this.aliases = aliases
    this.elem$ = $(elem)
}
UsernameImporter.prototype = {

    pull: function() {
        var that = this
        this.start()
        var providerName = this.elem$.attr("id").replace("input_", "")
        var queryStr = this.elem$.val()

        $.ajax({
            url: api_root+"/provider/"+providerName+"/memberitems/"+queryStr+"?method=sync",
            type: "GET",
            dataType: "json",
            success: function(data){that.done.call(that, data)},
            error: function(request){that.failure.call(that, request)}
        });

    },
    start:function() {
        changeControlGroupState(this.elem$, "working")
    },
    update: function(){},
    done: function(data){
        changeControlGroupState(this.elem$, "success")
        this.aliases.add(data.memberitems)
        this.elem$
            .parents(".control-group")
            .find("span.success span.value")
            .html(this.aliases.numAddedLast)
    },
    failure: function(request) {
        changeControlGroupState(this.elem$, "failure")
    }
}

// Import aliases from external services that want a username
var TextareaImporter = function(aliases, elem) {
    this.aliases = aliases
    this.elem$ = $(elem)
}
TextareaImporter.prototype = {
    pull: function(){
        var newAliases = this.parseTextareaArtifacts(this.elem$.val())
        this.aliases.add(newAliases)
    },
    parseTextareaArtifacts: function(str) {
        var ids = str.split("\n");
        var ret = [];
        for (i=0; i<ids.length; i++){
            var artifact = [];
            var thisId = ids[i];
            if (thisId.indexOf(":") > 0) {
                artifact[0] = thisId.split(':')[0]; // namespace
                artifact[1] = thisId.substr(artifact[0].length + 1) // id

                // handle urls:
                if (artifact[0] == "http" || artifact[0] == "https"){
                    artifact[0] = "url";
                    artifact[1] = thisId
                }
            }
            else {
                if (thisId.length > 0) {
                    var isnum_with_possible_period = /^[\d\.]+$/.test(thisId)
                    // handle dois entered without the doi prefix
                    if (thisId.substring(0,3) == "10.") {
                        artifact[0] = "doi"
                    } else if (isnum_with_possible_period && (thisId.length > 5) && (thisId.length <= 8)) {
                        // definition of pmid from http://www.nlm.nih.gov/bsd/mms/medlineelements.html#pmid
                        // this doesn't catch short PMIDs, but that's ok
                        artifact[0] = "pmid"
                    }
                    else {
                        artifact[0] = "unknown"
                    }
                    artifact[1] = thisId
                }
            }
            if (typeof artifact[1] != "undefined") {
                ret.push(artifact);
            }
        }
        return ret;
    },
    start:function(){},
    update:function(){},
    done:function(){},
    failure:function(){}

}

// upload bibtex from google scholar
var BibtexImporter = function(aliases, elem) {
    this.aliases = aliases
    this.elem$ = $(elem)
    this.bibtexEntriesParsedFromFile = []
}
BibtexImporter.prototype = {

    pull: function() {
        var that = this
        this.start()
        var providerName = this.elem$.attr("id").replace("input_", "")

        var formData = new FormData();
        formData.append('file', this.elem$[0].files[0]);

        $.ajax({
                   url: api_root+'/provider/bibtex/memberitems',
                   type: "POST",
                   processData: false,
                   contentType: false,
                   timeout: 5*1000,  // 5 seconds
                   data: formData,
                   dataType: "json",
                   success:  function(data){
                       entries = {
                           biblio: data,
                           total: data.length,
                           aliases: []
                       }
                       console.log("got some items back:", data)
                       that.update.call(that, entries)
                   },
                   error: function(request) {that.failure.call(that, request)}
               });

    },
    start:function() {
        changeControlGroupState(this.elem$, "working")
    },
    update: function(entries, errors){
        errors = errors || 0
        var that = this

        // end conditions
        if (!entries.biblio.length) return this.done(entries)
        if (errors > 3) return this.failure()

        for (k in entries.biblio){
            entries.aliases[k] = ["biblio", entries.biblio[k]]
        }

        that.updateProgressbar.call(
                            that,
                            entries.total,
                            entries.biblio.length
                        )
        this.done(entries)
    },
    done: function(entries){
        console.log("we're done!")
        changeControlGroupState(this.elem$, "success")
        this.aliases.add(entries.aliases)
        this.elem$
            .parents(".control-group")
            .find("span.success span.value")
            .html(this.aliases.numAddedLast)
    },
    failure: function() {
        changeControlGroupState(this.elem$, "failure")
    },
    updateProgressbar: function(total, remaining) {
        var done = total - remaining
        percentDone = Math.round(done / total * 100)
        this.elem$
            .parents(".control-group")
            .find("span.working span.value")
            .html(percentDone)
    }
}
<commit_msg>In /create page, set "name" to "Anonymous User" if creator leaves it blank.<commit_after>
var AliasList = function(){}
AliasList.prototype = {
    aliasesArr : [],
    numAddedLast: 0,
    add: function(aliases) {
        var oldLen = this.aliasesArr.length
        this.aliasesArr = _.union(aliases, this.aliasesArr)
        this.numAddedLast = this.aliasesArr.length - oldLen
        this.onChange()
        return this.numAddedLast
    },
    count: function() {
        return this.aliasesArr.length
    },
    forApi: function() {
        return this.aliasesArr
    },
    clear: function() {
        this.aliasesArr = []
        this.onChange()
        return true
    },
    onChange: function() {
        $("p#artcounter span").html(this.count())
    }
}

var AliasListInputs = function() {}
AliasListInputs.prototype = {
    aliases: new AliasList(),
    init: function() {
        var that = this

        this.textareaPlaceholders()
        this.initHelpModals()

        // import orcid, github, and slideshare from usernames
        $(".control-group.username input")
            .each(function(){
                $(this).blur(function(){
                    if (!$(this).val()) return false
                    var importer = new UsernameImporter(that.aliases, this)
                    importer.pull()
            })
        })

        // import from bibtex
        $("input#input_bibtex").change(function(){
            var importer = new BibtexImporter(that.aliases, this)
            importer.pull()
        })

        // set up the submit button
        $("#go-button").click(function(){
            var action = "update"

            // fetch ids from the textareas first
            $("textarea.ids").not(".default").each(function(){
                var importer = new TextareaImporter(that.aliases, this)
                importer.pull()
            })
            var button = new SubmitButton(that.aliases, this)

            if ($(this).hasClass(("update"))) {
                console.log("update!")
                return button.update(coll)
            }
            else if ($(this).hasClass(("create"))) {
                console.log("create!")
                return button.make()
            }

        })

        // clear the aliases when input modals are dismissed
        $("#import-products-modal").on("hide", function(){
            that.resetList.call(that)
        })

    },
    textareaPlaceholders: function() {
        // placeholder replacement
        $("textarea").each(function(){
            var this$ = $(this)
            var placeholderText = this$.attr("data-placeholder")
            this$.val(placeholderText).addClass("default")
            this$.blur(function(){
                if (!this$.val()) {
                    this$.val(placeholderText).addClass("default")
                    return false
                }
            })
            this$.focus(function(){
                if (this$.val() == placeholderText){
                    this$.val("").removeClass("default")
                }
            })
        })
    },
    initHelpModals: function(){

        $("#google-scholar-help-link").click(function(){
            $("#google-scholar-help").modal("show")
            return false
        })
        $("#orcid-help-link").click(function(){
            $("#orcid-help").modal("show")
            return false
        })
        $("#bibtex-fail-help a").click(function(){
            $(".modal").modal("hide")
            if ($(this).hasClass("uservoice")) {
                UserVoice.showPopupWidget()
            }
        })
    },
    resetList: function() {
        console.log("REEEEEEEEEEE SEEEETTTT!")
        this.aliases.clear()
        $(".import-products .control-group").each(function(){
            changeControlGroupState(this, "ready")
        })
        $(".import-products input").val("")
        $(".import-products textarea").val("")
        this.textareaPlaceholders()
    }
}

var SubmitButton = function(aliases, elem){
    this.aliases = aliases
    this.elem$ = $(elem)
}
SubmitButton.prototype = {

    make: function() {
        if (!this.start()) return false

        var givenName = $("div.inline-register input.given").val() || "Anonymous"
        var surname = $("div.inline-register input.surname").val() || "User"

        var requestObj = {
            alias_tiids: this.aliases.forApi(),
            email: $("div.inline-register input.email").val(),
            password: $("div.inline-register input.password").val(),
            given_name: givenName,
            surname: surname
        }

        $.ajax({
           url: webapp_root+'/user',
           type: "POST",
           dataType: "json",
           contentType: "application/json; charset=utf-8",
           data:  JSON.stringify(requestObj),
           success: function(data){
               console.log("finished creating the user!")
               location.href = "/" + data.url_slug
           }
        })
        return false
    },
    update: function(coll){
        if (!this.start()) return false
        this.addItemsToCollection(coll, this.aliases.forApi())
        return false
    },
    start:function(){
        if (!this.aliases.forApi().length) {
            alert("You haven't added any products.")
            return false
        }
        else if ($("div.inline-register .email").hasClass("failure")) {
            alert("please enter an email that's not already in use.")
            return false
        }
        else {
            changeControlGroupState(this.elem$, "working")
            console.log(this.elem$)
            return true
        }
    },
    failure: function() {
    },
    addItemsToCollection: function(coll, aliases) {
        var callbacks = {
            onSuccess: function(){location.reload()}
        }
        coll.addItems(aliases, callbacks)

    }
}

// Import aliases from external services that want a username
var UsernameImporter = function(aliases, elem) {
    this.aliases = aliases
    this.elem$ = $(elem)
}
UsernameImporter.prototype = {

    pull: function() {
        var that = this
        this.start()
        var providerName = this.elem$.attr("id").replace("input_", "")
        var queryStr = this.elem$.val()

        $.ajax({
            url: api_root+"/provider/"+providerName+"/memberitems/"+queryStr+"?method=sync",
            type: "GET",
            dataType: "json",
            success: function(data){that.done.call(that, data)},
            error: function(request){that.failure.call(that, request)}
        });

    },
    start:function() {
        changeControlGroupState(this.elem$, "working")
    },
    update: function(){},
    done: function(data){
        changeControlGroupState(this.elem$, "success")
        this.aliases.add(data.memberitems)
        this.elem$
            .parents(".control-group")
            .find("span.success span.value")
            .html(this.aliases.numAddedLast)
    },
    failure: function(request) {
        changeControlGroupState(this.elem$, "failure")
    }
}

// Import aliases from external services that want a username
var TextareaImporter = function(aliases, elem) {
    this.aliases = aliases
    this.elem$ = $(elem)
}
TextareaImporter.prototype = {
    pull: function(){
        var newAliases = this.parseTextareaArtifacts(this.elem$.val())
        this.aliases.add(newAliases)
    },
    parseTextareaArtifacts: function(str) {
        var ids = str.split("\n");
        var ret = [];
        for (i=0; i<ids.length; i++){
            var artifact = [];
            var thisId = ids[i];
            if (thisId.indexOf(":") > 0) {
                artifact[0] = thisId.split(':')[0]; // namespace
                artifact[1] = thisId.substr(artifact[0].length + 1) // id

                // handle urls:
                if (artifact[0] == "http" || artifact[0] == "https"){
                    artifact[0] = "url";
                    artifact[1] = thisId
                }
            }
            else {
                if (thisId.length > 0) {
                    var isnum_with_possible_period = /^[\d\.]+$/.test(thisId)
                    // handle dois entered without the doi prefix
                    if (thisId.substring(0,3) == "10.") {
                        artifact[0] = "doi"
                    } else if (isnum_with_possible_period && (thisId.length > 5) && (thisId.length <= 8)) {
                        // definition of pmid from http://www.nlm.nih.gov/bsd/mms/medlineelements.html#pmid
                        // this doesn't catch short PMIDs, but that's ok
                        artifact[0] = "pmid"
                    }
                    else {
                        artifact[0] = "unknown"
                    }
                    artifact[1] = thisId
                }
            }
            if (typeof artifact[1] != "undefined") {
                ret.push(artifact);
            }
        }
        return ret;
    },
    start:function(){},
    update:function(){},
    done:function(){},
    failure:function(){}

}

// upload bibtex from google scholar
var BibtexImporter = function(aliases, elem) {
    this.aliases = aliases
    this.elem$ = $(elem)
    this.bibtexEntriesParsedFromFile = []
}
BibtexImporter.prototype = {

    pull: function() {
        var that = this
        this.start()
        var providerName = this.elem$.attr("id").replace("input_", "")

        var formData = new FormData();
        formData.append('file', this.elem$[0].files[0]);

        $.ajax({
                   url: api_root+'/provider/bibtex/memberitems',
                   type: "POST",
                   processData: false,
                   contentType: false,
                   timeout: 5*1000,  // 5 seconds
                   data: formData,
                   dataType: "json",
                   success:  function(data){
                       entries = {
                           biblio: data,
                           total: data.length,
                           aliases: []
                       }
                       console.log("got some items back:", data)
                       that.update.call(that, entries)
                   },
                   error: function(request) {that.failure.call(that, request)}
               });

    },
    start:function() {
        changeControlGroupState(this.elem$, "working")
    },
    update: function(entries, errors){
        errors = errors || 0
        var that = this

        // end conditions
        if (!entries.biblio.length) return this.done(entries)
        if (errors > 3) return this.failure()

        for (k in entries.biblio){
            entries.aliases[k] = ["biblio", entries.biblio[k]]
        }

        that.updateProgressbar.call(
                            that,
                            entries.total,
                            entries.biblio.length
                        )
        this.done(entries)
    },
    done: function(entries){
        console.log("we're done!")
        changeControlGroupState(this.elem$, "success")
        this.aliases.add(entries.aliases)
        this.elem$
            .parents(".control-group")
            .find("span.success span.value")
            .html(this.aliases.numAddedLast)
    },
    failure: function() {
        changeControlGroupState(this.elem$, "failure")
    },
    updateProgressbar: function(total, remaining) {
        var done = total - remaining
        percentDone = Math.round(done / total * 100)
        this.elem$
            .parents(".control-group")
            .find("span.working span.value")
            .html(percentDone)
    }
}
<|endoftext|>


<commit_before>var ajaxLoadImg = "";

/*
* Manage list of aliases we can use to create and update collections.
*
*/
var AliasList = function(){}
AliasList.prototype = {
    aliases : [],
    importers: [],
    init: function() {
        var thisObj = this

        $("form.importers textarea").each(function(){
            var importer = new TextareaAliasImporter(this, thisObj.aliases)
            importer.init()
            thisObj.importers.push(importer)
        })
    }
}

/*
 * Base class for importing aliases from external providers
 * We'll subclass this for different kinds of member_items providers
 *
 */
var AliasImporter = function(inputElem, aliasList) {
    this.inputElem = inputElem
    this.aliasList = aliasList
}
AliasImporter.prototype = {
    init: function(){
        thisObj = this
        console.log(this.inputElem)

        $(this.inputElem).focus(function(){
            thisObj.focusHandler(this)
        })
        $(this.inputElem).blur(function(){
            thisObj.blurHandler(this)
        })
    },
    focusHandler: function(elem){}, // override this in subclasses
    blurHandler: function(elem) {}  // override this in subclasses
}

/*
 * Subclasses of AliasImporter; each imports from a different kind of source
 *
 */

// Import aliases that have been directly entered in textareas:
var TextareaAliasImporter = function(inputElem, aliasList) {
    AliasImporter.call(this, inputElem, aliasList) // call parent constructor
}
TextareaAliasImporter.prototype = Object.create(AliasImporter.prototype)
TextareaAliasImporter.prototype.focusHandler = function(elem) {
        console.log("focus, daniel-san!")
}
TextareaAliasImporter.prototype.blurHandler = function(elem) {
        console.log("blur, daniel-san!")
}

exampleStrings = {
    paste_input:"10.1038/171737a0\n13054692",
    paste_webpages: "http://www.example.com\nhttp://www.zombo.com",
    crossref_input: "Watson : A Structure for Deoxyribose Nucleic Acid",
    name: "My Collection"
}

inputExamplesIClickHandler = function(thisInput) {

}

addCollectionIds = function(idsArr, updateInfoLoc$, itemsAddedMsg$, showZeros) {
    if (itemsAddedMsg$ === undefined) {
        var itemsAddedMsg$ = $("items added")
    }

    var startingCollectionLength = collectionAliases.length
    var newIds = flatten(idsArr);

    // make an object with the unique key values
    var uniqueNamespaceIdPairs = {}
    for  (var i=0; i<collectionAliases.length; i++){
        var namespaceIdPair = collectionAliases[i].join(":")
        uniqueNamespaceIdPairs[namespaceIdPair] = 1
    }
    console.log(uniqueNamespaceIdPairs)

    for (var i=0; i < newIds.length; i++){
        var newNamespaceIdPair = newIds[i].join(":")
        if (!uniqueNamespaceIdPairs[newNamespaceIdPair]) {
            collectionAliases.push(newIds[i])
        }
    }
    $("div.progressbar").empty()
    $("span.loading").remove()

    // how many items are in the new collection now?
    var endingCollectionLength = collectionAliases.length;
    numIdsAdded = endingCollectionLength - startingCollectionLength;
    $("#artcounter span.count").html(endingCollectionLength);
    if (numIdsAdded || showZeros) {
        updateInfoLoc$.siblings("span.added").remove()
        $(""+numIdsAdded+"")
            .append(itemsAddedMsg$)
            .insertAfter(updateInfoLoc$)

        updateInfoLoc$.siblings("span.added")
            .find("span.count")
            .css({color: "#ff4e00"})
            .animate({color: "#555555"}, 1500)

    }
    return true;

}

// puts the textarea-entered ids in a format that addcollectionIds likes
parseTextareaArtifacts = function(str) {
    var ids = str.split("\n");
    var ret = [];
    for (i=0; i<ids.length; i++){
        var artifact = [];
        var thisId = ids[i];
        if (thisId.indexOf(":") > 0) {
            artifact[0] = thisId.split(':')[0]; // namespace
            artifact[1] = thisId.substr(artifact[0].length + 1) // id

            // handle urls:
            if (artifact[0] == "http"){
                artifact[0] = "url";
                artifact[1] = thisId
            }
        }
        else {
            if (thisId.length > 0) {
                var isnum_with_possible_period = /^[\d\.]+$/.test(thisId)
                // handle dois entered without the doi prefix
                if (thisId.substring(0,3) == "10.") {
                    artifact[0] = "doi"
                } else if (isnum_with_possible_period && (thisId.length > 5) && (thisId.length <= 8)) {
                    // definition of pmid from http://www.nlm.nih.gov/bsd/mms/medlineelements.html#pmid
                    // this doesn't catch short PMIDs, but that's ok
                    artifact[0] = "pmid"
                }
                else {
                    artifact[0] = "unknown"
                }
                artifact[1] = thisId
            }
        }
        if (typeof artifact[1] != "undefined") {
            ret.push(artifact);
        }
    }
    return ret;
}

progressbar = function(total, done, loc$) {
    percentDone = Math.round(done / total * 100)
    loc$.html(percentDone + "% done...")
}
bibtexUploadDone = function(numItemsTotal, aliases) {
    var numFailedItems = numItemsTotal - aliases.length
    var msg$ = $(ich.bibtexUploadDoneMsg({numFailedItems: numFailedItems}))
    msg$.find("a.help-text")
        .clickover()
    addCollectionIds(aliases, $("div.fileupload"), msg$, true)
}

update_bibtex_progress = function(query_hash) {
    $.ajax({
               url: "http://"+api_root+"/provider/bibtex/memberitems/"+query_hash+"?method=async",
               type: "GET",
               dataType: "json",
               success: function(response,status,xhr){
                   console.log("searched using query_hash " + query_hash)
                   console.log(response)
                   if (response.pages == response.complete) {
                       aliases = []
                       for (i=0; i<response.memberitems.length; i++) {
                           var aliases = aliases.concat(response.memberitems[i])
                       }
                       bibtexUploadDone(response.number_entries, aliases)
                   }
                   else {
                       progressbar(response.pages, response.complete, $("#bibtex_toggler_contents div.progressbar"))
                       setTimeout(function () {
                           update_bibtex_progress(query_hash)
                       }, 500)
                   }
               },
               error: function(XMLHttpRequest, textStatus, errorThrown) {
                   $("span.loading").remove()
                   $("div.fileupload span.added").remove()
                   $("div.fileupload").append("sorry, there was an error.")
               }
           });  }

upload_bibtex = function(files) {
    var fileInput = $("li #input_bibtex")[0];
    var file = fileInput.files[0];
    var formData = new FormData();
    formData.append('file', file);
    $("span.btn-file").remove()
    $(""+ajaxLoadImg+"").insertBefore("div.fileupload div.progressbar");

    console.log("starting ajax request now.")

    progressbar(1, 0, $("#bibtex_toggler_contents div.progressbar"))
    $.ajax({
               url: "http://"+api_root+'/provider/bibtex/memberitems',
               type: "POST",
               processData: false,
               contentType: false,
               timeout: 120*1000,  // 120 seconds, because bibtex is very slow
               data: formData,
               dataType: "json",
               success:  function(response,status,xhr){
                   query_hash = response.query_hash
                   console.log("started update request; got this query_hash back: " + query_hash)
                   update_bibtex_progress(query_hash)
               },
               error: function(XMLHttpRequest, textStatus, errorThrown) {
                   $("span.loading").remove()
                   $("div.fileupload span.added").remove()
                   $("div.fileupload").append("sorry, there was an error.")
               }
           });
}

createCollectionInit = function(){

    $("#google-scholar-help-link").click(function(){
        $("#google-scholar-help").modal("show")
        return false
    })
    $("#orcid-help-link").click(function(){
        $("#orcid-help").modal("show")
        return false
    })
    $("#bibtex-fail-help a").click(function(){
        $(".modal").modal("hide")
        if ($(this).hasClass("uservoice")) {
            UserVoice.showPopupWidget()
        }
    })

    $("li textarea, input#name").each(function(){
        $(this).val(exampleStrings[this.id])
    })
    $("div.toggler_contents input, ul#manual-add textarea, input#name")
        .focus(function(){
                   currentUserInputValue = $(this).val();
                   $(this).removeClass("no-input-yet")

                   // hid the example strings if they're still up.
                   if (currentUserInputValue == exampleStrings[this.id]) {
                       $(this).val("")
                   }
               })
        .blur(function(){
                  $this = $(this)
                  if ($this.val() == "") {
                      $this.addClass("no-input-yet")
                      $this.val(exampleStrings[this.id])
                      return false;
                  }
                  else if ($this.val() == currentUserInputValue) {
                      return false;
                  }

                  if ($this.hasClass("artifactList")) {
                      newIds = parseTextareaArtifacts($(this).val());
                      // limit to adding first 250 lines
                      newIds = newIds.slice(0, 100)
                      addCollectionIds(newIds, $(this))
                  }
                  else if ($this.attr("id") == "name") {
                      // do nothing, it's just an entry field. hack, ick.
                  }
                  else {
                      var idStrParts = $(this).attr("id").split('_');
                      var providerName = idStrParts[0];

                      if (providerName == "crossref") { // hack, should generalize for all textareas
                          var providerTypeQuery = "&type=import"
                          var pipeVal = $this.val().replace(":", "|");
                          var providerIdQuery = escape(pipeVal);
                      } else {
                          var providerIdQuery = escape($this.val());
                      }
                      $(this).siblings("span.added").remove()
                      $(this).not("input#name").after(""+ajaxLoadImg+"");
                      console.log("running memberitems")
                      $.ajax({
                                 url: "http://"+api_root+"/provider/"+providerName+"/memberitems/"+providerIdQuery+"?method=sync",
                                 type: "GET",
                                 dataType: "json",
                                 success: function(response,status,xhr){
                                     addCollectionIds(response.memberitems, $this)
                                 },
                                 error: function(XMLHttpRequest, textStatus, errorThrown) {
                                     $("span.loading").remove()
                                     $this.siblings("span.added").remove()
                                     var explainString;
                                     if (XMLHttpRequest.status == 404) {
                                         explainString = "sorry, not found."
                                     } else {
                                         explainString = "sorry, there was an error."
                                     }
                                     $this.after("" + explainString + "")
                                 }
                             });
                  }
              })

    // creating a collection by submitting the object IDs from the homepage
    $("#id-form").submit(function(){

        // make sure the user input something at all
        if (collectionAliases.length == 0) {
            alert("Looks like you haven't added any research objects to the collection yet.")
            return false;

            // create a collection with these aliases
        } else {
            console.log("adding collection with new items.")

            $("#go-button").replaceWith(""+ajaxLoadImg+"")

            var requestObj = {
                title: $('#name').val(),
                aliases: collectionAliases
            }

            $.ajax({
                       url: "http://"+api_root+'/collection',
                       type: "POST",
                       dataType: "json",
                       contentType: "application/json; charset=utf-8",
                       data:  JSON.stringify(requestObj),
                       success: function(ret){
                           returnedCollection=ret.collection

                           // add the id of the newly-created coll to the user's coll list
                           user.addColl(returnedCollection._id, ret.key)

                           var email = $("#inline-register-email").val()
                           var pw = $("#inline-register-pw").val()
                           if (email && pw){
                               user.setCreds(email, pw)
                           }

                           var success = function(){
                               _gaq.push(['_trackPageview', '/user/created']);
                               location.href = "/collection/" +returnedCollection._id
                           }

                           if (user.hasCreds()){
                               user.syncWithServer("push", {on200: success})
                           }
                           else {
                               success()
                           }
                       }
                   });
            return false;
        }
    });
}<commit_msg>save point: blur handler kind of does things.<commit_after>var ajaxLoadImg = "";

/*
* Manage list of aliases we can use to create and update collections.
*
*/
var AliasList = function(){}
AliasList.prototype = {
    aliases : [],
    importers: [],
    init: function() {
        var that = this

        $("form.importers textarea").each(function(){
            var importer = new TextareaAliasImporter()
            importer.init(this, that.aliases)
        })

        $("h3").click(function(){
            console.log("aliases:", that.aliases)
        })
    }
}

/*
 * Base class for importing aliases from external providers
 * We'll subclass this for different kinds of member_items providers
 *
 */
var AliasImporter = function() {}
AliasImporter.prototype = {
    doneImporting: function(elem, aliases, newAliases) {
        var numNewAliases = this.updateAliases(aliases, newAliases)
        $(elem).css("background", "red")
        console.log("done importing; got " + numNewAliases + " new aliases.")
    },
    updateAliases: function(aliases, newAliases){
        return 2
    }
}

/*
 * Subclasses of AliasImporter; each imports from a different kind of source
 *
 */

// Import aliases that have been directly entered in textareas:
var TextareaAliasImporter = function() {}
TextareaAliasImporter.prototype = _.extend(
    Object.create(AliasImporter.prototype),
    {
        init: function(elem, aliases) {
            that = this
            $(elem).focus(function(){})
            $(elem).blur(function(){
                console.log("blur", this.id, aliases)
                that.doneImporting(this, aliases, ["foo"])
            })
        }
    }
)

exampleStrings = {
    paste_input:"10.1038/171737a0\n13054692",
    paste_webpages: "http://www.example.com\nhttp://www.zombo.com",
    crossref_input: "Watson : A Structure for Deoxyribose Nucleic Acid",
    name: "My Collection"
}

inputExamplesIClickHandler = function(thisInput) {

}

addCollectionIds = function(idsArr, updateInfoLoc$, itemsAddedMsg$, showZeros) {
    if (itemsAddedMsg$ === undefined) {
        var itemsAddedMsg$ = $("items added")
    }

    var startingCollectionLength = collectionAliases.length
    var newIds = flatten(idsArr);

    // make an object with the unique key values
    var uniqueNamespaceIdPairs = {}
    for  (var i=0; i<collectionAliases.length; i++){
        var namespaceIdPair = collectionAliases[i].join(":")
        uniqueNamespaceIdPairs[namespaceIdPair] = 1
    }
    console.log(uniqueNamespaceIdPairs)

    for (var i=0; i < newIds.length; i++){
        var newNamespaceIdPair = newIds[i].join(":")
        if (!uniqueNamespaceIdPairs[newNamespaceIdPair]) {
            collectionAliases.push(newIds[i])
        }
    }
    $("div.progressbar").empty()
    $("span.loading").remove()

    // how many items are in the new collection now?
    var endingCollectionLength = collectionAliases.length;
    numIdsAdded = endingCollectionLength - startingCollectionLength;
    $("#artcounter span.count").html(endingCollectionLength);
    if (numIdsAdded || showZeros) {
        updateInfoLoc$.siblings("span.added").remove()
        $(""+numIdsAdded+"")
            .append(itemsAddedMsg$)
            .insertAfter(updateInfoLoc$)

        updateInfoLoc$.siblings("span.added")
            .find("span.count")
            .css({color: "#ff4e00"})
            .animate({color: "#555555"}, 1500)

    }
    return true;

}

// puts the textarea-entered ids in a format that addcollectionIds likes
parseTextareaArtifacts = function(str) {
    var ids = str.split("\n");
    var ret = [];
    for (i=0; i<ids.length; i++){
        var artifact = [];
        var thisId = ids[i];
        if (thisId.indexOf(":") > 0) {
            artifact[0] = thisId.split(':')[0]; // namespace
            artifact[1] = thisId.substr(artifact[0].length + 1) // id

            // handle urls:
            if (artifact[0] == "http"){
                artifact[0] = "url";
                artifact[1] = thisId
            }
        }
        else {
            if (thisId.length > 0) {
                var isnum_with_possible_period = /^[\d\.]+$/.test(thisId)
                // handle dois entered without the doi prefix
                if (thisId.substring(0,3) == "10.") {
                    artifact[0] = "doi"
                } else if (isnum_with_possible_period && (thisId.length > 5) && (thisId.length <= 8)) {
                    // definition of pmid from http://www.nlm.nih.gov/bsd/mms/medlineelements.html#pmid
                    // this doesn't catch short PMIDs, but that's ok
                    artifact[0] = "pmid"
                }
                else {
                    artifact[0] = "unknown"
                }
                artifact[1] = thisId
            }
        }
        if (typeof artifact[1] != "undefined") {
            ret.push(artifact);
        }
    }
    return ret;
}

progressbar = function(total, done, loc$) {
    percentDone = Math.round(done / total * 100)
    loc$.html(percentDone + "% done...")
}
bibtexUploadDone = function(numItemsTotal, aliases) {
    var numFailedItems = numItemsTotal - aliases.length
    var msg$ = $(ich.bibtexUploadDoneMsg({numFailedItems: numFailedItems}))
    msg$.find("a.help-text")
        .clickover()
    addCollectionIds(aliases, $("div.fileupload"), msg$, true)
}

update_bibtex_progress = function(query_hash) {
    $.ajax({
               url: "http://"+api_root+"/provider/bibtex/memberitems/"+query_hash+"?method=async",
               type: "GET",
               dataType: "json",
               success: function(response,status,xhr){
                   console.log("searched using query_hash " + query_hash)
                   console.log(response)
                   if (response.pages == response.complete) {
                       aliases = []
                       for (i=0; i<response.memberitems.length; i++) {
                           var aliases = aliases.concat(response.memberitems[i])
                       }
                       bibtexUploadDone(response.number_entries, aliases)
                   }
                   else {
                       progressbar(response.pages, response.complete, $("#bibtex_toggler_contents div.progressbar"))
                       setTimeout(function () {
                           update_bibtex_progress(query_hash)
                       }, 500)
                   }
               },
               error: function(XMLHttpRequest, textStatus, errorThrown) {
                   $("span.loading").remove()
                   $("div.fileupload span.added").remove()
                   $("div.fileupload").append("sorry, there was an error.")
               }
           });  }

upload_bibtex = function(files) {
    var fileInput = $("li #input_bibtex")[0];
    var file = fileInput.files[0];
    var formData = new FormData();
    formData.append('file', file);
    $("span.btn-file").remove()
    $(""+ajaxLoadImg+"").insertBefore("div.fileupload div.progressbar");

    console.log("starting ajax request now.")

    progressbar(1, 0, $("#bibtex_toggler_contents div.progressbar"))
    $.ajax({
               url: "http://"+api_root+'/provider/bibtex/memberitems',
               type: "POST",
               processData: false,
               contentType: false,
               timeout: 120*1000,  // 120 seconds, because bibtex is very slow
               data: formData,
               dataType: "json",
               success:  function(response,status,xhr){
                   query_hash = response.query_hash
                   console.log("started update request; got this query_hash back: " + query_hash)
                   update_bibtex_progress(query_hash)
               },
               error: function(XMLHttpRequest, textStatus, errorThrown) {
                   $("span.loading").remove()
                   $("div.fileupload span.added").remove()
                   $("div.fileupload").append("sorry, there was an error.")
               }
           });
}

createCollectionInit = function(){

    $("#google-scholar-help-link").click(function(){
        $("#google-scholar-help").modal("show")
        return false
    })
    $("#orcid-help-link").click(function(){
        $("#orcid-help").modal("show")
        return false
    })
    $("#bibtex-fail-help a").click(function(){
        $(".modal").modal("hide")
        if ($(this).hasClass("uservoice")) {
            UserVoice.showPopupWidget()
        }
    })

    $("li textarea, input#name").each(function(){
        $(this).val(exampleStrings[this.id])
    })
    $("div.toggler_contents input, ul#manual-add textarea, input#name")
        .focus(function(){
                   currentUserInputValue = $(this).val();
                   $(this).removeClass("no-input-yet")

                   // hid the example strings if they're still up.
                   if (currentUserInputValue == exampleStrings[this.id]) {
                       $(this).val("")
                   }
               })
        .blur(function(){
                  $this = $(this)
                  if ($this.val() == "") {
                      $this.addClass("no-input-yet")
                      $this.val(exampleStrings[this.id])
                      return false;
                  }
                  else if ($this.val() == currentUserInputValue) {
                      return false;
                  }

                  if ($this.hasClass("artifactList")) {
                      newIds = parseTextareaArtifacts($(this).val());
                      // limit to adding first 250 lines
                      newIds = newIds.slice(0, 100)
                      addCollectionIds(newIds, $(this))
                  }
                  else if ($this.attr("id") == "name") {
                      // do nothing, it's just an entry field. hack, ick.
                  }
                  else {
                      var idStrParts = $(this).attr("id").split('_');
                      var providerName = idStrParts[0];

                      if (providerName == "crossref") { // hack, should generalize for all textareas
                          var providerTypeQuery = "&type=import"
                          var pipeVal = $this.val().replace(":", "|");
                          var providerIdQuery = escape(pipeVal);
                      } else {
                          var providerIdQuery = escape($this.val());
                      }
                      $(this).siblings("span.added").remove()
                      $(this).not("input#name").after(""+ajaxLoadImg+"");
                      console.log("running memberitems")
                      $.ajax({
                                 url: "http://"+api_root+"/provider/"+providerName+"/memberitems/"+providerIdQuery+"?method=sync",
                                 type: "GET",
                                 dataType: "json",
                                 success: function(response,status,xhr){
                                     addCollectionIds(response.memberitems, $this)
                                 },
                                 error: function(XMLHttpRequest, textStatus, errorThrown) {
                                     $("span.loading").remove()
                                     $this.siblings("span.added").remove()
                                     var explainString;
                                     if (XMLHttpRequest.status == 404) {
                                         explainString = "sorry, not found."
                                     } else {
                                         explainString = "sorry, there was an error."
                                     }
                                     $this.after("" + explainString + "")
                                 }
                             });
                  }
              })

    // creating a collection by submitting the object IDs from the homepage
    $("#id-form").submit(function(){

        // make sure the user input something at all
        if (collectionAliases.length == 0) {
            alert("Looks like you haven't added any research objects to the collection yet.")
            return false;

            // create a collection with these aliases
        } else {
            console.log("adding collection with new items.")

            $("#go-button").replaceWith(""+ajaxLoadImg+"")

            var requestObj = {
                title: $('#name').val(),
                aliases: collectionAliases
            }

            $.ajax({
                       url: "http://"+api_root+'/collection',
                       type: "POST",
                       dataType: "json",
                       contentType: "application/json; charset=utf-8",
                       data:  JSON.stringify(requestObj),
                       success: function(ret){
                           returnedCollection=ret.collection

                           // add the id of the newly-created coll to the user's coll list
                           user.addColl(returnedCollection._id, ret.key)

                           var email = $("#inline-register-email").val()
                           var pw = $("#inline-register-pw").val()
                           if (email && pw){
                               user.setCreds(email, pw)
                           }

                           var success = function(){
                               _gaq.push(['_trackPageview', '/user/created']);
                               location.href = "/collection/" +returnedCollection._id
                           }

                           if (user.hasCreds()){
                               user.syncWithServer("push", {on200: success})
                           }
                           else {
                               success()
                           }
                       }
                   });
            return false;
        }
    });
}<|endoftext|>


<commit_before>
var AliasList = function(){}
AliasList.prototype = {
    aliasesArr : [],
    numAddedLast: 0,
    add: function(aliases) {
        var oldLen = this.aliasesArr.length
        this.aliasesArr = _.union(aliases, this.aliasesArr)
        this.numAddedLast = this.aliasesArr.length - oldLen
        this.onChange()
        return this.numAddedLast
    },
    count: function() {
        return this.aliasesArr.length
    },
    forApi: function() {
        return this.aliasesArr
    },
    clear: function() {
        this.aliasesArr = []
        this.onChange()
        return true
    },
    onChange: function() {
        $("p#artcounter span").html(this.count())
    }
}

var ExternalProfileIds = {
    github: null,
    slideshare: null,
    orcid: null
}

var AliasListInputs = function(user) {
    this.user = user
    this.init()
}
AliasListInputs.prototype = {
    aliases: new AliasList(),
    email: "",
    emailIsValid: false,
    ExternalProfileIds:  ExternalProfileIds, // someday this'll probably be an obj
    init: function() {
        var that = this

        this.textareaPlaceholders()
        this.initHelpModals()

        // import orcid, github, and slideshare from usernames
        $(".control-group.username input")
            .each(function(){
                $(this).blur(function(){
                    if (!$(this).val()) return false
                    var importer = new UsernameImporter(
                        that.aliases,
                        that.ExternalProfileIds,
                        this
                    )
                    importer.pull()
            })
        })

        // import from bibtex
        $("input#input_bibtex").change(function(){
            var importer = new BibtexImporter(that.aliases, this)
            importer.pull()
        })

        // set up the submit button
        $("#go-button").click(function(){
            var action = "update"

            // fetch ids from the textareas first
            $("textarea.ids").not(".default").each(function(){
                var importer = new TextareaImporter(that.aliases, this)
                importer.pull()
            })
            var button = new SubmitButton(that.aliases, that.ExternalProfileIds, this)

            if ($(this).hasClass(("update"))) {
                console.log("update!")
                return button.update(coll)
            }
            else if ($(this).hasClass(("create"))) {
                console.log("create!")
                return button.make()
            }

        })

        // clear the aliases when input modals are dismissed
        $("#import-products-modal").on("hide", function(){
            that.resetList.call(that)
        })

        // you can't submit the form until the required stuff all has a value.
        $("form.register").keyup( function(){
            that.validateRegistrationForm.call(that, this)
        })

        $("form.register input.email").blur(function(){
            that.validateEmail.call(that, this)
        })

    },
    validateEmail: function(input) {

        console.log("here's what's in the email box: ", $(input).val())

//        if (this.email == $(input).val()) return true // no change
        if (!$(input).val()) {
            changeElemState($(input), "ready")
            return true
        }

        var that = this
        that.email = $(input).val()
        changeElemState($(input), "working")
        $("#go-button").attr("disabled", "true")

        this.user.checkUsername(
            that.email,
            function(){
                changeElemState($(input), "success")
                that.emailIsValid = true
                that.validateRegistrationForm()
            },
            function(){
                changeElemState($(input), "error")
                that.emailIsValid = false
                that.validateRegistrationForm()
            }
        )
    },
    validateRegistrationForm: function() {
        var valid = true

        // email
        email$ = $("input.register.email")
        console.log("email is valid: ", this.emailIsValid)

        if (this.email != email$.val()) {
            valid = false
            changeElemState(email$, "ready")
        }
        if (!this.emailIsValid) {
            valid = false
        }

        // password
        var pw$ = $("input.password")
        if (pw$.val()) {
            changeElemState(pw$,  "success" )
        }
        else {
            valid = false
            changeElemState(pw$, "ready" )
        }

        // names
        given$ = $("input.name.given")
        surname$ = $("input.name.surname")
        if (given$.val() && surname$.val()){
            changeElemState(given$, "success")
        }
        else {
            valid = false
            changeElemState(given$, "ready")
        }

        if (valid) { // there's still a missing val
            $("#go-button").removeAttr("disabled")
        }
        else {
            $("#go-button").attr("disabled", "disabled")
        }
    },
    textareaPlaceholders: function() {
        // placeholder replacement
        $("textarea").each(function(){
            var this$ = $(this)
            var placeholderText = this$.attr("data-placeholder")
            this$.val(placeholderText).addClass("default")
            this$.blur(function(){
                if (!this$.val()) {
                    this$.val(placeholderText).addClass("default")
                    return false
                }
            })
            this$.focus(function(){
                if (this$.val() == placeholderText){
                    this$.val("").removeClass("default")
                }
            })
        })
    },
    initHelpModals: function(){

        $("#google-scholar-help-link").click(function(){
            $("#google-scholar-help").modal("show")
            return false
        })
        $("#orcid-help-link").click(function(){
            $("#orcid-help").modal("show")
            return false
        })
        $("#bibtex-fail-help a").click(function(){
            $(".modal").modal("hide")
            if ($(this).hasClass("uservoice")) {
                UserVoice.showPopupWidget()
            }
        })
    },
    resetList: function() {
        console.log("REEEEEEEEEEE SEEEETTTT!")
        this.aliases.clear()
        $(".import-products .control-group").each(function(){
            changeElemState(this, "ready")
        })
        $(".import-products input").val("")
        $(".import-products textarea").val("")
        this.textareaPlaceholders()
    }
}

var SubmitButton = function(aliases, ExternalProfileIds,  elem){
    this.aliases = aliases
    this.ExternalProfileIds = ExternalProfileIds
    this.elem$ = $(elem)
}
SubmitButton.prototype = {

    make: function() {
        if (!this.start()) return false

        var givenName = $("div.inline-register input.given").val() || "Anonymous"
        var surname = $("div.inline-register input.surname").val() || "User"

        var requestObj = {
            alias_tiids: this.aliases.forApi(),
            external_profile_ids: this.ExternalProfileIds,
            email: $("div.inline-register input.email").val(),
            password: $("div.inline-register input.password").val(),
            given_name: givenName,
            surname: surname
        }

        $.ajax({
           url: webapp_root+'/user',
           type: "POST",
           dataType: "json",
           contentType: "application/json; charset=utf-8",
           data:  JSON.stringify(requestObj),
           success: function(data){
               console.log("finished creating the user!")
               mixpanel.people.set({"$created": new Date()})

               location.href = "/" + data.url_slug
           }
        })
        return false
    },
    update: function(coll){
        if (!this.start()) return false
        this.addItemsToCollection(coll, this.aliases.forApi())
        return false
    },
    start:function(){
        if (!this.aliases.forApi().length) {
            alert("You haven't added any products.")
            return false
        }
        else if ($("div.inline-register .email").hasClass("error")) {
            alert("please enter an email that's not already in use.")
            return false
        }
        else {
            changeElemState(this.elem$, "working")
            console.log(this.elem$)
            return true
        }
    },
    failure: function() {
    },
    addItemsToCollection: function(coll, aliases) {
        var callbacks = {
            onSuccess: function(){location.reload()}
        }
        coll.addItems(aliases, callbacks)

    }
}

// Import aliases from external services that want a username
var UsernameImporter = function(aliases, ExternalProfileIds, elem) {
    this.aliases = aliases
    this.ExternalProfileIds = ExternalProfileIds
    this.elem$ = $(elem)
}
UsernameImporter.prototype = {

    pull: function() {
        var that = this
        this.start()
        var providerName = this.elem$.attr("id").replace("input_", "")
        var queryStr = this.elem$.val()

        $.ajax({
            url: api_root+"/provider/"+providerName+"/memberitems/"+queryStr+"?method=sync",
            type: "GET",
            dataType: "json",
            success: function(data){that.done.call(that, data, providerName, queryStr)},
            error: function(request){that.failure.call(that, request)}
        });

    },
    start:function() {
        changeElemState(this.elem$, "working")
    },
    update: function(){},
    done: function(data, providerName, queryStr){
        changeElemState(this.elem$, "success")
        this.ExternalProfileIds[providerName] = queryStr

        this.aliases.add(data.memberitems)
        this.elem$
            .parents(".control-group")
            .find("span.success span.value")
            .html(this.aliases.numAddedLast)
    },
    failure: function(request) {
        changeElemState(this.elem$, "error")
    }
}

// Import aliases from external services that want a username
var TextareaImporter = function(aliases, elem) {
    this.aliases = aliases
    this.elem$ = $(elem)
}
TextareaImporter.prototype = {
    pull: function(){
        var newAliases = this.parseTextareaArtifacts(this.elem$.val())
        this.aliases.add(newAliases)
    },
    parseTextareaArtifacts: function(str) {
        var ids = str.split("\n");
        var ret = [];
        for (i=0; i<ids.length; i++){
            var artifact = [];
            var thisId = ids[i];
            if (thisId.indexOf(":") > 0) {
                artifact[0] = thisId.split(':')[0]; // namespace
                artifact[1] = thisId.substr(artifact[0].length + 1) // id

                // handle urls:
                if (artifact[0] == "http" || artifact[0] == "https"){
                    artifact[0] = "url";
                    artifact[1] = thisId
                }
            }
            else {
                if (thisId.length > 0) {
                    var isnum_with_possible_period = /^[\d\.]+$/.test(thisId)
                    // handle dois entered without the doi prefix
                    if (thisId.substring(0,3) == "10.") {
                        artifact[0] = "doi"
                    } else if (isnum_with_possible_period && (thisId.length > 5) && (thisId.length <= 8)) {
                        // definition of pmid from http://www.nlm.nih.gov/bsd/mms/medlineelements.html#pmid
                        // this doesn't catch short PMIDs, but that's ok
                        artifact[0] = "pmid"
                    }
                    else {
                        artifact[0] = "unknown"
                    }
                    artifact[1] = thisId
                }
            }
            if (typeof artifact[1] != "undefined") {
                ret.push(artifact);
            }
        }
        return ret;
    },
    start:function(){},
    update:function(){},
    done:function(){},
    failure:function(){}

}

// upload bibtex from google scholar
var BibtexImporter = function(aliases, elem) {
    this.aliases = aliases
    this.elem$ = $(elem)
    this.bibtexEntriesParsedFromFile = []
}
BibtexImporter.prototype = {

    pull: function() {
        var that = this
        this.start()
        var providerName = this.elem$.attr("id").replace("input_", "")

        var formData = new FormData();
        formData.append('file', this.elem$[0].files[0]);

        $.ajax({
                   url: api_root+'/provider/bibtex/memberitems',
                   type: "POST",
                   processData: false,
                   contentType: false,
                   timeout: 5*1000,  // 5 seconds
                   data: formData,
                   dataType: "json",
                   success:  function(data){
                       entries = {
                           biblio: data,
                           total: data.length,
                           aliases: []
                       }
                       console.log("got some items back:", data)
                       that.update.call(that, entries)
                   },
                   error: function(request) {that.failure.call(that, request)}
               });

    },
    start:function() {
        changeElemState(this.elem$, "working")
    },
    update: function(entries, errors){
        errors = errors || 0
        var that = this

        // end conditions
        if (!entries.biblio.length) return this.done(entries)
        if (errors > 3) return this.failure()

        for (k in entries.biblio){
            entries.aliases[k] = ["biblio", entries.biblio[k]]
        }

        that.updateProgressbar.call(
                            that,
                            entries.total,
                            entries.biblio.length
                        )
        this.done(entries)
    },
    done: function(entries){
        console.log("we're done!")
        changeElemState(this.elem$, "success")
        this.aliases.add(entries.aliases)
        this.elem$
            .parents(".control-group")
            .find("span.success span.value")
            .html(this.aliases.numAddedLast)
    },
    failure: function() {
        changeElemState(this.elem$, "error")
    },
    updateProgressbar: function(total, remaining) {
        var done = total - remaining
        percentDone = Math.round(done / total * 100)
        this.elem$
            .parents(".control-group")
            .find("span.working span.value")
            .html(percentDone)
    }
}
<commit_msg>Require at least 4-digit pw.<commit_after>
var AliasList = function(){}
AliasList.prototype = {
    aliasesArr : [],
    numAddedLast: 0,
    add: function(aliases) {
        var oldLen = this.aliasesArr.length
        this.aliasesArr = _.union(aliases, this.aliasesArr)
        this.numAddedLast = this.aliasesArr.length - oldLen
        this.onChange()
        return this.numAddedLast
    },
    count: function() {
        return this.aliasesArr.length
    },
    forApi: function() {
        return this.aliasesArr
    },
    clear: function() {
        this.aliasesArr = []
        this.onChange()
        return true
    },
    onChange: function() {
        $("p#artcounter span").html(this.count())
    }
}

var ExternalProfileIds = {
    github: null,
    slideshare: null,
    orcid: null
}

var AliasListInputs = function(user) {
    this.user = user
    this.init()
}
AliasListInputs.prototype = {
    aliases: new AliasList(),
    email: "",
    emailIsValid: false,
    ExternalProfileIds:  ExternalProfileIds, // someday this'll probably be an obj
    init: function() {
        var that = this

        this.textareaPlaceholders()
        this.initHelpModals()

        // import orcid, github, and slideshare from usernames
        $(".control-group.username input")
            .each(function(){
                $(this).blur(function(){
                    if (!$(this).val()) return false
                    var importer = new UsernameImporter(
                        that.aliases,
                        that.ExternalProfileIds,
                        this
                    )
                    importer.pull()
            })
        })

        // import from bibtex
        $("input#input_bibtex").change(function(){
            var importer = new BibtexImporter(that.aliases, this)
            importer.pull()
        })

        // set up the submit button
        $("#go-button").click(function(){
            var action = "update"

            // fetch ids from the textareas first
            $("textarea.ids").not(".default").each(function(){
                var importer = new TextareaImporter(that.aliases, this)
                importer.pull()
            })
            var button = new SubmitButton(that.aliases, that.ExternalProfileIds, this)

            if ($(this).hasClass(("update"))) {
                console.log("update!")
                return button.update(coll)
            }
            else if ($(this).hasClass(("create"))) {
                console.log("create!")
                return button.make()
            }

        })

        // clear the aliases when input modals are dismissed
        $("#import-products-modal").on("hide", function(){
            that.resetList.call(that)
        })

        // you can't submit the form until the required stuff all has a value.
        $("form.register").keyup( function(){
            that.validateRegistrationForm.call(that, this)
        })

        $("form.register input.email").blur(function(){
            that.validateEmail.call(that, this)
        })

    },
    validateEmail: function(input) {

        console.log("here's what's in the email box: ", $(input).val())

//        if (this.email == $(input).val()) return true // no change
        if (!$(input).val()) {
            changeElemState($(input), "ready")
            return true
        }

        var that = this
        that.email = $(input).val()
        changeElemState($(input), "working")
        $("#go-button").attr("disabled", "true")

        this.user.checkUsername(
            that.email,
            function(){
                changeElemState($(input), "success")
                that.emailIsValid = true
                that.validateRegistrationForm()
            },
            function(){
                changeElemState($(input), "error")
                that.emailIsValid = false
                that.validateRegistrationForm()
            }
        )
    },
    validateRegistrationForm: function() {
        var valid = true

        // email
        email$ = $("input.register.email")
        console.log("email is valid: ", this.emailIsValid)

        if (this.email != email$.val()) {
            valid = false
            changeElemState(email$, "ready")
        }
        if (!this.emailIsValid) {
            valid = false
        }

        // password
        var pw$ = $("input.password")
        if (pw$.val().length > 3) {
            changeElemState(pw$,  "success" )
        }
        else {
            valid = false
            changeElemState(pw$, "ready" )
        }

        // names
        given$ = $("input.name.given")
        surname$ = $("input.name.surname")
        if (given$.val() && surname$.val()){
            changeElemState(given$, "success")
        }
        else {
            valid = false
            changeElemState(given$, "ready")
        }

        if (valid) { // there's still a missing val
            $("#go-button").removeAttr("disabled")
        }
        else {
            $("#go-button").attr("disabled", "disabled")
        }
    },
    textareaPlaceholders: function() {
        // placeholder replacement
        $("textarea").each(function(){
            var this$ = $(this)
            var placeholderText = this$.attr("data-placeholder")
            this$.val(placeholderText).addClass("default")
            this$.blur(function(){
                if (!this$.val()) {
                    this$.val(placeholderText).addClass("default")
                    return false
                }
            })
            this$.focus(function(){
                if (this$.val() == placeholderText){
                    this$.val("").removeClass("default")
                }
            })
        })
    },
    initHelpModals: function(){

        $("#google-scholar-help-link").click(function(){
            $("#google-scholar-help").modal("show")
            return false
        })
        $("#orcid-help-link").click(function(){
            $("#orcid-help").modal("show")
            return false
        })
        $("#bibtex-fail-help a").click(function(){
            $(".modal").modal("hide")
            if ($(this).hasClass("uservoice")) {
                UserVoice.showPopupWidget()
            }
        })
    },
    resetList: function() {
        console.log("REEEEEEEEEEE SEEEETTTT!")
        this.aliases.clear()
        $(".import-products .control-group").each(function(){
            changeElemState(this, "ready")
        })
        $(".import-products input").val("")
        $(".import-products textarea").val("")
        this.textareaPlaceholders()
    }
}

var SubmitButton = function(aliases, ExternalProfileIds,  elem){
    this.aliases = aliases
    this.ExternalProfileIds = ExternalProfileIds
    this.elem$ = $(elem)
}
SubmitButton.prototype = {

    make: function() {
        if (!this.start()) return false

        var givenName = $("div.inline-register input.given").val() || "Anonymous"
        var surname = $("div.inline-register input.surname").val() || "User"

        var requestObj = {
            alias_tiids: this.aliases.forApi(),
            external_profile_ids: this.ExternalProfileIds,
            email: $("div.inline-register input.email").val(),
            password: $("div.inline-register input.password").val(),
            given_name: givenName,
            surname: surname
        }

        $.ajax({
           url: webapp_root+'/user',
           type: "POST",
           dataType: "json",
           contentType: "application/json; charset=utf-8",
           data:  JSON.stringify(requestObj),
           success: function(data){
               console.log("finished creating the user!")
               mixpanel.people.set({"$created": new Date()})

               location.href = "/" + data.url_slug
           }
        })
        return false
    },
    update: function(coll){
        if (!this.start()) return false
        this.addItemsToCollection(coll, this.aliases.forApi())
        return false
    },
    start:function(){
        if (!this.aliases.forApi().length) {
            alert("You haven't added any products.")
            return false
        }
        else if ($("div.inline-register .email").hasClass("error")) {
            alert("please enter an email that's not already in use.")
            return false
        }
        else {
            changeElemState(this.elem$, "working")
            console.log(this.elem$)
            return true
        }
    },
    failure: function() {
    },
    addItemsToCollection: function(coll, aliases) {
        var callbacks = {
            onSuccess: function(){location.reload()}
        }
        coll.addItems(aliases, callbacks)

    }
}

// Import aliases from external services that want a username
var UsernameImporter = function(aliases, ExternalProfileIds, elem) {
    this.aliases = aliases
    this.ExternalProfileIds = ExternalProfileIds
    this.elem$ = $(elem)
}
UsernameImporter.prototype = {

    pull: function() {
        var that = this
        this.start()
        var providerName = this.elem$.attr("id").replace("input_", "")
        var queryStr = this.elem$.val()

        $.ajax({
            url: api_root+"/provider/"+providerName+"/memberitems/"+queryStr+"?method=sync",
            type: "GET",
            dataType: "json",
            success: function(data){that.done.call(that, data, providerName, queryStr)},
            error: function(request){that.failure.call(that, request)}
        });

    },
    start:function() {
        changeElemState(this.elem$, "working")
    },
    update: function(){},
    done: function(data, providerName, queryStr){
        changeElemState(this.elem$, "success")
        this.ExternalProfileIds[providerName] = queryStr

        this.aliases.add(data.memberitems)
        this.elem$
            .parents(".control-group")
            .find("span.success span.value")
            .html(this.aliases.numAddedLast)
    },
    failure: function(request) {
        changeElemState(this.elem$, "error")
    }
}

// Import aliases from external services that want a username
var TextareaImporter = function(aliases, elem) {
    this.aliases = aliases
    this.elem$ = $(elem)
}
TextareaImporter.prototype = {
    pull: function(){
        var newAliases = this.parseTextareaArtifacts(this.elem$.val())
        this.aliases.add(newAliases)
    },
    parseTextareaArtifacts: function(str) {
        var ids = str.split("\n");
        var ret = [];
        for (i=0; i<ids.length; i++){
            var artifact = [];
            var thisId = ids[i];
            if (thisId.indexOf(":") > 0) {
                artifact[0] = thisId.split(':')[0]; // namespace
                artifact[1] = thisId.substr(artifact[0].length + 1) // id

                // handle urls:
                if (artifact[0] == "http" || artifact[0] == "https"){
                    artifact[0] = "url";
                    artifact[1] = thisId
                }
            }
            else {
                if (thisId.length > 0) {
                    var isnum_with_possible_period = /^[\d\.]+$/.test(thisId)
                    // handle dois entered without the doi prefix
                    if (thisId.substring(0,3) == "10.") {
                        artifact[0] = "doi"
                    } else if (isnum_with_possible_period && (thisId.length > 5) && (thisId.length <= 8)) {
                        // definition of pmid from http://www.nlm.nih.gov/bsd/mms/medlineelements.html#pmid
                        // this doesn't catch short PMIDs, but that's ok
                        artifact[0] = "pmid"
                    }
                    else {
                        artifact[0] = "unknown"
                    }
                    artifact[1] = thisId
                }
            }
            if (typeof artifact[1] != "undefined") {
                ret.push(artifact);
            }
        }
        return ret;
    },
    start:function(){},
    update:function(){},
    done:function(){},
    failure:function(){}

}

// upload bibtex from google scholar
var BibtexImporter = function(aliases, elem) {
    this.aliases = aliases
    this.elem$ = $(elem)
    this.bibtexEntriesParsedFromFile = []
}
BibtexImporter.prototype = {

    pull: function() {
        var that = this
        this.start()
        var providerName = this.elem$.attr("id").replace("input_", "")

        var formData = new FormData();
        formData.append('file', this.elem$[0].files[0]);

        $.ajax({
                   url: api_root+'/provider/bibtex/memberitems',
                   type: "POST",
                   processData: false,
                   contentType: false,
                   timeout: 5*1000,  // 5 seconds
                   data: formData,
                   dataType: "json",
                   success:  function(data){
                       entries = {
                           biblio: data,
                           total: data.length,
                           aliases: []
                       }
                       console.log("got some items back:", data)
                       that.update.call(that, entries)
                   },
                   error: function(request) {that.failure.call(that, request)}
               });

    },
    start:function() {
        changeElemState(this.elem$, "working")
    },
    update: function(entries, errors){
        errors = errors || 0
        var that = this

        // end conditions
        if (!entries.biblio.length) return this.done(entries)
        if (errors > 3) return this.failure()

        for (k in entries.biblio){
            entries.aliases[k] = ["biblio", entries.biblio[k]]
        }

        that.updateProgressbar.call(
                            that,
                            entries.total,
                            entries.biblio.length
                        )
        this.done(entries)
    },
    done: function(entries){
        console.log("we're done!")
        changeElemState(this.elem$, "success")
        this.aliases.add(entries.aliases)
        this.elem$
            .parents(".control-group")
            .find("span.success span.value")
            .html(this.aliases.numAddedLast)
    },
    failure: function() {
        changeElemState(this.elem$, "error")
    },
    updateProgressbar: function(total, remaining) {
        var done = total - remaining
        percentDone = Math.round(done / total * 100)
        this.elem$
            .parents(".control-group")
            .find("span.working span.value")
            .html(percentDone)
    }
}
<|endoftext|>


<commit_before>/**
  * @constructor
  */

var VirtualTextSearch = function()
{
  const
  DEFAULT_STYLE = "background-color:#ff0; color:#000;",
  HIGHLIGHT_STYLE = "background-color:#0f0; color:#000;",
  DEFAULT_SCROLL_MARGIN = 50,
  SEARCH_DELAY = 50;

  var
  self = this,
  search_therm = '',
  cursor = -1,
  container = null,
  source_container = null,
  source_container_parentNode = null,
  timeouts = new Timeouts(),
  __script = null,
  __offset = -1,
  __length = 0,
  __hit = [],
  __input = null,
  __last_match_cursor = 0,

  search_node = function(node)
  {
    var cur_node = node.firstChild, pos = 0, hit = null, span = null, length = 0;
    while( cur_node && __offset > -1 )
    {
      switch(cur_node.nodeType)
      {
        case 1:
        {
          search_node(cur_node);
          break;
        }
        case 3:
        {
          if( cur_node.nodeValue.length > __offset )
          {
            pos = __offset;
            hit = cur_node.splitText(pos);
            if( ( length = hit.nodeValue.length ) >= __length )
            {
              length = __length;
              __offset = -1;
            }
            else
            {
              __length -= length;
              __offset = 0;
            }
            cur_node = hit.splitText(length);
            span = node.insertBefore(node.ownerDocument.createElement('span'), hit);
            span.style.cssText = HIGHLIGHT_STYLE;
            span.appendChild(node.removeChild(hit));
            __hit[__hit.length] = span;
          }
          else
          {
            __offset -= cur_node.nodeValue.length;
          }
          break;
        };
      }
      cur_node = cur_node.nextSibling;
    }
  };

  this.clearHighlightSpan = function(ele)
  {
      var parent = ele.parentNode;
      parent.replaceChild(ele.firstChild, ele);
      parent.normalize();
  }

  this.clearHit = function()
  {
    __hit.forEach(this.clearHighlightSpan);
    __hit = [];
  }

  this.clearScriptContext = function()
  {
    if(__script)
    {
      delete __script.line_matches;
      delete __script.line_offsets;
      delete __script.match_cursor;
      delete __script.match_length;
    }
  }

  this.search = function(new_search_therm)
  {
    var
    pos = -1,
    source = '',
    line_arr = null,
    line_arr_length = 0,
    line_cur = 0;

    if( new_search_therm != search_therm )
    {
      search_therm = new_search_therm;
      if(new_search_therm.length > 2)
      {
        self.clearHit();
        if( __script )
        {
          var line_matches = __script.line_matches = [];
          var line_offsets = __script.line_offsets = [];
          __script.match_cursor = 0;
          __script.match_length = search_therm.length
          source = __script.source;
          line_arr = __script.line_arr;
          line_arr_length = line_arr.length
          while( ( pos = source.indexOf(search_therm, pos + 1) ) != -1 )
          {
            while( line_cur < line_arr_length && line_arr[line_cur] <= pos && ++line_cur );
            line_matches[line_matches.length] = line_cur;
            line_offsets[line_offsets.length] = pos - line_arr[line_cur - 1];
          }
          if( __last_match_cursor )
          {
            if( __last_match_cursor < __script.match_length )
            {
              __script.match_cursor = __last_match_cursor;
            }
            __last_match_cursor = 0;
          }
          if( __script.line_matches.length )
          {
            self.highlight(true, new_search_therm);
          }
          else
          {
            topCell.statusbar.updateInfo(ui_strings.S_TEXT_STATUS_SEARCH_NO_MATCH.
              replace("%(SEARCH_TERM)s", new_search_therm));
          }
        }
      }
      else
      {
        if(__hit.length)
        {
          self.clearHit();
        }
        self.clearScriptContext();
        topCell.statusbar.updateInfo('');
        search_therm = '';
      }
    }

  }

  this.searchDelayed = function(new_search_therm)
  {
    timeouts.set(this.search, SEARCH_DELAY, new_search_therm);
  }

  this.update = function()
  {
    var new_search_therm = search_therm;
    if( search_therm.length > 2 )
    {
      search_therm = '';
      this.search(new_search_therm);
    }
  }

  this.highlight = function(set_match_cursor, new_search_therm)
  {
    // new_search_therm is passed to know the arguments.callee.caller context
    // highlight is called at the end of a succesful search and
    // on keyup if it was the enter key to highlight the next tolken
    if( views.js_source.isvisible()
        && __script
        && __script.line_matches
        && __script.line_matches.length )
    {
      var line = __script.line_matches[__script.match_cursor];
      var top_line = views.js_source.getTopLine();
      var bottom_line = views.js_source.getBottomLine();
      if(set_match_cursor)
      {
        __script.match_cursor = 0;
        while( __script.line_matches[__script.match_cursor] < top_line )
        {
          __script.match_cursor++;
        }
        line = __script.line_matches[__script.match_cursor];
      }
      if( line <= top_line || line >= bottom_line )
      {
        var plus_lines = views.js_source.getMaxLines() <= 7
          ? views.js_source.getMaxLines() / 2 >> 0
          : 7;
        views.js_source.showLine(__script.id, line - plus_lines );
        top_line = views.js_source.getTopLine();
      }
      if( !source_container )
      {
        source_container_parentNode = container.getElementsByTagName('div')[0];
        source_container = container.getElementsByTagName('div')[1];
      }
      var div = source_container.getElementsByTagName('div')[line - top_line];
      __offset = __script.line_offsets[__script.match_cursor];
      __length = __script.match_length;
      self.clearHit();
      search_node(div);
      source_container.parentNode.scrollLeft = 0;
      if( __hit.length
         && __hit[0].offsetLeft > source_container_parentNode.scrollLeft + source_container_parentNode.offsetWidth )
      {
        source_container.parentNode.scrollLeft = __hit[0].offsetLeft - 50;
      }
      topCell.statusbar.updateInfo(ui_strings.S_TEXT_STATUS_SEARCH.
        replace("%(SEARCH_TERM)s", search_therm).
        replace("%(SEARCH_COUNT_TOTAL)s", __script.line_matches.length).
        replace("%(SEARCH_COUNT_INDEX)s", __script.match_cursor + 1) );
      if( ++__script.match_cursor >= __script.line_matches.length )
      {
        __script.match_cursor = 0;
      }

    }
    // if the view was switched and the search tolken is still there
    // but no search was done jet for that new view
    // keyup event callback, so new_search_therm will be 'undefined'
    else if( new_search_therm != search_therm )
    {
      var new_search_therm = search_therm;
      search_therm = '';
      this.search(new_search_therm);
    }

  }

  this.setContainer = function(_container)
  {
    if(_container)
    {
      container = _container;
      source_container = null;
      source_container_parentNode = null;
    }
  }

  this.setFormInput = function(input)
  {
    if(input)
    {
      __input = input;
      if(search_therm)
      {
        __input.value = search_therm;
        __input.parentNode.firstChild.textContent = '';
        var new_search_therm = search_therm;
        search_therm = '';
        this.search(new_search_therm);
      }
    }
  }

  this.setScript = function(script)
  {
    __script = script;
    source_container = null;
    source_container_parentNode = null;
  }

  this.cleanup = function()
  {
    __last_match_cursor = __script && __script.match_cursor || 0;
    cursor = -1;
    self.clearScriptContext();
    self.clearHit();
    container = source_container = source_container_parentNode = __input = null;
    __offset = -1;
    topCell.statusbar.updateInfo('');
  }

};<commit_msg>synced with kaleidoscope<commit_after>/**
  * @constructor
  */

var VirtualTextSearch = function()
{
  const
  DEFAULT_STYLE = "background-color:#ff0; color:#000;",
  HIGHLIGHT_STYLE = "background-color:#0f0; color:#000;",
  DEFAULT_SCROLL_MARGIN = 50,
  SEARCH_DELAY = 50;

  var
  self = this,
  search_therm = '',
  cursor = -1,
  container = null,
  source_container = null,
  source_container_parentNode = null,
  timeouts = new Timeouts(),
  __script = null,
  __offset = -1,
  __length = 0,
  __hit = [],
  __input = null,
  __last_match_cursor = 0,

  search_node = function(node)
  {
    var cur_node = node && node.firstChild, pos = 0, hit = null, span = null, length = 0;
    while( cur_node && __offset > -1 )
    {
      switch(cur_node.nodeType)
      {
        case 1:
        {
          search_node(cur_node);
          break;
        }
        case 3:
        {
          if( cur_node.nodeValue.length > __offset )
          {
            pos = __offset;
            hit = cur_node.splitText(pos);
            if( ( length = hit.nodeValue.length ) >= __length )
            {
              length = __length;
              __offset = -1;
            }
            else
            {
              __length -= length;
              __offset = 0;
            }
            cur_node = hit.splitText(length);
            span = node.insertBefore(node.ownerDocument.createElement('span'), hit);
            span.style.cssText = HIGHLIGHT_STYLE;
            span.appendChild(node.removeChild(hit));
            __hit[__hit.length] = span;
          }
          else
          {
            __offset -= cur_node.nodeValue.length;
          }
          break;
        };
      }
      cur_node = cur_node.nextSibling;
    }
  };

  this.clearHighlightSpan = function(ele)
  {
      var parent = ele.parentNode;
      parent.replaceChild(ele.firstChild, ele);
      parent.normalize();
  }

  this.clearHit = function()
  {
    __hit.forEach(this.clearHighlightSpan);
    __hit = [];
  }

  this.clearScriptContext = function()
  {
    if(__script)
    {
      delete __script.line_matches;
      delete __script.line_offsets;
      delete __script.match_cursor;
      delete __script.match_length;
    }
  }

  this.search = function(new_search_therm)
  {
    var
    pos = -1,
    source = '',
    line_arr = null,
    line_arr_length = 0,
    line_cur = 0;

    if( new_search_therm != search_therm )
    {
      search_therm = new_search_therm;
      if(new_search_therm.length > 2)
      {
        self.clearHit();
        if( __script )
        {
          var line_matches = __script.line_matches = [];
          var line_offsets = __script.line_offsets = [];
          __script.match_cursor = 0;
          __script.match_length = search_therm.length
          source = __script.source;
          line_arr = __script.line_arr;
          line_arr_length = line_arr.length
          while( ( pos = source.indexOf(search_therm, pos + 1) ) != -1 )
          {
            while( line_cur < line_arr_length && line_arr[line_cur] <= pos && ++line_cur );
            line_matches[line_matches.length] = line_cur;
            line_offsets[line_offsets.length] = pos - line_arr[line_cur - 1];
          }
          if( __last_match_cursor )
          {
            if( __last_match_cursor < __script.match_length )
            {
              __script.match_cursor = __last_match_cursor;
            }
            __last_match_cursor = 0;
          }
          if( __script.line_matches.length )
          {
            self.highlight(true, new_search_therm);
          }
          else
          {
            topCell.statusbar.updateInfo(ui_strings.S_TEXT_STATUS_SEARCH_NO_MATCH.
              replace("%(SEARCH_TERM)s", new_search_therm));
          }
        }
      }
      else
      {
        if(__hit.length)
        {
          self.clearHit();
        }
        self.clearScriptContext();
        topCell.statusbar.updateInfo('');
        search_therm = '';
      }
    }

  }

  this.searchDelayed = function(new_search_therm)
  {
    timeouts.set(this.search, SEARCH_DELAY, new_search_therm);
  }

  this.update = function()
  {
    var new_search_therm = search_therm;
    if( search_therm.length > 2 )
    {
      search_therm = '';
      this.search(new_search_therm);
    }
  }

  this.highlight = function(set_match_cursor, new_search_therm)
  {
    // new_search_therm is passed to know the arguments.callee.caller context
    // highlight is called at the end of a succesful search and
    // on keyup if it was the enter key to highlight the next tolken
    if( views.js_source.isvisible()
        && __script
        && __script.line_matches
        && __script.line_matches.length )
    {
      var line = __script.line_matches[__script.match_cursor];
      var top_line = views.js_source.getTopLine();
      var bottom_line = views.js_source.getBottomLine();
      if(set_match_cursor)
      {
        __script.match_cursor = 0;
        while( __script.line_matches[__script.match_cursor] < top_line )
        {
          __script.match_cursor++;
        }
        line = __script.line_matches[__script.match_cursor];
      }
      if( line <= top_line || line >= bottom_line )
      {
        var plus_lines = views.js_source.getMaxLines() <= 7
          ? views.js_source.getMaxLines() / 2 >> 0
          : 7;
        views.js_source.showLine(__script.id, line - plus_lines );
        top_line = views.js_source.getTopLine();
      }
      if( !source_container )
      {
        source_container_parentNode = container.getElementsByTagName('div')[0];
        source_container = container.getElementsByTagName('div')[1];
      }
      var div = source_container.getElementsByTagName('div')[line - top_line];
      __offset = __script.line_offsets[__script.match_cursor];
      __length = __script.match_length;
      self.clearHit();
      search_node(div);
      source_container.parentNode.scrollLeft = 0;
      if( __hit.length
         && __hit[0].offsetLeft > source_container_parentNode.scrollLeft + source_container_parentNode.offsetWidth )
      {
        source_container.parentNode.scrollLeft = __hit[0].offsetLeft - 50;
      }
      topCell.statusbar.updateInfo(ui_strings.S_TEXT_STATUS_SEARCH.
        replace("%(SEARCH_TERM)s", search_therm).
        replace("%(SEARCH_COUNT_TOTAL)s", __script.line_matches.length).
        replace("%(SEARCH_COUNT_INDEX)s", __script.match_cursor + 1) );
      if( ++__script.match_cursor >= __script.line_matches.length )
      {
        __script.match_cursor = 0;
      }

    }
    // if the view was switched and the search tolken is still there
    // but no search was done jet for that new view
    // keyup event callback, so new_search_therm will be 'undefined'
    else if( new_search_therm != search_therm )
    {
      var new_search_therm = search_therm;
      search_therm = '';
      this.search(new_search_therm);
    }

  }

  this.setContainer = function(_container)
  {
    if(_container)
    {
      container = _container;
      source_container = null;
      source_container_parentNode = null;
    }
  }

  this.setFormInput = function(input)
  {
    if(input)
    {
      __input = input;
      if(search_therm)
      {
        __input.value = search_therm;
        __input.parentNode.firstChild.textContent = '';
        var new_search_therm = search_therm;
        search_therm = '';
        this.search(new_search_therm);
      }
    }
  }

  this.setScript = function(script)
  {
    __script = script;
    source_container = null;
    source_container_parentNode = null;
  }

  this.cleanup = function()
  {
    __last_match_cursor = __script && __script.match_cursor || 0;
    cursor = -1;
    self.clearScriptContext();
    self.clearHit();
    container = source_container = source_container_parentNode = __input = null;
    __offset = -1;
    topCell.statusbar.updateInfo('');
  }

};<|endoftext|>


<commit_before>import chokidar from 'chokidar';
import { resolve as pathResolve } from 'path';
import appRootDir from 'app-root-dir';
import { log } from '../../utils';
import HotDevelopment from './hot-development';

process.env.NODE_ENV = 'development';

// start dev bundles building
let devServer = new HotDevelopment();

// Any changes to our webpack bundleConfigs should restart the development devServer.
const watcher = chokidar.watch([
  pathResolve(appRootDir.get(), 'stanza', 'index'),
]);

watcher.on('ready', () => {
  watcher.on('change', () => {
    log({
      title: 'webpack',
      level: 'warn',
      message: 'Project build configuration has changed. Restarting the development devServer...',
    });

    devServer.dispose().then(() => {
      // Make sure our new webpack bundleConfigs aren't in the module cache.
      Object.keys(require.cache).forEach((modulePath) => {
        if (modulePath.indexOf('config') !== -1) {
          delete require.cache[modulePath];
        } else if (modulePath.indexOf('tools') !== -1) {
          delete require.cache[modulePath];
        }
      });

      // Create a new development devServer.
      devServer = new HotDevelopment();
    });
  });
});

// If we receive a kill cmd then we will first try to dispose our listeners.
process.on('SIGTERM', () =>
  devServer && devServer.dispose().then(() => process.exit(0)),
);
<commit_msg>fix path to config for watch<commit_after>import chokidar from 'chokidar';
import { resolve as pathResolve } from 'path';
import appRootDir from 'app-root-dir';
import { log } from '../../utils';
import HotDevelopment from './hot-development';

process.env.NODE_ENV = 'development';

// start dev bundles building
let devServer = new HotDevelopment();

// Any changes to our webpack bundleConfigs should restart the development devServer.
const watcher = chokidar.watch([
  pathResolve(appRootDir.get(), 'stanza', 'index.js'),
]);

watcher.on('ready', () => {
  watcher.on('change', () => {
    log({
      title: 'webpack',
      level: 'warn',
      message: 'Project build configuration has changed. Restarting the development devServer...',
    });

    devServer.dispose().then(() => {
      // Make sure our new webpack bundleConfigs aren't in the module cache.
      Object.keys(require.cache).forEach((modulePath) => {
        if (modulePath.indexOf('config') !== -1) {
          delete require.cache[modulePath];
        } else if (modulePath.indexOf('tools') !== -1) {
          delete require.cache[modulePath];
        }
      });

      // Create a new development devServer.
      devServer = new HotDevelopment();
    });
  });
});

// If we receive a kill cmd then we will first try to dispose our listeners.
process.on('SIGTERM', () =>
  devServer && devServer.dispose().then(() => process.exit(0)),
);
<|endoftext|>


<commit_before>'use strict';

/*@ngInject*/
module.exports.directive = function () {
  return {
    restrict: 'E',
    templateUrl: 'navbar.html',
    controller: 'NavbarCtrl'
  };
};

/*@ngInject*/
module.exports.controller = function ($scope, empiricalBaseURL) {
  $scope.baseRoute = function () {
    return empiricalBaseURL.split("api")[0];
  };
};
<commit_msg>use single quotes.<commit_after>'use strict';

/*@ngInject*/
module.exports.directive = function () {
  return {
    restrict: 'E',
    templateUrl: 'navbar.html',
    controller: 'NavbarCtrl'
  };
};

/*@ngInject*/
module.exports.controller = function ($scope, empiricalBaseURL) {
  $scope.baseRoute = function () {
    return empiricalBaseURL.split('api')[0];
  };
};
<|endoftext|>