First commit; requires latest Enano from Hg. It works!
authorDan
Sun, 11 Jan 2009 21:38:42 -0500
changeset 0 db23957ad1c7
child 1 f7b24c744747
First commit; requires latest Enano from Hg. It works!
plugins/AjIM2.0.php
plugins/ajim/client.php
plugins/ajim/enanosetup.php
plugins/ajim/language.json
plugins/ajim/server.php
plugins/ajim/shoutbox.css
plugins/ajim/shoutbox.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/AjIM2.0.php	Sun Jan 11 21:38:42 2009 -0500
@@ -0,0 +1,54 @@
+<?php
+/**!info**
+{
+  "Plugin Name"  : "AjIM 2.0",
+  "Plugin URI"   : "http://enanocms.org/plugin/ajim2",
+  "Description"  : "An AJAX shoutbox and more - re-implemented for Enano 1.2",
+  "Author"       : "Dan Fuhry",
+  "Version"      : "1.9.1",
+  "Author URI"   : "http://enanocms.org/"
+}
+**!*/
+
+/**!install dbms="mysql"; **
+CREATE TABLE {{TABLE_PREFIX}}ajim2 (
+  message_id int unsigned NOT NULL auto_increment,
+  user_id mediumint NOT NULL DEFAULT 1,
+  username varchar(20) NOT NULL DEFAULT 'Guest',
+  website varchar(128) NOT NULL DEFAULT '',
+  message text NOT NULL DEFAULT '',
+  message_time int unsigned NOT NULL DEFAULT 0,
+  message_update_time int unsigned NOT NULL DEFAULT 0,
+  PRIMARY KEY ( message_id )
+);
+**!*/
+
+/**!install dbms="postgresql"; **
+CREATE TABLE {{TABLE_PREFIX}}ajim2 (
+  message_id SERIAL,
+  user_id int NOT NULL DEFAULT 1,
+  username varchar(20) NOT NULL DEFAULT 'Guest',
+  website varchar(128) NOT NULL DEFAULT '',
+  message text NOT NULL DEFAULT '',
+  message_time int NOT NULL DEFAULT 0,
+  message_update_time int NOT NULL DEFAULT 0,
+  PRIMARY KEY ( message_id )
+);
+**!*/
+
+/**!uninstall dbms="mysql"; **
+DROP TABLE IF EXISTS {{TABLE_PREFIX}}ajim2;
+**!*/
+
+/**!uninstall dbms="postgresql"; **
+DROP TABLE {{TABLE_PREFIX}}ajim2;
+**!*/
+
+/**!language**
+!include "plugins/ajim/language.json"
+**!*/
+
+require(ENANO_ROOT . '/plugins/ajim/enanosetup.php');
+require(ENANO_ROOT . '/plugins/ajim/server.php');
+require(ENANO_ROOT . '/plugins/ajim/client.php');
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/ajim/client.php	Sun Jan 11 21:38:42 2009 -0500
@@ -0,0 +1,84 @@
+<?php
+
+$plugins->attachHook('compile_template', 'ajim_compile_sidebar();');
+
+function ajim_compile_sidebar()
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  global $lang;
+  
+  $template->add_header('<link rel="stylesheet" type="text/css" href="' . scriptPath . '/plugins/ajim/shoutbox.css" />');
+  $template->add_header('<script type="text/javascript" src="' . scriptPath . '/plugins/ajim/shoutbox.js"></script>');
+  $can_mod = $session->get_permissions('ajim_mod') ? 'true' : 'false';
+  $template->add_header('<script type="text/javascript">
+      var ajim_can_mod = ' . $can_mod . ';
+      var ajim_str_edit = "' . addslashes($lang->get('ajim_btn_edit')) . '";
+      var ajim_str_delete = "' . addslashes($lang->get('ajim_btn_delete')) . '";
+      var ajim_str_no_posts = "' . addslashes($lang->get('ajim_msg_no_posts')) . '";
+      var ajim_user_id = ' . $session->user_id . ';
+    </script>');
+  
+  $msg_loading = $lang->get('ajim_msg_loading');
+  $html = '<div class="ajim_wrapper">';
+  $html .= <<<__EOF
+    <div id="ajim_messages" class="ajim_messages">
+      <div id="ajim_error">
+      </div>
+      <span class="ajim_noposts" id="ajim_noposts">
+        $msg_loading
+      </span>
+    </div>
+    <div class="ajim_form">
+__EOF;
+  if ( $session->get_permissions('ajim_post') )
+  {
+    if ( $session->user_logged_in )
+    {
+      $html .= '<input type="hidden" id="ajim_nickname" value="' . htmlspecialchars($session->username) . '" />';
+    }
+    else
+    {
+      $l_name = $lang->get('ajim_lbl_name');
+      $l_site = $lang->get('ajim_lbl_website');
+      $html .= <<<______EOF
+        <table border="0" cellspacing="3">
+          <tr>
+            <td>
+              $l_name
+            </td>
+            <td>
+              <input type="text" class="ajim_field" id="ajim_nickname" value="Guest" />
+            </td>
+          </tr>
+        </table>
+______EOF;
+    }
+    $b_submit = $lang->get('ajim_btn_submit');
+    $html .= '<textarea id="ajim_message" rows="2" cols="20"></textarea>';
+    $html .= <<<____EOF
+      <div class="ajim_submit_wrap">
+        <input type="submit" id="ajim_submit" value="{$b_submit}" onclick="ajim_submit_message();" />
+      </div>
+____EOF;
+    if ( $session->get_permissions('ajim_mod') )
+    {
+      $html .= '<div id="ajim_mod">';
+      if ( $session->auth_level < USER_LEVEL_CHPREF )
+      {
+        $html .= '<a href="#" class="ajim_modlink" onclick="ajim_handle_click_mod(); return false;">' . $lang->get('ajim_btn_mod') . '</a>';
+      }
+      $html .= '</div>';
+    }
+  }
+  else
+  {
+    $msg_nopost = $lang->get('ajim_msg_no_post');
+    $html .= <<<____EOF
+      $msg_nopost
+____EOF;
+  }
+  
+  $html .= '  </div>
+            </div>';
+  $template->sidebar_widget('AjIM Shoutbox', $html);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/ajim/enanosetup.php	Sun Jan 11 21:38:42 2009 -0500
@@ -0,0 +1,10 @@
+<?php
+
+$plugins->attachHook('acl_rule_init', 'ajim_permissions_setup($session, $this);');
+
+function ajim_permissions_setup(&$session, &$paths)
+{
+  $session->register_acl_type('ajim_post', AUTH_ALLOW,    'ajim_perm_post', Array(),            'All');
+  $session->register_acl_type('ajim_edit', AUTH_ALLOW,    'ajim_perm_edit', Array(),            'All');
+  $session->register_acl_type('ajim_mod',  AUTH_DISALLOW, 'ajim_perm_mod',  Array('ajim_post'), 'All');
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/ajim/language.json	Sun Jan 11 21:38:42 2009 -0500
@@ -0,0 +1,33 @@
+{
+  // english
+  eng: {
+    categories: [ 'meta', 'ajim' ],
+    strings: {
+      meta: {
+        ajim: 'AjIM plugin'
+      },
+      ajim: {
+        msg_loading: 'Loading...',
+        lbl_name: 'Name:',
+        lbl_website: 'URL:',
+        btn_submit: 'Post',
+        msg_no_post: 'Posting is disabled.',
+        btn_edit: 'edit',
+        btn_delete: 'delete',
+        btn_save: 'save',
+        msg_no_posts: 'No posts.',
+        btn_mod: 'Moderation',
+        
+        err_generic_title: 'Shoutbox error',
+        err_bad_json: 'Invalid JSON response from server:',
+        err_post_denied: 'Access denied. Your post was not submitted.',
+        err_access_denied: 'You\'re not allowed to do that.',
+        err_no_post: 'Please enter a post.',
+        
+        perm_post: 'Post AjIM messages',
+        perm_edit: 'Edit own AjIM messages',
+        perm_mod: 'Moderate AjIM messages'
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/ajim/server.php	Sun Jan 11 21:38:42 2009 -0500
@@ -0,0 +1,264 @@
+<?php
+
+$plugins->attachHook('session_started', 'ajim_page_init();');
+
+function ajim_page_init()
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  
+  $paths->add_page(array(
+      'name' => 'AjIM JSON handler',
+      'urlname' => 'AjimJson',
+      'namespace' => 'Special',
+      'visible' => 0,
+      'special' => 1,
+      'comments_on' => 0,
+      'protected' => 0
+    ));
+}
+
+function page_Special_AjimJson()
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  global $lang;
+  
+  header('Content-type: text/javascript');
+  if ( !isset($_GET['r']) && !isset($_POST['r']) )
+  {
+    return print enano_json_encode(array(
+        'mode' => 'error',
+        'error' => 'No request specified.'
+      ));
+  }
+  $request = enano_json_decode($_REQUEST['r']);
+  if ( !isset($request['mode']) )
+  {
+    return print enano_json_encode(array(
+        'mode' => 'error',
+        'error' => 'No mode specified.'
+      ));
+  }
+  switch($request['mode'])
+  {
+    case 'watch':
+      @set_time_limit(0);
+      $time = ( !empty($request['lastrefresh']) ) ? intval($request['lastrefresh']) : 0;
+      $end = microtime_float() + 59;
+      // run cron-ish stuff
+      if ( intval(getConfig('ajim_last_cleanout', 0)) + 86400 < time() )
+      {
+        $q = $db->sql_query('SELECT COUNT(message_id) FROM ' . table_prefix . "ajim2;");
+        if ( !$q )
+          $db->die_json();
+        
+        list($count) = $db->fetchrow_num();
+        $db->free_result();
+        if ( intval($count) > 50 )
+        {
+          // if there are more than 50 messages in the database, clean it out
+          $limit = $count - 15;
+          $q = $db->sql_query('DELETE FROM ' . table_prefix . "ajim2 ORDER BY message_time ASC LIMIT $limit;");
+          if ( !$q )
+            $db->die_json();
+        }
+        
+        setConfig('ajim_last_cleanout', time());
+      }
+      
+      while ( microtime_float() < $end )
+      {
+        $q = $db->sql_query('SELECT * FROM ' . table_prefix . "ajim2 WHERE message_time >= $time OR message_update_time >= $time ORDER BY message_time DESC LIMIT 30;");
+        if ( !$q )
+          $db->die_json();
+        if ( $db->numrows() > 0 || $time == 0 )
+          break;
+        $db->free_result();
+        usleep(500000); // 0.5s
+      }
+      if ( $q )
+      {
+        $messages = array();
+        while ( $row = $db->fetchrow() )
+        {
+          $row['rank_info'] = $session->get_user_rank($row['user_id']);
+          $row['message_html'] = RenderMan::render($row['message']);
+          $row['human_time'] = enano_date('n/j, g:ia', $row['message_time']);
+          $messages[] = $row;
+        }
+        $response = array(
+          'mode' => 'messages',
+          'now' => time(),
+          'messages' => $messages
+        );
+        return print enano_json_encode($response);
+      }
+      else
+      {
+        return print enano_json_encode(array(
+            'mode' => 'messages',
+            'now' => time(),
+            'messages' => array()
+          ));
+      }
+      break;
+    case 'submit':
+      if ( !$session->get_permissions('ajim_post') )
+      {
+        return print enano_json_encode(array(
+            'mode' => 'error',
+            'error' => $lang->get('ajim_err_post_denied')
+          ));
+      }
+      $name = $session->user_logged_in ? $session->username : $request['user'];
+      $content = trim($request['message']);
+      if ( empty($content) )
+      {
+        return print enano_json_encode(array(
+            'mode' => 'error',
+            'error' => $lang->get('ajim_err_no_post')
+          ));
+      }
+      
+      $now = time();
+      $content_db = $db->escape($content);
+      $name_db = $db->escape($name);
+      
+      $sql = 'INSERT INTO ' . table_prefix . "ajim2(user_id, username, message, message_time, message_update_time) VALUES\n"
+                        . "  ({$session->user_id}, '$name_db', '$content_db', $now, $now);";
+      if ( !$db->sql_query($sql) )
+        $db->die_json();
+      
+      // workaround for no insert_id() on postgresql
+      $q = $db->sql_query('SELECT message_id FROM ' . table_prefix . "ajim2 WHERE username = '$name_db' AND message = '$content_db' AND message_time = $now ORDER BY message_id DESC LIMIT 1;");
+      if ( !$q )
+        $db->die_json();
+      
+      list($message_id) = $db->fetchrow_num();
+      $db->free_result();
+      
+      return print enano_json_encode(array(
+          'mode' => 'messages',
+          'messages' => array(array(
+            'rank_info' => $session->get_user_rank($session->user_id),
+            'human_time' => enano_date('n/j, g:ia'),
+            'message' => $content,
+            'username' => $name,
+            'user_id' => $session->user_id,
+            'message_time' => time(),
+            'message_update_time' => time(),
+            'message_id' => $message_id,
+            'message_html' => RenderMan::render($content)
+            ))
+        ));
+      break;
+    case 'delete':
+      if ( empty($request['message_id']) )
+      {
+        return print enano_json_encode(array(
+            'mode' => 'error',
+            'error' => 'No message_id specified.'
+          ));
+      }
+      
+      $message_id = intval($request['message_id']);
+      
+      if ( ( !$session->get_permissions('ajim_mod') || $session->auth_level < USER_LEVEL_CHPREF ) )
+      {
+        // we don't have permission according to ACLs, but try to see if we can edit our
+        // own posts. if so, we can allow this to continue.
+        $perm_override = false;
+        if ( $session->get_permissions('ajim_edit') && $session->user_logged_in )
+        {
+          $q = $db->sql_query('SELECT user_id FROM ' . table_prefix . "ajim2 WHERE message_id = $message_id;");
+          if ( !$q )
+            $db->die_json();
+          
+          list($user_id) = $db->fetchrow_num();
+          $db->free_result();
+          if ( $user_id === $session->user_id )
+          {
+            $perm_override = true;
+          }
+        }
+        if ( !$perm_override )
+        {
+          return print enano_json_encode(array(
+              'mode' => 'error',
+              'error' => $lang->get('ajim_err_access_denied')
+            ));
+        }
+      }
+      
+      $now = time();
+      $q = $db->sql_query('UPDATE ' . table_prefix . "ajim2 SET message = '', message_update_time = $now WHERE message_id = $message_id;");
+      if ( !$q )
+        $db->die_json();
+      
+      return print enano_json_encode(array(
+          'mode' => 'delete',
+          'message_id' => $message_id
+        ));
+      break;
+    case 'update':
+      if ( empty($request['message_id']) )
+      {
+        return print enano_json_encode(array(
+            'mode' => 'error',
+            'error' => 'No message_id specified.'
+          ));
+      }
+      
+      $message_id = intval($request['message_id']);
+      
+      if ( ( !$session->get_permissions('ajim_mod') || $session->auth_level < USER_LEVEL_CHPREF ) )
+      {
+        // we don't have permission according to ACLs, but try to see if we can edit our
+        // own posts. if so, we can allow this to continue.
+        $perm_override = false;
+        if ( $session->get_permissions('ajim_edit') && $session->user_logged_in )
+        {
+          $q = $db->sql_query('SELECT user_id FROM ' . table_prefix . "ajim2 WHERE message_id = $message_id;");
+          if ( !$q )
+            $db->die_json();
+          
+          list($user_id) = $db->fetchrow_num();
+          $db->free_result();
+          if ( $user_id === $session->user_id )
+          {
+            $perm_override = true;
+          }
+        }
+        if ( !$perm_override )
+        {
+          return print enano_json_encode(array(
+              'mode' => 'error',
+              'error' => $lang->get('ajim_err_access_denied')
+            ));
+        }
+      }
+      
+      $message = trim(@$request['message']);
+      if ( empty($message) )
+      {
+        return print enano_json_encode(array(
+            'mode' => 'error',
+            'error' => $lang->get('ajim_err_no_post')
+          ));
+      }
+      
+      $message_db = $db->escape($message);
+      $now = time();
+      $q = $db->sql_query('UPDATE ' . table_prefix . "ajim2 SET message = '{$message_db}', message_update_time = $now WHERE message_id = $message_id;");
+      if ( !$q )
+        $db->die_json();
+      
+      return print enano_json_encode(array(
+          'mode' => 'update',
+          'message_id' => $message_id,
+          'message' => $message,
+          'message_html' => RenderMan::render($message)
+        ));
+      break;
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/ajim/shoutbox.css	Sun Jan 11 21:38:42 2009 -0500
@@ -0,0 +1,88 @@
+div.ajim_wrapper {
+  padding: 2px;
+  color: #000;
+}
+
+div.ajim_wrapper > div {
+  border-color: #000;
+  border-style: solid;
+  font-family: arial, helvetica, sans-serif;
+  font-size: 75%;
+  padding: 3px;
+}
+
+div.ajim_messages {
+  border-width: 1px 1px 0 1px;
+  background-color: #fff;
+  height: 200px;
+  clip: rect(0px, auto, auto, 0px);
+  overflow: auto;
+}
+
+div.ajim_form {
+  border-width: 0 1px 1px 1px;
+}
+
+div.ajim_form input.ajim_field {
+  font-size: 100%;
+  width: 80%;
+}
+
+div.ajim_form textarea {
+  width: 93%;
+  font-size: 100%;
+}
+
+div.ajim_submit_wrap {
+  padding-top: 2px;
+  text-align: center;
+}
+
+div.ajim_submit_wrap input {
+  font-size: 100%;
+}
+
+span.ajim_noposts {
+  color: #a0a0a0;
+}
+
+div#ajim_error {
+  background-color: #ffd0d0;
+  color: #500000;
+}
+
+div.ajim_modbuttons {
+  float: right;
+}
+
+div.ajim_modbuttons a.ajim_btn_edit {
+  color: #30aa00;
+}
+
+div.ajim_modbuttons a.ajim_btn_delete {
+  color: #aa3000;
+}
+
+div.ajim_messagehead {
+  clear: both;
+  border-bottom: 1px solid #c8c8c8;
+  margin: 3px 0;
+}
+
+div.ajim_timestamp {
+  color: #aaaaaa;
+  font-style: italic;
+}
+
+div.ajim_message_inner p {
+  margin: 2px 0;
+}
+
+div#ajim_mod {
+  text-align: center;
+}
+
+a.ajim_modlink {
+  color: blue;
+  font-size: 87.5%;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/ajim/shoutbox.js	Sun Jan 11 21:38:42 2009 -0500
@@ -0,0 +1,402 @@
+var ajim_last_refresh = 0;
+
+window.ajim_init = function()
+{
+  window.ajim_authed = ( auth_level >= USER_LEVEL_CHPREF && ajim_can_mod );
+  // have it immediately pull in whatever comments the server wants us to pull
+  ajim_watch(true);
+  ajim_setup_textarea();
+}
+
+addOnloadHook(ajim_init);
+
+window.ajim_watch = function(immediate)
+{
+  ajim_send_request({
+      mode: 'watch',
+      lastrefresh: immediate ? 0 : ajim_last_refresh
+  });
+}
+
+window.ajim_send_request = function(request)
+{
+  request = ajaxEscape(toJSONString(request));
+  ajaxPost(makeUrlNS('Special', 'AjimJson'), 'r=' + request, function()
+    {
+      if ( ajax.readyState == 4 && ajax.status == 200 )
+      {
+        var response = String(ajax.responseText + '');
+        if ( !check_json_response(response) )
+        {
+          ajim_handle_invalid_json(response);
+          return false;
+        }
+        response = parseJSON(response);
+        ajim_handle_response(response);
+      }
+    });
+}
+
+window.ajim_handle_invalid_json = function(response)
+{
+  ajim_fail_message_list();
+  load_component('l10n');
+  var messages = document.getElementById('ajim_messages');
+  messages.innerHTML = $lang.get('ajim_err_bad_json') + '<br />';
+  messages.appendChild(document.createTextNode(response));
+}
+
+window.ajim_handle_response = function(response)
+{
+  switch(response.mode)
+  {
+    case 'messages':
+      ajim_show_message_list();
+      
+      var noposts = document.getElementById('ajim_noposts');
+      if ( noposts )
+        noposts.parentNode.removeChild(noposts);
+      for ( var i = response.messages.length - 1; i >= 0; i-- )
+      {
+        ajim_inject_message(response.messages[i]);
+      }
+      if ( response.now )
+      {
+        window.ajim_last_refresh = response.now;
+        ajim_watch();
+      }
+      break;
+    case 'delete':
+      var message = document.getElementById('ajim_message:' + response.message_id);
+      if ( message )
+      {
+        message.parentNode.removeChild(message);
+      }
+      ajim_show_message_list();
+      break;
+    case 'update':
+      var message = document.getElementById('ajim_message:' + response.message_id);
+      if ( message )
+      {
+        var inner = getElementsByClassName(message, 'div', 'ajim_message_inner')[0];
+        inner.innerHTML = response.message_html;
+        message.meta.message_src = response.message;
+      }
+      ajim_show_message_list();
+      break;
+    case 'error':
+      ajim_fail_message_list();
+      ajim_show_error(response.error);
+      break;
+  }
+}
+
+window.ajim_draw_message = function(message)
+{
+  var div = document.createElement('div');
+  div.id = 'ajim_message:' + message.message_id;
+  div.className = 'ajim_message';
+  div.meta = {
+    message_id: message.message_id,
+    message_src: message.message
+  };
+  
+  // deleted message?
+  if ( message.message == '' )
+    return div;
+  
+  // *sigh* actually draw a message.
+  
+  // mod buttons
+    var modbuttons = document.createElement('div');
+    modbuttons.className = 'ajim_modbuttons';
+    if ( !window.ajim_authed && ( ( message.user_id != 1 && message.user_id != ajim_user_id ) || message.user_id == 1 ) )
+      modbuttons.style.display = 'none';
+    
+    var edbtn = document.createElement('a');
+    edbtn.href = '#';
+    edbtn.className = 'ajim_btn_edit';
+    edbtn.appendChild(document.createTextNode(ajim_str_edit));
+    edbtn.onclick = ajim_handle_click_edit;
+    modbuttons.appendChild(edbtn);
+    
+    modbuttons.appendChild(document.createTextNode(' | '));
+    
+    var delbtn = document.createElement('a');
+    delbtn.href = '#';
+    delbtn.className = 'ajim_btn_delete';
+    delbtn.appendChild(document.createTextNode(ajim_str_delete));
+    delbtn.onclick = ajim_handle_click_delete;
+    modbuttons.appendChild(delbtn);
+    
+    div.appendChild(modbuttons);
+    
+  // username
+    var el = message.user_id == 1 ? 'span' : 'a';
+    var username = document.createElement(el);
+    username.appendChild(document.createTextNode(message.username));
+    username.title = message.rank_info.rank_title;
+    username.setAttribute('style', message.rank_info.rank_style);
+    if ( message.user_id != 1 )
+      username.href = makeUrlNS('User', message.username);
+    div.appendChild(username);
+    
+  // message header (does a clear: both)
+    var messagehead = document.createElement('div');
+    messagehead.className = 'ajim_messagehead';
+    div.appendChild(messagehead);
+    
+  // date
+    var date = document.createElement('div');
+    date.className = 'ajim_timestamp';
+    date.appendChild(document.createTextNode(message.human_time));
+    div.appendChild(date);
+    
+  // *finally* message
+    var msgdata = document.createElement('div');
+    msgdata.innerHTML = message.message_html;
+    msgdata.className = 'ajim_message_inner';
+    div.appendChild(msgdata);
+  
+  // message footer
+    var messagefoot = document.createElement('div');
+    messagefoot.className = 'ajim_messagefoot';
+    div.appendChild(messagefoot);
+  
+  return div;
+}
+
+window.ajim_inject_message = function(message)
+{
+  var drawn = ajim_draw_message(message);
+  var existing = document.getElementById('ajim_message:' + message.message_id);
+  if ( existing )
+  {
+    insertAfter(existing.parentNode, drawn, existing);
+    existing.parentNode.removeChild(existing);
+  }
+  else
+  {
+    ajim_inject_object(drawn);
+  }
+}
+
+window.ajim_inject_object = function(element)
+{
+  var error = document.getElementById('ajim_error');
+  insertAfter(error.parentNode, element, error);
+}
+
+window.ajim_show_error = function(message)
+{
+  if ( window.ajim_error_timeout )
+    window.clearTimeout(ajim_error_timeout);
+  var error = document.getElementById('ajim_error');
+  error.innerHTML = '';
+  error.appendChild(document.createTextNode(message));
+  window.ajim_error_timeout = window.setTimeout(ajim_clear_error, 5000);
+}
+
+window.ajim_clear_error = function()
+{
+  var error = document.getElementById('ajim_error');
+  error.innerHTML = '';
+}
+
+window.ajim_handle_click_edit = function()
+{
+  if ( this.editing )
+  {
+    this.editing = false;
+    
+    this.firstChild.nodeValue = $lang.get('ajim_btn_edit');
+    this.nextSibling.nextSibling.firstChild.nodeValue = $lang.get('ajim_btn_delete');
+    
+    var newsrc = this.ta.value;
+    this.ta.parentNode.removeChild(this.ta);
+    this.inner.style.display = 'block';
+    
+    if ( newsrc == '' )
+      ajim_show_error($lang.get('ajim_err_no_post'));
+    
+    ajim_hide_message_list();
+    
+    ajim_send_request({
+        mode: 'update',
+        message_id: this.parentNode.parentNode.meta.message_id,
+        message: newsrc
+      });
+  }
+  else
+  {
+    load_component('l10n');
+    this.firstChild.nodeValue = $lang.get('ajim_btn_save');
+    this.nextSibling.nextSibling.firstChild.nodeValue = $lang.get('etc_cancel').toLowerCase();
+    this.editing = true;
+    
+    var src = this.parentNode.parentNode.meta.message_src;
+    var inner = this.parentNode.nextSibling.nextSibling.nextSibling.nextSibling;
+    
+    var ta = document.createElement('textarea');
+    ta.value = src;
+    ta.style.fontSize = '100%';
+    ta.style.width = '93%';
+    inner.style.display = 'none';
+    this.parentNode.parentNode.appendChild(ta);
+    this.ta = ta;
+    this.inner = inner;
+  }
+  return false;
+}
+
+window.ajim_handle_click_delete = function()
+{
+  var editlink = this.previousSibling.previousSibling;
+  if ( editlink.editing )
+  {
+    editlink.editing = false;
+    
+    editlink.firstChild.nodeValue = $lang.get('ajim_btn_edit');
+    this.firstChild.nodeValue = $lang.get('ajim_btn_delete');
+    
+    editlink.ta.parentNode.removeChild(editlink.ta);
+    editlink.inner.style.display = 'block';
+  }
+  else
+  {
+    ajim_hide_message_list();
+    var message_id = this.parentNode.parentNode.meta.message_id;
+    ajim_send_request({
+        mode: 'delete',
+        message_id: message_id
+      });
+  }
+  return false;
+}
+
+window.ajim_handle_click_mod = function()
+{
+  if ( auth_level >= USER_LEVEL_CHPREF )
+    return false;
+  load_component('login');
+  
+  ajaxLogonInit(function(k)
+    {
+      ajaxLoginReplaceSIDInline(k, false, USER_LEVEL_CHPREF);
+      window.setTimeout(function()
+        {
+          mb_current_obj.destroy();
+          ajim_enable_mod_tools();
+        }, 500);
+    }, USER_LEVEL_CHPREF);
+  
+  return false;
+}
+
+window.ajim_enable_mod_tools = function()
+{
+  var mods = document.getElementsByClassName('div', 'ajim_modbuttons');
+  for ( var i = 0; i < mods.length; i++ )
+  {
+    mods[i].style.display = 'block';
+  }
+  document.getElementById('ajim_mod').innerHTML = '';
+}
+
+window.ajim_setup_textarea = function()
+{
+  var ta = document.getElementById('ajim_message');
+  if ( !ta )
+    return false;
+  
+  ta.shift = false;
+  ta.onkeypress = function(e)
+  {
+    if ( !e )
+      e = window.event;
+    if ( !e )
+      return true;
+    if ( typeof(e.keyCode) == undefined )
+      return true;
+    if ( e.keyCode == 13 )
+    {
+      if ( !this.shift )
+      {
+        ajim_submit_message();
+        e.preventDefault();
+        return false;
+      }
+    }
+  }
+  ta.onkeydown = function(e)
+  {
+    if ( !e )
+      e = window.event;
+    if ( !e )
+      return true;
+    if ( !e.keyCode )
+      return true;
+    if ( e.keyCode == 16 )
+    {
+      this.shift = true;
+    }
+  }
+  ta.onkeyup = function(e)
+  {
+    if ( !e )
+      e = window.event;
+    if ( !e )
+      return true;
+    if ( !e.keyCode )
+      return true;
+    if ( e.keyCode == 16 )
+    {
+      this.shift = false;
+    }
+  }
+}
+
+window.ajim_submit_message = function()
+{
+  var ta = document.getElementById('ajim_message');
+  if ( ta.value == '' )
+  {
+    load_component('l10n');
+    ajim_show_error($lang.get('ajim_err_no_post'));
+    return false;
+  }
+  
+  var user = document.getElementById('ajim_nickname');
+  if ( user.value == '' )
+    user.value = 'Guest';
+  
+  ajim_hide_message_list();
+  
+  ajim_send_request({
+      mode: 'submit',
+      user: user.value,
+      message: ta.value
+    });
+  
+  ta.value = '';
+}
+
+window.ajim_hide_message_list = function()
+{
+  var messages = document.getElementById('ajim_messages');
+  window.ajim_submit_whitey = whiteOutElement(messages);
+}
+
+window.ajim_show_message_list = function()
+{
+  if ( window.ajim_submit_whitey )
+    whiteOutReportSuccess(window.ajim_submit_whitey);
+  window.ajim_submit_whitey = false;
+}
+
+window.ajim_fail_message_list = function()
+{
+  if ( window.ajim_submit_whitey )
+    whiteOutReportFailure(window.ajim_submit_whitey);
+  window.ajim_submit_whitey = false;
+}