<commit_before>/*
 HTML5 Shiv v3.6.2pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
 downloaded from http://www.humber.ca/sites/all/themes/adaptivetheme/at_core/scripts/html5.js?nztwcq 2016-08-17
*/
(function(j,f){function s(a,b){var c=a.createElement("p"),m=a.getElementsByTagName("head")[0]||a.documentElement;c.innerHTML="x<style>"+b+"</style>";return m.insertBefore(c.lastChild,m.firstChild)}function o(){var a=d.elements;return"string"==typeof a?a.split(" "):a}function n(a){var b=t[a[u]];b||(b={},p++,a[u]=p,t[p]=b);return b}function v(a,b,c){b||(b=f);if(e)return b.createElement(a);c||(c=n(b));b=c.cache[a]?c.cache[a].cloneNode():y.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);
return b.canHaveChildren&&!z.test(a)?c.frag.appendChild(b):b}function A(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();a.createElement=function(c){return!d.shivMethods?b.createElem(c):v(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+o().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(d,b.frag)}
function w(a){a||(a=f);var b=n(a);if(d.shivCSS&&!q&&!b.hasCSS)b.hasCSS=!!s(a,"article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}mark{background:#FF0;color:#000}");e||A(a,b);return a}function B(a){for(var b,c=a.attributes,m=c.length,f=a.ownerDocument.createElement(l+":"+a.nodeName);m--;)b=c[m],b.specified&&f.setAttribute(b.nodeName,b.nodeValue);f.style.cssText=a.style.cssText;return f}function x(a){function b(){clearTimeout(d._removeSheetTimer);c&&c.removeNode(!0);c=null}
var c,f,d=n(a),e=a.namespaces,j=a.parentWindow;if(!C||a.printShived)return a;"undefined"==typeof e[l]&&e.add(l);j.attachEvent("onbeforeprint",function(){b();var g,i,d;d=a.styleSheets;for(var e=[],h=d.length,k=Array(h);h--;)k[h]=d[h];for(;d=k.pop();)if(!d.disabled&&D.test(d.media)){try{g=d.imports,i=g.length}catch(j){i=0}for(h=0;h<i;h++)k.push(g[h]);try{e.push(d.cssText)}catch(n){}}g=e.reverse().join("").split("{");i=g.length;h=RegExp("(^|[\\s,>+~])("+o().join("|")+")(?=[[\\s,>+~#.:]|$)","gi");for(k=
"$1"+l+"\\:$2";i--;)e=g[i]=g[i].split("}"),e[e.length-1]=e[e.length-1].replace(h,k),g[i]=e.join("}");e=g.join("{");i=a.getElementsByTagName("*");h=i.length;k=RegExp("^(?:"+o().join("|")+")$","i");for(d=[];h--;)g=i[h],k.test(g.nodeName)&&d.push(g.applyElement(B(g)));f=d;c=s(a,e)});j.attachEvent("onafterprint",function(){for(var a=f,c=a.length;c--;)a[c].removeNode();clearTimeout(d._removeSheetTimer);d._removeSheetTimer=setTimeout(b,500)});a.printShived=!0;return a}var r=j.html5||{},z=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,
y=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q,u="_html5shiv",p=0,t={},e;(function(){try{var a=f.createElement("a");a.innerHTML="<xyz></xyz>";q="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}e=b}catch(d){e=q=!0}})();var d={elements:r.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup main mark meter nav output progress section summary time video",
version:"3.6.2pre",shivCSS:!1!==r.shivCSS,supportsUnknownElements:e,shivMethods:!1!==r.shivMethods,type:"default",shivDocument:w,createElement:v,createDocumentFragment:function(a,b){a||(a=f);if(e)return a.createDocumentFragment();for(var b=b||n(a),c=b.frag.cloneNode(),d=0,j=o(),l=j.length;d<l;d++)c.createElement(j[d]);return c}};j.html5=d;w(f);var D=/^$|\b(?:all|print)\b/,l="html5shiv",C=!e&&function(){var a=f.documentElement;return!("undefined"==typeof f.namespaces||"undefined"==typeof f.parentWindow||
"undefined"==typeof a.applyElement||"undefined"==typeof a.removeNode||"undefined"==typeof j.attachEvent)}();d.type+=" print";d.shivPrint=x;x(f)})(this,document);
<commit_msg>Delete html5.js<commit_after><|endoftext|>


<commit_before>/**
 * Controls the creation of a table that renders the entries by month
 * by category with a yearly total for the category.
 *
 * Copyright 2015 Ethan Smith
 */

var Backbone = require('backbone'),
    ControlBones = require('./ControlBones'),

    // Model
    StatementsByCategory = require('../model/operations/statements/StatementsByCategory'),
    TotalByMonth = require('../model/operations/entries/TotalByMonth'),
    TableRowModel = require('../model/table/TableRowModel'),

    // Views
    SummaryBlock = require('../view/SummaryBlock'),
    TableView = require('../view/table/TableView'),
    TableMonthRow = require('../view/table/rows/TableMonthRow'),
    StatementLabelCell = require('../view/table/cell/StatementLabelCell'),
    AmountEntryCell = require('../view/table/cell/AmountEntryCell'),
    EditableAmountCell = require('../view/table/cell/EditableAmountCell'),
    StatementSumCell = require('../view/table/cell/StatementSumCell');

var CategorizedController = ControlBones.extend({
   title: 'Categorized Table',
   editable: false,
   hasSummary: true,

   /**
    * @param collection AmountEntryCollection
    * @return SummaryBlock
    */
   render: function(collection) {
      var self = this,
          categorized = (new StatementsByCategory()).run(collection);

      var summary = new SummaryBlock({
         model: this._createSummaryModel()
      });

      var table = new TableView({
         collection: this._createTableCollection(categorized),
         childViewOptions: {
            prependCellType: StatementLabelCell,
            cellType: this.editable ? EditableAmountCell : AmountEntryCell,
            appendCellType: this.hasSummary ? StatementSumCell : null
         },
         header: self._generateHeader()
      });

      table.on('editing:ended', function(originalHash, updatedModel) {
         var found = collection.findEntryWithHash(originalHash);
         if (found) {
            collection.remove(found);
         }

         collection.add(updatedModel);

         self.trigger('collection:updated', collection);
      });

      summary.on('show', function() {
         summary.content.show(table);
      });

      return summary;
   },

   _generateHeader: function() {
      return new TableMonthRow({
         prependedModel: new Backbone.Model(),
         appendedModel: this.hasSummary ? new Backbone.Model({
            'text': 'Yearly'
         }) : null
      });
   },

   /**
    * @param collection StatementCollection
    * @return Backbone.Collection
    */
   _createTableCollection: function(collection) {
      return new Backbone.Collection(collection.map(this._createRowModel));
   },

   /**
    * @param row Statement
    * @return TableRowModel
    */
   _createRowModel: function(row) {
      return new TableRowModel({
         prepended: row,
         members: (new TotalByMonth()).run(row.get('entries')),
         appended: row
      });
   }
});

module.exports = CategorizedController;
<commit_msg>Use new categorization in CategorizedController<commit_after>/**
 * Controls the creation of a table that renders the entries by month
 * by category with a yearly total for the category.
 *
 * Copyright 2015 Ethan Smith
 */

var _ = require('underscore'),
    Backbone = require('backbone'),
    ControlBones = require('./ControlBones'),

    // Model
    StatementsByCategory = require('../model/operations/statements/StatementsByCategory'),
    TotalByMonth = require('../model/operations/entries/TotalByMonth'),
    TableRowModel = require('../model/table/TableRowModel'),

    // Views
    SummaryBlock = require('../view/SummaryBlock'),
    TableView = require('../view/table/TableView'),
    TableMonthRow = require('../view/table/rows/TableMonthRow'),
    StatementLabelCell = require('../view/table/cell/StatementLabelCell'),
    AmountEntryCell = require('../view/table/cell/AmountEntryCell'),
    EditableAmountCell = require('../view/table/cell/EditableAmountCell'),
    StatementSumCell = require('../view/table/cell/StatementSumCell');

var CategorizedController = ControlBones.extend({
   title: 'Categorized Table',
   editable: false,
   hasSummary: true,

   /**
    * @param collection AmountEntryCollection
    * @return SummaryBlock
    */
   render: function(collection, supplementary) {
      var self = this,
          categoryPreference = supplementary ? _.pluck(supplementary.categories || [], 'key') : [],
          categorized = (new StatementsByCategory()).run(collection, categoryPreference);

      var summary = new SummaryBlock({
         model: this._createSummaryModel()
      });

      var table = new TableView({
         collection: this._createTableCollection(categorized),
         childViewOptions: {
            prependCellType: StatementLabelCell,
            cellType: this.editable ? EditableAmountCell : AmountEntryCell,
            appendCellType: this.hasSummary ? StatementSumCell : null
         },
         header: self._generateHeader()
      });

      table.on('editing:ended', function(originalHash, updatedModel) {
         var found = collection.findEntryWithHash(originalHash);
         if (found) {
            collection.remove(found);
         }

         collection.add(updatedModel);

         self.trigger('collection:updated', collection);
      });

      summary.on('show', function() {
         summary.content.show(table);
      });

      return summary;
   },

   _generateHeader: function() {
      return new TableMonthRow({
         prependedModel: new Backbone.Model(),
         appendedModel: this.hasSummary ? new Backbone.Model({
            'text': 'Yearly'
         }) : null
      });
   },

   /**
    * @param collection StatementCollection
    * @return Backbone.Collection
    */
   _createTableCollection: function(collection) {
      return new Backbone.Collection(collection.map(this._createRowModel));
   },

   /**
    * @param row Statement
    * @return TableRowModel
    */
   _createRowModel: function(row) {
      return new TableRowModel({
         prepended: row,
         members: (new TotalByMonth({
            'category': row.get('key')
         })).run(row.get('entries')),
         appended: row
      });
   }
});

module.exports = CategorizedController;
<|endoftext|>


<commit_before>/*
    ---------------------
    Chatzy HTML Variables
    ---------------------
*/

var messageTable = "X3266";
var messageContainer = "X6863";
var popup = "X4467";
var messageTime = "X2066";
var messageButton = "X9127";
var PMTag = "X2225";
var textBox = "X5395";
var visitorTable = "X6138";

/*
    -------------------
    Chatzy JS Variables
    -------------------
*/

var isCleared = "X6317";
var timeoutTimer = "X1903";

/*
    -----------------
    Wrapper Functions
    -----------------
*/

// Gets the HTML element with the specified ID
// elementID: String
function elementByID(elementID) {
    return document.getElementById(elementID);
}

// Gets a list of HTML elements with the specified class
// elementClass: String
function elementsByClass(elementClass) {
    return document.getElementsByClassName(elementClass);
}

// Removes the user from whatever room they are currently in
function leaveChat() {
    X8437("X3163");
}

// Closes whatever popup box is currently on the screen, if there is one.
function closePopup() {
    X3741();
}

// Posts a message to chat. All basic bold, italic, and strikethrough tags will be replaced with Chatzy ones
// message: String
function postMessage(message) {
    var HTMLTags = ["", "", "", "", "<s>", "</s>", "", ""];
    var ChatzyTags = ["[b]", "[/b]", "[i]", "[/i]", "[s]", "[/s]", "[u]", "[/u]"];
    for (var tag in HTMLTags) {
        if (HTMLTags.hasOwnProperty(tag)) {
            message = message.replace(HTMLTags[tag],ChatzyTags[tag]);
        }
    }
    X7302(message);
}

// Sets the user's current status, remembered if perm is true.
// status: String; perm: Boolean
function setStatus(status, perm) {
    postMessage("/status" + (perm ? "+ " : " ") + status);
    var p = new Promise(function(resolve, reject) {
        var iterations = 0;
        var vis = setInterval(function() {
            console.log(iterations);
            if (iterations <= 10 && window[popup].firstChild.innerText == "Your status was updated") {
                clearInterval(vis);
                resolve();
            } else if (iterations >= 10) {
                clearInterval(vis);
                reject();
            }
            iterations++;
        }, 1000);
    });
    p.then(function(){closePopup();});
}

// Closes the room, if user has permission
function closeChat() {
    postMessage("/close");
}

// Opens the room, if user has permission
function openChat() {
    postMessage("/open");
}

// Toggles whether the room is currently oppened or closed.
function toggleChatLock() {
    if(X6538.X6739) { //Variable for whether the chat is locked, of course.
        postMessage("/open");
    } else {
        postMessage("/close");
    }
}

// Uses Chatzy's search function to locate messages containing the specified term, or made by the specified poster.
// term: String; poster: String; caseSensitive: Boolean; wholeWord: Boolean
function searchMessages(term, poster, caseSensitive, wholeWord) {
    postMessage("/find " + (wholeWord ? "{W:1}" : "") +
                         (caseSensitive ? "{C:1}" : "") +
                         (poster ? "{V:" + poster + "} " : "") +
                         (term ? term : ""));
}

// Sends a private message to the specified user, if they are a premium user or in a premium room.
// name: String; message: String
function privateMessage(name, message) {
    postMessage("/pm \"" + name + "\" " + message);
}

// Kicks a given user from the room.
// user: String
function kickUser(user) {
    postMessage("/kick \"" + user + "\"");
}

// Kicks multiple users from the room in quick succession
// users: Array of Strings
function kickUsers(users) {
    for (var i in users) {
        if (users.hasOwnProperty(i)) {
            kickUser(users[i]);
        }
    }
}

// Bans a given user from the room.
// user: String
function banUser(user) {
    postMessage("/ban \"" + user + "\"");
}

// Bans multiple users from the room in quick succession
// users: Array of Strings
function banUsers(users) {
    for (var i in users) {
        if (users.hasOwnProperty(i)) {
            banUser(users[i]);
        }
    }
}

// Sends a private message to all online users
// message: String
function globalMessage(message) {
    var users = X9937.split("\n");
    for (var i = 1; i <= users[0]; i++) {
        var user = users[i].split("\t");
        privateMessage(user[0], message);   //Replace the 0 with other numbers to grab different values. 2 is last leave/exit, 4 is status, 5 is location.
    }
}

// Alters the room board in a specified way.
// Method is the style of editing to use. Options are: 0/default, overwrite. 1, append. 2, prepend. 3, replace.
// message: String; method: Int; key: Char
function editRoomBoard(message, method, key) {
    postMessage("/rb");
    setTimeout(function() {
        var BoardMessage = elementByID("X7308");
        switch (method) {
            case 1:
                BoardMessage.value = BoardMessage.value + "\n" + message;
                break;
            case 2:
                BoardMessage.value = message + "\n" + BoardMessage.value;
                break;
            case 3:
                if (BoardMessage.value.match(new RegExp(key, "g")).length > 1) {
                    BoardMessage.value = BoardMessage.value.replace(new RegExp(key + ".+?" + key, "g"), key + message + key);
                }
                break;
            default:
                BoardMessage.value = message;
        }
        X4296.onclick();
    }, 150);
}

// Changes current user's name. Currently causes page reload, possibly fixable?
// name: String
function changeName(name) {
   X2966('X9093');

    setTimeout(function() {
        X5067.value = name;
        X8998.onsubmit();
    }, 1000);
}

// Given a tab element and a certain class, it will either add or remove the class.
// elIn: Element; classIn: String; addClass: Boolean
function highlightTab(elIn, classIn, addClass) {
    var hasClass = new RegExp("\\b" + classIn + "\\b");
    if (!addClass != !elIn.className.match(hasClass)) { //This is a XOR. Combined with the below if, it means that this is checking whether we are adding or removing a class, and if that is necessary.
        if (addClass) {
            elIn.className += (elIn.className ? " " : "") + classIn;
        } else {
            elIn.className = elIn.className.replace(hasClass, "").replace(/^\s/, "").replace(/\s$/, "");
        }
    }
}

// Returns the text sufficient to generate a Chatzy menu tab.
// picName: String; clickFunc: String; displayText: String; isChecked: Boolean; isLocked: Boolean
function generateTab(picName, clickFunc, displayText, isChecked, isLocked) {
    return '' + (isChecked ? " ✓" : "") + (picName ? '' : "") + displayText + '';
}

// Returns a promise for certain visitor data from the visitor list.
// rows are named "Alias", "Last", "Loc", "UIP", "UID", "Status", "Perms"
// columns: List of Strings
function getVisitorData(columns) {
    return new Promise(function(resolve, reject) {
        X2822.onclick();
        var iterations = 0;
        var vis = setInterval(function() {
            iterations++;
            if (window[visitorTable]) {
                clearInterval(vis);
                var table = window[visitorTable].firstChild.children;
                closePopup();
                var visitorData = [];
                for (var i=1; i < table.length-1; i++) {
                    var visitor = [];
                    for (var j in columns) {
                        if (!columns.hasOwnProperty(j)) {
                            continue;
                        }
                        var option = columns[j];
                        switch (option) {
                            case "Alias":
                                visitor.push(table[i].firstChild.lastChild.innerText);
                                break;
                            case "Last":
                                visitor.push(table[i].children[1].innerText);
                                break;
                            case "Loc":
                                visitor.push(table[i].children[2].innerText);
                                break;
                            case "UIP":
                                visitor.push(table[i].children[3].innerText);
                                break;
                            case "UID":
                                visitor.push(table[i].children[4].innerText);
                                break;
                            case "Status":
                                visitor.push(table[i].children[5].firstChild.title);
                                break;
                            case "Perms":
                                var image = table[i].children[6].firstChild.firstChild.src;
                                var perm = "";
                                if (image.match("P.png")) {
                                    perm = "Moderator";
                                } else if (image.match("A.png")) {
                                    perm = "Regular";
                                } else if (image.match("S.png")) {
                                    perm = "Silenced";
                                } else if (image.match("0.png")) {
                                    perm = "Unknown";
                                } else if (image.match("K.png")) {
                                    perm = "Kicked";
                                } else if (image.match("D.png")) {
                                    perm = "Banned";
                                } else if (image.match("B.png")) {
                                    perm = "Blocked";
                                }
                                visitor.push(perm);
                        }
                    }
                    visitorData.push(visitor);
                }
                resolve(visitorData);
            } else if (iterations > 30) {
                clearInterval(vis);
                reject([]);
            }
        }, 1000);
    });
}
<commit_msg>Fixed X value<commit_after>/*
    ---------------------
    Chatzy HTML Variables
    ---------------------
*/

var messageTable = "X3266";
var messageContainer = "X6863";
var popup = "X4467";
var messageTime = "X2066";
var messageButton = "X9127";
var PMTag = "X2225";
var textBox = "X5395";
var visitorTable = "X6138";

/*
    -------------------
    Chatzy JS Variables
    -------------------
*/

var isCleared = "X6317";
var timeoutTimer = "X1903";

/*
    -----------------
    Wrapper Functions
    -----------------
*/

// Gets the HTML element with the specified ID
// elementID: String
function elementByID(elementID) {
    return document.getElementById(elementID);
}

// Gets a list of HTML elements with the specified class
// elementClass: String
function elementsByClass(elementClass) {
    return document.getElementsByClassName(elementClass);
}

// Removes the user from whatever room they are currently in
function leaveChat() {
    X8437("X3163");
}

// Closes whatever popup box is currently on the screen, if there is one.
function closePopup() {
    X3741();
}

// Posts a message to chat. All basic bold, italic, and strikethrough tags will be replaced with Chatzy ones
// message: String
function postMessage(message) {
    var HTMLTags = ["", "", "", "", "<s>", "</s>", "", ""];
    var ChatzyTags = ["[b]", "[/b]", "[i]", "[/i]", "[s]", "[/s]", "[u]", "[/u]"];
    for (var tag in HTMLTags) {
        if (HTMLTags.hasOwnProperty(tag)) {
            message = message.replace(HTMLTags[tag],ChatzyTags[tag]);
        }
    }
    X7302(message);
}

// Sets the user's current status, remembered if perm is true.
// status: String; perm: Boolean
function setStatus(status, perm) {
    postMessage("/status" + (perm ? "+ " : " ") + status);
    var p = new Promise(function(resolve, reject) {
        var iterations = 0;
        var vis = setInterval(function() {
            console.log(iterations);
            if (iterations <= 10 && window[popup].firstChild.innerText == "Your status was updated") {
                clearInterval(vis);
                resolve();
            } else if (iterations >= 10) {
                clearInterval(vis);
                reject();
            }
            iterations++;
        }, 1000);
    });
    p.then(function(){closePopup();});
}

// Closes the room, if user has permission
function closeChat() {
    postMessage("/close");
}

// Opens the room, if user has permission
function openChat() {
    postMessage("/open");
}

// Toggles whether the room is currently oppened or closed.
function toggleChatLock() {
    if(X6538.X6739) { //Variable for whether the chat is locked, of course.
        postMessage("/open");
    } else {
        postMessage("/close");
    }
}

// Uses Chatzy's search function to locate messages containing the specified term, or made by the specified poster.
// term: String; poster: String; caseSensitive: Boolean; wholeWord: Boolean
function searchMessages(term, poster, caseSensitive, wholeWord) {
    postMessage("/find " + (wholeWord ? "{W:1}" : "") +
                         (caseSensitive ? "{C:1}" : "") +
                         (poster ? "{V:" + poster + "} " : "") +
                         (term ? term : ""));
}

// Sends a private message to the specified user, if they are a premium user or in a premium room.
// name: String; message: String
function privateMessage(name, message) {
    postMessage("/pm \"" + name + "\" " + message);
}

// Kicks a given user from the room.
// user: String
function kickUser(user) {
    postMessage("/kick \"" + user + "\"");
}

// Kicks multiple users from the room in quick succession
// users: Array of Strings
function kickUsers(users) {
    for (var i in users) {
        if (users.hasOwnProperty(i)) {
            kickUser(users[i]);
        }
    }
}

// Bans a given user from the room.
// user: String
function banUser(user) {
    postMessage("/ban \"" + user + "\"");
}

// Bans multiple users from the room in quick succession
// users: Array of Strings
function banUsers(users) {
    for (var i in users) {
        if (users.hasOwnProperty(i)) {
            banUser(users[i]);
        }
    }
}

// Sends a private message to all online users
// message: String
function globalMessage(message) {
    var users = X9937.split("\n");
    for (var i = 1; i <= users[0]; i++) {
        var user = users[i].split("\t");
        privateMessage(user[0], message);   //Replace the 0 with other numbers to grab different values. 2 is last leave/exit, 4 is status, 5 is location.
    }
}

// Alters the room board in a specified way.
// Method is the style of editing to use. Options are: 0/default, overwrite. 1, append. 2, prepend. 3, replace.
// message: String; method: Int; key: Char
function editRoomBoard(message, method, key) {
    postMessage("/rb");
    setTimeout(function() {
        var BoardMessage = elementByID("X7308");
        switch (method) {
            case 1:
                BoardMessage.value = BoardMessage.value + "\n" + message;
                break;
            case 2:
                BoardMessage.value = message + "\n" + BoardMessage.value;
                break;
            case 3:
                if (BoardMessage.value.match(new RegExp(key, "g")).length > 1) {
                    BoardMessage.value = BoardMessage.value.replace(new RegExp(key + ".+?" + key, "g"), key + message + key);
                }
                break;
            default:
                BoardMessage.value = message;
        }
        X4296.onclick();
    }, 150);
}

// Changes current user's name. Currently causes page reload, possibly fixable?
// name: String
function changeName(name) {
   X2966('X9093');

    setTimeout(function() {
        X5067.value = name;
        X8998.onsubmit();
    }, 1000);
}

// Given a tab element and a certain class, it will either add or remove the class.
// elIn: Element; classIn: String; addClass: Boolean
function highlightTab(elIn, classIn, addClass) {
    var hasClass = new RegExp("\\b" + classIn + "\\b");
    if (!addClass != !elIn.className.match(hasClass)) { //This is a XOR. Combined with the below if, it means that this is checking whether we are adding or removing a class, and if that is necessary.
        if (addClass) {
            elIn.className += (elIn.className ? " " : "") + classIn;
        } else {
            elIn.className = elIn.className.replace(hasClass, "").replace(/^\s/, "").replace(/\s$/, "");
        }
    }
}

// Returns the text sufficient to generate a Chatzy menu tab.
// picName: String; clickFunc: String; displayText: String; isChecked: Boolean; isLocked: Boolean
function generateTab(picName, clickFunc, displayText, isChecked, isLocked) {
    return '' + (isChecked ? " ✓" : "") + (picName ? '' : "") + displayText + '';
}

// Returns a promise for certain visitor data from the visitor list.
// rows are named "Alias", "Last", "Loc", "UIP", "UID", "Status", "Perms"
// columns: List of Strings
function getVisitorData(columns) {
    return new Promise(function(resolve, reject) {
        X2031.onclick();
        var iterations = 0;
        var vis = setInterval(function() {
            iterations++;
            if (window[visitorTable]) {
                clearInterval(vis);
                var table = window[visitorTable].firstChild.children;
                closePopup();
                var visitorData = [];
                for (var i=1; i < table.length-1; i++) {
                    var visitor = [];
                    for (var j in columns) {
                        if (!columns.hasOwnProperty(j)) {
                            continue;
                        }
                        var option = columns[j];
                        switch (option) {
                            case "Alias":
                                visitor.push(table[i].firstChild.lastChild.innerText);
                                break;
                            case "Last":
                                visitor.push(table[i].children[1].innerText);
                                break;
                            case "Loc":
                                visitor.push(table[i].children[2].innerText);
                                break;
                            case "UIP":
                                visitor.push(table[i].children[3].innerText);
                                break;
                            case "UID":
                                visitor.push(table[i].children[4].innerText);
                                break;
                            case "Status":
                                visitor.push(table[i].children[5].firstChild.title);
                                break;
                            case "Perms":
                                var image = table[i].children[6].firstChild.firstChild.src;
                                var perm = "";
                                if (image.match("P.png")) {
                                    perm = "Moderator";
                                } else if (image.match("A.png")) {
                                    perm = "Regular";
                                } else if (image.match("S.png")) {
                                    perm = "Silenced";
                                } else if (image.match("0.png")) {
                                    perm = "Unknown";
                                } else if (image.match("K.png")) {
                                    perm = "Kicked";
                                } else if (image.match("D.png")) {
                                    perm = "Banned";
                                } else if (image.match("B.png")) {
                                    perm = "Blocked";
                                }
                                visitor.push(perm);
                        }
                    }
                    visitorData.push(visitor);
                }
                resolve(visitorData);
            } else if (iterations > 30) {
                clearInterval(vis);
                reject([]);
            }
        }, 1000);
    });
}
<|endoftext|>


<commit_before>import sendEmail from '../../shared/lib/send-exchange-email';

const expectedEwsArgs = {
  'attributes' : {
    'MessageDisposition' : 'SendAndSaveCopy'
  },
  'SavedItemFolderId': {
    'DistinguishedFolderId': {
      'attributes': {
        'Id': 'sentitems'
      }
    }
  },
  'Items' : {
    'Message' : {
      'ItemClass': 'IPM.Note',
      'Subject' : 'Test Email Subject',
      'Body' : {
        'attributes': {
          'BodyType' : 'Text'
        },
        '$value': 'Test email'
      },
      'ToRecipients' : {
        'Mailbox' : {
          'EmailAddress' : 'test@test.com'
        }
      },
      'IsRead': 'false'
    }
  }
};

describe('send exchange email', () => {

  it('should be called with correct args', () => {
    return sendEmail(
      'test@test.com',
      'Test email',
      'Test Email Subject'
    ).then((args) => {
      expect(args.ewsFunction).toBe('CreateItem');
      expect(args.ewsArgs).toEqual(expectedEwsArgs);
    });
  });

});
<commit_msg>Exchange email test updates<commit_after>import sendEmail from '../../shared/lib/send-exchange-email';

const expectedEwsArgs = {
  'attributes' : {
    'MessageDisposition' : 'SendAndSaveCopy'
  },
  'SavedItemFolderId': {
    'DistinguishedFolderId': {
      'attributes': {
        'Id': 'sentitems'
      }
    }
  },
  'Items' : {
    'Message' : {
      'ItemClass': 'IPM.Note',
      'Subject' : 'Test Email Subject',
      'Body' : {
        'attributes': {
          'BodyType' : 'HTML'
        },
        '$value': 'Test email'
      },
      'ToRecipients' : {
        'Mailbox' : {
          'EmailAddress' : 'test@test.com'
        }
      },
      'IsRead': 'false'
    }
  }
};

describe('send exchange email', () => {

  it('should be called with correct args', () => {
    return sendEmail(
      'test@test.com',
      'Test email',
      'Test Email Subject'
    ).then((args) => {
      expect(args.ewsFunction).toBe('CreateItem');
      expect(args.ewsArgs).toEqual(expectedEwsArgs);
    });
  });

});
<|endoftext|>


<commit_before>"use strict";

import { getToken, redirectLogin } from "./common.js"
import * as config from "./config.js"

function parseService() {
    let pathname = window.location.pathname;
    let service = pathname.replace(config.ext, "").substring(1);
    return service
}

function getCodeifRedirected() {
    const queryString = window.location.search;
    const urlParams = new URLSearchParams(queryString)
    const code = urlParams.get("code")
    console.log(code)
    const state = urlParams.get("state")
    console.log(state)
    return [code, state]
}

function forwardServiceCode(service, slackToken, code, state) {
    const url = new URL(`/${service}/redirect`, config.backend_url)
    url.searchParams.set('code', code);
    url.searchParams.set('state', state);
    return fetch(url, {
        method: 'GET',
        headers: {
            'Authorization': 'Bearer ' + slackToken
        }
    })
        .then(response => {
            if (response.status !== 200) {
                throw `Failed to authenticate:${response.status}`;
            }
        })
        .catch(err => {
            console.log('Fetch Error', err)
            let elem = document.getElementById("msg");
            elem.innerHTML = `error sending ${service} Code to gargbot`
        });

}

function authorizeService(service, token) {
    const url = new URL(`/${service}/auth`, config.backend_url)
    return fetch(url, {
        method: 'GET',
        headers: {
            'Authorization': 'Bearer ' + token
        }
    })
        .then(response => {
            if (response.status !== 200) {
                throw "Failed to authenticate"
            }
            return response
        })
        .then(response => {
            const contentType = response.headers.get("content-type");
            if (contentType && contentType.indexOf("application/json") !== -1) {
                return response.json()
            }
        })
        .then(data => {
            console.log(data);
            return data
        })
        .catch(err => console.log('Fetch Error', err));

}

function redirectService(url) {
    location.href = url
}

function renderHealthMenu(service, token, report_enabled) {
    let elem = document.getElementById("msg");
    elem.innerHTML = "enable report?";
    let toggle = document.createElement("label");
    toggle.className = 'switch'

    let input = document.createElement("input");
    input.type = "checkbox";
    toggle.appendChild(input)

    let span = document.createElement("span");
    span.className = 'slider'
    toggle.appendChild(span)

    input.onclick = buttonClickMaker(service, token);
    input.checked = report_enabled;
    document.body.appendChild(toggle);

}

function toggleReport(service, token, enable) {
    const url = new URL("/toggle_report", config.backend_url)
    let data = {
        'service': service,
        'enable': enable
    }
    return fetch(url, {
        method: 'POST',
        headers: {
            'Authorization': 'Bearer ' + token,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(data)
    })
        .then(response => {
            if (response.status !== 200) {
                throw ("Failed to set setting:" + response.status);
            }
            console.log(response)
        })
}

function buttonClickMaker(service, token) {
    async function inner() {
        this.disabled = true;
        let checked = this.checked
        try {
            await toggleReport(service, token, checked)
        } catch {
            console.log(checked)
            this.checked = !checked
        } finally {
            this.disabled = false;
        }
    }
    return inner
}
async function main() {
    let service = parseService();
    let slackToken = getToken();
    if (!slackToken) {
        // not logged in to slack
        redirectLogin(service)
    }

    let [serviceCode, state] = getCodeifRedirected();
    if (serviceCode != null) {
        // in the process of logging in to service
        await forwardServiceCode(service, slackToken, serviceCode, state)
    }

    let user_data = await authorizeService(service, slackToken)
    if (user_data && "auth_url" in user_data) {
        redirectService(user_data["auth_url"])
    } else if (user_data && "report_enabled" in user_data) {
        console.log(`server indicates logged into ${service}`)
        let report_enabled = user_data["report_enabled"]
        renderHealthMenu(service, slackToken, report_enabled);
    } else {
        let elem = document.getElementById("msg");
        elem.innerHTML = "Failed to authenticate";
    }

}

main();

<commit_msg>Remove js error catching to prevent loop<commit_after>"use strict";

import { getToken, redirectLogin } from "./common.js"
import * as config from "./config.js"

function parseService() {
    let pathname = window.location.pathname;
    let service = pathname.replace(config.ext, "").substring(1);
    return service
}

function getCodeifRedirected() {
    const queryString = window.location.search;
    const urlParams = new URLSearchParams(queryString)
    const code = urlParams.get("code")
    console.log(code)
    const state = urlParams.get("state")
    console.log(state)
    return [code, state]
}

function forwardServiceCode(service, slackToken, code, state) {
    const url = new URL(`/${service}/redirect`, config.backend_url)
    url.searchParams.set('code', code);
    url.searchParams.set('state', state);
    return fetch(url, {
        method: 'GET',
        headers: {
            'Authorization': 'Bearer ' + slackToken
        }
    })
        .then(response => {
            if (response.status !== 200) {
                let elem = document.getElementById("msg");
                elem.innerHTML = `Error sending ${service} code to gargbot`
                throw `Failed to authenticate:${response.status}`;
            }
        })

}

function authorizeService(service, token) {
    const url = new URL(`/${service}/auth`, config.backend_url)
    return fetch(url, {
        method: 'GET',
        headers: {
            'Authorization': 'Bearer ' + token
        }
    })
        .then(response => {
            if (response.status !== 200) {
                let elem = document.getElementById("msg");
                elem.innerHTML = `Error authenticating ${service}`
                throw "Failed to authenticate"
            }
            return response
        })
        .then(response => {
            const contentType = response.headers.get("content-type");
            if (contentType && contentType.indexOf("application/json") !== -1) {
                return response.json()
            }
        })
        .then(data => {
            console.log(data);
            return data
        })

}

function redirectService(url) {
    location.href = url
}

function renderHealthMenu(service, token, report_enabled) {
    let elem = document.getElementById("msg");
    elem.innerHTML = "enable report?";
    let toggle = document.createElement("label");
    toggle.className = 'switch'

    let input = document.createElement("input");
    input.type = "checkbox";
    toggle.appendChild(input)

    let span = document.createElement("span");
    span.className = 'slider'
    toggle.appendChild(span)

    input.onclick = buttonClickMaker(service, token);
    input.checked = report_enabled;
    document.body.appendChild(toggle);

}

function toggleReport(service, token, enable) {
    const url = new URL("/toggle_report", config.backend_url)
    let data = {
        'service': service,
        'enable': enable
    }
    return fetch(url, {
        method: 'POST',
        headers: {
            'Authorization': 'Bearer ' + token,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(data)
    })
        .then(response => {
            if (response.status !== 200) {
                throw ("Failed to set setting:" + response.status);
            }
            console.log(response)
        })
}

function buttonClickMaker(service, token) {
    async function inner() {
        this.disabled = true;
        let checked = this.checked
        try {
            await toggleReport(service, token, checked)
        } catch {
            console.log(checked)
            this.checked = !checked
        } finally {
            this.disabled = false;
        }
    }
    return inner
}

async function main() {
    let service = parseService();
    let slackToken = getToken();
    if (!slackToken) {
        // not logged in to slack
        redirectLogin(service)
    }

    let [serviceCode, state] = getCodeifRedirected();
    if (serviceCode != null) {
        // in the process of logging in to service
        await forwardServiceCode(service, slackToken, serviceCode, state)
    }

    let user_data = await authorizeService(service, slackToken)
    if (user_data && "auth_url" in user_data) {
        redirectService(user_data["auth_url"])
    } else if (user_data && "report_enabled" in user_data) {
        console.log(`server indicates logged into ${service}`)
        let report_enabled = user_data["report_enabled"]
        renderHealthMenu(service, slackToken, report_enabled);
    } else {
        let elem = document.getElementById("msg");
        elem.innerHTML = "Failed to authenticate";
    }

}

main();

<|endoftext|>


<commit_before>/*
Copyright 2015 OpenMarket Ltd

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

    http://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.
*/

'use strict';

var React = require("react");
var MatrixClientPeg = require("../../MatrixClientPeg");

module.exports = {
    propTypes: {
        onRoomCreated: React.PropTypes.func,
    },

    phases: {
        CONFIG: "CONFIG",  // We're waiting for user to configure and hit create.
        CREATING: "CREATING",  // We're sending the request.
        CREATED: "CREATED",  // We successfully created the room.
        ERROR: "ERROR",  // There was an error while trying to create room.
    },

    getDefaultProps: function() {
        return {
            onRoomCreated: function() {},
        };
    },

    getInitialState: function() {
        return {
            phase: this.phases.CONFIG,
            error_string: "",
        };
    },

    onCreateRoom: function() {
        var options = {};

        var room_name = this.getName();
        if (room_name) {
            options.name = room_name;
        }

        var preset = this.getPreset();
        if (preset) {
            options.preset = preset;
        }

        var invited_users = this.getInvitedUsers();
        if (invited_users) {
            options.invite = invited_users;
        }

        var cli = MatrixClientPeg.get();
        if (!cli) {
            // TODO: Error.
            console.error("Cannot create room: No matrix client.");
            return;
        }

        var deferred = MatrixClientPeg.get().createRoom(options);

        this.setState({
            phase: this.phases.CREATING,
        });

        var self = this;

        deferred.then(function () {
            self.setState({
                phase: self.phases.CREATED,
            });
            self.props.onRoomCreated();
        }, function(err) {
            self.setState({
                phase: self.phases.ERROR,
                error_string: err.toString(),
            });
        });
    }
};
<commit_msg>port create room<commit_after>/*
Copyright 2015 OpenMarket Ltd

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

    http://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.
*/

'use strict';

var React = require("react");
var MatrixClientPeg = require("../../MatrixClientPeg");
var PresetValues = require('../atoms/create_room/Presets').Presets;
var q = require('q');
var encryption = require("../../encryption");

module.exports = {
    propTypes: {
        onRoomCreated: React.PropTypes.func,
    },

    phases: {
        CONFIG: "CONFIG",  // We're waiting for user to configure and hit create.
        CREATING: "CREATING",  // We're sending the request.
        CREATED: "CREATED",  // We successfully created the room.
        ERROR: "ERROR",  // There was an error while trying to create room.
    },

    getDefaultProps: function() {
        return {
            onRoomCreated: function() {},
        };
    },

    getInitialState: function() {
        return {
            phase: this.phases.CONFIG,
            error_string: "",
            is_private: true,
            share_history: false,
            default_preset: PresetValues.PrivateChat,
            topic: '',
            room_name: '',
            invited_users: [],
        };
    },

    onCreateRoom: function() {
        var options = {};

        if (this.state.room_name) {
            options.name = this.state.room_name;
        }

        if (this.state.topic) {
            options.topic = this.state.topic;
        }

        if (this.state.preset) {
            if (this.state.preset != PresetValues.Custom) {
                options.preset = this.state.preset;
            } else {
                options.initial_state = [
                    {
                        type: "m.room.join_rules",
                        content: {
                            "join_rules": this.state.is_private ? "invite" : "public"
                        }
                    },
                    {
                        type: "m.room.history_visibility",
                        content: {
                            "history_visibility": this.state.share_history ? "shared" : "invited"
                        }
                    },
                ];
            }
        }

        options.invite = this.state.invited_users;

        var alias = this.getAliasLocalpart();
        if (alias) {
            options.room_alias_name = alias;
        }

        var cli = MatrixClientPeg.get();
        if (!cli) {
            // TODO: Error.
            console.error("Cannot create room: No matrix client.");
            return;
        }

        var deferred = cli.createRoom(options);

        var response;

        if (this.state.encrypt) {
            deferred = deferred.then(function(res) {
                response = res;
                return encryption.enableEncryption(
                    cli, response.roomId, options.invite
                );
            }).then(function() {
                return q(response) }
            );
        }

        this.setState({
            phase: this.phases.CREATING,
        });

        var self = this;

        deferred.then(function (resp) {
            self.setState({
                phase: self.phases.CREATED,
            });
            self.props.onRoomCreated(resp.room_id);
        }, function(err) {
            self.setState({
                phase: self.phases.ERROR,
                error_string: err.toString(),
            });
        });
    }
};
<|endoftext|>


<commit_before>/*******************************************************************************
 * Name: QuizziPedia::Back-End::Config::Passport;
 * Description: classe che permette la registrazione all'applicazione.
 * Creation data: 27-04-2016;
 * Author: Franco Berton.
 ********************************************************************************
 * Updates history
 *-------------------------------------------------------------------------------
 * ID: Config_20160427;
 * Update data: 27-04-2016;
 * Description: Creata classe e inserite procedure necessarie all'avvio del
 * server;
 * Autore: Franco Berton.
 *-------------------------------------------------------------------------------
 * * ID: Config_20160427;
 * Update data: 01-05-2016;
 * Description: Creati i metodi: exports(), use();
 * Autore: Franco Berton.
 *-------------------------------------------------------------------------------
 *******************************************************************************/

// load all the things we need
var LocalStrategy   = require('passport-local').Strategy;

// load up the user model
var User        = require('../App/Model/UserModel');
var Topic = require('../App/Model/TopicModel');

// expose this function to our app using module.exports
module.exports = function(passport) {
    // =========================================================================
    // passport session setup ==================================================
    // =========================================================================
    // required for persistent login sessions
    // passport needs ability to serialize and unserialize users out of session

    // used to serialize the user for the session
    passport.serializeUser(function(user, done) {
        done(null, user.id);
    });

    // used to deserialize the user
    passport.deserializeUser(function(id, done) {
        User.findById(id, function(err, user) {
            done(err, user);
        });
    });

    // =========================================================================
    // LOCAL SIGNUP ============================================================
    // =========================================================================
    // we are using named strategies since we have one for login and one for signup
    // by default, if there was no name, it would just be called 'local'

    passport.use('local-signup', new LocalStrategy({
            passReqToCallback : true // allows us to pass back the entire request to the callback
        },
        function(req, username, password, done) {

            // asynchronous
            // User.findOne wont fire unless data is sent back
            process.nextTick(function() {
                // find a user whose username is the same as the forms username
                // we are checking to see if the user trying to login already exists
                User.findOne({$or: [{'username' : username}, {'email' : req.params.email}]}, function(err, user) {
                    if (err)
                        return done(err);
                    // check to see if theres already a user with that email
                    if (user) {
                        if (user.username == username && user.email == req.params.email)
                            return done(null, false, {code:4,title:'Errore Registrazione',message: 'Username e Email già presente'});
                        else {
                            if (user.email === req.params.email)
                                return done(null, false, {code:3, title:'Errore Registrazione', message: 'Email già presente'})
                            else
                                return done(null, false, {code:2, title:'Errore Registrazione', message: 'Username già presente'})
                        }
                    } else {

                        // if there is no user with that email
                        // create the user
                        var newUser            = new User();

                        // set the user's local credentials
                        newUser.password 	  = newUser.generateHash(password)
                        newUser.username      = username;
                        newUser.email    	  = req.params.email;
                        newUser.surname 	  = req.params.surname;
                        newUser.name    	  = req.params.name;
                        newUser.privilege     = 'normal';
                        Topic.find({},function(err,topics){
                            if(err)
                                throw err;
                            topics.forEach(function(topic){
                                newUser.statistics.push({
                                    topicName: topic.name
                                });
                            });
                            // save the user
                            newUser.save(function(err) {
                                if (err)
                                    throw err;
                                return done(null, newUser,{code:1, title:'Registrazione', message: 'Registrazione avvenuta con successo'});
                            });
                        });

                    }
                });
            });

        }));
    // =========================================================================
    // LOCAL LOGIN =============================================================
    // =========================================================================
    // we are using named strategies since we have one for login and one for signup
    // by default, if there was no name, it would just be called 'local'

    passport.use('local-signin', new LocalStrategy({
            passReqToCallback : true // allows us to pass back the entire request to the callback
        },
        function(req, username, password, done) {
            // callback with email and password from our form
            // find a user whose email is the same as the forms email
            // we are checking to see if the user trying to login already exists
            var UsernameOrEmail = (username.indexOf('@') === -1) ? {'username': username} : {'email': username};
            User.findOne( UsernameOrEmail , function(err, user) {
                if (err)
                    return done(err);

                // if no user is found, return the message
                if (!user)
                    return done(null, false, req.flash('loginMessage', 'No user found.')); // req.flash is the way to set flashdata using connect-flash

                // if the user is found but the password is wrong
                if (!user.validPassword(password))
                    return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata
                // all is well, return successful user
                return done(null, user);
            })
        }));

};
<commit_msg>updated passport<commit_after>/*******************************************************************************
 * Name: QuizziPedia::Back-End::Config::Passport;
 * Description: classe che permette la registrazione all'applicazione.
 * Creation data: 27-04-2016;
 * Author: Franco Berton.
 ********************************************************************************
 * Updates history
 *-------------------------------------------------------------------------------
 * ID: Config_20160427;
 * Update data: 27-04-2016;
 * Description: Creata classe e inserite procedure necessarie all'avvio del
 * server;
 * Autore: Franco Berton.
 *-------------------------------------------------------------------------------
 * * ID: Config_20160427;
 * Update data: 01-05-2016;
 * Description: Creati i metodi: exports(), use();
 * Autore: Franco Berton.
 *-------------------------------------------------------------------------------
 *******************************************************************************/

// load all the things we need
var LocalStrategy   = require('passport-local').Strategy;

// load up the user model
var User        = require('../App/Model/UserModel');
var Topic = require('../App/Model/TopicModel');

// expose this function to our app using module.exports
module.exports = function(passport) {
    // =========================================================================
    // passport session setup ==================================================
    // =========================================================================
    // required for persistent login sessions
    // passport needs ability to serialize and unserialize users out of session

    // used to serialize the user for the session
    passport.serializeUser(function(user, done) {
        done(null, user.id);
    });

    // used to deserialize the user
    passport.deserializeUser(function(id, done) {
        User.findById(id, function(err, user) {
            done(err, user);
        });
    });

    // =========================================================================
    // LOCAL SIGNUP ============================================================
    // =========================================================================
    // we are using named strategies since we have one for login and one for signup
    // by default, if there was no name, it would just be called 'local'

    passport.use('local-signup', new LocalStrategy({
            passReqToCallback : true // allows us to pass back the entire request to the callback
        },
        function(req, username, password, done) {

            // asynchronous
            // User.findOne wont fire unless data is sent back
            process.nextTick(function() {
                // find a user whose username is the same as the forms username
                // we are checking to see if the user trying to login already exists
                User.findOne({$or: [{'username' : username}, {'email' : req.body.email}]}, function(err, user) {
                    if (err)
                        return done(err);
                    // check to see if theres already a user with that email
                    if (user) {
                        if (user.username == username && user.email == req.body.email)
                            return done(null, false, {code:4,title:'Errore Registrazione',message: 'Username e Email già presente'});
                        else {
                            if (user.email === req.body.email)
                                return done(null, false, {code:3, title:'Errore Registrazione', message: 'Email già presente'})
                            else
                                return done(null, false, {code:2, title:'Errore Registrazione', message: 'Username già presente'})
                        }
                    } else {

                        // if there is no user with that email
                        // create the user
                        var newUser            = new User();

                        // set the user's local credentials
                        newUser.password 	  = newUser.generateHash(password)
                        newUser.username      = username;
                        newUser.email    	  = req.body.email;
                        newUser.surname 	  = req.body.surname;
                        newUser.name    	  = req.body.name;
                        newUser.privilege     = 'normal';
                        Topic.find({},function(err,topics){
                            if(err)
                                throw err;
                            topics.forEach(function(topic){
                                newUser.statistics.push({
                                    topicName: topic.name
                                });
                            });
                            // save the user
                            newUser.save(function(err) {
                                if (err)
                                    throw err;
                                return done(null, newUser,{code:1, title:'Registrazione', message: 'Registrazione avvenuta con successo'});
                            });
                        });

                    }
                });
            });

        }));
    // =========================================================================
    // LOCAL LOGIN =============================================================
    // =========================================================================
    // we are using named strategies since we have one for login and one for signup
    // by default, if there was no name, it would just be called 'local'

    passport.use('local-signin', new LocalStrategy({
            passReqToCallback : true // allows us to pass back the entire request to the callback
        },
        function(req, username, password, done) {
            // callback with email and password from our form
            // find a user whose email is the same as the forms email
            // we are checking to see if the user trying to login already exists
            var UsernameOrEmail = (username.indexOf('@') === -1) ? {'username': username} : {'email': username};
            User.findOne( UsernameOrEmail , function(err, user) {
                if (err)
                    return done(err);

                // if no user is found, return the message
                if (!user)
                    return done(null, false, req.flash('loginMessage', 'No user found.')); // req.flash is the way to set flashdata using connect-flash

                // if the user is found but the password is wrong
                if (!user.validPassword(password))
                    return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata
                // all is well, return successful user
                return done(null, user);
            })
        }));

};
<|endoftext|>


<commit_before>/**
 * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.md or http://ckeditor.com/license
 */

CKEDITOR.editorConfig = function( config ) {
    'use strict';
	// Define changes to default configuration here.
	// For complete reference see:
	// http://docs.ckeditor.com/#!/api/CKEDITOR.config
    var Abilian = require('Abilian');
    config.defaultLanguage = Abilian.locale;

    config.skin = 'moono';

    config.extraPlugins = ['autolink',
                           'bootstrapVisibility'];
    config.extraPlugins = config.extraPlugins.join(',');

    config.toolbar = [
		{ name: 'styles', items: [ 'Format' ] },
		{ name: 'basicstyles',
          items: [ 'Bold', 'Italic', 'Underline', '-',
                   'RemoveFormat' ] },
		{ name: 'paragraph',
          items: [ 'NumberedList', 'BulletedList', '-',
                   'Blockquote', '-',
                   'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock' ] },
		{ name: 'links', items: [ 'Link', 'Unlink'] },
		{ name: 'insert', items: [ 'Image'] },
		{ name: 'clipboard', items: [ 'Paste', 'PasteText', 'PasteFromWord', '-',
                                      'Undo', 'Redo' ] }
	];
	// Set the most common block elements.
	config.format_tags = 'p;h1;h2;h3;pre';

	// Simplify the dialog windows.
	config.removeDialogTabs = 'image:advanced;link:advanced';

    config.allowedContent = {
    'a': { attributes: ['!href', 'title'] },
    'abbr': { attributes: ['title'] },
    'acronym': { attributes: ['title'] },
    'b': {},
    'blockquote': { attributes: ['title'] },
    'br': {},
    'code': { attributes: ['title'] },
    'em': {},
    'i': {},
    'li': {},
    'ol': { attributes: ['title'] },
    'strong': {},
    'ul': { attributes: ['title'] },
    'h1': {},
    'h2': {},
    'h3': {},
    'h4': {},
    'h5': {},
    'h6': {},
    'p': { attributes: ['style'], styles: ['text-align'] },
    'u': {},
    'img': { attributes: ['!src', 'alt', 'title'] }
    };

};
<commit_msg>ckeditor config no html/xml entities<commit_after>/**
 * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.md or http://ckeditor.com/license
 */

CKEDITOR.editorConfig = function( config ) {
    'use strict';
	// Define changes to default configuration here.
	// For complete reference see:
	// http://docs.ckeditor.com/#!/api/CKEDITOR.config
    var Abilian = require('Abilian');
    config.defaultLanguage = Abilian.locale;

    // http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html#.entities
    // disable accent encoding
    config.entities = false;

    config.skin = 'moono';

    config.extraPlugins = ['autolink',
                           'bootstrapVisibility'];
    config.extraPlugins = config.extraPlugins.join(',');

    config.toolbar = [
		{ name: 'styles', items: [ 'Format' ] },
		{ name: 'basicstyles',
          items: [ 'Bold', 'Italic', 'Underline', '-',
                   'RemoveFormat' ] },
		{ name: 'paragraph',
          items: [ 'NumberedList', 'BulletedList', '-',
                   'Blockquote', '-',
                   'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock' ] },
		{ name: 'links', items: [ 'Link', 'Unlink'] },
		{ name: 'insert', items: [ 'Image'] },
		{ name: 'clipboard', items: [ 'Paste', 'PasteText', 'PasteFromWord', '-',
                                      'Undo', 'Redo' ] }
	];
	// Set the most common block elements.
	config.format_tags = 'p;h1;h2;h3;pre';

	// Simplify the dialog windows.
	config.removeDialogTabs = 'image:advanced;link:advanced';

    config.allowedContent = {
    'a': { attributes: ['!href', 'title'] },
    'abbr': { attributes: ['title'] },
    'acronym': { attributes: ['title'] },
    'b': {},
    'blockquote': { attributes: ['title'] },
    'br': {},
    'code': { attributes: ['title'] },
    'em': {},
    'i': {},
    'li': {},
    'ol': { attributes: ['title'] },
    'strong': {},
    'ul': { attributes: ['title'] },
    'h1': {},
    'h2': {},
    'h3': {},
    'h4': {},
    'h5': {},
    'h6': {},
    'p': { attributes: ['style'], styles: ['text-align'] },
    'u': {},
    'img': { attributes: ['!src', 'alt', 'title'] }
    };

};
<|endoftext|>


<commit_before>$().ready(function() {
    // 根据屏幕宽度置顶样式
    var width = document.body.clientWidth,
        TOTAL = {min: 5, max: 12};
    if (width < 380) {
        alert('请将手机设置成横屏模式！');
        window.location.reload();
        return;
    }
    alert(width);
    if (width <= 480) {
        TOTAL.min = 6;
        $(document.body).addClass("ip4");
    } else if (width >= 660) {
        TOTAL.min = 8;
        $(document.body).addClass("ip6");
    }

    var names = $('.logo-name-wrap').children(),
        logos = $('.logo-wrap').children(),
        idx = 0,
        stages = [
            {theme: 'max-logo-wrap', total: TOTAL.min, bonus: 1},
            /*{theme: 'max-logo-wrap', total: TOTAL.min, bonus: 1},
            {theme: 'max-logo-wrap', total: TOTAL.min, bonus: 1},
            {theme: 'max-logo-wrap', total: TOTAL.min, bonus: 1},
            {theme: 'max-logo-wrap', total: TOTAL.min, bonus: 1},
            {theme: 'max-logo-wrap', total: TOTAL.min, bonus: 1},*/
            //{theme: 'medium-logo-wrap', total: TOTAL.max, bonus: 3},
            //{theme: 'medium-logo-wrap', total: TOTAL.max, bonus: 3},
        ],
        finds = [],
        playing = false,
        bonus = 0,
        seconds = 45;

    if (names.length != logos.length) {
        alert('初始化游戏失败！');
        return;
    }

    // add event
    $('.logo-wrap').on('click', '.active', function(e){
        if (!playing) { return; }

        if (parseInt($(e.currentTarget).attr('data-idx')) == finds[0]) {
            bonus += stages[idx].bonus;
            idx++;
            scene();
        } else {
            $(e.currentTarget).addClass('wrong');
            seconds -= 3;
        }
    });

    function scene() {
        // next
        if (idx >= stages.length) {
            idx = stages.length - 1;
        }

        // reset
        $('.logo-wrap').removeClass('max-logo-wrap');
        $('.logo-wrap .active').removeClass('active');
        $('.logo-name-wrap .active').removeClass('active');
        finds = [];

        // init
        var len = names.length;
        var stage = stages[idx], token = parseInt(12345678 * Math.random()) + parseInt(87654321 * Math.random());
        var map = {};
        for (var i=0; i<stage.total; i++) {
            var position = (token + parseInt(100 * Math.random())) % len;
            while(map[position]) {
                position++;
            }
            map[position] = 1;
            finds.push(position);
        }

        //console.info(finds);

        // render
        $('.logo-wrap').addClass(stage.theme);
        $(names[finds[0]]).addClass('active');
        for (var i=0; i<finds.length; i++) {
            $(logos[finds[i]]).addClass('active');
            $(logos[finds[i]]).attr('data-idx', finds[i]);
        }
    }

    function start() {
        $('#finddiff-entry').hide();
        $('.start').removeClass("layer-show").addClass("layer");
        $('.end').removeClass("layer-show").addClass("layer");
        $('#finddiff-game').show();

        // 开始游戏
        playing = true;
        // 生成场景
        scene();
        // 倒计时
        seconds = 45;
        var timers = setInterval(function() {
            if (seconds <= 0) {
                playing = false;
                update();
                end();
                clearInterval(timers);
            } else {
                $('.remain-time').text('剩余时间：' + --seconds + '秒 金币数：' + bonus + '个');
            }
        }, 1000);
        $('.remain-time').text('剩余时间：' + seconds + '秒 金币数：' + bonus + '个');
    }
    //start();

    function update() {

        $.ajax({
            type: 'GET',
            url: './' + $('#finddiff-game').attr('data-id') + '/bonus',
            data: { bonus: bonus, token: (new Date()).getTime() },
            dataType: 'text',
            success: function(data) {
                var best = parseInt($('.result-wrap .bonus').text()), msg = '';
                if (bonus > best) {
                    msg = '历史最好成绩：' + bonus + '个金币！！！';
                    $('.result-wrap .bonus').text(bonus);
                } else if (bonus > 0) {
                    msg = '本次只获得' + bonus + '个金币，请继续加油！'
                } else {
                    msg = '一句话：加油！'
                }
                alert(msg);
            },
            error: function(xhr, type) {
                alert('无法保存游戏分数！');
            }
        })
    }

    function end() {
        $('#finddiff-entry').show();
        $('.end').addClass("layer-show");
        $('#finddiff-game').hide();
    }

    $('.start-btn').click(function() {
        start();
    });

    $('.restart-btn').click(function() {
        start();
    });

    $('.share-btn').click(function() {
        $("#finddiff-mask").show();
    });
    $("#finddiff-mask").click(function() {
        $(this).hide();
    });
});<commit_msg>add style<commit_after>$().ready(function() {
    // 根据屏幕宽度置顶样式
    var width = document.body.clientWidth,
        TOTAL = {min: 5, max: 12};
    if (width < 380) {
        alert('请将手机设置成横屏模式！');
        window.location.reload();
        return;
    }
    alert(width);
    if (width <= 480) {
        TOTAL.min = 6;
        $(document.body).addClass("ip4");
    } else if (width >= 640) {
        TOTAL.min = 8;
        $(document.body).addClass("ip6");
    }

    var names = $('.logo-name-wrap').children(),
        logos = $('.logo-wrap').children(),
        idx = 0,
        stages = [
            {theme: 'max-logo-wrap', total: TOTAL.min, bonus: 1},
            /*{theme: 'max-logo-wrap', total: TOTAL.min, bonus: 1},
            {theme: 'max-logo-wrap', total: TOTAL.min, bonus: 1},
            {theme: 'max-logo-wrap', total: TOTAL.min, bonus: 1},
            {theme: 'max-logo-wrap', total: TOTAL.min, bonus: 1},
            {theme: 'max-logo-wrap', total: TOTAL.min, bonus: 1},*/
            //{theme: 'medium-logo-wrap', total: TOTAL.max, bonus: 3},
            //{theme: 'medium-logo-wrap', total: TOTAL.max, bonus: 3},
        ],
        finds = [],
        playing = false,
        bonus = 0,
        seconds = 45;

    if (names.length != logos.length) {
        alert('初始化游戏失败！');
        return;
    }

    // add event
    $('.logo-wrap').on('click', '.active', function(e){
        if (!playing) { return; }

        if (parseInt($(e.currentTarget).attr('data-idx')) == finds[0]) {
            bonus += stages[idx].bonus;
            idx++;
            scene();
        } else {
            $(e.currentTarget).addClass('wrong');
            seconds -= 3;
        }
    });

    function scene() {
        // next
        if (idx >= stages.length) {
            idx = stages.length - 1;
        }

        // reset
        $('.logo-wrap').removeClass('max-logo-wrap');
        $('.logo-wrap .active').removeClass('active');
        $('.logo-name-wrap .active').removeClass('active');
        finds = [];

        // init
        var len = names.length;
        var stage = stages[idx], token = parseInt(12345678 * Math.random()) + parseInt(87654321 * Math.random());
        var map = {};
        for (var i=0; i<stage.total; i++) {
            var position = (token + parseInt(100 * Math.random())) % len;
            while(map[position]) {
                position++;
            }
            map[position] = 1;
            finds.push(position);
        }

        //console.info(finds);

        // render
        $('.logo-wrap').addClass(stage.theme);
        $(names[finds[0]]).addClass('active');
        for (var i=0; i<finds.length; i++) {
            $(logos[finds[i]]).addClass('active');
            $(logos[finds[i]]).attr('data-idx', finds[i]);
        }
    }

    function start() {
        $('#finddiff-entry').hide();
        $('.start').removeClass("layer-show").addClass("layer");
        $('.end').removeClass("layer-show").addClass("layer");
        $('#finddiff-game').show();

        // 开始游戏
        playing = true;
        // 生成场景
        scene();
        // 倒计时
        seconds = 45;
        var timers = setInterval(function() {
            if (seconds <= 0) {
                playing = false;
                update();
                end();
                clearInterval(timers);
            } else {
                $('.remain-time').text('剩余时间：' + --seconds + '秒 金币数：' + bonus + '个');
            }
        }, 1000);
        $('.remain-time').text('剩余时间：' + seconds + '秒 金币数：' + bonus + '个');
    }
    //start();

    function update() {

        $.ajax({
            type: 'GET',
            url: './' + $('#finddiff-game').attr('data-id') + '/bonus',
            data: { bonus: bonus, token: (new Date()).getTime() },
            dataType: 'text',
            success: function(data) {
                var best = parseInt($('.result-wrap .bonus').text()), msg = '';
                if (bonus > best) {
                    msg = '历史最好成绩：' + bonus + '个金币！！！';
                    $('.result-wrap .bonus').text(bonus);
                } else if (bonus > 0) {
                    msg = '本次只获得' + bonus + '个金币，请继续加油！'
                } else {
                    msg = '一句话：加油！'
                }
                alert(msg);
            },
            error: function(xhr, type) {
                alert('无法保存游戏分数！');
            }
        })
    }

    function end() {
        $('#finddiff-entry').show();
        $('.end').addClass("layer-show");
        $('#finddiff-game').hide();
    }

    $('.start-btn').click(function() {
        start();
    });

    $('.restart-btn').click(function() {
        start();
    });

    $('.share-btn').click(function() {
        $("#finddiff-mask").show();
    });
    $("#finddiff-mask").click(function() {
        $(this).hide();
    });
});<|endoftext|>


<commit_before>import Ember from 'ember';

let cachedRequireEntries;
let cachedScriptTags;
let cachedLinkTags;

/**
 * Determines whether an array contains the provided item.
 *
 * @param {Array} array
 * @param {Any} item
 * @return {Boolean}
 */
function has(array, item) {
  return array.indexOf(item) !== -1;
}

/**
 * Returns a function which you only want to run once
 * @param {Function} fn
 * @param {Any} context
 * @return {Function|null}
 */
function once(fn, context) {
  let result;

  return () => {
    if (fn) {
      result = fn.apply(context || this, arguments);
      fn = null;
    }
    return result;
  };
}

/**
 * Removes a DOM Node from the document.
 *
 * @param {Node} node
 * @return {Void}
 */
function removeNode(node) {
  node.parentNode.removeChild(node);
}

/**
 * Converts an iterable object into an actual Array.
 *
 * @param {Iterable} iterable
 * @return {Array}
 */
function toArray(iterable) {
  return Array.prototype.slice.call(iterable);
}

/**
 * Returns all of the HTML Elements matching a given selector as an array.
 *
 * @param {String} selector
 * @return {Array<HTMLElement>}
 */
function getAll(selector) {
  const htmlCollection = document.querySelectorAll(selector);
  return toArray(htmlCollection);
}

/**
 * Deletes an entry from require's list of modules.
 *
 * @param {String} entry
 * @return {Void}
 */
function resetRequireEntry(entry) {
  delete self.requirejs.entries[entry];
}

/**
 * Compares two arrays, if they're different, invokes a callback for each
 * entry that does not appear in the initial array.
 *
 * @param {Array} initial
 * @param {Array} current
 * @param {Function} diffHandler
 * @return {Void}
 */
function compareAndIterate(initial, current, diffHandler) {
  if (initial.length < current.length) {
    for (let i = 0; i < current.length; i++) {
      let entry = current[i];
      if (!has(initial, entry)) {
        diffHandler(entry);
      }
    }
  }
}

/**
 * Gets the current loaded asset state including scripts, links, and require
 * modules.
 *
 * @return {Object}
 */
export function getLoadedAssetState() {
  return {
    requireEntries: Object.keys(self.requirejs.entries),
    scripts: getAll('script'),
    links: getAll('link')
  };
}

/**
 * Caches the current loaded asset state with regards to links, scripts, and JS
 * modules currently present.
 *
 * @return {Void}
 */
export function cacheLoadedAssetState() {
  ({
    requireEntries: cachedRequireEntries,
    scripts: cachedScriptTags,
    links: cachedLinkTags
  } = getLoadedAssetState());
}

/**
 * Restores the loaded asset state to the previous cached value with regards to
 * links, scripts, and JS modules.
 *
 * @return {Void}
 */
export function resetLoadedAssetState() {
  const {
    requireEntries: currentRequireEntries,
    scripts: currentScriptTags,
    links: currentLinkTags
  } = getLoadedAssetState();

  compareAndIterate(cachedRequireEntries, currentRequireEntries, resetRequireEntry);
  compareAndIterate(cachedScriptTags, currentScriptTags, removeNode);
  compareAndIterate(cachedLinkTags, currentLinkTags, removeNode);
}
<commit_msg>removes needless function<commit_after>import Ember from 'ember';

let cachedRequireEntries;
let cachedScriptTags;
let cachedLinkTags;

/**
 * Determines whether an array contains the provided item.
 *
 * @param {Array} array
 * @param {Any} item
 * @return {Boolean}
 */
function has(array, item) {
  return array.indexOf(item) !== -1;
}

/**
 * Removes a DOM Node from the document.
 *
 * @param {Node} node
 * @return {Void}
 */
function removeNode(node) {
  node.parentNode.removeChild(node);
}

/**
 * Converts an iterable object into an actual Array.
 *
 * @param {Iterable} iterable
 * @return {Array}
 */
function toArray(iterable) {
  return Array.prototype.slice.call(iterable);
}

/**
 * Returns all of the HTML Elements matching a given selector as an array.
 *
 * @param {String} selector
 * @return {Array<HTMLElement>}
 */
function getAll(selector) {
  const htmlCollection = document.querySelectorAll(selector);
  return toArray(htmlCollection);
}

/**
 * Deletes an entry from require's list of modules.
 *
 * @param {String} entry
 * @return {Void}
 */
function resetRequireEntry(entry) {
  delete self.requirejs.entries[entry];
}

/**
 * Compares two arrays, if they're different, invokes a callback for each
 * entry that does not appear in the initial array.
 *
 * @param {Array} initial
 * @param {Array} current
 * @param {Function} diffHandler
 * @return {Void}
 */
function compareAndIterate(initial, current, diffHandler) {
  if (initial.length < current.length) {
    for (let i = 0; i < current.length; i++) {
      let entry = current[i];
      if (!has(initial, entry)) {
        diffHandler(entry);
      }
    }
  }
}

/**
 * Gets the current loaded asset state including scripts, links, and require
 * modules.
 *
 * @return {Object}
 */
export function getLoadedAssetState() {
  return {
    requireEntries: Object.keys(self.requirejs.entries),
    scripts: getAll('script'),
    links: getAll('link')
  };
}

/**
 * Caches the current loaded asset state with regards to links, scripts, and JS
 * modules currently present.
 *
 * @return {Void}
 */
export function cacheLoadedAssetState() {
  ({
    requireEntries: cachedRequireEntries,
    scripts: cachedScriptTags,
    links: cachedLinkTags
  } = getLoadedAssetState());
}

/**
 * Restores the loaded asset state to the previous cached value with regards to
 * links, scripts, and JS modules.
 *
 * @return {Void}
 */
export function resetLoadedAssetState() {
  const {
    requireEntries: currentRequireEntries,
    scripts: currentScriptTags,
    links: currentLinkTags
  } = getLoadedAssetState();

  compareAndIterate(cachedRequireEntries, currentRequireEntries, resetRequireEntry);
  compareAndIterate(cachedScriptTags, currentScriptTags, removeNode);
  compareAndIterate(cachedLinkTags, currentLinkTags, removeNode);
}
<|endoftext|>


<commit_before>/* eslint-disable object-shorthand */

// Get various parts of the WebExtension framework that we need.
var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");

// You probably already know what this does.
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");

// This is the important part. It implements the functions and events defined in schema.json.
// The variable must have the same name you've been using so far, "myapi" in this case.
var compose_ext = class extends ExtensionCommon.ExtensionAPI {
  getAPI(context) {
    let { extension } = context;
    let { tabManager, windowManager } = extension;
    async function getTabWindow(tabId){
      return (await tabManager.get(tabId)).nativeTab;
    }
    return {
      // Again, this key must have the same name.
      compose_ext: {

        getCurrentLanguage: async function(tabId) {
          return (await getTabWindow(tabId)).document.documentElement.getAttribute("lang");
        },

        canSpellCheck: async function(tabId) {
          var window = await getTabWindow(tabId);
          if(Services.appinfo.version > '89.0') return true;
          return window.gSpellChecker && window.gSpellChecker.canSpellCheck && window.gSpellChecker.enabled;
        },

        setSpellCheckerLanguage: async function(tabId, lang) {
          var window = await getTabWindow(tabId);
          var fake_event = {
            target: {
              value: lang
            },
            stopPropagation: function(){}
          };
          return window.ChangeLanguage(fake_event);
        },

        showNotification: async function(tabId, string, options){
          options = options || {};
          var window = await getTabWindow(tabId);
          var notification_value = "show-message";
          //FIXME: DRY this code with changeLabel
          let nb = (window.gNotification && window.gNotification.notificationbox) || window.gComposeNotification;
          var n = nb.getNotificationWithValue(notification_value);
          if(n) {
            n.label = string;
          } else {
            var buttons = options.buttons || [];
            var priority = nb.PRIORITY_INFO_HIGH;
            if(Services.appinfo.version >= '92.0'){
              n = nb.appendNotification(
                notification_value,
                {
                  image: options.logo_url,
                  priority: priority,
                  label: string
                },
                buttons);
            }else
              n = nb.appendNotification(string, notification_value, options.logo_url, priority, buttons);
          }
          // setup timeout
          if (options.notification_time) {
            if(this.label_timeout){
              window.clearTimeout(this.label_timeout);
            }
            this.label_timeout = window.setTimeout( function(){
              nb.removeNotification( n );
            }, options.notification_time);
          }
        },

        // An event. Most of this is boilerplate you don't need to worry about, just copy it.
        onLanguageChange: new ExtensionCommon.EventManager({
          context,
          name: "compose_ext.onLanguageChange",
          // In this function we add listeners for any events we want to listen to, and return a
          // function that removes those listeners. To have the event fire in your extension,
          // call fire.async.
          register(fire) {
            function callback(event_name, event, language) {
              let win = windowManager.wrapWindow(event.target.ownerGlobal);
              var tab = tabManager.convert(win.activeTab.nativeTab);
              return fire.async(tab.id, language);
            }

            windowListener.add(callback);
            return function() {
              windowListener.remove(callback);
            };
          },
        }).api(),

        onRecipientsChange: new ExtensionCommon.EventManager({
          context,
          name: "compose_ext.onRecipientsChange",
          // In this function we add listeners for any events we want to listen to, and return a
          // function that removes those listeners. To have the event fire in your extension,
          // call fire.async.
          register(fire) {
            function callback(event_name, event) {
              let win = windowManager.wrapWindow(event.target.ownerGlobal);
              var tab = tabManager.convert(win.activeTab.nativeTab);
              return fire.async(tab.id);
            }

            recipientsChangeWindowListener.add(callback);
            return function() {
              recipientsChangeWindowListener.remove(callback);
            };
          },
        }).api(),

      },
    };
  }
};

// A helpful class for listening to windows opening and closing.
// (This file had a lowercase E in Thunderbird 65 and earlier.)
var { ExtensionSupport } = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm");

// This object is just what we're using to listen for toolbar clicks. The implementation isn't
// what this example is about, but you might be interested as it's a common pattern. We count the
// number of callbacks waiting for events so that we're only listening if we need to be.
var windowListener = new class extends ExtensionCommon.EventEmitter {
  constructor() {
    super();
    this.callbackCount = 0;
  }

  handleEvent(event) {
    var lang = event.target.getAttribute('lang');
    windowListener.emit("language-changed", event, lang);
  }

  add(callback) {
    this.on("language-changed", callback);
    this.callbackCount++;

    if (this.callbackCount == 1) {
      ExtensionSupport.registerWindowListener("compose_ext-windowListener", {
        //TODO: set composer url.
        chromeURLs: ["chrome://messenger/content/messengercompose/messengercompose.xhtml"],
        onLoadWindow: function(window) {
          windowListener.subscribeLanguageChangeEvents(window);
        },
      });
    }
  }

  remove(callback) {
    this.off("language-changed", callback);
    this.callbackCount--;

    if (this.callbackCount == 0) {
      ExtensionSupport.unregisterWindowListener("compose_ext-windowListener");
    }
  }

  subscribeLanguageChangeEvents(window) {
    //We don't capture "spellcheck-changed" event because it's only fired
    //when language is changed in the context menu (rigt click menu). Not when changed
    //from any other source.

    // The document lang attribute is updated always so its the best way.
    var langObserver = new window.MutationObserver(function(mutations) {
      mutations.forEach(function(mutation) {
        if (mutation.type == "attributes" && mutation.attributeName == "lang") {
          windowListener.handleEvent(mutation);
        }
      });
    });
    langObserver.observe(window.document.documentElement, { attributes: true });
  }
};

var recipientsChangeWindowListener = new class extends ExtensionCommon.EventEmitter {
  constructor() {
    super();
    this.callbackCount = 0;
  }

  handleEvent(event) {
    recipientsChangeWindowListener.emit("recipients-changed", event);
  }

  add(callback) {
    this.on("recipients-changed", callback);
    this.callbackCount++;

    if (this.callbackCount == 1) {
      ExtensionSupport.registerWindowListener("recipientsChangeWindowListener", {
        chromeURLs: ["chrome://messenger/content/messengercompose/messengercompose.xhtml"],
        onLoadWindow: function(window) {
          recipientsChangeWindowListener.detectRecipientsChange(window);
        },
      });
    }
  }

  remove(callback) {
    this.off("recipients-changed", callback);
    this.callbackCount--;

    if (this.callbackCount == 0) {
      ExtensionSupport.unregisterWindowListener("recipientsChangeWindowListener");
    }
  }

  detectRecipientsChange(window) {
    window.document.getElementById('recipientsContainer').addEventListener('change', function(event) {
      recipientsChangeWindowListener.handleEvent(event);
    });

    window.document.getElementById('msgSubject').addEventListener('focus', function(event) {
      recipientsChangeWindowListener.handleEvent(event);
    });

    window.document.getElementById('content-frame').addEventListener('focus', function(event){
      recipientsChangeWindowListener.handleEvent(event);
    });
  }
};<commit_msg>Remove old FIXME in compose_ext<commit_after>/* eslint-disable object-shorthand */

// Get various parts of the WebExtension framework that we need.
var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");

// You probably already know what this does.
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");

// This is the important part. It implements the functions and events defined in schema.json.
// The variable must have the same name you've been using so far, "myapi" in this case.
var compose_ext = class extends ExtensionCommon.ExtensionAPI {
  getAPI(context) {
    let { extension } = context;
    let { tabManager, windowManager } = extension;
    async function getTabWindow(tabId){
      return (await tabManager.get(tabId)).nativeTab;
    }
    return {
      // Again, this key must have the same name.
      compose_ext: {

        getCurrentLanguage: async function(tabId) {
          return (await getTabWindow(tabId)).document.documentElement.getAttribute("lang");
        },

        canSpellCheck: async function(tabId) {
          var window = await getTabWindow(tabId);
          if(Services.appinfo.version > '89.0') return true;
          return window.gSpellChecker && window.gSpellChecker.canSpellCheck && window.gSpellChecker.enabled;
        },

        setSpellCheckerLanguage: async function(tabId, lang) {
          var window = await getTabWindow(tabId);
          var fake_event = {
            target: {
              value: lang
            },
            stopPropagation: function(){}
          };
          return window.ChangeLanguage(fake_event);
        },

        showNotification: async function(tabId, string, options){
          options = options || {};
          var window = await getTabWindow(tabId);
          var notification_value = "show-message";
          let nb = (window.gNotification && window.gNotification.notificationbox) || window.gComposeNotification;
          var n = nb.getNotificationWithValue(notification_value);
          if(n) {
            n.label = string;
          } else {
            var buttons = options.buttons || [];
            var priority = nb.PRIORITY_INFO_HIGH;
            if(Services.appinfo.version >= '92.0'){
              n = nb.appendNotification(
                notification_value,
                {
                  image: options.logo_url,
                  priority: priority,
                  label: string
                },
                buttons);
            }else
              n = nb.appendNotification(string, notification_value, options.logo_url, priority, buttons);
          }
          // setup timeout
          if (options.notification_time) {
            if(this.label_timeout){
              window.clearTimeout(this.label_timeout);
            }
            this.label_timeout = window.setTimeout( function(){
              nb.removeNotification( n );
            }, options.notification_time);
          }
        },

        // An event. Most of this is boilerplate you don't need to worry about, just copy it.
        onLanguageChange: new ExtensionCommon.EventManager({
          context,
          name: "compose_ext.onLanguageChange",
          // In this function we add listeners for any events we want to listen to, and return a
          // function that removes those listeners. To have the event fire in your extension,
          // call fire.async.
          register(fire) {
            function callback(event_name, event, language) {
              let win = windowManager.wrapWindow(event.target.ownerGlobal);
              var tab = tabManager.convert(win.activeTab.nativeTab);
              return fire.async(tab.id, language);
            }

            windowListener.add(callback);
            return function() {
              windowListener.remove(callback);
            };
          },
        }).api(),

        onRecipientsChange: new ExtensionCommon.EventManager({
          context,
          name: "compose_ext.onRecipientsChange",
          // In this function we add listeners for any events we want to listen to, and return a
          // function that removes those listeners. To have the event fire in your extension,
          // call fire.async.
          register(fire) {
            function callback(event_name, event) {
              let win = windowManager.wrapWindow(event.target.ownerGlobal);
              var tab = tabManager.convert(win.activeTab.nativeTab);
              return fire.async(tab.id);
            }

            recipientsChangeWindowListener.add(callback);
            return function() {
              recipientsChangeWindowListener.remove(callback);
            };
          },
        }).api(),

      },
    };
  }
};

// A helpful class for listening to windows opening and closing.
// (This file had a lowercase E in Thunderbird 65 and earlier.)
var { ExtensionSupport } = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm");

// This object is just what we're using to listen for toolbar clicks. The implementation isn't
// what this example is about, but you might be interested as it's a common pattern. We count the
// number of callbacks waiting for events so that we're only listening if we need to be.
var windowListener = new class extends ExtensionCommon.EventEmitter {
  constructor() {
    super();
    this.callbackCount = 0;
  }

  handleEvent(event) {
    var lang = event.target.getAttribute('lang');
    windowListener.emit("language-changed", event, lang);
  }

  add(callback) {
    this.on("language-changed", callback);
    this.callbackCount++;

    if (this.callbackCount == 1) {
      ExtensionSupport.registerWindowListener("compose_ext-windowListener", {
        //TODO: set composer url.
        chromeURLs: ["chrome://messenger/content/messengercompose/messengercompose.xhtml"],
        onLoadWindow: function(window) {
          windowListener.subscribeLanguageChangeEvents(window);
        },
      });
    }
  }

  remove(callback) {
    this.off("language-changed", callback);
    this.callbackCount--;

    if (this.callbackCount == 0) {
      ExtensionSupport.unregisterWindowListener("compose_ext-windowListener");
    }
  }

  subscribeLanguageChangeEvents(window) {
    //We don't capture "spellcheck-changed" event because it's only fired
    //when language is changed in the context menu (rigt click menu). Not when changed
    //from any other source.

    // The document lang attribute is updated always so its the best way.
    var langObserver = new window.MutationObserver(function(mutations) {
      mutations.forEach(function(mutation) {
        if (mutation.type == "attributes" && mutation.attributeName == "lang") {
          windowListener.handleEvent(mutation);
        }
      });
    });
    langObserver.observe(window.document.documentElement, { attributes: true });
  }
};

var recipientsChangeWindowListener = new class extends ExtensionCommon.EventEmitter {
  constructor() {
    super();
    this.callbackCount = 0;
  }

  handleEvent(event) {
    recipientsChangeWindowListener.emit("recipients-changed", event);
  }

  add(callback) {
    this.on("recipients-changed", callback);
    this.callbackCount++;

    if (this.callbackCount == 1) {
      ExtensionSupport.registerWindowListener("recipientsChangeWindowListener", {
        chromeURLs: ["chrome://messenger/content/messengercompose/messengercompose.xhtml"],
        onLoadWindow: function(window) {
          recipientsChangeWindowListener.detectRecipientsChange(window);
        },
      });
    }
  }

  remove(callback) {
    this.off("recipients-changed", callback);
    this.callbackCount--;

    if (this.callbackCount == 0) {
      ExtensionSupport.unregisterWindowListener("recipientsChangeWindowListener");
    }
  }

  detectRecipientsChange(window) {
    window.document.getElementById('recipientsContainer').addEventListener('change', function(event) {
      recipientsChangeWindowListener.handleEvent(event);
    });

    window.document.getElementById('msgSubject').addEventListener('focus', function(event) {
      recipientsChangeWindowListener.handleEvent(event);
    });

    window.document.getElementById('content-frame').addEventListener('focus', function(event){
      recipientsChangeWindowListener.handleEvent(event);
    });
  }
};<|endoftext|>