понедельник, 31 октября 2011 г.

Lorem Ipsum

Lorem ipsum - это хорошо. Но прогресс не стоит на месте. И появляются всё новые вариации:

И картиночные (даст картинку нужного размера):

Checkbox в Chrome и Safari

В браузерах, основанных на WebKit, иногда портятся checkbox-ы. Девид Уолш описал проблему и дал великолепное решение:

.checkboxList li { /* ..or whatever the parent is */
  line-height: 20px;
}

В Safari есть WebKit!

В Safari обнаружен аналог Firebug из Firefox и WebKit из Chrome. По умолчанию отключён. Включать так:

Safari -> Preferences -> Advanced -> Show develop menu in menu bar

C#: Enum в ComboBox

Сбросить Enum в Combobox можно одной строкой:
comboBox.DataSource = Enum.GetValues(typeof(AnEnumType));

И выделяем:
comboBox.SelectedItem = AnEnumType.Value

пятница, 21 октября 2011 г.

JavaScript: быстрые циклы

length в JavaScript - штука медленная. Это очень хорошо видно по скорости выполнения циклов. Вовремя заменив for на while, можно получить выигрыш в производительности в 7 раз.

В умелых руках циклы JavaScript прекрасно заменяют друг друга. А значит, есть повод дополнить старый постинг о среднем арифметическом.

var digitRegEx=/^-?\d+([,\.]\d+)?$/g;
 
function arithmeticMean() {
  var len = arguments.length, i = len, finalSum = 0;
  if (!i)
    return 0;
  while (i--)
    if (digitRegEx.test(arguments[i]))
      finalSum += parseFloat(arguments[i]);
  return (len) ? finalSum / len : 0;
}

Кстати, как народная, так и более-менее проектная реализация всяких дополнительных функций для IE грешат for по lenght и ужасающе медленным trim(). Если руки дойдут - надо бу исправить.

вторник, 18 октября 2011 г.

JavaScript: быстрый парсинг числа

Как вы думаете, как быстрее парсить число с плавающей точкой - вот так:

function isNumber(n) {
    if (n == null) return null;
    var num_parsed = parseFloat(n);
    return (!isNaN(num_parsed) && isFinite(n)) ?  true : false;
}

или так (regExp немного исправлен по сравнению с примером с суммой, чтобы уважить сербов):

var digitRegEx=/^-?\d+([,\.](\d+)?)?$/g;

function isNumberRegExp(n) {
    if(digitRegEx.test(n))
 return true;
    else
 return false;
}

По идее, regExp должен работать медленней. А на самом деле скорость почти одинакова. Такие дела.

понедельник, 17 октября 2011 г.

CoffeeScript

Есть такая штука - CoffeeScript. Нечто вроде JavaScript, но в 2 раза короче:

JavaScript

var cubes, list, math, num, number, opposite, race, square;
var __slice = Array.prototype.slice;
number = 42;
opposite = true;
if (opposite) number = -42;
square = function(x) {
  return x * x;
};
list = [1, 2, 3, 4, 5];
math = {
  root: Math.sqrt,
  square: square,
  cube: function(x) {
    return x * square(x);
  }
};
race = function() {
  var runners, winner;
  winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  return print(winner, runners);
};
if (typeof elvis !== "undefined" && elvis !== null) alert("I knew it!");
cubes = (function() {
  var _i, _len, _results;
  _results = [];
  for (_i = 0, _len = list.length; _i < _len; _i++) {
    num = list[_i];
    _results.push(math.cube(num));
  }
  return _results;
})();

CoffeeScript

# Assignment:
number   = 42
opposite = true

# Conditions:
number = -42 if opposite

# Functions:
square = (x) -> x * x

# Arrays:
list = [1, 2, 3, 4, 5]

# Objects:
math =
  root:   Math.sqrt
  square: square
  cube:   (x) -> x * square x

# Splats:
race = (winner, runners...) ->
  print winner, runners

# Existence:
alert "I knew it!" if elvis?

# Array comprehensions:
cubes = (math.cube num for num in list)
Википедия говорит, что в новом Ruby он сменит JavaScript. А пока, чтобы не пропало:

Продолжаем писать слайдер

Обещанный рассказ про скрипт для слайд-шоу.

Сначала определим классы для самого слайдера и для каждого изображения внутри.

function SimpleSlider(width, height, duration){
 this.type = "SimpleSlider";
 this.width = width;
 this.height = height;
 this.duration = (duration) ? duration : 1000;
 this.images = new Array(); //картиночки
 
 this.imgprefix = 'slider-img-';
 this.currimage = 0;
}
function SimpleSliderItem(url, width, height, itemid){
 this.type = "SimpleSliderItem";
 this.url = url;
 this.width = width;
 this.height = height;
 this.itemid = itemid;
}

Добавляем изображение (slider.addImage("..."), разумеется). Перед добавлением кэшируем его, создавая объект типа Image. Этот объект хорош разве что тем, что то, что попадает в его src, будет обязательно прокешировано. Как вставить его на страницу - загадка. Поэтому заполняем images нашим собственным типом и не забываем, что добавлять больше 9999 картинок - нельзя :):

SimpleSlider.prototype.addImage = function(url) {
    if(this.images.length >= 9999)
       return;
    //Caching
    var Image1= new Image(this.width,this.height);
    Image1.src = url;
   //Appending
    this.images.push(new SimpleSliderItem(url, this.width, this.height, this.images.length));
};

SimpleSlider.prototype.insertImage = function(id) {
    if (this.images.length > id){
  var imgElem = document.createElement('img'); 
  imgElem.setAttribute('id', this.imgprefix + id);
  imgElem.setAttribute('class', 'slider-block');
  
  imgElem.setAttribute('src', this.images[id].url);
   
  imgElem.setAttribute('style', 'width: ' + this.images[id].width + '; height: ' + this.images[id].height + '; z-index: ' + (this.images.length - id) + ';');
  return imgElem;
 } else {
  return null;
 }  
};

Вставить все, одно под одним:

SimpleSlider.prototype.insertImages = function(imgElem) {
 imgElem.setAttribute('style', 'width: '+this.width+'; height: ' + this.height + ';');
    for(var img in this.images)  
 {
  var elem = this.insertImage(img);
  if(elem)
   imgElem.appendChild(elem);
 }
};

И вот настало время сделать сам слайдер. Какое изображение следующее - он узнают из функции nextImageId(), а текущее - currImageId(). Если бы это был C#, мы бы оформили их как параметры класса.

В changeImage применяем jQuery. Сначала находим то, что надо и то, на что его менять - а потом меняем. Правда, возникает проблема: в 1-ой картинке z_index больше, чем в последней, и если сделать ей show, то она просто прыгнет наверх безо всякого fade. Поэтому мы ставим последней по счёту картинке z-Index в 9999 (поэтому добавлять можно не больше 9998 изображений), в currImage.fadeOut встроили небольшую callback функцию, которая возвращает z-Index обратно:

SimpleSlider.prototype.nextImageId = function() {
 if(!this.images.length)
  return null;
 this.currimage++;
 if(this.currimage >= this.images.length)
  this.currimage = 0;
 return "#" + this.imgprefix + this.currimage;
};

SimpleSlider.prototype.currImageId = function() {
 if(!this.images.length)
  return null;
 return "#" + this.imgprefix + this.currimage;
};

SimpleSlider.prototype.changeImage = function() {
 var currImage = $(slider.currImageId());
 var nextImage = $(slider.nextImageId());
 isLastItem = !this.currimage;
 if(isLastItem)
  currImage.css('z-Index', '9999');
 currImage.fadeOut(this.duration, function() {
   if(parseInt(currImage.css('z-Index')) == 9999)
    currImage.css('z-Index', '1');
  });
 nextImage.show();
};

пятница, 14 октября 2011 г.

JavaScript: переменные в RegExp

RegExp-переменные для string.replace() в JavaScript от автора известной мануалки.

  • $1: 1-ая группа
  • $99: 99-ая группа. Если группы 99 нет - 9-ая и 9. Если 9-ой нет - просто 99 долларов
  • $+: Группа с максимальным номером.
  • $&: Весь RegExp. Никакого $0 нет!!!
  • $` (backtick): Слева от RegExp-а.
  • $' (single quote): Справа от RegExp-а.
  • $_: Вся строка, на которую натравили RegExp

четверг, 13 октября 2011 г.

Плагины для Firefox

По мотивам списка плагинов Firefox для веб-разработки.

Мой выбор:

- Firebug
- Firecookie
- YSlow
- Web Developer
- ColorZilla
- iMacros - тестировать за нас будут роботы.
- SEO-шникам - гореть в аду.

JavaScript: concat для getElementsByTagName

Иногда гибкость JavaScript немного обманывает. Например, все знают, что getElementsByTagName возвращает вроде бы массив. И если нам нужно получить все input и textarea, то мы посмотрим в справке, что есть фунция concat и - склеим!

Увы, нас ждёт разочарование. То, что приходит - это набор, но не совсем массив. Его надо преобразовывать в Array и уже потом склеивать.

Как склеивать? Обычно рекомендуют Array.prototype.slice.call(document.getElementsByTagName('input'), 0) или немыслимое [].slice.call(document.getElementsByTagName('input'), 0). Это работает во всех браузерах, кроме... IE. IE считает, что COM-объект HTMLCollection вовсе не обзательно будет массивом. И бросает ошибку "JScript object expected.".

Поэтому мы расширим функцию из предыдущего примера ещё одной полезной тулзой.

function toArray(obj) {
    var array = [];
    for (var i = 0; obj.length && i < obj.length; i++)
      array[i] = obj[i];
    return array;
  }

  function setReadOnly(){
    var item = document.getElementsByTagName('input');
    var el, els = toArray(document.getElementsByTagName('input')).concat(
                      toArray(document.getElementsByTagName('textarea')));
   for(el in els)
     if(els[el].readOnly && typeof(els[el].className) != "undefined")
       els[el].className += ' readonly';
   }

JavaScript: Стиль для read-only

Как изменить стиль для input'ов, для которых выставлено readonly="readonly"? По идее, в css:

input[readonly="readonly"]
{
 color:  #707070;
 cursor: default; 
}
textarea[readonly="readonly"]
{
 color:  #707070;
 cursor: default; 
}

Это работает в Firefox, Opera, Chrome и, наверное, Safari. А вот в IE - нет :(.

Поэтому напишем код, который цепляется к OnLoad и будет работать только в IE (другим браузерам window.attachEvent и className неизвестны).

function setReadOnly(){
  var el, els = document.getElementsByTagName('input');
  for (el in els)
    if (els[el].readOnly && typeof(els[el].className) != "undefined")
      els[el].className += ' readonly';
}
if (window.attachEvent) 
  window.attachEvent('onload', setReadOnly);

А потом добавим в css обработку для этого класса:
.readonly
{
 color:  #707070;
 cursor: default; 
}

Не забудьте дописать в скрипт обработку для textarea.

C++: Размер массива, switch в одну строку и cдвиги

Размер массива в C/C++:

MyHugeStructure array[100];
int array_size = sizeof(array)/sizeof(*array);

for(int i = 0; i < array_size; i++) 
    array[i].id = i;

Следующие два варианта актуальны и для других языков.

Switch в одну строку с поддержкой всех типов:
str = number == 1 ? "one" : 
      number == 2 ? "two" :
      number == 3 ? "three" :
      number == 4 || rand() == 42 ? "four" :
      number == 5 ? "five" :
      "unknown number";

Стандарт C - штука нестрогая. Например, char - это не 1 байт, не 2 и не 4. char - это sizeof(char) и единственное ограничение: sizeof(char) < sizeof(int). Вспоминаем, что из себя представляют числа в памяти и поэтому НИКОГДА не пытаемся поделить на 2 через сдвиг отрицательное число.
//ТАК ДЕЛАТЬ НЕЛЬЗЯ!!
int a = -2;
printf("%dn", a >> 1);

Взято отсюда

среда, 12 октября 2011 г.

JavaScript: Переменное количество аргументов у функции

Внутри каждой функции JavaScript доступен массив arguments, в котором лежат все переданные аргументы. Это позволяет, например, посчитать среднее арифметическое для любого числа аргументов.

Пишем:

var digitRegEx=/^-?\d+([,\.]\d+)?$/g;

function arithmeticMean() {
  if (!arguments.length)
    return 0;
  var finalSum = 0;
  for (var i = 0; i < arguments.length; i++)
    if (digitRegEx.test(arguments[i]))
      finalSum += parseFloat(arguments[i]);
  return (arguments.length) ? finalSum / arguments.length : 0;
}

Считаем:

alert(arithmeticMean(1, 2, 3, 4, '5', 'this param is counted as 0');

А вот делать digitRegEx.compile() - не надо. В Opera 11 откомпилированные RegExp перестают работать.

вторник, 11 октября 2011 г.

JavaScript: Простое слайд-шоу

На главной странице сайта бюро переводов КонтактЧайна недавно появилось новое слайдшоу. Быстрое и настраивается легко. Написал его я. JavaScript и чуть-чуть jQuery.
После запуска нужно, чтобы функция changeImage() вызывалась раз за разом через определённые промежутки времени. В коде это выглядит так:

var slider = new SimpleSlider(640, 250);

function sliderTimer() {
 slider.changeImage();
 t=setTimeout("sliderTimer()",1000);
}
$(function(){
    slider.addImage("image1.jpg");
    slider.addImage("image2.jpg");
    slider.addImage("image3.jpg");
    slider.insertImages(document.getElementById("slider_simple"));
    sliderTimer();
});
Дальше я расскажу о том, как устроен этот скрипт изнутри.