<commit_before>import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
import moment from 'moment';
import {inject as service} from '@ember/service';

export default class MembersRoute extends AuthenticatedRoute {
    @service config;
    @service ellaSparse;
    @service store;

    queryParams = {
        label: {refreshModel: true},
        searchParam: {refreshModel: true, replace: true}
    };

    // redirect to posts screen if:
    // - TODO: members is disabled?
    // - logged in user isn't owner/admin
    beforeModel() {
        super.beforeModel(...arguments);
        return this.session.user.then((user) => {
            if (!user.isOwnerOrAdmin) {
                return this.transitionTo('home');
            }
        });
    }

    model(params) {
        if (!params.searchParam) {
            this.controllerFor('members').resetSearch();
        }

        // use a fixed created_at date so that subsequent pages have a consistent index
        let startDate = new Date();

        // bypass the stale data shortcut if params change
        let forceReload = params.label !== this._lastLabel || params.searchParam !== this._lastSearchParam;
        this._lastLabel = params.label;
        this._lastSearchParam = params.searchParam;

        // unless we have a forced reload, do not re-fetch the members list unless it's more than a minute old
        // keeps navigation between list->details->list snappy
        if (!forceReload && this._startDate && !(this._startDate - startDate > 1 * 60 * 1000)) {
            return this.controller.members;
        }

        this._startDate = startDate;

        return this.ellaSparse.array((range = {}, query = {}) => {
            const labelFilter = params.label ? `label:'${params.label}'+` : '';

            query = Object.assign({
                limit: range.length,
                page: range.start / range.length,
                order: 'created_at desc',
                filter: `${labelFilter}created_at:<='${moment.utc(this._startDate).format('YYYY-MM-DD HH:mm:ss')}'`,
                search: params.searchParam
            }, query);

            return this.store.query('member', query).then((result) => {
                return {
                    data: result,
                    total: result.meta.pagination.total
                };
            });
        }, {
            limit: 50
        });
    }

    // trigger a background load of members plus labels for filter dropdown
    setupController(controller) {
        super.setupController(...arguments);
        controller.fetchLabelsTask.perform();
    }

    buildRouteInfoMetadata() {
        return {
            titleToken: 'Members'
        };
    }
}
<commit_msg>Fixed sending of empty search param in members browse requests<commit_after>import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
import moment from 'moment';
import {inject as service} from '@ember/service';

export default class MembersRoute extends AuthenticatedRoute {
    @service config;
    @service ellaSparse;
    @service store;

    queryParams = {
        label: {refreshModel: true},
        searchParam: {refreshModel: true, replace: true}
    };

    // redirect to posts screen if:
    // - TODO: members is disabled?
    // - logged in user isn't owner/admin
    beforeModel() {
        super.beforeModel(...arguments);
        return this.session.user.then((user) => {
            if (!user.isOwnerOrAdmin) {
                return this.transitionTo('home');
            }
        });
    }

    model(params) {
        const {label, searchParam} = params;

        if (!searchParam) {
            this.controllerFor('members').resetSearch();
        }

        // use a fixed created_at date so that subsequent pages have a consistent index
        let startDate = new Date();

        // bypass the stale data shortcut if params change
        let forceReload = label !== this._lastLabel || searchParam !== this._lastSearchParam;
        this._lastLabel = label;
        this._lastSearchParam = searchParam;

        // unless we have a forced reload, do not re-fetch the members list unless it's more than a minute old
        // keeps navigation between list->details->list snappy
        if (!forceReload && this._startDate && !(this._startDate - startDate > 1 * 60 * 1000)) {
            return this.controller.members;
        }

        this._startDate = startDate;

        return this.ellaSparse.array((range = {}, query = {}) => {
            const labelFilter = label ? `label:'${label}'+` : '';
            const searchQuery = searchParam ? {search: searchParam} : {};

            query = Object.assign({
                limit: range.length,
                page: range.start / range.length,
                order: 'created_at desc',
                filter: `${labelFilter}created_at:<='${moment.utc(this._startDate).format('YYYY-MM-DD HH:mm:ss')}'`
            }, searchQuery, query);

            return this.store.query('member', query).then((result) => {
                return {
                    data: result,
                    total: result.meta.pagination.total
                };
            });
        }, {
            limit: 50
        });
    }

    // trigger a background load of members plus labels for filter dropdown
    setupController(controller) {
        super.setupController(...arguments);
        controller.fetchLabelsTask.perform();
    }

    buildRouteInfoMetadata() {
        return {
            titleToken: 'Members'
        };
    }
}
<|endoftext|>


<commit_before>import React, {Component, PropTypes} from 'react';
import Modal from 'react-modal';
import JSONTree from 'react-json-tree';
import classNames from 'classnames';

const modalStyle = {
  overlay: {
    zIndex: 9998,
    backgroundColor: 'rgba(0, 0, 0, 0.75)'
  },
  content: {
    backgroundColor: 'dimGray',
    color: 'white',
    zIndex: 9999,
    border: '2px black'
  }
};

const theme = {
  scheme: 'google',
  author: 'seth wright (http://sethawright.com)',
  base00: '#1d1f21',
  base01: '#282a2e',
  base02: '#373b41',
  base03: '#969896',
  base04: '#b4b7b4',
  base05: '#c5c8c6',
  base06: '#e0e0e0',
  base07: '#ffffff',
  base08: '#CC342B',
  base09: '#F96A38',
  base0A: '#FBA922',
  base0B: '#198844',
  base0C: '#3971ED',
  base0D: '#3971ED',
  base0E: '#A36AC7',
  base0F: '#3971ED'
};

class ResultsPanel extends Component {
  constructor() {
    super();

    this.state = {
      currentPage: 0,
      pageSize: 10
    };

    this.switchPage = this.switchPage.bind(this);
    this.exportResults = this.exportResults.bind(this);
  }

  exportResults() {
    let dataStr = 'data:application/json;charset=utf-8,' + encodeURIComponent(JSON.stringify({results:this.props.results}, 0, 2));
    const dlAnchorElem = document.getElementById('downloadAnchorElem');
    dlAnchorElem.setAttribute("href", dataStr);
    dlAnchorElem.setAttribute("download", "results.json");
    dlAnchorElem.click();
  }

  switchPage(page) {
    this.setState({currentPage: page});
  }

  render() {

    const pageCount = Math.ceil(this.props.results.length / this.state.pageSize);
    const pages = [];

    const paginationStyle = {
      display: 'inline',
      cursor: 'pointer',
      margin: '3px',
      padding: '2px',
      textAlign: 'center',
      borderRight: '1px solid rgba(0,0,0,0.25)'
    };

    const ellipsisStyle = {
      display: 'inline',
      margin: '3px',
      padding: '2px',
      textAlign: 'center',
      borderRight: '1px solid rgba(0,0,0,0.25)'
    };
    let pageStyle = {...paginationStyle};
    if (this.state.currentPage === 0) {
      pageStyle.color = 'red';
    }
    pages.push(
1
);

    const paginationMin = (Math.max(this.state.currentPage - 3, 1));
    const paginationMax = (Math.min(this.state.currentPage + 3, pageCount));

    if (paginationMin > 1) {
      pages.push(

);
    }

    for (let p = paginationMin; p < paginationMax; p++) {
      pageStyle = {...paginationStyle};
      if (p === this.state.currentPage) {
        pageStyle.color = 'red';
      }
      pages.push(
{p + 1}
);
    }

    if (pageCount > paginationMax) {
      pages.push(

);
      pages.push(
{pageCount + 1}
);
    }

    const windowMin = (this.state.currentPage * this.state.pageSize);
    const windowMax = (this.state.currentPage * this.state.pageSize) + this.state.pageSize - 1;

    return (
      <Modal
        id='resultsPanel'
        isOpen={this.props.isResultsOpen}
        onRequestClose={this.props.hideResults}
        style={modalStyle}>
        <button className='mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect'
                onClick={this.props.clearResults}>Clear All Results
        </button>

        <button className='mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect'
                style={{float: 'right'}}
                onClick={this.exportResults}>
          Export
        </button>

        {pageCount > 1 ?

            {pages}

 : null}

            {this.props.results.map((result, i) => {
              if (i < windowMin || i > windowMax) {
                return;
              }

              let cn = classNames('result', (result.isError ? 'error' : 'success'));
              if (typeof result.result === 'string') {
                result.result = {data: result.result};
              }

              return (

{result.source}

                    <JSONTree data={result.result} theme={theme} isLightTheme={false}/>

);
            })}

      </Modal>
    );
  }
}

ResultsPanel.propTypes = {
  results: PropTypes.arrayOf(PropTypes.shape({
    id: PropTypes.any,
    isError: PropTypes.bool.isRequired,
    result: PropTypes.any.isRequired
  }).isRequired).isRequired,
  isResultsOpen: PropTypes.bool.isRequired,
  hideResults: PropTypes.func.isRequired,
  clearResults: PropTypes.func.isRequired,
  removeResult: PropTypes.func.isRequired
};

ResultsPanel.defaultProps = {
  results: []
};

export default ResultsPanel;
<commit_msg>clearing error message for missing property<commit_after>import React, {Component, PropTypes} from 'react';
import Modal from 'react-modal';
import JSONTree from 'react-json-tree';
import classNames from 'classnames';

const modalStyle = {
  overlay: {
    zIndex: 9998,
    backgroundColor: 'rgba(0, 0, 0, 0.75)'
  },
  content: {
    backgroundColor: 'dimGray',
    color: 'white',
    zIndex: 9999,
    border: '2px black'
  }
};

const theme = {
  scheme: 'google',
  author: 'seth wright (http://sethawright.com)',
  base00: '#1d1f21',
  base01: '#282a2e',
  base02: '#373b41',
  base03: '#969896',
  base04: '#b4b7b4',
  base05: '#c5c8c6',
  base06: '#e0e0e0',
  base07: '#ffffff',
  base08: '#CC342B',
  base09: '#F96A38',
  base0A: '#FBA922',
  base0B: '#198844',
  base0C: '#3971ED',
  base0D: '#3971ED',
  base0E: '#A36AC7',
  base0F: '#3971ED'
};

class ResultsPanel extends Component {
  constructor() {
    super();

    this.state = {
      currentPage: 0,
      pageSize: 10
    };

    this.switchPage = this.switchPage.bind(this);
    this.exportResults = this.exportResults.bind(this);
  }

  exportResults() {
    let dataStr = 'data:application/json;charset=utf-8,' + encodeURIComponent(JSON.stringify({results:this.props.results}, 0, 2));
    const dlAnchorElem = document.getElementById('downloadAnchorElem');
    dlAnchorElem.setAttribute("href", dataStr);
    dlAnchorElem.setAttribute("download", "results.json");
    dlAnchorElem.click();
  }

  switchPage(page) {
    this.setState({currentPage: page});
  }

  render() {

    const pageCount = Math.ceil(this.props.results.length / this.state.pageSize);
    const pages = [];

    const paginationStyle = {
      display: 'inline',
      cursor: 'pointer',
      margin: '3px',
      padding: '2px',
      textAlign: 'center',
      borderRight: '1px solid rgba(0,0,0,0.25)'
    };

    const ellipsisStyle = {
      display: 'inline',
      margin: '3px',
      padding: '2px',
      textAlign: 'center',
      borderRight: '1px solid rgba(0,0,0,0.25)'
    };
    let pageStyle = {...paginationStyle};
    if (this.state.currentPage === 0) {
      pageStyle.color = 'red';
    }
    pages.push(
1
);

    const paginationMin = (Math.max(this.state.currentPage - 3, 1));
    const paginationMax = (Math.min(this.state.currentPage + 3, pageCount));

    if (paginationMin > 1) {
      pages.push(

);
    }

    for (let p = paginationMin; p < paginationMax; p++) {
      pageStyle = {...paginationStyle};
      if (p === this.state.currentPage) {
        pageStyle.color = 'red';
      }
      pages.push(
{p + 1}
);
    }

    if (pageCount > paginationMax) {
      pages.push(

);
      pages.push(
{pageCount + 1}
);
    }

    const windowMin = (this.state.currentPage * this.state.pageSize);
    const windowMax = (this.state.currentPage * this.state.pageSize) + this.state.pageSize - 1;

    return (
      <Modal
        id='resultsPanel'
        contentLabel="Results"
        isOpen={this.props.isResultsOpen}
        onRequestClose={this.props.hideResults}
        style={modalStyle}>
        <button className='mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect'
                onClick={this.props.clearResults}>Clear All Results
        </button>

        <button className='mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect'
                style={{float: 'right'}}
                onClick={this.exportResults}>
          Export
        </button>

        {pageCount > 1 ?

            {pages}

 : null}

            {this.props.results.map((result, i) => {
              if (i < windowMin || i > windowMax) {
                return;
              }

              let cn = classNames('result', (result.isError ? 'error' : 'success'));
              if (typeof result.result === 'string') {
                result.result = {data: result.result};
              }

              return (

{result.source}

                    <JSONTree data={result.result} theme={theme} isLightTheme={false}/>

);
            })}

      </Modal>
    );
  }
}

ResultsPanel.propTypes = {
  results: PropTypes.arrayOf(PropTypes.shape({
    id: PropTypes.any,
    isError: PropTypes.bool.isRequired,
    result: PropTypes.any.isRequired
  }).isRequired).isRequired,
  isResultsOpen: PropTypes.bool.isRequired,
  hideResults: PropTypes.func.isRequired,
  clearResults: PropTypes.func.isRequired,
  removeResult: PropTypes.func.isRequired
};

ResultsPanel.defaultProps = {
  results: []
};

export default ResultsPanel;
<|endoftext|>


<commit_before>var assert = require('assert');

import {connectedComponents} from './connected_components';

var tests = [
    {
        graph: {
            vertexCount: 0,
            directed: false,
            edges: []
        },
        components: []
    },
    {
        graph: {
            vertexCount: 1,
            directed: false,
            edges: []
        },
        components: [0]
    },
    {
        graph: {
            vertexCount: 2,
            directed: false,
            edges: []
        },
        components: [0, 1]
    },
    {
        graph: {
            vertexCount: 2,
            directed: false,
            edges: [
                [0, 1]
            ]
        },
        components: [0, 0]
    },
    {
        graph: {
            vertexCount: 7,
            directed: false,
            edges: [
                [0, 2],
                [2, 3],
                [2, 5],
                [1, 4]
            ]
        },
        components: [0, 1, 0, 0, 1, 0, 2]
    }
];

function runTest(test) {
    assert.deepEqual(connectedComponents(test.graph), test.components);
}

tests.forEach(runTest);

console.log('All tests OK.');
<commit_msg>[connected_components/javascript] Replace var by let<commit_after>let assert = require('assert');

import {connectedComponents} from './connected_components';

let tests = [
    {
        graph: {
            vertexCount: 0,
            directed: false,
            edges: []
        },
        components: []
    },
    {
        graph: {
            vertexCount: 1,
            directed: false,
            edges: []
        },
        components: [0]
    },
    {
        graph: {
            vertexCount: 2,
            directed: false,
            edges: []
        },
        components: [0, 1]
    },
    {
        graph: {
            vertexCount: 2,
            directed: false,
            edges: [
                [0, 1]
            ]
        },
        components: [0, 0]
    },
    {
        graph: {
            vertexCount: 7,
            directed: false,
            edges: [
                [0, 2],
                [2, 3],
                [2, 5],
                [1, 4]
            ]
        },
        components: [0, 1, 0, 0, 1, 0, 2]
    }
];

function runTest(test) {
    assert.deepEqual(connectedComponents(test.graph), test.components);
}

tests.forEach(runTest);

console.log('All tests OK.');
<|endoftext|>


<commit_before>var m             	= require('mithril');
var Navbar        	= require('../../components/navbar/navbar.js');
var NewApp        	= require('../../components/forms/newApp/newApp.js');
var Messaging     	= require('../../components/messaging/messaging.js');
var OnsiteInterview = require('../../components/forms/onsiteInterview/onsiteInterview.js');
var Phases        	= require('../../components/phases/phases.js');
var PhoneScreen     = require('../../components/forms/phoneScreen/phoneScreen.js');
var StudentInfo   	= require('../../components/studentInfo/studentInfo.js');
var StudentJobs     = require('../../components/studentJobs/studentJobs.js')

exports.controller = function () {
  var ctrl = this;
}

exports.view = function (ctrl) {
  return m('.container', [
  	m.component(StudentJobs),
    m.component(NewApp),
    m.component(StudentInfo)
  ])
}<commit_msg>studentInfo and newApp correct list<commit_after>var m             	= require('mithril');
var Navbar        	= require('../../components/navbar/navbar.js');
var NewApp        	= require('../../components/forms/newApp/newApp.js');
var Messaging     	= require('../../components/messaging/messaging.js');
var OnsiteInterview = require('../../components/forms/onsiteInterview/onsiteInterview.js');
var Phases        	= require('../../components/phases/phases.js');
var PhoneScreen     = require('../../components/forms/phoneScreen/phoneScreen.js');
var StudentInfo   	= require('../../components/studentInfo/studentInfo.js');
var StudentJobs     = require('../../components/studentJobs/studentJobs.js')

exports.controller = function () {
  var ctrl = this;
}

exports.view = function (ctrl) {
  return m('.container', [
  	m.component(StudentJobs),
    m.component(StudentInfo)
    m.component(NewApp),
  ])
}<|endoftext|>


<commit_before>describe('the fahrenheit2celsius canary spec', () => {
  it('shows the infrastructure works', () => {
    true.should.be.true();
  });

  describe('fahrenheit2celsius should', () => {
    it('give 0°C for 32°F', () => {
      fahrenheit2celsiusOf(32).should.equal(0);
    });
    it('give 10°C for 50°F');
  });
});
<commit_msg>change message to TypeError: Cannot read property 'should' of undefined<commit_after>describe('the fahrenheit2celsius canary spec', () => {
  it('shows the infrastructure works', () => {
    true.should.be.true();
  });

  let fahrenheit2celsiusOf = function(number) {

  }
  describe('fahrenheit2celsius should', () => {
    it('give 0°C for 32°F', () => {
      fahrenheit2celsiusOf(32).should.equal(0);
    });
    it('give 10°C for 50°F');
  });
});
<|endoftext|>


<commit_before>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2009 Apple, Inc. All rights reserved.
// License:   Licened under MIT license (see license.js)
// ==========================================================================

sc_require('views/list');
sc_require('views/table_row');
sc_require('views/table_head');
sc_require('mixins/table_delegate');

/** @class

  A table view renders a two-dimensional grid of data.

  TODO: More documentation.

  @extends SC.ListView
  @extends SC.TableDelegate
  @since SproutCore 1.1
*/

SC.TableView = SC.ListView.extend(SC.TableDelegate, {
  /** @scope SC.TableView.prototype */

  // ..........................................................
  // PROPERTIES
  //

  classNames: ['sc-table-view'],

  childViews: "tableHeadView scrollView".w(),

  scrollView: SC.ScrollView.design({
    isVisible: YES,
    layout: {
      left:   -1,
      right:  0,
      bottom: 0,
      top:    18
    },
    hasHorizontalScroller: NO,
    contentView: SC.View.design({
    }),

    // FIXME: Hack.
    _sv_offsetDidChange: function() {
      this.get('parentView')._sctv_scrollOffsetDidChange();
    }.observes('verticalScrollOffset', 'horizontalScrollOffset')
  }),

  hasHorizontalScroller: NO,
  hasVerticalScroller: NO,

  selectOnMouseDown: NO,

  // FIXME: Charles originally had this as an outlet, but that doesn't work.
  // Figure out why.
  containerView: function() {
    var scrollView = this.get('scrollView');
    return (scrollView && scrollView.get) ? scrollView.get('contentView') : null;
    //return this.get('scrollView').get('contentView');
  }.property('scrollView'),

  layout: { left: 0, right: 0, top: 0, bottom: 0 },

  init: function() {
    window.table = this; // DEBUG
    //this._sctv_columnsDidChange();
    return sc_super();
  },

  canReorderContent: NO,

  isInDragMode: NO,

  // ..........................................................
  // EVENT RESPONDERS
  //

  mouseDownInTableHeaderView: function(evt, header) {
    var column = header.get('column');

    if (!column.get('isReorderable') && !column.get('isSortable')) {
      return NO;
    }

    // Save the mouseDown event so we can use it for mouseUp/mouseDragged.
    this._mouseDownEvent = evt;
    // Set the timer for switching from a sort action to a reorder action.
    this._mouseDownTimer = SC.Timer.schedule({
      target: this,
      action: '_scthv_enterDragMode',
      interval: 300
    });

    return YES;
  },

  mouseUpInTableHeaderView: function(evt, header) {
    var isInDragMode = this.get('isInDragMode');
    // Only sort if we're not in drag mode (i.e., short clicks).
    if (!isInDragMode) {
      var column = header.get('column');
      // Change the sort state of the associated column.
      this.set('sortedColumn', column);

      var sortState = column.get('sortState');
      var newSortState = sortState === SC.SORT_ASCENDING ?
       SC.SORT_DESCENDING : SC.SORT_ASCENDING;

      column.set('sortState', newSortState);
    }

    // Exit drag mode (and cancel any scheduled drag modes).
    // this._scthv_exitDragMode();
    this._dragging = false;
    if (this._mouseDownTimer) {
      this._mouseDownTimer.invalidate();
    }

  },

  mouseDraggedInTableHeaderView: function(evt, header) {
    SC.RunLoop.begin();
    var isInDragMode = this.get('isInDragMode');
    if (!isInDragMode) return NO;

    if (!this._dragging) {
      SC.Drag.start({
        event:  this._mouseDownEvent,
        source: header,
        dragView: this._scthv_dragViewForHeader(),
        ghost: YES
        //anchorView: this.get('parentView')
      });
      this._dragging = true;
    }

    return sc_super();
    SC.RunLoop.end();
  },

  // ..........................................................
  // COLUMN PROPERTIES
  //

  /**
    A collection of `SC.TableColumn` objects. Modify the array to adjust the
    columns.

    @property
    @type Array
  */
  columns: [],

  /**
    Which column will alter its size so that the columns fill the available
    width of the table. If `null`, the last column will stretch.

    @property
    @type SC.TableColumn
  */
  flexibleColumn: null,

  /**
    Which column is currently the "active" column for sorting purposes.
    Doesn't say anything about sorting direction; for that, read the
    `sortState` property of the sorted column.

    @property
    @type SC.TableColumn
  */
  sortedColumn: null,

  // ..........................................................
  // HEAD PROPERTIES
  //

  /**
    if YES, the table view will generate a head row at the top of the table
    view.

    @property
    @type Boolean
  */
  hasTableHead: YES,

  /**
    The view that serves as the head view for the table (if any).

    @property
    @type SC.View
  */
  tableHeadView: SC.TableHeadView.design({
    layout: { top: 0, left: 0, right: 0 }
  }),

  /**
    The height of the table head in pixels.

    @property
    @type Number
  */
  tableHeadHeight: 18,

  // ..........................................................
  // ROW PROPERTIES
  //

  /**
    Whether all rows in the table will have the same pixel height. If so, we
    can compute offsets very cheaply.

    @property
    @type Boolean
  */
  hasUniformRowHeights: YES,

  /**
    How high each row should be, in pixels.

    @property
    @type Number
  */
  rowHeight: 18,

  /**
    Which view to use for a table row.

    @property
    @type SC.View
  */
  exampleView: SC.TableRowView,

  // ..........................................................
  // DRAG-REORDER MODE
  //

  isInColumnDragMode: NO,

  // ..........................................................
  // OTHER PROPERTIES
  //

  filterKey: null,

  /**
    Returns the top offset for the specified content index.  This will take
    into account any custom row heights and group views.

    @param {Number} idx the content index
    @returns {Number} the row offset in pixels
  */

  rowOffsetForContentIndex: function(contentIndex) {
    var top = 0, idx;

    if (this.get('hasUniformRowHeights')) {
      return top + (this.get('rowHeight') * contentIndex);
    } else {
      for (idx = 0; idx < contentIndex; i++) {
        top += this.rowHeightForContentIndex(idx);
      }
      return top;
    }
  },

  /**
    Returns the row height for the specified content index.  This will take
    into account custom row heights and group rows.

    @param {Number} idx content index
    @returns {Number} the row height in pixels
  */
  rowHeightForContentIndex: function(contentIndex) {
    if (this.get('hasUniformRowHeights')) {
      return this.get('rowHeight');
    } else {
      // TODO
    }
  },

  /**
    Computes the layout for a specific content index by combining the current
    row heights.

    @param {Number} index content index
  */
  layoutForContentIndex: function(index) {
    return {
      top:    this.rowOffsetForContentIndex(index),
      height: this.rowHeightForContentIndex(index),
      left:   0,
      right:  0
    };
  },

  createItemView: function(exampleClass, idx, attrs) {
    // Add a `tableView` attribute to each created row so it has a way to
    // refer back to this view.
    attrs.tableView = this;
    return exampleClass.create(attrs);
  },

  clippingFrame: function() {
    var cv = this.get('containerView'),
        sv = this.get('scrollView'),
        f  = this.get('frame');

    if (!sv.get) {
      return f;
    }

    return {
      height: f.height,
      width:  f.width,
      x:      sv.get('horizontalScrollOffset'),
      y:      sv.get('verticalScrollOffset')
    };

  }.property('frame', 'content').cacheable(),

  _sctv_scrollOffsetDidChange: function() {
    this.notifyPropertyChange('clippingFrame');
  },

  // ..........................................................
  // SUBCLASS IMPLEMENTATIONS
  //

  computeLayout: function() {
    var layout = sc_super(),
        containerView = this.get('containerView'),
        frame = this.get('frame');

    var minHeight = layout.minHeight;
    delete layout.minHeight;

    // FIXME: In the middle of initialization, the TableView needs to be
    // reloaded in order to become aware of the proper display state of the
    // table rows. This is currently the best heuristic I can find to decide
    // when to do the reload. But the whole thing is a hack and should be
    // fixed as soon as possible.
    // var currentHeight = containerView.get('layout').height;
    // if (currentHeight !== height) {
    //   this.reload();
    // }

    containerView.adjust('minHeight', minHeight);
    containerView.layoutDidChange();

    //containerView.adjust('height', height);
    //containerView.layoutDidChange();

    this.notifyPropertyChange('clippingFrame');
    return layout;
  },

  // ..........................................................
  // INTERNAL SUPPORT
  //

  // When the columns change, go through all the columns and set their tableContent to be this table's content
  // TODO: should these guys not just have a binding of this instead?
  _sctv_columnsDidChange: function() {

    var columns = this.get('columns'),
        content = this.get('content'),
        idx;

    for (idx = 0; idx < columns.get('length'); idx++) {
      columns.objectAt(idx).set('tableContent', content);
    }
    this.get('tableHeadView')._scthv_handleChildren();
    this.reload();

  }.observes('columns'),

  // Do stuff when our frame size changes.
  _sctv_adjustColumnWidthsOnResize: function() {

    var width   = this.get('frame').width;
    var content = this.get('content'),
        del = this.delegateFor('isTableDelegate', this.delegate, content);

    if (this.get('columns').length == 0) return;
    width = del.tableShouldResizeWidthTo(this, width);

    var columns = this.get('columns'), totalColumnWidth = 0, idx;

    for (var idx = 0; idx < columns.length; idx++) {
      totalColumnWidth += columns.objectAt(idx).get('width');
    }

    if (width === 0) width = totalColumnWidth;
    var flexibleColumn = this.get('flexibleColumn') ||
      this.get('columns').objectAt(this.get('columns').length - 1);
    var flexibleWidth = flexibleColumn.get('width') +
     (width - totalColumnWidth);

    flexibleColumn.set('width', flexibleWidth);
  }.observes('frame'),

  // =============================================================
  // = This is all terrible, but will have to do in the interim. =
  // =============================================================
  _sctv_sortContent: function() {
    var sortedColumn = this.get('sortedColumn');
    var sortKey = sortedColumn.get('key');
    this.set('orderBy', sortKey);
  },

  _sctv_sortedColumnDidChange: function() {
    var columns = this.get('columns'),
        sortedColumn = this.get('sortedColumn'),
        column, idx;

    for (idx = 0; idx < columns.get('length'); idx++) {
      column = columns.objectAt(idx);
      if (column !== sortedColumn) {
        column.set('sortState', null);
      }
    }

    this.invokeOnce('_sctv_sortContent');
  }.observes('sortedColumn')
});
<commit_msg>no border on tables<commit_after>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2009 Apple, Inc. All rights reserved.
// License:   Licened under MIT license (see license.js)
// ==========================================================================

sc_require('views/list');
sc_require('views/table_row');
sc_require('views/table_head');
sc_require('mixins/table_delegate');

/** @class

  A table view renders a two-dimensional grid of data.

  TODO: More documentation.

  @extends SC.ListView
  @extends SC.TableDelegate
  @since SproutCore 1.1
*/

SC.TableView = SC.ListView.extend(SC.TableDelegate, {
  /** @scope SC.TableView.prototype */

  // ..........................................................
  // PROPERTIES
  //

  classNames: ['sc-table-view'],

  childViews: "tableHeadView scrollView".w(),

  scrollView: SC.ScrollView.design({
    isVisible: YES,
    layout: {
      left:   -1,
      right:  0,
      bottom: 0,
      top:    18
    },
    hasHorizontalScroller: NO,
    borderStyle: SC.BORDER_NONE,
    contentView: SC.View.design({
    }),

    // FIXME: Hack.
    _sv_offsetDidChange: function() {
      this.get('parentView')._sctv_scrollOffsetDidChange();
    }.observes('verticalScrollOffset', 'horizontalScrollOffset')
  }),

  hasHorizontalScroller: NO,
  hasVerticalScroller: NO,

  selectOnMouseDown: NO,

  // FIXME: Charles originally had this as an outlet, but that doesn't work.
  // Figure out why.
  containerView: function() {
    var scrollView = this.get('scrollView');
    return (scrollView && scrollView.get) ? scrollView.get('contentView') : null;
    //return this.get('scrollView').get('contentView');
  }.property('scrollView'),

  layout: { left: 0, right: 0, top: 0, bottom: 0 },

  init: function() {
    window.table = this; // DEBUG
    //this._sctv_columnsDidChange();
    return sc_super();
  },

  canReorderContent: NO,

  isInDragMode: NO,

  // ..........................................................
  // EVENT RESPONDERS
  //

  mouseDownInTableHeaderView: function(evt, header) {
    var column = header.get('column');

    if (!column.get('isReorderable') && !column.get('isSortable')) {
      return NO;
    }

    // Save the mouseDown event so we can use it for mouseUp/mouseDragged.
    this._mouseDownEvent = evt;
    // Set the timer for switching from a sort action to a reorder action.
    this._mouseDownTimer = SC.Timer.schedule({
      target: this,
      action: '_scthv_enterDragMode',
      interval: 300
    });

    return YES;
  },

  mouseUpInTableHeaderView: function(evt, header) {
    var isInDragMode = this.get('isInDragMode');
    // Only sort if we're not in drag mode (i.e., short clicks).
    if (!isInDragMode) {
      var column = header.get('column');
      // Change the sort state of the associated column.
      this.set('sortedColumn', column);

      var sortState = column.get('sortState');
      var newSortState = sortState === SC.SORT_ASCENDING ?
       SC.SORT_DESCENDING : SC.SORT_ASCENDING;

      column.set('sortState', newSortState);
    }

    // Exit drag mode (and cancel any scheduled drag modes).
    // this._scthv_exitDragMode();
    this._dragging = false;
    if (this._mouseDownTimer) {
      this._mouseDownTimer.invalidate();
    }

  },

  mouseDraggedInTableHeaderView: function(evt, header) {
    SC.RunLoop.begin();
    var isInDragMode = this.get('isInDragMode');
    if (!isInDragMode) return NO;

    if (!this._dragging) {
      SC.Drag.start({
        event:  this._mouseDownEvent,
        source: header,
        dragView: this._scthv_dragViewForHeader(),
        ghost: YES
        //anchorView: this.get('parentView')
      });
      this._dragging = true;
    }

    return sc_super();
    SC.RunLoop.end();
  },

  // ..........................................................
  // COLUMN PROPERTIES
  //

  /**
    A collection of `SC.TableColumn` objects. Modify the array to adjust the
    columns.

    @property
    @type Array
  */
  columns: [],

  /**
    Which column will alter its size so that the columns fill the available
    width of the table. If `null`, the last column will stretch.

    @property
    @type SC.TableColumn
  */
  flexibleColumn: null,

  /**
    Which column is currently the "active" column for sorting purposes.
    Doesn't say anything about sorting direction; for that, read the
    `sortState` property of the sorted column.

    @property
    @type SC.TableColumn
  */
  sortedColumn: null,

  // ..........................................................
  // HEAD PROPERTIES
  //

  /**
    if YES, the table view will generate a head row at the top of the table
    view.

    @property
    @type Boolean
  */
  hasTableHead: YES,

  /**
    The view that serves as the head view for the table (if any).

    @property
    @type SC.View
  */
  tableHeadView: SC.TableHeadView.design({
    layout: { top: 0, left: 0, right: 0 }
  }),

  /**
    The height of the table head in pixels.

    @property
    @type Number
  */
  tableHeadHeight: 18,

  // ..........................................................
  // ROW PROPERTIES
  //

  /**
    Whether all rows in the table will have the same pixel height. If so, we
    can compute offsets very cheaply.

    @property
    @type Boolean
  */
  hasUniformRowHeights: YES,

  /**
    How high each row should be, in pixels.

    @property
    @type Number
  */
  rowHeight: 18,

  /**
    Which view to use for a table row.

    @property
    @type SC.View
  */
  exampleView: SC.TableRowView,

  // ..........................................................
  // DRAG-REORDER MODE
  //

  isInColumnDragMode: NO,

  // ..........................................................
  // OTHER PROPERTIES
  //

  filterKey: null,

  /**
    Returns the top offset for the specified content index.  This will take
    into account any custom row heights and group views.

    @param {Number} idx the content index
    @returns {Number} the row offset in pixels
  */

  rowOffsetForContentIndex: function(contentIndex) {
    var top = 0, idx;

    if (this.get('hasUniformRowHeights')) {
      return top + (this.get('rowHeight') * contentIndex);
    } else {
      for (idx = 0; idx < contentIndex; i++) {
        top += this.rowHeightForContentIndex(idx);
      }
      return top;
    }
  },

  /**
    Returns the row height for the specified content index.  This will take
    into account custom row heights and group rows.

    @param {Number} idx content index
    @returns {Number} the row height in pixels
  */
  rowHeightForContentIndex: function(contentIndex) {
    if (this.get('hasUniformRowHeights')) {
      return this.get('rowHeight');
    } else {
      // TODO
    }
  },

  /**
    Computes the layout for a specific content index by combining the current
    row heights.

    @param {Number} index content index
  */
  layoutForContentIndex: function(index) {
    return {
      top:    this.rowOffsetForContentIndex(index),
      height: this.rowHeightForContentIndex(index),
      left:   0,
      right:  0
    };
  },

  createItemView: function(exampleClass, idx, attrs) {
    // Add a `tableView` attribute to each created row so it has a way to
    // refer back to this view.
    attrs.tableView = this;
    return exampleClass.create(attrs);
  },

  clippingFrame: function() {
    var cv = this.get('containerView'),
        sv = this.get('scrollView'),
        f  = this.get('frame');

    if (!sv.get) {
      return f;
    }

    return {
      height: f.height,
      width:  f.width,
      x:      sv.get('horizontalScrollOffset'),
      y:      sv.get('verticalScrollOffset')
    };

  }.property('frame', 'content').cacheable(),

  _sctv_scrollOffsetDidChange: function() {
    this.notifyPropertyChange('clippingFrame');
  },

  // ..........................................................
  // SUBCLASS IMPLEMENTATIONS
  //

  computeLayout: function() {
    var layout = sc_super(),
        containerView = this.get('containerView'),
        frame = this.get('frame');

    var minHeight = layout.minHeight;
    delete layout.minHeight;

    // FIXME: In the middle of initialization, the TableView needs to be
    // reloaded in order to become aware of the proper display state of the
    // table rows. This is currently the best heuristic I can find to decide
    // when to do the reload. But the whole thing is a hack and should be
    // fixed as soon as possible.
    // var currentHeight = containerView.get('layout').height;
    // if (currentHeight !== height) {
    //   this.reload();
    // }

    containerView.adjust('minHeight', minHeight);
    containerView.layoutDidChange();

    //containerView.adjust('height', height);
    //containerView.layoutDidChange();

    this.notifyPropertyChange('clippingFrame');
    return layout;
  },

  // ..........................................................
  // INTERNAL SUPPORT
  //

  // When the columns change, go through all the columns and set their tableContent to be this table's content
  // TODO: should these guys not just have a binding of this instead?
  _sctv_columnsDidChange: function() {

    var columns = this.get('columns'),
        content = this.get('content'),
        idx;

    for (idx = 0; idx < columns.get('length'); idx++) {
      columns.objectAt(idx).set('tableContent', content);
    }
    this.get('tableHeadView')._scthv_handleChildren();
    this.reload();

  }.observes('columns'),

  // Do stuff when our frame size changes.
  _sctv_adjustColumnWidthsOnResize: function() {

    var width   = this.get('frame').width;
    var content = this.get('content'),
        del = this.delegateFor('isTableDelegate', this.delegate, content);

    if (this.get('columns').length == 0) return;
    width = del.tableShouldResizeWidthTo(this, width);

    var columns = this.get('columns'), totalColumnWidth = 0, idx;

    for (var idx = 0; idx < columns.length; idx++) {
      totalColumnWidth += columns.objectAt(idx).get('width');
    }

    if (width === 0) width = totalColumnWidth;
    var flexibleColumn = this.get('flexibleColumn') ||
      this.get('columns').objectAt(this.get('columns').length - 1);
    var flexibleWidth = flexibleColumn.get('width') +
     (width - totalColumnWidth);

    flexibleColumn.set('width', flexibleWidth);
  }.observes('frame'),

  // =============================================================
  // = This is all terrible, but will have to do in the interim. =
  // =============================================================
  _sctv_sortContent: function() {
    var sortedColumn = this.get('sortedColumn');
    var sortKey = sortedColumn.get('key');
    this.set('orderBy', sortKey);
  },

  _sctv_sortedColumnDidChange: function() {
    var columns = this.get('columns'),
        sortedColumn = this.get('sortedColumn'),
        column, idx;

    for (idx = 0; idx < columns.get('length'); idx++) {
      column = columns.objectAt(idx);
      if (column !== sortedColumn) {
        column.set('sortState', null);
      }
    }

    this.invokeOnce('_sctv_sortContent');
  }.observes('sortedColumn')
});
<|endoftext|>


<commit_before>angular
    .module('app.filter')
    .directive('wlfgFilterProgress', wlfgFilterProgress);

wlfgFilterProgress.$inject = ['$stateParams', '$location'];
function wlfgFilterProgress($stateParams, $location) {
    var directive = {
        link: link,
        restrict: 'A',
        templateUrl: 'app/filter/character/filter.progress.directive.html'
    };

    return directive;

    function link($scope, element, attrs) {
        $scope.progress = {difficulty:"none", min:1, max:13};

        if ($stateParams.progress) {
            $scope.filters.progress = $stateParams.progress;
            $scope.progress.active = true;
            $scope.progress.difficulty = $stateParams.progress.split(".")[0];
            $scope.progress.min = $stateParams.progress.split(".")[1];
            $scope.progress.max = $stateParams.progress.split(".")[2];

        }

        $scope.filters.states.progress = true;

        // Allow the progress filter to be toggled off by clicking on the
        // currently active difficulty. This avoids the need for a fourth
        // box with value="none" to clear the selection.
        // http://stackoverflow.com/questions/25443018/angularjs-is-it-possible-to-deselect-html-radio-input-by-click
        var lastDifficulty = $scope.progress.difficulty;
        $scope.maybeToggleOff = function (event) {
            if (event.target.value === lastDifficulty) {
                $scope.progress.difficulty = "none";
                lastDifficulty = "none";
            } else {
                lastDifficulty = event.target.value;
            }
        };

        $scope.$watch('progress', function() {
            if ($scope.$parent.loading || $scope.loading) {
                return;
            }

            if ($scope.progress.difficulty === "none") {
                $location.search('progress', null);
                $scope.filters.progress = null;
            } else {
                $location.search('progress', $scope.progress.difficulty + "."+ $scope.progress.min+ "."+ $scope.progress.max);
                $scope.filters.progress = $scope.progress.difficulty + "."+ $scope.progress.min+ "."+ $scope.progress.max;
            }

            $scope.$parent.loading = true;
        },true);
    }
}<commit_msg>Filter progress for Emerald Nightmare<commit_after>angular
    .module('app.filter')
    .directive('wlfgFilterProgress', wlfgFilterProgress);

wlfgFilterProgress.$inject = ['$stateParams', '$location'];
function wlfgFilterProgress($stateParams, $location) {
    var directive = {
        link: link,
        restrict: 'A',
        templateUrl: 'app/filter/character/filter.progress.directive.html'
    };

    return directive;

    function link($scope, element, attrs) {
        $scope.progress = {difficulty:"none", min:1, max:7};

        if ($stateParams.progress) {
            $scope.filters.progress = $stateParams.progress;
            $scope.progress.active = true;
            $scope.progress.difficulty = $stateParams.progress.split(".")[0];
            $scope.progress.min = $stateParams.progress.split(".")[1];
            $scope.progress.max = $stateParams.progress.split(".")[2];

        }

        $scope.filters.states.progress = true;

        // Allow the progress filter to be toggled off by clicking on the
        // currently active difficulty. This avoids the need for a fourth
        // box with value="none" to clear the selection.
        // http://stackoverflow.com/questions/25443018/angularjs-is-it-possible-to-deselect-html-radio-input-by-click
        var lastDifficulty = $scope.progress.difficulty;
        $scope.maybeToggleOff = function (event) {
            if (event.target.value === lastDifficulty) {
                $scope.progress.difficulty = "none";
                lastDifficulty = "none";
            } else {
                lastDifficulty = event.target.value;
            }
        };

        $scope.$watch('progress', function() {
            if ($scope.$parent.loading || $scope.loading) {
                return;
            }

            if ($scope.progress.difficulty === "none") {
                $location.search('progress', null);
                $scope.filters.progress = null;
            } else {
                $location.search('progress', $scope.progress.difficulty + "."+ $scope.progress.min+ "."+ $scope.progress.max);
                $scope.filters.progress = $scope.progress.difficulty + "."+ $scope.progress.min+ "."+ $scope.progress.max;
            }

            $scope.$parent.loading = true;
        },true);
    }
}<|endoftext|>


<commit_before>'use strict';

angular.module('mean.icu.ui.tasklistdirective', [])
.directive('icuTaskList', function ($state, $uiViewScroll, $stateParams, $timeout, context, UsersService) {
        var creatingStatuses = {
            NotCreated: 0,
            Creating: 1,
            Created: 2
        };

        function controller($scope, TasksService) {
        $scope.context = context;
        $scope.isLoading = true;

        _($scope.tasks).each(function(t) {
            t.__state = creatingStatuses.Created;
        });

            var newTask = {
            title: '',
            watchers: [],
            tags: [],
            __state: creatingStatuses.NotCreated,
            __autocomplete: true
        };

        if (!$scope.displayOnly) {
            if (context.entityName === 'my'){
                UsersService.getMe().then(function (me) {
                    newTask.assign = me._id;
                    $scope.tasks.push(_(newTask).clone());
                });
            }
            else
                $scope.tasks.push(_(newTask).clone());
        }

        if (context.entityName === 'all') {
        	$scope.detailsState = 'main.tasks.all.details';
        } else if (context.entityName === 'my') {
        	$scope.detailsState = 'main.tasks.byassign.details';
        } else {
        	$scope.detailsState = 'main.tasks.byentity.details';
        }

        $scope.createOrUpdate = function(task) {
            if (context.entityName !== 'all') {
                task[context.entityName] = context.entity;
            }

            if (task.__state === creatingStatuses.NotCreated) {
                task.__state = creatingStatuses.Creating;

                return TasksService.create(task).then(function(result) {
                    task.__state = creatingStatuses.Created;

                    $scope.tasks.push(_(newTask).clone());

                    return task;
                });
            } else if (task.__state === creatingStatuses.Created) {
                return TasksService.update(task);
            }
        };
        $scope.debouncedUpdate = _.debounce($scope.createOrUpdate, 300);

        $scope.searchResults = [];

        $scope.search = function(task) {
            if (context.entityName !== 'discussion') {
                return;
            }

            if (!task.__autocomplete) {
                return;
            }

            var term = task.title;
            if (!term) {
                return;
            }

            $scope.searchResults.length = 0;
            $scope.selectedSuggestion = 0;
            TasksService.search(term).then(function(searchResults) {
                _(searchResults).each(function(sr) {
                    var alreadyAdded = _($scope.tasks).any(function(t) {
                        return t._id === sr._id;
                    });

                    if (!alreadyAdded) {
                        $scope.searchResults.push(sr);
                    }
                });
                $scope.selectedSuggestion = 0;
            });
        };

        $scope.select = function(selectedTask) {
            var currentTask = _($scope.tasks).find(function(t) {
                return t.__autocomplete;
            });

            TasksService.remove(currentTask._id);

            _(currentTask).assign(selectedTask);
            currentTask.__autocomplete = false;

            $scope.searchResults.length = 0;
            $scope.selectedSuggestion = 0;

            $scope.createOrUpdate(currentTask).then(function(task) {
                $state.go('main.tasks.byentity.details', {
                    id: task._id,
                    entity: context.entityName,
                    entityId: context.entityId
                });
            });
        };

    }

    function link($scope, $element) {
        var isScrolled = false;

        $scope.initialize = function($event, task) {
            if ($scope.displayOnly) {
                return;
            }

            var nameFocused = angular.element($event.target).hasClass('name');

            if (task.__state === creatingStatuses.NotCreated) {
                $scope.createOrUpdate(task).then(function() {
                    $state.go($scope.detailsState, {
                        id: task._id,
                        entity: context.entityName,
                        entityId: context.entityId,
                        nameFocused: nameFocused
                    });
                });
            } else {
                $state.go($scope.detailsState, {
                    id: task._id,
                    entity: context.entityName,
                    entityId: context.entityId,
                    nameFocused: nameFocused
                });
            }
        };

        $scope.isCurrentState = function (id) {
            var isActive = ($state.current.name.indexOf('main.tasks.byentity.details') === 0 ||
                            $state.current.name.indexOf('main.tasks.all.details') === 0
                       ) && $state.params.id === id;

            if (isActive && !isScrolled) {
                $uiViewScroll($element.find('[data-id="' + $stateParams.id + '"]'));
                isScrolled = true;
            }

            return isActive;
        };

        $scope.onEnter = function($event, index) {
            // if ($event.keyCode === 13 || $event.keyCode === 9) {
            //     $event.preventDefault();

            //     $scope.tasks[index].__autocomplete = false;
            //     if ($element.find('td.name')[index+1]) $element.find('td.name')[index+1].focus();
            //     else {
            //     	$timeout(function() {
			//             $element.find('td.name')[index+1].focus();
			//         }, 500);
            //     }

            // }
        };

        $scope.focusAutoComplete = function($event) {
            if ($event.keyCode === 38) {
                if ($scope.selectedSuggestion > 0) {
                    $scope.selectedSuggestion -= 1;
                }
                $event.preventDefault();
            } else if ($event.keyCode === 40) {
                if ($scope.selectedSuggestion < $scope.searchResults.length - 1) {
                    $scope.selectedSuggestion += 1;
                }
                $event.preventDefault();
            } else if ($event.keyCode === 13) {
                var sr = $scope.searchResults[$scope.selectedSuggestion];
                $scope.select(sr);
            }

        };

        $scope.hideAutoComplete = function(task) {
            task.__autocomplete = false;
            $scope.searchResults.length = 0;
            $scope.selectedSuggestion = 0;
        };

        // infinite scroll
        $timeout(function() {
            $scope.displayLimit = Math.ceil($element.height() / 50);
            $scope.isLoading = false;
        }, 0);

        $scope.loadMore = function() {
            if (!$scope.isLoading && $scope.loadNext) {
                $scope.isLoading = true;
                $scope.loadNext().then(function(tasks) {
                    var offset = $scope.displayOnly ? 0 : 1;

                    if (tasks.data.length) {
                        var index = $scope.tasks.length - offset;
                        var args = [index, 0].concat(tasks.data);

                        [].splice.apply($scope.tasks, args);
                    }

                    $scope.loadNext = tasks.next;
                    $scope.loadPrev = tasks.prev;
                    $scope.isLoading = false;
                });
            }
        };
    }

    return {
        restrict: 'A',
        templateUrl: '/icu/components/task-list-directive/task-list.directive.template.html',
        scope: {
            tasks: '=',
            loadNext: '=',
            loadPrev: '=',
            drawArrow: '=',
            groupTasks: '=',
            order: '=',
            displayOnly: '=',
            autocomplete: '='
        },
        link: link,
        controller: controller
    };
});
<commit_msg>remove focuse in focusAutoComplete<commit_after>'use strict';

angular.module('mean.icu.ui.tasklistdirective', [])
.directive('icuTaskList', function ($state, $uiViewScroll, $stateParams, $timeout, context, UsersService) {
        var creatingStatuses = {
            NotCreated: 0,
            Creating: 1,
            Created: 2
        };

        function controller($scope, TasksService) {
        $scope.context = context;
        $scope.isLoading = true;

        _($scope.tasks).each(function(t) {
            t.__state = creatingStatuses.Created;
        });

            var newTask = {
            title: '',
            watchers: [],
            tags: [],
            __state: creatingStatuses.NotCreated,
            __autocomplete: true
        };

        if (!$scope.displayOnly) {
            if (context.entityName === 'my'){
                UsersService.getMe().then(function (me) {
                    newTask.assign = me._id;
                    $scope.tasks.push(_(newTask).clone());
                });
            }
            else
                $scope.tasks.push(_(newTask).clone());
        }

        if (context.entityName === 'all') {
        	$scope.detailsState = 'main.tasks.all.details';
        } else if (context.entityName === 'my') {
        	$scope.detailsState = 'main.tasks.byassign.details';
        } else {
        	$scope.detailsState = 'main.tasks.byentity.details';
        }

        $scope.createOrUpdate = function(task) {
            if (context.entityName !== 'all') {
                task[context.entityName] = context.entity;
            }

            if (task.__state === creatingStatuses.NotCreated) {
                task.__state = creatingStatuses.Creating;

                return TasksService.create(task).then(function(result) {
                    task.__state = creatingStatuses.Created;

                    $scope.tasks.push(_(newTask).clone());

                    return task;
                });
            } else if (task.__state === creatingStatuses.Created) {
                return TasksService.update(task);
            }
        };
        $scope.debouncedUpdate = _.debounce($scope.createOrUpdate, 300);

        $scope.searchResults = [];

        $scope.search = function(task) {
            if (context.entityName !== 'discussion') {
                return;
            }

            if (!task.__autocomplete) {
                return;
            }

            var term = task.title;
            if (!term) {
                return;
            }

            $scope.searchResults.length = 0;
            $scope.selectedSuggestion = 0;
            TasksService.search(term).then(function(searchResults) {
                _(searchResults).each(function(sr) {
                    var alreadyAdded = _($scope.tasks).any(function(t) {
                        return t._id === sr._id;
                    });

                    if (!alreadyAdded) {
                        $scope.searchResults.push(sr);
                    }
                });
                $scope.selectedSuggestion = 0;
            });
        };

        $scope.select = function(selectedTask) {
            var currentTask = _($scope.tasks).find(function(t) {
                return t.__autocomplete;
            });

            TasksService.remove(currentTask._id);

            _(currentTask).assign(selectedTask);
            currentTask.__autocomplete = false;

            $scope.searchResults.length = 0;
            $scope.selectedSuggestion = 0;

            $scope.createOrUpdate(currentTask).then(function(task) {
                $state.go('main.tasks.byentity.details', {
                    id: task._id,
                    entity: context.entityName,
                    entityId: context.entityId
                });
            });
        };

    }

    function link($scope, $element) {
        var isScrolled = false;

        $scope.initialize = function($event, task) {
            if ($scope.displayOnly) {
                return;
            }

            var nameFocused = angular.element($event.target).hasClass('name');

            if (task.__state === creatingStatuses.NotCreated) {
                $scope.createOrUpdate(task).then(function() {
                    $state.go($scope.detailsState, {
                        id: task._id,
                        entity: context.entityName,
                        entityId: context.entityId,
                        nameFocused: nameFocused
                    });
                });
            } else {
                $state.go($scope.detailsState, {
                    id: task._id,
                    entity: context.entityName,
                    entityId: context.entityId,
                    nameFocused: nameFocused
                });
            }
        };

        $scope.isCurrentState = function (id) {
            var isActive = ($state.current.name.indexOf('main.tasks.byentity.details') === 0 ||
                            $state.current.name.indexOf('main.tasks.all.details') === 0
                       ) && $state.params.id === id;

            if (isActive && !isScrolled) {
                $uiViewScroll($element.find('[data-id="' + $stateParams.id + '"]'));
                isScrolled = true;
            }

            return isActive;
        };

        $scope.onEnter = function($event, index) {
            // if ($event.keyCode === 13 || $event.keyCode === 9) {
            //     $event.preventDefault();

            //     $scope.tasks[index].__autocomplete = false;
            //     if ($element.find('td.name')[index+1]) $element.find('td.name')[index+1].focus();
            //     else {
            //     	$timeout(function() {
			//             $element.find('td.name')[index+1].focus();
			//         }, 500);
            //     }

            // }
        };

        $scope.focusAutoComplete = function($event) {
            angular.element($event.target).css('box-shadow', 'none')
            if ($event.keyCode === 38) {
                if ($scope.selectedSuggestion > 0) {
                    $scope.selectedSuggestion -= 1;
                }
                $event.preventDefault();
            } else if ($event.keyCode === 40) {
                if ($scope.selectedSuggestion < $scope.searchResults.length - 1) {
                    $scope.selectedSuggestion += 1;
                }
                $event.preventDefault();
            } else if ($event.keyCode === 13) {
                var sr = $scope.searchResults[$scope.selectedSuggestion];
                $scope.select(sr);
            }

        };

        $scope.hideAutoComplete = function(task) {
            task.__autocomplete = false;
            $scope.searchResults.length = 0;
            $scope.selectedSuggestion = 0;
        };

        // infinite scroll
        $timeout(function() {
            $scope.displayLimit = Math.ceil($element.height() / 50);
            $scope.isLoading = false;
        }, 0);

        $scope.loadMore = function() {
            if (!$scope.isLoading && $scope.loadNext) {
                $scope.isLoading = true;
                $scope.loadNext().then(function(tasks) {
                    var offset = $scope.displayOnly ? 0 : 1;

                    if (tasks.data.length) {
                        var index = $scope.tasks.length - offset;
                        var args = [index, 0].concat(tasks.data);

                        [].splice.apply($scope.tasks, args);
                    }

                    $scope.loadNext = tasks.next;
                    $scope.loadPrev = tasks.prev;
                    $scope.isLoading = false;
                });
            }
        };
    }

    return {
        restrict: 'A',
        templateUrl: '/icu/components/task-list-directive/task-list.directive.template.html',
        scope: {
            tasks: '=',
            loadNext: '=',
            loadPrev: '=',
            drawArrow: '=',
            groupTasks: '=',
            order: '=',
            displayOnly: '=',
            autocomplete: '='
        },
        link: link,
        controller: controller
    };
});
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 Vanderbilt University, All rights reserved.
 *
 * Author: Robert Kereskenyi
 *
 * This file contains the core functionality for getting
 * and rendering the svg
 */

"use strict";

define(['js/Constants',
        'js/NodePropertyNames',
        'js/RegistryKeys',
        'js/Utils/DisplayFormat',
        'js/Decorators/DecoratorWithPorts.Base',
        'js/Widgets/DiagramDesigner/DiagramDesignerWidget.Constants',
        'text!./default.svg'], function (CONSTANTS,
                                         nodePropertyNames,
                                         REGISTRY_KEYS,
                                         displayFormat,
                                         DecoratorBase,
                                         DiagramDesignerWidgetConstants,
                                         DefaultSvgTemplate) {

    var SVGDecoratorCore,
        ABSTRACT_CLASS = 'abstract',
        SVG_DIR = CONSTANTS.ASSETS_DECORATOR_SVG_FOLDER,
        FILL_COLOR_CLASS = "fill-color",
        BORDER_COLOR_CLASS = "border-color",
        TEXT_COLOR_CLASS = "text-color",
        DEFAULT_SVG_DEFAULT_HEIGHT = 50;

    /**
     * Contains downloaded svg elements from the server.
     * @type {{}}
     * @private
     */
    //var svgCache = {};

    /**
     * Svg element that can be used as a placeholder for the icon if the icon does not exist on the server.
     * @type {*|jQuery}
     * @private
     */
    var defaultSVG = $(DefaultSvgTemplate);

    SVGDecoratorCore = function () {
        DecoratorBase.apply(this, []);
    };

    _.extend(SVGDecoratorCore.prototype, DecoratorBase.prototype);

    SVGDecoratorCore.prototype._initializeVariables = function (params) {
        this.name = "";
        this.formattedName = "";
        this.$name = undefined;

        //Get custom data from svg
        if (params.data){
            this.customData = [];
            //list of data to retrieve
            var i = params.data.length;

            while (i--){
                if (this[params.data[i]] === undefined){//Don't overwrite anything meaningful
                    //add params.data to custom params.data list to retrieve from svg
                    this.customData.push(params.data[i]);
                    this[params.data[i]] = null;
                }
            }
        }

        this.svgCache = {};
    };

    /**** Override from *.WidgetDecoratorBase ****/
    SVGDecoratorCore.prototype.doSearch = function (searchDesc) {
        var searchText = searchDesc.toString().toLowerCase();

        return (this.formattedName && this.formattedName.toLowerCase().indexOf(searchText) !== -1);
    };

    SVGDecoratorCore.prototype._renderContent = function () {
        //render GME-ID in the DOM, for debugging
        this.$el.attr({"data-id": this._metaInfo[CONSTANTS.GME_ID]});

        /* BUILD UI*/
        //find placeholders
        this.$name = this.$el.find(".name");
        this.$svgContent = this.$el.find(".svg-content");

		this._update();
    };

	SVGDecoratorCore.prototype._update = function () {
        this._updateSVGFile();
        this._updateColors();
        this._updateName();
        this._updateAbstract();
        this._updatePorts();//Will be overridden by ports class if extended
    };

    SVGDecoratorCore.prototype._updateColors = function () {
        var svg = this.$svgElement,
            fillColorElements = svg.find('.' + FILL_COLOR_CLASS),
            borderColorElements = svg.find('.' + BORDER_COLOR_CLASS),
            textColorElements = svg.find('.' + TEXT_COLOR_CLASS);

        this._getNodeColorsFromRegistry();

        if (this.fillColor) {
            fillColorElements.css({'fill': this.fillColor});
        } else {
            fillColorElements.css({'fill': ''});
        }

        if (this.borderColor) {
            borderColorElements.css({'stroke': this.borderColor});
        } else {
            borderColorElements.css({'stroke': ''});
        }

        if (this.textColor) {
            this.$el.css({'color': this.textColor});
            textColorElements.css({'fill': this.textColor});
        } else {
            this.$el.css({'color': ''});
            textColorElements.css({'fill': ''});
        }
    };

    SVGDecoratorCore.prototype._getNodeColorsFromRegistry = function () {
        var objID = this._metaInfo[CONSTANTS.GME_ID];
        this.fillColor = this.preferencesHelper.getRegistry(objID, REGISTRY_KEYS.COLOR, true);
        this.borderColor = this.preferencesHelper.getRegistry(objID, REGISTRY_KEYS.BORDER_COLOR, true);
        this.textColor = this.preferencesHelper.getRegistry(objID, REGISTRY_KEYS.TEXT_COLOR, true);
    };

    /***** UPDATE THE NAME OF THE NODE *****/
    SVGDecoratorCore.prototype._updateName = function () {
        var client = this._control._client,
            nodeObj = client.getNode(this._metaInfo[CONSTANTS.GME_ID]),
            noName = "(N/A)";

        if (nodeObj) {
            this.name = nodeObj.getAttribute(nodePropertyNames.Attributes.name);
            this.formattedName = displayFormat.resolve(nodeObj);
        } else {
            this.name = "";
            this.formattedName = noName;
        }

        this.$name.text(this.formattedName);
        this.$name.attr("title", this.formattedName);
    };

    /***** UPDATE THE ABSTRACTNESS OF THE NODE *****/
    SVGDecoratorCore.prototype._updateAbstract = function () {
        var client = this._control._client,
            nodeObj = client.getNode(this._metaInfo[CONSTANTS.GME_ID]);

        if (nodeObj) {
            if (nodeObj.getRegistry(REGISTRY_KEYS.IS_ABSTRACT) === true) {
                this.$el.addClass(ABSTRACT_CLASS);
            } else {
                this.$el.removeClass(ABSTRACT_CLASS);
            }
        } else {
            this.$el.removeClass(ABSTRACT_CLASS);
        }
    };

    /***** UPDATE THE SVG ICON OF THE NODE *****/
    SVGDecoratorCore.prototype._updateSVGFile = function () {
        var client = this._control._client,
            nodeObj = client.getNode(this._metaInfo[CONSTANTS.GME_ID]),
            svgFile = "",
            svgURL,
            self = this,
            logger = this.logger;

        if (nodeObj) {
            svgFile = nodeObj.getRegistry(REGISTRY_KEYS.SVG_ICON);
        }

        if (svgFile) {
            if (this._SVGFile !== svgFile) {
                if (this.svgCache[svgFile]) {
                    this._updateSVGContent(svgFile);
                } else {
                    // get the svg from the server in SYNC mode, may take some time
                    svgURL = SVG_DIR + svgFile;
                    $.ajax(svgURL, {'async': false})
                        .done(function ( data ) {
                            // downloaded successfully
                            // cache the content if valid
                            var svgElements = $(data).find('svg');
                            if (svgElements.length > 0) {
                                self.svgCache[svgFile] = { 'el': svgElements.first(),
                                                      'customConnectionAreas': undefined};
                                self._discoverCustomConnectionAreas(svgFile);
                                self._getCustomDataFromSvg(svgFile);
                                self.processCustomSvgData();
                                self._updateSVGContent(svgFile);
                            } else {
                                self._updateSVGContent(undefined);
                            }
                        })
                        .fail(function () {
                            // download failed for this type
                            logger.error('Failed to download SVG file: ' + svgFile);
                            self._updateSVGContent(svgFile);
                        });
                }
                this._SVGFile = svgFile;
            }
        } else {
            if (svgFile !== "") {
                logger.error('Invalid SVG file: "' + svgFile + '"');
                this._updateSVGContent(undefined);
            } else {
                this._updateSVGContent('');
            }
        }
    };

    SVGDecoratorCore.prototype._updateSVGContent = function (svg) {
        var svgIcon;
        //set new content
        this.$svgContent.empty();

        //remove existing connectors (if any)
        this.$el.find('> .' + DiagramDesignerWidgetConstants.CONNECTOR_CLASS).remove();

        this._defaultSVGUsed = false;

        if (this.svgCache[svg]) {
            svgIcon = this.svgCache[svg].el.clone();
        } else {
            svgIcon = defaultSVG.clone();
            if (svg !== '') {
                $(svgIcon.find('text')).html('!!! ' + svg + ' !!!');
            } else {
                this._defaultSVGUsed = true;
            }

        }

        this.$svgElement = svgIcon;
        this._getCustomConnectionAreas(svg);
        this._generateConnectors();

        this.$svgContent.append(svgIcon);
    };

    SVGDecoratorCore.prototype._getCustomDataFromSvg = function (svgFile) {
        //Remove custom data from svg and store it appropriately
        if (this.customData){
            var i = this.customData.length,
                customDataName,
                svgElement = this.svgCache[svgFile].el,
                k;

            while (i--){
                customDataName = this.customData[i];
                this[customDataName] = svgElement.find('.' + customDataName);
                k = this[customDataName].length;
                while (k--){
                    this[customDataName][k].remove();
                }
            }
        }
    };

    SVGDecoratorCore.prototype.processCustomSvgData = function () {
        //OVERRIDE
    };

    SVGDecoratorCore.prototype.getSVGCustomData = function (dataName) {
        var result = null;
        if (this.customData && this.customData.indexOf(dataName) !== -1){
            if (this[dataName] instanceof Array){
                result = this[dataName].slice();
            } else if (this[dataName] instanceof Object){
                result = _.extend({}, this[dataName]);
            }
        }
        return result;
    };

    /***** FUNCTIONS TO OVERRIDE *****/

    SVGDecoratorCore.prototype._updateExtras = function () {
        //Can be overridden for custom functionality
    };

    /***** PORT FUNCTIONALITY *****/
    //Overridden in SVGDecorator.Ports.js
    SVGDecoratorCore.prototype._updatePorts = function () {
        //If no ports in model, does nothing
    };

    SVGDecoratorCore.prototype._fixPortContainerPosition = function () {
        //If no ports in model, does nothing
    };

    /***** CONNECTION FUNCTIONALITY *****/
    //Overridden in SVGDecorator.Connection.js
    SVGDecoratorCore.prototype._discoverCustomConnectionAreas = function () {
        //If no connections in model, does nothing
    };

    SVGDecoratorCore.prototype._getCustomConnectionAreas = function () {
        //If no connections in model, does nothing
    };

    //Overridden in SVGDecorator.Connection.js
    SVGDecoratorCore.prototype._generateConnectors = function () {
        //If no connections in model, does nothing
    };

    return SVGDecoratorCore;
});
<commit_msg>Updated syntax<commit_after>/*globals define,_*/
/*
 * Copyright (C) 2013 Vanderbilt University, All rights reserved.
 *
 * @author rkereskenyi / https://github/rkereskenyi
 *
 * This file contains the core functionality for getting
 * and rendering the svg
 */

"use strict";

define(['js/Constants',
        'js/NodePropertyNames',
        'js/RegistryKeys',
        'js/Utils/DisplayFormat',
        'js/Decorators/DecoratorWithPorts.Base',
        'js/Widgets/DiagramDesigner/DiagramDesignerWidget.Constants',
        'text!./default.svg'], function (CONSTANTS,
                                         nodePropertyNames,
                                         REGISTRY_KEYS,
                                         displayFormat,
                                         DecoratorBase,
                                         DiagramDesignerWidgetConstants,
                                         DefaultSvgTemplate) {

    var SVGDecoratorCore,
        ABSTRACT_CLASS = 'abstract',
        SVG_DIR = CONSTANTS.ASSETS_DECORATOR_SVG_FOLDER,
        FILL_COLOR_CLASS = "fill-color",
        BORDER_COLOR_CLASS = "border-color",
        TEXT_COLOR_CLASS = "text-color",
        DEFAULT_SVG_DEFAULT_HEIGHT = 50;

    /**
     * Contains downloaded svg elements from the server.
     * @type {{}}
     * @private
     */
    //var svgCache = {};

    /**
     * Svg element that can be used as a placeholder for the icon if the icon does not exist on the server.
     * @type {*|jQuery}
     * @private
     */
    var defaultSVG = $(DefaultSvgTemplate);

    SVGDecoratorCore = function () {
        DecoratorBase.apply(this, []);
    };

    _.extend(SVGDecoratorCore.prototype, DecoratorBase.prototype);

    SVGDecoratorCore.prototype._initializeVariables = function (params) {
        this.name = "";
        this.formattedName = "";
        this.$name = undefined;

        //Get custom data from svg
        if (params.data){
            this.customData = [];
            //list of data to retrieve
            var i = params.data.length;

            while (i--){
                if (this[params.data[i]] === undefined){//Don't overwrite anything meaningful
                    //add params.data to custom params.data list to retrieve from svg
                    this.customData.push(params.data[i]);
                    this[params.data[i]] = null;
                }
            }
        }

        this.svgCache = {};
    };

    /**** Override from *.WidgetDecoratorBase ****/
    SVGDecoratorCore.prototype.doSearch = function (searchDesc) {
        var searchText = searchDesc.toString().toLowerCase();

        return (this.formattedName && this.formattedName.toLowerCase().indexOf(searchText) !== -1);
    };

    SVGDecoratorCore.prototype._renderContent = function () {
        //render GME-ID in the DOM, for debugging
        this.$el.attr({"data-id": this._metaInfo[CONSTANTS.GME_ID]});

        /* BUILD UI*/
        //find placeholders
        this.$name = this.$el.find(".name");
        this.$svgContent = this.$el.find(".svg-content");

		this._update();
    };

	SVGDecoratorCore.prototype._update = function () {
        this._updateSVGFile();
        this._updateColors();
        this._updateName();
        this._updateAbstract();
        this._updatePorts();//Will be overridden by ports class if extended
    };

    SVGDecoratorCore.prototype._updateColors = function () {
        var svg = this.$svgElement,
            fillColorElements = svg.find('.' + FILL_COLOR_CLASS),
            borderColorElements = svg.find('.' + BORDER_COLOR_CLASS),
            textColorElements = svg.find('.' + TEXT_COLOR_CLASS);

        this._getNodeColorsFromRegistry();

        if (this.fillColor) {
            fillColorElements.css({'fill': this.fillColor});
        } else {
            fillColorElements.css({'fill': ''});
        }

        if (this.borderColor) {
            borderColorElements.css({'stroke': this.borderColor});
        } else {
            borderColorElements.css({'stroke': ''});
        }

        if (this.textColor) {
            this.$el.css({'color': this.textColor});
            textColorElements.css({'fill': this.textColor});
        } else {
            this.$el.css({'color': ''});
            textColorElements.css({'fill': ''});
        }
    };

    SVGDecoratorCore.prototype._getNodeColorsFromRegistry = function () {
        var objID = this._metaInfo[CONSTANTS.GME_ID];
        this.fillColor = this.preferencesHelper.getRegistry(objID, REGISTRY_KEYS.COLOR, true);
        this.borderColor = this.preferencesHelper.getRegistry(objID, REGISTRY_KEYS.BORDER_COLOR, true);
        this.textColor = this.preferencesHelper.getRegistry(objID, REGISTRY_KEYS.TEXT_COLOR, true);
    };

    /***** UPDATE THE NAME OF THE NODE *****/
    SVGDecoratorCore.prototype._updateName = function () {
        var client = this._control._client,
            nodeObj = client.getNode(this._metaInfo[CONSTANTS.GME_ID]),
            noName = "(N/A)";

        if (nodeObj) {
            this.name = nodeObj.getAttribute(nodePropertyNames.Attributes.name);
            this.formattedName = displayFormat.resolve(nodeObj);
        } else {
            this.name = "";
            this.formattedName = noName;
        }

        this.$name.text(this.formattedName);
        this.$name.attr("title", this.formattedName);
    };

    /***** UPDATE THE ABSTRACTNESS OF THE NODE *****/
    SVGDecoratorCore.prototype._updateAbstract = function () {
        var client = this._control._client,
            nodeObj = client.getNode(this._metaInfo[CONSTANTS.GME_ID]);

        if (nodeObj) {
            if (nodeObj.getRegistry(REGISTRY_KEYS.IS_ABSTRACT) === true) {
                this.$el.addClass(ABSTRACT_CLASS);
            } else {
                this.$el.removeClass(ABSTRACT_CLASS);
            }
        } else {
            this.$el.removeClass(ABSTRACT_CLASS);
        }
    };

    /***** UPDATE THE SVG ICON OF THE NODE *****/
    SVGDecoratorCore.prototype._updateSVGFile = function () {
        var client = this._control._client,
            nodeObj = client.getNode(this._metaInfo[CONSTANTS.GME_ID]),
            svgFile = "",
            svgURL,
            self = this,
            logger = this.logger;

        if (nodeObj) {
            svgFile = nodeObj.getRegistry(REGISTRY_KEYS.SVG_ICON);
        }

        if (svgFile) {
            if (this._SVGFile !== svgFile) {
                if (this.svgCache[svgFile]) {
                    this._updateSVGContent(svgFile);
                } else {
                    // get the svg from the server in SYNC mode, may take some time
                    svgURL = SVG_DIR + svgFile;
                    $.ajax(svgURL, {'async': false})
                        .done(function ( data ) {
                            // downloaded successfully
                            // cache the content if valid
                            var svgElements = $(data).find('svg');
                            if (svgElements.length > 0) {
                                self.svgCache[svgFile] = { 'el': svgElements.first(),
                                                      'customConnectionAreas': undefined};
                                self._discoverCustomConnectionAreas(svgFile);
                                self._getCustomDataFromSvg(svgFile);
                                self.processCustomSvgData();
                                self._updateSVGContent(svgFile);
                            } else {
                                self._updateSVGContent(undefined);
                            }
                        })
                        .fail(function () {
                            // download failed for this type
                            logger.error('Failed to download SVG file: ' + svgFile);
                            self._updateSVGContent(svgFile);
                        });
                }
                this._SVGFile = svgFile;
            }
        } else {
            if (svgFile !== "") {
                logger.error('Invalid SVG file: "' + svgFile + '"');
                this._updateSVGContent(undefined);
            } else {
                this._updateSVGContent('');
            }
        }
    };

    SVGDecoratorCore.prototype._updateSVGContent = function (svg) {
        var svgIcon;
        //set new content
        this.$svgContent.empty();

        //remove existing connectors (if any)
        this.$el.find('> .' + DiagramDesignerWidgetConstants.CONNECTOR_CLASS).remove();

        this._defaultSVGUsed = false;

        if (this.svgCache[svg]) {
            svgIcon = this.svgCache[svg].el.clone();
        } else {
            svgIcon = defaultSVG.clone();
            if (svg !== '') {
                $(svgIcon.find('text')).html('!!! ' + svg + ' !!!');
            } else {
                this._defaultSVGUsed = true;
            }

        }

        this.$svgElement = svgIcon;
        this._getCustomConnectionAreas(svg);
        this._generateConnectors();

        this.$svgContent.append(svgIcon);
    };

    SVGDecoratorCore.prototype._getCustomDataFromSvg = function (svgFile) {
        //Remove custom data from svg and store it appropriately
        if (this.customData){
            var i = this.customData.length,
                customDataName,
                svgElement = this.svgCache[svgFile].el,
                k;

            while (i--){
                customDataName = this.customData[i];
                this[customDataName] = svgElement.find('.' + customDataName);
                k = this[customDataName].length;
                while (k--){
                    this[customDataName][k].remove();
                }
            }
        }
    };

    SVGDecoratorCore.prototype.processCustomSvgData = function () {
        //OVERRIDE
    };

    SVGDecoratorCore.prototype.getSVGCustomData = function (dataName) {
        var result = null;
        if (this.customData && this.customData.indexOf(dataName) !== -1){
            if (this[dataName] instanceof Array){
                result = this[dataName].slice();
            } else if (this[dataName] instanceof Object){
                result = _.extend({}, this[dataName]);
            }
        }
        return result;
    };

    /***** FUNCTIONS TO OVERRIDE *****/

    SVGDecoratorCore.prototype._updateExtras = function () {
        //Can be overridden for custom functionality
    };

    /***** PORT FUNCTIONALITY *****/
    //Overridden in SVGDecorator.Ports.js
    SVGDecoratorCore.prototype._updatePorts = function () {
        //If no ports in model, does nothing
    };

    SVGDecoratorCore.prototype._fixPortContainerPosition = function () {
        //If no ports in model, does nothing
    };

    /***** CONNECTION FUNCTIONALITY *****/
    //Overridden in SVGDecorator.Connection.js
    SVGDecoratorCore.prototype._discoverCustomConnectionAreas = function () {
        //If no connections in model, does nothing
    };

    SVGDecoratorCore.prototype._getCustomConnectionAreas = function () {
        //If no connections in model, does nothing
    };

    //Overridden in SVGDecorator.Connection.js
    SVGDecoratorCore.prototype._generateConnectors = function () {
        //If no connections in model, does nothing
    };

    return SVGDecoratorCore;
});
<|endoftext|>


<commit_before>import {createSelector} from 'reselect';
import moment from 'moment';
import {filterSync} from '@ciscospark/helper-html';
import {
  ITEM_TYPE_ACTIVITY,
  ITEM_TYPE_DAY_SEPARATOR,
  ITEM_TYPE_NEW_MESSAGE_SEPARATOR
} from '@ciscospark/react-component-activity-list';

import defaultFormatters from './formatters';
import {isActivityVisible} from './helpers';

const getConversationActivities = (state) => state.conversation.get('activities');
const getAvatar = (state) => state.avatar;
const getUsers = (state) => state.users;
const getFlags = (state) => state.flags.get('flags');
const getSendingActivities = (state) => state.activity;
const getActivityFormatter = (state, props) => props.activityFormatter;
const getLastAcknowledgedActivityId = (state) => state.conversation.get('lastAcknowledgedActivityId');
const getOnEvent = (state, props) => props.onEvent;

/**
 * Applies safe filters activity content
 *
 * @param {Object} activityObject raw activity.object
 * @returns {Object}
 */

export function filterActivity(activityObject) {
  const outputActivity = Object.assign({}, activityObject);

  if (outputActivity.content) {
    outputActivity.content = filterSync(() => {}, {
      'spark-mention': ['data-object-type', 'data-object-id', 'data-object-url'],
      a: ['href'],
      b: [],
      blockquote: ['class'],
      strong: [],
      i: [],
      em: [],
      pre: [],
      code: ['class'],
      br: [],
      hr: [],
      p: [],
      ul: [],
      ol: [],
      li: [],
      h1: [],
      h2: [],
      h3: [],
      h4: [],
      h5: [],
      h6: []
    }, [], outputActivity.content);
  }

  return outputActivity;
}

/**
 * Applies additional formatting to activity
 *
 * @export
 * @param {Object} activityObject
 * @returns {Object}
 */

export function formatActivity(activity, activityFormatter, onEvent) {
  const activityObject = filterActivity(activity);

  if (typeof activityFormatter === 'function') {
    return activityFormatter(activityObject, defaultFormatters, onEvent);
  }

  return defaultFormatters(activityObject, onEvent);
}

/**
 * This loops through our conversation activities and computes an array
 * of 'visible activities' to be used with the ActivityList component
 */
export const getActivityList = createSelector(
  [
    getConversationActivities,
    getAvatar,
    getUsers,
    getSendingActivities,
    getFlags,
    getLastAcknowledgedActivityId,
    getActivityFormatter,
    getOnEvent
  ],
  (
    conversationActivities,
    avatar,
    users,
    sendingActivities,
    flags,
    lastAcknowledgedActivityId,
    activityFormatter,
    onEvent
  ) => {
    const avatars = avatar.get('items');
    const currentUser = users.getIn(['byId', users.get('currentUserId')]);
    const inFlightActivities = sendingActivities.get('inFlightActivities');
    const activityFailures = sendingActivities.get('activityFailures');
    const visibleActivityList = [];
    const now = moment();
    let lastActorId, lastDay, lastMinute, lastVerb;
    let shouldDisplayNewMessageMarker = false;

    conversationActivities.forEach((activity) => {
      if (isActivityVisible(activity)) {
        // Insert day separator if this activity and last one happen on a different day
        const activityDay = moment(activity.published, moment.ISO_8601).endOf('day');
        const activityMinute = moment(activity.published, moment.ISO_8601).endOf('minute');

        const sameDay = activityDay.diff(lastDay, 'days') === 0;
        const sameMinute = activityMinute.diff(lastMinute, 'minutes') === 0;

        if (lastDay && !sameDay) {
          visibleActivityList.push({
            type: ITEM_TYPE_DAY_SEPARATOR,
            fromDate: lastDay,
            key: `day-separtor-${activity.id}`,
            now,
            toDate: activityDay
          });
        }
        lastDay = activityDay;
        lastMinute = activityMinute;

        // New message marker
        if (shouldDisplayNewMessageMarker) {
          visibleActivityList.push({
            type: ITEM_TYPE_NEW_MESSAGE_SEPARATOR,
            key: `new-messages-${activity.id}`
          });
          shouldDisplayNewMessageMarker = false;
        }

        // Actual visible activity item
        // additional items don't repeat user avatar and name
        const isAdditional = sameDay && sameMinute && lastActorId === activity.actor.id && lastVerb === activity.verb;

        lastActorId = activity.actor.id;
        lastVerb = activity.verb;

        const isFlagged = !!flags.count() && flags.has(activity.url);
        const isFlagPending = isFlagged && flags.getIn([activity.url, 'isInFlight']);

        let formattedActivity = activity;

        if (activity.verb === 'post') {
          formattedActivity = Object.assign({}, activity, {
            object: formatActivity(activity.object, activityFormatter, onEvent)
          });
        }

        // Name of the user
        let name = activity.actor.displayName;

        if (activity.verb === 'add' || activity.verb === 'leave') {
          name = activity.object.displayName;
        }

        const visibleActivity = {
          currentUser,
          type: ITEM_TYPE_ACTIVITY,
          activity: formattedActivity,
          avatarUrl: avatars.get(activity.actor.id),
          isAdditional,
          isFlagged,
          isFlagPending,
          isSelf: currentUser.id === activity.actor.id,
          name
        };

        visibleActivityList.push(visibleActivity);

        // Check if this is the last read activity
        const isLastAcked = lastAcknowledgedActivityId && lastAcknowledgedActivityId === activity.id;
        const isNotSelf = currentUser.id !== activity.actor.id;

        if (isLastAcked && isNotSelf) {
          shouldDisplayNewMessageMarker = true;
        }
      }
    });

    // Create a "fake" activity to display in flight activities
    inFlightActivities.forEach((inFlightActivity) => {
      visibleActivityList.push({
        currentUser,
        type: ITEM_TYPE_ACTIVITY,
        activity: inFlightActivity,
        avatarUrl: avatars.get(currentUser.id),
        isAdditional: false,
        isFlagged: false,
        isFlagPending: false,
        isSelf: true,
        isPending: true
      });
    });

    // Create a "fake" activity to display failed activities
    activityFailures.forEach((activityFailure) => {
      visibleActivityList.push({
        currentUser,
        type: ITEM_TYPE_ACTIVITY,
        activity: activityFailure,
        avatarUrl: avatars.get(currentUser.id),
        isAdditional: false,
        hasError: true,
        isFlagged: false,
        isFlagPending: false,
        isSelf: true,
        isPending: true
      });
    });

    return visibleActivityList;
  }
);
<commit_msg>chore(activity-list): convert to @webex sdk<commit_after>import {createSelector} from 'reselect';
import moment from 'moment';
import {filterSync} from '@webex/helper-html';
import {
  ITEM_TYPE_ACTIVITY,
  ITEM_TYPE_DAY_SEPARATOR,
  ITEM_TYPE_NEW_MESSAGE_SEPARATOR
} from '@ciscospark/react-component-activity-list';

import defaultFormatters from './formatters';
import {isActivityVisible} from './helpers';

const getConversationActivities = (state) => state.conversation.get('activities');
const getAvatar = (state) => state.avatar;
const getUsers = (state) => state.users;
const getFlags = (state) => state.flags.get('flags');
const getSendingActivities = (state) => state.activity;
const getActivityFormatter = (state, props) => props.activityFormatter;
const getLastAcknowledgedActivityId = (state) => state.conversation.get('lastAcknowledgedActivityId');
const getOnEvent = (state, props) => props.onEvent;

/**
 * Applies safe filters activity content
 *
 * @param {Object} activityObject raw activity.object
 * @returns {Object}
 */

export function filterActivity(activityObject) {
  const outputActivity = Object.assign({}, activityObject);

  if (outputActivity.content) {
    outputActivity.content = filterSync(() => {}, {
      'spark-mention': ['data-object-type', 'data-object-id', 'data-object-url'],
      a: ['href'],
      b: [],
      blockquote: ['class'],
      strong: [],
      i: [],
      em: [],
      pre: [],
      code: ['class'],
      br: [],
      hr: [],
      p: [],
      ul: [],
      ol: [],
      li: [],
      h1: [],
      h2: [],
      h3: [],
      h4: [],
      h5: [],
      h6: []
    }, [], outputActivity.content);
  }

  return outputActivity;
}

/**
 * Applies additional formatting to activity
 *
 * @export
 * @param {Object} activityObject
 * @returns {Object}
 */

export function formatActivity(activity, activityFormatter, onEvent) {
  const activityObject = filterActivity(activity);

  if (typeof activityFormatter === 'function') {
    return activityFormatter(activityObject, defaultFormatters, onEvent);
  }

  return defaultFormatters(activityObject, onEvent);
}

/**
 * This loops through our conversation activities and computes an array
 * of 'visible activities' to be used with the ActivityList component
 */
export const getActivityList = createSelector(
  [
    getConversationActivities,
    getAvatar,
    getUsers,
    getSendingActivities,
    getFlags,
    getLastAcknowledgedActivityId,
    getActivityFormatter,
    getOnEvent
  ],
  (
    conversationActivities,
    avatar,
    users,
    sendingActivities,
    flags,
    lastAcknowledgedActivityId,
    activityFormatter,
    onEvent
  ) => {
    const avatars = avatar.get('items');
    const currentUser = users.getIn(['byId', users.get('currentUserId')]);
    const inFlightActivities = sendingActivities.get('inFlightActivities');
    const activityFailures = sendingActivities.get('activityFailures');
    const visibleActivityList = [];
    const now = moment();
    let lastActorId, lastDay, lastMinute, lastVerb;
    let shouldDisplayNewMessageMarker = false;

    conversationActivities.forEach((activity) => {
      if (isActivityVisible(activity)) {
        // Insert day separator if this activity and last one happen on a different day
        const activityDay = moment(activity.published, moment.ISO_8601).endOf('day');
        const activityMinute = moment(activity.published, moment.ISO_8601).endOf('minute');

        const sameDay = activityDay.diff(lastDay, 'days') === 0;
        const sameMinute = activityMinute.diff(lastMinute, 'minutes') === 0;

        if (lastDay && !sameDay) {
          visibleActivityList.push({
            type: ITEM_TYPE_DAY_SEPARATOR,
            fromDate: lastDay,
            key: `day-separtor-${activity.id}`,
            now,
            toDate: activityDay
          });
        }
        lastDay = activityDay;
        lastMinute = activityMinute;

        // New message marker
        if (shouldDisplayNewMessageMarker) {
          visibleActivityList.push({
            type: ITEM_TYPE_NEW_MESSAGE_SEPARATOR,
            key: `new-messages-${activity.id}`
          });
          shouldDisplayNewMessageMarker = false;
        }

        // Actual visible activity item
        // additional items don't repeat user avatar and name
        const isAdditional = sameDay && sameMinute && lastActorId === activity.actor.id && lastVerb === activity.verb;

        lastActorId = activity.actor.id;
        lastVerb = activity.verb;

        const isFlagged = !!flags.count() && flags.has(activity.url);
        const isFlagPending = isFlagged && flags.getIn([activity.url, 'isInFlight']);

        let formattedActivity = activity;

        if (activity.verb === 'post') {
          formattedActivity = Object.assign({}, activity, {
            object: formatActivity(activity.object, activityFormatter, onEvent)
          });
        }

        // Name of the user
        let name = activity.actor.displayName;

        if (activity.verb === 'add' || activity.verb === 'leave') {
          name = activity.object.displayName;
        }

        const visibleActivity = {
          currentUser,
          type: ITEM_TYPE_ACTIVITY,
          activity: formattedActivity,
          avatarUrl: avatars.get(activity.actor.id),
          isAdditional,
          isFlagged,
          isFlagPending,
          isSelf: currentUser.id === activity.actor.id,
          name
        };

        visibleActivityList.push(visibleActivity);

        // Check if this is the last read activity
        const isLastAcked = lastAcknowledgedActivityId && lastAcknowledgedActivityId === activity.id;
        const isNotSelf = currentUser.id !== activity.actor.id;

        if (isLastAcked && isNotSelf) {
          shouldDisplayNewMessageMarker = true;
        }
      }
    });

    // Create a "fake" activity to display in flight activities
    inFlightActivities.forEach((inFlightActivity) => {
      visibleActivityList.push({
        currentUser,
        type: ITEM_TYPE_ACTIVITY,
        activity: inFlightActivity,
        avatarUrl: avatars.get(currentUser.id),
        isAdditional: false,
        isFlagged: false,
        isFlagPending: false,
        isSelf: true,
        isPending: true
      });
    });

    // Create a "fake" activity to display failed activities
    activityFailures.forEach((activityFailure) => {
      visibleActivityList.push({
        currentUser,
        type: ITEM_TYPE_ACTIVITY,
        activity: activityFailure,
        avatarUrl: avatars.get(currentUser.id),
        isAdditional: false,
        hasError: true,
        isFlagged: false,
        isFlagPending: false,
        isSelf: true,
        isPending: true
      });
    });

    return visibleActivityList;
  }
);
<|endoftext|>