<commit_before>/* *****************************************************************************
 * This file is part of ThreadVis.
 * http://threadvis.mozdev.org/
 *
 * ThreadVis started as part of Alexander C. Hubmann-Haidvogel's Master's Thesis
 * titled "ThreadVis for Thunderbird: A Thread Visualisation Extension for the
 * Mozilla Thunderbird Email Client" at Graz University of Technology, Austria.
 * An electronic version of the thesis is available online at
 * http://www.iicm.tugraz.at/ahubmann.pdf
 *
 * Copyright (C) 2005, 2006, 2007 Alexander C. Hubmann
 * Copyright (C) 2007, 2008, 2009, 2010 Alexander C. Hubmann-Haidvogel
 *
 * ThreadVis is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * ThreadVis is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with ThreadVis. If not, see <http://www.gnu.org/licenses/>.
 *
 * Version: $Id$
 * *****************************************************************************
 * JavaScript file to react to preference changing events
 ******************************************************************************/

if (! window.ThreadVisNS) {
    window.ThreadVisNS = {};
}

/** ****************************************************************************
 * Preference observer
 *
 * @return
 *          A new observer object
 ******************************************************************************/
ThreadVisNS.PreferenceObserver = function() {
    this.PREF_BRANCH = "extensions.threadvis.";

    this.PREF_ABOUT = this.PREF_BRANCH + "about";
    this.PREF_DISABLED_ACCOUNTS = this.PREF_BRANCH + "disabledaccounts";
    this.PREF_DISABLED_FOLDERS = this.PREF_BRANCH + "disabledfolders";
    this.PREF_ENABLED = this.PREF_BRANCH + "enabled";
    this.PREF_SENTMAIL_FOLDERFLAG = this.PREF_BRANCH + "sentmail.folderflag";
    this.PREF_SENTMAIL_IDENTITY = this.PREF_BRANCH + "sentmail.identity";
    this.PREF_SVG_HEIGHT = this.PREF_BRANCH + "svg.height";
    this.PREF_SVG_WIDTH = this.PREF_BRANCH + "svg.width";
    this.PREF_TIMELINE = this.PREF_BRANCH + "timeline.enabled";
    this.PREF_TIMESCALING = this.PREF_BRANCH + "timescaling.enabled";
    this.PREF_VIS_DOTSIZE = this.PREF_BRANCH + "visualisation.dotsize";
    this.PREF_VIS_ARC_MINHEIGHT = this.PREF_BRANCH + "visualisation.arcminheight";
    this.PREF_VIS_ARC_RADIUS = this.PREF_BRANCH + "visualisation.arcradius";
    this.PREF_VIS_ARC_DIFFERENCE = this.PREF_BRANCH + "visualisation.arcdifference";
    this.PREF_VIS_ARC_WIDTH = this.PREF_BRANCH + "visualisation.arcwidth";
    this.PREF_VIS_SPACING = this.PREF_BRANCH + "visualisation.spacing";
    this.PREF_VIS_MESSAGE_CIRCLES = this.PREF_BRANCH + "visualisation.messagecircles";
    this.PREF_VIS_COLOUR = this.PREF_BRANCH + "visualisation.colour";
    this.PREF_VIS_COLOURS_BACKGROUND = this.PREF_BRANCH + "visualisation.colours.background";
    this.PREF_VIS_COLOURS_BORDER = this.PREF_BRANCH + "visualisation.colours.border";
    this.PREF_VIS_COLOURS_RECEIVED = this.PREF_BRANCH + "visualisation.colours.received";
    this.PREF_VIS_COLOURS_SENT = this.PREF_BRANCH + "visualisation.colours.sent";
    this.PREF_VIS_HIDE_ON_DISABLE = this.PREF_BRANCH + "visualisation.hideondisable";
    this.PREF_VIS_HIDE_ON_SINGLE = this.PREF_BRANCH + "visualisation.hideonsingle"
    this.PREF_VIS_HIGHLIGHT = this.PREF_BRANCH + "visualisation.highlight";
    this.PREF_VIS_MINIMAL_WIDTH = this.PREF_BRANCH + "visualisation.minimalwidth";
    this.PREF_VIS_OPACITY = this.PREF_BRANCH + "visualisation.opacity";
    this.PREF_VIS_ZOOM = this.PREF_BRANCH + "visualisation.zoom";

    this.PREF_GLODA_ENABLED = "mailnews.database.global.indexer.enabled";

    this.prefBranch = null;
    this.preferences = new Object();

    var prefService = Components.classes["@mozilla.org/preferences-service;1"]
        .getService(Components.interfaces.nsIPrefService);
    this.prefBranch = prefService.getBranch(this.PREF_BRANCH);
    this.glodaPrefBranch = prefService.getBranch(this.PREF_GLODA_ENABLED);

    this.PREF_BOOL = this.prefBranch.PREF_BOOL;
    this.PREF_INT = this.prefBranch.PREF_INT;
    this.PREF_STRING = this.prefBranch.PREF_STRING;

    this.register();
    this.preferenceReload();
}

/** ****************************************************************************
 * Do callbacks after preference change
 *
 * @param pref
 *          The pref that changed
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.doCallback = function(pref) {
    var value = this.preferences[pref].value;
    var callbacks = this.preferences[pref].callbacks;
    for (var key in callbacks) {
        var func = callbacks[key];
        func(value);
    }
}

/** ****************************************************************************
 * Get preference value for given preference
 * @param pref
 *          The preference to get
 * @return
 *          The value of the preference
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.getPreference = function(pref) {
    return this.preferences[pref].value;
}

/** ****************************************************************************
 * Load a preference from the store
 *
 * @param pref
 *          The preference to load
 * @param type
 *          The type of the preference (bool, string, int)
 * @param def
 *          The default value
 * @param prefBranch
 *          The branch to use to read the value
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.loadPreference = function(pref, type,
    def, prefBranch) {
    this.preferences[pref] = {};
    this.preferences[pref].value = def;
    this.preferences[pref].callbacks = [];
    this.preferences[pref].type = type;

    if (! prefBranch) {
        prefBranch = this.prefBranch;
    }
    this.preferences[pref].branch = prefBranch;

    // remove leading branch from pref name
    var loadPref = pref.substring(prefBranch.root.length);

    if (prefBranch.getPrefType(loadPref) != type) {
        return;
    }

    switch (type) {
        case this.PREF_BOOL:
            this.preferences[pref].value = prefBranch.getBoolPref(loadPref);
            break;
        case this.PREF_STRING:
            this.preferences[pref].value = prefBranch.getCharPref(loadPref);
            break;
        case this.PREF_INT:
            this.preferences[pref].value = prefBranch.getIntPref(loadPref);
            break;
    }
}

/** ****************************************************************************
 * Observe preferences changes
 *
 * @param subject
 * @param topic
 * @param data
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.observe = function(subject, topic,
    data) {
    if(topic != "nsPref:changed") {
        return;
    }

    // reload preferences
    this.preferenceReload();
    this.doCallback(data);
}

/** ****************************************************************************
 * Reload preferences
 *
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.preferenceReload = function() {
    this.loadPreference(this.PREF_ABOUT,
        this.PREF_INT, 0);
    this.loadPreference(this.PREF_DISABLED_ACCOUNTS,
        this.PREF_STRING, "");
    this.loadPreference(this.PREF_DISABLED_FOLDERS,
        this.PREF_STRING, "");
    this.loadPreference(this.PREF_ENABLED,
        this.PREF_BOOL, true);
    this.loadPreference(this.PREF_SENTMAIL_FOLDERFLAG,
        this.PREF_BOOL, true);
    this.loadPreference(this.PREF_SENTMAIL_IDENTITY,
        this.PREF_BOOL, true);
    this.loadPreference(this.PREF_SVG_HEIGHT,
        this.PREF_INT, 1000);
    this.loadPreference(this.PREF_SVG_WIDTH,
        this.PREF_INT, 1000);
    this.loadPreference(this.PREF_TIMELINE,
        this.PREF_BOOL, true);
    this.loadPreference(this.PREF_TIMESCALING,
        this.PREF_BOOL, true);
    this.loadPreference(this.PREF_VIS_DOTSIZE,
        this.PREF_INT, 12);
    this.loadPreference(this.PREF_VIS_ARC_MINHEIGHT,
        this.PREF_INT, 12);
    this.loadPreference(this.PREF_VIS_ARC_RADIUS,
        this.PREF_INT, 32);
    this.loadPreference(this.PREF_VIS_ARC_DIFFERENCE,
        this.PREF_INT, 6);
    this.loadPreference(this.PREF_VIS_ARC_WIDTH,
        this.PREF_INT, 2);
    this.loadPreference(this.PREF_VIS_SPACING,
        this.PREF_INT, 24);
    this.loadPreference(this.PREF_VIS_MESSAGE_CIRCLES,
        this.PREF_BOOL, true);
    this.loadPreference(this.PREF_VIS_COLOUR,
        this.PREF_STRING, "author");
    this.loadPreference(this.PREF_VIS_COLOURS_BACKGROUND,
        this.PREF_STRING, "");
    this.loadPreference(this.PREF_VIS_COLOURS_BORDER,
        this.PREF_STRING, "");
    this.loadPreference(this.PREF_VIS_COLOURS_RECEIVED,
        this.PREF_STRING, "#7FFF00,#00FFFF,#7F00FF,#997200,#009926,#002699,#990072,#990000,#4C9900,#009999,#4C0099,#FFBF00,#00FF3F,#003FFF,#FF00BF");
    this.loadPreference(this.PREF_VIS_COLOURS_SENT,
        this.PREF_STRING, "#ff0000");
    this.loadPreference(this.PREF_VIS_HIDE_ON_DISABLE,
        this.PREF_BOOL, true);
    this.loadPreference(this.PREF_VIS_HIDE_ON_SINGLE,
        this.PREF_BOOL, false);
    this.loadPreference(this.PREF_VIS_HIGHLIGHT,
        this.PREF_BOOL, true);
    this.loadPreference(this.PREF_VIS_MINIMAL_WIDTH,
        this.PREF_INT, 0);
    this.loadPreference(this.PREF_VIS_OPACITY,
        this.PREF_INT, 30);
    this.loadPreference(this.PREF_VIS_ZOOM,
        this.PREF_STRING, "full");

    this.loadPreference(this.PREF_GLODA_ENABLED,
            this.PREF_BOOL, true, this.glodaPrefBranch);

}

/** ****************************************************************************
 * Register as preference changing observer
 *
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.register =  function() {
    // add observer for our own branch
    var pbi = this.prefBranch
        .QueryInterface(Components.interfaces.nsIPrefBranch2);
    pbi.addObserver("", this, false);

    // add observer for gloda
    var glodaObserver = this.glodaPrefBranch
        .QueryInterface(Components.interfaces.nsIPrefBranch2);
    glodaObserver.addObserver("", this, false);
}

/** ****************************************************************************
 * Register a callback hook
 *
 * @param preference
 *          The preference
 * @param func
 *          The function that has to be called if the preference value changes
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.registerCallback = function(preference,
    func) {
    this.preferences[preference].callbacks.push(func);
}

/** ****************************************************************************
 * Set preference value for given preference
 *
 * @param pref
 *          The name of the preference
 * @param val
 *          The value of the preference
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.setPreference = function(pref, val) {
    this.preferences[pref].value = val;
    this.storePreference(pref, val);
}

/** ****************************************************************************
 * Store a preference to the store
 *
 * @param pref
 *          The name of the preference
 * @param val
 *          The value of the preference
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.storePreference = function(pref, val) {
    var branch = this.preferences[pref].branch;
    var type = this.preferences[pref].type;
    // remove leading branch from pref name
    pref = pref.substring(branch.root.length);

    switch (type) {
        case this.PREF_BOOL:
            branch.setBoolPref(pref, val);
            break;
        case this.PREF_STRING:
            branch.setCharPref(pref, val);
            break;
        case this.PREF_INT:
            branch.setIntPref(pref, val);
            break;
    }
}

/** ****************************************************************************
 * Unregister observer
 *
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.unregister = function() {
    if(!this.prefBranch) {
        return;
    }

    var pbi = this.prefBranch
        .QueryInterface(Components.interfaces.nsIPrefBranch2);
    pbi.removeObserver("", this);
}
<commit_msg>fix (re)loading of preferences<commit_after>/* *****************************************************************************
 * This file is part of ThreadVis.
 * http://threadvis.mozdev.org/
 *
 * ThreadVis started as part of Alexander C. Hubmann-Haidvogel's Master's Thesis
 * titled "ThreadVis for Thunderbird: A Thread Visualisation Extension for the
 * Mozilla Thunderbird Email Client" at Graz University of Technology, Austria.
 * An electronic version of the thesis is available online at
 * http://www.iicm.tugraz.at/ahubmann.pdf
 *
 * Copyright (C) 2005, 2006, 2007 Alexander C. Hubmann
 * Copyright (C) 2007, 2008, 2009, 2010 Alexander C. Hubmann-Haidvogel
 *
 * ThreadVis is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * ThreadVis is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with ThreadVis. If not, see <http://www.gnu.org/licenses/>.
 *
 * Version: $Id$
 * *****************************************************************************
 * JavaScript file to react to preference changing events
 ******************************************************************************/

if (! window.ThreadVisNS) {
    window.ThreadVisNS = {};
}

/** ****************************************************************************
 * Preference observer
 *
 * @return
 *          A new observer object
 ******************************************************************************/
ThreadVisNS.PreferenceObserver = function() {
    this.PREF_BRANCH = "extensions.threadvis.";

    this.PREF_ABOUT = this.PREF_BRANCH + "about";
    this.PREF_DISABLED_ACCOUNTS = this.PREF_BRANCH + "disabledaccounts";
    this.PREF_DISABLED_FOLDERS = this.PREF_BRANCH + "disabledfolders";
    this.PREF_ENABLED = this.PREF_BRANCH + "enabled";
    this.PREF_SENTMAIL_FOLDERFLAG = this.PREF_BRANCH + "sentmail.folderflag";
    this.PREF_SENTMAIL_IDENTITY = this.PREF_BRANCH + "sentmail.identity";
    this.PREF_SVG_HEIGHT = this.PREF_BRANCH + "svg.height";
    this.PREF_SVG_WIDTH = this.PREF_BRANCH + "svg.width";
    this.PREF_TIMELINE = this.PREF_BRANCH + "timeline.enabled";
    this.PREF_TIMESCALING = this.PREF_BRANCH + "timescaling.enabled";
    this.PREF_VIS_DOTSIZE = this.PREF_BRANCH + "visualisation.dotsize";
    this.PREF_VIS_ARC_MINHEIGHT = this.PREF_BRANCH + "visualisation.arcminheight";
    this.PREF_VIS_ARC_RADIUS = this.PREF_BRANCH + "visualisation.arcradius";
    this.PREF_VIS_ARC_DIFFERENCE = this.PREF_BRANCH + "visualisation.arcdifference";
    this.PREF_VIS_ARC_WIDTH = this.PREF_BRANCH + "visualisation.arcwidth";
    this.PREF_VIS_SPACING = this.PREF_BRANCH + "visualisation.spacing";
    this.PREF_VIS_MESSAGE_CIRCLES = this.PREF_BRANCH + "visualisation.messagecircles";
    this.PREF_VIS_COLOUR = this.PREF_BRANCH + "visualisation.colour";
    this.PREF_VIS_COLOURS_BACKGROUND = this.PREF_BRANCH + "visualisation.colours.background";
    this.PREF_VIS_COLOURS_BORDER = this.PREF_BRANCH + "visualisation.colours.border";
    this.PREF_VIS_COLOURS_RECEIVED = this.PREF_BRANCH + "visualisation.colours.received";
    this.PREF_VIS_COLOURS_SENT = this.PREF_BRANCH + "visualisation.colours.sent";
    this.PREF_VIS_HIDE_ON_DISABLE = this.PREF_BRANCH + "visualisation.hideondisable";
    this.PREF_VIS_HIDE_ON_SINGLE = this.PREF_BRANCH + "visualisation.hideonsingle"
    this.PREF_VIS_HIGHLIGHT = this.PREF_BRANCH + "visualisation.highlight";
    this.PREF_VIS_MINIMAL_WIDTH = this.PREF_BRANCH + "visualisation.minimalwidth";
    this.PREF_VIS_OPACITY = this.PREF_BRANCH + "visualisation.opacity";
    this.PREF_VIS_ZOOM = this.PREF_BRANCH + "visualisation.zoom";

    this.PREF_GLODA_ENABLED = "mailnews.database.global.indexer.enabled";

    this.prefBranch = null;
    this.preferences = new Object();

    var prefService = Components.classes["@mozilla.org/preferences-service;1"]
        .getService(Components.interfaces.nsIPrefService);
    this.prefBranch = prefService.getBranch(this.PREF_BRANCH);
    this.glodaPrefBranch = prefService.getBranch(this.PREF_GLODA_ENABLED);

    this.PREF_BOOL = this.prefBranch.PREF_BOOL;
    this.PREF_INT = this.prefBranch.PREF_INT;
    this.PREF_STRING = this.prefBranch.PREF_STRING;

    this.register();
    this.preferenceReload();
}

/** ****************************************************************************
 * Do callbacks after preference change
 *
 * @param pref
 *          The pref that changed
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.doCallback = function(pref) {
    var value = this.getPreference(pref);
    var callbacks = this.preferences[pref].callbacks;
    for (var key in callbacks) {
        var func = callbacks[key];
        func(value);
    }
}

/** ****************************************************************************
 * Get preference value for given preference
 * @param pref
 *          The preference to get
 * @return
 *          The value of the preference
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.getPreference = function(pref) {
    return this.preferences[pref].value;
}

/** ****************************************************************************
 * Load a preference from the store
 *
 * @param pref
 *          The preference to load
 * @param type
 *          The type of the preference (bool, string, int)
 * @param def
 *          The default value
 * @param prefBranch
 *          The branch to use to read the value
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.loadPreference = function(pref, type,
    def, prefBranch) {
    if (this.preferences[pref] == null) {
        this.preferences[pref] = {};
        this.preferences[pref].value = def;
        this.preferences[pref].callbacks = [];
        this.preferences[pref].type = type;
        if (! prefBranch) {
            prefBranch = this.prefBranch;
        }
        this.preferences[pref].branch = prefBranch;
    }

    // remove leading branch from pref name
    var loadPref = pref.substring(this.preferences[pref].branch.root.length);
    if (this.preferences[pref].branch.getPrefType(loadPref) != type) {
        return;
    }

    switch (type) {
        case this.PREF_BOOL:
            this.preferences[pref].value = this.preferences[pref].branch
                .getBoolPref(loadPref);
            break;
        case this.PREF_STRING:
            this.preferences[pref].value = this.preferences[pref].branch
                .getCharPref(loadPref);
            break;
        case this.PREF_INT:
            this.preferences[pref].value = this.preferences[pref].branch
                .getIntPref(loadPref);
            break;
    }
}

/** ****************************************************************************
 * Reload preferences
 *
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.preferenceReload = function() {
    this.loadPreference(this.PREF_ABOUT,
        this.PREF_INT, 0);
    this.loadPreference(this.PREF_DISABLED_ACCOUNTS,
        this.PREF_STRING, "");
    this.loadPreference(this.PREF_DISABLED_FOLDERS,
        this.PREF_STRING, "");
    this.loadPreference(this.PREF_ENABLED,
        this.PREF_BOOL, true);
    this.loadPreference(this.PREF_SENTMAIL_FOLDERFLAG,
        this.PREF_BOOL, true);
    this.loadPreference(this.PREF_SENTMAIL_IDENTITY,
        this.PREF_BOOL, true);
    this.loadPreference(this.PREF_SVG_HEIGHT,
        this.PREF_INT, 1000);
    this.loadPreference(this.PREF_SVG_WIDTH,
        this.PREF_INT, 1000);
    this.loadPreference(this.PREF_TIMELINE,
        this.PREF_BOOL, true);
    this.loadPreference(this.PREF_TIMESCALING,
        this.PREF_BOOL, true);
    this.loadPreference(this.PREF_VIS_DOTSIZE,
        this.PREF_INT, 12);
    this.loadPreference(this.PREF_VIS_ARC_MINHEIGHT,
        this.PREF_INT, 12);
    this.loadPreference(this.PREF_VIS_ARC_RADIUS,
        this.PREF_INT, 32);
    this.loadPreference(this.PREF_VIS_ARC_DIFFERENCE,
        this.PREF_INT, 6);
    this.loadPreference(this.PREF_VIS_ARC_WIDTH,
        this.PREF_INT, 2);
    this.loadPreference(this.PREF_VIS_SPACING,
        this.PREF_INT, 24);
    this.loadPreference(this.PREF_VIS_MESSAGE_CIRCLES,
        this.PREF_BOOL, true);
    this.loadPreference(this.PREF_VIS_COLOUR,
        this.PREF_STRING, "author");
    this.loadPreference(this.PREF_VIS_COLOURS_BACKGROUND,
        this.PREF_STRING, "");
    this.loadPreference(this.PREF_VIS_COLOURS_BORDER,
        this.PREF_STRING, "");
    this.loadPreference(this.PREF_VIS_COLOURS_RECEIVED,
        this.PREF_STRING, "#7FFF00,#00FFFF,#7F00FF,#997200,#009926,#002699,#990072,#990000,#4C9900,#009999,#4C0099,#FFBF00,#00FF3F,#003FFF,#FF00BF");
    this.loadPreference(this.PREF_VIS_COLOURS_SENT,
        this.PREF_STRING, "#ff0000");
    this.loadPreference(this.PREF_VIS_HIDE_ON_DISABLE,
        this.PREF_BOOL, true);
    this.loadPreference(this.PREF_VIS_HIDE_ON_SINGLE,
        this.PREF_BOOL, false);
    this.loadPreference(this.PREF_VIS_HIGHLIGHT,
        this.PREF_BOOL, true);
    this.loadPreference(this.PREF_VIS_MINIMAL_WIDTH,
        this.PREF_INT, 0);
    this.loadPreference(this.PREF_VIS_OPACITY,
        this.PREF_INT, 30);
    this.loadPreference(this.PREF_VIS_ZOOM,
        this.PREF_STRING, "full");

    this.loadPreference(this.PREF_GLODA_ENABLED,
            this.PREF_BOOL, true, this.glodaPrefBranch);

}

/** ****************************************************************************
 * Register as preference changing observer
 *
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.register =  function() {
    // add observer for our own branch
    var pbi = this.prefBranch
        .QueryInterface(Components.interfaces.nsIPrefBranch2);
    var ref = this;
    pbi.addObserver("", {
        observe: function(subject, topic, data) {
            if (topic != "nsPref:changed") {
                return;
            }
            // reload preferences
            ref.preferenceReload();
            ref.doCallback(ref.PREF_BRANCH + data);
        }
    }, false);

    // add observer for gloda
    var glodaObserver = this.glodaPrefBranch
        .QueryInterface(Components.interfaces.nsIPrefBranch2);
    glodaObserver.addObserver("", {
        observe: function(subject, topic, data) {
            if (topic != "nsPref:changed") {
                return;
            }
            // reload preferences
            ref.preferenceReload();
            ref.doCallback(data);
        }
    }, false);
}

/** ****************************************************************************
 * Register a callback hook
 *
 * @param preference
 *          The preference
 * @param func
 *          The function that has to be called if the preference value changes
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.registerCallback = function(preference,
    func) {
    this.preferences[preference].callbacks.push(func);
}

/** ****************************************************************************
 * Set preference value for given preference
 *
 * @param pref
 *          The name of the preference
 * @param val
 *          The value of the preference
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.setPreference = function(pref, val) {
    this.preferences[pref].value = val;
    this.storePreference(pref, val);
}

/** ****************************************************************************
 * Store a preference to the store
 *
 * @param pref
 *          The name of the preference
 * @param val
 *          The value of the preference
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.storePreference = function(pref, val) {
    var branch = this.preferences[pref].branch;
    var type = this.preferences[pref].type;
    // remove leading branch from pref name
    pref = pref.substring(branch.root.length);

    switch (type) {
        case this.PREF_BOOL:
            branch.setBoolPref(pref, val);
            break;
        case this.PREF_STRING:
            branch.setCharPref(pref, val);
            break;
        case this.PREF_INT:
            branch.setIntPref(pref, val);
            break;
    }
}

/** ****************************************************************************
 * Unregister observer
 *
 * @return
 *          void
 ******************************************************************************/
ThreadVisNS.PreferenceObserver.prototype.unregister = function() {
    if(!this.prefBranch) {
        return;
    }

    var pbi = this.prefBranch
        .QueryInterface(Components.interfaces.nsIPrefBranch2);
    pbi.removeObserver("", this);
}
<|endoftext|>


<commit_before>/**
 * AdSense User Profile component.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import ProgressBar from '../../../components/progress-bar';
import { STORE_NAME as userStoreName } from '../../../googlesitekit/datastore/user/constants';
const { useSelect } = Data;

export default function UserProfile() {
	const userEmail = useSelect( ( select ) => select( userStoreName ).getEmail() );
	const userPicture = useSelect( ( select ) => select( userStoreName ).getPicture() );

	if ( 'undefined' === typeof userEmail || 'undefined' === typeof userPicture ) {
		return <ProgressBar small />;
	}

	return (

				{ userEmail }

	);
}
<commit_msg>Remove unhelpful alt text.<commit_after>/**
 * AdSense User Profile component.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import ProgressBar from '../../../components/progress-bar';
import { STORE_NAME as userStoreName } from '../../../googlesitekit/datastore/user/constants';
const { useSelect } = Data;

export default function UserProfile() {
	const userEmail = useSelect( ( select ) => select( userStoreName ).getEmail() );
	const userPicture = useSelect( ( select ) => select( userStoreName ).getPicture() );

	if ( 'undefined' === typeof userEmail || 'undefined' === typeof userPicture ) {
		return <ProgressBar small />;
	}

	return (

				{ userEmail }

	);
}
<|endoftext|>


<commit_before>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 * Views controller using deepjs tools and methods
 */
if (typeof define !== 'function') {
	var define = require('amdefine')(module);
}
define(["require", "deepjs/deep", "deepjs/lib/errors", "./directives"], function(require, deep, errors) {
	"use strict";

	/**
	 * view refresh sequence : arg = route params
	 * 	if(!initialised)
	 * 		init()
	 * 	then
	 * 		load(params);
	 * 			deepLoad what, how, where
	 * 		render(loaded);
	 * 			how(context);
	 * 		 	where(context);
	 * 		  	enhance(context);
	 * 		   	done(context);
	 *
	 * View remove sequence :
	 * 		remove each subs
	 * 		remove each dp-controlled
	 * 		remove html node
	 * 		clean();
	 */

	deep.errors.View = function(msg, report, fileName, lineNum) {
		if (typeof msg === 'object')
			report = msg;
		if (!msg)
			msg = "UIError";
		return errors.Error(1500, msg, report, fileName, lineNum);
	};

	deep.View = deep.Classes(function(layer) {
		if (layer)
			deep.aup(layer, this);
	}, {
		_deep_view_: true,
		fail: function(e) {
			deep.utils.dumpError(e);
			if (!this.where)
				return e;
			if (typeof this.where === 'string')
				return deep.nodes(this.where).done(function(s) {
					if (typeof s === 'function')
						s(e.toString());
					else
						$(s).replaceWith(e.toString());
					return e;
				});
			else if (typeof this.where === 'function')
				this.where(e.toString());
			else if (typeof jQuery !== 'undefined' && this.where instanceof jQuery) // WARNING : cheerio case not managed
				$(this.where).html(e.toString());
		},
		addSubControlled: function(ctrl) {
			var label = "view" + Date.now().valueOf();
			this._deep_controlled_ = this._deep_controlled_ || {};
			this._deep_controlled_[label] = ctrl;
		},
		remove: function() {
			//console.log("VIEW REMOVE : ", this.placed);
			if (this.subs)
				for (var i in this.subs)
					this.subs[i].remove();
			if (this._deep_controlled_) {
				for (var i in this._deep_controlled_)
					this._deep_controlled_[i].remove();
				this._deep_controlled_ = null;
			}
			if (this.placed) {
				// console.log("remove node : ", this, this.placed())
				deep.$(this.placed()).remove();
			}
			if (this.clean)
				this.clean();
			this.prepared = false;
			this.placed = null;
		},
		load: function(opt) {
			opt = opt || {};
			var params = opt.params,
				config = this.config || {},
				isServer = deep.context("isServer");
			//if (params && Object.keys(params).length === 0)
			//	params = null;
			if (config.scope && config.scope != "both")
				if (isServer) {
					if (config.scope != "server")
						return;
				} else if (config.scope != "browser")
				return;
			var self = this;
			if (this.init && !this.initialised)
				return deep.when(this.init())
					.done(function(success) {
						self.initialised = true;
						return self.load({
							params: params
						});
					});
			if (this.prepare && (!this.prepared || isServer))
				return deep.when(this.prepare())
					.done(function(success) {
						self.prepared = true;
						return self.load({
							params: params
						});
					});
			if (this.condition === false)
				return null;
			var promises = [],
				ctx = {
					params: params,
					context: deep.context(),
					ctrl: self
				};
			if (this.condition)
				if (typeof this.condition === "function" && !this.condition.apply(ctx))
					return null;
			if (this.what)
				promises.push(deep.nodes(this).query("./what").deepLoad(ctx, false));
			else
				promises.push(null);

			if (typeof this.how === 'string')
				promises.push(deep.nodes(this).query("./how").deepLoad(ctx, false, true));
			else
				promises.push(this.how);

			if (this.where)
				if (typeof this.where === 'string')
					promises.push(deep.nodes(this).query("./where").deepLoad(ctx, false, true));
				else
					promises.push(this.where);

				// console.log("launch deep load");
			return deep.all(promises)
				.done(function(res) {
					//console.log("view deep load : res  : ", res);
					var result = {
						_deep_render_node_: true,
						what: res[0],
						how: res[1],
						where: res[2],
						params: params
					};
					// console.log("view deep load done : ", self.how);
					return result;
				})
				.fail(function(e) {
					if (typeof self.fail === 'function')
						return self.fail(e) || e;
					return e;
				});
		},
		render: function(loaded, routeMatch, params) {
			// console.log("view render : ", loaded)
			if (!loaded)
				return;
			var self = this,
				config = this.config || {},
				isServer = deep.context("isServer");
			if (self._deep_controlled_) {
				for (var i in self._deep_controlled_)
					self._deep_controlled_[i].remove();
				self._deep_controlled_ = null;
			}
			var what = null,
				how = null,
				where = null,
				rendered = null,
				placed = null;
			if (loaded.what)
				what = loaded.what;
			if (loaded.how)
				how = loaded.how;
			if (loaded.where)
				where = loaded.where;
			what = (what && what._deep_query_node_) ? what.value : what;
			how = (how && how._deep_query_node_) ? how.value : how;
			where = (where && where._deep_query_node_) ? where.value : where;

			if (what && what._deep_ocm_)
				what = what();
			if (how && how._deep_ocm_)
				how = how();
			if (where && where._deep_ocm_)
				where = where();

			loaded.what = what;
			loaded.how = how;
			loaded.where = where;
			loaded.params = params;

			placed = self.placed ? self.placed() : null;

			loaded.placed = placed;
			loaded.ctrl = self;
			// console.log("render with : how : ", how, what)
			try {
				//console.log("WHAT : ", what);
				// console.log("HOW : ", how);
				if (routeMatch) {
					loaded.route = routeMatch;
				}
				if (typeof how === 'function')
					rendered = loaded.rendered = how.call(self, loaded);
				else if (how)
					rendered = loaded.rendered = how;
				else if (what)
					rendered = loaded.rendered = what;
				if (where && typeof where === 'function')
					placed = loaded.placed = where.call(self, loaded.rendered, loaded.placed);
				else if (typeof jQuery !== 'undefined' && where instanceof jQuery)
					placed = loaded.placed = where;
				else if (typeof where === 'string' && deep.Promise.context.$)
					placed = loaded.placed = deep.Promise.context.$(where);
				/*else
					placed = loaded.placed = null;*/
			} catch (e) {
				// console.log("error while rendering :  ",e);
				if (typeof self.fail === 'function')
					return self.fail(e) || e;
				return e;
			}

			if (placed && !isServer)
				self.placed = function() {
					// console.log("store placed : ", placed)
					return placed;
				};

			var promise = null;
			if (config.enhance !== false && placed && deep.Promise.context.$) {
				//console.log("view placed : placed = ", placed);
				if (placed._deep_html_merged_) {
					var subprom = [];
					for (var i in placed) {
						if (i === '_deep_html_merged_')
							continue;
						subprom.push(deep.ui.enhance(self, placed[i], loaded))
					}
					promise = deep.all(subprom);
				} else
					promise = deep.ui.enhance(self, placed, loaded);
			}

			//console.log("rendered : ", loaded);
			if (promise)
				return promise
					.done(function() {
						if (config.relink !== false && !isServer && placed && self.relink)
							self.relink(placed);
						if (typeof self.done === "function") {
							var done = self.done;
							if (done._deep_ocm_)
								done = done();
							return done.call(self, loaded) || loaded;
						}
						return loaded;
					})
					.fail(function(e) {
						if (typeof self.fail === 'function')
							return self.fail(e) || e;
						return e;
					});

			//if(config.relink == false)
			//	console.log("skip relink on : ", self);
			if (config.relink !== false && !isServer && placed && self.relink)
				self.relink(placed);
			if (typeof self.done === "function") {
				var done = self.done;
				if (done._deep_ocm_)
					done = done();
				return done.call(self, loaded) || loaded;
			}
			return loaded;
		},
		refresh: function(arg /* params, loaded, routeMatch */ ) {
			var config = this.config || {},
				isServer = deep.context("isServer");
			if (config.scope && config.scope != "both")
				if (!isServer) {
					if (config.scope != "browser")
						return;
				} else
			if (config.scope != "server")
				return;
			// console.log("view refresh : params : ", params, " - loaded : ", loaded);
			var self = this;
			if (this.init && !this.initialised)
				return deep.when(this.init())
					.done(function(success) {
						self.initialised = true;
						return self.refresh(arg);
					});
			if (this.prepare && (isServer || !this.prepared))
				return deep.when(this.prepare())
					.done(function(success) {
						self.prepared = true;
						return self.refresh(arg);
					});
			var loaded, params, routeMatch;
			if (arg)
				if (arg._deep_render_node_) {
					loaded = arg;
					params = loaded.params;
				} else
			if (arg._deep_matched_node_) {
				loaded = arg.loaded;
				params = arg.output;

				routeMatch = arg;
			} else
				params = arg;
			params = params || this.params;
			if (params && !isServer)
				this.params = params;

			var p;
			if (loaded)
				p = deep.when(this.render(loaded, routeMatch, params))
				.fail(function(e) {
					if (typeof self.fail === 'function') {
						var fail = self.fail;
						if (fail._deep_ocm_)
							fail = fail();
						return fail.call(self, e) || e;
					}
				});
			else
				p = deep.when(this.load({
					params: params
				}))
				.done(function(loaded) {
					return self.render(loaded, routeMatch, params);
				})
				.fail(function(e) {
					if (typeof self.fail === 'function') {
						var fail = self.fail;
						if (fail._deep_ocm_)
							fail = fail();
						return fail.call(self, e) || e;
					}
				});
			return p;
		},
		relink: function(selector) {
			if(deep.context("isServer"))
				return;
			var app = deep.currentApp(),
				$ = deep.$();
			if($)
				$(selector)
					.find(this.relinkSelector || "a")
					.each(function() {
						if (this._deep_rerouted_)
							return;
						this._deep_rerouted_ = true;

						var uri = $(this).attr("href");
						if (!uri)
							return;
						if (uri.substring(0, 4) === 'http')
							return;
						if (uri[0] == '/' && uri[1] == '/') // file
							return;
						// console.log("RELINK : ", uri, this);
						$(this).click(function(e) {
							if (e && e.preventDefault)
								e.preventDefault();
							deep.app(app).when(app.views.get(uri)).elog();
							return false;
						});
					});
		}
	});

	deep.View.relink = function(selector, relinkSelector) {
		// console.log("relink : ", selector);
		return deep.View.prototype.relink.call({
			relinkSelector: relinkSelector
		}, selector);
	};
	deep.coreUnits = deep.coreUnits || [];
	deep.coreUnits.push("js::deep-views/units/views");
	return deep.View;
});<commit_msg>isolate try/catch from render (for js compiler optimisation)<commit_after>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 * Views controller using deepjs tools and methods
 */
if (typeof define !== 'function') {
	var define = require('amdefine')(module);
}
define(["require", "deepjs/deep", "deepjs/lib/errors", "./directives"], function(require, deep, errors) {
	"use strict";

	/**
	 * view refresh sequence : arg = route params
	 * 	if(!initialised)
	 * 		init()
	 * 	then
	 * 		load(params);
	 * 			deepLoad what, how, where
	 * 		render(loaded);
	 * 			how(context);
	 * 		 	where(context);
	 * 		  	enhance(context);
	 * 		   	done(context);
	 *
	 * View remove sequence :
	 * 		remove each subs
	 * 		remove each dp-controlled
	 * 		remove html node
	 * 		clean();
	 */

	 var applyRender = function(self, loaded, routeMatch, params) {
		// console.log("view render : ", loaded)
		if (!loaded)
			return;
		var config = self.config || {},
			isServer = deep.context("isServer");
		if (self._deep_controlled_) {
			for (var i in self._deep_controlled_)
				self._deep_controlled_[i].remove();
			self._deep_controlled_ = null;
		}
		var what = null,
			how = null,
			where = null,
			rendered = null,
			placed = null;
		if (loaded.what)
			what = loaded.what;
		if (loaded.how)
			how = loaded.how;
		if (loaded.where)
			where = loaded.where;
		what = (what && what._deep_query_node_) ? what.value : what;
		how = (how && how._deep_query_node_) ? how.value : how;
		where = (where && where._deep_query_node_) ? where.value : where;

		if (what && what._deep_ocm_)
			what = what();
		if (how && how._deep_ocm_)
			how = how();
		if (where && where._deep_ocm_)
			where = where();

		loaded.what = what;
		loaded.how = how;
		loaded.where = where;
		loaded.params = params;

		placed = self.placed ? self.placed() : null;

		loaded.placed = placed;
		loaded.ctrl = self;
		// console.log("render with : how : ", how, what)
			//console.log("WHAT : ", what);
			// console.log("HOW : ", how);
			if (routeMatch) {
				loaded.route = routeMatch;
			}
			if (typeof how === 'function')
				rendered = loaded.rendered = how.call(self, loaded);
			else if (how)
				rendered = loaded.rendered = how;
			else if (what)
				rendered = loaded.rendered = what;
			if (where && typeof where === 'function')
				placed = loaded.placed = where.call(self, loaded.rendered, loaded.placed);
			else if (typeof jQuery !== 'undefined' && where instanceof jQuery)
				placed = loaded.placed = where;
			else if (typeof where === 'string' && deep.Promise.context.$)
				placed = loaded.placed = deep.Promise.context.$(where);
			/*else
				placed = loaded.placed = null;*/

		if (placed && !isServer)
			self.placed = function() {
				// console.log("store placed : ", placed)
				return placed;
			};

		var promise = null;
		if (config.enhance !== false && placed && deep.Promise.context.$) {
			//console.log("view placed : placed = ", placed);
			if (placed._deep_html_merged_) {
				var subprom = [];
				for (var i in placed) {
					if (i === '_deep_html_merged_')
						continue;
					subprom.push(deep.ui.enhance(self, placed[i], loaded))
				}
				promise = deep.all(subprom);
			} else
				promise = deep.ui.enhance(self, placed, loaded);
		}

		//console.log("rendered : ", loaded);
		if (promise)
			return promise
				.done(function() {
					if (config.relink !== false && !isServer && placed && self.relink)
						self.relink(placed);
					if (typeof self.done === "function") {
						var done = self.done;
						if (done._deep_ocm_)
							done = done();
						return done.call(self, loaded) || loaded;
					}
					return loaded;
				})
				.fail(function(e) {
					if (typeof self.fail === 'function')
						return self.fail(e) || e;
					return e;
				});

		//if(config.relink == false)
		//	console.log("skip relink on : ", self);
		if (config.relink !== false && !isServer && placed && self.relink)
			self.relink(placed);
		if (typeof self.done === "function") {
			var done = self.done;
			if (done._deep_ocm_)
				done = done();
			return done.call(self, loaded) || loaded;
		}
		return loaded;
	};

	deep.errors.View = function(msg, report, fileName, lineNum) {
		if (typeof msg === 'object')
			report = msg;
		if (!msg)
			msg = "UIError";
		return errors.Error(1500, msg, report, fileName, lineNum);
	};

	deep.View = deep.Classes(function(layer) {
		if (layer)
			deep.aup(layer, this);
	}, {
		_deep_view_: true,
		fail: function(e) {
			deep.utils.dumpError(e);
			if (!this.where)
				return e;
			if (typeof this.where === 'string')
				return deep.nodes(this.where).done(function(s) {
					if (typeof s === 'function')
						s(e.toString());
					else
						$(s).replaceWith(e.toString());
					return e;
				});
			else if (typeof this.where === 'function')
				this.where(e.toString());
			else if (typeof jQuery !== 'undefined' && this.where instanceof jQuery) // WARNING : cheerio case not managed
				$(this.where).html(e.toString());
		},
		addSubControlled: function(ctrl) {
			var label = "view" + Date.now().valueOf();
			this._deep_controlled_ = this._deep_controlled_ || {};
			this._deep_controlled_[label] = ctrl;
		},
		remove: function() {
			//console.log("VIEW REMOVE : ", this.placed);
			if (this.subs)
				for (var i in this.subs)
					this.subs[i].remove();
			if (this._deep_controlled_) {
				for (var i in this._deep_controlled_)
					this._deep_controlled_[i].remove();
				this._deep_controlled_ = null;
			}
			if (this.placed) {
				// console.log("remove node : ", this, this.placed())
				deep.$(this.placed()).remove();
			}
			if (this.clean)
				this.clean();
			this.prepared = false;
			this.placed = null;
		},
		load: function(opt) {
			opt = opt || {};
			var params = opt.params,
				config = this.config || {},
				isServer = deep.context("isServer");
			//if (params && Object.keys(params).length === 0)
			//	params = null;
			if (config.scope && config.scope != "both")
				if (isServer) {
					if (config.scope != "server")
						return;
				} else if (config.scope != "browser")
				return;
			var self = this;
			if (this.init && !this.initialised)
				return deep.when(this.init())
					.done(function(success) {
						self.initialised = true;
						return self.load({
							params: params
						});
					});
			if (this.prepare && (!this.prepared || isServer))
				return deep.when(this.prepare())
					.done(function(success) {
						self.prepared = true;
						return self.load({
							params: params
						});
					});
			if (this.condition === false)
				return null;
			var promises = [],
				ctx = {
					params: params,
					context: deep.context(),
					ctrl: self
				};
			if (this.condition)
				if (typeof this.condition === "function" && !this.condition.apply(ctx))
					return null;
			if (this.what)
				promises.push(deep.nodes(this).query("./what").deepLoad(ctx, false));
			else
				promises.push(null);

			if (typeof this.how === 'string')
				promises.push(deep.nodes(this).query("./how").deepLoad(ctx, false, true));
			else
				promises.push(this.how);

			if (this.where)
				if (typeof this.where === 'string')
					promises.push(deep.nodes(this).query("./where").deepLoad(ctx, false, true));
				else
					promises.push(this.where);

				// console.log("launch deep load");
			return deep.all(promises)
				.done(function(res) {
					//console.log("view deep load : res  : ", res);
					var result = {
						_deep_render_node_: true,
						what: res[0],
						how: res[1],
						where: res[2],
						params: params
					};
					// console.log("view deep load done : ", self.how);
					return result;
				})
				.fail(function(e) {
					if (typeof self.fail === 'function')
						return self.fail(e) || e;
					return e;
				});
		},
		render : function(loaded, routeMatch, params){
			try{
				return applyRender(this, loaded, routeMatch, params);
			}
			catch(e){
				deep.error("error catched while view.render : ", e);
				if (this.fail)
					return this.fail(e) || e;
				return e;
			}
		},
		refresh: function(arg /* params, loaded, routeMatch */ ) {
			var config = this.config || {},
				isServer = deep.context("isServer");
			if (config.scope && config.scope != "both")
				if (!isServer) {
					if (config.scope != "browser")
						return;
				} else
			if (config.scope != "server")
				return;
			// console.log("view refresh : params : ", params, " - loaded : ", loaded);
			var self = this;
			if (this.init && !this.initialised)
				return deep.when(this.init())
					.done(function(success) {
						self.initialised = true;
						return self.refresh(arg);
					});
			if (this.prepare && (isServer || !this.prepared))
				return deep.when(this.prepare())
					.done(function(success) {
						self.prepared = true;
						return self.refresh(arg);
					});
			var loaded, params, routeMatch;
			if (arg)
				if (arg._deep_render_node_) {
					loaded = arg;
					params = loaded.params;
				} else
			if (arg._deep_matched_node_) {
				loaded = arg.loaded;
				params = arg.output;

				routeMatch = arg;
			} else
				params = arg;
			params = params || this.params;
			if (params && !isServer)
				this.params = params;

			var p;
			if (loaded)
				p = deep.when(this.render(loaded, routeMatch, params))
				.fail(function(e) {
					if (typeof self.fail === 'function') {
						var fail = self.fail;
						if (fail._deep_ocm_)
							fail = fail();
						return fail.call(self, e) || e;
					}
				});
			else
				p = deep.when(this.load({
					params: params
				}))
				.done(function(loaded) {
					return self.render(loaded, routeMatch, params);
				})
				.fail(function(e) {
					if (typeof self.fail === 'function') {
						var fail = self.fail;
						if (fail._deep_ocm_)
							fail = fail();
						return fail.call(self, e) || e;
					}
				});
			return p;
		},
		relink: function(selector) {
			if(deep.context("isServer"))
				return;
			var app = deep.currentApp(),
				$ = deep.$();
			if($)
				$(selector)
					.find(this.relinkSelector || "a")
					.each(function() {
						if (this._deep_rerouted_)
							return;
						this._deep_rerouted_ = true;

						var uri = $(this).attr("href");
						if (!uri)
							return;
						if (uri.substring(0, 4) === 'http')
							return;
						if (uri[0] == '/' && uri[1] == '/') // file
							return;
						// console.log("RELINK : ", uri, this);
						$(this).click(function(e) {
							if (e && e.preventDefault)
								e.preventDefault();
							deep.app(app).when(app.views.get(uri)).elog();
							return false;
						});
					});
		}
	});

	deep.View.relink = function(selector, relinkSelector) {
		// console.log("relink : ", selector);
		return deep.View.prototype.relink.call({
			relinkSelector: relinkSelector
		}, selector);
	};
	deep.coreUnits = deep.coreUnits || [];
	deep.coreUnits.push("js::deep-views/units/views");
	return deep.View;
});<|endoftext|>


<commit_before>
  // returns how much "power" a user's votes have
  var getVotePower = function(user){
    // return (user && user.isAdmin) ? 5 : 1;
    return 1; // for now, leave everybody at 1 including admins; 5 is too unbalanced
  };

  var modifyKarma = function(userId, karma){
    Meteor.users.update({_id: userId}, {$inc: {karma: karma}});
  };

  var hasUpvotedItem= function(item, user){
    return item.upvoters && item.upvoters.indexOf(user._id) != -1;
  };

  var hasDownvotedItem= function(item, user){
    return item.downvoters && item.downvoters.indexOf(user._id) != -1;
  };

  var upvoteItem = function(collection, item) {
    var user = Meteor.user(),
        votePower = getVotePower(user);

    // make sure user has rights to upvote first
    if (!user || !canUpvote(user, collection, true)  || hasUpvotedItem(item, user))
      return false;

    // if user is upvoting a previously downvoted item, cancel downvote first
    if (hasDownvotedItem(item, user))
      cancelDownvote(collection, item, user);

    // Votes & Score
    var result = collection.update({_id: item && item._id},{
      $addToSet: {upvoters: user._id},
      $pull: {downvoters: user._id},
      $inc: {votes: 1, baseScore: votePower},
      $set: {inactive: false}
    });

    // extend item with baseScore to help calculate newScore
    item = _.extend(item, {baseScore: (item.baseScore + votePower)});
    updateScore({collection: collection, item: item, forceUpdate: true});

    // if the item is being upvoted by its own author, don't give karma
    if (item.userId != user._id){
      modifyKarma(item.userId, votePower);

      // if karma redistribution is enabled, give karma to all previous upvoters of the post
      // (but not to the person doing the upvoting)
      if(getSetting('redistributeKarma', false)){
        _.each(item.upvoters, function(upvoterId){
          // share the karma equally among all upvoters, but cap the value at 0.1
          var karmaIncrease = Math.min(0.1, votePower/item.upvoters.length);
          modifyKarma(upvoterId, 0.1);
        });
      }
    }
    return true;
  };

  var downvoteItem = function(collection, item) {
    var user = Meteor.user(),
        votePower = getVotePower(user);

    // make sure user has rights to downvote first
    if (!user || !canDownvote(user, collection, true)  || hasDownvotedItem(item, user))
      return false;

    // if user is downvoting a previously upvoted item, cancel upvote first
    if (hasUpvotedItem(item, user))
      cancelUpvote(collection, item, user);

    // Votes & Score
    collection.update({_id: item && item._id},{
      $addToSet: {downvoters: user._id},
      $pull: {upvoters: user._id},
      $inc: {votes: -1, baseScore: -votePower},
      $set: {inactive: false}
    });

    // extend item with baseScore to help calculate newScore
    item = _.extend(item, {baseScore: (item.baseScore + votePower)});
    updateScore({collection: collection, item: item, forceUpdate: true});

    // if the item is being upvoted by its own author, don't give karma
    if (item.userId != user._id)
      modifyKarma(item.userId, votePower);

    return true;
  };

  var cancelUpvote = function(collection, item) {
    var user = Meteor.user();
        votePower = getVotePower(user);

    // if user isn't among the upvoters, abort
    if(!hasUpvotedItem(item, user))
      return false;

    // Votes & Score
    collection.update({_id: item && item._id},{
      $pull: {upvoters: user._id},
      $inc: {votes: -1, baseScore: -votePower},
      $set: {inactive: false}
    });

    // extend item with baseScore to help calculate newScore
    item = _.extend(item, {baseScore: (item.baseScore + votePower)});
    updateScore({collection: collection, item: item, forceUpdate: true});

    // if the item is being upvoted by its own author, don't give karma
    if (item.userId != user._id)
      modifyKarma(item.userId, votePower);

    return true;
  };

  var cancelDownvote = function(collection, item) {
    var user = Meteor.user(),
      votePower = getVotePower(user);

    // if user isn't among the downvoters, abort
    if(!hasUpvotedItem(item, user))
      return false;

    // Votes & Score
    collection.update({_id: item && item._id},{
      $pull: {downvoters: user._id},
      $inc: {votes: 1, baseScore: votePower},
      $set: {inactive: false}
    });

    // extend item with baseScore to help calculate newScore
    item = _.extend(item, {baseScore: (item.baseScore + votePower)});
    updateScore({collection: collection, item: item, forceUpdate: true});

    // if the item is being upvoted by its own author, don't give karma
    if (item.userId != user._id)
      modifyKarma(item.userId, votePower);

    return true;
  };

  // note: doesn't actually seem very useful to enable admins to vote for other users. Remove this?
  var getUser = function(user){
    // only let admins specify different users for voting
    // if no user is specified, use current user by default
    return (isAdmin(Meteor.user()) && typeof user !== 'undefined') ? user : Meteor.user();
  };

  Meteor.methods({
    upvotePost: function(post, user){
      return upvoteItem.call(this, Posts, post);
    },
    downvotePost: function(post, user){
      return downvoteItem.call(this, Posts, post);
    },
    cancelUpvotePost: function(post, user){
      return cancelUpvote.call(this, Posts, post);
    },
    cancelDownvotePost: function(post, user){
      return cancelDownvote.call(this, Posts, post);
    },
    upvoteComment: function(comment, user){
      return upvoteItem.call(this, Comments, comment);
    },
    downvoteComment: function(comment, user){
      return upvoteItem.call(this, Comments, comment);
    },
    cancelUpvoteComment: function(comment, user){
      return cancelUpvote.call(this, Comments, comment);
    },
    cancelDownvoteComment: function(comment, user){
      return cancelDownvote.call(this, Comments, comment);
    }
  });
<commit_msg>fix for downvoting comments<commit_after>
  // returns how much "power" a user's votes have
  var getVotePower = function(user){
    // return (user && user.isAdmin) ? 5 : 1;
    return 1; // for now, leave everybody at 1 including admins; 5 is too unbalanced
  };

  var modifyKarma = function(userId, karma){
    Meteor.users.update({_id: userId}, {$inc: {karma: karma}});
  };

  var hasUpvotedItem= function(item, user){
    return item.upvoters && item.upvoters.indexOf(user._id) != -1;
  };

  var hasDownvotedItem= function(item, user){
    return item.downvoters && item.downvoters.indexOf(user._id) != -1;
  };

  var upvoteItem = function(collection, item) {
    var user = Meteor.user(),
        votePower = getVotePower(user);

    // make sure user has rights to upvote first
    if (!user || !canUpvote(user, collection, true)  || hasUpvotedItem(item, user))
      return false;

    // if user is upvoting a previously downvoted item, cancel downvote first
    if (hasDownvotedItem(item, user))
      cancelDownvote(collection, item, user);

    // Votes & Score
    var result = collection.update({_id: item && item._id},{
      $addToSet: {upvoters: user._id},
      $pull: {downvoters: user._id},
      $inc: {votes: 1, baseScore: votePower},
      $set: {inactive: false}
    });

    // extend item with baseScore to help calculate newScore
    item = _.extend(item, {baseScore: (item.baseScore + votePower)});
    updateScore({collection: collection, item: item, forceUpdate: true});

    // if the item is being upvoted by its own author, don't give karma
    if (item.userId != user._id){
      modifyKarma(item.userId, votePower);

      // if karma redistribution is enabled, give karma to all previous upvoters of the post
      // (but not to the person doing the upvoting)
      if(getSetting('redistributeKarma', false)){
        _.each(item.upvoters, function(upvoterId){
          // share the karma equally among all upvoters, but cap the value at 0.1
          var karmaIncrease = Math.min(0.1, votePower/item.upvoters.length);
          modifyKarma(upvoterId, 0.1);
        });
      }
    }
    return true;
  };

  var downvoteItem = function(collection, item) {
    var user = Meteor.user(),
        votePower = getVotePower(user);

    // make sure user has rights to downvote first
    if (!user || !canDownvote(user, collection, true)  || hasDownvotedItem(item, user))
      return false;

    // if user is downvoting a previously upvoted item, cancel upvote first
    if (hasUpvotedItem(item, user))
      cancelUpvote(collection, item, user);

    // Votes & Score
    collection.update({_id: item && item._id},{
      $addToSet: {downvoters: user._id},
      $pull: {upvoters: user._id},
      $inc: {votes: -1, baseScore: -votePower},
      $set: {inactive: false}
    });

    // extend item with baseScore to help calculate newScore
    item = _.extend(item, {baseScore: (item.baseScore + votePower)});
    updateScore({collection: collection, item: item, forceUpdate: true});

    // if the item is being upvoted by its own author, don't give karma
    if (item.userId != user._id)
      modifyKarma(item.userId, votePower);

    return true;
  };

  var cancelUpvote = function(collection, item) {
    var user = Meteor.user();
        votePower = getVotePower(user);

    // if user isn't among the upvoters, abort
    if(!hasUpvotedItem(item, user))
      return false;

    // Votes & Score
    collection.update({_id: item && item._id},{
      $pull: {upvoters: user._id},
      $inc: {votes: -1, baseScore: -votePower},
      $set: {inactive: false}
    });

    // extend item with baseScore to help calculate newScore
    item = _.extend(item, {baseScore: (item.baseScore + votePower)});
    updateScore({collection: collection, item: item, forceUpdate: true});

    // if the item is being upvoted by its own author, don't give karma
    if (item.userId != user._id)
      modifyKarma(item.userId, votePower);

    return true;
  };

  var cancelDownvote = function(collection, item) {
    var user = Meteor.user(),
      votePower = getVotePower(user);

    // if user isn't among the downvoters, abort
    if(!hasUpvotedItem(item, user))
      return false;

    // Votes & Score
    collection.update({_id: item && item._id},{
      $pull: {downvoters: user._id},
      $inc: {votes: 1, baseScore: votePower},
      $set: {inactive: false}
    });

    // extend item with baseScore to help calculate newScore
    item = _.extend(item, {baseScore: (item.baseScore + votePower)});
    updateScore({collection: collection, item: item, forceUpdate: true});

    // if the item is being upvoted by its own author, don't give karma
    if (item.userId != user._id)
      modifyKarma(item.userId, votePower);

    return true;
  };

  // note: doesn't actually seem very useful to enable admins to vote for other users. Remove this?
  var getUser = function(user){
    // only let admins specify different users for voting
    // if no user is specified, use current user by default
    return (isAdmin(Meteor.user()) && typeof user !== 'undefined') ? user : Meteor.user();
  };

  Meteor.methods({
    upvotePost: function(post, user){
      return upvoteItem.call(this, Posts, post);
    },
    downvotePost: function(post, user){
      return downvoteItem.call(this, Posts, post);
    },
    cancelUpvotePost: function(post, user){
      return cancelUpvote.call(this, Posts, post);
    },
    cancelDownvotePost: function(post, user){
      return cancelDownvote.call(this, Posts, post);
    },
    upvoteComment: function(comment, user){
      return upvoteItem.call(this, Comments, comment);
    },
    downvoteComment: function(comment, user){
      return downvoteItem.call(this, Comments, comment);
    },
    cancelUpvoteComment: function(comment, user){
      return cancelUpvote.call(this, Comments, comment);
    },
    cancelDownvoteComment: function(comment, user){
      return cancelDownvote.call(this, Comments, comment);
    }
  });
<|endoftext|>


<commit_before>app.controller('UserCtrl', function ($scope, $http, ModalService, authService, mediaService, queueService, toastr) {
  $scope.expand = false;
  $scope.searchResults = [];
  $scope.isSearching = false;
  $scope.isLoading = false;
  $scope.playlists={
    'Default':{
      Name:"Default", Active:true, Contents:[]
    }
  };
  $scope.playlistName="Default";
  $scope.joined=false;

  $scope.isAdding = false;
  $scope.userData = {};
  $scope.newPlaylist = {};
  $scope.addingPlaylist=false;

  fetch_playlist();

  function fetch_playlist(){
    if(!authService.getUser()){
      return;
    }
    $http.get('/api/playlists').then(function(res){
      var data = res.data;
      if(data.Success){
        $scope.playlists = data.Playlists;
        for(var pl in data.Playlists){
          if(data.Playlists[pl].Active){
            $scope.playlistName = data.Playlists[pl].Name;
            break;
          }
        }
      }
      else{
        toastr.error(data.Error, 'Problem retrieving playlist');
      }
    }, function(err){
      toastr.error(err, 'Problem retrieving playlist');
    });
  }

  mediaService.on('nextSong_fetch', function(){
    var vidinfo = $scope.playlists[$scope.playlistName].Contents.shift();
    mediaService.emit('nextSong_response', vidinfo);
    $scope.playlists[$scope.playlistName].Contents.push(vidinfo);
    $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(res){
      var data = res.data;
      if(data.Success){}
      else{
        console.log(data.Error);
      }
    },function(err){
      console.log(err);
    });
  });

  mediaService.on('queue_kick', function(){
    $scope.joined=false;
    toastr.error('You have been removed from the queue');
  });

  /*
  * Client Methods
  */
  $scope.search=function(){
    $scope.isSearching=true;
    $scope.isLoading = true;
    var cleancrit = encodeURIComponent($scope.searchCriteria.query);
    $http.get('/api/search/'+cleancrit)
    .then(function(res){
      var data = res.data;
      if(data.Success){
        $scope.searchResults = data.Videos;
      }
      else{
        console.log(data.Error);
        toastr.error('Error completing search');
      }
      $scope.isLoading = false;
    },function(error){
      $scope.isLoading = false;
      toastr.error('Error completing search');
      console.log(error);
    });
  };

  $scope.viewPlaylist=function(name){
    if($scope.playlistName && $scope.playlistName!==name){
      $scope.playlists[$scope.playlistName].Active=false;
    }
    $scope.playlistName=name;
    $scope.playlists[$scope.playlistName].Active=true;
    $scope.isSearching = false;
    $http.post('/api/playlists/setActive', $scope.playlists[name]).then(function(res){
      var data = res.data;
      if(data.Success){
        console.log('new playlist activated');
      }
      else{
        console.log(data.Error);
      }
    });
  };

  $scope.addToPlaylist=function(vidinfo){
    if(!vidinfo){
      return;
    }
    if($scope.playlists[$scope.playlistName].Contents.indexOf(vidinfo) > -1){
      toastr.error('Song already exists in playlist');
      return;
    }
    $scope.playlists[$scope.playlistName].Contents.unshift(vidinfo);
    $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(res){
      if(res.data.Success){
        toastr.success('Song Added to Playlist: ' + $scope.playlistName);
        console.log('playlist updated');
      }
      else{
        console.log(res.data.Error);
      }
    }, function(err){
      console.log(err);
    });
  };

  $scope.removeFromPlaylist=function(ind){
    var item = $scope.playlists[$scope.playlistName].Contents.splice(ind, 1)[0];
    $http.post('/api/playlists/removeItem', {PlaylistName: $scope.playlistName, VideoID: item.ID}).then(function(res){
      var data = res.data;
      if(data.Success){
        console.log('Playlist updated');
      }
      else{
        console.log(data.Error);
      }
    }, function(err){
      console.log(err);
    });
  };

  $scope.moveUp=function(ind){
    var item = $scope.playlists[$scope.playlistName].Contents[ind];
    $scope.playlists[$scope.playlistName].Contents.splice(ind, 1);
    $scope.playlists[$scope.playlistName].Contents.unshift(item);
    $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(res){
      var data = res.data;
      if(data.Success){
        console.log('Playlist updated');
      }
      else{
        console.log(data.Error);
      }
    }, function(err){
      console.log(err);
    });
  };

  $scope.moveDown=function(ind){
    var item = $scope.playlists[$scope.playlistName].Contents[ind];
    $scope.playlists[$scope.playlistName].Contents.splice(ind, 1);
    $scope.playlists[$scope.playlistName].Contents.push(item);
    $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(res){
      var data = res.data;
      if(data.Success){
        console.log('Playlist updated');
      }
      else{
        console.log(data.Error);
      }
    }, function(err){
      console.log(err);
    });
  };

  $scope.addPlaylist=function(){
    $scope.addingPlaylist = true;
    $scope.newPlaylist = {};
  };

  $scope.cancelPlaylistAdd=function(){
    $scope.addingPlaylist = false;
    $scope.newPlaylist = {};
  };

  $scope.registerPlaylist=function(){
    $http.post('/api/playlists/', $scope.newPlaylist).then(function(res){
      var data = res.data;
      if(data.Success){
        $scope.addingPlaylist=false;
        $scope.newPlaylist = {};
        fetch_playlist();
        toastr.success('Added Playlist!');
      }
      else{
        toastr.error(data.Error);
      }
    }, function(err){
      toastr.err('Error connecting to API');
    });
  };

  $scope.joinLeaveQueue=function(){
    if($scope.joined){
      $scope.joined = false;
      var user = authService.getUser();
      if(user){
        console.log('exiting queue');
        $http.delete('/api/radio/queue/'+user.Username).then(function(res){
          var data = res.data;
          if(data.Success){
            return;
          }
          else{
            console.log(data.Error);
            return;
          }
        }, function(err){
          console.log(err);
          return;
        });
      }
    }
    else{
      $scope.joined = true;
      $http.post('/api/radio/queue')
      .then(function(res){
        var data = res.data;
        if(data.Success){
          console.log('added to queue');
        }
        else{
          $scope.joined=false;
          toastr.error(data.Error, 'Could not join Queue');
          console.log(data.Error);
        }
      }, function(err){
        $scope.joined=false;
        console.log(err);
      });
    }
  };

  $scope.login=function(){
    ModalService.showModal({
      templateUrl: "views/auth.html",
      controller: "AuthCtrl"
    }).then(function(modal) {
      modal.element.modal();
      modal.close.then(function(result) {
        fetch_playlist();
        $scope.joined=false;
      });
    });
  };

  $scope.logOut=function(){
    authService.logOut();
  };

  $scope.getUser=function(){
    return authService.getUser();
  };

  $scope.$on('session_resume', function(){
    console.log('resuming session in progress');
    fetch_playlist();
    $scope.joined=false;
  });

});
<commit_msg>don't try to save a playlist change if its empty<commit_after>app.controller('UserCtrl', function ($scope, $http, ModalService, authService, mediaService, queueService, toastr) {
  $scope.expand = false;
  $scope.searchResults = [];
  $scope.isSearching = false;
  $scope.isLoading = false;
  $scope.playlists={
    'Default':{
      Name:"Default", Active:true, Contents:[]
    }
  };
  $scope.playlistName="Default";
  $scope.joined=false;

  $scope.isAdding = false;
  $scope.userData = {};
  $scope.newPlaylist = {};
  $scope.addingPlaylist=false;

  fetch_playlist();

  function fetch_playlist(){
    if(!authService.getUser()){
      return;
    }
    $http.get('/api/playlists').then(function(res){
      var data = res.data;
      if(data.Success){
        $scope.playlists = data.Playlists;
        for(var pl in data.Playlists){
          if(data.Playlists[pl].Active){
            $scope.playlistName = data.Playlists[pl].Name;
            break;
          }
        }
      }
      else{
        toastr.error(data.Error, 'Problem retrieving playlist');
      }
    }, function(err){
      toastr.error(err, 'Problem retrieving playlist');
    });
  }

  mediaService.on('nextSong_fetch', function(){
    var vidinfo = $scope.playlists[$scope.playlistName].Contents.shift();
    mediaService.emit('nextSong_response', vidinfo);
    if(vidinfo){
      $scope.playlists[$scope.playlistName].Contents.push(vidinfo);
      $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(res){
        var data = res.data;
        if(data.Success){}
        else{
          console.log(data.Error);
        }
      },function(err){
        console.log(err);
      });
    }
  });

  mediaService.on('queue_kick', function(){
    $scope.joined=false;
    toastr.error('You have been removed from the queue');
  });

  /*
  * Client Methods
  */
  $scope.search=function(){
    $scope.isSearching=true;
    $scope.isLoading = true;
    var cleancrit = encodeURIComponent($scope.searchCriteria.query);
    $http.get('/api/search/'+cleancrit)
    .then(function(res){
      var data = res.data;
      if(data.Success){
        $scope.searchResults = data.Videos;
      }
      else{
        console.log(data.Error);
        toastr.error('Error completing search');
      }
      $scope.isLoading = false;
    },function(error){
      $scope.isLoading = false;
      toastr.error('Error completing search');
      console.log(error);
    });
  };

  $scope.viewPlaylist=function(name){
    if($scope.playlistName && $scope.playlistName!==name){
      $scope.playlists[$scope.playlistName].Active=false;
    }
    $scope.playlistName=name;
    $scope.playlists[$scope.playlistName].Active=true;
    $scope.isSearching = false;
    $http.post('/api/playlists/setActive', $scope.playlists[name]).then(function(res){
      var data = res.data;
      if(data.Success){
        console.log('new playlist activated');
      }
      else{
        console.log(data.Error);
      }
    });
  };

  $scope.addToPlaylist=function(vidinfo){
    if(!vidinfo){
      return;
    }
    if($scope.playlists[$scope.playlistName].Contents.indexOf(vidinfo) > -1){
      toastr.error('Song already exists in playlist');
      return;
    }
    $scope.playlists[$scope.playlistName].Contents.unshift(vidinfo);
    $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(res){
      if(res.data.Success){
        toastr.success('Song Added to Playlist: ' + $scope.playlistName);
        console.log('playlist updated');
      }
      else{
        console.log(res.data.Error);
      }
    }, function(err){
      console.log(err);
    });
  };

  $scope.removeFromPlaylist=function(ind){
    var item = $scope.playlists[$scope.playlistName].Contents.splice(ind, 1)[0];
    $http.post('/api/playlists/removeItem', {PlaylistName: $scope.playlistName, VideoID: item.ID}).then(function(res){
      var data = res.data;
      if(data.Success){
        console.log('Playlist updated');
      }
      else{
        console.log(data.Error);
      }
    }, function(err){
      console.log(err);
    });
  };

  $scope.moveUp=function(ind){
    var item = $scope.playlists[$scope.playlistName].Contents[ind];
    $scope.playlists[$scope.playlistName].Contents.splice(ind, 1);
    $scope.playlists[$scope.playlistName].Contents.unshift(item);
    $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(res){
      var data = res.data;
      if(data.Success){
        console.log('Playlist updated');
      }
      else{
        console.log(data.Error);
      }
    }, function(err){
      console.log(err);
    });
  };

  $scope.moveDown=function(ind){
    var item = $scope.playlists[$scope.playlistName].Contents[ind];
    $scope.playlists[$scope.playlistName].Contents.splice(ind, 1);
    $scope.playlists[$scope.playlistName].Contents.push(item);
    $http.post('/api/playlists/update', $scope.playlists[$scope.playlistName]).then(function(res){
      var data = res.data;
      if(data.Success){
        console.log('Playlist updated');
      }
      else{
        console.log(data.Error);
      }
    }, function(err){
      console.log(err);
    });
  };

  $scope.addPlaylist=function(){
    $scope.addingPlaylist = true;
    $scope.newPlaylist = {};
  };

  $scope.cancelPlaylistAdd=function(){
    $scope.addingPlaylist = false;
    $scope.newPlaylist = {};
  };

  $scope.registerPlaylist=function(){
    $http.post('/api/playlists/', $scope.newPlaylist).then(function(res){
      var data = res.data;
      if(data.Success){
        $scope.addingPlaylist=false;
        $scope.newPlaylist = {};
        fetch_playlist();
        toastr.success('Added Playlist!');
      }
      else{
        toastr.error(data.Error);
      }
    }, function(err){
      toastr.err('Error connecting to API');
    });
  };

  $scope.joinLeaveQueue=function(){
    if($scope.joined){
      $scope.joined = false;
      var user = authService.getUser();
      if(user){
        console.log('exiting queue');
        $http.delete('/api/radio/queue/'+user.Username).then(function(res){
          var data = res.data;
          if(data.Success){
            return;
          }
          else{
            console.log(data.Error);
            return;
          }
        }, function(err){
          console.log(err);
          return;
        });
      }
    }
    else{
      $scope.joined = true;
      $http.post('/api/radio/queue')
      .then(function(res){
        var data = res.data;
        if(data.Success){
          console.log('added to queue');
        }
        else{
          $scope.joined=false;
          toastr.error(data.Error, 'Could not join Queue');
          console.log(data.Error);
        }
      }, function(err){
        $scope.joined=false;
        console.log(err);
      });
    }
  };

  $scope.login=function(){
    ModalService.showModal({
      templateUrl: "views/auth.html",
      controller: "AuthCtrl"
    }).then(function(modal) {
      modal.element.modal();
      modal.close.then(function(result) {
        fetch_playlist();
        $scope.joined=false;
      });
    });
  };

  $scope.logOut=function(){
    authService.logOut();
  };

  $scope.getUser=function(){
    return authService.getUser();
  };

  $scope.$on('session_resume', function(){
    console.log('resuming session in progress');
    fetch_playlist();
    $scope.joined=false;
  });

});
<|endoftext|>


<commit_before>(function (global, factory) {
  module && module.exports ? module.exports = factory() :
  define && define.amd ? define(factory) : global.Ways = factory();
}(this, function () {

  'use strict';

  // avoid requiring files if CJS or AMD is not supported
  if((module && module.exports) || (define && defined.amd)){
    var Way = require('./way');
    var Flow = require('./flow');
    var Location = require('./location');
  };

  // Config
  var flow = null;
  var mode = null;
  // Ways.location = new Location;
  var location = null;
  var routes = [];

  /**
   * Sets up a new route
   * @param {String} pattern      Pattern string
   * @param {Function} runner     Route's action runner
   * @param {Function} destroyer  Optional, Route's action destroyer (flow mode)
   * @param {String} dependency   Optional, specifies a dependency by pattern
   */
  function Ways(pattern, runner, destroyer, dependency){
    if(flow && arguments.length < 3)
      throw new Error('In `flow` mode you must to pass at least 3 args.');

    var route = new Way(pattern, runner, destroyer, dependency);
    routes.push(route);
    return route;
  }

  Ways.flow = function (m){
    routes = [];
    if((mode = m) != null)
      flow = new Flow(routes, mode);
  };

  Ways.use = function(location_middleware){
    location = new location_middleware;
    location.on('url:change', function() {
      dispatch(location.pathname());
    });
  };

  Ways.pathname = function(){
    if(location)
      return location.pathname();
  };

  Ways.go = function(url, title, state){
    if(location)
      location.push(url, title, state);
    else
      dispatch(url);
  };

  Ways.go.silent = function(url, title, state){
    if(location)
      location.replace(url, title, state);
  };

  Ways.reset = function(){
    flow = null;
    mode = null;
    location = null;
    routes = [];
  };

  function dispatch(url) {
    var i, url = '/' + url.replace(/^[\/]+|[\/]+$/mg, '');

    for(i in routes)
      if(routes[i].matcher.test(url))
        return run(url, routes[i]);

    throw new Error("Route not found for url '"+ url +"'");
  };

  function run(url, route) {
    flow ? flow.run(url, route) : route.run(url);
    return route;
  };

  return Ways;
}));<commit_msg>integrating with ways-addressbar<commit_after>(function (global, factory) {
  module && module.exports ? module.exports = factory() :
  define && define.amd ? define(factory) : global.Ways = factory();
}(this, function () {

  'use strict';

  // avoid requiring files if CJS or AMD is not supported
  if((module && module.exports) || (define && defined.amd)){
    var Way = require('./way');
    var Flow = require('./flow');
    var WaysAddressBar = require('ways-addressbar');
  };

  // Config
  var flow = null;
  var mode = null;
  var plugin = null;
  var routes = [];

  /**
   * Sets up a new route
   * @param {String} pattern      Pattern string
   * @param {Function} runner     Route's action runner
   * @param {Function} destroyer  Optional, Route's action destroyer (flow mode)
   * @param {String} dependency   Optional, specifies a dependency by pattern
   */
  function Ways(pattern, runner, destroyer, dependency){
    if(flow && arguments.length < 3)
      throw new Error('In `flow` mode you must to pass at least 3 args.');

    var route = new Way(pattern, runner, destroyer, dependency);
    routes.push(route);

    return route;
  }

  Ways.flow = function (m){
    routes = [];
    if((mode = m) != null)
      flow = new Flow(routes, mode);
  };

  Ways.use = function(plug){
    plugin = new plug;
    plugin.on('url:change', plugin_url_change);
  };

  Ways.pathname = function(){
    if(plugin)
      return plugin.pathname();
  };

  Ways.go = function(url, title, state){
    if(plugin)
      plugin.push(url, title, state);
    else
      dispatch(url);
  };

  Ways.go.silent = function(url, title, state){
    if(plugin)
      plugin.replace(url, title, state);
  };

  Ways.reset = function(){
    if(plugin)
      plugin.off('url:change', plugin_url_change)

    flow = null;
    mode = null;
    plugin = null;
    routes = [];
  };

  function plugin_url_change(url){
    dispatch(plugin.pathname());
  }

  function dispatch(url) {
    var i, route, url = '/' + url.replace(/^[\/]+|[\/]+$/mg, '');

    for(i in routes)
      if((route = routes[i]).matcher.test(url))
        return (flow ? flow.run(url, route) : route.run(url));

    throw new Error("Route not found for url '"+ url +"'");
  };

  Ways.addressbar = WaysAddressBar;

  return Ways;
}));<|endoftext|>


<commit_before>/*global define */
/*jshint indent:4 */

define(['jquery'], function ($) {
    "use strict";

    var postInfoTabsLinks = $('#post-info-tabs a');

    postInfoTabsLinks.click(function (e) {
        e.preventDefault();
        $(this).tab('show');
    });

    var postContactDiv = $('#post-contact');

    postContactDiv.on("submit", function (e) {
        var target = $(e.target);
        if (target.is('form')) {
            e.preventDefault();

            var submit = $('input[type="submit"]', postContactDiv);

            submit.data('loading-text', 'Enviando...').button('loading');

            $.ajax({
                type: 'POST',
                data: target.serialize(),
                success: function (result) {
                    postContactDiv.html(result);
                },
                complete: function (result) {
                    submit.button('reset');
                }
            });
        }
    });

    postContactDiv.on("click", function (e) {
        var target = $(e.target);
        if (target.is('.close')) {
            $.ajax({
                type: 'GET',
                success: function (result) {
                    postContactDiv.html(result);
                }
            });
        }
    });
});
<commit_msg>improve post.js<commit_after>/*global define */
/*jshint indent:4 */

define(['jquery'], function ($) {
    "use strict";

    if (AppParams.postEditable === true) {
        require(["views/user/post-manager"], function () {
        });
    }

    var $postInfoTabsLinks = $('#post-info-tabs a');

    $postInfoTabsLinks.click(function (e) {
        e.preventDefault();
        $(this).tab('show');
    });

    var $postContact = $('#post-contact');

    $postContact.on("submit", function (e) {
        var target = $(e.target);
        if (target.is('form')) {
            e.preventDefault();

            var $submit = $('input[type="submit"]', $postContact);

            $submit.data('loading-text', 'Enviando...').button('loading');

            $.ajax({
                type: 'POST',
                data: target.serialize(),
                success: function (result) {
                    $postContact.html(result);
                },
                complete: function (result) {
                    $submit.button('reset');
                }
            });
        }
    });

    $postContact.on("click", function (e) {
        var target = $(e.target);
        if (target.is('.close')) {
            $.ajax({
                type: 'GET',
                success: function (result) {
                    $postContact.html(result);
                }
            });
        }
    });

    var $postPicturesThumbnails = $("#post-pictures-thumbnails");
    var $postPicturesCarousel = $("#post-pictures-carousel");

    $postPicturesCarousel.carousel({
        interval: 0
    });

    $postPicturesThumbnails.on("click", function (e) {
        var $target = $(e.target);
        var $closestLi = $target.closest("li");

        if ($closestLi.hasClass("post-picture") && ! $target.hasClass("thumbnail-remove-picture")) {
            $postPicturesCarousel.carousel($closestLi.index());
        }
    });
});
<|endoftext|>