<commit_before>
// http://stackoverflow.com/a/16714931/861745
function fnYYYY_MM_DD(objDate) {
	if (objDate === undefined) {
		objDate = new Date();
	}
	return objDate.toISOString().slice(0,10);
}

// if this file is run directly, do the following:
if (require.main === module) {
	console.log( fnYYYY_MM_DD() );
}
<commit_msg>Update YYYY-MM-DD.js<commit_after>
// http://stackoverflow.com/a/16714931/861745
function fnYYYY_MM_DD(objDate) {
	if (objDate === undefined) {
		objDate = new Date();
	}
	return objDate.toISOString().slice(0,10);
}

// if this file is run directly, do the following:
if (typeof require == "undefined" || require.main === module) {
	// do the following only if file run directly with node or if it is run in the browser.
	console.log( fnYYYY_MM_DD() );
}
<|endoftext|>


<commit_before>/**
 * @overview Stations table interface
 */

'use strict'

const axios = require('axios')
const logger = require('../lib/logger')

/**
 * Page result/size limit
 * @type {number}
 */

class Station {
  /**
   * @param {Database} database A database client instance
   */
  constructor (database) {
    this.database = database
  }

  /**
   * Fetch a list of radio stations matching a query
   * @param   {Object} [filter={}] - Hashmap of search filtering options
   * @param   {string} [filter.query] - RediSearch query
   * @see     {@link http://redisearch.io/Query_Syntax}
   * @returns {Set} List of matching radio station records
   */
  search (filter = {}) {
    return this.database.execute('FT.SEARCH', ['stations', filter.query || 'stations'])
      .then((results) => {
        const stations = new Set()

        // Results start at index:1; first item is the total count
        results.slice(1, results.length).forEach((result) => {
          if (typeof result === 'string') {
            return
          }

          const station = result.reduce((prev, curr, index, collection) => {
            if (index % 2 === 0) {
              const value = collection[index + 1]
              prev[curr] = curr === 'urls'
                ? JSON.parse(value)
                : value
            }

            return prev
          }, {})

          stations.add(station)
        })

        return stations
      })
      .catch((error) => {
        logger.error(error)
        return Promise.reject(new Error(`Something went wrong while trying to fetch stations matching your search.`))
      })
  }

  /**
   * Fetches the media stream url for a given radio station
   * @param   {Object} title - Title of the radio station to find
   * @returns {Promise} Fetch operation
   */
  fetchStream (title) {
    return this.database.execute('get', `station:${title}.primary_format_stream`)
      .then(streamURL => {
        if (streamURL === null) {
          return Promise.reject(new Error(`Station stream for ${title} not found`))
        }

        // If already an actual media resource (not a playlist), use that
        if (!/.pls$|.m3u$/.test(streamURL)) {
          return Promise.resolve(streamURL)
        }

        // Grab the media resource using the playlist url
        return axios.get(streamURL).then(response => {
          const content = response.data.split('\n')
          const fileURL = content.find(line => /^File1=/.test(line))

          // Get the INI value
          return fileURL.replace(/^File1=/, '')
        })
      })
      .catch(error => {
        logger.error(error)
        return Promise.reject(new Error(`Failed to fetch stream for station with title: ${title}.`))
      })
  }

  fetchLinks (title) {
    return this.database.execute('get', `station:${title}.links`)
      .then(JSON.parse)
      .catch(error => {
        logger.error(error)
        return Promise.reject(new Error(`Failed to fetch links for station with title: ${title}.`))
      })
  }
}

module.exports = Station
<commit_msg>Removed dead `Station` code<commit_after>/**
 * @overview Stations table interface
 */

'use strict'

const logger = require('../lib/logger')

class Station {
  /**
   * @param {Database} database - The database client instance
   */
  constructor (database) {
    this.database = database
  }

  /**
   * Fetch a list of radio stations matching a query
   * @param   {Object} [filter={}] - Hashmap of search filtering options
   * @param   {string} [filter.query] - RediSearch query
   * @see     {@link http://redisearch.io/Query_Syntax}
   * @returns {Set} List of matching radio station records
   */
  search (filter = {}) {
    return this.database.execute('FT.SEARCH', ['stations', filter.query || 'stations'])
      .then((results) => {
        const stations = new Set()

        // Results start at index:1; first item is the total count
        results.slice(1, results.length).forEach((result) => {
          if (typeof result === 'string') {
            return
          }

          // Marshal a station object from an array of Redis keys/values
          // in the form of [key, value, key, value]
          const station = result.reduce((prev, curr, index, collection) => {
            if (index % 2 === 0) {
              const value = collection[index + 1]
              prev[curr] = curr === 'urls'
                ? JSON.parse(value)
                : value
            }

            return prev
          }, {})

          stations.add(station)
        })

        return stations
      })
      .catch((error) => {
        logger.error(error)
        return Promise.reject(new Error(`Something went wrong while trying to fetch stations matching your search.`))
      })
  }
}

module.exports = Station
<|endoftext|>


<commit_before>
import map from 'lodash/map';

const DELIMITER = ',';
const TERMINATE = '\n';
const ENCLOSER = '';

// automatically tell Excel to use that character as the separator
const EXCEL_META = `sep=${DELIMITER}`;

/**
 * Create CSV format from Object
 * @param  {array} items [{ id: 1, name: 'foo' }, {}, ...]
 * @param  {object} hook  Items meta { name: 'User name' }
 * @return {string}       csv
 */
const toCSV = (items, hook) =>
{
  const columns = hook ||
    Object.keys(items[0]).reduce((results, column) => ({ ...results, [column]: column }), {});

  const header = map(
    columns,
    (column, index) =>
    {
      if (typeof column === 'string')
      {
        return column;
      }
      else if (typeof column === 'object' && typeof column.title === 'string')
      {
        return column.title;
      }
      // react element
      else if (typeof column === 'object' && column.title && typeof column.title.props === 'object')
      {
        return column.title.props.children
          .map(item => (typeof item === 'string' ? item : ''))
          .join(' ')
          .replace(/  +/g, ' '); // eslint-disable-line
      }

      return index;
    },
  ).join(DELIMITER) + TERMINATE;

  return header + items
    .map(item => Object
      .keys(columns)
      .map(column => ENCLOSER + item[column] + ENCLOSER)
      .join(DELIMITER))
    .join(TERMINATE) + TERMINATE + EXCEL_META;
};

export default toCSV;
<commit_msg>fix(array): toCsv<commit_after>
import map from 'lodash/map';

const DELIMITER = ',';
const TERMINATE = '\n';
const ENCLOSER = '';

// automatically tell Excel to use that character as the separator
const EXCEL_META = `sep=${DELIMITER}`;

/**
 * Create CSV format from Object
 * @param  {array} items [{ id: 1, name: 'foo' }, {}, ...]
 * @param  {object} hook  Items meta { name: 'User name' }
 * @return {string}       csv
 */
const toCSV = (items, hook) =>
{
  const columns = hook ||
    Object.keys(items[0]).reduce((results, column) => ({ ...results, [column]: column }), {});

  const header = map(
    columns,
    (column, index) =>
    {
      if (typeof column === 'string')
      {
        return column;
      }
      else if (typeof column === 'object' && typeof column.title === 'string')
      {
        return column.title;
      }
      // react element
      else if (typeof column === 'object' && column.title && typeof column.title.props === 'object')
      {
        return column.title.props.children
          .map(item => (typeof item === 'string' ? item : ''))
          .join(' ')
          .replace(/  +/g, ' '); // eslint-disable-line
      }

      return index;
    },
  ).join(DELIMITER) + TERMINATE;

  return header + items
    .map(item => Object
      .keys(columns)
      .map(column => ENCLOSER + (item[column] || '') + ENCLOSER)
      .join(DELIMITER))
    .join(TERMINATE) + TERMINATE + EXCEL_META;
};

export default toCSV;
<|endoftext|>


<commit_before>/* Copyright (c) 2010, Sage Software, Inc. 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.
 */

/**
 * SData is an extension of dojo.store that is tailored to handling SData parameters, requests,
 * and pre-handling the responses.
 * @alternateClassName SData
 * @requires convert
 * @requires utility
 */
define('argos/Store/SData', [
    'dojo/_base/declare',
    'dojo/_base/lang',
    'dojo/_base/array',
    'dojo/_base/Deferred',
    'dojo/store/util/QueryResults',
    'dojo/string',
    'dojo/_base/json',
    '../convert',
    '../utility'
], function (
    declare,
    lang,
    array,
    Deferred,
    QueryResults,
    string,
    json,
    convert,
    utility
) {
    var parseOrderByRE = /((?:\w+)(?:\.\w+)?)(?:\s+(asc|desc))?/g,
        parseOrderBy = function(expression) {
            if (typeof expression !== 'string') return expression;

            var match,
                result = [];

            while (match = parseOrderByRE.exec(expression))
            {
                result.push({
                    attribute: match[1],
                    descending: match[2] && match[2].toLowerCase() == 'desc'
                });
            }

            return result;
        };

    return declare('argos.Store.SData', null, {
        doDateConversion: false,

        /* todo: is this the appropriate name for the expansion scope? */
        scope: null,
        where: null,
        select: null,
        include: null,
        orderBy: null,
        service: null,
        request: null,
        queryName: null,
        entityName: null,
        contractName: null,
        resourceKind: null,
        resourceProperty: null,
        resourcePredicate: null,
        executeQueryAs: null,
        executeGetAs: null,

        itemsProperty: '$resources',
        idProperty: '$key',
        labelProperty: '$descriptor',
        entityProperty: '$name',
        versionProperty: '$etag',

        constructor: function(props) {
            lang.mixin(this, props);
        },
        _createEntryRequest: function(id, getOptions) {
            var request = utility.expand(this, getOptions.request || this.request);
            if (request)
            {
                request = request.clone();
            }
            else
            {
                id = id || utility.expand(this.scope || this, getOptions.resourcePredicate || this.resourcePredicate);

                var contractName = utility.expand(this.scope || this, getOptions.contractName || this.contractName),
                    resourceKind = utility.expand(this.scope || this, getOptions.resourceKind || this.resourceKind),
                    resourceProperty = utility.expand(this.scope || this, getOptions.resourceProperty || this.resourceProperty),
                    resourcePredicate = id
                        ? typeof id === 'number'
                            ? id
                            : /\s+/.test(id) ? id : string.substitute("'${0}'", [id])
                        : null;

                    // todo: double quotes break some SData providers
                    // resourcePredicate = id
                    //    ? /(\s+)/.test(id) ? id : json.stringify(id) /* string keys are quoted, numeric keys are left alone */
                    //    : utility.expand(this, getOptions.resourcePredicate || this.resourcePredicate);

                if (resourceProperty)
                {
                    request = new Sage.SData.Client.SDataResourcePropertyRequest(this.service)
                        .setResourceProperty(resourceProperty)
                        .setResourceSelector(resourcePredicate);
                }
                else
                {
                    request = new Sage.SData.Client.SDataSingleResourceRequest(this.service)
                        .setResourceSelector(resourcePredicate);
                }

                if (contractName) request.setContractName(contractName);
                if (resourceKind) request.setResourceKind(resourceKind);
            }

            var select = utility.expand(this.scope || this, getOptions.select || this.select),
                include = utility.expand(this.scope || this, getOptions.include || this.include);

            if (select && select.length > 0)
                request.setQueryArg('select', select.join(','));

            if (include && include.length > 0)
                request.setQueryArg('include', include.join(','));

            return request;
        },
        _createFeedRequest: function(query, queryOptions) {
            var request = utility.expand(this, queryOptions.request || this.request);
            if (request)
            {
                request = request.clone();
            }
            else
            {
                var queryName = utility.expand(this.scope || this, queryOptions.queryName || this.queryName),
                    contractName = utility.expand(this.scope || this, queryOptions.contractName || this.contractName),
                    resourceKind = utility.expand(this.scope || this, queryOptions.resourceKind || this.resourceKind),
                    resourceProperty = utility.expand(this.scope || this, queryOptions.resourceProperty || this.resourceProperty),
                    resourcePredicate = utility.expand(this.scope || this, queryOptions.resourcePredicate || this.resourcePredicate);

                if (queryName)
                {
                    request = new Sage.SData.Client.SDataNamedQueryRequest(this.service)
                        .setQueryName(queryName);

                    if (resourcePredicate) request.getUri().setCollectionPredicate(resourcePredicate);
                }
                else if (resourceProperty)
                {
                    request = new Sage.SData.Client.SDataResourcePropertyRequest(this.service)
                        .setResourceProperty(resourceProperty)
                        .setResourceSelector(resourcePredicate);
                }
                else
                {
                    request = new Sage.SData.Client.SDataResourceCollectionRequest(this.service);
                }

                if (contractName) request.setContractName(contractName);
                if (resourceKind) request.setResourceKind(resourceKind);
            }

            var select = utility.expand(this.scope || this, queryOptions.select || this.select),
                include = utility.expand(this.scope || this, queryOptions.include || this.include),
                orderBy = utility.expand(this.scope || this, queryOptions.sort || this.orderBy);

            if (select && select.length > 0)
                request.setQueryArg('select', select.join(','));

            if (include && include.length > 0)
                request.setQueryArg('include', include.join(','));

            if (orderBy)
            {
                if (typeof orderBy === 'string')
                {
                    request.setQueryArg('orderby', orderBy);
                }
                else if (orderBy.length > 0)
                {
                    var order = [];
                    array.forEach(orderBy, function (v) {
                        if (v.descending)
                            this.push(v.attribute + ' desc');
                        else
                            this.push(v.attribute);
                    }, order);

                    request.setQueryArg('orderby', order.join(','));
                }
            }

            var where = utility.expand(this.scope || this, this.where),
                query = utility.expand(this.scope || this, query),
                conditions = [];

            if (where)
                conditions.push(where);

            if (query)
                conditions.push(query);

            if (conditions.length > 0)
                request.setQueryArg('where', '(' + conditions.join(') and (') + ')');

            if (typeof queryOptions.start !== 'undefined')
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.StartIndex, queryOptions.start + 1);

            if (typeof queryOptions.count !== 'undefined')
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.Count, queryOptions.count);

            return request;
        },
        _onRequestFeedSuccess: function(queryDeferred, feed) {
            if (feed)
            {
                var items = lang.getObject(this.itemsProperty, false, feed),
                    total = typeof feed['$totalResults'] === 'number' ? feed['$totalResults'] : -1;

                queryDeferred.total = total;
                queryDeferred.resolve(items);
            }
            else
            {
                var error = new Error('The feed result is invalid.');

                queryDeferred.reject(error);
            }
        },
        _onRequestEntrySuccess: function(deferred, entry) {
            if (entry)
            {
                deferred.resolve(this.doDateConversion ? this._handleDateConversion(entry) : entry);
            }
            else
            {
                var error = new Error('The entry result is invalid.');

                deferred.reject(error);
            }
        },
        _onRequestFailure: function(deferred, xhr, xhrOptions) {
            var error = new Error('An error occurred requesting: ' + xhrOptions.url);

            error.xhr = xhr;
            error.status = xhr.status;
            error.aborted = false;
            error.url = xhrOptions.url;

            deferred.reject(error);
        },
        _onRequestAbort: function(deferred, xhr, xhrOptions) {
            var error = new Error('An error occurred requesting: ' + xhrOptions.url);

            error.xhr = xhr;
            error.status = 0;
            error.responseText = null;
            error.aborted = true;

            deferred.reject(error);
        },
        _onCancel: function(handle) {
            this.store.abort(handle.value);
        },
        _handleDateConversion: function(entry) {
            for (var prop in entry)
            {
                if (convert.isDateString(entry[prop]))
                {
                    entry[prop] = convert.toDateFromString(entry[prop]);
                }
            }

            return entry;
        },
        _handleDateSerialization: function(entry) {
            for (var prop in entry)
            {
                if (entry[prop] instanceof Date)
                {
                    entry[prop] = this.service.isJsonEnabled()
                        ? convert.toJsonStringFromDate(entry[prop])
                        : convert.toIsoStringFromDate(entry[prop]);
                }
            }

            return entry;
        },
        get: function(id, /* sdata only */ getOptions) {
            // summary:
            //		Retrieves an object by its identity
            // id: Number
            //		The identity to use to lookup the object
            // returns: Object
            //		The object in the store that matches the given id.

            var handle = {},
                deferred = new Deferred(lang.hitch(this, this._onCancel, handle)),
                request = this._createEntryRequest(id, getOptions || {});

            var method = this.executeGetAs
                ? request[this.executeGetAs]
                : request.read;

            handle.value = method.call(request, {
                success: lang.hitch(this, this._onRequestEntrySuccess, deferred),
                failure: lang.hitch(this, this._onRequestFailure, deferred),
                abort: lang.hitch(this, this._onRequestAbort, deferred)
            });

            return deferred;
        },
        getIdentity: function(object) {
            // summary:
            //		Returns an object's identity
            // object: Object
            //		The object to get the identity from
            // returns: String|Number

            return lang.getObject(this.idProperty, false, object);
        },
        getLabel: function(object) {
            return lang.getObject(this.labelProperty, false, object);
        },
        getEntity: function(object) {
            return lang.getObject(this.entityProperty, false, object);
        },
        getVersion: function(object) {
            return lang.getObject(this.versionProperty, false, object);
        },
        put: function(object, putOptions) {
            // summary:
            //		Stores an object
            // object: Object
            //		The object to store.
            // directives: dojo.store.api.Store.PutDirectives?
            //		Additional directives for storing objects.
            // returns: Number|String

            putOptions = putOptions || {};

            var id = putOptions.id || this.getIdentity(object),
                entity = putOptions.entity || this.entityName,
                version = putOptions.version || this.getVersion(object),
                atom = !this.service.isJsonEnabled();

            if (id) object['$key'] = id;
            if (entity && atom) object['$name'] = entity;
            if (version) object['$etag'] = version;

            var handle = {},
                deferred = new Deferred(lang.hitch(this, this._onCancel, handle)),
                request = this._createEntryRequest(id, putOptions);

            var method = putOptions.overwrite
                ? request.update
                : request.create;

            handle.value = method.call(request, object, {
                success: lang.hitch(this, this._onTransmitEntrySuccess, deferred),
                failure: lang.hitch(this, this._onRequestFailure, deferred),
                abort: lang.hitch(this, this._onRequestAbort, deferred)
            });

            return deferred;
        },
        _onTransmitEntrySuccess: function(deferred, entry) {
            deferred.resolve(this.doDateConversion ? this._handleDateConversion(entry) : entry);
        },
        add: function(object, addOptions) {
            // summary:
            //		Creates an object, throws an error if the object already exists
            // object: Object
            //		The object to store.
            // directives: dojo.store.api.Store.PutDirectives?
            //		Additional directives for creating objects.
            // returns: Number|String
            addOptions = addOptions || {};
            addOptions.overwrite = false;

            return this.put(object, addOptions);
        },
        remove: function(id) {
            // summary:
            //		Deletes an object by its identity
            // id: Number
            //		The identity to use to delete the object

        },
        query: function(query, queryOptions) {
            // summary:
            //		Queries the store for objects. This does not alter the store, but returns a
            //		set of data from the store.
            // query: String|Object|Function
            //		The query to use for retrieving objects from the store.
            // options: dojo.store.api.Store.QueryOptions
            //		The optional arguments to apply to the resultset.
            // returns: dojo.store.api.Store.QueryResults
            //		The results of the query, extended with iterative methods.
            //
            // example:
            //		Given the following store:
            //
            //	...find all items where "prime" is true:
            //
            //	|	store.query({ prime: true }).forEach(function(object){
            //	|		// handle each object
            //	|	});

            var handle = {},
                queryDeferred = new Deferred(lang.hitch(this, this._onCancel, handle)),
                request = this._createFeedRequest(query, queryOptions || {});

            queryDeferred.total = -1;

            var method = this.executeQueryAs
                ? request[this.executeQueryAs]
                : request instanceof Sage.SData.Client.SDataResourcePropertyRequest
                    ? request.readFeed
                    : request.read;

            handle.value = method.call(request, {
                success: lang.hitch(this, this._onRequestFeedSuccess, queryDeferred),
                failure: lang.hitch(this, this._onRequestFailure, queryDeferred),
                abort: lang.hitch(this, this._onRequestAbort, queryDeferred),
                httpMethodOverride: queryOptions && queryOptions['httpMethodOverride']
            });

            return QueryResults(queryDeferred);
        },
        transaction: function() {
            // summary:
            //		Starts a new transaction.
            //		Note that a store user might not call transaction() prior to using put,
            //		delete, etc. in which case these operations effectively could be thought of
            //		as "auto-commit" style actions.
            // returns: dojo.store.api.Store.Transaction
            //		This represents the new current transaction.
        },
        getChildren: function(parent, options){
            // summary:
            //		Retrieves the children of an object.
            // parent: Object
            //		The object to find the children of.
            // options: dojo.store.api.Store.QueryOptions?
            //		Additional options to apply to the retrieval of the children.
            // returns: dojo.store.api.Store.QueryResults
            //		A result set of the children of the parent object.
        },
        getMetadata: function(object) {
            if (object)
            {
                return {
                    id: this.getIdentity(object),
                    label: this.getLabel(object),
                    entity: this.getEntity(object),
                    version: this.getVersion(object)
                };
            }

            return null;

            // summary:
            //		Returns any metadata about the object. This may include attribution,
            //		cache directives, history, or version information.
            // object: Object
            //		The object to return metadata for.
            // returns: Object
            //		An object containing metadata.
        }
    });
});<commit_msg>adjusted the formation of the SData store's predicate expressions.<commit_after>/* Copyright (c) 2010, Sage Software, Inc. 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.
 */

/**
 * SData is an extension of dojo.store that is tailored to handling SData parameters, requests,
 * and pre-handling the responses.
 * @alternateClassName SData
 * @requires convert
 * @requires utility
 */
define('argos/Store/SData', [
    'dojo/_base/declare',
    'dojo/_base/lang',
    'dojo/_base/array',
    'dojo/_base/Deferred',
    'dojo/store/util/QueryResults',
    'dojo/string',
    'dojo/_base/json',
    '../convert',
    '../utility'
], function (
    declare,
    lang,
    array,
    Deferred,
    QueryResults,
    string,
    json,
    convert,
    utility
) {
    var parseOrderByRE = /((?:\w+)(?:\.\w+)?)(?:\s+(asc|desc))?/g,
        parseOrderBy = function(expression) {
            if (typeof expression !== 'string') return expression;

            var match,
                result = [];

            while (match = parseOrderByRE.exec(expression))
            {
                result.push({
                    attribute: match[1],
                    descending: match[2] && match[2].toLowerCase() == 'desc'
                });
            }

            return result;
        };

    return declare('argos.Store.SData', null, {
        doDateConversion: false,

        /* todo: is this the appropriate name for the expansion scope? */
        scope: null,
        where: null,
        select: null,
        include: null,
        orderBy: null,
        service: null,
        request: null,
        queryName: null,
        entityName: null,
        contractName: null,
        resourceKind: null,
        resourceProperty: null,
        resourcePredicate: null,
        executeQueryAs: null,
        executeGetAs: null,

        itemsProperty: '$resources',
        idProperty: '$key',
        labelProperty: '$descriptor',
        entityProperty: '$name',
        versionProperty: '$etag',

        constructor: function(props) {
            lang.mixin(this, props);
        },
        _createEntryRequest: function(id, getOptions) {
            var request = utility.expand(this, getOptions.request || this.request);
            if (request)
            {
                request = request.clone();
            }
            else
            {
                id = id || utility.expand(this.scope || this, getOptions.resourcePredicate || this.resourcePredicate);

                var contractName = utility.expand(this.scope || this, getOptions.contractName || this.contractName),
                    resourceKind = utility.expand(this.scope || this, getOptions.resourceKind || this.resourceKind),
                    resourceProperty = utility.expand(this.scope || this, getOptions.resourceProperty || this.resourceProperty),
                    resourcePredicate = /\s+/.test(id) ? id : string.substitute("'${0}'", [id]);

                if (resourceProperty)
                {
                    request = new Sage.SData.Client.SDataResourcePropertyRequest(this.service)
                        .setResourceProperty(resourceProperty)
                        .setResourceSelector(resourcePredicate);
                }
                else
                {
                    request = new Sage.SData.Client.SDataSingleResourceRequest(this.service)
                        .setResourceSelector(resourcePredicate);
                }

                if (contractName) request.setContractName(contractName);
                if (resourceKind) request.setResourceKind(resourceKind);
            }

            var select = utility.expand(this.scope || this, getOptions.select || this.select),
                include = utility.expand(this.scope || this, getOptions.include || this.include);

            if (select && select.length > 0)
                request.setQueryArg('select', select.join(','));

            if (include && include.length > 0)
                request.setQueryArg('include', include.join(','));

            return request;
        },
        _createFeedRequest: function(query, queryOptions) {
            var request = utility.expand(this, queryOptions.request || this.request);
            if (request)
            {
                request = request.clone();
            }
            else
            {
                var queryName = utility.expand(this.scope || this, queryOptions.queryName || this.queryName),
                    contractName = utility.expand(this.scope || this, queryOptions.contractName || this.contractName),
                    resourceKind = utility.expand(this.scope || this, queryOptions.resourceKind || this.resourceKind),
                    resourceProperty = utility.expand(this.scope || this, queryOptions.resourceProperty || this.resourceProperty),
                    resourcePredicate = utility.expand(this.scope || this, queryOptions.resourcePredicate || this.resourcePredicate);

                if (queryName)
                {
                    request = new Sage.SData.Client.SDataNamedQueryRequest(this.service)
                        .setQueryName(queryName);

                    if (resourcePredicate) request.getUri().setCollectionPredicate(resourcePredicate);
                }
                else if (resourceProperty)
                {
                    request = new Sage.SData.Client.SDataResourcePropertyRequest(this.service)
                        .setResourceProperty(resourceProperty)
                        .setResourceSelector(resourcePredicate);
                }
                else
                {
                    request = new Sage.SData.Client.SDataResourceCollectionRequest(this.service);
                }

                if (contractName) request.setContractName(contractName);
                if (resourceKind) request.setResourceKind(resourceKind);
            }

            var select = utility.expand(this.scope || this, queryOptions.select || this.select),
                include = utility.expand(this.scope || this, queryOptions.include || this.include),
                orderBy = utility.expand(this.scope || this, queryOptions.sort || this.orderBy);

            if (select && select.length > 0)
                request.setQueryArg('select', select.join(','));

            if (include && include.length > 0)
                request.setQueryArg('include', include.join(','));

            if (orderBy)
            {
                if (typeof orderBy === 'string')
                {
                    request.setQueryArg('orderby', orderBy);
                }
                else if (orderBy.length > 0)
                {
                    var order = [];
                    array.forEach(orderBy, function (v) {
                        if (v.descending)
                            this.push(v.attribute + ' desc');
                        else
                            this.push(v.attribute);
                    }, order);

                    request.setQueryArg('orderby', order.join(','));
                }
            }

            var where = utility.expand(this.scope || this, this.where),
                query = utility.expand(this.scope || this, query),
                conditions = [];

            if (where)
                conditions.push(where);

            if (query)
                conditions.push(query);

            if (conditions.length > 0)
                request.setQueryArg('where', '(' + conditions.join(') and (') + ')');

            if (typeof queryOptions.start !== 'undefined')
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.StartIndex, queryOptions.start + 1);

            if (typeof queryOptions.count !== 'undefined')
                request.setQueryArg(Sage.SData.Client.SDataUri.QueryArgNames.Count, queryOptions.count);

            return request;
        },
        _onRequestFeedSuccess: function(queryDeferred, feed) {
            if (feed)
            {
                var items = lang.getObject(this.itemsProperty, false, feed),
                    total = typeof feed['$totalResults'] === 'number' ? feed['$totalResults'] : -1;

                queryDeferred.total = total;
                queryDeferred.resolve(items);
            }
            else
            {
                var error = new Error('The feed result is invalid.');

                queryDeferred.reject(error);
            }
        },
        _onRequestEntrySuccess: function(deferred, entry) {
            if (entry)
            {
                deferred.resolve(this.doDateConversion ? this._handleDateConversion(entry) : entry);
            }
            else
            {
                var error = new Error('The entry result is invalid.');

                deferred.reject(error);
            }
        },
        _onRequestFailure: function(deferred, xhr, xhrOptions) {
            var error = new Error('An error occurred requesting: ' + xhrOptions.url);

            error.xhr = xhr;
            error.status = xhr.status;
            error.aborted = false;
            error.url = xhrOptions.url;

            deferred.reject(error);
        },
        _onRequestAbort: function(deferred, xhr, xhrOptions) {
            var error = new Error('An error occurred requesting: ' + xhrOptions.url);

            error.xhr = xhr;
            error.status = 0;
            error.responseText = null;
            error.aborted = true;

            deferred.reject(error);
        },
        _onCancel: function(handle) {
            this.store.abort(handle.value);
        },
        _handleDateConversion: function(entry) {
            for (var prop in entry)
            {
                if (convert.isDateString(entry[prop]))
                {
                    entry[prop] = convert.toDateFromString(entry[prop]);
                }
            }

            return entry;
        },
        _handleDateSerialization: function(entry) {
            for (var prop in entry)
            {
                if (entry[prop] instanceof Date)
                {
                    entry[prop] = this.service.isJsonEnabled()
                        ? convert.toJsonStringFromDate(entry[prop])
                        : convert.toIsoStringFromDate(entry[prop]);
                }
            }

            return entry;
        },
        get: function(id, /* sdata only */ getOptions) {
            // summary:
            //		Retrieves an object by its identity
            // id: Number
            //		The identity to use to lookup the object
            // returns: Object
            //		The object in the store that matches the given id.

            var handle = {},
                deferred = new Deferred(lang.hitch(this, this._onCancel, handle)),
                request = this._createEntryRequest(id, getOptions || {});

            var method = this.executeGetAs
                ? request[this.executeGetAs]
                : request.read;

            handle.value = method.call(request, {
                success: lang.hitch(this, this._onRequestEntrySuccess, deferred),
                failure: lang.hitch(this, this._onRequestFailure, deferred),
                abort: lang.hitch(this, this._onRequestAbort, deferred)
            });

            return deferred;
        },
        getIdentity: function(object) {
            // summary:
            //		Returns an object's identity
            // object: Object
            //		The object to get the identity from
            // returns: String|Number

            return lang.getObject(this.idProperty, false, object);
        },
        getLabel: function(object) {
            return lang.getObject(this.labelProperty, false, object);
        },
        getEntity: function(object) {
            return lang.getObject(this.entityProperty, false, object);
        },
        getVersion: function(object) {
            return lang.getObject(this.versionProperty, false, object);
        },
        put: function(object, putOptions) {
            // summary:
            //		Stores an object
            // object: Object
            //		The object to store.
            // directives: dojo.store.api.Store.PutDirectives?
            //		Additional directives for storing objects.
            // returns: Number|String

            putOptions = putOptions || {};

            var id = putOptions.id || this.getIdentity(object),
                entity = putOptions.entity || this.entityName,
                version = putOptions.version || this.getVersion(object),
                atom = !this.service.isJsonEnabled();

            if (id) object['$key'] = id;
            if (entity && atom) object['$name'] = entity;
            if (version) object['$etag'] = version;

            var handle = {},
                deferred = new Deferred(lang.hitch(this, this._onCancel, handle)),
                request = this._createEntryRequest(id, putOptions);

            var method = putOptions.overwrite
                ? request.update
                : request.create;

            handle.value = method.call(request, object, {
                success: lang.hitch(this, this._onTransmitEntrySuccess, deferred),
                failure: lang.hitch(this, this._onRequestFailure, deferred),
                abort: lang.hitch(this, this._onRequestAbort, deferred)
            });

            return deferred;
        },
        _onTransmitEntrySuccess: function(deferred, entry) {
            deferred.resolve(this.doDateConversion ? this._handleDateConversion(entry) : entry);
        },
        add: function(object, addOptions) {
            // summary:
            //		Creates an object, throws an error if the object already exists
            // object: Object
            //		The object to store.
            // directives: dojo.store.api.Store.PutDirectives?
            //		Additional directives for creating objects.
            // returns: Number|String
            addOptions = addOptions || {};
            addOptions.overwrite = false;

            return this.put(object, addOptions);
        },
        remove: function(id) {
            // summary:
            //		Deletes an object by its identity
            // id: Number
            //		The identity to use to delete the object

        },
        query: function(query, queryOptions) {
            // summary:
            //		Queries the store for objects. This does not alter the store, but returns a
            //		set of data from the store.
            // query: String|Object|Function
            //		The query to use for retrieving objects from the store.
            // options: dojo.store.api.Store.QueryOptions
            //		The optional arguments to apply to the resultset.
            // returns: dojo.store.api.Store.QueryResults
            //		The results of the query, extended with iterative methods.
            //
            // example:
            //		Given the following store:
            //
            //	...find all items where "prime" is true:
            //
            //	|	store.query({ prime: true }).forEach(function(object){
            //	|		// handle each object
            //	|	});

            var handle = {},
                queryDeferred = new Deferred(lang.hitch(this, this._onCancel, handle)),
                request = this._createFeedRequest(query, queryOptions || {});

            queryDeferred.total = -1;

            var method = this.executeQueryAs
                ? request[this.executeQueryAs]
                : request instanceof Sage.SData.Client.SDataResourcePropertyRequest
                    ? request.readFeed
                    : request.read;

            handle.value = method.call(request, {
                success: lang.hitch(this, this._onRequestFeedSuccess, queryDeferred),
                failure: lang.hitch(this, this._onRequestFailure, queryDeferred),
                abort: lang.hitch(this, this._onRequestAbort, queryDeferred),
                httpMethodOverride: queryOptions && queryOptions['httpMethodOverride']
            });

            return QueryResults(queryDeferred);
        },
        transaction: function() {
            // summary:
            //		Starts a new transaction.
            //		Note that a store user might not call transaction() prior to using put,
            //		delete, etc. in which case these operations effectively could be thought of
            //		as "auto-commit" style actions.
            // returns: dojo.store.api.Store.Transaction
            //		This represents the new current transaction.
        },
        getChildren: function(parent, options){
            // summary:
            //		Retrieves the children of an object.
            // parent: Object
            //		The object to find the children of.
            // options: dojo.store.api.Store.QueryOptions?
            //		Additional options to apply to the retrieval of the children.
            // returns: dojo.store.api.Store.QueryResults
            //		A result set of the children of the parent object.
        },
        getMetadata: function(object) {
            if (object)
            {
                return {
                    id: this.getIdentity(object),
                    label: this.getLabel(object),
                    entity: this.getEntity(object),
                    version: this.getVersion(object)
                };
            }

            return null;

            // summary:
            //		Returns any metadata about the object. This may include attribution,
            //		cache directives, history, or version information.
            // object: Object
            //		The object to return metadata for.
            // returns: Object
            //		An object containing metadata.
        }
    });
});<|endoftext|>


<commit_before>(function($) {

    // Helper function to determine browser scrollbar width
    // All credit goes to Alexandre Gomes, http://www.alexandre-gomes.com/?p=115
    function getScrollBarWidth () {
      var inner = document.createElement('p');
      inner.style.width = "100%";
      inner.style.height = "200px";

      var outer = document.createElement('div');
      outer.style.position = "absolute";
      outer.style.top = "0px";
      outer.style.left = "0px";
      outer.style.visibility = "hidden";
      outer.style.width = "200px";
      outer.style.height = "150px";
      outer.style.overflow = "hidden";
      outer.appendChild (inner);

      document.body.appendChild (outer);
      var w1 = inner.offsetWidth;
      outer.style.overflow = 'scroll';
      var w2 = inner.offsetWidth;
      if (w1 == w2) w2 = outer.clientWidth;

      document.body.removeChild (outer);

      return (w1 - w2);
    };

    $(function(){
        // Determine what page we're on
        app.page = typeof app.page != 'undefined' ? app.page : 'any';

        // Monitoring page-specific
        if(app.page == 'index') {
        	// This is where we cache the autoprogress stuff
        	var autoprogress = null;
        	var autoprogress_state = null;
            var autoprogress_cookie = 'ganbatte_autoprogress_state';

            // ... and the autorefresh stuff
            var autorefresh = null;
            var autorefresh_state = null;
            var autorefresh_cookie = 'ganbatte_autorefresh_state';

        	function setAutoProgress(state) {
    			autoprogress_state = state;
                // Set the autoprogress cookie to the opposite value
                $.cookie(autoprogress_cookie, autoprogress_state, { expires: 999, path: '/' });

                if(autoprogress_state) {
                    $('.autoprogress-toggle').addClass('active').find('i').addClass('icon-pause').removeClass('icon-play');
                    autoprogress = setInterval(moveToNextGroup, app.progress_interval * 1000);
                }else {
                    $('.autoprogress-toggle').removeClass('active').find('i').removeClass('icon-pause').addClass('icon-play');
                    if(autoprogress != null) {
                    	clearInterval(autoprogress);
                    }
                }
            }

        	function toggleAutoProgress() {
        		state = !autoprogress_state;
        		setAutoProgress(state);
        	}

            function initAutoProgress() {
                // First, check if we should enable auto progressing
                autoprogress_state = $.cookie(autoprogress_cookie) || true;
                // Convert string to bool
                autoprogress_state = typeof autoprogress_state == 'string' ? (autoprogress_state == 'true' ? true: false) : autoprogress_state;
                // Start automatically moving to the next group
                setAutoProgress(autoprogress_state);

                // Make sure we can toggle auto progress
                $('.autoprogress-toggle').click(toggleAutoProgress);
            }

        	function setAutoRefresh(state) {
    			autorefresh_state = state;
                // Set the autorefresh cookie to the opposite value
                $.cookie(autorefresh_cookie, autorefresh_state, { expires: 999, path: '/' });

                if(autorefresh_state) {
                    $('.autorefresh-toggle').addClass('active').find('i').addClass('icon-spin');
                    autorefresh = setInterval(performDataRefresh, app.refresh_interval * 1000);
                }else {
                    $('.autorefresh-toggle').removeClass('active').find('i').removeClass('icon-spin');
                    if(autorefresh != null) {
                    	clearInterval(autorefresh);
                    }
                }
            }

        	function toggleAutoRefresh() {
        		state = !autorefresh_state;
        		setAutoRefresh(state);
        	}

            function initAutoRefresh() {
                // First, check if we should enable auto refreshing
                autorefresh_state = $.cookie(autorefresh_cookie) || true;
                // Convert string to bool
                autorefresh_state = typeof autorefresh_state == 'string' ? (autorefresh_state == 'true' ? true: false) : autorefresh_state;
                // Start automatically refreshing
                setAutoRefresh(autorefresh_state);

                // Make sure we can toggle auto refresh
                $('.autorefresh-toggle').click(toggleAutoRefresh);

                // Perform one data refresh on page load, no matter what
                performDataRefresh();
            }

            function queueElementMoveToContainer($elem, container, building) {
            	$elem.data({
            		'container': container,
            		'building': building
            	});

            	// Check if all sibling jobs in this item have similar data values set.
            	// If they do, it's time to actually execute the move.
            	var ready_to_move = true;
            	$elem.siblings().each(function() {
            		var $this = $(this);
            		var this_container = $this.data('container');
            		var this_building = $this.data('building');
            		if(typeof this_container == 'undefined' || typeof this_building == 'undefined') {
            			ready_to_move = false;
            		}
            	});

            	if(ready_to_move) {
            		executeElementMoveToContainer($elem.parent().parent());
            	}
            }

            function executeElementMoveToContainer($elem) {
            	var container = 'disabled';
            	var move_to_top = false;

            	$elem.find('.job').each(function() {
            		var $this = $(this);

            		var this_container = $this.data('container');
            		var this_building = $this.data('building');

            		// Failed stuff stays in the same block
            		if(container == 'failed') {
            			this_container = 'failed';
            		}else
            		// We can only move stuff to the disabled block if all jobs of the item are disabled
            		if(container != 'disabled' && this_container == 'disabled') {
            			this_container = container;
            		}

            		container = this_container;

            		// If we're building, we should move our element to the top of its element
            		if(this_building) {
            			move_to_top = true;
            		}

            		// Remove data values
            		$this.removeData('container');
            		$this.removeData('building');

            	});

        		// If this element is already the within its container and we don't have to move stuff to the top, do nothing
            	if($elem.parent().hasClass('jobs-container-' + container) && !move_to_top) return;
            	// If we have to move stuff to the top, but this element is already the first element within its container, do nothing
            	if(move_to_top && $elem.parent().children()[0] == $elem[0]) return;
            	// If the container doesn't exist, do nothing
            	var $container = $elem.parent().parent().find('.jobs-container-' + container);
            	if(!$container.length) return;
            	// If this element is already being animated, do nothing
            	if($elem.is(':animated')) return;
            	// Fade out this element (but not completely, or we'd lose the space it occupied
            	$elem.animate({
            		'opacity': 0.000001,
            	}, function() {
            		// Next, animate height to 0
            		$elem.animate({
            			'height': 0
            		}, function() {
            			// Next, make this element the first child of its new container
            			$elem.prependTo($container);
            			// Now, animate the height again
            			$elem.animate({
            				'height': '999px'
            			}, function() {
            				// Finally, fade our element back in
            				$elem.animate({
            					'opacity': 1
            				});
            			});
            		});
            	});
            }

            function performDataRefresh() {
            	$.getJSON(app.basepath + app.jobs, function(data) {
            		if(data.length) {
            			/*
            			 * First, loop through all of our job containers. The container's 'title' attribute will tell us
            			 * what job we're looking for.
            			 */
            			$('.job').each(function() {
            				var $this = $(this);
            				var job = $this.data('job');
                            var trigger = $this.data('trigger');

            				// Only do stuff if there's a job to do stuff for
            				if(typeof job != 'undefined' && job.length > 0) {
            					// First, remove all classes that indicate statuses
            					$this.removeClass('animated').removeClass('success').removeClass('error').removeClass('disabled');
            					// Set default container to disabled, to be overriden if we can match the job
    							var container = 'disabled';
    							var building = false;

            					// Loop through our received data, and look for an object with a name that matches our title
            					var matched = false;
            					$.each(data, function(key, val) {
            						if(val.name == job) {
            							matched = true;

            							building = val.color.indexOf('_anime') != -1;
            							var color = val.color.replace('_anime', '');

            							switch(color){
            							case 'blue':
            								// Blue stands for passing builds and good things
            								$this.addClass('bar-success');
            								// Move this item to the neutral jobs container
            								container = 'neutral';
            								break;
            							case 'disabled':
            								$this.addClass('disabled');
            								break;
            							case 'red':
            								// Red is bad things
            								$this.addClass('bar-danger');
            								container = 'failed';
            								break;
            							case 'grey':
            								// Grey stuff has the info class for now
            								$this.addClass('bar-info');
            								container = 'neutral';
            								break;
            							}

                                        // Figure out the cause of this build
                                        var cause = null;
                                        for(var i = 0; i < val.lastBuild.actions.length; i++) {
                                            if (val.lastBuild.actions[i].causes) {
                                                cause = val.lastBuild.actions[i].causes[0];
                                                break;
                                            }
                                        }

                                        // If this job is running, has a trigger and the last(current) build was triggered by another job,
                                        // then we're only really building if the current build cause is a job that matches data-trigger
                                        if (building && typeof trigger != 'undefined' && trigger.length > 0) {
                                            if (cause.upstreamProject && cause.upstreamProject != trigger) {
                                                building = false;
                                            }
                                        }

            							// If we're building, do some magic
            							if(building) {
            								$this.addClass('animated');
            							}

                                        // Display info about the last completed build
                                        if (val.lastCompletedBuild) {
                                            // Display the last build number
                                            $this.find('.job-lastbuild-number').html('#' + val.lastCompletedBuild.number);

                                            // Display the last build time
                                            $this.find('.job-lastbuild-time').html(BJSInstance.parse(val.lastCompletedBuild.timestamp / 1000));
                                        }

                                        // Display or hide info about a currently running build
                                        if (building && val.lastBuild && val.lastBuild.building) {
                                            // Display some basic info
                                            $this.find('.job-currentbuild-meta').html('#' + val.lastBuild.number);

                                            // The HTML we'll use to display the cause
                                            var cause_html = '';

                                            // Figure out the type of the cause (user, SCM or upstream build)
                                            if (cause.upstreamBuild) {
                                                cause_html = ' Build #' + cause.upstreamBuild;
                                            } else if (cause.userName) {
                                                cause_html = ' ' + cause.userName;
                                            } else {
                                                cause_html = ' SCM/misc';
                                            }

                                            $this.find('.job-currentbuild-cause').html(cause_html);

                                            $this.find('.job-currentbuild-info').fadeIn();

                                        } else {
                                            $this.find('.job-currentbuild-info').fadeOut();
                                        }
            						}
            					});
            					// If no matches were found within our data, this must mean something's broken or configured incorrectly.
            					if(!matched) {
            						$this.addClass('disabled');
            					}

								queueElementMoveToContainer($this, container, building);
            				}
            			});
            		}
            	});
            }

            function toggleSidebar(open) {
                if(open) {
                    $('.sidebar').removeClass('shrink');
                    $('.content').removeClass('expand');
                }else {
                    $('.sidebar').addClass('shrink');
                    $('.content').addClass('expand');
                }
            }

            function initSidebar() {
                var sidebar_cookie = 'ganbatte_sidebar_state';
                // First, check if we should start our sidebar opened
                var sidebar_state = $.cookie(sidebar_cookie) || true;
                // Convert string to bool
                sidebar_state = typeof sidebar_state == 'string' ? (sidebar_state == 'true' ? true : false) : sidebar_state;
                // Start up the sidebar toggler
                toggleSidebar(sidebar_state);

                // Make sure we can toggle our sidebar
                $('.sidebar-toggle').click(function(e) {
                    sidebar_state = !sidebar_state;
                    // Set the sidebar cookie to the opposite value
                    $.cookie(sidebar_cookie, sidebar_state, { expires: 999, path: '/' });
                    // Call the sidebar toggler
                    toggleSidebar(sidebar_state);
                });
            }

            function initTooltips() {
                $('[rel=tooltip]').tooltip();
            }

        	function fixSidebarDimensions() {
                var $sidebar_groups = $('.sidebar-groups');

                function fixSidebarHeight() {
                    // Calculate the desired height of the groups container
                    var height = ($(window).height() - $sidebar_groups.offset().top) + 'px';
                    // Set the height
                    $sidebar_groups.css('height', height);
                }

                function fixSidebarWidth() {
                    // Hide the scrollbar by settings a negative margin-right equal to the scrollbar width
                    var scrollbar_width = '-' + getScrollBarWidth() + 'px';
                    $sidebar_groups.css('margin-right', scrollbar_width);
                }

                $(window).resize(fixSidebarHeight);
                fixSidebarHeight();

                fixSidebarWidth();
        	}

        	function switchToGroup(id) {
        		$('.sidebar-group').removeClass('active');
        		$('.sidebar-group.group-' + id) .addClass('active');
        		var $siblings = $('.group.group-' + id).siblings();
        		if($siblings.length) {
            		var first = false;
            		$('.group.group-' + id).siblings().each(function() {
            			if(!first) {
            				first = true;
            				$(this).fadeOut(function() {
            					$('.group.group-' + id).removeClass('invisible').fadeIn();
            				});
            			}else{
            				$(this).fadeOut();
            			}
            		});
        		}
        		$('.group.group-' + id).removeClass('invisible').fadeIn();
        	}

        	function moveToNextGroup() {
        		var id = $('.sidebar-group.active').data('group-id');
        		var $next = $('.group.group-' + id).next();
        		if($next.length == 0) {
        			$next = $('.group').first();
        		}
        		var next = $next.data('group-id');
        		switchToGroup(next);
        	}

            function initSidebarGroups() {
            	fixSidebarDimensions();

            	// Make sure we can switch group views
            	$('.sidebar-group').click(function() {
            		if(typeof $(this).data('group-id') != 'undefined') {
                		// Manually moving to another group turns off autoprogress
                		setAutoProgress(false);

            			switchToGroup($(this).data('group-id'));
            		}
            	});

            	// Switch to the first group with items on page load
            	if($('.group').length) {
            		switchToGroup($('.group').first().data('group-id'));
            	}
            }

            // Init Beyond.JS
            BJSInstance = new BeyondJS();

            // Init tooltips
            initTooltips();
            // Init sidebar
            initSidebar();
            // Init sidebar groups
            initSidebarGroups();
            // Init auto-progress
            initAutoProgress();
            // Init auto-refresh
            initAutoRefresh();
        }
    });
})(jQuery);<commit_msg>The sidebar should be closed by default.<commit_after>(function($) {

    // Helper function to determine browser scrollbar width
    // All credit goes to Alexandre Gomes, http://www.alexandre-gomes.com/?p=115
    function getScrollBarWidth () {
      var inner = document.createElement('p');
      inner.style.width = "100%";
      inner.style.height = "200px";

      var outer = document.createElement('div');
      outer.style.position = "absolute";
      outer.style.top = "0px";
      outer.style.left = "0px";
      outer.style.visibility = "hidden";
      outer.style.width = "200px";
      outer.style.height = "150px";
      outer.style.overflow = "hidden";
      outer.appendChild (inner);

      document.body.appendChild (outer);
      var w1 = inner.offsetWidth;
      outer.style.overflow = 'scroll';
      var w2 = inner.offsetWidth;
      if (w1 == w2) w2 = outer.clientWidth;

      document.body.removeChild (outer);

      return (w1 - w2);
    };

    $(function(){
        // Determine what page we're on
        app.page = typeof app.page != 'undefined' ? app.page : 'any';

        // Monitoring page-specific
        if(app.page == 'index') {
        	// This is where we cache the autoprogress stuff
        	var autoprogress = null;
        	var autoprogress_state = null;
            var autoprogress_cookie = 'ganbatte_autoprogress_state';

            // ... and the autorefresh stuff
            var autorefresh = null;
            var autorefresh_state = null;
            var autorefresh_cookie = 'ganbatte_autorefresh_state';

        	function setAutoProgress(state) {
    			autoprogress_state = state;
                // Set the autoprogress cookie to the opposite value
                $.cookie(autoprogress_cookie, autoprogress_state, { expires: 999, path: '/' });

                if(autoprogress_state) {
                    $('.autoprogress-toggle').addClass('active').find('i').addClass('icon-pause').removeClass('icon-play');
                    autoprogress = setInterval(moveToNextGroup, app.progress_interval * 1000);
                }else {
                    $('.autoprogress-toggle').removeClass('active').find('i').removeClass('icon-pause').addClass('icon-play');
                    if(autoprogress != null) {
                    	clearInterval(autoprogress);
                    }
                }
            }

        	function toggleAutoProgress() {
        		state = !autoprogress_state;
        		setAutoProgress(state);
        	}

            function initAutoProgress() {
                // First, check if we should enable auto progressing
                autoprogress_state = $.cookie(autoprogress_cookie) || true;
                // Convert string to bool
                autoprogress_state = typeof autoprogress_state == 'string' ? (autoprogress_state == 'true' ? true: false) : autoprogress_state;
                // Start automatically moving to the next group
                setAutoProgress(autoprogress_state);

                // Make sure we can toggle auto progress
                $('.autoprogress-toggle').click(toggleAutoProgress);
            }

        	function setAutoRefresh(state) {
    			autorefresh_state = state;
                // Set the autorefresh cookie to the opposite value
                $.cookie(autorefresh_cookie, autorefresh_state, { expires: 999, path: '/' });

                if(autorefresh_state) {
                    $('.autorefresh-toggle').addClass('active').find('i').addClass('icon-spin');
                    autorefresh = setInterval(performDataRefresh, app.refresh_interval * 1000);
                }else {
                    $('.autorefresh-toggle').removeClass('active').find('i').removeClass('icon-spin');
                    if(autorefresh != null) {
                    	clearInterval(autorefresh);
                    }
                }
            }

        	function toggleAutoRefresh() {
        		state = !autorefresh_state;
        		setAutoRefresh(state);
        	}

            function initAutoRefresh() {
                // First, check if we should enable auto refreshing
                autorefresh_state = $.cookie(autorefresh_cookie) || true;
                // Convert string to bool
                autorefresh_state = typeof autorefresh_state == 'string' ? (autorefresh_state == 'true' ? true: false) : autorefresh_state;
                // Start automatically refreshing
                setAutoRefresh(autorefresh_state);

                // Make sure we can toggle auto refresh
                $('.autorefresh-toggle').click(toggleAutoRefresh);

                // Perform one data refresh on page load, no matter what
                performDataRefresh();
            }

            function queueElementMoveToContainer($elem, container, building) {
            	$elem.data({
            		'container': container,
            		'building': building
            	});

            	// Check if all sibling jobs in this item have similar data values set.
            	// If they do, it's time to actually execute the move.
            	var ready_to_move = true;
            	$elem.siblings().each(function() {
            		var $this = $(this);
            		var this_container = $this.data('container');
            		var this_building = $this.data('building');
            		if(typeof this_container == 'undefined' || typeof this_building == 'undefined') {
            			ready_to_move = false;
            		}
            	});

            	if(ready_to_move) {
            		executeElementMoveToContainer($elem.parent().parent());
            	}
            }

            function executeElementMoveToContainer($elem) {
            	var container = 'disabled';
            	var move_to_top = false;

            	$elem.find('.job').each(function() {
            		var $this = $(this);

            		var this_container = $this.data('container');
            		var this_building = $this.data('building');

            		// Failed stuff stays in the same block
            		if(container == 'failed') {
            			this_container = 'failed';
            		}else
            		// We can only move stuff to the disabled block if all jobs of the item are disabled
            		if(container != 'disabled' && this_container == 'disabled') {
            			this_container = container;
            		}

            		container = this_container;

            		// If we're building, we should move our element to the top of its element
            		if(this_building) {
            			move_to_top = true;
            		}

            		// Remove data values
            		$this.removeData('container');
            		$this.removeData('building');

            	});

        		// If this element is already the within its container and we don't have to move stuff to the top, do nothing
            	if($elem.parent().hasClass('jobs-container-' + container) && !move_to_top) return;
            	// If we have to move stuff to the top, but this element is already the first element within its container, do nothing
            	if(move_to_top && $elem.parent().children()[0] == $elem[0]) return;
            	// If the container doesn't exist, do nothing
            	var $container = $elem.parent().parent().find('.jobs-container-' + container);
            	if(!$container.length) return;
            	// If this element is already being animated, do nothing
            	if($elem.is(':animated')) return;
            	// Fade out this element (but not completely, or we'd lose the space it occupied
            	$elem.animate({
            		'opacity': 0.000001,
            	}, function() {
            		// Next, animate height to 0
            		$elem.animate({
            			'height': 0
            		}, function() {
            			// Next, make this element the first child of its new container
            			$elem.prependTo($container);
            			// Now, animate the height again
            			$elem.animate({
            				'height': '999px'
            			}, function() {
            				// Finally, fade our element back in
            				$elem.animate({
            					'opacity': 1
            				});
            			});
            		});
            	});
            }

            function performDataRefresh() {
            	$.getJSON(app.basepath + app.jobs, function(data) {
            		if(data.length) {
            			/*
            			 * First, loop through all of our job containers. The container's 'title' attribute will tell us
            			 * what job we're looking for.
            			 */
            			$('.job').each(function() {
            				var $this = $(this);
            				var job = $this.data('job');
                            var trigger = $this.data('trigger');

            				// Only do stuff if there's a job to do stuff for
            				if(typeof job != 'undefined' && job.length > 0) {
            					// First, remove all classes that indicate statuses
            					$this.removeClass('animated').removeClass('success').removeClass('error').removeClass('disabled');
            					// Set default container to disabled, to be overriden if we can match the job
    							var container = 'disabled';
    							var building = false;

            					// Loop through our received data, and look for an object with a name that matches our title
            					var matched = false;
            					$.each(data, function(key, val) {
            						if(val.name == job) {
            							matched = true;

            							building = val.color.indexOf('_anime') != -1;
            							var color = val.color.replace('_anime', '');

            							switch(color){
            							case 'blue':
            								// Blue stands for passing builds and good things
            								$this.addClass('bar-success');
            								// Move this item to the neutral jobs container
            								container = 'neutral';
            								break;
            							case 'disabled':
            								$this.addClass('disabled');
            								break;
            							case 'red':
            								// Red is bad things
            								$this.addClass('bar-danger');
            								container = 'failed';
            								break;
            							case 'grey':
            								// Grey stuff has the info class for now
            								$this.addClass('bar-info');
            								container = 'neutral';
            								break;
            							}

                                        // Figure out the cause of this build
                                        var cause = null;
                                        for(var i = 0; i < val.lastBuild.actions.length; i++) {
                                            if (val.lastBuild.actions[i].causes) {
                                                cause = val.lastBuild.actions[i].causes[0];
                                                break;
                                            }
                                        }

                                        // If this job is running, has a trigger and the last(current) build was triggered by another job,
                                        // then we're only really building if the current build cause is a job that matches data-trigger
                                        if (building && typeof trigger != 'undefined' && trigger.length > 0) {
                                            if (cause.upstreamProject && cause.upstreamProject != trigger) {
                                                building = false;
                                            }
                                        }

            							// If we're building, do some magic
            							if(building) {
            								$this.addClass('animated');
            							}

                                        // Display info about the last completed build
                                        if (val.lastCompletedBuild) {
                                            // Display the last build number
                                            $this.find('.job-lastbuild-number').html('#' + val.lastCompletedBuild.number);

                                            // Display the last build time
                                            $this.find('.job-lastbuild-time').html(BJSInstance.parse(val.lastCompletedBuild.timestamp / 1000));
                                        }

                                        // Display or hide info about a currently running build
                                        if (building && val.lastBuild && val.lastBuild.building) {
                                            // Display some basic info
                                            $this.find('.job-currentbuild-meta').html('#' + val.lastBuild.number);

                                            // The HTML we'll use to display the cause
                                            var cause_html = '';

                                            // Figure out the type of the cause (user, SCM or upstream build)
                                            if (cause.upstreamBuild) {
                                                cause_html = ' Build #' + cause.upstreamBuild;
                                            } else if (cause.userName) {
                                                cause_html = ' ' + cause.userName;
                                            } else {
                                                cause_html = ' SCM/misc';
                                            }

                                            $this.find('.job-currentbuild-cause').html(cause_html);

                                            $this.find('.job-currentbuild-info').fadeIn();

                                        } else {
                                            $this.find('.job-currentbuild-info').fadeOut();
                                        }
            						}
            					});
            					// If no matches were found within our data, this must mean something's broken or configured incorrectly.
            					if(!matched) {
            						$this.addClass('disabled');
            					}

								queueElementMoveToContainer($this, container, building);
            				}
            			});
            		}
            	});
            }

            function toggleSidebar(open) {
                if(open) {
                    $('.sidebar').removeClass('shrink');
                    $('.content').removeClass('expand');
                }else {
                    $('.sidebar').addClass('shrink');
                    $('.content').addClass('expand');
                }
            }

            function initSidebar() {
                var sidebar_cookie = 'ganbatte_sidebar_state';
                // First, check if we should start our sidebar opened
                var sidebar_state = $.cookie(sidebar_cookie) || false;
                // Convert string to bool
                sidebar_state = typeof sidebar_state == 'string' ? (sidebar_state == 'true' ? true : false) : sidebar_state;
                // Start up the sidebar toggler
                toggleSidebar(sidebar_state);

                // Make sure we can toggle our sidebar
                $('.sidebar-toggle').click(function(e) {
                    sidebar_state = !sidebar_state;
                    // Set the sidebar cookie to the opposite value
                    $.cookie(sidebar_cookie, sidebar_state, { expires: 999, path: '/' });
                    // Call the sidebar toggler
                    toggleSidebar(sidebar_state);
                });
            }

            function initTooltips() {
                $('[rel=tooltip]').tooltip();
            }

        	function fixSidebarDimensions() {
                var $sidebar_groups = $('.sidebar-groups');

                function fixSidebarHeight() {
                    // Calculate the desired height of the groups container
                    var height = ($(window).height() - $sidebar_groups.offset().top) + 'px';
                    // Set the height
                    $sidebar_groups.css('height', height);
                }

                function fixSidebarWidth() {
                    // Hide the scrollbar by settings a negative margin-right equal to the scrollbar width
                    var scrollbar_width = '-' + getScrollBarWidth() + 'px';
                    $sidebar_groups.css('margin-right', scrollbar_width);
                }

                $(window).resize(fixSidebarHeight);
                fixSidebarHeight();

                fixSidebarWidth();
        	}

        	function switchToGroup(id) {
        		$('.sidebar-group').removeClass('active');
        		$('.sidebar-group.group-' + id) .addClass('active');
        		var $siblings = $('.group.group-' + id).siblings();
        		if($siblings.length) {
            		var first = false;
            		$('.group.group-' + id).siblings().each(function() {
            			if(!first) {
            				first = true;
            				$(this).fadeOut(function() {
            					$('.group.group-' + id).removeClass('invisible').fadeIn();
            				});
            			}else{
            				$(this).fadeOut();
            			}
            		});
        		}
        		$('.group.group-' + id).removeClass('invisible').fadeIn();
        	}

        	function moveToNextGroup() {
        		var id = $('.sidebar-group.active').data('group-id');
        		var $next = $('.group.group-' + id).next();
        		if($next.length == 0) {
        			$next = $('.group').first();
        		}
        		var next = $next.data('group-id');
        		switchToGroup(next);
        	}

            function initSidebarGroups() {
            	fixSidebarDimensions();

            	// Make sure we can switch group views
            	$('.sidebar-group').click(function() {
            		if(typeof $(this).data('group-id') != 'undefined') {
                		// Manually moving to another group turns off autoprogress
                		setAutoProgress(false);

            			switchToGroup($(this).data('group-id'));
            		}
            	});

            	// Switch to the first group with items on page load
            	if($('.group').length) {
            		switchToGroup($('.group').first().data('group-id'));
            	}
            }

            // Init Beyond.JS
            BJSInstance = new BeyondJS();

            // Init tooltips
            initTooltips();
            // Init sidebar
            initSidebar();
            // Init sidebar groups
            initSidebarGroups();
            // Init auto-progress
            initAutoProgress();
            // Init auto-refresh
            initAutoRefresh();
        }
    });
})(jQuery);<|endoftext|>


<commit_before>var extra = (function() {

	var saveDocElement;

	// DOM elements
	var allElements = [];
	var allElementsField = [];

	function init() {

		bindElements();
		//loadHistoryData('../../app/data/index/1383055390.json');

		// Load state if storage is supported
		if ( ! supportsHtmlStorage() ) {
			loadHistoryData('../../app/data/index/1383055390.json'); // load json file
		}

		return findElementsEditable();
	}

	function bindElements() {

		saveDocElement = document.querySelector( '.saveDoc' );
		saveDocElement.onclick = onSaveDoc;

	}

	/* Find element editable and options */
	function findElementsEditable() {

		$('*[contenteditable=true]').each(function() {

			var classNames = $(this).attr('class');
			var className = classNames.split(" ",1);

			allElements.push('.' + className);
			allElementsField.push(document.querySelector( '.' + className ));
			if($(this).data('type') =="oneline") {
				document.querySelector('.' + className).onkeypress = onelineKeyPress;
			}

		});

		return config(allElements,allElementsField);
	}

	function onelineKeyPress( event ) {

		if ( event.keyCode === 13 ) {
			event.preventDefault();
		}
	}

	function config(a, b) {
		return {
			allElements: a,
			allElementsField: b
		};
	}

	function localstorageToJson() {
		return JSON.stringify(localStorage);
	}

	function onSaveDoc( event ) {

		//console.log(JSON.stringify(localStorage));

		var request = $.ajax({
			url: Conf.url +"history.php",
			type: "POST",
			data: { data : JSON.stringify(localStorage, null, '\t'), model : Conf.model, id : Conf.id },
			dataType: "html"
		});

		request.done(function( msg ) {
			console.log( msg );
		});

		request.fail(function( jqXHR, textStatus ) {
			console.log( "Request failed: " + textStatus );
		});

	}

	function preState( v ){
		return v.slice(1);
	}

	function loadHistoryData( file ) {

		$.getJSON( file , function( json ) {
			$.each( json, function( i, value ) {
				localStorage[i] = value;
			});

			// dynamic
			for (var i = allElements.length - 1; i >= 0; i--) {

				if(localStorage[preState(allElements[i])]) {
					allElementsField[i].innerHTML = localStorage[preState(allElements[i])];
				}

			};
		});
	}

	return {
		init: init
	};

})();

// Utility functions

String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g, ''); };

function supportsHtmlStorage() {
	try {
		return 'localStorage' in window && window['localStorage'] !== null;
	} catch (e) {
		return false;
	}
}<commit_msg>activ panel on click + load json history + load one json<commit_after>var extra = (function() {

	var saveDocElement;

	// DOM elements
	var allElements = [];
	var allElementsField = [];

	function init() {

		bindElements();
		//loadHistoryData('../../app/data/index/1383055390.json');

		// Load state if storage is supported
		if ( ! supportsHtmlStorage() ) {
			loadHistoryData('../../app/data/index/1383055390.json'); // load json file
		}

		return findElementsEditable();
	}

	function bindElements() {

		saveDocElement = document.querySelector( '.saveDoc' );
		saveDocElement.onclick = onSaveDoc;

		$('#simple-menu').sidr({side: 'right'});
	    $('#simple-menu').on('mouseover', getJsonHistory());

	}

	/* Find element editable and options */
	function findElementsEditable() {

		$('*[contenteditable=true]').each(function() {

			var classNames = $(this).attr('class');
			var className = classNames.split(" ",1);

			allElements.push('.' + className);
			allElementsField.push(document.querySelector( '.' + className ));
			if($(this).data('type') =="oneline") {
				document.querySelector('.' + className).onkeypress = onelineKeyPress;
			}

		});

		return config(allElements,allElementsField);
	}

	function onelineKeyPress( event ) {

		if ( event.keyCode === 13 ) {
			event.preventDefault();
		}
	}

	function config(a, b) {
		return {
			allElements: a,
			allElementsField: b
		};
	}

	function localstorageToJson() {
		return JSON.stringify(localStorage);
	}

	function onSaveDoc( event ) {

		//console.log(JSON.stringify(localStorage));

		var request = $.ajax({
			url: Conf.url +"history.php",
			type: "POST",
			data: { data : JSON.stringify(localStorage, null, '\t'), model : Conf.model, id : Conf.id },
			dataType: "html"
		});

		request.done(function( msg ) {
			console.log( msg );
			// get new history
			getJsonHistory();
		});

		request.fail(function( jqXHR, textStatus ) {
			console.log( "Request failed: " + textStatus );
		});

	}

	function preState( v ){
		return v.slice(1);
	}

	function loadHistoryData( file ) {

		$.getJSON( Conf.url +"history.php" , { model : Conf.model, id : Conf.id, file : file, method : 'one' }, function( json ) {
			$.each( json, function( i, value ) {
				localStorage[i] = value;
			});

			// dynamic
			for (var i = allElements.length - 1; i >= 0; i--) {

				if(localStorage[preState(allElements[i])]) {
					allElementsField[i].innerHTML = localStorage[preState(allElements[i])];
				}

			};
		});
	}

	function getJsonHistory() {

		$("#sidr-model").html(Conf.model);
		if (Conf.id) { $("#sidr-page").html(Conf.id); };

		$.ajax({
			url: Conf.url +"history.php",
			type: "GET",
			data: { model : Conf.model, id : Conf.id, method: 'list'},
			dataType: "html"
			}).done(function( msg ) {

				$("#sidr-history").html( msg );
				$("#sidr-history li").on('click',function() {
					loadHistoryData($(this).html());
			    });

		});
	}

	return {
		init: init
	};

})();

// Utility functions

String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g, ''); };

function supportsHtmlStorage() {
	try {
		return 'localStorage' in window && window['localStorage'] !== null;
	} catch (e) {
		return false;
	}
}<|endoftext|>


<commit_before>const mongoose = require('mongoose');

const Schema = mongoose.Schema;

/*
    userMsg model
 */

const userMsgSchema = new Schema({
  userId: {type: Schema.Types.ObjectId, required: true, ref: 'user'},
  likeMsgId: [String],
  followMsgId: [String],
  leaveMsgId: [String],
  noticeMsgId: [String],
  chatMsg: [{
    chatUserId: {type: Schema.Types.ObjectId, required: true, ref: 'user'},
    chatContent: {type: String, default: ''},
    chatCreateTime: {type: Date, default: Date.now()}
  }]
});

module.exports = mongoose.model('userMsg', userMsgSchema);
<commit_msg>Schema<commit_after>const mongoose = require('mongoose');

const Schema = mongoose.Schema;

/*
    userMsg model
 */

const userMsgSchema = new Schema({
  userId: {type: Schema.Types.ObjectId, required: true, ref: 'user'},
  unreadLikeMsgNum: {Type: Number, default: 0},
  unreadFollowMsgNum: {Type: Number, default: 0},
  unreadLeaveMsgNum: {Type: Number, default: 0},
  unreadNoticeMsgNum: {Type: Number, default: 0},
  chatMsg: [{
    chatUserId: {type: Schema.Types.ObjectId, required: true, ref: 'user'},
    chatContent: {type: String, default: ''},
    chatCreateTime: {type: Date, default: Date.now()}
  }]
});

module.exports = mongoose.model('userMsg', userMsgSchema);
<|endoftext|>


<commit_before>/**
 * @class CM_FormField_Location
 * @extends CM_FormField_SuggestOne
 */
var CM_FormField_Location = CM_FormField_SuggestOne.extend({
  _class: 'CM_FormField_Location',

  events: {
    'click .detectLocation': 'detectLocation'
  },

  ready: function() {
    CM_FormField_SuggestOne.prototype.ready.call(this);

    this.on('change', function() {
      this.updateDistanceField();
    }, this);
    var self = this;
    this.getDistanceField().on('ready', function() {
      self.updateDistanceField();
    });
  },

  /**
   * @returns {CM_FormField_Integer|Null}
   */
  getDistanceField: function() {
    if (!this.getOption("distanceName")) {
      return null;
    }
    return this.getForm().getField(this.getOption("distanceName"));
  },

  updateDistanceField: function() {
    if (this.getDistanceField()) {
      var distanceEnabled = false;
      var value = this.getValue();
      if (value) {
        distanceEnabled = value.level >= this.getOption("distanceLevelMin");
      }
      this.getDistanceField().setDisabled(!distanceEnabled);
    }
  },

  /**
   * @return {Object}
   */
  getValue: function() {
    return CM_FormField_SuggestOne.prototype.getValue.call(this);
  },

  /**
   * @param {Object} value
   */
  setValue: function(value) {
    return CM_FormField_SuggestOne.prototype.setValue.call(this, value);
  },

  /**
   * @returns {Promise}
   */
  detectLocation: function() {
    if (!'geolocation' in navigator) {
      throw new CM_Exception('Geolocation support unavailable');
    }
    this.$('.detect-location').addClass('waiting');

    var self = this;

    return new Promise(function(resolve, reject) {
      navigator.geolocation.getCurrentPosition(resolve, reject);
    })
      .then(function(position) {
        return self._lookupCoordinates(position.coords.latitude, position.coords.longitude);
      })
      .then(function(data) {
        if (data) {
          self.setValue(data);
        }
      })
      .catch(function(error) {
        self.error(cm.language.get('Unable to detect location'));
      })
      .finally(function() {
        self.$('.detect-location').removeClass('waiting');
      });
  },

  /**
   * @param {Number} lat
   * @param {Number} lon
   * @return {Promise}
   */
  _lookupCoordinates: function(lat, lon) {
    return this.ajax('getSuggestionByCoordinates', {lat: lat, lon: lon, levelMin: this.getOption('levelMin'), levelMax: this.getOption('levelMax')});
  }
});
<commit_msg>Fix Location's Distance detection.<commit_after>/**
 * @class CM_FormField_Location
 * @extends CM_FormField_SuggestOne
 */
var CM_FormField_Location = CM_FormField_SuggestOne.extend({
  _class: 'CM_FormField_Location',

  events: {
    'click .detectLocation': 'detectLocation'
  },

  ready: function() {
    CM_FormField_SuggestOne.prototype.ready.call(this);

    if (this.getDistanceField()) {
      this.on('change', function() {
        this.updateDistanceField();
      }, this);
      var self = this;

      this.getDistanceField().on('ready', function() {
        self.updateDistanceField();
      });
    }
  },

  /**
   * @returns {CM_FormField_Integer|Null}
   */
  getDistanceField: function() {
    if (!this.getOption("distanceName")) {
      return null;
    }
    return this.getForm().getField(this.getOption("distanceName"));
  },

  updateDistanceField: function() {
    if (this.getDistanceField()) {
      var distanceEnabled = false;
      var value = this.getValue();
      if (value) {
        distanceEnabled = value.level >= this.getOption("distanceLevelMin");
      }
      this.getDistanceField().setDisabled(!distanceEnabled);
    }
  },

  /**
   * @return {Object}
   */
  getValue: function() {
    return CM_FormField_SuggestOne.prototype.getValue.call(this);
  },

  /**
   * @param {Object} value
   */
  setValue: function(value) {
    return CM_FormField_SuggestOne.prototype.setValue.call(this, value);
  },

  /**
   * @returns {Promise}
   */
  detectLocation: function() {
    if (!'geolocation' in navigator) {
      throw new CM_Exception('Geolocation support unavailable');
    }
    this.$('.detect-location').addClass('waiting');

    var self = this;

    return new Promise(function(resolve, reject) {
      navigator.geolocation.getCurrentPosition(resolve, reject);
    })
      .then(function(position) {
        return self._lookupCoordinates(position.coords.latitude, position.coords.longitude);
      })
      .then(function(data) {
        if (data) {
          self.setValue(data);
        }
      })
      .catch(function(error) {
        self.error(cm.language.get('Unable to detect location'));
      })
      .finally(function() {
        self.$('.detect-location').removeClass('waiting');
      });
  },

  /**
   * @param {Number} lat
   * @param {Number} lon
   * @return {Promise}
   */
  _lookupCoordinates: function(lat, lon) {
    return this.ajax('getSuggestionByCoordinates', {lat: lat, lon: lon, levelMin: this.getOption('levelMin'), levelMax: this.getOption('levelMax')});
  }
});
<|endoftext|>