<commit_before>/**
 * @overview tests for ccm component for rendering a quiz
 * @author André Kless <andre.kless@web.de> 2017
 * @license The MIT License (MIT)
 */

ccm.files[ 'ccm.quiz.tests.js' ] = {
  setup: function ( suite, callback ) {
    suite.container = document.createElement( 'div' );
    document.body.appendChild( suite.container );
    suite.ccm.component( './../../ccm-components/quiz/ccm.quiz.js', { element: suite.container }, function ( component ) {
      suite.component = component;
      callback();
    } );
  },
  fundamental: {
    setup: function ( suite, callback ) {
      suite.component.instance( function ( instance ) {
        suite.instance = instance;
        callback();
      } );
    },
    tests: {
      componentName: function ( suite ) {
        suite.assertSame( 'quiz', suite.instance.component.name );
      },
      frameworkVersion: function ( suite ) {
        suite.assertEquals( '8.0.0', suite.instance.ccm.version() );
      },
      publicProperties: function ( suite ) {
        suite.assertEquals( [ 'start', 'ccm', 'element', 'id', 'index', 'component' ], Object.keys( suite.instance ) );
      },
      startCallback: function ( suite ) {
        suite.instance.start( suite.passed );
      },
      componentTag: function ( suite ) {
        suite.container.innerHTML = '<ccm-quiz></ccm-quiz>';
        suite.passed();
      }
    }
  },
  uniform_data_structure: {
    tests: {
      singleQuestion: function ( suite ) {
        suite.component.start( {
          questions: {},
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {
              suite.assertSame( 1, results.data.questions.length );
            }
          } ]
        } );
      },
      defaultsByConfig: function ( suite ) {
        suite.component.start( {
          text: true, description: true, answers: true, input: true, attributes: true, swap: true, encode: true, random: true, feedback: true, correct: true,
          questions: {},
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {

              var data = results.data;
              if ( data.text        ) return suite.failed( 'text property not deleted' );
              if ( data.description ) return suite.failed( 'description property not deleted' );
              if ( data.answers     ) return suite.failed( 'answers property not deleted' );
              if ( data.input       ) return suite.failed( 'input property not deleted' );
              if ( data.attributes  ) return suite.failed( 'attributes property not deleted' );
              if ( data.swap        ) return suite.failed( 'swap property not deleted' );
              if ( data.encode      ) return suite.failed( 'encode property not deleted' );
              if ( data.random      ) return suite.failed( 'random property not deleted' );
              if ( data.feedback    ) return suite.failed( 'feedback property not deleted' );
              if ( data.correct     ) return suite.failed( 'correct property not deleted' );

              var question = data.questions[ 0 ];
              if ( !question.text        ) return suite.failed( 'missing text property' );
              if ( !question.description ) return suite.failed( 'missing description property' );
              if ( !question.answers     ) return suite.failed( 'missing answers property' );
              if ( !question.input       ) return suite.failed( 'missing input property' );
              if ( !question.random      ) return suite.failed( 'missing random property' );
              if ( !question.feedback    ) return suite.failed( 'missing feedback property' );
              if ( !question.correct     ) return suite.failed( 'missing correct property' );

              var answer = question.answers[ 0 ];
              if ( !answer.attributes  ) return suite.failed( 'missing attributes property' );
              if ( !answer.swap        ) return suite.failed( 'missing swap property' );
              if ( !answer.encode      ) return suite.failed( 'missing encode property' );

              suite.passed();
            }
          } ]
        } );
      },
      defaultInput: function ( suite ) {
        suite.component.start( {
          questions: {},
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {
              suite.assertSame( 'checkbox', results.data.questions[ 0 ].input );
            }
          } ]
        } );
      },
      singleAnswer: function ( suite ) {
        suite.component.start( {
          questions: { answers: {} },
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {
              suite.assertSame( 1, results.data.questions[ 0 ].answers.length );
            }
          } ]
        } );
      },
      stringAnswers: function ( suite ) {
        suite.component.start( {
          questions: { answers: [ 'foo', {}, 'bar' ] },
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {
              suite.assertEquals( [ { text: 'foo' }, {}, { text: 'bar' } ], results.data.questions[ 0 ].answers );
            }
          } ]
        } );
      },
      singleCorrectNumber: function ( suite ) {
        suite.component.start( {
          questions: { answers: [ '', '', '' ], correct: 1 },
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {
              suite.assertEquals( [ false, true, false ], results.data.questions[ 0 ].correct );
            }
          } ]
        } );
      },
      fillUpValue: function ( suite ) {
        suite.component.start( {
          questions: { input: 'number', answers: [ '', '', '' ], correct: 5711 },
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {
              suite.assertEquals( [ 5711, '', '' ], results.data.questions[ 0 ].correct );
            }
          } ]
        } );
      },
      defaultsByQuestion: function ( suite ) {
        suite.component.start( {
          questions: {
            text: '',
            attributes: true, swap: true, encode: true,
            answers: ''
          },
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {

              var question = results.data.questions[ 0 ];
              if ( question.attributes ) return suite.failed( 'attributes property not deleted' );
              if ( question.swap       ) return suite.failed( 'swap property not deleted' );

              var answer = question.answers[ 0 ];
              if ( !answer.attributes  ) return suite.failed( 'missing attributes property' );
              if ( !answer.swap        ) return suite.failed( 'missing swap property' );
              if ( !answer.encode      ) return suite.failed( 'missing encode property' );

              suite.passed();
            }
          } ]
        } );
      }
    }
  },
  config: {
    tests: {
      logStartEvent: function ( suite ) {
        suite.component.start( {
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {
              if ( results.event !== 'start' ) return suite.failed( 'wrong event' );
              suite.assertEquals( [ 'questions', 'html_templates', 'css_layout', 'placeholder' ], Object.keys( results.data ) );
            }
          } ]
        } );
      },
      oneQuestionOneButton: function ( suite ) {
        suite.component.start( function ( instance ) {
          var buttons = instance.element.querySelectorAll( 'button' );
          if ( buttons.length !== 1 ) return suite.failed( 'not one button' );
          suite.assertSame( 'Finish', buttons[ 0 ].innerHTML );
        } );
      },
      logFinishEvent: function ( suite ) {
        suite.component.start( {
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            events: { finish: true },
            onfinish: function ( instance, results ) {
              suite.assertSame( 'finish', results.event );
            }
          } ]
        }, function ( instance ) {
          instance.element.querySelector( 'button' ).click();
        } );
      },
      loggedInUser: function ( suite ) {
        suite.component.start( {
          user: [ 'ccm.instance', './../../ccm-components/user/ccm.user.js' ],
          onfinish: function ( instance ) {
            suite.assertTrue( instance.user.isLoggedIn() );
          }
        }, function ( instance ) {
          if ( instance.user.isLoggedIn() ) suite.failed( 'user is already logged in' );
          instance.element.querySelector( 'button' ).click();
        } );
      }
    }
  },
  templates: {
    setup: function ( suite, callback ) {
      suite.component.start( { questions: [ {}, {} ] }, function ( instance ) {
        suite.instance = instance;
        callback();
      } );
    },
    tests: {
      main: function ( suite ) {
        if ( !suite.instance.element.querySelector( '#questions' ) ) return suite.failed( 'missing "questions" container' );
        if ( !suite.instance.element.querySelector( '#prev' ) ) return suite.failed( 'missing "prev" container' );
        if ( !suite.instance.element.querySelector( '#next' ) ) return suite.failed( 'missing "next" container' );
        if ( !suite.instance.element.querySelector( '#finish' ) ) return suite.failed( 'missing "finish" container' );
        suite.passed();
      }
    }
  },
  finally: function ( suite, callback ) {
    document.body.removeChild( suite.container );
    callback();
  }
};

ccm.components.testsuite.quiz = ccm.files[ 'ccm.quiz.tests.js' ];<commit_msg>add unit test for ccm.quiz.js<commit_after>/**
 * @overview tests for ccm component for rendering a quiz
 * @author André Kless <andre.kless@web.de> 2017
 * @license The MIT License (MIT)
 */

ccm.files[ 'ccm.quiz.tests.js' ] = {
  setup: function ( suite, callback ) {
    suite.container = document.createElement( 'div' );
    document.body.appendChild( suite.container );
    suite.ccm.component( './../../ccm-components/quiz/ccm.quiz.js', { element: suite.container }, function ( component ) {
      suite.component = component;
      callback();
    } );
  },
  fundamental: {
    setup: function ( suite, callback ) {
      suite.component.instance( function ( instance ) {
        suite.instance = instance;
        callback();
      } );
    },
    tests: {
      componentName: function ( suite ) {
        suite.assertSame( 'quiz', suite.instance.component.name );
      },
      frameworkVersion: function ( suite ) {
        suite.assertEquals( '8.0.0', suite.instance.ccm.version() );
      },
      publicProperties: function ( suite ) {
        suite.assertEquals( [ 'start', 'ccm', 'element', 'id', 'index', 'component' ], Object.keys( suite.instance ) );
      },
      startCallback: function ( suite ) {
        suite.instance.start( suite.passed );
      },
      componentTag: function ( suite ) {
        suite.container.innerHTML = '<ccm-quiz></ccm-quiz>';
        suite.passed();
      }
    }
  },
  uniform_data_structure: {
    tests: {
      singleQuestion: function ( suite ) {
        suite.component.start( {
          questions: {},
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {
              suite.assertSame( 1, results.data.questions.length );
            }
          } ]
        } );
      },
      defaultsByConfig: function ( suite ) {
        suite.component.start( {
          text: true, description: true, answers: true, input: true, attributes: true, swap: true, encode: true, random: true, feedback: true, correct: true,
          questions: {},
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {

              var data = results.data;
              if ( data.text        ) return suite.failed( 'text property not deleted' );
              if ( data.description ) return suite.failed( 'description property not deleted' );
              if ( data.answers     ) return suite.failed( 'answers property not deleted' );
              if ( data.input       ) return suite.failed( 'input property not deleted' );
              if ( data.attributes  ) return suite.failed( 'attributes property not deleted' );
              if ( data.swap        ) return suite.failed( 'swap property not deleted' );
              if ( data.encode      ) return suite.failed( 'encode property not deleted' );
              if ( data.random      ) return suite.failed( 'random property not deleted' );
              if ( data.feedback    ) return suite.failed( 'feedback property not deleted' );
              if ( data.correct     ) return suite.failed( 'correct property not deleted' );

              var question = data.questions[ 0 ];
              if ( !question.text        ) return suite.failed( 'missing text property' );
              if ( !question.description ) return suite.failed( 'missing description property' );
              if ( !question.answers     ) return suite.failed( 'missing answers property' );
              if ( !question.input       ) return suite.failed( 'missing input property' );
              if ( !question.random      ) return suite.failed( 'missing random property' );
              if ( !question.feedback    ) return suite.failed( 'missing feedback property' );
              if ( !question.correct     ) return suite.failed( 'missing correct property' );

              var answer = question.answers[ 0 ];
              if ( !answer.attributes  ) return suite.failed( 'missing attributes property' );
              if ( !answer.swap        ) return suite.failed( 'missing swap property' );
              if ( !answer.encode      ) return suite.failed( 'missing encode property' );

              suite.passed();
            }
          } ]
        } );
      },
      defaultInput: function ( suite ) {
        suite.component.start( {
          questions: {},
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {
              suite.assertSame( 'checkbox', results.data.questions[ 0 ].input );
            }
          } ]
        } );
      },
      singleAnswer: function ( suite ) {
        suite.component.start( {
          questions: { answers: {} },
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {
              suite.assertSame( 1, results.data.questions[ 0 ].answers.length );
            }
          } ]
        } );
      },
      stringAnswers: function ( suite ) {
        suite.component.start( {
          questions: { answers: [ 'foo', {}, 'bar' ] },
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {
              suite.assertEquals( [ { text: 'foo' }, {}, { text: 'bar' } ], results.data.questions[ 0 ].answers );
            }
          } ]
        } );
      },
      singleCorrectNumber: function ( suite ) {
        suite.component.start( {
          questions: { answers: [ '', '', '' ], correct: 1 },
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {
              suite.assertEquals( [ false, true, false ], results.data.questions[ 0 ].correct );
            }
          } ]
        } );
      },
      fillUpValue: function ( suite ) {
        suite.component.start( {
          questions: { input: 'number', answers: [ '', '', '' ], correct: 5711 },
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {
              suite.assertEquals( [ 5711, '', '' ], results.data.questions[ 0 ].correct );
            }
          } ]
        } );
      },
      defaultsByQuestion: function ( suite ) {
        suite.component.start( {
          questions: {
            text: '',
            attributes: true, swap: true, encode: true,
            answers: ''
          },
          logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
            logging: { data: true },
            onfinish: function ( instance, results ) {

              var question = results.data.questions[ 0 ];
              if ( question.attributes ) return suite.failed( 'attributes property not deleted' );
              if ( question.swap       ) return suite.failed( 'swap property not deleted' );

              var answer = question.answers[ 0 ];
              if ( !answer.attributes  ) return suite.failed( 'missing attributes property' );
              if ( !answer.swap        ) return suite.failed( 'missing swap property' );
              if ( !answer.encode      ) return suite.failed( 'missing encode property' );

              suite.passed();
            }
          } ]
        } );
      }
    }
  },
  config: {
    logger: {
      tests: {
        start: function ( suite ) {
          suite.component.start( {
            logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
              logging: { data: true },
              onfinish: function ( instance, results ) {
                if ( results.event !== 'start' ) return suite.failed( 'wrong event' );
                suite.assertEquals( [ 'questions', 'html_templates', 'css_layout', 'placeholder' ], Object.keys( results.data ) );
              }
            } ]
          } );
        },
        finish: function ( suite ) {
          suite.component.start( {
            logger: [ 'ccm.instance', './../../ccm-components/log/ccm.log.js', {
              events: { finish: true },
              onfinish: function ( instance, results ) {
                suite.assertSame( 'finish', results.event );
              }
            } ]
          }, function ( instance ) {
            instance.element.querySelector( 'button' ).click();
          } );
        }
      }
    },
    tests: {
      oneQuestion: function ( suite ) {
        suite.component.start( function ( instance ) {
          var buttons = instance.element.querySelectorAll( 'button' );
          if ( buttons.length !== 1 ) return suite.failed( 'not one button' );
          suite.assertSame( 'Finish', buttons[ 0 ].innerHTML );
        } );
      },
      shuffle: function ( suite ) {
        suite.component.instance( {
          questions: [ { text: 'foo' }, { text: 'bar' } ],
          shuffle: true
        }, function ( instance ) {
          var i = 0;
          start();
          function start() {
            i++;
            instance.start( function () {
              if ( instance.element.querySelectorAll( '.title' )[ 0 ].children[ 2 ].innerHTML === 'bar' )
                return suite.passed();
              else if ( i < 10 )
                start();
              else
                return suite.failed( 'same order' );
            } );
          }
        } );
      },
      loggedInUser: function ( suite ) {
        suite.component.start( {
          user: [ 'ccm.instance', './../../ccm-components/user/ccm.user.js' ],
          onfinish: function ( instance ) {
            suite.assertTrue( instance.user.isLoggedIn() );
          }
        }, function ( instance ) {
          if ( instance.user.isLoggedIn() ) suite.failed( 'user is already logged in' );
          instance.element.querySelector( 'button' ).click();
        } );
      }
    }
  },
  templates: {
    setup: function ( suite, callback ) {
      suite.component.start( { questions: [ {}, {} ] }, function ( instance ) {
        suite.instance = instance;
        callback();
      } );
    },
    tests: {
      main: function ( suite ) {
        if ( !suite.instance.element.querySelector( '#questions' ) ) return suite.failed( 'missing "questions" container' );
        if ( !suite.instance.element.querySelector( '#prev' ) ) return suite.failed( 'missing "prev" container' );
        if ( !suite.instance.element.querySelector( '#next' ) ) return suite.failed( 'missing "next" container' );
        if ( !suite.instance.element.querySelector( '#finish' ) ) return suite.failed( 'missing "finish" container' );
        suite.passed();
      }
    }
  },
  finally: function ( suite, callback ) {
    document.body.removeChild( suite.container );
    callback();
  }
};

ccm.components.testsuite.quiz = ccm.files[ 'ccm.quiz.tests.js' ];<|endoftext|>


<commit_before>import L from 'leaflet'

import LayerFactory from 'leaflet-coverage'
import {getLayerClass} from 'leaflet-coverage'
import ParameterSync from 'leaflet-coverage/renderers/ParameterSync.js'
import CoverageLegend from 'leaflet-coverage/controls/Legend.js'
import TimeAxis from 'leaflet-coverage/controls/TimeAxis.js'
import ProfilePlot from 'leaflet-coverage/popups/VerticalProfilePlot.js'

import {default as Action, VIEW} from './Action.js'
import {i18n, COVJSON_PREFIX} from '../util.js'
import SelectControl from './SelectControl.js'

const PROFILE_COLLECTION = COVJSON_PREFIX + 'VerticalProfileCoverageCollection'
const POINT_COLLECTION = COVJSON_PREFIX + 'PointCoverageCollection'

/**
 * Displays geospatial coverages on a map.
 */
export default class GeoCoverageView extends Action {
  constructor (data, context) {
    super(context)
    this.cov = data

    this._setHidden()

    this.layers = []
  }

  _setVisible () {
    this.visible = true
    this.label = 'Hide'
    this.icon = ''
    this.fire('labelChange')
  }

  _setHidden () {
    this.visible = false
    this.label = 'View'
    this.icon = ''
    this.fire('labelChange')
  }

  get isSupported () {
    if (this.cov.coverages && this.cov.coverages.length > 1) {
      // limited collection support
      if (this.cov.profiles.indexOf(PROFILE_COLLECTION) !== -1 || this.cov.profiles.indexOf(POINT_COLLECTION) !== -1) {
        // only support collections with root-level parameters (where we then assume a uniform collection)
        if (!this.cov.parameters) {
          return false
        }
      } else {
        return false
      }
    }
    let cov = this.cov
    if (cov.coverages) {
      cov = cov.coverages[0]
    }
    if (!getLayerClass(cov)) {
      return false
    }

    return true
  }

  run () {
    let map = this.context.map

    let dataset = this.context.dataset
    let datasetTitle = i18n(dataset.title)

    if (this.visible) {
      this.remove()
      this._setHidden()
      return
    }

    this._setVisible()

    let cov = this.cov
    if (cov.coverages && cov.coverages.length === 1) {
      cov = cov.coverages[0]
    }

    let formatLabel = this.context.distribution.formatImpl.shortLabel
    let layerNamePrefix = '' + formatLabel + ' '

    this.paramSync = new ParameterSync({
      syncProperties: {
        palette: (p1, p2) => p1,
        paletteExtent: (e1, e2) => e1 && e2 ? [Math.min(e1[0], e2[0]), Math.max(e1[1], e2[1])] : null
      }
    }).on('parameterAdd', e => {
        // The virtual sync layer proxies the synced palette, paletteExtent, and parameter.
        // The sync layer will fire a 'remove' event if all real layers for that parameter were removed.
        let layer = e.syncLayer
        if (layer.palette) {
          CoverageLegend(layer, {
            position: 'bottomright'
          }).addTo(map)
        }
      })

    // each parameter becomes a layer
    for (let key of cov.parameters.keys()) {
      let opts = {keys: [key]}
      let layerName = i18n(cov.parameters.get(key).observedProperty.label)
      let fullLayerName = layerNamePrefix + layerName
      let layer
      if (cov.coverages) {
        let layers = cov.coverages.map(coverage => this._createLayer(coverage, opts, true))
        // TODO this should be more clever and be oriented towards uniform collections
        //     then it would make sense to expose properties like palette etc.
        layer = L.layerGroup(layers)
      } else {
        layer = this._createLayer(cov, opts)
      }
      map.layerControl.addOverlay(
          layer, fullLayerName, {groupName: datasetTitle, expanded: true})
      this.layers.push(layer)
    }

    // display the first layer
    let firstLayer = this.layers[0]
    map.addLayer(firstLayer)
  }

  _createLayer (cov, opts, inCollection) {
    let map = this.context.map
    let layer = LayerFactory()(cov, opts)
      .on('add', e => {
        let covLayer = e.target

        // This registers the layer with the sync manager.
        // By doing that, the palette and extent get unified (if existing)
        // and an event gets fired if a new parameter was added.
        // See the code above where ParameterSync gets instantiated.
        this.paramSync.addLayer(covLayer)

        if (inCollection) {
          // we could display a time range control for filtering the displayed collection items
          // same for vertical axis where in addition a target value could be chosen
        } else {
          if (covLayer.timeSlices) {
            new TimeAxis(covLayer).addTo(map)
          }

          if (covLayer.verticalSlices) {
            let choices = covLayer.verticalSlices.map(val => ({
              value: val,
              label: val
            }))
            new SelectControl(covLayer, choices, {title: 'Vertical axis'})
              .on('change', event => {
                let vertical = parseFloat(event.value)
                covLayer.vertical = vertical
              })
              .addTo(map)
          }
        }
      })
      .on('dataLoading', () => this.fire('loading'))
      .on('dataLoad', () => this.fire('load'))

    // TODO use full URI
    if (cov.domainProfiles.some(p => p.endsWith('VerticalProfile'))) {
      // we do that outside of the above 'add' handler since we want to register only once,
      // not every time the layer is added to the map
      layer.on('click', () => new ProfilePlot(cov, opts).addTo(map))
    }
    return layer
  }

  remove () {
    let map = this.context.map

    for (let layer of this.layers) {
      if (map.hasLayer(layer)) {
        map.removeLayer(layer)
      }
      map.layerControl.removeLayer(layer)
    }
    this.layers = []
  }
}

GeoCoverageView.type = VIEW
<commit_msg>fix import after refactoring of leaflet-coverage<commit_after>import L from 'leaflet'

import LayerFactory from 'leaflet-coverage'
import {getLayerClass} from 'leaflet-coverage'
import ParameterSync from 'leaflet-coverage/layers/ParameterSync.js'
import CoverageLegend from 'leaflet-coverage/controls/Legend.js'
import TimeAxis from 'leaflet-coverage/controls/TimeAxis.js'
import ProfilePlot from 'leaflet-coverage/popups/VerticalProfilePlot.js'

import {default as Action, VIEW} from './Action.js'
import {i18n, COVJSON_PREFIX} from '../util.js'
import SelectControl from './SelectControl.js'

const PROFILE_COLLECTION = COVJSON_PREFIX + 'VerticalProfileCoverageCollection'
const POINT_COLLECTION = COVJSON_PREFIX + 'PointCoverageCollection'

/**
 * Displays geospatial coverages on a map.
 */
export default class GeoCoverageView extends Action {
  constructor (data, context) {
    super(context)
    this.cov = data

    this._setHidden()

    this.layers = []
  }

  _setVisible () {
    this.visible = true
    this.label = 'Hide'
    this.icon = ''
    this.fire('labelChange')
  }

  _setHidden () {
    this.visible = false
    this.label = 'View'
    this.icon = ''
    this.fire('labelChange')
  }

  get isSupported () {
    if (this.cov.coverages && this.cov.coverages.length > 1) {
      // limited collection support
      if (this.cov.profiles.indexOf(PROFILE_COLLECTION) !== -1 || this.cov.profiles.indexOf(POINT_COLLECTION) !== -1) {
        // only support collections with root-level parameters (where we then assume a uniform collection)
        if (!this.cov.parameters) {
          return false
        }
      } else {
        return false
      }
    }
    let cov = this.cov
    if (cov.coverages) {
      cov = cov.coverages[0]
    }
    if (!getLayerClass(cov)) {
      return false
    }

    return true
  }

  run () {
    let map = this.context.map

    let dataset = this.context.dataset
    let datasetTitle = i18n(dataset.title)

    if (this.visible) {
      this.remove()
      this._setHidden()
      return
    }

    this._setVisible()

    let cov = this.cov
    if (cov.coverages && cov.coverages.length === 1) {
      cov = cov.coverages[0]
    }

    let formatLabel = this.context.distribution.formatImpl.shortLabel
    let layerNamePrefix = '' + formatLabel + ' '

    this.paramSync = new ParameterSync({
      syncProperties: {
        palette: (p1, p2) => p1,
        paletteExtent: (e1, e2) => e1 && e2 ? [Math.min(e1[0], e2[0]), Math.max(e1[1], e2[1])] : null
      }
    }).on('parameterAdd', e => {
        // The virtual sync layer proxies the synced palette, paletteExtent, and parameter.
        // The sync layer will fire a 'remove' event if all real layers for that parameter were removed.
        let layer = e.syncLayer
        if (layer.palette) {
          CoverageLegend(layer, {
            position: 'bottomright'
          }).addTo(map)
        }
      })

    // each parameter becomes a layer
    for (let key of cov.parameters.keys()) {
      let opts = {keys: [key]}
      let layerName = i18n(cov.parameters.get(key).observedProperty.label)
      let fullLayerName = layerNamePrefix + layerName
      let layer
      if (cov.coverages) {
        let layers = cov.coverages.map(coverage => this._createLayer(coverage, opts, true))
        // TODO this should be more clever and be oriented towards uniform collections
        //     then it would make sense to expose properties like palette etc.
        layer = L.layerGroup(layers)
      } else {
        layer = this._createLayer(cov, opts)
      }
      map.layerControl.addOverlay(
          layer, fullLayerName, {groupName: datasetTitle, expanded: true})
      this.layers.push(layer)
    }

    // display the first layer
    let firstLayer = this.layers[0]
    map.addLayer(firstLayer)
  }

  _createLayer (cov, opts, inCollection) {
    let map = this.context.map
    let layer = LayerFactory()(cov, opts)
      .on('add', e => {
        let covLayer = e.target

        // This registers the layer with the sync manager.
        // By doing that, the palette and extent get unified (if existing)
        // and an event gets fired if a new parameter was added.
        // See the code above where ParameterSync gets instantiated.
        this.paramSync.addLayer(covLayer)

        if (inCollection) {
          // we could display a time range control for filtering the displayed collection items
          // same for vertical axis where in addition a target value could be chosen
        } else {
          if (covLayer.timeSlices) {
            let timeAxis = new TimeAxis(covLayer)
            timeAxis.addTo(map)
          }

          if (covLayer.verticalSlices) {
            let choices = covLayer.verticalSlices.map(val => ({
              value: val,
              label: val
            }))
            new SelectControl(covLayer, choices, {title: 'Vertical axis'})
              .on('change', event => {
                let vertical = parseFloat(event.value)
                covLayer.vertical = vertical
              })
              .addTo(map)
          }
        }
      })
      .on('dataLoading', () => this.fire('loading'))
      .on('dataLoad', () => this.fire('load'))

    // TODO use full URI
    if (cov.domainProfiles.some(p => p.endsWith('VerticalProfile'))) {
      // we do that outside of the above 'add' handler since we want to register only once,
      // not every time the layer is added to the map
      layer.on('click', () => new ProfilePlot(cov, opts).addTo(map))
    }
    return layer
  }

  remove () {
    let map = this.context.map

    for (let layer of this.layers) {
      if (map.hasLayer(layer)) {
        map.removeLayer(layer)
      }
      map.layerControl.removeLayer(layer)
    }
    this.layers = []
  }
}

GeoCoverageView.type = VIEW
<|endoftext|>


<commit_before>$.noty.themes.material = {
    name: "material",
    modal: {
        css: {
            position: "fixed",
            width: "100%",
            height: "100%",
            backgroundColor: "#000",
            zIndex: 10000,
            opacity: 0.6,
            display: "none",
            left: 0,
            top: 0
        }
    },
    style: function() {
        this.$bar.css({
            overflow: "hidden",
            boxShadow: "0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23)"
        });

        this.$message.css({
            fontFamily: "'Roboto', sans-serif",
            fontSize: "17px",
            textAlign: "center",
            padding: "1em 1.5em",
            width: "auto",
            position: "relative",

            display: "flex",
            alignItems: "center"
        });

        this.$closeButton.css({
            position: "absolute",
            top: 4, right: 4,
            width: 10, height: 10,
            background: "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAQAAAAnOwc2AAAAxUlEQVR4AR3MPUoDURSA0e++uSkkOxC3IAOWNtaCIDaChfgXBMEZbQRByxCwk+BasgQRZLSYoLgDQbARxry8nyumPcVRKDfd0Aa8AsgDv1zp6pYd5jWOwhvebRTbzNNEw5BSsIpsj/kurQBnmk7sIFcCF5yyZPDRG6trQhujXYosaFoc+2f1MJ89uc76IND6F9BvlXUdpb6xwD2+4q3me3bysiHvtLYrUJto7PD/ve7LNHxSg/woN2kSz4txasBdhyiz3ugPGetTjm3XRokAAAAASUVORK5CYII=)",
            display: "none",
            cursor: "pointer"
        });

        this.$buttons.css({
            padding: 5,
            textAlign: "right",
            borderTop: "1px solid #CCCCCC",
            backgroundColor: "#FFFFFF"
        });

        this.$buttons.find("button").css({
            marginLeft: 5
        });

        this.$buttons.find("button:first").css({
            marginLeft: 0
        });

        this.$bar.on({
            mouseenter: function() {
                $(this).find(".noty_close").stop().fadeTo("normal", 1);
            },
            mouseleave: function() {
                $(this).find(".noty_close").stop().fadeTo("normal", 0);
            }
        });

        switch(this.options.layout.name) {
            case "top":
                this.$bar.css({
                    borderRadius: "0px 0px 4px 4px",
                });
                break;
            case "topCenter":
            case "center":
            case "bottomCenter":
            case "inline":
                this.$bar.css({
                    borderRadius: "4px",
                });
                this.$message.css({ textAlign: "center" });
                break;
            case "topLeft":
            case "topRight":
            case "bottomLeft":
            case "bottomRight":
            case "centerLeft":
            case "centerRight":
                this.$bar.css({
                    borderRadius: "4px",
                });
                this.$message.css({ textAlign: "left" });
                break;
            case "bottom":
                this.$bar.css({
                    borderRadius: "4px 4px 0px 0px",
                    boxShadow: "box-shadow: 0 -3px 6px rgba(0, 0, 0, 0.16), 0 -3px 6px rgba(0, 0, 0, 0.23)"
                });
                break;
            default:
                this.$bar.css({
                });
                break;
        }

        switch(this.options.type) {
            case "alert":
            case "notification":
                this.$bar.css({ backgroundColor: "#323232", color: "#FFFFFF" });
                break;
            case "warning":
                this.$bar.css({ backgroundColor: "#FF9800", color: "#000000" });
                this.$buttons.css({borderTop: "1px solid #FFC237"});
                break;
            case "error":
                this.$bar.css({ backgroundColor: "#F44336", color: "#FFFFFF" });
                this.$message.css({ fontWeight: "bold" });
                this.$buttons.css({ borderTop: "1px solid darkred" });
                break;
            case "information":
                this.$bar.css({ backgroundColor: "#90CAF9", color: "#000000" });
                this.$buttons.css({borderTop: "1px solid #0B90C4"});
                break;
            case "success":
                this.$bar.css({ backgroundColor: "#8BC34A", color: "#000000" });
                this.$buttons.css({borderTop: "1px solid #50C24E"});
                break;
            default:
                this.$bar.css({ backgroundColor: "rgb(33, 33, 33)", color: "#FFFFFF" });
                break;
        }
    },
    callback: {
        onShow: function() {},
        onClose: function() {}
    }
};
<commit_msg>Use Catamaran in toasts to conform with rest of app<commit_after>$.noty.themes.material = {
    name: "material",
    modal: {
        css: {
            position: "fixed",
            width: "100%",
            height: "100%",
            backgroundColor: "#000",
            zIndex: 10000,
            opacity: 0.6,
            display: "none",
            left: 0,
            top: 0
        }
    },
    style: function() {
        this.$bar.css({
            overflow: "hidden",
            boxShadow: "0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23)"
        });

        this.$message.css({
            fontFamily: '"Catamaran", "Noto Sans", "Noto Sans CJK SC", "Noto Sans CJK TC", "Noto Sans CJK KR", "Noto Sans CJK JP", sans-serif',
            fontSize: "17px",
            textAlign: "center",
            padding: "1em 1.5em",
            width: "auto",
            position: "relative",

            display: "flex",
            alignItems: "center"
        });

        this.$closeButton.css({
            position: "absolute",
            top: 4, right: 4,
            width: 10, height: 10,
            background: "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAQAAAAnOwc2AAAAxUlEQVR4AR3MPUoDURSA0e++uSkkOxC3IAOWNtaCIDaChfgXBMEZbQRByxCwk+BasgQRZLSYoLgDQbARxry8nyumPcVRKDfd0Aa8AsgDv1zp6pYd5jWOwhvebRTbzNNEw5BSsIpsj/kurQBnmk7sIFcCF5yyZPDRG6trQhujXYosaFoc+2f1MJ89uc76IND6F9BvlXUdpb6xwD2+4q3me3bysiHvtLYrUJto7PD/ve7LNHxSg/woN2kSz4txasBdhyiz3ugPGetTjm3XRokAAAAASUVORK5CYII=)",
            display: "none",
            cursor: "pointer"
        });

        this.$buttons.css({
            padding: 5,
            textAlign: "right",
            borderTop: "1px solid #CCCCCC",
            backgroundColor: "#FFFFFF"
        });

        this.$buttons.find("button").css({
            marginLeft: 5
        });

        this.$buttons.find("button:first").css({
            marginLeft: 0
        });

        this.$bar.on({
            mouseenter: function() {
                $(this).find(".noty_close").stop().fadeTo("normal", 1);
            },
            mouseleave: function() {
                $(this).find(".noty_close").stop().fadeTo("normal", 0);
            }
        });

        switch(this.options.layout.name) {
            case "top":
                this.$bar.css({
                    borderRadius: "0px 0px 4px 4px",
                });
                break;
            case "topCenter":
            case "center":
            case "bottomCenter":
            case "inline":
                this.$bar.css({
                    borderRadius: "4px",
                });
                this.$message.css({ textAlign: "center" });
                break;
            case "topLeft":
            case "topRight":
            case "bottomLeft":
            case "bottomRight":
            case "centerLeft":
            case "centerRight":
                this.$bar.css({
                    borderRadius: "4px",
                });
                this.$message.css({ textAlign: "left" });
                break;
            case "bottom":
                this.$bar.css({
                    borderRadius: "4px 4px 0px 0px",
                    boxShadow: "box-shadow: 0 -3px 6px rgba(0, 0, 0, 0.16), 0 -3px 6px rgba(0, 0, 0, 0.23)"
                });
                break;
            default:
                this.$bar.css({
                });
                break;
        }

        switch(this.options.type) {
            case "alert":
            case "notification":
                this.$bar.css({ backgroundColor: "#323232", color: "#FFFFFF" });
                break;
            case "warning":
                this.$bar.css({ backgroundColor: "#FF9800", color: "#000000" });
                this.$buttons.css({borderTop: "1px solid #FFC237"});
                break;
            case "error":
                this.$bar.css({ backgroundColor: "#F44336", color: "#FFFFFF" });
                this.$message.css({ fontWeight: "bold" });
                this.$buttons.css({ borderTop: "1px solid darkred" });
                break;
            case "information":
                this.$bar.css({ backgroundColor: "#90CAF9", color: "#000000" });
                this.$buttons.css({borderTop: "1px solid #0B90C4"});
                break;
            case "success":
                this.$bar.css({ backgroundColor: "#8BC34A", color: "#000000" });
                this.$buttons.css({borderTop: "1px solid #50C24E"});
                break;
            default:
                this.$bar.css({ backgroundColor: "rgb(33, 33, 33)", color: "#FFFFFF" });
                break;
        }
    },
    callback: {
        onShow: function() {},
        onClose: function() {}
    }
};
<|endoftext|>


<commit_before>DateInputBehavior = Behavior.create({

  initialize: function(options) {
    this.element.setAttribute("autocomplete", "off");
    this.calendar = null;
    this.options = Object.extend(DateInputBehavior.DEFAULTS, options || {});
    this.date = this.getDate();
    this._createCalendar();
  },

  setDate: function(value, hideCalendar) {
    this.date = value;
    this.element.value = this.options.setter(this.date);
    var timeoutTime = 250;
    if (Prototype.Browser.IE) timeoutTime = 50;

    if (hideCalendar == null) hideCalendar = true;

    if (hideCalendar && this.calendar) {
      setTimeout(function() {
        this.calendar.element.hide();
        this.element.select();
      }.bind(this), timeoutTime);
    }
    this.element.fire('date:changed');
  },

  _createCalendar : function() {
    var calendar = $div({'class': 'calendar_popup'});
    var body = $(document.getElementsByTagName('body')[0]);
    body.insert(calendar);
    calendar.setStyle('position: absolute');
    this.calendar = new DateInputBehavior.Calendar(calendar, this);
  },

  onclick : function(event) {
    if (this._isOverWidget(event)) {
      this.calendar.toggle();
      event.stop();
    }
  },

  onmouseover: function(event) {
    if (this._isOverWidget(event)) this.element.setStyle("cursor: pointer");
    else this.element.setStyle("cursor: text");
  },

  onmouseout: function(event) {
    if (this._isOverWidget(event)) this.element.setStyle("cursor: text");
    else this.element.setStyle("cursor: pointer");
  },

  onmousemove: function(event) {
    this.onmouseover(event);
  },

  onkeypress: function(event) {
    switch(event.keyCode) {
      case Event.KEY_UP:
      case 38:
      case Event.KEY_DOWN:
      case 63233:
      case 40:
        this.calendar.toggle();
        event.stop();
        break;
      case Event.KEY_ESC:
        this.calendar.hide();
        break;
      case Event.KEY_TAB:
        this.calendar.hide();
        event.stop();
        var formElements = this.element.up('form').getElements();
        var elementIndex = formElements.indexOf(this.element) + 1;
        if (formElements.length > elementIndex) formElements[elementIndex].focus();
        break;
    }
  },

  onkeydown: function(event) {
    if (Prototype.Browser.IE) this.onkeypress(event);
    if (Prototype.Browser.WebKit && (event.keyCode == 40 || event.keyCode == 38)){
      this.onkeypress(event);
    }
  },

  getDate : function() {
    return this.options.getter(this.element.value) || new Date;
  },

  _isOverWidget: function(event) {
    var positionedOverWidget = null;
    if (Prototype.Browser.IE) {
      var widgetLeft = this.element.cumulativeOffset().left;
      var widgetRight = this.element.cumulativeOffset().left + this.element.getDimensions().width;
      positionedOverWidget = (event.pointerX() >= widgetLeft && event.pointerX() <= widgetRight);
    } else {
      var calendarIconWidth = parseInt(this.element.getStyle('padding-right'));
      var widgetLeft = this.element.cumulativeOffset().left + this.element.getDimensions().width - calendarIconWidth;
      positionedOverWidget = (event.pointerX() >= widgetLeft);
    }
    return positionedOverWidget;
  }
});

DateInputBehavior.Calendar = Behavior.create({

  initialize: function(selector) {
    this.selector = selector;
    this.element.hide();
    Event.observe(document, 'click', this.element.hide.bind(this.element));
  },

  show: function() {
    DateInputBehavior.Calendar.instances.invoke('hide');
    this.date = this.selector.getDate();
    this.redraw();
    this.element.setStyle({
      'top': this.selector.element.cumulativeOffset().top - (this.element.getHeight() + 4) + 'px',
      'left': Math.max(this.selector.element.cumulativeOffset().left + this.selector.element.getWidth() - this.element.getWidth() - 4, this.selector.element.cumulativeOffset().left) + 'px',
      'z-index': 10001
    });
    this.element.show();
    this.active = true;
  },

  hide: function() {
    this.element.hide();
    this.active = false;
  },

  toggle: function() {
    if (this.element.visible()) {
      this.hide();
    } else {
      this.show()
    }
  },

  redraw: function() {
    var oldMonth = this.element.down('select.month');
    if (oldMonth) Event.stopObserving(oldMonth, 'change', oldMonth._monthChanged);

    var oldYear = this.element.down('select.year');
    if (oldYear) Event.stopObserving(oldYear, 'change', oldYear._yearChanged);

    var html = '
' +
               '
' +
               '
' +
               '      ←	' +
               '      ' + this._monthYear() + '	' +
               '      →	' +
               '
' +
               '
' + this._dayRows() + '
' +
               '
' +
               '
' +
               this._buildDateCells() +
               '

';
    this.element.innerHTML = '';
    var table = DOM.Builder.fromHTML(html);
    this.element.insert(table);

    var newMonth = this.element.down('select.month');
    newMonth._monthChanged = this._monthChanged.bindAsEventListener(this);
    Event.observe(newMonth, 'change', newMonth._monthChanged);

    var newYear = this.element.down('select.year');
    newYear._yearChanged = this._yearChanged.bindAsEventListener(this);
    Event.observe(newYear, 'change', newYear._yearChanged);
  },

  onclick: function(event) {
    event.stop();
    if ($(event.target.parentNode).hasClassName('day')) return this._setDate(event.target);
    if ($(event.target.parentNode).hasClassName('back')) return this._backMonth();
    if ($(event.target.parentNode).hasClassName('forward')) return this._forwardMonth();
  },

  _monthChanged: function(event) {
    event.stop();
    return this._selectMonth(event.target);
  },

  _yearChanged: function(event) {
    event.stop();
    return this._selectYear(event.target);
  },

  _setDate: function(source) {
    if (source.innerHTML.strip() != '') {
      this.date.setDate(parseInt(source.innerHTML));
      this.selector.setDate(this.date);
      $A(this.element.getElementsByClassName('selected')).invoke('removeClassName', 'selected');
      source.parentNode.addClassName('selected');
    }
  },

  _backMonth: function() {
    this.date.setMonth(this.date.getMonth() - 1);
    this.redraw();
    return false;
  },

  _forwardMonth: function() {
    this.date.setMonth(this.date.getMonth() + 1);
    this.redraw();
    return false;
  },

  _selectMonth: function(combo) {
    this.date.setMonth(combo.selectedIndex);
    this.selector.setDate(this.date, false);
    this.redraw();
    return false;
  },

  _selectYear: function(combo) {
    var year = parseInt($F(combo))
    this.date.setYear(year);
    this.selector.setDate(this.date, false);
    this.redraw();
    return false;
  },

  _getDateFromSelector: function() {
    this.date = new Date(this.selector.date.getTime());
  },

  _firstDay: function(month, year) {
    return new Date(year, month, 1).getDay();
  },

  _monthLength: function(month, year) {
    var length = DateInputBehavior.Calendar.MONTHS[month].days;
    return (month == 1 && (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))) ? 29 : length;
  },

  _monthYear: function() {
    var currentMonth = this.date.getMonth();
    var currentYear = this.date.getFullYear();
    var todaysYear = (new Date()).getFullYear();
    var html = '';
    html += '<select class="month">';
    DateInputBehavior.Calendar.MONTHS.each(function(month, index) {
      if (index == currentMonth)  {
        html += '<option selected="selected">' + month.label + '</option>';
      } else {
        html += '<option>' + month.label + '</option>';
      }
    });
    html += '</select>';
    if (!(Prototype.Browser.WebKit || Prototype.Browser.MobileSafari)) html += ' ';
    html += '<select class="year">';
    for (var index = todaysYear - 100; index < todaysYear + 50; index++) {
      if (index == currentYear) {
        html += '<option selected="selected">' + index + '</option>';
      } else {
        html += '<option>' + index + '</option>';
      }
    }
    html += '</select>';
    return html;
  },

  _dayRows: function() {
    for (var i = 0, html='', day; day = DateInputBehavior.Calendar.DAYS[i]; i++)
      html += '' + day + '	';
    return html;
  },

  _buildDateCells: function() {
    var month = this.date.getMonth(), year = this.date.getFullYear();
    var day = 1, monthLength = this._monthLength(month, year), firstDay = this._firstDay(month, year);
    var html = '
';

    for (var i = 0; i < 9; i++) {
      for (var j = 0; j <= 6; j++) {

        if (day <= monthLength && (i > 0 || j >= firstDay)) {
          var classes = ['day'];

          if (this._compareDate(new Date, year, month, day)) classes.push('today');
          if (this._compareDate(this.selector.date, year, month, day)) classes.push('selected');

          html += '' +
                  '' + day++ + '' +
                  '	';
        } else html += '	';
      }

      if (day > monthLength) break;
      else html += '

';
    }

    return html + '
';
  },

  _compareDate: function(date, year, month, day) {
    return date.getFullYear() == year &&
           date.getMonth() == month &&
           date.getDate() == day;
  }
});

DateInputBehavior.DEFAULTS = {

  setter: function(date) {
    return  DateInputBehavior.Calendar.MONTHS[date.getMonth()].label +
      ' ' + date.getDate() + ', ' + date.getFullYear();
  },

  getter: function(value) {
    var parsed = Date.parse(value);

    if (!isNaN(parsed)) return new Date(parsed);
    else return null;
  }

};

Object.extend(DateInputBehavior.Calendar, {

  DAYS : $w('S M T W T F S'),

  MONTHS : [
    { label: 'January',   days: 31 },
    { label: 'February',  days: 28 },
    { label: 'March',     days: 31 },
    { label: 'April',     days: 30 },
    { label: 'May',       days: 31 },
    { label: 'June',      days: 30 },
    { label: 'July',      days: 31 },
    { label: 'August',    days: 31 },
    { label: 'September', days: 30 },
    { label: 'October',   days: 31 },
    { label: 'November',  days: 30 },
    { label: 'December',  days: 31 }
  ]

});<commit_msg>updated dateinput.js to calculate proper top offset<commit_after>DateInputBehavior = Behavior.create({

  initialize: function(options) {
    this.element.setAttribute("autocomplete", "off");
    this.calendar = null;
    this.options = Object.extend(DateInputBehavior.DEFAULTS, options || {});
    this.date = this.getDate();
    this._createCalendar();
  },

  setDate: function(value, hideCalendar) {
    this.date = value;
    this.element.value = this.options.setter(this.date);
    var timeoutTime = 250;
    if (Prototype.Browser.IE) timeoutTime = 50;

    if (hideCalendar == null) hideCalendar = true;

    if (hideCalendar && this.calendar) {
      setTimeout(function() {
        this.calendar.element.hide();
        this.element.select();
      }.bind(this), timeoutTime);
    }
    this.element.fire('date:changed');
  },

  _createCalendar : function() {
    var calendar = $div({'class': 'calendar_popup'});
    var body = $(document.getElementsByTagName('body')[0]);
    body.insert(calendar);
    calendar.setStyle('position: absolute');
    this.calendar = new DateInputBehavior.Calendar(calendar, this);
  },

  onclick : function(event) {
    if (this._isOverWidget(event)) {
      this.calendar.toggle();
      event.stop();
    }
  },

  onmouseover: function(event) {
    if (this._isOverWidget(event)) this.element.setStyle("cursor: pointer");
    else this.element.setStyle("cursor: text");
  },

  onmouseout: function(event) {
    if (this._isOverWidget(event)) this.element.setStyle("cursor: text");
    else this.element.setStyle("cursor: pointer");
  },

  onmousemove: function(event) {
    this.onmouseover(event);
  },

  onkeypress: function(event) {
    switch(event.keyCode) {
      case Event.KEY_UP:
      case 38:
      case Event.KEY_DOWN:
      case 63233:
      case 40:
        this.calendar.toggle();
        event.stop();
        break;
      case Event.KEY_ESC:
        this.calendar.hide();
        break;
      case Event.KEY_TAB:
        this.calendar.hide();
        event.stop();
        var formElements = this.element.up('form').getElements();
        var elementIndex = formElements.indexOf(this.element) + 1;
        if (formElements.length > elementIndex) formElements[elementIndex].focus();
        break;
    }
  },

  onkeydown: function(event) {
    if (Prototype.Browser.IE) this.onkeypress(event);
    if (Prototype.Browser.WebKit && (event.keyCode == 40 || event.keyCode == 38)){
      this.onkeypress(event);
    }
  },

  getDate : function() {
    return this.options.getter(this.element.value) || new Date;
  },

  _isOverWidget: function(event) {
    var positionedOverWidget = null;
    if (Prototype.Browser.IE) {
      var widgetLeft = this.element.cumulativeOffset().left;
      var widgetRight = this.element.cumulativeOffset().left + this.element.getDimensions().width;
      positionedOverWidget = (event.pointerX() >= widgetLeft && event.pointerX() <= widgetRight);
    } else {
      var calendarIconWidth = parseInt(this.element.getStyle('padding-right'));
      var widgetLeft = this.element.cumulativeOffset().left + this.element.getDimensions().width - calendarIconWidth;
      positionedOverWidget = (event.pointerX() >= widgetLeft);
    }
    return positionedOverWidget;
  }
});

DateInputBehavior.Calendar = Behavior.create({

  initialize: function(selector) {
    this.selector = selector;
    this.element.hide();
    Event.observe(document, 'click', this.element.hide.bind(this.element));
  },

  show: function() {
    DateInputBehavior.Calendar.instances.invoke('hide');
    this.date = this.selector.getDate();
    this.redraw();
    this.element.setStyle({
      'top': this.vertical_offset(this.selector.element) + 'px',
      'left': Math.max(this.selector.element.cumulativeOffset().left + this.selector.element.getWidth() - this.element.getWidth() - 4, this.selector.element.cumulativeOffset().left) + 'px',
      'z-index': 10001
    });
    this.element.show();
    this.active = true;
  },

  vertical_offset: function(selector){
    default_vertical_offset = this.selector.element.cumulativeOffset().top + this.selector.element.getHeight() + 2;
    this_height = this.element.getHeight();
    if(document.viewport.getHeight() > default_vertical_offset + this_height) {
      top_value = default_vertical_offset;
    } else {
      top_value = (default_vertical_offset - this_height - selector.getHeight() - 6);
    }
    if(top_value < document.viewport.getScrollOffsets().top) {
      top_value = document.viewport.getScrollOffsets().top;
    }
    return top_value;
  },

  hide: function() {
    this.element.hide();
    this.active = false;
  },

  toggle: function() {
    if (this.element.visible()) {
      this.hide();
    } else {
      this.show()
    }
  },

  redraw: function() {
    var oldMonth = this.element.down('select.month');
    if (oldMonth) Event.stopObserving(oldMonth, 'change', oldMonth._monthChanged);

    var oldYear = this.element.down('select.year');
    if (oldYear) Event.stopObserving(oldYear, 'change', oldYear._yearChanged);

    var html = '
' +
               '
' +
               '
' +
               '      ←	' +
               '      ' + this._monthYear() + '	' +
               '      →	' +
               '
' +
               '
' + this._dayRows() + '
' +
               '
' +
               '
' +
               this._buildDateCells() +
               '

';
    this.element.innerHTML = '';
    var table = DOM.Builder.fromHTML(html);
    this.element.insert(table);

    var newMonth = this.element.down('select.month');
    newMonth._monthChanged = this._monthChanged.bindAsEventListener(this);
    Event.observe(newMonth, 'change', newMonth._monthChanged);

    var newYear = this.element.down('select.year');
    newYear._yearChanged = this._yearChanged.bindAsEventListener(this);
    Event.observe(newYear, 'change', newYear._yearChanged);
  },

  onclick: function(event) {
    event.stop();
    if ($(event.target.parentNode).hasClassName('day')) return this._setDate(event.target);
    if ($(event.target.parentNode).hasClassName('back')) return this._backMonth();
    if ($(event.target.parentNode).hasClassName('forward')) return this._forwardMonth();
  },

  _monthChanged: function(event) {
    event.stop();
    return this._selectMonth(event.target);
  },

  _yearChanged: function(event) {
    event.stop();
    return this._selectYear(event.target);
  },

  _setDate: function(source) {
    if (source.innerHTML.strip() != '') {
      this.date.setDate(parseInt(source.innerHTML));
      this.selector.setDate(this.date);
      $A(this.element.getElementsByClassName('selected')).invoke('removeClassName', 'selected');
      source.parentNode.addClassName('selected');
    }
  },

  _backMonth: function() {
    this.date.setMonth(this.date.getMonth() - 1);
    this.redraw();
    return false;
  },

  _forwardMonth: function() {
    this.date.setMonth(this.date.getMonth() + 1);
    this.redraw();
    return false;
  },

  _selectMonth: function(combo) {
    this.date.setMonth(combo.selectedIndex);
    this.selector.setDate(this.date, false);
    this.redraw();
    return false;
  },

  _selectYear: function(combo) {
    var year = parseInt($F(combo))
    this.date.setYear(year);
    this.selector.setDate(this.date, false);
    this.redraw();
    return false;
  },

  _getDateFromSelector: function() {
    this.date = new Date(this.selector.date.getTime());
  },

  _firstDay: function(month, year) {
    return new Date(year, month, 1).getDay();
  },

  _monthLength: function(month, year) {
    var length = DateInputBehavior.Calendar.MONTHS[month].days;
    return (month == 1 && (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0))) ? 29 : length;
  },

  _monthYear: function() {
    var currentMonth = this.date.getMonth();
    var currentYear = this.date.getFullYear();
    var todaysYear = (new Date()).getFullYear();
    var html = '';
    html += '<select class="month">';
    DateInputBehavior.Calendar.MONTHS.each(function(month, index) {
      if (index == currentMonth)  {
        html += '<option selected="selected">' + month.label + '</option>';
      } else {
        html += '<option>' + month.label + '</option>';
      }
    });
    html += '</select>';
    if (!(Prototype.Browser.WebKit || Prototype.Browser.MobileSafari)) html += ' ';
    html += '<select class="year">';
    for (var index = todaysYear - 100; index < todaysYear + 50; index++) {
      if (index == currentYear) {
        html += '<option selected="selected">' + index + '</option>';
      } else {
        html += '<option>' + index + '</option>';
      }
    }
    html += '</select>';
    return html;
  },

  _dayRows: function() {
    for (var i = 0, html='', day; day = DateInputBehavior.Calendar.DAYS[i]; i++)
      html += '' + day + '	';
    return html;
  },

  _buildDateCells: function() {
    var month = this.date.getMonth(), year = this.date.getFullYear();
    var day = 1, monthLength = this._monthLength(month, year), firstDay = this._firstDay(month, year);
    var html = '
';

    for (var i = 0; i < 9; i++) {
      for (var j = 0; j <= 6; j++) {

        if (day <= monthLength && (i > 0 || j >= firstDay)) {
          var classes = ['day'];

          if (this._compareDate(new Date, year, month, day)) classes.push('today');
          if (this._compareDate(this.selector.date, year, month, day)) classes.push('selected');

          html += '' +
                  '' + day++ + '' +
                  '	';
        } else html += '	';
      }

      if (day > monthLength) break;
      else html += '

';
    }

    return html + '
';
  },

  _compareDate: function(date, year, month, day) {
    return date.getFullYear() == year &&
           date.getMonth() == month &&
           date.getDate() == day;
  }
});

DateInputBehavior.DEFAULTS = {

  setter: function(date) {
    return  DateInputBehavior.Calendar.MONTHS[date.getMonth()].label +
      ' ' + date.getDate() + ', ' + date.getFullYear();
  },

  getter: function(value) {
    var parsed = Date.parse(value);

    if (!isNaN(parsed)) return new Date(parsed);
    else return null;
  }

};

Object.extend(DateInputBehavior.Calendar, {

  DAYS : $w('S M T W T F S'),

  MONTHS : [
    { label: 'January',   days: 31 },
    { label: 'February',  days: 28 },
    { label: 'March',     days: 31 },
    { label: 'April',     days: 30 },
    { label: 'May',       days: 31 },
    { label: 'June',      days: 30 },
    { label: 'July',      days: 31 },
    { label: 'August',    days: 31 },
    { label: 'September', days: 30 },
    { label: 'October',   days: 31 },
    { label: 'November',  days: 30 },
    { label: 'December',  days: 31 }
  ]

});<|endoftext|>


<commit_before>
  //var map = null;
  var markers = [];
  var bounds;
  var geocoder;
  var image;
  var globalZindex = 1;
  var po;
  var map;
  var radius = 10, tips = {};
  var layer;
  var tile_url = 'http://ec2-50-16-103-51.compute-1.amazonaws.com/tiles/{X}/{Y}/{Z}/'++'/';
  var map_type;

  function initMap() {
    // Map html and events -> mapElements.js
     createMapElements();
  }

  function showMap() {
    $('div.map_window div.map_curtain').hide();
    $('p.georeferencing').hide();

    if (map==null) {
      po = org.polymaps;
      map = po.map()
          .container(document.getElementById('map').appendChild(po.svg('svg')))
          .center({lon: -1.3183, lat: 29.075})
          .zoom(2)
          .zoomRange([1, 20])
          .add(po.drag())
          .add(po.wheel())
          .add(po.dblclick());

          map.add(po.image()
              .url(po.url("http://{S}tile.cloudmade.com"
              + "/1a1b06b230af4efdbb989ea99e9841af"
              + "/998/256/{Z}/{X}/{Y}.png")
              .hosts(["a.", "b.", "c.", ""])));

          layer = po.image().url(po.url(tile_url + table_name + '/'+map_type+'/?sql='+sql+'&style=' + encodeURIComponent(JSON.stringify(style))));
          map.add(layer);
    } else {
      closeMapElements();
      layer.url(po.url(tile_url + table_name + '/'+ map_type +'/?sql='+sql+'&style=' + encodeURIComponent(JSON.stringify(style))));
    }
  }

  function hideMap() {
    $('div.map_window div.map_curtain').show();
  }

  function refreshLayer(_style) {
    layer.url(po.url(tile_url + table_name + '/'+ map_type +'/?sql='+sql+'&style=' + encodeURIComponent(JSON.stringify(_style))));
    layer.reload();
  }
<commit_msg>user id layers<commit_after>
  //var map = null;
  var markers = [];
  var bounds;
  var geocoder;
  var image;
  var globalZindex = 1;
  var po;
  var map;
  var radius = 10, tips = {};
  var layer;
  var tile_url = 'http://ec2-50-16-103-51.compute-1.amazonaws.com/tiles/{X}/{Y}/{Z}/'+user_id+'/';
  var map_type;

  function initMap() {
    // Map html and events -> mapElements.js
     createMapElements();
  }

  function showMap() {
    $('div.map_window div.map_curtain').hide();
    $('p.georeferencing').hide();

    if (map==null) {
      po = org.polymaps;
      map = po.map()
          .container(document.getElementById('map').appendChild(po.svg('svg')))
          .center({lon: -1.3183, lat: 29.075})
          .zoom(2)
          .zoomRange([1, 20])
          .add(po.drag())
          .add(po.wheel())
          .add(po.dblclick());

          map.add(po.image()
              .url(po.url("http://{S}tile.cloudmade.com"
              + "/1a1b06b230af4efdbb989ea99e9841af"
              + "/998/256/{Z}/{X}/{Y}.png")
              .hosts(["a.", "b.", "c.", ""])));

          layer = po.image().url(po.url(tile_url + table_name + '/'+map_type+'/?sql='+sql+'&style=' + encodeURIComponent(JSON.stringify(style))));
          map.add(layer);
    } else {
      closeMapElements();
      layer.url(po.url(tile_url + table_name + '/'+ map_type +'/?sql='+sql+'&style=' + encodeURIComponent(JSON.stringify(style))));
    }
  }

  function hideMap() {
    $('div.map_window div.map_curtain').show();
  }

  function refreshLayer(_style) {
    layer.url(po.url(tile_url + table_name + '/'+ map_type +'/?sql='+sql+'&style=' + encodeURIComponent(JSON.stringify(_style))));
    layer.reload();
  }
<|endoftext|>


<commit_before>var sAlert = require("sweetalert");

angular.module('courseReg', [])
    .controller('CoureRegController', ['$scope', '$http', function($scope, $http){
        $scope.courseRegList;

        /*Listener to button clicks*/
        var clickListener = function(e)
        {
            /*If send email button was clicked, use the API of emailJS to send
            * email to a specific email we configured before.
            * email sended to - sitjce@gmail.com*/

            if(e.target.id == "sendEmail")
            {
                /*First, we need to get list of courses that the user chose
                * in the checkboxes*/
                var i;
                /* getting an array of checkboxes from the html*/
                var checkboxArray = $('.checkbox');
                var chosenCourses = new Array(); // filling this string array with the names
                for(i=0; i<$scope.courseRegList.length; i++)
                {
                    if(checkboxArray[i].checked == true) // if checkbox set to true
                    {
                        chosenCourses.push(checkboxArray[i].defaultValue); // save course name
                    }
                }

                emailjs.send("gmail","regCourse",{
                    name:$("#username").val(),
                    email:$("#email").val(),
                    tel:$("#tel").val(),
                    course:chosenCourses,
                    notes:$("#notes").val()
                }).then(
                    function(response) {
                        sAlert.swal("המייל נשלח בהצלחה");
                    },
                    function(error) {
                        sAlert.swal("נכשל");
                    }
                );
            }
        }

        $scope.loadCourseReg = function()
        {
            $http.get('/course')
                .success(function(res){
                    $scope.courseRegList = res;
                    $("#sendEmail").click(clickListener);
                    console.log($scope.courseRegList);
                })
                .catch(function(err) {
                    console.log('Get courses error.');
                });
        };
        $scope.loadCourseReg();
    }]);<commit_msg>minor changes<commit_after>var sAlert = require("sweetalert");

angular.module('courseReg', [])
    .controller('CoureRegController', ['$scope', '$http', function($scope, $http){
        $scope.courseRegList;

        /*Listener to button clicks*/
        var clickListener = function(e)
        {
            /*If send email button was clicked, use the API of emailJS to send
            * email to a specific email we configured before.
            * email sended to - sitjce@gmail.com*/

            if(e.target.id == "sendEmail")
            {
                /*First, we need to get list of courses that the user chose
                * in the checkboxes*/
                var i;
                /* getting an array of checkboxes from the html*/
                var checkboxArray = $('.checkbox');
                var chosenCourses = new Array(); // filling this string array with the names
                for(i=0; i<$scope.courseRegList.length; i++)
                {
                    if(checkboxArray[i].checked == true) // if checkbox set to true
                    {
                        chosenCourses.push(checkboxArray[i].defaultValue); // save course name
                    }
                }
                sAlert.swal("המייל נשלח בהצלחה");
                emailjs.send("gmail","regCourse",{
                    name:$("#username").val(),
                    email:$("#email").val(),
                    tel:$("#tel").val(),
                    course:chosenCourses,
                    notes:$("#notes").val()
                }).then(
                    function(response) {
                        sAlert.swal("המייל נשלח בהצלחה");
                    },
                    function(error) {
                        sAlert.swal("נכשל");
                    }
                );
            }
        }

        $scope.loadCourseReg = function()
        {
            $http.get('/course')
                .success(function(res){
                    $scope.courseRegList = res;
                    $("#sendEmail").click(clickListener);
                    console.log($scope.courseRegList);
                })
                .catch(function(err) {
                    console.log('Get courses error.');
                });
        };
        $scope.loadCourseReg();
    }]);<|endoftext|>


<commit_before>'use strict';

app.service('baLocation', ['$q', 'baLibraryStore', function($q, baLibraryStore) {
  var location = {
    lat: null,
    lng: null,
    timeFetched: null
  };
  var explicitLoc = null;

  var geocoder = null;

  var maxCacheAge = 60 * 5;
  var promiseQueue = [];
  var state = {
    fetching: false,
    q: {
      cacheValid: function() {
        return location.timeFetched && (moment.utc().valueOf() - location.timeFetched) > maxCacheAge;
      },
      geolocationEnabled: function() {
        return "geolocation" in navigator;
      }
    }
  };

  function initialize() {
    // Make sure the Google Places API is loaded before continueing.
    baLibraryStore.load('googleplaces')
      .then(function() {
        geocoder = new google.maps.Geocoder;

        // This is called just to get the current position in the cache.
        // Allows the request to move quicker if the user clicks the
        // 'current position' button.
        console.log('Initializing Position');
        fetchPosition();
      }, function(response) {
        console.log('Failed to load the Google Places API.', response);
      });
  }
  initialize();

  var geocodeCoordinates = function(loc) {
    var deferred = $q.defer();
    var latlng = null;

    // If a location is provided in the params, geocode that.
    if (loc) {
      latlng = loc;
    // If a location is not provided, attempt to use the cached value.
    } else if (state.q.cacheValid()) {
      latlng = location;
    } else {
      deferred.reject('No location to geocode');
    }

    console.log('Geocoding Location', latlng, loc);

    geocoder.geocode({'location': latlng}, function(results, status) {
      if (status === 'OK') {
        deferred.resolve(results[0]);
      } else {
        deferred.reject(status);
      }
    });

    return deferred.promise;
  };

  var setExplicitPosition = function(loc) {
    explicitLoc = loc;
  };

  var setExplicitPositionWithCurrent = function() {
    var deferred = $q.defer();

    fetchPosition()
      .then(function(loc) {
        explicitLoc = loc;
        deferred.resolve(loc);
      }, function(response) {
        console.log('Failed to fetch position', response);
        deferred.reject(response);
      });

    return deferred.promise;
  }

  var fetchPosition = function(skipCache) {
    console.log('Fetching Position');
    var deferred = $q.defer();

    if (!skipCache && state.q.cacheValid()) {
      deferred.resolve(location);
    } else if (state.q.geolocationEnabled() && state.fetching) {
      promiseQueue.push(deferred);
    } else if (state.q.geolocationEnabled() && !state.fetching) {
      state.fetching = true;
      promiseQueue.push(deferred);

      navigator.geolocation.getCurrentPosition(function(position) {
        state.fetching = false;
        var time = moment.utc().valueOf();
        location = {
          lat: position.coords.latitude,
          lng: position.coords.longitude,
          timeFetched: time
        };

        _.forEach(promiseQueue, function(p) {
          console.log(' - Resolving Position');
          p.resolve(location);
        })
      });
    } else {
      console.log('Location is disabled');
      deferred.reject();
    }

    return deferred.promise;
  };

  var fetchPositionGeocode = function() {
    console.log('Fetching Location and Geocode');
    var deferred = $q.defer();

    fetchPosition()
      .then(function(position) {
        console.log();
        geocodeCoordinates(position)
          .then(function(geocode) {
            deferred.resolve(geocode);
          }, function(response) {
            deferred.reject(response);
          });
      }, function(response) {
        console.log('Failed to fetech position with geocode.');
        deferred.reject(response);
      });

    return deferred.promise;
  };

  var fetchExplicitPosition = function() {
    var deferred = $q.defer();

    console.log('CURRENT', explicitLoc);
    if (explicitLoc) {
      deferred.resolve(explicitLoc);
    } else {
      console.log('Explicit Location not set; using GPS location');
      fetchPosition()
        .then(function(loc) {
          explicitLoc = loc;
          deferred.resolve(explicitLoc);
        }, function(response) {
          deferred.reject(response);
        })
    }

    return deferred.promise;
  };

  var fetchExplicitPositionGeocode = function() {
    var deferred = $q.defer();

    fetchExplicitPosition()
      .then(function(position) {
        geocodeCoordinates(explicitLoc)
        .then(function(geocode) {
          deferred.resolve(geocode);
        }, function(response) {
          console.log('Failed to geocode coordinates', response);
          deferred.reject(response);
        });
      }, function(response) {
        console.log('Failed to fetch explicit location', response);
      });

    return deferred.promise;
  };

  var flushCache = function() {
    location = {
      lat: null,
      lng: null,
      timeFetched: null
    };
    state.fetching = false;
  }

  return {
    geocodeCoordinates: geocodeCoordinates,
    setExplicitPosition: setExplicitPosition,
    setExplicitPositionWithCurrent: setExplicitPositionWithCurrent,
    fetchPosition: fetchPosition,
    fetchPositionGeocode: fetchPositionGeocode,
    fetchExplicitPosition: fetchExplicitPosition,
    fetchExplicitPositionGeocode: fetchExplicitPositionGeocode,
    flushCache: flushCache,
    geolocationEnabled: state.q.geolocationEnabled
  };
}]);
<commit_msg>Error message on the geocode function in baLocation<commit_after>'use strict';

app.service('baLocation', ['$q', 'baLibraryStore', function($q, baLibraryStore) {
  var location = {
    lat: null,
    lng: null,
    timeFetched: null
  };
  var explicitLoc = null;

  var geocoder = null;

  var maxCacheAge = 60 * 5;
  var promiseQueue = [];
  var state = {
    fetching: false,
    q: {
      cacheValid: function() {
        return location.timeFetched && (moment.utc().valueOf() - location.timeFetched) > maxCacheAge;
      },
      geolocationEnabled: function() {
        return "geolocation" in navigator;
      }
    }
  };

  function initialize() {
    // Make sure the Google Places API is loaded before continueing.
    baLibraryStore.load('googleplaces')
      .then(function() {
        geocoder = new google.maps.Geocoder;

        // This is called just to get the current position in the cache.
        // Allows the request to move quicker if the user clicks the
        // 'current position' button.
        console.log('Initializing Position');
        fetchPosition();
      }, function(response) {
        console.log('Failed to load the Google Places API.', response);
      });
  }
  initialize();

  var geocodeCoordinates = function(loc) {
    var deferred = $q.defer();
    var latlng = null;

    // If a location is provided in the params, geocode that.
    if (loc) {
      latlng = loc;
    // If a location is not provided, attempt to use the cached value.
    } else if (state.q.cacheValid()) {
      latlng = location;
    } else {
      deferred.reject('No location to geocode');
    }

    console.log('Geocoding Location', latlng, loc);

    geocoder.geocode({'location': latlng}, function(results, status) {
      if (status === 'OK') {
        deferred.resolve(results[0]);
      } else {
        console.log('Failed to geocode', status, latlng);
        deferred.reject(status);
      }
    });

    return deferred.promise;
  };

  var setExplicitPosition = function(loc) {
    explicitLoc = loc;
  };

  var setExplicitPositionWithCurrent = function() {
    var deferred = $q.defer();

    fetchPosition()
      .then(function(loc) {
        explicitLoc = loc;
        deferred.resolve(loc);
      }, function(response) {
        console.log('Failed to fetch position', response);
        deferred.reject(response);
      });

    return deferred.promise;
  }

  var fetchPosition = function(skipCache) {
    console.log('Fetching Position');
    var deferred = $q.defer();

    if (!skipCache && state.q.cacheValid()) {
      deferred.resolve(location);
    } else if (state.q.geolocationEnabled() && state.fetching) {
      promiseQueue.push(deferred);
    } else if (state.q.geolocationEnabled() && !state.fetching) {
      state.fetching = true;
      promiseQueue.push(deferred);

      navigator.geolocation.getCurrentPosition(function(position) {
        state.fetching = false;
        var time = moment.utc().valueOf();
        location = {
          lat: position.coords.latitude,
          lng: position.coords.longitude,
          timeFetched: time
        };

        _.forEach(promiseQueue, function(p) {
          console.log(' - Resolving Position');
          p.resolve(location);
        })
      });
    } else {
      console.log('Location is disabled');
      deferred.reject();
    }

    return deferred.promise;
  };

  var fetchPositionGeocode = function() {
    console.log('Fetching Location and Geocode');
    var deferred = $q.defer();

    fetchPosition()
      .then(function(position) {
        console.log();
        geocodeCoordinates(position)
          .then(function(geocode) {
            deferred.resolve(geocode);
          }, function(response) {
            deferred.reject(response);
          });
      }, function(response) {
        console.log('Failed to fetech position with geocode.');
        deferred.reject(response);
      });

    return deferred.promise;
  };

  var fetchExplicitPosition = function() {
    var deferred = $q.defer();

    console.log('CURRENT', explicitLoc);
    if (explicitLoc) {
      deferred.resolve(explicitLoc);
    } else {
      console.log('Explicit Location not set; using GPS location');
      fetchPosition()
        .then(function(loc) {
          explicitLoc = loc;
          deferred.resolve(explicitLoc);
        }, function(response) {
          deferred.reject(response);
        })
    }

    return deferred.promise;
  };

  var fetchExplicitPositionGeocode = function() {
    var deferred = $q.defer();

    fetchExplicitPosition()
      .then(function(position) {
        geocodeCoordinates(explicitLoc)
        .then(function(geocode) {
          deferred.resolve(geocode);
        }, function(response) {
          console.log('Failed to geocode coordinates', response);
          deferred.reject(response);
        });
      }, function(response) {
        console.log('Failed to fetch explicit location', response);
      });

    return deferred.promise;
  };

  var flushCache = function() {
    location = {
      lat: null,
      lng: null,
      timeFetched: null
    };
    state.fetching = false;
  }

  return {
    geocodeCoordinates: geocodeCoordinates,
    setExplicitPosition: setExplicitPosition,
    setExplicitPositionWithCurrent: setExplicitPositionWithCurrent,
    fetchPosition: fetchPosition,
    fetchPositionGeocode: fetchPositionGeocode,
    fetchExplicitPosition: fetchExplicitPosition,
    fetchExplicitPositionGeocode: fetchExplicitPositionGeocode,
    flushCache: flushCache,
    geolocationEnabled: state.q.geolocationEnabled
  };
}]);
<|endoftext|>