<commit_before>'use strict';
describe('Calendar', function() {
    // Load the module with MainController
    beforeEach(module('gantt'));

    var Calendar;
    var moment;

    var expectTimeFrameToEqual = function(actual, expected) {
        expect(expected.start).toEqual(actual.start);
        expect(expected.end).toEqual(actual.end);
        expect(expected.working).toEqual(actual.working);
        expect(expected.color).toEqual(actual.color);
        expect(expected.classes).toEqual(actual.classes);
    };

    beforeEach(inject(['GanttCalendar', 'moment', function(_Calendar_, _moment_) {
        Calendar = _Calendar_;
        moment = _moment_;
    }]));

    it('should register and use default timeFrames',
        function() {
            var cal = new Calendar();

            var inputTimeFrames = {
                'day': {
                    start: moment('9:00', 'HH:mm'),
                    end: moment('18:00', 'HH:mm'),
                    working: true,
                    default: true
                },
                'noon': {
                    start: moment('12:00', 'HH:mm'),
                    end: moment('13:30', 'HH:mm'),
                    color: 'red',
                    classes: 'noon-css',
                    working: false,
                    default: true
                },
                'dummy': {
                    start: moment('20:00', 'HH:mm'),
                    end: moment('22:30', 'HH:mm'),
                    working: false,
                    default: false
                }
            };
            cal.registerTimeFrames(inputTimeFrames);
            var timeFrames = cal.getTimeFrames(moment());

            expect(timeFrames.length).toBe(2);

            expectTimeFrameToEqual(timeFrames[0], cal.timeFrames.day);
            expectTimeFrameToEqual(timeFrames[1], cal.timeFrames.noon);
        });

    it('should use right timeFrames with given dateFrame',
        function() {
            var cal = new Calendar();

            var inputTimeFrames = {
                'day': {
                    start: moment('9:00', 'HH:mm'),
                    end: moment('18:00', 'HH:mm'),
                    working: true,
                    default: true
                },
                'noon': {
                    start: moment('12:00', 'HH:mm'),
                    end: moment('13:30', 'HH:mm'),
                    color: 'red',
                    classes: 'noon-css',
                    working: false,
                    default: true
                },
                'closed': {
                    working: false
                }
            };
            cal.registerTimeFrames(inputTimeFrames);

            // I won't work on my birthday !
            cal.registerDateFrames({
                'my-birthday': {
                    evaluator: function(date) {
                        return date.month() === 7 && date.date() === 1;
                    },
                    targets: ['closed']
                },
                'halloween': {
                    date: moment('2014-10-31', 'YYYY-MM-DD'),
                    targets: ['day']
                },
                'holidays': {
                    start: moment('2014-08-15', 'YYYY-MM-DD'),
                    end: moment('2014-08-30', 'YYYY-MM-DD'),
                    targets: ['closed']
                }
            });

            var birthdayTimeFrames = cal.getTimeFrames(moment('2014-08-01', 'YYYY-MM-DD'));
            expect(birthdayTimeFrames.length).toBe(1);
            expectTimeFrameToEqual(birthdayTimeFrames[0], cal.timeFrames.closed);

            var halloweenTimeFrames = cal.getTimeFrames(moment('2014-10-31', 'YYYY-MM-DD'));
            expect(halloweenTimeFrames.length).toBe(1);
            expectTimeFrameToEqual(halloweenTimeFrames[0], cal.timeFrames.day);

            var holidaysTimeFrames = cal.getTimeFrames(moment('2014-08-20', 'YYYY-MM-DD'));
            expect(holidaysTimeFrames.length).toBe(1);
            expectTimeFrameToEqual(holidaysTimeFrames[0], cal.timeFrames.closed);

            var defaultTimeFrames = cal.getTimeFrames(moment('2014-11-01', 'YYYY-MM-DD'));
            expectTimeFrameToEqual(defaultTimeFrames[0], cal.timeFrames.day);
            expectTimeFrameToEqual(defaultTimeFrames[1], cal.timeFrames.noon);
        });

    it('should solve timeFrames conflict',
        function() {
            var cal = new Calendar();

            var inputTimeFrames = {
                'day': {
                    start: moment('9:00', 'HH:mm'),
                    end: moment('18:00', 'HH:mm'),
                    working: true,
                    default: true
                },
                'noon': {
                    start: moment('12:00', 'HH:mm'),
                    end: moment('13:30', 'HH:mm'),
                    color: 'red',
                    classes: 'noon-css',
                    working: false,
                    default: true
                },
                'dummy': {
                    start: moment('20:00', 'HH:mm'),
                    end: moment('22:30', 'HH:mm'),
                    working: false,
                    default: false
                }
            };
            cal.registerTimeFrames(inputTimeFrames);
            var timeFrames = cal.getTimeFrames(moment());

            var startDate = moment('0:00', 'HH:mm');
            var endDate = moment(startDate).add(1, 'day');

            timeFrames = cal.solve(timeFrames, startDate, endDate);
            expect(timeFrames.length).toBe(3);

            expect(timeFrames[0].start).toEqual(cal.timeFrames.day.start);
            expect(timeFrames[0].end).toEqual(cal.timeFrames.noon.start);
            expect(timeFrames[0].working).toBeTruthy();

            expect(timeFrames[1].start).toEqual(cal.timeFrames.noon.start);
            expect(timeFrames[1].end).toEqual(cal.timeFrames.noon.end);
            expect(timeFrames[1].classes).toEqual(cal.timeFrames.noon.classes);
            expect(timeFrames[1].color).toEqual(cal.timeFrames.noon.color);
            expect(timeFrames[1].working).toBeFalsy();

            expect(timeFrames[2].start).toEqual(cal.timeFrames.noon.end);
            expect(timeFrames[2].end).toEqual(cal.timeFrames.day.end);
            expect(timeFrames[2].working).toBeTruthy();
        });

    it('should solve single open non-working timeFrame ',
        function() {
            var cal = new Calendar();

            var inputTimeFrames = {
                'closed': {
                    working: false,
                    default: true
                }
            };
            cal.registerTimeFrames(inputTimeFrames);
            var timeFrames = cal.getTimeFrames(moment());

            timeFrames = cal.solve(timeFrames);
            expect(timeFrames.length).toBe(1);

            expect(timeFrames[0].working).toBeFalsy();
        });

    it('should solve timeFrame for small timePeriod',
        function() {
            var cal = new Calendar();

            var inputTimeFrames = {
                'day': {
                    start: moment('9:00', 'HH:mm'),
                    end: moment('18:00', 'HH:mm'),
                    working: true,
                    default: true
                },
                'noon': {
                    start: moment('12:00', 'HH:mm'),
                    end: moment('13:30', 'HH:mm'),
                    color: 'red',
                    classes: 'noon-css',
                    working: false,
                    default: true
                },
                'dummy': {
                    start: moment('20:00', 'HH:mm'),
                    end: moment('22:30', 'HH:mm'),
                    working: false,
                    default: false
                }
            };
            cal.registerTimeFrames(inputTimeFrames);
            var timeFrames = cal.getTimeFrames(moment());

            timeFrames = cal.solve(timeFrames, moment('12:00', 'HH:mm'), moment('13:00', 'HH:mm'));
            expect(timeFrames.length).toBe(1);

            expect(timeFrames[0].working).toBeFalsy();
            expect(timeFrames[0].color).toBe('red');
            expect(timeFrames[0].classes).toBe('noon-css');
        });

    it('should solve nothing when nothing is registered',
        function() {
            var cal = new Calendar();
            var timeFrames = cal.getTimeFrames(moment());

            timeFrames = cal.solve(timeFrames);
            expect(timeFrames.length).toBe(0);
        });

    it('should solve timeFrames using dateFrames',
        function() {
            var cal = new Calendar();

            var inputTimeFrames = {
                'day': {
                    start: moment('8:00', 'HH:mm'),
                    end: moment('20:00', 'HH:mm'),
                    working: true,
                    default: true
                },
                'noon': {
                    start: moment('12:00', 'HH:mm'),
                    end: moment('13:30', 'HH:mm'),
                    working: false,
                    default: true
                },
                'weekend': {
                    working: false
                },
                'holiday': {
                    working: false,
                    color: 'red',
                    classes: ['gantt-timeframe-holiday']
                }
            };

            var inputDateFrames = {
                'weekend': {
                    evaluator: function(date) {
                        return date.isoWeekday() === 6 || date.isoWeekday() === 7;
                    },
                    targets: ['weekend']
                },
                '11-november': {
                    evaluator: function(date) {
                        return date.month() === 10 && date.date() === 11;
                    },
                    targets: ['holiday']
                }
            };

            cal.registerTimeFrames(inputTimeFrames);
            cal.registerDateFrames(inputDateFrames);

            var timeFrames = cal.getTimeFrames(moment().month(10).date(11));
            timeFrames = cal.solve(timeFrames);
            expect(timeFrames.length).toBe(1);

            expect(timeFrames[0].working).toBeFalsy();
            expect(timeFrames[0].color).toBe('red');
            expect(timeFrames[0].classes.length).toBe(1);
            expect(timeFrames[0].classes[0]).toBe('gantt-timeframe-holiday');

            timeFrames = cal.getTimeFrames(moment().day(6));
            timeFrames = cal.solve(timeFrames);
            expect(timeFrames.length).toBe(1);

            expect(timeFrames[0].working).toBeFalsy();
            expect(timeFrames[0].color).toBeUndefined();
            expect(timeFrames[0].classes).toBeUndefined();

            timeFrames = cal.getTimeFrames(moment().month(3).date(5).day(3));
            timeFrames = cal.solve(timeFrames);
            expect(timeFrames.length).toBe(3);
        });

    it('should solve whole day working timeFrame with night as default',
        function() {
            var cal = new Calendar();

            var inputTimeFrames = {
                'night': {
                    color: 'black',
                    working: false,
                    default: true
                },
                'day': {
                    start: moment('8:00', 'HH:mm'),
                    end: moment('20:00', 'HH:mm'),
                    color: 'blue',
                    working: true,
                    default: true
                },
                'noon': {
                    start: moment('12:00', 'HH:mm'),
                    end: moment('13:30', 'HH:mm'),
                    color: 'red',
                    working: false,
                    default: true
                },
                'weekend': {
                    working: false
                },
                'holiday': {
                    working: false,
                    color: 'red',
                    classes: ['gantt-timeframe-holiday']
                }
            };

            cal.registerTimeFrames(inputTimeFrames);

            var cDate = moment();
            var cDateStartOfDay = moment(cDate).startOf('day');
            var cDateNextDay = moment(cDateStartOfDay).add(1, 'day');

            var timeFrames = cal.getTimeFrames(cDate);
            timeFrames = cal.solve(timeFrames, cDateStartOfDay, cDateNextDay);
            expect(timeFrames.length).toBe(5);

            expect(timeFrames[0].working).toBeFalsy();
            expect(timeFrames[0].color).toBe('black');

            expect(timeFrames[1].working).toBeTruthy();
            expect(timeFrames[1].color).toBe('blue');

            expect(timeFrames[2].working).toBeFalsy();
            expect(timeFrames[2].color).toBe('red');

            expect(timeFrames[3].working).toBeTruthy();
            expect(timeFrames[3].color).toBe('blue');

            expect(timeFrames[4].working).toBeFalsy();
            expect(timeFrames[4].color).toBe('black');

        });

});
<commit_msg>test(calendar): Add demo test case in calendar factory<commit_after>'use strict';
describe('Calendar', function() {
    // Load the module with MainController
    beforeEach(module('gantt'));

    var Calendar;
    var moment;

    var expectTimeFrameToEqual = function(actual, expected) {
        expect(expected.start).toEqual(actual.start);
        expect(expected.end).toEqual(actual.end);
        expect(expected.working).toEqual(actual.working);
        expect(expected.color).toEqual(actual.color);
        expect(expected.classes).toEqual(actual.classes);
    };

    beforeEach(inject(['GanttCalendar', 'moment', function(_Calendar_, _moment_) {
        Calendar = _Calendar_;
        moment = _moment_;
    }]));

    it('should register and use default timeFrames',
        function() {
            var cal = new Calendar();

            var inputTimeFrames = {
                'day': {
                    start: moment('9:00', 'HH:mm'),
                    end: moment('18:00', 'HH:mm'),
                    working: true,
                    default: true
                },
                'noon': {
                    start: moment('12:00', 'HH:mm'),
                    end: moment('13:30', 'HH:mm'),
                    color: 'red',
                    classes: 'noon-css',
                    working: false,
                    default: true
                },
                'dummy': {
                    start: moment('20:00', 'HH:mm'),
                    end: moment('22:30', 'HH:mm'),
                    working: false,
                    default: false
                }
            };
            cal.registerTimeFrames(inputTimeFrames);
            var timeFrames = cal.getTimeFrames(moment());

            expect(timeFrames.length).toBe(2);

            expectTimeFrameToEqual(timeFrames[0], cal.timeFrames.day);
            expectTimeFrameToEqual(timeFrames[1], cal.timeFrames.noon);
        });

    it('should use right timeFrames with given dateFrame',
        function() {
            var cal = new Calendar();

            var inputTimeFrames = {
                'day': {
                    start: moment('9:00', 'HH:mm'),
                    end: moment('18:00', 'HH:mm'),
                    working: true,
                    default: true
                },
                'noon': {
                    start: moment('12:00', 'HH:mm'),
                    end: moment('13:30', 'HH:mm'),
                    color: 'red',
                    classes: 'noon-css',
                    working: false,
                    default: true
                },
                'closed': {
                    working: false
                }
            };
            cal.registerTimeFrames(inputTimeFrames);

            // I won't work on my birthday !
            cal.registerDateFrames({
                'my-birthday': {
                    evaluator: function(date) {
                        return date.month() === 7 && date.date() === 1;
                    },
                    targets: ['closed']
                },
                'halloween': {
                    date: moment('2014-10-31', 'YYYY-MM-DD'),
                    targets: ['day']
                },
                'holidays': {
                    start: moment('2014-08-15', 'YYYY-MM-DD'),
                    end: moment('2014-08-30', 'YYYY-MM-DD'),
                    targets: ['closed']
                }
            });

            var birthdayTimeFrames = cal.getTimeFrames(moment('2014-08-01', 'YYYY-MM-DD'));
            expect(birthdayTimeFrames.length).toBe(1);
            expectTimeFrameToEqual(birthdayTimeFrames[0], cal.timeFrames.closed);

            var halloweenTimeFrames = cal.getTimeFrames(moment('2014-10-31', 'YYYY-MM-DD'));
            expect(halloweenTimeFrames.length).toBe(1);
            expectTimeFrameToEqual(halloweenTimeFrames[0], cal.timeFrames.day);

            var holidaysTimeFrames = cal.getTimeFrames(moment('2014-08-20', 'YYYY-MM-DD'));
            expect(holidaysTimeFrames.length).toBe(1);
            expectTimeFrameToEqual(holidaysTimeFrames[0], cal.timeFrames.closed);

            var defaultTimeFrames = cal.getTimeFrames(moment('2014-11-01', 'YYYY-MM-DD'));
            expectTimeFrameToEqual(defaultTimeFrames[0], cal.timeFrames.day);
            expectTimeFrameToEqual(defaultTimeFrames[1], cal.timeFrames.noon);
        });

    it('should solve timeFrames conflict',
        function() {
            var cal = new Calendar();

            var inputTimeFrames = {
                'day': {
                    start: moment('9:00', 'HH:mm'),
                    end: moment('18:00', 'HH:mm'),
                    working: true,
                    default: true
                },
                'noon': {
                    start: moment('12:00', 'HH:mm'),
                    end: moment('13:30', 'HH:mm'),
                    color: 'red',
                    classes: 'noon-css',
                    working: false,
                    default: true
                },
                'dummy': {
                    start: moment('20:00', 'HH:mm'),
                    end: moment('22:30', 'HH:mm'),
                    working: false,
                    default: false
                }
            };
            cal.registerTimeFrames(inputTimeFrames);
            var timeFrames = cal.getTimeFrames(moment());

            var startDate = moment('0:00', 'HH:mm');
            var endDate = moment(startDate).add(1, 'day');

            timeFrames = cal.solve(timeFrames, startDate, endDate);
            expect(timeFrames.length).toBe(3);

            expect(timeFrames[0].start).toEqual(cal.timeFrames.day.start);
            expect(timeFrames[0].end).toEqual(cal.timeFrames.noon.start);
            expect(timeFrames[0].working).toBeTruthy();

            expect(timeFrames[1].start).toEqual(cal.timeFrames.noon.start);
            expect(timeFrames[1].end).toEqual(cal.timeFrames.noon.end);
            expect(timeFrames[1].classes).toEqual(cal.timeFrames.noon.classes);
            expect(timeFrames[1].color).toEqual(cal.timeFrames.noon.color);
            expect(timeFrames[1].working).toBeFalsy();

            expect(timeFrames[2].start).toEqual(cal.timeFrames.noon.end);
            expect(timeFrames[2].end).toEqual(cal.timeFrames.day.end);
            expect(timeFrames[2].working).toBeTruthy();
        });

    it('should solve single open non-working timeFrame ',
        function() {
            var cal = new Calendar();

            var inputTimeFrames = {
                'closed': {
                    working: false,
                    default: true
                }
            };
            cal.registerTimeFrames(inputTimeFrames);
            var timeFrames = cal.getTimeFrames(moment());

            timeFrames = cal.solve(timeFrames);
            expect(timeFrames.length).toBe(1);

            expect(timeFrames[0].working).toBeFalsy();
        });

    it('should solve timeFrame for small timePeriod',
        function() {
            var cal = new Calendar();

            var inputTimeFrames = {
                'day': {
                    start: moment('9:00', 'HH:mm'),
                    end: moment('18:00', 'HH:mm'),
                    working: true,
                    default: true
                },
                'noon': {
                    start: moment('12:00', 'HH:mm'),
                    end: moment('13:30', 'HH:mm'),
                    color: 'red',
                    classes: 'noon-css',
                    working: false,
                    default: true
                },
                'dummy': {
                    start: moment('20:00', 'HH:mm'),
                    end: moment('22:30', 'HH:mm'),
                    working: false,
                    default: false
                }
            };
            cal.registerTimeFrames(inputTimeFrames);
            var timeFrames = cal.getTimeFrames(moment());

            timeFrames = cal.solve(timeFrames, moment('12:00', 'HH:mm'), moment('13:00', 'HH:mm'));
            expect(timeFrames.length).toBe(1);

            expect(timeFrames[0].working).toBeFalsy();
            expect(timeFrames[0].color).toBe('red');
            expect(timeFrames[0].classes).toBe('noon-css');
        });

    it('should solve nothing when nothing is registered',
        function() {
            var cal = new Calendar();
            var timeFrames = cal.getTimeFrames(moment());

            timeFrames = cal.solve(timeFrames);
            expect(timeFrames.length).toBe(0);
        });

    it('should solve timeFrames using dateFrames',
        function() {
            var cal = new Calendar();

            var inputTimeFrames = {
                'day': {
                    start: moment('8:00', 'HH:mm'),
                    end: moment('20:00', 'HH:mm'),
                    working: true,
                    default: true
                },
                'noon': {
                    start: moment('12:00', 'HH:mm'),
                    end: moment('13:30', 'HH:mm'),
                    working: false,
                    default: true
                },
                'weekend': {
                    working: false
                },
                'holiday': {
                    working: false,
                    color: 'red',
                    classes: ['gantt-timeframe-holiday']
                }
            };

            var inputDateFrames = {
                'weekend': {
                    evaluator: function(date) {
                        return date.isoWeekday() === 6 || date.isoWeekday() === 7;
                    },
                    targets: ['weekend']
                },
                '11-november': {
                    evaluator: function(date) {
                        return date.month() === 10 && date.date() === 11;
                    },
                    targets: ['holiday']
                }
            };

            cal.registerTimeFrames(inputTimeFrames);
            cal.registerDateFrames(inputDateFrames);

            var timeFrames = cal.getTimeFrames(moment().month(10).date(11));
            timeFrames = cal.solve(timeFrames);
            expect(timeFrames.length).toBe(1);

            expect(timeFrames[0].working).toBeFalsy();
            expect(timeFrames[0].color).toBe('red');
            expect(timeFrames[0].classes.length).toBe(1);
            expect(timeFrames[0].classes[0]).toBe('gantt-timeframe-holiday');

            timeFrames = cal.getTimeFrames(moment().day(6));
            timeFrames = cal.solve(timeFrames);
            expect(timeFrames.length).toBe(1);

            expect(timeFrames[0].working).toBeFalsy();
            expect(timeFrames[0].color).toBeUndefined();
            expect(timeFrames[0].classes).toBeUndefined();

            timeFrames = cal.getTimeFrames(moment().month(3).date(5).day(3));
            timeFrames = cal.solve(timeFrames);
            expect(timeFrames.length).toBe(3);
        });

    it('should solve whole day working timeFrame with night as default',
        function() {
            var cal = new Calendar();

            var inputTimeFrames = {
                'night': {
                    color: 'black',
                    working: false,
                    default: true
                },
                'day': {
                    start: moment('8:00', 'HH:mm'),
                    end: moment('20:00', 'HH:mm'),
                    color: 'blue',
                    working: true,
                    default: true
                },
                'noon': {
                    start: moment('12:00', 'HH:mm'),
                    end: moment('13:30', 'HH:mm'),
                    color: 'red',
                    working: false,
                    default: true
                },
                'weekend': {
                    working: false
                },
                'holiday': {
                    working: false,
                    color: 'red',
                    classes: ['gantt-timeframe-holiday']
                }
            };

            cal.registerTimeFrames(inputTimeFrames);

            var cDate = moment();
            var cDateStartOfDay = moment(cDate).startOf('day');
            var cDateNextDay = moment(cDateStartOfDay).add(1, 'day');

            var timeFrames = cal.getTimeFrames(cDate);
            timeFrames = cal.solve(timeFrames, cDateStartOfDay, cDateNextDay);
            expect(timeFrames.length).toBe(5);

            expect(timeFrames[0].working).toBeFalsy();
            expect(timeFrames[0].color).toBe('black');

            expect(timeFrames[1].working).toBeTruthy();
            expect(timeFrames[1].color).toBe('blue');

            expect(timeFrames[2].working).toBeFalsy();
            expect(timeFrames[2].color).toBe('red');

            expect(timeFrames[3].working).toBeTruthy();
            expect(timeFrames[3].color).toBe('blue');

            expect(timeFrames[4].working).toBeFalsy();
            expect(timeFrames[4].color).toBe('black');

        });

    it('should solve calendar from demo',
        function() {
            var cal = new Calendar();

            var inputTimeFrames = {
                'day': {
                    start: moment('8:00', 'HH:mm'),
                    end: moment('20:00', 'HH:mm'),
                    color: '#ACFFA3',
                    working: true,
                    default: true
                },
                'noon': {
                    start: moment('12:00', 'HH:mm'),
                    end: moment('13:30', 'HH:mm'),
                    working: false,
                    default: true
                },
                'closed': {
                    working: false,
                    default: true
                },
                'weekend': {
                    working: false
                },
                'holiday': {
                    working: false,
                    color: 'red',
                    classes: ['gantt-timeframe-holiday']
                }
            };

            cal.registerTimeFrames(inputTimeFrames);

            var cDate = moment();
            var cDateStartOfDay = moment(cDate).startOf('day');
            var cDateNextDay = moment(cDateStartOfDay).add(1, 'day');

            var timeFrames = cal.getTimeFrames(cDate);
            timeFrames = cal.solve(timeFrames, cDateStartOfDay, cDateNextDay);
            expect(timeFrames.length).toBe(5);

            expect(timeFrames[0].working).toBeFalsy();
            expect(timeFrames[0].color).toBeFalsy();

            expect(timeFrames[1].working).toBeTruthy();
            expect(timeFrames[1].color).toBe('#ACFFA3');

            expect(timeFrames[2].working).toBeFalsy();
            expect(timeFrames[2].color).toBeFalsy();

            expect(timeFrames[3].working).toBeTruthy();
            expect(timeFrames[3].color).toBe('#ACFFA3');

            expect(timeFrames[4].working).toBeFalsy();
            expect(timeFrames[4].color).toBeFalsy();

        });

});
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright (c) 2017 Google Inc. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * Code distributed by Google as part of this project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
'use strict';

defineParticle(({TransformationDomParticle}) => {
  return class ProductMultiplexer extends TransformationDomParticle {
    constructor() {
      super();
      this._itemSubIdByHostedSlotId = new Map();
      this._connByHostedConn = new Map();
    }
    async setViews(views) {
      let arc = await this.constructInnerArc();

      let hostedParticle = await views.get('hostedParticle').get();

      // Map all additional connections.
      let otherMappedViews = [];
      let otherConnections = [];
      let index = 2;
      for (let [connectionName, otherView] of views) {
        if (['list', 'hostedParticle'].includes(connectionName)) {
          continue;
        }
        otherMappedViews.push(`map '${await arc.mapHandle(otherView._view)}' as v${index}`);
        let hostedOtherConnectionName = hostedParticle.connections.find(conn => conn.type.equals(otherView.type)).name;
        otherConnections.push(`${hostedOtherConnectionName} <- v${index++}`);
        this._connByHostedConn.set(hostedOtherConnectionName, connectionName);
      }

      this.on(views, 'list', 'change', async e => {
        let handleIds = new Set(this._state.renderModel && this._state.renderModel.items ? this._state.renderModel.items.map(item => item.subId) : []);

        let listHandle = views.get('list');
        let list = await listHandle.toList();

        if (list.length > 0) {
          this.relevance = 0.1;
        }

        for (let [index, item] of list.entries()) {
          if (handleIds.has(item.id)) {
            continue;
          }
          let itemView = await arc.createHandle(listHandle.type.primitiveType(), 'item' + index);

          let hostedSlotName = [...hostedParticle.slots.keys()][0];
          let slotName = [...this.spec.slots.values()][0].name;
          let slotId = await arc.createSlot(this, slotName, hostedParticle.name, hostedSlotName);
          if (!slotId) {
            continue;
          }

          this._itemSubIdByHostedSlotId.set(slotId, item.id);

          let recipe = `
${this.serializeSchema(hostedParticle)}
recipe
  use '${itemView._id}' as v1
  ${otherMappedViews.join('\n')}
  slot '${slotId}' as s1
  ${hostedParticle.name}
    ${hostedParticle.connections[0].name} <- v1
    ${otherConnections.join('\n')}
    consume ${hostedSlotName} as s1
`;
          try {
            await arc.loadRecipe(recipe, this);
            itemView.set(item);
          } catch (e) {
            console.log(e);
          }
        }

        // Update props of all particle's views.
        this._updateAllViews(views, this.config);
      });
    }

    _willReceiveProps(props) {
      let newItems = TransformationDomParticle.propsToItems(props.list);
      // Join with existing items in particle's state.
      if (this._state.renderModel && this._state.renderModel.items) {
        newItems.forEach(newItem => {
          let item = this._state.renderModel.items.find(item => item.subId == newItem.subId);
          if (!!item) {
            return Object.assign(newItem, item);
          }
        });
      }
      this._setState({renderModel: {items: newItems}});
    }

    combineHostedModel(slotName, hostedSlotId, content) {
      let subId = this._itemSubIdByHostedSlotId.get(hostedSlotId);
      if (!subId) {
        return;
      }
      let items = this._state.renderModel ? this._state.renderModel.items : [];
      let listIndex = items.findIndex(item => item.subId == subId);
      if (listIndex >= 0 && listIndex < items.length) {
        items[listIndex] = Object.assign({}, content.model, items[listIndex]);
      } else {
        items.push(Object.assign(content.model, {subId}));
      }
      this._setState({renderModel: {items}});
    }

    combineHostedTemplate(slotName, hostedSlotId, content) {
      if (!this._state.template && !!content.template) {
        let template = content.template;
        // Replace hosted particle connection in template with the corresponding this particle connection names.
        // TODO: make this generic!
        this._connByHostedConn.forEach((conn, hostedConn) => {
          template = template.replace(new RegExp(`{{${hostedConn}.description}}`, 'g'), `{{${conn}.description}}`);
        });
        this._setState({template});
      }
    }
  };
});
<commit_msg>allow content.model to be undefined<commit_after>/**
 * @license
 * Copyright (c) 2017 Google Inc. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * Code distributed by Google as part of this project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
'use strict';

defineParticle(({TransformationDomParticle}) => {
  return class ProductMultiplexer extends TransformationDomParticle {
    constructor() {
      super();
      this._itemSubIdByHostedSlotId = new Map();
      this._connByHostedConn = new Map();
    }
    async setViews(views) {
      let arc = await this.constructInnerArc();

      let hostedParticle = await views.get('hostedParticle').get();

      // Map all additional connections.
      let otherMappedViews = [];
      let otherConnections = [];
      let index = 2;
      for (let [connectionName, otherView] of views) {
        if (['list', 'hostedParticle'].includes(connectionName)) {
          continue;
        }
        otherMappedViews.push(`map '${await arc.mapHandle(otherView._view)}' as v${index}`);
        let hostedOtherConnectionName = hostedParticle.connections.find(conn => conn.type.equals(otherView.type)).name;
        otherConnections.push(`${hostedOtherConnectionName} <- v${index++}`);
        this._connByHostedConn.set(hostedOtherConnectionName, connectionName);
      }

      this.on(views, 'list', 'change', async e => {
        let handleIds = new Set(this._state.renderModel && this._state.renderModel.items ? this._state.renderModel.items.map(item => item.subId) : []);

        let listHandle = views.get('list');
        let list = await listHandle.toList();

        if (list.length > 0) {
          this.relevance = 0.1;
        }

        for (let [index, item] of list.entries()) {
          if (handleIds.has(item.id)) {
            continue;
          }
          let itemView = await arc.createHandle(listHandle.type.primitiveType(), 'item' + index);

          let hostedSlotName = [...hostedParticle.slots.keys()][0];
          let slotName = [...this.spec.slots.values()][0].name;
          let slotId = await arc.createSlot(this, slotName, hostedParticle.name, hostedSlotName);
          if (!slotId) {
            continue;
          }

          this._itemSubIdByHostedSlotId.set(slotId, item.id);

          let recipe = `
${this.serializeSchema(hostedParticle)}
recipe
  use '${itemView._id}' as v1
  ${otherMappedViews.join('\n')}
  slot '${slotId}' as s1
  ${hostedParticle.name}
    ${hostedParticle.connections[0].name} <- v1
    ${otherConnections.join('\n')}
    consume ${hostedSlotName} as s1
`;
          try {
            await arc.loadRecipe(recipe, this);
            itemView.set(item);
          } catch (e) {
            console.log(e);
          }
        }

        // Update props of all particle's views.
        this._updateAllViews(views, this.config);
      });
    }

    _willReceiveProps(props) {
      let newItems = TransformationDomParticle.propsToItems(props.list);
      // Join with existing items in particle's state.
      if (this._state.renderModel && this._state.renderModel.items) {
        newItems.forEach(newItem => {
          let item = this._state.renderModel.items.find(item => item.subId == newItem.subId);
          if (!!item) {
            return Object.assign(newItem, item);
          }
        });
      }
      this._setState({renderModel: {items: newItems}});
    }

    combineHostedModel(slotName, hostedSlotId, content) {
      let subId = this._itemSubIdByHostedSlotId.get(hostedSlotId);
      if (!subId) {
        return;
      }
      let items = this._state.renderModel ? this._state.renderModel.items : [];
      let listIndex = items.findIndex(item => item.subId == subId);
      if (listIndex >= 0 && listIndex < items.length) {
        items[listIndex] = Object.assign({}, content.model, items[listIndex]);
      } else {
        items.push(Object.assign({}, content.model, {subId}));
      }
      this._setState({renderModel: {items}});
    }

    combineHostedTemplate(slotName, hostedSlotId, content) {
      if (!this._state.template && !!content.template) {
        let template = content.template;
        // Replace hosted particle connection in template with the corresponding this particle connection names.
        // TODO: make this generic!
        this._connByHostedConn.forEach((conn, hostedConn) => {
          template = template.replace(new RegExp(`{{${hostedConn}.description}}`, 'g'), `{{${conn}.description}}`);
        });
        this._setState({template});
      }
    }
  };
});
<|endoftext|>


<commit_before>import Cartesian3 from "../Core/Cartesian3.js";
import Check from "../Core/Check.js";
import defaultValue from "../Core/defaultValue.js";
import defined from "../Core/defined.js";
import DeveloperError from "../Core/DeveloperError.js";
import Event from "../Core/Event.js";
import ReferenceFrame from "../Core/ReferenceFrame.js";
import PositionProperty from "./PositionProperty.js";
import Property from "./Property.js";
import SampledProperty from "./SampledProperty.js";

/**
 * A {@link SampledProperty} which is also a {@link PositionProperty}.
 *
 * @alias SampledPositionProperty
 * @constructor
 *
 * @param {ReferenceFrame} [referenceFrame=ReferenceFrame.FIXED] The reference frame in which the position is defined.
 * @param {Number} [numberOfDerivatives=0] The number of derivatives that accompany each position; i.e. velocity, acceleration, etc...
 */
function SampledPositionProperty(referenceFrame, numberOfDerivatives) {
  numberOfDerivatives = defaultValue(numberOfDerivatives, 0);

  var derivativeTypes;
  if (numberOfDerivatives > 0) {
    derivativeTypes = new Array(numberOfDerivatives);
    for (var i = 0; i < numberOfDerivatives; i++) {
      derivativeTypes[i] = Cartesian3;
    }
  }

  this._numberOfDerivatives = numberOfDerivatives;
  this._property = new SampledProperty(Cartesian3, derivativeTypes);
  this._definitionChanged = new Event();
  this._referenceFrame = defaultValue(referenceFrame, ReferenceFrame.FIXED);

  this._property._definitionChanged.addEventListener(function () {
    this._definitionChanged.raiseEvent(this);
  }, this);
}

Object.defineProperties(SampledPositionProperty.prototype, {
  /**
   * Gets a value indicating if this property is constant.  A property is considered
   * constant if getValue always returns the same result for the current definition.
   * @memberof SampledPositionProperty.prototype
   *
   * @type {Boolean}
   * @readonly
   */
  isConstant: {
    get: function () {
      return this._property.isConstant;
    },
  },
  /**
   * Gets the event that is raised whenever the definition of this property changes.
   * The definition is considered to have changed if a call to getValue would return
   * a different result for the same time.
   * @memberof SampledPositionProperty.prototype
   *
   * @type {Event}
   * @readonly
   */
  definitionChanged: {
    get: function () {
      return this._definitionChanged;
    },
  },
  /**
   * Gets the reference frame in which the position is defined.
   * @memberof SampledPositionProperty.prototype
   * @type {ReferenceFrame}
   * @default ReferenceFrame.FIXED;
   */
  referenceFrame: {
    get: function () {
      return this._referenceFrame;
    },
  },
  /**
   * Gets the degree of interpolation to perform when retrieving a value. Call setInterpolationOptions to set this.
   * @memberof SampledPositionProperty.prototype
   *
   * @type {Number}
   * @default 1
   * @readonly
   */
  interpolationDegree: {
    get: function () {
      return this._property.interpolationDegree;
    },
  },
  /**
   * Gets the interpolation algorithm to use when retrieving a value. Call setInterpolationOptions to set this.
   * @memberof SampledPositionProperty.prototype
   *
   * @type {InterpolationAlgorithm}
   * @default LinearApproximation
   * @readonly
   */
  interpolationAlgorithm: {
    get: function () {
      return this._property.interpolationAlgorithm;
    },
  },
  /**
   * The number of derivatives contained by this property; i.e. 0 for just position, 1 for velocity, etc.
   * @memberof SampledPositionProperty.prototype
   *
   * @type {Number}
   * @default 0
   */
  numberOfDerivatives: {
    get: function () {
      return this._numberOfDerivatives;
    },
  },
  /**
   * Gets or sets the type of extrapolation to perform when a value
   * is requested at a time after any available samples.
   * @memberof SampledPositionProperty.prototype
   * @type {ExtrapolationType}
   * @default ExtrapolationType.NONE
   */
  forwardExtrapolationType: {
    get: function () {
      return this._property.forwardExtrapolationType;
    },
    set: function (value) {
      this._property.forwardExtrapolationType = value;
    },
  },
  /**
   * Gets or sets the amount of time to extrapolate forward before
   * the property becomes undefined.  A value of 0 will extrapolate forever.
   * @memberof SampledPositionProperty.prototype
   * @type {Number}
   * @default 0
   */
  forwardExtrapolationDuration: {
    get: function () {
      return this._property.forwardExtrapolationDuration;
    },
    set: function (value) {
      this._property.forwardExtrapolationDuration = value;
    },
  },
  /**
   * Gets or sets the type of extrapolation to perform when a value
   * is requested at a time before any available samples.
   * @memberof SampledPositionProperty.prototype
   * @type {ExtrapolationType}
   * @default ExtrapolationType.NONE
   */
  backwardExtrapolationType: {
    get: function () {
      return this._property.backwardExtrapolationType;
    },
    set: function (value) {
      this._property.backwardExtrapolationType = value;
    },
  },
  /**
   * Gets or sets the amount of time to extrapolate backward
   * before the property becomes undefined.  A value of 0 will extrapolate forever.
   * @memberof SampledPositionProperty.prototype
   * @type {Number}
   * @default 0
   */
  backwardExtrapolationDuration: {
    get: function () {
      return this._property.backwardExtrapolationDuration;
    },
    set: function (value) {
      this._property.backwardExtrapolationDuration = value;
    },
  },
});

/**
 * Gets the position at the provided time.
 *
 * @param {JulianDate} time The time for which to retrieve the value.
 * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
 * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
 */
SampledPositionProperty.prototype.getValue = function (time, result) {
  return this.getValueInReferenceFrame(time, ReferenceFrame.FIXED, result);
};

/**
 * Gets the position at the provided time and in the provided reference frame.
 *
 * @param {JulianDate} time The time for which to retrieve the value.
 * @param {ReferenceFrame} referenceFrame The desired referenceFrame of the result.
 * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
 * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
 */
SampledPositionProperty.prototype.getValueInReferenceFrame = function (
  time,
  referenceFrame,
  result
) {
  //>>includeStart('debug', pragmas.debug);
  Check.defined("time", time);
  Check.defined("referenceFrame", referenceFrame);
  //>>includeEnd('debug');

  result = this._property.getValue(time, result);
  if (defined(result)) {
    return PositionProperty.convertToReferenceFrame(
      time,
      result,
      this._referenceFrame,
      referenceFrame,
      result
    );
  }
  return undefined;
};

/**
 * Sets the algorithm and degree to use when interpolating a position.
 *
 * @param {Object} [options] Object with the following properties:
 * @param {InterpolationAlgorithm} [options.interpolationAlgorithm] The new interpolation algorithm.  If undefined, the existing property will be unchanged.
 * @param {Number} [options.interpolationDegree] The new interpolation degree.  If undefined, the existing property will be unchanged.
 */
SampledPositionProperty.prototype.setInterpolationOptions = function (options) {
  this._property.setInterpolationOptions(options);
};

/**
 * Adds a new sample.
 *
 * @param {JulianDate} time The sample time.
 * @param {Cartesian3} position The position at the provided time.
 * @param {Cartesian3[]} [derivatives] The array of derivative values at the provided time.
 */
SampledPositionProperty.prototype.addSample = function (
  time,
  position,
  derivatives
) {
  var numberOfDerivatives = this._numberOfDerivatives;
  //>>includeStart('debug', pragmas.debug);
  if (
    numberOfDerivatives > 0 &&
    (!defined(derivatives) || derivatives.length !== numberOfDerivatives)
  ) {
    throw new DeveloperError(
      "derivatives length must be equal to the number of derivatives."
    );
  }
  //>>includeEnd('debug');
  this._property.addSample(time, position, derivatives);
};

/**
 * Adds multiple samples via parallel arrays.
 *
 * @param {JulianDate[]} times An array of JulianDate instances where each index is a sample time.
 * @param {Cartesian3[]} positions An array of Cartesian3 position instances, where each value corresponds to the provided time index.
 * @param {Array[]} [derivatives] An array where each value is another array containing derivatives for the corresponding time index.
 *
 * @exception {DeveloperError} All arrays must be the same length.
 */
SampledPositionProperty.prototype.addSamples = function (
  times,
  positions,
  derivatives
) {
  this._property.addSamples(times, positions, derivatives);
};

/**
 * Adds samples as a single packed array where each new sample is represented as a date,
 * followed by the packed representation of the corresponding value and derivatives.
 *
 * @param {Number[]} packedSamples The array of packed samples.
 * @param {JulianDate} [epoch] If any of the dates in packedSamples are numbers, they are considered an offset from this epoch, in seconds.
 */
SampledPositionProperty.prototype.addSamplesPackedArray = function (
  packedSamples,
  epoch
) {
  this._property.addSamplesPackedArray(packedSamples, epoch);
};

/**
 * Removes a sample at the given time, if present.
 *
 * @param {JulianDate} time The sample time.
 * @returns {Boolean} true if a sample at time was removed, false otherwise.
 */
SampledPositionProperty.prototype.removeSample = function (time) {
  this._property.removeSample(time);
};

/**
 * Removes all samples for the given time interval.
 *
 * @param {TimeInterval} time The time interval for which to remove all samples.
 */
SampledPositionProperty.prototype.removeSamples = function (timeInterval) {
  this._property.removeSamples(timeInterval);
};

/**
 * Compares this property to the provided property and returns
 * true if they are equal, false otherwise.
 *
 * @param {Property} [other] The other property.
 * @returns {Boolean} true if left and right are equal, false otherwise.
 */
SampledPositionProperty.prototype.equals = function (other) {
  return (
    this === other || //
    (other instanceof SampledPositionProperty &&
    Property.equals(this._property, other._property) && //
      this._referenceFrame === other._referenceFrame)
  );
};
export default SampledPositionProperty;
<commit_msg>fixed the return statetment as SampledProperty removeSample is returning but this function is not even though the api docs states it should<commit_after>import Cartesian3 from "../Core/Cartesian3.js";
import Check from "../Core/Check.js";
import defaultValue from "../Core/defaultValue.js";
import defined from "../Core/defined.js";
import DeveloperError from "../Core/DeveloperError.js";
import Event from "../Core/Event.js";
import ReferenceFrame from "../Core/ReferenceFrame.js";
import PositionProperty from "./PositionProperty.js";
import Property from "./Property.js";
import SampledProperty from "./SampledProperty.js";

/**
 * A {@link SampledProperty} which is also a {@link PositionProperty}.
 *
 * @alias SampledPositionProperty
 * @constructor
 *
 * @param {ReferenceFrame} [referenceFrame=ReferenceFrame.FIXED] The reference frame in which the position is defined.
 * @param {Number} [numberOfDerivatives=0] The number of derivatives that accompany each position; i.e. velocity, acceleration, etc...
 */
function SampledPositionProperty(referenceFrame, numberOfDerivatives) {
  numberOfDerivatives = defaultValue(numberOfDerivatives, 0);

  var derivativeTypes;
  if (numberOfDerivatives > 0) {
    derivativeTypes = new Array(numberOfDerivatives);
    for (var i = 0; i < numberOfDerivatives; i++) {
      derivativeTypes[i] = Cartesian3;
    }
  }

  this._numberOfDerivatives = numberOfDerivatives;
  this._property = new SampledProperty(Cartesian3, derivativeTypes);
  this._definitionChanged = new Event();
  this._referenceFrame = defaultValue(referenceFrame, ReferenceFrame.FIXED);

  this._property._definitionChanged.addEventListener(function () {
    this._definitionChanged.raiseEvent(this);
  }, this);
}

Object.defineProperties(SampledPositionProperty.prototype, {
  /**
   * Gets a value indicating if this property is constant.  A property is considered
   * constant if getValue always returns the same result for the current definition.
   * @memberof SampledPositionProperty.prototype
   *
   * @type {Boolean}
   * @readonly
   */
  isConstant: {
    get: function () {
      return this._property.isConstant;
    },
  },
  /**
   * Gets the event that is raised whenever the definition of this property changes.
   * The definition is considered to have changed if a call to getValue would return
   * a different result for the same time.
   * @memberof SampledPositionProperty.prototype
   *
   * @type {Event}
   * @readonly
   */
  definitionChanged: {
    get: function () {
      return this._definitionChanged;
    },
  },
  /**
   * Gets the reference frame in which the position is defined.
   * @memberof SampledPositionProperty.prototype
   * @type {ReferenceFrame}
   * @default ReferenceFrame.FIXED;
   */
  referenceFrame: {
    get: function () {
      return this._referenceFrame;
    },
  },
  /**
   * Gets the degree of interpolation to perform when retrieving a value. Call setInterpolationOptions to set this.
   * @memberof SampledPositionProperty.prototype
   *
   * @type {Number}
   * @default 1
   * @readonly
   */
  interpolationDegree: {
    get: function () {
      return this._property.interpolationDegree;
    },
  },
  /**
   * Gets the interpolation algorithm to use when retrieving a value. Call setInterpolationOptions to set this.
   * @memberof SampledPositionProperty.prototype
   *
   * @type {InterpolationAlgorithm}
   * @default LinearApproximation
   * @readonly
   */
  interpolationAlgorithm: {
    get: function () {
      return this._property.interpolationAlgorithm;
    },
  },
  /**
   * The number of derivatives contained by this property; i.e. 0 for just position, 1 for velocity, etc.
   * @memberof SampledPositionProperty.prototype
   *
   * @type {Number}
   * @default 0
   */
  numberOfDerivatives: {
    get: function () {
      return this._numberOfDerivatives;
    },
  },
  /**
   * Gets or sets the type of extrapolation to perform when a value
   * is requested at a time after any available samples.
   * @memberof SampledPositionProperty.prototype
   * @type {ExtrapolationType}
   * @default ExtrapolationType.NONE
   */
  forwardExtrapolationType: {
    get: function () {
      return this._property.forwardExtrapolationType;
    },
    set: function (value) {
      this._property.forwardExtrapolationType = value;
    },
  },
  /**
   * Gets or sets the amount of time to extrapolate forward before
   * the property becomes undefined.  A value of 0 will extrapolate forever.
   * @memberof SampledPositionProperty.prototype
   * @type {Number}
   * @default 0
   */
  forwardExtrapolationDuration: {
    get: function () {
      return this._property.forwardExtrapolationDuration;
    },
    set: function (value) {
      this._property.forwardExtrapolationDuration = value;
    },
  },
  /**
   * Gets or sets the type of extrapolation to perform when a value
   * is requested at a time before any available samples.
   * @memberof SampledPositionProperty.prototype
   * @type {ExtrapolationType}
   * @default ExtrapolationType.NONE
   */
  backwardExtrapolationType: {
    get: function () {
      return this._property.backwardExtrapolationType;
    },
    set: function (value) {
      this._property.backwardExtrapolationType = value;
    },
  },
  /**
   * Gets or sets the amount of time to extrapolate backward
   * before the property becomes undefined.  A value of 0 will extrapolate forever.
   * @memberof SampledPositionProperty.prototype
   * @type {Number}
   * @default 0
   */
  backwardExtrapolationDuration: {
    get: function () {
      return this._property.backwardExtrapolationDuration;
    },
    set: function (value) {
      this._property.backwardExtrapolationDuration = value;
    },
  },
});

/**
 * Gets the position at the provided time.
 *
 * @param {JulianDate} time The time for which to retrieve the value.
 * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
 * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
 */
SampledPositionProperty.prototype.getValue = function (time, result) {
  return this.getValueInReferenceFrame(time, ReferenceFrame.FIXED, result);
};

/**
 * Gets the position at the provided time and in the provided reference frame.
 *
 * @param {JulianDate} time The time for which to retrieve the value.
 * @param {ReferenceFrame} referenceFrame The desired referenceFrame of the result.
 * @param {Cartesian3} [result] The object to store the value into, if omitted, a new instance is created and returned.
 * @returns {Cartesian3} The modified result parameter or a new instance if the result parameter was not supplied.
 */
SampledPositionProperty.prototype.getValueInReferenceFrame = function (
  time,
  referenceFrame,
  result
) {
  //>>includeStart('debug', pragmas.debug);
  Check.defined("time", time);
  Check.defined("referenceFrame", referenceFrame);
  //>>includeEnd('debug');

  result = this._property.getValue(time, result);
  if (defined(result)) {
    return PositionProperty.convertToReferenceFrame(
      time,
      result,
      this._referenceFrame,
      referenceFrame,
      result
    );
  }
  return undefined;
};

/**
 * Sets the algorithm and degree to use when interpolating a position.
 *
 * @param {Object} [options] Object with the following properties:
 * @param {InterpolationAlgorithm} [options.interpolationAlgorithm] The new interpolation algorithm.  If undefined, the existing property will be unchanged.
 * @param {Number} [options.interpolationDegree] The new interpolation degree.  If undefined, the existing property will be unchanged.
 */
SampledPositionProperty.prototype.setInterpolationOptions = function (options) {
  this._property.setInterpolationOptions(options);
};

/**
 * Adds a new sample.
 *
 * @param {JulianDate} time The sample time.
 * @param {Cartesian3} position The position at the provided time.
 * @param {Cartesian3[]} [derivatives] The array of derivative values at the provided time.
 */
SampledPositionProperty.prototype.addSample = function (
  time,
  position,
  derivatives
) {
  var numberOfDerivatives = this._numberOfDerivatives;
  //>>includeStart('debug', pragmas.debug);
  if (
    numberOfDerivatives > 0 &&
    (!defined(derivatives) || derivatives.length !== numberOfDerivatives)
  ) {
    throw new DeveloperError(
      "derivatives length must be equal to the number of derivatives."
    );
  }
  //>>includeEnd('debug');
  this._property.addSample(time, position, derivatives);
};

/**
 * Adds multiple samples via parallel arrays.
 *
 * @param {JulianDate[]} times An array of JulianDate instances where each index is a sample time.
 * @param {Cartesian3[]} positions An array of Cartesian3 position instances, where each value corresponds to the provided time index.
 * @param {Array[]} [derivatives] An array where each value is another array containing derivatives for the corresponding time index.
 *
 * @exception {DeveloperError} All arrays must be the same length.
 */
SampledPositionProperty.prototype.addSamples = function (
  times,
  positions,
  derivatives
) {
  this._property.addSamples(times, positions, derivatives);
};

/**
 * Adds samples as a single packed array where each new sample is represented as a date,
 * followed by the packed representation of the corresponding value and derivatives.
 *
 * @param {Number[]} packedSamples The array of packed samples.
 * @param {JulianDate} [epoch] If any of the dates in packedSamples are numbers, they are considered an offset from this epoch, in seconds.
 */
SampledPositionProperty.prototype.addSamplesPackedArray = function (
  packedSamples,
  epoch
) {
  this._property.addSamplesPackedArray(packedSamples, epoch);
};

/**
 * Removes a sample at the given time, if present.
 *
 * @param {JulianDate} time The sample time.
 * @returns {Boolean} true if a sample at time was removed, false otherwise.
 */
SampledPositionProperty.prototype.removeSample = function (time) {
  return this._property.removeSample(time);
};

/**
 * Removes all samples for the given time interval.
 *
 * @param {TimeInterval} time The time interval for which to remove all samples.
 */
SampledPositionProperty.prototype.removeSamples = function (timeInterval) {
  this._property.removeSamples(timeInterval);
};

/**
 * Compares this property to the provided property and returns
 * true if they are equal, false otherwise.
 *
 * @param {Property} [other] The other property.
 * @returns {Boolean} true if left and right are equal, false otherwise.
 */
SampledPositionProperty.prototype.equals = function (other) {
  return (
    this === other || //
    (other instanceof SampledPositionProperty &&
    Property.equals(this._property, other._property) && //
      this._referenceFrame === other._referenceFrame)
  );
};
export default SampledPositionProperty;
<|endoftext|>


<commit_before>describe('Scroll View', function() {
  var sc;
  beforeEach(function() {
    sc = document.createElement('scroll-content');
    s = document.createElement('scroll');
    sc.appendChild(s);
  });

  it('Should init', function() {
    var sv = new ionic.views.ScrollNative({
      el: sc
    });
  });

  it('Should be frozen after calling freeze', function(){
    var sv = new ionic.views.ScrollNative({
      el: sc
    });
    sv.freeze(true);
    expect(sv.__frozen).toEqual(true);
    sv.freeze(false);
    expect(sv.__frozen).toEqual(false);
  });

  it('Should be frozen shut after calling freezeShut', function(){
    var sv = new ionic.views.ScrollNative({
      el: sc
    });
    sv.freezeShut(true);
    expect(sv.__frozenShut).toEqual(true);
    sv.freezeShut(false);
    expect(sv.__frozenShut).toEqual(false);
  });

  it('Should shut down event completely on frozen shut', function(){
    var sv = new ionic.views.ScrollNative({
      el: sc
    });
    sv.freezeShut(true);

    var mockEvent = {
      preventDefault: jasmine.createSpy(),
      stopPropagation: jasmine.createSpy()
    };

    var result = sv.handleTouchMove(mockEvent);
    expect(result).toEqual(false);
    expect(mockEvent.preventDefault).toHaveBeenCalled();
    expect(mockEvent.stopPropagation).toHaveBeenCalled();
    expect(mockEvent.preventDefault.callCount).toEqual(1);
    expect(mockEvent.stopPropagation.callCount).toEqual(1);
  });

  it('Should shut down event completely on frozen shut', function(){
    var sv = new ionic.views.ScrollNative({
      el: sc
    });
    sv.freeze(true);

    var mockEvent = {
      preventDefault: jasmine.createSpy(),
      stopPropagation: jasmine.createSpy()
    };

    var result = sv.handleTouchMove(mockEvent);
    expect(result).toEqual(false);
    expect(mockEvent.preventDefault).toHaveBeenCalled();
    expect(mockEvent.stopPropagation).not.toHaveBeenCalled();
    expect(mockEvent.preventDefault.callCount).toEqual(1);
    expect(mockEvent.stopPropagation.callCount).toEqual(0);
  });
});
<commit_msg>improving bdd for tests for nav<commit_after>describe('Scroll View', function() {
  var sc;
  beforeEach(function() {
    sc = document.createElement('scroll-content');
    s = document.createElement('scroll');
    sc.appendChild(s);
  });

  it('Should init', function() {
    var sv = new ionic.views.ScrollNative({
      el: sc
    });
  });

  it('Should be frozen after calling freeze', function(){
    var sv = new ionic.views.ScrollNative({
      el: sc
    });
    sv.freeze(true);
    expect(sv.__frozen).toEqual(true);
    sv.freeze(false);
    expect(sv.__frozen).toEqual(false);
  });

  it('Should be frozen shut after calling freezeShut', function(){
    var sv = new ionic.views.ScrollNative({
      el: sc
    });
    sv.freezeShut(true);
    expect(sv.__frozenShut).toEqual(true);
    sv.freezeShut(false);
    expect(sv.__frozenShut).toEqual(false);
  });

  it('Should shut down event completely when view is frozen shut', function(){
    var sv = new ionic.views.ScrollNative({
      el: sc
    });
    sv.freezeShut(true);

    var mockEvent = {
      preventDefault: jasmine.createSpy(),
      stopPropagation: jasmine.createSpy()
    };

    var result = sv.handleTouchMove(mockEvent);
    expect(result).toEqual(false);
    expect(mockEvent.preventDefault).toHaveBeenCalled();
    expect(mockEvent.stopPropagation).toHaveBeenCalled();
    expect(mockEvent.preventDefault.callCount).toEqual(1);
    expect(mockEvent.stopPropagation.callCount).toEqual(1);
  });

  it('Should prevent default on event when view is frozen', function(){
    var sv = new ionic.views.ScrollNative({
      el: sc
    });
    sv.freeze(true);

    var mockEvent = {
      preventDefault: jasmine.createSpy(),
      stopPropagation: jasmine.createSpy()
    };

    var result = sv.handleTouchMove(mockEvent);
    expect(result).toEqual(false);
    expect(mockEvent.preventDefault).toHaveBeenCalled();
    expect(mockEvent.stopPropagation).not.toHaveBeenCalled();
    expect(mockEvent.preventDefault.callCount).toEqual(1);
    expect(mockEvent.stopPropagation.callCount).toEqual(0);
  });
});
<|endoftext|>


<commit_before>const { expect } = require('chai');
const unescapeHtml = require('../../src/utils/unescape-html');

describe('#unescapeHtml', () => {
  it('should properly transform lt, newline and gt', () => {
    const source = 'UNABLE TO RETRIEVE - RESTRICTED BF   \n><';
    expect(unescapeHtml(source)).to.be.eq('UNABLE TO RETRIEVE - RESTRICTED BF   \n><');
  });

  it('should not change original string', () => {
    const source = 'UNABLE TO RETRIEVE - RESTRICTED BFgt;lt;';
    expect(unescapeHtml(source)).to.be.eq('UNABLE TO RETRIEVE - RESTRICTED BFgt;lt;');
  });
});
<commit_msg>Add some more coverage<commit_after>const { expect } = require('chai');
const unescapeHtml = require('../../src/utils/unescape-html');

describe.only('#unescapeHtml', () => {
  it('should properly transform lt, newline and gt', () => {
    const source = 'UNABLE TO RETRIEVE - RESTRICTED BF   \n><';
    expect(unescapeHtml(source)).to.be.eq('UNABLE TO RETRIEVE - RESTRICTED BF   \n><');
  });

  it('should properly transform quot', () => {
    const source = 'sumtest "';
    expect(unescapeHtml(source)).to.be.eq('sumtest "');
  });

  it('should properly transform nbsp', () => {
    const source = 'some text ';
    expect(unescapeHtml(source)).to.be.eq('some text ');
  });

  it('should not change original string', () => {
    const source = 'UNABLE TO RETRIEVE - RESTRICTED BFgt;lt;';
    expect(unescapeHtml(source)).to.be.eq('UNABLE TO RETRIEVE - RESTRICTED BFgt;lt;');
  });
});
<|endoftext|>


<commit_before>// Submote by Zarlach

//Global vars
var subMotes    = {};           // subMotes[emote] = source
var subEmotes   = {};           // subEmotes[emote] = id
var bttvEmotes  = {};           // bttvEmotes[emote] = source

//Check if emotes are already stored locally
if (localStorage.getItem("subEmotes") === null)
    loadSubEmotes();
else
{
    subEmotes           = JSON.parse(localStorage.getItem("subEmotes"));
    var genDate         = Date.parse(subEmotes['generated_at']);
    var currentDate     = new Date();
    var expirationDate  = genDate+3600*1000/2;  //30 minutes

    //Check if expired
    if(currentDate.getTime() >= expirationDate)
        loadSubEmotes();
}

if (localStorage.getItem("bttvEmotes") === null)
    loadBetterTTVemotes();
else
    bttvEmotes = JSON.parse(localStorage.getItem("bttvEmotes"));

/**
 * Check for new chat messages
 */
$('.chat-lines').on('DOMNodeInserted', function(e)
{
    var element = e.target;
    var line    = $(element).last();

    //Check if it's a message
    if (line.last().length
        && line.find('.message').last().html() !== undefined
        && line.not('.admin'))
    {
        var message = line.find('.message').last();
        var badges  = line.find('.badges');
        var from    = line.find('.from').html().toLowerCase();

        //Parse message
        if(from !== 'jtv')
        {
            parseMessage(message, subEmotes);
            parseMessage(message, bttvEmotes);
        }

        //Append turbo
        if(from === 'zarlach' && badges.last().find('.submote-dev').length === 0)
        {
            $(badges).last().append('

');
            $(badges).last().find('.submote-dev').css({
                'width': '18px',
                'height': '18px',
                'background-image': 'url(https://cdn.rawgit.com/Zarlach/Submote/master/images/dev-badge.png)',
                'background-repat': 'no-repeat',
                'background-size': '18px 18px'
            });
        }
    }
});

/**
 * Load subscriber emotes from web
 */
function loadSubEmotes()
{
    $.getJSON('https:twitchemotes.com/api_cache/v2/subscriber.json', function(data)
    {
        $.each(data['channels'], function(channel, properties)
        {
            $.each(properties['emotes'], function(list, emote){
                subEmotes[emote['code']] = emote['image_id'];
            });
        });

        $.each(data['meta'], function(key, val){
            subEmotes[key] = val;
        });
    })
    .done(function()
    {
        subEmotes['provider'] = 'twitch';
        localStorage.setItem("subEmotes", JSON.stringify(subEmotes));
    })
    .fail(function()
    {
        //sendError('Submote could not load sub emotes');
        console.log('Could not load sub emotes');
    });
}

/**
 * Load BetterTTV emotes from web
 */
function loadBetterTTVemotes()
{
    $.getJSON('https://cdn.betterttv.net/emotes/emotes.json', function(data){
        $.each(data, function(key, value){
            bttvEmotes[value['regex'].replace('\\', '')] = value['url'].replace('//', 'https://');
        });
    })
    .done(function(){
        bttvEmotes['provider'] = 'betterttv';
        localStorage.setItem("bttvEmotes", JSON.stringify(bttvEmotes));
    })
    .fail(function(){
        console.log('Submote could not load BetterTTV emotes');
    });
}

/**
 * Scan message and replace words with emotes!
 *
 * @param  {element} ele        Message element
 * @param  {object} list        List of emotes
 * @param  {string} provider    Emote provider
 */
function parseMessage(ele, list)
{
    var msg         = ele.html();
    var split       = msg.replace(/(<([^>]+)>)/ig,'').trim().split(' ');
        split       = $.grep(split,function(n){ return(n) });
    var words       = [];
    var provider    = list['provider'];
    var regex;
    var word;

    //Remove duplicates
    $.each(split, function(i, el){
        if($.inArray(el, words) === -1) words.push(el);
    });

    //
    for (var i = 0; i <= words.length; i++) {
        word = words[i];

        if(validateFilter(word, list, provider))
        {
            regex = new RegExp('\\b'+word+'\\b(?=[^"]*(?:"[^"]*"[^"]*)*$)', 'g');
            msg = msg.replace(regex, generateEmoteImage(word, list[word], provider));
        }
    }

    ele.html(msg.trim());
}

/**
 * Generate emote image HTML tag.
 *
 * @param  {int} id Emote ID
 * @return {string}    HTML img tag
 */
function generateEmoteImage(emote, source, provider)
{
    switch(provider){
        case 'twitch':
            return '';
            break;
        case 'betterttv':
            return '';
            break;
    }
}

/**
 * Run selected word through a filter
 *
 * @param  {string}     word     Selected word
 * @param  {object}     list     Emote list
 * @param  {string}     provider Emote provider
 * @return {boolean}    Returns whether or not the word passed the filter
 */
function validateFilter(word, list, provider)
{
    var regex = new RegExp('^(?=.*[a-z])(?=.*[A-Z]).+$');

    //General filter
    if(list[word] === undefined
        || !regex.test(word)
        || word === 'provider'
        || word === 'generated_at'
        || word.length === 0)
        return false;

    //Provider specific filter
    switch(provider){
        case 'twitch':
            if (word[0] !== word[0].toLowerCase()
                || word === 'double'
                || word === 'triple'
                || word === 'quadra'
                || word === 'penta'
                || word === 'kill'
                || word === 'snap')
                return false;

            break;
        case 'betterttv':

            break;
    }

    return true;
}

/**
 * In case something fails, let the user know!
 *
 * @param  {string} message Error description
 */
function sendError(message)
{
    $('body').append('

'+message+'
Please refresh

');
}<commit_msg>Added PepePls<commit_after>// Submote by Zarlach

// Global vars
var subMotes    = {};           // subMotes[emote] = source
var subEmotes   = {};           // subEmotes[emote] = id
var bttvEmotes  = {};           // bttvEmotes[emote] = source

// Custom emotes
bttvEmotes['PepePls'] = 'https://cdn.betterttv.net/emote/55898e122612142e6aaa935b/1x';

// Check if emotes are already stored locally
if (localStorage.getItem("subEmotes") === null)
    loadSubEmotes();
else
{
    subEmotes           = JSON.parse(localStorage.getItem("subEmotes"));
    var genDate         = Date.parse(subEmotes['generated_at']);
    var currentDate     = new Date();
    var expirationDate  = genDate+3600*1000/2;  //30 minutes

    //Check if expired
    if(currentDate.getTime() >= expirationDate)
        loadSubEmotes();
}

if (localStorage.getItem("bttvEmotes") === null)
    loadBetterTTVemotes();
else
    bttvEmotes = JSON.parse(localStorage.getItem("bttvEmotes"));

/**
 * Check for new chat messages
 */
$('.chat-lines').on('DOMNodeInserted', function(e)
{
    var element = e.target;
    var line    = $(element).last();

    //Check if it's a message
    if (line.last().length
        && line.find('.message').last().html() !== undefined
        && line.not('.admin'))
    {
        var message = line.find('.message').last();
        var badges  = line.find('.badges');
        var from    = line.find('.from').html().toLowerCase();

        //Parse message
        if(from !== 'jtv')
        {
            parseMessage(message, subEmotes);
            parseMessage(message, bttvEmotes);
        }

        //Append turbo
        if(from === 'zarlach' && badges.last().find('.submote-dev').length === 0)
        {
            $(badges).last().append('

');
            $(badges).last().find('.submote-dev').css({
                'width': '18px',
                'height': '18px',
                'background-image': 'url(https://cdn.rawgit.com/Zarlach/Submote/master/images/dev-badge.png)',
                'background-repat': 'no-repeat',
                'background-size': '18px 18px'
            });
        }
    }
});

/**
 * Load subscriber emotes from web
 */
function loadSubEmotes()
{
    $.getJSON('https:twitchemotes.com/api_cache/v2/subscriber.json', function(data)
    {
        $.each(data['channels'], function(channel, properties)
        {
            $.each(properties['emotes'], function(list, emote){
                subEmotes[emote['code']] = emote['image_id'];
            });
        });

        $.each(data['meta'], function(key, val){
            subEmotes[key] = val;
        });
    })
    .done(function()
    {
        subEmotes['provider'] = 'twitch';
        localStorage.setItem("subEmotes", JSON.stringify(subEmotes));
    })
    .fail(function()
    {
        //sendError('Submote could not load sub emotes');
        console.log('Could not load sub emotes');
    });
}

/**
 * Load BetterTTV emotes from web
 */
function loadBetterTTVemotes()
{
    $.getJSON('https://cdn.betterttv.net/emotes/emotes.json', function(data){
        $.each(data, function(key, value){
            bttvEmotes[value['regex'].replace('\\', '')] = value['url'].replace('//', 'https://');
        });
    })
    .done(function(){
        bttvEmotes['provider'] = 'betterttv';
        localStorage.setItem("bttvEmotes", JSON.stringify(bttvEmotes));
    })
    .fail(function(){
        console.log('Submote could not load BetterTTV emotes');
    });
}

/**
 * Scan message and replace words with emotes!
 *
 * @param  {element} ele        Message element
 * @param  {object} list        List of emotes
 * @param  {string} provider    Emote provider
 */
function parseMessage(ele, list)
{
    var msg         = ele.html();
    var split       = msg.replace(/(<([^>]+)>)/ig,'').trim().split(' ');
        split       = $.grep(split,function(n){ return(n) });
    var words       = [];
    var provider    = list['provider'];
    var regex;
    var word;

    //Remove duplicates
    $.each(split, function(i, el){
        if($.inArray(el, words) === -1) words.push(el);
    });

    //
    for (var i = 0; i <= words.length; i++) {
        word = words[i];

        if(validateFilter(word, list, provider))
        {
            regex = new RegExp('\\b'+word+'\\b(?=[^"]*(?:"[^"]*"[^"]*)*$)', 'g');
            msg = msg.replace(regex, generateEmoteImage(word, list[word], provider));
        }
    }

    ele.html(msg.trim());
}

/**
 * Generate emote image HTML tag.
 *
 * @param  {int} id Emote ID
 * @return {string}    HTML img tag
 */
function generateEmoteImage(emote, source, provider)
{
    switch(provider){
        case 'twitch':
            return '';
            break;
        case 'betterttv':
            return '';
            break;
    }
}

/**
 * Run selected word through a filter
 *
 * @param  {string}     word     Selected word
 * @param  {object}     list     Emote list
 * @param  {string}     provider Emote provider
 * @return {boolean}    Returns whether or not the word passed the filter
 */
function validateFilter(word, list, provider)
{
    var regex = new RegExp('^(?=.*[a-z])(?=.*[A-Z]).+$');

    //General filter
    if(list[word] === undefined
        || !regex.test(word)
        || word === 'provider'
        || word === 'generated_at'
        || word.length === 0)
        return false;

    //Provider specific filter
    switch(provider){
        case 'twitch':
            if (word[0] !== word[0].toLowerCase()
                || word === 'double'
                || word === 'triple'
                || word === 'quadra'
                || word === 'penta'
                || word === 'kill'
                || word === 'snap')
                return false;

            break;
        case 'betterttv':

            break;
    }

    return true;
}

/**
 * In case something fails, let the user know!
 *
 * @param  {string} message Error description
 */
function sendError(message)
{
    $('body').append('

'+message+'
Please refresh

');
}<|endoftext|>


<commit_before>// ==========================================================================
//                          DG.GraphDropTarget
//
//  Author:   William Finzer
//
//  Copyright (c) 2014 by The Concord Consortium, Inc. All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// ==========================================================================

/** @class  Mixin to define behavior of graph subviews on drag

*/
DG.GraphDropTarget =
{
  kDropFrameClass: 'dg-graph-drop-frame',
  kDropHintClass: 'dg-graph-drop-hint',
  kDropBoxClass: 'dg-graph-drop-box',

  /**
   * Return the key to a localizable string to be displayed when the target has no current attribute
   */
  blankDropHint: '',

  // SC.DropTarget protocol
  isDropTarget: true,

  /**
   Graph controller observes this property to detect that a drag has taken place.
   @property{{collection:{DG.CollectionRecord}, attribute:{DG.Attribute}, text:{String},
   axisOrientation:{String} }}
   */
  dragData:null,

  getDataConfiguration: function() {
    return this.get('dataConfiguration') || this.getPath('model.dataConfiguration');
  },

  /**
   * Override SC.View for CODAP drop targets.
   * [CODAP fix] When the CODAP div is not at (0, 0) and when the page is scrolled,
   * the default Sproutcore mechanism for computing position does not give the desired
   * frame origin. This comes up when CODAP is used in embedded mode as in the ZiSci project.
   * Our fix is to use the jQuery 'offset' method to determine the offset regardless of positioning
   * and scrolling of CODAP div.
   *
   * Note that we are forgoing computation of possible scaling, which Sproutcore does do.
   * @override View.convertFrameToView
   */
  convertFrameToView: function (frame, targetView) {
    var tOffset = $(this.containerLayer()).offset();
    return { x: tOffset.left - window.pageXOffset, y: tOffset.top - window.pageYOffset, width: frame.width, height: frame.height };
  },

  computeDragOperations: function( iDrag) {
    if( this.isValidAttribute( iDrag))
      return SC.DRAG_LINK;
    else
      return SC.DRAG_NONE;
  },

  dragEntered: function( iDragObject, iEvent) {
    this.borderFrame.addClass('dg-graph-drop-frame-fill');
    this.showDropHint();
  },

  dragExited: function( iDragObject, iEvent) {
    this.borderFrame.removeClass('dg-graph-drop-frame-fill');
    this.hideDropHint();
  },

  acceptDragOperation: function() {
    return YES;
  },

  isValidAttributeForPlotSplit: function( iDrag) {
    var tDragAttr = iDrag.data.attribute,
        tCurrAtt = this.get('plottedAttribute'),
        tDragAttrIsNominal = tDragAttr.isNominal(),
        tDataConfiguration = this.getDataConfiguration(),
        tConfigurationHasAtLeastOneAttribute = tDataConfiguration &&
            tDataConfiguration.hasAtLeastOneAttributeAssigned(),
        tValidForPlotSplit = tDragAttrIsNominal && tConfigurationHasAtLeastOneAttribute &&
            tDragAttr !== tCurrAtt;
    return tValidForPlotSplit;
  },

  isValidAttribute: function( iDrag) {
    var tDragAttr = iDrag.data.attribute,
        tCurrAttr = this.get('plottedAttribute');
    return SC.none( tCurrAttr) || (tCurrAttr !== tDragAttr);
  },

  /**
   * Draw an orange frame to show we're a drop target.
   * Set the dropHintString for later display on dragEntered
   * @param iDrag {Object}
   */
  dragStarted: function( iDrag) {
    var tPaper = this.get('paper' );
    if (!tPaper) return;

    var kWidth = 3,
        tFrame,
        tDraggedName = iDrag.data.attribute.get('name'),
        tAttrName = this.getPath('plottedAttribute.name'),
        tDropHint;

    function isEmpty( iString) {
      return SC.empty( iString) || iString === 'undefined';
    }

    if( this.isValidAttribute( iDrag)) {
      if (this.get('orientation') === 'vertical2') {
        this.set('isVisible', true);
        var tParentView = this.get('parentView');
        if (tParentView)
          tParentView.makeSubviewFrontmost(this);
      }
      tDropHint = iDrag.data.attribute.isNominal() ? 'DG.GraphView.layoutPlotsVertically'.loc(tDraggedName) :
          (isEmpty(tAttrName) ? this.get('blankDropHint').loc(tDraggedName) :
              'DG.GraphView.replaceAttribute'.loc(tAttrName, tDraggedName));

      tFrame = {
        x: kWidth, y: kWidth,
        width: tPaper.width - 2 * kWidth,
        height: tPaper.height - 2 * kWidth
      };

      if (this.get('isVertical')) {
        tFrame.y += 18 + 2 * kWidth;
        tFrame.height -= 18 + 2 * kWidth;
      }

      if (SC.none(this.borderFrame)) {
        this.borderFrame = tPaper.path('')
            .addClass(this.kDropFrameClass);
      }
      this.borderFrame.attr({path: DG.RenderingUtilities.pathForFrame(tFrame)})
          .show();

      this.set('dropHintString', tDropHint);
    }
  },

  dragEnded: function() {
    if( this.borderFrame)
      this.borderFrame.hide();
  },

  /**
  @property{Raphael element}
  */
  borderFrame: null,

  /**
   * @property {String} - Display when dragged attribute is over this target
   */
  dropHintString: null,

  /**
   * @property {Raphael element}
   */
  dropHintElement: null,
  dropHintBox: null,

  isVertical: function() {
    var tOrientation = this.get('orientation');
    return tOrientation && ['vertical', 'vertical2', 'right'].indexOf( tOrientation) >= 0;
  }.property(),

  showDropHint: function() {
    if( SC.empty( this.dropHintString))
      return;
    var tPaper = this.get('paper' ),
        kPadding = 3,
        tX = tPaper.width / 2,
        tY = tPaper.height / 2;
    if( !this.dropHintElement) {
      this.dropHintBox = tPaper.rect( 0, 0, 0, 0, 3)
        .addClass( this.kDropBoxClass);
      this.dropHintElement = tPaper.text( tX, tY, this.dropHintString )
        .addClass( this.kDropHintClass);
    }
    this.dropHintBox.transform('');
    this.dropHintElement.transform('');
    this.dropHintElement.attr({ text: this.dropHintString, x: tX, y: tY });
    var tBBox = this.dropHintElement.getBBox();
    this.dropHintBox.attr({ x: tBBox.x - kPadding, y: tBBox.y - kPadding,
                          width: tBBox.width + 2 * kPadding, height: tBBox.height + 2 * kPadding });
    if( this.isVertical()) {
      this.dropHintBox.transform('R-90');
      this.dropHintElement.transform('R-90');
    }
    this.dropHintBox.toFront()
       .show();
    this.dropHintElement.toFront()
      .show();
  },

  hideDropHint: function() {
    if( this.dropHintElement) {
      this.dropHintElement.hide();
      this.dropHintBox.hide();
    }
  },

  /**
   Attempt to assign the given attribute to this axis.
   @param {SC.Drag} 'data' property contains 'collection', 'attribute', 'text' properties
   @param {SC.DRAG_LINK}
     */
  performDragOperation:function ( iDragObject, iDragOp ) {
    this.hideDropHint();
    this.set( 'dragData', iDragObject.data );
    return SC.DRAG_LINK;
  },

  /**
   * These methods -- externalDragDidChange, dataDragEntered, dataDragHovered,
   * dataDragDropped, and dataDragExited -- support drags initiated outside
   * the page, specifically drags from plugins.
   */
  _externalDragObject: function () {
    var data = DG.mainPage.getPath('mainPane.dragAttributeData');
    if (data) {
      return {
        data: data
      };
    }
  }.property(),
  externalDragDidChange: function () {
    var tDrag = this.get('_externalDragObject');
    if (!tDrag) {
      return;
    }
    if (DG.mainPage.getPath('mainPane._isDraggingAttr')) {
      this.dragStarted(tDrag);
    } else {
      this.dragEnded();
    }
  }.observes('DG.mainPage.mainPane._isDraggingAttr'),

  dataDragEntered: function (iEvent) {
    var externalDragObject = this.get('_externalDragObject');
    if (externalDragObject && this.isValidAttribute(externalDragObject)) {
      this.dragEntered(externalDragObject, iEvent);
      iEvent.preventDefault();
    }
  },
  dataDragHovered: function (iEvent) {
    var externalDragObject = this.get('_externalDragObject');
    if (externalDragObject && this.isValidAttribute(externalDragObject)) {
      iEvent.dataTransfer.dropEffect = 'copy';
      iEvent.preventDefault();
      iEvent.stopPropagation();
    } else {
      return false;
    }
  },
  dataDragDropped: function(iEvent) {
    var externalDragObject = this.get('_externalDragObject');
    var data;
    if (externalDragObject && this.isValidAttribute(externalDragObject)) {
      data = DG.mainPage.getPath('mainPane.dragAttributeData');
      this.hideDropHint();
      this.set('dragData', data);
      iEvent.preventDefault();
    } else {
      return false;
    }
  },
  dataDragExited: function (iEvent) {
    var externalDragObject = this.get('_externalDragObject');
    if (externalDragObject && this.isValidAttribute(externalDragObject)) {
      this.dragExited(externalDragObject, iEvent);
      iEvent.preventDefault();
    }
  }
};

<commit_msg>[#165860383] Bug fix: Horizontal axis hint says "Layout vertical"<commit_after>// ==========================================================================
//                          DG.GraphDropTarget
//
//  Author:   William Finzer
//
//  Copyright (c) 2014 by The Concord Consortium, Inc. All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// ==========================================================================

/** @class  Mixin to define behavior of graph subviews on drag

*/
DG.GraphDropTarget =
{
  kDropFrameClass: 'dg-graph-drop-frame',
  kDropHintClass: 'dg-graph-drop-hint',
  kDropBoxClass: 'dg-graph-drop-box',

  /**
   * Return the key to a localizable string to be displayed when the target has no current attribute
   */
  blankDropHint: '',

  // SC.DropTarget protocol
  isDropTarget: true,

  /**
   Graph controller observes this property to detect that a drag has taken place.
   @property{{collection:{DG.CollectionRecord}, attribute:{DG.Attribute}, text:{String},
   axisOrientation:{String} }}
   */
  dragData:null,

  getDataConfiguration: function() {
    return this.get('dataConfiguration') || this.getPath('model.dataConfiguration');
  },

  /**
   * Override SC.View for CODAP drop targets.
   * [CODAP fix] When the CODAP div is not at (0, 0) and when the page is scrolled,
   * the default Sproutcore mechanism for computing position does not give the desired
   * frame origin. This comes up when CODAP is used in embedded mode as in the ZiSci project.
   * Our fix is to use the jQuery 'offset' method to determine the offset regardless of positioning
   * and scrolling of CODAP div.
   *
   * Note that we are forgoing computation of possible scaling, which Sproutcore does do.
   * @override View.convertFrameToView
   */
  convertFrameToView: function (frame, targetView) {
    var tOffset = $(this.containerLayer()).offset();
    return { x: tOffset.left - window.pageXOffset, y: tOffset.top - window.pageYOffset, width: frame.width, height: frame.height };
  },

  computeDragOperations: function( iDrag) {
    if( this.isValidAttribute( iDrag))
      return SC.DRAG_LINK;
    else
      return SC.DRAG_NONE;
  },

  dragEntered: function( iDragObject, iEvent) {
    this.borderFrame.addClass('dg-graph-drop-frame-fill');
    this.showDropHint();
  },

  dragExited: function( iDragObject, iEvent) {
    this.borderFrame.removeClass('dg-graph-drop-frame-fill');
    this.hideDropHint();
  },

  acceptDragOperation: function() {
    return YES;
  },

  isValidAttributeForPlotSplit: function( iDrag) {
    var tDragAttr = iDrag.data.attribute,
        tCurrAtt = this.get('plottedAttribute'),
        tDragAttrIsNominal = tDragAttr.isNominal(),
        tDataConfiguration = this.getDataConfiguration(),
        tConfigurationHasAtLeastOneAttribute = tDataConfiguration &&
            tDataConfiguration.hasAtLeastOneAttributeAssigned(),
        tValidForPlotSplit = tDragAttrIsNominal && tConfigurationHasAtLeastOneAttribute &&
            tDragAttr !== tCurrAtt;
    return tValidForPlotSplit;
  },

  isValidAttribute: function( iDrag) {
    var tDragAttr = iDrag.data.attribute,
        tCurrAttr = this.get('plottedAttribute');
    return SC.none( tCurrAttr) || (tCurrAttr !== tDragAttr);
  },

  /**
   * Draw an orange frame to show we're a drop target.
   * Set the dropHintString for later display on dragEntered
   * @param iDrag {Object}
   */
  dragStarted: function( iDrag) {
    var tPaper = this.get('paper' );
    if (!tPaper) return;

    var kWidth = 3,
        tFrame,
        tDraggedName = iDrag.data.attribute.get('name'),
        tAttrName = this.getPath('plottedAttribute.name'),
        tOrientation = this.get('orientation'),
        tDropHint;

    function isEmpty( iString) {
      return SC.empty( iString) || iString === 'undefined';
    }

    if( this.isValidAttribute( iDrag)) {
      if (tOrientation === 'vertical2') {
        this.set('isVisible', true);
        var tParentView = this.get('parentView');
        if (tParentView)
          tParentView.makeSubviewFrontmost(this);
      }
      if(iDrag.data.attribute.isNominal()) {
        if(tOrientation === 'vertical' || tOrientation === 'vertical2')
          tDropHint = 'DG.GraphView.layoutPlotsVertically'.loc(tDraggedName);
        else tDropHint = 'DG.GraphView.layoutPlotsSideBySide'.loc(tDraggedName)
      }
      else {
        tDropHint = (isEmpty(tAttrName) ? this.get('blankDropHint').loc(tDraggedName) :
            'DG.GraphView.replaceAttribute'.loc(tAttrName, tDraggedName));
      }

      tFrame = {
        x: kWidth, y: kWidth,
        width: tPaper.width - 2 * kWidth,
        height: tPaper.height - 2 * kWidth
      };

      if (this.get('isVertical')) {
        tFrame.y += 18 + 2 * kWidth;
        tFrame.height -= 18 + 2 * kWidth;
      }

      if (SC.none(this.borderFrame)) {
        this.borderFrame = tPaper.path('')
            .addClass(this.kDropFrameClass);
      }
      this.borderFrame.attr({path: DG.RenderingUtilities.pathForFrame(tFrame)})
          .show();

      this.set('dropHintString', tDropHint);
    }
  },

  dragEnded: function() {
    if( this.borderFrame)
      this.borderFrame.hide();
  },

  /**
  @property{Raphael element}
  */
  borderFrame: null,

  /**
   * @property {String} - Display when dragged attribute is over this target
   */
  dropHintString: null,

  /**
   * @property {Raphael element}
   */
  dropHintElement: null,
  dropHintBox: null,

  isVertical: function() {
    var tOrientation = this.get('orientation');
    return tOrientation && ['vertical', 'vertical2', 'right'].indexOf( tOrientation) >= 0;
  }.property(),

  showDropHint: function() {
    if( SC.empty( this.dropHintString))
      return;
    var tPaper = this.get('paper' ),
        kPadding = 3,
        tX = tPaper.width / 2,
        tY = tPaper.height / 2;
    if( !this.dropHintElement) {
      this.dropHintBox = tPaper.rect( 0, 0, 0, 0, 3)
        .addClass( this.kDropBoxClass);
      this.dropHintElement = tPaper.text( tX, tY, this.dropHintString )
        .addClass( this.kDropHintClass);
    }
    this.dropHintBox.transform('');
    this.dropHintElement.transform('');
    this.dropHintElement.attr({ text: this.dropHintString, x: tX, y: tY });
    var tBBox = this.dropHintElement.getBBox();
    this.dropHintBox.attr({ x: tBBox.x - kPadding, y: tBBox.y - kPadding,
                          width: tBBox.width + 2 * kPadding, height: tBBox.height + 2 * kPadding });
    if( this.isVertical()) {
      this.dropHintBox.transform('R-90');
      this.dropHintElement.transform('R-90');
    }
    this.dropHintBox.toFront()
       .show();
    this.dropHintElement.toFront()
      .show();
  },

  hideDropHint: function() {
    if( this.dropHintElement) {
      this.dropHintElement.hide();
      this.dropHintBox.hide();
    }
  },

  /**
   Attempt to assign the given attribute to this axis.
   @param {SC.Drag} 'data' property contains 'collection', 'attribute', 'text' properties
   @param {SC.DRAG_LINK}
     */
  performDragOperation:function ( iDragObject, iDragOp ) {
    this.hideDropHint();
    this.set( 'dragData', iDragObject.data );
    return SC.DRAG_LINK;
  },

  /**
   * These methods -- externalDragDidChange, dataDragEntered, dataDragHovered,
   * dataDragDropped, and dataDragExited -- support drags initiated outside
   * the page, specifically drags from plugins.
   */
  _externalDragObject: function () {
    var data = DG.mainPage.getPath('mainPane.dragAttributeData');
    if (data) {
      return {
        data: data
      };
    }
  }.property(),
  externalDragDidChange: function () {
    var tDrag = this.get('_externalDragObject');
    if (!tDrag) {
      return;
    }
    if (DG.mainPage.getPath('mainPane._isDraggingAttr')) {
      this.dragStarted(tDrag);
    } else {
      this.dragEnded();
    }
  }.observes('DG.mainPage.mainPane._isDraggingAttr'),

  dataDragEntered: function (iEvent) {
    var externalDragObject = this.get('_externalDragObject');
    if (externalDragObject && this.isValidAttribute(externalDragObject)) {
      this.dragEntered(externalDragObject, iEvent);
      iEvent.preventDefault();
    }
  },
  dataDragHovered: function (iEvent) {
    var externalDragObject = this.get('_externalDragObject');
    if (externalDragObject && this.isValidAttribute(externalDragObject)) {
      iEvent.dataTransfer.dropEffect = 'copy';
      iEvent.preventDefault();
      iEvent.stopPropagation();
    } else {
      return false;
    }
  },
  dataDragDropped: function(iEvent) {
    var externalDragObject = this.get('_externalDragObject');
    var data;
    if (externalDragObject && this.isValidAttribute(externalDragObject)) {
      data = DG.mainPage.getPath('mainPane.dragAttributeData');
      this.hideDropHint();
      this.set('dragData', data);
      iEvent.preventDefault();
    } else {
      return false;
    }
  },
  dataDragExited: function (iEvent) {
    var externalDragObject = this.get('_externalDragObject');
    if (externalDragObject && this.isValidAttribute(externalDragObject)) {
      this.dragExited(externalDragObject, iEvent);
      iEvent.preventDefault();
    }
  }
};

<|endoftext|>