From ef1199167b7075a1911386dcbf09873bdb1dc606 Mon Sep 17 00:00:00 2001 From: Thomas Haddad Date: Tue, 17 Jan 2017 12:03:58 +0100 Subject: JS gardening for itineraries Signed-off-by: Thomas Shawarma Haddad --- .../es6_browserified/itineraries/components/App.js | 8 +- .../itineraries/components/StopPoint.js | 78 ++++++++++++++++++++ .../itineraries/components/StopPointList.js | 36 +++++++++ .../itineraries/components/Todo.js | 78 -------------------- .../itineraries/components/TodoList.js | 36 --------- .../itineraries/containers/AddStopPoint.js | 22 ++++++ .../itineraries/containers/AddTodo.js | 22 ------ .../itineraries/containers/VisibleStopPoints.js | 36 +++++++++ .../itineraries/containers/VisibleTodoList.js | 36 --------- .../es6_browserified/itineraries/index.js | 66 +++++++++++++++++ .../es6_browserified/itineraries/reducers/index.js | 8 +- .../itineraries/reducers/stopPoints.js | 85 ++++++++++++++++++++++ .../es6_browserified/itineraries/reducers/todos.js | 85 ---------------------- .../es6_browserified/itineraries/stop_points.js | 66 ----------------- app/views/routes/_form.html.slim | 2 +- spec/javascripts/itineraries/reducers_spec.js | 2 +- 16 files changed, 333 insertions(+), 333 deletions(-) create mode 100644 app/assets/javascripts/es6_browserified/itineraries/components/StopPoint.js create mode 100644 app/assets/javascripts/es6_browserified/itineraries/components/StopPointList.js delete mode 100644 app/assets/javascripts/es6_browserified/itineraries/components/Todo.js delete mode 100644 app/assets/javascripts/es6_browserified/itineraries/components/TodoList.js create mode 100644 app/assets/javascripts/es6_browserified/itineraries/containers/AddStopPoint.js delete mode 100644 app/assets/javascripts/es6_browserified/itineraries/containers/AddTodo.js create mode 100644 app/assets/javascripts/es6_browserified/itineraries/containers/VisibleStopPoints.js delete mode 100644 app/assets/javascripts/es6_browserified/itineraries/containers/VisibleTodoList.js create mode 100644 app/assets/javascripts/es6_browserified/itineraries/index.js create mode 100644 app/assets/javascripts/es6_browserified/itineraries/reducers/stopPoints.js delete mode 100644 app/assets/javascripts/es6_browserified/itineraries/reducers/todos.js delete mode 100644 app/assets/javascripts/es6_browserified/itineraries/stop_points.js diff --git a/app/assets/javascripts/es6_browserified/itineraries/components/App.js b/app/assets/javascripts/es6_browserified/itineraries/components/App.js index 7488b0b39..c02f9b814 100644 --- a/app/assets/javascripts/es6_browserified/itineraries/components/App.js +++ b/app/assets/javascripts/es6_browserified/itineraries/components/App.js @@ -1,11 +1,11 @@ var React = require('react') -var AddTodo = require('../containers/AddTodo') -var VisibleTodoList = require('../containers/VisibleTodoList') +var AddStopPoint = require('../containers/AddStopPoint') +var VisibleStopPoints = require('../containers/VisibleStopPoints') const App = () => (
- - + +
) diff --git a/app/assets/javascripts/es6_browserified/itineraries/components/StopPoint.js b/app/assets/javascripts/es6_browserified/itineraries/components/StopPoint.js new file mode 100644 index 000000000..30e7387c6 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/itineraries/components/StopPoint.js @@ -0,0 +1,78 @@ +var React = require('react') +var PropTypes = require('react').PropTypes +var BSelect2 = require('./BSelect2') + +const StopPoint = (props) => { + return ( +
+
+
+
+ {props.value.user_objectid} +
+ +
+ + +
+
+ +
+
+ + +
+
+
+
+ + +
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+ ) +} + +StopPoint.propTypes = { + onDeleteClick: PropTypes.func.isRequired, + onMoveUpClick: PropTypes.func.isRequired, + onMoveDownClick: PropTypes.func.isRequired, + onChange: PropTypes.func.isRequired, + onSelectChange: PropTypes.func.isRequired, + first: PropTypes.bool, + last: PropTypes.bool, + index: PropTypes.number, + value: PropTypes.object +} + +module.exports = StopPoint diff --git a/app/assets/javascripts/es6_browserified/itineraries/components/StopPointList.js b/app/assets/javascripts/es6_browserified/itineraries/components/StopPointList.js new file mode 100644 index 000000000..6c1afd48d --- /dev/null +++ b/app/assets/javascripts/es6_browserified/itineraries/components/StopPointList.js @@ -0,0 +1,36 @@ +var React = require('react') +var PropTypes = require('react').PropTypes +var StopPoint = require('./StopPoint') + +const StopPointList = ({ stopPoints, onDeleteClick, onMoveUpClick, onMoveDownClick, onChange, onSelectChange }) => { + return ( +
+ {stopPoints.map((stopPoint, index) => + onDeleteClick(index)} + onMoveUpClick={() => { + onMoveUpClick(index) + }} + onMoveDownClick={() => onMoveDownClick(index)} + onChange={ onChange } + onSelectChange={ (e) => onSelectChange(e, index) } + first={ index === 0 } + last={ index === (stopPoints.length - 1) } + index={ index } + value={ stopPoint } + /> + )} +
+ ) +} + +StopPointList.propTypes = { + stopPoints: PropTypes.array.isRequired, + onDeleteClick: PropTypes.func.isRequired, + onMoveUpClick: PropTypes.func.isRequired, + onMoveDownClick: PropTypes.func.isRequired, + onSelectChange: PropTypes.func.isRequired +} + +module.exports = StopPointList diff --git a/app/assets/javascripts/es6_browserified/itineraries/components/Todo.js b/app/assets/javascripts/es6_browserified/itineraries/components/Todo.js deleted file mode 100644 index f2932ab1d..000000000 --- a/app/assets/javascripts/es6_browserified/itineraries/components/Todo.js +++ /dev/null @@ -1,78 +0,0 @@ -var React = require('react') -var PropTypes = require('react').PropTypes -var BSelect2 = require('./BSelect2') - -const Todo = (props) => { - return ( -
-
-
-
- {props.value.user_objectid} -
- -
- - -
-
- -
-
- - -
-
-
-
- - -
-
- -
-
-
- -
-
- -
-
- -
-
-
-
-
- ) -} - -Todo.propTypes = { - onDeleteClick: PropTypes.func.isRequired, - onMoveUpClick: PropTypes.func.isRequired, - onMoveDownClick: PropTypes.func.isRequired, - onChange: PropTypes.func.isRequired, - onSelectChange: PropTypes.func.isRequired, - first: PropTypes.bool, - last: PropTypes.bool, - index: PropTypes.number, - value: PropTypes.object -} - -module.exports = Todo diff --git a/app/assets/javascripts/es6_browserified/itineraries/components/TodoList.js b/app/assets/javascripts/es6_browserified/itineraries/components/TodoList.js deleted file mode 100644 index 3ea2c90e1..000000000 --- a/app/assets/javascripts/es6_browserified/itineraries/components/TodoList.js +++ /dev/null @@ -1,36 +0,0 @@ -var React = require('react') -var PropTypes = require('react').PropTypes -var Todo = require('./Todo') - -const TodoList = ({ todos, onDeleteClick, onMoveUpClick, onMoveDownClick, onChange, onSelectChange }) => { - return ( -
- {todos.map((todo, index) => - onDeleteClick(index)} - onMoveUpClick={() => { - onMoveUpClick(index) - }} - onMoveDownClick={() => onMoveDownClick(index)} - onChange={ onChange } - onSelectChange={ (e) => onSelectChange(e, index) } - first={ index === 0 } - last={ index === (todos.length - 1) } - index={ index } - value={ todo } - /> - )} -
- ) -} - -TodoList.propTypes = { - todos: PropTypes.array.isRequired, - onDeleteClick: PropTypes.func.isRequired, - onMoveUpClick: PropTypes.func.isRequired, - onMoveDownClick: PropTypes.func.isRequired, - onSelectChange: PropTypes.func.isRequired -} - -module.exports = TodoList diff --git a/app/assets/javascripts/es6_browserified/itineraries/containers/AddStopPoint.js b/app/assets/javascripts/es6_browserified/itineraries/containers/AddStopPoint.js new file mode 100644 index 000000000..6a6489d61 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/itineraries/containers/AddStopPoint.js @@ -0,0 +1,22 @@ +var React = require('react') +var connect = require('react-redux').connect +var actions = require('../actions') + +let AddStopPoint = ({ dispatch }) => { + return ( +
+
{ + e.preventDefault() + dispatch(actions.addStop()) + }}> + + +
+
+ ) +} +AddStopPoint = connect()(AddStopPoint) + +module.exports = AddStopPoint diff --git a/app/assets/javascripts/es6_browserified/itineraries/containers/AddTodo.js b/app/assets/javascripts/es6_browserified/itineraries/containers/AddTodo.js deleted file mode 100644 index d0128f16d..000000000 --- a/app/assets/javascripts/es6_browserified/itineraries/containers/AddTodo.js +++ /dev/null @@ -1,22 +0,0 @@ -var React = require('react') -var connect = require('react-redux').connect -var actions = require('../actions') - -let AddTodo = ({ dispatch }) => { - return ( -
-
{ - e.preventDefault() - dispatch(actions.addStop()) - }}> - - -
-
- ) -} -AddTodo = connect()(AddTodo) - -module.exports = AddTodo diff --git a/app/assets/javascripts/es6_browserified/itineraries/containers/VisibleStopPoints.js b/app/assets/javascripts/es6_browserified/itineraries/containers/VisibleStopPoints.js new file mode 100644 index 000000000..729d27227 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/itineraries/containers/VisibleStopPoints.js @@ -0,0 +1,36 @@ +var actions = require('../actions') +var connect = require('react-redux').connect +var StopPointList = require('../components/StopPointList') + +const mapStateToProps = (state) => { + return { + stopPoints: state.stopPoints + } +} + +const mapDispatchToProps = (dispatch) => { + return { + onDeleteClick: (index) =>{ + dispatch(actions.deleteStop(index)) + }, + onMoveUpClick: (index) =>{ + dispatch(actions.moveStopUp(index)) + }, + onMoveDownClick: (index) =>{ + dispatch(actions.moveStopDown(index)) + }, + onChange: (index, text) =>{ + dispatch(actions.updateInputValue(index, text)) + }, + onSelectChange: (e, index) =>{ + dispatch(actions.updateSelectValue(e, index)) + } + } +} + +const VisibleStopPoints = connect( + mapStateToProps, + mapDispatchToProps +)(StopPointList) + +module.exports = VisibleStopPoints diff --git a/app/assets/javascripts/es6_browserified/itineraries/containers/VisibleTodoList.js b/app/assets/javascripts/es6_browserified/itineraries/containers/VisibleTodoList.js deleted file mode 100644 index 464d6e482..000000000 --- a/app/assets/javascripts/es6_browserified/itineraries/containers/VisibleTodoList.js +++ /dev/null @@ -1,36 +0,0 @@ -var actions = require('../actions') -var connect = require('react-redux').connect -var TodoList = require('../components/TodoList') - -const mapStateToProps = (state) => { - return { - todos: state.todos - } -} - -const mapDispatchToProps = (dispatch) => { - return { - onDeleteClick: (index) =>{ - dispatch(actions.deleteStop(index)) - }, - onMoveUpClick: (index) =>{ - dispatch(actions.moveStopUp(index)) - }, - onMoveDownClick: (index) =>{ - dispatch(actions.moveStopDown(index)) - }, - onChange: (index, text) =>{ - dispatch(actions.updateInputValue(index, text)) - }, - onSelectChange: (e, index) =>{ - dispatch(actions.updateSelectValue(e, index)) - } - } -} - -const VisibleTodoList = connect( - mapStateToProps, - mapDispatchToProps -)(TodoList) - -module.exports = VisibleTodoList diff --git a/app/assets/javascripts/es6_browserified/itineraries/index.js b/app/assets/javascripts/es6_browserified/itineraries/index.js new file mode 100644 index 000000000..16e3bb2c2 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/itineraries/index.js @@ -0,0 +1,66 @@ +var React = require('react') +var render = require('react-dom').render +var Provider = require('react-redux').Provider +var createStore = require('redux').createStore +var reducers = require('./reducers') +var App = require('./components/App') +var addInput = require('./form_helper') + +// logger, DO NOT REMOVE +// var applyMiddleware = require('redux').applyMiddleware +// var createLogger = require('redux-logger') +// var thunkMiddleware = require('redux-thunk').default +// var promise = require('redux-promise') + +const getInitialState = () => { + let state = [] + let datas = JSON.parse(decodeURIComponent(window.itinerary_stop)) + for (let [index, value] of datas.entries()){ + + let fancyText = value.name + if(value.zip_code && value.city_name) + fancyText += ", " + value.zip_code + " " + value.city_name + + state.push({ + stoppoint_id: value.stoppoint_id, + stoparea_id: value.stoparea_id, + user_objectid: value.user_objectid, + index: index, + city_name: value.city_name, + zip_code: value.zip_code, + text: fancyText, + for_boarding: value.for_boarding || "normal", + for_alighting: value.for_alighting || "normal" + }) + } + return state +} + +var initialState = {stopPoints: getInitialState()} +// const loggerMiddleware = createLogger() +let store = createStore( + reducers, + initialState + // applyMiddleware(thunkMiddleware, promise, loggerMiddleware) +) + +render( + + + , + document.getElementById('stop_points') +) + +document.querySelector('input[name=commit]').addEventListener('click', (event)=>{ + let state = store.getState() + for (let [i, stopPoint] of state.stopPoints.entries()){ + if (stopPoint.stoppoint_id == undefined){ + stopPoint.stoppoint_id = "" + } + addInput('id',stopPoint.stoppoint_id, i) + addInput('stop_area_id',stopPoint.stoparea_id, i) + addInput('position',i, i) + addInput('for_boarding',stopPoint.for_boarding, i) + addInput('for_alighting',stopPoint.for_alighting, i) + } +}) diff --git a/app/assets/javascripts/es6_browserified/itineraries/reducers/index.js b/app/assets/javascripts/es6_browserified/itineraries/reducers/index.js index 381b32d8b..446c9ed36 100644 --- a/app/assets/javascripts/es6_browserified/itineraries/reducers/index.js +++ b/app/assets/javascripts/es6_browserified/itineraries/reducers/index.js @@ -1,8 +1,8 @@ var combineReducers = require('redux').combineReducers -var todos = require('./todos') +var stopPoints = require('./stopPoints') -const todoApp = combineReducers({ - todos +const stopPointsApp = combineReducers({ + stopPoints }) -module.exports = todoApp +module.exports = stopPointsApp diff --git a/app/assets/javascripts/es6_browserified/itineraries/reducers/stopPoints.js b/app/assets/javascripts/es6_browserified/itineraries/reducers/stopPoints.js new file mode 100644 index 000000000..010ded766 --- /dev/null +++ b/app/assets/javascripts/es6_browserified/itineraries/reducers/stopPoints.js @@ -0,0 +1,85 @@ +var addInput = require('../form_helper') + +const stopPoint = (state = {}, action, length) => { + switch (action.type) { + case 'ADD_STOP': + return { + text: '', + index: length, + for_boarding: 'normal', + for_alighting: 'normal' + } + default: + return state + } +} +const updateFormForDeletion = (stop) =>{ + if (stop.stoppoint_id !== undefined){ + let now = Date.now() + addInput('id', stop.stoppoint_id, now) + addInput('_destroy', 'true', now) + } +} + +const stopPoints = (state = [], action) => { + switch (action.type) { + case 'ADD_STOP': + return [ + ...state, + stopPoint(undefined, action, state.length) + ] + case 'MOVE_STOP_UP': + return [ + ...state.slice(0, action.index - 1), + state[action.index], + state[action.index - 1], + ...state.slice(action.index + 1) + ] + case 'MOVE_STOP_DOWN': + return [ + ...state.slice(0, action.index), + state[action.index + 1], + state[action.index], + ...state.slice(action.index + 2) + ] + case 'DELETE_STOP': + updateFormForDeletion(state[action.index]) + return [ + ...state.slice(0, action.index), + ...state.slice(action.index + 1).map((stopPoint)=>{ + stopPoint.index-- + return stopPoint + }) + ] + case 'UPDATE_INPUT_VALUE': + return state.map( (t, i) => { + if (i === action.index) { + updateFormForDeletion(t) + return Object.assign( + {}, + t, + {stoppoint_id: "", text: action.text.text, stoparea_id: action.text.stoparea_id, user_objectid: action.text.user_objectid} + ) + } else { + return t + } + }) + // return state.map(t => + // stopPoint(t, action) + // ) + case 'UPDATE_SELECT_VALUE': + return state.map( (t,i) => { + if (i === action.index) { + let stopState = Object.assign({}, t) + stopState[action.select_id] = action.select_value + return stopState + } else { + return t + } + }) + default: + return state + } +} + +module.exports = stopPoints diff --git a/app/assets/javascripts/es6_browserified/itineraries/reducers/todos.js b/app/assets/javascripts/es6_browserified/itineraries/reducers/todos.js deleted file mode 100644 index 215a3e2c2..000000000 --- a/app/assets/javascripts/es6_browserified/itineraries/reducers/todos.js +++ /dev/null @@ -1,85 +0,0 @@ -var addInput = require('../form_helper') - -const todo = (state = {}, action, length) => { - switch (action.type) { - case 'ADD_STOP': - return { - text: '', - index: length, - for_boarding: 'normal', - for_alighting: 'normal' - } - default: - return state - } -} -const updateFormForDeletion = (stop) =>{ - if (stop.stoppoint_id !== undefined){ - let now = Date.now() - addInput('id', stop.stoppoint_id, now) - addInput('_destroy', 'true', now) - } -} - -const todos = (state = [], action) => { - switch (action.type) { - case 'ADD_STOP': - return [ - ...state, - todo(undefined, action, state.length) - ] - case 'MOVE_STOP_UP': - return [ - ...state.slice(0, action.index - 1), - state[action.index], - state[action.index - 1], - ...state.slice(action.index + 1) - ] - case 'MOVE_STOP_DOWN': - return [ - ...state.slice(0, action.index), - state[action.index + 1], - state[action.index], - ...state.slice(action.index + 2) - ] - case 'DELETE_STOP': - updateFormForDeletion(state[action.index]) - return [ - ...state.slice(0, action.index), - ...state.slice(action.index + 1).map((todo)=>{ - todo.index-- - return todo - }) - ] - case 'UPDATE_INPUT_VALUE': - return state.map( (t, i) => { - if (i === action.index) { - updateFormForDeletion(t) - return Object.assign( - {}, - t, - {stoppoint_id: "", text: action.text.text, stoparea_id: action.text.stoparea_id, user_objectid: action.text.user_objectid} - ) - } else { - return t - } - }) - // return state.map(t => - // todo(t, action) - // ) - case 'UPDATE_SELECT_VALUE': - return state.map( (t,i) => { - if (i === action.index) { - let stopState = Object.assign({}, t) - stopState[action.select_id] = action.select_value - return stopState - } else { - return t - } - }) - default: - return state - } -} - -module.exports = todos diff --git a/app/assets/javascripts/es6_browserified/itineraries/stop_points.js b/app/assets/javascripts/es6_browserified/itineraries/stop_points.js deleted file mode 100644 index d5f53fb4f..000000000 --- a/app/assets/javascripts/es6_browserified/itineraries/stop_points.js +++ /dev/null @@ -1,66 +0,0 @@ -var React = require('react') -var render = require('react-dom').render -var Provider = require('react-redux').Provider -var createStore = require('redux').createStore -var todoApp = require('./reducers') -var App = require('./components/App') -var addInput = require('./form_helper') - -// logger, DO NOT REMOVE -// var applyMiddleware = require('redux').applyMiddleware -// var createLogger = require('redux-logger') -// var thunkMiddleware = require('redux-thunk').default -// var promise = require('redux-promise') - -const getInitialState = () => { - let state = [] - let datas = JSON.parse(decodeURIComponent(window.itinerary_stop)) - for (let [index, value] of datas.entries()){ - - let fancyText = value.name - if(value.zip_code && value.city_name) - fancyText += ", " + value.zip_code + " " + value.city_name - - state.push({ - stoppoint_id: value.stoppoint_id, - stoparea_id: value.stoparea_id, - user_objectid: value.user_objectid, - index: index, - city_name: value.city_name, - zip_code: value.zip_code, - text: fancyText, - for_boarding: value.for_boarding || "normal", - for_alighting: value.for_alighting || "normal" - }) - } - return state -} - -var initialState = {todos: getInitialState()} -// const loggerMiddleware = createLogger() -let store = createStore( - todoApp, - initialState - // applyMiddleware(thunkMiddleware, promise, loggerMiddleware) -) - -render( - - - , - document.getElementById('stop_points') -) - -document.querySelector('input[name=commit]').addEventListener('click', (event)=>{ - let state = store.getState() - for (let [i, todo] of state.todos.entries()){ - if (todo.stoppoint_id == undefined){ - todo.stoppoint_id = "" - } - addInput('id',todo.stoppoint_id, i) - addInput('stop_area_id',todo.stoparea_id, i) - addInput('position',i, i) - addInput('for_boarding',todo.for_boarding, i) - addInput('for_alighting',todo.for_alighting, i) - } -}) diff --git a/app/views/routes/_form.html.slim b/app/views/routes/_form.html.slim index ae07d41de..a4da376cc 100644 --- a/app/views/routes/_form.html.slim +++ b/app/views/routes/_form.html.slim @@ -29,4 +29,4 @@ | window.itinerary_stop = "#{URI.escape(route_json_for_edit(@route))}" / StopPoints Reactux component -= javascript_include_tag 'es6_browserified/itineraries/stop_points.js' += javascript_include_tag 'es6_browserified/itineraries/index.js' diff --git a/spec/javascripts/itineraries/reducers_spec.js b/spec/javascripts/itineraries/reducers_spec.js index a8731af5f..344cccab5 100644 --- a/spec/javascripts/itineraries/reducers_spec.js +++ b/spec/javascripts/itineraries/reducers_spec.js @@ -1,4 +1,4 @@ -var reducer = require('es6_browserified/itineraries/reducers/todos') +var reducer = require('es6_browserified/itineraries/reducers/stopPoints') let state = [] describe('stops reducer', () => { beforeEach(()=>{ -- cgit v1.2.3 From ca371715123aa629925b05a7690697852c47b40d Mon Sep 17 00:00:00 2001 From: jpl Date: Tue, 17 Jan 2017 15:00:40 +0100 Subject: Refs #2402: addding openlayers lib --- app/assets/javascripts/OpenLayers/ol-debug.js | 92558 ++++++++++++++++++++++++ app/assets/javascripts/OpenLayers/ol.js | 1008 + app/assets/javascripts/application.js | 1 + app/assets/stylesheets/OpenLayers/ol.css | 1 + app/assets/stylesheets/application.sass.erb | 1 + app/views/layouts/application.html.slim | 12 +- app/views/routes/edit.html.slim | 15 + 7 files changed, 93590 insertions(+), 6 deletions(-) create mode 100644 app/assets/javascripts/OpenLayers/ol-debug.js create mode 100644 app/assets/javascripts/OpenLayers/ol.js create mode 100644 app/assets/stylesheets/OpenLayers/ol.css diff --git a/app/assets/javascripts/OpenLayers/ol-debug.js b/app/assets/javascripts/OpenLayers/ol-debug.js new file mode 100644 index 000000000..5513c545a --- /dev/null +++ b/app/assets/javascripts/OpenLayers/ol-debug.js @@ -0,0 +1,92558 @@ +// OpenLayers 3. See https://openlayers.org/ +// License: https://raw.githubusercontent.com/openlayers/ol3/master/LICENSE.md +// Version: v3.20.1 +;(function (root, factory) { + if (typeof exports === "object") { + module.exports = factory(); + } else if (typeof define === "function" && define.amd) { + define([], factory); + } else { + root.ol = factory(); + } +}(this, function () { + var OPENLAYERS = {}; + var goog = this.goog = {}; +this.CLOSURE_NO_DEPS = true; +// Copyright 2006 The Closure Library Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS-IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @fileoverview Bootstrap for the Google JS Library (Closure). + * + * In uncompiled mode base.js will write out Closure's deps file, unless the + * global CLOSURE_NO_DEPS is set to true. This allows projects to + * include their own deps file(s) from different locations. + * + * @author arv@google.com (Erik Arvidsson) + * + * @provideGoog + */ + + +/** + * @define {boolean} Overridden to true by the compiler when + * --process_closure_primitives is specified. + */ +var COMPILED = false; + + +/** + * Base namespace for the Closure library. Checks to see goog is already + * defined in the current scope before assigning to prevent clobbering if + * base.js is loaded more than once. + * + * @const + */ +var goog = goog || {}; + + +/** + * Reference to the global context. In most cases this will be 'window'. + */ +goog.global = this; + + +/** + * A hook for overriding the define values in uncompiled mode. + * + * In uncompiled mode, {@code CLOSURE_UNCOMPILED_DEFINES} may be defined before + * loading base.js. If a key is defined in {@code CLOSURE_UNCOMPILED_DEFINES}, + * {@code goog.define} will use the value instead of the default value. This + * allows flags to be overwritten without compilation (this is normally + * accomplished with the compiler's "define" flag). + * + * Example: + *
+ *   var CLOSURE_UNCOMPILED_DEFINES = {'goog.DEBUG': false};
+ * 
+ * + * @type {Object|undefined} + */ +goog.global.CLOSURE_UNCOMPILED_DEFINES; + + +/** + * A hook for overriding the define values in uncompiled or compiled mode, + * like CLOSURE_UNCOMPILED_DEFINES but effective in compiled code. In + * uncompiled code CLOSURE_UNCOMPILED_DEFINES takes precedence. + * + * Also unlike CLOSURE_UNCOMPILED_DEFINES the values must be number, boolean or + * string literals or the compiler will emit an error. + * + * While any @define value may be set, only those set with goog.define will be + * effective for uncompiled code. + * + * Example: + *
+ *   var CLOSURE_DEFINES = {'goog.DEBUG': false} ;
+ * 
+ * + * @type {Object|undefined} + */ +goog.global.CLOSURE_DEFINES; + + +/** + * Returns true if the specified value is not undefined. + * WARNING: Do not use this to test if an object has a property. Use the in + * operator instead. + * + * @param {?} val Variable to test. + * @return {boolean} Whether variable is defined. + */ +goog.isDef = function(val) { + // void 0 always evaluates to undefined and hence we do not need to depend on + // the definition of the global variable named 'undefined'. + return val !== void 0; +}; + + +/** + * Builds an object structure for the provided namespace path, ensuring that + * names that already exist are not overwritten. For example: + * "a.b.c" -> a = {};a.b={};a.b.c={}; + * Used by goog.provide and goog.exportSymbol. + * @param {string} name name of the object that this file defines. + * @param {*=} opt_object the object to expose at the end of the path. + * @param {Object=} opt_objectToExportTo The object to add the path to; default + * is |goog.global|. + * @private + */ +goog.exportPath_ = function(name, opt_object, opt_objectToExportTo) { + var parts = name.split('.'); + var cur = opt_objectToExportTo || goog.global; + + // Internet Explorer exhibits strange behavior when throwing errors from + // methods externed in this manner. See the testExportSymbolExceptions in + // base_test.html for an example. + if (!(parts[0] in cur) && cur.execScript) { + cur.execScript('var ' + parts[0]); + } + + // Certain browsers cannot parse code in the form for((a in b); c;); + // This pattern is produced by the JSCompiler when it collapses the + // statement above into the conditional loop below. To prevent this from + // happening, use a for-loop and reserve the init logic as below. + + // Parentheses added to eliminate strict JS warning in Firefox. + for (var part; parts.length && (part = parts.shift());) { + if (!parts.length && goog.isDef(opt_object)) { + // last part and we have an object; use it + cur[part] = opt_object; + } else if (cur[part]) { + cur = cur[part]; + } else { + cur = cur[part] = {}; + } + } +}; + + +/** + * Defines a named value. In uncompiled mode, the value is retrieved from + * CLOSURE_DEFINES or CLOSURE_UNCOMPILED_DEFINES if the object is defined and + * has the property specified, and otherwise used the defined defaultValue. + * When compiled the default can be overridden using the compiler + * options or the value set in the CLOSURE_DEFINES object. + * + * @param {string} name The distinguished name to provide. + * @param {string|number|boolean} defaultValue + */ +goog.define = function(name, defaultValue) { + var value = defaultValue; + if (!COMPILED) { + if (goog.global.CLOSURE_UNCOMPILED_DEFINES && + Object.prototype.hasOwnProperty.call( + goog.global.CLOSURE_UNCOMPILED_DEFINES, name)) { + value = goog.global.CLOSURE_UNCOMPILED_DEFINES[name]; + } else if ( + goog.global.CLOSURE_DEFINES && + Object.prototype.hasOwnProperty.call( + goog.global.CLOSURE_DEFINES, name)) { + value = goog.global.CLOSURE_DEFINES[name]; + } + } + goog.exportPath_(name, value); +}; + + +/** + * @define {boolean} DEBUG is provided as a convenience so that debugging code + * that should not be included in a production js_binary can be easily stripped + * by specifying --define goog.DEBUG=false to the JSCompiler. For example, most + * toString() methods should be declared inside an "if (goog.DEBUG)" conditional + * because they are generally used for debugging purposes and it is difficult + * for the JSCompiler to statically determine whether they are used. + */ +goog.define('goog.DEBUG', true); + + +/** + * @define {string} LOCALE defines the locale being used for compilation. It is + * used to select locale specific data to be compiled in js binary. BUILD rule + * can specify this value by "--define goog.LOCALE=" as JSCompiler + * option. + * + * Take into account that the locale code format is important. You should use + * the canonical Unicode format with hyphen as a delimiter. Language must be + * lowercase, Language Script - Capitalized, Region - UPPERCASE. + * There are few examples: pt-BR, en, en-US, sr-Latin-BO, zh-Hans-CN. + * + * See more info about locale codes here: + * http://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers + * + * For language codes you should use values defined by ISO 693-1. See it here + * http://www.w3.org/WAI/ER/IG/ert/iso639.htm. There is only one exception from + * this rule: the Hebrew language. For legacy reasons the old code (iw) should + * be used instead of the new code (he), see http://wiki/Main/IIISynonyms. + */ +goog.define('goog.LOCALE', 'en'); // default to en + + +/** + * @define {boolean} Whether this code is running on trusted sites. + * + * On untrusted sites, several native functions can be defined or overridden by + * external libraries like Prototype, Datejs, and JQuery and setting this flag + * to false forces closure to use its own implementations when possible. + * + * If your JavaScript can be loaded by a third party site and you are wary about + * relying on non-standard implementations, specify + * "--define goog.TRUSTED_SITE=false" to the JSCompiler. + */ +goog.define('goog.TRUSTED_SITE', true); + + +/** + * @define {boolean} Whether a project is expected to be running in strict mode. + * + * This define can be used to trigger alternate implementations compatible with + * running in EcmaScript Strict mode or warn about unavailable functionality. + * @see https://goo.gl/PudQ4y + * + */ +goog.define('goog.STRICT_MODE_COMPATIBLE', false); + + +/** + * @define {boolean} Whether code that calls {@link goog.setTestOnly} should + * be disallowed in the compilation unit. + */ +goog.define('goog.DISALLOW_TEST_ONLY_CODE', COMPILED && !goog.DEBUG); + + +/** + * @define {boolean} Whether to use a Chrome app CSP-compliant method for + * loading scripts via goog.require. @see appendScriptSrcNode_. + */ +goog.define('goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING', false); + + +/** + * Defines a namespace in Closure. + * + * A namespace may only be defined once in a codebase. It may be defined using + * goog.provide() or goog.module(). + * + * The presence of one or more goog.provide() calls in a file indicates + * that the file defines the given objects/namespaces. + * Provided symbols must not be null or undefined. + * + * In addition, goog.provide() creates the object stubs for a namespace + * (for example, goog.provide("goog.foo.bar") will create the object + * goog.foo.bar if it does not already exist). + * + * Build tools also scan for provide/require/module statements + * to discern dependencies, build dependency files (see deps.js), etc. + * + * @see goog.require + * @see goog.module + * @param {string} name Namespace provided by this file in the form + * "goog.package.part". + */ +goog.provide = function(name) { + if (goog.isInModuleLoader_()) { + throw Error('goog.provide can not be used within a goog.module.'); + } + if (!COMPILED) { + // Ensure that the same namespace isn't provided twice. + // A goog.module/goog.provide maps a goog.require to a specific file + if (goog.isProvided_(name)) { + throw Error('Namespace "' + name + '" already declared.'); + } + } + + goog.constructNamespace_(name); +}; + + +/** + * @param {string} name Namespace provided by this file in the form + * "goog.package.part". + * @param {Object=} opt_obj The object to embed in the namespace. + * @private + */ +goog.constructNamespace_ = function(name, opt_obj) { + if (!COMPILED) { + delete goog.implicitNamespaces_[name]; + + var namespace = name; + while ((namespace = namespace.substring(0, namespace.lastIndexOf('.')))) { + if (goog.getObjectByName(namespace)) { + break; + } + goog.implicitNamespaces_[namespace] = true; + } + } + + goog.exportPath_(name, opt_obj); +}; + + +/** + * Module identifier validation regexp. + * Note: This is a conservative check, it is very possible to be more lenient, + * the primary exclusion here is "/" and "\" and a leading ".", these + * restrictions are intended to leave the door open for using goog.require + * with relative file paths rather than module identifiers. + * @private + */ +goog.VALID_MODULE_RE_ = /^[a-zA-Z_$][a-zA-Z0-9._$]*$/; + + +/** + * Defines a module in Closure. + * + * Marks that this file must be loaded as a module and claims the namespace. + * + * A namespace may only be defined once in a codebase. It may be defined using + * goog.provide() or goog.module(). + * + * goog.module() has three requirements: + * - goog.module may not be used in the same file as goog.provide. + * - goog.module must be the first statement in the file. + * - only one goog.module is allowed per file. + * + * When a goog.module annotated file is loaded, it is enclosed in + * a strict function closure. This means that: + * - any variables declared in a goog.module file are private to the file + * (not global), though the compiler is expected to inline the module. + * - The code must obey all the rules of "strict" JavaScript. + * - the file will be marked as "use strict" + * + * NOTE: unlike goog.provide, goog.module does not declare any symbols by + * itself. If declared symbols are desired, use + * goog.module.declareLegacyNamespace(). + * + * + * See the public goog.module proposal: http://goo.gl/Va1hin + * + * @param {string} name Namespace provided by this file in the form + * "goog.package.part", is expected but not required. + */ +goog.module = function(name) { + if (!goog.isString(name) || !name || + name.search(goog.VALID_MODULE_RE_) == -1) { + throw Error('Invalid module identifier'); + } + if (!goog.isInModuleLoader_()) { + throw Error('Module ' + name + ' has been loaded incorrectly.'); + } + if (goog.moduleLoaderState_.moduleName) { + throw Error('goog.module may only be called once per module.'); + } + + // Store the module name for the loader. + goog.moduleLoaderState_.moduleName = name; + if (!COMPILED) { + // Ensure that the same namespace isn't provided twice. + // A goog.module/goog.provide maps a goog.require to a specific file + if (goog.isProvided_(name)) { + throw Error('Namespace "' + name + '" already declared.'); + } + delete goog.implicitNamespaces_[name]; + } +}; + + +/** + * @param {string} name The module identifier. + * @return {?} The module exports for an already loaded module or null. + * + * Note: This is not an alternative to goog.require, it does not + * indicate a hard dependency, instead it is used to indicate + * an optional dependency or to access the exports of a module + * that has already been loaded. + * @suppress {missingProvide} + */ +goog.module.get = function(name) { + return goog.module.getInternal_(name); +}; + + +/** + * @param {string} name The module identifier. + * @return {?} The module exports for an already loaded module or null. + * @private + */ +goog.module.getInternal_ = function(name) { + if (!COMPILED) { + if (goog.isProvided_(name)) { + // goog.require only return a value with-in goog.module files. + return name in goog.loadedModules_ ? goog.loadedModules_[name] : + goog.getObjectByName(name); + } else { + return null; + } + } +}; + + +/** + * @private {?{moduleName: (string|undefined), declareLegacyNamespace:boolean}} + */ +goog.moduleLoaderState_ = null; + + +/** + * @private + * @return {boolean} Whether a goog.module is currently being initialized. + */ +goog.isInModuleLoader_ = function() { + return goog.moduleLoaderState_ != null; +}; + + +/** + * Provide the module's exports as a globally accessible object under the + * module's declared name. This is intended to ease migration to goog.module + * for files that have existing usages. + * @suppress {missingProvide} + */ +goog.module.declareLegacyNamespace = function() { + if (!COMPILED && !goog.isInModuleLoader_()) { + throw new Error( + 'goog.module.declareLegacyNamespace must be called from ' + + 'within a goog.module'); + } + if (!COMPILED && !goog.moduleLoaderState_.moduleName) { + throw Error( + 'goog.module must be called prior to ' + + 'goog.module.declareLegacyNamespace.'); + } + goog.moduleLoaderState_.declareLegacyNamespace = true; +}; + + +/** + * Marks that the current file should only be used for testing, and never for + * live code in production. + * + * In the case of unit tests, the message may optionally be an exact namespace + * for the test (e.g. 'goog.stringTest'). The linter will then ignore the extra + * provide (if not explicitly defined in the code). + * + * @param {string=} opt_message Optional message to add to the error that's + * raised when used in production code. + */ +goog.setTestOnly = function(opt_message) { + if (goog.DISALLOW_TEST_ONLY_CODE) { + opt_message = opt_message || ''; + throw Error( + 'Importing test-only code into non-debug environment' + + (opt_message ? ': ' + opt_message : '.')); + } +}; + + +/** + * Forward declares a symbol. This is an indication to the compiler that the + * symbol may be used in the source yet is not required and may not be provided + * in compilation. + * + * The most common usage of forward declaration is code that takes a type as a + * function parameter but does not need to require it. By forward declaring + * instead of requiring, no hard dependency is made, and (if not required + * elsewhere) the namespace may never be required and thus, not be pulled + * into the JavaScript binary. If it is required elsewhere, it will be type + * checked as normal. + * + * + * @param {string} name The namespace to forward declare in the form of + * "goog.package.part". + */ +goog.forwardDeclare = function(name) {}; + + +/** + * Forward declare type information. Used to assign types to goog.global + * referenced object that would otherwise result in unknown type references + * and thus block property disambiguation. + */ +goog.forwardDeclare('Document'); +goog.forwardDeclare('HTMLScriptElement'); +goog.forwardDeclare('XMLHttpRequest'); + + +if (!COMPILED) { + /** + * Check if the given name has been goog.provided. This will return false for + * names that are available only as implicit namespaces. + * @param {string} name name of the object to look for. + * @return {boolean} Whether the name has been provided. + * @private + */ + goog.isProvided_ = function(name) { + return (name in goog.loadedModules_) || + (!goog.implicitNamespaces_[name] && + goog.isDefAndNotNull(goog.getObjectByName(name))); + }; + + /** + * Namespaces implicitly defined by goog.provide. For example, + * goog.provide('goog.events.Event') implicitly declares that 'goog' and + * 'goog.events' must be namespaces. + * + * @type {!Object} + * @private + */ + goog.implicitNamespaces_ = {'goog.module': true}; + + // NOTE: We add goog.module as an implicit namespace as goog.module is defined + // here and because the existing module package has not been moved yet out of + // the goog.module namespace. This satisifies both the debug loader and + // ahead-of-time dependency management. +} + + +/** + * Returns an object based on its fully qualified external name. The object + * is not found if null or undefined. If you are using a compilation pass that + * renames property names beware that using this function will not find renamed + * properties. + * + * @param {string} name The fully qualified name. + * @param {Object=} opt_obj The object within which to look; default is + * |goog.global|. + * @return {?} The value (object or primitive) or, if not found, null. + */ +goog.getObjectByName = function(name, opt_obj) { + var parts = name.split('.'); + var cur = opt_obj || goog.global; + for (var part; part = parts.shift();) { + if (goog.isDefAndNotNull(cur[part])) { + cur = cur[part]; + } else { + return null; + } + } + return cur; +}; + + +/** + * Globalizes a whole namespace, such as goog or goog.lang. + * + * @param {!Object} obj The namespace to globalize. + * @param {Object=} opt_global The object to add the properties to. + * @deprecated Properties may be explicitly exported to the global scope, but + * this should no longer be done in bulk. + */ +goog.globalize = function(obj, opt_global) { + var global = opt_global || goog.global; + for (var x in obj) { + global[x] = obj[x]; + } +}; + + +/** + * Adds a dependency from a file to the files it requires. + * @param {string} relPath The path to the js file. + * @param {!Array} provides An array of strings with + * the names of the objects this file provides. + * @param {!Array} requires An array of strings with + * the names of the objects this file requires. + * @param {boolean|!Object=} opt_loadFlags Parameters indicating + * how the file must be loaded. The boolean 'true' is equivalent + * to {'module': 'goog'} for backwards-compatibility. Valid properties + * and values include {'module': 'goog'} and {'lang': 'es6'}. + */ +goog.addDependency = function(relPath, provides, requires, opt_loadFlags) { + if (goog.DEPENDENCIES_ENABLED) { + var provide, require; + var path = relPath.replace(/\\/g, '/'); + var deps = goog.dependencies_; + if (!opt_loadFlags || typeof opt_loadFlags === 'boolean') { + opt_loadFlags = opt_loadFlags ? {'module': 'goog'} : {}; + } + for (var i = 0; provide = provides[i]; i++) { + deps.nameToPath[provide] = path; + deps.loadFlags[path] = opt_loadFlags; + } + for (var j = 0; require = requires[j]; j++) { + if (!(path in deps.requires)) { + deps.requires[path] = {}; + } + deps.requires[path][require] = true; + } + } +}; + + + + +// NOTE(nnaze): The debug DOM loader was included in base.js as an original way +// to do "debug-mode" development. The dependency system can sometimes be +// confusing, as can the debug DOM loader's asynchronous nature. +// +// With the DOM loader, a call to goog.require() is not blocking -- the script +// will not load until some point after the current script. If a namespace is +// needed at runtime, it needs to be defined in a previous script, or loaded via +// require() with its registered dependencies. +// +// User-defined namespaces may need their own deps file. For a reference on +// creating a deps file, see: +// Externally: https://developers.google.com/closure/library/docs/depswriter +// +// Because of legacy clients, the DOM loader can't be easily removed from +// base.js. Work is being done to make it disableable or replaceable for +// different environments (DOM-less JavaScript interpreters like Rhino or V8, +// for example). See bootstrap/ for more information. + + +/** + * @define {boolean} Whether to enable the debug loader. + * + * If enabled, a call to goog.require() will attempt to load the namespace by + * appending a script tag to the DOM (if the namespace has been registered). + * + * If disabled, goog.require() will simply assert that the namespace has been + * provided (and depend on the fact that some outside tool correctly ordered + * the script). + */ +goog.define('goog.ENABLE_DEBUG_LOADER', true); + + +/** + * @param {string} msg + * @private + */ +goog.logToConsole_ = function(msg) { + if (goog.global.console) { + goog.global.console['error'](msg); + } +}; + + +/** + * Implements a system for the dynamic resolution of dependencies that works in + * parallel with the BUILD system. Note that all calls to goog.require will be + * stripped by the JSCompiler when the --process_closure_primitives option is + * used. + * @see goog.provide + * @param {string} name Namespace to include (as was given in goog.provide()) in + * the form "goog.package.part". + * @return {?} If called within a goog.module file, the associated namespace or + * module otherwise null. + */ +goog.require = function(name) { + // If the object already exists we do not need do do anything. + if (!COMPILED) { + if (goog.ENABLE_DEBUG_LOADER && goog.IS_OLD_IE_) { + goog.maybeProcessDeferredDep_(name); + } + + if (goog.isProvided_(name)) { + if (goog.isInModuleLoader_()) { + return goog.module.getInternal_(name); + } else { + return null; + } + } + + if (goog.ENABLE_DEBUG_LOADER) { + var path = goog.getPathFromDeps_(name); + if (path) { + goog.writeScripts_(path); + return null; + } + } + + var errorMessage = 'goog.require could not find: ' + name; + goog.logToConsole_(errorMessage); + + throw Error(errorMessage); + } +}; + + +/** + * Path for included scripts. + * @type {string} + */ +goog.basePath = ''; + + +/** + * A hook for overriding the base path. + * @type {string|undefined} + */ +goog.global.CLOSURE_BASE_PATH; + + +/** + * Whether to write out Closure's deps file. By default, the deps are written. + * @type {boolean|undefined} + */ +goog.global.CLOSURE_NO_DEPS; + + +/** + * A function to import a single script. This is meant to be overridden when + * Closure is being run in non-HTML contexts, such as web workers. It's defined + * in the global scope so that it can be set before base.js is loaded, which + * allows deps.js to be imported properly. + * + * The function is passed the script source, which is a relative URI. It should + * return true if the script was imported, false otherwise. + * @type {(function(string): boolean)|undefined} + */ +goog.global.CLOSURE_IMPORT_SCRIPT; + + +/** + * Null function used for default values of callbacks, etc. + * @return {void} Nothing. + */ +goog.nullFunction = function() {}; + + +/** + * When defining a class Foo with an abstract method bar(), you can do: + * Foo.prototype.bar = goog.abstractMethod + * + * Now if a subclass of Foo fails to override bar(), an error will be thrown + * when bar() is invoked. + * + * Note: This does not take the name of the function to override as an argument + * because that would make it more difficult to obfuscate our JavaScript code. + * + * @type {!Function} + * @throws {Error} when invoked to indicate the method should be overridden. + */ +goog.abstractMethod = function() { + throw Error('unimplemented abstract method'); +}; + + +/** + * Adds a {@code getInstance} static method that always returns the same + * instance object. + * @param {!Function} ctor The constructor for the class to add the static + * method to. + */ +goog.addSingletonGetter = function(ctor) { + ctor.getInstance = function() { + if (ctor.instance_) { + return ctor.instance_; + } + if (goog.DEBUG) { + // NOTE: JSCompiler can't optimize away Array#push. + goog.instantiatedSingletons_[goog.instantiatedSingletons_.length] = ctor; + } + return ctor.instance_ = new ctor; + }; +}; + + +/** + * All singleton classes that have been instantiated, for testing. Don't read + * it directly, use the {@code goog.testing.singleton} module. The compiler + * removes this variable if unused. + * @type {!Array} + * @private + */ +goog.instantiatedSingletons_ = []; + + +/** + * @define {boolean} Whether to load goog.modules using {@code eval} when using + * the debug loader. This provides a better debugging experience as the + * source is unmodified and can be edited using Chrome Workspaces or similar. + * However in some environments the use of {@code eval} is banned + * so we provide an alternative. + */ +goog.define('goog.LOAD_MODULE_USING_EVAL', true); + + +/** + * @define {boolean} Whether the exports of goog.modules should be sealed when + * possible. + */ +goog.define('goog.SEAL_MODULE_EXPORTS', goog.DEBUG); + + +/** + * The registry of initialized modules: + * the module identifier to module exports map. + * @private @const {!Object} + */ +goog.loadedModules_ = {}; + + +/** + * True if goog.dependencies_ is available. + * @const {boolean} + */ +goog.DEPENDENCIES_ENABLED = !COMPILED && goog.ENABLE_DEBUG_LOADER; + + +/** + * @define {string} How to decide whether to transpile. Valid values + * are 'always', 'never', and 'detect'. The default ('detect') is to + * use feature detection to determine which language levels need + * transpilation. + */ +// NOTE(user): we could expand this to accept a language level to bypass +// detection: e.g. goog.TRANSPILE == 'es5' would transpile ES6 files but +// would leave ES3 and ES5 files alone. +goog.define('goog.TRANSPILE', 'detect'); + + +/** + * @define {string} Path to the transpiler. Executing the script at this + * path (relative to base.js) should define a function $jscomp.transpile. + */ +goog.define('goog.TRANSPILER', 'transpile.js'); + + +if (goog.DEPENDENCIES_ENABLED) { + /** + * This object is used to keep track of dependencies and other data that is + * used for loading scripts. + * @private + * @type {{ + * loadFlags: !Object>, + * nameToPath: !Object, + * requires: !Object>, + * visited: !Object, + * written: !Object, + * deferred: !Object + * }} + */ + goog.dependencies_ = { + loadFlags: {}, // 1 to 1 + + nameToPath: {}, // 1 to 1 + + requires: {}, // 1 to many + + // Used when resolving dependencies to prevent us from visiting file twice. + visited: {}, + + written: {}, // Used to keep track of script files we have written. + + deferred: {} // Used to track deferred module evaluations in old IEs + }; + + + /** + * Tries to detect whether is in the context of an HTML document. + * @return {boolean} True if it looks like HTML document. + * @private + */ + goog.inHtmlDocument_ = function() { + /** @type {Document} */ + var doc = goog.global.document; + return doc != null && 'write' in doc; // XULDocument misses write. + }; + + + /** + * Tries to detect the base path of base.js script that bootstraps Closure. + * @private + */ + goog.findBasePath_ = function() { + if (goog.isDef(goog.global.CLOSURE_BASE_PATH)) { + goog.basePath = goog.global.CLOSURE_BASE_PATH; + return; + } else if (!goog.inHtmlDocument_()) { + return; + } + /** @type {Document} */ + var doc = goog.global.document; + var scripts = doc.getElementsByTagName('SCRIPT'); + // Search backwards since the current script is in almost all cases the one + // that has base.js. + for (var i = scripts.length - 1; i >= 0; --i) { + var script = /** @type {!HTMLScriptElement} */ (scripts[i]); + var src = script.src; + var qmark = src.lastIndexOf('?'); + var l = qmark == -1 ? src.length : qmark; + if (src.substr(l - 7, 7) == 'base.js') { + goog.basePath = src.substr(0, l - 7); + return; + } + } + }; + + + /** + * Imports a script if, and only if, that script hasn't already been imported. + * (Must be called at execution time) + * @param {string} src Script source. + * @param {string=} opt_sourceText The optionally source text to evaluate + * @private + */ + goog.importScript_ = function(src, opt_sourceText) { + var importScript = + goog.global.CLOSURE_IMPORT_SCRIPT || goog.writeScriptTag_; + if (importScript(src, opt_sourceText)) { + goog.dependencies_.written[src] = true; + } + }; + + + /** + * Whether the browser is IE9 or earlier, which needs special handling + * for deferred modules. + * @const @private {boolean} + */ + goog.IS_OLD_IE_ = + !!(!goog.global.atob && goog.global.document && goog.global.document.all); + + + /** + * Given a URL initiate retrieval and execution of a script that needs + * pre-processing. + * @param {string} src Script source URL. + * @param {boolean} isModule Whether this is a goog.module. + * @param {boolean} needsTranspile Whether this source needs transpilation. + * @private + */ + goog.importProcessedScript_ = function(src, isModule, needsTranspile) { + // In an attempt to keep browsers from timing out loading scripts using + // synchronous XHRs, put each load in its own script block. + var bootstrap = 'goog.retrieveAndExec_("' + src + '", ' + isModule + ', ' + + needsTranspile + ');'; + + goog.importScript_('', bootstrap); + }; + + + /** @private {!Array} */ + goog.queuedModules_ = []; + + + /** + * Return an appropriate module text. Suitable to insert into + * a script tag (that is unescaped). + * @param {string} srcUrl + * @param {string} scriptText + * @return {string} + * @private + */ + goog.wrapModule_ = function(srcUrl, scriptText) { + if (!goog.LOAD_MODULE_USING_EVAL || !goog.isDef(goog.global.JSON)) { + return '' + + 'goog.loadModule(function(exports) {' + + '"use strict";' + scriptText + + '\n' + // terminate any trailing single line comment. + ';return exports' + + '});' + + '\n//# sourceURL=' + srcUrl + '\n'; + } else { + return '' + + 'goog.loadModule(' + + goog.global.JSON.stringify( + scriptText + '\n//# sourceURL=' + srcUrl + '\n') + + ');'; + } + }; + + // On IE9 and earlier, it is necessary to handle + // deferred module loads. In later browsers, the + // code to be evaluated is simply inserted as a script + // block in the correct order. To eval deferred + // code at the right time, we piggy back on goog.require to call + // goog.maybeProcessDeferredDep_. + // + // The goog.requires are used both to bootstrap + // the loading process (when no deps are available) and + // declare that they should be available. + // + // Here we eval the sources, if all the deps are available + // either already eval'd or goog.require'd. This will + // be the case when all the dependencies have already + // been loaded, and the dependent module is loaded. + // + // But this alone isn't sufficient because it is also + // necessary to handle the case where there is no root + // that is not deferred. For that there we register for an event + // and trigger goog.loadQueuedModules_ handle any remaining deferred + // evaluations. + + /** + * Handle any remaining deferred goog.module evals. + * @private + */ + goog.loadQueuedModules_ = function() { + var count = goog.queuedModules_.length; + if (count > 0) { + var queue = goog.queuedModules_; + goog.queuedModules_ = []; + for (var i = 0; i < count; i++) { + var path = queue[i]; + goog.maybeProcessDeferredPath_(path); + } + } + }; + + + /** + * Eval the named module if its dependencies are + * available. + * @param {string} name The module to load. + * @private + */ + goog.maybeProcessDeferredDep_ = function(name) { + if (goog.isDeferredModule_(name) && goog.allDepsAreAvailable_(name)) { + var path = goog.getPathFromDeps_(name); + goog.maybeProcessDeferredPath_(goog.basePath + path); + } + }; + + /** + * @param {string} name The module to check. + * @return {boolean} Whether the name represents a + * module whose evaluation has been deferred. + * @private + */ + goog.isDeferredModule_ = function(name) { + var path = goog.getPathFromDeps_(name); + var loadFlags = path && goog.dependencies_.loadFlags[path] || {}; + if (path && (loadFlags['module'] == 'goog' || + goog.needsTranspile_(loadFlags['lang']))) { + var abspath = goog.basePath + path; + return (abspath) in goog.dependencies_.deferred; + } + return false; + }; + + /** + * @param {string} name The module to check. + * @return {boolean} Whether the name represents a + * module whose declared dependencies have all been loaded + * (eval'd or a deferred module load) + * @private + */ + goog.allDepsAreAvailable_ = function(name) { + var path = goog.getPathFromDeps_(name); + if (path && (path in goog.dependencies_.requires)) { + for (var requireName in goog.dependencies_.requires[path]) { + if (!goog.isProvided_(requireName) && + !goog.isDeferredModule_(requireName)) { + return false; + } + } + } + return true; + }; + + + /** + * @param {string} abspath + * @private + */ + goog.maybeProcessDeferredPath_ = function(abspath) { + if (abspath in goog.dependencies_.deferred) { + var src = goog.dependencies_.deferred[abspath]; + delete goog.dependencies_.deferred[abspath]; + goog.globalEval(src); + } + }; + + + /** + * Load a goog.module from the provided URL. This is not a general purpose + * code loader and does not support late loading code, that is it should only + * be used during page load. This method exists to support unit tests and + * "debug" loaders that would otherwise have inserted script tags. Under the + * hood this needs to use a synchronous XHR and is not recommeneded for + * production code. + * + * The module's goog.requires must have already been satisified; an exception + * will be thrown if this is not the case. This assumption is that no + * "deps.js" file exists, so there is no way to discover and locate the + * module-to-be-loaded's dependencies and no attempt is made to do so. + * + * There should only be one attempt to load a module. If + * "goog.loadModuleFromUrl" is called for an already loaded module, an + * exception will be throw. + * + * @param {string} url The URL from which to attempt to load the goog.module. + */ + goog.loadModuleFromUrl = function(url) { + // Because this executes synchronously, we don't need to do any additional + // bookkeeping. When "goog.loadModule" the namespace will be marked as + // having been provided which is sufficient. + goog.retrieveAndExec_(url, true, false); + }; + + + /** + * Writes a new script pointing to {@code src} directly into the DOM. + * + * NOTE: This method is not CSP-compliant. @see goog.appendScriptSrcNode_ for + * the fallback mechanism. + * + * @param {string} src The script URL. + * @private + */ + goog.writeScriptSrcNode_ = function(src) { + goog.global.document.write( + '