<commit_before>/*************************************************************************
*      DemarcateJS v1.0 is an in-place Markdown editor and decoder       *
*                                                                        *
*      It was written by William Hart (http://www.williamhart.info) to   *
*      run on "textr" (http://to-textr.com/) a new Markdown enabled      *
*      platform to allow writing and sharing of online text              *
*                                                                        *
*                                                                        *
*      This code is provided under a GPLv3 License                       *
*               http://www.gnu.org/licenses/gpl-3.0.html                 *
*      It is also hosted at github:                                      *
*               http://will-hart.github.com/demarcate                    *
*      Contributions welcome.                                            *
*                                                                        *
*************************************************************************/

/*
 * Bash in an 'indexOf' function if not available
 * (looking at IE I think!)
 */
if(!Array.indexOf){
    Array.prototype.indexOf = function(obj){
        for (var i=0; i<this.length; i++){
            if (this[i]==obj){
                return i;
            }
        }
        return -1;
    }
}

/*
 * Now make a handy 'contains' function which returns true
 * if the element is in the array and false otherwise
 */
Array.prototype.contains = function(obj) {
    return this.indexOf(obj) >= 0;
}

/*
 * Whitelist of tags to include
 */
var demarcate_whitelist = [
    'DIV',
    'SPAN',
    'H1',
    'H2',
    'H3',
    'H4',
    'H5',
    'H6',
    'LI',
    'BLOCKQUOTE',
    'PRE',
    'CODE',
    'A',
    'P',
    'UL',
    'OL',
    'HR',
    'STRONG',
    'EM',
];

var editor_whitelist = [
    'h1',
    'h2',
    'h3',
    'h4',
    'h5',
    'h6',
    'li',
    'blockquote',
    'pre',
    'code',
    'p',
]

/*
 * Lookup table for line starts
 */
var line_starts = {
    'H1': '# ',
    'H2': '## ',
    'H3': '### ',
    'H4': '#### ',
    'H5': '##### ',
    'H6': '###### ',
    'LI': ' - ',
    'BLOCKQUOTE': '> ',
    'PRE': '    ',
    'CODE': '`',
    'A': '[',
    'HR': '\n---------------------\n\n',
    'STRONG': '**',
    'EM': '*',
};

/*
 * Lookup table for line ends
 */
var line_ends = {
    'H1': '\n\n',
    'H2': '\n\n',
    'H3': '\n\n',
    'H4': '\n\n',
    'H5': '\n\n',
    'H6': '\n\n',
    'LI': '\n',
    'BLOCKQUOTE': '\n\n',
    'PRE': '\n\n',
    'CODE': '`',
    'A': ']',
    'P': '\n\n',
    'DIV': '\n\n',
    'STRONG': '**',
    'EM': '*',
};

/*
 * A list of elements which have their internal
 * HTML added to the markdown document
 */
var include_internal = [
    'H1',
    'H2',
    'H3',
    'H4',
    'H5',
    'H6',
    'P',
    'BLOCKQUOTE',
    'A', //- not included here as requires special treatment
];

/*
 * Performs a number of manipulations on the edited string before adding
 * it back into the DOM.  For instance:
 *   - Strips html tags from the textareas to prevent injection
 *   - Restores links from []() syntax to  syntax
 */
function modifyHtml(str){
    // remove HTML tags
    var strippedText = $("
").html(str).text();

    // restore links to HTML.
    var full_regex = new RegExp("\\[(.*?)\\]\\((.*?)\\)", "gi");
    strippedText = strippedText.replace(full_regex, "$1");

    // all done!
    return strippedText;
}

/*
 * Recursively reverse the markdown of the element
 * and its child objects
 */
function demarkdown(elem, ignore_extras) {

    // check if ignore_extras was defined. Default is true
    ignore_extras = ignore_extras || false;

    // work out what we are looking at
    var node = elem.get(0);
    var tag_name = node.tagName;
    var node_type = node.nodeType;
    var result = "";

    // do not parse temporary dom elements
    if (elem.hasClass("demarcate_temporary")) return "";

    // check we are allowed to decode the tag
    if (! demarcate_whitelist.contains(tag_name) && node_type != 3) {
        return "";
    }

    // open the tag
    if (! ignore_extras || tag_name == 'A') {
        result = line_starts[tag_name] == undefined ? "" : line_starts[tag_name];
    }

    // add any inner html
    if (node_type == 3) {
        result += $.trim(node.nodeValue);
    }

    // add child elements
    $.each(elem.contents(), function(index, value) {
        result += demarkdown($(value), ignore_extras);
    });

    // close the tag
    if (! ignore_extras || tag_name == 'A') {
        result += line_ends[elem.get(0).tagName] == undefined ? "" : line_ends[tag_name];
    }

    // apply special behaviour for  tags
    if (tag_name == 'A') {
        result = " " + result + "(" + elem.attr('href') + ") ";
    }

    // return the result
    return result;
}

/*
 * generate a toolbar for setting the type of node
 * and saving or cancelling the results
 */
function generate_toolbar() {
    var toolbar = $("
", {id: 'demarcate_toolbar'});
    toolbar.append($("", {id: 'demarcate_h1', class: 'demarcate_style', href:"#" }));
    toolbar.append($("", {id: 'demarcate_h2', class: 'demarcate_style', href:"#" }));
    toolbar.append($("", {id: 'demarcate_h3', class: 'demarcate_style', href:"#" }));
    toolbar.append($("", {id: 'demarcate_h4', class: 'demarcate_style', href:"#" }));
    toolbar.append($("", {id: 'demarcate_h5', class: 'demarcate_style', href:"#" }));
    toolbar.append($("", {id: 'demarcate_h6', class: 'demarcate_style', href:"#" }));
    toolbar.append($("", {id: 'demarcate_p', class: 'demarcate_style',  href:"#" }));
    toolbar.append($("", {id: 'demarcate_code', class: 'demarcate_style', href:"#" }));
    toolbar.append($("", {id: 'demarcate_ul', class: 'demarcate_style', href:"#" }));
    toolbar.append($("", {id: 'demarcate_ol', class: 'demarcate_style', thref:"#" }));
    toolbar.append($("", {id: 'demarcate_cancel', href:"#" }));
    toolbar.append($("", {id: 'demarcate_save', href:"#" }));
    return toolbar;
}

/*
 * Sets an 'active' class for the toolbar item that matches the
 * current editing class
 */
function toolbar_set_active() {
    var tag_name = "";

    // get the type of tag we are editing
    if (current_demarcate_element == null) {
        return;
    } else {
        tag_name = current_demarcate_element.get(0).tagName;
    }

    // remove old active tags
    $(".demarcate_style").removeClass("active");

    // apply new active tags
    $("#demarcate_" + tag_name.toLowerCase()).addClass("active");
}

/*
 * Display an editor textarea
 */
function display_editor(elem) {
    elem = $(elem);
    var tag_name = elem.get(0).tagName;

    // double check we are allowed to edit this
    if (editor_whitelist.contains(tag_name.toLowerCase())) {

        // create the new text editor - ignore front matter
        var md = demarkdown(elem, true);
        var ed = $("<textarea id='demarcate'></textarea>");
        var tb = generate_toolbar();

        elem.after(ed);
        elem.after(tb);
        elem.addClass("demarcate_hide");

        // store the element currently being edited
        current_demarcate_element = elem;
        current_demarcate_editor = ed;

        // insert the markdown into the editor and focus
        // on the last character. Set toolbar buttons to active
        toolbar_set_active();

        // hook up jquery.autosize.js if present
        if (typeof elem.autosize != undefined) {
            ed.autosize({'append': '\n'});
        }
        ed.focus().val($.trim(md)).trigger('autosize');
    }
}

/*
 * Hides the editor textarea and restores the hidden div
 */
function hide_editor(e) {
    e.preventDefault();

    // remove the toolbar and editor
    $("div#demarcate_toolbar").remove();
    current_demarcate_editor.remove();
    current_demarcate_editor = null;

    // prune empty elements
    if (current_demarcate_element.html() === "") {
        current_demarcate_element.remove();
    } else {
        current_demarcate_element.removeClass("demarcate_hide");
    }
    current_demarcate_element = null;

    // prune any unsaved temporary elements. The save method
    // removes this class to prevent new elements from being
    // removed.
    $(".demarcate_temporary").remove();
}

/*
 * A mouseup handler that checks if the toolbar or editor was clicked.
 * If not, it hides the editor.
 */
function demarcate_click_elsewhere_save(e) {
    if (current_demarcate_editor == null) return;
    var tb = $("#demarcate_toolbar");
    if (! current_demarcate_editor.is(e.target) &&
        ! tb.is(e.target) && tb.has(e.target).length === 0) {
        $("#demarcate_save").click();
    }
}

/*
 * Connect all the demarcate_toolbar button events
 */
function enable_demarcate_toolbar_handlers() {

    // handle hitting the return key inside the editor - saves it
    $(document).on('keydown', '#demarcate', function(e) {
        if (e.keyCode == 13) { // enter  >>  save
            e.preventDefault();
            if (e.shiftKey) {
                $("#demarcate_save").click();
            } else {
                // create another element of the same type after this one
                var tag_name = current_demarcate_element.get(0).tagName;
                var new_elem = $("<" + tag_name + "/>");
                new_elem.insertAfter(current_demarcate_element);

                // force a save on the previous element
                $("#demarcate_save").click();

                // add the class after saving to prevent it being immediately pruned
                new_elem.addClass("demarcate_temporary");
                new_elem.click();
            }
        } else if (e.keyCode == 32) { // ctrl+space  >>  cycle element types
            // check for control space
            if (e.ctrlKey) {
                e.preventDefault();
                var next_style = $("div#demarcate_toolbar a.active").next().filter(".demarcate_style");
                if (next_style.length != 0) { // escape  >>  cancel editing
                    next_style.click();
                } else {
                    $("div#demarcate_toolbar a.demarcate_style").first().click();
                }
            }
        } else if (e.keyCode == 27) { //escape
            $("#demarcate_cancel").click();
        }
    });

    // handle clicking outside the div
    $(document).bind('mousedown', demarcate_click_elsewhere_save);

    // cancel button
    $(document).on('click', '#demarcate_cancel', function(e) {
        hide_editor(e);
        $(document).trigger('demarcate_editor_closed', [current_demarcate_element]);
    });

    // save button
    $(document).on('click', '#demarcate_save', function(e) {
        current_demarcate_element.html(modifyHtml(current_demarcate_editor.val()));
        current_demarcate_element.removeClass("demarcate_temporary");
        hide_editor(e)
        $(document).trigger('demarcate_editor_closed', [current_demarcate_element]);
    });

    $(document).on('click', '.demarcate_style', function(e) {
        e.preventDefault();
        var id = $(this).attr('id').replace("demarcate_", "");

        // check this is an allowable tag
        if (editor_whitelist.contains(id)) {
            // replace the element with the new type
            var new_elem = $("<" + id + "></" + id + ">");
            current_demarcate_element.after(new_elem);
            current_demarcate_element.remove();
            current_demarcate_element = new_elem;

            // currently cannot 'cancel' once the tag has changed
            // therefore lets hide the cancel button
            $("a#demarcate_cancel").fadeOut('fast',function() { this.remove(); });

            // set the current button classes and focus back on the editor
            toolbar_set_active()
            current_demarcate_editor.focus();
        } else {
            console.log("Unknown or disallowed tag type - " + id + ". Aborting tag change.");
        }
    });
};

/*
 * Hook up the 'demarcate' function as a jQuery plugin
 */
(function( $ ){
    $.fn.demarcate = function() {
        result = demarkdown(this);
        $(document).trigger("demarcation_complete", [result]);
        return result;
    };
})( jQuery );

/*
 * Now hookup whitelisted elements for auto-edit.
 */
(function( $ ){
    $.fn.enable_demarcate = function() {
        // give global access to the demarcate_editor object and other elements
        window.demarcate_dom_root = $(this);
        window.current_demarcate_editor = null;
        window.current_demarcate_element = null;

        len = editor_whitelist.length
        for (var i = 0; i < len; i++) {
            live_selector = "#" + this.attr('id') + " " + editor_whitelist[i];

            $(document).on('click', live_selector, function() {
                display_editor(this);
            });

            $(document).on('mouseenter', live_selector, function() {
                $(this).addClass("demarcate_hover_editable");
            });

            $(document).on('mouseleave', live_selector, function() {
                $(this).removeClass("demarcate_hover_editable");
            });
        }

        enable_demarcate_toolbar_handlers();

        // if our editor box is empty, add an initial 'edit me' paragraph
        // add a class to ensure this isn't parsed by the demarkdown function
        if (demarcate_dom_root.is(":empty") ||
                $.trim(demarcate_dom_root.html()) == "") {

            demarcate_dom_root.append(
                $('
', {
                        class: 'demarcate_temporary',
                        text: 'Click me to start editing'
                })
            );
        }
    };
})( jQuery );

<commit_msg>Convert to global element dictionary for attribute handling<commit_after>/*************************************************************************
*      DemarcateJS v1.0 is an in-place Markdown editor and decoder       *
*                                                                        *
*      It was written by William Hart (http://www.williamhart.info) to   *
*      run on "textr" (http://to-textr.com/) a new Markdown enabled      *
*      platform to allow writing and sharing of online text              *
*                                                                        *
*                                                                        *
*      This code is provided under a GPLv3 License                       *
*               http://www.gnu.org/licenses/gpl-3.0.html                 *
*      It is also hosted at github:                                      *
*               http://will-hart.github.com/demarcate                    *
*      Contributions welcome.                                            *
*                                                                        *
*************************************************************************/

/*
 * Whitelist of tags to include
 */
var tag_dict = {
    'div': {editable: false, markdownable: true, prefix: '', postfix: '', post_newline: false, childprefix: ''},
    'span': {editable: false, markdownable: true, prefix: '', postfix: '', post_newline: false, childprefix: ''},
    'h1': {editable: true, markdownable: true, prefix: '#', postfix: '\n', post_newline: true, childprefix: ''},
    'h2': {editable: true, markdownable: true, prefix: '##', postfix: '\n', post_newline: true, childprefix: ''},
    'h3': {editable: true, markdownable: true, prefix: '###', postfix: '\n', post_newline: true, childprefix: ''},
    'h4': {editable: true, markdownable: true, prefix: '####', postfix: '\n', post_newline: true, childprefix: ''},
    'h5': {editable: true, markdownable: true, prefix: '#####', postfix: '\n', post_newline: true, childprefix: ''},
    'h6': {editable: true, markdownable: true, prefix: '######', postfix: '\n', post_newline: true, childprefix: ''},
    'li': {editable: true, markdownable: true, prefix: '', postfix: '\n', post_newline: true, childprefix: ''},
    'ul': {editable: true, markdownable: true, prefix: '', postfix: '\n', post_newline: true, childprefix: ' - '},
    'ol': {editable: true, markdownable: true, prefix: '', postfix: '\n', post_newline: true, childprefix: ' 1. '},
    'blockquote': {editable: true, markdownable: true, prefix: '>', postfix: '\n', post_newline: true, childprefix: '>'},
    'pre': {editable: true, markdownable: true, prefix: '    ', postfix: '\n', post_newline: true, childprefix: '    '},
    'code': {editable: true, markdownable: true, prefix: '`', postfix: '`', post_newline: false, childprefix: ''},
    'a': {editable: true, markdownable: true, prefix: '[', postfix: ']', post_newline: false, childprefix: ''},
    'hr': {editable: false, markdownable: true, prefix: '\n---------------------', postfix: '\n', post_newline: true, childprefix: ''},
    'em': {editable: false, markdownable: true, prefix: '*', postfix: '*', post_newline: false, childprefix: ''},
    'strong': {editable: false, markdownable: true, prefix: '**', postfix: '**', post_newline: false, childprefix: ''},
    'p': {editable: true, markdownable: true, prefix: '', postfix: '\n', post_newline: true, childprefix: ''},
    '_text': {editable: false, markdownable: true, prefix: '', postfix: '', post_newline: false, childprefix: ''},
};

/*
 * Performs a number of manipulations on the edited string before adding
 * it back into the DOM.  For instance:
 *   - Strips html tags from the textareas to prevent injection
 *   - Restores links from []() syntax to  syntax
 */
function modifyHtml(str){
    // remove HTML tags
    var strippedText = $("
").html(str).text();

    // restore links to HTML.
    var full_regex = new RegExp("\\[(.*?)\\]\\((.*?)\\)", "gi");
    strippedText = strippedText.replace(full_regex, "$1");

    // all done!
    return strippedText;
}

/*
 * Recursively reverse the markdown of the element
 * and its child objects
 */
function demarkdown(elem, ignore_extras) {
    // check if ignore_extras was defined. Default is true
    ignore_extras = ignore_extras || false;

    // work out what we are looking at
    var node = elem.get(0);
    var node_type = node.nodeType;
    var tag_name = node_type == 3 ? '_text' : node.tagName.toLowerCase();
    var result = "";

    // do not parse temporary dom elements
    if (elem.hasClass("demarcate_temporary")) return result;

    // check if the element is in the tag_dict
    if (!(tag_name in tag_dict)) return result;

    // check we are allowed to decode the tag
    if (! tag_dict[tag_name].markdownable && node_type != 3) return result;

    // open the tag
    if (! ignore_extras || tag_name == 'a') {
        result = tag_dict[tag_name].prefix;
    }

    // add any text inside text nodes
    if (node_type == 3) {
        result += $.trim(node.nodeValue);
    }

    // add child elements
    $.each(elem.contents(), function(index, value) {
        result += demarkdown($(value), ignore_extras);
    });

    // close the tag
    if (! ignore_extras || tag_name == 'a') {
        result += tag_dict[tag_name].postfix;
    }

    // apply a new line if required
    if (tag_dict[tag_name].post_newline) {
        result += '\n';
    }

    // apply special behaviour for  tags
    if (tag_name == 'a') {
        result = " " + result + "(" + elem.attr('href') + ") ";
    }

    // return the result
    return result;
}

/*
 * generate a toolbar for setting the type of node
 * and saving or cancelling the results
 */
function generate_toolbar() {
    var toolbar = $("
", {id: 'demarcate_toolbar'});
    toolbar.append($("", {id: 'demarcate_h1', class: 'demarcate_style', href:"#" }));
    toolbar.append($("", {id: 'demarcate_h2', class: 'demarcate_style', href:"#" }));
    toolbar.append($("", {id: 'demarcate_h3', class: 'demarcate_style', href:"#" }));
    toolbar.append($("", {id: 'demarcate_h4', class: 'demarcate_style', href:"#" }));
    toolbar.append($("", {id: 'demarcate_h5', class: 'demarcate_style', href:"#" }));
    toolbar.append($("", {id: 'demarcate_h6', class: 'demarcate_style', href:"#" }));
    toolbar.append($("", {id: 'demarcate_p', class: 'demarcate_style',  href:"#" }));
    toolbar.append($("", {id: 'demarcate_code', class: 'demarcate_style', href:"#" }));
    toolbar.append($("", {id: 'demarcate_ul', class: 'demarcate_style', href:"#" }));
    toolbar.append($("", {id: 'demarcate_ol', class: 'demarcate_style', thref:"#" }));
    toolbar.append($("", {id: 'demarcate_cancel', href:"#" }));
    toolbar.append($("", {id: 'demarcate_save', href:"#" }));
    return toolbar;
}

/*
 * Sets an 'active' class for the toolbar item that matches the
 * current editing class
 */
function toolbar_set_active() {
    var tag_name = "";

    // get the type of tag we are editing
    if (current_demarcate_element == null) {
        return;
    } else {
        tag_name = current_demarcate_element.get(0).tagName.toLowerCase();
    }

    // remove old active tags
    $(".demarcate_style").removeClass("active");

    // apply new active tags
    $("#demarcate_" + tag_name).addClass("active");
}

/*
 * Display an editor textarea
 */
function display_editor(elem) {
    elem = $(elem);
    var tag_name = elem.get(0).tagName.toLowerCase();

    // double check we are allowed to edit this
    if (tag_name in tag_dict) {
        console.log("Displaying editor");

        // create the new text editor - ignore front matter
        var md = demarkdown(elem, true);
        var ed = $("<textarea id='demarcate'></textarea>");
        var tb = generate_toolbar();

        elem.after(ed);
        elem.after(tb);
        elem.addClass("demarcate_hide");

        // store the element currently being edited
        current_demarcate_element = elem;
        current_demarcate_editor = ed;

        // insert the markdown into the editor and focus
        // on the last character. Set toolbar buttons to active
        toolbar_set_active();

        // hook up jquery.autosize.js if present
        if (typeof elem.autosize != undefined) {
            ed.autosize({'append': '\n'});
        }
        ed.focus().val($.trim(md));
    }
}

/*
 * Hides the editor textarea and restores the hidden div
 */
function hide_editor(e) {
    e.preventDefault();

    console.log("Hiding editor");
    // remove the toolbar and editor
    $("div#demarcate_toolbar").remove();
    current_demarcate_editor.remove();
    current_demarcate_editor = null;

    // prune empty elements
    if (current_demarcate_element.html() === "") {
        current_demarcate_element.remove();
    } else {
        current_demarcate_element.removeClass("demarcate_hide");
    }
    current_demarcate_element = null;

    // prune any unsaved temporary elements. The save method
    // removes this class to prevent new elements from being
    // removed.
    $(".demarcate_temporary").remove();
}

/*
 * A mouseup handler that checks if the toolbar or editor was clicked.
 * If not, it hides the editor.
 */
function demarcate_click_elsewhere_save(e) {
    if (current_demarcate_editor == null) return;
    var tb = $("#demarcate_toolbar");
    if (! current_demarcate_editor.is(e.target) &&
        ! tb.is(e.target) && tb.has(e.target).length === 0) {
        $("#demarcate_save").click();
    }
}

/*
 * Connect all the demarcate_toolbar button events
 */
function enable_demarcate_toolbar_handlers() {

    // handle hitting the return key inside the editor - saves it
    $(document).on('keydown', '#demarcate', function(e) {
        if (e.keyCode == 13) { // enter  >>  save
            e.preventDefault();
            if (e.shiftKey) {
                $("#demarcate_save").click();
            } else {
                // create another element of the same type after this one
                var tag_name = current_demarcate_element.get(0).tagName;
                var new_elem = $("<" + tag_name + "/>");
                new_elem.insertAfter(current_demarcate_element);

                // force a save on the previous element
                $("#demarcate_save").click();

                // add the class after saving to prevent it being immediately pruned
                new_elem.addClass("demarcate_temporary");
                new_elem.click();
            }
        } else if (e.keyCode == 32) { // ctrl+space  >>  cycle element types
            // check for control space
            if (e.ctrlKey) {
                e.preventDefault();
                var next_style = $("div#demarcate_toolbar a.active").next().filter(".demarcate_style");
                if (next_style.length != 0) { // escape  >>  cancel editing
                    next_style.click();
                } else {
                    $("div#demarcate_toolbar a.demarcate_style").first().click();
                }
            }
        } else if (e.keyCode == 27) { //escape
            e.preventDefault();
            $("#demarcate_cancel").click();
        }
    });

    // handle clicking outside the div
    $(document).bind('mousedown', demarcate_click_elsewhere_save);

    // cancel button
    $(document).on('click', '#demarcate_cancel', function(e) {
        hide_editor(e);
        $(document).trigger('demarcate_editor_closed', [current_demarcate_element]);
    });

    // save button
    $(document).on('click', '#demarcate_save', function(e) {
        current_demarcate_element.html(modifyHtml(current_demarcate_editor.val()));
        current_demarcate_element.removeClass("demarcate_temporary");
        hide_editor(e)
        $(document).trigger('demarcate_editor_closed', [current_demarcate_element]);
    });

    $(document).on('click', '.demarcate_style', function(e) {
        e.preventDefault();
        var id = $(this).attr('id').replace("demarcate_", "");

        // check this is an allowable tag
        if (id in tag_dict) {
            // replace the element with the new type
            var new_elem = $("<" + id + "></" + id + ">");
            current_demarcate_element.after(new_elem);
            current_demarcate_element.remove();
            current_demarcate_element = new_elem;

            // currently cannot 'cancel' once the tag has changed
            // therefore lets hide the cancel button
            $("a#demarcate_cancel").fadeOut('fast',function() { this.remove(); });

            // set the current button classes and focus back on the editor
            toolbar_set_active()
            current_demarcate_editor.focus();
        } else {
            console.log("Unknown or disallowed tag type - " + id + ". Aborting tag change.");
        }
    });
};

/*
 * Hook up the 'demarcate' function as a jQuery plugin
 */
(function( $ ){
    $.fn.demarcate = function() {
        result = demarkdown(this);
        $(document).trigger("demarcation_complete", [result]);
        return result;
    };
})( jQuery );

/*
 * Now hookup whitelisted elements for auto-edit.
 */
(function( $ ){
    $.fn.enable_demarcate = function() {
        // give global access to the demarcate_editor object and other elements
        window.demarcate_dom_root = $(this);
        window.current_demarcate_editor = null;
        window.current_demarcate_element = null;

        for (var tag_name in tag_dict) {
            if (tag_dict[tag_name].editable) {
                live_selector = "#" + this.attr('id') + " " + tag_name;

                $(document).on('click', live_selector, function(e) {
                    if ($("#demarcate_toolbar").has(e.target).length > 0 ||
                            $("#demarcate_toolbar").is(e.target) ||
                            $(this).attr('id') === 'demarcate') {

                        return;
                    }
                    display_editor(this);
                });

                $(document).on('mouseenter', live_selector, function() {
                    $(this).addClass("demarcate_hover_editable");
                });

                $(document).on('mouseleave', live_selector, function() {
                    $(this).removeClass("demarcate_hover_editable");
                });
            }
        }

        enable_demarcate_toolbar_handlers();

        // if our editor box is empty, add an initial 'edit me' paragraph
        // add a class to ensure this isn't parsed by the demarkdown function
        if (demarcate_dom_root.is(":empty") ||
                $.trim(demarcate_dom_root.html()) == "") {

            demarcate_dom_root.append(
                $('
', {
                        class: 'demarcate_temporary',
                        text: 'Click me to start editing'
                })
            );
        }
    };
})( jQuery );

<|endoftext|>


<commit_before>function Display2D(context) {
    this.context = context;
}
Display2D.prototype = Object.create(Display.prototype);
Display2D.prototype.constructor = Display2D;

Display2D.prototype.clear = function() {
    var can = this.context.canvas, c = this.context;
    c.fillStyle = '#000';
    c.fillRect(0, 0, can.width, can.height);
    return this;
};

Display2D.prototype.draw = function() {
    var c = this.context, h = c.canvas.height, w = c.canvas.width,
        d = c.getImageData(0, 0, w, h);
    for (var y = 0; y < h; y++) {
        for (var x = 0; x < w; x++) {
            var i = w * 4 * y + x * 4,
                t = P(x / w, y / h).closest(this.points);
            d.data[i+0] = t.r;
            d.data[i+1] = t.g;
            d.data[i+2] = t.b;
            d.data[i+3] = 255;
        }
    }
    c.putImageData(d, 0, 0);
    var _this = this;
    c.strokeStyle = 'red';
    this.points.forEach(function(p) {
        var radius = 2;
        if (p === _this.selection) {
            radius *= 2;
            c.beginPath();
            c.arc(p.x * w, p.y * h, 8, 0, Math.PI * 2, false);
            c.stroke();
        }
        c.fillStyle = p.isDark() ? '#fff' : '#000';
        c.beginPath();
        c.arc(p.x * w, p.y * h, radius, 0, Math.PI * 2, false);
        c.fill();
    });
    return this;
};
<commit_msg>Drop the red circle bit.<commit_after>function Display2D(context) {
    this.context = context;
}
Display2D.prototype = Object.create(Display.prototype);
Display2D.prototype.constructor = Display2D;

Display2D.prototype.clear = function() {
    var can = this.context.canvas, c = this.context;
    c.fillStyle = '#000';
    c.fillRect(0, 0, can.width, can.height);
    return this;
};

Display2D.prototype.draw = function() {
    var c = this.context, h = c.canvas.height, w = c.canvas.width,
        d = c.getImageData(0, 0, w, h);
    for (var y = 0; y < h; y++) {
        for (var x = 0; x < w; x++) {
            var i = w * 4 * y + x * 4,
                t = P(x / w, y / h).closest(this.points);
            d.data[i+0] = t.r;
            d.data[i+1] = t.g;
            d.data[i+2] = t.b;
            d.data[i+3] = 255;
        }
    }
    c.putImageData(d, 0, 0);
    var _this = this;
    this.points.forEach(function(p) {
        var radius = 3;
        if (p === _this.selection) {
            radius *= 2;
        }
        c.fillStyle = p.isDark() ? '#fff' : '#000';
        c.beginPath();
        c.arc(p.x * w, p.y * h, radius, 0, Math.PI * 2, false);
        c.fill();
    });
    return this;
};
<|endoftext|>


<commit_before>import some from 'lodash/some'
import mergeWith from 'lodash/mergeWith'
import isFunction from 'lodash/isFunction'
import isUndefined from 'lodash/isUndefined'
import defaults from 'lodash/defaults'
import map from 'lodash/map'
import get from 'lodash/get'
import uniq from 'lodash/uniq'
import toPath from 'lodash/toPath'
import head from 'lodash/head'
import isPlainObject from 'lodash/isPlainObject'
import negateValue from './negateValue'
import * as corePlugins from '../plugins'
import configurePlugins from './configurePlugins'
import defaultConfig from '../../stubs/defaultConfig.stub'

const configUtils = {
  negative(scale) {
    return Object.keys(scale)
      .filter((key) => scale[key] !== '0')
      .reduce(
        (negativeScale, key) => ({
          ...negativeScale,
          [`-${key}`]: negateValue(scale[key]),
        }),
        {}
      )
  },
  breakpoints(screens) {
    return Object.keys(screens)
      .filter((key) => typeof screens[key] === 'string')
      .reduce(
        (breakpoints, key) => ({
          ...breakpoints,
          [`screen-${key}`]: screens[key],
        }),
        {}
      )
  },
}

function value(valueToResolve, ...args) {
  return isFunction(valueToResolve) ? valueToResolve(...args) : valueToResolve
}

function collectExtends(items) {
  return items.reduce((merged, { extend }) => {
    return mergeWith(merged, extend, (mergedValue, extendValue) => {
      if (isUndefined(mergedValue)) {
        return [extendValue]
      }

      if (Array.isArray(mergedValue)) {
        return [extendValue, ...mergedValue]
      }

      return [extendValue, mergedValue]
    })
  }, {})
}

function mergeThemes(themes) {
  return {
    ...themes.reduce((merged, theme) => defaults(merged, theme), {}),

    // In order to resolve n config objects, we combine all of their `extend` properties
    // into arrays instead of objects so they aren't overridden.
    extend: collectExtends(themes),
  }
}

function mergeExtensionCustomizer(merged, value) {
  // When we have an array of objects, we do want to merge it
  if (Array.isArray(merged) && isPlainObject(head(merged))) {
    return merged.concat(value)
  }

  // When the incoming value is an array, and the existing config is an object, prepend the existing object
  if (Array.isArray(value) && isPlainObject(head(value)) && isPlainObject(merged)) {
    return [merged, ...value]
  }

  // Override arrays (for example for font-families, box-shadows, ...)
  if (Array.isArray(value)) {
    return value
  }

  // Execute default behaviour
  return undefined
}

function mergeExtensions({ extend, ...theme }) {
  return mergeWith(theme, extend, (themeValue, extensions) => {
    // The `extend` property is an array, so we need to check if it contains any functions
    if (!isFunction(themeValue) && !some(extensions, isFunction)) {
      return mergeWith({}, themeValue, ...extensions, mergeExtensionCustomizer)
    }

    return (resolveThemePath, utils) =>
      mergeWith(
        {},
        ...[themeValue, ...extensions].map((e) => value(e, resolveThemePath, utils)),
        mergeExtensionCustomizer
      )
  })
}

function resolveFunctionKeys(object) {
  const resolvePath = (key, defaultValue) => {
    const path = toPath(key)

    let index = 0
    let val = object

    while (val !== undefined && val !== null && index < path.length) {
      val = val[path[index++]]
      val = isFunction(val) ? val(resolvePath, configUtils) : val
    }

    return val === undefined ? defaultValue : val
  }

  return Object.keys(object).reduce((resolved, key) => {
    return {
      ...resolved,
      [key]: isFunction(object[key]) ? object[key](resolvePath, configUtils) : object[key],
    }
  }, {})
}

function extractPluginConfigs(configs) {
  let allConfigs = []

  configs.forEach((config) => {
    allConfigs = [...allConfigs, config]

    const plugins = get(config, 'plugins', [])

    if (plugins.length === 0) {
      return
    }

    plugins.forEach((plugin) => {
      if (plugin.__isOptionsFunction) {
        plugin = plugin()
      }
      allConfigs = [...allConfigs, ...extractPluginConfigs([get(plugin, 'config', {})])]
    })
  })

  return allConfigs
}

function mergeVariants(variants) {
  const mergedVariants = variants.reduce((resolved, variants) => {
    Object.entries(variants || {}).forEach(([plugin, pluginVariants]) => {
      if (isFunction(pluginVariants)) {
        resolved[plugin] = pluginVariants({
          variants(path) {
            return get(resolved, path, [])
          },
          before(toInsert, variant, existingPluginVariants = get(resolved, plugin, [])) {
            if (variant === undefined) {
              return [...toInsert, ...existingPluginVariants]
            }

            const index = existingPluginVariants.indexOf(variant)

            if (index === -1) {
              return [...existingPluginVariants, ...toInsert]
            }

            return [
              ...existingPluginVariants.slice(0, index),
              ...toInsert,
              ...existingPluginVariants.slice(index),
            ]
          },
          after(toInsert, variant, existingPluginVariants = get(resolved, plugin, [])) {
            if (variant === undefined) {
              return [...existingPluginVariants, ...toInsert]
            }

            const index = existingPluginVariants.indexOf(variant)

            if (index === -1) {
              return [...toInsert, ...existingPluginVariants]
            }

            return [
              ...existingPluginVariants.slice(0, index + 1),
              ...toInsert,
              ...existingPluginVariants.slice(index + 1),
            ]
          },
          without(toRemove, existingPluginVariants = get(resolved, plugin, [])) {
            return existingPluginVariants.filter((v) => !toRemove.includes(v))
          },
        })
      } else {
        resolved[plugin] = pluginVariants
      }
    })

    return resolved
  }, {})

  return {
    ...mergedVariants,
    extend: collectExtends(variants),
  }
}

function mergeVariantExtensions({ extend, ...variants }, variantOrder) {
  return mergeWith(variants, extend, (variantsValue, extensions) => {
    const merged = uniq([...variantsValue, ...extensions].flat())

    if (extensions.flat().length === 0) {
      return merged
    }

    return merged.sort((a, z) => variantOrder.indexOf(a) - variantOrder.indexOf(z))
  })
}

function resolveVariants([firstConfig, ...variantConfigs], variantOrder) {
  // Global variants configuration like `variants: ['hover', 'focus']`
  if (Array.isArray(firstConfig)) {
    return firstConfig
  }

  return mergeVariantExtensions(
    mergeVariants([firstConfig, ...variantConfigs].reverse()),
    variantOrder
  )
}

function resolveCorePlugins(corePluginConfigs) {
  const result = [...corePluginConfigs].reduceRight((resolved, corePluginConfig) => {
    if (isFunction(corePluginConfig)) {
      return corePluginConfig({ corePlugins: resolved })
    }
    return configurePlugins(corePluginConfig, resolved)
  }, Object.keys(corePlugins))

  return result
}

function resolvePluginLists(pluginLists) {
  const result = [...pluginLists].reduceRight((resolved, pluginList) => {
    return [...resolved, ...pluginList]
  }, [])

  return result
}

export default function resolveConfig(configs) {
  const allConfigs = [
    ...extractPluginConfigs(configs),
    {
      darkMode: false,
      prefix: '',
      important: false,
      separator: ':',
      variantOrder: defaultConfig.variantOrder,
    },
  ]
  const { variantOrder } = allConfigs.find((c) => c.variantOrder)

  return defaults(
    {
      theme: resolveFunctionKeys(
        mergeExtensions(mergeThemes(map(allConfigs, (t) => get(t, 'theme', {}))))
      ),
      variants: resolveVariants(
        allConfigs.map((c) => get(c, 'variants', {})),
        variantOrder
      ),
      corePlugins: resolveCorePlugins(allConfigs.map((c) => c.corePlugins)),
      plugins: resolvePluginLists(configs.map((c) => get(c, 'plugins', []))),
    },
    ...allConfigs
  )
}
<commit_msg>Pass colors to theme closures<commit_after>import some from 'lodash/some'
import mergeWith from 'lodash/mergeWith'
import isFunction from 'lodash/isFunction'
import isUndefined from 'lodash/isUndefined'
import defaults from 'lodash/defaults'
import map from 'lodash/map'
import get from 'lodash/get'
import uniq from 'lodash/uniq'
import toPath from 'lodash/toPath'
import head from 'lodash/head'
import isPlainObject from 'lodash/isPlainObject'
import negateValue from './negateValue'
import * as corePlugins from '../plugins'
import configurePlugins from './configurePlugins'
import defaultConfig from '../../stubs/defaultConfig.stub'
import colors from '../../colors'

const configUtils = {
  colors,
  negative(scale) {
    return Object.keys(scale)
      .filter((key) => scale[key] !== '0')
      .reduce(
        (negativeScale, key) => ({
          ...negativeScale,
          [`-${key}`]: negateValue(scale[key]),
        }),
        {}
      )
  },
  breakpoints(screens) {
    return Object.keys(screens)
      .filter((key) => typeof screens[key] === 'string')
      .reduce(
        (breakpoints, key) => ({
          ...breakpoints,
          [`screen-${key}`]: screens[key],
        }),
        {}
      )
  },
}

function value(valueToResolve, ...args) {
  return isFunction(valueToResolve) ? valueToResolve(...args) : valueToResolve
}

function collectExtends(items) {
  return items.reduce((merged, { extend }) => {
    return mergeWith(merged, extend, (mergedValue, extendValue) => {
      if (isUndefined(mergedValue)) {
        return [extendValue]
      }

      if (Array.isArray(mergedValue)) {
        return [extendValue, ...mergedValue]
      }

      return [extendValue, mergedValue]
    })
  }, {})
}

function mergeThemes(themes) {
  return {
    ...themes.reduce((merged, theme) => defaults(merged, theme), {}),

    // In order to resolve n config objects, we combine all of their `extend` properties
    // into arrays instead of objects so they aren't overridden.
    extend: collectExtends(themes),
  }
}

function mergeExtensionCustomizer(merged, value) {
  // When we have an array of objects, we do want to merge it
  if (Array.isArray(merged) && isPlainObject(head(merged))) {
    return merged.concat(value)
  }

  // When the incoming value is an array, and the existing config is an object, prepend the existing object
  if (Array.isArray(value) && isPlainObject(head(value)) && isPlainObject(merged)) {
    return [merged, ...value]
  }

  // Override arrays (for example for font-families, box-shadows, ...)
  if (Array.isArray(value)) {
    return value
  }

  // Execute default behaviour
  return undefined
}

function mergeExtensions({ extend, ...theme }) {
  return mergeWith(theme, extend, (themeValue, extensions) => {
    // The `extend` property is an array, so we need to check if it contains any functions
    if (!isFunction(themeValue) && !some(extensions, isFunction)) {
      return mergeWith({}, themeValue, ...extensions, mergeExtensionCustomizer)
    }

    return (resolveThemePath, utils) =>
      mergeWith(
        {},
        ...[themeValue, ...extensions].map((e) => value(e, resolveThemePath, utils)),
        mergeExtensionCustomizer
      )
  })
}

function resolveFunctionKeys(object) {
  const resolvePath = (key, defaultValue) => {
    const path = toPath(key)

    let index = 0
    let val = object

    while (val !== undefined && val !== null && index < path.length) {
      val = val[path[index++]]
      val = isFunction(val) ? val(resolvePath, configUtils) : val
    }

    return val === undefined ? defaultValue : val
  }

  return Object.keys(object).reduce((resolved, key) => {
    return {
      ...resolved,
      [key]: isFunction(object[key]) ? object[key](resolvePath, configUtils) : object[key],
    }
  }, {})
}

function extractPluginConfigs(configs) {
  let allConfigs = []

  configs.forEach((config) => {
    allConfigs = [...allConfigs, config]

    const plugins = get(config, 'plugins', [])

    if (plugins.length === 0) {
      return
    }

    plugins.forEach((plugin) => {
      if (plugin.__isOptionsFunction) {
        plugin = plugin()
      }
      allConfigs = [...allConfigs, ...extractPluginConfigs([get(plugin, 'config', {})])]
    })
  })

  return allConfigs
}

function mergeVariants(variants) {
  const mergedVariants = variants.reduce((resolved, variants) => {
    Object.entries(variants || {}).forEach(([plugin, pluginVariants]) => {
      if (isFunction(pluginVariants)) {
        resolved[plugin] = pluginVariants({
          variants(path) {
            return get(resolved, path, [])
          },
          before(toInsert, variant, existingPluginVariants = get(resolved, plugin, [])) {
            if (variant === undefined) {
              return [...toInsert, ...existingPluginVariants]
            }

            const index = existingPluginVariants.indexOf(variant)

            if (index === -1) {
              return [...existingPluginVariants, ...toInsert]
            }

            return [
              ...existingPluginVariants.slice(0, index),
              ...toInsert,
              ...existingPluginVariants.slice(index),
            ]
          },
          after(toInsert, variant, existingPluginVariants = get(resolved, plugin, [])) {
            if (variant === undefined) {
              return [...existingPluginVariants, ...toInsert]
            }

            const index = existingPluginVariants.indexOf(variant)

            if (index === -1) {
              return [...toInsert, ...existingPluginVariants]
            }

            return [
              ...existingPluginVariants.slice(0, index + 1),
              ...toInsert,
              ...existingPluginVariants.slice(index + 1),
            ]
          },
          without(toRemove, existingPluginVariants = get(resolved, plugin, [])) {
            return existingPluginVariants.filter((v) => !toRemove.includes(v))
          },
        })
      } else {
        resolved[plugin] = pluginVariants
      }
    })

    return resolved
  }, {})

  return {
    ...mergedVariants,
    extend: collectExtends(variants),
  }
}

function mergeVariantExtensions({ extend, ...variants }, variantOrder) {
  return mergeWith(variants, extend, (variantsValue, extensions) => {
    const merged = uniq([...variantsValue, ...extensions].flat())

    if (extensions.flat().length === 0) {
      return merged
    }

    return merged.sort((a, z) => variantOrder.indexOf(a) - variantOrder.indexOf(z))
  })
}

function resolveVariants([firstConfig, ...variantConfigs], variantOrder) {
  // Global variants configuration like `variants: ['hover', 'focus']`
  if (Array.isArray(firstConfig)) {
    return firstConfig
  }

  return mergeVariantExtensions(
    mergeVariants([firstConfig, ...variantConfigs].reverse()),
    variantOrder
  )
}

function resolveCorePlugins(corePluginConfigs) {
  const result = [...corePluginConfigs].reduceRight((resolved, corePluginConfig) => {
    if (isFunction(corePluginConfig)) {
      return corePluginConfig({ corePlugins: resolved })
    }
    return configurePlugins(corePluginConfig, resolved)
  }, Object.keys(corePlugins))

  return result
}

function resolvePluginLists(pluginLists) {
  const result = [...pluginLists].reduceRight((resolved, pluginList) => {
    return [...resolved, ...pluginList]
  }, [])

  return result
}

export default function resolveConfig(configs) {
  const allConfigs = [
    ...extractPluginConfigs(configs),
    {
      darkMode: false,
      prefix: '',
      important: false,
      separator: ':',
      variantOrder: defaultConfig.variantOrder,
    },
  ]
  const { variantOrder } = allConfigs.find((c) => c.variantOrder)

  return defaults(
    {
      theme: resolveFunctionKeys(
        mergeExtensions(mergeThemes(map(allConfigs, (t) => get(t, 'theme', {}))))
      ),
      variants: resolveVariants(
        allConfigs.map((c) => get(c, 'variants', {})),
        variantOrder
      ),
      corePlugins: resolveCorePlugins(allConfigs.map((c) => c.corePlugins)),
      plugins: resolvePluginLists(configs.map((c) => get(c, 'plugins', []))),
    },
    ...allConfigs
  )
}
<|endoftext|>


<commit_before>var eecQaPlugin = {};

eecQaPlugin.getControlValue = function(controlId) {
  return $('#' + cw.LayoutManagers.WOGeneral.Controls.get(controlId)).val();
};

eecQaPlugin.callApi = function(service, method, parameters, callback) {
  var url = eecQaPlugin.application + '/services/AMS/' + service + '/' + method;
  var data = { data: JSON.stringify(parameters) };
  if (!(service == 'Authentication' && method == 'Authenticate')) {
    data.token = eecQaPlugin.token['Token'];
  }
  $.post(url, data, function(response) {
    if (response['Status'] == 0) {
      if (typeof callback === 'function') { callback(response['Value']); }
    } else if (response['Status'] == 1) {
      alert('Error calling Cityworks API.  ' + response['Message']);
      if (typeof callback === 'function') { callback(); }
    } else if (response['Status'] == 2) {
      //TODO: Re-Authenticate?  Throw unauthorized error?  Does this happen when they just don't have permissions too?
    }
  });
};

eecQaPlugin.getStatusLabel = function(test) {
  var label;
  if (test.total > 0) {
    label = test.complete + ' / ' + test.total;
  } else {
    if (test.status == 'pass') {
      label = '\u2611';
    } else {
      label = '\u2610';
    }
  }
  return label;
};

eecQaPlugin.updateTestView = function(testName) {
  var test = eecQaPlugin.tests[testName];
  var statusView = $(eecQaPlugin.selector + ' #eec-qa-test-' + testName + ' label.eec-qa-status');
  statusView.text(eecQaPlugin.getStatusLabel(test));
  if (test.status == 'pass') {
    statusView
      .addClass('eec-qa-status-pass')
      .removeClass('eec-qa-status-fail')
    ;
  } else {
    statusView
      .addClass('eec-qa-status-fail')
      .removeClass('eec-qa-status-pass')
    ;
  }
};

eecQaPlugin.setTestResults = function(testName, status, complete, total) {
  var test = eecQaPlugin.tests[testName];
  test.status = status;
  test.complete = complete;
  test.total = total;
  eecQaPlugin.updateTestView(testName);
};

eecQaPlugin.tests = {
  tasks: {
    description: 'Tasks Complete',
    update: function() {
      //TODO: Is this going to run async?
      eecQaPlugin.callApi('Tasks', 'ByWorkOrder', {WorkOrderIds: [eecQaPlugin.workOrderId]}, function(data) {
        var status = '';
        var complete = 0;
        var total = data.length;
        for (var i= 0; i<total; i++) {
          var task = data[i];
          if (task['Status'] == 'COMPLETE') { complete++; }
        }
        if (complete == total) {
          status = 'pass'
        } else {
          status = 'fail'
        }
        eecQaPlugin.setTestResults('tasks', status, complete, total);
      });
    }
  },
  inspections: {
    description: 'Inspections Complete',
    update: function() {}
  },
  customFields: {
    description: 'Required Custom Fields Filled In',
    update: function() {}
  },
  requiredFields: {
    description: 'Other Required Fields Filled In',
    update: function() {}
  },
  labor: {
    description: 'Labor Entered',
    update: function() {}
  },
  equipment: {
    description: 'Equipment Entered',
    update: function() {}
  },
  materials: {
    description: 'Materials Entered',
    update: function() {}
  }
};

eecQaPlugin.update = function(tests) {

  if (typeof tests === 'string') { tests = [tests]; }

  var updateTestByName = function(test) {
    eecQaPlugin.tests[test].update();
  };

  if (tests == undefined || tests == null) {
    // Nothing specified.  Update all.
    for (var test in eecQaPlugin.tests) {
      if (eecQaPlugin.tests.hasOwnProperty(test)) {
        updateTestByName(test);
      }
    }
  } else {
    // Tests specified.  Update by name.
    for (var i=0; i<tests.length; i++) {
      if (eecQaPlugin.tests.hasOwnProperty(tests[i])) {
        updateTestByName(tests[i]);
      }
    }
  }
  //TODO: Callback?
};

eecQaPlugin.init = function(params) {

  var authenticate = function(callback) {

    var authWithServer = function(callback) {
      eecQaPlugin.callApi('Authentication', 'Authenticate', eecQaPlugin['credentials'], function(data) {
        eecQaPlugin.token = data['Value'];
        localStorage.setItem('eec-qa-token', JSON.stringify(eecQaPlugin.token));
        if (typeof callback === 'function') { callback(); }
      });
    };

    var tokenSave = localStorage.getItem('eec-qa-token');
    if (tokenSave == null) {
      authWithServer(callback);
    } else {
      var token = JSON.parse();  //TODO: Check token with Authentication/Validate service
      if (token['Expires'] < new Date()) {  //TODO: Timezone check
        authWithServer(callback);
      } else {
        eecQaPlugin.token = token;
        if (typeof callback === 'function') { callback(); }
      }
    }
  };

  var build = function() {

    for (var testName in eecQaPlugin.tests) {
      if (eecQaPlugin.tests.hasOwnProperty(testName)) {
        var test = eecQaPlugin.tests[testName];
        $(eecQaPlugin.selector)
          .append($('
')
            .append($('')
              .text(eecQaPlugin.getStatusLabel(test))
            )
            .append($('
')
              .text(test.description)
            )
          )
        ;
      }
    }

    eecQaPlugin.update('tasks'); //TODO: Update all
  };

  eecQaPlugin.application = params['application'];
  eecQaPlugin.credentials = params['credentials'];
  eecQaPlugin.selector = params['selector'];
  eecQaPlugin.workOrderId = eecQaPlugin.getControlValue('cboWorkOrderId');

  authenticate(build);

};
<commit_msg>Developing...<commit_after>var eecQaPlugin = {};

eecQaPlugin.getControlValue = function(controlId) {
  return $('#' + cw.LayoutManagers.WOGeneral.Controls.get(controlId)).val();
};

eecQaPlugin.callApi = function(service, method, parameters, callback) {
  var url = eecQaPlugin.application + '/services/AMS/' + service + '/' + method;
  var data = { data: JSON.stringify(parameters) };
  if (!(service == 'Authentication' && method == 'Authenticate')) {
    data.token = eecQaPlugin.token['Token'];
  }
  $.post(url, data, function(response) {
    if (response['Status'] == 0) {
      if (typeof callback === 'function') { callback(response['Value']); }
    } else if (response['Status'] == 1) {
      alert('Error calling Cityworks API.  ' + response['Message']);
      if (typeof callback === 'function') { callback(); }
    } else if (response['Status'] == 2) {
      //TODO: Re-Authenticate?  Throw unauthorized error?  Does this happen when they just don't have permissions too?
    }
  });
};

eecQaPlugin.getStatusLabel = function(test) {
  var label;
  if (test.total > 0) {
    label = test.complete + ' / ' + test.total;
  } else {
    if (test.status == 'pass') {
      label = '\u2611';
    } else {
      label = '\u2610';
    }
  }
  return label;
};

eecQaPlugin.updateTestView = function(testName) {
  var test = eecQaPlugin.tests[testName];
  var statusView = $(eecQaPlugin.selector + ' #eec-qa-test-' + testName + ' label.eec-qa-status');
  statusView.text(eecQaPlugin.getStatusLabel(test));
  if (test.status == 'pass') {
    statusView
      .addClass('eec-qa-status-pass')
      .removeClass('eec-qa-status-fail')
    ;
  } else {
    statusView
      .addClass('eec-qa-status-fail')
      .removeClass('eec-qa-status-pass')
    ;
  }
};

eecQaPlugin.setTestResults = function(testName, status, complete, total) {
  var test = eecQaPlugin.tests[testName];
  test.status = status;
  test.complete = complete;
  test.total = total;
  eecQaPlugin.updateTestView(testName);
};

eecQaPlugin.tests = {
  tasks: {
    description: 'Tasks Complete',
    update: function() {
      //TODO: Is this going to run async?
      eecQaPlugin.callApi('Tasks', 'ByWorkOrder', {WorkOrderIds: [eecQaPlugin.workOrderId]}, function(data) {
        var status = '';
        var complete = 0;
        var total = data.length;
        for (var i= 0; i<total; i++) {
          var task = data[i];
          if (task['Status'] == 'COMPLETE') { complete++; }
        }
        if (complete == total) {
          status = 'pass'
        } else {
          status = 'fail'
        }
        eecQaPlugin.setTestResults('tasks', status, complete, total);
      });
    }
  },
  inspections: {
    description: 'Inspections Complete',
    update: function() {}
  },
  customFields: {
    description: 'Required Custom Fields Filled In',
    update: function() {}
  },
  requiredFields: {
    description: 'Other Required Fields Filled In',
    update: function() {}
  },
  labor: {
    description: 'Labor Entered',
    update: function() {}
  },
  equipment: {
    description: 'Equipment Entered',
    update: function() {}
  },
  materials: {
    description: 'Materials Entered',
    update: function() {}
  }
};

eecQaPlugin.update = function(tests) {

  if (typeof tests === 'string') { tests = [tests]; }

  var updateTestByName = function(test) {
    eecQaPlugin.tests[test].update();
  };

  if (tests == undefined || tests == null) {
    // Nothing specified.  Update all.
    for (var test in eecQaPlugin.tests) {
      if (eecQaPlugin.tests.hasOwnProperty(test)) {
        updateTestByName(test);
      }
    }
  } else {
    // Tests specified.  Update by name.
    for (var i=0; i<tests.length; i++) {
      if (eecQaPlugin.tests.hasOwnProperty(tests[i])) {
        updateTestByName(tests[i]);
      }
    }
  }
  //TODO: Callback?
};

eecQaPlugin.init = function(params) {

  var authenticate = function(callback) {

    var authWithServer = function(callback) {
      eecQaPlugin.callApi('Authentication', 'Authenticate', eecQaPlugin['credentials'], function(data) {
        eecQaPlugin.token = data;
        localStorage.setItem('eec-qa-token', JSON.stringify(eecQaPlugin.token));
        if (typeof callback === 'function') { callback(); }
      });
    };

    var tokenSave = localStorage.getItem('eec-qa-token');
    if (tokenSave == null) {
      authWithServer(callback);
    } else {
      var token = JSON.parse();  //TODO: Check token with Authentication/Validate service
      if (token['Expires'] < new Date()) {  //TODO: Timezone check
        authWithServer(callback);
      } else {
        eecQaPlugin.token = token;
        if (typeof callback === 'function') { callback(); }
      }
    }
  };

  var build = function() {

    for (var testName in eecQaPlugin.tests) {
      if (eecQaPlugin.tests.hasOwnProperty(testName)) {
        var test = eecQaPlugin.tests[testName];
        $(eecQaPlugin.selector)
          .append($('
')
            .append($('')
              .text(eecQaPlugin.getStatusLabel(test))
            )
            .append($('
')
              .text(test.description)
            )
          )
        ;
      }
    }

    eecQaPlugin.update('tasks'); //TODO: Update all
  };

  eecQaPlugin.application = params['application'];
  eecQaPlugin.credentials = params['credentials'];
  eecQaPlugin.selector = params['selector'];
  eecQaPlugin.workOrderId = eecQaPlugin.getControlValue('cboWorkOrderId');

  authenticate(build);

};
<|endoftext|>


<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.XHRLoader = function ( manager ) {

	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;

};

THREE.XHRLoader.prototype = {

	constructor: THREE.XHRLoader,

	load: function ( url, onLoad, onProgress, onError ) {

		var scope = this;

		var cached = THREE.Cache.get( url );

		if ( cached !== undefined ) {

			if ( onLoad ) onLoad( cached );
			return cached;

		}

		var request = new XMLHttpRequest();
		request.open( 'GET', url, true );

		request.addEventListener( 'load', function ( event ) {

			THREE.Cache.add( url, this.response );

			if ( onLoad ) onLoad( this.response );

			scope.manager.itemEnd( url );

		}, false );

		if ( onProgress !== undefined ) {

			request.addEventListener( 'progress', function ( event ) {

				onProgress( event );

			}, false );

		}

		if ( onError !== undefined ) {

			request.addEventListener( 'error', function ( event ) {

				onError( event );

			}, false );

		}

		if ( this.crossOrigin !== undefined ) request.crossOrigin = this.crossOrigin;
		if ( this.responseType !== undefined ) request.responseType = this.responseType;

		request.send( null );

		scope.manager.itemStart( url );

	},

	setResponseType: function ( value ) {

		this.responseType = value;

	},

	setCrossOrigin: function ( value ) {

		this.crossOrigin = value;

	}

};
<commit_msg>return http request on load #6641<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.XHRLoader = function ( manager ) {

	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;

};

THREE.XHRLoader.prototype = {

	constructor: THREE.XHRLoader,

	load: function ( url, onLoad, onProgress, onError ) {

		var scope = this;

		var cached = THREE.Cache.get( url );

		if ( cached !== undefined ) {

			if ( onLoad ) onLoad( cached );
			return cached;

		}

		var request = new XMLHttpRequest();
		request.open( 'GET', url, true );

		request.addEventListener( 'load', function ( event ) {

			THREE.Cache.add( url, this.response );

			if ( onLoad ) onLoad( this.response );

			scope.manager.itemEnd( url );

		}, false );

		if ( onProgress !== undefined ) {

			request.addEventListener( 'progress', function ( event ) {

				onProgress( event );

			}, false );

		}

		if ( onError !== undefined ) {

			request.addEventListener( 'error', function ( event ) {

				onError( event );

			}, false );

		}

		if ( this.crossOrigin !== undefined ) request.crossOrigin = this.crossOrigin;
		if ( this.responseType !== undefined ) request.responseType = this.responseType;

		request.send( null );

		scope.manager.itemStart( url );

		return request;

	},

	setResponseType: function ( value ) {

		this.responseType = value;

	},

	setCrossOrigin: function ( value ) {

		this.crossOrigin = value;

	}

};
<|endoftext|>


<commit_before>export default {
  el: {
    colorpicker: {
      confirm: 'Confirmar',
      clear: 'Limpar'
    },
    datepicker: {
      now: 'Agora',
      today: 'Hoje',
      cancel: 'Cancelar',
      clear: 'Limpar',
      confirm: 'Confirmar',
      selectDate: 'Selecione a data',
      selectTime: 'Selecione a hora',
      startDate: 'Data inicial',
      startTime: 'Hora inicial',
      endDate: 'Data final',
      endTime: 'Hora final',
      prevYear: 'Ano anterior',
      nextYear: 'Próximo ano',
      prevMonth: 'Mês anterior',
      nextMonth: 'Próximo mês',
      year: '',
      month1: 'Janeiro',
      month2: 'Fevereiro',
      month3: 'Março',
      month4: 'Abril',
      month5: 'Maio',
      month6: 'Junho',
      month7: 'Julho',
      month8: 'Agosto',
      month9: 'Setembro',
      month10: 'Outubro',
      month11: 'Novembro',
      month12: 'Dezembro',
      // week: 'semana',
      weeks: {
        sun: 'Dom',
        mon: 'Seg',
        tue: 'Ter',
        wed: 'Qua',
        thu: 'Qui',
        fri: 'Sex',
        sat: 'Sab'
      },
      months: {
        jan: 'Jan',
        feb: 'Fev',
        mar: 'Mar',
        apr: 'Abr',
        may: 'Mai',
        jun: 'Jun',
        jul: 'Jul',
        aug: 'Ago',
        sep: 'Set',
        oct: 'Out',
        nov: 'Nov',
        dec: 'Dez'
      }
    },
    select: {
      loading: 'Carregando',
      noMatch: 'Sem resultados',
      noData: 'Sem dados',
      placeholder: 'Selecione'
    },
    cascader: {
      noMatch: 'Sem resultados',
      loading: 'Carregando',
      placeholder: 'Selecione',
      noData: 'Sem dados'
    },
    pagination: {
      goto: 'Ir para',
      pagesize: '/página',
      total: 'Total {total}',
      pageClassifier: ''
    },
    messagebox: {
      title: 'Mensagem',
      confirm: 'Confirmar',
      cancel: 'Cancelar',
      error: 'Erro!'
    },
    upload: {
      deleteTip: 'aperte delete para apagar',
      delete: 'Apagar',
      preview: 'Pré-visualizar',
      continue: 'Continuar'
    },
    table: {
      emptyText: 'Sem dados',
      confirmFilter: 'Confirmar',
      resetFilter: 'Limpar',
      clearFilter: 'Todos',
      sumText: 'Total'
    },
    tree: {
      emptyText: 'Sem dados'
    },
    transfer: {
      noMatch: 'Sem resultados',
      noData: 'Sem dados',
      titles: ['Lista 1', 'Lista 2'],
      filterPlaceholder: 'Digite uma palavra-chave',
      noCheckedFormat: '{total} itens',
      hasCheckedFormat: '{checked}/{total} selecionados'
    },
    image: {
      error: 'FAILED' // to be translated
    },
    pageHeader: {
      title: 'Back' // to be translated
    }
  }
};
<commit_msg>Update pt-br.js (#15776)<commit_after>export default {
  el: {
    colorpicker: {
      confirm: 'Confirmar',
      clear: 'Limpar'
    },
    datepicker: {
      now: 'Agora',
      today: 'Hoje',
      cancel: 'Cancelar',
      clear: 'Limpar',
      confirm: 'Confirmar',
      selectDate: 'Selecione a data',
      selectTime: 'Selecione a hora',
      startDate: 'Data inicial',
      startTime: 'Hora inicial',
      endDate: 'Data final',
      endTime: 'Hora final',
      prevYear: 'Ano anterior',
      nextYear: 'Próximo ano',
      prevMonth: 'Mês anterior',
      nextMonth: 'Próximo mês',
      year: '',
      month1: 'Janeiro',
      month2: 'Fevereiro',
      month3: 'Março',
      month4: 'Abril',
      month5: 'Maio',
      month6: 'Junho',
      month7: 'Julho',
      month8: 'Agosto',
      month9: 'Setembro',
      month10: 'Outubro',
      month11: 'Novembro',
      month12: 'Dezembro',
      // week: 'semana',
      weeks: {
        sun: 'Dom',
        mon: 'Seg',
        tue: 'Ter',
        wed: 'Qua',
        thu: 'Qui',
        fri: 'Sex',
        sat: 'Sab'
      },
      months: {
        jan: 'Jan',
        feb: 'Fev',
        mar: 'Mar',
        apr: 'Abr',
        may: 'Mai',
        jun: 'Jun',
        jul: 'Jul',
        aug: 'Ago',
        sep: 'Set',
        oct: 'Out',
        nov: 'Nov',
        dec: 'Dez'
      }
    },
    select: {
      loading: 'Carregando',
      noMatch: 'Sem resultados',
      noData: 'Sem dados',
      placeholder: 'Selecione'
    },
    cascader: {
      noMatch: 'Sem resultados',
      loading: 'Carregando',
      placeholder: 'Selecione',
      noData: 'Sem dados'
    },
    pagination: {
      goto: 'Ir para',
      pagesize: '/página',
      total: 'Total {total}',
      pageClassifier: ''
    },
    messagebox: {
      title: 'Mensagem',
      confirm: 'Confirmar',
      cancel: 'Cancelar',
      error: 'Erro!'
    },
    upload: {
      deleteTip: 'aperte delete para apagar',
      delete: 'Apagar',
      preview: 'Pré-visualizar',
      continue: 'Continuar'
    },
    table: {
      emptyText: 'Sem dados',
      confirmFilter: 'Confirmar',
      resetFilter: 'Limpar',
      clearFilter: 'Todos',
      sumText: 'Total'
    },
    tree: {
      emptyText: 'Sem dados'
    },
    transfer: {
      noMatch: 'Sem resultados',
      noData: 'Sem dados',
      titles: ['Lista 1', 'Lista 2'],
      filterPlaceholder: 'Digite uma palavra-chave',
      noCheckedFormat: '{total} itens',
      hasCheckedFormat: '{checked}/{total} selecionados'
    },
    image: {
      error: 'Erro ao carregar imagem'
    },
    pageHeader: {
      title: 'Voltar'
    }
  }
};
<|endoftext|>


<commit_before>(function(mw, $) {
	$(function() {
		api = new mw.Api();
		$('a.embedvideo-evl').click(function(e){
			e.preventDefault();

			var data = $(this).data('video-json');
			data['action'] = 'embedvideo';
			if (typeof data['player'] === 'undefined') {
				data['player'] = 'default';
			}
			var player = data['player'];
			var container = $('#vplayerbox-'+player);
			if (!container.length) {
				mw.debug('No matching vplayer tag found for this link!');
				return;
			}
			// modify dimensions call to match container size if exists.
			if (container.data('size')) {
				data['dimensions'] = container.data('size');
			}
			api.get( data )
			.done( function( res ) {
				if (typeof res.embedvideo.html !== 'undefined') {
					content = res.embedvideo.html;
				} else {
					content = "There was an error while loading this video";
				}
				if (data.notice) {
					content = content + "" + data.notice + "";
				}
				container.html(content);
			} );
		});
    });
}(mediaWiki, jQuery));
<commit_msg>use mw.log.error instead of mw.debug<commit_after>(function(mw, $) {
	$(function() {
		api = new mw.Api();
		$('a.embedvideo-evl').click(function(e){
			e.preventDefault();

			var data = $(this).data('video-json');
			data['action'] = 'embedvideo';
			if (typeof data['player'] === 'undefined') {
				data['player'] = 'default';
			}
			var player = data['player'];
			var container = $('#vplayerbox-'+player);
			if (!container.length) {
				mw.log.error('No matching vplayer tag found for this link!');
				return;
			}
			// modify dimensions call to match container size if exists.
			if (container.data('size')) {
				data['dimensions'] = container.data('size');
			}
			api.get( data )
			.done( function( res ) {
				if (typeof res.embedvideo.html !== 'undefined') {
					content = res.embedvideo.html;
				} else {
					content = "There was an error while loading this video";
				}
				if (data.notice) {
					content = content + "" + data.notice + "";
				}
				container.html(content);
			} );
		});
    });
}(mediaWiki, jQuery));
<|endoftext|>


<commit_before>window.addEventListener("load", monospaceInit, false);
var messangerwindow = document.getElementById("webMessengerRecentMessages");
function monospaceInit(evt) {
    detect(evt);
    messangerwindow.addEventListener('DOMNodeInserted', detect, false);
}

function detect(evt) {

    console.log("hello");
    //characters for codeblock
    var start = "`~ ";
    var stop = " ~`";

    //main chat only. small chat splits lines into seperate elements...
    var chat = messangerwindow.getElementsByClassName("_38"); //what is the exact meanning of _38???
    for (i = 0; i < chat.length; i++) {
        text = chat[i].getElementsByTagName("p")[0];
        // console.log( text );
        words = chat[i].innerText;
        // console.log(words + "contains lol? : " + words.indexOf( "lol" ) );
        var stop_index = words.indexOf(stop);
        var start_index = words.indexOf(start);
        if (stop_index > start_index && start_index > -1) {
            text.className += " code";
            text.innerText = words.substr(start_index + 3, stop_index - start_index - 3);
        }
    }
}
<commit_msg>remove hello log<commit_after>window.addEventListener("load", monospaceInit, false);
var messangerwindow = document.getElementById("webMessengerRecentMessages");
function monospaceInit(evt) {
    detect(evt);
    messangerwindow.addEventListener('DOMNodeInserted', detect, false);
}

function detect(evt) {

    console.log("bye");
    //characters for codeblock
    var start = "`~ ";
    var stop = " ~`";

    //main chat only. small chat splits lines into seperate elements...
    var chat = messangerwindow.getElementsByClassName("_38"); //what is the exact meanning of _38???
    for (i = 0; i < chat.length; i++) {
        text = chat[i].getElementsByTagName("p")[0];
        // console.log( text );
        words = chat[i].innerText;
        // console.log(words + "contains lol? : " + words.indexOf( "lol" ) );
        var stop_index = words.indexOf(stop);
        var start_index = words.indexOf(start);
        if (stop_index > start_index && start_index > -1) {
            text.className += " code";
            text.innerText = words.substr(start_index + 3, stop_index - start_index - 3);
        }
    }
}
<|endoftext|>


<commit_before>async function getRules() {
  const {rules} = await browser.storage.sync.get({rules: []})
  return rules
}

const ports = new Map()
browser.runtime.onConnect.addListener(async port => {
  ports.set(port.name, port)
  port.onDisconnect.addListener(() => ports.delete(port.name))

  port.postMessage(await getRules())
})

browser.storage.onChanged.addListener(({rules}, area) => {
  if (!rules || area != 'sync') {
    return
  }

  for (const port of ports.values()) {
    port.postMessage(rules.newValue)
  }
})

async function listRules() {
  const rules = await getRules()
  console.log('rules:')
  console.log(rules.map(r => JSON.stringify(r)).join('\n'))
}

async function addRule(rule) {
  const rules = await getRules()
  if (rules.includes(rule)) {
    console.log('rule already exists')
  } else {
    rules.push(rule)
    await browser.storage.sync.set({rules})
  }
  listRules()
}

async function removeRule(rule) {
  const rules = await getRules()
  const i = rules.indexOf(rule)
  if (i >= 0) {
    rules.splice(i, 1)
    await browser.storage.sync.set({rules})
  } else {
    console.log('rule not found')
  }
  listRules()
}

;[listRules, addRule, removeRule].map(f => {
  window[f.name] = (...args) => {
    f(...args)
  }
})
<commit_msg>Normalize new rules<commit_after>async function getRules() {
  const {rules} = await browser.storage.sync.get({rules: []})
  return rules
}

const ports = new Map()
browser.runtime.onConnect.addListener(async port => {
  ports.set(port.name, port)
  port.onDisconnect.addListener(() => ports.delete(port.name))

  port.postMessage(await getRules())
})

browser.storage.onChanged.addListener(({rules}, area) => {
  if (!rules || area != 'sync') {
    return
  }

  for (const port of ports.values()) {
    port.postMessage(rules.newValue)
  }
})

async function listRules() {
  const rules = await getRules()
  console.log('rules:')
  console.log(rules.map(r => JSON.stringify(r)).join('\n'))
}

async function addRule(rule) {
  rule = rule.replace(/^(?:https?:\/\/)?(?:www\d*\.)?/, '')
  const rules = await getRules()
  if (rules.includes(rule)) {
    console.log('rule already exists')
  } else {
    rules.push(rule)
    await browser.storage.sync.set({rules})
  }
  listRules()
}

async function removeRule(rule) {
  const rules = await getRules()
  const i = rules.indexOf(rule)
  if (i >= 0) {
    rules.splice(i, 1)
    await browser.storage.sync.set({rules})
  } else {
    console.log('rule not found')
  }
  listRules()
}

;[listRules, addRule, removeRule].map(f => {
  window[f.name] = (...args) => {
    f(...args)
  }
})
<|endoftext|>


<commit_before>var rootAPIURL = "https://api.psd401.net/v1";
var screwIE=Math.floor(Math.random()*100001);

var populateRSSFeeds = {
    init: function() {
        populateRSSFeeds.loadWebsiteRSSData();
        populateRSSFeeds.loadTechblogRSSData();
        populateRSSFeeds.loadSupRSSData();
        console.log("Should be done loading RSS");
    },
    loadWebsiteRSSData: function() {
        //console.log($("#websiteRSS-container").rss("https://psd401.net/index.php?format=feed&type=rss"));
        $("#websiteRSS-container").rss("https://psd401.net/index.php?format=feed&type=rss",
            {
                limit: 2,
                layoutTemplate: "{entries}",
                entryTemplate: '
{title} {shortBody}

{date}
',
                effect: 'slideFastSynced',
                dateFormat: 'MMMM Do, YYYY',
                error: function(){
                    console.log("There was an error");
                },
            }
        );
    },

    loadTechblogRSSData: function() {
        //console.log($("#techblogRSS-container").rss("http://techblog.psd401.net/?feed=rss2"));
        $("#techblogRSS-container").rss("http://techblog.psd401.net/?feed=rss2",{
                limit: 2,
                layoutTemplate: "{entries}",
                entryTemplate: '
{title} {shortBody}

{date}
',
                effect: 'slideFastSynced',
                dateFormat: 'MMMM Do, YYYY',
                error: function(){
                    console.log("There was an error");
                }
            }
        );
    },

    loadSupRSSData: function() {
         //console.log($("#supRSS-container").rss("https://script.google.com/a/macros/krishagel.com/s/AKfycbxIvJLmswNQRctRQ3UrQqwad_1sOx_SIH5VrSugxXYU-ot2hsc/exec?action=timeline&q=psdsup"));
        $("#supRSS-container").rss("https://script.google.com/a/macros/krishagel.com/s/AKfycbxIvJLmswNQRctRQ3UrQqwad_1sOx_SIH5VrSugxXYU-ot2hsc/exec?action=timeline&q=psdsup",
            {
                limit: 2,
                layoutTemplate: "{entries}",
                entryTemplate: '
{title}

{date}
',
                dateFormat: 'MMMM Do, YYYY',
                effect: 'slideFastSynced',
                error: function(){
                    console.log("There was an error");
                }
            }
        );
    }
}

$(document).ready(function(){
	//populateRSSFeeds.init();
    $('[data-toggle="tooltip"]').tooltip();

    setTimeout(function(){
        $('.psd-login-submit').tooltip('show');
        $('.psd-login-forgot').tooltip('show');
    }, 1200);

    setTimeout(function(){
        $('.psd-login-submit').tooltip('hide');
        $('.psd-login-forgot').tooltip('hide');
    }, 7000);

    $('.psd-login-submit').click(function(){
      stripEmail();
      $('form[name=login]').submit();
    });

    $(".psd-login-form-input").keypress(function(event){
        if(event.which == 13){
            $(".psd-login-form-input-password").focus();
        }
    });

    $(".psd-login-form-input-password").keypress(function(event) {
        if (event.which == 13) {
            event.preventDefault();
            stripEmail();
            $("form[name=login]").submit();
        }
    });

    if($(".logout-success").length > 0) {
        var timer = 10;
        setInterval(function(){
            $(".logout-success").html("Login " + timer);
            if(timer == 0){
                window.location.href = "/login?service=http%3A%2F%2Fmy.psd401.net"
            }
            timer --;
        }, 1000);
    }

    capsLock.observe(function (status) {
        if(status){
            $(".psd-login-form-input-password").tooltip("show");
        } else {
            $(".psd-login-form-input-password").tooltip("hide");
        }
    });
});

function stripEmail(){
    var username = $('.psd-login-form-input').val();
    username = username.toLowerCase().replace(/ /g, '');
    if (username.indexOf("@") != -1) {
        username = username.substring(0, username.indexOf('@'));
    }
    $('.psd-login-form-input').val(username);
}<commit_msg>Update cas.js<commit_after>var rootAPIURL = "https://api.psd401.net/v1";
var screwIE=Math.floor(Math.random()*100001);

var populateRSSFeeds = {
    init: function() {
        populateRSSFeeds.loadWebsiteRSSData();
        populateRSSFeeds.loadTechblogRSSData();
        populateRSSFeeds.loadSupRSSData();
        console.log("Should be done loading RSS");
    },
    loadWebsiteRSSData: function() {
        //console.log($("#websiteRSS-container").rss("https://psd401.net/index.php?format=feed&type=rss"));
        $("#websiteRSS-container").rss("https://psd401.net/index.php?format=feed&type=rss",
            {
                limit: 2,
                layoutTemplate: "{entries}",
                entryTemplate: '
{title} {shortBody}

{date}
',
                effect: 'slideFastSynced',
                dateFormat: 'MMMM Do, YYYY',
                error: function(){
                    console.log("There was an error");
                },
            }
        );
    },

    loadTechblogRSSData: function() {
        //console.log($("#techblogRSS-container").rss("http://techblog.psd401.net/?feed=rss2"));
        $("#techblogRSS-container").rss("http://techblog.psd401.net/?feed=rss2",{
                limit: 2,
                layoutTemplate: "{entries}",
                entryTemplate: '
{title} {shortBody}

{date}
',
                effect: 'slideFastSynced',
                dateFormat: 'MMMM Do, YYYY',
                error: function(){
                    console.log("There was an error");
                }
            }
        );
    },

    loadSupRSSData: function() {
         //console.log($("#supRSS-container").rss("https://script.google.com/a/macros/krishagel.com/s/AKfycbxIvJLmswNQRctRQ3UrQqwad_1sOx_SIH5VrSugxXYU-ot2hsc/exec?action=timeline&q=psdsup"));
        $("#supRSS-container").rss("https://script.google.com/a/macros/krishagel.com/s/AKfycbxIvJLmswNQRctRQ3UrQqwad_1sOx_SIH5VrSugxXYU-ot2hsc/exec?action=timeline&q=psdsup",
            {
                limit: 2,
                layoutTemplate: "{entries}",
                entryTemplate: '
{title}

{date}
',
                dateFormat: 'MMMM Do, YYYY',
                effect: 'slideFastSynced',
                error: function(){
                    console.log("There was an error");
                }
            }
        );
    }
}

$(document).ready(function(){
	//populateRSSFeeds.init();
    $('[data-toggle="tooltip"]').tooltip();

    setTimeout(function(){
        $('.psd-login-submit').tooltip('show');
        $('.psd-login-forgot').tooltip('show');
    }, 1200);

    setTimeout(function(){
        $('.psd-login-submit').tooltip('hide');
        $('.psd-login-forgot').tooltip('hide');
    }, 7000);

    $('.psd-login-submit').click(function(){
      stripEmail();
      $('form[name=login]').submit();
    });

    $(".psd-login-form-input").keypress(function(event){
        if(event.which == 13){
            $(".psd-login-form-input-password").focus();
        }
    });

    $(".psd-login-form-input-password").keypress(function(event) {
        if (event.which == 13) {
            event.preventDefault();
            stripEmail();
            $("form[name=login]").submit();
        }
    });

    if($(".logout-success").length > 0) {
        var timer = 10;
	var redirect = location.search.split('url=')[1] ? location.search.split('url=')[1] : '/login?service=http%3A%2F%2Fmy.psd401.net';
        $(".logout-success").attr("href", redirect);
        setInterval(function(){
            $(".logout-success").html("Login " + timer);
            if(timer == 0){
                window.location.href = redirect;
            }
            timer --;
        }, 1000);
    }

    capsLock.observe(function (status) {
        if(status){
            $(".psd-login-form-input-password").tooltip("show");
        } else {
            $(".psd-login-form-input-password").tooltip("hide");
        }
    });
});

function stripEmail(){
    var username = $('.psd-login-form-input').val();
    username = username.toLowerCase().replace(/ /g, '');
    if (username.indexOf("@") != -1) {
        username = username.substring(0, username.indexOf('@'));
    }
    $('.psd-login-form-input').val(username);
}
<|endoftext|>


<commit_before>/**
* Constants for us to use
**/
var CONSTANTS = {

	URL: {

		API: 'https://api.passmarked.com',
		WEB: 'https://passmarked.com'

	},
	CACHE: 60,
	INSTALL_KEY: 'install'

};

/**
* Sends a "install notice" to the Passmarked servers,
* which is also a welcome page for new users.
**/
function installNotice() {

	// check if not already set ...
	chrome.storage.sync.get(CONSTANTS.INSTALL_KEY, function(result) {

		// and .. ?
		if(!result.install) {

			// get current timestamp
		    var now = new Date().getTime();

		    // params to save
		    params = {};

		    // set our initial items
		    params[CONSTANTS.INSTALL_KEY] = JSON.stringify({

		    	timestamp: now

		    });

		    // set as a note
		    chrome.storage.sync.set(params, function() {

		    	// -- ENABLE TO VIEW THE CONTENT OF THE SYNC DATA STORAGE OBJECT
				// chrome.storage.sync.get(null, function (data) { console.info(data) });

		    	// open our welcome page with meta data
			    chrome.tabs.create({

			    	url: CONSTANTS.URL.WEB + '/welcome?' + [

			    		'client=chrome',
			    		'timestamp=' + now

			    	].join('&')

			    });

		    });

		}

	});

}

/**
* Returns a value from the cache but also checks the
* the timestamp first and clears cache if it's too old
**/
function byCache(key, fn) {

	// the timestamp key
	var timestamp_key = key + '.timestamp';

	// get by the key
	chrome.storage.local.get([ key, timestamp_key ], function(result) {

		// did we find anything
		if(result) {

			// current time
			var current_timestamp = new Date().getTime();

			// check the timestamp
			if( result[timestamp_key] &&
				( current_timestamp - result[timestamp_key] ) <= 1000 * 60 * CONSTANTS.CACHE ) {

				// output our item ..
				fn( JSON.parse(result[key]) )

			} else {

				// remove it
				chrome.storage.local.remove([ key, timestamp_key ], function() {

					// signal done and that nothing was found from cache ...
					fn(null);

				});

			}

		} else fn(null);

	});

}

/**
* Sets to the cache along with the timestamp
**/
function setCache(key, value, fn) {

	// the timestamp key
	var timestamp_key = key + '.timestamp';

	// params to set
	var params = {};

	// add in
	params[key] = JSON.stringify(value);
	params[timestamp_key] = new Date().getTime();

	// get by the key
	chrome.storage.local.set(params, function(){

		// signal that we are done
		fn(null);

	});

}

/**
* Returns the score info from the server
* using the cache and everything involved
**/
function getReportedInfo(domain, fn) {

	// key for the cache
	var cacheKey = domain.toLowerCase();

	// key for our local cache
	byCache(cacheKey, function(cached_details){

		if(cached_details) {

			// returns the cached items
			fn(cached_details);

		} else {

			// open a XHR for the request
			var xhr = new XMLHttpRequest();

			// open up a connection
			xhr.open("GET", CONSTANTS.URL.API + '/query?' + [

				'source=chrome.ext',
				'domain=' + domain

			].join('&'), false);

			// handle the response
			xhr.onreadystatechange = function() {

				console.log(xhr.readyState);
				console.dir(xhr);

				// handle when done
				if (xhr.readyState == 4) {

					// get our response
					var result = xhr.responseText;

					console.log(result);

					// can we parse it ?
					var jsonObj = null;

					// try to parse it
					try { jsonObj = JSON.parse(result); } catch(err) {}

					// could we parse ?
					if(jsonObj) {

						// save the url
						setCache(domain, jsonObj, function(){

							// return with info
							fn(jsonObj);

						});

					} else {

						// nope ...
						fn(null);

					}

				}

			};

			// send the request
			xhr.send();

		}

	});

}

/**
* Sets a Blank icon or just makes sure it's showing
**/
function showBlankIcon(tabId) {

	// create a local canvas element
	var canvas = document.createElement('canvas');
	var context = canvas.getContext('2d');

	// fill in the background with white
	context.fillStyle = 'white';
	context.fill();

	// handle a new image to draw
	drawing = new Image();

	// wait for the image to load first
	drawing.onload = function () {

		// draws our image after it's been loaded
		context.drawImage(drawing,0,4);

		// set the icon we want to use
		chrome.pageAction.setIcon({

			imageData: context.getImageData(0, 0, 19, 19),
			tabId: tabId

		});

		// show the page action to the tab this is active on
	    chrome.pageAction.show(tabId);

	};

	// update the source of the image with local assets
	drawing.src = "assets/bg19.png";

}

/**
* Sets a Icon that has a score showing
**/
function showScoreIcon(tabId, score) {

	// sanity check if we should render blank
	// icon for  a 'null' score
	if(!score) {

		// show a blank icon rather then
		showBlankIcon(tabId);
		return;

	}

	// create a local canvas element
	var canvas = document.createElement('canvas');
	var context = canvas.getContext('2d');

	// fill in the background with white
	context.fillStyle = 'white';
	context.fill();

	// draw the score out
	context.fillStyle = colorByScore(score);
	context.textAlign = "center";
	context.textBaseline = "middle";
	context.font = "11px Arial";
	context.fillText(score, 19 * 0.5,  (19 * 0.5)-2 );

	// handle a new image to draw
	drawing = new Image();

	// wait for the image to load first
	drawing.onload = function () {

		// draws our image after it's been loaded
		context.drawImage(drawing,0,11);

		// set the icon we want to use
		chrome.pageAction.setIcon({

			imageData: context.getImageData(0, 0, 19, 19),
			tabId: tabId

		});

		// show the page action to the tab this is active on
	    chrome.pageAction.show(tabId);

	};

	// update the source of the image with local assets
	drawing.src = "assets/bg.empty19.png";

}

/**
* Returns a color according to the score
**/
function colorByScore(score) {

	// local variable
	var parsedScore = null;
	var baseColor = null;

	// parse to int
	try { parsedScore = parseInt(score); } catch(err) {}

	// check we found a score ...
	if(!parsedScore) baseColor = 'd44937';
	else if(parsedScore < 45) baseColor = 'f72d49';
	else if(parsedScore < 70) baseColor = 'f96b25';
	else if(parsedScore >= 70) baseColor = '78cbd1';

	// returns the color according to score
	return colorLuminance(baseColor, -(1 - ( parsedScore/100 )) );

}

/**
* Returns color darker or lighter,
* -0.1 = 10% darker, 0.1 = 10% lighter
**/
function colorLuminance(hex, lum) {

	// validate hex string
	hex = String(hex).replace(/[^0-9a-f]/gi, '');
	if (hex.length < 6) {
		hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
	}
	lum = lum || 0;

	// convert to decimal and change luminosity
	var rgb = "#", c, i;
	for (i = 0; i < 3; i++) {

		c = parseInt(hex.substr(i*2,2), 16);
		c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16);
		rgb += ("00"+c).substr(c.length);

	}

	// returns the rgb
	return rgb;

}

/**
* Returns a domain by the url given
**/
function getDomainByUrl(url) {

	// returns the domain by the full url
	return URI(url).hostname();

}

/**
* Decides if we should show the icon on a url
**/
function allowActionByUrl(url) {

	// check if it's blank,
	// more a sanity check
	// than anything else
	if(!url) return false;

	// the lowered url
	url = (url || '').toLowerCase()

	// check if this is not a internal chrome page
	if(	url.indexOf('http://') != 0 &&
		url.indexOf('https://') != 0 ) return false;

	// check for local host
	if(url.indexOf('://localhost') != -1) return false;

	// default is true
	return true;

}

/**
* Handle a click on the page icon
**/
chrome.pageAction.onClicked.addListener(function(tab){

	// handle it
	var url = tab.url;

	// get the domain
	var hostname = getDomainByUrl(url);

	// get all the data
	getReportedInfo( hostname, function(report_overview_obj){

		// did we find one ?
		chrome.tabs.create({

			url: CONSTANTS.URL.API + '/redirect?' + [

				'url=' + encodeURIComponent(url),
				'source=chrome.ext'

			].join('&')

		}, function() {

			// cool open, will add here if anything is needed ...

		});

	} );

});

/**
* Handles when a url is created
**/
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {

	// check if we should worry
	if(!allowActionByUrl(tab.url)) return;

	// get the domain
	var domain = getDomainByUrl(tab.url);

	// check if we have a score for this domain
	getReportedInfo(domain, function(result){

		// did we find a item for the page ?
		if( result && result.count > 0 ) {

			// render the actual score we have
			showScoreIcon(tabId, result.score);

		} else {

			// render the blank icon for this page
			showBlankIcon(tabId);

		}

	});

});

// run our install notice
installNotice();<commit_msg>Removed debugging code that was left behind in my previous commit<commit_after>/**
* Constants for us to use
**/
var CONSTANTS = {

	URL: {

		API: 'https://api.passmarked.com',
		WEB: 'https://passmarked.com'

	},
	CACHE: 60,
	INSTALL_KEY: 'install'

};

/**
* Sends a "install notice" to the Passmarked servers,
* which is also a welcome page for new users.
**/
function installNotice() {

	// check if not already set ...
	chrome.storage.sync.get(CONSTANTS.INSTALL_KEY, function(result) {

		// and .. ?
		if(!result.install) {

			// get current timestamp
		    var now = new Date().getTime();

		    // params to save
		    params = {};

		    // set our initial items
		    params[CONSTANTS.INSTALL_KEY] = JSON.stringify({

		    	timestamp: now

		    });

		    // set as a note
		    chrome.storage.sync.set(params, function() {

		    	// -- ENABLE TO VIEW THE CONTENT OF THE SYNC DATA STORAGE OBJECT
				// chrome.storage.sync.get(null, function (data) { console.info(data) });

		    	// open our welcome page with meta data
			    chrome.tabs.create({

			    	url: CONSTANTS.URL.WEB + '/welcome?' + [

			    		'client=chrome',
			    		'timestamp=' + now

			    	].join('&')

			    });

		    });

		}

	});

}

/**
* Returns a value from the cache but also checks the
* the timestamp first and clears cache if it's too old
**/
function byCache(key, fn) {

	// the timestamp key
	var timestamp_key = key + '.timestamp';

	// get by the key
	chrome.storage.local.get([ key, timestamp_key ], function(result) {

		// did we find anything
		if(result) {

			// current time
			var current_timestamp = new Date().getTime();

			// check the timestamp
			if( result[timestamp_key] &&
				( current_timestamp - result[timestamp_key] ) <= 1000 * 60 * CONSTANTS.CACHE ) {

				// output our item ..
				fn( JSON.parse(result[key]) )

			} else {

				// remove it
				chrome.storage.local.remove([ key, timestamp_key ], function() {

					// signal done and that nothing was found from cache ...
					fn(null);

				});

			}

		} else fn(null);

	});

}

/**
* Sets to the cache along with the timestamp
**/
function setCache(key, value, fn) {

	// the timestamp key
	var timestamp_key = key + '.timestamp';

	// params to set
	var params = {};

	// add in
	params[key] = JSON.stringify(value);
	params[timestamp_key] = new Date().getTime();

	// get by the key
	chrome.storage.local.set(params, function(){

		// signal that we are done
		fn(null);

	});

}

/**
* Returns the score info from the server
* using the cache and everything involved
**/
function getReportedInfo(domain, fn) {

	// key for the cache
	var cacheKey = domain.toLowerCase();

	// key for our local cache
	byCache(cacheKey, function(cached_details){

		if(cached_details) {

			// returns the cached items
			fn(cached_details);

		} else {

			// open a XHR for the request
			var xhr = new XMLHttpRequest();

			// open up a connection
			xhr.open("GET", CONSTANTS.URL.API + '/query?' + [

				'source=chrome.ext',
				'domain=' + domain

			].join('&'), false);

			// handle the response
			xhr.onreadystatechange = function() {

				// handle when done
				if (xhr.readyState == 4) {

					// get our response
					var result = xhr.responseText;

					console.log(result);

					// can we parse it ?
					var jsonObj = null;

					// try to parse it
					try { jsonObj = JSON.parse(result); } catch(err) {}

					// could we parse ?
					if(jsonObj) {

						// save the url
						setCache(domain, jsonObj, function(){

							// return with info
							fn(jsonObj);

						});

					} else {

						// nope ...
						fn(null);

					}

				}

			};

			// send the request
			xhr.send();

		}

	});

}

/**
* Sets a Blank icon or just makes sure it's showing
**/
function showBlankIcon(tabId) {

	// create a local canvas element
	var canvas = document.createElement('canvas');
	var context = canvas.getContext('2d');

	// fill in the background with white
	context.fillStyle = 'white';
	context.fill();

	// handle a new image to draw
	drawing = new Image();

	// wait for the image to load first
	drawing.onload = function () {

		// draws our image after it's been loaded
		context.drawImage(drawing,0,4);

		// set the icon we want to use
		chrome.pageAction.setIcon({

			imageData: context.getImageData(0, 0, 19, 19),
			tabId: tabId

		});

		// show the page action to the tab this is active on
	    chrome.pageAction.show(tabId);

	};

	// update the source of the image with local assets
	drawing.src = "assets/bg19.png";

}

/**
* Sets a Icon that has a score showing
**/
function showScoreIcon(tabId, score) {

	// sanity check if we should render blank
	// icon for  a 'null' score
	if(!score) {

		// show a blank icon rather then
		showBlankIcon(tabId);
		return;

	}

	// create a local canvas element
	var canvas = document.createElement('canvas');
	var context = canvas.getContext('2d');

	// fill in the background with white
	context.fillStyle = 'white';
	context.fill();

	// draw the score out
	context.fillStyle = colorByScore(score);
	context.textAlign = "center";
	context.textBaseline = "middle";
	context.font = "11px Arial";
	context.fillText(score, 19 * 0.5,  (19 * 0.5)-2 );

	// handle a new image to draw
	drawing = new Image();

	// wait for the image to load first
	drawing.onload = function () {

		// draws our image after it's been loaded
		context.drawImage(drawing,0,11);

		// set the icon we want to use
		chrome.pageAction.setIcon({

			imageData: context.getImageData(0, 0, 19, 19),
			tabId: tabId

		});

		// show the page action to the tab this is active on
	    chrome.pageAction.show(tabId);

	};

	// update the source of the image with local assets
	drawing.src = "assets/bg.empty19.png";

}

/**
* Returns a color according to the score
**/
function colorByScore(score) {

	// local variable
	var parsedScore = null;
	var baseColor = null;

	// parse to int
	try { parsedScore = parseInt(score); } catch(err) {}

	// check we found a score ...
	if(!parsedScore) baseColor = 'd44937';
	else if(parsedScore < 45) baseColor = 'f72d49';
	else if(parsedScore < 70) baseColor = 'f96b25';
	else if(parsedScore >= 70) baseColor = '78cbd1';

	// returns the color according to score
	return colorLuminance(baseColor, -(1 - ( parsedScore/100 )) );

}

/**
* Returns color darker or lighter,
* -0.1 = 10% darker, 0.1 = 10% lighter
**/
function colorLuminance(hex, lum) {

	// validate hex string
	hex = String(hex).replace(/[^0-9a-f]/gi, '');
	if (hex.length < 6) {
		hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
	}
	lum = lum || 0;

	// convert to decimal and change luminosity
	var rgb = "#", c, i;
	for (i = 0; i < 3; i++) {

		c = parseInt(hex.substr(i*2,2), 16);
		c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16);
		rgb += ("00"+c).substr(c.length);

	}

	// returns the rgb
	return rgb;

}

/**
* Returns a domain by the url given
**/
function getDomainByUrl(url) {

	// returns the domain by the full url
	return URI(url).hostname();

}

/**
* Decides if we should show the icon on a url
**/
function allowActionByUrl(url) {

	// check if it's blank,
	// more a sanity check
	// than anything else
	if(!url) return false;

	// the lowered url
	url = (url || '').toLowerCase()

	// check if this is not a internal chrome page
	if(	url.indexOf('http://') != 0 &&
		url.indexOf('https://') != 0 ) return false;

	// check for local host
	if(url.indexOf('://localhost') != -1) return false;

	// default is true
	return true;

}

/**
* Handle a click on the page icon
**/
chrome.pageAction.onClicked.addListener(function(tab){

	// handle it
	var url = tab.url;

	// get the domain
	var hostname = getDomainByUrl(url);

	// get all the data
	getReportedInfo( hostname, function(report_overview_obj){

		// did we find one ?
		chrome.tabs.create({

			url: CONSTANTS.URL.API + '/redirect?' + [

				'url=' + encodeURIComponent(url),
				'source=chrome.ext'

			].join('&')

		}, function() {

			// cool open, will add here if anything is needed ...

		});

	} );

});

/**
* Handles when a url is created
**/
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {

	// check if we should worry
	if(!allowActionByUrl(tab.url)) return;

	// get the domain
	var domain = getDomainByUrl(tab.url);

	// check if we have a score for this domain
	getReportedInfo(domain, function(result){

		// did we find a item for the page ?
		if( result && result.count > 0 ) {

			// render the actual score we have
			showScoreIcon(tabId, result.score);

		} else {

			// render the blank icon for this page
			showBlankIcon(tabId);

		}

	});

});

// run our install notice
installNotice();<|endoftext|>