<commit_before>var lrSnippet = require('connect-livereload')();

var mountFolder = function (connect, dir) {
    return connect.static(require('path').resolve(dir));
};

module.exports = function (grunt) {
    // log task running time
    require('time-grunt')(grunt);

    // load all grunt tasks
    require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

    // configurable paths
    var pathConfig = {
        app: 'app',
        dist: 'dist',
        tmp: '.tmp',
        test: 'test'
    };

    grunt.initConfig({
        paths: pathConfig,
        watch: {
            compass: {
                files: ['<%= paths.app %>/compass/**/*'],
                tasks: ['compass:server']
            },
            test: {
                files: ['<%= paths.app %>/javascripts/**/*.js'],
                tasks: ['newer:jshint:test', 'karma:server:run'],
                options: {
                    spawn: false
                }
            },
            livereload: {
                files: [
                    '<%= paths.app %>/**/*.html',
                    '<%= paths.app %>/javascripts/**/*.js',
                    '<%= paths.app %>/images/**/*',
                    '<%= paths.tmp %>/stylesheets/**/*.css',
                    '<%= paths.tmp %>/images/**/*'
                ],
                options: {
                    livereload: true,
                    spawn: false
                }
            },
            configFiles: {
                files: ['Gruntfile.js'],
                options: {
                    reload: true
                }
            }
        },
        connect: {
            options: {
                port: 9999,
                hostname: '0.0.0.0'
            },
            server: {
                options: {
                    middleware: function (connect) {
                        return [
                            lrSnippet,
                            mountFolder(connect, pathConfig.tmp),
                            mountFolder(connect, pathConfig.app)
                        ];
                    }
                }
            }
        },
        open: {
            server: {
                path: 'http://127.0.0.1:<%= connect.options.port %>',
                app: 'Google Chrome Canary'
            }
        },
        clean: {
            dist: ['<%= paths.tmp %>', '<%= paths.dist %>'],
            server: '<%= paths.tmp %>'
        },
        useminPrepare: {
            html: ['<%= paths.app %>/**/*.html'],
            options: {
                dest: '<%= paths.dist %>'
            }
        },
        usemin: {
            html: ['<%= paths.dist %>/**/*.html'],
            css: ['<%= paths.dist %>/stylesheets/**/*.css'],
            options: {
                dirs: ['<%= paths.dist %>'],
                assetsDirs: ['<%= paths.dist %>']
            }
        },
        htmlmin: {
            options: {
                collapseWhitespace: true
            },
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%= paths.dist %>',
                    src: ['**/*.html'],
                    dest: '<%= paths.dist %>'
                }]
            }
        },
        copy: {
            dist: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%= paths.app %>',
                    dest: '<%= paths.dist %>',
                    src: [
                        '**/*.html',
                        '!components/**/*.html',
                        '!compass/**/*.html',
                        'images/**/*.{webp,gif,png,jpg,jpeg,ttf,otf,svg}'
                    ]
                }]
            },
            html: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%= paths.tmp %>',
                    dest: '<%= paths.dist %>',
                    src: [
                        '**/*.html'
                    ]
                }]
            },
            compass: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%= paths.tmp %>',
                    dest: '<%= paths.dist %>',
                    src: [
                        'images/**/*.{webp,gif,png,jpg,jpeg,ttf,otf,svg}'
                    ]
                }]
            }
        },
        compass: {
            options: {
                sassDir: '<%= paths.app %>/compass/sass',
                imagesDir: '<%= paths.app %>/compass/images',
                fontsDir: '<%= paths.app %>/images/fonts',
                relativeAssets: true
            },
            dist: {
                options: {
                    cssDir: '<%= paths.dist %>/stylesheets',
                    generatedImagesDir: '<%= paths.tmp %>/images',
                    httpGeneratedImagesPath: '/images/',
                    outputStyle: 'compressed',
                    environment: 'production',
                    relativeAssets: false
                }
            },
            server: {
                options: {
                    cssDir: '<%= paths.tmp %>/stylesheets',
                    generatedImagesDir: '<%= paths.tmp %>/images',
                    debugInfo: true,
                    environment: 'development'
                }
            }
        },
        rev: {
            dist: {
                files: {
                    src: [
                        '<%= paths.dist %>/javascripts/**/*.js',
                        '<%= paths.dist %>/stylesheets/**/*.css',
                        '<%= paths.dist %>/images/**/*.{webp,gif,png,jpg,jpeg,ttf,otf}'
                    ]
                }
            }
        },
        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%= paths.dist %>/images',
                    src: '**/*.{png,jpg,jpeg}',
                    dest: '<%= paths.dist %>/images'
                }]
            }
        },
        requirejs: {
            dist: {
                options: {
                    optimize: 'uglify',
                    uglify: {
                        toplevel: true,
                        ascii_only: false,
                        beautify: false
                    },
                    preserveLicenseComments: true,
                    useStrict: false,
                    wrap: true
                }
            }
        },
        concurrent: {
            server: {
                tasks: ['clean:server', 'compass:server'],
                options: {
                    logConcurrentOutput: true
                }
            },
            dist: {
                tasks: ['copy:dist', 'compass:dist'],
                options: {
                    logConcurrentOutput: true
                }
            }
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc'
            },
            test: ['<%= paths.app %>/javascripts/**/*.js']
        },
        karma: {
            options: {
                configFile: '<%= paths.test %>/karma.conf.js',
                browsers: ['Chrome_without_security']
            },
            server: {
                reporters: ['progress'],
                background: true
            },
            test: {
                reporters: ['progress', 'junit', 'coverage'],
                preprocessors: {
                    '<%= paths.app %>/javascripts/**/*.js' : 'coverage'
                },
                junitReporter: {
                    outputFile: '<%= paths.test %>/output/test-results.xml'
                },
                coverageReporter: {
                    type: 'html',
                    dir: '<%= paths.test %>/output/coverage/'
                },
                singleRun: true
            },
            travis: {
                browsers: ['PhantomJS'],
                reporters: ['progress'],
                singleRun: true
            }
        },
        bump: {
            options: {
                files: ['package.json', 'bower.json'],
                updateConfigs: [],
                commit: true,
                commitMessage: 'Release v%VERSION%',
                commitFiles: ['-a'],
                createTag: true,
                tagName: 'v%VERSION%',
                tagMessage: 'Version %VERSION%',
                push: false
            }
        },
        cdn: {
            options: {
                flatten: true
            },
            dist: {
                options: {
                    cdn: 'http://static.wdjimg.com/xxx',
                },
                src: ['<%= paths.dist %>/**/*.html', '<%= paths.dist %>/**/*.css']
            },
            staging: {
                options: {
                    cdn: 'https://s3.cn-north-1.amazonaws.com.cn/web-statics-staging/xxx',
                },
                src: ['<%= paths.dist %>/**/*.html', '<%= paths.dist %>/**/*.css']
            }
        },
        'aws_s3': {
            options: {
                accessKeyId: '',
                secretAccessKey: '',
                region: 'cn-north-1',
                uploadConcurrency: 5,
                signatureVersion: 'v4'
            },
            staging: {
                options: {
                    bucket: 'web-statics-staging',
                    differential: true,
                    params: {
                        CacheControl: '31536000'
                    }
                },
                files: [{
                    expand: true,
                    cwd: 'dist',
                    src: ['**', '!**/*.css', '!**/*.js'],
                    dest: 'xxx/'

                }, {
                    expand: true,
                    cwd: 'gzip',
                    src: ['**'],
                    dest: 'xxx/',
                    params: {
                        ContentEncoding: 'gzip'
                    }
                }]
            },
            production: {
                options: {
                    bucket: 'web-statics-production',
                    differential: true,
                    params: {
                        CacheControl: '31536000'
                    }
                },
                files: [{
                    expand: true,
                    cwd: 'dist',
                    src: ['**', '!**/*.css', '!**/*.js'],
                    dest: 'xxx/'
                }, {
                    expand: true,
                    cwd: 'gzip',
                    src: ['**'],
                    dest: 'xxx/',
                    params: {
                        ContentEncoding: 'gzip'
                    }
                }]
            }
        },
        compress: {
            js: {
                options: {
                    mode: 'gzip'
                },
                expand: true,
                cwd: 'dist/',
                src: ['**/*.js'],
                dest: 'gzip/',
                ext: '.js'
            },
            css: {
                options: {
                    mode: 'gzip'
                },
                expand: true,
                cwd: 'dist/',
                src: ['**/*.css'],
                dest: 'gzip/',
                ext: '.css'
            }
        }
    });

    grunt.registerTask('serve', [
        'concurrent:server',
        'connect:server',
        'karma:server',
        'open',
        'watch'
    ]);

    grunt.registerTask('test', [
        'jshint:test',
        'karma:test'
    ]);

    grunt.registerTask('test:travis', [
        'jshint:test',
        'karma:travis'
    ]);

    grunt.registerTask('build:staging', [
        'clean:dist',
        'concurrent:dist',
        'useminPrepare',
        'concat',
        'uglify',
        // 'cssmin', // Uncomment this line if using none-sass style
        // 'requirejs:dist', // Uncomment this line if using RequireJS in your project
        'rev',
        'copy:compass',
        'imagemin',
        'usemin',
        'htmlmin',
        'cdn:staging',
        'compress:js',
        'compress:css',
        'aws_s3:staging'
    ]);

    grunt.registerTask('build:production', [
        'clean:dist',
        'concurrent:dist',
        'useminPrepare',
        'concat',
        'uglify',
        // 'cssmin', // Uncomment this line if using none-sass style
        // 'requirejs:dist', // Uncomment this line if using RequireJS in your project
        'rev',
        'copy:compass',
        'imagemin',
        'usemin',
        'htmlmin',
        'cdn:dist',
        'compress:js',
        'compress:css',
        'aws_s3:production'
    ]);

    grunt.registerTask(['update'], [
        'bump-only:patch',
        'changelog',
        'bump-commit'
    ]);

    grunt.registerTask(['update:minor'], [
        'bump-only:minor',
        'changelog',
        'bump-commit'
    ]);

    grunt.registerTask(['update:major'], [
        'bump-only:major',
        'changelog',
        'bump-commit'
    ]);
};
<commit_msg>fix: Keep filename when compress resources.<commit_after>var lrSnippet = require('connect-livereload')();

var mountFolder = function (connect, dir) {
    return connect.static(require('path').resolve(dir));
};

module.exports = function (grunt) {
    // log task running time
    require('time-grunt')(grunt);

    // load all grunt tasks
    require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

    // configurable paths
    var pathConfig = {
        app: 'app',
        dist: 'dist',
        tmp: '.tmp',
        test: 'test'
    };

    grunt.initConfig({
        paths: pathConfig,
        watch: {
            compass: {
                files: ['<%= paths.app %>/compass/**/*'],
                tasks: ['compass:server']
            },
            test: {
                files: ['<%= paths.app %>/javascripts/**/*.js'],
                tasks: ['newer:jshint:test', 'karma:server:run'],
                options: {
                    spawn: false
                }
            },
            livereload: {
                files: [
                    '<%= paths.app %>/**/*.html',
                    '<%= paths.app %>/javascripts/**/*.js',
                    '<%= paths.app %>/images/**/*',
                    '<%= paths.tmp %>/stylesheets/**/*.css',
                    '<%= paths.tmp %>/images/**/*'
                ],
                options: {
                    livereload: true,
                    spawn: false
                }
            },
            configFiles: {
                files: ['Gruntfile.js'],
                options: {
                    reload: true
                }
            }
        },
        connect: {
            options: {
                port: 9999,
                hostname: '0.0.0.0'
            },
            server: {
                options: {
                    middleware: function (connect) {
                        return [
                            lrSnippet,
                            mountFolder(connect, pathConfig.tmp),
                            mountFolder(connect, pathConfig.app)
                        ];
                    }
                }
            }
        },
        open: {
            server: {
                path: 'http://127.0.0.1:<%= connect.options.port %>',
                app: 'Google Chrome Canary'
            }
        },
        clean: {
            dist: ['<%= paths.tmp %>', '<%= paths.dist %>'],
            server: '<%= paths.tmp %>'
        },
        useminPrepare: {
            html: ['<%= paths.app %>/**/*.html'],
            options: {
                dest: '<%= paths.dist %>'
            }
        },
        usemin: {
            html: ['<%= paths.dist %>/**/*.html'],
            css: ['<%= paths.dist %>/stylesheets/**/*.css'],
            options: {
                dirs: ['<%= paths.dist %>'],
                assetsDirs: ['<%= paths.dist %>']
            }
        },
        htmlmin: {
            options: {
                collapseWhitespace: true
            },
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%= paths.dist %>',
                    src: ['**/*.html'],
                    dest: '<%= paths.dist %>'
                }]
            }
        },
        copy: {
            dist: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%= paths.app %>',
                    dest: '<%= paths.dist %>',
                    src: [
                        '**/*.html',
                        '!components/**/*.html',
                        '!compass/**/*.html',
                        'images/**/*.{webp,gif,png,jpg,jpeg,ttf,otf,svg}'
                    ]
                }]
            },
            html: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%= paths.tmp %>',
                    dest: '<%= paths.dist %>',
                    src: [
                        '**/*.html'
                    ]
                }]
            },
            compass: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%= paths.tmp %>',
                    dest: '<%= paths.dist %>',
                    src: [
                        'images/**/*.{webp,gif,png,jpg,jpeg,ttf,otf,svg}'
                    ]
                }]
            }
        },
        compass: {
            options: {
                sassDir: '<%= paths.app %>/compass/sass',
                imagesDir: '<%= paths.app %>/compass/images',
                fontsDir: '<%= paths.app %>/images/fonts',
                relativeAssets: true
            },
            dist: {
                options: {
                    cssDir: '<%= paths.dist %>/stylesheets',
                    generatedImagesDir: '<%= paths.tmp %>/images',
                    httpGeneratedImagesPath: '/images/',
                    outputStyle: 'compressed',
                    environment: 'production',
                    relativeAssets: false
                }
            },
            server: {
                options: {
                    cssDir: '<%= paths.tmp %>/stylesheets',
                    generatedImagesDir: '<%= paths.tmp %>/images',
                    debugInfo: true,
                    environment: 'development'
                }
            }
        },
        rev: {
            dist: {
                files: {
                    src: [
                        '<%= paths.dist %>/javascripts/**/*.js',
                        '<%= paths.dist %>/stylesheets/**/*.css',
                        '<%= paths.dist %>/images/**/*.{webp,gif,png,jpg,jpeg,ttf,otf}'
                    ]
                }
            }
        },
        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%= paths.dist %>/images',
                    src: '**/*.{png,jpg,jpeg}',
                    dest: '<%= paths.dist %>/images'
                }]
            }
        },
        requirejs: {
            dist: {
                options: {
                    optimize: 'uglify',
                    uglify: {
                        toplevel: true,
                        ascii_only: false,
                        beautify: false
                    },
                    preserveLicenseComments: true,
                    useStrict: false,
                    wrap: true
                }
            }
        },
        concurrent: {
            server: {
                tasks: ['clean:server', 'compass:server'],
                options: {
                    logConcurrentOutput: true
                }
            },
            dist: {
                tasks: ['copy:dist', 'compass:dist'],
                options: {
                    logConcurrentOutput: true
                }
            }
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc'
            },
            test: ['<%= paths.app %>/javascripts/**/*.js']
        },
        karma: {
            options: {
                configFile: '<%= paths.test %>/karma.conf.js',
                browsers: ['Chrome_without_security']
            },
            server: {
                reporters: ['progress'],
                background: true
            },
            test: {
                reporters: ['progress', 'junit', 'coverage'],
                preprocessors: {
                    '<%= paths.app %>/javascripts/**/*.js' : 'coverage'
                },
                junitReporter: {
                    outputFile: '<%= paths.test %>/output/test-results.xml'
                },
                coverageReporter: {
                    type: 'html',
                    dir: '<%= paths.test %>/output/coverage/'
                },
                singleRun: true
            },
            travis: {
                browsers: ['PhantomJS'],
                reporters: ['progress'],
                singleRun: true
            }
        },
        bump: {
            options: {
                files: ['package.json', 'bower.json'],
                updateConfigs: [],
                commit: true,
                commitMessage: 'Release v%VERSION%',
                commitFiles: ['-a'],
                createTag: true,
                tagName: 'v%VERSION%',
                tagMessage: 'Version %VERSION%',
                push: false
            }
        },
        cdn: {
            options: {
                flatten: true
            },
            dist: {
                options: {
                    cdn: 'http://static.wdjimg.com/xxx',
                },
                src: ['<%= paths.dist %>/**/*.html', '<%= paths.dist %>/**/*.css']
            },
            staging: {
                options: {
                    cdn: 'https://s3.cn-north-1.amazonaws.com.cn/web-statics-staging/xxx',
                },
                src: ['<%= paths.dist %>/**/*.html', '<%= paths.dist %>/**/*.css']
            }
        },
        'aws_s3': {
            options: {
                accessKeyId: '',
                secretAccessKey: '',
                region: 'cn-north-1',
                uploadConcurrency: 5,
                signatureVersion: 'v4'
            },
            staging: {
                options: {
                    bucket: 'web-statics-staging',
                    differential: true,
                    params: {
                        CacheControl: '31536000'
                    }
                },
                files: [{
                    expand: true,
                    cwd: 'dist',
                    src: ['**', '!**/*.css', '!**/*.js'],
                    dest: 'xxx/'

                }, {
                    expand: true,
                    cwd: 'gzip',
                    src: ['**'],
                    dest: 'xxx/',
                    params: {
                        ContentEncoding: 'gzip'
                    }
                }]
            },
            production: {
                options: {
                    bucket: 'web-statics-production',
                    differential: true,
                    params: {
                        CacheControl: '31536000'
                    }
                },
                files: [{
                    expand: true,
                    cwd: 'dist',
                    src: ['**', '!**/*.css', '!**/*.js'],
                    dest: 'xxx/'
                }, {
                    expand: true,
                    cwd: 'gzip',
                    src: ['**'],
                    dest: 'xxx/',
                    params: {
                        ContentEncoding: 'gzip'
                    }
                }]
            }
        },
        compress: {
            gzip: {
                options: {
                    mode: 'gzip'
                },
                expand: true,
                cwd: 'dist/',
                src: ['**/*.js', '**/*.css'],
                dest: 'gzip/'

        }
    });

    grunt.registerTask('serve', [
        'concurrent:server',
        'connect:server',
        'karma:server',
        'open',
        'watch'
    ]);

    grunt.registerTask('test', [
        'jshint:test',
        'karma:test'
    ]);

    grunt.registerTask('test:travis', [
        'jshint:test',
        'karma:travis'
    ]);

    grunt.registerTask('build:staging', [
        'clean:dist',
        'concurrent:dist',
        'useminPrepare',
        'concat',
        'uglify',
        // 'cssmin', // Uncomment this line if using none-sass style
        // 'requirejs:dist', // Uncomment this line if using RequireJS in your project
        'rev',
        'copy:compass',
        'imagemin',
        'usemin',
        'htmlmin',
        'cdn:staging',
        'compress:gzip',
        'aws_s3:staging'
    ]);

    grunt.registerTask('build:production', [
        'clean:dist',
        'concurrent:dist',
        'useminPrepare',
        'concat',
        'uglify',
        // 'cssmin', // Uncomment this line if using none-sass style
        // 'requirejs:dist', // Uncomment this line if using RequireJS in your project
        'rev',
        'copy:compass',
        'imagemin',
        'usemin',
        'htmlmin',
        'cdn:dist',
        'compress:gzip',
        'aws_s3:production'
    ]);

    grunt.registerTask(['update'], [
        'bump-only:patch',
        'changelog',
        'bump-commit'
    ]);

    grunt.registerTask(['update:minor'], [
        'bump-only:minor',
        'changelog',
        'bump-commit'
    ]);

    grunt.registerTask(['update:major'], [
        'bump-only:major',
        'changelog',
        'bump-commit'
    ]);
};
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 Language Technology Group and Interactive Graphics Systems Group, Technische Universität Darmstadt, Germany
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

define([
    'angular',
    'ngSanitize',
    'ngMaterial'
], function (angular) {
    'use strict';

    angular.module('myApp.source', ['play.routing', 'ngSanitize', 'ngMaterial'])
        .config(['$uibTooltipProvider', function($uibTooltipProvider) {
            //$uibTooltipProvider.setTriggers({'mouseenter': 'mouseleave'});
            console.log("config");
        }])
        .controller('SourceController',
            [
                '$scope',
                '$http',
                '$timeout',
                '$mdToast',
                '$mdDialog',
                '$q',
                'playRoutes',
                '_',
                'sourceShareService',
                'highlightShareService',
                'uiShareService',
                'ObserverService',
                function ($scope,
                          $http,
                          $timeout,
                          $mdToast,
                          $mdDialog,
                          $q,
                          playRoutes,
                          _,
                          sourceShareService,
                          highlightShareService,
                          uiShareService,
                          ObserverService) {

                    $scope.allDocumentsLoadedMsg = 'All matching Documents loaded';
                    $scope.noDocumentsMsg = 'No document found for current applied filters.';

                    $scope.sourceShared = sourceShareService;
                    $scope.highlightShared = highlightShareService;
                    $scope.uiShareService = uiShareService;
                    $scope.docsLoading = false;
                    $scope.showLoading = false;
                    $scope.iteratorEmpty = false;

                    $scope.popover = {
                        template: 'doc_tooltip_tmpl',
                        placement: 'right',
                        trigger: 'None',
                        isOpen: [],
                        promises: []
                    };

                    $scope.labels = $scope.sourceShared.labels;

                    $scope.observer = ObserverService;

                    /**
                     * subscribe entity and metadata filters
                     */
                    $scope.observer_subscribe_entity = function (items) {
                        $scope.entityFilters = items
                    };
                    $scope.observer_subscribe_metadata = function (items) {
                        $scope.metadataFilters = items
                    };
                    $scope.observer_subscribe_fulltext = function (items) {
                        $scope.fulltextFilters = items
                    };
                    $scope.observer.subscribeItems($scope.observer_subscribe_entity, "entity");
                    $scope.observer.subscribeItems($scope.observer_subscribe_metadata, "metadata");
                    $scope.observer.subscribeItems($scope.observer_subscribe_fulltext, "fulltext");

                    /*

                     //TODO: examples of fetching documents with and without facet
                     playRoutes.controllers.DocumentController.getDocs('Clinton Snowden',[{'key':'Tags','data':['PTER','PREF']},{'key':'Classification','data':['CONFIDENTIAL']}]).get().then(function(x) {
                     //    console.log(x.data);
                     });
                     playRoutes.controllers.DocumentController.getDocs('',[{'key':'dummy','data': []}]).get().then(function(x) {
                     console.log(x.data);
                     });
                     */
                    /**
                     * load document list for current filtering
                     */
                    $scope.updateDocumentList = function () {
                        $scope.docsLoading = true;
                        $scope.showLoading = true;
                        console.log("reload doc list");
                        $scope.defered = $q.defer();
                        var entities = [];
                        angular.forEach($scope.entityFilters, function (item) {
                            entities.push(item.data.id);
                        });
                        var facets = $scope.observer.getFacets();
                        var fulltext = [];
                        angular.forEach($scope.fulltextFilters, function (item) {
                            fulltext.push(item.data.name);
                        });

                        playRoutes.controllers.DocumentController.getDocs(fulltext, facets, entities, $scope.observer.getTimeRange()).get().then(function (x) {
                            // console.log(x.data);
                            $scope.sourceShared.reset();
                            $scope.sourceShared.addDocs(x.data.docs);
                            $scope.hits = x.data.hits;
                            if ($scope.sourceShared.documentsInDB == -1){
                                $scope.sourceShared.documentsInDB = $scope.hits;
                            }
                            $(".docs-ul").scrollTop(0);
                            $scope.docsLoading = false;
                            $scope.showLoading = false;
                            $scope.defered.resolve("suc: docs");
                            $scope.iteratorEmpty = x.data.hits <= 50;
                            $("#vertical-container").css("height", $("#documents-view").height() - 110);

                        });
                        return $scope.defered.promise;
                    };

                    //initial document list load
                    $scope.updateDocumentList();

                    $scope.loadMore = function () {
                        console.log("reload doc list");
                        if (!$scope.iteratorEmpty) {
                            $scope.docsLoading = true;
                            var entities = [];
                            angular.forEach($scope.entityFilters, function (item) {
                                entities.push(item.data.id);
                            });
                            var facets = [];
                            if ($scope.metadataFilters.length > 0) {
                                angular.forEach($scope.metadataFilters, function (metaType) {
                                    if ($scope.metadataFilters[metaType].length > 0) {
                                        var keys = [];
                                        angular.forEach($scope.metadataFilters[metaType], function (x) {
                                            keys.push(x.data.name);
                                        });
                                        facets.push({key: metaType, data: keys});
                                    }
                                });
                                if (facets == 0) facets = [{'key': 'dummy', 'data': []}];

                            } else {
                                facets = [{'key': 'dummy', 'data': []}];
                            }
                            var fulltext = [];
                            angular.forEach($scope.fulltextFilters, function (item) {
                                fulltext.push(item.data.name);
                            });
                            playRoutes.controllers.DocumentController.getDocs(fulltext, facets, entities, $scope.observer.getTimeRange()).get().then(function (x) {
                                if (x.data.docs.length == 0 || x.data.docs.length <=50)
                                    $scope.iteratorEmpty = true;
                                else
                                    $scope.sourceShared.addDocs(x.data.docs);
                                $scope.docsLoading = false;

                            });
                        }
                    };

                    $scope.virtualScroll = {
                        getItemAtIndex: function(index) {
                            if (!$scope.docsLoading && !$scope.iteratorEmpty && $scope.sourceShared.documentList.length >= 50 && index >  $scope.sourceShared.documentList.length-3) {
                                $scope.loadMore();
                                return "Loading ...";
                            }
                            return  $scope.sourceShared.documentList[index];
                        },
                        getLength: function() {
                            return  $scope.sourceShared.documentList.length;
                        }
                    };

                    //subscribe to update document list on filter change
                    $scope.observer.registerObserverCallback({ priority: 2, callback: $scope.updateDocumentList });

                    $scope.observer.subscribeReset(function() {
                        return $scope.updateDocumentList();
                    });

                    $scope.loadFullDocument = function (doc) {
                        // Focus open tab if document is already opened
                        if($scope.isDocumentOpen(doc.id)) {
                            var index = _.findIndex($scope.sourceShared.tabs, function(t) { return t.id == doc.id; });
                            // Skip first network tab
                            $scope.selectedTab.index = index + 1;
                        } else {
                            var editItem = {
                                type: 'openDoc',
                                data: {
                                    id: doc.id,
                                    name: "#" + doc.id
                                }
                            };
                            $scope.observer.addItem(editItem);

                            playRoutes.controllers.DocumentController.getDocById(doc.id).get().then(function (response) {
                                var content = response.data[2];
                                playRoutes.controllers.EntityController.getEntitiesByDoc(doc.id).get().then(function (response) {
                                    // Provide document controller with document information
                                    $scope.sourceShared.tabs.push({
                                        id: doc.id,
                                        title: doc.id,
                                        content: content,
                                        meta: doc.metadata,
                                        entities: response.data
                                    });
                                });
                            });
                        }
                    };

                    $scope.isDocumentOpen = function (id) {
                        var index = _.findIndex($scope.sourceShared.tabs, function(t) { return t.id == id; });
                        return index != -1;
                    };

                    $scope.selectedTagChange = function(label) {
                        // Search tag was removed
                        if(_.isUndefined(label)) {
                            // Restore list to match filters again
                            $scope.updateDocumentList();
                        // Adjust list to match selected label
                        } else {
                            playRoutes.controllers.DocumentController.getDocsByLabel(label).get().then(function (response) {
                                $scope.sourceShared.reset();
                                $scope.sourceShared.addDocs(response.data.docs);
                                $scope.hits = response.data.hits;
                                $(".docs-ul").scrollTop(0);
                                $scope.iteratorEmpty = $scope.hits <= 50;
                            });
                        }
                    };

                    $scope.querySearch = function(query) {
                        var result = query ? $scope.labels.filter(createFilterFor(query)) : $scope.labels;
                        return result;
                    };

                    function createFilterFor(query) {
                        var lowercaseQuery = angular.lowercase(query);
                        return function filterFn(label) {
                            return (label.toLowerCase().indexOf(lowercaseQuery) === 0);
                        };
                    }

                    $(".docs-ul").on('scroll', function () {
                        if (!$scope.docsLoading) {
                            if (($(this).find("ul").height() - $(this).scrollTop()) < 1000)
                                $scope.loadMore();
                        }
                    });

                    $scope.showDocumentToast = function(message) {
                        $mdToast.show(
                            $mdToast.simple()
                                .textContent(message)
                                .position('bottom left')
                                .parent(angular.element('#document'))
                                .hideDelay(3000)
                        );
                    };

                    $scope.showMetaDialog = function($event, metadata) {
                        var parentEl = angular.element(document.body);
                        $mdDialog.show({
                            parent: parentEl,
                            targetEvent: $event,
                            template:
                            '<md-dialog aria-label="Metadata">' +
                            '  <md-dialog-content>'+
                                '<md-subheader class="md-no-sticky">Metadata</md-subheader>'+
                            '    <md-list class="md-dense">'+
                            '      <md-list-item ng-repeat="(key, value) in items">'+
                            '
{{key}}: {{value}}
' +
                            '      '+
                            '    </md-list-item></md-list>'+
                            '  </md-dialog-content>' +
                            '  <md-dialog-actions>' +
                            '    <md-button ng-click="closeDialog()" class="md-primary">' +
                            '      Close' +
                            '    </md-button>' +
                            '  </md-dialog-actions>' +
                            '</md-dialog>',
                            locals: {
                                items: metadata
                            },
                            controller: DialogController
                        });
                        function DialogController($scope, $mdDialog, items) {
                            $scope.items = items;
                            $scope.closeDialog = function() {
                                $mdDialog.hide();
                            }
                        }
                    };

                    /*$scope.hidePopover = function (id) {
                        $scope.popover.promises[id] = $timeout(function () {
                            $scope.hideFunction(id)
                        }, 10);
                    };

                    $scope.showPopover = function (id) {
                        if ($scope.popover.promises[id] != undefined) $timeout.cancel($scope.popover.promises[id]);
                        $scope.popover.isOpen[id] = true;
                    };

                    $scope.hideFunction = function (x) {
                        $scope.popover.isOpen[x] = false;
                    };*/
                }
            ]);
});
<commit_msg>facet bug for documents<commit_after>/*
 * Copyright (C) 2016 Language Technology Group and Interactive Graphics Systems Group, Technische Universität Darmstadt, Germany
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

define([
    'angular',
    'ngSanitize',
    'ngMaterial'
], function (angular) {
    'use strict';

    angular.module('myApp.source', ['play.routing', 'ngSanitize', 'ngMaterial'])
        .config(['$uibTooltipProvider', function($uibTooltipProvider) {
            //$uibTooltipProvider.setTriggers({'mouseenter': 'mouseleave'});
            console.log("config");
        }])
        .controller('SourceController',
            [
                '$scope',
                '$http',
                '$timeout',
                '$mdToast',
                '$mdDialog',
                '$q',
                'playRoutes',
                '_',
                'sourceShareService',
                'highlightShareService',
                'uiShareService',
                'ObserverService',
                function ($scope,
                          $http,
                          $timeout,
                          $mdToast,
                          $mdDialog,
                          $q,
                          playRoutes,
                          _,
                          sourceShareService,
                          highlightShareService,
                          uiShareService,
                          ObserverService) {

                    $scope.allDocumentsLoadedMsg = 'All matching Documents loaded';
                    $scope.noDocumentsMsg = 'No document found for current applied filters.';

                    $scope.sourceShared = sourceShareService;
                    $scope.highlightShared = highlightShareService;
                    $scope.uiShareService = uiShareService;
                    $scope.docsLoading = false;
                    $scope.showLoading = false;
                    $scope.iteratorEmpty = false;

                    $scope.popover = {
                        template: 'doc_tooltip_tmpl',
                        placement: 'right',
                        trigger: 'None',
                        isOpen: [],
                        promises: []
                    };

                    $scope.labels = $scope.sourceShared.labels;

                    $scope.observer = ObserverService;

                    /**
                     * subscribe entity and metadata filters
                     */
                    $scope.observer_subscribe_entity = function (items) {
                        $scope.entityFilters = items
                    };
                    $scope.observer_subscribe_metadata = function (items) {
                        $scope.metadataFilters = items
                    };
                    $scope.observer_subscribe_fulltext = function (items) {
                        $scope.fulltextFilters = items
                    };
                    $scope.observer.subscribeItems($scope.observer_subscribe_entity, "entity");
                    $scope.observer.subscribeItems($scope.observer_subscribe_metadata, "metadata");
                    $scope.observer.subscribeItems($scope.observer_subscribe_fulltext, "fulltext");

                    /*

                     //TODO: examples of fetching documents with and without facet
                     playRoutes.controllers.DocumentController.getDocs('Clinton Snowden',[{'key':'Tags','data':['PTER','PREF']},{'key':'Classification','data':['CONFIDENTIAL']}]).get().then(function(x) {
                     //    console.log(x.data);
                     });
                     playRoutes.controllers.DocumentController.getDocs('',[{'key':'dummy','data': []}]).get().then(function(x) {
                     console.log(x.data);
                     });
                     */
                    /**
                     * load document list for current filtering
                     */
                    $scope.updateDocumentList = function () {
                        $scope.docsLoading = true;
                        $scope.showLoading = true;
                        console.log("reload doc list");
                        $scope.defered = $q.defer();
                        var entities = [];
                        angular.forEach($scope.entityFilters, function (item) {
                            entities.push(item.data.id);
                        });
                        var facets = $scope.observer.getFacets();
                        var fulltext = [];
                        angular.forEach($scope.fulltextFilters, function (item) {
                            fulltext.push(item.data.name);
                        });

                        playRoutes.controllers.DocumentController.getDocs(fulltext, facets, entities, $scope.observer.getTimeRange()).get().then(function (x) {
                            // console.log(x.data);
                            $scope.sourceShared.reset();
                            $scope.sourceShared.addDocs(x.data.docs);
                            $scope.hits = x.data.hits;
                            if ($scope.sourceShared.documentsInDB == -1){
                                $scope.sourceShared.documentsInDB = $scope.hits;
                            }
                            $(".docs-ul").scrollTop(0);
                            $scope.docsLoading = false;
                            $scope.showLoading = false;
                            $scope.defered.resolve("suc: docs");
                            $scope.iteratorEmpty = x.data.hits <= 50;
                            $("#vertical-container").css("height", $("#documents-view").height() - 110);

                        });
                        return $scope.defered.promise;
                    };

                    //initial document list load
                    $scope.updateDocumentList();

                    $scope.loadMore = function () {
                        console.log("reload doc list");
                        if (!$scope.iteratorEmpty) {
                            $scope.docsLoading = true;
                            var entities = [];
                            angular.forEach($scope.entityFilters, function (item) {
                                entities.push(item.data.id);
                            });
                            var facets = $scope.observer.getFacets();
                            var fulltext = [];
                            angular.forEach($scope.fulltextFilters, function (item) {
                                fulltext.push(item.data.name);
                            });
                            playRoutes.controllers.DocumentController.getDocs(fulltext, facets, entities, $scope.observer.getTimeRange()).get().then(function (x) {
                                if (x.data.docs.length == 0 || x.data.docs.length <=50)
                                    $scope.iteratorEmpty = true;
                                else
                                    $scope.sourceShared.addDocs(x.data.docs);
                                $scope.docsLoading = false;

                            });
                        }
                    };

                    $scope.virtualScroll = {
                        getItemAtIndex: function(index) {
                            if (!$scope.docsLoading && !$scope.iteratorEmpty && $scope.sourceShared.documentList.length >= 50 && index >  $scope.sourceShared.documentList.length-3) {
                                $scope.loadMore();
                                return "Loading ...";
                            }
                            return  $scope.sourceShared.documentList[index];
                        },
                        getLength: function() {
                            return  $scope.sourceShared.documentList.length;
                        }
                    };

                    //subscribe to update document list on filter change
                    $scope.observer.registerObserverCallback({ priority: 2, callback: $scope.updateDocumentList });

                    $scope.observer.subscribeReset(function() {
                        return $scope.updateDocumentList();
                    });

                    $scope.loadFullDocument = function (doc) {
                        // Focus open tab if document is already opened
                        if($scope.isDocumentOpen(doc.id)) {
                            var index = _.findIndex($scope.sourceShared.tabs, function(t) { return t.id == doc.id; });
                            // Skip first network tab
                            $scope.selectedTab.index = index + 1;
                        } else {
                            var editItem = {
                                type: 'openDoc',
                                data: {
                                    id: doc.id,
                                    name: "#" + doc.id
                                }
                            };
                            $scope.observer.addItem(editItem);

                            playRoutes.controllers.DocumentController.getDocById(doc.id).get().then(function (response) {
                                var content = response.data[2];
                                playRoutes.controllers.EntityController.getEntitiesByDoc(doc.id).get().then(function (response) {
                                    // Provide document controller with document information
                                    $scope.sourceShared.tabs.push({
                                        id: doc.id,
                                        title: doc.id,
                                        content: content,
                                        meta: doc.metadata,
                                        entities: response.data
                                    });
                                });
                            });
                        }
                    };

                    $scope.isDocumentOpen = function (id) {
                        var index = _.findIndex($scope.sourceShared.tabs, function(t) { return t.id == id; });
                        return index != -1;
                    };

                    $scope.selectedTagChange = function(label) {
                        // Search tag was removed
                        if(_.isUndefined(label)) {
                            // Restore list to match filters again
                            $scope.updateDocumentList();
                        // Adjust list to match selected label
                        } else {
                            playRoutes.controllers.DocumentController.getDocsByLabel(label).get().then(function (response) {
                                $scope.sourceShared.reset();
                                $scope.sourceShared.addDocs(response.data.docs);
                                $scope.hits = response.data.hits;
                                $(".docs-ul").scrollTop(0);
                                $scope.iteratorEmpty = $scope.hits <= 50;
                            });
                        }
                    };

                    $scope.querySearch = function(query) {
                        var result = query ? $scope.labels.filter(createFilterFor(query)) : $scope.labels;
                        return result;
                    };

                    function createFilterFor(query) {
                        var lowercaseQuery = angular.lowercase(query);
                        return function filterFn(label) {
                            return (label.toLowerCase().indexOf(lowercaseQuery) === 0);
                        };
                    }

                    $(".docs-ul").on('scroll', function () {
                        if (!$scope.docsLoading) {
                            if (($(this).find("ul").height() - $(this).scrollTop()) < 1000)
                                $scope.loadMore();
                        }
                    });

                    $scope.showDocumentToast = function(message) {
                        $mdToast.show(
                            $mdToast.simple()
                                .textContent(message)
                                .position('bottom left')
                                .parent(angular.element('#document'))
                                .hideDelay(3000)
                        );
                    };

                    $scope.showMetaDialog = function($event, metadata) {
                        var parentEl = angular.element(document.body);
                        $mdDialog.show({
                            parent: parentEl,
                            targetEvent: $event,
                            template:
                            '<md-dialog aria-label="Metadata">' +
                            '  <md-dialog-content>'+
                                '<md-subheader class="md-no-sticky">Metadata</md-subheader>'+
                            '    <md-list class="md-dense">'+
                            '      <md-list-item ng-repeat="(key, value) in items">'+
                            '
{{key}}: {{value}}
' +
                            '      '+
                            '    </md-list-item></md-list>'+
                            '  </md-dialog-content>' +
                            '  <md-dialog-actions>' +
                            '    <md-button ng-click="closeDialog()" class="md-primary">' +
                            '      Close' +
                            '    </md-button>' +
                            '  </md-dialog-actions>' +
                            '</md-dialog>',
                            locals: {
                                items: metadata
                            },
                            controller: DialogController
                        });
                        function DialogController($scope, $mdDialog, items) {
                            $scope.items = items;
                            $scope.closeDialog = function() {
                                $mdDialog.hide();
                            }
                        }
                    };

                    /*$scope.hidePopover = function (id) {
                        $scope.popover.promises[id] = $timeout(function () {
                            $scope.hideFunction(id)
                        }, 10);
                    };

                    $scope.showPopover = function (id) {
                        if ($scope.popover.promises[id] != undefined) $timeout.cancel($scope.popover.promises[id]);
                        $scope.popover.isOpen[id] = true;
                    };

                    $scope.hideFunction = function (x) {
                        $scope.popover.isOpen[x] = false;
                    };*/
                }
            ]);
});
<|endoftext|>


<commit_before>(function() {

  // While most of the IDB behaviors match between implementations a
  // lot of the names still differ. This section tries to normalize the
  // different objects & methods.
  window.indexedDB = window.indexedDB ||
    window.mozIndexedDB ||
    window.webkitIndexedDB;

  window.IDBCursor = window.IDBCursor ||
    window.webkitIDBCursor;

  window.IDBKeyRange = window.IDBKeyRange ||
    window.webkitIDBKeyRange;

  window.IDBTransaction = window.IDBTransaction ||
    window.webkitIDBTransaction;

  window.IDBDatabaseException = window.IDBDatabaseException ||
    window.webkitIDBDatabaseException;

  var root = this;
  var pouch = {};

  if (typeof exports !== 'undefined') {
    exports.pouch = pouch;
  } else {
    root.pouch = pouch;
  }

  // IndexedDB requires a versioned database structure, this is going to make
  // it hard to dynamically create object stores if we needed to for things
  // like views
  var POUCH_VERSION = 1;

  // Cache for open databases
  var pouchCache = {};

  // The object stores created for each database
  // DOC_STORE stores the document meta data, its revision history and state
  var DOC_STORE = 'document-store';
  // BY_SEQ_STORE stores a particular version of a document, keyed by its
  // sequence id
  var BY_SEQ_STORE = 'by-sequence';

  // Enumerate errors, add the status code so we can reflect the HTTP api
  // in future
  var Errors = {
    MISSING_DOC: {
      status: 404,
      error: 'not_found',
      reason: 'missing'
    },
    REV_CONFLICT: {
      status: 409,
      error: 'conflict',
      reason: 'Document update conflict'
    }
  };

  // Pretty dumb name for a function, just wraps callback calls so we dont
  // to if (callback) callback() everywhere
  var call = function() {
    var fun = arguments[0];
    var args = Array.prototype.slice.call(arguments);
    args.shift();
    if (typeof fun === typeof Function) {
      fun.apply(this, args);
    }
  };

  // Preprocess documents, parse their revisions, assign an id and a
  // revision for new writes that are missing them, etc
  // I am fairly certain we shouldnt be throwing errors here
  var parseDoc = function(doc, newEdits) {
    if (newEdits) {
      if (!doc._id) {
        doc._id = Math.uuid();
      }
      var newRevId = Math.uuid(32, 16);
      if (doc._rev) {
        var revInfo = /^(\d+)-(.+)$/.exec(doc._rev);
        if (!revInfo) {
          throw "invalid value for property '_rev'";
        }
        doc._revisions = {
          start: parseInt(revInfo[1], 10) + 1,
          ids: [newRevId, revInfo[2]]
        };
      } else {
        doc._revisions = {
          start : 1,
          ids : [newRevId]
      };
      }
    } else {
      if (!doc._revisions) {
        throw "missing property '_revisions'";
      }
      if (!isFinite(doc._revisions.start)) {
        throw "property '_revisions.start' must be a number";
      }
      if (Array.isArray(doc._revisions) && doc._revisions.length > 0) {
        throw "property '_revisions.id' must be a non-empty array";
      }
    }
    doc._id = decodeURIComponent(doc._id);
    doc._rev = [doc._revisions.start, doc._revisions.ids[0]].join('-');
    return Object.keys(doc).reduce(function(acc, key) {
      if (/^_/.test(key))
        acc.metadata[key.slice(1)] = doc[key];
      else
        acc.data[key] = doc[key];
      return acc;
    }, {metadata : {}, data : {}});
  };

  var compareRevs = function(a, b) {
    // Sort by id
    if (a.id !== b.id) {
      return (a.id < b.id ? -1 : 1);
    }
    // Then by deleted
    if (a.deleted ^ b.deleted) {
      return (a.deleted ? -1 : 1);
    }
    // Then by rev id
    if (a.revisions.start === b.revisions.start) {
      return (a.revisions.ids < b.revisions.ids ? -1 : 1);
    }
    // Then by depth of edits
    return (a.revisions.start < b.revisions.start ? -1 : 1);
  };

  // This opens a database, creating it if needed and returns the api
  // used to access the database
  var makePouch = function(db) {

    // Wrapper for functions that call the bulkdocs api with a single doc,
    // if the first result is an error, return an error
    var singularErr = function(callback) {
      return function(err, results) {
        if (err || results[0].error) {
          call(callback, err || results[0]);
        } else {
          call(callback, null, results[0]);
        }
      };
    };

    // Now we create the PouchDB interface
    var pouch = {update_seq: 0};

    // First we look up the metadata in the ids database, then we fetch the
    // current revision(s) from the by sequence store
    pouch.get = function(id, opts, callback) {
      if (opts instanceof Function) {
        callback = opts;
        opts = {};
      }

      var req = db.transaction([DOC_STORE], IDBTransaction.READ)
        .objectStore(DOC_STORE).get(id);

      req.onsuccess = function(e) {
        var metadata = e.target.result;
        if (!e.target.result || metadata.deleted) {
          return call(callback, Errors.MISSING_DOC);
        }

        var nreq = db.transaction([BY_SEQ_STORE], IDBTransaction.READ)
          .objectStore(BY_SEQ_STORE).get(metadata.seq);
        nreq.onsuccess = function(e) {
          var doc = e.target.result;
          doc._id = metadata.id;
          doc._rev = metadata.rev;
          if (opts.revs_info) {
            doc._revs_info = metadata.revisions.ids.map(function(rev, i) {
              // we dont compact, so it kinda has to be, but need to properly
              // check in future
              return {rev: (i + 1) + '-' + rev, status: 'available'};
            });
          }
          callback(null, doc);
        };
      };
    };

    pouch.remove = function(doc, opts, callback) {
      if (opts instanceof Function) {
        callback = opts;
        opts = {};
      }
      doc._deleted = true;
      return pouch.bulkDocs({docs: [doc]}, opts, singularErr(callback));
    };

    pouch.put = pouch.post = function(doc, opts, callback) {
      if (opts instanceof Function) {
        callback = opts;
        opts = {};
      }
      pouch.bulkDocs({docs: [doc]}, opts, singularErr(callback));
    };

    pouch.bulkDocs = function(req, opts, callback) {
      if (opts instanceof Function) {
        callback = opts;
        opts = {};
      }

      var newEdits = 'new_edits' in opts ? opts._new_edits : true;

      // Parse and sort the docs
      var docInfos = req.docs.map(function(doc) {
        return parseDoc(doc, newEdits);
      });

      docInfos.sort(function(a, b) {
        return compareRevs(a.metadata, b.metadata);
      });

      var keyRange = IDBKeyRange.bound(
        docInfos[0].metadata.id, docInfos[docInfos.length-1].metadata.id,
        false, false);

      // This groups edits to the same document together
      var buckets = docInfos.reduce(function(acc, docInfo) {
        if (docInfo.metadata.id === acc[0][0].metadata.id) {
          acc[0].push(docInfo);
        } else {
          acc.unshift([docInfo]);
        }
        return acc;
      }, [[docInfos.shift()]]);

      var txn = db.transaction([DOC_STORE, BY_SEQ_STORE],
                               IDBTransaction.READ_WRITE);
      var results = [];

      txn.oncomplete = function(event) {
        results.forEach(function(result) {
          pouch.changes.emit(result);
        });
        call(callback, null, results);
      };

      txn.onerror = function(event) {
        if (callback) {
          var code = event.target.errorCode;
          var message = Object.keys(IDBDatabaseException)[code].toLowerCase();
          callback({
            error : event.type,
            reason : message
          });
        }
      };

      txn.ontimeout = function(event) {
        if (callback) {
          var code = event.target.errorCode;
          var message = Object.keys(IDBDatabaseException)[code].toLowerCase();
          callback({
            error : event.type,
            reason : message
          });
        }
      };

      var cursReq = txn.objectStore(DOC_STORE)
        .openCursor(keyRange, IDBCursor.NEXT);

      cursReq.onsuccess = function(event) {
        var cursor = event.target.result;
        if (cursor) {
          // I am guessing keyRange should be sorted in the same way buckets
          // are, so we can just take the first from buckets
          var doc = buckets.shift();
          // Documents are grouped by id in buckets, which means each document
          // has an array of edits, this currently only works for single edits
          // they should probably be getting merged
          var docInfo = doc[0];
          var revs = cursor.value.revisions.ids;
          // Currently ignoring the revision sequence number, we shouldnt do that
          if (revs[0] !== docInfo.metadata.revisions.ids[1]) {
            results.push(Errors.REV_CONFLICT);
            return cursor['continue']();
          }
          // Start of rev merging, for now we just keep a linear history
          // of revisions
          revs.shift();
          revs.forEach(function(rev) {
            docInfo.metadata.revisions.ids.push(rev);
          });

          var dataReq = txn.objectStore(BY_SEQ_STORE).put(docInfo.data);
          dataReq.onsuccess = function(e) {
            docInfo.metadata.seq = e.target.result;
            var metaDataReq = txn.objectStore(DOC_STORE).put(docInfo.metadata);
            metaDataReq.onsuccess = function() {
              results.push({
                id : docInfo.metadata.id,
                rev : docInfo.metadata.rev
              });
              return cursor['continue']();
            };
          };
        } else {
          // Cursor has exceeded the key range so the rest are inserts
          buckets.forEach(function(bucket) {
            // TODO: merge the bucket revs into a rev tree
            var docInfo = bucket[0];
            if (docInfo.metadata.deleted) {
              results.push(Errors.MISSING_DOC);
              return;
            }
            var dataReq = txn.objectStore(BY_SEQ_STORE).add(docInfo.data);
            dataReq.onsuccess = function(e) {
              docInfo.metadata.seq = e.target.result;
              var metaDataReq = txn.objectStore(DOC_STORE).add(docInfo.metadata);
              metaDataReq.onsuccess = function() {
                results.push({
                  id : docInfo.metadata.id,
                  rev : docInfo.metadata.rev
                });
              };
            };
          });
        }
      };
    };

    pouch.changes = function(opts) {
      if (!opts.seq) {
        opts.seq = 0;
      }
      var transaction = db.transaction([DOC_STORE, BY_SEQ_STORE]);
      var request = transaction.objectStore(BY_SEQ_STORE)
        .openCursor(IDBKeyRange.lowerBound(opts.seq));
      request.onsuccess = function(event) {
        var cursor = event.target.result;
        if (!cursor) {
          if (opts.continuous) {
            pouch.changes.addListener(opts.onChange);
          }
          if (opts.complete) {
            opts.complete();
          }
        } else {
          var index = transaction.objectStore(DOC_STORE).index('seq');
          index.get(cursor.key).onsuccess = function(event) {
            var doc = event.target.result;
            var c = {
              id: doc.id,
              seq: cursor.key,
              changes: doc.revisions.ids
            };
            if (opts.include_doc) {
              c.doc = cursor.value;
            }
            opts.onChange(c);
            cursor['continue']();
          };
        }
      };
      request.onerror = function(error) {
        // Cursor is out of range
        // NOTE: What should we do with a sequence that is too high?
        if (opts.continuous) {
          pouch.changes.addListener(opts.onChange);
        }
        call(opts.complete);
      };
    };

    pouch.changes.listeners = [];
    pouch.changes.emit = function() {
      var a = arguments;
      pouch.changes.listeners.forEach(function(l) {
        l.apply(l, a);
      });
    };
    pouch.changes.addListener = function(l) {
      pouch.changes.listeners.push(l);
    };

    return pouch;
  };

  pouch.open = function(name, opts, callback) {
    if (opts instanceof Function) {
      callback = opts;
      opts = {};
    }
    name = 'pouch:' + name;

    if (name in pouchCache) {
      return call(callback, null, pouchCache[name]);
    }

    var req = indexedDB.open(name);

    req.onupgradeneeded = function(e) {
      var db = e.target.result;
      db.createObjectStore(DOC_STORE, {keyPath : 'id'})
        .createIndex('seq', 'seq', {unique : true});
      db.createObjectStore(BY_SEQ_STORE, {autoIncrement : true});
    };

    req.onsuccess = function(e) {

      var db = e.target.result;

      db.onversionchange = function() {
        db.close();
        delete pouchCache[name];
      };

      // polyfill the new onupgradeneeded api for chrome
      if (db.setVersion && Number(db.version) !== POUCH_VERSION) {
        var versionReq = db.setVersion(POUCH_VERSION);
        versionReq.onsuccess = function() {
          req.onupgradeneeded(e);
          req.onsuccess(e);
        };
        return;
      }

      pouchCache[name] = makePouch(db);
      call(callback, null, pouchCache[name]);
    };

    req.onerror = function(e) {
      call(callback, {error: 'open', reason: e.toString()});
    };
  };

  pouch.deleteDatabase = function(name, callback) {

    var req = indexedDB.deleteDatabase('pouch:' + name);

    req.onsuccess = function() {
      call(callback, null);
    };

    req.onerror = function(e) {
      call(callback, {error: 'delete', reason: e.toString()});
    };
  };

}).call(this);<commit_msg>extract the writedoc function<commit_after>(function() {

  // While most of the IDB behaviors match between implementations a
  // lot of the names still differ. This section tries to normalize the
  // different objects & methods.
  window.indexedDB = window.indexedDB ||
    window.mozIndexedDB ||
    window.webkitIndexedDB;

  window.IDBCursor = window.IDBCursor ||
    window.webkitIDBCursor;

  window.IDBKeyRange = window.IDBKeyRange ||
    window.webkitIDBKeyRange;

  window.IDBTransaction = window.IDBTransaction ||
    window.webkitIDBTransaction;

  window.IDBDatabaseException = window.IDBDatabaseException ||
    window.webkitIDBDatabaseException;

  var root = this;
  var pouch = {};

  if (typeof exports !== 'undefined') {
    exports.pouch = pouch;
  } else {
    root.pouch = pouch;
  }

  // IndexedDB requires a versioned database structure, this is going to make
  // it hard to dynamically create object stores if we needed to for things
  // like views
  var POUCH_VERSION = 1;

  // Cache for open databases
  var pouchCache = {};

  // The object stores created for each database
  // DOC_STORE stores the document meta data, its revision history and state
  var DOC_STORE = 'document-store';
  // BY_SEQ_STORE stores a particular version of a document, keyed by its
  // sequence id
  var BY_SEQ_STORE = 'by-sequence';

  // Enumerate errors, add the status code so we can reflect the HTTP api
  // in future
  var Errors = {
    MISSING_DOC: {
      status: 404,
      error: 'not_found',
      reason: 'missing'
    },
    REV_CONFLICT: {
      status: 409,
      error: 'conflict',
      reason: 'Document update conflict'
    }
  };

  // Pretty dumb name for a function, just wraps callback calls so we dont
  // to if (callback) callback() everywhere
  var call = function() {
    var fun = arguments[0];
    var args = Array.prototype.slice.call(arguments);
    args.shift();
    if (typeof fun === typeof Function) {
      fun.apply(this, args);
    }
  };

  // Preprocess documents, parse their revisions, assign an id and a
  // revision for new writes that are missing them, etc
  // I am fairly certain we shouldnt be throwing errors here
  var parseDoc = function(doc, newEdits) {
    if (newEdits) {
      if (!doc._id) {
        doc._id = Math.uuid();
      }
      var newRevId = Math.uuid(32, 16);
      if (doc._rev) {
        var revInfo = /^(\d+)-(.+)$/.exec(doc._rev);
        if (!revInfo) {
          throw "invalid value for property '_rev'";
        }
        doc._revisions = {
          start: parseInt(revInfo[1], 10) + 1,
          ids: [newRevId, revInfo[2]]
        };
      } else {
        doc._revisions = {
          start : 1,
          ids : [newRevId]
      };
      }
    } else {
      if (!doc._revisions) {
        throw "missing property '_revisions'";
      }
      if (!isFinite(doc._revisions.start)) {
        throw "property '_revisions.start' must be a number";
      }
      if (Array.isArray(doc._revisions) && doc._revisions.length > 0) {
        throw "property '_revisions.id' must be a non-empty array";
      }
    }
    doc._id = decodeURIComponent(doc._id);
    doc._rev = [doc._revisions.start, doc._revisions.ids[0]].join('-');
    return Object.keys(doc).reduce(function(acc, key) {
      if (/^_/.test(key))
        acc.metadata[key.slice(1)] = doc[key];
      else
        acc.data[key] = doc[key];
      return acc;
    }, {metadata : {}, data : {}});
  };

  var compareRevs = function(a, b) {
    // Sort by id
    if (a.id !== b.id) {
      return (a.id < b.id ? -1 : 1);
    }
    // Then by deleted
    if (a.deleted ^ b.deleted) {
      return (a.deleted ? -1 : 1);
    }
    // Then by rev id
    if (a.revisions.start === b.revisions.start) {
      return (a.revisions.ids < b.revisions.ids ? -1 : 1);
    }
    // Then by depth of edits
    return (a.revisions.start < b.revisions.start ? -1 : 1);
  };

  // This opens a database, creating it if needed and returns the api
  // used to access the database
  var makePouch = function(db) {

    // Wrapper for functions that call the bulkdocs api with a single doc,
    // if the first result is an error, return an error
    var singularErr = function(callback) {
      return function(err, results) {
        if (err || results[0].error) {
          call(callback, err || results[0]);
        } else {
          call(callback, null, results[0]);
        }
      };
    };

    // Now we create the PouchDB interface
    var pouch = {update_seq: 0};

    // First we look up the metadata in the ids database, then we fetch the
    // current revision(s) from the by sequence store
    pouch.get = function(id, opts, callback) {
      if (opts instanceof Function) {
        callback = opts;
        opts = {};
      }

      var req = db.transaction([DOC_STORE], IDBTransaction.READ)
        .objectStore(DOC_STORE).get(id);

      req.onsuccess = function(e) {
        var metadata = e.target.result;
        if (!e.target.result || metadata.deleted) {
          return call(callback, Errors.MISSING_DOC);
        }

        var nreq = db.transaction([BY_SEQ_STORE], IDBTransaction.READ)
          .objectStore(BY_SEQ_STORE).get(metadata.seq);
        nreq.onsuccess = function(e) {
          var doc = e.target.result;
          doc._id = metadata.id;
          doc._rev = metadata.rev;
          if (opts.revs_info) {
            doc._revs_info = metadata.revisions.ids.map(function(rev, i) {
              // we dont compact, so it kinda has to be, but need to properly
              // check in future
              return {rev: (i + 1) + '-' + rev, status: 'available'};
            });
          }
          callback(null, doc);
        };
      };
    };

    pouch.remove = function(doc, opts, callback) {
      if (opts instanceof Function) {
        callback = opts;
        opts = {};
      }
      doc._deleted = true;
      return pouch.bulkDocs({docs: [doc]}, opts, singularErr(callback));
    };

    pouch.put = pouch.post = function(doc, opts, callback) {
      if (opts instanceof Function) {
        callback = opts;
        opts = {};
      }
      pouch.bulkDocs({docs: [doc]}, opts, singularErr(callback));
    };

    pouch.bulkDocs = function(req, opts, callback) {
      if (opts instanceof Function) {
        callback = opts;
        opts = {};
      }

      var newEdits = 'new_edits' in opts ? opts._new_edits : true;

      // Parse and sort the docs
      var docInfos = req.docs.map(function(doc) {
        return parseDoc(doc, newEdits);
      });

      docInfos.sort(function(a, b) {
        return compareRevs(a.metadata, b.metadata);
      });

      var keyRange = IDBKeyRange.bound(
        docInfos[0].metadata.id, docInfos[docInfos.length-1].metadata.id,
        false, false);

      // This groups edits to the same document together
      var buckets = docInfos.reduce(function(acc, docInfo) {
        if (docInfo.metadata.id === acc[0][0].metadata.id) {
          acc[0].push(docInfo);
        } else {
          acc.unshift([docInfo]);
        }
        return acc;
      }, [[docInfos.shift()]]);

      var txn = db.transaction([DOC_STORE, BY_SEQ_STORE],
                               IDBTransaction.READ_WRITE);
      var results = [];

      txn.oncomplete = function(event) {
        results.forEach(function(result) {
          pouch.changes.emit(result);
        });
        call(callback, null, results);
      };

      txn.onerror = function(event) {
        if (callback) {
          var code = event.target.errorCode;
          var message = Object.keys(IDBDatabaseException)[code].toLowerCase();
          callback({
            error : event.type,
            reason : message
          });
        }
      };

      txn.ontimeout = function(event) {
        if (callback) {
          var code = event.target.errorCode;
          var message = Object.keys(IDBDatabaseException)[code].toLowerCase();
          callback({
            error : event.type,
            reason : message
          });
        }
      };

      var writeDoc = function(docInfo, callback) {
        var dataReq = txn.objectStore(BY_SEQ_STORE).put(docInfo.data);
        dataReq.onsuccess = function(e) {
          docInfo.metadata.seq = e.target.result;
          var metaDataReq = txn.objectStore(DOC_STORE).put(docInfo.metadata);
          metaDataReq.onsuccess = function() {
            results.push({
              id : docInfo.metadata.id,
              rev : docInfo.metadata.rev
            });
            call(callback);
          };
        };
      };

      var cursReq = txn.objectStore(DOC_STORE)
        .openCursor(keyRange, IDBCursor.NEXT);

      cursReq.onsuccess = function(event) {
        var cursor = event.target.result;
        if (cursor) {
          // I am guessing keyRange should be sorted in the same way buckets
          // are, so we can just take the first from buckets
          var doc = buckets.shift();
          // Documents are grouped by id in buckets, which means each document
          // has an array of edits, this currently only works for single edits
          // they should probably be getting merged
          var docInfo = doc[0];
          var revs = cursor.value.revisions.ids;
          // Currently ignoring the revision sequence number, we shouldnt do that
          if (revs[0] !== docInfo.metadata.revisions.ids[1]) {
            results.push(Errors.REV_CONFLICT);
            return cursor['continue']();
          }
          // Start of rev merging, for now we just keep a linear history
          // of revisions
          revs.shift();
          revs.forEach(function(rev) {
            docInfo.metadata.revisions.ids.push(rev);
          });
          writeDoc(docInfo, function() {
            cursor['continue']();
          });
        } else {
          // Cursor has exceeded the key range so the rest are inserts
          buckets.forEach(function(bucket) {
            // TODO: merge the bucket revs into a rev tree
            var docInfo = bucket[0];
            if (docInfo.metadata.deleted) {
              results.push(Errors.MISSING_DOC);
              return;
            }
            writeDoc(docInfo);
          });
        }
      };
    };

    pouch.changes = function(opts) {
      if (!opts.seq) {
        opts.seq = 0;
      }
      var transaction = db.transaction([DOC_STORE, BY_SEQ_STORE]);
      var request = transaction.objectStore(BY_SEQ_STORE)
        .openCursor(IDBKeyRange.lowerBound(opts.seq));
      request.onsuccess = function(event) {
        var cursor = event.target.result;
        if (!cursor) {
          if (opts.continuous) {
            pouch.changes.addListener(opts.onChange);
          }
          if (opts.complete) {
            opts.complete();
          }
        } else {
          var index = transaction.objectStore(DOC_STORE).index('seq');
          index.get(cursor.key).onsuccess = function(event) {
            var doc = event.target.result;
            var c = {
              id: doc.id,
              seq: cursor.key,
              changes: doc.revisions.ids
            };
            if (opts.include_doc) {
              c.doc = cursor.value;
            }
            opts.onChange(c);
            cursor['continue']();
          };
        }
      };
      request.onerror = function(error) {
        // Cursor is out of range
        // NOTE: What should we do with a sequence that is too high?
        if (opts.continuous) {
          pouch.changes.addListener(opts.onChange);
        }
        call(opts.complete);
      };
    };

    pouch.changes.listeners = [];
    pouch.changes.emit = function() {
      var a = arguments;
      pouch.changes.listeners.forEach(function(l) {
        l.apply(l, a);
      });
    };
    pouch.changes.addListener = function(l) {
      pouch.changes.listeners.push(l);
    };

    return pouch;
  };

  pouch.open = function(name, opts, callback) {
    if (opts instanceof Function) {
      callback = opts;
      opts = {};
    }
    name = 'pouch:' + name;

    if (name in pouchCache) {
      return call(callback, null, pouchCache[name]);
    }

    var req = indexedDB.open(name);

    req.onupgradeneeded = function(e) {
      var db = e.target.result;
      db.createObjectStore(DOC_STORE, {keyPath : 'id'})
        .createIndex('seq', 'seq', {unique : true});
      db.createObjectStore(BY_SEQ_STORE, {autoIncrement : true});
    };

    req.onsuccess = function(e) {

      var db = e.target.result;

      db.onversionchange = function() {
        db.close();
        delete pouchCache[name];
      };

      // polyfill the new onupgradeneeded api for chrome
      if (db.setVersion && Number(db.version) !== POUCH_VERSION) {
        var versionReq = db.setVersion(POUCH_VERSION);
        versionReq.onsuccess = function() {
          req.onupgradeneeded(e);
          req.onsuccess(e);
        };
        return;
      }

      pouchCache[name] = makePouch(db);
      call(callback, null, pouchCache[name]);
    };

    req.onerror = function(e) {
      call(callback, {error: 'open', reason: e.toString()});
    };
  };

  pouch.deleteDatabase = function(name, callback) {

    var req = indexedDB.deleteDatabase('pouch:' + name);

    req.onsuccess = function() {
      call(callback, null);
    };

    req.onerror = function(e) {
      call(callback, {error: 'delete', reason: e.toString()});
    };
  };

}).call(this);<|endoftext|>


<commit_before>var body = document.querySelector('body');
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');

canvas.width = 800;
canvas.height = 600;

body.appendChild(canvas);

/* Animation test */
// var assets = [
// 	'/img/robowalk/robowalk00.png',
// 	'/img/robowalk/robowalk01.png',
// 	'/img/robowalk/robowalk02.png',
// 	'/img/robowalk/robowalk03.png',
// 	'/img/robowalk/robowalk04.png',
// 	'/img/robowalk/robowalk05.png',
// 	'/img/robowalk/robowalk06.png',
// 	'/img/robowalk/robowalk07.png',
// 	'/img/robowalk/robowalk08.png',
// 	'/img/robowalk/robowalk09.png',
// 	'/img/robowalk/robowalk10.png',
// 	'/img/robowalk/robowalk11.png',
// 	'/img/robowalk/robowalk12.png',
// 	'/img/robowalk/robowalk13.png',
// 	'/img/robowalk/robowalk14.png',
// 	'/img/robowalk/robowalk15.png',
// 	'/img/robowalk/robowalk16.png',
// 	'/img/robowalk/robowalk17.png',
// 	'/img/robowalk/robowalk18.png'
// ];
// var frames = [];
// var currFrame = 0;

// for(var i=0; i < assets.length; ++i) {
// 	var newImg = new Image();
// 	newImg.onload = function() {
// 		console.log('image loaded');
// 	};
// 	newImg.src = assets[i];
// 	frames[i] = newImg;
// }

// var animate = function() {
// 	ctx.clearRect(0, 0, canvas.width, canvas.height);
// 	ctx.drawImage(frames[currFrame], 100, 100);
// 	currFrame = (currFrame + 1) % frames.length;
// 	requestAnimationFrame(animate);
// }

// requestAnimationFrame(animate);

/* Atlas test */
function parseAtlasDefinition(atlasJSON) {
	var parsed = JSON.parse(atlasJSON);

	/*for(var key in parsed.frames) {
		var sprite = parsed.frames[key];
		// define center of sprite as offset
		var cx = -sprite.frame.w * 0.5;
		var cy = -sprite.frame.h * 0.5;

		// define the sprite for this sheet
		//this.defSprite(key, sprite.frame.x, sprite.frame.y, sprite.frame.w, sprite.frame.h, cx, cy);
	}*/
}

function main() {
	function onClick(e) {
		var canvasOffset = canvas.getBoundingClientRect();
		console.log((e.clientX - canvasOffset.left) + ', ' + (e.clientY - canvasOffset.top));
	}

	var atlasJson = null;

	var image = new Image();
	image.src = 'img/atlas.png';
	image.onload = function() {
		// attempt dl of atlas JSON
		var xhrAtlasJson = new XMLHttpRequest();
		xhrAtlasJson.responseType = 'json';
		xhrAtlasJson.open('GET', '/img/atlas.json', true);
		xhrAtlasJson.responseType = 'json';
		xhrAtlasJson.onload = function() {
			// store atlas JSON
			atlasJson = this.response;

			ctx.drawImage(
				image,
				atlasJson.frames['BHQ2.png'].frame.x,
				atlasJson.frames['BHQ2.png'].frame.y,
				atlasJson.frames['BHQ2.png'].sourceSize.w,
				atlasJson.frames['BHQ2.png'].sourceSize.h,
				10, 10, 70, 70
			);

			ctx.drawImage(
				image,
				atlasJson.frames['FAM2.png'].frame.x,
				atlasJson.frames['FAM2.png'].frame.y,
				atlasJson.frames['FAM2.png'].sourceSize.w,
				atlasJson.frames['FAM2.png'].sourceSize.h,
				100, 100, 70, 70
			);

			console.log(canvas);
			console.log(onClick);
			canvas.addEventListener('click', onClick);
		};
		xhrAtlasJson.send();
	};
}

main();

var AdamEngine = function() {
	this.gameObjs = {};
}

AdamEngine.prototype.createGameObj = function(gameObjName) {
	this.gameObjs[gameObjName] = {
		state: {},
		setup: function() {},
		update: function() {}
	};

	return this.gameObjs[gameObjName];
};

AdamEngine.prototype.deleteGameObj = function(gameObjName) {
	delete this.gameObjs[gameObjName];
};

AdamEngine.prototype.update = function() {};

AdamEngine.prototype.render = function() {};

var AE = new AdamEngine();
var Grid = AE.createGameObj('Grid');
Grid.setup = function() {
	this.state.grid = [];
	this.state.grid.push([])
};

AE.update();

// initialize all game objects first
<commit_msg>Experiments with Object.create<commit_after>var body = document.querySelector('body');
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');

canvas.width = 800;
canvas.height = 600;

body.appendChild(canvas);

/* Animation test */
// var assets = [
// 	'/img/robowalk/robowalk00.png',
// 	'/img/robowalk/robowalk01.png',
// 	'/img/robowalk/robowalk02.png',
// 	'/img/robowalk/robowalk03.png',
// 	'/img/robowalk/robowalk04.png',
// 	'/img/robowalk/robowalk05.png',
// 	'/img/robowalk/robowalk06.png',
// 	'/img/robowalk/robowalk07.png',
// 	'/img/robowalk/robowalk08.png',
// 	'/img/robowalk/robowalk09.png',
// 	'/img/robowalk/robowalk10.png',
// 	'/img/robowalk/robowalk11.png',
// 	'/img/robowalk/robowalk12.png',
// 	'/img/robowalk/robowalk13.png',
// 	'/img/robowalk/robowalk14.png',
// 	'/img/robowalk/robowalk15.png',
// 	'/img/robowalk/robowalk16.png',
// 	'/img/robowalk/robowalk17.png',
// 	'/img/robowalk/robowalk18.png'
// ];
// var frames = [];
// var currFrame = 0;

// for(var i=0; i < assets.length; ++i) {
// 	var newImg = new Image();
// 	newImg.onload = function() {
// 		console.log('image loaded');
// 	};
// 	newImg.src = assets[i];
// 	frames[i] = newImg;
// }

// var animate = function() {
// 	ctx.clearRect(0, 0, canvas.width, canvas.height);
// 	ctx.drawImage(frames[currFrame], 100, 100);
// 	currFrame = (currFrame + 1) % frames.length;
// 	requestAnimationFrame(animate);
// }

// requestAnimationFrame(animate);

/* Atlas test */
// function parseAtlasDefinition(atlasJSON) {
// 	var parsed = JSON.parse(atlasJSON);

// 	/*for(var key in parsed.frames) {
// 		var sprite = parsed.frames[key];
// 		// define center of sprite as offset
// 		var cx = -sprite.frame.w * 0.5;
// 		var cy = -sprite.frame.h * 0.5;

// 		// define the sprite for this sheet
// 		//this.defSprite(key, sprite.frame.x, sprite.frame.y, sprite.frame.w, sprite.frame.h, cx, cy);
// 	}*/
// }

// function main() {
// 	function onClick(e) {
// 		var canvasOffset = canvas.getBoundingClientRect();
// 		console.log((e.clientX - canvasOffset.left) + ', ' + (e.clientY - canvasOffset.top));
// 	}

// 	var atlasJson = null;

// 	var image = new Image();
// 	image.src = 'img/atlas.png';
// 	image.onload = function() {
// 		// attempt dl of atlas JSON
// 		var xhrAtlasJson = new XMLHttpRequest();
// 		xhrAtlasJson.responseType = 'json';
// 		xhrAtlasJson.open('GET', '/img/atlas.json', true);
// 		xhrAtlasJson.responseType = 'json';
// 		xhrAtlasJson.onload = function() {
// 			// store atlas JSON
// 			atlasJson = this.response;

// 			ctx.drawImage(
// 				image,
// 				atlasJson.frames['BHQ2.png'].frame.x,
// 				atlasJson.frames['BHQ2.png'].frame.y,
// 				atlasJson.frames['BHQ2.png'].sourceSize.w,
// 				atlasJson.frames['BHQ2.png'].sourceSize.h,
// 				10, 10, 70, 70
// 			);

// 			ctx.drawImage(
// 				image,
// 				atlasJson.frames['FAM2.png'].frame.x,
// 				atlasJson.frames['FAM2.png'].frame.y,
// 				atlasJson.frames['FAM2.png'].sourceSize.w,
// 				atlasJson.frames['FAM2.png'].sourceSize.h,
// 				100, 100, 70, 70
// 			);

// 			// console.log(canvas);
// 			// console.log(onClick);
// 			canvas.addEventListener('click', onClick);
// 		};
// 		xhrAtlasJson.send();
// 	};
// }

// main();

var AdamEngine = {
	worldObjs: {},
	storeObjs: {},

	/* Classes */
	gameObj: {
		type: null,
		state: {},
		setup: function() {},
		update: function() {}
	},

	// Initialize the game engine so everything can start working
	construct: function () {
		// world objs inherit from game obj
		this.worldObj = Object.create(this.gameObj);
		this.worldObj.type = 'worldObj';
		this.worldObj.state = {
			worldObjType: null,
			pos: {x: 0, y: 0},
			size: {w: 0, h: 0},
			image: null,
			color: null,
			stroke: null
		};
		this.worldObj.render= function() {};

		// store objs inherit from game obj
		this.storeObj = Object.create(this.gameObj);
		this.storeObj.type = 'storeObj';
	},

	/* Game Object Creators/Destroyers */
	createWorldObj: function(worldObjName) {
		this.worldObjs[worldObjName] = Object.create(this.worldObj);
		return this.worldObjs[worldObjName];
	},

	deleteWorldObj: function(worldObjName) {
		delete this.worldObjs[worldObjName];
	},

	createStoreObj: function(storeObjName) {
		this.storeObjs[storeObjName] = Object.create(this.storeObj);
		return this.storeObjs[storeObjName];
	},

	deleteStoreObj: function(storeObjName) {
		this.storeObjs[storeObjName] = Object.create(this.storeObj);
		return this.storeObjs[storeObjName];
	},

	/* Game Loop */
	start: function() {
		// run setup for all game objs
		for(var storeObjName in this.storeObjs) {
			this.storeObjs[storeObjName].setup();
		}

		for(var worldObjName in this.worldObjs) {
			this.worldObjs[worldObjName].setup();
		}

		AdamEngine.update(); // start game loop
	},

	update: function(cb) {
		for(var worldObjName in this.worldObjs) {
			this.worldObjs[worldObjName].update();
		}

		this.render();
	},

	render: function() {
		// render all pos x & y of all world objs
		for(var worldObjName in this.worldObjs) {
			var worldObj = this.worldObjs[worldObjName];
			if(worldObj.type === 'worldObj') {
				if(worldObj.state.worldObjType === 'rect') {
					ctx.fillStyle = worldObj.state.color;
					ctx.fillRect(worldObj.state.pos.x, worldObj.state.pos.y, worldObj.state.size.w, worldObj.state.size.h);

					if(worldObj.state.stroke !== null) {
						ctx.strokeStyle = worldObj.state.stroke.color;
						ctx.strokeRect(worldObj.state.stroke.x, worldObj.state.stroke.y, worldObj.state.stroke.w, worldObj.state.stroke.h);
					}
				}
			}
		}
	}
}

AdamEngine.construct();

var block = AdamEngine.createWorldObj('block');

block.setup = function() {
	this.state.pos = {
		x: 10,
		y: 10
	};

	this.state.size = {
		w: 10,
		h: 10
	};

	this.state.worldObjType = 'rect';
	this.state.color = '#00FF00';
	this.state.stroke = {x: 10, y: 10, w: 10, h: 10, color: '#FFF'};
};

block.update = function() {
	this.state.pos.x += 100;
};

AdamEngine.start();

<|endoftext|>


<commit_before>import logger from 'log-minim'
let log = logger("design")
log.setLevel("debug")

import Rx from 'rx'
let fromEvent = Rx.Observable.fromEvent
let Observable = Rx.Observable
let merge = Rx.Observable.merge

import defaults from "./designDefaults"

function makeModification$(intent){

  /**/
  let newDesign$ = intent.newDesign$
    .map((data) => (designData) => {

      let design = Object.assign({}, designData, data, defaults)
      return design
    })

  let updateDesign$ = intent.setDesignData$
    .map((data) => (designData) => {
      log.info("setting design data", data)

      let design = Object.assign({}, designData, data)

      return design
    })

  let setAsPersistent$ = intent.setAsPersistent$
    .map((flag) => (designData) => {
      log.info("setting design as persistent", flag)
      let output = designData._persistent
      if(flag === undefined || flag === null){
        output = !output
      }else{
        output = flag
      }

      let design = Object.assign({}, designData)
      design._persistent = output

      return design
    })
/*
      //seperation of "sinks" from the rest
      .filter(()=>self.state._persistent)//only save when design is set to persistent
      .debounce(1000)
      .map(self.kernel.saveDesignMeta.bind(self.kernel))
      .subscribe(function(def){
        def.promise.then(function(result){
          //FIXME: hack for now
          console.log("save result",result)
          let serverResp =  JSON.parse(result)
          let persistentUri = self.kernel.dataApi.designsUri+"/"+serverResp.slug

          localStorage.setItem("jam!-lastDesignUri",persistentUri)
        })
        localStorage.setItem("jam!-lastDesignName",self.state.design.name)

      })*/

    return merge(
      newDesign$,
      updateDesign$,
      setAsPersistent$

    )
}

function model(intent, source) {
  let source$ = source || Observable.just(defaults)

  let modification$ = makeModification$(intent)

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

export default model<commit_msg>- removed "sink" method from model<commit_after>import logger from 'log-minim'
let log = logger("design")
log.setLevel("debug")

import Rx from 'rx'
let fromEvent = Rx.Observable.fromEvent
let Observable = Rx.Observable
let merge = Rx.Observable.merge

import defaults from "./designDefaults"

function makeModification$(intent){

  /**/
  let newDesign$ = intent.newDesign$
    .map((data) => (designData) => {

      let design = Object.assign({}, designData, data, defaults)
      return design
    })

  let updateDesign$ = intent.setDesignData$
    .map((data) => (designData) => {
      log.info("setting design data", data)

      let design = Object.assign({}, designData, data)

      return design
    })

  let setAsPersistent$ = intent.setAsPersistent$
    .map((flag) => (designData) => {
      log.info("setting design as persistent", flag)
      let output = designData._persistent
      if(flag === undefined || flag === null){
        output = !output
      }else{
        output = flag
      }

      let design = Object.assign({}, designData)
      design._persistent = output

      return design
    })

    return merge(
      newDesign$,
      updateDesign$,
      setAsPersistent$

    )
}

function model(intent, source) {
  let source$ = source || Observable.just(defaults)

  let modification$ = makeModification$(intent)

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

export default model<|endoftext|>