<commit_before>const { app, Menu } = require('electron');
const _ = require('underscore-plus');
const MenuHelpers = require('../menu-helpers');

// Used to manage the global application menu.
//
// It's created by {AtomApplication} upon instantiation and used to add, remove
// and maintain the state of all menu items.
module.exports = class ApplicationMenu {
  constructor(version, autoUpdateManager) {
    this.version = version;
    this.autoUpdateManager = autoUpdateManager;
    this.windowTemplates = new WeakMap();
    this.setActiveTemplate(this.getDefaultTemplate());
    this.autoUpdateManager.on('state-changed', state =>
      this.showUpdateMenuItem(state)
    );
  }

  // Public: Updates the entire menu with the given keybindings.
  //
  // window - The BrowserWindow this menu template is associated with.
  // template - The Object which describes the menu to display.
  // keystrokesByCommand - An Object where the keys are commands and the values
  //                       are Arrays containing the keystroke.
  update(window, template, keystrokesByCommand) {
    this.translateTemplate(template, keystrokesByCommand);
    this.substituteVersion(template);
    this.windowTemplates.set(window, template);
    if (window === this.lastFocusedWindow)
      return this.setActiveTemplate(template);
  }

  setActiveTemplate(template) {
    if (!_.isEqual(template, this.activeTemplate)) {
      this.activeTemplate = template;
      this.menu = Menu.buildFromTemplate(_.deepClone(template));
      Menu.setApplicationMenu(this.menu);
    }

    return this.showUpdateMenuItem(this.autoUpdateManager.getState());
  }

  // Register a BrowserWindow with this application menu.
  addWindow(window) {
    if (this.lastFocusedWindow == null) this.lastFocusedWindow = window;

    const focusHandler = () => {
      this.lastFocusedWindow = window;
      const template = this.windowTemplates.get(window);
      if (template) this.setActiveTemplate(template);
    };

    window.on('focus', focusHandler);
    window.once('closed', () => {
      if (window === this.lastFocusedWindow) this.lastFocusedWindow = null;
      this.windowTemplates.delete(window);
      window.removeListener('focus', focusHandler);
    });

    this.enableWindowSpecificItems(true);
  }

  // Flattens the given menu and submenu items into an single Array.
  //
  // menu - A complete menu configuration object for atom-shell's menu API.
  //
  // Returns an Array of native menu items.
  flattenMenuItems(menu) {
    const object = menu.items || {};
    let items = [];
    for (let index in object) {
      const item = object[index];
      items.push(item);
      if (item.submenu)
        items = items.concat(this.flattenMenuItems(item.submenu));
    }
    return items;
  }

  // Flattens the given menu template into an single Array.
  //
  // template - An object describing the menu item.
  //
  // Returns an Array of native menu items.
  flattenMenuTemplate(template) {
    let items = [];
    for (let item of template) {
      items.push(item);
      if (item.submenu)
        items = items.concat(this.flattenMenuTemplate(item.submenu));
    }
    return items;
  }

  // Public: Used to make all window related menu items are active.
  //
  // enable - If true enables all window specific items, if false disables all
  //          window specific items.
  enableWindowSpecificItems(enable) {
    for (let item of this.flattenMenuItems(this.menu)) {
      if (item.metadata && item.metadata.windowSpecific) item.enabled = enable;
    }
  }

  // Replaces VERSION with the current version.
  substituteVersion(template) {
    let item = this.flattenMenuTemplate(template).find(
      ({ label }) => label === 'VERSION'
    );
    if (item) item.label = `Version ${this.version}`;
  }

  // Sets the proper visible state the update menu items
  showUpdateMenuItem(state) {
    const items = this.flattenMenuItems(this.menu);
    const checkForUpdateItem = items.find(
      ({ id }) => id === 'Check for Update'
    );
    const checkingForUpdateItem = items.find(
      ({ id }) => id === 'Checking for Update'
    );
    const downloadingUpdateItem = items.find(
      // ({ label }) => label === 'Downloading Update'
      ({ id }) => id === 'Downloading Update'
    );
    const installUpdateItem = items.find(
      // ({ label }) => label === 'Restart and Install Update'
      ({ id }) => id === 'Restart and Install Update'
    );

    if (
      !checkForUpdateItem ||
      !checkingForUpdateItem ||
      !downloadingUpdateItem ||
      !installUpdateItem
    )
      return;

    checkForUpdateItem.visible = false;
    checkingForUpdateItem.visible = false;
    downloadingUpdateItem.visible = false;
    installUpdateItem.visible = false;

    switch (state) {
      case 'idle':
      case 'error':
      case 'no-update-available':
        checkForUpdateItem.visible = true;
        break;
      case 'checking':
        checkingForUpdateItem.visible = true;
        break;
      case 'downloading':
        downloadingUpdateItem.visible = true;
        break;
      case 'update-available':
        installUpdateItem.visible = true;
        break;
    }
  }

  // Default list of menu items.
  //
  // Returns an Array of menu item Objects.
  getDefaultTemplate() {
    return [
      {
        label: 'Atom',
        id: 'Atom',
        submenu: [
          {
            label: 'Check for Update',
            id: 'Check for Update',
            metadata: { autoUpdate: true }
          },
          {
            label: 'Reload',
            id: 'Reload',
            accelerator: 'Command+R',
            click: () => {
              const window = this.focusedWindow();
              if (window) window.reload();
            }
          },
          {
            label: 'Close Window',
            id: 'Close Window',
            accelerator: 'Command+Shift+W',
            click: () => {
              const window = this.focusedWindow();
              if (window) window.close();
            }
          },
          {
            label: 'Toggle Dev Tools',
            id: 'Toggle Dev Tools',
            accelerator: 'Command+Alt+I',
            click: () => {
              const window = this.focusedWindow();
              if (window) window.toggleDevTools();
            }
          },
          {
            label: 'Quit',
            id: 'Quit',
            accelerator: 'Command+Q',
            click: () => app.quit()
          }
        ]
      }
    ];
  }

  focusedWindow() {
    return global.atomApplication
      .getAllWindows()
      .find(window => window.isFocused());
  }

  // Combines a menu template with the appropriate keystroke.
  //
  // template - An Object conforming to atom-shell's menu api but lacking
  //            accelerator and click properties.
  // keystrokesByCommand - An Object where the keys are commands and the values
  //                       are Arrays containing the keystroke.
  //
  // Returns a complete menu configuration object for atom-shell's menu API.
  translateTemplate(template, keystrokesByCommand) {
    template.forEach(item => {
      if (item.metadata == null) item.metadata = {};
      if (item.command) {
        const keystrokes = keystrokesByCommand[item.command];
        if (keystrokes && keystrokes.length > 0) {
          const keystroke = keystrokes[0];
          // Electron does not support multi-keystroke accelerators. Therefore,
          // when the command maps to a multi-stroke key binding, show the
          // keystrokes next to the item's label.
          if (keystroke.includes(' ')) {
            item.label += ` [${_.humanizeKeystroke(keystroke)}]`;
          } else {
            item.accelerator = MenuHelpers.acceleratorForKeystroke(keystroke);
          }
        }
        item.click = () =>
          global.atomApplication.sendCommand(item.command, item.commandDetail);
        if (!/^application:/.test(item.command)) {
          item.metadata.windowSpecific = true;
        }
      }
      if (item.submenu)
        this.translateTemplate(item.submenu, keystrokesByCommand);
    });
    return template;
  }
};
<commit_msg>Update src/main-process/application-menu.js<commit_after>const { app, Menu } = require('electron');
const _ = require('underscore-plus');
const MenuHelpers = require('../menu-helpers');

// Used to manage the global application menu.
//
// It's created by {AtomApplication} upon instantiation and used to add, remove
// and maintain the state of all menu items.
module.exports = class ApplicationMenu {
  constructor(version, autoUpdateManager) {
    this.version = version;
    this.autoUpdateManager = autoUpdateManager;
    this.windowTemplates = new WeakMap();
    this.setActiveTemplate(this.getDefaultTemplate());
    this.autoUpdateManager.on('state-changed', state =>
      this.showUpdateMenuItem(state)
    );
  }

  // Public: Updates the entire menu with the given keybindings.
  //
  // window - The BrowserWindow this menu template is associated with.
  // template - The Object which describes the menu to display.
  // keystrokesByCommand - An Object where the keys are commands and the values
  //                       are Arrays containing the keystroke.
  update(window, template, keystrokesByCommand) {
    this.translateTemplate(template, keystrokesByCommand);
    this.substituteVersion(template);
    this.windowTemplates.set(window, template);
    if (window === this.lastFocusedWindow)
      return this.setActiveTemplate(template);
  }

  setActiveTemplate(template) {
    if (!_.isEqual(template, this.activeTemplate)) {
      this.activeTemplate = template;
      this.menu = Menu.buildFromTemplate(_.deepClone(template));
      Menu.setApplicationMenu(this.menu);
    }

    return this.showUpdateMenuItem(this.autoUpdateManager.getState());
  }

  // Register a BrowserWindow with this application menu.
  addWindow(window) {
    if (this.lastFocusedWindow == null) this.lastFocusedWindow = window;

    const focusHandler = () => {
      this.lastFocusedWindow = window;
      const template = this.windowTemplates.get(window);
      if (template) this.setActiveTemplate(template);
    };

    window.on('focus', focusHandler);
    window.once('closed', () => {
      if (window === this.lastFocusedWindow) this.lastFocusedWindow = null;
      this.windowTemplates.delete(window);
      window.removeListener('focus', focusHandler);
    });

    this.enableWindowSpecificItems(true);
  }

  // Flattens the given menu and submenu items into an single Array.
  //
  // menu - A complete menu configuration object for atom-shell's menu API.
  //
  // Returns an Array of native menu items.
  flattenMenuItems(menu) {
    const object = menu.items || {};
    let items = [];
    for (let index in object) {
      const item = object[index];
      items.push(item);
      if (item.submenu)
        items = items.concat(this.flattenMenuItems(item.submenu));
    }
    return items;
  }

  // Flattens the given menu template into an single Array.
  //
  // template - An object describing the menu item.
  //
  // Returns an Array of native menu items.
  flattenMenuTemplate(template) {
    let items = [];
    for (let item of template) {
      items.push(item);
      if (item.submenu)
        items = items.concat(this.flattenMenuTemplate(item.submenu));
    }
    return items;
  }

  // Public: Used to make all window related menu items are active.
  //
  // enable - If true enables all window specific items, if false disables all
  //          window specific items.
  enableWindowSpecificItems(enable) {
    for (let item of this.flattenMenuItems(this.menu)) {
      if (item.metadata && item.metadata.windowSpecific) item.enabled = enable;
    }
  }

  // Replaces VERSION with the current version.
  substituteVersion(template) {
    let item = this.flattenMenuTemplate(template).find(
      ({ label }) => label === 'VERSION'
    );
    if (item) item.label = `Version ${this.version}`;
  }

  // Sets the proper visible state the update menu items
  showUpdateMenuItem(state) {
    const items = this.flattenMenuItems(this.menu);
    const checkForUpdateItem = items.find(
      ({ id }) => id === 'Check for Update'
    );
    const checkingForUpdateItem = items.find(
      ({ id }) => id === 'Checking for Update'
    );
    const downloadingUpdateItem = items.find(
      ({ id }) => id === 'Downloading Update'
    );
    const installUpdateItem = items.find(
      // ({ label }) => label === 'Restart and Install Update'
      ({ id }) => id === 'Restart and Install Update'
    );

    if (
      !checkForUpdateItem ||
      !checkingForUpdateItem ||
      !downloadingUpdateItem ||
      !installUpdateItem
    )
      return;

    checkForUpdateItem.visible = false;
    checkingForUpdateItem.visible = false;
    downloadingUpdateItem.visible = false;
    installUpdateItem.visible = false;

    switch (state) {
      case 'idle':
      case 'error':
      case 'no-update-available':
        checkForUpdateItem.visible = true;
        break;
      case 'checking':
        checkingForUpdateItem.visible = true;
        break;
      case 'downloading':
        downloadingUpdateItem.visible = true;
        break;
      case 'update-available':
        installUpdateItem.visible = true;
        break;
    }
  }

  // Default list of menu items.
  //
  // Returns an Array of menu item Objects.
  getDefaultTemplate() {
    return [
      {
        label: 'Atom',
        id: 'Atom',
        submenu: [
          {
            label: 'Check for Update',
            id: 'Check for Update',
            metadata: { autoUpdate: true }
          },
          {
            label: 'Reload',
            id: 'Reload',
            accelerator: 'Command+R',
            click: () => {
              const window = this.focusedWindow();
              if (window) window.reload();
            }
          },
          {
            label: 'Close Window',
            id: 'Close Window',
            accelerator: 'Command+Shift+W',
            click: () => {
              const window = this.focusedWindow();
              if (window) window.close();
            }
          },
          {
            label: 'Toggle Dev Tools',
            id: 'Toggle Dev Tools',
            accelerator: 'Command+Alt+I',
            click: () => {
              const window = this.focusedWindow();
              if (window) window.toggleDevTools();
            }
          },
          {
            label: 'Quit',
            id: 'Quit',
            accelerator: 'Command+Q',
            click: () => app.quit()
          }
        ]
      }
    ];
  }

  focusedWindow() {
    return global.atomApplication
      .getAllWindows()
      .find(window => window.isFocused());
  }

  // Combines a menu template with the appropriate keystroke.
  //
  // template - An Object conforming to atom-shell's menu api but lacking
  //            accelerator and click properties.
  // keystrokesByCommand - An Object where the keys are commands and the values
  //                       are Arrays containing the keystroke.
  //
  // Returns a complete menu configuration object for atom-shell's menu API.
  translateTemplate(template, keystrokesByCommand) {
    template.forEach(item => {
      if (item.metadata == null) item.metadata = {};
      if (item.command) {
        const keystrokes = keystrokesByCommand[item.command];
        if (keystrokes && keystrokes.length > 0) {
          const keystroke = keystrokes[0];
          // Electron does not support multi-keystroke accelerators. Therefore,
          // when the command maps to a multi-stroke key binding, show the
          // keystrokes next to the item's label.
          if (keystroke.includes(' ')) {
            item.label += ` [${_.humanizeKeystroke(keystroke)}]`;
          } else {
            item.accelerator = MenuHelpers.acceleratorForKeystroke(keystroke);
          }
        }
        item.click = () =>
          global.atomApplication.sendCommand(item.command, item.commandDetail);
        if (!/^application:/.test(item.command)) {
          item.metadata.windowSpecific = true;
        }
      }
      if (item.submenu)
        this.translateTemplate(item.submenu, keystrokesByCommand);
    });
    return template;
  }
};
<|endoftext|>


<commit_before>
var Show_Say           = $('#Write_To_Chat_Room');
var IN_CHAT_ROOM       = false;
var LAST_CHAT_MSG_DATE = null;
var MAX_CHAT_MSG_TOTAL = 250;
var TOTAL_CHAT_MSG     = 0;

function official_chat_msg(msg) {
  draw_chat_msg( 'div.official.chat_msg', msg );
}

function official_error_chat_msg(msg) {
  draw_chat_msg( 'div.official.chat_msg.error_msg', msg );
}

function me_mb_msg(o) {
  $('#Message_Board').find('div.msgs').prepend( compile_template('div.me_msg', o) );
}

function mb_msg(o) {
  if (_.isArray(o)) {
    _.each(o.slice().reverse(), function (m) {
      mb_msg(m);
    });
    return false;
  }

  $('#Message_Board').find('div.msgs').prepend( compile_template('div.msg', o) );
}

function me_chat_msg(msg) {
  draw_chat_msg( 'div.me_chat_msg', msg );
}

function chat_msg(msg) {
  draw_chat_msg( 'div.chat_msg', msg );
}

function draw_chat_msg(sel, msg) {
  TOTAL_CHAT_MSG += 1;
  $('#Chat_Msgs').prepend( compile_template(sel, msg) );
  if (TOTAL_CHAT_MSG > MAX_CHAT_MSG_TOTAL) {
    $('#Chat_Msgs').find('div.chat_msg').last().remove();
  }
}

function screen_name(name) {
  var parent = $('#Other_Screen_Names');
  var li = $('

');
  li.find('a').attr('href', "/me/" + name);
  li.find('a').text(name);

  parent.find('ul').prepend(li);
  $('#Other_Screen_Names').show();
}

$(function () {

  toggles("#Message_Board div.show_write a", "#Write_Message a.cancel");

  // ============================================
  // ================ Show lifes.................
  // ============================================
  if ($('#Other_Screen_Names').length) {
    var lifes = $.trim($(read_template('div.screen_names')).text()).split(/\s+/);
    var SN = $.trim($(read_template('div.screen_name')).text()).toUpperCase();

    _.each(lifes, function (l) {
      if (SN != l.toUpperCase())
        screen_name(l);
    });
  }

  // ============================================
  // ================ Create life................
  // ============================================
  if ($('#New_Life').length)
    form('#Create_Screen_Name', function (f) {
      f.at_least_one_not_empty('input[name="screen_name"]');
      f.on_success(function (result) {
        f.find('div.success').hide();
        screen_name(result.screen_name);
      });
    });

  // ============================================
  // ================ Post a message board msg...
  // ============================================
  form('#Write_Message', function (f) {
    f.at_least_one_not_empty('textarea');
    f.on_success(function (result) {
      f.find('div.success').hide();
      me_mb_msg(result.mb_msg);
      f.find('a.cancel').click();
    });
  });

  // ============================================
  // ================ Grab message board msgs....
  // ============================================
  post('/message_board/msgs', {}, function (err, o) {
    var div_loading = $('#Message_Board div.msgs div.loading');

    if (err) {
      log(err);
      div_loading.addClass('error_msg');
      div_loading.removeClass('loading');
      div_loading.text("Messages could not be retrieved at this time. Try again later by refreshing this page.");
      return false;
    }

    div_loading.remove();
    mb_msg(o.list);
  });

  // ============================================
  // ================ Grab chat room msgs........
  // ============================================
  every_secs(2, function () {
    if ( !IN_CHAT_ROOM )
      return false;
    post("/chat_room/msgs", {after: LAST_CHAT_MSG_DATE}, function (err, o) {
      if (err) {
        log(err);
        return false;
      }
      _.each(o.list, function (m) {
        chat_msg(m);
      });
    });
  });

  // ============================================
  // ================ ENTER The Chat Room........
  // ============================================
  on_click("#Enter_Chat_Room a", function (e) {
    $('#Enter_Chat_Room div.error_msg').hide();
    swap_display('#Home_Page', '#Chat_Room');
    official_chat_msg({
      body: "Entering chat room... please wait..."
    });

    // Enter the Chat Room...
    post("/chat_room/enter", {}, function (err, o) {
      IN_CHAT_ROOM = false;
      if (err) {
        log(err);
        in_secs(5, function () {
          official_error_chat_msg({body: "Your attempt to enter the chat room failed."});
          $('#Home_Page').show();
          $('#Chat_Room').hide();
          $('#Enter_Chat_Room div.error_msg').text('Your attempt to enter the chat room failed. Try again in a few minutes.');
          $('#Enter_Chat_Room div.error_msg').show();
        });
        return false;
      }

      IN_CHAT_ROOM = true;
      Show_Say.show();
      $('#Enter_Chat_Room div.error_msg').hide();
      official_chat_msg({body: o.msg});
    });

    return false;
  });

  // ============================================
  // ================ Talk to the Chat Room......
  // ============================================
  form('#Write_To_Chat_Room', function (f) {
    f.at_least_one_not_empty('textarea');
    f.on_success(function (result) {
      f.find('div.success').hide();
      me_chat_msg(result.chat_msg);
    });
  });

  // ============================================
  // ================ LEAVE The Chat Room........
  // ============================================
  on_click("#Leave_Chat_Room a", function (e) {
    IN_CHAT_ROOM = false;
    Show_Say.hide();
    swap_display('#Home_Page', '#Chat_Room');
    official_chat_msg({
      body: "Sending message that you are leaving..."
    });

    post("/chat_room/leave", {}, function (err, msg) {
      if (err) {
        log(err);
        return false;
      }

      official_chat_msg({body: msg.msg || "You are now OUT of the chat room."});
    });
    return false;
  });

});

// ========= OLD CODE =================
//
  // form('#Create_Folder form', function (f) {
    // f.on_success(function (result) {
      // log(result);
      // var new_folder = compile_template('div.folder', {'TITLE': result.name, 'LOCATION': result.location});
      // $('div.boxs').prepend(new_folder);
    // });

    // var path          = window.location.pathname;
    // var parent        = $(this).parent();
    // var orig_text     = $(this).text();
    // var link          = $(this);
    // var id            = 'create_folder_loading' ;
    // var ele           = $('
Processing...
');

    // $(this).after(ele);
    // $(this).hide();

    // post((path + '/create/folder').replace('//', '/'), function (err, results) {
      // ele.remove();

      // if (err) {

        // log(err, results);

        // var err_id = 'create_folder_error';
        // var min_15  = (1000 * 60 * 15);
        // link.after($('
Error occurred. Try again in...
'));
        // every_sec($(parent).find('div.' + err_id), function (target, since) {
          // if (since > min_15) {
            // link.show();
            // target.remove();
            // return;
          // }
          // target.text('Error occurred. Try again in ' + min_sec(min_15 - since) + ' mins.');
          // return true;
        // });

        // return;
      // }

      // link.show();
      // var succ = $('
Your new folder is at: HREF
'.replace(/HREF/g, results.location));
      // link.after(succ);

    // });

    // log(orig_text);
  // });

<commit_msg>Better usability for life creation.<commit_after>
var Show_Say           = $('#Write_To_Chat_Room');
var IN_CHAT_ROOM       = false;
var LAST_CHAT_MSG_DATE = null;
var MAX_CHAT_MSG_TOTAL = 250;
var TOTAL_CHAT_MSG     = 0;

function official_chat_msg(msg) {
  draw_chat_msg( 'div.official.chat_msg', msg );
}

function official_error_chat_msg(msg) {
  draw_chat_msg( 'div.official.chat_msg.error_msg', msg );
}

function me_mb_msg(o) {
  $('#Message_Board').find('div.msgs').prepend( compile_template('div.me_msg', o) );
}

function mb_msg(o) {
  if (_.isArray(o)) {
    _.each(o.slice().reverse(), function (m) {
      mb_msg(m);
    });
    return false;
  }

  $('#Message_Board').find('div.msgs').prepend( compile_template('div.msg', o) );
}

function me_chat_msg(msg) {
  draw_chat_msg( 'div.me_chat_msg', msg );
}

function chat_msg(msg) {
  draw_chat_msg( 'div.chat_msg', msg );
}

function draw_chat_msg(sel, msg) {
  TOTAL_CHAT_MSG += 1;
  $('#Chat_Msgs').prepend( compile_template(sel, msg) );
  if (TOTAL_CHAT_MSG > MAX_CHAT_MSG_TOTAL) {
    $('#Chat_Msgs').find('div.chat_msg').last().remove();
  }
}

function screen_name(name) {
  var parent = $('#Other_Screen_Names');
  var li = $('

');
  li.find('a').attr('href', "/me/" + name);
  li.find('a').text(name);

  parent.find('ul').prepend(li);
  $('#Other_Screen_Names').show();
}

$(function () {

  toggles("#Message_Board div.show_write a", "#Write_Message a.cancel");

  // ============================================
  // ================ Show lifes.................
  // ============================================
  if ($('#Other_Screen_Names').length) {
    var lifes = $.trim($(read_template('div.screen_names')).text()).split(/\s+/);
    var SN = $.trim($(read_template('div.screen_name')).text()).toUpperCase();

    _.each(lifes, function (l) {
      if (SN != l.toUpperCase())
        screen_name(l);
    });
  }

  // ============================================
  // ================ Create life................
  // ============================================
  if ($('#New_Life').length)
    form('#Create_Screen_Name', function (f) {
      f.at_least_one_not_empty('input[name="screen_name"]');
      f.on_success(function (result) {
        f.find('div.success').html('Your new life is at: okdoki.com/me/SN'.replace(/SN/g, result.screen_name));
        screen_name(result.screen_name);
      });
    });

  // ============================================
  // ================ Post a message board msg...
  // ============================================
  form('#Write_Message', function (f) {
    f.at_least_one_not_empty('textarea');
    f.on_success(function (result) {
      f.find('div.success').hide();
      me_mb_msg(result.mb_msg);
      f.find('a.cancel').click();
    });
  });

  // ============================================
  // ================ Grab message board msgs....
  // ============================================
  post('/message_board/msgs', {}, function (err, o) {
    var div_loading = $('#Message_Board div.msgs div.loading');

    if (err) {
      log(err);
      div_loading.addClass('error_msg');
      div_loading.removeClass('loading');
      div_loading.text("Messages could not be retrieved at this time. Try again later by refreshing this page.");
      return false;
    }

    div_loading.remove();
    mb_msg(o.list);
  });

  // ============================================
  // ================ Grab chat room msgs........
  // ============================================
  every_secs(2, function () {
    if ( !IN_CHAT_ROOM )
      return false;
    post("/chat_room/msgs", {after: LAST_CHAT_MSG_DATE}, function (err, o) {
      if (err) {
        log(err);
        return false;
      }
      _.each(o.list, function (m) {
        chat_msg(m);
      });
    });
  });

  // ============================================
  // ================ ENTER The Chat Room........
  // ============================================
  on_click("#Enter_Chat_Room a", function (e) {
    $('#Enter_Chat_Room div.error_msg').hide();
    swap_display('#Home_Page', '#Chat_Room');
    official_chat_msg({
      body: "Entering chat room... please wait..."
    });

    // Enter the Chat Room...
    post("/chat_room/enter", {}, function (err, o) {
      IN_CHAT_ROOM = false;
      if (err) {
        log(err);
        in_secs(5, function () {
          official_error_chat_msg({body: "Your attempt to enter the chat room failed."});
          $('#Home_Page').show();
          $('#Chat_Room').hide();
          $('#Enter_Chat_Room div.error_msg').text('Your attempt to enter the chat room failed. Try again in a few minutes.');
          $('#Enter_Chat_Room div.error_msg').show();
        });
        return false;
      }

      IN_CHAT_ROOM = true;
      Show_Say.show();
      $('#Enter_Chat_Room div.error_msg').hide();
      official_chat_msg({body: o.msg});
    });

    return false;
  });

  // ============================================
  // ================ Talk to the Chat Room......
  // ============================================
  form('#Write_To_Chat_Room', function (f) {
    f.at_least_one_not_empty('textarea');
    f.on_success(function (result) {
      f.find('div.success').hide();
      me_chat_msg(result.chat_msg);
    });
  });

  // ============================================
  // ================ LEAVE The Chat Room........
  // ============================================
  on_click("#Leave_Chat_Room a", function (e) {
    IN_CHAT_ROOM = false;
    Show_Say.hide();
    swap_display('#Home_Page', '#Chat_Room');
    official_chat_msg({
      body: "Sending message that you are leaving..."
    });

    post("/chat_room/leave", {}, function (err, msg) {
      if (err) {
        log(err);
        return false;
      }

      official_chat_msg({body: msg.msg || "You are now OUT of the chat room."});
    });
    return false;
  });

});

// ========= OLD CODE =================
//
  // form('#Create_Folder form', function (f) {
    // f.on_success(function (result) {
      // log(result);
      // var new_folder = compile_template('div.folder', {'TITLE': result.name, 'LOCATION': result.location});
      // $('div.boxs').prepend(new_folder);
    // });

    // var path          = window.location.pathname;
    // var parent        = $(this).parent();
    // var orig_text     = $(this).text();
    // var link          = $(this);
    // var id            = 'create_folder_loading' ;
    // var ele           = $('
Processing...
');

    // $(this).after(ele);
    // $(this).hide();

    // post((path + '/create/folder').replace('//', '/'), function (err, results) {
      // ele.remove();

      // if (err) {

        // log(err, results);

        // var err_id = 'create_folder_error';
        // var min_15  = (1000 * 60 * 15);
        // link.after($('
Error occurred. Try again in...
'));
        // every_sec($(parent).find('div.' + err_id), function (target, since) {
          // if (since > min_15) {
            // link.show();
            // target.remove();
            // return;
          // }
          // target.text('Error occurred. Try again in ' + min_sec(min_15 - since) + ' mins.');
          // return true;
        // });

        // return;
      // }

      // link.show();
      // var succ = $('
Your new folder is at: HREF
'.replace(/HREF/g, results.location));
      // link.after(succ);

    // });

    // log(orig_text);
  // });

<|endoftext|>


<commit_before>$( function() {

  var $setTrueButton = $( '.set-true' ),
      $setFalseButton = $( '.set-false' );

  var setter = undefined;

  $setTrueButton.on( 'click', function() {
    setter = true;
    console.log( "variable setter is now: ", setter );
    changerFunc = function() {
      console.log( "poop alarm is for real" );
    }
    changerFunc();
  });

  $setFalseButton.on( 'click', function() {
    setter = false;
    console.log( "variable setter is now: ", setter );
    changerFunc = function() {
      console.log( "false poop alarm" )
    }
    changerFunc();
  });

});
<commit_msg>Conclusion: Test failed. Read README.<commit_after>$( function() {

  var $setTrueButton = $( '.set-true' ),
      $setFalseButton = $( '.set-false' );

  var setter = undefined;

  $setTrueButton.on( 'click', function() {
    setter = true;
    console.log( "variable setter is now: ", setter );
    changerFunc = function() {
      console.log( "poop alarm is for real" );
    }
    changerFunc();
  });

  $setFalseButton.on( 'click', function() {
    setter = false;
    console.log( "variable setter is now: ", setter );
    changerFunc = function() {
      console.log( "false poop alarm" )
    }
    changerFunc();
  });

});

/****************************
**
** The code below is the same code as above but recoded
** in Revealing Modular Pattern design.
**
*****************************/

var TestModule = ( function( window, undefined ) {

  var $setTrueButton = $( '.set-true' ),
      $setFalseButton = $( '.set-false' ),
      $messagebox = $( '.messagebox' );

  var setter = undefined;

  function setTrue() {
    setter = true;
  }

  function setFalse() {
    setter = false;
  }

  function clickHandlers() {
    $setTrueButton.on( 'click', setTrue );
    $setFalseButton.on( 'click', setFalse );
  }

  return {
    clickEvents : clickHandlers
  };

} )( window );

TestModule.clickEvents();
<|endoftext|>


<commit_before>const test = require('tape');
const nvar = require('../lib');

// Helper to initialise new instances for each test.
function nv(source) {return nvar({source, target: Object.create(null)});}

// Canon: https://www.gnu.org/software/bash/manual/html_node/Single-Quotes.html
test('Escaping with single-quotes', function (t) {
  t.deepEqual(nv("toast='kaya'"), {toast: 'kaya'}, 'Does not include surrounding quotes in final value.');
  t.deepEqual(nv("toast='  kaya toast\t'"), {toast: '  kaya toast\t'}, 'Treats spaces and tabs literally.');
  t.deepEqual(nv("toast='kaya\ntoast'"), {toast: 'kaya\ntoast'}, 'Treats newlines literally.');
  t.deepEqual(nv("science='\\$\\`\\\n\\\\'"), {science: '\\$\\`\\\n\\\\'}, 'Prevents backslash-escaping.');
  t.deepEqual(nv("science='`~!@#$%^&*()-=_+[]\\{}|;:\",./<>?'"), {science: '`~!@#$%^&*()-=_+[]\\{}|;:",./<>?'}, 'Treats all other symbol characters (except single-quotes) literally.');

  t.end();
});
<commit_msg>Spec basic unquoted assignment.<commit_after>const test = require('tape');
const nvar = require('../lib');

// Helper to initialise new instances for each test.
function nv(source) {return nvar({source, target: Object.create(null)});}

test('Unquoted values', function (t) {
  t.deepEqual(nv('toast=kaya'), {toast: 'kaya'}, 'Handles basic unquoted assignment.');
  t.deepEqual(nv('toast=kaya nope'), {toast: 'kaya'}, 'Ignores non-assignments.');
  t.deepEqual(nv('toast=kaya eggs=hardboiled nope nope nope'), {toast: 'kaya', eggs: 'hardboiled'}, 'Accepts multiple assignments at the start of a single line.');
  t.deepEqual(nv('toast=kaya nope sorry=darling'), {toast: 'kaya'}, 'Ignores assignment-like statements once a non-assignment has been encountered.');

  t.end();
});

// Canon: https://www.gnu.org/software/bash/manual/html_node/Single-Quotes.html
test('Escaping with single-quotes', function (t) {
  t.deepEqual(nv("toast='kaya'"), {toast: 'kaya'}, 'Does not include surrounding quotes in final value.');
  t.deepEqual(nv("toast='  kaya toast\t'"), {toast: '  kaya toast\t'}, 'Treats spaces and tabs literally.');
  t.deepEqual(nv("toast='kaya\ntoast'"), {toast: 'kaya\ntoast'}, 'Treats newlines literally.');
  t.deepEqual(nv("science='\\$\\`\\\n\\\\'"), {science: '\\$\\`\\\n\\\\'}, 'Prevents backslash-escaping.');
  t.deepEqual(nv("science='`~!@#$%^&*()-=_+[]\\{}|;:\",./<>?'"), {science: '`~!@#$%^&*()-=_+[]\\{}|;:",./<>?'}, 'Treats all other symbol characters (except single-quotes) literally.');

  t.end();
});
<|endoftext|>


<commit_before>import {getDraft, mockSVGElement} from './Bootstrap.js';

import Draft     from '../src/Draft.js';
import Symbols   from '../src/helpers/Symbols.js';
import Middleman from '../src/helpers/Middleman.js';
import Rectangle from '../src/shapes/Rectangle.js';

describe('Draft', () => {

    it('Should be able to instantiate the constructor function;', () => {
        expect(getDraft() instanceof Draft).toBeTruthy();
    });

    it('Should be able to setup the D3 using the passed in element;', () => {

        const draft = getDraft();
        expect(mockSVGElement.getAttribute('width')).toEqual('100%');
        expect(mockSVGElement.getAttribute('height')).toEqual('100%');
        expect(Array.isArray(draft[Symbols.SVG])).toBeTruthy();
        expect(draft[Symbols.SVG][0][0]).toEqual(mockSVGElement);

    });

    it('Should be able to pass in options that override the defaults;', () => {

        const draft   = getDraft({ documentHeight: '50%', gridSize: 5 });
        const options = draft[Symbols.OPTIONS];

        expect(options.documentHeight).toEqual('50%');
        expect(options.documentWidth).toEqual('100%');
        expect(draft.options().gridSize).toEqual(5);

    });

    it('Should be able to manage shapes with add, remove, clear, list;', () => {

        const draft  = getDraft();
        const shapes = { first: new Rectangle(), second: new Rectangle() };

        expect(draft.all().length).toEqual(0);
        draft.add(shapes.first);
        draft.add(shapes.second);
        expect(draft.all().length).toEqual(2);
        draft.remove(shapes.first);
        expect(draft.all().length).toEqual(1);
        draft.remove(shapes.second);
        expect(draft.all().length).toEqual(0);

        draft.add(shapes.first);
        draft.add(shapes.second);
        expect(draft.all().length).toEqual(2);
        draft.clear();
        expect(draft.all().length).toEqual(0);

    });

    it('Should be able to add the middleman object to each added shape;', () => {

        const draft = getDraft();
        const shape = new Rectangle();

        expect(draft.add(shape)).toEqual(shape);
        expect(shape[Symbols.MIDDLEMAN] instanceof Middleman).toBeTruthy();

    });

    it('Should be able to invoke the callback hooks from the invocator;', () => {

        const draft = getDraft();
        const shape = new Rectangle();

        spyOn(shape, 'didAdd').and.callThrough();
        spyOn(shape, 'didRemove').and.callThrough();

        expect(draft.add(shape)).toEqual(shape);
        expect(shape.didAdd.calls.count()).toEqual(1);

        expect(draft.remove(shape)).toEqual(0);
        expect(shape.didRemove.calls.count()).toEqual(1);

        draft.add(shape);
        expect(shape.didAdd.calls.count()).toEqual(2);

        const clearLength = draft.clear();
        expect(clearLength).toEqual(0);
        expect(shape.didRemove.calls.count()).toEqual(2);

    });

    it('Should be able to invoke the select/deselect invocator hooks;', () => {

        const draft = getDraft();
        const shape = new Rectangle();
        draft.add(shape);

        spyOn(shape, 'didSelect').and.callThrough();
        spyOn(shape, 'didDeselect').and.callThrough();

        draft.select();
        expect(shape.didSelect.calls.count()).toEqual(1);

        draft.deselect();
        expect(shape.didDeselect.calls.count()).toEqual(1);

    });

    it('Should be able to select/deselect only certain shapes;', () => {

        const draft  = getDraft();
        const shapes = { first: new Rectangle(), second: new Rectangle() };

        draft.add(shapes.first);
        draft.add(shapes.second);

        spyOn(shapes.first, 'didSelect').and.callThrough();
        spyOn(shapes.second, 'didSelect').and.callThrough();

        spyOn(shapes.first, 'didDeselect').and.callThrough();
        spyOn(shapes.second, 'didDeselect').and.callThrough();

        draft.select([shapes.first]);
        expect(shapes.first.didSelect.calls.count()).toEqual(1);
        expect(shapes.second.didSelect.calls.count()).toEqual(0);

        draft.deselect([shapes.first]);
        expect(shapes.first.didDeselect.calls.count()).toEqual(1);
        expect(shapes.second.didDeselect.calls.count()).toEqual(0);

        draft.select();
        expect(shapes.first.didSelect.calls.count()).toEqual(2);
        expect(shapes.second.didSelect.calls.count()).toEqual(1);

    });

    it('Should be able to add a shape by its name, and throw an exception when not found;', () => {

        const draft = getDraft();
        const shape = draft.add('rectangle');

        expect(shape.constructor.name).toEqual('Rectangle');

        expect(() => draft.add('non-existent')).toThrow(new Error('Draft.js: Cannot map "non-existent" to a shape object.'));

    });

});<commit_msg>Added window.Draft test<commit_after>import {getDraft, mockSVGElement} from './Bootstrap.js';

import Draft     from '../src/Draft.js';
import Symbols   from '../src/helpers/Symbols.js';
import Middleman from '../src/helpers/Middleman.js';
import Rectangle from '../src/shapes/Rectangle.js';

describe('Draft', () => {

    it('Should be able to instantiate the constructor function;', () => {
        expect(getDraft() instanceof Draft).toBeTruthy();
        expect(window.Draft).toEqual(Draft);
    });

    it('Should be able to setup the D3 using the passed in element;', () => {

        const draft = getDraft();
        expect(mockSVGElement.getAttribute('width')).toEqual('100%');
        expect(mockSVGElement.getAttribute('height')).toEqual('100%');
        expect(Array.isArray(draft[Symbols.SVG])).toBeTruthy();
        expect(draft[Symbols.SVG][0][0]).toEqual(mockSVGElement);

    });

    it('Should be able to pass in options that override the defaults;', () => {

        const draft   = getDraft({ documentHeight: '50%', gridSize: 5 });
        const options = draft[Symbols.OPTIONS];

        expect(options.documentHeight).toEqual('50%');
        expect(options.documentWidth).toEqual('100%');
        expect(draft.options().gridSize).toEqual(5);

    });

    it('Should be able to manage shapes with add, remove, clear, list;', () => {

        const draft  = getDraft();
        const shapes = { first: new Rectangle(), second: new Rectangle() };

        expect(draft.all().length).toEqual(0);
        draft.add(shapes.first);
        draft.add(shapes.second);
        expect(draft.all().length).toEqual(2);
        draft.remove(shapes.first);
        expect(draft.all().length).toEqual(1);
        draft.remove(shapes.second);
        expect(draft.all().length).toEqual(0);

        draft.add(shapes.first);
        draft.add(shapes.second);
        expect(draft.all().length).toEqual(2);
        draft.clear();
        expect(draft.all().length).toEqual(0);

    });

    it('Should be able to add the middleman object to each added shape;', () => {

        const draft = getDraft();
        const shape = new Rectangle();

        expect(draft.add(shape)).toEqual(shape);
        expect(shape[Symbols.MIDDLEMAN] instanceof Middleman).toBeTruthy();

    });

    it('Should be able to invoke the callback hooks from the invocator;', () => {

        const draft = getDraft();
        const shape = new Rectangle();

        spyOn(shape, 'didAdd').and.callThrough();
        spyOn(shape, 'didRemove').and.callThrough();

        expect(draft.add(shape)).toEqual(shape);
        expect(shape.didAdd.calls.count()).toEqual(1);

        expect(draft.remove(shape)).toEqual(0);
        expect(shape.didRemove.calls.count()).toEqual(1);

        draft.add(shape);
        expect(shape.didAdd.calls.count()).toEqual(2);

        const clearLength = draft.clear();
        expect(clearLength).toEqual(0);
        expect(shape.didRemove.calls.count()).toEqual(2);

    });

    it('Should be able to invoke the select/deselect invocator hooks;', () => {

        const draft = getDraft();
        const shape = new Rectangle();
        draft.add(shape);

        spyOn(shape, 'didSelect').and.callThrough();
        spyOn(shape, 'didDeselect').and.callThrough();

        draft.select();
        expect(shape.didSelect.calls.count()).toEqual(1);

        draft.deselect();
        expect(shape.didDeselect.calls.count()).toEqual(1);

    });

    it('Should be able to select/deselect only certain shapes;', () => {

        const draft  = getDraft();
        const shapes = { first: new Rectangle(), second: new Rectangle() };

        draft.add(shapes.first);
        draft.add(shapes.second);

        spyOn(shapes.first, 'didSelect').and.callThrough();
        spyOn(shapes.second, 'didSelect').and.callThrough();

        spyOn(shapes.first, 'didDeselect').and.callThrough();
        spyOn(shapes.second, 'didDeselect').and.callThrough();

        draft.select([shapes.first]);
        expect(shapes.first.didSelect.calls.count()).toEqual(1);
        expect(shapes.second.didSelect.calls.count()).toEqual(0);

        draft.deselect([shapes.first]);
        expect(shapes.first.didDeselect.calls.count()).toEqual(1);
        expect(shapes.second.didDeselect.calls.count()).toEqual(0);

        draft.select();
        expect(shapes.first.didSelect.calls.count()).toEqual(2);
        expect(shapes.second.didSelect.calls.count()).toEqual(1);

    });

    it('Should be able to add a shape by its name, and throw an exception when not found;', () => {

        const draft = getDraft();
        const shape = draft.add('rectangle');

        expect(shape.constructor.name).toEqual('Rectangle');

        expect(() => draft.add('non-existent')).toThrow(new Error('Draft.js: Cannot map "non-existent" to a shape object.'));

    });

});<|endoftext|>


<commit_before>describe("autosubmit-plugin", function() {
    var pattern;

    requireDependencies(["patterns/autosubmit"], function(cls) {
        pattern = cls;
    });

    // Reset the lab before each test
    beforeEach(function() {
        $("#lab *").remove();
    });

    describe("parse", function() {
        it("Shorthand notation", function() {
            var $trigger = $("<input data-pat-autosubmit='500'/>");
                options = pattern.parse($trigger);
            expect(options.delay).toBe("500");
        });

        it("Multiple options not accepted", function() {
            var $trigger = $("<input data-pat-autosubmit='500 && 400'/>");
                options = pattern.parse($trigger);
            expect(options.delay).toBe("500");
        });
    });

    describe("validateOptions", function() {
        var defaultKeyupDelay = 400;  // as defined in patterns/autosubmit.js

        it("Integer delay", function() {
            var options = pattern.validateOptions({delay: 500});
            expect(options.delay).toBe(500);
        });

        it("String integer delay", function() {
            var options = pattern.validateOptions({delay: "500"});
            expect(options.delay).toBe(500);
        });

        it("Delay keyword", function() {
            var options = pattern.validateOptions({delay: "delay"});
            expect(options.delay).toBe(defaultKeyupDelay);
        });

        it("Delay set to true", function() {
            var options = pattern.validateOptions({delay: "true"});
            expect(options.delay).toBe(defaultKeyupDelay);
        });

        it("Invalid syntax", function() {
            var options = pattern.validateOptions({delay: "invalid"});
            expect(options.delay).toBe(defaultKeyupDelay);
        });

        it("Bad type", function() {
            var options = pattern.validateOptions({delay: [500]});
            expect(options.delay).toBe(defaultKeyupDelay);
        });

        it("Negative delay", function() {
            var options = pattern.validateOptions({delay: -500});
            expect(options.delay).toBe(defaultKeyupDelay);
        });

    });
});

// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<commit_msg>Make code in autosubmit test JSlint-compliant<commit_after>/*global $, beforeEach, describe, expect, it, requireDependencies */
describe("autosubmit-plugin", function () {
    "use strict";

    var pattern;

    requireDependencies(["patterns/autosubmit"], function (cls) {
        pattern = cls;
    });

    // Reset the lab before each test
    beforeEach(function () {
        $("#lab *").remove();
    });

    describe("parse", function () {
        it("Shorthand notation", function () {
            var $trigger = $("<input data-pat-autosubmit='500'/>"),
                options = pattern.parse($trigger);
            expect(options.delay).toBe("500");
        });

        it("Multiple options not accepted", function () {
            var $trigger = $("<input data-pat-autosubmit='500 && 400'/>"),
                options = pattern.parse($trigger);
            expect(options.delay).toBe("500");
        });
    });

    describe("validateOptions", function () {
        var defaultKeyupDelay = 400;  // as defined in patterns/autosubmit.js

        it("Integer delay", function () {
            var options = pattern.validateOptions({delay: 500});
            expect(options.delay).toBe(500);
        });

        it("String integer delay", function () {
            var options = pattern.validateOptions({delay: "500"});
            expect(options.delay).toBe(500);
        });

        it("Delay keyword", function () {
            var options = pattern.validateOptions({delay: "delay"});
            expect(options.delay).toBe(defaultKeyupDelay);
        });

        it("Delay set to true", function () {
            var options = pattern.validateOptions({delay: "true"});
            expect(options.delay).toBe(defaultKeyupDelay);
        });

        it("Invalid syntax", function () {
            var options = pattern.validateOptions({delay: "invalid"});
            expect(options.delay).toBe(defaultKeyupDelay);
        });

        it("Bad type", function () {
            var options = pattern.validateOptions({delay: [500]});
            expect(options.delay).toBe(defaultKeyupDelay);
        });

        it("Negative delay", function () {
            var options = pattern.validateOptions({delay: -500});
            expect(options.delay).toBe(defaultKeyupDelay);
        });

    });
});

// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<|endoftext|>


<commit_before>var source = new EventSource('http://localhost:8000/event/' + session_id + '/' + job_id);
source.addEventListener("message", eventHandler, false);
var indexes = {};
var pending = {};
var cursor = {};
indexes.progress = 0;
indexes.pending = 0;

function object_as_ul_recursive(item,indent,tag) {
  var padding = "";
  for ( var i = 0; i++; i < indent ) {
    padding += "  ";
  }
  output = padding + "
\n";
  if ( typeof item === 'object' ) {
    var item_keys = Object.keys(item);
    var item_keys_length = item_keys.length;
    item_keys.sort();
    for ( var item_i = 0; item_i < item_keys_length; item_i++ ) {
      var key = item_keys[item_i];
      var value = item[key];
      if ( typeof value === 'object' ) {
        output += padding + "
 " + key + "\n";
        output += object_as_ul_recursive(value, indent + 1);
        output += padding + "
\n";
      } else {
        output += padding + "

"+key + "

" + value + "

\n";
      }
    }
  } else {
    output += padding + "
 " + value + "
\n";
  }
  output += padding + "
\n";
  return output;
}

function eventHandler(event) {
  data = JSON.parse(event.data);
  var output = "";
  switch(data.event) {
  case 'progress_start':
    output = data.data[0] + "\n";
    output += "<progress id='progress_bar_" + indexes.progress + "' value='0' max='100'></progress>
\n";
    break;
  case 'progress':
    var progress_total = 100.0 * data.data[0] / data.data[1];
    document.querySelector('#progress_bar_' + indexes.progress.toString()).value = progress_total;
    document.querySelector('#progress_bar_' + indexes.progress.toString()).innerHTML = data.data[2];
    break;
  case 'progress_end':
    document.querySelector('#progress_bar_' + indexes.progress.toString()).value = 100;
    indexes.progress++;
    break;
  case 'data':
    indexes.data_tags = {};
    indexes.data_tags[data.data[0]] = indexes.data_tags[data.data[0]] || 0;
    output += object_as_ul_recursive(data.data[1],0,data.data[0] + indexes.data_tags[data.data[0]]);
    break;
  case 'finished':
    source.removeEventListener("message", eventHandler);
  case 'pending_action_start':
    pending[indexes.pending] = {};
    pending[indexes.pending]['actions'] = {};
    pending[indexes.pending]['effects'] = {};
    break;
  case 'action_context':
    cursor['action'] = {};
    cursor['action_context'] = 0;
    pending[indexes.pending]['actions'][data.data[0]] = cursor['action'];
    break;
  case 'action':
    cursor['action'][cursor['action_context']] = data.data[0];
    cursor['action_context']++;
    break;
  case 'effect_start':
    cursor['severity'] = {};
    break;
  case 'effect_context':
    cursor['effect'] = {};
    cursor['effect_context'] = 0;
    pending[indexes.pending]['effects'][data.data[0]] = cursor['effect'];
    break;
  case 'effect':
    var severity = data.data[0];
    cursor['effect'][severity] = cursor['effect'][severity] || {};
    cursor['effect'][severity][cursor['effect_context']] = data.data[1];
    cursor['effect_context']++;
    break;
  case 'effect_end':
    output += object_as_ul_recursive(pending[indexes.pending],0,'actions_and_effects'+indexes.pending);
    indexes.pending++;
    break;
  default:
    output += "" + event + "" + JSON.stringify(data) + "
\n";
  }
  document.querySelector('#result').innerHTML += output
}

<commit_msg>Handle event feed termination properly<commit_after>var source = new EventSource('/event/' + session_id + '/' + job_id);
source.addEventListener("message", eventHandler, false);
var indexes = {};
var pending = {};
var cursor = {};
indexes.progress = 0;
indexes.pending = 0;

function object_as_ul_recursive(item,indent,tag) {
  var padding = "";
  for ( var i = 0; i++; i < indent ) {
    padding += "  ";
  }
  output = padding + "
\n";
  if ( typeof item === 'object' ) {
    var item_keys = Object.keys(item);
    var item_keys_length = item_keys.length;
    item_keys.sort();
    for ( var item_i = 0; item_i < item_keys_length; item_i++ ) {
      var key = item_keys[item_i];
      var value = item[key];
      if ( typeof value === 'object' ) {
        output += padding + "
 " + key + "\n";
        output += object_as_ul_recursive(value, indent + 1);
        output += padding + "
\n";
      } else {
        output += padding + "

"+key + "

" + value + "

\n";
      }
    }
  } else {
    output += padding + "
 " + value + "
\n";
  }
  output += padding + "
\n";
  return output;
}

function eventHandler(event) {
  data = JSON.parse(event.data);
  var output = "";
  switch(data.event) {
  case 'progress_start':
    output = data.data[0] + "\n";
    output += "<progress id='progress_bar_" + indexes.progress + "' value='0' max='100'></progress>
\n";
    break;
  case 'progress':
    var progress_total = 100.0 * data.data[0] / data.data[1];
    document.querySelector('#progress_bar_' + indexes.progress.toString()).value = progress_total;
    document.querySelector('#progress_bar_' + indexes.progress.toString()).innerHTML = data.data[2];
    break;
  case 'progress_end':
    document.querySelector('#progress_bar_' + indexes.progress.toString()).value = 100;
    indexes.progress++;
    break;
  case 'data':
    indexes.data_tags = {};
    indexes.data_tags[data.data[0]] = indexes.data_tags[data.data[0]] || 0;
    output += object_as_ul_recursive(data.data[1],0,data.data[0] + indexes.data_tags[data.data[0]]);
    break;
  case 'finished':
    source.close();
    break;
  case 'pending_action_start':
    pending[indexes.pending] = {};
    pending[indexes.pending]['actions'] = {};
    pending[indexes.pending]['effects'] = {};
    break;
  case 'action_context':
    cursor['action'] = {};
    cursor['action_context'] = 0;
    pending[indexes.pending]['actions'][data.data[0]] = cursor['action'];
    break;
  case 'action':
    cursor['action'][cursor['action_context']] = data.data[0];
    cursor['action_context']++;
    break;
  case 'effect_start':
    cursor['severity'] = {};
    break;
  case 'effect_context':
    cursor['effect'] = {};
    cursor['effect_context'] = 0;
    pending[indexes.pending]['effects'][data.data[0]] = cursor['effect'];
    break;
  case 'effect':
    var severity = data.data[0];
    cursor['effect'][severity] = cursor['effect'][severity] || {};
    cursor['effect'][severity][cursor['effect_context']] = data.data[1];
    cursor['effect_context']++;
    break;
  case 'effect_end':
    output += object_as_ul_recursive(pending[indexes.pending],0,'actions_and_effects'+indexes.pending);
    indexes.pending++;
    break;
  default:
    output += "" + event + "" + JSON.stringify(data) + "
\n";
  }
  document.querySelector('#result').innerHTML += output
}

<|endoftext|>


<commit_before>var Filter = (function () {

function filter_term(operator, operand) {
    // For legacy reasons we must represent filter_terms as tuples
    // until we phase out all the code that assumes tuples.
    var term = [];
    term[0] = operator;
    term[1] = operand;

    // This is the new style we are phasing in.  (Yes, the same
    // object can be treated like either a tuple or a struct.)
    term.operator = operator;
    term.operand = operand;

    return term;
}

function mit_edu_stream_name_match(message, operand) {
    // MIT users expect narrowing to "social" to also show messages to /^(un)*social(.d)*$/
    // (unsocial, ununsocial, social.d, etc)
    // TODO: hoist the regex compiling out of the closure
    var m = /^(?:un)*(.+?)(?:\.d)*$/i.exec(operand);
    var base_stream_name = operand;
    if (m !== null && m[1] !== undefined) {
        base_stream_name = m[1];
    }
    var related_regexp = new RegExp(/^(un)*/.source + util.escape_regexp(base_stream_name) + /(\.d)*$/.source, 'i');
    return related_regexp.test(message.stream);
}

function mit_edu_topic_name_match(message, operand) {
    // MIT users expect narrowing to topic "foo" to also show messages to /^foo(.d)*$/
    // (foo, foo.d, foo.d.d, etc)
    // TODO: hoist the regex compiling out of the closure
    var m = /^(.*?)(?:\.d)*$/i.exec(operand);
    var base_topic = m[1];
    var related_regexp;

    // Additionally, MIT users expect the empty instance and
    // instance "personal" to be the same.
    if (base_topic === ''
        || base_topic.toLowerCase() === 'personal'
        || base_topic.toLowerCase() === '(instance "")')
    {
        related_regexp = /^(|personal|\(instance ""\))(\.d)*$/i;
    } else {
        related_regexp = new RegExp(/^/.source + util.escape_regexp(base_topic) + /(\.d)*$/.source, 'i');
    }

    return related_regexp.test(message.subject);
}

function message_in_home(message) {
    if (message.type === "private" || message.mentioned ||
        (page_params.narrow_stream !== undefined &&
         message.stream.toLowerCase() === page_params.narrow_stream.toLowerCase())) {
        return true;
    }

    return stream_data.in_home_view(message.stream);
}

function Filter(operators) {
    if (operators === undefined) {
        this._operators = [];
    } else {
        this._operators = this._canonicalize_operators(operators);
    }
}

var canonical_operators = {"from": "sender", "subject": "topic"};

Filter.canonicalize_operator = function (operator) {
    operator = operator.toLowerCase();
    if (canonical_operators.hasOwnProperty(operator)) {
        return canonical_operators[operator];
    } else {
        return operator;
    }
};

Filter.canonicalize_tuple = function (tuple) {
    var operator = tuple[0];
    var operand = tuple[1];

    operator = Filter.canonicalize_operator(operator);

    switch (operator) {
    case 'stream':
        operand = stream_data.get_name(operand);
        break;
    case 'topic':
        break;
    case 'sender':
    case 'pm-with':
        operand = operand.toString().toLowerCase();
        if (operand === 'me') {
            operand = page_params.email;
        }
        break;
    default:
        operand = operand.toString().toLowerCase();
    }

    // We may want to consider allowing mixed-case operators at some point
    return filter_term(operator, operand);
};

/* We use a variant of URI encoding which looks reasonably
   nice and still handles unambiguously cases such as
   spaces in operands.

   This is just for the search bar, not for saving the
   narrow in the URL fragment.  There we do use full
   URI encoding to avoid problematic characters. */
function encodeOperand(operand) {
    return operand.replace(/%/g,  '%25')
                  .replace(/\+/g, '%2B')
                  .replace(/ /g,  '+');
}

function decodeOperand(encoded, operator) {
    if (operator !== 'pm-with' && operator !== 'sender') {
        encoded = encoded.replace(/\+/g, ' ');
    }
    return util.robust_uri_decode(encoded);
}

// Parse a string into a list of operators (see below).
Filter.parse = function (str) {
    var operators   = [];
    var search_term = [];
    var operand;

    var matches = str.match(/"[^"]+"|\S+/g);
    if (matches === null) {
        return operators;
    }
    _.each(matches, function (token) {
        var parts, operator;
        parts = token.split(':');
        if (token[0] === '"' || parts.length === 1) {
            // Looks like a normal search term.
            search_term.push(token);
        } else {
            // Looks like an operator.
            // FIXME: Should we skip unknown operator names here?
            operator = parts.shift();
            operand = decodeOperand(parts.join(':'), operator);
            operators.push(filter_term(operator, operand));
        }
    });
    // NB: Callers of 'parse' can assume that the 'search' operator is last.
    if (search_term.length > 0) {
        operand = search_term.join(' ');
        operators.push(filter_term('search', operand));
    }
    return operators;
};

/* Convert a list of operators to a string.
   Each operator is a key-value pair like

       ['subject', 'my amazing subject']

   These are not keys in a JavaScript object, because we
   might need to support multiple operators of the same type.
*/
Filter.unparse = function (operators) {
    var parts = _.map(operators, function (elem) {
        var operator = elem[0];
        if (operator === 'search') {
            // Search terms are the catch-all case.
            // All tokens that don't start with a known operator and
            // a colon are glued together to form a search term.
            return elem[1];
        } else {
            return elem[0] + ':' + encodeOperand(elem[1].toString());
        }
    });
    return parts.join(' ');
};

Filter.prototype = {
    predicate: function Filter_predicate() {
        if (this._predicate === undefined) {
            this._predicate = this._build_predicate();
        }
        return this._predicate;
    },

    operators: function Filter_operators() {
        return this._operators;
    },

    public_operators: function Filter_public_operators() {
        var safe_to_return = _.filter(this._operators, function (value) {
            // Filter out the "in" keyword and the embedded narrow (if any).
            return value.operator !== 'in' && !(page_params.narrow_stream !== undefined &&
                                                value.operator === "stream" &&
                                                value.operand.toLowerCase() === page_params.narrow_stream.toLowerCase());
        });
        return safe_to_return;
    },

    operands: function Filter_get_operands(operator) {
        return _.chain(this._operators)
            .filter(function (elem) { return elem.operator === operator; })
            .map(function (elem) { return elem.operand; })
            .value();
    },

    has_operand: function Filter_has_operand(operator, operand) {
        return _.any(this._operators, function (elem) {
            return elem.operator === operator && elem.operand === operand;
        });
    },

    has_operator: function Filter_has_operator(operator) {
        return _.any(this._operators, function (elem) {
            return elem.operator === operator;
        });
    },

    is_search: function Filter_is_search() {
        return this.has_operator('search');
    },

    can_apply_locally: function Filter_can_apply_locally() {
        return ! this.is_search();
    },

    _canonicalize_operators: function Filter__canonicalize_operators(operators_mixed_case) {
        return _.map(operators_mixed_case, function (tuple) {
            return Filter.canonicalize_tuple(tuple);
        });
    },

    // Build a filter function from a list of operators.
    _build_predicate: function Filter__build_predicate() {
        var operators = this._operators;

        if (! this.can_apply_locally()) {
            return function () { return true; };
        }

        // FIXME: This is probably pretty slow.
        // We could turn it into something more like a compiler:
        // build JavaScript code in a string and then eval() it.

        return function (message) {
            var operand, i, index;
            for (i = 0; i < operators.length; i++) {
                // Inside this loop, the correct protocol for a test is to
                // * "return false" if the value does not match
                // * "break" if there is a match
                // If you "return true", you circumvent all future operators
                operand = operators[i].operand;
                switch (operators[i].operator) {
                case 'is':
                    if (operand === 'private') {
                        if (message.type !== 'private') {
                            return false;
                        }
                    } else if (operand === 'starred') {
                        if (!message.starred) {
                            return false;
                        }
                    } else if (operand === 'mentioned') {
                        if (!message.mentioned) {
                            return false;
                        }
                    } else if (operand === 'alerted') {
                        if (!message.alerted) {
                            return false;
                        }
                    }

                    break;

                case 'in':
                    if (operand === 'home') {
                        return message_in_home(message);
                    }
                    else if (operand === 'all') {
                        break;
                    }
                    break;

                case 'near':
                    break;

                case 'id':
                    if (message.id.toString() !== operand) {
                        return false;
                    }
                    break;

                case 'stream':
                    if (message.type !== 'stream') {
                        return false;
                    }

                    operand = operand.toLowerCase();
                    if (page_params.domain === "mit.edu") {
                        if (!mit_edu_stream_name_match(message, operand)) {
                            return false;
                        }
                    } else if (message.stream.toLowerCase() !== operand) {
                        return false;
                    }
                    break;

                case 'topic':
                    if (message.type !== 'stream') {
                        return false;
                    }

                    operand = operand.toLowerCase();
                    if (page_params.domain === "mit.edu") {
                        if (!mit_edu_topic_name_match(message, operand)) {
                            return false;
                        }
                    } else if (message.subject.toLowerCase() !== operand) {
                        return false;
                    }
                    break;

                case 'sender':
                    if ((message.sender_email.toLowerCase() !== operand)) {
                        return false;
                    }
                    break;

                case 'pm-with':
                    if ((message.type !== 'private') ||
                        message.reply_to.toLowerCase() !== operand.split(',').sort().join(',')) {
                        return false;
                    }
                    break;
                }
            }

            // All filters passed.
            return true;
        };
    }
};

return Filter;

}());
if (typeof module !== 'undefined') {
    module.exports = Filter;
}
<commit_msg>Use _.all() in Filter._build_predicate.<commit_after>var Filter = (function () {

function filter_term(operator, operand) {
    // For legacy reasons we must represent filter_terms as tuples
    // until we phase out all the code that assumes tuples.
    var term = [];
    term[0] = operator;
    term[1] = operand;

    // This is the new style we are phasing in.  (Yes, the same
    // object can be treated like either a tuple or a struct.)
    term.operator = operator;
    term.operand = operand;

    return term;
}

function mit_edu_stream_name_match(message, operand) {
    // MIT users expect narrowing to "social" to also show messages to /^(un)*social(.d)*$/
    // (unsocial, ununsocial, social.d, etc)
    // TODO: hoist the regex compiling out of the closure
    var m = /^(?:un)*(.+?)(?:\.d)*$/i.exec(operand);
    var base_stream_name = operand;
    if (m !== null && m[1] !== undefined) {
        base_stream_name = m[1];
    }
    var related_regexp = new RegExp(/^(un)*/.source + util.escape_regexp(base_stream_name) + /(\.d)*$/.source, 'i');
    return related_regexp.test(message.stream);
}

function mit_edu_topic_name_match(message, operand) {
    // MIT users expect narrowing to topic "foo" to also show messages to /^foo(.d)*$/
    // (foo, foo.d, foo.d.d, etc)
    // TODO: hoist the regex compiling out of the closure
    var m = /^(.*?)(?:\.d)*$/i.exec(operand);
    var base_topic = m[1];
    var related_regexp;

    // Additionally, MIT users expect the empty instance and
    // instance "personal" to be the same.
    if (base_topic === ''
        || base_topic.toLowerCase() === 'personal'
        || base_topic.toLowerCase() === '(instance "")')
    {
        related_regexp = /^(|personal|\(instance ""\))(\.d)*$/i;
    } else {
        related_regexp = new RegExp(/^/.source + util.escape_regexp(base_topic) + /(\.d)*$/.source, 'i');
    }

    return related_regexp.test(message.subject);
}

function message_in_home(message) {
    if (message.type === "private" || message.mentioned ||
        (page_params.narrow_stream !== undefined &&
         message.stream.toLowerCase() === page_params.narrow_stream.toLowerCase())) {
        return true;
    }

    return stream_data.in_home_view(message.stream);
}

function Filter(operators) {
    if (operators === undefined) {
        this._operators = [];
    } else {
        this._operators = this._canonicalize_operators(operators);
    }
}

var canonical_operators = {"from": "sender", "subject": "topic"};

Filter.canonicalize_operator = function (operator) {
    operator = operator.toLowerCase();
    if (canonical_operators.hasOwnProperty(operator)) {
        return canonical_operators[operator];
    } else {
        return operator;
    }
};

Filter.canonicalize_tuple = function (tuple) {
    var operator = tuple[0];
    var operand = tuple[1];

    operator = Filter.canonicalize_operator(operator);

    switch (operator) {
    case 'stream':
        operand = stream_data.get_name(operand);
        break;
    case 'topic':
        break;
    case 'sender':
    case 'pm-with':
        operand = operand.toString().toLowerCase();
        if (operand === 'me') {
            operand = page_params.email;
        }
        break;
    default:
        operand = operand.toString().toLowerCase();
    }

    // We may want to consider allowing mixed-case operators at some point
    return filter_term(operator, operand);
};

/* We use a variant of URI encoding which looks reasonably
   nice and still handles unambiguously cases such as
   spaces in operands.

   This is just for the search bar, not for saving the
   narrow in the URL fragment.  There we do use full
   URI encoding to avoid problematic characters. */
function encodeOperand(operand) {
    return operand.replace(/%/g,  '%25')
                  .replace(/\+/g, '%2B')
                  .replace(/ /g,  '+');
}

function decodeOperand(encoded, operator) {
    if (operator !== 'pm-with' && operator !== 'sender') {
        encoded = encoded.replace(/\+/g, ' ');
    }
    return util.robust_uri_decode(encoded);
}

// Parse a string into a list of operators (see below).
Filter.parse = function (str) {
    var operators   = [];
    var search_term = [];
    var operand;

    var matches = str.match(/"[^"]+"|\S+/g);
    if (matches === null) {
        return operators;
    }
    _.each(matches, function (token) {
        var parts, operator;
        parts = token.split(':');
        if (token[0] === '"' || parts.length === 1) {
            // Looks like a normal search term.
            search_term.push(token);
        } else {
            // Looks like an operator.
            // FIXME: Should we skip unknown operator names here?
            operator = parts.shift();
            operand = decodeOperand(parts.join(':'), operator);
            operators.push(filter_term(operator, operand));
        }
    });
    // NB: Callers of 'parse' can assume that the 'search' operator is last.
    if (search_term.length > 0) {
        operand = search_term.join(' ');
        operators.push(filter_term('search', operand));
    }
    return operators;
};

/* Convert a list of operators to a string.
   Each operator is a key-value pair like

       ['subject', 'my amazing subject']

   These are not keys in a JavaScript object, because we
   might need to support multiple operators of the same type.
*/
Filter.unparse = function (operators) {
    var parts = _.map(operators, function (elem) {
        var operator = elem[0];
        if (operator === 'search') {
            // Search terms are the catch-all case.
            // All tokens that don't start with a known operator and
            // a colon are glued together to form a search term.
            return elem[1];
        } else {
            return elem[0] + ':' + encodeOperand(elem[1].toString());
        }
    });
    return parts.join(' ');
};

Filter.prototype = {
    predicate: function Filter_predicate() {
        if (this._predicate === undefined) {
            this._predicate = this._build_predicate();
        }
        return this._predicate;
    },

    operators: function Filter_operators() {
        return this._operators;
    },

    public_operators: function Filter_public_operators() {
        var safe_to_return = _.filter(this._operators, function (value) {
            // Filter out the "in" keyword and the embedded narrow (if any).
            return value.operator !== 'in' && !(page_params.narrow_stream !== undefined &&
                                                value.operator === "stream" &&
                                                value.operand.toLowerCase() === page_params.narrow_stream.toLowerCase());
        });
        return safe_to_return;
    },

    operands: function Filter_get_operands(operator) {
        return _.chain(this._operators)
            .filter(function (elem) { return elem.operator === operator; })
            .map(function (elem) { return elem.operand; })
            .value();
    },

    has_operand: function Filter_has_operand(operator, operand) {
        return _.any(this._operators, function (elem) {
            return elem.operator === operator && elem.operand === operand;
        });
    },

    has_operator: function Filter_has_operator(operator) {
        return _.any(this._operators, function (elem) {
            return elem.operator === operator;
        });
    },

    is_search: function Filter_is_search() {
        return this.has_operator('search');
    },

    can_apply_locally: function Filter_can_apply_locally() {
        return ! this.is_search();
    },

    _canonicalize_operators: function Filter__canonicalize_operators(operators_mixed_case) {
        return _.map(operators_mixed_case, function (tuple) {
            return Filter.canonicalize_tuple(tuple);
        });
    },

    // Build a filter function from a list of operators.
    _build_predicate: function Filter__build_predicate() {
        var operators = this._operators;

        if (! this.can_apply_locally()) {
            return function () { return true; };
        }

        // FIXME: This is probably pretty slow.
        // We could turn it into something more like a compiler:
        // build JavaScript code in a string and then eval() it.

        return function (message) {
            return _.all(operators, function (term) {
                var operand = term.operand;
                switch (term.operator) {
                case 'is':
                    if (operand === 'private') {
                        if (message.type !== 'private') {
                            return false;
                        }
                    } else if (operand === 'starred') {
                        if (!message.starred) {
                            return false;
                        }
                    } else if (operand === 'mentioned') {
                        if (!message.mentioned) {
                            return false;
                        }
                    } else if (operand === 'alerted') {
                        if (!message.alerted) {
                            return false;
                        }
                    }

                    break;

                case 'in':
                    if (operand === 'home') {
                        return message_in_home(message);
                    }
                    else if (operand === 'all') {
                        break;
                    }
                    break;

                case 'near':
                    break;

                case 'id':
                    if (message.id.toString() !== operand) {
                        return false;
                    }
                    break;

                case 'stream':
                    if (message.type !== 'stream') {
                        return false;
                    }

                    operand = operand.toLowerCase();
                    if (page_params.domain === "mit.edu") {
                        if (!mit_edu_stream_name_match(message, operand)) {
                            return false;
                        }
                    } else if (message.stream.toLowerCase() !== operand) {
                        return false;
                    }
                    break;

                case 'topic':
                    if (message.type !== 'stream') {
                        return false;
                    }

                    operand = operand.toLowerCase();
                    if (page_params.domain === "mit.edu") {
                        if (!mit_edu_topic_name_match(message, operand)) {
                            return false;
                        }
                    } else if (message.subject.toLowerCase() !== operand) {
                        return false;
                    }
                    break;

                case 'sender':
                    if ((message.sender_email.toLowerCase() !== operand)) {
                        return false;
                    }
                    break;

                case 'pm-with':
                    if ((message.type !== 'private') ||
                        message.reply_to.toLowerCase() !== operand.split(',').sort().join(',')) {
                        return false;
                    }
                    break;
                }

                return true;
            });
        };
    }
};

return Filter;

}());
if (typeof module !== 'undefined') {
    module.exports = Filter;
}
<|endoftext|>


<commit_before>var reload = (function () {

var exports = {};

var reload_in_progress = false;
var reload_pending = false;

exports.is_pending = function () {
    return reload_pending;
};

exports.is_in_progress = function () {
    return reload_in_progress;
};

function preserve_state(send_after_reload) {
    if (send_after_reload === undefined) {
        send_after_reload = 0;
    }
    var url = "#reload:send_after_reload=" + Number(send_after_reload);
    url += "+csrf_token=" + encodeURIComponent(csrf_token);

    if (compose.composing() === 'stream') {
        url += "+msg_type=stream";
        url += "+stream=" + encodeURIComponent(compose.stream_name());
        url += "+subject=" + encodeURIComponent(compose.subject());
    } else if (compose.composing() === 'private') {
        url += "+msg_type=private";
        url += "+recipient=" + encodeURIComponent(compose.recipient());
    }

    if (compose.composing()){
        url += "+msg=" + encodeURIComponent(compose.message_content());
    }

    var pointer = current_msg_list.selected_id();
    if (pointer !== -1) {
        url += "+pointer=" + pointer;
    }

    var oldhash = window.location.hash;
    if (oldhash.length !== 0 && oldhash[0] === '#') {
        oldhash = oldhash.slice(1);
    }
    url += "+oldhash=" + encodeURIComponent(oldhash);

    window.location.replace(url);
}

// Check if we're doing a compose-preserving reload.  This must be
// done before the first call to get_updates
$(function () {
    var location = window.location.toString();
    var fragment = location.substring(location.indexOf('#') + 1);
    if (fragment.search("reload:") !== 0) {
        return;
    }
    fragment = fragment.replace(/^reload:/, "");
    var keyvals = fragment.split("+");
    var vars = {};
    _.each(keyvals, function (str) {
        var pair = str.split("=");
        vars[pair[0]] = decodeURIComponent(pair[1]);
    });

    // Prevent random people on the Internet from constructing links
    // that make you send a message.
    if (vars.csrf_token !== csrf_token) {
        return;
    }

    if (vars.msg !== undefined){
        var send_now = parseInt(vars.send_after_reload, 10);

        // TODO: preserve focus
        compose.start(vars.msg_type, {stream: vars.stream || '',
                                      subject: vars.subject || '',
                                      private_message_recipient: vars.recipient || '',
                                      content: vars.msg || ''});
        if (send_now) {
            compose.finish();
        }
    }

    var pointer = parseInt(vars.pointer, 10);

    if (pointer) {
        page_params.initial_pointer = pointer;
    }

    hashchange.changehash(vars.oldhash);
});

function do_reload_app(send_after_reload, save_state, message) {
    // TODO: we should completely disable the UI here
    if (save_state) {
        preserve_state(send_after_reload);
    }

    if (message === undefined) {
        message = "Reloading";
    }
    // TODO: We need a better API for showing messages.
    ui.report_message(message, $("#reloading-application"));
    reload_in_progress = true;
    window.location.reload(true);
}

exports.initiate = function (options) {
    options = _.defaults({}, options, {
        immediate: false,
        save_state: true,
        send_after_reload: false
    });

    if (options.immediate) {
        do_reload_app(options.send_after_reload, options.save_state, options.message);
    }

    if (reload_pending) {
        return;
    }
    reload_pending = true;

    // If the user is composing a message, reload if they become idle
    // while composing.  If they finish or cancel the compose, wait
    // until they're idle again
    var idle_control;
    var unconditional_timeout = 1000*60*30 + util.random_int(0, 1000*60*5);
    var composing_timeout     = 1000*60*5  + util.random_int(0, 1000*60);
    var home_timeout          = 1000*60    + util.random_int(0, 1000*60);
    var compose_done_handler, compose_started_handler;

    function reload_from_idle () {
        do_reload_app(false, options.save_state, options.message);
    }

    // Make sure we always do a reload eventually
    setTimeout(reload_from_idle, unconditional_timeout);

    compose_done_handler = function () {
        idle_control.cancel();
        idle_control = $(document).idle({'idle': home_timeout,
                                         'onIdle': reload_from_idle});
        $(document).off('compose_canceled.zulip compose_finished.zulip',
                        compose_done_handler);
        $(document).on('compose_started.zulip', compose_started_handler);
    };
    compose_started_handler = function () {
        idle_control.cancel();
        idle_control = $(document).idle({'idle': composing_timeout,
                                         'onIdle': reload_from_idle});
        $(document).off('compose_started.zulip', compose_started_handler);
        $(document).on('compose_canceled.zulip compose_finished.zulip',
                       compose_done_handler);
    };

    if (compose.composing()) {
        idle_control = $(document).idle({'idle': composing_timeout,
                                         'onIdle': reload_from_idle});
        $(document).on('compose_canceled.zulip compose_finished.zulip',
                       compose_done_handler);
    } else {
        idle_control = $(document).idle({'idle': home_timeout,
                                         'onIdle': reload_from_idle});
        $(document).on('compose_started.zulip', compose_started_handler);
    }
};

return exports;
}());
<commit_msg>Save the original initial_pointer when updating it on reload.<commit_after>var reload = (function () {

var exports = {};

var reload_in_progress = false;
var reload_pending = false;

exports.is_pending = function () {
    return reload_pending;
};

exports.is_in_progress = function () {
    return reload_in_progress;
};

function preserve_state(send_after_reload) {
    if (send_after_reload === undefined) {
        send_after_reload = 0;
    }
    var url = "#reload:send_after_reload=" + Number(send_after_reload);
    url += "+csrf_token=" + encodeURIComponent(csrf_token);

    if (compose.composing() === 'stream') {
        url += "+msg_type=stream";
        url += "+stream=" + encodeURIComponent(compose.stream_name());
        url += "+subject=" + encodeURIComponent(compose.subject());
    } else if (compose.composing() === 'private') {
        url += "+msg_type=private";
        url += "+recipient=" + encodeURIComponent(compose.recipient());
    }

    if (compose.composing()){
        url += "+msg=" + encodeURIComponent(compose.message_content());
    }

    var pointer = current_msg_list.selected_id();
    if (pointer !== -1) {
        url += "+pointer=" + pointer;
    }

    var oldhash = window.location.hash;
    if (oldhash.length !== 0 && oldhash[0] === '#') {
        oldhash = oldhash.slice(1);
    }
    url += "+oldhash=" + encodeURIComponent(oldhash);

    window.location.replace(url);
}

// Check if we're doing a compose-preserving reload.  This must be
// done before the first call to get_updates
$(function () {
    var location = window.location.toString();
    var fragment = location.substring(location.indexOf('#') + 1);
    if (fragment.search("reload:") !== 0) {
        return;
    }
    fragment = fragment.replace(/^reload:/, "");
    var keyvals = fragment.split("+");
    var vars = {};
    _.each(keyvals, function (str) {
        var pair = str.split("=");
        vars[pair[0]] = decodeURIComponent(pair[1]);
    });

    // Prevent random people on the Internet from constructing links
    // that make you send a message.
    if (vars.csrf_token !== csrf_token) {
        return;
    }

    if (vars.msg !== undefined){
        var send_now = parseInt(vars.send_after_reload, 10);

        // TODO: preserve focus
        compose.start(vars.msg_type, {stream: vars.stream || '',
                                      subject: vars.subject || '',
                                      private_message_recipient: vars.recipient || '',
                                      content: vars.msg || ''});
        if (send_now) {
            compose.finish();
        }
    }

    var pointer = parseInt(vars.pointer, 10);

    if (pointer) {
        page_params.orig_initial_pointer = page_params.initial_pointer;
        page_params.initial_pointer = pointer;
    }

    hashchange.changehash(vars.oldhash);
});

function do_reload_app(send_after_reload, save_state, message) {
    // TODO: we should completely disable the UI here
    if (save_state) {
        preserve_state(send_after_reload);
    }

    if (message === undefined) {
        message = "Reloading";
    }
    // TODO: We need a better API for showing messages.
    ui.report_message(message, $("#reloading-application"));
    reload_in_progress = true;
    window.location.reload(true);
}

exports.initiate = function (options) {
    options = _.defaults({}, options, {
        immediate: false,
        save_state: true,
        send_after_reload: false
    });

    if (options.immediate) {
        do_reload_app(options.send_after_reload, options.save_state, options.message);
    }

    if (reload_pending) {
        return;
    }
    reload_pending = true;

    // If the user is composing a message, reload if they become idle
    // while composing.  If they finish or cancel the compose, wait
    // until they're idle again
    var idle_control;
    var unconditional_timeout = 1000*60*30 + util.random_int(0, 1000*60*5);
    var composing_timeout     = 1000*60*5  + util.random_int(0, 1000*60);
    var home_timeout          = 1000*60    + util.random_int(0, 1000*60);
    var compose_done_handler, compose_started_handler;

    function reload_from_idle () {
        do_reload_app(false, options.save_state, options.message);
    }

    // Make sure we always do a reload eventually
    setTimeout(reload_from_idle, unconditional_timeout);

    compose_done_handler = function () {
        idle_control.cancel();
        idle_control = $(document).idle({'idle': home_timeout,
                                         'onIdle': reload_from_idle});
        $(document).off('compose_canceled.zulip compose_finished.zulip',
                        compose_done_handler);
        $(document).on('compose_started.zulip', compose_started_handler);
    };
    compose_started_handler = function () {
        idle_control.cancel();
        idle_control = $(document).idle({'idle': composing_timeout,
                                         'onIdle': reload_from_idle});
        $(document).off('compose_started.zulip', compose_started_handler);
        $(document).on('compose_canceled.zulip compose_finished.zulip',
                       compose_done_handler);
    };

    if (compose.composing()) {
        idle_control = $(document).idle({'idle': composing_timeout,
                                         'onIdle': reload_from_idle});
        $(document).on('compose_canceled.zulip compose_finished.zulip',
                       compose_done_handler);
    } else {
        idle_control = $(document).idle({'idle': home_timeout,
                                         'onIdle': reload_from_idle});
        $(document).on('compose_started.zulip', compose_started_handler);
    }
};

return exports;
}());
<|endoftext|>