AJAX comments are now paginated; plugin manager can now show system plugins; typo in installer corrected; links in oxygen/stpatty/admin footers changed to "About Enano" page; 1.0.1 release candidate
authorDan
Thu, 09 Aug 2007 12:26:16 -0400
changeset 85 7c68a18a27be
parent 84 f99fb84bd959
child 86 c162ca39db8f
AJAX comments are now paginated; plugin manager can now show system plugins; typo in installer corrected; links in oxygen/stpatty/admin footers changed to "About Enano" page; 1.0.1 release candidate
includes/clientside/static/comments.js
includes/clientside/static/enano-lib-basic.js
includes/clientside/static/misc.js
includes/clientside/static/paginate.js
includes/render.php
includes/template.php
install.php
plugins/PrivateMessages.php
plugins/SpecialAdmin.php
plugins/SpecialCSS.php
plugins/SpecialGroups.php
plugins/SpecialPageFuncs.php
plugins/SpecialSearch.php
plugins/SpecialUpdownload.php
plugins/SpecialUserFuncs.php
plugins/SpecialUserPrefs.php
themes/admin/footer.tpl
themes/oxygen/footer.tpl
themes/stpatty/footer.tpl
--- a/includes/clientside/static/comments.js	Mon Aug 06 10:37:42 2007 -0400
+++ b/includes/clientside/static/comments.js	Thu Aug 09 12:26:16 2007 -0400
@@ -1,8 +1,10 @@
 // Comments
 
 var comment_template = false;
+var comment_render_track = 0;
 
-function ajaxComments(parms) {
+function ajaxComments(parms)
+{
   setAjaxLoading();
   var pid = strToPageID(title);
   if(!parms)
@@ -106,64 +108,9 @@
   
   if ( data.count_total > 0 )
   {
-    var parser = new templateParser(comment_template);
-    for ( var i = 0; i < data.comments.length; i++ )
-    {
-      var tplvars = new Object();
-      
-      if ( data.comments[i].approved != '1' && !data.auth_mod_comments )
-        continue;
-      
-      tplvars.ID = i;
-      tplvars.DATETIME = data.comments[i].time;
-      tplvars.SUBJECT = data.comments[i].subject;
-      tplvars.DATA = data.comments[i].comment_data;
-      tplvars.SIGNATURE = data.comments[i].signature;
-      
-      if ( data.comments[i].approved != '1' )
-        tplvars.SUBJECT += ' <span style="color: #D84308">(Unapproved)</span>';
-      
-      // Name
-      tplvars.NAME = data.comments[i].name;
-      if ( data.comments[i].user_id > 1 )
-        tplvars.NAME = '<a href="' + makeUrlNS('User', data.comments[i].name) + '">' + data.comments[i].name + '</a>';
-      
-      // User level
-      tplvars.USER_LEVEL = 'Guest';
-      if ( data.comments[i].user_level >= data.user_level.member ) tplvars.USER_LEVEL = 'Member';
-      if ( data.comments[i].user_level >= data.user_level.mod ) tplvars.USER_LEVEL = 'Moderator';
-      if ( data.comments[i].user_level >= data.user_level.admin ) tplvars.USER_LEVEL = 'Administrator';
-      
-      // Send PM link
-      tplvars.SEND_PM_LINK=(data.comments[i].user_id>1)?'<a onclick="window.open(this.href); return false;" href="'+ makeUrlNS('Special', 'PrivateMessages/Compose/To/' + ( data.comments[i].name.replace(/ /g, '_') )) +'">Send private message</a><br />':'';
-      
-      // Add buddy link
-      tplvars.ADD_BUDDY_LINK=(data.comments[i].user_id>1)?'<a onclick="window.open(this.href); return false;" href="'+ makeUrlNS('Special', 'PrivateMessages/FriendList/Add/' + ( data.comments[i].name.replace(/ /g, '_') )) +'">Add to buddy list</a><br />':'';
-      
-      // Edit link
-      tplvars.EDIT_LINK='<a href="#edit_'+i+'" onclick="editComment(\''+i+'\', this); return false;" id="cmteditlink_'+i+'">edit</a>';
-      
-      // Delete link
-      tplvars.DELETE_LINK='<a href="#delete_'+i+'" onclick="deleteComment(\''+i+'\'); return false;">delete</a>';
-      
-      // Moderation: (Un)approve link
-      var appr = ( data.comments[i].approved == 1 ) ? 'Unapprove' : 'Approve';
-      tplvars.MOD_APPROVE_LINK='<a href="#approve_'+i+'" id="comment_approve_'+i+'" onclick="approveComment(\''+i+'\'); return false;">'+appr+'</a>';
-      
-      // Moderation: Delete post link
-      tplvars.MOD_DELETE_LINK='<a href="#mod_del_'+i+'" onclick="deleteComment(\''+i+'\'); return false;">Delete</a>';
-      
-      var tplbool = new Object();
-      
-      tplbool.signature = ( data.comments[i].signature == '' ) ? false : true;
-      tplbool.can_edit = ( data.auth_edit_comments && ( ( data.comments[i].user_id == data.user_id && data.logged_in ) || data.auth_mod_comments ) );
-      tplbool.auth_mod = data.auth_mod_comments;
-      
-      parser.assign_vars(tplvars);
-      parser.assign_bool(tplbool);
-      
-      html += '<div id="comment_holder_' + i + '"><input type="hidden" value="'+data.comments[i].comment_id+'" /><input type="hidden" id="comment_source_'+i+'" />' + parser.run() + '</div>';
-    }
+    comment_render_track = 0;
+    var commentpages = new paginator(data.comments, _render_comment, 0, 10, data);
+    html += commentpages.html;
   }
   
   if ( data.auth_post_comments )
@@ -200,11 +147,72 @@
     
   document.getElementById('ajaxEditContainer').innerHTML = html;
   
-  for ( i = 0; i < data.comments.length; i++ )
-  {
-    document.getElementById('comment_source_'+i).value = data.comments[i].comment_source;
-  }
+  //for ( i = 0; i < data.comments.length; i++ )
+  //{
+  //  document.getElementById('comment_source_'+i).value = data.comments[i].comment_source;
+  //}
+  
+}
+
+var _render_comment = function(this_comment, data)
+{
+  var i = comment_render_track;
+  comment_render_track++;
+  var parser = new templateParser(comment_template);
+  var tplvars = new Object();
+  
+  if ( this_comment.approved != '1' && !data.auth_mod_comments )
+    return '';
+  
+  tplvars.ID = i;
+  tplvars.DATETIME = this_comment.time;
+  tplvars.SUBJECT = this_comment.subject;
+  tplvars.DATA = this_comment.comment_data;
+  tplvars.SIGNATURE = this_comment.signature;
+  
+  if ( this_comment.approved != '1' )
+    tplvars.SUBJECT += ' <span style="color: #D84308">(Unapproved)</span>';
+  
+  // Name
+  tplvars.NAME = this_comment.name;
+  if ( this_comment.user_id > 1 )
+    tplvars.NAME = '<a href="' + makeUrlNS('User', this_comment.name) + '">' + this_comment.name + '</a>';
   
+  // User level
+  tplvars.USER_LEVEL = 'Guest';
+  if ( this_comment.user_level >= data.user_level.member ) tplvars.USER_LEVEL = 'Member';
+  if ( this_comment.user_level >= data.user_level.mod ) tplvars.USER_LEVEL = 'Moderator';
+  if ( this_comment.user_level >= data.user_level.admin ) tplvars.USER_LEVEL = 'Administrator';
+  
+  // Send PM link
+  tplvars.SEND_PM_LINK=(this_comment.user_id>1)?'<a onclick="window.open(this.href); return false;" href="'+ makeUrlNS('Special', 'PrivateMessages/Compose/To/' + ( this_comment.name.replace(/ /g, '_') )) +'">Send private message</a><br />':'';
+  
+  // Add buddy link
+  tplvars.ADD_BUDDY_LINK=(this_comment.user_id>1)?'<a onclick="window.open(this.href); return false;" href="'+ makeUrlNS('Special', 'PrivateMessages/FriendList/Add/' + ( this_comment.name.replace(/ /g, '_') )) +'">Add to buddy list</a><br />':'';
+  
+  // Edit link
+  tplvars.EDIT_LINK='<a href="#edit_'+i+'" onclick="editComment(\''+i+'\', this); return false;" id="cmteditlink_'+i+'">edit</a>';
+  
+  // Delete link
+  tplvars.DELETE_LINK='<a href="#delete_'+i+'" onclick="deleteComment(\''+i+'\'); return false;">delete</a>';
+  
+  // Moderation: (Un)approve link
+  var appr = ( this_comment.approved == 1 ) ? 'Unapprove' : 'Approve';
+  tplvars.MOD_APPROVE_LINK='<a href="#approve_'+i+'" id="comment_approve_'+i+'" onclick="approveComment(\''+i+'\'); return false;">'+appr+'</a>';
+  
+  // Moderation: Delete post link
+  tplvars.MOD_DELETE_LINK='<a href="#mod_del_'+i+'" onclick="deleteComment(\''+i+'\'); return false;">Delete</a>';
+  
+  var tplbool = new Object();
+  
+  tplbool.signature = ( this_comment.signature == '' ) ? false : true;
+  tplbool.can_edit = ( data.auth_edit_comments && ( ( this_comment.user_id == data.user_id && data.logged_in ) || data.auth_mod_comments ) );
+  tplbool.auth_mod = data.auth_mod_comments;
+  
+  parser.assign_vars(tplvars);
+  parser.assign_bool(tplbool);
+  
+  return '<div id="comment_holder_' + i + '"><input type="hidden" value="'+this_comment.comment_id+'" /><input type="hidden" id="comment_source_'+i+'" />' + parser.run() + '</div>';
 }
 
 function displayCommentForm()
--- a/includes/clientside/static/enano-lib-basic.js	Mon Aug 06 10:37:42 2007 -0400
+++ b/includes/clientside/static/enano-lib-basic.js	Thu Aug 09 12:26:16 2007 -0400
@@ -246,6 +246,7 @@
   'editor.js',
   'dynano.js',
   'flyin.js',
+  'paginate.js',
   'loader.js'
 ];
 
--- a/includes/clientside/static/misc.js	Mon Aug 06 10:37:42 2007 -0400
+++ b/includes/clientside/static/misc.js	Thu Aug 09 12:26:16 2007 -0400
@@ -557,59 +557,6 @@
   return str;
 }
 
-function paginator_goto(parentobj, this_page, num_pages, perpage, url_string)
-{
-  var height = $(parentobj).Height();
-  var width  = $(parentobj).Width();
-  var left   = $(parentobj).Left();
-  var top    = $(parentobj).Top();
-  var left_pos = left + width ;
-  var top_pos = height + top;
-  var div = document.createElement('div');
-  div.style.position = 'absolute';
-  div.style.top = top_pos + 'px';
-  div.className = 'question-box';
-  div.style.margin = '1px 0 0 2px';
-  var vtmp = 'input_' + Math.floor(Math.random() * 1000000);
-  div.innerHTML = 'Go to page:<br /><input type="text" size="2" style="padding: 1px; font-size: 8pt;" value="'+(parseInt(this_page)+1)+'" id="'+vtmp+'" />&emsp;<a href="#" onclick="paginator_submit(this, '+num_pages+', '+perpage+', unescape(\'' + escape(url_string) + '\')); return false;" style="font-size: 14pt; text-decoration: none;">&raquo;</a>&emsp;<a href="#" onclick="fly_out_top(this.parentNode, false, true); return false;" style="font-size: 14pt; text-decoration: none;">&times;</a>';
-  
-  var body = document.getElementsByTagName('body')[0];
-  domObjChangeOpac(0, div);
-  
-  body.appendChild(div);
-  
-  document.getElementById(vtmp).onkeypress = function(e){if(e.keyCode==13)this.nextSibling.nextSibling.onclick();};
-  document.getElementById(vtmp).focus();
-  
-  // fade the div
-  /*
-  if(!div.id) div.id = 'autofade_'+Math.floor(Math.random() * 100000);
-  var from = '#33FF33';
-  Fat.fade_element(div.id,30,2000,from,Fat.get_bgcolor(div.id));
-  */
-  
-  fly_in_bottom(div, false, true);
-  
-  var divh = $(div).Width();
-  left_pos = left_pos - divh;
-  div.style.left = left_pos + 'px';
-}
-
-function paginator_submit(obj, max, perpage, formatstring)
-{
-  var userinput = obj.previousSibling.previousSibling.value;
-  userinput = parseInt(userinput);
-  var offset = ( userinput - 1 ) * perpage;
-  if ( userinput > max || isNaN(userinput) || userinput < 1 )
-  {
-    new messagebox(MB_OK|MB_ICONSTOP, 'Invalid entry', 'Please enter a page number between 1 and ' + max + '.');
-    return false;
-  }
-  var url = sprintf(formatstring, String(offset));
-  fly_out_top(obj.parentNode, false, true);
-  window.location = url;
-}
-
 /**
  * Insert a DOM object _after_ the specified child.
  * @param object Parent node
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/paginate.js	Thu Aug 09 12:26:16 2007 -0400
@@ -0,0 +1,275 @@
+// Javascript pagination control
+
+/**
+ * Paginates an array of data.
+ * @param array List of objects to render
+ * @param function Function called on each member of the array to render, should take an array member and set this.html to a string
+ * @param int Optional. Object to start at, defaults to 0.
+ * @param int Optional. Objects per page, defaults to 10
+ * @param object Variable that will be passed to the renderer callback
+ */
+ 
+var pagin_objects = new Object();
+
+function paginator(data, callback, offset, perpage, passer)
+{
+  if ( !perpage || typeof(perpage) != 'number' || ( typeof(perpage) == 'number' && perpage < 1 ) )
+  {
+    this.perpage = 10;
+  }
+  else
+  {
+    this.perpage = perpage;
+  }
+  if ( typeof(offset) != 'number' )
+    this.offset = 0;
+  else
+    this.offset = offset;
+  if ( typeof(passer) != 'undefined' )
+    this.passer = passer;
+  else
+    this.passer = false;
+  this.num_pages = Math.ceil(data.length / perpage );
+  this.random_id = 'autopagin_' + Math.floor(Math.random() * 1000000);
+  this._build_control = _build_paginator;
+  if ( this.num_pages > 1 )
+  {
+    var pg_control = '<div class="'+this.random_id+'_control">'+this._build_control(0)+'</div>';
+  }
+  else
+  {
+    var pg_control = '';
+  }
+  this.html = pg_control;
+  var i = 0;
+  while ( i < data.length )
+  {
+    if ( i % this.perpage == 0 )
+    {
+      if ( i > 0 )
+        this.html += '</div>';
+      var display = ( ( i * this.perpage ) == this.offset ) ? '' : 'display: none;';
+      var thispage = Math.floor(i / this.perpage);
+      this.html += '<div id="' + this.random_id + '_' + thispage + '" style="' + display + '">';
+    }
+    this.html += callback(data[i], this.passer);
+    i++;
+  }
+  this.html += '</div>';
+  this.html += pg_control;
+  pagin_objects[this.random_id] = this;
+}
+
+function _build_paginator(this_page)
+{
+  var begin = '<div class="tblholder" style="display: table; margin: 10px 0 0 auto;"><table border="0" cellspacing="1" cellpadding="4"><tr><th>Page:</th>';
+  var block = '<td class="row1" style="text-align: center;">{LINK}</td>';
+  var end = '</tr></table></div>';
+  var blk = new templateParser(block);
+  var inner = '';
+  var cls = 'row2';
+  
+  if ( this.offset > 0 )
+  {
+    var url = '#';
+    var link = "<a href=\""+url+"\" style='text-decoration: none;'>&laquo; Prev</a>";
+    cls = ( cls == 'row1' ) ? 'row2' : 'row1';
+    blk.assign_vars({
+        CLASS: cls,
+        LINK: link
+      });
+    inner += blk.run();
+  }
+  if ( this.num_pages < 5 )
+  {
+    for ( var i = 0; i < this.num_pages; i++ )
+    {
+      cls = ( cls == 'row1' ) ? 'row2' : 'row1';
+      var url = '#';
+      var j = i + 1;
+      var link = ( i == this_page ) ? "<b>"+j+"</b>" : "<a href=\""+url+"\" onclick=\"jspaginator_goto('"+this.random_id+"', "+i+"); return false;\" style='text-decoration: none;'>"+j+"</a>";
+      blk.assign_vars({
+          CLASS: cls,
+          LINK: link
+        });
+      inner += blk.run();
+    }
+  }
+  else
+  {
+    if ( this_page + 5 > this.num_pages )
+    {
+      var list = new Array();
+      var tp = this_page;
+      if ( this_page + 0 == this.num_pages ) tp = tp - 3;
+      if ( this_page + 1 == this.num_pages ) tp = tp - 2;
+      if ( this_page + 2 == this.num_pages ) tp = tp - 1;
+      for ( var i = tp - 1; i <= tp + 1; i++ )
+      {
+        list.push(i);
+      }
+    }
+    else
+    {
+      var list = new Array();
+      var current = this_page;
+      var lower = ( current < 3 ) ? 1 : current - 1;
+      for ( var i = 0; i < 3; i++ )
+      {
+        list.push(lower + i);
+      }
+    }
+    var url = '#';
+    var link = ( 0 == this.offset ) ? "<b>First</b>" : "<a href=\""+url+"\" style='text-decoration: none;'>&laquo; First</a>";
+    blk.assign_vars({
+        CLASS: cls,
+        LINK: link
+      });
+    inner += blk.run();
+
+    // if ( !in_array(1, $list) )
+    // {
+    //   $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+    //   $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...'));
+    //   $inner .= $blk->run();
+    // }
+
+    for ( var k in list )
+    {
+      var i = list[k];
+      if ( i == this.num_pages )
+        break;
+      cls = ( cls == 'row1' ) ? 'row2' : 'row1';
+      var offset = i * this_page;
+      var url = '#';
+      var j = i + 1;
+      var link = ( offset == this.offset ) ? "<b>"+j+"</b>" : "<a href=\""+url+"\" style='text-decoration: none;'>"+j+"</a>";
+      blk.assign_vars({
+          CLASS: cls,
+          LINK: link
+        });
+      inner += blk.run();
+    }
+
+    var total = num_pages * perpage - perpage;
+
+    if ( this_page < this.num_pages )
+    {
+      // $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
+      // $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...'));
+      // $inner .= $blk->run();
+
+      cls = ( cls == 'row1' ) ? 'row2' : 'row1';
+      var url = '#';
+      var j = i + 1;
+      var link = ( total == this.offset ) ? "<b>Last</b>" : "<a href=\""+url+"\" style='text-decoration: none;'>Last &raquo;</a>";
+      blk.assign_vars({
+          CLASS: cls,
+          LINK: link
+        });
+      inner += blk.run();
+    }
+
+  }
+
+  if ( this.offset < total )
+  {
+    var url = '#page_' + abs(this.offset + this.perpage);
+    var link = "<a href=\""+url+"\" style='text-decoration: none;'>Next &raquo;</a>";
+    cls = ( cls == 'row1' ) ? 'row2' : 'row1';
+    blk.assign_vars({
+          CLASS: cls,
+          LINK: link
+        });
+      inner += blk.run();
+  }
+
+  inner += '<td class="row2" style="cursor: pointer;" onclick="paginator_goto(this, '+this_page+', '+this.num_pages+', '+this.perpage+', {js: true, random_id: \''+this.random_id+'\'});">&darr;</td>';
+
+  var paginator = "\n"+begin+inner+end+"\n";
+  return paginator;
+  
+}
+
+function jspaginator_goto(pagin_id, jump_to)
+{
+  var theobj = pagin_objects[pagin_id];
+  for ( var i = 0; i < theobj.num_pages; i++ )
+  {
+    var display = ( i == jump_to ) ? 'block' : 'none';
+    var thediv = document.getElementById(pagin_id + '_' + i);
+    if ( thediv )
+      thediv.style.display = display;
+  }
+  var pg_control = theobj._build_control(jump_to);
+  var divs = getElementsByClassName(document, 'div', pagin_id + '_control');
+  for ( var i = 0; i < divs.length; i++ )
+  {
+    divs[i].innerHTML = pg_control;
+  }
+}
+
+function paginator_goto(parentobj, this_page, num_pages, perpage, url_string)
+{
+  var height = $(parentobj).Height();
+  var width  = $(parentobj).Width();
+  var left   = $(parentobj).Left();
+  var top    = $(parentobj).Top();
+  var left_pos = left + width ;
+  var top_pos = height + top;
+  var div = document.createElement('div');
+  div.style.position = 'absolute';
+  div.style.top = top_pos + 'px';
+  div.className = 'question-box';
+  div.style.margin = '1px 0 0 2px';
+  var vtmp = 'input_' + Math.floor(Math.random() * 1000000);
+  var regex = new RegExp('\"', 'g');
+  var submit_target = ( typeof(url_string) == 'object' ) ? ( toJSONString(url_string) ).replace(regex, '\'') : 'unescape(\'' + escape(url_string) + '\')';
+  var onclick = 'paginator_submit(this, '+num_pages+', '+perpage+', '+submit_target+'); return false;';
+  div.innerHTML = 'Go to page:<br /><input type="text" size="2" style="padding: 1px; font-size: 8pt;" value="'+(parseInt(this_page)+1)+'" id="'+vtmp+'" />&emsp;<a href="#" onclick="'+onclick+'" style="font-size: 14pt; text-decoration: none;">&raquo;</a>&emsp;<a href="#" onclick="fly_out_top(this.parentNode, false, true); return false;" style="font-size: 14pt; text-decoration: none;">&times;</a>';
+  
+  var body = document.getElementsByTagName('body')[0];
+  domObjChangeOpac(0, div);
+  
+  body.appendChild(div);
+  
+  document.getElementById(vtmp).onkeypress = function(e){if(e.keyCode==13)this.nextSibling.nextSibling.onclick();};
+  document.getElementById(vtmp).focus();
+  
+  // fade the div
+  /*
+  if(!div.id) div.id = 'autofade_'+Math.floor(Math.random() * 100000);
+  var from = '#33FF33';
+  Fat.fade_element(div.id,30,2000,from,Fat.get_bgcolor(div.id));
+  */
+  
+  fly_in_bottom(div, false, true);
+  
+  var divh = $(div).Width();
+  left_pos = left_pos - divh;
+  div.style.left = left_pos + 'px';
+}
+
+function paginator_submit(obj, max, perpage, formatstring)
+{
+  var userinput = obj.previousSibling.previousSibling.value;
+  userinput = parseInt(userinput);
+  var offset = ( userinput - 1 ) * perpage;
+  if ( userinput > max || isNaN(userinput) || userinput < 1 )
+  {
+    new messagebox(MB_OK|MB_ICONSTOP, 'Invalid entry', 'Please enter a page number between 1 and ' + max + '.');
+    return false;
+  }
+  if ( typeof(formatstring) == 'object' )
+  {
+    fly_out_top(obj.parentNode, false, true);
+    jspaginator_goto(formatstring.random_id, ( offset / perpage ));
+  }
+  else
+  {
+    var url = sprintf(formatstring, String(offset));
+    fly_out_top(obj.parentNode, false, true);
+    window.location = url;
+  }
+}
+
--- a/includes/render.php	Mon Aug 06 10:37:42 2007 -0400
+++ b/includes/render.php	Thu Aug 09 12:26:16 2007 -0400
@@ -826,6 +826,12 @@
       
       $img_tag .= 'style="border-width: 0px; /* background-color: white; */" ';
       
+      $code = $plugins->setHook('img_tag_parse_img');
+      foreach ( $code as $cmd )
+      {
+        eval($cmd);
+      }
+      
       $img_tag .= '/>';
       
       $complete_tag = '';
@@ -868,7 +874,13 @@
       }
       else
       {
-        $complete_tag .= '<a href="' . makeUrlNS('File', $filename) . '" style="display: block;">';
+        $complete_tag .= '<a href="' . makeUrlNS('File', $filename) . '" style="display: block;"';
+        $code = $plugins->setHook('img_tag_parse_link');
+        foreach ( $code as $cmd )
+        {
+          eval($cmd);
+        }
+        $complete_tag .= '>';
         $complete_tag .= $img_tag;
         $complete_tag .= '</a>';
       }
--- a/includes/template.php	Mon Aug 06 10:37:42 2007 -0400
+++ b/includes/template.php	Thu Aug 09 12:26:16 2007 -0400
@@ -747,7 +747,8 @@
       'THEME_ID'=>$this->theme,
       'STYLE_ID'=>$this->style,
       'JS_DYNAMIC_VARS'=>$js_dynamic,
-      'UNREAD_PMS'=>$session->unread_pms
+      'UNREAD_PMS'=>$session->unread_pms,
+      'URL_ABOUT_ENANO' => makeUrlNS('Special', 'About_Enano', true)
       );
     
     foreach ( $paths->nslist as $ns_id => $ns_prefix )
--- a/install.php	Mon Aug 06 10:37:42 2007 -0400
+++ b/install.php	Thu Aug 09 12:26:16 2007 -0400
@@ -1119,7 +1119,7 @@
 RewriteEngine on
 RewriteCond %{REQUEST_FILENAME} !-d
 RewriteCond %{REQUEST_FILENAME} !-f
-RewriteRule ^(.+) '.scriptPath.'/index.php/$1 [L,QSA]
+RewriteRule ^(.+) '.scriptPath.'/index.php?title=$1 [L,QSA]
 RewriteRule \.(php|html|gif|jpg|png|css|js)$ - [L]
 ');
         fclose($ht);
--- a/plugins/PrivateMessages.php	Mon Aug 06 10:37:42 2007 -0400
+++ b/plugins/PrivateMessages.php	Thu Aug 09 12:26:16 2007 -0400
@@ -4,7 +4,7 @@
 Plugin URI: http://enanocms.org/
 Description: Provides the page Special:PrivateMessages, which is used to manage private message functions. Also handles buddy lists.
 Author: Dan Fuhry
-Version: 1.0
+Version: 1.0.1
 Author URI: http://enanocms.org/
 */
 
--- a/plugins/SpecialAdmin.php	Mon Aug 06 10:37:42 2007 -0400
+++ b/plugins/SpecialAdmin.php	Thu Aug 09 12:26:16 2007 -0400
@@ -2,7 +2,7 @@
 /*
 Plugin Name: Runt - the Enano administration panel
 Plugin URI: http://enanocms.org/
-Description: Provides the page Special:Administration, which is the AJAX frontend to the various Admin:
+Description: Provides the page Special:Administration, which is the AJAX frontend to the various Admin pagelets. This plugin cannot be disabled.
 Author: Dan Fuhry
 Version: 1.0.1
 Author URI: http://enanocms.org/
@@ -549,13 +549,13 @@
           echo('<h3>Error disabling plugin</h3><p>The demo lockdown plugin cannot be disabled in demo mode.</p>');
           break;
         }
-        if ( $_GET['plugin'] != 'SpecialAdmin.php' )
+        if ( !in_array($_GET['plugin'], $plugins->system_plugins) )
         {
           setConfig('plugin_'.$_GET['plugin'], '0');
         }
         else 
         {
-          echo('<h3>Error disabling plugin</h3><p>The administration panel plugin cannot be disabled.</p>');
+          echo('<h3>Error disabling plugin</h3><p>The plugin you selected cannot be disabled because it is a system plugin.</p>');
         }
         break;
     }
@@ -563,6 +563,7 @@
   $dir = './plugins/';
   $plugin_list = Array();
   $system = Array();
+  $show_system = ( isset($_GET['show_system']) && $_GET['show_system'] == 'yes' );
   
   if (is_dir($dir))
   {
@@ -572,10 +573,12 @@
       {
         if(preg_match('#^(.*?)\.php$#is', $file) && $file != 'index.php')
         {
+          unset($thelist);
           if ( in_array($file, $plugins->system_plugins) )
           {
+            if ( !$show_system )
+              continue;
             $thelist =& $system;
-            continue;
           }
           else
           {
@@ -614,28 +617,48 @@
   }
   echo('<div class="tblholder"><table border="0" width="100%" cellspacing="1" cellpadding="4">
       <tr><th>Plugin filename</th><th>Plugin name</th><th>Description</th><th>Author</th><th>Version</th><th></th></tr>');
-    $plugin_files = array_keys($plugin_list);
+    $plugin_files_1 = array_keys($plugin_list);
+    $plugin_files_2 = array_keys($system);
+    $plugin_files = array_values(array_merge($plugin_files_1, $plugin_files_2));
     $cls = 'row2';
     for ( $i = 0; $i < sizeof($plugin_files); $i++ )
     {
       $cls = ( $cls == 'row2' ) ? 'row3' : 'row2';
+      $this_plugin = ( isset($system[$plugin_files[$i]]) ) ? $system[$plugin_files[$i]] : $plugin_list[$plugin_files[$i]];
+      $is_system = ( $system[$plugin_files[$i]] );
+      $bgcolor = '';
+      if ( $is_system && $cls == 'row2' )
+        $bgcolor = ' style="background-color: #FFD8D8;"';
+      else if ( $is_system && $cls == 'row3' )
+        $bgcolor = ' style="background-color: #FFD0D0;"';
       echo '<tr>
-              <td class="'.$cls.'">'.$plugin_files[$i].'</td>
-              <td class="'.$cls.'"><a href="'.$plugin_list[$plugin_files[$i]]['uri'].'">'.$plugin_list[$plugin_files[$i]]['name'].'</a></td>
-              <td class="'.$cls.'">'.$plugin_list[$plugin_files[$i]]['desc'].'</td>
-              <td class="'.$cls.'"><a href="'.$plugin_list[$plugin_files[$i]]['aweb'].'">'.$plugin_list[$plugin_files[$i]]['auth'].'</a></td>
-              <td class="'.$cls.'">'.$plugin_list[$plugin_files[$i]]['vers'].'</td>
-              <td class="'.$cls.'">';
-      if ( getConfig('plugin_'.$plugin_files[$i]) == '1' )
+              <td class="'.$cls.'"'.$bgcolor.'>'.$plugin_files[$i].'</td>
+              <td class="'.$cls.'"'.$bgcolor.'><a href="'.$this_plugin['uri'].'">'.$this_plugin['name'].'</a></td>
+              <td class="'.$cls.'"'.$bgcolor.'>'.$this_plugin['desc'].'</td>
+              <td class="'.$cls.'"'.$bgcolor.'><a href="'.$this_plugin['aweb'].'">'.$this_plugin['auth'].'</a></td>
+              <td class="'.$cls.'"'.$bgcolor.'>'.$this_plugin['vers'].'</td>
+              <td class="'.$cls.'"'.$bgcolor.'>';
+      if ( !in_array($plugin_files[$i], $plugins->system_plugins) )
       {
-        echo '<a href="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'&amp;action=disable&amp;plugin='.$plugin_files[$i].'">Disable</a>';
+        if ( getConfig('plugin_'.$plugin_files[$i]) == '1' )
+        {
+          echo '<a href="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'&amp;show_system=' . ( $show_system ? 'yes' : 'no' ) . '&amp;action=disable&amp;plugin='.$plugin_files[$i].'">Disable</a>';
+        }
+        else
+        {
+          echo '<a href="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'&amp;show_system=' . ( $show_system ? 'yes' : 'no' ) . '&amp;action=enable&amp;plugin='.$plugin_files[$i].'">Enable</a>';
+        }
       }
       else
       {
-        echo '<a href="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'&amp;action=enable&amp;plugin='.$plugin_files[$i].'">Enable</a>';
+        echo '[System]';
       }
       echo '</td></tr>';
     }
+    $showhide_link = ( $show_system ) ?
+    '<a style="color: white;" href="' . makeUrlNS('Special', 'Administration', 'module=' . $paths->cpage['module'] . '&show_system=no', true) . '">Hide system plugins</a>' :
+    '<a style="color: white;" href="' . makeUrlNS('Special', 'Administration', 'module=' . $paths->cpage['module'] . '&show_system=yes', true) . '">Show system plugins</a>' ;
+    echo '<tr><th colspan="6" class="subhead">'.$showhide_link.'</th></tr>';
     echo '</table></div>';
 }
 
--- a/plugins/SpecialCSS.php	Mon Aug 06 10:37:42 2007 -0400
+++ b/plugins/SpecialCSS.php	Thu Aug 09 12:26:16 2007 -0400
@@ -4,7 +4,7 @@
 Plugin URI: http://enanocms.org/
 Description: Provides the page Special:CSS, which is used in template files to reference the style sheet. Disabling or deleting this plugin will result in site instability.
 Author: Dan Fuhry
-Version: 1.0
+Version: 1.0.1
 Author URI: http://enanocms.org/
 */
 
--- a/plugins/SpecialGroups.php	Mon Aug 06 10:37:42 2007 -0400
+++ b/plugins/SpecialGroups.php	Thu Aug 09 12:26:16 2007 -0400
@@ -4,7 +4,7 @@
 Plugin URI: http://enanocms.org/
 Description: Provides group moderators and site administrators with the ability to control who is part of their groups. 
 Author: Dan Fuhry
-Version: 1.0RC1
+Version: 1.0.1
 Author URI: http://enanocms.org/
 */
 
--- a/plugins/SpecialPageFuncs.php	Mon Aug 06 10:37:42 2007 -0400
+++ b/plugins/SpecialPageFuncs.php	Thu Aug 09 12:26:16 2007 -0400
@@ -4,7 +4,7 @@
 Plugin URI: http://enanocms.org/
 Description: Provides the page Special:CreatePage, which can be used to create new pages. Also adds the About Enano and GNU General Public License pages.
 Author: Dan Fuhry
-Version: 1.0
+Version: 1.0.1
 Author URI: http://enanocms.org/
 */
 
--- a/plugins/SpecialSearch.php	Mon Aug 06 10:37:42 2007 -0400
+++ b/plugins/SpecialSearch.php	Thu Aug 09 12:26:16 2007 -0400
@@ -4,7 +4,7 @@
 Plugin URI: http://enanocms.org/
 Description: Provides the page Special:Search, which is a frontend to the Enano search engine.
 Author: Dan Fuhry
-Version: 1.0
+Version: 1.0.1
 Author URI: http://enanocms.org/
 */
 
--- a/plugins/SpecialUpdownload.php	Mon Aug 06 10:37:42 2007 -0400
+++ b/plugins/SpecialUpdownload.php	Thu Aug 09 12:26:16 2007 -0400
@@ -4,7 +4,7 @@
 Plugin URI: http://enanocms.org/
 Description: Provides the pages Special:UploadFile and Special:DownloadFile. UploadFile is used to upload files to the site, and DownloadFile fetches the file from the database, creates thumbnails if necessary, and sends the file to the user.
 Author: Dan Fuhry
-Version: 1.0
+Version: 1.0.1
 Author URI: http://enanocms.org/
 */
 
--- a/plugins/SpecialUserFuncs.php	Mon Aug 06 10:37:42 2007 -0400
+++ b/plugins/SpecialUserFuncs.php	Thu Aug 09 12:26:16 2007 -0400
@@ -4,7 +4,7 @@
 Plugin URI: http://enanocms.org/
 Description: Provides the pages Special:Login, Special:Logout, Special:Register, and Special:Preferences.
 Author: Dan Fuhry
-Version: 1.0
+Version: 1.0.1
 Author URI: http://enanocms.org/
 */
 
--- a/plugins/SpecialUserPrefs.php	Mon Aug 06 10:37:42 2007 -0400
+++ b/plugins/SpecialUserPrefs.php	Thu Aug 09 12:26:16 2007 -0400
@@ -4,7 +4,7 @@
 Plugin URI: http://enanocms.org/
 Description: Provides the page Special:Preferences.
 Author: Dan Fuhry
-Version: 1.0
+Version: 1.0.1
 Author URI: http://enanocms.org/
 */
 
--- a/themes/admin/footer.tpl	Mon Aug 06 10:37:42 2007 -0400
+++ b/themes/admin/footer.tpl	Thu Aug 09 12:26:16 2007 -0400
@@ -1,6 +1,6 @@
           </div>
           <div class="footer">
-            {COPYRIGHT}<br />Powered by <a href="{CONTENTPATH}{NS_SPECIAL}About_Enano{ADMIN_SID_AUTO}">Enano</a> &bull; Copyright &copy; 2007 Dan Fuhry
+            {COPYRIGHT}<br />Powered by <a href="<!-- BEGIN stupid_mode -->http://enanocms.org/<!-- BEGINELSE stupid_mode -->{URL_ABOUT_ENANO}<!-- END stupid_mode -->">Enano</a> &bull; Copyright &copy; 2007 Dan Fuhry
           </div>
         </td>
         <td class="right"></td>
--- a/themes/oxygen/footer.tpl	Mon Aug 06 10:37:42 2007 -0400
+++ b/themes/oxygen/footer.tpl	Thu Aug 09 12:26:16 2007 -0400
@@ -12,7 +12,7 @@
                  -->
             <div id="credits">
               {COPYRIGHT}<br />
-              Powered by <a href="http://www.enanocms.org">Enano</a>  |  <a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.1</a>  |  <a href="http://jigsaw.w3.org/css-validator/validator?uri=referer">Valid CSS</a>  |  [[Stats]]
+              Powered by <a href="<!-- BEGIN stupid_mode -->http://enanocms.org/<!-- BEGINELSE stupid_mode -->{URL_ABOUT_ENANO}<!-- END stupid_mode -->">Enano</a>  |  <a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.1</a>  |  <a href="http://jigsaw.w3.org/css-validator/validator?uri=referer">Valid CSS</a>  |  [[Stats]]
             </div>
           
           </td><td id="mdg-btr"></td></tr>
--- a/themes/stpatty/footer.tpl	Mon Aug 06 10:37:42 2007 -0400
+++ b/themes/stpatty/footer.tpl	Thu Aug 09 12:26:16 2007 -0400
@@ -9,7 +9,7 @@
                  
                  -Dan
                  -->
-          {COPYRIGHT} &bull; Powered by <a href="<!-- BEGIN stupid_mode -->http://www.enanocms.org/<!-- BEGINELSE stupid_mode -->{CONTENTPATH}{NS_SPECIAL}About_Enano{ADMIN_SID_AUTO}<!-- END stupid_mode -->">Enano</a>  |  <a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.1</a>  |  <a href="http://jigsaw.w3.org/css-validator/validator?uri=referer">Valid CSS</a>  |  [[Stats]]
+          {COPYRIGHT} &bull; Powered by <a href="<!-- BEGIN stupid_mode -->http://enanocms.org/<!-- BEGINELSE stupid_mode -->{URL_ABOUT_ENANO}<!-- END stupid_mode -->">Enano</a>  |  <a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.1</a>  |  <a href="http://jigsaw.w3.org/css-validator/validator?uri=referer">Valid CSS</a>  |  [[Stats]]
         </div>
       </div>
     </div>