вторник, 7 мая 2013 г.

Динамическое обновление контента

Выкладываю свои наработки в этом направлении, ибо незачем добру пропадать
Или не добру
Вам виднее

Что конкретно делают нижеследующие скрипты? Перехватывают нажатие на ссылки, блокируя дефолтную загрузку страницы, вместо чего вызывается заданная пользователем функция, которая может грузить через аякс какую-то инфу Еще перехватываются нажатия на кнопки "назад-вперед" в браузере, т е сохраняется полноценная история просмотров, по которой можно переходить
На практике это выглядит вот так
Вот скрипт, отвечающий за историю (добавление/удаление значений в адресной строке):
function updateAnalytics(){
 $("#google_analytics").html("<script type='text/javascript'>"+
 "var _gaq = _gaq || [];"+
 "_gaq.push(['_setAccount', 'UA-39346755-1']);"+
 "_gaq.push(['_trackPageview']);"+
 "(function() {"+
  "var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;"+
  "ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';"+
  "var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);"+
 "})();</script>");
}
function _get_url_vars(string){
 var vars = [], hash;
 var hashes;
 if (string){hashes = string.slice(string.indexOf('?') + 1).split('&');}
    else {  hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');}
    for(var i = 0; i < hashes.length; i++)
    {
   if(hashes[i] == window.location){return vars;}
      else {
  hash = hashes[i].split('=');
        vars.push(hash[0]);
        vars[hash[0]] = hash[1];
   }
    }
    return vars;
}
function getUrlVar(name, string){
 if (string){return (_get_url_vars(string))[name];}
    else {return _url_vars[name];}
}
function getPrewUrlVar(name){
 return prew_url_vars[name];
}
var _url_vars = [];//тут храним массив переменных из адресной строки {имя->значение}
var prew_url_vars = [];
var tmp_prew_url_vars = [];
$(function (e) {//обновляем актуальность вышеопределенной переменной, при загрузке страницы и при нажатии по кнопочках "назад"/"вперед" в браузере
 $( window ).bind( "popstate", function( e ) {
   //var returnLocation = history.location || document.location;
   prew_url_vars = _copy_url_vars(_url_vars);
   _url_vars = _get_url_vars();
   _upd_url_vars();
   updbg();
   updateAnalytics();
    }); 
 _url_vars = _get_url_vars();
 _upd_url_vars();
 updbg();
 updateAnalytics();
});
var _urlvars_ = "?";//тут храним уже готовую строку с переменными, которую можно уже использовать
function addUrlVar(var_name, var_val){//доюавление переменной
 for (var i=0; i < _url_vars.length; i++){//если переменная с таким именем уже есть, то заменяем
  if (_url_vars[i] == var_name){delete _url_vars[_url_vars[i]]; _url_vars.splice(i, 1);}
 }
 _url_vars.push(var_name);
 _url_vars[var_name] = var_val;
 _upd_url_vars();
}
function removeUrlVar(var_name){//удаление переменной
 for (var i=0; i < _url_vars.length; i++){//удаляем уже существующую переменную с таким же именем, если она есть
  if (_url_vars[i] == var_name){delete _url_vars[_url_vars[i]]; _url_vars.splice(i, 1);}
 }
 _upd_url_vars();
}
function _copy_url_vars(o) {
 var r = [];
 for (var i=0; i < o.length; i++){
  r.push(o[i]);
     r[o[i]] = o[o[i]];
 }
 return r;
}
function updateUrl(){//обновляем историю, впихнув в нее нашу сгенерированную строку "_urlvars_"
 var sm = true;
 if (_url_vars.length == prew_url_vars.length && _url_vars.length > 0){
  for (var i=0; i < _url_vars.length && i < prew_url_vars.length; i++){
   if ((_url_vars[i] != tmp_prew_url_vars[i]) || (_url_vars[_url_vars[i]] != tmp_prew_url_vars[tmp_prew_url_vars[i]])){
    sm = false; break;
   }
  }
 }
 else {sm = false;}
 if (sm == true){return;}
 delete prew_url_vars;
 prew_url_vars = _copy_url_vars(tmp_prew_url_vars);
 tmp_prew_url_vars = _copy_url_vars(_url_vars)
 history.pushState( null, null, _urlvars_ );
 updbg();
 updateAnalytics();
}
function _upd_url_vars(){//собсно, основываясь на переменной "_url_vars", генерируем строку "_urlvars_" для вставки в историю
 _urlvars_ = "?";
 _url_vars.sort();
 for (var i=0; i < _url_vars.length; i++){
  if (i != 0){_urlvars_ = _urlvars_ + "&";}
  _urlvars_ = _urlvars_ + _url_vars[i] + "=" + _url_vars[_url_vars[i]];
 }
}

function updbg(){
 $("#debuginfo").html("");
 var test = "Prew: ";
 for (var i=0; i < prew_url_vars.length; i++){
  test += prew_url_vars[i] + "=" + prew_url_vars[prew_url_vars[i]]+", ";
 }
 addbg(test);
 test = "Cur: ";
 for (var i=0; i < _url_vars.length; i++){
  test += _url_vars[i] + "=" + _url_vars[_url_vars[i]]+", ";
 }
 addbg(test);
}

function addbg(inf){
 $("#debuginfo").append(inf+"<br>");
}
 

Как пользоваться:

addUrlVar("имя_переменной", значение );//добавляем переменную
updateUrl();//обновляем историю/адресную строку
Адресная строка станет из "example.ru" -> "example.ru?имя_переменной=значение"

removeUrlVar("имя_переменной");//удаление переменной
getUrlVar("имя_переменной", "строка");
//добываем текущее значение переменной, 
//и если второй параметр указан - переменная ищется не в адресной строке, 
//а во втором параметре (использую для поиска переменной в ссылках)
getPrewUrlVar("имя_переменной");//добываем предыдущее значение переменной
Отладочная инфа выводится в div с идентификатором "debuginfo", можете создать его где угодно с какими угодно стилями
Следующий скрипт отвечает за реестр и обработку переменных
//----------------------------------------------------------------------------com
var update_com = [];
function regUpdateCom(params, _com){
 _com.params = params;
 update_com[update_com.length] = _com;
}
var _com_at_start = true;
$(function (e) {
 $( window ).bind( "popstate", function( e ) {
   pageUpdate();
    }); 
 pageUpdate();
 $("body").on("click", "a", function(event){
  var o;
  var param_count, pv, cv, sm, param, val, pval;
  var href = $(this).attr('href').slice(0, $(this).attr('href').indexOf('?'));
  for (var i = 0; i < update_com.length && (href == window.location || href == '/'); i++){
   param_count = update_com[i].params.length;
   var res = [];
   pv = 0, cv = 0, sm = 0;
   //var test = "";
   for (var p = 0; p < param_count; p++){
    //test+="\n ";
    param = update_com[i].params[p];
    val = getUrlVar(param, $(this).attr("href"));
    //alert(param+"="+_url_vars[param]+", ");
    pval = getUrlVar(param);
    if (pval){pv++;}
    res.push(param);
    if (val){cv++; res[param] = val; addUrlVar(param, val);}else{res[param] = pval;}
    //var tsm = "is not sm";
    if (val == pval || (pval && !val)){
     sm++; 
     //tsm = "is sm";
    }
    //test+="param: "+param+", prew: "+pval+", cur: "+val+", "+tsm+", ";
   }
   if (pv == 0 && cv){
    if (update_com[i].on_open){update_com[i].on_open(res);}
    else {update_com[i].on_update(res);}
    updateUrl(); 
    //test+="\n todo: open"; alert (test); 
    o=1; continue;}
   else if (pv && cv && sm < param_count){
    update_com[i].on_update(res); 
    updateUrl(); 
    //test+="\n todo: update"; alert (test); 
    o=1; continue;}
   else if (pv && cv){
    //test+="\n todo: none"; alert (test); 
    o=1; continue;}
  }
  if(o){return false;}
 });
});
function pageUpdate(){
 addbg("<br>page update:");
 var test, tsm, param_count, pv, cv, sm, param, val, pval;
 for (var i = 0; i < update_com.length; i++){
  test = "";
  param_count = update_com[i].params.length;
  var res = [];
  pv = 0, cv = 0, sm = 0;
  for (var p = 0; p < param_count; p++){
   test+="\n ";
   param = update_com[i].params[p];
   pval = getPrewUrlVar(param);
   val = getUrlVar(param);
   if (pval){pv++;}
   if (val){cv++; res.push(param); res[param] = val;}
   tsm = "is not sm";
   if (val == pval){sm++;tsm = "is sm";}
   test+="param: "+param+", prew: "+pval+", cur: "+val+", "+tsm+", ";
  }
  //open | update
  if (pv == 0 && cv){
   if (update_com[i].on_truestart && _com_at_start){update_com[i].on_truestart(res);addbg(test+"on_truestart"+", (pv==0 && cv)");}
   else if (update_com[i].on_open){update_com[i].on_open(res);addbg(test+"on_open"+", (pv==0 && cv)");}
   else{update_com[i].on_update(res);addbg(test+"on_update"+", (pv==0 && cv)");}
  }
  //update
  else if (pv && cv && sm < param_count){update_com[i].on_update(res);addbg(test+"on_update" +", (pv && cv && sm < param_count)");}
  //close | update
  else if (pv && cv == 0){
   if (update_com[i].on_close){update_com[i].on_close();addbg(test+"on_close"+", (pv && cv == 0)");}
   else{update_com[i].on_update(res);addbg(test+"on_update"+", (pv && cv == 0)");}
  }
  //same
  else if (pv && cv && sm == param_count){
   if (update_com[i].on_same){update_com[i].on_same();addbg(test+"on_same"+", (pv && cv && sm == param_count)");}
  }
  //disabled | falsestart
  else if (pv == 0 && cv == 0){
   if (update_com[i].on_falsestart && _com_at_start){update_com[i].on_falsestart();addbg(test+"on_falsestart"+", (pv == 0 && cv == 0)");}
   else if (update_com[i].on_disabled){update_com[i].on_disabled();addbg(test+"on_disabled"+", (pv == 0 && cv == 0)");}
  }
 }
 _com_at_start = false;
}
Пример использования:
regUpdateCom(["имя_переменной"], {//регистрируем наш параметр, и с этого момента все клики по ссылках, содержащие его, будут обрабатываться заданными ниже вашими обработчиками
 //можно регистрировать более одного параметра подрят, с помощью такой записи "["имя_переменной1", "имя_переменной2"]"
 on_update:function(val){//on_update - эта функция вызывается при каждом обновлении адресной строки, будь то это переход по ссылке, или же нажатии на кнопку "назад" в браузере
  //val - массив, содержащий в себе все переменные из адресной строки и их текущие значения
  UpdateContent(val.имя_переменной);//ваша функция, и она очень хорошо умеет загружать данные через аякс :З 

                //val.имя_переменной - тут мы получаем, например, id загружаемого контента
 }, 
 on_falsestart:function(){//on_falsestart - вызывается когда пользователь только-что зашел на ваш сайт, но значения нашей переменной он не задал, тобишь она вызывается "по-дефолту"
  UpdateContent(0);
 }
});
Наши обработчики можно забиндить на следующие события:
on_open - когда предыдущее значение не назначено или равно нулю, но при этом текущее - назначено
on_update - предыдущее значение и текущее - назначены, но они разные
on_same - предыдущее значение назначено, как и текущее, при этом они еще и равны
on_close - предыдущее значение назначено, но текущее - пустое
on_falsestart - предыдущее и текущие значения отсутствуют, вызывается только при первом заходе на страницу
on_disabled - предыдущее значение и текущее - не назначены

 Для обеспечения работы всего этого добра, надо бы присоединить еще один скрипт, имитирующий HistoryAPI из HTML5, ну и плюс еще jQuery который наверняка используется большинством

Вот и все
Почти
Если кому интересно, могу рассказать как все это добро сдружить с поисковиками

Заметка: для вставки кода использую этот ресурс

Комментариев нет:

Отправить комментарий