<commit_before>/**
 * @constructor
 * @param {number} id
 * @param {EditSession} session Edit session.
 * @param {FileEntry} entry
 */
function Tab(id, session, entry, dialogController) {
  this.id_ = id;
  this.session_ = session;
  this.entry_ = entry;
  this.saved_ = true;
  this.path_ = null;
  this.dialogController_ = dialogController;
  if (this.entry_)
    this.updatePath_();
};

Tab.prototype.getId = function() {
  return this.id_;
};

Tab.prototype.getName = function() {
  if (this.entry_) {
    return this.entry_.name;
  } else {
    return 'Untitled ' + this.id_;
  }
};

/**
 * @return {string?} Filename extension or null.
 */
Tab.prototype.getExtension = function() {
  if (!this.entry_)
    return null;

  var match = /\.([^.\\\/]+)$/.exec(this.getName());

  if (match) {
    return match[1];
  } else {
    return null;
  }
};

Tab.prototype.getSession = function() {
  return this.session_;
};

/**
 * @param {FileEntry} entry
 */
Tab.prototype.setEntry = function(entry) {
  var nameChanged = this.getName() != entry.name;
  this.entry_ = entry;
  if (nameChanged)
    $.event.trigger('tabrenamed', this);
  this.updatePath_();
};

Tab.prototype.getEntry = function() {
  return this.entry_;
};

Tab.prototype.getPath = function() {
  return this.path_;
};

Tab.prototype.updatePath_ = function() {
  chrome.fileSystem.getDisplayPath(this.entry_, function(path) {
    this.path_ = path;
    $.event.trigger('tabpathchange', this);
  }.bind(this));
};

Tab.prototype.save = function(opt_callbackDone) {
  util.writeFile(
      this.entry_, this.session_.getValue(),
      function() {
        this.saved_ = true;
        $.event.trigger('tabsave', this);
        if (opt_callbackDone)
          opt_callbackDone();
      }.bind(this),
      this.reportWriteError_.bind(this));
};

Tab.prototype.reportWriteError_ = function(e) {
  this.dialogController_.setText(
      'Error saving file: ' + util.fsErrorStr(e));
  this.dialogController_.resetButtons();
  this.dialogController_.addButton('ok',
      chrome.i18n.getMessage('okDialogButton'));
  this.dialogController_.show();
};

Tab.prototype.isSaved = function() {
  return this.saved_;
};

Tab.prototype.changed = function() {
  if (this.saved_) {
    this.saved_ = false;
    $.event.trigger('tabchange', this);
  }
};

/**
 * @constructor
 */
function Tabs(editor, dialogController, settings) {
  this.editor_ = editor;
  this.dialogController_ = dialogController;
  this.settings_ = settings;
  this.tabs_ = [];
  this.currentTab_ = null;
  $(document).bind('docchange', this.onDocChanged_.bind(this));
}

/**
 * @type {Object} params
 * @type {function(FileEntry)} callback
 * @type {function()} opt_oncancel
 * Open a file in the system file picker. The FileEntry is copied to be stored
 * in background page, so it isn't destroyed when the window is closed.
 */
Tabs.prototype.chooseEntry = function(params, callback, opt_oncancel) {
  // TODO: Remove this when crbug.com/326523 is fixed.
  if (params.acceptsMultiple) {
    console.error('acceptsMultiple is not supported when saving a file');
    return;
  }
  chrome.fileSystem.chooseEntry(
      params,
      function(entry) {
        if (entry) {
          chrome.runtime.getBackgroundPage(function(bg) {
            bg.background.copyFileEntry(entry, callback);
          });
        } else {
          if (opt_oncancel)
            opt_oncancel();
        }
      });
};

/**
 * @type {Object} params
 * @type {function(FileEntry)} callback
 * @type {function()} opt_oncancel
 * Open one or multiple files in the system file picker. File Entries are
 * copied to be stored in background page, so they aren't destroyed when the
 * window is closed. Callback is called once for each File Entry.
 */
Tabs.prototype.chooseEntries = function(params, callback, opt_oncancel) {
  params.acceptsMultiple = true;
  chrome.fileSystem.chooseEntry(
      params,
      function(entries) {
        if (entries) {
          chrome.runtime.getBackgroundPage(function(bg) {
            for (var i = 0; i < entries.length; i++)
              bg.background.copyFileEntry(entries[i], callback);
          });
        } else {
          if (opt_oncancel)
            opt_oncancel();
        }
      });
};

Tabs.prototype.getTabById = function(id) {
  for (var i = 0; i < this.tabs_.length; i++) {
    if (this.tabs_[i].getId() === id)
      return this.tabs_[i];
  }
  return null;
};

Tabs.prototype.getCurrentTab = function(id) {
  return this.currentTab_;
};

Tabs.prototype.newWindow = function() {
  chrome.runtime.getBackgroundPage(function(bg) {
    bg.background.newWindow();
  }.bind(this));
};

Tabs.prototype.newTab = function(opt_content, opt_entry) {
  var id = 1;
  while (this.getTabById(id)) {
    id++;
  }

  var session = this.editor_.newSession(opt_content);

  var tab = new Tab(id, session, opt_entry || null, this.dialogController_);
  this.tabs_.push(tab);
  $.event.trigger('newtab', tab);
  this.showTab(tab.getId());
  var fileNameExtension = tab.getExtension();
  if (fileNameExtension)
    this.editor_.setMode(session, fileNameExtension);
};

Tabs.prototype.nextTab = function() {
  for (var i = 0; i < this.tabs_.length; i++) {
    if (this.tabs_[i] === this.currentTab_) {
      var next = i + 1;
      if (next === this.tabs_.length)
        next = 0;
      if (next !== i)
        this.showTab(this.tabs_[next].getId());
      return;
    }
  }
};

Tabs.prototype.showTab = function(tabId) {
  var tab = this.getTabById(tabId)
  this.editor_.setSession(tab.getSession());
  this.currentTab_ = tab;
  $.event.trigger('switchtab', tab);
  this.editor_.focus();
};

Tabs.prototype.close = function(tabId) {
  for (var i = 0; i < this.tabs_.length; i++) {
    if (this.tabs_[i].getId() == tabId)
      break;
  }

  if (i >= this.tabs_.length) {
    console.error('Can\'t find tab', tabId);
    return;
  }

  var tab = this.tabs_[i];

  if (!tab.isSaved()) {
    if (this.settings_.get('autosave') && tab.getEntry()) {
      this.save(tab, true /* close */);
    } else {
      this.dialogController_.setText(
          chrome.i18n.getMessage('saveFilePrompt'));
      this.dialogController_.resetButtons();
      this.dialogController_.addButton('yes',
          chrome.i18n.getMessage('yesDialogButton'));
      this.dialogController_.addButton('no',
          chrome.i18n.getMessage('noDialogButton'));
      this.dialogController_.addButton('cancel',
          chrome.i18n.getMessage('cancelDialogButton'));
      this.dialogController_.show(function(answer) {
        if (answer === 'yes') {
          this.save(tab, true /* close */);
          return;
        }

        if (answer === 'no') {
          this.closeTab_(tab);
          return;
        }
      }.bind(this));
    }
  } else {
    this.closeTab_(tab);
  }
};

/**
 * @param {Tab} tab
 * Close tab without checking whether it needs to be saved. The safe version
 * (invoking auto-save and, if needed, SaveAs dialog) is Tabs.close().
 */
Tabs.prototype.closeTab_ = function(tab) {
  if (tab === this.currentTab_) {
    if (this.tabs_.length > 1) {
      this.nextTab();
    } else {
      window.close();
    }
  }

  for (var i = 0; i < this.tabs_.length; i++) {
    if (this.tabs_[i] === tab)
      break;
  }

  this.tabs_.splice(i, 1);
  $.event.trigger('tabclosed', tab);
};

Tabs.prototype.closeCurrent = function() {
  this.close(this.currentTab_.getId());
};

Tabs.prototype.openFiles = function() {
  this.chooseEntries(
      {'type': 'openWritableFile'},
      this.openFileEntry.bind(this));
};

Tabs.prototype.save = function(opt_tab, opt_close) {
  if (!opt_tab)
    opt_tab = this.currentTab_;
  if (opt_tab.getEntry()) {
    var callback = null;
    if (opt_close)
      callback = this.closeTab_.bind(this, opt_tab);
    opt_tab.save(callback);
  } else {
    this.saveAs(opt_tab, opt_close);
  }
};

Tabs.prototype.saveAs = function(opt_tab, opt_close) {
  if (!opt_tab)
    opt_tab = this.currentTab_;
  var suggestedName = opt_tab.entry_ && opt_tab.entry_.name ||
                      util.sanitizeFileName(opt_tab.session_.getLine(0)) ||
                      opt_tab.getName();
  this.chooseEntry(
      {'type': 'saveFile', 'suggestedName': suggestedName},
      this.onSaveAsFileOpen_.bind(this, opt_tab, opt_close || false));
};

/**
 * @return {Array.<Object>} Each element:
 *     {entry: <FileEntry>, contents: <string>}.
 */
Tabs.prototype.getFilesToSave = function() {
  var toSave = [];

  for (i = 0; i < this.tabs_.length; i++) {
    if (!this.tabs_[i].isSaved() && this.tabs_[i].getEntry()) {
      toSave.push({'entry': this.tabs_[i].getEntry(),
                   'contents': editor.getContents(this.tabs_[i].getSession())});
    }
  }

  return toSave;
};

Tabs.prototype.openFileEntry = function(entry) {
  chrome.fileSystem.getDisplayPath(entry, function(path) {
    for (var i = 0; i < this.tabs_.length; i++) {
      if (this.tabs_[i].getPath() === path) {
        this.showTab(this.tabs_[i].getId());
        return;
      }
    }

    entry.file(this.readFileToNewTab_.bind(this, entry));
  }.bind(this));
};

Tabs.prototype.modeAutoSet = function(tab) {
  var extension = tab.getExtension();
  if (extension) {
    this.editor_.setMode(tab.getSession(), extension);
  }
};

Tabs.prototype.readFileToNewTab_ = function(entry, file) {
  var self = this;
  var reader = new FileReader();
  reader.onerror = util.handleFSError;
  reader.onloadend = function(e) {
    self.newTab(this.result, entry);
    if (self.tabs_.length === 2 &&
        !self.tabs_[0].getEntry() &&
        self.tabs_[0].isSaved()) {
      self.close(self.tabs_[0].getId());
    }
  };
  reader.readAsText(file);
}

Tabs.prototype.onSaveAsFileOpen_ = function(tab, close, entry) {
  if (!entry) {
    return;
  }

  tab.setEntry(entry);
  this.save(tab, close);
};

Tabs.prototype.onDocChanged_ = function(e, session) {
  var tab = this.currentTab_;
  if (this.currentTab_.getSession() !== session) {
    console.warn('Something wrong. Current session should be',
                 this.currentTab_.getSession(),
                 ', but this session was changed:', session);
    for (var i = 0; i < this.tabs_; i++) {
      if (this.tabs_[i].getSession() === session) {
        tab = this.tabs_[i];
        break;
      }
    }

    if (tab === this.currentTab_) {
      console.error('Unkown tab changed.');
      return;
    }
  }

  tab.changed();
};
<commit_msg>Used getEntry() instead of entry_<commit_after>/**
 * @constructor
 * @param {number} id
 * @param {EditSession} session Edit session.
 * @param {FileEntry} entry
 */
function Tab(id, session, entry, dialogController) {
  this.id_ = id;
  this.session_ = session;
  this.entry_ = entry;
  this.saved_ = true;
  this.path_ = null;
  this.dialogController_ = dialogController;
  if (this.entry_)
    this.updatePath_();
};

Tab.prototype.getId = function() {
  return this.id_;
};

Tab.prototype.getName = function() {
  if (this.entry_) {
    return this.entry_.name;
  } else {
    return 'Untitled ' + this.id_;
  }
};

/**
 * @return {string?} Filename extension or null.
 */
Tab.prototype.getExtension = function() {
  if (!this.entry_)
    return null;

  var match = /\.([^.\\\/]+)$/.exec(this.getName());

  if (match) {
    return match[1];
  } else {
    return null;
  }
};

Tab.prototype.getSession = function() {
  return this.session_;
};

/**
 * @param {FileEntry} entry
 */
Tab.prototype.setEntry = function(entry) {
  var nameChanged = this.getName() != entry.name;
  this.entry_ = entry;
  if (nameChanged)
    $.event.trigger('tabrenamed', this);
  this.updatePath_();
};

Tab.prototype.getEntry = function() {
  return this.entry_;
};

Tab.prototype.getPath = function() {
  return this.path_;
};

Tab.prototype.updatePath_ = function() {
  chrome.fileSystem.getDisplayPath(this.entry_, function(path) {
    this.path_ = path;
    $.event.trigger('tabpathchange', this);
  }.bind(this));
};

Tab.prototype.save = function(opt_callbackDone) {
  util.writeFile(
      this.entry_, this.session_.getValue(),
      function() {
        this.saved_ = true;
        $.event.trigger('tabsave', this);
        if (opt_callbackDone)
          opt_callbackDone();
      }.bind(this),
      this.reportWriteError_.bind(this));
};

Tab.prototype.reportWriteError_ = function(e) {
  this.dialogController_.setText(
      'Error saving file: ' + util.fsErrorStr(e));
  this.dialogController_.resetButtons();
  this.dialogController_.addButton('ok',
      chrome.i18n.getMessage('okDialogButton'));
  this.dialogController_.show();
};

Tab.prototype.isSaved = function() {
  return this.saved_;
};

Tab.prototype.changed = function() {
  if (this.saved_) {
    this.saved_ = false;
    $.event.trigger('tabchange', this);
  }
};

/**
 * @constructor
 */
function Tabs(editor, dialogController, settings) {
  this.editor_ = editor;
  this.dialogController_ = dialogController;
  this.settings_ = settings;
  this.tabs_ = [];
  this.currentTab_ = null;
  $(document).bind('docchange', this.onDocChanged_.bind(this));
}

/**
 * @type {Object} params
 * @type {function(FileEntry)} callback
 * @type {function()} opt_oncancel
 * Open a file in the system file picker. The FileEntry is copied to be stored
 * in background page, so it isn't destroyed when the window is closed.
 */
Tabs.prototype.chooseEntry = function(params, callback, opt_oncancel) {
  // TODO: Remove this when crbug.com/326523 is fixed.
  if (params.acceptsMultiple) {
    console.error('acceptsMultiple is not supported when saving a file');
    return;
  }
  chrome.fileSystem.chooseEntry(
      params,
      function(entry) {
        if (entry) {
          chrome.runtime.getBackgroundPage(function(bg) {
            bg.background.copyFileEntry(entry, callback);
          });
        } else {
          if (opt_oncancel)
            opt_oncancel();
        }
      });
};

/**
 * @type {Object} params
 * @type {function(FileEntry)} callback
 * @type {function()} opt_oncancel
 * Open one or multiple files in the system file picker. File Entries are
 * copied to be stored in background page, so they aren't destroyed when the
 * window is closed. Callback is called once for each File Entry.
 */
Tabs.prototype.chooseEntries = function(params, callback, opt_oncancel) {
  params.acceptsMultiple = true;
  chrome.fileSystem.chooseEntry(
      params,
      function(entries) {
        if (entries) {
          chrome.runtime.getBackgroundPage(function(bg) {
            for (var i = 0; i < entries.length; i++)
              bg.background.copyFileEntry(entries[i], callback);
          });
        } else {
          if (opt_oncancel)
            opt_oncancel();
        }
      });
};

Tabs.prototype.getTabById = function(id) {
  for (var i = 0; i < this.tabs_.length; i++) {
    if (this.tabs_[i].getId() === id)
      return this.tabs_[i];
  }
  return null;
};

Tabs.prototype.getCurrentTab = function(id) {
  return this.currentTab_;
};

Tabs.prototype.newWindow = function() {
  chrome.runtime.getBackgroundPage(function(bg) {
    bg.background.newWindow();
  }.bind(this));
};

Tabs.prototype.newTab = function(opt_content, opt_entry) {
  var id = 1;
  while (this.getTabById(id)) {
    id++;
  }

  var session = this.editor_.newSession(opt_content);

  var tab = new Tab(id, session, opt_entry || null, this.dialogController_);
  this.tabs_.push(tab);
  $.event.trigger('newtab', tab);
  this.showTab(tab.getId());
  var fileNameExtension = tab.getExtension();
  if (fileNameExtension)
    this.editor_.setMode(session, fileNameExtension);
};

Tabs.prototype.nextTab = function() {
  for (var i = 0; i < this.tabs_.length; i++) {
    if (this.tabs_[i] === this.currentTab_) {
      var next = i + 1;
      if (next === this.tabs_.length)
        next = 0;
      if (next !== i)
        this.showTab(this.tabs_[next].getId());
      return;
    }
  }
};

Tabs.prototype.showTab = function(tabId) {
  var tab = this.getTabById(tabId)
  this.editor_.setSession(tab.getSession());
  this.currentTab_ = tab;
  $.event.trigger('switchtab', tab);
  this.editor_.focus();
};

Tabs.prototype.close = function(tabId) {
  for (var i = 0; i < this.tabs_.length; i++) {
    if (this.tabs_[i].getId() == tabId)
      break;
  }

  if (i >= this.tabs_.length) {
    console.error('Can\'t find tab', tabId);
    return;
  }

  var tab = this.tabs_[i];

  if (!tab.isSaved()) {
    if (this.settings_.get('autosave') && tab.getEntry()) {
      this.save(tab, true /* close */);
    } else {
      this.dialogController_.setText(
          chrome.i18n.getMessage('saveFilePrompt'));
      this.dialogController_.resetButtons();
      this.dialogController_.addButton('yes',
          chrome.i18n.getMessage('yesDialogButton'));
      this.dialogController_.addButton('no',
          chrome.i18n.getMessage('noDialogButton'));
      this.dialogController_.addButton('cancel',
          chrome.i18n.getMessage('cancelDialogButton'));
      this.dialogController_.show(function(answer) {
        if (answer === 'yes') {
          this.save(tab, true /* close */);
          return;
        }

        if (answer === 'no') {
          this.closeTab_(tab);
          return;
        }
      }.bind(this));
    }
  } else {
    this.closeTab_(tab);
  }
};

/**
 * @param {Tab} tab
 * Close tab without checking whether it needs to be saved. The safe version
 * (invoking auto-save and, if needed, SaveAs dialog) is Tabs.close().
 */
Tabs.prototype.closeTab_ = function(tab) {
  if (tab === this.currentTab_) {
    if (this.tabs_.length > 1) {
      this.nextTab();
    } else {
      window.close();
    }
  }

  for (var i = 0; i < this.tabs_.length; i++) {
    if (this.tabs_[i] === tab)
      break;
  }

  this.tabs_.splice(i, 1);
  $.event.trigger('tabclosed', tab);
};

Tabs.prototype.closeCurrent = function() {
  this.close(this.currentTab_.getId());
};

Tabs.prototype.openFiles = function() {
  this.chooseEntries(
      {'type': 'openWritableFile'},
      this.openFileEntry.bind(this));
};

Tabs.prototype.save = function(opt_tab, opt_close) {
  if (!opt_tab)
    opt_tab = this.currentTab_;
  if (opt_tab.getEntry()) {
    var callback = null;
    if (opt_close)
      callback = this.closeTab_.bind(this, opt_tab);
    opt_tab.save(callback);
  } else {
    this.saveAs(opt_tab, opt_close);
  }
};

Tabs.prototype.saveAs = function(opt_tab, opt_close) {
  if (!opt_tab)
    opt_tab = this.currentTab_;
  var suggestedName = opt_tab.getEntry() && opt_tab.getEntry().name ||
                      util.sanitizeFileName(opt_tab.session_.getLine(0)) ||
                      opt_tab.getName();
  this.chooseEntry(
      {'type': 'saveFile', 'suggestedName': suggestedName},
      this.onSaveAsFileOpen_.bind(this, opt_tab, opt_close || false));
};

/**
 * @return {Array.<Object>} Each element:
 *     {entry: <FileEntry>, contents: <string>}.
 */
Tabs.prototype.getFilesToSave = function() {
  var toSave = [];

  for (i = 0; i < this.tabs_.length; i++) {
    if (!this.tabs_[i].isSaved() && this.tabs_[i].getEntry()) {
      toSave.push({'entry': this.tabs_[i].getEntry(),
                   'contents': editor.getContents(this.tabs_[i].getSession())});
    }
  }

  return toSave;
};

Tabs.prototype.openFileEntry = function(entry) {
  chrome.fileSystem.getDisplayPath(entry, function(path) {
    for (var i = 0; i < this.tabs_.length; i++) {
      if (this.tabs_[i].getPath() === path) {
        this.showTab(this.tabs_[i].getId());
        return;
      }
    }

    entry.file(this.readFileToNewTab_.bind(this, entry));
  }.bind(this));
};

Tabs.prototype.modeAutoSet = function(tab) {
  var extension = tab.getExtension();
  if (extension) {
    this.editor_.setMode(tab.getSession(), extension);
  }
};

Tabs.prototype.readFileToNewTab_ = function(entry, file) {
  var self = this;
  var reader = new FileReader();
  reader.onerror = util.handleFSError;
  reader.onloadend = function(e) {
    self.newTab(this.result, entry);
    if (self.tabs_.length === 2 &&
        !self.tabs_[0].getEntry() &&
        self.tabs_[0].isSaved()) {
      self.close(self.tabs_[0].getId());
    }
  };
  reader.readAsText(file);
}

Tabs.prototype.onSaveAsFileOpen_ = function(tab, close, entry) {
  if (!entry) {
    return;
  }

  tab.setEntry(entry);
  this.save(tab, close);
};

Tabs.prototype.onDocChanged_ = function(e, session) {
  var tab = this.currentTab_;
  if (this.currentTab_.getSession() !== session) {
    console.warn('Something wrong. Current session should be',
                 this.currentTab_.getSession(),
                 ', but this session was changed:', session);
    for (var i = 0; i < this.tabs_; i++) {
      if (this.tabs_[i].getSession() === session) {
        tab = this.tabs_[i];
        break;
      }
    }

    if (tab === this.currentTab_) {
      console.error('Unkown tab changed.');
      return;
    }
  }

  tab.changed();
};
<|endoftext|>


<commit_before>define(['require', 'exports', 'parser'], function(require, exports, parserJS) {
	var Parser = parserJS.Parser;
	var tests = exports.tests = [
		function basicParse1(parser) { // Test very basic parsing
			return assert(parser.parse('echo hello'), ['echo', 'hello']);
		},
		function basicParse2(parser) { // Some more basic parsing
			return assert(parser.parse('edit websites/WebCLIOS/index.html'), ['edit', 'websites/WebCLIOS/index.html']);
		},
		function basicParse3(parser) { // And even some more almost identical to above
			return assert(parser.parse('show websites/WebCLIOS/index.html'), ['show', 'websites/WebCLIOS/index.html']);
		},
		function history1(parser) { // Test to see if !! to get the whole last parse
			parser.parse('hello');

			return assert(parser.parse('!!'), ['hello']);
		},
		function history2(parser) { // Test to see if !$ correctly gets the last argument of the last command
			parser.parse('echo hello world');

			return assert(parser.parse('echo !$'), ['echo', 'world']);
		},
		function history3(parser) { // Test to see if !<num> works correctly basicly the same as !! but a different index (other than 0)
			parser.history[33] = { split: ['show', '~/code/cliParser/parser.html'], text: 'show ~/code/cliParser/parser.html' };

			return assert(parser.parse('!33'), ['show', '~/code/cliParser/parser.html']);
		},
		function history4(parser) { // Test !$ again this time more realistic
			parser.parse('ls /media');

			return assert(parser.parse('cd !$'), ['cd', '/media']);
		},
		function history5(parser) { // And again another realistic test
			parser.parse('ls /media');

			return assert(parser.parse('ls -lha !$'), ['ls', '-lha', '/media']);
		},
		function toCMDLine1(parser) { // Test to see if the toCMDLine will correctly create a command from a parsed array
			return assert(parser.toCMDLine(parser.parse('echo hello world')), '"echo" "hello" "world"');
		},
		function toCMDLine2(parser) { // Test it again now seeing if parsing it after running it through toCMDLine returns the correct result
			return assert(parser.parse(parser.toCMDLine(['echo', 'hello', 'world'])), ['echo', 'hello', 'world']);
		},
		function toCMDLine3(parser) { // Test to see if the reparsed is == to just parsed
			return assert(parser.parse(parser.toCMDLine(['cat', '/etc/httpd.conf'])), parser.parse('cat /etc/httpd.conf'));
		},
		function enviormentVariables1(parser) { // Test to see if variable subsitution works correctly
			return assert(parser.parse('echo $variable', { variable: "hello world" }), ['echo', 'hello', 'world']);
		},
		function enviormentVariables2(parser) { // Test it again
			return assert(parser.parse('$vim_path', { vim_path: '/usr/bin/vim' }), ['/usr/bin/vim']);
		},
		function embeddedCmd1(parser) { // Test embedded commands with the $(<cmd>) syntax
			return assert(parser.parse('echo $(pwd)', {}, function(cmd, env, execCmd) {
				return 'cmd';
			}), ['echo', 'cmd']);
		},
		function embeddedCmd2(parser) { // Test it again but with variable subsitution and backtick syntax mixed in
			return assert(parser.parse('echo $(echo `pwd`/$filename.$filetype)', { filename: 'hello', filetype: 'txt' }, function(cmd, env, execCMD) {
				return parser.toCMDLine(parser.parse(cmd, env, execCMD));
			}), ['echo', 'echo', 'pwd/hello.txt']);
		},
		function embeddedCmd3(parser) { // Test to see if escaping backslashes works
			return assert(parser.parse('\\\\$(pwd)', {}, function(cmd, env, execCMD) {
				return parser.parse(cmd, env, execCMD).join(' ');
			}), ['\\pwd']);
		},
		function string1(parser) { // Test strings to see if they correctly split the command
			return assert(parser.parse('echo "hello world"'), ['echo', 'hello world']);
		},
		function string2(parser) { // Test multiple strings
			return assert(parser.parse('"hi""hello "'), ['hihello ']);
		},
		function string3(parser) { // Test string now with single-quote
			return assert(parser.parse("echo 'hello world'"), ['echo', 'hello world'])
		},
		function string4(parser) {
			return assert(parser.parse("echo 'hello 'hi''"), ['echo', 'hello hi']);
		},
		function escape1(parser) { // Test to see if we can escape quotes
			return assert(parser.parse('echo "hi \\""'), ['echo', 'hi "']);
		},
		function escape2(parser) { // And now testing with $
			return assert(parser.parse('echo \\$filename'), ['echo', '$filename']);
		},
		function escape3(parser) { // Test for a bug i found where escaping backslashes doesn't work (problably because i hadn't implemented it yet)
			return assert(parser.parse('\\\\"hi "'), ['\\hi ']);
		}
	];

	function type(o) {
		var oType = typeof(o);

		switch(oType) {
			case 'object':
				if(o === null) oType = 'null';
				else if(o.constructor == String) oType = 'string';
				else if(o.constructor == Number) oType = 'number';
				else if(type(o.length) == 'number') oType = 'array';
				break;
		}

		return oType;
	}

	function equal(first, second) {
		var fType = type(first), sType = type(first);
		if(fType == 'array' && sType == 'array') { // Array
			var good = true;

			for(var i = 0; i < got.length; i++) {
				if(!equal(first[i], second[i])) good = false;
			}

			return good;
		} else if(fType == 'string' && sType == 'string') { // String
			return first.toString() == second.toString();
		} else {
			return false;
		}
	}

	function assert(got, expected) {
		return { value: got, expected: expected, good: equal(got, expected) };
	}

	exports.run = function run(printer) {
		var good = true, goods = [], tmp;

		printer = printer || ( !!window.puts ? function(str) { return puts(str + '\n'); } : console.log.bind(console)) || window.alert.bind(window);

		for(var i = 0; i < tests.length; i++) {
			try {
				if(!(tmp = tests[i](new Parser())).good) {
					good = false;
					goods[i] = false;
					printer('BAD: ' + tests[i].name + ' ' + tmp.value + ' ' + tmp.expected);
				} else {
					goods[i] = true;
					printer('GOOD: ' + tests[i].name);
				}
			} catch(ex) {
				printer('BAD: ' + tests[i].name + ' EX: ' + ex + ' ' + ex.stack + ' ' + ex.message);
			}
		}

		printer(good ? 'GOOD' : 'BAD');

		return good;
	};
});
<commit_msg>Fix equal for arrays<commit_after>define(['require', 'exports', 'parser'], function(require, exports, parserJS) {
	var Parser = parserJS.Parser;
	var tests = exports.tests = [
		function basicParse1(parser) { // Test very basic parsing
			return assert(parser.parse('echo hello'), ['echo', 'hello']);
		},
		function basicParse2(parser) { // Some more basic parsing
			return assert(parser.parse('edit websites/WebCLIOS/index.html'), ['edit', 'websites/WebCLIOS/index.html']);
		},
		function basicParse3(parser) { // And even some more almost identical to above
			return assert(parser.parse('show websites/WebCLIOS/index.html'), ['show', 'websites/WebCLIOS/index.html']);
		},
		function history1(parser) { // Test to see if !! to get the whole last parse
			parser.parse('hello');

			return assert(parser.parse('!!'), ['hello']);
		},
		function history2(parser) { // Test to see if !$ correctly gets the last argument of the last command
			parser.parse('echo hello world');

			return assert(parser.parse('echo !$'), ['echo', 'world']);
		},
		function history3(parser) { // Test to see if !<num> works correctly basicly the same as !! but a different index (other than 0)
			parser.history[33] = { split: ['show', '~/code/cliParser/parser.html'], text: 'show ~/code/cliParser/parser.html' };

			return assert(parser.parse('!33'), ['show', '~/code/cliParser/parser.html']);
		},
		function history4(parser) { // Test !$ again this time more realistic
			parser.parse('ls /media');

			return assert(parser.parse('cd !$'), ['cd', '/media']);
		},
		function history5(parser) { // And again another realistic test
			parser.parse('ls /media');

			return assert(parser.parse('ls -lha !$'), ['ls', '-lha', '/media']);
		},
		function toCMDLine1(parser) { // Test to see if the toCMDLine will correctly create a command from a parsed array
			return assert(parser.toCMDLine(parser.parse('echo hello world')), '"echo" "hello" "world"');
		},
		function toCMDLine2(parser) { // Test it again now seeing if parsing it after running it through toCMDLine returns the correct result
			return assert(parser.parse(parser.toCMDLine(['echo', 'hello', 'world'])), ['echo', 'hello', 'world']);
		},
		function toCMDLine3(parser) { // Test to see if the reparsed is == to just parsed
			return assert(parser.parse(parser.toCMDLine(['cat', '/etc/httpd.conf'])), parser.parse('cat /etc/httpd.conf'));
		},
		function enviormentVariables1(parser) { // Test to see if variable subsitution works correctly
			return assert(parser.parse('echo $variable', { variable: "hello world" }), ['echo', 'hello', 'world']);
		},
		function enviormentVariables2(parser) { // Test it again
			return assert(parser.parse('$vim_path', { vim_path: '/usr/bin/vim' }), ['/usr/bin/vim']);
		},
		function embeddedCmd1(parser) { // Test embedded commands with the $(<cmd>) syntax
			return assert(parser.parse('echo $(pwd)', {}, function(cmd, env, execCmd) {
				return 'cmd';
			}), ['echo', 'cmd']);
		},
		function embeddedCmd2(parser) { // Test it again but with variable subsitution and backtick syntax mixed in
			return assert(parser.parse('echo $(echo `pwd`/$filename.$filetype)', { filename: 'hello', filetype: 'txt' }, function(cmd, env, execCMD) {
				return parser.toCMDLine(parser.parse(cmd, env, execCMD));
			}), ['echo', 'echo', 'pwd/hello.txt']);
		},
		function embeddedCmd3(parser) { // Test to see if escaping backslashes works
			return assert(parser.parse('\\\\$(pwd)', {}, function(cmd, env, execCMD) {
				return parser.parse(cmd, env, execCMD).join(' ');
			}), ['\\pwd']);
		},
		function string1(parser) { // Test strings to see if they correctly split the command
			return assert(parser.parse('echo "hello world"'), ['echo', 'hello world']);
		},
		function string2(parser) { // Test multiple strings
			return assert(parser.parse('"hi""hello "'), ['hihello ']);
		},
		function string3(parser) { // Test string now with single-quote
			return assert(parser.parse("echo 'hello world'"), ['echo', 'hello world'])
		},
		function string4(parser) {
			return assert(parser.parse("echo 'hello 'hi''"), ['echo', 'hello hi']);
		},
		function escape1(parser) { // Test to see if we can escape quotes
			return assert(parser.parse('echo "hi \\""'), ['echo', 'hi "']);
		},
		function escape2(parser) { // And now testing with $
			return assert(parser.parse('echo \\$filename'), ['echo', '$filename']);
		},
		function escape3(parser) { // Test for a bug i found where escaping backslashes doesn't work (problably because i hadn't implemented it yet)
			return assert(parser.parse('\\\\"hi "'), ['\\hi ']);
		}
	];

	function type(o) {
		var oType = typeof(o);

		switch(oType) {
			case 'object':
				if(o === null) oType = 'null';
				else if(o.constructor == String) oType = 'string';
				else if(o.constructor == Number) oType = 'number';
				else if(type(o.length) == 'number') oType = 'array';
				break;
		}

		return oType;
	}

	function equal(first, second) {
		var fType = type(first), sType = type(first);
		if(fType == 'array' && sType == 'array') { // Array
			if(!equal(first.length, second.length)) return false;

			var good = true;

			for(var i = 0; i < first.length; i++) {
				if(!equal(first[i], second[i])) good = false;
			}

			return good;
		} else if(fType == 'string' && sType == 'string') { // String
			return first.toString() == second.toString();
		} else {
			return false;
		}
	}

	function assert(got, expected) {
		return { value: got, expected: expected, good: equal(got, expected) };
	}

	exports.run = function run(printer) {
		var good = true, goods = [], tmp;

		printer = printer || ( !!window.puts ? function(str) { return puts(str + '\n'); } : console.log.bind(console)) || window.alert.bind(window);

		for(var i = 0; i < tests.length; i++) {
			try {
				if(!(tmp = tests[i](new Parser())).good) {
					good = false;
					goods[i] = false;
					printer('BAD: ' + tests[i].name + ' ' + tmp.value + ' ' + tmp.expected);
				} else {
					goods[i] = true;
					printer('GOOD: ' + tests[i].name);
				}
			} catch(ex) {
				printer('BAD: ' + tests[i].name + ' EX: ' + ex + ' ' + ex.stack + ' ' + ex.message);
			}
		}

		printer(good ? 'GOOD' : 'BAD');

		return good;
	};
});
<|endoftext|>


<commit_before>/*
 * Laconica - a distributed open-source microblogging tool
 * Copyright (C) 2008, Controlez-Vous, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

$(document).ready(function(){
	// count character on keyup
	function counter(event){
		var maxLength = 140;
		var currentLength = $("#notice_data-text").val().length;
		var remaining = maxLength - currentLength;
		var counter = $("#notice_text-count");
		counter.text(remaining);

		if (remaining <= 0) {
			$("#form_notice").addClass("warning");
		} else {
			$("#form_notice").removeClass("warning");
		}
	}

	function submitonreturn(event) {
		if (event.keyCode == 13) {
			$("#form_notice").submit();
			event.preventDefault();
			event.stopPropagation();
			return false;
		}
		return true;
	}

	if ($("#notice_data-text").length) {
		$("#notice_data-text").bind("keyup", counter);
		$("#notice_data-text").bind("keydown", submitonreturn);

		// run once in case there's something in there
		counter();

		// set the focus
		$("#notice_data-text").focus();
	}

	// XXX: refactor this code

	var favoptions = { dataType: 'xml',
					   success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true);
												var dis = new_form.id;
												var fav = dis.replace('disfavor', 'favor');
												$('form#'+fav).replaceWith(new_form);
												$('form#'+dis).ajaxForm(disoptions).each(addAjaxHidden);
											  }
					 };

	var disoptions = { dataType: 'xml',
					   success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true);
												var fav = new_form.id;
												var dis = fav.replace('favor', 'disfavor');
												$('form#'+dis).replaceWith(new_form);
												$('form#'+fav).ajaxForm(favoptions).each(addAjaxHidden);
											  }
					 };

	var joinoptions = { dataType: 'xml',
					   success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true);
												var leave = new_form.id;
												var join = leave.replace('leave', 'join');
												$('form#'+join).replaceWith(new_form);
												$('form#'+leave).ajaxForm(leaveoptions).each(addAjaxHidden);
											  }
					 };

	var leaveoptions = { dataType: 'xml',
					   success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true);
												var join = new_form.id;
												var leave = join.replace('join', 'leave');
												$('form#'+leave).replaceWith(new_form);
												$('form#'+join).ajaxForm(joinoptions).each(addAjaxHidden);
											  }
					 };

	function addAjaxHidden() {
		var ajax = document.createElement('input');
		ajax.setAttribute('type', 'hidden');
		ajax.setAttribute('name', 'ajax');
		ajax.setAttribute('value', 1);
		this.appendChild(ajax);
	}

	$("form.form_favor").ajaxForm(favoptions);
	$("form.form_disfavor").ajaxForm(disoptions);
	$("form.form_group_join").ajaxForm(joinoptions);
	$("form.form_group_leave").ajaxForm(leaveoptions);
	$("form.form_favor").each(addAjaxHidden);
	$("form.form_disfavor").each(addAjaxHidden);
	$("form.form_group_join").each(addAjaxHidden);
	$("form.form_group_leave").each(addAjaxHidden);

	$("#form_user_nudge").ajaxForm ({ dataType: 'xml',
		beforeSubmit: function(xml) { $("#form_user_nudge input[type=submit]").attr("disabled", "disabled");
									  $("#form_user_nudge input[type=submit]").addClass("disabled");
									},
		success: function(xml) { $("#form_user_nudge").replaceWith(document._importNode($("#nudge_response", xml).get(0),true));
							     $("#form_user_nudge input[type=submit]").removeAttr("disabled");
							     $("#form_user_nudge input[type=submit]").removeClass("disabled");
							   }
	 });
	$("#form_user_nudge").each(addAjaxHidden);

	var Subscribe = { dataType: 'xml',
					  beforeSubmit: function(formData, jqForm, options) { $(".form_user_subscribe input[type=submit]").attr("disabled", "disabled");
																	      $(".form_user_subscribe input[type=submit]").addClass("disabled");
																	    },
					  success: function(xml) { var form_unsubscribe = document._importNode($('form', xml).get(0), true);
										  	   var form_unsubscribe_id = form_unsubscribe.id;
											   var form_subscribe_id = form_unsubscribe_id.replace('unsubscribe', 'subscribe');
											   $("form#"+form_subscribe_id).replaceWith(form_unsubscribe);
											   $("form#"+form_unsubscribe_id).ajaxForm(UnSubscribe).each(addAjaxHidden);
											   $("dd.subscribers").text(parseInt($("dd.subscribers").text())+1);
											   $(".form_user_subscribe input[type=submit]").removeAttr("disabled");
											   $(".form_user_subscribe input[type=submit]").removeClass("disabled");
										     }
					};

	var UnSubscribe = { dataType: 'xml',
						beforeSubmit: function(formData, jqForm, options) { $(".form_user_unsubscribe input[type=submit]").attr("disabled", "disabled");
																		    $(".form_user_unsubscribe input[type=submit]").addClass("disabled");
																		  },
					    success: function(xml) { var form_subscribe = document._importNode($('form', xml).get(0), true);
										  		 var form_subscribe_id = form_subscribe.id;
												 var form_unsubscribe_id = form_subscribe_id.replace('subscribe', 'unsubscribe');
												 $("form#"+form_unsubscribe_id).replaceWith(form_subscribe);
												 $("form#"+form_subscribe_id).ajaxForm(Subscribe).each(addAjaxHidden);
												 $("#profile_send_a_new_message").remove();
												 $("#profile_nudge").remove();
											     $("dd.subscribers").text(parseInt($("dd.subscribers").text())-1);
												 $(".form_user_unsubscribe input[type=submit]").removeAttr("disabled");
												 $(".form_user_unsubscribe input[type=submit]").removeClass("disabled");
											   }
					  };

	$(".form_user_subscribe").ajaxForm(Subscribe);
	$(".form_user_unsubscribe").ajaxForm(UnSubscribe);
	$(".form_user_subscribe").each(addAjaxHidden);
	$(".form_user_unsubscribe").each(addAjaxHidden);

	var PostNotice = { dataType: 'xml',
					   beforeSubmit: function(formData, jqForm, options) { if ($("#notice_data-text").get(0).value.length == 0) {
																				$("#form_notice").addClass("warning");
																				return false;
																		   }
																		   $("#form_notice").addClass("processing");
																		   $("#notice_action-submit").attr("disabled", "disabled");
																		   $("#notice_action-submit").addClass("disabled");
																		   return true;
												 						 },
					   success: function(xml) {	if ($("#error", xml).length > 0) {
													var result = document._importNode($("p", xml).get(0), true);
													result = result.textContent || result.innerHTML;
													alert(result);
												}
												else {
												    if ($("#command_result", xml).length > 0) {
													    var result = document._importNode($("p", xml).get(0), true);
													    result = result.textContent || result.innerHTML;
													    alert(result);
                                                    }
                                                    else {
													    $("#notices_primary .notices").prepend(document._importNode($("li", xml).get(0), true));
													    $("#notices_primary .notice:first").css({display:"none"});
													    $("#notices_primary .notice:first").fadeIn(2500);
													    NoticeHover();
													    NoticeReply();
													}
													$("#notice_data-text").val("");
                                                    counter();
												}
												$("#form_notice").removeClass("processing");
												$("#notice_action-submit").removeAttr("disabled");
												$("#notice_action-submit").removeClass("disabled");
											 }
					   };
	$("#form_notice").ajaxForm(PostNotice);
	$("#form_notice").each(addAjaxHidden);
    NoticeHover();
    NoticeReply();
});

function NoticeHover() {
    $("#content .notice").hover(
        function () {
            $(this).addClass('hover');
        },
        function () {
            $(this).removeClass('hover');
        }
    );
}

function NoticeReply() {
    if ($('#notice_data-text').length > 0) {
        $('#content .notice').each(function() {
            var notice = $(this);
            $('.notice_reply', $(this)).click(function() {
                var nickname = ($('.author .nickname', notice).length > 0) ? $('.author .nickname', notice) : $('.author .nickname');
                NoticeReplySet(nickname.text(), $('.notice_id', notice).text());
                return false;
            });
        });
    }
}

function NoticeReplySet(nick,id) {
	rgx_username = /^[0-9a-zA-Z\-_.]*$/;
	if (nick.match(rgx_username)) {
		replyto = "@" + nick + " ";
		if ($("#notice_data-text").length) {
			$("#notice_data-text").val(replyto);
			$("#form_notice input#notice_in-reply-to").val(id);
			$("#notice_data-text").focus();
			return false;
		}
	}
	return true;
}
<commit_msg>XHR alerts for server-side errors: 404, 502, 503, 504. There is also a 7 second timeout if the server doesn't get back with a response.<commit_after>/*
 * Laconica - a distributed open-source microblogging tool
 * Copyright (C) 2008, Controlez-Vous, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

$(document).ready(function(){
	// count character on keyup
	function counter(event){
		var maxLength = 140;
		var currentLength = $("#notice_data-text").val().length;
		var remaining = maxLength - currentLength;
		var counter = $("#notice_text-count");
		counter.text(remaining);

		if (remaining <= 0) {
			$("#form_notice").addClass("warning");
		} else {
			$("#form_notice").removeClass("warning");
		}
	}

	function submitonreturn(event) {
		if (event.keyCode == 13) {
			$("#form_notice").submit();
			event.preventDefault();
			event.stopPropagation();
			return false;
		}
		return true;
	}

	if ($("#notice_data-text").length) {
		$("#notice_data-text").bind("keyup", counter);
		$("#notice_data-text").bind("keydown", submitonreturn);

		// run once in case there's something in there
		counter();

		// set the focus
		$("#notice_data-text").focus();
	}

	// XXX: refactor this code

	var favoptions = { dataType: 'xml',
					   success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true);
												var dis = new_form.id;
												var fav = dis.replace('disfavor', 'favor');
												$('form#'+fav).replaceWith(new_form);
												$('form#'+dis).ajaxForm(disoptions).each(addAjaxHidden);
											  }
					 };

	var disoptions = { dataType: 'xml',
					   success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true);
												var fav = new_form.id;
												var dis = fav.replace('favor', 'disfavor');
												$('form#'+dis).replaceWith(new_form);
												$('form#'+fav).ajaxForm(favoptions).each(addAjaxHidden);
											  }
					 };

	var joinoptions = { dataType: 'xml',
					   success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true);
												var leave = new_form.id;
												var join = leave.replace('leave', 'join');
												$('form#'+join).replaceWith(new_form);
												$('form#'+leave).ajaxForm(leaveoptions).each(addAjaxHidden);
											  }
					 };

	var leaveoptions = { dataType: 'xml',
					   success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true);
												var join = new_form.id;
												var leave = join.replace('join', 'leave');
												$('form#'+leave).replaceWith(new_form);
												$('form#'+join).ajaxForm(joinoptions).each(addAjaxHidden);
											  }
					 };

	function addAjaxHidden() {
		var ajax = document.createElement('input');
		ajax.setAttribute('type', 'hidden');
		ajax.setAttribute('name', 'ajax');
		ajax.setAttribute('value', 1);
		this.appendChild(ajax);
	}

	$("form.form_favor").ajaxForm(favoptions);
	$("form.form_disfavor").ajaxForm(disoptions);
	$("form.form_group_join").ajaxForm(joinoptions);
	$("form.form_group_leave").ajaxForm(leaveoptions);
	$("form.form_favor").each(addAjaxHidden);
	$("form.form_disfavor").each(addAjaxHidden);
	$("form.form_group_join").each(addAjaxHidden);
	$("form.form_group_leave").each(addAjaxHidden);

	$("#form_user_nudge").ajaxForm ({ dataType: 'xml',
		beforeSubmit: function(xml) { $("#form_user_nudge input[type=submit]").attr("disabled", "disabled");
									  $("#form_user_nudge input[type=submit]").addClass("disabled");
									},
		success: function(xml) { $("#form_user_nudge").replaceWith(document._importNode($("#nudge_response", xml).get(0),true));
							     $("#form_user_nudge input[type=submit]").removeAttr("disabled");
							     $("#form_user_nudge input[type=submit]").removeClass("disabled");
							   }
	 });
	$("#form_user_nudge").each(addAjaxHidden);

	var Subscribe = { dataType: 'xml',
					  beforeSubmit: function(formData, jqForm, options) { $(".form_user_subscribe input[type=submit]").attr("disabled", "disabled");
																	      $(".form_user_subscribe input[type=submit]").addClass("disabled");
																	    },
					  success: function(xml) { var form_unsubscribe = document._importNode($('form', xml).get(0), true);
										  	   var form_unsubscribe_id = form_unsubscribe.id;
											   var form_subscribe_id = form_unsubscribe_id.replace('unsubscribe', 'subscribe');
											   $("form#"+form_subscribe_id).replaceWith(form_unsubscribe);
											   $("form#"+form_unsubscribe_id).ajaxForm(UnSubscribe).each(addAjaxHidden);
											   $("dd.subscribers").text(parseInt($("dd.subscribers").text())+1);
											   $(".form_user_subscribe input[type=submit]").removeAttr("disabled");
											   $(".form_user_subscribe input[type=submit]").removeClass("disabled");
										     }
					};

	var UnSubscribe = { dataType: 'xml',
						beforeSubmit: function(formData, jqForm, options) { $(".form_user_unsubscribe input[type=submit]").attr("disabled", "disabled");
																		    $(".form_user_unsubscribe input[type=submit]").addClass("disabled");
																		  },
					    success: function(xml) { var form_subscribe = document._importNode($('form', xml).get(0), true);
										  		 var form_subscribe_id = form_subscribe.id;
												 var form_unsubscribe_id = form_subscribe_id.replace('subscribe', 'unsubscribe');
												 $("form#"+form_unsubscribe_id).replaceWith(form_subscribe);
												 $("form#"+form_subscribe_id).ajaxForm(Subscribe).each(addAjaxHidden);
												 $("#profile_send_a_new_message").remove();
												 $("#profile_nudge").remove();
											     $("dd.subscribers").text(parseInt($("dd.subscribers").text())-1);
												 $(".form_user_unsubscribe input[type=submit]").removeAttr("disabled");
												 $(".form_user_unsubscribe input[type=submit]").removeClass("disabled");
											   }
					  };

	$(".form_user_subscribe").ajaxForm(Subscribe);
	$(".form_user_unsubscribe").ajaxForm(UnSubscribe);
	$(".form_user_subscribe").each(addAjaxHidden);
	$(".form_user_unsubscribe").each(addAjaxHidden);

	var PostNotice = { dataType: 'xml',
					   beforeSubmit: function(formData, jqForm, options) { if ($("#notice_data-text").get(0).value.length == 0) {
																				$("#form_notice").addClass("warning");
																				return false;
																		   }
																		   $("#form_notice").addClass("processing");
																		   $("#notice_action-submit").attr("disabled", "disabled");
																		   $("#notice_action-submit").addClass("disabled");
																		   return true;
												 						 },
					   timeout: 1000,
					   error: function (xhr, textStatus, errorThrown) {	$("#form_notice").removeClass("processing");
																		$("#notice_action-submit").removeAttr("disabled");
																		$("#notice_action-submit").removeClass("disabled");

																		if (textStatus == "timeout") {
																			alert ("Sorry! We had trouble sending your notice. The servers are overloaded. Please try again, and contact the site administrator if this problem persists");
																		}
																		else {
																			switch(xhr.status) {
																				default: case 404:
																					alert("Sorry! We had trouble sending your notice.  Please report the problem to the site administrator if this happens again.");
																					break;
																				case 502: case 503: case 504:
																					alert("Sorry! We had trouble sending your notice. The servers are overloaded. Please try again, and contact the site administrator if this problem persists.");
																					break;
																			}
																		}
																	  },
					   success: function(xml) {	if ($("#error", xml).length > 0) {
													var result = document._importNode($("p", xml).get(0), true);
													result = result.textContent || result.innerHTML;
													alert(result);
												}
												else {
												    if ($("#command_result", xml).length > 0) {
													    var result = document._importNode($("p", xml).get(0), true);
													    result = result.textContent || result.innerHTML;
													    alert(result);
                                                    }
                                                    else {
													    $("#notices_primary .notices").prepend(document._importNode($("li", xml).get(0), true));
													    $("#notices_primary .notice:first").css({display:"none"});
													    $("#notices_primary .notice:first").fadeIn(2500);
													    NoticeHover();
													    NoticeReply();
													}
													$("#notice_data-text").val("");
                                                    counter();
												}
												$("#form_notice").removeClass("processing");
												$("#notice_action-submit").removeAttr("disabled");
												$("#notice_action-submit").removeClass("disabled");
											 }
					   };
	$("#form_notice").ajaxForm(PostNotice);
	$("#form_notice").each(addAjaxHidden);
    NoticeHover();
    NoticeReply();
});

function NoticeHover() {
    $("#content .notice").hover(
        function () {
            $(this).addClass('hover');
        },
        function () {
            $(this).removeClass('hover');
        }
    );
}

function NoticeReply() {
    if ($('#notice_data-text').length > 0) {
        $('#content .notice').each(function() {
            var notice = $(this);
            $('.notice_reply', $(this)).click(function() {
                var nickname = ($('.author .nickname', notice).length > 0) ? $('.author .nickname', notice) : $('.author .nickname');
                NoticeReplySet(nickname.text(), $('.notice_id', notice).text());
                return false;
            });
        });
    }
}

function NoticeReplySet(nick,id) {
	rgx_username = /^[0-9a-zA-Z\-_.]*$/;
	if (nick.match(rgx_username)) {
		replyto = "@" + nick + " ";
		if ($("#notice_data-text").length) {
			$("#notice_data-text").val(replyto);
			$("#form_notice input#notice_in-reply-to").val(id);
			$("#notice_data-text").focus();
			return false;
		}
	}
	return true;
}
<|endoftext|>


<commit_before>/*
Copyright (C) 2008-2009  Arne Goedeke

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
/**
 * Some helpful utility functions.
 * @namespace
 */
UTIL = new Object();
/**
 * Flexible RegExp-based replace function. Calls a callback for every match and replaced it by the returned string.
 * @param {Object} reg RegExp Object to be used.
 * @param {String} s String to perform the replace on.
 * @param {Function} cb Callback to be called for every match. Parameters to the callback will be the result returned by the call to RegExp.exec and possible extra arguments that were passed to replace.
 * @returns The resulting string.
 */
UTIL.replace = function(reg, s, cb) {
	var res;
	var last = 0;
	var ret = "";
	var extra;

	if (arguments.length > 3) {
		extra = new Array();
		for (var i = 3; i < arguments.length; i++) extra[i-3] = arguments[i];
	}

	while (null != (res = reg.exec(s))) {
		ret += s.substr(last, reg.lastIndex - res[0].length - last);
		ret += (extra ? cb.apply(null, [res].concat(extra)) : cb(res));
		last = reg.lastIndex;
	}

	if (last < s.length) {
		ret += s.substr(last);
	}

	return ret;
};
UTIL.split_replace = function(reg, s, cb) {
	var res;
	var last = 0;
	var ret = new Array();
	var extra;

	if (arguments.length > 3) {
		extra = new Array();
		for (var i = 3; i < arguments.length; i++) extra[i-3] = arguments[i];
	}

	while (null != (res = reg.exec(s))) {
		ret.push(s.substr(last, reg.lastIndex - res[0].length - last));
		ret.push(extra ? cb.apply(null, [res].concat(extra)) : cb(res));
		last = reg.lastIndex;
	}

	if (last < s.length) {
		ret.push(s.substr(last));
	}

	return ret;
};
UTIL.has_prefix = function(s, n) {
	if (s.length < n.length) return false;
	return (n == s.substr(0, n.length));
};
UTIL.has_suffix = function(s, n) {
	if (s.length < n.length) return false;
	return (n == s.substr(s.length-n.length, n.length));
};
UTIL.search_array = function(a, n) {
	for (var i = 0; i < a.length; i++) {
		if (n == a[i]) return i;
	}

	return -1;
};
UTIL.replaceClass = function(o, cl1, cl2) {
	var classes = o.className.length ? o.className.split(' ') : [];
	var i = UTIL.search_array(classes, cl1);
	var j = UTIL.search_array(classes, cl2);

	if (i == -1 && j == -1) {
		if (cl2) classes.push(cl2);
	} else if (i == -1) {
		return;
	} else if (j == -1 && cl2) {
		classes[i] = cl2;
	} else {
		classes.splice(i, 1);
	}
	o.className = classes.join(" ");
};
UTIL.addClass = function(o, cl) {
	var classes = o.className.length ? o.className.split(' ') : [];
	var i = UTIL.search_array(classes, cl);

	if (i == -1) {
		classes.push(cl);
		o.className = classes.join(" ");
	}
};
UTIL.hasClass = function(o, cl) {
	var classes = o.className.split(' ');
	return (-1 != UTIL.search_array(classes, cl));
};
UTIL.removeClass = function(o, cl) {
	UTIL.replaceClass(o, cl);
};
UTIL.url_escape = function(s) {
    	return escape(s).replace(/\+/g, "%2B").replace(/\//g, "%2F");
};
UTIL.make_url = function(url, vars) {
    	var list = [];
	var key;
	if (vars) for (key in vars) if (vars.hasOwnProperty(key)) {
	    list.push(key + "=" + UTIL.url_escape(vars[key]));
	} else return url;

	return url + "?" + list.join("&");
};
UTIL.make_method_keep_this = function(obj, fun) {
    	if (arguments.length > 2) {
	    var list = Array.prototype.slice.call(arguments, 2);
	    return (function() {
		    return fun.apply(obj, [ this ].concat(list).concat(Array.prototype.concat.call(arguments)));
	    });
	}
	return (function() {
		return fun.apply(obj, [ this ].concat(Array.prototype.concat.call(arguments)));
	});
};
UTIL.make_method = function(obj, fun) {
    	if (arguments.length > 2) {
	    var list = Array.prototype.slice.call(arguments, 2);
	    return (function () {
		    return fun.apply(obj, list.concat(Array.prototype.slice.call(arguments)));
	    });
	}
    	return (function () {
		return fun.apply(obj, Array.prototype.slice.call(arguments));
	});
};
UTIL.Audio = function (params) {
	if (UTIL.App.has_vorbis && !!params.ogg) {
		this.url = params.ogg;
	} else if (UTIL.App.has_mp3 && !!params.mp3) {
		this.url = params.mp3;
	} else if (UTIL.App.has_wav && !!params.wav) {
		this.url = params.wav;
	}

	if (this.url) {
	    this.play = function() {
		this.audio = new Audio();
		this.audio.preload = !!params.autobuffer;
		this.audio.autoplay = !!params.autoplay;
		this.audio.loop = !!params.loop;
		this.audio.controls = !!params.controls;
		this.audio.src = this.url;
		if (this.div) {
		    if (this.div.firstChild) {
			this.div.replaceChild(this.audio, this.div.firstChild);
		    } else {
			this.div.appendChild(this.audio);
		    }
		}
		this.audio.play();

	    };
	    this.stop = function() {
		this.audio.pause();
	    };
	    if (!!params.controls || !!params.hidden) {
		this.div = document.createElement("div");
		this.getDomNode = function () {
		    return this.div;
		};
	    }
	} else {
	    if (!params.wav) throw("You are trying to use UTIL.Audio without html5 and a wav file. This will not work.");

	    if (UTIL.App.is_opera || navigator.appVersion.indexOf("Mac") != -1) {
		this.div = document.createElement("div");
		if (params.hidden) {
		    this.div.style.width = 0;
		    this.div.style.height = 0;
		}
		if (navigator.appVersion.indexOf("Linux") != -1) {
		    this.play = function () {
			this.div.innerHTML = "<embed src=\""+params.wav+"\" type=\"application/x-mplayer2\" autostart=true height=0 width=0 hidden=true>";
		    };
		} else {
		    this.play = function() {
			this.div.innerHTML = "<embed src=\""+params.wav+"\" type=\"audio/wav\" autostart=true height=0 width=0 hidden=true cache=true>";
		    }
		}
		this.getDomNode = function() {
		    return this.div;
		};
	    } else if (UTIL.App.is_ie) { // IE
		this.url = params.wav;
		if (!document.all.sound) {
		    var bgsound = document.createElement("bgsound");
		    bgsound.id = "sound";
		    document.body.appendChild(bgsound);
		}
		this.play = function () {
		    document.all.sound.src = this.url;
		}
		this.stop = function () {
		    document.all.sound.src = null;
		}
	    } else {
		this.div = document.createElement("div");
		this.div.style.width = 0;
		this.div.style.height = 0;
		this.embed = document.createElement("embed");
		this.embed.type = "audio/wav";
		this.embed.autostart = params.hasOwnProperty("autoplay") ? !!params.autoplay : false;
		this.embed.width = 0;
		this.embed.height = 0;
		this.embed.enablejavascript = true;
		this.embed.cache = params.hasOwnProperty("autobuffer") ? !!params.autobuffer : true;
		this.div.appendChild(this.embed);

		this.getDomNode = function () { return this.div; }

		if (this.embed.Play) {
		    this.play = function () { this.embed.Play(); }
		} else if (this.embed.DoPlay) {
		    this.play = function () { this.embed.DoPlay(); }
		} else throw("embed does not have a play method. Something is wrong.");

		this.stop = function () { this.embed.Stop(); }
	    }
	}
};
UTIL.App = {};
UTIL.App.is_opera = !!window.opera;
UTIL.App.is_ie = !!document.all && !UTIL.is_opera;
// The following are copied from http://www.thespanner.co.uk/2009/01/29/detecting-browsers-javascript-hacks/
UTIL.App.is_firefox = /a/[-1]=='a';
UTIL.App.is_safari = /a/.__proto__=='//';
UTIL.App.is_chrome = /source/.test((/a/.toString+''));
try {
    UTIL.App.audio = document.createElement('audio');
    UTIL.App.has_audio = !!UTIL.App.audio && !!UTIL.App.audio.canPlayType && !!UTIL.App.audio.play;
    UTIL.App.has_vorbis = UTIL.App.has_audio && UTIL.App.audio.canPlayType("audio/ogg") != "" && UTIL.App.audio.canPlayType("audio/ogg") != "no";
    UTIL.App.has_mp3 = UTIL.App.has_audio && UTIL.App.audio.canPlayType("audio/mpeg") != "" && UTIL.App.audio.canPlayType("audio/mpeg") != "no";
    UTIL.App.has_wav = UTIL.App.has_audio && UTIL.App.audio.canPlayType("audio/wav") != "" && UTIL.App.audio.canPlayType("audio/wav") != "no";
    delete UTIL.App.audio;
} catch (e) {
    UTIL.App.has_audio = false;
    UTIL.App.has_vorbis = false;
    UTIL.App.has_mp3 = false;
    UTIL.App.has_wav = false;
}
<commit_msg>moved the type detection scripts to UTIL<commit_after>/*
Copyright (C) 2008-2009  Arne Goedeke

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
/**
 * Some helpful utility functions.
 * @namespace
 */
UTIL = new Object();
/**
 * Flexible RegExp-based replace function. Calls a callback for every match and replaced it by the returned string.
 * @param {Object} reg RegExp Object to be used.
 * @param {String} s String to perform the replace on.
 * @param {Function} cb Callback to be called for every match. Parameters to the callback will be the result returned by the call to RegExp.exec and possible extra arguments that were passed to replace.
 * @returns The resulting string.
 */
UTIL.intp = function(i) { return (typeof(i) == "number" && i%1 == 0); };
UTIL.arrayp = function(a) { return (typeof(a) == "object" && a instanceof Array); };
UTIL.stringp = function(s) { return typeof(s) == "string"; };
UTIL.functionp = function(f) { return (typeof(f) == "function" || f instanceof Function); };
UTIL.objectp = function(o) { return typeof(o) == "object"; }
UTIL.replace = function(reg, s, cb) {
	var res;
	var last = 0;
	var ret = "";
	var extra;

	if (arguments.length > 3) {
		extra = new Array();
		for (var i = 3; i < arguments.length; i++) extra[i-3] = arguments[i];
	}

	while (null != (res = reg.exec(s))) {
		ret += s.substr(last, reg.lastIndex - res[0].length - last);
		ret += (extra ? cb.apply(null, [res].concat(extra)) : cb(res));
		last = reg.lastIndex;
	}

	if (last < s.length) {
		ret += s.substr(last);
	}

	return ret;
};
UTIL.split_replace = function(reg, s, cb) {
	var res;
	var last = 0;
	var ret = new Array();
	var extra;

	if (arguments.length > 3) {
		extra = new Array();
		for (var i = 3; i < arguments.length; i++) extra[i-3] = arguments[i];
	}

	while (null != (res = reg.exec(s))) {
		ret.push(s.substr(last, reg.lastIndex - res[0].length - last));
		ret.push(extra ? cb.apply(null, [res].concat(extra)) : cb(res));
		last = reg.lastIndex;
	}

	if (last < s.length) {
		ret.push(s.substr(last));
	}

	return ret;
};
UTIL.has_prefix = function(s, n) {
	if (s.length < n.length) return false;
	return (n == s.substr(0, n.length));
};
UTIL.has_suffix = function(s, n) {
	if (s.length < n.length) return false;
	return (n == s.substr(s.length-n.length, n.length));
};
UTIL.search_array = function(a, n) {
	for (var i = 0; i < a.length; i++) {
		if (n == a[i]) return i;
	}

	return -1;
};
UTIL.replaceClass = function(o, cl1, cl2) {
	var classes = o.className.length ? o.className.split(' ') : [];
	var i = UTIL.search_array(classes, cl1);
	var j = UTIL.search_array(classes, cl2);

	if (i == -1 && j == -1) {
		if (cl2) classes.push(cl2);
	} else if (i == -1) {
		return;
	} else if (j == -1 && cl2) {
		classes[i] = cl2;
	} else {
		classes.splice(i, 1);
	}
	o.className = classes.join(" ");
};
UTIL.addClass = function(o, cl) {
	var classes = o.className.length ? o.className.split(' ') : [];
	var i = UTIL.search_array(classes, cl);

	if (i == -1) {
		classes.push(cl);
		o.className = classes.join(" ");
	}
};
UTIL.hasClass = function(o, cl) {
	var classes = o.className.split(' ');
	return (-1 != UTIL.search_array(classes, cl));
};
UTIL.removeClass = function(o, cl) {
	UTIL.replaceClass(o, cl);
};
UTIL.url_escape = function(s) {
    	return escape(s).replace(/\+/g, "%2B").replace(/\//g, "%2F");
};
UTIL.make_url = function(url, vars) {
    	var list = [];
	var key;
	if (vars) for (key in vars) if (vars.hasOwnProperty(key)) {
	    list.push(key + "=" + UTIL.url_escape(vars[key]));
	} else return url;

	return url + "?" + list.join("&");
};
UTIL.make_method_keep_this = function(obj, fun) {
    	if (arguments.length > 2) {
	    var list = Array.prototype.slice.call(arguments, 2);
	    return (function() {
		    return fun.apply(obj, [ this ].concat(list).concat(Array.prototype.concat.call(arguments)));
	    });
	}
	return (function() {
		return fun.apply(obj, [ this ].concat(Array.prototype.concat.call(arguments)));
	});
};
UTIL.make_method = function(obj, fun) {
    	if (arguments.length > 2) {
	    var list = Array.prototype.slice.call(arguments, 2);
	    return (function () {
		    return fun.apply(obj, list.concat(Array.prototype.slice.call(arguments)));
	    });
	}
    	return (function () {
		return fun.apply(obj, Array.prototype.slice.call(arguments));
	});
};
UTIL.Audio = function (params) {
	if (UTIL.App.has_vorbis && !!params.ogg) {
		this.url = params.ogg;
	} else if (UTIL.App.has_mp3 && !!params.mp3) {
		this.url = params.mp3;
	} else if (UTIL.App.has_wav && !!params.wav) {
		this.url = params.wav;
	}

	if (this.url) {
	    this.play = function() {
		this.audio = new Audio();
		this.audio.preload = !!params.autobuffer;
		this.audio.autoplay = !!params.autoplay;
		this.audio.loop = !!params.loop;
		this.audio.controls = !!params.controls;
		this.audio.src = this.url;
		if (this.div) {
		    if (this.div.firstChild) {
			this.div.replaceChild(this.audio, this.div.firstChild);
		    } else {
			this.div.appendChild(this.audio);
		    }
		}
		this.audio.play();

	    };
	    this.stop = function() {
		this.audio.pause();
	    };
	    if (!!params.controls || !!params.hidden) {
		this.div = document.createElement("div");
		this.getDomNode = function () {
		    return this.div;
		};
	    }
	} else {
	    if (!params.wav) throw("You are trying to use UTIL.Audio without html5 and a wav file. This will not work.");

	    if (UTIL.App.is_opera || navigator.appVersion.indexOf("Mac") != -1) {
		this.div = document.createElement("div");
		if (params.hidden) {
		    this.div.style.width = 0;
		    this.div.style.height = 0;
		}
		if (navigator.appVersion.indexOf("Linux") != -1) {
		    this.play = function () {
			this.div.innerHTML = "<embed src=\""+params.wav+"\" type=\"application/x-mplayer2\" autostart=true height=0 width=0 hidden=true>";
		    };
		} else {
		    this.play = function() {
			this.div.innerHTML = "<embed src=\""+params.wav+"\" type=\"audio/wav\" autostart=true height=0 width=0 hidden=true cache=true>";
		    }
		}
		this.getDomNode = function() {
		    return this.div;
		};
	    } else if (UTIL.App.is_ie) { // IE
		this.url = params.wav;
		if (!document.all.sound) {
		    var bgsound = document.createElement("bgsound");
		    bgsound.id = "sound";
		    document.body.appendChild(bgsound);
		}
		this.play = function () {
		    document.all.sound.src = this.url;
		}
		this.stop = function () {
		    document.all.sound.src = null;
		}
	    } else {
		this.div = document.createElement("div");
		this.div.style.width = 0;
		this.div.style.height = 0;
		this.embed = document.createElement("embed");
		this.embed.type = "audio/wav";
		this.embed.autostart = params.hasOwnProperty("autoplay") ? !!params.autoplay : false;
		this.embed.width = 0;
		this.embed.height = 0;
		this.embed.enablejavascript = true;
		this.embed.cache = params.hasOwnProperty("autobuffer") ? !!params.autobuffer : true;
		this.div.appendChild(this.embed);

		this.getDomNode = function () { return this.div; }

		if (this.embed.Play) {
		    this.play = function () { this.embed.Play(); }
		} else if (this.embed.DoPlay) {
		    this.play = function () { this.embed.DoPlay(); }
		} else throw("embed does not have a play method. Something is wrong.");

		this.stop = function () { this.embed.Stop(); }
	    }
	}
};
UTIL.App = {};
UTIL.App.is_opera = !!window.opera;
UTIL.App.is_ie = !!document.all && !UTIL.is_opera;
// The following are copied from http://www.thespanner.co.uk/2009/01/29/detecting-browsers-javascript-hacks/
UTIL.App.is_firefox = /a/[-1]=='a';
UTIL.App.is_safari = /a/.__proto__=='//';
UTIL.App.is_chrome = /source/.test((/a/.toString+''));
try {
    UTIL.App.audio = document.createElement('audio');
    UTIL.App.has_audio = !!UTIL.App.audio && !!UTIL.App.audio.canPlayType && !!UTIL.App.audio.play;
    UTIL.App.has_vorbis = UTIL.App.has_audio && UTIL.App.audio.canPlayType("audio/ogg") != "" && UTIL.App.audio.canPlayType("audio/ogg") != "no";
    UTIL.App.has_mp3 = UTIL.App.has_audio && UTIL.App.audio.canPlayType("audio/mpeg") != "" && UTIL.App.audio.canPlayType("audio/mpeg") != "no";
    UTIL.App.has_wav = UTIL.App.has_audio && UTIL.App.audio.canPlayType("audio/wav") != "" && UTIL.App.audio.canPlayType("audio/wav") != "no";
    delete UTIL.App.audio;
} catch (e) {
    UTIL.App.has_audio = false;
    UTIL.App.has_vorbis = false;
    UTIL.App.has_mp3 = false;
    UTIL.App.has_wav = false;
}
<|endoftext|>


<commit_before>define(['backbone'], function(Backbone){

	return Backbone.View.extend({

		initialize: function(options){
			this.subviews = [];
			this.el.view = this;
		},

		addSubview: function(view){
			this.subviews.push(view);
		},

		setElement: function(element, delegate){
			Backbone.View.prototype.setElement.call(this, element, delegate);
		},

		remove: function(){
			delete this.el.view;
			Backbone.View.prototype.remove.call(this);
			_.each(this.subviews, function(subview){
				subview.remove();
			});
		},

		show: function(){},
		hide: function(){}

	});
});<commit_msg>add view state api<commit_after>define(['backbone'], function(Backbone){

	return Backbone.View.extend({

		initialize: function(options){
			this.subviews = [];
			this.el.view = this;
		},

		addSubview: function(view){
			this.subviews.push(view);
		},

		setElement: function(element, delegate){
			Backbone.View.prototype.setElement.call(this, element, delegate);
		},

		remove: function(){
			delete this.el.view;
			Backbone.View.prototype.remove.call(this);
			_.each(this.subviews, function(subview){
				subview.remove();
			});
		},

		show: function(){},
		hide: function(){},
		saveState: function(){},
		loadState: function(){}

	});
});<|endoftext|>


<commit_before>
import React from 'react'
import styled from 'styled-components'
import InputLabel from './InputLabel'
import Button from './Button'

import RegexIcon from './svg-icons/RegexIcon'
import CaseSensitiveIcon from './svg-icons/CaseSensitiveIcon'
import WholeWordIcon from './svg-icons/WholeWordIcon'

import SelectionIcon from './svg-icons/SelectionIcon'
import PageIcon from './svg-icons/PageIcon'
import DocumentIcon from './svg-icons/DocumentIcon'

const HelpPage = styled.div`
  position: absolute;
  top: ${props => props.isActive ? 0 : 240}px;
  width: 100%;
  overflow: scroll;
  height: 218px;
  padding: 14px 16px 16px 16px;
  background-color: ${props => props.theme.background};
  color: ${props => props.theme.text};
  z-index: 100;
  transition: top 0.15s ease-in-out;
  margin-bottom: 32px;
  box-sizing: border-box;
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
`

const HelpIconsContainer = styled.div`
  display: flex; /* or inline-flex */
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: flex-start;
  align-items: center;
`

const HelpIcon = styled.div`
  margin-right: 1em;

`

const HelpIconDescription = styled.div`

`

const BtnHelpContainer = styled.div`
  display: flex; /* or inline-flex */
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: space-between;
  align-items: stretch;
  margin-top: 2em;
`

const Help = (props) => {
  const {
    isActive,
    theme,
    close,
  } = props
  return <HelpPage
    isActive={isActive}
    theme={theme}
    >
    <InputLabel theme={theme}>Help</InputLabel>

Sketch Find and Replace

By Thierry Charbonnel - UX / UI and Code Designer

Options to find

    <HelpIconsContainer>
      <HelpIcon><RegexIcon theme={theme} isActive={true}/></HelpIcon>
      <HelpIconDescription>Regex (Regular expressions)*</HelpIconDescription>
    </HelpIconsContainer>

    <HelpIconsContainer>
      <HelpIcon><CaseSensitiveIcon theme={theme} isActive={true}/></HelpIcon>
      <HelpIconDescription>Case Sensitive (on)/ Case Insensitive (off)</HelpIconDescription>
    </HelpIconsContainer>

    <HelpIconsContainer>
      <HelpIcon><WholeWordIcon theme={theme} isActive={true}/></HelpIcon>
      <HelpIconDescription>Whole Word</HelpIconDescription>
    </HelpIconsContainer>

* Tips: Turn Regex off if you don't know what Regex is.

Replace context

    <HelpIconsContainer>
      <HelpIcon><SelectionIcon theme={theme} isActive={true}/></HelpIcon>
      <HelpIconDescription>Selection (visible if a selection is active)</HelpIconDescription>
    </HelpIconsContainer>

    <HelpIconsContainer>
      <HelpIcon><PageIcon theme={theme} isActive={true}/></HelpIcon>
      <HelpIconDescription>Current page</HelpIconDescription>
    </HelpIconsContainer>

    <HelpIconsContainer>
      <HelpIcon><DocumentIcon theme={theme} isActive={true}/></HelpIcon>
      <HelpIconDescription>All pages of a document</HelpIconDescription>
    </HelpIconsContainer>

By default Find and Replace don’t replace string of symbols master except if you are in selection mode or on the “Symbols” named page.

Know limitation

Backslash not allowed in the replace input.

Exit the text editon mode before to replace string

Regex (Regular expressions)

Get the Regex Power! ⚡

Regular expressions are patterns used to match character combinations in strings.

MDN Regular Expressions Guide

Javascript.info Regular Expressions Guide

Some Examples

The power of search and replace with regex.

Let's use the search and replace example from above:

Convert "John Smith" to "Smith John"

Find

(\w+)\s+(\w+)

Replace with

$2 $1

Result: Smith John.

Replace all double spaces

Find

{'\s{2,}'}

Replace with

(one space)

and more...

Say Hello

I’m always happy to be involved into interesting projects.

hello@anotherplanet.io

twitter: @Autre_planete

Github: @thierryc

    <BtnHelpContainer><Button onClick={close} theme={theme} primary theme={theme} isActive={true}>
      Close Help
    </Button></BtnHelpContainer>

  </HelpPage>
}

export default Help
<commit_msg>update help usage<commit_after>
import React from 'react'
import styled from 'styled-components'
import InputLabel from './InputLabel'
import Button from './Button'

import RegexIcon from './svg-icons/RegexIcon'
import CaseSensitiveIcon from './svg-icons/CaseSensitiveIcon'
import WholeWordIcon from './svg-icons/WholeWordIcon'

import SelectionIcon from './svg-icons/SelectionIcon'
import PageIcon from './svg-icons/PageIcon'
import DocumentIcon from './svg-icons/DocumentIcon'

const HelpPage = styled.div`
  position: absolute;
  top: ${props => props.isActive ? 0 : 240}px;
  width: 100%;
  overflow: scroll;
  height: 218px;
  padding: 14px 16px 16px 16px;
  background-color: ${props => props.theme.background};
  color: ${props => props.theme.text};
  z-index: 100;
  transition: top 0.15s ease-in-out;
  margin-bottom: 32px;
  box-sizing: border-box;
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
`

const HelpIconsContainer = styled.div`
  display: flex; /* or inline-flex */
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: flex-start;
  align-items: center;
`

const HelpIcon = styled.div`
  margin-right: 1em;

`

const HelpIconDescription = styled.div`

`

const BtnHelpContainer = styled.div`
  display: flex; /* or inline-flex */
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: space-between;
  align-items: stretch;
  margin-top: 2em;
`

const Help = (props) => {
  const {
    isActive,
    theme,
    close,
  } = props
  return <HelpPage
    isActive={isActive}
    theme={theme}
    >
    <InputLabel theme={theme}>Help</InputLabel>

Sketch Find and Replace

By Thierry Charbonnel - UX / UI and Code Designer

Options to find

    <HelpIconsContainer>
      <HelpIcon><RegexIcon theme={theme} isActive={true}/></HelpIcon>
      <HelpIconDescription>Regex (Regular expressions)*</HelpIconDescription>
    </HelpIconsContainer>

    <HelpIconsContainer>
      <HelpIcon><CaseSensitiveIcon theme={theme} isActive={true}/></HelpIcon>
      <HelpIconDescription>Case Sensitive (on)/ Case Insensitive (off)</HelpIconDescription>
    </HelpIconsContainer>

    <HelpIconsContainer>
      <HelpIcon><WholeWordIcon theme={theme} isActive={true}/></HelpIcon>
      <HelpIconDescription>Whole Word</HelpIconDescription>
    </HelpIconsContainer>

* Tips: Turn Regex off if you don't know what Regex is.

Replace context

    <HelpIconsContainer>
      <HelpIcon><SelectionIcon theme={theme} isActive={true}/></HelpIcon>
      <HelpIconDescription>Selection (visible if a selection is active)</HelpIconDescription>
    </HelpIconsContainer>

    <HelpIconsContainer>
      <HelpIcon><PageIcon theme={theme} isActive={true}/></HelpIcon>
      <HelpIconDescription>Current page</HelpIconDescription>
    </HelpIconsContainer>

    <HelpIconsContainer>
      <HelpIcon><DocumentIcon theme={theme} isActive={true}/></HelpIcon>
      <HelpIconDescription>All pages of a document</HelpIconDescription>
    </HelpIconsContainer>

By default Find and Replace don’t replace string of symbols master except if you are in selection mode or on the “Symbols” named page.

Know limitation

Backslash not allowed in the replace input.

Exit the text editon mode before to replace string

Regex (Regular expressions)

Get the Regex Power! ⚡

Regular expressions are patterns used to match character combinations in strings.

MDN Regular Expressions Guide

Javascript.info Regular Expressions Guide

Some Examples

The power of search and replace with regex.

Let's use the search and replace example from above:

Convert "John Smith" to "Smith John"

Find

(\w+)\s+(\w+)

Replace with

$2 $1

Result: Smith John.

Replace all double spaces

Find

{'\s{2,}'}

Replace with

(one space)

and more...

Say Hello

I’m always happy to be involved into interesting projects.

hello@anotherplanet.io

twitter: @Autre_planete

Github: @thierryc

    <BtnHelpContainer><Button onClick={close} theme={theme} primary theme={theme} isActive={true}>
      Close Help
    </Button></BtnHelpContainer>

  </HelpPage>
}

export default Help
<|endoftext|>


<commit_before>/**
 * Handle payloads received from Github and
 * launch the corresponding build if necessary
 */

var Job = require('../lib/job')
  , executor = require('../lib/executor')
  , customUtils = require('../lib/customUtils')
  , db = require('../lib/db')
  , _ = require('underscore')
  ;

module.exports = function (req, res, next) {
  console.log("CALLED");
  db.jobs.find({}, function (err, jobs) {
    var jobsNames = _.pluck(jobs, 'name')
      , payload = JSON.parse(req.body.payload)
      , receivedGithubRepoUrl = payload.repository.url
      , receivedBranch = payload.ref.replace(/^.*\//,'')
      , disabledMessage = { room_id: 'Deployment'
                          , from: 'Braindead CI'
                          , message_format: 'html'
                          , notify: 0
                          , color: 'gray'
                          }
      ;

    // Build all the enabled jobs corresponding using the repo and branch of this push
    jobsNames.forEach(function (name) {
      if (jobs[name].githubRepoUrl === receivedGithubRepoUrl && jobs[name].branch === receivedBranch) {
        if (jobs[name].enabled) {
          executor.registerBuild(name);
        } else {
          disabledMessage.message = name + " was not built since it's in disabled state";
          customUtils.sendMessageToHipchat(disabledMessage);
        }
      }
    });

    return res.send(200);   // Always return a success
  });
};
<commit_msg>Logging<commit_after>/**
 * Handle payloads received from Github and
 * launch the corresponding build if necessary
 */

var Job = require('../lib/job')
  , executor = require('../lib/executor')
  , customUtils = require('../lib/customUtils')
  , db = require('../lib/db')
  , _ = require('underscore')
  ;

module.exports = function (req, res, next) {
  console.log("CALLED");
  db.jobs.find({}, function (err, jobs) {
    var jobsNames = _.pluck(jobs, 'name')
      , payload = JSON.parse(req.body.payload)
      , receivedGithubRepoUrl = payload.repository.url
      , receivedBranch = payload.ref.replace(/^.*\//,'')
      , disabledMessage = { room_id: 'Deployment'
                          , from: 'Braindead CI'
                          , message_format: 'html'
                          , notify: 0
                          , color: 'gray'
                          }
      ;

      console.log(jobsNames);

    // Build all the enabled jobs corresponding using the repo and branch of this push
    jobsNames.forEach(function (name) {
      if (jobs[name].githubRepoUrl === receivedGithubRepoUrl && jobs[name].branch === receivedBranch) {
        if (jobs[name].enabled) {
          executor.registerBuild(name);
        } else {
          disabledMessage.message = name + " was not built since it's in disabled state";
          customUtils.sendMessageToHipchat(disabledMessage);
        }
      }
    });

    return res.send(200);   // Always return a success
  });
};
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var marked = require('marked');
var sizeOf = require('image-size');
var insertProjectInfo = require('./insert-project-info');
var compile = require('handlebars').compile;
var async = require('async');

var ownerId;
var gistId;
const utf8Encoding = {encoding: 'utf8'};

// parse triple dashes as section dividers
function mdToSections (text) {
  var slideRegExp = new RegExp(/\r?\n+---\r?\n+/g);
  var matches;
  var lastIndex = 0;
  var output = '';
  var wrapInSection = function (text) {
    return '
' + text + '
';
  };

  while ((matches = slideRegExp.exec(text)) !== null) {
    output += wrapInSection(marked(text.substring(lastIndex, matches.index)));
    lastIndex = slideRegExp.lastIndex;
  }

  output += wrapInSection(marked(text.substring(lastIndex)));
  return output;
}

module.exports = function (req, res, next) {
  'use strict';

  ownerId = req.params.owner || 'anon';
  gistId = req.params.project;

  const bodyToken = '{{{body}}}';
  const gistDir = req.app.locals.localDevDir || path.join(req.app.locals.cacheDir, ownerId, gistId);

  let html = req.app.locals.views['gist.html'].split(bodyToken);
  let gist;
  let gistFilenames;
  let parallaxBackground;
  let noIndexFile;
  let scripts = [
    '/public/d3.min.js',
    '/public/d3-maximize.min.js',
    '//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'
  ];
  let styles = [
    '/public/gist-info.css'
  ];
  let context = { owner: ownerId };
  let isReportUrl = req.url.slice(-8) === '/report/';
  let isPresentationUrl = req.url.substr(-14) === '/presentation/';
  let hasReport = false;
  let hasPresentation = false;

  const getGistFilePath = (filename) => {
    return path.join(gistDir, filename);
  };

  // steps

  const redirectIfNeeded = (cb) => {
    fs.readdir(gistDir, (err, files) => {
      hasPresentation = _.includes(files, 'presentation.md');
      hasReport = _.includes(files, 'report.md');

      if (err) return cb(err);

      if (!hasReport && !hasPresentation) {
        // if no valid files found, bail out and warn
        res.send('No valid files found. Valid files are ' + req.app.locals.validFiles.join(', '));
        return cb(true);
      } else {
        // if requesting a specific resource continue on
        if (isReportUrl && hasReport) return cb();
        if (isPresentationUrl && hasPresentation) return cb();

        // default redirect is report, if valid
        if (hasReport) {
          res.redirect(req.originalUrl + 'report/');
          return cb(true);
        }

        // fallback redirect is presentation
        if (hasPresentation) {
          res.redirect(req.originalUrl + 'presentation/');
          return cb(true);
        }
      }
    });
  };

  const getGistDetails = (cb) => {
    fs.readFile(getGistFilePath(req.app.locals.dataFilename), utf8Encoding, (err, data) => {
      gist = JSON.parse(data);
      cb(err, data);
    });
  };

  const getGistFiles = (cb) => {
    fs.readdir(gistDir, (err, files) => {
      gistFilenames = files;
      files.sort();

      files.forEach(function (filename) {
        if (filename.substr(-3) === '.js') scripts.push(filename);
        if (filename.substr(-4) === '.css') styles.push(filename);
        if (filename.indexOf('parallax') === 0 && gist.files[filename]) parallaxBackground = filename;
      });
      cb(err, files);
    });
  };

  const populateContext = (cb) => {
    context.title = gist.description ? gist.description.split(' | ')[0] : gist.id;
    context.scripts = scripts;
    context.styles = styles;
    context.gist_url = gist.html_url;
    cb();
  };

  const serveReport = (cb) => {
    if (!isReportUrl) return cb();

    fs.readFile(getGistFilePath('report.md'), utf8Encoding, (err, data) => {
      html = html[0] + '
' + bodyToken + '
' + html[1];
      context.body = marked(data);
      context.styles.unshift('/public/nciea.css');
      cb(err, data);
    });
  };

  const servePresentation = (cb) => {
    if (!isPresentationUrl) return cb();

    html = req.app.locals.views['presentation.html'];
    if (parallaxBackground) {
      var dim = sizeOf(getGistFilePath(parallaxBackground));
      html = html.split("parallaxBackgroundImage: '").join("parallaxBackgroundImage: '" + parallaxBackground);
      html = html.split("parallaxBackgroundSize: '").join("parallaxBackgroundSize: '" + dim.width + 'px ' + dim.height + 'px');
    }
    cb();
  };

  async.series([
    redirectIfNeeded,
    getGistDetails,
    getGistFiles,
    populateContext,
    serveReport,
    servePresentation
  ], (err, results) => {
    if (typeof err === 'boolean') return; // either redirect or error message
    if (err) {
      console.log(err);
      res.send('Something went wrong.')
    }

    if (gist.public) {
      html = insertProjectInfo(html, req.app.locals.views['gist-info.html']);
    }

    res.send(compile(html)(context));
  });
};
<commit_msg>Bail on error<commit_after>var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var marked = require('marked');
var sizeOf = require('image-size');
var insertProjectInfo = require('./insert-project-info');
var compile = require('handlebars').compile;
var async = require('async');

var ownerId;
var gistId;
const utf8Encoding = {encoding: 'utf8'};

// parse triple dashes as section dividers
function mdToSections (text) {
  var slideRegExp = new RegExp(/\r?\n+---\r?\n+/g);
  var matches;
  var lastIndex = 0;
  var output = '';
  var wrapInSection = function (text) {
    return '
' + text + '
';
  };

  while ((matches = slideRegExp.exec(text)) !== null) {
    output += wrapInSection(marked(text.substring(lastIndex, matches.index)));
    lastIndex = slideRegExp.lastIndex;
  }

  output += wrapInSection(marked(text.substring(lastIndex)));
  return output;
}

module.exports = function (req, res, next) {
  'use strict';

  ownerId = req.params.owner || 'anon';
  gistId = req.params.project;

  const bodyToken = '{{{body}}}';
  const gistDir = req.app.locals.localDevDir || path.join(req.app.locals.cacheDir, ownerId, gistId);

  let html = req.app.locals.views['gist.html'].split(bodyToken);
  let gist;
  let gistFilenames;
  let parallaxBackground;
  let noIndexFile;
  let scripts = [
    '/public/d3.min.js',
    '/public/d3-maximize.min.js',
    '//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'
  ];
  let styles = [
    '/public/gist-info.css'
  ];
  let context = { owner: ownerId };
  let isReportUrl = req.url.slice(-8) === '/report/';
  let isPresentationUrl = req.url.substr(-14) === '/presentation/';
  let hasReport = false;
  let hasPresentation = false;

  const getGistFilePath = (filename) => {
    return path.join(gistDir, filename);
  };

  // steps

  const redirectIfNeeded = (cb) => {
    fs.readdir(gistDir, (err, files) => {
      hasPresentation = _.includes(files, 'presentation.md');
      hasReport = _.includes(files, 'report.md');

      if (err) return cb(err);

      if (!hasReport && !hasPresentation) {
        // if no valid files found, bail out and warn
        res.send('No valid files found. Valid files are ' + req.app.locals.validFiles.join(', '));
        return cb(true);
      } else {
        // if requesting a specific resource continue on
        if (isReportUrl && hasReport) return cb();
        if (isPresentationUrl && hasPresentation) return cb();

        // default redirect is report, if valid
        if (hasReport) {
          res.redirect(req.originalUrl + 'report/');
          return cb(true);
        }

        // fallback redirect is presentation
        if (hasPresentation) {
          res.redirect(req.originalUrl + 'presentation/');
          return cb(true);
        }
      }
    });
  };

  const getGistDetails = (cb) => {
    fs.readFile(getGistFilePath(req.app.locals.dataFilename), utf8Encoding, (err, data) => {
      gist = JSON.parse(data);
      cb(err, data);
    });
  };

  const getGistFiles = (cb) => {
    fs.readdir(gistDir, (err, files) => {
      gistFilenames = files;
      files.sort();

      files.forEach(function (filename) {
        if (filename.substr(-3) === '.js') scripts.push(filename);
        if (filename.substr(-4) === '.css') styles.push(filename);
        if (filename.indexOf('parallax') === 0 && gist.files[filename]) parallaxBackground = filename;
      });
      cb(err, files);
    });
  };

  const populateContext = (cb) => {
    context.title = gist.description ? gist.description.split(' | ')[0] : gist.id;
    context.scripts = scripts;
    context.styles = styles;
    context.gist_url = gist.html_url;
    cb();
  };

  const serveReport = (cb) => {
    if (!isReportUrl) return cb();

    fs.readFile(getGistFilePath('report.md'), utf8Encoding, (err, data) => {
      html = html[0] + '
' + bodyToken + '
' + html[1];
      context.body = marked(data);
      context.styles.unshift('/public/nciea.css');
      cb(err, data);
    });
  };

  const servePresentation = (cb) => {
    if (!isPresentationUrl) return cb();

    html = req.app.locals.views['presentation.html'];
    if (parallaxBackground) {
      var dim = sizeOf(getGistFilePath(parallaxBackground));
      html = html.split("parallaxBackgroundImage: '").join("parallaxBackgroundImage: '" + parallaxBackground);
      html = html.split("parallaxBackgroundSize: '").join("parallaxBackgroundSize: '" + dim.width + 'px ' + dim.height + 'px');
    }
    cb();
  };

  async.series([
    redirectIfNeeded,
    getGistDetails,
    getGistFiles,
    populateContext,
    serveReport,
    servePresentation
  ], (err, results) => {
    if (typeof err === 'boolean') return; // either redirect or error message
    if (err) {
      console.log(err);
      return res.send('Something went wrong.');
    }

    if (gist.public) {
      html = insertProjectInfo(html, req.app.locals.views['gist-info.html']);
    }

    res.send(compile(html)(context));
  });
};
<|endoftext|>