GN_ElementPriceLoader

Обновление цен на элементы

目前为 2015-11-21 提交的版本。查看 最新版本

// ==UserScript==
// @name        GN_ElementPriceLoader
// @namespace   Gradient
// @description Обновление цен на элементы
// @include     /.+(heroeswm|178\.248\.235\.15).+/
// @exclude     /.+(heroeswm|178\.248\.235\.15).*?\/(login|war|cgame|frames|chat|chatonline|ch_box|chat_line|ticker|chatpost)\.php.*/
// @exclude     /.+daily\.heroeswm\.ru.+/
// @version     1.0.3
// ==/UserScript==

"use strict";

//----------------------------------------------------------------------------//

(function(){ // wrapper start
  
//----------------------------------------------------------------------------//
// UnifiedLibrary 1.4.0 start
//----------------------------------------------------------------------------//

//----------------------------------------------------------------------------//
// SysUtils
//----------------------------------------------------------------------------//

var GN_SysUtils = new SysUtils();
var SU = GN_SysUtils;

//----------------------------------------------------------------------------//

function SysUtils(){  // wrapper start
  
//----------------------------------------------------------------------------//
  
this.show_error = function(error_string){
  throw new Error(error_string);
};

//----------------------------------------------------------------------------//  
 
this.save_value = function(desc, value){
  var div = document.getElementById('GN_GM_Handler');
  div.setAttribute('desc',      desc);
  div.setAttribute('value',     value);
  div.setAttribute('operation', 'save');
  
  div.click();
  
  if(div.getAttribute('state') != 'complete')
    this.show_error('Ошибка при сохранении значения');
};
  
//----------------------------------------------------------------------------//  

this.load_value = function(value, def){
  var div = document.getElementById('GN_GM_Handler');
  div.setAttribute('desc',      value);
  div.setAttribute('operation', 'load');
  
  div.click();
  
  if(div.getAttribute('state') != 'complete')
    this.show_error('Ошибка при загрузке значения');

  return (div.getAttribute('is_null') == 'true' ? def : div.getAttribute('value'));
};

//----------------------------------------------------------------------------//

this.check_login = function(){
  var re = /.*?pl_id=\d+?.*?/gmi;

  if(!re.test(document.cookie.toString()))
    this.show_error('Пользователь не авторизован');
};

//----------------------------------------------------------------------------//

this.check_login();

//----------------------------------------------------------------------------//  
  
} // wrapper end

//----------------------------------------------------------------------------//
// CommonValues
//----------------------------------------------------------------------------//

var GN_CommonValues = new CommonValues();

//----------------------------------------------------------------------------//

function CommonValues(){  // wrapper start

//----------------------------------------------------------------------------//
// Elements
//----------------------------------------------------------------------------//

this.elements = JSON.parse(SU.load_value('GN_CommonValues_Elements', '[]'));
    
//----------------------------------------------------------------------------//
  
} // wrapper end

//----------------------------------------------------------------------------//
// GUIController
//----------------------------------------------------------------------------//

var GN_GUIController = new GUIController();

//----------------------------------------------------------------------------//

function GUIController(){  // wrapper start
  
//----------------------------------------------------------------------------//
  
clear_flash_z_index();
  
//----------------------------------------------------------------------------//
  
this.script_name = function(){
  return 'GN_GUIController';
};
  
const script_name = this.script_name();

//----------------------------------------------------------------------------// 

this.registerObject = function(object){
  root_div = document.getElementById(root.div.id);
      
  if(!root_div)
    root_div = create_node(root, document.body);
  else{
    var custom = root_div.getAttribute('custom').split('|');
    root.div.top    = +custom[0];
    root.div.left   = +custom[1];
    root.div.width  = +custom[2];
    root.div.height = +custom[3];
  }
  
  object.div.left = root.div.left + left;
  object.div.top  = top;
  
  var childs = root_div.childNodes;
  
  for(var i = 0; i < childs.length; ++i)
    if(childs[i].nodeName.toLowerCase() == 'div'){
      var height = +childs[i].getAttribute('custom').split('|')[3];
      object.div.top += height;
    }
  
  create_node(object, root_div);
  align_childs(root_div);
  collapse_childs(root_div);
};

//----------------------------------------------------------------------------//
  
this.hide_all = function(){
  if(!root_div)
    return;
  
  var childs = root_div.childNodes;
  for(var i = 0; i < childs.length; ++i)
    if(childs[i].nodeName.toLowerCase() == 'div')
      childs[i].style.top = +childs[i].getAttribute('custom').split('|')[0];
  
  align_childs(root_div);
  collapse_childs(root_div);
};

var hide_all = this.hide_all;

//----------------------------------------------------------------------------//

const left = 10;
const top  = 10;
  
var root = {
  div: {
    id:     script_name + 'MainDiv',
    top:    top,
    left:   left,
    width:  0,
    height: 0
  },

  input: {
    id:    script_name + 'MainInput',
    value: 'Скрипты',
    title: 'Конфигурация и запуск скриптов, не относящихся к определенной странице' 
  },
  
  child_divs: []
};
  
var root_div = document.getElementById(root.div.id);
  
//----------------------------------------------------------------------------//
  
function create_node(object, parent){
  var div_ = div(object.div);
  div_.setAttribute('expanded', 'false');
  parent.appendChild(div_);
  
  set_div_style(object.div);
  
  var input_ = input(object.input);
  div_.appendChild(input_);
  
  set_input_style(object.input);
  
  object.div.left  += div_.clientWidth;
  object.div.width  = div_.clientWidth;
  object.div.height = div_.clientHeight;
  
  var custom = [ object.div.top, object.div.left, object.div.width, object.div.height ];
  div_.setAttribute('custom', custom.join('|'));
  
  if(object.child_divs.length || object.div.id == root.div.id){
    input_.addEventListener('click', function(){
      expand_childs(div_);
    });
    
    create_child_nodes(object, div_);
  }
  
  return div_;
}

//----------------------------------------------------------------------------//
  
function create_child_nodes(object, parent){
  var childs = object.child_divs;
  
  for(var i = 0; i < childs.length; ++i){
    var child = childs[i];
    child.div.top  = top;
    child.div.left = left;
    
    if(i){
      var total_height = 0;
      
      for(var j = 0; j < i; ++j){
        var sibling     = childs[j];
        var sibling_div = document.getElementById(sibling.div.id);
        
        total_height += sibling_div.clientHeight;
      }
 
      child.div.top += total_height;
    }
    
    child.div.left += object.div.left;
    
    create_node(child, parent);
  }  
}
  
//----------------------------------------------------------------------------//

function expand_childs(el){
  var now_expanded = (el.getAttribute('expanded') == 'true');
  
  if(now_expanded && el == root_div){
    hide_all();
    return;
  }
  
  var childs = el.childNodes;

  for(var i = 0; i < childs.length; ++i)
    if(childs[i].nodeName.toLowerCase() == 'div')
      childs[i].style.display = !now_expanded ? 'block' : 'none';
  
  if(now_expanded){
    collapse_childs(el);
    
    if(el.parentNode == root_div){
      childs = root_div.childNodes;

      for(i = 0; i < childs.length; ++i)
        if(childs[i].nodeName.toLowerCase() == 'div' && childs[i] != el)
          childs[i].style.display = 'block';

      el.style.top   = +el.getAttribute('custom').split('|')[0];
      el.style.width = +el.getAttribute('custom').split('|')[2];
      
      align_childs(root_div);
    }
  }
  
  if(!now_expanded && el.parentNode == root_div){
    childs = root_div.childNodes;
    
    for(i = 0; i < childs.length; ++i){
      if(childs[i].nodeName.toLowerCase() == 'div' && childs[i] != el)
        childs[i].style.display = 'none';
    }
    
    el.style.top   = top;
    el.style.width = +el.getAttribute('custom').split('|')[2];
  }
  
  el.setAttribute('expanded', now_expanded ? 'false' : 'true');
}
  
//----------------------------------------------------------------------------//
  
function align_childs(el){
  var max_width = 0;
  var childs = el.childNodes;
  
  for(var i = 0; i < childs.length; ++i)
    if(childs[i].nodeName.toLowerCase() == 'div'){
      var width = +childs[i].getAttribute('custom').split('|')[2];

      if(width >= max_width)
        max_width = width;
    }

  for(i = 0; i < childs.length; ++i)
    if(childs[i].nodeName.toLowerCase() == 'div')
      childs[i].style.width = max_width;
}
  
//----------------------------------------------------------------------------//
  
function collapse_childs(el){
  var divs = el.querySelectorAll('div');

  for(var i = 0; i < divs.length; ++i){  
    divs[i].setAttribute('expanded', 'false');
    divs[i].style.display = 'none';
  }  
  
  el.setAttribute('expanded', 'false');
}
  
//----------------------------------------------------------------------------//  

function div(object){
  var div = document.createElement('div');
  div.setAttribute('id', object.id);

  return div;
}
  
//----------------------------------------------------------------------------//  
  
function set_div_style(object){
  var div   = document.getElementById(object.id);
  var style = div.style;
  
  style.position = 'fixed';
  style.top      = object.top + 'px';
  style.left     = object.left + 'px';
  style.zIndex   = 100;
}
  
//----------------------------------------------------------------------------//  
  
function input(object){
  var input = document.createElement('input');
  input.type  = 'button';
  input.id    = object.id;
  input.value = object.value;
  input.title = object.title;
  
  return input;
}
  
//----------------------------------------------------------------------------//
  
function set_input_style(object){
  var input = document.getElementById(object.id);
  var style = input.style;
  
  style.display    = 'block';
  style.width      = '95%';
  style.border     = '1px solid rgb(153, 153, 153)';  
  style.padding    = '1px';
  style.margin     = '2px';
  style.background = 'none repeat scroll 0% 0% rgb(204, 204, 204)';
  style.fontSize   = '12px';
  style.cursor     = 'pointer';
  style.zIndex     = 100;
}
  
//----------------------------------------------------------------------------//
  
function clear_flash_z_index(){
  var objects = document.querySelectorAll('object');

  for(var i = 0; i < objects.length; ++i){
    var o = objects[i];
    var param = document.createElement('param');
    param.setAttribute('name', 'wmode');
    param.setAttribute('value', 'opaque');

    o.insertBefore(param, o.firstChild);
  }
}

//----------------------------------------------------------------------------//  
  
} // wrapper end

//----------------------------------------------------------------------------//
// UnifiedLibrary end
//----------------------------------------------------------------------------//
  
var CV = GN_CommonValues;
var elements = CV.elements;

var save_value = SU.save_value;
var load_value = SU.load_value;
var show_error = SU.show_error;
  
var script_name = 'ElementPriceLoader';
  
var GC = GN_GUIController;
GC.registerObject(    
  {
    div: { id: GC.script_name() + '_' + script_name + 'Div' }, 

    input: {
      id:    GC.script_name() + '_' + script_name + 'Input',
      value: 'Обновление цен элементов',
      title: 'Обновление цен элементов' 
    },

    child_divs: []
  } 
);
  
var start_button = document.getElementById(GC.script_name() + '_' + script_name + 'Input');
  
start_button.addEventListener('click', function(e){
  draw_div(document.body);
});

//----------------------------------------------------------------------------//
  
function draw_div(parent){
  var div = document.createElement('div');
  div.id = script_name + 'Div';
  div.style.position = 'fixed';
  div.style.display  = 'block';
  div.style.top  = start_button.parentNode.style.top;
  div.style.zIndex = 100;
  
  var left = /(\d+)px/.exec(start_button.parentNode.style.left);
  div.style.left = +left[1] + start_button.parentNode.clientWidth + 'px';
  div.style.width = '300px';
  div.style.background = start_button.style.backgroundColor;
  
  parent.appendChild(div);

  draw_content(div);
}
  
//----------------------------------------------------------------------------//
  
function draw_content(parent){
  var table = document.createElement('table');
  table.style.width  = '100%';
  table.style.border = 'medium none';  
  
  parent.appendChild(table);
  
  draw_header(table);
  
  elements.forEach(function(current){
    draw_row(table, current);
  });
  
  draw_buttons(table);
}
  
//----------------------------------------------------------------------------//
  
function draw_header(parent){
  var upd_date = JSON.parse(load_value(script_name + '_LastUpdate', '0'));
  if(upd_date)
    upd_date = new Date(Date.parse(upd_date));
  
  var tr = document.createElement('tr');
  parent.appendChild(tr);
  
  var td = document.createElement('td');
  td.setAttribute('colspan', '4');
  td.id = script_name + '_LastUpdate';
  td.textContent = 'Дата последнего обновления: ' + (upd_date ? upd_date.toLocaleString() : 'еще не считывалось');
  tr.appendChild(td);

  tr = document.createElement('tr');
  tr.setAttribute('bgColor', '#DCDCDC');
  parent.appendChild(tr);
  
  td = document.createElement('td');
  td.textContent = 'Наименование';
  tr.appendChild(td);
  
  td = document.createElement('td');
  td.textContent = 'Текущее значение';
  tr.appendChild(td);
  
  td = document.createElement('td');
  td.textContent = 'Новое значение';
  tr.appendChild(td);
  
  td = document.createElement('td');
  td.textContent = 'Разница';
  tr.appendChild(td);
}
  
//----------------------------------------------------------------------------//
  
function draw_row(parent, object_){
  var tr = document.createElement('tr');
  tr.id = object_.id;
  parent.appendChild(tr);
  
  var td = document.createElement('td');
  td.textContent = object_.name + ':';
  tr.appendChild(td);
  
  td = document.createElement('td');
  td.textContent = object_.average_price;
  tr.appendChild(td);
  
  td = document.createElement('td');
  var input = document.createElement('input');
  input.type        = 'text';
  input.style.width = 40;
  input.value       = object_.average_price;
  input.onkeypress  = number_input;
  input.addEventListener('input', function(e){
    show_difference(input);
  });
  td.appendChild(input);
  tr.appendChild(td);
  
  td = document.createElement('td');
  var font = document.createElement('font');
  font.color = 'black';
  font.textContent = 0;
  td.appendChild(font);
  tr.appendChild(td);
}
  
//----------------------------------------------------------------------------//
  
function draw_buttons(parent){
  var tr = document.createElement('tr');
  parent.appendChild(tr);
  
  var td = document.createElement('td');
  td.setAttribute('align', 'right');
  td.setAttribute('colspan', '4');
  tr.appendChild(td);
  
  var button = document.createElement('input');
  button.type = 'button';
  button.value = 'Применить';
  button.addEventListener('click', function(e){  
    save_prices();
  });
  td.appendChild(button);
  
  button = document.createElement('input');
  button.type = 'button';
  button.value = 'Обновить';
  button.addEventListener('click', function(e){  
    load_prices();
  });
  td.appendChild(button);
  
  button = document.createElement('input');
  button.type = 'button';
  button.value = 'Отмена';
  button.addEventListener('click', function(e){  
    remove_div();
  });
  td.appendChild(button);
}
  
//----------------------------------------------------------------------------//
  
function save_prices(){
  var errors = [];
  
  var div = document.getElementById(script_name + 'Div');
  var trs = div.querySelectorAll('table > tr[id]');

  for(var i = 0; i < trs.length; ++i){
    var input = trs[i].querySelector('input');
    if(isNaN(+input.value) || +input.value <= 0){
      errors.push('Цена элемента должна быть положительной');
      break;
    }
  }

  if(errors.length){
    alert('Ошибки при сохранении:\n\n' + errors.join('\n'));
    return;
  }  
  
  var el_prices = [];
  
  for(var i = 0; i < trs.length; ++i){
    var input = trs[i].querySelector('input');
    el_prices.push({ id: trs[i].id, price: input.value });
  }

  save_value('GN_CommonValues_ElementPrices', JSON.stringify(el_prices));
  
  document.location = document.location;
}
  
//----------------------------------------------------------------------------//
  
function load_prices(){
  document.body.style.cursor = 'wait';
  
  var xhr = new XMLHttpRequest();
  xhr.open('GET', '/auction.php?cat=elements&sort=0', true);
  xhr.overrideMimeType('text/plain; charset=windows-1251');
  xhr.onreadystatechange = function(){
    if(xhr.readyState == 4)
      if(xhr.status == 200){
        var objects = parse_page(xhr.response);
        objects = filter_objects(objects);

        var div = document.getElementById(script_name + 'Div');
        objects.forEach(function(current){
          var tr = div.querySelector('table > tr[id="' + current.id + '"]');

          if(tr){
            var input = tr.querySelector('input');
            input.value = Math.floor(current.sum/current.count);
            show_difference(input);
          }
        });
        
        var upd_date = new Date();
        var td = document.getElementById(script_name + '_LastUpdate');
        td.textContent = 'Дата последнего обновления: ' + upd_date.toLocaleString();
        
        save_value(script_name + '_LastUpdate', JSON.stringify(upd_date));
        
        document.body.style.cursor = 'default';
      }
  };

  xhr.send(null);  
}
  
//----------------------------------------------------------------------------//
  
function parse_page(response){  
  var all_objects = [];
  
  response = response.replace(/(\n(\r)?)/g, ' ');
  
  var re = /.*?(<tr bgcolor='#(?:ffffff|eeeeee)' class=wb>.+?gold.gif.+?show_button.+?<\/tr>).*?/gmi;
  var matches = [];
  
  while(matches = re.exec(response))
  {
    var el_re = /.+\/i\/(.+?)\.gif'.+?gold.gif.+?<td>([0-9,]+?)<\/td>.+?onclick=.+?/i;
    var el_matches = el_re.exec(matches[1]);

    if(!el_matches)
      show_error('Ошибка при парсинге ' + matches[1]);

    var object = {
      id:    el_matches[1],
      price: +(el_matches[2].replace(/,/g, '')),
      count: 1
    };

    var count_re = /.*<b>(\d+?) шт.<\/b>/i;
    var c_matches = count_re.exec(matches[1]);
      
    if(c_matches)
      object.count = +c_matches[1];

    all_objects.push(object);
  }
  
  return all_objects;
}
  
//----------------------------------------------------------------------------//
  
function filter_objects(objects){
  var el_objects = [];
  var step      = 1.1;
  var max_count = 45;

  objects.forEach(function(current){
    var el = get_object(current.id, el_objects);
    
    if(!el)
      el_objects.push({ id: current.id, max_price: current.price, sum: current.price*current.count, count: current.count });
    else{
      if(current.price >= el.max_price && current.price <= el.max_price*step)
        el.max_price = current.price;
      
      if(current.price <= el.max_price*step && el.count < max_count){
        el.count += current.count;
        el.sum += current.price*current.count;
      }
    }
  });
  
  return el_objects;
}
  
//----------------------------------------------------------------------------//
  
function show_difference(input){
  var diff = +input.parentNode.previousSibling.textContent - +input.value;
  
  var font = input.parentNode.nextSibling.firstChild;
  font.color = diff == 0 ? 'black' : diff > 0 ? 'green' : 'red';
  font.textContent = diff; 
}
  
//----------------------------------------------------------------------------//
  
function get_object(id, array_){
  for(var i = 0; i < array_.length; ++i)
    if(array_[i].id == id)
      return array_[i];

  return null;
}
  
//----------------------------------------------------------------------------//
  
function remove_div(){
  var div = document.getElementById(script_name + 'Div');
  div.parentNode.removeChild(div);
}
  
//----------------------------------------------------------------------------//
  
function get_char(e) {
  if(e.which && e.charCode){
    if(e.which < 32) 
      return null;
    
    return String.fromCharCode(e.which)
  }

  return null;
}
  
//----------------------------------------------------------------------------//
  
function number_input(e){
  if(e.ctrlKey || e.altKey || e.metaKey) 
    return false;
  
  var chr = get_char(e);

  return chr == null || (chr >= '0' && chr <= '9');
}
  
//----------------------------------------------------------------------------//
  
}());  // wrapper end

//----------------------------------------------------------------------------//