<commit_before>import React from 'react';
import { StyleSheet, Text, Image, View, ListView, TouchableHighlight } from 'react-native';

export default ({tweets, stateNavigator}) => {
  const dataSource = new ListView
    .DataSource({rowHasChanged: (r1, r2) => r1 !== r2})
    .cloneWithRows(tweets);
  return (
    <View style={styles.view}>
      <Text style={styles.home}>Home</Text>
      <ListView
        dataSource={dataSource}
        renderRow={tweet => <Tweet {...tweet} stateNavigator={stateNavigator} />} />
    </View>
  );
};

const Tweet = ({id, name, logo, text, stateNavigator}) => (
  <TouchableHighlight underlayColor="white" onPress={() => {
    stateNavigator.navigate('tweet', {id});
  }}>
    <View style={styles.tweet}>
      <Image
        style={styles.logo}
        source={{uri: logo}}
      />
      <View style={styles.details}>
        <Text style={styles.name}>{name}</Text>
        <Text>{text}</Text>
      </View>
    </View>
  </TouchableHighlight>
);

const styles = StyleSheet.create({
  home: {
    paddingTop: 10,
    fontSize: 50,
    marginTop: 50,
  },
  tweet: {
    flexDirection: 'row',
    padding: 10,
    borderBottomColor: '#ccd6dd',
    borderBottomWidth: 1,
  },
  details: {
    flex: 1,
  },
  name: {
    fontWeight: 'bold',
  },
  logo: {
    width: 50,
    height: 50,
    borderRadius: 8,
    marginRight: 8,
  },
});
<commit_msg>Tweaked format<commit_after>import React from 'react';
import { StyleSheet, Text, Image, View, ListView, TouchableHighlight } from 'react-native';

export default ({tweets, stateNavigator}) => {
  const dataSource = new ListView
    .DataSource({rowHasChanged: (r1, r2) => r1 !== r2})
    .cloneWithRows(tweets);
  return (
    <View style={styles.view}>
      <Text style={styles.home}>Home</Text>
      <ListView
        dataSource={dataSource}
        renderRow={tweet => (
          <Tweet
            {...tweet}
            stateNavigator={stateNavigator} />
        )} />
    </View>
  );
};

const Tweet = ({id, name, logo, text, stateNavigator}) => (
  <TouchableHighlight
    underlayColor="white"
    onPress={() => {
      stateNavigator.navigate('tweet', {id});
  }}>
    <View style={styles.tweet}>
      <Image
        style={styles.logo}
        source={{uri: logo}}
      />
      <View style={styles.details}>
        <Text style={styles.name}>{name}</Text>
        <Text>{text}</Text>
      </View>
    </View>
  </TouchableHighlight>
);

const styles = StyleSheet.create({
  home: {
    paddingTop: 10,
    fontSize: 50,
    marginTop: 50,
  },
  tweet: {
    flexDirection: 'row',
    padding: 10,
    borderBottomColor: '#ccd6dd',
    borderBottomWidth: 1,
  },
  details: {
    flex: 1,
  },
  name: {
    fontWeight: 'bold',
  },
  logo: {
    width: 50,
    height: 50,
    borderRadius: 8,
    marginRight: 8,
  },
});
<|endoftext|>


<commit_before>snd.CLASS_DEF.push(function() {
    /**
     * 新しくオシレータ音源を生成します。
     * @class 任意の波形を再生するオシレータ音源を扱うクラスです。

     * snd.OscillatorSource.SINEなどの定数値でサイン波・矩形波・のこぎり波・三角波を設定できる他、波形はPeriodicWaveクラスでも定義が可能です。
     * @property {AudioParam} frequencyParam このOscillatorの周波数を変更するためのAudioParamです。他のAudioUnitの出力をこのOscillatorの周波数の値に渡す場合などに使用するためのもので、このプロパティに直接値を代入することはできません。

     * Oscillatorに具体的な周波数を設定したい場合は、frequencyプロパティを使用してください。

     * oscillatorが初期化されていない場合、undefinedが戻ります。
     * @property {Number} frequency このOscillatorの周波数です。

     * frequencyParamとは異なり、数値を直接渡すことが可能です。

     * 単位は[hz]です。

     * oscillatorが初期化されていない場合、undefinedが戻ります。
     * @property {AudioParam} detumeParam このOscillatorの周波数を変更するためのAudioParamです。他のAudioUnitの出力をこのOscillatorの周波数の値に渡す場合などに使用するためのもので、このプロパティに直接値を代入することはできません。

     * Oscillatorに具体的な値を設定したい場合は、detuneプロパティを使用してください。

     * oscillatorが初期化されていない場合、undefinedが戻ります。
     * @property {Number} detune このOscillatorのdetuneです。

     * frequencyに対して、音程の微妙な調整を行いたい場合に使用する値です。

     * detuneParamとは異なり、数値を直接渡すことが可能です。

     * 単位は[cent]です。（cent … 1/1200オクターブ。半音の1/100）

     * oscillatorが初期化されていない場合、undefinedが戻ります。
     * @param {String} id この音源をあらわすID
     */
    snd.OscillatorSource = function(id) {
        snd.Source.apply(this, arguments);

        this._periodicWave = null;
        this._source = null;

        this.listeners = {
            onended: []
        };

        Object.defineProperties(this, {
            periodicWave: {
                get: function() {
                    var ret = {};
                    ret.realArray = this._status.periodicWave.realArray;
                    ret.imagArray = this._status.periodicWave.imagArray;
                    return ret;
                },
                set: function(val) {
                    if (val == null) {
                        this._periodicWave = null;
                        this._status.periodicWave = null;

                        if (this._status.oscillatorType == snd.OscillatorSource.CUSTOM) {
                            this._status.oscillatorType = null;
                        }

                        this.setWaveForm();
                    } else if (val.realArray == null || val.imagArray == null) {
                        console.warn("periodicWave property must have realArray and imagArray.");
                    } else {
                        this._status.periodicWave = {
                            realArray: val.realArray,
                            imagArray: val.imagArray
                        };

                        this._status.oscillatorType = snd.OscillatorSource.CUSTOM;

                        this.setWaveForm();
                    }
                }
            },
            periodicWaveParam: {
                get: function() {
                    return this._periodicWave;
                }
            },
            oscillatorType: {
                get: function() {
                    return this._status.oscillatorType;
                },
                set: function(val) {
                    this._status.oscillatorType = val;

                    this._periodicWave = null;
                    this._status.periodicWave = null;
                }
            },
            frequency: {
                get: function() {
                    if (this._source != null) {
                        return this._source.frequency.value;
                    } else {
                        return undefined;
                    }
                },
                set: function(val) {
                    if (this._source != null) {
                        this._source.frequency.value = (val == null) ? 0.0 : val;
                        this._status.frequency = this._source.frequency.value;
                    }
                }
            },
            frequencyParam: {
                get: function() {
                    if (this._source != null) {
                        if (this._source.detune.id == null) {
                            this._source.detune.id = this.id + ".frequency";
                        }
                        return this._source.frequency;
                    } else {
                        return undefined;
                    }
                }
            },
            detune: {
                get: function() {
                    if (this._source != null) {
                        return this._source.detune.value;
                    } else {
                        return undefined;
                    }
                },
                set: function(val) {
                    if (this._source != null) {
                        this._source.detune.value = val;
                        this._status.detune = val;
                    }
                }
            },
            detuneParam: {
                get: function() {
                    if (this._source != null) {
                        if (this._source.detune.id == null) {
                            this._source.detune.id = this.id + ".detune";
                        }
                        return this._source.detune;
                    } else {
                        return undefined;
                    }
                }
            }
        });

        this.resetOscillator();
    };
    snd.OscillatorSource.prototype = Object.create(snd.Source.prototype);
    snd.OscillatorSource.prototype.constructor = snd.OscillatorSource;

    snd.OscillatorSource.CLASS_NAME = "snd.OscillatorSource";

    /**
     * 基準となる周波数(440Hz)です。
     * @type Number
     * @memberOf snd.OscillatorSource
     */
    snd.OscillatorSource.DEFAULT_FREQUENCY = 440;

    /**
     * サイン波を表す定数値です。
     * @type String
     * @memberOf snd.OscillatorSource
     */
    snd.OscillatorSource.SINE = "sine";
    /**
     * 矩形波を表す定数値です。
     * @type String
     * @memberOf snd.OscillatorSource
     */
    snd.OscillatorSource.SQUARE = "square";
    /**
     * のこぎり波を表す定数値です。
     * @type String
     * @memberOf snd.OscillatorSource
     */
    snd.OscillatorSource.SAWTOOTH = "sawtooth";
    /**
     * 三角波を表す定数値です。
     * @type String
     * @memberOf snd.OscillatorSource
     */
    snd.OscillatorSource.TRIANGLE = "triangle";
    /**
     * 波形にPeriodicWaveを使用している場合にoscillatorTypeに自動で設定される値です。

     * この定数は判定に使用するために用意したもので、波形の指定には使用しないでください。
     * @type String
     * @memberOf snd.OscillatorSource
     */
    snd.OscillatorSource.CUSTOM = "custom";

    snd.OscillatorSource.prototype.setWaveForm = function() {
        if (this._status.periodicWave != null) {
            this._periodicWave = snd.AUDIO_CONTEXT.createPeriodicWave(this._status.periodicWave.realArray, this._status.periodicWave.imagArray);
            this._source.setPeriodicWave(this._periodicWave);
        } else if (this._status.oscillatorType != null && this._status.oscillatorType != snd.OscillatorSource.CUSTOM) {
            this._source.type = this._status.oscillatorType;
        } else {
            this._source.type = snd.OscillatorSource.SINE;
            this._status.oscillatorType = snd.OscillatorSource.SINE;
            this._status.periodicWave = null;
            this._periodicWave = null;
        }
    };

    /**
     * 波形の種類を設定します。

     * 引数には、snd.oscillatortype.SINE, snd.oscillatortype.SQUARE, snd.oscillatortype.SAWTOOTH, snd.oscillatortype.TRIANGLEのいずれかを設定してください。
     * @param {OscillatorType} oscillatorType
     * @deprecated oscillatorTypeプロパティを使用してください。
     */
    snd.OscillatorSource.prototype.setOscillatorType = function(oscillatorType) {
        if (this._source != null) {
            this._source.type = oscillatorType;
        }
    };

    /**
     * このオシレータの波形の種類を返します。

     * @returns {String} 波形の種類
     * @deprecated oscillatorTypeプロパティを使用してください。
     */
    snd.OscillatorSource.prototype.getOscillatorType = function() {
        return this.oscillatorType;
    };

    /**
     * 周波数を設定します。
     * @param {type} hz 周波数[Hz]
     * @deprecated frequencyプロパティを使用してください。
     */
    snd.OscillatorSource.prototype.setFrequency = function(hz) {
        this.frequency = hz;
    };

    /**
     * 現在の周波数を取得します。
     * @returns {Number} 周波数[Hz]
     * @deprecated frequencyプロパティを使用してください。
     */
    snd.OscillatorSource.prototype.getFrequency = function() {
        return this.frequency;
    };

    /**
     * ピッチシフトの量を設定します。

     * 単位はセントです。
     * @param {Number} ピッチシフトの量 [cent]
     * @deprecated detuneプロパティを使用してください。
     */
    snd.OscillatorSource.prototype.setDetune = function(cent) {
        this.detune = cent;
    };

    /**
     * ピッチシフトの量を取得します

     * 単位はセントです。
     * @returns {Number} ピッチシフトの量 [cent]
     * @deprecated detuneプロパティを使用してください。
     */
    snd.OscillatorSource.prototype.getDetune = function() {
        return this.detune;
    };

    /**
     * フーリエ級数で表された波形を、このオシレータの波形として設定します。

     * @param {Float32Array} realArray フーリエ級数の実数部の配列
     * @param {Float32Array} imagArray フーリエ級数の虚数部の配列
     * @deprecated periodicWaveプロパティを使用してください。
     */
    snd.OscillatorSource.prototype.setPeriodicWave = function(realArray, imagArray) {
        this.periodicWave = {
            realArray: realArray,
            imagArray: imagArray
        };
    };

    /**
     * この音源の波形データを返します。
     * @returns {Object} 実数配列と虚数配列をまとめたオブジェクト（ret = {realArray:Float32Array, imagArray:Float32Array}）
     * @deprecated periodicWaveプロパティを使用してください。
     */
    snd.OscillatorSource.prototype.getPeriodicWave = function() {
        return this._periodicWave;
    }

    /**
     * 波形の再生をスタートします。
     *
     * @param {float} when 開始時刻 [秒]
     * @param {type} offset 使用しません
     * @param {type} duration 使用しません
     */
    snd.OscillatorSource.prototype.start = function(when, offset, duration) {
        if (this.status == snd.status.STOPPED) {
            this.resetOscillator();
        }

        if (this._source != null && this.status != snd.status.STARTED && this.status != snd.status.STOPPED) {
            if (when == null) {
                this._source.start(0);
            } else {
                this._source.start(when);
            }
            this._status.status = snd.status.STARTED;
        }
    };

    /**
     * 波形の出力を停止します。

     * !!注意!!

     * stopメソッドを使って波形の出力を停止すると、再度startメソッドを使っても
     * @param {float} when 終了するタイミング
     */
    snd.OscillatorSource.prototype.stop = function(when) {
        if (this.status == snd.status.STARTED) {
            if (when == null) {
                this._source.stop(0);
            } else {
                this._source.stop(when);
            }
            this._status.status = snd.status.STOPPED;
        }
    };

    snd.OscillatorSource.prototype.resetOscillator = function() {
        var _this = this;

        if (this._source != null) {
            if (this.status == snd.status.STARTED) {
                this.stop(0);
            }
        }

        this._source = snd.AUDIO_CONTEXT.createOscillator();
        this._source.onended = function() {
            _this.fireOnEndedEvent();
        };

        this.setWaveForm();

        this._source.connect(this._gain);

        this._status.status = snd.status.READY;
    };

    /* Add/Remove Event Listener Methods */

    snd.OscillatorSource.prototype.addOnEndedEventListener = function(listener) {
        this.listeners['onended'].push(listener);
    };

    snd.OscillatorSource.prototype.removeOnEndedEventListener = function(listener) {
        var a = this.listeners['onended'];
        for (var i = 0; i < a.length; i++) {
            if (a[i] === listener) {
                a.splice(i, 1);
                break;
            }
        }
    };

    snd.OscillatorSource.prototype.fireOnEndedEvent = function() {
        var listeners = this.listeners['onended'];
        for (var i = 0; i < listeners; i++) {
            listeners[i](this);
        }
    };

    snd.OscillatorSource.prototype.createStatus = function() {
        return new snd.OscillatorSource.Status();
    };

    snd.OscillatorSource.prototype.toJSON = function() {
        return this._status;
    };

    snd.OscillatorSource.prototype.loadData = function(data) {
        snd.Source.prototype.loadData.apply(this, arguments);

        if (data.periodicWave != null) {
            this._status.periodicWave = data.periodicWave;
            this._status.oscillatorType = snd.OscillatorSource.CUSTOM;
        } else {
            this._status.oscillatorType = data.oscillatorType;
            this._status.periodicWave = null;
        }

        this.setWaveForm();

        this.frequency = data.frequency;
        this.detune = data.detune;
    };

    snd.OscillatorSource.loadJSON = function(json) {
        var data = JSON.parse(json);
        if (data.className != snd.OscillatorSource.CLASS_NAME) {
            throw new snd.Exception(data.id + " is not instance of 'snd.OscillatorSource' class.");
        }

        var ret = new snd.OscillatorSource("");
        ret.loadData(data);
        return ret;
    };

    snd.OscillatorSource.Status = function() {
        snd.Source.Status.apply(this, arguments);

        this.className = snd.OscillatorSource.CLASS_NAME;
        this.type = snd.srctype.OSCILLATOR;
        this.status = snd.status.NONE;

        this.periodicWave = null;

        this.oscillatorType = null;

        this.frequency = snd.OscillatorSource.DEFAULT_FREQUENCY;
        this.detune = 0.0;
    };
});
<commit_msg>プロパティ frequency, detuneをparseFloatしてから設定するように変更<commit_after>snd.CLASS_DEF.push(function() {
    /**
     * 新しくオシレータ音源を生成します。
     * @class 任意の波形を再生するオシレータ音源を扱うクラスです。

     * snd.OscillatorSource.SINEなどの定数値でサイン波・矩形波・のこぎり波・三角波を設定できる他、波形はPeriodicWaveクラスでも定義が可能です。
     * @property {AudioParam} frequencyParam このOscillatorの周波数を変更するためのAudioParamです。他のAudioUnitの出力をこのOscillatorの周波数の値に渡す場合などに使用するためのもので、このプロパティに直接値を代入することはできません。

     * Oscillatorに具体的な周波数を設定したい場合は、frequencyプロパティを使用してください。

     * oscillatorが初期化されていない場合、undefinedが戻ります。
     * @property {Number} frequency このOscillatorの周波数です。

     * frequencyParamとは異なり、数値を直接渡すことが可能です。

     * 単位は[hz]です。

     * oscillatorが初期化されていない場合、undefinedが戻ります。
     * @property {AudioParam} detumeParam このOscillatorの周波数を変更するためのAudioParamです。他のAudioUnitの出力をこのOscillatorの周波数の値に渡す場合などに使用するためのもので、このプロパティに直接値を代入することはできません。

     * Oscillatorに具体的な値を設定したい場合は、detuneプロパティを使用してください。

     * oscillatorが初期化されていない場合、undefinedが戻ります。
     * @property {Number} detune このOscillatorのdetuneです。

     * frequencyに対して、音程の微妙な調整を行いたい場合に使用する値です。

     * detuneParamとは異なり、数値を直接渡すことが可能です。

     * 単位は[cent]です。（cent … 1/1200オクターブ。半音の1/100）

     * oscillatorが初期化されていない場合、undefinedが戻ります。
     * @param {String} id この音源をあらわすID
     */
    snd.OscillatorSource = function(id) {
        snd.Source.apply(this, arguments);

        this._periodicWave = null;
        this._source = null;

        this.listeners = {
            onended: []
        };

        Object.defineProperties(this, {
            periodicWave: {
                get: function() {
                    var ret = {};
                    ret.realArray = this._status.periodicWave.realArray;
                    ret.imagArray = this._status.periodicWave.imagArray;
                    return ret;
                },
                set: function(val) {
                    if (val == null) {
                        this._periodicWave = null;
                        this._status.periodicWave = null;

                        if (this._status.oscillatorType == snd.OscillatorSource.CUSTOM) {
                            this._status.oscillatorType = null;
                        }

                        this.setWaveForm();
                    } else if (val.realArray == null || val.imagArray == null) {
                        console.warn("periodicWave property must have realArray and imagArray.");
                    } else {
                        this._status.periodicWave = {
                            realArray: val.realArray,
                            imagArray: val.imagArray
                        };

                        this._status.oscillatorType = snd.OscillatorSource.CUSTOM;

                        this.setWaveForm();
                    }
                }
            },
            periodicWaveParam: {
                get: function() {
                    return this._periodicWave;
                }
            },
            oscillatorType: {
                get: function() {
                    return this._status.oscillatorType;
                },
                set: function(val) {
                    this._status.oscillatorType = val;

                    this._periodicWave = null;
                    this._status.periodicWave = null;
                }
            },
            frequency: {
                get: function() {
                    if (this._source != null) {
                        return this._source.frequency.value;
                    } else {
                        return undefined;
                    }
                },
                set: function(val) {
                    if (this._source != null) {
                        this._source.frequency.value = (val) ? parseFloat(val) : 0.0;
                        this._status.frequency = this._source.frequency.value;
                    }
                }
            },
            frequencyParam: {
                get: function() {
                    if (this._source != null) {
                        if (this._source.detune.id == null) {
                            this._source.detune.id = this.id + ".frequency";
                        }
                        return this._source.frequency;
                    } else {
                        return undefined;
                    }
                }
            },
            detune: {
                get: function() {
                    if (this._source != null) {
                        return this._source.detune.value;
                    } else {
                        return undefined;
                    }
                },
                set: function(val) {
                    if (this._source != null) {
                        this._source.detune.value = (val) ? parseFloat(val) : 0.0;
                        this._status.detune = val;
                    }
                }
            },
            detuneParam: {
                get: function() {
                    if (this._source != null) {
                        if (this._source.detune.id == null) {
                            this._source.detune.id = this.id + ".detune";
                        }
                        return this._source.detune;
                    } else {
                        return undefined;
                    }
                }
            }
        });

        this.resetOscillator();
    };
    snd.OscillatorSource.prototype = Object.create(snd.Source.prototype);
    snd.OscillatorSource.prototype.constructor = snd.OscillatorSource;

    snd.OscillatorSource.CLASS_NAME = "snd.OscillatorSource";

    /**
     * 基準となる周波数(440Hz)です。
     * @type Number
     * @memberOf snd.OscillatorSource
     */
    snd.OscillatorSource.DEFAULT_FREQUENCY = 440;

    /**
     * サイン波を表す定数値です。
     * @type String
     * @memberOf snd.OscillatorSource
     */
    snd.OscillatorSource.SINE = "sine";
    /**
     * 矩形波を表す定数値です。
     * @type String
     * @memberOf snd.OscillatorSource
     */
    snd.OscillatorSource.SQUARE = "square";
    /**
     * のこぎり波を表す定数値です。
     * @type String
     * @memberOf snd.OscillatorSource
     */
    snd.OscillatorSource.SAWTOOTH = "sawtooth";
    /**
     * 三角波を表す定数値です。
     * @type String
     * @memberOf snd.OscillatorSource
     */
    snd.OscillatorSource.TRIANGLE = "triangle";
    /**
     * 波形にPeriodicWaveを使用している場合にoscillatorTypeに自動で設定される値です。

     * この定数は判定に使用するために用意したもので、波形の指定には使用しないでください。
     * @type String
     * @memberOf snd.OscillatorSource
     */
    snd.OscillatorSource.CUSTOM = "custom";

    snd.OscillatorSource.prototype.setWaveForm = function() {
        if (this._status.periodicWave != null) {
            this._periodicWave = snd.AUDIO_CONTEXT.createPeriodicWave(this._status.periodicWave.realArray, this._status.periodicWave.imagArray);
            this._source.setPeriodicWave(this._periodicWave);
        } else if (this._status.oscillatorType != null && this._status.oscillatorType != snd.OscillatorSource.CUSTOM) {
            this._source.type = this._status.oscillatorType;
        } else {
            this._source.type = snd.OscillatorSource.SINE;
            this._status.oscillatorType = snd.OscillatorSource.SINE;
            this._status.periodicWave = null;
            this._periodicWave = null;
        }
    };

    /**
     * 波形の種類を設定します。

     * 引数には、snd.oscillatortype.SINE, snd.oscillatortype.SQUARE, snd.oscillatortype.SAWTOOTH, snd.oscillatortype.TRIANGLEのいずれかを設定してください。
     * @param {OscillatorType} oscillatorType
     * @deprecated oscillatorTypeプロパティを使用してください。
     */
    snd.OscillatorSource.prototype.setOscillatorType = function(oscillatorType) {
        if (this._source != null) {
            this._source.type = oscillatorType;
        }
    };

    /**
     * このオシレータの波形の種類を返します。

     * @returns {String} 波形の種類
     * @deprecated oscillatorTypeプロパティを使用してください。
     */
    snd.OscillatorSource.prototype.getOscillatorType = function() {
        return this.oscillatorType;
    };

    /**
     * 周波数を設定します。
     * @param {type} hz 周波数[Hz]
     * @deprecated frequencyプロパティを使用してください。
     */
    snd.OscillatorSource.prototype.setFrequency = function(hz) {
        this.frequency = hz;
    };

    /**
     * 現在の周波数を取得します。
     * @returns {Number} 周波数[Hz]
     * @deprecated frequencyプロパティを使用してください。
     */
    snd.OscillatorSource.prototype.getFrequency = function() {
        return this.frequency;
    };

    /**
     * ピッチシフトの量を設定します。

     * 単位はセントです。
     * @param {Number} ピッチシフトの量 [cent]
     * @deprecated detuneプロパティを使用してください。
     */
    snd.OscillatorSource.prototype.setDetune = function(cent) {
        this.detune = cent;
    };

    /**
     * ピッチシフトの量を取得します

     * 単位はセントです。
     * @returns {Number} ピッチシフトの量 [cent]
     * @deprecated detuneプロパティを使用してください。
     */
    snd.OscillatorSource.prototype.getDetune = function() {
        return this.detune;
    };

    /**
     * フーリエ級数で表された波形を、このオシレータの波形として設定します。

     * @param {Float32Array} realArray フーリエ級数の実数部の配列
     * @param {Float32Array} imagArray フーリエ級数の虚数部の配列
     * @deprecated periodicWaveプロパティを使用してください。
     */
    snd.OscillatorSource.prototype.setPeriodicWave = function(realArray, imagArray) {
        this.periodicWave = {
            realArray: realArray,
            imagArray: imagArray
        };
    };

    /**
     * この音源の波形データを返します。
     * @returns {Object} 実数配列と虚数配列をまとめたオブジェクト（ret = {realArray:Float32Array, imagArray:Float32Array}）
     * @deprecated periodicWaveプロパティを使用してください。
     */
    snd.OscillatorSource.prototype.getPeriodicWave = function() {
        return this._periodicWave;
    }

    /**
     * 波形の再生をスタートします。
     *
     * @param {float} when 開始時刻 [秒]
     * @param {type} offset 使用しません
     * @param {type} duration 使用しません
     */
    snd.OscillatorSource.prototype.start = function(when, offset, duration) {
        if (this.status == snd.status.STOPPED) {
            this.resetOscillator();
        }

        if (this._source != null && this.status != snd.status.STARTED && this.status != snd.status.STOPPED) {
            if (when == null) {
                this._source.start(0);
            } else {
                this._source.start(when);
            }
            this._status.status = snd.status.STARTED;
        }
    };

    /**
     * 波形の出力を停止します。

     * !!注意!!

     * stopメソッドを使って波形の出力を停止すると、再度startメソッドを使っても
     * @param {float} when 終了するタイミング
     */
    snd.OscillatorSource.prototype.stop = function(when) {
        if (this.status == snd.status.STARTED) {
            if (when == null) {
                this._source.stop(0);
            } else {
                this._source.stop(when);
            }
            this._status.status = snd.status.STOPPED;
        }
    };

    snd.OscillatorSource.prototype.resetOscillator = function() {
        var _this = this;

        if (this._source != null) {
            if (this.status == snd.status.STARTED) {
                this.stop(0);
            }
        }

        this._source = snd.AUDIO_CONTEXT.createOscillator();
        this._source.onended = function() {
            _this.fireOnEndedEvent();
        };

        this.setWaveForm();

        this._source.connect(this._gain);

        this._status.status = snd.status.READY;
    };

    /* Add/Remove Event Listener Methods */

    snd.OscillatorSource.prototype.addOnEndedEventListener = function(listener) {
        this.listeners['onended'].push(listener);
    };

    snd.OscillatorSource.prototype.removeOnEndedEventListener = function(listener) {
        var a = this.listeners['onended'];
        for (var i = 0; i < a.length; i++) {
            if (a[i] === listener) {
                a.splice(i, 1);
                break;
            }
        }
    };

    snd.OscillatorSource.prototype.onended = function(oscillator) {
    };

    snd.OscillatorSource.prototype.fireOnEndedEvent = function() {
        if (typeof(this.onended) == "function") {
            this.onended(this);
        }

        var listeners = this.listeners['onended'];
        for (var i = 0; i < listeners; i++) {
            if (typeof(listeners[i]) == "function") {
                listeners[i](this);
            }
        }
    };

    snd.OscillatorSource.prototype.createStatus = function() {
        return new snd.OscillatorSource.Status();
    };

    snd.OscillatorSource.prototype.toJSON = function() {
        return this._status;
    };

    snd.OscillatorSource.prototype.loadData = function(data) {
        snd.Source.prototype.loadData.apply(this, arguments);

        if (data.periodicWave != null) {
            this._status.periodicWave = data.periodicWave;
            this._status.oscillatorType = snd.OscillatorSource.CUSTOM;
        } else {
            this._status.oscillatorType = data.oscillatorType;
            this._status.periodicWave = null;
        }

        this.setWaveForm();

        this.frequency = data.frequency;
        this.detune = data.detune;
    };

    snd.OscillatorSource.loadJSON = function(json) {
        var data = JSON.parse(json);
        if (data.className != snd.OscillatorSource.CLASS_NAME) {
            throw new snd.Exception(data.id + " is not instance of 'snd.OscillatorSource' class.");
        }

        var ret = new snd.OscillatorSource("");
        ret.loadData(data);
        return ret;
    };

    snd.OscillatorSource.Status = function() {
        snd.Source.Status.apply(this, arguments);

        this.className = snd.OscillatorSource.CLASS_NAME;
        this.type = snd.srctype.OSCILLATOR;
        this.status = snd.status.NONE;

        this.periodicWave = null;

        this.oscillatorType = null;

        this.frequency = snd.OscillatorSource.DEFAULT_FREQUENCY;
        this.detune = 0.0;
    };
});
<|endoftext|>


<commit_before>import _ from 'lodash';
import initialMatrix from '../data.json';

// let matrixUsed = {};

// if(window.localStorage.loadSequence !== 'undefined'){
//   console.log('local storage set');
//   matrixUsed = JSON.parse(window.localStorage.loadSequence);
//   window.localStorage.loadSequence = undefined;
// }else {
//    console.log('local storage not set');
//   matrixUsed = initialMatrix;
// }

export default (state = initialMatrix, action) => {
  const newSequence = _.cloneDeep(state);

  switch (action.type){
    case "TOGGLE_SAMPLE":
    	const index = action.payload;
			// mutate toggle
			newSequence.matrix[index[0]][index[1]].toggled = !newSequence.matrix[index[0]][index[1]].toggled;

			// mutate class
			if(newSequence.matrix[index[0]][index[1]].class === 'step-tf'){
				newSequence.matrix[index[0]][index[1]].class = 'step-tt';
			} else if (newSequence.matrix[index[0]][index[1]].class === 'step-tt'){
				newSequence.matrix[index[0]][index[1]].class = 'step-tf';
			} else if (newSequence.matrix[index[0]][index[1]].class === 'step-mtt'){
        newSequence.matrix[index[0]][index[1]].class = 'step-mtf';
      }  else if (newSequence.matrix[index[0]][index[1]].class === 'step-mtf'){
        newSequence.matrix[index[0]][index[1]].class = 'step-mtt';
      }

      return newSequence;

    case "MUTE_TOGGLE":
      const muteIndex = action.payload;

      newSequence.matrix[muteIndex].forEach((step, index)=>{
        if(step.class === 'step-tt'){
          step.class = 'step-mtt';
        }else if (step.class === 'step-tf'){
          step.class = 'step-mtf';
        } else if (step.class === 'step-mtt'){
          step.class = 'step-tt';
        } else if (step.class === 'step-mtf'){
          step.class = 'step-tf';
        }
        console.log(step.class);
      });

     return newSequence;

    case "CHANGE_SAMPLE":
      console.log('change sample');
      newSequence.samples[action.sampleIndex] = action.sound;
      return newSequence;

    case "LOAD_PROFILE_SEQUENCE":
      console.log('add from profile');
      return action.payload.matrix;

    case "ADD_TRACK":
      if(newSequence.matrix.length === 50){
        return newSequence;
      }

      let newTrack = _.clone(state.matrix[0]);

      newTrack = newTrack.map((step) =>{
        step.class = "step-tf";
        step.toggled = false;
        return step;
      });

      newSequence.matrix.push(newTrack);

      let sampleLength = newSequence.matrix.length - 1;

      newSequence.samples[sampleLength] = 'bigkik.wav';

      return newSequence;

     case "CLEAR_SEQUENCER":

      state.matrix.forEach((track, index)=>{
        let clearedTrack = _.clone(state.matrix[index]);
        clearedTrack = clearedTrack.map((step) =>{
          step.class = "step-tf";
          step.toggled = false;
          return step;
        });
        newSequence.matrix[index] = clearedTrack;
      });

      return newSequence;

    case "DELETE_TRACK":
      if(newSequence.matrix.length === 1){
        return newSequence;
      }

      console.log('delete track');

      newSequence.matrix.splice(action.deleteTrackIndex, 1);

      delete newSequence.samples[action.deleteTrackIndex];

      let trackLength = newSequence.matrix.length - 1;
      let newSequenceArr = Object.keys(newSequence.samples).map(key => newSequence.samples[key]);

      for(var i=0;i<=trackLength;i++){
        newSequence.samples[i] = newSequenceArr[i];
      }

      return newSequence;

    case 'SAVE_BPM':
      const bpm = Number(action.payload);
      console.log('before: ', state);
      state.bpm = bpm;
      console.log('after: ', state);

      return state;

    case "ADD_BAR":

      let numOfSteps = action.payload;
      let currentLength = state.matrix[0].length
      var difference = currentLength - numOfSteps
      if(numOfSteps > currentLength){
        state.matrix.map((track,index) => {
          let newBar = _.clone(track);
          newBar = newBar.map((step) => {
            if(step.class === 'step-mtf' || step.class === 'step-mtt'){
              step.class = 'step-mtf';
              step.toggled = false;
              return step
            } else {
              step.class = 'step-tf';
              step.toggled = false;
              return step
            }
          });
          newBar.forEach((step)=>{
            newSequence.matrix[index].push(step);
          })

        });
      } else if (numOfSteps < currentLength) {
        state.matrix.map((track, index) => {
          let newBar = track.splice(0, difference)
          newSequence.matrix[index] = newBar;
        })

      }
      return newSequence;

    default:
      return state;
  }
};
<commit_msg>(refactor) Fixed load sequence before logging in<commit_after>import _ from 'lodash';
import initialMatrix from '../data.json';

let matrixUsed = {};

if(window.localStorage.length > 0){
  console.log('local storage set');
  matrixUsed = JSON.parse(window.localStorage.loadSequence);
  window.localStorage.clear();
}else {
   console.log('local storage not set');
  matrixUsed = initialMatrix;
}

export default (state = matrixUsed, action) => {
  const newSequence = _.cloneDeep(state);

  switch (action.type){
    case "TOGGLE_SAMPLE":
    	const index = action.payload;
			// mutate toggle
			newSequence.matrix[index[0]][index[1]].toggled = !newSequence.matrix[index[0]][index[1]].toggled;

			// mutate class
			if(newSequence.matrix[index[0]][index[1]].class === 'step-tf'){
				newSequence.matrix[index[0]][index[1]].class = 'step-tt';
			} else if (newSequence.matrix[index[0]][index[1]].class === 'step-tt'){
				newSequence.matrix[index[0]][index[1]].class = 'step-tf';
			} else if (newSequence.matrix[index[0]][index[1]].class === 'step-mtt'){
        newSequence.matrix[index[0]][index[1]].class = 'step-mtf';
      }  else if (newSequence.matrix[index[0]][index[1]].class === 'step-mtf'){
        newSequence.matrix[index[0]][index[1]].class = 'step-mtt';
      }

      return newSequence;

    case "MUTE_TOGGLE":
      const muteIndex = action.payload;

      newSequence.matrix[muteIndex].forEach((step, index)=>{
        if(step.class === 'step-tt'){
          step.class = 'step-mtt';
        }else if (step.class === 'step-tf'){
          step.class = 'step-mtf';
        } else if (step.class === 'step-mtt'){
          step.class = 'step-tt';
        } else if (step.class === 'step-mtf'){
          step.class = 'step-tf';
        }
        console.log(step.class);
      });

     return newSequence;

    case "CHANGE_SAMPLE":
      console.log('change sample');
      newSequence.samples[action.sampleIndex] = action.sound;
      return newSequence;

    case "LOAD_PROFILE_SEQUENCE":
      console.log('add from profile');
      return action.payload.matrix;

    case "ADD_TRACK":
      if(newSequence.matrix.length === 50){
        return newSequence;
      }

      let newTrack = _.clone(state.matrix[0]);

      newTrack = newTrack.map((step) =>{
        step.class = "step-tf";
        step.toggled = false;
        return step;
      });

      newSequence.matrix.push(newTrack);

      let sampleLength = newSequence.matrix.length - 1;

      newSequence.samples[sampleLength] = 'bigkik.wav';

      return newSequence;

     case "CLEAR_SEQUENCER":

      state.matrix.forEach((track, index)=>{
        let clearedTrack = _.clone(state.matrix[index]);
        clearedTrack = clearedTrack.map((step) =>{
          step.class = "step-tf";
          step.toggled = false;
          return step;
        });
        newSequence.matrix[index] = clearedTrack;
      });

      return newSequence;

    case "DELETE_TRACK":
      if(newSequence.matrix.length === 1){
        return newSequence;
      }

      console.log('delete track');

      newSequence.matrix.splice(action.deleteTrackIndex, 1);

      delete newSequence.samples[action.deleteTrackIndex];

      let trackLength = newSequence.matrix.length - 1;
      let newSequenceArr = Object.keys(newSequence.samples).map(key => newSequence.samples[key]);

      for(var i=0;i<=trackLength;i++){
        newSequence.samples[i] = newSequenceArr[i];
      }

      return newSequence;

    case 'SAVE_BPM':
      const bpm = Number(action.payload);
      console.log('before: ', state);
      state.bpm = bpm;
      console.log('after: ', state);

      return state;

    case "ADD_BAR":

      let numOfSteps = action.payload;
      let currentLength = state.matrix[0].length
      var difference = currentLength - numOfSteps
      if(numOfSteps > currentLength){
        state.matrix.map((track,index) => {
          let newBar = _.clone(track);
          newBar = newBar.map((step) => {
            if(step.class === 'step-mtf' || step.class === 'step-mtt'){
              step.class = 'step-mtf';
              step.toggled = false;
              return step
            } else {
              step.class = 'step-tf';
              step.toggled = false;
              return step
            }
          });
          newBar.forEach((step)=>{
            newSequence.matrix[index].push(step);
          })

        });
      } else if (numOfSteps < currentLength) {
        state.matrix.map((track, index) => {
          let newBar = track.splice(0, difference)
          newSequence.matrix[index] = newBar;
        })

      }
      return newSequence;

    default:
      return state;
  }
};
<|endoftext|>


<commit_before>/*
 * Copyright 2005-2014 The Kuali Foundation
 *
 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
 *
 * 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.
 */
/**
 * Processes a response that has been returned from an Ajax call
 *
 * @param contents - the response contents (or body)
 */
function KradResponse(contents) {
    this.responseContents = contents;
}

KradResponse.prototype = {
    // full response contents
    responseContents: null,

    // maps return types to handler function names
    handlerMapping: {"update-form": "updateFormHandler", "update-page": "updatePageHandler", "update-component": "updateComponentHandler",
        "update-view": "updateViewHandler", "redirect": "redirectHandler",
        "display-lightbox": "displayLightBoxHandler", "update-dialog":"updateDialogHandler"},

    // invoked to process the response contents by invoking necessary handlers
    processResponse: function () {
        var responseFn = this;

        // iterate over returned contents divs and invoke handler
        jQuery(this.responseContents).children().each(function () {
            var div = jQuery(this);

            // get the return type sent by the server
            var returnType = div.data("returntype");

            // find the handler function from the mapping
            var functionName = responseFn.handlerMapping[returnType];
            var handlerFunc = responseFn[functionName];

            // invoke the handler function
            if (handlerFunc) {
                handlerFunc(div, div.data());
            }

            hideEmptyCells();
        });
    },

    // finds the page content in the returned content and updates the page, then processes breadcrumbs and hidden
    // scripts. While processing, the page contents are hidden
    updatePageHandler: function (content, dataAttr) {
        var pageUpdate = jQuery("#page_update", content);
        var page = jQuery("[data-role='Page']", pageUpdate);
        var viewContent = jQuery("#" + kradVariables.VIEW_CONTENT_WRAPPER);

        page.hide();

        // give a selector that will avoid the temporary iframe used to hold ajax responses by the jquery form plugin
        var pageInLayout = "#" + kradVariables.VIEW_CONTENT_WRAPPER + " [data-role='Page']:first";
        hideBubblePopups(pageInLayout);

        var $pageInLayout = jQuery(pageInLayout);

        // update page contents from response
        viewContent.find("[data-for='" + $pageInLayout.attr("id") + "']").remove();
        $pageInLayout.replaceWith(pageUpdate.find(">*"));
        $pageInLayout = jQuery(pageInLayout);

        pageValidatorReady = false;
        runHiddenScripts(kradVariables.VIEW_CONTENT_WRAPPER, false, true);

        markActiveMenuLink();

        viewContent.trigger(kradVariables.EVENTS.ADJUST_PAGE_MARGIN);
        $pageInLayout.trigger(kradVariables.EVENTS.UPDATE_CONTENT);

        $pageInLayout.show();

        $pageInLayout.trigger(kradVariables.EVENTS.ADJUST_STICKY);
        $pageInLayout.trigger(kradVariables.EVENTS.PAGE_UPDATE_COMPLETE);
    },

    // finds the dialog content in the returned content and updates the view
    updateDialogHandler: function (content, dataAttr) {
        var id = dataAttr.updatecomponentid;
        var component = jQuery("#" + id + "_update", content);

        // remove old stuff
        if (jQuery("#" + id + "_errors").length) {
            jQuery("#" + id + "_errors").remove();
        }

        jQuery("input[data-for='" + id + "']").each(function () {
            jQuery(this).remove();
        });

        // replace component
        var $dialog = jQuery("#" + id);
        if ($dialog.length) {
            $dialog.replaceWith(component.html());

            $dialog.trigger(kradVariables.EVENTS.UPDATE_CONTENT);
        }

        runHiddenScripts(id);
    },

    // retrieves the component with the matching id from the server and replaces a matching
    // _refreshWrapper marker span with the same id with the result.  In addition, if the result contains a label
    // and a displayWith marker span has a matching id, that span will be replaced with the label content
    // and removed from the component.  This allows for label and component content separation on fields
    updateComponentHandler: function (content, dataAttr) {
        var id = dataAttr.id;

        var $componentInDom = jQuery("#" + id);

        hideBubblePopups($componentInDom);

        var component = jQuery("#" + id + "_update", content);

        // special label handling, if any
        var theLabel = jQuery("[data-label_for='" + id + "']", component);
        if (jQuery(".displayWith-" + id).length && theLabel.length) {
            theLabel.addClass("displayWith-" + id);
            jQuery("span.displayWith-" + id).replaceWith(theLabel);

            component.remove("[data-label_for='" + id + "']");
        }

        // remove old stuff
        if (jQuery("#" + id + "_errors").length) {
            jQuery("#" + id + "_errors").remove();
        }

        jQuery("input[data-for='" + id + "']").each(function () {
            jQuery(this).remove();
        });

        // replace component
        if ($componentInDom.length) {
            // only do highlighting if the is the first time the content is being displayed, and it is not
            // a dialog
            var componentInDialog = jQuery('#' + kradVariables.IDS.DIALOGS + ' #' + id).length > 0;
            if (!componentInDialog && $componentInDom.hasClass(kradVariables.CLASSES.PLACEHOLDER)) {
                var isNewlyDisclosed = true;
            }

            $componentInDom.replaceWith(component.html());

            $componentInDom = jQuery("#" + id);

            if ($componentInDom.parent().is("td")) {
                $componentInDom.parent().show();
            }

            var displayWithLabel = jQuery(".displayWith-" + id);
            displayWithLabel.show();
            if (displayWithLabel.parent().is("td") || displayWithLabel.parent().is("th")) {
                displayWithLabel.parent().show();
            }

            // assume this content is open if being refreshed
            var open = $componentInDom.attr("data-open");
            if (open !== undefined && open === "false") {
                $componentInDom.attr("data-open", "true");
                $componentInDom.show();
            }

            // runs scripts on the span or div with id
            runHiddenScripts(id);

            // Only for table layout collections. Keeps collection on same page.
            var currentPage = retrieveFromSession(id + ":currentPageRichTable");
            if (currentPage != null) {
                openDataTablePage(id, currentPage);
            }

            $componentInDom.unblock({onUnblock: function () {
                if (isNewlyDisclosed) {
                    $componentInDom.addClass(kradVariables.PROGRESSIVE_DISCLOSURE_HIGHLIGHT_CLASS);
                    $componentInDom.animate({backgroundColor: "transparent"}, 6000);
                }
              }
            });

            $componentInDom.trigger(kradVariables.EVENTS.UPDATE_CONTENT);
        }
    },

    // performs a redirect to the URL found in the returned contents
    redirectHandler: function (content, dataAttr) {
        // get url contents between div
        var redirectUrl = jQuery(content).text().trim();

        // don't check dirty state on a simple refresh (old url starts with the new one's url text)
        if (window.location.href.indexOf(redirectUrl) === 0) {
            dirtyFormState.skipDirtyChecks = true;
        }

        // redirect
        window.location.href = redirectUrl;
    },

    // replaces the view with the given content and run the hidden scripts
    updateViewHandler: function (content, dataAttr) {
        var app = jQuery("#" + kradVariables.APP_ID);
        app.hide();

        var update = jQuery("div[data-returntype='update-view']", content);

        var appHeaderUpdate = update.find("#" + kradVariables.APPLICATION_HEADER_WRAPPER);
        app.find("#" + kradVariables.APPLICATION_HEADER_WRAPPER).replaceWith(appHeaderUpdate);

        var kualiForm = app.find("#kualiForm");
        var kualiFormReplacement = update.find("#kualiForm");
        var view = app.find("[data-role='View']");
        var viewUpdate = update.find("[data-role='View']");

        if(kualiForm.length && kualiFormReplacement) {
            kualiForm.replaceWith(kualiFormReplacement);
        }
        else if (kualiForm.length && !kualiFormReplacement.length){
            kualiForm.replaceWith(viewUpdate);
        }
        else if (!kualiForm.length && kualiFormReplacement.length) {
            view.replaceWith(kualiFormReplacement);
        }
        else {
            view.replaceWith(viewUpdate);
        }

        var appFooterUpdate = update.find("#" + kradVariables.APPLICATION_FOOTER_WRAPPER);
        app.find("#" + kradVariables.APPLICATION_FOOTER_WRAPPER).replaceWith(appFooterUpdate);

        app.show();
        setupStickyHeaderAndFooter();
        runHiddenScripts(kradVariables.APP_ID);

        view.trigger(kradVariables.EVENTS.UPDATE_CONTENT);
    },

    // displays the response contents in a lightbox
    displayLightBoxHandler: function (content, dataAttr) {
        showLightboxContent(content);
    },

    // replaces the form action with the given content
    updateFormHandler: function (content, dataAttr) {

        var action = jQuery(content).html();
        // update form action with content

        jQuery("form#" + kradVariables.KUALI_FORM).attr('action', jQuery.trim(action));

    }
}<commit_msg>Fix to correctly pull incident report on ajax returns<commit_after>/*
 * Copyright 2005-2014 The Kuali Foundation
 *
 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
 *
 * 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.
 */
/**
 * Processes a response that has been returned from an Ajax call
 *
 * @param contents - the response contents (or body)
 */
function KradResponse(contents) {
    this.responseContents = contents;
}

KradResponse.prototype = {
    // full response contents
    responseContents: null,

    // maps return types to handler function names
    handlerMapping: {"update-form": "updateFormHandler", "update-page": "updatePageHandler", "update-component": "updateComponentHandler",
        "update-view": "updateViewHandler", "redirect": "redirectHandler",
        "display-lightbox": "displayLightBoxHandler", "update-dialog":"updateDialogHandler"},

    // invoked to process the response contents by invoking necessary handlers
    processResponse: function () {
        var responseFn = this;

        // iterate over returned contents divs and invoke handler
        jQuery(this.responseContents).children().each(function () {
            var div = jQuery(this);

            // get the return type sent by the server
            var returnType = div.data("returntype");

            // find the handler function from the mapping
            var functionName = responseFn.handlerMapping[returnType];
            var handlerFunc = responseFn[functionName];

            // invoke the handler function
            if (handlerFunc) {
                handlerFunc(div, div.data());
            }

            hideEmptyCells();
        });
    },

    // finds the page content in the returned content and updates the page, then processes breadcrumbs and hidden
    // scripts. While processing, the page contents are hidden
    updatePageHandler: function (content, dataAttr) {
        var pageUpdate = jQuery("#page_update", content);
        var page = jQuery("[data-role='Page']", pageUpdate);
        var viewContent = jQuery("#" + kradVariables.VIEW_CONTENT_WRAPPER);

        page.hide();

        // give a selector that will avoid the temporary iframe used to hold ajax responses by the jquery form plugin
        var pageInLayout = "#" + kradVariables.VIEW_CONTENT_WRAPPER + " [data-role='Page']:first";
        hideBubblePopups(pageInLayout);

        var $pageInLayout = jQuery(pageInLayout);

        // update page contents from response
        viewContent.find("[data-for='" + $pageInLayout.attr("id") + "']").remove();
        $pageInLayout.replaceWith(pageUpdate.find(">*"));
        $pageInLayout = jQuery(pageInLayout);

        pageValidatorReady = false;
        runHiddenScripts(kradVariables.VIEW_CONTENT_WRAPPER, false, true);

        markActiveMenuLink();

        viewContent.trigger(kradVariables.EVENTS.ADJUST_PAGE_MARGIN);
        $pageInLayout.trigger(kradVariables.EVENTS.UPDATE_CONTENT);

        $pageInLayout.show();

        $pageInLayout.trigger(kradVariables.EVENTS.ADJUST_STICKY);
        $pageInLayout.trigger(kradVariables.EVENTS.PAGE_UPDATE_COMPLETE);
    },

    // finds the dialog content in the returned content and updates the view
    updateDialogHandler: function (content, dataAttr) {
        var id = dataAttr.updatecomponentid;
        var component = jQuery("#" + id + "_update", content);

        // remove old stuff
        if (jQuery("#" + id + "_errors").length) {
            jQuery("#" + id + "_errors").remove();
        }

        jQuery("input[data-for='" + id + "']").each(function () {
            jQuery(this).remove();
        });

        // replace component
        var $dialog = jQuery("#" + id);
        if ($dialog.length) {
            $dialog.replaceWith(component.html());

            $dialog.trigger(kradVariables.EVENTS.UPDATE_CONTENT);
        }

        runHiddenScripts(id);
    },

    // retrieves the component with the matching id from the server and replaces a matching
    // _refreshWrapper marker span with the same id with the result.  In addition, if the result contains a label
    // and a displayWith marker span has a matching id, that span will be replaced with the label content
    // and removed from the component.  This allows for label and component content separation on fields
    updateComponentHandler: function (content, dataAttr) {
        var id = dataAttr.id;

        var $componentInDom = jQuery("#" + id);

        hideBubblePopups($componentInDom);

        var component = jQuery("#" + id + "_update", content);

        // special label handling, if any
        var theLabel = jQuery("[data-label_for='" + id + "']", component);
        if (jQuery(".displayWith-" + id).length && theLabel.length) {
            theLabel.addClass("displayWith-" + id);
            jQuery("span.displayWith-" + id).replaceWith(theLabel);

            component.remove("[data-label_for='" + id + "']");
        }

        // remove old stuff
        if (jQuery("#" + id + "_errors").length) {
            jQuery("#" + id + "_errors").remove();
        }

        jQuery("input[data-for='" + id + "']").each(function () {
            jQuery(this).remove();
        });

        // replace component
        if ($componentInDom.length) {
            // only do highlighting if the is the first time the content is being displayed, and it is not
            // a dialog
            var componentInDialog = jQuery('#' + kradVariables.IDS.DIALOGS + ' #' + id).length > 0;
            if (!componentInDialog && $componentInDom.hasClass(kradVariables.CLASSES.PLACEHOLDER)) {
                var isNewlyDisclosed = true;
            }

            $componentInDom.replaceWith(component.html());

            $componentInDom = jQuery("#" + id);

            if ($componentInDom.parent().is("td")) {
                $componentInDom.parent().show();
            }

            var displayWithLabel = jQuery(".displayWith-" + id);
            displayWithLabel.show();
            if (displayWithLabel.parent().is("td") || displayWithLabel.parent().is("th")) {
                displayWithLabel.parent().show();
            }

            // assume this content is open if being refreshed
            var open = $componentInDom.attr("data-open");
            if (open !== undefined && open === "false") {
                $componentInDom.attr("data-open", "true");
                $componentInDom.show();
            }

            // runs scripts on the span or div with id
            runHiddenScripts(id);

            // Only for table layout collections. Keeps collection on same page.
            var currentPage = retrieveFromSession(id + ":currentPageRichTable");
            if (currentPage != null) {
                openDataTablePage(id, currentPage);
            }

            $componentInDom.unblock({onUnblock: function () {
                if (isNewlyDisclosed) {
                    $componentInDom.addClass(kradVariables.PROGRESSIVE_DISCLOSURE_HIGHLIGHT_CLASS);
                    $componentInDom.animate({backgroundColor: "transparent"}, 6000);
                }
              }
            });

            $componentInDom.trigger(kradVariables.EVENTS.UPDATE_CONTENT);
        }
    },

    // performs a redirect to the URL found in the returned contents
    redirectHandler: function (content, dataAttr) {
        // get url contents between div
        var redirectUrl = jQuery(content).text().trim();

        // don't check dirty state on a simple refresh (old url starts with the new one's url text)
        if (window.location.href.indexOf(redirectUrl) === 0) {
            dirtyFormState.skipDirtyChecks = true;
        }

        // redirect
        window.location.href = redirectUrl;
    },

    // replaces the view with the given content and run the hidden scripts
    updateViewHandler: function (content, dataAttr) {
        var app = jQuery("#" + kradVariables.APP_ID);
        app.hide();

        var update = jQuery(content);

        var appHeaderUpdate = update.find("#" + kradVariables.APPLICATION_HEADER_WRAPPER);
        app.find("#" + kradVariables.APPLICATION_HEADER_WRAPPER).replaceWith(appHeaderUpdate);

        var kualiForm = app.find("#kualiForm");
        var kualiFormReplacement = update.find("#kualiForm");
        var view = app.find("[data-role='View']");
        var viewUpdate = update.find("[data-role='View']");

        if(kualiForm.length && kualiFormReplacement) {
            kualiForm.replaceWith(kualiFormReplacement);
        }
        else if (kualiForm.length && !kualiFormReplacement.length){
            kualiForm.replaceWith(viewUpdate);
        }
        else if (!kualiForm.length && kualiFormReplacement.length) {
            view.replaceWith(kualiFormReplacement);
        }
        else {
            view.replaceWith(viewUpdate);
        }

        var appFooterUpdate = update.find("#" + kradVariables.APPLICATION_FOOTER_WRAPPER);
        app.find("#" + kradVariables.APPLICATION_FOOTER_WRAPPER).replaceWith(appFooterUpdate);

        app.show();
        setupStickyHeaderAndFooter();
        runHiddenScripts(kradVariables.APP_ID);

        view.trigger(kradVariables.EVENTS.UPDATE_CONTENT);
    },

    // displays the response contents in a lightbox
    displayLightBoxHandler: function (content, dataAttr) {
        showLightboxContent(content);
    },

    // replaces the form action with the given content
    updateFormHandler: function (content, dataAttr) {

        var action = jQuery(content).html();
        // update form action with content

        jQuery("form#" + kradVariables.KUALI_FORM).attr('action', jQuery.trim(action));

    }
}<|endoftext|>


<commit_before>/*globals define, _, requirejs, WebGMEGlobal, Raphael*/

define(['js/logger'], function (Logger) {

    "use strict";

    var PanelManager;

    PanelManager = function () {
        this._logger = Logger.create('gme:PanelManager:PanelManager', WebGMEGlobal.gmeConfig.client.log);

        this._activePanel = undefined;
    };

    PanelManager.prototype.setActivePanel = function (p) {
        if (this._activePanel === p) {
            return;
        }

        if (this._activePanel) {
            //deactivate currently active panel
            this._activePanel.setActive(false);
        }

        this._activePanel = undefined;

        if (p && _.isFunction(p.setActive)) {
            this._activePanel = p;
            this._activePanel.setActive(true);
        }

        WebGMEGlobal.KeyboardManager.captureFocus();
    };

    PanelManager.prototype.getActivePanel = function () {
        return this._activePanel;
    };

    return PanelManager;
});<commit_msg>Activate panel 'p1' after split view is disabled.<commit_after>/*globals define, _, requirejs, WebGMEGlobal, Raphael*/

define(['js/logger'], function (Logger) {

    "use strict";

    var PanelManager;

    PanelManager = function () {
        this._logger = Logger.create('gme:PanelManager:PanelManager', WebGMEGlobal.gmeConfig.client.log);

        this._activePanel = undefined;
    };

    PanelManager.prototype.setActivePanel = function (p) {
        if (this._activePanel === p) {
            // [lattmann] we need to call setActive in order to get the split panel working correctly
            this._activePanel.setActive(true);

        } else {
            if (this._activePanel) {
                //deactivate currently active panel
                this._activePanel.setActive(false);
            }

            this._activePanel = undefined;

            if (p && _.isFunction(p.setActive)) {
                this._activePanel = p;
                this._activePanel.setActive(true);
            }
        }

        WebGMEGlobal.KeyboardManager.captureFocus();
    };

    PanelManager.prototype.getActivePanel = function () {
        return this._activePanel;
    };

    return PanelManager;
});<|endoftext|>


<commit_before>let mongoose = require('mongoose');
let Schema = mongoose.Schema;

let timetableSchema = new Schema({
  bollard: {
    type: String,
    required: true,
    trim: true,
    ref: 'Bollard'
  },
  line: {
    type: String,
    required: true,
    trim: true,
    ref: 'Line'
  },
  departureTime: {
    type: Date,
    required: true
  }
});

timetableSchema.index({
  bollard: 1,
  line: 1,
  departureTime: -1
});

module.exports = mongoose.model('Timetable', timetableSchema);<commit_msg>relation added to timetable schema<commit_after>let mongoose = require('mongoose');
let Schema = mongoose.Schema;

let timetableSchema = new Schema({
  bollard: {
    type: String,
    required: true,
    trim: true,
    ref: 'Bollard'
  },
  line: {
    type: String,
    required: true,
    trim: true,
    ref: 'Line'
  },
  relation: {
    type: String,
    required: true,
    trim: true
  },
  departureTime: {
    type: Date,
    required: true
  }
});

timetableSchema.index({
  bollard: 1,
  line: 1,
  departureTime: -1
});

module.exports = mongoose.model('Timetable', timetableSchema);<|endoftext|>


<commit_before>import Dungeon from '../dungeons/Dungeon.js';
// import GameEvent from '../events/GameEvent.js';
import GameEvents from '../events/GameEvents.js';

// import DungeonTooltips from './DungeonTooltips.js';

import SharedUIDataController from '../controllers/SharedUIDataController.js';

import Moves from '../entities/creatures/moves/Moves.js';

import DefaultPixiAnimationPack from './DefaultPixiAnimationPack.js';
import DefaultSpritePack from './DefaultSpritePack.js';
import PixiAnimationController from './PixiAnimationController.js';

const PIXI = require('pixi.js');

const TILE_WIDTH = 50;
const GAP_WIDTH = 0;

const NEUTRAL_COLOR = 0x46465a;
const ATTACK_MOVE_COLOR = 0x8b0000;
const ITEM_MOVE_COLOR = 0x7F00FF;
const ABILITY_MOVE_COLOR = 0x9400D3;

function getTileColor(sharedData, x, y) {
    const dungeon = sharedData.getDungeon();
    const player = dungeon.getPlayableCharacter();
    const playerLocation = dungeon.getTile(player);

    switch(sharedData.getMode()) {
    case SharedUIDataController.EXAMINE_MODE:
        return NEUTRAL_COLOR;
    case SharedUIDataController.ATTACK_MODE:
        return new Moves.AttackMove(playerLocation, x, y)
            .getReasonIllegal(dungeon, player) ?
            NEUTRAL_COLOR : ATTACK_MOVE_COLOR;
    case SharedUIDataController.TARGETTED_ABILITY_MODE: {
        const abilityIndex = sharedData.getTargettedAbility();
        return new Moves.UseAbilityMove(playerLocation, abilityIndex, x, y)
            .getReasonIllegal(dungeon, player) ?
            NEUTRAL_COLOR : ABILITY_MOVE_COLOR;
    }
    case SharedUIDataController.TARGETTED_ITEM_MODE: {
        const itemIndex = sharedData.getTargettedItem();
        return new Moves.UseItemMove(playerLocation, itemIndex, dungeon.getTile(x, y))
            .getReasonIllegal(dungeon, player) ?
            NEUTRAL_COLOR : ITEM_MOVE_COLOR;
    }
    case SharedUIDataController.NEUTRAL_MODE:
        return new Moves.AttackMove(playerLocation, x, y)
            .getReasonIllegal(dungeon, player) ?
            NEUTRAL_COLOR : ATTACK_MOVE_COLOR;
    default:
        throw new Error('This should never happen');
    }
}

function getIndicator(x, y, color) {
    const indicator = new PIXI.Graphics();
    indicator.lineStyle(1, color);
    indicator.drawRect(
        x * (TILE_WIDTH + GAP_WIDTH) + 1, y * (TILE_WIDTH + GAP_WIDTH),
        TILE_WIDTH + GAP_WIDTH - 1, TILE_WIDTH + GAP_WIDTH - 1
    );
    return indicator;
}

export default class PixiDungeonView {
    constructor(
        sharedData,
        spritePack = new DefaultSpritePack()) {
        if(!(sharedData instanceof SharedUIDataController)) {
            throw new Error('First parameter must be a SharedUIDataController');
        }
        this._sharedData = sharedData;
        this._indicators = [];
        this._clickHanders = [];
        this._mouseOverHandlers = [];
        this._mouseOutHandlers = [];

        this.setSpritePack(spritePack);

        const canvasContainer = this._canvasContainer = document.createElement('div');
        canvasContainer.classList.add('viewport-container');

        const pixiApp = this._pixiApp = new PIXI.Application();
        canvasContainer.appendChild(pixiApp.view);

        PIXI.loader.add('images/spritesheet.json').load(() => this.init());

        function resize() {
            const {clientWidth, clientHeight} = canvasContainer;
            pixiApp.renderer.resize(clientWidth, clientHeight);
        }

        setTimeout(resize);
        window.addEventListener('resize', resize);
    }

    init() {
        const stage = this.getStage();

        this._entitySprites = {};

        const sharedData = this._sharedData;
        this._pixiApp.renderer;
        const animationController = this._animationController = new PixiAnimationController(
            sharedData,
            this,
            this._pixiApp,
            new DefaultPixiAnimationPack()
        );

        sharedData.addObserver((event) => {
            if(!event) {
                return; // TODO: Make mouse events have an event type?
            }
            if(event instanceof Dungeon){
                this.populateStage(stage);
                document.querySelector('section.game').focus(); //TODO: Make canvas container focusable insted?
                this.moveViewport();
                //animationController.flush();
            } else {
                animationController.handleGameEvent(event);
            }
        });

        sharedData.addObserver((event) => {
            if(event instanceof GameEvents.SpawnEvent) {
                this.updateCreatureLocations();
                this._tileGroups[event.getX()][event.getY()].update();
            } else if(event instanceof GameEvents.HitpointsEvent) {
                /*if(event.getAmount() < 0) {
                    getScrollingText(event.getAmount(), x, y, DAMAGE_COLORS[event.getDamageType()] || 'green', DAMAGE_OUTLINE_COLORS[event.getDamageType()] || 'green')
                        .appendTo(grid.children[0]);
                }*/
            } else if(event instanceof GameEvents.TakeItemEvent || event instanceof GameEvents.ItemDropEvent) {
                this.updateItems();
            }
            this.updateStatBars();
            this.updateRangeIndicator();
            this.updateSelectedTileIndicator();
        });
    }

    setSpritePack(spritePack) {
        this._spritePack = spritePack;
    }

    getSpritePack() {
        return this._spritePack;
    }

    getStage() {
        return this._pixiApp.stage;
    }

    getTileGroup(param1, param2) {
        let x, y;
        if(param1.getX) {
            x = param1.getX();
            y = param1.getY();
        } else {
            x = param1;
            y = param2;
        }
        return this._tileGroups[x][y];
    }

    getItemContainer(x, y) {
        return this._itemContainers[x][y];
    }

    getCreatureContainer(x, y) {
        return this._creatureContainers[x][y];
    }

    addCreatureSprite(sprite, x, y) {
        this.getCreatureContainer(x, y).addChild(sprite);
    }

    removeCreatureSprite(x, y) {
        const container = this.getCreatureContainer(x, y);
        const sprite = container.children[0];
        container.removeChild(sprite);
        return sprite;
    }

    getEntityById(id) {
        return this._entitySprites[id];
    }

    removeEntityById(id) {
        const container = this._entitySprites[id];
        container.parent.removeChild(container);
        return container;
    }

    populateStage() {
        this.populateSprites();
        this.updateCreatureLocations();
        this.updateItems();
        this.updateVision();
    }

    addParticle(particle) {
        this._particleLayer.addChild(particle);
    }

    populateSprites() {
        const stage = this.getStage();
        while(stage.children.length) stage.removeChild(stage.children[0]);

        const dungeon = this._sharedData.getDungeon();
        const tileGroups = this._tileGroups = new Array(dungeon.getWidth()).fill(0).map(()=>[]);
        const itemContainers = this._itemContainers = new Array(dungeon.getWidth()).fill(0).map(()=>[]);
        const creatureContainers = this._creatureContainers = new Array(dungeon.getWidth()).fill(0).map(()=>[]);

        const tileLayer = this._tileLayer = new PIXI.Container();
        const indicatorLayer = this._indicatorLayer = new PIXI.Container();
        const itemLayer = this._itemLayer = new PIXI.Container();
        const creatureLayer = this._creatureLayer = new PIXI.Container();
        const particleLayer = this._particleLayer = new PIXI.Container();

        dungeon.forEachTile((tile, x, y) => {
            const tileGroup = this.getSpritePack().getTileGroup(tile);
            const xOffset = x * (TILE_WIDTH + GAP_WIDTH);
            const yOffset = y * (TILE_WIDTH + GAP_WIDTH);
            tileGroup.x = xOffset;
            tileGroup.y = yOffset;
            tileGroup.interactive = true;
            tileGroup.hitArea = new PIXI.Rectangle(0, 0, TILE_WIDTH, TILE_WIDTH);
            tileGroups[x][y] = tileGroup;

            tileGroup
            .on('click', () => {
                this._clickHanders.forEach(handler => handler(x, y));
            }).on('tap', () => {
                this._clickHanders.forEach(handler => handler(x, y));
            }).on('mouseover', () => {
                setTimeout(() => { // Ensure mouseout fires first
                    this._mouseOverHandlers.forEach(handler => handler(x, y));
                });
            }).on('mouseout', () => {
                this._mouseOutHandlers.forEach(handler => handler(x, y));
            });

            tileLayer.addChild(tileGroup);

            const itemContainer = itemContainers[x][y] = new PIXI.Container();
            itemContainer.x = xOffset;
            itemContainer.y = yOffset;
            itemLayer.addChild(itemContainer);

            const creatureContainer = creatureContainers[x][y] = new PIXI.Container();
            creatureContainer.x = xOffset;
            creatureContainer.y = yOffset;
            creatureLayer.addChild(creatureContainer);
        });

        stage.addChild(tileLayer);
        stage.addChild(indicatorLayer);
        stage.addChild(itemLayer);
        stage.addChild(creatureLayer);
        stage.addChild(particleLayer);
    }

    updateItems() {
        const dungeon = this._sharedData.getDungeon();
        const spritePack = this.getSpritePack();
        // const itemContainers = this._itemContainers;
        dungeon.forEachTile((tile, x, y) => {
            const itemLayer = this.getItemContainer(x, y);
            while(itemLayer.children.length) itemLayer.removeChildAt(0);
            tile.getItems().forEach(function(item) {
                itemLayer.addChild(spritePack.getItemSprite(item));
            });
        });
    }

    updateVision() {
        const dungeon = this._sharedData.getDungeon();
        const player = dungeon.getPlayableCharacter();
        if(player) {
            dungeon.forEachTile((tile, x, y) => {
                const tileGroup = this.getTileGroup(x, y);
                const itemContainer = this.getItemContainer(x, y);
                const creatureContainer = this.getCreatureContainer(x, y);
                const playerCanSeeTile = player.canSee(dungeon, tile);
                if(playerCanSeeTile) {
                    tileGroup.alpha = 1;
                } else if(player.hasSeen(tile)) {
                    tileGroup.alpha = .5;
                } else {
                    tileGroup.alpha = 0;
                }
                itemContainer.visible = creatureContainer.visible = playerCanSeeTile;
            });
        }
    }

    updateCreatureLocations() {
        const dungeon = this._sharedData.getDungeon();
        const spritePack = this.getSpritePack();
        const entitySprites = this._entitySprites; // TODO: Getter
        dungeon.getCreatures().forEach((creature) => {
            let sprite = entitySprites[creature.getId()];
            if(!sprite) {
                sprite = entitySprites[creature.getId()] = spritePack.getSpriteStack(
                    [creature.constructor.name]
                );
                sprite.addChild(new PIXI.Graphics());
            }
            if(sprite.parent) {
                sprite.parent.removeChild(sprite);
            }
            if(!creature.isDead()) {
                const tile = dungeon.getTile(creature);
                this.getCreatureContainer(tile.getX(), tile.getY()).addChild(sprite);
            }
        });
    }

    updateStatBars() {
        const dungeon = this._sharedData.getDungeon();
        const player = dungeon.getPlayableCharacter();
        const entitySprites = this._entitySprites; // TODO: Getter

        dungeon.getCreatures().forEach(function(creature) {
            const sprite = entitySprites[creature.getId()];
            if(sprite) {
                const creatureWidth = sprite.children[0].width;
                const statGraphics = sprite.children[1];

                statGraphics.clear();
                const padding = 4;
                const maxBarWidth = creatureWidth - 2 * padding;
                const barHeight = 3;

                const hpBarWidth = maxBarWidth * Math.max(0, creature.getCurrentHP()) / creature.getBaseHP();
                const actionBarWidth = maxBarWidth * creature.getTimeToNextMove() / creature.getSpeed();

                statGraphics.x = padding;
                statGraphics.y = padding;

                statGraphics.lineStyle(1, 0x660000);
                statGraphics.drawRect(0, 0, hpBarWidth, barHeight);
                statGraphics.beginFill(0x8f0222);
                statGraphics.drawRect(1, 1, hpBarWidth - 1, barHeight);
                statGraphics.endFill();

                if(creature === player) {
                    return;
                }

                statGraphics.lineStyle(1, 0xCC7000);
                statGraphics.drawRect(0, barHeight + 2, actionBarWidth, barHeight);
                statGraphics.beginFill(0xdddd00);
                statGraphics.drawRect(1, barHeight + 3, actionBarWidth - 1, barHeight - 1);
                statGraphics.endFill();
            }
        });
    }

    updateRangeIndicator() {
        let rangeIndicator = this._rangeIndicator;
        if(rangeIndicator && rangeIndicator.parent) {
            rangeIndicator.parent.removeChild(rangeIndicator); // TODO: Is there a remove self function?
        }

        const sharedData = this._sharedData;
        const dungeon = sharedData.getDungeon();
        const player = dungeon.getPlayableCharacter();
        let rangedAttack;
        if(typeof sharedData.getTargettedAbility() === 'number') {
            rangedAttack = player.getAbility(sharedData.getTargettedAbility());
        } else if(typeof sharedData.getTargettedItem() === 'number') {
            rangedAttack = player.getInventory().getItem(sharedData.getTargettedItem());
        } else {
            rangedAttack = player.getRangedWeapon();
        }
        if(!rangedAttack) {
            return;
        }

        rangeIndicator = this._rangeIndicator = new PIXI.Graphics();

        let color;
        if(typeof rangedAttack.isMovementAbility === 'function') {
            color = 0x9400D3;
        } else if(rangedAttack.isTargetted()) {
            color = 0x7F00FF;
        } else {
            color = 0x46465a;
        }

        const playerTile = dungeon.getTile(player);
        rangeIndicator.lineStyle(1, color, 1);
        rangeIndicator.drawCircle(
            (playerTile.getX() + .5) * TILE_WIDTH,
            (playerTile.getY() + .5) * TILE_WIDTH,
            rangedAttack.getRange() * TILE_WIDTH
        );

        this.getStage().addChild(rangeIndicator);
    }

    updateSelectedTileIndicator() {
        const indicatorLayer = this._indicatorLayer;
        while(indicatorLayer.children.length > 0) indicatorLayer.removeChildAt(0);

        const sharedData = this._sharedData;
        // const dungeon = sharedData.getDungeon();
        // const player = dungeon.getPlayableCharacter();
        // const playerLocation = dungeon.getTile(player);

        this._indicators = [
            sharedData.getHoverTile(),
            sharedData.getFocusTile()
        ].filter(Boolean).map((tile) => {
            const x = tile.getX();
            const y = tile.getY();
            const color = getTileColor(sharedData, x, y);
            const indicator = getIndicator(x, y, color);
            indicatorLayer.addChild(indicator);
            return indicator;
        });
    }

    moveViewport(
        xOffset = 0,
        yOffset = 0
    ) {
        const sharedData = this._sharedData;
        const stage = this.getStage();
        const dungeon = sharedData.getDungeon();
        const player = dungeon.getPlayableCharacter();
        const tile = dungeon.getTile(player);

        const x = tile.getX();
        const y = tile.getY();

        const canvasWidth = this.getDom().firstChild.width;
        const canvasHeight = this.getDom().firstChild.height;

        const cellDimension = TILE_WIDTH;
        const halfDimension = TILE_WIDTH / 2;
        const playerOffsetX = x * cellDimension + halfDimension;
        const playerOffsetY = y * cellDimension + halfDimension;

        stage.x = (canvasWidth / 2) - playerOffsetX - xOffset;
        stage.y = (canvasHeight / 2) - playerOffsetY - yOffset;
    }

    getDom() {
        return this._canvasContainer;
    }

    onClick(handler) {
        if(typeof handler !== 'function') {
            throw new Error('Handler must be a function');
        }
        this._clickHanders.push(handler);
    }

    onMouseOver(handler) {
        if(typeof handler !== 'function') {
            throw new Error('Handler must be a function');
        }
        this._mouseOverHandlers.push(handler);
    }

    onMouseOut(handler) {
        if(typeof handler !== 'function') {
            throw new Error('Handler must be a function');
        }
        this._mouseOutHandlers.push(handler);
    }

    // TODO: Cellphone zap
    // TODO: Projectile animations
    // TODO: Show buffs
    // TODO: Tooltips
    // TODO: Blue outline for movement move
}
<commit_msg>Range indicator slides with player<commit_after>import Dungeon from '../dungeons/Dungeon.js';
// import GameEvent from '../events/GameEvent.js';
import GameEvents from '../events/GameEvents.js';

// import DungeonTooltips from './DungeonTooltips.js';

import SharedUIDataController from '../controllers/SharedUIDataController.js';

import Moves from '../entities/creatures/moves/Moves.js';

import DefaultPixiAnimationPack from './DefaultPixiAnimationPack.js';
import DefaultSpritePack from './DefaultSpritePack.js';
import PixiAnimationController from './PixiAnimationController.js';

const PIXI = require('pixi.js');

const TILE_WIDTH = 50;
const GAP_WIDTH = 0;

const NEUTRAL_COLOR = 0x46465a;
const ATTACK_MOVE_COLOR = 0x8b0000;
const ITEM_MOVE_COLOR = 0x7F00FF;
const ABILITY_MOVE_COLOR = 0x9400D3;

function getTileColor(sharedData, x, y) {
    const dungeon = sharedData.getDungeon();
    const player = dungeon.getPlayableCharacter();
    const playerLocation = dungeon.getTile(player);

    switch(sharedData.getMode()) {
    case SharedUIDataController.EXAMINE_MODE:
        return NEUTRAL_COLOR;
    case SharedUIDataController.ATTACK_MODE:
        return new Moves.AttackMove(playerLocation, x, y)
            .getReasonIllegal(dungeon, player) ?
            NEUTRAL_COLOR : ATTACK_MOVE_COLOR;
    case SharedUIDataController.TARGETTED_ABILITY_MODE: {
        const abilityIndex = sharedData.getTargettedAbility();
        return new Moves.UseAbilityMove(playerLocation, abilityIndex, x, y)
            .getReasonIllegal(dungeon, player) ?
            NEUTRAL_COLOR : ABILITY_MOVE_COLOR;
    }
    case SharedUIDataController.TARGETTED_ITEM_MODE: {
        const itemIndex = sharedData.getTargettedItem();
        return new Moves.UseItemMove(playerLocation, itemIndex, dungeon.getTile(x, y))
            .getReasonIllegal(dungeon, player) ?
            NEUTRAL_COLOR : ITEM_MOVE_COLOR;
    }
    case SharedUIDataController.NEUTRAL_MODE:
        return new Moves.AttackMove(playerLocation, x, y)
            .getReasonIllegal(dungeon, player) ?
            NEUTRAL_COLOR : ATTACK_MOVE_COLOR;
    default:
        throw new Error('This should never happen');
    }
}

function getIndicator(x, y, color) {
    const indicator = new PIXI.Graphics();
    indicator.lineStyle(1, color);
    indicator.drawRect(
        x * (TILE_WIDTH + GAP_WIDTH) + 1, y * (TILE_WIDTH + GAP_WIDTH),
        TILE_WIDTH + GAP_WIDTH - 1, TILE_WIDTH + GAP_WIDTH - 1
    );
    return indicator;
}

export default class PixiDungeonView {
    constructor(
        sharedData,
        spritePack = new DefaultSpritePack()) {
        if(!(sharedData instanceof SharedUIDataController)) {
            throw new Error('First parameter must be a SharedUIDataController');
        }
        this._sharedData = sharedData;
        this._indicators = [];
        this._clickHanders = [];
        this._mouseOverHandlers = [];
        this._mouseOutHandlers = [];

        this.setSpritePack(spritePack);

        const canvasContainer = this._canvasContainer = document.createElement('div');
        canvasContainer.classList.add('viewport-container');

        const pixiApp = this._pixiApp = new PIXI.Application();
        canvasContainer.appendChild(pixiApp.view);

        PIXI.loader.add('images/spritesheet.json').load(() => this.init());

        function resize() {
            const {clientWidth, clientHeight} = canvasContainer;
            pixiApp.renderer.resize(clientWidth, clientHeight);
        }

        setTimeout(resize);
        window.addEventListener('resize', resize);
    }

    init() {
        const stage = this.getStage();

        this._entitySprites = {};

        const sharedData = this._sharedData;
        this._pixiApp.renderer;
        const animationController = this._animationController = new PixiAnimationController(
            sharedData,
            this,
            this._pixiApp,
            new DefaultPixiAnimationPack()
        );

        sharedData.addObserver((event) => {
            if(!event) {
                return; // TODO: Make mouse events have an event type?
            }
            if(event instanceof Dungeon){
                this.populateStage(stage);
                document.querySelector('section.game').focus(); //TODO: Make canvas container focusable insted?
                this.moveViewport();
                //animationController.flush();
            } else {
                animationController.handleGameEvent(event);
            }
        });

        sharedData.addObserver((event) => {
            if(event instanceof GameEvents.SpawnEvent) {
                this.updateCreatureLocations();
                this._tileGroups[event.getX()][event.getY()].update();
            } else if(event instanceof GameEvents.HitpointsEvent) {
                /*if(event.getAmount() < 0) {
                    getScrollingText(event.getAmount(), x, y, DAMAGE_COLORS[event.getDamageType()] || 'green', DAMAGE_OUTLINE_COLORS[event.getDamageType()] || 'green')
                        .appendTo(grid.children[0]);
                }*/
            } else if(event instanceof GameEvents.TakeItemEvent || event instanceof GameEvents.ItemDropEvent) {
                this.updateItems();
            }
            this.updateStatBars();
            this.updateRangeIndicator();
            this.updateSelectedTileIndicator();
        });
    }

    setSpritePack(spritePack) {
        this._spritePack = spritePack;
    }

    getSpritePack() {
        return this._spritePack;
    }

    getStage() {
        return this._pixiApp.stage;
    }

    getTileGroup(param1, param2) {
        let x, y;
        if(param1.getX) {
            x = param1.getX();
            y = param1.getY();
        } else {
            x = param1;
            y = param2;
        }
        return this._tileGroups[x][y];
    }

    getItemContainer(x, y) {
        return this._itemContainers[x][y];
    }

    getCreatureContainer(x, y) {
        return this._creatureContainers[x][y];
    }

    addCreatureSprite(sprite, x, y) {
        this.getCreatureContainer(x, y).addChild(sprite);
    }

    removeCreatureSprite(x, y) {
        const container = this.getCreatureContainer(x, y);
        const sprite = container.children[0];
        container.removeChild(sprite);
        return sprite;
    }

    getEntityById(id) {
        return this._entitySprites[id];
    }

    removeEntityById(id) {
        const container = this._entitySprites[id];
        container.parent.removeChild(container);
        return container;
    }

    populateStage() {
        this.populateSprites();
        this.updateCreatureLocations();
        this.updateItems();
        this.updateVision();
    }

    addParticle(particle) {
        this._particleLayer.addChild(particle);
    }

    populateSprites() {
        const stage = this.getStage();
        while(stage.children.length) stage.removeChild(stage.children[0]);

        const dungeon = this._sharedData.getDungeon();
        const tileGroups = this._tileGroups = new Array(dungeon.getWidth()).fill(0).map(()=>[]);
        const itemContainers = this._itemContainers = new Array(dungeon.getWidth()).fill(0).map(()=>[]);
        const creatureContainers = this._creatureContainers = new Array(dungeon.getWidth()).fill(0).map(()=>[]);

        const tileLayer = this._tileLayer = new PIXI.Container();
        const indicatorLayer = this._indicatorLayer = new PIXI.Container();
        const itemLayer = this._itemLayer = new PIXI.Container();
        const creatureLayer = this._creatureLayer = new PIXI.Container();
        const particleLayer = this._particleLayer = new PIXI.Container();

        dungeon.forEachTile((tile, x, y) => {
            const tileGroup = this.getSpritePack().getTileGroup(tile);
            const xOffset = x * (TILE_WIDTH + GAP_WIDTH);
            const yOffset = y * (TILE_WIDTH + GAP_WIDTH);
            tileGroup.x = xOffset;
            tileGroup.y = yOffset;
            tileGroup.interactive = true;
            tileGroup.hitArea = new PIXI.Rectangle(0, 0, TILE_WIDTH, TILE_WIDTH);
            tileGroups[x][y] = tileGroup;

            tileGroup
            .on('click', () => {
                this._clickHanders.forEach(handler => handler(x, y));
            }).on('tap', () => {
                this._clickHanders.forEach(handler => handler(x, y));
            }).on('mouseover', () => {
                setTimeout(() => { // Ensure mouseout fires first
                    this._mouseOverHandlers.forEach(handler => handler(x, y));
                });
            }).on('mouseout', () => {
                this._mouseOutHandlers.forEach(handler => handler(x, y));
            });

            tileLayer.addChild(tileGroup);

            const itemContainer = itemContainers[x][y] = new PIXI.Container();
            itemContainer.x = xOffset;
            itemContainer.y = yOffset;
            itemLayer.addChild(itemContainer);

            const creatureContainer = creatureContainers[x][y] = new PIXI.Container();
            creatureContainer.x = xOffset;
            creatureContainer.y = yOffset;
            creatureLayer.addChild(creatureContainer);
        });

        stage.addChild(tileLayer);
        stage.addChild(indicatorLayer);
        stage.addChild(itemLayer);
        stage.addChild(creatureLayer);
        stage.addChild(particleLayer);
    }

    updateItems() {
        const dungeon = this._sharedData.getDungeon();
        const spritePack = this.getSpritePack();
        // const itemContainers = this._itemContainers;
        dungeon.forEachTile((tile, x, y) => {
            const itemLayer = this.getItemContainer(x, y);
            while(itemLayer.children.length) itemLayer.removeChildAt(0);
            tile.getItems().forEach(function(item) {
                itemLayer.addChild(spritePack.getItemSprite(item));
            });
        });
    }

    updateVision() {
        const dungeon = this._sharedData.getDungeon();
        const player = dungeon.getPlayableCharacter();
        if(player) {
            dungeon.forEachTile((tile, x, y) => {
                const tileGroup = this.getTileGroup(x, y);
                const itemContainer = this.getItemContainer(x, y);
                const creatureContainer = this.getCreatureContainer(x, y);
                const playerCanSeeTile = player.canSee(dungeon, tile);
                if(playerCanSeeTile) {
                    tileGroup.alpha = 1;
                } else if(player.hasSeen(tile)) {
                    tileGroup.alpha = .5;
                } else {
                    tileGroup.alpha = 0;
                }
                itemContainer.visible = creatureContainer.visible = playerCanSeeTile;
            });
        }
    }

    updateCreatureLocations() {
        const dungeon = this._sharedData.getDungeon();
        const spritePack = this.getSpritePack();
        const entitySprites = this._entitySprites; // TODO: Getter
        dungeon.getCreatures().forEach((creature) => {
            let sprite = entitySprites[creature.getId()];
            if(!sprite) {
                sprite = entitySprites[creature.getId()] = spritePack.getSpriteStack(
                    [creature.constructor.name]
                );
                sprite.addChild(new PIXI.Graphics());
            }
            if(sprite.parent) {
                sprite.parent.removeChild(sprite);
            }
            if(!creature.isDead()) {
                const tile = dungeon.getTile(creature);
                this.getCreatureContainer(tile.getX(), tile.getY()).addChild(sprite);
            }
        });
    }

    updateStatBars() {
        const dungeon = this._sharedData.getDungeon();
        const player = dungeon.getPlayableCharacter();
        const entitySprites = this._entitySprites; // TODO: Getter

        dungeon.getCreatures().forEach(function(creature) {
            const sprite = entitySprites[creature.getId()];
            if(sprite) {
                const creatureWidth = sprite.children[0].width;
                const statGraphics = sprite.children[1];

                statGraphics.clear();
                const padding = 4;
                const maxBarWidth = creatureWidth - 2 * padding;
                const barHeight = 3;

                const hpBarWidth = maxBarWidth * Math.max(0, creature.getCurrentHP()) / creature.getBaseHP();
                const actionBarWidth = maxBarWidth * creature.getTimeToNextMove() / creature.getSpeed();

                statGraphics.x = padding;
                statGraphics.y = padding;

                statGraphics.lineStyle(1, 0x660000);
                statGraphics.drawRect(0, 0, hpBarWidth, barHeight);
                statGraphics.beginFill(0x8f0222);
                statGraphics.drawRect(1, 1, hpBarWidth - 1, barHeight);
                statGraphics.endFill();

                if(creature === player) {
                    return;
                }

                statGraphics.lineStyle(1, 0xCC7000);
                statGraphics.drawRect(0, barHeight + 2, actionBarWidth, barHeight);
                statGraphics.beginFill(0xdddd00);
                statGraphics.drawRect(1, barHeight + 3, actionBarWidth - 1, barHeight - 1);
                statGraphics.endFill();
            }
        });
    }

    updateRangeIndicator() {
        let rangeIndicator = this._rangeIndicator;
        if(rangeIndicator && rangeIndicator.parent) {
            rangeIndicator.parent.removeChild(rangeIndicator); // TODO: Is there a remove self function?
        }

        const sharedData = this._sharedData;
        const dungeon = sharedData.getDungeon();
        const player = dungeon.getPlayableCharacter();
        let rangedAttack;
        if(typeof sharedData.getTargettedAbility() === 'number') {
            rangedAttack = player.getAbility(sharedData.getTargettedAbility());
        } else if(typeof sharedData.getTargettedItem() === 'number') {
            rangedAttack = player.getInventory().getItem(sharedData.getTargettedItem());
        } else {
            rangedAttack = player.getRangedWeapon();
        }
        if(!rangedAttack) {
            return;
        }

        rangeIndicator = this._rangeIndicator = new PIXI.Graphics();

        let color;
        if(typeof rangedAttack.isMovementAbility === 'function') {
            color = 0x9400D3;
        } else if(rangedAttack.isTargetted()) {
            color = 0x7F00FF;
        } else {
            color = 0x46465a;
        }

        rangeIndicator.lineStyle(1, color, 1);
        rangeIndicator.drawCircle(TILE_WIDTH / 2, TILE_WIDTH / 2, rangedAttack.getRange() * TILE_WIDTH);

        this.getEntityById(player.getId()).addChild(rangeIndicator);
    }

    updateSelectedTileIndicator() {
        const indicatorLayer = this._indicatorLayer;
        while(indicatorLayer.children.length > 0) indicatorLayer.removeChildAt(0);

        const sharedData = this._sharedData;
        // const dungeon = sharedData.getDungeon();
        // const player = dungeon.getPlayableCharacter();
        // const playerLocation = dungeon.getTile(player);

        this._indicators = [
            sharedData.getHoverTile(),
            sharedData.getFocusTile()
        ].filter(Boolean).map((tile) => {
            const x = tile.getX();
            const y = tile.getY();
            const color = getTileColor(sharedData, x, y);
            const indicator = getIndicator(x, y, color);
            indicatorLayer.addChild(indicator);
            return indicator;
        });
    }

    moveViewport(
        xOffset = 0,
        yOffset = 0
    ) {
        const sharedData = this._sharedData;
        const stage = this.getStage();
        const dungeon = sharedData.getDungeon();
        const player = dungeon.getPlayableCharacter();
        const tile = dungeon.getTile(player);

        const x = tile.getX();
        const y = tile.getY();

        const canvasWidth = this.getDom().firstChild.width;
        const canvasHeight = this.getDom().firstChild.height;

        const cellDimension = TILE_WIDTH;
        const halfDimension = TILE_WIDTH / 2;
        const playerOffsetX = x * cellDimension + halfDimension;
        const playerOffsetY = y * cellDimension + halfDimension;

        stage.x = (canvasWidth / 2) - playerOffsetX - xOffset;
        stage.y = (canvasHeight / 2) - playerOffsetY - yOffset;
    }

    getDom() {
        return this._canvasContainer;
    }

    onClick(handler) {
        if(typeof handler !== 'function') {
            throw new Error('Handler must be a function');
        }
        this._clickHanders.push(handler);
    }

    onMouseOver(handler) {
        if(typeof handler !== 'function') {
            throw new Error('Handler must be a function');
        }
        this._mouseOverHandlers.push(handler);
    }

    onMouseOut(handler) {
        if(typeof handler !== 'function') {
            throw new Error('Handler must be a function');
        }
        this._mouseOutHandlers.push(handler);
    }

    // TODO: Cellphone zap
    // TODO: Projectile animations
    // TODO: Show buffs
    // TODO: Tooltips
    // TODO: Blue outline for movement move
}
<|endoftext|>