<commit_before>(function(w,d,$,undefined){
  'use strict';

  w.simpleEditor = (function(){

    var simpleEditor = function(options){
      this.el = false;
      if (typeof options.el !== "undefined"){
        this.$el = typeof options.el == "string" ? $(options.el) : options.el;
        this.el = this.$el[0];
      }

      this.static_url = $('meta[name="subdomain"]').attr('content');
      if (typeof options.static_url !== 'undefined'){
        this.static_url = options.static_url;
      }

      this.no_attachments = false;
      if (typeof options.no_attachments !== 'undefined'){
        this.no_attachments = options.no_attachments;
      }

      this.textarea = this.$el.find('textarea')[0];

      this.form = this.$el.find('form');

      this.bind();

      return this;
    };

    simpleEditor.prototype.nothingSelected = function(){
      return this.el.selectionStart === this.el.selectionEnd;
    };

    simpleEditor.prototype.getSelectionDetailsObject = function(){

      var text           = this.textarea.value,
          startPos       = this.textarea.selectionStart,
          endPos         = this.textarea.selectionEnd,
          selectedLength = this.textarea.selectionEnd-this.textarea.selectionStart;

      var startText     = text.substr(0,startPos),
          selectedText  = text.substr(startPos,selectedLength),
          endText       = text.substr(endPos,text.length);

      var retval = {
        start     : {
          position : startPos,
          text     : startText
        },
        end       : {
          position : endPos,
          text     : endText
        },
        selected  : {
          length   : selectedLength,
          text     : selectedText
        }
      };

      return retval;

    };

    simpleEditor.prototype.applyFormatting = function(text, tag){

      // splits text into array by newlines and applies tag to each index of array.
      var selectedTextFragments = text.split(/\n/g);
      for(var i=0,j=selectedTextFragments.length;i<j;i++){
          selectedTextFragments[i] = tag.replace(/%s/g, selectedTextFragments[i]);
      }

      var formattedText = selectedTextFragments.join('\n');

      return formattedText;
    };

    simpleEditor.prototype.formattedTextWith = function(tag){

      var selection = this.getSelectionDetailsObject();

      var newText = selection.start.text +
                    this.applyFormatting(selection.selected.text, tag) +
                    selection.end.text;

      return newText;
    };

    simpleEditor.prototype.insertLinkWith = function(tag){

      var selection = this.getSelectionDetailsObject();
      var link, newText;

      if (selection.selected.length < 1){
        link = w.prompt("Paste url here:");
        if (!link){
          return false;
        }
      }else{
        link = selection.selected.text;
      }

      newText = selection.start.text +
                    this.applyFormatting(link, tag) +
                    selection.end.text;

      return newText;
    };

    simpleEditor.prototype.h1 = function(){
      this.textarea.value = this.formattedTextWith("\n%s\n====");
    };

    simpleEditor.prototype.bold = function(){
      this.textarea.value = this.formattedTextWith("**%s**");
    };

    simpleEditor.prototype.italics = function(){
      this.textarea.value = this.formattedTextWith("*%s*");
    };

    simpleEditor.prototype.list = function(){
      this.textarea.value = this.formattedTextWith("*%s");
    };

    simpleEditor.prototype.quote = function(){
      this.textarea.value = this.formattedTextWith("> %s");
    };

    simpleEditor.prototype.link = function(){
      var output = this.insertLinkWith("[%s](%s)");
      if (output){
        this.textarea.value = output;
      }
    };

    simpleEditor.prototype.image = function(){

      var output = this.insertLinkWith("![%s](%s)");
      if (output){
        this.textarea.value = output;
      }
    };

    simpleEditor.prototype.fetchAttachments = function(options){

      var ajaxOptions = {
        url   : "",
        type  : 'GET'
      };

      if (typeof options !== 'undefined' &&
          typeof options == 'object'){
        ajaxOptions = $.extend({},ajaxOptions, options);
      }

      console.log(ajaxOptions);

      return $.ajax(ajaxOptions);

    };

    simpleEditor.prototype.clearAttachmentGallery = function(e){
      this.$el.find('.reply-box-attachments-gallery').html("");
      this.fileHandler.clear();
    };

    simpleEditor.prototype.renderAttachmentGallery = function(files){
      var ul,li,img,span;

      ul = document.createElement('ul');

      if(files.length>0){
        for(var i=0,j=files.length;i<j;i++){
          img = document.createElement('img');

          if (typeof files[i].meta !== 'undefined'){
            if (typeof files[i].meta.links !== 'undefined'){
              img.src = this.static_url + files[i].meta.links[0].href;
            }
          }else{
            img.src = files[i].data;
          }
          if (typeof files[i].fileHash !== 'undefined'){
            img.name = files[i].fileHash;
          }

          li = document.createElement('li');
          li.appendChild(img);

          span = document.createElement('span');
          span.className = 'remove';
          span.innerHTML = "×";
          li.appendChild(span);

          ul.appendChild(li);
        }
      }
      this.$el.find('.reply-box-attachments-gallery').html(ul);
    };

    simpleEditor.prototype.removeAttachmentFile = function(e){
      var self = $(e.currentTarget),
          parent = self.parent(),
          fileToBeRemoved = parent.find('img[name]');

      var delete_confirm = window.confirm("Are you sure you want to remove this attachment?");

      if (delete_confirm){
        if (fileToBeRemoved.length > 0){

          if (typeof this.attachments_delete == 'undefined'){
            this.attachments_delete = [];
          }

          var field_attachments_delete = this.form.find('input[name="attachments-delete"]');

          if (field_attachments_delete.length < 1){
            field_attachments_delete = $('<input name="attachments-delete" type="hidden"/>');
            this.form.append(field_attachments_delete);
          }

          if (this.attachments_delete.indexOf(fileToBeRemoved.attr('name')) === -1){
            this.attachments_delete.push(fileToBeRemoved.attr('name'));
            field_attachments_delete.val(this.attachments_delete.join(','));
          }

        }else{
          this.fileHandler.removeFile(self.index());
        }
        parent.remove();
      }

    };

    simpleEditor.prototype.toggleMarkdownPreview = function(e){
      var preview_window = this.$el.find('.wmd-preview-wrapper');

      preview_window.css('height', window.getComputedStyle(this.textarea).height);
      preview_window.toggle();
    }

    simpleEditor.prototype.bind = function(){

      // create a new instance of markdown.editor.js

      var converter = new Markdown.Converter();
      var help      = { handler : function(){ alert('help!'); } };
      this.editor = new Markdown.Editor(converter, this.$el, help);
      this.editor.run();
      window.editor = this.editor;

      //////////////////////
      //   attachments    //
      //////////////////////
      if (typeof FileHandler !== 'undefined' && !this.no_attachments){

        this.fileHandler = new FileHandler({
          el : this.$el.find('.reply-box-attachments')[0],
          dropzone : '.reply-box-drop-zone, .reply-box-attachments-gallery'
        });
        // this callback fires when dropped event fires and all files are collected
        this.fileHandler.onDragged($.proxy(function(files){
          this.renderAttachmentGallery(files);
        },this));

        this.fileHandler.onRemove($.proxy(function(files){
          this.renderAttachmentGallery(files);
        },this));

        // check for data-num-attachments attribute, if 1 or more
        // fire off an ajax call for the attachments json
        // on a response, pass the attachment items to the renderAttachmentGallery()
        var num_attachments = parseInt(this.$el.attr('data-num-attachments'),10);

        if (!isNaN(num_attachments) && num_attachments > 0){
          this.$el.find('.reply-box-attachments-gallery').html("Loading attachments...");

          this.fetchAttachments({
            url : this.$el.attr('data-source') + "attachments"
          }).success($.proxy(function(response){
            if (typeof response.data.attachments !== 'undefined'){
              this.renderAttachmentGallery(response.data.attachments.items);
            }
          },this));

        }
      }

      //////////////////////
      //   textcomplete   //
      //////////////////////

      var subdomain = $('meta[name="subdomain"]').attr('content'),
          static_url = subdomain,
          dataSource = subdomain + '/api/v1/profiles?disableBoiler&top=true&q=';

      if (typeof $.fn.textcomplete !== 'undefined'){

        $(this.textarea).textcomplete([
          {
            match: /\B([@+][\-+\w]*)$/,
            search: function (term, callback) {

              var _term = term.substr(1,term.length-1),
                  _symbol = term[0],
                  _callback = callback;

              $.ajax({
                url : dataSource + _term,
              }).success(function(data){

                _callback($.map(data.profiles.items, function (person) {
                    if (person.profileName.toLowerCase().indexOf(_term.toLowerCase()) === 0){
                      person.symbol = _symbol;

                      return person;
                    }else{
                      return null;
                    }
                }));
              });
            },
            template: function (person) {

                var img_src = static_url + person.avatar;

                if (person.avatar.indexOf('http://')===0){
                  img_src = person.avatar;
                }
                return '<img src="' + img_src + '" /> ' + person.symbol + person.profileName;
            },
            replace: function (person) {
                return person.symbol + person.profileName;
            },
            index: 1,
            maxCount: 5
          }
        ]);
      }

      ////////////////////////
      //     bind events    //
      ////////////////////////
      var events = [
        ['reset', 'form',        'clearAttachmentGallery'],
        ['click', '.reply-box-attachments-gallery li span.remove', 'removeAttachmentFile'],

        ['click', '.wmd-preview-button', 'toggleMarkdownPreview']
      ];

      for(var i in events){
        this.$el.on(events[i][0], events[i][1], $.proxy(this[events[i][2]], this) );
      }
    };

    return simpleEditor;
  })();

})(window,document,jQuery);<commit_msg>fire pretty print call after generating markdown preview<commit_after>(function(w,d,$,undefined){
  'use strict';

  w.simpleEditor = (function(){

    var simpleEditor = function(options){
      this.el = false;
      if (typeof options.el !== "undefined"){
        this.$el = typeof options.el == "string" ? $(options.el) : options.el;
        this.el = this.$el[0];
      }

      this.static_url = $('meta[name="subdomain"]').attr('content');
      if (typeof options.static_url !== 'undefined'){
        this.static_url = options.static_url;
      }

      this.no_attachments = false;
      if (typeof options.no_attachments !== 'undefined'){
        this.no_attachments = options.no_attachments;
      }

      this.textarea = this.$el.find('textarea')[0];

      this.form = this.$el.find('form');

      this.bind();

      return this;
    };

    simpleEditor.prototype.nothingSelected = function(){
      return this.el.selectionStart === this.el.selectionEnd;
    };

    simpleEditor.prototype.getSelectionDetailsObject = function(){

      var text           = this.textarea.value,
          startPos       = this.textarea.selectionStart,
          endPos         = this.textarea.selectionEnd,
          selectedLength = this.textarea.selectionEnd-this.textarea.selectionStart;

      var startText     = text.substr(0,startPos),
          selectedText  = text.substr(startPos,selectedLength),
          endText       = text.substr(endPos,text.length);

      var retval = {
        start     : {
          position : startPos,
          text     : startText
        },
        end       : {
          position : endPos,
          text     : endText
        },
        selected  : {
          length   : selectedLength,
          text     : selectedText
        }
      };

      return retval;

    };

    simpleEditor.prototype.applyFormatting = function(text, tag){

      // splits text into array by newlines and applies tag to each index of array.
      var selectedTextFragments = text.split(/\n/g);
      for(var i=0,j=selectedTextFragments.length;i<j;i++){
          selectedTextFragments[i] = tag.replace(/%s/g, selectedTextFragments[i]);
      }

      var formattedText = selectedTextFragments.join('\n');

      return formattedText;
    };

    simpleEditor.prototype.formattedTextWith = function(tag){

      var selection = this.getSelectionDetailsObject();

      var newText = selection.start.text +
                    this.applyFormatting(selection.selected.text, tag) +
                    selection.end.text;

      return newText;
    };

    simpleEditor.prototype.insertLinkWith = function(tag){

      var selection = this.getSelectionDetailsObject();
      var link, newText;

      if (selection.selected.length < 1){
        link = w.prompt("Paste url here:");
        if (!link){
          return false;
        }
      }else{
        link = selection.selected.text;
      }

      newText = selection.start.text +
                    this.applyFormatting(link, tag) +
                    selection.end.text;

      return newText;
    };

    simpleEditor.prototype.h1 = function(){
      this.textarea.value = this.formattedTextWith("\n%s\n====");
    };

    simpleEditor.prototype.bold = function(){
      this.textarea.value = this.formattedTextWith("**%s**");
    };

    simpleEditor.prototype.italics = function(){
      this.textarea.value = this.formattedTextWith("*%s*");
    };

    simpleEditor.prototype.list = function(){
      this.textarea.value = this.formattedTextWith("*%s");
    };

    simpleEditor.prototype.quote = function(){
      this.textarea.value = this.formattedTextWith("> %s");
    };

    simpleEditor.prototype.link = function(){
      var output = this.insertLinkWith("[%s](%s)");
      if (output){
        this.textarea.value = output;
      }
    };

    simpleEditor.prototype.image = function(){

      var output = this.insertLinkWith("![%s](%s)");
      if (output){
        this.textarea.value = output;
      }
    };

    simpleEditor.prototype.fetchAttachments = function(options){

      var ajaxOptions = {
        url   : "",
        type  : 'GET'
      };

      if (typeof options !== 'undefined' &&
          typeof options == 'object'){
        ajaxOptions = $.extend({},ajaxOptions, options);
      }

      console.log(ajaxOptions);

      return $.ajax(ajaxOptions);

    };

    simpleEditor.prototype.clearAttachmentGallery = function(e){
      this.$el.find('.reply-box-attachments-gallery').html("");
      this.fileHandler.clear();
    };

    simpleEditor.prototype.renderAttachmentGallery = function(files){
      var ul,li,img,span;

      ul = document.createElement('ul');

      if(files.length>0){
        for(var i=0,j=files.length;i<j;i++){
          img = document.createElement('img');

          if (typeof files[i].meta !== 'undefined'){
            if (typeof files[i].meta.links !== 'undefined'){
              img.src = this.static_url + files[i].meta.links[0].href;
            }
          }else{
            img.src = files[i].data;
          }
          if (typeof files[i].fileHash !== 'undefined'){
            img.name = files[i].fileHash;
          }

          li = document.createElement('li');
          li.appendChild(img);

          span = document.createElement('span');
          span.className = 'remove';
          span.innerHTML = "×";
          li.appendChild(span);

          ul.appendChild(li);
        }
      }
      this.$el.find('.reply-box-attachments-gallery').html(ul);
    };

    simpleEditor.prototype.removeAttachmentFile = function(e){
      var self = $(e.currentTarget),
          parent = self.parent(),
          fileToBeRemoved = parent.find('img[name]');

      var delete_confirm = window.confirm("Are you sure you want to remove this attachment?");

      if (delete_confirm){
        if (fileToBeRemoved.length > 0){

          if (typeof this.attachments_delete == 'undefined'){
            this.attachments_delete = [];
          }

          var field_attachments_delete = this.form.find('input[name="attachments-delete"]');

          if (field_attachments_delete.length < 1){
            field_attachments_delete = $('<input name="attachments-delete" type="hidden"/>');
            this.form.append(field_attachments_delete);
          }

          if (this.attachments_delete.indexOf(fileToBeRemoved.attr('name')) === -1){
            this.attachments_delete.push(fileToBeRemoved.attr('name'));
            field_attachments_delete.val(this.attachments_delete.join(','));
          }

        }else{
          this.fileHandler.removeFile(self.index());
        }
        parent.remove();
      }

    };

    simpleEditor.prototype.toggleMarkdownPreview = function(e){
      var preview_window = this.$el.find('.wmd-preview-wrapper');

      preview_window.css('height', window.getComputedStyle(this.textarea).height);
      preview_window.toggle();
      if (typeof prettyPrint !== 'undefined'){
        prettyPrint();
      }
    }

    simpleEditor.prototype.bind = function(){

      // create a new instance of markdown.editor.js

      var converter = new Markdown.Converter();
      var help      = { handler : function(){ alert('help!'); } };
      this.editor = new Markdown.Editor(converter, this.$el, help);
      this.editor.run();
      window.editor = this.editor;

      //////////////////////
      //   attachments    //
      //////////////////////
      if (typeof FileHandler !== 'undefined' && !this.no_attachments){

        this.fileHandler = new FileHandler({
          el : this.$el.find('.reply-box-attachments')[0],
          dropzone : '.reply-box-drop-zone, .reply-box-attachments-gallery'
        });
        // this callback fires when dropped event fires and all files are collected
        this.fileHandler.onDragged($.proxy(function(files){
          this.renderAttachmentGallery(files);
        },this));

        this.fileHandler.onRemove($.proxy(function(files){
          this.renderAttachmentGallery(files);
        },this));

        // check for data-num-attachments attribute, if 1 or more
        // fire off an ajax call for the attachments json
        // on a response, pass the attachment items to the renderAttachmentGallery()
        var num_attachments = parseInt(this.$el.attr('data-num-attachments'),10);

        if (!isNaN(num_attachments) && num_attachments > 0){
          this.$el.find('.reply-box-attachments-gallery').html("Loading attachments...");

          this.fetchAttachments({
            url : this.$el.attr('data-source') + "attachments"
          }).success($.proxy(function(response){
            if (typeof response.data.attachments !== 'undefined'){
              this.renderAttachmentGallery(response.data.attachments.items);
            }
          },this));

        }
      }

      //////////////////////
      //   textcomplete   //
      //////////////////////

      var subdomain = $('meta[name="subdomain"]').attr('content'),
          static_url = subdomain,
          dataSource = subdomain + '/api/v1/profiles?disableBoiler&top=true&q=';

      if (typeof $.fn.textcomplete !== 'undefined'){

        $(this.textarea).textcomplete([
          {
            match: /\B([@+][\-+\w]*)$/,
            search: function (term, callback) {

              var _term = term.substr(1,term.length-1),
                  _symbol = term[0],
                  _callback = callback;

              $.ajax({
                url : dataSource + _term,
              }).success(function(data){

                _callback($.map(data.profiles.items, function (person) {
                    if (person.profileName.toLowerCase().indexOf(_term.toLowerCase()) === 0){
                      person.symbol = _symbol;

                      return person;
                    }else{
                      return null;
                    }
                }));
              });
            },
            template: function (person) {

                var img_src = static_url + person.avatar;

                if (person.avatar.indexOf('http://')===0){
                  img_src = person.avatar;
                }
                return '<img src="' + img_src + '" /> ' + person.symbol + person.profileName;
            },
            replace: function (person) {
                return person.symbol + person.profileName;
            },
            index: 1,
            maxCount: 5
          }
        ]);
      }

      ////////////////////////
      //     bind events    //
      ////////////////////////
      var events = [
        ['reset', 'form',        'clearAttachmentGallery'],
        ['click', '.reply-box-attachments-gallery li span.remove', 'removeAttachmentFile'],

        ['click', '.wmd-preview-button', 'toggleMarkdownPreview']
      ];

      for(var i in events){
        this.$el.on(events[i][0], events[i][1], $.proxy(this[events[i][2]], this) );
      }
    };

    return simpleEditor;
  })();

})(window,document,jQuery);<|endoftext|>


<commit_before><commit_msg>New span 6 layout<commit_after><|endoftext|>


<commit_before><commit_msg>Fix crash for table.darktime (typo).<commit_after><|endoftext|>


<commit_before>module.exports = function(grunt) {

	grunt.initConfig({
		pkg: grunt.file.readJSON('package.json'),
		concat: {
		options: {
			// define a string to put between each file in the concatenated output
			separator: ''
		 },
		dist: {
			// the files to concatenate
			src: [
					   'src/header.js',
					   'src/transform.js',
					   'src/cell.js',
					   'src/node.js',
					   'src/camera.js',
					   'src/grid.js',
					   'src/line.js',
						 'src/imagehandler.js',
						 'src/sprite.js',
					   'src/util.js',
						 'src/engine.js'
					 ],
			// the location of the resulting JS file
			dest: 'dist/<%= pkg.name %>.js'
		 }
		},
		watch: {
		  files: ['<%= concat.dist.src %>'],
			tasks: ['concat:dist']
		},
		jasmine: {
			test:{
		  	src :[ '../lib/gl-matrix.js', 'dist/*.js'],
		  	options: {
				specs : 'specs/**/*spec.js',
		  		helpers : 'specs/helpers/*.js',
			  	timeout : 10000
				}
	 		}
		}
	});

grunt.loadNpmTasks('grunt-contrib-jasmine');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');

grunt.registerTask('test', ['jasmine']);
grunt.registerTask('default', ['watch']);

};
<commit_msg>adding make task to gruntfile<commit_after>module.exports = function(grunt) {

	grunt.initConfig({
		pkg: grunt.file.readJSON('package.json'),
		concat: {
		options: {
			// define a string to put between each file in the concatenated output
			separator: ''
		 },
		dist: {
			// the files to concatenate
			src: [
					   'src/header.js',
					   'src/transform.js',
					   'src/cell.js',
					   'src/node.js',
					   'src/camera.js',
					   'src/grid.js',
					   'src/line.js',
						 'src/imagehandler.js',
						 'src/sprite.js',
					   'src/util.js',
						 'src/engine.js'
					 ],
			// the location of the resulting JS file
			dest: 'dist/<%= pkg.name %>.js'
		 }
		},
		watch: {
		  files: ['<%= concat.dist.src %>'],
			tasks: ['concat:dist']
		},
		jasmine: {
			test:{
		  	src :[ '../lib/gl-matrix.js', 'dist/*.js'],
		  	options: {
				specs : 'specs/**/*spec.js',
		  		helpers : 'specs/helpers/*.js',
			  	timeout : 10000
				}
	 		}
		}
	});

grunt.loadNpmTasks('grunt-contrib-jasmine');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');

grunt.registerTask('test', ['jasmine']);
grunt.registerTask('default', ['watch']);
grunt.registerTask('make', ['concat:dist']);
};
<|endoftext|>


<commit_before>const Channel = require('./Channel');
const Role = require('./Role');
const PermissionOverwrites = require('./PermissionOverwrites');
const EvaluatedPermissions = require('./EvaluatedPermissions');
const Constants = require('../util/Constants');
const Collection = require('../util/Collection');

/**
 * Represents a guild channel (i.e. text channels and voice channels)
 * @extends {Channel}
 */
class GuildChannel extends Channel {
  constructor(guild, data) {
    super(guild.client, data);

    /**
     * The guild the channel is in
     * @type {Guild}
     */
    this.guild = guild;
  }

  setup(data) {
    super.setup(data);

    /**
     * The name of the guild channel
     * @type {string}
     */
    this.name = data.name;

    /**
     * The position of the channel in the list.
     * @type {number}
     */
    this.position = data.position;

    /**
     * A map of permission overwrites in this channel for roles and users.
     * @type {Collection<Snowflake, PermissionOverwrites>}
     */
    this.permissionOverwrites = new Collection();
    if (data.permission_overwrites) {
      for (const overwrite of data.permission_overwrites) {
        this.permissionOverwrites.set(overwrite.id, new PermissionOverwrites(this, overwrite));
      }
    }
  }

  /**
   * Gets the overall set of permissions for a user in this channel, taking into account roles and permission
   * overwrites.
   * @param {GuildMemberResolvable} member The user that you want to obtain the overall permissions for
   * @returns {?EvaluatedPermissions}
   */
  permissionsFor(member) {
    member = this.client.resolver.resolveGuildMember(this.guild, member);
    if (!member) return null;
    if (member.id === this.guild.ownerID) return new EvaluatedPermissions(member, Constants.ALL_PERMISSIONS);

    let permissions = 0;

    const roles = member.roles;
    for (const role of roles.values()) permissions |= role.permissions;

    const overwrites = this.overwritesFor(member, true, roles);
    for (const overwrite of overwrites.role.concat(overwrites.member)) {
      permissions &= ~overwrite.deny;
      permissions |= overwrite.allow;
    }

    const admin = Boolean(permissions & Constants.PermissionFlags.ADMINISTRATOR);
    if (admin) permissions = Constants.ALL_PERMISSIONS;

    return new EvaluatedPermissions(member, permissions);
  }

  overwritesFor(member, verified = false, roles = null) {
    if (!verified) member = this.client.resolver.resolveGuildMember(this.guild, member);
    if (!member) return [];

    roles = roles || member.roles;
    const roleOverwrites = [];
    const memberOverwrites = [];

    for (const overwrite of this.permissionOverwrites.values()) {
      if (overwrite.id === member.id) {
        memberOverwrites.push(overwrite);
      } else if (roles.has(overwrite.id)) {
        roleOverwrites.push(overwrite);
      }
    }

    return {
      role: roleOverwrites,
      member: memberOverwrites,
    };
  }

  /**
   * An object mapping permission flags to `true` (enabled) or `false` (disabled)
   * ```js
   * {
   *  'SEND_MESSAGES': true,
   *  'ATTACH_FILES': false,
   * }
   * ```
   * @typedef {Object} PermissionOverwriteOptions
   */

  /**
   * Overwrites the permissions for a user or role in this channel.
   * @param {RoleResolvable|UserResolvable} userOrRole The user or role to update
   * @param {PermissionOverwriteOptions} options The configuration for the update
   * @returns {Promise}
   * @example
   * // overwrite permissions for a message author
   * message.channel.overwritePermissions(message.author, {
   *  SEND_MESSAGES: false
   * })
   * .then(() => console.log('Done!'))
   * .catch(console.error);
   */
  overwritePermissions(userOrRole, options) {
    const payload = {
      allow: 0,
      deny: 0,
    };

    if (userOrRole instanceof Role) {
      payload.type = 'role';
    } else if (this.guild.roles.has(userOrRole)) {
      userOrRole = this.guild.roles.get(userOrRole);
      payload.type = 'role';
    } else {
      userOrRole = this.client.resolver.resolveUser(userOrRole);
      payload.type = 'member';
      if (!userOrRole) return Promise.reject(new TypeError('Supplied parameter was neither a User nor a Role.'));
    }

    payload.id = userOrRole.id;

    const prevOverwrite = this.permissionOverwrites.get(userOrRole.id);

    if (prevOverwrite) {
      payload.allow = prevOverwrite.allow;
      payload.deny = prevOverwrite.deny;
    }

    for (const perm in options) {
      if (options[perm] === true) {
        payload.allow |= Constants.PermissionFlags[perm] || 0;
        payload.deny &= ~(Constants.PermissionFlags[perm] || 0);
      } else if (options[perm] === false) {
        payload.allow &= ~(Constants.PermissionFlags[perm] || 0);
        payload.deny |= Constants.PermissionFlags[perm] || 0;
      } else if (options[perm] === null) {
        payload.allow &= ~(Constants.PermissionFlags[perm] || 0);
        payload.deny &= ~(Constants.PermissionFlags[perm] || 0);
      }
    }

    return this.client.rest.methods.setChannelOverwrite(this, payload);
  }

  /**
   * The data for a guild channel
   * @typedef {Object} ChannelData
   * @property {string} [name] The name of the channel
   * @property {number} [position] The position of the channel
   * @property {string} [topic] The topic of the text channel
   * @property {number} [bitrate] The bitrate of the voice channel
   * @property {number} [userLimit] The user limit of the channel
   */

  /**
   * Edits the channel
   * @param {ChannelData} data The new data for the channel
   * @returns {Promise<GuildChannel>}
   * @example
   * // edit a channel
   * channel.edit({name: 'new-channel'})
   *  .then(c => console.log(`Edited channel ${c}`))
   *  .catch(console.error);
   */
  edit(data) {
    return this.client.rest.methods.updateChannel(this, data);
  }

  /**
   * Set a new name for the guild channel
   * @param {string} name The new name for the guild channel
   * @returns {Promise<GuildChannel>}
   * @example
   * // set a new channel name
   * channel.setName('not_general')
   *  .then(newChannel => console.log(`Channel's new name is ${newChannel.name}`))
   *  .catch(console.error);
   */
  setName(name) {
    return this.edit({ name });
  }

  /**
   * Set a new position for the guild channel
   * @param {number} position The new position for the guild channel
   * @returns {Promise<GuildChannel>}
   * @example
   * // set a new channel position
   * channel.setPosition(2)
   *  .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`))
   *  .catch(console.error);
   */
  setPosition(position) {
    return this.client.rest.methods.updateChannel(this, { position });
  }

  /**
   * Set a new topic for the guild channel
   * @param {string} topic The new topic for the guild channel
   * @returns {Promise<GuildChannel>}
   * @example
   * // set a new channel topic
   * channel.setTopic('needs more rate limiting')
   *  .then(newChannel => console.log(`Channel's new topic is ${newChannel.topic}`))
   *  .catch(console.error);
   */
  setTopic(topic) {
    return this.client.rest.methods.updateChannel(this, { topic });
  }

  /**
   * Options given when creating a guild channel invite
   * @typedef {Object} InviteOptions
   * @property {boolean} [temporary=false] Whether the invite should kick users after 24hrs if they are not given a role
   * @property {number} [maxAge=0] Time in seconds the invite expires in
   * @property {number} [maxUses=0] Maximum amount of uses for this invite
   */

  /**
   * Create an invite to this guild channel
   * @param {InviteOptions} [options={}] The options for the invite
   * @returns {Promise<Invite>}
   */
  createInvite(options = {}) {
    return this.client.rest.methods.createChannelInvite(this, options);
  }

  /**
   * Clone this channel
   * @param {string} [name=this.name] Optional name for the new channel, otherwise it has the name of this channel
   * @param {boolean} [withPermissions=true] Whether to clone the channel with this channel's permission overwrites
   * @returns {Promise<GuildChannel>}
   */
  clone(name = this.name, withPermissions = true) {
    return this.guild.createChannel(name, this.type, withPermissions ? this.permissionOverwrites : []);
  }

  /**
   * Checks if this channel has the same type, topic, position, name, overwrites and ID as another channel.
   * In most cases, a simple `channel.id === channel2.id` will do, and is much faster too.
   * @param {GuildChannel} channel Channel to compare with
   * @returns {boolean}
   */
  equals(channel) {
    let equal = channel &&
      this.id === channel.id &&
      this.type === channel.type &&
      this.topic === channel.topic &&
      this.position === channel.position &&
      this.name === channel.name;

    if (equal) {
      if (this.permissionOverwrites && channel.permissionOverwrites) {
        equal = this.permissionOverwrites.equals(channel.permissionOverwrites);
      } else {
        equal = !this.permissionOverwrites && !channel.permissionOverwrites;
      }
    }

    return equal;
  }

  /**
   * When concatenated with a string, this automatically returns the channel's mention instead of the Channel object.
   * @returns {string}
   * @example
   * // Outputs: Hello from #general
   * console.log(`Hello from ${channel}`);
   * @example
   * // Outputs: Hello from #general
   * console.log('Hello from ' + channel);
   */
  toString() {
    return `<#${this.id}>`;
  }
}

module.exports = GuildChannel;
<commit_msg>check if a guildchannel is deletable (#1143)<commit_after>const Channel = require('./Channel');
const Role = require('./Role');
const PermissionOverwrites = require('./PermissionOverwrites');
const EvaluatedPermissions = require('./EvaluatedPermissions');
const Constants = require('../util/Constants');
const Collection = require('../util/Collection');

/**
 * Represents a guild channel (i.e. text channels and voice channels)
 * @extends {Channel}
 */
class GuildChannel extends Channel {
  constructor(guild, data) {
    super(guild.client, data);

    /**
     * The guild the channel is in
     * @type {Guild}
     */
    this.guild = guild;
  }

  setup(data) {
    super.setup(data);

    /**
     * The name of the guild channel
     * @type {string}
     */
    this.name = data.name;

    /**
     * The position of the channel in the list.
     * @type {number}
     */
    this.position = data.position;

    /**
     * A map of permission overwrites in this channel for roles and users.
     * @type {Collection<Snowflake, PermissionOverwrites>}
     */
    this.permissionOverwrites = new Collection();
    if (data.permission_overwrites) {
      for (const overwrite of data.permission_overwrites) {
        this.permissionOverwrites.set(overwrite.id, new PermissionOverwrites(this, overwrite));
      }
    }
  }

  /**
   * Gets the overall set of permissions for a user in this channel, taking into account roles and permission
   * overwrites.
   * @param {GuildMemberResolvable} member The user that you want to obtain the overall permissions for
   * @returns {?EvaluatedPermissions}
   */
  permissionsFor(member) {
    member = this.client.resolver.resolveGuildMember(this.guild, member);
    if (!member) return null;
    if (member.id === this.guild.ownerID) return new EvaluatedPermissions(member, Constants.ALL_PERMISSIONS);

    let permissions = 0;

    const roles = member.roles;
    for (const role of roles.values()) permissions |= role.permissions;

    const overwrites = this.overwritesFor(member, true, roles);
    for (const overwrite of overwrites.role.concat(overwrites.member)) {
      permissions &= ~overwrite.deny;
      permissions |= overwrite.allow;
    }

    const admin = Boolean(permissions & Constants.PermissionFlags.ADMINISTRATOR);
    if (admin) permissions = Constants.ALL_PERMISSIONS;

    return new EvaluatedPermissions(member, permissions);
  }

  overwritesFor(member, verified = false, roles = null) {
    if (!verified) member = this.client.resolver.resolveGuildMember(this.guild, member);
    if (!member) return [];

    roles = roles || member.roles;
    const roleOverwrites = [];
    const memberOverwrites = [];

    for (const overwrite of this.permissionOverwrites.values()) {
      if (overwrite.id === member.id) {
        memberOverwrites.push(overwrite);
      } else if (roles.has(overwrite.id)) {
        roleOverwrites.push(overwrite);
      }
    }

    return {
      role: roleOverwrites,
      member: memberOverwrites,
    };
  }

  /**
   * An object mapping permission flags to `true` (enabled) or `false` (disabled)
   * ```js
   * {
   *  'SEND_MESSAGES': true,
   *  'ATTACH_FILES': false,
   * }
   * ```
   * @typedef {Object} PermissionOverwriteOptions
   */

  /**
   * Overwrites the permissions for a user or role in this channel.
   * @param {RoleResolvable|UserResolvable} userOrRole The user or role to update
   * @param {PermissionOverwriteOptions} options The configuration for the update
   * @returns {Promise}
   * @example
   * // overwrite permissions for a message author
   * message.channel.overwritePermissions(message.author, {
   *  SEND_MESSAGES: false
   * })
   * .then(() => console.log('Done!'))
   * .catch(console.error);
   */
  overwritePermissions(userOrRole, options) {
    const payload = {
      allow: 0,
      deny: 0,
    };

    if (userOrRole instanceof Role) {
      payload.type = 'role';
    } else if (this.guild.roles.has(userOrRole)) {
      userOrRole = this.guild.roles.get(userOrRole);
      payload.type = 'role';
    } else {
      userOrRole = this.client.resolver.resolveUser(userOrRole);
      payload.type = 'member';
      if (!userOrRole) return Promise.reject(new TypeError('Supplied parameter was neither a User nor a Role.'));
    }

    payload.id = userOrRole.id;

    const prevOverwrite = this.permissionOverwrites.get(userOrRole.id);

    if (prevOverwrite) {
      payload.allow = prevOverwrite.allow;
      payload.deny = prevOverwrite.deny;
    }

    for (const perm in options) {
      if (options[perm] === true) {
        payload.allow |= Constants.PermissionFlags[perm] || 0;
        payload.deny &= ~(Constants.PermissionFlags[perm] || 0);
      } else if (options[perm] === false) {
        payload.allow &= ~(Constants.PermissionFlags[perm] || 0);
        payload.deny |= Constants.PermissionFlags[perm] || 0;
      } else if (options[perm] === null) {
        payload.allow &= ~(Constants.PermissionFlags[perm] || 0);
        payload.deny &= ~(Constants.PermissionFlags[perm] || 0);
      }
    }

    return this.client.rest.methods.setChannelOverwrite(this, payload);
  }

  /**
   * The data for a guild channel
   * @typedef {Object} ChannelData
   * @property {string} [name] The name of the channel
   * @property {number} [position] The position of the channel
   * @property {string} [topic] The topic of the text channel
   * @property {number} [bitrate] The bitrate of the voice channel
   * @property {number} [userLimit] The user limit of the channel
   */

  /**
   * Edits the channel
   * @param {ChannelData} data The new data for the channel
   * @returns {Promise<GuildChannel>}
   * @example
   * // edit a channel
   * channel.edit({name: 'new-channel'})
   *  .then(c => console.log(`Edited channel ${c}`))
   *  .catch(console.error);
   */
  edit(data) {
    return this.client.rest.methods.updateChannel(this, data);
  }

  /**
   * Set a new name for the guild channel
   * @param {string} name The new name for the guild channel
   * @returns {Promise<GuildChannel>}
   * @example
   * // set a new channel name
   * channel.setName('not_general')
   *  .then(newChannel => console.log(`Channel's new name is ${newChannel.name}`))
   *  .catch(console.error);
   */
  setName(name) {
    return this.edit({ name });
  }

  /**
   * Set a new position for the guild channel
   * @param {number} position The new position for the guild channel
   * @returns {Promise<GuildChannel>}
   * @example
   * // set a new channel position
   * channel.setPosition(2)
   *  .then(newChannel => console.log(`Channel's new position is ${newChannel.position}`))
   *  .catch(console.error);
   */
  setPosition(position) {
    return this.client.rest.methods.updateChannel(this, { position });
  }

  /**
   * Set a new topic for the guild channel
   * @param {string} topic The new topic for the guild channel
   * @returns {Promise<GuildChannel>}
   * @example
   * // set a new channel topic
   * channel.setTopic('needs more rate limiting')
   *  .then(newChannel => console.log(`Channel's new topic is ${newChannel.topic}`))
   *  .catch(console.error);
   */
  setTopic(topic) {
    return this.client.rest.methods.updateChannel(this, { topic });
  }

  /**
   * Options given when creating a guild channel invite
   * @typedef {Object} InviteOptions
   * @property {boolean} [temporary=false] Whether the invite should kick users after 24hrs if they are not given a role
   * @property {number} [maxAge=0] Time in seconds the invite expires in
   * @property {number} [maxUses=0] Maximum amount of uses for this invite
   */

  /**
   * Create an invite to this guild channel
   * @param {InviteOptions} [options={}] The options for the invite
   * @returns {Promise<Invite>}
   */
  createInvite(options = {}) {
    return this.client.rest.methods.createChannelInvite(this, options);
  }

  /**
   * Clone this channel
   * @param {string} [name=this.name] Optional name for the new channel, otherwise it has the name of this channel
   * @param {boolean} [withPermissions=true] Whether to clone the channel with this channel's permission overwrites
   * @returns {Promise<GuildChannel>}
   */
  clone(name = this.name, withPermissions = true) {
    return this.guild.createChannel(name, this.type, withPermissions ? this.permissionOverwrites : []);
  }

  /**
   * Checks if this channel has the same type, topic, position, name, overwrites and ID as another channel.
   * In most cases, a simple `channel.id === channel2.id` will do, and is much faster too.
   * @param {GuildChannel} channel Channel to compare with
   * @returns {boolean}
   */
  equals(channel) {
    let equal = channel &&
      this.id === channel.id &&
      this.type === channel.type &&
      this.topic === channel.topic &&
      this.position === channel.position &&
      this.name === channel.name;

    if (equal) {
      if (this.permissionOverwrites && channel.permissionOverwrites) {
        equal = this.permissionOverwrites.equals(channel.permissionOverwrites);
      } else {
        equal = !this.permissionOverwrites && !channel.permissionOverwrites;
      }
    }

    return equal;
  }

  /**
   * Whether the channel is deletable by the client user.
   * @type {boolean}
   * @readonly
   */
  get deletable() {
    return this.id !== this.guild.id &&
      this.permissionsFor(this.client.user).hasPermission(Constants.PermissionFlags.MANAGE_CHANNELS);
  }

  /**
   * When concatenated with a string, this automatically returns the channel's mention instead of the Channel object.
   * @returns {string}
   * @example
   * // Outputs: Hello from #general
   * console.log(`Hello from ${channel}`);
   * @example
   * // Outputs: Hello from #general
   * console.log('Hello from ' + channel);
   */
  toString() {
    return `<#${this.id}>`;
  }
}

module.exports = GuildChannel;
<|endoftext|>


<commit_before><commit_msg>Add bugsnag notifying<commit_after><|endoftext|>


<commit_before><commit_msg>getting data for current week from firebase<commit_after><|endoftext|>


<commit_before><commit_msg>fix config ref<commit_after><|endoftext|>


<commit_before>/*
 * jQuery hashchange event - v1.3 - 7/21/2010
 * http://benalman.com/projects/jquery-hashchange-plugin/
 *
 * Copyright (c) 2010 "Cowboy" Ben Alman
 * Dual licensed under the MIT and GPL licenses.
 * http://benalman.com/about/license/
 */
(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){r||l(a());n()}).attr("src",r||"javascript:0").insertAfter("body")[0].contentWindow;h.onpropertychange=function(){try{if(event.propertyName==="title"){q.document.title=h.title}}catch(s){}}}};j.stop=k;o=function(){return a(q.location.href)};l=function(v,s){var u=q.document,t=$.fn[c].domain;if(v!==s){u.title=h.title;u.open();t&&u.write('<script>document.domain="'+t+'"<\/script>');u.close();q.location.hash=v}}})();return j})()})(jQuery,this);

/* jquery.pjax.js with hash-navigation fallback
 * copyright andrew magalich
 * https://github.com/ckald/jquery-pjax
*/

// jquery.pjax.js
// copyright chris wanstrath
// https://github.com/defunkt/jquery-pjax

(function($){
   if (!$.hash) $.hash = '#!/';
   if (!$.siteurl) $.siteurl = 'http://yoursite.com'; // your site url
   if (!$.container) $.container = '#pjaxcontainer'; // container SELECTOR to use for hash navigation

/* When called on a link, fetches the href with ajax into the
   container specified as the first parameter or with the data-pjax
   attribute on the link itself.

   Tries to make sure the back button and ctrl+click work the way
   you'd expect.

   Accepts a jQuery ajax options object that may include these
   pjax specific options:

   container - Where to stick the response body. Usually a String selector.
               $(container).html(xhr.responseBody)
        push - Whether to pushState the URL. Defaults to true (of course).
     replace - Want to use replaceState instead? That's cool.

   For convenience the first parameter can be either the container or
   the options object.

   Returns the jQuery object*/
$.fn.pjax = function( container, options ) {
  if ( options )
    options.container = container;
  else
    options = $.isPlainObject(container) ? container : {container:container};

  // We can't persist $objects using the history API so we must use
  // a String selector. Bail if we got anything else.
  if ( typeof options.container !== 'string' ) {
    throw "pjax container must be a string selector!";
    return false;
  }

  return this.live('click', function(event){
    // Middle click, cmd click, and ctrl click should open
    // links in a new tab as normal.
    if ( event.which > 1 || event.metaKey )
      return true;

    var defaults = {
      url: this.href,
      container: $(this).attr('data-pjax'),
      clickedElement: $(this),
      isform: false
    }

    $.pjax($.extend({}, defaults, options));

    event.preventDefault();
  })
}

// Same as pjax but for forms, also will shows query in address

$.fn.pjaxform = function( container, options ) {
  if ( options )
    options.container = container;
  else
    options = $.isPlainObject(container) ? container : {container:container};

  // We can't persist $objects using the history API so we must use
  // a String selector. Bail if we got anything else.
  if ( typeof options.container !== 'string' ) {
    throw "pjax container must be a string selector!";
    return false;
  }

  return this.live('submit', function(event){
    data = $(this).serialize();
    options.type = $(this).attr('method');
    var defaults = {
      url: (options.type && options.type.toUpperCase()=='GET')?this.action+'?'+data:this.action,
      push: (options.type && options.type.toUpperCase()=='GET')?true:false,
      data: data,
      isform: true,
      container: $(this).attr('data-pjax'),
      clickedElement: $(this)
    }

    $.pjax($.extend({}, defaults, options));

    event.preventDefault();
  })
}

// Loads a URL with ajax, puts the response body inside a container,
// then pushState()'s the loaded URL.
//
// Works just like $.ajax in that it accepts a jQuery ajax
// settings object (with keys like url, type, data, etc).
//
// Accepts these extra keys:
//
// container - Where to stick the response body. Must be a String.
//             $(container).html(xhr.responseBody)
//      push - Whether to pushState the URL. Defaults to true (of course).
//   replace - Want to use replaceState instead? That's cool.
//
// Use it just like $.ajax:
//
//   var xhr = $.pjax({ url: this.href, container: '#main' })
//   console.log( xhr.readyState )
//
// Returns whatever $.ajax returns.
$.pjax = function( options ) {
  var $container = $(options.container),
      success = options.success || $.noop;

  // We don't want to let anyone override our success handler.
  delete options.success;

  // We can't persist $objects using the history API so we must use
  // a String selector. Bail if we got anything else.
  if ( typeof options.container !== 'string' )
    throw "pjax container must be a string selector!";

  var defaults = {
    timeout: 650,
    push: true,
    replace: false,
    // We want the browser to maintain two separate internal caches: one for
    // pjax'd partial page loads and one for normal page loads. Without
    // adding this secret parameter, some browsers will often confuse the two.
    data: { _pjax: true },
    type: 'POST',
    dataType: 'html',
    siteurl : $.siteurl,
    beforeSend: function(xhr){
      $container.trigger('start.pjax')
      xhr.setRequestHeader('X-PJAX', 'true')
    },
    error: function(data){
      this.success(data.responseText);
      $container.trigger('error.pjax');
    },
    complete: function(jqXHR){
      $container.trigger('complete.pjax', jqXHR);
    },
    success: function(data){
      // If we got no data or an entire web page, go directly
      // to the page and let normal error handling happen.

      if ( !$.trim(data) || /<html/i.test(data) )
      {
         return window.location = options.url;
      }

      // Make it happen.
      $container.html(data);

      // If there's a <title> tag in the response, use it as
      // the page's title.
      var oldTitle = document.title,
          title = $.trim( $container.find('title').remove().text() );
      if ( title ) document.title = title;

         var state = {
           pjax: options.container,
           timeout: options.timeout
         };

      if( $.support.pjax )
      {
         // If there are extra params, save the complete URL in the state object
         var query = $.param(options.data);
         if ( query != "_pjax=true" )
           state.url = options.url + (/\?/.test(options.url) ? "&" : "?") + query;

         if ( options.replace ) {
           window.history.replaceState(state, document.title, options.url);
         } else if ( options.push ) {
           // this extra replaceState before first push ensures good back
           // button behavior
           if ( !$.pjax.active ) {
             window.history.replaceState($.extend({}, state, {url:null}), oldTitle);
             $.pjax.active = true;
           }

           window.history.pushState(state, document.title, options.url);
         }

         // Google Analytics support
         if ( (options.replace || options.push) && window._gaq )
           _gaq.push(['_trackPageview']);

         // If the URL has a hash in it, make sure the browser
         // knows to navigate to the hash.
         var hash = window.location.hash.toString();
         if ( hash !== '' ) {
            window.location.hash = '';
            window.location.hash = hash;
         }

      }
      else {
        // change address if it is not form or GET form
         if (!options.isform || options.type.toUpperCase()=='GET') {
            window.location.hash = "!"+options.url.replace(options.siteurl,"");
            $.hash = window.location.hash;
         }
      }

      // Invoke their success handler if they gave us one.
      success.apply(this, arguments);
      $container.trigger('success.pjax');
    }
  }

  options = $.extend(true, {}, defaults, options);

  if ( $.isFunction(options.url) ) {
    options.url = options.url();
  }

  // Cancel the current request if we're already pjaxing
  var xhr = $.pjax.xhr;
  if ( xhr && xhr.readyState < 4) {
    xhr.onreadystatechange = $.noop;
    xhr.abort();
  }

  $.pjax.xhr = $.ajax(options);
  $(document).trigger('pjax', $.pjax.xhr, options);

  return $.pjax.xhr;
}

// Is pjax supported by this browser?
$.support.pjax = window.history && window.history.pushState;

// While page is loading, we should handle different URL types
var hash = window.location.hash.toString();

if( hash.length > 0 )
{
   if( $.support.pjax )
      location = $.siteurl+hash.substr(2);

}
else if( location.pathname.length > 1 || location.search.length > 1 )
{
    if( !$.support.pjax )
      window.location = $.siteurl+'/#!'+window.location.pathname+window.location.search;

}

// If there is no pjax support, we should handle hash changes
if( !$.support.pjax )
{
   $(window).hashchange(function(){
      hash = window.location.hash;

      if ( (hash.substr(0,2) == '#!' || hash=='') && hash != $.hash) {
         $.ajax({
               type: "POST",
               url: $.siteurl+hash.replace('#!',''),
               beforeSend : function(xhr) {
                  $($.container).trigger('start.pjax');
                  return xhr.setRequestHeader('X-PJAX','true');
               },
               success: function(msg){
                  $($.container).html(msg);
                  $($.container).trigger('success.pjax');
               },
               complete: function(jqXHR){
                  $($.container).trigger('complete.pjax', jqXHR);
               },
               error: function(a,b,c) {
                  $($.container).trigger('error.pjax');
               }
            });

      }
   });
   $(window).hashchange();
}

// Used to detect initial (useless) popstate.
// If history.state exists, assume browser isn't going to fire initial popstate.
var popped = ('state' in window.history), initialURL = location.href;

// popstate handler takes care of the back and forward buttons
//
// You probably shouldn't use pjax on pages with other pushState
// stuff yet.
$(window).bind('popstate', function(event){
  // Ignore inital popstate that some browsers fire on page load
  var initialPop = !popped && location.href == initialURL;
  popped = true;
  if ( initialPop ) return;

  var state = event.state;

  if ( state && state.pjax ) {
    var container = state.pjax;
    if ( $(container+'').length )
      $.pjax({
        url: state.url || location.href,
        container: container,
        push: false,
        timeout: state.timeout
      });
    else
      window.location = location.href;
  }
})

// Add the state property to jQuery's event object so we can use it in
// $(window).bind('popstate')
if ( $.inArray('state', $.event.props) < 0 )
  $.event.props.push('state');

})(jQuery);<commit_msg>add all parameters to callbacks<commit_after>/*
 * jQuery hashchange event - v1.3 - 7/21/2010
 * http://benalman.com/projects/jquery-hashchange-plugin/
 *
 * Copyright (c) 2010 "Cowboy" Ben Alman
 * Dual licensed under the MIT and GPL licenses.
 * http://benalman.com/about/license/
 */
(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){r||l(a());n()}).attr("src",r||"javascript:0").insertAfter("body")[0].contentWindow;h.onpropertychange=function(){try{if(event.propertyName==="title"){q.document.title=h.title}}catch(s){}}}};j.stop=k;o=function(){return a(q.location.href)};l=function(v,s){var u=q.document,t=$.fn[c].domain;if(v!==s){u.title=h.title;u.open();t&&u.write('<script>document.domain="'+t+'"<\/script>');u.close();q.location.hash=v}}})();return j})()})(jQuery,this);

/* jquery.pjax.js with hash-navigation fallback
 * copyright andrew magalich
 * https://github.com/ckald/jquery-pjax
*/

// jquery.pjax.js
// copyright chris wanstrath
// https://github.com/defunkt/jquery-pjax

(function($){
   if (!$.hash) $.hash = '#!/';
   if (!$.siteurl) $.siteurl = 'http://yoursite.com'; // your site url
   if (!$.container) $.container = '#pjaxcontainer'; // container SELECTOR to use for hash navigation

/* When called on a link, fetches the href with ajax into the
   container specified as the first parameter or with the data-pjax
   attribute on the link itself.

   Tries to make sure the back button and ctrl+click work the way
   you'd expect.

   Accepts a jQuery ajax options object that may include these
   pjax specific options:

   container - Where to stick the response body. Usually a String selector.
               $(container).html(xhr.responseBody)
        push - Whether to pushState the URL. Defaults to true (of course).
     replace - Want to use replaceState instead? That's cool.

   For convenience the first parameter can be either the container or
   the options object.

   Returns the jQuery object*/
$.fn.pjax = function( container, options ) {
  if ( options )
    options.container = container;
  else
    options = $.isPlainObject(container) ? container : {container:container};

  // We can't persist $objects using the history API so we must use
  // a String selector. Bail if we got anything else.
  if ( typeof options.container !== 'string' ) {
    throw "pjax container must be a string selector!";
    return false;
  }

  return this.live('click', function(event){
    // Middle click, cmd click, and ctrl click should open
    // links in a new tab as normal.
    if ( event.which > 1 || event.metaKey )
      return true;

    var defaults = {
      url: this.href,
      container: $(this).attr('data-pjax'),
      clickedElement: $(this),
      isform: false
    }

    $.pjax($.extend({}, defaults, options));

    event.preventDefault();
  })
}

// Same as pjax but for forms, also will shows query in address

$.fn.pjaxform = function( container, options ) {
  if ( options )
    options.container = container;
  else
    options = $.isPlainObject(container) ? container : {container:container};

  // We can't persist $objects using the history API so we must use
  // a String selector. Bail if we got anything else.
  if ( typeof options.container !== 'string' ) {
    throw "pjax container must be a string selector!";
    return false;
  }

  return this.live('submit', function(event){
    $(options.container).trigger('form-submit.pjax', $(this));
    data = $(this).serialize();
    options.type = $(this).attr('method');

    var defaults = {
      url: (options.type && options.type.toUpperCase()=='GET')?this.action+'?'+data:this.action,
      push: (options.type && options.type.toUpperCase()=='GET')?true:false,
      data: data,
      isform: true,
      container: $(this).attr('data-pjax'),
      clickedElement: $(this)
    }

    $.pjax($.extend({}, defaults, options));

    event.preventDefault();
  })
}

// Loads a URL with ajax, puts the response body inside a container,
// then pushState()'s the loaded URL.
//
// Works just like $.ajax in that it accepts a jQuery ajax
// settings object (with keys like url, type, data, etc).
//
// Accepts these extra keys:
//
// container - Where to stick the response body. Must be a String.
//             $(container).html(xhr.responseBody)
//      push - Whether to pushState the URL. Defaults to true (of course).
//   replace - Want to use replaceState instead? That's cool.
//
// Use it just like $.ajax:
//
//   var xhr = $.pjax({ url: this.href, container: '#main' })
//   console.log( xhr.readyState )
//
// Returns whatever $.ajax returns.
$.pjax = function( options ) {
  var $container = $(options.container),
      success = options.success || $.noop;

  // We don't want to let anyone override our success handler.
  delete options.success;

  // We can't persist $objects using the history API so we must use
  // a String selector. Bail if we got anything else.
  if ( typeof options.container !== 'string' )
    throw "pjax container must be a string selector!";

  var defaults = {
    timeout: 650,
    push: true,
    replace: false,
    // We want the browser to maintain two separate internal caches: one for
    // pjax'd partial page loads and one for normal page loads. Without
    // adding this secret parameter, some browsers will often confuse the two.
    data: { _pjax: true },
    type: 'POST',
    dataType: 'html',
    siteurl : $.siteurl,
    beforeSend: function(jqXHR, settings){
      jqXHR.setRequestHeader('X-PJAX', 'true');
      $container.trigger('start.pjax', [jqXHR, settings]);
    },
    error: function(jqXHR, textStatus, errorThrown){
      this.success(jqXHR.responseText);
      $container.trigger('error.pjax', [jqXHR, textStatus, errorThrown]);
    },
    complete: function(jqXHR, textStatus){
      $container.trigger('complete.pjax', [jqXHR, textStatus]);
    },
    success: function(data, textStatus, jqXHR){
      // If we got no data or an entire web page, go directly
      // to the page and let normal error handling happen.

      if ( !$.trim(data) || /<html/i.test(data) )
      {
         return window.location = options.url;
      }

      // Make it happen.
      $container.html(data);

      // If there's a <title> tag in the response, use it as
      // the page's title.
      var oldTitle = document.title,
          title = $.trim( $container.find('title').remove().text() );
      if ( title ) document.title = title;

         var state = {
           pjax: options.container,
           timeout: options.timeout
         };

      if( $.support.pjax )
      {
         // If there are extra params, save the complete URL in the state object
         var query = $.param(options.data);
         if ( query != "_pjax=true" )
           state.url = options.url + (/\?/.test(options.url) ? "&" : "?") + query;

         if ( options.replace ) {
           window.history.replaceState(state, document.title, options.url);
         } else if ( options.push ) {
           // this extra replaceState before first push ensures good back
           // button behavior
           if ( !$.pjax.active ) {
             window.history.replaceState($.extend({}, state, {url:null}), oldTitle);
             $.pjax.active = true;
           }

           window.history.pushState(state, document.title, options.url);
         }

         // Google Analytics support
         if ( (options.replace || options.push) && window._gaq )
           _gaq.push(['_trackPageview']);

         // If the URL has a hash in it, make sure the browser
         // knows to navigate to the hash.
         var hash = window.location.hash.toString();
         if ( hash !== '' ) {
            window.location.hash = '';
            window.location.hash = hash;
         }

      }
      else {
        // change address if it is not form or GET form
         if (!options.isform || options.type.toUpperCase()=='GET') {
            window.location.hash = "!"+options.url.replace(options.siteurl,"");
            $.hash = window.location.hash;
         }
      }

      // Invoke their success handler if they gave us one.
      success.apply(this, arguments);
      $container.trigger('success.pjax', [data, textStatus, jqXHR]);
    }
  }

  options = $.extend(true, {}, defaults, options);

  if ( $.isFunction(options.url) ) {
    options.url = options.url();
  }

  // Cancel the current request if we're already pjaxing
  var xhr = $.pjax.xhr;
  if ( xhr && xhr.readyState < 4) {
    xhr.onreadystatechange = $.noop;
    xhr.abort();
  }

  $.pjax.xhr = $.ajax(options);
  $(document).trigger('pjax', [$.pjax.xhr, options]);

  return $.pjax.xhr;
}

// Is pjax supported by this browser?
$.support.pjax = window.history && window.history.pushState;

// While page is loading, we should handle different URL types
var hash = window.location.hash.toString();

if( hash.length > 0 )
{
   if( $.support.pjax )
      location = $.siteurl+hash.substr(2);

}
else if( location.pathname.length > 1 || location.search.length > 1 )
{
    if( !$.support.pjax )
      window.location = $.siteurl+'/#!'+window.location.pathname+window.location.search;

}

// If there is no pjax support, we should handle hash changes
if( !$.support.pjax )
{
   $(window).hashchange(function(){
      hash = window.location.hash;

      if ( (hash.substr(0,2) == '#!' || hash=='') && hash != $.hash) {
         $.ajax({
               type: "POST",
               url: $.siteurl+hash.replace('#!',''),
               beforeSend : function(jqXHR, settings) {
                  jqXHR.setRequestHeader('X-PJAX','true');
                  $($.container).trigger('start.pjax', [jqXHR, settings]);
               },
               success: function(data, textStatus, jqXHR){
                  $($.container).html(data);
                  $($.container).trigger('success.pjax', [data, textStatus, jqXHR]);
               },
               complete: function(jqXHR, textStatus){
                  $($.container).trigger('complete.pjax', [jqXHR, textStatus]);
               },
               error: function(jqXHR, textStatus, errorThrown) {
                  $($.container).trigger('error.pjax', [jqXHR, textStatus, errorThrown]);
               }
            });

      }
   });
   $(window).hashchange();
}

// Used to detect initial (useless) popstate.
// If history.state exists, assume browser isn't going to fire initial popstate.
var popped = ('state' in window.history), initialURL = location.href;

// popstate handler takes care of the back and forward buttons
//
// You probably shouldn't use pjax on pages with other pushState
// stuff yet.
$(window).bind('popstate', function(event){
  // Ignore inital popstate that some browsers fire on page load
  var initialPop = !popped && location.href == initialURL;
  popped = true;
  if ( initialPop ) return;

  var state = event.state;

  if ( state && state.pjax ) {
    var container = state.pjax;
    if ( $(container+'').length )
      $.pjax({
        url: state.url || location.href,
        container: container,
        push: false,
        timeout: state.timeout
      });
    else
      window.location = location.href;
  }
})

// Add the state property to jQuery's event object so we can use it in
// $(window).bind('popstate')
if ( $.inArray('state', $.event.props) < 0 )
  $.event.props.push('state');

})(jQuery);
<|endoftext|>


<commit_before>/**
 * @jest-environment node
 */
import React from 'react'
import { renderToString, renderToNodeStream } from 'react-dom/server'
import ServerStyleSheet from '../models/ServerStyleSheet'
import { resetStyled, resetCreateGlobalStyle } from './utils'
import _keyframes from '../constructors/keyframes'
import stringifyRules from '../utils/stringifyRules'
import css from '../constructors/css'

jest.mock('../utils/nonce')

let index = 0
const keyframes = _keyframes(() => `keyframe_${index++}`, stringifyRules, css)

let styled
let createGlobalStyle

describe('ssr', () => {
  beforeEach(() => {
    // eslint-disable-next-line
    require('../utils/nonce').mockReset()

    styled = resetStyled(true)
    createGlobalStyle = resetCreateGlobalStyle()
  })

  afterEach(() => {
    process.env.NODE_ENV = 'test'
  })

  it('should extract the CSS in a simple case', () => {
    const Heading = styled.h1`
      color: red;
    `

    const sheet = new ServerStyleSheet()
    const html = renderToString(
      sheet.collectStyles(<Heading>Hello SSR!</Heading>)
    )
    const css = sheet.getStyleTags()

    expect(html).toMatchSnapshot()
    expect(css).toMatchSnapshot()
  })

  it('should extract both global and local CSS', () => {
    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const Heading = styled.h1`
      color: red;
    `

    const sheet = new ServerStyleSheet()
    const html = renderToString(
      sheet.collectStyles(
        <React.Fragment>
          <Component />
          <Heading>Hello SSR!</Heading>
        </React.Fragment>
      )
    )
    const css = sheet.getStyleTags()

    expect(html).toMatchSnapshot()
    expect(css).toMatchSnapshot()
  })

  it('should not spill ServerStyleSheets into each other', () => {
    const A = styled.h1`
      color: red;
    `
    const B = styled.h1`
      color: green;
    `

    const sheetA = new ServerStyleSheet()
    renderToString(sheetA.collectStyles())
    const cssA = sheetA.getStyleTags()

    const sheetB = new ServerStyleSheet()
    renderToString(sheetB.collectStyles())
    const cssB = sheetB.getStyleTags()

    expect(cssA).toContain('red')
    expect(cssA).not.toContain('green')
    expect(cssB).not.toContain('red')
    expect(cssB).toContain('green')
  })

  it('should add a nonce to the stylesheet if webpack nonce is detected in the global scope', () => {
    // eslint-disable-next-line
    require('../utils/nonce').mockImplementation(() => 'foo')

    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const Heading = styled.h1`
      color: red;
    `

    const sheet = new ServerStyleSheet()
    const html = renderToString(
      sheet.collectStyles(
        <React.Fragment>
          <Component />
          <Heading>Hello SSR!</Heading>
        </React.Fragment>
      )
    )
    const css = sheet.getStyleTags()

    expect(html).toMatchSnapshot()
    expect(css).toMatchSnapshot()
  })

  it('should render CSS in the order the components were defined, not rendered', () => {
    const ONE = styled.h1.withConfig({ componentId: 'ONE' })`
      color: red;
    `
    const TWO = styled.h2.withConfig({ componentId: 'TWO' })`
      color: blue;
    `

    const sheet = new ServerStyleSheet()
    const html = renderToString(
      sheet.collectStyles(

          <TWO />
          <ONE />

      )
    )
    const css = sheet.getStyleTags()

    expect(html).toMatchSnapshot()
    expect(css).toMatchSnapshot()
  })

  it('should share global styles but keep renders separate', () => {
    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const PageOne = styled.h1.withConfig({ componentId: 'PageOne' })`
      color: red;
    `
    const PageTwo = styled.h2.withConfig({ componentId: 'PageTwo' })`
      color: blue;
    `

    const sheetOne = new ServerStyleSheet()
    const htmlOne = renderToString(
      sheetOne.collectStyles(
        <React.Fragment>
          <Component />
          <PageOne>Camera One!</PageOne>
        </React.Fragment>
      )
    )
    const cssOne = sheetOne.getStyleTags()

    const sheetTwo = new ServerStyleSheet()
    const htmlTwo = renderToString(
      sheetTwo.collectStyles(
        <React.Fragment>
          <Component />
          <PageTwo>Camera Two!</PageTwo>
        </React.Fragment>
      )
    )
    const cssTwo = sheetTwo.getStyleTags()

    expect(htmlOne).toMatchSnapshot()
    expect(cssOne).toMatchSnapshot()
    expect(htmlTwo).toMatchSnapshot()
    expect(cssTwo).toMatchSnapshot()
  })

  it('should dispatch global styles to each ServerStyleSheet', () => {
    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const Header = styled.h1.withConfig({ componentId: 'Header' })`
      animation: ${props => props.animation} 1s both;
    `

    const sheet = new ServerStyleSheet()
    const html = renderToString(
      sheet.collectStyles(
        <React.Fragment>
          <Component />
          <Header animation={keyframes`0% { opacity: 0; }`} />
        </React.Fragment>
      )
    )
    const css = sheet.getStyleTags()

    expect(html).toMatchSnapshot()
    expect(css).toMatchSnapshot()
  })

  it('should return a generated React style element', () => {
    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const Heading = styled.h1`
      color: red;
    `

    const sheet = new ServerStyleSheet()
    const html = renderToString(
      sheet.collectStyles(
        <React.Fragment>
          <Component />
          <Heading>Hello SSR!</Heading>
        </React.Fragment>
      )
    )
    const elements = sheet.getStyleElement()

    expect(elements).toHaveLength(1)

    /* I know this looks pointless, but apparently I have the feeling we'll need this */
    expect(elements[0].props.dangerouslySetInnerHTML).toBeDefined()
    expect(elements[0].props.children).not.toBeDefined()

    expect(elements[0].props).toMatchSnapshot()
  })

  it('should return a generated React style element with nonce if webpack nonce is preset in the global scope', () => {
    // eslint-disable-next-line
    require('../utils/nonce').mockImplementation(() => 'foo')

    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const Heading = styled.h1`
      color: red;
    `

    const sheet = new ServerStyleSheet()
    const html = renderToString(
      sheet.collectStyles(
        <React.Fragment>
          <Heading>Hello SSR!</Heading>
          <Component />
        </React.Fragment>
      )
    )
    const elements = sheet.getStyleElement()

    expect(elements).toHaveLength(1)
    expect(elements[0].props.nonce).toBe('foo')
  })

  it('should interleave styles with rendered HTML when utilitizing streaming', () => {
    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const Heading = styled.h1`
      color: red;
    `

    const sheet = new ServerStyleSheet()
    const jsx = sheet.collectStyles(
      <React.Fragment>
        <Component />
        <Heading>Hello SSR!</Heading>
      </React.Fragment>
    )
    const stream = sheet.interleaveWithNodeStream(renderToNodeStream(jsx))

    return new Promise((resolve, reject) => {
      let received = ''

      stream.on('data', chunk => {
        received += chunk
      })

      stream.on('end', () => {
        expect(received).toMatchSnapshot()
        expect(sheet.sealed).toBe(true)
        resolve()
      })

      stream.on('error', reject)
    })
  })

  it('should interleave styles with rendered HTML when chunked streaming', () => {
    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const Heading = styled.h1`
      color: red;
    `

    const Body = styled.div`
      color: blue;
    `

    const SideBar = styled.div`
      color: yellow;
    `

    const Footer = styled.div`
      color: green;
    `

    const sheet = new ServerStyleSheet()
    const jsx = sheet.collectStyles(
      <React.Fragment>
        <Component />
        <Heading>Hello SSR!</Heading>

          {new Array(1000).fill(0).map(() => (

*************************

          ))}

        <SideBar>SideBar</SideBar>
        Footer
      </React.Fragment>
    )
    const stream = sheet.interleaveWithNodeStream(renderToNodeStream(jsx))

    return new Promise((resolve, reject) => {
      let received = ''

      stream.on('data', chunk => {
        received += chunk
      })

      stream.on('end', () => {
        expect(received).toMatchSnapshot()
        expect(sheet.sealed).toBe(true)
        expect(received).toMatch(/yellow/)
        expect(received).toMatch(/green/)
        resolve()
      })

      stream.on('error', reject)
    })
  })

  it('should handle errors while streaming', () => {
    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const Heading = styled.h1`
      color: red;
    `

    const sheet = new ServerStyleSheet()
    const jsx = sheet.collectStyles(null)
    const stream = sheet.interleaveWithNodeStream(renderToNodeStream(jsx))

    return new Promise((resolve, reject) => {
      stream.on('data', function noop() {})

      stream.on('error', err => {
        expect(err).toMatchSnapshot()
        expect(sheet.sealed).toBe(true)
        resolve()
      })
    })
  })
})
<commit_msg>remove unused test code<commit_after>/**
 * @jest-environment node
 */
import React from 'react'
import { renderToString, renderToNodeStream } from 'react-dom/server'
import ServerStyleSheet from '../models/ServerStyleSheet'
import { resetStyled, resetCreateGlobalStyle } from './utils'
import _keyframes from '../constructors/keyframes'
import stringifyRules from '../utils/stringifyRules'
import css from '../constructors/css'

jest.mock('../utils/nonce')

let index = 0
const keyframes = _keyframes(() => `keyframe_${index++}`, stringifyRules, css)

let styled
let createGlobalStyle

describe('ssr', () => {
  beforeEach(() => {
    // eslint-disable-next-line
    require('../utils/nonce').mockReset()

    styled = resetStyled(true)
    createGlobalStyle = resetCreateGlobalStyle()
  })

  afterEach(() => {
    process.env.NODE_ENV = 'test'
  })

  it('should extract the CSS in a simple case', () => {
    const Heading = styled.h1`
      color: red;
    `

    const sheet = new ServerStyleSheet()
    const html = renderToString(
      sheet.collectStyles(<Heading>Hello SSR!</Heading>)
    )
    const css = sheet.getStyleTags()

    expect(html).toMatchSnapshot()
    expect(css).toMatchSnapshot()
  })

  it('should extract both global and local CSS', () => {
    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const Heading = styled.h1`
      color: red;
    `

    const sheet = new ServerStyleSheet()
    const html = renderToString(
      sheet.collectStyles(
        <React.Fragment>
          <Component />
          <Heading>Hello SSR!</Heading>
        </React.Fragment>
      )
    )
    const css = sheet.getStyleTags()

    expect(html).toMatchSnapshot()
    expect(css).toMatchSnapshot()
  })

  it('should not spill ServerStyleSheets into each other', () => {
    const A = styled.h1`
      color: red;
    `
    const B = styled.h1`
      color: green;
    `

    const sheetA = new ServerStyleSheet()
    renderToString(sheetA.collectStyles())
    const cssA = sheetA.getStyleTags()

    const sheetB = new ServerStyleSheet()
    renderToString(sheetB.collectStyles())
    const cssB = sheetB.getStyleTags()

    expect(cssA).toContain('red')
    expect(cssA).not.toContain('green')
    expect(cssB).not.toContain('red')
    expect(cssB).toContain('green')
  })

  it('should add a nonce to the stylesheet if webpack nonce is detected in the global scope', () => {
    // eslint-disable-next-line
    require('../utils/nonce').mockImplementation(() => 'foo')

    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const Heading = styled.h1`
      color: red;
    `

    const sheet = new ServerStyleSheet()
    const html = renderToString(
      sheet.collectStyles(
        <React.Fragment>
          <Component />
          <Heading>Hello SSR!</Heading>
        </React.Fragment>
      )
    )
    const css = sheet.getStyleTags()

    expect(html).toMatchSnapshot()
    expect(css).toMatchSnapshot()
  })

  it('should render CSS in the order the components were defined, not rendered', () => {
    const ONE = styled.h1.withConfig({ componentId: 'ONE' })`
      color: red;
    `
    const TWO = styled.h2.withConfig({ componentId: 'TWO' })`
      color: blue;
    `

    const sheet = new ServerStyleSheet()
    const html = renderToString(
      sheet.collectStyles(

          <TWO />
          <ONE />

      )
    )
    const css = sheet.getStyleTags()

    expect(html).toMatchSnapshot()
    expect(css).toMatchSnapshot()
  })

  it('should share global styles but keep renders separate', () => {
    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const PageOne = styled.h1.withConfig({ componentId: 'PageOne' })`
      color: red;
    `
    const PageTwo = styled.h2.withConfig({ componentId: 'PageTwo' })`
      color: blue;
    `

    const sheetOne = new ServerStyleSheet()
    const htmlOne = renderToString(
      sheetOne.collectStyles(
        <React.Fragment>
          <Component />
          <PageOne>Camera One!</PageOne>
        </React.Fragment>
      )
    )
    const cssOne = sheetOne.getStyleTags()

    const sheetTwo = new ServerStyleSheet()
    const htmlTwo = renderToString(
      sheetTwo.collectStyles(
        <React.Fragment>
          <Component />
          <PageTwo>Camera Two!</PageTwo>
        </React.Fragment>
      )
    )
    const cssTwo = sheetTwo.getStyleTags()

    expect(htmlOne).toMatchSnapshot()
    expect(cssOne).toMatchSnapshot()
    expect(htmlTwo).toMatchSnapshot()
    expect(cssTwo).toMatchSnapshot()
  })

  it('should dispatch global styles to each ServerStyleSheet', () => {
    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const Header = styled.h1.withConfig({ componentId: 'Header' })`
      animation: ${props => props.animation} 1s both;
    `

    const sheet = new ServerStyleSheet()
    const html = renderToString(
      sheet.collectStyles(
        <React.Fragment>
          <Component />
          <Header animation={keyframes`0% { opacity: 0; }`} />
        </React.Fragment>
      )
    )
    const css = sheet.getStyleTags()

    expect(html).toMatchSnapshot()
    expect(css).toMatchSnapshot()
  })

  it('should return a generated React style element', () => {
    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const Heading = styled.h1`
      color: red;
    `

    const sheet = new ServerStyleSheet()
    const html = renderToString(
      sheet.collectStyles(
        <React.Fragment>
          <Component />
          <Heading>Hello SSR!</Heading>
        </React.Fragment>
      )
    )
    const elements = sheet.getStyleElement()

    expect(elements).toHaveLength(1)

    /* I know this looks pointless, but apparently I have the feeling we'll need this */
    expect(elements[0].props.dangerouslySetInnerHTML).toBeDefined()
    expect(elements[0].props.children).not.toBeDefined()

    expect(elements[0].props).toMatchSnapshot()
  })

  it('should return a generated React style element with nonce if webpack nonce is preset in the global scope', () => {
    // eslint-disable-next-line
    require('../utils/nonce').mockImplementation(() => 'foo')

    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const Heading = styled.h1`
      color: red;
    `

    const sheet = new ServerStyleSheet()
    const html = renderToString(
      sheet.collectStyles(
        <React.Fragment>
          <Heading>Hello SSR!</Heading>
          <Component />
        </React.Fragment>
      )
    )
    const elements = sheet.getStyleElement()

    expect(elements).toHaveLength(1)
    expect(elements[0].props.nonce).toBe('foo')
  })

  it('should interleave styles with rendered HTML when utilitizing streaming', () => {
    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const Heading = styled.h1`
      color: red;
    `

    const sheet = new ServerStyleSheet()
    const jsx = sheet.collectStyles(
      <React.Fragment>
        <Component />
        <Heading>Hello SSR!</Heading>
      </React.Fragment>
    )
    const stream = sheet.interleaveWithNodeStream(renderToNodeStream(jsx))

    return new Promise((resolve, reject) => {
      let received = ''

      stream.on('data', chunk => {
        received += chunk
      })

      stream.on('end', () => {
        expect(received).toMatchSnapshot()
        expect(sheet.sealed).toBe(true)
        resolve()
      })

      stream.on('error', reject)
    })
  })

  it('should interleave styles with rendered HTML when chunked streaming', () => {
    const Component = createGlobalStyle`
      body { background: papayawhip; }
    `
    const Heading = styled.h1`
      color: red;
    `

    const Body = styled.div`
      color: blue;
    `

    const SideBar = styled.div`
      color: yellow;
    `

    const Footer = styled.div`
      color: green;
    `

    const sheet = new ServerStyleSheet()
    const jsx = sheet.collectStyles(
      <React.Fragment>
        <Component />
        <Heading>Hello SSR!</Heading>

          {new Array(1000).fill(0).map(() => (

*************************

          ))}

        <SideBar>SideBar</SideBar>
        Footer
      </React.Fragment>
    )
    const stream = sheet.interleaveWithNodeStream(renderToNodeStream(jsx))

    return new Promise((resolve, reject) => {
      let received = ''

      stream.on('data', chunk => {
        received += chunk
      })

      stream.on('end', () => {
        expect(received).toMatchSnapshot()
        expect(sheet.sealed).toBe(true)
        expect(received).toMatch(/yellow/)
        expect(received).toMatch(/green/)
        resolve()
      })

      stream.on('error', reject)
    })
  })

  it('should handle errors while streaming', () => {
    const sheet = new ServerStyleSheet()
    const jsx = sheet.collectStyles(null)
    const stream = sheet.interleaveWithNodeStream(renderToNodeStream(jsx))

    return new Promise((resolve, reject) => {
      stream.on('data', function noop() {})

      stream.on('error', err => {
        expect(err).toMatchSnapshot()
        expect(sheet.sealed).toBe(true)
        resolve()
      })
    })
  })
})
<|endoftext|>


<commit_before>// BusinessProcess costs resolution

'use strict';

var memoize               = require('memoizee/plain')
  , definePercentage      = require('dbjs-ext/number/percentage')
  , defineCurrency        = require('dbjs-ext/number/currency')
  , defineMultipleProcess = require('../lib/multiple-process')
  , defineCost            = require('../cost')
  , defineRegistrations   = require('./registrations')

  , definePaymentReceiptUploads;

module.exports = memoize(function (db/* options */) {
	var BusinessProcess = defineRegistrations(db, arguments[1])
	  , Percentage = definePercentage(db)
	  , MultipleProcess = defineMultipleProcess(db)
	  , Currency = defineCurrency(db)
	  , Cost = defineCost(db);

	BusinessProcess.prototype.defineProperties({
		costs: { type: MultipleProcess, nested: true }
	});
	BusinessProcess.prototype.costs.map._descriptorPrototype_.type = Cost;
	BusinessProcess.prototype.costs.defineProperties({
		// Applicable costs resolved out of requested registrations
		applicable: { type: Cost, value: function (_observe) {
			var result = [];
			_observe(this.master.registrations.requested).forEach(function (registration) {
				_observe(registration.costs).forEach(function (cost) { result.push(cost); });
			});
			return result;
		} },
		// Payable subset of applicable costs
		// More directly: all applicable costs that are non 0
		payable: { type: Cost, multiple: true, value: function (_observe) {
			var result = [];
			this.applicable.forEach(function (cost) {
				var isPayable = Boolean(cost._get ? _observe(cost._amount) : cost.amount);
				if (isPayable) result.push(cost);
			});
			return result;
		} },
		// Paid costs
		paid: { type: Cost, multiple: true, value: function (_observe) {
			var result = [];
			this.payable.forEach(function (cost) {
				if (_observe(cost._isPaid)) result.push(cost);
			});
			return result;
		} },
		// Electronic costs
		electronic: { type: Cost, multiple: true, value: function (_observe) {
			var result = [];
			this.payable.forEach(function (cost) {
				if (cost.isElectronic) result.push(cost);
			});
			return result;
		} },
		// Payment progress
		paymentProgress: { type: Percentage, value: function (_observe) {
			var valid = 0, total = 0, paymentReceiptUploads = this.master.paymentReceiptUploads;
			// Eventual online payments
			if (this.electronic.size) {
				++total;
				if (this.electronic.every(function (cost) { return _observe(cost._isPaid); })) {
					++valid;
				}
			}
			total += _observe(paymentReceiptUploads.applicable._size);
			valid += _observe(paymentReceiptUploads.uploaded._size);
			if (!total) return 1;
			return valid / total;
		} },
		// Total for all payable costs
		totalAmount: { type: Currency, value: function (_observe) {
			var total = 0;
			this.payable.forEach(function (cost) {
				var amount = cost._get ? _observe(cost._amount) : cost.amount;
				total += amount;
			});
			return total;
		} }
	});

	if (!BusinessProcess.prototype.paymentReceiptUploads) definePaymentReceiptUploads(db);
	return BusinessProcess;
}, { normalizer: require('memoizee/normalizers/get-1')() });

definePaymentReceiptUploads = require('./payment-receipt-uploads');
<commit_msg>Introduce `paymentWeight` property<commit_after>// BusinessProcess costs resolution

'use strict';

var memoize               = require('memoizee/plain')
  , definePercentage      = require('dbjs-ext/number/percentage')
  , defineCurrency        = require('dbjs-ext/number/currency')
  , defineMultipleProcess = require('../lib/multiple-process')
  , defineCost            = require('../cost')
  , defineRegistrations   = require('./registrations')

  , definePaymentReceiptUploads;

module.exports = memoize(function (db/* options */) {
	var BusinessProcess = defineRegistrations(db, arguments[1])
	  , Percentage = definePercentage(db)
	  , MultipleProcess = defineMultipleProcess(db)
	  , Currency = defineCurrency(db)
	  , Cost = defineCost(db);

	BusinessProcess.prototype.defineProperties({
		costs: { type: MultipleProcess, nested: true }
	});
	BusinessProcess.prototype.costs.map._descriptorPrototype_.type = Cost;
	BusinessProcess.prototype.costs.defineProperties({
		// Applicable costs resolved out of requested registrations
		applicable: { type: Cost, value: function (_observe) {
			var result = [];
			_observe(this.master.registrations.requested).forEach(function (registration) {
				_observe(registration.costs).forEach(function (cost) { result.push(cost); });
			});
			return result;
		} },
		// Payable subset of applicable costs
		// More directly: all applicable costs that are non 0
		payable: { type: Cost, multiple: true, value: function (_observe) {
			var result = [];
			this.applicable.forEach(function (cost) {
				var isPayable = Boolean(cost._get ? _observe(cost._amount) : cost.amount);
				if (isPayable) result.push(cost);
			});
			return result;
		} },
		// Paid costs
		paid: { type: Cost, multiple: true, value: function (_observe) {
			var result = [];
			this.payable.forEach(function (cost) {
				if (_observe(cost._isPaid)) result.push(cost);
			});
			return result;
		} },
		// Electronic costs
		electronic: { type: Cost, multiple: true, value: function (_observe) {
			var result = [];
			this.payable.forEach(function (cost) {
				if (cost.isElectronic) result.push(cost);
			});
			return result;
		} },
		// Payment progress
		paymentProgress: { type: Percentage, value: function (_observe) {
			var valid = 0, total = 0, paymentReceiptUploads = this.master.paymentReceiptUploads;
			// Eventual online payments
			if (this.electronic.size) {
				++total;
				if (this.electronic.every(function (cost) { return _observe(cost._isPaid); })) {
					++valid;
				}
			}
			total += _observe(paymentReceiptUploads.applicable._size);
			valid += _observe(paymentReceiptUploads.uploaded._size);
			if (!total) return 1;
			return valid / total;
		} },
		// Payment weight
		// Indicates number of step user needs to take to complete payment step in Part A
		// e.g. one step per each payment receipt, and one step for one online payment
		// If it's zero, that means we should not show payment step at all
		paymentWeight: { type: Percentage, value: function (_observe) {
			var weight = 0;
			if (this.electronic.size) ++weight;
			weight += _observe(this.mater.paymentReceiptUploads.applicable._size);
			return weight;
		} },
		// Total for all payable costs
		totalAmount: { type: Currency, value: function (_observe) {
			var total = 0;
			this.payable.forEach(function (cost) {
				var amount = cost._get ? _observe(cost._amount) : cost.amount;
				total += amount;
			});
			return total;
		} }
	});

	if (!BusinessProcess.prototype.paymentReceiptUploads) definePaymentReceiptUploads(db);
	return BusinessProcess;
}, { normalizer: require('memoizee/normalizers/get-1')() });

definePaymentReceiptUploads = require('./payment-receipt-uploads');
<|endoftext|>