<commit_before>var Util, DOM, CloudFunc;
/* Функция которая возвратит обьект CloudCmd
 * @CloudFunc - обьект содержащий общий функционал
 *  клиентский и серверный
 */
(function(scope, Util, DOM, CloudFunc) {
    'use strict';

    scope.CloudCmd = new CloudCmdProto(Util, DOM, CloudFunc);

    function CloudCmdProto(Util, DOM, CloudFunc) {
        var Key, Config, Modules, Extensions,
            FileTemplate, PathTemplate, LinkTemplate, Listeners,
            CloudCmd                = this,
            Storage                 = DOM.Storage;

        this.LIBDIR                 = '/lib/';
        this.LIBDIRCLIENT           = '/lib/client/';
        this.JSONDIR                = '/json/';
        this.HTMLDIR                = '/html/';
        this.MIN_ONE_PANEL_WIDTH    = 1155;
        this.OLD_BROWSER            = false;
        this.HOST                   =  (function() {
            var lLocation = document.location;
            return lLocation.protocol + '//' + lLocation.host;
        })();

        /**
         * Функция привязываеться ко всем ссылкам и
         *  загружает содержимое каталогов
         *
         * @param pLink - ссылка
         * @param pNeedRefresh - необходимость обязательной загрузки данных с сервера
         */
        this.loadDir                = function(pLink, pNeedRefresh) {
            return function(pEvent) {
                /* показываем гиф загрузки возле пути папки сверху
                 * ctrl+r нажата? */

                var lCurrentLink    = DOM.getCurrentLink(),
                    lHref           = lCurrentLink.href,
                    lLink           = pLink || Util.removeStr(lHref, CloudCmd.HOST);

                lLink += '?json';

                if (lLink || lCurrentLink.target !== '_blank') {
                    DOM.Images.showLoad(pNeedRefresh ? {top:true} : null);

                    /* загружаем содержимое каталога */
                    CloudCmd.ajaxLoad(lLink, { refresh: pNeedRefresh });
                }

                DOM.preventDefault(pEvent);
            };
        };

        /**
         * функция устанавливает курсор на каталог
         * с которого мы пришли, если мы поднялись
         * в верх по файловой структуре
         * @param pDirName - имя каталога с которого мы пришли
         */
        function currentToParent(pDirName) {
            var lRootDir;
            /* убираем слэш с имени каталога */
            pDirName    = Util.removeStr(pDirName, '/');
            lRootDir    = DOM.getCurrentFileByName(pDirName);

            if (lRootDir) {
                DOM.setCurrentFile(lRootDir);
                DOM.scrollIntoViewIfNeeded(lRootDir, true);
            }
        }

        /**
         * function load modules
         * @pParams = {name, path, func, dobefore, arg}
         */
        function loadModule(pParams) {
            var lName, lPath, lFunc, lDoBefore, lSlash, lAfterSlash,
                isContain;

            if (pParams) {
                lName       = pParams.name,
                lPath       = pParams.path,
                lFunc       = pParams.func,
                lDoBefore   = pParams.dobefore;

                if (Util.isString(pParams))
                    lPath = pParams;

                if (lPath && !lName) {
                    lName = Util.getStrBigFirst(lPath);
                    lName = Util.removeStr(lName, '.js');

                    lSlash = lName.indexOf('/');
                    if (lSlash > 0) {
                        lAfterSlash = lName.substr(lSlash);
                        lName = Util.removeStr(lName, lAfterSlash);
                    }
                }

                isContain = Util.isContainStr(lPath, '.js');
                if (!isContain)
                    lPath += '.js';

                if (!CloudCmd[lName]) {
                    CloudCmd[lName] = function(pArg) {
                        var path = CloudCmd.LIBDIRCLIENT + lPath;

                        Util.exec(lDoBefore);

                        return DOM.jsload(path, lFunc ||
                            function() {
                                var Proto = CloudCmd[lName];

                                if (Util.isFunction(Proto))
                                    CloudCmd[lName] = new Proto(pArg);
                            });
                    };

                    CloudCmd[lName].show = CloudCmd[lName];
                }
            }
        }

        /** Конструктор CloudClient, который
         * выполняет весь функционал по
         * инициализации
         */
        this.init                    = function() {
            var lCallBack, lFunc;

            lCallBack = function() {
                Util.loadOnLoad([
                    Util.retFunc(CloudCmd.route, location.hash),
                    baseInit,
                    initModules,
                ]);
            },
            lFunc = function(pCallBack) {
                CloudCmd.OLD_BROWSER = true;
                var lSrc = CloudCmd.LIBDIRCLIENT + 'polyfill.js';

                DOM.jqueryLoad(
                    DOM.retJSLoad(lSrc, pCallBack)
                );
            };

            Util.ifExec(document.body.scrollIntoViewIfNeeded, lCallBack, lFunc);
        };

        this.route                   = function(pPath) {
            var lQuery, lModule, lFile, lCurrent, lMsg;

            if (pPath.length > 0) {
                lQuery  = pPath.split('/');

                if (lQuery.length > 0) {
                    lModule     = Util.getStrBigFirst(lQuery[1]);
                    lFile       = lQuery[2];
                    lCurrent    = DOM.getCurrentFileByName(lFile);
                    if (lFile && !lCurrent) {
                        lMsg = CloudFunc.formatMsg('set current file', lFile, 'error');
                        Util.log(lMsg);
                    } else {
                        DOM.setCurrentFile(lCurrent);
                        CloudCmd.execFromModule(lModule, 'show');
                    }
                }
            }
        };

        function initModules(pCallBack) {
            Util.ifExec(CloudCmd.Key, function() {
                Key          = new CloudCmd.Key();
                CloudCmd.Key = Key;
                Key.bind();
            }, function(callback) {
                loadModule({
                    /* привязываем клавиши к функциям */
                    path  : 'key.js',
                    func : callback
                 });
             });

            CloudCmd.getModules(function(pModules) {
                pModules                = pModules || [];

                var i, n, lStorage            = 'storage',
                    lShowLoadFunc       = Util.retFunc( DOM.Images.showLoad, {top:true} ),

                    lDoBefore           = {
                        'edit'  : lShowLoadFunc,
                        'view'  : lShowLoadFunc,
                        'menu'  : lShowLoadFunc
                    },

                    lLoad = function(pName, pPath, pDoBefore) {
                        loadModule({
                            path        : pPath,
                            name        : pName,
                            dobefore    : pDoBefore
                        });
                    };

                for (i = 0, n = pModules.length; i < n ; i++) {
                    var lModule = pModules[i];

                    if ( Util.isString(lModule) )
                        lLoad(null, lModule, lDoBefore[lModule]);
                }

                var lStorageObj = Util.findObjByNameInArr( pModules, lStorage ),
                    lMod        = Util.getNamesFromObjArray( lStorageObj );

                for (i = 0, n = lMod.length; i < n; i++) {
                    var lName = lMod[i],
                        lPath = lStorage + '/_' + lName.toLowerCase();

                    lLoad(lName, lPath);
                }

                Util.exec(pCallBack);

            });
        }

        function baseInit(pCallBack) {
            var LIB         = CloudCmd.LIBDIR,
                LIBCLIENT   = CloudCmd.LIBDIRCLIENT,
                files       = DOM.getFiles();

            /* выделяем строку с первым файлом                                  */
            if (files)
                DOM.setCurrentFile(files[0]);

            Listeners = CloudCmd.Listeners;
            Listeners.init();
            /* загружаем Google Analytics */
            Listeners.analytics();
            Listeners.changeLinks('js-' + CloudFunc.LEFTPANEL);
            Listeners.changeLinks('js-' + CloudFunc.RIGHTPANEL);

            Listeners.initKeysPanel();

            CloudCmd.getConfig(function(config) {
                var localStorage    = config.localStorage,
                    dirPath         = DOM.getCurrentDirPath();

                /* устанавливаем переменную доступности кэша                    */
                Storage.setAllowed(localStorage);
                /* Устанавливаем кэш корневого каталога                         */

                dirPath     = CloudFunc.rmLastSlash(dirPath) || '/';

                if (!Storage.get(dirPath))
                    Storage.set(dirPath, getJSONfromFileTable());
                });

            Util.exec(CloudCmd.Key);
            Util.exec(pCallBack);
        }

        function getSystemFile(pGlobal, pURL) {

            function lGetSysFile(pCallBack) {
                Util.ifExec(pGlobal, pCallBack, function(pCallBack) {
                    DOM.ajax({
                        url     : pURL,
                        success : function(pLocal) {
                            pGlobal = pLocal;
                            Util.exec(pCallBack, pLocal);
                        }
                    });
                });
            }

            return lGetSysFile;
        }

        this.setConfig              = function(config) { Config = config; };
        this.getConfig              = getSystemFile(Config,         CloudCmd.JSONDIR + 'config.json');
        this.getModules             = getSystemFile(Modules,        CloudCmd.JSONDIR + 'modules.json');
        this.getExt                 = getSystemFile(Extensions,        CloudCmd.JSONDIR + 'ext.json');
        this.getFileTemplate        = getSystemFile(FileTemplate,   CloudCmd.HTMLDIR + 'file.html');
        this.getPathTemplate        = getSystemFile(PathTemplate,   CloudCmd.HTMLDIR + 'path.html');
        this.getLinkTemplate        = getSystemFile(PathTemplate,   CloudCmd.HTMLDIR + 'link.html');

        this.execFromModule         = function(pModuleName, pFuncName, pParams) {
            var lObject     = CloudCmd[pModuleName];
            Util.ifExec(Util.isObject(lObject),
                function() {
                    var lObj = CloudCmd[pModuleName];
                    Util.exec( lObj[pFuncName], pParams);
                },

                function(pCallBack) {
                    Util.exec(lObject, pCallBack);
                });
        };

        this.refresh                =  function(pCurrent) {
            var lNEEDREFRESH    = true,
                lPanel          = pCurrent && pCurrent.parentElement,
                lPath           = DOM.getCurrentDirPath(lPanel),
                lLink           = CloudFunc.FS + lPath,
                lNotSlashlLink  = CloudFunc.rmLastSlash(lLink),
                lLoad           = CloudCmd.loadDir(lNotSlashlLink, lNEEDREFRESH);

            lLoad();
        };

        /**
         * Функция загружает json-данные о Файловой Системе
         * через ajax-запрос.
         * @param path - каталог для чтения
         * @param pOptions
         * { refresh, nohistory } - необходимость обновить данные о каталоге
         */
        this.ajaxLoad               = function(pPath, pOptions) {
            if (!pOptions)
                pOptions    = {};

            /* Отображаем красивые пути */
            var lSLASH      = '/',
                lFSPath     = decodeURI(pPath),
                lNOJSPath   = Util.removeStr( lFSPath, '?json' ),
                lCleanPath  = Util.removeStrOneTime( lNOJSPath, CloudFunc.FS   ) || lSLASH,

                lOldURL = window.location.pathname;

            if (lCleanPath === lSLASH)
                lNOJSPath = lSLASH;

            Util.log ('reading dir: "' + lCleanPath + '";');

            if (!pOptions.nohistory)
                DOM.setHistory(lNOJSPath, null, lNOJSPath);

            DOM.setTitle( CloudFunc.getTitle(lCleanPath) );

             /* если доступен localStorage и
              * в нём есть нужная нам директория -
              * читаем данные с него и
              * выходим
              * если стоит поле обязательной перезагрузки -
              * перезагружаемся
              */
            var lRet = pOptions.refresh;
            if (!lRet) {
                var lJSON = Storage.get(lCleanPath);

                if (lJSON) {
                    lJSON = Util.parseJSON(lJSON);
                    CloudCmd.createFileTable(lJSON);
                }
                else
                    lRet = true;
            }

            if (lRet)
                DOM.getCurrentFileContent({
                    url     : lFSPath,

                    dataType: 'json',

                    error   : function() {
                        DOM.setHistory(lOldURL, null, lOldURL);
                    },

                    success : function(pData) {
                        CloudCmd.createFileTable(pData);

                        /* переводим таблицу файлов в строку, для   *
                         * сохранения в localStorage                */
                        var lJSON_s = Util.stringifyJSON(pData);
                        Util.log(lJSON_s.length);

                        /* если размер данных не очень бошьой       *
                         * сохраняем их в кэше                      */
                        if (lJSON_s.length < 50000 )
                            Storage.set(lCleanPath, lJSON_s);
                    }
                });
        };

        /**
         * Функция строит файловую таблицу
         * @param pJSON  - данные о файлах
         */
        this.createFileTable        = function(pJSON) {
            var files,
                panel           = DOM.getPanel(),
                /* getting current element if was refresh */
                lPath           = DOM.getCurrentDirPath(panel),

                lCurrent        = DOM.getCurrentFile(),
                lDir            = DOM.getCurrentDirName(),

                lName           = DOM.getCurrentName(lCurrent),
                wasRefresh      = lPath === pJSON.path,
                lFuncs          = [
                    CloudCmd.getFileTemplate,
                    CloudCmd.getPathTemplate,
                    CloudCmd.getLinkTemplate
                ];

            Util.asyncCall(lFuncs, function(pTemplate, pPathTemplate, pLinkTemplate) {
                /* очищаем панель */
                var n, found,
                    i = panel.childNodes.length;

                while(i--)
                    panel.removeChild(panel.lastChild);

                panel.innerHTML = CloudFunc.buildFromJSON(pJSON, pTemplate, pPathTemplate, pLinkTemplate);

                files = DOM.getFiles(panel);

                /* searching current file */
                if (wasRefresh) {
                    n = files.length;

                    for (i = 0; i < n ; i++) {
                        var lVarCurrent = files[i],
                            lVarName    = DOM.getCurrentName(lVarCurrent);

                        found = lVarName === lName;

                        if (found) {
                            lCurrent    = files[i];
                            break;
                        }
                    }
                }
                if (!found) /* .. */
                    lCurrent = files[0];

                DOM.setCurrentFile(lCurrent);

                Listeners.changeLinks(panel.id);

                if (lName === '..' && lDir !== '/')
                    currentToParent(lDir);
            });
        };

        /**
         * Функция генерирует JSON из html-таблицы файлов и
         * используеться при первом заходе в корень
         */
        function getJSONfromFileTable() {
            var lLeft       = DOM.getById('js-left'),
                lPath       = DOM.getByClass('path')[0].textContent,

                lFileTable  = {
                    path    : lPath,
                    files   : []
                },

                files       = lFileTable.files,

                lLI         = DOM.getByTag('li', lLeft),
                i, n        = lLI.length;

            for (i = 0; i < n; i++) {
                var lCurrent    = lLI[i],
                    lName       = DOM.getCurrentName(lCurrent),
                    lSize       = DOM.getCurrentSize(lCurrent),

                lMode           = DOM.getCurrentMode(lCurrent);
                lMode           = CloudFunc.getNumericPermissions(lMode);

                if (lName !== '..')
                    lFileTable.files.push({
                        name: lName,
                        size: lSize,
                        mode: lMode
                    });
            }
            return Util.stringifyJSON(lFileTable);
        }
    }
})(this, Util, DOM, CloudFunc);
<commit_msg>refactor(client) getJSONfromFileTable<commit_after>var Util, DOM, CloudFunc;
/* Функция которая возвратит обьект CloudCmd
 * @CloudFunc - обьект содержащий общий функционал
 *  клиентский и серверный
 */
(function(scope, Util, DOM, CloudFunc) {
    'use strict';

    scope.CloudCmd = new CloudCmdProto(Util, DOM, CloudFunc);

    function CloudCmdProto(Util, DOM, CloudFunc) {
        var Key, Config, Modules, Extensions,
            FileTemplate, PathTemplate, LinkTemplate, Listeners,
            CloudCmd                = this,
            Storage                 = DOM.Storage;

        this.LIBDIR                 = '/lib/';
        this.LIBDIRCLIENT           = '/lib/client/';
        this.JSONDIR                = '/json/';
        this.HTMLDIR                = '/html/';
        this.MIN_ONE_PANEL_WIDTH    = 1155;
        this.OLD_BROWSER            = false;
        this.HOST                   =  (function() {
            var lLocation = document.location;
            return lLocation.protocol + '//' + lLocation.host;
        })();

        /**
         * Функция привязываеться ко всем ссылкам и
         *  загружает содержимое каталогов
         *
         * @param pLink - ссылка
         * @param pNeedRefresh - необходимость обязательной загрузки данных с сервера
         */
        this.loadDir                = function(pLink, pNeedRefresh) {
            return function(pEvent) {
                /* показываем гиф загрузки возле пути папки сверху
                 * ctrl+r нажата? */

                var lCurrentLink    = DOM.getCurrentLink(),
                    lHref           = lCurrentLink.href,
                    lLink           = pLink || Util.removeStr(lHref, CloudCmd.HOST);

                lLink += '?json';

                if (lLink || lCurrentLink.target !== '_blank') {
                    DOM.Images.showLoad(pNeedRefresh ? {top:true} : null);

                    /* загружаем содержимое каталога */
                    CloudCmd.ajaxLoad(lLink, { refresh: pNeedRefresh });
                }

                DOM.preventDefault(pEvent);
            };
        };

        /**
         * функция устанавливает курсор на каталог
         * с которого мы пришли, если мы поднялись
         * в верх по файловой структуре
         * @param pDirName - имя каталога с которого мы пришли
         */
        function currentToParent(pDirName) {
            var lRootDir;
            /* убираем слэш с имени каталога */
            pDirName    = Util.removeStr(pDirName, '/');
            lRootDir    = DOM.getCurrentFileByName(pDirName);

            if (lRootDir) {
                DOM.setCurrentFile(lRootDir);
                DOM.scrollIntoViewIfNeeded(lRootDir, true);
            }
        }

        /**
         * function load modules
         * @pParams = {name, path, func, dobefore, arg}
         */
        function loadModule(pParams) {
            var lName, lPath, lFunc, lDoBefore, lSlash, lAfterSlash,
                isContain;

            if (pParams) {
                lName       = pParams.name,
                lPath       = pParams.path,
                lFunc       = pParams.func,
                lDoBefore   = pParams.dobefore;

                if (Util.isString(pParams))
                    lPath = pParams;

                if (lPath && !lName) {
                    lName = Util.getStrBigFirst(lPath);
                    lName = Util.removeStr(lName, '.js');

                    lSlash = lName.indexOf('/');
                    if (lSlash > 0) {
                        lAfterSlash = lName.substr(lSlash);
                        lName = Util.removeStr(lName, lAfterSlash);
                    }
                }

                isContain = Util.isContainStr(lPath, '.js');
                if (!isContain)
                    lPath += '.js';

                if (!CloudCmd[lName]) {
                    CloudCmd[lName] = function(pArg) {
                        var path = CloudCmd.LIBDIRCLIENT + lPath;

                        Util.exec(lDoBefore);

                        return DOM.jsload(path, lFunc ||
                            function() {
                                var Proto = CloudCmd[lName];

                                if (Util.isFunction(Proto))
                                    CloudCmd[lName] = new Proto(pArg);
                            });
                    };

                    CloudCmd[lName].show = CloudCmd[lName];
                }
            }
        }

        /** Конструктор CloudClient, который
         * выполняет весь функционал по
         * инициализации
         */
        this.init                    = function() {
            var lCallBack, lFunc;

            lCallBack = function() {
                Util.loadOnLoad([
                    Util.retFunc(CloudCmd.route, location.hash),
                    baseInit,
                    initModules,
                ]);
            },
            lFunc = function(pCallBack) {
                CloudCmd.OLD_BROWSER = true;
                var lSrc = CloudCmd.LIBDIRCLIENT + 'polyfill.js';

                DOM.jqueryLoad(
                    DOM.retJSLoad(lSrc, pCallBack)
                );
            };

            Util.ifExec(document.body.scrollIntoViewIfNeeded, lCallBack, lFunc);
        };

        this.route                   = function(pPath) {
            var lQuery, lModule, lFile, lCurrent, lMsg;

            if (pPath.length > 0) {
                lQuery  = pPath.split('/');

                if (lQuery.length > 0) {
                    lModule     = Util.getStrBigFirst(lQuery[1]);
                    lFile       = lQuery[2];
                    lCurrent    = DOM.getCurrentFileByName(lFile);
                    if (lFile && !lCurrent) {
                        lMsg = CloudFunc.formatMsg('set current file', lFile, 'error');
                        Util.log(lMsg);
                    } else {
                        DOM.setCurrentFile(lCurrent);
                        CloudCmd.execFromModule(lModule, 'show');
                    }
                }
            }
        };

        function initModules(pCallBack) {
            Util.ifExec(CloudCmd.Key, function() {
                Key          = new CloudCmd.Key();
                CloudCmd.Key = Key;
                Key.bind();
            }, function(callback) {
                loadModule({
                    /* привязываем клавиши к функциям */
                    path  : 'key.js',
                    func : callback
                 });
             });

            CloudCmd.getModules(function(pModules) {
                pModules                = pModules || [];

                var i, n, lStorage            = 'storage',
                    lShowLoadFunc       = Util.retFunc( DOM.Images.showLoad, {top:true} ),

                    lDoBefore           = {
                        'edit'  : lShowLoadFunc,
                        'view'  : lShowLoadFunc,
                        'menu'  : lShowLoadFunc
                    },

                    lLoad = function(pName, pPath, pDoBefore) {
                        loadModule({
                            path        : pPath,
                            name        : pName,
                            dobefore    : pDoBefore
                        });
                    };

                for (i = 0, n = pModules.length; i < n ; i++) {
                    var lModule = pModules[i];

                    if ( Util.isString(lModule) )
                        lLoad(null, lModule, lDoBefore[lModule]);
                }

                var lStorageObj = Util.findObjByNameInArr( pModules, lStorage ),
                    lMod        = Util.getNamesFromObjArray( lStorageObj );

                for (i = 0, n = lMod.length; i < n; i++) {
                    var lName = lMod[i],
                        lPath = lStorage + '/_' + lName.toLowerCase();

                    lLoad(lName, lPath);
                }

                Util.exec(pCallBack);

            });
        }

        function baseInit(pCallBack) {
            var LIB         = CloudCmd.LIBDIR,
                LIBCLIENT   = CloudCmd.LIBDIRCLIENT,
                files       = DOM.getFiles();

            /* выделяем строку с первым файлом                                  */
            if (files)
                DOM.setCurrentFile(files[0]);

            Listeners = CloudCmd.Listeners;
            Listeners.init();
            /* загружаем Google Analytics */
            Listeners.analytics();
            Listeners.changeLinks('js-' + CloudFunc.LEFTPANEL);
            Listeners.changeLinks('js-' + CloudFunc.RIGHTPANEL);

            Listeners.initKeysPanel();

            CloudCmd.getConfig(function(config) {
                var localStorage    = config.localStorage,
                    dirPath         = DOM.getCurrentDirPath();

                /* устанавливаем переменную доступности кэша                    */
                Storage.setAllowed(localStorage);
                /* Устанавливаем кэш корневого каталога                         */

                dirPath     = CloudFunc.rmLastSlash(dirPath) || '/';

                if (!Storage.get(dirPath))
                    Storage.set(dirPath, getJSONfromFileTable());
                });

            Util.exec(CloudCmd.Key);
            Util.exec(pCallBack);
        }

        function getSystemFile(pGlobal, pURL) {

            function lGetSysFile(pCallBack) {
                Util.ifExec(pGlobal, pCallBack, function(pCallBack) {
                    DOM.ajax({
                        url     : pURL,
                        success : function(pLocal) {
                            pGlobal = pLocal;
                            Util.exec(pCallBack, pLocal);
                        }
                    });
                });
            }

            return lGetSysFile;
        }

        this.setConfig              = function(config) { Config = config; };
        this.getConfig              = getSystemFile(Config,         CloudCmd.JSONDIR + 'config.json');
        this.getModules             = getSystemFile(Modules,        CloudCmd.JSONDIR + 'modules.json');
        this.getExt                 = getSystemFile(Extensions,        CloudCmd.JSONDIR + 'ext.json');
        this.getFileTemplate        = getSystemFile(FileTemplate,   CloudCmd.HTMLDIR + 'file.html');
        this.getPathTemplate        = getSystemFile(PathTemplate,   CloudCmd.HTMLDIR + 'path.html');
        this.getLinkTemplate        = getSystemFile(PathTemplate,   CloudCmd.HTMLDIR + 'link.html');

        this.execFromModule         = function(pModuleName, pFuncName, pParams) {
            var lObject     = CloudCmd[pModuleName];
            Util.ifExec(Util.isObject(lObject),
                function() {
                    var lObj = CloudCmd[pModuleName];
                    Util.exec( lObj[pFuncName], pParams);
                },

                function(pCallBack) {
                    Util.exec(lObject, pCallBack);
                });
        };

        this.refresh                =  function(pCurrent) {
            var lNEEDREFRESH    = true,
                lPanel          = pCurrent && pCurrent.parentElement,
                lPath           = DOM.getCurrentDirPath(lPanel),
                lLink           = CloudFunc.FS + lPath,
                lNotSlashlLink  = CloudFunc.rmLastSlash(lLink),
                lLoad           = CloudCmd.loadDir(lNotSlashlLink, lNEEDREFRESH);

            lLoad();
        };

        /**
         * Функция загружает json-данные о Файловой Системе
         * через ajax-запрос.
         * @param path - каталог для чтения
         * @param pOptions
         * { refresh, nohistory } - необходимость обновить данные о каталоге
         */
        this.ajaxLoad               = function(pPath, pOptions) {
            if (!pOptions)
                pOptions    = {};

            /* Отображаем красивые пути */
            var lSLASH      = '/',
                lFSPath     = decodeURI(pPath),
                lNOJSPath   = Util.removeStr( lFSPath, '?json' ),
                lCleanPath  = Util.removeStrOneTime( lNOJSPath, CloudFunc.FS   ) || lSLASH,

                lOldURL = window.location.pathname;

            if (lCleanPath === lSLASH)
                lNOJSPath = lSLASH;

            Util.log ('reading dir: "' + lCleanPath + '";');

            if (!pOptions.nohistory)
                DOM.setHistory(lNOJSPath, null, lNOJSPath);

            DOM.setTitle( CloudFunc.getTitle(lCleanPath) );

             /* если доступен localStorage и
              * в нём есть нужная нам директория -
              * читаем данные с него и
              * выходим
              * если стоит поле обязательной перезагрузки -
              * перезагружаемся
              */
            var lRet = pOptions.refresh;
            if (!lRet) {
                var lJSON = Storage.get(lCleanPath);

                if (lJSON) {
                    lJSON = Util.parseJSON(lJSON);
                    CloudCmd.createFileTable(lJSON);
                }
                else
                    lRet = true;
            }

            if (lRet)
                DOM.getCurrentFileContent({
                    url     : lFSPath,

                    dataType: 'json',

                    error   : function() {
                        DOM.setHistory(lOldURL, null, lOldURL);
                    },

                    success : function(pData) {
                        CloudCmd.createFileTable(pData);

                        /* переводим таблицу файлов в строку, для   *
                         * сохранения в localStorage                */
                        var lJSON_s = Util.stringifyJSON(pData);
                        Util.log(lJSON_s.length);

                        /* если размер данных не очень бошьой       *
                         * сохраняем их в кэше                      */
                        if (lJSON_s.length < 50000 )
                            Storage.set(lCleanPath, lJSON_s);
                    }
                });
        };

        /**
         * Функция строит файловую таблицу
         * @param pJSON  - данные о файлах
         */
        this.createFileTable        = function(pJSON) {
            var files,
                panel           = DOM.getPanel(),
                /* getting current element if was refresh */
                lPath           = DOM.getCurrentDirPath(panel),

                lCurrent        = DOM.getCurrentFile(),
                lDir            = DOM.getCurrentDirName(),

                lName           = DOM.getCurrentName(lCurrent),
                wasRefresh      = lPath === pJSON.path,
                lFuncs          = [
                    CloudCmd.getFileTemplate,
                    CloudCmd.getPathTemplate,
                    CloudCmd.getLinkTemplate
                ];

            Util.asyncCall(lFuncs, function(pTemplate, pPathTemplate, pLinkTemplate) {
                /* очищаем панель */
                var n, found,
                    i = panel.childNodes.length;

                while(i--)
                    panel.removeChild(panel.lastChild);

                panel.innerHTML = CloudFunc.buildFromJSON(pJSON, pTemplate, pPathTemplate, pLinkTemplate);

                files = DOM.getFiles(panel);

                /* searching current file */
                if (wasRefresh) {
                    n = files.length;

                    for (i = 0; i < n ; i++) {
                        var lVarCurrent = files[i],
                            lVarName    = DOM.getCurrentName(lVarCurrent);

                        found = lVarName === lName;

                        if (found) {
                            lCurrent    = files[i];
                            break;
                        }
                    }
                }
                if (!found) /* .. */
                    lCurrent = files[0];

                DOM.setCurrentFile(lCurrent);

                Listeners.changeLinks(panel.id);

                if (lName === '..' && lDir !== '/')
                    currentToParent(lDir);
            });
        };

        /**
         * Функция генерирует JSON из html-таблицы файлов и
         * используеться при первом заходе в корень
         */
        function getJSONfromFileTable() {
            var current, name, size, mode, owner, ret,
                left        = DOM.getById('js-left'),
                path        = DOM.getByClass('path')[0].textContent,

                fileTable  = {
                    path    : path,
                    files   : []
                },

                files       = fileTable.files,

                li         = DOM.getByTag('li', left),
                i, n        = li.length;

            for (i = 0; i < n; i++) {
                current     = li[i];
                name        = DOM.getCurrentName(current);
                size        = DOM.getCurrentSize(current);
                owner       = DOM.getCurrentOwner(current);
                mode        = DOM.getCurrentMode(current);

                mode        = CloudFunc.getNumericPermissions(mode);

                if (name !== '..')
                    files.push({
                        name: name,
                        size: size,
                        mode: mode
                    });
            }

            ret = Util.stringifyJSON(fileTable);

            return ret;
        }
    }
})(this, Util, DOM, CloudFunc);
<|endoftext|>


<commit_before>
var util = require('util');
var domHelpers = require('./helpers-dom.js');

var WHITE_SPACE = /\s+/g;
var NEWLINE_NORMALIZE = /([ ]*)\n([ ]*)/g;
var DOUBLE_NEWLINE_NORMALIZE = /([\n]*)\n\n([\n]*)/g;

//
// Simple DOM:
// > like object structure, this is what they have in common
//  - `.type` is a string (root, text, element)
//  - `.parent` refer to the nodes parrent
//  - `.position` is the tag number from top to down
//  - `.children` is an array of the elements children
//  - `.append` adds a node to this node
//  - `.element` return the actual element
//

//
// Node
//  General abstaction between all node types
//  The rule is that this should contain the most obviouse implementation
//
function Node(type, parent) {
  this.type = type;
  this.parent = parent;

  // The specific constructor will set another value if necessary
  this.textLength = 0;

  this.tags = 0;
  this.position = -1;
  this.density = -1;

  this.children = [];

  this.text = '';
  this.textCompiled = false;
}

// Calculate the internal subStringLength and subTags properties
Node.prototype._updateCounters = function () {
  if (domHelpers.NO_TEXT_ELEMENTS.hasOwnProperty(this.tagname)) return;

  for (var i = 0, l = this.children.length; i < l; i++) {
    this.textLength += this.children[i].textLength;
    this.tags += this.children[i].tags;
  }
};

// Calculate the density
Node.prototype._updateDensity = function () {
  this.density = (this.tags === 0) ?
    this.textLength : this.textLength / this.tags;
};

Node.prototype.getText = function () {
  if (this.textCompiled === true) return this.text;

  for (var i = 0, l = this.children.length; i < l; i++) {
    var subnode = this.children[i];

    if (subnode.type === 'text') {
      this.text += this.children[i].text;
    }
    else if (subnode.type === 'element' && subnode.tagname === 'br') {
      this.text += '\n';
    }
    else if (subnode.type === 'element' &&
            domHelpers.BLOCK_ELEMENTS.hasOwnProperty(subnode.tagname) === true) {
      this.text += '\n\n' + subnode.getText() + '\n\n';
    }
    else if (domHelpers.NO_TEXT_ELEMENTS.hasOwnProperty(subnode.tagname) === false) {
      this.text += subnode.getText();
    }
  }

  this.text = this.text
    // Make sure that space don't surround newline
    .replace(NEWLINE_NORMALIZE, '\n')
    // Make sure that there is no more than two newlines after each other
    .replace(DOUBLE_NEWLINE_NORMALIZE, '\n\n');

  this.textCompiled = true;

  return this.text;
};

Node.prototype.remove = function () {
  if (this.parent) {
    // Remove this node
    var index = this.parent.children.indexOf(this);
    if (index !== -1) {
      this.parent.children.splice(index, 1);
    }

    // Set up all the parents to recalculate the text
    if (this.textLength !== 0) {
      var parent = this;
      while (parent = parent.parent) {
        parent.textCompiled = false;
        parent.text = '';
      }
    }
  }
};

Node.prototype.before = function () {
  var index = this.parent.children.indexOf(this);
  if (index === 0) return this.parent;
  return this.parent.children[index - 1];
};

Node.prototype.after = function () {
  var index = this.parent.children.indexOf(this);
  if (index === this.parent.children.length - 1) return this.parent;
  return this.parent.children[index + 1];
};

//
// RootNode
//   has no parent, tagname or attribute
//
function RootNode() {
  Node.call(this, 'root', null);
  this.position = 0;
  this.blocky = true;

  // Setup microdata root
  this.micro = new MicrodataRoot(this);
}
util.inherits(RootNode, Node);
exports.RootNode = RootNode;

RootNode.prototype.append = function (child) {
  this.children.push(child);

  return child;
};

RootNode.prototype.close = function () {
  this._updateCounters();
  this._updateDensity();

  return null;
};

RootNode.prototype.element = function () {
  return this;
};

//
// FragmentNode
//   has parent and children, but no tagname or attribute
//
function FragmentNode(parent) {
  Node.call(this, 'fragment', parent);
}
util.inherits(FragmentNode, Node);
exports.FragmentNode = FragmentNode;

FragmentNode.prototype.append = function (child) {
  this.children.push(child);

  return child;
};

FragmentNode.prototype.close = function () {
  return this.parent;
};

FragmentNode.prototype.element = function () {
  return this;
};

FragmentNode.prototype.assign = function (node) {
  node.children = this.children;
};

//
// TextNode
//   has a parent and a text containter
//
function TextNode(parent, text) {
  Node.call(this, 'text', parent);

  // A text node has no children instead it has a text container
  this.children = null;
  this.text = text;
  this.blocky = false;
  this.blockyChildren = false;
}
util.inherits(TextNode, Node);
exports.TextNode = TextNode;

TextNode.prototype.append = function (node) {
  if (node.type === 'text') {
    this.text += node.text;
    return this;
  } else {
    // Since the text there are to follow no will not be appended to this text
    // node close it
    this._textClose();

    // the parrent will assign a position
    this.parent.append(node);
    return node;
  }
};

TextNode.prototype._textClose = function () {
  this.text = this.text.replace(WHITE_SPACE, ' ');
  this.textCompiled = true;

  this.textLength = this.text.length;
  this._updateDensity();
};

TextNode.prototype.close = function () {
  this._textClose();

  return this.parent.close();
};

TextNode.prototype.element = function () {
  return this.parent;
};

//
// ElementNode
//   has a parent, tagname and attributes
//
function ElementNode(parent, tagname, attributes) {
  Node.call(this, 'element', parent);

  // Since this is an element there will minimum one tag
  this.tags = (tagname === 'br' || tagname === 'wbr') ? 0 : 1;

  // Element nodes also has a tagname and an attribute collection
  this.tagname = tagname;
  this.attr = attributes;
  this.classes = attributes.hasOwnProperty('class') ?
    attributes['class'].split(WHITE_SPACE) : [];

  // Setup microdata scrope or item
  if (attributes.hasOwnProperty('itemscope')) {
    this.micro = new MircodataScope(this);
  } else if (attributes.hasOwnProperty('itemprop')) {
    this.micro = new MircodataItem(this);
  } else {
    this.micro = null;
  }

  this.blocky = domHelpers.BLOCK_ELEMENTS.hasOwnProperty(tagname);
  this.blockyChildren = false;
}
util.inherits(ElementNode, Node);
exports.ElementNode = ElementNode;

ElementNode.prototype.append = function (child) {
  this.children.push(child);

  return child;
};

ElementNode.prototype.close = function () {
  this._updateCounters();
  this._updateDensity();

  // Check if a none blocky element contains a blocky element
  for (var i = 0, l = this.children.length; i < l; i++) {
    if (this.children[i].blocky === true) {
      this.blocky = true;
      this.blockyChildren = true;
      break;
    }
  }

  return this.parent;
};

ElementNode.prototype.element = function () {
  return this;
};

//
// Microdata DOM
// > A sort of subspace/sub-DOM for microdata
//  - `.type` is a string (root, scope, item)
//  - `.scope` itemtype value
//  - `.parent` refer to microdata container of this dataobject
//  - `.properties` an object of arrays, the `name` is the key and dataobjects are items
//  - `.key` itemprop value
//  - `.value` the assotiated value
//  - `.node` an reference to the node which the microdata is attached to
//
// NOTE: itemrefs and itemid are at this point not supported
//
// Information source:
// * http://diveintohtml5.info/extensibility.html
// * http://html5doctor.com/microdata/
//

//
// Mircodata
//  shared logic between all dataobjects
//
function Microdata(node, type) {
  this.node = node;
  this.type = type;

  // Find the parent
  var parentNode = this.node;
  while(parentNode = parentNode.parent) {
    if (parentNode.micro &&
       (parentNode.micro.type === 'root' || parentNode.micro.type === 'scope')) {
      break;
    }
  }
  this.parent = parentNode ? parentNode.micro : null;

  // Set the root reference
  this._root = parentNode ? parentNode.micro._root : this;
}

Microdata.prototype._appendProperty = function (item) {
  for (var i = 0, l = item.keys.length; i < l; i++) {
    if (Array.isArray(this.properties[item.keys[i]])) {
      this.properties[item.keys[i]].push(item);
    } else {
      this.properties[item.keys[i]] = [item];
    }
  }
};

Microdata.prototype._setKey = function () {
  if (this.node.attr.hasOwnProperty('itemprop')) {
    this.keys = this.node.attr.itemprop.split(WHITE_SPACE);
    this.parent._appendProperty(this);
  } else {
    this.keys = false;
  }
};

//
// MicrodataRoot
//  has only properties if that even exists
//
function MicrodataRoot(node) {
  Microdata.call(this, node, 'root');

  this.properties = {};
  this.scopes = {};
  this.value = null;
  this.scope = null;

  this.keys = null;
}
util.inherits(MicrodataRoot, Microdata);

MicrodataRoot.prototype._appendScope = function (item) {
  if (Array.isArray(this.scopes[item.scope])) {
    this.scopes[item.scope].push(item);
  } else {
    this.scopes[item.scope] = [item];
  }
};

//
// MircodataScope
//  has a parent, properties and a key, but no value
//
function MircodataScope(node) {
  Microdata.call(this, node, 'scope');

  this.properties = {};
  this.scopes = null;
  this.value = null;
  this.scope = null;

  this._setKey();

  if (node.attr.hasOwnProperty('itemtype')) {
    this.scope = node.attr.itemtype;
    this._root._appendScope(this);
  }
}
util.inherits(MircodataScope, Microdata);

//
// MircodataItem
//  has a parent and a (key, value), but no properties
//
function MircodataItem(node) {
  Microdata.call(this, node, 'item');

  this.properties = null;
  this.scopes = null;
  this.value = null;
  this.scope = null;

  this._setKey();

  // Find the value
  switch (node.tagname) {
    case 'meta':
      this.value = node.attr.content || null;
      break;

    case 'audio':
    case 'embed':
    case 'iframe':
    case 'img':
    case 'source':
    case 'video':
      this.value = node.attr.src || null;
      break;

    case 'a':
    case 'href':
    case 'link':
      this.value = node.attr.href || null;
      break;

    case 'object':
      this.value = node.attr.data || null;
      break;

    case 'time':
      this.value = node.attr.datetime || null;
      break;

    default:
      this._setupTextValue();
      break;
  }
}
util.inherits(MircodataItem, Microdata);

// Setup a cached text getter for the value property
MircodataItem.prototype._setupTextValue = function () {
  var self = this;

  Object.defineProperty(this, 'value', {
    configurable: true,
    enumerable: true,
    get: function () {
      return self.value = domHelpers.getRawText(self.node);
    },

    set: function (text) {
      Object.defineProperty(this, 'value', {
        configurable: true,
        enumerable: true,
        writable: true,
        value: text
      });
    }
  });
};
<commit_msg>[fix] recalc blocky falgs when node is deleted<commit_after>
var util = require('util');
var domHelpers = require('./helpers-dom.js');

var WHITE_SPACE = /\s+/g;
var NEWLINE_NORMALIZE = /([ ]*)\n([ ]*)/g;
var DOUBLE_NEWLINE_NORMALIZE = /([\n]*)\n\n([\n]*)/g;

//
// Simple DOM:
// > like object structure, this is what they have in common
//  - `.type` is a string (root, text, element)
//  - `.parent` refer to the nodes parrent
//  - `.position` is the tag number from top to down
//  - `.children` is an array of the elements children
//  - `.append` adds a node to this node
//  - `.element` return the actual element
//

//
// Node
//  General abstaction between all node types
//  The rule is that this should contain the most obviouse implementation
//
function Node(type, parent) {
  this.type = type;
  this.parent = parent;

  // The specific constructor will set another value if necessary
  this.textLength = 0;

  this.tags = 0;
  this.position = -1;
  this.density = -1;

  this.children = [];

  this.text = '';
  this.textCompiled = false;
}

// Calculate the internal subStringLength and subTags properties
Node.prototype._updateCounters = function () {
  if (domHelpers.NO_TEXT_ELEMENTS.hasOwnProperty(this.tagname)) return;

  for (var i = 0, l = this.children.length; i < l; i++) {
    this.textLength += this.children[i].textLength;
    this.tags += this.children[i].tags;
  }
};

// Calculate the density
Node.prototype._updateDensity = function () {
  this.density = (this.tags === 0) ?
    this.textLength : this.textLength / this.tags;
};

Node.prototype.getText = function () {
  if (this.textCompiled === true) return this.text;

  for (var i = 0, l = this.children.length; i < l; i++) {
    var subnode = this.children[i];

    if (subnode.type === 'text') {
      this.text += this.children[i].text;
    }
    else if (subnode.type === 'element' && subnode.tagname === 'br') {
      this.text += '\n';
    }
    else if (subnode.type === 'element' &&
            domHelpers.BLOCK_ELEMENTS.hasOwnProperty(subnode.tagname) === true) {
      this.text += '\n\n' + subnode.getText() + '\n\n';
    }
    else if (domHelpers.NO_TEXT_ELEMENTS.hasOwnProperty(subnode.tagname) === false) {
      this.text += subnode.getText();
    }
  }

  this.text = this.text
    // Make sure that space don't surround newline
    .replace(NEWLINE_NORMALIZE, '\n')
    // Make sure that there is no more than two newlines after each other
    .replace(DOUBLE_NEWLINE_NORMALIZE, '\n\n');

  this.textCompiled = true;

  return this.text;
};

Node.prototype._updateBlocky = function () {
  this.blocky = domHelpers.BLOCK_ELEMENTS.hasOwnProperty(this.tagname);

  // Check if a none blocky element contains a blocky element
  for (var i = 0, l = this.children.length; i < l; i++) {
    if (this.children[i].blocky === true) {
      this.blocky = true;
      this.blockyChildren = true;
      break;
    }
  }
};

Node.prototype.remove = function () {
  if (this.parent) {
    var parent;

    // Remove this node
    var index = this.parent.children.indexOf(this);
    if (index !== -1) {
      this.parent.children.splice(index, 1);
    }

    // Set up all the parents to recalculate the text
    if (this.textLength !== 0) {
      parent = this;
      while (parent = parent.parent) {
        if (parent.textCompiled === false) break;
        parent.textCompiled = false;
        parent.text = '';
      }
    }

    // Update blocky flags
    if (this.blocky === true) {
      parent = this;
      while(parent = parent.parent) {
        parent._updateBlocky();
        // If parent is blocky then nothing at this level has changed
        // and so other parents also won't change.
        if (parent.blocky === true) break;
      }
    }
  }
};

Node.prototype.before = function () {
  var index = this.parent.children.indexOf(this);
  if (index === 0) return this.parent;
  return this.parent.children[index - 1];
};

Node.prototype.after = function () {
  var index = this.parent.children.indexOf(this);
  if (index === this.parent.children.length - 1) return this.parent;
  return this.parent.children[index + 1];
};

//
// RootNode
//   has no parent, tagname or attribute
//
function RootNode() {
  Node.call(this, 'root', null);
  this.position = 0;
  this.blocky = true;

  // Setup microdata root
  this.micro = new MicrodataRoot(this);
}
util.inherits(RootNode, Node);
exports.RootNode = RootNode;

RootNode.prototype.append = function (child) {
  this.children.push(child);

  return child;
};

RootNode.prototype.close = function () {
  this._updateCounters();
  this._updateDensity();

  return null;
};

RootNode.prototype.element = function () {
  return this;
};

//
// FragmentNode
//   has parent and children, but no tagname or attribute
//
function FragmentNode(parent) {
  Node.call(this, 'fragment', parent);
}
util.inherits(FragmentNode, Node);
exports.FragmentNode = FragmentNode;

FragmentNode.prototype.append = function (child) {
  this.children.push(child);

  return child;
};

FragmentNode.prototype.close = function () {
  return this.parent;
};

FragmentNode.prototype.element = function () {
  return this;
};

FragmentNode.prototype.assign = function (node) {
  node.children = this.children;
};

//
// TextNode
//   has a parent and a text containter
//
function TextNode(parent, text) {
  Node.call(this, 'text', parent);

  // A text node has no children instead it has a text container
  this.children = null;
  this.text = text;
  this.blocky = false;
  this.blockyChildren = false;
}
util.inherits(TextNode, Node);
exports.TextNode = TextNode;

TextNode.prototype.append = function (node) {
  if (node.type === 'text') {
    this.text += node.text;
    return this;
  } else {
    // Since the text there are to follow no will not be appended to this text
    // node close it
    this._textClose();

    // the parrent will assign a position
    this.parent.append(node);
    return node;
  }
};

TextNode.prototype._textClose = function () {
  this.text = this.text.replace(WHITE_SPACE, ' ');
  this.textCompiled = true;

  this.textLength = this.text.length;
  this._updateDensity();
};

TextNode.prototype.close = function () {
  this._textClose();

  return this.parent.close();
};

TextNode.prototype.element = function () {
  return this.parent;
};

//
// ElementNode
//   has a parent, tagname and attributes
//
function ElementNode(parent, tagname, attributes) {
  Node.call(this, 'element', parent);

  // Since this is an element there will minimum one tag
  this.tags = (tagname === 'br' || tagname === 'wbr') ? 0 : 1;

  // Element nodes also has a tagname and an attribute collection
  this.tagname = tagname;
  this.attr = attributes;
  this.classes = attributes.hasOwnProperty('class') ?
    attributes['class'].split(WHITE_SPACE) : [];

  // Setup microdata scrope or item
  if (attributes.hasOwnProperty('itemscope')) {
    this.micro = new MircodataScope(this);
  } else if (attributes.hasOwnProperty('itemprop')) {
    this.micro = new MircodataItem(this);
  } else {
    this.micro = null;
  }

  this.blocky = false;
  this.blockyChildren = false;
}
util.inherits(ElementNode, Node);
exports.ElementNode = ElementNode;

ElementNode.prototype.append = function (child) {
  this.children.push(child);

  return child;
};

ElementNode.prototype.close = function () {
  this._updateCounters();
  this._updateDensity();

  this._updateBlocky();

  return this.parent;
};

ElementNode.prototype.element = function () {
  return this;
};

//
// Microdata DOM
// > A sort of subspace/sub-DOM for microdata
//  - `.type` is a string (root, scope, item)
//  - `.scope` itemtype value
//  - `.parent` refer to microdata container of this dataobject
//  - `.properties` an object of arrays, the `name` is the key and dataobjects are items
//  - `.key` itemprop value
//  - `.value` the assotiated value
//  - `.node` an reference to the node which the microdata is attached to
//
// NOTE: itemrefs and itemid are at this point not supported
//
// Information source:
// * http://diveintohtml5.info/extensibility.html
// * http://html5doctor.com/microdata/
//

//
// Mircodata
//  shared logic between all dataobjects
//
function Microdata(node, type) {
  this.node = node;
  this.type = type;

  // Find the parent
  var parentNode = this.node;
  while(parentNode = parentNode.parent) {
    if (parentNode.micro &&
       (parentNode.micro.type === 'root' || parentNode.micro.type === 'scope')) {
      break;
    }
  }
  this.parent = parentNode ? parentNode.micro : null;

  // Set the root reference
  this._root = parentNode ? parentNode.micro._root : this;
}

Microdata.prototype._appendProperty = function (item) {
  for (var i = 0, l = item.keys.length; i < l; i++) {
    if (Array.isArray(this.properties[item.keys[i]])) {
      this.properties[item.keys[i]].push(item);
    } else {
      this.properties[item.keys[i]] = [item];
    }
  }
};

Microdata.prototype._setKey = function () {
  if (this.node.attr.hasOwnProperty('itemprop')) {
    this.keys = this.node.attr.itemprop.split(WHITE_SPACE);
    this.parent._appendProperty(this);
  } else {
    this.keys = false;
  }
};

//
// MicrodataRoot
//  has only properties if that even exists
//
function MicrodataRoot(node) {
  Microdata.call(this, node, 'root');

  this.properties = {};
  this.scopes = {};
  this.value = null;
  this.scope = null;

  this.keys = null;
}
util.inherits(MicrodataRoot, Microdata);

MicrodataRoot.prototype._appendScope = function (item) {
  if (Array.isArray(this.scopes[item.scope])) {
    this.scopes[item.scope].push(item);
  } else {
    this.scopes[item.scope] = [item];
  }
};

//
// MircodataScope
//  has a parent, properties and a key, but no value
//
function MircodataScope(node) {
  Microdata.call(this, node, 'scope');

  this.properties = {};
  this.scopes = null;
  this.value = null;
  this.scope = null;

  this._setKey();

  if (node.attr.hasOwnProperty('itemtype')) {
    this.scope = node.attr.itemtype;
    this._root._appendScope(this);
  }
}
util.inherits(MircodataScope, Microdata);

//
// MircodataItem
//  has a parent and a (key, value), but no properties
//
function MircodataItem(node) {
  Microdata.call(this, node, 'item');

  this.properties = null;
  this.scopes = null;
  this.value = null;
  this.scope = null;

  this._setKey();

  // Find the value
  switch (node.tagname) {
    case 'meta':
      this.value = node.attr.content || null;
      break;

    case 'audio':
    case 'embed':
    case 'iframe':
    case 'img':
    case 'source':
    case 'video':
      this.value = node.attr.src || null;
      break;

    case 'a':
    case 'href':
    case 'link':
      this.value = node.attr.href || null;
      break;

    case 'object':
      this.value = node.attr.data || null;
      break;

    case 'time':
      this.value = node.attr.datetime || null;
      break;

    default:
      this._setupTextValue();
      break;
  }
}
util.inherits(MircodataItem, Microdata);

// Setup a cached text getter for the value property
MircodataItem.prototype._setupTextValue = function () {
  var self = this;

  Object.defineProperty(this, 'value', {
    configurable: true,
    enumerable: true,
    get: function () {
      return self.value = domHelpers.getRawText(self.node);
    },

    set: function (text) {
      Object.defineProperty(this, 'value', {
        configurable: true,
        enumerable: true,
        writable: true,
        value: text
      });
    }
  });
};
<|endoftext|>


<commit_before>// Amara, universalsubtitles.org
//
// Copyright (C) 2012 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

goog.provide('unisubs.player.WistiaVideoPlayer');

/**
 * @constructor
 */

 /***

 UGLY: this is ripped from the YTIFrame player

 ***/

unisubs.player.WistiaVideoPlayer = function(videoSource, opt_forDialog) {
    unisubs.player.AbstractVideoPlayer.call(this, videoSource);
    this.player_ = null;
    this.videoSource_ = videoSource;
    this.playerElemID_ = unisubs.randomString() + "_wistiaplayer";
    this.forDialog_ = !!opt_forDialog;
    this.commands_ = [];
    this.progressTimer_ = new goog.Timer(
        unisubs.player.AbstractVideoPlayer.PROGRESS_INTERVAL);
    this.timeUpdateTimer_ = new goog.Timer(
        unisubs.player.AbstractVideoPlayer.TIMEUPDATE_INTERVAL);
    this.videoPlayerType_ = 'wistia';

    this.player_ = null;
    this.modeSelect = null;
};
goog.inherits(unisubs.player.WistiaVideoPlayer, unisubs.player.AbstractVideoPlayer);

unisubs.player.WistiaVideoPlayer.prototype.isChromeless = function() {
    return true;
};

unisubs.player.WistiaVideoPlayer.prototype.setDimensionsKnownInternal = function() {
    this.dimensionsKnown_ = true;
    var size = this.getVideoSize();
    unisubs.style.setSize(this.getElement(), size.width, size.height);
    this.dispatchEvent(
        unisubs.player.AbstractVideoPlayer.EventType.DIMENSIONS_KNOWN);
};

unisubs.player.WistiaVideoPlayer.prototype.getVideoSize = function() {
    return this.playerSize_;
};
unisubs.player.WistiaVideoPlayer.prototype.getDuration = function() {
    return this.player_['duration']();
};
unisubs.player.WistiaVideoPlayer.isWistiaAPIReady = function() {
    var isReady =  window['Wistia'] && window['Wistia']['embed'];
    return isReady;
};

unisubs.player.WistiaVideoPlayer.prototype.onWistiaAPIReady = function(videoId, containerID)
{
    this.player_ = window['Wistia']['embed'](videoId, {
        playerColor: "ff0000",
        fullscreenButton: false,
        container: containerID,
        autoplay: false,
        chromeless: this.forDialog_,
        controlsVisibleOnLoad: false,
        doNotTrack: true,
        playButton: ! this.forDialog_,
        playBar: ! this.forDialog_,
        videoFoam: false
    });
    // add listeners to buttons
    var play_btn = goog.dom.getElementByClass('unisubs-play-beginner');
    var skip_btn = goog.dom.getElementByClass('unisubs-skip');
    goog.events.listen(play_btn, goog.events.EventType.CLICK, this.playInternal);
    goog.events.listen(skip_btn, goog.events.EventType.CLICK, this.videoSkip);
    // add listeners for TAB key
    var docKh = new goog.events.KeyHandler(document);
    var that = this;
    goog.events.listen(docKh, 'key', function (e) {
        if (e.keyCode == 9) { // TAB key
            if (e.shiftKey) {
                that.videoSkip();
            } else {
                that.playInternal();
            }
        }
    });
    // player controls
    goog.events.listen(goog.dom.getElementByClass('unisubs-playPause'),
        goog.events.EventType.CLICK, function () {
            if (! that.player_) { return; }
            that.player_['state']() == 'playing' ?
                that.player_['pause']() :
                that.player_['play']();
        }
    );
    this.player_['bind']('timechange', function(t){that.onPlayerTimeChanged(t);});
};

unisubs.player.WistiaVideoPlayer.prototype.onPlayerTimeChanged = function(newTime) {
    this.playTime_ = newTime *1000;
    this.dispatchEvent(
        unisubs.player.AbstractVideoPlayer.EventType.TIMEUPDATE);
};

unisubs.player.WistiaVideoPlayer.prototype.createDom = function() {
    unisubs.player.WistiaVideoPlayer.superClass_.createDom.call(this);
    this.setPlayerSize_();
    var embedUri = new goog.Uri(
        "http://fast.wistia.com/embed/iframe/" +
            this.videoSource_.getVideoId());
    this.addQueryString_(embedUri);
    this.playerSize_.width = 400;
    div_args = {
        'id': this.playerElemID_,
        'data-video-width': this.playerSize_.width + '',
        'data-video-height': this.playerSize_.height + '',
        'style': unisubs.style.setSizeInString('', this.playerSize_)
    };
    var videoDiv = this.getDomHelper().createDom('div', div_args);
    this.getElement().appendChild(videoDiv);
    var that = this;
	unisubs.addScript(
        "http://fast.wistia.com/static/E-v1.js",
        true,
        unisubs.player.WistiaVideoPlayer.isWistiaAPIReady,
        function(){
            that.onWistiaAPIReady(that.videoSource_.getVideoId(), that.playerElemID_);
     });

};

unisubs.player.WistiaVideoPlayer.prototype.setPlayheadTime = function(t) {
    if (!this.player_){
        return;
    }
    this.player_['time'](t ? t : 0);
}
unisubs.player.WistiaVideoPlayer.prototype.pauseInternal = function() {
    if (!this.player_){
        return;
    }
    this.player_['pause']();
}
unisubs.player.WistiaVideoPlayer.prototype.playInternal = function() {
    if (! this.player_) { return; }
    var speedmode = this.videoGetMode();
    if (speedmode == 'no') { // no autopause
        if (this.player_['state']() == 'playing') {
            this.player_['pause']();
        } else {
            this.player_['play']();
        }
    } else if (speedmode == 'au') { // magical autopause
    } else { // beginner
        this.player_['play']();
        var that = this;
        window.setTimeout(function () { that.player_['pause'](); }, 4000);
    }
}

unisubs.player.WistiaVideoPlayer.prototype.videoSkip = function() {
    if (! this.player_) { return; }
    var speedmode = this.videoGetMode();
    if (speedmode == 'pl') { // beginner
        this.player_['time'](this.player_['time']() - 4)['play']();
        var that = this;
        window.setTimeout(function () { that.player_['pause'](); }, 4000);
    } else {
        this.player_['time'](this.player_['time']() - 8)['play']();
    }
}

unisubs.player.WistiaVideoPlayer.prototype.videoGetMode = function() {
    if (! this.modeSelect) {
        var nodes = goog.dom.getChildren(goog.dom.getElementByClass('unisubs-speedmode'));
        for (ii = 0; ii < nodes.length; ++ii) {
            if (nodes[ii].nodeName == 'SELECT') {
                this.modeSelect = nodes[ii];
                break;
            }
        }
    }
    return this.modeSelect == null ? 'pl' : goog.dom.forms.getValue(this.modeSelect);
}

unisubs.player.WistiaVideoPlayer.prototype.addQueryString_ = function(uri) {
    var config = this.videoSource_.getVideoConfig();
    if (!this.forDialog_ && config) {
        for (var prop in config) {
            if (prop != 'width' && prop != 'height')
                uri.setParameterValue(prop, config[prop]);
        }
    }
    var locationUri = new goog.Uri(window.location);
    var domain = window.location.protocol + "//" +
        locationUri.getDomain() +
        (locationUri.getPort() != null ? (':' + locationUri.getPort()) : '');
    uri.setParameterValue('origin', domain).
        setParameterValue('wmode', 'opaque').
        setParameterValue('videoWidth',400).
        setParameterValue('videoHeight',300).
        setParameterValue('doNotTrack',true);

    if (this.forDialog_) {
        uri.setParameterValue('playbar',false).
        setParameterValue('chromeless', true);
    }
};

unisubs.player.WistiaVideoPlayer.prototype.setPlayerSize_ = function() {
    /*var sizeFromConfig = this.videoSource_.sizeFromConfig();
    if (!this.forDialog_ && sizeFromConfig)
        this.playerSize_ = sizeFromConfig;
    else
        this.playerSize_ = this.forDialog_ ?
        unisubs.player.AbstractVideoPlayer.DIALOG_SIZE :
        unisubs.player.AbstractVideoPlayer.DEFAULT_SIZE;
        */
      this.playerSize_ = unisubs.player.AbstractVideoPlayer.DEFAULT_SIZE
    this.setDimensionsKnownInternal();
};

unisubs.player.WistiaVideoPlayer.prototype.decorateInternal = function(elem) {
    unisubs.player.WistiaVideoPlayer.superClass_.decorateInternal.call(this, elem);
    this.iframe_ = elem;
    if (elem.id) {
        this.playerElemID_ = elem.id;
    }
    else {
        elem.id = this.playerElemID_;
    }

    this.playerSize_ = new goog.math.Size(
        parseInt(400), parseInt(300));
    this.setDimensionsKnownInternal();
};

unisubs.player.WistiaVideoPlayer.prototype.enterDocument = function() {
    unisubs.player.WistiaVideoPlayer.superClass_.enterDocument.call(this);
    var w = window;
    if (w['Wistia'] && w['Wistia']['Player'])
        this.makePlayer_();
    else {
        var readyFunc = "onYouTubePlayerAPIReady";
        var oldReady = goog.nullFunction;
        if (w[readyFunc])
            oldReady = w[readyFunc];
        var myOnReady = goog.bind(this.makePlayer_, this);
        window[readyFunc] = function() {
            oldReady();
            myOnReady();
        };
    }
};

unisubs.player.WistiaVideoPlayer.prototype.makePlayer_ = function() {
    var playerStateChange = goog.bind(this.playerStateChange_, this);
    this.almostPlayer_ = new window['Wistia']['Player'](
        this.playerElemID_, {
            'events': {
                'onReady': goog.bind(this.playerReady_, this),
                'onStateChange': function(state) {
                    playerStateChange(state['data']);
                }
            }
        });
};

unisubs.player.WistiaVideoPlayer.prototype.playerReady_ = function(e) {
    this.player_ = this.almostPlayer_;
    goog.array.forEach(this.commands_, function(cmd) { cmd(); });
    this.commands_ = [];
    this.getHandler().
        listen(this.progressTimer_, goog.Timer.TICK, this.progressTick_).
        listen(this.timeUpdateTimer_, goog.Timer.TICK, this.timeUpdateTick_);
    this.progressTimer_.start();
};

unisubs.player.WistiaVideoPlayer.prototype.getVideoElements = function() {
    return [this.iframe_];
};

unisubs.player.WistiaVideoPlayer.prototype.disposeInternal = function() {
    unisubs.player.WistiaVideoPlayer.superClass_.disposeInternal.call(this);
    this.progressTimer_.dispose();
    this.timeUpdateTimer_.dispose();
};

unisubs.player.WistiaVideoPlayer.prototype.exitDocument = function() {
    unisubs.player.WistiaVideoPlayer.superClass_.exitDocument.call(this);
    this.progressTimer_.stop();
    this.timeUpdateTimer_.stop();
};

unisubs.player.WistiaVideoPlayer.prototype.isPlaying = function() {
    return this.player_ && this.player_['state']() == 'playing';
};

unisubs.player.WistiaVideoPlayer.prototype.isPaused = function() {
    return this.player_ && this.player_['state']() == 'paused';
};

unisubs.player.WistiaVideoPlayer.prototype.getPlayheadTimeInternal = function() {
    if (this.player_) {
        return this.player_['time']();
    } else {
        return 0;
    }
};

unisubs.player.WistiaVideoPlayer.prototype.getVolume = function()
{
    return this.player_ ? this.player_['volume']() : 0;
};

unisubs.player.WistiaVideoPlayer.prototype.setVolume = function(vol)
{
    if (this.player_)
    {
        this.player_['volume'](vol);
        this.playVolume_ = vol;
    }
    else
        this.commands_.push(goog.bind(this.setVolume, this, vol));
}
<commit_msg>Implementing setPlayheadTime fixes seek not working<commit_after>// Amara, universalsubtitles.org
//
// Copyright (C) 2012 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

goog.provide('unisubs.player.WistiaVideoPlayer');

/**
 * @constructor
 */

 /***

 UGLY: this is ripped from the YTIFrame player

 ***/

unisubs.player.WistiaVideoPlayer = function(videoSource, opt_forDialog) {
    unisubs.player.AbstractVideoPlayer.call(this, videoSource);
    this.player_ = null;
    this.videoSource_ = videoSource;
    this.playerElemID_ = unisubs.randomString() + "_wistiaplayer";
    this.forDialog_ = !!opt_forDialog;
    this.commands_ = [];
    this.progressTimer_ = new goog.Timer(
        unisubs.player.AbstractVideoPlayer.PROGRESS_INTERVAL);
    this.timeUpdateTimer_ = new goog.Timer(
        unisubs.player.AbstractVideoPlayer.TIMEUPDATE_INTERVAL);
    this.videoPlayerType_ = 'wistia';

    this.player_ = null;
    this.modeSelect = null;
};
goog.inherits(unisubs.player.WistiaVideoPlayer, unisubs.player.AbstractVideoPlayer);

unisubs.player.WistiaVideoPlayer.prototype.isChromeless = function() {
    return true;
};

unisubs.player.WistiaVideoPlayer.prototype.setDimensionsKnownInternal = function() {
    this.dimensionsKnown_ = true;
    var size = this.getVideoSize();
    unisubs.style.setSize(this.getElement(), size.width, size.height);
    this.dispatchEvent(
        unisubs.player.AbstractVideoPlayer.EventType.DIMENSIONS_KNOWN);
};

unisubs.player.WistiaVideoPlayer.prototype.getVideoSize = function() {
    return this.playerSize_;
};
unisubs.player.WistiaVideoPlayer.prototype.getDuration = function() {
    return this.player_['duration']();
};
unisubs.player.WistiaVideoPlayer.isWistiaAPIReady = function() {
    var isReady =  window['Wistia'] && window['Wistia']['embed'];
    return isReady;
};

unisubs.player.WistiaVideoPlayer.prototype.onWistiaAPIReady = function(videoId, containerID)
{
    this.player_ = window['Wistia']['embed'](videoId, {
        playerColor: "ff0000",
        fullscreenButton: false,
        container: containerID,
        autoplay: false,
        chromeless: this.forDialog_,
        controlsVisibleOnLoad: false,
        doNotTrack: true,
        playButton: ! this.forDialog_,
        playBar: ! this.forDialog_,
        videoFoam: false
    });
    // add listeners to buttons
    var play_btn = goog.dom.getElementByClass('unisubs-play-beginner');
    var skip_btn = goog.dom.getElementByClass('unisubs-skip');
    goog.events.listen(play_btn, goog.events.EventType.CLICK, this.playInternal);
    goog.events.listen(skip_btn, goog.events.EventType.CLICK, this.videoSkip);
    // add listeners for TAB key
    var docKh = new goog.events.KeyHandler(document);
    var that = this;
    goog.events.listen(docKh, 'key', function (e) {
        if (e.keyCode == 9) { // TAB key
            if (e.shiftKey) {
                that.videoSkip();
            } else {
                that.playInternal();
            }
        }
    });
    // player controls
    goog.events.listen(goog.dom.getElementByClass('unisubs-playPause'),
        goog.events.EventType.CLICK, function () {
            if (! that.player_) { return; }
            that.player_['state']() == 'playing' ?
                that.player_['pause']() :
                that.player_['play']();
        }
    );
    this.player_['bind']('timechange', function(t){that.onPlayerTimeChanged(t);});
};

unisubs.player.WistiaVideoPlayer.prototype.onPlayerTimeChanged = function(newTime) {
    this.playTime_ = newTime *1000;
    this.dispatchEvent(
        unisubs.player.AbstractVideoPlayer.EventType.TIMEUPDATE);
};

unisubs.player.WistiaVideoPlayer.prototype.createDom = function() {
    unisubs.player.WistiaVideoPlayer.superClass_.createDom.call(this);
    this.setPlayerSize_();
    var embedUri = new goog.Uri(
        "http://fast.wistia.com/embed/iframe/" +
            this.videoSource_.getVideoId());
    this.addQueryString_(embedUri);
    this.playerSize_.width = 400;
    div_args = {
        'id': this.playerElemID_,
        'data-video-width': this.playerSize_.width + '',
        'data-video-height': this.playerSize_.height + '',
        'style': unisubs.style.setSizeInString('', this.playerSize_)
    };
    var videoDiv = this.getDomHelper().createDom('div', div_args);
    this.getElement().appendChild(videoDiv);
    var that = this;
	unisubs.addScript(
        "http://fast.wistia.com/static/E-v1.js",
        true,
        unisubs.player.WistiaVideoPlayer.isWistiaAPIReady,
        function(){
            that.onWistiaAPIReady(that.videoSource_.getVideoId(), that.playerElemID_);
     });

};

unisubs.player.WistiaVideoPlayer.prototype.setPlayheadTime = function(t) {
    if (this.player_) {
        this.player_['time'](t);
    } else {
        this.commands_.push(goog.bind(this.setPlayheadTime, this, playheadTime));
    }
}
unisubs.player.WistiaVideoPlayer.prototype.pauseInternal = function() {
    if (!this.player_){
        return;
    }
    this.player_['pause']();
}
unisubs.player.WistiaVideoPlayer.prototype.playInternal = function() {
    if (! this.player_) { return; }
    var speedmode = this.videoGetMode();
    if (speedmode == 'no') { // no autopause
        if (this.player_['state']() == 'playing') {
            this.player_['pause']();
        } else {
            this.player_['play']();
        }
    } else if (speedmode == 'au') { // magical autopause
    } else { // beginner
        this.player_['play']();
        var that = this;
        window.setTimeout(function () { that.player_['pause'](); }, 4000);
    }
}

unisubs.player.WistiaVideoPlayer.prototype.videoSkip = function() {
    if (! this.player_) { return; }
    var speedmode = this.videoGetMode();
    if (speedmode == 'pl') { // beginner
        this.player_['time'](this.player_['time']() - 4)['play']();
        var that = this;
        window.setTimeout(function () { that.player_['pause'](); }, 4000);
    } else {
        this.player_['time'](this.player_['time']() - 8)['play']();
    }
}

unisubs.player.WistiaVideoPlayer.prototype.videoGetMode = function() {
    if (! this.modeSelect) {
        var nodes = goog.dom.getChildren(goog.dom.getElementByClass('unisubs-speedmode'));
        for (ii = 0; ii < nodes.length; ++ii) {
            if (nodes[ii].nodeName == 'SELECT') {
                this.modeSelect = nodes[ii];
                break;
            }
        }
    }
    return this.modeSelect == null ? 'pl' : goog.dom.forms.getValue(this.modeSelect);
}

unisubs.player.WistiaVideoPlayer.prototype.addQueryString_ = function(uri) {
    var config = this.videoSource_.getVideoConfig();
    if (!this.forDialog_ && config) {
        for (var prop in config) {
            if (prop != 'width' && prop != 'height')
                uri.setParameterValue(prop, config[prop]);
        }
    }
    var locationUri = new goog.Uri(window.location);
    var domain = window.location.protocol + "//" +
        locationUri.getDomain() +
        (locationUri.getPort() != null ? (':' + locationUri.getPort()) : '');
    uri.setParameterValue('origin', domain).
        setParameterValue('wmode', 'opaque').
        setParameterValue('videoWidth',400).
        setParameterValue('videoHeight',300).
        setParameterValue('doNotTrack',true);

    if (this.forDialog_) {
        uri.setParameterValue('playbar',false).
        setParameterValue('chromeless', true);
    }
};

unisubs.player.WistiaVideoPlayer.prototype.setPlayerSize_ = function() {
    /*var sizeFromConfig = this.videoSource_.sizeFromConfig();
    if (!this.forDialog_ && sizeFromConfig)
        this.playerSize_ = sizeFromConfig;
    else
        this.playerSize_ = this.forDialog_ ?
        unisubs.player.AbstractVideoPlayer.DIALOG_SIZE :
        unisubs.player.AbstractVideoPlayer.DEFAULT_SIZE;
        */
      this.playerSize_ = unisubs.player.AbstractVideoPlayer.DEFAULT_SIZE
    this.setDimensionsKnownInternal();
};

unisubs.player.WistiaVideoPlayer.prototype.decorateInternal = function(elem) {
    unisubs.player.WistiaVideoPlayer.superClass_.decorateInternal.call(this, elem);
    this.iframe_ = elem;
    if (elem.id) {
        this.playerElemID_ = elem.id;
    }
    else {
        elem.id = this.playerElemID_;
    }

    this.playerSize_ = new goog.math.Size(
        parseInt(400), parseInt(300));
    this.setDimensionsKnownInternal();
};

unisubs.player.WistiaVideoPlayer.prototype.enterDocument = function() {
    unisubs.player.WistiaVideoPlayer.superClass_.enterDocument.call(this);
    var w = window;
    if (w['Wistia'] && w['Wistia']['Player'])
        this.makePlayer_();
    else {
        var readyFunc = "onYouTubePlayerAPIReady";
        var oldReady = goog.nullFunction;
        if (w[readyFunc])
            oldReady = w[readyFunc];
        var myOnReady = goog.bind(this.makePlayer_, this);
        window[readyFunc] = function() {
            oldReady();
            myOnReady();
        };
    }
};

unisubs.player.WistiaVideoPlayer.prototype.makePlayer_ = function() {
    var playerStateChange = goog.bind(this.playerStateChange_, this);
    this.almostPlayer_ = new window['Wistia']['Player'](
        this.playerElemID_, {
            'events': {
                'onReady': goog.bind(this.playerReady_, this),
                'onStateChange': function(state) {
                    playerStateChange(state['data']);
                }
            }
        });
};

unisubs.player.WistiaVideoPlayer.prototype.playerReady_ = function(e) {
    this.player_ = this.almostPlayer_;
    goog.array.forEach(this.commands_, function(cmd) { cmd(); });
    this.commands_ = [];
    this.getHandler().
        listen(this.progressTimer_, goog.Timer.TICK, this.progressTick_).
        listen(this.timeUpdateTimer_, goog.Timer.TICK, this.timeUpdateTick_);
    this.progressTimer_.start();
};

unisubs.player.WistiaVideoPlayer.prototype.getVideoElements = function() {
    return [this.iframe_];
};

unisubs.player.WistiaVideoPlayer.prototype.disposeInternal = function() {
    unisubs.player.WistiaVideoPlayer.superClass_.disposeInternal.call(this);
    this.progressTimer_.dispose();
    this.timeUpdateTimer_.dispose();
};

unisubs.player.WistiaVideoPlayer.prototype.exitDocument = function() {
    unisubs.player.WistiaVideoPlayer.superClass_.exitDocument.call(this);
    this.progressTimer_.stop();
    this.timeUpdateTimer_.stop();
};

unisubs.player.WistiaVideoPlayer.prototype.isPlaying = function() {
    return this.player_ && this.player_['state']() == 'playing';
};

unisubs.player.WistiaVideoPlayer.prototype.isPaused = function() {
    return this.player_ && this.player_['state']() == 'paused';
};

unisubs.player.WistiaVideoPlayer.prototype.getPlayheadTimeInternal = function() {
    if (this.player_) {
        return this.player_['time']();
    } else {
        return 0;
    }
};

unisubs.player.WistiaVideoPlayer.prototype.getVolume = function()
{
    return this.player_ ? this.player_['volume']() : 0;
};

unisubs.player.WistiaVideoPlayer.prototype.setVolume = function(vol)
{
    if (this.player_)
    {
        this.player_['volume'](vol);
        this.playVolume_ = vol;
    }
    else
        this.commands_.push(goog.bind(this.setVolume, this, vol));
}
<|endoftext|>


<commit_before>var request     = require('request');

var api         = require('./api');
var ApiError    = require('./errors/ApiError');

function Client(options) {

  var fieldsToValidate = !options.accessToken ?
    ['domain', 'clientID', 'clientSecret'] :
    ['domain'];

  fieldsToValidate.forEach(function (k) {
    if(!options[k]){
      throw new Error(k + ' is required');
    }
  });

  this.apiUrl =   'https://' + options.domain + '/api';
  this.tokenUrl = 'https://' + options.domain + '/oauth/token';
  this.options = options;
}

Client.getAccessToken = function (options, done) {
  var body = {
    'client_id':     options.clientID,
    'client_secret': options.clientSecret,
    'grant_type':    'client_credentials'
  };

  var tokenUrl = 'https://' + options.domain + '/oauth/token';

  request.post({
    url:  tokenUrl,
    form: body
  }, function (err, resp, body) {

    if (err) return done(err);
    if (resp.statusCode === 404) return done(new ApiError('unknown client', 404));
    if (resp.statusCode.toString().substr(0, 1) !== '2') return done(new ApiError(body, resp.statusCode));

    var accessToken = JSON.parse(body)['access_token'];
    done(null, accessToken);
  });
};

Client.prototype.getAccessToken = function(done){
  var self = this;

  if (this._currentAccessToken) return done(null, this._currentAccessToken);

  return Client.getAccessToken(this.options, function (err, token) {
    if (err) return done(err);

    self._currentAccessToken = token;

    var timer = setTimeout(function () {
      delete self._currentAccessToken;
    }, 1000 * 60 * 3); //~ 3 hours

    // Make the timer active but if it's the only item left in the event loop
    // won't keep the program running.
    timer.unref();

    done(null, token);
  });
};

Object.keys(api).forEach(function (m) {
  Client.prototype[m] = function (){
    var args = [].slice.call(arguments);
    var callback = args[args.length - 1];

    if (this.options.accessToken) {
      api[m].apply(this, [this.options.accessToken].concat(args));
    }
    else {
      this.getAccessToken(function (err, accessToken) {
        if (err) return callback(err);
        api[m].apply(this, [accessToken].concat(args));
      }.bind(this));
    }
  };
});

module.exports = Client;
<commit_msg>Minor: Fixing ~3 hours -> minutes<commit_after>var request     = require('request');

var api         = require('./api');
var ApiError    = require('./errors/ApiError');

function Client(options) {

  var fieldsToValidate = !options.accessToken ?
    ['domain', 'clientID', 'clientSecret'] :
    ['domain'];

  fieldsToValidate.forEach(function (k) {
    if(!options[k]){
      throw new Error(k + ' is required');
    }
  });

  this.apiUrl =   'https://' + options.domain + '/api';
  this.tokenUrl = 'https://' + options.domain + '/oauth/token';
  this.options = options;
}

Client.getAccessToken = function (options, done) {
  var body = {
    'client_id':     options.clientID,
    'client_secret': options.clientSecret,
    'grant_type':    'client_credentials'
  };

  var tokenUrl = 'https://' + options.domain + '/oauth/token';

  request.post({
    url:  tokenUrl,
    form: body
  }, function (err, resp, body) {

    if (err) return done(err);
    if (resp.statusCode === 404) return done(new ApiError('unknown client', 404));
    if (resp.statusCode.toString().substr(0, 1) !== '2') return done(new ApiError(body, resp.statusCode));

    var accessToken = JSON.parse(body)['access_token'];
    done(null, accessToken);
  });
};

Client.prototype.getAccessToken = function(done){
  var self = this;

  if (this._currentAccessToken) return done(null, this._currentAccessToken);

  return Client.getAccessToken(this.options, function (err, token) {
    if (err) return done(err);

    self._currentAccessToken = token;

    var timer = setTimeout(function () {
      delete self._currentAccessToken;
    }, 1000 * 60 * 3); //~ 3 minutes

    // Make the timer active but if it's the only item left in the event loop
    // won't keep the program running.
    timer.unref();

    done(null, token);
  });
};

Object.keys(api).forEach(function (m) {
  Client.prototype[m] = function (){
    var args = [].slice.call(arguments);
    var callback = args[args.length - 1];

    if (this.options.accessToken) {
      api[m].apply(this, [this.options.accessToken].concat(args));
    }
    else {
      this.getAccessToken(function (err, accessToken) {
        if (err) return callback(err);
        api[m].apply(this, [accessToken].concat(args));
      }.bind(this));
    }
  };
});

module.exports = Client;
<|endoftext|>


<commit_before>angular.module('main').directive('leaflet', [
           'leaflet', 'langManager', '$http', 'apiClient', 'item',
  function (leaflet, langManager, $http, apiClient, item) {
    return {
      template: '

',
      replace: true,
      scope: {
        previewData: '='
      },

      link: function ($scope, element, attributes) {

        $scope.$watchCollection(function(){return $scope.previewData}, function(newVal, oldVal) {
          if(Object.keys(newVal).length && newVal.geometry) {
            get_map(newVal);
          }
        });

        function get_map(data) {
          var lang = langManager.lang,
              cap_lang = lang[0].toUpperCase() + lang.slice(1),
              active_place_title = data.Header[cap_lang];

          //set map center
          var act_lat = data.geometry.coordinates[1],
              act_lng = data.geometry.coordinates[0];

          var map = L.map(element[0])
              .setView([act_lat, act_lng], 7);

          setTimeout(function() {map.invalidateSize();}, 1000);

          //add tiles
          var pngTiles = L.tileLayer('http://stamen-tiles-{s}.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png', {
            attribution: '© OpenStreetMap',
            maxZoom: 10,
            minZoom: 7,
            subdomains: ['a', 'b', 'c']
          }).addTo(map);

          var bounds = {};
          map.on('moveend', function () {
            bounds = map.getBounds();
            //bring places marks within display bounds
            leaflet.get_geo_places(bounds).then(function (places) {
              places.forEach(function(r) {
                if (r.geometry.coordinates) {
                  var lat = r.geometry.coordinates[1];
                      lng = r.geometry.coordinates[0];
                      title = r.Header[cap_lang],
                      type = r.PlaceTypeDesc['En'],
                      icon = eval(get_icon(type));

                  if (title !== active_place_title) {
                     marker = new L.marker([lat, lng], {icon: icon, title: title})
                        .on('click', function(e) {item.get_marker_link(r.Slug[cap_lang])})
                        .addTo(map);
                  }
                }
              })
            });
          });

          //add 'pin to start' control
          var ToStartControl = L.Control.extend({
              options: {
                  position: 'topleft',
              },

              onAdd: function (map) {
                // create the control container with a particular class name
                var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control');
                container.style.backgroundColor = '#fff';
                container.style.backgroundImage = "url('/images/focus_icon.png')";
                container.style.backgroundSize = "26px 26px";
                container.style.width = '26px';
                container.style.height = '26px';
                container.style.cursor = "pointer";

                container.onclick = function(){
                  map.panTo([act_lat, act_lng], {options: {animate:true}});
                }
                return container;
              }
          });

          map.addControl(new ToStartControl());

          //build custom markers
          var smCustomIcon = L.Icon.extend({
              options: {
                iconSize: [19.5, 27], iconAnchor: [10, 27], popupAnchor: [0, -27]
              }
          });

          var bgCustomIcon = L.Icon.extend({
              options: {
                iconSize: [26.25, 35], iconAnchor: [13, 35], popupAnchor: [0, -35]
              }
          });

          var active_icon_s = new smCustomIcon({iconUrl: '/images/active_marker.png'}),
              icon_s = new smCustomIcon({iconUrl: '/images/blue_marker.png'}),
              active_icon_b = new bgCustomIcon({iconUrl: '/images/active_marker.png'}),
              icon_b = new bgCustomIcon({iconUrl: '/images/blue_marker.png'});

          var place_type = data.PlaceTypeDesc['En'];
              active_icon = eval(get_active_icon(place_type));

          var mark = L.marker([act_lat, act_lng], {icon: active_icon, title: active_place_title})
                    .on('click', function(e) { item.get_marker_link(data.Slug[cap_lang])})
                    .addTo(map);

        };

        function get_icon (type) {
          return icon = (type == 'Town' || type == 'Village') ?
                'icon_s' : 'icon_b';
        };

        function get_active_icon (type) {
          return icon = type == 'Town' || type == 'Village' ?
                'active_icon_s' : 'active_icon_b';
        };
      }
    }
  }
]);
<commit_msg>fix 'center map' custom control button<commit_after>angular.module('main').directive('leaflet', [
           'leaflet', 'langManager', '$http', 'apiClient', 'item',
  function (leaflet, langManager, $http, apiClient, item) {
    return {
      template: '

',
      replace: true,
      scope: {
        previewData: '='
      },

      link: function ($scope, element, attributes) {

        $scope.$watchCollection(function(){return $scope.previewData}, function(newVal, oldVal) {
          if(Object.keys(newVal).length && newVal.geometry) {
            get_map(newVal);
          }
        });

        function get_map(data) {
          var lang = langManager.lang,
              cap_lang = lang[0].toUpperCase() + lang.slice(1),
              active_place_title = data.Header[cap_lang];

          //set map center
          var act_lat = data.geometry.coordinates[1],
              act_lng = data.geometry.coordinates[0];

          var map = L.map(element[0])
              .setView([act_lat, act_lng], 7);

          setTimeout(function() {map.invalidateSize();}, 1000);

          //add tiles
          var pngTiles = L.tileLayer('http://stamen-tiles-{s}.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png', {
            attribution: '© OpenStreetMap',
            maxZoom: 10,
            minZoom: 7,
            subdomains: ['a', 'b', 'c']
          }).addTo(map);

          var bounds = {};
          map.on('moveend', function () {
            bounds = map.getBounds();
            //bring places marks within display bounds
            leaflet.get_geo_places(bounds).then(function (places) {
              places.forEach(function(r) {
                if (r.geometry.coordinates) {
                  var lat = r.geometry.coordinates[1];
                      lng = r.geometry.coordinates[0];
                      title = r.Header[cap_lang],
                      type = r.PlaceTypeDesc['En'],
                      icon = eval(get_icon(type));

                  if (title !== active_place_title) {
                     marker = new L.marker([lat, lng], {icon: icon, title: title})
                        .on('click', function(e) {item.get_marker_link(r.Slug[cap_lang])})
                        .addTo(map);
                  }
                }
              })
            });
          });

          //add 'pin to start' control
          var ToStartControl = L.Control.extend({
              options: {
                  position: 'topleft',
              },

              onAdd: function (map) {
                // create custom control that centers map
                var container = L.DomUtil.create('div', 'leaflet-control-zoom leaflet-bar leaflet-control');
                container.innerHTML = '';
                container.onclick = function(){
                  map.panTo([act_lat, act_lng], {options: {animate:true}});
                }
                return container;
              }
          });

          map.addControl(new ToStartControl());

          //build custom markers
          var smCustomIcon = L.Icon.extend({
              options: {
                iconSize: [19.5, 27], iconAnchor: [10, 27], popupAnchor: [0, -27]
              }
          });

          var bgCustomIcon = L.Icon.extend({
              options: {
                iconSize: [26.25, 35], iconAnchor: [13, 35], popupAnchor: [0, -35]
              }
          });

          var active_icon_s = new smCustomIcon({iconUrl: '/images/active_marker.png'}),
              icon_s = new smCustomIcon({iconUrl: '/images/blue_marker.png'}),
              active_icon_b = new bgCustomIcon({iconUrl: '/images/active_marker.png'}),
              icon_b = new bgCustomIcon({iconUrl: '/images/blue_marker.png'});

          var place_type = data.PlaceTypeDesc['En'];
              active_icon = eval(get_active_icon(place_type));

          var mark = L.marker([act_lat, act_lng], {icon: active_icon, title: active_place_title})
                    .on('click', function(e) { item.get_marker_link(data.Slug[cap_lang])})
                    .addTo(map);

        };

        function get_icon (type) {
          return icon = (type == 'Town' || type == 'Village') ?
                'icon_s' : 'icon_b';
        };

        function get_active_icon (type) {
          return icon = type == 'Town' || type == 'Village' ?
                'active_icon_s' : 'active_icon_b';
        };
      }
    }
  }
]);
<|endoftext|>