пятница, 31 января 2014 г.

Структура организации папок и файлов в проекте

root-folder

├── index.html

├── styles
│   │
│   ├── default
│   │   │
│   │   ├── blocks
│   │   │       │
│   │   │       ├── news
│   │   │       │   ├── images
│   │   │       │   │     ├── bg
│   │   │       │   │           ├── group-bg.png
│   │   │       │   │
│   │   │       │   ├── main.less
│   │   │       │
│   │   │       ├── calendar
│   │   │             ├── images
│   │   │             │     ├── bg
│   │   │             │           ├── group-bg.png
│   │   │             │
│   │   │             ├── main.less
│   │   │
│   │   ├── fonts
│   │   │       │
│   │   │       ├── DinCyr
│   │   │       │   ├── dincyrregular.ttf
│   │   │       │   ├── dincyrregular.woff
│   │   │       │   ├── dincyrregular.svg
│   │   │       │
│   │   │       ├── DinCyrMed
│   │   │            ├── dincyrmed.ttf
│   │   │            ├── dincyrmed.woff
│   │   │            ├── dincyrmed.svg
│   │   │
│   │   ├── images
│   │   │       │
│   │   │       ├── bg
│   │   │       │   ├── group-bg.png
│   │   │       │
│   │   │       ├── icons
│   │   │            ├── open.png
│   │   │            ├── close.png
│   │   │
│   │   ├── index.css
│   │   ├── index-gte-ie8.css
│   │   │
│   │   ├── ie.less
│   │   ├── reset.less
│   │   ├── globals.less
│   │   ├── common.less
│   │   ├── layout.less
│   │   ├── print.less
│   │   ├── paths.less
│   │   ├── fonts.less
│   │   ├── mixins.less
│   │   ├── variables.less
│   │
│   ├── blue
│   │   │
│   │   ├── images
│   │   │       │
│   │   │       ├── bg
│   │   │       │   ├── group-bg.png
│   │   │       │
│   │   │       ├── icons
│   │   │            ├── open.png
│   │   │            ├── close.png
│   │   │
│   │   ├── index.css
│   │   ├── index-gte-ie8.css
│   │
│   ├── green
│   │   │
│   │   ├── images
│   │   │       │
│   │   │       ├── bg
│   │   │       │   ├── group-bg.png
│   │   │       │
│   │   │       ├── icons
│   │   │            ├── open.png
│   │   │            ├── close.png
│   │   │
│   │   ├── index.css
│   │   ├── index-gte-ie8.css
│   │
│   ├── vendor
│       │
│       ├── nprogress
│       │   │
│       │   ├── nprogress.css
│       │
│       ├── bootstrap
│           │
│           ├── images
│           │   ├── glyphicons-halflings.png
│           │   ├── glyphicons-halflings-white.png
│           │
│           ├── bootstrap.css

├── scripts
│   │
│   ├── libraries
│   │   ├── cookie
│   │   │   ├── cookie.js
│   │   ├── base64
│   │        ├── base64.js
│   │   ├── logger
│   │        ├── logger.js
│   │
│   ├── vendor
│   │   ├── jquery
│   │   │   ├── jquery.min.js
│   │   │   ├── jquery.migrate.js
│   │   │   ├── jquery.csshook.js
│   │   ├── require
│   │   │   ├── require.js
│   │   ├── nprogress
│   │        ├── nprogress.js
│   │
│   ├── routes
│   │   ├── main.url.js
│   │
│   ├── controllers
│   │   ├── calendar.ctrl.js
│   │   ├── search.ctrl.js
│   │
│   ├── models
│   │   ├── calendar.mdl.js
│   │   ├── search.mdl.js
│   │
│   ├── views
│   │   ├── calendar.tpl.js
│   │   ├── search.tpl.js
│   │
│   ├── viewControllers
│   │   ├── calendar.vctrl.js
│   │   ├── search.vctrl.js
│   │
│   ├── internalisation
│   │   ├── en.i18n.js
│   │   ├── ru.i18n.js
│   │
│   ├── helpers
│   │   ├── polyfills.hlp.js
│   │   ├── indexof.hlp.js
│   │   ├── cutcharacters.hlp.js
│   │
│   ├── widgets
│   │   ├── advertisement.wdg.js
│   │
│   ├── tests
│   │   ├── main.tst.js
│   │
│   ├── config.js
│   ├── initialisation.js
│   ├── index.js

├── mp3
│   ├── alarm.mp3

├── swf
│   │
│   ├── vendor
│   │  ├── soundmanager2
│   │        ├── soundmanager2.swf
│   │        ├── soundmanager2_debug.swf
│   │
│   ├── chart.swf

├── node_modules
├── package.json
├── Gruntfile.js
├── rungrunt.js
├── runserver.js

четверг, 30 января 2014 г.

Node JS Quick start functions


var file = require('../fileName');
var file = require('./fileName');
var file = require('./directory/fileName');

function myFunc () {};

if (module.parent) {
    module.exports.myFunc = myFunc;
} else {
    myFunc();
}

var events = require('events').EventEmitter;

events.on('click', function(obj){console.log(obj.a);});
events.emit('click', {a: 1});


function PhraseError () {
    Error.apply(this, arguments); // Вызов конструктора суперкласса - родительского класса. Таким образом все свойства Error попадают в PharaseError
}

// Http server и прослушка событий соединения с сервером

var http = require('http');

var server = new http.Server();

server.listen(1337, '127.0.0.1');

var counter = 0;

var emit = server.emit;

server.emit = function (event) {
    console.log(event);
    emit.apply(server, arguments);
}

server.on('request', function(request, response){
    response.end('Привет, мир!' + ++counter);
});

// Http server и вывод параметров query

var http = require('http');
var url = require('url');

var server = new http.Server(function(request, response){
    console.log(request.method, request.url);
    var urlParsed = url.parse(request.url, true);
    console.log(urlParsed);
    if (urlParsed.pathname === '/echo' && urlParsed.query.message) {
        response.statusCode = 200;
        response.setHeader('Cache-control', 'no-cache');
        response.write('Данные найдены');
        response.write(urlParsed.query.message);
        response.end('' + request.method + ' ' + request.url);
    } else {
        response.statusCode = 404;
        response.end('Page not found');
    }
});

server.listen(1337, '127.0.0.1');

// Использовать модуль supervisor для перезапуска сервера
supervisor server.js

// Дебаг в консоли

var server = new http.Server();

server.listen(1337, '127.0.0.1');

server.on('request', function(request, response){
    debugger; // Прерывание скрипта и вызов дебагера
    response.end('Привет, мир!' + ++counter);
});

node debug server;

// Можно установить npm install node-inspector
Исделать запуск дебаггера для Chrome
node --debug server.js
или
node --debug-brk server.js

// Команда debug вызывает debug в консоли браузера

// Чтение и отдача данных из файла

var http = require('http');
var fs = require('fs');

http.createServer(function(request, response){
    var info;
    if (request.url === '/') {
        info = fs.readFileSync('index.html');
        response.end(info);
    }
}).listen(3000, '127.0.0.1');

// Асинхронное чтение и отдача данных из файла

var http = require('http');
var fs = require('fs');

http.createServer(function(request, response){
    var info;
    if (request.url === '/') {
        fs.readFile('index.html', function(error, info){
            if (error) {
                console.log(error);
                response.end(error);
            }
            response.end(info);
        });
    } else if (request.url === '/now') {
        response.end((new Date()).toString());
    }
}).listen(3000, '127.0.0.1');


// Pipe

var fromReadFile = fs.read('file.txt');

fromReadFile.pipe(toWriteFile);
fromReadFile.pipe(response);
fromReadFile.pipe(process.stdout);

// Отправка данных при нажатии на гиперссылку

<a href="/logout" onclick="$('<form method="post" action="/logout"></form>').submit(); return false;">Выйти</a>

среда, 29 января 2014 г.

JavaScript Интернализация i18n

Файл ru.json

{
      "hello": "Привет"
    , "friend": "друг"
}

Файл index.js

var language = 'ru'
    , phrases = require('./' + language);

function sayHello () {
    console.log(phrases.hello + ', ' +  phrases.friend + '.');
}

sayHello();

вторник, 28 января 2014 г.

Перечисление свойств любого объекта Object.prototype.each

Object.prototype.each = function(f) {
  for (var prop in this) {
    if (!this.hasOwnProperty(prop)) {continue;}
    var value = this[prop];
    f.call(value, prop, value);
  }
};

var obj = { name: 'Вася', age: 25 };

obj.each(function(prop, val) {
  alert(prop); // name -> age
});

String.repeat()

String.prototype.repeat = function(times) {
    return new Array(times+1).join(this);
};

alert( "ля".repeat(3) ); // ляляля

Вызов родительского конструктора внутри функции для обеспечения наследования

function SlidingMenu(menuId) {

    Menu.apply(this, arguments); // (1) Родительский конструктор записывает в объект свойства и методы.

    var parentOpen = this.open;  // (2)

    this.open = function() {        // (3)
        parentOpen();                  // (3.1)
       ...                                      // (3.2)
    };

}

1) Вызов Menu.apply(this, arguments) вызывает функцию-конструктор меню, передавая ей текущий объект this и аргументы.
Она успешно срабатывает, инициализует меню и добавит в this публичные свойства и методы, например this.open.

2) Мы хотим заменить метод this.open() на свой расширенный. Это мы сделаем в следующей строке 3.1, а пока — скопируем родительский метод open в переменную.
Создадим наш собственный this.open(). Он перезапишет тот, который был создан Menu, в строке (1). Чтобы сохранить доступ к старому методу, мы скопировали его в 3.1.
Запустить родительский метод.
Затем наш собственный код…

Потеря constructor при изменении prototype

При создании функции конструктора, её prototype - это объект с единственным свойством constructor, которое указывает на саму функцию конструктор.

function Rabbit() { }

var rabbit = new Rabbit();

alert( rabbit.constructor == Rabbit ); // true

Таким образом, мы можем использовать свойство constructor, чтобы получить функцию-конструктор объекта, но при смене прототипа нужно смотреть, чтобы ненароком не перезаписать его.

function Rabbit(name) {
    this.name = name;
}

var rabbit = new Rabbit('Nick');
var cat = new rabbit.constructor('Ann');

alert(cat.name); // Ann

Свойство prototype есть у каждой функции, даже если его не ставить. Оно создается автоматически вместе с самой функцией, и по умолчанию является пустым объектом с единственным свойством constructor, которое ссылается обратно на функцию.

Вот такой вид имеет прототип по умолчанию:

function Rabbit () {}

Rabbit.prototype = {
  constructor: Rabbit
}

При переопределении прототипа свойство constructor может из него пропасть.

function Rabbit() { }

Rabbit.prototype = {};  // Теперь свойство constructor пропало!!!

var rabbit = new Rabbit();

alert( rabbit.constructor == Object ); // Теперь свойство constructor ссылается на Object, а не Rabbit, так как у Rabbit свойство constructor пропало после переопределения prototype!!!

JavaScript Object.create() polyfill

Можно присвоить Object.create функцию, чтобы иметь унифицированный вызов, но при этом стоит иметь в виду, что современные браузеры поддерживают также дополнительный второй аргумент Object.create, позволяющий задать свойства объекта, а присвоенная функция - нет.

Object.create = Object.create || function (obj) {

    if (arguments.length !== 1) {
        throw new Error('Object.create implementation only accepts one parameter.');
    }

    function F () {}
    F.prototype = obj;
    retun new F();

};

Простое отличие window.onload от DOMContentLoaded

window.onload срабатывает после загрузки всего: построения DOM, загрузки script, css, images и iframe.

DOMContentLoaded срабатывает после загрузки скриптов script, не имеющих атрибутов async и defer и построения DOM. Но, если после стиля идёт скрипт, то этот скрипт обязан дождаться, пока стиль загрузится.

JavaScript проверка наличия Console.log и простейший Дебагер

Самый простой способ вывода информации в консоль без ошибок в тех браузерах, где консоль не поддерживается.

console && console.log && console.log("whatever");

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

;(function () {

    window.console = window.console || {};

    var methods = [
        'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
        'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
        'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
        'timeStamp', 'trace', 'warn'
      ]
    , length = methods.length
    , currentMethod;

    while (length--) {
        currentMethod = methods[length];
        if ( ! window.console[currentMethod] ) {
            window.console[currentMethod] = function () {};
        }
    }

})();

Пример дебагера с использованием консоли.

var debug = {
      enable: true
    , log: function (message) {
        if (this.enable && console && console.log) {
            console.log(message);
        }
    }
};

debug.log('Все работает!');

Пример отсылки логов на сервер для записи их в лог-файл.

var Logger = {

      url: null

    , number: 0

    , log: function (message, url, line) {
        this._sendLog(message, url, line, 'log');
    }

    , debug: function (message, url, line) {
        this._sendLog(message, url, line, 'debug');
    }

    , info: function (message, url, line) {
        this._sendLog(message, url, line, 'info');
    }

    , warn: function (message, url, line) {
        this._sendLog(message, url, line, 'warn');
    }

    , error: function (message, url, line) {
        this._sendLog(message, url, line, 'error');
    }

    , _sendLog: function (message, url, line, level) {
        this.number++;
        var text = this.number + '. ' + message + ' (file: ' + url + (line !== undefined ? ', line: ' + line : '') + ')';
        $.ajax({
              url: this.url
            , type: 'POST'
            , cache: false
            , data: {message: text, level: level}
        });
    }

};

Logger.url = '/log';

Logger.debug('Инициализация констант завершена.', 'menu.html');

window.onerror = function(message, url, line) {
    Logger.error(message, url, line);
};

Приоритет вызовов команд дебагера:
log (1) < debug (2) < info (3) < warn (4) < error (5)

Пример простого Router

router.js

define(function(){
   
    var routes = [
                  {hash:'#list', controller:'ListController'},
                  {hash:'#add',  controller:'AddController'}
    ];
    var defaultRoute = '#list';
    var currentHash = '';
   
    function startRouting(){
        window.location.hash = window.location.hash || defaultRoute;
        setInterval(hashCheck, 100);
    }
   
    function hashCheck(){
        if (window.location.hash != currentHash){
            for (var i = 0, currentRoute; currentRoute = routes[i++];){
                if (window.location.hash == currentRoute.hash)
                    loadController(currentRoute.controller);
            }
            currentHash = window.location.hash;
        }
    }
   
    function loadController(controllerName){
        require(['Controllers/' + controllerName], function(controller){
            controller.start();
        });
    }
   
    return {
        startRouting:startRouting
    };
});

index.js

require(['Models/User', 'Router'], function(User, Router){
   
    var users = [
                 new User('Barney'),
                 new User('Cartman'),
                 new User('Sheldon')
    ];
   
    localStorage.users = JSON.stringify(users);

    Router.startRouting();
});

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

Шпаргалка по работе с DOM

Создание элементов

document.createElement(tag) - создать элемент с тегом tag
document.createTextNode(txt) - создать текстовый узел с текстом txt
node.cloneNode(deep) - клонировать существующий узел, если deep=true то с подузлами.

Свойства узлов

node.nodeType - тип узла: 1(элемент) / 3(текст) / другие.
elem.tagName - тег элемента.
elem.innerHTML - HTML внутри элемента.
node.data - содержимое любого узла любого типа, кроме элемента.

Ссылки

document.documentElement - элемент <HTML>
document.body - элемент <BODY>

По всем узлам:

parentNode
nextSibling previousSibling
childNodes firstChild lastChild

Только по элементам:

Дети: children (В IE 8- также содержит комментарии)
Соседи, кроме IE8-: nextElementSibling previousElementSibling
Дети, кроме IE8-: firstElementChild lastElementChild

Таблицы

table.rows[N] - строка TR номер N.
tr.cells[N] - ячейка TH/TD номер N.
tr.sectionRowIndex - номер строки в таблице в секции THEAD/TBODY.
td.cellIndex - номер ячейки в строке.

Формы

document.forms[N/name] - форма по номеру/имени.
form.elements[N/name] - элемент формы по номеру/имени
element.form - форма для элемента.

Поиск

document.getElementById(id) - По уникальному id
document.getElementsByName(name) - По атрибуту name, в IE<10 работает только для элементов, где name предусмотрен стандартом.
(elem/doc).getElementsByTagName(tag) - По тегу tag
(elem/doc).getElementsByClassName(class) - По классу, IE9+, корректно работает с элементами, у которых несколько классов.
(elem/doc).querySelectorAll(css) - По селектору CSS3, в IE8 по CSS 2.1
(elem/doc).querySelector(css) - По селектору, только первый элемент

Изменение

parent.appendChild(newChild)
parent.removeChild(child)
parent.insertBefore(newChild, refNode)
parent.insertAdjacentHTML("beforeBegin|afterBegin|beforeEnd|afterEnd", html)

Классы и стили

elem.className - Атрибут class
elem.classList.add(class) remove(class) toggle(class) - Управление классами в HTML5, для IE8+ есть эмуляция.
elem.style.display - Стиль в атрибуте style элемента
getComputedStyle(elem, '').display - Стиль с учётом CSS и style на элементе

Размеры и прокрутка элемента

clientLeft/Top - Ширина левой/верхней рамки border
clientWidth/Height - Ширина/высота внутренней части элемента, включая содержимое и padding, не включая полосу прокрутки (если есть).
scrollWidth/Height - Ширина/высота внутренней части элемента, с учетом прокрутки.
scrollLeft/Top - Ширина/высота прокрученной области.
offsetWidth/Height - Полный размер элемента: ширина/высота, включая border.

Размеры и прокрутка страницы

ширина/высота видимой области: document.documentElement.clientHeight
прокрутка(чтение): window.pageYOffset || document.documentElement.scrollTop
прокрутка(изменение): window.scrollBy(x,y): на x,y относительно текущей позиции.
window.scrollTo(pageX, pageY): на координаты в документе.
elem.scrollIntoView(true/false): прокрутить, чтобы elem стал видимым и оказался вверху окна(true) или внизу(false)

Координаты

относительно окна: elem.getBoundingClientRect()
относительно документа: elem.getBoundingClientRect() + прокрутка страницы
получить элемент по координатам: document.elementFromPoint(clientX, clientY)