includes/clientside/static/theme-manager.js
author Dan
Sat, 03 Jan 2009 18:11:18 -0500
changeset 800 9cdfe82c56cd
parent 699 c7d737202d59
child 823 4596c40aaa94
permissions -rw-r--r--
Major underlying changes to namespace handling. Each namespace is handled by its own class which extends Namespace_Default. Much greater customization/pluggability potential, at the possible expense of some code reusing (though code reusing has been avoided thus far). Also a bit better handling of page passwords [SECURITY].

function ajaxToggleSystemThemes()
{
  var theme_list = document.getElementById('theme_list_edit');
  var mode = ( theme_list.sys_shown ) ? 'hide' : 'show';
  for ( var i = 0; i < theme_list.childNodes.length; i++ )
  {
    var child = theme_list.childNodes[i];
    if ( child.tagName == 'DIV' )
    {
      if ( $dynano(child).hasClass('themebutton_theme_system') )
      {
        if ( $dynano(child).hasClass('themebutton_theme_disabled') )
        {
          $dynano(child).rmClass('themebutton_theme_disabled')
        }
        if ( mode == 'show' )
        {
          domObjChangeOpac(0, child);
          child.style.display = 'block';
          domOpacity(child, 0, 100, 1000);
        }
        else
        {
          domOpacity(child, 100, 0, 1000);
          setTimeout("document.getElementById('" + child.id + "').style.display = 'none';", 1050);
        }
      }
    }
  }
  theme_list.sys_shown = ( mode == 'show' );
  document.getElementById('systheme_toggler').innerHTML = ( mode == 'hide' ) ? $lang.get('acptm_btn_system_themes_show') : $lang.get('acptm_btn_system_themes_hide');
}

function ajaxInstallTheme(theme_id)
{
  var thediv = document.getElementById('themebtn_install_' + theme_id);
  if ( !thediv )
    return false;
  thediv.removeChild(thediv.getElementsByTagName('a')[0]);
  var status = document.createElement('div');
  status.className = 'status';
  thediv.appendChild(status);
  
  var req = toJSONString({
      mode: 'install',
      theme_id: theme_id
    });
  // we've finished nukeing the existing interface, request editor data
  ajaxPost(makeUrlNS('Admin', 'ThemeManager/action.json'), 'r=' + ajaxEscape(req), function()
    {
      if ( ajax.readyState == 4 && ajax.status == 200 )
      {
        var response = String(ajax.responseText + '');
        if ( response.substr(0, 1) == '{' )
        {
          response = parseJSON(response);
          if ( response.mode == 'error' )
          {
            alert(response.error);
            return false;
          }
        }
        
        var theme_list = document.getElementById('theme_list_edit');
  
        var btn = document.createElement('div');
        btn.className = 'themebutton';
        btn.style.backgroundImage = thediv.style.backgroundImage;
        btn.id = 'themebtn_edit_' + theme_id;
        
        var a = document.createElement('a');
        a.className = 'tb-inner';
        a.appendChild(document.createTextNode($lang.get('acptm_btn_theme_edit')));
        a.appendChild(document.createTextNode("\n"));
        a.theme_id = theme_id;
        a.onclick = function()
        {
          ajaxEditTheme(this.theme_id);
          return false;
        }
        a.href = '#';
        var span = document.createElement('span');
        span.className = 'themename';
        span.appendChild(document.createTextNode(thediv.getAttribute('enano:themename')));
        a.appendChild(span);
        btn.appendChild(a);
        btn.setAttribute('enano:themename', thediv.getAttribute('enano:themename'));
        theme_list.appendChild(btn);
        
        thediv.parentNode.removeChild(thediv);
      }
    });
}

function ajaxEditTheme(theme_id)
{
  // Fade out and subsequently destroy the entire list, then make an
  // ajax request to the theme manager for the theme info via JSON
  var theme_list = document.getElementById('theme_list_edit').parentNode;
  var backgroundImage = document.getElementById('themebtn_edit_' + theme_id).style.backgroundImage;
  /*
  for ( var i = 0; i < theme_list.childNodes.length; i++ )
  {
    var el = theme_list.childNodes[i];
    if ( el.tagName )
      domOpacity(el, 100, 0, 1000);
  }
  */
  var thediv = document.getElementById('themebtn_edit_' + theme_id);
  if ( !thediv )
    return false;
  thediv.removeChild(thediv.getElementsByTagName('a')[0]);
  var status = document.createElement('div');
  status.className = 'status';
  thediv.appendChild(status);
  
  setTimeout(function()
    {
      var req = toJSONString({
          mode: 'fetch_theme',
          theme_id: theme_id
        });
      // we've finished nukeing the existing interface, request editor data
      ajaxPost(makeUrlNS('Admin', 'ThemeManager/action.json'), 'r=' + ajaxEscape(req), function()
        {
          if ( ajax.readyState == 4 && ajax.status == 200 )
          {
            theme_list.innerHTML = '';
            var response = String(ajax.responseText + '');
            if ( !check_json_response(response) )
            {
              alert(response);
              return false;
            }
            response = parseJSON(response);
            if ( response.mode == 'error' )
            {
              alert(response.error);
              return false;
            }
            response.background_image = backgroundImage;
            ajaxBuildThemeEditor(response, theme_list);
          }
        });
    }, 200);
}

function ajaxBuildThemeEditor(data, target)
{
  // Build the theme editor interface
  // Init opacity
  domObjChangeOpac(0, target);
  
  // Theme preview
  var preview = document.createElement('div');
  preview.style.border = '1px solid #F0F0F0';
  preview.style.padding = '5px';
  preview.style.width = '216px';
  preview.style.height = '150px';
  preview.style.backgroundImage = data.background_image;
  preview.style.backgroundRepeat = 'no-repeat';
  preview.style.backgroundPosition = 'center center';
  preview.style.cssFloat = 'right';
  preview.style.styleFloat = 'right';
  
  target.appendChild(preview);
  
  // Heading
  var h3 = document.createElement('h3');
  h3.appendChild(document.createTextNode($lang.get('acptm_heading_theme_edit', { theme_name: data.theme_name })));
  target.appendChild(h3);
  
  // Field: Theme name
  var l_name = document.createElement('label');
  l_name.appendChild(document.createTextNode($lang.get('acptm_field_theme_name') + ' '));
  var f_name = document.createElement('input');
  f_name.type = 'text';
  f_name.id = 'themeed_field_name';
  f_name.value = data.theme_name;
  f_name.size = '40';
  l_name.appendChild(f_name);
  target.appendChild(l_name);
  
  target.appendChild(document.createElement('br'));
  target.appendChild(document.createElement('br'));
  
  // Field: default style
  var l_style = document.createElement('label');
  l_style.appendChild(document.createTextNode($lang.get('acptm_field_default_style') + ' '));
  var f_style = document.createElement('select');
  f_style.id = 'themeed_field_style';
  var opts = [];
  for ( var i = 0; i < data.css.length; i++ )
  {
    if ( data.css[i] == '_printable' )
      continue;
    
    opts[i] = document.createElement('option');
    opts[i].value = data.css[i];
    opts[i].appendChild(document.createTextNode(data.css[i]));
    if ( data.default_style == data.css[i] )
    {
      opts[i].selected = true;
    }
    f_style.appendChild(opts[i]);
  }
  l_style.appendChild(f_style);
  target.appendChild(l_style);
  
  target.appendChild(document.createElement('br'));
  target.appendChild(document.createElement('br'));
  
  // Default theme
  target.appendChild(document.createTextNode($lang.get('acptm_field_default_theme') + ' '));
  if ( data.is_default )
  {
    var l_default = document.createElement('b');
    l_default.appendChild(document.createTextNode($lang.get('acptm_field_default_msg_current')));
  }
  else
  {
    var l_default = document.createElement('label');
    var f_default = document.createElement('input');
    f_default.type = 'checkbox';
    f_default.id = 'themeed_field_default';
    l_default.appendChild(f_default);
    l_default.appendChild(document.createTextNode($lang.get('acptm_field_default_btn_make_default')));
  }
  target.appendChild(l_default);
  
  target.appendChild(document.createElement('br'));
  target.appendChild(document.createElement('br'));
  
  // Disable theme
  var disable_span = document.createElement('span');
  disable_span.appendChild(document.createTextNode($lang.get('acptm_field_disable_title') + ' '));
  target.appendChild(disable_span);
  var l_disable = document.createElement('label');
  var f_disable = document.createElement('input');
  f_disable.type = 'checkbox';
  f_disable.id = 'themeed_field_disable';
  if ( !data.enabled )
    f_disable.setAttribute('checked', 'checked');
  l_disable.style.fontWeight = 'bold';
  l_disable.appendChild(f_disable);
  l_disable.appendChild(document.createTextNode($lang.get('acptm_field_disable')));
  target.appendChild(l_disable);
  
  // Availability policy
  var h3 = document.createElement('h3');
  h3.appendChild(document.createTextNode($lang.get('acptm_heading_theme_groups')));
  target.appendChild(h3);
  
  // Label for the whole field
  var p_d_policy = document.createElement('p');
  p_d_policy.style.fontWeight = 'bold';
  p_d_policy.appendChild(document.createTextNode($lang.get('acptm_field_policy')));
  target.appendChild(p_d_policy);
  
  // Wrapper for options
  var p_f_policy = document.createElement('p');
  
  // Option: allow all
  var l_policy_allow_all = document.createElement('label');
  var f_policy_allow_all = document.createElement('input');
  f_policy_allow_all.type = 'radio';
  f_policy_allow_all.id = 'themeed_field_policy_allow_all';
  f_policy_allow_all.name = 'themeed_field_policy';
  f_policy_allow_all.value = 'allow_all';
  l_policy_allow_all.appendChild(f_policy_allow_all);
  l_policy_allow_all.appendChild(document.createTextNode(' ' + $lang.get('acptm_field_policy_allow_all')));
  if ( data.group_policy == 'allow_all' )
  {
    f_policy_allow_all.setAttribute('checked', 'checked');
  }
  
  // Option: whitelist
  var l_policy_whitelist = document.createElement('label');
  var f_policy_whitelist = document.createElement('input');
  f_policy_whitelist.type = 'radio';
  f_policy_whitelist.id = 'themeed_field_policy_whitelist';
  f_policy_whitelist.name = 'themeed_field_policy';
  f_policy_whitelist.value = 'whitelist';
  l_policy_whitelist.appendChild(f_policy_whitelist);
  l_policy_whitelist.appendChild(document.createTextNode(' ' + $lang.get('acptm_field_policy_whitelist')));
  if ( data.group_policy == 'whitelist' )
  {
    f_policy_whitelist.setAttribute('checked', 'checked');
  }
  
  // Option: blacklist
  var l_policy_blacklist = document.createElement('label');
  var f_policy_blacklist = document.createElement('input');
  f_policy_blacklist.type = 'radio';
  f_policy_blacklist.id = 'themeed_field_policy_blacklist';
  f_policy_blacklist.name = 'themeed_field_policy';
  f_policy_blacklist.value = 'blacklist';
  l_policy_blacklist.appendChild(f_policy_blacklist);
  l_policy_blacklist.appendChild(document.createTextNode(' ' + $lang.get('acptm_field_policy_blacklist')));
  if ( data.group_policy == 'blacklist' )
  {
    f_policy_blacklist.setAttribute('checked', 'checked');
  }
  f_policy_allow_all.onclick = ajaxThemeManagerHandlePolicyClick;
  f_policy_whitelist.onclick = ajaxThemeManagerHandlePolicyClick;
  f_policy_blacklist.onclick = ajaxThemeManagerHandlePolicyClick;
  
  p_f_policy.appendChild(l_policy_allow_all);
  p_f_policy.appendChild(document.createElement('br'));
  p_f_policy.appendChild(l_policy_whitelist);
  p_f_policy.appendChild(document.createElement('br'));
  p_f_policy.appendChild(l_policy_blacklist);
  
  target.appendChild(p_d_policy);
  target.appendChild(p_f_policy);
  
  var div_acl = document.createElement('div');
  div_acl.id = 'themeed_acl_box';
  div_acl.style.margin = '0 0 10px 30px';
  
  var h3_g = document.createElement('h3');
  h3_g.appendChild(document.createTextNode($lang.get('acptm_field_acl_heading_groups')));
  div_acl.appendChild(h3_g);
  
  var div_groups = document.createElement('div');
  div_groups.style.border = '1px solid #E8E8E8';
  div_groups.id = 'themeed_group_list';
  
  // Group list
  for ( var i in data.group_names )
  {
    var g_name = data.group_names[i];
    var check = document.createElement('input');
    check.type = 'checkbox';
    if ( in_array("g:" + i, data.group_list) )
    {
      check.setAttribute('checked', 'checked');
    }
    check.group_id = parseInt(i);
    var lbl_g_acl = document.createElement('label');
    lbl_g_acl.appendChild(check);
    var str = 'groupcp_grp_' + g_name.toLowerCase();
    var g_name_l10n = ( $lang.get(str) != str ) ? $lang.get(str) : g_name;
    lbl_g_acl.appendChild(document.createTextNode(g_name_l10n));
    div_groups.appendChild(lbl_g_acl);
    div_groups.appendChild(document.createElement('br'));
  }
  div_acl.appendChild(div_groups);
  
  var h3_u = document.createElement('h3');
  h3_u.appendChild(document.createTextNode($lang.get('acptm_field_acl_heading_users')));
  div_acl.appendChild(h3_u);
  
  // User addition field
  var frm = document.createElement('form');
  frm.action = 'javascript:ajaxThemeManagerHandleUserAdd();';
  frm.appendChild(document.createTextNode($lang.get('acptm_field_acl_add_user')));
  var f_useradd = document.createElement('input');
  f_useradd.type = 'text';
  f_useradd.id = 'themeed_field_adduser';
  f_useradd.onkeyup = function(e)
  {
    new AutofillUsername(this, e, false);
  }
  
  frm.appendChild(f_useradd);
  div_acl.appendChild(frm);
  
  div_acl.appendChild(document.createElement('br'));
  
  // User list
  var div_users = document.createElement('div');
  div_users.style.border = '1px solid #E8E8E8';
  div_users.style.padding = '4px';
  div_users.id = 'themeed_user_list';
  for ( var i = 0; i < data.group_list.length; i++ )
  {
    var id = data.group_list[i];
    if ( id.substr(0, 2) != 'u:' )
      continue;
    var uid = id.substr(2);
    var username = data.usernames[uid];
    
    var useritem = document.createElement('span');
    useritem.appendChild(document.createTextNode(username + ' '));
    useritem.userid = parseInt(uid);
    var deleter = document.createElement('a');
    deleter.href = '#';
    deleter.onclick = function()
    {
      ajaxThemeManagerHandleUserRemoval(this);
      return false;
    }
    deleter.appendChild(document.createTextNode('[X]'));
    useritem.appendChild(deleter);
    div_users.appendChild(useritem);
    div_users.appendChild(document.createElement('br'));
  }
  div_acl.appendChild(div_users);
  
  target.appendChild(div_acl);
  
  ajaxThemeManagerHandlePolicyClick();
  
  var clearer = document.createElement('span');
  clearer.className = 'menuclear';
  target.appendChild(clearer);
  
  // Theme ID
  var tid = document.createElement('input');
  tid.type = 'hidden';
  tid.id = 'themeed_theme_id';
  tid.value = data.theme_id;
  target.appendChild(tid);
  
  // Save button
  var raquo = unescape('%BB');
  var savebtn = document.createElement('input');
  savebtn.type = 'button';
  savebtn.style.fontWeight = 'bold';
  savebtn.value = $lang.get('etc_save_changes') + ' ' + raquo;
  savebtn.onclick = function()
  {
    ajaxThemeManagerHandleSaveRequest();
  }
  target.appendChild(savebtn);
  
  target.appendChild(document.createTextNode(' '));
  
  // Cancel button
  var savebtn = document.createElement('input');
  savebtn.type = 'button';
  savebtn.value = $lang.get('etc_cancel');
  savebtn.onclick = function()
  {
    ajaxPage(namespace_list['Admin'] + 'ThemeManager');
  }
  target.appendChild(savebtn);
  
  target.appendChild(document.createTextNode(' '));
  
  // Uninstall button
  var savebtn = document.createElement('input');
  savebtn.type = 'button';
  savebtn.value = $lang.get('acptm_btn_uninstall_theme');
  savebtn.style.color = '#D84308';
  savebtn.onclick = function()
  {
    if ( !confirm($lang.get('acptm_msg_uninstall_confirm')) )
      return false;
    ajaxThemeManagerHandleUninstallClick();
  }
  target.appendChild(savebtn);
  
  // Fade it all in
  domOpacity(target, 0, 100, 500);
  f_name.focus();
}

function ajaxThemeManagerHandlePolicyClick()
{
  if ( document.getElementById('themeed_field_policy_allow_all').checked )
  {
    document.getElementById('themeed_acl_box').style.display = 'none';
  }
  else if ( document.getElementById('themeed_field_policy_whitelist').checked || document.getElementById('themeed_field_policy_blacklist').checked )
  {
    document.getElementById('themeed_acl_box').style.display = 'block';
  }
}

function ajaxThemeManagerHandleUserAdd()
{
  var f_useradd = document.getElementById('themeed_field_adduser');
  f_useradd.setAttribute('disabled', 'disabled');
  var parent = f_useradd.parentNode;
  var img = document.createElement('img');
  img.src = ajax_load_icon;
  img.id = 'themeed_useradd_status';
  img.style.marginLeft = '10px';
  insertAfter(parent, img, f_useradd);
  
  var req = toJSONString({
      mode: 'uid_lookup',
      username: f_useradd.value
    });
  ajaxPost(makeUrlNS('Admin', 'ThemeManager/action.json'), 'r=' + ajaxEscape(req), function()
    {
      if ( ajax.readyState == 4 && ajax.status == 200 )
      {
        var img = document.getElementById('themeed_useradd_status');
        var f_useradd = document.getElementById('themeed_field_adduser');
        
        f_useradd.disabled = null;
        img.parentNode.removeChild(img);
        
        // process response
        var response = String(ajax.responseText + '');
        if ( !check_json_response(response) )
        {
          alert(response);
          return false;
        }
        response = parseJSON(response);
        if ( response.mode == 'error' )
        {
          alert(response.error);
          return false;
        }
            
        var uid = parseInt(response.uid);
        var username = response.username;
        
        // Loop through the list of users and remove any existing ones with the same uid
        var div_users = document.getElementById('themeed_user_list');
        var children = div_users.getElementsByTagName('span');
        for ( var i = 0; i < children.length; i++ )
        {
          var child = children[i];
          if ( child.userid == uid )
          {
            // the sister is the br element next to the span with the checkbox/text
            var sister = child.nextSibling;
            div_users.removeChild(child);
            div_users.removeChild(sister);
            break;
          }
        }
        
        var useritem = document.createElement('span');
        useritem.appendChild(document.createTextNode(username + ' '));
        useritem.userid = parseInt(uid);
        var deleter = document.createElement('a');
        deleter.href = '#';
        deleter.onclick = function()
        {
          ajaxThemeManagerHandleUserRemoval(this);
          return false;
        }
        deleter.appendChild(document.createTextNode('[X]'));
        useritem.appendChild(deleter);
        div_users.appendChild(useritem);
        div_users.appendChild(document.createElement('br'));
      }
    });
}

function ajaxThemeManagerHandleUserRemoval(el)
{
  var parent = el.parentNode;
  var uid = parent.userid;
  
  var grandparent = parent.parentNode;
  var sister = parent.nextSibling;
  grandparent.removeChild(parent);
  grandparent.removeChild(sister);
}

function ajaxThemeManagerHandleSaveRequest()
{
  // Build a JSON condensed request
  var md = false;
  if ( document.getElementById('themeed_field_default') )
  {
    if ( document.getElementById('themeed_field_default').checked )
    {
      md = true;
    }
  }
  var policy = 'allow_all';
  if ( document.getElementById('themeed_field_policy_whitelist').checked )
    policy = 'whitelist';
  else if ( document.getElementById('themeed_field_policy_blacklist').checked )
    policy = 'blacklist';
  var json_packet = {
    theme_id: document.getElementById('themeed_theme_id').value,
    theme_name: document.getElementById('themeed_field_name').value,
    default_style: document.getElementById('themeed_field_style').value,
    make_default: md,
    group_policy: policy,
    enabled: ( document.getElementById('themeed_field_disable').checked ? false : true )
  };
  var acl_list = [];
  var checks = document.getElementById('themeed_group_list').getElementsByTagName('input');
  for ( var i = 0; i < checks.length; i++ )
  {
    if ( checks[i].checked )
      acl_list.push('g:' + checks[i].group_id);
  }
  var spans = document.getElementById('themeed_user_list').getElementsByTagName('span');
  for ( var i = 0; i < spans.length; i++ )
  {
    if ( spans[i].userid )
      acl_list.push('u:' + spans[i].userid);
  }
  json_packet.group_list = acl_list;
  
  var json_send = {
    mode: 'save_theme',
    theme_data: json_packet
  };
  
  json_send = ajaxEscape(toJSONString(json_send));
  
  // Request the save
  var parent = document.getElementById('ajaxPageContainer');
  ajaxPost(makeUrlNS('Admin', 'ThemeManager/action.json'), 'r=' + json_send, function()
    {
      if ( ajax.readyState == 4 && ajax.status == 200 )
      {
        // process response
        var response = String(ajax.responseText + '');
        if ( !check_json_response(response) )
        {
          // For this we actually *expect* an HTML response.
          parent.innerHTML = response;
          return false;
        }
        response = parseJSON(response);
        if ( response.mode == 'error' )
        {
          alert(response.error);
          return false;
        }
      }
    });
}

function ajaxThemeManagerHandleUninstallClick()
{
  var theme_id = document.getElementById('themeed_theme_id').value;
  var json_send = {
    mode: 'uninstall',
    theme_id: theme_id
  };
  
  json_send = ajaxEscape(toJSONString(json_send));
  
  // Request the action
  var parent = document.getElementById('ajaxPageContainer');
  ajaxPost(makeUrlNS('Admin', 'ThemeManager/action.json'), 'r=' + json_send, function()
    {
      if ( ajax.readyState == 4 && ajax.status == 200 )
      {
        // process response
        var response = String(ajax.responseText + '');
        if ( !check_json_response(response) )
        {
          // For this we actually *expect* an HTML response.
          parent.innerHTML = response;
          return false;
        }
        response = parseJSON(response);
        if ( response.mode == 'error' )
        {
          alert(response.error);
          return false;
        }
      }
    });
}