First test of rank manager interface, not currently capable of doing anything interesting (fills form with placeholder data); strings are in an earlier commit
authorDan
Sat, 07 Jun 2008 12:48:39 -0400
changeset 563 0103428e2179
parent 562 75df0b2c596c
child 564 a1c450a911a6
First test of rank manager interface, not currently capable of doing anything interesting (fills form with placeholder data); strings are in an earlier commit
includes/clientside/css/enano-shared.css
includes/clientside/static/enano-lib-basic.js
includes/clientside/static/rank-manager.js
plugins/admin/UserRanks.php
--- a/includes/clientside/css/enano-shared.css	Sat Jun 07 12:46:18 2008 -0400
+++ b/includes/clientside/css/enano-shared.css	Sat Jun 07 12:48:39 2008 -0400
@@ -805,3 +805,25 @@
 .abutton_red         { color:            #880000 !important; }
 .abutton_red:hover   { background-color: #880000 !important; }
 
+/* User rank administration */
+
+div.rankadmin-left {
+  float: left;
+  border: 1px solid #e0e0e0;
+  margin: 0 1.4em 0 0;
+  padding: 0.6em;
+}
+
+a.rankadmin-editlink {
+  display: block;
+  font-size: large;
+  padding: 3px;
+}
+
+a.rankadmin-editlink:hover {
+  background-color: #f0f0f0;
+}
+
+div.rankadmin-right {
+  float: left;
+}
--- a/includes/clientside/static/enano-lib-basic.js	Sat Jun 07 12:46:18 2008 -0400
+++ b/includes/clientside/static/enano-lib-basic.js	Sat Jun 07 12:48:39 2008 -0400
@@ -338,6 +338,7 @@
   'paginate.js',
   'pwstrength.js',
   'theme-manager.js',
+  'rank-manager.js',
   'SpryEffects.js',
   'loader.js'
 ];
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/rank-manager.js	Sat Jun 07 12:48:39 2008 -0400
@@ -0,0 +1,234 @@
+/**
+ * Creates a control that can be used to edit a rank.
+ */
+
+var RankEditorControl = function(rankdata)
+{
+  this.rankdata = rankdata;
+  
+  // have the browser parse CSS for us and use an anchor to be as close
+  // as possible in calculating CSS
+  
+  // this is kind of a hack as it relies on setAttribute/getAttribute in
+  // order to obtain stringified versions of CSS data
+  var cssobj = document.createElement('a');
+  cssobj.setAttribute('style', this.rankdata.rank_style);
+  
+  this.style_sim_obj = cssobj;
+  
+  // figure out if we're editing or creating
+  this.editing = ( typeof(this.rankdata.rank_id) == 'number' );
+  
+  this.render = function()
+  {
+    var editor = document.createElement('div');
+    editor.className = 'tblholder';
+    // stash this editor instance in the parent div for later function calls
+    editor.editor = this;
+    
+    // tables suck.
+    var table = document.createElement('table');
+    table.setAttribute('cellspacing', '1');
+    table.setAttribute('cellpadding', '4');
+    table.setAttribute('width', '100%');
+    
+    // heading: "Edit rank: foo" or "Create a new rank"
+    var tr_head = document.createElement('tr');
+    var th_head = document.createElement('th');
+    th_head.setAttribute('colspan', '2');
+    if ( this.editing )
+    {
+      var th_head_string = 'acpur_th_edit_rank';
+      var th_head_data = { rank_title: $lang.get(this.rankdata.rank_title) };
+    }
+    else
+    {
+      var th_head_string = 'acpur_th_create_rank';
+      var th_head_data = { };
+    }
+    th_head.appendChild(document.createTextNode($lang.get(th_head_string, th_head_data)));
+    tr_head.appendChild(th_head);
+    table.appendChild(tr_head);
+    
+    // row: rank title
+    var tr_title = document.createElement('tr');
+    var td_title_l = document.createElement('td');
+    var td_title_f = document.createElement('td');
+    
+    td_title_l.className = td_title_f.className = 'row1';
+    
+    td_title_l.appendChild(document.createTextNode($lang.get('acpur_field_rank_title')));
+    
+    // field: rank title
+    var f_rank_title = document.createElement('input');
+    f_rank_title.type = 'text';
+    f_rank_title.size = '30';
+    f_rank_title.value = ( this.editing ) ? this.rankdata.rank_title : '';
+    this.f_rank_title = f_rank_title;
+    td_title_f.appendChild(f_rank_title);
+    
+    tr_title.appendChild(td_title_l);
+    tr_title.appendChild(td_title_f);
+    table.appendChild(tr_title);
+    
+    // row: basic style options
+    var tr_basic = document.createElement('tr');
+    var td_basic_l = document.createElement('td');
+    var td_basic_f = document.createElement('td');
+    
+    td_basic_l.className = td_basic_f.className = 'row2';
+    
+    td_basic_l.appendChild(document.createTextNode($lang.get('acpur_field_style_basic')));
+    
+    // fieldset: basic style options
+    // field: bold
+    var l_basic_bold = document.createElement('label');
+    var f_basic_bold = document.createElement('input');
+    f_basic_bold.type = 'checkbox';
+    f_basic_bold.checked = ( this.style_sim_obj.style.fontWeight == 'bold' ) ? true : false;
+    f_basic_bold.editor = this;
+    f_basic_bold.onclick = function()
+    {
+      this.editor.style_sim_obj.style.fontWeight = ( this.checked ) ? 'bold' : null;
+    }
+    l_basic_bold.style.fontWeight = 'bold';
+    l_basic_bold.appendChild(f_basic_bold);
+    l_basic_bold.appendChild(document.createTextNode(' '));
+    l_basic_bold.appendChild(document.createTextNode($lang.get('acpur_field_style_basic_bold')));
+    
+    // field: italic
+    var l_basic_italic = document.createElement('label');
+    var f_basic_italic = document.createElement('input');
+    f_basic_italic.type = 'checkbox';
+    f_basic_italic.checked = ( this.style_sim_obj.style.fontStyle == 'italic' ) ? true : false;
+    f_basic_italic.editor = this;
+    f_basic_italic.onclick = function()
+    {
+      this.editor.style_sim_obj.style.fontStyle = ( this.checked ) ? 'italic' : null;
+    }
+    l_basic_italic.style.fontStyle = 'italic';
+    l_basic_italic.appendChild(f_basic_italic);
+    l_basic_italic.appendChild(document.createTextNode(' '));
+    l_basic_italic.appendChild(document.createTextNode($lang.get('acpur_field_style_basic_italic')));
+    
+    // field: underline
+    var l_basic_underline = document.createElement('label');
+    var f_basic_underline = document.createElement('input');
+    f_basic_underline.type = 'checkbox';
+    f_basic_underline.checked = ( this.style_sim_obj.style.textDecoration == 'underline' ) ? true : false;
+    f_basic_underline.editor = this;
+    f_basic_underline.onclick = function()
+    {
+      this.editor.style_sim_obj.style.textDecoration = ( this.checked ) ? 'underline' : null;
+    }
+    l_basic_underline.style.textDecoration = 'underline';
+    l_basic_underline.appendChild(f_basic_underline);
+    l_basic_underline.appendChild(document.createTextNode(' '));
+    l_basic_underline.appendChild(document.createTextNode($lang.get('acpur_field_style_basic_underline')));
+    
+    // finish up formatting row#1
+    td_basic_f.appendChild(l_basic_bold);
+    td_basic_f.appendChild(document.createTextNode(' '));
+    td_basic_f.appendChild(l_basic_italic);
+    td_basic_f.appendChild(document.createTextNode(' '));
+    td_basic_f.appendChild(l_basic_underline);
+    
+    tr_basic.appendChild(td_basic_l);
+    tr_basic.appendChild(td_basic_f);
+    table.appendChild(tr_basic);
+    
+    // row: rank color
+    var tr_color = document.createElement('tr');
+    var td_color_l = document.createElement('td');
+    var td_color_f = document.createElement('td');
+    
+    td_color_l.className = td_color_f.className = 'row1';
+    
+    td_color_l.appendChild(document.createTextNode($lang.get('acpur_field_style_color')));
+    
+    // field: rank color
+    var f_rank_color = document.createElement('input');
+    f_rank_color.type = 'text';
+    f_rank_color.size = '7';
+    f_rank_color.value = ( this.editing ) ? this.rgb2hex(this.style_sim_obj.style.color) : '';
+    f_rank_color.style.backgroundColor = this.style_sim_obj.style.color;
+    this.f_rank_color = f_rank_color;
+    f_rank_color.onkeyup = function(e)
+    {
+      if ( !e.keyCode )
+        e = window.event;
+      if ( !e )
+        return false;
+      var chr = (String.fromCharCode(e.keyCode)).toLowerCase();
+      this.value = this.value.replace(/[^a-fA-F0-9]/g, '');
+      if ( this.value.length > 6 )
+      {
+        this.value = this.value.substr(0, 6);
+      }
+      if ( this.value.length == 6 || this.value.length == 3 )
+      {
+        this.style.backgroundColor = '#' + this.value;
+      }
+    }
+    td_color_f.appendChild(f_rank_color);
+    
+    tr_color.appendChild(td_color_l);
+    tr_color.appendChild(td_color_f);
+    table.appendChild(tr_color);
+    
+    // finalize the editor table
+    editor.appendChild(table);
+    
+    // stash rendered editor
+    this.editordiv = editor;
+    
+    // send output
+    return editor;
+  }
+  
+  this.getJSONDataset = function()
+  {
+    
+  }
+  
+  this.getCSS = function()
+  {
+    
+  }
+  
+  /**
+   * Converts a parenthetical color specification (rgb(x, y, z)) to hex form (xxyyzz)
+   * @param string
+   * @return string
+   */
+  
+  this.rgb2hex = function(rgb)
+  {
+    var p = rgb.match(/^rgb\(([0-9]+), ([0-9]+), ([0-9]+)\)$/);
+    if ( !p )
+      return rgb.replace(/^#/, '');
+    
+    var r = parseInt(p[1]).toString(16), g = parseInt(p[2]).toString(16), b = parseInt(p[3]).toString(16);
+    if ( r.length < 2 )
+      r = '0' + r;
+    if ( g.length < 2 )
+      g = '0' + g;
+    if ( b.length < 2 )
+      b = '0' + b;
+    
+    return r + g + b;
+  }
+}
+
+/**
+ * Perform request for editable rank data and draw editor
+ */
+
+function ajaxInitRankEdit(rank_id)
+{
+  var editor = new RankEditorControl({ rank_title: 'Foo', rank_id: rank_id, rank_style: 'color: #ff0000; font-weight: bold;' });
+  var ren
+  var container = document.getElementById('admin_ranks_container_right');
+  container.innerHTML = '';
+  container.appendChild(editor.render());
+}
--- a/plugins/admin/UserRanks.php	Sat Jun 07 12:46:18 2008 -0400
+++ b/plugins/admin/UserRanks.php	Sat Jun 07 12:48:39 2008 -0400
@@ -24,7 +24,50 @@
     return;
   }
   
-  echo 'Hello world!';
+  // This should be a constant somewhere
+  $protected_ranks = array(
+      RANK_ID_MEMBER,
+      RANK_ID_MOD,
+      RANK_ID_ADMIN,
+      RANK_ID_GUEST
+    );
+  
+  if ( $paths->getParam(0) == 'action.json' )
+  {
+    // ajax call
+    return true;
+  }
+  
+  // draw initial interface
+  // yes, four paragraphs of introduction. Suck it up.
+  echo '<h3>' . $lang->get('acpur_heading_main') . '</h3>';
+  echo '<p>' . $lang->get('acpur_intro_para1') . '</p>';
+  echo '<p>' . $lang->get('acpur_intro_para2') . '</p>';
+  echo '<p>' . $lang->get('acpur_intro_para3') . '</p>';
+  echo '<p>' . $lang->get('acpur_intro_para4') . '</p>';
+  
+  // fetch ranks
+  $q = $db->sql_query('SELECT rank_id, rank_title, rank_style FROM ' . table_prefix . "ranks ORDER BY rank_title ASC;");
+  if ( !$q )
+    $db->_die();
+  
+  echo '<div class="rankadmin-left" id="admin_ranks_container_left">';
+  while ( $row = $db->fetchrow() )
+  {
+    // format rank according to what its users look like
+    // rank titles can be stored as language strings, so have the language manager fetch this
+    // normally it refetches (which takes time) if a string isn't found, but it won't try to fetch
+    // a string that isn't in the category_stringid format
+    $rank_title = $lang->get($row['rank_title']);
+    // FIXME: make sure htmlspecialchars() is escaping quotes and backslashes
+    echo '<a href="#rank_edit:' . $row['rank_id'] . '" onclick="ajaxInitRankEdit(' . $row['rank_id'] . '); return false;" class="rankadmin-editlink" style="' . htmlspecialchars($row['rank_style']) . '">' . htmlspecialchars($rank_title) . '</a> ';
+  }
+  echo '</div>';
+  
+  echo '<div class="rankadmin-right" id="admin_ranks_container_right">';
+  echo $lang->get('acpur_msg_select_rank');
+  echo '</div>';
+  echo '<span class="menuclear"></span>';
 }
 
 ?>