<commit_before>(function(factory) {
    'use strict';

    if (typeof define === 'function' && define.amd) {
        define(['mimeparser', 'stringencoding'], factory);
    } else if (typeof exports === 'object') {
        module.exports = factory(require('mimeparser'), require('stringencoding'));
    }
})(function(MimeParser, stringencoding) {
    'use strict';

    var TextDecoder = stringencoding.TextDecoder;

    var parser = {};
    parser.parse = function(messageParts, cb) {
        var parsedCounter = 0;
        messageParts.forEach(function(msgPart) {
            var parser = new MimeParser();
            parser.onend = function() {
                walkMimeTree(parser.node, msgPart);
                delete msgPart.raw;

                // we're done with a body part, are we done?
                parsedCounter++;
                if (parsedCounter < messageParts.length) {
                    return;
                }

                cb(messageParts);
            };
            parser.end(msgPart.plaintext || msgPart.raw);
        });
    };

    var mimeTreeMatchers = [matchEncrypted, matchSigned, matchText, matchHtml, matchAttachment];

    function walkMimeTree(mimeNode, msgPart) {
        var i = mimeTreeMatchers.length;
        while (i--) {
            if (mimeTreeMatchers[i](mimeNode, msgPart)) {
                return;
            }
        }

        if (mimeNode._childNodes) {
            mimeNode._childNodes.forEach(function(childNode) {
                walkMimeTree(childNode, msgPart);
            });
        }
    }

    /**
     * Matches encrypted PGP/MIME nodes
     *
     * multipart/encrypted
     * |
     * |-- application/pgp-encrypted
     * |-- application/octet-stream <-- ciphertext
     */
    function matchEncrypted(node, msgPart) {
        var isEncrypted = /^multipart\/encrypted/i.test(node.contentType.value) && node._childNodes && node._childNodes[1];
        if (!isEncrypted) {
            return false;
        }

        msgPart.content = new TextDecoder('utf-8').decode(node._childNodes[1].content);
        return true;
    }

    /**
     * Matches signed PGP/MIME nodes
     *
     * multipart/signed
     * |
     * |-- *** (signed mime sub-tree)
     * |-- application/pgp-signature
     */
    function matchSigned(node, msgPart) {
        var isSigned = /^multipart\/signed/i.test(node.contentType.value) && node._childNodes && node._childNodes[0] && node._childNodes[1] && /^application\/pgp-signature/i.test(node._childNodes[1].contentType.value);

        if (!isSigned) {
            return false;
        }

        var part;
        if (msgPart.type === 'signed') {
            // this mime node is the signed node we gave to the mimeparser
            part = msgPart;
        } else {
            // this mime node is part of a signed or encrypted node
            part = {
                type: 'signed',
                content: []
            };
            msgPart.content.push(part);
        }

        part.signed = node._childNodes[0].raw;
        part.signature = new TextDecoder('utf-8').decode(node._childNodes[1].content);

        walkMimeTree(node._childNodes[0], part);

        return true;
    }

    /**
     * Matches non-attachment text/plain nodes
     */
    function matchText(node, msgPart) {
        var disposition = node.headers['content-disposition'];
        var isText = (/^text\/plain/i.test(node.contentType.value) && (!disposition || (disposition && disposition[0].value !== 'attachment')));

        if (!isText) {
            return false;
        }

        var content = new TextDecoder('utf-8').decode(node.content).replace(/([\r]?\n)*$/g, '');
        if (msgPart.type === 'text') {
            // this mime node is the text node we gave to the mimeparser
            msgPart.content = content;
        } else {
            // this mime node is part of a signed or encrypted node
            msgPart.content.push({
                type: 'text',
                content: content
            });
        }

        return true;
    }

    /**
     * Matches non-attachment text/html nodes
     */
    function matchHtml(node, msgPart) {
        var disposition = node.headers['content-disposition'];
        var isHtml = (/^text\/html/i.test(node.contentType.value) && (!disposition || (disposition && disposition[0].value !== 'attachment')));

        if (!isHtml) {
            return false;
        }

        var content = new TextDecoder('utf-8').decode(node.content).replace(/([\r]?\n)*$/g, '');
        if (msgPart.type === 'html') {
            // this mime node is the html node we gave to the mimeparser
            msgPart.content = content;
        } else {
            // this mime node is part of a signed or encrypted node
            msgPart.content.push({
                type: 'html',
                content: content
            });
        }

        return true;
    }

    /**
     * Matches non-attachment text/html nodes
     */
    function matchAttachment(node, msgPart) {
        var disposition = node.headers['content-disposition'],
            contentType = node.contentType.value;
        var isTextAttachment = /^text\//i.test(contentType) && !! disposition && disposition[0].value === 'attachment',
            isOtherAttachment = !/^text\//i.test(contentType) && !/^multipart\//i.test(contentType);

        if (!isTextAttachment && !isOtherAttachment) {
            return false;
        }

        if (msgPart.type === 'attachment') {
            // this mime node is the attachment node we gave to the mimeparser
            msgPart.content = node.content;
        } else {
            // this mime node is part of a signed or encrypted node
            msgPart.content.push({
                type: 'attachment',
                content: node.content,
                id: node.headers['content-id'] ? node.headers['content-id'][0].value : undefined
            });
        }

        return true;
    }

    return parser;

});<commit_msg>remove unnecessary api<commit_after>(function(factory) {
    'use strict';

    if (typeof define === 'function' && define.amd) {
        define(['mimeparser', 'stringencoding'], factory);
    } else if (typeof exports === 'object') {
        module.exports = factory(require('mimeparser'), require('stringencoding'));
    }
})(function(MimeParser, stringencoding) {
    'use strict';

    var TextDecoder = stringencoding.TextDecoder;

    var parser = {};
    parser.parse = function(messageParts, cb) {
        var parsedCounter = 0;
        messageParts.forEach(function(msgPart) {
            var parser = new MimeParser();
            parser.onend = function() {
                walkMimeTree(parser.node, msgPart);
                delete msgPart.raw;

                // we're done with a body part, are we done?
                parsedCounter++;
                if (parsedCounter < messageParts.length) {
                    return;
                }

                cb(messageParts);
            };
            parser.end(msgPart.raw);
        });
    };

    var mimeTreeMatchers = [matchEncrypted, matchSigned, matchText, matchHtml, matchAttachment];

    function walkMimeTree(mimeNode, msgPart) {
        var i = mimeTreeMatchers.length;
        while (i--) {
            if (mimeTreeMatchers[i](mimeNode, msgPart)) {
                return;
            }
        }

        if (mimeNode._childNodes) {
            mimeNode._childNodes.forEach(function(childNode) {
                walkMimeTree(childNode, msgPart);
            });
        }
    }

    /**
     * Matches encrypted PGP/MIME nodes
     *
     * multipart/encrypted
     * |
     * |-- application/pgp-encrypted
     * |-- application/octet-stream <-- ciphertext
     */
    function matchEncrypted(node, msgPart) {
        var isEncrypted = /^multipart\/encrypted/i.test(node.contentType.value) && node._childNodes && node._childNodes[1];
        if (!isEncrypted) {
            return false;
        }

        msgPart.content = new TextDecoder('utf-8').decode(node._childNodes[1].content);
        return true;
    }

    /**
     * Matches signed PGP/MIME nodes
     *
     * multipart/signed
     * |
     * |-- *** (signed mime sub-tree)
     * |-- application/pgp-signature
     */
    function matchSigned(node, msgPart) {
        var isSigned = /^multipart\/signed/i.test(node.contentType.value) && node._childNodes && node._childNodes[0] && node._childNodes[1] && /^application\/pgp-signature/i.test(node._childNodes[1].contentType.value);

        if (!isSigned) {
            return false;
        }

        var part;
        if (msgPart.type === 'signed') {
            // this mime node is the signed node we gave to the mimeparser
            part = msgPart;
        } else {
            // this mime node is part of a signed or encrypted node
            part = {
                type: 'signed',
                content: []
            };
            msgPart.content.push(part);
        }

        part.signed = node._childNodes[0].raw;
        part.signature = new TextDecoder('utf-8').decode(node._childNodes[1].content);

        walkMimeTree(node._childNodes[0], part);

        return true;
    }

    /**
     * Matches non-attachment text/plain nodes
     */
    function matchText(node, msgPart) {
        var disposition = node.headers['content-disposition'];
        var isText = (/^text\/plain/i.test(node.contentType.value) && (!disposition || (disposition && disposition[0].value !== 'attachment')));

        if (!isText) {
            return false;
        }

        var content = new TextDecoder('utf-8').decode(node.content).replace(/([\r]?\n)*$/g, '');
        if (msgPart.type === 'text') {
            // this mime node is the text node we gave to the mimeparser
            msgPart.content = content;
        } else {
            // this mime node is part of a signed or encrypted node
            msgPart.content.push({
                type: 'text',
                content: content
            });
        }

        return true;
    }

    /**
     * Matches non-attachment text/html nodes
     */
    function matchHtml(node, msgPart) {
        var disposition = node.headers['content-disposition'];
        var isHtml = (/^text\/html/i.test(node.contentType.value) && (!disposition || (disposition && disposition[0].value !== 'attachment')));

        if (!isHtml) {
            return false;
        }

        var content = new TextDecoder('utf-8').decode(node.content).replace(/([\r]?\n)*$/g, '');
        if (msgPart.type === 'html') {
            // this mime node is the html node we gave to the mimeparser
            msgPart.content = content;
        } else {
            // this mime node is part of a signed or encrypted node
            msgPart.content.push({
                type: 'html',
                content: content
            });
        }

        return true;
    }

    /**
     * Matches non-attachment text/html nodes
     */
    function matchAttachment(node, msgPart) {
        var disposition = node.headers['content-disposition'],
            contentType = node.contentType.value;
        var isTextAttachment = /^text\//i.test(contentType) && !! disposition && disposition[0].value === 'attachment',
            isOtherAttachment = !/^text\//i.test(contentType) && !/^multipart\//i.test(contentType);

        if (!isTextAttachment && !isOtherAttachment) {
            return false;
        }

        if (msgPart.type === 'attachment') {
            // this mime node is the attachment node we gave to the mimeparser
            msgPart.content = node.content;
        } else {
            // this mime node is part of a signed or encrypted node
            msgPart.content.push({
                type: 'attachment',
                content: node.content,
                id: node.headers['content-id'] ? node.headers['content-id'][0].value : undefined
            });
        }

        return true;
    }

    return parser;

});<|endoftext|>


<commit_before>// Sets the require.js configuration for your application.
require.config( {

      // 3rd party script alias names (Easier to type "jquery" than "libs/jquery-1.8.2.min")
      paths: {

            // Core Libraries
            "jquery": "libs/jquery",
            "jquerymobile": "libs/jquerymobile",
            "underscore": "libs/lodash",
            "backbone": "libs/backbone"

      },

      // Sets the configuration for your third party scripts that are not AMD compatible
      shim: {

            "backbone": {
                  "deps": [ "underscore", "jquery" ],
                  "exports": "Backbone"  //attaches "Backbone" to the window object
            }

      } // end Shim Configuration

} );

// Includes File Dependencies
require([ "jquery","backbone","routers/mobileRouter","jquerymobile" ], function( $, Backbone, Mobile ) {

      // Prevents all anchor click handling including the addition of active button state and alternate link bluring.
      $.mobile.linkBindingEnabled = false;

      // Disabling this will prevent jQuery Mobile from handling hash changes
      $.mobile.hashListeningEnabled = false;

      // Instantiates a new Backbone.js Mobile Router
      this.router = new Mobile();

} );<commit_msg>Added "mobileinit" handler to set up options<commit_after>// Sets the require.js configuration for your application.
require.config( {

      // 3rd party script alias names (Easier to type "jquery" than "libs/jquery-1.8.2.min")
      paths: {

            // Core Libraries
            "jquery": "libs/jquery",
            "jquerymobile": "libs/jquerymobile",
            "underscore": "libs/lodash",
            "backbone": "libs/backbone"

      },

      // Sets the configuration for your third party scripts that are not AMD compatible
      shim: {

            "backbone": {
                  "deps": [ "underscore", "jquery" ],
                  "exports": "Backbone"  //attaches "Backbone" to the window object
            }

      } // end Shim Configuration

} );

// Includes File Dependencies
require([ "jquery", "backbone", "routers/mobileRouter" ], function( $, Backbone, Mobile ) {

	$( document ).on( "mobileinit",
		// Set up the "mobileinit" handler before requiring jQuery Mobile's module
		function() {
			// Prevents all anchor click handling including the addition of active button state and alternate link bluring.
			$.mobile.linkBindingEnabled = false;

			// Disabling this will prevent jQuery Mobile from handling hash changes
			$.mobile.hashListeningEnabled = false;
		}
	)

	require( [ "jquerymobile" ], function() {
		// Instantiates a new Backbone.js Mobile Router
		this.router = new Mobile();
	});
} );<|endoftext|>


<commit_before>$(document).ready(function(){
  var sView = new Search.View
    , sController = new Search.Controller(sView);
  sController.bindListeners();
})

Search.Controller = function(sView){
  this.view = sView;
}

Search.Controller.prototype = {
  bindListeners: function(){
    this.searchFirstSongListener();
    this.cancelBtnListener();
  },

  searchFirstSongListener: function(){
    var self = this;
    $('#search_first_song').on('submit', function(e){
      e.preventDefault();
      self.searchFirstSong($(this));
    })
  },

  cancelBtnListener: function(){
    var self = this;
    $('#cancel-btn').on('click', function(e){
      self.cancelBtn();
    });
  },

  cancelBtn: function(){
    this.view.hideSearch();
  },

  searchFirstSong: function(form){
    var self = this
      , url = form.attr("action")
      , searchQuery = form.find('input').first().val();
    $.ajax({
      url: url,
      type: "POST",
      data: {search: searchQuery}
    }).done(function(response){
      $('#search-results').remove()
      $('#search-container').append(response)
      $('#search_first_song').find('input').first().val("")
      if($('#player').length==1){
        self.clickSongListener();
      }
      else{
        self.clickFirstSongListener();
      }
    })
  },

  clickFirstSongListener: function(){
    var self = this;
    $('.video-container').on('click', function(e){
      e.preventDefault();
      if(window.location.pathname.split('/')[3]=='guest'){
        self.guestClick($(this));
      }
      else{
        self.clickFirstSong($(this));
      }
    })
  },

  guestClick: function(container){
    var parameters = container.parent().attr('href').split('?')
        url = parameters[0]
        room = url.split('/')[2]
        videoId = parameters[1].split('=')[1]

    $.ajax({
      url: url+ "/guestsearch",
      type: "POST",
      data: {video_id: videoId}
    }).done(function(response){
      $('#search-results').remove()
      $('#search-container').append(response)
      $('#added_message').fadeOut(3000)
    })
  },

  clickSongListener: function(){
    var self = this;
    $('.video-container').on('click', function(e){
      e.preventDefault();
      self.clickSong($(this));
    })
  },

  clickFirstSong: function(container){
    var parameters = container.parent().attr('href').split('?')
        url = parameters[0]
        room = url.split('/')[2]
        videoId = parameters[1].split('=')[1]
    $.ajax({
      url: url+ "/theatre",
      type: "POST",
      data: {video_id: videoId}
    }).done(function(response){
      $('#search-container').remove();
      $('#search-results').remove();
      $('#search_first_song').remove();
      $('body').prepend(response);
      $('#search-container').css('display', 'none')
    })
  },

  clickSong: function(container){
    var parameters = container.parent().attr('href').split('?')
        url = parameters[0]
        videoId = parameters[1].split('=')[1]
    $.ajax({
      url: url+ '/theatre',
      type: "POST",
      data: {video_id: videoId, not_first_song: true}
    }).done(function(response){
      $('#search-results').remove()
      $('#player').append(response)
      $('#added_message').fadeOut(3000)
    })
  }
}

Search.View = function(){}

Search.View.prototype = {
  showSearch: function(){
    $('#search-container').fadeIn(2000);
    $('#cancel-btn').fadeIn(2000);
  },

  hideSearch: function(){
    $('#search-container').fadeOut(2000);
  }
}

<commit_msg>Separates view from controller and creates  add to playlist ajax<commit_after>$(document).ready(function(){
  var sController = new Search.Controller(Search.View);
  sController.bindListeners();
})

Search.Controller = function(sView){
  this.view = new sView;
}

Search.Controller.prototype = {
  bindListeners: function(){
    this.searchFirstSongListener();
    this.cancelBtnListener();
  },

  searchFirstSongListener: function(){
    var self = this;
    $('#search_first_song').on('submit', function(e){
      e.preventDefault();
      self.searchFirstSong($(this));
    })
  },

  cancelBtnListener: function(){
    var self = this;
    $('#cancel-btn').on('click', function(e){
      self.cancelBtn();
    });
  },

  cancelBtn: function(){
    this.view.cancelSearch();
  },

  searchFirstSong: function(form){
    var self = this
      , url = form.attr("action")
      , searchQuery = form.find('input').first().val();

    $.ajax({
      url: url,
      type: "POST",
      data: {search: searchQuery}
    }).done(function(response){
      self.view.removeSearchResults();
      self.view.hideSearchResults();
      $('#search-container').append(response)
      $('#search_first_song').find('input').first().val("")
      if($('#player').length==1){
        self.clickSongListener();
      }
      else{
        self.clickFirstSongListener();
      }
    })
  },

  clickFirstSongListener: function(){
    var self = this;
    $('.video-container').on('click', function(e){
      e.preventDefault();
      if(window.location.pathname.split('/')[3]=='guest'){
        self.guestClick($(this));
      }
      else{
        self.clickFirstSong($(this));
      }
    })
  },

  guestClick: function(container){
    var parameters = container.parent().attr('href').split('?')
        url = parameters[0]
        room = url.split('/')[2]
        videoId = parameters[1].split('=')[1]
        self = this

    $.ajax({
      url: url+ "/guestsearch",
      type: "POST",
      data: {video_id: videoId}
    }).done(function(response){
      self.view.hideSearchResults();
      setTimeout($('#search-container').append(response), 1000);
      $('#added_message').fadeOut(3000)
    })
  },

  clickSongListener: function(){
    var self = this;
    $('.video-container').on('click', function(e){
      e.preventDefault();
      self.clickSong($(this));
      self.addToPlaylist($(this));
    })
  },

  clickFirstSong: function(container){
    var parameters = container.parent().attr('href').split('?')
        url = parameters[0]
        room = url.split('/')[2]
        videoId = parameters[1].split('=')[1]
        self = this

    $.ajax({
      url: url+ "/theatre",
      type: "POST",
      data: {video_id: videoId}
    }).done(function(response){
      self.view.removeSearchContainer();
      self.view.hideSearchResults();
      self.view.removeSearchForm();
      $('body').prepend(response);
      self.sView.hideSearchContainer();
    })
  },

  clickSong: function(container){
    var parameters = container.parent().attr('href').split('?')
        url = parameters.shift()
        videoId = parameters.shift().split('=')[1]
        self = this
    $.ajax({
      url: url+ '/theatre',
      type: "POST",
      data: {video_id: videoId, not_first_song: true}
    }).done(function(response){
      self.view.hideSearchResults();
      setTimeout(function(){
        $('#player').append(response)
        self.view.removeSearchContainer();
      }, 1500);
      // $('#added_message').fadeOut(3000)
    })
  },

  addToPlaylist: function(container){
    var parameters = container.parent().attr('href').split('?')
        url = parameters.shift()
        videoId = parameters.shift().split('=')[1]
        self = this
    $.ajax({
      url: url+ '/add_to_queue',
      type: "GET",
      data: {video_id: videoId}
    }).done(function(response){
      $('#playlist-container ul').append(response)
    })

  }
}

Search.View = function(){}

Search.View.prototype = {
  showSearch: function(){
    $('#search-container').fadeIn(1000);
    $('#cancel-btn').fadeIn(1000);
  },

  cancelSearch: function(){
    $('#search-container').fadeOut(1000);
  },

  removeSearchResults: function(){
    $('#search-results').remove();
  },

  hideSearchResults: function(){
    $('#search-results').slideUp(1000)
  },

  removeSearchContainer: function(){
    $('#search-container').remove()
  },

  removeSearchForm: function(){
    $('#search_first_song').remove();
  },

  hideSearchContainer: function(){
    $('#search-container').css('display', 'none')
  }
}

<|endoftext|>


<commit_before>import _ from 'underscore';
import BaseCollection from './BaseCollection';

class Builds extends BaseCollection {

  url() {
    return "/api/builds";
  }

  parse() {
    this.addTimeHelpers();
  }

  getBranchModules(branchInfo) {

    let groupBuilds = this.groupBuilds()

    return _.findWhere(groupBuilds, {
      organization: branchInfo.org,
      name: branchInfo.repo,
      branch: branchInfo.branch,
    })

  }

  getModuleList() {
    // list of module names, used for sidebar search
    let modules = _.map(this.data, function(item){

      let {gitInfo, module, buildState} = item;
      let moduleInfo = {
        repository: gitInfo.repository,
        module: module.name,
        link: `${app.config.appRoot}/${gitInfo.host}/${gitInfo.organization}/${gitInfo.repository}/${gitInfo.branch}/${module.name}/${buildState.buildNumber}`
      };
      return moduleInfo;
    });

    return modules;
  }

  groupBuilds() {
    // builds grouped by repo
    let grouped = _(this.data).groupBy(function(o) {
      return o.gitInfo.repository;
    });

    _.each(grouped, (repo) => {
      repo.moduleIsBuilding = false;
      for (var value of repo) {
        if(value.buildState.result === 'IN_PROGRESS'){
          repo.moduleIsBuilding = true;
          break;
        }
      }
      return repo;
    })

    let groupedInArray = [];
    for (var repo in grouped) {
      groupedInArray.push({
        name: repo,
        isBuilding: grouped[repo].moduleIsBuilding,
        modules: grouped[repo]
      })
    }

    groupedInArray.forEach( (repo) => {
      repo.mostRecentBuild = repo.modules[0].buildState.startTime;
      repo.host = repo.modules[0].gitInfo.host;
      repo.branch = repo.modules[0].gitInfo.branch;
      repo.organization = repo.modules[0].gitInfo.organization;

      repo.modules.forEach( (module) => {
        module.modulePath = `${app.config.appRoot}/${module.gitInfo.host}/${module.gitInfo.organization}/${module.gitInfo.repository}/${module.gitInfo.branch}/${module.module.name}`
        if (module.buildState.startTime < repo.mostRecentBuild) {
          repo.mostRecentBuild = module.buildState.startTime;
        }

      })
    })

    // sort by if building then by most recent build time
    function cmp(x, y) {
      return x > y ? 1 : x < y ? -1 : 0;
    }

    groupedInArray.sort( (a,b) => { ;
      return cmp(b.isBuilding, a.isBuilding) || cmp(a.mostRecentBuild, b.mostRecentBuild);
    })

    return groupedInArray;

  }

}

export default Builds;
<commit_msg>add build link to builds collection<commit_after>import _ from 'underscore';
import BaseCollection from './BaseCollection';

class Builds extends BaseCollection {

  url() {
    return "/api/builds";
  }

  parse() {
    this.addTimeHelpers();
  }

  getBranchModules(branchInfo) {

    let groupBuilds = this.groupBuilds()

    return _.findWhere(groupBuilds, {
      organization: branchInfo.org,
      name: branchInfo.repo,
      branch: branchInfo.branch,
    })

  }

  getModuleList() {
    // list of module names, used for sidebar search
    let modules = _.map(this.data, function(item){

      let {gitInfo, module, buildState} = item;
      let moduleInfo = {
        repository: gitInfo.repository,
        module: module.name,
        link: `${app.config.appRoot}/${gitInfo.host}/${gitInfo.organization}/${gitInfo.repository}/${gitInfo.branch}/${module.name}/${buildState.buildNumber}`
      };
      return moduleInfo;
    });

    return modules;
  }

  groupBuilds() {
    // builds grouped by repo
    let grouped = _(this.data).groupBy(function(o) {
      return o.gitInfo.repository;
    });

    _.each(grouped, (repo) => {
      repo.moduleIsBuilding = false;
      for (var value of repo) {
        if(value.buildState.result === 'IN_PROGRESS'){
          repo.moduleIsBuilding = true;
          break;
        }
      }
      return repo;
    })

    let groupedInArray = [];
    for (var repo in grouped) {
      groupedInArray.push({
        name: repo,
        isBuilding: grouped[repo].moduleIsBuilding,
        modules: grouped[repo]
      })
    }

    groupedInArray.forEach( (repo) => {
      repo.mostRecentBuild = repo.modules[0].buildState.startTime;
      repo.host = repo.modules[0].gitInfo.host;
      repo.branch = repo.modules[0].gitInfo.branch;
      repo.organization = repo.modules[0].gitInfo.organization;

      repo.modules.forEach( (module) => {
        module.modulePath = `${app.config.appRoot}/${module.gitInfo.host}/${module.gitInfo.organization}/${module.gitInfo.repository}/${module.gitInfo.branch}/${module.module.name}`;
        module.buildState.buildLink = `${app.config.appRoot}/${module.gitInfo.host}/${module.gitInfo.organization}/${module.gitInfo.repository}/${module.gitInfo.branch}/${module.module.name}/${module.buildState.buildNumber}`;
        if (module.buildState.startTime < repo.mostRecentBuild) {
          repo.mostRecentBuild = module.buildState.startTime;
        }

      })
    })

    // sort by if building then by most recent build time
    function cmp(x, y) {
      return x > y ? 1 : x < y ? -1 : 0;
    }

    groupedInArray.sort( (a,b) => { ;
      return cmp(b.isBuilding, a.isBuilding) || cmp(a.mostRecentBuild, b.mostRecentBuild);
    })

    return groupedInArray;

  }

}

export default Builds;
<|endoftext|>


<commit_before>import Bandwidth from "../utils/bandwidth";
import AbstractTest from "./abstractTest";
import STATUS from "./status";

export default class XHRTest extends AbstractTest {
  /**
   * @param {string} step
   */
  constructor(step) {
    super(step);
  }

  /**
   * Prepare the test run
   */
  prepareRun() {
    Object.assign(this, {
      data: [],
      loadDiff: [],
      sizeLoaded: [],
      size: 0
    });
  }

  /**
   * Run the XHR based upload speed test
   * @param {object} params
   * @returns {Promise<void>}
   */
  runTest(params) {
    const index = this.index++;

    return new Promise((resolve, reject) => {
      if (this.test.status === STATUS.ABORTED) {
        this.status = STATUS.ABORTED;
        reject({
          status: STATUS.ABORTED
        });
        return;
      }

      if (this.status === STATUS.DONE) {
        resolve();
        return;
      }

      const xhr = new XMLHttpRequest();
      this.requests[index] = xhr;

      this.registerEvents(index, xhr, params, resolve, reject);
      this.sendMessage(xhr);
      xhr.startDate = Date.now();
    });
  }

  /**
   * Register events for the XHR of the bandwidth test
   * @param {number} index
   * @param {XMLHttpRequest} xhr
   * @param {object} params
   * @param {function} resolve
   * @param {function} reject
   */
  registerEvents(index, xhr, params, resolve, reject) {
    xhr = this.initXHR(index, xhr, params);
    const xhrProgressHandler = this.step === 'upload' ? xhr.upload : xhr;
    xhrProgressHandler.onprogress = e => this.handleProgress(e, index, xhr, resolve, reject);
    xhr.addEventListener("load", e => this.handleLoad(e, xhr, params, resolve, reject));
    xhr.addEventListener("error", e => this.handleError(e, params, resolve, reject));
    xhr.addEventListener("timeout", e => this.handleTimeout(e, params, resolve, reject));
  }

  /**
   * Handle the XHR progress event
   * @param {Event} e
   * @param {number} index
   * @param {XMLHttpRequest} xhr
   * @param {function} resolve
   * @param {function} reject
   */
  handleProgress(e, index, xhr, resolve, reject) {
    if (xhr.readyState === XMLHttpRequest.DONE) return;

    if (this.test.status === STATUS.ABORTED) {
      this.status = STATUS.ABORTED;
      xhr.abort();
      reject({ status: STATUS.ABORTED });
      return;
    }

    if (this.status === STATUS.DONE) {
      xhr.abort();
      resolve();
      return;
    }

    this.loadDiff[index] = e.loaded - this.sizeLoaded[index];
    this.sizeLoaded[index] = e.loaded;
    if (this.status === STATUS.RUNNING) {
      this.size += this.loadDiff[index];
    }
    this.processResult();
  }

  /**
   * Handle the XHR load event
   * @param {Event} e
   * @param {XMLHttpRequest} xhr
   * @param {object} params
   * @param {function} resolve
   * @param {function} reject
   */
  handleLoad(e, xhr, params, resolve, reject) {
    const duration = Date.now() - xhr.startDate;
    if (this.test.config[this.step].adjustSize && duration < this.test.config[this.step].minDuration) {
      this.test.config[this.step].size = Math.min(
        Math.round(e.loaded / (duration / 1000)),
        this.test.config[this.step].maxSize
      );
    }
    this.runTest(params)
      .then(resolve)
      .catch(reject);
  }

  /**
   * Handle the XHR error event
   * @param {Event} e
   * @param {object} params
   * @param {function} resolve
   * @param {function} reject
   */
  handleError(e, params, resolve, reject) {
    if (this.test.config.ignoreErrors) {
      this.runTest(params)
        .then(resolve)
        .catch(reject);
      return;
    }

    reject({
      status: STATUS.FAILED,
      error: e.error,
      message: e.message
    });
  }

  /**
   * Handle the XHR timeout event
   * @param {Event} e
   * @param {XMLHttpRequest} xhr
   * @param {object} params
   * @param {function} resolve
   * @param {function} reject
   */
  handleTimeout(e, params, resolve, reject) {
    if (this.test.config[this.step].adjustSize) {
      this.test.config[this.step].size = Math.max(
        Math.round(e.loaded / (this.test.config[this.step].maxDuration / 1000)),
        this.test.config[this.step].minSize
      );
    }
    this.runTest(params)
      .then(resolve)
      .catch(reject);
  }

  /**
   * Process the bandwidth speed test result
   */
  processResult() {
    this.test.result[this.step] = {
      status: this.status,
      progress: 0
    };
    if (this.status <= STATUS.WAITING) return;

    const durationFromInit = Date.now() - this.initDate;
    const durationFromStart = Date.now() - this.startDate;
    const progress = durationFromInit / this.test.config[this.step].duration;
    this.test.result[this.step].progress = progress;
    if (this.status <= STATUS.STARTING) return;

    const { bitBandwidth: bandwidth } = Bandwidth.compute(
      this.size,
      durationFromStart / 1000,
      this.test.config.overheadCompensation
    );
    this.test.result[this.step].speed = +bandwidth.toFixed(2);
  }
}
<commit_msg>fix download/upload size auto adjust setting<commit_after>import Bandwidth from "../utils/bandwidth";
import AbstractTest from "./abstractTest";
import STATUS from "./status";

export default class XHRTest extends AbstractTest {
  /**
   * @param {string} step
   */
  constructor(step) {
    super(step);
  }

  /**
   * Prepare the test run
   */
  prepareRun() {
    Object.assign(this, {
      data: [],
      loadDiff: [],
      sizeLoaded: [],
      size: 0
    });
  }

  /**
   * Run the XHR based upload speed test
   * @param {object} params
   * @returns {Promise<void>}
   */
  runTest(params) {
    const index = this.index++;

    return new Promise((resolve, reject) => {
      if (this.test.status === STATUS.ABORTED) {
        this.status = STATUS.ABORTED;
        reject({
          status: STATUS.ABORTED
        });
        return;
      }

      if (this.status === STATUS.DONE) {
        resolve();
        return;
      }

      const xhr = new XMLHttpRequest();
      this.requests[index] = xhr;

      this.registerEvents(index, xhr, params, resolve, reject);
      this.sendMessage(xhr);
      xhr.startDate = Date.now();
    });
  }

  /**
   * Register events for the XHR of the bandwidth test
   * @param {number} index
   * @param {XMLHttpRequest} xhr
   * @param {object} params
   * @param {function} resolve
   * @param {function} reject
   */
  registerEvents(index, xhr, params, resolve, reject) {
    xhr = this.initXHR(index, xhr, params);
    const xhrProgressHandler = this.step === 'upload' ? xhr.upload : xhr;
    xhrProgressHandler.onprogress = e => this.handleProgress(e, index, xhr, resolve, reject);
    xhr.addEventListener("load", e => this.handleLoad(e, xhr, params, resolve, reject));
    xhr.addEventListener("error", e => this.handleError(e, params, resolve, reject));
    xhr.addEventListener("timeout", e => this.handleTimeout(e, params, resolve, reject));
  }

  /**
   * Handle the XHR progress event
   * @param {Event} e
   * @param {number} index
   * @param {XMLHttpRequest} xhr
   * @param {function} resolve
   * @param {function} reject
   */
  handleProgress(e, index, xhr, resolve, reject) {
    if (xhr.readyState === XMLHttpRequest.DONE) return;

    if (this.test.status === STATUS.ABORTED) {
      this.status = STATUS.ABORTED;
      xhr.abort();
      reject({ status: STATUS.ABORTED });
      return;
    }

    if (this.status === STATUS.DONE) {
      xhr.abort();
      resolve();
      return;
    }

    this.loadDiff[index] = e.loaded - this.sizeLoaded[index];
    this.sizeLoaded[index] = e.loaded;
    if (this.status === STATUS.RUNNING) {
      this.size += this.loadDiff[index];
    }
    this.processResult();
  }

  /**
   * Handle the XHR load event
   * @param {Event} e
   * @param {XMLHttpRequest} xhr
   * @param {object} params
   * @param {function} resolve
   * @param {function} reject
   */
  handleLoad(e, xhr, params, resolve, reject) {
    const duration = Date.now() - xhr.startDate;
    if (this.test.config[this.step].adjustSize && e.laoded > 0 && duration < this.test.config[this.step].minDuration) {
      this.test.config[this.step].size = Math.min(
        Math.round(e.loaded / (duration / 1000)),
        this.test.config[this.step].maxSize
      );
    }
    this.runTest(params)
      .then(resolve)
      .catch(reject);
  }

  /**
   * Handle the XHR error event
   * @param {Event} e
   * @param {object} params
   * @param {function} resolve
   * @param {function} reject
   */
  handleError(e, params, resolve, reject) {
    if (this.test.config.ignoreErrors) {
      this.runTest(params)
        .then(resolve)
        .catch(reject);
      return;
    }

    reject({
      status: STATUS.FAILED,
      error: e.error,
      message: e.message
    });
  }

  /**
   * Handle the XHR timeout event
   * @param {Event} e
   * @param {XMLHttpRequest} xhr
   * @param {object} params
   * @param {function} resolve
   * @param {function} reject
   */
  handleTimeout(e, params, resolve, reject) {
    if (this.test.config[this.step].adjustSize) {
      this.test.config[this.step].size = Math.max(
        Math.round(e.loaded / (this.test.config[this.step].maxDuration / 1000)),
        this.test.config[this.step].minSize
      );
    }
    this.runTest(params)
      .then(resolve)
      .catch(reject);
  }

  /**
   * Process the bandwidth speed test result
   */
  processResult() {
    this.test.result[this.step] = {
      status: this.status,
      progress: 0
    };
    if (this.status <= STATUS.WAITING) return;

    const durationFromInit = Date.now() - this.initDate;
    const durationFromStart = Date.now() - this.startDate;
    const progress = durationFromInit / this.test.config[this.step].duration;
    this.test.result[this.step].progress = progress;
    if (this.status <= STATUS.STARTING) return;

    const { bitBandwidth: bandwidth } = Bandwidth.compute(
      this.size,
      durationFromStart / 1000,
      this.test.config.overheadCompensation
    );
    this.test.result[this.step].speed = +bandwidth.toFixed(2);
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Aura.ExportsModule = {
    "dispatchGlobalEvent": function (eventName, eventParams) {
        $A.clientService.setCurrentAccess($A.getRoot());
        try {
            $A.eventService.newEvent(eventName).setParams(eventParams).fire();
        } finally {
            $A.clientService.releaseCurrentAccess();
        }
    },

    "labels": function (obj) {
        return Object.keys(obj).reduce(function(r, cmpKey) {
            var key = obj[cmpKey];
            r[cmpKey] = $A.get('$Label.' + key);
            return r;
        }, {});
    },

    /**
     * Execute a global controller action.
     * @param {String} endpoint the controller and method to invoke.
     * @param {Object} params parameters to pass to the controller.
     * @return {Promise} promise that resolves when the action completes.
     */
    "executeGlobalController": function (endpoint, params) {
        var controllerName = 'c.aura://' + endpoint;
        var action = $A.get(controllerName);

        if (!action) {
            return Promise.reject(new Error('Controller for endpoint ' + endpoint + ' is not registered'));
        }
        action.setParams(params);

        return new Promise(function (resolve, reject) {
            action.setBackground();
            action.setCallback(null, function (response) {
                if (response.getState() !== 'SUCCESS') {
                    var actionErrors = response.getError();
                    if (actionErrors.length > 0) {
                        reject(actionErrors[0]);
                    } else {
                        reject(new Error('Error fetching component'));
                    }

                    return;
                }
                resolve(response.getReturnValue());
            });

            $A.run(function() { $A.enqueueAction(action); });
        });
    },

    "registerModule": function (module) {
        $A.componentService.initModuleDefs([module]);
        return module["descriptor"];
    },
    "hasModule": function(moduleName) {
        return $A.componentService.getComponentDef($A.componentService.createDescriptorConfig(moduleName));
    },
    "getModule": function(moduleName) {
        return $A.componentService.evaluateModuleDef(moduleName);
    },
    "sanitizeDOM": function (dirty, config) {
        return $A.util.sanitizeDOM(dirty, config);
    },
    "createComponent" : function (componentName, attributes, callback) {
        $A.clientService.setCurrentAccess($A.getRoot());
        try {
            $A.createComponent(componentName, attributes, $A.getCallback(callback));
        } finally {
            $A.clientService.releaseCurrentAccess();
        }
    }
};

Aura.ServiceApi = {
    "replaceModule": function (targetCtor, replacementCtor) {
        var targetDef;
        var replacementDef;

        Object.keys($A.componentService.moduleDefRegistry).some(function (key) {
            var def = $A.componentService.moduleDefRegistry[key];
            if (def.ns === targetCtor) {
                targetDef = def;
            } else if (def.ns === replacementCtor) {
                replacementDef = def;
            }
            return targetDef && replacementDef;
        });

        $A.assert(targetDef && replacementDef, 'Definitions could not be found');
        $A.assert(targetDef.access === replacementDef.access, 'Access checks do not match');
        $A.componentService.moduleDefRegistry[targetDef.moduleName] = replacementDef;
    }
};
<commit_msg>Wrap createComponent in $A.run (#1337)<commit_after>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Aura.ExportsModule = {
    "dispatchGlobalEvent": function (eventName, eventParams) {
        $A.clientService.setCurrentAccess($A.getRoot());
        try {
            $A.eventService.newEvent(eventName).setParams(eventParams).fire();
        } finally {
            $A.clientService.releaseCurrentAccess();
        }
    },

    "labels": function (obj) {
        return Object.keys(obj).reduce(function(r, cmpKey) {
            var key = obj[cmpKey];
            r[cmpKey] = $A.get('$Label.' + key);
            return r;
        }, {});
    },

    /**
     * Execute a global controller action.
     * @param {String} endpoint the controller and method to invoke.
     * @param {Object} params parameters to pass to the controller.
     * @return {Promise} promise that resolves when the action completes.
     */
    "executeGlobalController": function (endpoint, params) {
        var controllerName = 'c.aura://' + endpoint;
        var action = $A.get(controllerName);

        if (!action) {
            return Promise.reject(new Error('Controller for endpoint ' + endpoint + ' is not registered'));
        }
        action.setParams(params);

        return new Promise(function (resolve, reject) {
            action.setBackground();
            action.setCallback(null, function (response) {
                if (response.getState() !== 'SUCCESS') {
                    var actionErrors = response.getError();
                    if (actionErrors.length > 0) {
                        reject(actionErrors[0]);
                    } else {
                        reject(new Error('Error fetching component'));
                    }

                    return;
                }
                resolve(response.getReturnValue());
            });

            $A.run(function() { $A.enqueueAction(action); });
        });
    },

    "registerModule": function (module) {
        $A.componentService.initModuleDefs([module]);
        return module["descriptor"];
    },
    "hasModule": function(moduleName) {
        return $A.componentService.getComponentDef($A.componentService.createDescriptorConfig(moduleName));
    },
    "getModule": function(moduleName) {
        return $A.componentService.evaluateModuleDef(moduleName);
    },
    "sanitizeDOM": function (dirty, config) {
        return $A.util.sanitizeDOM(dirty, config);
    },
    "createComponent" : function (componentName, attributes, callback) {
        $A.clientService.setCurrentAccess($A.getRoot());
        try {
            $A.run(function() {
                $A.createComponent(componentName, attributes, $A.getCallback(callback));
            });
        } finally {
            $A.clientService.releaseCurrentAccess();
        }
    }
};

Aura.ServiceApi = {
    "replaceModule": function (targetCtor, replacementCtor) {
        var targetDef;
        var replacementDef;

        Object.keys($A.componentService.moduleDefRegistry).some(function (key) {
            var def = $A.componentService.moduleDefRegistry[key];
            if (def.ns === targetCtor) {
                targetDef = def;
            } else if (def.ns === replacementCtor) {
                replacementDef = def;
            }
            return targetDef && replacementDef;
        });

        $A.assert(targetDef && replacementDef, 'Definitions could not be found');
        $A.assert(targetDef.access === replacementDef.access, 'Access checks do not match');
        $A.componentService.moduleDefRegistry[targetDef.moduleName] = replacementDef;
    }
};
<|endoftext|>


<commit_before>/* eslint-disable no-console */
/* eslint-disable no-fallthrough */

(function() {

	mw.loader.using(['mediawiki.util']).done(function() {
		/* mediawiki.util */

		console.log("using User:Xiplus/global.js");

		/* 反importScript */
		var whitelist = ["Xiplus", "A2093064-test", "A2093064-bot"];
		if (whitelist.indexOf(mw.config.get('wgUserName')) === -1) {
			alert("請勿importScript User:Xiplus/global.js！可能有未預期的危害發生。");
			return;
		}

		// mw.loader.load('https://xiplus.ddns.net/Xiplus-zhWP/APIedit.js');
		mw.loader.load('https://meta.wikimedia.org/w/index.php?title=User:Xiplus/js/APIedit.js&action=raw&ctype=text/javascript');
		mw.loader.using(['mediawiki.util']).done(function() {
			mw.loader.load('https://en.wikipedia.org/w/index.php?title=MediaWiki:Gadget-ShowMessageNames.js&oldid=554722666&action=raw&ctype=text/javascript'); // 08:46, 5 August 2018 (UTC)
		});
		// [[File:Krinkle_CVNSimpleOverlay_wiki.js]]
		mw.loader.load('https://meta.wikimedia.org/w/index.php?title=User:Krinkle/Scripts/CVNSimpleOverlay_wiki.js&oldid=18174822&action=raw&ctype=text/javascript'); // 08:46, 5 August 2018 (UTC)
		mw.loader.load("https://zh.wikipedia.org/w/index.php?title=User:Bluedeck/serve/edit-count.js&oldid=49623399&action=raw&ctype=text/javascript"); // 08:46, 5 August 2018 (UTC)

		/* wikiplus */
		// mw.loader.load('https://xiplus.ddns.net/Xiplus-zhWP/w.js');
		mw.loader.load('https://wikiplus-app.com/Main.min.js');
		(function() {
			function wikiplusSettingdefaultSummary(w) {
				if (w.sectionNumber == -1) {
					return ' ';
				}
				if (w.sectionNumber == 0) {
					return '/* 首段 */ ';
				}
				return '/* ' + w.sectionName + ' */ ';
			}
			var wikiplusSetting = {
				"defaultSummary": wikiplusSettingdefaultSummary.toString().replace(/\s+/g, " "),
				"documatation": "http://zh.moegirl.org/User:%E5%A6%B9%E7%A9%BA%E9%85%B1/Wikiplus/%E8%AE%BE%E7%BD%AE%E8%AF%B4%E6%98%8E"
			};
			localStorage.setItem("Wikiplus_Settings", JSON.stringify(wikiplusSetting));
		})();

		/* XTools */
		mw.loader.load('https://www.mediawiki.org/w/index.php?title=XTools/ArticleInfo.js&oldid=2625658&action=raw&ctype=text/javascript'); // 08:46, 5 August 2018 (UTC)

		/* FakeRollback */
		if ($.inArray('sysop', mw.config.get('wgUserGroups')) === -1) {
			mw.loader.load('https://meta.wikimedia.org/w/index.php?title=User:WhitePhosphorus/js/FakeRollback.js&oldid=18757250&action=raw&ctype=text/javascript'); // 11:25, 4 January 2019 (UTC)
		}

		/* AutoUndo */
		if ($.inArray('sysop', mw.config.get('wgUserGroups')) === -1) {
			mw.loader.load('https://meta.wikimedia.org/w/index.php?title=User:Xiplus/js/AutoUndo.js&action=raw&ctype=text/javascript'); // 08:47, 5 August 2018 (UTC)
		}

		/* cvn-smart */
		// mw.loader.load('https://xiplus.ddns.net/wikipedia_rc/gadget.js');
		mw.loader.load('https://meta.wikimedia.org/w/index.php?title=User:Xiplus/js/cvn-smart-gadget.js&action=raw&ctype=text/javascript');

		/* history-merge */
		if ($.inArray('sysop', mw.config.get('wgUserGroups')) !== -1) {
			mw.loader.load('https://meta.wikimedia.org/w/index.php?title=User:Xiplus/js/history-merge.js&action=raw&ctype=text/javascript');
		}

		/* list-user-last-active */
		switch (mw.config.get('wgDBname')) {
			case 'zhwiki':
				break;
			default:
				mw.loader.load('https://meta.wikimedia.org/w/index.php?title=User:Xiplus/js/list-user-last-active.js&action=raw&ctype=text/javascript');
				break;
		}

		/* get-translatewiki-link */
		mw.loader.load('https://meta.wikimedia.org/w/index.php?title=User:Xiplus/js/get-translatewiki-link.js&action=raw&ctype=text/javascript');

		/* LinkToWikidata */
		if (mw.config.get('wgDBname').match(/^zhwik|enwiki/) && mw.config.get('wgDBname') != 'zhwiki') {
			mw.loader.load('https://xiplus.ddns.net/Xiplus-zhWP/LinkToWikidata.js');
		}

		/* UTC clock */
		mw.loader.load('//www.mediawiki.org/w/index.php?title=MediaWiki:Gadget-UTCLiveClock.js&action=raw&ctype=text/javascript');

		/* 頂欄 */
		document.all["pt-betafeatures"].hidden = true;
		document.all["pt-logout"].hidden = true;

		/* CentralAuth */
		function showCentralAuth(username) {
			if (username === undefined) {
				return;
			}
			if (mw.util.isIPAddress(username, true)) {
				username = username.replace(/\/\d+$/, '');
				mw.util.addPortletLink(
					'p-cactions',
					'https://tools.wmflabs.org/meta/stalktoy/' + username,
					'全域封禁'
				);
				mw.util.addPortletLink(
					'p-cactions',
					'https://whatismyipaddress.com/ip/' + username,
					'地理位置'
				);
				mw.util.addPortletLink(
					'p-cactions',
					'http://whois.tanet.edu.tw/showWhoisPublic.php?queryString=' + username,
					'TANet'
				);
				mw.util.addPortletLink(
					'p-cactions',
					'https://tools.wmflabs.org/ipcheck/index.php?ip=' + username,
					'Proxy Checker'
				);
			} else {
				mw.util.addPortletLink(
					'p-cactions',
					mw.config.get('wgServer') + mw.config.get('wgArticlePath').replace('$1', 'Special:CentralAuth') + '?target=' + encodeURIComponent(username),
					'全域帳號'
				);
			}
			mw.util.addPortletLink(
				'p-cactions',
				'https://tools.wmflabs.org/guc/?by=date&user=' + username,
				'全域貢獻'
			);
		}
		if (mw.config.get('wgNamespaceNumber') === 2 || mw.config.get('wgNamespaceNumber') === 3) {
			showCentralAuth(mw.config.get('wgTitle').replace(/^([^/]+).*$/, '$1'));
		} else if (mw.config.get('wgRelevantUserName') !== null) {
			showCentralAuth(mw.config.get('wgRelevantUserName'));
		} else if (mw.config.get('wgCanonicalSpecialPageName') === 'Contributions') {
			showCentralAuth($('[name="target"]').val());
		}

		/* Admin list */
		switch (mw.config.get('wgDBname')) {
			// case 'zh_classicalwiki':
			// case 'zh_yuewiki':
			case 'zhwiki':
				// case 'zhwikibooks':
				// case 'zhwikinews':
				// case 'zhwikiquote':
				// case 'zhwikisource':
				// case 'zhwikivoyage':
				// case 'zhwiktionary':
				break;
			default:
				mw.util.addPortletLink(
					'p-cactions',
					mw.config.get('wgServer') + mw.config.get('wgArticlePath').replace('$1', 'Special:Userlist') + '?group=sysop',
					'管理員列表'
				);
		}

		/* Twinkle */
		switch (mw.config.get('wgDBname')) {
			case 'enwiki':
			// case 'simplewiki':
			case 'zh_classicalwiki':
			case 'zhwiki':
			case 'zhwikibooks':
			// case 'zhwikinews':
			case 'zhwikiquote':
			// case 'zhwikisource':
			case 'zhwikiversity':
			case 'zhwikivoyage':
			case 'zhwiktionary':
				break;
			default:
				console.log("載入 Gadget-site-lib.js");
				mw.loader.load('//zh.wikipedia.org/w/index.php?title=MediaWiki:Gadget-site-lib.js&action=raw&ctype=text/javascript');
				console.log("測試版Twinkle");
				mw.loader.using(['mediawiki.user', 'mediawiki.util', 'mediawiki.RegExp', 'mediawiki.Title', 'jquery.ui.dialog', 'jquery.tipsy']).done(function() {
					console.log("Loading");
					mw.loader.load('//zh.wikipedia.org/w/index.php?title=User:Xiplus/Twinkle-dev.js&action=raw&ctype=text/javascript');
				});
				break;
		}

		/* Popup */
		switch (mw.config.get('wgDBname')) {
			case 'enwiki':
			case 'zhwiki':
				break;
			default:
				console.log("載入 A2569875Popup");
				mw.loader.load('//zh.wikipedia.org/w/index.php?title=User:A2569875-sandbox/MyPopupsSetting_zh-hant.js&action=raw&ctype=text/javascript');
				mw.loader.load('//zh.wikipedia.org/w/index.php?title=User:A2569875-sandbox/MyPopups.css&action=raw&ctype=text/css', 'text/css');
				break;
		}

		/* 側欄 */
		mw.util.addPortletLink(
			'p-tb',
			'/wiki/Special:PrefixIndex/' + mw.config.get('wgPageName'),
			'前綴索引',
			't-prefixindex',
			'',
			'',
			$('#t-specialpages')
		);

		mw.util.addPortletLink(
			'p-tb',
			'/wiki/?curid=' + mw.config.get('wgArticleId'),
			'短網址',
			't-shorturl',
			'',
			'',
			$('#t-info')
		);

		if (mw.config.get("wgNamespaceNumber") == 8) {
			mw.util.addPortletLink(
				'p-cactions',
				'https://translatewiki.net/wiki/' + mw.config.get("wgPageName").split("/")[0] + '/zh-hant?action=edit',
				'translatewiki'
			);
		}

		mw.loader.using(['mediawiki.api']).done(function() {
			new mw.Api().get({
				action: "query",
				format: "json",
				list: "logevents",
				leprop: "comment|type",
				letype: "delete",
				letitle: mw.config.get('wgPageName')
			}).then(function(data) {
				for (var i = 0; i < data.query.logevents.length; i++) {
					var comment = data.query.logevents[i].comment;
					console.log(comment);
				}
			});
		});

		/* mediawiki.util */
	});

	console.log("global.js end");

})();
<commit_msg>Update interface-global.js<commit_after>/* eslint-disable no-console */
/* eslint-disable no-fallthrough */

(function() {

	mw.loader.using(['mediawiki.util']).done(function() {
		/* mediawiki.util */

		console.log("using User:Xiplus/global.js");

		/* 反importScript */
		var whitelist = ["Xiplus", "A2093064-test", "A2093064-bot"];
		if (whitelist.indexOf(mw.config.get('wgUserName')) === -1) {
			alert("請勿importScript User:Xiplus/global.js！可能有未預期的危害發生。");
			return;
		}

		// mw.loader.load('https://xiplus.ddns.net/Xiplus-zhWP/APIedit.js');
		mw.loader.load('https://meta.wikimedia.org/w/index.php?title=User:Xiplus/js/APIedit.js&action=raw&ctype=text/javascript');
		mw.loader.using(['mediawiki.util']).done(function() {
			mw.loader.load('https://en.wikipedia.org/w/index.php?title=MediaWiki:Gadget-ShowMessageNames.js&oldid=554722666&action=raw&ctype=text/javascript'); // 08:46, 5 August 2018 (UTC)
		});
		// [[File:Krinkle_CVNSimpleOverlay_wiki.js]]
		mw.loader.load('https://meta.wikimedia.org/w/index.php?title=User:Krinkle/Scripts/CVNSimpleOverlay_wiki.js&oldid=18174822&action=raw&ctype=text/javascript'); // 08:46, 5 August 2018 (UTC)
		mw.loader.load("https://zh.wikipedia.org/w/index.php?title=User:Bluedeck/serve/edit-count.js&oldid=49623399&action=raw&ctype=text/javascript"); // 08:46, 5 August 2018 (UTC)
		mw.loader.load('//en.wikipedia.org/w/index.php?title=MediaWiki:Gadget-edittop.js&action=raw&ctype=text/javascript');

		/* wikiplus */
		// mw.loader.load('https://xiplus.ddns.net/Xiplus-zhWP/w.js');
		mw.loader.load('https://wikiplus-app.com/Main.min.js');
		(function() {
			function wikiplusSettingdefaultSummary(w) {
				if (w.sectionNumber == -1) {
					return ' ';
				}
				if (w.sectionNumber == 0) {
					return '/* 首段 */ ';
				}
				return '/* ' + w.sectionName + ' */ ';
			}
			var wikiplusSetting = {
				"defaultSummary": wikiplusSettingdefaultSummary.toString().replace(/\s+/g, " "),
				"documatation": "http://zh.moegirl.org/User:%E5%A6%B9%E7%A9%BA%E9%85%B1/Wikiplus/%E8%AE%BE%E7%BD%AE%E8%AF%B4%E6%98%8E"
			};
			localStorage.setItem("Wikiplus_Settings", JSON.stringify(wikiplusSetting));
		})();

		/* XTools */
		mw.loader.load('https://www.mediawiki.org/w/index.php?title=XTools/ArticleInfo.js&oldid=2625658&action=raw&ctype=text/javascript'); // 08:46, 5 August 2018 (UTC)

		/* FakeRollback */
		if ($.inArray('sysop', mw.config.get('wgUserGroups')) === -1) {
			mw.loader.load('https://meta.wikimedia.org/w/index.php?title=User:WhitePhosphorus/js/FakeRollback.js&action=raw&ctype=text/javascript');
		}

		/* AutoUndo */
		if ($.inArray('sysop', mw.config.get('wgUserGroups')) === -1) {
			mw.loader.load('https://meta.wikimedia.org/w/index.php?title=User:WhitePhosphorus/js/AutoUndo.js&action=raw&ctype=text/javascript');
		}

		/* cvn-smart */
		// mw.loader.load('https://xiplus.ddns.net/wikipedia_rc/gadget.js');
		mw.loader.load('https://meta.wikimedia.org/w/index.php?title=User:Xiplus/js/cvn-smart-gadget.js&action=raw&ctype=text/javascript');

		/* history-merge */
		if ($.inArray('sysop', mw.config.get('wgUserGroups')) !== -1) {
			mw.loader.load('https://meta.wikimedia.org/w/index.php?title=User:Xiplus/js/history-merge.js&action=raw&ctype=text/javascript');
		}

		/* list-user-last-active */
		switch (mw.config.get('wgDBname')) {
			case 'zhwiki':
				break;
			default:
				mw.loader.load('https://meta.wikimedia.org/w/index.php?title=User:Xiplus/js/list-user-last-active.js&action=raw&ctype=text/javascript');
				break;
		}

		/* smart rollback */
		if(typeof(smartRollbackConfig) === 'undefined') smartRollbackConfig = {};
		smartRollbackConfig.toolLinkMethod = 'p-tb';
		smartRollbackConfig.editSummaries = ['批量回退無意義文字', '批量回退破壞'];
		mw.loader.load('//meta.wikimedia.org/w/index.php?title=User:Hoo_man/smart_rollback.js&action=raw&ctype=text/javascript');

		/* get-translatewiki-link */
		mw.loader.load('https://meta.wikimedia.org/w/index.php?title=User:Xiplus/js/get-translatewiki-link.js&action=raw&ctype=text/javascript');

		/* LinkToWikidata */
		if (mw.config.get('wgDBname').match(/^zhwik|enwiki/) && mw.config.get('wgDBname') != 'zhwiki') {
			mw.loader.load('https://xiplus.ddns.net/Xiplus-zhWP/LinkToWikidata.js');
		}

		/* UTC clock */
		mw.loader.load('//www.mediawiki.org/w/index.php?title=MediaWiki:Gadget-UTCLiveClock.js&action=raw&ctype=text/javascript');

		/* 頂欄 */
		document.all["pt-betafeatures"].hidden = true;
		document.all["pt-logout"].hidden = true;

		/* CentralAuth */
		function showCentralAuth(username) {
			if (username === undefined) {
				return;
			}
			if (mw.util.isIPAddress(username, true)) {
				username = username.replace(/\/\d+$/, '');
				mw.util.addPortletLink(
					'p-cactions',
					'https://tools.wmflabs.org/meta/stalktoy/' + username,
					'全域封禁'
				);
				mw.util.addPortletLink(
					'p-cactions',
					'https://whatismyipaddress.com/ip/' + username,
					'地理位置'
				);
				mw.util.addPortletLink(
					'p-cactions',
					'http://whois.tanet.edu.tw/showWhoisPublic.php?queryString=' + username,
					'TANet'
				);
				mw.util.addPortletLink(
					'p-cactions',
					'https://tools.wmflabs.org/ipcheck/index.php?ip=' + username,
					'Proxy Checker'
				);
			} else {
				mw.util.addPortletLink(
					'p-cactions',
					mw.config.get('wgServer') + mw.config.get('wgArticlePath').replace('$1', 'Special:CentralAuth') + '?target=' + encodeURIComponent(username),
					'全域帳號'
				);
			}
			mw.util.addPortletLink(
				'p-cactions',
				'https://tools.wmflabs.org/guc/?by=date&user=' + username,
				'全域貢獻'
			);
		}
		if (mw.config.get('wgNamespaceNumber') === 2 || mw.config.get('wgNamespaceNumber') === 3) {
			showCentralAuth(mw.config.get('wgTitle').replace(/^([^/]+).*$/, '$1'));
		} else if (mw.config.get('wgRelevantUserName') !== null) {
			showCentralAuth(mw.config.get('wgRelevantUserName'));
		} else if (mw.config.get('wgCanonicalSpecialPageName') === 'Contributions') {
			showCentralAuth($('[name="target"]').val());
		}

		/* Admin list */
		switch (mw.config.get('wgDBname')) {
			// case 'zh_classicalwiki':
			// case 'zh_yuewiki':
			case 'zhwiki':
				// case 'zhwikibooks':
				// case 'zhwikinews':
				// case 'zhwikiquote':
				// case 'zhwikisource':
				// case 'zhwikivoyage':
				// case 'zhwiktionary':
				break;
			default:
				mw.util.addPortletLink(
					'p-cactions',
					mw.config.get('wgServer') + mw.config.get('wgArticlePath').replace('$1', 'Special:Userlist') + '?group=sysop',
					'管理員列表'
				);
		}

		/* Twinkle */
		switch (mw.config.get('wgDBname')) {
			case 'enwiki':
			// case 'simplewiki':
			case 'zh_classicalwiki':
			case 'zhwiki':
			case 'zhwikibooks':
			// case 'zhwikinews':
			case 'zhwikiquote':
			// case 'zhwikisource':
			case 'zhwikiversity':
			case 'zhwikivoyage':
			case 'zhwiktionary':
				break;
			default:
				console.log("載入 Gadget-site-lib.js");
				mw.loader.load('//zh.wikipedia.org/w/index.php?title=MediaWiki:Gadget-site-lib.js&action=raw&ctype=text/javascript');
				console.log("測試版Twinkle");
				mw.loader.using(['mediawiki.user', 'mediawiki.util', 'mediawiki.RegExp', 'mediawiki.Title', 'jquery.ui.dialog', 'jquery.tipsy']).done(function() {
					console.log("Loading");
					mw.loader.load('//zh.wikipedia.org/w/index.php?title=User:Xiplus/Twinkle-dev.js&action=raw&ctype=text/javascript');
				});
				break;
		}

		/* Popup */
		switch (mw.config.get('wgDBname')) {
			case 'enwiki':
			case 'zhwiki':
				break;
			default:
				console.log("載入 A2569875Popup");
				mw.loader.load('//zh.wikipedia.org/w/index.php?title=User:A2569875-sandbox/MyPopupsSetting_zh-hant.js&action=raw&ctype=text/javascript');
				mw.loader.load('//zh.wikipedia.org/w/index.php?title=User:A2569875-sandbox/MyPopups.css&action=raw&ctype=text/css', 'text/css');
				break;
		}

		/* 側欄 */
		mw.util.addPortletLink(
			'p-tb',
			'/wiki/Special:PrefixIndex/' + mw.config.get('wgPageName'),
			'前綴索引',
			't-prefixindex',
			'',
			'',
			$('#t-specialpages')
		);

		mw.util.addPortletLink(
			'p-tb',
			'/wiki/?curid=' + mw.config.get('wgArticleId'),
			'短網址',
			't-shorturl',
			'',
			'',
			$('#t-info')
		);

		if (mw.config.get("wgNamespaceNumber") == 8) {
			mw.util.addPortletLink(
				'p-cactions',
				'https://translatewiki.net/wiki/' + mw.config.get("wgPageName").split("/")[0] + '/zh-hant?action=edit',
				'translatewiki'
			);
		}

		mw.loader.using(['mediawiki.api']).done(function() {
			new mw.Api().get({
				action: "query",
				format: "json",
				list: "logevents",
				leprop: "comment|type",
				letype: "delete",
				letitle: mw.config.get('wgPageName')
			}).then(function(data) {
				for (var i = 0; i < data.query.logevents.length; i++) {
					var comment = data.query.logevents[i].comment;
					console.log(comment);
				}
			});
		});

		/* mediawiki.util */
	});

	console.log("global.js end");

})();<|endoftext|>


<commit_before>var mongoose = require('mongoose');
//var Email = mongoose.SchemaTypes.Email;

//Define the Database schema for "users" collection
var UserSchema = new mongoose.Schema({
  username: {
	  type: String,
	  unique: true,
	  required: true,
	  // trim removes empty spaces
	  trim: true
  },
  passwort: {
	  type: String,
	  required: true,
	  trim: true
  },
  email: {
	  type: text,
	  unique: true,
	  required: true,
	  trim: true
  },
  country: String,
  occupation: String,
  type: String,
  upvotes: { type: Number, default: 0},
  downvotes: { type: Number, default: 0},
  help: { type: Boolean, default: 0 },
  //Comments created by the user
  comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }],
});

//mongoose.model('User', UserSchema);
module.exports = mongoose.model("User", UserSchema);

<commit_msg>Update user-model.js<commit_after>var mongoose = require('mongoose');
//var Email = mongoose.SchemaTypes.Email;

//Define the Database schema for "users" collection
var UserSchema = new mongoose.Schema({
  username: {
	  type: String,
	  unique: true,
	  required: true,
	  // trim removes empty spaces
	  trim: true
  },
  passwort: {
	  type: String,
	  required: true,
	  trim: true
  },
  email: {
	  type: String,
	  unique: true,
	  required: true,
	  trim: true
  },
  country: String,
  occupation: String,
  type: String,
  upvotes: { type: Number, default: 0},
  downvotes: { type: Number, default: 0},
  help: { type: Boolean, default: 0 },
  //Comments created by the user
  comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }],
});

//mongoose.model('User', UserSchema);
module.exports = mongoose.model("User", UserSchema);

<|endoftext|>


<commit_before>var Backbone = require('backbone');
var _ = require('underscore');
var syncAbort = require('./backbone/sync-abort');

/**
 * State definition model.
 * Used to persist the dashboard state at any time
 */
module.exports = Backbone.Model.extend({

  /**
   * @override {Backbone.prototype.sync} abort ongoing request if there is any
   */
  sync: syncAbort,

  urlRoot: function () {
    return this._visDefinitionModel.stateURL();
  },

  idAttribute: '_fakeID',

  isNew: function () {
    return false;
  },

  initialize: function (attrs, opts) {
    if (!attrs.json) throw new Error('state json is required');
    if (!opts.visDefinitionModel) throw new Error('visDefinitionModel is required');
    if (!opts.dashboard) throw new Error('dashboard is required');

    this._visDefinitionModel = opts.visDefinitionModel;
    this._dashboard = opts.dashboard;

    this.set('_fakeID', '');

    this._initBinds();
  },

  toJSON: function () {
    return {
      json: this.get('json')
    };
  },

  _initBinds: function () {
    /*
     * TODO: Disabled widget states until issues are fixed.
     * See https://github.com/CartoDB/deep-insights.js/issues/416
     */
    // this._dashboard._dashboard.widgets._widgetsCollection.bind('change', _.debounce(this._updateState, 10), this);
    this._dashboard._dashboard.vis.map.bind('change', _.debounce(this._updateState, 250), this);
  },

  _updateState: function () {
    this.set('json', this._dashboard.getState());
    this.save();
  }
});
<commit_msg>find better way than fake id<commit_after>var Backbone = require('backbone');
var _ = require('underscore');
var syncAbort = require('./backbone/sync-abort');

/**
 * State definition model.
 * Used to persist the dashboard state at any time
 */
module.exports = Backbone.Model.extend({

  /**
   * @override {Backbone.prototype.sync} abort ongoing request if there is any
   */
  sync: syncAbort,

  url: function () {
    return this._visDefinitionModel.stateURL();
  },

  isNew: function () {
    return false;
  },

  initialize: function (attrs, opts) {
    if (!attrs.json) throw new Error('state json is required');
    if (!opts.visDefinitionModel) throw new Error('visDefinitionModel is required');
    if (!opts.dashboard) throw new Error('dashboard is required');

    this._visDefinitionModel = opts.visDefinitionModel;
    this._dashboard = opts.dashboard;

    this._initBinds();
  },

  toJSON: function () {
    return {
      json: this.get('json')
    };
  },

  _initBinds: function () {
    /*
     * TODO: Disabled widget states until issues are fixed.
     * See https://github.com/CartoDB/deep-insights.js/issues/416
     */
    // this._dashboard._dashboard.widgets._widgetsCollection.bind('change', _.debounce(this._updateState, 10), this);
    this._dashboard._dashboard.vis.map.bind('change', _.debounce(this._updateState, 250), this);
  },

  _updateState: function () {
    this.set('json', this._dashboard.getState());
    this.save();
  }
});
<|endoftext|>


<commit_before>import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { useParams, useRouteMatch } from 'react-router-dom';
import queryString from 'query-string';
import { Helmet } from 'react-helmet';
import { loader } from 'graphql.macro';
import { useQuery } from '@apollo/client';

import PageLayout from '../components/PageLayout';
import LooMap from '../components/LooMap';
import useMapPosition from '../components/useMapPosition';
import useNearbyLoos from '../components/useNearbyLoos';
import Box from '../components/Box';
import ToiletDetailsPanel from '../components/ToiletDetailsPanel';
import Sidebar from '../components/Sidebar';
import Notification from '../components/Notification';
import VisuallyHidden from '../components/VisuallyHidden';

import config, { FILTERS_KEY } from '../config';

const FIND_BY_ID = loader('./findLooById.graphql');

const HomePage = ({ initialPosition, ...props }) => {
  const [mapPosition, setMapPosition] = useMapPosition(config.fallbackLocation);

  let initialState = config.getSettings(FILTERS_KEY);

  // default any unsaved filters as 'false'
  config.filters.forEach((filter) => {
    initialState[filter.id] = initialState[filter.id] || false;
  });

  const [filters, setFilters] = useState(initialState);

  // keep local storage and state in sync
  React.useEffect(() => {
    window.localStorage.setItem(FILTERS_KEY, JSON.stringify(filters));
  }, [filters]);

  const { data: toiletData } = useNearbyLoos({
    variables: {
      lat: mapPosition.center.lat,
      lng: mapPosition.center.lng,
      radius: Math.ceil(mapPosition.radius),
    },
  });

  const selectedLooId = useParams().id;

  const { data, loading } = useQuery(FIND_BY_ID, {
    variables: {
      id: selectedLooId,
      skip: !selectedLooId,
    },
  });

  const { message } = queryString.parse(props.location.search);

  // get the filter objects from config for the filters applied by the user
  const applied = config.filters.filter((filter) => filters[filter.id]);

  // restrict the results to only those toilets which pass all of our filter requirements
  const toilets = toiletData.filter((toilet) =>
    applied.every((filter) => {
      const value = toilet[filter.id];

      if (value === null) {
        return false;
      }

      return !!value;
    })
  );

  const isLooPage = useRouteMatch('/loos/:id');

  const [shouldCenter, setShouldCenter] = React.useState(isLooPage);

  // set initial map center to toilet if on /loos/:id
  React.useEffect(() => {
    if (shouldCenter && data) {
      setMapPosition({
        center: data.loo.location,
      });

      // don't recenter the map each time the id changes
      setShouldCenter(false);
    }
  }, [data, shouldCenter, setMapPosition]);

  // set the map position if initialPosition prop exists
  React.useEffect(() => {
    if (initialPosition) {
      setMapPosition({
        center: initialPosition,
      });
    }
  }, [initialPosition, setMapPosition]);

  const [toiletPanelDimensions, setToiletPanelDimensions] = React.useState({});

  const pageTitle = config.getTitle(
    isLooPage && data ? data.loo.name || 'Unnamed Toilet' : 'Find Toilet'
  );

  return (
    <PageLayout mapCenter={mapPosition.center}>
      <Helmet>
        <title>{pageTitle}</title>
      </Helmet>

      <VisuallyHidden>

{pageTitle}

      </VisuallyHidden>

      <Box height="100%" display="flex" position="relative">
        <Box
          position="absolute"
          zIndex={1}
          top={0}
          left={[0, 3]}
          right={0}
          bottom={0}
          m={3}
          maxWidth={326}
          maxHeight="100%"
          overflowY="auto"
          // center on small viewports
          mx={['auto', 0]}
        >
          <Sidebar
            filters={filters}
            onFilterChange={setFilters}
            onSelectedItemChange={(center) => setMapPosition({ center })}
            onUpdateMapPosition={setMapPosition}
            mapCenter={mapPosition.center}
          />
        </Box>

        <LooMap
          loos={toilets.map((toilet) => {
            if (toilet.id === selectedLooId) {
              return {
                ...toilet,
                isHighlighted: true,
              };
            }
            return toilet;
          })}
          center={mapPosition.center}
          zoom={mapPosition.zoom}
          onViewportChanged={setMapPosition}
          controlsOffset={toiletPanelDimensions.height}
        />

        {Boolean(selectedLooId) && data && (
          <Box
            position="absolute"
            left={0}
            bottom={0}
            width="100%"
            zIndex={100}
          >
            <ToiletDetailsPanel
              data={data.loo}
              isLoading={loading}
              startExpanded={!!message}
              onDimensionsChange={setToiletPanelDimensions}
            >
              {config.messages[message] && (
                <Box
                  position="absolute"
                  left={0}
                  right={0}
                  bottom={0}
                  display="flex"
                  justifyContent="center"
                  p={4}
                  pt={1}
                  pb={[4, 3, 4]}
                  bg={['white', 'white', 'transparent']}
                >
                  <Notification
                    allowClose
                    children={config.messages[message]}
                  />
                </Box>
              )}
            </ToiletDetailsPanel>
          </Box>
        )}
      </Box>
    </PageLayout>
  );
};

HomePage.propTypes = {
  initialPosition: PropTypes.shape({
    lat: PropTypes.number,
    lng: PropTypes.number,
  }),
};

export default HomePage;
<commit_msg>fix: skip find loo by id query<commit_after>import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { useParams, useRouteMatch } from 'react-router-dom';
import queryString from 'query-string';
import { Helmet } from 'react-helmet';
import { loader } from 'graphql.macro';
import { useQuery } from '@apollo/client';

import PageLayout from '../components/PageLayout';
import LooMap from '../components/LooMap';
import useMapPosition from '../components/useMapPosition';
import useNearbyLoos from '../components/useNearbyLoos';
import Box from '../components/Box';
import ToiletDetailsPanel from '../components/ToiletDetailsPanel';
import Sidebar from '../components/Sidebar';
import Notification from '../components/Notification';
import VisuallyHidden from '../components/VisuallyHidden';

import config, { FILTERS_KEY } from '../config';

const FIND_BY_ID = loader('./findLooById.graphql');

const HomePage = ({ initialPosition, ...props }) => {
  const [mapPosition, setMapPosition] = useMapPosition(config.fallbackLocation);

  let initialState = config.getSettings(FILTERS_KEY);

  // default any unsaved filters as 'false'
  config.filters.forEach((filter) => {
    initialState[filter.id] = initialState[filter.id] || false;
  });

  const [filters, setFilters] = useState(initialState);

  // keep local storage and state in sync
  React.useEffect(() => {
    window.localStorage.setItem(FILTERS_KEY, JSON.stringify(filters));
  }, [filters]);

  const { data: toiletData } = useNearbyLoos({
    variables: {
      lat: mapPosition.center.lat,
      lng: mapPosition.center.lng,
      radius: Math.ceil(mapPosition.radius),
    },
  });

  const selectedLooId = useParams().id;

  const { data, loading } = useQuery(FIND_BY_ID, {
    skip: !selectedLooId,
    variables: {
      id: selectedLooId,
    },
  });

  const { message } = queryString.parse(props.location.search);

  // get the filter objects from config for the filters applied by the user
  const applied = config.filters.filter((filter) => filters[filter.id]);

  // restrict the results to only those toilets which pass all of our filter requirements
  const toilets = toiletData.filter((toilet) =>
    applied.every((filter) => {
      const value = toilet[filter.id];

      if (value === null) {
        return false;
      }

      return !!value;
    })
  );

  const isLooPage = useRouteMatch('/loos/:id');

  const [shouldCenter, setShouldCenter] = React.useState(isLooPage);

  // set initial map center to toilet if on /loos/:id
  React.useEffect(() => {
    if (shouldCenter && data) {
      setMapPosition({
        center: data.loo.location,
      });

      // don't recenter the map each time the id changes
      setShouldCenter(false);
    }
  }, [data, shouldCenter, setMapPosition]);

  // set the map position if initialPosition prop exists
  React.useEffect(() => {
    if (initialPosition) {
      setMapPosition({
        center: initialPosition,
      });
    }
  }, [initialPosition, setMapPosition]);

  const [toiletPanelDimensions, setToiletPanelDimensions] = React.useState({});

  const pageTitle = config.getTitle(
    isLooPage && data ? data.loo.name || 'Unnamed Toilet' : 'Find Toilet'
  );

  return (
    <PageLayout mapCenter={mapPosition.center}>
      <Helmet>
        <title>{pageTitle}</title>
      </Helmet>

      <VisuallyHidden>

{pageTitle}

      </VisuallyHidden>

      <Box height="100%" display="flex" position="relative">
        <Box
          position="absolute"
          zIndex={1}
          top={0}
          left={[0, 3]}
          right={0}
          bottom={0}
          m={3}
          maxWidth={326}
          maxHeight="100%"
          overflowY="auto"
          // center on small viewports
          mx={['auto', 0]}
        >
          <Sidebar
            filters={filters}
            onFilterChange={setFilters}
            onSelectedItemChange={(center) => setMapPosition({ center })}
            onUpdateMapPosition={setMapPosition}
            mapCenter={mapPosition.center}
          />
        </Box>

        <LooMap
          loos={toilets.map((toilet) => {
            if (toilet.id === selectedLooId) {
              return {
                ...toilet,
                isHighlighted: true,
              };
            }
            return toilet;
          })}
          center={mapPosition.center}
          zoom={mapPosition.zoom}
          onViewportChanged={setMapPosition}
          controlsOffset={toiletPanelDimensions.height}
        />

        {Boolean(selectedLooId) && data && (
          <Box
            position="absolute"
            left={0}
            bottom={0}
            width="100%"
            zIndex={100}
          >
            <ToiletDetailsPanel
              data={data.loo}
              isLoading={loading}
              startExpanded={!!message}
              onDimensionsChange={setToiletPanelDimensions}
            >
              {config.messages[message] && (
                <Box
                  position="absolute"
                  left={0}
                  right={0}
                  bottom={0}
                  display="flex"
                  justifyContent="center"
                  p={4}
                  pt={1}
                  pb={[4, 3, 4]}
                  bg={['white', 'white', 'transparent']}
                >
                  <Notification
                    allowClose
                    children={config.messages[message]}
                  />
                </Box>
              )}
            </ToiletDetailsPanel>
          </Box>
        )}
      </Box>
    </PageLayout>
  );
};

HomePage.propTypes = {
  initialPosition: PropTypes.shape({
    lat: PropTypes.number,
    lng: PropTypes.number,
  }),
};

export default HomePage;
<|endoftext|>