<commit_before>import moment from 'moment';

Meteor.methods({
  checkIfResidentWasActiveOnDate (residentId, date) {
    // Create morning and evening dates (Date objects)
    // in order to query activities for date
    const morning = moment(date).startOf('day').toDate();
    const evening = moment(date).endOf('day').toDate();

    // Check if resident has (at least one) recorded activity on that day (date)
    const residentActiveOnDate = Activities.findOne({
      // Make sure resident ID in resident IDs array
      residentIds: {
        $elemMatch: { $eq: residentId }
      },
      // Make sure activity recorded on desired date
      activityDate: {
        $gte: morning,
        $lte: evening,
      }
    });

    // Return the (boolean) value indicating whether resident was active on date
    // note: we make sure we got a document back by comparing against undefined
    return (residentActiveOnDate != undefined);
  },
  getResidentRecentActiveDaysCount (residentId, date = new Date()) {
    /*
    Get count of recent days (within past seven days) where resident was active
    */

    // Initialize counter for resident active days
    let activeDaysCount = 0;

    // Date one week ago
    const startDate = moment(date).subtract(1, 'weeks');

    // Get a date object for the end of day today
    const endDate = moment(date).endOf('day');

    // For each of the days in the past week,
    // check whether the user was active
    // increment 'active days' count for each active day
    for (let currentDay = moment(startDate); currentDay.isBefore(endDate); currentDay.add(1, 'day')) {
      // Check whether resident was active on current day
      const residentWasActive = Meteor.call('checkIfResidentWasActiveOnDate', residentId, currentDay.toDate());

      if (residentWasActive) {
        // Add one to active days count
        activeDaysCount += 1;
      }
    }

    return activeDaysCount;
  },
});
<commit_msg>Count number of resident activities on date<commit_after>import moment from 'moment';

Meteor.methods({
  checkIfResidentWasActiveOnDate (residentId, date) {
    // Create morning and evening dates (Date objects)
    // in order to query activities for date
    const morning = moment(date).startOf('day').toDate();
    const evening = moment(date).endOf('day').toDate();

    // Count the number of activities recorded for the resident on the given date
    const residentActivityCountOnDate = Activities.find({
      // Make sure resident ID in resident IDs array
      residentIds: {
        $elemMatch: { $eq: residentId }
      },
      // Make sure activity recorded on desired date
      activityDate: {
        $gte: morning,
        $lte: evening,
      }
    }).count();

    // Return the (boolean) value indicating whether resident was active on date
    // note: we are checking that the activity count is greater than zero
    return (residentActivityCountOnDate > 0);
  },
  getResidentRecentActiveDaysCount (residentId, date = new Date()) {
    /*
    Get count of recent days (within past seven days) where resident was active
    */

    // Initialize counter for resident active days
    let activeDaysCount = 0;

    // Date one week ago
    const startDate = moment(date).subtract(1, 'weeks');

    // Get a date object for the end of day today
    const endDate = moment(date).endOf('day');

    // For each of the days in the past week,
    // check whether the user was active
    // increment 'active days' count for each active day
    for (let currentDay = moment(startDate); currentDay.isBefore(endDate); currentDay.add(1, 'day')) {
      // Check whether resident was active on current day
      const residentWasActive = Meteor.call('checkIfResidentWasActiveOnDate', residentId, currentDay.toDate());

      if (residentWasActive) {
        // Add one to active days count
        activeDaysCount += 1;
      }
    }

    return activeDaysCount;
  },
});
<|endoftext|>


<commit_before>import got from 'got';
import WordResearch from '../dto/WordResearch';

const WORD_TYPE_VERB = 'Verb';
const WORD_TYPE_NOUN = 'Substantiv';
const wordTypes = [WORD_TYPE_VERB, WORD_TYPE_NOUN];

// @TODO extract/inject language-specific rules as adapter/strategy

class WiktionaryService {
  constructor() {
    this.languageShort = 'de';
  }

  async fetchRawData(word) {
    const getUri = query => `https://${this.languageShort}.wiktionary.org/w/api.php?format=json&action=parse&prop=wikitext|categories|parsetree&redirects=1&contentmodel=wikitext&page=${query}`;
    const wiktionaryResponse = await got(getUri(word), { json: true });
    const error = wiktionaryResponse.body.error;
    if (error) {
      throw new Error(`Error fetching word data: ${error.info}`);
    }

    return wiktionaryResponse.body;
  }

  async getWord(word) {
    const wordData = await this.fetchRawData(word);
    const wikitext = wordData.parse.wikitext['*'];
    const wordType = WiktionaryService.getWordType(wikitext);

    if (!wordTypes.includes(wordType)) {
      throw new Error(`Unknown word type: ${wordType}`);
    }

    const wordResearch = new WordResearch();
    wordResearch.wordDe = WiktionaryService.getWordDe(wikitext);
    wordResearch.wordEn = WiktionaryService.getWordEn(wikitext);
    wordResearch.wordType = WiktionaryService.getWordType(wikitext);
    wordResearch.lautschrift = WiktionaryService.getLautschrift(wikitext);
    wordResearch.verbPresentThirdPerson = wordType === WORD_TYPE_VERB ? WiktionaryService.getVerbPresentThirdPerson(wikitext) : null;
    wordResearch.verbPreteriteFirstPerson = wordType === WORD_TYPE_VERB ? WiktionaryService.getVerbPreteriteFirstPerson(wikitext) : null;
    wordResearch.verbPreteriteThirdPerson = wordType === WORD_TYPE_VERB ? WiktionaryService.getVerbPreteriteFirstPerson(wikitext) : null; // we take 1st person, as it seems to be the same as 3rd person most of the time
    wordResearch.verbPerfectAuxiliaryThird = wordType === WORD_TYPE_VERB ? WiktionaryService.getVerbPerfectAuxiliaryThirdPerson(wikitext) : null;
    wordResearch.verbPastParticiple = wordType === WORD_TYPE_VERB ? WiktionaryService.getVerbPastParticiple(wikitext) : null;
    wordResearch.nounArticle = wordType === WORD_TYPE_NOUN ? WiktionaryService.getNounArticle(wikitext) : null;
    wordResearch.nounPlural = wordType === WORD_TYPE_NOUN ? WiktionaryService.getNounPlural(wikitext) : null;
    wordResearch.nounGender = wordType === WORD_TYPE_NOUN ? WiktionaryService.getNounGender(wikitext) : null;
    wordResearch.usages = WiktionaryService.getExamples(wikitext, this.languageShort) || [];

    return wordResearch;
  }

  static getWordType(wikitext) {
    return wikitext.match(/{{Wortart\|(\w+)\|Deutsch}}/)[1];
  }

  static getWordDe(wikitext) {
    return wikitext.match(/== ([A-zÀ-ÿ]+) \({{Sprache\|Deutsch}}\)/)[1]; // match accented words
  }

  static getWordEn(wikitext) {
    const senses = WiktionaryService.getSenses(wikitext).map(sense => sense.value);

    return senses.join(', ');
  }

  static getLautschrift(wikitext) {
    return wikitext.match(/{{Lautschrift\|(\S+)}}\n/i)[1];
  }

  static getVerbPresentThirdPerson(wikitext) {
    return wikitext.match(/\|Präsens_er, sie, es=([A-zÀ-ÿ ]+)\n\|/i)[1];
  }

  static getVerbPreteriteFirstPerson(wikitext) {
    return wikitext.match(/\|Präteritum_ich=([A-zÀ-ÿ ]+)\n\|/i)[1];
  }

  static getVerbPerfectAuxiliaryThirdPerson(wikitext) {
    const auxilaryVerb = wikitext.match(/\|Hilfsverb=(\w+)\n}}/i)[1];
    return auxilaryVerb === 'haben' ? 'hat' : 'ist';
  }

  static getVerbPastParticiple(wikitext) {
    return wikitext.match(/\|Partizip II=([A-zÀ-ÿ ]+)\n\|/i)[1];
  }

  static getNounArticle(wikitext) {
    const genusToArticle = {
      m: 'der',
      f: 'die',
      n: 'das',
    };
    return genusToArticle[WiktionaryService.getNounGender(wikitext)];
  }

  static getNounPlural(wikitext) {
    return wikitext.match(/\|Nominativ Plural=([A-zÀ-ÿ ]+)\n\|/i)[1];
  }

  static getNounGender(wikitext) {
    return wikitext.match(/\|Genus=(\w+)\n\|/i)[1];
  }

  static getSenses(wikitext) {
    const mathedSenses = wikitext.match(/\[\d+] {{Ü\|en\|[\w\s]+}}/g);

    return mathedSenses.map(raw => {
      const matches = raw.match(/(\[\d+]) {{Ü\|en\|([\w\s]+)}}/);
      return {
        id: matches[1],
        value: matches[2],
      };
    });
  }

  static removeTagAndContents(text, tag) {
    const re = new RegExp(`<${tag}>.+?<\\/${tag}>`, 'g');

    return text.replace(re, '');
  }

  static getExamples(wikitext, languageShort) {
    const examplesContainer = WiktionaryService
      .removeTagAndContents(wikitext, 'ref') // remove quote references
      .replace(/{{Beispiele fehlen\|spr=de}}/, '') // clean "empty" example, as we use '^{' in the regex below
      .match(/{{Beispiele}}\n:([^{]+)/i); // match until next '{'
    const examples = examplesContainer[1].split('\n:');

    const examplesStructured = examples
      .map(exampleRaw => {
        const matches = exampleRaw.match(/(\[\d+]) (.+)/);

        if (!matches) {
          return null; // sometimes we get empty examples (e.g. when cleaned above)
        }

        return {
          sense: matches[1],
          value: matches[2],
        };
      })
      .filter(example => !!example); // remove empty

    return examplesStructured
      .map(example => { // eslint-disable-line arrow-body-style
        return {
          [languageShort]: example.value,
        };
      });
  }
}

export default WiktionaryService;
<commit_msg>[trivial] updated wiktionaryService todo<commit_after>import got from 'got';
import WordResearch from '../dto/WordResearch';

const WORD_TYPE_VERB = 'Verb';
const WORD_TYPE_NOUN = 'Substantiv';
const wordTypes = [WORD_TYPE_VERB, WORD_TYPE_NOUN];

// @TODO extract/inject language-specific rules as adapter/strategy/config

class WiktionaryService {
  constructor() {
    this.languageShort = 'de';
  }

  async fetchRawData(word) {
    const getUri = query => `https://${this.languageShort}.wiktionary.org/w/api.php?format=json&action=parse&prop=wikitext|categories|parsetree&redirects=1&contentmodel=wikitext&page=${query}`;
    const wiktionaryResponse = await got(getUri(word), { json: true });
    const error = wiktionaryResponse.body.error;
    if (error) {
      throw new Error(`Error fetching word data: ${error.info}`);
    }

    return wiktionaryResponse.body;
  }

  async getWord(word) {
    const wordData = await this.fetchRawData(word);
    const wikitext = wordData.parse.wikitext['*'];
    const wordType = WiktionaryService.getWordType(wikitext);

    if (!wordTypes.includes(wordType)) {
      throw new Error(`Unknown word type: ${wordType}`);
    }

    const wordResearch = new WordResearch();
    wordResearch.wordDe = WiktionaryService.getWordDe(wikitext);
    wordResearch.wordEn = WiktionaryService.getWordEn(wikitext);
    wordResearch.wordType = WiktionaryService.getWordType(wikitext);
    wordResearch.lautschrift = WiktionaryService.getLautschrift(wikitext);
    wordResearch.verbPresentThirdPerson = wordType === WORD_TYPE_VERB ? WiktionaryService.getVerbPresentThirdPerson(wikitext) : null;
    wordResearch.verbPreteriteFirstPerson = wordType === WORD_TYPE_VERB ? WiktionaryService.getVerbPreteriteFirstPerson(wikitext) : null;
    wordResearch.verbPreteriteThirdPerson = wordType === WORD_TYPE_VERB ? WiktionaryService.getVerbPreteriteFirstPerson(wikitext) : null; // we take 1st person, as it seems to be the same as 3rd person most of the time
    wordResearch.verbPerfectAuxiliaryThird = wordType === WORD_TYPE_VERB ? WiktionaryService.getVerbPerfectAuxiliaryThirdPerson(wikitext) : null;
    wordResearch.verbPastParticiple = wordType === WORD_TYPE_VERB ? WiktionaryService.getVerbPastParticiple(wikitext) : null;
    wordResearch.nounArticle = wordType === WORD_TYPE_NOUN ? WiktionaryService.getNounArticle(wikitext) : null;
    wordResearch.nounPlural = wordType === WORD_TYPE_NOUN ? WiktionaryService.getNounPlural(wikitext) : null;
    wordResearch.nounGender = wordType === WORD_TYPE_NOUN ? WiktionaryService.getNounGender(wikitext) : null;
    wordResearch.usages = WiktionaryService.getExamples(wikitext, this.languageShort) || [];

    return wordResearch;
  }

  static getWordType(wikitext) {
    return wikitext.match(/{{Wortart\|(\w+)\|Deutsch}}/)[1];
  }

  static getWordDe(wikitext) {
    return wikitext.match(/== ([A-zÀ-ÿ]+) \({{Sprache\|Deutsch}}\)/)[1]; // match accented words
  }

  static getWordEn(wikitext) {
    const senses = WiktionaryService.getSenses(wikitext).map(sense => sense.value);

    return senses.join(', ');
  }

  static getLautschrift(wikitext) {
    return wikitext.match(/{{Lautschrift\|(\S+)}}\n/i)[1];
  }

  static getVerbPresentThirdPerson(wikitext) {
    return wikitext.match(/\|Präsens_er, sie, es=([A-zÀ-ÿ ]+)\n\|/i)[1];
  }

  static getVerbPreteriteFirstPerson(wikitext) {
    return wikitext.match(/\|Präteritum_ich=([A-zÀ-ÿ ]+)\n\|/i)[1];
  }

  static getVerbPerfectAuxiliaryThirdPerson(wikitext) {
    const auxilaryVerb = wikitext.match(/\|Hilfsverb=(\w+)\n}}/i)[1];
    return auxilaryVerb === 'haben' ? 'hat' : 'ist';
  }

  static getVerbPastParticiple(wikitext) {
    return wikitext.match(/\|Partizip II=([A-zÀ-ÿ ]+)\n\|/i)[1];
  }

  static getNounArticle(wikitext) {
    const genusToArticle = {
      m: 'der',
      f: 'die',
      n: 'das',
    };
    return genusToArticle[WiktionaryService.getNounGender(wikitext)];
  }

  static getNounPlural(wikitext) {
    return wikitext.match(/\|Nominativ Plural=([A-zÀ-ÿ ]+)\n\|/i)[1];
  }

  static getNounGender(wikitext) {
    return wikitext.match(/\|Genus=(\w+)\n\|/i)[1];
  }

  static getSenses(wikitext) {
    const mathedSenses = wikitext.match(/\[\d+] {{Ü\|en\|[\w\s]+}}/g);

    return mathedSenses.map(raw => {
      const matches = raw.match(/(\[\d+]) {{Ü\|en\|([\w\s]+)}}/);
      return {
        id: matches[1],
        value: matches[2],
      };
    });
  }

  static removeTagAndContents(text, tag) {
    const re = new RegExp(`<${tag}>.+?<\\/${tag}>`, 'g');

    return text.replace(re, '');
  }

  static getExamples(wikitext, languageShort) {
    const examplesContainer = WiktionaryService
      .removeTagAndContents(wikitext, 'ref') // remove quote references
      .replace(/{{Beispiele fehlen\|spr=de}}/, '') // clean "empty" example, as we use '^{' in the regex below
      .match(/{{Beispiele}}\n:([^{]+)/i); // match until next '{'
    const examples = examplesContainer[1].split('\n:');

    const examplesStructured = examples
      .map(exampleRaw => {
        const matches = exampleRaw.match(/(\[\d+]) (.+)/);

        if (!matches) {
          return null; // sometimes we get empty examples (e.g. when cleaned above)
        }

        return {
          sense: matches[1],
          value: matches[2],
        };
      })
      .filter(example => !!example); // remove empty

    return examplesStructured
      .map(example => { // eslint-disable-line arrow-body-style
        return {
          [languageShort]: example.value,
        };
      });
  }
}

export default WiktionaryService;
<|endoftext|>


<commit_before>require('../../support/test_helper');

var assert = require('../../support/assert');
var TestClient = require('../../support/test-client');

describe('histogram-dataview', function() {

    afterEach(function(done) {
        if (this.testClient) {
            this.testClient.drain(done);
        } else {
            done();
        }
    });

    function createMapConfig(layers, dataviews, analysis) {
        return {
            version: '1.5.0',
            layers: layers,
            dataviews: dataviews || {},
            analyses: analysis || []
        };
    }

    var mapConfig = createMapConfig(
        [
            {
                "type": "cartodb",
                "options": {
                    "source": {
                        "id": "2570e105-7b37-40d2-bdf4-1af889598745"
                    },
                    "cartocss": "#points { marker-width: 10; marker-fill: red; }",
                    "cartocss_version": "2.3.0"
                }
            }
        ],
        {
            pop_max_histogram: {
                source: {
                    id: '2570e105-7b37-40d2-bdf4-1af889598745'
                },
                type: 'histogram',
                options: {
                    column: 'x'
                }
            }
        },
        [
            {
                "id": "2570e105-7b37-40d2-bdf4-1af889598745",
                "type": "source",
                "params": {
                    "query": "select null::geometry the_geom_webmercator, x from generate_series(0,1000) x"
                }
            }
        ]
    );

    it('should get bin_width right when max > min in filter', function(done) {
        var params = {
            bins: 10,
            start: 1e3,
            end: 0
        };

        this.testClient = new TestClient(mapConfig, 1234);
        this.testClient.getDataview('pop_max_histogram', params, function(err, dataview) {
            assert.ok(!err, err);

            assert.equal(dataview.type, 'histogram');
            assert.ok(dataview.bin_width > 0, 'Unexpected bin width: ' + dataview.bin_width);
            dataview.bins.forEach(function(bin) {
                assert.ok(bin.min <= bin.max, 'bin min < bin max: ' + JSON.stringify(bin));
            });

            done();
        });
    });

    it('should cast all overridable params to numbers', function(done) {
        var params = {
            bins: '256 AS other, (select 256 * 2) AS bins_number--',
            start: 1e3,
            end: 0,
            response: TestClient.RESPONSE.ERROR
        };

        this.testClient = new TestClient(mapConfig, 1234);
        this.testClient.getDataview('pop_max_histogram', params, function(err, res) {
            assert.ok(!err, err);

            assert.ok(res.errors);
            assert.equal(res.errors.length, 1);
            assert.ok(res.errors[0].match(/Invalid number format for parameter 'bins'/));

            done();
        });
    });
});
<commit_msg>Histogram going red: fails while quering Infinity and NanN values<commit_after>require('../../support/test_helper');

var assert = require('../../support/assert');
var TestClient = require('../../support/test-client');

function createMapConfig(layers, dataviews, analysis) {
    return {
        version: '1.5.0',
        layers: layers,
        dataviews: dataviews || {},
        analyses: analysis || []
    };
}

describe('histogram-dataview', function() {

    afterEach(function(done) {
        if (this.testClient) {
            this.testClient.drain(done);
        } else {
            done();
        }
    });

    var mapConfig = createMapConfig(
        [
            {
                "type": "cartodb",
                "options": {
                    "source": {
                        "id": "2570e105-7b37-40d2-bdf4-1af889598745"
                    },
                    "cartocss": "#points { marker-width: 10; marker-fill: red; }",
                    "cartocss_version": "2.3.0"
                }
            }
        ],
        {
            pop_max_histogram: {
                source: {
                    id: '2570e105-7b37-40d2-bdf4-1af889598745'
                },
                type: 'histogram',
                options: {
                    column: 'x'
                }
            }
        },
        [
            {
                "id": "2570e105-7b37-40d2-bdf4-1af889598745",
                "type": "source",
                "params": {
                    "query": "select null::geometry the_geom_webmercator, x from generate_series(0,1000) x"
                }
            }
        ]
    );

    it('should get bin_width right when max > min in filter', function(done) {
        var params = {
            bins: 10,
            start: 1e3,
            end: 0
        };

        this.testClient = new TestClient(mapConfig, 1234);
        this.testClient.getDataview('pop_max_histogram', params, function(err, dataview) {
            assert.ok(!err, err);

            assert.equal(dataview.type, 'histogram');
            assert.ok(dataview.bin_width > 0, 'Unexpected bin width: ' + dataview.bin_width);
            dataview.bins.forEach(function(bin) {
                assert.ok(bin.min <= bin.max, 'bin min < bin max: ' + JSON.stringify(bin));
            });

            done();
        });
    });

    it('should cast all overridable params to numbers', function(done) {
        var params = {
            bins: '256 AS other, (select 256 * 2) AS bins_number--',
            start: 1e3,
            end: 0,
            response: TestClient.RESPONSE.ERROR
        };

        this.testClient = new TestClient(mapConfig, 1234);
        this.testClient.getDataview('pop_max_histogram', params, function(err, res) {
            assert.ok(!err, err);
            assert.ok(res.errors);
            assert.equal(res.errors.length, 1);
            assert.ok(res.errors[0].match(/Invalid number format for parameter 'bins'/));

            done();
        });
    });
});

describe('histogram-dataview: special float valuer', function() {

    afterEach(function(done) {
        if (this.testClient) {
            this.testClient.drain(done);
        } else {
            done();
        }
    });

    var mapConfig = createMapConfig(
        [
            {
                "type": "cartodb",
                "options": {
                    "source": {
                        "id": "a0"
                    },
                    "cartocss": "#points { marker-width: 10; marker-fill: red; }",
                    "cartocss_version": "2.3.0"
                }
            }
        ],
        {
            val_histogram: {
                source: {
                    id: 'a0'
                },
                type: 'histogram',
                options: {
                    column: 'val'
                }
            }
        },
        [
            {
                "id": "a0",
                "type": "source",
                "params": {
                    "query": [
                        'SELECT',
                        '  null::geometry the_geom_webmercator,',
                        '  CASE',
                        '    WHEN x % 4 = 0 THEN \'infinity\'::float',
                        '    WHEN x % 4 = 1 THEN \'-infinity\'::float',
                        '    WHEN x % 4 = 2 THEN \'NaN\'::float',
                        '    ELSE x',
                        '  END AS val',
                        'FROM generate_series(1, 1000) x'
                    ].join('\n')
                }
            }
        ]
    );

    it('should filter infinities out and count them in the summary', function(done) {
        this.testClient = new TestClient(mapConfig, 1234);
        this.testClient.getDataview('val_histogram', {}, function(err, dataview) {
            assert.ok(!err, err);
            assert.ok(dataview.infinities === (250 + 250));
            assert.ok(dataview.nans === 250);
            done();
        });
    });
});
<|endoftext|>


<commit_before>var iso19139 = require('iso19139');
var moment = require('moment');
var async = require('async');
var _ = require('lodash');

var mongoose = require('../../mongoose');
var jobs = require('../../kue').jobs;

var PersistedCswRecord = mongoose.model('CswRecord');

/*
** Constructor
*/
function CswRecord(xmlElement, job) {
    if (!xmlElement) throw new Error('xmlElement is not defined');
    if (!job) throw new Error('job is not defined');

    this.xmlElement = xmlElement;
    this.recordName = xmlElement.name();
    this.job = job;
    this.parse();
}

/*
** Methods
*/
CswRecord.prototype.parse = function () {
    if (!this.xmlElement) throw new Error('xmlElement is not defined');

    if (this.recordName === 'MD_Metadata') {
        this.parsedRecord = iso19139.parse(this.xmlElement);
    } else {
        this.status = 'not-parsed';
        this.cleanXml();
    }
};

CswRecord.prototype.cleanXml = function () {
    this.xmlElement = null;
};

CswRecord.prototype.isValid = function () {
    if (!this.parsedRecord) return false;

    var record = this;

    function notValid() {
        record.status = 'not-valid';
        return false;
    }

    if (!this.parsedRecord.fileIdentifier) {
        this.job.log('[WARN] Dropping 1 record: no fileIdentifier set!');
        return notValid();
    }

    if (this.parsedRecord.fileIdentifier.length > 256) {
        this.job.log('[WARN] Dropping 1 record: fileIdentifier too long!');
        return notValid();
    }

    if (!this.parsedRecord._updated) {
        this.job.log('[WARN] Dropping 1 record: no dateStamp set!');
        return notValid();
    }

    if (!_.isDate(Date.parse(this.parsedRecord._updated))) {
        this.job.log('[WARN] Dropping 1 record: dateStamp not valid!');
        return notValid();
    }

    return true;
};

CswRecord.prototype.timestamp = function () {
    return moment(this.parsedRecord._updated).toDate();
};

CswRecord.prototype.updateCurrentRecord = function (done) {
    var query = {
        parentCatalog: this.job.service._id,
        identifier: this.parsedRecord.fileIdentifier,
        timestamp: this.timestamp()
    };

    var update = { $push: { synchronizations: this.job.id } };

    var job = this.job;
    var record = this;

    PersistedCswRecord.update(query, update, function (err, nModified) {
        if (err) {
            record.cleanXml();
            job.log('[ERROR] Unable to update a CSW record');
            return done(err);
        }

        if (nModified === 0) {
            done(null, false);
        } else if (nModified === 1) {
            record.status = 'not-updated';
            record.cleanXml();
            done(null, true);
        } else {
            record.cleanXml();
            done(new Error('Multiple CSW record updated!!'));
        }
    });
};

CswRecord.prototype.createNewRecord = function (done) {
    var query = {
        parentCatalog: this.job.service._id,
        identifier: this.parsedRecord.fileIdentifier,
        timestamp: this.timestamp(),
        synchronizations: [this.job.id],
        availableSince: this.job.id,
        xml: this.xmlElement.clone().toString()
    };

    this.cleanXml();

    var record = this;

    PersistedCswRecord.collection.insert(query, function (err) {
        if (err) {
            record.job.log('[ERROR] Unable to save a CSW record');
            return done(err);
        }

        record.status = 'created';
        // job.log('[INFO] New CSW record inserted');
        done();
    });
};

CswRecord.prototype.updateOrCreateRecord = function (done) {
    var record = this;

    record.updateCurrentRecord(function (err, updated) {
        if (err) return done(err);
        if (updated) {
            done();
        } else {
            record.createNewRecord(done);
        }
    });
};

CswRecord.prototype.createJob = function (done) {
    if (this.status !== 'created') return done();

    jobs
        .create('process-record', {
            recordId: this.parsedRecord.fileIdentifier,
            catalogId: this.job.service._id
        })
        .removeOnComplete(true)
        .attempts(5)
        .save(done);
};

CswRecord.prototype.process = function (done) {
    if (!this.isValid()) {
        this.cleanXml();
        return done();
    }

    async.series([
        _.bind(this.updateOrCreateRecord, this),
        _.bind(this.createJob, this)
    ], done);
};

/*
** Exports
*/
module.exports = CswRecord;
<commit_msg>Fix date parsing error<commit_after>var iso19139 = require('iso19139');
var moment = require('moment');
var async = require('async');
var _ = require('lodash');

var mongoose = require('../../mongoose');
var jobs = require('../../kue').jobs;

var PersistedCswRecord = mongoose.model('CswRecord');

/*
** Constructor
*/
function CswRecord(xmlElement, job) {
    if (!xmlElement) throw new Error('xmlElement is not defined');
    if (!job) throw new Error('job is not defined');

    this.xmlElement = xmlElement;
    this.recordName = xmlElement.name();
    this.job = job;
    this.parse();
}

/*
** Methods
*/
CswRecord.prototype.parse = function () {
    if (!this.xmlElement) throw new Error('xmlElement is not defined');

    if (this.recordName === 'MD_Metadata') {
        this.parsedRecord = iso19139.parse(this.xmlElement);
    } else {
        this.status = 'not-parsed';
        this.cleanXml();
    }
};

CswRecord.prototype.cleanXml = function () {
    this.xmlElement = null;
};

CswRecord.prototype.isValid = function () {
    if (!this.parsedRecord) return false;

    var record = this;

    function notValid() {
        record.status = 'not-valid';
        return false;
    }

    if (!this.parsedRecord.fileIdentifier) {
        this.job.log('[WARN] Dropping 1 record: no fileIdentifier set!');
        return notValid();
    }

    if (this.parsedRecord.fileIdentifier.length > 256) {
        this.job.log('[WARN] Dropping 1 record: fileIdentifier too long!');
        return notValid();
    }

    if (!this.parsedRecord._updated) {
        this.job.log('[WARN] Dropping 1 record: no dateStamp set!');
        return notValid();
    }

    if (!_.isDate(new Date(this.parsedRecord._updated))) {
        this.job.log('[WARN] Dropping 1 record: dateStamp not valid!');
        return notValid();
    }

    return true;
};

CswRecord.prototype.timestamp = function () {
    return moment(this.parsedRecord._updated).toDate();
};

CswRecord.prototype.updateCurrentRecord = function (done) {
    var query = {
        parentCatalog: this.job.service._id,
        identifier: this.parsedRecord.fileIdentifier,
        timestamp: this.timestamp()
    };

    var update = { $push: { synchronizations: this.job.id } };

    var job = this.job;
    var record = this;

    PersistedCswRecord.update(query, update, function (err, nModified) {
        if (err) {
            record.cleanXml();
            job.log('[ERROR] Unable to update a CSW record');
            return done(err);
        }

        if (nModified === 0) {
            done(null, false);
        } else if (nModified === 1) {
            record.status = 'not-updated';
            record.cleanXml();
            done(null, true);
        } else {
            record.cleanXml();
            done(new Error('Multiple CSW record updated!!'));
        }
    });
};

CswRecord.prototype.createNewRecord = function (done) {
    var query = {
        parentCatalog: this.job.service._id,
        identifier: this.parsedRecord.fileIdentifier,
        timestamp: this.timestamp(),
        synchronizations: [this.job.id],
        availableSince: this.job.id,
        xml: this.xmlElement.clone().toString()
    };

    this.cleanXml();

    var record = this;

    PersistedCswRecord.collection.insert(query, function (err) {
        if (err) {
            record.job.log('[ERROR] Unable to save a CSW record');
            return done(err);
        }

        record.status = 'created';
        // job.log('[INFO] New CSW record inserted');
        done();
    });
};

CswRecord.prototype.updateOrCreateRecord = function (done) {
    var record = this;

    record.updateCurrentRecord(function (err, updated) {
        if (err) return done(err);
        if (updated) {
            done();
        } else {
            record.createNewRecord(done);
        }
    });
};

CswRecord.prototype.createJob = function (done) {
    if (this.status !== 'created') return done();

    jobs
        .create('process-record', {
            recordId: this.parsedRecord.fileIdentifier,
            catalogId: this.job.service._id
        })
        .removeOnComplete(true)
        .attempts(5)
        .save(done);
};

CswRecord.prototype.process = function (done) {
    if (!this.isValid()) {
        this.cleanXml();
        return done();
    }

    async.series([
        _.bind(this.updateOrCreateRecord, this),
        _.bind(this.createJob, this)
    ], done);
};

/*
** Exports
*/
module.exports = CswRecord;
<|endoftext|>


<commit_before>'use strict';

const path = require('path');

const glob = require('glob');

const errors = require('../lib/errors');
const router = require('../lib/express').Router();

const CWD = path.join(__dirname, '../');

glob.sync('api/**/*.js', {cwd: CWD}).map((file) => {
  let uri = '/' + file.slice(0, -('.js'.length));
  let uris = [uri];
  if (uri.endsWith('/index')) {
    uris.push(uri.slice(0, -('/index'.length)));
  }

  let location = path.join(CWD, file);
  let handlers = require(location);

  uris.map((item) => {
    for (let handler in handlers) {
      router[handler](item, handlers[handler]);
    }
  });
});

// 抛出API接口的404错误
router.use('/api/*', function () {
  throw new errors.NotFound('page not found');
});

module.exports = router;
<commit_msg>fix: fix route error<commit_after>'use strict';

const path = require('path');

const glob = require('glob');

const errors = require('../lib/errors');
const router = require('../lib/express').Router();

const CWD = path.join(__dirname, '../');

glob.sync('api/**/*.js', {cwd: CWD}).map((file) => {
  let uri = '/' + file.slice(0, -('.js'.length));
  let uris = [uri];
  if (uri.endsWith('/index')) {
    uris.push(uri.slice(0, -('/index'.length)));
  }

  let location = path.join(CWD, file);
  let handlers = require(location);

  uris.map((item) => {
    for (let handler in handlers) {
      router[handler](item, handlers[handler]);
    }
  });
});

// 抛出API接口的404错误
router.use('/api', function () {
  throw new errors.NotFound('page not found');
});

module.exports = router;
<|endoftext|>


<commit_before>/**
 * @file DateTimePicker component
 * @author sunday(sunday.wei@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import _ from 'lodash';

import TextField from '../TextField';
import DayPicker from '../_DayPicker';
import MonthPicker from '../_MonthPicker';
import YearPicker from '../_YearPicker';
import TimeList from '../_TimeList';
import RaisedButton from '../RaisedButton';
import Popup from '../Popup';
import Theme from 'src/Theme';

export default class DateTimePicker extends Component {

    static propTypes = {

        /**
         * The CSS class name of the root element.
         */
        className: PropTypes.string,

        /**
         * Override the styles of the root element.
         */
        style: PropTypes.object,

        /**
         * Date picker input name.
         */
        name: PropTypes.string,

        /**
         * This is the initial date value of the component.
         */
        value: PropTypes.string,

        /**
         * The ending of a range of valid dates. The range includes the endDate.
         */
        maxValue: PropTypes.string,

        /**
         * The beginning of a range of valid dates. The range includes the startDate.
         */
        minValue: PropTypes.string,

        /**
         * DateTimePicker textField element placeholder.
         */
        placeholder: PropTypes.string,

        /**
         * Date Time format.
         */
        dateFormat: PropTypes.string,

        /**
         * Callback function that is fired when the date value changes.
         */
        onChange: PropTypes.func

    };
    static defaultProps = {
        className: '',
        style: null,
        name: '',
        value: moment().format('YYYY-MM-DD HH:mm:ss'),
        maxValue: '',
        minValue: '',
        placeholder: 'Date',
        dateFormat: 'YYYY-MM-DD HH:mm:ss',
        isFooter: true
    };

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.validValue = true;
        this.state = {
            value: props.value,
            popupVisible: false,
            triggerEl: null,
            year: moment(props.value).format('YYYY'),
            month: moment(props.value).format('MM'),
            day: moment(props.value).format('DD'),
            hour: moment(props.value).format('HH'),
            minute: moment(props.value).format('mm'),
            second: moment(props.value).format('ss'),
            datePickerLevel: 'day'
        };

        this.textFieldChangeHandle = ::this.textFieldChangeHandle;
        this.togglePopup = ::this.togglePopup;
        this.closePopup = ::this.closePopup;
        this.datePickerChangeHandle = ::this.datePickerChangeHandle;
        this.yearPickerChangeHandle = ::this.yearPickerChangeHandle;
        this.monthPickerChangeHandle = ::this.monthPickerChangeHandle;
        this.dayPickerChangeHandle = ::this.dayPickerChangeHandle;
        this.timePickerChangeHandle = ::this.timePickerChangeHandle;
        this.chooseDateAndTimeHandle = ::this.chooseDateAndTimeHandle;
        this.nowHandle = ::this.nowHandle;
        this.selectDateTimeHandle = ::this.selectDateTimeHandle;
    }

    datePickerChangeHandle(selectLevel) {
        this.setState({
            datePickerLevel: selectLevel
        });
    }

    textFieldChangeHandle(text) {
        const {minValue, maxValue, dateFormat} = this.props;
        if (text && text.length) {
            const flag = moment(text, dateFormat, true).isValid();
            if (flag) {
                if (minValue && moment(text).isBefore(minValue) || maxValue && moment(text).isAfter(maxValue)) {

                } else {
                    const select_year = moment(text).format('YYYY'),
                        select_month = moment(text).format('MM'),
                        select_day = moment(text).format('DD'),
                        hour = moment(text).format('HH'),
                        minute = moment(text).format('mm'),
                        second = moment(text).format('ss');
                    this.setState({
                        value: moment(text, dateFormat),
                        year: select_year,
                        month: select_month,
                        day: select_day,
                        hour: hour,
                        minute: minute,
                        second: second
                    });
                }
            }
        } else {
            this.setState({
                value: ''
            });
        }
    }

    dayPickerChangeHandle(date) {
        const {dateFormat} = this.props;
        this.setState({
            value: moment(date.time, dateFormat),
            year: date.year,
            month: date.month,
            day: date.day
        });
    }

    monthPickerChangeHandle(date) {
        this.setState({
            datePickerLevel: 'day',
            year: date.year,
            month: date.month
        });
    }

    yearPickerChangeHandle(year) {
        this.setState({
            datePickerLevel: 'month',
            year: year
        });
    }

    timePickerChangeHandle(obj) {
        let state = _.cloneDeep(this.state);
        state.hour = obj.hour;
        state.minute = obj.minute;
        state.second = obj.second;
        let timer = moment([state.year, +state.month - 1, state.day, state.hour, state.minute, state.second]).format(this.props.dateFormat);
        timer = moment(timer, this.props.dateFormat);
        this.setState({
            hour: obj.hour,
            minute: obj.minute,
            second: obj.second,
            value: timer
        });
    }

    chooseDateAndTimeHandle(value) {
        this.setState({
            datePickerLevel: value
        });
    }

    selectDateTimeHandle() {
        let state = _.cloneDeep(this.state);
        state.popupVisible = false;
        state.datePickerLevel = 'day';
        !this.props.disabled && this.setState(state, () => {
            this.props.onChange && this.props.onChange(state.value && moment(state.value).format(this.props.dateFormat));
        });
    }

    nowHandle() {
        const year = moment().format('YYYY'),
            month = moment().format('MM'),
            day = moment().format('DD'),
            hour = moment().format('HH'),
            minute = moment().format('mm'),
            second = moment().format('ss');

        let timer = moment(moment(), this.props.dateFormat);
        this.setState({
            value: timer,
            year: year,
            month: month,
            day: day,
            hour: hour,
            minute: minute,
            second: second
        });
    }

    togglePopup(e) {
        if (this.validValue) {
            this.setState({
                popupVisible: !this.state.popupVisible,
                triggerEl: e.target
            });
        }
    }

    closePopup() {
        const {value} = this.state;
        !this.props.disabled && this.setState({
            popupVisible: false
        }, () => {
            this.props.onChange && this.props.onChange(value && moment(value).format(this.props.dateFormat));
        });
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.value !== this.props.value || nextProps.dateFormat !== this.props.dateFormat) {
            const value = moment(nextProps.value, nextProps.dateFormat);
            this.setState({
                value: value,
                dateFormat: nextProps.dateFormat,
                year: moment(nextProps.value).format('YYYY'),
                month: moment(nextProps.value).format('MM'),
                day: moment(nextProps.value).format('DD'),
                hour: moment(nextProps.value).format('HH'),
                minute: moment(nextProps.value).format('mm'),
                second: moment(nextProps.value).format('ss')
            });
        }
    }

    componentDidMount() {
        // debugger
        const {value, dateFormat} = this.props;
        let state = _.cloneDeep(this.state);
        if (value) {
            if (moment(value, dateFormat).isValid()) {
                const select_year = moment(value).format('YYYY'),
                    select_month = moment(value).format('MM'),
                    select_day = moment(value).format('DD');
                state.value = moment(value, dateFormat);
                state.year = select_year;
                state.month = select_month;
                state.day = select_day;
                this.setState(state);
            } else {
                console.error('Invalid date');
                this.validValue = false;
            }
        }
    }

    render() {
        const {className, style, name, placeholder, dateFormat, maxValue, minValue, isFooter, disabled} = this.props;
        const {value, popupVisible, datePickerLevel, year, month, day, hour, minute, second, triggerEl} = this.state;
        let textValue = value && moment(value).format(dateFormat);
        return (
            <div className={`date-time-picker ${className}`}
                 ref="datePicker"
                 style={style}>

                <TextField ref="trigger"
                           className="date-picker-field"
                           name={name}
                           placeholder={placeholder}
                           value={textValue}
                           readOnly={true}
                           disabled={disabled}
                           clearButtonVisible={false}
                           isFocusedSelectAll={false}
                           onTouchTap={e => {
                               this.togglePopup(e);
                           }}
                />
                <Popup className={`date-time-picker-popup`}
                       visible={popupVisible}
                       triggerEl={triggerEl}
                       hasTriangle={false}
                       onRequestClose={() => {
                           this.closePopup();
                       }}>

                        <TextField className='calendar-input'
                                   placeholder={'Select Date'}
                                   clearButtonVisible={false}
                                   value={textValue}
                                   onChange={this.textFieldChangeHandle}/>

                    {
                        datePickerLevel == 'day' ?
                            <DayPicker
                                value={value}
                                dateFormat={dateFormat}
                                year={year}
                                month={month}
                                day={day}
                                hour={hour}
                                minute={minute}
                                second={second}
                                maxValue={maxValue ? moment(maxValue).format('YYYY-MM-DD') : null}
                                minValue={minValue ? moment(minValue).format('YYYY-MM-DD') : null}
                                isFooter={true}
                                onChange={this.dayPickerChangeHandle}
                                previousClick={this.datePickerChangeHandle}
                            />
                            : (
                                datePickerLevel == 'month' ?
                                    <MonthPicker
                                        value={value}
                                        year={year}
                                        month={month}
                                        day={day}
                                        maxValue={maxValue ? moment(maxValue).format('YYYY-MM-DD') : null}
                                        minValue={minValue ? moment(minValue).format('YYYY-MM-DD') : null}
                                        onChange={this.monthPickerChangeHandle}
                                        previousClick={this.datePickerChangeHandle}
                                    />
                                    : (
                                        datePickerLevel == 'year' ?
                                            <YearPicker
                                                value={value}
                                                year={year}
                                                month={month}
                                                day={day}
                                                maxValue={maxValue ? moment(maxValue).format('YYYY-MM-DD') : null}
                                                minValue={minValue ? moment(minValue).format('YYYY-MM-DD') : null}
                                                onChange={this.yearPickerChangeHandle}
                                            />
                                            :
                                            null
                                    )

                            )
                    }
                    {
                        <TimeList className={`time-picker-body ${datePickerLevel == 'time' ? '' : 'hidden'}`}
                                  dateFormat={dateFormat.split(' ')[1]}
                                  popupVisible={datePickerLevel == 'time' ? true : false}
                                  hour={hour}
                                  minute={minute}
                                  second={second}
                                  isRequired={(minValue && textValue.split(' ')[0] == minValue.split(' ')[0]) || (maxValue && textValue.split(' ')[0] == maxValue.split(' ')[0]) ? true : false}
                                  maxValue={maxValue && textValue.split(' ')[0] == maxValue.split(' ')[0] ? moment(maxValue).format('HH:mm:ss') : null}
                                  minValue={minValue && textValue.split(' ')[0] == minValue.split(' ')[0] ? moment(minValue).format('HH:mm:ss') : null}
                                  onChange={this.timePickerChangeHandle}
                        />
                    }
                    {
                        isFooter ?

                                    {
                                        (minValue && moment(this.props.value).isBefore(minValue)) || (maxValue && moment(maxValue).isBefore(this.props.value)) ?

                                                Now

                                            :

                                                Now

                                    }
                                    {
                                        datePickerLevel == 'time' ?
                                             {
                                                this.chooseDateAndTimeHandle('day');
                                            }}>
                                                Select date

                                            :
                                             {
                                                this.chooseDateAndTimeHandle('time');
                                            }}>
                                                Select time

                                    }

                                    <RaisedButton
                                        className={year && month && day && hour && minute && second ? 'active' : ''}
                                        value="Ok"
                                        theme={Theme.HIGHLIGHT}
                                    />

                            :
                            null
                    }

                </Popup>

        );
    }
};<commit_msg>update DateTimePicker<commit_after>/**
 * @file DateTimePicker component
 * @author sunday(sunday.wei@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import _ from 'lodash';

import TextField from '../TextField';
import DayPicker from '../_DayPicker';
import MonthPicker from '../_MonthPicker';
import YearPicker from '../_YearPicker';
import TimeList from '../_TimeList';
import RaisedButton from '../RaisedButton';
import Popup from '../Popup';
import Theme from 'src/Theme';

class DateTimePicker extends Component {

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.validValue = true;
        this.state = {
            value: props.value,
            popupVisible: false,
            triggerEl: null,
            year: moment(props.value).format('YYYY'),
            month: moment(props.value).format('MM'),
            day: moment(props.value).format('DD'),
            hour: moment(props.value).format('HH'),
            minute: moment(props.value).format('mm'),
            second: moment(props.value).format('ss'),
            datePickerLevel: 'day'
        };

        this.textFieldChangeHandle = ::this.textFieldChangeHandle;
        this.togglePopup = ::this.togglePopup;
        this.closePopup = ::this.closePopup;
        this.datePickerChangeHandle = ::this.datePickerChangeHandle;
        this.yearPickerChangeHandle = ::this.yearPickerChangeHandle;
        this.monthPickerChangeHandle = ::this.monthPickerChangeHandle;
        this.dayPickerChangeHandle = ::this.dayPickerChangeHandle;
        this.timePickerChangeHandle = ::this.timePickerChangeHandle;
        this.chooseDateAndTimeHandle = ::this.chooseDateAndTimeHandle;
        this.nowHandle = ::this.nowHandle;
        this.selectDateTimeHandle = ::this.selectDateTimeHandle;
    }

    datePickerChangeHandle(selectLevel) {
        this.setState({
            datePickerLevel: selectLevel
        });
    }

    textFieldChangeHandle(text) {
        const {minValue, maxValue, dateFormat} = this.props;
        if (text && text.length) {
            const flag = moment(text, dateFormat, true).isValid();
            if (flag) {
                if (minValue && moment(text).isBefore(minValue) || maxValue && moment(text).isAfter(maxValue)) {

                } else {
                    const select_year = moment(text).format('YYYY'),
                        select_month = moment(text).format('MM'),
                        select_day = moment(text).format('DD'),
                        hour = moment(text).format('HH'),
                        minute = moment(text).format('mm'),
                        second = moment(text).format('ss');
                    this.setState({
                        value: moment(text, dateFormat),
                        year: select_year,
                        month: select_month,
                        day: select_day,
                        hour: hour,
                        minute: minute,
                        second: second
                    });
                }
            }
        } else {
            this.setState({
                value: ''
            });
        }
    }

    dayPickerChangeHandle(date) {
        const {dateFormat} = this.props;
        this.setState({
            value: moment(date.time, dateFormat),
            year: date.year,
            month: date.month,
            day: date.day
        });
    }

    monthPickerChangeHandle(date) {
        this.setState({
            datePickerLevel: 'day',
            year: date.year,
            month: date.month
        });
    }

    yearPickerChangeHandle(year) {
        this.setState({
            datePickerLevel: 'month',
            year: year
        });
    }

    timePickerChangeHandle(obj) {
        let state = _.cloneDeep(this.state);
        state.hour = obj.hour;
        state.minute = obj.minute;
        state.second = obj.second;
        let timer = moment([state.year, +state.month - 1, state.day, state.hour, state.minute, state.second]).format(this.props.dateFormat);
        timer = moment(timer, this.props.dateFormat);
        this.setState({
            hour: obj.hour,
            minute: obj.minute,
            second: obj.second,
            value: timer
        });
    }

    chooseDateAndTimeHandle(value) {
        this.setState({
            datePickerLevel: value
        });
    }

    selectDateTimeHandle() {
        let state = _.cloneDeep(this.state);
        state.popupVisible = false;
        state.datePickerLevel = 'day';
        !this.props.disabled && this.setState(state, () => {
            this.props.onChange && this.props.onChange(state.value && moment(state.value).format(this.props.dateFormat));
        });
    }

    nowHandle() {
        const year = moment().format('YYYY'),
            month = moment().format('MM'),
            day = moment().format('DD'),
            hour = moment().format('HH'),
            minute = moment().format('mm'),
            second = moment().format('ss');

        let timer = moment(moment(), this.props.dateFormat);
        this.setState({
            value: timer,
            year: year,
            month: month,
            day: day,
            hour: hour,
            minute: minute,
            second: second
        });
    }

    togglePopup(e) {
        if (this.validValue) {
            this.setState({
                popupVisible: !this.state.popupVisible,
                triggerEl: e.target
            });
        }
    }

    closePopup() {
        const {value} = this.state;
        !this.props.disabled && this.setState({
            popupVisible: false
        }, () => {
            this.props.onChange && this.props.onChange(value && moment(value).format(this.props.dateFormat));
        });
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.value !== this.props.value || nextProps.dateFormat !== this.props.dateFormat) {
            const value = moment(nextProps.value, nextProps.dateFormat);
            this.setState({
                value: value,
                dateFormat: nextProps.dateFormat,
                year: moment(nextProps.value).format('YYYY'),
                month: moment(nextProps.value).format('MM'),
                day: moment(nextProps.value).format('DD'),
                hour: moment(nextProps.value).format('HH'),
                minute: moment(nextProps.value).format('mm'),
                second: moment(nextProps.value).format('ss')
            });
        }
    }

    componentDidMount() {
        // debugger
        const {value, dateFormat} = this.props;
        let state = _.cloneDeep(this.state);
        if (value) {
            if (moment(value, dateFormat).isValid()) {
                const select_year = moment(value).format('YYYY'),
                    select_month = moment(value).format('MM'),
                    select_day = moment(value).format('DD');
                state.value = moment(value, dateFormat);
                state.year = select_year;
                state.month = select_month;
                state.day = select_day;
                this.setState(state);
            } else {
                console.error('Invalid date');
                this.validValue = false;
            }
        }
    }

    render() {
        const {className, style, name, placeholder, dateFormat, maxValue, minValue, isFooter, disabled} = this.props;
        const {value, popupVisible, datePickerLevel, year, month, day, hour, minute, second, triggerEl} = this.state;
        let textValue = value && moment(value).format(dateFormat);
        return (
            <div className={`date-time-picker ${className}`}
                 ref="datePicker"
                 style={style}>

                <TextField ref="trigger"
                           className="date-picker-field"
                           name={name}
                           placeholder={placeholder}
                           value={textValue}
                           readOnly={true}
                           disabled={disabled}
                           clearButtonVisible={false}
                           isFocusedSelectAll={false}
                           onTouchTap={e => {
                               this.togglePopup(e);
                           }}
                />
                <Popup className={`date-time-picker-popup`}
                       visible={popupVisible}
                       triggerEl={triggerEl}
                       hasTriangle={false}
                       onRequestClose={() => {
                           this.closePopup();
                       }}>

                        <TextField className='calendar-input'
                                   placeholder={'Select Date'}
                                   clearButtonVisible={false}
                                   value={textValue}
                                   onChange={this.textFieldChangeHandle}/>

                    {
                        datePickerLevel == 'day' ?
                            <DayPicker
                                value={value}
                                dateFormat={dateFormat}
                                year={year}
                                month={month}
                                day={day}
                                hour={hour}
                                minute={minute}
                                second={second}
                                maxValue={maxValue ? moment(maxValue).format('YYYY-MM-DD') : null}
                                minValue={minValue ? moment(minValue).format('YYYY-MM-DD') : null}
                                isFooter={true}
                                onChange={this.dayPickerChangeHandle}
                                previousClick={this.datePickerChangeHandle}
                            />
                            : (
                                datePickerLevel == 'month' ?
                                    <MonthPicker
                                        value={value}
                                        year={year}
                                        month={month}
                                        day={day}
                                        maxValue={maxValue ? moment(maxValue).format('YYYY-MM-DD') : null}
                                        minValue={minValue ? moment(minValue).format('YYYY-MM-DD') : null}
                                        onChange={this.monthPickerChangeHandle}
                                        previousClick={this.datePickerChangeHandle}
                                    />
                                    : (
                                        datePickerLevel == 'year' ?
                                            <YearPicker
                                                value={value}
                                                year={year}
                                                month={month}
                                                day={day}
                                                maxValue={maxValue ? moment(maxValue).format('YYYY-MM-DD') : null}
                                                minValue={minValue ? moment(minValue).format('YYYY-MM-DD') : null}
                                                onChange={this.yearPickerChangeHandle}
                                            />
                                            :
                                            null
                                    )

                            )
                    }
                    {
                        <TimeList className={`time-picker-body ${datePickerLevel == 'time' ? '' : 'hidden'}`}
                                  dateFormat={dateFormat.split(' ')[1]}
                                  popupVisible={datePickerLevel == 'time' ? true : false}
                                  hour={hour}
                                  minute={minute}
                                  second={second}
                                  isRequired={(minValue && textValue.split(' ')[0] == minValue.split(' ')[0]) || (maxValue && textValue.split(' ')[0] == maxValue.split(' ')[0]) ? true : false}
                                  maxValue={maxValue && textValue.split(' ')[0] == maxValue.split(' ')[0] ? moment(maxValue).format('HH:mm:ss') : null}
                                  minValue={minValue && textValue.split(' ')[0] == minValue.split(' ')[0] ? moment(minValue).format('HH:mm:ss') : null}
                                  onChange={this.timePickerChangeHandle}
                        />
                    }
                    {
                        isFooter ?

                                    {
                                        (minValue && moment(this.props.value).isBefore(minValue)) || (maxValue && moment(maxValue).isBefore(this.props.value)) ?

                                                Now

                                            :

                                                Now

                                    }
                                    {
                                        datePickerLevel == 'time' ?
                                             {
                                                this.chooseDateAndTimeHandle('day');
                                            }}>
                                                Select date

                                            :
                                             {
                                                this.chooseDateAndTimeHandle('time');
                                            }}>
                                                Select time

                                    }

                                    <RaisedButton
                                        className={year && month && day && hour && minute && second ? 'active' : ''}
                                        value="Ok"
                                        theme={Theme.HIGHLIGHT}
                                    />

                            :
                            null
                    }

                </Popup>

        );
    }
};

DateTimePicker.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * Date picker input name.
     */
    name: PropTypes.string,

    /**
     * This is the initial date value of the component.
     */
    value: PropTypes.string,

    /**
     * The ending of a range of valid dates. The range includes the endDate.
     */
    maxValue: PropTypes.string,

    /**
     * The beginning of a range of valid dates. The range includes the startDate.
     */
    minValue: PropTypes.string,

    /**
     * DateTimePicker textField element placeholder.
     */
    placeholder: PropTypes.string,

    /**
     * Date Time format.
     */
    dateFormat: PropTypes.string,

    /**
     * Callback function that is fired when the date value changes.
     */
    onChange: PropTypes.func

};

DateTimePicker.defaultProps = {
    className: '',
    style: null,
    name: '',
    value: moment().format('YYYY-MM-DD HH:mm:ss'),
    maxValue: '',
    minValue: '',
    placeholder: 'Date',
    dateFormat: 'YYYY-MM-DD HH:mm:ss',
    isFooter: true
};

export default DateTimePicker;<|endoftext|>


<commit_before>"use strict";

(function(){
  jQuery.widget("bcdui.bcduiCommentNg", jQuery.bcdui.bcduiWidget,
    /** @lends bcdui.bcduiCommentNg */
  {

    _getCreateOptions : function(){
      return bcdui.widgetNg.impl.readParams.comment(this.element[0]);
    },

    _validateOptions : function(){
      bcdui.widgetNg.impl.validateParams.comment(this.options);
    },

    _create : function(){
      this._super();
      bcdui.log.isTraceEnabled() && bcdui.log.trace("creating comment widget with config ");

      // avoid rendering while attaching children
      this.element.hide();

      var commentBox = this._createCommentBox();

      // our config holds sope, instance and the actual data model
      var config = {
        scope: this.options.scope, instance: this.options.instance,
        commentModel: new bcdui.core.AutoModel({
          bindingSetId: "bcd_comment"
        , bRefs: "comment_text lastUpdate updatedBy"
        , filterElement: bcdui.util.xml.parseFilterExpression("scope='"+this.options.scope+"' and instance='"+this.options.instance+"'")
        , orderByBRefs: "lastUpdate-"
        , saveOptions: {
          // after saving, we unblock the ui and reload the model and of course refresh the vfs
            onSuccess: function() { setTimeout(jQuery.unblockUI);}
          , onFailure: function() { setTimeout(jQuery.unblockUI);}
          , onWrsValidationFailure: function() { setTimeout(jQuery.unblockUI);}
          , reload: true
        }
      })}

      this.element.data("_config_", config);

      // handle label creation after appending control
      this._createLabel(commentBox.attr("id"));

      // attach to DOM
      this.element.append(commentBox);

      // readd events
      this.element.off("click");
      this.element.on("click", ".edit", function() { jQuery(this).parent().next().toggle(); });
      this.element.on("click", ".bcdButton", function(){

        // show/hide input field row
        jQuery(this).closest(".bcdComment").find(".addRow").toggle();
        var conf = jQuery(this).closest(".bcdComment").parent().data("_config_");
        var value = jQuery(this).closest(".bcdComment").find("input").val() || "";
        var model = conf.commentModel;

        // add scope and instance columns in header and add a new prefilled row
        if (conf && model && value) {
          var lastPos = model.queryNodes("/*/wrs:Header/wrs:Columns/wrs:C").length + 1;
          bcdui.core.createElementWithPrototype(model.getData(), "/*/wrs:Header/wrs:Columns/wrs:C[@id='scope' and @pos='"+lastPos+"' and @nullable='1' and @type-name='VARCHAR']");
          bcdui.core.createElementWithPrototype(model.getData(), "/*/wrs:Header/wrs:Columns/wrs:C[@id='instance' and @pos='"+(lastPos + 1)+"' and @nullable='1' and @type-name='VARCHAR']");
          bcdui.wrs.wrsUtil.insertRow({model: model, propagateUpdate: false, rowStartPos:1, rowEndPos:1, insertBeforeSelection: true, setDefaultValue: false, fn: function(){
            bcdui.wrs.wrsUtil.setCellValue(model, 1, "comment_text", value);
            bcdui.wrs.wrsUtil.setCellValue(model, 1, "scope", conf.scope);
            bcdui.wrs.wrsUtil.setCellValue(model, 1, "instance", conf.instance);
            setTimeout(function(){jQuery.blockUI({message: bcdui.i18n.syncTranslateFormatMessage({msgid:"bcd_Wait"})})});
            model.sendData();
          }});
        }
      });

      // actual renderer, render cards per entry
      var tableRenderer = new bcdui.core.Renderer({
        targetHtml: this.element.find(".bcdComment .commentTable")
      , inputModel: config.commentModel
      , chain: function(doc, args) {
          this.element.find(".bcdComment .commentTable").empty();
          var comment_text_idx = config.commentModel.read("/*/wrs:Header/wrs:Columns/wrs:C[@id='comment_text']/@pos", "");
          var lastUpdate_idx = config.commentModel.read("/*/wrs:Header/wrs:Columns/wrs:C[@id='lastUpdate']/@pos", "");
          var updatedBy_idx = config.commentModel.read("/*/wrs:Header/wrs:Columns/wrs:C[@id='updatedBy']/@pos", "");
          Array.from(doc.selectNodes("/*/wrs:Data/wrs:R")).forEach(function(r) {
            var comment = r.selectSingleNode("wrs:C["+comment_text_idx+"]").text;
            var lastUpdate = r.selectSingleNode("wrs:C["+lastUpdate_idx+"]").text;
            var updatedBy = r.selectSingleNode("wrs:C["+updatedBy_idx+"]").text;
            jQuery("

" + lastUpdate + "

" + updatedBy + "

" + comment + "

").appendTo(this.element.find(".bcdComment .commentTable"));
          }.bind(this));
          return doc;
      }.bind(this)});

      // rerender when comment model was saved
      tableRenderer.onceReady(function() {
        config.commentModel.onReady(function() {
          tableRenderer.execute(true);
        }.bind(this));
      }.bind(this));

      // display constructed container
      this.element.show();
      // limit comment table's height to outer container height
      var outerHeight = this.element.parent().outerHeight();
      outerHeight -= this.element.find(".titleRow").outerHeight() || 0;
      outerHeight -= this.element.find(".addRow").outerHeight() || 0;
      this.element.find(".addRow").hide();
      this.element.find(".commentTable").css("overflow", "auto");
      this.element.find(".commentTable").css("height", outerHeight + "px");
    },

    _createCommentBox: function(){

      var opts = this.options;
      var caption = opts.caption || "";
      var title = caption.indexOf(bcdui.i18n.TAG) == 0 ? bcdui.i18n.syncTranslateFormatMessage({msgid:caption}) : caption;

      var rights = bcdui.config.clientRights && bcdui.config.clientRights.bcdComment ? "|" + bcdui.config.clientRights.bcdComment.join("|") + "|" : "";
      if (!(rights.indexOf("|*|") != -1 || rights.indexOf("|" + opts.scope + "|") != -1))
        opts.readonly = true;

      // outer widget container, in case of readonly, the input field is not rendered

      var placeholder = bcdui.util.escapeHtml(bcdui.i18n.syncTranslateFormatMessage({msgid:"bcd_Comment_Placeholder"}) || "Enter Comment");
      var addTxt = bcdui.util.escapeHtml(bcdui.i18n.syncTranslateFormatMessage({msgid:"bcd_Comment_Add"}) || "Add");
      var add = opts.readonly ? "" : "

"+title+"

<input class='form-control' maxlength='256' placeholder='"+placeholder+"'></input>

" + addTxt + "

";
      var el = jQuery("
"+add+"

");

      el.attr("id","comment_" + opts.id);
      el.find("input").attr("tabindex", opts.tabindex);
      el.find("input").attr("autofocus", opts.autofocus);
      el.find("input").attr("readonly", opts.readonly);
      if(opts.disabled){
        el.find("input").attr("disabled","disabled");
        el.find("input").addClass("bcdDisabled");
        el.find("a").attr("disabled","disabled");
        el.find("a").addClass("bcdDisabled");
      }

      return el;
    },

    /**
     * @private
     */
    _destroy: function() {
      this._super();
      this.element.off().data("_config_", null);
    }
  });
}());

/**
 * A namespace for the BCD-UI pasteList widget.
 * @namespace bcdui.widgetNg.comment
 * @private
 */
bcdui.widgetNg.comment = Object.assign(bcdui.widgetNg.comment,
/** @lends bcdui.widgetNg.comment */
{
  /**
   * @private
   */
  init: function(htmlElement){
    bcdui.log.isTraceEnabled() && bcdui.log.trace("bcdui comment widget adapter init");
    jQuery(htmlElement).bcduiCommentNg();
  }
});
<commit_msg>Client/Widget, comment widget, remove previously entered value on save<commit_after>"use strict";

(function(){
  jQuery.widget("bcdui.bcduiCommentNg", jQuery.bcdui.bcduiWidget,
    /** @lends bcdui.bcduiCommentNg */
  {

    _getCreateOptions : function(){
      return bcdui.widgetNg.impl.readParams.comment(this.element[0]);
    },

    _validateOptions : function(){
      bcdui.widgetNg.impl.validateParams.comment(this.options);
    },

    _create : function(){
      this._super();
      bcdui.log.isTraceEnabled() && bcdui.log.trace("creating comment widget with config ");

      // avoid rendering while attaching children
      this.element.hide();

      var commentBox = this._createCommentBox();

      // our config holds sope, instance and the actual data model
      var config = {
        scope: this.options.scope, instance: this.options.instance,
        commentModel: new bcdui.core.AutoModel({
          bindingSetId: "bcd_comment"
        , bRefs: "comment_text lastUpdate updatedBy"
        , filterElement: bcdui.util.xml.parseFilterExpression("scope='"+this.options.scope+"' and instance='"+this.options.instance+"'")
        , orderByBRefs: "lastUpdate-"
        , saveOptions: {
          // after saving, we unblock the ui and reload the model and of course refresh the vfs
            onSuccess: function() { setTimeout(jQuery.unblockUI);}
          , onFailure: function() { setTimeout(jQuery.unblockUI);}
          , onWrsValidationFailure: function() { setTimeout(jQuery.unblockUI);}
          , reload: true
        }
      })}

      this.element.data("_config_", config);

      // handle label creation after appending control
      this._createLabel(commentBox.attr("id"));

      // attach to DOM
      this.element.append(commentBox);

      // readd events
      this.element.off("click");
      this.element.on("click", ".edit", function() { jQuery(this).parent().next().toggle(); });
      this.element.on("click", ".bcdButton", function(){

        // show/hide input field row
        jQuery(this).closest(".bcdComment").find(".addRow").toggle();
        var conf = jQuery(this).closest(".bcdComment").parent().data("_config_");
        var value = jQuery(this).closest(".bcdComment").find("input").val() || "";
        var model = conf.commentModel;

        // add scope and instance columns in header and add a new prefilled row
        if (conf && model && value) {

          // remove entered value
          jQuery(this).closest(".bcdComment").find("input").val("");

          var lastPos = model.queryNodes("/*/wrs:Header/wrs:Columns/wrs:C").length + 1;
          bcdui.core.createElementWithPrototype(model.getData(), "/*/wrs:Header/wrs:Columns/wrs:C[@id='scope' and @pos='"+lastPos+"' and @nullable='1' and @type-name='VARCHAR']");
          bcdui.core.createElementWithPrototype(model.getData(), "/*/wrs:Header/wrs:Columns/wrs:C[@id='instance' and @pos='"+(lastPos + 1)+"' and @nullable='1' and @type-name='VARCHAR']");
          bcdui.wrs.wrsUtil.insertRow({model: model, propagateUpdate: false, rowStartPos:1, rowEndPos:1, insertBeforeSelection: true, setDefaultValue: false, fn: function(){
            bcdui.wrs.wrsUtil.setCellValue(model, 1, "comment_text", value);
            bcdui.wrs.wrsUtil.setCellValue(model, 1, "scope", conf.scope);
            bcdui.wrs.wrsUtil.setCellValue(model, 1, "instance", conf.instance);
            setTimeout(function(){jQuery.blockUI({message: bcdui.i18n.syncTranslateFormatMessage({msgid:"bcd_Wait"})})});
            model.sendData();
          }});
        }
      });

      // actual renderer, render cards per entry
      var tableRenderer = new bcdui.core.Renderer({
        targetHtml: this.element.find(".bcdComment .commentTable")
      , inputModel: config.commentModel
      , chain: function(doc, args) {
          this.element.find(".bcdComment .commentTable").empty();
          var comment_text_idx = config.commentModel.read("/*/wrs:Header/wrs:Columns/wrs:C[@id='comment_text']/@pos", "");
          var lastUpdate_idx = config.commentModel.read("/*/wrs:Header/wrs:Columns/wrs:C[@id='lastUpdate']/@pos", "");
          var updatedBy_idx = config.commentModel.read("/*/wrs:Header/wrs:Columns/wrs:C[@id='updatedBy']/@pos", "");
          Array.from(doc.selectNodes("/*/wrs:Data/wrs:R")).forEach(function(r) {
            var comment = r.selectSingleNode("wrs:C["+comment_text_idx+"]").text;
            var lastUpdate = r.selectSingleNode("wrs:C["+lastUpdate_idx+"]").text;
            var updatedBy = r.selectSingleNode("wrs:C["+updatedBy_idx+"]").text;
            jQuery("

" + lastUpdate + "

" + updatedBy + "

" + comment + "

").appendTo(this.element.find(".bcdComment .commentTable"));
          }.bind(this));
          return doc;
      }.bind(this)});

      // rerender when comment model was saved
      tableRenderer.onceReady(function() {
        config.commentModel.onReady(function() {
          tableRenderer.execute(true);
        }.bind(this));
      }.bind(this));

      // display constructed container
      this.element.show();
      // limit comment table's height to outer container height
      var outerHeight = this.element.parent().outerHeight();
      outerHeight -= this.element.find(".titleRow").outerHeight() || 0;
      outerHeight -= this.element.find(".addRow").outerHeight() || 0;
      this.element.find(".addRow").hide();
      this.element.find(".commentTable").css("overflow", "auto");
      this.element.find(".commentTable").css("height", outerHeight + "px");
    },

    _createCommentBox: function(){

      var opts = this.options;
      var caption = opts.caption || "";
      var title = caption.indexOf(bcdui.i18n.TAG) == 0 ? bcdui.i18n.syncTranslateFormatMessage({msgid:caption}) : caption;

      var rights = bcdui.config.clientRights && bcdui.config.clientRights.bcdComment ? "|" + bcdui.config.clientRights.bcdComment.join("|") + "|" : "";
      if (!(rights.indexOf("|*|") != -1 || rights.indexOf("|" + opts.scope + "|") != -1))
        opts.readonly = true;

      // outer widget container, in case of readonly, the input field is not rendered

      var placeholder = bcdui.util.escapeHtml(bcdui.i18n.syncTranslateFormatMessage({msgid:"bcd_Comment_Placeholder"}) || "Enter Comment");
      var addTxt = bcdui.util.escapeHtml(bcdui.i18n.syncTranslateFormatMessage({msgid:"bcd_Comment_Add"}) || "Add");
      var add = opts.readonly ? "" : "

"+title+"

<input class='form-control' maxlength='256' placeholder='"+placeholder+"'></input>

" + addTxt + "

";
      var el = jQuery("
"+add+"

");

      el.attr("id","comment_" + opts.id);
      el.find("input").attr("tabindex", opts.tabindex);
      el.find("input").attr("autofocus", opts.autofocus);
      el.find("input").attr("readonly", opts.readonly);
      if(opts.disabled){
        el.find("input").attr("disabled","disabled");
        el.find("input").addClass("bcdDisabled");
        el.find("a").attr("disabled","disabled");
        el.find("a").addClass("bcdDisabled");
      }

      return el;
    },

    /**
     * @private
     */
    _destroy: function() {
      this._super();
      this.element.off().data("_config_", null);
    }
  });
}());

/**
 * A namespace for the BCD-UI pasteList widget.
 * @namespace bcdui.widgetNg.comment
 * @private
 */
bcdui.widgetNg.comment = Object.assign(bcdui.widgetNg.comment,
/** @lends bcdui.widgetNg.comment */
{
  /**
   * @private
   */
  init: function(htmlElement){
    bcdui.log.isTraceEnabled() && bcdui.log.trace("bcdui comment widget adapter init");
    jQuery(htmlElement).bcduiCommentNg();
  }
});
<|endoftext|>


<commit_before>define(["dojo/_base/array", "./_base"], function(darray,mbase){
	// module:
	//		dojox/mobile/deviceTheme
	// summary:
	//		Automatic Theme Loader
	// description:
	//		Detects the User Agent of the browser and loads appropriate theme files.
	//		Simply dojo.require this module to enable the automatic theme loading.
	//
	//		By default, an all-in-one theme file (e.g. themes/iphone/iphone.css) is
	//		loaded. The all-in-one theme files contain style sheets for all the
	//		dojox.mobile widgets regardless of whether they are used in your
	//		application or not.
	//		If you want to choose what theme files to load, you can specify them
	//		via djConfig as shown in the following example:
	//
	//	|	djConfig="parseOnLoad:true, mblThemeFiles:['base','Button']"
	//
	//		Or you may want to use dojox.mobile.themeFiles as follows to get the
	//		same result. Note that the assignment has to be done before loading
	//		deviceTheme.js.
	//
	//	|	dojo.require("dojox.mobile");
	//	|	dojox.mobile.themeFiles = ['base','Button'];
	//	|	dojo.require("dojox.mobile.deviceTheme");
	//
	//		In the case of this example, if iphone is detected, for example, the
	//		following files will be loaded:
	//
	//	|	dojox/mobile/themes/iphone/base.css
	//	|	dojox/mobile/themes/iphone/Button.css
	//
	//		If you want to load style sheets for your own custom widgets, you can
	//		specify a package name along with a theme file name in an array.
	//
	//	|	['base',['com.acme','MyWidget']]
	//
	//		In this case, the following files will be loaded.
	//
	//	|	dojox/mobile/themes/iphone/base.css
	//	|	com/acme/themes/iphone/MyWidget.css
	//
	//		If you specify '@theme' as a theme file name, it will be replaced with
	//		the theme folder name. For example,
	//
	//	|	['@theme',['com.acme','MyWidget']]
	//
	//		will load the following files.
	//
	//	|	dojox/mobile/themes/iphone/iphone.css
	//	|	com/acme/themes/iphone/MyWidget.css

	dojox.mobile.loadCssFile = function(/*String*/file){
		dojo.create("LINK", {
			href: file,
			type: "text/css",
			rel: "stylesheet"
		}, dojo.doc.getElementsByTagName('head')[0]);
	};

	dojox.mobile.themeMap = dojox.mobile.themeMap || [
		// summary:
		//		A map of user-agents to theme files.
		// description:
		//		The first array element is a regexp pattern that matches the
		//		userAgent string.
		//
		//		The second array element is a theme folder name.
		//
		//		The third array element is an array of css file paths to load.
		//
		//		The matching is performed in the array order, and stops after the
		//		first match.
		[
			"Android",
			"android",
			[]
		],
		[
			"BlackBerry",
			"blackberry",
			[]
		],
		[
			"iPad",
			"iphone",
			[dojo.moduleUrl("dojox.mobile", "themes/iphone/ipad.css")]
		],
		[
			".*",
			"iphone",
			[]
		]
	];

	dojox.mobile.loadDeviceTheme = function(){
		var t = dojo.config["mblThemeFiles"] || dojox.mobile.themeFiles || ["@theme"];
		if(!dojo.isArray(t)){ console.log("loadDeviceTheme: array is expected but found: "+t); }
		var i, j;
		var m = dojox.mobile.themeMap;
		var ua = (location.search.match(/theme=(\w+)/)) ? RegExp.$1 : navigator.userAgent;
		for(i = 0; i < m.length; i++){
			if(ua.match(new RegExp(m[i][0]))){
				var theme = m[i][1];
				var files = m[i][2];
				for(j = t.length - 1; j >= 0; j--){
					var pkg = dojo.isArray(t[j]) ? t[j][0] : "dojox.mobile";
					var name = dojo.isArray(t[j]) ? t[j][1] : t[j];
					var f = "themes/" + theme + "/" +
						(name === "@theme" ? theme : name) + ".css";
					files.unshift(dojo.moduleUrl(pkg, f));
				}
				for(j = 0; j < files.length; j++){
					dojox.mobile.loadCssFile(files[j]);
				}
				break;
			}
		}
	};

	if(dojox.mobile.configDeviceTheme){
		dojox.mobile.configDeviceTheme();
	}
	dojox.mobile.loadDeviceTheme();

	return dojox.mobile.deviceTheme;
});
<commit_msg>Fixes #12961 toString() was necessary for objects returned from dojo.moduleUrl.<commit_after>define(["dojo/_base/array", "./_base"], function(darray,mbase){
	// module:
	//		dojox/mobile/deviceTheme
	// summary:
	//		Automatic Theme Loader
	// description:
	//		Detects the User Agent of the browser and loads appropriate theme files.
	//		Simply dojo.require this module to enable the automatic theme loading.
	//
	//		By default, an all-in-one theme file (e.g. themes/iphone/iphone.css) is
	//		loaded. The all-in-one theme files contain style sheets for all the
	//		dojox.mobile widgets regardless of whether they are used in your
	//		application or not.
	//		If you want to choose what theme files to load, you can specify them
	//		via djConfig as shown in the following example:
	//
	//	|	djConfig="parseOnLoad:true, mblThemeFiles:['base','Button']"
	//
	//		Or you may want to use dojox.mobile.themeFiles as follows to get the
	//		same result. Note that the assignment has to be done before loading
	//		deviceTheme.js.
	//
	//	|	dojo.require("dojox.mobile");
	//	|	dojox.mobile.themeFiles = ['base','Button'];
	//	|	dojo.require("dojox.mobile.deviceTheme");
	//
	//		In the case of this example, if iphone is detected, for example, the
	//		following files will be loaded:
	//
	//	|	dojox/mobile/themes/iphone/base.css
	//	|	dojox/mobile/themes/iphone/Button.css
	//
	//		If you want to load style sheets for your own custom widgets, you can
	//		specify a package name along with a theme file name in an array.
	//
	//	|	['base',['com.acme','MyWidget']]
	//
	//		In this case, the following files will be loaded.
	//
	//	|	dojox/mobile/themes/iphone/base.css
	//	|	com/acme/themes/iphone/MyWidget.css
	//
	//		If you specify '@theme' as a theme file name, it will be replaced with
	//		the theme folder name. For example,
	//
	//	|	['@theme',['com.acme','MyWidget']]
	//
	//		will load the following files.
	//
	//	|	dojox/mobile/themes/iphone/iphone.css
	//	|	com/acme/themes/iphone/MyWidget.css

	dojox.mobile.loadCssFile = function(/*String*/file){
		dojo.create("LINK", {
			href: file,
			type: "text/css",
			rel: "stylesheet"
		}, dojo.doc.getElementsByTagName('head')[0]);
	};

	dojox.mobile.themeMap = dojox.mobile.themeMap || [
		// summary:
		//		A map of user-agents to theme files.
		// description:
		//		The first array element is a regexp pattern that matches the
		//		userAgent string.
		//
		//		The second array element is a theme folder name.
		//
		//		The third array element is an array of css file paths to load.
		//
		//		The matching is performed in the array order, and stops after the
		//		first match.
		[
			"Android",
			"android",
			[]
		],
		[
			"BlackBerry",
			"blackberry",
			[]
		],
		[
			"iPad",
			"iphone",
			[dojo.moduleUrl("dojox.mobile", "themes/iphone/ipad.css")]
		],
		[
			".*",
			"iphone",
			[]
		]
	];

	dojox.mobile.loadDeviceTheme = function(){
		var t = dojo.config["mblThemeFiles"] || dojox.mobile.themeFiles || ["@theme"];
		if(!dojo.isArray(t)){ console.log("loadDeviceTheme: array is expected but found: "+t); }
		var i, j;
		var m = dojox.mobile.themeMap;
		var ua = (location.search.match(/theme=(\w+)/)) ? RegExp.$1 : navigator.userAgent;
		for(i = 0; i < m.length; i++){
			if(ua.match(new RegExp(m[i][0]))){
				var theme = m[i][1];
				var files = m[i][2];
				for(j = t.length - 1; j >= 0; j--){
					var pkg = dojo.isArray(t[j]) ? t[j][0] : "dojox.mobile";
					var name = dojo.isArray(t[j]) ? t[j][1] : t[j];
					var f = "themes/" + theme + "/" +
						(name === "@theme" ? theme : name) + ".css";
					files.unshift(dojo.moduleUrl(pkg, f));
				}
				for(j = 0; j < files.length; j++){
					dojox.mobile.loadCssFile(files[j].toString());
				}
				break;
			}
		}
	};

	if(dojox.mobile.configDeviceTheme){
		dojox.mobile.configDeviceTheme();
	}
	dojox.mobile.loadDeviceTheme();

	return dojox.mobile.deviceTheme;
});
<|endoftext|>