среда, 23 апреля 2014 г.

Мой JavaScript Router

Внимание!!! Код не проверен!

require.config({
    paths: {
          jquery: 'lib/jquery/jquery'
    }
});

define(['jquery'], function($) {

    // Маршрутизатор
   
    // Добавить URL в маршрутизатор
    // router.add('/edit/user', function(){alert('User.');});
   
    // Добавить сразу несколько URL в маршрутизатор
    // router.add({
    //        '/edit/user': function(){alert('User.');}
    //      , '/update/user':  function(){alert('Update.');}
    //  });
   
    // Добавить URL с переменным параметром
    // router.add('/edit/user/:id', function(id){alert(id);});
   
    // Добавить URL с переменным содержимым
    // router.add('/edit/user/*', function(somethingInURL){alert(somethingInURL);});
   
    // Изменить URL в маршрутизаторе
    // router.update('/edit/user', function(){alert('User.');});
   
    // Изменить сразу несколько URL в маршрутизаторе
    // router.update({
    //        '/edit/user': function(){alert('User.');}
    //      , '/update/user':  function(){alert('Update.');}
    //  });

    // Удалить URL из маршрутизатора
    // router.remove('/edit/user');
   
    // Удалить сразу несколько URL из маршрутизатора
    // router.remove('/edit/user', '/update/user');

    // Перейти по конкретному URL
    // router.go('/edit/user');
   
    // Начать отслеживание изменения URL в адресной строке
    // router.start();
   
    // Остановить отслеживание изменения URL в адресной строке
    // router.stop();

    var router = {

        // Массив для хранения маршрутов URL
       
          routes: []
       
        // Добавление маршрута URL и функции, вызываемой при переходе на него, в массив для хранения маршрутов
       
        , add: function (path, callback) {
            var i
                , len
                , notFoundPath = true;
            if (Object.prototype.toString.call(path) === '[object Object]') {
                for (var key in path) {
                    router.add(key, path[key]);
                }
            } else {
                if (Object.prototype.toString.call(path) === '[object String]') {    
                    path = path
                            .replace(/[-[\]{}()+?.,\\^$|#\s]/g, '\\$&') // ESC
                            .replace(/:([\w\d]+)/g, '([^\/]*)') // ARG_NAMED
                            .replace(/\*([\w\d]+)*/g, '(.*?)'); // ARG_SPLAT
                    path = new RegExp('^' + path + '$');
                }
                for (i = 0, len = router.routes.length; i < len; i++) {
                    if (router.routes[i].path === path) {
                        router.routes[i].path = path;
                        router.routes[i].callback = callback;
                        notFoundPath = false;
                        break;
                    }
                }
                if (notFoundPath) {
                    router.routes.push({
                          'path': path
                        , 'callback': callback
                    });
                }
            }
          }
         
        // Изменение в массиве для хранения маршрутов функции маршрута URL, вызываемой при переходе на него
       
        , update: function (path, callback) {
            var i
                , len
                , notFoundPath = true;
            if (Object.prototype.toString.call(path) === '[object Object]') {
                for (var key in path) {
                    router.add(key, path[key]);
                }
            } else {
                if (Object.prototype.toString.call(path) === '[object String]') {    
                    path = path
                            .replace(/[-[\]{}()+?.,\\^$|#\s]/g, '\\$&') // ESC
                            .replace(/:([\w\d]+)/g, '([^\/]*)') // ARG_NAMED
                            .replace(/\*([\w\d]+)*/g, '(.*?)'); // ARG_SPLAT
                    path = new RegExp('^' + path + '$');
                }
                for (i = 0, len = router.routes.length; i < len; i++) {
                    if (router.routes[i].path === path) {
                        router.routes[i].path = path;
                        router.routes[i].callback = callback;
                        notFoundPath = false;
                        break;
                    }
                }
                if (notFoundPath) {
                    router.routes.push({
                          'path': path
                        , 'callback': callback
                    });
                }
            }
          }
         
        // Удаление маршрута URL и функции, вызываемой при переходе на него, из массива для хранения маршрутов
       
        , remove: function () {
            var tempArray = []
                , argsLength = arguments.length
                , routesLength
                , path
                , i;
            if (argsLength > 0) {
                for (;argsLength--;) {
                    path = arguments[argsLength];
                    path = path
                            .replace(/[-[\]{}()+?.,\\^$|#\s]/g, '\\$&') // ESC
                            .replace(/:([\w\d]+)/g, '([^\/]*)') // ARG_NAMED
                            .replace(/\*([\w\d]+)*/g, '(.*?)'); // ARG_SPLAT
                    path = new RegExp('^' + path + '$');
                    for (i = 0, routesLength = router.routes.length; i < routesLength; i++) {
                        if (router.routes[i].path !== path) {
                            tempArray.push(router.routes[i]);
                        }
                    }
                    router.routes = tempArray;
                }
            }
          }
         
        // Настройка кэширования содержимого и определение поддержки браузером history API
         
        , history: {
              cache: false
            , support: ('history' in window)
          }
         
        // Запуск маршрутизатора для начала отслеживания изменений URL в адресной строке
       
        , start: function () {
            if (router.history.cache) {
                setTimeout(function(){ // Хак для браузеров на основе WebKit
                    $(window).bind('popstate', router.change);
                }, 0);
            } else {
                $(window).bind('hashchange', router.change);
            }
            router.change();
          }
         
        // Остановить отслеживание изменения URL в адресной строке
       
        , stop: function () {
            if (router.history.cache) {
                setTimeout(function(){ // Хак для браузеров на основе WebKit
                    $(window).unbind('popstate', router.change);
                }, 0);
            } else {
                $(window).unbind('hashchange', router.change);
            }
          }

        // Текущий URL в адресной строке
       
        , currentPath: null
       
        // Функция перехода по произвольному URL
       
        , go: function (path) {
            if (router.history.cache) {
                history.cache.pushState({}, document.title, router.getHost() + path);
            } else {
                window.location.hash = path;
            }
          }
         
        // Функция для обработки собтия изменения URL в адресной строке
       
        , change: function() { // Здесь важно ссылаться на router, а не на this, так как метод change вызывается в контексте window, а не в контексте router
            var path = router.history.cache ? router.getPath() : router.getFragment()
                , routesLength = router.routes.length
                , route
                , i;
            if (path === router.currentPath) {return;}
            router.currentPath = path;
            for (i = 0; i < routesLength; i++) {
                route = router.routes[i];
                if (router.match(path, route.path, route.callback)) {return;} // Провести сопоставление текущего URL с маршрутом из массива routes
            }
          }
         
        // Функция для сопоставления текущего URL с маршрутом из массива routes
         
        , match: function (path, routePath, routeCallback) {
            var match = routePath.exec(path) // Выполнить регулярное выражение из маршрута routes для данного пути
                , params;
            if (!match) {return false;}
            params = match.slice(1);
            routeCallback.apply(routeCallback, params);
            return true;
          }

        // Методы для получения различных частей адреса URL
       
        , getPath: function() {
            return window.location.pathname; // Результат: /edit/user/5
          }

        , getHash: function() {
            return window.location.hash; // Результат: #comment-25
          }

        , getHost: function() {
            return ('' + window.location).replace(router.getPath() + router.getHash(), ''); // Результат: http://site.com
          }

        , getFragment: function() {
            return router.getHash().replace(/^#!*/, ''); // Результат: comment-25
          }

    };

    return router;
   
});

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

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