понедельник, 17 февраля 2014 г.

JavaScript Дублирование кода

Скорее всего, в любом API содержится множество методов-аксессоров (геттеров, сеттеров, экзекуторов), которые делают похожие вещи. Вернёмся к примеру с DateInterval. Там мы наверняка предоставили бы методы start() и end() для управления интервалами. Простое решение может выглядеть так: DateInterval.prototype.start = function(date) { if (date === undefined) { return new Date(this.startDate.getTime()); } this.startDate.setTime(date.getTime()); return this; }; DateInterval.prototype.end = function(date) { if (date === undefined) { return new Date(this.endDate.getTime()); } this.endDate.setTime(date.getTime()); return this; }; Как видите, куча повторяющегося кода. Принцип «не повторяйся» (DRY или Don't Repeat Yourself, прим. ред.) подсказывает нам возможность воспользоваться шаблоном-генератором: var accessors = ["start", "end"]; for (var i = 0, length = accessors.length; i < length; i++) { var key = accessors[i]; DateInterval.prototype[key] = generateAccessor(key); } function generateAccessor(key) { var value = key + "Date"; return function(date) { if (date === undefined) { return new Date(this[value].getTime()); } this[value].setTime(date.getTime()); return this; }; } Такой подход позволит вам генерировать несколько похожих методов-аксессоров вместо того, чтобы указывать каждый из них по отдельности. Если ваши аксессоры требуют больше данных при генерации, чем просто строка, можно использовать что-то подобное: var accessors = {"start" : {color: "green"}, "end" : {color: "red"}}; for (var key in accessors) { DateInterval.prototype[key] = generateAccessor(key, accessors[key]); } function generateAccessor(key, accessor) { var value = key + "Date"; return function(date) { // тут делаем что-нибудь полезное, // используя `key` и `accessor.color` }; } В главе Обработка аргументов мы говорили о паттерне Метод, позволяющем принимать вашим геттерам и сеттерам значения различных полезных типов, вроде словарей и массивов. Паттерн Метод сам по себе достаточно универсален, и его можно с легкостью превратить в генератор: function wrapFlexibleAccessor(get, set) { return function(name, value) { var map; if (jQuery.isPlainObject(name)) { // устанавливаем словарь map = name; } else if (value !== undefined) { // устанавливаем значение (возможно, на нескольких именах), // преобразуем в словарь keys = name.split(" "); map = {}; for (var i = 0, length = keys.length; i < length; i++) { map[keys[i]] = value; } } else { return get.call(this, name); } for (var key in map) { set.call(this, name, map[key]); } return this; }; } DateInterval.prototype.values = wrapFlexibleAccessor( function(name) { return name !== undefined ? this.values[name] : this.values; }, function(name, value) { this.values[name] = value; } );

JavaScript Значения по умолчанию в функциях

var default_options = { accepts: "text", async: true, beforeSend: null, cache: false, complete: null, // и так далее }; //функция мечты function dream(options) { var o = jQuery.extend({}, default_options, options || {}); console.log(o.accepts); } // делаем значение по умолчанию публичным dream.default_options = default_options; dream({ async: false }); // выведется: "text"

пятница, 14 февраля 2014 г.

File Upload Check and Filter File extension

These examples were written based on the current specification and may not actually work in all (or any) browsers. The specification may also change in the future, which could break these examples.

The accept attribute may be specified to provide user agents with a hint of what file types will be accepted.

If specified, the attribute must consist of a set of comma-separated tokens, each of which must be an ASCII case-insensitive match for one of the following:

The string audio/*

Indicates that sound files are accepted.
The string video/*

Indicates that video files are accepted.
The string image/*

Indicates that image files are accepted.
A valid MIME type with no parameters

Indicates that files of the specified type are accepted.
A string whose first character is a U+002E FULL STOP character (.)

Indicates that files with the specified file extension are accepted.

<!-- Match all image files (image/*) -->
<input type="file" accept="image/*">

<!-- Match all video files (video/*) -->
<input type="file" accept="video/*">

<!-- Match all audio files (audio/*) -->
<input type="file" accept="audio/*">

<!-- Match all image files (image/*) and files with the extension ".someext" -->
<input type="file" accept=".someext,image/*">
<!-- See note below -->

<!-- Match all image files (image/*) and video files (video/*) -->
<input type="file" accept="image/*,video/*">
<!-- See note below -->

I needed to accept JPG, PNG, GIF, PDF, and EPS files, but accept='.jpg,.png,.gif,.pdf,.eps' didn't allow any selection. I tried many variations - space delimited, no dot characters, etc., but no dice in Chrome v20, so I ended up using the mime types and it worked great:

accept='image/jpeg,image/gif,image/png,application/pdf,image/x-eps'

As mentioned, the examples are taken from the specification and may not actually work in any browsers.

According to the spec: Value: A set of comma-separated strings, each of which is a valid MIME type, with no parameters. Just mime types. No extensions.

Accept attribute was introduced in the RFC 1867, intending to enable file-type filtering based on MIME type for the file-select control. But most, if not all, browsers make no use of this attribute. Using client-side scripting, you can make a sort of extension based validation, for submit data of correct type (extension).

Other solutions for advanced file uploading require Flash movies like SWFUpload or Java Applets like JUpload.

HTML

<input name="fileToUpload" type="file" accept="image/png" onchange="check_file()" >

JavaScript

function check_file(){
        str=document.getElementById('fileToUpload').value.toUpperCase();
        suffix=".JPG";
        suffix2=".JPEG";
        if(!(str.indexOf(suffix, str.length - suffix.length) !== -1 || str.indexOf(suffix2, str.length - suffix2.length) !== -1)){
            alert('File type not allowed,\nAllowed file: *.jpg,*.jpeg');
            document.getElementById('fileToUpload').value='';
        }
}

Another solution with a few lines

function checkFile(i){
  i = i.substr(i.length - 4, i.length).toLowerCase();
  i = i.replace('.','');
  switch(i){
    case 'jpg':
    case 'jpeg':
    case 'png':
    case 'gif':
      // do OK stuff
      break;
    default:
      // do error stuff
      break;
  }
}

One more example

function extractFilename(path) {
  if (path.substr(0, 12) == "C:\\fakepath\\")
    return path.substr(12); // modern browser
  var x;
  x = path.lastIndexOf('/');
  if (x >= 0) // Unix-based path
    return path.substr(x+1);
  x = path.lastIndexOf('\\');
  if (x >= 0) // Windows-based path
    return path.substr(x+1);
  return path; // just the file name
}

This can be used as follows:

<p><input type=file name=image onchange="updateFilename(this.value)"></p>
<p>The name of the file you picked is: <span id="filename">(none)</span></p>
<script>
 function updateFilename(path) {
   var name = extractFilename(path);
   document.getElementById('filename').textContent = name;
 }
</script>

Yes, it is extremely useful in browsers that support it, but the "limiting" is as a convenience to users (so they are not overwhelmed with irrelevant files) rather than as a way to prevent them from uploading things you don't want them uploading.

It is supported in

Chrome 16 +
Safari 6 +
Firefox 9 +
IE 10 +
Opera 11 +

Here is a list of content types you can use with it, followed by the corresponding file extensions (though of course you can use any file extension):

List of MIME Types by Content Type

MIME Type File Extension
application/envoy evy
application/fractals fif
application/futuresplash spl
application/hta hta
application/internet-property-stream acx
application/mac-binhex40 hqx
application/msword doc
application/msword dot
application/octet-stream *
application/octet-stream bin
application/octet-stream class
application/octet-stream dms
application/octet-stream exe
application/octet-stream lha
application/octet-stream lzh
application/oda oda
application/olescript axs
application/pdf pdf
application/pics-rules prf
application/pkcs10 p10
application/pkix-crl crl
application/postscript ai
application/postscript eps
application/postscript ps
application/rtf rtf
application/set-payment-initiation setpay
application/set-registration-initiation setreg
application/vnd.ms-excel xla
application/vnd.ms-excel xlc
application/vnd.ms-excel xlm
application/vnd.ms-excel xls
application/vnd.ms-excel xlt
application/vnd.ms-excel xlw
application/vnd.ms-outlook msg
application/vnd.ms-pkicertstore sst
application/vnd.ms-pkiseccat cat
application/vnd.ms-pkistl stl
application/vnd.ms-powerpoint pot
application/vnd.ms-powerpoint pps
application/vnd.ms-powerpoint ppt
application/vnd.ms-project mpp
application/vnd.ms-works wcm
application/vnd.ms-works wdb
application/vnd.ms-works wks
application/vnd.ms-works wps
application/winhlp hlp
application/x-bcpio bcpio
application/x-cdf cdf
application/x-compress z
application/x-compressed tgz
application/x-cpio cpio
application/x-csh csh
application/x-director dcr
application/x-director dir
application/x-director dxr
application/x-dvi dvi
application/x-gtar gtar
application/x-gzip gz
application/x-hdf hdf
application/x-internet-signup ins
application/x-internet-signup isp
application/x-iphone iii
application/x-javascript js
application/x-latex latex
application/x-msaccess mdb
application/x-mscardfile crd
application/x-msclip clp
application/x-msdownload dll
application/x-msmediaview m13
application/x-msmediaview m14
application/x-msmediaview mvb
application/x-msmetafile wmf
application/x-msmoney mny
application/x-mspublisher pub
application/x-msschedule scd
application/x-msterminal trm
application/x-mswrite wri
application/x-netcdf cdf
application/x-netcdf nc
application/x-perfmon pma
application/x-perfmon pmc
application/x-perfmon pml
application/x-perfmon pmr
application/x-perfmon pmw
application/x-pkcs12 p12
application/x-pkcs12 pfx
application/x-pkcs7-certificates p7b
application/x-pkcs7-certificates spc
application/x-pkcs7-certreqresp p7r
application/x-pkcs7-mime p7c
application/x-pkcs7-mime p7m
application/x-pkcs7-signature p7s
application/x-sh sh
application/x-shar shar
application/x-shockwave-flash swf
application/x-stuffit sit
application/x-sv4cpio sv4cpio
application/x-sv4crc sv4crc
application/x-tar tar
application/x-tcl tcl
application/x-tex tex
application/x-texinfo texi
application/x-texinfo texinfo
application/x-troff roff
application/x-troff t
application/x-troff tr
application/x-troff-man man
application/x-troff-me me
application/x-troff-ms ms
application/x-ustar ustar
application/x-wais-source src
application/x-x509-ca-cert cer
application/x-x509-ca-cert crt
application/x-x509-ca-cert der
application/ynd.ms-pkipko pko
application/zip zip
audio/basic au
audio/basic snd
audio/mid mid
audio/mid rmi
audio/mpeg mp3
audio/x-aiff aif
audio/x-aiff aifc
audio/x-aiff aiff
audio/x-mpegurl m3u
audio/x-pn-realaudio ra
audio/x-pn-realaudio ram
audio/x-wav wav
image/bmp bmp
image/cis-cod cod
image/gif gif
image/ief ief
image/jpeg jpe
image/jpeg jpeg
image/jpeg jpg
image/pipeg jfif
image/svg+xml svg
image/tiff tif
image/tiff tiff
image/x-cmu-raster ras
image/x-cmx cmx
image/x-icon ico
image/x-portable-anymap pnm
image/x-portable-bitmap pbm
image/x-portable-graymap pgm
image/x-portable-pixmap ppm
image/x-rgb rgb
image/x-xbitmap xbm
image/x-xpixmap xpm
image/x-xwindowdump xwd
message/rfc822 mht
message/rfc822 mhtml
message/rfc822 nws
text/css css
text/h323 323
text/html htm
text/html html
text/html stm
text/iuls uls
text/plain bas
text/plain c
text/plain h
text/plain txt
text/richtext rtx
text/scriptlet sct
text/tab-separated-values tsv
text/webviewhtml htt
text/x-component htc
text/x-setext etx
text/x-vcard vcf
video/mpeg mp2
video/mpeg mpa
video/mpeg mpe
video/mpeg mpeg
video/mpeg mpg
video/mpeg mpv2
video/quicktime mov
video/quicktime qt
video/x-la-asf lsf
video/x-la-asf lsx
video/x-ms-asf asf
video/x-ms-asf asr
video/x-ms-asf asx
video/x-msvideo avi
video/x-sgi-movie movie
x-world/x-vrml flr
x-world/x-vrml vrml
x-world/x-vrml wrl
x-world/x-vrml wrz
x-world/x-vrml xaf
x-world/x-vrml xof

четверг, 13 февраля 2014 г.

JavaScript Swig JS Использование в браузере

Рабочий пример использования Swig JS в браузере.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script type="text/javascript" src="swig.min.js"></script>
<script type="text/javascript">
window.onload = function(){
    var template = '{{ stuff }} {{ akg.name }} {% if stuff %} super Stuff {% endif %}';
    template += '{% for person in people %}'
                 + '{% if loop.first %}<ol>{% endif %}'
                 + '<li>Index: {{ loop.key }} {{ person.name }}</li>'
                 + '{% if loop.last %}</ol>{% endif %}'
                 + '{% endfor %}';
    template += '{% for item in seq -%} {{ item }} {%- endfor %}';
    var locals = {locals: {
           stuff: 'awesome'
         , akg: {name: 'Dima'}
         , people: [{name: 'One'}, {name: 'Two'}, {name: 'Three'}]
         , seq: [1, 2, 3, 4, 5]
    }};
    var result = swig.render(template, locals);
    document.body.innerHTML = result;
};
</script>
</head>
<body></body>
</html>

понедельник, 10 февраля 2014 г.

Ускорение работы циклов JavaScript на 50%

Данные примеры дают ускорение выполнения циклов JavaScript на 50%.

function process (value) {
    console.log(value);
}

var values = new Array(1000000);

var len = values.length;

// for loop
for (var i = len; i--;) {
    process(values[i]);
}

// do-while loop
var j = len - 1;
do {
    process(value[j]);
} while (j--)

// while loop
var k = len;
while (k--) {
    process(value[k]);
}

Running CPU Intensive JavaScript Computations in a Web Browser

Пример выполнения медленных расчетов на JavaScript в браузере с предотвращением появления окна с предложением остановить сценарий замедляющий работу веб-обозревателя:

function doSomething (callbackFunction [, additional arguments]) {
    // Initialize a few things here...
    (function startNextTimeout () {
        // Do a little bit of work here...
        if (termination condition) {
            // We are done
            callbackFunction();
        } else {
            // Process next chunk
            setTimeout(startNextTimeout, 0);
        }
    })();
}

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

function doSomething (progressFunction [, additional arguments]) {
    // Initialize a few things here...
    (function startNextTimeout () {
        // Do a little bit of work here...
        if (continuation condition) {
            // Inform the application of the progress
            progressFunction(value, total);
            // Process next chunk
            setTimeout(startNextTimeout, 0);
        }
    })();
}

Пример страницы, отображающей прогрессбар выполнения длительной операции:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <title>Running long JavaScript processes in a web browser</title>
    <style>
 
        body {
            padding:0;
            margin:1em;
        }

        #progressbar {
            position:relative;
            width:300px; height:20px;
            border:1px solid black;
            overflow:hidden;
        }

        #progressbar div {
            background:#316aC5;
            width:0; height:100%;
        }
 
    </style>
  </head>
  <body>
    <p>Sorting, please wait...</p>
    <div id="progressbar"><div></div></div>

    <script>

        (function () {

            var i, length, data, el, start;

            // Initialize a few things...
            length = 1000;
            data = [];
            el = document.getElementById('progressbar').firstChild;

            // Setup an array of random integers...
            for (i = 0; i < length; i++) {
                data[i] = Math.floor(Math.random() * length);
            }

            function sort (progressFunction) {
                i = 0;

                (function startNextTimeout () {
                    var j, value;

                    for (j = length; j > i; j--) {
                        if (data[j] < data[j - 1]) {
                            value = data[j];
                            data[j] = data[j - 1];
                            data[j - 1] = value;
                        }
                    }

                    i++;

                    progressFunction(i, length);

                    if (i < length) {
                        setTimeout(startNextTimeout, 0);
                    }

                })();
            }

            start = new Date().getTime();

            sort(function (value, total) {
                el.style.width = (100 * value / total) + "%";
                if (value >= total) {
                    alert('Total duration: ' + ((new Date().getTime() - start) / 1000) + ' seconds');
                }
            });

        })();

    </script>
  </body>
</html>

Пример последовательного выполнения задач по очереди:

function saveDocument(id){

        var tasks = [openDocument, writeText, closeDocument, updateUI];

        setTimeout(function startNextTask (){

            //execute the next task

            var task = tasks.shift();

            task(id);

            //determine if there's more

            if (tasks.length > 0) {

                setTimeout(startNextTask, 25);

             }

        }, 25);

}

среда, 5 февраля 2014 г.

Полезные приемы jQuery

Плавный скролл к верху страницы.

Эти 4 строки кода позволят вашим посетителям плавно проскролить страницу к верху простым нажатием ссылки (с id #top) расположенной внизу страницы.

$("a[href='#top']").click(function() {
  $("html, body").animate({ scrollTop: 0 }, "slow");
  return false;
});


Дублирование thead в самый низ html таблицы.

Для лучшей читаемости таблиц было бы неплохо скопировать шапку таблицы в низ таблицы. Собственно, это и делает следующий сниппет.

var $tfoot = $('<tfoot></tfoot>');
$($('thead').clone(true, true).children().get().reverse()).each(function() {
  $tfoot.append($(this));
});
$tfoot.insertAfter('table thead');


Загрузка внешнего контента.

Вам нужно добавить определенный внешний контент в div? Так вот это очень просто сделать с jQuery, как показано в нижеприведенном примере.

$("#content").load("somefile.html", function(response, status, xhr) {
  // error handling
  if(status == "error") {
    $("#content").html("An error occured: " + xhr.status + " " + xhr.statusText);
  }
});

Колонки одинаковой высоты.

В случае использования колонок для отображения контента вашего сайта, определенно будет смотреться лучше, если у колонок будет одинаковая высота. Код ниже возьмет все div элементы с классом .col и установит их высоту по самому высокому элементу. Супер полезно!

var maxheight = 0;
$("div.col").each(function() {
  if($(this).height() > maxheight) { maxheight = $(this).height(); }
});

$("div.col").height(maxheight);


Табличные полосы (зебра).

Когда данные отображаются в виде таблицы, отличающиеся цвета в каждой строке однозначно повышают читаемость. Вот сниппет для автоматического добавления CSS класса в каждую вторую(четную) строку таблицы.

$(document).ready(function(){                            
     $("table tr:even").addClass('stripe');
});


Частичное обновление страницы.

Если вам нужно обновить только часть страницы, то эти 3 строки кода точно помогут. В примере div с id #refresh автоматически обновляется каждые 10 секунд.

setInterval(function() {
  $("#refresh").load(location.href+" #refresh>*","");
}, 10000); // milliseconds to wait


Предзагрузка изображений.

jQuery упрощает предзагрузку изображений в фоне, так что посетителям не придется ждать целую вечность, когда появятся желаемые изображения. Код готов к использованию, просто отредактируйте список изоборажений в строке 8.

$.preloadImages = function() {
       for(var i = 0; i<arguments.length; i++) {
               $("<img />").attr("src", arguments[i]);
       }
}

$(document).ready(function() {
       $.preloadImages("hoverimage1.jpg","hoverimage2.jpg");
});


Открытие внешних ссылок в новом окне или новой вкладке.

Аттрибут target="_blank" позволяет вам открывать ссылки в новых окнах. Но это относится к открытию внешних ссылок, внутридоменные ссылки должны окрываться в том же окне.
Этот код находит внешнюю ссылку и добавляет в найденный элемент аттрибут target="_blank".

$('a').each(function() {
   var a = new RegExp('/' + window.location.host + '/');
   if(!a.test(this.href)) {
       $(this).click(function(event) {
           event.preventDefault();
           event.stopPropagation();
           window.open(this.href, '_blank');
       });
   }
});


Div по ширине/высоте вьюпорта.

Этот удобный фрагмент кода позволяет создавать растянутый по ширине/высоте вьюпорта div. Код также поддерживает изменение размеров окна. Прекрасное решение для модальных диалогов и popup-окон.

// global vars
var winWidth = $(window).width();
var winHeight = $(window).height();

// set initial div height / width
$('div').css({
    'width': winWidth,
'height': winHeight,
});

// make sure div stays full width/height on resize
$(window).resize(function(){
    $('div').css({
    'width': winWidth,
    'height': winHeight,
});
});


Проверка сложности пароля.

Когда вы предоставляете пользователям самостоятельный выбор пароля, было бы неплохо показать насколько сложен их пароль. Код сниппета именно это и делает.

Для начала создадим поля ввода:

<input type="password" name="pass" id="pass" />
<span id="passstrength"></span>


И далее немного jQuery кода. Введенный пароль будет проверен с помощью регулярных выражений и на основе этого пользователю будет выведено сообщение насколько сложен его пароль.

$('#pass').keyup(function(e) {
     var strongRegex = new RegExp("^(?=.{8,})(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W).*$", "g");
     var mediumRegex = new RegExp("^(?=.{7,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))).*$", "g");
     var enoughRegex = new RegExp("(?=.{6,}).*", "g");
     if (false == enoughRegex.test($(this).val())) {
             $('#passstrength').html('More Characters');
     } else if (strongRegex.test($(this).val())) {
             $('#passstrength').className = 'ok';
             $('#passstrength').html('Strong!');
     } else if (mediumRegex.test($(this).val())) {
             $('#passstrength').className = 'alert';
             $('#passstrength').html('Medium!');
     } else {
             $('#passstrength').className = 'error';
             $('#passstrength').html('Weak!');
     }
     return true;
});


Изменение размеров изображения.

Вы конечно можете изменять размеры ваших изображений на стороне сервера (например, используя PHP и GD-библиотеку), но иногда полезно делать это на клиентской стороне с помощью jQuery. Вот сниппет для этого.

$(window).bind("load", function() {
    // IMAGE RESIZE
    $('#product_cat_list img').each(function() {
        var maxWidth = 120;
        var maxHeight = 120;
        var ratio = 0;
        var width = $(this).width();
        var height = $(this).height();
   
        if(width > maxWidth){
            ratio = maxWidth / width;
            $(this).css("width", maxWidth);
            $(this).css("height", height * ratio);
            height = height * ratio;
        }
        var width = $(this).width();
        var height = $(this).height();
        if(height > maxHeight){
            ratio = maxHeight / height;
            $(this).css("height", maxHeight);
            $(this).css("width", width * ratio);
            width = width * ratio;
        }
    });
    //$("#contentpage img").show();
    // IMAGE RESIZE
});


Автоматическая загрузка контента по скроллу.

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

var loading = false;
$(window).scroll(function(){
    if((($(window).scrollTop()+$(window).height())+250)>=$(document).height()){
        if(loading == false){
            loading = true;
            $('#loadingbar').css("display","block");
            $.get("load.php?start="+$('#loaded_max').val(), function(loaded){
                $('body').append(loaded);
                $('#loaded_max').val(parseInt($('#loaded_max').val())+50);
                $('#loadingbar').css("display","none");
                loading = false;
            });
        }
    }
});

$(document).ready(function() {
    $('#loaded_max').val(50);
});


Проверить, загрузилось ли изображение.

Вот сниппет, который я часто использую при работе с изображениями, потому что, это лучший способ узнать, загрузилось изображение или нет.

var imgsrc = 'img/image1.png';
$('<img/>').load(function () {
    alert('image loaded');
}).error(function () {
    alert('error loading image');
}).attr('src', imgsrc);


Сортировка списка в алфавитном порядке.

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

$(function() {
    $.fn.sortList = function() {
    var mylist = $(this);
    var listitems = $('li', mylist).get();
    listitems.sort(function(a, b) {
        var compA = $(a).text().toUpperCase();
        var compB = $(b).text().toUpperCase();
        return (compA < compB) ? -1 : 1;
    });
    $.each(listitems, function(i, itm) {
        mylist.append(itm);
    });
   }

    $("ul#demoOne").sortList();

});

вторник, 4 февраля 2014 г.

Пишем JavaScript код без jQuery

AJAX

JSON

JQUERY

$.getJSON('/my/url', function(data) {

})

IE8+

request = new XMLHttpRequest
request.open('GET', '/my/url', true)
request.send()

request.onload = function() {
  data = JSON.parse(this.response)
}

Post

JQUERY

$.ajax({
  type: 'POST',
  url: '/my/url',
  data: data
})

IE8+

request = new XMLHttpRequest
request.open('POST', '/my/url', true)
request.send(data)

Request

JQUERY

$.ajax({
  type: 'GET',
  url: '/my/url',
  success: function(resp) {

  },
  error: function() {

  }
})

IE8+

request = new XMLHttpRequest
request.open('GET', '/my/url', true)
request.send()

request.onload = function() {
  resp = this.response
}

request.onerror = function() {

}

EFFECTS

Fade In

JQUERY

$(el).fadeIn()

IE8+

function fadeIn(el) {
  var opacity = 0

  el.style.opacity = 0
  el.style.filter = ''

  var last = +new Date
  var tick = function() {
    opacity += (new Date - last) / 400
    el.style.opacity = opacity
    el.style.filter = 'alpha(opacity=' + (100 * opacity)|0 + ')'

    last = +new Date

    if (opacity < 1)
      (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16)
  }

  tick()
}

fadeIn(el)

Hide

JQUERY

$(el).hide()

IE8+

el.style.display = 'none'

Show

JQUERY

$(el).show()

IE8+

el.style.display = ''

ELEMENTS

Add Class

JQUERY

$(el).addClass(className)

IE8+

if (el.classList)
  el.classList.add(className)
else
  el.className += ' ' + className

After

JQUERY

$(el).after(htmlString)

IE8+

el.insertAdjacentHTML('afterend', htmlString)

Append

JQUERY

$(parent).append(el)

IE8+

parent.appendChild(el)

Before

JQUERY

$(el).before(htmlString)

IE8+

el.insertAdjacentHTML('beforebegin', htmlString)

Children

JQUERY

$(el).children()

IE8+

el.children

Clone

JQUERY

$(el).clone()

IE8+

el.cloneNode(true)

Contains

JQUERY

$.contains(el, child)

IE8+

el !== child && el.contains(child)

Contains Selector

JQUERY

$(el).find(selector).length

IE8+

el.querySelector(selector) !== null

Each

JQUERY

$(selector).each(function(i, el){

})

IE8+

function forEachElement(selector, fn) {
  var elements = document.querySelectorAll(selector)
  for (var i = 0; i < elements.length; i++)
    fn(elements[i], i)
}

forEachElement(selector, function(el, i){

})

Empty

JQUERY

$(el).empty()

IE8+

el.innerHTML = '';

Filter

JQUERY

$(selector).filter(filterFn)
IE8+

function filter(selector, filterFn) {
  var elements = document.querySelectorAll(selector)
  var out = []
  for (var i = elements.length; i--;) {
    if (filterFn(elements[i]))
      out.unshift(elements[i])
  }
  return out
}

filter(selector, filterFn)

Finding Children

JQUERY

$(el).find(selector)

IE8+

el.querySelectorAll(selector)

Finding Elements

JQUERY

$('.my #awesome selector')

IE8+

document.querySelectorAll('.my #awesome selector')

Get Style

JQUERY

$(el).css(ruleName)

IE8+

// Varies based on the properties being retrieved, some can be retrieved from el.currentStyle
// https://github.com/jonathantneal/Polyfills-for-IE8/blob/master/getComputedStyle.js

Getting Attributes

JQUERY

$(el).attr('tabindex')

IE8+

el.getAttribute('tabindex')

Getting Html

JQUERY

$(el).html()

IE8+

el.innerHTML

Getting Outer Html

JQUERY

$('<div>').append($(el).clone()).html()

IE8+

el.outerHTML

Getting Text

JQUERY

$(el).text()

IE8+

el.textContent || el.innerText

Has Class

JQUERY

$(el).hasClass(className)

IE8+

if (el.classList)
  el.classList.contains(className)
else
  new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className)

Matches

JQUERY

$(el).is($(otherEl))

IE8+

el === otherEl

Matches Selector

JQUERY

$(el).is('.my-class')

IE8+

matches = function(el, selector) {
  var _matches = (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector)

  if (_matches) {
    return _matches.call(el, selector)
  } else {
    var nodes = el.parentNode.querySelectorAll(selector)
    for (var i = nodes.length; i--;) {
      if (nodes[i] === el)
        return true
    }
    return false
}

matches(el, '.my-class')

Next

JQUERY

$(el).next()

IE8+

// nextSibling can include text nodes
function nextElementSibling(el) {
  do { el = el.nextSibling } while ( el && el.nodeType !== 1 )
  return el
}

el.nextElementSibling || nextElementSibling(el)

Offset

JQUERY

$(el).offset()

IE8+

{left: el.offsetLeft, top: el.offsetTop}

Offset Parent

JQUERY

$(el).offsetParent()

IE8+

el.offsetParent || el

Parent

JQUERY

$(el).parent()

IE8+

el.parentNode

Prepend

JQUERY

$(parent).prepend(el)

IE8+

parent.insertBefore(el, parent.firstChild)

Prev

JQUERY

$(el).prev()

IE8+

// prevSibling can include text nodes
function prevElementSibling(el) {
  do { el = el.prevSibling } while ( el && el.nodeType !== 1 )
  return el
}

el.prevElementSibling || prevElementSibling(el)

Remove Class

JQUERY

$(el).removeClass(className)

IE8+

if (el.classList)
  el.classList.remove(className)
else
  el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ')

Remove

JQUERY

$(el).remove()

IE8+

el.parentNode.removeChild(el)

Replacing From Html

JQUERY

$(el).replaceWith(string)

IE8+

el.outerHTML = string

Set Style

JQUERY

$(el).css('border-width', '20px')

IE8+

// Use a class if possible
el.style.borderWidth = '20px'

Setting Attributes

JQUERY

$(el).attr('tabindex', 3)

IE8+

el.setAttribute('tabindex', 3)

Setting Html

JQUERY

$(el).html(string)

IE8+

el.innerHTML = string

Setting Text

JQUERY

$(el).text(string)

IE8+

if (el.textContent !== undefined)
  el.textContent = string
else
  el.innerText = string

Siblings

JQUERY

$(el).siblings()

IE8+

var siblings = Array.prototype.slice.call(el.parentNode.children)

for (var i = siblings.length; i--;) {
  if (siblings[i] === el) {
    siblings.splice(i, 1)
    break
  }
}

Toggle Class

JQUERY

$(el).toggleClass(className)

IE8+

if (el.classList) {
    el.classList.toggle(className)
} else {
    var classes = el.className.split(' ')
    var existingIndex = -1
    for (var i = classes.length; i--;) {
      if (classes[i] === className)
        existingIndex = i
    }

    if (existingIndex >= 0)
      classes.splice(existingIndex, 1)
    else
      classes.push(className)

    el.className = classes.join(' ')
}

EVENTS

Off

JQUERY

$(el).off(eventName, eventHandler)

IE8+

function removeEventListener(el, eventName, handler) {
  if (el.removeEventListener)
    el.removeEventListener(eventName, handler)
  else
    el.detachEvent('on' + eventName, handler)
}

removeEventListener(el, eventName, handler)

On

JQUERY

$(el).on(eventName, eventHandler)

IE8+

function addEventListener(el, eventName, handler) {
  if (el.addEventListener)
    el.addEventListener(eventName, handler)
  else
    el.attachEvent('on' + eventName, handler)
}

addEventListener(el, eventName, handler)

Ready

JQUERY

$(document).ready(function(){

})

IE8+

function ready(fn) {
  if (document.addEventListener) {
    document.addEventListener('DOMContentLoaded', fn)
  } else {
    document.attachEvent('onreadystatechange', function(){
      if (document.readyState === 'interactive')
        fn()
    })
  }
}

Trigger Custom

JQUERY

$(el).trigger('my-event', {some: 'data'})

IE8+

// Custom events are not natively supported, so you have to hijack a random
// event.
//
// Just use jQuery.

Trigger Native

JQUERY

$(el).trigger('change')

IE8+

if (document.createEvent) {
  event = document.createEvent('HTMLEvents')
  event.initEvent('change', true, false)
  el.dispatchEvent(event)
} else {
  el.fireEvent('onchange')
}

UTILS

Array Each

JQUERY

$.each(array, function(i, item){

})

IE8+

function forEach(array, fn) {
  for (i = 0; i < array.length; i++)
    fn(array[i], i)
}

forEach(array, function(item, i){

})

Bind

JQUERY

$.proxy(fn, context)

IE8+

function(){
  return fn.apply(context, arguments)
}

Deep Extend

JQUERY

$.extend(true, {}, objA, objB)

IE8+

deepExtend = function(out) {
  out = out || {}

  for (var i = 1; i < arguments.length; i++) {
    var obj = arguments[i]

    if (!obj)
      continue

    for (key in obj) {
      if (obj.hasOwnProperty(key)) {
        if (typeof obj[key] === 'object')
          deepExtend(out[key], obj[key])
        else
          out[key] = obj[key]
      }
    }
  }

  return out
}

deepExtend({}, objA, objB)

Extend

JQUERY

$.extend({}, objA, objB)

IE8+

extend = function(out) {
  out = out || {}

  for (var i = 1; i < arguments.length; i++) {
    if (!arguments[i])
      continue

    for (key in arguments[i]) {
      if (arguments[i].hasOwnProperty(key))
        out[key] = arguments[i][key]
    }
  }

  return out
}

extend({}, objA, objB)

Index Of

JQUERY

$.inArray(item, array)

IE8+

function indexOf(array, item) {
  for (var i = 0; i < array.length; i++) {
    if (array[i] === item)
      return i
  }
  return -1
}

indexOf(array, item)

Is Array

JQUERY

$.isArray(arr)

IE8+

isArray = Array.isArray || function(arr) {
  return Object.prototype.toString.call(arr) == '[object Array]'
}

isArray(arr)

Map

JQUERY

$.map(array, function(value, index){

})

IE8+

function map(arr, fn) {
  var results = []
  for (var i = 0; i < arr.length; i++)
    results.push(fn(arr[i], i))
  return results
}

map(array, function(value, index){

})

Now

JQUERY

$.now()

IE8+

new Date().getTime()

Parse Html

JQUERY

$.parseHTML(htmlString)

IE8+

var parseHTML = function(str) {
  var el = document.createElement('div')
  el.innerHTML = str
  return el.children
}

parseHTML(htmlString)

Parse Json

JQUERY

$.parseJSON(string)

IE8+

JSON.parse(string)

Trim

JQUERY

$.trim(string)

IE8+

string.replace(/^\s+|\s+$/g, '')