<commit_before>/* jslint browser: true */

/* global CodeMirror, performance*/

// WUI - https://github.com/grz0zrg/wui
/*#include wui/wui.js*/

// CodeMirror - https://codemirror.net/
/*#include codemirror/codemirror.js*/
/*#include codemirror/addon/search/searchcursor.js*/
/*#include codemirror/addon/search/match-highlighter.js*/
/*#include codemirror/addon/search/matchesonscrollbar.js*/
/*#include codemirror/addon/edit/closebrackets.js*/
/*#include codemirror/addon/edit/matchbrackets.js*/
/*#include codemirror/addon/scroll/simplescrollbars.js*/
/*#include codemirror/addon/scroll/annotatescrollbar.js*/
/*#include codemirror/addon/selection/active-line.js*/
/*#include codemirror/codemirror_glsl.js*/

// sharedb - https://github.com/share/sharedb
/*#include sharedb/sharedb.js*/
/*#include sharedb/ot-text.js*/

/*#include resize_throttler/resize_throttler.js*/

window.onload = function() {
var FragmentSynth = new (function () {
    "use strict";

    /***********************************************************
        Globals.
    ************************************************************/

    /*#include notification.js*/

    var _getSessionName = function () {
        var url_parts = window.location.pathname.split('/');

        return url_parts[url_parts.length - 1];
    };

    window.performance = window.performance || {};
    performance.now = (function() {
      return performance.now       ||
             performance.mozNow    ||
             performance.msNow     ||
             performance.oNow      ||
             performance.webkitNow ||
             function() { return new Date().getTime(); };
    })();

    window.AudioContext = window.AudioContext || window.webkitAudioContext || false;

    window.requestAnimationFrame =  window.requestAnimationFrame || window.mozRequestAnimationFrame ||
                                    window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
    window.cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame;

    if (!window.AudioContext) {
        _fail("The Web Audio API is not available, please use a Web Audio capable browser.", true);

        return;
    }

    if (!window.cancelAnimationFrame) {
        _fail("The cancelAnimationFrame function is not available, please use a web browser with cancelAnimationFrame support.", true);

        return;
    }

    if (!window.localStorage) {
        _fail("The localStorage API is not available, please use a web browser with localStorage support.", true);

        return;
    }

    if (!window.FileReader) {
        _fail("FileReader API is not available, please use a web browser with FileReader support.", true);

        return;
    }

    if (!window.Blob) {
        _fail("Blob API is not available, please use a web browser with Blob support.", true);

        return;
    }

    if (!window.File) {
        _fail("File API is not available, please use a web browser with File API support.", true);

        return;
    }

    if (typeof(Worker) === "undefined") {
        _fail("Web Workers are not available, please use a web browser with Web Workers support.", true);

        return;
    }

    /***********************************************************
        Fields.
    ************************************************************/

    var _fs_state = 1,

        _username = localStorage.getItem('fs-user-name'),
        _local_session_settings = localStorage.getItem(_getSessionName()),

        _red_curtain_element = document.getElementById("fs_red_curtain"),
        _user_name_element = document.getElementById("fs_user_name"),
        _time_infos = document.getElementById("fs_time_infos"),
        _hz_infos = document.getElementById("fs_hz_infos"),
        _xy_infos = document.getElementById("fs_xy_infos"),

        _haxis_infos = document.getElementById("fs_haxis_infos"),
        _vaxis_infos = document.getElementById("fs_vaxis_infos"),

        _canvas_container = document.getElementById("canvas_container"),
        _canvas = document.createElement("canvas"),

        _canvas_width  = 1024,
        _canvas_height = 439,//Math.round(window.innerHeight / 2) - 68,

        _canvas_width_m1 = _canvas_width - 1,
        _canvas_height_mul4 = _canvas_height * 4,

        _render_width = _canvas_width,
        _render_height = _canvas_height,

        _code_editor,
        _code_editor_element = document.getElementById("code"),
        _code_editor_theme = localStorage.getItem('fs-editor-theme'),
        _code_editor_theme_link,
        _code_editor_highlight = {
                showToken: /\w/,
                annotateScrollbar: true
            },
        _code_editor_settings = {
            value: "",
            theme: ((_code_editor_theme === null) ? "seti" : _code_editor_theme),
            matchBrackets: true,
            //autoCloseBrackets: true,
            lineNumbers: true,
            styleActiveLine: true,
            scrollbarStyle: "native",
            mode: "text/x-glsl"
        },

        _compile_timer,

        _undock_code_editor = false,

        _xyf_grid = false,

        _glsl_error = false,

        // settings
        _show_globaltime = false,
        _cm_highlight_matches = false,
        _cm_show_linenumbers = true,
        _cm_advanced_scrollbar = false,

        // mouse cursor over canvas
        _cx,
        _cy,

        _mx,
        _my,

        _nmx,
        _nmy,

        _cnmx,
        _cnmy,

        _mouse_btn = 0,

        _LEFT_MOUSE_BTN = 1,
        _RIGHT_MOUSE_BTN = 2,

        _fps = 60,

        _raf,

        _gl,

        _play_position_markers = [],

        _webgl_opts = {
                preserveDrawingBuffer: true
            },

        _prev_data = new Uint8Array(_canvas_height_mul4),
        _data = new Uint8Array(_canvas_height_mul4),
        _temp_data = new Uint8Array(_canvas_height_mul4),

        _midi_out_f,
        _midi_out = true,

        _quad_vertex_buffer,

        _program,

        _controls = {},

        _fragment_input_data = [],

        _input_panel_element = document.getElementById("fs_input_panel"),

        _codemirror_line_widgets = [],

        _time = 0,

        _pause_time = 0,

        _hover_freq = null,

        _input_channel_prefix = "iInput";

    /***********************************************************
        App. Includes.
    ************************************************************/

    /*#include config.js*/
    /*#include tools.js*/
    /*#include audio.js*/
    /*#include graphics.js*/
    /*#include glsl.js*/
    /*#include network.js*/
    /*#include discuss.js*/
    /*#include inputs.js*/
    /*#include editor.js*/
    /*#include transports.js*/
    /*#include ui.js*/
    /*#include fas.js*/

    /***********************************************************
        Functions.
    ************************************************************/

    var _updateScore = function (update_obj, update) {
        var prev_base_freq = _audio_infos.base_freq,
            prev_octave = _audio_infos.octaves,

            base_freq = _audio_infos.base_freq,
            octave = _audio_infos.octaves,

            prev_width = _canvas_width,
            prev_height = _canvas_height;

        if (update_obj["base_freq"] !== undefined) {
            base_freq = update_obj.base_freq;
        }

        if (update_obj["octave"] !== undefined) {
            octave = update_obj.octave;
        }

        _disableNotesProcessing();

        if (update_obj.height) {
            _canvas_height = update_obj.height;
            _canvas.height = _canvas_height;
            _canvas.style.height = _canvas_height + 'px';
            _canvas_height_mul4 = _canvas_height * 4;

            _vaxis_infos.style.height = _canvas_height + "px";

            _prev_data = new Uint8Array(_canvas_height_mul4);
            _data = new Uint8Array(_canvas_height_mul4);
            _temp_data = new Uint8Array(_canvas_height_mul4);

            _gl.viewport(0, 0, _canvas.width, _canvas.height);

            _updatePlayMarkersHeight(_canvas_height);
        }

        if (update_obj.width) {
            _canvas_width = update_obj.width;
            _canvas.width = _canvas_width;
            _canvas.style.width = _canvas_width + 'px';

            _gl.viewport(0, 0, _canvas.width, _canvas.height);
        }

        _generateOscillatorSet(_canvas_height, base_freq, octave);

        _compile();

        _updateCodeView();

        _updateAllPlayPosition();

        _fasNotify(_FAS_AUDIO_INFOS, _audio_infos);

        _enableNotesProcessing();

        WUI_RangeSlider.setValue("fs_score_width_input", _canvas_width);
        WUI_RangeSlider.setValue("fs_score_height_input", _canvas_height);
        WUI_RangeSlider.setValue("fs_score_octave_input", octave);
        WUI_RangeSlider.setValue("fs_score_base_input", base_freq);

        if (update) {
            _shareSettingsUpd([
                    prev_width, _canvas_width,
                    prev_height, _canvas_height,
                    prev_octave, octave,
                    prev_base_freq, base_freq
                ]);
        }
    };

    /***********************************************************
        Init.
    ************************************************************/

    _audioInit();

    if (!_username) {
        _username = "Anonymous";
    }

    _user_name_element.innerHTML = _username;

    //_canvas_width = _getElementOffset(_canvas_container).width;

    _render_width = _canvas_width;

    _canvas.width  = _render_width;
    _canvas.height = _render_height;

    _canvas.style.width  = _canvas_width  + 'px';
    _canvas.style.height = _canvas_height + 'px';

    _canvas_container.appendChild(_canvas);

    _vaxis_infos.style.height = _canvas_height + "px";

    // CodeMirror
    if (!_code_editor_theme) {
        _code_editor_theme = "seti";
    }

    _changeEditorTheme(_code_editor_theme);

    _code_editor = new CodeMirror(_code_editor_element, _code_editor_settings);
    _code_editor.setValue(document.getElementById("fragment-shader").text);

    CodeMirror.on(_code_editor, 'change', function (instance, change_obj) {
        clearTimeout(_compile_timer);
        _compile_timer = setTimeout(_compile, 500);
    });

    CodeMirror.on(_code_editor, 'changes', function (instance, changes) {
        _shareCodeEditorChanges(changes);
    });

    // WebGL
    _gl = _canvas.getContext("webgl", _webgl_opts) || _canvas.getContext("experimental-webgl", _webgl_opts);

    if (!_gl) {
        _fail("The WebGL API is not available, please try with a WebGL ready browser.", true);

        return;
    }

    _buildScreenAlignedQuad();

    _gl.viewport(0, 0, _canvas.width, _canvas.height);

    _compile();

    // setup user last settings for this session if any
    if (_local_session_settings) {
        _local_session_settings = JSON.parse(_local_session_settings);
        if ('gain' in _local_session_settings) {
            _volume = _local_session_settings.gain;

            WUI_RangeSlider.setValue("mst_slider", _volume, true);
        }
    } else {
        _local_session_settings = {
            gain: _volume,
        };
    }

    //_addPlayPositionMarker(_canvas_width / 4);
    //_addPlayPositionMarker(_canvas_width - _canvas_width / 4);

    _uiInit();

    _initNetwork();

    _play();

    /*#include events.js*/

    window.gb_code_editor_settings = _code_editor_settings;
    window.gb_code_editor = _code_editor;
    window.gb_code_editor_theme = _code_editor_theme;
})();
}
<commit_msg>add back silent notes optimization add osc. count infos for current frame (and the associated settings) fix electron app. when exiting<commit_after>/* jslint browser: true */

/* global CodeMirror, performance*/

// WUI - https://github.com/grz0zrg/wui
/*#include wui/wui.js*/

// CodeMirror - https://codemirror.net/
/*#include codemirror/codemirror.js*/
/*#include codemirror/addon/search/searchcursor.js*/
/*#include codemirror/addon/search/match-highlighter.js*/
/*#include codemirror/addon/search/matchesonscrollbar.js*/
/*#include codemirror/addon/edit/closebrackets.js*/
/*#include codemirror/addon/edit/matchbrackets.js*/
/*#include codemirror/addon/scroll/simplescrollbars.js*/
/*#include codemirror/addon/scroll/annotatescrollbar.js*/
/*#include codemirror/addon/selection/active-line.js*/
/*#include codemirror/codemirror_glsl.js*/

// sharedb - https://github.com/share/sharedb
/*#include sharedb/sharedb.js*/
/*#include sharedb/ot-text.js*/

/*#include resize_throttler/resize_throttler.js*/

window.onload = function() {
var FragmentSynth = new (function () {
    "use strict";

    /***********************************************************
        Globals.
    ************************************************************/

    /*#include notification.js*/

    var _getSessionName = function () {
        var url_parts = window.location.pathname.split('/');

        return url_parts[url_parts.length - 1];
    };

    window.performance = window.performance || {};
    performance.now = (function() {
      return performance.now       ||
             performance.mozNow    ||
             performance.msNow     ||
             performance.oNow      ||
             performance.webkitNow ||
             function() { return new Date().getTime(); };
    })();

    window.AudioContext = window.AudioContext || window.webkitAudioContext || false;

    window.requestAnimationFrame =  window.requestAnimationFrame || window.mozRequestAnimationFrame ||
                                    window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
    window.cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame;

    if (!window.AudioContext) {
        _fail("The Web Audio API is not available, please use a Web Audio capable browser.", true);

        return;
    }

    if (!window.cancelAnimationFrame) {
        _fail("The cancelAnimationFrame function is not available, please use a web browser with cancelAnimationFrame support.", true);

        return;
    }

    if (!window.localStorage) {
        _fail("The localStorage API is not available, please use a web browser with localStorage support.", true);

        return;
    }

    if (!window.FileReader) {
        _fail("FileReader API is not available, please use a web browser with FileReader support.", true);

        return;
    }

    if (!window.Blob) {
        _fail("Blob API is not available, please use a web browser with Blob support.", true);

        return;
    }

    if (!window.File) {
        _fail("File API is not available, please use a web browser with File API support.", true);

        return;
    }

    if (typeof(Worker) === "undefined") {
        _fail("Web Workers are not available, please use a web browser with Web Workers support.", true);

        return;
    }

    /***********************************************************
        Fields.
    ************************************************************/

    var _fs_state = 1,

        _username = localStorage.getItem('fs-user-name'),
        _local_session_settings = localStorage.getItem(_getSessionName()),

        _red_curtain_element = document.getElementById("fs_red_curtain"),
        _user_name_element = document.getElementById("fs_user_name"),
        _time_infos = document.getElementById("fs_time_infos"),
        _hz_infos = document.getElementById("fs_hz_infos"),
        _xy_infos = document.getElementById("fs_xy_infos"),
        _osc_infos = document.getElementById("fs_osc_infos"),

        _haxis_infos = document.getElementById("fs_haxis_infos"),
        _vaxis_infos = document.getElementById("fs_vaxis_infos"),

        _canvas_container = document.getElementById("canvas_container"),
        _canvas = document.createElement("canvas"),

        _canvas_width  = 1024,
        _canvas_height = 439,//Math.round(window.innerHeight / 2) - 68,

        _canvas_width_m1 = _canvas_width - 1,
        _canvas_height_mul4 = _canvas_height * 4,

        _render_width = _canvas_width,
        _render_height = _canvas_height,

        _code_editor,
        _code_editor_element = document.getElementById("code"),
        _code_editor_theme = localStorage.getItem('fs-editor-theme'),
        _code_editor_theme_link,
        _code_editor_highlight = {
                showToken: /\w/,
                annotateScrollbar: true
            },
        _code_editor_settings = {
            value: "",
            theme: ((_code_editor_theme === null) ? "seti" : _code_editor_theme),
            matchBrackets: true,
            //autoCloseBrackets: true,
            lineNumbers: true,
            styleActiveLine: true,
            scrollbarStyle: "native",
            mode: "text/x-glsl"
        },

        _compile_timer,

        _undock_code_editor = false,

        _xyf_grid = false,

        _glsl_error = false,

        // settings
        _show_globaltime = false,
        _show_oscinfos = false,
        _cm_highlight_matches = false,
        _cm_show_linenumbers = true,
        _cm_advanced_scrollbar = false,

        // mouse cursor over canvas
        _cx,
        _cy,

        _mx,
        _my,

        _nmx,
        _nmy,

        _cnmx,
        _cnmy,

        _mouse_btn = 0,

        _LEFT_MOUSE_BTN = 1,
        _RIGHT_MOUSE_BTN = 2,

        _fps = 60,

        _raf,

        _gl,

        _play_position_markers = [],

        _webgl_opts = {
                preserveDrawingBuffer: true
            },

        _prev_data = new Uint8Array(_canvas_height_mul4),
        _data = new Uint8Array(_canvas_height_mul4),
        _temp_data = new Uint8Array(_canvas_height_mul4),

        _midi_out_f,
        _midi_out = true,

        _quad_vertex_buffer,

        _program,

        _controls = {},

        _fragment_input_data = [],

        _input_panel_element = document.getElementById("fs_input_panel"),

        _codemirror_line_widgets = [],

        _time = 0,

        _pause_time = 0,

        _hover_freq = null,

        _input_channel_prefix = "iInput";

    /***********************************************************
        App. Includes.
    ************************************************************/

    /*#include config.js*/
    /*#include tools.js*/
    /*#include audio.js*/
    /*#include graphics.js*/
    /*#include glsl.js*/
    /*#include network.js*/
    /*#include discuss.js*/
    /*#include inputs.js*/
    /*#include editor.js*/
    /*#include transports.js*/
    /*#include ui.js*/
    /*#include fas.js*/

    /***********************************************************
        Functions.
    ************************************************************/

    var _updateScore = function (update_obj, update) {
        var prev_base_freq = _audio_infos.base_freq,
            prev_octave = _audio_infos.octaves,

            base_freq = _audio_infos.base_freq,
            octave = _audio_infos.octaves,

            prev_width = _canvas_width,
            prev_height = _canvas_height;

        if (update_obj["base_freq"] !== undefined) {
            base_freq = update_obj.base_freq;
        }

        if (update_obj["octave"] !== undefined) {
            octave = update_obj.octave;
        }

        _disableNotesProcessing();

        if (update_obj.height) {
            _canvas_height = update_obj.height;
            _canvas.height = _canvas_height;
            _canvas.style.height = _canvas_height + 'px';
            _canvas_height_mul4 = _canvas_height * 4;

            _vaxis_infos.style.height = _canvas_height + "px";

            _prev_data = new Uint8Array(_canvas_height_mul4);
            _data = new Uint8Array(_canvas_height_mul4);
            _temp_data = new Uint8Array(_canvas_height_mul4);

            _gl.viewport(0, 0, _canvas.width, _canvas.height);

            _updatePlayMarkersHeight(_canvas_height);
        }

        if (update_obj.width) {
            _canvas_width = update_obj.width;
            _canvas.width = _canvas_width;
            _canvas.style.width = _canvas_width + 'px';

            _gl.viewport(0, 0, _canvas.width, _canvas.height);
        }

        _generateOscillatorSet(_canvas_height, base_freq, octave);

        _compile();

        _updateCodeView();

        _updateAllPlayPosition();

        _fasNotify(_FAS_AUDIO_INFOS, _audio_infos);

        _enableNotesProcessing();

        WUI_RangeSlider.setValue("fs_score_width_input", _canvas_width);
        WUI_RangeSlider.setValue("fs_score_height_input", _canvas_height);
        WUI_RangeSlider.setValue("fs_score_octave_input", octave);
        WUI_RangeSlider.setValue("fs_score_base_input", base_freq);

        if (update) {
            _shareSettingsUpd([
                    prev_width, _canvas_width,
                    prev_height, _canvas_height,
                    prev_octave, octave,
                    prev_base_freq, base_freq
                ]);
        }
    };

    /***********************************************************
        Init.
    ************************************************************/

    _audioInit();

    if (!_username) {
        _username = "Anonymous";
    }

    _user_name_element.innerHTML = _username;

    //_canvas_width = _getElementOffset(_canvas_container).width;

    _render_width = _canvas_width;

    _canvas.width  = _render_width;
    _canvas.height = _render_height;

    _canvas.style.width  = _canvas_width  + 'px';
    _canvas.style.height = _canvas_height + 'px';

    _canvas_container.appendChild(_canvas);

    _vaxis_infos.style.height = _canvas_height + "px";

    // CodeMirror
    if (!_code_editor_theme) {
        _code_editor_theme = "seti";
    }

    _changeEditorTheme(_code_editor_theme);

    _code_editor = new CodeMirror(_code_editor_element, _code_editor_settings);
    _code_editor.setValue(document.getElementById("fragment-shader").text);

    CodeMirror.on(_code_editor, 'change', function (instance, change_obj) {
        clearTimeout(_compile_timer);
        _compile_timer = setTimeout(_compile, 500);
    });

    CodeMirror.on(_code_editor, 'changes', function (instance, changes) {
        _shareCodeEditorChanges(changes);
    });

    // WebGL
    _gl = _canvas.getContext("webgl", _webgl_opts) || _canvas.getContext("experimental-webgl", _webgl_opts);

    if (!_gl) {
        _fail("The WebGL API is not available, please try with a WebGL ready browser.", true);

        return;
    }

    _buildScreenAlignedQuad();

    _gl.viewport(0, 0, _canvas.width, _canvas.height);

    _compile();

    // setup user last settings for this session if any
    if (_local_session_settings) {
        _local_session_settings = JSON.parse(_local_session_settings);
        if ('gain' in _local_session_settings) {
            _volume = _local_session_settings.gain;

            WUI_RangeSlider.setValue("mst_slider", _volume, true);
        }
    } else {
        _local_session_settings = {
            gain: _volume,
        };
    }

    //_addPlayPositionMarker(_canvas_width / 4);
    //_addPlayPositionMarker(_canvas_width - _canvas_width / 4);

    _uiInit();

    _initNetwork();

    _play();

    /*#include events.js*/

    window.gb_code_editor_settings = _code_editor_settings;
    window.gb_code_editor = _code_editor;
    window.gb_code_editor_theme = _code_editor_theme;
})();
}
<|endoftext|>


<commit_before>/*!
 * jQuery Lifestream Plug-in
 * @version 0.3.7
 * Show a stream of your online activity
 *
 * Copyright 2011, Christian Vuerings - http://denbuzze.com
 */
/*global jQuery */
;(function( $ ){

  "use strict";

  /**
   * Initialize the lifestream plug-in
   * @param {Object} config Configuration object
   */
  $.fn.lifestream = function( config ) {

    // Make the plug-in chainable
    return this.each(function() {

      // The element where the lifestream is linked to
      var outputElement = $(this),

      // Extend the default settings with the values passed
      settings = jQuery.extend({
        // The name of the main lifestream class
        // We use this for the main ul class e.g. lifestream
        // and for the specific feeds e.g. lifestream-twitter
        classname: "lifestream",
        // Callback function which will be triggered when a feed is loaded
        feedloaded: null,
        // The amount of feed items you want to show
        limit: 10,
        // An array of feed items which you want to use
        list: []
      }, config),

      // The data object contains all the feed items
      data = {
        count: settings.list.length,
        items: []
      },

      // We use the item settings to pass the global settings variable to
      // every feed
      itemsettings = jQuery.extend( true, {}, settings ),

      /**
       * This method will be called every time a feed is loaded. This means
       * that several DOM changes will occur. We did this because otherwise it
       * takes to look before anything shows up.
       * We allow 1 request per feed - so 1 DOM change per feed
       * @private
       * @param {Array} inputdata an array containing all the feeditems for a
       * specific feed.
       */
      finished = function( inputdata ) {

        // Merge the feed items we have from other feeds, with the feeditems
        // from the new feed
        $.merge( data.items, inputdata );

        // Sort the feeditems by date - we want the most recent one first
        data.items.sort( function( a, b ) {
            return ( b.date - a.date );
        });

        var items = data.items,

            // We need to check whether the amount of current feed items is
            // smaller than the main limit. This parameter will be used in the
            // for loop
            length = ( items.length < settings.limit ) ?
              items.length :
              settings.limit,
            i = 0, item,

            // We create an unordered list which will create all the feed
            // items
            ul = $('
');

        // Run over all the feed items + add them as list items to the
        // unordered list
        for ( ; i < length; i++ ) {
          item = items[i];
          if ( item.html ) {
            $('
').data( "name", item.config.service )
                                           .data( "url", item.url || "#" )
                                           .data( "time", item.date )
                                           .append( item.html )
                                           .appendTo( ul );
          }
        }

        // Change the innerHTML with a list of all the feeditems in
        // chronological order
        outputElement.html( ul );

        // Trigger the feedloaded callback, if it is a function
        if ( $.isFunction( settings.feedloaded ) ) {
          settings.feedloaded();
        }

      },

      /**
       * Fire up all the feeds and pass them the right arugments.
       * @private
       */
      load = function() {

        var i = 0, j = settings.list.length;

        // We don't pass the list array to each feed  because this will create
        // a recursive JavaScript object
        delete itemsettings.list;

        // Run over all the items in the list
        for( ; i < j; i++ ) {

          var config = settings.list[i];

          // Check whether the feed exists, if the feed is a function and if a
          // user has been filled in
          if ( $.fn.lifestream.feeds[config.service] &&
               $.isFunction( $.fn.lifestream.feeds[config.service] ) &&
               config.user) {

            // You'll be able to get the global settings by using
            // config._settings in your feed
            config._settings = itemsettings;

            // Call the feed with a config object and finished callback
            $.fn.lifestream.feeds[config.service]( config, finished );
          }

        }

      };

      // Load the jQuery templates plug-in if it wasn't included in the page.
      // At then end we call the load method.
      if( !jQuery.tmpl ) {
        jQuery.getScript(
          "http://ajax.aspnetcdn.com/ajax/jquery.templates/beta1/jquery.tmpl.js",
          load);
      } else {
        load();
      }

    });

  };

  /**
   * Create a valid YQL URL by passing in a query
   * @param {String} query The query you want to convert into a valid yql url
   * @return {String} A valid YQL URL
   */
  $.fn.lifestream.createYqlUrl = function( query ) {
      return ( "http://query.yahooapis.com/v1/public/yql?q=__QUERY__&env=" +
      "store://datatables.org/alltableswithkeys&format=json")
        .replace( "__QUERY__" , encodeURIComponent( query ) );
  };

  /**
   * A big container which contains all available feeds
   */
  $.fn.lifestream.feeds = $.fn.lifestream.feeds || {};

  /**
   * Add compatible Object.keys support in older environments that do not natively support it
   * https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys#section_6
   */
  if(!Object.keys) {
    Object.keys = function(o){
      if (o !== Object(o)){
        throw new TypeError('Object.keys called on non-object');
      }
      var ret=[],p;
      for(p in o) {
        if(Object.prototype.hasOwnProperty.call(o,p)) {
          ret.push(p);
        }
      }
      return ret;
    };
  }

}( jQuery ));
<commit_msg>fewer OCD triggers in core (i.e. beautify)<commit_after>/*!
 * jQuery Lifestream Plug-in
 * @version 0.3.7
 * Show a stream of your online activity
 *
 * Copyright 2011, Christian Vuerings - http://denbuzze.com
 */
/*global jQuery */
;(function( $ ){

  "use strict";

  /**
   * Initialize the lifestream plug-in
   * @param {Object} config Configuration object
   */
  $.fn.lifestream = function( config ) {

    // Make the plug-in chainable
    return this.each(function() {

      // The element where the lifestream is linked to
      var outputElement = $(this),

      // Extend the default settings with the values passed
      settings = jQuery.extend({
        // The name of the main lifestream class
        // We use this for the main ul class e.g. lifestream
        // and for the specific feeds e.g. lifestream-twitter
        classname: "lifestream",
        // Callback function which will be triggered when a feed is loaded
        feedloaded: null,
        // The amount of feed items you want to show
        limit: 10,
        // An array of feed items which you want to use
        list: []
      }, config),

      // The data object contains all the feed items
      data = {
        count: settings.list.length,
        items: []
      },

      // We use the item settings to pass the global settings variable to
      // every feed
      itemsettings = jQuery.extend( true, {}, settings ),

      /**
       * This method will be called every time a feed is loaded. This means
       * that several DOM changes will occur. We did this because otherwise it
       * takes to look before anything shows up.
       * We allow 1 request per feed - so 1 DOM change per feed
       * @private
       * @param {Array} inputdata an array containing all the feeditems for a
       * specific feed.
       */
      finished = function( inputdata ) {

        // Merge the feed items we have from other feeds, with the feeditems
        // from the new feed
        $.merge( data.items, inputdata );

        // Sort the feeditems by date - we want the most recent one first
        data.items.sort( function( a, b ) {
            return ( b.date - a.date );
        });

        var items = data.items,

            // We need to check whether the amount of current feed items is
            // smaller than the main limit. This parameter will be used in the
            // for loop
            length = ( items.length < settings.limit ) ?
              items.length :
              settings.limit,
            i = 0, item,

            // We create an unordered list which will create all the feed
            // items
            ul = $('
');

        // Run over all the feed items + add them as list items to the
        // unordered list
        for ( ; i < length; i++ ) {
          item = items[i];
          if ( item.html ) {
            $('
').data( "name", item.config.service )
                                          .data( "url", item.url || "#" )
                                          .data( "time", item.date )
                                          .append( item.html )
                                          .appendTo( ul );
          }
        }

        // Change the innerHTML with a list of all the feeditems in
        // chronological order
        outputElement.html( ul );

        // Trigger the feedloaded callback, if it is a function
        if ( $.isFunction( settings.feedloaded ) ) {
          settings.feedloaded();
        }

      },

      /**
       * Fire up all the feeds and pass them the right arugments.
       * @private
       */
      load = function() {

        var i = 0, j = settings.list.length;

        // We don't pass the list array to each feed  because this will create
        // a recursive JavaScript object
        delete itemsettings.list;

        // Run over all the items in the list
        for( ; i < j; i++ ) {

          var config = settings.list[i];

          // Check whether the feed exists, if the feed is a function and if a
          // user has been filled in
          if ( $.fn.lifestream.feeds[config.service] &&
               $.isFunction( $.fn.lifestream.feeds[config.service] ) &&
               config.user) {

            // You'll be able to get the global settings by using
            // config._settings in your feed
            config._settings = itemsettings;

            // Call the feed with a config object and finished callback
            $.fn.lifestream.feeds[config.service]( config, finished );
          }

        }

      };

      // Load the jQuery templates plug-in if it wasn't included in the page.
      // At then end we call the load method.
      if( !jQuery.tmpl ) {
        jQuery.getScript(
          'http://ajax.aspnetcdn.com/ajax/jquery.templates/beta1/jquery.tmpl.js',
          load);
      } else {
        load();
      }

    });

  };

  /**
   * Create a valid YQL URL by passing in a query
   * @param {String} query The query you want to convert into a valid yql url
   * @return {String} A valid YQL URL
   */
  $.fn.lifestream.createYqlUrl = function( query ) {
      return ( 'http://query.yahooapis.com/v1/public/yql?q=__QUERY__&env=' +
      'store://datatables.org/alltableswithkeys&format=json')
        .replace( "__QUERY__" , encodeURIComponent( query ) );
  };

  /**
   * A big container which contains all available feeds
   */
  $.fn.lifestream.feeds = $.fn.lifestream.feeds || {};

  /**
   * Add compatible Object.keys support in older environments that do not natively support it
   * https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys#section_6
   */
  if(!Object.keys) {
    Object.keys = function(o){
      if (o !== Object(o)) {
        throw new TypeError('Object.keys called on non-object');
      }
      var ret=[],p;
      for(p in o) {
        if(Object.prototype.hasOwnProperty.call(o,p)) {
          ret.push(p);
        }
      }
      return ret;
    };
  }

}( jQuery ));
<|endoftext|>


<commit_before>.pragma library
var MIXPANEL_TOKEN = "";
var API_URL = "http://dailydota2.com/match-api";
<commit_msg>Added version string<commit_after>.pragma library
var MIXPANEL_TOKEN = "";
var API_URL = "http://dailydota2.com/match-api";
var VERSION = "0.0.1"
<|endoftext|>


<commit_before>var applicationConfigPath = require('application-config-path')
var path = require('path')

var APP_VERSION = require('./package.json').version

module.exports = {
  APP_COPYRIGHT: 'Copyright © 2014-2016 The WebTorrent Project',
  APP_FILE_ICON: path.join(__dirname, 'static', 'WebTorrentFile'),
  APP_ICON: path.join(__dirname, 'static', 'WebTorrent'),
  APP_NAME: 'WebTorrent',

  AUTO_UPDATE_URL: 'https://webtorrent.io/app/updates?version=' + APP_VERSION,
  AUTO_UPDATE_CHECK_STARTUP_DELAY: 60 * 1000 /* 1 minute */,

  CONFIG_PATH: applicationConfigPath('WebTorrent'),
  CONFIG_POSTER_PATH: path.join(applicationConfigPath('WebTorrent'), 'Posters'),
  CONFIG_TORRENT_PATH: path.join(applicationConfigPath('WebTorrent'), 'Torrents'),

  INDEX: 'file://' + path.join(__dirname, 'renderer', 'index.html'),

  IS_PRODUCTION: isProduction(),

  ROOT_PATH: __dirname,
  STATIC_PATH: path.join(__dirname, 'static'),

  SOUND_ADD: 'file://' + path.join(__dirname, 'static', 'sound', 'add.wav'),
  SOUND_DELETE: 'file://' + path.join(__dirname, 'static', 'sound', 'delete.wav'),
  SOUND_DISABLE: 'file://' + path.join(__dirname, 'static', 'sound', 'disable.wav'),
  SOUND_DONE: 'file://' + path.join(__dirname, 'static', 'sound', 'done.wav'),
  SOUND_ENABLE: 'file://' + path.join(__dirname, 'static', 'sound', 'enable.wav'),
  SOUND_ERROR: 'file://' + path.join(__dirname, 'static', 'sound', 'error.wav'),
  SOUND_PLAY: 'file://' + path.join(__dirname, 'static', 'sound', 'play.wav'),
  SOUND_STARTUP: 'file://' + path.join(__dirname, 'static', 'sound', 'startup.wav')
}

function isProduction () {
  if (!process.versions.electron) {
    return false
  }
  if (process.platform === 'darwin') {
    return !/\/Electron\.app\/Contents\/MacOS\/Electron$/.test(process.execPath)
  }
  if (process.platform === 'win32') {
    return !/\\electron\.exe$/.test(process.execPath)
  }
  if (process.platform === 'linux') {
    return !/\/electron$/.test(process.execPath)
  }
}
<commit_msg>config: put APP_NAME into a variable<commit_after>var applicationConfigPath = require('application-config-path')
var path = require('path')

var APP_NAME = 'WebTorrent'
var APP_VERSION = require('./package.json').version

module.exports = {
  APP_COPYRIGHT: 'Copyright © 2014-2016 The WebTorrent Project',
  APP_FILE_ICON: path.join(__dirname, 'static', 'WebTorrentFile'),
  APP_ICON: path.join(__dirname, 'static', 'WebTorrent'),
  APP_NAME: APP_NAME,

  AUTO_UPDATE_URL: 'https://webtorrent.io/app/updates?version=' + APP_VERSION,
  AUTO_UPDATE_CHECK_STARTUP_DELAY: 60 * 1000 /* 1 minute */,

  CONFIG_PATH: applicationConfigPath(APP_NAME),
  CONFIG_POSTER_PATH: path.join(applicationConfigPath(APP_NAME), 'Posters'),
  CONFIG_TORRENT_PATH: path.join(applicationConfigPath(APP_NAME), 'Torrents'),

  INDEX: 'file://' + path.join(__dirname, 'renderer', 'index.html'),

  IS_PRODUCTION: isProduction(),

  ROOT_PATH: __dirname,
  STATIC_PATH: path.join(__dirname, 'static'),

  SOUND_ADD: 'file://' + path.join(__dirname, 'static', 'sound', 'add.wav'),
  SOUND_DELETE: 'file://' + path.join(__dirname, 'static', 'sound', 'delete.wav'),
  SOUND_DISABLE: 'file://' + path.join(__dirname, 'static', 'sound', 'disable.wav'),
  SOUND_DONE: 'file://' + path.join(__dirname, 'static', 'sound', 'done.wav'),
  SOUND_ENABLE: 'file://' + path.join(__dirname, 'static', 'sound', 'enable.wav'),
  SOUND_ERROR: 'file://' + path.join(__dirname, 'static', 'sound', 'error.wav'),
  SOUND_PLAY: 'file://' + path.join(__dirname, 'static', 'sound', 'play.wav'),
  SOUND_STARTUP: 'file://' + path.join(__dirname, 'static', 'sound', 'startup.wav')
}

function isProduction () {
  if (!process.versions.electron) {
    return false
  }
  if (process.platform === 'darwin') {
    return !/\/Electron\.app\/Contents\/MacOS\/Electron$/.test(process.execPath)
  }
  if (process.platform === 'win32') {
    return !/\\electron\.exe$/.test(process.execPath)
  }
  if (process.platform === 'linux') {
    return !/\/electron$/.test(process.execPath)
  }
}
<|endoftext|>


<commit_before>module.exports = {
    port: process.env.PORT || 54321,
    cacheExpiration: 2 * 60 * 60 * 1000, //2h
    globalTickInterval: 2 * 60 * 1000, //2m
    parserTimeout: 20 * 1000, //20s
    restaurants: [
        { id: 0, name: "Jedáleň u Daňováka II", url: "https://www.zomato.com/sk/bratislava/jed%C3%A1le%C5%88-u-da%C5%88ov%C3%A1ka-2-petr%C5%BEalka-bratislava-v/menu#tabtop", module: "obedovat" },
        { id: 1, name: "U Daňováka", url: "https://www.zomato.com/sk/bratislava/re%C5%A1taur%C3%A1cia-u-da%C5%88ov%C3%A1ka-petr%C5%BEalka-bratislava-v/menu#tabtop", module: "obedovat" },
        { id: 2, name: "Giuliano", url: "http://www.giuliano.sk/sk/denne-menu/", module: "giuliano" },
        { id: 3, name: "ITB", url: "http://www.citycantina.sk/index.php?id=1&type=main_menu&t=1", module: "itb" },
        { id: 4, name: "Alfa", url: "https://www.zomato.com/sk/bratislava/alfa-petr%C5%BEalka-bratislava-v/menu#tabtop", module: "obedovat" },
        { id: 5, name: "Škôlka", url: "http://jedalen.vysnivany.sk/ukazka-strany", module: "skolka" },
        { id: 6, name: "Pizza Pazza", url: "http://www.pizzapazza.sk/sk/denne-menu/", module: "pizzapazza" },
        { id: 7, name: "Kamenica - Corleone Pizza", url: "http://restauracie.sme.sk/restauracia/kamenica-corleone-pizza_660-petrzalka_664/denne-menu", module: "sme" },
        { id: 8, name: "Numero Uno", url: "http://www.numerouno.sk/denne-menu-5/", module: "numerouno" },
        { id: 9, name: "Engerau restaurant", url: "https://www.zomato.com/sk/bratislava/engerau-restaurant-petr%C5%BEalka-bratislava-v/menu#tabtop", module: "obedovat" },
        { id: 10, name: "Jedáleň Albatros", url: "https://www.zomato.com/sk/bratislava/jed%C3%A1le%C5%88-albatros-petr%C5%BEalka-bratislava-v/menu#tabtop", module: "obedovat" }
    ],
    themes: {
        "jano": { name: "Jano", template: "../views/index.html" },
        "igor": { name: "Igor", template: "../views/index2.html" },
        "matus": { name: "Matúš", template: "../views/index3.html" },
        "iveta": { name: "Iveta", template: "../views/index4.html" },
        "telka": { name: "Telka", template: "../views/index5.html" }
    }
};
<commit_msg>Theme "Igor" removed<commit_after>module.exports = {
    port: process.env.PORT || 54321,
    cacheExpiration: 2 * 60 * 60 * 1000, //2h
    globalTickInterval: 2 * 60 * 1000, //2m
    parserTimeout: 20 * 1000, //20s
    restaurants: [
        { id: 0, name: "Jedáleň u Daňováka II", url: "https://www.zomato.com/sk/bratislava/jed%C3%A1le%C5%88-u-da%C5%88ov%C3%A1ka-2-petr%C5%BEalka-bratislava-v/menu#tabtop", module: "obedovat" },
        { id: 1, name: "U Daňováka", url: "https://www.zomato.com/sk/bratislava/re%C5%A1taur%C3%A1cia-u-da%C5%88ov%C3%A1ka-petr%C5%BEalka-bratislava-v/menu#tabtop", module: "obedovat" },
        { id: 2, name: "Giuliano", url: "http://www.giuliano.sk/sk/denne-menu/", module: "giuliano" },
        { id: 3, name: "ITB", url: "http://www.citycantina.sk/index.php?id=1&type=main_menu&t=1", module: "itb" },
        { id: 4, name: "Alfa", url: "https://www.zomato.com/sk/bratislava/alfa-petr%C5%BEalka-bratislava-v/menu#tabtop", module: "obedovat" },
        { id: 5, name: "Škôlka", url: "http://jedalen.vysnivany.sk/ukazka-strany", module: "skolka" },
        { id: 6, name: "Pizza Pazza", url: "http://www.pizzapazza.sk/sk/denne-menu/", module: "pizzapazza" },
        { id: 7, name: "Kamenica - Corleone Pizza", url: "http://restauracie.sme.sk/restauracia/kamenica-corleone-pizza_660-petrzalka_664/denne-menu", module: "sme" },
        { id: 8, name: "Numero Uno", url: "http://www.numerouno.sk/denne-menu-5/", module: "numerouno" },
        { id: 9, name: "Engerau restaurant", url: "https://www.zomato.com/sk/bratislava/engerau-restaurant-petr%C5%BEalka-bratislava-v/menu#tabtop", module: "obedovat" },
        { id: 10, name: "Jedáleň Albatros", url: "https://www.zomato.com/sk/bratislava/jed%C3%A1le%C5%88-albatros-petr%C5%BEalka-bratislava-v/menu#tabtop", module: "obedovat" }
    ],
    themes: {
        "jano": { name: "Jano", template: "../views/index.html" },
        "matus": { name: "Matúš", template: "../views/index3.html" },
        "iveta": { name: "Iveta", template: "../views/index4.html" },
        "telka": { name: "Telka", template: "../views/index5.html" }
    }
};
<|endoftext|>


<commit_before>//////// Helpers ////////

//Spacebars Helpers
Template.registerHelper('equals', function (a, b) {
    return a === b;
});

//UI Helpers
//Add Class
function addClass(e, cls){
    e.classList.add(cls);
}
//Remove Class
function removeClass(e, cls){
    e.classList.remove(cls);
}

//Remove Class (by Prefix)
function removeClassByPrefix(e, prefix) {
    var regx = new RegExp('\\b' + prefix + '.*?\\b', 'g');
    e.className = e.className.replace(regx, '');
    return e;
}

function hidden(e,state){
    if (state == false){
        e.setAttribute('aria-hidden', 'false');
    } else{
        e.setAttribute('aria-hidden', 'true');
    }
}

function active(e,state){
    if(state == true){
        e.setAttribute('aria-expanded','true');
    } else{
        e.setAttribute('aria-expanded','false');
    }
}

//////// Systems ////////

///// Focus Groups
// Focusable Variables
var focusable ='a[href], area[href], input, select, textarea, button, iframe, object, embed, *[tabindex], *[contenteditable]';
var globalFocusGroup = $('[data-focus="global"]').find(focusable);
var focusGlobalElFirst = globalFocusGroup[0];
var focusGlobalElLast = globalFocusGroup[globalFocusGroup.length-1];
var activeFocusGroup = $('[aria-hidden="false"][data-focus="group"]').find(focusable);
var focusGroupElFirst = activeFocusGroup[0];
var focusGroupElLast = activeFocusGroup[activeFocusGroup.length - 1];

//Redundant with above
function currentFocusGroup(){
    focusable ='a[href], area[href], input, select, textarea, button, iframe, object, embed, *[tabindex], *[contenteditable]';
    globalFocusGroup = $('[data-focus="global"]').find(focusable);
    focusGlobalElFirst = globalFocusGroup[0];
    focusGlobalElLast = globalFocusGroup[globalFocusGroup.length-1];
    activeFocusGroup = $('[aria-hidden="false"][data-focus="group"]').find(focusable);
    focusGroupElFirst = activeFocusGroup[0];
    focusGroupElLast = activeFocusGroup[activeFocusGroup.length - 1];
    console.log(focusGroupElFirst);
    console.log(focusGroupElLast);
    console.log(focusGlobalElFirst);
    console.log(focusGlobalElLast);
}
currentFocusGroup();

//Focus Groups Events
var resetFocus = false;
var focusToGroup = false;
var topFocus = false;
//This only works if the tab key alone is being used.
$("body").on("keydown", function(event) {
    if(event.keyCode == 9){
        var active;
        active = document.activeElement;
        console.log(active);
        if($(active).is(focusGroupElLast)){ resetFocus = true; } // :focusable
        if($(active).is(focusGlobalElLast)){ focusToGroup = true; } // :focusable
        if($(active).is(focusGroupElFirst)){ topFocus = true; } // :focusable
        if(!event.shiftKey){
            topFocus = false;
            if(resetFocus == true){
                focusGlobalElFirst.focus();
                resetFocus = false;
                event.preventDefault();
            }
            if(focusToGroup == true){
                focusGroupElFirst.focus();
                focusToGroup = false;
                event.preventDefault();
            }
        }
        if(event.shiftKey){
            resetFocus = false;
            focusToGroup = false;
            if(topFocus == true){
                focusGlobalElLast.focus();
                topFocus = false;
                event.preventDefault();
            }
        }
    }
});

//// Canvas States

function clearCanvas(){
    document.body.classList.remove('noScroll');
    var canvas = document.getElementById('canvas');
    canvas.setAttribute('data-canvas-position','');
    canvas.setAttribute('data-canvas-state','closed');
    canvas.setAttribute('data-canvas-width','');
}
//event.target function fires on click events of any element containing the data-attribute, "data-sidebar".
function toggleCanvas() {
    // Canvas Variables
    var toggle = document.querySelectorAll('[aria-controls]');
    var overlay = document.getElementById('overlay');
    var sidebar = document.querySelectorAll('section.sidebar');
    var canvas = document.getElementById('canvas');

    //Close open canvas elements if overlay or active li is clicked. Or if close canvas event fired
    if(event.target.getAttribute('aria-expanded') == 'true' || event.target == overlay || event.target.getAttribute('data-canvas-event') == 'close'){
        for (var i = 0, e; e = toggle[i]; i++) { active(e,false); } //Remove current toggle active states
        for (var i = 0, e; e = sidebar[i]; i++) { hidden(e,true); } //Clear all active Sidebars
        clearCanvas(); //Remove all canvas effect classes
        hidden(overlay,true);
        focusGlobalElFirst.focus();
    }

    // Open Overlay and offCanvas elements if clicking inactive list item
    else if(event.target.hasAttribute('aria-controls') && event.target.getAttribute('aria-expanded') == 'false'){
        clearCanvas();
        document.body.classList.add('noScroll');
        canvas.setAttribute('data-canvas-state','open'); //Add master canvas effect class
        hidden(overlay,false);
        for (var i = 0, e; e = toggle[i]; i++) { active(e,false); } //Clear all active toggles
        active(event.target,true); //Add active class to clicked element
        //Sets values based on the parameters of the current sidebar
        for (var i = 0, e; e = sidebar[i]; i++) {
            hidden(e,true); //Clear all active sidebars
            if ('#' + e.getAttribute('id') == event.target.getAttribute('aria-controls')){ //If Sidebar ID matches toggles' data-sidebar
                hidden(e,false); //Add active class to given sidebar
                canvas.setAttribute('data-canvas-width',e.dataset.width); //Add new sidebar-width effect class
                if(e.dataset.position == 'left'){ canvas.setAttribute('data-canvas-position','left'); }
                if(e.dataset.position == 'right'){ canvas.setAttribute('data-canvas-position','right'); }
            }
            //focusGroupElFirst.focus();
            event.preventDefault();
        }
        currentFocusGroup(); //Recalculate live focus areas
        focusGroupElFirst.focus();
    }
    currentFocusGroup(); //Recalculate live focus areas
}

Template.body.events({
    //Canvas Actions
    'click [aria-controls]': function (event) { toggleCanvas(); },
    'click .overlay': function (event) { toggleCanvas(); },
    'click .closeTab': function (event) { toggleCanvas(); }
    //'keyup': function (event) { tabAction(); } //This is ideal over jQuery bit above
});<commit_msg>Removed console logs from global.js.<commit_after>//////// Helpers ////////

//Spacebars Helpers
Template.registerHelper('equals', function (a, b) {
    return a === b;
});

//UI Helpers
//Add Class
function addClass(e, cls){
    e.classList.add(cls);
}
//Remove Class
function removeClass(e, cls){
    e.classList.remove(cls);
}

//Remove Class (by Prefix)
function removeClassByPrefix(e, prefix) {
    var regx = new RegExp('\\b' + prefix + '.*?\\b', 'g');
    e.className = e.className.replace(regx, '');
    return e;
}

function hidden(e,state){
    if (state == false){
        e.setAttribute('aria-hidden', 'false');
    } else{
        e.setAttribute('aria-hidden', 'true');
    }
}

function active(e,state){
    if(state == true){
        e.setAttribute('aria-expanded','true');
    } else{
        e.setAttribute('aria-expanded','false');
    }
}

//////// Systems ////////

///// Focus Groups
// Focusable Variables
var focusable ='a[href], area[href], input, select, textarea, button, iframe, object, embed, *[tabindex], *[contenteditable]';
var globalFocusGroup = $('[data-focus="global"]').find(focusable);
var focusGlobalElFirst = globalFocusGroup[0];
var focusGlobalElLast = globalFocusGroup[globalFocusGroup.length-1];
var activeFocusGroup = $('[aria-hidden="false"][data-focus="group"]').find(focusable);
var focusGroupElFirst = activeFocusGroup[0];
var focusGroupElLast = activeFocusGroup[activeFocusGroup.length - 1];

//Redundant with above
function currentFocusGroup(){
    focusable ='a[href], area[href], input, select, textarea, button, iframe, object, embed, *[tabindex], *[contenteditable]';
    globalFocusGroup = $('[data-focus="global"]').find(focusable);
    focusGlobalElFirst = globalFocusGroup[0];
    focusGlobalElLast = globalFocusGroup[globalFocusGroup.length-1];
    activeFocusGroup = $('[aria-hidden="false"][data-focus="group"]').find(focusable);
    focusGroupElFirst = activeFocusGroup[0];
    focusGroupElLast = activeFocusGroup[activeFocusGroup.length - 1];
}
currentFocusGroup();

//Focus Groups Events
var resetFocus = false;
var focusToGroup = false;
var topFocus = false;
//This only works if the tab key alone is being used.
$("body").on("keydown", function(event) {
    if(event.keyCode == 9){
        var active;
        active = document.activeElement;
        console.log(active);
        if($(active).is(focusGroupElLast)){ resetFocus = true; } // :focusable
        if($(active).is(focusGlobalElLast)){ focusToGroup = true; } // :focusable
        if($(active).is(focusGroupElFirst)){ topFocus = true; } // :focusable
        if(!event.shiftKey){
            topFocus = false;
            if(resetFocus == true){
                focusGlobalElFirst.focus();
                resetFocus = false;
                event.preventDefault();
            }
            if(focusToGroup == true){
                focusGroupElFirst.focus();
                focusToGroup = false;
                event.preventDefault();
            }
        }
        if(event.shiftKey){
            resetFocus = false;
            focusToGroup = false;
            if(topFocus == true){
                focusGlobalElLast.focus();
                topFocus = false;
                event.preventDefault();
            }
        }
    }
});

//// Canvas States

function clearCanvas(){
    document.body.classList.remove('noScroll');
    var canvas = document.getElementById('canvas');
    canvas.setAttribute('data-canvas-position','');
    canvas.setAttribute('data-canvas-state','closed');
    canvas.setAttribute('data-canvas-width','');
}
//event.target function fires on click events of any element containing the data-attribute, "data-sidebar".
function toggleCanvas() {
    // Canvas Variables
    var toggle = document.querySelectorAll('[aria-controls]');
    var overlay = document.getElementById('overlay');
    var sidebar = document.querySelectorAll('section.sidebar');
    var canvas = document.getElementById('canvas');

    //Close open canvas elements if overlay or active li is clicked. Or if close canvas event fired
    if(event.target.getAttribute('aria-expanded') == 'true' || event.target == overlay || event.target.getAttribute('data-canvas-event') == 'close'){
        for (var i = 0, e; e = toggle[i]; i++) { active(e,false); } //Remove current toggle active states
        for (var i = 0, e; e = sidebar[i]; i++) { hidden(e,true); } //Clear all active Sidebars
        clearCanvas(); //Remove all canvas effect classes
        hidden(overlay,true);
        focusGlobalElFirst.focus();
    }

    // Open Overlay and offCanvas elements if clicking inactive list item
    else if(event.target.hasAttribute('aria-controls') && event.target.getAttribute('aria-expanded') == 'false'){
        clearCanvas();
        document.body.classList.add('noScroll');
        canvas.setAttribute('data-canvas-state','open'); //Add master canvas effect class
        hidden(overlay,false);
        for (var i = 0, e; e = toggle[i]; i++) { active(e,false); } //Clear all active toggles
        active(event.target,true); //Add active class to clicked element
        //Sets values based on the parameters of the current sidebar
        for (var i = 0, e; e = sidebar[i]; i++) {
            hidden(e,true); //Clear all active sidebars
            if ('#' + e.getAttribute('id') == event.target.getAttribute('aria-controls')){ //If Sidebar ID matches toggles' data-sidebar
                hidden(e,false); //Add active class to given sidebar
                canvas.setAttribute('data-canvas-width',e.dataset.width); //Add new sidebar-width effect class
                if(e.dataset.position == 'left'){ canvas.setAttribute('data-canvas-position','left'); }
                if(e.dataset.position == 'right'){ canvas.setAttribute('data-canvas-position','right'); }
            }
            //focusGroupElFirst.focus();
            event.preventDefault();
        }
        currentFocusGroup(); //Recalculate live focus areas
        focusGroupElFirst.focus();
    }
    currentFocusGroup(); //Recalculate live focus areas
}

Template.body.events({
    //Canvas Actions
    'click [aria-controls]': function (event) { toggleCanvas(); },
    'click .overlay': function (event) { toggleCanvas(); },
    'click .closeTab': function (event) { toggleCanvas(); }
    //'keyup': function (event) { tabAction(); } //This is ideal over jQuery bit above
});<|endoftext|>


<commit_before>(function($, juice) {

	/**
	 * OOP Style class definition helper
	 *
	 */
	var Klass = function(code){
		var klass = function() {
			var instance = (null != arguments[0] && null != this.__init__
					&& 'function' == typeof this.__init__)
				? this.__init__.apply(this, arguments)
				: this;
			return instance;
		};
		$.extend(klass, this, klass.prototype, {
			'bind': function(type, fn) {
				this.__events__ = this.__events__ || {};
				this.__events__[type] = this.__events__[type] || [];
				this.__events__[type].push(fn);
				return this;
			},

			'unbind': function(type, fn) {
				if (this.__events__ && this.__events__[type]) {
					this.__events__[type].splice(this.__events__[type].indexOf(fn), 1);
				}
				return this;
			},

			'trigger': function(type, args){
				if (this.__events__ && this.__events__[type]){
					var evt = $.Event(type);
					evt.target = this;
					$.each(this.__events__[type], function(idx, fn) {
						fn.apply(this, $.merge([evt], args || []));
					});
				}
				return this;
			}
		}, code);

		klass.constructor = Class;
		return klass;
	};

	var mixin = function(previous, current){
		if (previous && previous != current){
			var type = typeof current;
			if (type != typeof previous) return current;
			switch(type){
				case 'function':
					var merged = function(){
						this.parent = arguments.callee.parent;
						return current.apply(this, arguments);
					};
					merged.parent = previous;
					return merged;
				case 'object': return $.merge(previous, current);
			}
		}
		return current;
	};

	$.extend(true, Klass.prototype, {
		'extend': function(properties) {
			var proto = new this(null);
			for (var property in properties){
				var pp = proto[property];
				proto[property] = mixin(pp, properties[property]);
			}
			return new Klass(proto);
		},

		'implement': function() {
			for (var i = 0, l = arguments.length; i < l; i++)
				$.extend(this.prototype, arguments[i]);
		}
	});

	window.Class = function(code) {
		return new Klass(code);
	};

	/**
	 * URL
	 *
	 */

	var URL = Class({
		__init__: function(url) {
			var parse = function(url) {
				var ptn = /^(?=[^&])(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/;
				var match = ptn.exec(url);
				return {
					scheme  : match[1],
					domain  : match[2],
					path    : match[3],
					query   : (function(query) {
						var qa = {};
						query = decodeURIComponent(query);
						query.replace(/([^=]+)=([^&]*)(&|$)/g, function(){
							qa[arguments[1]] = arguments[2];
							return arguments[0];
						});
						return qa;
					})(match[4]),
					fragment: match[5]
				};
			};
			var obj = parse(url);
			$.extend(this, obj);
		},
		toString: function() {
			var str ='';
			if (this.scheme) str += this.scheme + '://';
			if (this.domain) str += this.domain;
			if (this.path) str += this.path;
			if (this.query.toString().length > 0) str += '?' + $.param(this.query);
			if (this.fragment) str += '#' + this.fragment.replace(/^#+/,'');
			return str;
		}
	});

	window.URL = URL;

	$.extend(juice, {
		'options': $.extend({}, new URL(juice.env.src).query),
		'log' : function() {
			if (typeof window.console != 'undefined') {
				console.log.apply(console, arguments);
			}
		}
	});
})(jQuery, j$);<commit_msg>Class bug fix<commit_after>(function($, juice) {

	/**
	 * OOP Style class definition helper
	 *
	 */
	var Klass = function(code){
		var klass = function() {
			var instance = (null != arguments[0] && this.__init__ &&
					'function' == typeof this.__init__)
				? code.__init__.apply(this, arguments)
				: this;
			return instance;
		};
		$.extend(klass, this);
		$.extend(klass.prototype, {
			'bind': function(type, fn) {
				this.__events__ = this.__events__ || {};
				this.__events__[type] = this.__events__[type] || [];
				this.__events__[type].push(fn);
				return this;
			},

			'unbind': function(type, fn) {
				if (this.__events__ && this.__events__[type]) {
					this.__events__[type].splice(this.__events__[type].indexOf(fn), 1);
				}
				return this;
			},

			'trigger': function(type, args){
				if (this.__events__ && this.__events__[type]){
					var evt = $.Event(type);
					evt.target = this;
					$.each(this.__events__[type], function(idx, fn) {
						fn.apply(this, $.merge([evt], args || []));
					});
				}
				return this;
			}
		}, code);

		klass.constructor = Klass;
		return klass;
	};

	var mixin = function(previous, current){
		if (previous && previous != current){
			var type = typeof current;
			if (type != typeof previous) return current;
			switch(type){
				case 'function':
					var merged = function(){
						this.parent = arguments.callee.parent;
						return current.apply(this, arguments);
					};
					merged.parent = previous;
					return merged;
				case 'object': return $.merge(previous, current);
			}
		}
		return current;
	};

	$.extend(true, Klass.prototype, {
		'extend': function(properties) {
			var proto = new this(null);
			for (var property in properties){
				var pp = proto[property];
				proto[property] = mixin(pp, properties[property]);
			}
			return new Klass(proto);
		},

		'implement': function() {
			for (var i = 0, l = arguments.length; i < l; i++)
				$.extend(this.prototype, arguments[i]);
		}
	});

	window.Class = function(code) {
		return new Klass(code);
	};

	/**
	 * URL
	 *
	 */

	var URL = Class({
		__init__: function(url) {
			var parse = function(url) {
				var ptn = /^(?=[^&])(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/;
				var match = ptn.exec(url);
				return {
					scheme  : match[1],
					domain  : match[2],
					path    : match[3],
					query   : (function(query) {
						var qa = {};
						query = decodeURIComponent(query);
						query.replace(/([^=]+)=([^&]*)(&|$)/g, function(){
							qa[arguments[1]] = arguments[2];
							return arguments[0];
						});
						return qa;
					})(match[4]),
					fragment: match[5]
				};
			};
			$.extend(this, parse(url));
		},
		toString: function() {
			var str ='';
			if (this.scheme) str += this.scheme + '://';
			if (this.domain) str += this.domain;
			if (this.path) str += this.path;
			if (this.query.toString().length > 0) str += '?' + $.param(this.query);
			if (this.fragment) str += '#' + this.fragment.replace(/^#+/,'');
			return str;
		}
	});

	window.URL = URL;

	$.extend(juice, {
		'options': $.extend({}, new URL(juice.env.src).query),
		'log' : function() {
			if (typeof window.console != 'undefined') {
				console.log.apply(console, arguments);
			}
		}
	});
})(jQuery, j$);<|endoftext|>


<commit_before>"use strict";

const $ = require("jquery");
const templates = require("../views");
const options = require("./options");
const renderPreview = require("./renderPreview");
const utils = require("./utils");
const sorting = require("./sorting");
const constants = require("./constants");
const condensed = require("./condensed");
const JoinChannel = require("./join-channel");
const helpers_parse = require("./libs/handlebars/parse");
const Userlist = require("./userlist");

const chat = $("#chat");
const sidebar = $("#sidebar");

require("intersection-observer");

const historyObserver = window.IntersectionObserver ?
	new window.IntersectionObserver(loadMoreHistory, {
		root: chat.get(0),
	}) : null;

module.exports = {
	appendMessage,
	buildChannelMessages,
	renderChannel,
	renderChannelUsers,
	renderNetworks,
	trimMessageInChannel,
};

function buildChannelMessages(container, chanId, chanType, messages) {
	return messages.reduce((docFragment, message) => {
		appendMessage(docFragment, chanId, chanType, message);
		return docFragment;
	}, container);
}

function appendMessage(container, chanId, chanType, msg) {
	if (utils.lastMessageId < msg.id) {
		utils.lastMessageId = msg.id;
	}

	let lastChild = container.children(".msg, .date-marker-container").last();
	const renderedMessage = buildChatMessage(msg);

	// Check if date changed
	const msgTime = new Date(msg.time);
	const prevMsgTime = new Date(lastChild.data("time"));

	// Insert date marker if date changed compared to previous message
	if (prevMsgTime.toDateString() !== msgTime.toDateString()) {
		lastChild = $(templates.date_marker({time: msg.time}));
		container.append(lastChild);
	}

	// If current window is not a channel or this message is not condensable,
	// then just append the message to container and be done with it
	if (constants.condensedTypes.indexOf(msg.type) === -1 || chanType !== "channel") {
		container.append(renderedMessage);
		return;
	}

	const obj = {};
	obj[msg.type] = 1;

	// If the previous message is already condensed,
	// we just append to it and update text
	if (lastChild.hasClass("condensed")) {
		lastChild.append(renderedMessage);
		condensed.updateText(lastChild, obj);
		return;
	}

	// Always create a condensed container
	const newCondensed = $(templates.msg_condensed({time: msg.time}));

	condensed.updateText(newCondensed, obj);
	newCondensed.append(renderedMessage);
	container.append(newCondensed);
}

function buildChatMessage(msg) {
	const type = msg.type;
	let template = "msg";

	// See if any of the custom highlight regexes match
	if (!msg.highlight && !msg.self
		&& options.highlightsRE
		&& (type === "message" || type === "notice")
		&& options.highlightsRE.exec(msg.text)) {
		msg.highlight = true;
	}

	if (typeof templates.actions[type] !== "undefined") {
		template = "msg_action";
	} else if (type === "unhandled") {
		template = "msg_unhandled";
	}

	const renderedMessage = $(templates[template](msg));
	const content = renderedMessage.find(".content");

	if (template === "msg_action") {
		content.html(templates.actions[type](msg));
	}

	msg.previews.forEach((preview) => {
		renderPreview(preview, renderedMessage);
	});

	return renderedMessage;
}

function renderChannel(data) {
	renderChannelMessages(data);

	if (data.type === "channel") {
		const users = renderChannelUsers(data);

		Userlist.handleKeybinds(users.find(".search"));
	}

	if (historyObserver) {
		historyObserver.observe(chat.find("#chan-" + data.id + " .show-more").get(0));
	}
}

function renderChannelMessages(data) {
	const documentFragment = buildChannelMessages($(document.createDocumentFragment()), data.id, data.type, data.messages);
	const channel = chat.find("#chan-" + data.id + " .messages").append(documentFragment);

	renderUnreadMarker($(templates.unread_marker()), data.firstUnread, channel);
}

function renderUnreadMarker(template, firstUnread, channel) {
	if (firstUnread > 0) {
		let first = channel.find("#msg-" + firstUnread);

		if (!first.length) {
			template.data("unread-id", firstUnread);
			channel.prepend(template);
		} else {
			const parent = first.parent();

			if (parent.hasClass("condensed")) {
				first = parent;
			}

			first.before(template);
		}
	} else {
		channel.append(template);
	}
}

function renderChannelUsers(data) {
	const users = chat.find("#chan-" + data.id).find(".userlist");
	const nicks = data.users
		.concat() // Make a copy of the user list, sort is applied in-place
		.sort((a, b) => b.lastMessage - a.lastMessage)
		.map((a) => a.nick);

	// Before re-rendering the list of names, there might have been an entry
	// marked as active (i.e. that was highlighted by keyboard navigation).
	// It is `undefined` if there was none.
	const previouslyActive = users.find(".active");

	const search = users
		.find(".search")
		.prop("placeholder", nicks.length + " " + (nicks.length === 1 ? "user" : "users"));

	users
		.data("nicks", nicks)
		.find(".names-original")
		.html(templates.user(data));

	// Refresh user search
	if (search.val().length) {
		search.trigger("input");
	}

	// If a nick was highlighted before re-rendering the lists, re-highlight it in
	// the newly-rendered list.
	if (previouslyActive.length > 0) {
		// We need to un-highlight everything first because triggering `input` with
		// a value highlights the first entry.
		users.find(".user").removeClass("active");
		users.find(`.user[data-name="${previouslyActive.data("name")}"]`).addClass("active");
	}

	return users;
}

function renderNetworks(data, singleNetwork) {
	sidebar.find(".empty").hide();
	sidebar.find(".networks").append(
		templates.network({
			networks: data.networks,
		})
	);

	// Add keyboard handlers to the "Join a channel…" form inputs/button
	JoinChannel.handleKeybinds();

	let newChannels;
	const channels = $.map(data.networks, function(n) {
		return n.channels;
	});

	if (!singleNetwork && utils.lastMessageId > -1) {
		newChannels = [];

		channels.forEach((channel) => {
			const chan = $("#chan-" + channel.id);

			if (chan.length > 0) {
				if (chan.data("type") === "channel") {
					chan
						.data("needsNamesRefresh", true)
						.find(".header .topic")
						.html(helpers_parse(channel.topic))
						.prop("title", channel.topic);
				}

				if (channel.messages.length > 0) {
					const container = chan.find(".messages");
					buildChannelMessages(container, channel.id, channel.type, channel.messages);

					const unreadMarker = container.find(".unread-marker").data("unread-id", 0);
					renderUnreadMarker(unreadMarker, channel.firstUnread, container);

					if (container.find(".msg").length >= 100) {
						container.find(".show-more").addClass("show");
					}

					container.parent().trigger("keepToBottom");
				}
			} else {
				newChannels.push(channel);
			}
		});
	} else {
		newChannels = channels;
	}

	if (newChannels.length > 0) {
		chat.append(
			templates.chat({
				channels: newChannels,
			})
		);

		newChannels.forEach((channel) => {
			renderChannel(channel);

			if (channel.type === "channel") {
				chat.find("#chan-" + channel.id).data("needsNamesRefresh", true);
			}
		});
	}

	utils.confirmExit();
	sorting();

	if (sidebar.find(".highlight").length) {
		utils.toggleNotificationMarkers(true);
	}
}

function trimMessageInChannel(channel, messageLimit) {
	const messages = channel.find(".messages .msg").slice(0, -messageLimit);

	if (messages.length === 0) {
		return;
	}

	messages.remove();

	channel.find(".show-more").addClass("show");

	// Remove date-separators that would otherwise be "stuck" at the top of the channel
	channel.find(".date-marker-container").each(function() {
		if ($(this).next().hasClass("date-marker-container")) {
			$(this).remove();
		}
	});
}

function loadMoreHistory(entries) {
	entries.forEach((entry) => {
		if (!entry.isIntersecting) {
			return;
		}

		const target = $(entry.target).find(".show-more-button");

		if (target.prop("disabled")) {
			return;
		}

		target.trigger("click");
	});
}

sidebar.on("click", ".collapse-network", (e) => {
	const collapseButton = $(e.target);

	collapseButton.closest(".network").toggleClass("collapsed");

	if (collapseButton.attr("aria-expanded") === "true") {
		collapseButton.attr("aria-expanded", false);
		collapseButton.attr("aria-label", "Expand");
	} else {
		collapseButton.attr("aria-expanded", true);
		collapseButton.attr("aria-label", "Collapse");
	}

	return false;
});
<commit_msg>Select lobby of network when collapsing network<commit_after>"use strict";

const $ = require("jquery");
const templates = require("../views");
const options = require("./options");
const renderPreview = require("./renderPreview");
const utils = require("./utils");
const sorting = require("./sorting");
const constants = require("./constants");
const condensed = require("./condensed");
const JoinChannel = require("./join-channel");
const helpers_parse = require("./libs/handlebars/parse");
const Userlist = require("./userlist");

const chat = $("#chat");
const sidebar = $("#sidebar");

require("intersection-observer");

const historyObserver = window.IntersectionObserver ?
	new window.IntersectionObserver(loadMoreHistory, {
		root: chat.get(0),
	}) : null;

module.exports = {
	appendMessage,
	buildChannelMessages,
	renderChannel,
	renderChannelUsers,
	renderNetworks,
	trimMessageInChannel,
};

function buildChannelMessages(container, chanId, chanType, messages) {
	return messages.reduce((docFragment, message) => {
		appendMessage(docFragment, chanId, chanType, message);
		return docFragment;
	}, container);
}

function appendMessage(container, chanId, chanType, msg) {
	if (utils.lastMessageId < msg.id) {
		utils.lastMessageId = msg.id;
	}

	let lastChild = container.children(".msg, .date-marker-container").last();
	const renderedMessage = buildChatMessage(msg);

	// Check if date changed
	const msgTime = new Date(msg.time);
	const prevMsgTime = new Date(lastChild.data("time"));

	// Insert date marker if date changed compared to previous message
	if (prevMsgTime.toDateString() !== msgTime.toDateString()) {
		lastChild = $(templates.date_marker({time: msg.time}));
		container.append(lastChild);
	}

	// If current window is not a channel or this message is not condensable,
	// then just append the message to container and be done with it
	if (constants.condensedTypes.indexOf(msg.type) === -1 || chanType !== "channel") {
		container.append(renderedMessage);
		return;
	}

	const obj = {};
	obj[msg.type] = 1;

	// If the previous message is already condensed,
	// we just append to it and update text
	if (lastChild.hasClass("condensed")) {
		lastChild.append(renderedMessage);
		condensed.updateText(lastChild, obj);
		return;
	}

	// Always create a condensed container
	const newCondensed = $(templates.msg_condensed({time: msg.time}));

	condensed.updateText(newCondensed, obj);
	newCondensed.append(renderedMessage);
	container.append(newCondensed);
}

function buildChatMessage(msg) {
	const type = msg.type;
	let template = "msg";

	// See if any of the custom highlight regexes match
	if (!msg.highlight && !msg.self
		&& options.highlightsRE
		&& (type === "message" || type === "notice")
		&& options.highlightsRE.exec(msg.text)) {
		msg.highlight = true;
	}

	if (typeof templates.actions[type] !== "undefined") {
		template = "msg_action";
	} else if (type === "unhandled") {
		template = "msg_unhandled";
	}

	const renderedMessage = $(templates[template](msg));
	const content = renderedMessage.find(".content");

	if (template === "msg_action") {
		content.html(templates.actions[type](msg));
	}

	msg.previews.forEach((preview) => {
		renderPreview(preview, renderedMessage);
	});

	return renderedMessage;
}

function renderChannel(data) {
	renderChannelMessages(data);

	if (data.type === "channel") {
		const users = renderChannelUsers(data);

		Userlist.handleKeybinds(users.find(".search"));
	}

	if (historyObserver) {
		historyObserver.observe(chat.find("#chan-" + data.id + " .show-more").get(0));
	}
}

function renderChannelMessages(data) {
	const documentFragment = buildChannelMessages($(document.createDocumentFragment()), data.id, data.type, data.messages);
	const channel = chat.find("#chan-" + data.id + " .messages").append(documentFragment);

	renderUnreadMarker($(templates.unread_marker()), data.firstUnread, channel);
}

function renderUnreadMarker(template, firstUnread, channel) {
	if (firstUnread > 0) {
		let first = channel.find("#msg-" + firstUnread);

		if (!first.length) {
			template.data("unread-id", firstUnread);
			channel.prepend(template);
		} else {
			const parent = first.parent();

			if (parent.hasClass("condensed")) {
				first = parent;
			}

			first.before(template);
		}
	} else {
		channel.append(template);
	}
}

function renderChannelUsers(data) {
	const users = chat.find("#chan-" + data.id).find(".userlist");
	const nicks = data.users
		.concat() // Make a copy of the user list, sort is applied in-place
		.sort((a, b) => b.lastMessage - a.lastMessage)
		.map((a) => a.nick);

	// Before re-rendering the list of names, there might have been an entry
	// marked as active (i.e. that was highlighted by keyboard navigation).
	// It is `undefined` if there was none.
	const previouslyActive = users.find(".active");

	const search = users
		.find(".search")
		.prop("placeholder", nicks.length + " " + (nicks.length === 1 ? "user" : "users"));

	users
		.data("nicks", nicks)
		.find(".names-original")
		.html(templates.user(data));

	// Refresh user search
	if (search.val().length) {
		search.trigger("input");
	}

	// If a nick was highlighted before re-rendering the lists, re-highlight it in
	// the newly-rendered list.
	if (previouslyActive.length > 0) {
		// We need to un-highlight everything first because triggering `input` with
		// a value highlights the first entry.
		users.find(".user").removeClass("active");
		users.find(`.user[data-name="${previouslyActive.data("name")}"]`).addClass("active");
	}

	return users;
}

function renderNetworks(data, singleNetwork) {
	sidebar.find(".empty").hide();
	sidebar.find(".networks").append(
		templates.network({
			networks: data.networks,
		})
	);

	// Add keyboard handlers to the "Join a channel…" form inputs/button
	JoinChannel.handleKeybinds();

	let newChannels;
	const channels = $.map(data.networks, function(n) {
		return n.channels;
	});

	if (!singleNetwork && utils.lastMessageId > -1) {
		newChannels = [];

		channels.forEach((channel) => {
			const chan = $("#chan-" + channel.id);

			if (chan.length > 0) {
				if (chan.data("type") === "channel") {
					chan
						.data("needsNamesRefresh", true)
						.find(".header .topic")
						.html(helpers_parse(channel.topic))
						.prop("title", channel.topic);
				}

				if (channel.messages.length > 0) {
					const container = chan.find(".messages");
					buildChannelMessages(container, channel.id, channel.type, channel.messages);

					const unreadMarker = container.find(".unread-marker").data("unread-id", 0);
					renderUnreadMarker(unreadMarker, channel.firstUnread, container);

					if (container.find(".msg").length >= 100) {
						container.find(".show-more").addClass("show");
					}

					container.parent().trigger("keepToBottom");
				}
			} else {
				newChannels.push(channel);
			}
		});
	} else {
		newChannels = channels;
	}

	if (newChannels.length > 0) {
		chat.append(
			templates.chat({
				channels: newChannels,
			})
		);

		newChannels.forEach((channel) => {
			renderChannel(channel);

			if (channel.type === "channel") {
				chat.find("#chan-" + channel.id).data("needsNamesRefresh", true);
			}
		});
	}

	utils.confirmExit();
	sorting();

	if (sidebar.find(".highlight").length) {
		utils.toggleNotificationMarkers(true);
	}
}

function trimMessageInChannel(channel, messageLimit) {
	const messages = channel.find(".messages .msg").slice(0, -messageLimit);

	if (messages.length === 0) {
		return;
	}

	messages.remove();

	channel.find(".show-more").addClass("show");

	// Remove date-separators that would otherwise be "stuck" at the top of the channel
	channel.find(".date-marker-container").each(function() {
		if ($(this).next().hasClass("date-marker-container")) {
			$(this).remove();
		}
	});
}

function loadMoreHistory(entries) {
	entries.forEach((entry) => {
		if (!entry.isIntersecting) {
			return;
		}

		const target = $(entry.target).find(".show-more-button");

		if (target.prop("disabled")) {
			return;
		}

		target.trigger("click");
	});
}

sidebar.on("click", ".collapse-network", (e) => {
	const collapseButton = $(e.target);

	if (collapseButton.closest(".network").find(".active").length > 0) {
		collapseButton.closest(".lobby").click();
	}

	collapseButton.closest(".network").toggleClass("collapsed");

	if (collapseButton.attr("aria-expanded") === "true") {
		collapseButton.attr("aria-expanded", false);
		collapseButton.attr("aria-label", "Expand");
	} else {
		collapseButton.attr("aria-expanded", true);
		collapseButton.attr("aria-label", "Collapse");
	}

	return false;
});
<|endoftext|>