Alice

 view release on metacpan or  search on metacpan

lib/Alice/Readme.pod  view on Meta::CPAN

The only difference of note is the "Avatar" field. In reality, this field
just sets the B<realname>. Alice abuses this field to get avatars for users.
If a user has an image URL or an email address as their realname, alice
will display the image next too their messages. This feature can be disabled
in the Preferences window.

=head2 PREFERENCES WINDOW

The Preferences window can be used to set configuration options that
are not connection specific. You can toggle the use of avatars, timestamps,
and notifications. You can also edit a list of highlightable terms.

=head2 HTTP AUTHENTICATION

Some configuration options do not have a UI yet. The most notable
of these options is HTTP authentication. If you would like to use
HTTP authentication, you will have to edit your configuration file
by hand. You can find this file at ~/.alice/config.

The config is simply a perl hash. So, if you are familiar with perl it
should not be too intimidating. If you do not know perl, sorry! :)

You will need to add "user" and "pass" values to the "auth" hash.
The resulting section of configuration might look like this:

    'auth' => {
      'user' => 'lee',

share/static/alice-dark.css  view on Meta::CPAN

  padding: 0;
  height: auto;
  line-height: 0px; }

div#input div {
  padding: 0 3px;
  background: black;
  margin: 3px 0;
  position: relative; }

div#input div.editor,
div#input textarea {
  color: white;
  line-height: 1.2em;
  min-height: 1.2em;
  max-height: 150px;
  display: block;
  padding: 3px 0;
  border: none;
  margin: 0;
  outline: 0 none;
  font-size: 12px;
  overflow: hidden;
  resize: none;
  font-family: "Lucida Grande", Helvetica, sans-serif;
  background: black; }

div#input textarea {
  width: 100%; }

div#input div.editor {
  margin-right: 75px;
  -khtml-nbsp-mode: space; }

div#input div.editor_toolbar {
  overflow: hidden;
  position: absolute;
  top: -3px;
  right: 0px;
  width: 70px;
  bottom: -3px;
  z-index: 902;
  background: #333333; }

div#input div.editor_toolbar button {
  display: block;
  float: left;
  color: white;
  line-height: 12px;
  font-size: 12px;
  margin: 0;
  padding: 4px 4px;
  text-align: center;
  background: none;
  cursor: pointer;
  border: none;
  color: #666666; }

div#input div.editor_toolbar button.colors:hover {
  background: none; }

div#input div.editor_toolbar button.colors {
  width: 14px;
  height: 14px;
  border: 2px solid white;
  margin: 4px;
  padding: 0; }

div#input div.editor_toolbar button.selected {
  color: white; }

.bold {
  font-weight: bold; }

.italic {
  font-style: italic; }

.underline {
  text-decoration: underline; }

div.editor div,
div.editor p,
div.editor h1,
div.editor h2,
div.editor h3,
div.editor h4,
div.editor h5,
div.editor span {
  font-size: 1em !important;
  margin: 0 !important;
  padding: 0 !important; }

div.editor img {
  display: none !important; }

div#input input.send {
  display: none; }

ul#tabs {
  list-style: none;
  margin: 0;
  padding: 0;
  padding-left: 1px;

share/static/alice-dark.css  view on Meta::CPAN

    padding-right: 0px !important;
    text-overflow: clip; }

  div.msg {
    margin-left: 54px !important; }

  div#input div {
    margin-right: 58px;
    background: none; }

  div#input div.editor_toolbar {
    display: none; }

  div#input div.editor {
    margin-right: 0; }

  div#input input.send {
    display: block;
    position: absolute;
    bottom: 0px;
    right: 2px;
    z-index: 904; }

  div.msg.monospace, div.msg.announce {

share/static/alice-default.css  view on Meta::CPAN

  padding: 0;
  height: auto;
  line-height: 0px; }

div#input div {
  padding: 0 3px;
  background: white;
  margin: 3px 0;
  position: relative; }

div#input div.editor,
div#input textarea {
  color: black;
  line-height: 1.2em;
  min-height: 1.2em;
  max-height: 150px;
  display: block;
  padding: 3px 0;
  border: none;
  margin: 0;
  outline: 0 none;
  font-size: 12px;
  overflow: hidden;
  resize: none;
  font-family: "Lucida Grande", Helvetica, sans-serif;
  background: white; }

div#input textarea {
  width: 100%; }

div#input div.editor {
  margin-right: 75px;
  -khtml-nbsp-mode: space; }

div#input div.editor_toolbar {
  overflow: hidden;
  position: absolute;
  top: -3px;
  right: 0px;
  width: 70px;
  bottom: -3px;
  z-index: 902;
  background: #efefef; }

div#input div.editor_toolbar button {
  display: block;
  float: left;
  color: #222222;
  line-height: 12px;
  font-size: 12px;
  margin: 0;
  padding: 4px 4px;
  text-align: center;
  background: none;
  cursor: pointer;
  border: none;
  color: #999999; }

div#input div.editor_toolbar button.colors:hover {
  background: none; }

div#input div.editor_toolbar button.colors {
  width: 14px;
  height: 14px;
  border: 2px solid black;
  margin: 4px;
  padding: 0; }

div#input div.editor_toolbar button.selected {
  color: black; }

.bold {
  font-weight: bold; }

.italic {
  font-style: italic; }

.underline {
  text-decoration: underline; }

div.editor div,
div.editor p,
div.editor h1,
div.editor h2,
div.editor h3,
div.editor h4,
div.editor h5,
div.editor span {
  font-size: 1em !important;
  margin: 0 !important;
  padding: 0 !important; }

div.editor img {
  display: none !important; }

div#input input.send {
  display: none; }

ul#tabs {
  list-style: none;
  margin: 0;
  padding: 0;
  padding-left: 1px;

share/static/alice-default.css  view on Meta::CPAN

    padding-right: 0px !important;
    text-overflow: clip; }

  div.msg {
    margin-left: 54px !important; }

  div#input div {
    margin-right: 58px;
    background: none; }

  div#input div.editor_toolbar {
    display: none; }

  div#input div.editor {
    margin-right: 0; }

  div#input input.send {
    display: block;
    position: absolute;
    bottom: 0px;
    right: 2px;
    z-index: 904; }

  div.msg.monospace, div.msg.announce {

share/static/alice-solarized.css  view on Meta::CPAN

  padding: 0;
  height: auto;
  line-height: 0px; }

div#input div {
  padding: 0 3px;
  background: #fdf6e3;
  margin: 3px 0;
  position: relative; }

div#input div.editor,
div#input textarea {
  color: #073642;
  line-height: 1.2em;
  min-height: 1.2em;
  max-height: 150px;
  display: block;
  padding: 3px 0;
  border: none;
  margin: 0;
  outline: 0 none;
  font-size: 12px;
  overflow: hidden;
  resize: none;
  font-family: "Lucida Grande", Helvetica, sans-serif;
  background: #fdf6e3; }

div#input textarea {
  width: 100%; }

div#input div.editor {
  margin-right: 75px;
  -khtml-nbsp-mode: space; }

div#input div.editor_toolbar {
  overflow: hidden;
  position: absolute;
  top: -3px;
  right: 0px;
  width: 70px;
  bottom: -3px;
  z-index: 902;
  background: #eee8d5; }

div#input div.editor_toolbar button {
  display: block;
  float: left;
  color: white;
  line-height: 12px;
  font-size: 12px;
  margin: 0;
  padding: 4px 4px;
  text-align: center;
  background: none;
  cursor: pointer;
  border: none;
  color: #93a1a1; }

div#input div.editor_toolbar button.colors:hover {
  background: none; }

div#input div.editor_toolbar button.colors {
  width: 14px;
  height: 14px;
  border: 2px solid #073642;
  margin: 4px;
  padding: 0; }

div#input div.editor_toolbar button.selected {
  color: #586e75; }

.bold {
  font-weight: bold; }

.italic {
  font-style: italic; }

.underline {
  text-decoration: underline; }

div.editor div,
div.editor p,
div.editor h1,
div.editor h2,
div.editor h3,
div.editor h4,
div.editor h5,
div.editor span {
  font-size: 1em !important;
  margin: 0 !important;
  padding: 0 !important; }

div.editor img {
  display: none !important; }

div#input input.send {
  display: none; }

ul#tabs {
  list-style: none;
  margin: 0;
  padding: 0;
  padding-left: 1px;

share/static/alice-solarized.css  view on Meta::CPAN

    padding-right: 0px !important;
    text-overflow: clip; }

  div.msg {
    margin-left: 54px !important; }

  div#input div {
    margin-right: 58px;
    background: none; }

  div#input div.editor_toolbar {
    display: none; }

  div#input div.editor {
    margin-right: 0; }

  div#input input.send {
    display: block;
    position: absolute;
    bottom: 0px;
    right: 2px;
    z-index: 904; }

  div.msg.monospace, div.msg.announce {

share/static/alice.js  view on Meta::CPAN

/*  WysiHat - WYSIWYG JavaScript framework, version 0.2.1
 *  (c) 2008-2010 Joshua Peek
 *
 *  WysiHat is freely distributable under the terms of an MIT-style license.
 *--------------------------------------------------------------------------*/


var WysiHat = {};
WysiHat.Editor = {
  attach: function(textarea) {
    var editArea;

    textarea = $(textarea);

    var id = textarea.id + '_editor';
    if (editArea = $(id)) return editArea;

    editArea = new Element('div', {
      'id': id,
      'class': 'editor',
      'contentEditable': 'true'
    });

    editArea.update(WysiHat.Formatting.getBrowserMarkupFrom(textarea.value));

    Object.extend(editArea, WysiHat.Commands);

    textarea.insert({before: editArea});
    textarea.hide();


    return editArea;
  }
};
WysiHat.BrowserFeatures = (function() {
  function createTmpIframe(callback) {
    var frame, frameDocument;

    frame = new Element('iframe');
    frame.setStyle({
      position: 'absolute',
      left: '-1000px'

share/static/alice.js  view on Meta::CPAN

      value = element.innerHTML;
    else if (element.getValue)
      value = element.getValue();

    if (value && element.previousValue != value) {
      element.fire("field:change");
      element.previousValue = value;
    }
  }

  $(document.body).on("keyup", 'input,textarea,*[contenteditable=""],*[contenteditable=true]', fieldChangeHandler);
});

WysiHat.Commands = (function(window) {
  function boldSelection() {
    this.execCommand('bold', false, null);
  }

  function boldSelected() {
    return this.queryCommandState('bold');
  }

share/static/alice.js  view on Meta::CPAN


    this.execCommand('insertorderedlist', false, null);
  }

  function insertOrderedList() {
    this.toggleOrderedList();
  }

  function orderedListSelected() {
    var element = window.getSelection().getNode();
    if (element) return element.match('*[contenteditable=""] ol, *[contenteditable=true] ol, *[contenteditable=""] ol *, *[contenteditable=true] ol *');
    return false;
  }

  function toggleUnorderedList() {
    var selection, node;

    selection = window.getSelection();
    node      = selection.getNode();

    if (this.unorderedListSelected() && !node.match("ul li:last-child, ul li:last-child *")) {

share/static/alice.js  view on Meta::CPAN


    this.execCommand('insertunorderedlist', false, null);
  }

  function insertUnorderedList() {
    this.toggleUnorderedList();
  }

  function unorderedListSelected() {
    var element = window.getSelection().getNode();
    if (element) return element.match('*[contenteditable=""] ul, *[contenteditable=true] ul, *[contenteditable=""] ul *, *[contenteditable=true] ul *');
    return false;
  }

  function insertImage(url) {
    this.execCommand('insertImage', false, url);
  }

  function insertHTML(html) {
    if (Prototype.Browser.IE) {
      var range = window.document.selection.createRange();

share/static/alice.js  view on Meta::CPAN

      return handler.bind(this)();
    } else {
      try {
        return window.document.queryCommandState(state);
      } catch(e) { return null; }
    }
  }

  function getSelectedStyles() {
    var styles = $H({});
    var editor = this;
    editor.styleSelectors.each(function(style){
      var node = editor.selection.getNode();
      styles.set(style.first(), Element.getStyle(node, style.last()));
    });
    return styles;
  }

  return {
     boldSelection:            boldSelection,
     boldSelected:             boldSelected,
     underlineSelection:       underlineSelection,
     underlineSelected:        underlineSelected,

share/static/alice.js  view on Meta::CPAN


      result = container = new Element("div");
      walk(element.childNodes);
      flush();
      return result.innerHTML;
    }
  };
})();

WysiHat.Toolbar = Class.create((function() {
  function initialize(editor) {
    this.editor = editor;
    this.element = this.createToolbarElement();
  }

  function createToolbarElement() {
    var toolbar = new Element('div', { 'class': 'editor_toolbar' });
    this.editor.insert({before: toolbar});
    return toolbar;
  }

  function addButtonSet(set) {
    $A(set).each(function(button){
      this.addButton(button);
    }.bind(this));
  }

  function addButton(options, handler) {

share/static/alice.js  view on Meta::CPAN


    return button;
  }

  function buttonHandler(name, options) {
    if (options.handler)
      return options.handler;
    else if (options.get('handler'))
      return options.get('handler');
    else
      return function(editor) { editor.execCommand(name); };
  }

  function observeButtonClick(element, handler) {
    element.on('click', function(event) {
      handler(this.editor);
      event.stop();
    }.bind(this));
  }

  function buttonStateHandler(name, options) {
    if (options.query)
      return options.query;
    else if (options.get('query'))
      return options.get('query');
    else
      return function(editor) { return editor.queryCommandState(name); };
  }

  function observeStateChanges(element, name, handler) {
    var previousState;
    this.editor.on("selection:change", function(event) {
      var state = handler(this.editor);
      if (state != previousState) {
        previousState = state;
        this.updateButtonState(element, name, state);
      }
    }.bind(this));
  }

  function updateButtonState(element, name, state) {
    if (state)
      element.addClassName('selected');

share/static/alice.js  view on Meta::CPAN

    button.addClassName(options.get('name'));
    toolbar.appendChild(button);

    return button;
  },
  observeButtonClick: function(element, handler) {
    element.on('click', function(e) {e.stop()});
    element.on('mouseup', function(event) {
      alice.input.focus();

      handler(this.editor, element, this);

      this.editor.fire("selection:change");

      event.stop();
    }.bind(this));
  },
});

Object.extend(Alice.Toolbar, {
  updateColors: function (editor) {
    var range = alice.input.range || editor;
    if (range) {
      var node = range.getNode();
      var fg = node.getStyle("color");
      var bg = node.getStyle("background-color");
      var button = alice.input.toolbar.element.down("button.colors");
      button.setStyle({"border-color": fg, "background-color": bg});
    }
    return 1;
  }
});

Alice.Toolbar.ButtonSet = [
  {
    label: "",
    name: "colors",
    query: Alice.Toolbar.updateColors,
    handler: function (editor, button, toolbar) {
      var cb = function (color, fg) {
        if (fg) {
          button.setStyle({"border-color": color})
          editor.colorSelection(color);
        } else {
          button.setStyle({"background-color": color});
          editor.backgroundColorSelection(color);
        }
      };
      if (toolbar.picker) {
        toolbar.picker.remove();
        toolbar.picker = undefined;
      } else {
        toolbar.picker = new Alice.Colorpicker(button, cb);
      }
    }
  },
  {
    label: "b",
    name: "bold",
    handler: function (editor, button, toolbar) {
      editor.boldSelection();
    }
  },
  {
    label: "i",
    name: "italic",
    handler: function (editor, button, toolbar) {
      editor.italicSelection();
    }
  },
  {
    label: "u",
    name: "underline",
    handler: function (editor, button, toolbar) {
      var elem = toolbar.element.down(".underline");
      if (elem.hasClassName("selected"))
       elem.removeClassName("selected");
      else
       elem.addClassName("selected");

      editor.underlineSelection();
    }
  }
];

Alice.Colorpicker = Class.create({
  initialize: function(button, callback) {
    var elem = new Element("div").addClassName("color_picker");

    var toggle = new Element("div").addClassName("toggle");
    var blank = new Element("span").addClassName("blank").addClassName("color");

share/static/alice.js  view on Meta::CPAN

  }
});
Alice.Input = Class.create({
  initialize: function(application, element) {

    this.application = application;
    this.textarea = $(element);
    this.disabled = false;

    if (this.canContentEditable()) {
      this.editor = WysiHat.Editor.attach(this.textarea);
      this.element = this.editor;
      this.toolbar = new Alice.Toolbar(this.element)
      this.toolbar.addButtonSet(Alice.Toolbar.ButtonSet);
      var input = new Element("input", {type: "hidden", name: "html", value: 1});
      this.textarea.form.appendChild(input);

      document.observe("mousedown", function(e) {
        if (!e.findElement(".editor")) this.uncancelNextFocus();
      }.bind(this));

      this.editor.observe("keydown", function(){this.cancelNextFocus()}.bind(this));
      this.editor.observe("keyup", this.updateRange.bind(this));
      this.editor.observe("mouseup", this.updateRange.bind(this));
      this.editor.observe("paste", this.pasteHandler.bind(this));

      this.toolbar.element.on("mouseup","button",function(){
        this.cancelNextFocus();
      }.bind(this));
    } else {
      this.element = this.textarea;
      this.element.observe("keydown", this.resize.bind(this));
      this.element.observe("cut", this.resize.bind(this));
      this.element.observe("paste", this.resize.bind(this));
      this.element.observe("change", this.resize.bind(this));

share/static/alice.js  view on Meta::CPAN

    this.completion = false;
    this.focused = false;

    if (!this.application.isMobile) this.focus();

    this.element.observe("blur", this.onBlur.bind(this));
  },

  setValue: function(value) {
    this.textarea.setValue(value);
    if (this.editor) {
      this.editor.update(value);
      var text = document.createElement("BR");
      this.editor.appendChild(text);
    }
  },

  getValue: function() {
    if (this.editor) {
      return this.editor.innerHTML;
    }
    return this.textarea.getValue();
  },

  onKeyPress: function(event) {
    if (event.keyCode != Event.KEY_TAB) {
      this.completion = false;
      this.element.stopObserving("keypress");
    }
  },

share/static/alice.js  view on Meta::CPAN

      if (this.focused) return;

      if (this.skipThisFocus) {
        this.skipThisFocus = false;
        return;
      }
    }

    this.focused = true;

    if (this.editor) {
      var selection = window.getSelection();
      selection.removeAllRanges();
      if (this.range) {
        selection.addRange(this.range);
      } else {
        var text = document.createTextNode("");
        this.editor.appendChild(text);
        selection.selectNode(text);
        this.range = selection.getRangeAt(0);
      }
      this.editor.focus();
    } else {
      this.textarea.focus();
    }
  },

  onBlur: function(e) {
    this.focused = false;
  },

  previousCommand: function() {

share/static/alice.js  view on Meta::CPAN

  },

  send: function() {
    var msg = this.getValue();

    if (msg.length > 1024*2) {
      alert("That message is way too long, dude.");
      return;
    }

    if (this.editor) this.textarea.value = msg;

    var success = this.application.connection.sendMessage(this.textarea.form);
    if (success) {
      this.history.push(msg);
      this.setValue("");
      if (this.editor) this.editor.update();
      this.index = -1;
      this.stash();
      this.update();
      this.focus(1);
    }
    else {
      alert("Could not send message, not connected!");
    }
  },

  completeNickname: function(prev) {
    if (this.disabled) return;
    if (!this.completion) {
      this.completion = new Alice.Completion(this.application.activeWindow().getNicknames(), this.editor);
      this.element.observe("keypress", this.onKeyPress.bind(this));
    }

    if (prev)
      this.completion.prev();
    else
      this.completion.next();
  },

  stopCompletion: function() {

share/static/alice.js  view on Meta::CPAN

      visibility: "hidden",
      left:       "-" + this.element.getWidth() + "px",
      width:      this.element.getWidth() - 7 + "px",
      fontFamily: this.element.getStyle("fontFamily"),
      fontSize:   this.element.getStyle("fontSize"),
      lineHeight: this.element.getStyle("lineHeight"),
      whiteSpace: "pre-wrap",
      wordWrap:   "break-word"
    });

    if (this.editor) element.addClassName("editor");

    var value = this.getValue();
    element.update(value.replace(/\n$/, "\n\n").replace("\n", "<br>"));
    $(document.body).insert(element);

    var height = element.getHeight();
    element.remove();
    return height;
  },

share/static/alice.js  view on Meta::CPAN

        var blob = items[i].getAsFile();
        if (blob && blob.type.match(/image/)) {
          e.stop();
          var fd = new FormData();
          fd.append("image", blob);
          fd.append("key", "f1f60f1650a07bfe5f402f35205dffd4");
          var xhr = new XMLHttpRequest();
          xhr.open("POST", "http://api.imgur.com/2/upload.json");
          xhr.onload = function() {
            var url = xhr.responseText.evalJSON();
            this.editor.insertHTML(url.upload.links.original);
            this.updateRange();
          }.bind(this);
          xhr.send(fd);
          return;
        }
      }
    }

    var text = e.clipboardData.getData("Text");
    if (text) {
      e.preventDefault();
      text = text.escapeHTML().replace(/\n+/g, "<br>\n");
      this.editor.insertHTML(text);
      this.updateRange();
      return;
    }

    var url = e.clipboardData.getData("URL");
    if (url) {
      e.preventDefault();
      this.editor.insertHTML(url);
      this.updateRange();
      return;
    }

  }
});
Alice.Keyboard = Class.create({
  initialize: function(application) {
    this.application = application;
    this.isMac = navigator.platform.match(/mac/i);

share/static/alice.js  view on Meta::CPAN


  onCmdK: function() {
    this.activeWindow.clearMessages();
    this.application.connection.sendMessage({
      msg: "/clear",
      source: this.activeWindow.id,
    });
  },

  onCmdB: function() {
    if (this.application.input.editor) {
      this.application.input.focus();
      this.application.input.editor.boldSelection();
    }
  },

  onCmdShiftU: function() {
    if (this.application.input.editor) {
      this.application.input.focus();
      this.application.input.editor.underlineSelection();
    }
  },

  onCmdI: function() {
    if (this.application.input.editor) {
      this.application.input.focus();
      this.application.input.editor.italicSelection();
    }
  },

  onCmdU: function() {
    this.application.nextUnreadWindow();
  },

  onCmdShiftM: function() {
    this.application.windows().invoke('markRead');
  },

share/static/alice.js  view on Meta::CPAN


  enable: function() {
    this.enabled = true;
  },

  disable: function() {
    this.enabled = false;
  }
});
Alice.Completion = Class.create({
  initialize: function(candidates, editor) {
    var range = this.getRange();
    if (!range) return;

    this.element = range.startContainer;
    this.editor = editor;
    if (this.element == this.editor) {
      this.addTextNode();
    }

    this.value = this.element.data || "";
    this.index = range.startOffset;

    this.findStem();
    this.matches = this.matchAgainst(candidates);
    this.matchIndex = -1;
  },

  addTextNode: function() {

    this.editor.innerHTML = "";
    var node = document.createTextNode("");
    this.editor.appendChild(node);
    var selection = window.getSelection();
    selection.removeAllRanges();
    selection.selectNode(node);
    range = selection.getRangeAt(0);
    this.element = node;
  },

  getRange: function() {
    var selection = window.getSelection();
    if (selection.rangeCount > 0) {



( run in 0.774 second using v1.01-cache-2.11-cpan-de7293f3b23 )