<commit_before>/*jslint node: true */
'use strict';

var pkg = require('./package.json');
var AV_CONFIG_VERSION = '3.1.2';

//Using exclusion patterns slows down Grunt significantly
//instead of creating a set of patterns like '**/*.js' and '!**/node_modules/**'
//this method is used to create a set of inclusive patterns for all subdirectories
//skipping node_modules, bower_components, dist, and any .dirs
//This enables users to create any directory structure they desire.
var createFolderGlobs = function(fileTypePatterns) {
  fileTypePatterns = Array.isArray(fileTypePatterns) ? fileTypePatterns : [fileTypePatterns];
  var ignore = ['node_modules','bower_components','dist','temp'];
  var fs = require('fs');
  return fs.readdirSync(process.cwd())
          .map(function(file){
            if (ignore.indexOf(file) !== -1 ||
                file.indexOf('.') === 0 ||
                !fs.lstatSync(file).isDirectory()) {
              return null;
            } else {
              return fileTypePatterns.map(function(pattern) {
                return file + '/**/' + pattern;
              });
            }
          })
          .filter(function(patterns){
            return patterns;
          })
          .concat(fileTypePatterns);
};

module.exports = function (grunt) {

  // load all grunt tasks
  require('load-grunt-tasks')(grunt);

  // custom grunt task to check avConfig.js
  grunt.registerTask('check_config', function() {
    var fs = require('fs');
    var done = this.async();
    grunt.log.ok('Checking avConfig.js...');
    var conf = fs.readFile('avConfig.js', function(err, data) {
        if (err) {
            grunt.log.error('No avConfig.js file found');
            done(false);
        } else {
            var match = data.toString().match(/AV_CONFIG_VERSION = [\'\"]([\w\.]*)[\'\"];/);
            if (!match) {
                grunt.log.error('Invalid avConfig.js version');
            } else {
                var v = match[1];
                if (v === AV_CONFIG_VERSION) {
                    return done();
                } else {
                    grunt.log.error('Invalid avConfig.js version: ' + v);
                }
            }
            done(false);
        }
    });
  });

  // Project configuration.
  grunt.initConfig({
    connect: {
      main: {
        options: {
          port: 9001
        }
      }
    },
    watch: {
      main: {
        options: {
            livereload: true,
            livereloadOnError: false,
            spawn: false
        },
        files: [createFolderGlobs(['*.js','*.less','*.html']),'!_SpecRunner.html','!.grunt'],
        tasks: [] //all the tasks are run dynamically during the watch event handler
      }
    },
    jshint: {
      main: {
        options: {
            jshintrc: '.jshintrc'
        },
        src: createFolderGlobs('*.js')
      }
    },
    clean: {
      before:{
        src:['dist','temp']
      },
      after: {
        src:['temp']
      }
    },
    less: {
      production: {
        options: {
        },
        files: [{
          expand: true,
          src: ['bower_components/avCommon/themes/**/app.less'],
          dest: 'temp/',
          ext: '.css',
        }]
      }
    },
    autoprefixer: {
      options: {
        browsers: ['ie >= 8', 'ff > 4', 'last 8 versions']
      },
      main: {
        src: 'temp/bower_components/avCommon/themes/**/app.css'
      }
    },
    ngtemplates: {
      main: {
        options: {
            module: pkg.name,
            htmlmin:'<%= htmlmin.main.options %>'
        },
        src: [createFolderGlobs('*.html'),'!index.html','!_SpecRunner.html'],
        dest: 'temp/templates.js'
      },
      common: {
        options: {
            module: pkg.name,
            htmlmin:'<%= htmlmin.main.options %>'
        },
        cwd: 'bower_components/avCommon',
        src: ["avRegistration/**/*.html", "avUi/**/*.html" ],
        dest: 'temp/templates-common.js'
      }
    },
    copy: {
      main: {
        files: [
          {src: ['img/**'], dest: 'dist/'},
          {src: ['img/**'], dest: 'dist/'},
          {src: ['temp_data/**'], dest: 'dist/'},
          {
            expand: true,
            cwd:'bower_components/avCommon/themes',
            src: ['**/*.png'],
            dest: 'dist/themes/',
            ext: '.png',
            extDot: 'first'
          },
          {
            expand: true,
            cwd: 'bower_components/bootstrap/fonts/',
            src: ['**'],
            dest: 'dist/themes/fonts/'
          },
          {
            expand: true,
            cwd: 'bower_components/bootstrap/fonts/',
            src: ['**'],
            dest: 'dist/themes/fonts/'
          },
          {
            expand: true,
            cwd: 'bower_components/font-awesome/fonts/',
            src: ['**'],
            dest: 'dist/fonts/'
          }
          //{src: ['bower_components/angular-ui-utils/ui-utils-ieshiv.min.js'], dest: 'dist/'},
          //{src: ['bower_components/select2/*.png','bower_components/select2/*.gif'], dest:'dist/css/',flatten:true,expand:true},
          //{src: ['bower_components/angular-mocks/angular-mocks.js'], dest: 'dist/'}
        ]
      }
    },
    dom_munger:{
      read: {
        options: {
          read:[
            {selector:'script[class="libnocompat"]',attribute:'src',writeto:'libnocompatjs'},
            {selector:'script[class="lib"]',attribute:'src',writeto:'libjs'},
            {selector:'script[class="app"]',attribute:'src',writeto:'appjs'},
            {selector:'link[rel="stylesheet"][data-concat!="false"]',attribute:'href',writeto:'appcss'}
          ]
        },
        src: 'index.html'
      },
      update: {
        options: {
          remove: ['script[data-remove!="false"]','link[data-remove!="false"]'],
          append: [
            {selector:'body',html:'<!--[if lte IE 8]><script src="/election/libcompat-v3.0.1.min.js"></script><![endif]--><!--[if gte IE 9]><script src="/election/libnocompat-v3.0.1.min.js"></script><![endif]--><!--[if !IE]><!--><script src="/election/libnocompat-v3.0.1.min.js"></script><!--<![endif]-->'},
            {selector:'body',html:'<!--All the source code of this program under copyright. Take a look at the license details at https://github.com/agoravoting/agora-core-view/blob/master/README.md -->'},
            {selector:'body',html:'<script src="/election/lib-v3.0.1.min.js"></script>'},
            {selector:'body',html:'<script src="/election/avConfig-v3.0.1.js"></script>'},
            {selector:'body',html:'<script src="/election/avThemes-v3.0.1.js"></script>'},
            {selector:'body',html:'<script src="/election/app-v3.0.1.min.js"></script>'},
            {selector:'body',html:'<script src="/election/avPlugins-v3.0.1.js"></script>'},
            {selector:'head',html:'<link rel="stylesheet" id="theme" data-base="/election/" href="/election/themes/default/app.min.css">'}
          ]
        },
        src:'index.html',
        dest: 'dist/index.html'
      }
    },
    cssmin: {
      main: {
        files: [{
            expand: true,
            cwd:'temp/bower_components/avCommon/themes',
            src: ['**/app.css'],
            dest: 'dist/themes/',
            ext: '.min.css',
            extDot: 'first'
        }]
      },
    },
    concat: {
      main: {
        files: {
          'temp/libcompat.js': [
            'vendor/jquery.compat/jquery-1.11.1.js',
            'vendor/json3/json-v3.3.2.js',
            'vendor/crypto/unsupportedBrowser.js'
          ],
          'temp/libnocompat.js': ['<%= dom_munger.data.libnocompatjs %>'],
          'temp/lib.js': ['<%= dom_munger.data.libjs %>'],
          'temp/app.js': ['<%= dom_munger.data.appjs %>','<%= ngtemplates.main.dest %>','<%= ngtemplates.common.dest %>'],
          'dist/avConfig-v3.0.1.js': ['avConfig.js'],
          'dist/avThemes-v3.0.1.js': ['bower_components/avCommon/dist/avThemes-v3.0.1.js'],
          'dist/avPlugins-v3.0.1.js': ['plugins/**/*.js']
        }
      }
    },
    "merge-json": {
      main: {
        files: {
            "dist/locales/en.json": ["locales/en.json", "plugins/**/locales/en.json", "bower_components/avCommon/locales/en.json"],
            "dist/locales/es.json": ["locales/es.json", "plugins/**/locales/es.json", "bower_components/avCommon/locales/es.json"],
            "dist/locales/gl.json": ["locales/gl.json", "plugins/**/locales/gl.json", "bower_components/avCommon/locales/gl.json"],
            "dist/locales/ca.json": ["locales/ca.json", "plugins/**/locales/ca.json", "bower_components/avCommon/locales/ca.json"]
        }
      }
    },
    ngAnnotate: {
      main: {
        files: {
        'temp/app.js':['temp/app.js'],
        'temp/lib.js': ['temp/lib.js'],
        'temp/libnocompat.js': ['temp/libnocompat.js'],
        'temp/libcompat.js': ['temp/libcompat.js']
        }
      }
    },
    uglify: {
      main: {
        options:{
          mangle: false,
          compress: {},
          beautify: true
        },
        files: {
          'dist/app-v3.0.1.min.js': 'temp/app.js',
          'dist/lib-v3.0.1.min.js': 'temp/lib.js',
          'dist/libnocompat-v3.0.1.min.js': 'temp/libnocompat.js',
          'dist/libcompat-v3.0.1.min.js': 'temp/libcompat.js',
          'dist/avWidgets.min.js': 'avWidgets.js',

          "dist/locales/moment/en.js": "bower_components/moment/lang/en-gb.js",
          "dist/locales/moment/es.js": "bower_components/moment/lang/es.js",
          "dist/locales/moment/gl.js": "bower_components/moment/lang/gl.js",
          "dist/locales/moment/ca.js": "bower_components/moment/lang/ca.js"
        }
      }
    },
    htmlmin: {
      main: {
        options: {
          collapseBooleanAttributes: true,
          collapseWhitespace: true,
          removeAttributeQuotes: false,
          removeComments: false,
          removeEmptyAttributes: true,
          removeScriptTypeAttributes: true,
          removeStyleLinkTypeAttributes: true
        },
        files: {
          'dist/index.html': 'dist/index.html'
        }
      }
    },
    karma: {
      options: {
        frameworks: ['jasmine'],
        files: [  //this files data is also updated in the watch handler, if updated change there too
          '<%= dom_munger.data.libnocompatjs %>',
          '<%= dom_munger.data.libjs %>',
          'avConfig.js',
          'avThemes.js',
          'avWidgets.js',
          '<%= dom_munger.data.appjs %>',
          '<%= ngtemplates.main.dest %>',
          '<%= ngtemplates.common.dest %>',
          'bower_components/angular-mocks/angular-mocks.js',
          createFolderGlobs('*-spec.js')
        ],
        logLevel:'ERROR',
        reporters:['mocha'],
        autoWatch: false, //watching is handled by grunt-contrib-watch
        singleRun: true
      },
      all_tests: {
        browsers: ['PhantomJS','Chrome','Firefox']
      },
      during_watch: {
        browsers: ['PhantomJS']
      },
    },
    protractor: {
      options: {
        configFile: "node_modules/protractor/referenceConf.js", // Default config file
        keepAlive: true, // If false, the grunt process stops when the test fails.
        noColor: false, // If true, protractor will not use colors in its output.
        args: {
        // Arguments passed to the command
      }
    },
    //your_target: {   // Grunt requires at least one target to run so you can simply put 'all: {}' here too.
      all: {
      options: {
        configFile: "e2e.conf.js", // Target-specific config file
        args: {} // Target-specific arguments
      }
    },
  },

  });

  grunt.registerTask('build',['check_config', 'jshint','clean:before','less','autoprefixer','dom_munger','ngtemplates','cssmin','concat','merge-json','ngAnnotate','uglify','copy','htmlmin','clean:after']);
  grunt.registerTask('serve', ['dom_munger:read','jshint','connect', 'watch']);
  grunt.registerTask('test',['dom_munger:read','karma:all_tests']);

  grunt.event.on('watch', function(action, filepath) {
    //https://github.com/gruntjs/grunt-contrib-watch/issues/156

    var tasksToRun = [];

    if ((filepath.lastIndexOf('.json') !== -1 && filepath.lastIndexOf('.json') === filepath.length - 5) ||
        (filepath.lastIndexOf('.js') !== -1 && filepath.lastIndexOf('.js') === filepath.length - 3)) {

      //lint the changed js file
      grunt.config('jshint.main.src', filepath);
      tasksToRun.push('jshint');

      //find the appropriate unit t est for the changed file
      var spec = filepath;
      if (filepath.lastIndexOf('-spec.js') === -1 || filepath.lastIndexOf('-spec.js') !== filepath.length - 8) {
        spec = filepath.substring(0,filepath.length - 3) + '-spec.js';
      }

      //if the spec exists then lets run it
      if (grunt.file.exists(spec)) {
        var files = [].concat(grunt.config('dom_munger.data.libnocompatjs'));
        files.concat(grunt.config('dom_munger.data.libjs'));
        files.push('bower_components/angular-mocks/angular-mocks.js');
        files.push('avConfig.js');
        files.push('avThemes.js');
        files.push('avWidgets.js');
        files.concat(grunt.config('dom_munger.data.appjs'));
        files.concat(grunt.config('ngtemplates.main.dest'));
        files.push(spec);
        grunt.config('karma.options.files', files);
        tasksToRun.push('karma:during_watch');
      }
    }

    //if index.html changed, we need to reread the <script> tags so our next run of karma
    //will have the correct environment
    if (filepath === 'index.html') {
      tasksToRun.push('dom_munger:read');
    }

    grunt.config('watch.main.tasks',tasksToRun);

  });

  grunt.loadNpmTasks('grunt-protractor-runner');
};
<commit_msg>Changed avConfig version<commit_after>/*jslint node: true */
'use strict';

var pkg = require('./package.json');
var AV_CONFIG_VERSION = '3.1.3';

//Using exclusion patterns slows down Grunt significantly
//instead of creating a set of patterns like '**/*.js' and '!**/node_modules/**'
//this method is used to create a set of inclusive patterns for all subdirectories
//skipping node_modules, bower_components, dist, and any .dirs
//This enables users to create any directory structure they desire.
var createFolderGlobs = function(fileTypePatterns) {
  fileTypePatterns = Array.isArray(fileTypePatterns) ? fileTypePatterns : [fileTypePatterns];
  var ignore = ['node_modules','bower_components','dist','temp'];
  var fs = require('fs');
  return fs.readdirSync(process.cwd())
          .map(function(file){
            if (ignore.indexOf(file) !== -1 ||
                file.indexOf('.') === 0 ||
                !fs.lstatSync(file).isDirectory()) {
              return null;
            } else {
              return fileTypePatterns.map(function(pattern) {
                return file + '/**/' + pattern;
              });
            }
          })
          .filter(function(patterns){
            return patterns;
          })
          .concat(fileTypePatterns);
};

module.exports = function (grunt) {

  // load all grunt tasks
  require('load-grunt-tasks')(grunt);

  // custom grunt task to check avConfig.js
  grunt.registerTask('check_config', function() {
    var fs = require('fs');
    var done = this.async();
    grunt.log.ok('Checking avConfig.js...');
    var conf = fs.readFile('avConfig.js', function(err, data) {
        if (err) {
            grunt.log.error('No avConfig.js file found');
            done(false);
        } else {
            var match = data.toString().match(/AV_CONFIG_VERSION = [\'\"]([\w\.]*)[\'\"];/);
            if (!match) {
                grunt.log.error('Invalid avConfig.js version');
            } else {
                var v = match[1];
                if (v === AV_CONFIG_VERSION) {
                    return done();
                } else {
                    grunt.log.error('Invalid avConfig.js version: ' + v);
                }
            }
            done(false);
        }
    });
  });

  // Project configuration.
  grunt.initConfig({
    connect: {
      main: {
        options: {
          port: 9001
        }
      }
    },
    watch: {
      main: {
        options: {
            livereload: true,
            livereloadOnError: false,
            spawn: false
        },
        files: [createFolderGlobs(['*.js','*.less','*.html']),'!_SpecRunner.html','!.grunt'],
        tasks: [] //all the tasks are run dynamically during the watch event handler
      }
    },
    jshint: {
      main: {
        options: {
            jshintrc: '.jshintrc'
        },
        src: createFolderGlobs('*.js')
      }
    },
    clean: {
      before:{
        src:['dist','temp']
      },
      after: {
        src:['temp']
      }
    },
    less: {
      production: {
        options: {
        },
        files: [{
          expand: true,
          src: ['bower_components/avCommon/themes/**/app.less'],
          dest: 'temp/',
          ext: '.css',
        }]
      }
    },
    autoprefixer: {
      options: {
        browsers: ['ie >= 8', 'ff > 4', 'last 8 versions']
      },
      main: {
        src: 'temp/bower_components/avCommon/themes/**/app.css'
      }
    },
    ngtemplates: {
      main: {
        options: {
            module: pkg.name,
            htmlmin:'<%= htmlmin.main.options %>'
        },
        src: [createFolderGlobs('*.html'),'!index.html','!_SpecRunner.html'],
        dest: 'temp/templates.js'
      },
      common: {
        options: {
            module: pkg.name,
            htmlmin:'<%= htmlmin.main.options %>'
        },
        cwd: 'bower_components/avCommon',
        src: ["avRegistration/**/*.html", "avUi/**/*.html" ],
        dest: 'temp/templates-common.js'
      }
    },
    copy: {
      main: {
        files: [
          {src: ['img/**'], dest: 'dist/'},
          {src: ['img/**'], dest: 'dist/'},
          {src: ['temp_data/**'], dest: 'dist/'},
          {
            expand: true,
            cwd:'bower_components/avCommon/themes',
            src: ['**/*.png'],
            dest: 'dist/themes/',
            ext: '.png',
            extDot: 'first'
          },
          {
            expand: true,
            cwd: 'bower_components/bootstrap/fonts/',
            src: ['**'],
            dest: 'dist/themes/fonts/'
          },
          {
            expand: true,
            cwd: 'bower_components/bootstrap/fonts/',
            src: ['**'],
            dest: 'dist/themes/fonts/'
          },
          {
            expand: true,
            cwd: 'bower_components/font-awesome/fonts/',
            src: ['**'],
            dest: 'dist/fonts/'
          }
          //{src: ['bower_components/angular-ui-utils/ui-utils-ieshiv.min.js'], dest: 'dist/'},
          //{src: ['bower_components/select2/*.png','bower_components/select2/*.gif'], dest:'dist/css/',flatten:true,expand:true},
          //{src: ['bower_components/angular-mocks/angular-mocks.js'], dest: 'dist/'}
        ]
      }
    },
    dom_munger:{
      read: {
        options: {
          read:[
            {selector:'script[class="libnocompat"]',attribute:'src',writeto:'libnocompatjs'},
            {selector:'script[class="lib"]',attribute:'src',writeto:'libjs'},
            {selector:'script[class="app"]',attribute:'src',writeto:'appjs'},
            {selector:'link[rel="stylesheet"][data-concat!="false"]',attribute:'href',writeto:'appcss'}
          ]
        },
        src: 'index.html'
      },
      update: {
        options: {
          remove: ['script[data-remove!="false"]','link[data-remove!="false"]'],
          append: [
            {selector:'body',html:'<!--[if lte IE 8]><script src="/election/libcompat-v3.0.1.min.js"></script><![endif]--><!--[if gte IE 9]><script src="/election/libnocompat-v3.0.1.min.js"></script><![endif]--><!--[if !IE]><!--><script src="/election/libnocompat-v3.0.1.min.js"></script><!--<![endif]-->'},
            {selector:'body',html:'<!--All the source code of this program under copyright. Take a look at the license details at https://github.com/agoravoting/agora-core-view/blob/master/README.md -->'},
            {selector:'body',html:'<script src="/election/lib-v3.0.1.min.js"></script>'},
            {selector:'body',html:'<script src="/election/avConfig-v3.0.1.js"></script>'},
            {selector:'body',html:'<script src="/election/avThemes-v3.0.1.js"></script>'},
            {selector:'body',html:'<script src="/election/app-v3.0.1.min.js"></script>'},
            {selector:'body',html:'<script src="/election/avPlugins-v3.0.1.js"></script>'},
            {selector:'head',html:'<link rel="stylesheet" id="theme" data-base="/election/" href="/election/themes/default/app.min.css">'}
          ]
        },
        src:'index.html',
        dest: 'dist/index.html'
      }
    },
    cssmin: {
      main: {
        files: [{
            expand: true,
            cwd:'temp/bower_components/avCommon/themes',
            src: ['**/app.css'],
            dest: 'dist/themes/',
            ext: '.min.css',
            extDot: 'first'
        }]
      },
    },
    concat: {
      main: {
        files: {
          'temp/libcompat.js': [
            'vendor/jquery.compat/jquery-1.11.1.js',
            'vendor/json3/json-v3.3.2.js',
            'vendor/crypto/unsupportedBrowser.js'
          ],
          'temp/libnocompat.js': ['<%= dom_munger.data.libnocompatjs %>'],
          'temp/lib.js': ['<%= dom_munger.data.libjs %>'],
          'temp/app.js': ['<%= dom_munger.data.appjs %>','<%= ngtemplates.main.dest %>','<%= ngtemplates.common.dest %>'],
          'dist/avConfig-v3.0.1.js': ['avConfig.js'],
          'dist/avThemes-v3.0.1.js': ['bower_components/avCommon/dist/avThemes-v3.0.1.js'],
          'dist/avPlugins-v3.0.1.js': ['plugins/**/*.js']
        }
      }
    },
    "merge-json": {
      main: {
        files: {
            "dist/locales/en.json": ["locales/en.json", "plugins/**/locales/en.json", "bower_components/avCommon/locales/en.json"],
            "dist/locales/es.json": ["locales/es.json", "plugins/**/locales/es.json", "bower_components/avCommon/locales/es.json"],
            "dist/locales/gl.json": ["locales/gl.json", "plugins/**/locales/gl.json", "bower_components/avCommon/locales/gl.json"],
            "dist/locales/ca.json": ["locales/ca.json", "plugins/**/locales/ca.json", "bower_components/avCommon/locales/ca.json"]
        }
      }
    },
    ngAnnotate: {
      main: {
        files: {
        'temp/app.js':['temp/app.js'],
        'temp/lib.js': ['temp/lib.js'],
        'temp/libnocompat.js': ['temp/libnocompat.js'],
        'temp/libcompat.js': ['temp/libcompat.js']
        }
      }
    },
    uglify: {
      main: {
        options:{
          mangle: false,
          compress: {},
          beautify: true
        },
        files: {
          'dist/app-v3.0.1.min.js': 'temp/app.js',
          'dist/lib-v3.0.1.min.js': 'temp/lib.js',
          'dist/libnocompat-v3.0.1.min.js': 'temp/libnocompat.js',
          'dist/libcompat-v3.0.1.min.js': 'temp/libcompat.js',
          'dist/avWidgets.min.js': 'avWidgets.js',

          "dist/locales/moment/en.js": "bower_components/moment/lang/en-gb.js",
          "dist/locales/moment/es.js": "bower_components/moment/lang/es.js",
          "dist/locales/moment/gl.js": "bower_components/moment/lang/gl.js",
          "dist/locales/moment/ca.js": "bower_components/moment/lang/ca.js"
        }
      }
    },
    htmlmin: {
      main: {
        options: {
          collapseBooleanAttributes: true,
          collapseWhitespace: true,
          removeAttributeQuotes: false,
          removeComments: false,
          removeEmptyAttributes: true,
          removeScriptTypeAttributes: true,
          removeStyleLinkTypeAttributes: true
        },
        files: {
          'dist/index.html': 'dist/index.html'
        }
      }
    },
    karma: {
      options: {
        frameworks: ['jasmine'],
        files: [  //this files data is also updated in the watch handler, if updated change there too
          '<%= dom_munger.data.libnocompatjs %>',
          '<%= dom_munger.data.libjs %>',
          'avConfig.js',
          'avThemes.js',
          'avWidgets.js',
          '<%= dom_munger.data.appjs %>',
          '<%= ngtemplates.main.dest %>',
          '<%= ngtemplates.common.dest %>',
          'bower_components/angular-mocks/angular-mocks.js',
          createFolderGlobs('*-spec.js')
        ],
        logLevel:'ERROR',
        reporters:['mocha'],
        autoWatch: false, //watching is handled by grunt-contrib-watch
        singleRun: true
      },
      all_tests: {
        browsers: ['PhantomJS','Chrome','Firefox']
      },
      during_watch: {
        browsers: ['PhantomJS']
      },
    },
    protractor: {
      options: {
        configFile: "node_modules/protractor/referenceConf.js", // Default config file
        keepAlive: true, // If false, the grunt process stops when the test fails.
        noColor: false, // If true, protractor will not use colors in its output.
        args: {
        // Arguments passed to the command
      }
    },
    //your_target: {   // Grunt requires at least one target to run so you can simply put 'all: {}' here too.
      all: {
      options: {
        configFile: "e2e.conf.js", // Target-specific config file
        args: {} // Target-specific arguments
      }
    },
  },

  });

  grunt.registerTask('build',['check_config', 'jshint','clean:before','less','autoprefixer','dom_munger','ngtemplates','cssmin','concat','merge-json','ngAnnotate','uglify','copy','htmlmin','clean:after']);
  grunt.registerTask('serve', ['dom_munger:read','jshint','connect', 'watch']);
  grunt.registerTask('test',['dom_munger:read','karma:all_tests']);

  grunt.event.on('watch', function(action, filepath) {
    //https://github.com/gruntjs/grunt-contrib-watch/issues/156

    var tasksToRun = [];

    if ((filepath.lastIndexOf('.json') !== -1 && filepath.lastIndexOf('.json') === filepath.length - 5) ||
        (filepath.lastIndexOf('.js') !== -1 && filepath.lastIndexOf('.js') === filepath.length - 3)) {

      //lint the changed js file
      grunt.config('jshint.main.src', filepath);
      tasksToRun.push('jshint');

      //find the appropriate unit t est for the changed file
      var spec = filepath;
      if (filepath.lastIndexOf('-spec.js') === -1 || filepath.lastIndexOf('-spec.js') !== filepath.length - 8) {
        spec = filepath.substring(0,filepath.length - 3) + '-spec.js';
      }

      //if the spec exists then lets run it
      if (grunt.file.exists(spec)) {
        var files = [].concat(grunt.config('dom_munger.data.libnocompatjs'));
        files.concat(grunt.config('dom_munger.data.libjs'));
        files.push('bower_components/angular-mocks/angular-mocks.js');
        files.push('avConfig.js');
        files.push('avThemes.js');
        files.push('avWidgets.js');
        files.concat(grunt.config('dom_munger.data.appjs'));
        files.concat(grunt.config('ngtemplates.main.dest'));
        files.push(spec);
        grunt.config('karma.options.files', files);
        tasksToRun.push('karma:during_watch');
      }
    }

    //if index.html changed, we need to reread the <script> tags so our next run of karma
    //will have the correct environment
    if (filepath === 'index.html') {
      tasksToRun.push('dom_munger:read');
    }

    grunt.config('watch.main.tasks',tasksToRun);

  });

  grunt.loadNpmTasks('grunt-protractor-runner');
};
<|endoftext|>


<commit_before>import './module.js';
import Overlay from 'ol/Overlay';
import WMSGetFeatureInfo from 'ol/format/WMSGetFeatureInfo';
import VectorLayer from 'ol/layer/Vector';
import { unByKey } from 'ol/Observable';

angular.module('anol.getfeatureinfo')
/**
 * @ngdoc directive
 * @name anol.getfeatureinfo.directive:anolGetFeatureInfo
 *
 * @restrict A
 * @requires $http
 * @required $window
 * @requires anol.map.MapService
 * @requires anol.map.LayersService
 * @requires anol.map.ControlsService
 *
 * @description
 * Makes GetFeatureInfo request on all non vector layers with 'featureinfo' property
 * and show result if not empty depending on 'target' specified in 'featureinfo'
 *
 * @param {function} customTargetFilled Callback called after featureinfo result added to custom element
 * @param {string} templateUrl Url to template to use instead of default one
 * @param {function} beforeRequest Callback called before featureinfo requests are fulfilled
 * @param {string} proxyUrl Url for proxy to use for requests.
                            When proxyUrl is used, name of requested anol layer
 *                          is appended as path to proxyUrl. E.g.: proxyUrl = '/foo', for layer with name 'bar' requested url is '/foo/bar/'.
 *                          Also only url params are submitted.
 *
 * Layer property **featureinfo** - {Object} - Contains properties:
 * - **target** - {string} - Target for featureinfo result. ('_blank', '_popup', [element-id])
 */
    .directive('anolGetFeatureInfo', [
        '$templateRequest', '$http', '$window', '$q', '$compile', 'MapService', 'LayersService', 'ControlsService',
        function($templateRequest, $http, $window, $q, $compile, MapService, LayersService, ControlsService) {
            return {
                restrict: 'A',
                scope: {
                    customTargetFilled: '&',
                    beforeRequest: '&',
                    proxyUrl: '@',
                    popupOpeningDirection: '@',
                    waitingMarkerSrc: '@?',
                    waitingMarkerOffset: '=?',
                    excludeLayers: '=?'
                },
                template: function(tElement, tAttrs) {
                    if (tAttrs.templateUrl) {
                        return '

';
                    }
                    return require('./templates/getfeatureinfo.html');
                },
                link: {
                    pre: function(scope, element, attrs) {
                        if (attrs.templateUrl && attrs.templateUrl !== '') {
                            $templateRequest(attrs.templateUrl).then(function(html){
                                var template = angular.element(html);
                                element.html(template);
                                $compile(template)(scope);
                            });
                        }
                        scope.popupOpeningDirection = scope.popupOpeningDirection || 'top';

                        scope.map = MapService.getMap();
                        // get callback from wrapper function
                        scope.customTargetCallback = scope.customTargetFilled();
                        scope.beforeRequest = scope.beforeRequest();

                        if(angular.isDefined(scope.waitingMarkerSrc)) {
                            scope.waitingOverlayElement = element.find('#get-featureinfo-waiting-overlay');
                            $compile(scope.waitingOverlayElement)(scope);
                            scope.waitingOverlay = new Overlay({
                                element: scope.waitingOverlayElement[0],
                                position: undefined,
                                offset: scope.waitingMarkerOffset
                            });
                            scope.map.addOverlay(scope.waitingOverlay);
                        }
                        var view = scope.map.getView();

                        if(angular.isDefined(scope.proxyUrl)) {
                            if(scope.proxyUrl[scope.proxyUrl.length - 1] !== '/') {
                                scope.proxyUrl += '/';
                            }
                        }

                        var featureInfoLayer = new anol.layer.Feature({
                            name: 'featureInfoLayer',
                            displayInLayerswitcher: false,
                            style: scope.markerStyle
                        });
                        var markerOlLayerOptions = featureInfoLayer.olLayerOptions;
                        markerOlLayerOptions.source = new featureInfoLayer.OL_SOURCE_CLASS(featureInfoLayer.olSourceOptions);
                        markerOlLayerOptions.zIndex = 2001;
                        featureInfoLayer.setOlLayer(new featureInfoLayer.OL_LAYER_CLASS(markerOlLayerOptions));

                        LayersService.addSystemLayer(featureInfoLayer, 0);

                        var handleFeatureinfoResponses = function(featureInfoObjects) {
                            var divTargetCleared = false;
                            var popupContentTemp = $('

');
                            var popupCoordinate;
                            angular.forEach(featureInfoObjects, function(featureInfoObject) {
                                if(angular.isUndefined(featureInfoObject)) {
                                    return;
                                }
                                var iframe;
                                if(featureInfoObject.target === '_popup') {
                                    iframe = $('');
                                }
                                switch(featureInfoObject.target) {
                                case '_blank':
                                    $window.open(featureInfoObject.url, '_blank');
                                    break;
                                case '_popup':
                                    iframe.css('width', featureInfoObject.width || 300);
                                    iframe.css('height', featureInfoObject.height || 150);
                                    popupContentTemp.append(iframe);
                                    popupCoordinate = featureInfoObject.coordinate;
                                    break;
                                default:
                                    var temp = $('

');
                                    var target = angular.element(featureInfoObject.target);
                                    if(divTargetCleared === false) {
                                        target.empty();
                                        divTargetCleared = true;
                                    }
                                    var content = angular.element(featureInfoObject.response);
                                    temp.append(content);
                                    temp.find('meta').remove();
                                    temp.find('link').remove();
                                    temp.find('title').remove();
                                    temp.find('script').remove();
                                    target.append(temp.children());
                                    if(angular.isFunction(scope.customTargetCallback)) {
                                        scope.customTargetCallback();
                                    }
                                    break;
                                }
                            });
                            if(angular.isDefined(popupCoordinate)) {
                                scope.popupProperties = {
                                    coordinate: popupCoordinate,
                                    content: popupContentTemp.children()
                                };
                            }
                            scope.hideWaitingOverlay();
                        };

                        var handleGMLFeatureinfoResponses = function(responses) {
                            var format = new WMSGetFeatureInfo();

                            angular.forEach(responses, function(response) {
                                if(angular.isUndefined(response)) {
                                    return;
                                }
                                if(angular.isUndefined(response.gmlData)) {
                                    return;
                                }
                                var features = format.readFeatures(response.gmlData);
                                angular.forEach(features, function(feature) {
                                    feature.set('style', response.style);
                                });
                                featureInfoLayer.addFeatures(features);
                            });
                        };

                        scope.handleClick = function(evt) {
                            var viewResolution = view.getResolution();
                            var coordinate = evt.coordinate;

                            scope.popupProperties = {coordinate: undefined};
                            featureInfoLayer.clear();

                            if(angular.isFunction(scope.beforeRequest)) {
                                scope.beforeRequest();
                            }

                            scope.showWaitingOverlay(coordinate);

                            var requestPromises = [];
                            // this is resolved after all requests started
                            var requestsDeferred = $q.defer();
                            requestsDeferred.promise.then(function() {
                                // promises added before requests started
                                // all promises will be resolved, otherwise we can't access the data
                                // promises that should be rejected will be resolved with undefined
                                $q.all(requestPromises).then(handleFeatureinfoResponses);
                            });

                            var gmlRequestPromises = [];
                            var gmlRequestsDeferred = $q.defer();
                            gmlRequestsDeferred.promise.then(function() {
                                $q.all(requestPromises.concat(gmlRequestPromises)).then(handleGMLFeatureinfoResponses);
                            });

                            angular.forEach(LayersService.flattedLayers(), function(layer) {
                                if(!layer.getVisible()) {
                                    return;
                                }
                                if(layer.olLayer instanceof VectorLayer) {
                                    return;
                                }
                                if(!layer.featureinfo) {
                                    return;
                                }

                                var requestParams ={
                                    'INFO_FORMAT': 'text/html'
                                };
                                if(angular.isDefined(layer.featureinfo.featureCount)) {
                                    requestParams.FEATURE_COUNT = layer.featureinfo.featureCount;
                                }

                                var url = layer.getFeatureInfoUrl(
                                    coordinate, viewResolution, view.getProjection().getCode(), requestParams
                                );
                                if(angular.isDefined(scope.proxyUrl)) {
                                    url = scope.proxyUrl + layer.name + '/?' + url.split('?')[1];
                                }
                                if(angular.isDefined(url)) {
                                    var requestDeferred = $q.defer();
                                    requestPromises.push(requestDeferred.promise);
                                    $http.get(url).then(
                                        function(response) {
                                            if(angular.isString(response.data) && response.data !== '' && response.data.search('^\s*<\?xml') === -1) {
                                                requestDeferred.resolve({
                                                    target: layer.featureinfo.target,
                                                    width: layer.featureinfo.width,
                                                    height: layer.featureinfo.height,
                                                    url: url,
                                                    response: response.data,
                                                    coordinate: coordinate
                                                });
                                            } else {
                                                requestDeferred.resolve();
                                            }
                                        },
                                        function() {
                                            requestDeferred.resolve();
                                        }
                                    );
                                }

                                if(layer.featureinfo.gml !== true) {
                                    return;
                                }

                                var gmlRequestParams = {
                                    'INFO_FORMAT': 'application/vnd.ogc.gml'
                                };

                                if(angular.isDefined(layer.featureinfo.featureCount)) {
                                    gmlRequestParams.FEATURE_COUNT = layer.featureinfo.featureCount;
                                }

                                var gmlUrl = layer.getFeatureInfoUrl(
                                    coordinate, viewResolution, view.getProjection().getCode(), gmlRequestParams
                                );
                                if(angular.isDefined(scope.proxyUrl)) {
                                    gmlUrl = scope.proxyUrl + layer.name + '/?' + gmlUrl.split('?')[1];
                                }

                                if(angular.isDefined(gmlUrl)) {
                                    var gmlRequestDeferred = $q.defer();
                                    gmlRequestPromises.push(gmlRequestDeferred.promise);
                                    $http.get(gmlUrl).then(
                                        function(response) {
                                            gmlRequestDeferred.resolve({style: layer.featureinfo.gmlStyle, gmlData: response.data});
                                        },
                                        function() {
                                            gmlRequestDeferred.resolve();
                                        }
                                    );
                                }
                            });
                            requestsDeferred.resolve();
                            gmlRequestsDeferred.resolve();
                        };

                        scope.hideWaitingOverlay = function() {
                            if(angular.isDefined(scope.waitingMarkerSrc)) {
                                scope.waitingOverlay.setPosition(undefined);
                            }
                        };

                        scope.showWaitingOverlay = function(coordinate) {
                            if(angular.isDefined(scope.waitingMarkerSrc)) {
                                scope.waitingOverlay.setPosition(coordinate);
                            }
                        };

                        scope.featureInfoPopupClosed = function() {
                            featureInfoLayer.clear();
                        };
                    },
                    post: function(scope) {
                        var handlerKey;
                        var control = new anol.control.Control({
                            subordinate: true,
                            olControl: null
                        });
                        control.onDeactivate(function() {
                            unByKey(handlerKey);
                        });
                        control.onActivate(function() {
                            handlerKey = scope.map.on('singleclick', scope.handleClick, this);
                        });

                        control.activate();

                        ControlsService.addControl(control);
                    }
                }
            };
        }]);
<commit_msg>add option to load layer from gml via catalogservice<commit_after>import './module.js';
import Overlay from 'ol/Overlay';
import WMSGetFeatureInfo from 'ol/format/WMSGetFeatureInfo';
import VectorLayer from 'ol/layer/Vector';
import { unByKey } from 'ol/Observable';

angular.module('anol.getfeatureinfo')
/**
 * @ngdoc directive
 * @name anol.getfeatureinfo.directive:anolGetFeatureInfo
 *
 * @restrict A
 * @requires $http
 * @required $window
 * @requires anol.map.MapService
 * @requires anol.map.LayersService
 * @requires anol.map.ControlsService
 *
 * @description
 * Makes GetFeatureInfo request on all non vector layers with 'featureinfo' property
 * and show result if not empty depending on 'target' specified in 'featureinfo'
 *
 * @param {function} customTargetFilled Callback called after featureinfo result added to custom element
 * @param {string} templateUrl Url to template to use instead of default one
 * @param {function} beforeRequest Callback called before featureinfo requests are fulfilled
 * @param {string} proxyUrl Url for proxy to use for requests.
                            When proxyUrl is used, name of requested anol layer
 *                          is appended as path to proxyUrl. E.g.: proxyUrl = '/foo', for layer with name 'bar' requested url is '/foo/bar/'.
 *                          Also only url params are submitted.
 *
 * Layer property **featureinfo** - {Object} - Contains properties:
 * - **target** - {string} - Target for featureinfo result. ('_blank', '_popup', [element-id])
 */
    .directive('anolGetFeatureInfo', [
        '$templateRequest', '$http', '$window', '$q', '$compile', 'MapService', 'LayersService', 'ControlsService', 'CatalogService',
        function($templateRequest, $http, $window, $q, $compile, MapService, LayersService, ControlsService, CatalogService) {
            return {
                restrict: 'A',
                scope: {
                    customTargetFilled: '&',
                    beforeRequest: '&',
                    proxyUrl: '@',
                    popupOpeningDirection: '@',
                    waitingMarkerSrc: '@?',
                    waitingMarkerOffset: '=?',
                    excludeLayers: '=?'
                },
                template: function(tElement, tAttrs) {
                    if (tAttrs.templateUrl) {
                        return '

';
                    }
                    return require('./templates/getfeatureinfo.html');
                },
                link: {
                    pre: function(scope, element, attrs) {
                        if (attrs.templateUrl && attrs.templateUrl !== '') {
                            $templateRequest(attrs.templateUrl).then(function(html){
                                var template = angular.element(html);
                                element.html(template);
                                $compile(template)(scope);
                            });
                        }
                        scope.popupOpeningDirection = scope.popupOpeningDirection || 'top';

                        scope.map = MapService.getMap();
                        // get callback from wrapper function
                        scope.customTargetCallback = scope.customTargetFilled();
                        scope.beforeRequest = scope.beforeRequest();

                        scope.addLayerToMap = function(name) {
                            var layer = CatalogService.layerByName(name);
                            CatalogService.addToMap(layer);
                        };

                        if(angular.isDefined(scope.waitingMarkerSrc)) {
                            scope.waitingOverlayElement = element.find('#get-featureinfo-waiting-overlay');
                            $compile(scope.waitingOverlayElement)(scope);
                            scope.waitingOverlay = new Overlay({
                                element: scope.waitingOverlayElement[0],
                                position: undefined,
                                offset: scope.waitingMarkerOffset
                            });
                            scope.map.addOverlay(scope.waitingOverlay);
                        }
                        var view = scope.map.getView();

                        if(angular.isDefined(scope.proxyUrl)) {
                            if(scope.proxyUrl[scope.proxyUrl.length - 1] !== '/') {
                                scope.proxyUrl += '/';
                            }
                        }

                        var featureInfoLayer = new anol.layer.Feature({
                            name: 'featureInfoLayer',
                            displayInLayerswitcher: false,
                            style: scope.markerStyle
                        });
                        var markerOlLayerOptions = featureInfoLayer.olLayerOptions;
                        markerOlLayerOptions.source = new featureInfoLayer.OL_SOURCE_CLASS(featureInfoLayer.olSourceOptions);
                        markerOlLayerOptions.zIndex = 2001;
                        featureInfoLayer.setOlLayer(new featureInfoLayer.OL_LAYER_CLASS(markerOlLayerOptions));

                        LayersService.addSystemLayer(featureInfoLayer, 0);

                        var handleFeatureinfoResponses = function(featureInfoObjects) {
                            var divTargetCleared = false;
                            var popupContentTemp = $('

');
                            var popupCoordinate;
                            angular.forEach(featureInfoObjects, function(featureInfoObject) {
                                if(angular.isUndefined(featureInfoObject)) {
                                    return;
                                }
                                var iframe;
                                if(featureInfoObject.target === '_popup') {
                                    iframe = $('');
                                }
                                switch(featureInfoObject.target) {
                                case '_blank':
                                    $window.open(featureInfoObject.url, '_blank');
                                    break;
                                case '_popup':
                                    iframe.css('width', featureInfoObject.width || 300);
                                    iframe.css('height', featureInfoObject.height || 150);
                                    popupContentTemp.append(iframe);
                                    popupCoordinate = featureInfoObject.coordinate;
                                    break;
                                default:
                                    var temp = $('

');
                                    var target = angular.element(featureInfoObject.target);
                                    if(divTargetCleared === false) {
                                        target.empty();
                                        divTargetCleared = true;
                                    }
                                    var content = angular.element(featureInfoObject.response);
                                    temp.append(content);
                                    temp.find('meta').remove();
                                    temp.find('link').remove();
                                    temp.find('title').remove();
                                    temp.find('script').remove();
                                    target.append(temp.children());
                                    if(angular.isFunction(scope.customTargetCallback)) {
                                        scope.customTargetCallback();
                                    }
                                    break;
                                }
                            });
                            if(angular.isDefined(popupCoordinate)) {
                                scope.popupProperties = {
                                    coordinate: popupCoordinate,
                                    content: popupContentTemp.children()
                                };
                            }
                            scope.hideWaitingOverlay();
                        };

                        var handleGMLFeatureinfoResponses = function(responses) {
                            var format = new WMSGetFeatureInfo();
                            var layers = [];
                            var title;
                            var catalog = false;
                            // add feature to feateinfolayer
                            angular.forEach(responses, function(response) {
                                if(angular.isUndefined(response)) {
                                    return;
                                }
                                if(angular.isUndefined(response.gmlData)) {
                                    return;
                                }
                                var features = format.readFeatures(response.gmlData);
                                angular.forEach(features, function(feature) {
                                    feature.set('style', response.style);
                                    if (response.catalog) {
                                        catalog = true;
                                        layers.push(feature.get('layer'));
                                        title = response.title;
                                    }
                                });
                                featureInfoLayer.addFeatures(features);
                            });

                            if (catalog) {
                                // add layer identifier to popup
                                var popupContentTemp = $('

'+ title +'

');
                                angular.forEach(layers, function(name, idx) {
                                    var layer = $('
'+ name +'
');
                                    popupContentTemp.append(layer);
                                })
                                $compile(popupContentTemp)(scope);

                                scope.popupProperties = {
                                    coordinate: scope.clickedCoordiante,
                                    content: popupContentTemp.children()
                                }
                                scope.hideWaitingOverlay();
                            }
                        };

                        scope.handleClick = function(evt) {
                            var viewResolution = view.getResolution();
                            var coordinate = evt.coordinate;
                            scope.clickedCoordiante = coordinate;
                            scope.popupProperties = {
                                coordinate: undefined
                            };
                            featureInfoLayer.clear();

                            if(angular.isFunction(scope.beforeRequest)) {
                                scope.beforeRequest();
                            }

                            scope.showWaitingOverlay(coordinate);

                            var requestPromises = [];
                            // this is resolved after all requests started
                            var requestsDeferred = $q.defer();
                            requestsDeferred.promise.then(function() {
                                // promises added before requests started
                                // all promises will be resolved, otherwise we can't access the data
                                // promises that should be rejected will be resolved with undefined
                                $q.all(requestPromises).then(handleFeatureinfoResponses);
                            });

                            var gmlRequestPromises = [];
                            var gmlRequestsDeferred = $q.defer();
                            gmlRequestsDeferred.promise.then(function() {
                                $q.all(requestPromises.concat(gmlRequestPromises)).then(handleGMLFeatureinfoResponses);
                            });

                            angular.forEach(LayersService.flattedLayers(), function(layer) {
                                if(!layer.getVisible()) {
                                    return;
                                }
                                if(layer.olLayer instanceof VectorLayer) {
                                    return;
                                }
                                if(!layer.featureinfo) {
                                    return;
                                }

                                if(layer.featureinfo.gml !== true && layer.featureinfo.catalog !== true) {

                                    var requestParams ={
                                        'INFO_FORMAT': 'text/html'
                                    };
                                    if(angular.isDefined(layer.featureinfo.featureCount)) {
                                        requestParams.FEATURE_COUNT = layer.featureinfo.featureCount;
                                    }

                                    var url = layer.getFeatureInfoUrl(
                                        coordinate, viewResolution, view.getProjection().getCode(), requestParams
                                    );
                                    if(angular.isDefined(scope.proxyUrl)) {
                                        url = scope.proxyUrl + layer.name + '/?' + url.split('?')[1];
                                    }
                                    if(angular.isDefined(url)) {
                                        var requestDeferred = $q.defer();
                                        requestPromises.push(requestDeferred.promise);
                                        $http.get(url).then(
                                            function(response) {
                                                if(angular.isString(response.data) && response.data !== '' && response.data.search('^\s*<\?xml') === -1) {
                                                    requestDeferred.resolve({
                                                        target: layer.featureinfo.target,
                                                        width: layer.featureinfo.width,
                                                        height: layer.featureinfo.height,
                                                        url: url,
                                                        response: response.data,
                                                        coordinate: coordinate
                                                    });
                                                } else {
                                                    requestDeferred.resolve();
                                                }
                                            },
                                            function() {
                                                requestDeferred.resolve();
                                            }
                                        );
                                    }
                                    return;
                                }

                                var gmlRequestParams = {
                                    'INFO_FORMAT': 'application/vnd.ogc.gml'
                                };
                                if(angular.isDefined(layer.featureinfo.featureCount)) {
                                    gmlRequestParams.FEATURE_COUNT = layer.featureinfo.featureCount;
                                }

                                var gmlUrl = layer.getFeatureInfoUrl(
                                    coordinate, viewResolution, view.getProjection().getCode(), gmlRequestParams
                                );
                                if(angular.isDefined(scope.proxyUrl)) {
                                    gmlUrl = scope.proxyUrl + layer.name + '/?' + gmlUrl.split('?')[1];
                                }

                                if(angular.isDefined(gmlUrl)) {
                                    var gmlRequestDeferred = $q.defer();
                                    gmlRequestPromises.push(gmlRequestDeferred.promise);
                                    $http.get(gmlUrl).then(
                                        function(response) {
                                            gmlRequestDeferred.resolve({style: layer.featureinfo.gmlStyle, gmlData: response.data, title: layer.title, catalog: layer.featureinfo.catalog});
                                        },
                                        function() {
                                            gmlRequestDeferred.resolve();
                                        }
                                    );
                                }
                            });
                            requestsDeferred.resolve();
                            gmlRequestsDeferred.resolve();
                        };

                        scope.hideWaitingOverlay = function() {
                            if(angular.isDefined(scope.waitingMarkerSrc)) {
                                scope.waitingOverlay.setPosition(undefined);
                            }
                        };

                        scope.showWaitingOverlay = function(coordinate) {
                            if(angular.isDefined(scope.waitingMarkerSrc)) {
                                scope.waitingOverlay.setPosition(coordinate);
                            }
                        };

                        scope.featureInfoPopupClosed = function() {
                            featureInfoLayer.clear();
                        };
                    },
                    post: function(scope) {
                        var handlerKey;
                        var control = new anol.control.Control({
                            subordinate: true,
                            olControl: null
                        });
                        control.onDeactivate(function() {
                            unByKey(handlerKey);
                        });
                        control.onActivate(function() {
                            handlerKey = scope.map.on('singleclick', scope.handleClick, this);
                        });

                        control.activate();

                        ControlsService.addControl(control);
                    }
                }
            };
        }]);
<|endoftext|>


<commit_before>// Generated on 2015-03-16 using
// generator-webapp 0.5.1
'use strict';

// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// If you want to recursively match all subfolders, use:
// 'test/spec/**/*.js'

module.exports = function (grunt) {

  // Time how long tasks take. Can help when optimizing build times
  require('time-grunt')(grunt);

  // Load grunt tasks automatically
  require('load-grunt-tasks')(grunt);

  // Configurable paths
  var config = {
    app: 'app',
    dist: 'dist'
  };

  // Define the configuration for all the tasks
  grunt.initConfig({

    // Project settings
    config: config,

    // Watches files for changes and runs tasks based on the changed files
    watch: {
      bower: {
        files: ['bower.json'],
        tasks: ['wiredep']
      },
      js: {
        files: ['<%= config.app %>/scripts/{,*/}*.js'],
        tasks: ['jshint'],
        options: {
          livereload: true
        }
      },
      jstest: {
        files: ['test/spec/{,*/}*.js'],
        tasks: ['test:watch']
      },
      gruntfile: {
        files: ['Gruntfile.js']
      },
      sass: {
        files: ['<%= config.app %>/styles/{,*/}*.{scss,sass}'],
        tasks: ['sass:server', 'autoprefixer']
      },
      styles: {
        files: ['<%= config.app %>/styles/{,*/}*.css'],
        tasks: ['newer:copy:styles', 'autoprefixer']
      },
      livereload: {
        options: {
          livereload: '<%= connect.options.livereload %>'
        },
        files: [
          '<%= config.app %>/{,*/}*.html',
          '.tmp/styles/{,*/}*.css',
          '<%= config.app %>/images/{,*/}*'
        ]
      }
    },

    // The actual grunt server settings
    connect: {
      options: {
        port: 9000,
        open: true,
        livereload: 35729,
        // Change this to '0.0.0.0' to access the server from outside
        hostname: 'localhost'
      },
      livereload: {
        options: {
          middleware: function(connect) {
            return [
              connect.static('.tmp'),
              connect().use('/bower_components', connect.static('./bower_components')),
              connect.static(config.app)
            ];
          }
        }
      },
      test: {
        options: {
          open: false,
          port: 9001,
          middleware: function(connect) {
            return [
              connect.static('.tmp'),
              connect.static('test'),
              connect().use('/bower_components', connect.static('./bower_components')),
              connect.static(config.app)
            ];
          }
        }
      },
      dist: {
        options: {
          base: '<%= config.dist %>',
          livereload: false
        }
      }
    },

    // Empties folders to start fresh
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            '.tmp',
            '<%= config.dist %>/*',
            '!<%= config.dist %>/.git*'
          ]
        }]
      },
      server: '.tmp'
    },

    // Make sure code styles are up to par and there are no obvious mistakes
    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: [
        'Gruntfile.js',
        '<%= config.app %>/scripts/{,*/}*.js',
        '!<%= config.app %>/scripts/vendor/*',
        'test/spec/{,*/}*.js'
      ]
    },

    // Mocha testing framework configuration options
    mocha: {
      all: {
        options: {
          run: true,
          urls: ['http://<%= connect.test.options.hostname %>:<%= connect.test.options.port %>/index.html']
        }
      }
    },

    // Compiles Sass to CSS and generates necessary files if requested
    sass: {
      options: {
        loadPath: 'bower_components'
      },
      dist: {
        files: [{
          expand: true,
          cwd: '<%= config.app %>/styles',
          src: ['*.{scss,sass}'],
          dest: '.tmp/styles',
          ext: '.css'
        }]
      },
      server: {
        files: [{
          expand: true,
          cwd: '<%= config.app %>/styles',
          src: ['*.{scss,sass}'],
          dest: '.tmp/styles',
          ext: '.css'
        }]
      }
    },

    // Add vendor prefixed styles
    autoprefixer: {
      options: {
        browsers: ['> 1%', 'last 2 versions', 'Firefox ESR', 'Opera 12.1']
      },
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/styles/',
          src: '{,*/}*.css',
          dest: '.tmp/styles/'
        }]
      }
    },

    // Automatically inject Bower components into the HTML file
    wiredep: {
      app: {
        ignorePath: /^\/|\.\.\//,
        src: ['<%= config.app %>/index.html']
      },
      sass: {
        src: ['<%= config.app %>/styles/{,*/}*.{scss,sass}'],
        ignorePath: /(\.\.\/){1,2}bower_components\//
      }
    },

    // Renames files for browser caching purposes
    rev: {
      dist: {
        files: {
          src: [
            '<%= config.dist %>/scripts/{,*/}*.js',
            '<%= config.dist %>/styles/{,*/}*.css',
            '<%= config.dist %>/images/{,*/}*.*',
            '<%= config.dist %>/styles/fonts/{,*/}*.*',
            '<%= config.dist %>/*.{ico,png}'
          ]
        }
      }
    },

    // Reads HTML for usemin blocks to enable smart builds that automatically
    // concat, minify and revision files. Creates configurations in memory so
    // additional tasks can operate on them
    useminPrepare: {
      options: {
        dest: '<%= config.dist %>'
      },
      html: '<%= config.app %>/index.html'
    },

    // Performs rewrites based on rev and the useminPrepare configuration
    usemin: {
      options: {
        assetsDirs: [
          '<%= config.dist %>',
          '<%= config.dist %>/images',
          '<%= config.dist %>/styles'
        ]
      },
      html: ['<%= config.dist %>/{,*/}*.html'],
      css: ['<%= config.dist %>/styles/{,*/}*.css']
    },

    // The following *-min tasks produce minified files in the dist folder
    imagemin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= config.app %>/images',
          src: '{,*/}*.{gif,jpeg,jpg,png}',
          dest: '<%= config.dist %>/images'
        }]
      }
    },

    svgmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= config.app %>/images',
          src: '{,*/}*.svg',
          dest: '<%= config.dist %>/images'
        }]
      }
    },

    htmlmin: {
      dist: {
        options: {
          collapseBooleanAttributes: true,
          collapseWhitespace: true,
          conservativeCollapse: true,
          removeAttributeQuotes: true,
          removeCommentsFromCDATA: true,
          removeEmptyAttributes: true,
          removeOptionalTags: true,
          removeRedundantAttributes: true,
          useShortDoctype: true
        },
        files: [{
          expand: true,
          cwd: '<%= config.dist %>',
          src: '{,*/}*.html',
          dest: '<%= config.dist %>'
        }]
      }
    },

    // By default, your `index.html`'s <!-- Usemin block --> will take care
    // of minification. These next options are pre-configured if you do not
    // wish to use the Usemin blocks.
    // cssmin: {
    //   dist: {
    //     files: {
    //       '<%= config.dist %>/styles/main.css': [
    //         '.tmp/styles/{,*/}*.css',
    //         '<%= config.app %>/styles/{,*/}*.css'
    //       ]
    //     }
    //   }
    // },
    // uglify: {
    //   dist: {
    //     files: {
    //       '<%= config.dist %>/scripts/scripts.js': [
    //         '<%= config.dist %>/scripts/scripts.js'
    //       ]
    //     }
    //   }
    // },
    // concat: {
    //   dist: {}
    // },

    // Copies remaining files to places other tasks can use
    copy: {
      dist: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= config.app %>',
          dest: '<%= config.dist %>',
          src: [
            '*.{ico,png,txt}',
            'images/{,*/}*.webp',
            '{,*/}*.html',
            'styles/fonts/{,*/}*.*'
          ]
        }, {
          src: 'node_modules/apache-server-configs/dist/.htaccess',
          dest: '<%= config.dist %>/.htaccess'
        }]
      },
      styles: {
        expand: true,
        dot: true,
        cwd: '<%= config.app %>/styles',
        dest: '.tmp/styles/',
        src: '{,*/}*.css'
      }
    },

    // Run some tasks in parallel to speed up build process
    concurrent: {
      server: [
        'sass:server',
        'copy:styles'
      ],
      test: [
        'copy:styles'
      ],
      dist: [
        'sass',
        'copy:styles',
        'imagemin',
        'svgmin'
      ]
    }
  });

  grunt.registerTask('serve', 'start the server and preview your app, --allow-remote for remote access', function (target) {
    if (grunt.option('allow-remote')) {
      grunt.config.set('connect.options.hostname', '0.0.0.0');
    }
    if (target === 'dist') {
      return grunt.task.run(['build', 'connect:dist:keepalive']);
    }

    grunt.task.run([
      'clean:server',
      'wiredep',
      'concurrent:server',
      'autoprefixer',
      'connect:livereload',
      'watch'
    ]);
  });

  grunt.registerTask('server', function (target) {
    grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
    grunt.task.run([target ? ('serve:' + target) : 'serve']);
  });

  grunt.registerTask('test', function (target) {
    if (target !== 'watch') {
      grunt.task.run([
        'clean:server',
        'concurrent:test',
        'autoprefixer'
      ]);
    }

    grunt.task.run([
      'connect:test',
      'mocha'
    ]);
  });

  grunt.registerTask('build', [
    'clean:dist',
    'wiredep',
    'useminPrepare',
    'concurrent:dist',
    'autoprefixer',
    'concat',
    'cssmin',
    'uglify',
    'copy:dist',
    'rev',
    'usemin',
    'htmlmin'
  ]);

  grunt.registerTask('default', [
    'newer:jshint',
    'test',
    'build'
  ]);
};
<commit_msg>Added task to copy fonts/ and source/<commit_after>// Generated on 2015-03-16 using
// generator-webapp 0.5.1
'use strict';

// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// If you want to recursively match all subfolders, use:
// 'test/spec/**/*.js'

module.exports = function (grunt) {

  // Time how long tasks take. Can help when optimizing build times
  require('time-grunt')(grunt);

  // Load grunt tasks automatically
  require('load-grunt-tasks')(grunt);

  // Configurable paths
  var config = {
    app: 'app',
    dist: 'dist'
  };

  // Define the configuration for all the tasks
  grunt.initConfig({

    // Project settings
    config: config,

    // Watches files for changes and runs tasks based on the changed files
    watch: {
      bower: {
        files: ['bower.json'],
        tasks: ['wiredep']
      },
      js: {
        files: ['<%= config.app %>/scripts/{,*/}*.js'],
        tasks: ['jshint'],
        options: {
          livereload: true
        }
      },
      jstest: {
        files: ['test/spec/{,*/}*.js'],
        tasks: ['test:watch']
      },
      gruntfile: {
        files: ['Gruntfile.js']
      },
      sass: {
        files: ['<%= config.app %>/styles/{,*/}*.{scss,sass}'],
        tasks: ['sass:server', 'autoprefixer']
      },
      styles: {
        files: ['<%= config.app %>/styles/{,*/}*.css'],
        tasks: ['newer:copy:styles', 'autoprefixer']
      },
      livereload: {
        options: {
          livereload: '<%= connect.options.livereload %>'
        },
        files: [
          '<%= config.app %>/{,*/}*.html',
          '.tmp/styles/{,*/}*.css',
          '<%= config.app %>/images/{,*/}*'
        ]
      }
    },

    // The actual grunt server settings
    connect: {
      options: {
        port: 9000,
        open: true,
        livereload: 35729,
        // Change this to '0.0.0.0' to access the server from outside
        hostname: 'localhost'
      },
      livereload: {
        options: {
          middleware: function(connect) {
            return [
              connect.static('.tmp'),
              connect().use('/bower_components', connect.static('./bower_components')),
              connect.static(config.app)
            ];
          }
        }
      },
      test: {
        options: {
          open: false,
          port: 9001,
          middleware: function(connect) {
            return [
              connect.static('.tmp'),
              connect.static('test'),
              connect().use('/bower_components', connect.static('./bower_components')),
              connect.static(config.app)
            ];
          }
        }
      },
      dist: {
        options: {
          base: '<%= config.dist %>',
          livereload: false
        }
      }
    },

    // Empties folders to start fresh
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            '.tmp',
            '<%= config.dist %>/*',
            '!<%= config.dist %>/.git*'
          ]
        }]
      },
      server: '.tmp'
    },

    // Make sure code styles are up to par and there are no obvious mistakes
    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: [
        'Gruntfile.js',
        '<%= config.app %>/scripts/{,*/}*.js',
        '!<%= config.app %>/scripts/vendor/*',
        'test/spec/{,*/}*.js'
      ]
    },

    // Mocha testing framework configuration options
    mocha: {
      all: {
        options: {
          run: true,
          urls: ['http://<%= connect.test.options.hostname %>:<%= connect.test.options.port %>/index.html']
        }
      }
    },

    // Compiles Sass to CSS and generates necessary files if requested
    sass: {
      options: {
        loadPath: 'bower_components'
      },
      dist: {
        files: [{
          expand: true,
          cwd: '<%= config.app %>/styles',
          src: ['*.{scss,sass}'],
          dest: '.tmp/styles',
          ext: '.css'
        }]
      },
      server: {
        files: [{
          expand: true,
          cwd: '<%= config.app %>/styles',
          src: ['*.{scss,sass}'],
          dest: '.tmp/styles',
          ext: '.css'
        }]
      }
    },

    // Add vendor prefixed styles
    autoprefixer: {
      options: {
        browsers: ['> 1%', 'last 2 versions', 'Firefox ESR', 'Opera 12.1']
      },
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/styles/',
          src: '{,*/}*.css',
          dest: '.tmp/styles/'
        }]
      }
    },

    // Automatically inject Bower components into the HTML file
    wiredep: {
      app: {
        ignorePath: /^\/|\.\.\//,
        src: ['<%= config.app %>/index.html']
      },
      sass: {
        src: ['<%= config.app %>/styles/{,*/}*.{scss,sass}'],
        ignorePath: /(\.\.\/){1,2}bower_components\//
      }
    },

    // Renames files for browser caching purposes
    rev: {
      dist: {
        files: {
          src: [
            '<%= config.dist %>/scripts/{,*/}*.js',
            '<%= config.dist %>/styles/{,*/}*.css',
            '<%= config.dist %>/images/{,*/}*.*',
            '<%= config.dist %>/styles/fonts/{,*/}*.*',
            '<%= config.dist %>/*.{ico,png}'
          ]
        }
      }
    },

    // Reads HTML for usemin blocks to enable smart builds that automatically
    // concat, minify and revision files. Creates configurations in memory so
    // additional tasks can operate on them
    useminPrepare: {
      options: {
        dest: '<%= config.dist %>'
      },
      html: '<%= config.app %>/index.html'
    },

    // Performs rewrites based on rev and the useminPrepare configuration
    usemin: {
      options: {
        assetsDirs: [
          '<%= config.dist %>',
          '<%= config.dist %>/images',
          '<%= config.dist %>/styles'
        ]
      },
      html: ['<%= config.dist %>/{,*/}*.html'],
      css: ['<%= config.dist %>/styles/{,*/}*.css']
    },

    // The following *-min tasks produce minified files in the dist folder
    imagemin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= config.app %>/images',
          src: '{,*/}*.{gif,jpeg,jpg,png}',
          dest: '<%= config.dist %>/images'
        }]
      }
    },

    svgmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= config.app %>/images',
          src: '{,*/}*.svg',
          dest: '<%= config.dist %>/images'
        }]
      }
    },

    htmlmin: {
      dist: {
        options: {
          collapseBooleanAttributes: true,
          collapseWhitespace: true,
          conservativeCollapse: true,
          removeAttributeQuotes: true,
          removeCommentsFromCDATA: true,
          removeEmptyAttributes: true,
          removeOptionalTags: true,
          removeRedundantAttributes: true,
          useShortDoctype: true
        },
        files: [{
          expand: true,
          cwd: '<%= config.dist %>',
          src: '{,*/}*.html',
          dest: '<%= config.dist %>'
        }]
      }
    },

    // By default, your `index.html`'s <!-- Usemin block --> will take care
    // of minification. These next options are pre-configured if you do not
    // wish to use the Usemin blocks.
    // cssmin: {
    //   dist: {
    //     files: {
    //       '<%= config.dist %>/styles/main.css': [
    //         '.tmp/styles/{,*/}*.css',
    //         '<%= config.app %>/styles/{,*/}*.css'
    //       ]
    //     }
    //   }
    // },
    // uglify: {
    //   dist: {
    //     files: {
    //       '<%= config.dist %>/scripts/scripts.js': [
    //         '<%= config.dist %>/scripts/scripts.js'
    //       ]
    //     }
    //   }
    // },
    // concat: {
    //   dist: {}
    // },

    // Copies remaining files to places other tasks can use
    copy: {
      dist: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= config.app %>',
          dest: '<%= config.dist %>',
          src: [
            '*.{ico,png,txt}',
            'images/{,*/}*.webp',
            '{,*/}*.html',
            '{,*/}*.json',
            'styles/fonts/{,*/}*.*'
          ]
        }, {
          src: 'node_modules/apache-server-configs/dist/.htaccess',
          dest: '<%= config.dist %>/.htaccess'
        },{
          expand: true,
          filter: 'isFile',
          flatten: true,
          src : 'bower_components/font-awesome/fonts/{,*/}*.*',
          dest : '<%= config.dist %>/fonts/'
        }]
      },
      styles: {
        expand: true,
        dot: true,
        cwd: '<%= config.app %>/styles',
        dest: '.tmp/styles/',
        src: '{,*/}*.css'
      }
    },

    // Run some tasks in parallel to speed up build process
    concurrent: {
      server: [
        'sass:server',
        'copy:styles'
      ],
      test: [
        'copy:styles'
      ],
      dist: [
        'sass',
        'copy:styles',
        'imagemin',
        'svgmin'
      ]
    }
  });

  grunt.registerTask('serve', 'start the server and preview your app, --allow-remote for remote access', function (target) {
    if (grunt.option('allow-remote')) {
      grunt.config.set('connect.options.hostname', '0.0.0.0');
    }
    if (target === 'dist') {
      return grunt.task.run(['build', 'connect:dist:keepalive']);
    }

    grunt.task.run([
      'clean:server',
      'wiredep',
      'concurrent:server',
      'autoprefixer',
      'connect:livereload',
      'watch'
    ]);
  });

  grunt.registerTask('server', function (target) {
    grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
    grunt.task.run([target ? ('serve:' + target) : 'serve']);
  });

  grunt.registerTask('test', function (target) {
    if (target !== 'watch') {
      grunt.task.run([
        'clean:server',
        'concurrent:test',
        'autoprefixer'
      ]);
    }

    grunt.task.run([
      'connect:test',
      'mocha'
    ]);
  });

  grunt.registerTask('build', [
    'clean:dist',
    'wiredep',
    'useminPrepare',
    'concurrent:dist',
    'autoprefixer',
    'concat',
    'cssmin',
    'uglify',
    'copy:dist',
    'rev',
    'usemin',
    'htmlmin'
  ]);

  grunt.registerTask('default', [
    'newer:jshint',
    'test',
    'build'
  ]);
};
<|endoftext|>