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

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

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

export default class MaterialDateTimePicker extends Component {

    constructor(props, ...restArgs) {

        super(props, ...restArgs);
        this.validValue = true;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    render() {
        const {className, style, name, placeholder, dateFormat, maxValue, minValue, label, isLabelAnimate, isFooter} = this.props;
        const {value, popupVisible, datePickerLevel, year, month, day, hour, minute, second, triggerEl} = this.state;
        let textValue = value && moment(value).format(dateFormat);
        return (
            <div className={`date-time-picker ${className}`}
                 ref="datePicker"
                 style={style}>
                <MaterialDatePickerTextField
                    ref="datePickerInput"
                    name={name}
                    placeholder={placeholder}
                    value={textValue}
                    readOnly={!popupVisible}
                    clearButtonVisible={false}
                    isFocusedSelectAll={false}
                    popupVisible={popupVisible}
                    label={label}
                    isLabelAnimate={isLabelAnimate}
                    onChange={this.textFieldChangeHandle}
                    onTouchTap={e => {
                        this.togglePopup(e);
                    }}/>
                <Popup className={`material-date-time-picker-popup`}
                       visible={popupVisible}
                       triggerEl={triggerEl}
                       hasTriangle={false}
                       onRequestClose={() => {
                           this.closePopup();
                       }}>
                    {
                        datePickerLevel == 'day' ?
                            <DayPicker
                                value={value}
                                dateFormat={dateFormat}
                                year={year}
                                month={month}
                                day={day}
                                hour={hour}
                                minute={minute}
                                second={second}
                                maxValue={maxValue ? moment(maxValue).format('YYYY-MM-DD') : null}
                                minValue={minValue ? moment(minValue).format('YYYY-MM-DD') : null}
                                isFooter={true}
                                onChange={this.dayPickerChangeHandle}
                                previousClick={this.datePickerChangeHandle}
                            />
                            : (
                            datePickerLevel == 'month' ?
                                <MonthPicker
                                    value={value}
                                    year={year}
                                    month={month}
                                    day={day}
                                    maxValue={maxValue ? moment(maxValue).format('YYYY-MM-DD') : null}
                                    minValue={minValue ? moment(minValue).format('YYYY-MM-DD') : null}
                                    onChange={this.monthPickerChangeHandle}
                                    previousClick={this.datePickerChangeHandle}
                                />
                                : (
                                datePickerLevel == 'year' ?
                                    <YearPicker
                                        value={value}
                                        year={year}
                                        month={month}
                                        day={day}
                                        maxValue={maxValue ? moment(maxValue).format('YYYY-MM-DD') : null}
                                        minValue={minValue ? moment(minValue).format('YYYY-MM-DD') : null}
                                        onChange={this.yearPickerChangeHandle}
                                    />
                                    :
                                    null
                            )

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

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

                                                Now

                                            :

                                                Now

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

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

                                    }

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

                            :
                            null
                    }

                </Popup>

        );
    }
};

MaterialDateTimePicker.propTypes = {

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

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

    /**
     * MaterialDateTimePicker input name.
     */
    name: PropTypes.string,

    /**
     * The label of the MaterialDateTimePicker.
     */
    label: PropTypes.any,

    /**
     * The animate of the MaterialDateTimePicker.
     */
    isLabelAnimate: PropTypes.bool,

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

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

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

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

    /**
     * MaterialDateTimePicker format.
     */
    dateFormat: PropTypes.string,

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

};

MaterialDateTimePicker.defaultProps = {
    className: '',
    style: null,
    name: '',
    value: moment().format('YYYY-MM-DD HH:mm:ss'),
    maxValue: '',
    minValue: '',
    placeholder: 'Date',
    dateFormat: 'YYYY-MM-DD HH:mm:ss',
    isFooter: true
};<commit_msg>update MaterialDateTimePicker<commit_after>/**
 * @file DateTimePicker component
 * @author sunday(sunday.wei@derbysoft.com)
 */

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

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

class MaterialDateTimePicker extends Component {

    constructor(props, ...restArgs) {

        super(props, ...restArgs);
        this.validValue = true;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    render() {
        const {className, style, name, placeholder, dateFormat, maxValue, minValue, label, isLabelAnimate, isFooter} = this.props;
        const {value, popupVisible, datePickerLevel, year, month, day, hour, minute, second, triggerEl} = this.state;
        let textValue = value && moment(value).format(dateFormat);
        return (
            <div className={`date-time-picker ${className}`}
                 ref="datePicker"
                 style={style}>
                <MaterialDatePickerTextField
                    ref="datePickerInput"
                    name={name}
                    placeholder={placeholder}
                    value={textValue}
                    readOnly={!popupVisible}
                    clearButtonVisible={false}
                    isFocusedSelectAll={false}
                    popupVisible={popupVisible}
                    label={label}
                    isLabelAnimate={isLabelAnimate}
                    onChange={this.textFieldChangeHandle}
                    onTouchTap={e => {
                        this.togglePopup(e);
                    }}/>
                <Popup className={`material-date-time-picker-popup`}
                       visible={popupVisible}
                       triggerEl={triggerEl}
                       hasTriangle={false}
                       onRequestClose={() => {
                           this.closePopup();
                       }}>
                    {
                        datePickerLevel == 'day' ?
                            <DayPicker
                                value={value}
                                dateFormat={dateFormat}
                                year={year}
                                month={month}
                                day={day}
                                hour={hour}
                                minute={minute}
                                second={second}
                                maxValue={maxValue ? moment(maxValue).format('YYYY-MM-DD') : null}
                                minValue={minValue ? moment(minValue).format('YYYY-MM-DD') : null}
                                isFooter={true}
                                onChange={this.dayPickerChangeHandle}
                                previousClick={this.datePickerChangeHandle}
                            />
                            : (
                                datePickerLevel == 'month' ?
                                    <MonthPicker
                                        value={value}
                                        year={year}
                                        month={month}
                                        day={day}
                                        maxValue={maxValue ? moment(maxValue).format('YYYY-MM-DD') : null}
                                        minValue={minValue ? moment(minValue).format('YYYY-MM-DD') : null}
                                        onChange={this.monthPickerChangeHandle}
                                        previousClick={this.datePickerChangeHandle}
                                    />
                                    : (
                                        datePickerLevel == 'year' ?
                                            <YearPicker
                                                value={value}
                                                year={year}
                                                month={month}
                                                day={day}
                                                maxValue={maxValue ? moment(maxValue).format('YYYY-MM-DD') : null}
                                                minValue={minValue ? moment(minValue).format('YYYY-MM-DD') : null}
                                                onChange={this.yearPickerChangeHandle}
                                            />
                                            :
                                            null
                                    )

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

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

                                                Now

                                            :

                                                Now

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

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

                                    }

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

                            :
                            null
                    }

                </Popup>

        );
    }
};

MaterialDateTimePicker.propTypes = {

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

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

    /**
     * MaterialDateTimePicker input name.
     */
    name: PropTypes.string,

    /**
     * The label of the MaterialDateTimePicker.
     */
    label: PropTypes.any,

    /**
     * The animate of the MaterialDateTimePicker.
     */
    isLabelAnimate: PropTypes.bool,

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

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

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

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

    /**
     * MaterialDateTimePicker format.
     */
    dateFormat: PropTypes.string,

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

};

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

export default MaterialDateTimePicker;<|endoftext|>


<commit_before>$(function(){
    var dropdowns = $('#nav > ul > li > ul');

    $('#nav').mouseleave(function(){
        dropdowns.hide();
    });

    $('#nav > ul > li').each(function(){
        var section = $(this);
        var dropdown = section.find('ul');

        section.mouseenter(function(){
            dropdowns.hide();
            dropdown.show();
        });
    });

    $('textarea').click(function(){
        $('textarea').animate({height: '400px'});
    });

    $('textarea').keyup(function(){
        var preview = $('.preview');
        var text = $('textarea').val();
        var avatar = $('img.avatar');

        var imgcode = '';
        if (avatar.length > 0 ) {
            var imgcode = '';
        }

        html = text;

        html = html.replace('>', '>');
        html = html.replace('>', '<');

        html = html.replace(/\n\*(.*)/g, '

$1

');
        html = html.replace(/<\/ul>[ \n]*
/g, '');

        html = html.replace(/\*([^\n]*?)\*/g, '$1');

        html = html.replace(/(.*)\n+(-{5,})/g, '
$1
');

        html = html.replace(/http:\/\/([^ \n]+)/g, 'http://$1');
        html = html.replace(/\[([^\n]+?)\][ \n]*(.*?)<\/a>/g, '$1');

        html = html.replace(/([^\n])\n([^\n])/g, '$1 $2');
        html = html.replace(/\n{3,}/g, '

');
        html = html.replace(/\n+/g, '
');
        html = html.replace(/<\/ul>[ \n]*
/g, '
');

        html = imgcode + html + '';

        preview.html(html);
    });

    $('textarea').keyup();
});
<commit_msg>Improved formatting for board members<commit_after>$(function(){
    var dropdowns = $('#nav > ul > li > ul');

    $('#nav').mouseleave(function(){
        dropdowns.hide();
    });

    $('#nav > ul > li').each(function(){
        var section = $(this);
        var dropdown = section.find('ul');

        section.mouseenter(function(){
            dropdowns.hide();
            dropdown.show();
        });
    });

    $('textarea').click(function(){
        $('textarea').animate({height: '400px'});
    });

    $('textarea').keyup(function(){
        var preview = $('.preview');
        var text = $('textarea').val();
        var avatar = $('img.avatar');

        var imgcode = '';
        if (avatar.length > 0 ) {
            var imgcode = '';
        }

        html = text;

        html = html.replace('>', '>');
        html = html.replace('>', '<');

        html = html.replace(/\n\*(.*)/g, '

$1

');
        html = html.replace(/<\/ul>[ \n]*
/g, '');

        html = html.replace(/\*([^\n]*?)\*/g, '$1');

        html = html.replace(/(.*)\n+(-{5,})/g, '
$1
');

        html = html.replace(/http:\/\/([^ \n]+)/g, 'http://$1');
        html = html.replace(/\[([^\n]+?)\][ \n]*(.*?)<\/a>/g, '$1');

        html = html.replace('### VORSTAND', '
');
        html = html.replace(/\n*
\n*/, '
');

        html = html.replace(/([^\n])\n([^\n])/g, '$1 $2');
        html = html.replace(/\n{3,}/g, '

');
        html = html.replace(/\n+/g, '
');
        html = html.replace(/<\/ul>[ \n]*
/g, '
');

        html = imgcode + html + '';

        preview.html(html);
    });

    $('textarea').keyup();
});
<|endoftext|>


<commit_before>
import { invoke } from '../../fn/fn.js';
import { now } from '../../dom/dom.js';

const DEBUG  = false;

// Render queue

const queue = new Set();
const data  = [];

var point;
var frame;

function run(time) {
	if (DEBUG) {
		point = {};
		point.frameTime   = time / 1000;
		point.runTime     = now();
		point.queuedFns   = queue.size;
		point.insertedFns = 0;
		console.groupCollapsed('frame', point.frameTime.toFixed(3));
	}

	frame = true;

	// Use a .forEach() to support IE11, which doesnt have for..of
	queue.forEach(invoke('call', [null, time]));

	//var fn;
	//for (fn of queue) {
	//	fn(time);
	//}

	queue.clear();
	frame = undefined;

	if (DEBUG) {
		point.duration = now() - point.runTime;
		data.push(point);
		//console.log('Render duration ' + (point.duration).toFixed(3) + 's');
		console.groupEnd();
	}
}

function cue(fn) {
	if (queue.has(fn)) {
		//if (DEBUG) { console.warn('frame: Trying to add an existing fn. Dropped', fn.name + '()'); }
		return;
	}

	// Functions cued during frame are run syncronously (to preserve
	// inner-DOM-first order of execution during setup)
	if (frame === true) {
		if (DEBUG) { ++point.insertedFns; }
		fn();
		return;
	}

	queue.add(fn);

	if (frame === undefined) {
		//if (DEBUG) { console.log('(request master frame)'); }
		frame = requestAnimationFrame(run);
	}
}

function uncue(fn) {
	queue.delete(fn);

	if (frame !== undefined && frame !== true && queue.size === 0) {
		//if (DEBUG) { console.log('(cancel master frame)'); }
		cancelAnimationFrame(frame);
		frame = undefined;
	}
}

export { cue, uncue, data };
<commit_msg>Report long frame renders<commit_after>
import { invoke } from '../../fn/fn.js';
import { now } from '../../dom/dom.js';

const DEBUG  = false;

// Render queue

const queue = new Set();
const data  = [];
const maxFrameDuration = 0.015;

var point = {};
var frame;

function run(time) {
	if (DEBUG) {
		point.tStart      = 0;
		point.tStop       = 0;
		point.frameTime   = time / 1000;
		point.queuedFns   = queue.size;
		point.insertedFns = 0;
		console.groupCollapsed('frame', point.frameTime.toFixed(3));
	}

	frame = true;
	point.tStart = now();
	queue.forEach(invoke('call', [null, time]));
	point.tStop = now();

	if (point.tStop - point.tStart > maxFrameDuration) {
		console.warn('Sparky: frame took' + (point.tStop - point.tStart).toFixed(3) + 's to render.');
	}

	queue.clear();
	frame = undefined;

	if (DEBUG) {
		point.duration = now() - point.tStart;
		data.push(point);
		//console.log('Render duration ' + (point.duration).toFixed(3) + 's');
		console.groupEnd();
	}
}

function cue(fn) {
	if (queue.has(fn)) {
		//if (DEBUG) { console.warn('frame: Trying to add an existing fn. Dropped', fn.name + '()'); }
		return;
	}

	// Functions cued during frame are run syncronously (to preserve
	// inner-DOM-first order of execution during setup)
	if (frame === true) {
		if (DEBUG) { ++point.insertedFns; }
		fn();
		return;
	}

	queue.add(fn);

	if (frame === undefined) {
		//if (DEBUG) { console.log('(request master frame)'); }
		frame = requestAnimationFrame(run);
	}
}

function uncue(fn) {
	queue.delete(fn);

	if (frame !== undefined && frame !== true && queue.size === 0) {
		//if (DEBUG) { console.log('(cancel master frame)'); }
		cancelAnimationFrame(frame);
		frame = undefined;
	}
}

export { cue, uncue, data };
<|endoftext|>


<commit_before>var pushNotification;
var registroURL = 'http://www.villarrobledo.com/app/registro.php';
var noticiasURL = 'http://www.villarrobledo.com/app/listado_noticias.php';
function onNotificationGCM(e) {
  alert("EVENT -> RECEIVED:" + e.event);
  switch(e.event) {
    case 'registered':
      if(e.regid.length > 0) {
        alert('registration id = ' + e.regid);
        document.getElementById('regId').value = e.regid;
      }
      break;
    case 'message':
      alert('message = ' + e.payload.message + ' msgcnt = ' + e.payload.msgcnt);
      break;
    case 'error':
      alert('GCM error = ' + e.msg);
      break;
    default:
      alert('An unknown GCM event has occurred');
      break;
  }
}
function successHandler (result) {
  alert("success: " + result);
}
function errorHandler (error) {
  alert("error:" + error);
}

// Registrar el dispositivo para notificaciones Push
function registrar(){
  var nombre = $("#nombre").val();
  var email = $("#email").val();
  var regId = $("#regId]").val();
  if(regId != "") {
    jQuery.ajax({
      type: 'POST',
      url: registroURL,
      data: 'nombre=' + nombre+ '&emailr=' + email + '&regId=' + regId,
      dataType: 'html',
      cache: false,
      success: function(response) {
        alert("Informacíon enviada");
      }
    });
  } else {
    alert('Esperando el regId del registro en GCM!');
  }
}

function alertDismissed() {}
function checkConnection() {
  var networkState = navigator.connection.type;
  var states = {};
  states[Connection.UNKNOWN] = 'Desconocida';
  states[Connection.ETHERNET] = 'Ethernet';
  states[Connection.WIFI] = 'WiFi';
  states[Connection.CELL_2G] = 'Teléfono 2G';
  states[Connection.CELL_3G] = 'Teléfono 3G';
  states[Connection.CELL_4G] = 'Teléfono 4G';
  states[Connection.NONE] = 'Sin conexión';
  navigator.notification.alert("Conexión de red: " + states[networkState], alertDismissed(), 'Aviso', 'Cerrar');
}

// Al cargar la página de noticias
$(document).on('pagebeforeshow', '#noticias', function() {
  $.ajax({
    type: 'GET',
    url: noticiasURL;
    dataType: 'json',
    timeout: 25000,
    success: function(data, status) {
      $.each(data, function(i,item) {
        $('#listadonoticias').append('
' + item.publicacion + '
' + item.titulo + '
').trigger("create");
      });
    },
    error: function(xhr, status, error) {
      alert("ERROR - xhr.status: " + xhr.status + '\nxhr.responseText: ' + xhr.responseText + '\nxhr.statusText: ' + xhr.statusText + '\nError: ' + error + '\nStatus: ' + status);
    }
  });
});

// Al cargar Cordova PhoneGap
function onDeviceReady() {

  navigator.notification.alert("El dispositivo está preparado", alertDismissed(), 'Aviso', 'Cerrar');

  // Push Notifications
  pushNotification = window.plugins.pushNotification;
  devicePlatform = device.platform;
  alert("registering " + devicePlatform );
  if (devicePlatform == 'android' || devicePlatform == 'Android') {
    pushNotification.register(successHandler, errorHandler, {"senderID":"896955415622","ecb":"onNotificationGCM"});
  }

}

// Al cargar la aplicación
function init() {
  document.addEventListener("deviceready", onDeviceReady(), false);
}
<commit_msg>Otra maldita coma<commit_after>var pushNotification;
var registroURL = 'http://www.villarrobledo.com/app/registro.php';
var noticiasURL = 'http://www.villarrobledo.com/app/listado_noticias.php';
function onNotificationGCM(e) {
  alert("EVENT -> RECEIVED:" + e.event);
  switch(e.event) {
    case 'registered':
      if(e.regid.length > 0) {
        alert('registration id = ' + e.regid);
        document.getElementById('regId').value = e.regid;
      }
      break;
    case 'message':
      alert('message = ' + e.payload.message + ' msgcnt = ' + e.payload.msgcnt);
      break;
    case 'error':
      alert('GCM error = ' + e.msg);
      break;
    default:
      alert('An unknown GCM event has occurred');
      break;
  }
}
function successHandler (result) {
  alert("success: " + result);
}
function errorHandler (error) {
  alert("error:" + error);
}

// Registrar el dispositivo para notificaciones Push
function registrar(){
  var nombre = $("#nombre").val();
  var email = $("#email").val();
  var regId = $("#regId]").val();
  if(regId != "") {
    jQuery.ajax({
      type: 'POST',
      url: registroURL,
      data: 'nombre=' + nombre + '&emailr=' + email + '&regId=' + regId,
      dataType: 'html',
      cache: false,
      success: function(response) {
        alert("Informacíon enviada");
      }
    });
  } else {
    alert('Esperando el regId del registro en GCM!');
  }
}

function alertDismissed() {}
function checkConnection() {
  var networkState = navigator.connection.type;
  var states = {};
  states[Connection.UNKNOWN] = 'Desconocida';
  states[Connection.ETHERNET] = 'Ethernet';
  states[Connection.WIFI] = 'WiFi';
  states[Connection.CELL_2G] = 'Teléfono 2G';
  states[Connection.CELL_3G] = 'Teléfono 3G';
  states[Connection.CELL_4G] = 'Teléfono 4G';
  states[Connection.NONE] = 'Sin conexión';
  navigator.notification.alert("Conexión de red: " + states[networkState], alertDismissed(), 'Aviso', 'Cerrar');
}

// Al cargar la página de noticias
$(document).on('pagebeforeshow', '#noticias', function() {
  $.ajax({
    type: 'GET',
    url: noticiasURL,
    dataType: 'json',
    timeout: 25000,
    success: function(data, status) {
      $.each(data, function(i,item) {
        $('#listadonoticias').append('
' + item.publicacion + '
' + item.titulo + '
').trigger("create");
      });
    },
    error: function(xhr, status, error) {
      alert("ERROR - xhr.status: " + xhr.status + '\nxhr.responseText: ' + xhr.responseText + '\nxhr.statusText: ' + xhr.statusText + '\nError: ' + error + '\nStatus: ' + status);
    }
  });
});

// Al cargar Cordova PhoneGap
function onDeviceReady() {

  navigator.notification.alert("El dispositivo está preparado", alertDismissed(), 'Aviso', 'Cerrar');

  // Push Notifications
  pushNotification = window.plugins.pushNotification;
  devicePlatform = device.platform;
  alert("registering " + devicePlatform );
  if (devicePlatform == 'android' || devicePlatform == 'Android') {
    pushNotification.register(successHandler, errorHandler, {"senderID":"896955415622","ecb":"onNotificationGCM"});
  }

}

// Al cargar la aplicación
function init() {
  document.addEventListener("deviceready", onDeviceReady(), false);
}
<|endoftext|>


<commit_before>var CORS_PROXY_URL = "https://cors-anywhere.herokuapp.com/";
var CHECK_DOWNLOADS_FINISHED_EVERY_MS = 100;

/* User options */
var userDownload;
var targetName;
var section;
var maxImageCount;
var nameFormat;
var restrictByScore;
var restrictByScoreType;
var restrictByScoreValue;
var includeImages;
var includeGifs;
var includeNsfw;

var checkFinishedInterval;
var downloadRequests = new Set();
var downloadedCount;
var toDownloadCount;
var zip;

$(document).ready(function() {
    setRandomNamePlaceholder();

    $(".ui.checkbox").checkbox();
    $("select.dropdown").dropdown();

    /* Make sure one or both of include images and include animated images are checked */
    $.fn.form.settings.rules.includeAny = function(value) {
        return $("#includeImagesInput").parent().checkbox("is checked")
            || $("#includeGifsInput").parent().checkbox("is checked");
    };

    $(".ui.form")
        .form({
            fields: {
                targetNameInput : "empty",
                imageAmountInput : "integer[0..]",
                restrictByScoreValueInput : "integer[0..]",
                includeImagesInput : "includeAny",
                includeGifsInput : "includeAny"
            }
        })
        .on("change", "#includeImagesInput,#includeGifsInput", function(e) {
            /*
                Removes the red text from include images/include
                animated images when one of them have been pressed.
            */
            $(".ui.form").form("validate form");
        });

    $("#restrictByScoreInput").parent().checkbox({
        onChange: function() {
            if (this.checked) {
                $("#restrictByScoreTypeInput").parent().removeClass("disabled");
            } else {
                $("#restrictByScoreTypeInput").parent().addClass("disabled");
            }
            $("#restrictByScoreValueInput").prop("disabled", !this.checked);
        }
    });

    $("#userDownloadInput").parent().checkbox({
        onChange: function() {
            if (this.checked) {
                $("label[for=targetNameInput]").text("User Name");
                $("#sectionInput").parent().addClass("disabled");
                $("#targetNameInput").attr("placeholder", "uniquepassive");
            } else {
                $("label[for=targetNameInput]").text("Subreddit Name");
                $("#sectionInput").parent().removeClass("disabled");
                setRandomNamePlaceholder();
            }
        }
    });
});

$("#downloadButton").click(function() {
    $("#unknownNameErrorBox").hide();
    $("#noImagesFoundWarningBox").hide();

    if ($(".ui.form").form("validate form")) {
        /* Reset states */
        $(".ui.form").addClass("loading");
        $("#downloadingInfoBox").show();
        downloadRequests.clear();
        downloadedCount = 0;
        toDownloadCount = 0;
        zip = new JSZip();
        updateUI();

        /* Read user options */
        userDownload = $("#userDownloadInput").parent().checkbox("is checked");
        targetName = $("#targetNameInput").val();
        section = $("#sectionInput").val();
        nameFormat = $("#nameFormatInput").val();
        restrictByScore = $("#restrictByScoreInput").parent().checkbox("is checked");
        restrictByScoreType = $("#restrictByScoreTypeInput").val();
        restrictByScoreValue = $("#restrictByScoreValueInput").val();
        includeImages = $("#includeImagesInput").parent().checkbox("is checked");
        includeGifs = $("#includeGifsInput").parent().checkbox("is checked");
        includeNsfw = $("#includeNsfwInput").parent().checkbox("is checked");

        if (userDownload) {
            /* Handle the user entering /user/ or user/ before the user name */
            if (targetName.startsWith("/user/")) {
                targetName = targetName.substring(3);
            } else if (targetName.startsWith("user/")) {
                targetName = targetName.substring(2);
            }
        } else {
            /* Handle the user entering /r/ or r/ before the sub name */
            if (targetName.startsWith("/r/")) {
                targetName = targetName.substring(3);
            } else if (targetName.startsWith("r/")) {
                targetName = targetName.substring(2);
            }
        }

        $(".targetNameText").text(targetName);

        if (userDownload) {
            $(".downloadTypeText").text("user");
        } else {
            $(".downloadTypeText").text("subreddit");
        }

        /* Find images to scrape and start downloading */
        maxImageCount = $("#imageAmountInput").val();
        download();
    }
});

function updateUI() {
    $("#downloadedCountText").text(downloadedCount);
    $("#toDownloadCountText").text(toDownloadCount);
}

function download(anchor) {
    /* Max 100 posts per request */
    var maxImageCountNow = Math.min(maxImageCount - toDownloadCount, 100);

    /* Prevent extreme amounts of requests in the case that maxImageCountNow is for example 1 */
    if (maxImageCountNow < 50) {
        maxImageCountNow = 50;
    }

    var url;

    if (userDownload) {
        url = CORS_PROXY_URL
            + "https://www.reddit.com/user/" + targetName
            + ".json?limit=" + maxImageCountNow
            + (anchor !== undefined ? "&after=" + anchor : "");
    } else {
        url = CORS_PROXY_URL
            + "https://www.reddit.com/r/" + targetName
            + "/" + section + ".json?limit=" + maxImageCountNow
            + (anchor !== undefined ? "&after=" + anchor : "");
    }

    $.ajax({
        url: url,
        type: "GET",
        dataType: "json",
        contentType: "application/json; charset=utf-8",
        success: function(result, status, xhr) {
            /* Make sure we haven't been redirected to the search page = subreddit doesn't exist */
            if (!userDownload && xhr.getResponseHeader("X-Final-Url").indexOf(section + ".json") === -1) {
                $("#unknownNameErrorBox").show();
                doneDownloading();
                return;
            }

            var children = result.data.children;

            for (var i = 0; i < children.length; i++) {
                if (toDownloadCount >= maxImageCount) {
                    break;
                }

                var post = children[i].data;

                /* Only download if there's a URL */
                if (post.url === null) {
                    continue;
                }

                /* Respect user's nsfw option */
                if (!includeNsfw && post.over_18) {
                    continue;
                }

                /* Don't download images that come from posts with greater/less score than inputted */
                if (restrictByScore) {
                    if ((restrictByScoreType === "ge" && post.score < restrictByScoreValue)
                            || (restrictByScoreType === "le" && post.score > restrictByScoreValue)) {
                        continue;
                    }
                }

                var url = post.url;

                /* Continue if direct url is a gif and user doesn't want to download gifs */
                if (!includeGifs && (url.indexOf(".gif") !== -1 || url.indexOf(".gifv") !== -1)) {
                    continue;
                }

                /* Continue if direct url is an image and user doesn't want to download images */
                if (!includeImages && (url.indexOf(".jpg") !== -1 || url.indexOf(".png") !== -1)) {
                    continue;
                }

                if (isUrlDirect(url)) {
                    /* Handle item with extension (direct link) */
                    toDownloadCount++;
                    downloadUrl(url, post);
                } else if (url.startsWith("http://imgur.com/a/") || url.startsWith("https://imgur.com/a/")) {
                    /* Handle downloading an album */
                    var imageName = url.substring(url.lastIndexOf("/") + 1);

                    $.ajax({
                        url: "https://api.imgur.com/3/album/" + imageName,
                        type: "GET",
                        dataType: "json",
                        contentType: "application/json; charset=utf-8",
                        headers: {
                            "authorization": "Client-ID 326b1cb24da9d5e"
                        },
                        post: post, // pass to success function
                        success: function(result, status, xhr) {
                            var images = result.data.images;

                            for (var i = 0; i < images.length; i++) {
                                if (toDownloadCount >= maxImageCount) {
                                    break;
                                }

                                toDownloadCount++;

                                var url = images[i].link;
                                downloadUrl(url, this.post);
                            }
                        },
                        error: function(error) {
                            doneDownloading();
                            alert("Accessing the Imgur API failed!\nPlease contact the developer.");
                        }
                    });
                } else if (url.startsWith("http://imgur.com/") || url.startsWith("https://imgur.com/")) {
                    /* Handle downloading a single-image album */
                    toDownloadCount++;

                    var imageName = url.substring(url.lastIndexOf("/") + 1);

                    $.ajax({
                        url: "https://api.imgur.com/3/image/" + imageName,
                        type: "GET",
                        dataType: "json",
                        contentType: "application/json; charset=utf-8",
                        headers: {
                            "authorization": "Client-ID 326b1cb24da9d5e"
                        },
                        post: post, // pass to success function
                        success: function(result, status, xhr) {
                            var url = result.data.link;
                            downloadUrl(url, this.post);
                        },
                        error: function(error) {
                            doneDownloading();
                            alert("Accessing the Imgur API failed!\nPlease contact the developer.");
                        }
                    });
                }
            }

            if (children.length === 0 || toDownloadCount >= maxImageCount || result.data.after === null) {
                checkFinishedInterval = setInterval(function() {
                    if (downloadedCount === toDownloadCount) {
                        doneDownloading();
                    }
                }, CHECK_DOWNLOADS_FINISHED_EVERY_MS);
            } else {
                download(result.data.after);
            }
        },
        error: function(error) {
            if (error.status === 404 || error.status === 403) {
                /* If HTTP status is 404 or 403, the subreddit probably doesn't exist */
                $("#unknownNameErrorBox").show();
            } else if (error.status !== 200) {
                /* Notify user when a non-handled status code is received */
                alert("Unknown status code " + error.status + " received from lookup request.\nPlease contact the developer.");
            }
            doneDownloading();
        }
    });
}

function downloadUrl(url, post) {
    downloadImageAsBase64(url, post, function(url, post, data) {
        var destinationFileName;

        if (nameFormat === "file-name") {
            destinationFileName = getFileNameWithExtension(url);
        } else if (nameFormat === "post-id") {
            destinationFileName = post.name + getFileExtension(url);
        } else {
            /* default: post-name */
            var regex = /[^\/]+(?=\/$|$)/g;
            var postName = regex.exec(post.permalink)[0];
            destinationFileName = postName + getFileExtension(url);
        }

        zip.file(destinationFileName, data, { base64: true });
        downloadedCount++;
        updateUI();
    });
}

function isUrlDirect(url) {
    return url.indexOf(".jpg") !== -1 || url.indexOf(".png") !== -1
        || url.indexOf(".gif") !== -1 || url.indexOf(".gifv") !== -1;
}

function getFileNameWithExtension(url) {
    var regex = /[^/\\&\?]+\.\w{3,4}(?=[\?&].*$|$)/;
    var m = regex.exec(url);
    return m[0];
}

function getFileExtension(url) {
    var fileNameWithExt = getFileNameWithExtension(url);

    return fileNameWithExt
        .substring(fileNameWithExt.lastIndexOf("."));
}

function doneDownloading() {
    for (var xhr in downloadRequests) {
        xhr.abort();
    }

    clearInterval(checkFinishedInterval);

    if (downloadedCount > 0) {
        zip.generateAsync({ type:"blob" })
            .then(function(content) {
                saveAs(content, targetName + "_" + section + ".zip");
            });
    } else {
        /* Only show the "no images found" warning if the subreddit exists */
        if (!$("#unknownNameErrorBox").is(":visible")) {
            $("#noImagesFoundWarningBox").show();
        }
    }

    $(".ui.form").removeClass("loading");
    $("#downloadingInfoBox").hide();
}

function downloadImageAsBase64(url, post, callback) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
        downloadRequests.delete(this);

        var reader = new FileReader();
        reader.onloadend = function() {
            callback(url, post, reader.result.split(",").pop());
        }
        reader.readAsDataURL(xhr.response);
    };
    xhr.open("GET", CORS_PROXY_URL + url);
    xhr.responseType = "blob";
    xhr.send();

    downloadRequests.add(xhr);
}

/*
    Puts a random subreddit as sub name inputbox placeholder,
    list taken from https://www.reddit.com/reddits
*/
function setRandomNamePlaceholder() {
    var subreddits = [
        "funny",
        "pics",
        "me_irl",
        "aww",
        "dankmemes",
        "mildlyinteresting",
        "AdviceAnimals",
        "CrappyDesign",
        "OldSchoolCool",
        "2007scape"
    ];
    $("#targetNameInput").attr("placeholder",
        subreddits[Math.floor(Math.random() * subreddits.length)]);
}

// https://stackoverflow.com/a/30949767/4313694
$("button").on("mousedown",
    function(event) {
        event.preventDefault();
    }
);
<commit_msg>Prevent doneDownloading being run multiple times at once<commit_after>var CORS_PROXY_URL = "https://cors-anywhere.herokuapp.com/";
var CHECK_DOWNLOADS_FINISHED_EVERY_MS = 100;

/* User options */
var userDownload;
var targetName;
var section;
var maxImageCount;
var nameFormat;
var restrictByScore;
var restrictByScoreType;
var restrictByScoreValue;
var includeImages;
var includeGifs;
var includeNsfw;

var checkFinishedInterval;
var downloadRequests = new Set();
var downloadedCount;
var toDownloadCount;
var zip;

$(document).ready(function() {
    setRandomNamePlaceholder();

    $(".ui.checkbox").checkbox();
    $("select.dropdown").dropdown();

    /* Make sure one or both of include images and include animated images are checked */
    $.fn.form.settings.rules.includeAny = function(value) {
        return $("#includeImagesInput").parent().checkbox("is checked")
            || $("#includeGifsInput").parent().checkbox("is checked");
    };

    $(".ui.form")
        .form({
            fields: {
                targetNameInput : "empty",
                imageAmountInput : "integer[0..]",
                restrictByScoreValueInput : "integer[0..]",
                includeImagesInput : "includeAny",
                includeGifsInput : "includeAny"
            }
        })
        .on("change", "#includeImagesInput,#includeGifsInput", function(e) {
            /*
                Removes the red text from include images/include
                animated images when one of them have been pressed.
            */
            $(".ui.form").form("validate form");
        });

    $("#restrictByScoreInput").parent().checkbox({
        onChange: function() {
            if (this.checked) {
                $("#restrictByScoreTypeInput").parent().removeClass("disabled");
            } else {
                $("#restrictByScoreTypeInput").parent().addClass("disabled");
            }
            $("#restrictByScoreValueInput").prop("disabled", !this.checked);
        }
    });

    $("#userDownloadInput").parent().checkbox({
        onChange: function() {
            if (this.checked) {
                $("label[for=targetNameInput]").text("User Name");
                $("#sectionInput").parent().addClass("disabled");
                $("#targetNameInput").attr("placeholder", "uniquepassive");
            } else {
                $("label[for=targetNameInput]").text("Subreddit Name");
                $("#sectionInput").parent().removeClass("disabled");
                setRandomNamePlaceholder();
            }
        }
    });
});

$("#downloadButton").click(function() {
    $("#unknownNameErrorBox").hide();
    $("#noImagesFoundWarningBox").hide();

    if ($(".ui.form").form("validate form")) {
        /* Reset states */
        $(".ui.form").addClass("loading");
        $("#downloadingInfoBox").show();
        downloadRequests.clear();
        downloadedCount = 0;
        toDownloadCount = 0;
        zip = new JSZip();
        updateUI();

        /* Read user options */
        userDownload = $("#userDownloadInput").parent().checkbox("is checked");
        targetName = $("#targetNameInput").val();
        section = $("#sectionInput").val();
        nameFormat = $("#nameFormatInput").val();
        restrictByScore = $("#restrictByScoreInput").parent().checkbox("is checked");
        restrictByScoreType = $("#restrictByScoreTypeInput").val();
        restrictByScoreValue = $("#restrictByScoreValueInput").val();
        includeImages = $("#includeImagesInput").parent().checkbox("is checked");
        includeGifs = $("#includeGifsInput").parent().checkbox("is checked");
        includeNsfw = $("#includeNsfwInput").parent().checkbox("is checked");

        if (userDownload) {
            /* Handle the user entering /user/ or user/ before the user name */
            if (targetName.startsWith("/user/")) {
                targetName = targetName.substring(3);
            } else if (targetName.startsWith("user/")) {
                targetName = targetName.substring(2);
            }
        } else {
            /* Handle the user entering /r/ or r/ before the sub name */
            if (targetName.startsWith("/r/")) {
                targetName = targetName.substring(3);
            } else if (targetName.startsWith("r/")) {
                targetName = targetName.substring(2);
            }
        }

        $(".targetNameText").text(targetName);

        if (userDownload) {
            $(".downloadTypeText").text("user");
        } else {
            $(".downloadTypeText").text("subreddit");
        }

        /* Find images to scrape and start downloading */
        maxImageCount = $("#imageAmountInput").val();
        download();
    }
});

function updateUI() {
    $("#downloadedCountText").text(downloadedCount);
    $("#toDownloadCountText").text(toDownloadCount);
}

function download(anchor) {
    /* Max 100 posts per request */
    var maxImageCountNow = Math.min(maxImageCount - toDownloadCount, 100);

    /* Prevent extreme amounts of requests in the case that maxImageCountNow is for example 1 */
    if (maxImageCountNow < 50) {
        maxImageCountNow = 50;
    }

    var url;

    if (userDownload) {
        url = CORS_PROXY_URL
            + "https://www.reddit.com/user/" + targetName
            + ".json?limit=" + maxImageCountNow
            + (anchor !== undefined ? "&after=" + anchor : "");
    } else {
        url = CORS_PROXY_URL
            + "https://www.reddit.com/r/" + targetName
            + "/" + section + ".json?limit=" + maxImageCountNow
            + (anchor !== undefined ? "&after=" + anchor : "");
    }

    $.ajax({
        url: url,
        type: "GET",
        dataType: "json",
        contentType: "application/json; charset=utf-8",
        success: function(result, status, xhr) {
            /* Make sure we haven't been redirected to the search page = subreddit doesn't exist */
            if (!userDownload && xhr.getResponseHeader("X-Final-Url").indexOf(section + ".json") === -1) {
                $("#unknownNameErrorBox").show();
                doneDownloading();
                return;
            }

            var children = result.data.children;

            for (var i = 0; i < children.length; i++) {
                if (toDownloadCount >= maxImageCount) {
                    break;
                }

                var post = children[i].data;

                /* Only download if there's a URL */
                if (post.url === null) {
                    continue;
                }

                /* Respect user's nsfw option */
                if (!includeNsfw && post.over_18) {
                    continue;
                }

                /* Don't download images that come from posts with greater/less score than inputted */
                if (restrictByScore) {
                    if ((restrictByScoreType === "ge" && post.score < restrictByScoreValue)
                            || (restrictByScoreType === "le" && post.score > restrictByScoreValue)) {
                        continue;
                    }
                }

                var url = post.url;

                /* Continue if direct url is a gif and user doesn't want to download gifs */
                if (!includeGifs && (url.indexOf(".gif") !== -1 || url.indexOf(".gifv") !== -1)) {
                    continue;
                }

                /* Continue if direct url is an image and user doesn't want to download images */
                if (!includeImages && (url.indexOf(".jpg") !== -1 || url.indexOf(".png") !== -1)) {
                    continue;
                }

                if (isUrlDirect(url)) {
                    /* Handle item with extension (direct link) */
                    toDownloadCount++;
                    downloadUrl(url, post);
                } else if (url.startsWith("http://imgur.com/a/") || url.startsWith("https://imgur.com/a/")) {
                    /* Handle downloading an album */
                    var imageName = url.substring(url.lastIndexOf("/") + 1);

                    $.ajax({
                        url: "https://api.imgur.com/3/album/" + imageName,
                        type: "GET",
                        dataType: "json",
                        contentType: "application/json; charset=utf-8",
                        headers: {
                            "authorization": "Client-ID 326b1cb24da9d5e"
                        },
                        post: post, // pass to success function
                        success: function(result, status, xhr) {
                            var images = result.data.images;

                            for (var i = 0; i < images.length; i++) {
                                if (toDownloadCount >= maxImageCount) {
                                    break;
                                }

                                toDownloadCount++;

                                var url = images[i].link;
                                downloadUrl(url, this.post);
                            }
                        },
                        error: function(error) {
                            doneDownloading();
                            alert("Accessing the Imgur API failed!\nPlease contact the developer.");
                        }
                    });
                } else if (url.startsWith("http://imgur.com/") || url.startsWith("https://imgur.com/")) {
                    /* Handle downloading a single-image album */
                    toDownloadCount++;

                    var imageName = url.substring(url.lastIndexOf("/") + 1);

                    $.ajax({
                        url: "https://api.imgur.com/3/image/" + imageName,
                        type: "GET",
                        dataType: "json",
                        contentType: "application/json; charset=utf-8",
                        headers: {
                            "authorization": "Client-ID 326b1cb24da9d5e"
                        },
                        post: post, // pass to success function
                        success: function(result, status, xhr) {
                            var url = result.data.link;
                            downloadUrl(url, this.post);
                        },
                        error: function(error) {
                            doneDownloading();
                            alert("Accessing the Imgur API failed!\nPlease contact the developer.");
                        }
                    });
                }
            }

            if (children.length === 0 || toDownloadCount >= maxImageCount || result.data.after === null) {
                checkFinishedInterval = setInterval(function() {
                    if (downloadedCount === toDownloadCount) {
                        doneDownloading();
                    }
                }, CHECK_DOWNLOADS_FINISHED_EVERY_MS);
            } else {
                download(result.data.after);
            }
        },
        error: function(error) {
            if (error.status === 404 || error.status === 403) {
                /* If HTTP status is 404 or 403, the subreddit probably doesn't exist */
                $("#unknownNameErrorBox").show();
            } else if (error.status !== 200) {
                /* Notify user when a non-handled status code is received */
                alert("Unknown status code " + error.status + " received from lookup request.\nPlease contact the developer.");
            }
            doneDownloading();
        }
    });
}

function downloadUrl(url, post) {
    downloadImageAsBase64(url, post, function(url, post, data) {
        var destinationFileName;

        if (nameFormat === "file-name") {
            destinationFileName = getFileNameWithExtension(url);
        } else if (nameFormat === "post-id") {
            destinationFileName = post.name + getFileExtension(url);
        } else {
            /* default: post-name */
            var regex = /[^\/]+(?=\/$|$)/g;
            var postName = regex.exec(post.permalink)[0];
            destinationFileName = postName + getFileExtension(url);
        }

        zip.file(destinationFileName, data, { base64: true });
        downloadedCount++;
        updateUI();
    });
}

function isUrlDirect(url) {
    return url.indexOf(".jpg") !== -1 || url.indexOf(".png") !== -1
        || url.indexOf(".gif") !== -1 || url.indexOf(".gifv") !== -1;
}

function getFileNameWithExtension(url) {
    var regex = /[^/\\&\?]+\.\w{3,4}(?=[\?&].*$|$)/;
    var m = regex.exec(url);
    return m[0];
}

function getFileExtension(url) {
    var fileNameWithExt = getFileNameWithExtension(url);

    return fileNameWithExt
        .substring(fileNameWithExt.lastIndexOf("."));
}

function doneDownloading() {
    // only run the "done" code if we're downloading
    if (!$(".ui.form").hasClass("loading")) {
        return;
    }

    $(".ui.form").removeClass("loading");
    $("#downloadingInfoBox").hide();

    for (var xhr in downloadRequests) {
        xhr.abort();
    }

    clearInterval(checkFinishedInterval);

    if (downloadedCount > 0) {
        zip.generateAsync({ type:"blob" })
            .then(function(content) {
                saveAs(content, targetName + "_" + section + ".zip");
            });
    } else {
        /* Only show the "no images found" warning if the subreddit exists */
        if (!$("#unknownNameErrorBox").is(":visible")) {
            $("#noImagesFoundWarningBox").show();
        }
    }
}

function downloadImageAsBase64(url, post, callback) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
        downloadRequests.delete(this);

        var reader = new FileReader();
        reader.onloadend = function() {
            callback(url, post, reader.result.split(",").pop());
        }
        reader.readAsDataURL(xhr.response);
    };
    xhr.open("GET", CORS_PROXY_URL + url);
    xhr.responseType = "blob";
    xhr.send();

    downloadRequests.add(xhr);
}

/*
    Puts a random subreddit as sub name inputbox placeholder,
    list taken from https://www.reddit.com/reddits
*/
function setRandomNamePlaceholder() {
    var subreddits = [
        "funny",
        "pics",
        "me_irl",
        "aww",
        "dankmemes",
        "mildlyinteresting",
        "AdviceAnimals",
        "CrappyDesign",
        "OldSchoolCool",
        "2007scape"
    ];
    $("#targetNameInput").attr("placeholder",
        subreddits[Math.floor(Math.random() * subreddits.length)]);
}

// https://stackoverflow.com/a/30949767/4313694
$("button").on("mousedown",
    function(event) {
        event.preventDefault();
    }
);
<|endoftext|>


<commit_before>'use strict';

const queryBaseURL = 'http://classes.berkeley.edu/enrollment/update/';

var classList = [];
var intervalID = -1;

function getClassStatus(termID, classID, callback) {
    const queryURL = queryBaseURL + termID + '/' + classID;
    $.getJSON('//query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent('select * from json where url="' + queryURL + '"') + '&format=json').done(function(data) {
        if (callback != null) {
            data.query.results.json.changed = Math.floor(Date.now() / 1000);
            callback(data.query.results.json);
        }
    }).fail(function() {
        if (callback != null) {
            callback(null);
        }
    });
}

function Record(termID, classID, status) {
    this.termID = termID;
    this.classID = classID;
    this.status = status;
    this.sameID = function(rhs) {
        return this.termID == rhs.termID && this.classID == rhs.classID;
    };
    this.updateStatus = function(callback) {
        const self = this;
        getClassStatus(this.termID, this.classID, function(data) {
            if (data == null) {
                if (callback != null) {
                    callback(false);
                }
                return;
            }
            var changed = false;
            if (self.status.classSections.enrollmentStatus.enrolledCount != data.classSections.enrollmentStatus.enrolledCount || self.status.classSections.enrollmentStatus.waitlistedCount != data.classSections.enrollmentStatus.waitlistedCount) {
                changed = true;
            }
            self.status = data;
            if (callback != null) {
                callback(changed);
            }
        });
    };
    this.makeRow = function(index) {
        var content = '
';
        content += '' + this.termID + '	';
        content += '' + this.status.classSections.id + '	';
        var status;
        if (parseInt(this.status.classSections.enrollmentStatus.enrolledCount) < parseInt(this.status.classSections.enrollmentStatus.maxEnroll)) {
            status = 'Open';
        } else if (parseInt(this.status.classSections.enrollmentStatus.waitlistedCount) < parseInt(this.status.classSections.enrollmentStatus.maxWaitlist)) {
            status = 'Wait List';
        } else {
            status = 'Closed';
        }
        content += '' + status + '	';
        content += '' + this.status.classSections.enrollmentStatus.enrolledCount + ' / ' + this.status.classSections.enrollmentStatus.maxEnroll + '	';
        content += '' + this.status.classSections.enrollmentStatus.waitlistedCount + ' / ' + this.status.classSections.enrollmentStatus.maxWaitlist + '	';
        content += '' + new Date(parseInt(this.status.changed) * 1000).toLocaleString() + '	';
        content += '<button type="button" class="btn btn-danger btn-xs" id="' + index + '">Delete</button>	';
        content += '
';
        return content;
    };
}

function makeTable() {
    $('#tableBody').empty();
    $.each(classList, function(index, record) {
        $('#tableBody').append(record.makeRow(index));
        $('button#' + index).click(function() {
            classList.splice(index, 1);
            makeTable();
        });
    });
    localStorage.setItem('classList', JSON.stringify(classList));
}

$(document).ready(function() {
    $.getJSON('ajax/terms.json').done(function(terms) {
        $.each(terms, function(termName, termID) {
            $('#termID').append($('<option>', {value : termID}).text(termName));
        });
    }).fail(function() {
        window.alert('Terms are not loaded!');
        window.close();
    });
    $('#classID').bind('keypress', function(event) {
        if (event.keyCode == '13') {
            $('#selectBtn').click();
        }
    });
    $('#selectBtn').click(function() {
        const termID = $('#termID').val();
        const classID = $('#classID').val();
        if (/^\d+$/.test(classID) && classID.length == 5) {
            $('#selectBtn').prop('disabled', true);
            getClassStatus(termID, classID, function(data) {
                if (data == null) {
                    window.alert('Unknown network error!');
                } else if (data.classSections == null) {
                    window.alert('You entered an invalid Class ID!');
                    $('#classID').val('');
                    $('#classID').focus();
                } else {
                    const record = new Record(termID, classID, data);
                    var ok = true;
                    $.each(classList, function(index, value) {
                        if (value.sameID(record)) {
                            ok = false;
                            return false;
                        }
                    });
                    if (ok) {
                        classList.push(record);
                        makeTable();
                        $('#classID').val('');
                        $('#classID').focus();
                    } else {
                        window.alert('You had selected this class!');
                        $('#classID').val('');
                        $('#classID').focus();
                    }
                }
                $('#selectBtn').prop('disabled', false);
            });
        } else {
            window.alert('Please enter a five-digit integer in Class ID!');
            $('#classID').val('');
            $('#classID').focus();
        }
    });
    $('#refreshNowBtn').click(function() {
        $.each(classList, function(index, record) {
            record.updateStatus(function() {
                makeTable();
            });
        });
    });
    $('#confirmInterval').click(function() {
        if (intervalID != -1) {
            clearInterval(intervalID);
        }
        const interval = $('#interval').val();
        if ($.isNumeric(interval) && interval > 0) {
            intervalID = setInterval(function() {
                $('#refreshNowBtn').click();
            }, interval * 1000);
            window.alert('Auto refresh interval is set successfully!');
        } else {
            window.alert('You entered an invalid number!');
            $('#interval').val('');
            $('#interval').focus();
        }
    });
    const ls = localStorage.getItem('classList');
    if (ls != null) {
        classList = JSON.parse(ls);
        for (var i = 0 ; i < classList.length ; i++) {
            classList[i] = new Record(classList[i].termID, classList[i].classID, classList[i].status);
        }
        makeTable();
        $('#refreshNowBtn').click();
    }
});
<commit_msg>notification<commit_after>'use strict';

const queryBaseURL = 'http://classes.berkeley.edu/enrollment/update/';

var classList = [];
var intervalID = -1;

function getClassStatus(termID, classID, callback) {
    const queryURL = queryBaseURL + termID + '/' + classID;
    $.getJSON('//query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent('select * from json where url="' + queryURL + '"') + '&format=json').done(function(data) {
        if (callback != null) {
            data.query.results.json.changed = Math.floor(Date.now() / 1000);
            callback(data.query.results.json);
        }
    }).fail(function() {
        if (callback != null) {
            callback(null);
        }
    });
}

function Record(termID, classID, status) {
    this.termID = termID;
    this.classID = classID;
    this.status = status;
    this.sameID = function(rhs) {
        return this.termID == rhs.termID && this.classID == rhs.classID;
    };
    this.updateStatus = function(callback) {
        const self = this;
        getClassStatus(this.termID, this.classID, function(data) {
            if (data == null) {
                if (callback != null) {
                    callback(false);
                }
                return;
            }
            var changed = false;
            if (self.status.classSections.enrollmentStatus.enrolledCount != data.classSections.enrollmentStatus.enrolledCount || self.status.classSections.enrollmentStatus.waitlistedCount != data.classSections.enrollmentStatus.waitlistedCount) {
                changed = true;
            }
            self.status = data;
            if (callback != null) {
                callback(changed);
            }
        });
    };
    this.makeRow = function(index) {
        var content = '
';
        content += '' + this.termID + '	';
        content += '' + this.status.classSections.id + '	';
        var status;
        if (parseInt(this.status.classSections.enrollmentStatus.enrolledCount) < parseInt(this.status.classSections.enrollmentStatus.maxEnroll)) {
            status = 'Open';
        } else if (parseInt(this.status.classSections.enrollmentStatus.waitlistedCount) < parseInt(this.status.classSections.enrollmentStatus.maxWaitlist)) {
            status = 'Wait List';
        } else {
            status = 'Closed';
        }
        content += '' + status + '	';
        content += '' + this.status.classSections.enrollmentStatus.enrolledCount + ' / ' + this.status.classSections.enrollmentStatus.maxEnroll + '	';
        content += '' + this.status.classSections.enrollmentStatus.waitlistedCount + ' / ' + this.status.classSections.enrollmentStatus.maxWaitlist + '	';
        content += '' + new Date(parseInt(this.status.changed) * 1000).toLocaleString() + '	';
        content += '<button type="button" class="btn btn-danger btn-xs" id="' + index + '">Delete</button>	';
        content += '
';
        return content;
    };
}

function makeTable() {
    $('#tableBody').empty();
    $.each(classList, function(index, record) {
        $('#tableBody').append(record.makeRow(index));
        $('button#' + index).click(function() {
            classList.splice(index, 1);
            makeTable();
        });
    });
    localStorage.setItem('classList', JSON.stringify(classList));
}

$(document).ready(function() {
    $.getJSON('ajax/terms.json').done(function(terms) {
        $.each(terms, function(termName, termID) {
            $('#termID').append($('<option>', {value : termID}).text(termName));
        });
    }).fail(function() {
        window.alert('Terms are not loaded!');
        window.close();
    });
    $('#classID').bind('keypress', function(event) {
        if (event.keyCode == '13') {
            $('#selectBtn').click();
        }
    });
    $('#selectBtn').click(function() {
        const termID = $('#termID').val();
        const classID = $('#classID').val();
        if (/^\d+$/.test(classID) && classID.length == 5) {
            $('#selectBtn').prop('disabled', true);
            getClassStatus(termID, classID, function(data) {
                if (data == null) {
                    window.alert('Unknown network error!');
                } else if (data.classSections == null) {
                    window.alert('You entered an invalid Class ID!');
                    $('#classID').val('');
                    $('#classID').focus();
                } else {
                    const record = new Record(termID, classID, data);
                    var ok = true;
                    $.each(classList, function(index, value) {
                        if (value.sameID(record)) {
                            ok = false;
                            return false;
                        }
                    });
                    if (ok) {
                        classList.push(record);
                        makeTable();
                        $('#classID').val('');
                        $('#classID').focus();
                    } else {
                        window.alert('You had selected this class!');
                        $('#classID').val('');
                        $('#classID').focus();
                    }
                }
                $('#selectBtn').prop('disabled', false);
            });
        } else {
            window.alert('Please enter a five-digit integer in Class ID!');
            $('#classID').val('');
            $('#classID').focus();
        }
    });
    $('#refreshNowBtn').click(function() {
        $.each(classList, function(index, record) {
            record.updateStatus(function(changed) {
                makeTable();
                if (changed) {
                    Notification.requestPermission(function(status) {
                        if (status == 'granted') {
                            var n = new Notification('UC Berkeley Class Monitor', {
                                'body' : 'Class ' + record.classID + ' has changed.',
                                'icon' : 'favicon.ico'
                            });
                            n.onshow = function() {
                                setTimeout(function() {
                                    n.close();
                                }, 5000);
                            };
                            n.onclick = function() {
                                n.close();
                            };
                        }
                    });
                }
            });
        });
    });
    $('#confirmInterval').click(function() {
        if (intervalID != -1) {
            clearInterval(intervalID);
        }
        const interval = $('#interval').val();
        if ($.isNumeric(interval) && interval > 0) {
            intervalID = setInterval(function() {
                $('#refreshNowBtn').click();
            }, interval * 1000);
            window.alert('Auto refresh interval is set successfully!');
        } else {
            window.alert('You entered an invalid number!');
            $('#interval').val('');
            $('#interval').focus();
        }
    });
    const ls = localStorage.getItem('classList');
    if (ls != null) {
        classList = JSON.parse(ls);
        for (var i = 0 ; i < classList.length ; i++) {
            classList[i] = new Record(classList[i].termID, classList[i].classID, classList[i].status);
        }
        makeTable();
        $('#refreshNowBtn').click();
    }
    Notification.requestPermission();
});
<|endoftext|>