showModalDialog’s returnValue is undefined in Chrome

С мест сообщают – в Chrome у show­Modal­Dia­log return­Val­ue – unde­fined. Баг известен с 2010 года и пока (16 сентября 2012) не исправлен.

Фиксить так:

В окне, которое вызывает модальное:

window.returnValue = undefined;
var result = window.showModalDialog("modalwindow.aspx", window, "dialogHeight:650px; dialogWidth:900px;");
if (result == undefined)
   result = window.returnValue;
if (result != null && result != "undefined")
  // Do something with the return value
  // defined in "result"

В модальном окне:

if (window.opener) {
    window.opener.returnValue = "your return value";
}
window.returnValue = "your return value";
self.close();

IE теряет фокус на ссылке

В IE обнаружен загадочный баг.

Если ASP.Net страница:

  • делает (например, по нажатию на страницу) redi­rect на другую через anchor (т.е. otherPage.aspx#anchor)
  • в IIS настроен ISAPI_Rewrite (локально повторить не удалось)
  • браузер – IE (повторяется в т.ч. в 9-ом)

То может случиться так, что anchor “отбросится” и страниця загрузится как otherPage.aspx.

Выловить и перенастроить практически невозможно.

Единственный выход – вместо redi­rect вставлять в lit­er­al на странице “<script language=’javascript’>location.href = ‘otherPage.aspx#anchor’;</script>”. Можно дополнительно поставить проверку – делать такой redi­rect только если браузер ie. Название браузера искать в Request.Browser.Type.

О document.ready заботаться не стоит – redi­rect он и есть redi­rect.

Click() doesn’t work in Chrome and Safari

Иногда нужно сделать, чтобы файл загружался не через форму по умолчанию (которая отличается у разных браузеров), а по нажатию на кнопку. Форму прячут, вместо неё ставят кнопку и вызывают по щелчку для неё click() для спрятанной формы.

Как правило, это работает. Но в браузерах на движке WebKit (например, Chrome и Safari) может и не сработать. В частности, Safari игнорирует click() по скрытым объектам.

Поэтому надо скрывать “народным” способом, чтобы не поломать вёрстку:

Вместо:

display: none;

Поставить в CSS:

width: 0px;
height: 0px;
position: absolute;

Script: Play mp3 at background with JavaScript

Как сделать фоновую мелодию для веб-страницы из mp3-файла?

Для начала — убедиться, что она нужна. Я, например, считаю, что единственное место во всём Вебе, где уместны фоновые мелодии — это игры. Пожалуйста, ставьте такие скрипты только в них.

Так как стандарт очень долго хранил молчание насчёт фоновых мелодий, каждый браузер реализовывал его по-своему

Путаница тут страшная. <embed>, который часто советуют, например, требует от Fire­fox подгружать плагин. <audio> толком не поддерживается даже в IE. Да и вообще, ещё 2 года назад разные браузеры поддерживали разные форматы и табличка выглядела приблизительно так:

Brows­er Ogg MP3 WAV
Fire­Fox 3.6+
Safari 5+
Chrome 6
Opera 10.5+
Inter­net Explor­er 9 (beta)

Так что используйте JPlay­er. Но иногда и он обваливается с ошибкой, что b.test — не является функцией :(.
Мне jPlay­er не помог. Пришлось родить кроссплатформенное решение:

<bgsound src="sound/plan.mp3" loop="1">
<object id="opera_player1" data="sound/plan.mp3" type="application/x-mplayer2" width="0" height="0">
 <param name="filename" value="sound/plan.mp3">
 <param name="autostart" value="1">
 <param name="autoplay" value="1">
 <param name="hidden" value="1">
 <param name="playcount" value="9999">
</object>
<audio src="sound/plan.mp3" autoplay="autoplay" loop="loop">
<object id="webkit_player" data="sound/plan.mp3" type="application/x-mplayer2" width="0" height="0">
 <param name="filename" value="sound/plan.mp3">
 <param name="autostart" value="1">
 <param name="autoplay" value="1">
 <param name="hidden" value="1">>
</object>
</audio>

В IE я это, впрочем, пока не тестировал.

Первый блок — исключительно для Opera. Во втором не забываем loop=“loop” — Chrome игнорирует Play­count.

Важно помнить, что object в Fire­fox не понимает loop. Так что просто ставьте большой play­count. А вот webkit-браузеры понимают его слишком хорошо и будут играть мелодию, даже когда вы покините сайт. Поэтому не забудьте убрать param loop во втором блоке.

И никогда не пытайтесь сгенерировать этот код через JavaScript. Такая реализация страшно тормозит даже на локальном компьютере.

А ещё не забывайте, что браузеры — умные создания и если поместить эти object’ы в скрытый блок (не важно, через, dis­play: none; или vis­i­bil­i­ty: hid­den), Fire­fox их проигрывать не будет.

Причём мы говорим, разумеется, о desk­top-ных браузерах. Про мобильные даже вспоминать страшно.

JavaScript: Случайные элементы массива

Родилось из C#-овой, но на JavaScript наглядней.

Нужно выбрать из массива N случайных элементов. Как это сделать быстро?

Если длина массива <= N — это очевидно. А если нет? Сначала склонируем массив:

Object.prototype.clone = function() {
var newObj = (this instanceof Array) ? [] : {};
for (i in this) {
  if (i == 'clone') continue;
  newObj[i] = (this[i] && typeof this[i] == "object") ? this[i].clone() : this[i];
  return newObj;
};

Потом создадим новый массив и скопируем в него нужное число элементов, а из оригинала удалим:

function selectRemoveAdd(arr, max)
{
 var arrLength = arr.length;
 if(max >= arrLength)
  return arr.clone();
 var newArray = [];
 var cloneArray = arr.clone();
 var i = 0, newPos = 0;
 while(i++ < max)
 {
  newPos = getRandom(arrLength);
  newArray.push(cloneArray[newPos]);
  cloneArray.splice(newPos, 1);
  arrLength--;
 }
 return newArray;
}

Такой вариант обычно предлагают на форумах. Но зачем создавать ещё одни массив? Можно взять исходный и удалить всё лишнее:

var arrLength = arr.length;
 if(max >= arrLength)
  return arr.clone();
 var newArray = arr.clone();
 while(arrLength-- > max)
  newArray.splice(getRandom(arrLength), 1);
 return newArray;

Какой вариант быстрее? Правильный ответ, что быстрее оба, но по-разному. Если N меньше arr.length / 2, то первый, если больше — то второй. Поэтому самый красивый и правильный способ — это:

function selectRemoveOnly(arr, max)
{
 var arrLength = arr.length;
 var newArray = arr.clone();
 while(arrLength-- > max)
   newArray.splice(getRandom(arrLength), 1);
 return newArray;
}
function selectRemoveAdd(arr, max)
{
 var arrLength = arr.length;
 var newArray = [];
 var cloneArray = arr.clone();
 var i = 0, newPos = 0;
 while(i++ < max)
 {
  newPos = getRandom(arrLength);
  newArray.push(cloneArray[newPos]);
  cloneArray.splice(newPos, 1);
  arrLength--;
 }
 return newArray;
}
function selectOptimised(arr, max)
{
 if(max >= arr.Length)
  return arr.clone();
 if(max <= arr.length / 2)
  return selectRemoveAdd(arr, max);
 else
  return selectRemoveOnly(arr, max);
}

И работать будет просто замечательно:

JavaScript: Объекты и необъекты

Говорят, во всём семействе ECMAScript все переменные — псевдообъекты.

Так вот, это неправда.

В JavaScript, например, всего 6 типов объектов:

null, unde­fined, num­ber, string, boolean и object

а значит, записать в числовую переменную новое свойство — нельзя.

Вызывая оператор “.” для num­ber, string, boolean мы просто создаём ещё один object, который получает новое свйоство, а потом записывается в никуда. Правило конвертации простое:

  • если присвоили object — оставляем как есть
  • если присвоили unde­fined, кидаем excep­tion
  • во всех прочих случаях — new Number(input), new String(input) или new Boolean(input)

JavaScript: быстрый floor и приведение объектов

Чудесное от Михаила Барановского:

В JavaScript можно писать через степень:

var a = 120000; // make it shorter?
var a = 12e4;

 

var a = Math.floor(b);
// если b всегда > 0, можно сократить до:
var a = ~~b;

Легко получать текущую дату:

var date = +new Date;

Это работает, потому что + дёргает val­ue­of.

var a = new Boolean(false); // how to quickly check if (a)?
alert(typeof a); // "object"
alert(!!a); // always true, because a is an object
alert(!!+a);
// right result, because "+" is calling valueOf
// method and convert result to number "0..1"
alert(a>0); // even shorter