<commit_before>export default function(ngapp, fh) {
    let service,
        modules = {},
        failures = [],
        loaders = {
            default: function(module, fh, ngapp, moduleService) {
                let args = {
                    ngapp: ngapp,
                    fh: fh,
                    info: module.info,
                    modulePath: module.path,
                    moduleService: moduleService
                };
                let fn = new Function(...Object.keys(args), module.code);
                fn(...Object.values(args));
                modules[module.info.id] = module.info;
            }
        },
        deferredModules = [];

    // PRIVATE FUNCTIONS
    let prepareModule = function(modulePath, info) {
        return {
            info: info,
            path: fh.getFileUrl(modulePath),
            code: fh.loadTextFile(`${modulePath}\\index.js`)
        }
    };

    let validateModule = function(info) {
        return info && info.hasOwnProperty('id') && info.hasOwnProperty('name');
    };

    let getModuleInfo = function(modulePath) {
        let info = fh.loadJsonFile(`${modulePath}\\module.json`, null);
        return validateModule(info) && info;
    };

    let getModuleFolders = function() {
        if (!fh.jetpack.exists('modules')) return [];
        return fh.jetpack.find('modules', {
            matching: '*',
            files: false,
            directories: true,
            recursive: false
        });
    };

    let missingRequirementError = function(info) {
        let message = `Module ${info.name} requires modules which could not be found: `;
        info.requires.forEach(function(requirement) {
            if (modules.hasOwnProperty(requirement)) return;
            message += `\r\n- ${requirement}`;
        });
        failures.push(message);
    };

    let missingInfoError = function(modulePath) {
        failures.push(`Missing module.json file at ${modulePath}, failed to load module.`);
    };

    let loaderNotFoundError = function(module) {
        failures.push(`Failed to load ${module.info.id}, module loader ` +
            `${module.info.moduleLoader} not found.`);
    };

    let deferredError = function(module) {
        failures.push(`Failed to load ${module.info.id}, loader ` +
            `${module.info.moduleLoader} was declared but not instantiated.`);
    };

    let allRequirementsLoaded = function(requirements) {
        if (!requirements) return true;
        return requirements.reduce(function(b, requirement) {
            return b && modules.hasOwnProperty(requirement);
        }, true);
    };

    let build = function(module, allowDefer = true) {
        let loaderId = module.info.moduleLoader || 'default',
            loader = loaders[loaderId];
        if (!loader) {
            loaderNotFoundError(module);
        } else if (loader === true) {
            allowDefer ? deferredModules.push(module) : deferredError(module);
        } else {
            loader(module, fh, ngapp, service);
        }
    };

    let failedToLoadModules = function(modules) {
        modules.forEach((module) => missingRequirementError(module.info));
    };

    let buildModules = function(modules) {
        let unloadedCount = modules.length,
            lastUnloadedCount = 0,
            unloadedModules = modules;
        while (unloadedCount > 0 && unloadedCount !== lastUnloadedCount) {
            unloadedModules = unloadedModules.filter(function(module) {
                if (!allRequirementsLoaded(module.info.requires)) return true;
                build(module);
            });
            lastUnloadedCount = unloadedCount;
            unloadedCount = unloadedModules.length;
        }
        if (unloadedCount > 0) failedToLoadModules(unloadedModules);
    };

    // PUBLIC API
    service = {
        getInstalledModules: function() {
            let moduleFolders = getModuleFolders();
            return moduleFolders.map(function(modulePath) {
                let info = getModuleInfo(modulePath);
                if (info) info.modulePath = modulePath;
                return info;
            }).filter((info) => { return !!info });
        },
        loadModules: function() {
            let moduleFolders = getModuleFolders(),
                modules = [];
            moduleFolders.forEach(function(modulePath) {
                let info = getModuleInfo(modulePath);
                if (!info) {
                    missingInfoError(modulePath);
                } else {
                    modules.push(prepareModule(modulePath, info));
                }
            });
            buildModules(modules);
        },
        loadDeferredModules: function() {
            deferredModules.forEach((module) => build(module, false));
        },
        loadModule: function(modulePath) {
            let info = getModuleInfo(modulePath);
            if (!info) {
                missingInfoError(modulePath);
            } else {
                let module = prepareModule(modulePath, info);
                if (allRequirementsLoaded(info.requires)) {
                    build(module);
                    return true;
                } else {
                    missingRequirementError(info);
                }
            }
        },
        registerLoader: (id, loaderFunction) => loaders[id] = loaderFunction,
        deferLoader: (id) => loaders[id] = true,
        /*
         * 1. Extract module to temporary folder
         * 2. Load module info, if invalid fail and inform user, else continue.
         * 3. Check if a module is already installed with the same name
         * 4. If it does, prompt the user to check if they want to update, else prompt the
         *    user to verify they want to install the module
         * 5. Move module folder from temporary location to modules folder
         * 6. Load module if it can be hotloaded
         */
        installModule: function(filePath) {
            // TODO
        }
    };

    return service;
};
<commit_msg>moduleService: removed installModule stub, added getActiveModules function to public API, now tracking all loaded modules through `modules` instead of only ones loaded with the default module loader<commit_after>export default function(ngapp, fh) {
    let modules = {},
        failures = [],
        loaders = {
            default: function(module, fh, ngapp, moduleService) {
                let args = {
                    ngapp: ngapp,
                    fh: fh,
                    info: module.info,
                    modulePath: module.path,
                    moduleService: moduleService
                };
                let fn = new Function(...Object.keys(args), module.code);
                fn(...Object.values(args));
            }
        },
        deferredModules = [];

    // PRIVATE FUNCTIONS
    let prepareModule = function(modulePath, info) {
        return {
            info: info,
            path: fh.getFileUrl(modulePath),
            code: fh.loadTextFile(`${modulePath}\\index.js`)
        }
    };

    let validateModule = function(info) {
        return info && info.hasOwnProperty('id') && info.hasOwnProperty('name');
    };

    let getModuleInfo = function(modulePath) {
        let info = fh.loadJsonFile(`${modulePath}\\module.json`, null);
        return validateModule(info) && info;
    };

    let getModuleFolders = function() {
        if (!fh.jetpack.exists('modules')) return [];
        return fh.jetpack.find('modules', {
            matching: '*',
            files: false,
            directories: true,
            recursive: false
        });
    };

    let missingRequirementError = function(info) {
        let message = `Module ${info.name} requires modules which could not be found: `;
        info.requires.forEach(function(requirement) {
            if (modules.hasOwnProperty(requirement)) return;
            message += `\r\n- ${requirement}`;
        });
        failures.push(message);
    };

    let missingInfoError = function(modulePath) {
        failures.push(`Missing module.json file at ${modulePath}, failed to load module.`);
    };

    let loaderNotFoundError = function(module) {
        failures.push(`Failed to load ${module.info.id}, module loader ` +
            `${module.info.moduleLoader} not found.`);
    };

    let deferredError = function(module) {
        failures.push(`Failed to load ${module.info.id}, loader ` +
            `${module.info.moduleLoader} was declared but not instantiated.`);
    };

    let allRequirementsLoaded = function(requirements) {
        if (!requirements) return true;
        return requirements.reduce(function(b, requirement) {
            return b && modules.hasOwnProperty(requirement);
        }, true);
    };

    let build = function(module, allowDefer = true) {
        let loaderId = module.info.moduleLoader || 'default',
            loader = loaders[loaderId];
        if (!loader) {
            loaderNotFoundError(module);
        } else if (loader === true) {
            allowDefer ? deferredModules.push(module) : deferredError(module);
        } else {
            loader(modules, module, fh, ngapp, service);
            modules[module.info.id] = module.info;
        }
    };

    let failedToLoadModules = function(modules) {
        modules.forEach((module) => missingRequirementError(module.info));
    };

    let buildModules = function(modules) {
        let unloadedCount = modules.length,
            lastUnloadedCount = 0,
            unloadedModules = modules;
        while (unloadedCount > 0 && unloadedCount !== lastUnloadedCount) {
            unloadedModules = unloadedModules.filter(function(module) {
                if (!allRequirementsLoaded(module.info.requires)) return true;
                build(module);
            });
            lastUnloadedCount = unloadedCount;
            unloadedCount = unloadedModules.length;
        }
        if (unloadedCount > 0) failedToLoadModules(unloadedModules);
    };

    // PUBLIC API
    let service = {
        getActiveModules: () => { return modules; },
        getInstalledModules: function() {
            let moduleFolders = getModuleFolders();
            return moduleFolders.map(function(modulePath) {
                let info = getModuleInfo(modulePath);
                if (info) info.modulePath = modulePath;
                return info;
            }).filter((info) => { return !!info });
        },
        loadModules: function() {
            let moduleFolders = getModuleFolders(),
                modules = [];
            moduleFolders.forEach(function(modulePath) {
                let info = getModuleInfo(modulePath);
                if (!info) {
                    missingInfoError(modulePath);
                } else {
                    modules.push(prepareModule(modulePath, info));
                }
            });
            buildModules(modules);
        },
        loadModule: function(modulePath) {
            let info = getModuleInfo(modulePath);
            if (!info) {
                missingInfoError(modulePath);
            } else {
                let module = prepareModule(modulePath, info);
                if (allRequirementsLoaded(info.requires)) {
                    build(module);
                    return true;
                } else {
                    missingRequirementError(info);
                }
            }
        },
        loadDeferredModules: function() {
            deferredModules.forEach((module) => build(module, false));
        },
        registerLoader: (id, loaderFunction) => loaders[id] = loaderFunction,
        deferLoader: (id) => loaders[id] = true
    };

    return service;
};
<|endoftext|>


<commit_before>angular
  .module("animeHub")
  .controller("commentsController", commentsController);

commentsController.$inject = ['$stateParams', 'Comments'];
function commentsController($stateParams, Comments){
}<commit_msg>removed params<commit_after>angular
  .module("animeHub")
  .controller("commentsController", commentsController);

commentsController.$inject = ['Comments'];
function commentsController(Comments){
}<|endoftext|>


<commit_before>(function(){
  'use strict';

  angular.module('ui.grid').directive('uiGridHeader', ['$log', '$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($log, $templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    var defaultTemplate = 'ui-grid/ui-grid-header';

    return {
      restrict: 'EA',
      // templateUrl: 'ui-grid/ui-grid-header',
      replace: true,
      // priority: 1000,
      require: '?^uiGrid',
      scope: false,
      compile: function($elm, $attrs) {
        return {
          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
            var headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;

             gridUtil.getTemplate(headerTemplate)
              .then(function (contents) {
                var template = angular.element(contents);

                var newElm = $compile(template)($scope);
                $elm.append(newElm);

                if (uiGridCtrl) {
                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];

                  if (headerViewport) {
                    uiGridCtrl.headerViewport = headerViewport;
                  }
                }
              });
          },

          post: function ($scope, $elm, $attrs, uiGridCtrl) {
            if (uiGridCtrl === undefined) {
              throw new Error('[ui-grid-header] uiGridCtrl is undefined!');
            }

            $log.debug('ui-grid-header link');

            function updateColumnWidths() {
              var asterisksArray = [],
                  percentArray = [],
                  manualArray = [],
                  asteriskNum = 0,
                  totalWidth = 0;

              // Get the width of the viewport
              var availableWidth = uiGridCtrl.grid.getViewportWidth();

              if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
                availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
              }

              // The total number of columns
              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
              // var equalWidth = availableWidth / equalWidthColumnCount;

              // The last column we processed
              var lastColumn;

              var manualWidthSum = 0;

              var canvasWidth = 0;

              var ret = '';

              uiGridCtrl.grid.columns.forEach(function(column, i) {
                // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
                //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;

                // Skip hidden columns
                if (! column.visible) { return; }

                var colWidth,
                    isPercent = false;

                if (! angular.isNumber(column.width)) {
                  isPercent = isNaN(column.width) ? gridUtil.endsWith(column.width, "%") : false;
                }

                if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
                  asteriskNum = parseInt(asteriskNum + column.width.length, 10);

                  asterisksArray.push(column);
                }
                else if (isPercent) { // If the width is a percentage, save it until the very last.
                  percentArray.push(column);
                }
                else if (angular.isNumber(column.width)) {
                  manualWidthSum = parseInt(manualWidthSum + column.width, 10);

                  canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);

                  column.drawnWidth = column.width;

                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + column.width + 'px; }';
                }
              });

              // Get the remaining width (available width subtracted by the manual widths sum)
              var remainingWidth = availableWidth - manualWidthSum;

              var i, column, colWidth;

              if (percentArray.length > 0) {
                // Pre-process to make sure they're all within any min/max values
                for (i = 0; i < percentArray.length; i++) {
                  column = percentArray[i];

                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;

                  colWidth = parseInt(percent * remainingWidth, 10);

                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
                    colWidth = column.colDef.minWidth;

                    remainingWidth = remainingWidth - colWidth;

                    canvasWidth += colWidth;
                    column.drawnWidth = colWidth;

                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';

                    // Remove this element from the percent array so it's not processed below
                    percentArray.splice(i, 1);
                  }
                  else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
                    colWidth = column.colDef.maxWidth;

                    remainingWidth = remainingWidth - colWidth;

                    canvasWidth += colWidth;
                    column.drawnWidth = colWidth;

                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';

                    // Remove this element from the percent array so it's not processed below
                    percentArray.splice(i, 1);
                  }
                }

                percentArray.forEach(function(column) {
                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
                  var colWidth = parseInt(percent * remainingWidth, 10);

                  canvasWidth += colWidth;

                  column.drawnWidth = colWidth;

                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
                });
              }

              if (asterisksArray.length > 0) {
                var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);

                 // Pre-process to make sure they're all within any min/max values
                for (i = 0; i < asterisksArray.length; i++) {
                  column = asterisksArray[i];

                  colWidth = parseInt(asteriskVal * column.width.length, 10);

                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
                    colWidth = column.colDef.minWidth;

                    remainingWidth = remainingWidth - colWidth;
                    asteriskNum--;

                    canvasWidth += colWidth;
                    column.drawnWidth = colWidth;

                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';

                    lastColumn = column;

                    // Remove this element from the percent array so it's not processed below
                    asterisksArray.splice(i, 1);
                  }
                  else  if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
                    colWidth = column.colDef.maxWidth;

                    remainingWidth = remainingWidth - colWidth;
                    asteriskNum--;

                    canvasWidth += colWidth;
                    column.drawnWidth = colWidth;

                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';

                    // Remove this element from the percent array so it's not processed below
                    asterisksArray.splice(i, 1);
                  }
                }

                // Redo the asterisk value, as we may have removed columns due to width constraints
                asteriskVal = parseInt(remainingWidth / asteriskNum, 10);

                asterisksArray.forEach(function(column) {
                  var colWidth = parseInt(asteriskVal * column.width.length, 10);

                  canvasWidth += colWidth;

                  column.drawnWidth = colWidth;

                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
                });
              }

              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
              var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);

              if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
                debugger;

                var variableColumn = false;
                uiGridCtrl.grid.columns.forEach(function(col) {
                  if (col.width && ! angular.isNumber(col.width)) {
                    variableColumn = true;
                  }
                });

                if (variableColumn) {
                  var remFn = function (column) {
                    if (leftoverWidth > 0) {
                      column.drawnWidth = column.drawnWidth + 1;
                      canvasWidth = canvasWidth + 1;
                      leftoverWidth--;
                    }
                  };
                  while (leftoverWidth > 0) {
                    uiGridCtrl.grid.columns.forEach(remFn);
                  }
                }
              }

              if (canvasWidth < availableWidth) {
                canvasWidth = availableWidth;
              }

              // Build the CSS
              uiGridCtrl.grid.columns.forEach(function (column) {
                ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + column.drawnWidth + 'px; }';
              });

              $scope.columnStyles = ret;

              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
              if (uiGridCtrl.grid.verticalScrollbarWidth) {
                canvasWidth = canvasWidth + uiGridCtrl.grid.verticalScrollbarWidth;
              }
              // canvasWidth = canvasWidth + 1;

              uiGridCtrl.grid.canvasWidth = parseInt(canvasWidth, 10);
            }

            if (uiGridCtrl) {
              uiGridCtrl.header = $elm;

              var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
              if (headerViewport) {
                uiGridCtrl.headerViewport = headerViewport;
              }
            }

            //todo: remove this if by injecting gridCtrl into unit tests
            if (uiGridCtrl) {
              uiGridCtrl.grid.registerStyleComputation({
                priority: 5,
                func: updateColumnWidths
              });
            }
          }
        };
      }
    };
  }]);

})();<commit_msg>Remove debugger statement<commit_after>(function(){
  'use strict';

  angular.module('ui.grid').directive('uiGridHeader', ['$log', '$templateCache', '$compile', 'uiGridConstants', 'gridUtil', '$timeout', function($log, $templateCache, $compile, uiGridConstants, gridUtil, $timeout) {
    var defaultTemplate = 'ui-grid/ui-grid-header';

    return {
      restrict: 'EA',
      // templateUrl: 'ui-grid/ui-grid-header',
      replace: true,
      // priority: 1000,
      require: '?^uiGrid',
      scope: false,
      compile: function($elm, $attrs) {
        return {
          pre: function ($scope, $elm, $attrs, uiGridCtrl) {
            var headerTemplate = ($scope.grid.options.headerTemplate) ? $scope.grid.options.headerTemplate : defaultTemplate;

             gridUtil.getTemplate(headerTemplate)
              .then(function (contents) {
                var template = angular.element(contents);

                var newElm = $compile(template)($scope);
                $elm.append(newElm);

                if (uiGridCtrl) {
                  // Inject a reference to the header viewport (if it exists) into the grid controller for use in the horizontal scroll handler below
                  var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];

                  if (headerViewport) {
                    uiGridCtrl.headerViewport = headerViewport;
                  }
                }
              });
          },

          post: function ($scope, $elm, $attrs, uiGridCtrl) {
            if (uiGridCtrl === undefined) {
              throw new Error('[ui-grid-header] uiGridCtrl is undefined!');
            }

            $log.debug('ui-grid-header link');

            function updateColumnWidths() {
              var asterisksArray = [],
                  percentArray = [],
                  manualArray = [],
                  asteriskNum = 0,
                  totalWidth = 0;

              // Get the width of the viewport
              var availableWidth = uiGridCtrl.grid.getViewportWidth();

              if (typeof(uiGridCtrl.grid.verticalScrollbarWidth) !== 'undefined' && uiGridCtrl.grid.verticalScrollbarWidth !== undefined && uiGridCtrl.grid.verticalScrollbarWidth > 0) {
                availableWidth = availableWidth + uiGridCtrl.grid.verticalScrollbarWidth;
              }

              // The total number of columns
              // var equalWidthColumnCount = columnCount = uiGridCtrl.grid.options.columnDefs.length;
              // var equalWidth = availableWidth / equalWidthColumnCount;

              // The last column we processed
              var lastColumn;

              var manualWidthSum = 0;

              var canvasWidth = 0;

              var ret = '';

              uiGridCtrl.grid.columns.forEach(function(column, i) {
                // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + i + ' { width: ' + equalWidth + 'px; left: ' + left + 'px; }';
                //var colWidth = (typeof(c.width) !== 'undefined' && c.width !== undefined) ? c.width : equalWidth;

                // Skip hidden columns
                if (! column.visible) { return; }

                var colWidth,
                    isPercent = false;

                if (! angular.isNumber(column.width)) {
                  isPercent = isNaN(column.width) ? gridUtil.endsWith(column.width, "%") : false;
                }

                if (angular.isString(column.width) && column.width.indexOf('*') !== -1) { //  we need to save it until the end to do the calulations on the remaining width.
                  asteriskNum = parseInt(asteriskNum + column.width.length, 10);

                  asterisksArray.push(column);
                }
                else if (isPercent) { // If the width is a percentage, save it until the very last.
                  percentArray.push(column);
                }
                else if (angular.isNumber(column.width)) {
                  manualWidthSum = parseInt(manualWidthSum + column.width, 10);

                  canvasWidth = parseInt(canvasWidth, 10) + parseInt(column.width, 10);

                  column.drawnWidth = column.width;

                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + column.width + 'px; }';
                }
              });

              // Get the remaining width (available width subtracted by the manual widths sum)
              var remainingWidth = availableWidth - manualWidthSum;

              var i, column, colWidth;

              if (percentArray.length > 0) {
                // Pre-process to make sure they're all within any min/max values
                for (i = 0; i < percentArray.length; i++) {
                  column = percentArray[i];

                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;

                  colWidth = parseInt(percent * remainingWidth, 10);

                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
                    colWidth = column.colDef.minWidth;

                    remainingWidth = remainingWidth - colWidth;

                    canvasWidth += colWidth;
                    column.drawnWidth = colWidth;

                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';

                    // Remove this element from the percent array so it's not processed below
                    percentArray.splice(i, 1);
                  }
                  else if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
                    colWidth = column.colDef.maxWidth;

                    remainingWidth = remainingWidth - colWidth;

                    canvasWidth += colWidth;
                    column.drawnWidth = colWidth;

                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';

                    // Remove this element from the percent array so it's not processed below
                    percentArray.splice(i, 1);
                  }
                }

                percentArray.forEach(function(column) {
                  var percent = parseInt(column.width.replace(/%/g, ''), 10) / 100;
                  var colWidth = parseInt(percent * remainingWidth, 10);

                  canvasWidth += colWidth;

                  column.drawnWidth = colWidth;

                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
                });
              }

              if (asterisksArray.length > 0) {
                var asteriskVal = parseInt(remainingWidth / asteriskNum, 10);

                 // Pre-process to make sure they're all within any min/max values
                for (i = 0; i < asterisksArray.length; i++) {
                  column = asterisksArray[i];

                  colWidth = parseInt(asteriskVal * column.width.length, 10);

                  if (column.colDef.minWidth && colWidth < column.colDef.minWidth) {
                    colWidth = column.colDef.minWidth;

                    remainingWidth = remainingWidth - colWidth;
                    asteriskNum--;

                    canvasWidth += colWidth;
                    column.drawnWidth = colWidth;

                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';

                    lastColumn = column;

                    // Remove this element from the percent array so it's not processed below
                    asterisksArray.splice(i, 1);
                  }
                  else  if (column.colDef.maxWidth && colWidth > column.colDef.maxWidth) {
                    colWidth = column.colDef.maxWidth;

                    remainingWidth = remainingWidth - colWidth;
                    asteriskNum--;

                    canvasWidth += colWidth;
                    column.drawnWidth = colWidth;

                    // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';

                    // Remove this element from the percent array so it's not processed below
                    asterisksArray.splice(i, 1);
                  }
                }

                // Redo the asterisk value, as we may have removed columns due to width constraints
                asteriskVal = parseInt(remainingWidth / asteriskNum, 10);

                asterisksArray.forEach(function(column) {
                  var colWidth = parseInt(asteriskVal * column.width.length, 10);

                  canvasWidth += colWidth;

                  column.drawnWidth = colWidth;

                  // ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + colWidth + 'px; }';
                });
              }

              // If the grid width didn't divide evenly into the column widths and we have pixels left over, dole them out to the columns one by one to make everything fit
              var leftoverWidth = availableWidth - parseInt(canvasWidth, 10);

              if (leftoverWidth > 0 && canvasWidth > 0 && canvasWidth < availableWidth) {
                var variableColumn = false;
                uiGridCtrl.grid.columns.forEach(function(col) {
                  if (col.width && ! angular.isNumber(col.width)) {
                    variableColumn = true;
                  }
                });

                if (variableColumn) {
                  var remFn = function (column) {
                    if (leftoverWidth > 0) {
                      column.drawnWidth = column.drawnWidth + 1;
                      canvasWidth = canvasWidth + 1;
                      leftoverWidth--;
                    }
                  };
                  while (leftoverWidth > 0) {
                    uiGridCtrl.grid.columns.forEach(remFn);
                  }
                }
              }

              if (canvasWidth < availableWidth) {
                canvasWidth = availableWidth;
              }

              // Build the CSS
              uiGridCtrl.grid.columns.forEach(function (column) {
                ret = ret + ' .grid' + uiGridCtrl.grid.id + ' .col' + column.index + ' { width: ' + column.drawnWidth + 'px; }';
              });

              $scope.columnStyles = ret;

              // Add the vertical scrollbar width back in to the canvas width, it's taken out in getCanvasWidth
              if (uiGridCtrl.grid.verticalScrollbarWidth) {
                canvasWidth = canvasWidth + uiGridCtrl.grid.verticalScrollbarWidth;
              }
              // canvasWidth = canvasWidth + 1;

              uiGridCtrl.grid.canvasWidth = parseInt(canvasWidth, 10);
            }

            if (uiGridCtrl) {
              uiGridCtrl.header = $elm;

              var headerViewport = $elm[0].getElementsByClassName('ui-grid-header-viewport')[0];
              if (headerViewport) {
                uiGridCtrl.headerViewport = headerViewport;
              }
            }

            //todo: remove this if by injecting gridCtrl into unit tests
            if (uiGridCtrl) {
              uiGridCtrl.grid.registerStyleComputation({
                priority: 5,
                func: updateColumnWidths
              });
            }
          }
        };
      }
    };
  }]);

})();<|endoftext|>


<commit_before>( function( angular ) {
  'use strict';

  var trail = function( str, ch ) {
    return !str.match( new RegExp( ch + '$' ) ) ? str + ch : str;
  };

  var RouteContext = function( routeProvider ) {

    // Turns action key/value pair into object.
    //
    // Examples:
    //
    // objectifyAction( 'member', 'details' )
    // returns  { type: 'member', key : 'details' }
    //
    // objectifyAction( 'member', 'details' )
    // returns { type: 'member', key : 'details' };
    //
    // objectifyAction( 'member', 'details:edit' )
    // returns { type: 'member', key : 'details', alias:'edit' };
    //
    // objectifyAction( { type: 'member', alias:'edit'}, 'details' )
    // returns { type: 'member', alias:'edit', key : 'details' };
    var objectifyAction = function( action, key ) {
      var actionObj = {},
      keyalias = key.split( ':' );

      // if alias is encoded in key add it to obj and change key
      if ( keyalias.length >= 2 ) {
        key = keyalias[0];
        actionObj.alias = keyalias[1];
      }

      // add string actions as type
      if ( angular.isString( action ) ) {
        actionObj.type = action;
      }

      // extend actionObj with object actions
      if ( angular.isObject( action ) ) {
        actionObj = angular.extend( actionObj, action );
      }
      // add key and return
      return angular.extend( actionObj, { key: key } );
    };

    this.resource = function( options, scopedObject ) {

      var routeContext = new RouteContext( routeProvider );
      routeContext.scopeParent = this;

      routeContext.options = angular.extend( {}, this.options, options );

      var resource = routeContext.options;
      var actions = resource.actions || routeProvider.defaultActions;

      var path = resource.path ? resource.path + '/' : '';
      var routePrefix = resource.routePrefix || '/';

      var ctx = routeContext;
      var controllerPath = '';
      while (ctx.scopeParent) {
        controllerPath = ctx.options.name + '/' + controllerPath;
        ctx = ctx.scopeParent;
      }
      controllerPath = controllerPath.replace(/\/$/, '');

      // put collection actions first to ensure for example, that pr/new is not read as a details route (pr/:code).
      var orderedKeys = _.sortBy( _.keys( actions ), function( key ) { return actions[key] !== 'collection'; } );

      angular.forEach( orderedKeys, function( key ) {
        var action = objectifyAction( actions[key], key ),
        parentName = ( routeContext.scopeParent.options || { name: '' } ).name || '',
        aliasedParentName = angular.isDefined(( routeContext.scopeParent.options || {} ).urlAlias )
                     ? routeContext.scopeParent.options.urlAlias : ( routeContext.scopeParent.options || { name: '' } ).name || '',
        parentPath = ( path + parentName ) ? trail( path + parentName, '/' ) : '',
        aliasedParentPath = ( path + aliasedParentName ) ? trail( path + aliasedParentName, '/' ) : '',
        parentParam = !parentName ? '' : ( ':' + ( routeContext.scopeParent.options || { name: '' } ).name + '_id/' ),
        resourcePath = parentPath + resource.name + '/',
        resourceParam = ':' + angular.lowercase( resource.name ) + '_id/',
        viewLocation = angular.lowercase( trail( routeProvider.appRoot, '/' ) + resourcePath + ( action.alias || action.key ) + '.html' ),
        routeWithoutKey = angular.lowercase( aliasedParentPath + parentParam + ( angular.isDefined( resource.urlAlias ) ? resource.urlAlias : resource.name ) + '/' ).replace( '//', '/' );

        if ( action.type === 'member' ) {
          routeWithoutKey += resourceParam;
        }

        var routePath = angular.lowercase( routePrefix + routeWithoutKey );

        var routeProperties = {
          name: resource.name,
          templateUrl: viewLocation,
          reloadOnSearch: angular.isDefined( resource.reloadOnSearch ) ? resource.reloadOnSearch : true,
          layoutUrl: resource.layoutUrl,
          action: action.key,
          path: resource.path || '',
          urlAlias: resource.urlAlias,
          routePrefix: routePrefix,
          routePath: routePath,
          isResource: true,
          viewScope: action.type || 'member',
          controllerPath: controllerPath
        };

        if ( resource.routeTransform ) {
          resource.routeTransform( routeProperties );
        }

        routeProvider.$routeProvider.when( routePath + action.key, routeProperties );

        if ( action.key === routeProvider.collectionDefaultAction || action.key === routeProvider.memberDefaultAction ) {
          routeProvider.$routeProvider.when( routePath, {
            controllerPath: controllerPath,
            path: routeProperties.path,
            routePath: routePath,
            redirectTo: angular.lowercase( routePath + action.key )
          } );
        }
      } );

      //reset the parent scope's options to ignore any actions defined on this resource
      if ( options && options.actions ) {
        if ( this.options && this.options.actions ) {
          routeContext.options.actions = this.options.actions;
        } else {
          routeContext.options.actions = routeProvider.defaultActions;
        }
      }

      if ( scopedObject ) {
        scopedObject.call( routeContext );
      }

      return routeContext;
    };

    this.scope = function( options, scopedObject ) {
      var scopeContext = new RouteContext( routeProvider );
      scopeContext.options = options;
      angular.extend( scopeContext.options, this.options );

      scopedObject.call( scopeContext );
      return scopeContext;
    };

  };

  var routeProvider = function() {
    // -- config

    this.$routeProvider = routeProvider.$routeProvider;
    this.appRoot = 'client/app/';
    this.defaultActions = {
      'index': 'collection',
      'new': 'collection',
      'edit': 'member',
      'details': 'member'
    };
    this.collectionDefaultAction = 'index';
    this.memberDefaultAction = 'details';

    // -- end config

    this.resource = function( options, scopedObject ) {
      if ( angular.isString( options ) )
        options = { name: options };

      var routeContext = new RouteContext( this );
      routeContext.resource( options, scopedObject );
      return routeContext;
    };

    this.scope = function( options, scopedObject ) {
      var routeContext = new RouteContext( this );
      routeContext.options = angular.extend( {}, options, this.options );

      scopedObject.call( routeContext );
      return routeContext;
    };

    this.$get = ['$route', '$routeParams', '$location', function( $route, $routeParams, $location ) {

      return {
        link: function( options, additionalOptions ) {
          var params,
          intendedRoute = null,
          searchTerm = '',
          search,
          action,
          path,
          controller;

          if ( angular.isString(options) ) {
            var linkText = options;
            options = additionalOptions || {};
            if (linkText.indexOf('#') >= 0) {
              options.controller = linkText.substr(0, linkText.indexOf('#'));
              options.action = linkText.substr(linkText.indexOf('#') +1 );
            }
            else {
              options.controller = linkText;
            }
          }
          params = angular.extend( {}, $routeParams, options );

          if ($route.current) {
            controller = angular.lowercase( options.controller || $route.current.controllerPath );
            action = angular.lowercase( options.action || $route.current.action );
            path = angular.lowercase( options.path || $route.current.path || '' );
          } else {
            controller = angular.lowercase( options.controller );
            action = angular.lowercase( options.action );
            path = angular.lowercase( options.path );
          }

          if ( controller && !action ) { // we're just moving to a new controller and accepting the default action
            intendedRoute = _.find( $route.routes, function( r ) {
              return angular.lowercase( r.path || '' ) === path &&
              angular.lowercase( r.controllerPath ) === controller
            } );
          } else {
            intendedRoute = _.find( $route.routes, function( r ) {
                return (!$route.current || angular.lowercase( r.path || '' ) === path) &&
                angular.lowercase( r.controllerPath ) === controller &&
                angular.lowercase( r.action ) === action;
            } );
          }

          if ( !intendedRoute ) {
            return 'notfound?controller=' + controller +'&action=' + action;
          }
          // carry the search term over if the same route name
          search = $location.search();
          if ( !_.isEmpty( search ) && ( $route.current && intendedRoute.name === $route.current.$route.name ) ) {
            if ( intendedRoute.action === 'index' ) {
              searchTerm = decodeURIComponent( search.back || '' );
            }
            else if ( _.isUndefined( search.back ) ) {
              searchTerm = 'back=' + _.encodeUriQuery( _.toKeyValue( search ) );
            }
            else {
              searchTerm = _.toKeyValue( search );
            }
          }
          var path = ( intendedRoute.routePath + ( intendedRoute.action || '' ) ).
          replace( /:([^\/]+)/ig, function( match, group1 ) { return params[group1]; } );
          // remove trailing '/' to ensure hrefs works when running under a url prefix (e.g. http://localhost/MyApp/)
          path = path.replace( /^\/+/, '' );

          return path + ( searchTerm ? '?' + searchTerm : '' );
        },
        action: function( action ) {
          return this.link( { action: action } );
        },
        gotoLink: function( options ) {
          $location.url( this.link( options ) );
        },
        gotoAction: function( action ) {
          $location.url( this.action( action ) );
        }
      };
    }];
  };

  angular.module( 'cs.modules' ).config( ['$provide', '$routeProvider', function( $provide, $routeProvider ) {
    routeProvider.$routeProvider = $routeProvider;
    $provide.provider( 'route', routeProvider );
  }] );

} )( window.angular );
<commit_msg>tightened up default route finding (niave). fixed spacing<commit_after>( function( angular ) {
  'use strict';

  var trail = function( str, ch ) {
    return !str.match( new RegExp( ch + '$' ) ) ? str + ch : str;
  };

  var RouteContext = function( routeProvider ) {

    // Turns action key/value pair into object.
    //
    // Examples:
    //
    // objectifyAction( 'member', 'details' )
    // returns  { type: 'member', key : 'details' }
    //
    // objectifyAction( 'member', 'details' )
    // returns { type: 'member', key : 'details' };
    //
    // objectifyAction( 'member', 'details:edit' )
    // returns { type: 'member', key : 'details', alias:'edit' };
    //
    // objectifyAction( { type: 'member', alias:'edit'}, 'details' )
    // returns { type: 'member', alias:'edit', key : 'details' };
    var objectifyAction = function( action, key ) {
      var actionObj = {},
      keyalias = key.split( ':' );

      // if alias is encoded in key add it to obj and change key
      if ( keyalias.length >= 2 ) {
        key = keyalias[0];
        actionObj.alias = keyalias[1];
      }

      // add string actions as type
      if ( angular.isString( action ) ) {
        actionObj.type = action;
      }

      // extend actionObj with object actions
      if ( angular.isObject( action ) ) {
        actionObj = angular.extend( actionObj, action );
      }
      // add key and return
      return angular.extend( actionObj, { key: key } );
    };

    this.resource = function( options, scopedObject ) {

      var routeContext = new RouteContext( routeProvider );
      routeContext.scopeParent = this;

      routeContext.options = angular.extend( {}, this.options, options );

      var resource = routeContext.options;
      var actions = resource.actions || routeProvider.defaultActions;

      var path = resource.path ? resource.path + '/' : '';
      var routePrefix = resource.routePrefix || '/';

      var ctx = routeContext;
      var controllerPath = '';
      while ( ctx.scopeParent ) {
        controllerPath = ctx.options.name + '/' + controllerPath;
        ctx = ctx.scopeParent;
      }
      controllerPath = controllerPath.replace( /\/$/, '' );

      // put collection actions first to ensure for example, that pr/new is not read as a details route (pr/:code).
      var orderedKeys = _.sortBy( _.keys( actions ), function( key ) { return actions[key] !== 'collection'; } );

      angular.forEach( orderedKeys, function( key ) {
        var action = objectifyAction( actions[key], key ),
        parentName = ( routeContext.scopeParent.options || { name: '' } ).name || '',
        aliasedParentName = angular.isDefined(( routeContext.scopeParent.options || {} ).urlAlias )
                     ? routeContext.scopeParent.options.urlAlias : ( routeContext.scopeParent.options || { name: '' } ).name || '',
        parentPath = ( path + parentName ) ? trail( path + parentName, '/' ) : '',
        aliasedParentPath = ( path + aliasedParentName ) ? trail( path + aliasedParentName, '/' ) : '',
        parentParam = !parentName ? '' : ( ':' + ( routeContext.scopeParent.options || { name: '' } ).name + '_id/' ),
        resourcePath = parentPath + resource.name + '/',
        resourceParam = ':' + angular.lowercase( resource.name ) + '_id/',
        viewLocation = angular.lowercase( trail( routeProvider.appRoot, '/' ) + resourcePath + ( action.alias || action.key ) + '.html' ),
        routeWithoutKey = angular.lowercase( aliasedParentPath + parentParam + ( angular.isDefined( resource.urlAlias ) ? resource.urlAlias : resource.name ) + '/' ).replace( '//', '/' );

        if ( action.type === 'member' ) {
          routeWithoutKey += resourceParam;
        }

        var routePath = angular.lowercase( routePrefix + routeWithoutKey );

        var routeProperties = {
          name: resource.name,
          templateUrl: viewLocation,
          reloadOnSearch: angular.isDefined( resource.reloadOnSearch ) ? resource.reloadOnSearch : true,
          layoutUrl: resource.layoutUrl,
          action: action.key,
          path: resource.path || '',
          urlAlias: resource.urlAlias,
          routePrefix: routePrefix,
          routePath: routePath,
          isResource: true,
          viewScope: action.type || 'member',
          controllerPath: controllerPath
        };

        if ( resource.routeTransform ) {
          resource.routeTransform( routeProperties );
        }

        routeProvider.$routeProvider.when( routePath + action.key, routeProperties );

        if ( action.key === routeProvider.collectionDefaultAction || action.key === routeProvider.memberDefaultAction ) {
          routeProvider.$routeProvider.when( routePath, {
            controllerPath: controllerPath,
            path: routeProperties.path,
            routePath: routePath,
            redirectTo: angular.lowercase( routePath + action.key )
          } );
        }
      } );

      //reset the parent scope's options to ignore any actions defined on this resource
      if ( options && options.actions ) {
        if ( this.options && this.options.actions ) {
          routeContext.options.actions = this.options.actions;
        } else {
          routeContext.options.actions = routeProvider.defaultActions;
        }
      }

      if ( scopedObject ) {
        scopedObject.call( routeContext );
      }

      return routeContext;
    };

    this.scope = function( options, scopedObject ) {
      var scopeContext = new RouteContext( routeProvider );
      scopeContext.options = options;
      angular.extend( scopeContext.options, this.options );

      scopedObject.call( scopeContext );
      return scopeContext;
    };

  };

  var routeProvider = function() {
    // -- config

    this.$routeProvider = routeProvider.$routeProvider;
    this.appRoot = 'client/app/';
    this.defaultActions = {
      'index': 'collection',
      'new': 'collection',
      'edit': 'member',
      'details': 'member'
    };
    this.collectionDefaultAction = 'index';
    this.memberDefaultAction = 'details';

    // -- end config

    this.resource = function( options, scopedObject ) {
      if ( angular.isString( options ) )
        options = { name: options };

      var routeContext = new RouteContext( this );
      routeContext.resource( options, scopedObject );
      return routeContext;
    };

    this.scope = function( options, scopedObject ) {
      var routeContext = new RouteContext( this );
      routeContext.options = angular.extend( {}, options, this.options );

      scopedObject.call( routeContext );
      return routeContext;
    };

    this.$get = ['$route', '$routeParams', '$location', function( $route, $routeParams, $location ) {

      return {
        link: function( options, additionalOptions ) {
          var params,
          intendedRoute = null,
          searchTerm = '',
          search,
          action,
          path,
          controller;

          if ( angular.isString( options ) ) {
            var linkText = options;
            options = additionalOptions || {};
            if ( linkText.indexOf( '#' ) >= 0 ) {
              options.controller = linkText.substr( 0, linkText.indexOf( '#' ) );
              options.action = linkText.substr( linkText.indexOf( '#' ) + 1 );
            }
            else {
              options.controller = linkText;
            }
          }
          params = angular.extend( {}, $routeParams, options );

          if ( $route.current ) {
            controller = angular.lowercase( options.controller || $route.current.controllerPath );
            action = angular.lowercase( options.action || $route.current.action );
            path = angular.lowercase( options.path || $route.current.path || '' );
          } else {
            controller = angular.lowercase( options.controller );
            action = angular.lowercase( options.action );
            path = angular.lowercase( options.path );
          }

          if ( options.controller && !options.action ) { // we're just moving to a new controller and accepting the default action
            intendedRoute = _.find( $route.routes, function( r ) {
              return angular.lowercase( r.path || '' ) === path &&
                angular.lowercase( r.controllerPath ) === controller &&
                ( angular.lowercase( r.action ) === ( options[r.name + "_id"] ? 'details' : 'index' ) );
            } );
          } else {
            intendedRoute = _.find( $route.routes, function( r ) {
              return ( !$route.current || angular.lowercase( r.path || '' ) === path ) &&
              angular.lowercase( r.controllerPath ) === controller &&
              angular.lowercase( r.action ) === action;
            } );
          }

          if ( !intendedRoute ) {
            return 'notfound?controller=' + controller + '&action=' + action;
          }

          // carry the search term over if the same route name
          search = $location.search();
          if ( !_.isEmpty( search ) && ( $route.current && intendedRoute.name === $route.current.$route.name ) ) {
            if ( intendedRoute.action === 'index' ) {
              searchTerm = decodeURIComponent( search.back || '' );
            }
            else if ( _.isUndefined( search.back ) ) {
              searchTerm = 'back=' + _.encodeUriQuery( _.toKeyValue( search ) );
            }
            else {
              searchTerm = _.toKeyValue( search );
            }
          }

          var resultPath = ( intendedRoute.routePath + ( intendedRoute.action || '' ) ).
            replace( /:([^\/]+)/ig, function( match, group1 ) { return params[group1]; } );
          // remove trailing '/' to ensure hrefs works when running under a url prefix (e.g. http://localhost/MyApp/)
          resultPath = resultPath.replace( /^\/+/, '' );

          return resultPath + ( searchTerm ? '?' + searchTerm : '' );
        },
        action: function( action ) {
          return this.link( { action: action } );
        },
        gotoLink: function( options ) {
          $location.url( this.link( options ) );
        },
        gotoAction: function( action ) {
          $location.url( this.action( action ) );
        }
      };
    }];
  };

  angular.module( 'cs.modules' ).config( ['$provide', '$routeProvider', function( $provide, $routeProvider ) {
    routeProvider.$routeProvider = $routeProvider;
    $provide.provider( 'route', routeProvider );
  }] );

} )( window.angular );
<|endoftext|>


<commit_before>import Rx from 'rx'
let fromEvent = Rx.Observable.fromEvent
let Observable = Rx.Observable
let merge = Rx.Observable.merge

import logger from '../utils/log'
let log = logger("comments")
log.setLevel("info")

import {generateUUID} from 'usco-kernel2/src/utils'
import {toArray} from '../utils/utils'

//"comments" system
const defaults = {
  data:[
     /*{text:"bla bla details",author:"foo"},
     {text:"oh yes cool ",author:"bar"},*/
  ]
  ,bykey:{

  }
}

//comments[key]= "some quite long text, with markdown support "

function makeModification(intent){
  /*add comments*/
  let addComments$ = intent.addComments$
    .withLatestFrom(intent.settings$,function(newData,settings){
      return {newData, settings}
    })
    .map(({newData,settings}) => (existingData) => {
      log.info("adding comments", newData)

      let {data,bykey} = existingData
      let newComments = toArray(newData)
      let updatedData = Object.assign({},existingData)

      newComments.map(function(comment){
        let {iuid,typeUid} = comment.target
        let text = comment.text

        let key = [iuid,typeUid] /*{iUid:"xx",tUid:"xx", toString(){
          iUid+tUid
        }}*/

        //FIXME: how to deal with authors ?

        let entry = {text:text, author:"jon doe", iuid, typeUid}
        if(!updatedData.bykey[key])
          updatedData.bykey[key] = [] //we need LISTS of comments

        updatedData.bykey[key].push( entry )
        updatedData.data.push( entry )
      })
      return updatedData
    })

  return merge(
    addComments$
  )
}

function comments(intent, source) {
  let source$ = source || Observable.just(defaults)
  let modification$ = makeModification(intent)

  return modification$
    .merge(source$)
    .scan((existingData, modFn) => modFn(existingData))//combine existing data with new one
    //.distinctUntilChanged()
    .shareReplay(1)
}

export default comments<commit_msg>- modified /simplified comments model<commit_after>import Rx from 'rx'
let fromEvent = Rx.Observable.fromEvent
let Observable = Rx.Observable
let merge = Rx.Observable.merge

import logger from '../utils/log'
let log = logger("comments")
log.setLevel("info")

import {generateUUID} from 'usco-kernel2/src/utils'
import {toArray} from '../utils/utils'

//"comments" system
const defaults = {
  data:[
     /*{text:"bla bla details",author:"foo"},
     {text:"oh yes cool ",author:"bar"},*/
  ]
  ,bykey:{

  }
}

//comments[key]= "some quite long text, with markdown support "

function makeModification(intent){
  /*add comments*/
  let addComments$ = intent.addComments$
    .withLatestFrom(intent.settings$,function(newData,settings){
      return {newData, settings}
    })
    .map(({newData,settings}) => (existingData) => {
      log.info("adding comments", newData)

      let {data,bykey} = existingData
      let newComments = toArray(newData)
      let updatedData = Object.assign({},existingData)

      newComments.map(function(comment){
        let {iuid,typeUid} = comment.target
        let text = comment.text

        let key = [iuid,typeUid] /*{iUid:"xx",tUid:"xx", toString(){
          iUid+tUid
        }}*/

        //FIXME: how to deal with authors ?

        let entry = {text, author:"jon doe", key}
        if(!updatedData.bykey[key])
          updatedData.bykey[key] = [] //we need LISTS of comments

        updatedData.bykey[key].push( entry )
        updatedData.data.push( entry )
      })
      return updatedData
    })

  return merge(
    addComments$
  )
}

function comments(intent, source) {
  let source$ = source || Observable.just(defaults)
  let modification$ = makeModification(intent)

  return modification$
    .merge(source$)
    .scan((existingData, modFn) => modFn(existingData))//combine existing data with new one
    //.distinctUntilChanged()
    .shareReplay(1)
}

export default comments<|endoftext|>


<commit_before>import warning from 'warning'

/*eslint-disable no-empty */
const KeyPrefix = '@@History/'

function createKey(key) {
  return KeyPrefix + key
}

export function saveState(key, state) {
  try {
    window.sessionStorage.setItem(createKey(key), JSON.stringify(state))
  } catch (error) {
    if (error.name === 'QuotaExceededError')
      return warning(null, 'sessionStore is not accessible in incognito mode')

    throw error
  }
}

export function readState(key) {
  let json = window.sessionStorage.getItem(createKey(key))

  if (json) {
    try {
      return JSON.parse(json)
    } catch (error) {
      // Ignore invalid JSON.
    }
  }

  return null
}
<commit_msg>Update warning message<commit_after>import warning from 'warning'

/*eslint-disable no-empty */
const KeyPrefix = '@@History/'
const QuotaExceededError = 'QuotaExceededError'

function createKey(key) {
  return KeyPrefix + key
}

export function saveState(key, state) {
  try {
    window.sessionStorage.setItem(createKey(key), JSON.stringify(state))
  } catch (error) {
    if (error.name === QuotaExceededError || window.sessionStorage.length === 0) {
      // Probably in Safari "private mode" where sessionStorage quota is 0. #42
      warning(
        false,
        '[history] Unable to save state; sessionStorage is not available in Safari private mode'
      )

      return
    }

    throw error
  }
}

export function readState(key) {
  const json = window.sessionStorage.getItem(createKey(key))

  if (json) {
    try {
      return JSON.parse(json)
    } catch (error) {
      // Ignore invalid JSON.
    }
  }

  return null
}
<|endoftext|>


<commit_before>;(function(window, document, fabric) {
  'use strict';

  /**
   * @param Element|string element Image element
   * @param Array          options Options
   */
  function Darkroom(element, options) {
    return this.init(element, options);
  }

  window.Darkroom = Darkroom;
  Darkroom.plugins = [];

  if (window.module !== undefined) {
    module.exports = Darkroom;
  }

  Darkroom.extend = extend;

  function extend(b, a) {
    var prop;
    if (b === undefined) {
      return a;
    }
    for (prop in a) {
      if (a.hasOwnProperty(prop) && b.hasOwnProperty(prop) === false) {
        b[prop] = a[prop];
      }
    }
    return b;
  }

  function Plugin(darkroom, options) {
    this.darkroom = darkroom;
    this.options = extend(options, this.defaults);
    this.initialize();
  }

  Plugin.prototype = {
    defaults: {},
    initialize: function() { }
  }

  Plugin.extend = function(protoProps) {
    var parent = this;
    var child;

    if (protoProps && protoProps.hasOwnProperty('constructor')) {
      child = protoProps.constructor;
    } else {
      child = function(){ return parent.apply(this, arguments); };
    }

    extend(child, parent);

    var Surrogate = function(){ this.constructor = child; };
    Surrogate.prototype = parent.prototype;
    child.prototype = new Surrogate;

    if (protoProps) extend(child.prototype, protoProps);

    child.__super__ = parent.prototype;

    return child;
  }

  Darkroom.Plugin = Plugin;

  function Toolbar(element) {
    this.element = element;
    this.actionsElement = element.querySelector('.darkroom-toolbar-actions');
  }

  Toolbar.prototype.createButtonGroup = function(options) {
    var buttonGroup = document.createElement('li');
    buttonGroup.className = 'darkroom-button-group';
    //buttonGroup.innerHTML = '

';
    this.actionsElement.appendChild(buttonGroup);

    return new ButtonGroup(buttonGroup);
  };

  function ButtonGroup(element) {
    this.element = element;
  }

  ButtonGroup.prototype.createButton = function(options) {
    var defaults = {
      image: 'help',
      type: 'default',
      group: 'default',
      hide: false,
      disabled: false
    };

    options = extend(options, defaults);

    var button = document.createElement('button');
    button.className = 'darkroom-button darkroom-button-' + options.type;
    button.innerHTML = '';
    this.element.appendChild(button);

    var button = new Button(button);
    button.hide(options.hide);
    button.disable(options.disabled);

    return button;
  }

  function Button(element) {
    this.element = element;
  }
  Button.prototype = {
    addEventListener: function(eventName, callback) {
      this.element.addEventListener(eventName, callback);
    },
    active: function(value) {
      if (value)
        this.element.classList.add('darkroom-button-active');
      else
        this.element.classList.remove('darkroom-button-active');
    },
    hide: function(value) {
      if (value)
        this.element.classList.add('darkroom-button-hidden');
      else
        this.element.classList.remove('darkroom-button-hidden');
    },
    disable: function(value) {
      this.element.disabled = (value) ? true : false;
    }
  };

  var Canvas = fabric.util.createClass(fabric.Canvas, {
  });

  Darkroom.prototype = {
    defaults: {
      minWidth: null,
      minHeight: null,
      maxWidth: null,
      maxHeight: null,
      plugins: {},
      init: function() {}
    },

    addEventListener: function(eventName, callback) {
      this.canvas.getElement().addEventListener(eventName, callback);
    },
    dispatchEvent: function(event) {
      this.canvas.getElement().dispatchEvent(event);
    },

    init: function(element, options) {
      var _this = this;
      this.options = extend(options, this.defaults);

      if (typeof element === 'string')
        element = document.querySelector(element);
      if (null === element)
        return;

      var plugins = Darkroom.plugins;

      var image = new Image();

      image.onload = function() {
        _this
          .initDOM(element)
          .initImage(element)
          .initPlugins(plugins)
        ;

        // Execute a custom callback after initialization
        _this.options.init.bind(_this).call();
      }

      //image.crossOrigin = 'anonymous';
      image.src = element.src;
    },

    initDOM: function(element) {
      // Create toolbar element
      var toolbar = document.createElement('div');
      toolbar.className = 'darkroom-toolbar';
      toolbar.innerHTML = '

';

      // Create canvas element
      var canvas = document.createElement('canvas');
      var canvasContainer = document.createElement('div');
      canvasContainer.className = 'darkroom-image-container';
      canvasContainer.appendChild(canvas);

      // Create container element
      this.container = document.createElement('div');
      this.container.className = 'darkroom-container';

      // Assemble elements
      this.container.appendChild(toolbar);
      this.container.appendChild(canvasContainer);

      // Replace image with new DOM
      element.parentNode.replaceChild(this.container, element);

      // Save elements
      this.toolbar = new Toolbar(toolbar);
      this.canvas = new Canvas(canvas, {
        selection: false,
        backgroundColor: '#ccc',
      });

      return this;
    },

    initImage: function(image) {
      var width = image.width;
      var height = image.height;
      var scale = 1;
      var scaleX = 1;
      var scaleY = 1;

      if (null !== this.options.maxWidth && this.options.maxWidth < width) {
        scaleX =  this.options.maxWidth / width;
      }
      if (null !== this.options.maxHeight && this.options.maxHeight < height) {
        scaleY =  this.options.maxHeight / height;
      }
      scale = Math.min(scaleX, scaleY);

      if (null !== this.options.minWidth && this.options.minWidth > width) {
        scaleX =  this.options.minWidth / width;
      }
      if (null !== this.options.minHeight && this.options.minHeight > height) {
        scaleY =  this.options.minHeight / height;
      }
      scale = Math.max(scaleX, scaleY);

      width *= scale;
      height *= scale;

      this.image = new fabric.Image(image, {
        // options to make the image static
        selectable: false,
        evented: false,
        lockMovementX: true,
        lockMovementY: true,
        lockRotation: true,
        lockScalingX: true,
        lockScalingY: true,
        lockUniScaling: true,
        hasControls: false,
        hasBorders: false
      });
      this.image.setScaleX(scale);
      this.image.setScaleY(scale);

      this.canvas.setWidth(width);
      this.canvas.setHeight(height);
      this.canvas.add(this.image);
      this.canvas.centerObject(this.image);
      this.image.setCoords();

      return this;
    },

    initPlugins: function(plugins) {
      this.plugins = {};

      for (var name in plugins) {
        var plugin = plugins[name];
        var options = this.options.plugins[name];

        // Setting false into the plugin options will disable the plugin
        if (options === false) {
          continue;
        }

        this.plugins[name] = new plugin(this, options);
      }
    },

    getPlugin: function(name) {
      return this.plugins[name];
    },

    selfDestroy: function() {
      var container = this.container;

      var image = new Image();
      image.onload = function() {
        container.parentNode.replaceChild(image, container);
      }

      image.src = this.snapshotImage();

      // TODO
      // - destroy plugins
      // - delete canvas
    },

    snapshotImage: function() {
      return this.image.toDataURL();
    }

  };

})(window, window.document, fabric);
<commit_msg>Start some docs/comments<commit_after>//     DarkroomJS

//     (c) 2013 Matthieu Moquet.
//     DarkroomJS may be freely distributed under the MIT license.
//     For all details and documentation:
//     http://mattketmo.github.io/darkroomjs

;(function(window, document, fabric) {
  'use strict';

  // Utilities
  // ---------

  // Utility method to easily extend objects.
  function extend(b, a) {
    var prop;
    if (b === undefined) {
      return a;
    }
    for (prop in a) {
      if (a.hasOwnProperty(prop) && b.hasOwnProperty(prop) === false) {
        b[prop] = a[prop];
      }
    }
    return b;
  }

  // Root definitions
  // ----------------

  // Core object of DarkroomJS.
  // Basically it's a single object, instanciable via an element
  // (it could be a CSS selector or a DOM element), some custom options,
  // and a list of plugin objects (or none to use default ones).
  function Darkroom(element, options, plugins) {
    return this.init(element, options, plugins);
  }

  // Darkroom namespace is the only one available outside of this context.
  window.Darkroom = Darkroom;

  // Create an empty list of plugin objects, which will be filled by
  // other plugin scripts. This is the default plugin list if none is
  // specified in Darkroom'ss constructor.
  Darkroom.plugins = [];

  // Define a plugin object. This is the (abstract) parent class which
  // has to be extended for each plugin.
  function Plugin(darkroom, options) {
    this.darkroom = darkroom;
    this.options = extend(options, this.defaults);
    this.initialize();
  }

  Plugin.prototype = {
    defaults: {},
    initialize: function() { }
  }

  // Inspired by Backbone.js extend capability.
  Plugin.extend = function(protoProps) {
    var parent = this;
    var child;

    if (protoProps && protoProps.hasOwnProperty('constructor')) {
      child = protoProps.constructor;
    } else {
      child = function(){ return parent.apply(this, arguments); };
    }

    extend(child, parent);

    var Surrogate = function(){ this.constructor = child; };
    Surrogate.prototype = parent.prototype;
    child.prototype = new Surrogate;

    if (protoProps) extend(child.prototype, protoProps);

    child.__super__ = parent.prototype;

    return child;
  }

  // Attach the plugin class into the main namespace.
  Darkroom.Plugin = Plugin;

  // UI elements
  // -----------

  // Toolbar object.
  function Toolbar(element) {
    this.element = element;
    this.actionsElement = element.querySelector('.darkroom-toolbar-actions');
  }

  Toolbar.prototype.createButtonGroup = function(options) {
    var buttonGroup = document.createElement('li');
    buttonGroup.className = 'darkroom-button-group';
    /*buttonGroup.innerHTML = '

';*/
    this.actionsElement.appendChild(buttonGroup);

    return new ButtonGroup(buttonGroup);
  };

  // ButtonGroup object.
  function ButtonGroup(element) {
    this.element = element;
  }

  ButtonGroup.prototype.createButton = function(options) {
    var defaults = {
      image: 'help',
      type: 'default',
      group: 'default',
      hide: false,
      disabled: false
    };

    options = extend(options, defaults);

    var button = document.createElement('button');
    button.className = 'darkroom-button darkroom-button-' + options.type;
    button.innerHTML = '';
    this.element.appendChild(button);

    var button = new Button(button);
    button.hide(options.hide);
    button.disable(options.disabled);

    return button;
  }

  // Button object.
  function Button(element) {
    this.element = element;
  }
  Button.prototype = {
    addEventListener: function(eventName, callback) {
      this.element.addEventListener(eventName, callback);
    },
    active: function(value) {
      if (value)
        this.element.classList.add('darkroom-button-active');
      else
        this.element.classList.remove('darkroom-button-active');
    },
    hide: function(value) {
      if (value)
        this.element.classList.add('darkroom-button-hidden');
      else
        this.element.classList.remove('darkroom-button-hidden');
    },
    disable: function(value) {
      this.element.disabled = (value) ? true : false;
    }
  };

  // Extend the default fabric canvas object to add default options.
  var Canvas = fabric.util.createClass(fabric.Canvas, {
  });

  // Core object prototype
  // ---------------------

  Darkroom.prototype = {
    // This is the default options.
    // It has it's own options, such as dimension specification (min/max
    // width and height), plus options for each plugins.
    // Option for those plugins are passed through plugin name.
    // `init` option is a callback called after image is loaded into the
    // canvas.
    defaults: {
      // main options
      minWidth: null,
      minHeight: null,
      maxWidth: null,
      maxHeight: null,

      // plugins options
      plugins: {},

      // after initialisation callback
      init: function() {}
    },

    // Add ability to attach event listener on the core object.
    // It uses the canvas element to process events.
    addEventListener: function(eventName, callback) {
      this.canvas.getElement().addEventListener(eventName, callback);
    },
    dispatchEvent: function(event) {
      this.canvas.getElement().dispatchEvent(event);
    },

    // Initialisation.
    // It will replace the given image element by a canvas plus some wrapper
    // `div` blocks. A toolbar object is instanciated and the image is loaded
    // into the canvas element. Finally it calls each plugins initialisation
    // methods.
    init: function(element, options, plugins) {
      var _this = this;
      this.options = extend(options, this.defaults);

      if (typeof element === 'string')
        element = document.querySelector(element);
      if (null === element)
        return;

      var plugins = plugins || Darkroom.plugins;

      var image = new Image();

      image.onload = function() {
        _this
          .initDOM(element)
          .initImage(element)
          .initPlugins(plugins)
        ;

        // Execute a custom callback after initialization
        _this.options.init.bind(_this).call();
      }

      /*image.crossOrigin = 'anonymous';*/
      image.src = element.src;
    },

    initDOM: function(element) {
      // Create toolbar element
      var toolbar = document.createElement('div');
      toolbar.className = 'darkroom-toolbar';
      toolbar.innerHTML = '

';

      // Create canvas element
      var canvas = document.createElement('canvas');
      var canvasContainer = document.createElement('div');
      canvasContainer.className = 'darkroom-image-container';
      canvasContainer.appendChild(canvas);

      // Create container element
      this.container = document.createElement('div');
      this.container.className = 'darkroom-container';

      // Assemble elements
      this.container.appendChild(toolbar);
      this.container.appendChild(canvasContainer);

      // Replace image with new DOM
      element.parentNode.replaceChild(this.container, element);

      // Save elements
      this.toolbar = new Toolbar(toolbar);
      this.canvas = new Canvas(canvas, {
        selection: false,
        backgroundColor: '#ccc',
      });

      return this;
    },

    initImage: function(image) {
      var width = image.width;
      var height = image.height;
      var scale = 1;
      var scaleX = 1;
      var scaleY = 1;

      if (null !== this.options.maxWidth && this.options.maxWidth < width) {
        scaleX =  this.options.maxWidth / width;
      }
      if (null !== this.options.maxHeight && this.options.maxHeight < height) {
        scaleY =  this.options.maxHeight / height;
      }
      scale = Math.min(scaleX, scaleY);

      if (null !== this.options.minWidth && this.options.minWidth > width) {
        scaleX =  this.options.minWidth / width;
      }
      if (null !== this.options.minHeight && this.options.minHeight > height) {
        scaleY =  this.options.minHeight / height;
      }
      scale = Math.max(scaleX, scaleY);

      width *= scale;
      height *= scale;

      this.image = new fabric.Image(image, {
        // options to make the image static
        selectable: false,
        evented: false,
        lockMovementX: true,
        lockMovementY: true,
        lockRotation: true,
        lockScalingX: true,
        lockScalingY: true,
        lockUniScaling: true,
        hasControls: false,
        hasBorders: false
      });
      this.image.setScaleX(scale);
      this.image.setScaleY(scale);

      this.canvas.setWidth(width);
      this.canvas.setHeight(height);
      this.canvas.add(this.image);
      this.canvas.centerObject(this.image);
      this.image.setCoords();

      return this;
    },

    initPlugins: function(plugins) {
      this.plugins = {};

      for (var name in plugins) {
        var plugin = plugins[name];
        var options = this.options.plugins[name];

        // Setting false into the plugin options will disable the plugin
        if (options === false) {
          continue;
        }

        this.plugins[name] = new plugin(this, options);
      }
    },

    getPlugin: function(name) {
      return this.plugins[name];
    },

    selfDestroy: function() {
      var container = this.container;

      var image = new Image();
      image.onload = function() {
        container.parentNode.replaceChild(image, container);
      }

      image.src = this.snapshotImage();

      /* TODO
       - destroy plugins
       - delete canvas
      */
    },

    snapshotImage: function() {
      return this.image.toDataURL();
    }

  };

})(window, window.document, fabric);
<|endoftext|>


<commit_before>/*
==================================================================================================
  Core - JavaScript Foundation
  Copyright 2010-2012 Zynga Inc.
==================================================================================================
*/

(function(global)
{
	var merged = null;
	var root = null;
	var assets = {};

	/*
	// Jasy is replacing this call via the kernel permutation

	// Shorthands
	var assets = data.assets;
	var merged = data.merged;
	var root = data.root;
	*/

	/**
	 * {Array} Resolves the given @id {String} into the stored entry of the asset data base.
	 */
	var resolve = function(id)
	{
		if (id.constructor == Object) {
			return id;
		}

		if (core.Env.isSet("debug")) {
			core.Assert.isType(id, "String");
		}

		var splits = id.split("/");
		var current = assets;
		for (var i=0, l=splits.length; current&&i<l; i++) {
			current = current[splits[i]];
		}

		if (current == null) {
			console.warn("Could not resolve URI: " + id);
		}

		return current;
	};

	/**
	 * {Map} Collects asset with the given asset @prefix {String} from the given @section {Map}.
	 * Optionally works recursively by enabling @recursive {Boolean?false} or only
	 * returns the data by enabling @data {Boolean?false}. Last parameter @all {Map?}
	 * is used to fill an existing object instead of a new one.
	 */
	var collect = function(prefix, cut, section, recursive, data, all)
	{
		if (!all) {
			all = {};
		}

		if (section)
		{
			for (var filename in section)
			{
				var entry = section[filename];
				var id = prefix + "/" + filename;

				if (entry.constructor == Object)
				{
					if (recursive) {
						collect(id, cut, entry, recursive, data, all);
					}
				}
				else
				{
					var localId = !cut ? id : id.slice(cut);

					if (data) {
						all[localId] = entry;
					} else if (merged) {
						all[localId] = root + id;
					} else {
						all[localId] = root + entry[0];
					}
				}
			}
		}

		return all;
	};

	/**
	 * {String} Converts the given asset @id {String} to a full qualified URI.
	 * The method throws an error whenever an asset ID is unknown.
	 */
	var toUri = function(id)
	{
		if (core.Env.isSet("debug")) {
			core.Assert.isType(id, "String");
		}

		return root + (merged ? id : resolve(id)[0]);
	};

	/**
	 * Contains information about images (size, format, clipping, ...) and
	 * other assets like CSS files, local data, ...
	 *
	 * #require(ext.sugar.Array)
	 * #require(ext.sugar.Object)
	 * #require(ext.sugar.String)
	 */
	core.Module("core.io.Asset",
	{
		add : function(data)
		{
			console.debug("Adding asset data...", data);

			// Validate input data
			if (core.Env.isSet("debug"))
			{
				core.Assert.isType(data, "Map");
				core.Assert.isType(data.assets, "Map");
				core.Assert.isType(data.root, "String");
				core.Assert.isType(data.merged, "Boolean");
			}

			// Initial data
			if (root == null)
			{
				assets = data.assets;
				merged = data.merged;
				root = data.root;
			}

			// Inject data
			else
			{
				if (data.merged != merged) {
					throw new Error("Cannot handle merged and unmerged assets into one data set!");
				}

				if (data.root != root) {
					throw new Error("Cannot handle two different roots in on data set!");
				}

				// TODO: Merge assets

			}

		},

		toUri : toUri,

		/**
		 * {Boolean} Whether the registry has information about the given asset @id {String}.
		 */
		has : function(id)
		{
			if (core.Env.isSet("debug")) {
				core.Assert.isType(id, "String");
			}

			return !!resolve(id);
		},

		/**
		 * Loads the given @section {String}. Optionally @recursive {Boolean?false} it traverses
		 * the whole tree starting at @section. The optional @callback {Function?} is executed
		 * in the given @context {Object?} when all files are loaded. It is called with one
		 * parameter which contains are `Map` of all data (relative asset ID to loaded item).
		 * Optionally caching can be disabled by attaching a random `GET` parameter.
		 */
		loadSection: function(section, recursive, callback, context, nocache)
		{
			if (core.Env.isSet("debug"))
			{
				core.Assert.isType(section, "String");

				if (section == "") {
					throw new Error("Invalid section: " + section);
				}

				if (section.endsWith("/")) {
					throw new Error("Sections must not end with a slash!")
				}

				if (recursive != null) {
					core.Assert.isType(recursive, "Boolean");
				}

				if (callback != null) {
					core.Assert.isType(callback, "Function");
				}

				if (context != null) {
					core.Assert.isType(context, "Object");
				}

				if (nocache != null) {
					core.Assert.isType(nocache, "Boolean");
				}
			}

			// Collect assets
			var all = collect(section, section.length + 1, resolve(section), recursive);
			var uris = Object.values(all);

			// Build back tables to translate uris back to local IDs
			var urisToIds = uris.zip(Object.keys(all));

			var helper = callback ? function(data) {
				callback.call(context||global, Object.translate(data, urisToIds));
			} : callback;

			core.io.Queue.load(uris, helper, this, nocache);
		},

		/**
		 * Loads the given assets by their ID and executes @callback {Function?}
		 * in the given @context {Object?global}. Optionally caching can be disabled
		 * by attaching a random `GET` parameter.
		 */
		load: function(ids, callback, context, nocache)
		{
			if (core.Env.isSet("debug"))
			{
				core.Assert.isType(ids, "Array");

				if (callback != null) {
					core.Assert.isType(callback, "Function");
				}

				if (context != null) {
					core.Assert.isType(context, "Object");
				}

				if (nocache != null) {
					core.Assert.isType(nocache, "Boolean");
				}
			}

			var uris = ids.map(toUri);
			var urisToIds = uris.zip(ids);

			var helper = callback ? function(data) {
				callback.call(context||global, Object.translate(data, urisToIds));
			} : callback;

			core.io.Queue.load(uris, helper, this, nocache);
		},

		//
		// Data formats for image sprites / images frames:
		//
		// [width, height]
		// [400, 200]
		//
		// [width, height, cellNumber, rowNumber]
		// [400, 200, 20, 10]
		//
		// [width, height, cellNumber, rowNumber, frameNumber]
		// [400, 200, 20, 10, 183]
		//
		// [width, height, spriteId, left, top]
		// [24, 24, "icons.png", 48, 0]
		//
		// [width, height, spriteId, left, top, cellNumber, rowNumber]
		// [100, 100, "explode.png", 420, 245, 5, 5]
		// Image is part of sprite image explode.png with offsets 420x245. It contains 25 images with each being 20x20.
		//
		// [width, height, spriteId, left, top, cellNumber, rowNumber, frameNumber]
		// [100, 100, "explode.png", 420, 245, 5, 5, 23]
		// Image is part of sprite image explode.png with offsets 420x245. It contains 23 images with each being 20x20.
		//
		// [width, height, spriteId, left, top, [[left,top,width,height], ...]]
		// [60, 40, "explode.png", 420, 245, [[0,0,20,20],[20,0,40,40],[0,20,20,20]]]
		// Image is part of sprite image with offsets 420x245. It contains 3 manually positioned images.
		//

		/**
		 * {Array} Returns the dimensions of the given image @id {String} with as `width`, `height`.
		 */
		getImageSize : function(id)
		{
			var entry = resolve(id);
			var start = merged ? 0 : 1;

			return entry.slice(start, start+2);
		},

		getFrameNumber: function(id)
		{
			var entry = resolve(id);
			var number = 1;

			// Create duplicate with remove first item
			// Because in source (non merged) the first entry is the path
			if (!merged) {
				entry = entry.slice(1);
			}

			switch(entry.length)
			{
				case 4:
					// auto calculated frame size
					number = entry[2] * entry[3];
					break;

				case 5:
					// manually defined frame size
					number = entry[4];
					break;

				case 6:
					// manually defined frames
					number = entry[5].length;

				case 7:
					// auto calculated frame size (image sprite)
					number = entry[5] * entry[6];
					break;

				case 8:
					// manually defined frame size (image sprite)
					number = entry[7];
					break;
			}

			return number;
		},

		getImage : function(id)
		{
			var entry = resolve(id);

			// Is part of image sprite?
			if (typeof entry[2] == "string")
			{
				var spriteId = entry[2];

				// Local path (same folder as requested image)
				if (spriteId.indexOf("/") != -1)
				{
					var pos = spriteId.lastIndexOf("/");
					if (pos != -1) {
						src.slice(0, pos) + id;
					}
				}

				return {
					src : resolve(spriteId),
					left : entry[3],
					top : entry[4]
				};
			}
			else
			{
				// Return compatible data format in cases where no sprite sheet is used
				return {
					src : root + (merged ? id : entry[0]),
					left : 0,
					top: 0
				};
			}
		},

		getFrame : function(id, frame) {

		},

		getFrames : function(id) {

		}

	});

	core.io.Asset.add(core.Env.getValue("assets"));

})(this);

<commit_msg>Cleanup<commit_after>/*
==================================================================================================
  Core - JavaScript Foundation
  Copyright 2010-2012 Zynga Inc.
==================================================================================================
*/

(function(global)
{
	// Internal data stores
	var merged = null;
	var root = null;
	var assets = {};

	/**
	 * {Array} Resolves the given @id {String} into the stored entry of the asset data base.
	 */
	var resolve = function(id)
	{
		if (id.constructor == Object) {
			return id;
		}

		if (core.Env.isSet("debug")) {
			core.Assert.isType(id, "String");
		}

		var splits = id.split("/");
		var current = assets;
		for (var i=0, l=splits.length; current&&i<l; i++) {
			current = current[splits[i]];
		}

		if (current == null) {
			console.warn("Could not resolve URI: " + id);
		}

		return current;
	};

	/**
	 * {Map} Collects asset with the given asset @prefix {String} from the given @section {Map}.
	 * Optionally works recursively by enabling @recursive {Boolean?false} or only
	 * returns the data by enabling @data {Boolean?false}. Last parameter @all {Map?}
	 * is used to fill an existing object instead of a new one.
	 */
	var collect = function(prefix, cut, section, recursive, data, all)
	{
		if (!all) {
			all = {};
		}

		if (section)
		{
			for (var filename in section)
			{
				var entry = section[filename];
				var id = prefix + "/" + filename;

				if (entry.constructor == Object)
				{
					if (recursive) {
						collect(id, cut, entry, recursive, data, all);
					}
				}
				else
				{
					var localId = !cut ? id : id.slice(cut);

					if (data) {
						all[localId] = entry;
					} else if (merged) {
						all[localId] = root + id;
					} else {
						all[localId] = root + entry[0];
					}
				}
			}
		}

		return all;
	};

	/**
	 * {String} Converts the given asset @id {String} to a full qualified URI.
	 * The method throws an error whenever an asset ID is unknown.
	 */
	var toUri = function(id)
	{
		if (core.Env.isSet("debug")) {
			core.Assert.isType(id, "String");
		}

		return root + (merged ? id : resolve(id)[0]);
	};

	/**
	 * Contains information about images (size, format, clipping, ...) and
	 * other assets like CSS files, local data, ...
	 *
	 * #require(ext.sugar.Array)
	 * #require(ext.sugar.Object)
	 * #require(ext.sugar.String)
	 */
	core.Module("core.io.Asset",
	{
		add : function(data)
		{
			console.debug("Adding asset data...", data);

			// Validate input data
			if (core.Env.isSet("debug"))
			{
				core.Assert.isType(data, "Map");
				core.Assert.isType(data.assets, "Map");
				core.Assert.isType(data.root, "String");
				core.Assert.isType(data.merged, "Boolean");
			}

			// Initial data
			if (root == null)
			{
				assets = data.assets;
				merged = data.merged;
				root = data.root;
			}

			// Inject data
			else
			{
				if (data.merged != merged) {
					throw new Error("Cannot handle merged and unmerged assets into one data set!");
				}

				if (data.root != root) {
					throw new Error("Cannot handle two different roots in on data set!");
				}

				// TODO: Merge assets

			}

		},

		toUri : toUri,

		/**
		 * {Boolean} Whether the registry has information about the given asset @id {String}.
		 */
		has : function(id)
		{
			if (core.Env.isSet("debug")) {
				core.Assert.isType(id, "String");
			}

			return !!resolve(id);
		},

		/**
		 * Loads the given @section {String}. Optionally @recursive {Boolean?false} it traverses
		 * the whole tree starting at @section. The optional @callback {Function?} is executed
		 * in the given @context {Object?} when all files are loaded. It is called with one
		 * parameter which contains are `Map` of all data (relative asset ID to loaded item).
		 * Optionally caching can be disabled by attaching a random `GET` parameter.
		 */
		loadSection: function(section, recursive, callback, context, nocache)
		{
			if (core.Env.isSet("debug"))
			{
				core.Assert.isType(section, "String");

				if (section == "") {
					throw new Error("Invalid section: " + section);
				}

				if (section.endsWith("/")) {
					throw new Error("Sections must not end with a slash!")
				}

				if (recursive != null) {
					core.Assert.isType(recursive, "Boolean");
				}

				if (callback != null) {
					core.Assert.isType(callback, "Function");
				}

				if (context != null) {
					core.Assert.isType(context, "Object");
				}

				if (nocache != null) {
					core.Assert.isType(nocache, "Boolean");
				}
			}

			// Collect assets
			var all = collect(section, section.length + 1, resolve(section), recursive);
			var uris = Object.values(all);

			// Build back tables to translate uris back to local IDs
			var urisToIds = uris.zip(Object.keys(all));

			var helper = callback ? function(data) {
				callback.call(context||global, Object.translate(data, urisToIds));
			} : callback;

			core.io.Queue.load(uris, helper, this, nocache);
		},

		/**
		 * Loads the given assets by their ID and executes @callback {Function?}
		 * in the given @context {Object?global}. Optionally caching can be disabled
		 * by attaching a random `GET` parameter.
		 */
		load: function(ids, callback, context, nocache)
		{
			if (core.Env.isSet("debug"))
			{
				core.Assert.isType(ids, "Array");

				if (callback != null) {
					core.Assert.isType(callback, "Function");
				}

				if (context != null) {
					core.Assert.isType(context, "Object");
				}

				if (nocache != null) {
					core.Assert.isType(nocache, "Boolean");
				}
			}

			var uris = ids.map(toUri);
			var urisToIds = uris.zip(ids);

			var helper = callback ? function(data) {
				callback.call(context||global, Object.translate(data, urisToIds));
			} : callback;

			core.io.Queue.load(uris, helper, this, nocache);
		},

		//
		// Data formats for image sprites / images frames:
		//
		// [width, height]
		// [400, 200]
		//
		// [width, height, cellNumber, rowNumber]
		// [400, 200, 20, 10]
		//
		// [width, height, cellNumber, rowNumber, frameNumber]
		// [400, 200, 20, 10, 183]
		//
		// [width, height, spriteId, left, top]
		// [24, 24, "icons.png", 48, 0]
		//
		// [width, height, spriteId, left, top, cellNumber, rowNumber]
		// [100, 100, "explode.png", 420, 245, 5, 5]
		// Image is part of sprite image explode.png with offsets 420x245. It contains 25 images with each being 20x20.
		//
		// [width, height, spriteId, left, top, cellNumber, rowNumber, frameNumber]
		// [100, 100, "explode.png", 420, 245, 5, 5, 23]
		// Image is part of sprite image explode.png with offsets 420x245. It contains 23 images with each being 20x20.
		//
		// [width, height, spriteId, left, top, [[left,top,width,height], ...]]
		// [60, 40, "explode.png", 420, 245, [[0,0,20,20],[20,0,40,40],[0,20,20,20]]]
		// Image is part of sprite image with offsets 420x245. It contains 3 manually positioned images.
		//

		/**
		 * {Array} Returns the dimensions of the given image @id {String} with as `width`, `height`.
		 */
		getImageSize : function(id)
		{
			var entry = resolve(id);
			var start = merged ? 0 : 1;

			return entry.slice(start, start+2);
		},

		getFrameNumber: function(id)
		{
			var entry = resolve(id);
			var number = 1;

			// Create duplicate with remove first item
			// Because in source (non merged) the first entry is the path
			if (!merged) {
				entry = entry.slice(1);
			}

			switch(entry.length)
			{
				case 4:
					// auto calculated frame size
					number = entry[2] * entry[3];
					break;

				case 5:
					// manually defined frame size
					number = entry[4];
					break;

				case 6:
					// manually defined frames
					number = entry[5].length;

				case 7:
					// auto calculated frame size (image sprite)
					number = entry[5] * entry[6];
					break;

				case 8:
					// manually defined frame size (image sprite)
					number = entry[7];
					break;
			}

			return number;
		},

		getImage : function(id)
		{
			var entry = resolve(id);

			// Is part of image sprite?
			if (typeof entry[2] == "string")
			{
				var spriteId = entry[2];

				// Local path (same folder as requested image)
				if (spriteId.indexOf("/") != -1)
				{
					var pos = spriteId.lastIndexOf("/");
					if (pos != -1) {
						src.slice(0, pos) + id;
					}
				}

				return {
					src : resolve(spriteId),
					left : entry[3],
					top : entry[4]
				};
			}
			else
			{
				// Return compatible data format in cases where no sprite sheet is used
				return {
					src : root + (merged ? id : entry[0]),
					left : 0,
					top: 0
				};
			}
		},

		getFrame : function(id, frame) {

		},

		getFrames : function(id) {

		}

	});

	core.io.Asset.add(core.Env.getValue("assets"));

})(this);

<|endoftext|>