<commit_before>/*
Copyright 2016 OpenMarket Ltd

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.
*/

import React from 'react';
import MatrixClientPeg from '../../../MatrixClientPeg';
import {instanceForInstanceId} from '../../../utils/DirectoryUtils';

const DEFAULT_ICON_URL = require("../../../../res/img/network-matrix.svg");

export default class NetworkDropdown extends React.Component {
    constructor(props) {
        super(props);

        this.dropdownRootElement = null;
        this.ignoreEvent = null;

        this.onInputClick = this.onInputClick.bind(this);
        this.onRootClick = this.onRootClick.bind(this);
        this.onDocumentClick = this.onDocumentClick.bind(this);
        this.onMenuOptionClick = this.onMenuOptionClick.bind(this);
        this.onInputKeyUp = this.onInputKeyUp.bind(this);
        this.collectRoot = this.collectRoot.bind(this);
        this.collectInputTextBox = this.collectInputTextBox.bind(this);

        this.inputTextBox = null;

        const server = MatrixClientPeg.getHomeServerName();
        this.state = {
            expanded: false,
            selectedServer: server,
            selectedInstance: null,
            includeAllNetworks: false,
        };
    }

    componentWillMount() {
        // Listen for all clicks on the document so we can close the
        // menu when the user clicks somewhere else
        document.addEventListener('click', this.onDocumentClick, false);

        // fire this now so the defaults can be set up
        this.props.onOptionChange(this.state.selectedServer, this.state.selectedInstance, this.state.includeAllNetworks);
    }

    componentWillUnmount() {
        document.removeEventListener('click', this.onDocumentClick, false);
    }

    componentDidUpdate() {
        if (this.state.expanded && this.inputTextBox) {
            this.inputTextBox.focus();
        }
    }

    onDocumentClick(ev) {
        // Close the dropdown if the user clicks anywhere that isn't
        // within our root element
        if (ev !== this.ignoreEvent) {
            this.setState({
                expanded: false,
            });
        }
    }

    onRootClick(ev) {
        // This captures any clicks that happen within our elements,
        // such that we can then ignore them when they're seen by the
        // click listener on the document handler, ie. not close the
        // dropdown immediately after opening it.
        // NB. We can't just stopPropagation() because then the event
        // doesn't reach the React onClick().
        this.ignoreEvent = ev;
    }

    onInputClick(ev) {
        this.setState({
            expanded: !this.state.expanded,
        });
        ev.preventDefault();
    }

    onMenuOptionClick(server, instance, includeAll) {
        this.setState({
            expanded: false,
            selectedServer: server,
            selectedInstanceId: instance ? instance.instance_id : null,
            includeAll: includeAll,
        });
        this.props.onOptionChange(server, instance ? instance.instance_id : null, includeAll);
    }

    onInputKeyUp(e) {
        if (e.key == 'Enter') {
            this.setState({
                expanded: false,
                selectedServer: e.target.value,
                selectedNetwork: null,
            });
            this.props.onOptionChange(e.target.value, null);
        }
    }

    collectRoot(e) {
        if (this.dropdownRootElement) {
            this.dropdownRootElement.removeEventListener('click', this.onRootClick, false);
        }
        if (e) {
            e.addEventListener('click', this.onRootClick, false);
        }
        this.dropdownRootElement = e;
    }

    collectInputTextBox(e) {
        this.inputTextBox = e;
    }

    _getMenuOptions() {
        const options = [];

        let servers = [];
        if (this.props.config.servers) {
            servers = servers.concat(this.props.config.servers);
        }

        if (servers.indexOf(MatrixClientPeg.getHomeServerName()) == -1) {
            servers.unshift(MatrixClientPeg.getHomeServerName());
        }

        // For our own HS, we can use the instance_ids given in the third party protocols
        // response to get the server to filter the room list by network for us.
        // We can't get thirdparty protocols for remote server yet though, so for those
        // we can only show the default room list.
        for (const server of servers) {
            options.push(this._makeMenuOption(server, null, true));
            if (server == MatrixClientPeg.getHomeServerName()) {
                options.push(this._makeMenuOption(server, null, false));
                if (this.props.protocols) {
                    for (const proto of Object.keys(this.props.protocols)) {
                        if (!this.props.protocols[proto].instances) continue;

                        const sortedInstances = this.props.protocols[proto].instances;
                        sortedInstances.sort(function(x, y) {
                            const a = x.desc;
                            const b = y.desc;
                            if (a  b) {
                                return 1;
                            } else {
                                return 0;
                            }
                        });

                        for (const instance of sortedInstances) {
                            if (!instance.instance_id) continue;
                            options.push(this._makeMenuOption(server, instance, false));
                        }
                    }
                }
            }
        }

        return options;
    }

    _makeMenuOption(server, instance, includeAll, handleClicks) {
        if (handleClicks === undefined) handleClicks = true;

        let icon;
        let name;
        let span_class;
        let key;

        if (!instance && includeAll) {
            key = server;
            name = server;
            span_class = 'mx_NetworkDropdown_menu_all';
        } else if (!instance) {
            key = server + '_all';
            name = 'Matrix';
            icon = ;
            span_class = 'mx_NetworkDropdown_menu_network';
        } else {
            key = server + '_inst_' + instance.instance_id;
            const imgUrl = instance.icon ?
                MatrixClientPeg.get().mxcUrlToHttp(instance.icon, 25, 25, 'crop', true) :
                DEFAULT_ICON_URL;
            icon = ;
            name = instance.desc;
            span_class = 'mx_NetworkDropdown_menu_network';
        }

        const click_handler = handleClicks ? this.onMenuOptionClick.bind(this, server, instance, includeAll) : null;

        return

            {icon}
            {name}

;
    }

    render() {
        let current_value;

        let menu;
        if (this.state.expanded) {
            const menu_options = this._getMenuOptions();
            menu =

                {menu_options}

;
            current_value = <input type="text" className="mx_NetworkDropdown_networkoption"
                ref={this.collectInputTextBox} onKeyUp={this.onInputKeyUp}
                placeholder="matrix.org" // 'matrix.org' as an example of an HS name
            />;
        } else {
            const instance = instanceForInstanceId(this.props.protocols, this.state.selectedInstanceId);
            current_value = this._makeMenuOption(
                this.state.selectedServer, instance, this.state.includeAll, false,
            );
        }

        return

                {current_value}

                {menu}

;
    }
}

NetworkDropdown.propTypes = {
    onOptionChange: React.PropTypes.func.isRequired,
    protocols: React.PropTypes.object,
    // The room directory config. May have a 'servers' key that is a list of server names to include in the dropdown
    config: React.PropTypes.object,
};

NetworkDropdown.defaultProps = {
    protocols: {},
    config: {},
};
<commit_msg>RoomDirectory Dropdown should use roomDirectory.servers<commit_after>/*
Copyright 2016 OpenMarket Ltd

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.
*/

import React from 'react';
import MatrixClientPeg from '../../../MatrixClientPeg';
import {instanceForInstanceId} from '../../../utils/DirectoryUtils';

const DEFAULT_ICON_URL = require("../../../../res/img/network-matrix.svg");

export default class NetworkDropdown extends React.Component {
    constructor(props) {
        super(props);

        this.dropdownRootElement = null;
        this.ignoreEvent = null;

        this.onInputClick = this.onInputClick.bind(this);
        this.onRootClick = this.onRootClick.bind(this);
        this.onDocumentClick = this.onDocumentClick.bind(this);
        this.onMenuOptionClick = this.onMenuOptionClick.bind(this);
        this.onInputKeyUp = this.onInputKeyUp.bind(this);
        this.collectRoot = this.collectRoot.bind(this);
        this.collectInputTextBox = this.collectInputTextBox.bind(this);

        this.inputTextBox = null;

        const server = MatrixClientPeg.getHomeServerName();
        this.state = {
            expanded: false,
            selectedServer: server,
            selectedInstance: null,
            includeAllNetworks: false,
        };
    }

    componentWillMount() {
        // Listen for all clicks on the document so we can close the
        // menu when the user clicks somewhere else
        document.addEventListener('click', this.onDocumentClick, false);

        // fire this now so the defaults can be set up
        this.props.onOptionChange(this.state.selectedServer, this.state.selectedInstance, this.state.includeAllNetworks);
    }

    componentWillUnmount() {
        document.removeEventListener('click', this.onDocumentClick, false);
    }

    componentDidUpdate() {
        if (this.state.expanded && this.inputTextBox) {
            this.inputTextBox.focus();
        }
    }

    onDocumentClick(ev) {
        // Close the dropdown if the user clicks anywhere that isn't
        // within our root element
        if (ev !== this.ignoreEvent) {
            this.setState({
                expanded: false,
            });
        }
    }

    onRootClick(ev) {
        // This captures any clicks that happen within our elements,
        // such that we can then ignore them when they're seen by the
        // click listener on the document handler, ie. not close the
        // dropdown immediately after opening it.
        // NB. We can't just stopPropagation() because then the event
        // doesn't reach the React onClick().
        this.ignoreEvent = ev;
    }

    onInputClick(ev) {
        this.setState({
            expanded: !this.state.expanded,
        });
        ev.preventDefault();
    }

    onMenuOptionClick(server, instance, includeAll) {
        this.setState({
            expanded: false,
            selectedServer: server,
            selectedInstanceId: instance ? instance.instance_id : null,
            includeAll: includeAll,
        });
        this.props.onOptionChange(server, instance ? instance.instance_id : null, includeAll);
    }

    onInputKeyUp(e) {
        if (e.key == 'Enter') {
            this.setState({
                expanded: false,
                selectedServer: e.target.value,
                selectedNetwork: null,
            });
            this.props.onOptionChange(e.target.value, null);
        }
    }

    collectRoot(e) {
        if (this.dropdownRootElement) {
            this.dropdownRootElement.removeEventListener('click', this.onRootClick, false);
        }
        if (e) {
            e.addEventListener('click', this.onRootClick, false);
        }
        this.dropdownRootElement = e;
    }

    collectInputTextBox(e) {
        this.inputTextBox = e;
    }

    _getMenuOptions() {
        const options = [];

        let servers = [];
        if (this.props.config.roomDirectory.servers) {
            servers = servers.concat(this.props.config.roomDirectory.servers);
        }

        if (servers.indexOf(MatrixClientPeg.getHomeServerName()) == -1) {
            servers.unshift(MatrixClientPeg.getHomeServerName());
        }

        // For our own HS, we can use the instance_ids given in the third party protocols
        // response to get the server to filter the room list by network for us.
        // We can't get thirdparty protocols for remote server yet though, so for those
        // we can only show the default room list.
        for (const server of servers) {
            options.push(this._makeMenuOption(server, null, true));
            if (server == MatrixClientPeg.getHomeServerName()) {
                options.push(this._makeMenuOption(server, null, false));
                if (this.props.protocols) {
                    for (const proto of Object.keys(this.props.protocols)) {
                        if (!this.props.protocols[proto].instances) continue;

                        const sortedInstances = this.props.protocols[proto].instances;
                        sortedInstances.sort(function(x, y) {
                            const a = x.desc;
                            const b = y.desc;
                            if (a  b) {
                                return 1;
                            } else {
                                return 0;
                            }
                        });

                        for (const instance of sortedInstances) {
                            if (!instance.instance_id) continue;
                            options.push(this._makeMenuOption(server, instance, false));
                        }
                    }
                }
            }
        }

        return options;
    }

    _makeMenuOption(server, instance, includeAll, handleClicks) {
        if (handleClicks === undefined) handleClicks = true;

        let icon;
        let name;
        let span_class;
        let key;

        if (!instance && includeAll) {
            key = server;
            name = server;
            span_class = 'mx_NetworkDropdown_menu_all';
        } else if (!instance) {
            key = server + '_all';
            name = 'Matrix';
            icon = ;
            span_class = 'mx_NetworkDropdown_menu_network';
        } else {
            key = server + '_inst_' + instance.instance_id;
            const imgUrl = instance.icon ?
                MatrixClientPeg.get().mxcUrlToHttp(instance.icon, 25, 25, 'crop', true) :
                DEFAULT_ICON_URL;
            icon = ;
            name = instance.desc;
            span_class = 'mx_NetworkDropdown_menu_network';
        }

        const click_handler = handleClicks ? this.onMenuOptionClick.bind(this, server, instance, includeAll) : null;

        return

            {icon}
            {name}

;
    }

    render() {
        let current_value;

        let menu;
        if (this.state.expanded) {
            const menu_options = this._getMenuOptions();
            menu =

                {menu_options}

;
            current_value = <input type="text" className="mx_NetworkDropdown_networkoption"
                ref={this.collectInputTextBox} onKeyUp={this.onInputKeyUp}
                placeholder="matrix.org" // 'matrix.org' as an example of an HS name
            />;
        } else {
            const instance = instanceForInstanceId(this.props.protocols, this.state.selectedInstanceId);
            current_value = this._makeMenuOption(
                this.state.selectedServer, instance, this.state.includeAll, false,
            );
        }

        return

                {current_value}

                {menu}

;
    }
}

NetworkDropdown.propTypes = {
    onOptionChange: React.PropTypes.func.isRequired,
    protocols: React.PropTypes.object,
    // The room directory config. May have a 'servers' key that is a list of server names to include in the dropdown
    config: React.PropTypes.object,
};

NetworkDropdown.defaultProps = {
    protocols: {},
    config: {},
};
<|endoftext|>


<commit_before>"use strict";

const leap = require('../lib/isLeap.js');
const zellers = require('../lib/zeller.js');
const _ = require('lodash');

function howManyDays (year, month) {
  const toLeap = leap.leapYear(year);
  let manyDays = 31;

  if (month === 4 ||
      month === 6 ||
      month === 9 ||
      month === 11) {
    manyDays = 30;
  } else if (month === 2) {
    if (toLeap) {
      manyDays = 29;
    } else {
      manyDays = 28;
    }
  }

  return manyDays;
}

function weeks (year, month) {
  const days = howManyDays(year, month);
  const startDay = zellers.getDay(year, month, 1);

  let numweeks = Math.ceil( (days + startDay) / 7);

  return numweeks;
}

//Spaces on left should be based on the ratio of half the month + year length to get 20 characters
//September = 9 + 1space + 2016 = 4 === 14, so 3 spaces needed to center it?
//function monthHeaderSpace (year, month, os) {
function createMonthHeader (year, month, os) {
  const allMonths = ['January', 'February', 'March', 'April', 'May', ' June', ' July', 'August', 'September', 'October', ' November', ' December'];
  let thisMonth = allMonths[month-1];

  var base = `${thisMonth} ${year}`;
  var lspace = Math.floor((20 - base.length) / 2);
  var rspace = Math.ceil((20 - base.length) / 2);
  var lspacer = ' '.repeat(lspace);
  var rspacer = ' '.repeat(rspace) + '  ';
  var monthHeader;
  if (os === 'darwin') {
    monthHeader = `${lspacer}${base}\n`;
  } else {
    monthHeader = `${lspacer}${base}${rspacer}\n`;
  }

  return monthHeader;
}

//Day columns are always 20 characters wide
function printDayColumns (os) {
  var extraSpace;
  if (os === 'darwin') {
    extraSpace = ``;
  } else {
    extraSpace = `  `;
  }

  return `Su Mo Tu We Th Fr Sa${extraSpace}`;
}

function rowPrint (rowsByWeeks, os) {
  let numweeks = rowsByWeeks.length
  let calBody = '';
  var extraSpace;
  if (os === 'darwin') {
    extraSpace = ``;
  } else {
    extraSpace = `  `;
  }

  for (var i = 0; i < numweeks; i++) {
    calBody += `${rowsByWeeks[i].join(' ')}${extraSpace}`;

    if (os === 'darwin') {
      calBody = calBody.replace(/\s*$/,"");
    }

    if (i < 5) {
      calBody += `\n`;
    }

    if (os === 'darwin' && i === 5) {
      calBody += `\n`;
    }

  }

  return calBody;

}

function highlightCurrentDay (year, month, os) {
  var d = new Date();
  var n = d.getDate().toString();
  var m = d.getMonth();
  var y = d.getFullYear();
  var boldDate;

  if ((os !== 'darwin') && (year === y) && (m === month)) {
    if (n.length === 1) {
      boldDate = `_\b _\b${n}`;
      return boldDate;
    } else {
      var answer = n.split('');
      boldDate = `_\b${answer}_\b${answer}`;
      return boldDate;
    }
  }

}

function createWeeks (year, month, os) {
  const days = howManyDays(year, month);
  const startDay = zellers.getDay(year, month, 1);
  let arraysForDays = [];
  var i = 0;
  var d = new Date();
  var n = d.getDate();
  var boldDate = highlightCurrentDay(year, month, os);

  for (i = 0; i < days; i++) {
    if (i < 9) {
      arraysForDays[i] = ` ${i+1}`;
    } else {
      arraysForDays[i] = `${i+1}`;
    }

    if (os !== 'darwin' && (n === i+1)) {
      arraysForDays[i] = boldDate;
    }
  }

  for (i = 0; i < startDay; i++) {
    arraysForDays.unshift('  ');
  }

  var newIndex = arraysForDays.length;

  for (i = newIndex; i < 42; i++) {
    arraysForDays.push('  ');
  }

  return _.chunk(arraysForDays, 7);
}

function joinOutput (year, month, os) {
  let theMonth = createWeeks(year, month, os);
  let part = printDayColumns(os);
  let output = createMonthHeader(year, month, os);
  output += `${part}\n`;
  output += rowPrint(theMonth, os);
//  console.log(monthHeaderSpace(year, month, os));
  return output;
}

module.exports = {
  createWeeks: createWeeks,
  createMonthHeader: createMonthHeader,
  printDayColumns: printDayColumns,
  joinOutput: joinOutput,
  weeks: weeks,
  howManyDays: howManyDays,
  highlightCurrentDay: highlightCurrentDay,
  rowPrint: rowPrint
  }
<commit_msg>testing returns<commit_after>"use strict";

const leap = require('../lib/isLeap.js');
const zellers = require('../lib/zeller.js');
const _ = require('lodash');

function howManyDays (year, month) {
  const toLeap = leap.leapYear(year);
  let manyDays = 31;

  if (month === 4 ||
      month === 6 ||
      month === 9 ||
      month === 11) {
    manyDays = 30;
  } else if (month === 2) {
    if (toLeap) {
      manyDays = 29;
    } else {
      manyDays = 28;
    }
  }

  return manyDays;
}

function weeks (year, month) {
  const days = howManyDays(year, month);
  const startDay = zellers.getDay(year, month, 1);

  let numweeks = Math.ceil( (days + startDay) / 7);

  return numweeks;
}

//Spaces on left should be based on the ratio of half the month + year length to get 20 characters
//September = 9 + 1space + 2016 = 4 === 14, so 3 spaces needed to center it?
//function monthHeaderSpace (year, month, os) {
function createMonthHeader (year, month, os) {
  const allMonths = ['January', 'February', 'March', 'April', 'May', ' June', ' July', 'August', 'September', 'October', ' November', ' December'];
  let thisMonth = allMonths[month-1];

  var base = `${thisMonth} ${year}`;
  var lspace = Math.floor((20 - base.length) / 2);
  var rspace = Math.ceil((20 - base.length) / 2);
  var lspacer = ' '.repeat(lspace);
  var rspacer = ' '.repeat(rspace) + '  ';
  var monthHeader;
  if (os === 'darwin') {
    monthHeader = `${lspacer}${base}\n`;
  } else {
    monthHeader = `${lspacer}${base}${rspacer}\n`;
  }

  return monthHeader;
}

//Day columns are always 20 characters wide
function printDayColumns (os) {
  var extraSpace;
  if (os === 'darwin') {
    extraSpace = ``;
  } else {
    extraSpace = `  `;
  }

  return `Su Mo Tu We Th Fr Sa${extraSpace}`;
}

function rowPrint (rowsByWeeks, os) {
  let numweeks = rowsByWeeks.length
  let calBody = '';
  var extraSpace;
  if (os === 'darwin') {
    extraSpace = ``;
  } else {
    extraSpace = `  `;
  }

  for (var i = 0; i < numweeks; i++) {
    calBody += `${rowsByWeeks[i].join(' ')}${extraSpace}`;

    if (os === 'darwin') {
      calBody = calBody.replace(/\s*$/,"");
    }

    if (i < 5) {
      calBody += `\n`;
    }

    if (os === 'darwin' && i === 5) {
      calBody += `\n`;
    }

  }

  return calBody;

}

function highlightCurrentDay (year, month, os) {
  var d = new Date();
  var n = d.getDate().toString();
  var m = d.getMonth();
  var y = d.getFullYear();
  var boldDate;

  if ((os !== 'darwin') && (year === y) && (m === month)) {
    if (n.length === 1) {
      boldDate = `_\b _\b${n}`;
      return boldDate;
    } else {
      var answer = n.split('');
      boldDate = `_\b${answer}_\b${answer}`;
      return boldDate;
    }
  }

}

function createWeeks (year, month, os) {
  const days = howManyDays(year, month);
  const startDay = zellers.getDay(year, month, 1);
  let arraysForDays = [];
  var i = 0;
  var d = new Date();
  var m = d.getMonth();
  var n = d.getDate();
  var boldDate = highlightCurrentDay(year, month, os);

  for (i = 0; i < days; i++) {
    if (i < 9) {
      arraysForDays[i] = ` ${i+1}`;
    } else {
      arraysForDays[i] = `${i+1}`;
    }

    if (boldDate && (n === i+1) && (month === m)) {
      arraysForDays[i] = boldDate;
    }
  }

  for (i = 0; i < startDay; i++) {
    arraysForDays.unshift('  ');
  }

  var newIndex = arraysForDays.length;

  for (i = newIndex; i < 42; i++) {
    arraysForDays.push('  ');
  }

  return _.chunk(arraysForDays, 7);
}

function joinOutput (year, month, os) {
  let theMonth = createWeeks(year, month, os);
  let part = printDayColumns(os);
  let output = createMonthHeader(year, month, os);
  output += `${part}\n`;
  output += rowPrint(theMonth, os);
//  console.log(monthHeaderSpace(year, month, os));
  return output;
}

module.exports = {
  createWeeks: createWeeks,
  createMonthHeader: createMonthHeader,
  printDayColumns: printDayColumns,
  joinOutput: joinOutput,
  weeks: weeks,
  howManyDays: howManyDays,
  highlightCurrentDay: highlightCurrentDay,
  rowPrint: rowPrint
  }
<|endoftext|>


<commit_before>var _       = require('lodash');
var Promise = require('bluebird');

var search = require('./search');
var query  = require('./query');

var modelOptions = {};

function Model(connection, defaults, opt,schema) {
  this.index = opt.index || defaults.index;
  this.type = opt.type || defaults.type;
  this.connection = connection;
  this.schema = schema;
  // TODO after the props have been set it should check to see if the index exists
  // if the index does not exists then it should create the index mapping
  // based off of the schema mappings
  // There should also be strict mapping vs non strict

  var mapping = this.schema.getIndexMappingJSON();
  // todo compare mappings.
  connection.indices.putMapping({index:this.index,type:this.type, body:mapping })
}

/**
 * # Model
 */

/**
 * Creates an elasticsearch document
 *
 * To create the documents with your own id set the *opt.id* property to the id you want for that document.
 * @param  {Object}   doc the body of the elasticsearch document
 * @param  {Object}   opt Optional options objectg
 * @param  {Function} cb  Optional callback
 * @return {Promise}       If there is no callback it will return a promise
 */
Model.prototype.create = function (doc, opt, cb) {
  if (!opt) opt = {};
  var err = this.schema.validateDoc(doc);
  if (err.length > 0) {
    if (cb)
      cb({ msg: err.join('\m') }, undefined);
    else
      throw new Error(err.join('\n'));
  }else {
    var body = {
      body: this.schema.applySchema(doc)
    };
    return this
      .connection
      .create(_.merge(
        {
          index: this.index,
          type: this.type,
          id: opt.id
        }, body),
      cb
    );
  }
}

/**
 * Update document by id
 * @param  {String|Number|ElasticsearchId}   id  document id
 * @param  {Object}   doc body
 * @param  {Object}   opt Optional options object
 * @param  {Function} cb  Optional callback
 * @return {Promise}       If there is no callback it will return a promise
 */
Model.prototype.update = function (id, doc, opt, cb) {
  if (!opt) opt = {};

  return this
    .connection
    .update(_.merge(
      {
        index: this.index,
        type: this.type,
        id: id,
        body: {
          doc: doc
        }
      }, opt),
      cb
    );
}

/**
 * Deletes a document based of the supllied id
 * @param  {String|Number|ElasicsearchId}   id  document id
 * @param  {Object}   opt Optional options object
 * @param  {Function} cb  Optional callback
 * @return {Promise}       If there is no callback it will return a promise
 */
Model.prototype.delete = function (id, opt, cb) {
  if (!opt) opt = {};

  return this
    .connection
    .delete(_.merge(
      {
        index: this.index,
        type: this.type,
        id: id
      }, opt),
      cb
    );
}

/**
 * Delete document by a query
 * @param  {Object}   body Query body
 * @param  {Object}   opt Optional options object
 * @param  {Function} cb  Optional callback
 * @return {Promise}       If there is no callback it will return a promise
 */
Model.prototype.deleteByQuery = function (body, opt, cb) {
  if (!opt) opt = {};

  return this
    .connection
    .deleteByQuery(_.merge(
      {
        index: this.index,
        type: this.type,
        body: body
      }, opt),
      cb
    );
}

Model.prototype = _.merge(Model.prototype, query);

Model.prototype = _.merge(Model.prototype, search);

module.exports = Model;

/**
 * ## Query API
 *
 * Click [here](https://github.com/LucioFranco/Rebound-ODM/blob/master/API.md#query) for the Query API
 *
 * ## Search API
 *
 * Click [here](https://github.com/LucioFranco/Rebound-ODM/blob/master/API.md#search) for the Search API
 */
<commit_msg>fix for ids on create<commit_after>var _       = require('lodash');
var Promise = require('bluebird');

var search = require('./search');
var query  = require('./query');

var modelOptions = {};

function Model(connection, defaults, opt,schema) {
  this.index = opt.index || defaults.index;
  this.type = opt.type || defaults.type;
  this.connection = connection;
  this.schema = schema;
  // TODO after the props have been set it should check to see if the index exists
  // if the index does not exists then it should create the index mapping
  // based off of the schema mappings
  // There should also be strict mapping vs non strict

  var mapping = this.schema.getIndexMappingJSON();
  console.log(this.schema.getIndexMapping())
  // todo compare mappings.
  connection.indices.putMapping({index:this.index,type:this.type, body:mapping.properties })
}

/**
 * # Model
 */

/**
 * Creates an elasticsearch document
 *
 * To create the documents with your own id set the *opt.id* property to the id you want for that document.
 * @param  {Object}   doc the body of the elasticsearch document
 * @param  {Object}   opt Optional options objectg
 * @param  {Function} cb  Optional callback
 * @return {Promise}       If there is no callback it will return a promise
 */
Model.prototype.create = function (doc, opt, cb) {
  if (!opt) opt = {};
  var err = this.schema.validateDoc(doc);
  if (err.length > 0) {
    if (cb)
      cb({ msg: err.join('\m') }, undefined);
    else
      throw new Error(err.join('\n'));
  }else {
    var body = {
      body: this.schema.applySchema(doc)
    };
    return this
      .connection
      .create(_.merge(
        {
          index: this.index,
          type: this.type,
          id: opt.id
        }, body),
      cb
    );
  }
}

/**
 * Update document by id
 * @param  {String|Number|ElasticsearchId}   id  document id
 * @param  {Object}   doc body
 * @param  {Object}   opt Optional options object
 * @param  {Function} cb  Optional callback
 * @return {Promise}       If there is no callback it will return a promise
 */
Model.prototype.update = function (id, doc, opt, cb) {
  if (!opt) opt = {};

  return this
    .connection
    .update(_.merge(
      {
        index: this.index,
        type: this.type,
        id: id,
        body: {
          doc: doc
        }
      }, opt),
      cb
    );
}

/**
 * Deletes a document based of the supllied id
 * @param  {String|Number|ElasicsearchId}   id  document id
 * @param  {Object}   opt Optional options object
 * @param  {Function} cb  Optional callback
 * @return {Promise}       If there is no callback it will return a promise
 */
Model.prototype.delete = function (id, opt, cb) {
  if (!opt) opt = {};

  return this
    .connection
    .delete(_.merge(
      {
        index: this.index,
        type: this.type,
        id: id
      }, opt),
      cb
    );
}

/**
 * Delete document by a query
 * @param  {Object}   body Query body
 * @param  {Object}   opt Optional options object
 * @param  {Function} cb  Optional callback
 * @return {Promise}       If there is no callback it will return a promise
 */
Model.prototype.deleteByQuery = function (body, opt, cb) {
  if (!opt) opt = {};

  return this
    .connection
    .deleteByQuery(_.merge(
      {
        index: this.index,
        type: this.type,
        body: body
      }, opt),
      cb
    );
}

Model.prototype = _.merge(Model.prototype, query);

Model.prototype = _.merge(Model.prototype, search);

module.exports = Model;

/**
 * ## Query API
 *
 * Click [here](https://github.com/LucioFranco/Rebound-ODM/blob/master/API.md#query) for the Query API
 *
 * ## Search API
 *
 * Click [here](https://github.com/LucioFranco/Rebound-ODM/blob/master/API.md#search) for the Search API
 */
<|endoftext|>


<commit_before>/**!
 * Part of the jMediaelement-Project | http://github.com/aFarkas/jMediaelement
 * @author Alexander Farkas
 * Copyright 2010, Alexander Farkas
 * Dual licensed under the MIT or GPL Version 2 licenses.
 */
(function($){
	$.extend($.fn.mediaElementEmbed.defaults,
			{
				vlc: {}
			}
		)
	;

	var doc	 			= document,
		defaultAttrs 	= {
			pluginspage: 'http://www.videolan.org',
			version: 'VideoLAN.VLCPlugin.2',
			progid: 'VideoLAN.VLCPlugin.2',
			events: 'true',
			type: 'application/x-vlc-plugin'
		},
		activeXAttrs 	= {
			classid: 'clsid:9BE31822-FDAD-461B-AD51-BE1D1C159921'
		}
	;
	function embedVlc(elem, id, attrs, params){
		var vlc;
		attrs = $.extend({}, defaultAttrs, attrs);
		if(!window.ActiveXObject){
			vlc = doc.createElement('object');
			$.each(attrs, function(name, val){
				vlc.setAttribute(name, val);
			});

			$.each(params, function(name, val){
				var param = doc.createElement('param');
				param.setAttribute('name', name);
				param.setAttribute('value', val);
				vlc.appendChild(param);
			});
			vlc.setAttribute('id', id);
			vlc.setAttribute('name', id);
			elem.parentNode.replaceChild(vlc, elem);
		} else if(elem.outerHTML){
			vlc = '<object';
			$.each($.extend({}, attrs, activeXAttrs), function(name, val){
				vlc += ' '+ name +'="'+ val +'"';
			});
			vlc += ' name="'+ id +'"';
			vlc += ' id="'+ id +'"';
			vlc += '>';
			$.each(params, function(name, val){
				vlc += ' <param name="'+ name +'" value="'+ val +'" />';
			});
			vlc += '</object>';
			elem.outerHTML = vlc;
			vlc = doc.getElementById(id);
		}
		return vlc;
	}
	var vlcMM = {
			isTechAvailable: function(){
				if($.support.vlc !== undefined){
					return $.support.vlc;
				}
				$.support.vlc = false;
				if(navigator.plugins && navigator.plugins.length){
					$.each(navigator.plugins, function(i, plugin){
						if((plugin.name || '').toLowerCase() === 'vlc multimedia plug-in'){
							$.support.vlc = true;
							return false;
						}
					});

				} else if(window.ActiveXObject){
					try {
						new ActiveXObject('VideoLAN.VLCPlugin.2');
						$.support.vlc = true;
					} catch(e){}
				}
				return $.support.vlc;
			},
			_embed: function(src, id, api, dims, attrs, fn){

				var opts 	= api.embedOpts.vlc,
					vlcAttr = $.extend({}, dims, {src: src}),
					params 	= {
						src: src,
						ShowDisplay: 'true',
						AutoPlay: ''+ attrs.autoplay,//
						AutoLoop: ''+attrs.loop
					},
					vlc
				;
				$.extend(vlcAttr, params);
				vlc = $('<div />').css(dims).insertBefore(api.html5elem);
				vlc = $(embedVlc(vlc[0], id, vlcAttr, params)).css(dims);
				fn(vlc[0]);
			},
			canPlayCodecs: ['avc1.42E01E', 'mp4a.40.2', 'avc1.58A01E', 'avc1.4D401E', 'avc1.64001E', 'theora', 'vorbis'],
			canPlayContainer: ['video/x-msvideo', 'video/quicktime', 'video/x-m4v', 'video/mp4', 'video/m4p', 'video/x-flv', 'video/flv', 'audio/mpeg', 'audio/x-fla', 'audio/fla', 'video/ogg', 'video/x-ogg', 'audio/x-ogg', 'audio/ogg', 'application/ogg', 'application/x-ogg']
		}
	;

	$.multimediaSupport.add('vlc', 'video', vlcMM);
	$.multimediaSupport.add('vlc', 'audio', vlcMM);
})(jQuery);
<commit_msg>added bulletproof active x detection for activex<commit_after>/**!
 * Part of the jMediaelement-Project | http://github.com/aFarkas/jMediaelement
 * @author Alexander Farkas
 * Copyright 2010, Alexander Farkas
 * Dual licensed under the MIT or GPL Version 2 licenses.
 */
(function($){
	$.extend($.fn.mediaElementEmbed.defaults,
			{
				vlc: {}
			}
		)
	;

	var doc	 			= document,
		defaultAttrs 	= {
			pluginspage: 'http://www.videolan.org',
			version: 'VideoLAN.VLCPlugin.2',
			progid: 'VideoLAN.VLCPlugin.2',
			events: 'true',
			type: 'application/x-vlc-plugin'
		},
		activeXAttrs 	= {
			classid: 'clsid:9BE31822-FDAD-461B-AD51-BE1D1C159921'
		}
	;
	function embedVlc(elem, id, attrs, params){
		var vlc;
		attrs = $.extend({}, defaultAttrs, attrs);
		if(!window.ActiveXObject){
			vlc = doc.createElement('object');
			$.each(attrs, function(name, val){
				vlc.setAttribute(name, val);
			});

			$.each(params, function(name, val){
				var param = doc.createElement('param');
				param.setAttribute('name', name);
				param.setAttribute('value', val);
				vlc.appendChild(param);
			});
			vlc.setAttribute('id', id);
			vlc.setAttribute('name', id);
			elem.parentNode.replaceChild(vlc, elem);
		} else if(elem.outerHTML){
			vlc = '<object';
			$.each($.extend({}, attrs, activeXAttrs), function(name, val){
				vlc += ' '+ name +'="'+ val +'"';
			});
			vlc += ' name="'+ id +'"';
			vlc += ' id="'+ id +'"';
			vlc += '>';
			$.each(params, function(name, val){
				vlc += ' <param name="'+ name +'" value="'+ val +'" />';
			});
			vlc += '</object>';
			elem.outerHTML = vlc;
			vlc = doc.getElementById(id);
		}
		return vlc;
	}
	var vlcMM = {
			isTechAvailable: function(){
				if($.support.vlc !== undefined){
					return $.support.vlc;
				}
				$.support.vlc = false;
				if(navigator.plugins && navigator.plugins.length){
					$.each(navigator.plugins, function(i, plugin){
						if((plugin.name || '').toLowerCase() === 'vlc multimedia plug-in'){
							$.support.vlc = true;
							return false;
						}
					});

				} else if(window.ActiveXObject){
					try {
						if(new ActiveXObject('VideoLAN.VLCPlugin.2')){
							$.support.vlc = true;
						}
					} catch(e){}
				}
				return $.support.vlc;
			},
			_embed: function(src, id, api, dims, attrs, fn){

				var opts 	= api.embedOpts.vlc,
					vlcAttr = $.extend({}, dims, {src: src}),
					params 	= {
						src: src,
						ShowDisplay: 'true',
						AutoPlay: ''+ attrs.autoplay,//
						AutoLoop: ''+attrs.loop
					},
					vlc
				;
				$.extend(vlcAttr, params);
				vlc = $('<div />').css(dims).insertBefore(api.html5elem);
				vlc = $(embedVlc(vlc[0], id, vlcAttr, params)).css(dims);
				fn(vlc[0]);
			},
			canPlayCodecs: ['avc1.42E01E', 'mp4a.40.2', 'avc1.58A01E', 'avc1.4D401E', 'avc1.64001E', 'theora', 'vorbis'],
			canPlayContainer: ['video/x-msvideo', 'video/quicktime', 'video/x-m4v', 'video/mp4', 'video/m4p', 'video/x-flv', 'video/flv', 'audio/mpeg', 'audio/x-fla', 'audio/fla', 'video/ogg', 'video/x-ogg', 'audio/x-ogg', 'audio/ogg', 'application/ogg', 'application/x-ogg']
		}
	;

	$.multimediaSupport.add('vlc', 'video', vlcMM);
	$.multimediaSupport.add('vlc', 'audio', vlcMM);
})(jQuery);
<|endoftext|>


<commit_before>var tsort         = require('tsort'),
	_             = require('lodash'),
	AliasResolver = require('./aliases'),
	UA            = require('./UA'),
	sources       = require('./sources');

// Polyfill String.prototype.startsWith
if (!String.prototype.startsWith) {
	require('../polyfills/String.prototype.startsWith/polyfill');
}

require('es6-promise').polyfill();

// Load additional useragent features: primarily to use: agent.satisfies to
// test a browser version against a semver string
require('useragent/features');

"use strict";

function getAllPolyfills() {
	return sources.latest.listPolyfills();
}

function getOptions(opts) {
	return _.extend({
		uaString: '',
		minify: true,
		unknown: 'ignore',
		features: {},
		libVersion: 'latest'
	}, opts);
}

/**
 * Given a set of features that should be polyfilled in 'options.features' (with flags i.e. `{<featurename>: {flags:[<flaglist>]}, ...}`), determine which have a configuration valid for the given options.uaString, and return a set of canonical (unaliased) features (with flags) and polyfill variants.
 *
 * @return array, canonicalised features filtered for UA
 */
function getPolyfills(options) {
	var ua, features, sourceslib;

	options = getOptions(options);

	features = options.features;
	sourceslib = sources.getCollection(options.libVersion);
	ua = new UA(options.uaString);

	var aliasResolver = new AliasResolver([
		function aliasFromConfig(featureName) {
			return sourceslib.getConfigAliases(featureName);
		},
		function aliasAll(featureName) {
			if (featureName === 'all') {
				return sourceslib.listPolyfills();
			}
		}
	]);

	features = aliasResolver.resolve(features);

	function chooseVariant(featureName, feature) {
		if (!feature || feature.polyfillVariant !== undefined) return;
		var polyfill = sourceslib.getPolyfill(featureName);
		if (polyfill) {
			Object.keys(polyfill.variants).forEach(function(variantName) {
				var v = polyfill.variants[variantName];
				if (v.browsers && v.browsers[ua.getFamily()] && ua.satisfies(v.browsers[ua.getFamily()])) {
					feature.polyfillVariant = variantName;
					return false;
				}
			});
			if (!feature.polyfillVariant && feature.flags.indexOf('always') !== -1 && polyfill.variants['default']) {
				feature.polyfillVariant = 'default';
			}
			if (!feature.polyfillVariant && (options.unknown === 'polyfill' && ua.isUnknown())) {
				feature.polyfillVariant = 'default';
			}
			if (feature.polyfillVariant) {
				if (polyfill.variants[feature.polyfillVariant].dependencies) {
					polyfill.variants[feature.polyfillVariant].dependencies.forEach(function(dep) {
						if (!features[dep]) {
							features[dep] = {flags:feature.flags, aliasOf: [featureName]};
						} else if (!features[dep].aliasOf) {
							features[dep].aliasOf = [];
						}
						if (features[dep].aliasOf.indexOf(featureName) == -1) {
							features[dep].aliasOf.push(featureName);
						}
						chooseVariant(dep, features[dep]);
					});
				}
				return;
			}
		}
		delete features[featureName];
	}

	// chooseVariant modifies the features object, so use forEach rather than map and disregard return value
	Object.keys(features).forEach(function(featureName) {
		chooseVariant(featureName, features[featureName]);
	});
	return features;
}

function getPolyfillString(options) {
	var ua, uaDebugName;
	var currentPolyfills = {};
	var features = [];
	var explainerComment = [];
	var sourceslib;

	options = getOptions(options);
	console.log(options);
	ua = new UA(options.uaString);
	uaDebugName = (ua.isUnknown() ? 'Unknown (using policy: '+options.unknown+')' : ua.getFamily() + '/' + ua.getVersion());

	try {
		sourceslib = sources.getCollection(options.libVersion);
	} catch(e) {
		if (e.message == 'No matching version found') {
			sourceslib = null;
		} else {
			throw e;
		}
	}

	if (!ua.meetsBaseline() && !(ua.isUnknown() && options.unknown === 'polyfill')) {
		explainerComment = ['Unsupported UA detected: ' + uaDebugName];
		if (ua.getBaseline()) {
			explainerComment.push('Version range for polyfill support in this family is: ' + ua.getBaseline());
		}

	} else if (!sourceslib) {
		explainerComment = [
			'Cannot find a polyfill collection to satisfy version: '+options.libVersion+'.',
			'Available versions: '+sources.listVersions()
		];

	} else {
		if (options.minify) {
			explainerComment = ['Rerun without minification for verbose metadata'];
		} else  {
			explainerComment = [
				'For detailed credits and licence information see http://github.com/financial-times/polyfill-service.',
				'',
				'UA detected: ' + uaDebugName,
				'Features requested: ' + Object.keys(options.features),
				'Library version: ' + sourceslib.getVersion(),
				''
			]
		}
		features = getPolyfills(options);
	}

	var warnings = {unknown:[], nopolyfill:[]};
	var graph = tsort();

	Object.keys(features).forEach(function(featureName) {
		var feature = features[featureName];

		if (!sourceslib.getPolyfill(featureName)) {
			warnings.unknown.push(' - '+featureName);
		} else if (!feature.polyfillVariant) {
			warnings.nopolyfill.push(' - '+featureName);
		} else {

			graph.add(featureName);
			var polyfill = sourceslib.getPolyfill(featureName).variants[feature.polyfillVariant];
			var srcKey = (options.minify ? 'min':'raw') + 'Source';

			feature.polyfillOutput = polyfill[srcKey];

			if (feature.flags.indexOf('gated') !== -1 && polyfill.detectSource) {
				feature.polyfillOutput = "if (!(" + polyfill.detectSource + ")) {" + feature.polyfillOutput + "}\n\n";
			}

			if (polyfill.dependencies) {
				for (var i = 0; i < polyfill.dependencies.length; i++) {
					if (features[polyfill.dependencies[i]]) {
						graph.add(polyfill.dependencies[i], featureName);
					}
				}
			}
			feature.comment = '- ' + featureName + (feature.polyfillVariant !== 'default' ? '-'+feature.polyfillVariant:'') + ', License: ' + (polyfill.license || 'CC0')  + ' ' + ((feature.aliasOf && feature.aliasOf.length) ? ' (required by "' + feature.aliasOf.join('", "') + '")' : '');
		}
	});

	// Using the graph order, build the completed polyfill bundle
	var builtPolyfillString = '';
	graph.sort().forEach(function(featureName) {
		builtPolyfillString += features[featureName].polyfillOutput || '';
		if (!options.minify && features[featureName].comment) explainerComment.push(features[featureName].comment);
	});

	if (warnings.unknown.length && !options.minify) {
		explainerComment = explainerComment.concat(
			'',
			'These features were not recognised:',
			warnings.unknown
		);
	}

	if (warnings.nopolyfill.length && !options.minify) {
		explainerComment = explainerComment.concat(
			'',
			'These features have no polyfill suitable for '+ua.getFamily() + '/' + ua.getVersion() + ':',
			warnings.nopolyfill
		);
	}

	return '/* ' + explainerComment.join('\n * ') + ' */\n\n' + builtPolyfillString;
}

module.exports = {
	getPolyfills: getPolyfills,
	getAllPolyfills: getAllPolyfills,
	getPolyfillString: getPolyfillString,
	normalizeUserAgent: UA.normalize
};
<commit_msg>Remove stray debug<commit_after>var tsort         = require('tsort'),
	_             = require('lodash'),
	AliasResolver = require('./aliases'),
	UA            = require('./UA'),
	sources       = require('./sources');

// Polyfill String.prototype.startsWith
if (!String.prototype.startsWith) {
	require('../polyfills/String.prototype.startsWith/polyfill');
}

require('es6-promise').polyfill();

// Load additional useragent features: primarily to use: agent.satisfies to
// test a browser version against a semver string
require('useragent/features');

"use strict";

function getAllPolyfills() {
	return sources.latest.listPolyfills();
}

function getOptions(opts) {
	return _.extend({
		uaString: '',
		minify: true,
		unknown: 'ignore',
		features: {},
		libVersion: 'latest'
	}, opts);
}

/**
 * Given a set of features that should be polyfilled in 'options.features' (with flags i.e. `{<featurename>: {flags:[<flaglist>]}, ...}`), determine which have a configuration valid for the given options.uaString, and return a set of canonical (unaliased) features (with flags) and polyfill variants.
 *
 * @return array, canonicalised features filtered for UA
 */
function getPolyfills(options) {
	var ua, features, sourceslib;

	options = getOptions(options);

	features = options.features;
	sourceslib = sources.getCollection(options.libVersion);
	ua = new UA(options.uaString);

	var aliasResolver = new AliasResolver([
		function aliasFromConfig(featureName) {
			return sourceslib.getConfigAliases(featureName);
		},
		function aliasAll(featureName) {
			if (featureName === 'all') {
				return sourceslib.listPolyfills();
			}
		}
	]);

	features = aliasResolver.resolve(features);

	function chooseVariant(featureName, feature) {
		if (!feature || feature.polyfillVariant !== undefined) return;
		var polyfill = sourceslib.getPolyfill(featureName);
		if (polyfill) {
			Object.keys(polyfill.variants).forEach(function(variantName) {
				var v = polyfill.variants[variantName];
				if (v.browsers && v.browsers[ua.getFamily()] && ua.satisfies(v.browsers[ua.getFamily()])) {
					feature.polyfillVariant = variantName;
					return false;
				}
			});
			if (!feature.polyfillVariant && feature.flags.indexOf('always') !== -1 && polyfill.variants['default']) {
				feature.polyfillVariant = 'default';
			}
			if (!feature.polyfillVariant && (options.unknown === 'polyfill' && ua.isUnknown())) {
				feature.polyfillVariant = 'default';
			}
			if (feature.polyfillVariant) {
				if (polyfill.variants[feature.polyfillVariant].dependencies) {
					polyfill.variants[feature.polyfillVariant].dependencies.forEach(function(dep) {
						if (!features[dep]) {
							features[dep] = {flags:feature.flags, aliasOf: [featureName]};
						} else if (!features[dep].aliasOf) {
							features[dep].aliasOf = [];
						}
						if (features[dep].aliasOf.indexOf(featureName) == -1) {
							features[dep].aliasOf.push(featureName);
						}
						chooseVariant(dep, features[dep]);
					});
				}
				return;
			}
		}
		delete features[featureName];
	}

	// chooseVariant modifies the features object, so use forEach rather than map and disregard return value
	Object.keys(features).forEach(function(featureName) {
		chooseVariant(featureName, features[featureName]);
	});
	return features;
}

function getPolyfillString(options) {
	var ua, uaDebugName;
	var currentPolyfills = {};
	var features = [];
	var explainerComment = [];
	var sourceslib;

	options = getOptions(options);
	ua = new UA(options.uaString);
	uaDebugName = (ua.isUnknown() ? 'Unknown (using policy: '+options.unknown+')' : ua.getFamily() + '/' + ua.getVersion());

	try {
		sourceslib = sources.getCollection(options.libVersion);
	} catch(e) {
		if (e.message == 'No matching version found') {
			sourceslib = null;
		} else {
			throw e;
		}
	}

	if (!ua.meetsBaseline() && !(ua.isUnknown() && options.unknown === 'polyfill')) {
		explainerComment = ['Unsupported UA detected: ' + uaDebugName];
		if (ua.getBaseline()) {
			explainerComment.push('Version range for polyfill support in this family is: ' + ua.getBaseline());
		}

	} else if (!sourceslib) {
		explainerComment = [
			'Cannot find a polyfill collection to satisfy version: '+options.libVersion+'.',
			'Available versions: '+sources.listVersions()
		];

	} else {
		if (options.minify) {
			explainerComment = ['Rerun without minification for verbose metadata'];
		} else  {
			explainerComment = [
				'For detailed credits and licence information see http://github.com/financial-times/polyfill-service.',
				'',
				'UA detected: ' + uaDebugName,
				'Features requested: ' + Object.keys(options.features),
				'Library version: ' + sourceslib.getVersion(),
				''
			]
		}
		features = getPolyfills(options);
	}

	var warnings = {unknown:[], nopolyfill:[]};
	var graph = tsort();

	Object.keys(features).forEach(function(featureName) {
		var feature = features[featureName];

		if (!sourceslib.getPolyfill(featureName)) {
			warnings.unknown.push(' - '+featureName);
		} else if (!feature.polyfillVariant) {
			warnings.nopolyfill.push(' - '+featureName);
		} else {

			graph.add(featureName);
			var polyfill = sourceslib.getPolyfill(featureName).variants[feature.polyfillVariant];
			var srcKey = (options.minify ? 'min':'raw') + 'Source';

			feature.polyfillOutput = polyfill[srcKey];

			if (feature.flags.indexOf('gated') !== -1 && polyfill.detectSource) {
				feature.polyfillOutput = "if (!(" + polyfill.detectSource + ")) {" + feature.polyfillOutput + "}\n\n";
			}

			if (polyfill.dependencies) {
				for (var i = 0; i < polyfill.dependencies.length; i++) {
					if (features[polyfill.dependencies[i]]) {
						graph.add(polyfill.dependencies[i], featureName);
					}
				}
			}
			feature.comment = '- ' + featureName + (feature.polyfillVariant !== 'default' ? '-'+feature.polyfillVariant:'') + ', License: ' + (polyfill.license || 'CC0')  + ' ' + ((feature.aliasOf && feature.aliasOf.length) ? ' (required by "' + feature.aliasOf.join('", "') + '")' : '');
		}
	});

	// Using the graph order, build the completed polyfill bundle
	var builtPolyfillString = '';
	graph.sort().forEach(function(featureName) {
		builtPolyfillString += features[featureName].polyfillOutput || '';
		if (!options.minify && features[featureName].comment) explainerComment.push(features[featureName].comment);
	});

	if (warnings.unknown.length && !options.minify) {
		explainerComment = explainerComment.concat(
			'',
			'These features were not recognised:',
			warnings.unknown
		);
	}

	if (warnings.nopolyfill.length && !options.minify) {
		explainerComment = explainerComment.concat(
			'',
			'These features have no polyfill suitable for '+ua.getFamily() + '/' + ua.getVersion() + ':',
			warnings.nopolyfill
		);
	}

	return '/* ' + explainerComment.join('\n * ') + ' */\n\n' + builtPolyfillString;
}

module.exports = {
	getPolyfills: getPolyfills,
	getAllPolyfills: getAllPolyfills,
	getPolyfillString: getPolyfillString,
	normalizeUserAgent: UA.normalize
};
<|endoftext|>


<commit_before>/*
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/

'use strict';

// Include Gulp & Tools We'll Use
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var del = require('del');
var runSequence = require('run-sequence');
var browserSync = require('browser-sync');
var reload = browserSync.reload;
var merge = require('merge-stream');
var path = require('path');
var fs = require('fs');
var shell = require('gulp-shell'); // https://www.npmjs.com/package/gulp-shell
var glob = require('glob');
var historyApiFallback = require('connect-history-api-fallback');

var AUTOPREFIXER_BROWSERS = [
  'ie >= 10',
  'ie_mob >= 10',
  'ff >= 30',
  'chrome >= 34',
  'safari >= 7',
  'opera >= 23',
  'ios >= 7',
  'android >= 4.4',
  'bb >= 10'
];

var styleTask = function (stylesPath, srcs) {
  return gulp.src(srcs.map(function(src) {
      return path.join('app', stylesPath, src);
    }))
    .pipe($.changed(stylesPath, {extension: '.css'}))
    .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
    .pipe(gulp.dest('.tmp/' + stylesPath))
    .pipe($.if('*.css', $.cssmin()))
    .pipe(gulp.dest('dist/' + stylesPath))
    .pipe($.size({title: stylesPath}));
};

// Compile and Automatically Prefix Stylesheets
gulp.task('styles', function () {
  return styleTask('styles', ['**/*.css']);
});

gulp.task('elements', function () {
  return styleTask('elements', ['**/*.css']);
});

// Lint JavaScript
gulp.task('jshint', function () {
  return gulp.src([
      'app/scripts/**/*.js',
      'app/elements/**/*.js',
      'app/elements/**/*.html'
    ])
    .pipe(reload({stream: true, once: true}))
    .pipe($.jshint.extract()) // Extract JS from .html files
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'))
    .pipe($.if(!browserSync.active, $.jshint.reporter('fail')));
});

// Optimize Images
gulp.task('images', function () {
  return gulp.src('app/images/**/*')
    .pipe($.cache($.imagemin({
      progressive: true,
      interlaced: true
    })))
    .pipe(gulp.dest('dist/images'))
    .pipe($.size({title: 'images'}));
});

// Copy All Files At The Root Level (app)
gulp.task('copy', function () {
  var app = gulp.src([
    'app/*',
    '!app/test',
    '!app/precache.json'
  ], {
    dot: true
  }).pipe(gulp.dest('dist'));

  var bower = gulp.src([
    'bower_components/**/*'
  ]).pipe(gulp.dest('dist/bower_components'));

  var elements = gulp.src(['app/elements/**/*.html'])
    .pipe(gulp.dest('dist/elements'));

  var swBootstrap = gulp.src(['bower_components/platinum-sw/bootstrap/*.js'])
    .pipe(gulp.dest('dist/elements/bootstrap'));

  var swToolbox = gulp.src(['bower_components/sw-toolbox/*.js'])
    .pipe(gulp.dest('dist/sw-toolbox'));

  var vulcanized = gulp.src(['app/elements/elements.html'])
    .pipe($.rename('elements.vulcanized.html'))
    .pipe(gulp.dest('dist/elements'));

  return merge(app, bower, elements, vulcanized, swBootstrap, swToolbox)
    .pipe($.size({title: 'copy'}));
});

// Copy Web Fonts To Dist
gulp.task('fonts', function () {
  return gulp.src(['app/fonts/**'])
    .pipe(gulp.dest('dist/fonts'))
    .pipe($.size({title: 'fonts'}));
});

// Scan Your HTML For Assets & Optimize Them
gulp.task('html', function () {
  var assets = $.useref.assets({searchPath: ['.tmp', 'app', 'dist']});

  return gulp.src(['app/**/*.html', '!app/{elements,test}/**/*.html'])
    // Replace path for vulcanized assets
    .pipe($.if('*.html', $.replace('elements/elements.html', 'elements/elements.vulcanized.html')))
    .pipe(assets)
    // Concatenate And Minify JavaScript
    .pipe($.if('*.js', $.uglify({preserveComments: 'some'})))
    // Concatenate And Minify Styles
    // In case you are still using useref build blocks
    .pipe($.if('*.css', $.cssmin()))
    .pipe(assets.restore())
    .pipe($.useref())
    // Minify Any HTML
    .pipe($.if('*.html', $.minifyHtml({
      quotes: true,
      empty: true,
      spare: true
    })))
    // Output Files
    .pipe(gulp.dest('dist'))
    .pipe($.size({title: 'html'}));
});

// Vulcanize imports
gulp.task('vulcanize', function () {
  var DEST_DIR = 'dist/elements';

  return gulp.src('dist/elements/elements.vulcanized.html')
    .pipe($.vulcanize({
      stripComments: true,
      inlineCss: true,
      inlineScripts: true
    }))
    .pipe(gulp.dest(DEST_DIR))
    .pipe($.size({title: 'vulcanize'}));
});

// Generate a list of files that should be precached when serving from 'dist'.
// The list will be consumed by the <platinum-sw-cache> element.
gulp.task('precache', function (callback) {
  var dir = 'dist';

  glob('{elements,scripts,styles}/**/*.*', {cwd: dir}, function(error, files) {
    if (error) {
      callback(error);
    } else {
      files.push('index.html', './', 'bower_components/webcomponentsjs/webcomponents-lite.min.js');
      var filePath = path.join(dir, 'precache.json');
      fs.writeFile(filePath, JSON.stringify(files), callback);
    }
  });
});

// Clean Output Directory
gulp.task('clean', del.bind(null, ['.tmp', 'dist']));

// Watch Files For Changes & Reload
gulp.task('serve', ['styles', 'elements', 'images'], function () {
  browserSync({
    notify: false,
    logPrefix: 'PSK',
    snippetOptions: {
      rule: {
        match: '',
        fn: function (snippet) {
          return snippet;
        }
      }
    },
    // shell as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: {
      baseDir: ['.tmp', 'app'],
      middleware: [ historyApiFallback() ],
      routes: {
        '/bower_components': 'bower_components'
      }
    }
  });

  gulp.watch(['app/**/*.html'], reload);
  gulp.watch(['app/styles/**/*.css'], ['styles', reload]);
  gulp.watch(['app/elements/**/*.css'], ['elements', reload]);
  gulp.watch(['app/{scripts,elements}/**/*.js'], ['jshint']);
  gulp.watch(['app/images/**/*'], reload);
});

// Build and serve the output from the dist build
gulp.task('serve:dist', ['default'], function () {
  browserSync({
    notify: false,
    logPrefix: 'PSK',
    snippetOptions: {
      rule: {
        match: '',
        fn: function (snippet) {
          return snippet;
        }
      }
    },
    // run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: 'dist',
    middleware: [ historyApiFallback() ]
  });
});

// Build Production Files, the Default Task
gulp.task('default', ['clean'], function (cb) {
  runSequence(
    ['copy', 'styles'],
    'elements',
    ['jshint', 'images', 'fonts', 'html'],
    'vulcanize',
    cb);
    // Note: add , 'precache' , after 'vulcanize', if your are going to use Service Worker
});

// Netoyage de Cordova
gulp.task('cordova_clean', shell.task('rm -Rf cordova'));

// Création de Cordova
gulp.task('cordova_create', shell.task('cordova create cordova com.winegame.cordova "Winegame" --copy-from=dist'));

// Ajout de la plate-forme IOS pour Cordova
gulp.task('cordova_platform_ios', shell.task('cordova platform add ios', {cwd: 'cordova'}));

// Ajout de la plate-forme android pour Cordova
gulp.task('cordova_platform_android', shell.task('cordova platform add android', {cwd: 'cordova'}));

// Prepare Cordova
gulp.task('cordova_prepare', shell.task('cordova prepare', {cwd: 'cordova'}));

// Génère la partie Cordova
gulp.task('cordova', ['default'], function (cb) {
  runSequence(
    'cordova_clean',
    'cordova_create',
    'cordova_platform_android',
    'cordova_platform_ios',
    'cordova_prepare',
    cb);
});

// Émule l'application pour android
gulp.task('cordova:emulate:android', shell.task('cordova emulate android', {cwd: 'cordova'}));

// Émule l'application pour ios
gulp.task('cordova:emulate:ios', shell.task('cordova emulate android', {cwd: 'cordova'}));

// Load tasks for web-component-tester
// Adds tasks for `gulp test:local` and `gulp test:remote`
require('web-component-tester').gulp.init(gulp);

// Load custom tasks from the `tasks` directory
try { require('require-dir')('tasks'); } catch (err) {}
<commit_msg>Ajout des commandes pour générer et emuler avec cordova<commit_after>/*
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/

'use strict';

// Include Gulp & Tools We'll Use
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var del = require('del');
var runSequence = require('run-sequence');
var browserSync = require('browser-sync');
var reload = browserSync.reload;
var merge = require('merge-stream');
var path = require('path');
var fs = require('fs');
var shell = require('gulp-shell'); // https://www.npmjs.com/package/gulp-shell
var glob = require('glob');
var historyApiFallback = require('connect-history-api-fallback');

var AUTOPREFIXER_BROWSERS = [
  'ie >= 10',
  'ie_mob >= 10',
  'ff >= 30',
  'chrome >= 34',
  'safari >= 7',
  'opera >= 23',
  'ios >= 7',
  'android >= 4.4',
  'bb >= 10'
];

var styleTask = function (stylesPath, srcs) {
  return gulp.src(srcs.map(function(src) {
      return path.join('app', stylesPath, src);
    }))
    .pipe($.changed(stylesPath, {extension: '.css'}))
    .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
    .pipe(gulp.dest('.tmp/' + stylesPath))
    .pipe($.if('*.css', $.cssmin()))
    .pipe(gulp.dest('dist/' + stylesPath))
    .pipe($.size({title: stylesPath}));
};

// Compile and Automatically Prefix Stylesheets
gulp.task('styles', function () {
  return styleTask('styles', ['**/*.css']);
});

gulp.task('elements', function () {
  return styleTask('elements', ['**/*.css']);
});

// Lint JavaScript
gulp.task('jshint', function () {
  return gulp.src([
      'app/scripts/**/*.js',
      'app/elements/**/*.js',
      'app/elements/**/*.html'
    ])
    .pipe(reload({stream: true, once: true}))
    .pipe($.jshint.extract()) // Extract JS from .html files
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'))
    .pipe($.if(!browserSync.active, $.jshint.reporter('fail')));
});

// Optimize Images
gulp.task('images', function () {
  return gulp.src('app/images/**/*')
    .pipe($.cache($.imagemin({
      progressive: true,
      interlaced: true
    })))
    .pipe(gulp.dest('dist/images'))
    .pipe($.size({title: 'images'}));
});

// Copy All Files At The Root Level (app)
gulp.task('copy', function () {
  var app = gulp.src([
    'app/*',
    '!app/test',
    '!app/precache.json'
  ], {
    dot: true
  }).pipe(gulp.dest('dist'));

  var bower = gulp.src([
    'bower_components/**/*.js',
    'bower_components/**/*.css',
    'bower_components/**/*.html',
    '!bower_components/**/test/*',
    '!bower_components/**/demo/*'
  ]).pipe(gulp.dest('dist/bower_components'));

  var elements = gulp.src(['app/elements/**/*.html'])
    .pipe(gulp.dest('dist/elements'));

  var swBootstrap = gulp.src(['bower_components/platinum-sw/bootstrap/*.js'])
    .pipe(gulp.dest('dist/elements/bootstrap'));

  var swToolbox = gulp.src(['bower_components/sw-toolbox/*.js'])
    .pipe(gulp.dest('dist/sw-toolbox'));

  var vulcanized = gulp.src(['app/elements/elements.html'])
    .pipe($.rename('elements.vulcanized.html'))
    .pipe(gulp.dest('dist/elements'));

  return merge(app, bower, elements, vulcanized, swBootstrap, swToolbox)
    .pipe($.size({title: 'copy'}));
});

// Copy Web Fonts To Dist
gulp.task('fonts', function () {
  return gulp.src(['app/fonts/**'])
    .pipe(gulp.dest('dist/fonts'))
    .pipe($.size({title: 'fonts'}));
});

// Scan Your HTML For Assets & Optimize Them
gulp.task('html', function () {
  var assets = $.useref.assets({searchPath: ['.tmp', 'app', 'dist']});

  return gulp.src(['app/**/*.html', '!app/{elements,test}/**/*.html'])
    // Replace path for vulcanized assets
    .pipe($.if('*.html', $.replace('elements/elements.html', 'elements/elements.vulcanized.html')))
    .pipe(assets)
    // Concatenate And Minify JavaScript
    .pipe($.if('*.js', $.uglify({preserveComments: 'some'})))
    // Concatenate And Minify Styles
    // In case you are still using useref build blocks
    .pipe($.if('*.css', $.cssmin()))
    .pipe(assets.restore())
    .pipe($.useref())
    // Minify Any HTML
    .pipe($.if('*.html', $.minifyHtml({
      quotes: true,
      empty: true,
      spare: true
    })))
    // Output Files
    .pipe(gulp.dest('dist'))
    .pipe($.size({title: 'html'}));
});

// Vulcanize imports
gulp.task('vulcanize', function () {
  var DEST_DIR = 'dist/elements';

  return gulp.src('dist/elements/elements.vulcanized.html')
    .pipe($.vulcanize({
      stripComments: true,
      inlineCss: true,
      inlineScripts: true
    }))
    .pipe(gulp.dest(DEST_DIR))
    .pipe($.size({title: 'vulcanize'}));
});

// Generate a list of files that should be precached when serving from 'dist'.
// The list will be consumed by the <platinum-sw-cache> element.
gulp.task('precache', function (callback) {
  var dir = 'dist';

  glob('{elements,scripts,styles}/**/*.*', {cwd: dir}, function(error, files) {
    if (error) {
      callback(error);
    } else {
      files.push('index.html', './', 'bower_components/webcomponentsjs/webcomponents-lite.min.js');
      var filePath = path.join(dir, 'precache.json');
      fs.writeFile(filePath, JSON.stringify(files), callback);
    }
  });
});

// Clean Output Directory
gulp.task('clean', del.bind(null, ['.tmp', 'dist']));

// Watch Files For Changes & Reload
gulp.task('serve', ['styles', 'elements', 'images'], function () {
  browserSync({
    notify: false,
    logPrefix: 'PSK',
    snippetOptions: {
      rule: {
        match: '',
        fn: function (snippet) {
          return snippet;
        }
      }
    },
    // shell as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: {
      baseDir: ['.tmp', 'app'],
      middleware: [ historyApiFallback() ],
      routes: {
        '/bower_components': 'bower_components'
      }
    }
  });

  gulp.watch(['app/**/*.html'], reload);
  gulp.watch(['app/styles/**/*.css'], ['styles', reload]);
  gulp.watch(['app/elements/**/*.css'], ['elements', reload]);
  gulp.watch(['app/{scripts,elements}/**/*.js'], ['jshint']);
  gulp.watch(['app/images/**/*'], reload);
});

// Build and serve the output from the dist build
gulp.task('serve:dist', ['default'], function () {
  browserSync({
    notify: false,
    logPrefix: 'PSK',
    snippetOptions: {
      rule: {
        match: '',
        fn: function (snippet) {
          return snippet;
        }
      }
    },
    // run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: 'dist',
    middleware: [ historyApiFallback() ]
  });
});

// Build Production Files, the Default Task
gulp.task('default', ['clean'], function (cb) {
  runSequence(
    ['copy', 'styles'],
    'elements',
    ['jshint', 'images', 'fonts', 'html'],
    'vulcanize',
    cb);
    // Note: add , 'precache' , after 'vulcanize', if your are going to use Service Worker
});

// Netoyage de Cordova
gulp.task('cordova_clean', shell.task('rm -Rf cordova'));

// Création de Cordova
gulp.task('cordova_create', shell.task('cordova create cordova com.winegame.cordova "Winegame" --copy-from=dist'));

// Ajout de la plate-forme IOS pour Cordova
gulp.task('cordova_platform_ios', shell.task('cordova platform add ios', {cwd: 'cordova'}));

// Ajout de la plate-forme android pour Cordova
gulp.task('cordova_platform_android', shell.task('cordova platform add android', {cwd: 'cordova'}));

// Prepare Cordova
gulp.task('cordova_prepare', shell.task('cordova prepare', {cwd: 'cordova'}));

// Génère la partie Cordova
gulp.task('cordova', ['default'], function (cb) {
  runSequence(
    'cordova_clean',
    'cordova_create',
    'cordova_platform_android',
    'cordova_platform_ios',
    'cordova_prepare',
    cb);
});

// Nettoie le repertoire www de cordova
gulp.task('cordova:build:clean_www', shell.task('rm -Rf cordova/www/*'));

// Copie le dossier dist dans le www de cordova
gulp.task('cordova:build:refresh', ['cordova:build:clean_www'], function(){
  var app = gulp.src([
    'dist/**'
  ]).pipe(gulp.dest('cordova/www'));
});

// Génere le build cordova pour android
gulp.task('cordova:build:android', ['cordova:build:refresh'], shell.task('cordova build android', {cwd: 'cordova'}));

// Génere le build cordova pour ios
gulp.task('cordova:build:ios', ['cordova:build:refresh'], shell.task('cordova build ios', {cwd: 'cordova'}));

// Émule l'application pour android
gulp.task('cordova:emulate:android', ['cordova:build:android'], shell.task('cordova emulate android', {cwd: 'cordova'}));

// Émule l'application pour ios
gulp.task('cordova:emulate:ios', ['cordova:build:ios'], shell.task('cordova emulate android', {cwd: 'cordova'}));

// Load tasks for web-component-tester
// Adds tasks for `gulp test:local` and `gulp test:remote`
require('web-component-tester').gulp.init(gulp);

// Load custom tasks from the `tasks` directory
try { require('require-dir')('tasks'); } catch (err) {}
<|endoftext|>


<commit_before>/**
 * intrabuild
 * (c) 2002-2008 siteartwork.de/MindPatterns
 * license@siteartwork.de
 *
 * $Author$
 * $Id$
 * $Date$
 * $Revision$
 * $LastChangedDate$
 * $LastChangedBy$
 * $URL$
 */

Ext.namespace('de.intrabuild.groupware.feeds');

de.intrabuild.groupware.feeds.FeedGrid = function(config) {

	Ext.ux.util.MessageBus.subscribe(
	   'de.intrabuild.groupware.feeds.FeedViewbaton.onFeedLoadSuccess',
	   this.onFeedItemLoaded,
	   this
	);

    Ext.ux.util.MessageBus.subscribe(
       'de.intrabuild.groupware.feeds.FeedPreview.onLoadSuccess',
       this.onFeedItemLoaded,
       this
    );

    Ext.apply(this, config);

    this.store = de.intrabuild.util.Registry.get('de.intrabuild.groupware.feeds.FeedStore');

    this.store.setDefaultSort('pubDate', "DESC");

    this.columns = [{
        id:'name',
        header: "Feed",
        hidden:true,
        width: 120,
        sortable: true,
        dataIndex: 'name'
      },{
        id:'title',
        header: "Titel",
        width: 220,
        sortable: true,
        dataIndex: 'title'
      },{
        header: "Beschreibung",
        hidden:true,
        width: 180,
        sortable: true,
        dataIndex: 'description'
      },{
        header: "Datum",
        width: 120,
        hidden:true,
        sortable: true,
        renderer: Ext.util.Format.dateRenderer('d.m.Y H:i'),
        dataIndex: 'pubDate'
      }
    ];

    this.view = new Ext.grid.GroupingView({
        forceFit:false,
        showGroupName : false,
        groupTextTpl: '{text} ({[values.rs.length]}/{[function(){var b = 0;for (var i = 0, rs = values.rs, max_i = rs.length; i < max_i; i++) {if (!rs[i].data.isRead) {b++;}}return b;}()]})',// ((rs.length]})',
        getRowClass : this.applyRowClass
    });

    var displayOptionsMenu = new Ext.menu.Menu({
        items: [{
            id : 'groupFeeds',
            text: 'nach Feeds gruppieren',
            checked: true,
            //group: 'de.intrabuild.groupware.FeedGrid.display',
            checkHandler: this.toggleGroupView,
            scope: this
          },
          "-",{
            iconCls : 'de-intrabuild-groupware-feeds-FeedGrid-optionsMenu-configureItem-icon',
            text    : "Einstellungen...",
            scope   : this,
            handler : function() {
                var optDialog = new de.intrabuild.groupware.feeds.FeedOptionsDialog();
                optDialog.show();
            }

          }]
    });

    this.tbar = new Ext.Toolbar([{
        cls     : 'x-btn-icon',
        iconCls : 'de-intrabuild-groupware-feeds-FeedGrid-toolbar-addFeedButton-icon',
        handler : function(){
			var dialog = new de.intrabuild.groupware.feeds.AddFeedDialog({
                animateTarget : this.getTopToolbar().items.get(0).el.dom.id
            });
            dialog.show();
        },
        scope : this
      },{
        cls     : 'x-btn-icon',
        iconCls : 'de-intrabuild-groupware-feeds-FeedGrid-toolbar-refreshFeedsButton-icon',
        handler : function(){
            this.clkRow    = null;
            this.clkRecord = null;
            de.intrabuild.util.Registry.get('de.intrabuild.groupware.feeds.AccountStore').reload();
            this.store.reload();},
        scope: this
      },{
        id      : 'displayOptions',
        cls     : 'x-btn-icon',
        iconCls : 'de-intrabuild-groupware-feeds-FeedGrid-toolbar-displayOptionsButton-icon',
        menu    : displayOptionsMenu
      }
    ]);

    de.intrabuild.groupware.feeds.FeedGrid.superclass.constructor.call(this, {

        loadMask : {msg:'Lade Feeds...'},

        autoScroll:true,
        style:'cursor:default',
        title: 'Feeds',
        iconCls: 'de-intrabuild-groupware-feeds-Icon',
        border:false,
        hideBorders:true
    });

    // install listeners
    this.on('cellclick',    this.onCellClick, this, {buffer : 200});
    this.on('celldblclick', this.onCellDblClick, this);

    var preview = de.intrabuild.groupware.feeds.FeedPreview;

    this.on('resize',         preview.hide.createDelegate(preview, [true]));
    this.on('beforecollapse', preview.hide.createDelegate(preview, [true, false]));
    this.on('contextmenu',    preview.hide.createDelegate(preview, [false]));

    this.on('contextmenu', this.onContextClick, this);
    this.on('rowcontextmenu', this.onRowContextClick, this);
    displayOptionsMenu.on('beforeshow', this.onBeforeShow, this);

    /**
     * @ext-bug
     * setChecked neeeds to supress the event and compare the groupfield
     * width the field the clicked column represents. This seems buggy in Ext2.0 Alpha
     */
    this.view.beforeMenuShow = function(){
        var field = this.getGroupField();
        this.hmenu.items.get('groupBy').setDisabled(this.cm.config[this.hdCtxIndex].groupable === false);
        this.hmenu.items.get('showGroups').setChecked(field == this.cm.getDataIndex(this.hdCtxIndex), true);
    }
};

Ext.extend(de.intrabuild.groupware.feeds.FeedGrid, Ext.grid.GridPanel, {

    clkRow          : null,
    clkRecord       : null,
    cellClickActive : false,

    /**
     * Checks the group state and checks/unchecks the "show feeds grouped" items
     * as needed.
     */
    onBeforeShow : function()
    {
        if (this.view.getGroupField() != 'name') {
            this.getTopToolbar().items.get('displayOptions').menu.items.get('groupFeeds').setChecked(false, true);
        }
    },

    toggleGroupView : function(item, checked)
    {
        if (!checked) {
            this.store.clearGrouping();
        } else {
            this.store.groupBy('name', true);
        }
    },

    // within this function "this" is actually the GridView
    applyRowClass: function(record, rowIndex, p, ds)
    {
        if (record.data.isRead) {
            return 'de-intrabuild-groupware-feeds-FeedGrid-itemRead';
        } else {
            return 'de-intrabuild-groupware-feeds-FeedGrid-itemUnread';
        }
    },

    // private
    commitRecords : function()
    {
        var m = this.store.getModifiedRecords();

        var l = m.length;

        if (l == 0) {
            return;
        }

        var requestArray = new Array();

        for (var i = 0; i < l; i++) {
            requestArray.push({
                'id'     : m[i].id,
                'isRead' : m[i].get('isRead')
            });
        }

        Ext.Ajax.request({
            url: '/groupware/feeds/set.item.read/format/json',
            params: {
                json: Ext.encode(requestArray)
            }
        });

        this.store.commitChanges();
    },

	onFeedItemLoaded : function(subject, message)
	{
		if (message.id) {
			this.markItemsRead(true, message.id)
		}
	},

    markItemsRead : function(bRead, id)
    {
        var feedIds = new Array();

		if (!id) {
			var selection = this.selModel.getSelections();
			for (var i = 0; i < selection.length; i++) {
				selection[i].set('isRead', bRead);
			}
		} else {
			var rec = this.store.getById(id);
			if (rec) {
				rec.set('isRead', bRead);
			}
		}

        this.commitRecords();
    },

    onCellClick : function(grid, rowIndex, columnIndex, e)
    {
		if (this.cellClickActive) {
            this.cellClickActive = false;
            return;
        }

        if (e.shiftKey || e.ctrlKey) {
            return;
        }

        this.clkRow    = this.view.getRow(rowIndex);
        this.clkRecord = this.store.getAt(rowIndex);
		de.intrabuild.groupware.feeds.FeedPreview.show(grid, rowIndex, columnIndex, e);
    },

    onCellDblClick : function(grid, rowIndex, columnIndex, eventObject)
    {
		this.cellClickActive = true;
		var feedItem = grid.getStore().getAt(rowIndex);
		de.intrabuild.groupware.feeds.FeedPreview.hide(true, false);
        de.intrabuild.groupware.feeds.FeedViewBaton.showFeed(feedItem, true);
    },

    // private
    /**
     *
     * @access private
     */
    createContextMenu : function()
    {
        if(!this.menu){ // create context menu on first right click
            this.menu = new Ext.menu.Menu({
                items: [{
                    text: 'Aktualisieren',
                    scope:this,
                    handler: function(){
                        this.clkRow    = null;
                        this.clkRecord = null;
                        de.intrabuild.util.Registry.get('de.intrabuild.groupware.feeds.AccountStore').reload();
                        this.store.reload();}
                  },
                 '-',{
                    text: 'als gelesen markieren',
                    scope:this,
                    handler: function(){
                        this.markItemsRead(true);}
                  },{
                    text: 'als ungelesen markieren',
                    scope:this,
                    handler: function(){
                        this.markItemsRead(false);}
                  },
                  '-',{
                    text:'Einstellungen...',
                    scope:this,
                    handler: function(){
                        var dialog = new de.intrabuild.groupware.feeds.FeedOptionsDialog();
                        dialog.show();
                    }
                }]
            });
            this.menu.on('hide', this.onContextHide, this);
        }
    },

    onContextClick : function(e)
    {
        e.stopEvent();

        // row was clicked, we wont handle this
        if (e.getTarget().id == "") {
            return;
        }

        this.createContextMenu();

        this.selModel.clearSelections();

        this.clkRow    = null;
        this.clkRecord = null;

        this.menu.items.get(2).setDisabled(true);
        this.menu.items.get(3).setDisabled(true);

        this.menu.showAt(e.getXY());
    },

    onRowContextClick : function(grid, index, e)
    {
        var selModel = this.selModel;

        this.createContextMenu();

        e.stopEvent();
        if(this.ctxRow){
            //Ext.fly(this.ctxRow).removeClass('x-node-ctx');
            this.ctxRow = null;
        }

        this.ctxRow    = this.view.getRow(index);
        this.ctxRecord = this.store.getAt(index);

        if (!selModel.isSelected(index)) {
            selModel.selectRow(index, false);
        }

        if (selModel.getCount() == 1) {
            this.menu.items.get(2).setDisabled((this.ctxRecord.data.isRead == true));
            this.menu.items.get(3).setDisabled(!(this.ctxRecord.data.isRead == true));
        } else {
            this.menu.items.get(2).setDisabled(false);
            this.menu.items.get(3).setDisabled(false);
        }

        //Ext.fly(this.ctxRow).addClass('x-node-ctx');
        this.menu.showAt(e.getXY());
    },

    onContextHide : function()
    {
        if(this.ctxRow){
           // Ext.fly(this.ctxRow).removeClass('x-node-ctx');
            this.ctxRow = null;
        }
    }

});<commit_msg> - enhancement: grouping headers are now updated when items get marked as read or unread (closes CN-43)<commit_after>/**
 * intrabuild
 * (c) 2002-2008 siteartwork.de/MindPatterns
 * license@siteartwork.de
 *
 * $Author$
 * $Id$
 * $Date$
 * $Revision$
 * $LastChangedDate$
 * $LastChangedBy$
 * $URL$
 */

Ext.namespace('de.intrabuild.groupware.feeds');

de.intrabuild.groupware.feeds.FeedGrid = function(config) {

	Ext.ux.util.MessageBus.subscribe(
	   'de.intrabuild.groupware.feeds.FeedViewbaton.onFeedLoadSuccess',
	   this.onFeedItemLoaded,
	   this
	);

    Ext.ux.util.MessageBus.subscribe(
       'de.intrabuild.groupware.feeds.FeedPreview.onLoadSuccess',
       this.onFeedItemLoaded,
       this
    );

    Ext.apply(this, config);

    this.store = de.intrabuild.util.Registry.get('de.intrabuild.groupware.feeds.FeedStore');

    this.store.setDefaultSort('pubDate', "DESC");

    this.columns = [{
        id:'name',
        header: "Feed",
        hidden:true,
        width: 120,
        sortable: true,
        dataIndex: 'name'
      },{
        id:'title',
        header: "Titel",
        width: 220,
        sortable: true,
        dataIndex: 'title'
      },{
        header: "Beschreibung",
        hidden:true,
        width: 180,
        sortable: true,
        dataIndex: 'description'
      },{
        header: "Datum",
        width: 120,
        hidden:true,
        sortable: true,
        renderer: Ext.util.Format.dateRenderer('d.m.Y H:i'),
        dataIndex: 'pubDate'
      }
    ];

	var groupTextTpl  = '{text} ({[values.rs.length]}/{[function(){var b = 0;for (var i = 0, rs = values.rs, max_i = rs.length; i < max_i; i++) {if (!rs[i].data.isRead) {b++;}}return b;}()]})';
	this.groupTextTpl = new Ext.XTemplate(groupTextTpl);
	this.groupTextTpl.compile();

    this.view = new Ext.grid.GroupingView({
        forceFit      : false,
        showGroupName : false,
        groupTextTpl  : groupTextTpl,
        getRowClass   : this.applyRowClass
    });

    var displayOptionsMenu = new Ext.menu.Menu({
        items: [{
            id : 'groupFeeds',
            text: 'nach Feeds gruppieren',
            checked: true,
            //group: 'de.intrabuild.groupware.FeedGrid.display',
            checkHandler: this.toggleGroupView,
            scope: this
          },
          "-",{
            iconCls : 'de-intrabuild-groupware-feeds-FeedGrid-optionsMenu-configureItem-icon',
            text    : "Einstellungen...",
            scope   : this,
            handler : function() {
                var optDialog = new de.intrabuild.groupware.feeds.FeedOptionsDialog();
                optDialog.show();
            }

          }]
    });

    this.tbar = new Ext.Toolbar([{
        cls     : 'x-btn-icon',
        iconCls : 'de-intrabuild-groupware-feeds-FeedGrid-toolbar-addFeedButton-icon',
        handler : function(){
			var dialog = new de.intrabuild.groupware.feeds.AddFeedDialog({
                animateTarget : this.getTopToolbar().items.get(0).el.dom.id
            });
            dialog.show();
        },
        scope : this
      },{
        cls     : 'x-btn-icon',
        iconCls : 'de-intrabuild-groupware-feeds-FeedGrid-toolbar-refreshFeedsButton-icon',
        handler : function(){
            this.clkRow    = null;
            this.clkRecord = null;
            de.intrabuild.util.Registry.get('de.intrabuild.groupware.feeds.AccountStore').reload();
            this.store.reload();},
        scope: this
      },{
        id      : 'displayOptions',
        cls     : 'x-btn-icon',
        iconCls : 'de-intrabuild-groupware-feeds-FeedGrid-toolbar-displayOptionsButton-icon',
        menu    : displayOptionsMenu
      }
    ]);

    de.intrabuild.groupware.feeds.FeedGrid.superclass.constructor.call(this, {

        loadMask : {msg:'Lade Feeds...'},

        autoScroll:true,
        style:'cursor:default',
        title: 'Feeds',
        iconCls: 'de-intrabuild-groupware-feeds-Icon',
        border:false,
        hideBorders:true
    });

    // install listeners
    this.on('cellclick',    this.onCellClick, this, {buffer : 200});
    this.on('celldblclick', this.onCellDblClick, this);

    var preview = de.intrabuild.groupware.feeds.FeedPreview;

    this.on('resize',         preview.hide.createDelegate(preview, [true]));
    this.on('beforecollapse', preview.hide.createDelegate(preview, [true, false]));
    this.on('contextmenu',    preview.hide.createDelegate(preview, [false]));

    this.on('contextmenu', this.onContextClick, this);
    this.on('rowcontextmenu', this.onRowContextClick, this);
    displayOptionsMenu.on('beforeshow', this.onBeforeShow, this);

    /**
     * @ext-bug
     * setChecked neeeds to supress the event and compare the groupfield
     * width the field the clicked column represents. This seems buggy in Ext2.0 Alpha
     */
    this.view.beforeMenuShow = function(){
        var field = this.getGroupField();
        this.hmenu.items.get('groupBy').setDisabled(this.cm.config[this.hdCtxIndex].groupable === false);
        this.hmenu.items.get('showGroups').setChecked(field == this.cm.getDataIndex(this.hdCtxIndex), true);
    }
};

Ext.extend(de.intrabuild.groupware.feeds.FeedGrid, Ext.grid.GridPanel, {

    clkRow          : null,
    clkRecord       : null,
    cellClickActive : false,

    /**
     * Checks the group state and checks/unchecks the "show feeds grouped" items
     * as needed.
     */
    onBeforeShow : function()
    {
        if (this.view.getGroupField() != 'name') {
            this.getTopToolbar().items.get('displayOptions').menu.items.get('groupFeeds').setChecked(false, true);
        }
    },

    toggleGroupView : function(item, checked)
    {
        if (!checked) {
            this.store.clearGrouping();
        } else {
            this.store.groupBy('name', true);
        }
    },

    // within this function "this" is actually the GridView
    applyRowClass: function(record, rowIndex, p, ds)
    {
        if (record.data.isRead) {
            return 'de-intrabuild-groupware-feeds-FeedGrid-itemRead';
        } else {
            return 'de-intrabuild-groupware-feeds-FeedGrid-itemUnread';
        }
    },

    // private
    commitRecords : function()
    {
        var m = this.store.getModifiedRecords();

        var l = m.length;

        if (l == 0) {
            return;
        }

        var requestArray = new Array();

        for (var i = 0; i < l; i++) {
            requestArray.push({
                'id'     : m[i].id,
                'isRead' : m[i].get('isRead')
            });
        }

        Ext.Ajax.request({
            url: '/groupware/feeds/set.item.read/format/json',
            params: {
                json: Ext.encode(requestArray)
            }
        });

        this.store.commitChanges();
		this._updateGroupTemplates();
    },

	onFeedItemLoaded : function(subject, message)
	{
		if (message.id) {
			this.markItemsRead(true, message.id)
		}
	},

    _updateGroupTemplates : function()
	{
		var view = this.view;
        var rs   = this.store.getRange();
        var len  = rs.length;
		if (len < 1) {
			return [];
		}

        var groupField = view.getGroupField();

		var r;
        var gvalue;
		var indexes = {};
	    var groups = [];

        for (var i = 0; i < len; i++) {
            r      = rs[i];
			gvalue = r.data[groupField];

			if (!indexes[gvalue]) {
				indexes[gvalue] = [];
			}

			indexes[gvalue].push(r);
        }

		var a  = 0;
		var gr = view.getGroups();
		for (var i in indexes) {
			gr[a++].firstChild.firstChild.innerHTML = this.groupTextTpl.apply({
                text : i,
				rs : indexes[i]
			});
		}
    },

    markItemsRead : function(bRead, id)
    {
        var feedIds = new Array();

		if (!id) {
			var selection = this.selModel.getSelections();
			for (var i = 0; i < selection.length; i++) {
				selection[i].set('isRead', bRead);
			}
		} else {
			var rec = this.store.getById(id);
			if (rec) {
				rec.set('isRead', bRead);
			}
		}

        this.commitRecords();
    },

    onCellClick : function(grid, rowIndex, columnIndex, e)
    {
		if (this.cellClickActive) {
            this.cellClickActive = false;
            return;
        }

        if (e.shiftKey || e.ctrlKey) {
            return;
        }

        this.clkRow    = this.view.getRow(rowIndex);
        this.clkRecord = this.store.getAt(rowIndex);
		de.intrabuild.groupware.feeds.FeedPreview.show(grid, rowIndex, columnIndex, e);
    },

    onCellDblClick : function(grid, rowIndex, columnIndex, eventObject)
    {
		this.cellClickActive = true;
		var feedItem = grid.getStore().getAt(rowIndex);
		de.intrabuild.groupware.feeds.FeedPreview.hide(true, false);
        de.intrabuild.groupware.feeds.FeedViewBaton.showFeed(feedItem, true);
    },

    // private
    /**
     *
     * @access private
     */
    createContextMenu : function()
    {
        if(!this.menu){ // create context menu on first right click
            this.menu = new Ext.menu.Menu({
                items: [{
                    text: 'Aktualisieren',
                    scope:this,
                    handler: function(){
                        this.clkRow    = null;
                        this.clkRecord = null;
                        de.intrabuild.util.Registry.get('de.intrabuild.groupware.feeds.AccountStore').reload();
                        this.store.reload();}
                  },
                 '-',{
                    text: 'als gelesen markieren',
                    scope:this,
                    handler: function(){
                        this.markItemsRead(true);}
                  },{
                    text: 'als ungelesen markieren',
                    scope:this,
                    handler: function(){
                        this.markItemsRead(false);}
                  },
                  '-',{
                    text:'Einstellungen...',
                    scope:this,
                    handler: function(){
                        var dialog = new de.intrabuild.groupware.feeds.FeedOptionsDialog();
                        dialog.show();
                    }
                }]
            });
            this.menu.on('hide', this.onContextHide, this);
        }
    },

    onContextClick : function(e)
    {
        e.stopEvent();

        // row was clicked, we wont handle this
        if (e.getTarget().id == "") {
            return;
        }

        this.createContextMenu();

        this.selModel.clearSelections();

        this.clkRow    = null;
        this.clkRecord = null;

        this.menu.items.get(2).setDisabled(true);
        this.menu.items.get(3).setDisabled(true);

        this.menu.showAt(e.getXY());
    },

    onRowContextClick : function(grid, index, e)
    {
        var selModel = this.selModel;

        this.createContextMenu();

        e.stopEvent();
        if(this.ctxRow){
            //Ext.fly(this.ctxRow).removeClass('x-node-ctx');
            this.ctxRow = null;
        }

        this.ctxRow    = this.view.getRow(index);
        this.ctxRecord = this.store.getAt(index);

        if (!selModel.isSelected(index)) {
            selModel.selectRow(index, false);
        }

        if (selModel.getCount() == 1) {
            this.menu.items.get(2).setDisabled((this.ctxRecord.data.isRead == true));
            this.menu.items.get(3).setDisabled(!(this.ctxRecord.data.isRead == true));
        } else {
            this.menu.items.get(2).setDisabled(false);
            this.menu.items.get(3).setDisabled(false);
        }

        //Ext.fly(this.ctxRow).addClass('x-node-ctx');
        this.menu.showAt(e.getXY());
    },

    onContextHide : function()
    {
        if(this.ctxRow){
           // Ext.fly(this.ctxRow).removeClass('x-node-ctx');
            this.ctxRow = null;
        }
    }

});<|endoftext|>